summaryrefslogtreecommitdiff
path: root/sys
diff options
context:
space:
mode:
Diffstat (limited to 'sys')
-rw-r--r--sys/dev/ic/aac.c3646
-rw-r--r--sys/dev/ic/aac_tables.h4
-rw-r--r--sys/dev/ic/aacreg.h1426
-rw-r--r--sys/dev/ic/aacvar.h448
-rw-r--r--sys/dev/pci/aac_pci.c39
5 files changed, 3814 insertions, 1749 deletions
diff --git a/sys/dev/ic/aac.c b/sys/dev/ic/aac.c
index 3373f80911e..2ba71c4b898 100644
--- a/sys/dev/ic/aac.c
+++ b/sys/dev/ic/aac.c
@@ -1,9 +1,12 @@
-/* $OpenBSD: aac.c,v 1.24 2005/09/15 05:33:39 krw Exp $ */
+/* $OpenBSD: aac.c,v 1.25 2005/11/18 05:39:10 nate Exp $ */
/*-
* Copyright (c) 2000 Michael Smith
+ * Copyright (c) 2001 Scott Long
* Copyright (c) 2000 BSDi
+ * Copyright (c) 2001 Adaptec, Inc.
* Copyright (c) 2000 Niklas Hallqvist
+ * Copyright (c) 2004 Nathan Binkert
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -47,7 +50,9 @@
#include <sys/buf.h>
#include <sys/device.h>
#include <sys/kernel.h>
+#include <sys/kthread.h>
#include <sys/malloc.h>
+#include <sys/rwlock.h>
#include <machine/bus.h>
@@ -71,43 +76,51 @@
#define AAC_BIGSECS 63 /* mapping 255*63 */
#define AAC_SECS32 0x1f /* round capacity */
-void aac_bio_complete(struct aac_ccb *);
-void aac_complete(void *, int);
+struct scsi_xfer;
+
void aac_copy_internal_data(struct scsi_xfer *, u_int8_t *, size_t);
-struct scsi_xfer *aac_dequeue(struct aac_softc *);
-int aac_dequeue_fib(struct aac_softc *, int, u_int32_t *,
- struct aac_fib **);
char *aac_describe_code(struct aac_code_lookup *, u_int32_t);
void aac_describe_controller(struct aac_softc *);
void aac_enqueue(struct aac_softc *, struct scsi_xfer *, int);
-void aac_enqueue_ccb(struct aac_softc *, struct aac_ccb *);
-int aac_enqueue_fib(struct aac_softc *, int, struct aac_ccb *);
+int aac_enqueue_fib(struct aac_softc *, int, struct aac_command *);
+int aac_dequeue_fib(struct aac_softc *, int, u_int32_t *,
+ struct aac_fib **);
+int aac_enqueue_response(struct aac_softc *sc, int queue,
+ struct aac_fib *fib);
+
void aac_eval_mapping(u_int32_t, int *, int *, int *);
-int aac_exec_ccb(struct aac_ccb *);
-void aac_free_ccb(struct aac_softc *, struct aac_ccb *);
-struct aac_ccb *aac_get_ccb(struct aac_softc *, int);
-#if 0
-void aac_handle_aif(struct aac_softc *, struct aac_aif_command *);
-#endif
+void aac_print_printf(struct aac_softc *);
void aac_host_command(struct aac_softc *);
void aac_host_response(struct aac_softc *);
int aac_init(struct aac_softc *);
+int aac_check_firmware(struct aac_softc *);
int aac_internal_cache_cmd(struct scsi_xfer *);
-int aac_map_command(struct aac_ccb *);
-#ifdef AAC_DEBUG
-void aac_print_fib(struct aac_softc *, struct aac_fib *, const char *);
-#endif
+
+/* Command Processing */
+void aac_timeout(struct aac_softc *);
+void aac_command_timeout(struct aac_command *);
+int aac_map_command(struct aac_command *);
+void aac_complete(void *);
+int aac_bio_command(struct aac_softc *, struct aac_command **);
+void aac_bio_complete(struct aac_command *);
+int aac_wait_command(struct aac_command *, int);
+void aac_create_thread(void *);
+void aac_command_thread(void *);
+
+/* Command Buffer Management */
+void aac_map_command_sg(void *, bus_dma_segment_t *, int, int);
+int aac_alloc_commands(struct aac_softc *);
+void aac_free_commands(struct aac_softc *);
+void aac_unmap_command(struct aac_command *);
+
int aac_raw_scsi_cmd(struct scsi_xfer *);
int aac_scsi_cmd(struct scsi_xfer *);
-int aac_start(struct aac_ccb *);
-void aac_start_ccbs(struct aac_softc *);
+void aac_startio(struct aac_softc *);
void aac_startup(struct aac_softc *);
+void aac_add_container(struct aac_softc *, struct aac_mntinforesp *, int);
+void aac_shutdown(void *);
int aac_sync_command(struct aac_softc *, u_int32_t, u_int32_t,
u_int32_t, u_int32_t, u_int32_t, u_int32_t *);
-int aac_sync_fib(struct aac_softc *, u_int32_t, u_int32_t, void *,
- u_int16_t, void *, u_int16_t *);
-void aac_timeout(void *);
-void aac_unmap_command(struct aac_ccb *);
void aac_watchdog(void *);
struct cfdriver aac_cd = {
@@ -126,15 +139,25 @@ struct scsi_device aac_dev = {
NULL, NULL, NULL, NULL
};
-/* i960Rx interface */
-int aac_rx_get_fwstatus(struct aac_softc *);
-void aac_rx_qnotify(struct aac_softc *, int);
-int aac_rx_get_istatus(struct aac_softc *);
-void aac_rx_clear_istatus(struct aac_softc *, int);
-void aac_rx_set_mailbox(struct aac_softc *, u_int32_t, u_int32_t,
- u_int32_t, u_int32_t, u_int32_t);
-int aac_rx_get_mailboxstatus(struct aac_softc *);
-void aac_rx_set_interrupts(struct aac_softc *, int);
+/* Falcon/PPC interface */
+int aac_fa_get_fwstatus(struct aac_softc *);
+void aac_fa_qnotify(struct aac_softc *, int);
+int aac_fa_get_istatus(struct aac_softc *);
+void aac_fa_clear_istatus(struct aac_softc *, int);
+void aac_fa_set_mailbox(struct aac_softc *, u_int32_t, u_int32_t, u_int32_t,
+ u_int32_t, u_int32_t);
+int aac_fa_get_mailbox(struct aac_softc *, int);
+void aac_fa_set_interrupts(struct aac_softc *, int);
+
+struct aac_interface aac_fa_interface = {
+ aac_fa_get_fwstatus,
+ aac_fa_qnotify,
+ aac_fa_get_istatus,
+ aac_fa_clear_istatus,
+ aac_fa_set_mailbox,
+ aac_fa_get_mailbox,
+ aac_fa_set_interrupts
+};
/* StrongARM interface */
int aac_sa_get_fwstatus(struct aac_softc *);
@@ -143,914 +166,921 @@ int aac_sa_get_istatus(struct aac_softc *);
void aac_sa_clear_istatus(struct aac_softc *, int);
void aac_sa_set_mailbox(struct aac_softc *, u_int32_t, u_int32_t,
u_int32_t, u_int32_t, u_int32_t);
-int aac_sa_get_mailboxstatus(struct aac_softc *);
+int aac_sa_get_mailbox(struct aac_softc *, int);
void aac_sa_set_interrupts(struct aac_softc *, int);
-struct aac_interface aac_rx_interface = {
- aac_rx_get_fwstatus,
- aac_rx_qnotify,
- aac_rx_get_istatus,
- aac_rx_clear_istatus,
- aac_rx_set_mailbox,
- aac_rx_get_mailboxstatus,
- aac_rx_set_interrupts
-};
-
struct aac_interface aac_sa_interface = {
aac_sa_get_fwstatus,
aac_sa_qnotify,
aac_sa_get_istatus,
aac_sa_clear_istatus,
aac_sa_set_mailbox,
- aac_sa_get_mailboxstatus,
+ aac_sa_get_mailbox,
aac_sa_set_interrupts
};
+/* i960Rx interface */
+int aac_rx_get_fwstatus(struct aac_softc *);
+void aac_rx_qnotify(struct aac_softc *, int);
+int aac_rx_get_istatus(struct aac_softc *);
+void aac_rx_clear_istatus(struct aac_softc *, int);
+void aac_rx_set_mailbox(struct aac_softc *, u_int32_t, u_int32_t,
+ u_int32_t, u_int32_t, u_int32_t);
+int aac_rx_get_mailbox(struct aac_softc *, int);
+void aac_rx_set_interrupts(struct aac_softc *, int);
+
+struct aac_interface aac_rx_interface = {
+ aac_rx_get_fwstatus,
+ aac_rx_qnotify,
+ aac_rx_get_istatus,
+ aac_rx_clear_istatus,
+ aac_rx_set_mailbox,
+ aac_rx_get_mailbox,
+ aac_rx_set_interrupts
+};
+
#ifdef AAC_DEBUG
int aac_debug = AAC_DEBUG;
#endif
int
-aac_attach(sc)
- struct aac_softc *sc;
+aac_attach(struct aac_softc *sc)
{
- int i, error;
- bus_dma_segment_t seg;
- int nsegs;
- struct aac_ccb *ccb;
+ int error;
- TAILQ_INIT(&sc->sc_free_ccb);
- TAILQ_INIT(&sc->sc_ccbq);
- TAILQ_INIT(&sc->sc_completed);
- LIST_INIT(&sc->sc_queue);
+ /*
+ * Initialise per-controller queues.
+ */
+ aac_initq_free(sc);
+ aac_initq_ready(sc);
+ aac_initq_busy(sc);
+ aac_initq_bio(sc);
/* disable interrupts before we enable anything */
AAC_MASK_INTERRUPTS(sc);
/* mark controller as suspended until we get ourselves organised */
- sc->sc_state |= AAC_STATE_SUSPEND;
+ sc->aac_state |= AAC_STATE_SUSPEND;
/*
- * Initialise the adapter.
+ * Check that the firmware on the card is supported.
*/
- error = aac_init(sc);
+ error = aac_check_firmware(sc);
if (error)
return (error);
- /*
- * Print a little information about the controller.
+ /*
+ * Initialize locks
*/
- aac_describe_controller(sc);
+ AAC_LOCK_INIT(&sc->aac_sync_lock, "AAC sync FIB lock");
+ AAC_LOCK_INIT(&sc->aac_aifq_lock, "AAC AIF lock");
+ AAC_LOCK_INIT(&sc->aac_io_lock, "AAC I/O lock");
+ AAC_LOCK_INIT(&sc->aac_container_lock, "AAC container lock");
+ TAILQ_INIT(&sc->aac_container_tqh);
- /* Initialize the ccbs */
- for (i = 0; i < AAC_ADAP_NORM_CMD_ENTRIES; i++) {
- ccb = &sc->sc_ccbs[i];
- error = bus_dmamap_create(sc->sc_dmat,
- (AAC_MAXSGENTRIES - 1) << PGSHIFT, AAC_MAXSGENTRIES,
- (AAC_MAXSGENTRIES - 1) << PGSHIFT, 0,
- BUS_DMA_NOWAIT | BUS_DMA_ALLOCNOW, &ccb->ac_dmamap_xfer);
- if (error) {
- printf("%s: cannot create ccb dmamap (%d)",
- sc->sc_dev.dv_xname, error);
- /* XXX cleanup */
- return (1);
- }
-
- /* allocate the FIB cluster in DMAable memory and load it */
- if (bus_dmamem_alloc(sc->sc_dmat, sizeof *ccb->ac_fib, 1, 0,
- &seg, 1, &nsegs, BUS_DMA_NOWAIT)) {
- printf("%s: can't allocate FIB structure\n",
- sc->sc_dev.dv_xname);
- /* XXX cleanup */
- return (1);
- }
- ccb->ac_fibphys = seg.ds_addr;
- if (bus_dmamem_map(sc->sc_dmat, &seg, nsegs,
- sizeof *ccb->ac_fib, (caddr_t *)&ccb->ac_fib, 0)) {
- printf("%s: can't map FIB structure\n",
- sc->sc_dev.dv_xname);
- /* XXX cleanup */
- return (1);
- }
-
- TAILQ_INSERT_TAIL(&sc->sc_free_ccb, &sc->sc_ccbs[i],
- ac_chain);
- }
+ /* Initialize the local AIF queue pointers */
+ sc->aac_aifq_head = sc->aac_aifq_tail = AAC_AIFQ_LENGTH;
- /* Fill in the prototype scsi_link. */
- sc->sc_link.adapter_softc = sc;
- sc->sc_link.adapter = &aac_switch;
- sc->sc_link.device = &aac_dev;
/*
- * XXX Theoretically this should be AAC_ADAP_NORM_CMD_ENTRIES but
- * XXX in some configurations this can cause "not queued" errors.
- * XXX A quarter of that number has been reported to be safe.
+ * Initialise the adapter.
*/
- sc->sc_link.openings = AAC_ADAP_NORM_CMD_ENTRIES / 4;
- sc->sc_link.adapter_buswidth = AAC_MAX_CONTAINERS;
- sc->sc_link.adapter_target = AAC_MAX_CONTAINERS;
-
- config_found(&sc->sc_dev, &sc->sc_link, scsiprint);
-
- return (0);
-}
-
-/*
- * Look up a text description of a numeric error code and return a pointer to
- * same.
- */
-char *
-aac_describe_code(table, code)
- struct aac_code_lookup *table;
- u_int32_t code;
-{
- int i;
+ error = aac_init(sc);
+ if (error)
+ return (error);
- for (i = 0; table[i].string != NULL; i++)
- if (table[i].code == code)
- return (table[i].string);
- return (table[i + 1].string);
-}
+ /* Fill in the prototype scsi_link. */
+ sc->aac_link.adapter_softc = sc;
+ sc->aac_link.adapter = &aac_switch;
+ sc->aac_link.device = &aac_dev;
+ sc->aac_link.openings = (sc->total_fibs - 8) /
+ (sc->aac_container_count ? sc->aac_container_count : 1);
+ sc->aac_link.adapter_buswidth = AAC_MAX_CONTAINERS;
+ sc->aac_link.adapter_target = AAC_MAX_CONTAINERS;
-void
-aac_describe_controller(sc)
- struct aac_softc *sc;
-{
- u_int8_t buf[AAC_FIB_DATASIZE]; /* XXX a bit big for the stack */
- u_int16_t bufsize;
- struct aac_adapter_info *info;
- u_int8_t arg;
+ config_found(&sc->aac_dev, &sc->aac_link, scsiprint);
- arg = 0;
- if (aac_sync_fib(sc, RequestAdapterInfo, 0, &arg, sizeof arg, &buf,
- &bufsize)) {
- printf("%s: RequestAdapterInfo failed\n", sc->sc_dev.dv_xname);
- return;
- }
- if (bufsize != sizeof *info) {
- printf("%s: "
- "RequestAdapterInfo returned wrong data size (%d != %d)\n",
- sc->sc_dev.dv_xname, bufsize, sizeof *info);
- return;
- }
- info = (struct aac_adapter_info *)&buf[0];
+ /* Create the AIF thread */
+ sc->aifthread = 0;
+ sc->aifflags = 0;
+ kthread_create_deferred(aac_create_thread, sc);
- printf("%s: %s %dMHz, %dMB, %s (%d) Kernel %d.%d-%d\n",
- sc->sc_dev.dv_xname,
- aac_describe_code(aac_cpu_variant, info->CpuVariant),
- info->ClockSpeed, info->TotalMem / (1024 * 1024),
- aac_describe_code(aac_battery_platform, info->batteryPlatform),
- info->batteryPlatform, info->KernelRevision.external.comp.major,
- info->KernelRevision.external.comp.minor,
- info->KernelRevision.external.comp.dash);
+#if 0
+ /* Register the shutdown method to only be called post-dump */
+ sc->aac_sdh = shutdownhook_establish(aac_shutdown, (void *)sc);
+#endif
- /* save the kernel revision structure for later use */
- sc->sc_revision = info->KernelRevision;
+ return (0);
}
-int
-aac_init(sc)
- struct aac_softc *sc;
+void
+aac_create_thread(void *arg)
{
- bus_dma_segment_t seg;
- int nsegs;
- int i, error;
- int state = 0;
- struct aac_adapter_init *ip;
- u_int32_t code;
- u_int8_t *qaddr;
-
- /*
- * First wait for the adapter to come ready.
- */
- for (i = 0; i < AAC_BOOT_TIMEOUT * 1000; i++) {
- code = AAC_GET_FWSTATUS(sc);
- if (code & AAC_SELF_TEST_FAILED) {
- printf("%s: FATAL: selftest failed\n",
- sc->sc_dev.dv_xname);
- return (ENXIO);
- }
- if (code & AAC_KERNEL_PANIC) {
- printf("%s: FATAL: controller kernel panic\n",
- sc->sc_dev.dv_xname);
- return (ENXIO);
- }
- if (code & AAC_UP_AND_RUNNING)
- break;
- DELAY(1000);
- }
- if (i == AAC_BOOT_TIMEOUT * 1000) {
- printf("%s: FATAL: controller not coming ready, status %x\n",
- sc->sc_dev.dv_xname, code);
- return (ENXIO);
- }
-
- if (bus_dmamem_alloc(sc->sc_dmat, sizeof *sc->sc_common, 1, 0, &seg, 1,
- &nsegs, BUS_DMA_NOWAIT)) {
- printf("%s: can't allocate common structure\n",
- sc->sc_dev.dv_xname);
- return (ENOMEM);
- }
- state++;
- sc->sc_common_busaddr = seg.ds_addr;
- if (bus_dmamem_map(sc->sc_dmat, &seg, nsegs, sizeof *sc->sc_common,
- (caddr_t *)&sc->sc_common, 0)) {
- printf("%s: can't map common structure\n",
- sc->sc_dev.dv_xname);
- error = ENOMEM;
- goto bail_out;
- }
- state++;
- bzero(sc->sc_common, sizeof *sc->sc_common);
-
- /*
- * Fill in the init structure. This tells the adapter about
- * the physical location * of various important shared data
- * structures.
- */
- ip = &sc->sc_common->ac_init;
- ip->InitStructRevision = AAC_INIT_STRUCT_REVISION;
-
- ip->AdapterFibsPhysicalAddress =
- sc->sc_common_busaddr + offsetof(struct aac_common, ac_fibs);
- ip->AdapterFibsVirtualAddress = &sc->sc_common->ac_fibs[0];
- ip->AdapterFibsSize = AAC_ADAPTER_FIBS * sizeof(struct aac_fib);
- ip->AdapterFibAlign = sizeof(struct aac_fib);
-
- ip->PrintfBufferAddress =
- sc->sc_common_busaddr + offsetof(struct aac_common, ac_printf);
- ip->PrintfBufferSize = AAC_PRINTF_BUFSIZE;
-
- ip->HostPhysMemPages = 0; /* not used? */
- ip->HostElapsedSeconds = 0; /* reset later if invalid */
-
- /*
- * 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 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.
- *
- * 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 functions which
- * 'know' the size of each list by virtue of a table.
- */
- qaddr = &sc->sc_common->ac_qbuf[0] + AAC_QUEUE_ALIGN;
- qaddr -= (u_int32_t)qaddr % AAC_QUEUE_ALIGN; /* XXX not portable */
- sc->sc_queues = (struct aac_queue_table *)qaddr;
- ip->CommHeaderAddress = sc->sc_common_busaddr +
- ((char *)sc->sc_queues - (char *)sc->sc_common);
- bzero(sc->sc_queues, sizeof(struct aac_queue_table));
-
- sc->sc_queues->qt_qindex[AAC_HOST_NORM_CMD_QUEUE][AAC_PRODUCER_INDEX] =
- AAC_HOST_NORM_CMD_ENTRIES;
- sc->sc_queues->qt_qindex[AAC_HOST_NORM_CMD_QUEUE][AAC_CONSUMER_INDEX] =
- AAC_HOST_NORM_CMD_ENTRIES;
- sc->sc_queues->qt_qindex[AAC_HOST_HIGH_CMD_QUEUE][AAC_PRODUCER_INDEX] =
- AAC_HOST_HIGH_CMD_ENTRIES;
- sc->sc_queues->qt_qindex[AAC_HOST_HIGH_CMD_QUEUE][AAC_CONSUMER_INDEX] =
- AAC_HOST_HIGH_CMD_ENTRIES;
- sc->sc_queues->qt_qindex[AAC_ADAP_NORM_CMD_QUEUE][AAC_PRODUCER_INDEX] =
- AAC_ADAP_NORM_CMD_ENTRIES;
- sc->sc_queues->qt_qindex[AAC_ADAP_NORM_CMD_QUEUE][AAC_CONSUMER_INDEX] =
- AAC_ADAP_NORM_CMD_ENTRIES;
- sc->sc_queues->qt_qindex[AAC_ADAP_HIGH_CMD_QUEUE][AAC_PRODUCER_INDEX] =
- AAC_ADAP_HIGH_CMD_ENTRIES;
- sc->sc_queues->qt_qindex[AAC_ADAP_HIGH_CMD_QUEUE][AAC_CONSUMER_INDEX] =
- AAC_ADAP_HIGH_CMD_ENTRIES;
- sc->sc_queues->
- qt_qindex[AAC_HOST_NORM_RESP_QUEUE][AAC_PRODUCER_INDEX] =
- AAC_HOST_NORM_RESP_ENTRIES;
- sc->sc_queues->
- qt_qindex[AAC_HOST_NORM_RESP_QUEUE][AAC_CONSUMER_INDEX] =
- AAC_HOST_NORM_RESP_ENTRIES;
- sc->sc_queues->
- qt_qindex[AAC_HOST_HIGH_RESP_QUEUE][AAC_PRODUCER_INDEX] =
- AAC_HOST_HIGH_RESP_ENTRIES;
- sc->sc_queues->
- qt_qindex[AAC_HOST_HIGH_RESP_QUEUE][AAC_CONSUMER_INDEX] =
- AAC_HOST_HIGH_RESP_ENTRIES;
- sc->sc_queues->
- qt_qindex[AAC_ADAP_NORM_RESP_QUEUE][AAC_PRODUCER_INDEX] =
- AAC_ADAP_NORM_RESP_ENTRIES;
- sc->sc_queues->
- qt_qindex[AAC_ADAP_NORM_RESP_QUEUE][AAC_CONSUMER_INDEX] =
- AAC_ADAP_NORM_RESP_ENTRIES;
- sc->sc_queues->
- qt_qindex[AAC_ADAP_HIGH_RESP_QUEUE][AAC_PRODUCER_INDEX] =
- AAC_ADAP_HIGH_RESP_ENTRIES;
- sc->sc_queues->
- qt_qindex[AAC_ADAP_HIGH_RESP_QUEUE][AAC_CONSUMER_INDEX] =
- AAC_ADAP_HIGH_RESP_ENTRIES;
- sc->sc_qentries[AAC_HOST_NORM_CMD_QUEUE] =
- &sc->sc_queues->qt_HostNormCmdQueue[0];
- sc->sc_qentries[AAC_HOST_HIGH_CMD_QUEUE] =
- &sc->sc_queues->qt_HostHighCmdQueue[0];
- sc->sc_qentries[AAC_ADAP_NORM_CMD_QUEUE] =
- &sc->sc_queues->qt_AdapNormCmdQueue[0];
- sc->sc_qentries[AAC_ADAP_HIGH_CMD_QUEUE] =
- &sc->sc_queues->qt_AdapHighCmdQueue[0];
- sc->sc_qentries[AAC_HOST_NORM_RESP_QUEUE] =
- &sc->sc_queues->qt_HostNormRespQueue[0];
- sc->sc_qentries[AAC_HOST_HIGH_RESP_QUEUE] =
- &sc->sc_queues->qt_HostHighRespQueue[0];
- sc->sc_qentries[AAC_ADAP_NORM_RESP_QUEUE] =
- &sc->sc_queues->qt_AdapNormRespQueue[0];
- sc->sc_qentries[AAC_ADAP_HIGH_RESP_QUEUE] =
- &sc->sc_queues->qt_AdapHighRespQueue[0];
+ struct aac_softc *sc = arg;
- /*
- * Do controller-type-specific initialisation
- */
- switch (sc->sc_hwif) {
- case AAC_HWIF_I960RX:
- AAC_SETREG4(sc, AAC_RX_ODBR, ~0);
- break;
+ if (kthread_create(aac_command_thread, sc, &sc->aifthread, "%s",
+ sc->aac_dev.dv_xname)) {
+ /* TODO disable aac */
+ printf("%s: failed to create kernel thread, disabled",
+ sc->aac_dev.dv_xname);
}
+ AAC_DPRINTF(AAC_D_MISC, ("%s: aac_create_thread\n",
+ sc->aac_dev.dv_xname));
- /*
- * Give the init structure to the controller.
- */
- if (aac_sync_command(sc, AAC_MONKER_INITSTRUCT,
- sc->sc_common_busaddr + offsetof(struct aac_common, ac_init), 0, 0,
- 0, NULL)) {
- printf("%s: error establishing init structure\n",
- sc->sc_dev.dv_xname);
- error = EIO;
- goto bail_out;
- }
-
- aac_startup(sc);
-
- return (0);
-
- bail_out:
- if (state > 1)
- bus_dmamem_unmap(sc->sc_dmat, (caddr_t)sc->sc_common,
- sizeof *sc->sc_common);
- if (state > 0)
- bus_dmamem_free(sc->sc_dmat, &seg, 1);
- return (error);
}
/*
* Probe for containers, create disks.
*/
void
-aac_startup (sc)
- struct aac_softc *sc;
+aac_startup(struct aac_softc *sc)
{
- struct aac_mntinfo mi;
- struct aac_mntinforesponse mir;
- u_int16_t rsize;
- int i, drv_cyls, drv_hds, drv_secs;
+ struct aac_fib *fib;
+ struct aac_mntinfo *mi;
+ struct aac_mntinforesp *mir = NULL;
+ int count = 0, i = 0;
+
+ aac_alloc_sync_fib(sc, &fib, 0);
+ mi = (struct aac_mntinfo *)&fib->data[0];
+
+ AAC_DPRINTF(AAC_D_MISC, ("%s: aac startup\n", sc->aac_dev.dv_xname));
+
+ sc->aac_container_count = 0;
/* loop over possible containers */
- mi.Command = VM_NameServe;
- mi.MntType = FT_FILESYS;
- for (i = 0; i < AAC_MAX_CONTAINERS; i++) {
+ do {
/* request information on this container */
- mi.MntCount = i;
- if (aac_sync_fib(sc, ContainerCommand, 0, &mi, sizeof mi, &mir,
- &rsize)) {
- printf("%s: error probing container %d",
- sc->sc_dev.dv_xname, i);
- continue;
- }
- /* check response size */
- if (rsize != sizeof mir) {
- printf("%s: container info response wrong size "
- "(%d should be %d)",
- sc->sc_dev.dv_xname, rsize, sizeof mir);
+ bzero(mi, sizeof(struct aac_mntinfo));
+ mi->Command = VM_NameServe;
+ mi->MntType = FT_FILESYS;
+ mi->MntCount = i;
+ if (aac_sync_fib(sc, ContainerCommand, 0, fib,
+ sizeof(struct aac_mntinfo))) {
+ printf("%s: error probing container %d\n",
+ sc->aac_dev.dv_xname, i);
continue;
}
+ mir = (struct aac_mntinforesp *)&fib->data[0];
+ /* XXX Need to check if count changed */
+ count = mir->MntRespCount;
+
+#if 0
+ aac_add_container(sc, mir, 0);
+#else
/*
* Check container volume type for validity. Note
- * that many of the possible types * may never show
- * up.
+ * that many of the possible types may never show up.
*/
- if (mir.Status == ST_OK &&
- mir.MntTable[0].VolType != CT_NONE) {
+ if (mir->Status == ST_OK &&
+ mir->MntTable[0].VolType != CT_NONE) {
+ int drv_cyls, drv_hds, drv_secs;
+
AAC_DPRINTF(AAC_D_MISC,
- ("%d: id %x name '%.16s' size %u type %d", i,
- mir.MntTable[0].ObjectId,
- mir.MntTable[0].FileSystemName,
- mir.MntTable[0].Capacity,
- mir.MntTable[0].VolType));
+ ("%s: %d: id %x name '%.16s' size %u type %d\n",
+ sc->aac_dev.dv_xname, i,
+ mir->MntTable[0].ObjectId,
+ mir->MntTable[0].FileSystemName,
+ mir->MntTable[0].Capacity,
+ mir->MntTable[0].VolType));
- sc->sc_hdr[i].hd_present = 1;
- sc->sc_hdr[i].hd_size = mir.MntTable[0].Capacity;
+ sc->aac_container_count++;
+ sc->aac_hdr[i].hd_present = 1;
+ sc->aac_hdr[i].hd_size = mir->MntTable[0].Capacity;
/*
* Evaluate mapping (sectors per head, heads per cyl)
*/
- sc->sc_hdr[i].hd_size &= ~AAC_SECS32;
- aac_eval_mapping(sc->sc_hdr[i].hd_size, &drv_cyls,
- &drv_hds, &drv_secs);
- sc->sc_hdr[i].hd_heads = drv_hds;
- sc->sc_hdr[i].hd_secs = drv_secs;
+ sc->aac_hdr[i].hd_size &= ~AAC_SECS32;
+ aac_eval_mapping(sc->aac_hdr[i].hd_size, &drv_cyls,
+ &drv_hds, &drv_secs);
+ sc->aac_hdr[i].hd_heads = drv_hds;
+ sc->aac_hdr[i].hd_secs = drv_secs;
/* Round the size */
- sc->sc_hdr[i].hd_size = drv_cyls * drv_hds * drv_secs;
+ sc->aac_hdr[i].hd_size = drv_cyls * drv_hds * drv_secs;
- sc->sc_hdr[i].hd_devtype = mir.MntTable[0].VolType;
+ sc->aac_hdr[i].hd_devtype = mir->MntTable[0].VolType;
/* XXX Save the name too for use in IDENTIFY later */
}
- }
+#endif
+
+ i++;
+ } while ((i < count) && (i < AAC_MAX_CONTAINERS));
+
+ aac_release_sync_fib(sc);
+
+#if 0
+ /* poke the bus to actually attach the child devices */
+ if (bus_generic_attach(sc->aac_dev))
+ printf("%s: bus_generic_attach failed\n",
+ sc->aac_dev.dv_xname);
+#endif
+
/* mark the controller up */
- sc->sc_state &= ~AAC_STATE_SUSPEND;
+ sc->aac_state &= ~AAC_STATE_SUSPEND;
/* enable interrupts now */
AAC_UNMASK_INTERRUPTS(sc);
}
+#if 0
+/*
+ * Create a device to respresent a new container
+ */
void
-aac_eval_mapping(size, cyls, heads, secs)
- u_int32_t size;
- int *cyls, *heads, *secs;
+aac_add_container(struct aac_softc *sc, struct aac_mntinforesp *mir, int f)
{
- *cyls = size / AAC_HEADS / AAC_SECS;
- if (*cyls < AAC_MAXCYLS) {
- *heads = AAC_HEADS;
- *secs = AAC_SECS;
- } else {
- /* Too high for 64 * 32 */
- *cyls = size / AAC_MEDHEADS / AAC_MEDSECS;
- if (*cyls < AAC_MAXCYLS) {
- *heads = AAC_MEDHEADS;
- *secs = AAC_MEDSECS;
- } else {
- /* Too high for 127 * 63 */
- *cyls = size / AAC_BIGHEADS / AAC_BIGSECS;
- *heads = AAC_BIGHEADS;
- *secs = AAC_BIGSECS;
- }
+ struct aac_container *co;
+ device_t child;
+
+ /*
+ * Check container volume type for validity. Note that many of
+ * the possible types may never show up.
+ */
+ if ((mir->Status == ST_OK) && (mir->MntTable[0].VolType != CT_NONE)) {
+ co = (struct aac_container *)malloc(sizeof *co, M_DEVBUF,
+ M_NOWAIT);
+ if (co == NULL)
+ panic("Out of memory?!\n");
+ bzero(co, sizeof *co);
+ AAC_DPRINTF(AAC_D_MISC,
+ ("%s: id %x name '%.16s' size %u type %d\n",
+ sc->aac_dev.dv_xname,
+ mir->MntTable[0].ObjectId,
+ mir->MntTable[0].FileSystemName,
+ mir->MntTable[0].Capacity,
+ mir->MntTable[0].VolType);
+
+ if ((child = device_add_child(sc->aac_dev, "aacd", -1)) == NULL)
+ printf("%s: device_add_child failed\n",
+ sc->aac_dev.dv_xname);
+ else
+ device_set_ivars(child, co);
+ device_set_desc(child, aac_describe_code(aac_container_types,
+ mir->MntTable[0].VolType));
+ co->co_disk = child;
+ co->co_found = f;
+ bcopy(&mir->MntTable[0], &co->co_mntobj,
+ sizeof(struct aac_mntobj));
+ AAC_LOCK_ACQUIRE(&sc->aac_container_lock);
+ TAILQ_INSERT_TAIL(&sc->aac_container_tqh, co, co_link);
+ AAC_LOCK_RELEASE(&sc->aac_container_lock);
}
}
+#endif
-int
-aac_raw_scsi_cmd(xs)
- struct scsi_xfer *xs;
+#if 0
+/*
+ * Free all of the resources associated with (sc)
+ *
+ * Should not be called if the controller is active.
+ */
+void
+aac_free(struct aac_softc *sc)
{
- AAC_DPRINTF(AAC_D_CMD, ("aac_raw_scsi_cmd "));
- /* XXX Not yet implemented */
- xs->error = XS_DRIVER_STUFFUP;
- return (COMPLETE);
+ debug_called(1);
+
+ /* remove the control device */
+ if (sc->aac_dev_t != NULL)
+ destroy_dev(sc->aac_dev_t);
+
+ /* throw away any FIB buffers, discard the FIB DMA tag */
+ aac_free_commands(sc);
+ if (sc->aac_fib_dmat)
+ bus_dma_tag_destroy(sc->aac_fib_dmat);
+
+ free(sc->aac_commands, M_AACBUF);
+
+ /* 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);
+ }
+ if (sc->aac_common_dmat)
+ bus_dma_tag_destroy(sc->aac_common_dmat);
+
+ /* disconnect the interrupt handler */
+ if (sc->aac_intr)
+ bus_teardown_intr(sc->aac_dev, sc->aac_irq, sc->aac_intr);
+ if (sc->aac_irq != NULL)
+ bus_release_resource(sc->aac_dev, SYS_RES_IRQ, sc->aac_irq_rid,
+ sc->aac_irq);
+
+ /* destroy data-transfer DMA tag */
+ if (sc->aac_buffer_dmat)
+ bus_dma_tag_destroy(sc->aac_buffer_dmat);
+
+ /* destroy the parent DMA tag */
+ if (sc->aac_parent_dmat)
+ bus_dma_tag_destroy(sc->aac_parent_dmat);
+
+ /* release the register window mapping */
+ if (sc->aac_regs_resource != NULL)
+ bus_release_resource(sc->aac_dev, SYS_RES_MEMORY,
+ sc->aac_regs_rid, sc->aac_regs_resource);
}
+/*
+ * Disconnect from the controller completely, in preparation for unload.
+ */
int
-aac_scsi_cmd(xs)
- struct scsi_xfer *xs;
+aac_detach(device_t dev)
{
- struct scsi_link *link = xs->sc_link;
- struct aac_softc *sc = link->adapter_softc;
- u_int8_t target = link->target;
- struct aac_ccb *ccb;
- u_int32_t blockno, blockcnt;
- struct scsi_rw *rw;
- struct scsi_rw_big *rwb;
- aac_lock_t lock;
- int retval = SUCCESSFULLY_QUEUED;
+ struct aac_softc *sc;
+ struct aac_container *co;
+ struct aac_sim *sim;
+ int error;
- AAC_DPRINTF(AAC_D_CMD, ("aac_scsi_cmd "));
+ debug_called(1);
- xs->error = XS_NOERROR;
+ sc = device_get_softc(dev);
- if (target >= AAC_MAX_CONTAINERS || !sc->sc_hdr[target].hd_present ||
- link->lun != 0) {
- /*
- * XXX Should be XS_SENSE but that would require setting up a
- * faked sense too.
- */
- xs->error = XS_DRIVER_STUFFUP;
- xs->flags |= ITSDONE;
- scsi_done(xs);
- return (COMPLETE);
+ if (sc->aac_state & AAC_STATE_OPEN)
+ return(EBUSY);
+
+ /* Remove the child containers */
+ while ((co = TAILQ_FIRST(&sc->aac_container_tqh)) != NULL) {
+ error = device_delete_child(dev, co->co_disk);
+ if (error)
+ return (error);
+ TAILQ_REMOVE(&sc->aac_container_tqh, co, co_link);
+ free(co, M_AACBUF);
}
- lock = AAC_LOCK(sc);
+ /* Remove the CAM SIMs */
+ while ((sim = TAILQ_FIRST(&sc->aac_sim_tqh)) != NULL) {
+ TAILQ_REMOVE(&sc->aac_sim_tqh, sim, sim_link);
+ error = device_delete_child(dev, sim->sim_dev);
+ if (error)
+ return (error);
+ free(sim, M_AACBUF);
+ }
- /* Don't double enqueue if we came from aac_chain. */
- if (xs != LIST_FIRST(&sc->sc_queue))
- aac_enqueue(sc, xs, 0);
+ if (sc->aifflags & AAC_AIFFLAGS_RUNNING) {
+ sc->aifflags |= AAC_AIFFLAGS_EXIT;
+ wakeup(sc->aifthread);
+ tsleep(sc->aac_dev, PUSER | PCATCH, "aacdch", 30 * hz);
+ }
- while ((xs = aac_dequeue(sc))) {
- xs->error = XS_NOERROR;
- ccb = NULL;
- link = xs->sc_link;
- target = link->target;
-
- switch (xs->cmd->opcode) {
- case TEST_UNIT_READY:
- case REQUEST_SENSE:
- case INQUIRY:
- case MODE_SENSE:
- case START_STOP:
- case READ_CAPACITY:
-#if 0
- case VERIFY:
-#endif
- if (!aac_internal_cache_cmd(xs)) {
- AAC_UNLOCK(sc, lock);
- return (TRY_AGAIN_LATER);
- }
- xs->flags |= ITSDONE;
- scsi_done(xs);
- goto ready;
+ if (sc->aifflags & AAC_AIFFLAGS_RUNNING)
+ panic("Cannot shutdown AIF thread\n");
- case PREVENT_ALLOW:
- AAC_DPRINTF(AAC_D_CMD, ("PREVENT/ALLOW "));
- /* XXX Not yet implemented */
- xs->error = XS_NOERROR;
- xs->flags |= ITSDONE;
- scsi_done(xs);
- goto ready;
+ if ((error = aac_shutdown(dev)))
+ return(error);
- case SYNCHRONIZE_CACHE:
- AAC_DPRINTF(AAC_D_CMD, ("SYNCHRONIZE_CACHE "));
- /* XXX Not yet implemented */
- xs->error = XS_NOERROR;
- xs->flags |= ITSDONE;
- scsi_done(xs);
- goto ready;
+ EVENTHANDLER_DEREGISTER(shutdown_final, sc->eh);
- default:
- AAC_DPRINTF(AAC_D_CMD,
- ("unknown opc %d ", xs->cmd->opcode));
- /* XXX Not yet implemented */
- xs->error = XS_DRIVER_STUFFUP;
- xs->flags |= ITSDONE;
- scsi_done(xs);
- goto ready;
+ aac_free(sc);
- case READ_COMMAND:
- case READ_BIG:
- case WRITE_COMMAND:
- case WRITE_BIG:
- AAC_DPRINTF(AAC_D_CMD,
- ("rw opc %d ", xs->cmd->opcode));
-
- if (xs->cmd->opcode != SYNCHRONIZE_CACHE) {
- /* A read or write operation. */
- if (xs->cmdlen == 6) {
- rw = (struct scsi_rw *)xs->cmd;
- blockno = _3btol(rw->addr) &
- (SRW_TOPADDR << 16 | 0xffff);
- blockcnt =
- rw->length ? rw->length : 0x100;
- } else {
- rwb = (struct scsi_rw_big *)xs->cmd;
- blockno = _4btol(rwb->addr);
- blockcnt = _2btol(rwb->length);
- }
- if (blockno >= sc->sc_hdr[target].hd_size ||
- blockno + blockcnt >
- sc->sc_hdr[target].hd_size) {
- printf(
- "%s: out of bounds %u-%u >= %u\n",
- sc->sc_dev.dv_xname, blockno,
- blockcnt,
- sc->sc_hdr[target].hd_size);
- /*
- * XXX Should be XS_SENSE but that
- * would require setting up a faked
- * sense too.
- */
- xs->error = XS_DRIVER_STUFFUP;
- xs->flags |= ITSDONE;
- scsi_done(xs);
- goto ready;
- }
- }
+ return(0);
+}
+
+/*
+ * Bring the controller down to a dormant state and detach all child devices.
+ *
+ * This function is called before detach or system shutdown.
+ *
+ * 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
+aac_shutdown(device_t dev)
+{
+ struct aac_softc *sc;
+ struct aac_fib *fib;
+ struct aac_close_command *cc;
- ccb = aac_get_ccb(sc, xs->flags);
+ debug_called(1);
- /*
- * We are out of commands, try again in a little while.
- */
- if (ccb == NULL) {
- xs->error = XS_DRIVER_STUFFUP;
- AAC_UNLOCK(sc, lock);
- return (TRY_AGAIN_LATER);
- }
+ sc = device_get_softc(dev);
- ccb->ac_blockno = blockno;
- ccb->ac_blockcnt = blockcnt;
- ccb->ac_xs = xs;
- ccb->ac_timeout = xs->timeout;
-
- if (xs->cmd->opcode != SYNCHRONIZE_CACHE &&
- aac_map_command(ccb)) {
- aac_free_ccb(sc, ccb);
- xs->error = XS_DRIVER_STUFFUP;
- xs->flags |= ITSDONE;
- scsi_done(xs);
- goto ready;
- }
+ sc->aac_state |= AAC_STATE_SUSPEND;
- aac_enqueue_ccb(sc, ccb);
- /* XXX what if enqueue did not start a transfer? */
- if (xs->flags & SCSI_POLL) {
-#if 0
- if (!aac_wait(sc, ccb, ccb->ac_timeout)) {
- AAC_UNLOCK(sc, lock);
- printf("%s: command timed out\n",
- sc->sc_dev.dv_xname);
- xs->error = XS_TIMEOUT;
- return (TRY_AGAIN_LATER);
- }
- xs->flags |= ITSDONE;
- scsi_done(xs);
-#endif
- }
- }
+ /*
+ * Send a Container shutdown followed by a HostShutdown FIB to the
+ * controller to convince it that we don't want to talk to it anymore.
+ * We've been closed and all I/O completed already
+ */
+ device_printf(sc->aac_dev, "shutting down controller...");
+
+ aac_alloc_sync_fib(sc, &fib, AAC_SYNC_LOCK_FORCE);
+ cc = (struct aac_close_command *)&fib->data[0];
- ready:
+ bzero(cc, sizeof(struct aac_close_command));
+ cc->Command = VM_CloseAll;
+ cc->ContainerId = 0xffffffff;
+ if (aac_sync_fib(sc, ContainerCommand, 0, fib,
+ sizeof(struct aac_close_command)))
+ printf("FAILED.\n");
+ else
+ printf("done\n");
+ else {
+ fib->data[0] = 0;
/*
- * Don't process the queue if we are polling.
+ * 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 (xs->flags & SCSI_POLL) {
- retval = COMPLETE;
- break;
+ if (aac_sync_fib(sc, FsaHostShutdown, AAC_FIBSTATE_SHUTDOWN,
+ fib, 1)) {
+ printf("FAILED.\n");
+ } else {
+ printf("done.\n");
}
}
- AAC_UNLOCK(sc, lock);
- return (retval);
+ AAC_MASK_INTERRUPTS(sc);
+
+ return(0);
}
-void
-aac_copy_internal_data(xs, data, size)
- struct scsi_xfer *xs;
- u_int8_t *data;
- size_t size;
+/*
+ * Bring the controller to a quiescent state, ready for system suspend.
+ */
+int
+aac_suspend(device_t dev)
{
- size_t copy_cnt;
+ struct aac_softc *sc;
- AAC_DPRINTF(AAC_D_MISC, ("aac_copy_internal_data "));
+ debug_called(1);
- if (!xs->datalen)
- printf("uio move not yet supported\n");
- else {
- copy_cnt = MIN(size, xs->datalen);
- bcopy(data, xs->data, copy_cnt);
- }
+ sc = device_get_softc(dev);
+
+ sc->aac_state |= AAC_STATE_SUSPEND;
+
+ AAC_MASK_INTERRUPTS(sc);
+ return(0);
}
-/* Emulated SCSI operation on cache device */
+/*
+ * Bring the controller back to a state ready for operation.
+ */
int
-aac_internal_cache_cmd(xs)
- struct scsi_xfer *xs;
+aac_resume(device_t dev)
{
- struct scsi_link *link = xs->sc_link;
- struct aac_softc *sc = link->adapter_softc;
- struct scsi_inquiry_data inq;
- struct scsi_sense_data sd;
- struct scsi_read_cap_data rcd;
- u_int8_t target = link->target;
+ struct aac_softc *sc;
- AAC_DPRINTF(AAC_D_CMD, ("aac_internal_cache_cmd "));
+ debug_called(1);
- switch (xs->cmd->opcode) {
- case TEST_UNIT_READY:
- case START_STOP:
-#if 0
- case VERIFY:
+ sc = device_get_softc(dev);
+
+ sc->aac_state &= ~AAC_STATE_SUSPEND;
+ AAC_UNMASK_INTERRUPTS(sc);
+ return(0);
+}
#endif
- AAC_DPRINTF(AAC_D_CMD, ("opc %d tgt %d ", xs->cmd->opcode,
- target));
- break;
- case REQUEST_SENSE:
- AAC_DPRINTF(AAC_D_CMD, ("REQUEST SENSE tgt %d ", target));
- bzero(&sd, sizeof sd);
- sd.error_code = 0x70;
- sd.segment = 0;
- sd.flags = SKEY_NO_SENSE;
- aac_enc32(sd.info, 0);
- sd.extra_len = 0;
- aac_copy_internal_data(xs, (u_int8_t *)&sd, sizeof sd);
- break;
+/*
+ * Take an interrupt.
+ */
+int
+aac_intr(void *arg)
+{
+ struct aac_softc *sc = arg;
+ u_int16_t reason;
- case INQUIRY:
- AAC_DPRINTF(AAC_D_CMD, ("INQUIRY tgt %d devtype %x ", target,
- sc->sc_hdr[target].hd_devtype));
- bzero(&inq, sizeof inq);
- /* XXX How do we detect removable/CD-ROM devices? */
- inq.device = T_DIRECT;
- inq.dev_qual2 = 0;
- inq.version = 2;
- inq.response_format = 2;
- inq.additional_length = 32;
- strlcpy(inq.vendor, "Adaptec", sizeof inq.vendor);
- snprintf(inq.product, sizeof inq.product, "Container #%02d",
- target);
- strlcpy(inq.revision, " ", sizeof inq.revision);
- aac_copy_internal_data(xs, (u_int8_t *)&inq, sizeof inq);
- break;
- case READ_CAPACITY:
- AAC_DPRINTF(AAC_D_CMD, ("READ CAPACITY tgt %d ", target));
- bzero(&rcd, sizeof rcd);
- _lto4b(sc->sc_hdr[target].hd_size - 1, rcd.addr);
- _lto4b(AAC_BLOCK_SIZE, rcd.length);
- aac_copy_internal_data(xs, (u_int8_t *)&rcd, sizeof rcd);
- break;
+ /*
+ * Read the status register directly. This is faster than taking the
+ * driver lock and reading the queues directly. It also saves having
+ * to turn parts of the driver lock into a spin mutex, which would be
+ * ugly.
+ */
+ reason = AAC_GET_ISTATUS(sc);
+ AAC_CLEAR_ISTATUS(sc, reason);
+ (void)AAC_GET_ISTATUS(sc);
- default:
- AAC_DPRINTF(AAC_D_CMD, ("unsupported scsi command %#x tgt %d ",
- xs->cmd->opcode, target));
- xs->error = XS_DRIVER_STUFFUP;
+ if (reason == 0)
return (0);
+
+ AAC_DPRINTF(AAC_D_INTR, ("%s: intr: sc=%p: reason=%#x\n",
+ sc->aac_dev.dv_xname, sc, reason));
+
+ /* controller wants to talk to us */
+ if (reason & (AAC_DB_PRINTF | AAC_DB_COMMAND_READY |
+ AAC_DB_RESPONSE_READY)) {
+
+ if (reason & AAC_DB_RESPONSE_READY) {
+ /* handle completion processing */
+ if (sc->aifflags & AAC_AIFFLAGS_RUNNING) {
+ sc->aifflags |= AAC_AIFFLAGS_COMPLETE;
+ } else {
+ AAC_LOCK_ACQUIRE(&sc->aac_io_lock);
+ aac_complete(sc);
+ AAC_LOCK_RELEASE(&sc->aac_io_lock);
+ }
+ }
+
+
+ /*
+ * XXX Make sure that we don't get fooled by strange messages
+ * that start with a NULL.
+ */
+ if (reason & AAC_DB_PRINTF)
+ if (sc->aac_common->ac_printf[0] == 0)
+ sc->aac_common->ac_printf[0] = 32;
+
+ /*
+ * This might miss doing the actual wakeup. However, the
+ * msleep that this is waking up has a timeout, so it will
+ * wake up eventually. AIFs and printfs are low enough
+ * priority that they can handle hanging out for a few seconds
+ * if needed.
+ */
+ if (sc->aifthread)
+ wakeup(sc->aifthread);
+
}
- xs->error = XS_NOERROR;
return (1);
}
/*
- * Take an interrupt.
+ * Command Processing
*/
-int
-aac_intr(arg)
- void *arg;
+
+/*
+ * Start as much queued I/O as possible on the controller
+ */
+void
+aac_startio(struct aac_softc *sc)
{
- struct aac_softc *sc = arg;
- u_int16_t reason;
- int claimed = 0;
+ struct aac_command *cm;
- AAC_DPRINTF(AAC_D_INTR, ("aac_intr(%p) ", sc));
+ AAC_DPRINTF(AAC_D_CMD, ("%s: start command", sc->aac_dev.dv_xname));
- reason = AAC_GET_ISTATUS(sc);
- AAC_DPRINTF(AAC_D_INTR, ("istatus 0x%04x ", reason));
-
- /* controller wants to talk to the log? XXX should we defer this? */
- if (reason & AAC_DB_PRINTF) {
- if (sc->sc_common->ac_printf[0]) {
- printf("%s: ** %.*s", sc->sc_dev.dv_xname,
- AAC_PRINTF_BUFSIZE, sc->sc_common->ac_printf);
- sc->sc_common->ac_printf[0] = 0;
- }
- AAC_CLEAR_ISTATUS(sc, AAC_DB_PRINTF);
- AAC_QNOTIFY(sc, AAC_DB_PRINTF);
- claimed = 1;
+ if (sc->flags & AAC_QUEUE_FRZN) {
+ AAC_DPRINTF(AAC_D_CMD, (": queue frozen"));
+ return;
}
- /* Controller has a message for us? */
- if (reason & AAC_DB_COMMAND_READY) {
- aac_host_command(sc);
- AAC_CLEAR_ISTATUS(sc, AAC_DB_COMMAND_READY);
- claimed = 1;
- }
-
- /* Controller has a response for us? */
- if (reason & AAC_DB_RESPONSE_READY) {
- aac_host_response(sc);
- AAC_CLEAR_ISTATUS(sc, AAC_DB_RESPONSE_READY);
- claimed = 1;
+ AAC_DPRINTF(AAC_D_CMD, ("\n"));
+
+ for (;;) {
+ /*
+ * Try to get a command that's been put off for lack of
+ * resources
+ */
+ cm = aac_dequeue_ready(sc);
+
+ /*
+ * Try to build a command off the bio queue (ignore error
+ * return)
+ */
+ if (cm == NULL) {
+ AAC_DPRINTF(AAC_D_CMD, ("\n"));
+ aac_bio_command(sc, &cm);
+ AAC_DPRINTF(AAC_D_CMD, ("%s: start done bio",
+ sc->aac_dev.dv_xname));
+ }
+
+ /* nothing to do? */
+ if (cm == NULL)
+ break;
+
+ /*
+ * Try to give the command to the controller. Any error is
+ * catastrophic since it means that bus_dmamap_load() failed.
+ */
+ if (aac_map_command(cm) != 0)
+ panic("aac: error mapping command %p\n", cm);
+
+ AAC_DPRINTF(AAC_D_CMD, ("\n%s: another command",
+ sc->aac_dev.dv_xname));
}
- /*
- * Spurious interrupts that we don't use - reset the mask and clear
- * the interrupts.
- */
- if (reason & (AAC_DB_SYNC_COMMAND | AAC_DB_COMMAND_NOT_FULL |
- AAC_DB_RESPONSE_NOT_FULL)) {
- AAC_UNMASK_INTERRUPTS(sc);
- AAC_CLEAR_ISTATUS(sc, AAC_DB_SYNC_COMMAND |
- AAC_DB_COMMAND_NOT_FULL | AAC_DB_RESPONSE_NOT_FULL);
- claimed = 1;
+ AAC_DPRINTF(AAC_D_CMD, ("\n"));
+}
+
+/*
+ * Deliver a command to the controller; allocate controller resources at the
+ * last moment when possible.
+ */
+int
+aac_map_command(struct aac_command *cm)
+{
+ struct aac_softc *sc = cm->cm_sc;
+ int error = 0;
+
+ AAC_DPRINTF(AAC_D_CMD, (": map command"));
+
+ /* don't map more than once */
+ if (cm->cm_flags & AAC_CMD_MAPPED)
+ panic("aac: command %p already mapped", cm);
+
+ if (cm->cm_datalen != 0) {
+ error = bus_dmamap_load(sc->aac_dmat, cm->cm_datamap,
+ cm->cm_data, cm->cm_datalen, NULL,
+ BUS_DMA_NOWAIT);
+ if (error)
+ return (error);
+
+ aac_map_command_sg(cm, cm->cm_datamap->dm_segs,
+ cm->cm_datamap->dm_nsegs, 0);
+ } else {
+ aac_map_command_sg(cm, NULL, 0, 0);
}
- return (claimed);
+ return (error);
}
/*
* Handle notification of one or more FIBs coming from the controller.
*/
void
-aac_host_command(struct aac_softc *sc)
+aac_command_thread(void *arg)
{
+ struct aac_softc *sc = arg;
struct aac_fib *fib;
u_int32_t fib_size;
+ int size, retval;
+
+ AAC_DPRINTF(AAC_D_THREAD, ("%s: aac_command_thread: starting\n",
+ sc->aac_dev.dv_xname));
+ AAC_LOCK_ACQUIRE(&sc->aac_io_lock);
+ sc->aifflags = AAC_AIFFLAGS_RUNNING;
+
+ while ((sc->aifflags & AAC_AIFFLAGS_EXIT) == 0) {
+
+ AAC_DPRINTF(AAC_D_THREAD,
+ ("%s: aac_command_thread: aifflags=%#x\n",
+ sc->aac_dev.dv_xname, sc->aifflags));
+ retval = 0;
+
+ if ((sc->aifflags & AAC_AIFFLAGS_PENDING) == 0) {
+ AAC_DPRINTF(AAC_D_THREAD,
+ ("%s: command thread sleeping\n",
+ sc->aac_dev.dv_xname));
+ AAC_LOCK_RELEASE(&sc->aac_io_lock);
+ retval = tsleep(sc->aifthread, PRIBIO, "aifthd",
+ AAC_PERIODIC_INTERVAL * hz);
+ AAC_LOCK_ACQUIRE(&sc->aac_io_lock);
+ }
- for (;;) {
- if (aac_dequeue_fib(sc, AAC_HOST_NORM_CMD_QUEUE, &fib_size,
- &fib))
- break; /* nothing to do */
+ if ((sc->aifflags & AAC_AIFFLAGS_COMPLETE) != 0) {
+ aac_complete(sc);
+ sc->aifflags &= ~AAC_AIFFLAGS_COMPLETE;
+ }
- switch(fib->Header.Command) {
- case AifRequest:
-#if 0
- aac_handle_aif(sc,
- (struct aac_aif_command *)&fib->data[0]);
-#endif
+ /*
+ * While we're here, check to see if any commands are stuck.
+ * This is pretty low-priority, so it's ok if it doesn't
+ * always fire.
+ */
+ if (retval == EWOULDBLOCK)
+ aac_timeout(sc);
- break;
- default:
- printf("%s: unknown command from controller\n",
- sc->sc_dev.dv_xname);
+ /* Check the hardware printf message buffer */
+ if (sc->aac_common->ac_printf[0] != 0)
+ aac_print_printf(sc);
+
+ /* Also check to see if the adapter has a command for us. */
+ while (aac_dequeue_fib(sc, AAC_HOST_NORM_CMD_QUEUE,
+ &fib_size, &fib) == 0) {
+
AAC_PRINT_FIB(sc, fib);
- break;
- }
+
+ switch (fib->Header.Command) {
+ case AifRequest:
+ //aac_handle_aif(sc, fib);
+ break;
+ default:
+ printf("%s: unknown command from controller\n",
+ sc->aac_dev.dv_xname);
+ break;
+ }
- /* XXX reply to FIBs requesting responses ?? */
- /* XXX how do we return these FIBs to the controller? */
+ if ((fib->Header.XferState == 0) ||
+ (fib->Header.StructType != AAC_FIBTYPE_TFIB))
+ break;
+
+ /* Return the AIF to the controller. */
+ if (fib->Header.XferState & AAC_FIBSTATE_FROMADAP) {
+ fib->Header.XferState |= AAC_FIBSTATE_DONEHOST;
+ *(AAC_FSAStatus*)fib->data = ST_OK;
+
+ /* XXX Compute the Size field? */
+ size = fib->Header.Size;
+ if (size > sizeof(struct aac_fib)) {
+ size = sizeof(struct aac_fib);
+ fib->Header.Size = size;
+ }
+
+ /*
+ * Since we did not generate this command, it
+ * cannot go through the normal
+ * enqueue->startio chain.
+ */
+ aac_enqueue_response(sc,
+ AAC_ADAP_NORM_RESP_QUEUE,
+ fib);
+ }
+ }
}
+ sc->aifflags &= ~AAC_AIFFLAGS_RUNNING;
+ AAC_LOCK_RELEASE(&sc->aac_io_lock);
+
+#if 0
+ /*
+ * if we ever implement detach, we should have detach tsleep
+ * to wait for this thread to finish
+ */
+ wakeup(sc->aac_dev);
+#endif
+
+ AAC_DPRINTF(AAC_D_THREAD, ("%s: aac_command_thread: exiting\n",
+ sc->aac_dev.dv_xname));
+ kthread_exit(0);
}
/*
- * Handle notification of one or more FIBs completed by the controller
+ * Process completed commands.
*/
void
-aac_host_response(struct aac_softc *sc)
+aac_complete(void *context)
{
- struct aac_ccb *ccb;
+ struct aac_softc *sc = (struct aac_softc *)context;
+ struct aac_command *cm;
struct aac_fib *fib;
u_int32_t fib_size;
+ AAC_DPRINTF(AAC_D_CMD, ("%s: complete", sc->aac_dev.dv_xname));
+
+ /* pull completed commands off the queue */
for (;;) {
/* look for completed FIBs on our queue */
if (aac_dequeue_fib(sc, AAC_HOST_NORM_RESP_QUEUE, &fib_size,
- &fib))
+ &fib))
break; /* nothing to do */
-
- /* get the command, unmap and queue for later processing */
- ccb = (struct aac_ccb *)fib->Header.SenderData;
- if (ccb == NULL) {
+
+ /* get the command, unmap and hand off for processing */
+ cm = sc->aac_commands + fib->Header.SenderData;
+ if (cm == NULL) {
AAC_PRINT_FIB(sc, fib);
+ break;
+ }
+
+ aac_remove_busy(cm);
+ aac_unmap_command(cm);
+ cm->cm_flags |= AAC_CMD_COMPLETED;
+
+ /* is there a completion handler? */
+ if (cm->cm_complete != NULL) {
+ cm->cm_complete(cm);
} else {
- timeout_del(&ccb->ac_xs->stimeout);
- aac_unmap_command(ccb); /* XXX defer? */
- aac_enqueue_completed(ccb);
+ /* assume that someone is sleeping on this command */
+ wakeup(cm);
}
}
- /* handle completion processing */
- aac_complete(sc, 0);
+ AAC_DPRINTF(AAC_D_CMD, ("\n"));
+ /* see if we can start some more I/O */
+ sc->flags &= ~AAC_QUEUE_FRZN;
+ aac_startio(sc);
}
/*
- * Process completed commands.
+ * Get a bio and build a command to go with it.
*/
-void
-aac_complete(void *context, int pending)
+int
+aac_bio_command(struct aac_softc *sc, struct aac_command **cmp)
{
- struct aac_softc *sc = (struct aac_softc *)context;
- struct aac_ccb *ccb;
+ struct aac_command *cm;
+ struct aac_fib *fib;
+ struct scsi_xfer *xs;
+ u_int8_t opcode = 0;
- /* pull completed commands off the queue */
- for (;;) {
- ccb = aac_dequeue_completed(sc);
- if (ccb == NULL)
- return;
- ccb->ac_flags |= AAC_ACF_COMPLETED;
+ AAC_DPRINTF(AAC_D_CMD, ("%s: bio command", sc->aac_dev.dv_xname));
-#if 0
- /* is there a completion handler? */
- if (ccb->ac_complete != NULL) {
- ccb->ac_complete(ccb);
+ /* get the resources we will need */
+ if ((cm = aac_dequeue_bio(sc)) == NULL)
+ goto fail;
+ xs = cm->cm_private;
+
+ /* build the FIB */
+ fib = cm->cm_fib;
+ fib->Header.Size = sizeof(struct aac_fib_header);
+ fib->Header.XferState =
+ AAC_FIBSTATE_HOSTOWNED |
+ AAC_FIBSTATE_INITIALISED |
+ AAC_FIBSTATE_EMPTY |
+ AAC_FIBSTATE_FROMHOST |
+ AAC_FIBSTATE_REXPECTED |
+ AAC_FIBSTATE_NORM |
+ AAC_FIBSTATE_ASYNC |
+ AAC_FIBSTATE_FAST_RESPONSE;
+
+ switch(xs->cmd->opcode) {
+ case READ_COMMAND:
+ case READ_BIG:
+ opcode = READ_COMMAND;
+ break;
+ case WRITE_COMMAND:
+ case WRITE_BIG:
+ opcode = WRITE_COMMAND;
+ break;
+ default:
+ panic("%s: invalid opcode %#x\n", sc->aac_dev.dv_xname,
+ xs->cmd->opcode);
+ }
+
+ /* build the read/write request */
+ if ((sc->flags & AAC_FLAGS_SG_64BIT) == 0) {
+ fib->Header.Command = ContainerCommand;
+ if (opcode == READ_COMMAND) {
+ struct aac_blockread *br;
+ br = (struct aac_blockread *)&fib->data[0];
+ br->Command = VM_CtBlockRead;
+ br->ContainerId = xs->sc_link->target;
+ br->BlockNumber = cm->cm_blkno;
+ br->ByteCount = cm->cm_bcount * AAC_BLOCK_SIZE;
+ fib->Header.Size += sizeof(struct aac_blockread);
+ cm->cm_sgtable = &br->SgMap;
+ cm->cm_flags |= AAC_CMD_DATAIN;
} else {
- /* assume that someone is sleeping on this command */
- wakeup(ccb);
+ struct aac_blockwrite *bw;
+ bw = (struct aac_blockwrite *)&fib->data[0];
+ bw->Command = VM_CtBlockWrite;
+ bw->ContainerId = xs->sc_link->target;
+ bw->BlockNumber = cm->cm_blkno;
+ bw->ByteCount = cm->cm_bcount * AAC_BLOCK_SIZE;
+ bw->Stable = CUNSTABLE;
+ fib->Header.Size += sizeof(struct aac_blockwrite);
+ cm->cm_flags |= AAC_CMD_DATAOUT;
+ cm->cm_sgtable = &bw->SgMap;
+ }
+ } else {
+ fib->Header.Command = ContainerCommand64;
+ if (opcode == READ_COMMAND) {
+ struct aac_blockread64 *br;
+ br = (struct aac_blockread64 *)&fib->data[0];
+ br->Command = VM_CtHostRead64;
+ br->ContainerId = xs->sc_link->target;
+ br->BlockNumber = cm->cm_blkno;
+ br->SectorCount = cm->cm_bcount;
+ br->Pad = 0;
+ br->Flags = 0;
+ fib->Header.Size += sizeof(struct aac_blockread64);
+ cm->cm_flags |= AAC_CMD_DATAOUT;
+ (struct aac_sg_table64 *)cm->cm_sgtable = &br->SgMap64;
+ } else {
+ struct aac_blockwrite64 *bw;
+ bw = (struct aac_blockwrite64 *)&fib->data[0];
+ bw->Command = VM_CtHostWrite64;
+ bw->ContainerId = xs->sc_link->target;
+ bw->BlockNumber = cm->cm_blkno;
+ bw->SectorCount = cm->cm_bcount;
+ bw->Pad = 0;
+ bw->Flags = 0;
+ fib->Header.Size += sizeof(struct aac_blockwrite64);
+ cm->cm_flags |= AAC_CMD_DATAIN;
+ (struct aac_sg_table64 *)cm->cm_sgtable = &bw->SgMap64;
}
-#else
- aac_bio_complete(ccb);
-#endif
}
+
+ *cmp = cm;
+ AAC_DPRINTF(AAC_D_CMD, ("\n"));
+ return(0);
+
+fail:
+ AAC_DPRINTF(AAC_D_CMD, ("\n"));
+ return(ENOMEM);
}
/*
* Handle a bio-instigated command that has been completed.
*/
void
-aac_bio_complete(struct aac_ccb *ccb)
+aac_bio_complete(struct aac_command *cm)
{
- struct scsi_xfer *xs = ccb->ac_xs;
- struct aac_softc *sc = xs->sc_link->adapter_softc;
- struct buf *bp = xs->bp;
struct aac_blockread_response *brr;
struct aac_blockwrite_response *bwr;
+ struct scsi_xfer *xs = (struct scsi_xfer *)cm->cm_private;
+ struct buf *bp = xs->bp;
AAC_FSAStatus status;
+ int s;
+
+ AAC_DPRINTF(AAC_D_CMD,
+ ("%s: bio complete\n", cm->cm_sc->aac_dev.dv_xname));
+ s = splbio();
+ aac_release_command(cm);
if (bp == NULL)
- goto done;
+ goto exit;
/* fetch relevant status and then release the command */
if (bp->b_flags & B_READ) {
- brr = (struct aac_blockread_response *)&ccb->ac_fib->data[0];
+ brr = (struct aac_blockread_response *)&cm->cm_fib->data[0];
status = brr->Status;
} else {
- bwr = (struct aac_blockwrite_response *)&ccb->ac_fib->data[0];
+ bwr = (struct aac_blockwrite_response *)&cm->cm_fib->data[0];
status = bwr->Status;
}
- aac_free_ccb(sc, ccb);
/* fix up the bio based on status */
if (status == ST_OK) {
@@ -1058,32 +1088,634 @@ aac_bio_complete(struct aac_ccb *ccb)
} else {
bp->b_error = EIO;
bp->b_flags |= B_ERROR;
-
- /* XXX be more verbose? */
- printf("%s: I/O error %d (%s)\n", sc->sc_dev.dv_xname,
- status, AAC_COMMAND_STATUS(status));
+
+ /* pass an error string out to the disk layer */
+ aac_describe_code(aac_command_status_table, status);
}
-done:
+ exit:
+ xs->error = XS_NOERROR;
+ xs->resid = 0;
+ xs->flags |= ITSDONE;
scsi_done(xs);
+ splx(s);
+}
+
+/*
+ * 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
+ * be stuck here forever. At the same time, signals are not caught
+ * because there is a risk that a signal could wakeup the tsleep before
+ * the card has a chance to complete the command. The passed in timeout
+ * is ignored for the same reason. Since there is no way to cancel a
+ * command in progress, we should probably create a 'dead' queue where
+ * commands go that have been interrupted/timed-out/etc, that keeps them
+ * out of the free pool. That way, if the card is just slow, it won't
+ * spam the memory of a command that has been recycled.
+ */
+int
+aac_wait_command(struct aac_command *cm, int timeout)
+{
+ struct aac_softc *sc = cm->cm_sc;
+ int error = 0;
+
+ AAC_DPRINTF(AAC_D_CMD, (": wait for command"));
+
+ /* Put the command on the ready queue and get things going */
+ cm->cm_queue = AAC_ADAP_NORM_CMD_QUEUE;
+ aac_enqueue_ready(cm);
+ AAC_DPRINTF(AAC_D_CMD, ("\n"));
+ aac_startio(sc);
+ while (!(cm->cm_flags & AAC_CMD_COMPLETED) && (error != EWOULDBLOCK)) {
+ AAC_DPRINTF(AAC_D_MISC, ("%s: sleeping until command done\n",
+ sc->aac_dev.dv_xname));
+ AAC_LOCK_RELEASE(&sc->aac_io_lock);
+ error = tsleep(cm, PRIBIO, "aacwait", timeout);
+ AAC_LOCK_ACQUIRE(&sc->aac_io_lock);
+ }
+ return (error);
+}
+
+/*
+ *Command Buffer Management
+ */
+
+/*
+ * Allocate a command.
+ */
+int
+aac_alloc_command(struct aac_softc *sc, struct aac_command **cmp)
+{
+ struct aac_command *cm;
+
+ AAC_DPRINTF(AAC_D_CMD, (": allocate command"));
+ if ((cm = aac_dequeue_free(sc)) == NULL) {
+ AAC_DPRINTF(AAC_D_CMD, (" failed"));
+ return (EBUSY);
+ }
+
+ *cmp = cm;
+ return(0);
+}
+
+/*
+ * Release a command back to the freelist.
+ */
+void
+aac_release_command(struct aac_command *cm)
+{
+ AAC_DPRINTF(AAC_D_CMD, (": release command"));
+
+ /* (re)initialise the command/FIB */
+ cm->cm_sgtable = NULL;
+ cm->cm_flags = 0;
+ cm->cm_complete = NULL;
+ cm->cm_private = NULL;
+ cm->cm_fib->Header.XferState = AAC_FIBSTATE_EMPTY;
+ cm->cm_fib->Header.StructType = AAC_FIBTYPE_TFIB;
+ cm->cm_fib->Header.Flags = 0;
+ cm->cm_fib->Header.SenderSize = sizeof(struct aac_fib);
+
+ /*
+ * These are duplicated in aac_start to cover the case where an
+ * intermediate stage may have destroyed them. They're left
+ * initialised here for debugging purposes only.
+ */
+ cm->cm_fib->Header.ReceiverFibAddress = (u_int32_t)cm->cm_fibphys;
+ cm->cm_fib->Header.SenderData = 0;
+
+ aac_enqueue_free(cm);
+}
+
+/*
+ * Allocate and initialise commands/FIBs for this adapter.
+ */
+int
+aac_alloc_commands(struct aac_softc *sc)
+{
+ struct aac_command *cm;
+ struct aac_fibmap *fm;
+ int i, error;
+
+ if (sc->total_fibs + AAC_FIB_COUNT > sc->aac_max_fibs)
+ return (ENOMEM);
+
+ fm = malloc(sizeof(struct aac_fibmap), M_DEVBUF, M_NOWAIT);
+ if (fm == NULL)
+ goto exit;
+ bzero(fm, sizeof(struct aac_fibmap));
+
+ /* allocate the FIBs in DMAable memory and load them */
+ if (bus_dmamem_alloc(sc->aac_dmat, AAC_FIBMAP_SIZE, PAGE_SIZE, 0,
+ &fm->aac_seg, 1, &fm->aac_nsegs, BUS_DMA_NOWAIT)) {
+ printf("%s: can't alloc FIBs\n", sc->aac_dev.dv_xname);
+ error = ENOBUFS;
+ goto exit_alloc;
+ }
+
+ if (bus_dmamem_map(sc->aac_dmat, &fm->aac_seg, 1,
+ AAC_FIBMAP_SIZE, (caddr_t *)&fm->aac_fibs, BUS_DMA_NOWAIT)) {
+ printf("%s: can't map FIB structure\n", sc->aac_dev.dv_xname);
+ error = ENOBUFS;
+ goto exit_map;
+ }
+
+ if (bus_dmamap_create(sc->aac_dmat, AAC_FIBMAP_SIZE, 1,
+ AAC_FIBMAP_SIZE, 0, BUS_DMA_NOWAIT, &fm->aac_fibmap)) {
+ printf("%s: can't create dma map\n", sc->aac_dev.dv_xname);
+ error = ENOBUFS;
+ goto exit_create;
+ }
+
+ if (bus_dmamap_load(sc->aac_dmat, fm->aac_fibmap, fm->aac_fibs,
+ AAC_FIBMAP_SIZE, NULL, BUS_DMA_NOWAIT)) {
+ printf("%s: can't load dma map\n", sc->aac_dev.dv_xname);
+ error = ENOBUFS;
+ goto exit_load;
+ }
+
+ /* initialise constant fields in the command structure */
+ AAC_LOCK_ACQUIRE(&sc->aac_io_lock);
+ bzero(fm->aac_fibs, AAC_FIB_COUNT * sizeof(struct aac_fib));
+ for (i = 0; i < AAC_FIB_COUNT; i++) {
+ cm = sc->aac_commands + sc->total_fibs;
+ fm->aac_commands = cm;
+ cm->cm_sc = sc;
+ cm->cm_fib = fm->aac_fibs + i;
+ cm->cm_fibphys = fm->aac_fibmap->dm_segs[0].ds_addr +
+ (i * sizeof(struct aac_fib));
+ cm->cm_index = sc->total_fibs;
+
+ if (bus_dmamap_create(sc->aac_dmat, MAXBSIZE, AAC_MAXSGENTRIES,
+ MAXBSIZE, 0, BUS_DMA_NOWAIT, &cm->cm_datamap)) {
+ break;
+ }
+ aac_release_command(cm);
+ sc->total_fibs++;
+ }
+
+ if (i > 0) {
+ TAILQ_INSERT_TAIL(&sc->aac_fibmap_tqh, fm, fm_link);
+ AAC_DPRINTF(AAC_D_MISC, ("%s: total_fibs= %d\n",
+ sc->aac_dev.dv_xname,
+ sc->total_fibs));
+ AAC_LOCK_RELEASE(&sc->aac_io_lock);
+ return (0);
+ }
+
+ exit_load:
+ bus_dmamap_destroy(sc->aac_dmat, fm->aac_fibmap);
+ exit_create:
+ bus_dmamem_unmap(sc->aac_dmat, (caddr_t)fm->aac_fibs, AAC_FIBMAP_SIZE);
+ exit_map:
+ bus_dmamem_free(sc->aac_dmat, &fm->aac_seg, fm->aac_nsegs);
+ exit_alloc:
+ free(fm, M_DEVBUF);
+ exit:
+ AAC_LOCK_RELEASE(&sc->aac_io_lock);
+ return (error);
+}
+
+/*
+ * Free FIBs owned by this adapter.
+ */
+void
+aac_free_commands(struct aac_softc *sc)
+{
+ struct aac_fibmap *fm;
+ struct aac_command *cm;
+ int i;
+
+ while ((fm = TAILQ_FIRST(&sc->aac_fibmap_tqh)) != NULL) {
+
+ TAILQ_REMOVE(&sc->aac_fibmap_tqh, fm, fm_link);
+
+ /*
+ * We check against total_fibs to handle partially
+ * allocated blocks.
+ */
+ for (i = 0; i < AAC_FIB_COUNT && sc->total_fibs--; i++) {
+ cm = fm->aac_commands + i;
+ bus_dmamap_destroy(sc->aac_dmat, cm->cm_datamap);
+ }
+
+ bus_dmamap_unload(sc->aac_dmat, fm->aac_fibmap);
+ bus_dmamap_destroy(sc->aac_dmat, fm->aac_fibmap);
+ bus_dmamem_unmap(sc->aac_dmat, (caddr_t)fm->aac_fibs,
+ AAC_FIBMAP_SIZE);
+ bus_dmamem_free(sc->aac_dmat, &fm->aac_seg, fm->aac_nsegs);
+ free(fm, M_DEVBUF);
+ }
+}
+
+
+/*
+ * Command-mapping helper function - populate this command's s/g table.
+ */
+void
+aac_map_command_sg(void *arg, bus_dma_segment_t *segs, int nseg, int error)
+{
+ struct aac_command *cm = arg;
+ struct aac_softc *sc = cm->cm_sc;
+ struct aac_fib *fib = cm->cm_fib;
+ int i;
+
+ /* copy into the FIB */
+ if (cm->cm_sgtable != NULL) {
+ if ((cm->cm_sc->flags & AAC_FLAGS_SG_64BIT) == 0) {
+ struct aac_sg_table *sg = cm->cm_sgtable;
+ sg->SgCount = nseg;
+ for (i = 0; i < nseg; i++) {
+ sg->SgEntry[i].SgAddress = segs[i].ds_addr;
+ sg->SgEntry[i].SgByteCount = segs[i].ds_len;
+ }
+ /* update the FIB size for the s/g count */
+ fib->Header.Size += nseg * sizeof(struct aac_sg_entry);
+ } else {
+ struct aac_sg_table64 *sg;
+ sg = (struct aac_sg_table64 *)cm->cm_sgtable;
+ sg->SgCount = nseg;
+ for (i = 0; i < nseg; i++) {
+ sg->SgEntry64[i].SgAddress = segs[i].ds_addr;
+ sg->SgEntry64[i].SgByteCount = segs[i].ds_len;
+ }
+ /* update the FIB size for the s/g count */
+ fib->Header.Size += nseg*sizeof(struct aac_sg_entry64);
+ }
+ }
+
+ /* Fix up the address values in the FIB. Use the command array index
+ * instead of a pointer since these fields are only 32 bits. Shift
+ * the SenderFibAddress over to make room for the fast response bit.
+ */
+ cm->cm_fib->Header.SenderFibAddress = (cm->cm_index << 1);
+ cm->cm_fib->Header.ReceiverFibAddress = cm->cm_fibphys;
+
+ /* save a pointer to the command for speedy reverse-lookup */
+ cm->cm_fib->Header.SenderData = cm->cm_index;
+
+ if (cm->cm_flags & AAC_CMD_DATAIN)
+ bus_dmamap_sync(sc->aac_dmat, cm->cm_datamap, 0,
+ cm->cm_datamap->dm_mapsize,
+ BUS_DMASYNC_PREREAD);
+ if (cm->cm_flags & AAC_CMD_DATAOUT)
+ bus_dmamap_sync(sc->aac_dmat, cm->cm_datamap, 0,
+ cm->cm_datamap->dm_mapsize,
+ BUS_DMASYNC_PREWRITE);
+ cm->cm_flags |= AAC_CMD_MAPPED;
+
+ /* put the FIB on the outbound queue */
+ if (aac_enqueue_fib(sc, cm->cm_queue, cm) == EBUSY) {
+ aac_remove_busy(cm);
+ aac_unmap_command(cm);
+ aac_requeue_ready(cm);
+ }
+}
+
+/*
+ * Unmap a command from controller-visible space.
+ */
+void
+aac_unmap_command(struct aac_command *cm)
+{
+ struct aac_softc *sc = cm->cm_sc;
+
+ if (!(cm->cm_flags & AAC_CMD_MAPPED))
+ return;
+
+ if (cm->cm_datalen != 0) {
+ if (cm->cm_flags & AAC_CMD_DATAIN)
+ bus_dmamap_sync(sc->aac_dmat, cm->cm_datamap, 0,
+ cm->cm_datamap->dm_mapsize,
+ BUS_DMASYNC_POSTREAD);
+ if (cm->cm_flags & AAC_CMD_DATAOUT)
+ bus_dmamap_sync(sc->aac_dmat, cm->cm_datamap, 0,
+ cm->cm_datamap->dm_mapsize,
+ BUS_DMASYNC_POSTWRITE);
+
+ bus_dmamap_unload(sc->aac_dmat, cm->cm_datamap);
+ }
+ cm->cm_flags &= ~AAC_CMD_MAPPED;
+}
+
+/*
+ * Hardware Interface
+ */
+
+/*
+ * Initialise the adapter.
+ */
+int
+aac_check_firmware(struct aac_softc *sc)
+{
+ u_int32_t major, minor, options;
+
+ /*
+ * Retrieve the firmware version numbers. Dell PERC2/QC cards with
+ * firmware version 1.x are not compatible with this driver.
+ */
+ if (sc->flags & AAC_FLAGS_PERC2QC) {
+ if (aac_sync_command(sc, AAC_MONKER_GETKERNVER, 0, 0, 0, 0,
+ NULL)) {
+ printf("%s: Error reading firmware version\n",
+ sc->aac_dev.dv_xname);
+ return (EIO);
+ }
+
+ /* These numbers are stored as ASCII! */
+ major = (AAC_GET_MAILBOX(sc, 1) & 0xff) - 0x30;
+ minor = (AAC_GET_MAILBOX(sc, 2) & 0xff) - 0x30;
+ if (major == 1) {
+ printf("%s: Firmware version %d.%d is not supported\n",
+ sc->aac_dev.dv_xname, major, minor);
+ return (EINVAL);
+ }
+ }
+
+ /*
+ * Retrieve the capabilities/supported options word so we know what
+ * work-arounds to enable.
+ */
+ if (aac_sync_command(sc, AAC_MONKER_GETINFO, 0, 0, 0, 0, NULL)) {
+ printf("%s: RequestAdapterInfo failed\n",
+ sc->aac_dev.dv_xname);
+ return (EIO);
+ }
+ options = AAC_GET_MAILBOX(sc, 1);
+ sc->supported_options = options;
+
+ if ((options & AAC_SUPPORTED_4GB_WINDOW) != 0 &&
+ (sc->flags & AAC_FLAGS_NO4GB) == 0)
+ sc->flags |= AAC_FLAGS_4GB_WINDOW;
+ if (options & AAC_SUPPORTED_NONDASD)
+ sc->flags |= AAC_FLAGS_ENABLE_CAM;
+ if ((options & AAC_SUPPORTED_SGMAP_HOST64) != 0
+ && (sizeof(bus_addr_t) > 4)) {
+ printf("%s: Enabling 64-bit address support\n",
+ sc->aac_dev.dv_xname);
+ sc->flags |= AAC_FLAGS_SG_64BIT;
+ }
+
+ /* Check for broken hardware that does a lower number of commands */
+ if ((sc->flags & AAC_FLAGS_256FIBS) == 0)
+ sc->aac_max_fibs = AAC_MAX_FIBS;
+ else
+ sc->aac_max_fibs = 256;
+
+ return (0);
+}
+
+int
+aac_init(struct aac_softc *sc)
+{
+ bus_dma_segment_t seg;
+ int nsegs;
+ int i, error;
+ int state = 0;
+ struct aac_adapter_init *ip;
+ time_t then;
+ u_int32_t code, qoffset;
+
+ /*
+ * First wait for the adapter to come ready.
+ */
+ then = time_second;
+ for (i = 0; i < AAC_BOOT_TIMEOUT * 1000; i++) {
+ code = AAC_GET_FWSTATUS(sc);
+ if (code & AAC_SELF_TEST_FAILED) {
+ printf("%s: FATAL: selftest failed\n",
+ sc->aac_dev.dv_xname);
+ return (ENXIO);
+ }
+ if (code & AAC_KERNEL_PANIC) {
+ printf("%s: FATAL: controller kernel panic\n",
+ sc->aac_dev.dv_xname);
+ return (ENXIO);
+ }
+ if (code & AAC_UP_AND_RUNNING)
+ break;
+ DELAY(1000);
+ }
+ if (i == AAC_BOOT_TIMEOUT * 1000) {
+ printf("%s: FATAL: controller not coming ready, status %x\n",
+ sc->aac_dev.dv_xname, code);
+ return (ENXIO);
+ }
+
+ /*
+ * Work around a bug in the 2120 and 2200 that cannot DMA commands
+ * below address 8192 in physical memory.
+ * XXX If the padding is not needed, can it be put to use instead
+ * of ignored?
+ */
+ if (bus_dmamem_alloc(sc->aac_dmat, AAC_COMMON_ALLOCSIZE, PAGE_SIZE, 0,
+ &seg, 1, &nsegs, BUS_DMA_NOWAIT)) {
+ printf("%s: can't allocate common structure\n",
+ sc->aac_dev.dv_xname);
+ return (ENOMEM);
+ }
+ state++;
+
+ if (bus_dmamem_map(sc->aac_dmat, &seg, nsegs, AAC_COMMON_ALLOCSIZE,
+ (caddr_t *)&sc->aac_common, BUS_DMA_NOWAIT)) {
+ printf("%s: can't map common structure\n",
+ sc->aac_dev.dv_xname);
+ error = ENOMEM;
+ goto bail_out;
+ }
+ state++;
+
+ if (bus_dmamap_create(sc->aac_dmat, AAC_COMMON_ALLOCSIZE, 1,
+ AAC_COMMON_ALLOCSIZE, 0, BUS_DMA_NOWAIT, &sc->aac_common_map)) {
+ printf("%s: can't create dma map\n", sc->aac_dev.dv_xname);
+ error = ENOBUFS;
+ goto bail_out;
+ }
+ state++;
+
+ if (bus_dmamap_load(sc->aac_dmat, sc->aac_common_map, sc->aac_common,
+ AAC_COMMON_ALLOCSIZE, NULL, BUS_DMA_NOWAIT)) {
+ printf("%s: can't load dma map\n", sc->aac_dev.dv_xname);
+ error = ENOBUFS;
+ goto bail_out;
+ }
+ state++;
+
+ sc->aac_common_busaddr = sc->aac_common_map->dm_segs[0].ds_addr;
+
+ if (sc->aac_common_busaddr < 8192) {
+ (uint8_t *)sc->aac_common += 8192;
+ sc->aac_common_busaddr += 8192;
+ }
+ bzero(sc->aac_common, sizeof *sc->aac_common);
+
+ /* Allocate some FIBs and associated command structs */
+ TAILQ_INIT(&sc->aac_fibmap_tqh);
+ sc->aac_commands = malloc(AAC_MAX_FIBS * sizeof(struct aac_command),
+ M_DEVBUF, M_WAITOK);
+ bzero(sc->aac_commands, AAC_MAX_FIBS * sizeof(struct aac_command));
+ while (sc->total_fibs < AAC_MAX_FIBS) {
+ if (aac_alloc_commands(sc) != 0)
+ break;
+ }
+ if (sc->total_fibs == 0)
+ goto out;
+
+ /*
+ * Fill in the init structure. This tells the adapter about the
+ * physical location of various important shared data structures.
+ */
+ ip = &sc->aac_common->ac_init;
+ ip->InitStructRevision = AAC_INIT_STRUCT_REVISION;
+ ip->MiniPortRevision = AAC_INIT_STRUCT_MINIPORT_REVISION;
+
+ ip->AdapterFibsPhysicalAddress = sc->aac_common_busaddr +
+ offsetof(struct aac_common, ac_fibs);
+ ip->AdapterFibsVirtualAddress = 0;
+ ip->AdapterFibsSize = AAC_ADAPTER_FIBS * sizeof(struct aac_fib);
+ ip->AdapterFibAlign = sizeof(struct aac_fib);
+
+ ip->PrintfBufferAddress = sc->aac_common_busaddr +
+ offsetof(struct aac_common, ac_printf);
+ ip->PrintfBufferSize = AAC_PRINTF_BUFSIZE;
+
+ /*
+ * The adapter assumes that pages are 4K in size, except on some
+ * broken firmware versions that do the page->byte conversion twice,
+ * therefore 'assuming' that this value is in 16MB units (2^24).
+ * Round up since the granularity is so high.
+ */
+ ip->HostPhysMemPages = ctob(physmem) / AAC_PAGE_SIZE;
+ if (sc->flags & AAC_FLAGS_BROKEN_MEMMAP) {
+ ip->HostPhysMemPages =
+ (ip->HostPhysMemPages + AAC_PAGE_SIZE) / AAC_PAGE_SIZE;
+ }
+ ip->HostElapsedSeconds = time_second; /* reset later if invalid */
+
+ /*
+ * Initialise FIB queues. Note that it appears that the layout of the
+ * indexes 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, 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 functions which 'know' the size of each list by
+ * virtue of a table.
+ */
+ qoffset = offsetof(struct aac_common, ac_qbuf) + AAC_QUEUE_ALIGN;
+ qoffset &= ~(AAC_QUEUE_ALIGN - 1);
+ sc->aac_queues =
+ (struct aac_queue_table *)((caddr_t)sc->aac_common + qoffset);
+ ip->CommHeaderAddress = sc->aac_common_busaddr + qoffset;
+
+ sc->aac_queues->qt_qindex[AAC_HOST_NORM_CMD_QUEUE][AAC_PRODUCER_INDEX] =
+ AAC_HOST_NORM_CMD_ENTRIES;
+ sc->aac_queues->qt_qindex[AAC_HOST_NORM_CMD_QUEUE][AAC_CONSUMER_INDEX] =
+ AAC_HOST_NORM_CMD_ENTRIES;
+ sc->aac_queues->qt_qindex[AAC_HOST_HIGH_CMD_QUEUE][AAC_PRODUCER_INDEX] =
+ AAC_HOST_HIGH_CMD_ENTRIES;
+ sc->aac_queues->qt_qindex[AAC_HOST_HIGH_CMD_QUEUE][AAC_CONSUMER_INDEX] =
+ AAC_HOST_HIGH_CMD_ENTRIES;
+ sc->aac_queues->qt_qindex[AAC_ADAP_NORM_CMD_QUEUE][AAC_PRODUCER_INDEX] =
+ AAC_ADAP_NORM_CMD_ENTRIES;
+ sc->aac_queues->qt_qindex[AAC_ADAP_NORM_CMD_QUEUE][AAC_CONSUMER_INDEX] =
+ AAC_ADAP_NORM_CMD_ENTRIES;
+ sc->aac_queues->qt_qindex[AAC_ADAP_HIGH_CMD_QUEUE][AAC_PRODUCER_INDEX] =
+ AAC_ADAP_HIGH_CMD_ENTRIES;
+ sc->aac_queues->qt_qindex[AAC_ADAP_HIGH_CMD_QUEUE][AAC_CONSUMER_INDEX] =
+ AAC_ADAP_HIGH_CMD_ENTRIES;
+ sc->aac_queues->qt_qindex[AAC_HOST_NORM_RESP_QUEUE][AAC_PRODUCER_INDEX]=
+ AAC_HOST_NORM_RESP_ENTRIES;
+ sc->aac_queues->qt_qindex[AAC_HOST_NORM_RESP_QUEUE][AAC_CONSUMER_INDEX]=
+ AAC_HOST_NORM_RESP_ENTRIES;
+ sc->aac_queues->qt_qindex[AAC_HOST_HIGH_RESP_QUEUE][AAC_PRODUCER_INDEX]=
+ AAC_HOST_HIGH_RESP_ENTRIES;
+ sc->aac_queues->qt_qindex[AAC_HOST_HIGH_RESP_QUEUE][AAC_CONSUMER_INDEX]=
+ AAC_HOST_HIGH_RESP_ENTRIES;
+ sc->aac_queues->qt_qindex[AAC_ADAP_NORM_RESP_QUEUE][AAC_PRODUCER_INDEX]=
+ AAC_ADAP_NORM_RESP_ENTRIES;
+ sc->aac_queues->qt_qindex[AAC_ADAP_NORM_RESP_QUEUE][AAC_CONSUMER_INDEX]=
+ AAC_ADAP_NORM_RESP_ENTRIES;
+ sc->aac_queues->qt_qindex[AAC_ADAP_HIGH_RESP_QUEUE][AAC_PRODUCER_INDEX]=
+ AAC_ADAP_HIGH_RESP_ENTRIES;
+ sc->aac_queues->qt_qindex[AAC_ADAP_HIGH_RESP_QUEUE][AAC_CONSUMER_INDEX]=
+ AAC_ADAP_HIGH_RESP_ENTRIES;
+ sc->aac_qentries[AAC_HOST_NORM_CMD_QUEUE] =
+ &sc->aac_queues->qt_HostNormCmdQueue[0];
+ sc->aac_qentries[AAC_HOST_HIGH_CMD_QUEUE] =
+ &sc->aac_queues->qt_HostHighCmdQueue[0];
+ sc->aac_qentries[AAC_ADAP_NORM_CMD_QUEUE] =
+ &sc->aac_queues->qt_AdapNormCmdQueue[0];
+ sc->aac_qentries[AAC_ADAP_HIGH_CMD_QUEUE] =
+ &sc->aac_queues->qt_AdapHighCmdQueue[0];
+ sc->aac_qentries[AAC_HOST_NORM_RESP_QUEUE] =
+ &sc->aac_queues->qt_HostNormRespQueue[0];
+ sc->aac_qentries[AAC_HOST_HIGH_RESP_QUEUE] =
+ &sc->aac_queues->qt_HostHighRespQueue[0];
+ sc->aac_qentries[AAC_ADAP_NORM_RESP_QUEUE] =
+ &sc->aac_queues->qt_AdapNormRespQueue[0];
+ sc->aac_qentries[AAC_ADAP_HIGH_RESP_QUEUE] =
+ &sc->aac_queues->qt_AdapHighRespQueue[0];
+
+ /*
+ * Do controller-type-specific initialisation
+ */
+ switch (sc->aac_hwif) {
+ case AAC_HWIF_I960RX:
+ AAC_SETREG4(sc, AAC_RX_ODBR, ~0);
+ break;
+ }
+
+ /*
+ * 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)) {
+ printf("%s: error establishing init structure\n",
+ sc->aac_dev.dv_xname);
+ error = EIO;
+ goto bail_out;
+ }
+
+ aac_describe_controller(sc);
+ aac_startup(sc);
+
+ return (0);
+
+ bail_out:
+ if (state > 3)
+ bus_dmamap_unload(sc->aac_dmat, sc->aac_common_map);
+ if (state > 2)
+ bus_dmamap_destroy(sc->aac_dmat, sc->aac_common_map);
+ if (state > 1)
+ bus_dmamem_unmap(sc->aac_dmat, (caddr_t)sc->aac_common,
+ sizeof *sc->aac_common);
+ if (state > 0)
+ bus_dmamem_free(sc->aac_dmat, &seg, 1);
+
+ out:
+ return (error);
}
/*
* Send a synchronous command to the controller and wait for a result.
*/
int
-aac_sync_command(sc, command, arg0, arg1, arg2, arg3, sp)
- 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;
+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)
{
+// time_t then;
int i;
u_int32_t status;
- aac_lock_t lock = AAC_LOCK(sc);
+ u_int16_t reason;
/* populate the mailbox */
AAC_SET_MAILBOX(sc, command, arg0, arg1, arg2, arg3);
@@ -1093,188 +1725,485 @@ aac_sync_command(sc, command, arg0, arg1, arg2, arg3, sp)
/* then set it to signal the adapter */
AAC_QNOTIFY(sc, AAC_DB_SYNC_COMMAND);
+
+#if 0
+ /* spin waiting for the command to complete */
+ then = time_second;
+ do {
+ if (time_second > (then + AAC_IMMEDIATE_TIMEOUT)) {
+ AAC_DPRINTF(AAC_D_MISC, ("timed out"));
+ return(EIO);
+ }
+ } while (!(AAC_GET_ISTATUS(sc) & AAC_DB_SYNC_COMMAND));
+#else
DELAY(AAC_SYNC_DELAY);
/* spin waiting for the command to complete */
for (i = 0; i < AAC_IMMEDIATE_TIMEOUT * 1000; i++) {
- if (AAC_GET_ISTATUS(sc) & AAC_DB_SYNC_COMMAND)
+ reason = AAC_GET_ISTATUS(sc);
+ if (reason & AAC_DB_SYNC_COMMAND)
+ break;
+ reason = AAC_GET_ISTATUS(sc);
+ if (reason & AAC_DB_SYNC_COMMAND)
+ break;
+ reason = AAC_GET_ISTATUS(sc);
+ if (reason & AAC_DB_SYNC_COMMAND)
break;
DELAY(1000);
}
if (i == AAC_IMMEDIATE_TIMEOUT * 1000) {
- AAC_UNLOCK(sc, lock);
+ printf("aac_sync_command: failed, reason=%#x\n", reason);
return (EIO);
}
+#endif
/* clear the completion flag */
AAC_CLEAR_ISTATUS(sc, AAC_DB_SYNC_COMMAND);
/* get the command status */
- status = AAC_GET_MAILBOXSTATUS(sc);
- AAC_UNLOCK(sc, lock);
+ status = AAC_GET_MAILBOX(sc, 0);
+
if (sp != NULL)
*sp = status;
- return (0); /* check command return status? */
+
+ return(0);
+}
+
+/*
+ * Grab the sync fib area.
+ */
+int
+aac_alloc_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.
*/
int
-aac_sync_fib(sc, command, xferstate, data, datasize, result, resultsize)
- struct aac_softc *sc;
- u_int32_t command;
- u_int32_t xferstate;
- void *data;
- u_int16_t datasize;
- void *result;
- u_int16_t *resultsize;
+aac_sync_fib(struct aac_softc *sc, u_int32_t command, u_int32_t xferstate,
+ struct aac_fib *fib, u_int16_t datasize)
{
- struct aac_fib *fib = &sc->sc_common->ac_sync_fib;
- if (datasize > AAC_FIB_DATASIZE)
- return (EINVAL);
+ if (datasize > AAC_FIB_DATASIZE) {
+ printf("aac_sync_fib 1: datasize=%d AAC_FIB_DATASIZE\n",
+ datasize, AAC_FIB_DATASIZE);
+ return(EINVAL);
+ }
/*
* Set up the sync FIB
*/
fib->Header.XferState = AAC_FIBSTATE_HOSTOWNED |
- AAC_FIBSTATE_INITIALISED | AAC_FIBSTATE_EMPTY;
+ AAC_FIBSTATE_INITIALISED |
+ AAC_FIBSTATE_EMPTY;
fib->Header.XferState |= xferstate;
fib->Header.Command = command;
fib->Header.StructType = AAC_FIBTYPE_TFIB;
- fib->Header.Size = sizeof fib + datasize;
- fib->Header.SenderSize = sizeof *fib;
- fib->Header.SenderFibAddress = (u_int32_t)fib;
- fib->Header.ReceiverFibAddress =
- sc->sc_common_busaddr + offsetof(struct aac_common, ac_sync_fib);
+ fib->Header.Size = sizeof(struct aac_fib) + datasize;
+ fib->Header.SenderSize = sizeof(struct aac_fib);
+ fib->Header.SenderFibAddress = 0; /* Not needed */
+ fib->Header.ReceiverFibAddress = sc->aac_common_busaddr +
+ offsetof(struct aac_common,
+ ac_sync_fib);
/*
- * Copy in data.
+ * Give the FIB to the controller, wait for a response.
*/
- if (data != NULL) {
- bcopy(data, fib->data, datasize);
- fib->Header.XferState |=
- AAC_FIBSTATE_FROMHOST | AAC_FIBSTATE_NORM;
+ if (aac_sync_command(sc, AAC_MONKER_SYNCFIB,
+ fib->Header.ReceiverFibAddress, 0, 0, 0, NULL)) {
+ AAC_DPRINTF(AAC_D_IO, ("%s: aac_sync_fib: IO error\n",
+ sc->aac_dev.dv_xname));
+ printf("aac_sync_fib 2\n");
+ return(EIO);
+ }
+
+ return (0);
+}
+
+/*****************************************************************************
+ * Adapter-space FIB queue manipulation
+ *
+ * Note that the queue implementation here is a little funky; neither the PI or
+ * CI will ever be zero. This behaviour is a controller feature.
+ */
+static struct {
+ int size;
+ int notify;
+} aac_qinfo[] = {
+ { AAC_HOST_NORM_CMD_ENTRIES, AAC_DB_COMMAND_NOT_FULL },
+ { AAC_HOST_HIGH_CMD_ENTRIES, 0 },
+ { AAC_ADAP_NORM_CMD_ENTRIES, AAC_DB_COMMAND_READY },
+ { AAC_ADAP_HIGH_CMD_ENTRIES, 0 },
+ { AAC_HOST_NORM_RESP_ENTRIES, AAC_DB_RESPONSE_NOT_FULL },
+ { AAC_HOST_HIGH_RESP_ENTRIES, 0 },
+ { AAC_ADAP_NORM_RESP_ENTRIES, AAC_DB_RESPONSE_READY },
+ { AAC_ADAP_HIGH_RESP_ENTRIES, 0 }
+};
+
+/*
+ * Atomically insert an entry into the nominated queue, returns 0 on success
+ * or EBUSY if the queue is full.
+ *
+ * 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).
+ */
+int
+aac_enqueue_fib(struct aac_softc *sc, int queue, struct aac_command *cm)
+{
+ u_int32_t pi, ci;
+ int error;
+ u_int32_t fib_size;
+ u_int32_t fib_addr;
+
+ fib_size = cm->cm_fib->Header.Size;
+ fib_addr = cm->cm_fib->Header.ReceiverFibAddress;
+
+ /* get the producer/consumer indices */
+ pi = sc->aac_queues->qt_qindex[queue][AAC_PRODUCER_INDEX];
+ ci = sc->aac_queues->qt_qindex[queue][AAC_CONSUMER_INDEX];
+
+ /* wrap the queue? */
+ if (pi >= aac_qinfo[queue].size)
+ pi = 0;
+
+ /* check for queue full */
+ if ((pi + 1) == ci) {
+ error = EBUSY;
+ goto out;
}
+ /* populate queue entry */
+ (sc->aac_qentries[queue] + pi)->aq_fib_size = fib_size;
+ (sc->aac_qentries[queue] + pi)->aq_fib_addr = fib_addr;
+
+ /* update producer index */
+ sc->aac_queues->qt_qindex[queue][AAC_PRODUCER_INDEX] = pi + 1;
+
/*
- * Give the FIB to the controller, wait for a response.
+ * To avoid a race with its completion interrupt, place this command on
+ * the busy queue prior to advertising it to the controller.
*/
- if (aac_sync_command(sc, AAC_MONKER_SYNCFIB,
- fib->Header.ReceiverFibAddress, 0, 0, 0, NULL)) {
- return (EIO);
+ aac_enqueue_busy(cm);
+
+ /* notify the adapter if we know how */
+ if (aac_qinfo[queue].notify != 0)
+ AAC_QNOTIFY(sc, aac_qinfo[queue].notify);
+
+ error = 0;
+
+out:
+ return (error);
+}
+
+/*
+ * Atomically remove one entry from the nominated queue, returns 0 on success
+ * or ENOENT if the queue is empty.
+ */
+int
+aac_dequeue_fib(struct aac_softc *sc, int queue, u_int32_t *fib_size,
+ struct aac_fib **fib_addr)
+{
+ u_int32_t pi, ci;
+ u_int32_t fib_index;
+ int notify;
+ int error;
+
+ /* get the producer/consumer indices */
+ pi = sc->aac_queues->qt_qindex[queue][AAC_PRODUCER_INDEX];
+ ci = sc->aac_queues->qt_qindex[queue][AAC_CONSUMER_INDEX];
+
+ /* check for queue empty */
+ if (ci == pi) {
+ error = ENOENT;
+ goto out;
}
- /*
- * Copy out the result
- */
- if (result != NULL) {
- *resultsize = fib->Header.Size - sizeof fib->Header;
- bcopy(fib->data, result, *resultsize);
+ /* wrap the pi so the following test works */
+ if (pi >= aac_qinfo[queue].size)
+ pi = 0;
+
+ notify = 0;
+ if (ci == pi + 1)
+ notify++;
+
+ /* wrap the queue? */
+ if (ci >= aac_qinfo[queue].size)
+ ci = 0;
+
+ /* fetch the entry */
+ *fib_size = (sc->aac_qentries[queue] + ci)->aq_fib_size;
+
+ switch (queue) {
+ case AAC_HOST_NORM_CMD_QUEUE:
+ case AAC_HOST_HIGH_CMD_QUEUE:
+ /*
+ * The aq_fib_addr is only 32 bits wide so it can't be counted
+ * on to hold an address. For AIF's, the adapter assumes
+ * that it's giving us an address into the array of AIF fibs.
+ * Therefore, we have to convert it to an index.
+ */
+ fib_index = (sc->aac_qentries[queue] + ci)->aq_fib_addr /
+ sizeof(struct aac_fib);
+ *fib_addr = &sc->aac_common->ac_fibs[fib_index];
+ break;
+
+ case AAC_HOST_NORM_RESP_QUEUE:
+ case AAC_HOST_HIGH_RESP_QUEUE:
+ {
+ struct aac_command *cm;
+
+ /*
+ * As above, an index is used instead of an actual address.
+ * Gotta shift the index to account for the fast response
+ * bit. No other correction is needed since this value was
+ * originally provided by the driver via the SenderFibAddress
+ * field.
+ */
+ fib_index = (sc->aac_qentries[queue] + ci)->aq_fib_addr;
+ cm = sc->aac_commands + (fib_index >> 1);
+ *fib_addr = cm->cm_fib;
+
+ /*
+ * Is this a fast response? If it is, update the fib fields in
+ * local memory since the whole fib isn't DMA'd back up.
+ */
+ if (fib_index & 0x01) {
+ (*fib_addr)->Header.XferState |= AAC_FIBSTATE_DONEADAP;
+ *((u_int32_t*)((*fib_addr)->data)) = AAC_ERROR_NORMAL;
+ }
+ break;
}
- return (0);
+ default:
+ panic("Invalid queue in aac_dequeue_fib()");
+ break;
+ }
+
+
+ /* update consumer index */
+ sc->aac_queues->qt_qindex[queue][AAC_CONSUMER_INDEX] = ci + 1;
+
+ /* if we have made the queue un-full, notify the adapter */
+ if (notify && (aac_qinfo[queue].notify != 0))
+ AAC_QNOTIFY(sc, aac_qinfo[queue].notify);
+ error = 0;
+
+out:
+ return (error);
+}
+
+/*
+ * Put our response to an Adapter Initialed Fib on the response queue
+ */
+int
+aac_enqueue_response(struct aac_softc *sc, int queue, struct aac_fib *fib)
+{
+ u_int32_t pi, ci;
+ int error;
+ u_int32_t fib_size;
+ u_int32_t fib_addr;
+
+ /* Tell the adapter where the FIB is */
+ fib_size = fib->Header.Size;
+ fib_addr = fib->Header.SenderFibAddress;
+ fib->Header.ReceiverFibAddress = fib_addr;
+
+ /* get the producer/consumer indices */
+ pi = sc->aac_queues->qt_qindex[queue][AAC_PRODUCER_INDEX];
+ ci = sc->aac_queues->qt_qindex[queue][AAC_CONSUMER_INDEX];
+
+ /* wrap the queue? */
+ if (pi >= aac_qinfo[queue].size)
+ pi = 0;
+
+ /* check for queue full */
+ if ((pi + 1) == ci) {
+ error = EBUSY;
+ goto out;
+ }
+
+ /* populate queue entry */
+ (sc->aac_qentries[queue] + pi)->aq_fib_size = fib_size;
+ (sc->aac_qentries[queue] + pi)->aq_fib_addr = fib_addr;
+
+ /* update producer index */
+ sc->aac_queues->qt_qindex[queue][AAC_PRODUCER_INDEX] = pi + 1;
+
+ /* notify the adapter if we know how */
+ if (aac_qinfo[queue].notify != 0)
+ AAC_QNOTIFY(sc, aac_qinfo[queue].notify);
+
+ error = 0;
+
+out:
+ return(error);
}
void
-aacminphys(bp)
- struct buf *bp;
+aac_command_timeout(struct aac_command *cm)
{
-#if 0
- u_int8_t *buf = bp->b_data;
- paddr_t pa;
- long off;
-#endif
+ struct aac_softc *sc = cm->cm_sc;
- AAC_DPRINTF(AAC_D_MISC, ("aacminphys(0x%x) ", bp));
+ printf("%s: COMMAND %p (flags=%#x) TIMEOUT AFTER %d SECONDS\n",
+ sc->aac_dev.dv_xname, cm, cm->cm_flags,
+ (int)(time_second - cm->cm_timestamp));
- minphys(bp);
+ if (cm->cm_flags & AAC_CMD_TIMEDOUT)
+ return;
+
+ cm->cm_flags |= AAC_CMD_TIMEDOUT;
+
+ AAC_PRINT_FIB(sc, cm->cm_fib);
+
+ if (cm->cm_flags & AAC_ON_AACQ_BIO) {
+ struct scsi_xfer *xs = cm->cm_private;
+ int s = splbio();
+ xs->error = XS_DRIVER_STUFFUP;
+ xs->flags |= ITSDONE;
+ scsi_done(xs);
+ splx(s);
+
+ aac_remove_bio(cm);
+ aac_unmap_command(cm);
+ }
}
+void
+aac_timeout(struct aac_softc *sc)
+{
+ struct aac_command *cm;
+ time_t deadline;
+
+ /*
+ * Traverse the busy command list and timeout any commands
+ * that are past their deadline.
+ */
+ deadline = time_second - AAC_CMD_TIMEOUT;
+ TAILQ_FOREACH(cm, &sc->aac_busy, cm_link) {
+ if (cm->cm_timestamp < deadline)
+ aac_command_timeout(cm);
+ }
+}
+
+/*
+ * Interface Function Vectors
+ */
+
/*
* Read the current firmware status word.
*/
int
-aac_sa_get_fwstatus(sc)
- struct aac_softc *sc;
+aac_sa_get_fwstatus(struct aac_softc *sc)
{
return (AAC_GETREG4(sc, AAC_SA_FWSTATUS));
}
int
-aac_rx_get_fwstatus(sc)
- struct aac_softc *sc;
+aac_rx_get_fwstatus(struct aac_softc *sc)
{
return (AAC_GETREG4(sc, AAC_RX_FWSTATUS));
}
+int
+aac_fa_get_fwstatus(struct aac_softc *sc)
+{
+ return (AAC_GETREG4(sc, AAC_FA_FWSTATUS));
+}
+
/*
* Notify the controller of a change in a given queue
*/
void
-aac_sa_qnotify(sc, qbit)
- struct aac_softc *sc;
- int qbit;
+aac_sa_qnotify(struct aac_softc *sc, int qbit)
{
AAC_SETREG2(sc, AAC_SA_DOORBELL1_SET, qbit);
}
void
-aac_rx_qnotify(sc, qbit)
- struct aac_softc *sc;
- int qbit;
+aac_rx_qnotify(struct aac_softc *sc, int qbit)
{
AAC_SETREG4(sc, AAC_RX_IDBR, qbit);
}
+void
+aac_fa_qnotify(struct aac_softc *sc, int qbit)
+{
+ AAC_SETREG2(sc, AAC_FA_DOORBELL1, qbit);
+ AAC_FA_HACK(sc);
+}
+
/*
* Get the interrupt reason bits
*/
int
-aac_sa_get_istatus(sc)
- struct aac_softc *sc;
+aac_sa_get_istatus(struct aac_softc *sc)
{
return (AAC_GETREG2(sc, AAC_SA_DOORBELL0));
}
int
-aac_rx_get_istatus(sc)
- struct aac_softc *sc;
+aac_rx_get_istatus(struct aac_softc *sc)
{
return (AAC_GETREG4(sc, AAC_RX_ODBR));
}
+int
+aac_fa_get_istatus(struct aac_softc *sc)
+{
+ return (AAC_GETREG2(sc, AAC_FA_DOORBELL0));
+}
+
/*
* Clear some interrupt reason bits
*/
void
-aac_sa_clear_istatus(sc, mask)
- struct aac_softc *sc;
- int mask;
+aac_sa_clear_istatus(struct aac_softc *sc, int mask)
{
AAC_SETREG2(sc, AAC_SA_DOORBELL0_CLEAR, mask);
}
void
-aac_rx_clear_istatus(sc, mask)
- struct aac_softc *sc;
- int mask;
+aac_rx_clear_istatus(struct aac_softc *sc, int mask)
{
AAC_SETREG4(sc, AAC_RX_ODBR, mask);
}
+void
+aac_fa_clear_istatus(struct aac_softc *sc, int mask)
+{
+ AAC_SETREG2(sc, AAC_FA_DOORBELL0_CLEAR, mask);
+ AAC_FA_HACK(sc);
+}
+
/*
* Populate the mailbox and set the command word
*/
void
-aac_sa_set_mailbox(sc, command, arg0, arg1, arg2, arg3)
- struct aac_softc *sc;
- u_int32_t command;
- u_int32_t arg0;
- u_int32_t arg1;
- u_int32_t arg2;
- u_int32_t arg3;
+aac_sa_set_mailbox(struct aac_softc *sc, u_int32_t command, u_int32_t arg0,
+ u_int32_t arg1, u_int32_t arg2, u_int32_t arg3)
{
AAC_SETREG4(sc, AAC_SA_MAILBOX, command);
AAC_SETREG4(sc, AAC_SA_MAILBOX + 4, arg0);
@@ -1284,13 +2213,8 @@ aac_sa_set_mailbox(sc, command, arg0, arg1, arg2, arg3)
}
void
-aac_rx_set_mailbox(sc, command, arg0, arg1, arg2, arg3)
- struct aac_softc *sc;
- u_int32_t command;
- u_int32_t arg0;
- u_int32_t arg1;
- u_int32_t arg2;
- u_int32_t arg3;
+aac_rx_set_mailbox(struct aac_softc *sc, u_int32_t command, u_int32_t arg0,
+ u_int32_t arg1, u_int32_t arg2, u_int32_t arg3)
{
AAC_SETREG4(sc, AAC_RX_MAILBOX, command);
AAC_SETREG4(sc, AAC_RX_MAILBOX + 4, arg0);
@@ -1299,31 +2223,52 @@ aac_rx_set_mailbox(sc, command, arg0, arg1, arg2, arg3)
AAC_SETREG4(sc, AAC_RX_MAILBOX + 16, arg3);
}
+void
+aac_fa_set_mailbox(struct aac_softc *sc, u_int32_t command, u_int32_t arg0,
+ u_int32_t arg1, u_int32_t arg2, u_int32_t arg3)
+{
+ AAC_SETREG4(sc, AAC_FA_MAILBOX, command);
+ AAC_FA_HACK(sc);
+ AAC_SETREG4(sc, AAC_FA_MAILBOX + 4, arg0);
+ AAC_FA_HACK(sc);
+ AAC_SETREG4(sc, AAC_FA_MAILBOX + 8, arg1);
+ AAC_FA_HACK(sc);
+ AAC_SETREG4(sc, AAC_FA_MAILBOX + 12, arg2);
+ AAC_FA_HACK(sc);
+ AAC_SETREG4(sc, AAC_FA_MAILBOX + 16, arg3);
+ AAC_FA_HACK(sc);
+}
+
/*
* Fetch the immediate command status word
*/
int
-aac_sa_get_mailboxstatus(sc)
- struct aac_softc *sc;
+aac_sa_get_mailbox(struct aac_softc *sc, int mb)
{
- return (AAC_GETREG4(sc, AAC_SA_MAILBOX));
+ return (AAC_GETREG4(sc, AAC_SA_MAILBOX + (mb * 4)));
}
int
-aac_rx_get_mailboxstatus(sc)
- struct aac_softc *sc;
+aac_rx_get_mailbox(struct aac_softc *sc, int mb)
{
- return (AAC_GETREG4(sc, AAC_RX_MAILBOX));
+ return (AAC_GETREG4(sc, AAC_RX_MAILBOX + (mb * 4)));
+}
+
+int
+aac_fa_get_mailbox(struct aac_softc *sc, int mb)
+{
+ return (AAC_GETREG4(sc, AAC_FA_MAILBOX + (mb * 4)));
}
/*
* Set/clear interrupt masks
*/
void
-aac_sa_set_interrupts(sc, enable)
- struct aac_softc *sc;
- int enable;
+aac_sa_set_interrupts(struct aac_softc *sc, int enable)
{
+ AAC_DPRINTF(AAC_D_INTR, ("%s: %sable interrupts\n",
+ sc->aac_dev.dv_xname, enable ? "en" : "dis"));
+
if (enable)
AAC_SETREG2((sc), AAC_SA_MASK0_CLEAR, AAC_DB_INTERRUPTS);
else
@@ -1331,506 +2276,431 @@ aac_sa_set_interrupts(sc, enable)
}
void
-aac_rx_set_interrupts(sc, enable)
- struct aac_softc *sc;
- int enable;
+aac_rx_set_interrupts(struct aac_softc *sc, int enable)
{
+ AAC_DPRINTF(AAC_D_INTR, ("%s: %sable interrupts",
+ sc->aac_dev.dv_xname, enable ? "en" : "dis"));
+
if (enable)
AAC_SETREG4(sc, AAC_RX_OIMR, ~AAC_DB_INTERRUPTS);
else
AAC_SETREG4(sc, AAC_RX_OIMR, ~0);
}
-struct aac_ccb *
-aac_get_ccb(sc, flags)
- struct aac_softc *sc;
- int flags;
-{
- struct aac_ccb *ccb;
- aac_lock_t lock;
-
- AAC_DPRINTF(AAC_D_QUEUE, ("aac_get_ccb(%p, 0x%x) ", sc, flags));
-
- lock = AAC_LOCK(sc);
-
- for (;;) {
- ccb = TAILQ_FIRST(&sc->sc_free_ccb);
- if (ccb != NULL)
- break;
- if (flags & SCSI_NOSLEEP)
- goto bail_out;
- tsleep(&sc->sc_free_ccb, PRIBIO, "aac_ccb", 0);
- }
-
- TAILQ_REMOVE(&sc->sc_free_ccb, ccb, ac_chain);
-
- /* initialise the command/FIB */
- ccb->ac_sgtable = NULL;
- ccb->ac_flags = 0;
- ccb->ac_fib->Header.XferState = AAC_FIBSTATE_EMPTY;
- ccb->ac_fib->Header.StructType = AAC_FIBTYPE_TFIB;
- ccb->ac_fib->Header.Flags = 0;
- ccb->ac_fib->Header.SenderSize = sizeof(struct aac_fib);
-
- /*
- * These are duplicated in aac_start to cover the case where an
- * intermediate stage may have destroyed them. They're left
- * initialised here for debugging purposes only.
- */
- ccb->ac_fib->Header.SenderFibAddress = (u_int32_t)ccb->ac_fib;
- ccb->ac_fib->Header.ReceiverFibAddress = ccb->ac_fibphys;
-
- bail_out:
- AAC_UNLOCK(sc, lock);
- return (ccb);
-}
-
void
-aac_free_ccb(sc, ccb)
- struct aac_softc *sc;
- struct aac_ccb *ccb;
+aac_fa_set_interrupts(struct aac_softc *sc, int enable)
{
- aac_lock_t lock;
-
- AAC_DPRINTF(AAC_D_QUEUE, ("aac_free_ccb(%p, %p) ", sc, ccb));
+ AAC_DPRINTF(AAC_D_INTR, ("%s: %sable interrupts",
+ sc->aac_dev.dv_xname, enable ? "en" : "dis"));
- lock = AAC_LOCK(sc);
-
- TAILQ_INSERT_HEAD(&sc->sc_free_ccb, ccb, ac_chain);
-
- /* If the free list was empty, wake up potential waiters. */
- if (TAILQ_NEXT(ccb, ac_chain) == NULL)
- wakeup(&sc->sc_free_ccb);
-
- AAC_UNLOCK(sc, lock);
+ if (enable) {
+ AAC_SETREG2((sc), AAC_FA_MASK0_CLEAR, AAC_DB_INTERRUPTS);
+ AAC_FA_HACK(sc);
+ } else {
+ AAC_SETREG2((sc), AAC_FA_MASK0, ~0);
+ AAC_FA_HACK(sc);
+ }
}
void
-aac_enqueue_ccb(sc, ccb)
- struct aac_softc *sc;
- struct aac_ccb *ccb;
+aac_eval_mapping(size, cyls, heads, secs)
+ u_int32_t size;
+ int *cyls, *heads, *secs;
{
- AAC_DPRINTF(AAC_D_QUEUE, ("aac_enqueue_ccb(%p, %p) ", sc, ccb));
-
- timeout_set(&ccb->ac_xs->stimeout, aac_timeout, ccb);
- TAILQ_INSERT_TAIL(&sc->sc_ccbq, ccb, ac_chain);
- aac_start_ccbs(sc);
+ *cyls = size / AAC_HEADS / AAC_SECS;
+ if (*cyls < AAC_MAXCYLS) {
+ *heads = AAC_HEADS;
+ *secs = AAC_SECS;
+ } else {
+ /* Too high for 64 * 32 */
+ *cyls = size / AAC_MEDHEADS / AAC_MEDSECS;
+ if (*cyls < AAC_MAXCYLS) {
+ *heads = AAC_MEDHEADS;
+ *secs = AAC_MEDSECS;
+ } else {
+ /* Too high for 127 * 63 */
+ *cyls = size / AAC_BIGHEADS / AAC_BIGSECS;
+ *heads = AAC_BIGHEADS;
+ *secs = AAC_BIGSECS;
+ }
+ }
}
void
-aac_start_ccbs(sc)
- struct aac_softc *sc;
+aac_copy_internal_data(struct scsi_xfer *xs, u_int8_t *data, size_t size)
{
- struct aac_ccb *ccb;
- struct scsi_xfer *xs;
-
- AAC_DPRINTF(AAC_D_QUEUE, ("aac_start_ccbs(%p) ", sc));
-
- while ((ccb = TAILQ_FIRST(&sc->sc_ccbq)) != NULL) {
-
- xs = ccb->ac_xs;
- if (ccb->ac_flags & AAC_ACF_WATCHDOG)
- timeout_del(&xs->stimeout);
+ struct aac_softc *sc = xs->sc_link->adapter_softc;
+ size_t copy_cnt;
- if (aac_exec_ccb(ccb) == 0) {
- ccb->ac_flags |= AAC_ACF_WATCHDOG;
- timeout_set(&ccb->ac_xs->stimeout, aac_watchdog, ccb);
- timeout_add(&xs->stimeout,
- (AAC_WATCH_TIMEOUT * hz) / 1000);
- break;
- }
- TAILQ_REMOVE(&sc->sc_ccbq, ccb, ac_chain);
+ AAC_DPRINTF(AAC_D_MISC, ("%s: aac_copy_internal_data\n",
+ sc->aac_dev.dv_xname));
- if ((xs->flags & SCSI_POLL) == 0) {
- timeout_set(&ccb->ac_xs->stimeout, aac_timeout, ccb);
- timeout_add(&xs->stimeout,
- (ccb->ac_timeout * hz) / 1000);
- }
+ if (!xs->datalen)
+ printf("%s: uio move not yet supported\n",
+ sc->aac_dev.dv_xname);
+ else {
+ copy_cnt = MIN(size, xs->datalen);
+ bcopy(data, xs->data, copy_cnt);
}
}
+/* Emulated SCSI operation on cache device */
int
-aac_exec_ccb(ccb)
- struct aac_ccb *ccb;
+aac_internal_cache_cmd(struct scsi_xfer *xs)
{
- struct scsi_xfer *xs = ccb->ac_xs;
struct scsi_link *link = xs->sc_link;
+ struct aac_softc *sc = link->adapter_softc;
+ struct scsi_inquiry_data inq;
+ struct scsi_sense_data sd;
+ struct scsi_read_cap_data rcd;
u_int8_t target = link->target;
- int i;
- struct aac_fib *fib;
- struct aac_blockread *br;
- struct aac_blockwrite *bw;
- bus_dmamap_t xfer;
- AAC_DPRINTF(AAC_D_CMD, ("aac_exec_ccb(%p, %p) ", xs, ccb));
-
- /* build the FIB */
- fib = ccb->ac_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);
+ AAC_DPRINTF(AAC_D_CMD, ("aac_internal_cache_cmd: ",
+ sc->aac_dev.dv_xname));
switch (xs->cmd->opcode) {
- case PREVENT_ALLOW:
- case SYNCHRONIZE_CACHE:
- if (xs->cmd->opcode == PREVENT_ALLOW) {
- /* XXX PREVENT_ALLOW support goes here */
- } else {
- AAC_DPRINTF(AAC_D_CMD,
- ("SYNCHRONIZE CACHE tgt %d ", target));
- }
+ case TEST_UNIT_READY:
+ case START_STOP:
+#if 0
+ case VERIFY:
+#endif
+ AAC_DPRINTF(AAC_D_CMD, ("opc %#x tgt %d ", xs->cmd->opcode,
+ target));
break;
- case WRITE_COMMAND:
- case WRITE_BIG:
- bw = (struct aac_blockwrite *)&fib->data[0];
- bw->Command = VM_CtBlockWrite;
- bw->ContainerId = target;
- bw->BlockNumber = ccb->ac_blockno;
- bw->ByteCount = ccb->ac_blockcnt * DEV_BSIZE;
- bw->Stable = CUNSTABLE; /* XXX what's appropriate here? */
- fib->Header.Size += sizeof(struct aac_blockwrite);
- ccb->ac_sgtable = &bw->SgMap;
+ case REQUEST_SENSE:
+ AAC_DPRINTF(AAC_D_CMD, ("REQUEST SENSE tgt %d ", target));
+ bzero(&sd, sizeof sd);
+ sd.error_code = 0x70;
+ sd.segment = 0;
+ sd.flags = SKEY_NO_SENSE;
+ aac_enc32(sd.info, 0);
+ sd.extra_len = 0;
+ aac_copy_internal_data(xs, (u_int8_t *)&sd, sizeof sd);
break;
- case READ_COMMAND:
- case READ_BIG:
- br = (struct aac_blockread *)&fib->data[0];
- br->Command = VM_CtBlockRead;
- br->ContainerId = target;
- br->BlockNumber = ccb->ac_blockno;
- br->ByteCount = ccb->ac_blockcnt * DEV_BSIZE;
- fib->Header.Size += sizeof(struct aac_blockread);
- ccb->ac_sgtable = &br->SgMap;
+ case INQUIRY:
+ AAC_DPRINTF(AAC_D_CMD, ("INQUIRY tgt %d devtype %x ", target,
+ sc->aac_hdr[target].hd_devtype));
+ bzero(&inq, sizeof inq);
+ /* XXX How do we detect removable/CD-ROM devices? */
+ inq.device = T_DIRECT;
+ inq.dev_qual2 = 0;
+ inq.version = 2;
+ inq.response_format = 2;
+ inq.additional_length = 32;
+ strlcpy(inq.vendor, "Adaptec", sizeof inq.vendor);
+ snprintf(inq.product, sizeof inq.product, "Container #%02d",
+ target);
+ strlcpy(inq.revision, " ", sizeof inq.revision);
+ aac_copy_internal_data(xs, (u_int8_t *)&inq, sizeof inq);
break;
- }
- if (xs->cmd->opcode != PREVENT_ALLOW &&
- xs->cmd->opcode != SYNCHRONIZE_CACHE) {
- xfer = ccb->ac_dmamap_xfer;
- ccb->ac_sgtable->SgCount = xfer->dm_nsegs;
- for (i = 0; i < xfer->dm_nsegs; i++) {
- ccb->ac_sgtable->SgEntry[i].SgAddress =
- xfer->dm_segs[i].ds_addr;
- ccb->ac_sgtable->SgEntry[i].SgByteCount =
- xfer->dm_segs[i].ds_len;
- AAC_DPRINTF(AAC_D_IO,
- ("#%d va %p pa %p len %x\n", i, buf,
- xfer->dm_segs[i].ds_addr,
- xfer->dm_segs[i].ds_len));
- }
+ case READ_CAPACITY:
+ AAC_DPRINTF(AAC_D_CMD, ("READ CAPACITY tgt %d ", target));
+ bzero(&rcd, sizeof rcd);
+ _lto4b(sc->aac_hdr[target].hd_size - 1, rcd.addr);
+ _lto4b(AAC_BLOCK_SIZE, rcd.length);
+ aac_copy_internal_data(xs, (u_int8_t *)&rcd, sizeof rcd);
+ break;
- /* update the FIB size for the s/g count */
- fib->Header.Size += xfer->dm_nsegs *
- sizeof(struct aac_sg_entry);
+ default:
+ AAC_DPRINTF(AAC_D_CMD, ("\n"));
+ printf("aac_internal_cache_cmd got bad opcode: %#x\n",
+ xs->cmd->opcode);
+ xs->error = XS_DRIVER_STUFFUP;
+ return (0);
}
- if (aac_start(ccb) == 0) {
- xs->error = XS_NOERROR;
- xs->resid = 0;
- return (1);
- }
- return (0);
+ xs->error = XS_NOERROR;
+ return (1);
}
-/********************************************************************************
- * Deliver a command to the controller; allocate controller resources at the
- * last moment when possible.
- */
-int
-aac_start(struct aac_ccb *ccb)
+void
+aacminphys(struct buf *bp)
{
- struct aac_softc *sc = ccb->ac_xs->sc_link->adapter_softc;
-
#if 0
- /* get the command mapped */
- aac_map_command(ccb);
+ u_int8_t *buf = bp->b_data;
+ paddr_t pa;
+ long off;
#endif
- /* fix up the address values */
- ccb->ac_fib->Header.SenderFibAddress = (u_int32_t)ccb->ac_fib;
- ccb->ac_fib->Header.ReceiverFibAddress = ccb->ac_fibphys;
-
- /* save a pointer to the command for speedy reverse-lookup */
- ccb->ac_fib->Header.SenderData = (u_int32_t)ccb; /* XXX ack, sizing */
+ AAC_DPRINTF(AAC_D_MISC, ("aacminphys(0x%x)\n", bp));
- /* put the FIB on the outbound queue */
- if (aac_enqueue_fib(sc, AAC_ADAP_NORM_CMD_QUEUE, ccb))
- return (EBUSY);
+#if 0 /* As this is way more than MAXPHYS it's really not necessary. */
+ if (bp->b_bcount > ((AAC_MAXOFFSETS - 1) * PAGE_SIZE))
+ bp->b_bcount = ((AAC_MAXOFFSETS - 1) * PAGE_SIZE);
+#endif
- return (0);
+#if 0
+ for (off = PAGE_SIZE, pa = vtophys(buf); off < bp->b_bcount;
+ off += PAGE_SIZE)
+ if (pa + off != vtophys(buf + off)) {
+ bp->b_bcount = off;
+ break;
+ }
+#endif
+ minphys(bp);
}
-/*
- * Map a command into controller-visible space.
- */
int
-aac_map_command(struct aac_ccb *ccb)
+aac_raw_scsi_cmd(struct scsi_xfer *xs)
{
- struct scsi_xfer *xs = ccb->ac_xs;
+#ifdef AAC_DEBUG
struct aac_softc *sc = xs->sc_link->adapter_softc;
- int error;
-
-#if 0
- /* don't map more than once */
- if (ccb->ac_flags & AAC_CMD_MAPPED)
- return;
#endif
+ AAC_DPRINTF(AAC_D_CMD, ("%s: aac_raw_scsi_cmd\n",
+ sc->aac_dev.dv_xname));
- if (xs->datalen != 0) {
- error = bus_dmamap_load(sc->sc_dmat, ccb->ac_dmamap_xfer,
- xs->data, xs->datalen, NULL,
- (xs->flags & SCSI_NOSLEEP) ? BUS_DMA_NOWAIT :
- BUS_DMA_WAITOK);
- if (error) {
- printf("%s: aac_scsi_cmd: ", sc->sc_dev.dv_xname);
- if (error == EFBIG)
- printf("more than %d dma segs\n",
- AAC_MAXSGENTRIES);
- else
- printf("error %d loading dma map\n", error);
- return (error);
- }
-
- bus_dmamap_sync(sc->sc_dmat, ccb->ac_dmamap_xfer, 0,
- ccb->ac_dmamap_xfer->dm_mapsize,
- (xs->flags & SCSI_DATA_IN) ? BUS_DMASYNC_PREREAD :
- BUS_DMASYNC_PREWRITE);
- }
-
-#if 0
- ccb->ac_flags |= AAC_CMD_MAPPED;
-#endif
- return (0);
+ /* XXX Not yet implemented */
+ xs->error = XS_DRIVER_STUFFUP;
+ return (COMPLETE);
}
-/*
- * Unmap a command from controller-visible space.
- */
-void
-aac_unmap_command(struct aac_ccb *ccb)
+int
+aac_scsi_cmd(struct scsi_xfer *xs)
{
- struct scsi_xfer *xs = ccb->ac_xs;
- struct aac_softc *sc = xs->sc_link->adapter_softc;
-
-#if 0
- if (!(ccb->ac_flags & AAC_CMD_MAPPED))
- return;
-#endif
+ struct scsi_link *link = xs->sc_link;
+ struct aac_softc *sc = link->adapter_softc;
+ u_int8_t target = link->target;
+ struct aac_command *cm;
+ u_int32_t blockno, blockcnt;
+ struct scsi_rw *rw;
+ struct scsi_rw_big *rwb;
+ int retval = SUCCESSFULLY_QUEUED;
+ int s = splbio();
- if (xs->datalen != 0) {
- bus_dmamap_sync(sc->sc_dmat, ccb->ac_dmamap_xfer, 0,
- ccb->ac_dmamap_xfer->dm_mapsize,
- (xs->flags & SCSI_DATA_IN) ? BUS_DMASYNC_POSTREAD :
- BUS_DMASYNC_POSTWRITE);
+ xs->error = XS_NOERROR;
- bus_dmamap_unload(sc->sc_dmat, ccb->ac_dmamap_xfer);
+ if (target >= AAC_MAX_CONTAINERS || !sc->aac_hdr[target].hd_present ||
+ link->lun != 0) {
+ /*
+ * XXX Should be XS_SENSE but that would require setting up a
+ * faked sense too.
+ */
+ xs->error = XS_DRIVER_STUFFUP;
+ xs->flags |= ITSDONE;
+ scsi_done(xs);
+ splx(s);
+ return (COMPLETE);
}
+
+ AAC_DPRINTF(AAC_D_CMD, ("%s: aac_scsi_cmd: ", sc->aac_dev.dv_xname));
+
+ xs->error = XS_NOERROR;
+ cm = NULL;
+ link = xs->sc_link;
+ target = link->target;
+
+ switch (xs->cmd->opcode) {
+ case TEST_UNIT_READY:
+ case REQUEST_SENSE:
+ case INQUIRY:
+ case START_STOP:
+ case READ_CAPACITY:
#if 0
- ccb->ac_flags &= ~AAC_CMD_MAPPED;
+ case VERIFY:
#endif
-}
+ if (!aac_internal_cache_cmd(xs)) {
+ splx(s);
+ return (TRY_AGAIN_LATER);
+ }
+ xs->flags |= ITSDONE;
+ scsi_done(xs);
+ goto ready;
-void
-aac_timeout(arg)
- void *arg;
-{
- struct aac_ccb *ccb = arg;
- struct scsi_link *link = ccb->ac_xs->sc_link;
- struct aac_softc *sc = link->adapter_softc;
- aac_lock_t lock;
+ case PREVENT_ALLOW:
+ AAC_DPRINTF(AAC_D_CMD, ("PREVENT/ALLOW "));
+ /* XXX Not yet implemented */
+ xs->error = XS_NOERROR;
+ xs->flags |= ITSDONE;
+ scsi_done(xs);
+ goto ready;
- sc_print_addr(link);
- printf("timed out\n");
+ case SYNCHRONIZE_CACHE:
+ AAC_DPRINTF(AAC_D_CMD, ("SYNCHRONIZE_CACHE "));
+ /* XXX Not yet implemented */
+ xs->error = XS_NOERROR;
+ xs->flags |= ITSDONE;
+ scsi_done(xs);
+ goto ready;
- /* XXX Test for multiple timeouts */
+ default:
+ AAC_DPRINTF(AAC_D_CMD, ("unknown opc %#x ", xs->cmd->opcode));
+ /* XXX Not yet implemented */
+ xs->error = XS_DRIVER_STUFFUP;
+ xs->flags |= ITSDONE;
+ scsi_done(xs);
+ goto ready;
- ccb->ac_xs->error = XS_TIMEOUT;
- lock = AAC_LOCK(sc);
- aac_enqueue_ccb(sc, ccb);
- AAC_UNLOCK(sc, lock);
-}
+ case READ_COMMAND:
+ case READ_BIG:
+ case WRITE_COMMAND:
+ case WRITE_BIG:
+ AAC_DPRINTF(AAC_D_CMD, ("rw opc %#x ", xs->cmd->opcode));
+
+ /* A read or write operation. */
+ if (xs->cmdlen == 6) {
+ rw = (struct scsi_rw *)xs->cmd;
+ blockno = _3btol(rw->addr) &
+ (SRW_TOPADDR << 16 | 0xffff);
+ blockcnt = rw->length ? rw->length : 0x100;
+ } else {
+ rwb = (struct scsi_rw_big *)xs->cmd;
+ blockno = _4btol(rwb->addr);
+ blockcnt = _2btol(rwb->length);
+ }
-void
-aac_watchdog(arg)
- void *arg;
-{
- struct aac_ccb *ccb = arg;
- struct scsi_link *link = ccb->ac_xs->sc_link;
- struct aac_softc *sc = link->adapter_softc;
- aac_lock_t lock;
+ AAC_DPRINTF(AAC_D_CMD, ("blkno=%d bcount=%d ",
+ xs->cmd->opcode, blockno, blockcnt));
- lock = AAC_LOCK(sc);
- ccb->ac_flags &= ~AAC_ACF_WATCHDOG;
- aac_start_ccbs(sc);
- AAC_UNLOCK(sc, lock);
-}
-/*
- * Insert a command into the driver queue, either at the front or at the tail.
- * It's ok to overload the freelist link as these structures are never on
- * the freelist at this time.
- */
-void
-aac_enqueue(sc, xs, infront)
- struct aac_softc *sc;
- struct scsi_xfer *xs;
- int infront;
-{
- if (infront || LIST_FIRST(&sc->sc_queue) == NULL) {
- if (LIST_FIRST(&sc->sc_queue) == NULL)
- sc->sc_queuelast = xs;
- LIST_INSERT_HEAD(&sc->sc_queue, xs, free_list);
- return;
- }
- LIST_INSERT_AFTER(sc->sc_queuelast, xs, free_list);
- sc->sc_queuelast = xs;
-}
+ if (blockno >= sc->aac_hdr[target].hd_size ||
+ blockno + blockcnt > sc->aac_hdr[target].hd_size) {
+ AAC_DPRINTF(AAC_D_CMD, ("\n"));
+ printf("%s: out of bounds %u-%u >= %u\n",
+ sc->aac_dev.dv_xname, blockno,
+ blockcnt, sc->aac_hdr[target].hd_size);
+ /*
+ * XXX Should be XS_SENSE but that
+ * would require setting up a faked
+ * sense too.
+ */
+ xs->error = XS_DRIVER_STUFFUP;
+ xs->flags |= ITSDONE;
+ scsi_done(xs);
+ goto ready;
+ }
-/*
- * Pull a command off the front of the driver queue.
- */
-struct scsi_xfer *
-aac_dequeue(sc)
- struct aac_softc *sc;
-{
- struct scsi_xfer *xs;
+ if (aac_alloc_command(sc, &cm)) {
+ AAC_DPRINTF(AAC_D_CMD,
+ (": out of commands, try later\n"));
+ /*
+ * We are out of commands, try again
+ * in a little while.
+ */
+ xs->error = XS_DRIVER_STUFFUP;
+ splx(s);
+ return (TRY_AGAIN_LATER);
+ }
- xs = LIST_FIRST(&sc->sc_queue);
- if (xs == NULL)
- return (NULL);
- LIST_REMOVE(xs, free_list);
+ /* fill out the command */
+ cm->cm_data = (void *)xs->data;
+ cm->cm_datalen = xs->datalen;
+ cm->cm_complete = aac_bio_complete;
+ cm->cm_private = xs;
+ cm->cm_timestamp = time_second;
+ cm->cm_queue = AAC_ADAP_NORM_CMD_QUEUE;
+ cm->cm_blkno = blockno;
+ cm->cm_bcount = blockcnt;
+
+ AAC_DPRINTF(AAC_D_CMD, ("\n"));
+ aac_enqueue_bio(cm);
+ aac_startio(sc);
+
+ /* XXX what if enqueue did not start a transfer? */
+ if (xs->flags & SCSI_POLL) {
+ if (!aac_wait_command(cm, xs->timeout))
+ {
+ printf("%s: command timed out\n",
+ sc->aac_dev.dv_xname);
+ xs->error = XS_TIMEOUT;
+ splx(s);
+ return (TRY_AGAIN_LATER);
+ }
+ xs->flags |= ITSDONE;
+ scsi_done(xs);
+ }
+ }
- if (LIST_FIRST(&sc->sc_queue) == NULL)
- sc->sc_queuelast = NULL;
+ ready:
+ /*
+ * Don't process the queue if we are polling.
+ */
+ if (xs->flags & SCSI_POLL)
+ retval = COMPLETE;
- return (xs);
+ splx(s);
+ AAC_DPRINTF(AAC_D_CMD, ("%s: scsi_cmd complete\n",
+ sc->aac_dev.dv_xname));
+ return (retval);
}
-/********************************************************************************
- * Adapter-space FIB queue manipulation
- *
- * Note that the queue implementation here is a little funky; neither the PI or
- * CI will ever be zero. This behaviour is a controller feature.
+/*
+ * Debugging and Diagnostics
*/
-static struct {
- int size;
- int notify;
-} aac_qinfo[] = {
- { AAC_HOST_NORM_CMD_ENTRIES, AAC_DB_COMMAND_NOT_FULL },
- { AAC_HOST_HIGH_CMD_ENTRIES, 0 },
- { AAC_ADAP_NORM_CMD_ENTRIES, AAC_DB_COMMAND_READY },
- { AAC_ADAP_HIGH_CMD_ENTRIES, 0 },
- { AAC_HOST_NORM_RESP_ENTRIES, AAC_DB_RESPONSE_NOT_FULL },
- { AAC_HOST_HIGH_RESP_ENTRIES, 0 },
- { AAC_ADAP_NORM_RESP_ENTRIES, AAC_DB_RESPONSE_READY },
- { AAC_ADAP_HIGH_RESP_ENTRIES, 0 }
-};
/*
- * 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.
+ * Print some information about the controller.
*/
-int
-aac_enqueue_fib(struct aac_softc *sc, int queue, struct aac_ccb *ccb)
+void
+aac_describe_controller(struct aac_softc *sc)
{
- u_int32_t pi, ci;
- int error;
- aac_lock_t lock;
- u_int32_t fib_size;
- u_int32_t fib_addr;
-
- fib_size = ccb->ac_fib->Header.Size;
- fib_addr = ccb->ac_fib->Header.ReceiverFibAddress;
-
- lock = AAC_LOCK(sc);
-
- /* get the producer/consumer indices */
- pi = sc->sc_queues->qt_qindex[queue][AAC_PRODUCER_INDEX];
- ci = sc->sc_queues->qt_qindex[queue][AAC_CONSUMER_INDEX];
+ struct aac_fib *fib;
+ struct aac_adapter_info *info;
- /* wrap the queue? */
- if (pi >= aac_qinfo[queue].size)
- pi = 0;
+ aac_alloc_sync_fib(sc, &fib, 0);
- /* check for queue full */
- if ((pi + 1) == ci) {
- error = EBUSY;
- goto out;
+ fib->data[0] = 0;
+ if (aac_sync_fib(sc, RequestAdapterInfo, 0, fib, 1)) {
+ printf("%s: RequestAdapterInfo failed 2\n",
+ sc->aac_dev.dv_xname);
+ aac_release_sync_fib(sc);
+ return;
}
+ info = (struct aac_adapter_info *)&fib->data[0];
- /* populate queue entry */
- (sc->sc_qentries[queue] + pi)->aq_fib_size = fib_size;
- (sc->sc_qentries[queue] + pi)->aq_fib_addr = fib_addr;
+ printf("%s: %s %dMHz, %dMB cache memory, %s\n", sc->aac_dev.dv_xname,
+ aac_describe_code(aac_cpu_variant, info->CpuVariant),
+ info->ClockSpeed, info->BufferMem / (1024 * 1024),
+ aac_describe_code(aac_battery_platform, info->batteryPlatform));
- /* update producer index */
- sc->sc_queues->qt_qindex[queue][AAC_PRODUCER_INDEX] = pi + 1;
+ /* save the kernel revision structure for later use */
+ sc->aac_revision = info->KernelRevision;
+ printf("%s: Kernel %d.%d-%d, Build %d, S/N %6X\n",
+ sc->aac_dev.dv_xname,
+ info->KernelRevision.external.comp.major,
+ info->KernelRevision.external.comp.minor,
+ info->KernelRevision.external.comp.dash,
+ info->KernelRevision.buildNumber,
+ (u_int32_t)(info->SerialNumber & 0xffffff));
- /* notify the adapter if we know how */
- if (aac_qinfo[queue].notify != 0)
- AAC_QNOTIFY(sc, aac_qinfo[queue].notify);
+ aac_release_sync_fib(sc);
- error = 0;
-
-out:
- AAC_UNLOCK(sc, lock);
- return (error);
+#if 0
+ if (1 || bootverbose) {
+ device_printf(sc->aac_dev, "Supported Options=%b\n",
+ sc->supported_options,
+ "\20"
+ "\1SNAPSHOT"
+ "\2CLUSTERS"
+ "\3WCACHE"
+ "\4DATA64"
+ "\5HOSTTIME"
+ "\6RAID50"
+ "\7WINDOW4GB"
+ "\10SCSIUPGD"
+ "\11SOFTERR"
+ "\12NORECOND"
+ "\13SGMAP64"
+ "\14ALARM"
+ "\15NONDASD");
+ }
+#endif
}
/*
- * Atomically remove one entry from the nominated queue, returns 0 on success
- * or ENOENT if the queue is empty.
+ * Look up a text description of a numeric error code and return a pointer to
+ * same.
*/
-int
-aac_dequeue_fib(struct aac_softc *sc, int queue, u_int32_t *fib_size,
- struct aac_fib **fib_addr)
+char *
+aac_describe_code(struct aac_code_lookup *table, u_int32_t code)
{
- u_int32_t pi, ci;
- int notify;
- int error;
- aac_lock_t lock;
-
- lock = AAC_LOCK(sc);
-
- /* get the producer/consumer indices */
- pi = sc->sc_queues->qt_qindex[queue][AAC_PRODUCER_INDEX];
- ci = sc->sc_queues->qt_qindex[queue][AAC_CONSUMER_INDEX];
-
- /* check for queue empty */
- if (ci == pi) {
- error = ENOENT;
- goto out;
- }
-
- notify = 0;
- if (ci == pi + 1)
- notify++;
-
- /* wrap the queue? */
- if (ci >= aac_qinfo[queue].size)
- ci = 0;
-
- /* fetch the entry */
- *fib_size = (sc->sc_qentries[queue] + ci)->aq_fib_size;
- *fib_addr =
- (struct aac_fib *)(sc->sc_qentries[queue] + ci)->aq_fib_addr;
-
- /* update consumer index */
- sc->sc_queues->qt_qindex[queue][AAC_CONSUMER_INDEX] = ci + 1;
-
- /* if we have made the queue un-full, notify the adapter */
- if (notify && (aac_qinfo[queue].notify != 0))
- AAC_QNOTIFY(sc, aac_qinfo[queue].notify);
- error = 0;
+ int i;
-out:
- AAC_UNLOCK(sc, lock);
- return (error);
+ for (i = 0; table[i].string != NULL; i++)
+ if (table[i].code == code)
+ return(table[i].string);
+ return(table[i + 1].string);
}
#ifdef AAC_DEBUG
@@ -1904,4 +2774,286 @@ aac_print_fib(struct aac_softc *sc, struct aac_fib *fib, const char *caller)
break;
}
}
+
+/*
+ * Describe an AIF we have received.
+ */
+void
+aac_print_aif(struct aac_softc *sc, struct aac_aif_command *aif)
+{
+ printf("%s: print_aif: ", sc->aac_dev.dv_xname);
+
+ switch(aif->command) {
+ case AifCmdEventNotify:
+ printf("EventNotify(%d)\n", aif->seqNumber);
+
+ switch(aif->data.EN.type) {
+ case AifEnGeneric:
+ /* Generic notification */
+ printf("\t(Generic) %.*s\n",
+ (int)sizeof(aif->data.EN.data.EG),
+ aif->data.EN.data.EG.text);
+ break;
+ case AifEnTaskComplete:
+ /* Task has completed */
+ printf("\t(TaskComplete)\n");
+ break;
+ case AifEnConfigChange:
+ /* Adapter configuration change occurred */
+ printf("\t(ConfigChange)\n");
+ break;
+ case AifEnContainerChange:
+ /* Adapter specific container configuration change */
+ printf("\t(ContainerChange) container %d,%d\n",
+ aif->data.EN.data.ECC.container[0],
+ aif->data.EN.data.ECC.container[1]);
+ break;
+ case AifEnDeviceFailure:
+ /* SCSI device failed */
+ printf("\t(DeviceFailure) handle %d\n",
+ aif->data.EN.data.EDF.deviceHandle);
+ break;
+ case AifEnMirrorFailover:
+ /* Mirror failover started */
+ printf("\t(MirrorFailover) container %d failed, "
+ "migrating from slice %d to %d\n",
+ aif->data.EN.data.EMF.container,
+ aif->data.EN.data.EMF.failedSlice,
+ aif->data.EN.data.EMF.creatingSlice);
+ break;
+ case AifEnContainerEvent:
+ /* Significant container event */
+ printf("\t(ContainerEvent) container %d event %d\n",
+ aif->data.EN.data.ECE.container,
+ aif->data.EN.data.ECE.eventType);
+ break;
+ case AifEnFileSystemChange:
+ /* File system changed */
+ printf("\t(FileSystemChange)\n");
+ break;
+ case AifEnConfigPause:
+ /* Container pause event */
+ printf("\t(ConfigPause)\n");
+ break;
+ case AifEnConfigResume:
+ /* Container resume event */
+ printf("\t(ConfigResume)\n");
+ break;
+ case AifEnFailoverChange:
+ /* Failover space assignment changed */
+ printf("\t(FailoverChange)\n");
+ break;
+ case AifEnRAID5RebuildDone:
+ /* RAID5 rebuild finished */
+ printf("\t(RAID5RebuildDone)\n");
+ break;
+ case AifEnEnclosureManagement:
+ /* Enclosure management event */
+ printf("\t(EnclosureManagement) EMPID %d unit %d "
+ "event %d\n",
+ aif->data.EN.data.EEE.empID,
+ aif->data.EN.data.EEE.unitID,
+ aif->data.EN.data.EEE.eventType);
+ break;
+ case AifEnBatteryEvent:
+ /* Significant NV battery event */
+ printf("\t(BatteryEvent) %d (state was %d, is %d\n",
+ aif->data.EN.data.EBE.transition_type,
+ aif->data.EN.data.EBE.current_state,
+ aif->data.EN.data.EBE.prior_state);
+ break;
+ case AifEnAddContainer:
+ /* A new container was created. */
+ printf("\t(AddContainer)\n");
+ break;
+ case AifEnDeleteContainer:
+ /* A container was deleted. */
+ printf("\t(DeleteContainer)\n");
+ break;
+ case AifEnBatteryNeedsRecond:
+ /* The battery needs reconditioning */
+ printf("\t(BatteryNeedsRecond)\n");
+ break;
+ case AifEnClusterEvent:
+ /* Some cluster event */
+ printf("\t(ClusterEvent) event %d\n",
+ aif->data.EN.data.ECLE.eventType);
+ break;
+ case AifEnDiskSetEvent:
+ /* A disk set event occured. */
+ printf("(DiskSetEvent) event %d "
+ "diskset %lld creator %lld\n",
+ aif->data.EN.data.EDS.eventType,
+ aif->data.EN.data.EDS.DsNum,
+ aif->data.EN.data.EDS.CreatorId);
+ break;
+ case AifDenMorphComplete:
+ /* A morph operation completed */
+ printf("\t(MorphComplete)\n");
+ break;
+ case AifDenVolumeExtendComplete:
+ /* A volume expand operation completed */
+ printf("\t(VolumeExtendComplete)\n");
+ break;
+ default:
+ printf("\t(%d)\n", aif->data.EN.type);
+ break;
+ }
+ break;
+ case AifCmdJobProgress:
+ {
+ char *status;
+ switch(aif->data.PR[0].status) {
+ case AifJobStsSuccess:
+ status = "success"; break;
+ case AifJobStsFinished:
+ status = "finished"; break;
+ case AifJobStsAborted:
+ status = "aborted"; break;
+ case AifJobStsFailed:
+ status = "failed"; break;
+ case AifJobStsSuspended:
+ status = "suspended"; break;
+ case AifJobStsRunning:
+ status = "running"; break;
+ default:
+ status = "unknown status"; break;
+ }
+
+ printf("JobProgress (%d) - %s (%d, %d)\n",
+ aif->seqNumber, status,
+ aif->data.PR[0].currentTick,
+ aif->data.PR[0].finalTick);
+
+ switch(aif->data.PR[0].jd.type) {
+ case AifJobScsiZero:
+ /* SCSI dev clear operation */
+ printf("\t(ScsiZero) handle %d\n",
+ aif->data.PR[0].jd.client.scsi_dh);
+ break;
+ case AifJobScsiVerify:
+ /* SCSI device Verify operation NO REPAIR */
+ printf("\t(ScsiVerify) handle %d\n",
+ aif->data.PR[0].jd.client.scsi_dh);
+ break;
+ case AifJobScsiExercise:
+ /* SCSI device Exercise operation */
+ printf("\t(ScsiExercise) handle %d\n",
+ aif->data.PR[0].jd.client.scsi_dh);
+ break;
+ case AifJobScsiVerifyRepair:
+ /* SCSI device Verify operation WITH repair */
+ printf("\t(ScsiVerifyRepair) handle %d\n",
+ aif->data.PR[0].jd.client.scsi_dh);
+ break;
+ case AifJobCtrZero:
+ /* Container clear operation */
+ printf("\t(ConatainerZero) container %d\n",
+ aif->data.PR[0].jd.client.container.src);
+ break;
+ case AifJobCtrCopy:
+ /* Container copy operation */
+ printf("\t(ConatainerCopy) container %d to %d\n",
+ aif->data.PR[0].jd.client.container.src,
+ aif->data.PR[0].jd.client.container.dst);
+ break;
+ case AifJobCtrCreateMirror:
+ /* Container Create Mirror operation */
+ printf("\t(ConatainerCreateMirror) container %d\n",
+ aif->data.PR[0].jd.client.container.src);
+ /* XXX two containers? */
+ break;
+ case AifJobCtrMergeMirror:
+ /* Container Merge Mirror operation */
+ printf("\t(ConatainerMergeMirror) container %d\n",
+ aif->data.PR[0].jd.client.container.src);
+ /* XXX two containers? */
+ break;
+ case AifJobCtrScrubMirror:
+ /* Container Scrub Mirror operation */
+ printf("\t(ConatainerScrubMirror) container %d\n",
+ aif->data.PR[0].jd.client.container.src);
+ break;
+ case AifJobCtrRebuildRaid5:
+ /* Container Rebuild Raid5 operation */
+ printf("\t(ConatainerRebuildRaid5) container %d\n",
+ aif->data.PR[0].jd.client.container.src);
+ break;
+ case AifJobCtrScrubRaid5:
+ /* Container Scrub Raid5 operation */
+ printf("\t(ConatainerScrubRaid5) container %d\n",
+ aif->data.PR[0].jd.client.container.src);
+ break;
+ case AifJobCtrMorph:
+ /* Container morph operation */
+ printf("\t(ConatainerMorph) container %d\n",
+ aif->data.PR[0].jd.client.container.src);
+ /* XXX two containers? */
+ break;
+ case AifJobCtrPartCopy:
+ /* Container Partition copy operation */
+ printf("\t(ConatainerPartCopy) container %d to %d\n",
+ aif->data.PR[0].jd.client.container.src,
+ aif->data.PR[0].jd.client.container.dst);
+ break;
+ case AifJobCtrRebuildMirror:
+ /* Container Rebuild Mirror operation */
+ printf("\t(ConatainerRebuildMirror) container %d\n",
+ aif->data.PR[0].jd.client.container.src);
+ break;
+ case AifJobCtrCrazyCache:
+ /* crazy cache */
+ printf("\t(ConatainerCrazyCache) container %d\n",
+ aif->data.PR[0].jd.client.container.src);
+ /* XXX two containers? */
+ break;
+ case AifJobFsCreate:
+ /* File System Create operation */
+ printf("\t(FsCreate)\n");
+ break;
+ case AifJobFsVerify:
+ /* File System Verify operation */
+ printf("\t(FsVerivy)\n");
+ break;
+ case AifJobFsExtend:
+ /* File System Extend operation */
+ printf("\t(FsExtend)\n");
+ break;
+ case AifJobApiFormatNTFS:
+ /* Format a drive to NTFS */
+ printf("\t(FormatNTFS)\n");
+ break;
+ case AifJobApiFormatFAT:
+ /* Format a drive to FAT */
+ printf("\t(FormatFAT)\n");
+ break;
+ case AifJobApiUpdateSnapshot:
+ /* update the read/write half of a snapshot */
+ printf("\t(UpdateSnapshot)\n");
+ break;
+ case AifJobApiFormatFAT32:
+ /* Format a drive to FAT32 */
+ printf("\t(FormatFAT32)\n");
+ break;
+ case AifJobCtlContinuousCtrVerify:
+ /* Adapter operation */
+ printf("\t(ContinuousCtrVerify)\n");
+ break;
+ default:
+ printf("\t(%d)\n", aif->data.PR[0].jd.type);
+ break;
+ }
+ break;
+ }
+ case AifCmdAPIReport:
+ printf("APIReport (%d)\n", aif->seqNumber);
+ break;
+ case AifCmdDriverNotify:
+ printf("DriverNotify (%d)\n", aif->seqNumber);
+ break;
+ default:
+ printf("AIF %d (%d)\n", aif->command, aif->seqNumber);
+ break;
+ }
+}
#endif
diff --git a/sys/dev/ic/aac_tables.h b/sys/dev/ic/aac_tables.h
index c0fedc3ca60..3ba773425fd 100644
--- a/sys/dev/ic/aac_tables.h
+++ b/sys/dev/ic/aac_tables.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: aac_tables.h,v 1.2 2004/05/21 20:34:52 marco Exp $ */
+/* $OpenBSD: aac_tables.h,v 1.3 2005/11/18 05:39:10 nate Exp $ */
/*-
* Copyright (c) 2000 Michael Smith
@@ -83,7 +83,7 @@ static struct aac_code_lookup aac_cpu_variant[] = {
{ "i960HX", CPUI960_HX },
{ "i960RX", CPUI960_RX },
{ "StrongARM SA110", CPUARM_SA110 },
- { "PowerPC 603e", CPUPPC_603e },
+ { "MPC824x", CPUMPC_824x },
{ "Unknown StrongARM", CPUARM_xxx },
{ "Unknown PowerPC", CPUPPC_xxx },
{ "Intel GC80302 IOP", CPUI960_302},
diff --git a/sys/dev/ic/aacreg.h b/sys/dev/ic/aacreg.h
index 1a66fa1a28a..4557e1485e4 100644
--- a/sys/dev/ic/aacreg.h
+++ b/sys/dev/ic/aacreg.h
@@ -1,9 +1,10 @@
-/* $OpenBSD: aacreg.h,v 1.6 2004/05/21 20:34:52 marco Exp $ */
+/* $OpenBSD: aacreg.h,v 1.7 2005/11/18 05:39:10 nate Exp $ */
/*-
* Copyright (c) 2000 Michael Smith
- * Copyright (c) 2000 Scott Long
+ * Copyright (c) 2000-2001 Scott Long
* Copyright (c) 2000 BSDi
+ * Copyright (c) 2001 Adaptec, Inc.
* Copyright (c) 2000 Niklas Hallqvist
* All rights reserved.
*
@@ -28,7 +29,7 @@
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
- * $FreeBSD: /c/ncvs/src/sys/dev/aac/aacreg.h,v 1.1 2000/09/13 03:20:34 msmith Exp $
+ * $FreeBSD$
*/
/*
@@ -55,27 +56,37 @@
* We establish 4 command queues and matching response queues. Queues must
* be 16-byte aligned, and are sized as follows:
*/
-#define AAC_HOST_NORM_CMD_ENTRIES 8 /* cmd adapter->host, normal pri */
-#define AAC_HOST_HIGH_CMD_ENTRIES 4 /* cmd adapter->host, high pri */
-#define AAC_ADAP_NORM_CMD_ENTRIES 512 /* cmd host->adapter, normal pri */
-#define AAC_ADAP_HIGH_CMD_ENTRIES 4 /* cmd host->adapter, high pri */
-#define AAC_HOST_NORM_RESP_ENTRIES 512 /* resp, adapter->host, normal pri */
-#define AAC_HOST_HIGH_RESP_ENTRIES 4 /* resp, adapter->host, high pri */
-#define AAC_ADAP_NORM_RESP_ENTRIES 8 /* resp, host->adapter, normal pri */
-#define AAC_ADAP_HIGH_RESP_ENTRIES 4 /* resp, host->adapter, high pri */
-
-#define AAC_TOTALQ_LENGTH \
- (AAC_HOST_HIGH_CMD_ENTRIES + AAC_HOST_NORM_CMD_ENTRIES + \
- AAC_ADAP_HIGH_CMD_ENTRIES + AAC_ADAP_NORM_CMD_ENTRIES + \
- AAC_HOST_HIGH_RESP_ENTRIES + AAC_HOST_NORM_RESP_ENTRIES + \
- AAC_ADAP_HIGH_RESP_ENTRIES + AAC_ADAP_NORM_RESP_ENTRIES)
-
+#define AAC_HOST_NORM_CMD_ENTRIES 8 /* command adapter->host,
+ * normal priority */
+#define AAC_HOST_HIGH_CMD_ENTRIES 4 /* command adapter->host,
+ * high priority */
+#define AAC_ADAP_NORM_CMD_ENTRIES 512 /* command host->adapter,
+ * normal priority */
+#define AAC_ADAP_HIGH_CMD_ENTRIES 4 /* command host->adapter,
+ * high priority */
+#define AAC_HOST_NORM_RESP_ENTRIES 512 /* response, adapter->host,
+ * normal priority */
+#define AAC_HOST_HIGH_RESP_ENTRIES 4 /* response, adapter->host,
+ * high priority */
+#define AAC_ADAP_NORM_RESP_ENTRIES 8 /* response, host->adapter,
+ * normal priority */
+#define AAC_ADAP_HIGH_RESP_ENTRIES 4 /* response, host->adapter,
+ * high priority */
+
+#define AAC_TOTALQ_LENGTH (AAC_HOST_HIGH_CMD_ENTRIES + \
+ AAC_HOST_NORM_CMD_ENTRIES + \
+ AAC_ADAP_HIGH_CMD_ENTRIES + \
+ AAC_ADAP_NORM_CMD_ENTRIES + \
+ AAC_HOST_HIGH_RESP_ENTRIES + \
+ AAC_HOST_NORM_RESP_ENTRIES + \
+ AAC_ADAP_HIGH_RESP_ENTRIES + \
+ AAC_ADAP_NORM_RESP_ENTRIES)
#define AAC_QUEUE_COUNT 8
#define AAC_QUEUE_ALIGN 16
struct aac_queue_entry {
- u_int32_t aq_fib_size; /* FIB size in bytes */
- u_int32_t aq_fib_addr; /* receiver-space address of the FIB */
+ u_int32_t aq_fib_size; /* FIB size in bytes */
+ u_int32_t aq_fib_addr; /* receiver-space address of the FIB */
} __attribute__ ((__packed__));
#define AAC_PRODUCER_INDEX 0
@@ -87,48 +98,200 @@ struct aac_queue_entry {
*/
struct aac_queue_table {
/* queue consumer/producer indexes (layout mandated by adapter) */
- u_int32_t qt_qindex[AAC_QUEUE_COUNT][2];
+ u_int32_t qt_qindex[AAC_QUEUE_COUNT][2];
/* queue entry structures (layout mandated by adapter) */
- struct aac_queue_entry qt_HostNormCmdQueue[AAC_HOST_NORM_CMD_ENTRIES];
- struct aac_queue_entry qt_HostHighCmdQueue[AAC_HOST_HIGH_CMD_ENTRIES];
- struct aac_queue_entry qt_AdapNormCmdQueue[AAC_ADAP_NORM_CMD_ENTRIES];
- struct aac_queue_entry qt_AdapHighCmdQueue[AAC_ADAP_HIGH_CMD_ENTRIES];
- struct aac_queue_entry
- qt_HostNormRespQueue[AAC_HOST_NORM_RESP_ENTRIES];
- struct aac_queue_entry
- qt_HostHighRespQueue[AAC_HOST_HIGH_RESP_ENTRIES];
- struct aac_queue_entry
- qt_AdapNormRespQueue[AAC_ADAP_NORM_RESP_ENTRIES];
- struct aac_queue_entry
- qt_AdapHighRespQueue[AAC_ADAP_HIGH_RESP_ENTRIES];
+ struct aac_queue_entry qt_HostNormCmdQueue [AAC_HOST_NORM_CMD_ENTRIES];
+ struct aac_queue_entry qt_HostHighCmdQueue [AAC_HOST_HIGH_CMD_ENTRIES];
+ struct aac_queue_entry qt_AdapNormCmdQueue [AAC_ADAP_NORM_CMD_ENTRIES];
+ struct aac_queue_entry qt_AdapHighCmdQueue [AAC_ADAP_HIGH_CMD_ENTRIES];
+ struct aac_queue_entry qt_HostNormRespQueue[AAC_HOST_NORM_RESP_ENTRIES];
+ struct aac_queue_entry qt_HostHighRespQueue[AAC_HOST_HIGH_RESP_ENTRIES];
+ struct aac_queue_entry qt_AdapNormRespQueue[AAC_ADAP_NORM_RESP_ENTRIES];
+ struct aac_queue_entry qt_AdapHighRespQueue[AAC_ADAP_HIGH_RESP_ENTRIES];
+} __attribute__ ((__packed__));
+
+/*
+ * Queue names
+ *
+ * Note that we base these at 0 in order to use them as array indices. Adaptec
+ * used base 1 for some unknown reason, and sorted them in a different order.
+ */
+#define AAC_HOST_NORM_CMD_QUEUE 0
+#define AAC_HOST_HIGH_CMD_QUEUE 1
+#define AAC_ADAP_NORM_CMD_QUEUE 2
+#define AAC_ADAP_HIGH_CMD_QUEUE 3
+#define AAC_HOST_NORM_RESP_QUEUE 4
+#define AAC_HOST_HIGH_RESP_QUEUE 5
+#define AAC_ADAP_NORM_RESP_QUEUE 6
+#define AAC_ADAP_HIGH_RESP_QUEUE 7
+
+/*
+ * List structure used to chain FIBs (used by the adapter - we hang FIBs off
+ * our private command structure and don't touch these)
+ */
+struct aac_fib_list_entry {
+ u_int32_t Flink;
+ u_int32_t Blink;
} __attribute__ ((__packed__));
/*
+ * FIB (FSA Interface Block?); this is the datastructure passed between the host
+ * and adapter.
+ */
+struct aac_fib_header {
+ u_int32_t XferState;
+ u_int16_t Command;
+ u_int8_t StructType;
+ u_int8_t Flags;
+ u_int16_t Size;
+ u_int16_t SenderSize;
+ u_int32_t SenderFibAddress;
+ u_int32_t ReceiverFibAddress;
+ u_int32_t SenderData;
+ union {
+ struct {
+ u_int32_t ReceiverTimeStart;
+ u_int32_t ReceiverTimeDone;
+ } _s;
+ struct aac_fib_list_entry FibLinks;
+ } _u;
+} __attribute__ ((__packed__));
+
+#define AAC_FIB_DATASIZE (512 - sizeof(struct aac_fib_header))
+
+struct aac_fib {
+ struct aac_fib_header Header;
+ u_int8_t data[AAC_FIB_DATASIZE];
+} __attribute__ ((__packed__));
+
+/*
+ * FIB commands
+ */
+typedef enum {
+ TestCommandResponse = 1,
+ TestAdapterCommand = 2,
+
+ /* lowlevel and comm commands */
+ LastTestCommand = 100,
+ ReinitHostNormCommandQueue = 101,
+ ReinitHostHighCommandQueue = 102,
+ ReinitHostHighRespQueue = 103,
+ ReinitHostNormRespQueue = 104,
+ ReinitAdapNormCommandQueue = 105,
+ ReinitAdapHighCommandQueue = 107,
+ ReinitAdapHighRespQueue = 108,
+ ReinitAdapNormRespQueue = 109,
+ InterfaceShutdown = 110,
+ DmaCommandFib = 120,
+ StartProfile = 121,
+ TermProfile = 122,
+ SpeedTest = 123,
+ TakeABreakPt = 124,
+ RequestPerfData = 125,
+ SetInterruptDefTimer= 126,
+ SetInterruptDefCount= 127,
+ GetInterruptDefStatus= 128,
+ LastCommCommand = 129,
+
+ /* filesystem commands */
+ NuFileSystem = 300,
+ UFS = 301,
+ HostFileSystem = 302,
+ LastFileSystemCommand = 303,
+
+ /* Container Commands */
+ ContainerCommand = 500,
+ ContainerCommand64 = 501,
+
+ /* Cluster Commands */
+ ClusterCommand = 550,
+
+ /* Scsi Port commands (scsi passthrough) */
+ ScsiPortCommand = 600,
+
+ /* misc house keeping and generic adapter initiated commands */
+ AifRequest = 700,
+ CheckRevision = 701,
+ FsaHostShutdown = 702,
+ RequestAdapterInfo = 703,
+ IsAdapterPaused = 704,
+ SendHostTime = 705,
+ LastMiscCommand = 706
+} AAC_FibCommands;
+
+/*
+ * FIB types
+ */
+#define AAC_FIBTYPE_TFIB 1
+#define AAC_FIBTYPE_TQE 2
+#define AAC_FIBTYPE_TCTPERF 3
+
+/*
+ * FIB transfer state
+ */
+#define AAC_FIBSTATE_HOSTOWNED (1<<0) /* owned by the host */
+#define AAC_FIBSTATE_ADAPTEROWNED (1<<1) /* owned by the adapter */
+#define AAC_FIBSTATE_INITIALISED (1<<2) /* initialised */
+#define AAC_FIBSTATE_EMPTY (1<<3) /* empty */
+#define AAC_FIBSTATE_FROMPOOL (1<<4) /* allocated from pool */
+#define AAC_FIBSTATE_FROMHOST (1<<5) /* sent from the host */
+#define AAC_FIBSTATE_FROMADAP (1<<6) /* sent from the adapter */
+#define AAC_FIBSTATE_REXPECTED (1<<7) /* response is expected */
+#define AAC_FIBSTATE_RNOTEXPECTED (1<<8) /* response is not expected */
+#define AAC_FIBSTATE_DONEADAP (1<<9) /* processed by the adapter */
+#define AAC_FIBSTATE_DONEHOST (1<<10) /* processed by the host */
+#define AAC_FIBSTATE_HIGH (1<<11) /* high priority */
+#define AAC_FIBSTATE_NORM (1<<12) /* normal priority */
+#define AAC_FIBSTATE_ASYNC (1<<13)
+#define AAC_FIBSTATE_ASYNCIO (1<<13) /* to be removed */
+#define AAC_FIBSTATE_PAGEFILEIO (1<<14) /* to be removed */
+#define AAC_FIBSTATE_SHUTDOWN (1<<15)
+#define AAC_FIBSTATE_LAZYWRITE (1<<16) /* to be removed */
+#define AAC_FIBSTATE_ADAPMICROFIB (1<<17)
+#define AAC_FIBSTATE_BIOSFIB (1<<18)
+#define AAC_FIBSTATE_FAST_RESPONSE (1<<19) /* fast response capable */
+#define AAC_FIBSTATE_APIFIB (1<<20)
+
+/*
+ * FIB error values
+ */
+#define AAC_ERROR_NORMAL 0x00
+#define AAC_ERROR_PENDING 0x01
+#define AAC_ERROR_FATAL 0x02
+#define AAC_ERROR_INVALID_QUEUE 0x03
+#define AAC_ERROR_NOENTRIES 0x04
+#define AAC_ERROR_SENDFAILED 0x05
+#define AAC_ERROR_INVALID_QUEUE_PRIORITY 0x06
+#define AAC_ERROR_FIB_ALLOCATION_FAILED 0x07
+#define AAC_ERROR_FIB_DEALLOCATION_FAILED 0x08
+
+/*
* Adapter Init Structure: this is passed to the adapter with the
* AAC_MONKER_INITSTRUCT command to point it at our control structures.
*/
struct aac_adapter_init {
- u_int32_t InitStructRevision;
-#define AAC_INIT_STRUCT_REVISION 3
- u_int32_t MiniPortRevision;
- u_int32_t FilesystemRevision;
- u_int32_t CommHeaderAddress;
- u_int32_t FastIoCommAreaAddress;
- u_int32_t AdapterFibsPhysicalAddress;
- void *AdapterFibsVirtualAddress;
- u_int32_t AdapterFibsSize;
- u_int32_t AdapterFibAlign;
- u_int32_t PrintfBufferAddress;
- u_int32_t PrintfBufferSize;
- u_int32_t HostPhysMemPages;
- u_int32_t HostElapsedSeconds;
-} __packed;
+ u_int32_t InitStructRevision;
+#define AAC_INIT_STRUCT_REVISION 3
+ u_int32_t MiniPortRevision;
+#define AAC_INIT_STRUCT_MINIPORT_REVISION 1
+ u_int32_t FilesystemRevision;
+ u_int32_t CommHeaderAddress;
+ u_int32_t FastIoCommAreaAddress;
+ u_int32_t AdapterFibsPhysicalAddress;
+ u_int32_t AdapterFibsVirtualAddress;
+ u_int32_t AdapterFibsSize;
+ u_int32_t AdapterFibAlign;
+ u_int32_t PrintfBufferAddress;
+ u_int32_t PrintfBufferSize;
+#define AAC_PAGE_SIZE 4096
+ u_int32_t HostPhysMemPages;
+ u_int32_t HostElapsedSeconds;
+} __attribute__ ((__packed__));
/*
* Shared data types
*/
-
/*
* Container types
*/
@@ -146,7 +309,8 @@ typedef enum {
CT_RAID10, /* stripe of mirror */
CT_RAID00, /* stripe of stripe */
CT_VOLUME_OF_MIRRORS, /* volume of mirror */
- CT_PSEUDO_RAID3 /* really raid4 */
+ CT_PSEUDO_RAID3, /* really raid4 */
+ CT_RAID50, /* stripe of raid5 */
} AAC_FSAVolType;
/*
@@ -161,9 +325,10 @@ typedef enum {
FT_SOCK, /* socket */
FT_FIFO, /* fifo */
FT_FILESYS, /* ADAPTEC's "FSA"(tm) filesystem */
- FT_DRIVE, /* phys disk - addressable in scsi by bus/target/lun */
+ FT_DRIVE, /* physical disk - addressable in scsi by b/t/l */
FT_SLICE, /* virtual disk - raw volume - slice */
- FT_PARTITION, /* FSA part, inside slice, container building block */
+ FT_PARTITION, /* FSA partition - carved out of a slice - building
+ * block for containers */
FT_VOLUME, /* Container - Volume Set */
FT_STRIPE, /* Container - Stripe Set */
FT_MIRROR, /* Container - Mirror Set */
@@ -175,53 +340,72 @@ typedef enum {
* Host-side scatter/gather list for 32-bit commands.
*/
struct aac_sg_entry {
- u_int32_t SgAddress;
- u_int32_t SgByteCount;
+ u_int32_t SgAddress;
+ u_int32_t SgByteCount;
+} __attribute__ ((__packed__));
+
+struct aac_sg_entry64 {
+ u_int64_t SgAddress;
+ u_int32_t SgByteCount;
} __attribute__ ((__packed__));
struct aac_sg_table {
- u_int32_t SgCount;
- struct aac_sg_entry SgEntry[0];
+ u_int32_t SgCount;
+ struct aac_sg_entry SgEntry[0];
} __attribute__ ((__packed__));
/*
* Host-side scatter/gather list for 64-bit commands.
*/
struct aac_sg_table64 {
- u_int8_t SgCount;
- u_int8_t SgSectorsPerPage;
- u_int16_t SgByteOffset;
- u_int64_t SgEntry[0];
+ u_int32_t SgCount;
+ struct aac_sg_entry64 SgEntry64[0];
} __attribute__ ((__packed__));
/*
* Container creation data
*/
struct aac_container_creation {
- u_int8_t ViaBuildNumber;
- u_int8_t MicroSecond;
- u_int8_t Via; /* 1 = FSU, 2 = API, etc. */
- u_int8_t YearsSince1900;
- u_int32_t Month:4; /* 1-12 */
- u_int32_t Day:6; /* 1-32 */
- u_int32_t Hour:6; /* 0-23 */
- u_int32_t Minute:6; /* 0-59 */
- u_int32_t Second:6; /* 0-59 */
- u_int64_t ViaAdapterSerialNumber;
+ u_int8_t ViaBuildNumber;
+ u_int8_t MicroSecond;
+ u_int8_t Via; /* 1 = FSU, 2 = API, etc. */
+ u_int8_t YearsSince1900;
+ u_int32_t Month:4; /* 1-12 */
+ u_int32_t Day:6; /* 1-32 */
+ u_int32_t Hour:6; /* 0-23 */
+ u_int32_t Minute:6; /* 0-59 */
+ u_int32_t Second:6; /* 0-59 */
+ u_int64_t ViaAdapterSerialNumber;
} __attribute__ ((__packed__));
+/*
+ * Revision number handling
+ */
+
+typedef enum {
+ RevApplication = 1,
+ RevDkiCli,
+ RevNetService,
+ RevApi,
+ RevFileSysDriver,
+ RevMiniportDriver,
+ RevAdapterSW,
+ RevMonitor,
+ RevRemoteApi
+} RevComponent;
+
struct FsaRevision {
union {
- struct {
- u_int8_t dash;
- u_int8_t type;
- u_int8_t minor;
- u_int8_t major;
- } comp;
- u_int32_t ul;
+ struct {
+ u_int8_t dash;
+ u_int8_t type;
+ u_int8_t minor;
+ u_int8_t major;
+ } comp;
+ u_int32_t ul;
} external;
- u_int32_t buildNumber;
-} __packed;
+ u_int32_t buildNumber;
+} __attribute__ ((__packed__));
/*
* Adapter Information
@@ -246,7 +430,7 @@ typedef enum {
CPUI960_RX,
CPUARM_SA110,
CPUARM_xxx,
- CPUPPC_603e,
+ CPUMPC_824x,
CPUPPC_xxx,
CPUI960_302,
CPUSUBTYPE__last
@@ -291,7 +475,8 @@ typedef enum {
/*
* XXX the aac-2622 with no battery present reports PLATFORM_BAT_OPT_PRESENT
*/
-typedef enum {
+typedef enum
+{
PLATFORM_BAT_REQ_PRESENT = 1, /* BATTERY REQUIRED AND PRESENT */
PLATFORM_BAT_REQ_NOTPRESENT, /* BATTERY REQUIRED AND NOT PRESENT */
PLATFORM_BAT_OPT_PRESENT, /* BATTERY OPTIONAL AND PRESENT */
@@ -300,27 +485,50 @@ typedef enum {
} AAC_BatteryPlatform;
/*
+ * options supported by this board
+ * there has to be a one to one mapping of these defines and the ones in
+ * fsaapi.h, search for FSA_SUPPORT_SNAPSHOT
+ */
+#define AAC_SUPPORTED_SNAPSHOT 0x01
+#define AAC_SUPPORTED_CLUSTERS 0x02
+#define AAC_SUPPORTED_WRITE_CACHE 0x04
+#define AAC_SUPPORTED_64BIT_DATA 0x08
+#define AAC_SUPPORTED_HOST_TIME_FIB 0x10
+#define AAC_SUPPORTED_RAID50 0x20
+#define AAC_SUPPORTED_4GB_WINDOW 0x40
+#define AAC_SUPPORTED_SCSI_UPGRADEABLE 0x80
+#define AAC_SUPPORTED_SOFT_ERR_REPORT 0x100
+#define AAC_SUPPORTED_NOT_RECONDITION 0x200
+#define AAC_SUPPORTED_SGMAP_HOST64 0x400
+#define AAC_SUPPORTED_ALARM 0x800
+#define AAC_SUPPORTED_NONDASD 0x1000
+
+/*
* Structure used to respond to a RequestAdapterInfo fib.
*/
struct aac_adapter_info {
- AAC_Platform PlatformBase; /* adapter type */
- AAC_CpuType CpuArchitecture; /* adapter CPU type */
- AAC_CpuSubType CpuVariant; /* adapter CPU subtype */
- u_int32_t ClockSpeed; /* adapter CPU clockspeed */
- u_int32_t ExecutionMem; /* adapter Execution Memory size */
- u_int32_t BufferMem; /* adapter Data Memory */
- u_int32_t TotalMem; /* adapter Total Memory */
- struct FsaRevision KernelRevision; /* adapter Kernel SW Revision */
- struct FsaRevision MonitorRevision; /* adapter Monitor/Diag SW Rev */
- struct FsaRevision HardwareRevision; /* TDB */
- struct FsaRevision BIOSRevision; /* adapter BIOS Revision */
- u_int32_t ClusteringEnabled;
- u_int32_t ClusterChannelMask;
- u_int64_t SerialNumber;
- AAC_BatteryPlatform batteryPlatform;
- u_int32_t SupportedOptions; /* supported features of this ctrlr */
- AAC_OemFlavor OemVariant;
-} __packed;
+ AAC_Platform PlatformBase; /* adapter type */
+ AAC_CpuType CpuArchitecture; /* adapter CPU type */
+ AAC_CpuSubType CpuVariant; /* adapter CPU subtype */
+ u_int32_t ClockSpeed; /* adapter CPU clockspeed */
+ u_int32_t ExecutionMem; /* adapter Execution Memory
+ * size */
+ u_int32_t BufferMem; /* adapter Data Memory */
+ 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;/* TBD */
+ struct FsaRevision BIOSRevision; /* adapter BIOS Revision */
+ u_int32_t ClusteringEnabled;
+ u_int32_t ClusterChannelMask;
+ u_int64_t SerialNumber;
+ AAC_BatteryPlatform batteryPlatform;
+ u_int32_t SupportedOptions; /* supported features of this
+ * controller */
+ AAC_OemFlavor OemVariant;
+} __attribute__ ((__packed__));
/*
* Monitor/Kernel interface.
@@ -331,104 +539,588 @@ struct aac_adapter_info {
*/
#define AAC_MONKER_INITSTRUCT 0x05
#define AAC_MONKER_SYNCFIB 0x0c
+#define AAC_MONKER_GETKERNVER 0x11
+#define AAC_MONKER_GETINFO 0x19
+
+/*
+ * Adapter Status Register
+ *
+ * Phase Staus mailbox is 32bits:
+ * <31:16> = Phase Status
+ * <15:0> = Phase
+ *
+ * The adapter reports its present state through the phase. Only
+ * a single phase should be ever be set. Each phase can have multiple
+ * phase status bits to provide more detailed information about the
+ * state of the adapter.
+ */
+#define AAC_SELF_TEST_FAILED 0x00000004
+#define AAC_UP_AND_RUNNING 0x00000080
+#define AAC_KERNEL_PANIC 0x00000100
+
+/*
+ * Data types relating to control and monitoring of the NVRAM/WriteCache
+ * subsystem.
+ */
+
+#define AAC_NFILESYS 24 /* maximum number of filesystems */
+
+/*
+ * NVRAM/Write Cache subsystem states
+ */
+typedef enum {
+ NVSTATUS_DISABLED = 0, /* present, clean, not being used */
+ NVSTATUS_ENABLED, /* present, possibly dirty, ready for use */
+ NVSTATUS_ERROR, /* present, dirty, contains dirty data */
+ NVSTATUS_BATTERY, /* present, bad or low battery, may contain
+ * dirty data */
+ NVSTATUS_UNKNOWN /* for bad/missing device */
+} AAC_NVSTATUS;
+
+/*
+ * NVRAM/Write Cache subsystem battery component states
+ *
+ */
+typedef enum {
+ NVBATTSTATUS_NONE = 0, /* battery has no power or is not present */
+ NVBATTSTATUS_LOW, /* battery is low on power */
+ NVBATTSTATUS_OK, /* battery is okay - normal operation possible
+ * only in this state */
+ NVBATTSTATUS_RECONDITIONING /* no battery present - reconditioning
+ * in process */
+} AAC_NVBATTSTATUS;
+
+/*
+ * Battery transition type
+ */
+typedef enum {
+ NVBATT_TRANSITION_NONE = 0, /* battery now has no power or is not
+ * present */
+ NVBATT_TRANSITION_LOW, /* battery is now low on power */
+ NVBATT_TRANSITION_OK /* battery is now okay - normal
+ * operation possible only in this
+ * state */
+} AAC_NVBATT_TRANSITION;
+
+/*
+ * NVRAM Info structure returned for NVRAM_GetInfo call
+ */
+struct aac_nvramdevinfo {
+ u_int32_t NV_Enabled; /* write caching enabled */
+ u_int32_t NV_Error; /* device in error state */
+ u_int32_t NV_NDirty; /* count of dirty NVRAM buffers */
+ u_int32_t NV_NActive; /* count of NVRAM buffers being
+ * written */
+} __attribute__ ((__packed__));
+
+struct aac_nvraminfo {
+ AAC_NVSTATUS NV_Status; /* nvram subsystem status */
+ AAC_NVBATTSTATUS NV_BattStatus; /* battery status */
+ u_int32_t NV_Size; /* size of WriteCache NVRAM in
+ * bytes */
+ u_int32_t NV_BufSize; /* size of NVRAM buffers in
+ * bytes */
+ u_int32_t NV_NBufs; /* number of NVRAM buffers */
+ u_int32_t NV_NDirty; /* Num dirty NVRAM buffers */
+ u_int32_t NV_NClean; /* Num clean NVRAM buffers */
+ u_int32_t NV_NActive; /* Num NVRAM buffers being
+ * written */
+ u_int32_t NV_NBrokered; /* Num brokered NVRAM buffers */
+ struct aac_nvramdevinfo NV_DevInfo[AAC_NFILESYS]; /* per device
+ * info */
+ u_int32_t NV_BattNeedsReconditioning; /* boolean */
+ u_int32_t NV_TotalSize; /* size of all non-volatile
+ * memories in bytes */
+} __attribute__ ((__packed__));
+
+/*
+ * Data types relating to adapter-initiated FIBs
+ *
+ * Based on types and structures in <aifstruc.h>
+ */
+
+/*
+ * Progress Reports
+ */
+typedef enum {
+ AifJobStsSuccess = 1,
+ AifJobStsFinished,
+ AifJobStsAborted,
+ AifJobStsFailed,
+ AifJobStsLastReportMarker = 100, /* All prior mean last report */
+ AifJobStsSuspended,
+ AifJobStsRunning
+} AAC_AifJobStatus;
+
+typedef enum {
+ AifJobScsiMin = 1, /* Minimum value for Scsi operation */
+ AifJobScsiZero, /* SCSI device clear operation */
+ AifJobScsiVerify, /* SCSI device Verify operation NO
+ * REPAIR */
+ AifJobScsiExercise, /* SCSI device Exercise operation */
+ AifJobScsiVerifyRepair, /* SCSI device Verify operation WITH
+ * repair */
+ AifJobScsiMax = 99, /* Max Scsi value */
+ AifJobCtrMin, /* Min Ctr op value */
+ AifJobCtrZero, /* Container clear operation */
+ AifJobCtrCopy, /* Container copy operation */
+ AifJobCtrCreateMirror, /* Container Create Mirror operation */
+ AifJobCtrMergeMirror, /* Container Merge Mirror operation */
+ AifJobCtrScrubMirror, /* Container Scrub Mirror operation */
+ AifJobCtrRebuildRaid5, /* Container Rebuild Raid5 operation */
+ AifJobCtrScrubRaid5, /* Container Scrub Raid5 operation */
+ AifJobCtrMorph, /* Container morph operation */
+ AifJobCtrPartCopy, /* Container Partition copy operation */
+ AifJobCtrRebuildMirror, /* Container Rebuild Mirror operation */
+ AifJobCtrCrazyCache, /* crazy cache */
+ AifJobCtrMax = 199, /* Max Ctr type operation */
+ AifJobFsMin, /* Min Fs type operation */
+ AifJobFsCreate, /* File System Create operation */
+ AifJobFsVerify, /* File System Verify operation */
+ AifJobFsExtend, /* File System Extend operation */
+ AifJobFsMax = 299, /* Max Fs type operation */
+ AifJobApiFormatNTFS, /* Format a drive to NTFS */
+ AifJobApiFormatFAT, /* Format a drive to FAT */
+ AifJobApiUpdateSnapshot, /* update the read/write half of a
+ * snapshot */
+ AifJobApiFormatFAT32, /* Format a drive to FAT32 */
+ AifJobApiMax = 399, /* Max API type operation */
+ AifJobCtlContinuousCtrVerify, /* Adapter operation */
+ AifJobCtlMax = 499 /* Max Adapter type operation */
+} AAC_AifJobType;
+
+struct aac_AifContainers {
+ u_int32_t src; /* from/master */
+ u_int32_t dst; /* to/slave */
+} __attribute__ ((__packed__));
+
+union aac_AifJobClient {
+ struct aac_AifContainers container; /* For Container and
+ * filesystem progress
+ * ops; */
+ int32_t scsi_dh; /* For SCSI progress
+ * ops */
+};
+
+struct aac_AifJobDesc {
+ u_int32_t jobID; /* DO NOT FILL IN! Will be
+ * filled in by AIF */
+ AAC_AifJobType type; /* Operation that is being
+ * performed */
+ union aac_AifJobClient client; /* Details */
+} __attribute__ ((__packed__));
+
+struct aac_AifJobProgressReport {
+ struct aac_AifJobDesc jd;
+ AAC_AifJobStatus status;
+ u_int32_t finalTick;
+ u_int32_t currentTick;
+ u_int32_t jobSpecificData1;
+ u_int32_t jobSpecificData2;
+} __attribute__ ((__packed__));
+
+/*
+ * Event Notification
+ */
+typedef enum {
+ /* General application notifies start here */
+ AifEnGeneric = 1, /* Generic notification */
+ AifEnTaskComplete, /* Task has completed */
+ AifEnConfigChange, /* Adapter config change occurred */
+ AifEnContainerChange, /* Adapter specific container
+ * configuration change */
+ AifEnDeviceFailure, /* SCSI device failed */
+ AifEnMirrorFailover, /* Mirror failover started */
+ AifEnContainerEvent, /* Significant container event */
+ AifEnFileSystemChange, /* File system changed */
+ AifEnConfigPause, /* Container pause event */
+ AifEnConfigResume, /* Container resume event */
+ AifEnFailoverChange, /* Failover space assignment changed */
+ AifEnRAID5RebuildDone, /* RAID5 rebuild finished */
+ AifEnEnclosureManagement, /* Enclosure management event */
+ AifEnBatteryEvent, /* Significant NV battery event */
+ AifEnAddContainer, /* A new container was created. */
+ AifEnDeleteContainer, /* A container was deleted. */
+ AifEnSMARTEvent, /* SMART Event */
+ AifEnBatteryNeedsRecond, /* The battery needs reconditioning */
+ AifEnClusterEvent, /* Some cluster event */
+ AifEnDiskSetEvent, /* A disk set event occured. */
+ AifDriverNotifyStart=199, /* Notifies for host driver go here */
+ /* Host driver notifications start here */
+ AifDenMorphComplete, /* A morph operation completed */
+ AifDenVolumeExtendComplete /* Volume expand operation completed */
+} AAC_AifEventNotifyType;
+
+struct aac_AifEnsGeneric {
+ char text[132]; /* Generic text */
+} __attribute__ ((__packed__));
+
+struct aac_AifEnsDeviceFailure {
+ u_int32_t deviceHandle; /* SCSI device handle */
+} __attribute__ ((__packed__));
+
+struct aac_AifEnsMirrorFailover {
+ u_int32_t container; /* Container with failed element */
+ u_int32_t failedSlice; /* Old slice which failed */
+ u_int32_t creatingSlice; /* New slice used for auto-create */
+} __attribute__ ((__packed__));
+
+struct aac_AifEnsContainerChange {
+ u_int32_t container[2]; /* container that changed, -1 if no
+ * container */
+} __attribute__ ((__packed__));
+
+struct aac_AifEnsContainerEvent {
+ u_int32_t container; /* container number */
+ u_int32_t eventType; /* event type */
+} __attribute__ ((__packed__));
+
+struct aac_AifEnsEnclosureEvent {
+ u_int32_t empID; /* enclosure management proc number */
+ u_int32_t unitID; /* unitId, fan id, power supply id,
+ * slot id, tempsensor id. */
+ u_int32_t eventType; /* event type */
+} __attribute__ ((__packed__));
+
+struct aac_AifEnsBatteryEvent {
+ AAC_NVBATT_TRANSITION transition_type; /* eg from low to ok */
+ AAC_NVBATTSTATUS current_state; /* current batt state */
+ AAC_NVBATTSTATUS prior_state; /* prev batt state */
+} __attribute__ ((__packed__));
+
+struct aac_AifEnsDiskSetEvent {
+ u_int32_t eventType;
+ u_int64_t DsNum;
+ u_int64_t CreatorId;
+} __attribute__ ((__packed__));
+
+typedef enum {
+ CLUSTER_NULL_EVENT = 0,
+ CLUSTER_PARTNER_NAME_EVENT, /* change in partner hostname or
+ * adaptername from NULL to non-NULL */
+ /* (partner's agent may be up) */
+ CLUSTER_PARTNER_NULL_NAME_EVENT /* change in partner hostname or
+ * adaptername from non-null to NULL */
+ /* (partner has rebooted) */
+} AAC_ClusterAifEvent;
+
+struct aac_AifEnsClusterEvent {
+ AAC_ClusterAifEvent eventType;
+} __attribute__ ((__packed__));
+
+struct aac_AifEventNotify {
+ AAC_AifEventNotifyType type;
+ union {
+ struct aac_AifEnsGeneric EG;
+ struct aac_AifEnsDeviceFailure EDF;
+ struct aac_AifEnsMirrorFailover EMF;
+ struct aac_AifEnsContainerChange ECC;
+ struct aac_AifEnsContainerEvent ECE;
+ struct aac_AifEnsEnclosureEvent EEE;
+ struct aac_AifEnsBatteryEvent EBE;
+ struct aac_AifEnsDiskSetEvent EDS;
+/* struct aac_AifEnsSMARTEvent ES;*/
+ struct aac_AifEnsClusterEvent ECLE;
+ } data;
+} __attribute__ ((__packed__));
+
+/*
+ * Adapter Initiated FIB command structures. Start with the adapter
+ * initiated FIBs that really come from the adapter, and get responded
+ * to by the host.
+ */
+#define AAC_AIF_REPORT_MAX_SIZE 64
+
+typedef enum {
+ AifCmdEventNotify = 1, /* Notify of event */
+ AifCmdJobProgress, /* Progress report */
+ AifCmdAPIReport, /* Report from other user of API */
+ AifCmdDriverNotify, /* Notify host driver of event */
+ AifReqJobList = 100, /* Gets back complete job list */
+ AifReqJobsForCtr, /* Gets back jobs for specific container */
+ AifReqJobsForScsi, /* Gets back jobs for specific SCSI device */
+ AifReqJobReport, /* Gets back a specific job report or list */
+ AifReqTerminateJob, /* Terminates job */
+ AifReqSuspendJob, /* Suspends a job */
+ AifReqResumeJob, /* Resumes a job */
+ AifReqSendAPIReport, /* API generic report requests */
+ AifReqAPIJobStart, /* Start a job from the API */
+ AifReqAPIJobUpdate, /* Update a job report from the API */
+ AifReqAPIJobFinish /* Finish a job from the API */
+} AAC_AifCommand;
+
+struct aac_aif_command {
+ AAC_AifCommand command; /* Tell host what type of
+ * notify this is */
+ u_int32_t seqNumber; /* To allow ordering of
+ * reports (if necessary) */
+ union {
+ struct aac_AifEventNotify EN; /* Event notify */
+ struct aac_AifJobProgressReport PR[1]; /* Progress report */
+ u_int8_t AR[AAC_AIF_REPORT_MAX_SIZE];
+ u_int8_t data[AAC_FIB_DATASIZE - 8];
+ } data;
+} __attribute__ ((__packed__));
+
+/*
+ * Filesystem commands/data
+ *
+ * The adapter has a very complex filesystem interface, most of which we ignore.
+ * (And which seems not to be implemented, anyway.)
+ */
+
+/*
+ * FSA commands
+ * (not used?)
+ */
+typedef enum {
+ Null = 0,
+ GetAttributes,
+ SetAttributes,
+ Lookup,
+ ReadLink,
+ Read,
+ Write,
+ Create,
+ MakeDirectory,
+ SymbolicLink,
+ MakeNode,
+ Removex,
+ RemoveDirectory,
+ Rename,
+ Link,
+ ReadDirectory,
+ ReadDirectoryPlus,
+ FileSystemStatus,
+ FileSystemInfo,
+ PathConfigure,
+ Commit,
+ Mount,
+ UnMount,
+ Newfs,
+ FsCheck,
+ FsSync,
+ SimReadWrite,
+ SetFileSystemStatus,
+ BlockRead,
+ BlockWrite,
+ NvramIoctl,
+ FsSyncWait,
+ ClearArchiveBit,
+ SetAcl,
+ GetAcl,
+ AssignAcl,
+ FaultInsertion,
+ CrazyCache
+} AAC_FSACommand;
/*
* Command status values
*/
typedef enum {
- ST_OK = 0,
- ST_PERM = 1,
- ST_NOENT = 2,
- ST_IO = 5,
- ST_NXIO = 6,
- ST_E2BIG = 7,
- ST_ACCES = 13,
- ST_EXIST = 17,
- ST_XDEV = 18,
- ST_NODEV = 19,
- ST_NOTDIR = 20,
- ST_ISDIR = 21,
- ST_INVAL = 22,
- ST_FBIG = 27,
- ST_NOSPC = 28,
- ST_ROFS = 30,
- ST_MLINK = 31,
- ST_WOULDBLOCK = 35,
- ST_NAMETOOLONG = 63,
- ST_NOTEMPTY = 66,
- ST_DQUOT = 69,
- ST_STALE = 70,
- ST_REMOTE = 71,
- ST_BADHANDLE = 10001,
- ST_NOT_SYNC = 10002,
- ST_BAD_COOKIE = 10003,
- ST_NOTSUPP = 10004,
- ST_TOOSMALL = 10005,
- ST_SERVERFAULT = 10006,
- ST_BADTYPE = 10007,
- ST_JUKEBOX = 10008,
- ST_NOTMOUNTED = 10009,
- ST_MAINTMODE = 10010,
- ST_STALEACL = 10011
+ ST_OK = 0,
+ ST_PERM = 1,
+ ST_NOENT = 2,
+ ST_IO = 5,
+ ST_NXIO = 6,
+ ST_E2BIG = 7,
+ ST_ACCES = 13,
+ ST_EXIST = 17,
+ ST_XDEV = 18,
+ ST_NODEV = 19,
+ ST_NOTDIR = 20,
+ ST_ISDIR = 21,
+ ST_INVAL = 22,
+ ST_FBIG = 27,
+ ST_NOSPC = 28,
+ ST_ROFS = 30,
+ ST_MLINK = 31,
+ ST_WOULDBLOCK = 35,
+ ST_NAMETOOLONG = 63,
+ ST_NOTEMPTY = 66,
+ ST_DQUOT = 69,
+ ST_STALE = 70,
+ ST_REMOTE = 71,
+ ST_BADHANDLE = 10001,
+ ST_NOT_SYNC = 10002,
+ ST_BAD_COOKIE = 10003,
+ ST_NOTSUPP = 10004,
+ ST_TOOSMALL = 10005,
+ ST_SERVERFAULT = 10006,
+ ST_BADTYPE = 10007,
+ ST_JUKEBOX = 10008,
+ ST_NOTMOUNTED = 10009,
+ ST_MAINTMODE = 10010,
+ ST_STALEACL = 10011
} AAC_FSAStatus;
/*
* Volume manager commands
*/
typedef enum _VM_COMMANDS {
- VM_Null = 0,
- VM_NameServe,
- VM_ContainerConfig,
- VM_Ioctl,
- VM_FilesystemIoctl,
- VM_CloseAll,
- VM_CtBlockRead,
- VM_CtBlockWrite,
- VM_SliceBlockRead, /* raw access to configured "storage objects" */
- VM_SliceBlockWrite,
- VM_DriveBlockRead, /* raw access to physical devices */
- VM_DriveBlockWrite,
- VM_EnclosureMgt, /* enclosure management */
- VM_Unused, /* used to be diskset management */
- VM_CtBlockVerify,
- VM_CtPerf, /* performance test */
- VM_CtBlockRead64,
- VM_CtBlockWrite64,
- VM_CtBlockVerify64,
+ VM_Null = 0,
+ VM_NameServe,
+ VM_ContainerConfig,
+ VM_Ioctl,
+ VM_FilesystemIoctl,
+ VM_CloseAll,
+ VM_CtBlockRead,
+ VM_CtBlockWrite,
+ VM_SliceBlockRead, /* raw access to configured storage objects */
+ VM_SliceBlockWrite,
+ VM_DriveBlockRead, /* raw access to physical devices */
+ VM_DriveBlockWrite,
+ VM_EnclosureMgt, /* enclosure management */
+ VM_Unused, /* used to be diskset management */
+ VM_CtBlockVerify,
+ VM_CtPerf, /* performance test */
+ VM_CtBlockRead64,
+ VM_CtBlockWrite64,
+ VM_CtBlockVerify64,
+ VM_CtHostRead64,
+ VM_CtHostWrite64,
} AAC_VMCommand;
/*
- * "Mountable object"
+ * "mountable object"
*/
struct aac_mntobj {
- u_int32_t ObjectId;
- char FileSystemName[16];
- struct aac_container_creation CreateInfo;
- u_int32_t Capacity;
- AAC_FSAVolType VolType;
- AAC_FType ObjType;
- u_int32_t ContentState;
-#define AAC_FSCS_READONLY 0x0002 /* XXX need more information than this */
+ u_int32_t ObjectId;
+ char FileSystemName[16];
+ struct aac_container_creation CreateInfo;
+ u_int32_t Capacity;
+ u_int32_t VolType;
+ u_int32_t ObjType;
+ u_int32_t ContentState;
+#define FSCS_READONLY 0x0002 /* XXX need more information
+ * than this */
union {
- u_int32_t pad[8];
+ u_int32_t pad[8];
} ObjExtension;
- u_int32_t AlterEgoId;
+ u_int32_t AlterEgoId;
} __attribute__ ((__packed__));
struct aac_mntinfo {
- AAC_VMCommand Command;
- AAC_FType MntType;
- u_int32_t MntCount;
+ u_int32_t Command;
+ u_int32_t MntType;
+ u_int32_t MntCount;
} __attribute__ ((__packed__));
-struct aac_mntinforesponse {
- AAC_FSAStatus Status;
- AAC_FType MntType;
- u_int32_t MntRespCount;
- struct aac_mntobj MntTable[1];
+struct aac_mntinforesp {
+ u_int32_t Status;
+ u_int32_t MntType;
+ u_int32_t MntRespCount;
+ struct aac_mntobj MntTable[1];
} __attribute__ ((__packed__));
/*
+ * Container shutdown command.
+ */
+struct aac_closecommand {
+ u_int32_t Command;
+ u_int32_t ContainerId;
+} __attribute__ ((__packed__));
+
+/*
+ * Container Config Command
+ */
+#define CT_GET_SCSI_METHOD 64
+struct aac_ctcfg {
+ u_int32_t Command;
+ u_int32_t cmd;
+ u_int32_t param;
+} __attribute__ ((__packed__));
+
+struct aac_ctcfg_resp {
+ u_int32_t Status;
+ u_int32_t resp;
+ u_int32_t param;
+} __attribute__ ((__packed__));
+
+/*
+ * 'Ioctl' commads
+ */
+#define AAC_SCSI_MAX_PORTS 10
+#define AAC_BUS_NO_EXIST 0
+#define AAC_BUS_VALID 1
+#define AAC_BUS_FAULTED 2
+#define AAC_BUS_DISABLED 3
+#define GetBusInfo 0x9
+
+struct aac_getbusinf {
+ u_int32_t ProbeComplete;
+ u_int32_t BusCount;
+ u_int32_t TargetsPerBus;
+ u_int8_t InitiatorBusId[AAC_SCSI_MAX_PORTS];
+ u_int8_t BusValid[AAC_SCSI_MAX_PORTS];
+} __attribute__ ((__packed__));
+
+struct aac_vmioctl {
+ u_int32_t Command;
+ u_int32_t ObjType;
+ u_int32_t MethId;
+ u_int32_t ObjId;
+ u_int32_t IoctlCmd;
+ u_int32_t IoctlBuf[1]; /* Placeholder? */
+} __attribute__ ((__packed__));
+
+struct aac_vmi_businf_resp {
+ u_int32_t Status;
+ u_int32_t ObjType;
+ u_int32_t MethId;
+ u_int32_t ObjId;
+ u_int32_t IoctlCmd;
+ struct aac_getbusinf BusInf;
+} __attribute__ ((__packed__));
+
+#define AAC_BTL_TO_HANDLE(b, t, l) \
+ (((b & 0x3f) << 7) | ((l & 0x7) << 4) | (t & 0xf))
+#define GetDeviceProbeInfo 0x5
+
+struct aac_vmi_devinfo_resp {
+ u_int32_t Status;
+ u_int32_t ObjType;
+ u_int32_t MethId;
+ u_int32_t ObjId;
+ u_int32_t IoctlCmd;
+ u_int8_t VendorId[8];
+ u_int8_t ProductId[16];
+ u_int8_t ProductRev[4];
+ u_int32_t Inquiry7;
+ u_int32_t align1;
+ u_int32_t Inquiry0;
+ u_int32_t align2;
+ u_int32_t Inquiry1;
+ u_int32_t align3;
+ u_int32_t reserved[2];
+ u_int8_t VendorSpecific[20];
+ u_int32_t Smart:1;
+ u_int32_t AAC_Managed:1;
+ u_int32_t align4;
+ u_int32_t reserved2:6;
+ u_int32_t Bus;
+ u_int32_t Target;
+ u_int32_t Lun;
+ u_int32_t ultraEnable:1,
+ disconnectEnable:1,
+ fast20EnabledW:1,
+ scamDevice:1,
+ scamTolerant:1,
+ setForSync:1,
+ setForWide:1,
+ syncDevice:1,
+ wideDevice:1,
+ reserved1:7,
+ ScsiRate:8,
+ ScsiOffset:8;
+}; /* Do not pack */
+
+#define ResetBus 0x16
+struct aac_resetbus {
+ u_int32_t BusNumber;
+};
+
+/*
* Write 'stability' options.
*/
typedef enum {
@@ -453,68 +1145,199 @@ typedef enum {
*/
struct aac_blockread {
- AAC_VMCommand Command; /* not FSACommand! */
- u_int32_t ContainerId;
- u_int32_t BlockNumber;
- u_int32_t ByteCount;
- struct aac_sg_table SgMap; /* variable size */
+ u_int32_t Command; /* not FSACommand! */
+ u_int32_t ContainerId;
+ u_int32_t BlockNumber;
+ u_int32_t ByteCount;
+ struct aac_sg_table SgMap; /* variable size */
+} __attribute__ ((__packed__));
+
+struct aac_blockread64 {
+ u_int32_t Command;
+ u_int16_t ContainerId;
+ u_int16_t SectorCount;
+ u_int32_t BlockNumber;
+ u_int16_t Pad;
+ u_int16_t Flags;
+ struct aac_sg_table64 SgMap64;
} __attribute__ ((__packed__));
struct aac_blockread_response {
- AAC_FSAStatus Status;
- u_int32_t ByteCount;
+ u_int32_t Status;
+ u_int32_t ByteCount;
} __attribute__ ((__packed__));
struct aac_blockwrite {
- AAC_VMCommand Command; /* not FSACommand! */
- u_int32_t ContainerId;
- u_int32_t BlockNumber;
- u_int32_t ByteCount;
- AAC_CacheLevel Stable;
- struct aac_sg_table SgMap; /* variable size */
+ u_int32_t Command; /* not FSACommand! */
+ u_int32_t ContainerId;
+ u_int32_t BlockNumber;
+ u_int32_t ByteCount;
+ u_int32_t Stable;
+ struct aac_sg_table SgMap; /* variable size */
+} __attribute__ ((__packed__));
+
+struct aac_blockwrite64 {
+ u_int32_t Command; /* not FSACommand! */
+ u_int16_t ContainerId;
+ u_int16_t SectorCount;
+ u_int32_t BlockNumber;
+ u_int16_t Pad;
+ u_int16_t Flags;
+ struct aac_sg_table64 SgMap64; /* variable size */
} __attribute__ ((__packed__));
struct aac_blockwrite_response {
- AAC_FSAStatus Status;
- u_int32_t ByteCount;
- AAC_CommitLevel Committed;
+ u_int32_t Status;
+ u_int32_t ByteCount;
+ u_int32_t Committed;
} __attribute__ ((__packed__));
/*
+ * Container shutdown command.
+ */
+struct aac_close_command {
+ u_int32_t Command;
+ u_int32_t ContainerId;
+};
+
+/*
+ * SCSI Passthrough structures
+ */
+struct aac_srb32 {
+ u_int32_t function;
+ u_int32_t bus;
+ u_int32_t target;
+ u_int32_t lun;
+ u_int32_t timeout;
+ u_int32_t flags;
+ u_int32_t data_len;
+ u_int32_t retry_limit;
+ u_int32_t cdb_len;
+ u_int8_t cdb[16];
+ struct aac_sg_table sg_map32;
+};
+
+enum {
+ AAC_SRB_FUNC_EXECUTE_SCSI = 0x00,
+ AAC_SRB_FUNC_CLAIM_DEVICE,
+ AAC_SRB_FUNC_IO_CONTROL,
+ AAC_SRB_FUNC_RECEIVE_EVENT,
+ AAC_SRB_FUNC_RELEASE_QUEUE,
+ AAC_SRB_FUNC_ATTACH_DEVICE,
+ AAC_SRB_FUNC_RELEASE_DEVICE,
+ AAC_SRB_FUNC_SHUTDOWN,
+ AAC_SRB_FUNC_FLUSH,
+ AAC_SRB_FUNC_ABORT_COMMAND = 0x10,
+ AAC_SRB_FUNC_RELEASE_RECOVERY,
+ AAC_SRB_FUNC_RESET_BUS,
+ AAC_SRB_FUNC_RESET_DEVICE,
+ AAC_SRB_FUNC_TERMINATE_IO,
+ AAC_SRB_FUNC_FLUSH_QUEUE,
+ AAC_SRB_FUNC_REMOVE_DEVICE,
+ AAC_SRB_FUNC_DOMAIN_VALIDATION
+};
+
+#define AAC_SRB_FLAGS_NO_DATA_XFER 0x0000
+#define AAC_SRB_FLAGS_DISABLE_DISCONNECT 0x0004
+#define AAC_SRB_FLAGS_DISABLE_SYNC_TRANSFER 0x0008
+#define AAC_SRB_FLAGS_BYPASS_FROZEN_QUEUE 0x0010
+#define AAC_SRB_FLAGS_DISABLE_AUTOSENSE 0x0020
+#define AAC_SRB_FLAGS_DATA_IN 0x0040
+#define AAC_SRB_FLAGS_DATA_OUT 0x0080
+#define AAC_SRB_FLAGS_UNSPECIFIED_DIRECTION \
+ (AAC_SRB_FLAGS_DATA_IN | AAC_SRB_FLAGS_DATA_OUT)
+
+#define AAC_HOST_SENSE_DATA_MAX 30
+
+struct aac_srb_response {
+ u_int32_t fib_status;
+ u_int32_t srb_status;
+ u_int32_t scsi_status;
+ u_int32_t data_len;
+ u_int32_t sense_len;
+ u_int8_t sense[AAC_HOST_SENSE_DATA_MAX];
+};
+
+enum {
+ AAC_SRB_STS_PENDING = 0x00,
+ AAC_SRB_STS_SUCCESS,
+ AAC_SRB_STS_ABORTED,
+ AAC_SRB_STS_ABORT_FAILED,
+ AAC_SRB_STS_ERROR,
+ AAC_SRB_STS_BUSY,
+ AAC_SRB_STS_INVALID_REQUEST,
+ AAC_SRB_STS_INVALID_PATH_ID,
+ AAC_SRB_STS_NO_DEVICE,
+ AAC_SRB_STS_TIMEOUT,
+ AAC_SRB_STS_SELECTION_TIMEOUT,
+ AAC_SRB_STS_COMMAND_TIMEOUT,
+ AAC_SRB_STS_MESSAGE_REJECTED = 0x0D,
+ AAC_SRB_STS_BUS_RESET,
+ AAC_SRB_STS_PARITY_ERROR,
+ AAC_SRB_STS_REQUEST_SENSE_FAILED,
+ AAC_SRB_STS_NO_HBA,
+ AAC_SRB_STS_DATA_OVERRUN,
+ AAC_SRB_STS_UNEXPECTED_BUS_FREE,
+ AAC_SRB_STS_PHASE_SEQUENCE_FAILURE,
+ AAC_SRB_STS_BAD_SRB_BLOCK_LENGTH,
+ AAC_SRB_STS_REQUEST_FLUSHED,
+ AAC_SRB_STS_INVALID_LUN = 0x20,
+ AAC_SRB_STS_INVALID_TARGET_ID,
+ AAC_SRB_STS_BAD_FUNCTION,
+ AAC_SRB_STS_ERROR_RECOVERY
+};
+
+/*
+ * Register set for adapters based on the Falcon bridge and PPC core
+ */
+
+#define AAC_FA_DOORBELL0_CLEAR 0x00
+#define AAC_FA_DOORBELL1_CLEAR 0x02
+#define AAC_FA_DOORBELL0 0x04
+#define AAC_FA_DOORBELL1 0x06
+#define AAC_FA_MASK0_CLEAR 0x08
+#define AAC_FA_MASK1_CLEAR 0x0a
+#define AAC_FA_MASK0 0x0c
+#define AAC_FA_MASK1 0x0e
+#define AAC_FA_MAILBOX 0x10
+#define AAC_FA_FWSTATUS 0x2c /* Mailbox 7 */
+#define AAC_FA_INTSRC 0x900
+
+#define AAC_FA_HACK(sc) (void)AAC_GETREG4(sc, AAC_FA_INTSRC)
+
+/*
* Register definitions for the Adaptec AAC-364 'Jalapeno I/II' adapters, based
* on the SA110 'StrongArm'.
*/
-#define AAC_REGSIZE 0x100
+#define AAC_REGSIZE 0x100
-/* doorbell 0 (adapter->host) */
-#define AAC_SA_DOORBELL0_CLEAR 0x98
-#define AAC_SA_DOORBELL0_SET 0x9c
-#define AAC_SA_DOORBELL0 0x9c
-#define AAC_SA_MASK0_CLEAR 0xa0
-#define AAC_SA_MASK0_SET 0xa4
+#define AAC_SA_DOORBELL0_CLEAR 0x98 /* doorbell 0 (adapter->host) */
+#define AAC_SA_DOORBELL0_SET 0x9c
+#define AAC_SA_DOORBELL0 0x9c
+#define AAC_SA_MASK0_CLEAR 0xa0
+#define AAC_SA_MASK0_SET 0xa4
-/* doorbell 1 (host->adapter) */
-#define AAC_SA_DOORBELL1_CLEAR 0x9a
-#define AAC_SA_DOORBELL1_SET 0x9e
-#define AAC_SA_MASK1_CLEAR 0xa2
-#define AAC_SA_MASK1_SET 0xa6
+#define AAC_SA_DOORBELL1_CLEAR 0x9a /* doorbell 1 (host->adapter) */
+#define AAC_SA_DOORBELL1_SET 0x9e
+#define AAC_SA_DOORBELL1 0x9e
+#define AAC_SA_MASK1_CLEAR 0xa2
+#define AAC_SA_MASK1_SET 0xa6
-/* mailbox (20 bytes) */
-#define AAC_SA_MAILBOX 0xa8
-#define AAC_SA_FWSTATUS 0xc4
+#define AAC_SA_MAILBOX 0xa8 /* mailbox (20 bytes) */
+#define AAC_SA_FWSTATUS 0xc4
/*
- * Register definitions for the Adaptec 'Pablano' adapters, based on the
- * i960Rx, and other related adapters.
+ * Register definitions for the Adaptec 'Pablano' adapters, based on the i960Rx,
+ * and other related adapters.
*/
-#define AAC_RX_IDBR 0x20 /* inbound doorbell */
-#define AAC_RX_IISR 0x24 /* inbound interrupt status */
-#define AAC_RX_IIMR 0x28 /* inbound interrupt mask */
-#define AAC_RX_ODBR 0x2c /* outbound doorbell */
-#define AAC_RX_OISR 0x30 /* outbound interrupt status */
-#define AAC_RX_OIMR 0x34 /* outbound interrupt mask */
+#define AAC_RX_IDBR 0x20 /* inbound doorbell register */
+#define AAC_RX_IISR 0x24 /* inbound interrupt status register */
+#define AAC_RX_IIMR 0x28 /* inbound interrupt mask register */
+#define AAC_RX_ODBR 0x2c /* outbound doorbell register */
+#define AAC_RX_OISR 0x30 /* outbound interrupt status register */
+#define AAC_RX_OIMR 0x34 /* outbound interrupt mask register */
#define AAC_RX_MAILBOX 0x50 /* mailbox (20 bytes) */
#define AAC_RX_FWSTATUS 0x6c
@@ -539,182 +1362,13 @@ struct aac_blockwrite_response {
* DOORBELL0 and setting it in DOORBELL1.
* (ODBR and IDBR respectively for the i960Rx adapters)
*/
-#define AAC_DB_PRINTF (1<<5)
-
-/*
- * Mask containing the interrupt bits we care about. We don't anticipate
- * (or want) interrupts not in this mask.
- */
-#define AAC_DB_INTERRUPTS \
- (AAC_DB_COMMAND_READY | AAC_DB_RESPONSE_READY | AAC_DB_PRINTF)
-
-/*
- * Queue names
- *
- * Note that we base these at 0 in order to use them as array indices. Adaptec
- * used base 1 for some unknown reason, and sorted them in a different order.
- */
-#define AAC_HOST_NORM_CMD_QUEUE 0
-#define AAC_HOST_HIGH_CMD_QUEUE 1
-#define AAC_ADAP_NORM_CMD_QUEUE 2
-#define AAC_ADAP_HIGH_CMD_QUEUE 3
-#define AAC_HOST_NORM_RESP_QUEUE 4
-#define AAC_HOST_HIGH_RESP_QUEUE 5
-#define AAC_ADAP_NORM_RESP_QUEUE 6
-#define AAC_ADAP_HIGH_RESP_QUEUE 7
-
-/*
- * List structure used to chain FIBs (used by the adapter - we hang FIBs off
- * our private command structure and don't touch these)
- */
-struct aac_fib_list_entry {
- struct fib_list_entry *Flink;
- struct fib_list_entry *Blink;
-} __packed;
-
-/*
- * FIB (FSA Interface Block?); this is the datastructure passed between the
- * host and adapter.
- */
-struct aac_fib_header {
- u_int32_t XferState;
- u_int16_t Command;
- u_int8_t StructType;
- u_int8_t Flags;
- u_int16_t Size;
- u_int16_t SenderSize;
- u_int32_t SenderFibAddress;
- u_int32_t ReceiverFibAddress;
- u_int32_t SenderData;
- union {
- struct {
- u_int32_t ReceiverTimeStart;
- u_int32_t ReceiverTimeDone;
- } _s;
- struct aac_fib_list_entry FibLinks;
- } _u;
-} __packed;
-
-#define AAC_FIB_DATASIZE (512 - sizeof(struct aac_fib_header))
-
-struct aac_fib {
- struct aac_fib_header Header;
- u_int8_t data[AAC_FIB_DATASIZE];
-} __packed;
-
-/*
- * FIB commands
- */
-typedef enum {
- TestCommandResponse = 1,
- TestAdapterCommand = 2,
-
- /* lowlevel and comm commands */
- LastTestCommand = 100,
- ReinitHostNormCommandQueue = 101,
- ReinitHostHighCommandQueue = 102,
- ReinitHostHighRespQueue = 103,
- ReinitHostNormRespQueue = 104,
- ReinitAdapNormCommandQueue = 105,
- ReinitAdapHighCommandQueue = 107,
- ReinitAdapHighRespQueue = 108,
- ReinitAdapNormRespQueue = 109,
- InterfaceShutdown = 110,
- DmaCommandFib = 120,
- StartProfile = 121,
- TermProfile = 122,
- SpeedTest = 123,
- TakeABreakPt = 124,
- RequestPerfData = 125,
- SetInterruptDefTimer= 126,
- SetInterruptDefCount= 127,
- GetInterruptDefStatus= 128,
- LastCommCommand = 129,
-
- /* filesystem commands */
- NuFileSystem = 300,
- UFS = 301,
- HostFileSystem = 302,
- LastFileSystemCommand = 303,
-
- /* Container Commands */
- ContainerCommand = 500,
- ContainerCommand64 = 501,
-
- /* Cluster Commands */
- ClusterCommand = 550,
-
- /* Scsi Port commands (scsi passthrough) */
- ScsiPortCommand = 600,
-
- /* misc house keeping and generic adapter initiated commands */
- AifRequest = 700,
- CheckRevision = 701,
- FsaHostShutdown = 702,
- RequestAdapterInfo = 703,
- IsAdapterPaused = 704,
- SendHostTime = 705,
- LastMiscCommand = 706
-} AAC_FibCommands;
+#define AAC_DB_PRINTF (1<<5) /* adapter requests host printf */
+#define AAC_PRINTF_DONE (1<<5) /* Host completed printf processing */
/*
- * FIB types
- */
-#define AAC_FIBTYPE_TFIB 1
-#define AAC_FIBTYPE_TQE 2
-#define AAC_FIBTYPE_TCTPERF 3
-
-/*
- * FIB transfer state
+ * Mask containing the interrupt bits we care about. We don't anticipate (or
+ * want) interrupts not in this mask.
*/
-#define AAC_FIBSTATE_HOSTOWNED (1<<0) /* owned by the host */
-#define AAC_FIBSTATE_ADAPTEROWNED (1<<1) /* owned by the adapter */
-#define AAC_FIBSTATE_INITIALISED (1<<2) /* initialised */
-#define AAC_FIBSTATE_EMPTY (1<<3) /* empty */
-#define AAC_FIBSTATE_FROMPOOL (1<<4) /* allocated from pool */
-#define AAC_FIBSTATE_FROMHOST (1<<5) /* sent from the host */
-#define AAC_FIBSTATE_FROMADAP (1<<6) /* sent from the adapter */
-#define AAC_FIBSTATE_REXPECTED (1<<7) /* response is expected */
-#define AAC_FIBSTATE_RNOTEXPECTED (1<<8) /* response is not expected */
-#define AAC_FIBSTATE_DONEADAP (1<<9) /* processed by the adapter */
-#define AAC_FIBSTATE_DONEHOST (1<<10) /* processed by the host */
-#define AAC_FIBSTATE_HIGH (1<<11) /* high priority */
-#define AAC_FIBSTATE_NORM (1<<12) /* normal priority */
-#define AAC_FIBSTATE_ASYNC (1<<13)
-#define AAC_FIBSTATE_ASYNCIO (1<<13) /* to be removed */
-#define AAC_FIBSTATE_PAGEFILEIO (1<<14) /* to be removed */
-#define AAC_FIBSTATE_SHUTDOWN (1<<15)
-#define AAC_FIBSTATE_LAZYWRITE (1<<16) /* to be removed */
-#define AAC_FIBSTATE_ADAPMICROFIB (1<<17)
-#define AAC_FIBSTATE_BIOSFIB (1<<18)
-#define AAC_FIBSTATE_FAST_RESPONSE (1<<19) /* fast response capable */
-#define AAC_FIBSTATE_APIFIB (1<<20)
-
-/*
- * FIB error values
- */
-#define AAC_ERROR_NORMAL 0x00
-#define AAC_ERROR_PENDING 0x01
-#define AAC_ERROR_FATAL 0x02
-#define AAC_ERROR_INVALID_QUEUE 0x03
-#define AAC_ERROR_NOENTRIES 0x04
-#define AAC_ERROR_SENDFAILED 0x05
-#define AAC_ERROR_INVALID_QUEUE_PRIORITY 0x06
-#define AAC_ERROR_FIB_ALLOCATION_FAILED 0x07
-#define AAC_ERROR_FIB_DEALLOCATION_FAILED 0x08
-
-/*
- * Adapter Status Register
- *
- * Phase Staus mailbox is 32bits:
- * <31:16> = Phase Status
- * <15:0> = Phase
- *
- * The adapter reports its present state through the phase. Only
- * a single phase should be ever be set. Each phase can have multiple
- * phase status bits to provide more detailed information about the
- * state of the adapter.
- */
-#define AAC_SELF_TEST_FAILED 0x00000004
-#define AAC_UP_AND_RUNNING 0x00000080
-#define AAC_KERNEL_PANIC 0x00000100
+#define AAC_DB_INTERRUPTS (AAC_DB_COMMAND_READY | \
+ AAC_DB_RESPONSE_READY | \
+ AAC_DB_PRINTF)
diff --git a/sys/dev/ic/aacvar.h b/sys/dev/ic/aacvar.h
index e654d7595d6..2be60aba46a 100644
--- a/sys/dev/ic/aacvar.h
+++ b/sys/dev/ic/aacvar.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: aacvar.h,v 1.4 2003/10/21 18:58:48 jmc Exp $ */
+/* $OpenBSD: aacvar.h,v 1.5 2005/11/18 05:39:10 nate Exp $ */
/*-
* Copyright (c) 2000 Michael Smith
@@ -38,17 +38,29 @@
* - Niklas Hallqvist
*/
+/* compatability */
+#define time_second (mono_time.tv_sec)
+
/* Debugging */
+// #define AAC_DEBUG 0x0
+
#ifdef AAC_DEBUG
#define AAC_DPRINTF(mask, args) if (aac_debug & (mask)) printf args
-#define AAC_D_INTR 0x01
-#define AAC_D_MISC 0x02
-#define AAC_D_CMD 0x04
-#define AAC_D_QUEUE 0x08
-#define AAC_D_IO 0x10
+#define AAC_D_INTR 0x001
+#define AAC_D_MISC 0x002
+#define AAC_D_CMD 0x004
+#define AAC_D_QUEUE 0x008
+#define AAC_D_IO 0x010
+#define AAC_D_IOCTL 0x020
+#define AAC_D_LOCK 0x040
+#define AAC_D_THREAD 0x080
+#define AAC_D_FIB 0x100
extern int aac_debug;
-#define AAC_PRINT_FIB(sc, fib) aac_print_fib((sc), (fib), __func__)
+#define AAC_PRINT_FIB(sc, fib) do { \
+ if (aac_debug & AAC_D_FIB) \
+ aac_print_fib((sc), (fib), __func__); \
+} while (0)
#else
#define AAC_DPRINTF(mask, args)
#define AAC_PRINT_FIB(sc, fib)
@@ -67,6 +79,20 @@ struct aac_softc;
#define AAC_ADAPTER_FIBS 8
/*
+ * FIBs are allocated in page-size chunks and can grow up to the 512
+ * limit imposed by the hardware.
+ */
+#define AAC_FIB_COUNT (PAGE_SIZE/sizeof(struct aac_fib))
+#define AAC_MAX_FIBS 512
+#define AAC_FIBMAP_SIZE (PAGE_SIZE)
+
+/*
+ * The controller reports status events in AIFs. We hang on to a number of
+ * these in order to pass them out to user-space management tools.
+ */
+#define AAC_AIFQ_LENGTH 64
+
+/*
* Firmware messages are passed in the printf buffer.
*/
#define AAC_PRINTF_BUFSIZE 256
@@ -78,14 +104,25 @@ struct aac_softc;
#define AAC_BOOT_TIMEOUT (3 * 60)
/*
- * Wait this long for a lost interrupt to get detected.
+ * Timeout for immediate commands.
*/
-#define AAC_WATCH_TIMEOUT 10000 /* 10000 * 1ms = 10s */
+#define AAC_IMMEDIATE_TIMEOUT 30
/*
- * Timeout for immediate commands.
+ * Timeout for normal commands
*/
-#define AAC_IMMEDIATE_TIMEOUT 30
+#define AAC_CMD_TIMEOUT 30 /* seconds */
+
+/*
+ * Rate at which we periodically check for timed out commands and kick the
+ * controller.
+ */
+#define AAC_PERIODIC_INTERVAL 20 /* seconds */
+
+/*
+ * Wait this long for a lost interrupt to get detected.
+ */
+#define AAC_WATCH_TIMEOUT 10000 /* 10000 * 1ms = 10s */
/*
* Delay 20ms after the qnotify in sync operations. Experimentally deduced.
@@ -97,6 +134,7 @@ struct aac_softc;
* ourselves to a reasonable maximum and ensure alignment.
*/
#define AAC_MAXSGENTRIES 64 /* max S/G entries, limit 65535 */
+
/*
* We gather a number of adapter-visible items into a single structure.
*
@@ -126,6 +164,7 @@ struct aac_common {
/* fib for synchronous commands */
struct aac_fib ac_sync_fib;
};
+#define AAC_COMMON_ALLOCSIZE (8192 + sizeof(struct aac_common))
/*
* Interface operations
@@ -137,42 +176,63 @@ struct aac_interface {
void (*aif_set_istatus)(struct aac_softc *, int);
void (*aif_set_mailbox)(struct aac_softc *, u_int32_t,
u_int32_t, u_int32_t, u_int32_t, u_int32_t);
- int (*aif_get_mailboxstatus)(struct aac_softc *);
+ int (*aif_get_mailbox)(struct aac_softc *, int mb);
void (*aif_set_interrupts)(struct aac_softc *, int);
};
-extern struct aac_interface aac_rx_interface;
+extern struct aac_interface aac_fa_interface;
extern struct aac_interface aac_sa_interface;
+extern struct aac_interface aac_rx_interface;
-#define AAC_GET_FWSTATUS(sc) ((sc)->sc_if.aif_get_fwstatus(sc))
+#define AAC_GET_FWSTATUS(sc) ((sc)->aac_if.aif_get_fwstatus(sc))
#define AAC_QNOTIFY(sc, qbit) \
- ((sc)->sc_if.aif_qnotify((sc), (qbit)))
-#define AAC_GET_ISTATUS(sc) ((sc)->sc_if.aif_get_istatus(sc))
+ ((sc)->aac_if.aif_qnotify((sc), (qbit)))
+#define AAC_GET_ISTATUS(sc) ((sc)->aac_if.aif_get_istatus(sc))
#define AAC_CLEAR_ISTATUS(sc, mask) \
- ((sc)->sc_if.aif_set_istatus((sc), (mask)))
+ ((sc)->aac_if.aif_set_istatus((sc), (mask)))
#define AAC_SET_MAILBOX(sc, command, arg0, arg1, arg2, arg3) \
do { \
- ((sc)->sc_if.aif_set_mailbox((sc), (command), (arg0), \
+ ((sc)->aac_if.aif_set_mailbox((sc), (command), (arg0), \
(arg1), (arg2), (arg3))); \
} while(0)
-#define AAC_GET_MAILBOXSTATUS(sc) \
- ((sc)->sc_if.aif_get_mailboxstatus(sc))
+#define AAC_GET_MAILBOX(sc, mb) \
+ ((sc)->aac_if.aif_get_mailbox(sc, (mb)))
#define AAC_MASK_INTERRUPTS(sc) \
- ((sc)->sc_if.aif_set_interrupts((sc), 0))
+ ((sc)->aac_if.aif_set_interrupts((sc), 0))
#define AAC_UNMASK_INTERRUPTS(sc) \
- ((sc)->sc_if.aif_set_interrupts((sc), 1))
+ ((sc)->aac_if.aif_set_interrupts((sc), 1))
#define AAC_SETREG4(sc, reg, val) \
- bus_space_write_4((sc)->sc_memt, (sc)->sc_memh, (reg), (val))
+ bus_space_write_4((sc)->aac_memt, (sc)->aac_memh, (reg), (val))
#define AAC_GETREG4(sc, reg) \
- bus_space_read_4((sc)->sc_memt, (sc)->sc_memh, (reg))
+ bus_space_read_4((sc)->aac_memt, (sc)->aac_memh, (reg))
#define AAC_SETREG2(sc, reg, val) \
- bus_space_write_2((sc)->sc_memt, (sc)->sc_memh, (reg), (val))
+ bus_space_write_2((sc)->aac_memt, (sc)->aac_memh, (reg), (val))
#define AAC_GETREG2(sc, reg) \
- bus_space_read_2((sc)->sc_memt, (sc)->sc_memh, (reg))
+ bus_space_read_2((sc)->aac_memt, (sc)->aac_memh, (reg))
#define AAC_SETREG1(sc, reg, val) \
- bus_space_write_1((sc)->sc_memt, (sc)->sc_memh, (reg), (val))
+ bus_space_write_1((sc)->aac_memt, (sc)->aac_memh, (reg), (val))
#define AAC_GETREG1(sc, reg) \
- bus_space_read_1((sc)->sc_memt, (sc)->sc_memh, (reg))
+ bus_space_read_1((sc)->aac_memt, (sc)->aac_memh, (reg))
+
+/* Define the OS version specific locks */
+typedef struct rwlock aac_lock_t;
+#define AAC_LOCK_INIT(l, s) do { \
+ rw_init((l)); \
+ AAC_DPRINTF(AAC_D_LOCK, ("%s: init lock @%s: %d\n", \
+ sc->aac_dev.dv_xname, __FUNCTION__, __LINE__)); \
+} while (0)
+
+#define AAC_LOCK_ACQUIRE(l) do { \
+ AAC_DPRINTF(AAC_D_LOCK, ("%s: lock @%s: %d\n", \
+ sc->aac_dev.dv_xname, __FUNCTION__, __LINE__)); \
+ rw_enter_write((l)); \
+} while (0)
+
+#define AAC_LOCK_RELEASE(l) do { \
+ rw_exit_write((l)); \
+ AAC_DPRINTF(AAC_D_LOCK, ("%s: unlock @%s: %d\n", \
+ sc->aac_dev.dv_xname, __FUNCTION__, __LINE__)); \
+} while (0)
/*
* Per-container data structure
@@ -180,69 +240,136 @@ extern struct aac_interface aac_sa_interface;
struct aac_container
{
struct aac_mntobj co_mntobj;
- struct device co_disk;
+ int co_found;
+ TAILQ_ENTRY(aac_container) co_link;
};
/*
* A command contol block, one for each corresponding command index of the
* controller.
*/
-struct aac_ccb {
- TAILQ_ENTRY(aac_ccb) ac_chain;
- struct scsi_xfer *ac_xs;
- struct aac_fib *ac_fib; /* FIB associated with this command */
- bus_addr_t ac_fibphys; /* bus address of the FIB */
- bus_dmamap_t ac_dmamap_xfer;
- struct aac_sg_table *ac_sgtable;/* pointer to s/g table in command */
- int ac_timeout;
- u_int32_t ac_blockno;
- u_int32_t ac_blockcnt;
- u_int8_t ac_flags;
-#define AAC_ACF_WATCHDOG 0x1
-#define AAC_ACF_COMPLETED 0x2
+struct aac_command
+{
+ TAILQ_ENTRY(aac_command) cm_link; /* list linkage */
+
+ struct aac_softc *cm_sc; /* controller that owns us */
+
+ struct aac_fib *cm_fib; /* FIB for this command */
+ bus_addr_t cm_fibphys; /* bus address of the FIB */
+ void *cm_data;
+ size_t cm_datalen;
+ bus_dmamap_t cm_datamap;
+ struct aac_sg_table *cm_sgtable; /* pointer to s/g table */
+
+ u_int cm_flags;
+#define AAC_CMD_MAPPED (1<<0) /* command has had its data mapped */
+#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 */
+#define AAC_ON_AACQ_FREE (1<<5)
+#define AAC_ON_AACQ_READY (1<<6)
+#define AAC_ON_AACQ_BUSY (1<<7)
+#define AAC_ON_AACQ_BIO (1<<8)
+#define AAC_ON_AACQ_MASK ((1<<5)|(1<<6)|(1<<7)|(1<<8))
+#define AAC_QUEUE_FRZN (1<<9) /* Freeze the processing of
+ * commands on the queue. */
+#define AAC_ACF_WATCHDOG (1<<10)
+
+ void (*cm_complete)(struct aac_command *);
+ void *cm_private;
+ u_int32_t cm_blkno;
+ u_int32_t cm_bcount;
+ time_t cm_timestamp; /* command creation time */
+ int cm_queue;
+ int cm_index;
+};
+
+struct aac_fibmap {
+ TAILQ_ENTRY(aac_fibmap) fm_link; /* list linkage */
+ struct aac_fib *aac_fibs;
+ bus_dmamap_t aac_fibmap;
+ bus_dma_segment_t aac_seg;
+ int aac_nsegs;
+ struct aac_command *aac_commands;
+};
+
+/*
+ * Command queue statistics
+ */
+#define AACQ_FREE 0
+#define AACQ_BIO 1
+#define AACQ_READY 2
+#define AACQ_BUSY 3
+#define AACQ_COUNT 4 /* total number of queues */
+
+struct aac_qstat {
+ u_int32_t q_length;
+ u_int32_t q_max;
};
/*
* Per-controller structure.
*/
-struct aac_softc {
- struct device sc_dev;
- void *sc_ih;
- struct scsi_link sc_link; /* Virtual SCSI bus for cache devs */
+struct aac_softc
+{
+ struct device aac_dev;
+ void *aac_ih;
+ struct scsi_link aac_link; /* Virtual SCSI bus for cache devs */
- bus_space_tag_t sc_memt;
- bus_space_handle_t sc_memh;
- bus_dma_tag_t sc_dmat; /* parent DMA tag */
+ bus_space_tag_t aac_memt;
+ bus_space_handle_t aac_memh;
+ bus_dma_tag_t aac_dmat; /* parent DMA tag */
/* controller features, limits and status */
- int sc_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 sc_revision;
+ struct FsaRevision aac_revision;
- int sc_hwif; /* controller hardware interface */
+ int aac_hwif; /* controller hardware interface */
#define AAC_HWIF_I960RX 0
#define AAC_HWIF_STRONGARM 1
+#define AAC_HWIF_FALCON 2
+#define AAC_HWIF_UNKNOWN -1
+
+ struct aac_common *aac_common;
+ bus_dmamap_t aac_common_map;
+ u_int32_t aac_common_busaddr;
+ struct aac_interface aac_if;
- struct aac_common *sc_common;
- u_int32_t sc_common_busaddr;
- struct aac_interface sc_if;
+ /* command/fib resources */
+ TAILQ_HEAD(,aac_fibmap) aac_fibmap_tqh;
+ u_int total_fibs;
+ struct aac_command *aac_commands;
- /* XXX This should really be dynamic. It is very wasteful now. */
- struct aac_ccb sc_ccbs[AAC_ADAP_NORM_CMD_ENTRIES];
- TAILQ_HEAD(, aac_ccb) sc_free_ccb, sc_ccbq;
- /* commands on hold for controller resources */
- TAILQ_HEAD(, aac_ccb) sc_ready;
- /* commands which have been returned by the controller */
- TAILQ_HEAD(, aac_ccb) sc_completed;
- LIST_HEAD(, scsi_xfer) sc_queue;
- struct scsi_xfer *sc_queuelast;
+ /* command management */
+ 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_busy;
+ TAILQ_HEAD(,aac_command) aac_bio;
/* command management */
- struct aac_queue_table *sc_queues;
- struct aac_queue_entry *sc_qentries[AAC_QUEUE_COUNT];
+ 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 */
+ TAILQ_HEAD(,aac_container) 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;
+
+ aac_lock_t aac_io_lock;
struct {
u_int8_t hd_present;
@@ -260,19 +387,58 @@ struct aac_softc {
u_int8_t hd_ldr_no;
u_int8_t hd_rw_attribs;
u_int32_t hd_start_sec;
- } sc_hdr[AAC_MAX_CONTAINERS];
+ } aac_hdr[AAC_MAX_CONTAINERS];
+ int aac_container_count;
+
+ /* management interface */
+ aac_lock_t aac_aifq_lock;
+ struct aac_aif_command aac_aifq[AAC_AIFQ_LENGTH];
+ int aac_aifq_head;
+ int aac_aifq_tail;
+ struct selinfo aac_select;
+ struct proc *aifthread;
+ int aifflags;
+#define AAC_AIFFLAGS_RUNNING (1 << 0)
+#define AAC_AIFFLAGS_AIF (1 << 1)
+#define AAC_AIFFLAGS_EXIT (1 << 2)
+#define AAC_AIFFLAGS_EXITED (1 << 3)
+#define AAC_AIFFLAGS_COMPLETE (1 << 4)
+#define AAC_AIFFLAGS_PRINTF (1 << 5)
+#define AAC_AIFFLAGS_PENDING (AAC_AIFFLAGS_AIF | AAC_AIFFLAGS_COMPLETE | \
+ AAC_AIFFLAGS_PRINTF)
+
+ u_int32_t flags;
+#define AAC_FLAGS_PERC2QC (1 << 0)
+#define AAC_FLAGS_ENABLE_CAM (1 << 1) /* No SCSI passthrough */
+#define AAC_FLAGS_CAM_NORESET (1 << 2) /* Fake SCSI resets */
+#define AAC_FLAGS_CAM_PASSONLY (1 << 3) /* Only create pass devices */
+#define AAC_FLAGS_SG_64BIT (1 << 4) /* Use 64-bit S/G addresses */
+#define AAC_FLAGS_4GB_WINDOW (1 << 5) /* Device can access host mem
+ * 2GB-4GB range */
+#define AAC_FLAGS_NO4GB (1 << 6) /* Can't access host mem >2GB*/
+#define AAC_FLAGS_256FIBS (1 << 7) /* Can only do 256 commands */
+#define AAC_FLAGS_BROKEN_MEMMAP (1 << 8) /* Broken HostPhysMemPages */
+
+ u_int32_t supported_options;
+ int aac_max_fibs;
+ void *aac_sdh;
};
-/* XXX These have to become spinlocks in case of SMP */
-#define AAC_LOCK(sc) splbio()
-#define AAC_UNLOCK(sc, lock) splx(lock)
-typedef int aac_lock_t;
+/*
+ * Public functions
+ */
+extern int aac_wait_command(struct aac_command *, int);
+extern int aac_alloc_command(struct aac_softc *, struct aac_command **);
+extern void aac_release_command(struct aac_command *);
+extern int aac_alloc_sync_fib(struct aac_softc *, struct aac_fib **, int);
+extern void aac_release_sync_fib(struct aac_softc *);
+extern int aac_sync_fib(struct aac_softc *, u_int32_t, u_int32_t,
+ struct aac_fib *, u_int16_t);
void aacminphys(struct buf *);
int aac_attach(struct aac_softc *);
int aac_intr(void *);
-#ifdef __GNUC__
/* These all require correctly aligned buffers */
static __inline__ void aac_enc16(u_int8_t *, u_int16_t);
static __inline__ void aac_enc32(u_int8_t *, u_int32_t);
@@ -309,33 +475,121 @@ aac_dec32(addr)
return letoh32(*(u_int32_t *)addr);
}
-/*
- * Queue primitives
- *
- * These are broken out individually to make statistics gathering easier.
- */
+/* Declarations copied from aac.c */
+#ifdef AAC_DEBUG
+void aac_print_fib(struct aac_softc *, struct aac_fib *, const char *);
+void aac_print_aif(struct aac_softc *, struct aac_aif_command *);
+#endif
+void aac_handle_aif(struct aac_softc *, struct aac_fib *);
+
+
-static __inline__ void
-aac_enqueue_completed(struct aac_ccb *ccb)
-{
- struct aac_softc *sc = ccb->ac_xs->sc_link->adapter_softc;
- aac_lock_t lock;
- lock = AAC_LOCK(sc);
- TAILQ_INSERT_TAIL(&sc->sc_completed, ccb, ac_chain);
- AAC_UNLOCK(sc, lock);
-}
-static __inline__ struct aac_ccb *
-aac_dequeue_completed(struct aac_softc *sc)
+/*
+ * Queue primitives for driver queues.
+ */
+#define AACQ_ADD(sc, qname) \
+ do { \
+ struct aac_qstat *qs; \
+ \
+ 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) \
+{ \
+ AAC_DPRINTF(AAC_D_CMD, (": enqueue " #name)); \
+ if ((cm->cm_flags & AAC_ON_AACQ_MASK) != 0) { \
+ printf("command %p is on another queue, flags = %#x\n", \
+ cm, cm->cm_flags); \
+ panic("command is on another queue"); \
+ } \
+ TAILQ_INSERT_TAIL(&cm->cm_sc->aac_ ## name, cm, cm_link); \
+ cm->cm_flags |= AAC_ON_ ## index; \
+ AACQ_ADD(cm->cm_sc, index); \
+} \
+static __inline void \
+aac_requeue_ ## name (struct aac_command *cm) \
+{ \
+ AAC_DPRINTF(AAC_D_CMD, (": requeue " #name)); \
+ if ((cm->cm_flags & AAC_ON_AACQ_MASK) != 0) { \
+ printf("command %p is on another queue, flags = %#x\n", \
+ cm, cm->cm_flags); \
+ panic("command is on another queue"); \
+ } \
+ TAILQ_INSERT_HEAD(&cm->cm_sc->aac_ ## name, cm, cm_link); \
+ cm->cm_flags |= AAC_ON_ ## index; \
+ AACQ_ADD(cm->cm_sc, index); \
+} \
+static __inline struct aac_command * \
+aac_dequeue_ ## name (struct aac_softc *sc) \
+{ \
+ struct aac_command *cm; \
+ \
+ if ((cm = TAILQ_FIRST(&sc->aac_ ## name)) != NULL) { \
+ AAC_DPRINTF(AAC_D_CMD, (": dequeue " #name)); \
+ if ((cm->cm_flags & AAC_ON_ ## index) == 0) { \
+ printf("dequeue - command %p not in queue, flags = %#x, " \
+ "bit = %#x\n", cm, cm->cm_flags, \
+ AAC_ON_ ## index); \
+ panic("command not in queue"); \
+ } \
+ TAILQ_REMOVE(&sc->aac_ ## name, cm, cm_link); \
+ cm->cm_flags &= ~AAC_ON_ ## index; \
+ AACQ_REMOVE(sc, index); \
+ } \
+ return(cm); \
+} \
+static __inline void \
+aac_remove_ ## name (struct aac_command *cm) \
+{ \
+ AAC_DPRINTF(AAC_D_CMD, (": remove " #name)); \
+ if ((cm->cm_flags & AAC_ON_ ## index) == 0) { \
+ printf("remove - command %p not in queue, flags = %#x, " \
+ "bit = %#x\n", cm, cm->cm_flags, \
+ AAC_ON_ ## index); \
+ panic("command not in queue"); \
+ } \
+ TAILQ_REMOVE(&cm->cm_sc->aac_ ## name, cm, cm_link); \
+ cm->cm_flags &= ~AAC_ON_ ## index; \
+ AACQ_REMOVE(cm->cm_sc, index); \
+} \
+struct hack
+
+AACQ_COMMAND_QUEUE(free, AACQ_FREE);
+AACQ_COMMAND_QUEUE(ready, AACQ_READY);
+AACQ_COMMAND_QUEUE(busy, AACQ_BUSY);
+AACQ_COMMAND_QUEUE(bio, AACQ_BIO);
+
+static __inline void
+aac_print_printf(struct aac_softc *sc)
{
- struct aac_ccb *ccb;
- aac_lock_t lock;
-
- lock = AAC_LOCK(sc);
- if ((ccb = TAILQ_FIRST(&sc->sc_completed)) != NULL)
- TAILQ_REMOVE(&sc->sc_completed, ccb, ac_chain);
- AAC_UNLOCK(sc, lock);
- return (ccb);
+ /*
+ * XXX We have the ability to read the length of the printf string
+ * from out of the mailboxes.
+ */
+ printf("** %s: %.*s", sc->aac_dev.dv_xname, AAC_PRINTF_BUFSIZE,
+ sc->aac_common->ac_printf);
+ sc->aac_common->ac_printf[0] = 0;
+ AAC_QNOTIFY(sc, AAC_DB_PRINTF);
}
-#endif
diff --git a/sys/dev/pci/aac_pci.c b/sys/dev/pci/aac_pci.c
index 161b78354d2..f720476d938 100644
--- a/sys/dev/pci/aac_pci.c
+++ b/sys/dev/pci/aac_pci.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: aac_pci.c,v 1.15 2005/08/09 04:10:10 mickey Exp $ */
+/* $OpenBSD: aac_pci.c,v 1.16 2005/11/18 05:39:10 nate Exp $ */
/*-
* Copyright (c) 2000 Michael Smith
@@ -44,6 +44,8 @@
#include <sys/kernel.h>
#include <sys/malloc.h>
#include <sys/queue.h>
+#include <sys/select.h>
+#include <sys/rwlock.h>
#include <machine/bus.h>
#include <machine/endian.h>
@@ -162,12 +164,10 @@ struct aac_ident {
/* HP NetRAID-4M */
{ PCI_VENDOR_DEC, PCI_PRODUCT_DEC_CPQ42XX, PCI_VENDOR_HP,
PCI_PRODUCT_HP_NETRAID_4M, AAC_HWIF_STRONGARM },
- /* Adaptec ASR-2120S */
{ PCI_VENDOR_ADP2, PCI_PRODUCT_ADP2_ASR2200S, PCI_VENDOR_ADP2,
- PCI_PRODUCT_ADP2_AACASR2120S, AAC_HWIF_I960RX },
- /* Adaptec ASR-2200S */
+ PCI_PRODUCT_ADP2_ASR2120S, AAC_HWIF_I960RX },
{ PCI_VENDOR_ADP2, PCI_PRODUCT_ADP2_ASR2200S, PCI_VENDOR_ADP2,
- PCI_PRODUCT_ADP2_AACASR2200S, AAC_HWIF_I960RX },
+ PCI_PRODUCT_ADP2_ASR2200S, AAC_HWIF_I960RX },
{ 0, 0, 0, 0 }
};
@@ -250,8 +250,8 @@ aac_pci_attach(parent, self, aux)
* Map control/status registers.
*/
if (pci_mapreg_map(pa, PCI_MAPREG_START,
- PCI_MAPREG_TYPE_MEM | PCI_MAPREG_MEM_TYPE_32BIT, 0, &sc->sc_memt,
- &sc->sc_memh, &membase, &memsize, AAC_REGSIZE)) {
+ PCI_MAPREG_TYPE_MEM | PCI_MAPREG_MEM_TYPE_32BIT, 0, &sc->aac_memt,
+ &sc->aac_memh, &membase, &memsize, AAC_REGSIZE)) {
printf("can't find mem space\n");
goto bail_out;
}
@@ -262,9 +262,9 @@ aac_pci_attach(parent, self, aux)
goto bail_out;
}
intrstr = pci_intr_string(pc, ih);
- sc->sc_ih = pci_intr_establish(pc, ih, IPL_BIO, aac_intr, sc,
- sc->sc_dev.dv_xname);
- if (sc->sc_ih == NULL) {
+ sc->aac_ih = pci_intr_establish(pc, ih, IPL_BIO, aac_intr, sc,
+ sc->aac_dev.dv_xname);
+ if (sc->aac_ih == NULL) {
printf("couldn't establish interrupt");
if (intrstr != NULL)
printf(" at %s", intrstr);
@@ -275,25 +275,30 @@ aac_pci_attach(parent, self, aux)
if (intrstr != NULL)
printf("%s\n", intrstr);
- sc->sc_dmat = pa->pa_dmat;
+ sc->aac_dmat = pa->pa_dmat;
for (m = aac_identifiers; m->vendor != 0; m++)
if (m->vendor == PCI_VENDOR(pa->pa_id) &&
m->device == PCI_PRODUCT(pa->pa_id)) {
if (m->subvendor == PCI_VENDOR(subsysid) &&
m->subdevice == PCI_PRODUCT(subsysid)) {
- sc->sc_hwif = m->hwif;
- switch(sc->sc_hwif) {
+ sc->aac_hwif = m->hwif;
+ switch(sc->aac_hwif) {
case AAC_HWIF_I960RX:
AAC_DPRINTF(AAC_D_MISC,
("set hardware up for i960Rx"));
- sc->sc_if = aac_rx_interface;
+ sc->aac_if = aac_rx_interface;
break;
case AAC_HWIF_STRONGARM:
AAC_DPRINTF(AAC_D_MISC,
("set hardware up for StrongARM"));
- sc->sc_if = aac_sa_interface;
+ sc->aac_if = aac_sa_interface;
+ break;
+ case AAC_HWIF_FALCON:
+ AAC_DPRINTF(AAC_D_MISC,
+ ("set hardware up for Falcon/PPC"));
+ sc->aac_if = aac_fa_interface;
break;
}
break;
@@ -307,8 +312,8 @@ aac_pci_attach(parent, self, aux)
bail_out:
if (state > 1)
- pci_intr_disestablish(pc, sc->sc_ih);
+ pci_intr_disestablish(pc, sc->aac_ih);
if (state > 0)
- bus_space_unmap(sc->sc_memt, sc->sc_memh, memsize);
+ bus_space_unmap(sc->aac_memt, sc->aac_memh, memsize);
return;
}