mfi(4): Merge LSI's latest driver changes (updates us to version 3.981).
authorSascha Wildner <saw@online.de>
Thu, 11 Aug 2011 18:31:01 +0000 (20:31 +0200)
committerSascha Wildner <saw@online.de>
Thu, 11 Aug 2011 18:31:31 +0000 (20:31 +0200)
This adds support for a number of cards (according to LSI's README):

* LSI MegaRAID SAS 9240-4i
* LSI MegaRAID SAS 9240-8i
* LSI MegaRAID SAS 9260-4i
* LSI MegaRAID SAS 9260-8i
* LSI MegaRAID SAS 9260DE-8i
* LSI MegaRAID SAS 9260-16i
* LSI MegaRAID SAS 9261-8i
* LSI MegaRAID SAS 9280-4i4e
* LSI MegaRAID SAS 9280-8e
* LSI MegaRAID SAS 9280DE-8e
* LSI MegaRAID SAS 9280-16i4e
* LSI MegaRAID SAS 9280-24i4e

It was tested by Tomi Juvonen <tomi.juvonen@kenou.biz> on an
IBM ServeRAID M1015 controller using LSI's 9240-8i IR firmware.

share/man/man4/mfi.4
sys/conf/files
sys/dev/raid/mfi/Makefile
sys/dev/raid/mfi/mfi.c
sys/dev/raid/mfi/mfi_cam.c
sys/dev/raid/mfi/mfi_disk.c
sys/dev/raid/mfi/mfi_pci.c
sys/dev/raid/mfi/mfi_syspd.c [new file with mode: 0644]
sys/dev/raid/mfi/mfireg.h
sys/dev/raid/mfi/mfivar.h

index a49dcd4..ffad85e 100644 (file)
@@ -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 11, 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 access to JBOD disks is provided via
+.Pa /dev/mfisyspd?
 device nodes.
 A simple management interface is also provided on a per-controller basis via
 the
@@ -64,6 +66,18 @@ Older SCSI and SATA MegaRAID cards are supported by
 .Xr amr 4
 and will not work with this driver.
 .Pp
+3 Gb/s and 6 Gb/s support both initiator target (IT) and integrated RAID (IR)
+firmware (see
+.Pa http://kb.lsi.com/KnowledgebaseArticle16266.aspx ) .
+The
+.Nm
+driver supports controllers with an IR image.
+At least some cards (such as the
+.Tn IBM ServeRAID M1015 )
+will attach to the
+.Xr mps 4
+driver when IT firmware is used.
+.Pp
 Two sysctls are provided to tune the
 .Nm
 driver's behavior when a request is made to remove a mounted volume.
@@ -85,12 +99,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 +136,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?
+JBOD disk interface
 .It Pa /dev/mfi?
 management interface
 .El
@@ -108,9 +148,12 @@ 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"
+dito for JBOD disks
 .El
 .Sh SEE ALSO
 .Xr amr 4 ,
+.Xr mps 4 ,
 .Xr pci 4 ,
 .Xr mfiutil 8
 .Sh HISTORY
@@ -123,5 +166,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.
index 09fb925..44f9272 100644 (file)
@@ -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
index 5a81b72..809eac3 100644 (file)
@@ -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
 
index 210f5f8..e48d06d 100644 (file)
  * 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 $
  */
 #include <sys/device.h>
 #include <sys/mplock2.h>
 
+#include <bus/cam/scsi/scsi_all.h>
+
 #include <dev/raid/mfi/mfireg.h>
 #include <dev/raid/mfi/mfi_ioctl.h>
 #include <dev/raid/mfi/mfivar.h>
@@ -88,13 +120,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,11 +200,14 @@ 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) {
+               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);
        }
 }
 
@@ -202,30 +242,33 @@ mfi_check_clear_intr_ppc(struct mfi_softc *sc)
        int32_t status;
 
        status = MFI_READ4(sc, MFI_OSTS);
-       if (sc->mfi_flags & MFI_FLAGS_1078) {
-               if (!(status & MFI_1078_RM)) {
-                       return 1;
-               }
-       } else if (sc->mfi_flags & MFI_FLAGS_GEN2) {
-               if (!(status & MFI_GEN2_RM)) {
-                       return 1;
-               }
-       }
+       if (((sc->mfi_flags & MFI_FLAGS_1078) && !(status & MFI_1078_RM)) ||
+           ((sc->mfi_flags & MFI_FLAGS_GEN2) && !(status & MFI_GEN2_RM)) ||
+           ((sc->mfi_flags & MFI_FLAGS_SKINNY) && !(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;
 }
 
 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);
+       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 );
+       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 +276,13 @@ 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;
+       bus_space_handle_t idb;
 
-       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;
+       idb = sc->mfi_flags & MFI_FLAGS_SKINNY ? MFI_SKINNY_IDB : MFI_IDB;
        while (fw_state != MFI_FWSTATE_READY) {
                if (bootverbose)
                        device_printf(sc->mfi_dev, "Waiting for firmware to "
@@ -245,11 +293,11 @@ 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);
+                       MFI_WRITE4(sc, idb, MFI_FWINIT_CLEAR_HANDSHAKE);
                        max_wait = 2;
                        break;
                case MFI_FWSTATE_OPERATIONAL:
-                       MFI_WRITE4(sc, MFI_IDB, MFI_FWINIT_READY);
+                       MFI_WRITE4(sc, idb, MFI_FWINIT_READY);
                        max_wait = 10;
                        break;
                case MFI_FWSTATE_UNDEFINED:
@@ -257,12 +305,15 @@ 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);
+                       MFI_WRITE4(sc, idb, MFI_FWINIT_HOTPLUG);
                        max_wait = 10;
                        break;
                default:
@@ -271,12 +322,18 @@ 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 +343,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 +361,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 +370,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 +462,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 +486,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 +510,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 +541,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 +719,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 +727,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 +751,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 +773,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 +1030,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 +1105,75 @@ 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 syspd 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 list\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);
+}
 
 static void
 mfi_ldprobe(struct mfi_softc *sc)
@@ -1216,6 +1386,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 +1404,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 +1499,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 +1545,193 @@ 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 mfi_command *cm = NULL;
+       struct mfi_disk *mfid;
+
+       /* 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)
+               return (NULL);
+       mfid = bio->bio_driver_info;
+       if (mfid->ld_flags & MFI_DISK_FLAGS_SYSPD)
+               cm = mfi_build_syspdio(sc, bio);
+       else
+               cm = mfi_build_ldio(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_disk *disk;
-       int flags, blkcount;
+       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);
 
-       if ((bio = mfi_dequeue_bio(sc)) == NULL) {
-               mfi_release_command(cm);
-               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:
+               pass->cdb[0] = READ_10;
+               flags = MFI_CMD_DATAIN;
+               break;
+       case BUF_CMD_WRITE:
+               pass->cdb[0] = WRITE_10;
+               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 +1753,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 +1867,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 +1882,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,12 +1937,10 @@ 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);
-
-       return;
 }
 
 static int
@@ -1647,6 +2027,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 +2035,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 +2073,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 +2115,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] = WRITE_10;
+       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 +2240,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 +2271,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 +2298,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 +2338,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 +2433,54 @@ out:
 #endif
 
 static int
+mfi_check_for_sscd(struct mfi_softc *sc, struct mfi_command *cm)
+{
+       struct mfi_config_data *conf_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 +2497,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 +2581,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 +2648,25 @@ 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 +2676,8 @@ 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 +2865,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 +2910,15 @@ 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);
index abf7e9e..4d3933a 100644 (file)
  * 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) {
index d0ff04e..57732ea 100644 (file)
  * 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,9 +206,9 @@ 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)) {
+            sc->ld_controller->mfi_detaching)) {
                lockmgr(&sc->ld_controller->mfi_io_lock, LK_RELEASE);
                return (EBUSY);
        }
@@ -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;
index 1a095bc..cb3163d 100644 (file)
  * 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,13 @@ mfi_pci_detach(device_t dev)
                        return (error);
                }
        }
+       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 (file)
index 0000000..0a3fca2
--- /dev/null
@@ -0,0 +1,323 @@
+/*-
+ * 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 = MFI_DISK_FLAGS_SYSPD;
+
+       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;
+       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);
+}
index 92b6f19..f2396d4 100644 (file)
  * 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 $
  */
 #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
 
 #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 {
index 99eca53..4ec8907 100644 (file)
  * 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;
@@ -108,6 +146,12 @@ struct mfi_command {
        int                     cm_error;
 };
 
+/*
+ * XXX swildner
+ *
+ * At the moment we rely on mfi_disk and mfi_system_pd having the same size.
+ * A future cleanup should merge them.
+ */
 struct mfi_disk {
        TAILQ_ENTRY(mfi_disk)   ld_link;
        device_t        ld_dev;
@@ -120,6 +164,19 @@ struct mfi_disk {
        int             ld_flags;
 #define MFI_DISK_FLAGS_OPEN    0x01
 #define        MFI_DISK_FLAGS_DISABLED 0x02
+#define        MFI_DISK_FLAGS_SYSPD    0x04
+};
+
+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 {
@@ -137,6 +194,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 +222,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 +276,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 +304,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 +449,7 @@ MALLOC_DECLARE(M_MFIBUF);
 
 #define MFI_CMD_TIMEOUT 30
 #define MFI_MAXPHYS (128 * 1024)
+#define SKINNY_MEMORY 0x02000000
 
 #ifdef MFI_DEBUG
 extern void mfi_print_cmd(struct mfi_command *cm);