diff --git a/sys/dev/raid/ciss/ciss.c b/sys/dev/raid/ciss/ciss.c
index e42b0fe..c3c8c44 100644
--- a/sys/dev/raid/ciss/ciss.c
+++ b/sys/dev/raid/ciss/ciss.c
@@ -24,8 +24,6 @@
  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  * SUCH DAMAGE.
  *
- *	$FreeBSD: src/sys/dev/ciss/ciss.c,v 1.2.2.25 2008/06/10 18:51:05 ps Exp $
- *	$DragonFly: src/sys/dev/raid/ciss/ciss.c,v 1.28 2008/05/18 20:30:23 pavalos Exp $
  */
 
 /*
@@ -87,6 +85,8 @@
 #include <sys/kthread.h>
 #include <sys/queue.h>
 #include <sys/rman.h>
+#include <sys/sysctl.h>
+#include <sys/lock.h>
 
 #include <bus/cam/cam.h>
 #include <bus/cam/cam_ccb.h>
@@ -103,8 +103,8 @@
 #include <bus/pci/pcivar.h>
 
 #include "cissreg.h"
-#include "cissvar.h"
 #include "cissio.h"
+#include "cissvar.h"
 
 MALLOC_DEFINE(CISS_MALLOC_CLASS, "ciss_data", "ciss internal data buffers");
 
@@ -117,6 +117,8 @@ static int	ciss_shutdown(device_t dev);
 
 /* (de)initialisation functions, control wrappers */
 static int	ciss_init_pci(struct ciss_softc *sc);
+static int	ciss_setup_msix(struct ciss_softc *sc);
+static int	ciss_init_perf(struct ciss_softc *sc);
 static int	ciss_wait_adapter(struct ciss_softc *sc);
 static int	ciss_flush_adapter(struct ciss_softc *sc);
 static int	ciss_init_requests(struct ciss_softc *sc);
@@ -130,17 +132,21 @@ static int	ciss_identify_logical(struct ciss_softc *sc, struct ciss_ldrive *ld);
 static int	ciss_get_ldrive_status(struct ciss_softc *sc,  struct ciss_ldrive *ld);
 static int	ciss_update_config(struct ciss_softc *sc);
 static int	ciss_accept_media(struct ciss_softc *sc, struct ciss_ldrive *ld);
+static void	ciss_init_sysctl(struct ciss_softc *sc);
+static void	ciss_soft_reset(struct ciss_softc *sc);
 static void	ciss_free(struct ciss_softc *sc);
 static void	ciss_spawn_notify_thread(struct ciss_softc *sc);
 static void	ciss_kill_notify_thread(struct ciss_softc *sc);
 
 /* request submission/completion */
 static int	ciss_start(struct ciss_request *cr);
-static void	ciss_done(struct ciss_softc *sc);
+static void	ciss_done(struct ciss_softc *sc, cr_qhead_t *qh);
+static void	ciss_perf_done(struct ciss_softc *sc, cr_qhead_t *qh);
 static void	ciss_intr(void *arg);
-static void	ciss_complete(struct ciss_softc *sc);
-static int	ciss_report_request(struct ciss_request *cr, int *command_status,
-				    int *scsi_status);
+static void	ciss_perf_intr(void *arg);
+static void	ciss_perf_msi_intr(void *arg);
+static void	ciss_complete(struct ciss_softc *sc, cr_qhead_t *qh);
+static int	_ciss_report_request(struct ciss_request *cr, int *command_status, int *scsi_status, const char *func);
 static int	ciss_synch_request(struct ciss_request *cr, int timeout);
 static int	ciss_poll_request(struct ciss_request *cr, int timeout);
 static int	ciss_wait_request(struct ciss_request *cr, int timeout);
@@ -182,6 +188,8 @@ static int	ciss_name_device(struct ciss_softc *sc, int bus, int target);
 
 /* periodic status monitoring */
 static void	ciss_periodic(void *arg);
+static void	ciss_nop_complete(struct ciss_request *cr);
+static void	ciss_disable_adapter(struct ciss_softc *sc);
 static void	ciss_notify_event(struct ciss_softc *sc);
 static void	ciss_notify_complete(struct ciss_request *cr);
 static int	ciss_notify_abort(struct ciss_softc *sc);
@@ -217,9 +225,9 @@ static driver_t ciss_pci_driver = {
 };
 
 static devclass_t	ciss_devclass;
-
-DECLARE_DUMMY_MODULE(ciss);
 DRIVER_MODULE(ciss, pci, ciss_pci_driver, ciss_devclass, 0, 0);
+MODULE_DEPEND(ciss, cam, 1, 1, 1);
+MODULE_DEPEND(ciss, pci, 1, 1, 1);
 
 /*
  * Control device interface.
@@ -232,9 +240,9 @@ static d_ioctl_t	ciss_ioctl;
 
 static struct dev_ops ciss_ops = {
     { "ciss", CISS_CDEV_MAJOR, 0 },
-    .d_open =		ciss_open,
-    .d_close =		ciss_close,
-    .d_ioctl =		ciss_ioctl
+    .d_open =          ciss_open,
+    .d_close =         ciss_close,
+    .d_ioctl =         ciss_ioctl
 };
 
 /*
@@ -244,6 +252,27 @@ static struct dev_ops ciss_ops = {
 static unsigned int ciss_expose_hidden_physical = 0;
 TUNABLE_INT("hw.ciss.expose_hidden_physical", &ciss_expose_hidden_physical);
 
+static unsigned int ciss_nop_message_heartbeat = 0;
+TUNABLE_INT("hw.ciss.nop_message_heartbeat", &ciss_nop_message_heartbeat);
+
+/*
+ * This tunable can force a particular transport to be used:
+ * <= 0 : use default
+ *    1 : force simple
+ *    2 : force performant
+ */
+static int ciss_force_transport = 0;
+TUNABLE_INT("hw.ciss.force_transport", &ciss_force_transport);
+
+/*
+ * This tunable can force a particular interrupt delivery method to be used:
+ * <= 0 : use default
+ *    1 : force INTx
+ *    2 : force MSIX
+ */
+static int ciss_force_interrupt = 0;
+TUNABLE_INT("hw.ciss.force_interrupt", &ciss_force_interrupt);
+
 /************************************************************************
  * CISS adapters amazingly don't have a defined programming interface
  * value.  (One could say some very despairing things about PCI and
@@ -286,17 +315,20 @@ static struct
     { 0x103C, 0x3234, CISS_BOARD_SA5,	"HP Smart Array P400" },
     { 0x103C, 0x3235, CISS_BOARD_SA5,	"HP Smart Array P400i" },
     { 0x103C, 0x3236, CISS_BOARD_SA5,	"HP Smart Array" },
-    { 0x103C, 0x3237, CISS_BOARD_SA5,	"HP Smart Array" },
+    { 0x103C, 0x3237, CISS_BOARD_SA5,	"HP Smart Array E500" },
     { 0x103C, 0x3238, CISS_BOARD_SA5,	"HP Smart Array" },
     { 0x103C, 0x3239, CISS_BOARD_SA5,	"HP Smart Array" },
     { 0x103C, 0x323A, CISS_BOARD_SA5,	"HP Smart Array" },
     { 0x103C, 0x323B, CISS_BOARD_SA5,	"HP Smart Array" },
     { 0x103C, 0x323C, CISS_BOARD_SA5,	"HP Smart Array" },
+    { 0x103C, 0x323D, CISS_BOARD_SA5,	"HP Smart Array P700m" },
     { 0x103C, 0x3241, CISS_BOARD_SA5,	"HP Smart Array P212" },
     { 0x103C, 0x3243, CISS_BOARD_SA5,	"HP Smart Array P410" },
     { 0x103C, 0x3245, CISS_BOARD_SA5,	"HP Smart Array P410i" },
     { 0x103C, 0x3247, CISS_BOARD_SA5,	"HP Smart Array P411" },
     { 0x103C, 0x3249, CISS_BOARD_SA5,	"HP Smart Array P812" },
+    { 0x103C, 0x324A, CISS_BOARD_SA5,	"HP Smart Array P712m" },
+    { 0x103C, 0x324B, CISS_BOARD_SA5,	"HP Smart Array" },
     { 0, 0, 0, NULL }
 };
 
@@ -327,7 +359,7 @@ ciss_probe(device_t dev)
     i = ciss_lookup(dev);
     if (i != -1) {
 	device_set_desc(dev, ciss_vendor_data[i].desc);
-	return(-10);
+	return(BUS_PROBE_DEFAULT);
     }
     return(ENOENT);
 }
@@ -339,7 +371,7 @@ static int
 ciss_attach(device_t dev)
 {
     struct ciss_softc	*sc;
-    int			i, error;
+    int			error;
 
     debug_called(1);
 
@@ -385,22 +417,6 @@ ciss_attach(device_t dev)
 
     sc = device_get_softc(dev);
     sc->ciss_dev = dev;
-    callout_init(&sc->ciss_periodic);
-
-    /*
-     * Work out adapter type.
-     */
-    i = ciss_lookup(dev);
-    if (ciss_vendor_data[i].flags & CISS_BOARD_SA5) {
-	sc->ciss_interrupt_mask = CISS_TL_SIMPLE_INTR_OPQ_SA5;
-    } else if (ciss_vendor_data[i].flags & CISS_BOARD_SA5B) {
-	sc->ciss_interrupt_mask = CISS_TL_SIMPLE_INTR_OPQ_SA5B;
-    } else {
-	/* really an error on our part */
-	ciss_printf(sc, "unable to determine hardware type\n");
-	error = ENXIO;
-	goto out;
-    }
 
     /*
      * Do PCI-specific init.
@@ -412,9 +428,14 @@ ciss_attach(device_t dev)
      * Initialise driver queues.
      */
     ciss_initq_free(sc);
-    ciss_initq_busy(sc);
-    ciss_initq_complete(sc);
     ciss_initq_notify(sc);
+    lockinit(&sc->ciss_lock, "cisslock", 0, LK_CANRECURSE);
+    callout_init(&sc->ciss_periodic);
+
+    /*
+     * Initalize device sysctls.
+     */
+    ciss_init_sysctl(sc);
 
     /*
      * Initialise command/request pool.
@@ -456,7 +477,7 @@ ciss_attach(device_t dev)
      */
     ciss_periodic(sc);
 
-    /*
+   /*
      * Create the control device.
      */
     sc->ciss_dev_t = make_dev(&ciss_ops, device_get_unit(sc->ciss_dev),
@@ -489,13 +510,16 @@ ciss_detach(device_t dev)
 
     debug_called(1);
 
-    if (sc->ciss_flags & CISS_FLAG_CONTROL_OPEN)
+    lockmgr(&sc->ciss_lock, LK_EXCLUSIVE);
+    if (sc->ciss_flags & CISS_FLAG_CONTROL_OPEN) {
+	lockmgr(&sc->ciss_lock, LK_RELEASE);
 	return (EBUSY);
+    }
 
     /* flush adapter cache */
     ciss_flush_adapter(sc);
 
-    /* release all resources */
+    /* release all resources.  The lock is released and freed here too. */
     ciss_free(sc);
 
     return(0);
@@ -511,12 +535,32 @@ ciss_shutdown(device_t dev)
 
     debug_called(1);
 
+    lockmgr(&sc->ciss_lock, LK_EXCLUSIVE);
     /* flush adapter cache */
     ciss_flush_adapter(sc);
 
+    if (sc->ciss_soft_reset)
+	ciss_soft_reset(sc);
+    lockmgr(&sc->ciss_lock, LK_RELEASE);
+
     return(0);
 }
 
+static void
+ciss_init_sysctl(struct ciss_softc *sc)
+{
+    sysctl_ctx_init(&sc->sysctl_ctx);
+    sc->sysctl_tree = SYSCTL_ADD_NODE(&sc->sysctl_ctx,
+			SYSCTL_STATIC_CHILDREN(_hw), OID_AUTO,
+			device_get_nameunit(sc->ciss_dev), CTLFLAG_RD, 0, "");
+    if (sc->sysctl_tree == NULL) {
+	device_printf(sc->ciss_dev, "can't add sysctl node\n");
+    } else {
+	SYSCTL_ADD_INT(&sc->sysctl_ctx, SYSCTL_CHILDREN(sc->sysctl_tree),
+	    OID_AUTO, "soft_reset", CTLFLAG_RW, &sc->ciss_soft_reset, 0, "");
+    }
+}
+
 /************************************************************************
  * Perform PCI-specific attachment actions.
  */
@@ -524,19 +568,43 @@ static int
 ciss_init_pci(struct ciss_softc *sc)
 {
     uintptr_t		cbase, csize, cofs;
-    int			error;
+    uint32_t		method, supported_methods;
+    int			error, sqmask, i;
+    void		*intr;
 
     debug_called(1);
 
     /*
+     * Work out adapter type.
+     */
+    i = ciss_lookup(sc->ciss_dev);
+    if (i < 0) {
+	ciss_printf(sc, "unknown adapter type\n");
+	return (ENXIO);
+    }
+
+    if (ciss_vendor_data[i].flags & CISS_BOARD_SA5) {
+	sqmask = CISS_TL_SIMPLE_INTR_OPQ_SA5;
+    } else if (ciss_vendor_data[i].flags & CISS_BOARD_SA5B) {
+	sqmask = CISS_TL_SIMPLE_INTR_OPQ_SA5B;
+    } else {
+	/*
+	 * XXX Big hammer, masks/unmasks all possible interrupts.  This should
+	 * work on all hardware variants.  Need to add code to handle the
+	 * "controller crashed" interupt bit that this unmasks.
+	 */
+	sqmask = ~0;
+    }
+
+    /*
      * Allocate register window first (we need this to find the config
      * struct).
      */
     error = ENXIO;
     sc->ciss_regs_rid = CISS_TL_SIMPLE_BAR_REGS;
     if ((sc->ciss_regs_resource =
-	 bus_alloc_resource(sc->ciss_dev, SYS_RES_MEMORY, &sc->ciss_regs_rid,
-			    0, ~0, 1, RF_ACTIVE)) == NULL) {
+	 bus_alloc_resource_any(sc->ciss_dev, SYS_RES_MEMORY,
+				&sc->ciss_regs_rid, RF_ACTIVE)) == NULL) {
 	ciss_printf(sc, "can't allocate register window\n");
 	return(ENXIO);
     }
@@ -550,8 +618,8 @@ ciss_init_pci(struct ciss_softc *sc)
     sc->ciss_cfg_rid = CISS_TL_SIMPLE_READ(sc, CISS_TL_SIMPLE_CFG_BAR) & 0xffff;
     if (sc->ciss_cfg_rid != sc->ciss_regs_rid) {
 	if ((sc->ciss_cfg_resource =
-	     bus_alloc_resource(sc->ciss_dev, SYS_RES_MEMORY, &sc->ciss_cfg_rid,
-				0, ~0, 1, RF_ACTIVE)) == NULL) {
+	     bus_alloc_resource_any(sc->ciss_dev, SYS_RES_MEMORY,
+				    &sc->ciss_cfg_rid, RF_ACTIVE)) == NULL) {
 	    ciss_printf(sc, "can't allocate config window\n");
 	    return(ENXIO);
 	}
@@ -577,6 +645,12 @@ ciss_init_pci(struct ciss_softc *sc)
     debug(1, "config struct at %p", sc->ciss_cfg);
 
     /*
+     * Calculate the number of request structures/commands we are
+     * going to provide for this adapter.
+     */
+    sc->ciss_max_requests = min(CISS_MAX_REQUESTS, sc->ciss_cfg->max_outstanding_commands);
+
+    /*
      * Validate the config structure.  If we supported other transport
      * methods, we could select amongst them at this point in time.
      */
@@ -588,14 +662,49 @@ ciss_init_pci(struct ciss_softc *sc)
     }
 
     /*
-     * Put the board into simple mode, and tell it we're using the low
-     * 4GB of RAM.  Set the default interrupt coalescing options.
+     * Select the mode of operation, prefer Performant.
      */
-    if (!(sc->ciss_cfg->supported_methods & CISS_TRANSPORT_METHOD_SIMPLE)) {
-	ciss_printf(sc, "adapter does not support 'simple' transport layer\n");
+    if (!(sc->ciss_cfg->supported_methods &
+	(CISS_TRANSPORT_METHOD_SIMPLE | CISS_TRANSPORT_METHOD_PERF))) {
+	ciss_printf(sc, "No supported transport layers: 0x%x\n",
+	    sc->ciss_cfg->supported_methods);
+	return(ENXIO);
+    }
+
+    switch (ciss_force_transport) {
+    case 1:
+	supported_methods = CISS_TRANSPORT_METHOD_SIMPLE;
+	break;
+    case 2:
+	supported_methods = CISS_TRANSPORT_METHOD_PERF;
+	break;
+    default:
+	supported_methods = sc->ciss_cfg->supported_methods;
+	break;
+    }
+
+setup:
+    if (supported_methods & CISS_TRANSPORT_METHOD_PERF) {
+	method = CISS_TRANSPORT_METHOD_PERF;
+	sc->ciss_perf = (struct ciss_perf_config *)(cbase + cofs +
+	    sc->ciss_cfg->transport_offset);
+	if (ciss_init_perf(sc)) {
+	    supported_methods &= ~method;
+	    goto setup;
+	}
+    } else if (supported_methods & CISS_TRANSPORT_METHOD_SIMPLE) {
+	method = CISS_TRANSPORT_METHOD_SIMPLE;
+    } else {
+	ciss_printf(sc, "No supported transport methods: 0x%x\n",
+	    sc->ciss_cfg->supported_methods);
 	return(ENXIO);
     }
-    sc->ciss_cfg->requested_method = CISS_TRANSPORT_METHOD_SIMPLE;
+
+    /*
+     * Tell it we're using the low 4GB of RAM.  Set the default interrupt
+     * coalescing options.
+     */
+    sc->ciss_cfg->requested_method = method;
     sc->ciss_cfg->command_physlimit = 0;
     sc->ciss_cfg->interrupt_coalesce_delay = CISS_INTERRUPT_COALESCE_DELAY;
     sc->ciss_cfg->interrupt_coalesce_count = CISS_INTERRUPT_COALESCE_COUNT;
@@ -609,11 +718,15 @@ ciss_init_pci(struct ciss_softc *sc)
 		    CISS_TL_SIMPLE_READ(sc, CISS_TL_SIMPLE_IDBR));
 	return(ENXIO);
     }
-    if (!(sc->ciss_cfg->active_method != CISS_TRANSPORT_METHOD_SIMPLE)) {
-	ciss_printf(sc,
-		    "adapter refuses to go into 'simple' transport mode (0x%x, 0x%x)\n",
-		    sc->ciss_cfg->supported_methods, sc->ciss_cfg->active_method);
-	return(ENXIO);
+    if ((sc->ciss_cfg->active_method & method) == 0) {
+	supported_methods &= ~method;
+	if (supported_methods == 0) {
+	    ciss_printf(sc, "adapter refuses to go into available transports "
+		"mode (0x%x, 0x%x)\n", supported_methods,
+		sc->ciss_cfg->active_method);
+	    return(ENXIO);
+	} else 
+	    goto setup;
     }
 
     /*
@@ -622,6 +735,30 @@ ciss_init_pci(struct ciss_softc *sc)
     if ((error = ciss_wait_adapter(sc)) != 0)
 	return(error);
 
+    /* Prepare to possibly use MSIX and/or PERFORMANT interrupts.  Normal
+     * interrupts have a rid of 0, this will be overridden if MSIX is used.
+     */
+    sc->ciss_irq_rid[0] = 0;
+    if (method == CISS_TRANSPORT_METHOD_PERF) {
+	ciss_printf(sc, "PERFORMANT Transport\n");
+	if ((ciss_force_interrupt != 1) && (ciss_setup_msix(sc) == 0)) {
+	    intr = ciss_perf_msi_intr;
+	    sc->ciss_interrupt_mask = CISS_TL_PERF_INTR_MSI;
+	} else {
+	    intr = ciss_perf_intr;
+	    sc->ciss_interrupt_mask = CISS_TL_PERF_INTR_OPQ;
+	}
+    } else {
+	ciss_printf(sc, "SIMPLE Transport\n");
+	/* MSIX doesn't seem to work in SIMPLE mode, only enable if it forced */
+	if (ciss_force_interrupt == 2)
+	    /* If this fails, we automatically revert to INTx */
+	    ciss_setup_msix(sc);
+	sc->ciss_perf = NULL;
+	intr = ciss_intr;
+	sc->ciss_interrupt_mask = sqmask;
+    }
+
     /*
      * Turn off interrupts before we go routing anything.
      */
@@ -630,17 +767,15 @@ ciss_init_pci(struct ciss_softc *sc)
     /*
      * Allocate and set up our interrupt.
      */
-    sc->ciss_irq_rid = 0;
     if ((sc->ciss_irq_resource =
-	 bus_alloc_resource(sc->ciss_dev, SYS_RES_IRQ, &sc->ciss_irq_rid, 0, ~0, 1, 
-			    RF_ACTIVE | RF_SHAREABLE)) == NULL) {
+	 bus_alloc_resource_any(sc->ciss_dev, SYS_RES_IRQ, &sc->ciss_irq_rid[0],
+				RF_ACTIVE | RF_SHAREABLE)) == NULL) {
 	ciss_printf(sc, "can't allocate interrupt\n");
 	return(ENXIO);
     }
-    error = bus_setup_intr(sc->ciss_dev, sc->ciss_irq_resource, 
-			   0, ciss_intr, sc,
-			   &sc->ciss_intr, NULL);
-    if (error) {
+
+    if (bus_setup_intr(sc->ciss_dev, sc->ciss_irq_resource,
+		       0, ciss_intr, sc,  &sc->ciss_intr, NULL)) {
 	ciss_printf(sc, "can't set up interrupt\n");
 	return(ENXIO);
     }
@@ -660,7 +795,7 @@ ciss_init_pci(struct ciss_softc *sc)
 			   BUS_SPACE_MAXSIZE_32BIT,	/* maxsize */
 			   CISS_COMMAND_SG_LENGTH,	/* nsegments */
 			   BUS_SPACE_MAXSIZE_32BIT,	/* maxsegsize */
-			   BUS_DMA_ALLOCNOW,		/* flags */
+			   0,				/* flags */
 			   &sc->ciss_parent_dmat)) {
 	ciss_printf(sc, "can't allocate parent DMA tag\n");
 	return(ENOMEM);
@@ -686,6 +821,109 @@ ciss_init_pci(struct ciss_softc *sc)
 }
 
 /************************************************************************
+ * Setup MSI/MSIX operation (Performant only)
+ * Four interrupts are available, but we only use 1 right now.
+ */
+static int
+ciss_setup_msix(struct ciss_softc *sc)
+{
+    uint32_t id;
+    int val, i;
+
+    /* Weed out devices that don't actually support MSI */
+    id = (pci_get_subvendor(sc->ciss_dev) << 16) |
+	pci_get_subdevice(sc->ciss_dev);
+    if ((id == 0x0e114070) || (id == 0x0e114080) || (id == 0x0e114082) ||
+	(id == 0x0e114083))
+	return (EINVAL);
+
+    val = pci_msix_count(sc->ciss_dev);
+    if ((val != CISS_MSI_COUNT) || (pci_alloc_msix(sc->ciss_dev, &val) != 0))
+	return (EINVAL);
+
+    sc->ciss_msi = val;
+    ciss_printf(sc, "Using MSIX interrupt\n");
+
+    for (i = 0; i < CISS_MSI_COUNT; i++)
+	sc->ciss_irq_rid[i] = i + 1;
+
+    return (0);
+
+}
+
+/************************************************************************
+ * Setup the Performant structures.
+ */
+static int
+ciss_init_perf(struct ciss_softc *sc)
+{
+    struct ciss_perf_config *pc = sc->ciss_perf;
+    int reply_size;
+
+    /*
+     * Create the DMA tag for the reply queue.
+     */
+    reply_size = sizeof(uint64_t) * sc->ciss_max_requests;
+    if (bus_dma_tag_create(sc->ciss_parent_dmat,	/* parent */
+			   1, 0, 			/* alignment, boundary */
+			   BUS_SPACE_MAXADDR_32BIT,	/* lowaddr */
+			   BUS_SPACE_MAXADDR, 		/* highaddr */
+			   NULL, NULL, 			/* filter, filterarg */
+			   reply_size, 1,		/* maxsize, nsegments */
+			   BUS_SPACE_MAXSIZE_32BIT,	/* maxsegsize */
+			   0,				/* flags */
+			   &sc->ciss_reply_dmat)) {
+	ciss_printf(sc, "can't allocate reply DMA tag\n");
+	return(ENOMEM);
+    }
+    /*
+     * Allocate memory and make it available for DMA.
+     */
+    if (bus_dmamem_alloc(sc->ciss_reply_dmat, (void **)&sc->ciss_reply,
+			 BUS_DMA_NOWAIT, &sc->ciss_reply_map)) {
+	ciss_printf(sc, "can't allocate reply memory\n");
+	return(ENOMEM);
+    }
+    bus_dmamap_load(sc->ciss_reply_dmat, sc->ciss_reply_map, sc->ciss_reply,
+		    reply_size, ciss_command_map_helper, &sc->ciss_reply_phys, 0);
+    bzero(sc->ciss_reply, reply_size);
+
+    sc->ciss_cycle = 0x1;
+    sc->ciss_rqidx = 0;
+
+    /*
+     * Preload the fetch table with common command sizes.  This allows the
+     * hardware to not waste bus cycles for typical i/o commands, but also not
+     * tax the driver to be too exact in choosing sizes.  The table is optimized
+     * for page-aligned i/o's, but since most i/o comes from the various pagers,
+     * it's a reasonable assumption to make.
+     */
+    pc->fetch_count[CISS_SG_FETCH_NONE] = (sizeof(struct ciss_command) + 15) / 16;
+    pc->fetch_count[CISS_SG_FETCH_1] =
+	(sizeof(struct ciss_command) + sizeof(struct ciss_sg_entry) * 1 + 15) / 16;
+    pc->fetch_count[CISS_SG_FETCH_2] =
+	(sizeof(struct ciss_command) + sizeof(struct ciss_sg_entry) * 2 + 15) / 16;
+    pc->fetch_count[CISS_SG_FETCH_4] =
+	(sizeof(struct ciss_command) + sizeof(struct ciss_sg_entry) * 4 + 15) / 16;
+    pc->fetch_count[CISS_SG_FETCH_8] =
+	(sizeof(struct ciss_command) + sizeof(struct ciss_sg_entry) * 8 + 15) / 16;
+    pc->fetch_count[CISS_SG_FETCH_16] =
+	(sizeof(struct ciss_command) + sizeof(struct ciss_sg_entry) * 16 + 15) / 16;
+    pc->fetch_count[CISS_SG_FETCH_32] =
+	(sizeof(struct ciss_command) + sizeof(struct ciss_sg_entry) * 32 + 15) / 16;
+    pc->fetch_count[CISS_SG_FETCH_MAX] = (CISS_COMMAND_ALLOC_SIZE + 15) / 16;
+
+    pc->rq_size = sc->ciss_max_requests; /* XXX less than the card supports? */
+    pc->rq_count = 1;	/* XXX Hardcode for a single queue */
+    pc->rq_bank_hi = 0;
+    pc->rq_bank_lo = 0;
+    pc->rq[0].rq_addr_hi = 0x0;
+    pc->rq[0].rq_addr_lo = sc->ciss_reply_phys;
+
+    return(0);
+}
+
+/************************************************************************
  * Wait for the adapter to come ready.
  */
 static int
@@ -731,7 +969,10 @@ ciss_flush_adapter(struct ciss_softc *sc)
      * it, as we may be going to do more I/O (eg. we are emulating
      * the Synchronise Cache command).
      */
-    cbfc = kmalloc(sizeof(*cbfc), CISS_MALLOC_CLASS, M_INTWAIT | M_ZERO);
+    if ((cbfc = kmalloc(sizeof(*cbfc), CISS_MALLOC_CLASS, M_NOWAIT | M_ZERO)) == NULL) {
+	error = ENOMEM;
+	goto out;
+    }
     if ((error = ciss_get_bmic_request(sc, &cr, CISS_BMIC_FLUSH_CACHE,
 				       (void **)&cbfc, sizeof(*cbfc))) != 0)
 	goto out;
@@ -766,6 +1007,41 @@ out:
     return(error);
 }
 
+static void
+ciss_soft_reset(struct ciss_softc *sc)
+{
+    struct ciss_request		*cr = NULL;
+    struct ciss_command		*cc;
+    int				i, error = 0;
+
+    for (i = 0; i < sc->ciss_max_logical_bus; i++) {
+	/* only reset proxy controllers */
+	if (sc->ciss_controllers[i].physical.bus == 0)
+	    continue;
+
+	if ((error = ciss_get_request(sc, &cr)) != 0)
+	    break;
+
+	if ((error = ciss_get_bmic_request(sc, &cr, CISS_BMIC_SOFT_RESET,
+					   NULL, 0)) != 0)
+	    break;
+
+	cc = CISS_FIND_COMMAND(cr);
+	cc->header.address = sc->ciss_controllers[i];
+
+	if ((error = ciss_synch_request(cr, 60 * 1000)) != 0)
+	    break;
+
+	ciss_release_request(cr);
+    }
+
+    if (error)
+	ciss_printf(sc, "error resetting controller (%d)\n", error);
+
+    if (cr != NULL)
+	ciss_release_request(cr);
+}
+
 /************************************************************************
  * Allocate memory for the adapter command structures, initialise
  * the request structures.
@@ -781,12 +1057,6 @@ ciss_init_requests(struct ciss_softc *sc)
 
     debug_called(1);
 
-    /*
-     * Calculate the number of request structures/commands we are
-     * going to provide for this adapter.
-     */
-    sc->ciss_max_requests = min(CISS_MAX_REQUESTS, sc->ciss_cfg->max_outstanding_commands);
-
     if (bootverbose)
 	ciss_printf(sc, "using %d of %d available commands\n",
 		    sc->ciss_max_requests, sc->ciss_cfg->max_outstanding_commands);
@@ -795,14 +1065,14 @@ ciss_init_requests(struct ciss_softc *sc)
      * Create the DMA tag for commands.
      */
     if (bus_dma_tag_create(sc->ciss_parent_dmat,	/* parent */
-			   1, 0, 			/* alignment, boundary */
+			   32, 0, 			/* alignment, boundary */
 			   BUS_SPACE_MAXADDR_32BIT,	/* lowaddr */
 			   BUS_SPACE_MAXADDR, 		/* highaddr */
 			   NULL, NULL, 			/* filter, filterarg */
 			   CISS_COMMAND_ALLOC_SIZE *
 			   sc->ciss_max_requests, 1,	/* maxsize, nsegments */
 			   BUS_SPACE_MAXSIZE_32BIT,	/* maxsegsize */
-			   BUS_DMA_ALLOCNOW,		/* flags */
+			   0,				/* flags */
 			   &sc->ciss_command_dmat)) {
 	ciss_printf(sc, "can't allocate command DMA tag\n");
 	return(ENOMEM);
@@ -815,9 +1085,9 @@ ciss_init_requests(struct ciss_softc *sc)
 	ciss_printf(sc, "can't allocate command memory\n");
 	return(ENOMEM);
     }
-    bus_dmamap_load(sc->ciss_command_dmat, sc->ciss_command_map, sc->ciss_command,
+    bus_dmamap_load(sc->ciss_command_dmat, sc->ciss_command_map,sc->ciss_command,
 		    CISS_COMMAND_ALLOC_SIZE * sc->ciss_max_requests,
-		    ciss_command_map_helper, sc, 0);
+		    ciss_command_map_helper, &sc->ciss_command_phys, 0);
     bzero(sc->ciss_command, CISS_COMMAND_ALLOC_SIZE * sc->ciss_max_requests);
 
     /*
@@ -837,9 +1107,10 @@ ciss_init_requests(struct ciss_softc *sc)
 static void
 ciss_command_map_helper(void *arg, bus_dma_segment_t *segs, int nseg, int error)
 {
-    struct ciss_softc	*sc = (struct ciss_softc *)arg;
+    uint32_t *addr;
 
-    sc->ciss_command_phys = segs->ds_addr;
+    addr = arg;
+    *addr = segs[0].ds_addr;
 }
 
 /************************************************************************
@@ -895,9 +1166,8 @@ ciss_identify_adapter(struct ciss_softc *sc)
 	goto out;
     }
 
-#if 1
+#if 0
     /* XXX later revisions may not need this */
-    /* Apparently we still need this */
     sc->ciss_flags |= CISS_FLAG_FAKE_SYNCH;
 #endif
 
@@ -972,7 +1242,11 @@ ciss_report_luns(struct ciss_softc *sc, int opcode, int nunits)
     if ((error = ciss_get_request(sc, &cr)) != 0)
 	goto out;
     report_size = sizeof(*cll) + nunits * sizeof(union ciss_device_address);
-    cll = kmalloc(report_size, CISS_MALLOC_CLASS, M_INTWAIT | M_ZERO);
+    if ((cll = kmalloc(report_size, CISS_MALLOC_CLASS, M_NOWAIT | M_ZERO)) == NULL) {
+	ciss_printf(sc, "can't allocate memory for lun report\n");
+	error = ENOMEM;
+	goto out;
+    }
 
     /*
      * Build the Report Logical/Physical LUNs command.
@@ -1075,12 +1349,20 @@ ciss_init_logical(struct ciss_softc *sc)
 
     sc->ciss_logical =
 	kmalloc(sc->ciss_max_logical_bus * sizeof(struct ciss_ldrive *),
-		CISS_MALLOC_CLASS, M_INTWAIT | M_ZERO);
+	       CISS_MALLOC_CLASS, M_NOWAIT | M_ZERO);
+    if (sc->ciss_logical == NULL) {
+	error = ENXIO;
+	goto out;
+    }
 
     for (i = 0; i <= sc->ciss_max_logical_bus; i++) {
 	sc->ciss_logical[i] =
 	    kmalloc(CISS_MAX_LOGICAL * sizeof(struct ciss_ldrive),
-		    CISS_MALLOC_CLASS, M_INTWAIT | M_ZERO);
+		   CISS_MALLOC_CLASS, M_NOWAIT | M_ZERO);
+	if (sc->ciss_logical[i] == NULL) {
+	    error = ENXIO;
+	    goto out;
+	}
 
 	for (j = 0; j < CISS_MAX_LOGICAL; j++)
 	    sc->ciss_logical[i][j].cl_status = CISS_LD_NONEXISTENT;
@@ -1188,7 +1470,13 @@ ciss_init_physical(struct ciss_softc *sc)
 
     sc->ciss_controllers =
 	kmalloc(sc->ciss_max_logical_bus * sizeof (union ciss_device_address),
-		CISS_MALLOC_CLASS, M_INTWAIT | M_ZERO);
+	       CISS_MALLOC_CLASS, M_NOWAIT | M_ZERO);
+
+    if (sc->ciss_controllers == NULL) {
+	ciss_printf(sc, "Could not allocate memory for controller map\n");
+	error = ENOMEM;
+	goto out;
+    }
 
     /* setup a map of controller addresses */
     for (i = 0; i < nphys; i++) {
@@ -1199,12 +1487,22 @@ ciss_init_physical(struct ciss_softc *sc)
 
     sc->ciss_physical =
 	kmalloc(sc->ciss_max_physical_bus * sizeof(struct ciss_pdrive *),
-		CISS_MALLOC_CLASS, M_INTWAIT | M_ZERO);
+	       CISS_MALLOC_CLASS, M_NOWAIT | M_ZERO);
+    if (sc->ciss_physical == NULL) {
+	ciss_printf(sc, "Could not allocate memory for physical device map\n");
+	error = ENOMEM;
+	goto out;
+    }
 
     for (i = 0; i < sc->ciss_max_physical_bus; i++) {
 	sc->ciss_physical[i] =
 	    kmalloc(sizeof(struct ciss_pdrive) * CISS_MAX_PHYSTGT,
-		    CISS_MALLOC_CLASS, M_INTWAIT | M_ZERO);
+		   CISS_MALLOC_CLASS, M_NOWAIT | M_ZERO);
+	if (sc->ciss_physical[i] == NULL) {
+	    ciss_printf(sc, "Could not allocate memory for target map\n");
+	    error = ENOMEM;
+	    goto out;
+	}
     }
 
     ciss_filter_physical(sc, cll);
@@ -1520,7 +1818,7 @@ ciss_accept_media(struct ciss_softc *sc, struct ciss_ldrive *ld)
 
     ldrive = CISS_LUN_TO_TARGET(ld->cl_address.logical.lun);
 
-    debug(0, "bringing logical drive %d back online", ldrive);
+    debug(0, "bringing logical drive %d back online");
 
     /*
      * Build a CISS BMIC command to bring the drive back online.
@@ -1568,7 +1866,7 @@ static void
 ciss_free(struct ciss_softc *sc)
 {
     struct ciss_request *cr;
-    int			i;
+    int			i, j;
 
     debug_called(1);
 
@@ -1583,10 +1881,35 @@ ciss_free(struct ciss_softc *sc)
 
     ciss_kill_notify_thread(sc);
 
+    /* disconnect from CAM */
+    if (sc->ciss_cam_sim) {
+	for (i = 0; i < sc->ciss_max_logical_bus; i++) {
+	    if (sc->ciss_cam_sim[i]) {
+		xpt_bus_deregister(cam_sim_path(sc->ciss_cam_sim[i]));
+		cam_sim_free(sc->ciss_cam_sim[i]);
+	    }
+	}
+	for (i = CISS_PHYSICAL_BASE; i < sc->ciss_max_physical_bus +
+	     CISS_PHYSICAL_BASE; i++) {
+	    if (sc->ciss_cam_sim[i]) {
+		xpt_bus_deregister(cam_sim_path(sc->ciss_cam_sim[i]));
+		cam_sim_free(sc->ciss_cam_sim[i]);
+	    }
+	}
+	kfree(sc->ciss_cam_sim, CISS_MALLOC_CLASS);
+    }
+    if (sc->ciss_cam_devq)
+	cam_simq_release(sc->ciss_cam_devq);
+
     /* remove the control device */
+    lockmgr(&sc->ciss_lock, LK_RELEASE);
     if (sc->ciss_dev_t != NULL)
 	destroy_dev(sc->ciss_dev_t);
 
+    /* Final cleanup of the callout. */
+    callout_stop(&sc->ciss_periodic);
+    lockuninit(&sc->ciss_lock);
+
     /* free the controller data */
     if (sc->ciss_id != NULL)
 	kfree(sc->ciss_id, CISS_MALLOC_CLASS);
@@ -1602,11 +1925,9 @@ ciss_free(struct ciss_softc *sc)
 	bus_teardown_intr(sc->ciss_dev, sc->ciss_irq_resource, sc->ciss_intr);
     if (sc->ciss_irq_resource != NULL)
 	bus_release_resource(sc->ciss_dev, SYS_RES_IRQ,
-			     sc->ciss_irq_rid, sc->ciss_irq_resource);
-
-    /* destroy DMA tags */
-    if (sc->ciss_parent_dmat)
-	bus_dma_tag_destroy(sc->ciss_parent_dmat);
+			     sc->ciss_irq_rid[0], sc->ciss_irq_resource);
+    if (sc->ciss_msi)
+	pci_release_msi(sc->ciss_dev);
 
     while ((cr = ciss_dequeue_free(sc)) != NULL)
 	bus_dmamap_destroy(sc->ciss_buffer_dmat, cr->cr_datamap);
@@ -1621,29 +1942,26 @@ ciss_free(struct ciss_softc *sc)
     if (sc->ciss_command_dmat)
 	bus_dma_tag_destroy(sc->ciss_command_dmat);
 
-    /* disconnect from CAM */
-    if (sc->ciss_cam_sim) {
-	for (i = 0; i < sc->ciss_max_logical_bus; i++) {
-	    if (sc->ciss_cam_sim[i]) {
-		xpt_bus_deregister(cam_sim_path(sc->ciss_cam_sim[i]));
-		cam_sim_free(sc->ciss_cam_sim[i]);
-	    }
-	}
-	for (i = CISS_PHYSICAL_BASE; i < sc->ciss_max_physical_bus +
-	     CISS_PHYSICAL_BASE; i++) {
-	    if (sc->ciss_cam_sim[i]) {
-		xpt_bus_deregister(cam_sim_path(sc->ciss_cam_sim[i]));
-		cam_sim_free(sc->ciss_cam_sim[i]);
-	    }
-	}
-	kfree(sc->ciss_cam_sim, CISS_MALLOC_CLASS);
+    if (sc->ciss_reply) {
+	bus_dmamap_unload(sc->ciss_reply_dmat, sc->ciss_reply_map);
+	bus_dmamem_free(sc->ciss_reply_dmat, sc->ciss_reply, sc->ciss_reply_map);
     }
-    if (sc->ciss_cam_devq)
-	cam_simq_release(sc->ciss_cam_devq);
+    if (sc->ciss_reply_dmat)
+	bus_dma_tag_destroy(sc->ciss_reply_dmat);
 
+    /* destroy DMA tags */
+    if (sc->ciss_parent_dmat)
+	bus_dma_tag_destroy(sc->ciss_parent_dmat);
     if (sc->ciss_logical) {
-	for (i = 0; i < sc->ciss_max_logical_bus; i++)
+	for (i = 0; i <= sc->ciss_max_logical_bus; i++) {
+	    for (j = 0; j < CISS_MAX_LOGICAL; j++) {
+		if (sc->ciss_logical[i][j].cl_ldrive)
+		    kfree(sc->ciss_logical[i][j].cl_ldrive, CISS_MALLOC_CLASS);
+		if (sc->ciss_logical[i][j].cl_lstatus)
+		    kfree(sc->ciss_logical[i][j].cl_lstatus, CISS_MALLOC_CLASS);
+	    }
 	    kfree(sc->ciss_logical[i], CISS_MALLOC_CLASS);
+	}
 	kfree(sc->ciss_logical, CISS_MALLOC_CLASS);
     }
 
@@ -1655,6 +1973,7 @@ ciss_free(struct ciss_softc *sc)
 
     if (sc->ciss_controllers)
 	kfree(sc->ciss_controllers, CISS_MALLOC_CLASS);
+
 }
 
 /************************************************************************
@@ -1706,26 +2025,20 @@ ciss_start(struct ciss_request *cr)
  * (eg. timeouts, etc.)
  */
 static void
-ciss_done(struct ciss_softc *sc)
+ciss_done(struct ciss_softc *sc, cr_qhead_t *qh)
 {
     struct ciss_request	*cr;
     struct ciss_command	*cc;
     u_int32_t		tag, index;
-    int			complete;
 
     debug_called(3);
 
     /*
      * Loop quickly taking requests from the adapter and moving them
-     * from the busy queue to the completed queue.
+     * to the completed queue.
      */
-    complete = 0;
     for (;;) {
 
-	/* see if the OPQ contains anything */
-	if (!CISS_TL_SIMPLE_OPQ_INTERRUPT(sc))
-	    break;
-
 	tag = CISS_TL_SIMPLE_FETCH_CMD(sc);
 	if (tag == CISS_TL_SIMPLE_OPQ_EMPTY)
 	    break;
@@ -1739,21 +2052,45 @@ ciss_done(struct ciss_softc *sc)
 	cr = &(sc->ciss_request[index]);
 	cc = CISS_FIND_COMMAND(cr);
 	cc->header.host_tag = tag;	/* not updated by adapter */
-	if (ciss_remove_busy(cr)) {
-	    /* assume this is garbage out of the adapter */
-	    ciss_printf(sc, "completed nonbusy request %d\n", index);
-	} else {
-	    ciss_enqueue_complete(cr);
-	}
-	complete = 1;
+	ciss_enqueue_complete(cr, qh);
     }
 
+}
+
+static void
+ciss_perf_done(struct ciss_softc *sc, cr_qhead_t *qh)
+{
+    struct ciss_request	*cr;
+    struct ciss_command	*cc;
+    u_int32_t		tag, index;
+
+    debug_called(3);
+
     /*
-     * Invoke completion processing.  If we can defer this out of
-     * interrupt context, that'd be good.
+     * Loop quickly taking requests from the adapter and moving them
+     * to the completed queue.
      */
-    if (complete)
-	ciss_complete(sc);
+    for (;;) {
+	tag = sc->ciss_reply[sc->ciss_rqidx];
+	if ((tag & CISS_CYCLE_MASK) != sc->ciss_cycle)
+	    break;
+	index = tag >> 2;
+	debug(2, "completed command %d%s\n", index,
+	      (tag & CISS_HDR_HOST_TAG_ERROR) ? " with error" : "");
+	if (index < sc->ciss_max_requests) {
+	    cr = &(sc->ciss_request[index]);
+	    cc = CISS_FIND_COMMAND(cr);
+	    cc->header.host_tag = tag;	/* not updated by adapter */
+	    ciss_enqueue_complete(cr, qh);
+	} else {
+	    ciss_printf(sc, "completed invalid request %d (0x%x)\n", index, tag);
+	}
+	if (++sc->ciss_rqidx == sc->ciss_max_requests) {
+	    sc->ciss_rqidx = 0;
+	    sc->ciss_cycle ^= 1;
+	}
+    }
+
 }
 
 /************************************************************************
@@ -1762,15 +2099,48 @@ ciss_done(struct ciss_softc *sc)
 static void
 ciss_intr(void *arg)
 {
+    cr_qhead_t qh;
     struct ciss_softc	*sc = (struct ciss_softc *)arg;
 
     /*
      * The only interrupt we recognise indicates that there are
      * entries in the outbound post queue.
      */
-    ciss_done(sc);
+    STAILQ_INIT(&qh);
+    ciss_done(sc, &qh);
+    lockmgr(&sc->ciss_lock, LK_EXCLUSIVE);
+    ciss_complete(sc, &qh);
+    lockmgr(&sc->ciss_lock, LK_RELEASE);
+}
+
+static void
+ciss_perf_intr(void *arg)
+{
+    struct ciss_softc	*sc = (struct ciss_softc *)arg;
+
+    /* Clear the interrupt and flush the bridges.  Docs say that the flush
+     * needs to be done twice, which doesn't seem right.
+     */
+    CISS_TL_PERF_CLEAR_INT(sc);
+    CISS_TL_PERF_FLUSH_INT(sc);
+
+    ciss_perf_msi_intr(sc);
+}
+
+static void
+ciss_perf_msi_intr(void *arg)
+{
+    cr_qhead_t qh;
+    struct ciss_softc	*sc = (struct ciss_softc *)arg;
+
+    STAILQ_INIT(&qh);
+    ciss_perf_done(sc, &qh);
+    lockmgr(&sc->ciss_lock, LK_EXCLUSIVE);
+    ciss_complete(sc, &qh);
+    lockmgr(&sc->ciss_lock, LK_RELEASE);
 }
 
+
 /************************************************************************
  * Process completed requests.
  *
@@ -1781,7 +2151,7 @@ ciss_intr(void *arg)
  * - by clearing the CISS_REQ_POLL flag in interrupt/timeout context
  */
 static void
-ciss_complete(struct ciss_softc *sc)
+ciss_complete(struct ciss_softc *sc, cr_qhead_t *qh)
 {
     struct ciss_request	*cr;
 
@@ -1792,10 +2162,14 @@ ciss_complete(struct ciss_softc *sc)
      * completion processing on them.
      */
     for (;;) {
-	if ((cr = ciss_dequeue_complete(sc)) == NULL)
+	if ((cr = ciss_dequeue_complete(sc, qh)) == NULL)
 	    break;
 	ciss_unmap_request(cr);
 
+	if ((cr->cr_flags & CISS_REQ_BUSY) == 0)
+	    ciss_printf(sc, "WARNING: completing non-busy request\n");
+	cr->cr_flags &= ~CISS_REQ_BUSY;
+
 	/*
 	 * If the request has a callback, invoke it.
 	 */
@@ -1835,7 +2209,7 @@ ciss_complete(struct ciss_softc *sc)
  * and command status values.
  */
 static int
-ciss_report_request(struct ciss_request *cr, int *command_status, int *scsi_status)
+_ciss_report_request(struct ciss_request *cr, int *command_status, int *scsi_status, const char *func)
 {
     struct ciss_command		*cc;
     struct ciss_error_info	*ce;
@@ -1884,10 +2258,11 @@ ciss_report_request(struct ciss_request *cr, int *command_status, int *scsi_stat
 			ce->command_status, ciss_name_command_status(ce->command_status),
 			ce->scsi_status);
 	if (ce->command_status == CISS_CMD_STATUS_INVALID_COMMAND) {
-	    ciss_printf(cr->cr_sc, "invalid command, offense size %d at %d, value 0x%x\n",
+	    ciss_printf(cr->cr_sc, "invalid command, offense size %d at %d, value 0x%x, function %s\n",
 			ce->additional_error_info.invalid_command.offense_size,
 			ce->additional_error_info.invalid_command.offense_offset,
-			ce->additional_error_info.invalid_command.offense_value);
+			ce->additional_error_info.invalid_command.offense_value,
+			func);
 	}
     }
 #if 0
@@ -1920,16 +2295,24 @@ ciss_synch_request(struct ciss_request *cr, int timeout)
 static int
 ciss_poll_request(struct ciss_request *cr, int timeout)
 {
+    cr_qhead_t qh;
+    struct ciss_softc *sc;
     int		error;
 
     debug_called(2);
 
+    STAILQ_INIT(&qh);
+    sc = cr->cr_sc;
     cr->cr_flags |= CISS_REQ_POLL;
     if ((error = ciss_start(cr)) != 0)
 	return(error);
 
     do {
-	ciss_done(cr->cr_sc);
+	if (sc->ciss_perf)
+	    ciss_perf_done(sc, &qh);
+	else
+	    ciss_done(sc, &qh);
+	ciss_complete(sc, &qh);
 	if (!(cr->cr_flags & CISS_REQ_POLL))
 	    return(0);
 	DELAY(1000);
@@ -2032,6 +2415,7 @@ ciss_get_request(struct ciss_softc *sc, struct ciss_request **crp)
     cr->cr_flags = 0;
     cr->cr_complete = NULL;
     cr->cr_private = NULL;
+    cr->cr_sg_tag = CISS_SG_MAX;	/* Backstop to prevent accidents */
 
     ciss_preen_command(cr);
     *crp = cr;
@@ -2108,7 +2492,10 @@ ciss_get_bmic_request(struct ciss_softc *sc, struct ciss_request **crp,
     dataout = 0;
     if ((bufsize > 0) && (bufp != NULL)) {
 	if (*bufp == NULL) {
-	    buf = kmalloc(bufsize, CISS_MALLOC_CLASS, M_INTWAIT | M_ZERO);
+	    if ((buf = kmalloc(bufsize, CISS_MALLOC_CLASS, M_NOWAIT | M_ZERO)) == NULL) {
+		error = ENOMEM;
+		goto out;
+	    }
 	} else {
 	    buf = *bufp;
 	    dataout = 1;	/* we are given a buffer, so we are writing */
@@ -2143,8 +2530,6 @@ out:
     if (error) {
 	if (cr != NULL)
 	    ciss_release_request(cr);
-	if ((bufp != NULL) && (*bufp == NULL) && (buf != NULL))
-	    kfree(buf, CISS_MALLOC_CLASS);
     } else {
 	*crp = cr;
 	if ((bufp != NULL) && (*bufp == NULL) && (buf != NULL))
@@ -2171,8 +2556,10 @@ ciss_user_command(struct ciss_softc *sc, IOCTL_Command_struct *ioc)
     /*
      * Get a request.
      */
-    if ((error = ciss_get_request(sc, &cr)) != 0)
-	goto out;
+    crit_enter();
+    while (ciss_get_request(sc, &cr) != 0)
+	tsleep(sc, 0, "cissREQ", hz);
+    crit_exit();
     cc = CISS_FIND_COMMAND(cr);
 
     /*
@@ -2180,7 +2567,10 @@ ciss_user_command(struct ciss_softc *sc, IOCTL_Command_struct *ioc)
      */
     cr->cr_length = ioc->buf_size;
     if (ioc->buf_size > 0) {
-	cr->cr_data = kmalloc(ioc->buf_size, CISS_MALLOC_CLASS, M_WAITOK);
+	if ((cr->cr_data = kmalloc(ioc->buf_size, CISS_MALLOC_CLASS, M_NOWAIT)) == NULL) {
+	    error = ENOMEM;
+	    goto out;
+	}
 	if ((error = copyin(ioc->buf, cr->cr_data, ioc->buf_size))) {
 	    debug(0, "copyin: bad data buffer %p/%d", ioc->buf, ioc->buf_size);
 	    goto out;
@@ -2264,8 +2654,12 @@ ciss_map_request(struct ciss_request *cr)
 	/*
 	 * Post the command to the adapter.
 	 */
-	ciss_enqueue_busy(cr);
-	CISS_TL_SIMPLE_POST_CMD(cr->cr_sc, CISS_FIND_COMMANDPHYS(cr));
+	cr->cr_sg_tag = CISS_SG_NONE;
+	cr->cr_flags |= CISS_REQ_BUSY;
+	if (sc->ciss_perf)
+	    CISS_TL_PERF_POST_CMD(sc, cr);
+	else
+	    CISS_TL_SIMPLE_POST_CMD(sc, CISS_FIND_COMMANDPHYS(cr));
     }
 
     return(0);
@@ -2276,7 +2670,7 @@ ciss_request_map_helper(void *arg, bus_dma_segment_t *segs, int nseg, int error)
 {
     struct ciss_command	*cc;
     struct ciss_request *cr;
-    struct ciss_softc   *sc;
+    struct ciss_softc	*sc;
     int			i;
 
     debug_called(2);
@@ -2299,11 +2693,31 @@ ciss_request_map_helper(void *arg, bus_dma_segment_t *segs, int nseg, int error)
     if (cr->cr_flags & CISS_REQ_DATAOUT)
 	bus_dmamap_sync(sc->ciss_buffer_dmat, cr->cr_datamap, BUS_DMASYNC_PREWRITE);
 
+    if (nseg == 0)
+	cr->cr_sg_tag = CISS_SG_NONE;
+    else if (nseg == 1)
+	cr->cr_sg_tag = CISS_SG_1;
+    else if (nseg == 2)
+	cr->cr_sg_tag = CISS_SG_2;
+    else if (nseg <= 4)
+	cr->cr_sg_tag = CISS_SG_4;
+    else if (nseg <= 8)
+	cr->cr_sg_tag = CISS_SG_8;
+    else if (nseg <= 16)
+	cr->cr_sg_tag = CISS_SG_16;
+    else if (nseg <= 32)
+	cr->cr_sg_tag = CISS_SG_32;
+    else
+	cr->cr_sg_tag = CISS_SG_MAX;
+
     /*
      * Post the command to the adapter.
      */
-    ciss_enqueue_busy(cr);
-    CISS_TL_SIMPLE_POST_CMD(cr->cr_sc, CISS_FIND_COMMANDPHYS(cr));
+    cr->cr_flags |= CISS_REQ_BUSY;
+    if (sc->ciss_perf)
+	CISS_TL_PERF_POST_CMD(sc, cr);
+    else
+	CISS_TL_SIMPLE_POST_CMD(sc, CISS_FIND_COMMANDPHYS(cr));
 }
 
 /************************************************************************
@@ -2371,7 +2785,11 @@ ciss_cam_init(struct ciss_softc *sc)
     maxbus = max(sc->ciss_max_logical_bus, sc->ciss_max_physical_bus +
 		 CISS_PHYSICAL_BASE);
     sc->ciss_cam_sim = kmalloc(maxbus * sizeof(struct cam_sim*),
-			       CISS_MALLOC_CLASS, M_INTWAIT | M_ZERO);
+			      CISS_MALLOC_CLASS, M_NOWAIT | M_ZERO);
+    if (sc->ciss_cam_sim == NULL) {
+	ciss_printf(sc, "can't allocate memory for controller SIM\n");
+	return(ENOMEM);
+    }
 
     for (i = 0; i < sc->ciss_max_logical_bus; i++) {
 	if ((sc->ciss_cam_sim[i] = cam_sim_alloc(ciss_cam_action, ciss_cam_poll,
@@ -2387,12 +2805,15 @@ ciss_cam_init(struct ciss_softc *sc)
 	/*
 	 * Register bus with this SIM.
 	 */
-	if (i == 0 || sc->ciss_controllers[i].physical.bus != 0) {
+	lockmgr(&sc->ciss_lock, LK_EXCLUSIVE);
+	if (i == 0 || sc->ciss_controllers[i].physical.bus != 0) { 
 	    if (xpt_bus_register(sc->ciss_cam_sim[i], i) != 0) {
 		ciss_printf(sc, "can't register SCSI bus %d\n", i);
+		lockmgr(&sc->ciss_lock, LK_RELEASE);
 		return (ENXIO);
 	    }
 	}
+	lockmgr(&sc->ciss_lock, LK_RELEASE);
     }
 
     for (i = CISS_PHYSICAL_BASE; i < sc->ciss_max_physical_bus +
@@ -2407,16 +2828,21 @@ ciss_cam_init(struct ciss_softc *sc)
 	    return (ENOMEM);
 	}
 
+	lockmgr(&sc->ciss_lock, LK_EXCLUSIVE);
 	if (xpt_bus_register(sc->ciss_cam_sim[i], i) != 0) {
 	    ciss_printf(sc, "can't register SCSI bus %d\n", i);
+	    lockmgr(&sc->ciss_lock, LK_RELEASE);
 	    return (ENXIO);
 	}
+	lockmgr(&sc->ciss_lock, LK_RELEASE);
     }
 
     /*
      * Initiate a rescan of the bus.
      */
+    lockmgr(&sc->ciss_lock, LK_EXCLUSIVE);
     ciss_cam_rescan_all(sc);
+    lockmgr(&sc->ciss_lock, LK_RELEASE);
 
     return(0);
 }
@@ -2432,12 +2858,15 @@ ciss_cam_rescan_target(struct ciss_softc *sc, int bus, int target)
 
     debug_called(1);
 
-    ccb = kmalloc(sizeof(union ccb), M_TEMP, M_WAITOK | M_ZERO);
+    if ((ccb = kmalloc(sizeof(union ccb), CISS_MALLOC_CLASS, M_NOWAIT | M_ZERO)) == NULL) {
+	ciss_printf(sc, "rescan failed (can't allocate CCB)\n");
+	return;
+    }
 
     if (xpt_create_path(&path, xpt_periph, cam_sim_path(sc->ciss_cam_sim[bus]),
 			target, CAM_LUN_WILDCARD) != CAM_REQ_CMP) {
 	ciss_printf(sc, "rescan failed (can't create path)\n");
-	kfree(ccb, M_TEMP);
+	kfree(ccb, CISS_MALLOC_CLASS);
 	return;
     }
 
@@ -2468,7 +2897,7 @@ static void
 ciss_cam_rescan_callback(struct cam_periph *periph, union ccb *ccb)
 {
     xpt_free_path(ccb->ccb_h.path);
-    kfree(ccb, M_TEMP);
+    kfree(ccb, CISS_MALLOC_CLASS);
 }
 
 /************************************************************************
@@ -2507,7 +2936,7 @@ ciss_cam_action(struct cam_sim *sim, union ccb *ccb)
 	ld = NULL;
 	if (!physical)
 	    ld = &sc->ciss_logical[bus][target];
-
+	    
 	/*
 	 * Use the cached geometry settings unless the fault tolerance
 	 * is invalid.
@@ -2560,8 +2989,8 @@ ciss_cam_action(struct cam_sim *sim, union ccb *ccb)
     {
 	struct ccb_trans_settings	*cts = &ccb->cts;
 	int				bus, target;
-	struct ccb_trans_settings_spi *spi =
-	    &cts->xport_specific.spi;
+	struct ccb_trans_settings_spi *spi = &cts->xport_specific.spi;
+	struct ccb_trans_settings_scsi *scsi = &cts->proto_specific.scsi;
 
 	bus = cam_sim_bus(sim);
 	target = cts->ccb_h.target_id;
@@ -2576,12 +3005,15 @@ ciss_cam_action(struct cam_sim *sim, union ccb *ccb)
 	spi->valid = CTS_SPI_VALID_DISC;
 	spi->flags = CTS_SPI_FLAGS_DISC_ENB;
 
+	scsi->valid = CTS_SCSI_VALID_TQ;
+	scsi->flags = CTS_SCSI_FLAGS_TAG_ENB;
+
 	cts->ccb_h.status = CAM_REQ_CMP;
 	break;
     }
 
     default:		/* we can't do this */
-	debug(1, "unsupported func_code = 0x%x", ccb->ccb_h.func_code);
+	debug(1, "unspported func_code = 0x%x", ccb->ccb_h.func_code);
 	ccb->ccb_h.status = CAM_REQ_INVALID;
 	break;
     }
@@ -2764,11 +3196,17 @@ ciss_cam_emulate(struct ciss_softc *sc, struct ccb_scsiio *csio)
 static void
 ciss_cam_poll(struct cam_sim *sim)
 {
+    cr_qhead_t qh;
     struct ciss_softc	*sc = cam_sim_softc(sim);
 
     debug_called(2);
 
-    ciss_done(sc);
+    STAILQ_INIT(&qh);
+    if (sc->ciss_perf)
+	ciss_perf_done(sc, &qh);
+    else
+	ciss_done(sc, &qh);
+    ciss_complete(sc, &qh);
 }
 
 /************************************************************************
@@ -2847,8 +3285,8 @@ ciss_cam_complete(struct ciss_request *cr)
     /* tell CAM we're ready for more commands */
     csio->ccb_h.status |= CAM_RELEASE_SIMQ;
 
-    xpt_done((union ccb *)csio);
     ciss_release_request(cr);
+    xpt_done((union ccb *)csio);
 }
 
 /********************************************************************************
@@ -2922,7 +3360,7 @@ ciss_name_device(struct ciss_softc *sc, int bus, int target)
 	return (0);
     if ((periph = ciss_find_periph(sc, bus, target)) != NULL) {
 	ksprintf(sc->ciss_logical[bus][target].cl_name, "%s%d",
-		 periph->periph_name, periph->unit_number);
+		periph->periph_name, periph->unit_number);
 	return(0);
     }
     sc->ciss_logical[bus][target].cl_name[0] = 0;
@@ -2936,6 +3374,9 @@ static void
 ciss_periodic(void *arg)
 {
     struct ciss_softc	*sc;
+    struct ciss_request	*cr = NULL;
+    struct ciss_command	*cc = NULL;
+    int			error = 0;
 
     debug_called(1);
 
@@ -2950,7 +3391,8 @@ ciss_periodic(void *arg)
 	      sc->ciss_heartbeat, sc->ciss_heart_attack);
 	if (sc->ciss_heart_attack == 3) {
 	    ciss_printf(sc, "ADAPTER HEARTBEAT FAILED\n");
-	    /* XXX should reset adapter here */
+	    ciss_disable_adapter(sc);
+	    return;
 	}
     } else {
 	sc->ciss_heartbeat = sc->ciss_cfg->heartbeat;
@@ -2959,6 +3401,24 @@ ciss_periodic(void *arg)
     }
 
     /*
+     * Send the NOP message and wait for a response.
+     */
+    if (ciss_nop_message_heartbeat != 0 && (error = ciss_get_request(sc, &cr)) == 0) {
+	cc = CISS_FIND_COMMAND(cr);
+	cr->cr_complete = ciss_nop_complete;
+	cc->cdb.cdb_length = 1;
+	cc->cdb.type = CISS_CDB_TYPE_MESSAGE;
+	cc->cdb.attribute = CISS_CDB_ATTRIBUTE_SIMPLE;
+	cc->cdb.direction = CISS_CDB_DIRECTION_WRITE;
+	cc->cdb.timeout = 0;
+	cc->cdb.cdb[0] = CISS_OPCODE_MESSAGE_NOP;
+
+	if ((error = ciss_start(cr)) != 0) {
+	    ciss_printf(sc, "SENDING NOP MESSAGE FAILED\n");
+	}
+    }
+
+    /*
      * If the notify event request has died for some reason, or has
      * not started yet, restart it.
      */
@@ -2970,9 +3430,77 @@ ciss_periodic(void *arg)
     /*
      * Reschedule.
      */
-    if (!(sc->ciss_flags & CISS_FLAG_ABORTING))
-	callout_reset(&sc->ciss_periodic, CISS_HEARTBEAT_RATE * hz,
-		      ciss_periodic, sc);
+    callout_reset(&sc->ciss_periodic, CISS_HEARTBEAT_RATE * hz, ciss_periodic, sc);
+}
+
+static void
+ciss_nop_complete(struct ciss_request *cr)
+{
+    struct ciss_softc		*sc;
+    static int			first_time = 1;
+
+    sc = cr->cr_sc;
+    if (ciss_report_request(cr, NULL, NULL) != 0) {
+	if (first_time == 1) {
+	    first_time = 0;
+	    ciss_printf(sc, "SENDING NOP MESSAGE FAILED (not logging anymore)\n");
+	}
+    }
+
+    ciss_release_request(cr);
+}
+
+/************************************************************************
+ * Disable the adapter.
+ *
+ * The all requests in completed queue is failed with hardware error.
+ * This will cause failover in a multipath configuration.
+ */
+static void
+ciss_disable_adapter(struct ciss_softc *sc)
+{
+    cr_qhead_t			qh;
+    struct ciss_request		*cr;
+    struct ciss_command		*cc;
+    struct ciss_error_info	*ce;
+    int				i;
+
+    CISS_TL_SIMPLE_DISABLE_INTERRUPTS(sc);
+    pci_disable_busmaster(sc->ciss_dev);
+    sc->ciss_flags &= ~CISS_FLAG_RUNNING;
+
+    for (i = 1; i < sc->ciss_max_requests; i++) {
+	cr = &sc->ciss_request[i];
+	if ((cr->cr_flags & CISS_REQ_BUSY) == 0)
+	    continue;
+
+	cc = CISS_FIND_COMMAND(cr);
+	ce = (struct ciss_error_info *)&(cc->sg[0]);
+	ce->command_status = CISS_CMD_STATUS_HARDWARE_ERROR;
+	ciss_enqueue_complete(cr, &qh);
+    }
+
+    for (;;) {
+	if ((cr = ciss_dequeue_complete(sc, &qh)) == NULL)
+	    break;
+    
+	/*
+	 * If the request has a callback, invoke it.
+	 */
+	if (cr->cr_complete != NULL) {
+	    cr->cr_complete(cr);
+	    continue;
+	}
+
+	/*
+	 * If someone is sleeping on this request, wake them up.
+	 */
+	if (cr->cr_flags & CISS_REQ_SLEEP) {
+	    cr->cr_flags &= ~CISS_REQ_SLEEP;
+	    wakeup(cr);
+	    continue;
+	}
+    }
 }
 
 /************************************************************************
@@ -3011,7 +3539,11 @@ ciss_notify_event(struct ciss_softc *sc)
      * structure.
      */
     if (cr->cr_data == NULL) {
-	cr->cr_data = kmalloc(CISS_NOTIFY_DATA_SIZE, CISS_MALLOC_CLASS, M_INTWAIT);
+	if ((cr->cr_data = kmalloc(CISS_NOTIFY_DATA_SIZE, CISS_MALLOC_CLASS, M_NOWAIT)) == NULL) {
+	    debug(0, "can't get notify event request buffer");
+	    error = ENOMEM;
+	    goto out;
+	}
 	cr->cr_length = CISS_NOTIFY_DATA_SIZE;
     }
 
@@ -3165,7 +3697,11 @@ ciss_notify_abort(struct ciss_softc *sc)
 	goto out;
 
     /* get a buffer for the result */
-    cr->cr_data = kmalloc(CISS_NOTIFY_DATA_SIZE, CISS_MALLOC_CLASS, M_INTWAIT);
+    if ((cr->cr_data = kmalloc(CISS_NOTIFY_DATA_SIZE, CISS_MALLOC_CLASS, M_NOWAIT)) == NULL) {
+	debug(0, "can't get notify event request buffer");
+	error = ENOMEM;
+	goto out;
+    }
     cr->cr_length = CISS_NOTIFY_DATA_SIZE;
 
     /* build the CDB */
@@ -3490,7 +4026,7 @@ ciss_notify_physical(struct ciss_softc *sc, struct ciss_notify *cn)
 static void
 ciss_notify_hotplug(struct ciss_softc *sc, struct ciss_notify *cn)
 {
-    struct ciss_lun_report *cll;
+    struct ciss_lun_report *cll = NULL;
     int bus, target;
 
     switch (cn->subclass) {
@@ -3500,13 +4036,13 @@ ciss_notify_hotplug(struct ciss_softc *sc, struct ciss_notify *cn)
 	target =
 	    CISS_BIG_MAP_TARGET(sc, cn->data.drive.big_physical_drive_number);
 
-	crit_enter();
 	if (cn->detail == 0) {
 	    /*
 	     * Mark the device offline so that it'll start producing selection
 	     * timeouts to the upper layer.
 	     */
-	    sc->ciss_physical[bus][target].cp_online = 0;
+	    if ((bus >= 0) && (target >= 0))
+		sc->ciss_physical[bus][target].cp_online = 0;
 	} else {
 	    /*
 	     * Rescan the physical lun list for new items
@@ -3519,13 +4055,15 @@ ciss_notify_hotplug(struct ciss_softc *sc, struct ciss_notify *cn)
 	    }
 	    ciss_filter_physical(sc, cll);
 	}
-	crit_exit();
 	break;
 
     default:
 	ciss_printf(sc, "Unknown hotplug event %d\n", cn->subclass);
 	return;
     }
+
+    if (cll != NULL)
+	kfree(cll, CISS_MALLOC_CLASS);
 }
 
 /************************************************************************
@@ -3541,18 +4079,18 @@ ciss_notify_thread(void *arg)
 
     sc = (struct ciss_softc *)arg;
 
-    crit_enter();
     for (;;) {
-	if (TAILQ_EMPTY(&sc->ciss_notify) != 0 &&
+	crit_enter();
+	if (STAILQ_EMPTY(&sc->ciss_notify) != 0 &&
 	    (sc->ciss_flags & CISS_FLAG_THREAD_SHUT) == 0) {
 	    tsleep(&sc->ciss_notify, 0, "idle", 0);
 	}
+	crit_exit();
 
 	if (sc->ciss_flags & CISS_FLAG_THREAD_SHUT)
 	    break;
 
 	cr = ciss_dequeue_notify(sc);
-	crit_exit();
 
 	if (cr == NULL)
 		panic("cr null");
@@ -3572,11 +4110,9 @@ ciss_notify_thread(void *arg)
 
 	ciss_release_request(cr);
 
-	crit_enter();
     }
     sc->ciss_notify_thread = NULL;
     wakeup(&sc->ciss_notify_thread);
-    crit_exit();
 
     kthread_exit();
 }
@@ -3858,7 +4394,7 @@ ciss_name_ldrive_org(int org)
     case CISS_LDRIVE_RAIDADG:
 	return("RAID ADG");
     }
-    return("unknown");
+    return("unkown");
 }
 
 /************************************************************************
@@ -3913,7 +4449,9 @@ ciss_open(struct dev_open_args *ap)
 
     /* we might want to veto if someone already has us open */
 
+    lockmgr(&sc->ciss_lock, LK_EXCLUSIVE);
     sc->ciss_flags |= CISS_FLAG_CONTROL_OPEN;
+    lockmgr(&sc->ciss_lock, LK_RELEASE);
     return(0);
 }
 
@@ -3930,7 +4468,9 @@ ciss_close(struct dev_close_args *ap)
 
     sc = (struct ciss_softc *)dev->si_drv1;
 
+    lockmgr(&sc->ciss_lock, LK_EXCLUSIVE);
     sc->ciss_flags &= ~CISS_FLAG_CONTROL_OPEN;
+    lockmgr(&sc->ciss_lock, LK_RELEASE);
     return (0);
 }
 
@@ -3944,18 +4484,43 @@ static int
 ciss_ioctl(struct dev_ioctl_args *ap)
 {
     cdev_t dev = ap->a_head.a_dev;
+    caddr_t addr = ap->a_data;
     struct ciss_softc		*sc;
+    IOCTL_Command_struct	*ioc	= (IOCTL_Command_struct *)addr;
+#ifdef __amd64__
+    IOCTL_Command_struct32	*ioc32	= (IOCTL_Command_struct32 *)addr;
+    IOCTL_Command_struct	ioc_swab;
+#endif
     int				error;
 
     debug_called(1);
 
     sc = (struct ciss_softc *)dev->si_drv1;
     error = 0;
+    lockmgr(&sc->ciss_lock, LK_EXCLUSIVE);
 
     switch(ap->a_cmd) {
+    case CCISS_GETQSTATS:
+    {
+	union ciss_statrequest *cr = (union ciss_statrequest *)addr;
+
+	switch (cr->cs_item) {
+	case CISSQ_FREE:
+	case CISSQ_NOTIFY:
+	    bcopy(&sc->ciss_qstat[cr->cs_item], &cr->cs_qstat,
+		sizeof(struct ciss_qstat));
+	    break;
+	default:
+	    error = ENOIOCTL;
+	    break;
+	}
+
+	break;
+    }
+
     case CCISS_GETPCIINFO:
     {
-	cciss_pci_info_struct	*pis = (cciss_pci_info_struct *)ap->a_data;
+	cciss_pci_info_struct	*pis = (cciss_pci_info_struct *)addr;
 
 	pis->bus = pci_get_bus(sc->ciss_dev);
 	pis->dev_fn = pci_get_slot(sc->ciss_dev);
@@ -3966,7 +4531,7 @@ ciss_ioctl(struct dev_ioctl_args *ap)
 
     case CCISS_GETINTINFO:
     {
-	cciss_coalint_struct	*cis = (cciss_coalint_struct *)ap->a_data;
+	cciss_coalint_struct	*cis = (cciss_coalint_struct *)addr;
 
 	cis->delay = sc->ciss_cfg->interrupt_coalesce_delay;
 	cis->count = sc->ciss_cfg->interrupt_coalesce_count;
@@ -3976,7 +4541,7 @@ ciss_ioctl(struct dev_ioctl_args *ap)
 
     case CCISS_SETINTINFO:
     {
-	cciss_coalint_struct	*cis = (cciss_coalint_struct *)ap->a_data;
+	cciss_coalint_struct	*cis = (cciss_coalint_struct *)addr;
 
 	if ((cis->delay == 0) && (cis->count == 0)) {
 	    error = EINVAL;
@@ -3998,32 +4563,32 @@ ciss_ioctl(struct dev_ioctl_args *ap)
     }
 
     case CCISS_GETNODENAME:
-	bcopy(sc->ciss_cfg->server_name, (NodeName_type *)ap->a_data,
+	bcopy(sc->ciss_cfg->server_name, (NodeName_type *)addr,
 	      sizeof(NodeName_type));
 	break;
 
     case CCISS_SETNODENAME:
-	bcopy((NodeName_type *)ap->a_data, sc->ciss_cfg->server_name,
+	bcopy((NodeName_type *)addr, sc->ciss_cfg->server_name,
 	      sizeof(NodeName_type));
 	if (ciss_update_config(sc))
 	    error = EIO;
 	break;
 
     case CCISS_GETHEARTBEAT:
-	*(Heartbeat_type *)ap->a_data = sc->ciss_cfg->heartbeat;
+	*(Heartbeat_type *)addr = sc->ciss_cfg->heartbeat;
 	break;
 
     case CCISS_GETBUSTYPES:
-	*(BusTypes_type *)ap->a_data = sc->ciss_cfg->bus_types;
+	*(BusTypes_type *)addr = sc->ciss_cfg->bus_types;
 	break;
 
     case CCISS_GETFIRMVER:
-	bcopy(sc->ciss_id->running_firmware_revision, (FirmwareVer_type *)ap->a_data,
+	bcopy(sc->ciss_id->running_firmware_revision, (FirmwareVer_type *)addr,
 	      sizeof(FirmwareVer_type));
 	break;
 
     case CCISS_GETDRIVERVER:
-	*(DriverVer_type *)ap->a_data = CISS_DRIVER_VERSION;
+	*(DriverVer_type *)addr = CISS_DRIVER_VERSION;
 	break;
 
     case CCISS_REVALIDVOLS:
@@ -4036,12 +4601,23 @@ ciss_ioctl(struct dev_ioctl_args *ap)
 	 */
 	break;
 
+#ifdef __amd64__
+    case CCISS_PASSTHRU32:
+	ioc_swab.LUN_info	= ioc32->LUN_info;
+	ioc_swab.Request	= ioc32->Request;
+	ioc_swab.error_info	= ioc32->error_info;
+	ioc_swab.buf_size	= ioc32->buf_size;
+	ioc_swab.buf		= (u_int8_t *)(uintptr_t)ioc32->buf;
+	ioc			= &ioc_swab;
+	/* FALLTHROUGH */
+#endif
+
     case CCISS_PASSTHRU:
-	error = ciss_user_command(sc, (IOCTL_Command_struct *)ap->a_data);
+	error = ciss_user_command(sc, ioc);
 	break;
 
     default:
-	debug(0, "unknown ioctl 0x%lx", ap->a_cmd);
+	debug(0, "unknown ioctl 0x%lx", cmd);
 
 	debug(1, "CCISS_GETPCIINFO:   0x%lx", CCISS_GETPCIINFO);
 	debug(1, "CCISS_GETINTINFO:   0x%lx", CCISS_GETINTINFO);
@@ -4059,5 +4635,6 @@ ciss_ioctl(struct dev_ioctl_args *ap)
 	break;
     }
 
+    lockmgr(&sc->ciss_lock, LK_RELEASE);
     return(error);
 }
diff --git a/sys/dev/raid/ciss/cissio.h b/sys/dev/raid/ciss/cissio.h
index 1aba2ce..74268c8 100644
--- a/sys/dev/raid/ciss/cissio.h
+++ b/sys/dev/raid/ciss/cissio.h
@@ -22,9 +22,6 @@
  * 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/ciss/cissio.h,v 1.1.2.1 2001/12/12 06:38:16 ps Exp $
- *	$DragonFly: src/sys/dev/raid/ciss/cissio.h,v 1.4 2007/09/15 13:18:40 swildner Exp $
  */
 
 /*
@@ -128,20 +125,20 @@ typedef struct {
     u_int32_t		Bus:6;
     u_int32_t		Mode:2;
     SCSI3Addr_struct	Target[2];
-} PhysDevAddr_struct;
+} __packed PhysDevAddr_struct;
   
 typedef struct {
     u_int32_t		VolId:30;
     u_int32_t		Mode:2;
     u_int8_t		reserved[4];
-} LogDevAddr_struct;
+} __packed LogDevAddr_struct;
 
 typedef union {
     u_int8_t		LunAddrBytes[8];
     SCSI3Addr_struct	SCSI3Lun[4];
     PhysDevAddr_struct	PhysDev;
     LogDevAddr_struct	LogDev;
-} LUNAddr_struct;
+} __packed LUNAddr_struct;
 
 typedef struct {
     u_int8_t	CDBLen;
@@ -152,7 +149,7 @@ typedef struct {
     } __packed Type;
     u_int16_t	Timeout;
     u_int8_t	CDB[16];
-} RequestBlock_struct;
+} __packed RequestBlock_struct;
 
 typedef union {
     struct {
@@ -166,7 +163,7 @@ typedef union {
 	u_int8_t	offense_num;
 	u_int32_t	offense_value;
     } __packed Invalid_Cmd;
-} MoreErrInfo_struct;
+} __packed MoreErrInfo_struct;
 
 typedef struct {
     u_int8_t		ScsiStatus;
@@ -175,7 +172,7 @@ typedef struct {
     u_int32_t		ResidualCnt;
     MoreErrInfo_struct	MoreErrInfo;
     u_int8_t		SenseInfo[SENSEINFOBYTES];
-} ErrorInfo_struct;
+} __packed ErrorInfo_struct;
 
 typedef struct {
     LUNAddr_struct	LUN_info;	/* 8 */
@@ -183,7 +180,25 @@ typedef struct {
     ErrorInfo_struct	error_info;	/* 48 */
     u_int16_t		buf_size;	/* 2 */
     u_int8_t		*buf;		/* 4 */
-} IOCTL_Command_struct;
+} __packed IOCTL_Command_struct;
+
+/************************************************************************
+ * Command queue statistics
+ */
+
+#define CISSQ_FREE	0
+#define CISSQ_NOTIFY	1
+#define CISSQ_COUNT	2
+
+struct ciss_qstat {
+    uint32_t		q_length;
+    uint32_t		q_max;
+};
+
+union ciss_statrequest {
+    uint32_t		cs_item;
+    struct ciss_qstat	cs_qstat;
+};
 
 /*
  * Note that we'd normally pass the struct in directly, but
@@ -200,5 +215,6 @@ typedef struct {
 #define CCISS_GETDRIVERVER	_IOR ('C', 208, DriverVer_type)
 #define CCISS_REVALIDVOLS	_IO  ('C', 209)
 #define CCISS_PASSTHRU		_IOWR ('C', 210, IOCTL_Command_struct)
+#define CCISS_GETQSTATS		_IOWR ('C', 211, union ciss_statrequest)
 
 #pragma pack()
diff --git a/sys/dev/raid/ciss/cissreg.h b/sys/dev/raid/ciss/cissreg.h
index 3c0fbb9..10edfbb 100644
--- a/sys/dev/raid/ciss/cissreg.h
+++ b/sys/dev/raid/ciss/cissreg.h
@@ -22,9 +22,6 @@
  * 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/ciss/cissreg.h,v 1.1.2.9 2005/12/31 06:28:57 ps Exp $
- *	$DragonFly: src/sys/dev/raid/ciss/cissreg.h,v 1.2 2003/06/17 04:28:23 dillon Exp $
  */
 
 /*
@@ -76,7 +73,7 @@ struct ciss_header
 #define CISS_HDR_HOST_TAG_ERROR	(1<<1)
     u_int32_t	host_tag_zeroes;	/* tag is 64 bits, but interface only supports 32 */
     union ciss_device_address address;
-} __attribute__ ((packed));
+} __packed;
 
 struct ciss_cdb
 {
@@ -97,13 +94,13 @@ struct ciss_cdb
     u_int16_t	timeout;		/* seconds */
 #define CISS_CDB_BUFFER_SIZE	16
     u_int8_t	cdb[CISS_CDB_BUFFER_SIZE];
-} __attribute__ ((packed));
+} __packed;
 
 struct ciss_error_info_pointer
 {
     u_int64_t	error_info_address;	/* points to ciss_error_info structure */
     u_int32_t	error_info_length;
-} __attribute__ ((packed));
+} __packed;
 
 struct ciss_error_info
 {
@@ -139,16 +136,16 @@ struct ciss_error_info
 	    u_int8_t	res1[3];
 	    u_int8_t	type;
 	    u_int32_t	error_info;
-	} common_info __attribute__ ((packed));
+	} __packed common_info;
 	struct {
 	    u_int8_t	res1[2];
 	    u_int8_t	offense_size;
 	    u_int8_t	offense_offset;
 	    u_int32_t	offense_value;
-	} invalid_command __attribute__ ((packed));
+	} __packed invalid_command;
     } additional_error_info;
     u_int8_t	sense_info[0];
-} __attribute__ ((packed));
+} __packed;
 
 struct ciss_sg_entry
 {
@@ -157,7 +154,7 @@ struct ciss_sg_entry
     u_int32_t	length;
     u_int32_t	:31;
     u_int32_t	extension:1;		/* address points to another s/g chain */
-} __attribute__ ((packed));
+} __packed;
 
 struct ciss_command
 {
@@ -165,7 +162,7 @@ struct ciss_command
     struct ciss_cdb			cdb;
     struct ciss_error_info_pointer	error_info;
     struct ciss_sg_entry		sg[0];
-} __attribute__ ((packed));
+} __packed;
 
 #define CISS_OPCODE_REPORT_LOGICAL_LUNS		0xc2
 #define CISS_OPCODE_REPORT_PHYSICAL_LUNS	0xc3
@@ -175,7 +172,7 @@ struct ciss_lun_report
     u_int32_t	list_size;		/* big-endian */
     u_int32_t	:32;
     union ciss_device_address lun[0];
-} __attribute__ ((packed));
+} __packed;
 
 #define	CISS_VPD_LOGICAL_DRIVE_GEOMETRY		0xc1
 struct ciss_ldrive_geometry
@@ -199,7 +196,7 @@ struct ciss_report_cdb
     u_int32_t	length;			/* big-endian */
     u_int8_t	:8;
     u_int8_t	control;
-} __attribute__ ((packed));
+} __packed;
 
 /*
  * Note that it's not clear whether we have to set the detail field to
@@ -233,7 +230,7 @@ struct ciss_message_cdb
     u_int16_t	:16;
     u_int32_t	abort_tag;					/* XXX endianness? */
     u_int8_t	reserved[8];
-} __attribute__ ((packed));
+} __packed;
 
 /*
  * CISS vendor-specific commands/messages.
@@ -263,7 +260,7 @@ struct ciss_notify_cdb
     u_int32_t	length;			/* must be 512, little-endian */
 #define CISS_NOTIFY_DATA_SIZE	512
     u_int8_t	control;
-} __attribute__ ((packed));
+} __packed;
 
 #define CISS_NOTIFY_NOTIFIER		0
 #define CISS_NOTIFY_NOTIFIER_STATUS		0
@@ -313,19 +310,19 @@ struct ciss_notify_drive
     u_int8_t	spare_drive_flag;
     u_int8_t	big_physical_drive_number;
     u_int8_t	enclosure_bay_number;
-} __attribute__ ((packed));
+} __packed;
 
 struct ciss_notify_locator
 {
     u_int16_t	port;
     u_int16_t	id;
     u_int16_t	box;
-} __attribute__ ((packed));
+} __packed;
 
 struct ciss_notify_redundant_controller
 {
     u_int16_t	slot;
-} __attribute__ ((packed));
+} __packed;
 
 struct ciss_notify_logical_status
 {
@@ -333,8 +330,8 @@ struct ciss_notify_logical_status
     u_int8_t	previous_state;
     u_int8_t	new_state;
     u_int8_t	spare_state;
-} __attribute__ ((packed));
- 
+} __packed;
+
 struct ciss_notify_rebuild_aborted
 {
     u_int16_t	logical_drive;
@@ -342,7 +339,7 @@ struct ciss_notify_rebuild_aborted
     u_int8_t	error_drive;
     u_int8_t	big_replacement_drive;
     u_int8_t	big_error_drive;
-} __attribute__ ((packed));
+} __packed;
 
 struct ciss_notify_io_error
 {
@@ -353,12 +350,12 @@ struct ciss_notify_io_error
     u_int8_t	failure_bus;
     u_int8_t	failure_drive;
     u_int64_t	big_lba;
-} __attribute__ ((packed));
+} __packed;
 
 struct ciss_notify_consistency_completed
 {
     u_int16_t	logical_drive;
-} __attribute__ ((packed));
+} __packed;
 
 struct ciss_notify
 {
@@ -385,7 +382,7 @@ struct ciss_notify
     u_int16_t	pre_power_up_time;
     union ciss_device_address	device;
     /* XXX pads to 512 bytes */
-} __attribute__ ((packed));
+} __packed;
 
 /*
  * CISS config table, which describes the controller's
@@ -400,6 +397,7 @@ struct ciss_config_table
     u_int32_t	supported_methods;
 #define CISS_TRANSPORT_METHOD_READY	(1<<0)
 #define CISS_TRANSPORT_METHOD_SIMPLE	(1<<1)
+#define CISS_TRANSPORT_METHOD_PERF	(1<<2)
     u_int32_t	active_method;
     u_int32_t	requested_method;
     u_int32_t	command_physlimit;
@@ -425,7 +423,31 @@ struct ciss_config_table
 #define CISS_DRIVER_DAUGHTER_ATTACHED		(1<<8)
 #define CISS_DRIVER_SCSI_PREFETCH		(1<<9)
     u_int32_t	max_sg_length;		/* 31 in older firmware */
-} __attribute__ ((packed));
+} __packed;
+
+/*
+ * Configuration table for the Performant transport.  Only 4 request queues
+ * are mentioned in this table, though apparently up to 256 can exist.
+ */
+struct ciss_perf_config {
+    uint32_t	fetch_count[8];
+#define CISS_SG_FETCH_MAX	0
+#define CISS_SG_FETCH_1		1
+#define CISS_SG_FETCH_2		2
+#define CISS_SG_FETCH_4		3
+#define CISS_SG_FETCH_8		4
+#define CISS_SG_FETCH_16	5
+#define CISS_SG_FETCH_32	6
+#define CISS_SG_FETCH_NONE	7
+    uint32_t	rq_size;
+    uint32_t	rq_count;
+    uint32_t	rq_bank_lo;
+    uint32_t	rq_bank_hi;
+    struct {
+	uint32_t	rq_addr_lo;
+	uint32_t	rq_addr_hi;
+    } __packed rq[4];
+} __packed;
 
 /*
  * In a flagrant violation of what CISS seems to be meant to be about,
@@ -448,6 +470,7 @@ struct ciss_config_table
 #define CISS_BMIC_ID_PDRIVE		0x15
 #define CISS_BMIC_BLINK_PDRIVE		0x16
 #define CISS_BMIC_SENSE_BLINK_PDRIVE	0x17
+#define CISS_BMIC_SOFT_RESET		0x40
 #define CISS_BMIC_FLUSH_CACHE		0xc2
 #define CISS_BMIC_ACCEPT_MEDIA		0xe0
 
@@ -500,7 +523,7 @@ struct ciss_bmic_cdb {
     u_int8_t	bmic_opcode;
     u_int16_t	size;			/* big-endian */
     u_int8_t	res2;
-} __attribute__ ((packed));
+} __packed;
 
 /*
  * BMIC command command/return structures.
@@ -525,7 +548,7 @@ struct ciss_bmic_id_ldrive {
     char	logical_drive_label[64];
     u_int64_t	big_blocks_available;
     u_int8_t	res3[410];
-} __attribute__ ((packed));
+} __packed;
 
 /* CISS_BMIC_ID_LSTATUS */
 struct ciss_bmic_id_lstatus {
@@ -572,7 +595,7 @@ struct ciss_bmic_id_lstatus {
     u_int8_t	drive_rebuilding;
     u_int64_t	big_blocks_to_recover;
     u_int8_t	res4[28];
-} __attribute__ ((packed));
+} __packed;
 
 /* CISS_BMIC_ID_CTLR */
 struct ciss_bmic_id_table {
@@ -601,7 +624,7 @@ struct ciss_bmic_id_table {
     u_int8_t	big_drive_present_map[CISS_BIG_MAP_ENTRIES / 8];
     u_int8_t	big_external_drive_present_map[CISS_BIG_MAP_ENTRIES / 8];
     u_int8_t	big_non_disk_map[CISS_BIG_MAP_ENTRIES / 8];
-} __attribute__ ((packed));
+} __packed;
 
 /* CISS_BMIC_ID_PDRIVE */
 struct ciss_bmic_id_pdrive {
@@ -642,7 +665,7 @@ struct ciss_bmic_id_pdrive {
     u_int16_t	rpm;
     u_int8_t	drive_type;
     u_int8_t	res6[393];
-} __attribute__ ((packed));
+} __packed;
 
 /* CISS_BMIC_BLINK_PDRIVE */
 /* CISS_BMIC_SENSE_BLINK_PDRIVE */
@@ -653,7 +676,7 @@ struct ciss_bmic_blink_pdrive {
 #define CISS_BMIC_BLINK_ALL	1
 #define CISS_BMIC_BLINK_TIMED	2
     u_int8_t	res2[248];
-} __attribute__ ((packed));
+} __packed;
 
 /* CISS_BMIC_FLUSH_CACHE */
 struct ciss_bmic_flush_cache {
@@ -661,7 +684,7 @@ struct ciss_bmic_flush_cache {
 #define CISS_BMIC_FLUSH_AND_ENABLE	0
 #define CISS_BMIC_FLUSH_AND_DISABLE	1
     u_int8_t	res1[510];
-} __attribute__ ((packed));
+} __packed;
 
 #ifdef _KERNEL
 /*
@@ -685,6 +708,10 @@ struct ciss_bmic_flush_cache {
 #define CISS_TL_SIMPLE_OPQ	0x44	/* outbound post queue */
 #define CISS_TL_SIMPLE_OPQ_EMPTY	(~(u_int32_t)0)
 
+#define CISS_TL_SIMPLE_OSR	0x9c	/* outbound status register */
+#define CISS_TL_SIMPLE_ODC	0xa0	/* outbound doorbell clear register */
+#define CISS_TL_SIMPLE_ODC_CLEAR	(0x1)
+
 #define CISS_TL_SIMPLE_CFG_BAR	0xb4	/* should be 0x14 */
 #define CISS_TL_SIMPLE_CFG_OFF	0xb8	/* offset in BAR at which config table is located */
 
@@ -699,10 +726,16 @@ struct ciss_bmic_flush_cache {
 #define CISS_TL_SIMPLE_POST_CMD(sc, phys)	CISS_TL_SIMPLE_WRITE(sc, CISS_TL_SIMPLE_IPQ, phys)
 #define CISS_TL_SIMPLE_FETCH_CMD(sc)		CISS_TL_SIMPLE_READ(sc, CISS_TL_SIMPLE_OPQ)
 
-/*
- * XXX documentation conflicts with the Linux driver as to whether setting or clearing
- *     bits masks interrupts
- */
+#define CISS_TL_PERF_INTR_OPQ	(CISS_TL_SIMPLE_INTR_OPQ_SA5 | CISS_TL_SIMPLE_INTR_OPQ_SA5B)
+#define CISS_TL_PERF_INTR_MSI	0x01
+
+#define CISS_TL_PERF_POST_CMD(sc, cr)		CISS_TL_SIMPLE_WRITE(sc, CISS_TL_SIMPLE_IPQ, CISS_FIND_COMMANDPHYS(cr) | (cr)->cr_sg_tag)
+#define CISS_TL_PERF_FLUSH_INT(sc)		CISS_TL_SIMPLE_READ(sc, CISS_TL_SIMPLE_OSR)
+#define CISS_TL_PERF_CLEAR_INT(sc)		CISS_TL_SIMPLE_WRITE(sc, CISS_TL_SIMPLE_ODC, CISS_TL_SIMPLE_ODC_CLEAR)
+#define CISS_CYCLE_MASK		0x00000001
+
+#define CISS_MSI_COUNT	4
+
 #define CISS_TL_SIMPLE_DISABLE_INTERRUPTS(sc) \
 	CISS_TL_SIMPLE_WRITE(sc, CISS_TL_SIMPLE_IMR, \
 			     CISS_TL_SIMPLE_READ(sc, CISS_TL_SIMPLE_IMR) | (sc)->ciss_interrupt_mask)
@@ -710,7 +743,5 @@ struct ciss_bmic_flush_cache {
 	CISS_TL_SIMPLE_WRITE(sc, CISS_TL_SIMPLE_IMR, \
 			     CISS_TL_SIMPLE_READ(sc, CISS_TL_SIMPLE_IMR) & ~(sc)->ciss_interrupt_mask)
 
-#define CISS_TL_SIMPLE_OPQ_INTERRUPT(sc) \
-	(CISS_TL_SIMPLE_READ(sc, CISS_TL_SIMPLE_ISR) & (sc)->ciss_interrupt_mask)
 
 #endif /* _KERNEL */
diff --git a/sys/dev/raid/ciss/cissvar.h b/sys/dev/raid/ciss/cissvar.h
index 1ccd863..08e84af 100644
--- a/sys/dev/raid/ciss/cissvar.h
+++ b/sys/dev/raid/ciss/cissvar.h
@@ -22,9 +22,6 @@
  * 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/ciss/cissvar.h,v 1.3.2.4 2004/06/23 20:48:36 scottl Exp $
- *	$DragonFly: src/sys/dev/raid/ciss/cissvar.h,v 1.7 2006/12/22 23:26:23 swildner Exp $
  */
 
 #include <sys/thread2.h>
@@ -33,6 +30,8 @@
  * CISS adapter driver datastructures
  */
 
+typedef STAILQ_HEAD(, ciss_request)	cr_qhead_t;
+
 /************************************************************************
  * Tunable parameters
  */
@@ -64,7 +63,7 @@
  *
  * If the delay is set to 0, interrupts are delivered immediately.
  */
-#define CISS_INTERRUPT_COALESCE_DELAY	1000
+#define CISS_INTERRUPT_COALESCE_DELAY	0
 #define CISS_INTERRUPT_COALESCE_COUNT	16
 
 /*
@@ -75,30 +74,6 @@
 #define CISS_HEARTBEAT_RATE		10
 
 /************************************************************************
- * Compatibility with older versions of FreeBSD
- */
-#if defined(__FreeBSD__) && __FreeBSD_version < 440001
-#warning testing old-FreeBSD compat
-typedef struct proc	d_thread_t;
-#endif
-
-/************************************************************************
- * Command queue statistics
- */
-
-#define CISSQ_FREE	0
-#define CISSQ_BUSY	1
-#define CISSQ_COMPLETE	2
-#define CISSQ_NOTIFY	3
-#define CISSQ_COUNT	4
-
-struct ciss_qstat
-{
-    u_int32_t	q_length;
-    u_int32_t	q_max;
-};
-
-/************************************************************************
  * Driver version.  Only really significant to the ACU interface.
  */
 #define CISS_DRIVER_VERSION	20011201
@@ -113,7 +88,7 @@ struct ciss_qstat
  */
 struct ciss_request
 {
-    TAILQ_ENTRY(ciss_request)	cr_link;
+    STAILQ_ENTRY(ciss_request)	cr_link;
     int				cr_onq;		/* which queue we are on */
 
     struct ciss_softc		*cr_sc;		/* controller softc */
@@ -127,9 +102,19 @@ struct ciss_request
 #define CISS_REQ_POLL		(1<<2)		/* submitter polling */
 #define CISS_REQ_DATAOUT	(1<<3)		/* data host->adapter */
 #define CISS_REQ_DATAIN		(1<<4)		/* data adapter->host */
+#define CISS_REQ_BUSY		(1<<5)		/* controller has req */
 
     void			(* cr_complete)(struct ciss_request *);
     void			*cr_private;
+    int				cr_sg_tag;
+#define CISS_SG_MAX		((CISS_SG_FETCH_MAX << 1) | 0x1)
+#define CISS_SG_1		((CISS_SG_FETCH_1 << 1) | 0x01)
+#define CISS_SG_2		((CISS_SG_FETCH_2 << 1) | 0x01)
+#define CISS_SG_4		((CISS_SG_FETCH_4 << 1) | 0x01)
+#define CISS_SG_8		((CISS_SG_FETCH_8 << 1) | 0x01)
+#define CISS_SG_16		((CISS_SG_FETCH_16 << 1) | 0x01)
+#define CISS_SG_32		((CISS_SG_FETCH_32 << 1) | 0x01)
+#define CISS_SG_NONE		((CISS_SG_FETCH_NONE << 1) | 0x01)
 };
 
 /*
@@ -144,10 +129,13 @@ struct ciss_request
  * too small.
  */
 
-#define CISS_COMMAND_ALLOC_SIZE		1024	/* XXX tune to get sensible s/g list length */
+#define CISS_COMMAND_ALLOC_SIZE		512	/* XXX tune to get sensible s/g list length */
 #define CISS_COMMAND_SG_LENGTH	((CISS_COMMAND_ALLOC_SIZE - sizeof(struct ciss_command)) \
 				 / sizeof(struct ciss_sg_entry))
 
+/* XXX Prep for increasing max i/o */
+#define CISS_MAX_SG_ELEMENTS   17
+
 /*
  * Per-logical-drive data.
  */
@@ -192,7 +180,7 @@ struct ciss_softc
 {
     /* bus connections */
     device_t			ciss_dev;		/* bus attachment */
-    cdev_t			ciss_dev_t;		/* control device */
+    struct cdev *ciss_dev_t;		/* control device */
 
     struct resource		*ciss_regs_resource;	/* register interface window */
     int				ciss_regs_rid;		/* resource ID */
@@ -202,12 +190,14 @@ struct ciss_softc
     struct resource		*ciss_cfg_resource;	/* config struct interface window */
     int				ciss_cfg_rid;		/* resource ID */
     struct ciss_config_table	*ciss_cfg;		/* config table in adapter memory */
+    struct ciss_perf_config	*ciss_perf;		/* config table for the performant */
     struct ciss_bmic_id_table	*ciss_id;		/* ID table in host memory */
     u_int32_t			ciss_heartbeat;		/* last heartbeat value */
     int				ciss_heart_attack;	/* number of times we have seen this value */
 
+    int				ciss_msi;
     struct resource		*ciss_irq_resource;	/* interrupt */
-    int				ciss_irq_rid;		/* resource ID */
+    int				ciss_irq_rid[CISS_MSI_COUNT];		/* resource ID */
     void			*ciss_intr;		/* interrupt handle */
 
     bus_dma_tag_t		ciss_parent_dmat;	/* parent DMA tag */
@@ -215,21 +205,27 @@ struct ciss_softc
 
     u_int32_t			ciss_interrupt_mask;	/* controller interrupt mask bits */
 
+    uint64_t			*ciss_reply;
+    int				ciss_cycle;
+    int				ciss_rqidx;
+    bus_dma_tag_t		ciss_reply_dmat;
+    bus_dmamap_t		ciss_reply_map;
+    uint32_t			ciss_reply_phys;
+
     int				ciss_max_requests;
     struct ciss_request		ciss_request[CISS_MAX_REQUESTS];	/* requests */
     void			*ciss_command;		/* command structures */
     bus_dma_tag_t		ciss_command_dmat;	/* command DMA tag */
     bus_dmamap_t		ciss_command_map;	/* command DMA map */
     u_int32_t			ciss_command_phys;	/* command array base address */
-    TAILQ_HEAD(,ciss_request)	ciss_free;		/* requests available for reuse */
-    TAILQ_HEAD(,ciss_request)	ciss_busy;		/* requests in the adapter */
-    TAILQ_HEAD(,ciss_request)	ciss_complete;		/* requests which have been returned by the adapter */
-    TAILQ_HEAD(,ciss_request)	ciss_notify;		/* requests which are defered for processing */
-    struct thread		*ciss_notify_thread;
+    cr_qhead_t			ciss_free;		/* requests available for reuse */
+    cr_qhead_t			ciss_notify;		/* requests which are defered for processing */
+    struct proc			*ciss_notify_thread;
 
     struct callout		ciss_periodic;		/* periodic event handling */
     struct ciss_request		*ciss_periodic_notify;	/* notify callback request */
 
+    struct lock			ciss_lock;
     struct ciss_ldrive		**ciss_logical;
     struct ciss_pdrive		**ciss_physical;
     union ciss_device_address	*ciss_controllers;	/* controller address */
@@ -240,6 +236,8 @@ struct ciss_softc
     struct cam_devq		*ciss_cam_devq;
     struct cam_sim		**ciss_cam_sim;
 
+    int				ciss_soft_reset;
+
     int				ciss_flags;
 #define CISS_FLAG_NOTIFY_OK	(1<<0)		/* notify command running OK */
 #define CISS_FLAG_CONTROL_OPEN	(1<<1)		/* control device is open */
@@ -251,6 +249,10 @@ struct ciss_softc
 #define CISS_FLAG_THREAD_SHUT	(1<<20)		/* shutdown the kthread */
 
     struct ciss_qstat		ciss_qstat[CISSQ_COUNT];	/* queue statistics */
+
+    /* sysctl tree glue */
+    struct sysctl_ctx_list	sysctl_ctx;
+    struct sysctl_oid		*sysctl_tree;
 };
 
 /*
@@ -287,11 +289,11 @@ struct ciss_softc
 	do {								\
 	    if (level <= CISS_DEBUG) kprintf("%s: called\n", __func__);	\
 	} while(0)
-# define debug_struct(s)		kprintf("  SIZE %s: %d\n", #s, sizeof(struct s))
-# define debug_union(s)			kprintf("  SIZE %s: %d\n", #s, sizeof(union s))
-# define debug_type(s)			kprintf("  SIZE %s: %d\n", #s, sizeof(s))
+# define debug_struct(s)		kprintf("  SIZE %s: %zu\n", #s, sizeof(struct s))
+# define debug_union(s)			kprintf("  SIZE %s: %zu\n", #s, sizeof(union s))
+# define debug_type(s)			kprintf("  SIZE %s: %zu\n", #s, sizeof(s))
 # define debug_field(s, f)		kprintf("  OFFSET %s.%s: %d\n", #s, #f, ((int)&(((struct s *)0)->f)))
-# define debug_const(c)			kprintf("  CONST %s %d/0x%x\n", #c, c, c);
+# define debug_const(c)			kprintf("  CONST %s %jd/0x%jx\n", #c, (intmax_t)c, (intmax_t)c);
 #else
 # define debug(level, fmt, args...)
 # define debug_called(level)
@@ -329,14 +331,14 @@ struct ciss_softc
 static __inline void							\
 ciss_initq_ ## name (struct ciss_softc *sc)				\
 {									\
-    TAILQ_INIT(&sc->ciss_ ## name);					\
+    STAILQ_INIT(&sc->ciss_ ## name);					\
     CISSQ_INIT(sc, index);						\
 }									\
 static __inline void							\
 ciss_enqueue_ ## name (struct ciss_request *cr)				\
 {									\
     crit_enter();							\
-    TAILQ_INSERT_TAIL(&cr->cr_sc->ciss_ ## name, cr, cr_link);		\
+    STAILQ_INSERT_TAIL(&cr->cr_sc->ciss_ ## name, cr, cr_link);		\
     CISSQ_ADD(cr->cr_sc, index);					\
     cr->cr_onq = index;							\
     crit_exit();							\
@@ -344,51 +346,45 @@ ciss_enqueue_ ## name (struct ciss_request *cr)				\
 static __inline void							\
 ciss_requeue_ ## name (struct ciss_request *cr)				\
 {									\
-    crit_enter();							\
-    TAILQ_INSERT_HEAD(&cr->cr_sc->ciss_ ## name, cr, cr_link);		\
+									\
+    STAILQ_INSERT_HEAD(&cr->cr_sc->ciss_ ## name, cr, cr_link);		\
     CISSQ_ADD(cr->cr_sc, index);					\
     cr->cr_onq = index;							\
-    crit_exit();							\
 }									\
 static __inline struct ciss_request *					\
 ciss_dequeue_ ## name (struct ciss_softc *sc)				\
 {									\
     struct ciss_request	*cr;						\
 									\
-    crit_enter();							\
-    if ((cr = TAILQ_FIRST(&sc->ciss_ ## name)) != NULL) {		\
-	TAILQ_REMOVE(&sc->ciss_ ## name, cr, cr_link);			\
+    if ((cr = STAILQ_FIRST(&sc->ciss_ ## name)) != NULL) {		\
+	STAILQ_REMOVE_HEAD(&sc->ciss_ ## name, cr_link);		\
 	CISSQ_REMOVE(sc, index);					\
 	cr->cr_onq = -1;						\
     }									\
-    crit_exit();							\
     return(cr);								\
 }									\
-static __inline int							\
-ciss_remove_ ## name (struct ciss_request *cr)				\
-{									\
-    int			error;						\
-									\
-    crit_enter();							\
-    if (cr->cr_onq != index) {						\
-	kprintf("request on queue %d (expected %d)\n", cr->cr_onq, index);\
-	error = 1;							\
-    } else {								\
-	TAILQ_REMOVE(&cr->cr_sc->ciss_ ## name, cr, cr_link);		\
-	CISSQ_REMOVE(cr->cr_sc, index);					\
-	cr->cr_onq = -1;						\
-	error = 0;							\
-    }									\
-    crit_exit();							\
-    return(error);							\
-}									\
 struct hack
 
 CISSQ_REQUEST_QUEUE(free, CISSQ_FREE);
-CISSQ_REQUEST_QUEUE(busy, CISSQ_BUSY);
-CISSQ_REQUEST_QUEUE(complete, CISSQ_COMPLETE);
 CISSQ_REQUEST_QUEUE(notify, CISSQ_NOTIFY);
 
+static __inline void
+ciss_enqueue_complete(struct ciss_request *ac, cr_qhead_t *head)
+{
+
+    STAILQ_INSERT_TAIL(head, ac, cr_link);
+}
+
+static __inline struct ciss_request *
+ciss_dequeue_complete(struct ciss_softc *sc, cr_qhead_t *head)
+{
+    struct ciss_request  *ac;
+
+    if ((ac = STAILQ_FIRST(head)) != NULL)
+        STAILQ_REMOVE_HEAD(head, cr_link);
+    return(ac);
+}
+
 /********************************************************************************
  * space-fill a character string
  */
@@ -403,3 +399,6 @@ padstr(char *targ, const char *src, int len)
 	}
     }
 }
+
+#define ciss_report_request(a, b, c)	\
+	_ciss_report_request(a, b, c, __FUNCTION__)
