[Midnightbsd-cvs] src: dev/mfi: merge

laffer1 at midnightbsd.org laffer1 at midnightbsd.org
Tue Nov 25 11:45:36 EST 2008


Log Message:
-----------
merge

Modified Files:
--------------
    src/sys/dev/mfi:
        mfi.c (r1.1 -> r1.2)
        mfi_disk.c (r1.1 -> r1.2)
        mfi_ioctl.h (r1.1 -> r1.2)
        mfi_pci.c (r1.1 -> r1.2)
        mfireg.h (r1.1 -> r1.2)
        mfivar.h (r1.1 -> r1.2)

Added Files:
-----------
    src/sys/dev/mfi:
        mfi_cam.c (r1.1)
        mfi_debug.c (r1.1)
        mfi_linux.c (r1.1)

-------------- next part --------------
Index: mfi_disk.c
===================================================================
RCS file: /home/cvs/src/sys/dev/mfi/mfi_disk.c,v
retrieving revision 1.1
retrieving revision 1.2
diff -L sys/dev/mfi/mfi_disk.c -L sys/dev/mfi/mfi_disk.c -u -r1.1 -r1.2
--- sys/dev/mfi/mfi_disk.c
+++ sys/dev/mfi/mfi_disk.c
@@ -25,16 +25,17 @@
  */
 
 #include <sys/cdefs.h>
-__FBSDID("$FreeBSD: src/sys/dev/mfi/mfi_disk.c,v 1.2.2.1 2006/04/04 03:24:48 scottl Exp $");
-__MBSDID("$MidnightBSD$");
+__FBSDID("$FreeBSD: src/sys/dev/mfi/mfi_disk.c,v 1.7 2007/08/13 19:29:17 jhb Exp $");
 
 #include "opt_mfi.h"
 
 #include <sys/param.h>
 #include <sys/systm.h>
 #include <sys/kernel.h>
+#include <sys/selinfo.h>
 #include <sys/module.h>
 #include <sys/malloc.h>
+#include <sys/uio.h>
 
 #include <sys/bio.h>
 #include <sys/bus.h>
@@ -64,15 +65,6 @@
 
 static devclass_t	mfi_disk_devclass;
 
-struct mfi_disk {
-	device_t	ld_dev;
-	int		ld_id;
-	int		ld_unit;
-	struct mfi_softc *ld_controller;
-	struct mfi_ld	*ld_ld;
-	struct disk	*ld_disk;
-};
-
 static device_method_t mfi_disk_methods[] = {
 	DEVMETHOD(device_probe,		mfi_disk_probe),
 	DEVMETHOD(device_attach,	mfi_disk_attach),
@@ -99,31 +91,48 @@
 mfi_disk_attach(device_t dev)
 {
 	struct mfi_disk *sc;
-	struct mfi_ld *ld;
+	struct mfi_ld_info *ld_info;
 	uint64_t sectors;
 	uint32_t secsize;
+	char *state;
 
 	sc = device_get_softc(dev);
-	ld = device_get_ivars(dev);
+	ld_info = device_get_ivars(dev);
 
 	sc->ld_dev = dev;
-	sc->ld_id = ld->ld_id;
+	sc->ld_id = ld_info->ld_config.properties.ld.v.target_id;
 	sc->ld_unit = device_get_unit(dev);
-	sc->ld_ld = device_get_ivars(dev);
+	sc->ld_info = ld_info;
 	sc->ld_controller = device_get_softc(device_get_parent(dev));
+	sc->ld_flags = 0;
 
-	sectors = sc->ld_ld->ld_sectors;
-	secsize = sc->ld_ld->ld_secsize;
-	if (secsize != MFI_SECTOR_LEN) {
-		device_printf(sc->ld_dev, "Reported sector length %d is not "
-		    "512, aborting\n", secsize);
-		free(sc->ld_ld, M_MFIBUF);
-		return (EINVAL);
+	sectors = ld_info->size;
+	secsize = MFI_SECTOR_LEN;
+	mtx_lock(&sc->ld_controller->mfi_io_lock);
+	TAILQ_INSERT_TAIL(&sc->ld_controller->mfi_ld_tqh, sc, ld_link);
+	mtx_unlock(&sc->ld_controller->mfi_io_lock);
+
+	switch (ld_info->ld_config.params.state) {
+	case MFI_LD_STATE_OFFLINE:
+		state = "offline";
+		break;
+	case MFI_LD_STATE_PARTIALLY_DEGRADED:
+		state = "partially degraded";
+		break;
+	case MFI_LD_STATE_DEGRADED:
+		state = "degraded";
+		break;
+	case MFI_LD_STATE_OPTIMAL:
+		state = "optimal";
+		break;
+	default:
+		state = "unknown";
+		break;
 	}
-	TAILQ_INSERT_TAIL(&sc->ld_controller->mfi_ld_tqh, ld, ld_link);
-
-	device_printf(dev, "%juMB (%ju sectors) RAID\n",
-	    sectors / (1024 * 1024 / secsize), sectors);
+	device_printf(dev, "%juMB (%ju sectors) RAID volume '%s' is %s\n",
+		      sectors / (1024 * 1024 / secsize), sectors,
+		      ld_info->ld_config.properties.name,
+		      state);
 
 	sc->ld_disk = disk_alloc();
 	sc->ld_disk->d_drv1 = sc;
@@ -155,27 +164,79 @@
 
 	sc = device_get_softc(dev);
 
-	if (sc->ld_disk->d_flags & DISKFLAG_OPEN)
+	mtx_lock(&sc->ld_controller->mfi_io_lock);
+	if (((sc->ld_disk->d_flags & DISKFLAG_OPEN) ||
+	    (sc->ld_flags & MFI_DISK_FLAGS_OPEN)) &&
+	    (sc->ld_controller->mfi_keep_deleted_volumes ||
+	    sc->ld_controller->mfi_detaching)) {
+		mtx_unlock(&sc->ld_controller->mfi_io_lock);
 		return (EBUSY);
+	}
+	mtx_unlock(&sc->ld_controller->mfi_io_lock);
 
 	disk_destroy(sc->ld_disk);
+	mtx_lock(&sc->ld_controller->mfi_io_lock);
+	TAILQ_REMOVE(&sc->ld_controller->mfi_ld_tqh, sc, ld_link);
+	mtx_unlock(&sc->ld_controller->mfi_io_lock);
+	free(sc->ld_info, M_MFIBUF);
 	return (0);
 }
 
 static int
 mfi_disk_open(struct disk *dp)
 {
+	struct mfi_disk *sc;
+	int error;
 
-	return (0);
+	sc = dp->d_drv1;
+	mtx_lock(&sc->ld_controller->mfi_io_lock);
+	if (sc->ld_flags & MFI_DISK_FLAGS_DISABLED)
+		error = ENXIO;
+	else {
+		sc->ld_flags |= MFI_DISK_FLAGS_OPEN;
+		error = 0;
+	}
+	mtx_unlock(&sc->ld_controller->mfi_io_lock);
+
+	return (error);
 }
 
 static int
 mfi_disk_close(struct disk *dp)
 {
+	struct mfi_disk *sc;
+
+	sc = dp->d_drv1;
+	mtx_lock(&sc->ld_controller->mfi_io_lock);
+	sc->ld_flags &= ~MFI_DISK_FLAGS_OPEN;
+	mtx_unlock(&sc->ld_controller->mfi_io_lock);
 
 	return (0);
 }
 
+int
+mfi_disk_disable(struct mfi_disk *sc)
+{
+
+	mtx_assert(&sc->ld_controller->mfi_io_lock, MA_OWNED);
+	if (sc->ld_flags & MFI_DISK_FLAGS_OPEN) {
+		if (sc->ld_controller->mfi_delete_busy_volumes)
+			return (0);
+		device_printf(sc->ld_dev, "Unable to delete busy device\n");
+		return (EBUSY);
+	}
+	sc->ld_flags |= MFI_DISK_FLAGS_DISABLED;
+	return (0);
+}
+
+void
+mfi_disk_enable(struct mfi_disk *sc)
+{
+
+	mtx_assert(&sc->ld_controller->mfi_io_lock, MA_OWNED);
+	sc->ld_flags &= ~MFI_DISK_FLAGS_DISABLED;
+}
+
 static void
 mfi_disk_strategy(struct bio *bio)
 {
@@ -234,7 +295,7 @@
 
 	if (len > 0) {
 		if ((error = mfi_dump_blocks(parent_sc, sc->ld_id, offset /
-		    sc->ld_ld->ld_secsize, virt, len)) != 0)
+		    MFI_SECTOR_LEN, virt, len)) != 0)
 			return (error);
 	} else {
 		/* mfi_sync_cache(parent_sc, sc->ld_id); */
Index: mfi.c
===================================================================
RCS file: /home/cvs/src/sys/dev/mfi/mfi.c,v
retrieving revision 1.1
retrieving revision 1.2
diff -L sys/dev/mfi/mfi.c -L sys/dev/mfi/mfi.c -u -r1.1 -r1.2
--- sys/dev/mfi/mfi.c
+++ sys/dev/mfi/mfi.c
@@ -23,17 +23,45 @@
  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  * SUCH DAMAGE.
  */
+/*-
+ * Copyright (c) 2007 LSI Corp.
+ * Copyright (c) 2007 Rajesh Prabhakaran.
+ * 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.
+ */
 
 #include <sys/cdefs.h>
-__FBSDID("$FreeBSD: src/sys/dev/mfi/mfi.c,v 1.3.2.1 2006/04/04 03:24:48 scottl Exp $");
-__MBSDID("$MidnightBSD$");
+__FBSDID("$FreeBSD: src/sys/dev/mfi/mfi.c,v 1.33.4.1 2008/02/04 14:54:21 ambrisko Exp $");
 
 #include "opt_mfi.h"
 
 #include <sys/param.h>
 #include <sys/systm.h>
+#include <sys/sysctl.h>
 #include <sys/malloc.h>
 #include <sys/kernel.h>
+#include <sys/poll.h>
+#include <sys/selinfo.h>
 #include <sys/bus.h>
 #include <sys/conf.h>
 #include <sys/eventhandler.h>
@@ -41,6 +69,9 @@
 #include <sys/bus_dma.h>
 #include <sys/bio.h>
 #include <sys/ioccom.h>
+#include <sys/uio.h>
+#include <sys/proc.h>
+#include <sys/signalvar.h>
 
 #include <machine/bus.h>
 #include <machine/resource.h>
@@ -50,31 +81,56 @@
 #include <dev/mfi/mfivar.h>
 
 static int	mfi_alloc_commands(struct mfi_softc *);
-static void	mfi_release_command(struct mfi_command *cm);
 static int	mfi_comms_init(struct mfi_softc *);
-static int	mfi_polled_command(struct mfi_softc *, struct mfi_command *);
+static int	mfi_wait_command(struct mfi_softc *, struct mfi_command *);
 static int	mfi_get_controller_info(struct mfi_softc *);
+static int	mfi_get_log_state(struct mfi_softc *,
+		    struct mfi_evt_log_state **);
+static int	mfi_get_entry(struct mfi_softc *, int);
+static int	mfi_dcmd_command(struct mfi_softc *, struct mfi_command **,
+		    uint32_t, void **, size_t);
 static void	mfi_data_cb(void *, bus_dma_segment_t *, int, int);
 static void	mfi_startup(void *arg);
 static void	mfi_intr(void *arg);
-static void	mfi_enable_intr(struct mfi_softc *sc);
-static void	mfi_ldprobe_inq(struct mfi_softc *sc);
-static void	mfi_ldprobe_inq_complete(struct mfi_command *);
-static int	mfi_ldprobe_capacity(struct mfi_softc *sc, int id);
-static void	mfi_ldprobe_capacity_complete(struct mfi_command *);
-static int	mfi_ldprobe_tur(struct mfi_softc *sc, int id);
-static void	mfi_ldprobe_tur_complete(struct mfi_command *);
-static int	mfi_add_ld(struct mfi_softc *sc, int id, uint64_t, uint32_t);
+static void	mfi_ldprobe(struct mfi_softc *sc);
+static int	mfi_aen_register(struct mfi_softc *sc, int seq, int locale);
+static void	mfi_aen_complete(struct mfi_command *);
+static int	mfi_aen_setup(struct mfi_softc *, uint32_t);
+static int	mfi_add_ld(struct mfi_softc *sc, int);
+static void	mfi_add_ld_complete(struct mfi_command *);
 static struct mfi_command * mfi_bio_command(struct mfi_softc *);
 static void	mfi_bio_complete(struct mfi_command *);
 static int	mfi_mapcmd(struct mfi_softc *, struct mfi_command *);
 static int	mfi_send_frame(struct mfi_softc *, struct mfi_command *);
 static void	mfi_complete(struct mfi_softc *, struct mfi_command *);
+static int	mfi_abort(struct mfi_softc *, struct mfi_command *);
+static int	mfi_linux_ioctl_int(struct cdev *, u_long, caddr_t, int, d_thread_t *);
+static void	mfi_timeout(void *);
+static void 	mfi_enable_intr_xscale(struct mfi_softc *sc);
+static void 	mfi_enable_intr_ppc(struct mfi_softc *sc);
+static int32_t 	mfi_read_fw_status_xscale(struct mfi_softc *sc);
+static int32_t 	mfi_read_fw_status_ppc(struct mfi_softc *sc);
+static int 	mfi_check_clear_intr_xscale(struct mfi_softc *sc);
+static int 	mfi_check_clear_intr_ppc(struct mfi_softc *sc);
+static void 	mfi_issue_cmd_xscale(struct mfi_softc *sc,uint32_t bus_add,uint32_t frame_cnt);
+static void 	mfi_issue_cmd_ppc(struct mfi_softc *sc,uint32_t bus_add,uint32_t frame_cnt);
+
+SYSCTL_NODE(_hw, OID_AUTO, mfi, CTLFLAG_RD, 0, "MFI driver parameters");
+static int	mfi_event_locale = MFI_EVT_LOCALE_ALL;
+TUNABLE_INT("hw.mfi.event_locale", &mfi_event_locale);
+SYSCTL_INT(_hw_mfi, OID_AUTO, event_locale, CTLFLAG_RW, &mfi_event_locale,
+            0, "event message locale");
+
+static int	mfi_event_class = MFI_EVT_CLASS_INFO;
+TUNABLE_INT("hw.mfi.event_class", &mfi_event_class);
+SYSCTL_INT(_hw_mfi, OID_AUTO, event_class, CTLFLAG_RW, &mfi_event_class,
+          0, "event message class");
 
 /* Management interface */
 static d_open_t		mfi_open;
 static d_close_t	mfi_close;
 static d_ioctl_t	mfi_ioctl;
+static d_poll_t		mfi_poll;
 
 static struct cdevsw mfi_cdevsw = {
 	.d_version = 	D_VERSION,
@@ -82,12 +138,76 @@
 	.d_open = 	mfi_open,
 	.d_close =	mfi_close,
 	.d_ioctl =	mfi_ioctl,
+	.d_poll =	mfi_poll,
 	.d_name =	"mfi",
 };
 
 MALLOC_DEFINE(M_MFIBUF, "mfibuf", "Buffers for the MFI driver");
 
-#define MFI_INQ_LENGTH SHORT_INQUIRY_LENGTH 
+#define MFI_INQ_LENGTH SHORT_INQUIRY_LENGTH
+
+static void
+mfi_enable_intr_xscale(struct mfi_softc *sc)
+{
+	MFI_WRITE4(sc, MFI_OMSK, 0x01);
+}
+
+static void
+mfi_enable_intr_ppc(struct mfi_softc *sc)
+{
+	MFI_WRITE4(sc, MFI_ODCR0, 0xFFFFFFFF);
+	MFI_WRITE4(sc, MFI_OMSK, ~MFI_1078_EIM);
+}
+
+static int32_t
+mfi_read_fw_status_xscale(struct mfi_softc *sc)
+{
+	return MFI_READ4(sc, MFI_OMSG0);
+}
+ 
+static int32_t
+mfi_read_fw_status_ppc(struct mfi_softc *sc)
+{
+	return MFI_READ4(sc, MFI_OSP0);
+}
+
+static int 
+mfi_check_clear_intr_xscale(struct mfi_softc *sc)
+{
+	int32_t status;
+
+	status = MFI_READ4(sc, MFI_OSTS);
+	if ((status & MFI_OSTS_INTR_VALID) == 0)
+		return 1;
+
+	MFI_WRITE4(sc, MFI_OSTS, status);
+	return 0;
+ }
+
+static int 
+mfi_check_clear_intr_ppc(struct mfi_softc *sc)
+{
+	int32_t status;
+
+	status = MFI_READ4(sc, MFI_OSTS);
+	if (!status)
+		return 1; 
+
+	MFI_WRITE4(sc, MFI_ODCR0, status);
+	return 0;
+ }
+
+static void 
+mfi_issue_cmd_xscale(struct mfi_softc *sc,uint32_t bus_add,uint32_t frame_cnt)
+{
+	MFI_WRITE4(sc, MFI_IQP,(bus_add >>3)|frame_cnt);
+}
+  
+static void 
+mfi_issue_cmd_ppc(struct mfi_softc *sc,uint32_t bus_add,uint32_t frame_cnt)
+{
+	MFI_WRITE4(sc, MFI_IQP, (bus_add |frame_cnt <<1)|1 );
+}
 
 static int
 mfi_transition_firmware(struct mfi_softc *sc)
@@ -95,11 +215,11 @@
 	int32_t fw_state, cur_state;
 	int max_wait, i;
 
-	fw_state = MFI_READ4(sc, MFI_OMSG0) & MFI_FWSTATE_MASK;
+	fw_state = sc->mfi_read_fw_status(sc)& MFI_FWSTATE_MASK;
 	while (fw_state != MFI_FWSTATE_READY) {
 		if (bootverbose)
 			device_printf(sc->mfi_dev, "Waiting for firmware to "
-			    "become ready\n");
+			"become ready\n");
 		cur_state = fw_state;
 		switch (fw_state) {
 		case MFI_FWSTATE_FAULT:
@@ -128,7 +248,7 @@
 			return (ENXIO);
 		}
 		for (i = 0; i < (max_wait * 10); i++) {
-			fw_state = MFI_READ4(sc, MFI_OMSG0) & MFI_FWSTATE_MASK;
+			fw_state = sc->mfi_read_fw_status(sc) & MFI_FWSTATE_MASK;
 			if (fw_state == cur_state)
 				DELAY(100000);
 			else
@@ -157,16 +277,34 @@
 {
 	uint32_t status;
 	int error, commsz, framessz, sensesz;
-	int frames, unit;
+	int frames, unit, max_fw_sge;
+    device_printf(sc->mfi_dev, "Megaraid SAS driver Ver 2.00 \n");
 
 	mtx_init(&sc->mfi_io_lock, "MFI I/O lock", NULL, MTX_DEF);
+	sx_init(&sc->mfi_config_lock, "MFI config");
 	TAILQ_INIT(&sc->mfi_ld_tqh);
+	TAILQ_INIT(&sc->mfi_aen_pids);
+	TAILQ_INIT(&sc->mfi_cam_ccbq);
 
 	mfi_initq_free(sc);
 	mfi_initq_ready(sc);
 	mfi_initq_busy(sc);
 	mfi_initq_bio(sc);
 
+	if (sc->mfi_flags & MFI_FLAGS_1064R) {
+		sc->mfi_enable_intr = mfi_enable_intr_xscale;
+		sc->mfi_read_fw_status = mfi_read_fw_status_xscale;
+		sc->mfi_check_clear_intr = mfi_check_clear_intr_xscale;
+		sc->mfi_issue_cmd = mfi_issue_cmd_xscale;
+	}
+	else {
+		sc->mfi_enable_intr =  mfi_enable_intr_ppc;
+ 		sc->mfi_read_fw_status = mfi_read_fw_status_ppc;
+		sc->mfi_check_clear_intr = mfi_check_clear_intr_ppc;
+		sc->mfi_issue_cmd = mfi_issue_cmd_ppc;
+	}
+
+
 	/* Before we get too far, see if the firmware is working */
 	if ((error = mfi_transition_firmware(sc)) != 0) {
 		device_printf(sc->mfi_dev, "Firmware not in READY state, "
@@ -181,10 +319,10 @@
 	 * It would be nice if these constants were available at runtime
 	 * instead of compile time.
 	 */
-	status = MFI_READ4(sc, MFI_OMSG0);
+	status = sc->mfi_read_fw_status(sc);
 	sc->mfi_max_fw_cmds = status & MFI_FWSTATE_MAXCMD_MASK;
-	sc->mfi_max_fw_sgl = (status & MFI_FWSTATE_MAXSGL_MASK) >> 16;
-	sc->mfi_total_sgl = min(sc->mfi_max_fw_sgl, ((MAXPHYS / PAGE_SIZE) +1));
+	max_fw_sge = (status & MFI_FWSTATE_MAXSGL_MASK) >> 16;
+	sc->mfi_max_sge = min(max_fw_sge, ((MAXPHYS / PAGE_SIZE) + 1));
 
 	/*
 	 * Create the dma tag for data buffers.  Used both for block I/O
@@ -196,7 +334,7 @@
 				BUS_SPACE_MAXADDR,	/* highaddr */
 				NULL, NULL,		/* filter, filterarg */
 				BUS_SPACE_MAXSIZE_32BIT,/* maxsize */
-				sc->mfi_total_sgl,	/* nsegments */
+				sc->mfi_max_sge,	/* nsegments */
 				BUS_SPACE_MAXSIZE_32BIT,/* maxsegsize */
 				BUS_DMA_ALLOCNOW,	/* flags */
 				busdma_lock_mutex,	/* lockfunc */
@@ -239,24 +377,23 @@
 
 	/*
 	 * Allocate DMA memory for the command frames.  Keep them in the
-	 * lower 4GB for efficiency.  Calculate the size of the frames at
-	 * the same time; the frame is 64 bytes plus space for the SG lists.
+	 * lower 4GB for efficiency.  Calculate the size of the commands at
+	 * the same time; each command is one 64 byte frame plus a set of
+         * additional frames for holding sg lists or other data.
 	 * The assumption here is that the SG list will start at the second
-	 * 64 byte segment of the frame and not use the unused bytes in the
-	 * frame.  While this might seem wasteful, apparently the frames must
-	 * be 64 byte aligned, so any savings would be negated by the extra
-	 * alignment padding.
+	 * frame and not use the unused bytes in the first frame.  While this
+	 * isn't technically correct, it simplifies the calculation and allows
+	 * for command frames that might be larger than an mfi_io_frame.
 	 */
 	if (sizeof(bus_addr_t) == 8) {
-		sc->mfi_sgsize = sizeof(struct mfi_sg64);
+		sc->mfi_sge_size = sizeof(struct mfi_sg64);
 		sc->mfi_flags |= MFI_FLAGS_SG64;
 	} else {
-		sc->mfi_sgsize = sizeof(struct mfi_sg32);
+		sc->mfi_sge_size = sizeof(struct mfi_sg32);
 	}
-	frames = (sc->mfi_sgsize * sc->mfi_total_sgl + MFI_FRAME_SIZE - 1) /
-	    MFI_FRAME_SIZE + 1;
-	sc->mfi_frame_size = frames * MFI_FRAME_SIZE;
-	framessz = sc->mfi_frame_size * sc->mfi_max_fw_cmds;
+	frames = (sc->mfi_sge_size * sc->mfi_max_sge - 1) / MFI_FRAME_SIZE + 2;
+	sc->mfi_cmd_size = frames * MFI_FRAME_SIZE;
+	framessz = sc->mfi_cmd_size * sc->mfi_max_fw_cmds;
 	if (bus_dma_tag_create( sc->mfi_parent_dmat,	/* parent */
 				64, 0,			/* algnmnt, boundary */
 				BUS_SPACE_MAXADDR_32BIT,/* lowaddr */
@@ -316,10 +453,12 @@
 	if ((error = mfi_get_controller_info(sc)) != 0)
 		return (error);
 
-#if 0
-	if ((error = mfi_setup_aen(sc)) != 0)
+	mtx_lock(&sc->mfi_io_lock);
+	if ((error = mfi_aen_setup(sc, 0), 0) != 0) {
+		mtx_unlock(&sc->mfi_io_lock);
 		return (error);
-#endif
+	}
+	mtx_unlock(&sc->mfi_io_lock);
 
 	/*
 	 * Set up the interrupt handler.  XXX This should happen in
@@ -332,7 +471,7 @@
 		return (EINVAL);
 	}
 	if (bus_setup_intr(sc->mfi_dev, sc->mfi_irq, INTR_MPSAFE|INTR_TYPE_BIO,
-	    mfi_intr, sc, &sc->mfi_intr)) {
+	    NULL, mfi_intr, sc, &sc->mfi_intr)) {
 		device_printf(sc->mfi_dev, "Cannot set up interrupt\n");
 		return (EINVAL);
 	}
@@ -361,8 +500,27 @@
 	unit = device_get_unit(sc->mfi_dev);
 	sc->mfi_cdev = make_dev(&mfi_cdevsw, unit, UID_ROOT, GID_OPERATOR,
 	    0640, "mfi%d", unit);
+	if (unit == 0)
+		make_dev_alias(sc->mfi_cdev, "megaraid_sas_ioctl_node");
 	if (sc->mfi_cdev != NULL)
 		sc->mfi_cdev->si_drv1 = sc;
+	SYSCTL_ADD_INT(device_get_sysctl_ctx(sc->mfi_dev),
+	    SYSCTL_CHILDREN(device_get_sysctl_tree(sc->mfi_dev)),
+	    OID_AUTO, "delete_busy_volumes", CTLFLAG_RW,
+	    &sc->mfi_delete_busy_volumes, 0, "Allow removal of busy volumes");
+	SYSCTL_ADD_INT(device_get_sysctl_ctx(sc->mfi_dev),
+	    SYSCTL_CHILDREN(device_get_sysctl_tree(sc->mfi_dev)),
+	    OID_AUTO, "keep_deleted_volumes", CTLFLAG_RW,
+	    &sc->mfi_keep_deleted_volumes, 0,
+	    "Don't detach the mfid device for a busy volume that is deleted");
+
+	device_add_child(sc->mfi_dev, "mfip", -1);
+	bus_generic_attach(sc->mfi_dev);
+
+	/* Start the timeout watchdog */
+	callout_init(&sc->mfi_watchdog_callout, 1);
+	callout_reset(&sc->mfi_watchdog_callout, MFI_CMD_TIMEOUT * hz,
+	    mfi_timeout, sc);
 
 	return (0);
 }
@@ -383,14 +541,15 @@
 
 	for (i = 0; i < ncmds; i++) {
 		cm = &sc->mfi_commands[i];
-		cm->cm_frame = (union mfi_frame *)((uintptr_t)sc->mfi_frames + 
-		    sc->mfi_frame_size * i);
+		cm->cm_frame = (union mfi_frame *)((uintptr_t)sc->mfi_frames +
+		    sc->mfi_cmd_size * i);
 		cm->cm_frame_busaddr = sc->mfi_frames_busaddr +
-		    sc->mfi_frame_size * i;
+		    sc->mfi_cmd_size * i;
 		cm->cm_frame->header.context = i;
 		cm->cm_sense = &sc->mfi_sense[i];
 		cm->cm_sense_busaddr= sc->mfi_sense_busaddr + MFI_SENSE_LEN * i;
 		cm->cm_sc = sc;
+		cm->cm_index = i;
 		if (bus_dmamap_create(sc->mfi_buffer_dmat, 0,
 		    &cm->cm_dmamap) == 0)
 			mfi_release_command(cm);
@@ -402,29 +561,88 @@
 	return (0);
 }
 
-static void
+void
 mfi_release_command(struct mfi_command *cm)
 {
+	struct mfi_frame_header *hdr;
 	uint32_t *hdr_data;
 
 	/*
 	 * Zero out the important fields of the frame, but make sure the
-	 * context field is preserved
+	 * context field is preserved.  For efficiency, handle the fields
+	 * as 32 bit words.  Clear out the first S/G entry too for safety.
 	 */
+	hdr = &cm->cm_frame->header;
+	if (cm->cm_data != NULL && hdr->sg_count) {
+		cm->cm_sg->sg32[0].len = 0;
+		cm->cm_sg->sg32[0].addr = 0;
+	}
+
 	hdr_data = (uint32_t *)cm->cm_frame;
-	hdr_data[0] = 0;
-	hdr_data[1] = 0;
+	hdr_data[0] = 0;	/* cmd, sense_len, cmd_status, scsi_status */
+	hdr_data[1] = 0;	/* target_id, lun_id, cdb_len, sg_count */
+	hdr_data[4] = 0;	/* flags, timeout */
+	hdr_data[5] = 0;	/* data_len */
 
 	cm->cm_extra_frames = 0;
 	cm->cm_flags = 0;
 	cm->cm_complete = NULL;
 	cm->cm_private = NULL;
+	cm->cm_data = NULL;
 	cm->cm_sg = 0;
 	cm->cm_total_frame_size = 0;
+
 	mfi_enqueue_free(cm);
 }
 
 static int
+mfi_dcmd_command(struct mfi_softc *sc, struct mfi_command **cmp, uint32_t opcode,
+    void **bufp, size_t bufsize)
+{
+	struct mfi_command *cm;
+	struct mfi_dcmd_frame *dcmd;
+	void *buf = NULL;
+	
+	mtx_assert(&sc->mfi_io_lock, MA_OWNED);
+	
+	cm = mfi_dequeue_free(sc);
+	if (cm == NULL)
+		return (EBUSY);
+
+	if ((bufsize > 0) && (bufp != NULL)) {
+		if (*bufp == NULL) {
+			buf = malloc(bufsize, M_MFIBUF, M_NOWAIT|M_ZERO);
+			if (buf == NULL) {
+				mfi_release_command(cm);
+				return (ENOMEM);
+			}
+			*bufp = buf;
+		} else {
+			buf = *bufp;
+		}
+	}
+
+	dcmd =  &cm->cm_frame->dcmd;
+	bzero(dcmd->mbox, MFI_MBOX_SIZE);
+	dcmd->header.cmd = MFI_CMD_DCMD;
+	dcmd->header.timeout = 0;
+	dcmd->header.flags = 0;
+	dcmd->header.data_len = bufsize;
+	dcmd->opcode = opcode;
+	cm->cm_sg = &dcmd->sgl;
+	cm->cm_total_frame_size = MFI_DCMD_FRAME_SIZE;
+	cm->cm_flags = 0;
+	cm->cm_data = buf;
+	cm->cm_private = buf;
+	cm->cm_len = bufsize;
+
+	*cmp = cm;
+	if ((bufp != NULL) && (*bufp == NULL) && (buf != NULL))
+		*bufp = buf;
+	return (0);
+}
+
+static int
 mfi_comms_init(struct mfi_softc *sc)
 {
 	struct mfi_command *cm;
@@ -432,6 +650,7 @@
 	struct mfi_init_qinfo *qinfo;
 	int error;
 
+	mtx_lock(&sc->mfi_io_lock);
 	if ((cm = mfi_dequeue_free(sc)) == NULL)
 		return (EBUSY);
 
@@ -454,12 +673,16 @@
 	init->header.cmd = MFI_CMD_INIT;
 	init->header.data_len = sizeof(struct mfi_init_qinfo);
 	init->qinfo_new_addr_lo = cm->cm_frame_busaddr + MFI_FRAME_SIZE;
+	cm->cm_data = NULL;
+	cm->cm_flags = MFI_CMD_POLLED;
 
-	if ((error = mfi_polled_command(sc, cm)) != 0) {
+	if ((error = mfi_mapcmd(sc, cm)) != 0) {
 		device_printf(sc->mfi_dev, "failed to send init command\n");
+		mtx_unlock(&sc->mfi_io_lock);
 		return (error);
 	}
 	mfi_release_command(cm);
+	mtx_unlock(&sc->mfi_io_lock);
 
 	return (0);
 }
@@ -467,48 +690,24 @@
 static int
 mfi_get_controller_info(struct mfi_softc *sc)
 {
-	struct mfi_command *cm;
-	struct mfi_dcmd_frame *dcmd;
-	struct mfi_ctrl_info *ci;
+	struct mfi_command *cm = NULL;
+	struct mfi_ctrl_info *ci = NULL;
 	uint32_t max_sectors_1, max_sectors_2;
 	int error;
 
-	if ((cm = mfi_dequeue_free(sc)) == NULL)
-		return (EBUSY);
-
-	ci = malloc(sizeof(struct mfi_ctrl_info), M_MFIBUF, M_NOWAIT | M_ZERO);
-	if (ci == NULL) {
-		mfi_release_command(cm);
-		return (ENOMEM);
-	}
-
-	dcmd = &cm->cm_frame->dcmd;
-	bzero(dcmd->mbox, MFI_MBOX_SIZE);
-	dcmd->header.cmd = MFI_CMD_DCMD;
-	dcmd->header.timeout = 0;
-	dcmd->header.data_len = sizeof(struct mfi_ctrl_info);
-	dcmd->opcode = MFI_DCMD_CTRL_GETINFO;
-	cm->cm_sg = &dcmd->sgl;
-	cm->cm_total_frame_size = MFI_DCMD_FRAME_SIZE;
+	mtx_lock(&sc->mfi_io_lock);
+	error = mfi_dcmd_command(sc, &cm, MFI_DCMD_CTRL_GETINFO,
+	    (void **)&ci, sizeof(*ci));
+	if (error)
+		goto out;
 	cm->cm_flags = MFI_CMD_DATAIN | MFI_CMD_POLLED;
-	cm->cm_data = ci;
-	cm->cm_len = sizeof(struct mfi_ctrl_info);
 
 	if ((error = mfi_mapcmd(sc, cm)) != 0) {
-		device_printf(sc->mfi_dev, "Controller info buffer map failed");
-		free(ci, M_MFIBUF);
-		mfi_release_command(cm);
-		return (error);
-	}
-
-	/* It's ok if this fails, just use default info instead */
-	if ((error = mfi_polled_command(sc, cm)) != 0) {
 		device_printf(sc->mfi_dev, "Failed to get controller info\n");
-		sc->mfi_max_io = (sc->mfi_total_sgl - 1) * PAGE_SIZE /
+		sc->mfi_max_io = (sc->mfi_max_sge - 1) * PAGE_SIZE /
 		    MFI_SECTOR_LEN;
-		free(ci, M_MFIBUF);
-		mfi_release_command(cm);
-		return (0);
+		error = 0;
+		goto out;
 	}
 
 	bus_dmamap_sync(sc->mfi_buffer_dmat, cm->cm_dmamap,
@@ -519,37 +718,102 @@
 	max_sectors_2 = ci->max_request_size;
 	sc->mfi_max_io = min(max_sectors_1, max_sectors_2);
 
-	free(ci, M_MFIBUF);
-	mfi_release_command(cm);
+out:
+	if (ci)
+		free(ci, M_MFIBUF);
+	if (cm)
+		mfi_release_command(cm);
+	mtx_unlock(&sc->mfi_io_lock);
+	return (error);
+}
+
+static int
+mfi_get_log_state(struct mfi_softc *sc, struct mfi_evt_log_state **log_state)
+{
+	struct mfi_command *cm = NULL;
+	int error;
+
+	error = mfi_dcmd_command(sc, &cm, MFI_DCMD_CTRL_EVENT_GETINFO,
+	    (void **)log_state, sizeof(**log_state));
+	if (error)
+		goto out;
+	cm->cm_flags = MFI_CMD_DATAIN | MFI_CMD_POLLED;
+
+	if ((error = mfi_mapcmd(sc, cm)) != 0) {
+		device_printf(sc->mfi_dev, "Failed to get log state\n");
+		goto out;
+	}
+
+	bus_dmamap_sync(sc->mfi_buffer_dmat, cm->cm_dmamap,
+	    BUS_DMASYNC_POSTREAD);
+	bus_dmamap_unload(sc->mfi_buffer_dmat, cm->cm_dmamap);
+
+out:
+	if (cm)
+		mfi_release_command(cm);
 
 	return (error);
 }
 
 static int
-mfi_polled_command(struct mfi_softc *sc, struct mfi_command *cm)
+mfi_aen_setup(struct mfi_softc *sc, uint32_t seq_start)
 {
-	struct mfi_frame_header *hdr;
-	int tm = MFI_POLL_TIMEOUT_SECS * 1000000;
+	struct mfi_evt_log_state *log_state = NULL;
+	union mfi_evt class_locale;
+	int error = 0;
+	uint32_t seq;
+
+	class_locale.members.reserved = 0;
+	class_locale.members.locale = mfi_event_locale;
+	class_locale.members.class  = mfi_event_class;
+
+	if (seq_start == 0) {
+		error = mfi_get_log_state(sc, &log_state);
+		if (error) {
+			if (log_state)
+				free(log_state, M_MFIBUF);
+			return (error);
+		}
+		/*
+		 * Don't run them yet since we can't parse them.
+		 * We can indirectly get the contents from
+		 * the AEN mechanism via setting it lower then
+		 * current.  The firmware will iterate through them.
+		 */
+		for (seq = log_state->shutdown_seq_num;
+		     seq <= log_state->newest_seq_num; seq++) {
+			mfi_get_entry(sc, seq);
+		}
+	} else
+		seq = seq_start;
+	mfi_aen_register(sc, seq, class_locale.word);
+	free(log_state, M_MFIBUF);
 
-	hdr = &cm->cm_frame->header;
-	hdr->cmd_status = 0xff;
-	hdr->flags |= MFI_FRAME_DONT_POST_IN_REPLY_QUEUE;
+	return 0;
+}
 
-	mfi_send_frame(sc, cm);
+static int
+mfi_wait_command(struct mfi_softc *sc, struct mfi_command *cm)
+{
 
-	while (hdr->cmd_status == 0xff) {
-		DELAY(1000);
-		tm -= 1000;
-		if (tm <= 0)
-			break;
-	}
+	mtx_assert(&sc->mfi_io_lock, MA_OWNED);
+	cm->cm_complete = NULL;
 
-	if (hdr->cmd_status == 0xff) {
-		device_printf(sc->mfi_dev, "Frame %p timed out\n", hdr);
-		return (ETIMEDOUT);
-	}
 
-	return (0);
+	/*
+	 * MegaCli can issue a DCMD of 0.  In this case do nothing
+	 * and return 0 to it as status
+	 */
+	if (cm->cm_frame->dcmd.opcode == 0) {
+		cm->cm_frame->header.cmd_status = MFI_STAT_OK;
+		cm->cm_error = 0;
+		return (cm->cm_error);
+	}
+	mfi_enqueue_ready(cm);
+	mfi_startio(sc);
+	if ((cm->cm_flags & MFI_CMD_COMPLETED) == 0)
+		msleep(cm, &sc->mfi_io_lock, PRIBIO, "mfiwait", 0);
+	return (cm->cm_error);
 }
 
 void
@@ -558,6 +822,8 @@
 	struct mfi_command *cm;
 	int i;
 
+	callout_drain(&sc->mfi_watchdog_callout);
+
 	if (sc->mfi_cdev != NULL)
 		destroy_dev(sc->mfi_cdev);
 
@@ -604,8 +870,10 @@
 	if (sc->mfi_parent_dmat != NULL)
 		bus_dma_tag_destroy(sc->mfi_parent_dmat);
 
-	if (mtx_initialized(&sc->mfi_io_lock))
+	if (mtx_initialized(&sc->mfi_io_lock)) {
 		mtx_destroy(&sc->mfi_io_lock);
+		sx_destroy(&sc->mfi_config_lock);
+	}
 
 	return;
 }
@@ -619,8 +887,12 @@
 
 	config_intrhook_disestablish(&sc->mfi_ich);
 
-	mfi_enable_intr(sc);
-	mfi_ldprobe_inq(sc);
+	sc->mfi_enable_intr(sc);
+	sx_xlock(&sc->mfi_config_lock);
+	mtx_lock(&sc->mfi_io_lock);
+	mfi_ldprobe(sc);
+	mtx_unlock(&sc->mfi_io_lock);
+	sx_xunlock(&sc->mfi_config_lock);
 }
 
 static void
@@ -628,39 +900,37 @@
 {
 	struct mfi_softc *sc;
 	struct mfi_command *cm;
-	uint32_t status, pi, ci, context;
+	uint32_t pi, ci, context;
 
 	sc = (struct mfi_softc *)arg;
 
-	status = MFI_READ4(sc, MFI_OSTS);
-	if ((status & MFI_OSTS_INTR_VALID) == 0)
+	if (sc->mfi_check_clear_intr(sc))
 		return;
-	MFI_WRITE4(sc, MFI_OSTS, status);
 
 	pi = sc->mfi_comms->hw_pi;
 	ci = sc->mfi_comms->hw_ci;
-
 	mtx_lock(&sc->mfi_io_lock);
 	while (ci != pi) {
 		context = sc->mfi_comms->hw_reply_q[ci];
-		sc->mfi_comms->hw_reply_q[ci] = 0xffffffff;
-		if (context == 0xffffffff) {
-			device_printf(sc->mfi_dev, "mfi_intr: invalid context "
-			    "pi= %d ci= %d\n", pi, ci);
-		} else {
+		if (context < sc->mfi_max_fw_cmds) {
 			cm = &sc->mfi_commands[context];
 			mfi_remove_busy(cm);
+			cm->cm_error = 0;
 			mfi_complete(sc, cm);
 		}
-		ci++;
-		if (ci == (sc->mfi_max_fw_cmds + 1)) {
+		if (++ci == (sc->mfi_max_fw_cmds + 1)) {
 			ci = 0;
 		}
 	}
-	mtx_unlock(&sc->mfi_io_lock);
 
 	sc->mfi_comms->hw_ci = ci;
 
+	/* Give defered I/O a chance to run */
+	if (sc->mfi_flags & MFI_FLAGS_QFRZN)
+		sc->mfi_flags &= ~MFI_FLAGS_QFRZN;
+	mfi_startio(sc);
+	mtx_unlock(&sc->mfi_io_lock);
+
 	return;
 }
 
@@ -671,278 +941,597 @@
 	struct mfi_command *cm;
 	int error;
 
-	if ((cm = mfi_dequeue_free(sc)) == NULL)
-		return (EBUSY);
+	mtx_lock(&sc->mfi_io_lock);
+	error = mfi_dcmd_command(sc, &cm, MFI_DCMD_CTRL_SHUTDOWN, NULL, 0);
+	if (error) {
+		mtx_unlock(&sc->mfi_io_lock);
+		return (error);
+	}
 
-	/* AEN? */
+	if (sc->mfi_aen_cm != NULL)
+		mfi_abort(sc, sc->mfi_aen_cm);
 
 	dcmd = &cm->cm_frame->dcmd;
-	bzero(dcmd->mbox, MFI_MBOX_SIZE);
-	dcmd->header.cmd = MFI_CMD_DCMD;
-	dcmd->header.sg_count = 0;
 	dcmd->header.flags = MFI_FRAME_DIR_NONE;
-	dcmd->header.timeout = 0;
-	dcmd->header.data_len = 0;
-	dcmd->opcode = MFI_DCMD_CTRL_SHUTDOWN;
+	cm->cm_flags = MFI_CMD_POLLED;
+	cm->cm_data = NULL;
 
-	if ((error = mfi_polled_command(sc, cm)) != 0) {
+	if ((error = mfi_mapcmd(sc, cm)) != 0) {
 		device_printf(sc->mfi_dev, "Failed to shutdown controller\n");
 	}
 
+	mfi_release_command(cm);
+	mtx_unlock(&sc->mfi_io_lock);
 	return (error);
 }
 
 static void
-mfi_enable_intr(struct mfi_softc *sc)
+mfi_ldprobe(struct mfi_softc *sc)
 {
+	struct mfi_frame_header *hdr;
+	struct mfi_command *cm = NULL;
+	struct mfi_ld_list *list = NULL;
+	struct mfi_disk *ld;
+	int error, i;
 
-	MFI_WRITE4(sc, MFI_OMSK, 0x01);
-}
+	sx_assert(&sc->mfi_config_lock, SA_XLOCKED);
+	mtx_assert(&sc->mfi_io_lock, MA_OWNED);
 
-static void
-mfi_ldprobe_inq(struct mfi_softc *sc)
-{
-	struct mfi_command *cm;
-	struct mfi_pass_frame *pass;
-	char *inq;
-	int i;
+	error = mfi_dcmd_command(sc, &cm, MFI_DCMD_LD_GET_LIST,
+	    (void **)&list, sizeof(*list));
+	if (error)
+		goto out;
 
-	/* Probe all possible targets with a SCSI INQ command */
-	mtx_lock(&sc->mfi_io_lock);
-	sc->mfi_probe_count = 0;
-	for (i = 0; i < MFI_MAX_CHANNEL_DEVS; i++) {
-		inq = malloc(MFI_INQ_LENGTH, M_MFIBUF, M_NOWAIT|M_ZERO);
-		if (inq == NULL)
-			break;
-		cm = mfi_dequeue_free(sc);
-		if (cm == NULL) {
-			tsleep(mfi_startup, 0, "mfistart", 5 * hz);
-			i--;
-			continue;
-		}
-		pass = &cm->cm_frame->pass;
-		pass->header.cmd = MFI_CMD_LD_SCSI_IO;
-		pass->header.target_id = i;
-		pass->header.lun_id = 0;
-		pass->header.cdb_len = 6;
-		pass->header.timeout = 0;
-		pass->header.data_len = MFI_INQ_LENGTH;
-		bzero(pass->cdb, 16);
-		pass->cdb[0] = INQUIRY;
-		pass->cdb[4] = MFI_INQ_LENGTH;
-		pass->header.sense_len = MFI_SENSE_LEN;
-		pass->sense_addr_lo = cm->cm_sense_busaddr;
-		pass->sense_addr_hi = 0;
-		cm->cm_complete = mfi_ldprobe_inq_complete;
-		cm->cm_private = inq;
-		cm->cm_sg = &pass->sgl;
-		cm->cm_total_frame_size = MFI_PASS_FRAME_SIZE;
-		cm->cm_flags |= MFI_CMD_DATAIN;
-		cm->cm_data = inq;
-		cm->cm_len = MFI_INQ_LENGTH;
-		sc->mfi_probe_count++;
-		mfi_enqueue_ready(cm);
-		mfi_startio(sc);
+	cm->cm_flags = MFI_CMD_DATAIN;
+	if (mfi_wait_command(sc, cm) != 0) {
+		device_printf(sc->mfi_dev, "Failed to get device listing\n");
+		goto out;
 	}
 
-	/* Sleep while the arrays are attaching */
-	msleep(mfi_startup, &sc->mfi_io_lock, 0, "mfistart", 60 * hz);
-	mtx_unlock(&sc->mfi_io_lock);
+	hdr = &cm->cm_frame->header;
+	if (hdr->cmd_status != MFI_STAT_OK) {
+		device_printf(sc->mfi_dev, "MFI_DCMD_LD_GET_LIST failed %x\n",
+		    hdr->cmd_status);
+		goto out;
+	}
+
+	for (i = 0; i < list->ld_count; i++) {
+		TAILQ_FOREACH(ld, &sc->mfi_ld_tqh, ld_link) {
+			if (ld->ld_id == list->ld_list[i].ld.v.target_id)
+				goto skip_add;
+		}
+		mfi_add_ld(sc, list->ld_list[i].ld.v.target_id);
+	skip_add:;
+	}
+out:
+	if (list)
+		free(list, M_MFIBUF);
+	if (cm)
+		mfi_release_command(cm);
 
 	return;
 }
 
 static void
-mfi_ldprobe_inq_complete(struct mfi_command *cm)
+mfi_decode_evt(struct mfi_softc *sc, struct mfi_evt_detail *detail)
 {
-	struct mfi_frame_header *hdr;
-	struct mfi_softc *sc;
-	struct scsi_inquiry_data *inq;
-
-	sc = cm->cm_sc;
-	inq = cm->cm_private;
-	hdr = &cm->cm_frame->header;
-
-	if ((hdr->cmd_status != MFI_STAT_OK) || (hdr->scsi_status != 0x00) ||
-	    (SID_TYPE(inq) != T_DIRECT)) {
-		free(inq, M_MFIBUF);
-		mfi_release_command(cm);
-		if (--sc->mfi_probe_count <= 0)
-			wakeup(mfi_startup);
-		return;
+	switch (detail->arg_type) {
+	case MR_EVT_ARGS_NONE:
+		device_printf(sc->mfi_dev, "%d (%us/0x%04x/%d) - %s\n",
+		    detail->seq,
+		    detail->time,
+		    detail->class.members.locale,
+		    detail->class.members.class,
+		    detail->description
+		    );
+		break;
+	case MR_EVT_ARGS_CDB_SENSE:
+		device_printf(sc->mfi_dev, "%d (%us/0x%04x/%d) - PD %02d(e%d/s%d) CDB %*D"
+		    "Sense %*D\n: %s\n",
+		    detail->seq,
+		    detail->time,
+		    detail->class.members.locale,
+		    detail->class.members.class,
+		    detail->args.cdb_sense.pd.device_id,
+		    detail->args.cdb_sense.pd.enclosure_index,
+		    detail->args.cdb_sense.pd.slot_number,
+		    detail->args.cdb_sense.cdb_len,
+		    detail->args.cdb_sense.cdb,
+		    ":",
+		    detail->args.cdb_sense.sense_len,
+		    detail->args.cdb_sense.sense,
+		    ":",
+		    detail->description
+		    );
+		break;
+	case MR_EVT_ARGS_LD:
+		device_printf(sc->mfi_dev, "%d (%us/0x%04x/%d) - VD %02d/%d "
+		    "event: %s\n",
+		    detail->seq,
+		    detail->time,
+		    detail->class.members.locale,
+		    detail->class.members.class,
+		    detail->args.ld.ld_index,
+		    detail->args.ld.target_id,
+		    detail->description
+		    );
+		break;
+	case MR_EVT_ARGS_LD_COUNT:
+		device_printf(sc->mfi_dev, "%d (%us/0x%04x/%d) - VD %02d/%d "
+		    "count %lld: %s\n",
+		    detail->seq,
+		    detail->time,
+		    detail->class.members.locale,
+		    detail->class.members.class,
+		    detail->args.ld_count.ld.ld_index,
+		    detail->args.ld_count.ld.target_id,
+		    (long long)detail->args.ld_count.count,
+		    detail->description
+		    );
+		break;
+	case MR_EVT_ARGS_LD_LBA:
+		device_printf(sc->mfi_dev, "%d (%us/0x%04x/%d) - VD %02d/%d "
+		    "lba %lld: %s\n",
+		    detail->seq,
+		    detail->time,
+		    detail->class.members.locale,
+		    detail->class.members.class,
+		    detail->args.ld_lba.ld.ld_index,
+		    detail->args.ld_lba.ld.target_id,
+		    (long long)detail->args.ld_lba.lba,
+		    detail->description
+		    );
+		break;
+	case MR_EVT_ARGS_LD_OWNER:
+		device_printf(sc->mfi_dev, "%d (%us/0x%04x/%d) - VD %02d/%d "
+		    "owner changed: prior %d, new %d: %s\n",
+		    detail->seq,
+		    detail->time,
+		    detail->class.members.locale,
+		    detail->class.members.class,
+		    detail->args.ld_owner.ld.ld_index,
+		    detail->args.ld_owner.ld.target_id,
+		    detail->args.ld_owner.pre_owner,
+		    detail->args.ld_owner.new_owner,
+		    detail->description
+		    );
+		break;
+	case MR_EVT_ARGS_LD_LBA_PD_LBA:
+		device_printf(sc->mfi_dev, "%d (%us/0x%04x/%d) - VD %02d/%d "
+		    "lba %lld, physical drive PD %02d(e%d/s%d) lba %lld: %s\n",
+		    detail->seq,
+		    detail->time,
+		    detail->class.members.locale,
+		    detail->class.members.class,
+		    detail->args.ld_lba_pd_lba.ld.ld_index,
+		    detail->args.ld_lba_pd_lba.ld.target_id,
+		    (long long)detail->args.ld_lba_pd_lba.ld_lba,
+		    detail->args.ld_lba_pd_lba.pd.device_id,
+		    detail->args.ld_lba_pd_lba.pd.enclosure_index,
+		    detail->args.ld_lba_pd_lba.pd.slot_number,
+		    (long long)detail->args.ld_lba_pd_lba.pd_lba,
+		    detail->description
+		    );
+		break;
+	case MR_EVT_ARGS_LD_PROG:
+		device_printf(sc->mfi_dev, "%d (%us/0x%04x/%d) - VD %02d/%d "
+		    "progress %d%% in %ds: %s\n",
+		    detail->seq,
+		    detail->time,
+		    detail->class.members.locale,
+		    detail->class.members.class,
+		    detail->args.ld_prog.ld.ld_index,
+		    detail->args.ld_prog.ld.target_id,
+		    detail->args.ld_prog.prog.progress/655,
+		    detail->args.ld_prog.prog.elapsed_seconds,
+		    detail->description
+		    );
+		break;
+	case MR_EVT_ARGS_LD_STATE:
+		device_printf(sc->mfi_dev, "%d (%us/0x%04x/%d) - VD %02d/%d "
+		    "state prior %d new %d: %s\n",
+		    detail->seq,
+		    detail->time,
+		    detail->class.members.locale,
+		    detail->class.members.class,
+		    detail->args.ld_state.ld.ld_index,
+		    detail->args.ld_state.ld.target_id,
+		    detail->args.ld_state.prev_state,
+		    detail->args.ld_state.new_state,
+		    detail->description
+		    );
+		break;
+	case MR_EVT_ARGS_LD_STRIP:
+		device_printf(sc->mfi_dev, "%d (%us/0x%04x/%d) - VD %02d/%d "
+		    "strip %lld: %s\n",
+		    detail->seq,
+		    detail->time,
+		    detail->class.members.locale,
+		    detail->class.members.class,
+		    detail->args.ld_strip.ld.ld_index,
+		    detail->args.ld_strip.ld.target_id,
+		    (long long)detail->args.ld_strip.strip,
+		    detail->description
+		    );
+		break;
+	case MR_EVT_ARGS_PD:
+		device_printf(sc->mfi_dev, "%d (%us/0x%04x/%d) - PD %02d(e%d/s%d) "
+		    "event: %s\n",
+		    detail->seq,
+		    detail->time,
+		    detail->class.members.locale,
+		    detail->class.members.class,
+		    detail->args.pd.device_id,
+		    detail->args.pd.enclosure_index,
+		    detail->args.pd.slot_number,
+		    detail->description
+		    );
+		break;
+	case MR_EVT_ARGS_PD_ERR:
+		device_printf(sc->mfi_dev, "%d (%us/0x%04x/%d) - PD %02d(e%d/s%d) "
+		    "err %d: %s\n",
+		    detail->seq,
+		    detail->time,
+		    detail->class.members.locale,
+		    detail->class.members.class,
+		    detail->args.pd_err.pd.device_id,
+		    detail->args.pd_err.pd.enclosure_index,
+		    detail->args.pd_err.pd.slot_number,
+		    detail->args.pd_err.err,
+		    detail->description
+		    );
+		break;
+	case MR_EVT_ARGS_PD_LBA:
+		device_printf(sc->mfi_dev, "%d (%us/0x%04x/%d) - PD %02d(e%d/s%d) "
+		    "lba %lld: %s\n",
+		    detail->seq,
+		    detail->time,
+		    detail->class.members.locale,
+		    detail->class.members.class,
+		    detail->args.pd_lba.pd.device_id,
+		    detail->args.pd_lba.pd.enclosure_index,
+		    detail->args.pd_lba.pd.slot_number,
+		    (long long)detail->args.pd_lba.lba,
+		    detail->description
+		    );
+		break;
+	case MR_EVT_ARGS_PD_LBA_LD:
+		device_printf(sc->mfi_dev, "%d (%us/0x%04x/%d) - PD %02d(e%d/s%d) "
+		    "lba %lld VD %02d/%d: %s\n",
+		    detail->seq,
+		    detail->time,
+		    detail->class.members.locale,
+		    detail->class.members.class,
+		    detail->args.pd_lba_ld.pd.device_id,
+		    detail->args.pd_lba_ld.pd.enclosure_index,
+		    detail->args.pd_lba_ld.pd.slot_number,
+		    (long long)detail->args.pd_lba.lba,
+		    detail->args.pd_lba_ld.ld.ld_index,
+		    detail->args.pd_lba_ld.ld.target_id,
+		    detail->description
+		    );
+		break;
+	case MR_EVT_ARGS_PD_PROG:
+		device_printf(sc->mfi_dev, "%d (%us/0x%04x/%d) - PD %02d(e%d/s%d) "
+		    "progress %d%% seconds %ds: %s\n",
+		    detail->seq,
+		    detail->time,
+		    detail->class.members.locale,
+		    detail->class.members.class,
+		    detail->args.pd_prog.pd.device_id,
+		    detail->args.pd_prog.pd.enclosure_index,
+		    detail->args.pd_prog.pd.slot_number,
+		    detail->args.pd_prog.prog.progress/655,
+		    detail->args.pd_prog.prog.elapsed_seconds,
+		    detail->description
+		    );
+		break;
+	case MR_EVT_ARGS_PD_STATE:
+		device_printf(sc->mfi_dev, "%d (%us/0x%04x/%d) - PD %02d(e%d/s%d) "
+		    "state prior %d new %d: %s\n",
+		    detail->seq,
+		    detail->time,
+		    detail->class.members.locale,
+		    detail->class.members.class,
+		    detail->args.pd_prog.pd.device_id,
+		    detail->args.pd_prog.pd.enclosure_index,
+		    detail->args.pd_prog.pd.slot_number,
+		    detail->args.pd_state.prev_state,
+		    detail->args.pd_state.new_state,
+		    detail->description
+		    );
+		break;
+	case MR_EVT_ARGS_PCI:
+		device_printf(sc->mfi_dev, "%d (%us/0x%04x/%d) - PCI 0x04%x 0x04%x "
+		    "0x04%x 0x04%x: %s\n",
+		    detail->seq,
+		    detail->time,
+		    detail->class.members.locale,
+		    detail->class.members.class,
+		    detail->args.pci.venderId,
+		    detail->args.pci.deviceId,
+		    detail->args.pci.subVenderId,
+		    detail->args.pci.subDeviceId,
+		    detail->description
+		    );
+		break;
+	case MR_EVT_ARGS_RATE:
+		device_printf(sc->mfi_dev, "%d (%us/0x%04x/%d) - Rebuild rate %d: %s\n",
+		    detail->seq,
+		    detail->time,
+		    detail->class.members.locale,
+		    detail->class.members.class,
+		    detail->args.rate,
+		    detail->description
+		    );
+		break;
+	case MR_EVT_ARGS_TIME:
+		device_printf(sc->mfi_dev, "%d (%us/0x%04x/%d) - Adapter ticks %d "
+		    "elapsed %ds: %s\n",
+		    detail->seq,
+		    detail->time,
+		    detail->class.members.locale,
+		    detail->class.members.class,
+		    detail->args.time.rtc,
+		    detail->args.time.elapsedSeconds,
+		    detail->description
+		    );
+		break;
+	case MR_EVT_ARGS_ECC:
+		device_printf(sc->mfi_dev, "%d (%us/0x%04x/%d) - Adapter ECC %x,%x: %s: %s\n",
+		    detail->seq,
+		    detail->time,
+		    detail->class.members.locale,
+		    detail->class.members.class,
+		    detail->args.ecc.ecar,
+		    detail->args.ecc.elog,
+		    detail->args.ecc.str,
+		    detail->description
+		    );
+		break;
+	default:
+		device_printf(sc->mfi_dev, "%d (%us/0x%04x/%d) - Type %d: %s\n",
+		    detail->seq,
+		    detail->time,
+		    detail->class.members.locale,
+		    detail->class.members.class,
+		    detail->arg_type, detail->description
+		    );
 	}
-
-	free(inq, M_MFIBUF);
-	mfi_release_command(cm);
-	mfi_ldprobe_tur(sc, hdr->target_id);
 }
 
 static int
-mfi_ldprobe_tur(struct mfi_softc *sc, int id)
+mfi_aen_register(struct mfi_softc *sc, int seq, int locale)
 {
 	struct mfi_command *cm;
-	struct mfi_pass_frame *pass;
+	struct mfi_dcmd_frame *dcmd;
+	union mfi_evt current_aen, prior_aen;
+	struct mfi_evt_detail *ed = NULL;
+	int error = 0;
+
+	current_aen.word = locale;
+	if (sc->mfi_aen_cm != NULL) {
+		prior_aen.word =
+		    ((uint32_t *)&sc->mfi_aen_cm->cm_frame->dcmd.mbox)[1];
+		if (prior_aen.members.class <= current_aen.members.class &&
+		    !((prior_aen.members.locale & current_aen.members.locale)
+		    ^current_aen.members.locale)) {
+			return (0);
+		} else {
+			prior_aen.members.locale |= current_aen.members.locale;
+			if (prior_aen.members.class
+			    < current_aen.members.class)
+				current_aen.members.class =
+				    prior_aen.members.class;
+			mfi_abort(sc, sc->mfi_aen_cm);
+		}
+	}
+
+	error = mfi_dcmd_command(sc, &cm, MFI_DCMD_CTRL_EVENT_WAIT,
+	    (void **)&ed, sizeof(*ed));
+	if (error) {
+		goto out;
+	}
+
+	dcmd = &cm->cm_frame->dcmd;
+	((uint32_t *)&dcmd->mbox)[0] = seq;
+	((uint32_t *)&dcmd->mbox)[1] = locale;
+	cm->cm_flags = MFI_CMD_DATAIN;
+	cm->cm_complete = mfi_aen_complete;
+
+	sc->mfi_aen_cm = cm;
 
-	cm = mfi_dequeue_free(sc);
-	if (cm == NULL)
-		return (EBUSY);
-	pass = &cm->cm_frame->pass;
-	pass->header.cmd = MFI_CMD_LD_SCSI_IO;
-	pass->header.target_id = id;
-	pass->header.lun_id = 0;
-	pass->header.cdb_len = 6;
-	pass->header.timeout = 0;
-	pass->header.data_len = 0;
-	bzero(pass->cdb, 16);
-	pass->cdb[0] = TEST_UNIT_READY;
-	pass->header.sense_len = MFI_SENSE_LEN;
-	pass->sense_addr_lo = cm->cm_sense_busaddr;
-	pass->sense_addr_hi = 0;
-	cm->cm_complete = mfi_ldprobe_tur_complete;
-	cm->cm_total_frame_size = MFI_PASS_FRAME_SIZE;
-	cm->cm_flags = 0;
 	mfi_enqueue_ready(cm);
 	mfi_startio(sc);
 
-	return (0);
+out:
+	return (error);
 }
 
 static void
-mfi_ldprobe_tur_complete(struct mfi_command *cm)
+mfi_aen_complete(struct mfi_command *cm)
 {
 	struct mfi_frame_header *hdr;
 	struct mfi_softc *sc;
+	struct mfi_evt_detail *detail;
+	struct mfi_aen *mfi_aen_entry, *tmp;
+	int seq = 0, aborted = 0;
 
 	sc = cm->cm_sc;
 	hdr = &cm->cm_frame->header;
 
-	if ((hdr->cmd_status != MFI_STAT_OK) || (hdr->scsi_status != 0x00)) {
-		device_printf(sc->mfi_dev, "Logical disk %d is not ready, "
-		    "cmd_status= %d scsi_status= %d\n", hdr->target_id,
-		    hdr->cmd_status, hdr->scsi_status);
-		mfi_print_sense(sc, cm->cm_sense);
-		mfi_release_command(cm);
-		if (--sc->mfi_probe_count <= 0)
-			wakeup(mfi_startup);
+	if (sc->mfi_aen_cm == NULL)
 		return;
+
+	if (sc->mfi_aen_cm->cm_aen_abort || hdr->cmd_status == 0xff) {
+		sc->mfi_aen_cm->cm_aen_abort = 0;
+		aborted = 1;
+	} else {
+		sc->mfi_aen_triggered = 1;
+		if (sc->mfi_poll_waiting) {
+			sc->mfi_poll_waiting = 0;
+			selwakeup(&sc->mfi_select);
+		}
+		detail = cm->cm_data;
+		/*
+		 * XXX If this function is too expensive or is recursive, then
+		 * events should be put onto a queue and processed later.
+		 */
+		mtx_unlock(&sc->mfi_io_lock);
+		mfi_decode_evt(sc, detail);
+		mtx_lock(&sc->mfi_io_lock);
+		seq = detail->seq + 1;
+		TAILQ_FOREACH_SAFE(mfi_aen_entry, &sc->mfi_aen_pids, aen_link, tmp) {
+			TAILQ_REMOVE(&sc->mfi_aen_pids, mfi_aen_entry,
+			    aen_link);
+			PROC_LOCK(mfi_aen_entry->p);
+			psignal(mfi_aen_entry->p, SIGIO);
+			PROC_UNLOCK(mfi_aen_entry->p);
+			free(mfi_aen_entry, M_MFIBUF);
+		}
 	}
+
+	free(cm->cm_data, M_MFIBUF);
+	sc->mfi_aen_cm = NULL;
+	wakeup(&sc->mfi_aen_cm);
 	mfi_release_command(cm);
-	mfi_ldprobe_capacity(sc, hdr->target_id);
+
+	/* set it up again so the driver can catch more events */
+	if (!aborted) {
+		mfi_aen_setup(sc, seq);
+	}
 }
 
+/* Only do one event for now so we can easily iterate through them */
+#define MAX_EVENTS 1
 static int
-mfi_ldprobe_capacity(struct mfi_softc *sc, int id)
+mfi_get_entry(struct mfi_softc *sc, int seq)
 {
 	struct mfi_command *cm;
-	struct mfi_pass_frame *pass;
-	struct scsi_read_capacity_data_long *cap;
+	struct mfi_dcmd_frame *dcmd;
+	struct mfi_evt_list *el;
+	int error;
+	int i;
+	int size;
 
-	cap = malloc(sizeof(*cap), M_MFIBUF, M_NOWAIT|M_ZERO);
-	if (cap == NULL)
-		return (ENOMEM);
-	cm = mfi_dequeue_free(sc);
-	if (cm == NULL)
+	if ((cm = mfi_dequeue_free(sc)) == NULL) {
 		return (EBUSY);
-	pass = &cm->cm_frame->pass;
-	pass->header.cmd = MFI_CMD_LD_SCSI_IO;
-	pass->header.target_id = id;
-	pass->header.lun_id = 0;
-	pass->header.cdb_len = 6;
-	pass->header.timeout = 0;
-	pass->header.data_len = sizeof(*cap);
-	bzero(pass->cdb, 16);
-	pass->cdb[0] = 0x9e;	/* READ CAPACITY 16 */
-	pass->cdb[13] = sizeof(*cap);
-	pass->header.sense_len = MFI_SENSE_LEN;
-	pass->sense_addr_lo = cm->cm_sense_busaddr;
-	pass->sense_addr_hi = 0;
-	cm->cm_complete = mfi_ldprobe_capacity_complete;
-	cm->cm_private = cap;
-	cm->cm_sg = &pass->sgl;
-	cm->cm_total_frame_size = MFI_PASS_FRAME_SIZE;
-	cm->cm_flags |= MFI_CMD_DATAIN;
-	cm->cm_data = cap;
-	cm->cm_len = sizeof(*cap);
-	mfi_enqueue_ready(cm);
-	mfi_startio(sc);
+	}
 
-	return (0);
-}
+	size = sizeof(struct mfi_evt_list) + sizeof(struct mfi_evt_detail)
+		* (MAX_EVENTS - 1);
+	el = malloc(size, M_MFIBUF, M_NOWAIT | M_ZERO);
+	if (el == NULL) {
+		mfi_release_command(cm);
+		return (ENOMEM);
+	}
 
-static void
-mfi_ldprobe_capacity_complete(struct mfi_command *cm)
-{
-	struct mfi_frame_header *hdr;
-	struct mfi_softc *sc;
-	struct scsi_read_capacity_data_long *cap;
-	uint64_t sectors;
-	uint32_t secsize;
-	int target;
-
-	sc = cm->cm_sc;
-	cap = cm->cm_private;
-	hdr = &cm->cm_frame->header;
+	dcmd = &cm->cm_frame->dcmd;
+	bzero(dcmd->mbox, MFI_MBOX_SIZE);
+	dcmd->header.cmd = MFI_CMD_DCMD;
+	dcmd->header.timeout = 0;
+	dcmd->header.data_len = size;
+	dcmd->opcode = MFI_DCMD_CTRL_EVENT_GET;
+	((uint32_t *)&dcmd->mbox)[0] = seq;
+	((uint32_t *)&dcmd->mbox)[1] = MFI_EVT_LOCALE_ALL;
+	cm->cm_sg = &dcmd->sgl;
+	cm->cm_total_frame_size = MFI_DCMD_FRAME_SIZE;
+	cm->cm_flags = MFI_CMD_DATAIN | MFI_CMD_POLLED;
+	cm->cm_data = el;
+	cm->cm_len = size;
 
-	if ((hdr->cmd_status != MFI_STAT_OK) || (hdr->scsi_status != 0x00)) {
-		device_printf(sc->mfi_dev, "Failed to read capacity for "
-		    "logical disk\n");
-		device_printf(sc->mfi_dev, "cmd_status= %d scsi_status= %d\n",
-		    hdr->cmd_status, hdr->scsi_status);
-		free(cap, M_MFIBUF);
+	if ((error = mfi_mapcmd(sc, cm)) != 0) {
+		device_printf(sc->mfi_dev, "Failed to get controller entry\n");
+		sc->mfi_max_io = (sc->mfi_max_sge - 1) * PAGE_SIZE /
+		    MFI_SECTOR_LEN;
+		free(el, M_MFIBUF);
 		mfi_release_command(cm);
-		if (--sc->mfi_probe_count <= 0)
-			wakeup(mfi_startup);
-		return;
+		return (0);
 	}
-	target = hdr->target_id;
-	sectors = scsi_8btou64(cap->addr);
-	secsize = scsi_4btoul(cap->length);
-	free(cap, M_MFIBUF);
-	mfi_release_command(cm);
-	mfi_add_ld(sc, target, sectors, secsize);
-	if (--sc->mfi_probe_count <= 0)
-		wakeup(mfi_startup);
 
-	return;
+	bus_dmamap_sync(sc->mfi_buffer_dmat, cm->cm_dmamap,
+	    BUS_DMASYNC_POSTREAD);
+	bus_dmamap_unload(sc->mfi_buffer_dmat, cm->cm_dmamap);
+
+	if (dcmd->header.cmd_status != MFI_STAT_NOT_FOUND) {
+		for (i = 0; i < el->count; i++) {
+			if (seq + i == el->event[i].seq)
+				mfi_decode_evt(sc, &el->event[i]);
+		}
+	}
+
+	free(cm->cm_data, M_MFIBUF);
+	mfi_release_command(cm);
+	return (0);
 }
 
 static int
-mfi_add_ld(struct mfi_softc *sc, int id, uint64_t sectors, uint32_t secsize)
+mfi_add_ld(struct mfi_softc *sc, int id)
 {
-	struct mfi_ld *ld;
-	device_t child;
+	struct mfi_command *cm;
+	struct mfi_dcmd_frame *dcmd = NULL;
+	struct mfi_ld_info *ld_info = NULL;
+	int error;
 
-	if ((secsize == 0) || (sectors == 0)) {
-		device_printf(sc->mfi_dev, "Invalid capacity parameters for "
-		      "logical disk %d\n", id);
-		return (EINVAL);
+	mtx_assert(&sc->mfi_io_lock, MA_OWNED);
+
+	error = mfi_dcmd_command(sc, &cm, MFI_DCMD_LD_GET_INFO,
+	    (void **)&ld_info, sizeof(*ld_info));
+	if (error) {
+		device_printf(sc->mfi_dev,
+		    "Failed to allocate for MFI_DCMD_LD_GET_INFO %d\n", error);
+		if (ld_info)
+			free(ld_info, M_MFIBUF);
+		return (error);
+	}
+	cm->cm_flags = MFI_CMD_DATAIN;
+	dcmd = &cm->cm_frame->dcmd;
+	dcmd->mbox[0] = id;
+	if (mfi_wait_command(sc, cm) != 0) {
+		device_printf(sc->mfi_dev,
+		    "Failed to get logical drive: %d\n", id);
+		free(ld_info, M_MFIBUF);
+		return (0);
 	}
 
-	ld = malloc(sizeof(struct mfi_ld), M_MFIBUF, M_NOWAIT|M_ZERO);
-	if (ld == NULL) {
-		device_printf(sc->mfi_dev, "Cannot allocate ld\n");
-		return (ENOMEM);
+	mfi_add_ld_complete(cm);
+	return (0);
+}
+
+static void
+mfi_add_ld_complete(struct mfi_command *cm)
+{
+	struct mfi_frame_header *hdr;
+	struct mfi_ld_info *ld_info;
+	struct mfi_softc *sc;
+	device_t child;
+
+	sc = cm->cm_sc;
+	hdr = &cm->cm_frame->header;
+	ld_info = cm->cm_private;
+
+	if (hdr->cmd_status != MFI_STAT_OK) {
+		free(ld_info, M_MFIBUF);
+		mfi_release_command(cm);
+		return;
 	}
+	mfi_release_command(cm);
 
+	mtx_unlock(&sc->mfi_io_lock);
+	mtx_lock(&Giant);
 	if ((child = device_add_child(sc->mfi_dev, "mfid", -1)) == NULL) {
 		device_printf(sc->mfi_dev, "Failed to add logical disk\n");
-		return (EINVAL);
+		free(ld_info, M_MFIBUF);
+		mtx_unlock(&Giant);
+		mtx_lock(&sc->mfi_io_lock);
+		return;
 	}
 
-	ld->ld_id = id;
-	ld->ld_disk = child;
-	ld->ld_secsize = secsize;
-	ld->ld_sectors = sectors;
-
-	device_set_ivars(child, ld);
+	device_set_ivars(child, ld_info);
 	device_set_desc(child, "MFI Logical Disk");
-	mtx_unlock(&sc->mfi_io_lock);
-	mtx_lock(&Giant);
 	bus_generic_attach(sc->mfi_dev);
 	mtx_unlock(&Giant);
 	mtx_lock(&sc->mfi_io_lock);
-
-	return (0);
 }
 
 static struct mfi_command *
@@ -951,7 +1540,7 @@
 	struct mfi_io_frame *io;
 	struct mfi_command *cm;
 	struct bio *bio;
-	int flags, blkcount;;
+	int flags, blkcount;
 
 	if ((cm = mfi_dequeue_free(sc)) == NULL)
 		return (NULL);
@@ -993,7 +1582,6 @@
 	cm->cm_sg = &io->sgl;
 	cm->cm_total_frame_size = MFI_IO_FRAME_SIZE;
 	cm->cm_flags = flags;
-
 	return (cm);
 }
 
@@ -1024,6 +1612,7 @@
 mfi_startio(struct mfi_softc *sc)
 {
 	struct mfi_command *cm;
+	struct ccb_hdr *ccbh;
 
 	for (;;) {
 		/* Don't bother if we're short on resources */
@@ -1033,6 +1622,11 @@
 		/* Try a command that has already been prepared */
 		cm = mfi_dequeue_ready(sc);
 
+		if (cm == NULL) {
+			if ((ccbh = TAILQ_FIRST(&sc->mfi_cam_ccbq)) != NULL)
+				cm = sc->mfi_cam_start(ccbh);
+		}
+
 		/* Nope, so look for work on the bioq */
 		if (cm == NULL)
 			cm = mfi_bio_command(sc);
@@ -1054,6 +1648,8 @@
 {
 	int error, polled;
 
+	mtx_assert(&sc->mfi_io_lock, MA_OWNED);
+
 	if (cm->cm_data != NULL) {
 		polled = (cm->cm_flags & MFI_CMD_POLLED) ? BUS_DMA_NOWAIT : 0;
 		error = bus_dmamap_load(sc->mfi_buffer_dmat, cm->cm_dmamap,
@@ -1063,7 +1659,6 @@
 			return (0);
 		}
 	} else {
-		mfi_enqueue_busy(cm);
 		error = mfi_send_frame(sc, cm);
 	}
 
@@ -1079,14 +1674,18 @@
 	struct mfi_softc *sc;
 	int i, dir;
 
-	if (error)
-		return;
-
 	cm = (struct mfi_command *)arg;
 	sc = cm->cm_sc;
 	hdr = &cm->cm_frame->header;
 	sgl = cm->cm_sg;
 
+	if (error) {
+		printf("error %d in callback\n", error);
+		cm->cm_error = error;
+		mfi_complete(sc, cm);
+		return;
+	}
+
 	if ((sc->mfi_flags & MFI_FLAGS_SG64) == 0) {
 		for (i = 0; i < nsegs; i++) {
 			sgl->sg32[i].addr = segs[i].ds_addr;
@@ -1119,14 +1718,10 @@
 	 * least 1 frame, so don't compensate for the modulo of the
 	 * following division.
 	 */
-	cm->cm_total_frame_size += (sc->mfi_sgsize * nsegs);
+	cm->cm_total_frame_size += (sc->mfi_sge_size * nsegs);
 	cm->cm_extra_frames = (cm->cm_total_frame_size - 1) / MFI_FRAME_SIZE;
 
-	/* The caller will take care of delivering polled commands */
-	if ((cm->cm_flags & MFI_CMD_POLLED) == 0) {
-		mfi_enqueue_busy(cm);
-		mfi_send_frame(sc, cm);
-	}
+	mfi_send_frame(sc, cm);
 
 	return;
 }
@@ -1134,22 +1729,53 @@
 static int
 mfi_send_frame(struct mfi_softc *sc, struct mfi_command *cm)
 {
+	struct mfi_frame_header *hdr;
+	int tm = MFI_POLL_TIMEOUT_SECS * 1000;
+
+	hdr = &cm->cm_frame->header;
+
+	if ((cm->cm_flags & MFI_CMD_POLLED) == 0) {
+		cm->cm_timestamp = time_uptime;
+		mfi_enqueue_busy(cm);
+	} else {
+		hdr->cmd_status = 0xff;
+		hdr->flags |= MFI_FRAME_DONT_POST_IN_REPLY_QUEUE;
+	}
 
 	/*
 	 * The bus address of the command is aligned on a 64 byte boundary,
 	 * leaving the least 6 bits as zero.  For whatever reason, the
 	 * hardware wants the address shifted right by three, leaving just
-	 * 3 zero bits.  These three bits are then used to indicate how many
-	 * 64 byte frames beyond the first one are used in the command.  The
-	 * extra frames are typically filled with S/G elements.  The extra
-	 * frames must also be contiguous.  Thus, a compound frame can be at
-	 * most 512 bytes long, allowing for up to 59 32-bit S/G elements or
-	 * 39 64-bit S/G elements for block I/O commands.  This means that
-	 * I/O transfers of 256k and higher simply are not possible, which
-	 * is quite odd for such a modern adapter.
+	 * 3 zero bits.  These three bits are then used as a prefetching
+	 * hint for the hardware to predict how many frames need to be
+	 * fetched across the bus.  If a command has more than 8 frames
+	 * then the 3 bits are set to 0x7 and the firmware uses other
+	 * information in the command to determine the total amount to fetch.
+	 * However, FreeBSD doesn't support I/O larger than 128K, so 8 frames
+	 * is enough for both 32bit and 64bit systems.
 	 */
-	MFI_WRITE4(sc, MFI_IQP, (cm->cm_frame_busaddr >> 3) |
-	    cm->cm_extra_frames);
+	if (cm->cm_extra_frames > 7)
+		cm->cm_extra_frames = 7;
+
+	sc->mfi_issue_cmd(sc,cm->cm_frame_busaddr,cm->cm_extra_frames);
+
+	if ((cm->cm_flags & MFI_CMD_POLLED) == 0)
+		return (0);
+
+	/* This is a polled command, so busy-wait for it to complete. */
+	while (hdr->cmd_status == 0xff) {
+		DELAY(1000);
+		tm -= 1;
+		if (tm <= 0)
+			break;
+	}
+
+	if (hdr->cmd_status == 0xff) {
+		device_printf(sc->mfi_dev, "Frame %p timed out "
+			      "command 0x%X\n", hdr, cm->cm_frame->dcmd.opcode);
+		return (ETIMEDOUT);
+	}
+
 	return (0);
 }
 
@@ -1170,11 +1796,46 @@
 		cm->cm_flags &= ~MFI_CMD_MAPPED;
 	}
 
+	cm->cm_flags |= MFI_CMD_COMPLETED;
+
 	if (cm->cm_complete != NULL)
 		cm->cm_complete(cm);
+	else
+		wakeup(cm);
+}
 
-	sc->mfi_flags &= ~MFI_FLAGS_QFRZN;
-	mfi_startio(sc);
+static int
+mfi_abort(struct mfi_softc *sc, struct mfi_command *cm_abort)
+{
+	struct mfi_command *cm;
+	struct mfi_abort_frame *abort;
+	int i = 0;
+
+	mtx_assert(&sc->mfi_io_lock, MA_OWNED);
+
+	if ((cm = mfi_dequeue_free(sc)) == NULL) {
+		return (EBUSY);
+	}
+
+	abort = &cm->cm_frame->abort;
+	abort->header.cmd = MFI_CMD_ABORT;
+	abort->header.flags = 0;
+	abort->abort_context = cm_abort->cm_frame->header.context;
+	abort->abort_mfi_addr_lo = cm_abort->cm_frame_busaddr;
+	abort->abort_mfi_addr_hi = 0;
+	cm->cm_data = NULL;
+	cm->cm_flags = MFI_CMD_POLLED;
+
+	sc->mfi_aen_cm->cm_aen_abort = 1;
+	mfi_mapcmd(sc, cm);
+	mfi_release_command(cm);
+
+	while (i < 5 && sc->mfi_aen_cm != NULL) {
+		msleep(&sc->mfi_aen_cm, &sc->mfi_io_lock, 0, "mfiabort", 5 * hz);
+		i++;
+	}
+
+	return (0);
 }
 
 int
@@ -1204,12 +1865,7 @@
 	cm->cm_total_frame_size = MFI_IO_FRAME_SIZE;
 	cm->cm_flags = MFI_CMD_POLLED | MFI_CMD_DATAOUT;
 
-	if ((error = mfi_mapcmd(sc, cm)) != 0) {
-		mfi_release_command(cm);
-		return (error);
-	}
-
-	error = mfi_polled_command(sc, cm);
+	error = mfi_mapcmd(sc, cm);
 	bus_dmamap_sync(sc->mfi_buffer_dmat, cm->cm_dmamap,
 	    BUS_DMASYNC_POSTWRITE);
 	bus_dmamap_unload(sc->mfi_buffer_dmat, cm->cm_dmamap);
@@ -1222,30 +1878,162 @@
 mfi_open(struct cdev *dev, int flags, int fmt, d_thread_t *td)
 {
 	struct mfi_softc *sc;
+	int error;
 
 	sc = dev->si_drv1;
-	sc->mfi_flags |= MFI_FLAGS_OPEN;
 
-	return (0);
+	mtx_lock(&sc->mfi_io_lock);
+	if (sc->mfi_detaching)
+		error = ENXIO;
+	else {
+		sc->mfi_flags |= MFI_FLAGS_OPEN;
+		error = 0;
+	}
+	mtx_unlock(&sc->mfi_io_lock);
+
+	return (error);
 }
 
 static int
 mfi_close(struct cdev *dev, int flags, int fmt, d_thread_t *td)
 {
 	struct mfi_softc *sc;
+	struct mfi_aen *mfi_aen_entry, *tmp;
 
 	sc = dev->si_drv1;
+
+	mtx_lock(&sc->mfi_io_lock);
 	sc->mfi_flags &= ~MFI_FLAGS_OPEN;
 
+	TAILQ_FOREACH_SAFE(mfi_aen_entry, &sc->mfi_aen_pids, aen_link, tmp) {
+		if (mfi_aen_entry->p == curproc) {
+			TAILQ_REMOVE(&sc->mfi_aen_pids, mfi_aen_entry,
+			    aen_link);
+			free(mfi_aen_entry, M_MFIBUF);
+		}
+	}
+	mtx_unlock(&sc->mfi_io_lock);
 	return (0);
 }
 
 static int
+mfi_config_lock(struct mfi_softc *sc, uint32_t opcode)
+{
+
+	switch (opcode) {
+	case MFI_DCMD_LD_DELETE:
+	case MFI_DCMD_CFG_ADD:
+	case MFI_DCMD_CFG_CLEAR:
+		sx_xlock(&sc->mfi_config_lock);
+		return (1);
+	default:
+		return (0);
+	}
+}
+
+static void
+mfi_config_unlock(struct mfi_softc *sc, int locked)
+{
+
+	if (locked)
+		sx_xunlock(&sc->mfi_config_lock);
+}
+
+/* Perform pre-issue checks on commands from userland and possibly veto them. */
+static int
+mfi_check_command_pre(struct mfi_softc *sc, struct mfi_command *cm)
+{
+	struct mfi_disk *ld, *ld2;
+	int error;
+
+	mtx_assert(&sc->mfi_io_lock, MA_OWNED);
+	error = 0;
+	switch (cm->cm_frame->dcmd.opcode) {
+	case MFI_DCMD_LD_DELETE:
+		TAILQ_FOREACH(ld, &sc->mfi_ld_tqh, ld_link) {
+			if (ld->ld_id == cm->cm_frame->dcmd.mbox[0])
+				break;
+		}
+		if (ld == NULL)
+			error = ENOENT;
+		else
+			error = mfi_disk_disable(ld);
+		break;
+	case MFI_DCMD_CFG_CLEAR:
+		TAILQ_FOREACH(ld, &sc->mfi_ld_tqh, ld_link) {
+			error = mfi_disk_disable(ld);
+			if (error)
+				break;
+		}
+		if (error) {
+			TAILQ_FOREACH(ld2, &sc->mfi_ld_tqh, ld_link) {
+				if (ld2 == ld)
+					break;
+				mfi_disk_enable(ld2);
+			}
+		}
+		break;
+	default:
+		break;
+	}
+	return (error);
+}
+
+/* Perform post-issue checks on commands from userland. */
+static void
+mfi_check_command_post(struct mfi_softc *sc, struct mfi_command *cm)
+{
+	struct mfi_disk *ld, *ldn;
+
+	switch (cm->cm_frame->dcmd.opcode) {
+	case MFI_DCMD_LD_DELETE:
+		TAILQ_FOREACH(ld, &sc->mfi_ld_tqh, ld_link) {
+			if (ld->ld_id == cm->cm_frame->dcmd.mbox[0])
+				break;
+		}
+		KASSERT(ld != NULL, ("volume dissappeared"));
+		if (cm->cm_frame->header.cmd_status == MFI_STAT_OK) {
+			mtx_unlock(&sc->mfi_io_lock);
+			mtx_lock(&Giant);
+			device_delete_child(sc->mfi_dev, ld->ld_dev);
+			mtx_unlock(&Giant);
+			mtx_lock(&sc->mfi_io_lock);
+		} else
+			mfi_disk_enable(ld);
+		break;
+	case MFI_DCMD_CFG_CLEAR:
+		if (cm->cm_frame->header.cmd_status == MFI_STAT_OK) {
+			mtx_unlock(&sc->mfi_io_lock);
+			mtx_lock(&Giant);
+			TAILQ_FOREACH_SAFE(ld, &sc->mfi_ld_tqh, ld_link, ldn) {
+				device_delete_child(sc->mfi_dev, ld->ld_dev);
+			}
+			mtx_unlock(&Giant);
+			mtx_lock(&sc->mfi_io_lock);
+		} else {
+			TAILQ_FOREACH(ld, &sc->mfi_ld_tqh, ld_link)
+				mfi_disk_enable(ld);
+		}
+		break;
+	case MFI_DCMD_CFG_ADD:
+		mfi_ldprobe(sc);
+		break;
+	}
+}
+
+static int
 mfi_ioctl(struct cdev *dev, u_long cmd, caddr_t arg, int flag, d_thread_t *td)
 {
 	struct mfi_softc *sc;
 	union mfi_statrequest *ms;
-	int error;
+	struct mfi_ioc_packet *ioc;
+	struct mfi_ioc_aen *aen;
+	struct mfi_command *cm = NULL;
+	uint32_t context;
+	uint8_t *sense_ptr;
+	uint8_t *data = NULL, *temp;
+	int i;
+	int error, locked;
 
 	sc = dev->si_drv1;
 	error = 0;
@@ -1262,14 +2050,509 @@
 			    sizeof(struct mfi_qstat));
 			break;
 		default:
-			error = ENOENT;
+			error = ENOIOCTL;
 			break;
 		}
 		break;
+	case MFIIO_QUERY_DISK:
+	{
+		struct mfi_query_disk *qd;
+		struct mfi_disk *ld;
+
+		qd = (struct mfi_query_disk *)arg;
+		mtx_lock(&sc->mfi_io_lock);
+		TAILQ_FOREACH(ld, &sc->mfi_ld_tqh, ld_link) {
+			if (ld->ld_id == qd->array_id)
+				break;
+		}
+		if (ld == NULL) {
+			qd->present = 0;
+			mtx_unlock(&sc->mfi_io_lock);
+			return (0);
+		}
+		qd->present = 1;
+		if (ld->ld_flags & MFI_DISK_FLAGS_OPEN)
+			qd->open = 1;
+		bzero(qd->devname, SPECNAMELEN + 1);
+		snprintf(qd->devname, SPECNAMELEN, "mfid%d", ld->ld_unit);
+		mtx_unlock(&sc->mfi_io_lock);
+		break;
+	}
+	case MFI_CMD:
+		ioc = (struct mfi_ioc_packet *)arg;
+
+		mtx_lock(&sc->mfi_io_lock);
+		if ((cm = mfi_dequeue_free(sc)) == NULL) {
+			mtx_unlock(&sc->mfi_io_lock);
+			return (EBUSY);
+		}
+		mtx_unlock(&sc->mfi_io_lock);
+		locked = 0;
+
+		/*
+		 * save off original context since copying from user
+		 * will clobber some data
+		 */
+		context = cm->cm_frame->header.context;
+
+		bcopy(ioc->mfi_frame.raw, cm->cm_frame,
+		      2 * MFI_DCMD_FRAME_SIZE);  /* this isn't quite right */
+		cm->cm_total_frame_size = (sizeof(union mfi_sgl) * ioc->mfi_sge_count) + ioc->mfi_sgl_off;
+		if (ioc->mfi_sge_count) {
+			cm->cm_sg =
+			    (union mfi_sgl *)&cm->cm_frame->bytes[ioc->mfi_sgl_off];
+		}
+		cm->cm_flags = 0;
+		if (cm->cm_frame->header.flags & MFI_FRAME_DATAIN)
+			cm->cm_flags |= MFI_CMD_DATAIN;
+		if (cm->cm_frame->header.flags & MFI_FRAME_DATAOUT)
+			cm->cm_flags |= MFI_CMD_DATAOUT;
+		/* Legacy app shim */
+		if (cm->cm_flags == 0)
+			cm->cm_flags |= MFI_CMD_DATAIN | MFI_CMD_DATAOUT;
+		cm->cm_len = cm->cm_frame->header.data_len;
+		if (cm->cm_flags & (MFI_CMD_DATAIN | MFI_CMD_DATAOUT)) {
+			cm->cm_data = data = malloc(cm->cm_len, M_MFIBUF,
+			    M_WAITOK | M_ZERO);
+			if (cm->cm_data == NULL) {
+				device_printf(sc->mfi_dev, "Malloc failed\n");
+				goto out;
+			}
+		} else {
+			cm->cm_data = 0;
+		}
+
+		/* restore header context */
+		cm->cm_frame->header.context = context;
+
+		temp = data;
+		if (cm->cm_flags & MFI_CMD_DATAOUT) {
+			for (i = 0; i < ioc->mfi_sge_count; i++) {
+				error = copyin(ioc->mfi_sgl[i].iov_base,
+				       temp,
+				       ioc->mfi_sgl[i].iov_len);
+				if (error != 0) {
+					device_printf(sc->mfi_dev,
+					    "Copy in failed\n");
+					goto out;
+				}
+				temp = &temp[ioc->mfi_sgl[i].iov_len];
+			}
+		}
+
+		if (cm->cm_frame->header.cmd == MFI_CMD_DCMD)
+			locked = mfi_config_lock(sc, cm->cm_frame->dcmd.opcode);
+
+		mtx_lock(&sc->mfi_io_lock);
+		error = mfi_check_command_pre(sc, cm);
+		if (error) {
+			mtx_unlock(&sc->mfi_io_lock);
+			goto out;
+		}
+
+		if ((error = mfi_wait_command(sc, cm)) != 0) {
+			device_printf(sc->mfi_dev,
+			    "Controller polled failed\n");
+			mtx_unlock(&sc->mfi_io_lock);
+			goto out;
+		}
+
+		mfi_check_command_post(sc, cm);
+		mtx_unlock(&sc->mfi_io_lock);
+
+		temp = data;
+		if (cm->cm_flags & MFI_CMD_DATAIN) {
+			for (i = 0; i < ioc->mfi_sge_count; i++) {
+				error = copyout(temp,
+					ioc->mfi_sgl[i].iov_base,
+					ioc->mfi_sgl[i].iov_len);
+				if (error != 0) {
+					device_printf(sc->mfi_dev,
+					    "Copy out failed\n");
+					goto out;
+				}
+				temp = &temp[ioc->mfi_sgl[i].iov_len];
+			}
+		}
+
+		if (ioc->mfi_sense_len) {
+			/* copy out sense */
+			sense_ptr = &((struct mfi_ioc_packet*)arg)
+			    ->mfi_frame.raw[0];
+			error = copyout(cm->cm_sense, sense_ptr,
+			    ioc->mfi_sense_len);
+			if (error != 0) {
+				device_printf(sc->mfi_dev,
+				    "Copy out failed\n");
+				goto out;
+			}
+		}
+
+		ioc->mfi_frame.hdr.cmd_status = cm->cm_frame->header.cmd_status;
+out:
+		mfi_config_unlock(sc, locked);
+		if (data)
+			free(data, M_MFIBUF);
+		if (cm) {
+			mtx_lock(&sc->mfi_io_lock);
+			mfi_release_command(cm);
+			mtx_unlock(&sc->mfi_io_lock);
+		}
+
+		break;
+	case MFI_SET_AEN:
+		aen = (struct mfi_ioc_aen *)arg;
+		error = mfi_aen_register(sc, aen->aen_seq_num,
+		    aen->aen_class_locale);
+
+		break;
+	case MFI_LINUX_CMD_2: /* Firmware Linux ioctl shim */
+		{
+			devclass_t devclass;
+			struct mfi_linux_ioc_packet l_ioc;
+			int adapter;
+
+			devclass = devclass_find("mfi");
+			if (devclass == NULL)
+				return (ENOENT);
+
+			error = copyin(arg, &l_ioc, sizeof(l_ioc));
+			if (error)
+				return (error);
+			adapter = l_ioc.lioc_adapter_no;
+			sc = devclass_get_softc(devclass, adapter);
+			if (sc == NULL)
+				return (ENOENT);
+			return (mfi_linux_ioctl_int(sc->mfi_cdev,
+			    cmd, arg, flag, td));
+			break;
+		}
+	case MFI_LINUX_SET_AEN_2: /* AEN Linux ioctl shim */
+		{
+			devclass_t devclass;
+			struct mfi_linux_ioc_aen l_aen;
+			int adapter;
+
+			devclass = devclass_find("mfi");
+			if (devclass == NULL)
+				return (ENOENT);
+
+			error = copyin(arg, &l_aen, sizeof(l_aen));
+			if (error)
+				return (error);
+			adapter = l_aen.laen_adapter_no;
+			sc = devclass_get_softc(devclass, adapter);
+			if (sc == NULL)
+				return (ENOENT);
+			return (mfi_linux_ioctl_int(sc->mfi_cdev,
+			    cmd, arg, flag, td));
+			break;
+		}
 	default:
+		device_printf(sc->mfi_dev, "IOCTL 0x%lx not handled\n", cmd);
 		error = ENOENT;
 		break;
 	}
 
 	return (error);
 }
+
+static int
+mfi_linux_ioctl_int(struct cdev *dev, u_long cmd, caddr_t arg, int flag, d_thread_t *td)
+{
+	struct mfi_softc *sc;
+	struct mfi_linux_ioc_packet l_ioc;
+	struct mfi_linux_ioc_aen l_aen;
+	struct mfi_command *cm = NULL;
+	struct mfi_aen *mfi_aen_entry;
+	uint8_t *sense_ptr;
+	uint32_t context;
+	uint8_t *data = NULL, *temp;
+	void *temp_convert;
+	int i;
+	int error, locked;
+
+	sc = dev->si_drv1;
+	error = 0;
+	switch (cmd) {
+	case MFI_LINUX_CMD_2: /* Firmware Linux ioctl shim */
+		error = copyin(arg, &l_ioc, sizeof(l_ioc));
+		if (error != 0)
+			return (error);
+
+		if (l_ioc.lioc_sge_count > MAX_LINUX_IOCTL_SGE) {
+			return (EINVAL);
+		}
+
+		mtx_lock(&sc->mfi_io_lock);
+		if ((cm = mfi_dequeue_free(sc)) == NULL) {
+			mtx_unlock(&sc->mfi_io_lock);
+			return (EBUSY);
+		}
+		mtx_unlock(&sc->mfi_io_lock);
+		locked = 0;
+
+		/*
+		 * save off original context since copying from user
+		 * will clobber some data
+		 */
+		context = cm->cm_frame->header.context;
+
+		bcopy(l_ioc.lioc_frame.raw, cm->cm_frame,
+		      2 * MFI_DCMD_FRAME_SIZE);	/* this isn't quite right */
+		cm->cm_total_frame_size = (sizeof(union mfi_sgl) * l_ioc.lioc_sge_count) + l_ioc.lioc_sgl_off;
+		if (l_ioc.lioc_sge_count)
+			cm->cm_sg =
+			    (union mfi_sgl *)&cm->cm_frame->bytes[l_ioc.lioc_sgl_off];
+		cm->cm_flags = 0;
+		if (cm->cm_frame->header.flags & MFI_FRAME_DATAIN)
+			cm->cm_flags |= MFI_CMD_DATAIN;
+		if (cm->cm_frame->header.flags & MFI_FRAME_DATAOUT)
+			cm->cm_flags |= MFI_CMD_DATAOUT;
+		cm->cm_len = cm->cm_frame->header.data_len;
+		if (cm->cm_flags & (MFI_CMD_DATAIN | MFI_CMD_DATAOUT)) {
+			cm->cm_data = data = malloc(cm->cm_len, M_MFIBUF,
+			    M_WAITOK | M_ZERO);
+			if (cm->cm_data == NULL) {
+				device_printf(sc->mfi_dev, "Malloc failed\n");
+				goto out;
+			}
+		} else {
+			cm->cm_data = 0;
+		}
+
+		/* restore header context */
+		cm->cm_frame->header.context = context;
+
+		temp = data;
+		if (cm->cm_flags & MFI_CMD_DATAOUT) {
+			for (i = 0; i < l_ioc.lioc_sge_count; i++) {
+				temp_convert =
+				    (void *)(uintptr_t)l_ioc.lioc_sgl[i].iov_base;
+				error = copyin(temp_convert,
+				       temp,
+				       l_ioc.lioc_sgl[i].iov_len);
+				if (error != 0) {
+					device_printf(sc->mfi_dev,
+					    "Copy in failed\n");
+					goto out;
+				}
+				temp = &temp[l_ioc.lioc_sgl[i].iov_len];
+			}
+		}
+
+		if (cm->cm_frame->header.cmd == MFI_CMD_DCMD)
+			locked = mfi_config_lock(sc, cm->cm_frame->dcmd.opcode);
+
+		mtx_lock(&sc->mfi_io_lock);
+		error = mfi_check_command_pre(sc, cm);
+		if (error) {
+			mtx_unlock(&sc->mfi_io_lock);
+			goto out;
+		}
+
+		if ((error = mfi_wait_command(sc, cm)) != 0) {
+			device_printf(sc->mfi_dev,
+			    "Controller polled failed\n");
+			mtx_unlock(&sc->mfi_io_lock);
+			goto out;
+		}
+
+		mfi_check_command_post(sc, cm);
+		mtx_unlock(&sc->mfi_io_lock);
+
+		temp = data;
+		if (cm->cm_flags & MFI_CMD_DATAIN) {
+			for (i = 0; i < l_ioc.lioc_sge_count; i++) {
+				temp_convert =
+				    (void *)(uintptr_t)l_ioc.lioc_sgl[i].iov_base;
+				error = copyout(temp,
+					temp_convert,
+					l_ioc.lioc_sgl[i].iov_len);
+				if (error != 0) {
+					device_printf(sc->mfi_dev,
+					    "Copy out failed\n");
+					goto out;
+				}
+				temp = &temp[l_ioc.lioc_sgl[i].iov_len];
+			}
+		}
+
+		if (l_ioc.lioc_sense_len) {
+			/* copy out sense */
+			sense_ptr = &((struct mfi_linux_ioc_packet*)arg)
+			    ->lioc_frame.raw[0];
+			error = copyout(cm->cm_sense, sense_ptr,
+			    l_ioc.lioc_sense_len);
+			if (error != 0) {
+				device_printf(sc->mfi_dev,
+				    "Copy out failed\n");
+				goto out;
+			}
+		}
+
+		error = copyout(&cm->cm_frame->header.cmd_status,
+			&((struct mfi_linux_ioc_packet*)arg)
+			->lioc_frame.hdr.cmd_status,
+			1);
+		if (error != 0) {
+			device_printf(sc->mfi_dev,
+				      "Copy out failed\n");
+			goto out;
+		}
+
+out:
+		mfi_config_unlock(sc, locked);
+		if (data)
+			free(data, M_MFIBUF);
+		if (cm) {
+			mtx_lock(&sc->mfi_io_lock);
+			mfi_release_command(cm);
+			mtx_unlock(&sc->mfi_io_lock);
+		}
+
+		return (error);
+	case MFI_LINUX_SET_AEN_2: /* AEN Linux ioctl shim */
+		error = copyin(arg, &l_aen, sizeof(l_aen));
+		if (error != 0)
+			return (error);
+		printf("AEN IMPLEMENTED for pid %d\n", curproc->p_pid);
+		mfi_aen_entry = malloc(sizeof(struct mfi_aen), M_MFIBUF,
+		    M_WAITOK);
+		mtx_lock(&sc->mfi_io_lock);
+		if (mfi_aen_entry != NULL) {
+			mfi_aen_entry->p = curproc;
+			TAILQ_INSERT_TAIL(&sc->mfi_aen_pids, mfi_aen_entry,
+			    aen_link);
+		}
+		error = mfi_aen_register(sc, l_aen.laen_seq_num,
+		    l_aen.laen_class_locale);
+
+		if (error != 0) {
+			TAILQ_REMOVE(&sc->mfi_aen_pids, mfi_aen_entry,
+			    aen_link);
+			free(mfi_aen_entry, M_MFIBUF);
+		}
+		mtx_unlock(&sc->mfi_io_lock);
+
+		return (error);
+	default:
+		device_printf(sc->mfi_dev, "IOCTL 0x%lx not handled\n", cmd);
+		error = ENOENT;
+		break;
+	}
+
+	return (error);
+}
+
+static int
+mfi_poll(struct cdev *dev, int poll_events, struct thread *td)
+{
+	struct mfi_softc *sc;
+	int revents = 0;
+
+	sc = dev->si_drv1;
+
+	if (poll_events & (POLLIN | POLLRDNORM)) {
+		if (sc->mfi_aen_triggered != 0) {
+			revents |= poll_events & (POLLIN | POLLRDNORM);
+			sc->mfi_aen_triggered = 0;
+		}
+		if (sc->mfi_aen_triggered == 0 && sc->mfi_aen_cm == NULL) {
+			revents |= POLLERR;
+		}
+	}
+
+	if (revents == 0) {
+		if (poll_events & (POLLIN | POLLRDNORM)) {
+			sc->mfi_poll_waiting = 1;
+			selrecord(td, &sc->mfi_select);
+		}
+	}
+
+	return revents;
+}
+
+
+static void
+mfi_dump_all(void)
+{
+	struct mfi_softc *sc;
+	struct mfi_command *cm;
+	devclass_t dc;
+	time_t deadline;
+	int timedout;
+	int i;
+
+	dc = devclass_find("mfi");
+	if (dc == NULL) {
+		printf("No mfi dev class\n");
+		return;
+	}
+
+	for (i = 0; ; i++) {
+		sc = devclass_get_softc(dc, i);
+		if (sc == NULL)
+			break;
+		device_printf(sc->mfi_dev, "Dumping\n\n");
+		timedout = 0;
+		deadline = time_uptime - MFI_CMD_TIMEOUT;
+		mtx_lock(&sc->mfi_io_lock);
+		TAILQ_FOREACH(cm, &sc->mfi_busy, cm_link) {
+			if (cm->cm_timestamp < deadline) {
+				device_printf(sc->mfi_dev,
+				    "COMMAND %p TIMEOUT AFTER %d SECONDS\n", cm,
+				    (int)(time_uptime - cm->cm_timestamp));
+				MFI_PRINT_CMD(cm);
+				timedout++;
+			}
+		}
+
+#if 0
+		if (timedout)
+			MFI_DUMP_CMDS(SC);
+#endif
+
+		mtx_unlock(&sc->mfi_io_lock);
+	}
+
+	return;
+}
+
+static void
+mfi_timeout(void *data)
+{
+	struct mfi_softc *sc = (struct mfi_softc *)data;
+	struct mfi_command *cm;
+	time_t deadline;
+	int timedout = 0;
+
+	deadline = time_uptime - MFI_CMD_TIMEOUT;
+	mtx_lock(&sc->mfi_io_lock);
+	TAILQ_FOREACH(cm, &sc->mfi_busy, cm_link) {
+		if (sc->mfi_aen_cm == cm)
+			continue;
+		if ((sc->mfi_aen_cm != cm) && (cm->cm_timestamp < deadline)) {
+			device_printf(sc->mfi_dev,
+			    "COMMAND %p TIMEOUT AFTER %d SECONDS\n", cm,
+			    (int)(time_uptime - cm->cm_timestamp));
+			MFI_PRINT_CMD(cm);
+			MFI_VALIDATE_CMD(sc, cm);
+			timedout++;
+		}
+	}
+
+#if 0
+	if (timedout)
+		MFI_DUMP_CMDS(SC);
+#endif
+
+	mtx_unlock(&sc->mfi_io_lock);
+
+	callout_reset(&sc->mfi_watchdog_callout, MFI_CMD_TIMEOUT * hz,
+	    mfi_timeout, sc);
+
+	if (0)
+		mfi_dump_all();
+	return;
+}
Index: mfi_ioctl.h
===================================================================
RCS file: /home/cvs/src/sys/dev/mfi/mfi_ioctl.h,v
retrieving revision 1.1
retrieving revision 1.2
diff -L sys/dev/mfi/mfi_ioctl.h -L sys/dev/mfi/mfi_ioctl.h -u -r1.1 -r1.2
--- sys/dev/mfi/mfi_ioctl.h
+++ sys/dev/mfi/mfi_ioctl.h
@@ -25,8 +25,14 @@
  */
 
 #include <sys/cdefs.h>
-__FBSDID("$FreeBSD: src/sys/dev/mfi/mfi_ioctl.h,v 1.1.2.1 2006/04/04 03:24:48 scottl Exp $");
-__MBSDID("$MidnightBSD");
+__FBSDID("$FreeBSD: src/sys/dev/mfi/mfi_ioctl.h,v 1.5 2007/05/10 15:33:41 scottl Exp $");
+
+#if defined(__amd64__) /* Assume amd64 wants 32 bit Linux */
+struct iovec32 {
+	u_int32_t	iov_base;
+	int		iov_len;
+};
+#endif
 
 #define MFIQ_FREE	0
 #define MFIQ_BIO	1
@@ -44,5 +50,78 @@
 	struct mfi_qstat	ms_qstat;
 };
 
+#define MAX_IOCTL_SGE	16
+
+struct mfi_ioc_packet {
+	uint16_t	mfi_adapter_no;
+	uint16_t	mfi_pad1;
+	uint32_t	mfi_sgl_off;
+	uint32_t	mfi_sge_count;
+	uint32_t	mfi_sense_off;
+	uint32_t	mfi_sense_len;
+	union {
+		uint8_t raw[128];
+		struct mfi_frame_header hdr;
+	} mfi_frame;
+
+	struct iovec mfi_sgl[MAX_IOCTL_SGE];
+} __packed;
+
+struct mfi_ioc_aen {
+	uint16_t	aen_adapter_no;
+	uint16_t	aen_pad1;
+	uint32_t	aen_seq_num;
+	uint32_t	aen_class_locale;
+} __packed;
+
+#define MFI_CMD		_IOWR('M', 1, struct mfi_ioc_packet)
+#define MFI_SET_AEN	_IOW('M', 3, struct mfi_ioc_aen)
+
+#define MAX_LINUX_IOCTL_SGE	16
+
+struct mfi_linux_ioc_packet {
+	uint16_t	lioc_adapter_no;
+	uint16_t	lioc_pad1;
+	uint32_t	lioc_sgl_off;
+	uint32_t	lioc_sge_count;
+	uint32_t	lioc_sense_off;
+	uint32_t	lioc_sense_len;
+	union {
+		uint8_t raw[128];
+		struct mfi_frame_header hdr;
+	} lioc_frame;
+
+#if defined(__amd64__) /* Assume amd64 wants 32 bit Linux */
+	struct iovec32 lioc_sgl[MAX_LINUX_IOCTL_SGE];
+#else
+	struct iovec lioc_sgl[MAX_LINUX_IOCTL_SGE];
+#endif
+} __packed;
+
 #define MFIIO_STATS	_IOWR('Q', 101, union mfi_statrequest)
 
+struct mfi_linux_ioc_aen {
+	uint16_t	laen_adapter_no;
+	uint16_t	laen_pad1;
+	uint32_t	laen_seq_num;
+	uint32_t	laen_class_locale;
+} __packed;
+
+struct mfi_query_disk {
+	uint8_t	array_id;
+	uint8_t	present;
+	uint8_t	open;
+	uint8_t reserved;	/* reserved for future use */
+	char	devname[SPECNAMELEN + 1];
+} __packed;
+
+#define MFIIO_QUERY_DISK	_IOWR('Q', 102, struct mfi_query_disk)
+
+/*
+ * Create a second set so the FreeBSD native ioctl doesn't
+ * conflict in FreeBSD ioctl handler.  Translate in mfi_linux.c.
+ */
+#define MFI_LINUX_CMD		0xc1144d01
+#define MFI_LINUX_SET_AEN	0x400c4d03
+#define MFI_LINUX_CMD_2		0xc1144d02
+#define MFI_LINUX_SET_AEN_2	0x400c4d04
--- /dev/null
+++ sys/dev/mfi/mfi_cam.c
@@ -0,0 +1,386 @@
+/*-
+ * Copyright 2007 Scott Long
+ * 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.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD: src/sys/dev/mfi/mfi_cam.c,v 1.2.2.1 2007/10/19 15:23:23 scottl Exp $");
+
+#include "opt_mfi.h"
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/kernel.h>
+#include <sys/malloc.h>
+#include <sys/module.h>
+#include <sys/selinfo.h>
+#include <sys/bus.h>
+#include <sys/conf.h>
+#include <sys/eventhandler.h>
+#include <sys/rman.h>
+#include <sys/bus_dma.h>
+#include <sys/bio.h>
+#include <sys/ioccom.h>
+#include <sys/uio.h>
+#include <sys/proc.h>
+#include <sys/signalvar.h>
+
+#include <cam/cam.h>
+#include <cam/cam_ccb.h>
+#include <cam/cam_debug.h>
+#include <cam/cam_sim.h>
+#include <cam/cam_xpt_sim.h>
+#include <cam/scsi/scsi_all.h>
+#include <cam/scsi/scsi_message.h>
+
+#include <sys/bus.h>
+#include <sys/conf.h>
+#include <machine/md_var.h>
+#include <machine/bus.h>
+#include <machine/resource.h>
+#include <sys/rman.h>
+
+#include <dev/mfi/mfireg.h>
+#include <dev/mfi/mfi_ioctl.h>
+#include <dev/mfi/mfivar.h>
+
+struct mfip_softc {
+	device_t	dev;
+	struct mfi_softc *mfi_sc;
+	struct cam_devq *devq;
+	struct cam_sim	*sim;
+	struct cam_path	*path;
+};
+
+static int	mfip_probe(device_t);
+static int	mfip_attach(device_t);
+static int	mfip_detach(device_t);
+static void	mfip_cam_action(struct cam_sim *, union ccb *);
+static void	mfip_cam_poll(struct cam_sim *);
+static struct mfi_command * mfip_start(void *);
+static void	mfip_done(struct mfi_command *cm);
+
+static devclass_t	mfip_devclass;
+static device_method_t	mfip_methods[] = {
+	DEVMETHOD(device_probe,		mfip_probe),
+	DEVMETHOD(device_attach,	mfip_attach),
+	DEVMETHOD(device_detach,	mfip_detach),
+	{0, 0}
+};
+static driver_t mfip_driver = {
+	"mfip",
+	mfip_methods,
+	sizeof(struct mfip_softc)
+};
+DRIVER_MODULE(mfip, mfi, mfip_driver, mfip_devclass, 0, 0);
+MODULE_DEPEND(mfip, cam, 1, 1, 1);
+
+#define ccb_mfip_ptr sim_priv.entries[0].ptr
+
+static int
+mfip_probe(device_t dev)
+{
+
+	device_set_desc(dev, "SCSI Passthrough Bus");
+	return (0);
+}
+
+static int
+mfip_attach(device_t dev)
+{
+	struct mfip_softc *sc;
+	struct mfi_softc *mfisc;
+
+	sc = device_get_softc(dev);
+	if (sc == NULL)
+		return (EINVAL);
+
+	mfisc = device_get_softc(device_get_parent(dev));
+	sc->dev = dev;
+	sc->mfi_sc = mfisc;
+	mfisc->mfi_cam_start = mfip_start;
+
+	if ((sc->devq = cam_simq_alloc(MFI_SCSI_MAX_CMDS)) == NULL)
+		return (ENOMEM);
+
+	sc->sim = cam_sim_alloc(mfip_cam_action, mfip_cam_poll, "mfi", sc,
+				device_get_unit(dev), &mfisc->mfi_io_lock, 1,
+				MFI_SCSI_MAX_CMDS, sc->devq);
+	if (sc->sim == NULL) {
+		cam_simq_free(sc->devq);
+		device_printf(dev, "CAM SIM attach failed\n");
+		return (EINVAL);
+	}
+
+	mtx_lock(&mfisc->mfi_io_lock);
+	if (xpt_bus_register(sc->sim, dev, 0) != 0) {
+		device_printf(dev, "XPT bus registration failed\n");
+		cam_sim_free(sc->sim, FALSE);
+		cam_simq_free(sc->devq);
+		mtx_unlock(&mfisc->mfi_io_lock);
+		return (EINVAL);
+	}
+	mtx_unlock(&mfisc->mfi_io_lock);
+
+	return (0);
+}
+
+static int
+mfip_detach(device_t dev)
+{
+	struct mfip_softc *sc;
+
+	sc = device_get_softc(dev);
+	if (sc == NULL)
+		return (EINVAL);
+
+	if (sc->sim != NULL) {
+		mtx_lock(&sc->mfi_sc->mfi_io_lock);
+		xpt_bus_deregister(cam_sim_path(sc->sim));
+		cam_sim_free(sc->sim, FALSE);
+		mtx_unlock(&sc->mfi_sc->mfi_io_lock);
+	}
+
+	if (sc->devq != NULL)
+		cam_simq_free(sc->devq);
+
+	return (0);
+}
+
+static void
+mfip_cam_action(struct cam_sim *sim, union ccb *ccb)
+{
+	struct mfip_softc *sc = cam_sim_softc(sim);
+	struct mfi_softc *mfisc = sc->mfi_sc;
+
+	mtx_assert(&mfisc->mfi_io_lock, MA_OWNED);
+
+	switch (ccb->ccb_h.func_code) {
+	case XPT_PATH_INQ:
+	{
+		struct ccb_pathinq *cpi = &ccb->cpi;
+
+		cpi->version_num = 1;
+		cpi->hba_inquiry = PI_SDTR_ABLE|PI_TAG_ABLE|PI_WIDE_16;
+		cpi->target_sprt = 0;
+		cpi->hba_misc = PIM_NOBUSRESET|PIM_SEQSCAN;
+		cpi->hba_eng_cnt = 0;
+		cpi->max_target = MFI_SCSI_MAX_TARGETS;
+		cpi->max_lun = MFI_SCSI_MAX_LUNS;
+		cpi->initiator_id = MFI_SCSI_INITIATOR_ID;
+		strncpy(cpi->sim_vid, "FreeBSD", SIM_IDLEN);
+		strncpy(cpi->hba_vid, "LSI", HBA_IDLEN);
+		strncpy(cpi->dev_name, cam_sim_name(sim), DEV_IDLEN);
+		cpi->unit_number = cam_sim_unit(sim);
+		cpi->bus_id = cam_sim_bus(sim);
+		cpi->base_transfer_speed = 150000;
+		cpi->transport = XPORT_SAS;
+		cpi->transport_version = 0;
+		cpi->protocol = PROTO_SCSI;
+		cpi->protocol_version = SCSI_REV_2;
+		cpi->ccb_h.status = CAM_REQ_CMP;
+		break;
+	}
+	case XPT_RESET_BUS:
+		ccb->ccb_h.status = CAM_REQ_CMP;
+		break;
+	case XPT_RESET_DEV:
+		ccb->ccb_h.status = CAM_REQ_CMP;
+		break;
+	case XPT_GET_TRAN_SETTINGS:
+	{
+		struct ccb_trans_settings_sas *sas =
+		    &ccb->cts.xport_specific.sas;
+
+		ccb->cts.protocol = PROTO_SCSI;
+		ccb->cts.protocol_version = SCSI_REV_2;
+		ccb->cts.transport = XPORT_SAS;
+		ccb->cts.transport_version = 0;
+
+		sas->valid &= ~CTS_SAS_VALID_SPEED;
+		sas->bitrate = 150000;
+
+		ccb->ccb_h.status = CAM_REQ_CMP;
+		break;
+	}
+	case XPT_SET_TRAN_SETTINGS:
+		ccb->ccb_h.status = CAM_FUNC_NOTAVAIL;
+		break;
+	case XPT_SCSI_IO:
+	{
+		struct ccb_hdr		*ccbh = &ccb->ccb_h;
+		struct ccb_scsiio	*csio = &ccb->csio;
+
+		ccbh->status = CAM_REQ_INPROG;
+		if (csio->cdb_len > MFI_SCSI_MAX_CDB_LEN) {
+			ccbh->status = CAM_REQ_INVALID;
+			break;
+		}
+		if ((ccbh->flags & CAM_DIR_MASK) != CAM_DIR_NONE) {
+			if (ccbh->flags & CAM_DATA_PHYS) {
+				ccbh->status = CAM_REQ_INVALID;
+				break;
+			}
+			if (ccbh->flags & CAM_SCATTER_VALID) {
+				ccbh->status = CAM_REQ_INVALID;
+				break;
+			}
+		}
+
+		ccbh->ccb_mfip_ptr = sc;
+		TAILQ_INSERT_TAIL(&mfisc->mfi_cam_ccbq, ccbh, sim_links.tqe);
+		mfi_startio(mfisc);
+		return;
+	}
+	default:
+		ccb->ccb_h.status = CAM_REQ_INVALID;
+		break;
+	}
+
+	xpt_done(ccb);
+	return;
+}
+
+static struct mfi_command *
+mfip_start(void *data)
+{
+	union ccb *ccb = data;
+	struct ccb_hdr *ccbh = &ccb->ccb_h;
+	struct ccb_scsiio *csio = &ccb->csio;
+	struct mfip_softc *sc;
+	struct mfi_pass_frame *pt;
+	struct mfi_command *cm;
+
+	sc = ccbh->ccb_mfip_ptr;
+
+	if ((cm = mfi_dequeue_free(sc->mfi_sc)) == NULL)
+		return (NULL);
+
+	pt = &cm->cm_frame->pass;
+	pt->header.cmd = MFI_CMD_PD_SCSI_IO;
+	pt->header.cmd_status = 0;
+	pt->header.scsi_status = 0;
+	pt->header.target_id = ccbh->target_id;
+	pt->header.lun_id = ccbh->target_lun;
+	pt->header.flags = 0;
+	pt->header.timeout = 0;
+	pt->header.data_len = csio->dxfer_len;
+	pt->header.sense_len = MFI_SENSE_LEN;
+	pt->header.cdb_len = csio->cdb_len;
+	pt->sense_addr_lo = cm->cm_sense_busaddr;
+	pt->sense_addr_hi = 0;
+	if (ccbh->flags & CAM_CDB_POINTER)
+		bcopy(csio->cdb_io.cdb_ptr, &pt->cdb[0], csio->cdb_len);
+	else
+		bcopy(csio->cdb_io.cdb_bytes, &pt->cdb[0], csio->cdb_len);
+	cm->cm_complete = mfip_done;
+	cm->cm_private = ccb;
+	cm->cm_sg = &pt->sgl;
+	cm->cm_total_frame_size = MFI_PASS_FRAME_SIZE;
+	cm->cm_data = csio->data_ptr;
+	cm->cm_len = csio->dxfer_len;
+	switch (ccbh->flags & CAM_DIR_MASK) {
+	case CAM_DIR_IN:
+		cm->cm_flags = MFI_CMD_DATAIN;
+		break;
+	case CAM_DIR_OUT:
+		cm->cm_flags = MFI_CMD_DATAOUT;
+		break;
+	case CAM_DIR_NONE:
+	default:
+		cm->cm_data = NULL;
+		cm->cm_len = 0;
+		cm->cm_flags = 0;
+		break;
+	}
+
+	TAILQ_REMOVE(&sc->mfi_sc->mfi_cam_ccbq, ccbh, sim_links.tqe);
+	return (cm);
+}
+
+static void
+mfip_done(struct mfi_command *cm)
+{
+	union ccb *ccb = cm->cm_private;
+	struct ccb_hdr *ccbh = &ccb->ccb_h;
+	struct ccb_scsiio *csio = &ccb->csio;
+	struct mfip_softc *sc;
+	struct mfi_pass_frame *pt;
+
+	sc = ccbh->ccb_mfip_ptr;
+	pt = &cm->cm_frame->pass;
+
+	switch (pt->header.cmd_status) {
+	case MFI_STAT_OK:
+	{
+		uint8_t command, device;
+
+		ccbh->status = CAM_REQ_CMP;
+		csio->scsi_status = pt->header.scsi_status;
+		if (ccbh->flags & CAM_CDB_POINTER)
+			command = ccb->csio.cdb_io.cdb_ptr[0];
+		else
+			command = ccb->csio.cdb_io.cdb_bytes[0];
+		if (command == INQUIRY) {
+			device = ccb->csio.data_ptr[0] & 0x1f;
+			if ((device == T_DIRECT) || (device == T_PROCESSOR))
+				csio->data_ptr[0] =
+				     (device & 0xe0) | T_NODEVICE;
+		}
+		break;
+	}
+	case MFI_STAT_SCSI_DONE_WITH_ERROR:
+	{
+		int sense_len;
+
+		ccbh->status = CAM_SCSI_STATUS_ERROR | CAM_AUTOSNS_VALID;
+		csio->scsi_status = pt->header.scsi_status;
+		sense_len = min(pt->header.sense_len, sizeof(struct scsi_sense_data));
+		bzero(&csio->sense_data, sizeof(struct scsi_sense_data));
+		bcopy(&cm->cm_sense->data[0], &csio->sense_data, sense_len);
+		break;
+	}
+	case MFI_STAT_DEVICE_NOT_FOUND:
+		ccbh->status = CAM_SEL_TIMEOUT;
+		break;
+	case MFI_STAT_SCSI_IO_FAILED:
+		ccbh->status = CAM_REQ_CMP_ERR;
+		csio->scsi_status = pt->header.scsi_status;
+		break;
+	default:
+		ccbh->status = CAM_REQ_CMP_ERR;
+		csio->scsi_status = pt->header.scsi_status;
+		break;
+	}
+
+	mfi_release_command(cm);
+	xpt_done(ccb);
+}
+
+static void
+mfip_cam_poll(struct cam_sim *sim)
+{
+	return;
+}
+
Index: mfi_pci.c
===================================================================
RCS file: /home/cvs/src/sys/dev/mfi/mfi_pci.c,v
retrieving revision 1.1
retrieving revision 1.2
diff -L sys/dev/mfi/mfi_pci.c -L sys/dev/mfi/mfi_pci.c -u -r1.1 -r1.2
--- sys/dev/mfi/mfi_pci.c
+++ sys/dev/mfi/mfi_pci.c
@@ -23,10 +23,35 @@
  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  * SUCH DAMAGE.
  */
+/*-
+ * Copyright (c) 2007 LSI Corp.
+ * Copyright (c) 2007 Rajesh Prabhakaran.
+ * 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.
+ */
 
 #include <sys/cdefs.h>
-__FBSDID("$FreeBSD: src/sys/dev/mfi/mfi_pci.c,v 1.1.2.1 2006/04/04 03:24:48 scottl Exp $");
-__MBSDID("$MidnightBSD$");
+__FBSDID("$FreeBSD: src/sys/dev/mfi/mfi_pci.c,v 1.9 2007/08/25 23:58:45 scottl Exp $");
 
 /* PCI/PCI-X/PCIe bus interface for the LSI MegaSAS controllers */
 
@@ -35,11 +60,13 @@
 #include <sys/param.h>
 #include <sys/systm.h>
 #include <sys/kernel.h>
+#include <sys/selinfo.h>
 #include <sys/module.h>
 #include <sys/bus.h>
 #include <sys/conf.h>
 #include <sys/bio.h>
 #include <sys/malloc.h>
+#include <sys/uio.h>
 
 #include <machine/bus.h>
 #include <machine/resource.h>
@@ -87,8 +114,10 @@
 	int		flags;
 	const char	*desc;
 } mfi_identifiers[] = {
-	{0x1000, 0x0411, 0xffff, 0xffff, 0, "LSI MegaSAS 1064R"},
-	{0x1028, 0x0015, 0xffff, 0xffff, 0, "Dell PERC 5/i"},
+	{0x1000, 0x0411, 0xffff, 0xffff, MFI_FLAGS_1064R, "LSI MegaSAS 1064R"}, /* Brocton IOP */
+	{0x1000, 0x0413, 0xffff, 0xffff, MFI_FLAGS_1064R, "LSI MegaSAS 1064R"}, /* Verde ZCR */
+	{0x1028, 0x0015, 0xffff, 0xffff, MFI_FLAGS_1064R, "Dell PERC 5/i"},
+	{0x1000, 0x0060, 0xffff, 0xffff, MFI_FLAGS_1078,  "LSI MegaSAS 1078"},
 	{0, 0, 0, 0, 0, NULL}
 };
 
@@ -193,21 +222,29 @@
 mfi_pci_detach(device_t dev)
 {
 	struct mfi_softc *sc;
-	struct mfi_ld *ld;
+	struct mfi_disk *ld;
 	int error;
 
 	sc = device_get_softc(dev);
 
-	if ((sc->mfi_flags & MFI_FLAGS_OPEN) != 0)
+	sx_xlock(&sc->mfi_config_lock);
+	mtx_lock(&sc->mfi_io_lock);
+	if ((sc->mfi_flags & MFI_FLAGS_OPEN) != 0) {
+		mtx_unlock(&sc->mfi_io_lock);
+		sx_xunlock(&sc->mfi_config_lock);
 		return (EBUSY);
+	}
+	sc->mfi_detaching = 1;
+	mtx_unlock(&sc->mfi_io_lock);
 
-        while ((ld = TAILQ_FIRST(&sc->mfi_ld_tqh)) != NULL) {
-                error = device_delete_child(dev, ld->ld_disk);
-		if (error)
+	while ((ld = TAILQ_FIRST(&sc->mfi_ld_tqh)) != NULL) {
+		if ((error = device_delete_child(dev, ld->ld_dev)) != 0) {
+			sc->mfi_detaching = 0;
+			sx_xunlock(&sc->mfi_config_lock);
 			return (error);
-		TAILQ_REMOVE(&sc->mfi_ld_tqh, ld, ld_link);
-		free(ld, M_MFIBUF);
+		}
 	}
+	sx_xunlock(&sc->mfi_config_lock);
 
 	EVENTHANDLER_DEREGISTER(shutdown_final, sc->mfi_eh);
 
Index: mfireg.h
===================================================================
RCS file: /home/cvs/src/sys/dev/mfi/mfireg.h,v
retrieving revision 1.1
retrieving revision 1.2
diff -L sys/dev/mfi/mfireg.h -L sys/dev/mfi/mfireg.h -u -r1.1 -r1.2
--- sys/dev/mfi/mfireg.h
+++ sys/dev/mfi/mfireg.h
@@ -23,13 +23,38 @@
  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  * SUCH DAMAGE.
  */
+/*-
+ * Copyright (c) 2007 LSI Corp.
+ * Copyright (c) 2007 Rajesh Prabhakaran.
+ * 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.
+ */
 
 #ifndef _MFIREG_H
 #define _MFIREG_H
 
 #include <sys/cdefs.h>
-__FBSDID("$FreeBSD: src/sys/dev/mfi/mfireg.h,v 1.1.2.1 2006/04/04 03:24:48 scottl Exp $");
-__MBSDID("$MidnightBSD$");
+__FBSDID("$FreeBSD: src/sys/dev/mfi/mfireg.h,v 1.10.4.1 2008/02/04 14:54:21 ambrisko Exp $");
 
 /*
  * MegaRAID SAS MFI firmware definitions
@@ -57,6 +82,17 @@
 #define MFI_IQP		0x40	/* Inbound queue port */
 #define MFI_OQP		0x44	/* Outbound queue port */
 
+/*
+ * 1078 specific related register
+ */
+#define MFI_ODR0	0x9c 		/* outbound doorbell register0 */
+#define MFI_ODCR0	0xa0 		/* outbound doorbell clear register0  */
+#define MFI_OSP0	0xb0 		/* outbound scratch pad0  */
+#define MFI_1078_EIM	0x80000004 	/* 1078 enable intrrupt mask  */
+#define MFI_RMI		0x2 		/* reply message interrupt  */       
+#define MFI_1078_RM	0x80000000 	/* reply 1078 message interrupt  */
+#define MFI_ODC		0x4 		/* outbound doorbell change interrupt */
+
 /* Bits for MFI_OSTS */
 #define MFI_OSTS_INTR_VALID	0x00000002
 
@@ -102,12 +138,21 @@
 /* Direct commands */
 typedef enum {
 	MFI_DCMD_CTRL_GETINFO =		0x01010000,
+	MFI_DCMD_CTRL_MFC_DEFAULTS_GET =0x010e0201,
+	MFI_DCMD_CTRL_MFC_DEFAULTS_SET =0x010e0202,
 	MFI_DCMD_CTRL_FLUSHCACHE =	0x01101000,
 	MFI_DCMD_CTRL_SHUTDOWN =	0x01050000,
 	MFI_DCMD_CTRL_EVENT_GETINFO =	0x01040100,
 	MFI_DCMD_CTRL_EVENT_GET =	0x01040300,
 	MFI_DCMD_CTRL_EVENT_WAIT =	0x01040500,
+	MFI_DCMD_LD_GET_LIST =		0x03010000,
+	MFI_DCMD_LD_GET_INFO =		0x03020000,
 	MFI_DCMD_LD_GET_PROP =		0x03030000,
+	MFI_DCMD_LD_SET_PROP =		0x03040000,
+	MFI_DCMD_LD_DELETE =		0x03090000,
+	MFI_DCMD_CFG_READ =		0x04010000,
+	MFI_DCMD_CFG_ADD =		0x04020000,
+	MFI_DCMD_CFG_CLEAR =		0x04030000,
 	MFI_DCMD_CLUSTER =		0x08000000,
 	MFI_DCMD_CLUSTER_RESET_ALL =	0x08010100,
 	MFI_DCMD_CLUSTER_RESET_LD =	0x08010200
@@ -121,7 +166,7 @@
 #define MFI_SHUTDOWN_SPINDOWN	0x01
 
 /*
- * MFI Frmae flags
+ * MFI Frame flags
  */
 #define MFI_FRAME_POST_IN_REPLY_QUEUE		0x0000
 #define MFI_FRAME_DONT_POST_IN_REPLY_QUEUE	0x0001
@@ -219,29 +264,45 @@
 } mfi_evt_locale_t;
 
 typedef enum {
-        MR_EVT_ARGS_NONE =		0x00,
-        MR_EVT_ARGS_CDB_SENSE,
-        MR_EVT_ARGS_LD,
-        MR_EVT_ARGS_LD_COUNT,
-        MR_EVT_ARGS_LD_LBA,
-        MR_EVT_ARGS_LD_OWNER,
-        MR_EVT_ARGS_LD_LBA_PD_LBA,
-        MR_EVT_ARGS_LD_PROG,
-        MR_EVT_ARGS_LD_STATE,
-        MR_EVT_ARGS_LD_STRIP,
-        MR_EVT_ARGS_PD,
-        MR_EVT_ARGS_PD_ERR,
-        MR_EVT_ARGS_PD_LBA,
-        MR_EVT_ARGS_PD_LBA_LD,
-        MR_EVT_ARGS_PD_PROG,
-        MR_EVT_ARGS_PD_STATE,
-        MR_EVT_ARGS_PCI,
-        MR_EVT_ARGS_RATE,
-        MR_EVT_ARGS_STR,
-        MR_EVT_ARGS_TIME,
-        MR_EVT_ARGS_ECC
+	MR_EVT_ARGS_NONE =		0x00,
+	MR_EVT_ARGS_CDB_SENSE,
+	MR_EVT_ARGS_LD,
+	MR_EVT_ARGS_LD_COUNT,
+	MR_EVT_ARGS_LD_LBA,
+	MR_EVT_ARGS_LD_OWNER,
+	MR_EVT_ARGS_LD_LBA_PD_LBA,
+	MR_EVT_ARGS_LD_PROG,
+	MR_EVT_ARGS_LD_STATE,
+	MR_EVT_ARGS_LD_STRIP,
+	MR_EVT_ARGS_PD,
+	MR_EVT_ARGS_PD_ERR,
+	MR_EVT_ARGS_PD_LBA,
+	MR_EVT_ARGS_PD_LBA_LD,
+	MR_EVT_ARGS_PD_PROG,
+	MR_EVT_ARGS_PD_STATE,
+	MR_EVT_ARGS_PCI,
+	MR_EVT_ARGS_RATE,
+	MR_EVT_ARGS_STR,
+	MR_EVT_ARGS_TIME,
+	MR_EVT_ARGS_ECC
 } mfi_evt_args;
 
+typedef enum {
+	MR_LD_CACHE_WRITE_BACK =	0x01,
+	MR_LD_CACHE_WRITE_ADAPTIVE =	0x02,
+	MR_LD_CACHE_READ_AHEAD =	0x04,
+	MR_LD_CACHE_READ_ADAPTIVE =	0x08,
+	MR_LD_CACHE_WRITE_CACHE_BAD_BBU=0x10,
+	MR_LD_CACHE_ALLOW_WRITE_CACHE =	0x20,
+	MR_LD_CACHE_ALLOW_READ_CACHE =	0x40
+} mfi_ld_cache;
+
+typedef enum {
+	MR_PD_CACHE_UNCHANGED  =	0,
+	MR_PD_CACHE_ENABLE =		1,
+	MR_PD_CACHE_DISABLE =		2
+} mfi_pd_cache;
+
 /*
  * Other propertities and definitions
  */
@@ -256,7 +317,8 @@
 #define MFI_FRAME_SIZE		64
 #define MFI_MBOX_SIZE		12
 
-#define MFI_POLL_TIMEOUT_SECS	10
+/* Firmware flashing can take 40s */
+#define MFI_POLL_TIMEOUT_SECS	50
 
 /* Allow for speedier math calculations */
 #define MFI_SECTOR_LEN		512
@@ -290,6 +352,8 @@
 	uint32_t	context;
 	uint32_t	pad0;
 	uint16_t	flags;
+#define MFI_FRAME_DATAOUT	0x08
+#define MFI_FRAME_DATAIN	0x10
 	uint16_t	timeout;
 	uint32_t	data_len;
 } __packed;
@@ -454,6 +518,51 @@
 	char		 build_time[16];
 } __packed;
 
+/* Controller default settings */
+struct mfi_defaults {
+	uint64_t	sas_addr;
+	uint8_t		phy_polarity;
+	uint8_t		background_rate;
+	uint8_t		stripe_size;
+	uint8_t		flush_time;
+	uint8_t		write_back;
+	uint8_t		read_ahead;
+	uint8_t		cache_when_bbu_bad;
+	uint8_t		cached_io;
+	uint8_t		smart_mode;
+	uint8_t		alarm_disable;
+	uint8_t		coercion;
+	uint8_t		zrc_config;
+	uint8_t		dirty_led_shows_drive_activity;
+	uint8_t		bios_continue_on_error;
+	uint8_t		spindown_mode;
+	uint8_t		allowed_device_types;
+	uint8_t		allow_mix_in_enclosure;
+	uint8_t		allow_mix_in_ld;
+	uint8_t		allow_sata_in_cluster;
+	uint8_t		max_chained_enclosures;
+	uint8_t		disable_ctrl_r;
+	uint8_t		enabel_web_bios;
+	uint8_t		phy_polarity_split;
+	uint8_t		direct_pd_mapping;
+	uint8_t		bios_enumerate_lds;
+	uint8_t		restored_hot_spare_on_insertion;
+	uint8_t		expose_enclosure_devices;
+	uint8_t		maintain_pd_fail_history;
+	uint8_t		resv[28];
+} __packed;
+
+/* Controller default settings */
+struct mfi_bios_data {
+	uint16_t	boot_target_id;
+	uint8_t		do_not_int_13;
+	uint8_t		continue_on_error;
+	uint8_t		verbose;
+	uint8_t		geometry;
+	uint8_t		expose_all_drives;
+	uint8_t		reserved[56];
+	uint8_t		check_sum;
+} __packed;
 
 /* SAS (?) controller info, returned from MFI_DCMD_CTRL_GETINFO. */
 struct mfi_ctrl_info {
@@ -509,7 +618,7 @@
 #define MFI_INFO_RAID_6		0x10
 
 	uint32_t		adapter_ops;
-#define MFI_INFO_AOPS_RBLD_RATE		0x0001		
+#define MFI_INFO_AOPS_RBLD_RATE		0x0001
 #define MFI_INFO_AOPS_CC_RATE		0x0002
 #define MFI_INFO_AOPS_BGI_RATE		0x0004
 #define MFI_INFO_AOPS_RECON_RATE	0x0008
@@ -557,4 +666,418 @@
 	uint8_t			pad[0x800 - 0x6a0];
 } __packed;
 
+/* keep track of an event. */
+union mfi_evt {
+	struct {
+		uint16_t	locale;
+		uint8_t		reserved;
+		int8_t		class;
+	} members;
+	uint32_t		word;
+} __packed;
+
+/* event log state. */
+struct mfi_evt_log_state {
+	uint32_t		newest_seq_num;
+	uint32_t		oldest_seq_num;
+	uint32_t		clear_seq_num;
+	uint32_t		shutdown_seq_num;
+	uint32_t		boot_seq_num;
+} __packed;
+
+struct mfi_progress {
+	uint16_t		progress;
+	uint16_t		elapsed_seconds;
+} __packed;
+
+struct mfi_evt_ld {
+	uint16_t		target_id;
+	uint8_t			ld_index;
+	uint8_t			reserved;
+} __packed;
+
+struct mfi_evt_pd {
+	uint16_t		device_id;
+	uint8_t			enclosure_index;
+	uint8_t			slot_number;
+} __packed;
+
+/* SAS (?) event detail, returned from MFI_DCMD_CTRL_EVENT_WAIT. */
+struct mfi_evt_detail {
+	uint32_t		seq;
+	uint32_t		time;
+	uint32_t		code;
+	union mfi_evt		class;
+	uint8_t			arg_type;
+	uint8_t			reserved1[15];
+
+	union {
+		struct {
+			struct mfi_evt_pd	pd;
+			uint8_t			cdb_len;
+			uint8_t			sense_len;
+			uint8_t			reserved[2];
+			uint8_t			cdb[16];
+			uint8_t			sense[64];
+		} cdb_sense;
+
+		struct mfi_evt_ld		ld;
+
+		struct {
+			struct mfi_evt_ld	ld;
+			uint64_t		count;
+		} ld_count;
+
+		struct {
+			uint64_t		lba;
+			struct mfi_evt_ld	ld;
+		} ld_lba;
+
+		struct {
+			struct mfi_evt_ld	ld;
+			uint32_t		pre_owner;
+			uint32_t		new_owner;
+		} ld_owner;
+
+		struct {
+			uint64_t		ld_lba;
+			uint64_t		pd_lba;
+			struct mfi_evt_ld	ld;
+			struct mfi_evt_pd	pd;
+		} ld_lba_pd_lba;
+
+		struct {
+			struct mfi_evt_ld	ld;
+			struct mfi_progress	prog;
+		} ld_prog;
+
+		struct {
+			struct mfi_evt_ld	ld;
+			uint32_t		prev_state;
+			uint32_t		new_state;
+		} ld_state;
+
+		struct {
+			uint64_t		strip;
+			struct mfi_evt_ld	ld;
+		} ld_strip;
+
+		struct mfi_evt_pd		pd;
+
+		struct {
+			struct mfi_evt_pd	pd;
+			uint32_t		err;
+		} pd_err;
+
+		struct {
+			uint64_t		lba;
+			struct mfi_evt_pd	pd;
+		} pd_lba;
+
+		struct {
+			uint64_t		lba;
+			struct mfi_evt_pd	pd;
+			struct mfi_evt_ld	ld;
+		} pd_lba_ld;
+
+		struct {
+			struct mfi_evt_pd	pd;
+			struct mfi_progress	prog;
+		} pd_prog;
+
+		struct {
+			struct mfi_evt_pd	ld;
+			uint32_t		prev_state;
+			uint32_t		new_state;
+		} pd_state;
+
+		struct {
+			uint16_t		venderId;
+			uint16_t		deviceId;
+			uint16_t		subVenderId;
+			uint16_t		subDeviceId;
+		} pci;
+
+		uint32_t			rate;
+
+		char				str[96];
+
+		struct {
+			uint32_t		rtc;
+			uint16_t		elapsedSeconds;
+		} time;
+
+		struct {
+			uint32_t		ecar;
+			uint32_t		elog;
+			char			str[64];
+		} ecc;
+
+		uint8_t		b[96];
+		uint16_t	s[48];
+		uint32_t	w[24];
+		uint64_t	d[12];
+	} args;
+
+	char description[128];
+} __packed;
+
+struct mfi_evt_list {
+	uint32_t		count;
+	uint32_t		reserved;
+	struct mfi_evt_detail	event[1];
+} __packed;
+
+union mfi_pd_ref {
+	struct {
+		uint16_t	device_id;
+		uint16_t	seq_num;
+	} v;
+	uint32_t	ref;
+} __packed;
+
+union mfi_pd_ddf_type {
+	struct {
+		union {
+			struct {
+				uint16_t	forced_pd_guid	: 1;
+				uint16_t	in_vd		: 1;
+				uint16_t	is_global_spare	: 1;
+				uint16_t	is_spare	: 1;
+				uint16_t	is_foreign	: 1;
+				uint16_t	reserved	: 7;
+				uint16_t	intf		: 4;
+			} pd_type;
+			uint16_t	type;
+		} v;
+		uint16_t		reserved;
+	} ddf;
+	struct {
+		uint32_t		reserved;
+	} non_disk;
+	uint32_t			type;
+} __packed;
+
+struct mfi_pd_progress {
+	struct {
+		uint32_t		rbld	: 1;
+		uint32_t		patrol	: 1;
+		uint32_t		clear	: 1;
+		uint32_t		reserved: 29;
+	} active;
+	struct mfi_progress		rbld;
+	struct mfi_progress		patrol;
+	struct mfi_progress		clear;
+	struct mfi_progress		reserved[4];
+} __packed;
+
+struct mfi_pd_info {
+	union mfi_pd_ref		ref;
+	uint8_t				inquiry_data[96];
+	uint8_t				vpd_page83[64];
+	uint8_t				not_supported;
+	uint8_t				scsi_dev_type;
+	uint8_t				connected_port_bitmap;
+	uint8_t				device_speed;
+	uint32_t			media_err_count;
+	uint32_t			other_err_count;
+	uint32_t			pred_fail_count;
+	uint32_t			last_pred_fail_event_seq_num;
+	uint16_t			fw_state;
+	uint8_t				disable_for_removal;
+	uint8_t				link_speed;
+	union mfi_pd_ddf_type		state;
+	struct {
+		uint8_t			count;
+		uint8_t			is_path_broken;
+		uint8_t			reserved[6];
+		uint64_t		sas_addr[4];
+	} path_info;
+	uint64_t			raw_size;
+	uint64_t			non_coerced_size;
+	uint64_t			coerced_size;
+	uint16_t			encl_device_id;
+	uint8_t				encl_index;
+	uint8_t				slot_number;
+	struct mfi_pd_progress		prog_info;
+	uint8_t				bad_block_table_full;
+	uint8_t				unusable_in_current_config;
+	uint8_t				vpd_page83_ext[64];
+	uint8_t				reserved[512-358];
+} __packed;
+
+struct mfi_pd_address {
+	uint16_t		device_id;
+	uint16_t		encl_device_id;
+	uint8_t			encl_index;
+	uint8_t			slot_number;
+	uint8_t			scsi_dev_type;
+	uint8_t			connect_port_bitmap;
+	uint64_t		sas_addr[2];
+} __packed;
+
+struct mfi_pd_list {
+	uint32_t		size;
+	uint32_t		count;
+	uint8_t			data;
+	/*
+	struct mfi_pd_address	addr[];
+	*/
+} __packed;
+
+union mfi_ld_ref {
+	struct {
+		uint8_t		target_id;
+		uint8_t		reserved;
+		uint16_t	seq;
+	} v;
+	uint32_t		ref;
+} __packed;
+
+struct mfi_ld_list {
+	uint32_t		ld_count;
+	uint32_t		reserved1;
+	struct {
+		union mfi_ld_ref	ld;
+		uint8_t		state;
+		uint8_t		reserved2[3];
+		uint64_t	size;
+	} ld_list[MFI_MAX_LD];
+} __packed;
+
+enum mfi_ld_access {
+	MFI_LD_ACCESS_RW =	0,
+	MFI_LD_ACCSSS_RO = 	2,
+	MFI_LD_ACCESS_BLOCKED =	3,
+};
+#define MFI_LD_ACCESS_MASK	3
+
+enum mfi_ld_state {
+	MFI_LD_STATE_OFFLINE =			0,
+	MFI_LD_STATE_PARTIALLY_DEGRADED =	1,
+	MFI_LD_STATE_DEGRADED =			2,
+	MFI_LD_STATE_OPTIMAL =			3
+};
+
+struct mfi_ld_props {
+	union mfi_ld_ref	ld;
+	char			name[16];
+	uint8_t			default_cache_policy;
+	uint8_t			access_policy;
+	uint8_t			disk_cache_policy;
+	uint8_t			current_cache_policy;
+	uint8_t			no_bgi;
+	uint8_t			reserved[7];
+} __packed;
+
+struct mfi_ld_params {
+	uint8_t			primary_raid_level;
+	uint8_t			raid_level_qualifier;
+	uint8_t			secondary_raid_level;
+	uint8_t			stripe_size;
+	uint8_t			num_drives;
+	uint8_t			span_depth;
+	uint8_t			state;
+	uint8_t			init_state;
+	uint8_t			is_consistent;
+	uint8_t			reserved[23];
+} __packed;
+
+struct mfi_ld_progress {
+	uint32_t		active;
+#define	MFI_LD_PROGRESS_CC	(1<<0)
+#define	MFI_LD_PROGRESS_BGI	(1<<1)
+#define	MFI_LD_PROGRESS_FGI	(1<<2)
+#define	MFI_LD_PORGRESS_RECON	(1<<3)
+	struct mfi_progress	cc;
+	struct mfi_progress	bgi;
+	struct mfi_progress	fgi;
+	struct mfi_progress	recon;
+	struct mfi_progress	reserved[4];
+} __packed;
+
+struct mfi_span {
+	uint64_t		start_block;
+	uint64_t		num_blocks;
+	uint16_t		array_ref;
+	uint8_t			reserved[6];
+} __packed;
+
+#define	MFI_MAX_SPAN_DEPTH	8
+struct mfi_ld_config {
+	struct mfi_ld_props	properties;
+	struct mfi_ld_params	params;
+	struct mfi_span		span[MFI_MAX_SPAN_DEPTH];
+} __packed;
+
+struct mfi_ld_info {
+	struct mfi_ld_config	ld_config;
+	uint64_t		size;
+	struct mfi_ld_progress	progress;
+	uint16_t		cluster_owner;
+	uint8_t			reconstruct_active;
+	uint8_t			reserved1[1];
+	uint8_t			vpd_page83[64];
+	uint8_t			reserved2[16];
+} __packed;
+
+union mfi_spare_type {
+	struct {
+		uint8_t		is_dedicate		:1;
+		uint8_t		is_revertable		:1;
+		uint8_t		is_encl_affinity	:1;
+		uint8_t		reserved		:5;
+	} v;
+	uint8_t		type;
+} __packed;
+
+#define MAX_ARRAYS 16
+struct mfi_spare {
+	union mfi_pd_ref	ref;
+	union mfi_spare_type	spare_type;
+	uint8_t			reserved[2];
+	uint8_t			array_count;
+	uint16_t		array_refd[MAX_ARRAYS];
+} __packed;
+
+#define MAX_ROW_SIZE 32
+struct mfi_array {
+	uint64_t			size;
+	uint8_t				num_drives;
+	uint8_t				reserved;
+	uint16_t			array_ref;
+	uint8_t				pad[20];
+	struct {
+		union mfi_pd_ref	ref;
+		uint16_t		fw_state;
+		struct {
+			uint8_t		pd;
+			uint8_t		slot;
+		} encl;
+	} pd[MAX_ROW_SIZE];
+} __packed;
+
+struct mfi_config_data {
+	uint32_t		size;
+	uint16_t		array_count;
+	uint16_t		array_size;
+	uint16_t		log_drv_count;
+	uint16_t		log_drv_size;
+	uint16_t		spares_count;
+	uint16_t		spares_size;
+	uint8_t			reserved[16];
+	uint8_t			data;
+	/*
+	struct mfi_array	array[];
+	struct mfi_ld_config	ld[];
+	struct mfi_spare	spare[];
+	*/
+} __packed;
+
+#define MFI_SCSI_MAX_TARGETS	128
+#define MFI_SCSI_MAX_LUNS	8
+#define MFI_SCSI_INITIATOR_ID	255
+#define MFI_SCSI_MAX_CMDS	8
+#define MFI_SCSI_MAX_CDB_LEN	16
+
 #endif /* _MFIREG_H */
--- /dev/null
+++ sys/dev/mfi/mfi_debug.c
@@ -0,0 +1,263 @@
+/*-
+ * Copyright (c) 2006 IronPort Systems
+ * 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.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD: src/sys/dev/mfi/mfi_debug.c,v 1.3 2006/10/16 04:18:38 scottl Exp $");
+
+#include "opt_mfi.h"
+
+#ifdef MFI_DEBUG
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/kernel.h>
+#include <sys/conf.h>
+#include <sys/bus.h>
+#include <sys/bio.h>
+#include <sys/lock.h>
+#include <sys/mutex.h>
+#include <sys/malloc.h>
+#include <sys/selinfo.h>
+#include <sys/taskqueue.h>
+#include <sys/uio.h>
+#include <machine/resource.h>
+#include <machine/bus.h>
+
+#include <vm/vm.h>
+#include <vm/pmap.h>
+
+#include <dev/mfi/mfireg.h>
+#include <dev/mfi/mfi_ioctl.h>
+#include <dev/mfi/mfivar.h>
+
+static void
+mfi_print_frame_flags(device_t dev, uint32_t flags)
+{
+	device_printf(dev, "flags=%b\n", flags,
+	    "\20"
+	    "\1NOPOST"
+	    "\2SGL64"
+	    "\3SENSE64"
+	    "\4WRITE"
+	    "\5READ");
+}
+
+static void
+mfi_print_sgl(struct mfi_frame_header *hdr, union mfi_sgl *sgl, int count)
+{
+	int i, columns = 0;
+
+	printf("SG List:\n");
+	for (i = 0; i < count; i++) {
+		if (hdr->flags & MFI_FRAME_SGL64) {
+			printf("0x%lx:%06d ", (u_long)sgl->sg64[i].addr,
+			    sgl->sg64[i].len);
+			columns += 26;
+			if (columns > 77) {
+				printf("\n");
+				columns = 0;
+			}
+		} else {
+			printf("0x%x:%06d ", sgl->sg32[i].addr,
+			    sgl->sg32[i].len);
+			columns += 18;
+			if (columns > 71) {
+				printf("\n");
+				columns = 0;
+			}
+		}
+	}
+	if (columns != 0)
+		printf("\n");
+
+}
+
+static void
+mfi_print_ldio(struct mfi_softc *sc, device_t dev, struct mfi_command *cm)
+{
+	struct mfi_io_frame *io;
+	struct mfi_frame_header *hdr;
+
+	io = &cm->cm_frame->io;
+	hdr = &io->header;
+
+	device_printf(dev, "cmd=%s target_id=%d sg_count=%d data_len=%d "
+	    "lba=%d\n", (hdr->cmd == MFI_CMD_LD_READ) ? "LD_READ":"LD_WRITE",
+	     hdr->target_id, hdr->sg_count, hdr->data_len, io->lba_lo);
+	mfi_print_frame_flags(dev, hdr->flags);
+	mfi_print_sgl(hdr, &io->sgl, hdr->sg_count);
+
+}
+
+static void
+mfi_print_dcmd(struct mfi_softc *sc, device_t dev, struct mfi_command *cm)
+{
+	struct mfi_dcmd_frame *dcmd;
+	struct mfi_frame_header *hdr;
+	const char *opcode;
+
+	dcmd = &cm->cm_frame->dcmd;
+	hdr = &dcmd->header;
+
+	switch (dcmd->opcode) {
+	case MFI_DCMD_CTRL_GETINFO:
+		opcode = "CTRL_GETINFO";
+		break;
+	case MFI_DCMD_CTRL_FLUSHCACHE:
+		opcode = "CTRL_FLUSHCACHE";
+		break;
+	case MFI_DCMD_CTRL_SHUTDOWN:
+		opcode = "CTRL_SHUTDOWN";
+		break;
+	case MFI_DCMD_CTRL_EVENT_GETINFO:
+		opcode = "EVENT_GETINFO";
+		break;
+	case MFI_DCMD_CTRL_EVENT_GET:
+		opcode = "EVENT_GET";
+		break;
+	case MFI_DCMD_CTRL_EVENT_WAIT:
+		opcode = "EVENT_WAIT";
+		break;
+	case MFI_DCMD_LD_GET_LIST:
+		opcode = "LD_GET_LIST";
+		break;
+	case MFI_DCMD_LD_GET_INFO:
+		opcode = "LD_GET_INFO";
+		break;
+	case MFI_DCMD_LD_GET_PROP:
+		opcode = "LD_GET_PROP";
+		break;
+	case MFI_DCMD_LD_SET_PROP:
+		opcode = "LD_SET_PROP";
+		break;
+	case MFI_DCMD_CLUSTER:
+		opcode = "CLUSTER";
+		break;
+	case MFI_DCMD_CLUSTER_RESET_ALL:
+		opcode = "CLUSTER_RESET_ALL";
+		break;
+	case MFI_DCMD_CLUSTER_RESET_LD:
+		opcode = "CLUSTER_RESET_LD";
+		break;
+	default:
+		opcode = "UNKNOWN";
+		break;
+	}
+
+	device_printf(dev, "cmd=MFI_CMD_DCMD opcode=%s data_len=%d\n",
+	    opcode, hdr->data_len);
+	mfi_print_frame_flags(dev, hdr->flags);
+	mfi_print_sgl(hdr, &dcmd->sgl, hdr->sg_count);
+
+}
+
+static void
+mfi_print_generic_frame(struct mfi_softc *sc, struct mfi_command *cm)
+{
+	hexdump(cm->cm_frame, cm->cm_total_frame_size, NULL, HD_OMIT_CHARS);
+}
+
+void
+mfi_print_cmd(struct mfi_command *cm)
+{
+	device_t dev;
+	struct mfi_softc *sc;
+
+	sc = cm->cm_sc;
+	dev = sc->mfi_dev;
+
+	device_printf(dev, "cm=%p index=%d total_frame_size=%d "
+	    "extra_frames=%d\n", cm, cm->cm_index, cm->cm_total_frame_size,
+	    cm->cm_extra_frames);
+	device_printf(dev, "flags=%b\n", cm->cm_flags,
+	    "\20"
+	    "\1MAPPED"
+	    "\2DATAIN"
+	    "\3DATAOUT"
+	    "\4COMPLETED"
+	    "\5POLLED"
+	    "\6Q_FREE"
+	    "\7Q_READY"
+	    "\10Q_BUSY");
+
+	switch (cm->cm_frame->header.cmd) {
+	case MFI_CMD_DCMD:
+		mfi_print_dcmd(sc, dev, cm);
+		break;
+	case MFI_CMD_LD_READ:
+	case MFI_CMD_LD_WRITE:
+		mfi_print_ldio(sc, dev, cm);
+		break;
+	default:
+		mfi_print_generic_frame(sc, cm);
+		break;
+	}
+
+	return;
+}
+
+void
+mfi_dump_cmds(struct mfi_softc *sc)
+{
+	int i;
+
+	for (i = 0; i < sc->mfi_total_cmds; i++)
+		mfi_print_generic_frame(sc, &sc->mfi_commands[i]);
+}
+
+void
+mfi_validate_sg(struct mfi_softc *sc, struct mfi_command *cm,
+	const char *function, int line)
+{
+	struct mfi_frame_header *hdr;
+	int i;
+	uint32_t count = 0, data_len;
+
+	hdr = &cm->cm_frame->header;
+	count = 0;
+	for (i = 0; i < hdr->sg_count; i++) {
+		count += cm->cm_sg->sg32[i].len;
+	}
+	/*
+	count++;
+	*/
+	data_len = hdr->data_len;
+	switch (hdr->cmd) {
+	case MFI_CMD_LD_READ:
+	case MFI_CMD_LD_WRITE:
+		data_len = data_len * 512;
+	case MFI_CMD_DCMD:
+		if (count != data_len) {
+			device_printf(sc->mfi_dev,
+			    "%s %d COMMAND %p S/G count bad %d %d %d 0x%jx\n",
+			    function, line, cm, count, data_len, cm->cm_len,
+			    (intmax_t)pmap_kextract((vm_offset_t)cm->cm_data));
+			MFI_PRINT_CMD(cm);
+		}
+	}
+}
+
+#endif
--- /dev/null
+++ sys/dev/mfi/mfi_linux.c
@@ -0,0 +1,103 @@
+/*-
+ * Copyright (c) 2006 IronPort Systems
+ * 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.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD: src/sys/dev/mfi/mfi_linux.c,v 1.2 2006/11/14 16:48:00 ambrisko Exp $");
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/conf.h>
+#include <sys/kernel.h>
+#include <sys/module.h>
+#include <sys/file.h>
+#include <sys/proc.h>
+
+#if defined(__amd64__) /* Assume amd64 wants 32 bit Linux */
+#include <machine/../linux32/linux.h>
+#include <machine/../linux32/linux32_proto.h>
+#else
+#include <machine/../linux/linux.h>
+#include <machine/../linux/linux_proto.h>
+#endif
+#include <compat/linux/linux_ioctl.h>
+#include <compat/linux/linux_util.h>
+
+#include <dev/mfi/mfireg.h>
+#include <dev/mfi/mfi_ioctl.h>
+
+/* There are multiple ioctl number ranges that need to be handled */
+#define MFI_LINUX_IOCTL_MIN  0x4d00
+#define MFI_LINUX_IOCTL_MAX  0x4d04
+
+static linux_ioctl_function_t mfi_linux_ioctl;
+static struct linux_ioctl_handler mfi_linux_handler = {mfi_linux_ioctl,
+						       MFI_LINUX_IOCTL_MIN,
+						       MFI_LINUX_IOCTL_MAX};
+
+SYSINIT  (mfi_register,   SI_SUB_KLD, SI_ORDER_MIDDLE,
+	  linux_ioctl_register_handler, &mfi_linux_handler);
+SYSUNINIT(mfi_unregister, SI_SUB_KLD, SI_ORDER_MIDDLE,
+	  linux_ioctl_unregister_handler, &mfi_linux_handler);
+
+static struct linux_device_handler mfi_device_handler =
+	{ "mfi", "megaraid_sas", "mfi0", "megaraid_sas_ioctl_node", -1, 0, 1};
+
+SYSINIT  (mfi_register2,   SI_SUB_KLD, SI_ORDER_MIDDLE,
+	  linux_device_register_handler, &mfi_device_handler);
+SYSUNINIT(mfi_unregister2, SI_SUB_KLD, SI_ORDER_MIDDLE,
+	  linux_device_unregister_handler, &mfi_device_handler);
+
+static int
+mfi_linux_modevent(module_t mod, int cmd, void *data)
+{
+	return (0);
+}
+
+DEV_MODULE(mfi_linux, mfi_linux_modevent, NULL);
+MODULE_DEPEND(mfi, linux, 1, 1, 1);
+
+static int
+mfi_linux_ioctl(d_thread_t *p, struct linux_ioctl_args *args)
+{
+	struct file *fp;
+	int error;
+	u_long cmd = args->cmd;
+
+	switch (cmd) {
+	case MFI_LINUX_CMD:
+		cmd = MFI_LINUX_CMD_2;
+		break;
+	case MFI_LINUX_SET_AEN:
+		cmd = MFI_LINUX_SET_AEN_2;
+		break;
+	}
+
+	if ((error = fget(p, args->fd, &fp)) != 0)
+		return (error);
+	error = fo_ioctl(fp, cmd, (caddr_t)args->arg, p->td_ucred, p);
+	fdrop(fp, p);
+	return (error);
+}
Index: mfivar.h
===================================================================
RCS file: /home/cvs/src/sys/dev/mfi/mfivar.h,v
retrieving revision 1.1
retrieving revision 1.2
diff -L sys/dev/mfi/mfivar.h -L sys/dev/mfi/mfivar.h -u -r1.1 -r1.2
--- sys/dev/mfi/mfivar.h
+++ sys/dev/mfi/mfivar.h
@@ -23,13 +23,41 @@
  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  * SUCH DAMAGE.
  */
+/*-
+ * Copyright (c) 2007 LSI Corp.
+ * Copyright (c) 2007 Rajesh Prabhakaran.
+ * 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.
+ */
 
 #ifndef _MFIVAR_H
 #define _MFIVAR_H
 
 #include <sys/cdefs.h>
-__FBSDID("$FreeBSD: src/sys/dev/mfi/mfivar.h,v 1.1.2.1 2006/04/04 03:24:48 scottl Exp $");
-__MBSDID("$MidnightBSD$");
+__FBSDID("$FreeBSD: src/sys/dev/mfi/mfivar.h,v 1.11 2007/08/25 23:58:45 scottl Exp $");
+
+#include <sys/lock.h>
+#include <sys/sx.h>
 
 /*
  * SCSI structures and definitions are used from here, but no linking
@@ -44,9 +72,12 @@
 };
 
 struct mfi_softc;
+struct disk;
+struct ccb_hdr;
 
 struct mfi_command {
 	TAILQ_ENTRY(mfi_command) cm_link;
+	time_t			cm_timestamp;
 	struct mfi_softc	*cm_sc;
 	union mfi_frame		*cm_frame;
 	uint32_t		cm_frame_busaddr;
@@ -68,16 +99,29 @@
 #define MFI_ON_MFIQ_READY	(1<<6)
 #define MFI_ON_MFIQ_BUSY	(1<<7)
 #define MFI_ON_MFIQ_MASK	((1<<5)|(1<<6)|(1<<7))
+	int			cm_aen_abort;
 	void			(* cm_complete)(struct mfi_command *cm);
 	void			*cm_private;
+	int			cm_index;
+	int			cm_error;
+};
+
+struct mfi_disk {
+	TAILQ_ENTRY(mfi_disk)	ld_link;
+	device_t	ld_dev;
+	int		ld_id;
+	int		ld_unit;
+	struct mfi_softc *ld_controller;
+	struct mfi_ld_info	*ld_info;
+	struct disk	*ld_disk;
+	int		ld_flags;
+#define MFI_DISK_FLAGS_OPEN	0x01
+#define	MFI_DISK_FLAGS_DISABLED	0x02
 };
 
-struct mfi_ld {
-	TAILQ_ENTRY(mfi_ld)	ld_link;
-	device_t		ld_disk;
-	uint64_t		ld_sectors;
-	uint32_t		ld_secsize;
-	int			ld_id;
+struct mfi_aen {
+	TAILQ_ENTRY(mfi_aen) aen_link;
+	struct proc			*p;
 };
 
 struct mfi_softc {
@@ -86,6 +130,9 @@
 #define MFI_FLAGS_SG64		(1<<0)
 #define MFI_FLAGS_QFRZN		(1<<1)
 #define MFI_FLAGS_OPEN		(1<<2)
+#define MFI_FLAGS_STOP		(1<<3)
+#define MFI_FLAGS_1064R		(1<<4)
+#define MFI_FLAGS_1078		(1<<5)
 
 	struct mfi_hwcomms		*mfi_comms;
 	TAILQ_HEAD(,mfi_command)	mfi_free;
@@ -111,6 +158,15 @@
 	uint32_t			mfi_frames_busaddr;
 	union mfi_frame			*mfi_frames;
 
+	TAILQ_HEAD(,mfi_aen)		mfi_aen_pids;
+	struct mfi_command		*mfi_aen_cm;
+	uint32_t			mfi_aen_triggered;
+	uint32_t			mfi_poll_waiting;
+	struct selinfo			mfi_select;
+	int				mfi_delete_busy_volumes;
+	int				mfi_keep_deleted_volumes;
+	int				mfi_detaching;
+
 	bus_dma_tag_t			mfi_sense_dmat;
 	bus_dmamap_t			mfi_sense_dmamap;
 	uint32_t			mfi_sense_busaddr;
@@ -122,7 +178,6 @@
 
 	struct intr_config_hook		mfi_ich;
 	eventhandler_tag		eh;
-	int				mfi_probe_count;
 
 	/*
 	 * Allocation for the command array.  Used as an indexable array to
@@ -139,33 +194,39 @@
 	 */
 	int				mfi_max_fw_cmds;
 	/*
-	 * Max number of S/G elements the firmware can handle
-	 */
-	int				mfi_max_fw_sgl;
-	/*
 	 * How many S/G elements we'll ever actually use 
 	 */
-	int				mfi_total_sgl;
+	int				mfi_max_sge;
 	/*
 	 * How many bytes a compound frame is, including all of the extra frames
 	 * that are used for S/G elements.
 	 */
-	int				mfi_frame_size;
+	int				mfi_cmd_size;
 	/*
 	 * How large an S/G element is.  Used to calculate the number of single
 	 * frames in a command.
 	 */
-	int				mfi_sgsize;
+	int				mfi_sge_size;
 	/*
 	 * Max number of sectors that the firmware allows
 	 */
 	uint32_t			mfi_max_io;
 
-	TAILQ_HEAD(,mfi_ld)		mfi_ld_tqh;
+	TAILQ_HEAD(,mfi_disk)		mfi_ld_tqh;
 	eventhandler_tag		mfi_eh;
 	struct cdev			*mfi_cdev;
 
+	TAILQ_HEAD(, ccb_hdr)		mfi_cam_ccbq;
+	struct mfi_command *		(* mfi_cam_start)(void *);
+	struct callout			mfi_watchdog_callout;
 	struct mtx			mfi_io_lock;
+	struct sx			mfi_config_lock;
+
+	/* Controller type specific interfaces */
+	void	(*mfi_enable_intr)(struct mfi_softc *sc);
+	int32_t	(*mfi_read_fw_status)(struct mfi_softc *sc);
+	int	(*mfi_check_clear_intr)(struct mfi_softc *sc);
+ 	void	(*mfi_issue_cmd)(struct mfi_softc *sc,uint32_t bus_add,uint32_t frame_cnt);
 };
 
 extern int mfi_attach(struct mfi_softc *);
@@ -173,6 +234,8 @@
 extern int mfi_shutdown(struct mfi_softc *);
 extern void mfi_startio(struct mfi_softc *);
 extern void mfi_disk_complete(struct bio *);
+extern int mfi_disk_disable(struct mfi_disk *);
+extern void mfi_disk_enable(struct mfi_disk *);
 extern int mfi_dump_blocks(struct mfi_softc *, int id, uint64_t, void *, int);
 
 #define MFIQ_ADD(sc, qname)					\
@@ -314,4 +377,21 @@
 
 MALLOC_DECLARE(M_MFIBUF);
 
+#define MFI_CMD_TIMEOUT 30
+
+#ifdef MFI_DEBUG
+extern void mfi_print_cmd(struct mfi_command *cm);
+extern void mfi_dump_cmds(struct mfi_softc *sc);
+extern void mfi_validate_sg(struct mfi_softc *, struct mfi_command *, const char *, int );
+#define MFI_PRINT_CMD(cm)	mfi_print_cmd(cm)
+#define MFI_DUMP_CMDS(sc)	mfi_dump_cmds(sc)
+#define MFI_VALIDATE_CMD(sc, cm) mfi_validate_sg(sc, cm, __FUNCTION__, __LINE__)
+#else
+#define MFI_PRINT_CMD(cm)
+#define MFI_DUMP_CMDS(sc)
+#define MFI_VALIDATE_CMD(sc, cm)
+#endif
+
+extern void mfi_release_command(struct mfi_command *cm);
+
 #endif /* _MFIVAR_H */


More information about the Midnightbsd-cvs mailing list