aac(4) sync with FreeBSD

Peter Avalos pavalos at theshell.com
Sun Jan 13 09:35:55 PST 2008


Here's a patch that syncs the aac(4) driver with FreeBSD.  I don't have
the hardware to test this, but I need some of these changes before I can
progress with CAM.  Please provide comments, and please test if you have
the hardware.  I plan on comitting this next weekend.

--Peter

http://www.theshell.com/~pavalos/wip/aac.patch
Major sync with FreeBSD.
diff --git a/sys/dev/raid/aac/aac.c b/sys/dev/raid/aac/aac.c
index d5e6809..4234a75 100644
--- a/sys/dev/raid/aac/aac.c
+++ b/sys/dev/raid/aac/aac.c
@@ -33,6 +33,8 @@
 /*
  * Driver for the Adaptec 'FSA' family of PCI/SCSI RAID adapters.
  */
+#define AAC_DRIVER_VERSION		0x02000000
+#define AAC_DRIVERNAME			"aac"
 
 #include "opt_aac.h"
 
@@ -44,13 +46,6 @@
 #include <sys/kthread.h>
 #include <sys/sysctl.h>
 #include <sys/poll.h>
-#if defined(__FreeBSD__) && __FreeBSD_version >= 500005
-#include <sys/selinfo.h>
-#else
-#include <sys/select.h>
-#endif
-
-#include "aac_compat.h"
 
 #include <sys/bus.h>
 #include <sys/conf.h>
@@ -59,12 +54,15 @@
 #include <sys/signalvar.h>
 #include <sys/time.h>
 #include <sys/eventhandler.h>
+#include <sys/rman.h>
+
+#include <bus/pci/pcireg.h>
+#include <bus/pci/pcivar.h>
 
 #include "aacreg.h"
 #include "aac_ioctl.h"
 #include "aacvar.h"
 #include "aac_tables.h"
-#include "aac_cam.h"
 
 static void	aac_startup(void *arg);
 static void	aac_add_container(struct aac_softc *sc,
@@ -74,20 +72,20 @@ static int	aac_shutdown(device_t dev);
 
 /* Command Processing */
 static void	aac_timeout(void *ssc);
-static int	aac_start(struct aac_command *cm);
+static int	aac_map_command(struct aac_command *cm);
 static void	aac_complete(void *context, int pending);
 static int	aac_bio_command(struct aac_softc *sc, struct aac_command **cmp);
 static void	aac_bio_complete(struct aac_command *cm);
-static int	aac_wait_command(struct aac_command *cm, int timeout);
-static void	aac_host_command(struct aac_softc *sc);
-static void	aac_host_response(struct aac_softc *sc);
+static int	aac_wait_command(struct aac_command *cm);
+static void	aac_command_thread(struct aac_softc *sc);
 
 /* Command Buffer Management */
+static void	aac_map_command_sg(void *arg, bus_dma_segment_t *segs,
+				   int nseg, int error);
 static void	aac_map_command_helper(void *arg, bus_dma_segment_t *segs,
 				       int nseg, int error);
 static int	aac_alloc_commands(struct aac_softc *sc);
 static void	aac_free_commands(struct aac_softc *sc);
-static void	aac_map_command(struct aac_command *cm);
 static void	aac_unmap_command(struct aac_command *cm);
 
 /* Hardware Interface */
@@ -123,7 +121,8 @@ struct aac_interface aac_fa_interface = {
 	aac_fa_clear_istatus,
 	aac_fa_set_mailbox,
 	aac_fa_get_mailbox,
-	aac_fa_set_interrupts
+	aac_fa_set_interrupts,
+	NULL, NULL, NULL
 };
 
 /* StrongARM interface */
@@ -144,10 +143,11 @@ struct aac_interface aac_sa_interface = {
 	aac_sa_clear_istatus,
 	aac_sa_set_mailbox,
 	aac_sa_get_mailbox,
-	aac_sa_set_interrupts
+	aac_sa_set_interrupts,
+	NULL, NULL, NULL
 };
 
-/* i960Rx interface */	
+/* i960Rx interface */
 static int	aac_rx_get_fwstatus(struct aac_softc *sc);
 static void	aac_rx_qnotify(struct aac_softc *sc, int qbit);
 static int	aac_rx_get_istatus(struct aac_softc *sc);
@@ -157,6 +157,9 @@ static void	aac_rx_set_mailbox(struct aac_softc *sc, u_int32_t command,
 				   u_int32_t arg2, u_int32_t arg3);
 static int	aac_rx_get_mailbox(struct aac_softc *sc, int mb);
 static void	aac_rx_set_interrupts(struct aac_softc *sc, int enable);
+static int aac_rx_send_command(struct aac_softc *sc, struct aac_command *cm);
+static int aac_rx_get_outb_queue(struct aac_softc *sc);
+static void aac_rx_set_outb_queue(struct aac_softc *sc, int index);
 
 struct aac_interface aac_rx_interface = {
 	aac_rx_get_fwstatus,
@@ -165,7 +168,37 @@ struct aac_interface aac_rx_interface = {
 	aac_rx_clear_istatus,
 	aac_rx_set_mailbox,
 	aac_rx_get_mailbox,
-	aac_rx_set_interrupts
+	aac_rx_set_interrupts,
+	aac_rx_send_command,
+	aac_rx_get_outb_queue,
+	aac_rx_set_outb_queue
+};
+
+/* Rocket/MIPS interface */
+static int	aac_rkt_get_fwstatus(struct aac_softc *sc);
+static void	aac_rkt_qnotify(struct aac_softc *sc, int qbit);
+static int	aac_rkt_get_istatus(struct aac_softc *sc);
+static void	aac_rkt_clear_istatus(struct aac_softc *sc, int mask);
+static void	aac_rkt_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);
+static int	aac_rkt_get_mailbox(struct aac_softc *sc, int mb);
+static void	aac_rkt_set_interrupts(struct aac_softc *sc, int enable);
+static int aac_rkt_send_command(struct aac_softc *sc, struct aac_command *cm);
+static int aac_rkt_get_outb_queue(struct aac_softc *sc);
+static void aac_rkt_set_outb_queue(struct aac_softc *sc, int index);
+
+struct aac_interface aac_rkt_interface = {
+	aac_rkt_get_fwstatus,
+	aac_rkt_qnotify,
+	aac_rkt_get_istatus,
+	aac_rkt_clear_istatus,
+	aac_rkt_set_mailbox,
+	aac_rkt_get_mailbox,
+	aac_rkt_set_interrupts,
+	aac_rkt_send_command,
+	aac_rkt_get_outb_queue,
+	aac_rkt_set_outb_queue
 };
 
 /* Debugging and Diagnostics */
@@ -178,13 +211,16 @@ static d_open_t		aac_open;
 static d_close_t	aac_close;
 static d_ioctl_t	aac_ioctl;
 static d_poll_t		aac_poll;
-static int		aac_ioctl_sendfib(struct aac_softc *sc, caddr_t ufib);
+static int		aac_ioctl_sendfib(struct aac_softc *sc, caddr_t ufib) __unused;
 static void		aac_handle_aif(struct aac_softc *sc,
 					   struct aac_fib *fib);
 static int		aac_rev_check(struct aac_softc *sc, caddr_t udata);
 static int		aac_getnext_aif(struct aac_softc *sc, caddr_t arg);
 static int		aac_return_aif(struct aac_softc *sc, caddr_t uptr);
 static int		aac_query_disk(struct aac_softc *sc, caddr_t uptr);
+static int		aac_get_pci_info(struct aac_softc *sc, caddr_t uptr);
+static void		aac_ioctl_event(struct aac_softc *sc,
+				        struct aac_event *event, void *arg);
 
 #define AAC_CDEV_MAJOR	150
 
@@ -227,15 +263,10 @@ aac_attach(struct aac_softc *sc)
 	aac_initq_complete(sc);
 	aac_initq_bio(sc);
 
-#if defined(__FreeBSD__) && __FreeBSD_version >= 500005
 	/*
 	 * Initialise command-completion task.
 	 */
 	TASK_INIT(&sc->aac_task_complete, 0, aac_complete, sc);
-#endif
-
-	/* disable interrupts before we enable anything */
-	AAC_MASK_INTERRUPTS(sc);
 
 	/* mark controller as suspended until we get ourselves organised */
 	sc->aac_state |= AAC_STATE_SUSPEND;
@@ -246,8 +277,18 @@ aac_attach(struct aac_softc *sc)
 	if ((error = aac_check_firmware(sc)) != 0)
 		return(error);
 
-	/* Init the sync fib lock */
-	AAC_LOCK_INIT(&sc->aac_sync_lock, "AAC sync FIB lock");
+	/*
+	 * Initialize locks
+	 */
+	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);
+	TAILQ_INIT(&sc->aac_ev_cmfree);
+
+
+	/* Initialize the local AIF queue pointers */
+	sc->aac_aifq_head = sc->aac_aifq_tail = AAC_AIFQ_LENGTH;
 
 	/*
 	 * Initialise the adapter.
@@ -255,22 +296,48 @@ aac_attach(struct aac_softc *sc)
 	if ((error = aac_init(sc)) != 0)
 		return(error);
 
-	/* 
-	 * Print a little information about the controller.
+	/*
+	 * Allocate and connect our interrupt.
 	 */
-	aac_describe_controller(sc);
+	sc->aac_irq_rid = 0;
+	if ((sc->aac_irq = bus_alloc_resource_any(sc->aac_dev, SYS_RES_IRQ,
+			   			  &sc->aac_irq_rid,
+			   			  RF_SHAREABLE |
+						  RF_ACTIVE)) == NULL) {
+		device_printf(sc->aac_dev, "can't allocate interrupt\n");
+		return (EINVAL);
+	}
+	if (sc->flags & AAC_FLAGS_NEW_COMM) {
+		if (bus_setup_intr(sc->aac_dev, sc->aac_irq,
+				   INTR_MPSAFE, aac_new_intr,
+				   sc, &sc->aac_intr, NULL)) {
+			device_printf(sc->aac_dev, "can't set up interrupt\n");
+			return (EINVAL);
+		}
+	} else {
+		if (bus_setup_intr(sc->aac_dev, sc->aac_irq,
+				   INTR_FAST, aac_fast_intr,
+				   sc, &sc->aac_intr, NULL)) {
+			device_printf(sc->aac_dev,
+				      "can't set up FAST interrupt\n");
+			if (bus_setup_intr(sc->aac_dev, sc->aac_irq,
+					   INTR_MPSAFE, aac_fast_intr,
+					   sc, &sc->aac_intr, NULL)) {
+				device_printf(sc->aac_dev,
+					     "can't set up MPSAFE interrupt\n");
+				return (EINVAL);
+			}
+		}
+	}
 
 	/*
-	 * Register to probe our containers later.
+	 * Print a little information about the controller.
 	 */
-	TAILQ_INIT(&sc->aac_container_tqh);
-	AAC_LOCK_INIT(&sc->aac_container_lock, "AAC container lock");
+	aac_describe_controller(sc);
 
 	/*
-	 * Lock for the AIF queue
+	 * Register to probe our containers later.
 	 */
-	AAC_LOCK_INIT(&sc->aac_aifq_lock, "AAC AIF lock");
-
 	sc->aac_ich.ich_func = aac_startup;
 	sc->aac_ich.ich_arg = sc;
 	sc->aac_ich.ich_desc = "aac";
@@ -285,37 +352,48 @@ aac_attach(struct aac_softc *sc)
 	 */
 	unit = device_get_unit(sc->aac_dev);
 	dev_ops_add(&aac_ops, -1, unit);
-	sc->aac_dev_t = make_dev(&aac_ops, unit, UID_ROOT, GID_WHEEL, 0644,
+	sc->aac_dev_t = make_dev(&aac_ops, unit, UID_ROOT, GID_OPERATOR, 0640,
 				 "aac%d", unit);
-#if defined(__FreeBSD__) && __FreeBSD_version > 500005
-	(void)make_dev_alias(sc->aac_dev_t, "afa%d", unit);
-	(void)make_dev_alias(sc->aac_dev_t, "hpn%d", unit);
-#endif
 	sc->aac_dev_t->si_drv1 = sc;
 	reference_dev(sc->aac_dev_t);
 
 	/* Create the AIF thread */
-#if defined(__FreeBSD__) && __FreeBSD_version > 500005
-	if (kthread_create((void(*)(void *))aac_host_command, sc,
-			   &sc->aifthread, 0, "aac%daif", unit))
-#else
-	if (kthread_create((void(*)(void *))aac_host_command, sc,
+	if (kthread_create((void(*)(void *))aac_command_thread, sc,
 			   &sc->aifthread, "aac%daif", unit))
-#endif
 		panic("Could not create AIF thread\n");
 
 	/* Register the shutdown method to only be called post-dump */
-	if ((EVENTHANDLER_REGISTER(shutdown_post_sync, aac_shutdown, sc->aac_dev,
-				   SHUTDOWN_PRI_DRIVER)) == NULL)
-	device_printf(sc->aac_dev, "shutdown event registration failed\n");
+	if ((sc->eh = EVENTHANDLER_REGISTER(shutdown_post_sync, aac_shutdown,
+	    sc->aac_dev, SHUTDOWN_PRI_DRIVER)) == NULL)
+		device_printf(sc->aac_dev,
+			      "shutdown event registration failed\n");
 
 	/* Register with CAM for the non-DASD devices */
-	if ((sc->flags & AAC_FLAGS_ENABLE_CAM) != 0)
+	if ((sc->flags & AAC_FLAGS_ENABLE_CAM) != 0) {
+		TAILQ_INIT(&sc->aac_sim_tqh);
 		aac_get_bus_info(sc);
+	}
 
 	return(0);
 }
 
+void
+aac_add_event(struct aac_softc *sc, struct aac_event *event)
+{
+
+	switch (event->ev_type & AAC_EVENT_MASK) {
+	case AAC_EVENT_CMFREE:
+		TAILQ_INSERT_TAIL(&sc->aac_ev_cmfree, event, ev_links);
+		break;
+	default:
+		device_printf(sc->aac_dev, "aac_add event: unknown event %d\n",
+		    event->ev_type);
+		break;
+	}
+
+	return;
+}
+
 /*
  * Probe for containers, create disks.
  */
@@ -335,7 +413,8 @@ aac_startup(void *arg)
 	/* disconnect ourselves from the intrhook chain */
 	config_intrhook_disestablish(&sc->aac_ich);
 
-	aac_alloc_sync_fib(sc, &fib, 0);
+	AAC_LOCK_ACQUIRE(&sc->aac_io_lock);
+	aac_alloc_sync_fib(sc, &fib);
 	mi = (struct aac_mntinfo *)&fib->data[0];
 
 	/* loop over possible containers */
@@ -361,6 +440,7 @@ aac_startup(void *arg)
 	} while ((i < count) && (i < AAC_MAX_CONTAINERS));
 
 	aac_release_sync_fib(sc);
+	AAC_LOCK_RELEASE(&sc->aac_io_lock);
 
 	/* poke the bus to actually attach the child devices */
 	if (bus_generic_attach(sc->aac_dev))
@@ -371,10 +451,6 @@ aac_startup(void *arg)
 
 	/* enable interrupts now */
 	AAC_UNMASK_INTERRUPTS(sc);
-
-	/* enable the timeout watchdog */
-	callout_reset(&sc->aac_watchdog, AAC_PERIODIC_INTERVAL * hz,
-		      aac_timeout, sc);
 }
 
 /*
@@ -386,18 +462,18 @@ aac_add_container(struct aac_softc *sc, struct aac_mntinforesp *mir, int f)
 	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)) {
-		MALLOC(co, struct aac_container *, sizeof *co, M_AACBUF,
-		       M_INTWAIT);
-		debug(1, "id %x  name '%.16s'  size %u  type %d", 
+		co = (struct aac_container *)kmalloc(sizeof *co, M_AACBUF,
+		       M_INTWAIT | M_ZERO);
+		debug(1, "id %x  name '%.16s'  size %u  type %d",
 		      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)
 			device_printf(sc->aac_dev, "device_add_child failed\n");
 		else
@@ -422,6 +498,7 @@ aac_add_container(struct aac_softc *sc, struct aac_mntinforesp *mir, int f)
 void
 aac_free(struct aac_softc *sc)
 {
+
 	debug_called(1);
 
 	/* remove the control device */
@@ -429,11 +506,12 @@ aac_free(struct aac_softc *sc)
 		destroy_dev(sc->aac_dev_t);
 
 	/* throw away any FIB buffers, discard the FIB DMA tag */
-	if (sc->aac_fibs != NULL)
-		aac_free_commands(sc);
+	aac_free_commands(sc);
 	if (sc->aac_fib_dmat)
 		bus_dma_tag_destroy(sc->aac_fib_dmat);
 
+	kfree(sc->aac_commands, M_AACBUF);
+
 	/* destroy the common area */
 	if (sc->aac_common) {
 		bus_dmamap_unload(sc->aac_common_dmat, sc->aac_common_dmamap);
@@ -473,9 +551,9 @@ int
 aac_detach(device_t dev)
 {
 	struct aac_softc *sc;
-#if AAC_BROKEN
+	struct aac_container *co;
+	struct aac_sim	*sim;
 	int error;
-#endif
 
 	debug_called(1);
 
@@ -484,9 +562,26 @@ aac_detach(device_t dev)
 	callout_stop(&sc->aac_watchdog);
 
 	if (sc->aac_state & AAC_STATE_OPEN)
-	return(EBUSY);
+		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);
+		kfree(co, M_AACBUF);
+	}
+
+	/* 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);
+		kfree(sim, M_AACBUF);
+	}
 
-#if AAC_BROKEN
 	if (sc->aifflags & AAC_AIFFLAGS_RUNNING) {
 		sc->aifflags |= AAC_AIFFLAGS_EXIT;
 		wakeup(sc->aifthread);
@@ -499,12 +594,15 @@ aac_detach(device_t dev)
 	if ((error = aac_shutdown(dev)))
 		return(error);
 
+	EVENTHANDLER_DEREGISTER(shutdown_post_sync, sc->eh);
+
 	aac_free(sc);
 
+	lockuninit(&sc->aac_aifq_lock);
+	lockuninit(&sc->aac_io_lock);
+	lockuninit(&sc->aac_container_lock);
+
 	return(0);
-#else
-	return (EBUSY);
-#endif
 }
 
 /*
@@ -526,18 +624,17 @@ aac_shutdown(device_t dev)
 
 	sc = device_get_softc(dev);
 
-	crit_enter();
-
 	sc->aac_state |= AAC_STATE_SUSPEND;
 
-	/* 
+	/*
 	 * 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);
+	AAC_LOCK_ACQUIRE(&sc->aac_io_lock);
+	aac_alloc_sync_fib(sc, &fib);
 	cc = (struct aac_close_command *)&fib->data[0];
 
 	bzero(cc, sizeof(struct aac_close_command));
@@ -546,6 +643,9 @@ aac_shutdown(device_t dev)
 	if (aac_sync_fib(sc, ContainerCommand, 0, fib,
 	    sizeof(struct aac_close_command)))
 		kprintf("FAILED.\n");
+	else
+		kprintf("done\n");
+#if 0
 	else {
 		fib->data[0] = 0;
 		/*
@@ -561,10 +661,12 @@ aac_shutdown(device_t dev)
 			kprintf("done.\n");
 		}
 	}
+#endif
 
 	AAC_MASK_INTERRUPTS(sc);
+	aac_release_sync_fib(sc);
+	AAC_LOCK_RELEASE(&sc->aac_io_lock);
 
-	crit_exit();
 	return(0);
 }
 
@@ -580,12 +682,9 @@ aac_suspend(device_t dev)
 
 	sc = device_get_softc(dev);
 
-	crit_enter();
-
 	sc->aac_state |= AAC_STATE_SUSPEND;
-	
+
 	AAC_MASK_INTERRUPTS(sc);
-	crit_exit();
 	return(0);
 }
 
@@ -607,48 +706,122 @@ aac_resume(device_t dev)
 }
 
 /*
- * Take an interrupt.
+ * Interrupt handler for NEW_COMM interface.
  */
 void
-aac_intr(void *arg)
+aac_new_intr(void *arg)
+{
+	struct aac_softc *sc;
+	u_int32_t index, fast;
+	struct aac_command *cm;
+	struct aac_fib *fib;
+	int i;
+
+	debug_called(2);
+
+	sc = (struct aac_softc *)arg;
+
+	AAC_LOCK_ACQUIRE(&sc->aac_io_lock);
+	while (1) {
+		index = AAC_GET_OUTB_QUEUE(sc);
+		if (index == 0xffffffff)
+			index = AAC_GET_OUTB_QUEUE(sc);
+		if (index == 0xffffffff)
+			break;
+		if (index & 2) {
+			if (index == 0xfffffffe) {
+				/* XXX This means that the controller wants
+				 * more work.  Ignore it for now.
+				 */
+				continue;
+			}
+			/* AIF */
+			fib = (struct aac_fib *)kmalloc(sizeof *fib, M_AACBUF,
+				   M_INTWAIT | M_ZERO);
+			index &= ~2;
+			for (i = 0; i < sizeof(struct aac_fib)/4; ++i)
+				((u_int32_t *)fib)[i] = AAC_GETREG4(sc, index + i*4);
+			aac_handle_aif(sc, fib);
+			kfree(fib, M_AACBUF);
+
+			/*
+			 * AIF memory is owned by the adapter, so let it
+			 * know that we are done with it.
+			 */
+			AAC_SET_OUTB_QUEUE(sc, index);
+			AAC_CLEAR_ISTATUS(sc, AAC_DB_RESPONSE_READY);
+		} else {
+			fast = index & 1;
+			cm = sc->aac_commands + (index >> 2);
+			fib = cm->cm_fib;
+			if (fast) {
+				fib->Header.XferState |= AAC_FIBSTATE_DONEADAP;
+				*((u_int32_t *)(fib->data)) = AAC_ERROR_NORMAL;
+			}
+			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 {
+				/* assume that someone is sleeping on this
+				 * command
+				 */
+				wakeup(cm);
+			}
+			sc->flags &= ~AAC_QUEUE_FRZN;
+		}
+	}
+	/* see if we can start some more I/O */
+	if ((sc->flags & AAC_QUEUE_FRZN) == 0)
+		aac_startio(sc);
+
+	AAC_LOCK_RELEASE(&sc->aac_io_lock);
+}
+
+void
+aac_fast_intr(void *arg)
 {
 	struct aac_softc *sc;
 	u_int16_t reason;
-	u_int32_t *resp_queue;
 
 	debug_called(2);
 
 	sc = (struct aac_softc *)arg;
 
 	/*
-	 * Optimize the common case of adapter response interrupts.
-	 * We must read from the card prior to processing the responses
-	 * to ensure the clear is flushed prior to accessing the queues.
-	 * Reading the queues from local memory might save us a PCI read.
+	 * 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.
 	 */
-	resp_queue = sc->aac_queues->qt_qindex[AAC_HOST_NORM_RESP_QUEUE];
-	if (resp_queue[AAC_PRODUCER_INDEX] != resp_queue[AAC_CONSUMER_INDEX])
-		reason = AAC_DB_RESPONSE_READY;
-	else 
-		reason = AAC_GET_ISTATUS(sc);
+	reason = AAC_GET_ISTATUS(sc);
 	AAC_CLEAR_ISTATUS(sc, reason);
-	(void)AAC_GET_ISTATUS(sc);
 
-	/* It's not ok to return here because of races with the previous step */
+	/* handle completion processing */
 	if (reason & AAC_DB_RESPONSE_READY)
-		aac_host_response(sc);
+		taskqueue_enqueue(taskqueue_swi, &sc->aac_task_complete);
 
-	/* controller wants to talk to the log */
-	if (reason & AAC_DB_PRINTF)
-		aac_print_printf(sc);
+	/* controller wants to talk to us */
+	if (reason & (AAC_DB_PRINTF | AAC_DB_COMMAND_READY)) {
+		/*
+		 * XXX Make sure that we don't get fooled by strange messages
+		 * that start with a NULL.
+		 */
+		if ((reason & AAC_DB_PRINTF) &&
+			(sc->aac_common->ac_printf[0] == 0))
+			sc->aac_common->ac_printf[0] = 32;
 
-	/* controller has a message for us? */
-	if (reason & AAC_DB_COMMAND_READY) {
-		/* XXX What happens if the thread is already awake? */
-		if (sc->aifflags & AAC_AIFFLAGS_RUNNING) {
-			sc->aifflags |= AAC_AIFFLAGS_PENDING;
-			wakeup(sc->aifthread);
-		}
+		/*
+		 * 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.
+		 */
+		wakeup(sc->aifthread);
 	}
 }
 
@@ -666,15 +839,18 @@ aac_startio(struct aac_softc *sc)
 
 	debug_called(2);
 
+	if (sc->flags & AAC_QUEUE_FRZN)
+		return;
+
 	for (;;) {
 		/*
-		 * Try to get a command that's been put off for lack of 
+		 * 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 
+		 * Try to build a command off the bio queue (ignore error
 		 * return)
 		 */
 		if (cm == NULL)
@@ -684,12 +860,12 @@ aac_startio(struct aac_softc *sc)
 		if (cm == NULL)
 			break;
 
-		/* try to give the command to the controller */
-		if (aac_start(cm) == EBUSY) {
-			/* put it on the ready queue for later */
-			aac_requeue_ready(cm);
-			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);
 	}
 }
 
@@ -698,7 +874,7 @@ aac_startio(struct aac_softc *sc)
  * last moment when possible.
  */
 static int
-aac_start(struct aac_command *cm)
+aac_map_command(struct aac_command *cm)
 {
 	struct aac_softc *sc;
 	int error;
@@ -706,48 +882,88 @@ aac_start(struct aac_command *cm)
 	debug_called(2);
 
 	sc = cm->cm_sc;
+	error = 0;
 
-	/* get the command mapped */
-	aac_map_command(cm);
-
-	/* fix up the address values in the FIB */
-	cm->cm_fib->Header.SenderFibAddress = (u_int32_t)cm->cm_fib;
-	cm->cm_fib->Header.ReceiverFibAddress = cm->cm_fibphys;
+	/* don't map more than once */
+	if (cm->cm_flags & AAC_CMD_MAPPED)
+		panic("aac: command %p already mapped", cm);
 
-	/* save a pointer to the command for speedy reverse-lookup */
-	cm->cm_fib->Header.SenderData = (u_int32_t)cm;	/* XXX 64-bit physical
-							 * address issue */
-	/* put the FIB on the outbound queue */
-	error = aac_enqueue_fib(sc, cm->cm_queue, cm);
-	return(error);
+	if (cm->cm_datalen != 0) {
+		error = bus_dmamap_load(sc->aac_buffer_dmat, cm->cm_datamap,
+					cm->cm_data, cm->cm_datalen,
+					aac_map_command_sg, cm, 0);
+		if (error == EINPROGRESS) {
+			debug(1, "freezing queue\n");
+			sc->flags |= AAC_QUEUE_FRZN;
+			error = 0;
+		}
+	} else {
+		aac_map_command_sg(cm, NULL, 0, 0);
+	}
+	return (error);
 }
 
 /*
  * Handle notification of one or more FIBs coming from the controller.
  */
 static void
-aac_host_command(struct aac_softc *sc)
+aac_command_thread(struct aac_softc *sc)
 {
 	struct aac_fib *fib;
 	u_int32_t fib_size;
-	int size;
+	int size, retval;
 
 	debug_called(2);
 
-	sc->aifflags |= AAC_AIFFLAGS_RUNNING;
+	AAC_LOCK_ACQUIRE(&sc->aac_io_lock);
+	sc->aifflags = AAC_AIFFLAGS_RUNNING;
 
-	while (!(sc->aifflags & AAC_AIFFLAGS_EXIT)) {
-		if (!(sc->aifflags & AAC_AIFFLAGS_PENDING))
-			tsleep(sc->aifthread, 0, "aifthd", 15 * hz);
+	while ((sc->aifflags & AAC_AIFFLAGS_EXIT) == 0) {
+		retval = 0;
+		if ((sc->aifflags & AAC_AIFFLAGS_PENDING) == 0) {
+			crit_enter();
+			tsleep_interlock(sc->aifthread);
+			AAC_LOCK_RELEASE(&sc->aac_io_lock);
+			retval = tsleep(sc->aifthread, 0,
+					"aifthd", AAC_PERIODIC_INTERVAL * hz);
+			AAC_LOCK_ACQUIRE(&sc->aac_io_lock);
+			crit_exit();
+		}
+		/*
+		 * First see if any FIBs need to be allocated.  This needs
+		 * to be called without the driver lock because contigmalloc
+		 * will grab Giant, and would result in an LOR.
+		 */
+		if ((sc->aifflags & AAC_AIFFLAGS_ALLOCFIBS) != 0) {
+			AAC_LOCK_RELEASE(&sc->aac_io_lock);
+			aac_alloc_commands(sc);
+			AAC_LOCK_ACQUIRE(&sc->aac_io_lock);
+			sc->aifflags &= ~AAC_AIFFLAGS_ALLOCFIBS;
+			aac_startio(sc);
+		}
+
+		/*
+		 * 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);
+
+		/* Check the hardware printf message buffer */
+		if (sc->aac_common->ac_printf[0] != 0)
+			aac_print_printf(sc);
 
-		sc->aifflags &= ~AAC_AIFFLAGS_PENDING;
+		/* Also check to see if the adapter has a command for us. */
+		if (sc->flags & AAC_FLAGS_NEW_COMM)
+			continue;
 		for (;;) {
 			if (aac_dequeue_fib(sc, AAC_HOST_NORM_CMD_QUEUE,
 					    &fib_size, &fib))
-				break;	/* nothing to do */
-	
+				break;
+
 			AAC_PRINT_FIB(sc, fib);
-	
+
 			switch (fib->Header.Command) {
 			case AifRequest:
 				aac_handle_aif(sc, fib);
@@ -758,11 +974,12 @@ aac_host_command(struct aac_softc *sc)
 				break;
 			}
 
-			/* Return the AIF to the controller. */
 			if ((fib->Header.XferState == 0) ||
-			    (fib->Header.StructType != AAC_FIBTYPE_TFIB))
+			    (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;
@@ -779,75 +996,50 @@ aac_host_command(struct aac_softc *sc)
 				 * enqueue->startio chain.
 				 */
 				aac_enqueue_response(sc,
-						     AAC_ADAP_NORM_RESP_QUEUE,
-						     fib);
+						 AAC_ADAP_NORM_RESP_QUEUE,
+						 fib);
 			}
 		}
 	}
 	sc->aifflags &= ~AAC_AIFFLAGS_RUNNING;
+	AAC_LOCK_RELEASE(&sc->aac_io_lock);
 	wakeup(sc->aac_dev);
 
-#if defined(__FreeBSD__) && __FreeBSD_version > 500005
-	mtx_lock(&Giant);
-#endif
 	kthread_exit();
 }
 
 /*
- * Handle notification of one or more FIBs completed by the controller
+ * Process completed commands.
  */
 static void
-aac_host_response(struct aac_softc *sc)
+aac_complete(void *context, int pending)
 {
+	struct aac_softc *sc;
 	struct aac_command *cm;
 	struct aac_fib *fib;
 	u_int32_t fib_size;
 
 	debug_called(2);
 
+	sc = (struct aac_softc *)context;
+
+	AAC_LOCK_ACQUIRE(&sc->aac_io_lock);
+
+	/* 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 */
-		cm = (struct aac_command *)fib->Header.SenderData;
+		cm = sc->aac_commands + fib->Header.SenderData;
 		if (cm == NULL) {
 			AAC_PRINT_FIB(sc, fib);
-		} else {
-			aac_remove_busy(cm);
-			aac_unmap_command(cm);		/* XXX defer? */
-			aac_enqueue_complete(cm);
-		}
-	}
-
-	/* handle completion processing */
-#if defined(__FreeBSD__) && __FreeBSD_version >= 500005
-	taskqueue_enqueue(taskqueue_swi, &sc->aac_task_complete);
-#else
-	aac_complete(sc, 0);
-#endif
-}
-
-/*
- * Process completed commands.
- */
-static void
-aac_complete(void *context, int pending)
-{
-	struct aac_softc *sc;
-	struct aac_command *cm;
-	
-	debug_called(2);
-
-	sc = (struct aac_softc *)context;
-
-	/* pull completed commands off the queue */
-	for (;;) {
-		cm = aac_dequeue_complete(sc);
-		if (cm == NULL)
 			break;
+		}
+		aac_remove_busy(cm);
+		aac_unmap_command(cm);		/* XXX defer? */
 		cm->cm_flags |= AAC_CMD_COMPLETED;
 
 		/* is there a completion handler? */
 	}
 
 	/* see if we can start some more I/O */
+	sc->flags &= ~AAC_QUEUE_FRZN;
 	aac_startio(sc);
+
+	AAC_LOCK_RELEASE(&sc->aac_io_lock);
 }
 
 /*
@@ -889,8 +1084,6 @@ aac_bio_command(struct aac_softc *sc, struct aac_command **cmp)
 {
 	struct aac_command *cm;
 	struct aac_fib *fib;
-	struct aac_blockread *br;
-	struct aac_blockwrite *bw;
 	struct aac_disk *ad;
 	struct bio *bio;
 	struct buf *bp;
@@ -899,10 +1092,11 @@ aac_bio_command(struct aac_softc *sc, struct aac_command **cmp)
 
 	/* get the resources we will need */
 	cm = NULL;
-	if ((bio = aac_dequeue_bio(sc)) == NULL)
-		goto fail;
+	bio = NULL;
 	if (aac_alloc_command(sc, &cm))	/* get a command */
 		goto fail;
+	if ((bio = aac_dequeue_bio(sc)) == NULL)
+		goto fail;
 
 	/* fill out the command */
 	bp = bio->bio_buf;
@@ -915,39 +1109,89 @@ aac_bio_command(struct aac_softc *sc, struct aac_command **cmp)
 
 	/* build the FIB */
 	fib = cm->cm_fib;
-	fib->Header.XferState =  
-		AAC_FIBSTATE_HOSTOWNED   | 
-		AAC_FIBSTATE_INITIALISED | 
-		AAC_FIBSTATE_EMPTY	 | 
+	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;
-	fib->Header.Command = ContainerCommand;
-	fib->Header.Size = sizeof(struct aac_fib_header);
 
 	/* build the read/write request */
 	ad = (struct aac_disk *)bio->bio_driver_info;
-	if (bp->b_cmd == BUF_CMD_READ) {
-		br = (struct aac_blockread *)&fib->data[0];
-		br->Command = VM_CtBlockRead;
-		br->ContainerId = ad->ad_container->co_mntobj.ObjectId;
-		br->BlockNumber = bio->bio_offset / AAC_BLOCK_SIZE;
-		br->ByteCount = bp->b_bcount;
-		fib->Header.Size += sizeof(struct aac_blockread);
-		cm->cm_sgtable = &br->SgMap;
-		cm->cm_flags |= AAC_CMD_DATAIN;
+
+	if (sc->flags & AAC_FLAGS_RAW_IO) {
+		struct aac_raw_io *raw;
+		raw = (struct aac_raw_io *)&fib->data[0];
+		fib->Header.Command = RawIo;
+		raw->BlockNumber = bio->bio_offset / AAC_BLOCK_SIZE;
+		raw->ByteCount = bp->b_bcount;
+		raw->ContainerId = ad->ad_container->co_mntobj.ObjectId;
+		raw->BpTotal = 0;
+		raw->BpComplete = 0;
+		fib->Header.Size += sizeof(struct aac_raw_io);
+		cm->cm_sgtable = (struct aac_sg_table *)&raw->SgMapRaw;
+		if (bp->b_cmd == BUF_CMD_READ) {
+			raw->Flags = 1;
+			cm->cm_flags |= AAC_CMD_DATAIN;
+		} else {
+			raw->Flags = 0;
+			cm->cm_flags |= AAC_CMD_DATAOUT;
+		}
+	} else if ((sc->flags & AAC_FLAGS_SG_64BIT) == 0) {
+		fib->Header.Command = ContainerCommand;
+		if (bp->b_cmd == BUF_CMD_READ) {
+			struct aac_blockread *br;
+			br = (struct aac_blockread *)&fib->data[0];
+			br->Command = VM_CtBlockRead;
+			br->ContainerId = ad->ad_container->co_mntobj.ObjectId;
+			br->BlockNumber = bio->bio_offset / AAC_BLOCK_SIZE;
+			br->ByteCount = bp->b_bcount;
+			fib->Header.Size += sizeof(struct aac_blockread);
+			cm->cm_sgtable = &br->SgMap;
+			cm->cm_flags |= AAC_CMD_DATAIN;
+		} else {
+			struct aac_blockwrite *bw;
+			bw = (struct aac_blockwrite *)&fib->data[0];
+			bw->Command = VM_CtBlockWrite;
+			bw->ContainerId = ad->ad_container->co_mntobj.ObjectId;
+			bw->BlockNumber = bio->bio_offset / AAC_BLOCK_SIZE;
+			bw->ByteCount = bp->b_bcount;
+			bw->Stable = CUNSTABLE;
+			fib->Header.Size += sizeof(struct aac_blockwrite);
+			cm->cm_flags |= AAC_CMD_DATAOUT;
+			cm->cm_sgtable = &bw->SgMap;
+		}
 	} else {
-		bw = (struct aac_blockwrite *)&fib->data[0];
-		bw->Command = VM_CtBlockWrite;
-		bw->ContainerId = ad->ad_container->co_mntobj.ObjectId;
-		bw->BlockNumber = bio->bio_offset / AAC_BLOCK_SIZE;
-		bw->ByteCount = bp->b_bcount;
-		bw->Stable = CUNSTABLE;	/* XXX what's appropriate here? */
-		fib->Header.Size += sizeof(struct aac_blockwrite);
-		cm->cm_flags |= AAC_CMD_DATAOUT;
-		cm->cm_sgtable = &bw->SgMap;
+		fib->Header.Command = ContainerCommand64;
+		if (bp->b_cmd == BUF_CMD_READ) {
+			struct aac_blockread64 *br;
+			br = (struct aac_blockread64 *)&fib->data[0];
+			br->Command = VM_CtHostRead64;
+			br->ContainerId = ad->ad_container->co_mntobj.ObjectId;
+			br->SectorCount = bp->b_bcount / AAC_BLOCK_SIZE;
+			br->BlockNumber = bio->bio_offset / AAC_BLOCK_SIZE;
+			br->Pad = 0;
+			br->Flags = 0;
+			fib->Header.Size += sizeof(struct aac_blockread64);
+			cm->cm_flags |= AAC_CMD_DATAOUT;
+			cm->cm_sgtable = (struct aac_sg_table *)&br->SgMap64;
+		} else {
+			struct aac_blockwrite64 *bw;
+			bw = (struct aac_blockwrite64 *)&fib->data[0];
+			bw->Command = VM_CtHostWrite64;
+			bw->ContainerId = ad->ad_container->co_mntobj.ObjectId;
+			bw->SectorCount = bp->b_bcount / AAC_BLOCK_SIZE;
+			bw->BlockNumber = bio->bio_offset / AAC_BLOCK_SIZE;
+			bw->Pad = 0;
+			bw->Flags = 0;
+			fib->Header.Size += sizeof(struct aac_blockwrite64);
+			cm->cm_flags |= AAC_CMD_DATAIN;
+			cm->cm_sgtable = (struct aac_sg_table *)&bw->SgMap64;
+		}
 	}
 
 	*cmp = cm;
@@ -1048,7 +1292,7 @@ aac_dump_enqueue(struct aac_disk *ad, u_int64_t lba, void *data, int dumppages)
 	cm->cm_flags |= AAC_CMD_DATAOUT;
 	cm->cm_sgtable = &bw->SgMap;
 
-	return (aac_start(cm));
+	return (aac_map_command(cm));
 }
 
 /*
@@ -1101,29 +1345,33 @@ aac_dump_complete(struct aac_softc *sc)
  * 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.
+ *     because there is a risk that a signal could wakeup the sleep before
+ *     the card has a chance to complete the command.  Since there is no way
+ *     to cancel a command that is in progress, we can't protect against the
+ *     card completing a command late and spamming the command and data
+ *     memory.  So, we are held hostage until the command completes.
  */
 static int
-aac_wait_command(struct aac_command *cm, int timeout)
+aac_wait_command(struct aac_command *cm)
 {
-	int error = 0;
+	struct aac_softc *sc;
+	int error;
 
 	debug_called(2);
 
+	sc = cm->cm_sc;
+
 	/* Put the command on the ready queue and get things going */
 	cm->cm_queue = AAC_ADAP_NORM_CMD_QUEUE;
 	aac_enqueue_ready(cm);
-	aac_startio(cm->cm_sc);
+	aac_startio(sc);
+	/* Lock is held */
+	KKASSERT(lockstatus(&sc->aac_io_lock, curthread) != 0);
 	crit_enter();
-	while (!(cm->cm_flags & AAC_CMD_COMPLETED) && (error != EWOULDBLOCK)) {
-		error = tsleep(cm, 0, "aacwait", 0);
-	}
+	tsleep_interlock(cm);
+	AAC_LOCK_RELEASE(&sc->aac_io_lock);
+	error = tsleep(cm, 0, "aacwait", 0);
+	AAC_LOCK_ACQUIRE(&sc->aac_io_lock);
 	crit_exit();
 	return(error);
 }
@@ -1142,8 +1390,13 @@ aac_alloc_command(struct aac_softc *sc, struct aac_command **cmp)
 
 	debug_called(3);
 
-	if ((cm = aac_dequeue_free(sc)) == NULL)
-		return(ENOMEM);
+	if ((cm = aac_dequeue_free(sc)) == NULL) {
+		if (sc->total_fibs < sc->aac_max_fibs) {
+			sc->aifflags |= AAC_AIFFLAGS_ALLOCFIBS;
+			wakeup(sc->aifthread);
+		}
+		return (EBUSY);
+	}
 
 	*cmp = cm;
 	return(0);
@@ -1155,6 +1408,9 @@ aac_alloc_command(struct aac_softc *sc, struct aac_command **cmp)
 void
 aac_release_command(struct aac_command *cm)
 {
+	struct aac_event *event;
+	struct aac_softc *sc;
+
 	debug_called(3);
 
 	/* (re)initialise the command/FIB */
@@ -1165,18 +1421,24 @@ aac_release_command(struct aac_command *cm)
 	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);
+	cm->cm_fib->Header.SenderSize = cm->cm_sc->aac_max_fib_size;
 
-	/* 
+	/*
 	 * 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.SenderFibAddress = (u_int32_t)cm->cm_fib;
 	cm->cm_fib->Header.ReceiverFibAddress = (u_int32_t)cm->cm_fibphys;
 	cm->cm_fib->Header.SenderData = 0;
 
 	aac_enqueue_free(cm);
+
+	sc = cm->cm_sc;
+	event = TAILQ_FIRST(&sc->aac_ev_cmfree);
+	if (event != NULL) {
+		TAILQ_REMOVE(&sc->aac_ev_cmfree, event, ev_links);
+		event->ev_callback(sc, event, event->ev_arg);
+	}
 }
 
 /*
@@ -1185,13 +1447,13 @@ aac_release_command(struct aac_command *cm)
 static void
 aac_map_command_helper(void *arg, bus_dma_segment_t *segs, int nseg, int error)
 {
-	struct aac_softc *sc;
+	uint64_t	*fibphys;
 
-	sc = (struct aac_softc *)arg;
+	fibphys = (uint64_t *)arg;
 
 	debug_called(3);
 
-	sc->aac_fibphys = segs[0].ds_addr;
+	*fibphys = segs[0].ds_addr;
 }
 
 /*
@@ -1201,32 +1463,63 @@ static int
 aac_alloc_commands(struct aac_softc *sc)
 {
 	struct aac_command *cm;
-	int i;
- 
-	debug_called(1);
+	struct aac_fibmap *fm;
+	uint64_t fibphys;
+	int i, error;
+
+	debug_called(2);
+
+	if (sc->total_fibs + sc->aac_max_fibs_alloc > sc->aac_max_fibs)
+		return (ENOMEM);
+
+	fm = kmalloc(sizeof(struct aac_fibmap), M_AACBUF, M_INTWAIT | M_ZERO);
 
 	/* allocate the FIBs in DMAable memory and load them */
-	if (bus_dmamem_alloc(sc->aac_fib_dmat, (void **)&sc->aac_fibs,
-			 BUS_DMA_NOWAIT, &sc->aac_fibmap)) {
-		return(ENOMEM);
+	if (bus_dmamem_alloc(sc->aac_fib_dmat, (void **)&fm->aac_fibs,
+			     BUS_DMA_NOWAIT, &fm->aac_fibmap)) {
+		device_printf(sc->aac_dev,
+			      "Not enough contiguous memory available.\n");
+		kfree(fm, M_AACBUF);
+		return (ENOMEM);
 	}
 
-	bus_dmamap_load(sc->aac_fib_dmat, sc->aac_fibmap, sc->aac_fibs, 
-			AAC_FIB_COUNT * sizeof(struct aac_fib),
-			aac_map_command_helper, sc, 0);
+	/* Ignore errors since this doesn't bounce */
+	bus_dmamap_load(sc->aac_fib_dmat, fm->aac_fibmap, fm->aac_fibs,
+			sc->aac_max_fibs_alloc * sc->aac_max_fib_size,
+			aac_map_command_helper, &fibphys, 0);
 
 	/* initialise constant fields in the command structure */
-	bzero(sc->aac_fibs, AAC_FIB_COUNT * sizeof(struct aac_fib));
-	for (i = 0; i < AAC_FIB_COUNT; i++) {
-		cm = &sc->aac_command[i];
+	bzero(fm->aac_fibs, sc->aac_max_fibs_alloc * sc->aac_max_fib_size);
+	for (i = 0; i < sc->aac_max_fibs_alloc; i++) {
+		cm = sc->aac_commands + sc->total_fibs;
+		fm->aac_commands = cm;
 		cm->cm_sc = sc;
-		cm->cm_fib = sc->aac_fibs + i;
-		cm->cm_fibphys = sc->aac_fibphys + (i * sizeof(struct aac_fib));
+		cm->cm_fib = (struct aac_fib *)
+			((u_int8_t *)fm->aac_fibs + i*sc->aac_max_fib_size);
+		cm->cm_fibphys = fibphys + i*sc->aac_max_fib_size;
+		cm->cm_index = sc->total_fibs;
 
-		if (!bus_dmamap_create(sc->aac_buffer_dmat, 0, &cm->cm_datamap))
-			aac_release_command(cm);
+		if ((error = bus_dmamap_create(sc->aac_buffer_dmat, 0,
+					       &cm->cm_datamap)) != 0)
+			break;
+		AAC_LOCK_ACQUIRE(&sc->aac_io_lock);
+		aac_release_command(cm);
+		sc->total_fibs++;
+		AAC_LOCK_RELEASE(&sc->aac_io_lock);
 	}
-	return(0);
+
+	if (i > 0) {
+		AAC_LOCK_ACQUIRE(&sc->aac_io_lock);
+		TAILQ_INSERT_TAIL(&sc->aac_fibmap_tqh, fm, fm_link);
+		debug(1, "total_fibs= %d\n", sc->total_fibs);
+		AAC_LOCK_RELEASE(&sc->aac_io_lock);
+		return (0);
+	}
+
+	bus_dmamap_unload(sc->aac_fib_dmat, fm->aac_fibmap);
+	bus_dmamem_free(sc->aac_fib_dmat, fm->aac_fibs, fm->aac_fibmap);
+	kfree(fm, M_AACBUF);
+	return (ENOMEM);
 }
 
 /*
@@ -1235,16 +1528,27 @@ aac_alloc_commands(struct aac_softc *sc)
 static void
 aac_free_commands(struct aac_softc *sc)
 {
+	struct aac_fibmap *fm;
+	struct aac_command *cm;
 	int i;
 
 	debug_called(1);
 
-	for (i = 0; i < AAC_FIB_COUNT; i++)
-		bus_dmamap_destroy(sc->aac_buffer_dmat,
-				   sc->aac_command[i].cm_datamap);
+	while ((fm = TAILQ_FIRST(&sc->aac_fibmap_tqh)) != NULL) {
 
-	bus_dmamap_unload(sc->aac_fib_dmat, sc->aac_fibmap);
-	bus_dmamem_free(sc->aac_fib_dmat, sc->aac_fibs, sc->aac_fibmap);
+		TAILQ_REMOVE(&sc->aac_fibmap_tqh, fm, fm_link);
+		/*
+		 * We check against total_fibs to handle partially
+		 * allocated blocks.
+		 */
+		for (i = 0; i < sc->aac_max_fibs_alloc && sc->total_fibs--; i++) {
+			cm = fm->aac_commands + i;
+			bus_dmamap_destroy(sc->aac_buffer_dmat, cm->cm_datamap);
+		}
+		bus_dmamap_unload(sc->aac_fib_dmat, fm->aac_fibmap);
+		bus_dmamem_free(sc->aac_fib_dmat, fm->aac_fibs, fm->aac_fibmap);
+		kfree(fm, M_AACBUF);
+	}
 }
 
 /*
@@ -1253,61 +1557,92 @@ aac_free_commands(struct aac_softc *sc)
 static void
 aac_map_command_sg(void *arg, bus_dma_segment_t *segs, int nseg, int error)
 {
+	struct aac_softc *sc;
 	struct aac_command *cm;
 	struct aac_fib *fib;
-	struct aac_sg_table *sg;
 	int i;
 
 	debug_called(3);
 
 	cm = (struct aac_command *)arg;
+	sc = cm->cm_sc;
 	fib = cm->cm_fib;
 
-	/* find the s/g table */
-	sg = cm->cm_sgtable;
-
 	/* copy into the FIB */
-	if (sg != NULL) {
-		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;
+	if (cm->cm_sgtable != NULL) {
+		if (fib->Header.Command == RawIo) {
+			struct aac_sg_tableraw *sg;
+			sg = (struct aac_sg_tableraw *)cm->cm_sgtable;
+			sg->SgCount = nseg;
+			for (i = 0; i < nseg; i++) {
+				sg->SgEntryRaw[i].SgAddress = segs[i].ds_addr;
+				sg->SgEntryRaw[i].SgByteCount = segs[i].ds_len;
+				sg->SgEntryRaw[i].Next = 0;
+				sg->SgEntryRaw[i].Prev = 0;
+				sg->SgEntryRaw[i].Flags = 0;
+			}
+			/* update the FIB size for the s/g count */
+			fib->Header.Size += nseg*sizeof(struct aac_sg_entryraw);
+		} else if ((cm->cm_sc->flags & AAC_FLAGS_SG_64BIT) == 0) {
+			struct aac_sg_table *sg;
+			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);
 		}
-		/* update the FIB size for the s/g count */
-		fib->Header.Size += nseg * sizeof(struct aac_sg_entry);
 	}
 
-}
-
-/*
- * Map a command into controller-visible space.
- */
-static void
-aac_map_command(struct aac_command *cm)
-{
-	struct aac_softc *sc;
-
-	debug_called(2);
-
-	sc = cm->cm_sc;
-
-	/* don't map more than once */
-	if (cm->cm_flags & AAC_CMD_MAPPED)
-		return;
+	/* 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
+	 * and for the AIF bit
+	 */
+	cm->cm_fib->Header.SenderFibAddress = (cm->cm_index << 2);
+	cm->cm_fib->Header.ReceiverFibAddress = (u_int32_t)cm->cm_fibphys;
 
-	if (cm->cm_datalen != 0) {
-		bus_dmamap_load(sc->aac_buffer_dmat, cm->cm_datamap,
-				cm->cm_data, cm->cm_datalen,
-				aac_map_command_sg, cm, 0);
+	/* 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_buffer_dmat, cm->cm_datamap,
+				BUS_DMASYNC_PREREAD);
+	if (cm->cm_flags & AAC_CMD_DATAOUT)
+		bus_dmamap_sync(sc->aac_buffer_dmat, cm->cm_datamap,
+				BUS_DMASYNC_PREWRITE);
+	cm->cm_flags |= AAC_CMD_MAPPED;
 
-		if (cm->cm_flags & AAC_CMD_DATAIN)
-			bus_dmamap_sync(sc->aac_buffer_dmat, cm->cm_datamap,
-					BUS_DMASYNC_PREREAD);
-		if (cm->cm_flags & AAC_CMD_DATAOUT)
-			bus_dmamap_sync(sc->aac_buffer_dmat, cm->cm_datamap,
-					BUS_DMASYNC_PREWRITE);
+	if (sc->flags & AAC_FLAGS_NEW_COMM) {
+		int count = 10000000L;
+		while (AAC_SEND_COMMAND(sc, cm) != 0) {
+			if (--count == 0) {
+				aac_unmap_command(cm);
+				sc->flags |= AAC_QUEUE_FRZN;
+				aac_requeue_ready(cm);
+			}
+			DELAY(5);			/* wait 5 usec. */
+		}
+	} else {
+		/* Put the FIB on the outbound queue */
+		if (aac_enqueue_fib(sc, cm->cm_queue, cm) == EBUSY) {
+			aac_unmap_command(cm);
+			sc->flags |= AAC_QUEUE_FRZN;
+			aac_requeue_ready(cm);
+		}
 	}
-	cm->cm_flags |= AAC_CMD_MAPPED;
 }
 
 /*
@@ -1360,7 +1695,8 @@ aac_common_map(void *arg, bus_dma_segment_t *segs, int nseg, int error)
 static int
 aac_check_firmware(struct aac_softc *sc)
 {
-	u_int32_t major, minor, options;
+	u_int32_t major, minor, options = 0, atu_size = 0;
+	int status;
 
 	debug_called(1);
 
@@ -1389,20 +1725,91 @@ aac_check_firmware(struct aac_softc *sc)
 
 	/*
 	 * Retrieve the capabilities/supported options word so we know what
-	 * work-arounds to enable.
+	 * work-arounds to enable.  Some firmware revs don't support this
+	 * command.
 	 */
-	if (aac_sync_command(sc, AAC_MONKER_GETINFO, 0, 0, 0, 0, NULL)) {
-		device_printf(sc->aac_dev, "RequestAdapterInfo failed\n");
-		return (EIO);
+	if (aac_sync_command(sc, AAC_MONKER_GETINFO, 0, 0, 0, 0, &status)) {
+		if (status != AAC_SRB_STS_INVALID_REQUEST) {
+			device_printf(sc->aac_dev,
+			     "RequestAdapterInfo failed\n");
+			return (EIO);
+		}
+	} else {
+		options = AAC_GET_MAILBOX(sc, 1);
+		atu_size = AAC_GET_MAILBOX(sc, 2);
+		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)) {
+			device_printf(sc->aac_dev,
+			    "Enabling 64-bit address support\n");
+			sc->flags |= AAC_FLAGS_SG_64BIT;
+		}
+		if ((options & AAC_SUPPORTED_NEW_COMM)
+		 && sc->aac_if.aif_send_command)
+			sc->flags |= AAC_FLAGS_NEW_COMM;
+		if (options & AAC_SUPPORTED_64BIT_ARRAYSIZE)
+			sc->flags |= AAC_FLAGS_ARRAY_64BIT;
 	}
-	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;
+	/* Check for broken hardware that does a lower number of commands */
+	sc->aac_max_fibs = (sc->flags & AAC_FLAGS_256FIBS ? 256:512);
+
+	/* Remap mem. resource, if required */
+	if ((sc->flags & AAC_FLAGS_NEW_COMM) &&
+		atu_size > rman_get_size(sc->aac_regs_resource)) {
+		bus_release_resource(
+			sc->aac_dev, SYS_RES_MEMORY,
+			sc->aac_regs_rid, sc->aac_regs_resource);
+		sc->aac_regs_resource = bus_alloc_resource(
+			sc->aac_dev, SYS_RES_MEMORY, &sc->aac_regs_rid,
+			0ul, ~0ul, atu_size, RF_ACTIVE);
+		if (sc->aac_regs_resource == NULL) {
+			sc->aac_regs_resource = bus_alloc_resource_any(
+				sc->aac_dev, SYS_RES_MEMORY,
+				&sc->aac_regs_rid, RF_ACTIVE);
+			if (sc->aac_regs_resource == NULL) {
+				device_printf(sc->aac_dev,
+				    "couldn't allocate register window\n");
+				return (ENXIO);
+			}
+			sc->flags &= ~AAC_FLAGS_NEW_COMM;
+		}
+		sc->aac_btag = rman_get_bustag(sc->aac_regs_resource);
+		sc->aac_bhandle = rman_get_bushandle(sc->aac_regs_resource);
+	}
+
+	/* Read preferred settings */
+	sc->aac_max_fib_size = sizeof(struct aac_fib);
+	sc->aac_max_sectors = 128;				/* 64KB */
+	if (sc->flags & AAC_FLAGS_SG_64BIT)
+		sc->aac_sg_tablesize = (AAC_FIB_DATASIZE
+		 - sizeof(struct aac_blockwrite64)
+		 + sizeof(struct aac_sg_table64))
+		 / sizeof(struct aac_sg_table64);
+	else
+		sc->aac_sg_tablesize = (AAC_FIB_DATASIZE
+		 - sizeof(struct aac_blockwrite)
+		 + sizeof(struct aac_sg_table))
+		 / sizeof(struct aac_sg_table);
+
+	if (!aac_sync_command(sc, AAC_MONKER_GETCOMMPREF, 0, 0, 0, 0, NULL)) {
+		options = AAC_GET_MAILBOX(sc, 1);
+		sc->aac_max_fib_size = (options & 0xFFFF);
+		sc->aac_max_sectors = (options >> 16) << 1;
+		options = AAC_GET_MAILBOX(sc, 2);
+		sc->aac_sg_tablesize = (options >> 16);
+		options = AAC_GET_MAILBOX(sc, 3);
+		sc->aac_max_fibs = (options & 0xFFFF);
+	}
+	if (sc->aac_max_fib_size > PAGE_SIZE)
+		sc->aac_max_fib_size = PAGE_SIZE;
+	sc->aac_max_fibs_alloc = PAGE_SIZE / sc->aac_max_fib_size;
 
 	return (0);
 }
@@ -1412,8 +1819,7 @@ aac_init(struct aac_softc *sc)
 {
 	struct aac_adapter_init	*ip;
 	time_t then;
-	u_int32_t code;
-	u_int8_t *qaddr;
+	u_int32_t code, qoffset;
 	int error;
 
 	debug_called(1);
@@ -1447,11 +1853,13 @@ aac_init(struct aac_softc *sc)
  	 */
  	if (bus_dma_tag_create(sc->aac_parent_dmat, 	/* parent */
  			       1, 0, 			/* algnmnt, boundary */
+			       (sc->flags & AAC_FLAGS_SG_64BIT) ?
+			       BUS_SPACE_MAXADDR :
  			       BUS_SPACE_MAXADDR_32BIT,	/* lowaddr */
  			       BUS_SPACE_MAXADDR, 	/* highaddr */
  			       NULL, NULL, 		/* filter, filterarg */
  			       MAXBSIZE,		/* maxsize */
- 			       AAC_MAXSGENTRIES,	/* nsegments */
+ 			       sc->aac_sg_tablesize,	/* nsegments */
  			       MAXBSIZE,		/* maxsegsize */
  			       BUS_DMA_ALLOCNOW,	/* flags */
  			       &sc->aac_buffer_dmat)) {
@@ -1469,12 +1877,12 @@ aac_init(struct aac_softc *sc)
  			       0x7fffffff,		/* lowaddr */
  			       BUS_SPACE_MAXADDR, 	/* highaddr */
  			       NULL, NULL, 		/* filter, filterarg */
- 			       AAC_FIB_COUNT *
- 			       sizeof(struct aac_fib),  /* maxsize */
+			       sc->aac_max_fibs_alloc *
+			       sc->aac_max_fib_size,	/* maxsize */
  			       1,			/* nsegments */
- 			       AAC_FIB_COUNT *
- 			       sizeof(struct aac_fib),	/* maxsegsize */
- 			       BUS_DMA_ALLOCNOW,	/* flags */
+			       sc->aac_max_fibs_alloc *
+			       sc->aac_max_fib_size,	/* maxsegsize */
+ 			       0,			/* flags */
  			       &sc->aac_fib_dmat)) {
  		device_printf(sc->aac_dev, "can't allocate FIB DMA tag\n");
  		goto out;
@@ -1493,7 +1901,7 @@ aac_init(struct aac_softc *sc)
 			       8192 + sizeof(struct aac_common), /* maxsize */
 			       1,			/* nsegments */
 			       BUS_SPACE_MAXSIZE_32BIT,	/* maxsegsize */
-			       BUS_DMA_ALLOCNOW,	/* flags */
+			       0,			/* flags */
 			       &sc->aac_common_dmat)) {
 		device_printf(sc->aac_dev,
 			      "can't allocate common structure DMA tag\n");
@@ -1522,7 +1930,14 @@ aac_init(struct aac_softc *sc)
 	bzero(sc->aac_common, sizeof(*sc->aac_common));
 
 	/* Allocate some FIBs and associated command structs */
-	if (aac_alloc_commands(sc) != 0)
+	TAILQ_INIT(&sc->aac_fibmap_tqh);
+	sc->aac_commands = kmalloc(sc->aac_max_fibs * sizeof(struct aac_command),
+				  M_AACBUF, M_INTWAIT | M_ZERO);
+	while (sc->total_fibs < AAC_PREALLOCATE_FIBS) {
+		if (aac_alloc_commands(sc) != 0)
+			break;
+	}
+	if (sc->total_fibs == 0)
 		goto out;
 
 	/*
@@ -1531,11 +1946,15 @@ aac_init(struct aac_softc *sc)
 	 */
 	ip = &sc->aac_common->ac_init;
 	ip->InitStructRevision = AAC_INIT_STRUCT_REVISION;
+	if (sc->aac_max_fib_size > sizeof(struct aac_fib)) {
+		ip->InitStructRevision = AAC_INIT_STRUCT_REVISION_4;
+		sc->flags |= AAC_FLAGS_RAW_IO;
+	}
 	ip->MiniPortRevision = AAC_INIT_STRUCT_MINIPORT_REVISION;
 
 	ip->AdapterFibsPhysicalAddress = sc->aac_common_busaddr +
 					 offsetof(struct aac_common, ac_fibs);
-	ip->AdapterFibsVirtualAddress = (aac_phys_addr_t)&sc->aac_common->ac_fibs[0];
+	ip->AdapterFibsVirtualAddress = 0;
 	ip->AdapterFibsSize = AAC_ADAPTER_FIBS * sizeof(struct aac_fib);
 	ip->AdapterFibAlign = sizeof(struct aac_fib);
 
@@ -1543,34 +1962,51 @@ aac_init(struct aac_softc *sc)
 				  offsetof(struct aac_common, ac_printf);
 	ip->PrintfBufferSize = AAC_PRINTF_BUFSIZE;
 
-	/* The adapter assumes that pages are 4K in size */
+	/*
+	 * 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.
+	 */
 	/* XXX why should the adapter care? */
 	ip->HostPhysMemPages = ctob((int)Maxmem) / 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 */
 
+	ip->InitFlags = 0;
+	if (sc->flags & AAC_FLAGS_NEW_COMM) {
+		ip->InitFlags = INITFLAGS_NEW_COMM_SUPPORTED;
+		device_printf(sc->aac_dev, "New comm. interface enabled\n");
+	}
+
+	ip->MaxIoCommands = sc->aac_max_fibs;
+	ip->MaxIoSize = sc->aac_max_sectors << 9;
+	ip->MaxFibSize = sc->aac_max_fib_size;
+
 	/*
 	 * 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 
+	 * 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 
+	 * 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->aac_common->ac_qbuf[0] + AAC_QUEUE_ALIGN;
-	qaddr -= (u_int32_t)qaddr % AAC_QUEUE_ALIGN;
-	sc->aac_queues = (struct aac_queue_table *)qaddr;
-	ip->CommHeaderAddress = sc->aac_common_busaddr +
-				((u_int32_t)sc->aac_queues -
-				(u_int32_t)sc->aac_common);
-	bzero(sc->aac_queues, sizeof(struct aac_queue_table));
+	qoffset = offsetof(struct aac_common, ac_qbuf) + AAC_QUEUE_ALIGN;
+	qoffset &= ~(AAC_QUEUE_ALIGN - 1);
+	sc->aac_queues =
+	    (struct aac_queue_table *)((uintptr_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;
@@ -1628,12 +2064,17 @@ aac_init(struct aac_softc *sc)
 	case AAC_HWIF_I960RX:
 		AAC_SETREG4(sc, AAC_RX_ODBR, ~0);
 		break;
+	case AAC_HWIF_RKT:
+		AAC_SETREG4(sc, AAC_RKT_ODBR, ~0);
+		break;
+	default:
+		break;
 	}
 
 	/*
 	 * Give the init structure to the controller.
 	 */
-	if (aac_sync_command(sc, AAC_MONKER_INITSTRUCT, 
+	if (aac_sync_command(sc, AAC_MONKER_INITSTRUCT,
 			     sc->aac_common_busaddr +
 			     offsetof(struct aac_common, ac_init), 0, 0, 0,
 			     NULL)) {
@@ -1650,6 +2091,7 @@ out:
 
 /*
  * Send a synchronous command to the controller and wait for a result.
+ * Indicate if the controller completed the command with an error status.
  */
 static int
 aac_sync_command(struct aac_softc *sc, u_int32_t command,
@@ -1686,46 +2128,18 @@ aac_sync_command(struct aac_softc *sc, u_int32_t command,
 	status = AAC_GET_MAILBOX(sc, 0);
 	if (sp != NULL)
 		*sp = 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);
+	if (status != AAC_SRB_STS_SUCCESS)
+		return (-1);
+	return(0);
 }
 
-/*
- * Send a synchronous FIB to the controller and wait for a result.
- */
 int
-aac_sync_fib(struct aac_softc *sc, u_int32_t command, u_int32_t xferstate, 
+aac_sync_fib(struct aac_softc *sc, u_int32_t command, u_int32_t xferstate,
 		 struct aac_fib *fib, u_int16_t datasize)
 {
 	debug_called(3);
+	KKASSERT(lockstatus(&sc->aac_io_lock, curthread) != 0);
 
 	if (datasize > AAC_FIB_DATASIZE)
 		return(EINVAL);
@@ -1741,7 +2155,7 @@ aac_sync_fib(struct aac_softc *sc, u_int32_t command, u_int32_t xferstate,
 	fib->Header.StructType = AAC_FIBTYPE_TFIB;
 	fib->Header.Size = sizeof(struct aac_fib) + datasize;
 	fib->Header.SenderSize = sizeof(struct aac_fib);
-	fib->Header.SenderFibAddress = (u_int32_t)fib;
+	fib->Header.SenderFibAddress = 0;	/* Not needed */
 	fib->Header.ReceiverFibAddress = sc->aac_common_busaddr +
 					 offsetof(struct aac_common,
 						  ac_sync_fib);
@@ -1797,11 +2211,9 @@ aac_enqueue_fib(struct aac_softc *sc, int queue, struct aac_command *cm)
 
 	debug_called(3);
 
-	fib_size = cm->cm_fib->Header.Size; 
+	fib_size = cm->cm_fib->Header.Size;
 	fib_addr = cm->cm_fib->Header.ReceiverFibAddress;
 
-	crit_enter();
-
 	/* 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];
@@ -1837,7 +2249,6 @@ aac_enqueue_fib(struct aac_softc *sc, int queue, struct aac_command *cm)
 	error = 0;
 
 out:
-	crit_exit();
 	return(error);
 }
 
@@ -1850,13 +2261,12 @@ 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 error;
 	int notify;
 
 	debug_called(3);
 
-	crit_enter();
-
 	/* 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];
@@ -1881,18 +2291,52 @@ aac_dequeue_fib(struct aac_softc *sc, int queue, u_int32_t *fib_size,
 
 	/* fetch the entry */
 	*fib_size = (sc->aac_qentries[queue] + ci)->aq_fib_size;
-	*fib_addr = (struct aac_fib *)(sc->aac_qentries[queue] +
-				       ci)->aq_fib_addr;
 
-	/*
-	 * Is this a fast response? If it is, update the fib fields in
-	 * local memory so the whole fib doesn't have to be DMA'd back up.
-	 */
-	if (*(uintptr_t *)fib_addr & 0x01) {
-		*(uintptr_t *)fib_addr &= ~0x01;
-		(*fib_addr)->Header.XferState |= AAC_FIBSTATE_DONEADAP;
-		*((u_int32_t*)((*fib_addr)->data)) = AAC_ERROR_NORMAL;
+	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 >> 2);
+		*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;
+	}
+	default:
+		panic("Invalid queue in aac_dequeue_fib()");
+		break;
 	}
+
 	/* update consumer index */
 	sc->aac_queues->qt_qindex[queue][AAC_CONSUMER_INDEX] = ci + 1;
 
@@ -1902,7 +2346,6 @@ aac_dequeue_fib(struct aac_softc *sc, int queue, u_int32_t *fib_size,
 	error = 0;
 
 out:
-	crit_exit();
 	return(error);
 }
 
@@ -1920,12 +2363,10 @@ aac_enqueue_response(struct aac_softc *sc, int queu 	debug_called(1);
 
 	/* Tell the adapter where the FIB is */
-	fib_size = fib->Header.Size; 
+	fib_size = fib->Header.Size;
 	fib_addr = fib->Header.SenderFibAddress;
 	fib->Header.ReceiverFibAddress = fib_addr;
 
-	crit_enter();
-
 	/* 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];
@@ -1954,7 +2395,6 @@ aac_enqueue_response(struct aac_softc *sc, int queue, struct aac_fib *fib)
 	error = 0;
 
 out:
-	crit_exit();
 	return(error);
 }
 
@@ -1969,29 +2409,12 @@ aac_timeout(void *xsc)
 	struct aac_command *cm;
 	time_t deadline;
 	int timedout, code;
-#if 0
-	/* simulate an interrupt to handle possibly-missed interrupts */
-	/*
-	 * XXX This was done to work around another bug which has since been
-	 * fixed.  It is dangerous anyways because you don't want multiple
-	 * threads in the interrupt handler at the same time!  If calling
-	 * is deamed neccesary in the future, proper mutexes must be used.
-	 */
-	crit_enter();
-	aac_intr(sc);
-	crit_exit();
-
-	/* kick the I/O queue to restart it in the case of deadlock */
-	aac_startio(sc);
-#endif
-
 	/*
-	 * traverse the busy command list, bitch about late commands once
+	 * Traverse the busy command list, bitch about late commands once
 	 * only.
 	 */
 	timedout = 0;
 	deadline = time_second - AAC_CMD_TIMEOUT;
-	crit_enter();
 	TAILQ_FOREACH(cm, &sc->aac_busy, cm_link) {
 		if ((cm->cm_timestamp  < deadline)
 			/* && !(cm->cm_flags & AAC_CMD_TIMEDOUT) */) {
@@ -2011,11 +2434,6 @@ aac_timeout(void *xsc)
 
 		}
 	}
-	crit_exit();
-
-	/* reset the timer for next time */
-	callout_reset(&sc->aac_watchdog, AAC_PERIODIC_INTERVAL * hz,
-		      aac_timeout, sc);
 }
 
 /*
@@ -2052,6 +2470,14 @@ aac_fa_get_fwstatus(struct aac_softc *sc)
 	return (val);
 }
 
+static int
+aac_rkt_get_fwstatus(struct aac_softc *sc)
+{
+	debug_called(3);
+
+	return(AAC_GETREG4(sc, AAC_RKT_FWSTATUS));
+}
+
 /*
  * Notify the controller of a change in a given queue
  */
@@ -2081,6 +2507,14 @@ aac_fa_qnotify(struct aac_softc *sc, int qbit)
 	AAC_FA_HACK(sc);
 }
 
+static void
+aac_rkt_qnotify(struct aac_softc *sc, int qbit)
+{
+	debug_called(3);
+
+	AAC_SETREG4(sc, AAC_RKT_IDBR, qbit);
+}
+
 /*
  * Get the interrupt reason bits
  */
@@ -2111,6 +2545,14 @@ aac_fa_get_istatus(struct aac_softc *sc)
 	return (val);
 }
 
+static int
+aac_rkt_get_istatus(struct aac_softc *sc)
+{
+	debug_called(3);
+
+	return(AAC_GETREG4(sc, AAC_RKT_ODBR));
+}
+
 /*
  * Clear some interrupt reason bits
  */
@@ -2139,6 +2581,14 @@ aac_fa_clear_istatus(struct aac_softc *sc, int mask)
 	AAC_FA_HACK(sc);
 }
 
+static void
+aac_rkt_clear_istatus(struct aac_softc *sc, int mask)
+{
+	debug_called(3);
+
+	AAC_SETREG4(sc, AAC_RKT_ODBR, mask);
+}
+
 /*
  * Populate the mailbox and set the command word
  */
@@ -2186,6 +2636,19 @@ aac_fa_set_mailbox(struct aac_softc *sc, u_int32_t command,
 	AAC_FA_HACK(sc);
 }
 
+static void
+aac_rkt_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)
+{
+	debug_called(4);
+
+	AAC_SETREG4(sc, AAC_RKT_MAILBOX, command);
+	AAC_SETREG4(sc, AAC_RKT_MAILBOX + 4, arg0);
+	AAC_SETREG4(sc, AAC_RKT_MAILBOX + 8, arg1);
+	AAC_SETREG4(sc, AAC_RKT_MAILBOX + 12, arg2);
+	AAC_SETREG4(sc, AAC_RKT_MAILBOX + 16, arg3);
+}
+
 /*
  * Fetch the immediate command status word
  */
@@ -2216,6 +2679,14 @@ aac_fa_get_mailbox(struct aac_softc *sc, int mb)
 	return (val);
 }
 
+static int
+aac_rkt_get_mailbox(struct aac_softc *sc, int mb)
+{
+	debug_called(4);
+
+	return(AAC_GETREG4(sc, AAC_RKT_MAILBOX + (mb * 4)));
+}
+
 /*
  * Set/clear interrupt masks
  */
@@ -2237,7 +2708,10 @@ aac_rx_set_interrupts(struct aac_softc *sc, int enable)
 	debug(2, "%sable interrupts", enable ? "en" : "dis");
 
 	if (enable) {
-		AAC_SETREG4(sc, AAC_RX_OIMR, ~AAC_DB_INTERRUPTS);
+		if (sc->flags & AAC_FLAGS_NEW_COMM)
+			AAC_SETREG4(sc, AAC_RX_OIMR, ~AAC_DB_INT_NEW_COMM);
+		else
+			AAC_SETREG4(sc, AAC_RX_OIMR, ~AAC_DB_INTERRUPTS);
 	} else {
 		AAC_SETREG4(sc, AAC_RX_OIMR, ~0);
 	}
@@ -2257,6 +2731,105 @@ aac_fa_set_interrupts(struct aac_softc *sc, int enable)
 	}
 }
 
+static void
+aac_rkt_set_interrupts(struct aac_softc *sc, int enable)
+{
+	debug(2, "%sable interrupts", enable ? "en" : "dis");
+
+	if (enable) {
+		if (sc->flags & AAC_FLAGS_NEW_COMM)
+			AAC_SETREG4(sc, AAC_RKT_OIMR, ~AAC_DB_INT_NEW_COMM);
+		else
+			AAC_SETREG4(sc, AAC_RKT_OIMR, ~AAC_DB_INTERRUPTS);
+	} else {
+		AAC_SETREG4(sc, AAC_RKT_OIMR, ~0);
+	}
+}
+
+/*
+ * New comm. interface: Send command functions
+ */
+static int
+aac_rx_send_command(struct aac_softc *sc, struct aac_command *cm)
+{
+	u_int32_t index, device;
+
+	debug(2, "send command (new comm.)");
+
+	index = AAC_GETREG4(sc, AAC_RX_IQUE);
+	if (index == 0xffffffffL)
+		index = AAC_GETREG4(sc, AAC_RX_IQUE);
+	if (index == 0xffffffffL)
+		return index;
+	aac_enqueue_busy(cm);
+	device = index;
+	AAC_SETREG4(sc, device, (u_int32_t)(cm->cm_fibphys & 0xffffffffUL));
+	device += 4;
+	AAC_SETREG4(sc, device, (u_int32_t)(cm->cm_fibphys >> 32));
+	device += 4;
+	AAC_SETREG4(sc, device, cm->cm_fib->Header.Size);
+	AAC_SETREG4(sc, AAC_RX_IQUE, index);
+	return 0;
+}
+
+static int
+aac_rkt_send_command(struct aac_softc *sc, struct aac_command *cm)
+{
+	u_int32_t index, device;
+
+	debug(2, "send command (new comm.)");
+
+	index = AAC_GETREG4(sc, AAC_RKT_IQUE);
+	if (index == 0xffffffffL)
+		index = AAC_GETREG4(sc, AAC_RKT_IQUE);
+	if (index == 0xffffffffL)
+		return index;
+	aac_enqueue_busy(cm);
+	device = index;
+	AAC_SETREG4(sc, device, (u_int32_t)(cm->cm_fibphys & 0xffffffffUL));
+	device += 4;
+	AAC_SETREG4(sc, device, (u_int32_t)(cm->cm_fibphys >> 32));
+	device += 4;
+	AAC_SETREG4(sc, device, cm->cm_fib->Header.Size);
+	AAC_SETREG4(sc, AAC_RKT_IQUE, index);
+	return 0;
+}
+
+/*
+ * New comm. interface: get, set outbound queue index
+ */
+static int
+aac_rx_get_outb_queue(struct aac_softc *sc)
+{
+	debug_called(3);
+
+	return(AAC_GETREG4(sc, AAC_RX_OQUE));
+}
+
+static int
+aac_rkt_get_outb_queue(struct aac_softc *sc)
+{
+	debug_called(3);
+
+	return(AAC_GETREG4(sc, AAC_RKT_OQUE));
+}
+
+static void
+aac_rx_set_outb_queue(struct aac_softc *sc, int index)
+{
+	debug_called(3);
+
+	AAC_SETREG4(sc, AAC_RX_OQUE, index);
+}
+
+static void
+aac_rkt_set_outb_queue(struct aac_softc *sc, int index)
+{
+	debug_called(3);
+
+	AAC_SETREG4(sc, AAC_RKT_OQUE, index);
+}
+
 /*
  * Debugging and Diagnostics
  */
@@ -2272,34 +2845,45 @@ aac_describe_controller(struct aac_softc *sc)
 
 	debug_called(2);
 
-	aac_alloc_sync_fib(sc, &fib, 0);
+	AAC_LOCK_ACQUIRE(&sc->aac_io_lock);
+	aac_alloc_sync_fib(sc, &fib);
 
 	fib->data[0] = 0;
 	if (aac_sync_fib(sc, RequestAdapterInfo, 0, fib, 1)) {
 		device_printf(sc->aac_dev, "RequestAdapterInfo failed\n");
 		aac_release_sync_fib(sc);
+		AAC_LOCK_RELEASE(&sc->aac_io_lock);
 		return;
 	}
-	info = (struct aac_adapter_info *)&fib->data[0];   
-
-	device_printf(sc->aac_dev, "%s %dMHz, %dMB cache memory, %s\n", 
-		      aac_describe_code(aac_cpu_variant, info->CpuVariant),
-		      info->ClockSpeed, info->BufferMem / (1024 * 1024), 
-		      aac_describe_code(aac_battery_platform,
-					info->batteryPlatform));
 
 	/* save the kernel revision structure for later use */
+	info = (struct aac_adapter_info *)&fib->data[0];
 	sc->aac_revision = info->KernelRevision;
-	device_printf(sc->aac_dev, "Kernel %d.%d-%d, Build %d, S/N %6X\n",
-		      info->KernelRevision.external.comp.major,
-		      info->KernelRevision.external.comp.minor,
-		      info->KernelRevision.external.comp.dash,
-		      info->KernelRevision.buildNumber,
-		      (u_int32_t)(info->SerialNumber & 0xffffff));
 
-	aac_release_sync_fib(sc);
+	device_printf(sc->aac_dev, "Adaptec Raid Controller %d.%d.%d-%d\n",
+		AAC_DRIVER_VERSION >> 24,
+		(AAC_DRIVER_VERSION >> 16) & 0xFF,
+		AAC_DRIVER_VERSION & 0xFF,
+		AAC_DRIVER_BUILD);
+
+	if (bootverbose) {
+		device_printf(sc->aac_dev, "%s %dMHz, %dMB memory "
+		    "(%dMB cache, %dMB execution), %s\n",
+		    aac_describe_code(aac_cpu_variant, info->CpuVariant),
+		    info->ClockSpeed, info->TotalMem / (1024 * 1024),
+		    info->BufferMem / (1024 * 1024),
+		    info->ExecutionMem / (1024 * 1024),
+		    aac_describe_code(aac_battery_platform,
+		    info->batteryPlatform));
+
+		device_printf(sc->aac_dev,
+		    "Kernel %d.%d-%d, Build %d, S/N %6X\n",
+		    info->KernelRevision.external.comp.major,
+		    info->KernelRevision.external.comp.minor,
+		    info->KernelRevision.external.comp.dash,
+		    info->KernelRevision.buildNumber,
+		    (u_int32_t)(info->SerialNumber & 0xffffff));
 
-	if (1 || bootverbose) {
 		device_printf(sc->aac_dev, "Supported Options=%b\n",
 			      sc->supported_options,
 			      "\20"
@@ -2315,8 +2899,16 @@ aac_describe_controller(struct aac_softc *sc)
 			      "\12NORECOND"
 			      "\13SGMAP64"
 			      "\14ALARM"
-			      "\15NONDASD");
+			      "\15NONDASD"
+			      "\16SCSIMGT"
+			      "\17RAIDSCSI"
+			      "\21ADPTINFO"
+			      "\22NEWCOMM"
+			      "\23ARRAY64BIT"
+			      "\24HEATSENSOR");
 	}
+	aac_release_sync_fib(sc);
+	AAC_LOCK_RELEASE(&sc->aac_io_lock);
 }
 
 /*
@@ -2380,7 +2972,7 @@ aac_ioctl(struct dev_ioctl_args *ap)
 	caddr_t arg = ap->a_data;
 	struct aac_softc *sc = dev->si_drv1;
 	int error = 0;
-	int i;
+	uint32_t cookie;
 
 	debug_called(2);
 
@@ -2426,11 +3018,11 @@ aac_ioctl(struct dev_ioctl_args *ap)
 		 *
 		 * The Linux code hands the driver a pointer into kernel space,
 		 * and then trusts it when the caller hands it back.  Aiee!
-		 * Here, we give it the proc pointer of the per-adapter aif 
+		 * Here, we give it the proc pointer of the per-adapter aif
 		 * thread. It's only used as a sanity check in other calls.
 		 */
-		i = (int)sc->aifthread;
-		error = copyout(&i, arg, sizeof(i));
+		cookie = (uint32_t)(uintptr_t)sc->aifthread;
+		error = copyout(&cookie, arg, sizeof(cookie));
 		break;
 	case FSACTL_GET_NEXT_ADAPTER_FIB:
 		debug(1, "FSACTL_GET_NEXT_ADAPTER_FIB");
@@ -2447,15 +3039,21 @@ aac_ioctl(struct dev_ioctl_args *ap)
 	case FSACTL_QUERY_DISK:
 		debug(1, "FSACTL_QUERY_DISK");
 		error = aac_query_disk(sc, arg);
-			break;
+		break;
 	case FSACTL_DELETE_DISK:
 		/*
 		 * We don't trust the underland to tell us when to delete a
-		 * container, rather we rely on an AIF coming from the 
+		 * container, rather we rely on an AIF coming from the
 		 * controller
 		 */
 		error = 0;
 		break;
+	case FSACTL_GET_PCI_INFO:
+		arg = *(caddr_t*)arg;
+	case FSACTL_LNX_GET_PCI_INFO:
+		debug(1, "FSACTL_GET_PCI_INFO");
+		error = aac_get_pci_info(sc, arg);
+		break;
 	default:
 		debug(1, "unsupported cmd 0x%lx\n", ap->a_cmd);
 		error = EINVAL;
@@ -2489,6 +3087,27 @@ aac_poll(struct dev_poll_args *ap)
 	return (0);
 }
 
+static void
+aac_ioctl_event(struct aac_softc *sc, struct aac_event *event, void *arg)
+{
+
+	switch (event->ev_type) {
+	case AAC_EVENT_CMFREE:
+		AAC_LOCK_ACQUIRE(&sc->aac_io_lock);
+		if (aac_alloc_command(sc, (struct aac_command **)arg)) {
+			aac_add_event(sc, event);
+			AAC_LOCK_RELEASE(&sc->aac_io_lock);
+			return;
+		}
+		kfree(event, M_AACBUF);
+		wakeup(arg);
+		AAC_LOCK_RELEASE(&sc->aac_io_lock);
+		break;
+	default:
+		break;
+	}
+}
+
 /*
  * Send a FIB supplied from userspace
  */
@@ -2505,10 +3124,24 @@ aac_ioctl_sendfib(struct aac_softc *sc, caddr_t ufib)
 	/*
 	 * Get a command
 	 */
+	AAC_LOCK_ACQUIRE(&sc->aac_io_lock);
 	if (aac_alloc_command(sc, &cm)) {
-		error = EBUSY;
-		goto out;
+		struct aac_event *event;
+
+		event = kmalloc(sizeof(struct aac_event), M_AACBUF,
+		    M_INTWAIT | M_ZERO);
+		event->ev_type = AAC_EVENT_CMFREE;
+		event->ev_callback = aac_ioctl_event;
+		event->ev_arg = &cm;
+		aac_add_event(sc, event);
+		crit_enter();
+		tsleep_interlock(&cm);
+		AAC_LOCK_RELEASE(&sc->aac_io_lock);
+		tsleep(&cm, 0, "sendfib", 0);
+		AAC_LOCK_ACQUIRE(&sc->aac_io_lock);
+		crit_exit();
 	}
+	AAC_LOCK_RELEASE(&sc->aac_io_lock);
 
 	/*
 	 * Fetch the FIB header, then re-copy to get data as well.
@@ -2518,7 +3151,7 @@ aac_ioctl_sendfib(struct aac_softc *sc, caddr_t ufib)
 		goto out;
 	size = cm->cm_fib->Header.Size + sizeof(struct aac_fib_header);
 	if (size > sizeof(struct aac_fib)) {
-		device_printf(sc->aac_dev, "incoming FIB oversized (%d > %d)\n",
+		device_printf(sc->aac_dev, "incoming FIB oversized (%d > %zd)\n",
 			      size, sizeof(struct aac_fib));
 		size = sizeof(struct aac_fib);
 	}
@@ -2530,26 +3163,32 @@ aac_ioctl_sendfib(struct aac_softc *sc, caddr_t ufib)
 	/*
 	 * Pass the FIB to the controller, wait for it to complete.
 	 */
-	if ((error = aac_wait_command(cm, 30)) != 0) {	/* XXX user timeout? */
-		kprintf("aac_wait_command return %d\n", error);
+	AAC_LOCK_ACQUIRE(&sc->aac_io_lock);
+	if ((error = aac_wait_command(cm)) != 0) {
+		device_printf(sc->aac_dev,
+			      "aac_wait_command return %d\n", error);
 		goto out;
 	}
+	AAC_LOCK_RELEASE(&sc->aac_io_lock);
 
 	/*
 	 * Copy the FIB and data back out to the caller.
 	 */
 	size = cm->cm_fib->Header.Size;
 	if (size > sizeof(struct aac_fib)) {
-		device_printf(sc->aac_dev, "outbound FIB oversized (%d > %d)\n",
+		device_printf(sc->aac_dev, "outbound FIB oversized (%d > %zd)\n",
 			      size, sizeof(struct aac_fib));
 		size = sizeof(struct aac_fib);
 	}
 	error = copyout(cm->cm_fib, ufib, size);
+	AAC_LOCK_ACQUIRE(&sc->aac_io_lock);
 
 out:
 	if (cm != NULL) {
 		aac_release_command(cm);
 	}
+
+	AAC_LOCK_RELEASE(&sc->aac_io_lock);
 	return(error);
 }
 
@@ -2580,11 +3219,11 @@ aac_handle_aif(struct aac_softc *sc, struct aac_fib *fib)
 		case AifEnAddContainer:
 		case AifEnDeleteContainer:
 			/*
-			 * A container was added or deleted, but the message 
+			 * A container was added or deleted, but the message
 			 * doesn't tell us anything else!  Re-enumerate the
 			 * containers and sort things out.
 			 */
-			aac_alloc_sync_fib(sc, &fib, 0);
+			aac_alloc_sync_fib(sc, &fib);
 			mi = (struct aac_mntinfo *)&fib->data[0];
 			do {
 				/*
@@ -2619,7 +3258,7 @@ aac_handle_aif(struct aac_softc *sc, struct aac_fib *fib)
 				    (mir->MntTable[0].VolType != CT_NONE)) {
 					found = 0;
 					TAILQ_FOREACH(co,
-						      &sc->aac_container_tqh, 
+						      &sc->aac_container_tqh,
 						      co_link) {
 						if (co->co_mntobj.ObjectId ==
 						    mir->MntTable[0].ObjectId) {
@@ -2639,7 +3278,8 @@ aac_handle_aif(struct aac_softc *sc, struct aac_fib *fib)
 
 					/*
 					 * This is a new container.  Do all the
-					 * appropriate things to set it up.						 */
+					 * appropriate things to set it up.
+					 */
 					aac_add_container(sc, mir, 1);
 					added = 1;
 				}
@@ -2657,8 +3297,12 @@ aac_handle_aif(struct aac_softc *sc, struct aac_fib *fib)
 			co = TAILQ_FIRST(&sc->aac_container_tqh);
 			while (co != NULL) {
 				if (co->co_found == 0) {
+					AAC_LOCK_RELEASE(&sc->aac_io_lock);
+					get_mplock();
 					device_delete_child(sc->aac_dev,
 							    co->co_disk);
+					rel_mplock();
+					AAC_LOCK_ACQUIRE(&sc->aac_io_lock);
 					co_next = TAILQ_NEXT(co, co_link);
 					AAC_LOCK_ACQUIRE(&sc->
 							aac_container_lock);
@@ -2666,7 +3310,7 @@ aac_handle_aif(struct aac_softc *sc, struct aac_fib *fib)
 						     co_link);
 					AAC_LOCK_RELEASE(&sc->
 							 aac_container_lock);
-					FREE(co, M_AACBUF);
+					kfree(co, M_AACBUF);
 					co = co_next;
 				} else {
 					co->co_found = 0;
@@ -2675,10 +3319,15 @@ aac_handle_aif(struct aac_softc *sc, struct aac_fib *fib)
 			}
 
 			/* Attach the newly created containers */
-			if (added)
+			if (added) {
+				AAC_LOCK_RELEASE(&sc->aac_io_lock);
+				get_mplock();
 				bus_generic_attach(sc->aac_dev);
-	
-				break;
+				rel_mplock();
+				AAC_LOCK_ACQUIRE(&sc->aac_io_lock);
+			}
+
+			break;
 
 		default:
 			break;
@@ -2763,11 +3412,10 @@ aac_getnext_aif(struct aac_softc *sc, caddr_t arg)
 		/*
 		 * Check the magic number that we gave the caller.
 		 */
-		if (agf.AdapterFibContext != (int)sc->aifthread) {
+		if (agf.AdapterFibContext != (int)(uintptr_t)sc->aifthread) {
 			error = EFAULT;
 		} else {
 	
-			crit_enter();
 			error = aac_return_aif(sc, agf.AifFib);
 	
 			if ((error == EAGAIN) && (agf.Wait)) {
@@ -2781,7 +3429,6 @@ aac_getnext_aif(struct aac_softc *sc, caddr_t arg)
 				}
 				sc->aac_state &= ~AAC_STATE_AIF_SLEEPER;
 			}
-			crit_exit();
 		}
 	}
 	return(error);
@@ -2795,26 +3442,49 @@ aac_getnext_aif(struct aac_softc *sc, caddr_t arg)
 static int
 aac_return_aif(struct aac_softc *sc, caddr_t uptr)
 {
-	int error;
+	int next, error;
 
 	debug_called(2);
 
 	AAC_LOCK_ACQUIRE(&sc->aac_aifq_lock);
 	if (sc->aac_aifq_tail == sc->aac_aifq_head) {
-		error = EAGAIN;
-	} else {
-		error = copyout(&sc->aac_aifq[sc->aac_aifq_tail], uptr,
-				sizeof(struct aac_aif_command));
-		if (error)
-			kprintf("aac_return_aif: copyout returned %d\n", error);
-		if (!error)
-			sc->aac_aifq_tail = (sc->aac_aifq_tail + 1) %
-					    AAC_AIFQ_LENGTH;
+		AAC_LOCK_RELEASE(&sc->aac_aifq_lock);
+		return (EAGAIN);
 	}
+
+	next = (sc->aac_aifq_tail + 1) % AAC_AIFQ_LENGTH;
+	error = copyout(&sc->aac_aifq[next], uptr,
+			sizeof(struct aac_aif_command));
+	if (error)
+		device_printf(sc->aac_dev,
+		    "aac_return_aif: copyout returned %d\n", error);
+	else
+		sc->aac_aifq_tail = next;
+
 	AAC_LOCK_RELEASE(&sc->aac_aifq_lock);
 	return(error);
 }
 
+static int
+aac_get_pci_info(struct aac_softc *sc, caddr_t uptr)
+{
+	struct aac_pci_info {
+		u_int32_t bus;
+		u_int32_t slot;
+	} pciinf;
+	int error;
+
+	debug_called(2);
+
+	pciinf.bus = pci_get_bus(sc->aac_dev);
+	pciinf.slot = pci_get_slot(sc->aac_dev);
+
+	error = copyout((caddr_t)&pciinf, uptr,
+			sizeof(struct aac_pci_info));
+
+	return (error);
+}
+
 /*
  * Give the userland some information about the container.  The AAC arch
  * expects the driver to be a SCSI passthrough type driver, so it expects
@@ -2847,23 +3517,23 @@ aac_query_disk(struct aac_softc *sc, caddr_t uptr)
 			break;
 		}
 
-		if (co == NULL) {
+	if (co == NULL) {
 			query_disk.Valid = 0;
 			query_disk.Locked = 0;
 			query_disk.Deleted = 1;		/* XXX is this right? */
-		} else {
-			disk = device_get_softc(co->co_disk);
-			query_disk.Valid = 1;
-			query_disk.Locked =
-			    (disk->ad_flags & AAC_DISK_OPEN) ? 1 : 0;
-			query_disk.Deleted = 0;
-			query_disk.Bus = device_get_unit(sc->aac_dev);
-			query_disk.Target = disk->unit;
-			query_disk.Lun = 0;
-			query_disk.UnMapped = 0;
-			bcopy(disk->ad_dev_t->si_name,
-			      &query_disk.diskDeviceName[0], 10);
-		}
+	} else {
+		disk = device_get_softc(co->co_disk);
+		query_disk.Valid = 1;
+		query_disk.Locked =
+		    (disk->ad_flags & AAC_DISK_OPEN) ? 1 : 0;
+		query_disk.Deleted = 0;
+		query_disk.Bus = device_get_unit(sc->aac_dev);
+		query_disk.Target = disk->unit;
+		query_disk.Lun = 0;
+		query_disk.UnMapped = 0;
+		bcopy(disk->ad_dev_t->si_name,
+		      &query_disk.diskDeviceName[0], 10);
+	}
 	AAC_LOCK_RELEASE(&sc->aac_container_lock);
 
 	error = copyout((caddr_t)&query_disk, uptr,
@@ -2881,11 +3551,12 @@ aac_get_bus_info(struct aac_softc *sc)
 	struct aac_vmioctl *vmi;
 	struct aac_vmi_businf_resp *vmi_resp;
 	struct aac_getbusinf businfo;
-	struct aac_cam_inf *caminf;
+	struct aac_sim *caminf;
 	device_t child;
 	int i, found, error;
 
-	aac_alloc_sync_fib(sc, &fib, 0);
+	AAC_LOCK_ACQUIRE(&sc->aac_io_lock);
+	aac_alloc_sync_fib(sc, &fib);
 	c_cmd = (struct aac_ctcfg *)&fib->data[0];
 	bzero(c_cmd, sizeof(struct aac_ctcfg));
 
@@ -2899,6 +3570,7 @@ aac_get_bus_info(struct aac_softc *sc)
 		device_printf(sc->aac_dev, "Error %d sending "
 		    "VM_ContainerConfig command\n", error);
 		aac_release_sync_fib(sc);
+		AAC_LOCK_RELEASE(&sc->aac_io_lock);
 		return;
 	}
 
@@ -2907,6 +3579,7 @@ aac_get_bus_info(struct aac_softc *sc)
 		device_printf(sc->aac_dev, "VM_ContainerConfig returned 0x%x\n",
 		    c_resp->Status);
 		aac_release_sync_fib(sc);
+		AAC_LOCK_RELEASE(&sc->aac_io_lock);
 		return;
 	}
 
@@ -2927,6 +3600,7 @@ aac_get_bus_info(struct aac_softc *sc)
 		device_printf(sc->aac_dev, "Error %d sending VMIoctl command\n",
 		    error);
 		aac_release_sync_fib(sc);
+		AAC_LOCK_RELEASE(&sc->aac_io_lock);
 		return;
 	}
 
@@ -2934,33 +3608,40 @@ aac_get_bus_info(struct aac_softc *sc)
 	if (vmi_resp->Status != ST_OK) {
 		debug(1, "VM_Ioctl returned %d\n", vmi_resp->Status);
 		aac_release_sync_fib(sc);
+		AAC_LOCK_RELEASE(&sc->aac_io_lock);
 		return;
 	}
 
 	bcopy(&vmi_resp->BusInf, &businfo, sizeof(struct aac_getbusinf));
 	aac_release_sync_fib(sc);
+	AAC_LOCK_RELEASE(&sc->aac_io_lock);
 
 	found = 0;
 	for (i = 0; i < businfo.BusCount; i++) {
 		if (businfo.BusValid[i] != AAC_BUS_VALID)
 			continue;
 
-		MALLOC(caminf, struct aac_cam_inf *,
-		    sizeof(struct aac_cam_inf), M_AACBUF, M_INTWAIT | M_ZERO);
+		caminf = (struct aac_sim *)kmalloc(sizeof(struct aac_sim),
+		    M_AACBUF, M_INTWAIT | M_ZERO);
 
 		child = device_add_child(sc->aac_dev, "aacp", -1);
 		if (child == NULL) {
-			device_printf(sc->aac_dev, "device_add_child failed\n");
-			continue;
-		}
+			device_printf(sc->aac_dev,
+			    "device_add_child failed for passthrough bus %d\n",
+			    i);
+			kfree(caminf, M_AACBUF);
+			break;
+		};
 
 		caminf->TargetsPerBus = businfo.TargetsPerBus;
 		caminf->BusNumber = i;
 		caminf->InitiatorBusId = businfo.InitiatorBusId[i];
 		caminf->aac_sc = sc;
+		caminf->sim_dev = child;
 
 		device_set_ivars(child, caminf);
 		device_set_desc(child, "SCSI Passthrough Bus");
+		TAILQ_INSERT_TAIL(&sc->aac_sim_tqh, caminf, sim_link);
 
 		found = 1;
 	}
diff --git a/sys/dev/raid/aac/aac_cam.c b/sys/dev/raid/aac/aac_cam.c
index 1f8496f..6e2d1d2 100644
--- a/sys/dev/raid/aac/aac_cam.c
+++ b/sys/dev/raid/aac/aac_cam.c
@@ -1,4 +1,4 @@
-/*
+/*-
  * Copyright (c) 2002 Adaptec, Inc.
  * All rights reserved.
  *
@@ -38,6 +38,7 @@
 #include <sys/kernel.h>
 #include <sys/sysctl.h>
 #include <sys/malloc.h>
+#include <sys/module.h>
 
 #include <bus/cam/cam.h>
 #include <bus/cam/cam_ccb.h>
@@ -47,7 +48,6 @@
 #include <bus/cam/scsi/scsi_all.h>
 #include <bus/cam/scsi/scsi_message.h>
 
-#include "aac_compat.h"
 #include <sys/bus.h>
 #include <sys/conf.h>
 #include <sys/devicestat.h>
@@ -62,11 +62,10 @@
 #include "aacreg.h"
 #include "aac_ioctl.h"
 #include "aacvar.h"
-#include "aac_cam.h"
 
 struct aac_cam {
 	device_t		dev;
-	struct aac_cam_inf	*inf;
+	struct aac_sim		*inf;
 	struct cam_sim		*sim;
 	struct cam_path		*path;
 };
@@ -80,7 +79,6 @@ static void aac_cam_complete(struct aac_command *);
 static u_int32_t aac_cam_reset_bus(struct cam_sim *, union ccb *);
 static u_int32_t aac_cam_abort_ccb(struct cam_sim *, union ccb *);
 static u_int32_t aac_cam_term_io(struct cam_sim *, union ccb *);
-static int aac_cam_get_tran_settings(struct aac_softc *, struct ccb_trans_settings *, u_int32_t);
 
 static devclass_t	aac_pass_devclass;
 
@@ -102,10 +100,29 @@ MODULE_DEPEND(aacp, cam, 1, 1, 1);
 
 MALLOC_DEFINE(M_AACCAM, "aaccam", "AAC CAM info");
 
+static void
+aac_cam_event(struct aac_softc *sc, struct aac_event *event, void *arg)
+{
+	struct aac_cam *camsc;
+
+	switch (event->ev_type) {
+	case AAC_EVENT_CMFREE:
+		camsc = arg;
+		kfree(event, M_AACCAM);
+		xpt_release_simq(camsc->sim, 1);
+		break;
+	default:
+		device_printf(sc->aac_dev, "unknown event %d in aac_cam\n",
+		    event->ev_type);
+		break;
+	}
+
+	return;
+}
+
 static int
 aac_cam_probe(device_t dev)
 {
-
 	debug_called(2);
 
 	return (0);
@@ -114,6 +131,19 @@ aac_cam_probe(device_t dev)
 static int
 aac_cam_detach(device_t dev)
 {
+	struct aac_cam *camsc;
+	debug_called(2);
+
+	camsc = (struct aac_cam *)device_get_softc(dev);
+
+	get_mplock();
+
+	xpt_async(AC_LOST_DEVICE, camsc->path, NULL);
+	xpt_free_path(camsc->path);
+	xpt_bus_deregister(cam_sim_path(camsc->sim));
+	cam_sim_free(camsc->sim);
+
+	rel_mplock();
 
 	return (0);
 }
@@ -128,12 +158,12 @@ aac_cam_attach(device_t dev)
 	struct cam_sim *sim;
 	struct cam_path *path;
 	struct aac_cam *camsc;
-	struct aac_cam_inf *inf;
+	struct aac_sim *inf;
 
 	debug_called(1);
 
 	camsc = (struct aac_cam *)device_get_softc(dev);
-	inf = (struct aac_cam_inf *)device_get_ivars(dev);
+	inf = (struct aac_sim *)device_get_ivars(dev);
 	camsc->inf = inf;
 
 	devq = cam_simq_alloc(inf->TargetsPerBus);
@@ -220,6 +250,8 @@ aac_cam_action(struct cam_sim *sim, union ccb *ccb)
 		cpi->version_num = 1;
 		cpi->hba_inquiry = PI_WIDE_16;
 		cpi->target_sprt = 0;
+
+		/* Resetting via the passthrough causes problems. */
 		cpi->hba_misc = PIM_NOBUSRESET;
 		cpi->hba_eng_cnt = 0;
 		cpi->max_target = camsc->inf->TargetsPerBus;
@@ -243,12 +275,26 @@ aac_cam_action(struct cam_sim *sim, union ccb *ccb)
 	}
 	case XPT_GET_TRAN_SETTINGS:
 	{
-		u_int32_t handle;
-
-		handle = AAC_BTL_TO_HANDLE(camsc->inf->BusNumber,
-		    ccb->ccb_h.target_id, ccb->ccb_h.target_lun);
-		ccb->ccb_h.status = aac_cam_get_tran_settings(sc, &ccb->cts,
-		    handle);
+#ifdef	CAM_NEW_TRAN_CODE
+		struct ccb_trans_settings_scsi *scsi =
+			&ccb->cts.proto_specific.scsi;
+		struct ccb_trans_settings_spi *spi =
+			&ccb->cts.xport_specific.spi;
+		ccb->cts.protocol = PROTO_SCSI;
+		ccb->cts.protocol_version = SCSI_REV_2;
+		ccb->cts.transport = XPORT_SPI;
+		ccb->cts.transport_version = 2;
+		if (ccb->ccb_h.target_lun != CAM_LUN_WILDCARD) {
+			scsi->valid = CTS_SCSI_VALID_TQ;
+			spi->valid |= CTS_SPI_VALID_DISC;
+		} else {
+			scsi->valid = 0;
+		}
+#else
+		ccb->cts.flags &= ~(CCB_TRANS_DISC_ENB | CCB_TRANS_TAG_ENB);
+		ccb->cts.valid = CCB_TRANS_DISC_VALID | CCB_TRANS_TQ_VALID;
+#endif
+		ccb->ccb_h.status = CAM_REQ_CMP;
 		xpt_done(ccb);
 		return;
 	}
@@ -282,10 +328,20 @@ aac_cam_action(struct cam_sim *sim, union ccb *ccb)
 
 	/* Async ops that require communcation with the controller */
 
+	AAC_LOCK_ACQUIRE(&sc->aac_io_lock);
 	if (aac_alloc_command(sc, &cm)) {
+		struct aac_event *event;
+
 		xpt_freeze_simq(sim, 1);
 		ccb->ccb_h.status = CAM_REQUEUE_REQ;
 		xpt_done(ccb);
+		event = kmalloc(sizeof(struct aac_event), M_AACCAM,
+				M_INTWAIT | M_ZERO);
+		event->ev_callback = aac_cam_event;
+		event->ev_arg = camsc;
+		event->ev_type = AAC_EVENT_CMFREE;
+		aac_add_event(sc, event);
+		AAC_LOCK_RELEASE(&sc->aac_io_lock);
 		return;
 	}
 
@@ -335,9 +391,14 @@ aac_cam_action(struct cam_sim *sim, union ccb *ccb)
 			if ((ccb->ccb_h.flags & CAM_SCATTER_VALID) == 0) {
 				srb->data_len = csio->dxfer_len;
 				if (ccb->ccb_h.flags & CAM_DATA_PHYS) {
+					/*
+					 * XXX This isn't 64-bit clean.
+					 * However, this condition is not
+					 * normally used in CAM.
+					 */
 					srb->sg_map32.SgCount = 1;
 					srb->sg_map32.SgEntry[0].SgAddress =
-					    (u_int32_t)csio->data_ptr;
+					    (uint32_t)(uintptr_t)csio->data_ptr;
 					srb->sg_map32.SgEntry[0].SgByteCount =
 					    csio->dxfer_len;
 				} else {
@@ -368,6 +429,7 @@ aac_cam_action(struct cam_sim *sim, union ccb *ccb)
 		} else {
 			ccb->ccb_h.status = CAM_REQ_CMP;
 			xpt_done(ccb);
+			AAC_LOCK_RELEASE(&sc->aac_io_lock);
 			return;
 		}
 	default:
@@ -398,6 +460,8 @@ aac_cam_action(struct cam_sim *sim, union ccb *ccb)
 	aac_enqueue_ready(cm);
 
+	AAC_LOCK_RELEASE(&sc->aac_io_lock);
+
 	return;
 }
 
@@ -452,7 +516,7 @@ aac_cam_complete(struct aac_command *cm)
 				    srbr->sense_len);
 				ccb->csio.sense_len = sense_len;
 				ccb->ccb_h.status |= CAM_AUTOSNS_VALID;
-				scsi_sense_print(&ccb->csio);
+				/* scsi_sense_print(&ccb->csio); */
 			}
 
 			/* If this is an inquiry command, fake things out */
@@ -478,7 +542,6 @@ aac_cam_complete(struct aac_command *cm)
 	}
 
 	aac_release_command(cm);
-
 	xpt_done(ccb);
 
 	return;
@@ -502,7 +565,8 @@ aac_cam_reset_bus(struct cam_sim *sim, union ccb *ccb)
 		return (CAM_REQ_ABORTED);
 	}
 
-	aac_alloc_sync_fib(sc, &fib, 0);
+	AAC_LOCK_ACQUIRE(&sc->aac_io_lock);
+	aac_alloc_sync_fib(sc, &fib);
 
 	vmi = (struct aac_vmioctl *)&fib->data[0];
 	bzero(vmi, sizeof(struct aac_vmioctl));
@@ -519,13 +583,15 @@ aac_cam_reset_bus(struct cam_sim *sim, union ccb *ccb)
 	e = aac_sync_fib(sc, ContainerCommand, 0, fib,
 	    sizeof(struct aac_vmioctl));
 	if (e) {
-		device_printf(sc->aac_dev, "Error 0x%x sending passthrough\n",
+		device_printf(sc->aac_dev,"Error %d sending ResetBus command\n",
 		    e);
 		aac_release_sync_fib(sc);
+		AAC_LOCK_RELEASE(&sc->aac_io_lock);
 		return (CAM_REQ_ABORTED);
 	}
 
 	aac_release_sync_fib(sc);
+	AAC_LOCK_RELEASE(&sc->aac_io_lock);
 	return (CAM_REQ_CMP);
 }
 
@@ -540,57 +606,3 @@ aac_cam_term_io(struct cam_sim *sim, union ccb *ccb)
 {
 	return (CAM_UA_TERMIO);
 }
-
-static int
-aac_cam_get_tran_settings(struct aac_softc *sc, struct ccb_trans_settings *cts, u_int32_t handle)
-{
-	struct aac_fib *fib;
-	struct aac_vmioctl *vmi;
-	struct aac_vmi_devinfo_resp *vmi_resp;
-	int error;
-
-	aac_alloc_sync_fib(sc, &fib, 0);
-	vmi = (struct aac_vmioctl *)&fib->data[0];
-	bzero(vmi, sizeof(struct aac_vmioctl));
-
-	vmi->Command = VM_Ioctl;
-	vmi->ObjType = FT_DRIVE;
-	vmi->MethId = sc->scsi_method_id;
-	vmi->ObjId = handle;
-	vmi->IoctlCmd = GetDeviceProbeInfo;
-
-	error = aac_sync_fib(sc, ContainerCommand, 0, fib,
-	    sizeof(struct aac_vmioctl));
-	if (error) {
-		device_printf(sc->aac_dev, "Error %d sending VMIoctl command\n",
-		    error);
-		aac_release_sync_fib(sc);
-		return (CAM_REQ_INVALID);
-	}
-
-	vmi_resp = (struct aac_vmi_devinfo_resp *)&fib->data[0];
-	if (vmi_resp->Status != ST_OK) {
-		debug(1, "VM_Ioctl returned %d\n", vmi_resp->Status);
-		aac_release_sync_fib(sc);
-		return (CAM_REQ_CMP_ERR);
-	}
-
-	cts->bus_width = ((vmi_resp->Inquiry7 & 0x60) >> 5);
-	if (vmi_resp->ScsiRate) {
-		cts->sync_period =
-		    scsi_calc_syncparam((10000 / vmi_resp->ScsiRate));
-		cts->sync_offset = vmi_resp->ScsiOffset;
-	} else {
-		cts->sync_period = 0;
-		cts->sync_offset = 0;
-	}
-	cts->flags &= ~(CCB_TRANS_DISC_ENB | CCB_TRANS_TAG_ENB);
-	cts->valid = CCB_TRANS_DISC_VALID		|
-		     CCB_TRANS_SYNC_RATE_VALID		|
-		     CCB_TRANS_SYNC_OFFSET_VALID	|
-		     CCB_TRANS_BUS_WIDTH_VALID		|
-		     CCB_TRANS_TQ_VALID;
-
-	aac_release_sync_fib(sc);
-	return (CAM_REQ_CMP);
-}
diff --git a/sys/dev/raid/aac/aac_cam.h b/sys/dev/raid/aac/aac_cam.h
deleted file mode 100644
index 1110d78..0000000
--- a/sys/dev/raid/aac/aac_cam.h
+++ /dev/null
@@ -1,35 +0,0 @@
-/*
- * Copyright (c) 2002 Adaptec, Inc.
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- *    notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- *    notice, this list of conditions and the following disclaimer in the
- *    documentation and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
- * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
- * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- *
- *	$FreeBSD: src/sys/dev/aac/aac_cam.h,v 1.1.2.1 2002/04/30 22:58:37 scottl Exp $
- *	$DragonFly: src/sys/dev/raid/aac/aac_cam.h,v 1.2 2003/06/17 04:28:21 dillon Exp $
- */
-
-struct aac_cam_inf {
-	int			TargetsPerBus;
-	int			BusNumber;
-	int			InitiatorBusId;
-	struct aac_softc	*aac_sc;
-};
diff --git a/sys/dev/raid/aac/aac_compat.h b/sys/dev/raid/aac/aac_compat.h
deleted file mode 100644
index 6dfe1a7..0000000
--- a/sys/dev/raid/aac/aac_compat.h
+++ /dev/null
@@ -1,42 +0,0 @@
-/*-
- * Copyright (c) 2000 Michael Smith
- * Copyright (c) 2000 BSDi
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- *    notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- *    notice, this list of conditions and the following disclaimer in the
- *    documentation and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
- * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
- * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- *
- * $FreeBSD: src/sys/dev/aac/aac_compat.h,v 1.2.2.2 2001/09/19 19:09:11 scottl Exp $
- * $DragonFly: src/sys/dev/raid/aac/aac_compat.h,v 1.8 2006/04/30 17:22:16 dillon Exp $
- */
-/*
- * Backwards compatibility support.
- */
-
-/*
- * Handle the new/old bio/buf changeover
- */
-
-#ifdef __DragonFly__
-#include <sys/proc.h>
-#include <sys/buf.h>
-#include <sys/buf2.h>
-#endif
diff --git a/sys/dev/raid/aac/aac_debug.c b/sys/dev/raid/aac/aac_debug.c
index 3ba1a2e..b2c8ddf 100644
--- a/sys/dev/raid/aac/aac_debug.c
+++ b/sys/dev/raid/aac/aac_debug.c
@@ -39,7 +39,6 @@
 #include <sys/systm.h>
 #include <sys/kernel.h>
 
-#include "aac_compat.h"
 #include <sys/bus.h>
 #include <sys/devicestat.h>
 #include <sys/disk.h>
@@ -345,10 +344,10 @@ aac_print_aif(struct aac_softc *sc, struct aac_aif_command *aif)
 			break;
 		case AifEnDiskSetEvent:		/* A disk set event occured. */
 			device_printf(sc->aac_dev, "(DiskSetEvent) event %d "
-				      "diskset %lld creator %lld\n",
+				      "diskset %jd creator %jd\n",
 				      aif->data.EN.data.EDS.eventType, 
-				      aif->data.EN.data.EDS.DsNum, 
-				      aif->data.EN.data.EDS.CreatorId);
+				      (intmax_t)aif->data.EN.data.EDS.DsNum, 
+				      (intmax_t)aif->data.EN.data.EDS.CreatorId);
 			break;
 		case AifDenMorphComplete: 	/* A morph operation
 						 * completed */
diff --git a/sys/dev/raid/aac/aac_disk.c b/sys/dev/raid/aac/aac_disk.c
index 8987a3a..bf00ec6 100644
--- a/sys/dev/raid/aac/aac_disk.c
+++ b/sys/dev/raid/aac/aac_disk.c
@@ -35,9 +35,9 @@
 #include <sys/param.h>
 #include <sys/systm.h>
 #include <sys/kernel.h>
+#include <sys/module.h>
 #include <sys/sysctl.h>
 
-#include "aac_compat.h"
 #include <sys/bus.h>
 #include <sys/conf.h>
 #include <sys/devicestat.h>
@@ -204,10 +204,13 @@ aac_disk_strategy(struct dev_strategy_args *ap)
 	}
 
 	/* perform accounting */
-	devstat_start_transaction(&sc->ad_stats);
 
 	/* pass the bio to the controller - it can work out who we are */
+	AAC_LOCK_ACQUIRE(&sc->ad_controller->aac_io_lock);
+	devstat_start_transaction(&sc->ad_stats);
 	aac_submit_bio(sc, bio);
+	AAC_LOCK_RELEASE(&sc->ad_controller->aac_io_lock);
+
 	return(0);
 }
 
diff --git a/sys/dev/raid/aac/aac_linux.c b/sys/dev/raid/aac/aac_linux.c
index 71fc5d0..e2694f1 100644
--- a/sys/dev/raid/aac/aac_linux.c
+++ b/sys/dev/raid/aac/aac_linux.c
@@ -34,6 +34,7 @@
 #include <sys/systm.h>
 #include <sys/conf.h>
 #include <sys/kernel.h>
+#include <sys/module.h>
 #include <sys/file.h>
 #include <sys/ioccom.h>
 #include <sys/mapped_ioctl.h>
diff --git a/sys/dev/raid/aac/aac_pci.c b/sys/dev/raid/aac/aac_pci.c
index eebfe7d..7f7cfe6 100644
--- a/sys/dev/raid/aac/aac_pci.c
+++ b/sys/dev/raid/aac/aac_pci.c
@@ -39,8 +39,8 @@
 #include <sys/param.h>
 #include <sys/systm.h>
 #include <sys/kernel.h>
+#include <sys/module.h>
 
-#include "aac_compat.h"
 #include <sys/bus.h>
 #include <sys/conf.h>
 #include <sys/devicestat.h>
@@ -110,8 +110,8 @@ static struct aac_ident
 	"Dell PERC 3/Di"},
 	{0x1011, 0x0046, 0x9005, 0x0364, AAC_HWIF_STRONGARM, 0,
 	"Adaptec AAC-364"},
-	{0x1011, 0x0046, 0x9005, 0x0365, AAC_HWIF_STRONGARM, 0,
-	"Adaptec SCSI RAID 5400S"},
+	{0x1011, 0x0046, 0x9005, 0x0365, AAC_HWIF_STRONGARM,
+	 AAC_FLAGS_BROKEN_MEMMAP, "Adaptec SCSI RAID 5400S"},
 	{0x1011, 0x0046, 0x9005, 0x1364, AAC_HWIF_STRONGARM, AAC_FLAGS_PERC2QC,
 	"Dell PERC 2/QC"},
 	{0x1011, 0x0046, 0x103c, 0x10c2, AAC_HWIF_STRONGARM, 0,
@@ -123,35 +123,110 @@ static struct aac_ident
 	{0x9005, 0x0285, 0x9005, 0x0286, AAC_HWIF_I960RX, AAC_FLAGS_NO4GB,
 	"Adaptec SCSI RAID 2120S"},
 	{0x9005, 0x0285, 0x9005, 0x0290, AAC_HWIF_I960RX, AAC_FLAGS_NO4GB,
-	 "Adaptec SCSI RAID 2410SA"},
+	 "Adaptec SATA RAID 2410SA"},
 	{0x9005, 0x0285, 0x1028, 0x0291, AAC_HWIF_I960RX, AAC_FLAGS_NO4GB,
 	 "Dell CERC SATA RAID 2"},
 	{0x9005, 0x0285, 0x9005, 0x0292, AAC_HWIF_I960RX, AAC_FLAGS_NO4GB,
-	 "Adaptec SCSI RAID 2810SA"},
+	 "Adaptec SATA RAID 2810SA"},
+	{0x9005, 0x0285, 0x9005, 0x0293, AAC_HWIF_I960RX, AAC_FLAGS_NO4GB,
+	 "Adaptec SATA RAID 21610SA"},
+	{0x9005, 0x0285, 0x103c, 0x3227, AAC_HWIF_I960RX, AAC_FLAGS_NO4GB,
+	 "HP ML110 G2 (Adaptec 2610SA)"},
+	{0x9005, 0x0286, 0x9005, 0x028c, AAC_HWIF_RKT, 0,
+	 "Adaptec SCSI RAID 2230S"},
+	{0x9005, 0x0286, 0x9005, 0x028d, AAC_HWIF_RKT, 0,
+	 "Adaptec SCSI RAID 2130S"},
+
+	{0x9005, 0x0285, 0x9005, 0x0287, AAC_HWIF_I960RX, AAC_FLAGS_NO4GB |
+	 AAC_FLAGS_256FIBS, "Adaptec SCSI RAID 2200S"},
+	{0x9005, 0x0285, 0x17aa, 0x0286, AAC_HWIF_I960RX, AAC_FLAGS_NO4GB |
+	 AAC_FLAGS_256FIBS, "Legend S220"},
+	{0x9005, 0x0285, 0x17aa, 0x0287, AAC_HWIF_I960RX, AAC_FLAGS_NO4GB |
+	 AAC_FLAGS_256FIBS, "Legend S230"},
+	{0x9005, 0x0285, 0x9005, 0x0288, AAC_HWIF_I960RX, 0,
+	 "Adaptec SCSI RAID 3230S"},
+	{0x9005, 0x0285, 0x9005, 0x0289, AAC_HWIF_I960RX, 0,
+	 "Adaptec SCSI RAID 3240S"},
+	{0x9005, 0x0285, 0x9005, 0x028a, AAC_HWIF_I960RX, 0,
+	 "Adaptec SCSI RAID 2020ZCR"},
+	{0x9005, 0x0285, 0x9005, 0x028b, AAC_HWIF_I960RX, 0,
+	 "Adaptec SCSI RAID 2025ZCR"},
+	{0x9005, 0x0286, 0x9005, 0x029b, AAC_HWIF_RKT, 0,
+	 "Adaptec SATA RAID 2820SA"},
+	{0x9005, 0x0286, 0x9005, 0x029c, AAC_HWIF_RKT, 0,
+	 "Adaptec SATA RAID 2620SA"},
+	{0x9005, 0x0286, 0x9005, 0x029d, AAC_HWIF_RKT, 0,
+	 "Adaptec SATA RAID 2420SA"},
+	{0x9005, 0x0286, 0x9005, 0x029e, AAC_HWIF_RKT, 0,
+	 "ICP ICP9024RO SCSI RAID"},
+	{0x9005, 0x0286, 0x9005, 0x029f, AAC_HWIF_RKT, 0,
+	 "ICP ICP9014RO SCSI RAID"},
+	{0x9005, 0x0285, 0x9005, 0x0294, AAC_HWIF_I960RX, 0,
+	 "Adaptec SATA RAID 2026ZCR"},
+	{0x9005, 0x0285, 0x103c, 0x3227, AAC_HWIF_I960RX, 0,
+	 "Adaptec SATA RAID 2610SA"},
+	{0x9005, 0x0285, 0x9005, 0x0296, AAC_HWIF_I960RX, 0,
+	 "Adaptec SCSI RAID 2240S"},
+	{0x9005, 0x0285, 0x9005, 0x0297, AAC_HWIF_I960RX, 0,
+	 "Adaptec SAS RAID 4005SAS"},
+	{0x9005, 0x0285, 0x1014, 0x02f2, AAC_HWIF_I960RX, 0,
+	 "IBM ServeRAID 8i"},
+	{0x9005, 0x0285, 0x9005, 0x0298, AAC_HWIF_I960RX, 0,
+	 "Adaptec SAS RAID 4000SAS"},
+	{0x9005, 0x0285, 0x9005, 0x0299, AAC_HWIF_I960RX, 0,
+	 "Adaptec SAS RAID 4800SAS"},
+	{0x9005, 0x0285, 0x9005, 0x029a, AAC_HWIF_I960RX, 0,
+	 "Adaptec SAS RAID 4805SAS"},
+	{0x9005, 0x0285, 0x9005, 0x028e, AAC_HWIF_I960RX, 0,
+	 "Adaptec SATA RAID 2020SA ZCR"},
+	{0x9005, 0x0285, 0x9005, 0x028f, AAC_HWIF_I960RX, 0,
+	 "Adaptec SATA RAID 2025SA ZCR"},
+	{0x9005, 0x0285, 0x9005, 0x02a4, AAC_HWIF_I960RX, 0,
+	 "ICP ICP9085LI SAS RAID"},
+	{0x9005, 0x0285, 0x9005, 0x02a5, AAC_HWIF_I960RX, 0,
+	 "ICP ICP5085BR SAS RAID"},
+	{0x9005, 0x0286, 0x9005, 0x02a0, AAC_HWIF_RKT, 0,
+	 "ICP ICP9047MA SATA RAID"},
+	{0x9005, 0x0286, 0x9005, 0x02a1, AAC_HWIF_RKT, 0,
+	 "ICP ICP9087MA SATA RAID"},
+	{0x9005, 0x0285, 0x9005, 0x02bb, AAC_HWIF_I960RX, 0,
+	 "Adaptec RAID 3405"},
+	{0x9005, 0x0285, 0x9005, 0x02bc, AAC_HWIF_I960RX, 0,
+	 "Adaptec RAID 3805"},
+	{0x9005, 0x0286, 0x1014, 0x9580, AAC_HWIF_RKT, 0,
+	 "IBM ServeRAID-8k"},
 	{0, 0, 0, 0, 0, 0, 0}
 };
 
+static struct aac_ident *
+aac_find_ident(device_t dev)
+{
+	struct aac_ident *m;
+
+	for (m = aac_identifiers; m->vendor != 0; m++) {
+		if ((m->vendor == pci_get_vendor(dev)) &&
+		    (m->device == pci_get_device(dev)) &&
+		    (m->subvendor == pci_get_subvendor(dev)) &&
+		    (m->subdevice == pci_get_subdevice(dev)))
+		return (m);
+	}
+
+	return (NULL);
+}
+
 /*
  * Determine whether this is one of our supported adapters.
  */
 static int
 aac_pci_probe(device_t dev)
 {
-	struct aac_ident *m;
+	struct aac_ident *id;
 
 	debug_called(1);
 
-	for (m = aac_identifiers; m->vendor != 0; m++) {
-		if ((m->vendor == pci_get_vendor(dev)) &&
-		    (m->device == pci_get_device(dev)) &&
-		    ((m->subvendor == 0) || (m->subvendor ==
-					     pci_get_subvendor(dev))) &&
-		    ((m->subdevice == 0) || ((m->subdevice ==
-					      pci_get_subdevice(dev))))) {
-		
-			device_set_desc(dev, m->desc);
-			return(-10);	/* allow room to be overridden */
-		}
+	if ((id = aac_find_ident(dev)) != NULL) {
+		device_set_desc(dev, id->desc);
+		return(BUS_PROBE_DEFAULT);
 	}
 	return(ENXIO);
 }
@@ -163,7 +238,8 @@ static int
 aac_pci_attach(device_t dev)
 {
 	struct aac_softc *sc;
-	int i, error;
+	struct aac_ident *id;
+	int error;
 	u_int32_t command;
 
 	debug_called(1);
@@ -197,12 +273,12 @@ aac_pci_attach(device_t dev)
 	/*
 	 * Allocate the PCI register window.
 	 */
-	sc->aac_regs_rid = 0x10;	/* first base address register */
-	if ((sc->aac_regs_resource = bus_alloc_resource(sc->aac_dev,
-							SYS_RES_MEMORY,
-							&sc->aac_regs_rid,
-							0, ~0, 1,
-							RF_ACTIVE)) == NULL) {
+	sc->aac_regs_rid = PCIR_BAR(0);
+	if ((sc->aac_regs_resource = bus_alloc_resource_any(sc->aac_dev,
+							    SYS_RES_MEMORY,
+							    &sc->aac_regs_rid,
+							    RF_ACTIVE)) ==
+							    NULL) {
 		device_printf(sc->aac_dev,
 			      "couldn't allocate register window\n");
 		goto out;
@@ -210,23 +286,6 @@ aac_pci_attach(device_t dev)
 	sc->aac_btag = rman_get_bustag(sc->aac_regs_resource);
 	sc->aac_bhandle = rman_get_bushandle(sc->aac_regs_resource);
 
-	/* 
-	 * Allocate and connect our interrupt.
-	 */
-	sc->aac_irq_rid = 0;
-	if ((sc->aac_irq = bus_alloc_resource(sc->aac_dev, SYS_RES_IRQ,
-			   		      &sc->aac_irq_rid, 0, ~0, 1,
-			   		      RF_SHAREABLE |
-					      RF_ACTIVE)) == NULL) {
-		device_printf(sc->aac_dev, "can't allocate interrupt\n");
-		goto out;
-	}
-	if (bus_setup_intr(sc->aac_dev, sc->aac_irq, 0,
-			   aac_intr, sc, &sc->aac_intr, NULL)) {
-		device_printf(sc->aac_dev, "can't set up interrupt\n");
-		goto out;
-	}
-
 	/* assume failure is 'out of memory' */
 	error = ENOMEM;
 
@@ -237,11 +296,11 @@ aac_pci_attach(device_t dev)
 	 */
 	if (bus_dma_tag_create(NULL, 			/* parent */
 			       PAGE_SIZE, 0,		/* algnmnt, boundary */
-			       BUS_SPACE_MAXADDR_32BIT,	/* lowaddr */
+			       BUS_SPACE_MAXADDR,	/* lowaddr */
 			       BUS_SPACE_MAXADDR, 	/* highaddr */
 			       NULL, NULL, 		/* filter, filterarg */
 			       BUS_SPACE_MAXSIZE_32BIT,	/* maxsize */
-			       AAC_MAXSGENTRIES,	/* nsegments */
+			       BUS_SPACE_UNRESTRICTED,	/* nsegments */
 			       BUS_SPACE_MAXSIZE_32BIT,	/* maxsegsize */
 			       0,			/* flags */
 			       &sc->aac_parent_dmat)) {
@@ -253,49 +312,103 @@ aac_pci_attach(device_t dev)
 	 * Detect the hardware interface version, set up the bus interface
 	 * indirection.
 	 */
-	sc->aac_hwif = AAC_HWIF_UNKNOWN;
-	for (i = 0; aac_identifiers[i].vendor != 0; i++) {
-		if ((aac_identifiers[i].vendor == pci_get_vendor(dev)) &&
-		    (aac_identifiers[i].device == pci_get_device(dev)) &&
-		    (aac_identifiers[i].subvendor == pci_get_subvendor(dev)) &&
-		    (aac_identifiers[i].subdevice == pci_get_subdevice(dev))) {
-			sc->aac_hwif = aac_identifiers[i].hwif;
-			switch(sc->aac_hwif) {
-			case AAC_HWIF_I960RX:
-				debug(2, "set hardware up for i960Rx");
-				sc->aac_if = aac_rx_interface;
-				break;
-
-			case AAC_HWIF_STRONGARM:
-				debug(2, "set hardware up for StrongARM");
-				sc->aac_if = aac_sa_interface;
-				break;
-			case AAC_HWIF_FALCON:
-				debug(2, "set hardware up for Falcon/PPC");
-				sc->aac_if = aac_fa_interface;
-				break;
-			}
-
-			/* Set up quirks */
-			sc->flags = aac_identifiers[i].quirks;
-
-			break;
-		}
-	}
-	if (sc->aac_hwif == AAC_HWIF_UNKNOWN) {
+	id = aac_find_ident(dev);
+	sc->aac_hwif = id->hwif;
+	switch(sc->aac_hwif) {
+	case AAC_HWIF_I960RX:
+		debug(2, "set hardware up for i960Rx");
+		sc->aac_if = aac_rx_interface;
+		break;
+	case AAC_HWIF_STRONGARM:
+		debug(2, "set hardware up for StrongARM");
+		sc->aac_if = aac_sa_interface;
+		break;
+	case AAC_HWIF_FALCON:
+		debug(2, "set hardware up for Falcon/PPC");
+		sc->aac_if = aac_fa_interface;
+		break;
+	case AAC_HWIF_RKT:
+		debug(2, "set hardware up for Rocket/MIPS");
+		sc->aac_if = aac_rkt_interface;
+		break;
+	default:
+		sc->aac_hwif = AAC_HWIF_UNKNOWN;
 		device_printf(sc->aac_dev, "unknown hardware type\n");
 		error = ENXIO;
 		goto out;
 	}
 
+	/* Set up quirks */
+	sc->flags = id->quirks;
 
 	/*
 	 * Do bus-independent initialisation.
 	 */
 	error = aac_attach(sc);
-	
+
 out:
 	if (error)
 		aac_free(sc);
 	return(error);
 }
+
+/*
+ * Do nothing driver that will attach to the SCSI channels of a Dell PERC
+ * controller.  This is needed to keep the power management subsystem from
+ * trying to power down these devices.
+ */
+static int aacch_probe(device_t dev);
+static int aacch_attach(device_t dev);
+static int aacch_detach(device_t dev);
+
+static device_method_t aacch_methods[] = {
+	/* Device interface */
+	DEVMETHOD(device_probe,		aacch_probe),
+	DEVMETHOD(device_attach,	aacch_attach),
+	DEVMETHOD(device_detach,	aacch_detach),
+	{ 0, 0 }
+};
+
+struct aacch_softc {
+	device_t	dev;
+};
+
+static driver_t aacch_driver = {
+	"aacch",
+	aacch_methods,
+	sizeof(struct aacch_softc)
+};
+
+static devclass_t	aacch_devclass;
+DRIVER_MODULE(aacch, pci, aacch_driver, aacch_devclass, 0, 0);
+
+static int
+aacch_probe(device_t dev)
+{
+
+	if ((pci_get_vendor(dev) != 0x9005) ||
+	    (pci_get_device(dev) != 0x00c5))
+		return (ENXIO);
+
+	device_set_desc(dev, "AAC RAID Channel");
+	return (-10);
+}
+
+static int
+aacch_attach(device_t dev)
+{
+	struct aacch_softc *sc;
+
+	sc = device_get_softc(dev);
+
+	sc->dev = dev;
+
+	return (0);
+}
+
+static int
+aacch_detach(device_t dev)
+{
+
+	return (0);
+}
diff --git a/sys/dev/raid/aac/aac_tables.h b/sys/dev/raid/aac/aac_tables.h
index c2e8ca0..42974fa 100644
--- a/sys/dev/raid/aac/aac_tables.h
+++ b/sys/dev/raid/aac/aac_tables.h
@@ -41,7 +41,7 @@ static struct aac_code_lookup aac_command_status_table[] = {
 	{"I/O error",				5},
 	{"device not configured",		6},
 	{"too big",				7},
-	{"permission denoed",			13},
+	{"permission denied",			13},
 	{"file exists",				17},
 	{"cross-device link",			18},
 	{"operation not supported by device",	19},
@@ -67,7 +67,7 @@ static struct aac_code_lookup aac_command_status_table[] = {
 	{"bad type",				10007},
 	{"jukebox",				10008},
 	{"not mounted",				10009},
-	{"in maintenace mode",			10010},
+	{"in maintenance mode",			10010},
 	{"stale ACL",				10011},
 	{NULL, 					0},
 	{"unknown command status",		0}
@@ -80,8 +80,12 @@ static struct aac_code_lookup aac_cpu_variant[] = {
 	{"i960CX",		CPUI960_CX},
 	{"i960HX",		CPUI960_HX},
 	{"i960RX",		CPUI960_RX},
+	{"i960 80303",		CPUI960_80303},
 	{"StrongARM SA110",	CPUARM_SA110},
-	{"MPC824x",		CPUMPC_824x},
+	{"PPC603e",		CPUPPC_603e},
+	{"XScale 80321",	CPU_XSCALE_80321},
+	{"MIPS 4KC",		CPU_MIPS_4KC},
+	{"MIPS 5KC",		CPU_MIPS_5KC},
 	{"Unknown StrongARM",	CPUARM_xxx},
 	{"Unknown PowerPC",	CPUPPC_xxx},
 	{NULL, 0},
@@ -113,6 +117,11 @@ static struct aac_code_lookup aac_container_types[] = {
 	{"Volume of Mirrors",	CT_VOLUME_OF_MIRRORS},
 	{"Pseudo RAID 3",	CT_PSEUDO_RAID3},
 	{"RAID 0/5",		CT_RAID50},
+	{"RAID 5D",		CT_RAID5D},
+	{"RAID 0/5D",		CT_RAID5D0},
+	{"RAID 1E",		CT_RAID1E},
+	{"RAID 6",		CT_RAID6},
+	{"RAID 0/6",		CT_RAID60},
 	{NULL, 0},
 	{"unknown",		0}
 };
diff --git a/sys/dev/raid/aac/aacreg.h b/sys/dev/raid/aac/aacreg.h
index de02783..bd5a648 100644
--- a/sys/dev/raid/aac/aacreg.h
+++ b/sys/dev/raid/aac/aacreg.h
@@ -201,12 +201,17 @@ typedef enum {
 	/* Container Commands */
 	ContainerCommand =		500,
 	ContainerCommand64 =		501,
+	RawIo = 			502,	
 
 	/* Cluster Commands */
 	ClusterCommand =		550,
 
 	/* Scsi Port commands (scsi passthrough) */
 	ScsiPortCommand =		600,
+	ScsiPortCommandU64 =		601,
+	SataPortCommandU64 =		602,
+	SasSmpPassThrough =		603,
+	SasRequestPhyInfo =		612,
 
 	/* misc house keeping and generic adapter initiated commands */
 	AifRequest =			700,
@@ -215,7 +220,21 @@ typedef enum {
 	RequestAdapterInfo =		703,
 	IsAdapterPaused =		704,
 	SendHostTime =			705,
-	LastMiscCommand =		706
+	RequestSupplementAdapterInfo =	706,	/* Supp. Info for set in UCC
+						 * use only if supported 
+						 * (RequestAdapterInfo first) */
+	LastMiscCommand =		707,
+  
+	OnLineDiagnostic =		800,      
+	FduAdapterTest =		801, 
+	RequestCompatibilityId =	802,
+	AdapterEnvironmentInfo =	803,	/* temp. sensors */
+	NvsramEventLog =		900,
+	ResetNvsramEventLogPointers =	901,
+	EnableEventLog =		902,
+	DisableEventLog =		903,
+	EncryptedKeyTransportFIB=	904,    
+	KeyableFeaturesFIB=		905     
 } AAC_FibCommands;
 
 /*
@@ -271,6 +290,7 @@ typedef enum {
 struct aac_adapter_init {
 	u_int32_t	InitStructRevision;
 #define AAC_INIT_STRUCT_REVISION		3
+#define AAC_INIT_STRUCT_REVISION_4		4
 	u_int32_t	MiniPortRevision;
 #define AAC_INIT_STRUCT_MINIPORT_REVISION	1
 	u_int32_t	FilesystemRevision;
@@ -285,6 +305,12 @@ struct aac_adapter_init {
 #define	AAC_PAGE_SIZE				4096
 	u_int32_t	HostPhysMemPages;
 	u_int32_t	HostElapsedSeconds;
+	/* ADAPTER_INIT_STRUCT_REVISION_4 begins here */
+	u_int32_t	InitFlags;			/* flags for supported features */
+#define INITFLAGS_NEW_COMM_SUPPORTED	1
+	u_int32_t	MaxIoCommands;		/* max outstanding commands */
+	u_int32_t	MaxIoSize;			/* largest I/O command */
+	u_int32_t	MaxFibSize;			/* largest FIB to adapter */
 } __attribute__ ((packed));
 
 typedef u_int32_t	aac_phys_addr_t;
@@ -311,6 +337,11 @@ typedef enum {
 	CT_VOLUME_OF_MIRRORS,       /* volume of mirror */
 	CT_PSEUDO_RAID3,            /* really raid4 */
 	CT_RAID50,		    /* stripe of raid5 */
+	CT_RAID5D,		    /* raid5 distributed hot-sparing */
+	CT_RAID5D0,
+	CT_RAID1E,		    /* extended raid1 mirroring */
+	CT_RAID6,
+	CT_RAID60,
 } AAC_FSAVolType;
 
 /*
@@ -344,6 +375,19 @@ struct aac_sg_entry {
 	u_int32_t	SgByteCount;
 } __attribute__ ((packed));
 
+struct aac_sg_entry64 {
+	u_int64_t	SgAddress;
+	u_int32_t	SgByteCount;
+} __packed;
+
+struct aac_sg_entryraw {
+	u_int32_t	Next;		/* reserved for FW use */
+	u_int32_t	Prev;		/* reserved for FW use */
+	u_int64_t	SgAddress;
+	u_int32_t	SgByteCount;
+	u_int32_t	Flags;		/* reserved for FW use */
+} __packed;
+
 struct aac_sg_table {
 	u_int32_t		SgCount;
 	struct aac_sg_entry	SgEntry[0];
@@ -353,13 +397,19 @@ struct aac_sg_table {
  * 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));
 
 /*
+ * s/g list for raw commands
+ */
+struct aac_sg_tableraw {
+	u_int32_t	SgCount;
+	struct aac_sg_entryraw	SgEntryRaw[0];
+} __packed;
+
+/*
  * Container creation data
  */
 struct aac_container_creation {
@@ -417,6 +467,8 @@ typedef enum {
 	CPU_ALPHA,
 	CPU_P7,
 	CPU_I960_RX,
+	CPU_MIPS,
+	CPU_XSCALE,
 	CPU__last
 } AAC_CpuType;  
 
@@ -427,8 +479,12 @@ typedef enum {
 	CPUI960_RX,
 	CPUARM_SA110,
 	CPUARM_xxx,
-	CPUMPC_824x,
+	CPUPPC_603e,
 	CPUPPC_xxx,
+	CPUI960_80303,
+	CPU_XSCALE_80321,
+	CPU_MIPS_4KC,
+	CPU_MIPS_5KC,
 	CPUSUBTYPE__last
 } AAC_CpuSubType;
 
@@ -453,6 +509,20 @@ typedef enum {
 	PLAT_POBLANO_XXX,
 	PLAT_JALAPENO_P2,
 	PLAT_HABANERO,
+	PLAT_VULCAN,
+	PLAT_CRUSADER,
+	PLAT_LANCER,
+	PLAT_HARRIER,
+	PLAT_TERMINATOR,
+	PLAT_SKYHAWK,
+	PLAT_CORSAIR,
+	PLAT_JAGUAR,
+	PLAT_SATAHAWK,
+	PLAT_SATANATOR,
+	PLAT_PROWLER,
+	PLAT_BLACKBIRD,
+	PLAT_SABREEXPRESS,
+	PLAT_INTRUDER,
 	PLAT__last
 } AAC_Platform;
 
@@ -462,9 +532,14 @@ typedef enum {
 	OEM_FLAVOR_HP,
 	OEM_FLAVOR_IBM,
 	OEM_FLAVOR_CPQ,
-	OEM_FLAVOR_BRAND_X,
-	OEM_FLAVOR_BRAND_Y,
+	OEM_FLAVOR_FSC,
+	OEM_FLAVOR_DWS,
 	OEM_FLAVOR_BRAND_Z,
+	OEM_FLAVOR_LEGEND,
+	OEM_FLAVOR_HITACHI,
+	OEM_FLAVOR_ESG,
+	OEM_FLAVOR_ICP,
+	OEM_FLAVOR_SCM,
 	OEM_FLAVOR__last
 } AAC_OemFlavor;
 
@@ -498,6 +573,12 @@ typedef enum
 #define AAC_SUPPORTED_SGMAP_HOST64	0x400
 #define AAC_SUPPORTED_ALARM		0x800
 #define AAC_SUPPORTED_NONDASD		0x1000
+#define AAC_SUPPORTED_SCSI_MANAGED	0x2000	
+#define AAC_SUPPORTED_RAID_SCSI_MODE	0x4000	
+#define AAC_SUPPORTED_SUPPLEMENT_ADAPTER_INFO	0x10000
+#define AAC_SUPPORTED_NEW_COMM		0x20000
+#define AAC_SUPPORTED_64BIT_ARRAYSIZE	0x40000
+#define AAC_SUPPORTED_HEAT_SENSOR	0x80000
 
 /* 
  * Structure used to respond to a RequestAdapterInfo fib.
@@ -533,10 +614,16 @@ struct aac_adapter_info {
 /*
  * Synchronous commands to the monitor/kernel.
  */
+#define AAC_MONKER_BREAKPOINT	0x04
 #define AAC_MONKER_INITSTRUCT	0x05
 #define AAC_MONKER_SYNCFIB	0x0c
 #define AAC_MONKER_GETKERNVER	0x11
+#define AAC_MONKER_POSTRESULTS	0x14
 #define AAC_MONKER_GETINFO	0x19
+#define AAC_MONKER_GETDRVPROP	0x23
+#define AAC_MONKER_RCVTEMP	0x25
+#define AAC_MONKER_GETCOMMPREF	0x26
+#define AAC_MONKER_REINIT	0xee
 
 /*
  *  Adapter Status Register
@@ -551,6 +638,7 @@ struct aac_adapter_info {
  *  state of the adapter.
  */
 #define AAC_SELF_TEST_FAILED	0x00000004
+#define AAC_MONITOR_PANIC	0x00000020
 #define AAC_UP_AND_RUNNING	0x00000080
 #define AAC_KERNEL_PANIC	0x00000100
 
@@ -656,6 +744,7 @@ typedef enum {
 	AifJobScsiExercise,		/* SCSI device Exercise operation */
 	AifJobScsiVerifyRepair,		/* SCSI device Verify operation WITH
 					 * repair */
+	AifJobScsiWritePattern,		/* write pattern */
 	AifJobScsiMax = 99,		/* Max Scsi value */
 	AifJobCtrMin,			/* Min Ctr op value */
 	AifJobCtrZero,			/* Container clear operation */
@@ -669,6 +758,12 @@ typedef enum {
 	AifJobCtrPartCopy,		/* Container Partition copy operation */
 	AifJobCtrRebuildMirror,		/* Container Rebuild Mirror operation */
 	AifJobCtrCrazyCache,		/* crazy cache */
+	AifJobCtrCopyback,		/* Container Copyback operation */
+	AifJobCtrCompactRaid5D,		/* Container Compaction operation */
+	AifJobCtrExpandRaid5D,		/* Container Expansion operation */
+	AifJobCtrRebuildRaid6,		/* Container Rebuild Raid6 operation */
+	AifJobCtrScrubRaid6,		/* Container Scrub Raid6 operation */
+	AifJobCtrSSBackup,		/* Container snapshot backup task */
 	AifJobCtrMax = 199,		/* Max Ctr type operation */
 	AifJobFsMin,			/* Min Fs type operation */
 	AifJobFsCreate,			/* File System Create operation */
@@ -851,9 +946,10 @@ struct aac_aif_command {
 	u_int32_t	seqNumber;	/* To allow ordering of
 					 * reports (if necessary) */
 	union {
-	struct aac_AifEventNotify	EN;	/* Event notify structure */
-	struct aac_AifJobProgressReport	PR[1];	/* Progress report */
-	u_int8_t			AR[AAC_AIF_REPORT_MAX_SIZE];
+		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));
 
@@ -972,6 +1068,10 @@ typedef enum _VM_COMMANDS {
 	VM_CtBlockRead64,
 	VM_CtBlockWrite64,
 	VM_CtBlockVerify64,
+	VM_CtHostRead64,
+	VM_CtHostWrite64,
+	VM_DrvErrTblLog,	/* drive error table/log type of command */
+	VM_NameServe64		 
 } AAC_VMCommand;
 
 /*
@@ -1066,8 +1166,15 @@ struct aac_vmi_businf_resp {
 	struct aac_getbusinf	BusInf;
 } __attribute__ ((packed));
 
+#if 0
 #define AAC_BTL_TO_HANDLE(b, t, l) \
     (((b & 0x3f) << 7) | ((l & 0x7) << 4) | (t & 0xf))
+#else
+#define AAC_BTL_TO_HANDLE(b, t, l) \
+    ((((u_int32_t)b & 0x0f) << 24) | \
+     (((u_int32_t)l & 0xff) << 16) | \
+     ((u_int32_t)t & 0xffff))
+#endif
 #define GetDeviceProbeInfo 0x5
 
 struct aac_vmi_devinfo_resp {
@@ -1145,6 +1252,16 @@ struct aac_blockread {
 	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;
+} __packed;
+
 struct aac_blockread_response {
 	u_int32_t		Status;
 	u_int32_t		ByteCount;
@@ -1159,12 +1276,32 @@ struct aac_blockwrite {
 	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 */
+} __packed;
+
 struct aac_blockwrite_response {
 	u_int32_t		Status;
 	u_int32_t		ByteCount;
 } __attribute__ ((packed));
 
+struct aac_raw_io {
+	u_int64_t		BlockNumber;
+	u_int32_t		ByteCount;
+	u_int16_t		ContainerId;
+	u_int16_t		Flags;				/* 0: W, 1: R */
+	u_int16_t		BpTotal;			/* reserved for FW use */
+	u_int16_t		BpComplete;			/* reserved for FW use */
+	struct aac_sg_tableraw	SgMapRaw;	/* variable size */
+} __packed;
+
 /*
  * Container shutdown command.
  */
@@ -1231,6 +1368,11 @@ struct aac_srb_response {
 	u_int8_t	sense[AAC_HOST_SENSE_DATA_MAX];
 };
 
+/*
+ * Status codes for SCSI passthrough commands.  Since they are based on ASPI,
+ * they also exactly match CAM status codes in both enumeration and meaning.
+ * They seem to also be used as status codes for synchronous FIBs.
+ */
 enum {
 	AAC_SRB_STS_PENDING			= 0x00,
 	AAC_SRB_STS_SUCCESS,
@@ -1309,11 +1451,30 @@ enum {
 #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_IQUE		0x40	/* inbound queue */
+#define AAC_RX_OQUE		0x44	/* outbound queue */
 
 #define AAC_RX_MAILBOX		0x50	/* mailbox (20 bytes) */
 #define AAC_RX_FWSTATUS		0x6c
 
 /*
+ * Register definitions for the Adaptec 'Rocket' RAID-On-Chip adapters.
+ * Unsurprisingly, it's quite similar to the i960!
+ */
+
+#define AAC_RKT_IDBR		0x20	/* inbound doorbell register */
+#define AAC_RKT_IISR		0x24	/* inbound interrupt status register */
+#define AAC_RKT_IIMR		0x28	/* inbound interrupt mask register */
+#define AAC_RKT_ODBR		0x2c	/* outbound doorbell register */
+#define AAC_RKT_OISR		0x30	/* outbound interrupt status register */
+#define AAC_RKT_OIMR		0x34	/* outbound interrupt mask register */
+#define AAC_RKT_IQUE		0x40	/* inbound queue */
+#define AAC_RKT_OQUE		0x44	/* outbound queue */
+
+#define AAC_RKT_MAILBOX		0x1000	/* mailbox */
+#define AAC_RKT_FWSTATUS	0x101c	/* Firmware Status (mailbox 7) */
+
+/*
  * Common bit definitions for the doorbell registers.
  */
 
@@ -1343,3 +1504,5 @@ enum {
 #define AAC_DB_INTERRUPTS	(AAC_DB_COMMAND_READY  |	\
 				 AAC_DB_RESPONSE_READY |	\
 				 AAC_DB_PRINTF)
+#define AAC_DB_INT_NEW_COMM		0x08		
+
diff --git a/sys/dev/raid/aac/aacvar.h b/sys/dev/raid/aac/aacvar.h
index 3d3cb7b..b15a50c 100644
--- a/sys/dev/raid/aac/aacvar.h
+++ b/sys/dev/raid/aac/aacvar.h
@@ -30,6 +30,12 @@
  *	$DragonFly: src/sys/dev/raid/aac/aacvar.h,v 1.19 2007/11/10 19:50:29 swildner Exp $
  */
 
+#include <sys/buf.h>
+#include <sys/buf2.h>
+#include <sys/eventhandler.h>
+#include <sys/lock.h>
+#include <sys/selinfo.h>
+#include <sys/taskqueue.h>
 #include <sys/thread2.h>
 
 /*
@@ -48,13 +54,11 @@
 #define AAC_ADAPTER_FIBS	8
 
 /*
- * FIBs are allocated up-front, and the pool isn't grown.  We should allocate
- * enough here to let us keep the adapter busy without wasting large amounts
- * of kernel memory.  The current interface implementation limits us to 512
- * FIBs queued for the adapter at any one time.
+ * FIBs are allocated in page-size chunks and can grow up to the 512
+ * limit imposed by the hardware.
  */
-#define AAC_FIB_COUNT		128
-
+#define AAC_PREALLOCATE_FIBS	128
+#define AAC_NUM_MGT_FIB		8
 /*
  * 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.
@@ -94,14 +98,6 @@
 #define AAC_DISK_MAJOR	200
 
 /*
- * Driver Variable Definitions
- */
-
-#if defined(__FreeBSD__) && __FreeBSD_version >= 500005
-# include <sys/taskqueue.h>
-#endif
-
-/*
  * Per-container data structure
  */
 struct aac_container
@@ -113,6 +109,19 @@ struct aac_container
 };
 
 /*
+ * Per-SIM data structure
+ */
+struct aac_sim
+{
+	device_t		sim_dev;
+	int			TargetsPerBus;
+	int			BusNumber;
+	int			InitiatorBusId;
+	struct aac_softc	*aac_sc;
+	TAILQ_ENTRY(aac_sim)	sim_link;
+};
+
+/*
  * Per-disk structure
  */
 struct aac_disk 
@@ -143,7 +152,7 @@ struct aac_command
 
 	struct aac_fib		*cm_fib;	/* FIB associated with this
 						 * command */
-	u_int32_t		cm_fibphys;	/* bus address of the FIB */
+	u_int64_t		cm_fibphys;	/* bus address of the FIB */
 	struct buf		*cm_data;	/* pointer to data in kernel
 						 * space */
 	u_int32_t		cm_datalen;	/* data length */
@@ -163,12 +172,24 @@ struct aac_command
 #define AAC_ON_AACQ_READY	(1<<6)
 #define AAC_ON_AACQ_BUSY	(1<<7)
 #define AAC_ON_AACQ_COMPLETE	(1<<8)
-#define AAC_ON_AACQ_MASK	((1<<5)|(1<<6)|(1<<7)|(1<<8))
+#define AAC_ON_AACQ_NORM	(1<<10)
+#define AAC_ON_AACQ_AIF		(1<<11)
+#define AAC_ON_AACQ_MASK	((1<<5)|(1<<6)|(1<<7)|(1<<8)|(1<<10)|(1<11))
+#define AAC_QUEUE_FRZN		(1<<9)		/* Freeze the processing of
+						 * commands on the queue. */
 
 	void			(* cm_complete)(struct aac_command *cm);
 	void			*cm_private;
 	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;
+	struct aac_command	*aac_commands;
 };
 
 /*
@@ -216,10 +237,14 @@ struct aac_interface
 				   u_int32_t arg2, u_int32_t arg3);
 	int	(*aif_get_mailbox)(struct aac_softc *sc, int mb);
 	void	(*aif_set_interrupts)(struct aac_softc *sc, int enable);
+	int	(*aif_send_command)(struct aac_softc *sc, struct aac_command *cm);
+	int	(*aif_get_outb_queue)(struct aac_softc *sc);
+	void	(*aif_set_outb_queue)(struct aac_softc *sc, int index);
 };
 extern struct aac_interface	aac_rx_interface;
 extern struct aac_interface	aac_sa_interface;
 extern struct aac_interface	aac_fa_interface;
+extern struct aac_interface	aac_rkt_interface;
 
 #define AAC_GET_FWSTATUS(sc)		((sc)->aac_if.aif_get_fwstatus((sc)))
 #define AAC_QNOTIFY(sc, qbit)		((sc)->aac_if.aif_qnotify((sc), (qbit)))
@@ -235,6 +260,9 @@ extern struct aac_interface	aac_fa_interface;
 					0))
 #define AAC_UNMASK_INTERRUPTS(sc)	((sc)->aac_if.aif_set_interrupts((sc), \
 					1))
+#define AAC_SEND_COMMAND(sc, cm)	((sc)->aac_if.aif_send_command((sc), (cm)))
+#define AAC_GET_OUTB_QUEUE(sc)		((sc)->aac_if.aif_get_outb_queue((sc)))
+#define AAC_SET_OUTB_QUEUE(sc, idx)	((sc)->aac_if.aif_set_outb_queue((sc), (idx)))
 
 #define AAC_SETREG4(sc, reg, val)	bus_space_write_4(sc->aac_btag, \
 					sc->aac_bhandle, reg, val)
@@ -249,24 +277,11 @@ extern struct aac_interface	aac_fa_interface;
 #define AAC_GETREG1(sc, reg)		bus_space_read_1 (sc->aac_btag, \
 					sc->aac_bhandle, reg)
 
-TAILQ_HEAD(aac_container_tq, aac_container);
-
 /* Define the OS version specific locks */
-#if defined(__FreeBSD__) && __FreeBSD_version >= 500005
-#include <sys/lock.h>
-#include <sys/mutex.h>
-typedef struct mtx aac_lock_t;
-#define AAC_LOCK_INIT(l, s)	mtx_init(l, s, MTX_DEF)
-#define AAC_LOCK_ACQUIRE(l)	mtx_lock(l)
-#define AAC_LOCK_RELEASE(l)	mtx_unlock(l)
-#else
 typedef struct lock aac_lock_t;
-#define AAC_LOCK_INIT(l, s)	lockinit(l, "aac", 0, 0)
-#define AAC_LOCK_ACQUIRE(l)	lockmgr(l, LK_EXCLUSIVE|LK_RETRY)
+#define AAC_LOCK_INIT(l, s)	lockinit(l, s, 0, LK_EXCLUSIVE|LK_CANRECURSE)
+#define AAC_LOCK_ACQUIRE(l)	lockmgr(l, LK_EXCLUSIVE)
 #define AAC_LOCK_RELEASE(l)	lockmgr(l, LK_RELEASE)
-#endif
-
-#include <sys/selinfo.h>
 
 /*
  * Per-controller structure.
@@ -287,6 +302,7 @@ struct aac_softc
 	struct resource		*aac_irq;		/* interrupt */
 	int			aac_irq_rid;
 	void			*aac_intr;		/* interrupt handle */
+	eventhandler_tag	eh;
 
 	/* controller features, limits and status */
 	int			aac_state;
@@ -300,7 +316,8 @@ struct aac_softc
 	int			aac_hwif;
 #define AAC_HWIF_I960RX		0
 #define AAC_HWIF_STRONGARM	1
-#define	AAC_HWIF_FALCON		2
+#define AAC_HWIF_FALCON		2
+#define AAC_HWIF_RKT		3
 #define AAC_HWIF_UNKNOWN	-1
 	bus_dma_tag_t		aac_common_dmat;	/* common structure
 							 * DMA tag */
@@ -312,10 +329,9 @@ struct aac_softc
 
 	/* command/fib resources */
 	bus_dma_tag_t		aac_fib_dmat;	/* DMA tag for allocing FIBs */
-	struct aac_fib		*aac_fibs;
-	bus_dmamap_t		aac_fibmap;
-	u_int32_t		aac_fibphys;
-	struct aac_command	aac_command[AAC_FIB_COUNT];
+	TAILQ_HEAD(,aac_fibmap)	aac_fibmap_tqh;
+	u_int			total_fibs;
+	struct aac_command	*aac_commands;
 
 	/* command management */
 	TAILQ_HEAD(,aac_command) aac_free;	/* command structures 
@@ -325,6 +341,11 @@ struct aac_softc
 	TAILQ_HEAD(,aac_command) aac_busy;
 	TAILQ_HEAD(,aac_command) aac_complete;	/* commands which have been
 						 * returned by the controller */
+	TAILQ_HEAD(,aac_command) aac_aif;
+#if 0
+	TAILQ_HEAD(,aac_command) aac_norm;
+#endif
+	TAILQ_HEAD(,aac_event)  aac_ev_cmfree;
 	struct bio_queue_head	aac_bioq;
 	struct aac_queue_table	*aac_queues;
 	struct aac_queue_entry	*aac_qentries[AAC_QUEUE_COUNT];
@@ -332,18 +353,18 @@ struct aac_softc
 	struct aac_qstat	aac_qstat[AACQ_COUNT];	/* queue statistics */
 
 	/* connected containters */
-	struct aac_container_tq	aac_container_tqh;
+	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;
+	/*
+	 * The general I/O lock.  This protects the sync fib, the lists, the
+	 * queues, and the registers.
+	 */
+	aac_lock_t		aac_io_lock;
 
 	/* delayed activity infrastructure */
-#if defined(__FreeBSD__) && __FreeBSD_version >= 500005
 	struct task		aac_task_complete;	/* deferred-completion
 							 * task */
-#endif
 	struct intr_config_hook	aac_ich;
 
 	/* management interface */
@@ -356,23 +377,61 @@ struct aac_softc
 	struct thread		*aifthread;
 	int			aifflags;
 #define AAC_AIFFLAGS_RUNNING	(1 << 0)
-#define AAC_AIFFLAGS_PENDING	(1 << 1)
+#define AAC_AIFFLAGS_AIF	(1 << 1)
 #define	AAC_AIFFLAGS_EXIT	(1 << 2)
 #define AAC_AIFFLAGS_EXITED	(1 << 3)
+#define AAC_AIFFLAGS_PRINTF	(1 << 4)
+#define	AAC_AIFFLAGS_ALLOCFIBS	(1 << 5)
+#define AAC_AIFFLAGS_PENDING	(AAC_AIFFLAGS_AIF | AAC_AIFFLAGS_PRINTF | \
+				 AAC_AIFFLAGS_ALLOCFIBS)
 	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 */
+#define AAC_FLAGS_SLAVE		(1 << 9)
+#define AAC_FLAGS_MASTER	(1 << 10)
+#define AAC_FLAGS_NEW_COMM	(1 << 11)	/* New comm. interface supported */
+#define AAC_FLAGS_RAW_IO	(1 << 12)	/* Raw I/O interface */
+#define AAC_FLAGS_ARRAY_64BIT	(1 << 13)	/* 64-bit array size */
   
 	u_int32_t		supported_options;
 	u_int32_t		scsi_method_id;
+	TAILQ_HEAD(,aac_sim)	aac_sim_tqh;
+
+	u_int32_t	aac_max_fibs;		/* max. FIB count */
+	u_int32_t	aac_max_fibs_alloc;	/* max. alloc. per alloc_commands() */
+	u_int32_t	aac_max_fib_size;	/* max. FIB size */
+	u_int32_t	aac_sg_tablesize;	/* max. sg count from host */
+	u_int32_t	aac_max_sectors;	/* max. I/O size from host (blocks) */
+};
+
+/*
+ * Event callback mechanism for the driver
+ */
+#define AAC_EVENT_NONE		0x00
+#define AAC_EVENT_CMFREE	0x01
+#define AAC_EVENT_MASK		0xff
+#define AAC_EVENT_REPEAT	0x100
+
+typedef void aac_event_cb_t(struct aac_softc *sc, struct aac_event *event,
+    void *arg);
+struct aac_event {
+	TAILQ_ENTRY(aac_event)	ev_links;
+	int			ev_type;
+	aac_event_cb_t		*ev_callback;
+	void			*ev_arg;
 };
 
+#ifndef AAC_DRIVER_BUILD
+# define AAC_DRIVER_BUILD 1
+#endif
 
 /*
  * Public functions
@@ -382,7 +441,8 @@ extern int		aac_attach(struct aac_softc *sc);
 extern int		aac_detach(device_t dev);
 extern int		aac_suspend(device_t dev); 
 extern int		aac_resume(device_t dev);
-extern void		aac_intr(void *arg);
+extern void		aac_new_intr(void *arg);
+extern void		aac_fast_intr(void *arg);
 extern devclass_t	aac_devclass;
 extern void		aac_submit_bio(struct aac_disk *ad, struct bio *bio);
 extern void		aac_biodone(struct bio *bio, const char *code);
@@ -393,12 +453,11 @@ extern void		aac_startio(struct aac_softc *sc);
 extern int		aac_alloc_command(struct aac_softc *sc,
 					  struct aac_command **cmp);
 extern void		aac_release_command(struct aac_command *cm);
-extern int		aac_alloc_sync_fib(struct aac_softc *sc,
-					 struct aac_fib **fib, int flags);
-extern void		aac_release_sync_fib(struct aac_softc *sc);
 extern int		aac_sync_fib(struct aac_softc *sc, u_int32_t command,
 				     u_int32_t xferstate, struct aac_fib *fib,
 				     u_int16_t datasize);
+extern void		aac_add_event(struct aac_softc *sc, struct aac_event
+				      *event);
 
 /*
  * Debugging levels:
@@ -468,7 +527,6 @@ aac_initq_ ## name (struct aac_softc *sc)				\
 static __inline void							\
 aac_enqueue_ ## name (struct aac_command *cm)				\
 {									\
-	crit_enter();							\
 	if ((cm->cm_flags & AAC_ON_AACQ_MASK) != 0) {			\
 		kprintf("command %p is on another queue, flags = %#x\n",	\
 		       cm, cm->cm_flags);				\
@@ -477,12 +535,10 @@ aac_enqueue_ ## name (struct aac_command *cm)				\
 	TAILQ_INSERT_TAIL(&cm->cm_sc->aac_ ## name, cm, cm_link);	\
 	cm->cm_flags |= AAC_ON_ ## index;				\
 	AACQ_ADD(cm->cm_sc, index);					\
-	crit_exit();							\
 }									\
 static __inline void							\
 aac_requeue_ ## name (struct aac_command *cm)				\
 {									\
-	crit_enter();							\
 	if ((cm->cm_flags & AAC_ON_AACQ_MASK) != 0) {			\
 		kprintf("command %p is on another queue, flags = %#x\n",	\
 		       cm, cm->cm_flags);				\
@@ -491,14 +547,12 @@ aac_requeue_ ## name (struct aac_command *cm)				\
 	TAILQ_INSERT_HEAD(&cm->cm_sc->aac_ ## name, cm, cm_link);	\
 	cm->cm_flags |= AAC_ON_ ## index;				\
 	AACQ_ADD(cm->cm_sc, index);					\
-	crit_exit();							\
 }									\
 static __inline struct aac_command *					\
 aac_dequeue_ ## name (struct aac_softc *sc)				\
 {									\
 	struct aac_command *cm;						\
 									\
-	crit_enter();							\
 	if ((cm = TAILQ_FIRST(&sc->aac_ ## name)) != NULL) {		\
 		if ((cm->cm_flags & AAC_ON_ ## index) == 0) {		\
 			kprintf("command %p not in queue, flags = %#x, "	\
@@ -510,13 +564,11 @@ aac_dequeue_ ## name (struct aac_softc *sc)				\
 		cm->cm_flags &= ~AAC_ON_ ## index;			\
 		AACQ_REMOVE(sc, index);					\
 	}								\
-	crit_exit();							\
 	return(cm);							\
 }									\
 static __inline void							\
 aac_remove_ ## name (struct aac_command *cm)				\
 {									\
-	crit_enter();							\
 	if ((cm->cm_flags & AAC_ON_ ## index) == 0) {			\
 		kprintf("command %p not in queue, flags = %#x, "		\
 		       "bit = %#x\n", cm, cm->cm_flags, 		\
@@ -526,7 +578,6 @@ aac_remove_ ## name (struct aac_command *cm)				\
 	TAILQ_REMOVE(&cm->cm_sc->aac_ ## name, cm, cm_link);		\
 	cm->cm_flags &= ~AAC_ON_ ## index;				\
 	AACQ_REMOVE(cm->cm_sc, index);					\
-	crit_exit();							\
 }									\
 struct hack
 
@@ -548,10 +599,8 @@ aac_initq_bio(struct aac_softc *sc)
 static __inline void
 aac_enqueue_bio(struct aac_softc *sc, struct bio *bio)
 {
-	crit_enter();
 	bioq_insert_tail(&sc->aac_bioq, bio);
 	AACQ_ADD(sc, AACQ_BIO);
-	crit_exit();
 }
 
 static __inline struct bio *
@@ -559,12 +608,10 @@ aac_dequeue_bio(struct aac_softc *sc)
 {
 	struct bio *bio;
 
-	crit_enter();
 	if ((bio = bioq_first(&sc->aac_bioq)) != NULL) {
 		bioq_remove(&sc->aac_bioq, bio);
 		AACQ_REMOVE(sc, AACQ_BIO);
 	}
-	crit_exit();
 	return(bio);
 }
 
@@ -577,5 +624,23 @@ aac_print_printf(struct aac_softc *sc)
 	 */
 	device_printf(sc->aac_dev, "**Monitor** %.*s", AAC_PRINTF_BUFSIZE,
 		      sc->aac_common->ac_printf);
+	sc->aac_common->ac_printf[0] = 0;
 	AAC_QNOTIFY(sc, AAC_DB_PRINTF);
 }
+
+static __inline int
+aac_alloc_sync_fib(struct aac_softc *sc, struct aac_fib **fib)
+{
+
+	KKASSERT(lockstatus(&sc->aac_io_lock, curthread) != 0);
+	*fib = &sc->aac_common->ac_sync_fib;
+	return (0);
+}
+
+static __inline void
+aac_release_sync_fib(struct aac_softc *sc)
+{
+
+	KKASSERT(lockstatus(&sc->aac_io_lock, curthread) != 0);
+}
+
Attachment:
pgp00001.pgp
-------------- next part --------------
A non-text attachment was scrubbed...
Name: pgp00001.pgp
Type: application/octet-stream
Size: 189 bytes
Desc: "Description: PGP signature"
URL: <http://lists.dragonflybsd.org/pipermail/submit/attachments/20080113/c4fc692f/attachment-0018.obj>


More information about the Submit mailing list