diff options
Diffstat (limited to 'sys/dev/ciss/ciss.c')
-rw-r--r-- | sys/dev/ciss/ciss.c | 481 |
1 files changed, 388 insertions, 93 deletions
diff --git a/sys/dev/ciss/ciss.c b/sys/dev/ciss/ciss.c index 5e4bf4c..58c590c 100644 --- a/sys/dev/ciss/ciss.c +++ b/sys/dev/ciss/ciss.c @@ -102,8 +102,8 @@ #include <dev/pci/pcivar.h> #include <dev/ciss/cissreg.h> -#include <dev/ciss/cissvar.h> #include <dev/ciss/cissio.h> +#include <dev/ciss/cissvar.h> MALLOC_DEFINE(CISS_MALLOC_CLASS, "ciss_data", "ciss internal data buffers"); @@ -116,6 +116,8 @@ static int ciss_shutdown(device_t dev); /* (de)initialisation functions, control wrappers */ static int ciss_init_pci(struct ciss_softc *sc); +static int ciss_setup_msix(struct ciss_softc *sc); +static int ciss_init_perf(struct ciss_softc *sc); static int ciss_wait_adapter(struct ciss_softc *sc); static int ciss_flush_adapter(struct ciss_softc *sc); static int ciss_init_requests(struct ciss_softc *sc); @@ -137,11 +139,13 @@ static void ciss_kill_notify_thread(struct ciss_softc *sc); /* request submission/completion */ static int ciss_start(struct ciss_request *cr); -static void ciss_done(struct ciss_softc *sc); +static void ciss_done(struct ciss_softc *sc, cr_qhead_t *qh); +static void ciss_perf_done(struct ciss_softc *sc, cr_qhead_t *qh); static void ciss_intr(void *arg); -static void ciss_complete(struct ciss_softc *sc); -static int ciss_report_request(struct ciss_request *cr, int *command_status, - int *scsi_status); +static void ciss_perf_intr(void *arg); +static void ciss_perf_msi_intr(void *arg); +static void ciss_complete(struct ciss_softc *sc, cr_qhead_t *qh); +static int _ciss_report_request(struct ciss_request *cr, int *command_status, int *scsi_status, const char *func); static int ciss_synch_request(struct ciss_request *cr, int timeout); static int ciss_poll_request(struct ciss_request *cr, int timeout); static int ciss_wait_request(struct ciss_request *cr, int timeout); @@ -250,6 +254,24 @@ TUNABLE_INT("hw.ciss.expose_hidden_physical", &ciss_expose_hidden_physical); static unsigned int ciss_nop_message_heartbeat = 0; TUNABLE_INT("hw.ciss.nop_message_heartbeat", &ciss_nop_message_heartbeat); +/* + * This tunable can force a particular transport to be used: + * <= 0 : use default + * 1 : force simple + * 2 : force performant + */ +static int ciss_force_transport = 0; +TUNABLE_INT("hw.ciss.force_transport", &ciss_force_transport); + +/* + * This tunable can force a particular interrupt delivery method to be used: + * <= 0 : use default + * 1 : force INTx + * 2 : force MSIX + */ +static int ciss_force_interrupt = 0; +TUNABLE_INT("hw.ciss.force_interrupt", &ciss_force_interrupt); + /************************************************************************ * CISS adapters amazingly don't have a defined programming interface * value. (One could say some very despairing things about PCI and @@ -422,8 +444,6 @@ ciss_attach(device_t dev) * Initialise driver queues. */ ciss_initq_free(sc); - ciss_initq_busy(sc); - ciss_initq_complete(sc); ciss_initq_notify(sc); mtx_init(&sc->ciss_mtx, "cissmtx", NULL, MTX_DEF); callout_init_mtx(&sc->ciss_periodic, &sc->ciss_mtx, 0); @@ -558,7 +578,9 @@ static int ciss_init_pci(struct ciss_softc *sc) { uintptr_t cbase, csize, cofs; + uint32_t method, supported_methods; int error; + void *intr; debug_called(1); @@ -611,6 +633,12 @@ ciss_init_pci(struct ciss_softc *sc) debug(1, "config struct at %p", sc->ciss_cfg); /* + * Calculate the number of request structures/commands we are + * going to provide for this adapter. + */ + sc->ciss_max_requests = min(CISS_MAX_REQUESTS, sc->ciss_cfg->max_outstanding_commands); + + /* * Validate the config structure. If we supported other transport * methods, we could select amongst them at this point in time. */ @@ -622,14 +650,49 @@ ciss_init_pci(struct ciss_softc *sc) } /* - * Put the board into simple mode, and tell it we're using the low - * 4GB of RAM. Set the default interrupt coalescing options. + * Select the mode of operation, prefer Performant. */ - if (!(sc->ciss_cfg->supported_methods & CISS_TRANSPORT_METHOD_SIMPLE)) { - ciss_printf(sc, "adapter does not support 'simple' transport layer\n"); + if (!(sc->ciss_cfg->supported_methods & + (CISS_TRANSPORT_METHOD_SIMPLE | CISS_TRANSPORT_METHOD_PERF))) { + ciss_printf(sc, "No supported transport layers: 0x%x\n", + sc->ciss_cfg->supported_methods); + return(ENXIO); + } + + switch (ciss_force_transport) { + case 1: + supported_methods = CISS_TRANSPORT_METHOD_SIMPLE; + break; + case 2: + supported_methods = CISS_TRANSPORT_METHOD_PERF; + break; + default: + supported_methods = sc->ciss_cfg->supported_methods; + break; + } + +setup: + if (supported_methods & CISS_TRANSPORT_METHOD_PERF) { + method = CISS_TRANSPORT_METHOD_PERF; + sc->ciss_perf = (struct ciss_perf_config *)(cbase + cofs + + sc->ciss_cfg->transport_offset); + if (ciss_init_perf(sc)) { + supported_methods &= ~method; + goto setup; + } + } else if (supported_methods & CISS_TRANSPORT_METHOD_SIMPLE) { + method = CISS_TRANSPORT_METHOD_SIMPLE; + } else { + ciss_printf(sc, "No supported transport methods: 0x%x\n", + sc->ciss_cfg->supported_methods); return(ENXIO); } - sc->ciss_cfg->requested_method = CISS_TRANSPORT_METHOD_SIMPLE; + + /* + * Tell it we're using the low 4GB of RAM. Set the default interrupt + * coalescing options. + */ + sc->ciss_cfg->requested_method = method; sc->ciss_cfg->command_physlimit = 0; sc->ciss_cfg->interrupt_coalesce_delay = CISS_INTERRUPT_COALESCE_DELAY; sc->ciss_cfg->interrupt_coalesce_count = CISS_INTERRUPT_COALESCE_COUNT; @@ -643,11 +706,15 @@ ciss_init_pci(struct ciss_softc *sc) CISS_TL_SIMPLE_READ(sc, CISS_TL_SIMPLE_IDBR)); return(ENXIO); } - if (!(sc->ciss_cfg->active_method != CISS_TRANSPORT_METHOD_SIMPLE)) { - ciss_printf(sc, - "adapter refuses to go into 'simple' transport mode (0x%x, 0x%x)\n", - sc->ciss_cfg->supported_methods, sc->ciss_cfg->active_method); - return(ENXIO); + if ((sc->ciss_cfg->active_method & method) == 0) { + supported_methods &= ~method; + if (supported_methods == 0) { + ciss_printf(sc, "adapter refuses to go into available transports " + "mode (0x%x, 0x%x)\n", supported_methods, + sc->ciss_cfg->active_method); + return(ENXIO); + } else + goto setup; } /* @@ -656,6 +723,26 @@ ciss_init_pci(struct ciss_softc *sc) if ((error = ciss_wait_adapter(sc)) != 0) return(error); + /* Prepare to possibly use MSIX and/or PERFORMANT interrupts. Normal + * interrupts have a rid of 0, this will be overridden if MSIX is used. + */ + sc->ciss_irq_rid[0] = 0; + if (method == CISS_TRANSPORT_METHOD_PERF) { + ciss_printf(sc, "PERFORMANT Transport\n"); + if ((ciss_force_interrupt != 1) && (ciss_setup_msix(sc) == 0)) + intr = ciss_perf_msi_intr; + else + intr = ciss_perf_intr; + } else { + ciss_printf(sc, "SIMPLE Transport\n"); + /* MSIX doesn't seem to work in SIMPLE mode, only enable if it forced */ + if (ciss_force_interrupt == 2) + /* If this fails, we automatically revert to INTx */ + ciss_setup_msix(sc); + sc->ciss_perf = NULL; + intr = ciss_intr; + } + /* * Turn off interrupts before we go routing anything. */ @@ -664,15 +751,15 @@ ciss_init_pci(struct ciss_softc *sc) /* * Allocate and set up our interrupt. */ - sc->ciss_irq_rid = 0; if ((sc->ciss_irq_resource = - bus_alloc_resource_any(sc->ciss_dev, SYS_RES_IRQ, &sc->ciss_irq_rid, + bus_alloc_resource_any(sc->ciss_dev, SYS_RES_IRQ, &sc->ciss_irq_rid[0], RF_ACTIVE | RF_SHAREABLE)) == NULL) { ciss_printf(sc, "can't allocate interrupt\n"); return(ENXIO); } + if (bus_setup_intr(sc->ciss_dev, sc->ciss_irq_resource, - INTR_TYPE_CAM|INTR_MPSAFE, NULL, ciss_intr, sc, + INTR_TYPE_CAM|INTR_MPSAFE, NULL, intr, sc, &sc->ciss_intr)) { ciss_printf(sc, "can't set up interrupt\n"); return(ENXIO); @@ -693,7 +780,7 @@ ciss_init_pci(struct ciss_softc *sc) BUS_SPACE_MAXSIZE_32BIT, /* maxsize */ CISS_COMMAND_SG_LENGTH, /* nsegments */ BUS_SPACE_MAXSIZE_32BIT, /* maxsegsize */ - BUS_DMA_ALLOCNOW, /* flags */ + 0, /* flags */ NULL, NULL, /* lockfunc, lockarg */ &sc->ciss_parent_dmat)) { ciss_printf(sc, "can't allocate parent DMA tag\n"); @@ -711,7 +798,7 @@ ciss_init_pci(struct ciss_softc *sc) NULL, NULL, /* filter, filterarg */ MAXBSIZE, CISS_COMMAND_SG_LENGTH, /* maxsize, nsegments */ BUS_SPACE_MAXSIZE_32BIT, /* maxsegsize */ - 0, /* flags */ + BUS_DMA_ALLOCNOW, /* flags */ busdma_lock_mutex, &sc->ciss_mtx, /* lockfunc, lockarg */ &sc->ciss_buffer_dmat)) { ciss_printf(sc, "can't allocate buffer DMA tag\n"); @@ -721,6 +808,110 @@ ciss_init_pci(struct ciss_softc *sc) } /************************************************************************ + * Setup MSI/MSIX operation (Performant only) + * Four interrupts are available, but we only use 1 right now. + */ +static int +ciss_setup_msix(struct ciss_softc *sc) +{ + uint32_t id; + int val, i; + + /* Weed out devices that don't actually support MSI */ + id = (pci_get_subvendor(sc->ciss_dev) << 16) | + pci_get_subdevice(sc->ciss_dev); + if ((id == 0x0e114070) || (id == 0x0e114080) || (id == 0x0e114082) || + (id == 0x0e114083)) + return (EINVAL); + + val = pci_msix_count(sc->ciss_dev); + if ((val != CISS_MSI_COUNT) || (pci_alloc_msix(sc->ciss_dev, &val) != 0)) + return (EINVAL); + + sc->ciss_msi = val; + ciss_printf(sc, "Using MSIX interrupt\n"); + + for (i = 0; i < CISS_MSI_COUNT; i++) + sc->ciss_irq_rid[i] = i + 1; + + return (0); + +} + +/************************************************************************ + * Setup the Performant structures. + */ +static int +ciss_init_perf(struct ciss_softc *sc) +{ + struct ciss_perf_config *pc = sc->ciss_perf; + int reply_size; + + /* + * Create the DMA tag for the reply queue. + */ + reply_size = sizeof(uint64_t) * sc->ciss_max_requests; + if (bus_dma_tag_create(sc->ciss_parent_dmat, /* parent */ + 1, 0, /* alignment, boundary */ + BUS_SPACE_MAXADDR_32BIT, /* lowaddr */ + BUS_SPACE_MAXADDR, /* highaddr */ + NULL, NULL, /* filter, filterarg */ + reply_size, 1, /* maxsize, nsegments */ + BUS_SPACE_MAXSIZE_32BIT, /* maxsegsize */ + 0, /* flags */ + NULL, NULL, /* lockfunc, lockarg */ + &sc->ciss_reply_dmat)) { + ciss_printf(sc, "can't allocate reply DMA tag\n"); + return(ENOMEM); + } + /* + * Allocate memory and make it available for DMA. + */ + if (bus_dmamem_alloc(sc->ciss_reply_dmat, (void **)&sc->ciss_reply, + BUS_DMA_NOWAIT, &sc->ciss_reply_map)) { + ciss_printf(sc, "can't allocate reply memory\n"); + return(ENOMEM); + } + bus_dmamap_load(sc->ciss_reply_dmat, sc->ciss_reply_map, sc->ciss_reply, + reply_size, ciss_command_map_helper, &sc->ciss_reply_phys, 0); + bzero(sc->ciss_reply, reply_size); + + sc->ciss_cycle = 0x1; + sc->ciss_rqidx = 0; + + /* + * Preload the fetch table with common command sizes. This allows the + * hardware to not waste bus cycles for typical i/o commands, but also not + * tax the driver to be too exact in choosing sizes. The table is optimized + * for page-aligned i/o's, but since most i/o comes from the various pagers, + * it's a reasonable assumption to make. + */ + pc->fetch_count[CISS_SG_FETCH_NONE] = (sizeof(struct ciss_command) + 15) / 16; + pc->fetch_count[CISS_SG_FETCH_1] = + (sizeof(struct ciss_command) + sizeof(struct ciss_sg_entry) * 1 + 15) / 16; + pc->fetch_count[CISS_SG_FETCH_2] = + (sizeof(struct ciss_command) + sizeof(struct ciss_sg_entry) * 2 + 15) / 16; + pc->fetch_count[CISS_SG_FETCH_4] = + (sizeof(struct ciss_command) + sizeof(struct ciss_sg_entry) * 4 + 15) / 16; + pc->fetch_count[CISS_SG_FETCH_8] = + (sizeof(struct ciss_command) + sizeof(struct ciss_sg_entry) * 8 + 15) / 16; + pc->fetch_count[CISS_SG_FETCH_16] = + (sizeof(struct ciss_command) + sizeof(struct ciss_sg_entry) * 16 + 15) / 16; + pc->fetch_count[CISS_SG_FETCH_32] = + (sizeof(struct ciss_command) + sizeof(struct ciss_sg_entry) * 32 + 15) / 16; + pc->fetch_count[CISS_SG_FETCH_MAX] = (CISS_COMMAND_ALLOC_SIZE + 15) / 16; + + pc->rq_size = sc->ciss_max_requests; /* XXX less than the card supports? */ + pc->rq_count = 1; /* XXX Hardcode for a single queue */ + pc->rq_bank_hi = 0; + pc->rq_bank_lo = 0; + pc->rq[0].rq_addr_hi = 0x0; + pc->rq[0].rq_addr_lo = sc->ciss_reply_phys; + + return(0); +} + +/************************************************************************ * Wait for the adapter to come ready. */ static int @@ -854,12 +1045,6 @@ ciss_init_requests(struct ciss_softc *sc) debug_called(1); - /* - * Calculate the number of request structures/commands we are - * going to provide for this adapter. - */ - sc->ciss_max_requests = min(CISS_MAX_REQUESTS, sc->ciss_cfg->max_outstanding_commands); - if (bootverbose) ciss_printf(sc, "using %d of %d available commands\n", sc->ciss_max_requests, sc->ciss_cfg->max_outstanding_commands); @@ -868,14 +1053,14 @@ ciss_init_requests(struct ciss_softc *sc) * Create the DMA tag for commands. */ if (bus_dma_tag_create(sc->ciss_parent_dmat, /* parent */ - 1, 0, /* alignment, boundary */ + 32, 0, /* alignment, boundary */ BUS_SPACE_MAXADDR_32BIT, /* lowaddr */ BUS_SPACE_MAXADDR, /* highaddr */ NULL, NULL, /* filter, filterarg */ CISS_COMMAND_ALLOC_SIZE * sc->ciss_max_requests, 1, /* maxsize, nsegments */ BUS_SPACE_MAXSIZE_32BIT, /* maxsegsize */ - BUS_DMA_ALLOCNOW, /* flags */ + 0, /* flags */ NULL, NULL, /* lockfunc, lockarg */ &sc->ciss_command_dmat)) { ciss_printf(sc, "can't allocate command DMA tag\n"); @@ -889,9 +1074,9 @@ ciss_init_requests(struct ciss_softc *sc) ciss_printf(sc, "can't allocate command memory\n"); return(ENOMEM); } - bus_dmamap_load(sc->ciss_command_dmat, sc->ciss_command_map, sc->ciss_command, + bus_dmamap_load(sc->ciss_command_dmat, sc->ciss_command_map,sc->ciss_command, CISS_COMMAND_ALLOC_SIZE * sc->ciss_max_requests, - ciss_command_map_helper, sc, 0); + ciss_command_map_helper, &sc->ciss_command_phys, 0); bzero(sc->ciss_command, CISS_COMMAND_ALLOC_SIZE * sc->ciss_max_requests); /* @@ -911,9 +1096,10 @@ ciss_init_requests(struct ciss_softc *sc) static void ciss_command_map_helper(void *arg, bus_dma_segment_t *segs, int nseg, int error) { - struct ciss_softc *sc = (struct ciss_softc *)arg; + uint32_t *addr; - sc->ciss_command_phys = segs->ds_addr; + addr = arg; + *addr = segs[0].ds_addr; } /************************************************************************ @@ -1728,11 +1914,9 @@ ciss_free(struct ciss_softc *sc) bus_teardown_intr(sc->ciss_dev, sc->ciss_irq_resource, sc->ciss_intr); if (sc->ciss_irq_resource != NULL) bus_release_resource(sc->ciss_dev, SYS_RES_IRQ, - sc->ciss_irq_rid, sc->ciss_irq_resource); - - /* destroy DMA tags */ - if (sc->ciss_parent_dmat) - bus_dma_tag_destroy(sc->ciss_parent_dmat); + sc->ciss_irq_rid[0], sc->ciss_irq_resource); + if (sc->ciss_msi) + pci_release_msi(sc->ciss_dev); while ((cr = ciss_dequeue_free(sc)) != NULL) bus_dmamap_destroy(sc->ciss_buffer_dmat, cr->cr_datamap); @@ -1747,6 +1931,16 @@ ciss_free(struct ciss_softc *sc) if (sc->ciss_command_dmat) bus_dma_tag_destroy(sc->ciss_command_dmat); + if (sc->ciss_reply) { + bus_dmamap_unload(sc->ciss_reply_dmat, sc->ciss_reply_map); + bus_dmamem_free(sc->ciss_reply_dmat, sc->ciss_reply, sc->ciss_reply_map); + } + if (sc->ciss_reply_dmat) + bus_dma_tag_destroy(sc->ciss_reply_dmat); + + /* destroy DMA tags */ + if (sc->ciss_parent_dmat) + bus_dma_tag_destroy(sc->ciss_parent_dmat); if (sc->ciss_logical) { for (i = 0; i <= sc->ciss_max_logical_bus; i++) { for (j = 0; j < CISS_MAX_LOGICAL; j++) { @@ -1820,20 +2014,18 @@ ciss_start(struct ciss_request *cr) * (eg. timeouts, etc.) */ static void -ciss_done(struct ciss_softc *sc) +ciss_done(struct ciss_softc *sc, cr_qhead_t *qh) { struct ciss_request *cr; struct ciss_command *cc; u_int32_t tag, index; - int complete; debug_called(3); /* * Loop quickly taking requests from the adapter and moving them - * from the busy queue to the completed queue. + * to the completed queue. */ - complete = 0; for (;;) { /* see if the OPQ contains anything */ @@ -1853,21 +2045,45 @@ ciss_done(struct ciss_softc *sc) cr = &(sc->ciss_request[index]); cc = CISS_FIND_COMMAND(cr); cc->header.host_tag = tag; /* not updated by adapter */ - if (ciss_remove_busy(cr)) { - /* assume this is garbage out of the adapter */ - ciss_printf(sc, "completed nonbusy request %d\n", index); - } else { - ciss_enqueue_complete(cr); - } - complete = 1; + ciss_enqueue_complete(cr, qh); } +} + +static void +ciss_perf_done(struct ciss_softc *sc, cr_qhead_t *qh) +{ + struct ciss_request *cr; + struct ciss_command *cc; + u_int32_t tag, index; + + debug_called(3); + /* - * Invoke completion processing. If we can defer this out of - * interrupt context, that'd be good. + * Loop quickly taking requests from the adapter and moving them + * to the completed queue. */ - if (complete) - ciss_complete(sc); + for (;;) { + tag = sc->ciss_reply[sc->ciss_rqidx]; + if ((tag & CISS_CYCLE_MASK) != sc->ciss_cycle) + break; + index = tag >> 2; + debug(2, "completed command %d%s\n", index, + (tag & CISS_HDR_HOST_TAG_ERROR) ? " with error" : ""); + if (index < sc->ciss_max_requests) { + cr = &(sc->ciss_request[index]); + cc = CISS_FIND_COMMAND(cr); + cc->header.host_tag = tag; /* not updated by adapter */ + ciss_enqueue_complete(cr, qh); + } else { + ciss_printf(sc, "completed invalid request %d (0x%x)\n", index, tag); + } + if (++sc->ciss_rqidx == sc->ciss_max_requests) { + sc->ciss_rqidx = 0; + sc->ciss_cycle ^= 1; + } + } + } /************************************************************************ @@ -1876,17 +2092,48 @@ ciss_done(struct ciss_softc *sc) static void ciss_intr(void *arg) { + cr_qhead_t qh; struct ciss_softc *sc = (struct ciss_softc *)arg; /* * The only interrupt we recognise indicates that there are * entries in the outbound post queue. */ + STAILQ_INIT(&qh); + ciss_done(sc, &qh); mtx_lock(&sc->ciss_mtx); - ciss_done(sc); + ciss_complete(sc, &qh); mtx_unlock(&sc->ciss_mtx); } +static void +ciss_perf_intr(void *arg) +{ + struct ciss_softc *sc = (struct ciss_softc *)arg; + + /* Clear the interrupt and flush the bridges. Docs say that the flush + * needs to be done twice, which doesn't seem right. + */ + CISS_TL_PERF_CLEAR_INT(sc); + CISS_TL_PERF_FLUSH_INT(sc); + + ciss_perf_msi_intr(sc); +} + +static void +ciss_perf_msi_intr(void *arg) +{ + cr_qhead_t qh; + struct ciss_softc *sc = (struct ciss_softc *)arg; + + STAILQ_INIT(&qh); + ciss_perf_done(sc, &qh); + mtx_lock(&sc->ciss_mtx); + ciss_complete(sc, &qh); + mtx_unlock(&sc->ciss_mtx); +} + + /************************************************************************ * Process completed requests. * @@ -1897,7 +2144,7 @@ ciss_intr(void *arg) * - by clearing the CISS_REQ_POLL flag in interrupt/timeout context */ static void -ciss_complete(struct ciss_softc *sc) +ciss_complete(struct ciss_softc *sc, cr_qhead_t *qh) { struct ciss_request *cr; @@ -1908,10 +2155,14 @@ ciss_complete(struct ciss_softc *sc) * completion processing on them. */ for (;;) { - if ((cr = ciss_dequeue_complete(sc)) == NULL) + if ((cr = ciss_dequeue_complete(sc, qh)) == NULL) break; ciss_unmap_request(cr); + if ((cr->cr_flags & CISS_REQ_BUSY) == 0) + ciss_printf(sc, "WARNING: completing non-busy request\n"); + cr->cr_flags &= ~CISS_REQ_BUSY; + /* * If the request has a callback, invoke it. */ @@ -1951,7 +2202,7 @@ ciss_complete(struct ciss_softc *sc) * and command status values. */ static int -ciss_report_request(struct ciss_request *cr, int *command_status, int *scsi_status) +_ciss_report_request(struct ciss_request *cr, int *command_status, int *scsi_status, const char *func) { struct ciss_command *cc; struct ciss_error_info *ce; @@ -2000,10 +2251,11 @@ ciss_report_request(struct ciss_request *cr, int *command_status, int *scsi_stat ce->command_status, ciss_name_command_status(ce->command_status), ce->scsi_status); if (ce->command_status == CISS_CMD_STATUS_INVALID_COMMAND) { - ciss_printf(cr->cr_sc, "invalid command, offense size %d at %d, value 0x%x\n", + ciss_printf(cr->cr_sc, "invalid command, offense size %d at %d, value 0x%x, function %s\n", ce->additional_error_info.invalid_command.offense_size, ce->additional_error_info.invalid_command.offense_offset, - ce->additional_error_info.invalid_command.offense_value); + ce->additional_error_info.invalid_command.offense_value, + func); } } #if 0 @@ -2036,16 +2288,24 @@ ciss_synch_request(struct ciss_request *cr, int timeout) static int ciss_poll_request(struct ciss_request *cr, int timeout) { + cr_qhead_t qh; + struct ciss_softc *sc; int error; debug_called(2); + STAILQ_INIT(&qh); + sc = cr->cr_sc; cr->cr_flags |= CISS_REQ_POLL; if ((error = ciss_start(cr)) != 0) return(error); do { - ciss_done(cr->cr_sc); + if (sc->ciss_perf) + ciss_perf_done(sc, &qh); + else + ciss_done(sc, &qh); + ciss_complete(sc, &qh); if (!(cr->cr_flags & CISS_REQ_POLL)) return(0); DELAY(1000); @@ -2062,7 +2322,7 @@ ciss_poll_request(struct ciss_request *cr, int timeout) static int ciss_wait_request(struct ciss_request *cr, int timeout) { - int s, error; + int error; debug_called(2); @@ -2070,11 +2330,9 @@ ciss_wait_request(struct ciss_request *cr, int timeout) if ((error = ciss_start(cr)) != 0) return(error); - s = splcam(); while ((cr->cr_flags & CISS_REQ_SLEEP) && (error != EWOULDBLOCK)) { error = msleep(cr, &cr->cr_sc->ciss_mtx, PRIBIO, "cissREQ", (timeout * hz) / 1000); } - splx(s); return(error); } @@ -2148,6 +2406,7 @@ ciss_get_request(struct ciss_softc *sc, struct ciss_request **crp) cr->cr_flags = 0; cr->cr_complete = NULL; cr->cr_private = NULL; + cr->cr_sg_tag = CISS_SG_MAX; /* Backstop to prevent accidents */ ciss_preen_command(cr); *crp = cr; @@ -2384,8 +2643,12 @@ ciss_map_request(struct ciss_request *cr) /* * Post the command to the adapter. */ - ciss_enqueue_busy(cr); - CISS_TL_SIMPLE_POST_CMD(cr->cr_sc, CISS_FIND_COMMANDPHYS(cr)); + cr->cr_sg_tag = CISS_SG_NONE; + cr->cr_flags |= CISS_REQ_BUSY; + if (sc->ciss_perf) + CISS_TL_PERF_POST_CMD(sc, cr); + else + CISS_TL_SIMPLE_POST_CMD(sc, CISS_FIND_COMMANDPHYS(cr)); } return(0); @@ -2419,11 +2682,31 @@ ciss_request_map_helper(void *arg, bus_dma_segment_t *segs, int nseg, int error) if (cr->cr_flags & CISS_REQ_DATAOUT) bus_dmamap_sync(sc->ciss_buffer_dmat, cr->cr_datamap, BUS_DMASYNC_PREWRITE); + if (nseg == 1) + cr->cr_sg_tag = CISS_SG_NONE; + else if (nseg == 1) + cr->cr_sg_tag = CISS_SG_1; + else if (nseg == 2) + cr->cr_sg_tag = CISS_SG_2; + else if (nseg <= 4) + cr->cr_sg_tag = CISS_SG_4; + else if (nseg <= 8) + cr->cr_sg_tag = CISS_SG_8; + else if (nseg <= 16) + cr->cr_sg_tag = CISS_SG_16; + else if (nseg <= 32) + cr->cr_sg_tag = CISS_SG_32; + else + cr->cr_sg_tag = CISS_SG_MAX; + /* * Post the command to the adapter. */ - ciss_enqueue_busy(cr); - CISS_TL_SIMPLE_POST_CMD(cr->cr_sc, CISS_FIND_COMMANDPHYS(cr)); + cr->cr_flags |= CISS_REQ_BUSY; + if (sc->ciss_perf) + CISS_TL_PERF_POST_CMD(sc, cr); + else + CISS_TL_SIMPLE_POST_CMD(sc, CISS_FIND_COMMANDPHYS(cr)); } /************************************************************************ @@ -2502,7 +2785,7 @@ ciss_cam_init(struct ciss_softc *sc) "ciss", sc, device_get_unit(sc->ciss_dev), &sc->ciss_mtx, - sc->ciss_max_requests - 2, + 2, sc->ciss_max_requests - 2, sc->ciss_cam_devq)) == NULL) { ciss_printf(sc, "can't allocate CAM SIM for controller %d\n", i); @@ -2900,11 +3183,17 @@ ciss_cam_emulate(struct ciss_softc *sc, struct ccb_scsiio *csio) static void ciss_cam_poll(struct cam_sim *sim) { + cr_qhead_t qh; struct ciss_softc *sc = cam_sim_softc(sim); debug_called(2); - ciss_done(sc); + STAILQ_INIT(&qh); + if (sc->ciss_perf) + ciss_perf_done(sc, &qh); + else + ciss_done(sc, &qh); + ciss_complete(sc, &qh); } /************************************************************************ @@ -2983,8 +3272,8 @@ ciss_cam_complete(struct ciss_request *cr) /* tell CAM we're ready for more commands */ csio->ccb_h.status |= CAM_RELEASE_SIMQ; - xpt_done((union ccb *)csio); ciss_release_request(cr); + xpt_done((union ccb *)csio); } /******************************************************************************** @@ -3157,29 +3446,29 @@ ciss_nop_complete(struct ciss_request *cr) static void ciss_disable_adapter(struct ciss_softc *sc) { + cr_qhead_t qh; struct ciss_request *cr; struct ciss_command *cc; struct ciss_error_info *ce; - int s; - - s = splcam(); + int i; CISS_TL_SIMPLE_DISABLE_INTERRUPTS(sc); pci_disable_busmaster(sc->ciss_dev); sc->ciss_flags &= ~CISS_FLAG_RUNNING; - for (;;) { - if ((cr = ciss_dequeue_busy(sc)) == NULL) - break; + for (i = 1; i < sc->ciss_max_requests; i++) { + cr = &sc->ciss_request[i]; + if ((cr->cr_flags & CISS_REQ_BUSY) == 0) + continue; cc = CISS_FIND_COMMAND(cr); ce = (struct ciss_error_info *)&(cc->sg[0]); ce->command_status = CISS_CMD_STATUS_HARDWARE_ERROR; - ciss_enqueue_complete(cr); + ciss_enqueue_complete(cr, &qh); } for (;;) { - if ((cr = ciss_dequeue_complete(sc)) == NULL) + if ((cr = ciss_dequeue_complete(sc, &qh)) == NULL) break; /* @@ -3199,8 +3488,6 @@ ciss_disable_adapter(struct ciss_softc *sc) continue; } } - - splx(s); } /************************************************************************ @@ -3381,7 +3668,7 @@ ciss_notify_abort(struct ciss_softc *sc) struct ciss_request *cr; struct ciss_command *cc; struct ciss_notify_cdb *cnc; - int error, s, command_status, scsi_status; + int error, command_status, scsi_status; debug_called(1); @@ -3475,7 +3762,6 @@ ciss_notify_abort(struct ciss_softc *sc) * requires the Notify Event command to be cancelled in order to * maintain internal bookkeeping. */ - s = splcam(); while (sc->ciss_periodic_notify != NULL) { error = msleep(&sc->ciss_periodic_notify, &sc->ciss_mtx, PRIBIO, "cissNEA", hz * 5); if (error == EWOULDBLOCK) { @@ -3483,7 +3769,6 @@ ciss_notify_abort(struct ciss_softc *sc) break; } } - splx(s); out: /* release the cancel request */ @@ -3728,7 +4013,6 @@ ciss_notify_hotplug(struct ciss_softc *sc, struct ciss_notify *cn) { struct ciss_lun_report *cll = NULL; int bus, target; - int s; switch (cn->subclass) { case CISS_NOTIFY_HOTPLUG_PHYSICAL: @@ -3737,7 +4021,6 @@ ciss_notify_hotplug(struct ciss_softc *sc, struct ciss_notify *cn) target = CISS_BIG_MAP_TARGET(sc, cn->data.drive.big_physical_drive_number); - s = splcam(); if (cn->detail == 0) { /* * Mark the device offline so that it'll start producing selection @@ -3757,7 +4040,6 @@ ciss_notify_hotplug(struct ciss_softc *sc, struct ciss_notify *cn) } ciss_filter_physical(sc, cll); } - splx(s); break; default: @@ -3779,16 +4061,14 @@ ciss_notify_thread(void *arg) struct ciss_softc *sc; struct ciss_request *cr; struct ciss_notify *cn; - int s; sc = (struct ciss_softc *)arg; #if __FreeBSD_version >= 500000 mtx_lock(&sc->ciss_mtx); #endif - s = splcam(); for (;;) { - if (TAILQ_EMPTY(&sc->ciss_notify) != 0 && + if (STAILQ_EMPTY(&sc->ciss_notify) != 0 && (sc->ciss_flags & CISS_FLAG_THREAD_SHUT) == 0) { msleep(&sc->ciss_notify, &sc->ciss_mtx, PUSER, "idle", 0); } @@ -3797,7 +4077,6 @@ ciss_notify_thread(void *arg) break; cr = ciss_dequeue_notify(sc); - splx(s); if (cr == NULL) panic("cr null"); @@ -3817,11 +4096,9 @@ ciss_notify_thread(void *arg) ciss_release_request(cr); - s = splcam(); } sc->ciss_notify_thread = NULL; wakeup(&sc->ciss_notify_thread); - splx(s); #if __FreeBSD_version >= 500000 mtx_unlock(&sc->ciss_mtx); @@ -4215,6 +4492,24 @@ ciss_ioctl(struct cdev *dev, u_long cmd, caddr_t addr, int32_t flag, d_thread_t mtx_lock(&sc->ciss_mtx); switch(cmd) { + case CCISS_GETQSTATS: + { + union ciss_statrequest *cr = (union ciss_statrequest *)addr; + + switch (cr->cs_item) { + case CISSQ_FREE: + case CISSQ_NOTIFY: + bcopy(&sc->ciss_qstat[cr->cs_item], &cr->cs_qstat, + sizeof(struct ciss_qstat)); + break; + default: + error = ENOIOCTL; + break; + } + + break; + } + case CCISS_GETPCIINFO: { cciss_pci_info_struct *pis = (cciss_pci_info_struct *)addr; |