mps(4): Sync with FreeBSD.
authorSascha Wildner <saw@online.de>
Tue, 7 Feb 2012 08:42:32 +0000 (09:42 +0100)
committerSascha Wildner <saw@online.de>
Tue, 7 Feb 2012 08:43:27 +0000 (09:43 +0100)
This a still in progress port of the new, LSI-supported version of the
mps(4) driver from FreeBSD.

Some of the changes are (from FreeBSD's commit msg):

- Integrated RAID (IR) support.
- Support for WarpDrive controllers.
- Support for SCSI protection information (EEDP).
- Support for TLR (Transport Level Retries), needed for tape drives.
- Improved error recovery code.
- ioctl interface compatible with LSI utilities.

This commit also moves the driver from sys/dev/disk to sys/dev/raid.

It still fails attaching at this stage. Work on it will continue in
master.

35 files changed:
share/man/man4/mps.4
sys/conf/files
sys/dev/disk/Makefile
sys/dev/disk/mps/Makefile [deleted file]
sys/dev/disk/mps/mps_ioctl.h [deleted file]
sys/dev/disk/mps/mps_sas.c [deleted file]
sys/dev/disk/mps/mps_user.c [deleted file]
sys/dev/disk/mps/mpsvar.h [deleted file]
sys/dev/raid/Makefile
sys/dev/raid/mps/Makefile [new file with mode: 0644]
sys/dev/raid/mps/mpi/mpi2.h [moved from sys/dev/disk/mps/mpi/mpi2.h with 94% similarity]
sys/dev/raid/mps/mpi/mpi2_cnfg.h [moved from sys/dev/disk/mps/mpi/mpi2_cnfg.h with 90% similarity]
sys/dev/raid/mps/mpi/mpi2_hbd.h [moved from sys/dev/disk/mps/mpi/mpi2_hbd.h with 72% similarity]
sys/dev/raid/mps/mpi/mpi2_history.txt [moved from sys/dev/disk/mps/mpi/mpi2_history.txt with 75% similarity]
sys/dev/raid/mps/mpi/mpi2_init.h [moved from sys/dev/disk/mps/mpi/mpi2_init.h with 91% similarity]
sys/dev/raid/mps/mpi/mpi2_ioc.h [moved from sys/dev/disk/mps/mpi/mpi2_ioc.h with 89% similarity]
sys/dev/raid/mps/mpi/mpi2_ra.h [moved from sys/dev/disk/mps/mpi/mpi2_ra.h with 71% similarity]
sys/dev/raid/mps/mpi/mpi2_raid.h [moved from sys/dev/disk/mps/mpi/mpi2_raid.h with 89% similarity]
sys/dev/raid/mps/mpi/mpi2_sas.h [moved from sys/dev/disk/mps/mpi/mpi2_sas.h with 86% similarity]
sys/dev/raid/mps/mpi/mpi2_targ.h [moved from sys/dev/disk/mps/mpi/mpi2_targ.h with 92% similarity]
sys/dev/raid/mps/mpi/mpi2_tool.h [moved from sys/dev/disk/mps/mpi/mpi2_tool.h with 82% similarity]
sys/dev/raid/mps/mpi/mpi2_type.h [moved from sys/dev/disk/mps/mpi/mpi2_type.h with 58% similarity]
sys/dev/raid/mps/mps.c [moved from sys/dev/disk/mps/mps.c with 70% similarity]
sys/dev/raid/mps/mps_config.c [new file with mode: 0644]
sys/dev/raid/mps/mps_ioctl.h [new file with mode: 0644]
sys/dev/raid/mps/mps_mapping.c [new file with mode: 0644]
sys/dev/raid/mps/mps_mapping.h [copied from sys/dev/disk/mps/mps_table.h with 51% similarity]
sys/dev/raid/mps/mps_pci.c [moved from sys/dev/disk/mps/mps_pci.c with 69% similarity]
sys/dev/raid/mps/mps_sas.c [new file with mode: 0644]
sys/dev/raid/mps/mps_sas.h [new file with mode: 0644]
sys/dev/raid/mps/mps_sas_lsi.c [new file with mode: 0644]
sys/dev/raid/mps/mps_table.c [moved from sys/dev/disk/mps/mps_table.c with 94% similarity]
sys/dev/raid/mps/mps_table.h [moved from sys/dev/disk/mps/mps_table.h with 100% similarity]
sys/dev/raid/mps/mps_user.c [new file with mode: 0644]
sys/dev/raid/mps/mpsvar.h [new file with mode: 0644]

index 8516e19..bcdfa7e 100644 (file)
@@ -32,7 +32,7 @@
 .\" Author: Ken Merry <ken@FreeBSD.org>
 .\"
 .\" $Id: //depot/SpectraBSD/head/share/man/man4/mps.4#4 $
-.\" $FreeBSD: src/share/man/man4/mps.4,v 1.3 2010/10/07 21:56:10 ken Exp $
+.\" $FreeBSD: src/share/man/man4/mps.4,v 1.5 2011/11/11 12:06:09 brueffer Exp $
 .\"
 .Dd September 13, 2010
 .Dt MPS 4
@@ -60,9 +60,9 @@ driver provides support for LSI Logic Fusion-MPT 2
 .Tn SAS
 controllers.
 .Sh HARDWARE
-The following controllers are supported by the
+The
 .Nm
-driver
+driver supports the following controllers:
 .Pp
 .Bl -bullet -compact
 .It
@@ -143,6 +143,19 @@ Enable prints for controller events.
 .Xr sa 4 ,
 .Xr scsi 4 ,
 .Xr targ 4
+.Sh HISTORY
+The
+.Nm
+driver first appeared in
+.Fx 9.0 .
+.Sh AUTHORS
+.An -nosplit
+The
+.Nm
+driver was originally written by
+.An Scott Long Aq scottl@FreeBSD.org .
+This man page was written by
+.An Ken Merry Aq ken@FreeBSD.org .
 .Sh BUGS
 This driver is still in development, it has only been tested on the amd64
 architecture and has some known shortcomings:
@@ -158,16 +171,3 @@ times, without user intervention.
 .It
 The error recovery code isn't complete.
 .El
-.Sh HISTORY
-The
-.Nm
-driver first appeared in
-.Fx 9.0 .
-.Sh AUTHORS
-.An -nosplit
-The
-.Nm
-driver was originally written by
-.An Scott Long Aq scottl@FreeBSD.org .
-This man page was written by
-.An Ken Merry Aq ken@FreeBSD.org .
index 47314f3..cf01bf8 100644 (file)
@@ -617,11 +617,14 @@ bus/mmc/mmc.c                     optional mmc
 bus/mmc/mmcbr_if.m             standard
 bus/mmc/mmcbus_if.m            standard
 dev/disk/mmcsd/mmcsd.c         optional mmcsd
-dev/disk/mps/mps.c             optional mps
-dev/disk/mps/mps_pci.c         optional mps pci
-dev/disk/mps/mps_sas.c         optional mps
-dev/disk/mps/mps_table.c       optional mps
-dev/disk/mps/mps_user.c                optional mps
+dev/raid/mps/mps.c             optional mps
+dev/raid/mps/mps_config.c      optional mps
+dev/raid/mps/mps_mapping.c     optional mps
+dev/raid/mps/mps_pci.c         optional mps pci
+dev/raid/mps/mps_sas.c         optional mps
+dev/raid/mps/mps_sas_lsi.c     optional mps
+dev/raid/mps/mps_table.c       optional mps
+dev/raid/mps/mps_user.c                optional mps
 dev/disk/mpt/mpt.c             optional mpt
 dev/disk/mpt/mpt_cam.c         optional mpt
 dev/disk/mpt/mpt_debug.c       optional mpt
index 66ef8ea..ca649a2 100644 (file)
@@ -1,6 +1,6 @@
 .include "${.CURDIR}/../../platform/${MACHINE_PLATFORM}/Makefile.inc"
 
-SUBDIR= ahci aic aic7xxx ccd dm iscsi isp ispfw md mmcsd mps mpt ncv nsp
+SUBDIR= ahci aic aic7xxx ccd dm iscsi isp ispfw md mmcsd mpt ncv nsp
 SUBDIR+= sbp sdhci sili stg sym trm vn vpo
 
 .for dir in ${SUBDIR}
diff --git a/sys/dev/disk/mps/Makefile b/sys/dev/disk/mps/Makefile
deleted file mode 100644 (file)
index 77b1a1e..0000000
+++ /dev/null
@@ -1,10 +0,0 @@
-# $FreeBSD: src/sys/modules/mps/Makefile,v 1.3 2010/10/17 20:01:56 scottl Exp $
-
-KMOD=  mps
-SRCS=  mps_pci.c mps.c mps_sas.c mps_table.c mps_user.c
-SRCS+= opt_mps.h opt_cam.h opt_compat.h
-SRCS+= device_if.h bus_if.h pci_if.h
-
-#CFLAGS += -DMPS_DEBUG
-
-.include <bsd.kmod.mk>
diff --git a/sys/dev/disk/mps/mps_ioctl.h b/sys/dev/disk/mps/mps_ioctl.h
deleted file mode 100644 (file)
index d804d05..0000000
+++ /dev/null
@@ -1,106 +0,0 @@
-/*-
- * Copyright (c) 2008 Yahoo!, Inc.
- * All rights reserved.
- * Written by: John Baldwin <jhb@FreeBSD.org>
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- *    notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- *    notice, this list of conditions and the following disclaimer in the
- *    documentation and/or other materials provided with the distribution.
- * 3. Neither the name of the author nor the names of any co-contributors
- *    may be used to endorse or promote products derived from this software
- *    without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
- * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
- * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- *
- * LSI MPT-Fusion Host Adapter FreeBSD userland interface
- *
- * $FreeBSD: src/sys/dev/mps/mps_ioctl.h,v 1.2 2010/10/11 21:26:24 mdf Exp $
- */
-
-#ifndef _MPS_IOCTL_H_
-#define        _MPS_IOCTL_H_
-
-#include <dev/disk/mps/mpi/mpi2_type.h>
-#include <dev/disk/mps/mpi/mpi2.h>
-#include <dev/disk/mps/mpi/mpi2_cnfg.h>
-#include <dev/disk/mps/mpi/mpi2_sas.h>
-
-/*
- * For the read header requests, the header should include the page
- * type or extended page type, page number, and page version.  The
- * buffer and length are unused.  The completed header is returned in
- * the 'header' member.
- *
- * For the read page and write page requests, 'buf' should point to a
- * buffer of 'len' bytes which holds the entire page (including the
- * header).
- *
- * All requests specify the page address in 'page_address'.
- */
-struct mps_cfg_page_req {
-       MPI2_CONFIG_PAGE_HEADER header;
-       uint32_t page_address;
-       void    *buf;
-       int     len;
-       uint16_t ioc_status;
-};
-
-struct mps_ext_cfg_page_req {
-       MPI2_CONFIG_EXTENDED_PAGE_HEADER header;
-       uint32_t page_address;
-       void    *buf;
-       int     len;
-       uint16_t ioc_status;
-};
-
-struct mps_raid_action {
-       uint8_t action;
-       uint8_t volume_bus;
-       uint8_t volume_id;
-       uint8_t phys_disk_num;
-       uint32_t action_data_word;
-       void *buf;
-       int len;
-       uint32_t volume_status;
-       uint32_t action_data[4];
-       uint16_t action_status;
-       uint16_t ioc_status;
-       uint8_t write;
-};
-
-struct mps_usr_command {
-       void *req;
-       uint32_t req_len;
-       void *rpl;
-       uint32_t rpl_len;
-       void *buf;
-       int len;
-       uint32_t flags;
-};
-
-#define MPSIO_MPS_COMMAND_FLAG_VERBOSE 0x01
-#define MPSIO_MPS_COMMAND_FLAG_DEBUG 0x02
-#define        MPSIO_READ_CFG_HEADER   _IOWR('M', 200, struct mps_cfg_page_req)
-#define        MPSIO_READ_CFG_PAGE     _IOWR('M', 201, struct mps_cfg_page_req)
-#define        MPSIO_READ_EXT_CFG_HEADER _IOWR('M', 202, struct mps_ext_cfg_page_req)
-#define        MPSIO_READ_EXT_CFG_PAGE _IOWR('M', 203, struct mps_ext_cfg_page_req)
-#define        MPSIO_WRITE_CFG_PAGE    _IOWR('M', 204, struct mps_cfg_page_req)
-#define        MPSIO_RAID_ACTION       _IOWR('M', 205, struct mps_raid_action)
-#define        MPSIO_MPS_COMMAND       _IOWR('M', 210, struct mps_usr_command)
-
-#endif /* !_MPS_IOCTL_H_ */
diff --git a/sys/dev/disk/mps/mps_sas.c b/sys/dev/disk/mps/mps_sas.c
deleted file mode 100644 (file)
index bc34cec..0000000
+++ /dev/null
@@ -1,2016 +0,0 @@
-/*-
- * Copyright (c) 2009 Yahoo! Inc.
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- *    notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- *    notice, this list of conditions and the following disclaimer in the
- *    documentation and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
- * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
- * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- *
- * $FreeBSD: src/sys/dev/mps/mps_sas.c,v 1.7 2010/12/11 00:36:35 ken Exp $
- */
-
-/* Communications core for LSI MPT2 */
-
-#include <sys/types.h>
-#include <sys/param.h>
-#include <sys/systm.h>
-#include <sys/kernel.h>
-#include <sys/module.h>
-#include <sys/bus.h>
-#include <sys/conf.h>
-#include <sys/bio.h>
-#include <sys/malloc.h>
-#include <sys/uio.h>
-#include <sys/sysctl.h>
-#include <sys/endian.h>
-
-#include <sys/rman.h>
-#include <sys/lock.h>
-#include <sys/globaldata.h>
-
-#include <bus/cam/cam.h>
-#include <bus/cam/cam_ccb.h>
-#include <bus/cam/cam_debug.h>
-#include <bus/cam/cam_sim.h>
-#include <bus/cam/cam_xpt_sim.h>
-#include <bus/cam/cam_xpt_periph.h>
-#include <bus/cam/cam_periph.h>
-#include <bus/cam/scsi/scsi_all.h>
-#include <bus/cam/scsi/scsi_message.h>
-#if __FreeBSD_version >= 900026
-#include <bus/cam/scsi/smp_all.h>
-#endif
-
-#include <dev/disk/mps/mpi/mpi2_type.h>
-#include <dev/disk/mps/mpi/mpi2.h>
-#include <dev/disk/mps/mpi/mpi2_ioc.h>
-#include <dev/disk/mps/mpi/mpi2_sas.h>
-#include <dev/disk/mps/mpi/mpi2_cnfg.h>
-#include <dev/disk/mps/mpi/mpi2_init.h>
-#include <dev/disk/mps/mpsvar.h>
-#include <dev/disk/mps/mps_table.h>
-
-struct mpssas_target {
-       uint16_t        handle;
-       uint8_t         linkrate;
-       uint64_t        devname;
-       uint64_t        sasaddr;
-       uint32_t        devinfo;
-       uint16_t        encl_handle;
-       uint16_t        encl_slot;
-       uint16_t        parent_handle;
-       int             flags;
-#define MPSSAS_TARGET_INABORT  (1 << 0)
-#define MPSSAS_TARGET_INRESET  (1 << 1)
-#define MPSSAS_TARGET_INCHIPRESET (1 << 2)
-#define MPSSAS_TARGET_INRECOVERY 0x7
-       uint16_t        tid;
-};
-
-struct mpssas_softc {
-       struct mps_softc        *sc;
-       u_int                   flags;
-#define MPSSAS_IN_DISCOVERY    (1 << 0)
-#define MPSSAS_IN_STARTUP      (1 << 1)
-#define MPSSAS_DISCOVERY_TIMEOUT_PENDING       (1 << 2)
-#define MPSSAS_QUEUE_FROZEN    (1 << 3)
-       struct mpssas_target    *targets;
-       struct cam_devq         *devq;
-       struct cam_sim          *sim;
-       struct cam_path         *path;
-       struct intr_config_hook sas_ich;
-       struct callout          discovery_callout;
-       u_int                   discovery_timeouts;
-       struct mps_event_handle *mpssas_eh;
-};
-
-struct mpssas_devprobe {
-       struct mps_config_params        params;
-       u_int                   state;
-#define MPSSAS_PROBE_DEV1      0x01
-#define MPSSAS_PROBE_DEV2      0x02
-#define MPSSAS_PROBE_PHY       0x03
-#define MPSSAS_PROBE_EXP       0x04
-#define MPSSAS_PROBE_PHY2      0x05
-#define MPSSAS_PROBE_EXP2      0x06
-       struct mpssas_target    target;
-};
-
-#define MPSSAS_DISCOVERY_TIMEOUT       20
-#define MPSSAS_MAX_DISCOVERY_TIMEOUTS  10 /* 200 seconds */
-
-MALLOC_DEFINE(M_MPSSAS, "MPSSAS", "MPS SAS memory");
-
-static __inline int mpssas_set_lun(uint8_t *lun, u_int ccblun);
-static struct mpssas_target * mpssas_alloc_target(struct mpssas_softc *,
-    struct mpssas_target *);
-static struct mpssas_target * mpssas_find_target(struct mpssas_softc *, int,
-     uint16_t);
-static void mpssas_announce_device(struct mpssas_softc *,
-     struct mpssas_target *);
-static void mpssas_bus_scan_cb(struct cam_periph *periph, union ccb *ccb);
-static void mpssas_startup(void *data);
-static void mpssas_discovery_end(struct mpssas_softc *sassc);
-static void mpssas_discovery_timeout(void *data);
-static void mpssas_prepare_remove(struct mpssas_softc *,
-    MPI2_EVENT_SAS_TOPO_PHY_ENTRY *);
-static void mpssas_remove_device(struct mps_softc *, struct mps_command *);
-static void mpssas_remove_complete(struct mps_softc *, struct mps_command *);
-static void mpssas_action(struct cam_sim *sim, union ccb *ccb);
-static void mpssas_poll(struct cam_sim *sim);
-static void mpssas_probe_device(struct mps_softc *sc, uint16_t handle);
-static void mpssas_probe_device_complete(struct mps_softc *sc,
-     struct mps_config_params *params);
-static void mpssas_scsiio_timeout(void *data);
-static void mpssas_abort_complete(struct mps_softc *sc, struct mps_command *cm);
-static void mpssas_recovery(struct mps_softc *, struct mps_command *);
-static int mpssas_map_tm_request(struct mps_softc *sc, struct mps_command *cm);
-static void mpssas_issue_tm_request(struct mps_softc *sc,
-                                   struct mps_command *cm);
-static void mpssas_tm_complete(struct mps_softc *sc, struct mps_command *cm,
-                              int error);
-static int mpssas_complete_tm_request(struct mps_softc *sc,
-                                     struct mps_command *cm, int free_cm);
-static void mpssas_action_scsiio(struct mpssas_softc *, union ccb *);
-static void mpssas_scsiio_complete(struct mps_softc *, struct mps_command *);
-#if __FreeBSD_version >= 900026
-static void mpssas_smpio_complete(struct mps_softc *sc, struct mps_command *cm);
-static void mpssas_send_smpcmd(struct mpssas_softc *sassc, union ccb *ccb,
-                              uint64_t sasaddr);
-static void mpssas_action_smpio(struct mpssas_softc *sassc, union ccb *ccb);
-#endif /* __FreeBSD_version >= 900026 */
-static void mpssas_resetdev(struct mpssas_softc *, struct mps_command *);
-static void mpssas_action_resetdev(struct mpssas_softc *, union ccb *);
-static void mpssas_resetdev_complete(struct mps_softc *, struct mps_command *);
-static void mpssas_freeze_device(struct mpssas_softc *, struct mpssas_target *);
-static void mpssas_unfreeze_device(struct mpssas_softc *, struct mpssas_target *) __unused;
-
-/*
- * Abstracted so that the driver can be backwards and forwards compatible
- * with future versions of CAM that will provide this functionality.
- */
-#define MPS_SET_LUN(lun, ccblun)       \
-       mpssas_set_lun(lun, ccblun)
-
-static __inline int
-mpssas_set_lun(uint8_t *lun, u_int ccblun)
-{
-       uint64_t *newlun;
-
-       newlun = (uint64_t *)lun;
-       *newlun = 0;
-       if (ccblun <= 0xff) {
-               /* Peripheral device address method, LUN is 0 to 255 */
-               lun[1] = ccblun;
-       } else if (ccblun <= 0x3fff) {
-               /* Flat space address method, LUN is <= 16383 */
-               scsi_ulto2b(ccblun, lun);
-               lun[0] |= 0x40;
-       } else if (ccblun <= 0xffffff) {
-               /* Extended flat space address method, LUN is <= 16777215 */
-               scsi_ulto3b(ccblun, &lun[1]);
-               /* Extended Flat space address method */
-               lun[0] = 0xc0;
-               /* Length = 1, i.e. LUN is 3 bytes long */
-               lun[0] |= 0x10;
-               /* Extended Address Method */
-               lun[0] |= 0x02;
-       } else {
-               return (EINVAL);
-       }
-
-       return (0);
-}
-
-static struct mpssas_target *
-mpssas_alloc_target(struct mpssas_softc *sassc, struct mpssas_target *probe)
-{
-       struct mpssas_target *target;
-       int start;
-
-       mps_dprint(sassc->sc, MPS_TRACE, "%s\n", __func__);
-
-       /*
-        * If it's not a sata or sas target, CAM won't be able to see it.  Put
-        * it into a high-numbered slot so that it's accessible but not
-        * interrupting the target numbering sequence of real drives.
-        */
-       if ((probe->devinfo & (MPI2_SAS_DEVICE_INFO_SSP_TARGET |
-           MPI2_SAS_DEVICE_INFO_STP_TARGET | MPI2_SAS_DEVICE_INFO_SATA_DEVICE))
-           == 0) {
-               start = 200;
-       } else {
-               /*
-                * Use the enclosure number and slot number as a hint for target
-                * numbering.  If that doesn't produce a sane result, search the
-                * entire space.
-                */
-#if 0
-               start = probe->encl_handle * 16 + probe->encl_slot;
-#else
-               start = probe->encl_slot;
-#endif
-               if (start >= sassc->sc->facts->MaxTargets)
-                       start = 0;
-       }
-
-       target = mpssas_find_target(sassc, start, 0);
-
-       /*
-        * Nothing found on the first pass, try a second pass that searches the
-        * entire space.
-        */
-       if (target == NULL)
-               target = mpssas_find_target(sassc, 0, 0);
-
-       return (target);
-}
-
-static struct mpssas_target *
-mpssas_find_target(struct mpssas_softc *sassc, int start, uint16_t handle)
-{
-       struct mpssas_target *target;
-       int i;
-
-       for (i = start; i < sassc->sc->facts->MaxTargets; i++) {
-               target = &sassc->targets[i];
-               if (target->handle == handle)
-                       return (target);
-       }
-
-       return (NULL);
-}
-
-/*
- * Start the probe sequence for a given device handle.  This will not
- * block.
- */
-static void
-mpssas_probe_device(struct mps_softc *sc, uint16_t handle)
-{
-       struct mpssas_devprobe *probe;
-       struct mps_config_params *params;
-       MPI2_CONFIG_EXTENDED_PAGE_HEADER *hdr;
-       int error;
-
-       mps_dprint(sc, MPS_TRACE, "%s\n", __func__);
-
-       probe = kmalloc(sizeof(*probe), M_MPSSAS, M_NOWAIT | M_ZERO);
-       if (probe == NULL) {
-               mps_dprint(sc, MPS_FAULT, "Out of memory starting probe\n");
-               return;
-       }
-       params = &probe->params;
-       hdr = &params->hdr.Ext;
-
-       params->action = MPI2_CONFIG_ACTION_PAGE_HEADER;
-       params->page_address = MPI2_SAS_DEVICE_PGAD_FORM_HANDLE | handle;
-       hdr->ExtPageType = MPI2_CONFIG_EXTPAGETYPE_SAS_DEVICE;
-       hdr->ExtPageLength = 0;
-       hdr->PageNumber = 0;
-       hdr->PageVersion = 0;
-       params->buffer = NULL;
-       params->length = 0;
-       params->callback = mpssas_probe_device_complete;
-       params->cbdata = probe;
-       probe->target.handle = handle;
-       probe->state = MPSSAS_PROBE_DEV1;
-
-       if ((error = mps_read_config_page(sc, params)) != 0) {
-               kfree(probe, M_MPSSAS);
-               mps_dprint(sc, MPS_FAULT, "Failure starting device probe\n");
-               return;
-       }
-}
-
-static void
-mpssas_probe_device_complete(struct mps_softc *sc,
-    struct mps_config_params *params)
-{
-       MPI2_CONFIG_EXTENDED_PAGE_HEADER *hdr;
-       struct mpssas_devprobe *probe;
-       int error;
-
-       mps_dprint(sc, MPS_TRACE, "%s\n", __func__);
-
-       hdr = &params->hdr.Ext;
-       probe = params->cbdata;
-
-       switch (probe->state) {
-       case MPSSAS_PROBE_DEV1:
-       case MPSSAS_PROBE_PHY:
-       case MPSSAS_PROBE_EXP:
-               if (params->status != MPI2_IOCSTATUS_SUCCESS) {
-                       mps_dprint(sc, MPS_FAULT,
-                           "Probe Failure 0x%x state %d\n", params->status,
-                           probe->state);
-                       kfree(probe, M_MPSSAS);
-                       return;
-               }
-               params->action = MPI2_CONFIG_ACTION_PAGE_READ_CURRENT;
-               params->length = hdr->ExtPageLength * 4;
-               params->buffer = kmalloc(params->length, M_MPSSAS,
-                   M_ZERO|M_NOWAIT);
-               if (params->buffer == NULL) {
-                       mps_dprint(sc, MPS_FAULT, "Out of memory at state "
-                          "0x%x, size 0x%x\n", probe->state, params->length);
-                       kfree(probe, M_MPSSAS);
-                       return;
-               }
-               if (probe->state == MPSSAS_PROBE_DEV1)
-                       probe->state = MPSSAS_PROBE_DEV2;
-               else if (probe->state == MPSSAS_PROBE_PHY)
-                       probe->state = MPSSAS_PROBE_PHY2;
-               else if (probe->state == MPSSAS_PROBE_EXP)
-                       probe->state = MPSSAS_PROBE_EXP2;
-               error = mps_read_config_page(sc, params);
-               break;
-       case MPSSAS_PROBE_DEV2:
-       {
-               MPI2_CONFIG_PAGE_SAS_DEV_0 *buf;
-
-               if (params->status != MPI2_IOCSTATUS_SUCCESS) {
-                       mps_dprint(sc, MPS_FAULT,
-                           "Probe Failure 0x%x state %d\n", params->status,
-                           probe->state);
-                       kfree(params->buffer, M_MPSSAS);
-                       kfree(probe, M_MPSSAS);
-                       return;
-               }
-               buf = params->buffer;
-               mps_print_sasdev0(sc, buf);
-
-               probe->target.devname = mps_to_u64(&buf->DeviceName);
-               probe->target.devinfo = buf->DeviceInfo;
-               probe->target.encl_handle = buf->EnclosureHandle;
-               probe->target.encl_slot = buf->Slot;
-               probe->target.sasaddr = mps_to_u64(&buf->SASAddress);
-               probe->target.parent_handle = buf->ParentDevHandle;
-
-               if (buf->DeviceInfo & MPI2_SAS_DEVICE_INFO_DIRECT_ATTACH) {
-                       params->page_address =
-                           MPI2_SAS_PHY_PGAD_FORM_PHY_NUMBER | buf->PhyNum;
-                       hdr->ExtPageType = MPI2_CONFIG_EXTPAGETYPE_SAS_PHY;
-                       hdr->PageNumber = 0;
-                       probe->state = MPSSAS_PROBE_PHY;
-               } else {
-                       params->page_address =
-                           MPI2_SAS_EXPAND_PGAD_FORM_HNDL_PHY_NUM |
-                           buf->ParentDevHandle | (buf->PhyNum << 16);
-                       hdr->ExtPageType = MPI2_CONFIG_EXTPAGETYPE_SAS_EXPANDER;
-                       hdr->PageNumber = 1;
-                       probe->state = MPSSAS_PROBE_EXP;
-               }
-               params->action = MPI2_CONFIG_ACTION_PAGE_HEADER;
-               hdr->ExtPageLength = 0;
-               hdr->PageVersion = 0;
-               params->buffer = NULL;
-               params->length = 0;
-               kfree(buf, M_MPSSAS);
-               error = mps_read_config_page(sc, params);
-               break;
-       }
-       case MPSSAS_PROBE_PHY2:
-       case MPSSAS_PROBE_EXP2:
-       {
-               MPI2_CONFIG_PAGE_SAS_PHY_0 *phy;
-               MPI2_CONFIG_PAGE_EXPANDER_1 *exp;
-               struct mpssas_softc *sassc;
-               struct mpssas_target *targ;
-               char devstring[80];
-               uint16_t handle;
-
-               if (params->status != MPI2_IOCSTATUS_SUCCESS) {
-                       mps_dprint(sc, MPS_FAULT,
-                           "Probe Failure 0x%x state %d\n", params->status,
-                           probe->state);
-                       kfree(params->buffer, M_MPSSAS);
-                       kfree(probe, M_MPSSAS);
-                       return;
-               }
-
-               if (probe->state == MPSSAS_PROBE_PHY2) {
-                       phy = params->buffer;
-                       mps_print_sasphy0(sc, phy);
-                       probe->target.linkrate = phy->NegotiatedLinkRate & 0xf;
-               } else {
-                       exp = params->buffer;
-                       mps_print_expander1(sc, exp);
-                       probe->target.linkrate = exp->NegotiatedLinkRate & 0xf;
-               }
-               kfree(params->buffer, M_MPSSAS);
-
-               sassc = sc->sassc;
-               handle = probe->target.handle;
-               if ((targ = mpssas_find_target(sassc, 0, handle)) != NULL) {
-                       mps_printf(sc, "Ignoring dup device handle 0x%04x\n",
-                           handle);
-                       kfree(probe, M_MPSSAS);
-                       return;
-               }
-               if ((targ = mpssas_alloc_target(sassc, &probe->target)) == NULL) {
-                       mps_printf(sc, "Target table overflow, handle 0x%04x\n",
-                           handle);
-                       kfree(probe, M_MPSSAS);
-                       return;
-               }
-
-               *targ = probe->target;  /* Copy the attributes */
-               targ->tid = targ - sassc->targets;
-               mps_describe_devinfo(targ->devinfo, devstring, 80);
-               if (bootverbose)
-                       mps_printf(sc, "Found device <%s> <%s> <0x%04x> "
-                           "<%d/%d>\n", devstring,
-                           mps_describe_table(mps_linkrate_names,
-                           targ->linkrate), targ->handle, targ->encl_handle,
-                           targ->encl_slot);
-
-               kfree(probe, M_MPSSAS);
-               mpssas_announce_device(sassc, targ);
-               break;
-       }
-       default:
-               kprintf("what?\n");
-       }
-}
-
-/*
- * The MPT2 firmware performs debounce on the link to avoid transient link errors
- * and false removals.  When it does decide that link has been lost and a device
- * need to go away, it expects that the host will perform a target reset and then
- * an op remove.  The reset has the side-effect of aborting any outstanding
- * requests for the device, which is required for the op-remove to succeed.  It's
- * not clear if the host should check for the device coming back alive after the
- * reset.
- */
-static void
-mpssas_prepare_remove(struct mpssas_softc *sassc, MPI2_EVENT_SAS_TOPO_PHY_ENTRY *phy)
-{
-       MPI2_SCSI_TASK_MANAGE_REQUEST *req;
-       struct mps_softc *sc;
-       struct mps_command *cm;
-       struct mpssas_target *targ = NULL;
-       uint16_t handle;
-
-       mps_dprint(sassc->sc, MPS_TRACE, "%s\n", __func__);
-
-       handle = phy->AttachedDevHandle;
-       targ = mpssas_find_target(sassc, 0, handle);
-       if (targ == NULL)
-               /* We don't know about this device? */
-               return;
-
-       sc = sassc->sc;
-       cm = mps_alloc_command(sc);
-       if (cm == NULL) {
-               mps_printf(sc, "command alloc failure in mpssas_prepare_remove\n");
-               return;
-       }
-
-       req = (MPI2_SCSI_TASK_MANAGE_REQUEST *)cm->cm_req;
-       req->DevHandle = targ->handle;
-       req->Function = MPI2_FUNCTION_SCSI_TASK_MGMT;
-       req->TaskType = MPI2_SCSITASKMGMT_TASKTYPE_TARGET_RESET;
-
-       /* SAS Hard Link Reset / SATA Link Reset */
-       req->MsgFlags = MPI2_SCSITASKMGMT_MSGFLAGS_LINK_RESET;
-
-       cm->cm_data = NULL;
-       cm->cm_desc.Default.RequestFlags = MPI2_REQ_DESCRIPT_FLAGS_DEFAULT_TYPE;
-       cm->cm_complete = mpssas_remove_device;
-       cm->cm_targ = targ;
-       mpssas_issue_tm_request(sc, cm);
-}
-
-static void
-mpssas_remove_device(struct mps_softc *sc, struct mps_command *cm)
-{
-       MPI2_SCSI_TASK_MANAGE_REPLY *reply;
-       MPI2_SAS_IOUNIT_CONTROL_REQUEST *req;
-       struct mpssas_target *targ;
-       uint16_t handle;
-
-       mps_dprint(sc, MPS_TRACE, "%s\n", __func__);
-
-       reply = (MPI2_SCSI_TASK_MANAGE_REPLY *)cm->cm_reply;
-       handle = cm->cm_targ->handle;
-
-       mpssas_complete_tm_request(sc, cm, /*free_cm*/ 0);
-
-       if (reply->IOCStatus != MPI2_IOCSTATUS_SUCCESS) {
-               mps_printf(sc, "Failure 0x%x reseting device 0x%04x\n",
-                  reply->IOCStatus, handle);
-               mps_free_command(sc, cm);
-               return;
-       }
-
-       mps_printf(sc, "Reset aborted %d commands\n",
-           (u_int)reply->TerminationCount);
-       mps_free_reply(sc, cm->cm_reply_data);
-
-       /* Reuse the existing command */
-       req = (MPI2_SAS_IOUNIT_CONTROL_REQUEST *)cm->cm_req;
-       req->Function = MPI2_FUNCTION_SAS_IO_UNIT_CONTROL;
-       req->Operation = MPI2_SAS_OP_REMOVE_DEVICE;
-       req->DevHandle = handle;
-       cm->cm_data = NULL;
-       cm->cm_desc.Default.RequestFlags = MPI2_REQ_DESCRIPT_FLAGS_DEFAULT_TYPE;
-       cm->cm_flags &= ~MPS_CM_FLAGS_COMPLETE;
-       cm->cm_complete = mpssas_remove_complete;
-
-       mps_map_command(sc, cm);
-
-       mps_dprint(sc, MPS_INFO, "clearing target handle 0x%04x\n", handle);
-       targ = mpssas_find_target(sc->sassc, 0, handle);
-       if (targ != NULL) {
-               targ->handle = 0x0;
-               mpssas_announce_device(sc->sassc, targ);
-       }
-}
-
-static void
-mpssas_remove_complete(struct mps_softc *sc, struct mps_command *cm)
-{
-       MPI2_SAS_IOUNIT_CONTROL_REPLY *reply;
-
-       mps_dprint(sc, MPS_TRACE, "%s\n", __func__);
-
-       reply = (MPI2_SAS_IOUNIT_CONTROL_REPLY *)cm->cm_reply;
-
-       mps_printf(sc, "mpssas_remove_complete on target 0x%04x,"
-          " IOCStatus= 0x%x\n", cm->cm_targ->tid, reply->IOCStatus);
-
-       mps_free_command(sc, cm);
-}
-
-static void
-mpssas_evt_handler(struct mps_softc *sc, uintptr_t data,
-    MPI2_EVENT_NOTIFICATION_REPLY *event)
-{
-       struct mpssas_softc *sassc;
-
-       mps_dprint(sc, MPS_TRACE, "%s\n", __func__);
-
-       sassc = sc->sassc;
-       mps_print_evt_sas(sc, event);
-
-       switch (event->Event) {
-       case MPI2_EVENT_SAS_DISCOVERY:
-       {
-               MPI2_EVENT_DATA_SAS_DISCOVERY *data;
-
-               data = (MPI2_EVENT_DATA_SAS_DISCOVERY *)&event->EventData;
-
-               if (data->ReasonCode & MPI2_EVENT_SAS_DISC_RC_STARTED)
-                       mps_dprint(sc, MPS_TRACE,"SAS discovery start event\n");
-               if (data->ReasonCode & MPI2_EVENT_SAS_DISC_RC_COMPLETED) {
-                       mps_dprint(sc, MPS_TRACE, "SAS discovery end event\n");
-                       sassc->flags &= ~MPSSAS_IN_DISCOVERY;
-                       mpssas_discovery_end(sassc);
-               }
-               break;
-       }
-       case MPI2_EVENT_SAS_TOPOLOGY_CHANGE_LIST:
-       {
-               MPI2_EVENT_DATA_SAS_TOPOLOGY_CHANGE_LIST *data;
-               MPI2_EVENT_SAS_TOPO_PHY_ENTRY *phy;
-               int i;
-
-               data = (MPI2_EVENT_DATA_SAS_TOPOLOGY_CHANGE_LIST *)
-                   &event->EventData;
-
-               if (data->ExpStatus == MPI2_EVENT_SAS_TOPO_ES_ADDED) {
-                       if (bootverbose)
-                               kprintf("Expander found at enclosure %d\n",
-                                   data->EnclosureHandle);
-                       mpssas_probe_device(sc, data->ExpanderDevHandle);
-               }
-
-               for (i = 0; i < data->NumEntries; i++) {
-                       phy = &data->PHY[i];
-                       switch (phy->PhyStatus & MPI2_EVENT_SAS_TOPO_RC_MASK) {
-                       case MPI2_EVENT_SAS_TOPO_RC_TARG_ADDED:
-                               mpssas_probe_device(sc, phy->AttachedDevHandle);
-                               break;
-                       case MPI2_EVENT_SAS_TOPO_RC_TARG_NOT_RESPONDING:
-                               mpssas_prepare_remove(sassc, phy);
-                               break;
-                       case MPI2_EVENT_SAS_TOPO_RC_PHY_CHANGED:
-                       case MPI2_EVENT_SAS_TOPO_RC_NO_CHANGE:
-                       case MPI2_EVENT_SAS_TOPO_RC_DELAY_NOT_RESPONDING:
-                       default:
-                               break;
-                       }
-               }
-
-               break;
-       }
-       case MPI2_EVENT_SAS_ENCL_DEVICE_STATUS_CHANGE:
-               break;
-       default:
-               break;
-       }
-
-       mps_free_reply(sc, data);
-}
-
-static int
-mpssas_register_events(struct mps_softc *sc)
-{
-       uint8_t events[16];
-
-       bzero(events, 16);
-       setbit(events, MPI2_EVENT_SAS_DEVICE_STATUS_CHANGE);
-       setbit(events, MPI2_EVENT_SAS_DISCOVERY);
-       setbit(events, MPI2_EVENT_SAS_BROADCAST_PRIMITIVE);
-       setbit(events, MPI2_EVENT_SAS_INIT_DEVICE_STATUS_CHANGE);
-       setbit(events, MPI2_EVENT_SAS_INIT_TABLE_OVERFLOW);
-       setbit(events, MPI2_EVENT_SAS_TOPOLOGY_CHANGE_LIST);
-       setbit(events, MPI2_EVENT_SAS_ENCL_DEVICE_STATUS_CHANGE);
-
-       mps_register_events(sc, events, mpssas_evt_handler, NULL,
-           &sc->sassc->mpssas_eh);
-
-       return (0);
-}
-
-int
-mps_attach_sas(struct mps_softc *sc)
-{
-       struct mpssas_softc *sassc;
-       int error = 0;
-       int num_sim_reqs;
-
-       mps_dprint(sc, MPS_TRACE, "%s\n", __func__);
-
-       sassc = kmalloc(sizeof(struct mpssas_softc), M_MPT2, M_WAITOK|M_ZERO);
-       sassc->targets = kmalloc(sizeof(struct mpssas_target) *
-           sc->facts->MaxTargets, M_MPT2, M_WAITOK|M_ZERO);
-       sc->sassc = sassc;
-       sassc->sc = sc;
-
-       /*
-        * Tell CAM that we can handle 5 fewer requests than we have
-        * allocated.  If we allow the full number of requests, all I/O
-        * will halt when we run out of resources.  Things work fine with
-        * just 1 less request slot given to CAM than we have allocated.
-        * We also need a couple of extra commands so that we can send down
-        * abort, reset, etc. requests when commands time out.  Otherwise
-        * we could wind up in a situation with sc->num_reqs requests down
-        * on the card and no way to send an abort.
-        *
-        * XXX KDM need to figure out why I/O locks up if all commands are
-        * used.
-        */
-       num_sim_reqs = sc->num_reqs - 5;
-
-       if ((sassc->devq = cam_simq_alloc(num_sim_reqs)) == NULL) {
-               mps_dprint(sc, MPS_FAULT, "Cannot allocate SIMQ\n");
-               error = ENOMEM;
-               goto out;
-       }
-
-       sassc->sim = cam_sim_alloc(mpssas_action, mpssas_poll, "mps", sassc,
-           device_get_unit(sc->mps_dev), &sc->mps_lock, num_sim_reqs,
-           num_sim_reqs, sassc->devq);
-       if (sassc->sim == NULL) {
-               mps_dprint(sc, MPS_FAULT, "Cannot allocate SIM\n");
-               error = EINVAL;
-               goto out;
-       }
-
-       /*
-        * XXX There should be a bus for every port on the adapter, but since
-        * we're just going to fake the topology for now, we'll pretend that
-        * everything is just a target on a single bus.
-        */
-       mps_lock(sc);
-       if ((error = xpt_bus_register(sassc->sim, 0)) != 0) {
-               mps_dprint(sc, MPS_FAULT, "Error %d registering SCSI bus\n",
-                   error);
-               mps_unlock(sc);
-               goto out;
-       }
-
-       /*
-        * Assume that discovery events will start right away.  Freezing
-        * the simq will prevent the CAM boottime scanner from running
-        * before discovery is complete.
-        */
-       sassc->flags = MPSSAS_IN_STARTUP | MPSSAS_IN_DISCOVERY;
-       xpt_freeze_simq(sassc->sim, 1);
-
-       mps_unlock(sc);
-
-       callout_init(&sassc->discovery_callout);
-       sassc->discovery_timeouts = 0;
-
-       mpssas_register_events(sc);
-out:
-       if (error)
-               mps_detach_sas(sc);
-       return (error);
-}
-
-int
-mps_detach_sas(struct mps_softc *sc)
-{
-       struct mpssas_softc *sassc;
-
-       mps_dprint(sc, MPS_TRACE, "%s\n", __func__);
-
-       if (sc->sassc == NULL)
-               return (0);
-
-       sassc = sc->sassc;
-
-       /* Make sure CAM doesn't wedge if we had to bail out early. */
-       mps_lock(sc);
-       if (sassc->flags & MPSSAS_IN_STARTUP)
-               xpt_release_simq(sassc->sim, 1);
-       mps_unlock(sc);
-
-       if (sassc->mpssas_eh != NULL)
-               mps_deregister_events(sc, sassc->mpssas_eh);
-
-       mps_lock(sc);
-
-       if (sassc->sim != NULL) {
-               xpt_bus_deregister(cam_sim_path(sassc->sim));
-               cam_sim_free(sassc->sim);
-       }
-       mps_unlock(sc);
-
-       if (sassc->devq != NULL)
-               cam_simq_release(sassc->devq);
-
-       kfree(sassc->targets, M_MPT2);
-       kfree(sassc, M_MPT2);
-       sc->sassc = NULL;
-
-       return (0);
-}
-
-static void
-mpssas_discovery_end(struct mpssas_softc *sassc)
-{
-       struct mps_softc *sc = sassc->sc;
-
-       mps_dprint(sc, MPS_TRACE, "%s\n", __func__);
-
-       if (sassc->flags & MPSSAS_DISCOVERY_TIMEOUT_PENDING)
-               callout_stop(&sassc->discovery_callout);
-
-       if ((sassc->flags & MPSSAS_IN_STARTUP) != 0) {
-               mps_dprint(sc, MPS_INFO,
-                   "mpssas_discovery_end: removing confighook\n");
-               sassc->flags &= ~MPSSAS_IN_STARTUP;
-               xpt_release_simq(sassc->sim, 1);
-       }
-#if 0
-       mpssas_announce_device(sassc, NULL);
-#endif
-
-}
-
-static void
-mpssas_announce_device(struct mpssas_softc *sassc, struct mpssas_target *targ)
-{
-       union ccb *ccb;
-       int bus, tid, lun;
-
-       /*
-        * Force a rescan, a hackish way to announce devices.
-        * XXX Doing a scan on an individual device is hackish in that it
-        *     won't scan the LUNs.
-        * XXX Does it matter if any of this fails?
-        */
-       bus = cam_sim_path(sassc->sim);
-       if (targ != NULL) {
-               tid = targ->tid;
-               lun = 0;
-       } else {
-               tid = CAM_TARGET_WILDCARD;
-               lun = CAM_LUN_WILDCARD;
-       }
-       ccb = xpt_alloc_ccb();
-       if (ccb == NULL)
-               return;
-       if (xpt_create_path(&ccb->ccb_h.path, xpt_periph, bus, tid,
-           CAM_LUN_WILDCARD) != CAM_REQ_CMP) {
-               xpt_free_ccb(ccb);
-               return;
-       }
-       mps_dprint(sassc->sc, MPS_INFO, "Triggering rescan of %d:%d:-1\n",
-           bus, tid);
-       xpt_setup_ccb(&ccb->ccb_h, ccb->ccb_h.path, 5/*priority (low)*/);
-       ccb->ccb_h.func_code = XPT_SCAN_BUS;
-       ccb->ccb_h.cbfcnp = mpssas_bus_scan_cb;
-       ccb->crcn.flags = CAM_FLAG_NONE;
-       xpt_action(ccb);
-}
-
-static void
-mpssas_bus_scan_cb(struct cam_periph *periph, union ccb *ccb)
-{
-       xpt_free_path(ccb->ccb_h.path);
-       kfree(ccb, M_TEMP);
-}
-
-static void
-mpssas_startup(void *data)
-{
-       struct mpssas_softc *sassc = data;
-
-       mps_dprint(sassc->sc, MPS_TRACE, "%s\n", __func__);
-
-       mps_lock(sassc->sc);
-       if ((sassc->flags & MPSSAS_IN_DISCOVERY) == 0) {
-               mpssas_discovery_end(sassc);
-       } else {
-               if (sassc->discovery_timeouts < MPSSAS_MAX_DISCOVERY_TIMEOUTS) {
-                       sassc->flags |= MPSSAS_DISCOVERY_TIMEOUT_PENDING;
-                       callout_reset(&sassc->discovery_callout,
-                           MPSSAS_DISCOVERY_TIMEOUT * hz,
-                           mpssas_discovery_timeout, sassc);
-                       sassc->discovery_timeouts++;
-               } else {
-                       mps_dprint(sassc->sc, MPS_FAULT,
-                           "Discovery timed out, continuing.\n");
-                       sassc->flags &= ~MPSSAS_IN_DISCOVERY;
-                       mpssas_discovery_end(sassc);
-               }
-       }
-       mps_unlock(sassc->sc);
-
-       return;
-}
-
-static void
-mpssas_discovery_timeout(void *data)
-{
-       struct mpssas_softc *sassc = data;
-       struct mps_softc *sc;
-
-       sc = sassc->sc;
-       mps_dprint(sc, MPS_TRACE, "%s\n", __func__);
-
-       mps_lock(sc);
-       mps_printf(sc,
-           "Timeout waiting for discovery, interrupts may not be working!\n");
-       sassc->flags &= ~MPSSAS_DISCOVERY_TIMEOUT_PENDING;
-
-       /* Poll the hardware for events in case interrupts aren't working */
-       mps_intr_locked(sc);
-       mps_unlock(sc);
-
-       /* Check the status of discovery and re-arm the timeout if needed */
-       mpssas_startup(sassc);
-}
-
-static void
-mpssas_action(struct cam_sim *sim, union ccb *ccb)
-{
-       struct mpssas_softc *sassc;
-
-       sassc = cam_sim_softc(sim);
-
-       mps_dprint(sassc->sc, MPS_TRACE, "%s func 0x%x\n", __func__,
-           ccb->ccb_h.func_code);
-
-       switch (ccb->ccb_h.func_code) {
-       case XPT_PATH_INQ:
-       {
-               struct ccb_pathinq *cpi = &ccb->cpi;
-
-               cpi->version_num = 1;
-               cpi->hba_inquiry = PI_SDTR_ABLE|PI_TAG_ABLE|PI_WIDE_16;
-               cpi->target_sprt = 0;
-               cpi->hba_misc = PIM_NOBUSRESET;
-               cpi->hba_eng_cnt = 0;
-               cpi->max_target = sassc->sc->facts->MaxTargets - 1;
-               cpi->max_lun = 0;
-               cpi->initiator_id = 255;
-               strncpy(cpi->sim_vid, "FreeBSD", SIM_IDLEN);
-               strncpy(cpi->hba_vid, "LSILogic", HBA_IDLEN);
-               strncpy(cpi->dev_name, cam_sim_name(sim), DEV_IDLEN);
-               cpi->unit_number = cam_sim_unit(sim);
-               cpi->bus_id = cam_sim_bus(sim);
-               cpi->base_transfer_speed = 150000;
-               cpi->transport = XPORT_SAS;
-               cpi->transport_version = 0;
-               cpi->protocol = PROTO_SCSI;
-               cpi->protocol_version = SCSI_REV_SPC;
-               cpi->ccb_h.status = CAM_REQ_CMP;
-               break;
-       }
-       case XPT_GET_TRAN_SETTINGS:
-       {
-               struct ccb_trans_settings       *cts;
-               struct ccb_trans_settings_sas   *sas;
-               struct ccb_trans_settings_scsi  *scsi;
-               struct mpssas_target *targ;
-
-               cts = &ccb->cts;
-               sas = &cts->xport_specific.sas;
-               scsi = &cts->proto_specific.scsi;
-
-               targ = &sassc->targets[cts->ccb_h.target_id];
-               if (targ->handle == 0x0) {
-                       cts->ccb_h.status = CAM_TID_INVALID;
-                       break;
-               }
-
-               cts->protocol_version = SCSI_REV_SPC2;
-               cts->transport = XPORT_SAS;
-               cts->transport_version = 0;
-
-               sas->valid = CTS_SAS_VALID_SPEED;
-               switch (targ->linkrate) {
-               case 0x08:
-                       sas->bitrate = 150000;
-                       break;
-               case 0x09:
-                       sas->bitrate = 300000;
-                       break;
-               case 0x0a:
-                       sas->bitrate = 600000;
-                       break;
-               default:
-                       sas->valid = 0;
-               }
-
-               cts->protocol = PROTO_SCSI;
-               scsi->valid = CTS_SCSI_VALID_TQ;
-               scsi->flags = CTS_SCSI_FLAGS_TAG_ENB;
-
-               cts->ccb_h.status = CAM_REQ_CMP;
-               break;
-       }
-       case XPT_CALC_GEOMETRY:
-               cam_calc_geometry(&ccb->ccg, /*extended*/1);
-               ccb->ccb_h.status = CAM_REQ_CMP;
-               break;
-       case XPT_RESET_DEV:
-               mpssas_action_resetdev(sassc, ccb);
-               return;
-       case XPT_RESET_BUS:
-       case XPT_ABORT:
-       case XPT_TERM_IO:
-               ccb->ccb_h.status = CAM_REQ_CMP;
-               break;
-       case XPT_SCSI_IO:
-               mpssas_action_scsiio(sassc, ccb);
-               return;
-#if __FreeBSD_version >= 900026
-       case XPT_SMP_IO:
-               mpssas_action_smpio(sassc, ccb);
-               return;
-#endif /* __FreeBSD_version >= 900026 */
-       default:
-               ccb->ccb_h.status = CAM_FUNC_NOTAVAIL;
-               break;
-       }
-       xpt_done(ccb);
-
-}
-
-#if 0
-static void
-mpssas_resettimeout_complete(struct mps_softc *sc, struct mps_command *cm)
-{
-       MPI2_SCSI_TASK_MANAGE_REPLY *resp;
-       uint16_t code;
-
-       mps_dprint(sc, MPS_TRACE, "%s\n", __func__);
-
-       resp = (MPI2_SCSI_TASK_MANAGE_REPLY *)cm->cm_reply;
-       code = resp->ResponseCode;
-
-       mps_free_command(sc, cm);
-       mpssas_unfreeze_device(sassc, targ);
-
-       if (code != MPI2_SCSITASKMGMT_RSP_TM_COMPLETE) {
-               mps_reset_controller(sc);
-       }
-
-       return;
-}
-#endif
-
-static void
-mpssas_scsiio_timeout(void *data)
-{
-       union ccb *ccb;
-       struct mps_softc *sc;
-       struct mps_command *cm;
-       struct mpssas_target *targ;
-#if 0
-       char cdb_str[(SCSI_MAX_CDBLEN * 3) + 1];
-#endif
-
-       cm = (struct mps_command *)data;
-       sc = cm->cm_sc;
-
-       /*
-        * Run the interrupt handler to make sure it's not pending.  This
-        * isn't perfect because the command could have already completed
-        * and been re-used, though this is unlikely.
-        */
-       mps_lock(sc);
-       mps_intr_locked(sc);
-       if (cm->cm_state == MPS_CM_STATE_FREE) {
-               mps_unlock(sc);
-               return;
-       }
-
-       ccb = cm->cm_complete_data;
-       targ = cm->cm_targ;
-       if (targ == NULL)
-               /* Driver bug */
-               targ = &sc->sassc->targets[ccb->ccb_h.target_id];
-
-       xpt_print(ccb->ccb_h.path, "SCSI command timeout on device handle "
-                 "0x%04x SMID %d\n", targ->handle, cm->cm_desc.Default.SMID);
-       /*
-        * XXX KDM this is useful for debugging purposes, but the existing
-        * scsi_op_desc() implementation can't handle a NULL value for
-        * inq_data.  So this will remain commented out until I bring in
-        * those changes as well.
-        */
-#if 0
-       xpt_print(ccb->ccb_h.path, "Timed out command: %s. CDB %s\n",
-                 scsi_op_desc((ccb->ccb_h.flags & CAM_CDB_POINTER) ?
-                               ccb->csio.cdb_io.cdb_ptr[0] :
-                               ccb->csio.cdb_io.cdb_bytes[0], NULL),
-                 scsi_cdb_string((ccb->ccb_h.flags & CAM_CDB_POINTER) ?
-                                  ccb->csio.cdb_io.cdb_ptr :
-                                  ccb->csio.cdb_io.cdb_bytes, cdb_str,
-                                  sizeof(cdb_str)));
-#endif
-
-       /* Inform CAM about the timeout and that recovery is starting. */
-#if 0
-       if ((targ->flags & MPSSAS_TARGET_INRECOVERY) == 0) {
-               mpssas_freeze_device(sc->sassc, targ);
-               ccb->ccb_h.status = CAM_CMD_TIMEOUT;
-               xpt_done(ccb);
-       }
-#endif
-       mpssas_freeze_device(sc->sassc, targ);
-       ccb->ccb_h.status = CAM_CMD_TIMEOUT;
-
-       /*
-        * recycle the command into recovery so that there's no risk of
-        * command allocation failure.
-        */
-       cm->cm_state = MPS_CM_STATE_TIMEDOUT;
-       mpssas_recovery(sc, cm);
-       mps_unlock(sc);
-}
-
-static void
-mpssas_abort_complete(struct mps_softc *sc, struct mps_command *cm)
-{
-       MPI2_SCSI_TASK_MANAGE_REQUEST *req;
-
-       req = (MPI2_SCSI_TASK_MANAGE_REQUEST *)cm->cm_req;
-
-       mps_printf(sc, "%s: abort request on handle %#04x SMID %d "
-                  "complete\n", __func__, req->DevHandle, req->TaskMID);
-
-       mpssas_complete_tm_request(sc, cm, /*free_cm*/ 1);
-}
-
-static void
-mpssas_recovery(struct mps_softc *sc, struct mps_command *abort_cm)
-{
-       struct mps_command *cm;
-       MPI2_SCSI_TASK_MANAGE_REQUEST *req, *orig_req;
-
-       cm = mps_alloc_command(sc);
-       if (cm == NULL) {
-               mps_printf(sc, "%s: command allocation failure\n", __func__);
-               return;
-       }
-
-       cm->cm_targ = abort_cm->cm_targ;
-       cm->cm_complete = mpssas_abort_complete;
-
-       req = (MPI2_SCSI_TASK_MANAGE_REQUEST *)cm->cm_req;
-       orig_req = (MPI2_SCSI_TASK_MANAGE_REQUEST *)abort_cm->cm_req;
-       req->DevHandle = abort_cm->cm_targ->handle;
-       req->Function = MPI2_FUNCTION_SCSI_TASK_MGMT;
-       req->TaskType = MPI2_SCSITASKMGMT_TASKTYPE_ABORT_TASK;
-       memcpy(req->LUN, orig_req->LUN, sizeof(req->LUN));
-       req->TaskMID = abort_cm->cm_desc.Default.SMID;
-
-       cm->cm_data = NULL;
-       cm->cm_desc.Default.RequestFlags = MPI2_REQ_DESCRIPT_FLAGS_DEFAULT_TYPE;
-
-       mpssas_issue_tm_request(sc, cm);
-
-}
-
-/*
- * Can return 0 or EINPROGRESS on success.  Any other value means failure.
- */
-static int
-mpssas_map_tm_request(struct mps_softc *sc, struct mps_command *cm)
-{
-       int error;
-
-       error = 0;
-
-       cm->cm_flags |= MPS_CM_FLAGS_ACTIVE;
-       error = mps_map_command(sc, cm);
-       if ((error == 0)
-        || (error == EINPROGRESS))
-               sc->tm_cmds_active++;
-
-       return (error);
-}
-
-static void
-mpssas_issue_tm_request(struct mps_softc *sc, struct mps_command *cm)
-{
-       int freeze_queue, send_command, error;
-
-       freeze_queue = 0;
-       send_command = 0;
-       error = 0;
-
-       KKASSERT(lockstatus(&sc->mps_lock, curthread) != 0);
-
-       /*
-        * If there are no other pending task management commands, go
-        * ahead and send this one.  There is a small amount of anecdotal
-        * evidence that sending lots of task management commands at once
-        * may cause the controller to lock up.  Or, if the user has
-        * configured the driver (via the allow_multiple_tm_cmds variable) to
-        * not serialize task management commands, go ahead and send the
-        * command if even other task management commands are pending.
-        */
-       if (TAILQ_FIRST(&sc->tm_list) == NULL) {
-               send_command = 1;
-               freeze_queue = 1;
-       } else if (sc->allow_multiple_tm_cmds != 0)
-               send_command = 1;
-
-       TAILQ_INSERT_TAIL(&sc->tm_list, cm, cm_link);
-       if (send_command != 0) {
-               /*
-                * Freeze the SIM queue while we issue the task management
-                * command.  According to the Fusion-MPT 2.0 spec, task
-                * management requests are serialized, and so the host
-                * should not send any I/O requests while task management
-                * requests are pending.
-                */
-               if (freeze_queue != 0)
-                       xpt_freeze_simq(sc->sassc->sim, 1);
-
-               error = mpssas_map_tm_request(sc, cm);
-
-               /*
-                * At present, there is no error path back from
-                * mpssas_map_tm_request() (which calls mps_map_command())
-                * when cm->cm_data == NULL.  But since there is a return
-                * value, we check it just in case the implementation
-                * changes later.
-                */
-               if ((error != 0)
-                && (error != EINPROGRESS))
-                       mpssas_tm_complete(sc, cm,
-                           MPI2_SCSITASKMGMT_RSP_TM_FAILED);
-       }
-}
-
-static void
-mpssas_tm_complete(struct mps_softc *sc, struct mps_command *cm, int error)
-{
-       MPI2_SCSI_TASK_MANAGE_REPLY *resp;
-
-       resp = (MPI2_SCSI_TASK_MANAGE_REPLY *)cm->cm_reply;
-
-       resp->ResponseCode = error;
-
-       /*
-        * Call the callback for this command, it will be
-        * removed from the list and freed via the callback.
-        */
-       cm->cm_complete(sc, cm);
-}
-
-/*
- * Complete a task management request.  The basic completion operation will
- * always succeed.  Returns status for sending any further task management
- * commands that were queued.
- */
-static int
-mpssas_complete_tm_request(struct mps_softc *sc, struct mps_command *cm,
-                          int free_cm)
-{
-       int error;
-
-       error = 0;
-
-       KKASSERT(lockstatus(&sc->mps_lock, curthread) != 0);
-
-       TAILQ_REMOVE(&sc->tm_list, cm, cm_link);
-       cm->cm_flags &= ~MPS_CM_FLAGS_ACTIVE;
-       sc->tm_cmds_active--;
-
-       if (free_cm != 0)
-               mps_free_command(sc, cm);
-
-       if (TAILQ_FIRST(&sc->tm_list) == NULL) {
-               /*
-                * Release the SIM queue, we froze it when we sent the first
-                * task management request.
-                */
-               xpt_release_simq(sc->sassc->sim, 1);
-       } else if ((sc->tm_cmds_active == 0)
-               || (sc->allow_multiple_tm_cmds != 0)) {
-               int error;
-               struct mps_command *cm2;
-
-restart_traversal:
-
-               /*
-                * We don't bother using TAILQ_FOREACH_SAFE here, but
-                * rather use the standard version and just restart the
-                * list traversal if we run into the error case.
-                * TAILQ_FOREACH_SAFE allows safe removal of the current
-                * list element, but if you have a queue of task management
-                * commands, all of which have mapping errors, you'll end
-                * up with recursive calls to this routine and so you could
-                * wind up removing more than just the current list element.
-                */
-               TAILQ_FOREACH(cm2, &sc->tm_list, cm_link) {
-                       MPI2_SCSI_TASK_MANAGE_REQUEST *req;
-
-                       /* This command is active, no need to send it again */
-                       if (cm2->cm_flags & MPS_CM_FLAGS_ACTIVE)
-                               continue;
-
-                       req = (MPI2_SCSI_TASK_MANAGE_REQUEST *)cm2->cm_req;
-
-                       mps_printf(sc, "%s: sending deferred task management "
-                           "request for handle %#04x SMID %d\n", __func__,
-                           req->DevHandle, req->TaskMID);
-
-                       error = mpssas_map_tm_request(sc, cm2);
-
-                       /*
-                        * Check for errors.  If we had an error, complete
-                        * this command with an error, and keep going through
-                        * the list until we are able to send at least one
-                        * command or all of them are completed with errors.
-                        *
-                        * We don't want to wind up in a situation where
-                        * we're stalled out with no way for queued task
-                        * management commands to complete.
-                        *
-                        * Note that there is not currently an error path
-                        * back from mpssas_map_tm_request() (which calls
-                        * mps_map_command()) when cm->cm_data == NULL.
-                        * But we still want to check for errors here in
-                        * case the implementation changes, or in case
-                        * there is some reason for a data payload here.
-                        */
-                       if ((error != 0)
-                        && (error != EINPROGRESS)) {
-                               mpssas_tm_complete(sc, cm,
-                                   MPI2_SCSITASKMGMT_RSP_TM_FAILED);
-
-                               /*
-                                * If we don't currently have any commands
-                                * active, go back to the beginning and see
-                                * if there are any more that can be started.
-                                * Otherwise, we're done here.
-                                */
-                               if (sc->tm_cmds_active == 0)
-                                       goto restart_traversal;
-                               else
-                                       break;
-                       }
-
-                       /*
-                        * If the user only wants one task management command
-                        * active at a time, we're done, since we've
-                        * already successfully sent a command at this point.
-                        */
-                       if (sc->allow_multiple_tm_cmds == 0)
-                               break;
-               }
-       }
-
-       return (error);
-}
-
-static void
-mpssas_action_scsiio(struct mpssas_softc *sassc, union ccb *ccb)
-{
-       MPI2_SCSI_IO_REQUEST *req;
-       struct ccb_scsiio *csio;
-       struct mps_softc *sc;
-       struct mpssas_target *targ;
-       struct mps_command *cm;
-
-       mps_dprint(sassc->sc, MPS_TRACE, "%s\n", __func__);
-
-       sc = sassc->sc;
-
-       csio = &ccb->csio;
-       targ = &sassc->targets[csio->ccb_h.target_id];
-       if (targ->handle == 0x0) {
-               csio->ccb_h.status = CAM_SEL_TIMEOUT;
-               xpt_done(ccb);
-               return;
-       }
-
-       cm = mps_alloc_command(sc);
-       if (cm == NULL) {
-               if ((sassc->flags & MPSSAS_QUEUE_FROZEN) == 0) {
-                       xpt_freeze_simq(sassc->sim, 1);
-                       sassc->flags |= MPSSAS_QUEUE_FROZEN;
-               }
-               ccb->ccb_h.status &= ~CAM_SIM_QUEUED;
-               ccb->ccb_h.status |= CAM_REQUEUE_REQ;
-               xpt_done(ccb);
-               return;
-       }
-
-       req = (MPI2_SCSI_IO_REQUEST *)cm->cm_req;
-       req->DevHandle = targ->handle;
-       req->Function = MPI2_FUNCTION_SCSI_IO_REQUEST;
-       req->MsgFlags = 0;
-       req->SenseBufferLowAddress = cm->cm_sense_busaddr;
-       req->SenseBufferLength = MPS_SENSE_LEN;
-       req->SGLFlags = 0;
-       req->ChainOffset = 0;
-       req->SGLOffset0 = 24;   /* 32bit word offset to the SGL */
-       req->SGLOffset1= 0;
-       req->SGLOffset2= 0;
-       req->SGLOffset3= 0;
-       req->SkipCount = 0;
-       req->DataLength = csio->dxfer_len;
-       req->BidirectionalDataLength = 0;
-       req->IoFlags = csio->cdb_len;
-       req->EEDPFlags = 0;
-
-       /* Note: BiDirectional transfers are not supported */
-       switch (csio->ccb_h.flags & CAM_DIR_MASK) {
-       case CAM_DIR_IN:
-               req->Control = MPI2_SCSIIO_CONTROL_READ;
-               cm->cm_flags |= MPS_CM_FLAGS_DATAIN;
-               break;
-       case CAM_DIR_OUT:
-               req->Control = MPI2_SCSIIO_CONTROL_WRITE;
-               cm->cm_flags |= MPS_CM_FLAGS_DATAOUT;
-               break;
-       case CAM_DIR_NONE:
-       default:
-               req->Control = MPI2_SCSIIO_CONTROL_NODATATRANSFER;
-               break;
-       }
-
-       /*
-        * It looks like the hardware doesn't require an explicit tag
-        * number for each transaction.  SAM Task Management not supported
-        * at the moment.
-        */
-       switch (csio->tag_action) {
-       case MSG_HEAD_OF_Q_TAG:
-               req->Control |= MPI2_SCSIIO_CONTROL_HEADOFQ;
-               break;
-       case MSG_ORDERED_Q_TAG:
-               req->Control |= MPI2_SCSIIO_CONTROL_ORDEREDQ;
-               break;
-       case MSG_ACA_TASK:
-               req->Control |= MPI2_SCSIIO_CONTROL_ACAQ;
-               break;
-       case CAM_TAG_ACTION_NONE:
-       case MSG_SIMPLE_Q_TAG:
-       default:
-               req->Control |= MPI2_SCSIIO_CONTROL_SIMPLEQ;
-               break;
-       }
-
-       if (MPS_SET_LUN(req->LUN, csio->ccb_h.target_lun) != 0) {
-               mps_free_command(sc, cm);
-               ccb->ccb_h.status = CAM_LUN_INVALID;
-               xpt_done(ccb);
-               return;
-       }
-
-       if (csio->ccb_h.flags & CAM_CDB_POINTER)
-               bcopy(csio->cdb_io.cdb_ptr, &req->CDB.CDB32[0], csio->cdb_len);
-       else
-               bcopy(csio->cdb_io.cdb_bytes, &req->CDB.CDB32[0],csio->cdb_len);
-       req->IoFlags = csio->cdb_len;
-
-       /*
-        * XXX need to handle S/G lists and physical addresses here.
-        */
-       cm->cm_data = csio->data_ptr;
-       cm->cm_length = csio->dxfer_len;
-       cm->cm_sge = &req->SGL;
-       cm->cm_sglsize = (32 - 24) * 4;
-       cm->cm_desc.SCSIIO.RequestFlags = MPI2_REQ_DESCRIPT_FLAGS_SCSI_IO;
-       cm->cm_desc.SCSIIO.DevHandle = targ->handle;
-       cm->cm_complete = mpssas_scsiio_complete;
-       cm->cm_complete_data = ccb;
-       cm->cm_targ = targ;
-
-       callout_reset(&cm->cm_callout, (ccb->ccb_h.timeout * hz) / 1000,
-          mpssas_scsiio_timeout, cm);
-
-       mps_map_command(sc, cm);
-       return;
-}
-
-static void
-mpssas_scsiio_complete(struct mps_softc *sc, struct mps_command *cm)
-{
-       MPI2_SCSI_IO_REPLY *rep;
-       union ccb *ccb;
-       struct mpssas_softc *sassc;
-       u_int sense_len;
-       int dir = 0;
-
-       mps_dprint(sc, MPS_TRACE, "%s\n", __func__);
-
-       callout_stop(&cm->cm_callout);
-
-       sassc = sc->sassc;
-       ccb = cm->cm_complete_data;
-       rep = (MPI2_SCSI_IO_REPLY *)cm->cm_reply;
-
-       if (cm->cm_data != NULL) {
-               if (cm->cm_flags & MPS_CM_FLAGS_DATAIN)
-                       dir = BUS_DMASYNC_POSTREAD;
-               else if (cm->cm_flags & MPS_CM_FLAGS_DATAOUT)
-                       dir = BUS_DMASYNC_POSTWRITE;;
-               bus_dmamap_sync(sc->buffer_dmat, cm->cm_dmamap, dir);
-               bus_dmamap_unload(sc->buffer_dmat, cm->cm_dmamap);
-       }
-
-       if (sassc->flags & MPSSAS_QUEUE_FROZEN) {
-               ccb->ccb_h.flags |= CAM_RELEASE_SIMQ;
-               sassc->flags &= ~MPSSAS_QUEUE_FROZEN;
-       }
-
-       /* Take the fast path to completion */
-       if (cm->cm_reply == NULL) {
-               ccb->ccb_h.status = CAM_REQ_CMP;
-               ccb->csio.scsi_status = SCSI_STATUS_OK;
-               mps_free_command(sc, cm);
-               xpt_done(ccb);
-               return;
-       }
-
-       mps_dprint(sc, MPS_INFO, "(%d:%d:%d) IOCStatus= 0x%x, "
-           "ScsiStatus= 0x%x, SCSIState= 0x%x TransferCount= 0x%x\n",
-           xpt_path_path_id(ccb->ccb_h.path),
-           xpt_path_target_id(ccb->ccb_h.path),
-           xpt_path_lun_id(ccb->ccb_h.path), rep->IOCStatus,
-           rep->SCSIStatus, rep->SCSIState, (u_int)rep->TransferCount);
-
-       switch (rep->IOCStatus & MPI2_IOCSTATUS_MASK) {
-       case MPI2_IOCSTATUS_BUSY:
-       case MPI2_IOCSTATUS_INSUFFICIENT_RESOURCES:
-               /*
-                * The controller is overloaded, try waiting a bit for it
-                * to free up.
-                */
-               ccb->ccb_h.status = CAM_BUSY;
-               break;
-       case MPI2_IOCSTATUS_SCSI_DATA_UNDERRUN:
-               ccb->csio.resid = cm->cm_length - rep->TransferCount;
-               /* FALLTHROUGH */
-       case MPI2_IOCSTATUS_SUCCESS:
-       case MPI2_IOCSTATUS_SCSI_RECOVERED_ERROR:
-               ccb->ccb_h.status = CAM_REQ_CMP;
-               break;
-       case MPI2_IOCSTATUS_SCSI_DATA_OVERRUN:
-               /* resid is ignored for this condition */
-               ccb->csio.resid = 0;
-               ccb->ccb_h.status = CAM_DATA_RUN_ERR;
-               break;
-       case MPI2_IOCSTATUS_SCSI_INVALID_DEVHANDLE:
-       case MPI2_IOCSTATUS_SCSI_DEVICE_NOT_THERE:
-               ccb->ccb_h.status = CAM_DEV_NOT_THERE;
-               break;
-       case MPI2_IOCSTATUS_SCSI_TASK_TERMINATED:
-               /*
-                * This is one of the responses that comes back when an I/O
-                * has been aborted.  If it is because of a timeout that we
-                * initiated, just set the status to CAM_CMD_TIMEOUT.
-                * Otherwise set it to CAM_REQ_ABORTED.  The effect on the
-                * command is the same (it gets retried, subject to the
-                * retry counter), the only difference is what gets printed
-                * on the console.
-                */
-               if (cm->cm_state == MPS_CM_STATE_TIMEDOUT)
-                       ccb->ccb_h.status = CAM_CMD_TIMEOUT;
-               else
-                       ccb->ccb_h.status = CAM_REQ_ABORTED;
-               break;
-       case MPI2_IOCSTATUS_SCSI_IOC_TERMINATED:
-       case MPI2_IOCSTATUS_SCSI_EXT_TERMINATED:
-               ccb->ccb_h.status = CAM_REQ_ABORTED;
-               break;
-       case MPI2_IOCSTATUS_INVALID_SGL:
-               mps_print_scsiio_cmd(sc, cm);
-               ccb->ccb_h.status = CAM_UNREC_HBA_ERROR;
-               break;
-       case MPI2_IOCSTATUS_INVALID_FUNCTION:
-       case MPI2_IOCSTATUS_INTERNAL_ERROR:
-       case MPI2_IOCSTATUS_INVALID_VPID:
-       case MPI2_IOCSTATUS_INVALID_FIELD:
-       case MPI2_IOCSTATUS_INVALID_STATE:
-       case MPI2_IOCSTATUS_OP_STATE_NOT_SUPPORTED:
-       case MPI2_IOCSTATUS_SCSI_IO_DATA_ERROR:
-       case MPI2_IOCSTATUS_SCSI_PROTOCOL_ERROR:
-       case MPI2_IOCSTATUS_SCSI_RESIDUAL_MISMATCH:
-       case MPI2_IOCSTATUS_SCSI_TASK_MGMT_FAILED:
-       default:
-               ccb->ccb_h.status = CAM_REQ_CMP_ERR;
-       }
-
-
-       if ((rep->SCSIState & MPI2_SCSI_STATE_NO_SCSI_STATUS) == 0) {
-               ccb->csio.scsi_status = rep->SCSIStatus;
-
-               switch (rep->SCSIStatus) {
-               case MPI2_SCSI_STATUS_TASK_SET_FULL:
-               case MPI2_SCSI_STATUS_CHECK_CONDITION:
-                       ccb->ccb_h.status = CAM_SCSI_STATUS_ERROR;
-                       break;
-               case MPI2_SCSI_STATUS_COMMAND_TERMINATED:
-               case MPI2_SCSI_STATUS_TASK_ABORTED:
-                       ccb->ccb_h.status = CAM_REQ_ABORTED;
-                       break;
-               case MPI2_SCSI_STATUS_GOOD:
-               default:
-                       break;
-               }
-       }
-
-       if (rep->SCSIState & MPI2_SCSI_STATE_AUTOSENSE_VALID) {
-               sense_len = MIN(rep->SenseCount,
-                   sizeof(struct scsi_sense_data));
-               if (sense_len < rep->SenseCount)
-                       ccb->csio.sense_resid = rep->SenseCount - sense_len;
-               bcopy(cm->cm_sense, &ccb->csio.sense_data, sense_len);
-               ccb->ccb_h.status |= CAM_AUTOSNS_VALID;
-       }
-
-       if (rep->SCSIState & MPI2_SCSI_STATE_AUTOSENSE_FAILED)
-               ccb->ccb_h.status = CAM_AUTOSENSE_FAIL;
-
-       if (rep->SCSIState & MPI2_SCSI_STATE_RESPONSE_INFO_VALID)
-               ccb->ccb_h.status = CAM_REQ_CMP_ERR;
-
-       mps_free_command(sc, cm);
-       xpt_done(ccb);
-}
-
-#if __FreeBSD_version >= 900026
-static void
-mpssas_smpio_complete(struct mps_softc *sc, struct mps_command *cm)
-{
-       MPI2_SMP_PASSTHROUGH_REPLY *rpl;
-       MPI2_SMP_PASSTHROUGH_REQUEST *req;
-       uint64_t sasaddr;
-       union ccb *ccb;
-
-       ccb = cm->cm_complete_data;
-       rpl = (MPI2_SMP_PASSTHROUGH_REPLY *)cm->cm_reply;
-       if (rpl == NULL) {
-               mps_dprint(sc, MPS_INFO, "%s: NULL cm_reply!\n", __func__);
-               ccb->ccb_h.status = CAM_REQ_CMP_ERR;
-               goto bailout;
-       }
-
-       req = (MPI2_SMP_PASSTHROUGH_REQUEST *)cm->cm_req;
-       sasaddr = le32toh(req->SASAddress.Low);
-       sasaddr |= ((uint64_t)(le32toh(req->SASAddress.High))) << 32;
-
-       if ((rpl->IOCStatus & MPI2_IOCSTATUS_MASK) != MPI2_IOCSTATUS_SUCCESS ||
-           rpl->SASStatus != MPI2_SASSTATUS_SUCCESS) {
-               mps_dprint(sc, MPS_INFO, "%s: IOCStatus %04x SASStatus %02x\n",
-                   __func__, rpl->IOCStatus, rpl->SASStatus);
-               ccb->ccb_h.status = CAM_REQ_CMP_ERR;
-               goto bailout;
-       }
-
-       mps_dprint(sc, MPS_INFO, "%s: SMP request to SAS address "
-                  "%#jx completed successfully\n", __func__,
-                  (uintmax_t)sasaddr);
-
-       if (ccb->smpio.smp_response[2] == SMP_FR_ACCEPTED)
-               ccb->ccb_h.status = CAM_REQ_CMP;
-       else
-               ccb->ccb_h.status = CAM_SMP_STATUS_ERROR;
-
-bailout:
-       /*
-        * We sync in both directions because we had DMAs in the S/G list
-        * in both directions.
-        */
-       bus_dmamap_sync(sc->buffer_dmat, cm->cm_dmamap,
-                       BUS_DMASYNC_POSTREAD | BUS_DMASYNC_POSTWRITE);
-       bus_dmamap_unload(sc->buffer_dmat, cm->cm_dmamap);
-       mps_free_command(sc, cm);
-       xpt_done(ccb);
-}
-
-static void
-mpssas_send_smpcmd(struct mpssas_softc *sassc, union ccb *ccb, uint64_t sasaddr)
-{
-       struct mps_command *cm;
-       uint8_t *request, *response;
-       MPI2_SMP_PASSTHROUGH_REQUEST *req;
-       struct mps_softc *sc;
-       struct sglist *sg;
-       int error;
-
-       sc = sassc->sc;
-       sg = NULL;
-       error = 0;
-
-       /*
-        * XXX We don't yet support physical addresses here.
-        */
-       if (ccb->ccb_h.flags & (CAM_DATA_PHYS|CAM_SG_LIST_PHYS)) {
-               mps_printf(sc, "%s: physical addresses not supported\n",
-                          __func__);
-               ccb->ccb_h.status = CAM_REQ_INVALID;
-               xpt_done(ccb);
-               return;
-       }
-
-       /*
-        * If the user wants to send an S/G list, check to make sure they
-        * have single buffers.
-        */
-       if (ccb->ccb_h.flags & CAM_SCATTER_VALID) {
-               /*
-                * The chip does not support more than one buffer for the
-                * request or response.
-                */
-               if ((ccb->smpio.smp_request_sglist_cnt > 1)
-                 || (ccb->smpio.smp_response_sglist_cnt > 1)) {
-                       mps_printf(sc, "%s: multiple request or response "
-                                  "buffer segments not supported for SMP\n",
-                                  __func__);
-                       ccb->ccb_h.status = CAM_REQ_INVALID;
-                       xpt_done(ccb);
-                       return;
-               }
-
-               /*
-                * The CAM_SCATTER_VALID flag was originally implemented
-                * for the XPT_SCSI_IO CCB, which only has one data pointer.
-                * We have two.  So, just take that flag to mean that we
-                * might have S/G lists, and look at the S/G segment count
-                * to figure out whether that is the case for each individual
-                * buffer.
-                */
-               if (ccb->smpio.smp_request_sglist_cnt != 0) {
-                       bus_dma_segment_t *req_sg;
-
-                       req_sg = (bus_dma_segment_t *)ccb->smpio.smp_request;
-                       request = (uint8_t *)req_sg[0].ds_addr;
-               } else
-                       request = ccb->smpio.smp_request;
-
-               if (ccb->smpio.smp_response_sglist_cnt != 0) {
-                       bus_dma_segment_t *rsp_sg;
-
-                       rsp_sg = (bus_dma_segment_t *)ccb->smpio.smp_response;
-                       response = (uint8_t *)rsp_sg[0].ds_addr;
-               } else
-                       response = ccb->smpio.smp_response;
-       } else {
-               request = ccb->smpio.smp_request;
-               response = ccb->smpio.smp_response;
-       }
-
-       cm = mps_alloc_command(sc);
-       if (cm == NULL) {
-               mps_printf(sc, "%s: cannot allocate command\n", __func__);
-               ccb->ccb_h.status = CAM_RESRC_UNAVAIL;
-               xpt_done(ccb);
-               return;
-       }
-
-       req = (MPI2_SMP_PASSTHROUGH_REQUEST *)cm->cm_req;
-       bzero(req, sizeof(*req));
-       req->Function = MPI2_FUNCTION_SMP_PASSTHROUGH;
-
-       /* Allow the chip to use any route to this SAS address. */
-       req->PhysicalPort = 0xff;
-
-       req->RequestDataLength = ccb->smpio.smp_request_len;
-       req->SGLFlags =
-           MPI2_SGLFLAGS_SYSTEM_ADDRESS_SPACE | MPI2_SGLFLAGS_SGL_TYPE_MPI;
-
-       mps_dprint(sc, MPS_INFO, "%s: sending SMP request to SAS "
-                  "address %#jx\n", __func__, (uintmax_t)sasaddr);
-
-       mpi_init_sge(cm, req, &req->SGL);
-
-       /*
-        * Set up a uio to pass into mps_map_command().  This allows us to
-        * do one map command, and one busdma call in there.
-        */
-       cm->cm_uio.uio_iov = cm->cm_iovec;
-       cm->cm_uio.uio_iovcnt = 2;
-       cm->cm_uio.uio_segflg = UIO_SYSSPACE;
-
-       /*
-        * The read/write flag isn't used by busdma, but set it just in
-        * case.  This isn't exactly accurate, either, since we're going in
-        * both directions.
-        */
-       cm->cm_uio.uio_rw = UIO_WRITE;
-
-       cm->cm_iovec[0].iov_base = request;
-       cm->cm_iovec[0].iov_len = req->RequestDataLength;
-       cm->cm_iovec[1].iov_base = response;
-       cm->cm_iovec[1].iov_len = ccb->smpio.smp_response_len;
-
-       cm->cm_uio.uio_resid = cm->cm_iovec[0].iov_len +
-                              cm->cm_iovec[1].iov_len;
-
-       /*
-        * Trigger a warning message in mps_data_cb() for the user if we
-        * wind up exceeding two S/G segments.  The chip expects one
-        * segment for the request and another for the response.
-        */
-       cm->cm_max_segs = 2;
-
-       cm->cm_desc.Default.RequestFlags = MPI2_REQ_DESCRIPT_FLAGS_DEFAULT_TYPE;
-       cm->cm_complete = mpssas_smpio_complete;
-       cm->cm_complete_data = ccb;
-
-       /*
-        * Tell the mapping code that we're using a uio, and that this is
-        * an SMP passthrough request.  There is a little special-case
-        * logic there (in mps_data_cb()) to handle the bidirectional
-        * transfer.
-        */
-       cm->cm_flags |= MPS_CM_FLAGS_USE_UIO | MPS_CM_FLAGS_SMP_PASS |
-                       MPS_CM_FLAGS_DATAIN | MPS_CM_FLAGS_DATAOUT;
-
-       /* The chip data format is little endian. */
-       req->SASAddress.High = htole32(sasaddr >> 32);
-       req->SASAddress.Low = htole32(sasaddr);
-
-       /*
-        * XXX Note that we don't have a timeout/abort mechanism here.
-        * From the manual, it looks like task management requests only
-        * work for SCSI IO and SATA passthrough requests.  We may need to
-        * have a mechanism to retry requests in the event of a chip reset
-        * at least.  Hopefully the chip will insure that any errors short
-        * of that are relayed back to the driver.
-        */
-       error = mps_map_command(sc, cm);
-       if ((error != 0) && (error != EINPROGRESS)) {
-               mps_printf(sc, "%s: error %d returned from mps_map_command()\n",
-                          __func__, error);
-               goto bailout_error;
-       }
-
-       return;
-
-bailout_error:
-       mps_free_command(sc, cm);
-       ccb->ccb_h.status = CAM_RESRC_UNAVAIL;
-       xpt_done(ccb);
-       return;
-
-}
-
-static void
-mpssas_action_smpio(struct mpssas_softc *sassc, union ccb *ccb)
-{
-       struct mps_softc *sc;
-       struct mpssas_target *targ;
-       uint64_t sasaddr = 0;
-
-       sc = sassc->sc;
-
-       /*
-        * Make sure the target exists.
-        */
-       targ = &sassc->targets[ccb->ccb_h.target_id];
-       if (targ->handle == 0x0) {
-               mps_printf(sc, "%s: target %d does not exist!\n", __func__,
-                          ccb->ccb_h.target_id);
-               ccb->ccb_h.status = CAM_SEL_TIMEOUT;
-               xpt_done(ccb);
-               return;
-       }
-
-       /*
-        * If this device has an embedded SMP target, we'll talk to it
-        * directly.
-        * figure out what the expander's address is.
-        */
-       if ((targ->devinfo & MPI2_SAS_DEVICE_INFO_SMP_TARGET) != 0)
-               sasaddr = targ->sasaddr;
-
-       /*
-        * If we don't have a SAS address for the expander yet, try
-        * grabbing it from the page 0x83 information cached in the
-        * transport layer for this target.  LSI expanders report the
-        * expander SAS address as the port-associated SAS address in
-        * Inquiry VPD page 0x83.  Maxim expanders don't report it in page
-        * 0x83.
-        *
-        * XXX KDM disable this for now, but leave it commented out so that
-        * it is obvious that this is another possible way to get the SAS
-        * address.
-        *
-        * The parent handle method below is a little more reliable, and
-        * the other benefit is that it works for devices other than SES
-        * devices.  So you can send a SMP request to a da(4) device and it
-        * will get routed to the expander that device is attached to.
-        * (Assuming the da(4) device doesn't contain an SMP target...)
-        */
-#if 0
-       if (sasaddr == 0)
-               sasaddr = xpt_path_sas_addr(ccb->ccb_h.path);
-#endif
-
-       /*
-        * If we still don't have a SAS address for the expander, look for
-        * the parent device of this device, which is probably the expander.
-        */
-       if (sasaddr == 0) {
-               struct mpssas_target *parent_target;
-
-               if (targ->parent_handle == 0x0) {
-                       mps_printf(sc, "%s: handle %d does not have a valid "
-                                  "parent handle!\n", __func__, targ->handle);
-                       ccb->ccb_h.status = CAM_REQ_INVALID;
-                       goto bailout;
-               }
-               parent_target = mpssas_find_target(sassc, 0,
-                                                  targ->parent_handle);
-
-               if (parent_target == NULL) {
-                       mps_printf(sc, "%s: handle %d does not have a valid "
-                                  "parent target!\n", __func__, targ->handle);
-                       ccb->ccb_h.status = CAM_REQ_INVALID;
-                       goto bailout;
-               }
-
-               if ((parent_target->devinfo &
-                    MPI2_SAS_DEVICE_INFO_SMP_TARGET) == 0) {
-                       mps_printf(sc, "%s: handle %d parent %d does not "
-                                  "have an SMP target!\n", __func__,
-                                  targ->handle, parent_target->handle);
-                       ccb->ccb_h.status = CAM_REQ_INVALID;
-                       goto bailout;
-
-               }
-
-               sasaddr = parent_target->sasaddr;
-       }
-
-       if (sasaddr == 0) {
-               mps_printf(sc, "%s: unable to find SAS address for handle %d\n",
-                          __func__, targ->handle);
-               ccb->ccb_h.status = CAM_REQ_INVALID;
-               goto bailout;
-       }
-       mpssas_send_smpcmd(sassc, ccb, sasaddr);
-
-       return;
-
-bailout:
-       xpt_done(ccb);
-
-}
-
-#endif /* __FreeBSD_version >= 900026 */
-
-static void
-mpssas_action_resetdev(struct mpssas_softc *sassc, union ccb *ccb)
-{
-       struct mps_softc *sc;
-       struct mps_command *cm;
-       struct mpssas_target *targ;
-
-       sc = sassc->sc;
-       targ = &sassc->targets[ccb->ccb_h.target_id];
-
-       if (targ->flags & MPSSAS_TARGET_INRECOVERY) {
-               ccb->ccb_h.status = CAM_RESRC_UNAVAIL;
-               xpt_done(ccb);
-               return;
-       }
-
-       cm = mps_alloc_command(sc);
-       if (cm == NULL) {
-               mps_printf(sc, "%s: cannot alloc command\n", __func__);
-               ccb->ccb_h.status = CAM_RESRC_UNAVAIL;
-               xpt_done(ccb);
-               return;
-       }
-
-       cm->cm_targ = targ;
-       cm->cm_complete = mpssas_resetdev_complete;
-       cm->cm_complete_data = ccb;
-
-       mpssas_resetdev(sassc, cm);
-}
-
-static void
-mpssas_resetdev(struct mpssas_softc *sassc, struct mps_command *cm)
-{
-       MPI2_SCSI_TASK_MANAGE_REQUEST *req;
-       struct mps_softc *sc;
-
-       mps_dprint(sassc->sc, MPS_TRACE, "%s\n", __func__);
-
-       sc = sassc->sc;
-
-       req = (MPI2_SCSI_TASK_MANAGE_REQUEST *)cm->cm_req;
-       req->DevHandle = cm->cm_targ->handle;
-       req->Function = MPI2_FUNCTION_SCSI_TASK_MGMT;
-       req->TaskType = MPI2_SCSITASKMGMT_TASKTYPE_TARGET_RESET;
-
-       /* SAS Hard Link Reset / SATA Link Reset */
-       req->MsgFlags = MPI2_SCSITASKMGMT_MSGFLAGS_LINK_RESET;
-
-       cm->cm_data = NULL;
-       cm->cm_desc.Default.RequestFlags = MPI2_REQ_DESCRIPT_FLAGS_DEFAULT_TYPE;
-
-       mpssas_issue_tm_request(sc, cm);
-}
-
-static void
-mpssas_resetdev_complete(struct mps_softc *sc, struct mps_command *cm)
-{
-       MPI2_SCSI_TASK_MANAGE_REPLY *resp;
-       union ccb *ccb;
-
-       mps_dprint(sc, MPS_TRACE, "%s\n", __func__);
-
-       resp = (MPI2_SCSI_TASK_MANAGE_REPLY *)cm->cm_reply;
-       ccb = cm->cm_complete_data;
-
-       kprintf("resetdev complete IOCStatus= 0x%x ResponseCode= 0x%x\n",
-           resp->IOCStatus, resp->ResponseCode);
-
-       if (resp->ResponseCode == MPI2_SCSITASKMGMT_RSP_TM_COMPLETE)
-               ccb->ccb_h.status = CAM_REQ_CMP;
-       else
-               ccb->ccb_h.status = CAM_REQ_CMP_ERR;
-
-       mpssas_complete_tm_request(sc, cm, /*free_cm*/ 1);
-
-       xpt_done(ccb);
-}
-
-static void
-mpssas_poll(struct cam_sim *sim)
-{
-       struct mpssas_softc *sassc;
-
-       sassc = cam_sim_softc(sim);
-       mps_intr_locked(sassc->sc);
-}
-
-static void
-mpssas_freeze_device(struct mpssas_softc *sassc, struct mpssas_target *targ)
-{
-}
-
-static void
-mpssas_unfreeze_device(struct mpssas_softc *sassc, struct mpssas_target *targ)
-{
-}
diff --git a/sys/dev/disk/mps/mps_user.c b/sys/dev/disk/mps/mps_user.c
deleted file mode 100644 (file)
index 920eea7..0000000
+++ /dev/null
@@ -1,943 +0,0 @@
-/*-
- * Copyright (c) 2008 Yahoo!, Inc.
- * All rights reserved.
- * Written by: John Baldwin <jhb@FreeBSD.org>
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- *    notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- *    notice, this list of conditions and the following disclaimer in the
- *    documentation and/or other materials provided with the distribution.
- * 3. Neither the name of the author nor the names of any co-contributors
- *    may be used to endorse or promote products derived from this software
- *    without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
- * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
- * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- *
- * LSI MPS-Fusion Host Adapter FreeBSD userland interface
- *
- * $FreeBSD: src/sys/dev/mps/mps_user.c,v 1.9 2010/11/30 22:39:46 ken Exp $
- */
-
-#include "opt_compat.h"
-
-#include <sys/types.h>
-#include <sys/param.h>
-#include <sys/systm.h>
-#include <sys/kernel.h>
-#include <sys/module.h>
-#include <sys/bus.h>
-#include <sys/conf.h>
-#include <sys/bio.h>
-#include <sys/malloc.h>
-#include <sys/uio.h>
-#include <sys/sysctl.h>
-#include <sys/ioccom.h>
-#include <sys/endian.h>
-#include <sys/proc.h>
-#include <sys/sysent.h>
-
-#include <sys/rman.h>
-#include <sys/device.h>
-
-#include <bus/cam/scsi/scsi_all.h>
-
-#include <dev/disk/mps/mpi/mpi2_type.h>
-#include <dev/disk/mps/mpi/mpi2.h>
-#include <dev/disk/mps/mpi/mpi2_ioc.h>
-#include <dev/disk/mps/mpi/mpi2_cnfg.h>
-#include <dev/disk/mps/mpsvar.h>
-#include <dev/disk/mps/mps_table.h>
-#include <dev/disk/mps/mps_ioctl.h>
-
-static d_open_t                mps_open;
-static d_close_t       mps_close;
-static d_ioctl_t       mps_ioctl_devsw;
-
-static struct dev_ops mps_ops = {
-       { "mps", 0, 0 },
-       .d_open =       mps_open,
-       .d_close =      mps_close,
-       .d_ioctl =      mps_ioctl_devsw,
-};
-
-typedef int (mps_user_f)(struct mps_command *, struct mps_usr_command *);
-static mps_user_f      mpi_pre_ioc_facts;
-static mps_user_f      mpi_pre_port_facts;
-static mps_user_f      mpi_pre_fw_download;
-static mps_user_f      mpi_pre_fw_upload;
-static mps_user_f      mpi_pre_sata_passthrough;
-static mps_user_f      mpi_pre_smp_passthrough;
-static mps_user_f      mpi_pre_config;
-static mps_user_f      mpi_pre_sas_io_unit_control;
-
-static int mps_user_read_cfg_header(struct mps_softc *,
-                                   struct mps_cfg_page_req *);
-static int mps_user_read_cfg_page(struct mps_softc *,
-                                 struct mps_cfg_page_req *, void *);
-static int mps_user_read_extcfg_header(struct mps_softc *,
-                                    struct mps_ext_cfg_page_req *);
-static int mps_user_read_extcfg_page(struct mps_softc *,
-                                    struct mps_ext_cfg_page_req *, void *);
-static int mps_user_write_cfg_page(struct mps_softc *,
-                                  struct mps_cfg_page_req *, void *);
-static int mps_user_setup_request(struct mps_command *,
-                                 struct mps_usr_command *);
-static int mps_user_command(struct mps_softc *, struct mps_usr_command *);
-
-static MALLOC_DEFINE(M_MPSUSER, "mps_user", "Buffers for mps(4) ioctls");
-
-int
-mps_attach_user(struct mps_softc *sc)
-{
-       int unit;
-
-       unit = device_get_unit(sc->mps_dev);
-       sc->mps_cdev = make_dev(&mps_ops, unit, UID_ROOT, GID_OPERATOR, 0640,
-           "mps%d", unit);
-       if (sc->mps_cdev == NULL) {
-               return (ENOMEM);
-       }
-       sc->mps_cdev->si_drv1 = sc;
-       return (0);
-}
-
-void
-mps_detach_user(struct mps_softc *sc)
-{
-
-       /* XXX: do a purge of pending requests? */
-       destroy_dev(sc->mps_cdev);
-       dev_ops_remove_minor(&mps_ops, device_get_unit(sc->mps_dev));
-
-}
-
-static int
-mps_open(struct dev_open_args *ap)
-{
-
-       return (0);
-}
-
-static int
-mps_close(struct dev_close_args *ap)
-{
-
-       return (0);
-}
-
-static int
-mps_user_read_cfg_header(struct mps_softc *sc,
-    struct mps_cfg_page_req *page_req)
-{
-       MPI2_CONFIG_PAGE_HEADER *hdr;
-       struct mps_config_params params;
-       int         error;
-
-       hdr = &params.hdr.Struct;
-       params.action = MPI2_CONFIG_ACTION_PAGE_HEADER;
-       params.page_address = le32toh(page_req->page_address);
-       hdr->PageVersion = 0;
-       hdr->PageLength = 0;
-       hdr->PageNumber = page_req->header.PageNumber;
-       hdr->PageType = page_req->header.PageType;
-       params.buffer = NULL;
-       params.length = 0;
-       params.callback = NULL;
-
-       if ((error = mps_read_config_page(sc, &params)) != 0) {
-               /*
-                * Leave the request. Without resetting the chip, it's
-                * still owned by it and we'll just get into trouble
-                * freeing it now. Mark it as abandoned so that if it
-                * shows up later it can be freed.
-                */
-               mps_printf(sc, "read_cfg_header timed out\n");
-               return (ETIMEDOUT);
-       }
-
-       page_req->ioc_status = htole16(params.status);
-       if ((page_req->ioc_status & MPI2_IOCSTATUS_MASK) ==
-           MPI2_IOCSTATUS_SUCCESS) {
-               bcopy(hdr, &page_req->header, sizeof(page_req->header));
-       }
-
-       return (0);
-}
-
-static int
-mps_user_read_cfg_page(struct mps_softc *sc, struct mps_cfg_page_req *page_req,
-    void *buf)
-{
-       MPI2_CONFIG_PAGE_HEADER *reqhdr, *hdr;
-       struct mps_config_params params;
-       int           error;
-
-       reqhdr = buf;
-       hdr = &params.hdr.Struct;
-       hdr->PageVersion = reqhdr->PageVersion;
-       hdr->PageLength = reqhdr->PageLength;
-       hdr->PageNumber = reqhdr->PageNumber;
-       hdr->PageType = reqhdr->PageType & MPI2_CONFIG_PAGETYPE_MASK;
-       params.action = MPI2_CONFIG_ACTION_PAGE_READ_CURRENT;
-       params.page_address = le32toh(page_req->page_address);
-       params.buffer = buf;
-       params.length = le32toh(page_req->len);
-       params.callback = NULL;
-
-       if ((error = mps_read_config_page(sc, &params)) != 0) {
-               mps_printf(sc, "mps_user_read_cfg_page timed out\n");
-               return (ETIMEDOUT);
-       }
-
-       page_req->ioc_status = htole16(params.status);
-       return (0);
-}
-
-static int
-mps_user_read_extcfg_header(struct mps_softc *sc,
-    struct mps_ext_cfg_page_req *ext_page_req)
-{
-       MPI2_CONFIG_EXTENDED_PAGE_HEADER *hdr;
-       struct mps_config_params params;
-       int         error;
-
-       hdr = &params.hdr.Ext;
-       params.action = MPI2_CONFIG_ACTION_PAGE_HEADER;
-       hdr->PageVersion = ext_page_req->header.PageVersion;
-       hdr->ExtPageLength = 0;
-       hdr->PageNumber = ext_page_req->header.PageNumber;
-       hdr->ExtPageType = ext_page_req->header.ExtPageType;
-       params.page_address = le32toh(ext_page_req->page_address);
-       if ((error = mps_read_config_page(sc, &params)) != 0) {
-               /*
-                * Leave the request. Without resetting the chip, it's
-                * still owned by it and we'll just get into trouble
-                * freeing it now. Mark it as abandoned so that if it
-                * shows up later it can be freed.
-                */
-               mps_printf(sc, "mps_user_read_extcfg_header timed out\n");
-               return (ETIMEDOUT);
-       }
-
-       ext_page_req->ioc_status = htole16(params.status);
-       if ((ext_page_req->ioc_status & MPI2_IOCSTATUS_MASK) ==
-           MPI2_IOCSTATUS_SUCCESS) {
-               ext_page_req->header.PageVersion = hdr->PageVersion;
-               ext_page_req->header.PageNumber = hdr->PageNumber;
-               ext_page_req->header.PageType = hdr->PageType;
-               ext_page_req->header.ExtPageLength = hdr->ExtPageLength;
-               ext_page_req->header.ExtPageType = hdr->ExtPageType;
-       }
-
-       return (0);
-}
-
-static int
-mps_user_read_extcfg_page(struct mps_softc *sc,
-    struct mps_ext_cfg_page_req *ext_page_req, void *buf)
-{
-       MPI2_CONFIG_EXTENDED_PAGE_HEADER *reqhdr, *hdr;
-       struct mps_config_params params;
-       int error;
-
-       reqhdr = buf;
-       hdr = &params.hdr.Ext;
-       params.action = MPI2_CONFIG_ACTION_PAGE_READ_CURRENT;
-       params.page_address = le32toh(ext_page_req->page_address);
-       hdr->PageVersion = reqhdr->PageVersion;
-       hdr->PageNumber = reqhdr->PageNumber;
-       hdr->ExtPageType = reqhdr->ExtPageType;
-       hdr->ExtPageLength = reqhdr->ExtPageLength;
-       params.buffer = buf;
-       params.length = le32toh(ext_page_req->len);
-       params.callback = NULL;
-
-       if ((error = mps_read_config_page(sc, &params)) != 0) {
-               mps_printf(sc, "mps_user_read_extcfg_page timed out\n");
-               return (ETIMEDOUT);
-       }
-
-       ext_page_req->ioc_status = htole16(params.status);
-       return (0);
-}
-
-static int
-mps_user_write_cfg_page(struct mps_softc *sc,
-    struct mps_cfg_page_req *page_req, void *buf)
-{
-       MPI2_CONFIG_PAGE_HEADER *reqhdr, *hdr;
-       struct mps_config_params params;
-       u_int         hdr_attr;
-       int           error;
-
-       reqhdr = buf;
-       hdr = &params.hdr.Struct;
-       hdr_attr = reqhdr->PageType & MPI2_CONFIG_PAGEATTR_MASK;
-       if (hdr_attr != MPI2_CONFIG_PAGEATTR_CHANGEABLE &&
-           hdr_attr != MPI2_CONFIG_PAGEATTR_PERSISTENT) {
-               mps_printf(sc, "page type 0x%x not changeable\n",
-                       reqhdr->PageType & MPI2_CONFIG_PAGETYPE_MASK);
-               return (EINVAL);
-       }
-
-       /*
-        * There isn't any point in restoring stripped out attributes
-        * if you then mask them going down to issue the request.
-        */
-
-       hdr->PageVersion = reqhdr->PageVersion;
-       hdr->PageLength = reqhdr->PageLength;
-       hdr->PageNumber = reqhdr->PageNumber;
-       hdr->PageType = reqhdr->PageType;
-       params.action = MPI2_CONFIG_ACTION_PAGE_WRITE_CURRENT;
-       params.page_address = le32toh(page_req->page_address);
-       params.buffer = buf;
-       params.length = le32toh(page_req->len);
-       params.callback = NULL;
-
-       if ((error = mps_write_config_page(sc, &params)) != 0) {
-               mps_printf(sc, "mps_write_cfg_page timed out\n");
-               return (ETIMEDOUT);
-       }
-
-       page_req->ioc_status = htole16(params.status);
-       return (0);
-}
-
-void
-mpi_init_sge(struct mps_command *cm, void *req, void *sge)
-{
-       int off, space;
-
-       space = (int)cm->cm_sc->facts->IOCRequestFrameSize * 4;
-       off = (uintptr_t)sge - (uintptr_t)req;
-
-       KASSERT(off < space, ("bad pointers %p %p, off %d, space %d",
-            req, sge, off, space));
-
-       cm->cm_sge = sge;
-       cm->cm_sglsize = space - off;
-}
-
-/*
- * Prepare the mps_command for an IOC_FACTS request.
- */
-static int
-mpi_pre_ioc_facts(struct mps_command *cm, struct mps_usr_command *cmd)
-{
-       MPI2_IOC_FACTS_REQUEST *req = (void *)cm->cm_req;
-       MPI2_IOC_FACTS_REPLY *rpl;
-
-       if (cmd->req_len != sizeof *req)
-               return (EINVAL);
-       if (cmd->rpl_len != sizeof *rpl)
-               return (EINVAL);
-
-       cm->cm_sge = NULL;
-       cm->cm_sglsize = 0;
-       return (0);
-}
-
-/*
- * Prepare the mps_command for a PORT_FACTS request.
- */
-static int
-mpi_pre_port_facts(struct mps_command *cm, struct mps_usr_command *cmd)
-{
-       MPI2_PORT_FACTS_REQUEST *req = (void *)cm->cm_req;
-       MPI2_PORT_FACTS_REPLY *rpl;
-
-       if (cmd->req_len != sizeof *req)
-               return (EINVAL);
-       if (cmd->rpl_len != sizeof *rpl)
-               return (EINVAL);
-
-       cm->cm_sge = NULL;
-       cm->cm_sglsize = 0;
-       return (0);
-}
-
-/*
- * Prepare the mps_command for a FW_DOWNLOAD request.
- */
-static int
-mpi_pre_fw_download(struct mps_command *cm, struct mps_usr_command *cmd)
-{
-       MPI2_FW_DOWNLOAD_REQUEST *req = (void *)cm->cm_req;
-       MPI2_FW_DOWNLOAD_REPLY *rpl;
-       MPI2_FW_DOWNLOAD_TCSGE tc;
-       int error;
-
-       /*
-        * This code assumes there is room in the request's SGL for
-        * the TransactionContext plus at least a SGL chain element.
-        */
-       CTASSERT(sizeof req->SGL >= sizeof tc + MPS_SGC_SIZE);
-
-       if (cmd->req_len != sizeof *req)
-               return (EINVAL);
-       if (cmd->rpl_len != sizeof *rpl)
-               return (EINVAL);
-
-       if (cmd->len == 0)
-               return (EINVAL);
-
-       error = copyin(cmd->buf, cm->cm_data, cmd->len);
-       if (error != 0)
-               return (error);
-
-       mpi_init_sge(cm, req, &req->SGL);
-       bzero(&tc, sizeof tc);
-
-       /*
-        * For now, the F/W image must be provided in a single request.
-        */
-       if ((req->MsgFlags & MPI2_FW_DOWNLOAD_MSGFLGS_LAST_SEGMENT) == 0)
-               return (EINVAL);
-       if (req->TotalImageSize != cmd->len)
-               return (EINVAL);
-
-       /*
-        * The value of the first two elements is specified in the
-        * Fusion-MPT Message Passing Interface document.
-        */
-       tc.ContextSize = 0;
-       tc.DetailsLength = 12;
-       tc.ImageOffset = 0;
-       tc.ImageSize = cmd->len;
-
-       cm->cm_flags |= MPS_CM_FLAGS_DATAOUT;
-
-       return (mps_push_sge(cm, &tc, sizeof tc, 0));
-}
-
-/*
- * Prepare the mps_command for a FW_UPLOAD request.
- */
-static int
-mpi_pre_fw_upload(struct mps_command *cm, struct mps_usr_command *cmd)
-{
-       MPI2_FW_UPLOAD_REQUEST *req = (void *)cm->cm_req;
-       MPI2_FW_UPLOAD_REPLY *rpl;
-       MPI2_FW_UPLOAD_TCSGE tc;
-
-       /*
-        * This code assumes there is room in the request's SGL for
-        * the TransactionContext plus at least a SGL chain element.
-        */
-       CTASSERT(sizeof req->SGL >= sizeof tc + MPS_SGC_SIZE);
-
-       if (cmd->req_len != sizeof *req)
-               return (EINVAL);
-       if (cmd->rpl_len != sizeof *rpl)
-               return (EINVAL);
-
-       mpi_init_sge(cm, req, &req->SGL);
-       if (cmd->len == 0) {
-               /* Perhaps just asking what the size of the fw is? */
-               return (0);
-       }
-
-       bzero(&tc, sizeof tc);
-
-       /*
-        * The value of the first two elements is specified in the
-        * Fusion-MPT Message Passing Interface document.
-        */
-       tc.ContextSize = 0;
-       tc.DetailsLength = 12;
-       /*
-        * XXX Is there any reason to fetch a partial image?  I.e. to
-        * set ImageOffset to something other than 0?
-        */
-       tc.ImageOffset = 0;
-       tc.ImageSize = cmd->len;
-
-       return (mps_push_sge(cm, &tc, sizeof tc, 0));
-}
-
-/*
- * Prepare the mps_command for a SATA_PASSTHROUGH request.
- */
-static int
-mpi_pre_sata_passthrough(struct mps_command *cm, struct mps_usr_command *cmd)
-{
-       MPI2_SATA_PASSTHROUGH_REQUEST *req = (void *)cm->cm_req;
-       MPI2_SATA_PASSTHROUGH_REPLY *rpl;
-
-       if (cmd->req_len != sizeof *req)
-               return (EINVAL);
-       if (cmd->rpl_len != sizeof *rpl)
-               return (EINVAL);
-
-       mpi_init_sge(cm, req, &req->SGL);
-       return (0);
-}
-
-/*
- * Prepare the mps_command for a SMP_PASSTHROUGH request.
- */
-static int
-mpi_pre_smp_passthrough(struct mps_command *cm, struct mps_usr_command *cmd)
-{
-       MPI2_SMP_PASSTHROUGH_REQUEST *req = (void *)cm->cm_req;
-       MPI2_SMP_PASSTHROUGH_REPLY *rpl;
-
-       if (cmd->req_len != sizeof *req)
-               return (EINVAL);
-       if (cmd->rpl_len != sizeof *rpl)
-               return (EINVAL);
-
-       mpi_init_sge(cm, req, &req->SGL);
-       return (0);
-}
-
-/*
- * Prepare the mps_command for a CONFIG request.
- */
-static int
-mpi_pre_config(struct mps_command *cm, struct mps_usr_command *cmd)
-{
-       MPI2_CONFIG_REQUEST *req = (void *)cm->cm_req;
-       MPI2_CONFIG_REPLY *rpl;
-
-       if (cmd->req_len != sizeof *req)
-               return (EINVAL);
-       if (cmd->rpl_len != sizeof *rpl)
-               return (EINVAL);
-
-       mpi_init_sge(cm, req, &req->PageBufferSGE);
-       return (0);
-}
-
-/*
- * Prepare the mps_command for a SAS_IO_UNIT_CONTROL request.
- */
-static int
-mpi_pre_sas_io_unit_control(struct mps_command *cm,
-                            struct mps_usr_command *cmd)
-{
-
-       cm->cm_sge = NULL;
-       cm->cm_sglsize = 0;
-       return (0);
-}
-
-/*
- * A set of functions to prepare an mps_command for the various
- * supported requests.
- */
-struct mps_user_func {
-       U8              Function;
-       mps_user_f      *f_pre;
-} mps_user_func_list[] = {
-       { MPI2_FUNCTION_IOC_FACTS,              mpi_pre_ioc_facts },
-       { MPI2_FUNCTION_PORT_FACTS,             mpi_pre_port_facts },
-       { MPI2_FUNCTION_FW_DOWNLOAD,            mpi_pre_fw_download },
-       { MPI2_FUNCTION_FW_UPLOAD,              mpi_pre_fw_upload },
-       { MPI2_FUNCTION_SATA_PASSTHROUGH,       mpi_pre_sata_passthrough },
-       { MPI2_FUNCTION_SMP_PASSTHROUGH,        mpi_pre_smp_passthrough},
-       { MPI2_FUNCTION_CONFIG,                 mpi_pre_config},
-       { MPI2_FUNCTION_SAS_IO_UNIT_CONTROL,    mpi_pre_sas_io_unit_control },
-       { 0xFF,                                 NULL } /* list end */
-};
-
-static int
-mps_user_setup_request(struct mps_command *cm, struct mps_usr_command *cmd)
-{
-       MPI2_REQUEST_HEADER *hdr = (MPI2_REQUEST_HEADER *)cm->cm_req;
-       struct mps_user_func *f;
-
-       for (f = mps_user_func_list; f->f_pre != NULL; f++) {
-               if (hdr->Function == f->Function)
-                       return (f->f_pre(cm, cmd));
-       }
-       return (EINVAL);
-}
-
-static int
-mps_user_command(struct mps_softc *sc, struct mps_usr_command *cmd)
-{
-       MPI2_REQUEST_HEADER *hdr;
-       MPI2_DEFAULT_REPLY *rpl;
-       void *buf = NULL;
-       struct mps_command *cm = NULL;
-       int err = 0;
-       int sz;
-
-       mps_lock(sc);
-       cm = mps_alloc_command(sc);
-
-       if (cm == NULL) {
-               mps_printf(sc, "mps_user_command: no mps requests\n");
-               err = ENOMEM;
-               goto Ret;
-       }
-       mps_unlock(sc);
-
-       hdr = (MPI2_REQUEST_HEADER *)cm->cm_req;
-
-       mps_dprint(sc, MPS_INFO, "mps_user_command: req %p %d  rpl %p %d\n",
-                   cmd->req, cmd->req_len, cmd->rpl, cmd->rpl_len );
-
-       if (cmd->req_len > (int)sc->facts->IOCRequestFrameSize * 4) {
-               err = EINVAL;
-               goto RetFreeUnlocked;
-       }
-       err = copyin(cmd->req, hdr, cmd->req_len);
-       if (err != 0)
-               goto RetFreeUnlocked;
-
-       mps_dprint(sc, MPS_INFO, "mps_user_command: Function %02X  "
-           "MsgFlags %02X\n", hdr->Function, hdr->MsgFlags );
-
-       err = mps_user_setup_request(cm, cmd);
-       if (err != 0) {
-               mps_printf(sc, "mps_user_command: unsupported function 0x%X\n",
-                   hdr->Function );
-               goto RetFreeUnlocked;
-       }
-
-       if (cmd->len > 0) {
-               buf = kmalloc(cmd->len, M_MPSUSER, M_WAITOK|M_ZERO);
-               cm->cm_data = buf;
-               cm->cm_length = cmd->len;
-       } else {
-               cm->cm_data = NULL;
-               cm->cm_length = 0;
-       }
-
-       cm->cm_flags = MPS_CM_FLAGS_SGE_SIMPLE | MPS_CM_FLAGS_WAKEUP;
-       cm->cm_desc.Default.RequestFlags = MPI2_REQ_DESCRIPT_FLAGS_DEFAULT_TYPE;
-
-       mps_lock(sc);
-       err = mps_map_command(sc, cm);
-
-       if (err != 0 && err != EINPROGRESS) {
-               mps_printf(sc, "%s: invalid request: error %d\n",
-                   __func__, err);
-               goto Ret;
-       }
-       lksleep(cm, &sc->mps_lock, 0, "mpsuser", 0);
-
-       rpl = (MPI2_DEFAULT_REPLY *)cm->cm_reply;
-       sz = rpl->MsgLength * 4;
-
-       if (sz > cmd->rpl_len) {
-               mps_printf(sc,
-                   "mps_user_command: reply buffer too small %d required %d\n",
-                   cmd->rpl_len, sz );
-               err = EINVAL;
-               sz = cmd->rpl_len;
-       }
-
-       mps_unlock(sc);
-       copyout(rpl, cmd->rpl, sz);
-       if (buf != NULL)
-               copyout(buf, cmd->buf, cmd->len);
-       mps_dprint(sc, MPS_INFO, "mps_user_command: reply size %d\n", sz );
-
-RetFreeUnlocked:
-       mps_lock(sc);
-       if (cm != NULL)
-               mps_free_command(sc, cm);
-Ret:
-       mps_unlock(sc);
-       if (buf != NULL)
-               kfree(buf, M_MPSUSER);
-       return (err);
-}
-
-static int
-mps_ioctl(struct cdev *dev, u_long cmd, void *arg, int flag)
-{
-       struct mps_softc *sc;
-       struct mps_cfg_page_req *page_req;
-       struct mps_ext_cfg_page_req *ext_page_req;
-       void *mps_page;
-       int error;
-
-       mps_page = NULL;
-       sc = dev->si_drv1;
-       page_req = (void *)arg;
-       ext_page_req = (void *)arg;
-
-       switch (cmd) {
-       case MPSIO_READ_CFG_HEADER:
-               mps_lock(sc);
-               error = mps_user_read_cfg_header(sc, page_req);
-               mps_unlock(sc);
-               break;
-       case MPSIO_READ_CFG_PAGE:
-               mps_page = kmalloc(page_req->len, M_MPSUSER, M_WAITOK | M_ZERO);
-               error = copyin(page_req->buf, mps_page,
-                   sizeof(MPI2_CONFIG_PAGE_HEADER));
-               if (error)
-                       break;
-               mps_lock(sc);
-               error = mps_user_read_cfg_page(sc, page_req, mps_page);
-               mps_unlock(sc);
-               if (error)
-                       break;
-               error = copyout(mps_page, page_req->buf, page_req->len);
-               break;
-       case MPSIO_READ_EXT_CFG_HEADER:
-               mps_lock(sc);
-               error = mps_user_read_extcfg_header(sc, ext_page_req);
-               mps_unlock(sc);
-               break;
-       case MPSIO_READ_EXT_CFG_PAGE:
-               mps_page = kmalloc(ext_page_req->len, M_MPSUSER, M_WAITOK|M_ZERO);
-               error = copyin(ext_page_req->buf, mps_page,
-                   sizeof(MPI2_CONFIG_EXTENDED_PAGE_HEADER));
-               if (error)
-                       break;
-               mps_lock(sc);
-               error = mps_user_read_extcfg_page(sc, ext_page_req, mps_page);
-               mps_unlock(sc);
-               if (error)
-                       break;
-               error = copyout(mps_page, ext_page_req->buf, ext_page_req->len);
-               break;
-       case MPSIO_WRITE_CFG_PAGE:
-               mps_page = kmalloc(page_req->len, M_MPSUSER, M_WAITOK|M_ZERO);
-               error = copyin(page_req->buf, mps_page, page_req->len);
-               if (error)
-                       break;
-               mps_lock(sc);
-               error = mps_user_write_cfg_page(sc, page_req, mps_page);
-               mps_unlock(sc);
-               break;
-       case MPSIO_MPS_COMMAND:
-               error = mps_user_command(sc, (struct mps_usr_command *)arg);
-               break;
-       default:
-               error = ENOIOCTL;
-               break;
-       }
-
-       if (mps_page != NULL)
-               kfree(mps_page, M_MPSUSER);
-
-       return (error);
-}
-
-#ifdef COMPAT_FREEBSD32
-
-/* Macros from compat/freebsd32/freebsd32.h */
-#define        PTRIN(v)        (void *)(uintptr_t)(v)
-#define        PTROUT(v)       (uint32_t)(uintptr_t)(v)
-
-#define        CP(src,dst,fld) do { (dst).fld = (src).fld; } while (0)
-#define        PTRIN_CP(src,dst,fld)                           \
-       do { (dst).fld = PTRIN((src).fld); } while (0)
-#define        PTROUT_CP(src,dst,fld) \
-       do { (dst).fld = PTROUT((src).fld); } while (0)
-
-struct mps_cfg_page_req32 {
-       MPI2_CONFIG_PAGE_HEADER header;
-       uint32_t page_address;
-       uint32_t buf;
-       int     len;
-       uint16_t ioc_status;
-};
-
-struct mps_ext_cfg_page_req32 {
-       MPI2_CONFIG_EXTENDED_PAGE_HEADER header;
-       uint32_t page_address;
-       uint32_t buf;
-       int     len;
-       uint16_t ioc_status;
-};
-
-struct mps_raid_action32 {
-       uint8_t action;
-       uint8_t volume_bus;
-       uint8_t volume_id;
-       uint8_t phys_disk_num;
-       uint32_t action_data_word;
-       uint32_t buf;
-       int len;
-       uint32_t volume_status;
-       uint32_t action_data[4];
-       uint16_t action_status;
-       uint16_t ioc_status;
-       uint8_t write;
-};
-
-struct mps_usr_command32 {
-       uint32_t req;
-       uint32_t req_len;
-       uint32_t rpl;
-       uint32_t rpl_len;
-       uint32_t buf;
-       int len;
-       uint32_t flags;
-};
-
-#define        MPSIO_READ_CFG_HEADER32 _IOWR('M', 200, struct mps_cfg_page_req32)
-#define        MPSIO_READ_CFG_PAGE32   _IOWR('M', 201, struct mps_cfg_page_req32)
-#define        MPSIO_READ_EXT_CFG_HEADER32 _IOWR('M', 202, struct mps_ext_cfg_page_req32)
-#define        MPSIO_READ_EXT_CFG_PAGE32 _IOWR('M', 203, struct mps_ext_cfg_page_req32)
-#define        MPSIO_WRITE_CFG_PAGE32  _IOWR('M', 204, struct mps_cfg_page_req32)
-#define        MPSIO_RAID_ACTION32     _IOWR('M', 205, struct mps_raid_action32)
-#define        MPSIO_MPS_COMMAND32     _IOWR('M', 210, struct mps_usr_command32)
-
-static int
-mps_ioctl32(struct cdev *dev, u_long cmd32, void *_arg, int flag,
-    struct thread *td)
-{
-       struct mps_cfg_page_req32 *page32 = _arg;
-       struct mps_ext_cfg_page_req32 *ext32 = _arg;
-       struct mps_raid_action32 *raid32 = _arg;
-       struct mps_usr_command32 *user32 = _arg;
-       union {
-               struct mps_cfg_page_req page;
-               struct mps_ext_cfg_page_req ext;
-               struct mps_raid_action raid;
-               struct mps_usr_command user;
-       } arg;
-       u_long cmd;
-       int error;
-
-       switch (cmd32) {
-       case MPSIO_READ_CFG_HEADER32:
-       case MPSIO_READ_CFG_PAGE32:
-       case MPSIO_WRITE_CFG_PAGE32:
-               if (cmd32 == MPSIO_READ_CFG_HEADER32)
-                       cmd = MPSIO_READ_CFG_HEADER;
-               else if (cmd32 == MPSIO_READ_CFG_PAGE32)
-                       cmd = MPSIO_READ_CFG_PAGE;
-               else
-                       cmd = MPSIO_WRITE_CFG_PAGE;
-               CP(*page32, arg.page, header);
-               CP(*page32, arg.page, page_address);
-               PTRIN_CP(*page32, arg.page, buf);
-               CP(*page32, arg.page, len);
-               CP(*page32, arg.page, ioc_status);
-               break;
-
-       case MPSIO_READ_EXT_CFG_HEADER32:
-       case MPSIO_READ_EXT_CFG_PAGE32:
-               if (cmd32 == MPSIO_READ_EXT_CFG_HEADER32)
-                       cmd = MPSIO_READ_EXT_CFG_HEADER;
-               else
-                       cmd = MPSIO_READ_EXT_CFG_PAGE;
-               CP(*ext32, arg.ext, header);
-               CP(*ext32, arg.ext, page_address);
-               PTRIN_CP(*ext32, arg.ext, buf);
-               CP(*ext32, arg.ext, len);
-               CP(*ext32, arg.ext, ioc_status);
-               break;
-
-       case MPSIO_RAID_ACTION32:
-               cmd = MPSIO_RAID_ACTION;
-               CP(*raid32, arg.raid, action);
-               CP(*raid32, arg.raid, volume_bus);
-               CP(*raid32, arg.raid, volume_id);
-               CP(*raid32, arg.raid, phys_disk_num);
-               CP(*raid32, arg.raid, action_data_word);
-               PTRIN_CP(*raid32, arg.raid, buf);
-               CP(*raid32, arg.raid, len);
-               CP(*raid32, arg.raid, volume_status);
-               bcopy(raid32->action_data, arg.raid.action_data,
-                   sizeof arg.raid.action_data);
-               CP(*raid32, arg.raid, ioc_status);
-               CP(*raid32, arg.raid, write);
-               break;
-
-       case MPSIO_MPS_COMMAND32:
-               cmd = MPSIO_MPS_COMMAND;
-               PTRIN_CP(*user32, arg.user, req);
-               CP(*user32, arg.user, req_len);
-               PTRIN_CP(*user32, arg.user, rpl);
-               CP(*user32, arg.user, rpl_len);
-               PTRIN_CP(*user32, arg.user, buf);
-               CP(*user32, arg.user, len);
-               CP(*user32, arg.user, flags);
-               break;
-       default:
-               return (ENOIOCTL);
-       }
-
-       error = mps_ioctl(dev, cmd, &arg, flag, td);
-       if (error == 0 && (cmd32 & IOC_OUT) != 0) {
-               switch (cmd32) {
-               case MPSIO_READ_CFG_HEADER32:
-               case MPSIO_READ_CFG_PAGE32:
-               case MPSIO_WRITE_CFG_PAGE32:
-                       CP(arg.page, *page32, header);
-                       CP(arg.page, *page32, page_address);
-                       PTROUT_CP(arg.page, *page32, buf);
-                       CP(arg.page, *page32, len);
-                       CP(arg.page, *page32, ioc_status);
-                       break;
-
-               case MPSIO_READ_EXT_CFG_HEADER32:
-               case MPSIO_READ_EXT_CFG_PAGE32:
-                       CP(arg.ext, *ext32, header);
-                       CP(arg.ext, *ext32, page_address);
-                       PTROUT_CP(arg.ext, *ext32, buf);
-                       CP(arg.ext, *ext32, len);
-                       CP(arg.ext, *ext32, ioc_status);
-                       break;
-
-               case MPSIO_RAID_ACTION32:
-                       CP(arg.raid, *raid32, action);
-                       CP(arg.raid, *raid32, volume_bus);
-                       CP(arg.raid, *raid32, volume_id);
-                       CP(arg.raid, *raid32, phys_disk_num);
-                       CP(arg.raid, *raid32, action_data_word);
-                       PTROUT_CP(arg.raid, *raid32, buf);
-                       CP(arg.raid, *raid32, len);
-                       CP(arg.raid, *raid32, volume_status);
-                       bcopy(arg.raid.action_data, raid32->action_data,
-                           sizeof arg.raid.action_data);
-                       CP(arg.raid, *raid32, ioc_status);
-                       CP(arg.raid, *raid32, write);
-                       break;
-
-               case MPSIO_MPS_COMMAND32:
-                       PTROUT_CP(arg.user, *user32, req);
-                       CP(arg.user, *user32, req_len);
-                       PTROUT_CP(arg.user, *user32, rpl);
-                       CP(arg.user, *user32, rpl_len);
-                       PTROUT_CP(arg.user, *user32, buf);
-                       CP(arg.user, *user32, len);
-                       CP(arg.user, *user32, flags);
-                       break;
-               }
-       }
-
-       return (error);
-}
-#endif /* COMPAT_FREEBSD32 */
-
-static int
-mps_ioctl_devsw(struct dev_ioctl_args *ap)
-{
-       cdev_t dev = ap->a_head.a_dev;
-       u_long com = ap->a_cmd;
-       caddr_t arg = ap->a_data;
-       int flag = ap->a_fflag;
-
-#ifdef COMPAT_FREEBSD32
-       if (SV_CURPROC_FLAG(SV_ILP32))
-               return (mps_ioctl32(dev, com, arg, flag, td));
-#endif
-       return (mps_ioctl(dev, com, arg, flag));
-}
diff --git a/sys/dev/disk/mps/mpsvar.h b/sys/dev/disk/mps/mpsvar.h
deleted file mode 100644 (file)
index b7461a3..0000000
+++ /dev/null
@@ -1,389 +0,0 @@
-/*-
- * Copyright (c) 2009 Yahoo! Inc.
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- *    notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- *    notice, this list of conditions and the following disclaimer in the
- *    documentation and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
- * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
- * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- *
- * $FreeBSD: src/sys/dev/mps/mpsvar.h,v 1.5 2010/12/10 21:45:10 ken Exp $
- */
-
-#ifndef _MPSVAR_H
-#define _MPSVAR_H
-
-#define MPS_DB_MAX_WAIT                2500
-
-#define MPS_REQ_FRAMES         1024
-#define MPS_EVT_REPLY_FRAMES   32
-#define MPS_REPLY_FRAMES       MPS_REQ_FRAMES
-#define MPS_CHAIN_FRAMES       1024
-#define MPS_SENSE_LEN          SSD_FULL_SIZE
-#define MPS_MSI_COUNT          1
-#define MPS_SGE64_SIZE         12
-#define MPS_SGE32_SIZE         8
-#define MPS_SGC_SIZE           8
-
-#define MPS_PERIODIC_DELAY     1       /* 1 second heartbeat/watchdog check */
-
-struct mps_softc;
-struct mps_command;
-struct mpssas_softc;
-struct mpssas_target;
-
-MALLOC_DECLARE(M_MPT2);
-
-typedef void mps_evt_callback_t(struct mps_softc *, uintptr_t,
-    MPI2_EVENT_NOTIFICATION_REPLY *reply);
-typedef void mps_command_callback_t(struct mps_softc *, struct mps_command *cm);
-
-struct mps_chain {
-       TAILQ_ENTRY(mps_chain)          chain_link;
-       MPI2_SGE_IO_UNION               *chain;
-       uint32_t                        chain_busaddr;
-};
-
-/*
- * This needs to be at least 2 to support SMP passthrough.
- */
-#define        MPS_IOVEC_COUNT 2
-
-struct mps_command {
-       TAILQ_ENTRY(mps_command)        cm_link;
-       struct mps_softc                *cm_sc;
-       void                            *cm_data;
-       u_int                           cm_length;
-       struct uio                      cm_uio;
-       struct iovec                    cm_iovec[MPS_IOVEC_COUNT];
-       u_int                           cm_max_segs;
-       u_int                           cm_sglsize;
-       MPI2_SGE_IO_UNION               *cm_sge;
-       uint8_t                         *cm_req;
-       uint8_t                         *cm_reply;
-       uint32_t                        cm_reply_data;
-       mps_command_callback_t          *cm_complete;
-       void                            *cm_complete_data;
-       struct mpssas_target            *cm_targ;
-       MPI2_REQUEST_DESCRIPTOR_UNION   cm_desc;
-       u_int                           cm_flags;
-#define MPS_CM_FLAGS_POLLED            (1 << 0)
-#define MPS_CM_FLAGS_COMPLETE          (1 << 1)
-#define MPS_CM_FLAGS_SGE_SIMPLE                (1 << 2)
-#define MPS_CM_FLAGS_DATAOUT           (1 << 3)
-#define MPS_CM_FLAGS_DATAIN            (1 << 4)
-#define MPS_CM_FLAGS_WAKEUP            (1 << 5)
-#define MPS_CM_FLAGS_ACTIVE            (1 << 6)
-#define MPS_CM_FLAGS_USE_UIO           (1 << 7)
-#define MPS_CM_FLAGS_SMP_PASS          (1 << 8)
-       u_int                           cm_state;
-#define MPS_CM_STATE_FREE              0
-#define MPS_CM_STATE_BUSY              1
-#define MPS_CM_STATE_TIMEDOUT          2
-       bus_dmamap_t                    cm_dmamap;
-       struct scsi_sense_data          *cm_sense;
-       TAILQ_HEAD(, mps_chain)         cm_chain_list;
-       uint32_t                        cm_req_busaddr;
-       uint32_t                        cm_sense_busaddr;
-       struct callout                  cm_callout;
-};
-
-struct mps_event_handle {
-       TAILQ_ENTRY(mps_event_handle)   eh_list;
-       mps_evt_callback_t              *callback;
-       void                            *data;
-       uint8_t                         mask[16];
-};
-
-struct mps_softc {
-       device_t                        mps_dev;
-       struct cdev                     *mps_cdev;
-       u_int                           mps_flags;
-#define MPS_FLAGS_INTX         (1 << 0)
-#define MPS_FLAGS_MSI          (1 << 1)
-#define MPS_FLAGS_BUSY         (1 << 2)
-#define MPS_FLAGS_SHUTDOWN     (1 << 3)
-       u_int                           mps_debug;
-       u_int                           allow_multiple_tm_cmds;
-       int                             tm_cmds_active;
-       struct sysctl_ctx_list          sysctl_ctx;
-       struct sysctl_oid               *sysctl_tree;
-       struct mps_command              *commands;
-       struct mps_chain                *chains;
-       struct callout                  periodic;
-
-       struct mpssas_softc             *sassc;
-
-       TAILQ_HEAD(, mps_command)       req_list;
-       TAILQ_HEAD(, mps_chain)         chain_list;
-       TAILQ_HEAD(, mps_command)       tm_list;
-       int                             replypostindex;
-       int                             replyfreeindex;
-
-       struct resource                 *mps_regs_resource;
-       bus_space_handle_t              mps_bhandle;
-       bus_space_tag_t                 mps_btag;
-       int                             mps_regs_rid;
-
-       bus_dma_tag_t                   mps_parent_dmat;
-       bus_dma_tag_t                   buffer_dmat;
-
-       MPI2_IOC_FACTS_REPLY            *facts;
-       MPI2_PORT_FACTS_REPLY           *pfacts;
-       int                             num_reqs;
-       int                             num_replies;
-       int                             fqdepth;        /* Free queue */
-       int                             pqdepth;        /* Post queue */
-
-       uint8_t                         event_mask[16];
-       TAILQ_HEAD(, mps_event_handle)  event_list;
-       struct mps_event_handle         *mps_log_eh;
-
-       struct lock                     mps_lock;
-       struct intr_config_hook         mps_ich;
-       struct resource                 *mps_irq[MPS_MSI_COUNT];
-       void                            *mps_intrhand[MPS_MSI_COUNT];
-       int                             mps_irq_rid[MPS_MSI_COUNT];
-
-       uint8_t                         *req_frames;
-       bus_addr_t                      req_busaddr;
-       bus_dma_tag_t                   req_dmat;
-       bus_dmamap_t                    req_map;
-
-       uint8_t                         *reply_frames;
-       bus_addr_t                      reply_busaddr;
-       bus_dma_tag_t                   reply_dmat;
-       bus_dmamap_t                    reply_map;
-
-       struct scsi_sense_data          *sense_frames;
-       bus_addr_t                      sense_busaddr;
-       bus_dma_tag_t                   sense_dmat;
-       bus_dmamap_t                    sense_map;
-
-       uint8_t                         *chain_frames;
-       bus_addr_t                      chain_busaddr;
-       bus_dma_tag_t                   chain_dmat;
-       bus_dmamap_t                    chain_map;
-
-       MPI2_REPLY_DESCRIPTORS_UNION    *post_queue;
-       bus_addr_t                      post_busaddr;
-       uint32_t                        *free_queue;
-       bus_addr_t                      free_busaddr;
-       bus_dma_tag_t                   queues_dmat;
-       bus_dmamap_t                    queues_map;
-};
-
-struct mps_config_params {
-       MPI2_CONFIG_EXT_PAGE_HEADER_UNION       hdr;
-       u_int           action;
-       u_int           page_address;   /* Attributes, not a phys address */
-       u_int           status;
-       void            *buffer;
-       u_int           length;
-       int             timeout;
-       void            (*callback)(struct mps_softc *, struct mps_config_params *);
-       void            *cbdata;
-};
-
-static __inline uint32_t
-mps_regread(struct mps_softc *sc, uint32_t offset)
-{
-       return (bus_space_read_4(sc->mps_btag, sc->mps_bhandle, offset));
-}
-
-static __inline void
-mps_regwrite(struct mps_softc *sc, uint32_t offset, uint32_t val)
-{
-       bus_space_write_4(sc->mps_btag, sc->mps_bhandle, offset, val);
-}
-
-static __inline void
-mps_free_reply(struct mps_softc *sc, uint32_t busaddr)
-{
-
-       if (++sc->replyfreeindex >= sc->fqdepth)
-               sc->replyfreeindex = 0;
-       sc->free_queue[sc->replyfreeindex] = busaddr;
-       mps_regwrite(sc, MPI2_REPLY_FREE_HOST_INDEX_OFFSET, sc->replyfreeindex);
-}
-
-static __inline struct mps_chain *
-mps_alloc_chain(struct mps_softc *sc)
-{
-       struct mps_chain *chain;
-
-       if ((chain = TAILQ_FIRST(&sc->chain_list)) != NULL)
-               TAILQ_REMOVE(&sc->chain_list, chain, chain_link);
-       return (chain);
-}
-
-static __inline void
-mps_free_chain(struct mps_softc *sc, struct mps_chain *chain)
-{
-#if 0
-       bzero(chain->chain, 128);
-#endif
-       TAILQ_INSERT_TAIL(&sc->chain_list, chain, chain_link);
-}
-
-static __inline void
-mps_free_command(struct mps_softc *sc, struct mps_command *cm)
-{
-       struct mps_chain *chain, *chain_temp;
-
-       if (cm->cm_reply != NULL) {
-               mps_free_reply(sc, cm->cm_reply_data);
-               cm->cm_reply = NULL;
-       }
-       cm->cm_flags = 0;
-       cm->cm_complete = NULL;
-       cm->cm_complete_data = NULL;
-       cm->cm_targ = 0;
-       cm->cm_max_segs = 0;
-       cm->cm_state = MPS_CM_STATE_FREE;
-       TAILQ_FOREACH_MUTABLE(chain, &cm->cm_chain_list, chain_link, chain_temp) {
-               TAILQ_REMOVE(&cm->cm_chain_list, chain, chain_link);
-               mps_free_chain(sc, chain);
-       }
-       TAILQ_INSERT_TAIL(&sc->req_list, cm, cm_link);
-}
-
-static __inline struct mps_command *
-mps_alloc_command(struct mps_softc *sc)
-{
-       struct mps_command *cm;
-
-       cm = TAILQ_FIRST(&sc->req_list);
-       if (cm == NULL)
-               return (NULL);
-
-       TAILQ_REMOVE(&sc->req_list, cm, cm_link);
-       KASSERT(cm->cm_state == MPS_CM_STATE_FREE, ("mps: Allocating busy command\n"));
-       cm->cm_state = MPS_CM_STATE_BUSY;
-       return (cm);
-}
-
-static __inline void
-mps_lock(struct mps_softc *sc)
-{
-       lockmgr(&sc->mps_lock, LK_EXCLUSIVE);
-}
-
-static __inline void
-mps_unlock(struct mps_softc *sc)
-{
-       lockmgr(&sc->mps_lock, LK_RELEASE);
-}
-
-#define MPS_INFO       (1 << 0)
-#define MPS_TRACE      (1 << 1)
-#define MPS_FAULT      (1 << 2)
-#define MPS_EVENT      (1 << 3)
-#define MPS_LOG                (1 << 4)
-
-#define mps_printf(sc, args...)                                \
-       device_printf((sc)->mps_dev, ##args)
-
-#define mps_dprint(sc, level, msg, args...)            \
-do {                                                   \
-       if (sc->mps_debug & level)                      \
-               device_printf(sc->mps_dev, msg, ##args);        \
-} while (0)
-
-#define mps_dprint_field(sc, level, msg, args...)              \
-do {                                                           \
-       if (sc->mps_debug & level)                              \
-               kprintf("\t" msg, ##args);                      \
-} while (0)
-
-#define MPS_PRINTFIELD_START(sc, tag...)       \
-       mps_dprint((sc), MPS_INFO, ##tag);      \
-       mps_dprint_field((sc), MPS_INFO, ":\n")
-#define MPS_PRINTFIELD_END(sc, tag)            \
-       mps_dprint((sc), MPS_INFO, tag "\n")
-#define MPS_PRINTFIELD(sc, facts, attr, fmt)   \
-       mps_dprint_field((sc), MPS_INFO, #attr ": " #fmt "\n", (facts)->attr)
-
-#define MPS_EVENTFIELD_START(sc, tag...)       \
-       mps_dprint((sc), MPS_EVENT, ##tag);     \
-       mps_dprint_field((sc), MPS_EVENT, ":\n")
-#define MPS_EVENTFIELD(sc, facts, attr, fmt)   \
-       mps_dprint_field((sc), MPS_EVENT, #attr ": " #fmt "\n", (facts)->attr)
-
-static __inline void
-mps_from_u64(uint64_t data, U64 *mps)
-{
-       (mps)->High = (uint32_t)((data) >> 32);
-       (mps)->Low = (uint32_t)((data) & 0xffffffff);
-}
-
-static __inline uint64_t
-mps_to_u64(U64 *data)
-{
-
-       return (((uint64_t)data->High << 32) | data->Low);
-}
-
-static __inline void
-mps_mask_intr(struct mps_softc *sc)
-{
-       uint32_t mask;
-
-       mask = mps_regread(sc, MPI2_HOST_INTERRUPT_MASK_OFFSET);
-       mask |= MPI2_HIM_REPLY_INT_MASK;
-       mps_regwrite(sc, MPI2_HOST_INTERRUPT_MASK_OFFSET, mask);
-}
-
-static __inline void
-mps_unmask_intr(struct mps_softc *sc)
-{
-       uint32_t mask;
-
-       mask = mps_regread(sc, MPI2_HOST_INTERRUPT_MASK_OFFSET);
-       mask &= ~MPI2_HIM_REPLY_INT_MASK;
-       mps_regwrite(sc, MPI2_HOST_INTERRUPT_MASK_OFFSET, mask);
-}
-
-int mps_pci_setup_interrupts(struct mps_softc *);
-int mps_attach(struct mps_softc *sc);
-int mps_free(struct mps_softc *sc);
-void mps_intr(void *);
-void mps_intr_msi(void *);
-void mps_intr_locked(void *);
-int mps_register_events(struct mps_softc *, uint8_t *, mps_evt_callback_t *,
-    void *, struct mps_event_handle **);
-int mps_update_events(struct mps_softc *, struct mps_event_handle *, uint8_t *);
-int mps_deregister_events(struct mps_softc *, struct mps_event_handle *);
-int mps_request_polled(struct mps_softc *sc, struct mps_command *cm);
-void mps_enqueue_request(struct mps_softc *, struct mps_command *);
-int mps_push_sge(struct mps_command *, void *, size_t, int);
-int mps_add_dmaseg(struct mps_command *, vm_paddr_t, size_t, u_int, int);
-int mps_attach_sas(struct mps_softc *sc);
-int mps_detach_sas(struct mps_softc *sc);
-int mps_map_command(struct mps_softc *sc, struct mps_command *cm);
-int mps_read_config_page(struct mps_softc *, struct mps_config_params *);
-int mps_write_config_page(struct mps_softc *, struct mps_config_params *);
-void mps_memaddr_cb(void *, bus_dma_segment_t *, int , int );
-void mpi_init_sge(struct mps_command *cm, void *req, void *sge);
-int mps_attach_user(struct mps_softc *);
-void mps_detach_user(struct mps_softc *);
-
-SYSCTL_DECL(_hw_mps);
-
-#endif
index 3ce204e..44461cd 100644 (file)
@@ -1,4 +1,4 @@
 SUBDIR=        aac amr arcmsr asr ciss hptiop hptmv \
-       iir ips mfi mlx mly pst twa twe tws vinum
+       iir ips mfi mlx mly mps pst twa twe tws vinum
 
 .include <bsd.subdir.mk>
diff --git a/sys/dev/raid/mps/Makefile b/sys/dev/raid/mps/Makefile
new file mode 100644 (file)
index 0000000..57e8bb6
--- /dev/null
@@ -0,0 +1,14 @@
+# $FreeBSD: src/sys/modules/mps/Makefile,v 1.4 2012/01/26 18:17:21 ken Exp $
+
+.PATH: ${.CURDIR}/../../dev/mps
+
+KMOD=  mps
+SRCS=  mps_pci.c mps.c mps_sas.c mps_table.c mps_user.c
+SRCS+= mps_config.c mps_mapping.c mps_sas_lsi.c
+SRCS+= opt_cam.h opt_compat.h
+SRCS+= device_if.h bus_if.h pci_if.h
+
+#CFLAGS += -DMPS_DEBUG
+DEBUG_FLAGS += -g
+
+.include <bsd.kmod.mk>
similarity index 94%
rename from sys/dev/disk/mps/mpi/mpi2.h
rename to sys/dev/raid/mps/mpi/mpi2.h
index e336234..4196be7 100644 (file)
@@ -1,6 +1,35 @@
-/* $FreeBSD: src/sys/dev/mps/mpi/mpi2.h,v 1.1 2010/09/10 15:03:56 ken Exp $ */
+/*-
+ * Copyright (c) 2011 LSI Corp.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * LSI MPT-Fusion Host Adapter FreeBSD
+ *
+ * $FreeBSD: src/sys/dev/mps/mpi/mpi2.h,v 1.2 2012/01/26 18:17:21 ken Exp $
+ */
+
 /*
- *  Copyright (c) 2000-2009 LSI Corporation.
+ *  Copyright (c) 2000-2011 LSI Corporation.
  *
  *
  *           Name:  mpi2.h
@@ -9,7 +38,7 @@
  *                  scatter/gather formats.
  *  Creation Date:  June 21, 2006
  *
- *  mpi2.h Version:  02.00.14
+ *  mpi2.h Version:  02.00.18
  *
  *  Version History
  *  ---------------
  *                      Added MSI-x index mask and shift for Reply Post Host
  *                      Index register.
  *                      Added function code for Host Based Discovery Action.
+ *  02-10-10  02.00.15  Bumped MPI2_HEADER_VERSION_UNIT.
+ *                      Added define for MPI2_FUNCTION_PWR_MGMT_CONTROL.
+ *                      Added defines for product-specific range of message
+ *                      function codes, 0xF0 to 0xFF.
+ *  05-12-10  02.00.16  Bumped MPI2_HEADER_VERSION_UNIT.
+ *                      Added alternative defines for the SGE Direction bit.
+ *  08-11-10  02.00.17  Bumped MPI2_HEADER_VERSION_UNIT.
+ *  11-10-10  02.00.18  Bumped MPI2_HEADER_VERSION_UNIT.
+ *                      Added MPI2_IEEE_SGE_FLAGS_SYSTEMPLBCPI_ADDR define.
  *  --------------------------------------------------------------------------
  */
 
 #define MPI2_VERSION_02_00                  (0x0200)
 
 /* versioning for this MPI header set */
-#define MPI2_HEADER_VERSION_UNIT            (0x0E)
+#define MPI2_HEADER_VERSION_UNIT            (0x12)
 #define MPI2_HEADER_VERSION_DEV             (0x00)
 #define MPI2_HEADER_VERSION_UNIT_MASK       (0xFF00)
 #define MPI2_HEADER_VERSION_UNIT_SHIFT      (8)
@@ -476,8 +514,6 @@ typedef union _MPI2_REPLY_DESCRIPTORS_UNION
 /*****************************************************************************
 *
 *        Message Functions
-*              0x80 -> 0x8F reserved for private message use per product
-*
 *
 *****************************************************************************/
 
@@ -508,6 +544,9 @@ typedef union _MPI2_REPLY_DESCRIPTORS_UNION
 #define MPI2_FUNCTION_TARGET_CMD_BUF_LIST_POST      (0x25) /* Target Command Buffer Post List */
 #define MPI2_FUNCTION_RAID_ACCELERATOR              (0x2C) /* RAID Accelerator */
 #define MPI2_FUNCTION_HOST_BASED_DISCOVERY_ACTION   (0x2F) /* Host Based Discovery Action */
+#define MPI2_FUNCTION_PWR_MGMT_CONTROL              (0x30) /* Power Management Control */
+#define MPI2_FUNCTION_MIN_PRODUCT_SPECIFIC          (0xF0) /* beginning of product-specific range */
+#define MPI2_FUNCTION_MAX_PRODUCT_SPECIFIC          (0xFF) /* end of product-specific range */
 
 
 
@@ -922,6 +961,9 @@ typedef struct _MPI2_MPI_SGE_UNION
 #define MPI2_SGE_FLAGS_IOC_TO_HOST              (0x00)
 #define MPI2_SGE_FLAGS_HOST_TO_IOC              (0x04)
 
+#define MPI2_SGE_FLAGS_DEST                     (MPI2_SGE_FLAGS_IOC_TO_HOST)
+#define MPI2_SGE_FLAGS_SOURCE                   (MPI2_SGE_FLAGS_HOST_TO_IOC)
+
 /* Address Size */
 
 #define MPI2_SGE_FLAGS_32_BIT_ADDRESSING        (0x00)
@@ -1046,11 +1088,11 @@ typedef struct _MPI2_IEEE_SGE_UNION
 /* Data Location Address Space */
 
 #define MPI2_IEEE_SGE_FLAGS_ADDR_MASK           (0x03)
-#define MPI2_IEEE_SGE_FLAGS_SYSTEM_ADDR         (0x00)
-#define MPI2_IEEE_SGE_FLAGS_IOCDDR_ADDR         (0x01)
+#define MPI2_IEEE_SGE_FLAGS_SYSTEM_ADDR         (0x00) /* IEEE Simple Element only */
+#define MPI2_IEEE_SGE_FLAGS_IOCDDR_ADDR         (0x01) /* IEEE Simple Element only */
 #define MPI2_IEEE_SGE_FLAGS_IOCPLB_ADDR         (0x02)
-#define MPI2_IEEE_SGE_FLAGS_IOCPLBNTA_ADDR      (0x03)
-
+#define MPI2_IEEE_SGE_FLAGS_IOCPLBNTA_ADDR      (0x03) /* IEEE Simple Element only */
+#define MPI2_IEEE_SGE_FLAGS_SYSTEMPLBCPI_ADDR   (0x03) /* IEEE Chain Element only */
 
 /****************************************************************************
 *  IEEE SGE operation Macros
similarity index 90%
rename from sys/dev/disk/mps/mpi/mpi2_cnfg.h
rename to sys/dev/raid/mps/mpi/mpi2_cnfg.h
index 7c7ba2f..fc0f6d8 100644 (file)
@@ -1,13 +1,42 @@
-/* $FreeBSD: src/sys/dev/mps/mpi/mpi2_cnfg.h,v 1.1 2010/09/10 15:03:56 ken Exp $ */
+/*-
+ * Copyright (c) 2011 LSI Corp.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * LSI MPT-Fusion Host Adapter FreeBSD
+ *
+ * $FreeBSD: src/sys/dev/mps/mpi/mpi2_cnfg.h,v 1.2 2012/01/26 18:17:21 ken Exp $
+ */
+
 /*
- *  Copyright (c) 2000-2009 LSI Corporation.
+ *  Copyright (c) 2000-2011 LSI Corporation.
  *
  *
  *           Name:  mpi2_cnfg.h
  *          Title:  MPI Configuration messages and pages
  *  Creation Date:  November 10, 2006
  *
- *    mpi2_cnfg.h Version:  02.00.13
+ *    mpi2_cnfg.h Version:  02.00.17
  *
  *  Version History
  *  ---------------
  *                      Added Ethernet configuration pages.
  *  10-28-09  02.00.13  Added MPI2_IOUNITPAGE1_ENABLE_HOST_BASED_DISCOVERY.
  *                      Added SAS PHY Page 4 structure and defines.
+ *  02-10-10  02.00.14  Modified the comments for the configuration page
+ *                      structures that contain an array of data. The host
+ *                      should use the "count" field in the page data (e.g. the
+ *                      NumPhys field) to determine the number of valid elements
+ *                      in the array.
+ *                      Added/modified some MPI2_MFGPAGE_DEVID_SAS defines.
+ *                      Added PowerManagementCapabilities to IO Unit Page 7.
+ *                      Added PortWidthModGroup field to
+ *                      MPI2_SAS_IO_UNIT5_PHY_PM_SETTINGS.
+ *                      Added MPI2_CONFIG_PAGE_SASIOUNIT_6 and related defines.
+ *                      Added MPI2_CONFIG_PAGE_SASIOUNIT_7 and related defines.
+ *                      Added MPI2_CONFIG_PAGE_SASIOUNIT_8 and related defines.
+ *  05-12-10  02.00.15  Added MPI2_RAIDVOL0_STATUS_FLAG_VOL_NOT_CONSISTENT
+ *                      define.
+ *                      Added MPI2_PHYSDISK0_INCOMPATIBLE_MEDIA_TYPE define.
+ *                      Added MPI2_SAS_NEG_LINK_RATE_UNSUPPORTED_PHY define.
+ *  08-11-10  02.00.16  Removed IO Unit Page 1 device path (multi-pathing)
+ *                      defines.
+ *  11-10-10  02.00.17  Added ReceptacleID field (replacing Reserved1) to
+ *                      MPI2_MANPAGE7_CONNECTOR_INFO and reworked defines for
+ *                      the Pinout field.
+ *                      Added BoardTemperature and BoardTemperatureUnits fields
+ *                      to MPI2_CONFIG_PAGE_IO_UNIT_7.
+ *                      Added MPI2_CONFIG_EXTPAGETYPE_EXT_MANUFACTURING define
+ *                      and MPI2_CONFIG_PAGE_EXT_MAN_PS structure.
  *  --------------------------------------------------------------------------
  */
 
@@ -193,6 +247,7 @@ typedef union _MPI2_CONFIG_EXT_PAGE_HEADER_UNION
 #define MPI2_CONFIG_EXTPAGETYPE_DRIVER_MAPPING      (0x17)
 #define MPI2_CONFIG_EXTPAGETYPE_SAS_PORT            (0x18)
 #define MPI2_CONFIG_EXTPAGETYPE_ETHERNET            (0x19)
+#define MPI2_CONFIG_EXTPAGETYPE_EXT_MANUFACTURING   (0x1A)
 
 
 /*****************************************************************************
@@ -322,7 +377,7 @@ typedef struct _MPI2_CONFIG_REQUEST
 #define MPI2_CONFIG_ACTION_PAGE_READ_NVRAM          (0x06)
 #define MPI2_CONFIG_ACTION_PAGE_GET_CHANGEABLE      (0x07)
 
-/* values for SGLFlags field are in the SGL section of mpi2.h */
+/* use MPI2_SGLFLAGS_ defines from mpi2.h for the SGLFlags field */
 
 
 /* Config Reply Message */
@@ -368,14 +423,19 @@ typedef struct _MPI2_CONFIG_REPLY
 #define MPI2_MFGPAGE_DEVID_SAS2116_1                (0x0064)
 #define MPI2_MFGPAGE_DEVID_SAS2116_2                (0x0065)
 
+#define MPI2_MFGPAGE_DEVID_SSS6200                  (0x007E)
+
 #define MPI2_MFGPAGE_DEVID_SAS2208_1                (0x0080)
 #define MPI2_MFGPAGE_DEVID_SAS2208_2                (0x0081)
 #define MPI2_MFGPAGE_DEVID_SAS2208_3                (0x0082)
 #define MPI2_MFGPAGE_DEVID_SAS2208_4                (0x0083)
 #define MPI2_MFGPAGE_DEVID_SAS2208_5                (0x0084)
 #define MPI2_MFGPAGE_DEVID_SAS2208_6                (0x0085)
-#define MPI2_MFGPAGE_DEVID_SAS2208_7                (0x0086)
-#define MPI2_MFGPAGE_DEVID_SAS2208_8                (0x0087)
+#define MPI2_MFGPAGE_DEVID_SAS2308_1                (0x0086)
+#define MPI2_MFGPAGE_DEVID_SAS2308_2                (0x0087)
+#define MPI2_MFGPAGE_DEVID_SAS2308_3                (0x006E)
+
+
 
 
 /* Manufacturing Page 0 */
@@ -541,7 +601,7 @@ typedef struct _MPI2_CONFIG_PAGE_MAN_4
 
 /*
  * Host code (drivers, BIOS, utilities, etc.) should leave this define set to
- * one and check Header.PageLength or NumPhys at runtime.
+ * one and check the value returned for NumPhys at runtime.
  */
 #ifndef MPI2_MAN_PAGE_5_PHY_ENTRIES
 #define MPI2_MAN_PAGE_5_PHY_ENTRIES         (1)
@@ -590,23 +650,31 @@ typedef struct _MPI2_MANPAGE7_CONNECTOR_INFO
     U32                         Pinout;                 /* 0x00 */
     U8                          Connector[16];          /* 0x04 */
     U8                          Location;               /* 0x14 */
-    U8                          Reserved1;              /* 0x15 */
+    U8                          ReceptacleID;           /* 0x15 */
     U16                         Slot;                   /* 0x16 */
     U32                         Reserved2;              /* 0x18 */
 } MPI2_MANPAGE7_CONNECTOR_INFO, MPI2_POINTER PTR_MPI2_MANPAGE7_CONNECTOR_INFO,
   Mpi2ManPage7ConnectorInfo_t, MPI2_POINTER pMpi2ManPage7ConnectorInfo_t;
 
 /* defines for the Pinout field */
-#define MPI2_MANPAGE7_PINOUT_SFF_8484_L4                (0x00080000)
-#define MPI2_MANPAGE7_PINOUT_SFF_8484_L3                (0x00040000)
-#define MPI2_MANPAGE7_PINOUT_SFF_8484_L2                (0x00020000)
-#define MPI2_MANPAGE7_PINOUT_SFF_8484_L1                (0x00010000)
-#define MPI2_MANPAGE7_PINOUT_SFF_8470_L4                (0x00000800)
-#define MPI2_MANPAGE7_PINOUT_SFF_8470_L3                (0x00000400)
-#define MPI2_MANPAGE7_PINOUT_SFF_8470_L2                (0x00000200)
-#define MPI2_MANPAGE7_PINOUT_SFF_8470_L1                (0x00000100)
-#define MPI2_MANPAGE7_PINOUT_SFF_8482                   (0x00000002)
-#define MPI2_MANPAGE7_PINOUT_CONNECTION_UNKNOWN         (0x00000001)
+#define MPI2_MANPAGE7_PINOUT_LANE_MASK                  (0x0000FF00)
+#define MPI2_MANPAGE7_PINOUT_LANE_SHIFT                 (8)
+
+#define MPI2_MANPAGE7_PINOUT_TYPE_MASK                  (0x000000FF)
+#define MPI2_MANPAGE7_PINOUT_TYPE_UNKNOWN               (0x00)
+#define MPI2_MANPAGE7_PINOUT_SATA_SINGLE                (0x01)
+#define MPI2_MANPAGE7_PINOUT_SFF_8482                   (0x02)
+#define MPI2_MANPAGE7_PINOUT_SFF_8486                   (0x03)
+#define MPI2_MANPAGE7_PINOUT_SFF_8484                   (0x04)
+#define MPI2_MANPAGE7_PINOUT_SFF_8087                   (0x05)
+#define MPI2_MANPAGE7_PINOUT_SFF_8643_4I                (0x06)
+#define MPI2_MANPAGE7_PINOUT_SFF_8643_8I                (0x07)
+#define MPI2_MANPAGE7_PINOUT_SFF_8470                   (0x08)
+#define MPI2_MANPAGE7_PINOUT_SFF_8088                   (0x09)
+#define MPI2_MANPAGE7_PINOUT_SFF_8644_4X                (0x0A)
+#define MPI2_MANPAGE7_PINOUT_SFF_8644_8X                (0x0B)
+#define MPI2_MANPAGE7_PINOUT_SFF_8644_16X               (0x0C)
+#define MPI2_MANPAGE7_PINOUT_SFF_8436                   (0x0D)
 
 /* defines for the Location field */
 #define MPI2_MANPAGE7_LOCATION_UNKNOWN                  (0x01)
@@ -619,7 +687,7 @@ typedef struct _MPI2_MANPAGE7_CONNECTOR_INFO
 
 /*
  * Host code (drivers, BIOS, utilities, etc.) should leave this define set to
- * one and check NumPhys at runtime.
+ * one and check the value returned for NumPhys at runtime.
  */
 #ifndef MPI2_MANPAGE7_CONNECTOR_INFO_MAX
 #define MPI2_MANPAGE7_CONNECTOR_INFO_MAX  (1)
@@ -640,7 +708,7 @@ typedef struct _MPI2_CONFIG_PAGE_MAN_7
   MPI2_POINTER PTR_MPI2_CONFIG_PAGE_MAN_7,
   Mpi2ManufacturingPage7_t, MPI2_POINTER pMpi2ManufacturingPage7_t;
 
-#define MPI2_MANUFACTURING7_PAGEVERSION                 (0x00)
+#define MPI2_MANUFACTURING7_PAGEVERSION                 (0x01)
 
 /* defines for the Flags field */
 #define MPI2_MANPAGE7_FLAG_USE_SLOT_INFO                (0x00000001)
@@ -717,6 +785,7 @@ typedef struct _MPI2_CONFIG_PAGE_IO_UNIT_1
 /* IO Unit Page 1 Flags defines */
 #define MPI2_IOUNITPAGE1_ENABLE_HOST_BASED_DISCOVERY    (0x00000800)
 #define MPI2_IOUNITPAGE1_MASK_SATA_WRITE_CACHE          (0x00000600)
+#define MPI2_IOUNITPAGE1_SATA_WRITE_CACHE_SHIFT         (9)
 #define MPI2_IOUNITPAGE1_ENABLE_SATA_WRITE_CACHE        (0x00000000)
 #define MPI2_IOUNITPAGE1_DISABLE_SATA_WRITE_CACHE       (0x00000200)
 #define MPI2_IOUNITPAGE1_UNCHANGED_SATA_WRITE_CACHE     (0x00000400)
@@ -724,15 +793,13 @@ typedef struct _MPI2_CONFIG_PAGE_IO_UNIT_1
 #define MPI2_IOUNITPAGE1_DISABLE_IR                     (0x00000040)
 #define MPI2_IOUNITPAGE1_DISABLE_TASK_SET_FULL_HANDLING (0x00000020)
 #define MPI2_IOUNITPAGE1_IR_USE_STATIC_VOLUME_ID        (0x00000004)
-#define MPI2_IOUNITPAGE1_MULTI_PATHING                  (0x00000002)
-#define MPI2_IOUNITPAGE1_SINGLE_PATHING                 (0x00000000)
 
 
 /* IO Unit Page 3 */
 
 /*
  * Host code (drivers, BIOS, utilities, etc.) should leave this define set to
- * one and check Header.PageLength at runtime.
+ * one and check the value returned for GPIOCount at runtime.
  */
 #ifndef MPI2_IO_UNIT_PAGE_3_GPIO_VAL_MAX
 #define MPI2_IO_UNIT_PAGE_3_GPIO_VAL_MAX    (1)
@@ -761,7 +828,7 @@ typedef struct _MPI2_CONFIG_PAGE_IO_UNIT_3
 
 /*
  * Upper layer code (drivers, utilities, etc.) should leave this define set to
- * one and check Header.PageLength or NumDmaEngines at runtime.
+ * one and check the value returned for NumDmaEngines at runtime.
  */
 #ifndef MPI2_IOUNITPAGE5_DMAENGINE_ENTRIES
 #define MPI2_IOUNITPAGE5_DMAENGINE_ENTRIES      (1)
@@ -826,15 +893,17 @@ typedef struct _MPI2_CONFIG_PAGE_IO_UNIT_7
     U8                      PCIeWidth;                              /* 0x06 */
     U8                      PCIeSpeed;                              /* 0x07 */
     U32                     ProcessorState;                         /* 0x08 */
-    U32                     Reserved2;                              /* 0x0C */
+    U32                     PowerManagementCapabilities;            /* 0x0C */
     U16                     IOCTemperature;                         /* 0x10 */
     U8                      IOCTemperatureUnits;                    /* 0x12 */
     U8                      IOCSpeed;                               /* 0x13 */
-    U32                     Reserved3;                              /* 0x14 */
+    U16                     BoardTemperature;                       /* 0x14 */
+    U8                      BoardTemperatureUnits;                  /* 0x16 */
+    U8                      Reserved3;                              /* 0x17 */
 } MPI2_CONFIG_PAGE_IO_UNIT_7, MPI2_POINTER PTR_MPI2_CONFIG_PAGE_IO_UNIT_7,
   Mpi2IOUnitPage7_t, MPI2_POINTER pMpi2IOUnitPage7_t;
 
-#define MPI2_IOUNITPAGE7_PAGEVERSION                    (0x00)
+#define MPI2_IOUNITPAGE7_PAGEVERSION                    (0x02)
 
 /* defines for IO Unit Page 7 PCIeWidth field */
 #define MPI2_IOUNITPAGE7_PCIE_WIDTH_X1              (0x01)
@@ -855,6 +924,13 @@ typedef struct _MPI2_CONFIG_PAGE_IO_UNIT_7
 #define MPI2_IOUNITPAGE7_PSTATE_DISABLED            (0x01)
 #define MPI2_IOUNITPAGE7_PSTATE_ENABLED             (0x02)
 
+/* defines for IO Unit Page 7 PowerManagementCapabilities field */
+#define MPI2_IOUNITPAGE7_PMCAP_12_5_PCT_IOCSPEED    (0x00000400)
+#define MPI2_IOUNITPAGE7_PMCAP_25_0_PCT_IOCSPEED    (0x00000200)
+#define MPI2_IOUNITPAGE7_PMCAP_50_0_PCT_IOCSPEED    (0x00000100)
+#define MPI2_IOUNITPAGE7_PMCAP_PCIE_WIDTH_CHANGE    (0x00000008)
+#define MPI2_IOUNITPAGE7_PMCAP_PCIE_SPEED_CHANGE    (0x00000004)
+
 /* defines for IO Unit Page 7 IOCTemperatureUnits field */
 #define MPI2_IOUNITPAGE7_IOC_TEMP_NOT_PRESENT       (0x00)
 #define MPI2_IOUNITPAGE7_IOC_TEMP_FAHRENHEIT        (0x01)
@@ -866,6 +942,11 @@ typedef struct _MPI2_CONFIG_PAGE_IO_UNIT_7
 #define MPI2_IOUNITPAGE7_IOC_SPEED_QUARTER          (0x04)
 #define MPI2_IOUNITPAGE7_IOC_SPEED_EIGHTH           (0x08)
 
+/* defines for IO Unit Page 7 BoardTemperatureUnits field */
+#define MPI2_IOUNITPAGE7_BOARD_TEMP_NOT_PRESENT     (0x00)
+#define MPI2_IOUNITPAGE7_BOARD_TEMP_FAHRENHEIT      (0x01)
+#define MPI2_IOUNITPAGE7_BOARD_TEMP_CELSIUS         (0x02)
+
 
 
 /****************************************************************************
@@ -1198,7 +1279,7 @@ typedef struct _MPI2_CONFIG_PAGE_BIOS_3
 
 /*
  * Host code (drivers, BIOS, utilities, etc.) should leave this define set to
- * one and check Header.PageLength or NumPhys at runtime.
+ * one and check the value returned for NumPhys at runtime.
  */
 #ifndef MPI2_BIOS_PAGE_4_PHY_ENTRIES
 #define MPI2_BIOS_PAGE_4_PHY_ENTRIES        (1)
@@ -1272,7 +1353,7 @@ typedef struct _MPI2_RAIDVOL0_SETTINGS
 
 /*
  * Host code (drivers, BIOS, utilities, etc.) should leave this define set to
- * one and check Header.PageLength at runtime.
+ * one and check the value returned for NumPhysDisks at runtime.
  */
 #ifndef MPI2_RAID_VOL_PAGE_0_PHYSDISK_MAX
 #define MPI2_RAID_VOL_PAGE_0_PHYSDISK_MAX       (1)
@@ -1329,6 +1410,7 @@ typedef struct _MPI2_CONFIG_PAGE_RAID_VOL_0
 #define MPI2_RAIDVOL0_STATUS_FLAG_CAPACITY_EXPANSION        (0x00040000)
 #define MPI2_RAIDVOL0_STATUS_FLAG_BACKGROUND_INIT           (0x00020000)
 #define MPI2_RAIDVOL0_STATUS_FLAG_RESYNC_IN_PROGRESS        (0x00010000)
+#define MPI2_RAIDVOL0_STATUS_FLAG_VOL_NOT_CONSISTENT        (0x00000080)
 #define MPI2_RAIDVOL0_STATUS_FLAG_OCE_ALLOWED               (0x00000040)
 #define MPI2_RAIDVOL0_STATUS_FLAG_BGI_COMPLETE              (0x00000020)
 #define MPI2_RAIDVOL0_STATUS_FLAG_1E_OFFSET_MIRROR          (0x00000000)
@@ -1451,11 +1533,15 @@ typedef struct _MPI2_CONFIG_PAGE_RD_PDISK_0
 #define MPI2_PHYSDISK0_INCOMPATIBLE_MAX_LBA             (0x03)
 #define MPI2_PHYSDISK0_INCOMPATIBLE_SATA_EXTENDED_CMD   (0x04)
 #define MPI2_PHYSDISK0_INCOMPATIBLE_REMOVEABLE_MEDIA    (0x05)
+#define MPI2_PHYSDISK0_INCOMPATIBLE_MEDIA_TYPE          (0x06)
 #define MPI2_PHYSDISK0_INCOMPATIBLE_UNKNOWN             (0xFF)
 
 /* PhysDiskAttributes defines */
+#define MPI2_PHYSDISK0_ATTRIB_MEDIA_MASK                (0x0C)
 #define MPI2_PHYSDISK0_ATTRIB_SOLID_STATE_DRIVE         (0x08)
 #define MPI2_PHYSDISK0_ATTRIB_HARD_DISK_DRIVE           (0x04)
+
+#define MPI2_PHYSDISK0_ATTRIB_PROTOCOL_MASK             (0x03)
 #define MPI2_PHYSDISK0_ATTRIB_SAS_PROTOCOL              (0x02)
 #define MPI2_PHYSDISK0_ATTRIB_SATA_PROTOCOL             (0x01)
 
@@ -1474,7 +1560,7 @@ typedef struct _MPI2_CONFIG_PAGE_RD_PDISK_0
 
 /*
  * Host code (drivers, BIOS, utilities, etc.) should leave this define set to
- * one and check Header.PageLength or NumPhysDiskPaths at runtime.
+ * one and check the value returned for NumPhysDiskPaths at runtime.
  */
 #ifndef MPI2_RAID_PHYS_DISK1_PATH_MAX
 #define MPI2_RAID_PHYS_DISK1_PATH_MAX   (1)
@@ -1527,6 +1613,7 @@ typedef struct _MPI2_CONFIG_PAGE_RD_PDISK_1
 #define MPI2_SAS_NEG_LINK_RATE_SATA_OOB_COMPLETE        (0x03)
 #define MPI2_SAS_NEG_LINK_RATE_PORT_SELECTOR            (0x04)
 #define MPI2_SAS_NEG_LINK_RATE_SMP_RESET_IN_PROGRESS    (0x05)
+#define MPI2_SAS_NEG_LINK_RATE_UNSUPPORTED_PHY          (0x06)
 #define MPI2_SAS_NEG_LINK_RATE_1_5                      (0x08)
 #define MPI2_SAS_NEG_LINK_RATE_3_0                      (0x09)
 #define MPI2_SAS_NEG_LINK_RATE_6_0                      (0x0A)
@@ -1553,6 +1640,7 @@ typedef struct _MPI2_CONFIG_PAGE_RD_PDISK_1
 #define MPI2_SAS_PHYINFO_PHY_VACANT                     (0x80000000)
 
 #define MPI2_SAS_PHYINFO_PHY_POWER_CONDITION_MASK       (0x18000000)
+#define MPI2_SAS_PHYINFO_SHIFT_PHY_POWER_CONDITION      (27)
 #define MPI2_SAS_PHYINFO_PHY_POWER_ACTIVE               (0x00000000)
 #define MPI2_SAS_PHYINFO_PHY_POWER_PARTIAL              (0x08000000)
 #define MPI2_SAS_PHYINFO_PHY_POWER_SLUMBER              (0x10000000)
@@ -1636,7 +1724,7 @@ typedef struct _MPI2_SAS_IO_UNIT0_PHY_DATA
 
 /*
  * Host code (drivers, BIOS, utilities, etc.) should leave this define set to
- * one and check Header.ExtPageLength or NumPhys at runtime.
+ * one and check the value returned for NumPhys at runtime.
  */
 #ifndef MPI2_SAS_IOUNIT0_PHY_MAX
 #define MPI2_SAS_IOUNIT0_PHY_MAX        (1)
@@ -1707,7 +1795,7 @@ typedef struct _MPI2_SAS_IO_UNIT1_PHY_DATA
 
 /*
  * Host code (drivers, BIOS, utilities, etc.) should leave this define set to
- * one and check Header.ExtPageLength or NumPhys at runtime.
+ * one and check the value returned for NumPhys at runtime.
  */
 #ifndef MPI2_SAS_IOUNIT1_PHY_MAX
 #define MPI2_SAS_IOUNIT1_PHY_MAX        (1)
@@ -1798,7 +1886,7 @@ typedef struct _MPI2_SAS_IOUNIT4_SPINUP_GROUP
 
 /*
  * Host code (drivers, BIOS, utilities, etc.) should leave this define set to
- * four and check Header.ExtPageLength or NumPhys at runtime.
+ * one and check the value returned for NumPhys at runtime.
  */
 #ifndef MPI2_SAS_IOUNIT4_PHY_MAX
 #define MPI2_SAS_IOUNIT4_PHY_MAX        (4)
@@ -1837,7 +1925,7 @@ typedef struct _MPI2_CONFIG_PAGE_SASIOUNIT_4
 typedef struct _MPI2_SAS_IO_UNIT5_PHY_PM_SETTINGS
 {
     U8          ControlFlags;               /* 0x00 */
-    U8          Reserved1;                  /* 0x01 */
+    U8          PortWidthModGroup;          /* 0x01 */
     U16         InactivityTimerExponent;    /* 0x02 */
     U8          SATAPartialTimeout;         /* 0x04 */
     U8          Reserved2;                  /* 0x05 */
@@ -1857,6 +1945,9 @@ typedef struct _MPI2_SAS_IO_UNIT5_PHY_PM_SETTINGS
 #define MPI2_SASIOUNIT5_CONTROL_SATA_SLUMBER_ENABLE     (0x02)
 #define MPI2_SASIOUNIT5_CONTROL_SATA_PARTIAL_ENABLE     (0x01)
 
+/* defines for PortWidthModeGroup field */
+#define MPI2_SASIOUNIT5_PWMG_DISABLE                    (0xFF)
+
 /* defines for InactivityTimerExponent field */
 #define MPI2_SASIOUNIT5_ITE_MASK_SAS_SLUMBER            (0x7000)
 #define MPI2_SASIOUNIT5_ITE_SHIFT_SAS_SLUMBER           (12)
@@ -1878,7 +1969,7 @@ typedef struct _MPI2_SAS_IO_UNIT5_PHY_PM_SETTINGS
 
 /*
  * Host code (drivers, BIOS, utilities, etc.) should leave this define set to
- * one and check Header.ExtPageLength or NumPhys at runtime.
+ * one and check the value returned for NumPhys at runtime.
  */
 #ifndef MPI2_SAS_IOUNIT5_PHY_MAX
 #define MPI2_SAS_IOUNIT5_PHY_MAX        (1)
@@ -1896,7 +1987,137 @@ typedef struct _MPI2_CONFIG_PAGE_SASIOUNIT_5
   MPI2_POINTER PTR_MPI2_CONFIG_PAGE_SASIOUNIT_5,
   Mpi2SasIOUnitPage5_t, MPI2_POINTER pMpi2SasIOUnitPage5_t;
 
-#define MPI2_SASIOUNITPAGE5_PAGEVERSION     (0x00)
+#define MPI2_SASIOUNITPAGE5_PAGEVERSION     (0x01)
+
+
+/* SAS IO Unit Page 6 */
+
+typedef struct _MPI2_SAS_IO_UNIT6_PORT_WIDTH_MOD_GROUP_STATUS
+{
+    U8          CurrentStatus;              /* 0x00 */
+    U8          CurrentModulation;          /* 0x01 */
+    U8          CurrentUtilization;         /* 0x02 */
+    U8          Reserved1;                  /* 0x03 */
+    U32         Reserved2;                  /* 0x04 */
+} MPI2_SAS_IO_UNIT6_PORT_WIDTH_MOD_GROUP_STATUS,
+  MPI2_POINTER PTR_MPI2_SAS_IO_UNIT6_PORT_WIDTH_MOD_GROUP_STATUS,
+  Mpi2SasIOUnit6PortWidthModGroupStatus_t,
+  MPI2_POINTER pMpi2SasIOUnit6PortWidthModGroupStatus_t;
+
+/* defines for CurrentStatus field */
+#define MPI2_SASIOUNIT6_STATUS_UNAVAILABLE                      (0x00)
+#define MPI2_SASIOUNIT6_STATUS_UNCONFIGURED                     (0x01)
+#define MPI2_SASIOUNIT6_STATUS_INVALID_CONFIG                   (0x02)
+#define MPI2_SASIOUNIT6_STATUS_LINK_DOWN                        (0x03)
+#define MPI2_SASIOUNIT6_STATUS_OBSERVATION_ONLY                 (0x04)
+#define MPI2_SASIOUNIT6_STATUS_INACTIVE                         (0x05)
+#define MPI2_SASIOUNIT6_STATUS_ACTIVE_IOUNIT                    (0x06)
+#define MPI2_SASIOUNIT6_STATUS_ACTIVE_HOST                      (0x07)
+
+/* defines for CurrentModulation field */
+#define MPI2_SASIOUNIT6_MODULATION_25_PERCENT                   (0x00)
+#define MPI2_SASIOUNIT6_MODULATION_50_PERCENT                   (0x01)
+#define MPI2_SASIOUNIT6_MODULATION_75_PERCENT                   (0x02)
+#define MPI2_SASIOUNIT6_MODULATION_100_PERCENT                  (0x03)
+
+/*
+ * Host code (drivers, BIOS, utilities, etc.) should leave this define set to
+ * one and check the value returned for NumGroups at runtime.
+ */
+#ifndef MPI2_SAS_IOUNIT6_GROUP_MAX
+#define MPI2_SAS_IOUNIT6_GROUP_MAX      (1)
+#endif
+
+typedef struct _MPI2_CONFIG_PAGE_SASIOUNIT_6
+{
+    MPI2_CONFIG_EXTENDED_PAGE_HEADER    Header;                     /* 0x00 */
+    U32                                 Reserved1;                  /* 0x08 */
+    U32                                 Reserved2;                  /* 0x0C */
+    U8                                  NumGroups;                  /* 0x10 */
+    U8                                  Reserved3;                  /* 0x11 */
+    U16                                 Reserved4;                  /* 0x12 */
+    MPI2_SAS_IO_UNIT6_PORT_WIDTH_MOD_GROUP_STATUS
+        PortWidthModulationGroupStatus[MPI2_SAS_IOUNIT6_GROUP_MAX]; /* 0x14 */
+} MPI2_CONFIG_PAGE_SASIOUNIT_6,
+  MPI2_POINTER PTR_MPI2_CONFIG_PAGE_SASIOUNIT_6,
+  Mpi2SasIOUnitPage6_t, MPI2_POINTER pMpi2SasIOUnitPage6_t;
+
+#define MPI2_SASIOUNITPAGE6_PAGEVERSION     (0x00)
+
+
+/* SAS IO Unit Page 7 */
+
+typedef struct _MPI2_SAS_IO_UNIT7_PORT_WIDTH_MOD_GROUP_SETTINGS
+{
+    U8          Flags;                      /* 0x00 */
+    U8          Reserved1;                  /* 0x01 */
+    U16         Reserved2;                  /* 0x02 */
+    U8          Threshold75Pct;             /* 0x04 */
+    U8          Threshold50Pct;             /* 0x05 */
+    U8          Threshold25Pct;             /* 0x06 */
+    U8          Reserved3;                  /* 0x07 */
+} MPI2_SAS_IO_UNIT7_PORT_WIDTH_MOD_GROUP_SETTINGS,
+  MPI2_POINTER PTR_MPI2_SAS_IO_UNIT7_PORT_WIDTH_MOD_GROUP_SETTINGS,
+  Mpi2SasIOUnit7PortWidthModGroupSettings_t,
+  MPI2_POINTER pMpi2SasIOUnit7PortWidthModGroupSettings_t;
+
+/* defines for Flags field */
+#define MPI2_SASIOUNIT7_FLAGS_ENABLE_PORT_WIDTH_MODULATION  (0x01)
+
+
+/*
+ * Host code (drivers, BIOS, utilities, etc.) should leave this define set to
+ * one and check the value returned for NumGroups at runtime.
+ */
+#ifndef MPI2_SAS_IOUNIT7_GROUP_MAX
+#define MPI2_SAS_IOUNIT7_GROUP_MAX      (1)
+#endif
+
+typedef struct _MPI2_CONFIG_PAGE_SASIOUNIT_7
+{
+    MPI2_CONFIG_EXTENDED_PAGE_HEADER            Header;             /* 0x00 */
+    U8                                          SamplingInterval;   /* 0x08 */
+    U8                                          WindowLength;       /* 0x09 */
+    U16                                         Reserved1;          /* 0x0A */
+    U32                                         Reserved2;          /* 0x0C */
+    U32                                         Reserved3;          /* 0x10 */
+    U8                                          NumGroups;          /* 0x14 */
+    U8                                          Reserved4;          /* 0x15 */
+    U16                                         Reserved5;          /* 0x16 */
+    MPI2_SAS_IO_UNIT7_PORT_WIDTH_MOD_GROUP_SETTINGS
+        PortWidthModulationGroupSettings[MPI2_SAS_IOUNIT7_GROUP_MAX]; /* 0x18 */
+} MPI2_CONFIG_PAGE_SASIOUNIT_7,
+  MPI2_POINTER PTR_MPI2_CONFIG_PAGE_SASIOUNIT_7,
+  Mpi2SasIOUnitPage7_t, MPI2_POINTER pMpi2SasIOUnitPage7_t;
+
+#define MPI2_SASIOUNITPAGE7_PAGEVERSION     (0x00)
+
+
+/* SAS IO Unit Page 8 */
+
+typedef struct _MPI2_CONFIG_PAGE_SASIOUNIT_8
+{
+    MPI2_CONFIG_EXTENDED_PAGE_HEADER    Header;                             /* 0x00 */
+    U32                                 Reserved1;                          /* 0x08 */
+    U32                                 PowerManagementCapabilities;        /* 0x0C */
+    U32                                 Reserved2;                          /* 0x10 */
+} MPI2_CONFIG_PAGE_SASIOUNIT_8,
+  MPI2_POINTER PTR_MPI2_CONFIG_PAGE_SASIOUNIT_8,
+  Mpi2SasIOUnitPage8_t, MPI2_POINTER pMpi2SasIOUnitPage8_t;
+
+#define MPI2_SASIOUNITPAGE8_PAGEVERSION     (0x00)
+
+/* defines for PowerManagementCapabilities field */
+#define MPI2_SASIOUNIT8_PM_HOST_PORT_WIDTH_MOD          (0x000001000)
+#define MPI2_SASIOUNIT8_PM_HOST_SAS_SLUMBER_MODE        (0x000000800)
+#define MPI2_SASIOUNIT8_PM_HOST_SAS_PARTIAL_MODE        (0x000000400)
+#define MPI2_SASIOUNIT8_PM_HOST_SATA_SLUMBER_MODE       (0x000000200)
+#define MPI2_SASIOUNIT8_PM_HOST_SATA_PARTIAL_MODE       (0x000000100)
+#define MPI2_SASIOUNIT8_PM_IOUNIT_PORT_WIDTH_MOD        (0x000000010)
+#define MPI2_SASIOUNIT8_PM_IOUNIT_SAS_SLUMBER_MODE      (0x000000008)
+#define MPI2_SASIOUNIT8_PM_IOUNIT_SAS_PARTIAL_MODE      (0x000000004)
+#define MPI2_SASIOUNIT8_PM_IOUNIT_SATA_SLUMBER_MODE     (0x000000002)
+#define MPI2_SASIOUNIT8_PM_IOUNIT_SATA_PARTIAL_MODE     (0x000000001)
 
 
 
@@ -2187,7 +2408,7 @@ typedef struct _MPI2_SASPHY2_PHY_EVENT
 
 /*
  * Host code (drivers, BIOS, utilities, etc.) should leave this define set to
- * one and check Header.ExtPageLength or NumPhyEvents at runtime.
+ * one and check the value returned for NumPhyEvents at runtime.
  */
 #ifndef MPI2_SASPHY2_PHY_EVENT_MAX
 #define MPI2_SASPHY2_PHY_EVENT_MAX      (1)
@@ -2280,7 +2501,7 @@ typedef struct _MPI2_SASPHY3_PHY_EVENT_CONFIG
 
 /*
  * Host code (drivers, BIOS, utilities, etc.) should leave this define set to
- * one and check Header.ExtPageLength or NumPhyEvents at runtime.
+ * one and check the value returned for NumPhyEvents at runtime.
  */
 #ifndef MPI2_SASPHY3_PHY_EVENT_MAX
 #define MPI2_SASPHY3_PHY_EVENT_MAX      (1)
@@ -2392,7 +2613,7 @@ typedef struct _MPI2_CONFIG_PAGE_SAS_ENCLOSURE_0
 
 /*
  * Host code (drivers, BIOS, utilities, etc.) should leave this define set to
- * one and check Header.ExtPageLength or NumPhys at runtime.
+ * one and check the value returned for NumLogEntries at runtime.
  */
 #ifndef MPI2_LOG_0_NUM_LOG_ENTRIES
 #define MPI2_LOG_0_NUM_LOG_ENTRIES          (1)
@@ -2442,7 +2663,7 @@ typedef struct _MPI2_CONFIG_PAGE_LOG_0
 
 /*
  * Host code (drivers, BIOS, utilities, etc.) should leave this define set to
- * one and check Header.ExtPageLength or NumPhys at runtime.
+ * one and check the value returned for NumElements at runtime.
  */
 #ifndef MPI2_RAIDCONFIG0_MAX_ELEMENTS
 #define MPI2_RAIDCONFIG0_MAX_ELEMENTS       (1)
@@ -2642,4 +2863,24 @@ typedef struct _MPI2_CONFIG_PAGE_ETHERNET_1
 #define MPI2_ETHPG1_MS_DATA_RATE_1GBIT              (0x03)
 
 
+/****************************************************************************
+*   Extended Manufacturing Config Pages
+****************************************************************************/
+
+/*
+ * Generic structure to use for product-specific extended manufacturing pages
+ * (currently Extended Manufacturing Page 40 through Extended Manufacturing
+ * Page 60).
+ */
+
+typedef struct _MPI2_CONFIG_PAGE_EXT_MAN_PS
+{
+    MPI2_CONFIG_EXTENDED_PAGE_HEADER    Header;                 /* 0x00 */
+    U32                                 ProductSpecificInfo;    /* 0x08 */
+} MPI2_CONFIG_PAGE_EXT_MAN_PS,
+  MPI2_POINTER PTR_MPI2_CONFIG_PAGE_EXT_MAN_PS,
+  Mpi2ExtManufacturingPagePS_t, MPI2_POINTER pMpi2ExtManufacturingPagePS_t;
+
+/* PageVersion should be provided by product-specific code */
+
 #endif
similarity index 72%
rename from sys/dev/disk/mps/mpi/mpi2_hbd.h
rename to sys/dev/raid/mps/mpi/mpi2_hbd.h
index c2d81e7..41ac3fb 100644 (file)
@@ -1,13 +1,42 @@
-/* $FreeBSD: src/sys/dev/mps/mpi/mpi2_hbd.h,v 1.1 2010/09/10 15:03:56 ken Exp $ */
+/*-
+ * Copyright (c) 2011 LSI Corp.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * LSI MPT-Fusion Host Adapter FreeBSD
+ *
+ * $FreeBSD: src/sys/dev/mps/mpi/mpi2_hbd.h,v 1.2 2012/01/26 18:17:21 ken Exp $
+ */
+
 /*
- *  Copyright (c) 2009 LSI Corporation.
+ *  Copyright (c) 2009-2011 LSI Corporation.
  *
  *
  *           Name:  mpi2_hbd.h
  *          Title:  MPI Host Based Discovery messages and structures
  *  Creation Date:  October 21, 2009
  *
- *  mpi2_hbd.h Version:  02.00.00
+ *  mpi2_hbd.h Version:  02.00.01
  *
  *  Version History
  *  ---------------
@@ -15,6 +44,8 @@
  *  Date      Version   Description
  *  --------  --------  ------------------------------------------------------
  *  10-28-09  02.00.00  Initial version.
+ *  08-11-10  02.00.01  Removed PortGroups, DmaGroup, and ControlGroup from
+ *                      HBD Action request, replaced by AdditionalInfo field.
  *  --------------------------------------------------------------------------
  */
 
@@ -48,10 +79,7 @@ typedef struct _MPI2_HBD_ACTION_REQUEST
     U8                      Port;               /* 0x25 */
     U8                      MaxConnections;     /* 0x26 */
     U8                      MaxRate;            /* 0x27 */
-    U8                      PortGroups;         /* 0x28 */
-    U8                      DmaGroup;           /* 0x29 */
-    U8                      ControlGroup;       /* 0x2A */
-    U8                      Reserved6;          /* 0x2B */
+    U32                     AdditionalInfo;     /* 0x28 */
     U16                     InitialAWT;         /* 0x2C */
     U16                     Reserved7;          /* 0x2E */
     U32                     Reserved8;          /* 0x30 */
similarity index 75%
rename from sys/dev/disk/mps/mpi/mpi2_history.txt
rename to sys/dev/raid/mps/mpi/mpi2_history.txt
index 6247f92..a87375f 100644 (file)
@@ -1,29 +1,58 @@
-/* $FreeBSD: src/sys/dev/mps/mpi/mpi2_history.txt,v 1.1 2010/09/10 15:03:56 ken Exp $ */
+/*-
+ * Copyright (c) 2011 LSI Corp.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * LSI MPT-Fusion Host Adapter FreeBSD
+ *
+ * $FreeBSD: src/sys/dev/mps/mpi/mpi2_history.txt,v 1.2 2012/01/26 18:17:21 ken Exp $
+ */
+
  ==============================
  Fusion-MPT MPI 2.0 Header File Change History
  ==============================
 
- Copyright (c) 2000-2009 LSI Corporation.
+ Copyright (c) 2000-2011 LSI Corporation.
 
  ---------------------------------------
- Header Set Release Version:    02.00.14
- Header Set Release Date:       10-28-09
+ Header Set Release Version:    02.00.18
+ Header Set Release Date:       11-10-10
  ---------------------------------------
 
  Filename               Current version     Prior version
  ----------             ---------------     -------------
- mpi2.h                 02.00.14            02.00.13
- mpi2_cnfg.h            02.00.13            02.00.12
- mpi2_init.h            02.00.08            02.00.07
- mpi2_ioc.h             02.00.13            02.00.12
- mpi2_raid.h            02.00.04            02.00.04
- mpi2_sas.h             02.00.03            02.00.02
- mpi2_targ.h            02.00.03            02.00.03
- mpi2_tool.h            02.00.04            02.00.04
+ mpi2.h                 02.00.18            02.00.17
+ mpi2_cnfg.h            02.00.17            02.00.16
+ mpi2_init.h            02.00.11            02.00.10
+ mpi2_ioc.h             02.00.16            02.00.15
+ mpi2_raid.h            02.00.05            02.00.05
+ mpi2_sas.h             02.00.05            02.00.05
+ mpi2_targ.h            02.00.04            02.00.04
+ mpi2_tool.h            02.00.06            02.00.06
  mpi2_type.h            02.00.00            02.00.00
  mpi2_ra.h              02.00.00            02.00.00
- mpi2_hbd.h             02.00.00
- mpi2_history.txt       02.00.14            02.00.13
+ mpi2_hbd.h             02.00.01            02.00.01
+ mpi2_history.txt       02.00.18            02.00.17
 
 
  *  Date      Version   Description
@@ -72,6 +101,15 @@ mpi2.h
  *                      Added MSI-x index mask and shift for Reply Post Host
  *                      Index register.
  *                      Added function code for Host Based Discovery Action.
+ *  02-10-10  02.00.15  Bumped MPI2_HEADER_VERSION_UNIT.
+ *                      Added define for MPI2_FUNCTION_PWR_MGMT_CONTROL.
+ *                      Added defines for product-specific range of message
+ *                      function codes, 0xF0 to 0xFF.
+ *  05-12-10  02.00.16  Bumped MPI2_HEADER_VERSION_UNIT.
+ *                      Added alternative defines for the SGE Direction bit.
+ *  08-11-10  02.00.17  Bumped MPI2_HEADER_VERSION_UNIT.
+ *  11-10-10  02.00.18  Bumped MPI2_HEADER_VERSION_UNIT.
+ *                      Added MPI2_IEEE_SGE_FLAGS_SYSTEMPLBCPI_ADDR define.
  *  --------------------------------------------------------------------------
 
 mpi2_cnfg.h
@@ -171,6 +209,31 @@ mpi2_cnfg.h
  *                      Added Ethernet configuration pages.
  *  10-28-09  02.00.13  Added MPI2_IOUNITPAGE1_ENABLE_HOST_BASED_DISCOVERY.
  *                      Added SAS PHY Page 4 structure and defines.
+ *  02-10-10  02.00.14  Modified the comments for the configuration page
+ *                      structures that contain an array of data. The host
+ *                      should use the "count" field in the page data (e.g. the
+ *                      NumPhys field) to determine the number of valid elements
+ *                      in the array.
+ *                      Added/modified some MPI2_MFGPAGE_DEVID_SAS defines.
+ *                      Added PowerManagementCapabilities to IO Unit Page 7.
+ *                      Added PortWidthModGroup field to
+ *                      MPI2_SAS_IO_UNIT5_PHY_PM_SETTINGS.
+ *                      Added MPI2_CONFIG_PAGE_SASIOUNIT_6 and related defines.
+ *                      Added MPI2_CONFIG_PAGE_SASIOUNIT_7 and related defines.
+ *                      Added MPI2_CONFIG_PAGE_SASIOUNIT_8 and related defines.
+ *  05-12-10  02.00.15  Added MPI2_RAIDVOL0_STATUS_FLAG_VOL_NOT_CONSISTENT
+ *                      define.
+ *                      Added MPI2_PHYSDISK0_INCOMPATIBLE_MEDIA_TYPE define.
+ *                      Added MPI2_SAS_NEG_LINK_RATE_UNSUPPORTED_PHY define.
+ *  08-11-10  02.00.16  Removed IO Unit Page 1 device path (multi-pathing)
+ *                      defines.
+ *  11-10-10  02.00.17  Added ReceptacleID field (replacing Reserved1) to
+ *                      MPI2_MANPAGE7_CONNECTOR_INFO and reworked defines for
+ *                      the Pinout field.
+ *                      Added BoardTemperature and BoardTemperatureUnits fields
+ *                      to MPI2_CONFIG_PAGE_IO_UNIT_7.
+ *                      Added MPI2_CONFIG_EXTPAGETYPE_EXT_MANUFACTURING define
+ *                      and MPI2_CONFIG_PAGE_EXT_MAN_PS structure.
  *  --------------------------------------------------------------------------
 
 mpi2_init.h
@@ -192,6 +255,9 @@ mpi2_init.h
  *                      both SCSI IO Error Reply and SCSI Task Management Reply.
  *                      Added ResponseInfo field to MPI2_SCSI_TASK_MANAGE_REPLY.
  *                      Added MPI2_SCSITASKMGMT_RSP_TM_OVERLAPPED_TAG define.
+ *  02-10-10  02.00.09  Removed unused structure that had "#if 0" around it.
+ *  05-12-10  02.00.10  Added optional vendor-unique region to SCSI IO Request.
+ *  11-10-10  02.00.11  Added MPI2_SCSIIO_NUM_SGLOFFSETS define.
  *  --------------------------------------------------------------------------
 
 mpi2_ioc.h
@@ -280,6 +346,12 @@ mpi2_ioc.h
  *                      (MPI2_FW_HEADER_PID_).
  *                      Modified values for SAS ProductID Family
  *                      (MPI2_FW_HEADER_PID_FAMILY_).
+ *  02-10-10  02.00.14  Added SAS Quiesce Event structure and defines.
+ *                      Added PowerManagementControl Request structures and
+ *                      defines.
+ *  05-12-10  02.00.15  Marked Task Set Full Event as obsolete.
+ *                      Added MPI2_EVENT_SAS_TOPO_LR_UNSUPPORTED_PHY define.
+ *  11-10-10  02.00.16  Added MPI2_FW_DOWNLOAD_ITYPE_MIN_PRODUCT_SPECIFIC.
  *  --------------------------------------------------------------------------
 
 mpi2_raid.h
@@ -292,6 +364,7 @@ mpi2_raid.h
  *                      can be sized by the build environment.
  *  07-30-09  02.00.04  Added proper define for the Use Default Settings bit of
  *                      VolumeCreationFlags and marked the old one as obsolete.
+ *  05-12-10  02.00.05  Added MPI2_RAID_VOL_FLAGS_OP_MDC define.
  *  --------------------------------------------------------------------------
 
 mpi2_sas.h
@@ -302,6 +375,8 @@ mpi2_sas.h
  *                      Request.
  *  10-28-09  02.00.03  Changed the type of SGL in MPI2_SATA_PASSTHROUGH_REQUEST
  *                      to MPI2_SGE_IO_UNION since it supports chained SGLs.
+ *  05-12-10  02.00.04  Modified some comments.
+ *  08-11-10  02.00.05  Added NCQ operations to SAS IO Unit Control.
  *  --------------------------------------------------------------------------
 
 mpi2_targ.h
@@ -313,6 +388,7 @@ mpi2_targ.h
  *                      MPI2_TARGET_CMD_BUF_POST_BASE_REQUEST.
  *                      Target Status Send Request only takes a single SGE for
  *                      response data.
+ *  02-10-10  02.00.04  Added comment to MPI2_TARGET_SSP_RSP_IU structure.
  *  --------------------------------------------------------------------------
 
 mpi2_tool.h
@@ -325,6 +401,9 @@ mpi2_tool.h
  *                      and reply messages.
  *                      Added MPI2_DIAG_BUF_TYPE_EXTENDED.
  *                      Incremented MPI2_DIAG_BUF_TYPE_COUNT.
+ *  05-12-10  02.00.05  Added Diagnostic Data Upload tool.
+ *  08-11-10  02.00.06  Added defines that were missing for Diagnostic Buffer
+ *                      Post Request.
  *  --------------------------------------------------------------------------
 
 mpi2_type.h
@@ -337,24 +416,40 @@ mpi2_ra.h
 
 mpi2_hbd.h
  *  10-28-09  02.00.00  Initial version.
+ *  08-11-10  02.00.01  Removed PortGroups, DmaGroup, and ControlGroup from
+ *                      HBD Action request, replaced by AdditionalInfo field.
  *  --------------------------------------------------------------------------
 
 
 mpi2_history.txt         Parts list history
 
-Filename     02.00.14  02.00.13  02.00.12
-----------   --------  --------  --------
-mpi2.h       02.00.14  02.00.13  02.00.12
-mpi2_cnfg.h  02.00.13  02.00.12  02.00.11
-mpi2_init.h  02.00.08  02.00.07  02.00.07
-mpi2_ioc.h   02.00.13  02.00.12  02.00.11
-mpi2_raid.h  02.00.04  02.00.04  02.00.03
-mpi2_sas.h   02.00.03  02.00.02  02.00.02
-mpi2_targ.h  02.00.03  02.00.03  02.00.03
-mpi2_tool.h  02.00.04  02.00.04  02.00.03
-mpi2_type.h  02.00.00  02.00.00  02.00.00
-mpi2_ra.h    02.00.00  02.00.00  02.00.00
-mpi2_hbd.h   02.00.00
+Filename     02.00.18
+----------   --------
+mpi2.h       02.00.18
+mpi2_cnfg.h  02.00.17
+mpi2_init.h  02.00.11
+mpi2_ioc.h   02.00.16
+mpi2_raid.h  02.00.05
+mpi2_sas.h   02.00.05
+mpi2_targ.h  02.00.04
+mpi2_tool.h  02.00.06
+mpi2_type.h  02.00.00
+mpi2_ra.h    02.00.00
+mpi2_hbd.h   02.00.01
+
+Filename     02.00.17  02.00.16  02.00.15  02.00.14  02.00.13  02.00.12
+----------   --------  --------  --------  --------  --------  --------
+mpi2.h       02.00.17  02.00.16  02.00.15  02.00.14  02.00.13  02.00.12
+mpi2_cnfg.h  02.00.16  02.00.15  02.00.14  02.00.13  02.00.12  02.00.11
+mpi2_init.h  02.00.10  02.00.10  02.00.09  02.00.08  02.00.07  02.00.07
+mpi2_ioc.h   02.00.15  02.00.15  02.00.14  02.00.13  02.00.12  02.00.11
+mpi2_raid.h  02.00.05  02.00.05  02.00.04  02.00.04  02.00.04  02.00.03
+mpi2_sas.h   02.00.05  02.00.04  02.00.03  02.00.03  02.00.02  02.00.02
+mpi2_targ.h  02.00.04  02.00.04  02.00.04  02.00.03  02.00.03  02.00.03
+mpi2_tool.h  02.00.06  02.00.05  02.00.04  02.00.04  02.00.04  02.00.03
+mpi2_type.h  02.00.00  02.00.00  02.00.00  02.00.00  02.00.00  02.00.00
+mpi2_ra.h    02.00.00  02.00.00  02.00.00  02.00.00  02.00.00  02.00.00
+mpi2_hbd.h   02.00.01  02.00.00  02.00.00  02.00.00
 
 Filename     02.00.11  02.00.10  02.00.09  02.00.08  02.00.07  02.00.06
 ----------   --------  --------  --------  --------  --------  --------
similarity index 91%
rename from sys/dev/disk/mps/mpi/mpi2_init.h
rename to sys/dev/raid/mps/mpi/mpi2_init.h
index 7d0c435..4c6ec98 100644 (file)
@@ -1,13 +1,42 @@
-/* $FreeBSD: src/sys/dev/mps/mpi/mpi2_init.h,v 1.1 2010/09/10 15:03:56 ken Exp $ */
+/*-
+ * Copyright (c) 2011 LSI Corp.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * LSI MPT-Fusion Host Adapter FreeBSD
+ *
+ * $FreeBSD: src/sys/dev/mps/mpi/mpi2_init.h,v 1.2 2012/01/26 18:17:21 ken Exp $
+ */
+
 /*
- *  Copyright (c) 2000-2009 LSI Corporation.
+ *  Copyright (c) 2000-2011 LSI Corporation.
  *
  *
  *           Name:  mpi2_init.h
  *          Title:  MPI SCSI initiator mode messages and structures
  *  Creation Date:  June 23, 2006
  *
- *    mpi2_init.h Version:  02.00.08
+ *    mpi2_init.h Version:  02.00.11
  *
  *  Version History
  *  ---------------
@@ -32,6 +61,9 @@
  *                      both SCSI IO Error Reply and SCSI Task Management Reply.
  *                      Added ResponseInfo field to MPI2_SCSI_TASK_MANAGE_REPLY.
  *                      Added MPI2_SCSITASKMGMT_RSP_TM_OVERLAPPED_TAG define.
+ *  02-10-10  02.00.09  Removed unused structure that had "#if 0" around it.
+ *  05-12-10  02.00.10  Added optional vendor-unique region to SCSI IO Request.
+ *  11-10-10  02.00.11  Added MPI2_SCSIIO_NUM_SGLOFFSETS define.
  *  --------------------------------------------------------------------------
  */
 
@@ -58,20 +90,6 @@ typedef struct
 } MPI2_SCSI_IO_CDB_EEDP32, MPI2_POINTER PTR_MPI2_SCSI_IO_CDB_EEDP32,
   Mpi2ScsiIoCdbEedp32_t, MPI2_POINTER pMpi2ScsiIoCdbEedp32_t;
 
-/* TBD: I don't think this is needed for MPI2/Gen2 */
-#if 0
-typedef struct
-{
-    U8                      CDB[16];                    /* 0x00 */
-    U32                     DataLength;                 /* 0x10 */
-    U32                     PrimaryReferenceTag;        /* 0x14 */
-    U16                     PrimaryApplicationTag;      /* 0x18 */
-    U16                     PrimaryApplicationTagMask;  /* 0x1A */
-    U32                     TransferLength;             /* 0x1C */
-} MPI2_SCSI_IO32_CDB_EEDP16, MPI2_POINTER PTR_MPI2_SCSI_IO32_CDB_EEDP16,
-  Mpi2ScsiIo32CdbEedp16_t, MPI2_POINTER pMpi2ScsiIo32CdbEedp16_t;
-#endif
-
 typedef union
 {
     U8                      CDB32[32];
@@ -112,7 +130,13 @@ typedef struct _MPI2_SCSI_IO_REQUEST
     U8                      LUN[8];                         /* 0x34 */
     U32                     Control;                        /* 0x3C */
     MPI2_SCSI_IO_CDB_UNION  CDB;                            /* 0x40 */
+
+#ifdef MPI2_SCSI_IO_VENDOR_UNIQUE_REGION /* typically this is left undefined */
+    MPI2_SCSI_IO_VENDOR_UNIQUE VendorRegion;
+#endif
+
     MPI2_SGE_IO_UNION       SGL;                            /* 0x60 */
+
 } MPI2_SCSI_IO_REQUEST, MPI2_POINTER PTR_MPI2_SCSI_IO_REQUEST,
   Mpi2SCSIIORequest_t, MPI2_POINTER pMpi2SCSIIORequest_t;
 
@@ -146,6 +170,9 @@ typedef struct _MPI2_SCSI_IO_REQUEST
 #define MPI2_SCSIIO_SGLFLAGS_SGL1_SHIFT             (4)
 #define MPI2_SCSIIO_SGLFLAGS_SGL0_SHIFT             (0)
 
+/* number of SGLOffset fields */
+#define MPI2_SCSIIO_NUM_SGLOFFSETS                  (4)
+
 /* SCSI IO IoFlags bits */
 
 /* Large CDB Address Space */
similarity index 89%
rename from sys/dev/disk/mps/mpi/mpi2_ioc.h
rename to sys/dev/raid/mps/mpi/mpi2_ioc.h
index c25b2f4..7dd0b36 100644 (file)
@@ -1,13 +1,42 @@
-/* $FreeBSD: src/sys/dev/mps/mpi/mpi2_ioc.h,v 1.1 2010/09/10 15:03:56 ken Exp $ */
+/*-
+ * Copyright (c) 2011 LSI Corp.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * LSI MPT-Fusion Host Adapter FreeBSD
+ *
+ * $FreeBSD: src/sys/dev/mps/mpi/mpi2_ioc.h,v 1.2 2012/01/26 18:17:21 ken Exp $
+ */
+
 /*
- *  Copyright (c) 2000-2009 LSI Corporation.
+ *  Copyright (c) 2000-2011 LSI Corporation.
  *
  *
  *           Name:  mpi2_ioc.h
  *          Title:  MPI IOC, Port, Event, FW Download, and FW Upload messages
  *  Creation Date:  October 11, 2006
  *
- *  mpi2_ioc.h Version:  02.00.13
+ *  mpi2_ioc.h Version:  02.00.16
  *
  *  Version History
  *  ---------------
  *                      (MPI2_FW_HEADER_PID_).
  *                      Modified values for SAS ProductID Family
  *                      (MPI2_FW_HEADER_PID_FAMILY_).
+ *  02-10-10  02.00.14  Added SAS Quiesce Event structure and defines.
+ *                      Added PowerManagementControl Request structures and
+ *                      defines.
+ *  05-12-10  02.00.15  Marked Task Set Full Event as obsolete.
+ *                      Added MPI2_EVENT_SAS_TOPO_LR_UNSUPPORTED_PHY define.
+ *  11-10-10  02.00.16  Added MPI2_FW_DOWNLOAD_ITYPE_MIN_PRODUCT_SPECIFIC.
  *  --------------------------------------------------------------------------
  */
 
@@ -454,7 +489,7 @@ typedef struct _MPI2_EVENT_NOTIFICATION_REPLY
 #define MPI2_EVENT_STATE_CHANGE                     (0x0002)
 #define MPI2_EVENT_HARD_RESET_RECEIVED              (0x0005)
 #define MPI2_EVENT_EVENT_CHANGE                     (0x000A)
-#define MPI2_EVENT_TASK_SET_FULL                    (0x000E)
+#define MPI2_EVENT_TASK_SET_FULL                    (0x000E) /* obsolete */
 #define MPI2_EVENT_SAS_DEVICE_STATUS_CHANGE         (0x000F)
 #define MPI2_EVENT_IR_OPERATION_STATUS              (0x0014)
 #define MPI2_EVENT_SAS_DISCOVERY                    (0x0016)
@@ -470,6 +505,7 @@ typedef struct _MPI2_EVENT_NOTIFICATION_REPLY
 #define MPI2_EVENT_SAS_PHY_COUNTER                  (0x0022)
 #define MPI2_EVENT_GPIO_INTERRUPT                   (0x0023)
 #define MPI2_EVENT_HOST_BASED_DISCOVERY_PHY         (0x0024)
+#define MPI2_EVENT_SAS_QUIESCE                      (0x0025)
 
 
 /* Log Entry Added Event data */
@@ -515,6 +551,7 @@ typedef struct _MPI2_EVENT_DATA_HARD_RESET_RECEIVED
   MPI2_POINTER pMpi2EventDataHardResetReceived_t;
 
 /* Task Set Full Event data */
+/*   this event is obsolete */
 
 typedef struct _MPI2_EVENT_DATA_TASK_SET_FULL
 {
@@ -829,6 +866,7 @@ typedef struct _MPI2_EVENT_DATA_SAS_TOPOLOGY_CHANGE_LIST
 #define MPI2_EVENT_SAS_TOPO_LR_SATA_OOB_COMPLETE            (0x03)
 #define MPI2_EVENT_SAS_TOPO_LR_PORT_SELECTOR                (0x04)
 #define MPI2_EVENT_SAS_TOPO_LR_SMP_RESET_IN_PROGRESS        (0x05)
+#define MPI2_EVENT_SAS_TOPO_LR_UNSUPPORTED_PHY              (0x06)
 #define MPI2_EVENT_SAS_TOPO_LR_RATE_1_5                     (0x08)
 #define MPI2_EVENT_SAS_TOPO_LR_RATE_3_0                     (0x09)
 #define MPI2_EVENT_SAS_TOPO_LR_RATE_6_0                     (0x0A)
@@ -896,6 +934,23 @@ typedef struct _MPI2_EVENT_DATA_SAS_PHY_COUNTER
 /* use MPI2_SASPHY3_TFLAGS_ values from mpi2_cnfg.h for the ThresholdFlags field */
 
 
+/* SAS Quiesce Event data */
+
+typedef struct _MPI2_EVENT_DATA_SAS_QUIESCE
+{
+    U8                      ReasonCode;                 /* 0x00 */
+    U8                      Reserved1;                  /* 0x01 */
+    U16                     Reserved2;                  /* 0x02 */
+    U32                     Reserved3;                  /* 0x04 */
+} MPI2_EVENT_DATA_SAS_QUIESCE,
+  MPI2_POINTER PTR_MPI2_EVENT_DATA_SAS_QUIESCE,
+  Mpi2EventDataSasQuiesce_t, MPI2_POINTER pMpi2EventDataSasQuiesce_t;
+
+/* SAS Quiesce Event data ReasonCode values */
+#define MPI2_EVENT_SAS_QUIESCE_RC_STARTED                   (0x01)
+#define MPI2_EVENT_SAS_QUIESCE_RC_COMPLETED                 (0x02)
+
+
 /* Host Based Discovery Phy Event data */
 
 typedef struct _MPI2_EVENT_HBD_PHY_SAS
@@ -1009,7 +1064,9 @@ typedef struct _MPI2_FW_DOWNLOAD_REQUEST
 #define MPI2_FW_DOWNLOAD_ITYPE_CONFIG_1             (0x07)
 #define MPI2_FW_DOWNLOAD_ITYPE_CONFIG_2             (0x08)
 #define MPI2_FW_DOWNLOAD_ITYPE_MEGARAID             (0x09)
+#define MPI2_FW_DOWNLOAD_ITYPE_COMPLETE             (0x0A)
 #define MPI2_FW_DOWNLOAD_ITYPE_COMMON_BOOT_BLOCK    (0x0B)
+#define MPI2_FW_DOWNLOAD_ITYPE_MIN_PRODUCT_SPECIFIC (0xF0)
 
 /* FWDownload TransactionContext Element */
 typedef struct _MPI2_FW_DOWNLOAD_TCSGE
@@ -1186,7 +1243,6 @@ typedef struct _MPI2_FW_IMAGE_HEADER
 
 #define MPI2_FW_HEADER_PID_PROD_MASK                    (0x0F00)
 #define MPI2_FW_HEADER_PID_PROD_A                       (0x0000)
-#define MPI2_FW_HEADER_PID_PROD_MASK                    (0x0F00)
 #define MPI2_FW_HEADER_PID_PROD_TARGET_INITIATOR_SCSI   (0x0200)
 #define MPI2_FW_HEADER_PID_PROD_IR_SCSI                 (0x0700)
 
@@ -1410,4 +1466,100 @@ typedef struct _MPI2_INIT_IMAGE_FOOTER
 #define MPI2_INIT_IMAGE_RESETVECTOR_OFFSET      (0x14)
 
 
+/****************************************************************************
+*  PowerManagementControl message
+****************************************************************************/
+
+/* PowerManagementControl Request message */
+typedef struct _MPI2_PWR_MGMT_CONTROL_REQUEST
+{
+    U8                      Feature;                    /* 0x00 */
+    U8                      Reserved1;                  /* 0x01 */
+    U8                      ChainOffset;                /* 0x02 */
+    U8                      Function;                   /* 0x03 */
+    U16                     Reserved2;                  /* 0x04 */
+    U8                      Reserved3;                  /* 0x06 */
+    U8                      MsgFlags;                   /* 0x07 */
+    U8                      VP_ID;                      /* 0x08 */
+    U8                      VF_ID;                      /* 0x09 */
+    U16                     Reserved4;                  /* 0x0A */
+    U8                      Parameter1;                 /* 0x0C */
+    U8                      Parameter2;                 /* 0x0D */
+    U8                      Parameter3;                 /* 0x0E */
+    U8                      Parameter4;                 /* 0x0F */
+    U32                     Reserved5;                  /* 0x10 */
+    U32                     Reserved6;                  /* 0x14 */
+} MPI2_PWR_MGMT_CONTROL_REQUEST, MPI2_POINTER PTR_MPI2_PWR_MGMT_CONTROL_REQUEST,
+  Mpi2PwrMgmtControlRequest_t, MPI2_POINTER pMpi2PwrMgmtControlRequest_t;
+
+/* defines for the Feature field */
+#define MPI2_PM_CONTROL_FEATURE_DA_PHY_POWER_COND       (0x01)
+#define MPI2_PM_CONTROL_FEATURE_PORT_WIDTH_MODULATION   (0x02)
+#define MPI2_PM_CONTROL_FEATURE_PCIE_LINK               (0x03)
+#define MPI2_PM_CONTROL_FEATURE_IOC_SPEED               (0x04)
+#define MPI2_PM_CONTROL_FEATURE_MIN_PRODUCT_SPECIFIC    (0x80)
+#define MPI2_PM_CONTROL_FEATURE_MAX_PRODUCT_SPECIFIC    (0xFF)
+
+/* parameter usage for the MPI2_PM_CONTROL_FEATURE_DA_PHY_POWER_COND Feature */
+/* Parameter1 contains a PHY number */
+/* Parameter2 indicates power condition action using these defines */
+#define MPI2_PM_CONTROL_PARAM2_PARTIAL                  (0x01)
+#define MPI2_PM_CONTROL_PARAM2_SLUMBER                  (0x02)
+#define MPI2_PM_CONTROL_PARAM2_EXIT_PWR_MGMT            (0x03)
+/* Parameter3 and Parameter4 are reserved */
+
+/* parameter usage for the MPI2_PM_CONTROL_FEATURE_PORT_WIDTH_MODULATION Feature */
+/* Parameter1 contains SAS port width modulation group number */
+/* Parameter2 indicates IOC action using these defines */
+#define MPI2_PM_CONTROL_PARAM2_REQUEST_OWNERSHIP        (0x01)
+#define MPI2_PM_CONTROL_PARAM2_CHANGE_MODULATION        (0x02)
+#define MPI2_PM_CONTROL_PARAM2_RELINQUISH_OWNERSHIP     (0x03)
+/* Parameter3 indicates desired modulation level using these defines */
+#define MPI2_PM_CONTROL_PARAM3_25_PERCENT               (0x00)
+#define MPI2_PM_CONTROL_PARAM3_50_PERCENT               (0x01)
+#define MPI2_PM_CONTROL_PARAM3_75_PERCENT               (0x02)
+#define MPI2_PM_CONTROL_PARAM3_100_PERCENT              (0x03)
+/* Parameter4 is reserved */
+
+/* parameter usage for the MPI2_PM_CONTROL_FEATURE_PCIE_LINK Feature */
+/* Parameter1 indicates desired PCIe link speed using these defines */
+#define MPI2_PM_CONTROL_PARAM1_PCIE_2_5_GBPS            (0x00)
+#define MPI2_PM_CONTROL_PARAM1_PCIE_5_0_GBPS            (0x01)
+#define MPI2_PM_CONTROL_PARAM1_PCIE_8_0_GBPS            (0x02)
+/* Parameter2 indicates desired PCIe link width using these defines */
+#define MPI2_PM_CONTROL_PARAM2_WIDTH_X1                 (0x01)
+#define MPI2_PM_CONTROL_PARAM2_WIDTH_X2                 (0x02)
+#define MPI2_PM_CONTROL_PARAM2_WIDTH_X4                 (0x04)
+#define MPI2_PM_CONTROL_PARAM2_WIDTH_X8                 (0x08)
+/* Parameter3 and Parameter4 are reserved */
+
+/* parameter usage for the MPI2_PM_CONTROL_FEATURE_IOC_SPEED Feature */
+/* Parameter1 indicates desired IOC hardware clock speed using these defines */
+#define MPI2_PM_CONTROL_PARAM1_FULL_IOC_SPEED           (0x01)
+#define MPI2_PM_CONTROL_PARAM1_HALF_IOC_SPEED           (0x02)
+#define MPI2_PM_CONTROL_PARAM1_QUARTER_IOC_SPEED        (0x04)
+#define MPI2_PM_CONTROL_PARAM1_EIGHTH_IOC_SPEED         (0x08)
+/* Parameter2, Parameter3, and Parameter4 are reserved */
+
+
+/* PowerManagementControl Reply message */
+typedef struct _MPI2_PWR_MGMT_CONTROL_REPLY
+{
+    U8                      Feature;                    /* 0x00 */
+    U8                      Reserved1;                  /* 0x01 */
+    U8                      MsgLength;                  /* 0x02 */
+    U8                      Function;                   /* 0x03 */
+    U16                     Reserved2;                  /* 0x04 */
+    U8                      Reserved3;                  /* 0x06 */
+    U8                      MsgFlags;                   /* 0x07 */
+    U8                      VP_ID;                      /* 0x08 */
+    U8                      VF_ID;                      /* 0x09 */
+    U16                     Reserved4;                  /* 0x0A */
+    U16                     Reserved5;                  /* 0x0C */
+    U16                     IOCStatus;                  /* 0x0E */
+    U32                     IOCLogInfo;                 /* 0x10 */
+} MPI2_PWR_MGMT_CONTROL_REPLY, MPI2_POINTER PTR_MPI2_PWR_MGMT_CONTROL_REPLY,
+  Mpi2PwrMgmtControlReply_t, MPI2_POINTER pMpi2PwrMgmtControlReply_t;
+
+
 #endif
similarity index 71%
rename from sys/dev/disk/mps/mpi/mpi2_ra.h
rename to sys/dev/raid/mps/mpi/mpi2_ra.h
index 859925d..4d9e130 100644 (file)
@@ -1,6 +1,35 @@
-/* $FreeBSD: src/sys/dev/mps/mpi/mpi2_ra.h,v 1.1 2010/09/10 15:03:56 ken Exp $ */
+/*-
+ * Copyright (c) 2011 LSI Corp.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * LSI MPT-Fusion Host Adapter FreeBSD
+ *
+ * $FreeBSD: src/sys/dev/mps/mpi/mpi2_ra.h,v 1.2 2012/01/26 18:17:21 ken Exp $
+ */
+
 /*
- *  Copyright (c) 2009 LSI Corporation.
+ *  Copyright (c) 2011 LSI Corporation.
  *
  *
  *           Name:  mpi2_ra.h
similarity index 89%
rename from sys/dev/disk/mps/mpi/mpi2_raid.h
rename to sys/dev/raid/mps/mpi/mpi2_raid.h
index d106352..f1f1988 100644 (file)
@@ -1,13 +1,42 @@
-/* $FreeBSD: src/sys/dev/mps/mpi/mpi2_raid.h,v 1.1 2010/09/10 15:03:56 ken Exp $ */
+/*-
+ * Copyright (c) 2011 LSI Corp.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * LSI MPT-Fusion Host Adapter FreeBSD
+ *
+ * $FreeBSD: src/sys/dev/mps/mpi/mpi2_raid.h,v 1.2 2012/01/26 18:17:21 ken Exp $
+ */
+
 /*
- *  Copyright (c) 2000-2008 LSI Corporation.
+ *  Copyright (c) 2000-2011 LSI Corporation.
  *
  *
  *           Name:  mpi2_raid.h
  *          Title:  MPI Integrated RAID messages and structures
  *  Creation Date:  April 26, 2007
  *
- *    mpi2_raid.h Version:  02.00.04
+ *    mpi2_raid.h Version:  02.00.05
  *
  *  Version History
  *  ---------------
@@ -23,6 +52,7 @@
  *                      can be sized by the build environment.
  *  07-30-09  02.00.04  Added proper define for the Use Default Settings bit of
  *                      VolumeCreationFlags and marked the old one as obsolete.
+ *  05-12-10  02.00.05  Added MPI2_RAID_VOL_FLAGS_OP_MDC define.
  *  --------------------------------------------------------------------------
  */
 
@@ -261,6 +291,7 @@ typedef struct _MPI2_RAID_VOL_INDICATOR
 #define MPI2_RAID_VOL_FLAGS_OP_ONLINE_CAP_EXPANSION (0x00000001)
 #define MPI2_RAID_VOL_FLAGS_OP_CONSISTENCY_CHECK    (0x00000002)
 #define MPI2_RAID_VOL_FLAGS_OP_RESYNC               (0x00000003)
+#define MPI2_RAID_VOL_FLAGS_OP_MDC                  (0x00000004)
 
 
 /* RAID Action Reply ActionData union */
similarity index 86%
rename from sys/dev/disk/mps/mpi/mpi2_sas.h
rename to sys/dev/raid/mps/mpi/mpi2_sas.h
index 2d2e469..a232d92 100644 (file)
@@ -1,13 +1,42 @@
-/* $FreeBSD: src/sys/dev/mps/mpi/mpi2_sas.h,v 1.1 2010/09/10 15:03:56 ken Exp $ */
+/*-
+ * Copyright (c) 2011 LSI Corp.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * LSI MPT-Fusion Host Adapter FreeBSD
+ *
+ * $FreeBSD: src/sys/dev/mps/mpi/mpi2_sas.h,v 1.2 2012/01/26 18:17:21 ken Exp $
+ */
+
 /*
- *  Copyright (c) 2000-2007 LSI Corporation.
+ *  Copyright (c) 2000-2011 LSI Corporation.
  *
  *
  *           Name:  mpi2_sas.h
  *          Title:  MPI Serial Attached SCSI structures and definitions
  *  Creation Date:  February 9, 2007
  *
- *  mpi2.h Version:  02.00.03
+ *  mpi2_sas.h Version:  02.00.05
  *
  *  Version History
  *  ---------------
@@ -21,6 +50,8 @@
  *                      Request.
  *  10-28-09  02.00.03  Changed the type of SGL in MPI2_SATA_PASSTHROUGH_REQUEST
  *                      to MPI2_SGE_IO_UNION since it supports chained SGLs.
+ *  05-12-10  02.00.04  Modified some comments.
+ *  08-11-10  02.00.05  Added NCQ operations to SAS IO Unit Control.
  *  --------------------------------------------------------------------------
  */
 
@@ -111,7 +142,7 @@ typedef struct _MPI2_SMP_PASSTHROUGH_REQUEST
 /* values for PassthroughFlags field */
 #define MPI2_SMP_PT_REQ_PT_FLAGS_IMMEDIATE      (0x80)
 
-/* values for SGLFlags field are in the SGL section of mpi2.h */
+/* use MPI2_SGLFLAGS_ defines from mpi2.h for the SGLFlags field */
 
 
 /* SMP Passthrough Reply Message */
@@ -163,7 +194,7 @@ typedef struct _MPI2_SATA_PASSTHROUGH_REQUEST
     U32                     Reserved4;          /* 0x14 */
     U32                     DataLength;         /* 0x18 */
     U8                      CommandFIS[20];     /* 0x1C */
-    MPI2_SGE_IO_UNION       SGL;                /* 0x20 */
+    MPI2_SGE_IO_UNION       SGL;                /* 0x30 */
 } MPI2_SATA_PASSTHROUGH_REQUEST, MPI2_POINTER PTR_MPI2_SATA_PASSTHROUGH_REQUEST,
   Mpi2SataPassthroughRequest_t, MPI2_POINTER pMpi2SataPassthroughRequest_t;
 
@@ -175,7 +206,7 @@ typedef struct _MPI2_SATA_PASSTHROUGH_REQUEST
 #define MPI2_SATA_PT_REQ_PT_FLAGS_WRITE             (0x0002)
 #define MPI2_SATA_PT_REQ_PT_FLAGS_READ              (0x0001)
 
-/* values for SGLFlags field are in the SGL section of mpi2.h */
+/* use MPI2_SGLFLAGS_ defines from mpi2.h for the SGLFlags field */
 
 
 /* SATA Passthrough Reply Message */
@@ -246,6 +277,8 @@ typedef struct _MPI2_SAS_IOUNIT_CONTROL_REQUEST
 #define MPI2_SAS_OP_REMOVE_DEVICE               (0x0D)
 #define MPI2_SAS_OP_LOOKUP_MAPPING              (0x0E)
 #define MPI2_SAS_OP_SET_IOC_PARAMETER           (0x0F)
+#define MPI2_SAS_OP_DEV_ENABLE_NCQ              (0x14)
+#define MPI2_SAS_OP_DEV_DISABLE_NCQ             (0x15)
 #define MPI2_SAS_OP_PRODUCT_SPECIFIC_MIN        (0x80)
 
 /* values for the PrimFlags field */
similarity index 92%
rename from sys/dev/disk/mps/mpi/mpi2_targ.h
rename to sys/dev/raid/mps/mpi/mpi2_targ.h
index b1d8ab3..f52d578 100644 (file)
@@ -1,13 +1,42 @@
-/* $FreeBSD: src/sys/dev/mps/mpi/mpi2_targ.h,v 1.1 2010/09/10 15:03:56 ken Exp $ */
+/*-
+ * Copyright (c) 2011 LSI Corp.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * LSI MPT-Fusion Host Adapter FreeBSD
+ *
+ * $FreeBSD: src/sys/dev/mps/mpi/mpi2_targ.h,v 1.2 2012/01/26 18:17:21 ken Exp $
+ */
+
 /*
- *  Copyright (c) 2000-2008 LSI Corporation.
+ *  Copyright (c) 2000-2011 LSI Corporation.
  *
  *
  *           Name:  mpi2_targ.h
  *          Title:  MPI Target mode messages and structures
  *  Creation Date:  September 8, 2006
  *
- *    mpi2_targ.h Version: 02.00.03
+ *    mpi2_targ.h Version: 02.00.04
  *
  *  Version History
  *  ---------------
@@ -22,6 +51,7 @@
  *                      MPI2_TARGET_CMD_BUF_POST_BASE_REQUEST.
  *                      Target Status Send Request only takes a single SGE for
  *                      response data.
+ *  02-10-10  02.00.04  Added comment to MPI2_TARGET_SSP_RSP_IU structure.
  *  --------------------------------------------------------------------------
  */
 
@@ -343,6 +373,7 @@ typedef struct _MPI2_TARGET_STATUS_SEND_REQUEST
 typedef struct _MPI2_TARGET_SSP_RSP_IU
 {
     U32     Reserved0[6]; /* reserved for SSP header */ /* 0x00 */
+
     /* start of RESPONSE information unit */
     U32     Reserved1;                                  /* 0x18 */
     U32     Reserved2;                                  /* 0x1C */
@@ -352,6 +383,8 @@ typedef struct _MPI2_TARGET_SSP_RSP_IU
     U32     Reserved4;                                  /* 0x24 */
     U32     SenseDataLength;                            /* 0x28 */
     U32     ResponseDataLength;                         /* 0x2C */
+
+    /* start of Response or Sense Data (size may vary dynamically) */
     U8      ResponseSenseData[4];                       /* 0x30 */
 } MPI2_TARGET_SSP_RSP_IU, MPI2_POINTER PTR_MPI2_TARGET_SSP_RSP_IU,
   Mpi2TargetSspRspIu_t, MPI2_POINTER pMpi2TargetSspRspIu_t;
similarity index 82%
rename from sys/dev/disk/mps/mpi/mpi2_tool.h
rename to sys/dev/raid/mps/mpi/mpi2_tool.h
index c827e3a..249bb87 100644 (file)
@@ -1,13 +1,42 @@
-/* $FreeBSD: src/sys/dev/mps/mpi/mpi2_tool.h,v 1.1 2010/09/10 15:03:56 ken Exp $ */
+/*-
+ * Copyright (c) 2011 LSI Corp.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * LSI MPT-Fusion Host Adapter FreeBSD
+ *
+ * $FreeBSD: src/sys/dev/mps/mpi/mpi2_tool.h,v 1.2 2012/01/26 18:17:21 ken Exp $
+ */
+
 /*
- *  Copyright (c) 2000-2009 LSI Corporation.
+ *  Copyright (c) 2000-2011 LSI Corporation.
  *
  *
  *           Name:  mpi2_tool.h
  *          Title:  MPI diagnostic tool structures and definitions
  *  Creation Date:  March 26, 2007
  *
- *    mpi2_tool.h Version:  02.00.04
+ *    mpi2_tool.h Version:  02.00.06
  *
  *  Version History
  *  ---------------
@@ -23,6 +52,9 @@
  *                      and reply messages.
  *                      Added MPI2_DIAG_BUF_TYPE_EXTENDED.
  *                      Incremented MPI2_DIAG_BUF_TYPE_COUNT.
+ *  05-12-10  02.00.05  Added Diagnostic Data Upload tool.
+ *  08-11-10  02.00.06  Added defines that were missing for Diagnostic Buffer
+ *                      Post Request.
  *  --------------------------------------------------------------------------
  */
 
@@ -38,6 +70,7 @@
 /* defines for the Tools */
 #define MPI2_TOOLBOX_CLEAN_TOOL                     (0x00)
 #define MPI2_TOOLBOX_MEMORY_MOVE_TOOL               (0x01)
+#define MPI2_TOOLBOX_DIAG_DATA_UPLOAD_TOOL          (0x02)
 #define MPI2_TOOLBOX_ISTWI_READ_WRITE_TOOL          (0x03)
 #define MPI2_TOOLBOX_BEACON_TOOL                    (0x05)
 #define MPI2_TOOLBOX_DIAGNOSTIC_CLI_TOOL            (0x06)
@@ -121,6 +154,46 @@ typedef struct _MPI2_TOOLBOX_MEM_MOVE_REQUEST
 
 
 /****************************************************************************
+*  Toolbox Diagnostic Data Upload request
+****************************************************************************/
+
+typedef struct _MPI2_TOOLBOX_DIAG_DATA_UPLOAD_REQUEST
+{
+    U8                      Tool;                       /* 0x00 */
+    U8                      Reserved1;                  /* 0x01 */
+    U8                      ChainOffset;                /* 0x02 */
+    U8                      Function;                   /* 0x03 */
+    U16                     Reserved2;                  /* 0x04 */
+    U8                      Reserved3;                  /* 0x06 */
+    U8                      MsgFlags;                   /* 0x07 */
+    U8                      VP_ID;                      /* 0x08 */
+    U8                      VF_ID;                      /* 0x09 */
+    U16                     Reserved4;                  /* 0x0A */
+    U8                      SGLFlags;                   /* 0x0C */
+    U8                      Reserved5;                  /* 0x0D */
+    U16                     Reserved6;                  /* 0x0E */
+    U32                     Flags;                      /* 0x10 */
+    U32                     DataLength;                 /* 0x14 */
+    MPI2_SGE_SIMPLE_UNION   SGL;                        /* 0x18 */
+} MPI2_TOOLBOX_DIAG_DATA_UPLOAD_REQUEST,
+  MPI2_POINTER PTR_MPI2_TOOLBOX_DIAG_DATA_UPLOAD_REQUEST,
+  Mpi2ToolboxDiagDataUploadRequest_t,
+  MPI2_POINTER pMpi2ToolboxDiagDataUploadRequest_t;
+
+/* use MPI2_SGLFLAGS_ defines from mpi2.h for the SGLFlags field */
+
+
+typedef struct _MPI2_DIAG_DATA_UPLOAD_HEADER
+{
+    U32                     DiagDataLength;             /* 00h */
+    U8                      FormatCode;                 /* 04h */
+    U8                      Reserved1;                  /* 05h */
+    U16                     Reserved2;                  /* 06h */
+} MPI2_DIAG_DATA_UPLOAD_HEADER, MPI2_POINTER PTR_MPI2_DIAG_DATA_UPLOAD_HEADER,
+  Mpi2DiagDataUploadHeader_t, MPI2_POINTER pMpi2DiagDataUploadHeader_t;
+
+
+/****************************************************************************
 *  Toolbox ISTWI Read Write Tool
 ****************************************************************************/
 
@@ -164,7 +237,7 @@ typedef struct _MPI2_TOOLBOX_ISTWI_READ_WRITE_REQUEST
 #define MPI2_TOOL_ISTWI_ACTION_RELEASE_BUS          (0x11)
 #define MPI2_TOOL_ISTWI_ACTION_RESET                (0x12)
 
-/* values for SGLFlags field are in the SGL section of mpi2.h */
+/* use MPI2_SGLFLAGS_ defines from mpi2.h for the SGLFlags field */
 
 
 /* Toolbox ISTWI Read Write Tool reply message */
@@ -251,7 +324,7 @@ typedef struct _MPI2_TOOLBOX_DIAGNOSTIC_CLI_REQUEST
   Mpi2ToolboxDiagnosticCliRequest_t,
   MPI2_POINTER pMpi2ToolboxDiagnosticCliRequest_t;
 
-/* values for SGLFlags field are in the SGL section of mpi2.h */
+/* use MPI2_SGLFLAGS_ defines from mpi2.h for the SGLFlags field */
 
 
 /* Toolbox Diagnostic CLI Tool reply message */
@@ -319,6 +392,10 @@ typedef struct _MPI2_DIAG_BUFFER_POST_REQUEST
 /* count of the number of buffer types */
 #define MPI2_DIAG_BUF_TYPE_COUNT                    (0x03)
 
+/* values for the Flags field */
+#define MPI2_DIAG_BUF_FLAG_RELEASE_ON_FULL          (0x00000002)
+#define MPI2_DIAG_BUF_FLAG_IMMEDIATE_RELEASE        (0x00000001)
+
 
 /****************************************************************************
 *  Diagnostic Buffer Post reply
similarity index 58%
rename from sys/dev/disk/mps/mpi/mpi2_type.h
rename to sys/dev/raid/mps/mpi/mpi2_type.h
index fca0fa6..0ed736f 100644 (file)
@@ -1,6 +1,35 @@
-/* $FreeBSD: src/sys/dev/mps/mpi/mpi2_type.h,v 1.1 2010/09/10 15:03:56 ken Exp $ */
+/*-
+ * Copyright (c) 2011 LSI Corp.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * LSI MPT-Fusion Host Adapter FreeBSD
+ *
+ * $FreeBSD: src/sys/dev/mps/mpi/mpi2_type.h,v 1.2 2012/01/26 18:17:21 ken Exp $
+ */
+
 /*
- *  Copyright (c) 2000-2007 LSI Corporation.
+ *  Copyright (c) 2000-2011 LSI Corporation.
  *
  *
  *           Name:  mpi2_type.h
similarity index 70%
rename from sys/dev/disk/mps/mps.c
rename to sys/dev/raid/mps/mps.c
index 013cca8..903d51c 100644 (file)
  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  * SUCH DAMAGE.
  *
- * $FreeBSD: src/sys/dev/mps/mps.c,v 1.9 2010/12/10 21:45:10 ken Exp $
+ */
+/*-
+ * Copyright (c) 2011 LSI Corp.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * LSI MPT-Fusion Host Adapter FreeBSD
+ *
+ * $FreeBSD: src/sys/dev/mps/mps.c,v 1.14 2012/01/26 18:17:21 ken Exp $
  */
 
 /* Communications core for LSI MPT2 */
 
+/* TODO Move headers to mpsvar */
 #include <sys/types.h>
 #include <sys/param.h>
 #include <sys/systm.h>
 #include <sys/kernel.h>
 #include <sys/lock.h>
-#include <sys/mutex.h>
+#include <sys/globaldata.h>
 #include <sys/module.h>
 #include <sys/bus.h>
 #include <sys/conf.h>
 #include <sys/malloc.h>
 #include <sys/uio.h>
 #include <sys/sysctl.h>
+#include <sys/queue.h>
+#include <sys/kthread.h>
 #include <sys/endian.h>
+#include <sys/eventhandler.h>
 
 #include <sys/rman.h>
 
-#include <bus/cam/scsi/scsi_all.h>
+#include <bus/pci/pcivar.h>
 
-#include <dev/disk/mps/mpi/mpi2_type.h>
-#include <dev/disk/mps/mpi/mpi2.h>
-#include <dev/disk/mps/mpi/mpi2_ioc.h>
-#include <dev/disk/mps/mpi/mpi2_cnfg.h>
-#include <dev/disk/mps/mpsvar.h>
-#include <dev/disk/mps/mps_table.h>
+#include <bus/cam/scsi/scsi_all.h>
 
+#include <dev/raid/mps/mpi/mpi2_type.h>
+#include <dev/raid/mps/mpi/mpi2.h>
+#include <dev/raid/mps/mpi/mpi2_ioc.h>
+#include <dev/raid/mps/mpi/mpi2_sas.h>
+#include <dev/raid/mps/mpi/mpi2_cnfg.h>
+#include <dev/raid/mps/mpi/mpi2_init.h>
+#include <dev/raid/mps/mpi/mpi2_tool.h>
+#include <dev/raid/mps/mps_ioctl.h>
+#include <dev/raid/mps/mpsvar.h>
+#include <dev/raid/mps/mps_table.h>
+
+static int mps_diag_reset(struct mps_softc *sc);
+static int mps_init_queues(struct mps_softc *sc);
+static int mps_message_unit_reset(struct mps_softc *sc);
+static int mps_transition_operational(struct mps_softc *sc);
 static void mps_startup(void *arg);
-static void mps_startup_complete(struct mps_softc *sc, struct mps_command *cm);
 static int mps_send_iocinit(struct mps_softc *sc);
 static int mps_attach_log(struct mps_softc *sc);
-static void mps_dispatch_event(struct mps_softc *sc, uintptr_t data, MPI2_EVENT_NOTIFICATION_REPLY *reply);
+static __inline void mps_complete_command(struct mps_command *cm);
+static void mps_dispatch_event(struct mps_softc *sc, uintptr_t data,
+    MPI2_EVENT_NOTIFICATION_REPLY *reply);
 static void mps_config_complete(struct mps_softc *sc, struct mps_command *cm);
 static void mps_periodic(void *);
+static int mps_reregister_events(struct mps_softc *sc);
+static void mps_enqueue_request(struct mps_softc *sc, struct mps_command *cm);
 
 SYSCTL_NODE(_hw, OID_AUTO, mps, CTLFLAG_RD, 0, "MPS Driver Parameters");
 
@@ -73,7 +118,7 @@ MALLOC_DEFINE(M_MPT2, "mps", "mpt2 driver memory");
 static char mpt2_reset_magic[] = { 0x00, 0x0f, 0x04, 0x0b, 0x02, 0x07, 0x0d };
 
 static int
-mps_hard_reset(struct mps_softc *sc)
+mps_diag_reset(struct mps_softc *sc)
 {
        uint32_t reg;
        int i, error, tries = 0;
@@ -124,7 +169,7 @@ mps_hard_reset(struct mps_softc *sc)
 }
 
 static int
-mps_soft_reset(struct mps_softc *sc)
+mps_message_unit_reset(struct mps_softc *sc)
 {
 
        mps_dprint(sc, MPS_TRACE, "%s\n", __func__);
@@ -155,7 +200,7 @@ mps_transition_ready(struct mps_softc *sc)
                 * resetting it.
                 */
                if (reg & MPI2_DOORBELL_USED) {
-                       mps_hard_reset(sc);
+                       mps_diag_reset(sc);
                        DELAY(50000);
                        continue;
                }
@@ -176,10 +221,10 @@ mps_transition_ready(struct mps_softc *sc)
                } else if (state == MPI2_IOC_STATE_FAULT) {
                        mps_dprint(sc, MPS_INFO, "IOC in fault state 0x%x\n",
                            state & MPI2_DOORBELL_FAULT_CODE_MASK);
-                       mps_hard_reset(sc);
+                       mps_diag_reset(sc);
                } else if (state == MPI2_IOC_STATE_OPERATIONAL) {
                        /* Need to take ownership */
-                       mps_soft_reset(sc);
+                       mps_message_unit_reset(sc);
                } else if (state == MPI2_IOC_STATE_RESET) {
                        /* Wait a bit, IOC might be in transition */
                        mps_dprint(sc, MPS_FAULT,
@@ -215,14 +260,108 @@ mps_transition_operational(struct mps_softc *sc)
 
        state = reg & MPI2_IOC_STATE_MASK;
        if (state != MPI2_IOC_STATE_READY) {
-               if ((error = mps_transition_ready(sc)) != 0)
+               if ((error = mps_transition_ready(sc)) != 0) {
+                       mps_dprint(sc, MPS_FAULT,
+                           "%s failed to transition ready\n", __func__);
                        return (error);
+               }
        }
 
        error = mps_send_iocinit(sc);
        return (error);
 }
 
+/*
+ * XXX Some of this should probably move to mps.c
+ *
+ * The terms diag reset and hard reset are used interchangeably in the MPI
+ * docs to mean resetting the controller chip.  In this code diag reset
+ * cleans everything up, and the hard reset function just sends the reset
+ * sequence to the chip.  This should probably be refactored so that every
+ * subsystem gets a reset notification of some sort, and can clean up
+ * appropriately.
+ */
+int
+mps_reinit(struct mps_softc *sc)
+{
+       int error;
+       uint32_t db;
+
+       mps_printf(sc, "%s sc %p\n", __func__, sc);
+
+       KKASSERT(lockstatus(&sc->mps_lock, curthread) != 0);
+
+       if (sc->mps_flags & MPS_FLAGS_DIAGRESET) {
+               mps_printf(sc, "%s reset already in progress\n", __func__);
+               return 0;
+       }
+
+       /* make sure the completion callbacks can recognize they're getting
+        * a NULL cm_reply due to a reset.
+        */
+       sc->mps_flags |= MPS_FLAGS_DIAGRESET;
+
+       mps_printf(sc, "%s mask interrupts\n", __func__);
+       mps_mask_intr(sc);
+
+       error = mps_diag_reset(sc);
+       if (error != 0) {
+               panic("%s hard reset failed with error %d\n",
+                   __func__, error);
+       }
+
+       /* Restore the PCI state, including the MSI-X registers */
+       mps_pci_restore(sc);
+
+       /* Give the I/O subsystem special priority to get itself prepared */
+       mpssas_handle_reinit(sc);
+
+       /* reinitialize queues after the reset */
+       bzero(sc->free_queue, sc->fqdepth * 4);
+       mps_init_queues(sc);
+
+       /* get the chip out of the reset state */
+       error = mps_transition_operational(sc);
+       if (error != 0)
+               panic("%s transition operational failed with error %d\n",
+                   __func__, error);
+
+       /* Reinitialize the reply queue. This is delicate because this
+        * function is typically invoked by task mgmt completion callbacks,
+        * which are called by the interrupt thread.  We need to make sure
+        * the interrupt handler loop will exit when we return to it, and
+        * that it will recognize the indexes we've changed.
+        */
+       sc->replypostindex = 0;
+       mps_regwrite(sc, MPI2_REPLY_FREE_HOST_INDEX_OFFSET, sc->replyfreeindex);
+       mps_regwrite(sc, MPI2_REPLY_POST_HOST_INDEX_OFFSET, sc->replypostindex);
+
+       db = mps_regread(sc, MPI2_DOORBELL_OFFSET);
+       mps_printf(sc, "%s doorbell 0x%08x\n", __func__, db);
+
+       mps_printf(sc, "%s unmask interrupts post %u free %u\n", __func__,
+           sc->replypostindex, sc->replyfreeindex);
+
+       mps_unmask_intr(sc);
+
+       mps_printf(sc, "%s restarting post %u free %u\n", __func__,
+           sc->replypostindex, sc->replyfreeindex);
+
+       /* restart will reload the event masks clobbered by the reset, and
+        * then enable the port.
+        */
+       mps_reregister_events(sc);
+
+       /* the end of discovery will release the simq, so we're done. */
+       mps_printf(sc, "%s finished sc %p post %u free %u\n",
+           __func__, sc,
+           sc->replypostindex, sc->replyfreeindex);
+
+       sc->mps_flags &= ~MPS_FLAGS_DIAGRESET;
+
+       return 0;
+}
+
 /* Wait for the chip to ACK a word that we've put into its FIFO */
 static int
 mps_wait_db_ack(struct mps_softc *sc)
@@ -377,11 +516,18 @@ mps_request_sync(struct mps_softc *sc, void *req, MPI2_DEFAULT_REPLY *reply,
        return (0);
 }
 
-void
+static void
 mps_enqueue_request(struct mps_softc *sc, struct mps_command *cm)
 {
 
-       mps_dprint(sc, MPS_TRACE, "%s\n", __func__);
+       mps_dprint(sc, MPS_TRACE, "%s SMID %u cm %p ccb %p\n", __func__,
+           cm->cm_desc.Default.SMID, cm, cm->cm_ccb);
+
+       if (sc->mps_flags & MPS_FLAGS_ATTACH_DONE)
+               KKASSERT(lockstatus(&sc->mps_lock, curthread) != 0);
+
+       if (++sc->io_cmds_active > sc->io_cmds_highwater)
+               sc->io_cmds_highwater++;
 
        mps_regwrite(sc, MPI2_REQUEST_DESCRIPTOR_POST_LOW_OFFSET,
            cm->cm_desc.Words.Low);
@@ -389,30 +535,6 @@ mps_enqueue_request(struct mps_softc *sc, struct mps_command *cm)
            cm->cm_desc.Words.High);
 }
 
-int
-mps_request_polled(struct mps_softc *sc, struct mps_command *cm)
-{
-       int error, timeout = 0;
-
-       error = 0;
-
-       cm->cm_flags |= MPS_CM_FLAGS_POLLED;
-       cm->cm_complete = NULL;
-       mps_map_command(sc, cm);
-
-       while ((cm->cm_flags & MPS_CM_FLAGS_COMPLETE) == 0) {
-               mps_intr(sc);
-               DELAY(50 * 1000);
-               if (timeout++ > 1000) {
-                       mps_dprint(sc, MPS_FAULT, "polling failed\n");
-                       error = ETIMEDOUT;
-                       break;
-               }
-       }
-
-       return (error);
-}
-
 /*
  * Just the FACTS, ma'am.
  */
@@ -455,9 +577,19 @@ mps_get_portfacts(struct mps_softc *sc, MPI2_PORT_FACTS_REPLY *facts, int port)
        cm->cm_data = NULL;
        error = mps_request_polled(sc, cm);
        reply = (MPI2_PORT_FACTS_REPLY *)cm->cm_reply;
-       if ((reply->IOCStatus & MPI2_IOCSTATUS_MASK) != MPI2_IOCSTATUS_SUCCESS)
+       if (reply == NULL) {
+               mps_printf(sc, "%s NULL reply\n", __func__);
+               goto done;
+       }
+       if ((reply->IOCStatus & MPI2_IOCSTATUS_MASK) != MPI2_IOCSTATUS_SUCCESS) {
+               mps_printf(sc,
+                   "%s error %d iocstatus 0x%x iocloginfo 0x%x type 0x%x\n",
+                   __func__, error, reply->IOCStatus, (u_int)reply->IOCLogInfo,
+                   reply->PortType);
                error = ENXIO;
+       }
        bcopy(reply, facts, sizeof(MPI2_PORT_FACTS_REPLY));
+done:
        mps_free_command(sc, cm);
 
        return (error);
@@ -508,35 +640,6 @@ mps_send_iocinit(struct mps_softc *sc)
        return (error);
 }
 
-static int
-mps_send_portenable(struct mps_softc *sc)
-{
-       MPI2_PORT_ENABLE_REQUEST *request;
-       struct mps_command *cm;
-
-       mps_dprint(sc, MPS_TRACE, "%s\n", __func__);
-
-       if ((cm = mps_alloc_command(sc)) == NULL)
-               return (EBUSY);
-       request = (MPI2_PORT_ENABLE_REQUEST *)cm->cm_req;
-       request->Function = MPI2_FUNCTION_PORT_ENABLE;
-       request->MsgFlags = 0;
-       request->VP_ID = 0;
-       cm->cm_desc.Default.RequestFlags = MPI2_REQ_DESCRIPT_FLAGS_DEFAULT_TYPE;
-       cm->cm_complete = mps_startup_complete;
-
-       mps_enqueue_request(sc, cm);
-       return (0);
-}
-
-static int
-mps_send_mur(struct mps_softc *sc)
-{
-
-       /* Placeholder */
-       return (0);
-}
-
 void
 mps_memaddr_cb(void *arg, bus_dma_segment_t *segs, int nsegs, int error)
 {
@@ -668,7 +771,7 @@ mps_alloc_requests(struct mps_softc *sc)
         bus_dmamap_load(sc->req_dmat, sc->req_map, sc->req_frames, rsize,
            mps_memaddr_cb, &sc->req_busaddr, 0);
 
-       rsize = sc->facts->IOCRequestFrameSize * MPS_CHAIN_FRAMES * 4;
+       rsize = sc->facts->IOCRequestFrameSize * sc->max_chains * 4;
         if (bus_dma_tag_create( sc->mps_parent_dmat,    /* parent */
                                16, 0,                  /* algnmnt, boundary */
                                BUS_SPACE_MAXADDR_32BIT,/* lowaddr */
@@ -714,15 +817,16 @@ mps_alloc_requests(struct mps_softc *sc)
         bus_dmamap_load(sc->sense_dmat, sc->sense_map, sc->sense_frames, rsize,
            mps_memaddr_cb, &sc->sense_busaddr, 0);
 
-       sc->chains = kmalloc(sizeof(struct mps_chain) * MPS_CHAIN_FRAMES,
-           M_MPT2, M_WAITOK | M_ZERO);
-       for (i = 0; i < MPS_CHAIN_FRAMES; i++) {
+       sc->chains = kmalloc(sizeof(struct mps_chain) * sc->max_chains, M_MPT2,
+           M_WAITOK | M_ZERO);
+       for (i = 0; i < sc->max_chains; i++) {
                chain = &sc->chains[i];
                chain->chain = (MPI2_SGE_IO_UNION *)(sc->chain_frames +
                    i * sc->facts->IOCRequestFrameSize * 4);
                chain->chain_busaddr = sc->chain_busaddr +
                    i * sc->facts->IOCRequestFrameSize * 4;
                mps_free_chain(sc, chain);
+               sc->chain_free_lowwater++;
        }
 
        /* XXX Need to pick a more precise value */
@@ -737,7 +841,7 @@ mps_alloc_requests(struct mps_softc *sc)
                                 BUS_SPACE_MAXSIZE_32BIT,/* maxsegsize */
                                 BUS_DMA_ALLOCNOW,      /* flags */
                                 &sc->buffer_dmat)) {
-               device_printf(sc->mps_dev, "Cannot allocate sense DMA tag\n");
+               device_printf(sc->mps_dev, "Cannot allocate buffer DMA tag\n");
                return (ENOMEM);
         }
 
@@ -762,8 +866,12 @@ mps_alloc_requests(struct mps_softc *sc)
 
                /* XXX Is a failure here a critical problem? */
                if (bus_dmamap_create(sc->buffer_dmat, 0, &cm->cm_dmamap) == 0)
-                       mps_free_command(sc, cm);
+                       if (i <= sc->facts->HighPriorityCredit)
+                               mps_free_high_priority_command(sc, cm);
+                       else
+                               mps_free_command(sc, cm);
                else {
+                       panic("failed to allocate command %d\n", i);
                        sc->num_reqs = i;
                        break;
                }
@@ -797,28 +905,59 @@ mps_init_queues(struct mps_softc *sc)
        return (0);
 }
 
-int
-mps_attach(struct mps_softc *sc)
+/* Get the driver parameter tunables.  Lowest priority are the driver defaults.
+ * Next are the global settings, if they exist.  Highest are the per-unit
+ * settings, if they exist.
+ */
+static void
+mps_get_tunables(struct mps_softc *sc)
 {
-       int i, error;
-       char tmpstr[80], tmpstr2[80];
+       char tmpstr[80];
+
+       /* XXX default to some debugging for now */
+       sc->mps_debug = MPS_FAULT;
+#if 0 /* XXX swildner */
+       sc->disable_msix = 0;
+#endif
+       sc->enable_msi = 1;
+       sc->max_chains = MPS_CHAIN_FRAMES;
 
        /*
-        * Grab any tunable-set debug level so that tracing works as early
-        * as possible.
+        * Grab the global variables.
         */
-       ksnprintf(tmpstr, sizeof(tmpstr), "hw.mps.%d.debug_level",
+       TUNABLE_INT_FETCH("hw.mps.debug_level", &sc->mps_debug);
+#if 0 /* XXX swildner */
+       TUNABLE_INT_FETCH("hw.mps.disable_msix", &sc->disable_msix);
+#endif
+       TUNABLE_INT_FETCH("hw.mps.msi.enable", &sc->enable_msi);
+       TUNABLE_INT_FETCH("hw.mps.max_chains", &sc->max_chains);
+
+       /* Grab the unit-instance variables */
+       ksnprintf(tmpstr, sizeof(tmpstr), "dev.mps.%d.debug_level",
            device_get_unit(sc->mps_dev));
        TUNABLE_INT_FETCH(tmpstr, &sc->mps_debug);
-       ksnprintf(tmpstr, sizeof(tmpstr), "hw.mps.%d.allow_multiple_tm_cmds",
+
+#if 0 /* XXX swildner */
+       ksnprintf(tmpstr, sizeof(tmpstr), "dev.mps.%d.disable_msix",
            device_get_unit(sc->mps_dev));
-       TUNABLE_INT_FETCH(tmpstr, &sc->allow_multiple_tm_cmds);
+       TUNABLE_INT_FETCH(tmpstr, &sc->disable_msix);
+#endif
 
-       mps_dprint(sc, MPS_TRACE, "%s\n", __func__);
+       ksnprintf(tmpstr, sizeof(tmpstr), "dev.mps.%d.enable_msi",
+           device_get_unit(sc->mps_dev));
+       TUNABLE_INT_FETCH(tmpstr, &sc->enable_msi);
 
-       lockinit(&sc->mps_lock, "MPT2SAS lock", 0, LK_CANRECURSE);
-       callout_init(&sc->periodic);
-       TAILQ_INIT(&sc->event_list);
+       ksnprintf(tmpstr, sizeof(tmpstr), "dev.mps.%d.max_chains",
+           device_get_unit(sc->mps_dev));
+       TUNABLE_INT_FETCH(tmpstr, &sc->max_chains);
+}
+
+static void
+mps_setup_sysctl(struct mps_softc *sc)
+{
+       struct sysctl_ctx_list  *sysctl_ctx = NULL;
+       struct sysctl_oid       *sysctl_tree = NULL;
+       char tmpstr[80], tmpstr2[80];
 
        /*
         * Setup the sysctl variable so the user can change the debug level
@@ -830,22 +969,79 @@ mps_attach(struct mps_softc *sc)
 
        sysctl_ctx_init(&sc->sysctl_ctx);
        sc->sysctl_tree = SYSCTL_ADD_NODE(&sc->sysctl_ctx,
-           SYSCTL_STATIC_CHILDREN(_hw_mps), OID_AUTO, tmpstr2, CTLFLAG_RD,
-           0, tmpstr);
+           SYSCTL_STATIC_CHILDREN(_hw_mps), OID_AUTO, tmpstr2,
+           CTLFLAG_RD, 0, tmpstr);
        if (sc->sysctl_tree == NULL)
-               return (ENOMEM);
+               return;
+       sysctl_ctx = &sc->sysctl_ctx;
+       sysctl_tree = sc->sysctl_tree;
 
-       SYSCTL_ADD_INT(&sc->sysctl_ctx, SYSCTL_CHILDREN(sc->sysctl_tree),
+       SYSCTL_ADD_INT(sysctl_ctx, SYSCTL_CHILDREN(sysctl_tree),
            OID_AUTO, "debug_level", CTLFLAG_RW, &sc->mps_debug, 0,
            "mps debug level");
 
-       SYSCTL_ADD_INT(&sc->sysctl_ctx, SYSCTL_CHILDREN(sc->sysctl_tree),
-           OID_AUTO, "allow_multiple_tm_cmds", CTLFLAG_RW,
-           &sc->allow_multiple_tm_cmds, 0,
-           "allow multiple simultaneous task management cmds");
+#if 0 /* XXX swildner */
+       SYSCTL_ADD_INT(sysctl_ctx, SYSCTL_CHILDREN(sysctl_tree),
+           OID_AUTO, "disable_msix", CTLFLAG_RD, &sc->disable_msix, 0,
+           "Disable the use of MSI-X interrupts");
+#endif
+
+       SYSCTL_ADD_INT(sysctl_ctx, SYSCTL_CHILDREN(sysctl_tree),
+           OID_AUTO, "enable_msi", CTLFLAG_RD, &sc->enable_msi, 0,
+           "Enable the use of MSI interrupts");
+
+       SYSCTL_ADD_STRING(sysctl_ctx, SYSCTL_CHILDREN(sysctl_tree),
+           OID_AUTO, "firmware_version", CTLFLAG_RW, &sc->fw_version,
+           strlen(sc->fw_version), "firmware version");
+
+       SYSCTL_ADD_STRING(sysctl_ctx, SYSCTL_CHILDREN(sysctl_tree),
+           OID_AUTO, "driver_version", CTLFLAG_RW, MPS_DRIVER_VERSION,
+           strlen(MPS_DRIVER_VERSION), "driver version");
+
+       SYSCTL_ADD_INT(sysctl_ctx, SYSCTL_CHILDREN(sysctl_tree),
+           OID_AUTO, "io_cmds_active", CTLFLAG_RD,
+           &sc->io_cmds_active, 0, "number of currently active commands");
+
+       SYSCTL_ADD_INT(sysctl_ctx, SYSCTL_CHILDREN(sysctl_tree),
+           OID_AUTO, "io_cmds_highwater", CTLFLAG_RD,
+           &sc->io_cmds_highwater, 0, "maximum active commands seen");
+
+       SYSCTL_ADD_INT(sysctl_ctx, SYSCTL_CHILDREN(sysctl_tree),
+           OID_AUTO, "chain_free", CTLFLAG_RD,
+           &sc->chain_free, 0, "number of free chain elements");
+
+       SYSCTL_ADD_INT(sysctl_ctx, SYSCTL_CHILDREN(sysctl_tree),
+           OID_AUTO, "chain_free_lowwater", CTLFLAG_RD,
+           &sc->chain_free_lowwater, 0,"lowest number of free chain elements");
+
+       SYSCTL_ADD_INT(sysctl_ctx, SYSCTL_CHILDREN(sysctl_tree),
+           OID_AUTO, "max_chains", CTLFLAG_RD,
+           &sc->max_chains, 0,"maximum chain frames that will be allocated");
+
+#if __FreeBSD_version >= 900030
+       SYSCTL_ADD_UQUAD(sysctl_ctx, SYSCTL_CHILDREN(sysctl_tree),
+           OID_AUTO, "chain_alloc_fail", CTLFLAG_RD,
+           &sc->chain_alloc_fail, "chain allocation failures");
+#endif //FreeBSD_version >= 900030
+}
+
+int
+mps_attach(struct mps_softc *sc)
+{
+       int i, error;
+
+       mps_get_tunables(sc);
 
-       if ((error = mps_transition_ready(sc)) != 0)
+       mps_dprint(sc, MPS_TRACE, "%s\n", __func__);
+
+       lockinit(&sc->mps_lock, "MPT2SAS lock", 0, LK_CANRECURSE);
+       callout_init(&sc->periodic);
+       TAILQ_INIT(&sc->event_list);
+
+       if ((error = mps_transition_ready(sc)) != 0) {
+               mps_printf(sc, "%s failed to transition ready\n", __func__);
                return (error);
+       }
 
        sc->facts = kmalloc(sizeof(MPI2_IOC_FACTS_REPLY), M_MPT2,
            M_ZERO|M_NOWAIT);
@@ -854,13 +1050,16 @@ mps_attach(struct mps_softc *sc)
 
        mps_print_iocfacts(sc, sc->facts);
 
-       mps_printf(sc, "Firmware: %02d.%02d.%02d.%02d\n",
+       ksnprintf(sc->fw_version, sizeof(sc->fw_version),
+           "%02d.%02d.%02d.%02d",
            sc->facts->FWVersion.Struct.Major,
            sc->facts->FWVersion.Struct.Minor,
            sc->facts->FWVersion.Struct.Unit,
            sc->facts->FWVersion.Struct.Dev);
-       mps_printf(sc, "IOCCapabilities: %b\n",
-           (u_int)(sc->facts->IOCCapabilities),
+
+       mps_printf(sc, "Firmware: %s, Driver: %s\n", sc->fw_version,
+           MPS_DRIVER_VERSION);
+       mps_printf(sc, "IOCCapabilities: %b\n", (int)sc->facts->IOCCapabilities,
            "\20" "\3ScsiTaskFull" "\4DiagTrace" "\5SnapBuf" "\6ExtBuf"
            "\7EEDP" "\10BiDirTarg" "\11Multicast" "\14TransRetry" "\15IR"
            "\16EventReplay" "\17RaidAccel" "\20MSIXIndex" "\21HostDisc");
@@ -873,12 +1072,44 @@ mps_attach(struct mps_softc *sc)
         */
        if ((sc->facts->IOCCapabilities &
            MPI2_IOCFACTS_CAPABILITY_EVENT_REPLAY) == 0) {
-               mps_hard_reset(sc);
+               mps_diag_reset(sc);
                if ((error = mps_transition_ready(sc)) != 0)
                        return (error);
        }
 
        /*
+        * Set flag if IR Firmware is loaded.
+        */
+       if (sc->facts->IOCCapabilities &
+           MPI2_IOCFACTS_CAPABILITY_INTEGRATED_RAID)
+               sc->ir_firmware = 1;
+
+       /*
+        * Check if controller supports FW diag buffers and set flag to enable
+        * each type.
+        */
+       if (sc->facts->IOCCapabilities &
+           MPI2_IOCFACTS_CAPABILITY_DIAG_TRACE_BUFFER)
+               sc->fw_diag_buffer_list[MPI2_DIAG_BUF_TYPE_TRACE].enabled =
+                   TRUE;
+       if (sc->facts->IOCCapabilities &
+           MPI2_IOCFACTS_CAPABILITY_SNAPSHOT_BUFFER)
+               sc->fw_diag_buffer_list[MPI2_DIAG_BUF_TYPE_SNAPSHOT].enabled =
+                   TRUE;
+       if (sc->facts->IOCCapabilities &
+           MPI2_IOCFACTS_CAPABILITY_EXTENDED_BUFFER)
+               sc->fw_diag_buffer_list[MPI2_DIAG_BUF_TYPE_EXTENDED].enabled =
+                   TRUE;
+
+       /*
+        * Set flag if EEDP is supported and if TLR is supported.
+        */
+       if (sc->facts->IOCCapabilities & MPI2_IOCFACTS_CAPABILITY_EEDP)
+               sc->eedp_enabled = TRUE;
+       if (sc->facts->IOCCapabilities & MPI2_IOCFACTS_CAPABILITY_TLR)
+               sc->control_TLR = TRUE;
+
+       /*
         * Size the queues. Since the reply queues always need one free entry,
         * we'll just deduct one reply message here.
         */
@@ -886,18 +1117,21 @@ mps_attach(struct mps_softc *sc)
        sc->num_replies = MIN(MPS_REPLY_FRAMES + MPS_EVT_REPLY_FRAMES,
            sc->facts->MaxReplyDescriptorPostQueueDepth) - 1;
        TAILQ_INIT(&sc->req_list);
+       TAILQ_INIT(&sc->high_priority_req_list);
        TAILQ_INIT(&sc->chain_list);
        TAILQ_INIT(&sc->tm_list);
 
        if (((error = mps_alloc_queues(sc)) != 0) ||
            ((error = mps_alloc_replies(sc)) != 0) ||
            ((error = mps_alloc_requests(sc)) != 0)) {
+               mps_printf(sc, "%s failed to alloc\n", __func__);
                mps_free(sc);
                return (error);
        }
 
        if (((error = mps_init_queues(sc)) != 0) ||
            ((error = mps_transition_operational(sc)) != 0)) {
+               mps_printf(sc, "%s failed to transition operational\n", __func__);
                mps_free(sc);
                return (error);
        }
@@ -920,6 +1154,8 @@ mps_attach(struct mps_softc *sc)
            sc->facts->NumberOfPorts, M_MPT2, M_ZERO|M_WAITOK);
        for (i = 0; i < sc->facts->NumberOfPorts; i++) {
                if ((error = mps_get_portfacts(sc, &sc->pfacts[i], i)) != 0) {
+                       mps_printf(sc, "%s failed to get portfacts for port %d\n",
+                           __func__, i);
                        mps_free(sc);
                        return (error);
                }
@@ -938,10 +1174,17 @@ mps_attach(struct mps_softc *sc)
        }
 
        if ((error = mps_pci_setup_interrupts(sc)) != 0) {
+               mps_printf(sc, "%s failed to setup interrupts\n", __func__);
                mps_free(sc);
                return (error);
        }
 
+       /*
+        * The static page function currently read is ioc page8.  Others can be
+        * added in future.
+        */
+       mps_base_static_config_pages(sc);
+
        /* Start the periodic watchdog check on the IOC Doorbell */
        mps_periodic(sc);
 
@@ -957,9 +1200,24 @@ mps_attach(struct mps_softc *sc)
                error = EINVAL;
        }
 
+       /*
+        * Allow IR to shutdown gracefully when shutdown occurs.
+        */
+       sc->shutdown_eh = EVENTHANDLER_REGISTER(shutdown_final,
+           mpssas_ir_shutdown, sc, SHUTDOWN_PRI_DEFAULT);
+
+       if (sc->shutdown_eh == NULL)
+               mps_dprint(sc, MPS_FAULT, "shutdown event registration "
+                   "failed\n");
+
+       mps_setup_sysctl(sc);
+
+       sc->mps_flags |= MPS_FLAGS_ATTACH_DONE;
+
        return (error);
 }
 
+/* Run through any late-start handlers. */
 static void
 mps_startup(void *arg)
 {
@@ -969,7 +1227,9 @@ mps_startup(void *arg)
 
        mps_lock(sc);
        mps_unmask_intr(sc);
-       mps_send_portenable(sc);
+       /* initialize device mapping tables */
+       mps_mapping_initialize(sc);
+       mpssas_startup(sc);
        mps_unlock(sc);
 }
 
@@ -981,39 +1241,21 @@ mps_periodic(void *arg)
        uint32_t db;
 
        sc = (struct mps_softc *)arg;
-       if (sc->mps_flags & MPS_FLAGS_SHUTDOWN)
+       mps_lock(sc);
+       if (sc->mps_flags & MPS_FLAGS_SHUTDOWN) {
+               mps_unlock(sc);
                return;
+       }
 
        db = mps_regread(sc, MPI2_DOORBELL_OFFSET);
        if ((db & MPI2_IOC_STATE_MASK) == MPI2_IOC_STATE_FAULT) {
                device_printf(sc->mps_dev, "IOC Fault 0x%08x, Resetting\n", db);
-               /* XXX Need to broaden this to re-initialize the chip */
-               mps_hard_reset(sc);
-               db = mps_regread(sc, MPI2_DOORBELL_OFFSET);
-               if ((db & MPI2_IOC_STATE_MASK) == MPI2_IOC_STATE_FAULT) {
-                       device_printf(sc->mps_dev, "Second IOC Fault 0x%08x, "
-                           "Giving up!\n", db);
-                       return;
-               }
+
+               mps_reinit(sc);
        }
 
        callout_reset(&sc->periodic, MPS_PERIODIC_DELAY * hz, mps_periodic, sc);
-}
-
-static void
-mps_startup_complete(struct mps_softc *sc, struct mps_command *cm)
-{
-       MPI2_PORT_ENABLE_REPLY *reply;
-
-       mps_dprint(sc, MPS_TRACE, "%s\n", __func__);
-
-       reply = (MPI2_PORT_ENABLE_REPLY *)cm->cm_reply;
-       if ((reply->IOCStatus & MPI2_IOCSTATUS_MASK) != MPI2_IOCSTATUS_SUCCESS)
-               mps_dprint(sc, MPS_FAULT, "Portenable failed\n");
-
-       mps_free_command(sc, cm);
-       config_intrhook_disestablish(&sc->mps_ich);
-
+       mps_unlock(sc);
 }
 
 static void
@@ -1082,6 +1324,8 @@ mps_free(struct mps_softc *sc)
 #if 0 /* XXX swildner */
        /* Lock must not be held for this */
        callout_drain(&sc->periodic);
+#else
+       callout_stop(&sc->periodic);
 #endif
 
        if (((error = mps_detach_log(sc)) != 0) ||
@@ -1090,7 +1334,7 @@ mps_free(struct mps_softc *sc)
 
        /* Put the IOC back in the READY state. */
        mps_lock(sc);
-       if ((error = mps_send_mur(sc)) != 0) {
+       if ((error = mps_transition_ready(sc)) != 0) {
                mps_unlock(sc);
                return (error);
        }
@@ -1153,11 +1397,45 @@ mps_free(struct mps_softc *sc)
        if (sc->sysctl_tree != NULL)
                sysctl_ctx_free(&sc->sysctl_ctx);
 
+       mps_mapping_free_memory(sc);
+
+       /* Deregister the shutdown function */
+       if (sc->shutdown_eh != NULL)
+               EVENTHANDLER_DEREGISTER(shutdown_final, sc->shutdown_eh);
+
        lockuninit(&sc->mps_lock);
 
        return (0);
 }
 
+static __inline void
+mps_complete_command(struct mps_command *cm)
+{
+       if (cm->cm_flags & MPS_CM_FLAGS_POLLED)
+               cm->cm_flags |= MPS_CM_FLAGS_COMPLETE;
+
+       if (cm->cm_complete != NULL) {
+               mps_dprint(cm->cm_sc, MPS_TRACE,
+                          "%s cm %p calling cm_complete %p data %p reply %p\n",
+                          __func__, cm, cm->cm_complete, cm->cm_complete_data,
+                          cm->cm_reply);
+               cm->cm_complete(cm->cm_sc, cm);
+       }
+
+       if (cm->cm_flags & MPS_CM_FLAGS_WAKEUP) {
+               mps_dprint(cm->cm_sc, MPS_TRACE, "%s: waking up %p\n",
+                          __func__, cm);
+               wakeup(cm);
+       }
+
+       if (cm->cm_sc->io_cmds_active != 0) {
+               cm->cm_sc->io_cmds_active--;
+       } else {
+               mps_dprint(cm->cm_sc, MPS_INFO, "Warning: io_cmds_active is "
+                   "out of sync - resynching to 0\n");
+       }
+}
+
 void
 mps_intr(void *data)
 {
@@ -1191,6 +1469,7 @@ mps_intr_msi(void *data)
        struct mps_softc *sc;
 
        sc = (struct mps_softc *)data;
+       mps_dprint(sc, MPS_TRACE, "%s\n", __func__);
        mps_lock(sc);
        mps_intr_locked(data);
        mps_unlock(sc);
@@ -1208,20 +1487,35 @@ mps_intr_locked(void *data)
        struct mps_command *cm = NULL;
        uint8_t flags;
        u_int pq;
+       MPI2_DIAG_RELEASE_REPLY *rel_rep;
+       mps_fw_diagnostic_buffer_t *pBuffer;
 
        sc = (struct mps_softc *)data;
 
        pq = sc->replypostindex;
+       mps_dprint(sc, MPS_TRACE,
+           "%s sc %p starting with replypostindex %u\n",
+           __func__, sc, sc->replypostindex);
 
        for ( ;; ) {
                cm = NULL;
-               desc = &sc->post_queue[pq];
+               desc = &sc->post_queue[sc->replypostindex];
                flags = desc->Default.ReplyFlags &
                    MPI2_RPY_DESCRIPT_FLAGS_TYPE_MASK;
                if ((flags == MPI2_RPY_DESCRIPT_FLAGS_UNUSED)
                 || (desc->Words.High == 0xffffffff))
                        break;
 
+               /* increment the replypostindex now, so that event handlers
+                * and cm completion handlers which decide to do a diag
+                * reset can zero it without it getting incremented again
+                * afterwards, and we break out of this loop on the next
+                * iteration since the reply post queue has been cleared to
+                * 0xFF and all descriptors look unused (which they are).
+                */
+               if (++sc->replypostindex >= sc->pqdepth)
+                       sc->replypostindex = 0;
+
                switch (flags) {
                case MPI2_RPY_DESCRIPT_FLAGS_SCSI_IO_SUCCESS:
                        cm = &sc->commands[desc->SCSIIOSuccess.SMID];
@@ -1263,8 +1557,32 @@ mps_intr_locked(void *data)
                                panic("Reply address out of range");
                        }
                        if (desc->AddressReply.SMID == 0) {
-                               mps_dispatch_event(sc, baddr,
-                                  (MPI2_EVENT_NOTIFICATION_REPLY *) reply);
+                               if (((MPI2_DEFAULT_REPLY *)reply)->Function ==
+                                   MPI2_FUNCTION_DIAG_BUFFER_POST) {
+                                       /*
+                                        * If SMID is 0 for Diag Buffer Post,
+                                        * this implies that the reply is due to
+                                        * a release function with a status that
+                                        * the buffer has been released.  Set
+                                        * the buffer flags accordingly.
+                                        */
+                                       rel_rep =
+                                           (MPI2_DIAG_RELEASE_REPLY *)reply;
+                                       if (rel_rep->IOCStatus ==
+                                           MPI2_IOCSTATUS_DIAGNOSTIC_RELEASED)
+                                           {
+                                               pBuffer =
+                                                   &sc->fw_diag_buffer_list[
+                                                   rel_rep->BufferType];
+                                               pBuffer->valid_data = TRUE;
+                                               pBuffer->owned_by_firmware =
+                                                   FALSE;
+                                               pBuffer->immediate = FALSE;
+                                       }
+                               } else
+                                       mps_dispatch_event(sc, baddr,
+                                           (MPI2_EVENT_NOTIFICATION_REPLY *)
+                                           reply);
                        } else {
                                cm = &sc->commands[desc->AddressReply.SMID];
                                cm->cm_reply = reply;
@@ -1284,27 +1602,18 @@ mps_intr_locked(void *data)
                        break;
                }
 
-               if (cm != NULL) {
-                       if (cm->cm_flags & MPS_CM_FLAGS_POLLED)
-                               cm->cm_flags |= MPS_CM_FLAGS_COMPLETE;
-
-                       if (cm->cm_complete != NULL)
-                               cm->cm_complete(sc, cm);
-
-                       if (cm->cm_flags & MPS_CM_FLAGS_WAKEUP)
-                               wakeup(cm);
-               }
+               if (cm != NULL)
+                       mps_complete_command(cm);
 
                desc->Words.Low = 0xffffffff;
                desc->Words.High = 0xffffffff;
-               if (++pq >= sc->pqdepth)
-                       pq = 0;
        }
 
        if (pq != sc->replypostindex) {
-               mps_dprint(sc, MPS_INFO, "writing postindex %d\n", pq);
-               mps_regwrite(sc, MPI2_REPLY_POST_HOST_INDEX_OFFSET, pq);
-               sc->replypostindex = pq;
+               mps_dprint(sc, MPS_TRACE,
+                   "%s sc %p writing postindex %d\n",
+                   __func__, sc, sc->replypostindex);
+               mps_regwrite(sc, MPI2_REPLY_POST_HOST_INDEX_OFFSET, sc->replypostindex);
        }
 
        return;
@@ -1327,6 +1636,28 @@ mps_dispatch_event(struct mps_softc *sc, uintptr_t data,
 
        if (handled == 0)
                device_printf(sc->mps_dev, "Unhandled event 0x%x\n", event);
+
+       /*
+        * This is the only place that the event/reply should be freed.
+        * Anything wanting to hold onto the event data should have
+        * already copied it into their own storage.
+        */
+       mps_free_reply(sc, data);
+}
+
+static void
+mps_reregister_events_complete(struct mps_softc *sc, struct mps_command *cm)
+{
+       mps_dprint(sc, MPS_TRACE, "%s\n", __func__);
+
+       if (cm->cm_reply)
+               mps_print_event(sc,
+                       (MPI2_EVENT_NOTIFICATION_REPLY *)cm->cm_reply);
+
+       mps_free_command(sc, cm);
+
+       /* next, send a port enable */
+       mpssas_startup(sc);
 }
 
 /*
@@ -1393,14 +1724,60 @@ mps_update_events(struct mps_softc *sc, struct mps_event_handle *handle,
 
        error = mps_request_polled(sc, cm);
        reply = (MPI2_EVENT_NOTIFICATION_REPLY *)cm->cm_reply;
-       if ((reply->IOCStatus & MPI2_IOCSTATUS_MASK) != MPI2_IOCSTATUS_SUCCESS)
+       if ((reply == NULL) ||
+           (reply->IOCStatus & MPI2_IOCSTATUS_MASK) != MPI2_IOCSTATUS_SUCCESS)
                error = ENXIO;
        mps_print_event(sc, reply);
+       mps_dprint(sc, MPS_TRACE, "%s finished error %d\n", __func__, error);
 
        mps_free_command(sc, cm);
        return (error);
 }
 
+static int
+mps_reregister_events(struct mps_softc *sc)
+{
+       MPI2_EVENT_NOTIFICATION_REQUEST *evtreq;
+       struct mps_command *cm;
+       struct mps_event_handle *eh;
+       int error, i;
+
+       mps_dprint(sc, MPS_TRACE, "%s\n", __func__);
+
+       /* first, reregister events */
+
+       memset(sc->event_mask, 0xff, 16);
+
+       TAILQ_FOREACH(eh, &sc->event_list, eh_list) {
+               for (i = 0; i < 16; i++)
+                       sc->event_mask[i] &= ~eh->mask[i];
+       }
+
+       if ((cm = mps_alloc_command(sc)) == NULL)
+               return (EBUSY);
+       evtreq = (MPI2_EVENT_NOTIFICATION_REQUEST *)cm->cm_req;
+       evtreq->Function = MPI2_FUNCTION_EVENT_NOTIFICATION;
+       evtreq->MsgFlags = 0;
+       evtreq->SASBroadcastPrimitiveMasks = 0;
+#ifdef MPS_DEBUG_ALL_EVENTS
+       {
+               u_char fullmask[16];
+               memset(fullmask, 0x00, 16);
+               bcopy(fullmask, (uint8_t *)&evtreq->EventMasks, 16);
+       }
+#else
+               bcopy(sc->event_mask, (uint8_t *)&evtreq->EventMasks, 16);
+#endif
+       cm->cm_desc.Default.RequestFlags = MPI2_REQ_DESCRIPT_FLAGS_DEFAULT_TYPE;
+       cm->cm_data = NULL;
+       cm->cm_complete = mps_reregister_events_complete;
+
+       error = mps_map_command(sc, cm);
+
+       mps_dprint(sc, MPS_TRACE, "%s finished with error %d\n", __func__, error);
+       return (error);
+}
+
 int
 mps_deregister_events(struct mps_softc *sc, struct mps_event_handle *handle)
 {
@@ -1459,6 +1836,7 @@ mps_push_sge(struct mps_command *cm, void *sgep, size_t len, int segsleft)
        MPI2_SGE_TRANSACTION_UNION *tc = sgep;
        MPI2_SGE_SIMPLE64 *sge = sgep;
        int error, type;
+       uint32_t saved_buf_len, saved_address_low, saved_address_high;
 
        type = (tc->Flags & MPI2_SGE_FLAGS_ELEMENT_MASK);
 
@@ -1485,8 +1863,7 @@ mps_push_sge(struct mps_command *cm, void *sgep, size_t len, int segsleft)
                if (((sge->FlagsLength >> MPI2_SGE_FLAGS_SHIFT) &
                    MPI2_SGE_FLAGS_ADDRESS_SIZE) == 0)
                        panic("SGE simple %p flags %02x not marked 64-bit?",
-                           sge,
-                           (u_int)(sge->FlagsLength >> MPI2_SGE_FLAGS_SHIFT));
+                           sge, (u_int)(sge->FlagsLength >> MPI2_SGE_FLAGS_SHIFT));
 
                break;
        default:
@@ -1558,12 +1935,48 @@ mps_push_sge(struct mps_command *cm, void *sgep, size_t len, int segsleft)
 
        if (segsleft == 1 && type == MPI2_SGE_FLAGS_SIMPLE_ELEMENT) {
                /*
-                * Last element of the last segment of the entire
-                * buffer.
+                * If this is a bi-directional request, need to account for that
+                * here.  Save the pre-filled sge values.  These will be used
+                * either for the 2nd SGL or for a single direction SGL.  If
+                * cm_out_len is non-zero, this is a bi-directional request, so
+                * fill in the OUT SGL first, then the IN SGL, otherwise just
+                * fill in the IN SGL.  Note that at this time, when filling in
+                * 2 SGL's for a bi-directional request, they both use the same
+                * DMA buffer (same cm command).
                 */
-               sge->FlagsLength |= ((MPI2_SGE_FLAGS_LAST_ELEMENT |
+               saved_buf_len = sge->FlagsLength & 0x00FFFFFF;
+               saved_address_low = sge->Address.Low;
+               saved_address_high = sge->Address.High;
+               if (cm->cm_out_len) {
+                       sge->FlagsLength = cm->cm_out_len |
+                           ((uint32_t)(MPI2_SGE_FLAGS_SIMPLE_ELEMENT |
+                           MPI2_SGE_FLAGS_END_OF_BUFFER |
+                           MPI2_SGE_FLAGS_HOST_TO_IOC |
+                           MPI2_SGE_FLAGS_64_BIT_ADDRESSING) <<
+                           MPI2_SGE_FLAGS_SHIFT);
+                       cm->cm_sglsize -= len;
+                       bcopy(sgep, cm->cm_sge, len);
+                       cm->cm_sge = (MPI2_SGE_IO_UNION *)((uintptr_t)cm->cm_sge
+                           + len);
+               }
+               sge->FlagsLength = saved_buf_len |
+                   ((uint32_t)(MPI2_SGE_FLAGS_SIMPLE_ELEMENT |
                    MPI2_SGE_FLAGS_END_OF_BUFFER |
-                   MPI2_SGE_FLAGS_END_OF_LIST) << MPI2_SGE_FLAGS_SHIFT);
+                   MPI2_SGE_FLAGS_LAST_ELEMENT |
+                   MPI2_SGE_FLAGS_END_OF_LIST |
+                   MPI2_SGE_FLAGS_64_BIT_ADDRESSING) <<
+                   MPI2_SGE_FLAGS_SHIFT);
+               if (cm->cm_flags & MPS_CM_FLAGS_DATAIN) {
+                       sge->FlagsLength |=
+                           ((uint32_t)(MPI2_SGE_FLAGS_IOC_TO_HOST) <<
+                           MPI2_SGE_FLAGS_SHIFT);
+               } else {
+                       sge->FlagsLength |=
+                           ((uint32_t)(MPI2_SGE_FLAGS_HOST_TO_IOC) <<
+                           MPI2_SGE_FLAGS_SHIFT);
+               }
+               sge->Address.Low = saved_address_low;
+               sge->Address.High = saved_address_high;
        }
 
        cm->cm_sglsize -= len;
@@ -1582,10 +1995,10 @@ mps_add_dmaseg(struct mps_command *cm, vm_paddr_t pa, size_t len, u_int flags,
        MPI2_SGE_SIMPLE64 sge;
 
        /*
-        * This driver always uses 64-bit address elements for
-        * simplicity.
+        * This driver always uses 64-bit address elements for simplicity.
         */
-       flags |= MPI2_SGE_FLAGS_SIMPLE_ELEMENT | MPI2_SGE_FLAGS_ADDRESS_SIZE;
+       flags |= MPI2_SGE_FLAGS_SIMPLE_ELEMENT |
+           MPI2_SGE_FLAGS_64_BIT_ADDRESSING;
        sge.FlagsLength = len | (flags << MPI2_SGE_FLAGS_SHIFT);
        mps_from_u64(pa, &sge.Address);
 
@@ -1613,8 +2026,8 @@ mps_data_cb(void *arg, bus_dma_segment_t *segs, int nsegs, int error)
        }
 
        /*
-        * Set up DMA direction flags.  Note that we don't support
-        * bi-directional transfers, with the exception of SMP passthrough.
+        * Set up DMA direction flags.  Bi-directional requests are also handled
+        * here.  In that case, both direction flags will be set.
         */
        sflags = 0;
        if (cm->cm_flags & MPS_CM_FLAGS_SMP_PASS) {
@@ -1640,21 +2053,22 @@ mps_data_cb(void *arg, bus_dma_segment_t *segs, int nsegs, int error)
                sflags |= MPI2_SGE_FLAGS_DIRECTION |
                          MPI2_SGE_FLAGS_END_OF_BUFFER;
        } else if (cm->cm_flags & MPS_CM_FLAGS_DATAOUT) {
-               sflags |= MPI2_SGE_FLAGS_DIRECTION;
+               sflags |= MPI2_SGE_FLAGS_HOST_TO_IOC;
                dir = BUS_DMASYNC_PREWRITE;
        } else
                dir = BUS_DMASYNC_PREREAD;
 
        for (i = 0; i < nsegs; i++) {
-               if ((cm->cm_flags & MPS_CM_FLAGS_SMP_PASS)
-                && (i != 0)) {
+               if ((cm->cm_flags & MPS_CM_FLAGS_SMP_PASS) && (i != 0)) {
                        sflags &= ~MPI2_SGE_FLAGS_DIRECTION;
                }
                error = mps_add_dmaseg(cm, segs[i].ds_addr, segs[i].ds_len,
                    sflags, nsegs - i);
                if (error != 0) {
                        /* Resource shortage, roll back! */
-                       mps_printf(sc, "out of chain frames\n");
+                       mps_dprint(sc, MPS_INFO, "out of chain frames\n");
+                       cm->cm_flags |= MPS_CM_FLAGS_CHAIN_FAILED;
+                       mps_complete_command(cm);
                        return;
                }
        }
@@ -1673,8 +2087,11 @@ mps_data_cb2(void *arg, bus_dma_segment_t *segs, int nsegs, bus_size_t mapsize,
 }
 
 /*
+ * This is the routine to enqueue commands ansynchronously.
  * Note that the only error path here is from bus_dmamap_load(), which can
- * return EINPROGRESS if it is waiting for resources.
+ * return EINPROGRESS if it is waiting for resources.  Other than this, it's
+ * assumed that if you have a command in-hand, then you have enough credits
+ * to use it.
  */
 int
 mps_map_command(struct mps_softc *sc, struct mps_command *cm)
@@ -1706,6 +2123,57 @@ mps_map_command(struct mps_softc *sc, struct mps_command *cm)
 }
 
 /*
+ * This is the routine to enqueue commands synchronously.  An error of
+ * EINPROGRESS from mps_map_command() is ignored since the command will
+ * be executed and enqueued automatically.  Other errors come from msleep().
+ */
+int
+mps_wait_command(struct mps_softc *sc, struct mps_command *cm, int timeout)
+{
+       int error;
+
+       KKASSERT(lockstatus(&sc->mps_lock, curthread) != 0);
+
+       cm->cm_complete = NULL;
+       cm->cm_flags |= MPS_CM_FLAGS_WAKEUP;
+       error = mps_map_command(sc, cm);
+       if ((error != 0) && (error != EINPROGRESS))
+               return (error);
+       error = lksleep(cm, &sc->mps_lock, 0, "mpswait", timeout);
+       if (error == EWOULDBLOCK)
+               error = ETIMEDOUT;
+       return (error);
+}
+
+/*
+ * This is the routine to enqueue a command synchonously and poll for
+ * completion.  Its use should be rare.
+ */
+int
+mps_request_polled(struct mps_softc *sc, struct mps_command *cm)
+{
+       int error, timeout = 0;
+
+       error = 0;
+
+       cm->cm_flags |= MPS_CM_FLAGS_POLLED;
+       cm->cm_complete = NULL;
+       mps_map_command(sc, cm);
+
+       while ((cm->cm_flags & MPS_CM_FLAGS_COMPLETE) == 0) {
+               mps_intr_locked(sc);
+               DELAY(50 * 1000);
+               if (timeout++ > 1000) {
+                       mps_dprint(sc, MPS_FAULT, "polling failed\n");
+                       error = ETIMEDOUT;
+                       break;
+               }
+       }
+
+       return (error);
+}
+
+/*
  * The MPT driver had a verbose interface for config pages.  In this driver,
  * reduce it to much simplier terms, similar to the Linux driver.
  */
@@ -1763,11 +2231,13 @@ mps_read_config_page(struct mps_softc *sc, struct mps_config_params *params)
                cm->cm_complete = mps_config_complete;
                return (mps_map_command(sc, cm));
        } else {
-               cm->cm_complete = NULL;
-               cm->cm_flags |= MPS_CM_FLAGS_WAKEUP;
-               if ((error = mps_map_command(sc, cm)) != 0)
+               error = mps_wait_command(sc, cm, 0);
+               if (error) {
+                       mps_dprint(sc, MPS_FAULT,
+                           "Error %d reading config page\n", error);
+                       mps_free_command(sc, cm);
                        return (error);
-               lksleep(cm, &sc->mps_lock, 0, "mpswait", 0);
+               }
                mps_config_complete(sc, cm);
        }
 
@@ -1794,7 +2264,20 @@ mps_config_complete(struct mps_softc *sc, struct mps_command *cm)
                bus_dmamap_unload(sc->buffer_dmat, cm->cm_dmamap);
        }
 
+       /*
+        * XXX KDM need to do more error recovery?  This results in the
+        * device in question not getting probed.
+        */
+       if ((cm->cm_flags & MPS_CM_FLAGS_ERROR_MASK) != 0) {
+               params->status = MPI2_IOCSTATUS_BUSY;
+               goto done;
+       }
+
        reply = (MPI2_CONFIG_REPLY *)cm->cm_reply;
+       if (reply == NULL) {
+               params->status = MPI2_IOCSTATUS_BUSY;
+               goto done;
+       }
        params->status = reply->IOCStatus;
        if (params->hdr.Ext.ExtPageType != 0) {
                params->hdr.Ext.ExtPageType = reply->ExtPageType;
@@ -1806,6 +2289,7 @@ mps_config_complete(struct mps_softc *sc, struct mps_command *cm)
                params->hdr.Struct.PageVersion = reply->Header.PageVersion;
        }
 
+done:
        mps_free_command(sc, cm);
        if (params->callback != NULL)
                params->callback(sc, params);
diff --git a/sys/dev/raid/mps/mps_config.c b/sys/dev/raid/mps/mps_config.c
new file mode 100644 (file)
index 0000000..44b70eb
--- /dev/null
@@ -0,0 +1,1390 @@
+/*-
+ * Copyright (c) 2011 LSI Corp.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * LSI MPT-Fusion Host Adapter FreeBSD
+ *
+ * $FreeBSD: src/sys/dev/mps/mps_config.c,v 1.1 2012/01/26 18:17:21 ken Exp $
+ */
+
+/* TODO Move headers to mpsvar */
+#include <sys/types.h>
+#include <sys/param.h>
+#include <sys/lock.h>
+#include <sys/mutex.h>
+#include <sys/systm.h>
+#include <sys/kernel.h>
+#include <sys/malloc.h>
+#include <sys/kthread.h>
+#include <sys/taskqueue.h>
+#include <sys/bus.h>
+#include <sys/endian.h>
+#include <sys/sysctl.h>
+#include <sys/eventhandler.h>
+#include <sys/uio.h>
+#include <dev/raid/mps/mpi/mpi2_type.h>
+#include <dev/raid/mps/mpi/mpi2.h>
+#include <dev/raid/mps/mpi/mpi2_ioc.h>
+#include <dev/raid/mps/mpi/mpi2_sas.h>
+#include <dev/raid/mps/mpi/mpi2_cnfg.h>
+#include <dev/raid/mps/mpi/mpi2_init.h>
+#include <dev/raid/mps/mpi/mpi2_tool.h>
+#include <dev/raid/mps/mps_ioctl.h>
+#include <dev/raid/mps/mpsvar.h>
+
+/**
+ * mps_config_get_ioc_pg8 - obtain ioc page 8
+ * @sc: per adapter object
+ * @mpi_reply: reply mf payload returned from firmware
+ * @config_page: contents of the config page
+ * Context: sleep.
+ *
+ * Returns 0 for success, non-zero for failure.
+ */
+int
+mps_config_get_ioc_pg8(struct mps_softc *sc, Mpi2ConfigReply_t *mpi_reply,
+    Mpi2IOCPage8_t *config_page)
+{
+       MPI2_CONFIG_REQUEST *request;
+       MPI2_CONFIG_REPLY *reply;
+       struct mps_command *cm;
+       MPI2_CONFIG_PAGE_IOC_8 *page = NULL;
+       int error = 0;
+       u16 ioc_status;
+
+       mps_dprint(sc, MPS_TRACE, "%s\n", __func__);
+
+       if ((cm = mps_alloc_command(sc)) == NULL) {
+               kprintf("%s: command alloc failed @ line %d\n", __func__,
+                   __LINE__);
+               error = EBUSY;
+               goto out;
+       }
+       request = (MPI2_CONFIG_REQUEST *)cm->cm_req;
+       bzero(request, sizeof(MPI2_CONFIG_REQUEST));
+       request->Function = MPI2_FUNCTION_CONFIG;
+       request->Action = MPI2_CONFIG_ACTION_PAGE_HEADER;
+       request->Header.PageType = MPI2_CONFIG_PAGETYPE_IOC;
+       request->Header.PageNumber = 8;
+       request->Header.PageVersion = MPI2_IOCPAGE8_PAGEVERSION;
+       cm->cm_desc.Default.RequestFlags = MPI2_REQ_DESCRIPT_FLAGS_DEFAULT_TYPE;
+       cm->cm_data = NULL;
+       error = mps_request_polled(sc, cm);
+       reply = (MPI2_CONFIG_REPLY *)cm->cm_reply;
+       if (error || (reply == NULL)) {
+               /* FIXME */
+               /* If the poll returns error then we need to do diag reset */
+               kprintf("%s: poll for header completed with error %d",
+                   __func__, error);
+               error = ENXIO;
+               goto out;
+       }
+       ioc_status = le16toh(reply->IOCStatus) & MPI2_IOCSTATUS_MASK;
+       bcopy(reply, mpi_reply, sizeof(MPI2_CONFIG_REPLY));
+       if (ioc_status != MPI2_IOCSTATUS_SUCCESS) {
+               /* FIXME */
+               /* If the poll returns error then we need to do diag reset */
+               kprintf("%s: header read with error; iocstatus = 0x%x\n",
+                   __func__, ioc_status);
+               error = ENXIO;
+               goto out;
+       }
+       /* We have to do free and alloc for the reply-free and reply-post
+        * counters to match - Need to review the reply FIFO handling.
+        */
+       mps_free_command(sc, cm);
+
+       if ((cm = mps_alloc_command(sc)) == NULL) {
+               kprintf("%s: command alloc failed @ line %d\n", __func__,
+                   __LINE__);
+               error = EBUSY;
+               goto out;
+       }
+       request = (MPI2_CONFIG_REQUEST *)cm->cm_req;
+       bzero(request, sizeof(MPI2_CONFIG_REQUEST));
+       request->Function = MPI2_FUNCTION_CONFIG;
+       request->Action = MPI2_CONFIG_ACTION_PAGE_READ_CURRENT;
+       request->Header.PageType = MPI2_CONFIG_PAGETYPE_IOC;
+       request->Header.PageNumber = 8;
+       request->Header.PageVersion = MPI2_IOCPAGE8_PAGEVERSION;
+       request->Header.PageLength = mpi_reply->Header.PageLength;
+       cm->cm_length =  le16toh(mpi_reply->Header.PageLength) * 4;
+       cm->cm_sge = &request->PageBufferSGE;
+       cm->cm_sglsize = sizeof(MPI2_SGE_IO_UNION);
+       cm->cm_flags = MPS_CM_FLAGS_SGE_SIMPLE | MPS_CM_FLAGS_DATAIN;
+       cm->cm_desc.Default.RequestFlags = MPI2_REQ_DESCRIPT_FLAGS_DEFAULT_TYPE;
+       page = kmalloc((cm->cm_length), M_MPT2, M_ZERO | M_NOWAIT);
+       if (!page) {
+               kprintf("%s: page alloc failed\n", __func__);
+               error = ENOMEM;
+               goto out;
+       }
+       cm->cm_data = page;
+       error = mps_request_polled(sc, cm);
+       reply = (MPI2_CONFIG_REPLY *)cm->cm_reply;
+       if (error || (reply == NULL)) {
+               /* FIXME */
+               /* If the poll returns error then we need to do diag reset */
+               kprintf("%s: poll for page completed with error %d",
+                   __func__, error);
+               error = ENXIO;
+               goto out;
+       }
+       ioc_status = le16toh(reply->IOCStatus) & MPI2_IOCSTATUS_MASK;
+       bcopy(reply, mpi_reply, sizeof(MPI2_CONFIG_REPLY));
+       if (ioc_status != MPI2_IOCSTATUS_SUCCESS) {
+               /* FIXME */
+               /* If the poll returns error then we need to do diag reset */
+               kprintf("%s: page read with error; iocstatus = 0x%x\n",
+                   __func__, ioc_status);
+               error = ENXIO;
+               goto out;
+       }
+       bcopy(page, config_page, MIN(cm->cm_length, (sizeof(Mpi2IOCPage8_t))));
+
+out:
+       kfree(page, M_MPT2);
+       if (cm)
+               mps_free_command(sc, cm);
+       return (error);
+}
+
+/**
+ * mps_config_get_man_pg10 - obtain Manufacturing Page 10 data and set flags
+ *   accordingly.  Currently, this page does not need to return to caller.
+ * @sc: per adapter object
+ * @mpi_reply: reply mf payload returned from firmware
+ * Context: sleep.
+ *
+ * Returns 0 for success, non-zero for failure.
+ */
+int
+mps_config_get_man_pg10(struct mps_softc *sc, Mpi2ConfigReply_t *mpi_reply)
+{
+       MPI2_CONFIG_REQUEST *request;
+       MPI2_CONFIG_REPLY *reply;
+       struct mps_command *cm;
+       pMpi2ManufacturingPagePS_t page = NULL;
+       uint32_t *pPS_info;
+       uint8_t OEM_Value = 0;
+       int error = 0;
+       u16 ioc_status;
+
+       mps_dprint(sc, MPS_TRACE, "%s\n", __func__);
+
+       if ((cm = mps_alloc_command(sc)) == NULL) {
+               kprintf("%s: command alloc failed @ line %d\n", __func__,
+                   __LINE__);
+               error = EBUSY;
+               goto out;
+       }
+       request = (MPI2_CONFIG_REQUEST *)cm->cm_req;
+       bzero(request, sizeof(MPI2_CONFIG_REQUEST));
+       request->Function = MPI2_FUNCTION_CONFIG;
+       request->Action = MPI2_CONFIG_ACTION_PAGE_HEADER;
+       request->Header.PageType = MPI2_CONFIG_PAGETYPE_MANUFACTURING;
+       request->Header.PageNumber = 10;
+       request->Header.PageVersion = MPI2_MANUFACTURING10_PAGEVERSION;
+       cm->cm_desc.Default.RequestFlags = MPI2_REQ_DESCRIPT_FLAGS_DEFAULT_TYPE;
+       cm->cm_data = NULL;
+       error = mps_request_polled(sc, cm);
+       reply = (MPI2_CONFIG_REPLY *)cm->cm_reply;
+       if (error || (reply == NULL)) {
+               /* FIXME */
+               /* If the poll returns error then we need to do diag reset */
+               kprintf("%s: poll for header completed with error %d",
+                   __func__, error);
+               error = ENXIO;
+               goto out;
+       }
+       ioc_status = le16toh(reply->IOCStatus) & MPI2_IOCSTATUS_MASK;
+       bcopy(reply, mpi_reply, sizeof(MPI2_CONFIG_REPLY));
+       if (ioc_status != MPI2_IOCSTATUS_SUCCESS) {
+               /* FIXME */
+               /* If the poll returns error then we need to do diag reset */
+               kprintf("%s: header read with error; iocstatus = 0x%x\n",
+                   __func__, ioc_status);
+               error = ENXIO;
+               goto out;
+       }
+       /* We have to do free and alloc for the reply-free and reply-post
+        * counters to match - Need to review the reply FIFO handling.
+        */
+       mps_free_command(sc, cm);
+
+       if ((cm = mps_alloc_command(sc)) == NULL) {
+               kprintf("%s: command alloc failed @ line %d\n", __func__,
+                   __LINE__);
+               error = EBUSY;
+               goto out;
+       }
+       request = (MPI2_CONFIG_REQUEST *)cm->cm_req;
+       bzero(request, sizeof(MPI2_CONFIG_REQUEST));
+       request->Function = MPI2_FUNCTION_CONFIG;
+       request->Action = MPI2_CONFIG_ACTION_PAGE_READ_CURRENT;
+       request->Header.PageType = MPI2_CONFIG_PAGETYPE_MANUFACTURING;
+       request->Header.PageNumber = 10;
+       request->Header.PageVersion = MPI2_MANUFACTURING10_PAGEVERSION;
+       request->Header.PageLength = mpi_reply->Header.PageLength;
+       cm->cm_length =  le16toh(mpi_reply->Header.PageLength) * 4;
+       cm->cm_sge = &request->PageBufferSGE;
+       cm->cm_sglsize = sizeof(MPI2_SGE_IO_UNION);
+       cm->cm_flags = MPS_CM_FLAGS_SGE_SIMPLE | MPS_CM_FLAGS_DATAIN;
+       cm->cm_desc.Default.RequestFlags = MPI2_REQ_DESCRIPT_FLAGS_DEFAULT_TYPE;
+       page = kmalloc(MPS_MAN_PAGE10_SIZE, M_MPT2, M_ZERO | M_NOWAIT);
+       if (!page) {
+               kprintf("%s: page alloc failed\n", __func__);
+               error = ENOMEM;
+               goto out;
+       }
+       cm->cm_data = page;
+       error = mps_request_polled(sc, cm);
+       reply = (MPI2_CONFIG_REPLY *)cm->cm_reply;
+       if (error || (reply == NULL)) {
+               /* FIXME */
+               /* If the poll returns error then we need to do diag reset */
+               kprintf("%s: poll for page completed with error %d",
+                   __func__, error);
+               error = ENXIO;
+               goto out;
+       }
+       ioc_status = le16toh(reply->IOCStatus) & MPI2_IOCSTATUS_MASK;
+       bcopy(reply, mpi_reply, sizeof(MPI2_CONFIG_REPLY));
+       if (ioc_status != MPI2_IOCSTATUS_SUCCESS) {
+               /* FIXME */
+               /* If the poll returns error then we need to do diag reset */
+               kprintf("%s: page read with error; iocstatus = 0x%x\n",
+                   __func__, ioc_status);
+               error = ENXIO;
+               goto out;
+       }
+
+       /*
+        * If OEM ID is unknown, fail the request.
+        */
+       sc->WD_hide_expose = MPS_WD_HIDE_ALWAYS;
+       OEM_Value = (uint8_t)(page->ProductSpecificInfo & 0x000000FF);
+       if (OEM_Value != MPS_WD_LSI_OEM) {
+               mps_dprint(sc, MPS_FAULT, "Unknown OEM value for WarpDrive "
+                   "(0x%x)\n", OEM_Value);
+               error = ENXIO;
+               goto out;
+       }
+
+       /*
+        * Set the phys disks hide/expose value.
+        */
+       pPS_info = (uint32_t *)&page->ProductSpecificInfo;
+       sc->WD_hide_expose = (uint8_t)(pPS_info[5]);
+       sc->WD_hide_expose &= MPS_WD_HIDE_EXPOSE_MASK;
+       if ((sc->WD_hide_expose != MPS_WD_HIDE_ALWAYS) &&
+           (sc->WD_hide_expose != MPS_WD_EXPOSE_ALWAYS) &&
+           (sc->WD_hide_expose != MPS_WD_HIDE_IF_VOLUME)) {
+               mps_dprint(sc, MPS_FAULT, "Unknown value for WarpDrive "
+                   "hide/expose: 0x%x\n", sc->WD_hide_expose);
+               error = ENXIO;
+               goto out;
+       }
+
+out:
+       kfree(page, M_MPT2);
+       if (cm)
+               mps_free_command(sc, cm);
+       return (error);
+}
+
+/**
+ * mps_base_static_config_pages - static start of day config pages.
+ * @sc: per adapter object
+ *
+ * Return nothing.
+ */
+void
+mps_base_static_config_pages(struct mps_softc *sc)
+{
+       Mpi2ConfigReply_t       mpi_reply;
+       int                     retry;
+
+       retry = 0;
+       while (mps_config_get_ioc_pg8(sc, &mpi_reply, &sc->ioc_pg8)) {
+               retry++;
+               if (retry > 5) {
+                       /* We need to Handle this situation */
+                       /*FIXME*/
+                       break;
+               }
+       }
+}
+
+/**
+ * mps_wd_config_pages - get info required to support WarpDrive.  This needs to
+ *    be called after discovery is complete to guarentee that IR info is there.
+ * @sc: per adapter object
+ *
+ * Return nothing.
+ */
+void
+mps_wd_config_pages(struct mps_softc *sc)
+{
+       Mpi2ConfigReply_t       mpi_reply;
+       pMpi2RaidVolPage0_t     raid_vol_pg0 = NULL;
+       Mpi2RaidPhysDiskPage0_t phys_disk_pg0;
+       pMpi2RaidVol0PhysDisk_t pRVPD;
+       uint32_t                stripe_size, phys_disk_page_address;
+       uint16_t                block_size;
+       uint8_t                 index, stripe_exp = 0, block_exp = 0;
+
+       /*
+        * Get the WD settings from manufacturing page 10 if using a WD HBA.
+        * This will be used to determine if phys disks should always be
+        * hidden, hidden only if part of a WD volume, or never hidden.  Also,
+        * get the WD RAID Volume info and fail if volume does not exist or if
+        * volume does not meet the requirements for a WD volume.  No retry
+        * here.  Just default to HIDE ALWAYS if man Page10 fails, or clear WD
+        * Valid flag if Volume info fails.
+        */
+       sc->WD_valid_config = FALSE;
+       if (sc->mps_flags & MPS_FLAGS_WD_AVAILABLE) {
+               if (mps_config_get_man_pg10(sc, &mpi_reply)) {
+                       mps_dprint(sc, MPS_FAULT,
+                           "mps_config_get_man_pg10 failed! Using 0 (Hide "
+                           "Always) for WarpDrive hide/expose value.\n");
+                       sc->WD_hide_expose = MPS_WD_HIDE_ALWAYS;
+               }
+
+               /*
+                * Get first RAID Volume Page0 using GET_NEXT_HANDLE.
+                */
+               raid_vol_pg0 = kmalloc(sizeof(Mpi2RaidVolPage0_t) +
+                   (sizeof(Mpi2RaidVol0PhysDisk_t) * MPS_MAX_DISKS_IN_VOL),
+                   M_MPT2, M_ZERO | M_NOWAIT);
+               if (!raid_vol_pg0) {
+                       kprintf("%s: page alloc failed\n", __func__);
+                       goto out;
+               }
+
+               if (mps_config_get_raid_volume_pg0(sc, &mpi_reply, raid_vol_pg0,
+                   0x0000FFFF)) {
+                       mps_dprint(sc, MPS_INFO,
+                           "mps_config_get_raid_volume_pg0 failed! Assuming "
+                           "WarpDrive IT mode.\n");
+                       goto out;
+               }
+
+               /*
+                * Check for valid WD configuration:
+                *   volume type is RAID0
+                *   number of phys disks in the volume is no more than 8
+                */
+               if ((raid_vol_pg0->VolumeType != MPI2_RAID_VOL_TYPE_RAID0) ||
+                   (raid_vol_pg0->NumPhysDisks > 8)) {
+                       mps_dprint(sc, MPS_FAULT,
+                           "Invalid WarpDrive configuration. Direct Drive I/O "
+                           "will not be used.\n");
+                       goto out;
+               }
+
+               /*
+                * Save the WD RAID data to be used during WD I/O.
+                */
+               sc->DD_max_lba = le64toh((uint64_t)raid_vol_pg0->MaxLBA.High <<
+                   32 | (uint64_t)raid_vol_pg0->MaxLBA.Low);
+               sc->DD_num_phys_disks = raid_vol_pg0->NumPhysDisks;
+               sc->DD_dev_handle = raid_vol_pg0->DevHandle;
+               sc->DD_stripe_size = raid_vol_pg0->StripeSize;
+               sc->DD_block_size = raid_vol_pg0->BlockSize;
+
+               /*
+                * Find power of 2 of stripe size and set this as the exponent.
+                * Fail if stripe size is 0.
+                */
+               stripe_size = raid_vol_pg0->StripeSize;
+               for (index = 0; index < 32; index++) {
+                       if (stripe_size & 1)
+                               break;
+                       stripe_exp++;
+                       stripe_size >>= 1;
+               }
+               if (index == 32) {
+                       mps_dprint(sc, MPS_FAULT,
+                           "RAID Volume's stripe size is 0. Direct Drive I/O "
+                           "will not be used.\n");
+                       goto out;
+               }
+               sc->DD_stripe_exponent = stripe_exp;
+
+               /*
+                * Find power of 2 of block size and set this as the exponent.
+                * Fail if block size is 0.
+                */
+               block_size = raid_vol_pg0->BlockSize;
+               for (index = 0; index < 16; index++) {
+                       if (block_size & 1)
+                               break;
+                       block_exp++;
+                       block_size >>= 1;
+               }
+               if (index == 16) {
+                       mps_dprint(sc, MPS_FAULT,
+                           "RAID Volume's block size is 0. Direct Drive I/O "
+                           "will not be used.\n");
+                       goto out;
+               }
+               sc->DD_block_exponent = block_exp;
+
+               /*
+                * Loop through all of the volume's Phys Disks to map the phys
+                * disk number into the columm map.  This is used during Direct
+                * Drive I/O to send the request to the correct SSD.
+                */
+               pRVPD = (pMpi2RaidVol0PhysDisk_t)&raid_vol_pg0->PhysDisk;
+               for (index = 0; index < raid_vol_pg0->NumPhysDisks; index++) {
+                       sc->DD_column_map[pRVPD->PhysDiskMap].phys_disk_num =
+                           pRVPD->PhysDiskNum;
+                       pRVPD++;
+               }
+
+               /*
+                * Get second RAID Volume Page0 using previous handle.  This
+                * page should not exist.  If it does, must not proceed with WD
+                * handling.
+                */
+               if (mps_config_get_raid_volume_pg0(sc, &mpi_reply,
+                   raid_vol_pg0, (u32)raid_vol_pg0->DevHandle)) {
+                       if (mpi_reply.IOCStatus !=
+                           MPI2_IOCSTATUS_CONFIG_INVALID_PAGE) {
+                               mps_dprint(sc, MPS_FAULT,
+                                   "Multiple RAID Volume Page0! Direct Drive "
+                                   "I/O will not be used.\n");
+                               goto out;
+                       }
+               } else {
+                       mps_dprint(sc, MPS_FAULT,
+                           "Multiple volumes! Direct Drive I/O will not be "
+                           "used.\n");
+                       goto out;
+               }
+
+               /*
+                * Get RAID Volume Phys Disk Page 0 for all SSDs in the volume.
+                */
+               for (index = 0; index < raid_vol_pg0->NumPhysDisks; index++) {
+                       phys_disk_page_address =
+                           MPI2_PHYSDISK_PGAD_FORM_PHYSDISKNUM +
+                           sc->DD_column_map[index].phys_disk_num;
+                       if (mps_config_get_raid_pd_pg0(sc, &mpi_reply,
+                           &phys_disk_pg0, phys_disk_page_address)) {
+                               mps_dprint(sc, MPS_FAULT,
+                                   "mps_config_get_raid_pd_pg0 failed! Direct "
+                                   "Drive I/O will not be used.\n");
+                               goto out;
+                       }
+                       if (phys_disk_pg0.DevHandle == 0xFFFF) {
+                               mps_dprint(sc, MPS_FAULT,
+                                   "Invalid Phys Disk DevHandle! Direct Drive "
+                                   "I/O will not be used.\n");
+                               goto out;
+                       }
+                       sc->DD_column_map[index].dev_handle =
+                           phys_disk_pg0.DevHandle;
+               }
+               sc->WD_valid_config = TRUE;
+out:
+               if (raid_vol_pg0)
+                       kfree(raid_vol_pg0, M_MPT2);
+       }
+}
+
+/**
+ * mps_config_get_dpm_pg0 - obtain driver persistent mapping page0
+ * @sc: per adapter object
+ * @mpi_reply: reply mf payload returned from firmware
+ * @config_page: contents of the config page
+ * @sz: size of buffer passed in config_page
+ * Context: sleep.
+ *
+ * Returns 0 for success, non-zero for failure.
+ */
+int
+mps_config_get_dpm_pg0(struct mps_softc *sc, Mpi2ConfigReply_t *mpi_reply,
+    Mpi2DriverMappingPage0_t *config_page, u16 sz)
+{
+       MPI2_CONFIG_REQUEST *request;
+       MPI2_CONFIG_REPLY *reply;
+       struct mps_command *cm;
+       Mpi2DriverMappingPage0_t *page = NULL;
+       int error = 0;
+       u16 ioc_status;
+
+       mps_dprint(sc, MPS_TRACE, "%s\n", __func__);
+
+       memset(config_page, 0, sz);
+       if ((cm = mps_alloc_command(sc)) == NULL) {
+               kprintf("%s: command alloc failed @ line %d\n", __func__,
+                   __LINE__);
+               error = EBUSY;
+               goto out;
+       }
+       request = (MPI2_CONFIG_REQUEST *)cm->cm_req;
+       bzero(request, sizeof(MPI2_CONFIG_REQUEST));
+       request->Function = MPI2_FUNCTION_CONFIG;
+       request->Action = MPI2_CONFIG_ACTION_PAGE_HEADER;
+       request->Header.PageType = MPI2_CONFIG_PAGETYPE_EXTENDED;
+       request->ExtPageType = MPI2_CONFIG_EXTPAGETYPE_DRIVER_MAPPING;
+       request->Header.PageNumber = 0;
+       request->Header.PageVersion = MPI2_DRIVERMAPPING0_PAGEVERSION;
+       request->PageAddress = sc->max_dpm_entries <<
+           MPI2_DPM_PGAD_ENTRY_COUNT_SHIFT;
+       cm->cm_desc.Default.RequestFlags = MPI2_REQ_DESCRIPT_FLAGS_DEFAULT_TYPE;
+       cm->cm_data = NULL;
+       error = mps_request_polled(sc, cm);
+       reply = (MPI2_CONFIG_REPLY *)cm->cm_reply;
+       if (error || (reply == NULL)) {
+               /* FIXME */
+               /* If the poll returns error then we need to do diag reset */
+               kprintf("%s: poll for header completed with error %d",
+                   __func__, error);
+               error = ENXIO;
+               goto out;
+       }
+       ioc_status = le16toh(reply->IOCStatus) & MPI2_IOCSTATUS_MASK;
+       bcopy(reply, mpi_reply, sizeof(MPI2_CONFIG_REPLY));
+       if (ioc_status != MPI2_IOCSTATUS_SUCCESS) {
+               /* FIXME */
+               /* If the poll returns error then we need to do diag reset */
+               kprintf("%s: header read with error; iocstatus = 0x%x\n",
+                   __func__, ioc_status);
+               error = ENXIO;
+               goto out;
+       }
+       /* We have to do free and alloc for the reply-free and reply-post
+        * counters to match - Need to review the reply FIFO handling.
+        */
+       mps_free_command(sc, cm);
+
+       if ((cm = mps_alloc_command(sc)) == NULL) {
+               kprintf("%s: command alloc failed @ line %d\n", __func__,
+                   __LINE__);
+               error = EBUSY;
+               goto out;
+       }
+       request = (MPI2_CONFIG_REQUEST *)cm->cm_req;
+       bzero(request, sizeof(MPI2_CONFIG_REQUEST));
+       request->Function = MPI2_FUNCTION_CONFIG;
+       request->Action = MPI2_CONFIG_ACTION_PAGE_READ_NVRAM;
+       request->Header.PageType = MPI2_CONFIG_PAGETYPE_EXTENDED;
+       request->ExtPageType = MPI2_CONFIG_EXTPAGETYPE_DRIVER_MAPPING;
+       request->Header.PageNumber = 0;
+       request->Header.PageVersion = MPI2_DRIVERMAPPING0_PAGEVERSION;
+       request->PageAddress = sc->max_dpm_entries <<
+           MPI2_DPM_PGAD_ENTRY_COUNT_SHIFT;
+       request->ExtPageLength = mpi_reply->ExtPageLength;
+       cm->cm_length =  le16toh(request->ExtPageLength) * 4;
+       cm->cm_sge = &request->PageBufferSGE;
+       cm->cm_sglsize = sizeof(MPI2_SGE_IO_UNION);
+       cm->cm_flags = MPS_CM_FLAGS_SGE_SIMPLE | MPS_CM_FLAGS_DATAIN;
+       cm->cm_desc.Default.RequestFlags = MPI2_REQ_DESCRIPT_FLAGS_DEFAULT_TYPE;
+       page = kmalloc(cm->cm_length, M_MPT2, M_ZERO|M_NOWAIT);
+       if (!page) {
+               kprintf("%s: page alloc failed\n", __func__);
+               error = ENOMEM;
+               goto out;
+       }
+       cm->cm_data = page;
+       error = mps_request_polled(sc, cm);
+       reply = (MPI2_CONFIG_REPLY *)cm->cm_reply;
+       if (error || (reply == NULL)) {
+               /* FIXME */
+               /* If the poll returns error then we need to do diag reset */
+               kprintf("%s: poll for page completed with error %d",
+                   __func__, error);
+               error = ENXIO;
+               goto out;
+       }
+       ioc_status = le16toh(reply->IOCStatus) & MPI2_IOCSTATUS_MASK;
+       bcopy(reply, mpi_reply, sizeof(MPI2_CONFIG_REPLY));
+       if (ioc_status != MPI2_IOCSTATUS_SUCCESS) {
+               /* FIXME */
+               /* If the poll returns error then we need to do diag reset */
+               kprintf("%s: page read with error; iocstatus = 0x%x\n",
+                   __func__, ioc_status);
+               error = ENXIO;
+               goto out;
+       }
+       bcopy(page, config_page, MIN(cm->cm_length, sz));
+out:
+       kfree(page, M_MPT2);
+       if (cm)
+               mps_free_command(sc, cm);
+       return (error);
+}
+
+/**
+ * mps_config_set_dpm_pg0 - write an entry in driver persistent mapping page0
+ * @sc: per adapter object
+ * @mpi_reply: reply mf payload returned from firmware
+ * @config_page: contents of the config page
+ * @entry_idx: entry index in DPM Page0 to be modified
+ * Context: sleep.
+ *
+ * Returns 0 for success, non-zero for failure.
+ */
+
+int mps_config_set_dpm_pg0(struct mps_softc *sc, Mpi2ConfigReply_t *mpi_reply,
+    Mpi2DriverMappingPage0_t *config_page, u16 entry_idx)
+{
+       MPI2_CONFIG_REQUEST *request;
+       MPI2_CONFIG_REPLY *reply;
+       struct mps_command *cm;
+       MPI2_CONFIG_PAGE_DRIVER_MAPPING_0 *page = NULL;
+       int error = 0;
+       u16 ioc_status;
+
+       mps_dprint(sc, MPS_TRACE, "%s\n", __func__);
+
+       if ((cm = mps_alloc_command(sc)) == NULL) {
+               kprintf("%s: command alloc failed @ line %d\n", __func__,
+                   __LINE__);
+               error = EBUSY;
+               goto out;
+       }
+       request = (MPI2_CONFIG_REQUEST *)cm->cm_req;
+       bzero(request, sizeof(MPI2_CONFIG_REQUEST));
+       request->Function = MPI2_FUNCTION_CONFIG;
+       request->Action = MPI2_CONFIG_ACTION_PAGE_HEADER;
+       request->Header.PageType = MPI2_CONFIG_PAGETYPE_EXTENDED;
+       request->ExtPageType = MPI2_CONFIG_EXTPAGETYPE_DRIVER_MAPPING;
+       request->Header.PageNumber = 0;
+       request->Header.PageVersion = MPI2_DRIVERMAPPING0_PAGEVERSION;
+       request->PageAddress = 1 << MPI2_DPM_PGAD_ENTRY_COUNT_SHIFT;
+       request->PageAddress |= htole16(entry_idx);
+       cm->cm_desc.Default.RequestFlags = MPI2_REQ_DESCRIPT_FLAGS_DEFAULT_TYPE;
+       cm->cm_data = NULL;
+       error = mps_request_polled(sc, cm);
+       reply = (MPI2_CONFIG_REPLY *)cm->cm_reply;
+       if (error || (reply == NULL)) {
+               /* FIXME */
+               /* If the poll returns error then we need to do diag reset */
+               kprintf("%s: poll for header completed with error %d",
+                   __func__, error);
+               error = ENXIO;
+               goto out;
+       }
+       ioc_status = le16toh(reply->IOCStatus) & MPI2_IOCSTATUS_MASK;
+       bcopy(reply, mpi_reply, sizeof(MPI2_CONFIG_REPLY));
+       if (ioc_status != MPI2_IOCSTATUS_SUCCESS) {
+               /* FIXME */
+               /* If the poll returns error then we need to do diag reset */
+               kprintf("%s: header read with error; iocstatus = 0x%x\n",
+                   __func__, ioc_status);
+               error = ENXIO;
+               goto out;
+       }
+       /* We have to do free and alloc for the reply-free and reply-post
+        * counters to match - Need to review the reply FIFO handling.
+        */
+       mps_free_command(sc, cm);
+
+       if ((cm = mps_alloc_command(sc)) == NULL) {
+               kprintf("%s: command alloc failed @ line %d\n", __func__,
+                   __LINE__);
+               error = EBUSY;
+               goto out;
+       }
+       request = (MPI2_CONFIG_REQUEST *)cm->cm_req;
+       bzero(request, sizeof(MPI2_CONFIG_REQUEST));
+       request->Function = MPI2_FUNCTION_CONFIG;
+       request->Action = MPI2_CONFIG_ACTION_PAGE_WRITE_NVRAM;
+       request->Header.PageType = MPI2_CONFIG_PAGETYPE_EXTENDED;
+       request->ExtPageType = MPI2_CONFIG_EXTPAGETYPE_DRIVER_MAPPING;
+       request->Header.PageNumber = 0;
+       request->Header.PageVersion = MPI2_DRIVERMAPPING0_PAGEVERSION;
+       request->ExtPageLength = mpi_reply->ExtPageLength;
+       request->PageAddress = 1 << MPI2_DPM_PGAD_ENTRY_COUNT_SHIFT;
+       request->PageAddress |= htole16(entry_idx);
+       cm->cm_length = le16toh(mpi_reply->ExtPageLength) * 4;
+       cm->cm_sge = &request->PageBufferSGE;
+       cm->cm_sglsize = sizeof(MPI2_SGE_IO_UNION);
+       cm->cm_flags = MPS_CM_FLAGS_SGE_SIMPLE | MPS_CM_FLAGS_DATAOUT;
+       cm->cm_desc.Default.RequestFlags = MPI2_REQ_DESCRIPT_FLAGS_DEFAULT_TYPE;
+       page = kmalloc(cm->cm_length, M_MPT2, M_ZERO | M_NOWAIT);
+       if (!page) {
+               kprintf("%s: page alloc failed\n", __func__);
+               error = ENOMEM;
+               goto out;
+       }
+       bcopy(config_page, page, MIN(cm->cm_length,
+           (sizeof(Mpi2DriverMappingPage0_t))));
+       cm->cm_data = page;
+       error = mps_request_polled(sc, cm);
+       reply = (MPI2_CONFIG_REPLY *)cm->cm_reply;
+       if (error || (reply == NULL)) {
+               /* FIXME */
+               /* If the poll returns error then we need to do diag reset */
+               kprintf("%s: poll for page completed with error %d",
+                   __func__, error);
+               error = ENXIO;
+               goto out;
+       }
+       ioc_status = le16toh(reply->IOCStatus) & MPI2_IOCSTATUS_MASK;
+       bcopy(reply, mpi_reply, sizeof(MPI2_CONFIG_REPLY));
+       if (ioc_status != MPI2_IOCSTATUS_SUCCESS) {
+               /* FIXME */
+               /* If the poll returns error then we need to do diag reset */
+               kprintf("%s: page written with error; iocstatus = 0x%x\n",
+                   __func__, ioc_status);
+               error = ENXIO;
+               goto out;
+       }
+out:
+       kfree(page, M_MPT2);
+       if (cm)
+               mps_free_command(sc, cm);
+       return (error);
+}
+
+/**
+ * mps_config_get_sas_device_pg0 - obtain sas device page 0
+ * @sc: per adapter object
+ * @mpi_reply: reply mf payload returned from firmware
+ * @config_page: contents of the config page
+ * @form: GET_NEXT_HANDLE or HANDLE
+ * @handle: device handle
+ * Context: sleep.
+ *
+ * Returns 0 for success, non-zero for failure.
+ */
+int
+mps_config_get_sas_device_pg0(struct mps_softc *sc, Mpi2ConfigReply_t
+    *mpi_reply, Mpi2SasDevicePage0_t *config_page, u32 form, u16 handle)
+{
+       MPI2_CONFIG_REQUEST *request;
+       MPI2_CONFIG_REPLY *reply;
+       struct mps_command *cm;
+       Mpi2SasDevicePage0_t *page = NULL;
+       int error = 0;
+       u16 ioc_status;
+
+       mps_dprint(sc, MPS_TRACE, "%s\n", __func__);
+
+       if ((cm = mps_alloc_command(sc)) == NULL) {
+               kprintf("%s: command alloc failed @ line %d\n", __func__,
+                   __LINE__);
+               error = EBUSY;
+               goto out;
+       }
+       request = (MPI2_CONFIG_REQUEST *)cm->cm_req;
+       bzero(request, sizeof(MPI2_CONFIG_REQUEST));
+       request->Function = MPI2_FUNCTION_CONFIG;
+       request->Action = MPI2_CONFIG_ACTION_PAGE_HEADER;
+       request->Header.PageType = MPI2_CONFIG_PAGETYPE_EXTENDED;
+       request->ExtPageType = MPI2_CONFIG_EXTPAGETYPE_SAS_DEVICE;
+       request->Header.PageNumber = 0;
+       request->Header.PageVersion = MPI2_SASDEVICE0_PAGEVERSION;
+       cm->cm_desc.Default.RequestFlags = MPI2_REQ_DESCRIPT_FLAGS_DEFAULT_TYPE;
+       cm->cm_data = NULL;
+       error = mps_request_polled(sc, cm);
+       reply = (MPI2_CONFIG_REPLY *)cm->cm_reply;
+       if (error || (reply == NULL)) {
+               /* FIXME */
+               /* If the poll returns error then we need to do diag reset */
+               kprintf("%s: poll for header completed with error %d",
+                   __func__, error);
+               error = ENXIO;
+               goto out;
+       }
+       ioc_status = le16toh(reply->IOCStatus) & MPI2_IOCSTATUS_MASK;
+       bcopy(reply, mpi_reply, sizeof(MPI2_CONFIG_REPLY));
+       if (ioc_status != MPI2_IOCSTATUS_SUCCESS) {
+               /* FIXME */
+               /* If the poll returns error then we need to do diag reset */
+               kprintf("%s: header read with error; iocstatus = 0x%x\n",
+                   __func__, ioc_status);
+               error = ENXIO;
+               goto out;
+       }
+       /* We have to do free and alloc for the reply-free and reply-post
+        * counters to match - Need to review the reply FIFO handling.
+        */
+       mps_free_command(sc, cm);
+
+       if ((cm = mps_alloc_command(sc)) == NULL) {
+               kprintf("%s: command alloc failed @ line %d\n", __func__,
+                   __LINE__);
+               error = EBUSY;
+               goto out;
+       }
+       request = (MPI2_CONFIG_REQUEST *)cm->cm_req;
+       bzero(request, sizeof(MPI2_CONFIG_REQUEST));
+       request->Function = MPI2_FUNCTION_CONFIG;
+       request->Action = MPI2_CONFIG_ACTION_PAGE_READ_CURRENT;
+       request->Header.PageType = MPI2_CONFIG_PAGETYPE_EXTENDED;
+       request->ExtPageType = MPI2_CONFIG_EXTPAGETYPE_SAS_DEVICE;
+       request->Header.PageNumber = 0;
+       request->Header.PageVersion = MPI2_SASDEVICE0_PAGEVERSION;
+       request->ExtPageLength = mpi_reply->ExtPageLength;
+       request->PageAddress = htole32(form | handle);
+       cm->cm_length = le16toh(mpi_reply->ExtPageLength) * 4;
+       cm->cm_sge = &request->PageBufferSGE;
+       cm->cm_sglsize = sizeof(MPI2_SGE_IO_UNION);
+       cm->cm_flags = MPS_CM_FLAGS_SGE_SIMPLE | MPS_CM_FLAGS_DATAIN;
+       cm->cm_desc.Default.RequestFlags = MPI2_REQ_DESCRIPT_FLAGS_DEFAULT_TYPE;
+       page = kmalloc(cm->cm_length, M_MPT2, M_ZERO | M_NOWAIT);
+       if (!page) {
+               kprintf("%s: page alloc failed\n", __func__);
+               error = ENOMEM;
+               goto out;
+       }
+       cm->cm_data = page;
+
+       error = mps_request_polled(sc, cm);
+       reply = (MPI2_CONFIG_REPLY *)cm->cm_reply;
+       if (error || (reply == NULL)) {
+               /* FIXME */
+               /* If the poll returns error then we need to do diag reset */
+               kprintf("%s: poll for page completed with error %d",
+                   __func__, error);
+               error = ENXIO;
+               goto out;
+       }
+       ioc_status = le16toh(reply->IOCStatus) & MPI2_IOCSTATUS_MASK;
+       bcopy(reply, mpi_reply, sizeof(MPI2_CONFIG_REPLY));
+       if (ioc_status != MPI2_IOCSTATUS_SUCCESS) {
+               /* FIXME */
+               /* If the poll returns error then we need to do diag reset */
+               kprintf("%s: page read with error; iocstatus = 0x%x\n",
+                   __func__, ioc_status);
+               error = ENXIO;
+               goto out;
+       }
+       bcopy(page, config_page, MIN(cm->cm_length,
+           sizeof(Mpi2SasDevicePage0_t)));
+out:
+       kfree(page, M_MPT2);
+       if (cm)
+               mps_free_command(sc, cm);
+       return (error);
+}
+
+/**
+ * mps_config_get_bios_pg3 - obtain BIOS page 3
+ * @sc: per adapter object
+ * @mpi_reply: reply mf payload returned from firmware
+ * @config_page: contents of the config page
+ * Context: sleep.
+ *
+ * Returns 0 for success, non-zero for failure.
+ */
+int
+mps_config_get_bios_pg3(struct mps_softc *sc, Mpi2ConfigReply_t *mpi_reply,
+    Mpi2BiosPage3_t *config_page)
+{
+       MPI2_CONFIG_REQUEST *request;
+       MPI2_CONFIG_REPLY *reply;
+       struct mps_command *cm;
+       Mpi2BiosPage3_t *page = NULL;
+       int error = 0;
+       u16 ioc_status;
+
+       mps_dprint(sc, MPS_TRACE, "%s\n", __func__);
+
+       if ((cm = mps_alloc_command(sc)) == NULL) {
+               kprintf("%s: command alloc failed @ line %d\n", __func__,
+                   __LINE__);
+               error = EBUSY;
+               goto out;
+       }
+       request = (MPI2_CONFIG_REQUEST *)cm->cm_req;
+       bzero(request, sizeof(MPI2_CONFIG_REQUEST));
+       request->Function = MPI2_FUNCTION_CONFIG;
+       request->Action = MPI2_CONFIG_ACTION_PAGE_HEADER;
+       request->Header.PageType = MPI2_CONFIG_PAGETYPE_BIOS;
+       request->Header.PageNumber = 3;
+       request->Header.PageVersion = MPI2_BIOSPAGE3_PAGEVERSION;
+       cm->cm_desc.Default.RequestFlags = MPI2_REQ_DESCRIPT_FLAGS_DEFAULT_TYPE;
+       cm->cm_data = NULL;
+       error = mps_request_polled(sc, cm);
+       reply = (MPI2_CONFIG_REPLY *)cm->cm_reply;
+       if (error || (reply == NULL)) {
+               /* FIXME */
+               /* If the poll returns error then we need to do diag reset */
+               kprintf("%s: poll for header completed with error %d",
+      &nb