From 29571811407dc4e8e6d6083c9e714f53bef39cf7 Mon Sep 17 00:00:00 2001
From: Sascha Wildner <saw@online.de>
Date: Fri, 5 Aug 2011 14:56:43 +0200
Subject: [PATCH 2/3] WIP

---
 share/man/man4/mfi.4         |   40 +++-
 sys/conf/files               |    1 +
 sys/dev/raid/mfi/Makefile    |    2 +-
 sys/dev/raid/mfi/mfi.c       |  664 +++++++++++++++++++++++++++++++++++++++---
 sys/dev/raid/mfi/mfi_cam.c   |   38 +++-
 sys/dev/raid/mfi/mfi_disk.c  |   36 +++-
 sys/dev/raid/mfi/mfi_pci.c   |   47 +++-
 sys/dev/raid/mfi/mfi_syspd.c |  325 +++++++++++++++++++++
 sys/dev/raid/mfi/mfireg.h    |   86 +++++-
 sys/dev/raid/mfi/mfivar.h    |   59 ++++
 sys/sys/bio.h                |    1 +
 11 files changed, 1244 insertions(+), 55 deletions(-)
 create mode 100644 sys/dev/raid/mfi/mfi_syspd.c

diff --git a/share/man/man4/mfi.4 b/share/man/man4/mfi.4
index a49dcd4..7a66617 100644
--- a/share/man/man4/mfi.4
+++ b/share/man/man4/mfi.4
@@ -24,7 +24,7 @@
 .\"
 .\" $FreeBSD: src/share/man/man4/mfi.4,v 1.13 2010/05/12 17:12:38 brueffer Exp $
 .\"
-.Dd November 30, 2010
+.Dd August 2, 2011
 .Dt MFI 4
 .Os
 .Sh NAME
@@ -49,6 +49,8 @@ mfi_load="YES"
 This driver is for LSI's next generation PCI Express SAS RAID controllers.
 Access to RAID arrays (logical disks) from this driver is provided via
 .Pa /dev/mfid?
+.\"and
+.\".Pa /dev/mfisyspd?
 device nodes.
 A simple management interface is also provided on a per-controller basis via
 the
@@ -85,12 +87,36 @@ LSI MegaRAID SAS 8408E
 .It
 LSI MegaRAID SAS 8480E
 .It
-LSI MegaRAID SAS 9260
+LSI MegaRAID SAS 9240-4i
+.It
+LSI MegaRAID SAS 9240-8i
+.It
+LSI MegaRAID SAS 9260-4i
+.It
+LSI MegaRAID SAS 9260-8i
+.It
+LSI MegaRAID SAS 9260DE-8i
+.It
+LSI MegaRAID SAS 9260-16i
+.It
+LSI MegaRAID SAS 9261-8i
+.It
+LSI MegaRAID SAS 9280-4i4e
+.It
+LSI MegaRAID SAS 9280-8e
+.It
+LSI MegaRAID SAS 9280DE-8e
+.It
+LSI MegaRAID SAS 9280-16i4e
+.It
+LSI MegaRAID SAS 9280-24i4e
 .It
 Dell PERC5
 .It
 Dell PERC6
 .It
+IBM ServeRAID M1015 SAS/SATA
+.It
 IBM ServeRAID M5015 SAS/SATA
 .It
 IBM ServeRAID-MR10i
@@ -98,9 +124,11 @@ IBM ServeRAID-MR10i
 Intel RAID Controller SROMBSAS18E
 .El
 .Sh FILES
-.Bl -tag -width ".Pa /dev/mfid?" -compact
+.Bl -tag -width ".Pa /dev/mfisyspd?" -compact
 .It Pa /dev/mfid?
 array/logical disk interface
+.\".It Pa /dev/mfisyspd?
+.\"XXX
 .It Pa /dev/mfi?
 management interface
 .El
@@ -108,6 +136,8 @@ management interface
 .Bl -diag
 .It "mfid%d: Unable to delete busy device"
 An attempt was made to remove a mounted volume.
+.\".It "mfisyspd%d: Unable to delete busy device"
+.\"XXX An attempt was made to remove a mounted volume.
 .El
 .Sh SEE ALSO
 .Xr amr 4 ,
@@ -123,5 +153,5 @@ The
 .Nm
 driver and this manual page were written by
 .An Scott Long Aq scottl@FreeBSD.org .
-.Sh BUGS
-The driver does not support big-endian architectures at this time.
+.\".Sh BUGS
+.\"The driver does not support big-endian architectures at this time.
diff --git a/sys/conf/files b/sys/conf/files
index 09fb925..44f9272 100644
--- a/sys/conf/files
+++ b/sys/conf/files
@@ -592,6 +592,7 @@ dev/raid/mfi/mfi.c		optional mfi
 dev/raid/mfi/mfi_debug.c	optional mfi
 dev/raid/mfi/mfi_pci.c		optional mfi pci
 dev/raid/mfi/mfi_disk.c		optional mfi
+dev/raid/mfi/mfi_syspd.c	optional mfi
 dev/raid/mfi/mfi_linux.c	optional mfi compat_linux
 dev/raid/mfi/mfi_cam.c		optional mfip scbus
 dev/netif/mii_layer/mii.c		optional miibus
diff --git a/sys/dev/raid/mfi/Makefile b/sys/dev/raid/mfi/Makefile
index 5a81b72..809eac3 100644
--- a/sys/dev/raid/mfi/Makefile
+++ b/sys/dev/raid/mfi/Makefile
@@ -8,7 +8,7 @@ SUBDIR+= mfi_linux
 .endif
 
 KMOD=	mfi
-SRCS=	mfi.c mfi_pci.c mfi_disk.c mfi_debug.c
+SRCS=	mfi.c mfi_pci.c mfi_disk.c mfi_debug.c mfi_syspd.c
 SRCS+=	opt_mfi.h opt_cam.h
 SRCS+=	device_if.h bus_if.h pci_if.h
 
diff --git a/sys/dev/raid/mfi/mfi.c b/sys/dev/raid/mfi/mfi.c
index 210f5f8..cdfc689 100644
--- a/sys/dev/raid/mfi/mfi.c
+++ b/sys/dev/raid/mfi/mfi.c
@@ -48,6 +48,36 @@
  * 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.
+ */
+/*-
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ *            Copyright 1994-2009 The FreeBSD Project.
+ *            All rights reserved.
+ *
+ * 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 FREEBSD PROJECT``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 FREEBSD PROJECT 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.
+ *
+ * The views and conclusions contained in the software and documentation
+ * are those of the authors and should not be interpreted as representing
+ * official policies,either expressed or implied, of the FreeBSD Project.
  *
  * $FreeBSD: src/sys/dev/mfi/mfi.c,v 1.57 2011/07/14 20:20:33 jhb Exp $
  */
@@ -88,13 +118,18 @@ 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_ldprobe(struct mfi_softc *sc);
+static void	mfi_syspdprobe(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 int	mfi_add_sys_pd(struct mfi_softc *sc, int);
+static void	mfi_add_sys_pd_complete(struct mfi_command *);
 static struct mfi_command * mfi_bio_command(struct mfi_softc *);
 static void	mfi_bio_complete(struct mfi_command *);
+static struct mfi_command * mfi_build_ldio(struct mfi_softc *,struct bio*);
+static struct mfi_command * mfi_build_syspdio(struct mfi_softc *,struct bio*);
 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 *);
@@ -163,12 +198,17 @@ mfi_enable_intr_xscale(struct mfi_softc *sc)
 static void
 mfi_enable_intr_ppc(struct mfi_softc *sc)
 {
-	MFI_WRITE4(sc, MFI_ODCR0, 0xFFFFFFFF);
 	if (sc->mfi_flags & MFI_FLAGS_1078) {
+		MFI_WRITE4(sc, MFI_ODCR0, 0xFFFFFFFF);
 		MFI_WRITE4(sc, MFI_OMSK, ~MFI_1078_EIM);
-	} else if (sc->mfi_flags & MFI_FLAGS_GEN2) {
+	}
+	else if (sc->mfi_flags & MFI_FLAGS_GEN2) {
+		MFI_WRITE4(sc, MFI_ODCR0, 0xFFFFFFFF);
 		MFI_WRITE4(sc, MFI_OMSK, ~MFI_GEN2_EIM);
 	}
+	else if (sc->mfi_flags & MFI_FLAGS_SKINNY) {
+		MFI_WRITE4(sc, MFI_OMSK, ~0x00000001);
+	}
 }
 
 static int32_t
@@ -210,9 +250,15 @@ mfi_check_clear_intr_ppc(struct mfi_softc *sc)
 		if (!(status & MFI_GEN2_RM)) {
 			return 1;
 		}
+	} else if (sc->mfi_flags & MFI_FLAGS_SKINNY) {
+		if (!(status & MFI_SKINNY_RM)) {
+			return 1;
+		}
 	}
-
-	MFI_WRITE4(sc, MFI_ODCR0, status);
+	if (sc->mfi_flags & MFI_FLAGS_SKINNY)
+		MFI_WRITE4(sc, MFI_OSTS, status);
+	else
+		MFI_WRITE4(sc, MFI_ODCR0, status);
 	return 0;
 }
 
@@ -225,7 +271,12 @@ 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)
 {
-	MFI_WRITE4(sc, MFI_IQP, (bus_add |frame_cnt <<1)|1 );
+	if (sc->mfi_flags & MFI_FLAGS_SKINNY) {
+		MFI_WRITE4(sc, MFI_IQPL, (bus_add |frame_cnt <<1)|1 );
+		MFI_WRITE4(sc, MFI_IQPH, 0x00000000);
+	} else {
+		MFI_WRITE4(sc, MFI_IQP, (bus_add |frame_cnt <<1)|1 );
+	}
 }
 
 static int
@@ -233,8 +284,11 @@ mfi_transition_firmware(struct mfi_softc *sc)
 {
 	uint32_t fw_state, cur_state;
 	int max_wait, i;
+	uint32_t cur_abs_reg_val = 0;
+	uint32_t prev_abs_reg_val = 0;
 
-	fw_state = sc->mfi_read_fw_status(sc)& MFI_FWSTATE_MASK;
+	cur_abs_reg_val = sc->mfi_read_fw_status(sc);
+	fw_state = cur_abs_reg_val & MFI_FWSTATE_MASK;
 	while (fw_state != MFI_FWSTATE_READY) {
 		if (bootverbose)
 			device_printf(sc->mfi_dev, "Waiting for firmware to "
@@ -245,11 +299,17 @@ mfi_transition_firmware(struct mfi_softc *sc)
 			device_printf(sc->mfi_dev, "Firmware fault\n");
 			return (ENXIO);
 		case MFI_FWSTATE_WAIT_HANDSHAKE:
-			MFI_WRITE4(sc, MFI_IDB, MFI_FWINIT_CLEAR_HANDSHAKE);
+			if (sc->mfi_flags & MFI_FLAGS_SKINNY)
+			    MFI_WRITE4(sc, MFI_SKINNY_IDB, MFI_FWINIT_CLEAR_HANDSHAKE);
+			else
+			    MFI_WRITE4(sc, MFI_IDB, MFI_FWINIT_CLEAR_HANDSHAKE);
 			max_wait = 2;
 			break;
 		case MFI_FWSTATE_OPERATIONAL:
-			MFI_WRITE4(sc, MFI_IDB, MFI_FWINIT_READY);
+			if (sc->mfi_flags & MFI_FLAGS_SKINNY)
+			    MFI_WRITE4(sc, MFI_SKINNY_IDB, MFI_FWINIT_READY);
+			else
+			    MFI_WRITE4(sc, MFI_IDB, MFI_FWINIT_READY);
 			max_wait = 10;
 			break;
 		case MFI_FWSTATE_UNDEFINED:
@@ -257,12 +317,18 @@ mfi_transition_firmware(struct mfi_softc *sc)
 			max_wait = 2;
 			break;
 		case MFI_FWSTATE_FW_INIT:
-		case MFI_FWSTATE_DEVICE_SCAN:
 		case MFI_FWSTATE_FLUSH_CACHE:
 			max_wait = 20;
 			break;
+		case MFI_FWSTATE_DEVICE_SCAN:
+			max_wait = 180; /* wait for 180 seconds */
+			prev_abs_reg_val = cur_abs_reg_val;
+			break;
 		case MFI_FWSTATE_BOOT_MESSAGE_PENDING:
-			MFI_WRITE4(sc, MFI_IDB, MFI_FWINIT_HOTPLUG);
+			if (sc->mfi_flags & MFI_FLAGS_SKINNY)
+			    MFI_WRITE4(sc, MFI_SKINNY_IDB, MFI_FWINIT_HOTPLUG);
+			else
+			    MFI_WRITE4(sc, MFI_IDB, MFI_FWINIT_HOTPLUG);
 			max_wait = 10;
 			break;
 		default:
@@ -271,12 +337,20 @@ mfi_transition_firmware(struct mfi_softc *sc)
 			return (ENXIO);
 		}
 		for (i = 0; i < (max_wait * 10); i++) {
-			fw_state = sc->mfi_read_fw_status(sc) & MFI_FWSTATE_MASK;
+
+			cur_abs_reg_val = sc->mfi_read_fw_status(sc);
+			fw_state = cur_abs_reg_val & MFI_FWSTATE_MASK;
 			if (fw_state == cur_state)
 				DELAY(100000);
 			else
 				break;
 		}
+		if (fw_state == MFI_FWSTATE_DEVICE_SCAN) {
+			/* Check the device scanning progress */
+			if (prev_abs_reg_val != cur_abs_reg_val) {
+				continue;
+			}
+		}
 		if (fw_state == cur_state) {
 			device_printf(sc->mfi_dev, "Firmware stuck in state "
 			    "%#x\n", fw_state);
@@ -286,6 +360,16 @@ mfi_transition_firmware(struct mfi_softc *sc)
 	return (0);
 }
 
+#if defined(__x86_64__)
+static void
+mfi_addr64_cb(void *arg, bus_dma_segment_t *segs, int nsegs, int error)
+{
+	uint64_t *addr;
+
+	addr = arg;
+	*addr = segs[0].ds_addr;
+}
+#else
 static void
 mfi_addr32_cb(void *arg, bus_dma_segment_t *segs, int nsegs, int error)
 {
@@ -294,6 +378,7 @@ mfi_addr32_cb(void *arg, bus_dma_segment_t *segs, int nsegs, int error)
 	addr = arg;
 	*addr = segs[0].ds_addr;
 }
+#endif
 
 int
 mfi_attach(struct mfi_softc *sc)
@@ -302,11 +387,12 @@ mfi_attach(struct mfi_softc *sc)
 	int error, commsz, framessz, sensesz;
 	int frames, unit, max_fw_sge;
 
-	device_printf(sc->mfi_dev, "Megaraid SAS driver Ver 3.00 \n");
+	device_printf(sc->mfi_dev, "Megaraid SAS driver Ver 3.981 \n");
 
 	lockinit(&sc->mfi_io_lock, "MFI I/O lock", 0, LK_CANRECURSE);
 	lockinit(&sc->mfi_config_lock, "MFI config", 0, LK_CANRECURSE);
 	TAILQ_INIT(&sc->mfi_ld_tqh);
+	TAILQ_INIT(&sc->mfi_syspd_tqh);
 	TAILQ_INIT(&sc->mfi_aen_pids);
 	TAILQ_INIT(&sc->mfi_cam_ccbq);
 
@@ -393,8 +479,13 @@ mfi_attach(struct mfi_softc *sc)
 		return (ENOMEM);
 	}
 	bzero(sc->mfi_comms, commsz);
+#if defined(__x86_64__)
+	bus_dmamap_load(sc->mfi_comms_dmat, sc->mfi_comms_dmamap,
+	    sc->mfi_comms, commsz, mfi_addr64_cb, &sc->mfi_comms_busaddr, 0);
+#else
 	bus_dmamap_load(sc->mfi_comms_dmat, sc->mfi_comms_dmamap,
 	    sc->mfi_comms, commsz, mfi_addr32_cb, &sc->mfi_comms_busaddr, 0);
+#endif
 
 	/*
 	 * Allocate DMA memory for the command frames.  Keep them in the
@@ -412,6 +503,8 @@ mfi_attach(struct mfi_softc *sc)
 	} else {
 		sc->mfi_sge_size = sizeof(struct mfi_sg32);
 	}
+	if (sc->mfi_flags & MFI_FLAGS_SKINNY)
+		sc->mfi_sge_size = sizeof(struct mfi_sg_skinny);
 	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;
@@ -434,8 +527,13 @@ mfi_attach(struct mfi_softc *sc)
 		return (ENOMEM);
 	}
 	bzero(sc->mfi_frames, framessz);
+#if defined(__x86_64__)
+	bus_dmamap_load(sc->mfi_frames_dmat, sc->mfi_frames_dmamap,
+	    sc->mfi_frames, framessz, mfi_addr64_cb, &sc->mfi_frames_busaddr,0);
+#else
 	bus_dmamap_load(sc->mfi_frames_dmat, sc->mfi_frames_dmamap,
 	    sc->mfi_frames, framessz, mfi_addr32_cb, &sc->mfi_frames_busaddr,0);
+#endif
 
 	/*
 	 * Allocate DMA memory for the frame sense data.  Keep them in the
@@ -460,8 +558,13 @@ mfi_attach(struct mfi_softc *sc)
 		device_printf(sc->mfi_dev, "Cannot allocate sense memory\n");
 		return (ENOMEM);
 	}
+#if defined(__x86_64__)
+	bus_dmamap_load(sc->mfi_sense_dmat, sc->mfi_sense_dmamap,
+	    sc->mfi_sense, sensesz, mfi_addr64_cb, &sc->mfi_sense_busaddr, 0);
+#else
 	bus_dmamap_load(sc->mfi_sense_dmat, sc->mfi_sense_dmamap,
 	    sc->mfi_sense, sensesz, mfi_addr32_cb, &sc->mfi_sense_busaddr, 0);
+#endif
 
 	if ((error = mfi_alloc_commands(sc)) != 0)
 		return (error);
@@ -633,6 +736,7 @@ mfi_dcmd_command(struct mfi_softc *sc, struct mfi_command **cmp, uint32_t opcode
 	struct mfi_command *cm;
 	struct mfi_dcmd_frame *dcmd;
 	void *buf = NULL;
+	uint32_t context = 0;
 
 	KKASSERT(lockstatus(&sc->mfi_io_lock, curthread) != 0);
 
@@ -640,6 +744,11 @@ mfi_dcmd_command(struct mfi_softc *sc, struct mfi_command **cmp, uint32_t opcode
 	if (cm == NULL)
 		return (EBUSY);
 
+	/* Zero out the MFI frame */
+	context = cm->cm_frame->header.context;
+	bzero(cm->cm_frame,sizeof (union mfi_frame));
+	cm->cm_frame->header.context = context;
+
 	if ((bufsize > 0) && (bufp != NULL)) {
 		if (*bufp == NULL) {
 			buf = kmalloc(bufsize, M_MFIBUF, M_NOWAIT|M_ZERO);
@@ -659,6 +768,7 @@ mfi_dcmd_command(struct mfi_softc *sc, struct mfi_command **cmp, uint32_t opcode
 	dcmd->header.timeout = 0;
 	dcmd->header.flags = 0;
 	dcmd->header.data_len = bufsize;
+	dcmd->header.scsi_status = 0;
 	dcmd->opcode = opcode;
 	cm->cm_sg = &dcmd->sgl;
 	cm->cm_total_frame_size = MFI_DCMD_FRAME_SIZE;
@@ -680,11 +790,17 @@ mfi_comms_init(struct mfi_softc *sc)
 	struct mfi_init_frame *init;
 	struct mfi_init_qinfo *qinfo;
 	int error;
+	uint32_t context = 0;
 
 	lockmgr(&sc->mfi_io_lock, LK_EXCLUSIVE);
 	if ((cm = mfi_dequeue_free(sc)) == NULL)
 		return (EBUSY);
 
+	/* Zero out the MFI frame */
+	context = cm->cm_frame->header.context;
+	bzero(cm->cm_frame,sizeof (union mfi_frame));
+	cm->cm_frame->header.context = context;
+
 	/*
 	 * Abuse the SG list area of the frame to hold the init_qinfo
 	 * object;
@@ -931,6 +1047,8 @@ mfi_startup(void *arg)
 	lockmgr(&sc->mfi_config_lock, LK_EXCLUSIVE);
 	lockmgr(&sc->mfi_io_lock, LK_EXCLUSIVE);
 	mfi_ldprobe(sc);
+	if (sc->mfi_flags & MFI_FLAGS_SKINNY)
+	    mfi_syspdprobe(sc);
 	lockmgr(&sc->mfi_io_lock, LK_RELEASE);
 	lockmgr(&sc->mfi_config_lock, LK_RELEASE);
 }
@@ -1004,6 +1122,76 @@ mfi_shutdown(struct mfi_softc *sc)
 	lockmgr(&sc->mfi_io_lock, LK_RELEASE);
 	return (error);
 }
+static void
+mfi_syspdprobe(struct mfi_softc *sc)
+{
+	struct mfi_frame_header *hdr;
+	struct mfi_command *cm = NULL;
+	struct mfi_pd_list *pdlist = NULL;
+	struct mfi_system_pd *syspd;
+	int error, i;
+
+	KKASSERT(lockstatus(&sc->mfi_config_lock, curthread) != 0);
+	KKASSERT(lockstatus(&sc->mfi_io_lock, curthread) != 0);
+	/* Add SYSTEM PD's */
+	error = mfi_dcmd_command(sc, &cm, MFI_DCMD_PD_LIST_QUERY,
+	    (void **)&pdlist, sizeof(*pdlist));
+	if (error) {
+	    device_printf(sc->mfi_dev,"Error while forming SYSTEM PD list\n");
+	    goto out;
+	}
+
+	cm->cm_flags = MFI_CMD_DATAIN | MFI_CMD_POLLED;
+	cm->cm_frame->dcmd.mbox[0] = MR_PD_QUERY_TYPE_EXPOSED_TO_HOST;
+	cm->cm_frame->dcmd.mbox[1] = 0;
+	if (mfi_mapcmd(sc, cm) != 0) {
+	    device_printf(sc->mfi_dev, "Failed to get syspd device listing\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);
+	hdr = &cm->cm_frame->header;
+	if (hdr->cmd_status != MFI_STAT_OK) {
+	    device_printf(sc->mfi_dev, "MFI_DCMD_PD_LIST_QUERY failed %x\n",
+			  hdr->cmd_status);
+	    goto out;
+	}
+	for (i=0;i<pdlist->count;i++) {
+	    if(pdlist->addr[i].device_id == pdlist->addr[i].encl_device_id)
+		goto skip_sys_pd_add;
+	    /* Get each PD and add it to the system */
+	    if (!TAILQ_EMPTY(&sc->mfi_syspd_tqh)) {
+	        TAILQ_FOREACH(syspd, &sc->mfi_syspd_tqh,pd_link) {
+		if (syspd->pd_id == pdlist->addr[i].device_id)
+		    goto skip_sys_pd_add;
+	        }
+	    }
+	    mfi_add_sys_pd(sc,pdlist->addr[i].device_id);
+	    skip_sys_pd_add:;
+
+	}
+	/* Delete SYSPD's whose state has been changed */
+	if (!TAILQ_EMPTY(&sc->mfi_syspd_tqh)) {
+	    TAILQ_FOREACH(syspd, &sc->mfi_syspd_tqh,pd_link) {
+			for (i=0;i<pdlist->count;i++) {
+				if (syspd->pd_id == pdlist->addr[i].device_id)
+				    goto skip_sys_pd_delete;
+			}
+			get_mplock();
+			device_delete_child(sc->mfi_dev,syspd->pd_dev);
+			rel_mplock();
+skip_sys_pd_delete:;
+		}
+	}
+out:
+	if (pdlist)
+	    kfree(pdlist, M_MFIBUF);
+	if (cm)
+	    mfi_release_command(cm);
+
+	return;
+}
 
 static void
 mfi_ldprobe(struct mfi_softc *sc)
@@ -1216,6 +1404,7 @@ mfi_parse_entries(struct mfi_softc *sc, int start_seq, int stop_seq)
 	struct mfi_evt_list *el;
 	union mfi_evt class_locale;
 	int error, i, seq, size;
+	uint32_t context = 0;
 
 	class_locale.members.reserved = 0;
 	class_locale.members.locale = mfi_event_locale;
@@ -1233,11 +1422,17 @@ mfi_parse_entries(struct mfi_softc *sc, int start_seq, int stop_seq)
 			return (EBUSY);
 		}
 
+		/* Zero out the MFI frame */
+		context = cm->cm_frame->header.context;
+		bzero(cm->cm_frame,sizeof (union mfi_frame));
+		cm->cm_frame->header.context = context;
+
 		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->header.scsi_status = 0;
 		dcmd->opcode = MFI_DCMD_CTRL_EVENT_GET;
 		((uint32_t *)&dcmd->mbox)[0] = seq;
 		((uint32_t *)&dcmd->mbox)[1] = class_locale.word;
@@ -1322,8 +1517,13 @@ mfi_add_ld(struct mfi_softc *sc, int id)
 		kfree(ld_info, M_MFIBUF);
 		return (0);
 	}
-
-	mfi_add_ld_complete(cm);
+	if (ld_info->ld_config.params.isSSCD != 1)
+		mfi_add_ld_complete(cm);
+	else {
+		mfi_release_command(cm);
+		if(ld_info)		/* SSCD drives ld_info free here */
+			kfree(ld_info, M_MFIBUF);
+	}
 	return (0);
 }
 
@@ -1363,24 +1563,202 @@ mfi_add_ld_complete(struct mfi_command *cm)
 	lockmgr(&sc->mfi_io_lock, LK_EXCLUSIVE);
 }
 
+static int
+mfi_add_sys_pd(struct mfi_softc *sc,int id)
+{
+	struct mfi_command *cm;
+	struct mfi_dcmd_frame *dcmd = NULL;
+	struct mfi_pd_info *pd_info = NULL;
+	int error;
+
+	KKASSERT(lockstatus(&sc->mfi_io_lock, curthread) != 0);
+
+	error = mfi_dcmd_command(sc,&cm,MFI_DCMD_PD_GET_INFO,
+		(void **)&pd_info, sizeof(*pd_info));
+	if (error) {
+	    device_printf(sc->mfi_dev,
+		"Failed to allocated for MFI_DCMD_PD_GET_INFO %d\n",error);
+	    if (pd_info)
+		kfree(pd_info,M_MFIBUF);
+	    return (error);
+	}
+	cm->cm_flags = MFI_CMD_DATAIN | MFI_CMD_POLLED;
+	dcmd = &cm->cm_frame->dcmd;
+	dcmd->mbox[0]=id;
+	dcmd->header.scsi_status = 0;
+	dcmd->header.pad0 = 0;
+	if (mfi_mapcmd(sc,cm) != 0) {
+	    device_printf(sc->mfi_dev,
+		"Failed to get physical drive info %d\n",id);
+	    kfree(pd_info,M_MFIBUF);
+	    return (0);
+	}
+	bus_dmamap_sync(sc->mfi_buffer_dmat,cm->cm_dmamap,BUS_DMASYNC_POSTREAD);
+	bus_dmamap_unload(sc->mfi_buffer_dmat,cm->cm_dmamap);
+	mfi_add_sys_pd_complete(cm);
+	return (0);
+}
+
+static void
+mfi_add_sys_pd_complete(struct mfi_command *cm)
+{
+	struct mfi_frame_header *hdr;
+	struct mfi_pd_info *pd_info;
+	struct mfi_softc *sc;
+	device_t child;
+
+	sc = cm->cm_sc;
+	hdr = &cm->cm_frame->header;
+	pd_info = cm->cm_private;
+
+	if (hdr->cmd_status != MFI_STAT_OK) {
+	    kfree(pd_info, M_MFIBUF);
+	    mfi_release_command(cm);
+	    return;
+	}
+	if (pd_info->fw_state != MFI_PD_STATE_SYSTEM) {
+	    device_printf(sc->mfi_dev,"PD=%x is not SYSTEM PD\n",
+			  pd_info->ref.v.device_id);
+	    kfree(pd_info, M_MFIBUF);
+	    mfi_release_command(cm);
+	    return;
+	}
+	mfi_release_command(cm);
+
+	lockmgr(&sc->mfi_io_lock, LK_RELEASE);
+	get_mplock();
+	if ((child = device_add_child(sc->mfi_dev, "mfisyspd", -1)) == NULL) {
+	    device_printf(sc->mfi_dev, "Failed to add system pd\n");
+	    kfree(pd_info, M_MFIBUF);
+	    rel_mplock();
+	    lockmgr(&sc->mfi_io_lock, LK_EXCLUSIVE);
+	    return;
+	}
+
+	device_set_ivars(child, pd_info);
+	device_set_desc(child, "MFI System PD");
+	bus_generic_attach(sc->mfi_dev);
+	rel_mplock();
+	lockmgr(&sc->mfi_io_lock, LK_EXCLUSIVE);
+}
 static struct mfi_command *
 mfi_bio_command(struct mfi_softc *sc)
 {
-	struct mfi_io_frame *io;
-	struct mfi_command *cm;
 	struct bio *bio;
-	struct buf *bp;
-	struct mfi_disk *disk;
-	int flags, blkcount;
+	struct mfi_command *cm = NULL;
 
-	if ((cm = mfi_dequeue_free(sc)) == NULL)
+	/*reserving two commands to avoid starvation for IOCTL*/
+	if (sc->mfi_qstat[MFIQ_FREE].q_length < 2) {
 		return (NULL);
+	}
 
 	if ((bio = mfi_dequeue_bio(sc)) == NULL) {
-		mfi_release_command(cm);
 		return (NULL);
 	}
+#if defined(__x86_64__)
+	if ((uint64_t)bio->bio_driver_info2 == MFI_LD_IO) {
+#else
+	if ((int)bio->bio_driver_info2 == MFI_LD_IO) {
+#endif
+		cm = mfi_build_ldio(sc,bio);
+#if defined(__x86_64__)
+	} else if ((uint64_t) bio->bio_driver_info2 == MFI_PD_IO) {
+#else
+	} else if ((int)bio->bio_driver_info2 == MFI_PD_IO) {
+#endif
+		cm = mfi_build_syspdio(sc,bio);
+	}
+	if (!cm)
+	    mfi_enqueue_bio(sc,bio);
+	return cm;
+}
+static struct mfi_command *
+mfi_build_syspdio(struct mfi_softc *sc, struct bio *bio)
+{
+	struct mfi_command *cm;
+	struct buf *bp;
+	struct mfi_system_pd *disk;
+	struct mfi_pass_frame *pass;
+	int flags = 0,blkcount = 0;
+	uint32_t context = 0;
+
+	if ((cm = mfi_dequeue_free(sc)) == NULL)
+	    return (NULL);
+
+	/* Zero out the MFI frame */
+	context = cm->cm_frame->header.context;
+	bzero(cm->cm_frame,sizeof(union mfi_frame));
+	cm->cm_frame->header.context = context;
+	bp = bio->bio_buf;
+	pass = &cm->cm_frame->pass;
+	bzero(pass->cdb,16);
+	pass->header.cmd = MFI_CMD_PD_SCSI_IO;
+	switch (bp->b_cmd & 0x03) {
+	case BUF_CMD_READ:
+#define SCSI_READ 0x28
+		pass->cdb[0] = SCSI_READ;
+		flags = MFI_CMD_DATAIN;
+		break;
+	case BUF_CMD_WRITE:
+#define SCSI_WRITE 0x2a
+		pass->cdb[0] = SCSI_WRITE;
+		flags = MFI_CMD_DATAOUT;
+		break;
+	default:
+		panic("Invalid bio command");
+	}
+
+	/* Cheat with the sector length to avoid a non-constant division */
+	blkcount = (bp->b_bcount + MFI_SECTOR_LEN - 1) / MFI_SECTOR_LEN;
+	disk = bio->bio_driver_info;
+	/* Fill the LBA and Transfer length in CDB */
+	pass->cdb[2] = ((bio->bio_offset / MFI_SECTOR_LEN) & 0xff000000) >> 24;
+	pass->cdb[3] = ((bio->bio_offset / MFI_SECTOR_LEN) & 0x00ff0000) >> 16;
+	pass->cdb[4] = ((bio->bio_offset / MFI_SECTOR_LEN) & 0x0000ff00) >> 8;
+	pass->cdb[5] = (bio->bio_offset / MFI_SECTOR_LEN) & 0x000000ff;
+	pass->cdb[7] = (blkcount & 0xff00) >> 8;
+	pass->cdb[8] = (blkcount & 0x00ff);
+	pass->header.target_id = disk->pd_id;
+	pass->header.timeout = 0;
+	pass->header.flags = 0;
+	pass->header.scsi_status = 0;
+	pass->header.sense_len = MFI_SENSE_LEN;
+	pass->header.data_len = bp->b_bcount;
+	pass->header.cdb_len = 10;
+#if defined(__x86_64__)
+	pass->sense_addr_lo = (cm->cm_sense_busaddr & 0xFFFFFFFF);
+	pass->sense_addr_hi = (cm->cm_sense_busaddr & 0xFFFFFFFF00000000) >> 32;
+#else
+	pass->sense_addr_lo = cm->cm_sense_busaddr;
+	pass->sense_addr_hi = 0;
+#endif
+	cm->cm_complete = mfi_bio_complete;
+	cm->cm_private = bio;
+	cm->cm_data = bp->b_data;
+	cm->cm_len = bp->b_bcount;
+	cm->cm_sg = &pass->sgl;
+	cm->cm_total_frame_size = MFI_PASS_FRAME_SIZE;
+	cm->cm_flags = flags;
+	return (cm);
+}
 
+static struct mfi_command *
+mfi_build_ldio(struct mfi_softc *sc,struct bio *bio)
+{
+	struct mfi_io_frame *io;
+	struct buf *bp;
+	struct mfi_disk *disk;
+	struct mfi_command *cm;
+	int flags, blkcount;
+	uint32_t context = 0;
+
+	if ((cm = mfi_dequeue_free(sc)) == NULL)
+	    return (NULL);
+
+	/* Zero out the MFI frame */
+	context = cm->cm_frame->header.context;
+	bzero(cm->cm_frame,sizeof(union mfi_frame));
+	cm->cm_frame->header.context = context;
 	bp = bio->bio_buf;
 	io = &cm->cm_frame->io;
 	switch (bp->b_cmd & 0x03) {
@@ -1402,10 +1780,16 @@ mfi_bio_command(struct mfi_softc *sc)
 	io->header.target_id = disk->ld_id;
 	io->header.timeout = 0;
 	io->header.flags = 0;
+	io->header.scsi_status = 0;
 	io->header.sense_len = MFI_SENSE_LEN;
 	io->header.data_len = blkcount;
+#if defined(__x86_64__)
+	io->sense_addr_lo = (cm->cm_sense_busaddr & 0xFFFFFFFF);
+	io->sense_addr_hi = (cm->cm_sense_busaddr & 0xFFFFFFFF00000000) >> 32;
+#else
 	io->sense_addr_lo = cm->cm_sense_busaddr;
 	io->sense_addr_hi = 0;
+#endif
 	io->lba_hi = ((bio->bio_offset / MFI_SECTOR_LEN) & 0xffffffff00000000) >> 32;
 	io->lba_lo = (bio->bio_offset / MFI_SECTOR_LEN) & 0xffffffff;
 	cm->cm_complete = mfi_bio_complete;
@@ -1510,6 +1894,8 @@ mfi_data_cb(void *arg, bus_dma_segment_t *segs, int nsegs, int error)
 	union mfi_sgl *sgl;
 	struct mfi_softc *sc;
 	int i, dir;
+	int sgl_mapped = 0;
+	int sge_size = 0;
 
 	cm = (struct mfi_command *)arg;
 	sc = cm->cm_sc;
@@ -1523,17 +1909,40 @@ mfi_data_cb(void *arg, bus_dma_segment_t *segs, int nsegs, int error)
 		return;
 	}
 
-	if ((sc->mfi_flags & MFI_FLAGS_SG64) == 0) {
-		for (i = 0; i < nsegs; i++) {
-			sgl->sg32[i].addr = segs[i].ds_addr;
-			sgl->sg32[i].len = segs[i].ds_len;
-		}
-	} else {
+	/* Use IEEE sgl only for IO's on a SKINNY controller
+	 * For other commands on a SKINNY controller use either
+	 * sg32 or sg64 based on the sizeof(bus_addr_t).
+	 * Also calculate the total frame size based on the type
+	 * of SGL used.
+	 */
+	if (((cm->cm_frame->header.cmd == MFI_CMD_PD_SCSI_IO) ||
+	    (cm->cm_frame->header.cmd == MFI_CMD_LD_READ) ||
+	    (cm->cm_frame->header.cmd == MFI_CMD_LD_WRITE)) &&
+	    (sc->mfi_flags & MFI_FLAGS_SKINNY)) {
 		for (i = 0; i < nsegs; i++) {
-			sgl->sg64[i].addr = segs[i].ds_addr;
-			sgl->sg64[i].len = segs[i].ds_len;
+			sgl->sg_skinny[i].addr = segs[i].ds_addr;
+			sgl->sg_skinny[i].len = segs[i].ds_len;
+			sgl->sg_skinny[i].flag = 0;
+		}
+		hdr->flags |= MFI_FRAME_IEEE_SGL | MFI_FRAME_SGL64;
+		sgl_mapped = 1;
+		sge_size = sizeof(struct mfi_sg_skinny);
+	}
+	if (!sgl_mapped) {
+		if ((sc->mfi_flags & MFI_FLAGS_SG64) == 0) {
+			for (i = 0; i < nsegs; i++) {
+				sgl->sg32[i].addr = segs[i].ds_addr;
+				sgl->sg32[i].len = segs[i].ds_len;
+			}
+			sge_size = sizeof(struct mfi_sg32);
+		} else {
+			for (i = 0; i < nsegs; i++) {
+				sgl->sg64[i].addr = segs[i].ds_addr;
+				sgl->sg64[i].len = segs[i].ds_len;
+			}
+			hdr->flags |= MFI_FRAME_SGL64;
+			sge_size = sizeof(struct mfi_sg64);
 		}
-		hdr->flags |= MFI_FRAME_SGL64;
 	}
 	hdr->sg_count = nsegs;
 
@@ -1555,7 +1964,7 @@ mfi_data_cb(void *arg, bus_dma_segment_t *segs, int nsegs, int error)
 	 * least 1 frame, so don't compensate for the modulo of the
 	 * following division.
 	 */
-	cm->cm_total_frame_size += (sc->mfi_sge_size * nsegs);
+	cm->cm_total_frame_size += (sge_size * nsegs);
 	cm->cm_extra_frames = (cm->cm_total_frame_size - 1) / MFI_FRAME_SIZE;
 
 	mfi_send_frame(sc, cm);
@@ -1647,6 +2056,7 @@ mfi_abort(struct mfi_softc *sc, struct mfi_command *cm_abort)
 	struct mfi_command *cm;
 	struct mfi_abort_frame *abort;
 	int i = 0;
+	uint32_t context = 0;
 
 	KKASSERT(lockstatus(&sc->mfi_io_lock, curthread) != 0);
 
@@ -1654,12 +2064,23 @@ mfi_abort(struct mfi_softc *sc, struct mfi_command *cm_abort)
 		return (EBUSY);
 	}
 
+	/* Zero out the MFI frame */
+	context = cm->cm_frame->header.context;
+	bzero(cm->cm_frame,sizeof (union mfi_frame));
+	cm->cm_frame->header.context = context;
+
 	abort = &cm->cm_frame->abort;
 	abort->header.cmd = MFI_CMD_ABORT;
 	abort->header.flags = 0;
+	abort->header.scsi_status = 0;
 	abort->abort_context = cm_abort->cm_frame->header.context;
+#if defined(__x86_64__)
+	abort->abort_mfi_addr_lo = cm_abort->cm_frame_busaddr & 0xFFFFFFFF;
+	abort->abort_mfi_addr_hi = (cm_abort->cm_frame_busaddr & 0xFFFFFFFF00000000 ) >> 32  ;
+#else
 	abort->abort_mfi_addr_lo = cm_abort->cm_frame_busaddr;
 	abort->abort_mfi_addr_hi = 0;
+#endif
 	cm->cm_data = NULL;
 	cm->cm_flags = MFI_CMD_POLLED;
 
@@ -1681,19 +2102,31 @@ mfi_dump_blocks(struct mfi_softc *sc, int id, uint64_t lba, void *virt, int len)
 	struct mfi_command *cm;
 	struct mfi_io_frame *io;
 	int error;
+	uint32_t context = 0;
 
 	if ((cm = mfi_dequeue_free(sc)) == NULL)
 		return (EBUSY);
 
+	/* Zero out the MFI frame */
+	context = cm->cm_frame->header.context;
+	bzero(cm->cm_frame,sizeof (union mfi_frame));
+	cm->cm_frame->header.context = context;
+
 	io = &cm->cm_frame->io;
 	io->header.cmd = MFI_CMD_LD_WRITE;
 	io->header.target_id = id;
 	io->header.timeout = 0;
 	io->header.flags = 0;
+	io->header.scsi_status = 0;
 	io->header.sense_len = MFI_SENSE_LEN;
 	io->header.data_len = (len + MFI_SECTOR_LEN - 1) / MFI_SECTOR_LEN;
+#if defined(__x86_64__)
+	io->sense_addr_lo = (cm->cm_sense_busaddr & 0xFFFFFFFF);
+	io->sense_addr_hi = (cm->cm_sense_busaddr & 0xFFFFFFFF00000000 ) >> 32;
+#else
 	io->sense_addr_lo = cm->cm_sense_busaddr;
 	io->sense_addr_hi = 0;
+#endif
 	io->lba_hi = (lba & 0xffffffff00000000) >> 32;
 	io->lba_lo = lba & 0xffffffff;
 	cm->cm_data = virt;
@@ -1711,6 +2144,58 @@ mfi_dump_blocks(struct mfi_softc *sc, int id, uint64_t lba, void *virt, int len)
 	return (error);
 }
 
+int
+mfi_dump_syspd_blocks(struct mfi_softc *sc, int id, uint64_t lba, void *virt,
+    int len)
+{
+	struct mfi_command *cm;
+	struct mfi_pass_frame *pass;
+	int error;
+	int blkcount = 0;
+
+	if ((cm = mfi_dequeue_free(sc)) == NULL)
+		return (EBUSY);
+
+	pass = &cm->cm_frame->pass;
+	bzero(pass->cdb,16);
+	pass->header.cmd = MFI_CMD_PD_SCSI_IO;
+	pass->cdb[0] = SCSI_WRITE;
+	pass->cdb[2] = (lba & 0xff000000) >> 24;
+	pass->cdb[3] = (lba & 0x00ff0000) >> 16;
+	pass->cdb[4] = (lba & 0x0000ff00) >> 8;
+	pass->cdb[5] = (lba & 0x000000ff);
+	blkcount = (len + MFI_SECTOR_LEN - 1) / MFI_SECTOR_LEN;
+	pass->cdb[7] = (blkcount & 0xff00) >> 8;
+	pass->cdb[8] = (blkcount & 0x00ff);
+	pass->header.target_id = id;
+	pass->header.timeout = 0;
+	pass->header.flags = 0;
+	pass->header.scsi_status = 0;
+	pass->header.sense_len = MFI_SENSE_LEN;
+	pass->header.data_len = len;
+	pass->header.cdb_len = 10;
+#if defined(__x86_64__)
+	pass->sense_addr_lo = (cm->cm_sense_busaddr & 0xFFFFFFFF);
+	pass->sense_addr_hi = (cm->cm_sense_busaddr & 0xFFFFFFFF00000000 ) >> 32;
+#else
+	pass->sense_addr_lo = cm->cm_sense_busaddr;
+	pass->sense_addr_hi = 0;
+#endif
+	cm->cm_data = virt;
+	cm->cm_len = len;
+	cm->cm_sg = &pass->sgl;
+	cm->cm_total_frame_size = MFI_PASS_FRAME_SIZE;
+	cm->cm_flags = MFI_CMD_POLLED | MFI_CMD_DATAOUT;
+
+	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);
+	mfi_release_command(cm);
+
+	return (error);
+}
+
 static int
 mfi_open(struct dev_open_args *ap)
 {
@@ -1784,6 +2269,9 @@ mfi_check_command_pre(struct mfi_softc *sc, struct mfi_command *cm)
 {
 	struct mfi_disk *ld, *ld2;
 	int error;
+	struct mfi_system_pd *syspd = NULL;
+	uint16_t syspd_id;
+	uint16_t *mbox;
 
 	KKASSERT(lockstatus(&sc->mfi_io_lock, curthread) != 0);
 	error = 0;
@@ -1812,6 +2300,22 @@ mfi_check_command_pre(struct mfi_softc *sc, struct mfi_command *cm)
 			}
 		}
 		break;
+	case MFI_DCMD_PD_STATE_SET:
+		mbox = (uint16_t *) cm->cm_frame->dcmd.mbox;
+		syspd_id = mbox[0];
+		if (mbox[2] == MFI_PD_STATE_UNCONFIGURED_GOOD) {
+			if (!TAILQ_EMPTY(&sc->mfi_syspd_tqh)) {
+			    TAILQ_FOREACH(syspd,&sc->mfi_syspd_tqh,pd_link) {
+				if(syspd->pd_id == syspd_id)
+					break;
+			   }
+			}
+		}
+		else
+			break;
+		if(syspd)
+			error = mfi_syspd_disable(syspd);
+		break;
 	default:
 		break;
 	}
@@ -1823,6 +2327,9 @@ static void
 mfi_check_command_post(struct mfi_softc *sc, struct mfi_command *cm)
 {
 	struct mfi_disk *ld, *ldn;
+	struct mfi_system_pd *syspd = NULL;
+	uint16_t syspd_id;
+	uint16_t *mbox;
 
 	switch (cm->cm_frame->dcmd.opcode) {
 	case MFI_DCMD_LD_DELETE:
@@ -1860,6 +2367,23 @@ mfi_check_command_post(struct mfi_softc *sc, struct mfi_command *cm)
 	case MFI_DCMD_CFG_FOREIGN_IMPORT:
 		mfi_ldprobe(sc);
 		break;
+	case MFI_DCMD_PD_STATE_SET:
+		mbox = (uint16_t *) cm->cm_frame->dcmd.mbox;
+		syspd_id = mbox[0];
+		if (mbox[2] == MFI_PD_STATE_UNCONFIGURED_GOOD) {
+			if (!TAILQ_EMPTY(&sc->mfi_syspd_tqh)) {
+			    TAILQ_FOREACH(syspd,&sc->mfi_syspd_tqh,pd_link) {
+				if(syspd->pd_id == syspd_id)
+					break;
+			   }
+			}
+		}
+		else
+			break;
+		/* If the transition fails then enable the syspd again */
+		if(syspd && cm->cm_frame->header.cmd_status != MFI_STAT_OK)
+			mfi_syspd_enable(syspd);
+		break;
 	}
 }
 
@@ -1938,6 +2462,55 @@ out:
 #endif
 
 static int
+mfi_check_for_sscd(struct mfi_softc *sc, struct mfi_command *cm)
+{
+	struct mfi_config_data *conf_data=(struct mfi_config_data *)cm->cm_data;
+	struct mfi_command *ld_cm = NULL;
+	struct mfi_ld_info *ld_info = NULL;
+	int error = 0;
+
+	if ((cm->cm_frame->dcmd.opcode == MFI_DCMD_CFG_ADD) &&
+	    (conf_data->ld[0].params.isSSCD == 1)) {
+		error = 1;
+	}else if (cm->cm_frame->dcmd.opcode == MFI_DCMD_LD_DELETE) {
+		error = mfi_dcmd_command (sc, &ld_cm, MFI_DCMD_LD_GET_INFO,
+					  (void **)&ld_info, sizeof(*ld_info));
+		if (error) {
+			device_printf(sc->mfi_dev,"Failed to allocate"
+					"MFI_DCMD_LD_GET_INFO %d", error);
+			if (ld_info)
+				kfree(ld_info, M_MFIBUF);
+			return 0;
+		}
+		ld_cm->cm_flags = MFI_CMD_DATAIN;
+		ld_cm->cm_frame->dcmd.mbox[0]= cm->cm_frame->dcmd.mbox[0];
+		ld_cm->cm_frame->header.target_id = cm->cm_frame->dcmd.mbox[0];
+		if (mfi_wait_command(sc, ld_cm) != 0) {
+			device_printf(sc->mfi_dev,"failed to get log drv\n");
+			mfi_release_command(ld_cm);
+			kfree(ld_info, M_MFIBUF);
+			return 0;
+		}
+
+		if(ld_cm->cm_frame->header.cmd_status != MFI_STAT_OK) {
+			kfree(ld_info, M_MFIBUF);
+			mfi_release_command(ld_cm);
+			return 0;
+		}
+		else
+			ld_info = (struct mfi_ld_info *)ld_cm->cm_private;
+
+		if (ld_info->ld_config.params.isSSCD == 1)
+			error = 1;
+
+		mfi_release_command(ld_cm);
+		kfree(ld_info, M_MFIBUF);
+
+	}
+	return error;
+}
+
+static int
 mfi_ioctl(struct dev_ioctl_args *ap)
 {
 	cdev_t dev = ap->a_head.a_dev;
@@ -1954,7 +2527,7 @@ mfi_ioctl(struct dev_ioctl_args *ap)
 	struct mfi_command *cm = NULL;
 	uint32_t context;
 	union mfi_sense_ptr sense_ptr;
-	uint8_t *data = NULL, *temp;
+	uint8_t *data = NULL, *temp, skip_pre_post = 0;
 	int i;
 	struct mfi_ioc_passthru *iop = (struct mfi_ioc_passthru *)arg;
 #ifdef __x86_64__
@@ -2038,6 +2611,8 @@ mfi_ioctl(struct dev_ioctl_args *ap)
 		    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;
+		cm->cm_frame->header.scsi_status = 0;
+		cm->cm_frame->header.pad0 = 0;
 		if (ioc->mfi_sge_count) {
 			cm->cm_sg =
 			    (union mfi_sgl *)&cm->cm_frame->bytes[ioc->mfi_sgl_off];
@@ -2103,15 +2678,23 @@ mfi_ioctl(struct dev_ioctl_args *ap)
 			locked = mfi_config_lock(sc, cm->cm_frame->dcmd.opcode);
 
 		if (cm->cm_frame->header.cmd == MFI_CMD_PD_SCSI_IO) {
+#if defined(__x86_64__)
+			cm->cm_frame->pass.sense_addr_lo = (cm->cm_sense_busaddr & 0xFFFFFFFF);
+			cm->cm_frame->pass.sense_addr_hi = (cm->cm_sense_busaddr& 0xFFFFFFFF00000000) >> 32;
+#else
 			cm->cm_frame->pass.sense_addr_lo = cm->cm_sense_busaddr;
 			cm->cm_frame->pass.sense_addr_hi = 0;
+#endif
 		}
 
 		lockmgr(&sc->mfi_io_lock, LK_EXCLUSIVE);
-		error = mfi_check_command_pre(sc, cm);
-		if (error) {
-			lockmgr(&sc->mfi_io_lock, LK_RELEASE);
-			goto out;
+		skip_pre_post = mfi_check_for_sscd(sc, cm);
+		if (!skip_pre_post) {
+			error = mfi_check_command_pre(sc, cm);
+			if (error) {
+				lockmgr(&sc->mfi_io_lock, LK_RELEASE);
+				goto out;
+			}
 		}
 
 		if ((error = mfi_wait_command(sc, cm)) != 0) {
@@ -2121,7 +2704,9 @@ mfi_ioctl(struct dev_ioctl_args *ap)
 			goto out;
 		}
 
-		mfi_check_command_post(sc, cm);
+		if (!skip_pre_post) {
+			mfi_check_command_post(sc, cm);
+		}
 		lockmgr(&sc->mfi_io_lock, LK_RELEASE);
 
 		temp = data;
@@ -2309,6 +2894,8 @@ mfi_linux_ioctl_int(struct cdev *dev, u_long cmd, caddr_t arg, int flag)
 		      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;
+		cm->cm_frame->header.scsi_status = 0;
+		cm->cm_frame->header.pad0 = 0;
 		if (l_ioc.lioc_sge_count)
 			cm->cm_sg =
 			    (union mfi_sgl *)&cm->cm_frame->bytes[l_ioc.lioc_sgl_off];
@@ -2352,8 +2939,13 @@ mfi_linux_ioctl_int(struct cdev *dev, u_long cmd, caddr_t arg, int flag)
 			locked = mfi_config_lock(sc, cm->cm_frame->dcmd.opcode);
 
 		if (cm->cm_frame->header.cmd == MFI_CMD_PD_SCSI_IO) {
+#if defined(__x86_64__)
+			cm->cm_frame->pass.sense_addr_lo = (cm->cm_sense_busaddr & 0xFFFFFFFF);
+			cm->cm_frame->pass.sense_addr_hi = (cm->cm_sense_busaddr & 0xFFFFFFFF00000000) >> 32;
+#else
 			cm->cm_frame->pass.sense_addr_lo = cm->cm_sense_busaddr;
 			cm->cm_frame->pass.sense_addr_hi = 0;
+#endif
 		}
 
 		lockmgr(&sc->mfi_io_lock, LK_EXCLUSIVE);
diff --git a/sys/dev/raid/mfi/mfi_cam.c b/sys/dev/raid/mfi/mfi_cam.c
index abf7e9e..0313dee 100644
--- a/sys/dev/raid/mfi/mfi_cam.c
+++ b/sys/dev/raid/mfi/mfi_cam.c
@@ -22,6 +22,36 @@
  * 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.
+ */
+/*-
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ *            Copyright 1994-2009 The FreeBSD Project.
+ *            All rights reserved.
+ *
+ * 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 FREEBSD PROJECT``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 FREEBSD PROJECT 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.
+ *
+ * The views and conclusions contained in the software and documentation
+ * are those of the authors and should not be interpreted as representing
+ * official policies,either expressed or implied, of the FreeBSD Project.
  *
  * $FreeBSD: src/sys/dev/mfi/mfi_cam.c,v 1.6 2011/06/28 08:36:48 kevlo Exp $
  */
@@ -260,12 +290,18 @@ mfip_start(void *data)
 	struct mfip_softc *sc;
 	struct mfi_pass_frame *pt;
 	struct mfi_command *cm;
+	uint32_t context = 0;
 
 	sc = ccbh->ccb_mfip_ptr;
 
 	if ((cm = mfi_dequeue_free(sc->mfi_sc)) == NULL)
 		return (NULL);
 
+	/* Zero out the MFI frame */
+	context = cm->cm_frame->header.context;
+	bzero(cm->cm_frame,sizeof(union mfi_frame));
+	cm->cm_frame->header.context = context;
+
 	pt = &cm->cm_frame->pass;
 	pt->header.cmd = MFI_CMD_PD_SCSI_IO;
 	pt->header.cmd_status = 0;
@@ -314,10 +350,8 @@ 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) {
diff --git a/sys/dev/raid/mfi/mfi_disk.c b/sys/dev/raid/mfi/mfi_disk.c
index d0ff04e..6de5819 100644
--- a/sys/dev/raid/mfi/mfi_disk.c
+++ b/sys/dev/raid/mfi/mfi_disk.c
@@ -22,6 +22,36 @@
  * 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.
+ */
+/*-
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ *            Copyright 1994-2009 The FreeBSD Project.
+ *            All rights reserved.
+ *
+ * 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 FREEBSD PROJECT``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 FREEBSD PROJECT 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.
+ *
+ * The views and conclusions contained in the software and documentation
+ * are those of the authors and should not be interpreted as representing
+ * official policies,either expressed or implied, of the FreeBSD Project.
  *
  * $FreeBSD: src/sys/dev/mfi/mfi_disk.c,v 1.8 2008/11/17 23:30:19 jhb Exp $
  */
@@ -176,7 +206,7 @@ mfi_disk_detach(device_t dev)
 	sc = device_get_softc(dev);
 
 	lockmgr(&sc->ld_controller->mfi_io_lock, LK_EXCLUSIVE);
-	if (((sc->ld_flags & MFI_DISK_FLAGS_OPEN)) &&
+	if ((sc->ld_flags & MFI_DISK_FLAGS_OPEN) &&
 	    (sc->ld_controller->mfi_keep_deleted_volumes ||
 	    sc->ld_controller->mfi_detaching)) {
 		lockmgr(&sc->ld_controller->mfi_io_lock, LK_RELEASE);
@@ -231,7 +261,7 @@ mfi_disk_disable(struct mfi_disk *sc)
 	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");
+		device_printf(sc->ld_dev, "Unable to delete busy ld device\n");
 		return (EBUSY);
 	}
 	sc->ld_flags |= MFI_DISK_FLAGS_DISABLED;
@@ -283,6 +313,8 @@ mfi_disk_strategy(struct dev_strategy_args *ap)
 
 	controller = sc->ld_controller;
 	bio->bio_driver_info = sc;
+	/* Mark it as LD IO */
+	bio->bio_driver_info2 = (void *)MFI_LD_IO;
 	lockmgr(&controller->mfi_io_lock, LK_EXCLUSIVE);
 	mfi_enqueue_bio(controller, bio);
 	devstat_start_transaction(&sc->ld_devstat);
diff --git a/sys/dev/raid/mfi/mfi_pci.c b/sys/dev/raid/mfi/mfi_pci.c
index 1a095bc..374048b 100644
--- a/sys/dev/raid/mfi/mfi_pci.c
+++ b/sys/dev/raid/mfi/mfi_pci.c
@@ -48,6 +48,36 @@
  * 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.
+ */
+/*-
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ *            Copyright 1994-2009 The FreeBSD Project.
+ *            All rights reserved.
+ *
+ * 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 FREEBSD PROJECT``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 FREEBSD PROJECT 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.
+ *
+ * The views and conclusions contained in the software and documentation
+ * are those of the authors and should not be interpreted as representing
+ * official policies,either expressed or implied, of the FreeBSD Project.
  *
  * $FreeBSD: src/sys/dev/mfi/mfi_pci.c,v 1.16 2010/03/02 17:34:11 kib Exp $
  */
@@ -114,12 +144,15 @@ struct mfi_ident {
 } mfi_identifiers[] = {
 	{0x1000, 0x0060, 0x1028, 0xffff, MFI_FLAGS_1078,  "Dell PERC 6"},
 	{0x1000, 0x0060, 0xffff, 0xffff, MFI_FLAGS_1078,  "LSI MegaSAS 1078"},
+	{0x1000, 0x0071, 0xffff, 0xffff, MFI_FLAGS_SKINNY, "Drake Skinny"},
+	{0x1000, 0x0073, 0xffff, 0xffff, MFI_FLAGS_SKINNY, "Drake Skinny"},
 	{0x1000, 0x0078, 0xffff, 0xffff, MFI_FLAGS_GEN2,  "LSI MegaSAS Gen2"},
 	{0x1000, 0x0079, 0x1028, 0x1f15, MFI_FLAGS_GEN2,  "Dell PERC H800 Adapter"},
 	{0x1000, 0x0079, 0x1028, 0x1f16, MFI_FLAGS_GEN2,  "Dell PERC H700 Adapter"},
 	{0x1000, 0x0079, 0x1028, 0x1f17, MFI_FLAGS_GEN2,  "Dell PERC H700 Integrated"},
 	{0x1000, 0x0079, 0x1028, 0x1f18, MFI_FLAGS_GEN2,  "Dell PERC H700 Modular"},
 	{0x1000, 0x0079, 0x1028, 0x1f19, MFI_FLAGS_GEN2,  "Dell PERC H700"},
+	{0x1000, 0x0079, 0x1028, 0x1f1a, MFI_FLAGS_GEN2,  "Dell PERC H800 Proto Adapter"},
 	{0x1000, 0x0079, 0x1028, 0x1f1b, MFI_FLAGS_GEN2,  "Dell PERC H800"},
 	{0x1000, 0x0079, 0x1028, 0xffff, MFI_FLAGS_GEN2,  "Dell PERC Gen2"},
 	{0x1000, 0x0079, 0xffff, 0xffff, MFI_FLAGS_GEN2,  "LSI MegaSAS Gen2"},
@@ -193,8 +226,9 @@ mfi_pci_attach(device_t dev)
 	    (sc->mfi_flags & MFI_FLAGS_1078)) {
 		/* 1068/1078: Memory mapped BAR is at offset 0x10 */
 		sc->mfi_regs_rid = PCIR_BAR(0);
-	} else if (sc->mfi_flags & MFI_FLAGS_GEN2) {
-		/* GEN2: Memory mapped BAR is at offset 0x14 */
+	} else if ((sc->mfi_flags & MFI_FLAGS_GEN2) ||
+		   (sc->mfi_flags & MFI_FLAGS_SKINNY)) {
+		/* GEN2/Skinny: Memory mapped BAR is at offset 0x14 */
 		sc->mfi_regs_rid = PCIR_BAR(1);
 	}
 	if ((sc->mfi_regs_resource = bus_alloc_resource_any(sc->mfi_dev,
@@ -237,6 +271,7 @@ mfi_pci_detach(device_t dev)
 {
 	struct mfi_softc *sc;
 	struct mfi_disk *ld;
+	struct mfi_system_pd *syspd = NULL;
 	int error;
 
 	sc = device_get_softc(dev);
@@ -258,6 +293,14 @@ mfi_pci_detach(device_t dev)
 			return (error);
 		}
 	}
+	if (!TAILQ_EMPTY(&sc->mfi_syspd_tqh))
+	while ((syspd = TAILQ_FIRST(&sc->mfi_syspd_tqh)) != NULL) {
+		if ((error = device_delete_child(dev,syspd->pd_dev)) != 0) {
+			sc->mfi_detaching = 0;
+			lockmgr(&sc->mfi_config_lock, LK_RELEASE);
+			return (error);
+		}
+	}
 	lockmgr(&sc->mfi_config_lock, LK_RELEASE);
 
 	EVENTHANDLER_DEREGISTER(shutdown_final, sc->mfi_eh);
diff --git a/sys/dev/raid/mfi/mfi_syspd.c b/sys/dev/raid/mfi/mfi_syspd.c
new file mode 100644
index 0000000..603ca6e
--- /dev/null
+++ b/sys/dev/raid/mfi/mfi_syspd.c
@@ -0,0 +1,325 @@
+/*-
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ *            Copyright 1994-2009 The FreeBSD Project.
+ *            All rights reserved.
+ *
+ * 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 FREEBSD PROJECT``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 FREEBSD PROJECT 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.
+ *
+ * The views and conclusions contained in the software and documentation
+ * are those of the authors and should not be interpreted as representing
+ * official policies,either expressed or implied, of the FreeBSD Project.
+ *
+ * $FreeBSD: src/sys/dev/mfi/mfi_pddisk.c,v 1.2.2.6 2007/08/24 17:29:18 jhb Exp $
+ */
+
+#include "opt_mfi.h"
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/kernel.h>
+#include <sys/module.h>
+#include <sys/malloc.h>
+#include <sys/uio.h>
+
+#include <sys/bio.h>
+#include <sys/buf2.h>
+#include <sys/bus.h>
+#include <sys/conf.h>
+#include <sys/disk.h>
+
+#include <vm/vm.h>
+#include <vm/pmap.h>
+
+#include <machine/md_var.h>
+#include <sys/rman.h>
+
+#include <dev/raid/mfi/mfireg.h>
+#include <dev/raid/mfi/mfi_ioctl.h>
+#include <dev/raid/mfi/mfivar.h>
+
+static int	mfi_syspd_probe(device_t dev);
+static int	mfi_syspd_attach(device_t dev);
+static int	mfi_syspd_detach(device_t dev);
+
+static d_open_t		mfi_syspd_open;
+static d_close_t	mfi_syspd_close;
+static d_strategy_t	mfi_syspd_strategy;
+static d_dump_t		mfi_syspd_dump;
+
+static struct dev_ops mfi_syspd_ops = {
+	{ "mfisyspd", 0, D_DISK },
+	.d_open = mfi_syspd_open,
+	.d_close = mfi_syspd_close,
+	.d_strategy = mfi_syspd_strategy,
+	.d_dump = mfi_syspd_dump,
+};
+
+static devclass_t	mfi_syspd_devclass;
+
+static device_method_t mfi_syspd_methods[] = {
+	DEVMETHOD(device_probe,		mfi_syspd_probe),
+	DEVMETHOD(device_attach,	mfi_syspd_attach),
+	DEVMETHOD(device_detach,	mfi_syspd_detach),
+	{ 0, 0 }
+};
+
+static driver_t mfi_syspd_driver = {
+	"mfisyspd",
+	mfi_syspd_methods,
+	sizeof(struct mfi_system_pd)
+};
+
+DRIVER_MODULE(mfisyspd, mfi, mfi_syspd_driver, mfi_syspd_devclass, 0, 0);
+
+static int
+mfi_syspd_probe(device_t dev)
+{
+
+	return (0);
+}
+
+static int
+mfi_syspd_attach(device_t dev)
+{
+	struct mfi_system_pd *sc;
+	struct mfi_pd_info *pd_info;
+	struct disk_info info;
+	uint64_t sectors;
+	uint32_t secsize;
+
+	sc = device_get_softc(dev);
+	pd_info = device_get_ivars(dev);
+
+	sc->pd_dev = dev;
+	sc->pd_id = pd_info->ref.v.device_id;
+	sc->pd_unit = device_get_unit(dev);
+	sc->pd_info = pd_info;
+	sc->pd_controller = device_get_softc(device_get_parent(dev));
+	sc->pd_flags = 0;
+
+	sectors = pd_info->raw_size;
+	secsize = MFI_SECTOR_LEN;
+	lockmgr(&sc->pd_controller->mfi_io_lock, LK_EXCLUSIVE);
+	TAILQ_INSERT_TAIL(&sc->pd_controller->mfi_syspd_tqh, sc, pd_link);
+	lockmgr(&sc->pd_controller->mfi_io_lock, LK_RELEASE);
+	device_printf(dev, "%juMB (%ju sectors) SYSPD volume\n",
+		      sectors / (1024 * 1024 / secsize), sectors);
+
+	devstat_add_entry(&sc->pd_devstat, "mfisyspd", device_get_unit(dev),
+	    MFI_SECTOR_LEN, DEVSTAT_NO_ORDERED_TAGS,
+	    DEVSTAT_TYPE_STORARRAY | DEVSTAT_TYPE_IF_OTHER,
+	    DEVSTAT_PRIORITY_ARRAY);
+
+	sc->pd_disk.d_cdev = disk_create(sc->pd_unit, &sc->pd_disk,
+	    &mfi_syspd_ops);
+	sc->pd_disk.d_cdev->si_drv1 = sc;
+	sc->pd_disk.d_cdev->si_iosize_max = sc->pd_controller->mfi_max_io *
+	    secsize;
+
+	bzero(&info, sizeof(info));
+	info.d_media_blksize = secsize; /* mandatory */
+	info.d_media_blocks = sectors;
+
+	if (info.d_media_blocks >= (1 * 1024 * 1024)) {
+		info.d_nheads = 255;
+		info.d_secpertrack = 63;
+	} else {
+		info.d_nheads = 64;
+		info.d_secpertrack = 32;
+	}
+
+	disk_setdiskinfo(&sc->pd_disk, &info);
+
+	device_printf(dev, " SYSPD volume attached\n");
+	return (0);
+}
+
+static int
+mfi_syspd_detach(device_t dev)
+{
+	struct mfi_system_pd *sc;
+
+	sc = device_get_softc(dev);
+	device_printf(dev, "Detaching syspd\n");
+	lockmgr(&sc->pd_controller->mfi_io_lock, LK_EXCLUSIVE);
+	if ((sc->pd_flags & MFI_DISK_FLAGS_OPEN) &&
+	    (sc->pd_controller->mfi_keep_deleted_volumes ||
+	    sc->pd_controller->mfi_detaching)) {
+		lockmgr(&sc->pd_controller->mfi_io_lock, LK_RELEASE);
+		device_printf(dev,"Cant detach syspd\n");
+		return (EBUSY);
+	}
+	lockmgr(&sc->pd_controller->mfi_io_lock, LK_RELEASE);
+
+	disk_destroy(&sc->pd_disk);
+	devstat_remove_entry(&sc->pd_devstat);
+	lockmgr(&sc->pd_controller->mfi_io_lock, LK_EXCLUSIVE);
+	TAILQ_REMOVE(&sc->pd_controller->mfi_syspd_tqh, sc, pd_link);
+	lockmgr(&sc->pd_controller->mfi_io_lock, LK_RELEASE);
+	kfree(sc->pd_info, M_MFIBUF);
+	return (0);
+}
+
+static int
+mfi_syspd_open(struct dev_open_args *ap)
+{
+	struct mfi_system_pd *sc = ap->a_head.a_dev->si_drv1;
+	int error;
+
+	lockmgr(&sc->pd_controller->mfi_io_lock, LK_EXCLUSIVE);
+	if (sc->pd_flags & MFI_DISK_FLAGS_DISABLED)
+		error = ENXIO;
+	else {
+		sc->pd_flags |= MFI_DISK_FLAGS_OPEN;
+		error = 0;
+	}
+	lockmgr(&sc->pd_controller->mfi_io_lock, LK_RELEASE);
+	return (error);
+}
+
+static int
+mfi_syspd_close(struct dev_close_args *ap)
+{
+	struct mfi_system_pd *sc = ap->a_head.a_dev->si_drv1;
+
+	lockmgr(&sc->pd_controller->mfi_io_lock, LK_EXCLUSIVE);
+	sc->pd_flags &= ~MFI_DISK_FLAGS_OPEN;
+	lockmgr(&sc->pd_controller->mfi_io_lock, LK_RELEASE);
+
+	return (0);
+}
+
+int
+mfi_syspd_disable(struct mfi_system_pd *sc)
+{
+
+	device_printf(sc->pd_dev,"syspd disable \n");
+	KKASSERT(lockstatus(&sc->pd_controller->mfi_io_lock, curthread) != 0);
+	if (sc->pd_flags & MFI_DISK_FLAGS_OPEN) {
+		if (sc->pd_controller->mfi_delete_busy_volumes)
+			return (0);
+		device_printf(sc->pd_dev, "Unable to delete busy syspd device\n");
+		return (EBUSY);
+	}
+	sc->pd_flags |= MFI_DISK_FLAGS_DISABLED;
+	return (0);
+}
+
+void
+mfi_syspd_enable(struct mfi_system_pd *sc)
+{
+
+	device_printf(sc->pd_dev,"syspd enable \n");
+	KKASSERT(lockstatus(&sc->pd_controller->mfi_io_lock, curthread) != 0);
+	sc->pd_flags &= ~MFI_DISK_FLAGS_DISABLED;
+}
+
+static int
+mfi_syspd_strategy(struct dev_strategy_args *ap)
+{
+	struct bio *bio = ap->a_bio;
+	struct buf *bp = bio->bio_buf;
+	struct mfi_system_pd *sc = ap->a_head.a_dev->si_drv1;
+	struct mfi_softc *controller;
+
+	if (sc == NULL) {
+		bp->b_error = EINVAL;
+		bp->b_flags |= B_ERROR;
+		bp->b_resid = bp->b_bcount;
+		biodone(bio);
+		return (0);
+	}
+
+	/*
+	 * XXX swildner
+	 *
+	 * If it's a null transfer, do nothing. FreeBSD's original driver
+	 * doesn't have this, but that caused hard error messages (even
+	 * though everything else continued to work fine). Interestingly,
+	 * only when HAMMER was used.
+	 *
+	 * Several others of our RAID drivers have this check, such as
+	 * aac(4) and ida(4), so we insert it here, too.
+	 *
+	 * The cause of null transfers is yet unknown.
+	 */
+	if (bp->b_bcount == 0) {
+		bp->b_resid = bp->b_bcount;
+		biodone(bio);
+		return (0);
+	}
+
+	controller = sc->pd_controller;
+	bio->bio_driver_info = sc;
+	/* Mark it as system PD IO */
+	bio->bio_driver_info2 = (void *)MFI_PD_IO;
+	lockmgr(&controller->mfi_io_lock, LK_EXCLUSIVE);
+	mfi_enqueue_bio(controller, bio);
+	devstat_start_transaction(&sc->pd_devstat);
+	mfi_startio(controller);
+	lockmgr(&controller->mfi_io_lock, LK_RELEASE);
+	return (0);
+}
+
+#if 0
+void
+mfi_disk_complete(struct bio *bio)
+{
+	struct mfi_system_pd *sc = bio->bio_driver_info;
+	struct buf *bp = bio->bio_buf;
+
+	devstat_end_transaction_buf(&sc->pd_devstat, bp);
+	if (bio->b_flags & B_ERROR) {
+		if (bp->b_error == 0)
+			bp->b_error = EIO;
+		diskerr(bio, sc->pd_disk.d_cdev, "hard error", -1, 1);
+		kprintf("\n");
+	} else {
+		bp->b_resid = 0;
+	}
+	biodone(bio);
+}
+#endif
+
+static int
+mfi_syspd_dump(struct dev_dump_args *ap)
+{
+	cdev_t dev = ap->a_head.a_dev;
+	off_t offset = ap->a_offset;
+	void *virt = ap->a_virtual;
+	size_t len = ap->a_length;
+	struct mfi_system_pd *sc;
+	struct mfi_softc *parent_sc;
+	int error;
+
+	sc = dev->si_drv1;
+	parent_sc = sc->pd_controller;
+
+	if (len > 0) {
+		if ((error = mfi_dump_syspd_blocks(parent_sc, sc->pd_id, offset /
+		    MFI_SECTOR_LEN, virt, len)) != 0)
+			return (error);
+	} else {
+		/* mfi_sync_cache(parent_sc, sc->ld_id); */
+	}
+	return (0);
+}
diff --git a/sys/dev/raid/mfi/mfireg.h b/sys/dev/raid/mfi/mfireg.h
index 92b6f19..f2396d4 100644
--- a/sys/dev/raid/mfi/mfireg.h
+++ b/sys/dev/raid/mfi/mfireg.h
@@ -48,6 +48,36 @@
  * 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.
+ */
+/*-
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ *            Copyright 1994-2009 The FreeBSD Project.
+ *            All rights reserved.
+ *
+ * 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 FREEBSD PROJECT``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 FREEBSD PROJECT 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.
+ *
+ * The views and conclusions contained in the software and documentation
+ * are those of the authors and should not be interpreted as representing
+ * official policies,either expressed or implied, of the FreeBSD Project.
  *
  * $FreeBSD: src/sys/dev/mfi/mfireg.h,v 1.16 2011/07/14 20:20:33 jhb Exp $
  */
@@ -98,6 +128,20 @@
 #define MFI_GEN2_EIM	0x00000005	/* GEN2 enable interrupt mask */
 #define MFI_GEN2_RM	0x00000001	/* reply GEN2 message interrupt */
 
+/*
+ * gen2 specific changes
+ */
+#define MFI_GEN2_EIM	0x00000005	/* gen2 enable interrupt mask */
+#define MFI_GEN2_RM	0x00000001	/* reply gen2 message interrupt */
+
+/*
+ * skinny specific changes
+ */
+#define MFI_SKINNY_IDB	0x00	/* Inbound doorbell is at 0x00 for skinny */
+#define MFI_IQPL	0x000000c0
+#define MFI_IQPH	0x000000c4
+#define MFI_SKINNY_RM	0x00000001	/* reply skinny message interrupt */
+
 /* Bits for MFI_OSTS */
 #define MFI_OSTS_INTR_VALID	0x00000002
 
@@ -118,6 +162,8 @@
 #define MFI_FWSTATE_FAULT		0xf0000000
 #define MFI_FWSTATE_MAXSGL_MASK		0x00ff0000
 #define MFI_FWSTATE_MAXCMD_MASK		0x0000ffff
+#define MFI_FWSTATE_HOSTMEMREQD_MASK	0x08000000
+#define MFI_FWSTATE_BOOT_MESSAGE_PENDING	0x90000000
 
 /*
  * Control bits to drive the card to ready state.  These go into the IDB
@@ -144,6 +190,7 @@ typedef enum {
 
 /* Direct commands */
 typedef enum {
+	MFI_DCMD_CTRL_MFI_HOST_MEM_ALLOC = 0x0100e100,
 	MFI_DCMD_CTRL_GETINFO =		0x01010000,
 	MFI_DCMD_CTRL_MFC_DEFAULTS_GET =0x010e0201,
 	MFI_DCMD_CTRL_MFC_DEFAULTS_SET =0x010e0202,
@@ -163,6 +210,7 @@ typedef enum {
 	MFI_DCMD_FLASH_FW_FLASH =	0x010f0300,
 	MFI_DCMD_FLASH_FW_CLOSE =	0x010f0400,
 	MFI_DCMD_PD_GET_LIST =		0x02010000,
+	MFI_DCMD_PD_LIST_QUERY =	0x02010100,
 	MFI_DCMD_PD_GET_INFO = 		0x02020000,
 	MFI_DCMD_PD_STATE_SET =		0x02030100,
 	MFI_DCMD_PD_REBUILD_START =	0x02040100,
@@ -212,6 +260,7 @@ typedef enum {
 #define MFI_FRAME_DIR_WRITE			0x0008
 #define MFI_FRAME_DIR_READ			0x0010
 #define MFI_FRAME_DIR_BOTH			0x0018
+#define MFI_FRAME_IEEE_SGL			0x0020
 
 /* MFI Status codes */
 typedef enum {
@@ -351,6 +400,15 @@ typedef enum {
 	MR_PD_CACHE_DISABLE =		2
 } mfi_pd_cache;
 
+typedef enum {
+	MR_PD_QUERY_TYPE_ALL =		0,
+	MR_PD_QUERY_TYPE_STATE =	1,
+	MR_PD_QUERY_TYPE_POWER_STATE =	2,
+	MR_PD_QUERY_TYPE_MEDIA_TYPE =	3,
+	MR_PD_QUERY_TYPE_SPEED =	4,
+	MR_PD_QUERY_TYPE_EXPOSED_TO_HOST =	5, /*query for system drives */
+} mfi_pd_query_type;
+
 /*
  * Other propertities and definitions
  */
@@ -383,9 +441,16 @@ struct mfi_sg64 {
 	uint32_t	len;
 } __packed;
 
+struct mfi_sg_skinny {
+	uint64_t	addr;
+	uint32_t	len;
+	uint32_t	flag;
+} __packed;
+
 union mfi_sgl {
 	struct mfi_sg32	sg32[1];
 	struct mfi_sg64	sg64[1];
+	struct mfi_sg_skinny sg_skinny[1];
 } __packed;
 
 /* Message frames.  All messages have a common header */
@@ -399,6 +464,10 @@ struct mfi_frame_header {
 	uint8_t		cdb_len;
 	uint8_t		sg_count;
 	uint32_t	context;
+	/*
+	 * pad0 is MSI Specific. Not used by Driver. Zero the value before
+	 * sending the command to f/w
+	 */
 	uint32_t	pad0;
 	uint16_t	flags;
 #define MFI_FRAME_DATAOUT	0x08
@@ -446,10 +515,10 @@ struct mfi_dcmd_frame {
 struct mfi_abort_frame {
 	struct mfi_frame_header header;
 	uint32_t	abort_context;
-	uint32_t	pad;
+	uint32_t	reserved0;
 	uint32_t	abort_mfi_addr_lo;
 	uint32_t	abort_mfi_addr_hi;
-	uint32_t	reserved[6];
+	uint32_t	reserved1[6];
 } __packed;
 
 struct mfi_smp_frame {
@@ -963,10 +1032,11 @@ struct mfi_pd_address {
 	uint64_t		sas_addr[2];
 } __packed;
 
+#define MAX_SYS_PDS 240
 struct mfi_pd_list {
 	uint32_t		size;
 	uint32_t		count;
-	struct mfi_pd_address	addr[0];
+	struct mfi_pd_address	addr[MAX_SYS_PDS];
 } __packed;
 
 enum mfi_pd_state {
@@ -1039,7 +1109,9 @@ struct mfi_ld_params {
 #define	MFI_LD_PARAMS_INIT_QUICK	1
 #define	MFI_LD_PARAMS_INIT_FULL		2
 	uint8_t			is_consistent;
-	uint8_t			reserved[23];
+	uint8_t			reserved1[6];
+	uint8_t			isSSCD;
+	uint8_t			reserved2[16];
 } __packed;
 
 struct mfi_ld_progress {
@@ -1117,9 +1189,9 @@ struct mfi_config_data {
 	uint16_t		spares_count;
 	uint16_t		spares_size;
 	uint8_t			reserved[16];
-	struct mfi_array	array[0];
-	struct mfi_ld_config	ld[0];
-	struct mfi_spare	spare[0];
+	struct mfi_array	array[1];
+	struct mfi_ld_config	ld[1];
+	struct mfi_spare	spare[1];
 } __packed;
 
 struct mfi_bbu_capacity_info {
diff --git a/sys/dev/raid/mfi/mfivar.h b/sys/dev/raid/mfi/mfivar.h
index 99eca53..ea1c700 100644
--- a/sys/dev/raid/mfi/mfivar.h
+++ b/sys/dev/raid/mfi/mfivar.h
@@ -48,6 +48,36 @@
  * 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.
+ */
+/*-
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ *            Copyright 1994-2009 The FreeBSD Project.
+ *            All rights reserved.
+ *
+ * 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 FREEBSD PROJECT``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 FREEBSD PROJECT 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.
+ *
+ * The views and conclusions contained in the software and documentation
+ * are those of the authors and should not be interpreted as representing
+ * official policies,either expressed or implied, of the FreeBSD Project.
  *
  * $FreeBSD: src/sys/dev/mfi/mfivar.h,v 1.13 2009/07/10 08:18:08 scottl Exp $
  */
@@ -82,9 +112,17 @@ struct mfi_command {
 	time_t			cm_timestamp;
 	struct mfi_softc	*cm_sc;
 	union mfi_frame		*cm_frame;
+#if defined(__x86_64__)
+	uint64_t		cm_frame_busaddr;
+#else
 	uint32_t		cm_frame_busaddr;
+#endif
 	struct mfi_sense	*cm_sense;
+#if defined(__x86_64__)
+	uint64_t		cm_sense_busaddr;
+#else
 	uint32_t		cm_sense_busaddr;
+#endif
 	bus_dmamap_t		cm_dmamap;
 	union mfi_sgl		*cm_sg;
 	void			*cm_data;
@@ -122,6 +160,18 @@ struct mfi_disk {
 #define	MFI_DISK_FLAGS_DISABLED	0x02
 };
 
+struct mfi_system_pd {
+	TAILQ_ENTRY(mfi_system_pd)	pd_link;
+	device_t	pd_dev;
+	int		pd_id;
+	int		pd_unit;
+	struct mfi_softc *pd_controller;
+	struct mfi_pd_info	*pd_info;
+	struct disk	pd_disk;
+	struct devstat	pd_devstat;
+	int		pd_flags;
+};
+
 struct mfi_aen {
 	TAILQ_ENTRY(mfi_aen) aen_link;
 	struct proc			*p;
@@ -137,6 +187,7 @@ struct mfi_softc {
 #define MFI_FLAGS_1064R		(1<<4)
 #define MFI_FLAGS_1078		(1<<5)
 #define MFI_FLAGS_GEN2		(1<<6)
+#define MFI_FLAGS_SKINNY	(1<<7)
 
 	struct mfi_hwcomms		*mfi_comms;
 	TAILQ_HEAD(,mfi_command)	mfi_free;
@@ -164,6 +215,7 @@ struct mfi_softc {
 
 	TAILQ_HEAD(,mfi_aen)		mfi_aen_pids;
 	struct mfi_command		*mfi_aen_cm;
+	struct mfi_command		*mfi_skinny_cm;
 	uint32_t			mfi_aen_triggered;
 	uint32_t			mfi_poll_waiting;
 	struct kqinfo			mfi_kq;
@@ -217,6 +269,7 @@ struct mfi_softc {
 	uint32_t			mfi_max_io;
 
 	TAILQ_HEAD(,mfi_disk)		mfi_ld_tqh;
+	TAILQ_HEAD(,mfi_system_pd)	mfi_syspd_tqh;
 	eventhandler_tag		mfi_eh;
 	struct cdev			*mfi_cdev;
 
@@ -244,6 +297,9 @@ 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);
+extern int mfi_syspd_disable(struct mfi_system_pd *);
+extern void mfi_syspd_enable(struct mfi_system_pd *);
+extern int mfi_dump_syspd_blocks(struct mfi_softc *, int id, uint64_t, void *, int);
 
 #define MFIQ_ADD(sc, qname)					\
 	do {							\
@@ -386,6 +442,9 @@ MALLOC_DECLARE(M_MFIBUF);
 
 #define MFI_CMD_TIMEOUT 30
 #define MFI_MAXPHYS (128 * 1024)
+#define MFI_PD_IO	0
+#define MFI_LD_IO	1
+#define SKINNY_MEMORY 0x02000000
 
 #ifdef MFI_DEBUG
 extern void mfi_print_cmd(struct mfi_command *cm);
diff --git a/sys/sys/bio.h b/sys/sys/bio.h
index bb502dc..b97bbab 100644
--- a/sys/sys/bio.h
+++ b/sys/sys/bio.h
@@ -69,6 +69,7 @@ struct bio {
 	biodone_t	*bio_done;   	/* MPSAFE caller completion function */
 	off_t		bio_offset;	/* Logical offset relative to device */
 	void		*bio_driver_info;
+	void		*bio_driver_info2;
 	int		bio_flags;
 	union {
 		void	*ptr;
-- 
1.7.4.4

