aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMike Smith <msmith@FreeBSD.org>2000-12-27 13:14:56 +0000
committerMike Smith <msmith@FreeBSD.org>2000-12-27 13:14:56 +0000
commit0b94a66e3f8a898cdf6481c428f6cedca31c3958 (patch)
treeec62607fcbabe6e3a1c785966ff8fda5084b071f
parent826737698c2b14f965eba2841619566ab3e08b0b (diff)
downloadsrc-0b94a66e3f8a898cdf6481c428f6cedca31c3958.tar.gz
src-0b94a66e3f8a898cdf6481c428f6cedca31c3958.zip
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.
Notes
Notes: svn path=/head/; revision=70393
-rw-r--r--sys/dev/aac/aac.c407
-rw-r--r--sys/dev/aac/aac_compat.h2
-rw-r--r--sys/dev/aac/aac_debug.c12
-rw-r--r--sys/dev/aac/aac_disk.c7
-rw-r--r--sys/dev/aac/aac_ioctl.h25
-rw-r--r--sys/dev/aac/aac_pci.c9
-rw-r--r--sys/dev/aac/aacreg.h2
-rw-r--r--sys/dev/aac/aacvar.h286
-rw-r--r--sys/sys/aac_ioctl.h25
9 files changed, 437 insertions, 338 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 <sys/disk.h>
#include <sys/file.h>
#include <sys/signalvar.h>
+#include <sys/time.h>
#include <machine/bus_memio.h>
#include <machine/bus.h>
#include <machine/resource.h>
#include <dev/aac/aacreg.h>
+#include <dev/aac/aac_ioctl.h>
#include <dev/aac/aacvar.h>
#include <dev/aac/aac_tables.h>
-#include <dev/aac/aac_ioctl.h>
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
/*
@@ -209,9 +205,15 @@ aac_attach(struct aac_softc *sc)
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)
@@ -1416,6 +1373,41 @@ out:
}
/********************************************************************************
+ * 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
@@ -1802,28 +1816,6 @@ aac_handle_aif(struct aac_softc *sc, struct aac_aif_command *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 <sys/bio.h>
-#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 <machine/bus.h>
#include <dev/aac/aacreg.h>
+#include <dev/aac/aac_ioctl.h>
#include <dev/aac/aacvar.h>
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 <sys/rman.h>
#include <dev/aac/aacreg.h>
+#include <dev/aac/aac_ioctl.h>
#include <dev/aac/aacvar.h>
/*
@@ -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 <pci/pcivar.h>
#include <dev/aac/aacreg.h>
+#include <dev/aac/aac_ioctl.h>
#include <dev/aac/aacvar.h>
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_enqueue_ready(struct aac_command *cm)
-{
- int s;
-
- s = splbio();
- TAILQ_INSERT_TAIL(&cm->cm_sc->aac_ready, cm, cm_link);
- splx(s);
-}
-
-static __inline void
-aac_requeue_ready(struct aac_command *cm)
-{
- int s;
-
- s = splbio();
- TAILQ_INSERT_HEAD(&cm->cm_sc->aac_ready, cm, cm_link);
- 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)
+aac_initq_bio(struct aac_softc *sc)
{
- 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);
+ bioq_init(&sc->aac_bioq);
+ AACQ_INIT(sc, AACQ_BIO);
}
static __inline void
-aac_enqueue_free(struct aac_command *cm)
+aac_enqueue_bio(struct aac_softc *sc, struct bio *bp)
{
int s;
s = splbio();
- TAILQ_INSERT_HEAD(&cm->cm_sc->aac_freecmds, cm, cm_link);
+ bioq_insert_tail(&sc->aac_bioq, bp);
+ AACQ_ADD(sc, AACQ_BIO);
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)
+static __inline struct bio *
+aac_dequeue_bio(struct aac_softc *sc)
{
int s;
+ struct bio *bp;
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);
+ if ((bp = bioq_first(&sc->aac_bioq)) != NULL) {
+ bioq_remove(&sc->aac_bioq, bp);
+ AACQ_REMOVE(sc, AACQ_BIO);
+ }
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
/*