Prepare for a major update to the aac driver:

Update the aac driver with the new crashdump api.
	Protect sync fibs with a mutex.
	Align all DMA buffers on a PAGE_SIZE boundary.

MFC after:	3 days
This commit is contained in:
Scott Long 2002-04-24 05:12:50 +00:00
parent d5d1c5a11e
commit cbfd045b10
5 changed files with 164 additions and 257 deletions

View File

@ -73,7 +73,7 @@
static void aac_startup(void *arg);
static void aac_add_container(struct aac_softc *sc,
struct aac_mntinforesponse *mir, int f);
struct aac_mntinforesp *mir, int f);
/* Command Processing */
static void aac_startio(struct aac_softc *sc);
@ -105,10 +105,6 @@ static int 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);
static int aac_sync_fib(struct aac_softc *sc, u_int32_t command,
u_int32_t xferstate, void *data,
u_int16_t datasize, void *result,
u_int16_t *resultsize);
static int aac_enqueue_fib(struct aac_softc *sc, int queue,
struct aac_command *cm);
static int aac_dequeue_fib(struct aac_softc *sc, int queue,
@ -271,6 +267,9 @@ aac_attach(struct aac_softc *sc)
if ((error = aac_alloc_commands(sc)) != 0)
return(error);
/* Init the sync fib lock */
AAC_LOCK_INIT(&sc->aac_sync_lock, "AAC sync FIB lock");
/*
* Initialise the adapter.
*/
@ -338,9 +337,9 @@ static void
aac_startup(void *arg)
{
struct aac_softc *sc;
struct aac_mntinfo mi;
struct aac_mntinforesponse mir;
u_int16_t rsize;
struct aac_fib *fib;
struct aac_mntinfo *mi;
struct aac_mntinforesp *mir = NULL;
int i = 0;
debug_called(1);
@ -350,28 +349,28 @@ aac_startup(void *arg)
/* disconnect ourselves from the intrhook chain */
config_intrhook_disestablish(&sc->aac_ich);
aac_get_sync_fib(sc, &fib, 0);
mi = (struct aac_mntinfo *)&fib->data[0];
/* loop over possible containers */
mi.Command = VM_NameServe;
mi.MntType = FT_FILESYS;
mi->Command = VM_NameServe;
mi->MntType = FT_FILESYS;
do {
/* request information on this container */
mi.MntCount = i;
rsize = sizeof(mir);
if (aac_sync_fib(sc, ContainerCommand, 0, &mi,
sizeof(struct aac_mntinfo), &mir, &rsize)) {
mi->MntCount = i;
if (aac_sync_fib(sc, ContainerCommand, 0, fib,
sizeof(struct aac_mntinfo))) {
debug(2, "error probing container %d", i);
continue;
}
/* check response size */
if (rsize != sizeof(mir)) {
debug(2, "container info response wrong size "
"(%d should be %d)", rsize, sizeof(mir));
continue;
}
aac_add_container(sc, &mir, 0);
mir = (struct aac_mntinforesp *)&fib->data[0];
aac_add_container(sc, mir, 0);
i++;
} while ((i < mir.MntRespCount) && (i < AAC_MAX_CONTAINERS));
} while ((i < mir->MntRespCount) && (i < AAC_MAX_CONTAINERS));
aac_release_sync_fib(sc);
/* poke the bus to actually attach the child devices */
if (bus_generic_attach(sc->aac_dev))
@ -391,7 +390,7 @@ aac_startup(void *arg)
* Create a device to respresent a new container
*/
static void
aac_add_container(struct aac_softc *sc, struct aac_mntinforesponse *mir, int f)
aac_add_container(struct aac_softc *sc, struct aac_mntinforesp *mir, int f)
{
struct aac_container *co;
device_t child;
@ -527,8 +526,9 @@ int
aac_shutdown(device_t dev)
{
struct aac_softc *sc;
struct aac_close_command cc;
int s, i;
struct aac_fib *fib;
struct aac_close_command *cc;
int s;
debug_called(1);
@ -545,20 +545,24 @@ aac_shutdown(device_t dev)
*/
device_printf(sc->aac_dev, "shutting down controller...");
cc.Command = VM_CloseAll;
cc.ContainerId = 0xffffffff;
if (aac_sync_fib(sc, ContainerCommand, 0, &cc, sizeof(cc), NULL, NULL))
aac_get_sync_fib(sc, &fib, AAC_SYNC_LOCK_FORCE);
cc = (struct aac_close_command *)&fib->data[0];
cc->Command = VM_CloseAll;
cc->ContainerId = 0xffffffff;
if (aac_sync_fib(sc, ContainerCommand, 0, fib,
sizeof(struct aac_close_command)))
printf("FAILED.\n");
else {
i = 0;
fib->data[0] = 0;
/*
* XXX Issuing this command to the controller makes it shut down
* but also keeps it from coming back up without a reset of the
* PCI bus. This is not desirable if you are just unloading the
* driver module with the intent to reload it later.
*/
if (aac_sync_fib(sc, FsaHostShutdown, AAC_FIBSTATE_SHUTDOWN, &i,
sizeof(i), NULL, NULL)) {
if (aac_sync_fib(sc, FsaHostShutdown, AAC_FIBSTATE_SHUTDOWN,
fib, 1)) {
printf("FAILED.\n");
} else {
printf("done.\n");
@ -999,102 +1003,6 @@ aac_bio_complete(struct aac_command *cm)
aac_biodone(bp);
}
/*
* Dump a block of data to the controller. If the queue is full, tell the
* caller to hold off and wait for the queue to drain.
*/
int
aac_dump_enqueue(struct aac_disk *ad, u_int32_t lba, void *data, int dumppages)
{
struct aac_softc *sc;
struct aac_command *cm;
struct aac_fib *fib;
struct aac_blockwrite *bw;
sc = ad->ad_controller;
cm = NULL;
if (aac_alloc_command(sc, &cm))
return (EBUSY);
/* fill out the command */
cm->cm_data = data;
cm->cm_datalen = dumppages * PAGE_SIZE;
cm->cm_complete = NULL;
cm->cm_private = NULL;
cm->cm_timestamp = time_second;
cm->cm_queue = AAC_ADAP_NORM_CMD_QUEUE;
/* build the FIB */
fib = cm->cm_fib;
fib->Header.XferState =
AAC_FIBSTATE_HOSTOWNED |
AAC_FIBSTATE_INITIALISED |
AAC_FIBSTATE_FROMHOST |
AAC_FIBSTATE_REXPECTED |
AAC_FIBSTATE_NORM;
fib->Header.Command = ContainerCommand;
fib->Header.Size = sizeof(struct aac_fib_header);
bw = (struct aac_blockwrite *)&fib->data[0];
bw->Command = VM_CtBlockWrite;
bw->ContainerId = ad->ad_container->co_mntobj.ObjectId;
bw->BlockNumber = lba;
bw->ByteCount = dumppages * PAGE_SIZE;
bw->Stable = CUNSTABLE; /* XXX what's appropriate here? */
fib->Header.Size += sizeof(struct aac_blockwrite);
cm->cm_flags |= AAC_CMD_DATAOUT;
cm->cm_sgtable = &bw->SgMap;
return (aac_start(cm));
}
/*
* Wait for the card's queue to drain when dumping. Also check for monitor
* printf's
*/
void
aac_dump_complete(struct aac_softc *sc)
{
struct aac_fib *fib;
struct aac_command *cm;
u_int16_t reason;
u_int32_t pi, ci, fib_size;
do {
reason = AAC_GET_ISTATUS(sc);
if (reason & AAC_DB_RESPONSE_READY) {
AAC_CLEAR_ISTATUS(sc, AAC_DB_RESPONSE_READY);
for (;;) {
if (aac_dequeue_fib(sc,
AAC_HOST_NORM_RESP_QUEUE,
&fib_size, &fib))
break;
cm = (struct aac_command *)
fib->Header.SenderData;
if (cm == NULL)
AAC_PRINT_FIB(sc, fib);
else {
aac_remove_busy(cm);
aac_unmap_command(cm);
aac_enqueue_complete(cm);
aac_release_command(cm);
}
}
}
if (reason & AAC_DB_PRINTF) {
AAC_CLEAR_ISTATUS(sc, AAC_DB_PRINTF);
aac_print_printf(sc);
}
pi = sc->aac_queues->qt_qindex[AAC_ADAP_NORM_CMD_QUEUE][
AAC_PRODUCER_INDEX];
ci = sc->aac_queues->qt_qindex[AAC_ADAP_NORM_CMD_QUEUE][
AAC_CONSUMER_INDEX];
} while (ci != pi);
return;
}
/*
* Submit a command to the controller, return when it completes.
* XXX This is very dangerous! If the card has gone out to lunch, we could
@ -1603,20 +1511,44 @@ aac_sync_command(struct aac_softc *sc, u_int32_t command,
return(0);
}
/*
* Grab the sync fib area.
*/
int
aac_get_sync_fib(struct aac_softc *sc, struct aac_fib **fib, int flags)
{
/*
* If the force flag is set, the system is shutting down, or in
* trouble. Ignore the mutex.
*/
if (!(flags & AAC_SYNC_LOCK_FORCE))
AAC_LOCK_ACQUIRE(&sc->aac_sync_lock);
*fib = &sc->aac_common->ac_sync_fib;
return (1);
}
/*
* Release the sync fib area.
*/
void
aac_release_sync_fib(struct aac_softc *sc)
{
AAC_LOCK_RELEASE(&sc->aac_sync_lock);
}
/*
* Send a synchronous FIB to the controller and wait for a result.
*/
static int
int
aac_sync_fib(struct aac_softc *sc, u_int32_t command, u_int32_t xferstate,
void *data, u_int16_t datasize,
void *result, u_int16_t *resultsize)
struct aac_fib *fib, u_int16_t datasize)
{
struct aac_fib *fib;
debug_called(3);
fib = &sc->aac_common->ac_sync_fib;
if (datasize > AAC_FIB_DATASIZE)
return(EINVAL);
@ -1636,17 +1568,6 @@ aac_sync_fib(struct aac_softc *sc, u_int32_t command, u_int32_t xferstate,
offsetof(struct aac_common,
ac_sync_fib);
/*
* Copy in data.
*/
if (data != NULL) {
KASSERT(datasize <= sizeof(fib->data),
("aac_sync_fib: datasize to large"));
bcopy(data, fib->data, datasize);
fib->Header.XferState |= AAC_FIBSTATE_FROMHOST |
AAC_FIBSTATE_NORM;
}
/*
* Give the FIB to the controller, wait for a response.
*/
@ -1656,19 +1577,7 @@ aac_sync_fib(struct aac_softc *sc, u_int32_t command, u_int32_t xferstate,
return(EIO);
}
/*
* Copy out the result
*/
if (result != NULL) {
u_int copysize;
copysize = fib->Header.Size - sizeof(struct aac_fib_header);
if (copysize > *resultsize)
copysize = *resultsize;
*resultsize = fib->Header.Size - sizeof(struct aac_fib_header);
bcopy(fib->data, result, copysize);
}
return(0);
return (0);
}
/*
@ -2156,28 +2065,19 @@ aac_fa_set_interrupts(struct aac_softc *sc, int enable)
static void
aac_describe_controller(struct aac_softc *sc)
{
u_int8_t buf[AAC_FIB_DATASIZE]; /* XXX really a bit big
* for the stack */
u_int16_t bufsize;
struct aac_fib *fib;
struct aac_adapter_info *info;
u_int8_t arg;
debug_called(2);
arg = 0;
bufsize = sizeof(buf);
if (aac_sync_fib(sc, RequestAdapterInfo, 0, &arg, sizeof(arg), &buf,
&bufsize)) {
aac_get_sync_fib(sc, &fib, 0);
fib->data[0] = 0;
if (aac_sync_fib(sc, RequestAdapterInfo, 0, fib, 1)) {
device_printf(sc->aac_dev, "RequestAdapterInfo failed\n");
return;
}
if (bufsize != sizeof(*info)) {
device_printf(sc->aac_dev,
"RequestAdapterInfo returned wrong data size "
"(%d != %d)\n", bufsize, sizeof(*info));
/*return;*/
}
info = (struct aac_adapter_info *)&buf[0];
info = (struct aac_adapter_info *)&fib->data[0];
device_printf(sc->aac_dev, "%s %dMHz, %dMB cache memory, %s\n",
aac_describe_code(aac_cpu_variant, info->CpuVariant),
@ -2444,8 +2344,8 @@ aac_handle_aif(struct aac_softc *sc, struct aac_fib *fib)
{
struct aac_aif_command *aif;
struct aac_container *co, *co_next;
struct aac_mntinfo mi;
struct aac_mntinforesponse mir;
struct aac_mntinfo *mi;
struct aac_mntinforesp *mir = NULL;
u_int16_t rsize;
int next, found;
int added = 0, i = 0;
@ -2466,8 +2366,10 @@ aac_handle_aif(struct aac_softc *sc, struct aac_fib *fib)
* doesn't tell us anything else! Re-enumerate the
* containers and sort things out.
*/
mi.Command = VM_NameServe;
mi.MntType = FT_FILESYS;
aac_get_sync_fib(sc, &fib, 0);
mi = (struct aac_mntinfo *)&fib->data[0];
mi->Command = VM_NameServe;
mi->MntType = FT_FILESYS;
do {
/*
* Ask the controller for its containers one at
@ -2476,32 +2378,28 @@ aac_handle_aif(struct aac_softc *sc, struct aac_fib *fib)
* midway through this enumaration?
* XXX This should be done async.
*/
mi.MntCount = i;
mi->MntCount = i;
rsize = sizeof(mir);
if (aac_sync_fib(sc, ContainerCommand, 0, &mi,
sizeof(mi), &mir, &rsize)) {
if (aac_sync_fib(sc, ContainerCommand, 0, fib,
sizeof(struct aac_mntinfo))) {
debug(2, "Error probing container %d\n",
i);
continue;
}
if (rsize != sizeof(mir)) {
debug(2, "Container response size too "
"large\n");
continue;
}
mir = (struct aac_mntinforesp *)&fib->data[0];
/*
* Check the container against our list.
* co->co_found was already set to 0 in a
* previous run.
*/
if ((mir.Status == ST_OK) &&
(mir.MntTable[0].VolType != CT_NONE)) {
if ((mir->Status == ST_OK) &&
(mir->MntTable[0].VolType != CT_NONE)) {
found = 0;
TAILQ_FOREACH(co,
&sc->aac_container_tqh,
co_link) {
if (co->co_mntobj.ObjectId ==
mir.MntTable[0].ObjectId) {
mir->MntTable[0].ObjectId) {
co->co_found = 1;
found = 1;
break;
@ -2519,12 +2417,13 @@ aac_handle_aif(struct aac_softc *sc, struct aac_fib *fib)
/*
* This is a new container. Do all the
* appropriate things to set it up. */
aac_add_container(sc, &mir, 1);
aac_add_container(sc, mir, 1);
added = 1;
}
i++;
} while ((i < mir.MntRespCount) &&
} while ((i < mir->MntRespCount) &&
(i < AAC_MAX_CONTAINERS));
aac_release_sync_fib(sc);
/*
* Go through our list of containers and see which ones

View File

@ -108,18 +108,18 @@ static driver_t aac_disk_driver = {
sizeof(struct aac_disk)
};
#define AAC_MAXIO 65536
DRIVER_MODULE(aacd, aac, aac_disk_driver, aac_disk_devclass, 0, 0);
/* sysctl tunables */
static unsigned int aac_iosize_max = 65536; /* due to limits of the card */
static unsigned int aac_iosize_max = AAC_MAXIO; /* due to limits of the card */
TUNABLE_INT("hw.aac.iosize_max", &aac_iosize_max);
SYSCTL_DECL(_hw_aac);
SYSCTL_UINT(_hw_aac, OID_AUTO, iosize_max, CTLFLAG_RD, &aac_iosize_max, 0,
"Max I/O size per transfer to an array");
#define AAC_MAXIO 65536
/*
* Handle open from generic layer.
*
@ -212,89 +212,90 @@ aac_disk_strategy(struct bio *bp)
return;
}
/*
* Map the S/G elements for doing a dump.
*/
static void
aac_dump_map_sg(void *arg, bus_dma_segment_t *segs, int nsegs, int error)
{
struct aac_fib *fib;
struct aac_blockwrite *bw;
struct aac_sg_table *sg;
int i;
fib = (struct aac_fib *)arg;
bw = (struct aac_blockwrite *)&fib->data[0];
sg = &bw->SgMap;
if (sg != NULL) {
sg->SgCount = nsegs;
for (i = 0; i < nsegs; i++) {
sg->SgEntry[i].SgAddress = segs[i].ds_addr;
sg->SgEntry[i].SgByteCount = segs[i].ds_len;
}
fib->Header.Size = nsegs * sizeof(struct aac_sg_entry);
}
}
/*
* Dump memory out to an array
*
* This queues blocks of memory of size AAC_MAXIO to the controller and waits
* for the controller to complete the requests.
* Send out one command at a time with up to AAC_MAXIO of data.
*/
static int
aac_disk_dump(dev_t dev, void *virtual, vm_offset_t physical, off_t offset, size_t length)
{
/* XXX: This needs modified for the new dump API */
return (ENXIO);
#if 0
struct aac_disk *ad;
struct aac_softc *sc;
vm_offset_t addr;
long blkcnt;
unsigned int count, blkno, secsize;
int dumppages;
int i, error;
struct aac_fib *fib;
struct aac_blockwrite *bw;
size_t len;
int size;
static bus_dmamap_t dump_datamap;
static int first = 0;
ad = dev->si_drv1;
addr = 0;
dumppages = AAC_MAXIO / PAGE_SIZE;
if ((error = disk_dumpcheck(dev, &count, &blkno, &secsize)))
return (error);
if (ad == NULL)
return (ENXIO);
return (EINVAL);
sc= ad->ad_controller;
blkcnt = howmany(PAGE_SIZE, secsize);
while (count > 0) {
caddr_t va = NULL;
if ((count / blkcnt) < dumppages)
dumppages = count / blkcnt;
for (i = 0; i < dumppages; ++i) {
vm_offset_t a = addr + (i * PAGE_SIZE);
if (is_physical_memory(a)) {
va = pmap_kenter_temporary(trunc_page(a), i);
} else {
va = pmap_kenter_temporary(trunc_page(0), i);
}
if (!first) {
first = 1;
if (bus_dmamap_create(sc->aac_buffer_dmat, 0, &dump_datamap)) {
printf("bus_dmamap_create failed\n");
return (ENOMEM);
}
}
retry:
/*
* Queue the block to the controller. If the queue is full,
* EBUSY will be returned.
*/
error = aac_dump_enqueue(ad, blkno, va, dumppages);
if (error && (error != EBUSY))
return (error);
aac_get_sync_fib(sc, &fib, AAC_SYNC_LOCK_FORCE);
bw = (struct aac_blockwrite *)&fib->data[0];
if (!error) {
if (dumpstatus(addr, (off_t)(count * DEV_BSIZE)) < 0)
return (EINTR);
while (length > 0) {
len = (length > AAC_MAXIO) ? AAC_MAXIO : length;
bw->Command = VM_CtBlockWrite;
bw->ContainerId = ad->ad_container->co_mntobj.ObjectId;
bw->BlockNumber = offset / AAC_BLOCK_SIZE;
bw->ByteCount = len;
bw->Stable = CUNSTABLE;
bus_dmamap_load(sc->aac_buffer_dmat, dump_datamap, virtual,
len, aac_dump_map_sg, fib, 0);
bus_dmamap_sync(sc->aac_buffer_dmat, dump_datamap,
BUS_DMASYNC_PREWRITE);
blkno += blkcnt * dumppages;
count -= blkcnt * dumppages;
addr += PAGE_SIZE * dumppages;
if (count > 0)
continue;
/* fib->Header.Size is set in aac_dump_map_sg */
size = fib->Header.Size + sizeof(struct aac_blockwrite);
if (aac_sync_fib(sc, ContainerCommand, 0, fib, size)) {
printf("Error dumping block 0x%x\n", physical);
return (EIO);
}
/*
* Either the queue was full on the last attemp, or we have no
* more data to dump. Let the queue drain out and retry the
* block if the queue was full.
*/
aac_dump_complete(sc);
if (error == EBUSY)
goto retry;
length -= len;
offset += len;
}
return (0);
#endif
}
/*

View File

@ -224,7 +224,7 @@ aac_pci_attach(device_t dev)
* Note that some of these controllers are 64-bit capable.
*/
if (bus_dma_tag_create(NULL, /* parent */
1, 0, /* algnmnt, boundary */
PAGE_SIZE, 0, /* algnmnt, boundary */
BUS_SPACE_MAXADDR_32BIT, /* lowaddr */
BUS_SPACE_MAXADDR, /* highaddr */
NULL, NULL, /* filter, filterarg */

View File

@ -986,7 +986,7 @@ struct aac_mntinfo {
u_int32_t MntCount;
} __attribute__ ((packed));
struct aac_mntinforesponse {
struct aac_mntinforesp {
AAC_FSAStatus Status;
AAC_FType MntType;
u_int32_t MntRespCount;

View File

@ -336,6 +336,10 @@ struct aac_softc
struct aac_container_tq aac_container_tqh;
aac_lock_t aac_container_lock;
/* Protect the sync fib */
#define AAC_SYNC_LOCK_FORCE (1 << 0)
aac_lock_t aac_sync_lock;
/* delayed activity infrastructure */
#if __FreeBSD_version >= 500005
struct task aac_task_complete; /* deferred-completion
@ -373,9 +377,12 @@ extern int aac_resume(device_t dev);
extern void aac_intr(void *arg);
extern void aac_submit_bio(struct bio *bp);
extern void aac_biodone(struct bio *bp);
extern int aac_dump_enqueue(struct aac_disk *ad, u_int32_t lba,
void *data, int nblks);
extern void aac_dump_complete(struct aac_softc *sc);
extern int aac_get_sync_fib(struct aac_softc *sc,
struct aac_fib **fib, int flags);
extern void aac_release_sync_fib(struct aac_softc *sc);
extern int aac_sync_fib(struct aac_softc *sc, u_int32_t command,
u_int32_t xferstate, struct aac_fib *fib,
u_int16_t datasize);
/*
* Debugging levels:
@ -400,7 +407,7 @@ extern void aac_print_fib(struct aac_softc *sc, struct aac_fib *fib,
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, __func__)
#define AAC_PRINT_FIB(sc, fib) aac_print_fib(sc, fib, __func__)
#else
# define debug(level, fmt, args...)