From 0b94a66e3f8a898cdf6481c428f6cedca31c3958 Mon Sep 17 00:00:00 2001 From: Mike Smith Date: Wed, 27 Dec 2000 13:14:56 +0000 Subject: [PATCH] Major bugfix and minor update. This should resolve the current issues with the driver locking up under load. - Restructure so that we use a static pool of commands/FIBs, rather than allocating them in clusters. The cluster allocation just made things more complicated, and allowed us to waste more memory in peak load situations. - Make queueing macros more like my other drivers. This adds queue stats for free. Add some debugging to take advantage of this. - Reimplement the periodic timeout scan. Kick the interrupt handler and the start routine every scan as well, just to be safe. Track busy commands properly. - Bring resource cleanup into line with resource allocation. We should now clean up correctly after a failed probe/unload/etc. - Try to start new commands when old ones are completed. We weren't doing this before, which could lead to deadlock when the controller was full. - Don't try to build a new command if we have found a deferred command. This could cause us to lose the deferred command. - Use diskerr() to report I/O errors. - Don't bail if the AdapterInfo structure is the wrong size. Some variation seems to be normal. We need to improve our handing of 2.x firmware sets. - Improve some comments in an attempt to try to make things clearer. - Restructure to avoid some warnings. --- sys/dev/aac/aac.c | 407 ++++++++++++++++++++------------------- sys/dev/aac/aac_compat.h | 2 +- sys/dev/aac/aac_debug.c | 12 +- sys/dev/aac/aac_disk.c | 7 +- sys/dev/aac/aac_ioctl.h | 25 +++ sys/dev/aac/aac_pci.c | 9 +- sys/dev/aac/aacreg.h | 2 +- sys/dev/aac/aacvar.h | 294 ++++++++++++++-------------- sys/sys/aac_ioctl.h | 25 +++ 9 files changed, 441 insertions(+), 342 deletions(-) diff --git a/sys/dev/aac/aac.c b/sys/dev/aac/aac.c index f225430842e4..b1b17fec9d03 100644 --- a/sys/dev/aac/aac.c +++ b/sys/dev/aac/aac.c @@ -44,15 +44,16 @@ #include #include #include +#include #include #include #include #include +#include #include #include -#include devclass_t aac_devclass; @@ -60,7 +61,7 @@ static void aac_startup(void *arg); /* Command Processing */ static void aac_startio(struct aac_softc *sc); -static void aac_timeout(struct aac_command *cm); +static void aac_timeout(struct aac_softc *sc); static int aac_start(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); @@ -72,9 +73,9 @@ static void aac_host_response(struct aac_softc *sc); /* Command Buffer Management */ static int aac_alloc_command(struct aac_softc *sc, struct aac_command **cmp); static void aac_release_command(struct aac_command *cm); -static void aac_map_command_cluster(void *arg, bus_dma_segment_t *segs, int nseg, int error); -static void aac_alloc_command_cluster(struct aac_softc *sc); -static void aac_free_command_cluster(struct aac_command_cluster *cmc); +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); @@ -140,10 +141,10 @@ static d_close_t aac_close; static d_ioctl_t aac_ioctl; static int aac_ioctl_sendfib(struct aac_softc *sc, caddr_t ufib); static void aac_handle_aif(struct aac_softc *sc, struct aac_aif_command *aif); -static int aac_return_aif(struct aac_softc *sc, caddr_t uptr); #ifdef AAC_COMPAT_LINUX static int aac_linux_rev_check(struct aac_softc *sc, caddr_t udata); static int aac_linux_getnext_aif(struct aac_softc *sc, caddr_t arg); +static int aac_linux_return_aif(struct aac_softc *sc, caddr_t uptr); #endif #define AAC_CDEV_MAJOR 150 @@ -165,11 +166,6 @@ static struct cdevsw aac_cdevsw = { -1, /* bmaj */ }; -/* Timeout for giving up on a command sent to the controller */ -#ifndef AAC_CMD_TIMEOUT -#define AAC_CMD_TIMEOUT 15 -#endif - /******************************************************************************** ******************************************************************************** Device Interface @@ -189,11 +185,11 @@ aac_attach(struct aac_softc *sc) /* * Initialise per-controller queues. */ - TAILQ_INIT(&sc->aac_freecmds); - TAILQ_INIT(&sc->aac_ready); - TAILQ_INIT(&sc->aac_completed); - TAILQ_INIT(&sc->aac_clusters); - bioq_init(&sc->aac_bioq); + aac_initq_free(sc); + aac_initq_ready(sc); + aac_initq_busy(sc); + aac_initq_complete(sc); + aac_initq_bio(sc); #if __FreeBSD_version >= 500005 /* @@ -208,10 +204,16 @@ aac_attach(struct aac_softc *sc) /* mark controller as suspended until we get ourselves organised */ sc->aac_state |= AAC_STATE_SUSPEND; + /* + * Allocate command structures. + */ + if ((error = aac_alloc_commands(sc)) != 0) + return(error); + /* * Initialise the adapter. */ - if ((error = aac_init(sc))) + if ((error = aac_init(sc)) != 0) return(error); /* @@ -222,7 +224,6 @@ aac_attach(struct aac_softc *sc) /* * Register to probe our containers later. */ - bzero(&sc->aac_ich, sizeof(struct intr_config_hook)); sc->aac_ich.ich_func = aac_startup; sc->aac_ich.ich_arg = sc; if (config_intrhook_establish(&sc->aac_ich) != 0) { @@ -303,36 +304,38 @@ aac_startup(void *arg) /* enable interrupts now */ AAC_UNMASK_INTERRUPTS(sc); + + /* enable the timeout watchdog */ + timeout((timeout_t*)aac_timeout, sc, AAC_PERIODIC_INTERVAL * hz); } /******************************************************************************** * Free all of the resources associated with (sc) * * Should not be called if the controller is active. - * - * XXX verify that we are freeing all our resources here... */ void aac_free(struct aac_softc *sc) { - struct aac_command_cluster *cmc; - debug_called(1); /* remove the control device */ if (sc->aac_dev_t != NULL) destroy_dev(sc->aac_dev_t); - /* throw away any command buffers */ - while ((cmc = aac_dequeue_cluster(sc)) != NULL) - aac_free_command_cluster(cmc); + /* throw away any FIB buffers, discard the FIB DMA tag */ + if (sc->aac_fibs != NULL) + aac_free_commands(sc); + if (sc->aac_fib_dmat) + bus_dma_tag_destroy(sc->aac_fib_dmat); /* destroy the common area */ if (sc->aac_common) { bus_dmamap_unload(sc->aac_common_dmat, sc->aac_common_dmamap); bus_dmamem_free(sc->aac_common_dmat, sc->aac_common, sc->aac_common_dmamap); - bus_dma_tag_destroy(sc->aac_common_dmat); } + if (sc->aac_common_dmat) + bus_dma_tag_destroy(sc->aac_common_dmat); /* disconnect the interrupt handler */ if (sc->aac_intr) @@ -344,10 +347,6 @@ aac_free(struct aac_softc *sc) if (sc->aac_buffer_dmat) bus_dma_tag_destroy(sc->aac_buffer_dmat); - /* destroy FIB DMA tag */ - if (sc->aac_buffer_dmat) - bus_dma_tag_destroy(sc->aac_fib_dmat); - /* destroy the parent DMA tag */ if (sc->aac_parent_dmat) bus_dma_tag_destroy(sc->aac_parent_dmat); @@ -384,7 +383,7 @@ aac_detach(device_t dev) * * This function is called before detach or system shutdown. * - * Note that we can assume that the camq on the controller is empty, as we won't + * Note that we can assume that the bioq on the controller is empty, as we won't * allow shutdown if any device is open. */ int @@ -522,18 +521,13 @@ aac_startio(struct aac_softc *sc) cm = aac_dequeue_ready(sc); /* try to build a command off the bio queue (ignore error return) */ - aac_bio_command(sc, &cm); + if (cm == NULL) + aac_bio_command(sc, &cm); /* nothing to do? */ if (cm == NULL) break; - /* Set a timeout for this command to be completed by the controller */ - /* Disable this for now until the timeout queue is fixed or the driver - * can watch timeouts itself - * cm->timeout_handle = timeout((timeout_t*)aac_timeout, cm, AAC_CMD_TIMEOUT * hz); - */ - /* try to give the command to the controller */ if (aac_start(cm) == EBUSY) { /* put it on the ready queue for later */ @@ -543,27 +537,6 @@ aac_startio(struct aac_softc *sc) } } -static void -aac_timeout(struct aac_command *cm) -{ - struct aac_softc *sc; - struct bio *bp; - struct aac_disk *ad; - - sc = cm->cm_sc; - bp = (struct bio*)cm->cm_private; - ad = (struct aac_disk *)bp->bio_dev->si_drv1; - - device_printf(sc->aac_dev, "Timeout waiting for controller to respond to command\n"); - - /* Should try to requeue the command... is it possible? Bail for now */ - bp->bio_error = EIO; - bp->bio_flags |= BIO_ERROR; - devstat_end_transaction_bio(&ad->ad_stats, bp); - biodone(bp); - aac_release_command(cm); -} - /******************************************************************************** * Deliver a command to the controller; allocate controller resources at the * last moment when possible. @@ -572,25 +545,30 @@ static int aac_start(struct aac_command *cm) { struct aac_softc *sc = cm->cm_sc; + int s, error; debug_called(2); /* get the command mapped */ aac_map_command(cm); - /* fix up the address values */ + /* 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; /* save a pointer to the command for speedy reverse-lookup */ - cm->cm_fib->Header.SenderData = (u_int32_t)cm; /* XXX ack, sizing */ + cm->cm_fib->Header.SenderData = (u_int32_t)cm; /* XXX 64-bit physical address issue */ /* put the FIB on the outbound queue */ + s = splbio(); if (aac_enqueue_fib(sc, AAC_ADAP_NORM_CMD_QUEUE, cm->cm_fib->Header.Size, - cm->cm_fib->Header.ReceiverFibAddress)) - return(EBUSY); - - return(0); + cm->cm_fib->Header.ReceiverFibAddress)) { + error = EBUSY; + } else { + aac_enqueue_busy(cm); + error = 0; + } + return(error); } /******************************************************************************** @@ -645,8 +623,9 @@ aac_host_response(struct aac_softc *sc) if (cm == NULL) { AAC_PRINT_FIB(sc, fib); } else { + aac_remove_busy(cm); aac_unmap_command(cm); /* XXX defer? */ - aac_enqueue_completed(cm); + aac_enqueue_complete(cm); } } @@ -671,9 +650,9 @@ aac_complete(void *context, int pending) /* pull completed commands off the queue */ for (;;) { - cm = aac_dequeue_completed(sc); + cm = aac_dequeue_complete(sc); if (cm == NULL) - return; + break; cm->cm_flags |= AAC_CMD_COMPLETED; /* is there a completion handler? */ @@ -684,6 +663,9 @@ aac_complete(void *context, int pending) wakeup(cm); } } + + /* see if we can start some more I/O */ + aac_startio(sc); } /******************************************************************************** @@ -698,7 +680,7 @@ aac_submit_bio(struct bio *bp) debug_called(2); /* queue the BIO and try to get some work done */ - bioq_insert_tail(&sc->aac_bioq, bp); + aac_enqueue_bio(sc, bp); aac_startio(sc); } @@ -714,23 +696,22 @@ aac_bio_command(struct aac_softc *sc, struct aac_command **cmp) struct aac_blockwrite *bw; struct aac_disk *ad; struct bio *bp; - int s; debug_called(2); /* get the resources we will need */ cm = NULL; - s = splbio(); - if ((bp = bioq_first(&sc->aac_bioq))) - bioq_remove(&sc->aac_bioq, bp); - splx(s); - if (bp == NULL) /* no work? */ + if ((bp = aac_dequeue_bio(sc)) == NULL) goto fail; if (aac_alloc_command(sc, &cm)) /* get a command */ goto fail; /* fill out the command */ + cm->cm_data = (void *)bp->bio_data; + cm->cm_datalen = bp->bio_bcount; + cm->cm_complete = aac_bio_complete; cm->cm_private = bp; + cm->cm_timestamp = time_second; /* build the FIB */ fib = cm->cm_fib; @@ -745,9 +726,6 @@ aac_bio_command(struct aac_softc *sc, struct aac_command **cmp) /* build the read/write request */ ad = (struct aac_disk *)bp->bio_dev->si_drv1; - cm->cm_data = (void *)bp->bio_data; - cm->cm_datalen = bp->bio_bcount; - cm->cm_complete = aac_bio_complete; if (BIO_IS_READ(bp)) { br = (struct aac_blockread *)&fib->data[0]; br->Command = VM_CtBlockRead; @@ -774,7 +752,7 @@ aac_bio_command(struct aac_softc *sc, struct aac_command **cmp) fail: if (bp != NULL) - bioq_insert_tail(&sc->aac_bioq, bp); + aac_enqueue_bio(sc, bp); if (cm != NULL) aac_release_command(cm); return(ENOMEM); @@ -786,18 +764,11 @@ fail: static void aac_bio_complete(struct aac_command *cm) { - struct aac_softc *sc = cm->cm_sc; struct aac_blockread_response *brr; struct aac_blockwrite_response *bwr; struct bio *bp; AAC_FSAStatus status; - /* kill the timeout timer */ - /* Disable this for now until the timeout queue is fixed or the driver - * can watch timeouts itself - * untimeout((timeout_t *)aac_timeout, cm, cm->timeout_handle); - */ - /* fetch relevant status and then release the command */ bp = (struct bio *)cm->cm_private; if (BIO_IS_READ(bp)) { @@ -815,11 +786,10 @@ aac_bio_complete(struct aac_command *cm) } else { bp->bio_error = EIO; bp->bio_flags |= BIO_ERROR; - - /* XXX be more verbose? */ - device_printf(sc->aac_dev, "I/O error %d (%s)\n", status, AAC_COMMAND_STATUS(status)); + /* pass an error string out to the disk layer */ + bp->bio_driver1 = aac_describe_code(aac_command_status_table, status); } - aac_complete_bio(bp); /* XXX rename one of these functions! */ + aac_biodone(bp); } /******************************************************************************** @@ -859,15 +829,22 @@ aac_alloc_command(struct aac_softc *sc, struct aac_command **cmp) debug_called(3); - cm = aac_dequeue_free(sc); - if (cm == NULL) { - aac_alloc_command_cluster(sc); - cm = aac_dequeue_free(sc); - } - if (cm == NULL) + if ((cm = aac_dequeue_free(sc)) == NULL) return(ENOMEM); - /* initialise the command/FIB */ + *cmp = cm; + return(0); +} + +/******************************************************************************** + * Release a command back to the freelist. + */ +static void +aac_release_command(struct aac_command *cm) +{ + debug_called(3); + + /* (re)initialise the command/FIB */ cm->cm_sgtable = NULL; cm->cm_flags = 0; cm->cm_complete = NULL; @@ -885,90 +862,67 @@ aac_alloc_command(struct aac_softc *sc, struct aac_command **cmp) cm->cm_fib->Header.SenderFibAddress = (u_int32_t)cm->cm_fib; cm->cm_fib->Header.ReceiverFibAddress = cm->cm_fibphys; - *cmp = cm; - return(0); -} - -/******************************************************************************** - * Release a command back to the freelist. - */ -static void -aac_release_command(struct aac_command *cm) -{ - debug_called(3); - aac_enqueue_free(cm); } /******************************************************************************** - * Map helper for command cluster allocation. Tell each of the FIBs what its - * address in the adapter's space is, fill in a few other fields. + * Map helper for command/FIB allocation. */ static void -aac_map_command_cluster(void *arg, bus_dma_segment_t *segs, int nseg, int error) +aac_map_command_helper(void *arg, bus_dma_segment_t *segs, int nseg, int error) { - struct aac_command_cluster *cmc = (struct aac_command_cluster *)arg; + struct aac_softc *sc = (struct aac_softc *)arg; debug_called(3); - cmc->cmc_fibphys = segs[0].ds_addr; + sc->aac_fibphys = segs[0].ds_addr; } /******************************************************************************** - * Allocate and initialise a cluster of commands. + * Allocate and initialise commands/FIBs for this adapter. */ -static void -aac_alloc_command_cluster(struct aac_softc *sc) +static int +aac_alloc_commands(struct aac_softc *sc) { - struct aac_command_cluster *cmc; struct aac_command *cm; int i; debug_called(1); - cmc = malloc(sizeof(struct aac_command_cluster), M_DEVBUF, - M_NOWAIT | M_ZERO); - if (cmc != NULL) { - /* allocate the FIB cluster in DMAable memory and load it */ - if (bus_dmamem_alloc(sc->aac_fib_dmat, (void **)&cmc->cmc_fibs, BUS_DMA_NOWAIT, &cmc->cmc_fibmap)) { - free(cmc, M_DEVBUF); - return; - } - bus_dmamap_load(sc->aac_fib_dmat, cmc->cmc_fibmap, cmc->cmc_fibs, - AAC_CLUSTER_COUNT * sizeof(struct aac_fib), aac_map_command_cluster, cmc, 0); - - aac_enqueue_cluster(sc, cmc); - for (i = 0; i < AAC_CLUSTER_COUNT; i++) { - cm = &cmc->cmc_command[i]; - cm->cm_sc = sc; - cm->cm_fib = cmc->cmc_fibs + i; - cm->cm_fibphys = cmc->cmc_fibphys + (i * sizeof(struct aac_fib)); - - if (!bus_dmamap_create(sc->aac_buffer_dmat, 0, &cm->cm_datamap)) - aac_release_command(cm); - } - } else { - debug(2, "can't allocate memeory for command cluster"); + /* 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); } + 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); + + /* initialise constant fields in the command structure */ + for (i = 0; i < AAC_FIB_COUNT; i++) { + cm = &sc->aac_command[i]; + cm->cm_sc = sc; + cm->cm_fib = sc->aac_fibs + i; + cm->cm_fibphys = sc->aac_fibphys + (i * sizeof(struct aac_fib)); + + if (!bus_dmamap_create(sc->aac_buffer_dmat, 0, &cm->cm_datamap)) + aac_release_command(cm); + } + return(0); } /******************************************************************************** - * Free a command cluster. + * Free FIBs owned by this adapter. */ static void -aac_free_command_cluster(struct aac_command_cluster *cmc) +aac_free_commands(struct aac_softc *sc) { - struct aac_softc *sc = cmc->cmc_command[0].cm_sc; int i; debug_called(1); - for (i = 0; i < AAC_CLUSTER_COUNT; i++) - bus_dmamap_destroy(sc->aac_buffer_dmat, cmc->cmc_command[i].cm_datamap); - bus_dmamap_unload(sc->aac_fib_dmat, cmc->cmc_fibmap); - bus_dmamem_free(sc->aac_fib_dmat, cmc->cmc_fibs, cmc->cmc_fibmap); - - free(cmc, M_DEVBUF); + for (i = 0; i < AAC_FIB_COUNT; i++) + bus_dmamap_destroy(sc->aac_buffer_dmat, sc->aac_command[i].cm_datamap); + bus_dmamap_unload(sc->aac_fib_dmat, sc->aac_fibmap); + bus_dmamem_free(sc->aac_fib_dmat, sc->aac_fibs, sc->aac_fibmap); } /******************************************************************************** @@ -1142,11 +1096,13 @@ aac_init(struct aac_softc *sc) /* * Initialise FIB queues. Note that it appears that the layout of the indexes - * and the segmentation of the entries is mandated by the adapter, which is + * 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. + * 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 list manipulation @@ -1196,8 +1152,8 @@ aac_init(struct aac_softc *sc) * Give the init structure to the controller. */ if (aac_sync_command(sc, AAC_MONKER_INITSTRUCT, - sc->aac_common_busaddr + offsetof(struct aac_common, ac_init), - 0, 0, 0, NULL)) { + sc->aac_common_busaddr + offsetof(struct aac_common, ac_init), + 0, 0, 0, NULL)) { device_printf(sc->aac_dev, "error establishing init structure\n"); return(EIO); } @@ -1210,8 +1166,8 @@ aac_init(struct aac_softc *sc) */ static int aac_sync_command(struct aac_softc *sc, u_int32_t command, - u_int32_t arg0, u_int32_t arg1, u_int32_t arg2, u_int32_t arg3, - u_int32_t *sp) + u_int32_t arg0, u_int32_t arg1, u_int32_t arg2, u_int32_t arg3, + u_int32_t *sp) { time_t then; u_int32_t status; @@ -1243,7 +1199,7 @@ aac_sync_command(struct aac_softc *sc, u_int32_t command, status = AAC_GET_MAILBOXSTATUS(sc); if (sp != NULL) *sp = status; - return(0); /* check command return status? */ + return(0); } /******************************************************************************** @@ -1285,7 +1241,7 @@ aac_sync_fib(struct aac_softc *sc, u_int32_t command, u_int32_t xferstate, * Give the FIB to the controller, wait for a response. */ if (aac_sync_command(sc, AAC_MONKER_SYNCFIB, fib->Header.ReceiverFibAddress, - 0, 0, 0, NULL)) { + 0, 0, 0, NULL)) { debug(2, "IO error"); return(EIO); } @@ -1324,9 +1280,10 @@ static struct { * Atomically insert an entry into the nominated queue, returns 0 on success or EBUSY * if the queue is full. * - * XXX note that it would be more efficient to defer notifying the controller in - * the case where we may be inserting several entries in rapid succession, but - * implementing this usefully is difficult. + * Note: it would be more efficient to defer notifying the controller in + * the case where we may be inserting several entries in rapid succession, but + * implementing this usefully may be difficult (it would involve a separate + * queue/notify interface). */ static int aac_enqueue_fib(struct aac_softc *sc, int queue, u_int32_t fib_size, u_int32_t fib_addr) @@ -1415,6 +1372,41 @@ out: return(error); } +/******************************************************************************** + * Check for commands that have been outstanding for a suspiciously long time, + * and complain about them. + */ +static void +aac_timeout(struct aac_softc *sc) +{ + int s; + struct aac_command *cm; + time_t deadline; + + /* simulate an interrupt to handle possibly-missed interrupts */ + aac_intr(sc); + + /* kick the I/O queue to restart it in the case of deadlock */ + aac_startio(sc); + + /* traverse the busy command list, bitch about late commands once only */ + deadline = time_second - AAC_CMD_TIMEOUT; + s = splbio(); + TAILQ_FOREACH(cm, &sc->aac_busy, cm_link) { + if ((cm->cm_timestamp < deadline) && !(cm->cm_flags & AAC_CMD_TIMEDOUT)) { + cm->cm_flags |= AAC_CMD_TIMEDOUT; + device_printf(sc->aac_dev, "COMMAND TIMED OUT AFTER %d SECONDS\n", + (int)(time_second - cm->cm_timestamp)); + AAC_PRINT_FIB(sc, cm->cm_fib); + } + } + splx(s); + + /* reset the timer for next time */ + timeout((timeout_t*)aac_timeout, sc, AAC_PERIODIC_INTERVAL * hz); + return; +} + /******************************************************************************** ******************************************************************************** Interface Function Vectors @@ -1600,7 +1592,7 @@ aac_describe_controller(struct aac_softc *sc) if (bufsize != sizeof(*info)) { device_printf(sc->aac_dev, "RequestAdapterInfo returned wrong data size (%d != %d)\n", bufsize, sizeof(*info)); - return; + /*return;*/ } info = (struct aac_adapter_info *)&buf[0]; @@ -1630,7 +1622,7 @@ aac_describe_code(struct aac_code_lookup *table, u_int32_t code) for (i = 0; table[i].string != NULL; i++) if (table[i].code == code) return(table[i].string); - return(table[i+1].string); + return(table[i + 1].string); } /***************************************************************************** @@ -1671,43 +1663,65 @@ aac_close(dev_t dev, int flags, int fmt, struct proc *p) static int aac_ioctl(dev_t dev, u_long cmd, caddr_t arg, int flag, struct proc *p) { - struct aac_softc *sc = dev->si_drv1; - int error = 0, i; + union aac_statrequest *as = (union aac_statrequest *)arg; + struct aac_softc *sc = dev->si_drv1; + int error = 0; +#ifdef AAC_COMPAT_LINUX + int i; +#endif debug_called(2); switch (cmd) { + case AACIO_STATS: + switch (as->as_item) { + case AACQ_FREE: + case AACQ_BIO: + case AACQ_READY: + case AACQ_BUSY: + case AACQ_COMPLETE: + bcopy(&sc->aac_qstat[as->as_item], &as->as_qstat, sizeof(struct aac_qstat)); + break; + default: + error = ENOENT; + break; + } + break; + #ifdef AAC_COMPAT_LINUX case FSACTL_SENDFIB: - debug(0, "FSACTL_SENDFIB"); + debug(1, "FSACTL_SENDFIB"); error = aac_ioctl_sendfib(sc, arg); break; case FSACTL_AIF_THREAD: - debug(0, "FSACTL_AIF_THREAD"); + debug(1, "FSACTL_AIF_THREAD"); error = EINVAL; break; case FSACTL_OPEN_GET_ADAPTER_FIB: - debug(0, "FSACTL_OPEN_GET_ADAPTER_FIB"); + debug(1, "FSACTL_OPEN_GET_ADAPTER_FIB"); /* * Pass the caller out an AdapterFibContext. * * Note that because we only support one opener, we * basically ignore this. Set the caller's context to a magic * number just in case. + * + * The Linux code hands the driver a pointer into kernel space, + * and then trusts it when the caller hands it back. Aiee! */ i = AAC_AIF_SILLYMAGIC; error = copyout(&i, arg, sizeof(i)); break; case FSACTL_GET_NEXT_ADAPTER_FIB: - debug(0, "FSACTL_GET_NEXT_ADAPTER_FIB"); + debug(1, "FSACTL_GET_NEXT_ADAPTER_FIB"); error = aac_linux_getnext_aif(sc, arg); break; case FSACTL_CLOSE_GET_ADAPTER_FIB: - debug(0, "FSACTL_CLOSE_GET_ADAPTER_FIB"); + debug(1, "FSACTL_CLOSE_GET_ADAPTER_FIB"); /* don't do anything here */ break; case FSACTL_MINIPORT_REV_CHECK: - debug(0, "FSACTL_MINIPORT_REV_CHECK"); + debug(1, "FSACTL_MINIPORT_REV_CHECK"); error = aac_linux_rev_check(sc, arg); break; #endif @@ -1801,28 +1815,6 @@ aac_handle_aif(struct aac_softc *sc, struct aac_aif_command *aif) aac_print_aif(sc, aif); } -/******************************************************************************** - * Hand the next AIF off the top of the queue out to userspace. - */ -static int -aac_return_aif(struct aac_softc *sc, caddr_t uptr) -{ - int error, s; - - debug_called(2); - - s = splbio(); - 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) - sc->aac_aifq_tail = (sc->aac_aifq_tail + 1) % AAC_AIFQ_LENGTH; - } - splx(s); - return(error); -} - /******************************************************************************** ******************************************************************************** Linux Management Interface @@ -1860,7 +1852,7 @@ aac_linux_ioctl(struct proc *p, struct linux_ioctl_args *args) } /******************************************************************************** - * Return the Revision of the driver to the userspace and check to see if the + * Return the Revision of the driver to userspace and check to see if the * userspace app is possibly compatible. This is extremely bogus right now * because I have no idea how to handle the versioning of this driver. It is * needed, though, to get aaccli working. @@ -1914,14 +1906,14 @@ aac_linux_getnext_aif(struct aac_softc *sc, caddr_t arg) } else { s = splbio(); - error = aac_return_aif(sc, agf.AifFib); + error = aac_linux_return_aif(sc, agf.AifFib); if ((error == EAGAIN) && (agf.Wait)) { sc->aac_state |= AAC_STATE_AIF_SLEEPER; while (error == EAGAIN) { error = tsleep(sc->aac_aifq, PRIBIO | PCATCH, "aacaif", 0); if (error == 0) - error = aac_return_aif(sc, agf.AifFib); + error = aac_linux_return_aif(sc, agf.AifFib); } sc->aac_state &= ~AAC_STATE_AIF_SLEEPER; } @@ -1931,4 +1923,27 @@ aac_linux_getnext_aif(struct aac_softc *sc, caddr_t arg) return(error); } +/******************************************************************************** + * Hand the next AIF off the top of the queue out to userspace. + */ +static int +aac_linux_return_aif(struct aac_softc *sc, caddr_t uptr) +{ + int error, s; + + debug_called(2); + + s = splbio(); + 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) + sc->aac_aifq_tail = (sc->aac_aifq_tail + 1) % AAC_AIFQ_LENGTH; + } + splx(s); + return(error); +} + + #endif /* AAC_COMPAT_LINUX */ diff --git a/sys/dev/aac/aac_compat.h b/sys/dev/aac/aac_compat.h index 26429b596c6e..5c3ab8bc0915 100644 --- a/sys/dev/aac/aac_compat.h +++ b/sys/dev/aac/aac_compat.h @@ -60,5 +60,5 @@ #else /* new bio style */ # include -#define BIO_IS_READ(x) ((x)->bio_cmd == BIO_READ) +# define BIO_IS_READ(x) ((x)->bio_cmd == BIO_READ) #endif diff --git a/sys/dev/aac/aac_debug.c b/sys/dev/aac/aac_debug.c index 09293adeee28..3298502bb300 100644 --- a/sys/dev/aac/aac_debug.c +++ b/sys/dev/aac/aac_debug.c @@ -44,6 +44,7 @@ #include #include +#include #include void aac_printstate0(void); @@ -90,7 +91,16 @@ aac_print_queues(struct aac_softc *sc) sc->aac_queues->qt_qindex[AAC_ADAP_HIGH_RESP_QUEUE][AAC_PRODUCER_INDEX], sc->aac_queues->qt_qindex[AAC_ADAP_HIGH_RESP_QUEUE][AAC_CONSUMER_INDEX], AAC_ADAP_HIGH_RESP_ENTRIES); - + device_printf(sc->aac_dev, "AACQ_FREE %d/%d\n", + sc->aac_qstat[AACQ_FREE].q_length, sc->aac_qstat[AACQ_FREE].q_max); + device_printf(sc->aac_dev, "AACQ_BIO %d/%d\n", + sc->aac_qstat[AACQ_BIO].q_length, sc->aac_qstat[AACQ_BIO].q_max); + device_printf(sc->aac_dev, "AACQ_READY %d/%d\n", + sc->aac_qstat[AACQ_READY].q_length, sc->aac_qstat[AACQ_READY].q_max); + device_printf(sc->aac_dev, "AACQ_BUSY %d/%d\n", + sc->aac_qstat[AACQ_BUSY].q_length, sc->aac_qstat[AACQ_BUSY].q_max); + device_printf(sc->aac_dev, "AACQ_COMPLETE %d/%d\n", + sc->aac_qstat[AACQ_COMPLETE].q_length, sc->aac_qstat[AACQ_COMPLETE].q_max); } /******************************************************************************** diff --git a/sys/dev/aac/aac_disk.c b/sys/dev/aac/aac_disk.c index 3b6581d918a8..1505a6adeec5 100644 --- a/sys/dev/aac/aac_disk.c +++ b/sys/dev/aac/aac_disk.c @@ -41,6 +41,7 @@ #include #include +#include #include /* @@ -187,13 +188,15 @@ aac_disk_strategy(struct bio *bp) * Handle completion of an I/O request. */ void -aac_complete_bio(struct bio *bp) +aac_biodone(struct bio *bp) { struct aac_disk *sc = (struct aac_disk *)bp->bio_dev->si_drv1; debug_called(4); devstat_end_transaction_bio(&sc->ad_stats, bp); + if (bp->bio_flags & BIO_ERROR) + diskerr(bp, (char *)bp->bio_driver1, 0, &sc->ad_label); biodone(bp); } @@ -226,7 +229,7 @@ aac_disk_attach(device_t dev) sc->ad_container = device_get_ivars(dev); sc->ad_dev = dev; - /* require that extended translation be enabled XXX document! */ + /* require that extended translation be enabled - other drivers read the disk! */ sc->ad_size = sc->ad_container->co_mntobj.Capacity; if (sc->ad_size >= (2 * 1024 * 1024)) { /* 2GB */ sc->ad_heads = 255; diff --git a/sys/dev/aac/aac_ioctl.h b/sys/dev/aac/aac_ioctl.h index 354c0aa5cddc..084e6e4db4a4 100644 --- a/sys/dev/aac/aac_ioctl.h +++ b/sys/dev/aac/aac_ioctl.h @@ -28,6 +28,31 @@ * $FreeBSD$ */ +/* + * Command queue statistics + */ +#define AACQ_FREE 0 +#define AACQ_BIO 1 +#define AACQ_READY 2 +#define AACQ_BUSY 3 +#define AACQ_COMPLETE 4 +#define AACQ_COUNT 5 /* total number of queues */ + +struct aac_qstat { + u_int32_t q_length; + u_int32_t q_max; +}; + +/* + * Statistics request + */ +union aac_statrequest { + u_int32_t as_item; + struct aac_qstat as_qstat; +}; + +#define AACIO_STATS _IOWR('T', 101, union aac_statrequest) + #ifdef AAC_COMPAT_LINUX /* diff --git a/sys/dev/aac/aac_pci.c b/sys/dev/aac/aac_pci.c index 654954bfd211..654e07537c36 100644 --- a/sys/dev/aac/aac_pci.c +++ b/sys/dev/aac/aac_pci.c @@ -50,6 +50,7 @@ #include #include +#include #include static int aac_pci_probe(device_t dev); @@ -230,7 +231,7 @@ aac_pci_attach(device_t dev) BUS_SPACE_MAXADDR, /* lowaddr */ BUS_SPACE_MAXADDR, /* highaddr */ NULL, NULL, /* filter, filterarg */ - AAC_CLUSTER_COUNT * sizeof(struct aac_fib), 1,/* maxsize, nsegments */ + AAC_FIB_COUNT * sizeof(struct aac_fib), 1, /* maxsize, nsegments */ BUS_SPACE_MAXSIZE_32BIT, /* maxsegsize */ 0, /* flags */ &sc->aac_fib_dmat)) { @@ -241,6 +242,7 @@ 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))) { @@ -259,6 +261,11 @@ aac_pci_attach(device_t dev) break; } } + if (sc->aac_hwif == AAC_HWIF_UNKNOWN) { + device_printf(sc->aac_dev, "unknown hardware type\n"); + error = ENXIO; + goto out; + } /* * Do bus-independent initialisation. diff --git a/sys/dev/aac/aacreg.h b/sys/dev/aac/aacreg.h index 9f538a36b739..3fda5144d6b5 100644 --- a/sys/dev/aac/aacreg.h +++ b/sys/dev/aac/aacreg.h @@ -489,7 +489,7 @@ struct aac_adapter_info { u_int32_t TotalMem; /* adapter Total Memory */ struct FsaRevision KernelRevision; /* adapter Kernel Software Revision */ struct FsaRevision MonitorRevision; /* adapter Monitor/Diagnostic Software Revision */ - struct FsaRevision HardwareRevision;/* TDB */ + struct FsaRevision HardwareRevision;/* TBD */ struct FsaRevision BIOSRevision; /* adapter BIOS Revision */ u_int32_t ClusteringEnabled; u_int32_t ClusterChannelMask; diff --git a/sys/dev/aac/aacvar.h b/sys/dev/aac/aacvar.h index f70cb6480ff9..0869ccb3909b 100644 --- a/sys/dev/aac/aacvar.h +++ b/sys/dev/aac/aacvar.h @@ -45,13 +45,12 @@ #define AAC_ADAPTER_FIBS 8 /* - * FIBs are allocated in clusters as we need them; each cluster must be physically - * contiguous. Set the number of FIBs to try to allocate in a cluster. - * Setting this value too high may result in FIBs not being available in conditions - * of high load with fragmented physical memory. The value must be a multiple of - * (PAGE_SIZE / 512). + * 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. */ -#define AAC_CLUSTER_COUNT 64 +#define AAC_FIB_COUNT 128 /* * The controller reports status events in AIFs. We hang on to a number of these @@ -72,7 +71,18 @@ /* * Timeout for immediate commands. */ -#define AAC_IMMEDIATE_TIMEOUT 30 +#define AAC_IMMEDIATE_TIMEOUT 30 /* seconds */ + +/* + * Timeout for normal commands + */ +#define AAC_CMD_TIMEOUT 30 /* seconds */ + +/* + * Rate at which we periodically check for timed out commands and kick the + * controller. + */ +#define AAC_PERIODIC_INTERVAL 10 /* seconds */ /* * Character device major numbers. @@ -139,26 +149,11 @@ struct aac_command #define AAC_CMD_DATAIN (1<<1) /* command involves data moving from controller to host */ #define AAC_CMD_DATAOUT (1<<2) /* command involves data moving from host to controller */ #define AAC_CMD_COMPLETED (1<<3) /* command has been completed */ +#define AAC_CMD_TIMEDOUT (1<<4) /* command taken too long */ void (* cm_complete)(struct aac_command *cm); void *cm_private; - struct callout_handle timeout_handle; /* timeout handle */ -}; - -/* - * Command/command packet cluster. - * - * Due to the difficulty of using the zone allocator to create a new - * zone from within a module, we use our own clustering to reduce - * memory wastage due to allocating lots of these small structures. - */ -struct aac_command_cluster -{ - TAILQ_ENTRY(aac_command_cluster) cmc_link; - struct aac_fib *cmc_fibs; - bus_dmamap_t cmc_fibmap; - u_int32_t cmc_fibphys; - struct aac_command cmc_command[AAC_CLUSTER_COUNT]; + time_t cm_timestamp; /* command creation time */ }; /* @@ -231,29 +226,30 @@ extern struct aac_interface aac_sa_interface; struct aac_softc { /* bus connections */ - device_t aac_dev; - struct resource *aac_regs_resource; /* register interface window */ - int aac_regs_rid; /* resource ID */ - bus_space_handle_t aac_bhandle; /* bus space handle */ - bus_space_tag_t aac_btag; /* bus space tag */ - bus_dma_tag_t aac_parent_dmat; /* parent DMA tag */ - bus_dma_tag_t aac_buffer_dmat; /* data buffer/command DMA tag */ - struct resource *aac_irq; /* interrupt */ - int aac_irq_rid; - void *aac_intr; /* interrupt handle */ + device_t aac_dev; + struct resource *aac_regs_resource; /* register interface window */ + int aac_regs_rid; /* resource ID */ + bus_space_handle_t aac_bhandle; /* bus space handle */ + bus_space_tag_t aac_btag; /* bus space tag */ + bus_dma_tag_t aac_parent_dmat; /* parent DMA tag */ + bus_dma_tag_t aac_buffer_dmat; /* data buffer/command DMA tag */ + struct resource *aac_irq; /* interrupt */ + int aac_irq_rid; + void *aac_intr; /* interrupt handle */ /* controller features, limits and status */ - int aac_state; + int aac_state; #define AAC_STATE_SUSPEND (1<<0) #define AAC_STATE_OPEN (1<<1) #define AAC_STATE_INTERRUPTS_ON (1<<2) #define AAC_STATE_AIF_SLEEPER (1<<3) - struct FsaRevision aac_revision; + struct FsaRevision aac_revision; /* controller hardware interface */ int aac_hwif; #define AAC_HWIF_I960RX 0 #define AAC_HWIF_STRONGARM 1 +#define AAC_HWIF_UNKNOWN -1 bus_dma_tag_t aac_common_dmat; /* common structure DMA tag */ bus_dmamap_t aac_common_dmamap; /* common structure DMA map */ struct aac_common *aac_common; @@ -261,17 +257,23 @@ struct aac_softc struct aac_interface aac_if; /* command/fib resources */ - TAILQ_HEAD(,aac_command_cluster) aac_clusters; /* command memory blocks */ - bus_dma_tag_t aac_fib_dmat; /* DMA tag for allocating FIBs */ + bus_dma_tag_t aac_fib_dmat; /* DMA tag for allocating FIBs */ + struct aac_fib *aac_fibs; + bus_dmamap_t aac_fibmap; + u_int32_t aac_fibphys; + struct aac_command aac_command[AAC_FIB_COUNT]; /* command management */ - TAILQ_HEAD(,aac_command) aac_freecmds; /* command structures available for reuse */ + TAILQ_HEAD(,aac_command) aac_free; /* command structures available for reuse */ TAILQ_HEAD(,aac_command) aac_ready; /* commands on hold for controller resources */ - TAILQ_HEAD(,aac_command) aac_completed; /* commands which have been returned by the controller */ + TAILQ_HEAD(,aac_command) aac_busy; + TAILQ_HEAD(,aac_command) aac_complete; /* commands which have been returned by the controller */ struct bio_queue_head aac_bioq; struct aac_queue_table *aac_queues; struct aac_queue_entry *aac_qentries[AAC_QUEUE_COUNT]; + struct aac_qstat aac_qstat[AACQ_COUNT]; /* queue statistics */ + /* connected containters */ struct aac_container aac_container[AAC_MAX_CONTAINERS]; @@ -301,7 +303,7 @@ extern int aac_resume(device_t dev); extern void aac_intr(void *arg); extern devclass_t aac_devclass; extern void aac_submit_bio(struct bio *bp); -extern void aac_complete_bio(struct bio *bp); +extern void aac_biodone(struct bio *bp); /* * Debugging levels: @@ -310,25 +312,31 @@ extern void aac_complete_bio(struct bio *bp); * 2 - extremely noisy, emit trace items in loops, etc. */ #ifdef AAC_DEBUG -#define debug(level, fmt, args...) do { if (level <= AAC_DEBUG) printf("%s: " fmt "\n", __FUNCTION__ , ##args); } while(0) -#define debug_called(level) do { if (level <= AAC_DEBUG) printf(__FUNCTION__ ": called\n"); } while(0) +# define debug(level, fmt, args...) \ + do { \ + if (level <= AAC_DEBUG) printf("%s: " fmt "\n", __FUNCTION__ , ##args); \ + } while(0) +# define debug_called(level) \ + do { \ + if (level <= AAC_DEBUG) printf(__FUNCTION__ ": called\n"); \ + } while(0) extern void aac_print_queues(struct aac_softc *sc); extern void aac_panic(struct aac_softc *sc, char *reason); extern void aac_print_fib(struct aac_softc *sc, struct aac_fib *fib, char *caller); extern void aac_print_aif(struct aac_softc *sc, struct aac_aif_command *aif); -#define AAC_PRINT_FIB(sc, fib) aac_print_fib(sc, fib, __FUNCTION__) +# define AAC_PRINT_FIB(sc, fib) aac_print_fib(sc, fib, __FUNCTION__) #else -#define debug(level, fmt, args...) -#define debug_called(level) +# define debug(level, fmt, args...) +# define debug_called(level) -#define aac_print_queues(sc) -#define aac_panic(sc, reason) -#define aac_print_aif(sc, aif) +# define aac_print_queues(sc) +# define aac_panic(sc, reason) +# define aac_print_aif(sc, aif) -#define AAC_PRINT_FIB(sc, fib) +# define AAC_PRINT_FIB(sc, fib) #endif struct aac_code_lookup { @@ -337,109 +345,115 @@ struct aac_code_lookup { }; /******************************************************************************** - * Queue primitives - * - * These are broken out individually to make statistics gathering easier. + * Queue primitives for driver queues. */ +#define AACQ_ADD(sc, qname) \ + do { \ + struct aac_qstat *qs = &(sc)->aac_qstat[qname]; \ + \ + qs->q_length++; \ + if (qs->q_length > qs->q_max) \ + qs->q_max = qs->q_length; \ + } while(0) + +#define AACQ_REMOVE(sc, qname) (sc)->aac_qstat[qname].q_length-- +#define AACQ_INIT(sc, qname) \ + do { \ + sc->aac_qstat[qname].q_length = 0; \ + sc->aac_qstat[qname].q_max = 0; \ + } while(0) + + +#define AACQ_COMMAND_QUEUE(name, index) \ +static __inline void \ +aac_initq_ ## name (struct aac_softc *sc) \ +{ \ + TAILQ_INIT(&sc->aac_ ## name); \ + AACQ_INIT(sc, index); \ +} \ +static __inline void \ +aac_enqueue_ ## name (struct aac_command *cm) \ +{ \ + int s; \ + \ + s = splbio(); \ + TAILQ_INSERT_TAIL(&cm->cm_sc->aac_ ## name, cm, cm_link); \ + AACQ_ADD(cm->cm_sc, index); \ + splx(s); \ +} \ +static __inline void \ +aac_requeue_ ## name (struct aac_command *cm) \ +{ \ + int s; \ + \ + s = splbio(); \ + TAILQ_INSERT_HEAD(&cm->cm_sc->aac_ ## name, cm, cm_link); \ + AACQ_ADD(cm->cm_sc, index); \ + splx(s); \ +} \ +static __inline struct aac_command * \ +aac_dequeue_ ## name (struct aac_softc *sc) \ +{ \ + struct aac_command *cm; \ + int s; \ + \ + s = splbio(); \ + if ((cm = TAILQ_FIRST(&sc->aac_ ## name)) != NULL) { \ + TAILQ_REMOVE(&sc->aac_ ## name, cm, cm_link); \ + AACQ_REMOVE(sc, index); \ + } \ + splx(s); \ + return(cm); \ +} \ +static __inline void \ +aac_remove_ ## name (struct aac_command *cm) \ +{ \ + int s; \ + \ + s = splbio(); \ + TAILQ_REMOVE(&cm->cm_sc->aac_ ## name, cm, cm_link); \ + AACQ_REMOVE(cm->cm_sc, index); \ + splx(s); \ +} \ +struct hack + +AACQ_COMMAND_QUEUE(free, AACQ_FREE); +AACQ_COMMAND_QUEUE(ready, AACQ_READY); +AACQ_COMMAND_QUEUE(busy, AACQ_BUSY); +AACQ_COMMAND_QUEUE(complete, AACQ_COMPLETE); + +/* + * outstanding bio queue + */ +static __inline void +aac_initq_bio(struct aac_softc *sc) +{ + bioq_init(&sc->aac_bioq); + AACQ_INIT(sc, AACQ_BIO); +} static __inline void -aac_enqueue_ready(struct aac_command *cm) +aac_enqueue_bio(struct aac_softc *sc, struct bio *bp) { int s; s = splbio(); - TAILQ_INSERT_TAIL(&cm->cm_sc->aac_ready, cm, cm_link); + bioq_insert_tail(&sc->aac_bioq, bp); + AACQ_ADD(sc, AACQ_BIO); splx(s); } -static __inline void -aac_requeue_ready(struct aac_command *cm) +static __inline struct bio * +aac_dequeue_bio(struct aac_softc *sc) { int s; + struct bio *bp; s = splbio(); - TAILQ_INSERT_HEAD(&cm->cm_sc->aac_ready, cm, cm_link); + if ((bp = bioq_first(&sc->aac_bioq)) != NULL) { + bioq_remove(&sc->aac_bioq, bp); + AACQ_REMOVE(sc, AACQ_BIO); + } splx(s); -} - -static __inline struct aac_command * -aac_dequeue_ready(struct aac_softc *sc) -{ - struct aac_command *cm; - int s; - - s = splbio(); - if ((cm = TAILQ_FIRST(&sc->aac_ready)) != NULL) - TAILQ_REMOVE(&sc->aac_ready, cm, cm_link); - splx(s); - return(cm); -} - -static __inline void -aac_enqueue_completed(struct aac_command *cm) -{ - int s; - - s = splbio(); - TAILQ_INSERT_TAIL(&cm->cm_sc->aac_completed, cm, cm_link); - splx(s); -} - -static __inline struct aac_command * -aac_dequeue_completed(struct aac_softc *sc) -{ - struct aac_command *cm; - int s; - - s = splbio(); - if ((cm = TAILQ_FIRST(&sc->aac_completed)) != NULL) - TAILQ_REMOVE(&sc->aac_completed, cm, cm_link); - splx(s); - return(cm); -} - -static __inline void -aac_enqueue_free(struct aac_command *cm) -{ - int s; - - s = splbio(); - TAILQ_INSERT_HEAD(&cm->cm_sc->aac_freecmds, cm, cm_link); - splx(s); -} - -static __inline struct aac_command * -aac_dequeue_free(struct aac_softc *sc) -{ - struct aac_command *cm; - int s; - - s = splbio(); - if ((cm = TAILQ_FIRST(&sc->aac_freecmds)) != NULL) - TAILQ_REMOVE(&sc->aac_freecmds, cm, cm_link); - splx(s); - return(cm); -} - -static __inline void -aac_enqueue_cluster(struct aac_softc *sc, struct aac_command_cluster *cmc) -{ - int s; - - s = splbio(); - TAILQ_INSERT_HEAD(&sc->aac_clusters, cmc, cmc_link); - splx(s); -} - -static __inline struct aac_command_cluster * -aac_dequeue_cluster(struct aac_softc *sc) -{ - struct aac_command_cluster *cmc; - int s; - - s = splbio(); - if ((cmc = TAILQ_FIRST(&sc->aac_clusters)) != NULL) - TAILQ_REMOVE(&sc->aac_clusters, cmc, cmc_link); - splx(s); - return(cmc); + return(bp); } diff --git a/sys/sys/aac_ioctl.h b/sys/sys/aac_ioctl.h index 354c0aa5cddc..084e6e4db4a4 100644 --- a/sys/sys/aac_ioctl.h +++ b/sys/sys/aac_ioctl.h @@ -28,6 +28,31 @@ * $FreeBSD$ */ +/* + * Command queue statistics + */ +#define AACQ_FREE 0 +#define AACQ_BIO 1 +#define AACQ_READY 2 +#define AACQ_BUSY 3 +#define AACQ_COMPLETE 4 +#define AACQ_COUNT 5 /* total number of queues */ + +struct aac_qstat { + u_int32_t q_length; + u_int32_t q_max; +}; + +/* + * Statistics request + */ +union aac_statrequest { + u_int32_t as_item; + struct aac_qstat as_qstat; +}; + +#define AACIO_STATS _IOWR('T', 101, union aac_statrequest) + #ifdef AAC_COMPAT_LINUX /*