Major sync with FreeBSD. diff --git a/sys/dev/raid/aac/aac.c b/sys/dev/raid/aac/aac.c index d5e6809..4234a75 100644 --- a/sys/dev/raid/aac/aac.c +++ b/sys/dev/raid/aac/aac.c @@ -33,6 +33,8 @@ /* * Driver for the Adaptec 'FSA' family of PCI/SCSI RAID adapters. */ +#define AAC_DRIVER_VERSION 0x02000000 +#define AAC_DRIVERNAME "aac" #include "opt_aac.h" @@ -44,13 +46,6 @@ #include #include #include -#if defined(__FreeBSD__) && __FreeBSD_version >= 500005 -#include -#else -#include -#endif - -#include "aac_compat.h" #include #include @@ -59,12 +54,15 @@ #include #include #include +#include + +#include +#include #include "aacreg.h" #include "aac_ioctl.h" #include "aacvar.h" #include "aac_tables.h" -#include "aac_cam.h" static void aac_startup(void *arg); static void aac_add_container(struct aac_softc *sc, @@ -74,20 +72,20 @@ static int aac_shutdown(device_t dev); /* Command Processing */ static void aac_timeout(void *ssc); -static int aac_start(struct aac_command *cm); +static int aac_map_command(struct aac_command *cm); static void aac_complete(void *context, int pending); static int aac_bio_command(struct aac_softc *sc, struct aac_command **cmp); static void aac_bio_complete(struct aac_command *cm); -static int aac_wait_command(struct aac_command *cm, int timeout); -static void aac_host_command(struct aac_softc *sc); -static void aac_host_response(struct aac_softc *sc); +static int aac_wait_command(struct aac_command *cm); +static void aac_command_thread(struct aac_softc *sc); /* Command Buffer Management */ +static void aac_map_command_sg(void *arg, bus_dma_segment_t *segs, + int nseg, int error); static void aac_map_command_helper(void *arg, bus_dma_segment_t *segs, int nseg, int error); static int aac_alloc_commands(struct aac_softc *sc); static void aac_free_commands(struct aac_softc *sc); -static void aac_map_command(struct aac_command *cm); static void aac_unmap_command(struct aac_command *cm); /* Hardware Interface */ @@ -123,7 +121,8 @@ struct aac_interface aac_fa_interface = { aac_fa_clear_istatus, aac_fa_set_mailbox, aac_fa_get_mailbox, - aac_fa_set_interrupts + aac_fa_set_interrupts, + NULL, NULL, NULL }; /* StrongARM interface */ @@ -144,10 +143,11 @@ struct aac_interface aac_sa_interface = { aac_sa_clear_istatus, aac_sa_set_mailbox, aac_sa_get_mailbox, - aac_sa_set_interrupts + aac_sa_set_interrupts, + NULL, NULL, NULL }; -/* i960Rx interface */ +/* i960Rx interface */ static int aac_rx_get_fwstatus(struct aac_softc *sc); static void aac_rx_qnotify(struct aac_softc *sc, int qbit); static int aac_rx_get_istatus(struct aac_softc *sc); @@ -157,6 +157,9 @@ static void aac_rx_set_mailbox(struct aac_softc *sc, u_int32_t command, u_int32_t arg2, u_int32_t arg3); static int aac_rx_get_mailbox(struct aac_softc *sc, int mb); static void aac_rx_set_interrupts(struct aac_softc *sc, int enable); +static int aac_rx_send_command(struct aac_softc *sc, struct aac_command *cm); +static int aac_rx_get_outb_queue(struct aac_softc *sc); +static void aac_rx_set_outb_queue(struct aac_softc *sc, int index); struct aac_interface aac_rx_interface = { aac_rx_get_fwstatus, @@ -165,7 +168,37 @@ struct aac_interface aac_rx_interface = { aac_rx_clear_istatus, aac_rx_set_mailbox, aac_rx_get_mailbox, - aac_rx_set_interrupts + aac_rx_set_interrupts, + aac_rx_send_command, + aac_rx_get_outb_queue, + aac_rx_set_outb_queue +}; + +/* Rocket/MIPS interface */ +static int aac_rkt_get_fwstatus(struct aac_softc *sc); +static void aac_rkt_qnotify(struct aac_softc *sc, int qbit); +static int aac_rkt_get_istatus(struct aac_softc *sc); +static void aac_rkt_clear_istatus(struct aac_softc *sc, int mask); +static void aac_rkt_set_mailbox(struct aac_softc *sc, u_int32_t command, + u_int32_t arg0, u_int32_t arg1, + u_int32_t arg2, u_int32_t arg3); +static int aac_rkt_get_mailbox(struct aac_softc *sc, int mb); +static void aac_rkt_set_interrupts(struct aac_softc *sc, int enable); +static int aac_rkt_send_command(struct aac_softc *sc, struct aac_command *cm); +static int aac_rkt_get_outb_queue(struct aac_softc *sc); +static void aac_rkt_set_outb_queue(struct aac_softc *sc, int index); + +struct aac_interface aac_rkt_interface = { + aac_rkt_get_fwstatus, + aac_rkt_qnotify, + aac_rkt_get_istatus, + aac_rkt_clear_istatus, + aac_rkt_set_mailbox, + aac_rkt_get_mailbox, + aac_rkt_set_interrupts, + aac_rkt_send_command, + aac_rkt_get_outb_queue, + aac_rkt_set_outb_queue }; /* Debugging and Diagnostics */ @@ -178,13 +211,16 @@ static d_open_t aac_open; static d_close_t aac_close; static d_ioctl_t aac_ioctl; static d_poll_t aac_poll; -static int aac_ioctl_sendfib(struct aac_softc *sc, caddr_t ufib); +static int aac_ioctl_sendfib(struct aac_softc *sc, caddr_t ufib) __unused; static void aac_handle_aif(struct aac_softc *sc, struct aac_fib *fib); static int aac_rev_check(struct aac_softc *sc, caddr_t udata); static int aac_getnext_aif(struct aac_softc *sc, caddr_t arg); static int aac_return_aif(struct aac_softc *sc, caddr_t uptr); static int aac_query_disk(struct aac_softc *sc, caddr_t uptr); +static int aac_get_pci_info(struct aac_softc *sc, caddr_t uptr); +static void aac_ioctl_event(struct aac_softc *sc, + struct aac_event *event, void *arg); #define AAC_CDEV_MAJOR 150 @@ -227,15 +263,10 @@ aac_attach(struct aac_softc *sc) aac_initq_complete(sc); aac_initq_bio(sc); -#if defined(__FreeBSD__) && __FreeBSD_version >= 500005 /* * Initialise command-completion task. */ TASK_INIT(&sc->aac_task_complete, 0, aac_complete, sc); -#endif - - /* disable interrupts before we enable anything */ - AAC_MASK_INTERRUPTS(sc); /* mark controller as suspended until we get ourselves organised */ sc->aac_state |= AAC_STATE_SUSPEND; @@ -246,8 +277,18 @@ aac_attach(struct aac_softc *sc) if ((error = aac_check_firmware(sc)) != 0) return(error); - /* Init the sync fib lock */ - AAC_LOCK_INIT(&sc->aac_sync_lock, "AAC sync FIB lock"); + /* + * Initialize locks + */ + AAC_LOCK_INIT(&sc->aac_aifq_lock, "AAC AIF lock"); + AAC_LOCK_INIT(&sc->aac_io_lock, "AAC I/O lock"); + AAC_LOCK_INIT(&sc->aac_container_lock, "AAC container lock"); + TAILQ_INIT(&sc->aac_container_tqh); + TAILQ_INIT(&sc->aac_ev_cmfree); + + + /* Initialize the local AIF queue pointers */ + sc->aac_aifq_head = sc->aac_aifq_tail = AAC_AIFQ_LENGTH; /* * Initialise the adapter. @@ -255,22 +296,48 @@ aac_attach(struct aac_softc *sc) if ((error = aac_init(sc)) != 0) return(error); - /* - * Print a little information about the controller. + /* + * Allocate and connect our interrupt. */ - aac_describe_controller(sc); + sc->aac_irq_rid = 0; + if ((sc->aac_irq = bus_alloc_resource_any(sc->aac_dev, SYS_RES_IRQ, + &sc->aac_irq_rid, + RF_SHAREABLE | + RF_ACTIVE)) == NULL) { + device_printf(sc->aac_dev, "can't allocate interrupt\n"); + return (EINVAL); + } + if (sc->flags & AAC_FLAGS_NEW_COMM) { + if (bus_setup_intr(sc->aac_dev, sc->aac_irq, + INTR_MPSAFE, aac_new_intr, + sc, &sc->aac_intr, NULL)) { + device_printf(sc->aac_dev, "can't set up interrupt\n"); + return (EINVAL); + } + } else { + if (bus_setup_intr(sc->aac_dev, sc->aac_irq, + INTR_FAST, aac_fast_intr, + sc, &sc->aac_intr, NULL)) { + device_printf(sc->aac_dev, + "can't set up FAST interrupt\n"); + if (bus_setup_intr(sc->aac_dev, sc->aac_irq, + INTR_MPSAFE, aac_fast_intr, + sc, &sc->aac_intr, NULL)) { + device_printf(sc->aac_dev, + "can't set up MPSAFE interrupt\n"); + return (EINVAL); + } + } + } /* - * Register to probe our containers later. + * Print a little information about the controller. */ - TAILQ_INIT(&sc->aac_container_tqh); - AAC_LOCK_INIT(&sc->aac_container_lock, "AAC container lock"); + aac_describe_controller(sc); /* - * Lock for the AIF queue + * Register to probe our containers later. */ - AAC_LOCK_INIT(&sc->aac_aifq_lock, "AAC AIF lock"); - sc->aac_ich.ich_func = aac_startup; sc->aac_ich.ich_arg = sc; sc->aac_ich.ich_desc = "aac"; @@ -285,37 +352,48 @@ aac_attach(struct aac_softc *sc) */ unit = device_get_unit(sc->aac_dev); dev_ops_add(&aac_ops, -1, unit); - sc->aac_dev_t = make_dev(&aac_ops, unit, UID_ROOT, GID_WHEEL, 0644, + sc->aac_dev_t = make_dev(&aac_ops, unit, UID_ROOT, GID_OPERATOR, 0640, "aac%d", unit); -#if defined(__FreeBSD__) && __FreeBSD_version > 500005 - (void)make_dev_alias(sc->aac_dev_t, "afa%d", unit); - (void)make_dev_alias(sc->aac_dev_t, "hpn%d", unit); -#endif sc->aac_dev_t->si_drv1 = sc; reference_dev(sc->aac_dev_t); /* Create the AIF thread */ -#if defined(__FreeBSD__) && __FreeBSD_version > 500005 - if (kthread_create((void(*)(void *))aac_host_command, sc, - &sc->aifthread, 0, "aac%daif", unit)) -#else - if (kthread_create((void(*)(void *))aac_host_command, sc, + if (kthread_create((void(*)(void *))aac_command_thread, sc, &sc->aifthread, "aac%daif", unit)) -#endif panic("Could not create AIF thread\n"); /* Register the shutdown method to only be called post-dump */ - if ((EVENTHANDLER_REGISTER(shutdown_post_sync, aac_shutdown, sc->aac_dev, - SHUTDOWN_PRI_DRIVER)) == NULL) - device_printf(sc->aac_dev, "shutdown event registration failed\n"); + if ((sc->eh = EVENTHANDLER_REGISTER(shutdown_post_sync, aac_shutdown, + sc->aac_dev, SHUTDOWN_PRI_DRIVER)) == NULL) + device_printf(sc->aac_dev, + "shutdown event registration failed\n"); /* Register with CAM for the non-DASD devices */ - if ((sc->flags & AAC_FLAGS_ENABLE_CAM) != 0) + if ((sc->flags & AAC_FLAGS_ENABLE_CAM) != 0) { + TAILQ_INIT(&sc->aac_sim_tqh); aac_get_bus_info(sc); + } return(0); } +void +aac_add_event(struct aac_softc *sc, struct aac_event *event) +{ + + switch (event->ev_type & AAC_EVENT_MASK) { + case AAC_EVENT_CMFREE: + TAILQ_INSERT_TAIL(&sc->aac_ev_cmfree, event, ev_links); + break; + default: + device_printf(sc->aac_dev, "aac_add event: unknown event %d\n", + event->ev_type); + break; + } + + return; +} + /* * Probe for containers, create disks. */ @@ -335,7 +413,8 @@ aac_startup(void *arg) /* disconnect ourselves from the intrhook chain */ config_intrhook_disestablish(&sc->aac_ich); - aac_alloc_sync_fib(sc, &fib, 0); + AAC_LOCK_ACQUIRE(&sc->aac_io_lock); + aac_alloc_sync_fib(sc, &fib); mi = (struct aac_mntinfo *)&fib->data[0]; /* loop over possible containers */ @@ -361,6 +440,7 @@ aac_startup(void *arg) } while ((i < count) && (i < AAC_MAX_CONTAINERS)); aac_release_sync_fib(sc); + AAC_LOCK_RELEASE(&sc->aac_io_lock); /* poke the bus to actually attach the child devices */ if (bus_generic_attach(sc->aac_dev)) @@ -371,10 +451,6 @@ aac_startup(void *arg) /* enable interrupts now */ AAC_UNMASK_INTERRUPTS(sc); - - /* enable the timeout watchdog */ - callout_reset(&sc->aac_watchdog, AAC_PERIODIC_INTERVAL * hz, - aac_timeout, sc); } /* @@ -386,18 +462,18 @@ aac_add_container(struct aac_softc *sc, struct aac_mntinforesp *mir, int f) struct aac_container *co; device_t child; - /* + /* * Check container volume type for validity. Note that many of * the possible types may never show up. */ if ((mir->Status == ST_OK) && (mir->MntTable[0].VolType != CT_NONE)) { - MALLOC(co, struct aac_container *, sizeof *co, M_AACBUF, - M_INTWAIT); - debug(1, "id %x name '%.16s' size %u type %d", + co = (struct aac_container *)kmalloc(sizeof *co, M_AACBUF, + M_INTWAIT | M_ZERO); + debug(1, "id %x name '%.16s' size %u type %d", mir->MntTable[0].ObjectId, mir->MntTable[0].FileSystemName, mir->MntTable[0].Capacity, mir->MntTable[0].VolType); - + if ((child = device_add_child(sc->aac_dev, "aacd", -1)) == NULL) device_printf(sc->aac_dev, "device_add_child failed\n"); else @@ -422,6 +498,7 @@ aac_add_container(struct aac_softc *sc, struct aac_mntinforesp *mir, int f) void aac_free(struct aac_softc *sc) { + debug_called(1); /* remove the control device */ @@ -429,11 +506,12 @@ aac_free(struct aac_softc *sc) destroy_dev(sc->aac_dev_t); /* throw away any FIB buffers, discard the FIB DMA tag */ - if (sc->aac_fibs != NULL) - aac_free_commands(sc); + aac_free_commands(sc); if (sc->aac_fib_dmat) bus_dma_tag_destroy(sc->aac_fib_dmat); + kfree(sc->aac_commands, M_AACBUF); + /* destroy the common area */ if (sc->aac_common) { bus_dmamap_unload(sc->aac_common_dmat, sc->aac_common_dmamap); @@ -473,9 +551,9 @@ int aac_detach(device_t dev) { struct aac_softc *sc; -#if AAC_BROKEN + struct aac_container *co; + struct aac_sim *sim; int error; -#endif debug_called(1); @@ -484,9 +562,26 @@ aac_detach(device_t dev) callout_stop(&sc->aac_watchdog); if (sc->aac_state & AAC_STATE_OPEN) - return(EBUSY); + return(EBUSY); + + /* Remove the child containers */ + while ((co = TAILQ_FIRST(&sc->aac_container_tqh)) != NULL) { + error = device_delete_child(dev, co->co_disk); + if (error) + return (error); + TAILQ_REMOVE(&sc->aac_container_tqh, co, co_link); + kfree(co, M_AACBUF); + } + + /* Remove the CAM SIMs */ + while ((sim = TAILQ_FIRST(&sc->aac_sim_tqh)) != NULL) { + TAILQ_REMOVE(&sc->aac_sim_tqh, sim, sim_link); + error = device_delete_child(dev, sim->sim_dev); + if (error) + return (error); + kfree(sim, M_AACBUF); + } -#if AAC_BROKEN if (sc->aifflags & AAC_AIFFLAGS_RUNNING) { sc->aifflags |= AAC_AIFFLAGS_EXIT; wakeup(sc->aifthread); @@ -499,12 +594,15 @@ aac_detach(device_t dev) if ((error = aac_shutdown(dev))) return(error); + EVENTHANDLER_DEREGISTER(shutdown_post_sync, sc->eh); + aac_free(sc); + lockuninit(&sc->aac_aifq_lock); + lockuninit(&sc->aac_io_lock); + lockuninit(&sc->aac_container_lock); + return(0); -#else - return (EBUSY); -#endif } /* @@ -526,18 +624,17 @@ aac_shutdown(device_t dev) sc = device_get_softc(dev); - crit_enter(); - sc->aac_state |= AAC_STATE_SUSPEND; - /* + /* * Send a Container shutdown followed by a HostShutdown FIB to the * controller to convince it that we don't want to talk to it anymore. * We've been closed and all I/O completed already */ device_printf(sc->aac_dev, "shutting down controller..."); - aac_alloc_sync_fib(sc, &fib, AAC_SYNC_LOCK_FORCE); + AAC_LOCK_ACQUIRE(&sc->aac_io_lock); + aac_alloc_sync_fib(sc, &fib); cc = (struct aac_close_command *)&fib->data[0]; bzero(cc, sizeof(struct aac_close_command)); @@ -546,6 +643,9 @@ aac_shutdown(device_t dev) if (aac_sync_fib(sc, ContainerCommand, 0, fib, sizeof(struct aac_close_command))) kprintf("FAILED.\n"); + else + kprintf("done\n"); +#if 0 else { fib->data[0] = 0; /* @@ -561,10 +661,12 @@ aac_shutdown(device_t dev) kprintf("done.\n"); } } +#endif AAC_MASK_INTERRUPTS(sc); + aac_release_sync_fib(sc); + AAC_LOCK_RELEASE(&sc->aac_io_lock); - crit_exit(); return(0); } @@ -580,12 +682,9 @@ aac_suspend(device_t dev) sc = device_get_softc(dev); - crit_enter(); - sc->aac_state |= AAC_STATE_SUSPEND; - + AAC_MASK_INTERRUPTS(sc); - crit_exit(); return(0); } @@ -607,48 +706,122 @@ aac_resume(device_t dev) } /* - * Take an interrupt. + * Interrupt handler for NEW_COMM interface. */ void -aac_intr(void *arg) +aac_new_intr(void *arg) +{ + struct aac_softc *sc; + u_int32_t index, fast; + struct aac_command *cm; + struct aac_fib *fib; + int i; + + debug_called(2); + + sc = (struct aac_softc *)arg; + + AAC_LOCK_ACQUIRE(&sc->aac_io_lock); + while (1) { + index = AAC_GET_OUTB_QUEUE(sc); + if (index == 0xffffffff) + index = AAC_GET_OUTB_QUEUE(sc); + if (index == 0xffffffff) + break; + if (index & 2) { + if (index == 0xfffffffe) { + /* XXX This means that the controller wants + * more work. Ignore it for now. + */ + continue; + } + /* AIF */ + fib = (struct aac_fib *)kmalloc(sizeof *fib, M_AACBUF, + M_INTWAIT | M_ZERO); + index &= ~2; + for (i = 0; i < sizeof(struct aac_fib)/4; ++i) + ((u_int32_t *)fib)[i] = AAC_GETREG4(sc, index + i*4); + aac_handle_aif(sc, fib); + kfree(fib, M_AACBUF); + + /* + * AIF memory is owned by the adapter, so let it + * know that we are done with it. + */ + AAC_SET_OUTB_QUEUE(sc, index); + AAC_CLEAR_ISTATUS(sc, AAC_DB_RESPONSE_READY); + } else { + fast = index & 1; + cm = sc->aac_commands + (index >> 2); + fib = cm->cm_fib; + if (fast) { + fib->Header.XferState |= AAC_FIBSTATE_DONEADAP; + *((u_int32_t *)(fib->data)) = AAC_ERROR_NORMAL; + } + aac_remove_busy(cm); + aac_unmap_command(cm); + cm->cm_flags |= AAC_CMD_COMPLETED; + + /* is there a completion handler? */ + if (cm->cm_complete != NULL) { + cm->cm_complete(cm); + } else { + /* assume that someone is sleeping on this + * command + */ + wakeup(cm); + } + sc->flags &= ~AAC_QUEUE_FRZN; + } + } + /* see if we can start some more I/O */ + if ((sc->flags & AAC_QUEUE_FRZN) == 0) + aac_startio(sc); + + AAC_LOCK_RELEASE(&sc->aac_io_lock); +} + +void +aac_fast_intr(void *arg) { struct aac_softc *sc; u_int16_t reason; - u_int32_t *resp_queue; debug_called(2); sc = (struct aac_softc *)arg; /* - * Optimize the common case of adapter response interrupts. - * We must read from the card prior to processing the responses - * to ensure the clear is flushed prior to accessing the queues. - * Reading the queues from local memory might save us a PCI read. + * Read the status register directly. This is faster than taking the + * driver lock and reading the queues directly. It also saves having + * to turn parts of the driver lock into a spin mutex, which would be + * ugly. */ - resp_queue = sc->aac_queues->qt_qindex[AAC_HOST_NORM_RESP_QUEUE]; - if (resp_queue[AAC_PRODUCER_INDEX] != resp_queue[AAC_CONSUMER_INDEX]) - reason = AAC_DB_RESPONSE_READY; - else - reason = AAC_GET_ISTATUS(sc); + reason = AAC_GET_ISTATUS(sc); AAC_CLEAR_ISTATUS(sc, reason); - (void)AAC_GET_ISTATUS(sc); - /* It's not ok to return here because of races with the previous step */ + /* handle completion processing */ if (reason & AAC_DB_RESPONSE_READY) - aac_host_response(sc); + taskqueue_enqueue(taskqueue_swi, &sc->aac_task_complete); - /* controller wants to talk to the log */ - if (reason & AAC_DB_PRINTF) - aac_print_printf(sc); + /* controller wants to talk to us */ + if (reason & (AAC_DB_PRINTF | AAC_DB_COMMAND_READY)) { + /* + * XXX Make sure that we don't get fooled by strange messages + * that start with a NULL. + */ + if ((reason & AAC_DB_PRINTF) && + (sc->aac_common->ac_printf[0] == 0)) + sc->aac_common->ac_printf[0] = 32; - /* controller has a message for us? */ - if (reason & AAC_DB_COMMAND_READY) { - /* XXX What happens if the thread is already awake? */ - if (sc->aifflags & AAC_AIFFLAGS_RUNNING) { - sc->aifflags |= AAC_AIFFLAGS_PENDING; - wakeup(sc->aifthread); - } + /* + * This might miss doing the actual wakeup. However, the + * msleep that this is waking up has a timeout, so it will + * wake up eventually. AIFs and printfs are low enough + * priority that they can handle hanging out for a few seconds + * if needed. + */ + wakeup(sc->aifthread); } } @@ -666,15 +839,18 @@ aac_startio(struct aac_softc *sc) debug_called(2); + if (sc->flags & AAC_QUEUE_FRZN) + return; + for (;;) { /* - * Try to get a command that's been put off for lack of + * Try to get a command that's been put off for lack of * resources */ cm = aac_dequeue_ready(sc); /* - * Try to build a command off the bio queue (ignore error + * Try to build a command off the bio queue (ignore error * return) */ if (cm == NULL) @@ -684,12 +860,12 @@ aac_startio(struct aac_softc *sc) if (cm == NULL) break; - /* try to give the command to the controller */ - if (aac_start(cm) == EBUSY) { - /* put it on the ready queue for later */ - aac_requeue_ready(cm); - break; - } + /* + * Try to give the command to the controller. Any error is + * catastrophic since it means that bus_dmamap_load() failed. + */ + if (aac_map_command(cm) != 0) + panic("aac: error mapping command %p\n", cm); } } @@ -698,7 +874,7 @@ aac_startio(struct aac_softc *sc) * last moment when possible. */ static int -aac_start(struct aac_command *cm) +aac_map_command(struct aac_command *cm) { struct aac_softc *sc; int error; @@ -706,48 +882,88 @@ aac_start(struct aac_command *cm) debug_called(2); sc = cm->cm_sc; + error = 0; - /* get the command mapped */ - aac_map_command(cm); - - /* fix up the address values in the FIB */ - cm->cm_fib->Header.SenderFibAddress = (u_int32_t)cm->cm_fib; - cm->cm_fib->Header.ReceiverFibAddress = cm->cm_fibphys; + /* don't map more than once */ + if (cm->cm_flags & AAC_CMD_MAPPED) + panic("aac: command %p already mapped", cm); - /* save a pointer to the command for speedy reverse-lookup */ - cm->cm_fib->Header.SenderData = (u_int32_t)cm; /* XXX 64-bit physical - * address issue */ - /* put the FIB on the outbound queue */ - error = aac_enqueue_fib(sc, cm->cm_queue, cm); - return(error); + if (cm->cm_datalen != 0) { + error = bus_dmamap_load(sc->aac_buffer_dmat, cm->cm_datamap, + cm->cm_data, cm->cm_datalen, + aac_map_command_sg, cm, 0); + if (error == EINPROGRESS) { + debug(1, "freezing queue\n"); + sc->flags |= AAC_QUEUE_FRZN; + error = 0; + } + } else { + aac_map_command_sg(cm, NULL, 0, 0); + } + return (error); } /* * Handle notification of one or more FIBs coming from the controller. */ static void -aac_host_command(struct aac_softc *sc) +aac_command_thread(struct aac_softc *sc) { struct aac_fib *fib; u_int32_t fib_size; - int size; + int size, retval; debug_called(2); - sc->aifflags |= AAC_AIFFLAGS_RUNNING; + AAC_LOCK_ACQUIRE(&sc->aac_io_lock); + sc->aifflags = AAC_AIFFLAGS_RUNNING; - while (!(sc->aifflags & AAC_AIFFLAGS_EXIT)) { - if (!(sc->aifflags & AAC_AIFFLAGS_PENDING)) - tsleep(sc->aifthread, 0, "aifthd", 15 * hz); + while ((sc->aifflags & AAC_AIFFLAGS_EXIT) == 0) { + retval = 0; + if ((sc->aifflags & AAC_AIFFLAGS_PENDING) == 0) { + crit_enter(); + tsleep_interlock(sc->aifthread); + AAC_LOCK_RELEASE(&sc->aac_io_lock); + retval = tsleep(sc->aifthread, 0, + "aifthd", AAC_PERIODIC_INTERVAL * hz); + AAC_LOCK_ACQUIRE(&sc->aac_io_lock); + crit_exit(); + } + /* + * First see if any FIBs need to be allocated. This needs + * to be called without the driver lock because contigmalloc + * will grab Giant, and would result in an LOR. + */ + if ((sc->aifflags & AAC_AIFFLAGS_ALLOCFIBS) != 0) { + AAC_LOCK_RELEASE(&sc->aac_io_lock); + aac_alloc_commands(sc); + AAC_LOCK_ACQUIRE(&sc->aac_io_lock); + sc->aifflags &= ~AAC_AIFFLAGS_ALLOCFIBS; + aac_startio(sc); + } + + /* + * While we're here, check to see if any commands are stuck. + * This is pretty low-priority, so it's ok if it doesn't + * always fire. + */ + if (retval == EWOULDBLOCK) + aac_timeout(sc); + + /* Check the hardware printf message buffer */ + if (sc->aac_common->ac_printf[0] != 0) + aac_print_printf(sc); - sc->aifflags &= ~AAC_AIFFLAGS_PENDING; + /* Also check to see if the adapter has a command for us. */ + if (sc->flags & AAC_FLAGS_NEW_COMM) + continue; for (;;) { if (aac_dequeue_fib(sc, AAC_HOST_NORM_CMD_QUEUE, &fib_size, &fib)) - break; /* nothing to do */ - + break; + AAC_PRINT_FIB(sc, fib); - + switch (fib->Header.Command) { case AifRequest: aac_handle_aif(sc, fib); @@ -758,11 +974,12 @@ aac_host_command(struct aac_softc *sc) break; } - /* Return the AIF to the controller. */ if ((fib->Header.XferState == 0) || - (fib->Header.StructType != AAC_FIBTYPE_TFIB)) + (fib->Header.StructType != AAC_FIBTYPE_TFIB)) { break; + } + /* Return the AIF to the controller. */ if (fib->Header.XferState & AAC_FIBSTATE_FROMADAP) { fib->Header.XferState |= AAC_FIBSTATE_DONEHOST; *(AAC_FSAStatus*)fib->data = ST_OK; @@ -779,75 +996,50 @@ aac_host_command(struct aac_softc *sc) * enqueue->startio chain. */ aac_enqueue_response(sc, - AAC_ADAP_NORM_RESP_QUEUE, - fib); + AAC_ADAP_NORM_RESP_QUEUE, + fib); } } } sc->aifflags &= ~AAC_AIFFLAGS_RUNNING; + AAC_LOCK_RELEASE(&sc->aac_io_lock); wakeup(sc->aac_dev); -#if defined(__FreeBSD__) && __FreeBSD_version > 500005 - mtx_lock(&Giant); -#endif kthread_exit(); } /* - * Handle notification of one or more FIBs completed by the controller + * Process completed commands. */ static void -aac_host_response(struct aac_softc *sc) +aac_complete(void *context, int pending) { + struct aac_softc *sc; struct aac_command *cm; struct aac_fib *fib; u_int32_t fib_size; debug_called(2); + sc = (struct aac_softc *)context; + + AAC_LOCK_ACQUIRE(&sc->aac_io_lock); + + /* pull completed commands off the queue */ for (;;) { /* look for completed FIBs on our queue */ if (aac_dequeue_fib(sc, AAC_HOST_NORM_RESP_QUEUE, &fib_size, - &fib)) + &fib)) break; /* nothing to do */ - + /* get the command, unmap and queue for later processing */ - cm = (struct aac_command *)fib->Header.SenderData; + cm = sc->aac_commands + fib->Header.SenderData; if (cm == NULL) { AAC_PRINT_FIB(sc, fib); - } else { - aac_remove_busy(cm); - aac_unmap_command(cm); /* XXX defer? */ - aac_enqueue_complete(cm); - } - } - - /* handle completion processing */ -#if defined(__FreeBSD__) && __FreeBSD_version >= 500005 - taskqueue_enqueue(taskqueue_swi, &sc->aac_task_complete); -#else - aac_complete(sc, 0); -#endif -} - -/* - * Process completed commands. - */ -static void -aac_complete(void *context, int pending) -{ - struct aac_softc *sc; - struct aac_command *cm; - - debug_called(2); - - sc = (struct aac_softc *)context; - - /* pull completed commands off the queue */ - for (;;) { - cm = aac_dequeue_complete(sc); - if (cm == NULL) break; + } + aac_remove_busy(cm); + aac_unmap_command(cm); /* XXX defer? */ cm->cm_flags |= AAC_CMD_COMPLETED; /* is there a completion handler? */ @@ -860,7 +1052,10 @@ aac_complete(void *context, int pending) } /* see if we can start some more I/O */ + sc->flags &= ~AAC_QUEUE_FRZN; aac_startio(sc); + + AAC_LOCK_RELEASE(&sc->aac_io_lock); } /* @@ -889,8 +1084,6 @@ aac_bio_command(struct aac_softc *sc, struct aac_command **cmp) { struct aac_command *cm; struct aac_fib *fib; - struct aac_blockread *br; - struct aac_blockwrite *bw; struct aac_disk *ad; struct bio *bio; struct buf *bp; @@ -899,10 +1092,11 @@ aac_bio_command(struct aac_softc *sc, struct aac_command **cmp) /* get the resources we will need */ cm = NULL; - if ((bio = aac_dequeue_bio(sc)) == NULL) - goto fail; + bio = NULL; if (aac_alloc_command(sc, &cm)) /* get a command */ goto fail; + if ((bio = aac_dequeue_bio(sc)) == NULL) + goto fail; /* fill out the command */ bp = bio->bio_buf; @@ -915,39 +1109,89 @@ aac_bio_command(struct aac_softc *sc, struct aac_command **cmp) /* build the FIB */ fib = cm->cm_fib; - fib->Header.XferState = - AAC_FIBSTATE_HOSTOWNED | - AAC_FIBSTATE_INITIALISED | - AAC_FIBSTATE_EMPTY | + fib->Header.Size = sizeof(struct aac_fib_header); + fib->Header.XferState = + AAC_FIBSTATE_HOSTOWNED | + AAC_FIBSTATE_INITIALISED | + AAC_FIBSTATE_EMPTY | AAC_FIBSTATE_FROMHOST | AAC_FIBSTATE_REXPECTED | AAC_FIBSTATE_NORM | AAC_FIBSTATE_ASYNC | AAC_FIBSTATE_FAST_RESPONSE; - fib->Header.Command = ContainerCommand; - fib->Header.Size = sizeof(struct aac_fib_header); /* build the read/write request */ ad = (struct aac_disk *)bio->bio_driver_info; - if (bp->b_cmd == BUF_CMD_READ) { - br = (struct aac_blockread *)&fib->data[0]; - br->Command = VM_CtBlockRead; - br->ContainerId = ad->ad_container->co_mntobj.ObjectId; - br->BlockNumber = bio->bio_offset / AAC_BLOCK_SIZE; - br->ByteCount = bp->b_bcount; - fib->Header.Size += sizeof(struct aac_blockread); - cm->cm_sgtable = &br->SgMap; - cm->cm_flags |= AAC_CMD_DATAIN; + + if (sc->flags & AAC_FLAGS_RAW_IO) { + struct aac_raw_io *raw; + raw = (struct aac_raw_io *)&fib->data[0]; + fib->Header.Command = RawIo; + raw->BlockNumber = bio->bio_offset / AAC_BLOCK_SIZE; + raw->ByteCount = bp->b_bcount; + raw->ContainerId = ad->ad_container->co_mntobj.ObjectId; + raw->BpTotal = 0; + raw->BpComplete = 0; + fib->Header.Size += sizeof(struct aac_raw_io); + cm->cm_sgtable = (struct aac_sg_table *)&raw->SgMapRaw; + if (bp->b_cmd == BUF_CMD_READ) { + raw->Flags = 1; + cm->cm_flags |= AAC_CMD_DATAIN; + } else { + raw->Flags = 0; + cm->cm_flags |= AAC_CMD_DATAOUT; + } + } else if ((sc->flags & AAC_FLAGS_SG_64BIT) == 0) { + fib->Header.Command = ContainerCommand; + if (bp->b_cmd == BUF_CMD_READ) { + struct aac_blockread *br; + br = (struct aac_blockread *)&fib->data[0]; + br->Command = VM_CtBlockRead; + br->ContainerId = ad->ad_container->co_mntobj.ObjectId; + br->BlockNumber = bio->bio_offset / AAC_BLOCK_SIZE; + br->ByteCount = bp->b_bcount; + fib->Header.Size += sizeof(struct aac_blockread); + cm->cm_sgtable = &br->SgMap; + cm->cm_flags |= AAC_CMD_DATAIN; + } else { + struct aac_blockwrite *bw; + bw = (struct aac_blockwrite *)&fib->data[0]; + bw->Command = VM_CtBlockWrite; + bw->ContainerId = ad->ad_container->co_mntobj.ObjectId; + bw->BlockNumber = bio->bio_offset / AAC_BLOCK_SIZE; + bw->ByteCount = bp->b_bcount; + bw->Stable = CUNSTABLE; + fib->Header.Size += sizeof(struct aac_blockwrite); + cm->cm_flags |= AAC_CMD_DATAOUT; + cm->cm_sgtable = &bw->SgMap; + } } else { - bw = (struct aac_blockwrite *)&fib->data[0]; - bw->Command = VM_CtBlockWrite; - bw->ContainerId = ad->ad_container->co_mntobj.ObjectId; - bw->BlockNumber = bio->bio_offset / AAC_BLOCK_SIZE; - bw->ByteCount = bp->b_bcount; - bw->Stable = CUNSTABLE; /* XXX what's appropriate here? */ - fib->Header.Size += sizeof(struct aac_blockwrite); - cm->cm_flags |= AAC_CMD_DATAOUT; - cm->cm_sgtable = &bw->SgMap; + fib->Header.Command = ContainerCommand64; + if (bp->b_cmd == BUF_CMD_READ) { + struct aac_blockread64 *br; + br = (struct aac_blockread64 *)&fib->data[0]; + br->Command = VM_CtHostRead64; + br->ContainerId = ad->ad_container->co_mntobj.ObjectId; + br->SectorCount = bp->b_bcount / AAC_BLOCK_SIZE; + br->BlockNumber = bio->bio_offset / AAC_BLOCK_SIZE; + br->Pad = 0; + br->Flags = 0; + fib->Header.Size += sizeof(struct aac_blockread64); + cm->cm_flags |= AAC_CMD_DATAOUT; + cm->cm_sgtable = (struct aac_sg_table *)&br->SgMap64; + } else { + struct aac_blockwrite64 *bw; + bw = (struct aac_blockwrite64 *)&fib->data[0]; + bw->Command = VM_CtHostWrite64; + bw->ContainerId = ad->ad_container->co_mntobj.ObjectId; + bw->SectorCount = bp->b_bcount / AAC_BLOCK_SIZE; + bw->BlockNumber = bio->bio_offset / AAC_BLOCK_SIZE; + bw->Pad = 0; + bw->Flags = 0; + fib->Header.Size += sizeof(struct aac_blockwrite64); + cm->cm_flags |= AAC_CMD_DATAIN; + cm->cm_sgtable = (struct aac_sg_table *)&bw->SgMap64; + } } *cmp = cm; @@ -1048,7 +1292,7 @@ aac_dump_enqueue(struct aac_disk *ad, u_int64_t lba, void *data, int dumppages) cm->cm_flags |= AAC_CMD_DATAOUT; cm->cm_sgtable = &bw->SgMap; - return (aac_start(cm)); + return (aac_map_command(cm)); } /* @@ -1101,29 +1345,33 @@ aac_dump_complete(struct aac_softc *sc) * Submit a command to the controller, return when it completes. * XXX This is very dangerous! If the card has gone out to lunch, we could * be stuck here forever. At the same time, signals are not caught - * because there is a risk that a signal could wakeup the tsleep before - * the card has a chance to complete the command. The passed in timeout - * is ignored for the same reason. Since there is no way to cancel a - * command in progress, we should probably create a 'dead' queue where - * commands go that have been interrupted/timed-out/etc, that keeps them - * out of the free pool. That way, if the card is just slow, it won't - * spam the memory of a command that has been recycled. + * because there is a risk that a signal could wakeup the sleep before + * the card has a chance to complete the command. Since there is no way + * to cancel a command that is in progress, we can't protect against the + * card completing a command late and spamming the command and data + * memory. So, we are held hostage until the command completes. */ static int -aac_wait_command(struct aac_command *cm, int timeout) +aac_wait_command(struct aac_command *cm) { - int error = 0; + struct aac_softc *sc; + int error; debug_called(2); + sc = cm->cm_sc; + /* Put the command on the ready queue and get things going */ cm->cm_queue = AAC_ADAP_NORM_CMD_QUEUE; aac_enqueue_ready(cm); - aac_startio(cm->cm_sc); + aac_startio(sc); + /* Lock is held */ + KKASSERT(lockstatus(&sc->aac_io_lock, curthread) != 0); crit_enter(); - while (!(cm->cm_flags & AAC_CMD_COMPLETED) && (error != EWOULDBLOCK)) { - error = tsleep(cm, 0, "aacwait", 0); - } + tsleep_interlock(cm); + AAC_LOCK_RELEASE(&sc->aac_io_lock); + error = tsleep(cm, 0, "aacwait", 0); + AAC_LOCK_ACQUIRE(&sc->aac_io_lock); crit_exit(); return(error); } @@ -1142,8 +1390,13 @@ aac_alloc_command(struct aac_softc *sc, struct aac_command **cmp) debug_called(3); - if ((cm = aac_dequeue_free(sc)) == NULL) - return(ENOMEM); + if ((cm = aac_dequeue_free(sc)) == NULL) { + if (sc->total_fibs < sc->aac_max_fibs) { + sc->aifflags |= AAC_AIFFLAGS_ALLOCFIBS; + wakeup(sc->aifthread); + } + return (EBUSY); + } *cmp = cm; return(0); @@ -1155,6 +1408,9 @@ aac_alloc_command(struct aac_softc *sc, struct aac_command **cmp) void aac_release_command(struct aac_command *cm) { + struct aac_event *event; + struct aac_softc *sc; + debug_called(3); /* (re)initialise the command/FIB */ @@ -1165,18 +1421,24 @@ aac_release_command(struct aac_command *cm) cm->cm_fib->Header.XferState = AAC_FIBSTATE_EMPTY; cm->cm_fib->Header.StructType = AAC_FIBTYPE_TFIB; cm->cm_fib->Header.Flags = 0; - cm->cm_fib->Header.SenderSize = sizeof(struct aac_fib); + cm->cm_fib->Header.SenderSize = cm->cm_sc->aac_max_fib_size; - /* + /* * These are duplicated in aac_start to cover the case where an * intermediate stage may have destroyed them. They're left * initialised here for debugging purposes only. */ - cm->cm_fib->Header.SenderFibAddress = (u_int32_t)cm->cm_fib; cm->cm_fib->Header.ReceiverFibAddress = (u_int32_t)cm->cm_fibphys; cm->cm_fib->Header.SenderData = 0; aac_enqueue_free(cm); + + sc = cm->cm_sc; + event = TAILQ_FIRST(&sc->aac_ev_cmfree); + if (event != NULL) { + TAILQ_REMOVE(&sc->aac_ev_cmfree, event, ev_links); + event->ev_callback(sc, event, event->ev_arg); + } } /* @@ -1185,13 +1447,13 @@ aac_release_command(struct aac_command *cm) static void aac_map_command_helper(void *arg, bus_dma_segment_t *segs, int nseg, int error) { - struct aac_softc *sc; + uint64_t *fibphys; - sc = (struct aac_softc *)arg; + fibphys = (uint64_t *)arg; debug_called(3); - sc->aac_fibphys = segs[0].ds_addr; + *fibphys = segs[0].ds_addr; } /* @@ -1201,32 +1463,63 @@ static int aac_alloc_commands(struct aac_softc *sc) { struct aac_command *cm; - int i; - - debug_called(1); + struct aac_fibmap *fm; + uint64_t fibphys; + int i, error; + + debug_called(2); + + if (sc->total_fibs + sc->aac_max_fibs_alloc > sc->aac_max_fibs) + return (ENOMEM); + + fm = kmalloc(sizeof(struct aac_fibmap), M_AACBUF, M_INTWAIT | M_ZERO); /* allocate the FIBs in DMAable memory and load them */ - if (bus_dmamem_alloc(sc->aac_fib_dmat, (void **)&sc->aac_fibs, - BUS_DMA_NOWAIT, &sc->aac_fibmap)) { - return(ENOMEM); + if (bus_dmamem_alloc(sc->aac_fib_dmat, (void **)&fm->aac_fibs, + BUS_DMA_NOWAIT, &fm->aac_fibmap)) { + device_printf(sc->aac_dev, + "Not enough contiguous memory available.\n"); + kfree(fm, M_AACBUF); + return (ENOMEM); } - bus_dmamap_load(sc->aac_fib_dmat, sc->aac_fibmap, sc->aac_fibs, - AAC_FIB_COUNT * sizeof(struct aac_fib), - aac_map_command_helper, sc, 0); + /* Ignore errors since this doesn't bounce */ + bus_dmamap_load(sc->aac_fib_dmat, fm->aac_fibmap, fm->aac_fibs, + sc->aac_max_fibs_alloc * sc->aac_max_fib_size, + aac_map_command_helper, &fibphys, 0); /* initialise constant fields in the command structure */ - bzero(sc->aac_fibs, AAC_FIB_COUNT * sizeof(struct aac_fib)); - for (i = 0; i < AAC_FIB_COUNT; i++) { - cm = &sc->aac_command[i]; + bzero(fm->aac_fibs, sc->aac_max_fibs_alloc * sc->aac_max_fib_size); + for (i = 0; i < sc->aac_max_fibs_alloc; i++) { + cm = sc->aac_commands + sc->total_fibs; + fm->aac_commands = cm; cm->cm_sc = sc; - cm->cm_fib = sc->aac_fibs + i; - cm->cm_fibphys = sc->aac_fibphys + (i * sizeof(struct aac_fib)); + cm->cm_fib = (struct aac_fib *) + ((u_int8_t *)fm->aac_fibs + i*sc->aac_max_fib_size); + cm->cm_fibphys = fibphys + i*sc->aac_max_fib_size; + cm->cm_index = sc->total_fibs; - if (!bus_dmamap_create(sc->aac_buffer_dmat, 0, &cm->cm_datamap)) - aac_release_command(cm); + if ((error = bus_dmamap_create(sc->aac_buffer_dmat, 0, + &cm->cm_datamap)) != 0) + break; + AAC_LOCK_ACQUIRE(&sc->aac_io_lock); + aac_release_command(cm); + sc->total_fibs++; + AAC_LOCK_RELEASE(&sc->aac_io_lock); } - return(0); + + if (i > 0) { + AAC_LOCK_ACQUIRE(&sc->aac_io_lock); + TAILQ_INSERT_TAIL(&sc->aac_fibmap_tqh, fm, fm_link); + debug(1, "total_fibs= %d\n", sc->total_fibs); + AAC_LOCK_RELEASE(&sc->aac_io_lock); + return (0); + } + + bus_dmamap_unload(sc->aac_fib_dmat, fm->aac_fibmap); + bus_dmamem_free(sc->aac_fib_dmat, fm->aac_fibs, fm->aac_fibmap); + kfree(fm, M_AACBUF); + return (ENOMEM); } /* @@ -1235,16 +1528,27 @@ aac_alloc_commands(struct aac_softc *sc) static void aac_free_commands(struct aac_softc *sc) { + struct aac_fibmap *fm; + struct aac_command *cm; int i; debug_called(1); - for (i = 0; i < AAC_FIB_COUNT; i++) - bus_dmamap_destroy(sc->aac_buffer_dmat, - sc->aac_command[i].cm_datamap); + while ((fm = TAILQ_FIRST(&sc->aac_fibmap_tqh)) != NULL) { - bus_dmamap_unload(sc->aac_fib_dmat, sc->aac_fibmap); - bus_dmamem_free(sc->aac_fib_dmat, sc->aac_fibs, sc->aac_fibmap); + TAILQ_REMOVE(&sc->aac_fibmap_tqh, fm, fm_link); + /* + * We check against total_fibs to handle partially + * allocated blocks. + */ + for (i = 0; i < sc->aac_max_fibs_alloc && sc->total_fibs--; i++) { + cm = fm->aac_commands + i; + bus_dmamap_destroy(sc->aac_buffer_dmat, cm->cm_datamap); + } + bus_dmamap_unload(sc->aac_fib_dmat, fm->aac_fibmap); + bus_dmamem_free(sc->aac_fib_dmat, fm->aac_fibs, fm->aac_fibmap); + kfree(fm, M_AACBUF); + } } /* @@ -1253,61 +1557,92 @@ aac_free_commands(struct aac_softc *sc) static void aac_map_command_sg(void *arg, bus_dma_segment_t *segs, int nseg, int error) { + struct aac_softc *sc; struct aac_command *cm; struct aac_fib *fib; - struct aac_sg_table *sg; int i; debug_called(3); cm = (struct aac_command *)arg; + sc = cm->cm_sc; fib = cm->cm_fib; - /* find the s/g table */ - sg = cm->cm_sgtable; - /* copy into the FIB */ - if (sg != NULL) { - sg->SgCount = nseg; - for (i = 0; i < nseg; i++) { - sg->SgEntry[i].SgAddress = segs[i].ds_addr; - sg->SgEntry[i].SgByteCount = segs[i].ds_len; + if (cm->cm_sgtable != NULL) { + if (fib->Header.Command == RawIo) { + struct aac_sg_tableraw *sg; + sg = (struct aac_sg_tableraw *)cm->cm_sgtable; + sg->SgCount = nseg; + for (i = 0; i < nseg; i++) { + sg->SgEntryRaw[i].SgAddress = segs[i].ds_addr; + sg->SgEntryRaw[i].SgByteCount = segs[i].ds_len; + sg->SgEntryRaw[i].Next = 0; + sg->SgEntryRaw[i].Prev = 0; + sg->SgEntryRaw[i].Flags = 0; + } + /* update the FIB size for the s/g count */ + fib->Header.Size += nseg*sizeof(struct aac_sg_entryraw); + } else if ((cm->cm_sc->flags & AAC_FLAGS_SG_64BIT) == 0) { + struct aac_sg_table *sg; + sg = cm->cm_sgtable; + sg->SgCount = nseg; + for (i = 0; i < nseg; i++) { + sg->SgEntry[i].SgAddress = segs[i].ds_addr; + sg->SgEntry[i].SgByteCount = segs[i].ds_len; + } + /* update the FIB size for the s/g count */ + fib->Header.Size += nseg*sizeof(struct aac_sg_entry); + } else { + struct aac_sg_table64 *sg; + sg = (struct aac_sg_table64 *)cm->cm_sgtable; + sg->SgCount = nseg; + for (i = 0; i < nseg; i++) { + sg->SgEntry64[i].SgAddress = segs[i].ds_addr; + sg->SgEntry64[i].SgByteCount = segs[i].ds_len; + } + /* update the FIB size for the s/g count */ + fib->Header.Size += nseg*sizeof(struct aac_sg_entry64); } - /* update the FIB size for the s/g count */ - fib->Header.Size += nseg * sizeof(struct aac_sg_entry); } -} - -/* - * Map a command into controller-visible space. - */ -static void -aac_map_command(struct aac_command *cm) -{ - struct aac_softc *sc; - - debug_called(2); - - sc = cm->cm_sc; - - /* don't map more than once */ - if (cm->cm_flags & AAC_CMD_MAPPED) - return; + /* Fix up the address values in the FIB. Use the command array index + * instead of a pointer since these fields are only 32 bits. Shift + * the SenderFibAddress over to make room for the fast response bit + * and for the AIF bit + */ + cm->cm_fib->Header.SenderFibAddress = (cm->cm_index << 2); + cm->cm_fib->Header.ReceiverFibAddress = (u_int32_t)cm->cm_fibphys; - if (cm->cm_datalen != 0) { - bus_dmamap_load(sc->aac_buffer_dmat, cm->cm_datamap, - cm->cm_data, cm->cm_datalen, - aac_map_command_sg, cm, 0); + /* save a pointer to the command for speedy reverse-lookup */ + cm->cm_fib->Header.SenderData = cm->cm_index; + + if (cm->cm_flags & AAC_CMD_DATAIN) + bus_dmamap_sync(sc->aac_buffer_dmat, cm->cm_datamap, + BUS_DMASYNC_PREREAD); + if (cm->cm_flags & AAC_CMD_DATAOUT) + bus_dmamap_sync(sc->aac_buffer_dmat, cm->cm_datamap, + BUS_DMASYNC_PREWRITE); + cm->cm_flags |= AAC_CMD_MAPPED; - if (cm->cm_flags & AAC_CMD_DATAIN) - bus_dmamap_sync(sc->aac_buffer_dmat, cm->cm_datamap, - BUS_DMASYNC_PREREAD); - if (cm->cm_flags & AAC_CMD_DATAOUT) - bus_dmamap_sync(sc->aac_buffer_dmat, cm->cm_datamap, - BUS_DMASYNC_PREWRITE); + if (sc->flags & AAC_FLAGS_NEW_COMM) { + int count = 10000000L; + while (AAC_SEND_COMMAND(sc, cm) != 0) { + if (--count == 0) { + aac_unmap_command(cm); + sc->flags |= AAC_QUEUE_FRZN; + aac_requeue_ready(cm); + } + DELAY(5); /* wait 5 usec. */ + } + } else { + /* Put the FIB on the outbound queue */ + if (aac_enqueue_fib(sc, cm->cm_queue, cm) == EBUSY) { + aac_unmap_command(cm); + sc->flags |= AAC_QUEUE_FRZN; + aac_requeue_ready(cm); + } } - cm->cm_flags |= AAC_CMD_MAPPED; } /* @@ -1360,7 +1695,8 @@ aac_common_map(void *arg, bus_dma_segment_t *segs, int nseg, int error) static int aac_check_firmware(struct aac_softc *sc) { - u_int32_t major, minor, options; + u_int32_t major, minor, options = 0, atu_size = 0; + int status; debug_called(1); @@ -1389,20 +1725,91 @@ aac_check_firmware(struct aac_softc *sc) /* * Retrieve the capabilities/supported options word so we know what - * work-arounds to enable. + * work-arounds to enable. Some firmware revs don't support this + * command. */ - if (aac_sync_command(sc, AAC_MONKER_GETINFO, 0, 0, 0, 0, NULL)) { - device_printf(sc->aac_dev, "RequestAdapterInfo failed\n"); - return (EIO); + if (aac_sync_command(sc, AAC_MONKER_GETINFO, 0, 0, 0, 0, &status)) { + if (status != AAC_SRB_STS_INVALID_REQUEST) { + device_printf(sc->aac_dev, + "RequestAdapterInfo failed\n"); + return (EIO); + } + } else { + options = AAC_GET_MAILBOX(sc, 1); + atu_size = AAC_GET_MAILBOX(sc, 2); + sc->supported_options = options; + + if ((options & AAC_SUPPORTED_4GB_WINDOW) != 0 && + (sc->flags & AAC_FLAGS_NO4GB) == 0) + sc->flags |= AAC_FLAGS_4GB_WINDOW; + if (options & AAC_SUPPORTED_NONDASD) + sc->flags |= AAC_FLAGS_ENABLE_CAM; + if ((options & AAC_SUPPORTED_SGMAP_HOST64) != 0 + && (sizeof(bus_addr_t) > 4)) { + device_printf(sc->aac_dev, + "Enabling 64-bit address support\n"); + sc->flags |= AAC_FLAGS_SG_64BIT; + } + if ((options & AAC_SUPPORTED_NEW_COMM) + && sc->aac_if.aif_send_command) + sc->flags |= AAC_FLAGS_NEW_COMM; + if (options & AAC_SUPPORTED_64BIT_ARRAYSIZE) + sc->flags |= AAC_FLAGS_ARRAY_64BIT; } - options = AAC_GET_MAILBOX(sc, 1); - sc->supported_options = options; - if ((options & AAC_SUPPORTED_4GB_WINDOW) != 0 && - (sc->flags & AAC_FLAGS_NO4GB) == 0) - sc->flags |= AAC_FLAGS_4GB_WINDOW; - if (options & AAC_SUPPORTED_NONDASD) - sc->flags |= AAC_FLAGS_ENABLE_CAM; + /* Check for broken hardware that does a lower number of commands */ + sc->aac_max_fibs = (sc->flags & AAC_FLAGS_256FIBS ? 256:512); + + /* Remap mem. resource, if required */ + if ((sc->flags & AAC_FLAGS_NEW_COMM) && + atu_size > rman_get_size(sc->aac_regs_resource)) { + bus_release_resource( + sc->aac_dev, SYS_RES_MEMORY, + sc->aac_regs_rid, sc->aac_regs_resource); + sc->aac_regs_resource = bus_alloc_resource( + sc->aac_dev, SYS_RES_MEMORY, &sc->aac_regs_rid, + 0ul, ~0ul, atu_size, RF_ACTIVE); + if (sc->aac_regs_resource == NULL) { + sc->aac_regs_resource = bus_alloc_resource_any( + sc->aac_dev, SYS_RES_MEMORY, + &sc->aac_regs_rid, RF_ACTIVE); + if (sc->aac_regs_resource == NULL) { + device_printf(sc->aac_dev, + "couldn't allocate register window\n"); + return (ENXIO); + } + sc->flags &= ~AAC_FLAGS_NEW_COMM; + } + sc->aac_btag = rman_get_bustag(sc->aac_regs_resource); + sc->aac_bhandle = rman_get_bushandle(sc->aac_regs_resource); + } + + /* Read preferred settings */ + sc->aac_max_fib_size = sizeof(struct aac_fib); + sc->aac_max_sectors = 128; /* 64KB */ + if (sc->flags & AAC_FLAGS_SG_64BIT) + sc->aac_sg_tablesize = (AAC_FIB_DATASIZE + - sizeof(struct aac_blockwrite64) + + sizeof(struct aac_sg_table64)) + / sizeof(struct aac_sg_table64); + else + sc->aac_sg_tablesize = (AAC_FIB_DATASIZE + - sizeof(struct aac_blockwrite) + + sizeof(struct aac_sg_table)) + / sizeof(struct aac_sg_table); + + if (!aac_sync_command(sc, AAC_MONKER_GETCOMMPREF, 0, 0, 0, 0, NULL)) { + options = AAC_GET_MAILBOX(sc, 1); + sc->aac_max_fib_size = (options & 0xFFFF); + sc->aac_max_sectors = (options >> 16) << 1; + options = AAC_GET_MAILBOX(sc, 2); + sc->aac_sg_tablesize = (options >> 16); + options = AAC_GET_MAILBOX(sc, 3); + sc->aac_max_fibs = (options & 0xFFFF); + } + if (sc->aac_max_fib_size > PAGE_SIZE) + sc->aac_max_fib_size = PAGE_SIZE; + sc->aac_max_fibs_alloc = PAGE_SIZE / sc->aac_max_fib_size; return (0); } @@ -1412,8 +1819,7 @@ aac_init(struct aac_softc *sc) { struct aac_adapter_init *ip; time_t then; - u_int32_t code; - u_int8_t *qaddr; + u_int32_t code, qoffset; int error; debug_called(1); @@ -1447,11 +1853,13 @@ aac_init(struct aac_softc *sc) */ if (bus_dma_tag_create(sc->aac_parent_dmat, /* parent */ 1, 0, /* algnmnt, boundary */ + (sc->flags & AAC_FLAGS_SG_64BIT) ? + BUS_SPACE_MAXADDR : BUS_SPACE_MAXADDR_32BIT, /* lowaddr */ BUS_SPACE_MAXADDR, /* highaddr */ NULL, NULL, /* filter, filterarg */ MAXBSIZE, /* maxsize */ - AAC_MAXSGENTRIES, /* nsegments */ + sc->aac_sg_tablesize, /* nsegments */ MAXBSIZE, /* maxsegsize */ BUS_DMA_ALLOCNOW, /* flags */ &sc->aac_buffer_dmat)) { @@ -1469,12 +1877,12 @@ aac_init(struct aac_softc *sc) 0x7fffffff, /* lowaddr */ BUS_SPACE_MAXADDR, /* highaddr */ NULL, NULL, /* filter, filterarg */ - AAC_FIB_COUNT * - sizeof(struct aac_fib), /* maxsize */ + sc->aac_max_fibs_alloc * + sc->aac_max_fib_size, /* maxsize */ 1, /* nsegments */ - AAC_FIB_COUNT * - sizeof(struct aac_fib), /* maxsegsize */ - BUS_DMA_ALLOCNOW, /* flags */ + sc->aac_max_fibs_alloc * + sc->aac_max_fib_size, /* maxsegsize */ + 0, /* flags */ &sc->aac_fib_dmat)) { device_printf(sc->aac_dev, "can't allocate FIB DMA tag\n"); goto out; @@ -1493,7 +1901,7 @@ aac_init(struct aac_softc *sc) 8192 + sizeof(struct aac_common), /* maxsize */ 1, /* nsegments */ BUS_SPACE_MAXSIZE_32BIT, /* maxsegsize */ - BUS_DMA_ALLOCNOW, /* flags */ + 0, /* flags */ &sc->aac_common_dmat)) { device_printf(sc->aac_dev, "can't allocate common structure DMA tag\n"); @@ -1522,7 +1930,14 @@ aac_init(struct aac_softc *sc) bzero(sc->aac_common, sizeof(*sc->aac_common)); /* Allocate some FIBs and associated command structs */ - if (aac_alloc_commands(sc) != 0) + TAILQ_INIT(&sc->aac_fibmap_tqh); + sc->aac_commands = kmalloc(sc->aac_max_fibs * sizeof(struct aac_command), + M_AACBUF, M_INTWAIT | M_ZERO); + while (sc->total_fibs < AAC_PREALLOCATE_FIBS) { + if (aac_alloc_commands(sc) != 0) + break; + } + if (sc->total_fibs == 0) goto out; /* @@ -1531,11 +1946,15 @@ aac_init(struct aac_softc *sc) */ ip = &sc->aac_common->ac_init; ip->InitStructRevision = AAC_INIT_STRUCT_REVISION; + if (sc->aac_max_fib_size > sizeof(struct aac_fib)) { + ip->InitStructRevision = AAC_INIT_STRUCT_REVISION_4; + sc->flags |= AAC_FLAGS_RAW_IO; + } ip->MiniPortRevision = AAC_INIT_STRUCT_MINIPORT_REVISION; ip->AdapterFibsPhysicalAddress = sc->aac_common_busaddr + offsetof(struct aac_common, ac_fibs); - ip->AdapterFibsVirtualAddress = (aac_phys_addr_t)&sc->aac_common->ac_fibs[0]; + ip->AdapterFibsVirtualAddress = 0; ip->AdapterFibsSize = AAC_ADAPTER_FIBS * sizeof(struct aac_fib); ip->AdapterFibAlign = sizeof(struct aac_fib); @@ -1543,34 +1962,51 @@ aac_init(struct aac_softc *sc) offsetof(struct aac_common, ac_printf); ip->PrintfBufferSize = AAC_PRINTF_BUFSIZE; - /* The adapter assumes that pages are 4K in size */ + /* + * The adapter assumes that pages are 4K in size, except on some + * broken firmware versions that do the page->byte conversion twice, + * therefore 'assuming' that this value is in 16MB units (2^24). + * Round up since the granularity is so high. + */ /* XXX why should the adapter care? */ ip->HostPhysMemPages = ctob((int)Maxmem) / AAC_PAGE_SIZE; + if (sc->flags & AAC_FLAGS_BROKEN_MEMMAP) { + ip->HostPhysMemPages = + (ip->HostPhysMemPages + AAC_PAGE_SIZE) / AAC_PAGE_SIZE; + } ip->HostElapsedSeconds = time_second; /* reset later if invalid */ + ip->InitFlags = 0; + if (sc->flags & AAC_FLAGS_NEW_COMM) { + ip->InitFlags = INITFLAGS_NEW_COMM_SUPPORTED; + device_printf(sc->aac_dev, "New comm. interface enabled\n"); + } + + ip->MaxIoCommands = sc->aac_max_fibs; + ip->MaxIoSize = sc->aac_max_sectors << 9; + ip->MaxFibSize = sc->aac_max_fib_size; + /* * Initialise FIB queues. Note that it appears that the layout of the * indexes and the segmentation of the entries may be mandated by the * adapter, which is only told about the base of the queue index fields. * * The initial values of the indices are assumed to inform the adapter - * of the sizes of the respective queues, and theoretically it could + * of the sizes of the respective queues, and theoretically it could * work out the entire layout of the queue structures from this. We * take the easy route and just lay this area out like everyone else * does. * - * The Linux driver uses a much more complex scheme whereby several - * header records are kept for each queue. We use a couple of generic + * The Linux driver uses a much more complex scheme whereby several + * header records are kept for each queue. We use a couple of generic * list manipulation functions which 'know' the size of each list by * virtue of a table. */ - qaddr = &sc->aac_common->ac_qbuf[0] + AAC_QUEUE_ALIGN; - qaddr -= (u_int32_t)qaddr % AAC_QUEUE_ALIGN; - sc->aac_queues = (struct aac_queue_table *)qaddr; - ip->CommHeaderAddress = sc->aac_common_busaddr + - ((u_int32_t)sc->aac_queues - - (u_int32_t)sc->aac_common); - bzero(sc->aac_queues, sizeof(struct aac_queue_table)); + qoffset = offsetof(struct aac_common, ac_qbuf) + AAC_QUEUE_ALIGN; + qoffset &= ~(AAC_QUEUE_ALIGN - 1); + sc->aac_queues = + (struct aac_queue_table *)((uintptr_t)sc->aac_common + qoffset); + ip->CommHeaderAddress = sc->aac_common_busaddr + qoffset; sc->aac_queues->qt_qindex[AAC_HOST_NORM_CMD_QUEUE][AAC_PRODUCER_INDEX] = AAC_HOST_NORM_CMD_ENTRIES; @@ -1628,12 +2064,17 @@ aac_init(struct aac_softc *sc) case AAC_HWIF_I960RX: AAC_SETREG4(sc, AAC_RX_ODBR, ~0); break; + case AAC_HWIF_RKT: + AAC_SETREG4(sc, AAC_RKT_ODBR, ~0); + break; + default: + break; } /* * Give the init structure to the controller. */ - if (aac_sync_command(sc, AAC_MONKER_INITSTRUCT, + if (aac_sync_command(sc, AAC_MONKER_INITSTRUCT, sc->aac_common_busaddr + offsetof(struct aac_common, ac_init), 0, 0, 0, NULL)) { @@ -1650,6 +2091,7 @@ out: /* * Send a synchronous command to the controller and wait for a result. + * Indicate if the controller completed the command with an error status. */ static int aac_sync_command(struct aac_softc *sc, u_int32_t command, @@ -1686,46 +2128,18 @@ aac_sync_command(struct aac_softc *sc, u_int32_t command, status = AAC_GET_MAILBOX(sc, 0); if (sp != NULL) *sp = status; - return(0); -} - -/* - * Grab the sync fib area. - */ -int -aac_alloc_sync_fib(struct aac_softc *sc, struct aac_fib **fib, int flags) -{ - - /* - * If the force flag is set, the system is shutting down, or in - * trouble. Ignore the mutex. - */ - if (!(flags & AAC_SYNC_LOCK_FORCE)) - AAC_LOCK_ACQUIRE(&sc->aac_sync_lock); - - *fib = &sc->aac_common->ac_sync_fib; - - return (1); -} - -/* - * Release the sync fib area. - */ -void -aac_release_sync_fib(struct aac_softc *sc) -{ - AAC_LOCK_RELEASE(&sc->aac_sync_lock); + if (status != AAC_SRB_STS_SUCCESS) + return (-1); + return(0); } -/* - * Send a synchronous FIB to the controller and wait for a result. - */ int -aac_sync_fib(struct aac_softc *sc, u_int32_t command, u_int32_t xferstate, +aac_sync_fib(struct aac_softc *sc, u_int32_t command, u_int32_t xferstate, struct aac_fib *fib, u_int16_t datasize) { debug_called(3); + KKASSERT(lockstatus(&sc->aac_io_lock, curthread) != 0); if (datasize > AAC_FIB_DATASIZE) return(EINVAL); @@ -1741,7 +2155,7 @@ aac_sync_fib(struct aac_softc *sc, u_int32_t command, u_int32_t xferstate, fib->Header.StructType = AAC_FIBTYPE_TFIB; fib->Header.Size = sizeof(struct aac_fib) + datasize; fib->Header.SenderSize = sizeof(struct aac_fib); - fib->Header.SenderFibAddress = (u_int32_t)fib; + fib->Header.SenderFibAddress = 0; /* Not needed */ fib->Header.ReceiverFibAddress = sc->aac_common_busaddr + offsetof(struct aac_common, ac_sync_fib); @@ -1797,11 +2211,9 @@ aac_enqueue_fib(struct aac_softc *sc, int queue, struct aac_command *cm) debug_called(3); - fib_size = cm->cm_fib->Header.Size; + fib_size = cm->cm_fib->Header.Size; fib_addr = cm->cm_fib->Header.ReceiverFibAddress; - crit_enter(); - /* get the producer/consumer indices */ pi = sc->aac_queues->qt_qindex[queue][AAC_PRODUCER_INDEX]; ci = sc->aac_queues->qt_qindex[queue][AAC_CONSUMER_INDEX]; @@ -1837,7 +2249,6 @@ aac_enqueue_fib(struct aac_softc *sc, int queue, struct aac_command *cm) error = 0; out: - crit_exit(); return(error); } @@ -1850,13 +2261,12 @@ aac_dequeue_fib(struct aac_softc *sc, int queue, u_int32_t *fib_size, struct aac_fib **fib_addr) { u_int32_t pi, ci; + u_int32_t fib_index; int error; int notify; debug_called(3); - crit_enter(); - /* get the producer/consumer indices */ pi = sc->aac_queues->qt_qindex[queue][AAC_PRODUCER_INDEX]; ci = sc->aac_queues->qt_qindex[queue][AAC_CONSUMER_INDEX]; @@ -1881,18 +2291,52 @@ aac_dequeue_fib(struct aac_softc *sc, int queue, u_int32_t *fib_size, /* fetch the entry */ *fib_size = (sc->aac_qentries[queue] + ci)->aq_fib_size; - *fib_addr = (struct aac_fib *)(sc->aac_qentries[queue] + - ci)->aq_fib_addr; - /* - * Is this a fast response? If it is, update the fib fields in - * local memory so the whole fib doesn't have to be DMA'd back up. - */ - if (*(uintptr_t *)fib_addr & 0x01) { - *(uintptr_t *)fib_addr &= ~0x01; - (*fib_addr)->Header.XferState |= AAC_FIBSTATE_DONEADAP; - *((u_int32_t*)((*fib_addr)->data)) = AAC_ERROR_NORMAL; + switch (queue) { + case AAC_HOST_NORM_CMD_QUEUE: + case AAC_HOST_HIGH_CMD_QUEUE: + /* + * The aq_fib_addr is only 32 bits wide so it can't be counted + * on to hold an address. For AIF's, the adapter assumes + * that it's giving us an address into the array of AIF fibs. + * Therefore, we have to convert it to an index. + */ + fib_index = (sc->aac_qentries[queue] + ci)->aq_fib_addr / + sizeof(struct aac_fib); + *fib_addr = &sc->aac_common->ac_fibs[fib_index]; + break; + + case AAC_HOST_NORM_RESP_QUEUE: + case AAC_HOST_HIGH_RESP_QUEUE: + { + struct aac_command *cm; + + /* + * As above, an index is used instead of an actual address. + * Gotta shift the index to account for the fast response + * bit. No other correction is needed since this value was + * originally provided by the driver via the SenderFibAddress + * field. + */ + fib_index = (sc->aac_qentries[queue] + ci)->aq_fib_addr; + cm = sc->aac_commands + (fib_index >> 2); + *fib_addr = cm->cm_fib; + + /* + * Is this a fast response? If it is, update the fib fields in + * local memory since the whole fib isn't DMA'd back up. + */ + if (fib_index & 0x01) { + (*fib_addr)->Header.XferState |= AAC_FIBSTATE_DONEADAP; + *((u_int32_t*)((*fib_addr)->data)) = AAC_ERROR_NORMAL; + } + break; + } + default: + panic("Invalid queue in aac_dequeue_fib()"); + break; } + /* update consumer index */ sc->aac_queues->qt_qindex[queue][AAC_CONSUMER_INDEX] = ci + 1; @@ -1902,7 +2346,6 @@ aac_dequeue_fib(struct aac_softc *sc, int queue, u_int32_t *fib_size, error = 0; out: - crit_exit(); return(error); } @@ -1920,12 +2363,10 @@ aac_enqueue_response(struct aac_softc *sc, int queue, struct aac_fib *fib) debug_called(1); /* Tell the adapter where the FIB is */ - fib_size = fib->Header.Size; + fib_size = fib->Header.Size; fib_addr = fib->Header.SenderFibAddress; fib->Header.ReceiverFibAddress = fib_addr; - crit_enter(); - /* get the producer/consumer indices */ pi = sc->aac_queues->qt_qindex[queue][AAC_PRODUCER_INDEX]; ci = sc->aac_queues->qt_qindex[queue][AAC_CONSUMER_INDEX]; @@ -1954,7 +2395,6 @@ aac_enqueue_response(struct aac_softc *sc, int queue, struct aac_fib *fib) error = 0; out: - crit_exit(); return(error); } @@ -1969,29 +2409,12 @@ aac_timeout(void *xsc) struct aac_command *cm; time_t deadline; int timedout, code; -#if 0 - /* simulate an interrupt to handle possibly-missed interrupts */ - /* - * XXX This was done to work around another bug which has since been - * fixed. It is dangerous anyways because you don't want multiple - * threads in the interrupt handler at the same time! If calling - * is deamed neccesary in the future, proper mutexes must be used. - */ - crit_enter(); - aac_intr(sc); - crit_exit(); - - /* kick the I/O queue to restart it in the case of deadlock */ - aac_startio(sc); -#endif - /* - * traverse the busy command list, bitch about late commands once + * Traverse the busy command list, bitch about late commands once * only. */ timedout = 0; deadline = time_second - AAC_CMD_TIMEOUT; - crit_enter(); TAILQ_FOREACH(cm, &sc->aac_busy, cm_link) { if ((cm->cm_timestamp < deadline) /* && !(cm->cm_flags & AAC_CMD_TIMEDOUT) */) { @@ -2011,11 +2434,6 @@ aac_timeout(void *xsc) } } - crit_exit(); - - /* reset the timer for next time */ - callout_reset(&sc->aac_watchdog, AAC_PERIODIC_INTERVAL * hz, - aac_timeout, sc); } /* @@ -2052,6 +2470,14 @@ aac_fa_get_fwstatus(struct aac_softc *sc) return (val); } +static int +aac_rkt_get_fwstatus(struct aac_softc *sc) +{ + debug_called(3); + + return(AAC_GETREG4(sc, AAC_RKT_FWSTATUS)); +} + /* * Notify the controller of a change in a given queue */ @@ -2081,6 +2507,14 @@ aac_fa_qnotify(struct aac_softc *sc, int qbit) AAC_FA_HACK(sc); } +static void +aac_rkt_qnotify(struct aac_softc *sc, int qbit) +{ + debug_called(3); + + AAC_SETREG4(sc, AAC_RKT_IDBR, qbit); +} + /* * Get the interrupt reason bits */ @@ -2111,6 +2545,14 @@ aac_fa_get_istatus(struct aac_softc *sc) return (val); } +static int +aac_rkt_get_istatus(struct aac_softc *sc) +{ + debug_called(3); + + return(AAC_GETREG4(sc, AAC_RKT_ODBR)); +} + /* * Clear some interrupt reason bits */ @@ -2139,6 +2581,14 @@ aac_fa_clear_istatus(struct aac_softc *sc, int mask) AAC_FA_HACK(sc); } +static void +aac_rkt_clear_istatus(struct aac_softc *sc, int mask) +{ + debug_called(3); + + AAC_SETREG4(sc, AAC_RKT_ODBR, mask); +} + /* * Populate the mailbox and set the command word */ @@ -2186,6 +2636,19 @@ aac_fa_set_mailbox(struct aac_softc *sc, u_int32_t command, AAC_FA_HACK(sc); } +static void +aac_rkt_set_mailbox(struct aac_softc *sc, u_int32_t command, u_int32_t arg0, + u_int32_t arg1, u_int32_t arg2, u_int32_t arg3) +{ + debug_called(4); + + AAC_SETREG4(sc, AAC_RKT_MAILBOX, command); + AAC_SETREG4(sc, AAC_RKT_MAILBOX + 4, arg0); + AAC_SETREG4(sc, AAC_RKT_MAILBOX + 8, arg1); + AAC_SETREG4(sc, AAC_RKT_MAILBOX + 12, arg2); + AAC_SETREG4(sc, AAC_RKT_MAILBOX + 16, arg3); +} + /* * Fetch the immediate command status word */ @@ -2216,6 +2679,14 @@ aac_fa_get_mailbox(struct aac_softc *sc, int mb) return (val); } +static int +aac_rkt_get_mailbox(struct aac_softc *sc, int mb) +{ + debug_called(4); + + return(AAC_GETREG4(sc, AAC_RKT_MAILBOX + (mb * 4))); +} + /* * Set/clear interrupt masks */ @@ -2237,7 +2708,10 @@ aac_rx_set_interrupts(struct aac_softc *sc, int enable) debug(2, "%sable interrupts", enable ? "en" : "dis"); if (enable) { - AAC_SETREG4(sc, AAC_RX_OIMR, ~AAC_DB_INTERRUPTS); + if (sc->flags & AAC_FLAGS_NEW_COMM) + AAC_SETREG4(sc, AAC_RX_OIMR, ~AAC_DB_INT_NEW_COMM); + else + AAC_SETREG4(sc, AAC_RX_OIMR, ~AAC_DB_INTERRUPTS); } else { AAC_SETREG4(sc, AAC_RX_OIMR, ~0); } @@ -2257,6 +2731,105 @@ aac_fa_set_interrupts(struct aac_softc *sc, int enable) } } +static void +aac_rkt_set_interrupts(struct aac_softc *sc, int enable) +{ + debug(2, "%sable interrupts", enable ? "en" : "dis"); + + if (enable) { + if (sc->flags & AAC_FLAGS_NEW_COMM) + AAC_SETREG4(sc, AAC_RKT_OIMR, ~AAC_DB_INT_NEW_COMM); + else + AAC_SETREG4(sc, AAC_RKT_OIMR, ~AAC_DB_INTERRUPTS); + } else { + AAC_SETREG4(sc, AAC_RKT_OIMR, ~0); + } +} + +/* + * New comm. interface: Send command functions + */ +static int +aac_rx_send_command(struct aac_softc *sc, struct aac_command *cm) +{ + u_int32_t index, device; + + debug(2, "send command (new comm.)"); + + index = AAC_GETREG4(sc, AAC_RX_IQUE); + if (index == 0xffffffffL) + index = AAC_GETREG4(sc, AAC_RX_IQUE); + if (index == 0xffffffffL) + return index; + aac_enqueue_busy(cm); + device = index; + AAC_SETREG4(sc, device, (u_int32_t)(cm->cm_fibphys & 0xffffffffUL)); + device += 4; + AAC_SETREG4(sc, device, (u_int32_t)(cm->cm_fibphys >> 32)); + device += 4; + AAC_SETREG4(sc, device, cm->cm_fib->Header.Size); + AAC_SETREG4(sc, AAC_RX_IQUE, index); + return 0; +} + +static int +aac_rkt_send_command(struct aac_softc *sc, struct aac_command *cm) +{ + u_int32_t index, device; + + debug(2, "send command (new comm.)"); + + index = AAC_GETREG4(sc, AAC_RKT_IQUE); + if (index == 0xffffffffL) + index = AAC_GETREG4(sc, AAC_RKT_IQUE); + if (index == 0xffffffffL) + return index; + aac_enqueue_busy(cm); + device = index; + AAC_SETREG4(sc, device, (u_int32_t)(cm->cm_fibphys & 0xffffffffUL)); + device += 4; + AAC_SETREG4(sc, device, (u_int32_t)(cm->cm_fibphys >> 32)); + device += 4; + AAC_SETREG4(sc, device, cm->cm_fib->Header.Size); + AAC_SETREG4(sc, AAC_RKT_IQUE, index); + return 0; +} + +/* + * New comm. interface: get, set outbound queue index + */ +static int +aac_rx_get_outb_queue(struct aac_softc *sc) +{ + debug_called(3); + + return(AAC_GETREG4(sc, AAC_RX_OQUE)); +} + +static int +aac_rkt_get_outb_queue(struct aac_softc *sc) +{ + debug_called(3); + + return(AAC_GETREG4(sc, AAC_RKT_OQUE)); +} + +static void +aac_rx_set_outb_queue(struct aac_softc *sc, int index) +{ + debug_called(3); + + AAC_SETREG4(sc, AAC_RX_OQUE, index); +} + +static void +aac_rkt_set_outb_queue(struct aac_softc *sc, int index) +{ + debug_called(3); + + AAC_SETREG4(sc, AAC_RKT_OQUE, index); +} + /* * Debugging and Diagnostics */ @@ -2272,34 +2845,45 @@ aac_describe_controller(struct aac_softc *sc) debug_called(2); - aac_alloc_sync_fib(sc, &fib, 0); + AAC_LOCK_ACQUIRE(&sc->aac_io_lock); + aac_alloc_sync_fib(sc, &fib); fib->data[0] = 0; if (aac_sync_fib(sc, RequestAdapterInfo, 0, fib, 1)) { device_printf(sc->aac_dev, "RequestAdapterInfo failed\n"); aac_release_sync_fib(sc); + AAC_LOCK_RELEASE(&sc->aac_io_lock); return; } - info = (struct aac_adapter_info *)&fib->data[0]; - - device_printf(sc->aac_dev, "%s %dMHz, %dMB cache memory, %s\n", - aac_describe_code(aac_cpu_variant, info->CpuVariant), - info->ClockSpeed, info->BufferMem / (1024 * 1024), - aac_describe_code(aac_battery_platform, - info->batteryPlatform)); /* save the kernel revision structure for later use */ + info = (struct aac_adapter_info *)&fib->data[0]; sc->aac_revision = info->KernelRevision; - device_printf(sc->aac_dev, "Kernel %d.%d-%d, Build %d, S/N %6X\n", - info->KernelRevision.external.comp.major, - info->KernelRevision.external.comp.minor, - info->KernelRevision.external.comp.dash, - info->KernelRevision.buildNumber, - (u_int32_t)(info->SerialNumber & 0xffffff)); - aac_release_sync_fib(sc); + device_printf(sc->aac_dev, "Adaptec Raid Controller %d.%d.%d-%d\n", + AAC_DRIVER_VERSION >> 24, + (AAC_DRIVER_VERSION >> 16) & 0xFF, + AAC_DRIVER_VERSION & 0xFF, + AAC_DRIVER_BUILD); + + if (bootverbose) { + device_printf(sc->aac_dev, "%s %dMHz, %dMB memory " + "(%dMB cache, %dMB execution), %s\n", + aac_describe_code(aac_cpu_variant, info->CpuVariant), + info->ClockSpeed, info->TotalMem / (1024 * 1024), + info->BufferMem / (1024 * 1024), + info->ExecutionMem / (1024 * 1024), + aac_describe_code(aac_battery_platform, + info->batteryPlatform)); + + device_printf(sc->aac_dev, + "Kernel %d.%d-%d, Build %d, S/N %6X\n", + info->KernelRevision.external.comp.major, + info->KernelRevision.external.comp.minor, + info->KernelRevision.external.comp.dash, + info->KernelRevision.buildNumber, + (u_int32_t)(info->SerialNumber & 0xffffff)); - if (1 || bootverbose) { device_printf(sc->aac_dev, "Supported Options=%b\n", sc->supported_options, "\20" @@ -2315,8 +2899,16 @@ aac_describe_controller(struct aac_softc *sc) "\12NORECOND" "\13SGMAP64" "\14ALARM" - "\15NONDASD"); + "\15NONDASD" + "\16SCSIMGT" + "\17RAIDSCSI" + "\21ADPTINFO" + "\22NEWCOMM" + "\23ARRAY64BIT" + "\24HEATSENSOR"); } + aac_release_sync_fib(sc); + AAC_LOCK_RELEASE(&sc->aac_io_lock); } /* @@ -2380,7 +2972,7 @@ aac_ioctl(struct dev_ioctl_args *ap) caddr_t arg = ap->a_data; struct aac_softc *sc = dev->si_drv1; int error = 0; - int i; + uint32_t cookie; debug_called(2); @@ -2426,11 +3018,11 @@ aac_ioctl(struct dev_ioctl_args *ap) * * The Linux code hands the driver a pointer into kernel space, * and then trusts it when the caller hands it back. Aiee! - * Here, we give it the proc pointer of the per-adapter aif + * Here, we give it the proc pointer of the per-adapter aif * thread. It's only used as a sanity check in other calls. */ - i = (int)sc->aifthread; - error = copyout(&i, arg, sizeof(i)); + cookie = (uint32_t)(uintptr_t)sc->aifthread; + error = copyout(&cookie, arg, sizeof(cookie)); break; case FSACTL_GET_NEXT_ADAPTER_FIB: debug(1, "FSACTL_GET_NEXT_ADAPTER_FIB"); @@ -2447,15 +3039,21 @@ aac_ioctl(struct dev_ioctl_args *ap) case FSACTL_QUERY_DISK: debug(1, "FSACTL_QUERY_DISK"); error = aac_query_disk(sc, arg); - break; + break; case FSACTL_DELETE_DISK: /* * We don't trust the underland to tell us when to delete a - * container, rather we rely on an AIF coming from the + * container, rather we rely on an AIF coming from the * controller */ error = 0; break; + case FSACTL_GET_PCI_INFO: + arg = *(caddr_t*)arg; + case FSACTL_LNX_GET_PCI_INFO: + debug(1, "FSACTL_GET_PCI_INFO"); + error = aac_get_pci_info(sc, arg); + break; default: debug(1, "unsupported cmd 0x%lx\n", ap->a_cmd); error = EINVAL; @@ -2489,6 +3087,27 @@ aac_poll(struct dev_poll_args *ap) return (0); } +static void +aac_ioctl_event(struct aac_softc *sc, struct aac_event *event, void *arg) +{ + + switch (event->ev_type) { + case AAC_EVENT_CMFREE: + AAC_LOCK_ACQUIRE(&sc->aac_io_lock); + if (aac_alloc_command(sc, (struct aac_command **)arg)) { + aac_add_event(sc, event); + AAC_LOCK_RELEASE(&sc->aac_io_lock); + return; + } + kfree(event, M_AACBUF); + wakeup(arg); + AAC_LOCK_RELEASE(&sc->aac_io_lock); + break; + default: + break; + } +} + /* * Send a FIB supplied from userspace */ @@ -2505,10 +3124,24 @@ aac_ioctl_sendfib(struct aac_softc *sc, caddr_t ufib) /* * Get a command */ + AAC_LOCK_ACQUIRE(&sc->aac_io_lock); if (aac_alloc_command(sc, &cm)) { - error = EBUSY; - goto out; + struct aac_event *event; + + event = kmalloc(sizeof(struct aac_event), M_AACBUF, + M_INTWAIT | M_ZERO); + event->ev_type = AAC_EVENT_CMFREE; + event->ev_callback = aac_ioctl_event; + event->ev_arg = &cm; + aac_add_event(sc, event); + crit_enter(); + tsleep_interlock(&cm); + AAC_LOCK_RELEASE(&sc->aac_io_lock); + tsleep(&cm, 0, "sendfib", 0); + AAC_LOCK_ACQUIRE(&sc->aac_io_lock); + crit_exit(); } + AAC_LOCK_RELEASE(&sc->aac_io_lock); /* * Fetch the FIB header, then re-copy to get data as well. @@ -2518,7 +3151,7 @@ aac_ioctl_sendfib(struct aac_softc *sc, caddr_t ufib) goto out; size = cm->cm_fib->Header.Size + sizeof(struct aac_fib_header); if (size > sizeof(struct aac_fib)) { - device_printf(sc->aac_dev, "incoming FIB oversized (%d > %d)\n", + device_printf(sc->aac_dev, "incoming FIB oversized (%d > %zd)\n", size, sizeof(struct aac_fib)); size = sizeof(struct aac_fib); } @@ -2530,26 +3163,32 @@ aac_ioctl_sendfib(struct aac_softc *sc, caddr_t ufib) /* * Pass the FIB to the controller, wait for it to complete. */ - if ((error = aac_wait_command(cm, 30)) != 0) { /* XXX user timeout? */ - kprintf("aac_wait_command return %d\n", error); + AAC_LOCK_ACQUIRE(&sc->aac_io_lock); + if ((error = aac_wait_command(cm)) != 0) { + device_printf(sc->aac_dev, + "aac_wait_command return %d\n", error); goto out; } + AAC_LOCK_RELEASE(&sc->aac_io_lock); /* * Copy the FIB and data back out to the caller. */ size = cm->cm_fib->Header.Size; if (size > sizeof(struct aac_fib)) { - device_printf(sc->aac_dev, "outbound FIB oversized (%d > %d)\n", + device_printf(sc->aac_dev, "outbound FIB oversized (%d > %zd)\n", size, sizeof(struct aac_fib)); size = sizeof(struct aac_fib); } error = copyout(cm->cm_fib, ufib, size); + AAC_LOCK_ACQUIRE(&sc->aac_io_lock); out: if (cm != NULL) { aac_release_command(cm); } + + AAC_LOCK_RELEASE(&sc->aac_io_lock); return(error); } @@ -2580,11 +3219,11 @@ aac_handle_aif(struct aac_softc *sc, struct aac_fib *fib) case AifEnAddContainer: case AifEnDeleteContainer: /* - * A container was added or deleted, but the message + * A container was added or deleted, but the message * doesn't tell us anything else! Re-enumerate the * containers and sort things out. */ - aac_alloc_sync_fib(sc, &fib, 0); + aac_alloc_sync_fib(sc, &fib); mi = (struct aac_mntinfo *)&fib->data[0]; do { /* @@ -2619,7 +3258,7 @@ aac_handle_aif(struct aac_softc *sc, struct aac_fib *fib) (mir->MntTable[0].VolType != CT_NONE)) { found = 0; TAILQ_FOREACH(co, - &sc->aac_container_tqh, + &sc->aac_container_tqh, co_link) { if (co->co_mntobj.ObjectId == mir->MntTable[0].ObjectId) { @@ -2639,7 +3278,8 @@ aac_handle_aif(struct aac_softc *sc, struct aac_fib *fib) /* * This is a new container. Do all the - * appropriate things to set it up. */ + * appropriate things to set it up. + */ aac_add_container(sc, mir, 1); added = 1; } @@ -2657,8 +3297,12 @@ aac_handle_aif(struct aac_softc *sc, struct aac_fib *fib) co = TAILQ_FIRST(&sc->aac_container_tqh); while (co != NULL) { if (co->co_found == 0) { + AAC_LOCK_RELEASE(&sc->aac_io_lock); + get_mplock(); device_delete_child(sc->aac_dev, co->co_disk); + rel_mplock(); + AAC_LOCK_ACQUIRE(&sc->aac_io_lock); co_next = TAILQ_NEXT(co, co_link); AAC_LOCK_ACQUIRE(&sc-> aac_container_lock); @@ -2666,7 +3310,7 @@ aac_handle_aif(struct aac_softc *sc, struct aac_fib *fib) co_link); AAC_LOCK_RELEASE(&sc-> aac_container_lock); - FREE(co, M_AACBUF); + kfree(co, M_AACBUF); co = co_next; } else { co->co_found = 0; @@ -2675,10 +3319,15 @@ aac_handle_aif(struct aac_softc *sc, struct aac_fib *fib) } /* Attach the newly created containers */ - if (added) + if (added) { + AAC_LOCK_RELEASE(&sc->aac_io_lock); + get_mplock(); bus_generic_attach(sc->aac_dev); - - break; + rel_mplock(); + AAC_LOCK_ACQUIRE(&sc->aac_io_lock); + } + + break; default: break; @@ -2763,11 +3412,10 @@ aac_getnext_aif(struct aac_softc *sc, caddr_t arg) /* * Check the magic number that we gave the caller. */ - if (agf.AdapterFibContext != (int)sc->aifthread) { + if (agf.AdapterFibContext != (int)(uintptr_t)sc->aifthread) { error = EFAULT; } else { - crit_enter(); error = aac_return_aif(sc, agf.AifFib); if ((error == EAGAIN) && (agf.Wait)) { @@ -2781,7 +3429,6 @@ aac_getnext_aif(struct aac_softc *sc, caddr_t arg) } sc->aac_state &= ~AAC_STATE_AIF_SLEEPER; } - crit_exit(); } } return(error); @@ -2795,26 +3442,49 @@ aac_getnext_aif(struct aac_softc *sc, caddr_t arg) static int aac_return_aif(struct aac_softc *sc, caddr_t uptr) { - int error; + int next, error; debug_called(2); AAC_LOCK_ACQUIRE(&sc->aac_aifq_lock); if (sc->aac_aifq_tail == sc->aac_aifq_head) { - error = EAGAIN; - } else { - error = copyout(&sc->aac_aifq[sc->aac_aifq_tail], uptr, - sizeof(struct aac_aif_command)); - if (error) - kprintf("aac_return_aif: copyout returned %d\n", error); - if (!error) - sc->aac_aifq_tail = (sc->aac_aifq_tail + 1) % - AAC_AIFQ_LENGTH; + AAC_LOCK_RELEASE(&sc->aac_aifq_lock); + return (EAGAIN); } + + next = (sc->aac_aifq_tail + 1) % AAC_AIFQ_LENGTH; + error = copyout(&sc->aac_aifq[next], uptr, + sizeof(struct aac_aif_command)); + if (error) + device_printf(sc->aac_dev, + "aac_return_aif: copyout returned %d\n", error); + else + sc->aac_aifq_tail = next; + AAC_LOCK_RELEASE(&sc->aac_aifq_lock); return(error); } +static int +aac_get_pci_info(struct aac_softc *sc, caddr_t uptr) +{ + struct aac_pci_info { + u_int32_t bus; + u_int32_t slot; + } pciinf; + int error; + + debug_called(2); + + pciinf.bus = pci_get_bus(sc->aac_dev); + pciinf.slot = pci_get_slot(sc->aac_dev); + + error = copyout((caddr_t)&pciinf, uptr, + sizeof(struct aac_pci_info)); + + return (error); +} + /* * Give the userland some information about the container. The AAC arch * expects the driver to be a SCSI passthrough type driver, so it expects @@ -2847,23 +3517,23 @@ aac_query_disk(struct aac_softc *sc, caddr_t uptr) break; } - if (co == NULL) { + if (co == NULL) { query_disk.Valid = 0; query_disk.Locked = 0; query_disk.Deleted = 1; /* XXX is this right? */ - } else { - disk = device_get_softc(co->co_disk); - query_disk.Valid = 1; - query_disk.Locked = - (disk->ad_flags & AAC_DISK_OPEN) ? 1 : 0; - query_disk.Deleted = 0; - query_disk.Bus = device_get_unit(sc->aac_dev); - query_disk.Target = disk->unit; - query_disk.Lun = 0; - query_disk.UnMapped = 0; - bcopy(disk->ad_dev_t->si_name, - &query_disk.diskDeviceName[0], 10); - } + } else { + disk = device_get_softc(co->co_disk); + query_disk.Valid = 1; + query_disk.Locked = + (disk->ad_flags & AAC_DISK_OPEN) ? 1 : 0; + query_disk.Deleted = 0; + query_disk.Bus = device_get_unit(sc->aac_dev); + query_disk.Target = disk->unit; + query_disk.Lun = 0; + query_disk.UnMapped = 0; + bcopy(disk->ad_dev_t->si_name, + &query_disk.diskDeviceName[0], 10); + } AAC_LOCK_RELEASE(&sc->aac_container_lock); error = copyout((caddr_t)&query_disk, uptr, @@ -2881,11 +3551,12 @@ aac_get_bus_info(struct aac_softc *sc) struct aac_vmioctl *vmi; struct aac_vmi_businf_resp *vmi_resp; struct aac_getbusinf businfo; - struct aac_cam_inf *caminf; + struct aac_sim *caminf; device_t child; int i, found, error; - aac_alloc_sync_fib(sc, &fib, 0); + AAC_LOCK_ACQUIRE(&sc->aac_io_lock); + aac_alloc_sync_fib(sc, &fib); c_cmd = (struct aac_ctcfg *)&fib->data[0]; bzero(c_cmd, sizeof(struct aac_ctcfg)); @@ -2899,6 +3570,7 @@ aac_get_bus_info(struct aac_softc *sc) device_printf(sc->aac_dev, "Error %d sending " "VM_ContainerConfig command\n", error); aac_release_sync_fib(sc); + AAC_LOCK_RELEASE(&sc->aac_io_lock); return; } @@ -2907,6 +3579,7 @@ aac_get_bus_info(struct aac_softc *sc) device_printf(sc->aac_dev, "VM_ContainerConfig returned 0x%x\n", c_resp->Status); aac_release_sync_fib(sc); + AAC_LOCK_RELEASE(&sc->aac_io_lock); return; } @@ -2927,6 +3600,7 @@ aac_get_bus_info(struct aac_softc *sc) device_printf(sc->aac_dev, "Error %d sending VMIoctl command\n", error); aac_release_sync_fib(sc); + AAC_LOCK_RELEASE(&sc->aac_io_lock); return; } @@ -2934,33 +3608,40 @@ aac_get_bus_info(struct aac_softc *sc) if (vmi_resp->Status != ST_OK) { debug(1, "VM_Ioctl returned %d\n", vmi_resp->Status); aac_release_sync_fib(sc); + AAC_LOCK_RELEASE(&sc->aac_io_lock); return; } bcopy(&vmi_resp->BusInf, &businfo, sizeof(struct aac_getbusinf)); aac_release_sync_fib(sc); + AAC_LOCK_RELEASE(&sc->aac_io_lock); found = 0; for (i = 0; i < businfo.BusCount; i++) { if (businfo.BusValid[i] != AAC_BUS_VALID) continue; - MALLOC(caminf, struct aac_cam_inf *, - sizeof(struct aac_cam_inf), M_AACBUF, M_INTWAIT | M_ZERO); + caminf = (struct aac_sim *)kmalloc(sizeof(struct aac_sim), + M_AACBUF, M_INTWAIT | M_ZERO); child = device_add_child(sc->aac_dev, "aacp", -1); if (child == NULL) { - device_printf(sc->aac_dev, "device_add_child failed\n"); - continue; - } + device_printf(sc->aac_dev, + "device_add_child failed for passthrough bus %d\n", + i); + kfree(caminf, M_AACBUF); + break; + }; caminf->TargetsPerBus = businfo.TargetsPerBus; caminf->BusNumber = i; caminf->InitiatorBusId = businfo.InitiatorBusId[i]; caminf->aac_sc = sc; + caminf->sim_dev = child; device_set_ivars(child, caminf); device_set_desc(child, "SCSI Passthrough Bus"); + TAILQ_INSERT_TAIL(&sc->aac_sim_tqh, caminf, sim_link); found = 1; } diff --git a/sys/dev/raid/aac/aac_cam.c b/sys/dev/raid/aac/aac_cam.c index 1f8496f..6e2d1d2 100644 --- a/sys/dev/raid/aac/aac_cam.c +++ b/sys/dev/raid/aac/aac_cam.c @@ -1,4 +1,4 @@ -/* +/*- * Copyright (c) 2002 Adaptec, Inc. * All rights reserved. * @@ -38,6 +38,7 @@ #include #include #include +#include #include #include @@ -47,7 +48,6 @@ #include #include -#include "aac_compat.h" #include #include #include @@ -62,11 +62,10 @@ #include "aacreg.h" #include "aac_ioctl.h" #include "aacvar.h" -#include "aac_cam.h" struct aac_cam { device_t dev; - struct aac_cam_inf *inf; + struct aac_sim *inf; struct cam_sim *sim; struct cam_path *path; }; @@ -80,7 +79,6 @@ static void aac_cam_complete(struct aac_command *); static u_int32_t aac_cam_reset_bus(struct cam_sim *, union ccb *); static u_int32_t aac_cam_abort_ccb(struct cam_sim *, union ccb *); static u_int32_t aac_cam_term_io(struct cam_sim *, union ccb *); -static int aac_cam_get_tran_settings(struct aac_softc *, struct ccb_trans_settings *, u_int32_t); static devclass_t aac_pass_devclass; @@ -102,10 +100,29 @@ MODULE_DEPEND(aacp, cam, 1, 1, 1); MALLOC_DEFINE(M_AACCAM, "aaccam", "AAC CAM info"); +static void +aac_cam_event(struct aac_softc *sc, struct aac_event *event, void *arg) +{ + struct aac_cam *camsc; + + switch (event->ev_type) { + case AAC_EVENT_CMFREE: + camsc = arg; + kfree(event, M_AACCAM); + xpt_release_simq(camsc->sim, 1); + break; + default: + device_printf(sc->aac_dev, "unknown event %d in aac_cam\n", + event->ev_type); + break; + } + + return; +} + static int aac_cam_probe(device_t dev) { - debug_called(2); return (0); @@ -114,6 +131,19 @@ aac_cam_probe(device_t dev) static int aac_cam_detach(device_t dev) { + struct aac_cam *camsc; + debug_called(2); + + camsc = (struct aac_cam *)device_get_softc(dev); + + get_mplock(); + + xpt_async(AC_LOST_DEVICE, camsc->path, NULL); + xpt_free_path(camsc->path); + xpt_bus_deregister(cam_sim_path(camsc->sim)); + cam_sim_free(camsc->sim); + + rel_mplock(); return (0); } @@ -128,12 +158,12 @@ aac_cam_attach(device_t dev) struct cam_sim *sim; struct cam_path *path; struct aac_cam *camsc; - struct aac_cam_inf *inf; + struct aac_sim *inf; debug_called(1); camsc = (struct aac_cam *)device_get_softc(dev); - inf = (struct aac_cam_inf *)device_get_ivars(dev); + inf = (struct aac_sim *)device_get_ivars(dev); camsc->inf = inf; devq = cam_simq_alloc(inf->TargetsPerBus); @@ -220,6 +250,8 @@ aac_cam_action(struct cam_sim *sim, union ccb *ccb) cpi->version_num = 1; cpi->hba_inquiry = PI_WIDE_16; cpi->target_sprt = 0; + + /* Resetting via the passthrough causes problems. */ cpi->hba_misc = PIM_NOBUSRESET; cpi->hba_eng_cnt = 0; cpi->max_target = camsc->inf->TargetsPerBus; @@ -243,12 +275,26 @@ aac_cam_action(struct cam_sim *sim, union ccb *ccb) } case XPT_GET_TRAN_SETTINGS: { - u_int32_t handle; - - handle = AAC_BTL_TO_HANDLE(camsc->inf->BusNumber, - ccb->ccb_h.target_id, ccb->ccb_h.target_lun); - ccb->ccb_h.status = aac_cam_get_tran_settings(sc, &ccb->cts, - handle); +#ifdef CAM_NEW_TRAN_CODE + struct ccb_trans_settings_scsi *scsi = + &ccb->cts.proto_specific.scsi; + struct ccb_trans_settings_spi *spi = + &ccb->cts.xport_specific.spi; + ccb->cts.protocol = PROTO_SCSI; + ccb->cts.protocol_version = SCSI_REV_2; + ccb->cts.transport = XPORT_SPI; + ccb->cts.transport_version = 2; + if (ccb->ccb_h.target_lun != CAM_LUN_WILDCARD) { + scsi->valid = CTS_SCSI_VALID_TQ; + spi->valid |= CTS_SPI_VALID_DISC; + } else { + scsi->valid = 0; + } +#else + ccb->cts.flags &= ~(CCB_TRANS_DISC_ENB | CCB_TRANS_TAG_ENB); + ccb->cts.valid = CCB_TRANS_DISC_VALID | CCB_TRANS_TQ_VALID; +#endif + ccb->ccb_h.status = CAM_REQ_CMP; xpt_done(ccb); return; } @@ -282,10 +328,20 @@ aac_cam_action(struct cam_sim *sim, union ccb *ccb) /* Async ops that require communcation with the controller */ + AAC_LOCK_ACQUIRE(&sc->aac_io_lock); if (aac_alloc_command(sc, &cm)) { + struct aac_event *event; + xpt_freeze_simq(sim, 1); ccb->ccb_h.status = CAM_REQUEUE_REQ; xpt_done(ccb); + event = kmalloc(sizeof(struct aac_event), M_AACCAM, + M_INTWAIT | M_ZERO); + event->ev_callback = aac_cam_event; + event->ev_arg = camsc; + event->ev_type = AAC_EVENT_CMFREE; + aac_add_event(sc, event); + AAC_LOCK_RELEASE(&sc->aac_io_lock); return; } @@ -335,9 +391,14 @@ aac_cam_action(struct cam_sim *sim, union ccb *ccb) if ((ccb->ccb_h.flags & CAM_SCATTER_VALID) == 0) { srb->data_len = csio->dxfer_len; if (ccb->ccb_h.flags & CAM_DATA_PHYS) { + /* + * XXX This isn't 64-bit clean. + * However, this condition is not + * normally used in CAM. + */ srb->sg_map32.SgCount = 1; srb->sg_map32.SgEntry[0].SgAddress = - (u_int32_t)csio->data_ptr; + (uint32_t)(uintptr_t)csio->data_ptr; srb->sg_map32.SgEntry[0].SgByteCount = csio->dxfer_len; } else { @@ -368,6 +429,7 @@ aac_cam_action(struct cam_sim *sim, union ccb *ccb) } else { ccb->ccb_h.status = CAM_REQ_CMP; xpt_done(ccb); + AAC_LOCK_RELEASE(&sc->aac_io_lock); return; } default: @@ -398,6 +460,8 @@ aac_cam_action(struct cam_sim *sim, union ccb *ccb) aac_enqueue_ready(cm); aac_startio(cm->cm_sc); + AAC_LOCK_RELEASE(&sc->aac_io_lock); + return; } @@ -452,7 +516,7 @@ aac_cam_complete(struct aac_command *cm) srbr->sense_len); ccb->csio.sense_len = sense_len; ccb->ccb_h.status |= CAM_AUTOSNS_VALID; - scsi_sense_print(&ccb->csio); + /* scsi_sense_print(&ccb->csio); */ } /* If this is an inquiry command, fake things out */ @@ -478,7 +542,6 @@ aac_cam_complete(struct aac_command *cm) } aac_release_command(cm); - xpt_done(ccb); return; @@ -502,7 +565,8 @@ aac_cam_reset_bus(struct cam_sim *sim, union ccb *ccb) return (CAM_REQ_ABORTED); } - aac_alloc_sync_fib(sc, &fib, 0); + AAC_LOCK_ACQUIRE(&sc->aac_io_lock); + aac_alloc_sync_fib(sc, &fib); vmi = (struct aac_vmioctl *)&fib->data[0]; bzero(vmi, sizeof(struct aac_vmioctl)); @@ -519,13 +583,15 @@ aac_cam_reset_bus(struct cam_sim *sim, union ccb *ccb) e = aac_sync_fib(sc, ContainerCommand, 0, fib, sizeof(struct aac_vmioctl)); if (e) { - device_printf(sc->aac_dev, "Error 0x%x sending passthrough\n", + device_printf(sc->aac_dev,"Error %d sending ResetBus command\n", e); aac_release_sync_fib(sc); + AAC_LOCK_RELEASE(&sc->aac_io_lock); return (CAM_REQ_ABORTED); } aac_release_sync_fib(sc); + AAC_LOCK_RELEASE(&sc->aac_io_lock); return (CAM_REQ_CMP); } @@ -540,57 +606,3 @@ aac_cam_term_io(struct cam_sim *sim, union ccb *ccb) { return (CAM_UA_TERMIO); } - -static int -aac_cam_get_tran_settings(struct aac_softc *sc, struct ccb_trans_settings *cts, u_int32_t handle) -{ - struct aac_fib *fib; - struct aac_vmioctl *vmi; - struct aac_vmi_devinfo_resp *vmi_resp; - int error; - - aac_alloc_sync_fib(sc, &fib, 0); - vmi = (struct aac_vmioctl *)&fib->data[0]; - bzero(vmi, sizeof(struct aac_vmioctl)); - - vmi->Command = VM_Ioctl; - vmi->ObjType = FT_DRIVE; - vmi->MethId = sc->scsi_method_id; - vmi->ObjId = handle; - vmi->IoctlCmd = GetDeviceProbeInfo; - - error = aac_sync_fib(sc, ContainerCommand, 0, fib, - sizeof(struct aac_vmioctl)); - if (error) { - device_printf(sc->aac_dev, "Error %d sending VMIoctl command\n", - error); - aac_release_sync_fib(sc); - return (CAM_REQ_INVALID); - } - - vmi_resp = (struct aac_vmi_devinfo_resp *)&fib->data[0]; - if (vmi_resp->Status != ST_OK) { - debug(1, "VM_Ioctl returned %d\n", vmi_resp->Status); - aac_release_sync_fib(sc); - return (CAM_REQ_CMP_ERR); - } - - cts->bus_width = ((vmi_resp->Inquiry7 & 0x60) >> 5); - if (vmi_resp->ScsiRate) { - cts->sync_period = - scsi_calc_syncparam((10000 / vmi_resp->ScsiRate)); - cts->sync_offset = vmi_resp->ScsiOffset; - } else { - cts->sync_period = 0; - cts->sync_offset = 0; - } - cts->flags &= ~(CCB_TRANS_DISC_ENB | CCB_TRANS_TAG_ENB); - cts->valid = CCB_TRANS_DISC_VALID | - CCB_TRANS_SYNC_RATE_VALID | - CCB_TRANS_SYNC_OFFSET_VALID | - CCB_TRANS_BUS_WIDTH_VALID | - CCB_TRANS_TQ_VALID; - - aac_release_sync_fib(sc); - return (CAM_REQ_CMP); -} diff --git a/sys/dev/raid/aac/aac_cam.h b/sys/dev/raid/aac/aac_cam.h deleted file mode 100644 index 1110d78..0000000 --- a/sys/dev/raid/aac/aac_cam.h +++ /dev/null @@ -1,35 +0,0 @@ -/* - * Copyright (c) 2002 Adaptec, Inc. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - * - * $FreeBSD: src/sys/dev/aac/aac_cam.h,v 1.1.2.1 2002/04/30 22:58:37 scottl Exp $ - * $DragonFly: src/sys/dev/raid/aac/aac_cam.h,v 1.2 2003/06/17 04:28:21 dillon Exp $ - */ - -struct aac_cam_inf { - int TargetsPerBus; - int BusNumber; - int InitiatorBusId; - struct aac_softc *aac_sc; -}; diff --git a/sys/dev/raid/aac/aac_compat.h b/sys/dev/raid/aac/aac_compat.h deleted file mode 100644 index 6dfe1a7..0000000 --- a/sys/dev/raid/aac/aac_compat.h +++ /dev/null @@ -1,42 +0,0 @@ -/*- - * Copyright (c) 2000 Michael Smith - * Copyright (c) 2000 BSDi - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - * - * $FreeBSD: src/sys/dev/aac/aac_compat.h,v 1.2.2.2 2001/09/19 19:09:11 scottl Exp $ - * $DragonFly: src/sys/dev/raid/aac/aac_compat.h,v 1.8 2006/04/30 17:22:16 dillon Exp $ - */ -/* - * Backwards compatibility support. - */ - -/* - * Handle the new/old bio/buf changeover - */ - -#ifdef __DragonFly__ -#include -#include -#include -#endif diff --git a/sys/dev/raid/aac/aac_debug.c b/sys/dev/raid/aac/aac_debug.c index 3ba1a2e..b2c8ddf 100644 --- a/sys/dev/raid/aac/aac_debug.c +++ b/sys/dev/raid/aac/aac_debug.c @@ -39,7 +39,6 @@ #include #include -#include "aac_compat.h" #include #include #include @@ -345,10 +344,10 @@ aac_print_aif(struct aac_softc *sc, struct aac_aif_command *aif) break; case AifEnDiskSetEvent: /* A disk set event occured. */ device_printf(sc->aac_dev, "(DiskSetEvent) event %d " - "diskset %lld creator %lld\n", + "diskset %jd creator %jd\n", aif->data.EN.data.EDS.eventType, - aif->data.EN.data.EDS.DsNum, - aif->data.EN.data.EDS.CreatorId); + (intmax_t)aif->data.EN.data.EDS.DsNum, + (intmax_t)aif->data.EN.data.EDS.CreatorId); break; case AifDenMorphComplete: /* A morph operation * completed */ diff --git a/sys/dev/raid/aac/aac_disk.c b/sys/dev/raid/aac/aac_disk.c index 8987a3a..bf00ec6 100644 --- a/sys/dev/raid/aac/aac_disk.c +++ b/sys/dev/raid/aac/aac_disk.c @@ -35,9 +35,9 @@ #include #include #include +#include #include -#include "aac_compat.h" #include #include #include @@ -204,10 +204,13 @@ aac_disk_strategy(struct dev_strategy_args *ap) } /* perform accounting */ - devstat_start_transaction(&sc->ad_stats); /* pass the bio to the controller - it can work out who we are */ + AAC_LOCK_ACQUIRE(&sc->ad_controller->aac_io_lock); + devstat_start_transaction(&sc->ad_stats); aac_submit_bio(sc, bio); + AAC_LOCK_RELEASE(&sc->ad_controller->aac_io_lock); + return(0); } diff --git a/sys/dev/raid/aac/aac_linux.c b/sys/dev/raid/aac/aac_linux.c index 71fc5d0..e2694f1 100644 --- a/sys/dev/raid/aac/aac_linux.c +++ b/sys/dev/raid/aac/aac_linux.c @@ -34,6 +34,7 @@ #include #include #include +#include #include #include #include diff --git a/sys/dev/raid/aac/aac_pci.c b/sys/dev/raid/aac/aac_pci.c index eebfe7d..7f7cfe6 100644 --- a/sys/dev/raid/aac/aac_pci.c +++ b/sys/dev/raid/aac/aac_pci.c @@ -39,8 +39,8 @@ #include #include #include +#include -#include "aac_compat.h" #include #include #include @@ -110,8 +110,8 @@ static struct aac_ident "Dell PERC 3/Di"}, {0x1011, 0x0046, 0x9005, 0x0364, AAC_HWIF_STRONGARM, 0, "Adaptec AAC-364"}, - {0x1011, 0x0046, 0x9005, 0x0365, AAC_HWIF_STRONGARM, 0, - "Adaptec SCSI RAID 5400S"}, + {0x1011, 0x0046, 0x9005, 0x0365, AAC_HWIF_STRONGARM, + AAC_FLAGS_BROKEN_MEMMAP, "Adaptec SCSI RAID 5400S"}, {0x1011, 0x0046, 0x9005, 0x1364, AAC_HWIF_STRONGARM, AAC_FLAGS_PERC2QC, "Dell PERC 2/QC"}, {0x1011, 0x0046, 0x103c, 0x10c2, AAC_HWIF_STRONGARM, 0, @@ -123,35 +123,110 @@ static struct aac_ident {0x9005, 0x0285, 0x9005, 0x0286, AAC_HWIF_I960RX, AAC_FLAGS_NO4GB, "Adaptec SCSI RAID 2120S"}, {0x9005, 0x0285, 0x9005, 0x0290, AAC_HWIF_I960RX, AAC_FLAGS_NO4GB, - "Adaptec SCSI RAID 2410SA"}, + "Adaptec SATA RAID 2410SA"}, {0x9005, 0x0285, 0x1028, 0x0291, AAC_HWIF_I960RX, AAC_FLAGS_NO4GB, "Dell CERC SATA RAID 2"}, {0x9005, 0x0285, 0x9005, 0x0292, AAC_HWIF_I960RX, AAC_FLAGS_NO4GB, - "Adaptec SCSI RAID 2810SA"}, + "Adaptec SATA RAID 2810SA"}, + {0x9005, 0x0285, 0x9005, 0x0293, AAC_HWIF_I960RX, AAC_FLAGS_NO4GB, + "Adaptec SATA RAID 21610SA"}, + {0x9005, 0x0285, 0x103c, 0x3227, AAC_HWIF_I960RX, AAC_FLAGS_NO4GB, + "HP ML110 G2 (Adaptec 2610SA)"}, + {0x9005, 0x0286, 0x9005, 0x028c, AAC_HWIF_RKT, 0, + "Adaptec SCSI RAID 2230S"}, + {0x9005, 0x0286, 0x9005, 0x028d, AAC_HWIF_RKT, 0, + "Adaptec SCSI RAID 2130S"}, + + {0x9005, 0x0285, 0x9005, 0x0287, AAC_HWIF_I960RX, AAC_FLAGS_NO4GB | + AAC_FLAGS_256FIBS, "Adaptec SCSI RAID 2200S"}, + {0x9005, 0x0285, 0x17aa, 0x0286, AAC_HWIF_I960RX, AAC_FLAGS_NO4GB | + AAC_FLAGS_256FIBS, "Legend S220"}, + {0x9005, 0x0285, 0x17aa, 0x0287, AAC_HWIF_I960RX, AAC_FLAGS_NO4GB | + AAC_FLAGS_256FIBS, "Legend S230"}, + {0x9005, 0x0285, 0x9005, 0x0288, AAC_HWIF_I960RX, 0, + "Adaptec SCSI RAID 3230S"}, + {0x9005, 0x0285, 0x9005, 0x0289, AAC_HWIF_I960RX, 0, + "Adaptec SCSI RAID 3240S"}, + {0x9005, 0x0285, 0x9005, 0x028a, AAC_HWIF_I960RX, 0, + "Adaptec SCSI RAID 2020ZCR"}, + {0x9005, 0x0285, 0x9005, 0x028b, AAC_HWIF_I960RX, 0, + "Adaptec SCSI RAID 2025ZCR"}, + {0x9005, 0x0286, 0x9005, 0x029b, AAC_HWIF_RKT, 0, + "Adaptec SATA RAID 2820SA"}, + {0x9005, 0x0286, 0x9005, 0x029c, AAC_HWIF_RKT, 0, + "Adaptec SATA RAID 2620SA"}, + {0x9005, 0x0286, 0x9005, 0x029d, AAC_HWIF_RKT, 0, + "Adaptec SATA RAID 2420SA"}, + {0x9005, 0x0286, 0x9005, 0x029e, AAC_HWIF_RKT, 0, + "ICP ICP9024RO SCSI RAID"}, + {0x9005, 0x0286, 0x9005, 0x029f, AAC_HWIF_RKT, 0, + "ICP ICP9014RO SCSI RAID"}, + {0x9005, 0x0285, 0x9005, 0x0294, AAC_HWIF_I960RX, 0, + "Adaptec SATA RAID 2026ZCR"}, + {0x9005, 0x0285, 0x103c, 0x3227, AAC_HWIF_I960RX, 0, + "Adaptec SATA RAID 2610SA"}, + {0x9005, 0x0285, 0x9005, 0x0296, AAC_HWIF_I960RX, 0, + "Adaptec SCSI RAID 2240S"}, + {0x9005, 0x0285, 0x9005, 0x0297, AAC_HWIF_I960RX, 0, + "Adaptec SAS RAID 4005SAS"}, + {0x9005, 0x0285, 0x1014, 0x02f2, AAC_HWIF_I960RX, 0, + "IBM ServeRAID 8i"}, + {0x9005, 0x0285, 0x9005, 0x0298, AAC_HWIF_I960RX, 0, + "Adaptec SAS RAID 4000SAS"}, + {0x9005, 0x0285, 0x9005, 0x0299, AAC_HWIF_I960RX, 0, + "Adaptec SAS RAID 4800SAS"}, + {0x9005, 0x0285, 0x9005, 0x029a, AAC_HWIF_I960RX, 0, + "Adaptec SAS RAID 4805SAS"}, + {0x9005, 0x0285, 0x9005, 0x028e, AAC_HWIF_I960RX, 0, + "Adaptec SATA RAID 2020SA ZCR"}, + {0x9005, 0x0285, 0x9005, 0x028f, AAC_HWIF_I960RX, 0, + "Adaptec SATA RAID 2025SA ZCR"}, + {0x9005, 0x0285, 0x9005, 0x02a4, AAC_HWIF_I960RX, 0, + "ICP ICP9085LI SAS RAID"}, + {0x9005, 0x0285, 0x9005, 0x02a5, AAC_HWIF_I960RX, 0, + "ICP ICP5085BR SAS RAID"}, + {0x9005, 0x0286, 0x9005, 0x02a0, AAC_HWIF_RKT, 0, + "ICP ICP9047MA SATA RAID"}, + {0x9005, 0x0286, 0x9005, 0x02a1, AAC_HWIF_RKT, 0, + "ICP ICP9087MA SATA RAID"}, + {0x9005, 0x0285, 0x9005, 0x02bb, AAC_HWIF_I960RX, 0, + "Adaptec RAID 3405"}, + {0x9005, 0x0285, 0x9005, 0x02bc, AAC_HWIF_I960RX, 0, + "Adaptec RAID 3805"}, + {0x9005, 0x0286, 0x1014, 0x9580, AAC_HWIF_RKT, 0, + "IBM ServeRAID-8k"}, {0, 0, 0, 0, 0, 0, 0} }; +static struct aac_ident * +aac_find_ident(device_t dev) +{ + struct aac_ident *m; + + for (m = aac_identifiers; m->vendor != 0; m++) { + if ((m->vendor == pci_get_vendor(dev)) && + (m->device == pci_get_device(dev)) && + (m->subvendor == pci_get_subvendor(dev)) && + (m->subdevice == pci_get_subdevice(dev))) + return (m); + } + + return (NULL); +} + /* * Determine whether this is one of our supported adapters. */ static int aac_pci_probe(device_t dev) { - struct aac_ident *m; + struct aac_ident *id; debug_called(1); - for (m = aac_identifiers; m->vendor != 0; m++) { - if ((m->vendor == pci_get_vendor(dev)) && - (m->device == pci_get_device(dev)) && - ((m->subvendor == 0) || (m->subvendor == - pci_get_subvendor(dev))) && - ((m->subdevice == 0) || ((m->subdevice == - pci_get_subdevice(dev))))) { - - device_set_desc(dev, m->desc); - return(-10); /* allow room to be overridden */ - } + if ((id = aac_find_ident(dev)) != NULL) { + device_set_desc(dev, id->desc); + return(BUS_PROBE_DEFAULT); } return(ENXIO); } @@ -163,7 +238,8 @@ static int aac_pci_attach(device_t dev) { struct aac_softc *sc; - int i, error; + struct aac_ident *id; + int error; u_int32_t command; debug_called(1); @@ -197,12 +273,12 @@ aac_pci_attach(device_t dev) /* * Allocate the PCI register window. */ - sc->aac_regs_rid = 0x10; /* first base address register */ - if ((sc->aac_regs_resource = bus_alloc_resource(sc->aac_dev, - SYS_RES_MEMORY, - &sc->aac_regs_rid, - 0, ~0, 1, - RF_ACTIVE)) == NULL) { + sc->aac_regs_rid = PCIR_BAR(0); + if ((sc->aac_regs_resource = bus_alloc_resource_any(sc->aac_dev, + SYS_RES_MEMORY, + &sc->aac_regs_rid, + RF_ACTIVE)) == + NULL) { device_printf(sc->aac_dev, "couldn't allocate register window\n"); goto out; @@ -210,23 +286,6 @@ aac_pci_attach(device_t dev) sc->aac_btag = rman_get_bustag(sc->aac_regs_resource); sc->aac_bhandle = rman_get_bushandle(sc->aac_regs_resource); - /* - * Allocate and connect our interrupt. - */ - sc->aac_irq_rid = 0; - if ((sc->aac_irq = bus_alloc_resource(sc->aac_dev, SYS_RES_IRQ, - &sc->aac_irq_rid, 0, ~0, 1, - RF_SHAREABLE | - RF_ACTIVE)) == NULL) { - device_printf(sc->aac_dev, "can't allocate interrupt\n"); - goto out; - } - if (bus_setup_intr(sc->aac_dev, sc->aac_irq, 0, - aac_intr, sc, &sc->aac_intr, NULL)) { - device_printf(sc->aac_dev, "can't set up interrupt\n"); - goto out; - } - /* assume failure is 'out of memory' */ error = ENOMEM; @@ -237,11 +296,11 @@ aac_pci_attach(device_t dev) */ if (bus_dma_tag_create(NULL, /* parent */ PAGE_SIZE, 0, /* algnmnt, boundary */ - BUS_SPACE_MAXADDR_32BIT, /* lowaddr */ + BUS_SPACE_MAXADDR, /* lowaddr */ BUS_SPACE_MAXADDR, /* highaddr */ NULL, NULL, /* filter, filterarg */ BUS_SPACE_MAXSIZE_32BIT, /* maxsize */ - AAC_MAXSGENTRIES, /* nsegments */ + BUS_SPACE_UNRESTRICTED, /* nsegments */ BUS_SPACE_MAXSIZE_32BIT, /* maxsegsize */ 0, /* flags */ &sc->aac_parent_dmat)) { @@ -253,49 +312,103 @@ aac_pci_attach(device_t dev) * Detect the hardware interface version, set up the bus interface * indirection. */ - sc->aac_hwif = AAC_HWIF_UNKNOWN; - for (i = 0; aac_identifiers[i].vendor != 0; i++) { - if ((aac_identifiers[i].vendor == pci_get_vendor(dev)) && - (aac_identifiers[i].device == pci_get_device(dev)) && - (aac_identifiers[i].subvendor == pci_get_subvendor(dev)) && - (aac_identifiers[i].subdevice == pci_get_subdevice(dev))) { - sc->aac_hwif = aac_identifiers[i].hwif; - switch(sc->aac_hwif) { - case AAC_HWIF_I960RX: - debug(2, "set hardware up for i960Rx"); - sc->aac_if = aac_rx_interface; - break; - - case AAC_HWIF_STRONGARM: - debug(2, "set hardware up for StrongARM"); - sc->aac_if = aac_sa_interface; - break; - case AAC_HWIF_FALCON: - debug(2, "set hardware up for Falcon/PPC"); - sc->aac_if = aac_fa_interface; - break; - } - - /* Set up quirks */ - sc->flags = aac_identifiers[i].quirks; - - break; - } - } - if (sc->aac_hwif == AAC_HWIF_UNKNOWN) { + id = aac_find_ident(dev); + sc->aac_hwif = id->hwif; + switch(sc->aac_hwif) { + case AAC_HWIF_I960RX: + debug(2, "set hardware up for i960Rx"); + sc->aac_if = aac_rx_interface; + break; + case AAC_HWIF_STRONGARM: + debug(2, "set hardware up for StrongARM"); + sc->aac_if = aac_sa_interface; + break; + case AAC_HWIF_FALCON: + debug(2, "set hardware up for Falcon/PPC"); + sc->aac_if = aac_fa_interface; + break; + case AAC_HWIF_RKT: + debug(2, "set hardware up for Rocket/MIPS"); + sc->aac_if = aac_rkt_interface; + break; + default: + sc->aac_hwif = AAC_HWIF_UNKNOWN; device_printf(sc->aac_dev, "unknown hardware type\n"); error = ENXIO; goto out; } + /* Set up quirks */ + sc->flags = id->quirks; /* * Do bus-independent initialisation. */ error = aac_attach(sc); - + out: if (error) aac_free(sc); return(error); } + +/* + * Do nothing driver that will attach to the SCSI channels of a Dell PERC + * controller. This is needed to keep the power management subsystem from + * trying to power down these devices. + */ +static int aacch_probe(device_t dev); +static int aacch_attach(device_t dev); +static int aacch_detach(device_t dev); + +static device_method_t aacch_methods[] = { + /* Device interface */ + DEVMETHOD(device_probe, aacch_probe), + DEVMETHOD(device_attach, aacch_attach), + DEVMETHOD(device_detach, aacch_detach), + { 0, 0 } +}; + +struct aacch_softc { + device_t dev; +}; + +static driver_t aacch_driver = { + "aacch", + aacch_methods, + sizeof(struct aacch_softc) +}; + +static devclass_t aacch_devclass; +DRIVER_MODULE(aacch, pci, aacch_driver, aacch_devclass, 0, 0); + +static int +aacch_probe(device_t dev) +{ + + if ((pci_get_vendor(dev) != 0x9005) || + (pci_get_device(dev) != 0x00c5)) + return (ENXIO); + + device_set_desc(dev, "AAC RAID Channel"); + return (-10); +} + +static int +aacch_attach(device_t dev) +{ + struct aacch_softc *sc; + + sc = device_get_softc(dev); + + sc->dev = dev; + + return (0); +} + +static int +aacch_detach(device_t dev) +{ + + return (0); +} diff --git a/sys/dev/raid/aac/aac_tables.h b/sys/dev/raid/aac/aac_tables.h index c2e8ca0..42974fa 100644 --- a/sys/dev/raid/aac/aac_tables.h +++ b/sys/dev/raid/aac/aac_tables.h @@ -41,7 +41,7 @@ static struct aac_code_lookup aac_command_status_table[] = { {"I/O error", 5}, {"device not configured", 6}, {"too big", 7}, - {"permission denoed", 13}, + {"permission denied", 13}, {"file exists", 17}, {"cross-device link", 18}, {"operation not supported by device", 19}, @@ -67,7 +67,7 @@ static struct aac_code_lookup aac_command_status_table[] = { {"bad type", 10007}, {"jukebox", 10008}, {"not mounted", 10009}, - {"in maintenace mode", 10010}, + {"in maintenance mode", 10010}, {"stale ACL", 10011}, {NULL, 0}, {"unknown command status", 0} @@ -80,8 +80,12 @@ static struct aac_code_lookup aac_cpu_variant[] = { {"i960CX", CPUI960_CX}, {"i960HX", CPUI960_HX}, {"i960RX", CPUI960_RX}, + {"i960 80303", CPUI960_80303}, {"StrongARM SA110", CPUARM_SA110}, - {"MPC824x", CPUMPC_824x}, + {"PPC603e", CPUPPC_603e}, + {"XScale 80321", CPU_XSCALE_80321}, + {"MIPS 4KC", CPU_MIPS_4KC}, + {"MIPS 5KC", CPU_MIPS_5KC}, {"Unknown StrongARM", CPUARM_xxx}, {"Unknown PowerPC", CPUPPC_xxx}, {NULL, 0}, @@ -113,6 +117,11 @@ static struct aac_code_lookup aac_container_types[] = { {"Volume of Mirrors", CT_VOLUME_OF_MIRRORS}, {"Pseudo RAID 3", CT_PSEUDO_RAID3}, {"RAID 0/5", CT_RAID50}, + {"RAID 5D", CT_RAID5D}, + {"RAID 0/5D", CT_RAID5D0}, + {"RAID 1E", CT_RAID1E}, + {"RAID 6", CT_RAID6}, + {"RAID 0/6", CT_RAID60}, {NULL, 0}, {"unknown", 0} }; diff --git a/sys/dev/raid/aac/aacreg.h b/sys/dev/raid/aac/aacreg.h index de02783..bd5a648 100644 --- a/sys/dev/raid/aac/aacreg.h +++ b/sys/dev/raid/aac/aacreg.h @@ -201,12 +201,17 @@ typedef enum { /* Container Commands */ ContainerCommand = 500, ContainerCommand64 = 501, + RawIo = 502, /* Cluster Commands */ ClusterCommand = 550, /* Scsi Port commands (scsi passthrough) */ ScsiPortCommand = 600, + ScsiPortCommandU64 = 601, + SataPortCommandU64 = 602, + SasSmpPassThrough = 603, + SasRequestPhyInfo = 612, /* misc house keeping and generic adapter initiated commands */ AifRequest = 700, @@ -215,7 +220,21 @@ typedef enum { RequestAdapterInfo = 703, IsAdapterPaused = 704, SendHostTime = 705, - LastMiscCommand = 706 + RequestSupplementAdapterInfo = 706, /* Supp. Info for set in UCC + * use only if supported + * (RequestAdapterInfo first) */ + LastMiscCommand = 707, + + OnLineDiagnostic = 800, + FduAdapterTest = 801, + RequestCompatibilityId = 802, + AdapterEnvironmentInfo = 803, /* temp. sensors */ + NvsramEventLog = 900, + ResetNvsramEventLogPointers = 901, + EnableEventLog = 902, + DisableEventLog = 903, + EncryptedKeyTransportFIB= 904, + KeyableFeaturesFIB= 905 } AAC_FibCommands; /* @@ -271,6 +290,7 @@ typedef enum { struct aac_adapter_init { u_int32_t InitStructRevision; #define AAC_INIT_STRUCT_REVISION 3 +#define AAC_INIT_STRUCT_REVISION_4 4 u_int32_t MiniPortRevision; #define AAC_INIT_STRUCT_MINIPORT_REVISION 1 u_int32_t FilesystemRevision; @@ -285,6 +305,12 @@ struct aac_adapter_init { #define AAC_PAGE_SIZE 4096 u_int32_t HostPhysMemPages; u_int32_t HostElapsedSeconds; + /* ADAPTER_INIT_STRUCT_REVISION_4 begins here */ + u_int32_t InitFlags; /* flags for supported features */ +#define INITFLAGS_NEW_COMM_SUPPORTED 1 + u_int32_t MaxIoCommands; /* max outstanding commands */ + u_int32_t MaxIoSize; /* largest I/O command */ + u_int32_t MaxFibSize; /* largest FIB to adapter */ } __attribute__ ((packed)); typedef u_int32_t aac_phys_addr_t; @@ -311,6 +337,11 @@ typedef enum { CT_VOLUME_OF_MIRRORS, /* volume of mirror */ CT_PSEUDO_RAID3, /* really raid4 */ CT_RAID50, /* stripe of raid5 */ + CT_RAID5D, /* raid5 distributed hot-sparing */ + CT_RAID5D0, + CT_RAID1E, /* extended raid1 mirroring */ + CT_RAID6, + CT_RAID60, } AAC_FSAVolType; /* @@ -344,6 +375,19 @@ struct aac_sg_entry { u_int32_t SgByteCount; } __attribute__ ((packed)); +struct aac_sg_entry64 { + u_int64_t SgAddress; + u_int32_t SgByteCount; +} __packed; + +struct aac_sg_entryraw { + u_int32_t Next; /* reserved for FW use */ + u_int32_t Prev; /* reserved for FW use */ + u_int64_t SgAddress; + u_int32_t SgByteCount; + u_int32_t Flags; /* reserved for FW use */ +} __packed; + struct aac_sg_table { u_int32_t SgCount; struct aac_sg_entry SgEntry[0]; @@ -353,13 +397,19 @@ struct aac_sg_table { * Host-side scatter/gather list for 64-bit commands. */ struct aac_sg_table64 { - u_int8_t SgCount; - u_int8_t SgSectorsPerPage; - u_int16_t SgByteOffset; - u_int64_t SgEntry[0]; + u_int32_t SgCount; + struct aac_sg_entry64 SgEntry64[0]; } __attribute__ ((packed)); /* + * s/g list for raw commands + */ +struct aac_sg_tableraw { + u_int32_t SgCount; + struct aac_sg_entryraw SgEntryRaw[0]; +} __packed; + +/* * Container creation data */ struct aac_container_creation { @@ -417,6 +467,8 @@ typedef enum { CPU_ALPHA, CPU_P7, CPU_I960_RX, + CPU_MIPS, + CPU_XSCALE, CPU__last } AAC_CpuType; @@ -427,8 +479,12 @@ typedef enum { CPUI960_RX, CPUARM_SA110, CPUARM_xxx, - CPUMPC_824x, + CPUPPC_603e, CPUPPC_xxx, + CPUI960_80303, + CPU_XSCALE_80321, + CPU_MIPS_4KC, + CPU_MIPS_5KC, CPUSUBTYPE__last } AAC_CpuSubType; @@ -453,6 +509,20 @@ typedef enum { PLAT_POBLANO_XXX, PLAT_JALAPENO_P2, PLAT_HABANERO, + PLAT_VULCAN, + PLAT_CRUSADER, + PLAT_LANCER, + PLAT_HARRIER, + PLAT_TERMINATOR, + PLAT_SKYHAWK, + PLAT_CORSAIR, + PLAT_JAGUAR, + PLAT_SATAHAWK, + PLAT_SATANATOR, + PLAT_PROWLER, + PLAT_BLACKBIRD, + PLAT_SABREEXPRESS, + PLAT_INTRUDER, PLAT__last } AAC_Platform; @@ -462,9 +532,14 @@ typedef enum { OEM_FLAVOR_HP, OEM_FLAVOR_IBM, OEM_FLAVOR_CPQ, - OEM_FLAVOR_BRAND_X, - OEM_FLAVOR_BRAND_Y, + OEM_FLAVOR_FSC, + OEM_FLAVOR_DWS, OEM_FLAVOR_BRAND_Z, + OEM_FLAVOR_LEGEND, + OEM_FLAVOR_HITACHI, + OEM_FLAVOR_ESG, + OEM_FLAVOR_ICP, + OEM_FLAVOR_SCM, OEM_FLAVOR__last } AAC_OemFlavor; @@ -498,6 +573,12 @@ typedef enum #define AAC_SUPPORTED_SGMAP_HOST64 0x400 #define AAC_SUPPORTED_ALARM 0x800 #define AAC_SUPPORTED_NONDASD 0x1000 +#define AAC_SUPPORTED_SCSI_MANAGED 0x2000 +#define AAC_SUPPORTED_RAID_SCSI_MODE 0x4000 +#define AAC_SUPPORTED_SUPPLEMENT_ADAPTER_INFO 0x10000 +#define AAC_SUPPORTED_NEW_COMM 0x20000 +#define AAC_SUPPORTED_64BIT_ARRAYSIZE 0x40000 +#define AAC_SUPPORTED_HEAT_SENSOR 0x80000 /* * Structure used to respond to a RequestAdapterInfo fib. @@ -533,10 +614,16 @@ struct aac_adapter_info { /* * Synchronous commands to the monitor/kernel. */ +#define AAC_MONKER_BREAKPOINT 0x04 #define AAC_MONKER_INITSTRUCT 0x05 #define AAC_MONKER_SYNCFIB 0x0c #define AAC_MONKER_GETKERNVER 0x11 +#define AAC_MONKER_POSTRESULTS 0x14 #define AAC_MONKER_GETINFO 0x19 +#define AAC_MONKER_GETDRVPROP 0x23 +#define AAC_MONKER_RCVTEMP 0x25 +#define AAC_MONKER_GETCOMMPREF 0x26 +#define AAC_MONKER_REINIT 0xee /* * Adapter Status Register @@ -551,6 +638,7 @@ struct aac_adapter_info { * state of the adapter. */ #define AAC_SELF_TEST_FAILED 0x00000004 +#define AAC_MONITOR_PANIC 0x00000020 #define AAC_UP_AND_RUNNING 0x00000080 #define AAC_KERNEL_PANIC 0x00000100 @@ -656,6 +744,7 @@ typedef enum { AifJobScsiExercise, /* SCSI device Exercise operation */ AifJobScsiVerifyRepair, /* SCSI device Verify operation WITH * repair */ + AifJobScsiWritePattern, /* write pattern */ AifJobScsiMax = 99, /* Max Scsi value */ AifJobCtrMin, /* Min Ctr op value */ AifJobCtrZero, /* Container clear operation */ @@ -669,6 +758,12 @@ typedef enum { AifJobCtrPartCopy, /* Container Partition copy operation */ AifJobCtrRebuildMirror, /* Container Rebuild Mirror operation */ AifJobCtrCrazyCache, /* crazy cache */ + AifJobCtrCopyback, /* Container Copyback operation */ + AifJobCtrCompactRaid5D, /* Container Compaction operation */ + AifJobCtrExpandRaid5D, /* Container Expansion operation */ + AifJobCtrRebuildRaid6, /* Container Rebuild Raid6 operation */ + AifJobCtrScrubRaid6, /* Container Scrub Raid6 operation */ + AifJobCtrSSBackup, /* Container snapshot backup task */ AifJobCtrMax = 199, /* Max Ctr type operation */ AifJobFsMin, /* Min Fs type operation */ AifJobFsCreate, /* File System Create operation */ @@ -851,9 +946,10 @@ struct aac_aif_command { u_int32_t seqNumber; /* To allow ordering of * reports (if necessary) */ union { - struct aac_AifEventNotify EN; /* Event notify structure */ - struct aac_AifJobProgressReport PR[1]; /* Progress report */ - u_int8_t AR[AAC_AIF_REPORT_MAX_SIZE]; + struct aac_AifEventNotify EN; /* Event notify */ + struct aac_AifJobProgressReport PR[1]; /* Progress report */ + u_int8_t AR[AAC_AIF_REPORT_MAX_SIZE]; + u_int8_t data[AAC_FIB_DATASIZE - 8]; } data; } __attribute__ ((packed)); @@ -972,6 +1068,10 @@ typedef enum _VM_COMMANDS { VM_CtBlockRead64, VM_CtBlockWrite64, VM_CtBlockVerify64, + VM_CtHostRead64, + VM_CtHostWrite64, + VM_DrvErrTblLog, /* drive error table/log type of command */ + VM_NameServe64 } AAC_VMCommand; /* @@ -1066,8 +1166,15 @@ struct aac_vmi_businf_resp { struct aac_getbusinf BusInf; } __attribute__ ((packed)); +#if 0 #define AAC_BTL_TO_HANDLE(b, t, l) \ (((b & 0x3f) << 7) | ((l & 0x7) << 4) | (t & 0xf)) +#else +#define AAC_BTL_TO_HANDLE(b, t, l) \ + ((((u_int32_t)b & 0x0f) << 24) | \ + (((u_int32_t)l & 0xff) << 16) | \ + ((u_int32_t)t & 0xffff)) +#endif #define GetDeviceProbeInfo 0x5 struct aac_vmi_devinfo_resp { @@ -1145,6 +1252,16 @@ struct aac_blockread { struct aac_sg_table SgMap; /* variable size */ } __attribute__ ((packed)); +struct aac_blockread64 { + u_int32_t Command; + u_int16_t ContainerId; + u_int16_t SectorCount; + u_int32_t BlockNumber; + u_int16_t Pad; + u_int16_t Flags; + struct aac_sg_table64 SgMap64; +} __packed; + struct aac_blockread_response { u_int32_t Status; u_int32_t ByteCount; @@ -1159,12 +1276,32 @@ struct aac_blockwrite { struct aac_sg_table SgMap; /* variable size */ } __attribute__ ((packed)); +struct aac_blockwrite64 { + u_int32_t Command; /* not FSACommand! */ + u_int16_t ContainerId; + u_int16_t SectorCount; + u_int32_t BlockNumber; + u_int16_t Pad; + u_int16_t Flags; + struct aac_sg_table64 SgMap64; /* variable size */ +} __packed; + struct aac_blockwrite_response { u_int32_t Status; u_int32_t ByteCount; u_int32_t Committed; } __attribute__ ((packed)); +struct aac_raw_io { + u_int64_t BlockNumber; + u_int32_t ByteCount; + u_int16_t ContainerId; + u_int16_t Flags; /* 0: W, 1: R */ + u_int16_t BpTotal; /* reserved for FW use */ + u_int16_t BpComplete; /* reserved for FW use */ + struct aac_sg_tableraw SgMapRaw; /* variable size */ +} __packed; + /* * Container shutdown command. */ @@ -1231,6 +1368,11 @@ struct aac_srb_response { u_int8_t sense[AAC_HOST_SENSE_DATA_MAX]; }; +/* + * Status codes for SCSI passthrough commands. Since they are based on ASPI, + * they also exactly match CAM status codes in both enumeration and meaning. + * They seem to also be used as status codes for synchronous FIBs. + */ enum { AAC_SRB_STS_PENDING = 0x00, AAC_SRB_STS_SUCCESS, @@ -1309,11 +1451,30 @@ enum { #define AAC_RX_ODBR 0x2c /* outbound doorbell register */ #define AAC_RX_OISR 0x30 /* outbound interrupt status register */ #define AAC_RX_OIMR 0x34 /* outbound interrupt mask register */ +#define AAC_RX_IQUE 0x40 /* inbound queue */ +#define AAC_RX_OQUE 0x44 /* outbound queue */ #define AAC_RX_MAILBOX 0x50 /* mailbox (20 bytes) */ #define AAC_RX_FWSTATUS 0x6c /* + * Register definitions for the Adaptec 'Rocket' RAID-On-Chip adapters. + * Unsurprisingly, it's quite similar to the i960! + */ + +#define AAC_RKT_IDBR 0x20 /* inbound doorbell register */ +#define AAC_RKT_IISR 0x24 /* inbound interrupt status register */ +#define AAC_RKT_IIMR 0x28 /* inbound interrupt mask register */ +#define AAC_RKT_ODBR 0x2c /* outbound doorbell register */ +#define AAC_RKT_OISR 0x30 /* outbound interrupt status register */ +#define AAC_RKT_OIMR 0x34 /* outbound interrupt mask register */ +#define AAC_RKT_IQUE 0x40 /* inbound queue */ +#define AAC_RKT_OQUE 0x44 /* outbound queue */ + +#define AAC_RKT_MAILBOX 0x1000 /* mailbox */ +#define AAC_RKT_FWSTATUS 0x101c /* Firmware Status (mailbox 7) */ + +/* * Common bit definitions for the doorbell registers. */ @@ -1343,3 +1504,5 @@ enum { #define AAC_DB_INTERRUPTS (AAC_DB_COMMAND_READY | \ AAC_DB_RESPONSE_READY | \ AAC_DB_PRINTF) +#define AAC_DB_INT_NEW_COMM 0x08 + diff --git a/sys/dev/raid/aac/aacvar.h b/sys/dev/raid/aac/aacvar.h index 3d3cb7b..b15a50c 100644 --- a/sys/dev/raid/aac/aacvar.h +++ b/sys/dev/raid/aac/aacvar.h @@ -30,6 +30,12 @@ * $DragonFly: src/sys/dev/raid/aac/aacvar.h,v 1.19 2007/11/10 19:50:29 swildner Exp $ */ +#include +#include +#include +#include +#include +#include #include /* @@ -48,13 +54,11 @@ #define AAC_ADAPTER_FIBS 8 /* - * FIBs are allocated up-front, and the pool isn't grown. We should allocate - * enough here to let us keep the adapter busy without wasting large amounts - * of kernel memory. The current interface implementation limits us to 512 - * FIBs queued for the adapter at any one time. + * FIBs are allocated in page-size chunks and can grow up to the 512 + * limit imposed by the hardware. */ -#define AAC_FIB_COUNT 128 - +#define AAC_PREALLOCATE_FIBS 128 +#define AAC_NUM_MGT_FIB 8 /* * The controller reports status events in AIFs. We hang on to a number of * these in order to pass them out to user-space management tools. @@ -94,14 +98,6 @@ #define AAC_DISK_MAJOR 200 /* - * Driver Variable Definitions - */ - -#if defined(__FreeBSD__) && __FreeBSD_version >= 500005 -# include -#endif - -/* * Per-container data structure */ struct aac_container @@ -113,6 +109,19 @@ struct aac_container }; /* + * Per-SIM data structure + */ +struct aac_sim +{ + device_t sim_dev; + int TargetsPerBus; + int BusNumber; + int InitiatorBusId; + struct aac_softc *aac_sc; + TAILQ_ENTRY(aac_sim) sim_link; +}; + +/* * Per-disk structure */ struct aac_disk @@ -143,7 +152,7 @@ struct aac_command struct aac_fib *cm_fib; /* FIB associated with this * command */ - u_int32_t cm_fibphys; /* bus address of the FIB */ + u_int64_t cm_fibphys; /* bus address of the FIB */ struct buf *cm_data; /* pointer to data in kernel * space */ u_int32_t cm_datalen; /* data length */ @@ -163,12 +172,24 @@ struct aac_command #define AAC_ON_AACQ_READY (1<<6) #define AAC_ON_AACQ_BUSY (1<<7) #define AAC_ON_AACQ_COMPLETE (1<<8) -#define AAC_ON_AACQ_MASK ((1<<5)|(1<<6)|(1<<7)|(1<<8)) +#define AAC_ON_AACQ_NORM (1<<10) +#define AAC_ON_AACQ_AIF (1<<11) +#define AAC_ON_AACQ_MASK ((1<<5)|(1<<6)|(1<<7)|(1<<8)|(1<<10)|(1<11)) +#define AAC_QUEUE_FRZN (1<<9) /* Freeze the processing of + * commands on the queue. */ void (* cm_complete)(struct aac_command *cm); void *cm_private; time_t cm_timestamp; /* command creation time */ int cm_queue; + int cm_index; +}; + +struct aac_fibmap { + TAILQ_ENTRY(aac_fibmap) fm_link; /* list linkage */ + struct aac_fib *aac_fibs; + bus_dmamap_t aac_fibmap; + struct aac_command *aac_commands; }; /* @@ -216,10 +237,14 @@ struct aac_interface u_int32_t arg2, u_int32_t arg3); int (*aif_get_mailbox)(struct aac_softc *sc, int mb); void (*aif_set_interrupts)(struct aac_softc *sc, int enable); + int (*aif_send_command)(struct aac_softc *sc, struct aac_command *cm); + int (*aif_get_outb_queue)(struct aac_softc *sc); + void (*aif_set_outb_queue)(struct aac_softc *sc, int index); }; extern struct aac_interface aac_rx_interface; extern struct aac_interface aac_sa_interface; extern struct aac_interface aac_fa_interface; +extern struct aac_interface aac_rkt_interface; #define AAC_GET_FWSTATUS(sc) ((sc)->aac_if.aif_get_fwstatus((sc))) #define AAC_QNOTIFY(sc, qbit) ((sc)->aac_if.aif_qnotify((sc), (qbit))) @@ -235,6 +260,9 @@ extern struct aac_interface aac_fa_interface; 0)) #define AAC_UNMASK_INTERRUPTS(sc) ((sc)->aac_if.aif_set_interrupts((sc), \ 1)) +#define AAC_SEND_COMMAND(sc, cm) ((sc)->aac_if.aif_send_command((sc), (cm))) +#define AAC_GET_OUTB_QUEUE(sc) ((sc)->aac_if.aif_get_outb_queue((sc))) +#define AAC_SET_OUTB_QUEUE(sc, idx) ((sc)->aac_if.aif_set_outb_queue((sc), (idx))) #define AAC_SETREG4(sc, reg, val) bus_space_write_4(sc->aac_btag, \ sc->aac_bhandle, reg, val) @@ -249,24 +277,11 @@ extern struct aac_interface aac_fa_interface; #define AAC_GETREG1(sc, reg) bus_space_read_1 (sc->aac_btag, \ sc->aac_bhandle, reg) -TAILQ_HEAD(aac_container_tq, aac_container); - /* Define the OS version specific locks */ -#if defined(__FreeBSD__) && __FreeBSD_version >= 500005 -#include -#include -typedef struct mtx aac_lock_t; -#define AAC_LOCK_INIT(l, s) mtx_init(l, s, MTX_DEF) -#define AAC_LOCK_ACQUIRE(l) mtx_lock(l) -#define AAC_LOCK_RELEASE(l) mtx_unlock(l) -#else typedef struct lock aac_lock_t; -#define AAC_LOCK_INIT(l, s) lockinit(l, "aac", 0, 0) -#define AAC_LOCK_ACQUIRE(l) lockmgr(l, LK_EXCLUSIVE|LK_RETRY) +#define AAC_LOCK_INIT(l, s) lockinit(l, s, 0, LK_EXCLUSIVE|LK_CANRECURSE) +#define AAC_LOCK_ACQUIRE(l) lockmgr(l, LK_EXCLUSIVE) #define AAC_LOCK_RELEASE(l) lockmgr(l, LK_RELEASE) -#endif - -#include /* * Per-controller structure. @@ -287,6 +302,7 @@ struct aac_softc struct resource *aac_irq; /* interrupt */ int aac_irq_rid; void *aac_intr; /* interrupt handle */ + eventhandler_tag eh; /* controller features, limits and status */ int aac_state; @@ -300,7 +316,8 @@ struct aac_softc int aac_hwif; #define AAC_HWIF_I960RX 0 #define AAC_HWIF_STRONGARM 1 -#define AAC_HWIF_FALCON 2 +#define AAC_HWIF_FALCON 2 +#define AAC_HWIF_RKT 3 #define AAC_HWIF_UNKNOWN -1 bus_dma_tag_t aac_common_dmat; /* common structure * DMA tag */ @@ -312,10 +329,9 @@ struct aac_softc /* command/fib resources */ bus_dma_tag_t aac_fib_dmat; /* DMA tag for allocing FIBs */ - struct aac_fib *aac_fibs; - bus_dmamap_t aac_fibmap; - u_int32_t aac_fibphys; - struct aac_command aac_command[AAC_FIB_COUNT]; + TAILQ_HEAD(,aac_fibmap) aac_fibmap_tqh; + u_int total_fibs; + struct aac_command *aac_commands; /* command management */ TAILQ_HEAD(,aac_command) aac_free; /* command structures @@ -325,6 +341,11 @@ struct aac_softc TAILQ_HEAD(,aac_command) aac_busy; TAILQ_HEAD(,aac_command) aac_complete; /* commands which have been * returned by the controller */ + TAILQ_HEAD(,aac_command) aac_aif; +#if 0 + TAILQ_HEAD(,aac_command) aac_norm; +#endif + TAILQ_HEAD(,aac_event) aac_ev_cmfree; struct bio_queue_head aac_bioq; struct aac_queue_table *aac_queues; struct aac_queue_entry *aac_qentries[AAC_QUEUE_COUNT]; @@ -332,18 +353,18 @@ struct aac_softc struct aac_qstat aac_qstat[AACQ_COUNT]; /* queue statistics */ /* connected containters */ - struct aac_container_tq aac_container_tqh; + TAILQ_HEAD(,aac_container) aac_container_tqh; aac_lock_t aac_container_lock; - /* Protect the sync fib */ -#define AAC_SYNC_LOCK_FORCE (1 << 0) - aac_lock_t aac_sync_lock; + /* + * The general I/O lock. This protects the sync fib, the lists, the + * queues, and the registers. + */ + aac_lock_t aac_io_lock; /* delayed activity infrastructure */ -#if defined(__FreeBSD__) && __FreeBSD_version >= 500005 struct task aac_task_complete; /* deferred-completion * task */ -#endif struct intr_config_hook aac_ich; /* management interface */ @@ -356,23 +377,61 @@ struct aac_softc struct thread *aifthread; int aifflags; #define AAC_AIFFLAGS_RUNNING (1 << 0) -#define AAC_AIFFLAGS_PENDING (1 << 1) +#define AAC_AIFFLAGS_AIF (1 << 1) #define AAC_AIFFLAGS_EXIT (1 << 2) #define AAC_AIFFLAGS_EXITED (1 << 3) +#define AAC_AIFFLAGS_PRINTF (1 << 4) +#define AAC_AIFFLAGS_ALLOCFIBS (1 << 5) +#define AAC_AIFFLAGS_PENDING (AAC_AIFFLAGS_AIF | AAC_AIFFLAGS_PRINTF | \ + AAC_AIFFLAGS_ALLOCFIBS) u_int32_t flags; #define AAC_FLAGS_PERC2QC (1 << 0) #define AAC_FLAGS_ENABLE_CAM (1 << 1) /* No SCSI passthrough */ #define AAC_FLAGS_CAM_NORESET (1 << 2) /* Fake SCSI resets */ #define AAC_FLAGS_CAM_PASSONLY (1 << 3) /* Only create pass devices */ +#define AAC_FLAGS_SG_64BIT (1 << 4) /* Use 64-bit S/G addresses */ #define AAC_FLAGS_4GB_WINDOW (1 << 5) /* Device can access host mem * 2GB-4GB range */ #define AAC_FLAGS_NO4GB (1 << 6) /* Can't access host mem >2GB */ #define AAC_FLAGS_256FIBS (1 << 7) /* Can only do 256 commands */ +#define AAC_FLAGS_BROKEN_MEMMAP (1 << 8) /* Broken HostPhysMemPages */ +#define AAC_FLAGS_SLAVE (1 << 9) +#define AAC_FLAGS_MASTER (1 << 10) +#define AAC_FLAGS_NEW_COMM (1 << 11) /* New comm. interface supported */ +#define AAC_FLAGS_RAW_IO (1 << 12) /* Raw I/O interface */ +#define AAC_FLAGS_ARRAY_64BIT (1 << 13) /* 64-bit array size */ u_int32_t supported_options; u_int32_t scsi_method_id; + TAILQ_HEAD(,aac_sim) aac_sim_tqh; + + u_int32_t aac_max_fibs; /* max. FIB count */ + u_int32_t aac_max_fibs_alloc; /* max. alloc. per alloc_commands() */ + u_int32_t aac_max_fib_size; /* max. FIB size */ + u_int32_t aac_sg_tablesize; /* max. sg count from host */ + u_int32_t aac_max_sectors; /* max. I/O size from host (blocks) */ +}; + +/* + * Event callback mechanism for the driver + */ +#define AAC_EVENT_NONE 0x00 +#define AAC_EVENT_CMFREE 0x01 +#define AAC_EVENT_MASK 0xff +#define AAC_EVENT_REPEAT 0x100 + +typedef void aac_event_cb_t(struct aac_softc *sc, struct aac_event *event, + void *arg); +struct aac_event { + TAILQ_ENTRY(aac_event) ev_links; + int ev_type; + aac_event_cb_t *ev_callback; + void *ev_arg; }; +#ifndef AAC_DRIVER_BUILD +# define AAC_DRIVER_BUILD 1 +#endif /* * Public functions @@ -382,7 +441,8 @@ extern int aac_attach(struct aac_softc *sc); extern int aac_detach(device_t dev); extern int aac_suspend(device_t dev); extern int aac_resume(device_t dev); -extern void aac_intr(void *arg); +extern void aac_new_intr(void *arg); +extern void aac_fast_intr(void *arg); extern devclass_t aac_devclass; extern void aac_submit_bio(struct aac_disk *ad, struct bio *bio); extern void aac_biodone(struct bio *bio, const char *code); @@ -393,12 +453,11 @@ extern void aac_startio(struct aac_softc *sc); extern int aac_alloc_command(struct aac_softc *sc, struct aac_command **cmp); extern void aac_release_command(struct aac_command *cm); -extern int aac_alloc_sync_fib(struct aac_softc *sc, - struct aac_fib **fib, int flags); -extern void aac_release_sync_fib(struct aac_softc *sc); extern int aac_sync_fib(struct aac_softc *sc, u_int32_t command, u_int32_t xferstate, struct aac_fib *fib, u_int16_t datasize); +extern void aac_add_event(struct aac_softc *sc, struct aac_event + *event); /* * Debugging levels: @@ -468,7 +527,6 @@ aac_initq_ ## name (struct aac_softc *sc) \ static __inline void \ aac_enqueue_ ## name (struct aac_command *cm) \ { \ - crit_enter(); \ if ((cm->cm_flags & AAC_ON_AACQ_MASK) != 0) { \ kprintf("command %p is on another queue, flags = %#x\n", \ cm, cm->cm_flags); \ @@ -477,12 +535,10 @@ aac_enqueue_ ## name (struct aac_command *cm) \ TAILQ_INSERT_TAIL(&cm->cm_sc->aac_ ## name, cm, cm_link); \ cm->cm_flags |= AAC_ON_ ## index; \ AACQ_ADD(cm->cm_sc, index); \ - crit_exit(); \ } \ static __inline void \ aac_requeue_ ## name (struct aac_command *cm) \ { \ - crit_enter(); \ if ((cm->cm_flags & AAC_ON_AACQ_MASK) != 0) { \ kprintf("command %p is on another queue, flags = %#x\n", \ cm, cm->cm_flags); \ @@ -491,14 +547,12 @@ aac_requeue_ ## name (struct aac_command *cm) \ TAILQ_INSERT_HEAD(&cm->cm_sc->aac_ ## name, cm, cm_link); \ cm->cm_flags |= AAC_ON_ ## index; \ AACQ_ADD(cm->cm_sc, index); \ - crit_exit(); \ } \ static __inline struct aac_command * \ aac_dequeue_ ## name (struct aac_softc *sc) \ { \ struct aac_command *cm; \ \ - crit_enter(); \ if ((cm = TAILQ_FIRST(&sc->aac_ ## name)) != NULL) { \ if ((cm->cm_flags & AAC_ON_ ## index) == 0) { \ kprintf("command %p not in queue, flags = %#x, " \ @@ -510,13 +564,11 @@ aac_dequeue_ ## name (struct aac_softc *sc) \ cm->cm_flags &= ~AAC_ON_ ## index; \ AACQ_REMOVE(sc, index); \ } \ - crit_exit(); \ return(cm); \ } \ static __inline void \ aac_remove_ ## name (struct aac_command *cm) \ { \ - crit_enter(); \ if ((cm->cm_flags & AAC_ON_ ## index) == 0) { \ kprintf("command %p not in queue, flags = %#x, " \ "bit = %#x\n", cm, cm->cm_flags, \ @@ -526,7 +578,6 @@ aac_remove_ ## name (struct aac_command *cm) \ TAILQ_REMOVE(&cm->cm_sc->aac_ ## name, cm, cm_link); \ cm->cm_flags &= ~AAC_ON_ ## index; \ AACQ_REMOVE(cm->cm_sc, index); \ - crit_exit(); \ } \ struct hack @@ -548,10 +599,8 @@ aac_initq_bio(struct aac_softc *sc) static __inline void aac_enqueue_bio(struct aac_softc *sc, struct bio *bio) { - crit_enter(); bioq_insert_tail(&sc->aac_bioq, bio); AACQ_ADD(sc, AACQ_BIO); - crit_exit(); } static __inline struct bio * @@ -559,12 +608,10 @@ aac_dequeue_bio(struct aac_softc *sc) { struct bio *bio; - crit_enter(); if ((bio = bioq_first(&sc->aac_bioq)) != NULL) { bioq_remove(&sc->aac_bioq, bio); AACQ_REMOVE(sc, AACQ_BIO); } - crit_exit(); return(bio); } @@ -577,5 +624,23 @@ aac_print_printf(struct aac_softc *sc) */ device_printf(sc->aac_dev, "**Monitor** %.*s", AAC_PRINTF_BUFSIZE, sc->aac_common->ac_printf); + sc->aac_common->ac_printf[0] = 0; AAC_QNOTIFY(sc, AAC_DB_PRINTF); } + +static __inline int +aac_alloc_sync_fib(struct aac_softc *sc, struct aac_fib **fib) +{ + + KKASSERT(lockstatus(&sc->aac_io_lock, curthread) != 0); + *fib = &sc->aac_common->ac_sync_fib; + return (0); +} + +static __inline void +aac_release_sync_fib(struct aac_softc *sc) +{ + + KKASSERT(lockstatus(&sc->aac_io_lock, curthread) != 0); +} +