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.
This commit is contained in:
Mike Smith 2000-12-27 13:14:56 +00:00
parent 826737698c
commit 0b94a66e3f
9 changed files with 441 additions and 342 deletions

View File

@ -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
/*
@ -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 */

View File

@ -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

View File

@ -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);
}
/********************************************************************************

View File

@ -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;

View File

@ -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
/*

View File

@ -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.

View File

@ -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;

View File

@ -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);
}

View File

@ -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
/*