[SCSI] mpt2sas v00.100.11.15
authorEric Moore <eric.moore@lsi.com>
Mon, 9 Mar 2009 07:21:12 +0000 (01:21 -0600)
committerJames Bottomley <James.Bottomley@HansenPartnership.com>
Fri, 13 Mar 2009 21:08:49 +0000 (16:08 -0500)
* This is new scsi lld device driver from LSI supporting the SAS 2.0
  standard. I have split patchs by filename.

* Here is list of new 6gb host controllers:

  LSI SAS2004
  LSI SAS2008
  LSI SAS2108
  LSI SAS2116

* Here are the changes in the 4th posting of this patch set:

(1) fix compile errors when SCSI_MPT2SAS_LOGGING is not enabled
(2) add mpt2sas to the SCSI Mid Layer Makefile
(3) append mpt2sas_ to the naming of all non-static functions
(4) fix oops for SMP_PASSTHRU
(5) doorbell algorithm imported changes from windows driver

* Here are the changes in the 3rd posting of this patch set:

(1) add readl following writel from the function that disables interrupts
(2) replace 0xFFFFFFFFFFFFFFFFULL with ~0ULL
(3) when calling pci_enable_msix, only pass one msix entry (instead of 15).
(4) remove the "current HW implementation uses..... " comment in the sources
(5) merged bug fix for SIGIO/POLLIN notifcation; reported by the storlib team.

* Here are the changes in the 2nd posting of this patch set:

(1) use little endian types in the mpi headers
(2) merged in bug fix's from inhouse drivers.

Signed-off-by: Eric Moore <eric.moore@lsi.com>
Tested-by: peter Bogdanovic <pbog@us.ibm.com>
Signed-off-by: James Bottomley <James.Bottomley@HansenPartnership.com>
20 files changed:
drivers/scsi/Kconfig
drivers/scsi/Makefile
drivers/scsi/mpt2sas/Kconfig [new file with mode: 0644]
drivers/scsi/mpt2sas/Makefile [new file with mode: 0644]
drivers/scsi/mpt2sas/mpi/mpi2.h [new file with mode: 0644]
drivers/scsi/mpt2sas/mpi/mpi2_cnfg.h [new file with mode: 0644]
drivers/scsi/mpt2sas/mpi/mpi2_init.h [new file with mode: 0644]
drivers/scsi/mpt2sas/mpi/mpi2_ioc.h [new file with mode: 0644]
drivers/scsi/mpt2sas/mpi/mpi2_raid.h [new file with mode: 0644]
drivers/scsi/mpt2sas/mpi/mpi2_sas.h [new file with mode: 0644]
drivers/scsi/mpt2sas/mpi/mpi2_tool.h [new file with mode: 0644]
drivers/scsi/mpt2sas/mpi/mpi2_type.h [new file with mode: 0644]
drivers/scsi/mpt2sas/mpt2sas_base.c [new file with mode: 0644]
drivers/scsi/mpt2sas/mpt2sas_base.h [new file with mode: 0644]
drivers/scsi/mpt2sas/mpt2sas_config.c [new file with mode: 0644]
drivers/scsi/mpt2sas/mpt2sas_ctl.c [new file with mode: 0644]
drivers/scsi/mpt2sas/mpt2sas_ctl.h [new file with mode: 0644]
drivers/scsi/mpt2sas/mpt2sas_debug.h [new file with mode: 0644]
drivers/scsi/mpt2sas/mpt2sas_scsih.c [new file with mode: 0644]
drivers/scsi/mpt2sas/mpt2sas_transport.c [new file with mode: 0644]

index e420ad0acebf49296f3e5695d59952e10a4af88c..e2f44e6c0bcb8cd19a7558357e012ef9d1dcb23f 100644 (file)
@@ -571,6 +571,7 @@ config SCSI_ARCMSR_AER
          To enable this function, choose Y here.
 
 source "drivers/scsi/megaraid/Kconfig.megaraid"
+source "drivers/scsi/mpt2sas/Kconfig"
 
 config SCSI_HPTIOP
        tristate "HighPoint RocketRAID 3xxx/4xxx Controller support"
index 05558b1704199a654428f81bb31e48f76f08b42c..cf7929634668e83a304d09f2a5d2f552d1c4d28b 100644 (file)
@@ -99,6 +99,7 @@ obj-$(CONFIG_SCSI_DC390T)     += tmscsim.o
 obj-$(CONFIG_MEGARAID_LEGACY)  += megaraid.o
 obj-$(CONFIG_MEGARAID_NEWGEN)  += megaraid/
 obj-$(CONFIG_MEGARAID_SAS)     += megaraid/
+obj-$(CONFIG_SCSI_MPT2SAS)     += mpt2sas/
 obj-$(CONFIG_SCSI_ACARD)       += atp870u.o
 obj-$(CONFIG_SCSI_SUNESP)      += esp_scsi.o   sun_esp.o
 obj-$(CONFIG_SCSI_GDTH)                += gdth.o
diff --git a/drivers/scsi/mpt2sas/Kconfig b/drivers/scsi/mpt2sas/Kconfig
new file mode 100644 (file)
index 0000000..4a86855
--- /dev/null
@@ -0,0 +1,66 @@
+#
+# Kernel configuration file for the MPT2SAS
+#
+# This code is based on drivers/scsi/mpt2sas/Kconfig
+# Copyright (C) 2007-2008  LSI Corporation
+#  (mailto:DL-MPTFusionLinux@lsi.com)
+
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License
+# as published by the Free Software Foundation; either version 2
+# of the License, or (at your option) any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+
+# NO WARRANTY
+# THE PROGRAM IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OR
+# CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED INCLUDING, WITHOUT
+# LIMITATION, ANY WARRANTIES OR CONDITIONS OF TITLE, NON-INFRINGEMENT,
+# MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. Each Recipient is
+# solely responsible for determining the appropriateness of using and
+# distributing the Program and assumes all risks associated with its
+# exercise of rights under this Agreement, including but not limited to
+# the risks and costs of program errors, damage to or loss of data,
+# programs or equipment, and unavailability or interruption of operations.
+
+# DISCLAIMER OF LIABILITY
+# NEITHER RECIPIENT NOR ANY CONTRIBUTORS SHALL HAVE ANY LIABILITY FOR ANY
+# DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+# DAMAGES (INCLUDING WITHOUT LIMITATION LOST PROFITS), 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 OR DISTRIBUTION OF THE PROGRAM OR THE EXERCISE OF ANY RIGHTS GRANTED
+# HEREUNDER, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGES
+
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301,
+# USA.
+
+config SCSI_MPT2SAS
+       tristate "LSI MPT Fusion SAS 2.0 Device Driver"
+       depends on PCI && SCSI
+       select SCSI_SAS_ATTRS
+       ---help---
+       This driver supports PCI-Express SAS 6Gb/s Host Adapters.
+
+config SCSI_MPT2SAS_MAX_SGE
+       int "LSI MPT Fusion Max number of SG Entries (16 - 128)"
+       depends on PCI && SCSI && SCSI_MPT2SAS
+       default "128"
+       range 16 128
+       ---help---
+       This option allows you to specify the maximum number of scatter-
+       gather entries per I/O. The driver default is 128, which matches
+       SAFE_PHYS_SEGMENTS.  However, it may decreased down to 16.
+       Decreasing this parameter will reduce memory requirements
+       on a per controller instance.
+
+config SCSI_MPT2SAS_LOGGING
+       bool "LSI MPT Fusion logging facility"
+       depends on PCI && SCSI && SCSI_MPT2SAS
+       ---help---
+       This turns on a logging facility.
diff --git a/drivers/scsi/mpt2sas/Makefile b/drivers/scsi/mpt2sas/Makefile
new file mode 100644 (file)
index 0000000..728f047
--- /dev/null
@@ -0,0 +1,7 @@
+# mpt2sas makefile
+obj-$(CONFIG_SCSI_MPT2SAS) += mpt2sas.o
+mpt2sas-y +=  mpt2sas_base.o        \
+               mpt2sas_config.o    \
+               mpt2sas_scsih.o     \
+               mpt2sas_transport.o \
+               mpt2sas_ctl.o
diff --git a/drivers/scsi/mpt2sas/mpi/mpi2.h b/drivers/scsi/mpt2sas/mpi/mpi2.h
new file mode 100644 (file)
index 0000000..7bb2ece
--- /dev/null
@@ -0,0 +1,1067 @@
+/*
+ *  Copyright (c) 2000-2009 LSI Corporation.
+ *
+ *
+ *           Name:  mpi2.h
+ *          Title:  MPI Message independent structures and definitions
+ *                  including System Interface Register Set and
+ *                  scatter/gather formats.
+ *  Creation Date:  June 21, 2006
+ *
+ *  mpi2.h Version:  02.00.11
+ *
+ *  Version History
+ *  ---------------
+ *
+ *  Date      Version   Description
+ *  --------  --------  ------------------------------------------------------
+ *  04-30-07  02.00.00  Corresponds to Fusion-MPT MPI Specification Rev A.
+ *  06-04-07  02.00.01  Bumped MPI2_HEADER_VERSION_UNIT.
+ *  06-26-07  02.00.02  Bumped MPI2_HEADER_VERSION_UNIT.
+ *  08-31-07  02.00.03  Bumped MPI2_HEADER_VERSION_UNIT.
+ *                      Moved ReplyPostHostIndex register to offset 0x6C of the
+ *                      MPI2_SYSTEM_INTERFACE_REGS and modified the define for
+ *                      MPI2_REPLY_POST_HOST_INDEX_OFFSET.
+ *                      Added union of request descriptors.
+ *                      Added union of reply descriptors.
+ *  10-31-07  02.00.04  Bumped MPI2_HEADER_VERSION_UNIT.
+ *                      Added define for MPI2_VERSION_02_00.
+ *                      Fixed the size of the FunctionDependent5 field in the
+ *                      MPI2_DEFAULT_REPLY structure.
+ *  12-18-07  02.00.05  Bumped MPI2_HEADER_VERSION_UNIT.
+ *                      Removed the MPI-defined Fault Codes and extended the
+ *                      product specific codes up to 0xEFFF.
+ *                      Added a sixth key value for the WriteSequence register
+ *                      and changed the flush value to 0x0.
+ *                      Added message function codes for Diagnostic Buffer Post
+ *                      and Diagnsotic Release.
+ *                      New IOCStatus define: MPI2_IOCSTATUS_DIAGNOSTIC_RELEASED
+ *                      Moved MPI2_VERSION_UNION from mpi2_ioc.h.
+ *  02-29-08  02.00.06  Bumped MPI2_HEADER_VERSION_UNIT.
+ *  03-03-08  02.00.07  Bumped MPI2_HEADER_VERSION_UNIT.
+ *  05-21-08  02.00.08  Bumped MPI2_HEADER_VERSION_UNIT.
+ *                      Added #defines for marking a reply descriptor as unused.
+ *  06-27-08  02.00.09  Bumped MPI2_HEADER_VERSION_UNIT.
+ *  10-02-08  02.00.10  Bumped MPI2_HEADER_VERSION_UNIT.
+ *                      Moved LUN field defines from mpi2_init.h.
+ *  01-19-09  02.00.11  Bumped MPI2_HEADER_VERSION_UNIT.
+ *  --------------------------------------------------------------------------
+ */
+
+#ifndef MPI2_H
+#define MPI2_H
+
+
+/*****************************************************************************
+*
+*        MPI Version Definitions
+*
+*****************************************************************************/
+
+#define MPI2_VERSION_MAJOR                  (0x02)
+#define MPI2_VERSION_MINOR                  (0x00)
+#define MPI2_VERSION_MAJOR_MASK             (0xFF00)
+#define MPI2_VERSION_MAJOR_SHIFT            (8)
+#define MPI2_VERSION_MINOR_MASK             (0x00FF)
+#define MPI2_VERSION_MINOR_SHIFT            (0)
+#define MPI2_VERSION ((MPI2_VERSION_MAJOR << MPI2_VERSION_MAJOR_SHIFT) |   \
+                                      MPI2_VERSION_MINOR)
+
+#define MPI2_VERSION_02_00                  (0x0200)
+
+/* versioning for this MPI header set */
+#define MPI2_HEADER_VERSION_UNIT            (0x0B)
+#define MPI2_HEADER_VERSION_DEV             (0x00)
+#define MPI2_HEADER_VERSION_UNIT_MASK       (0xFF00)
+#define MPI2_HEADER_VERSION_UNIT_SHIFT      (8)
+#define MPI2_HEADER_VERSION_DEV_MASK        (0x00FF)
+#define MPI2_HEADER_VERSION_DEV_SHIFT       (0)
+#define MPI2_HEADER_VERSION ((MPI2_HEADER_VERSION_UNIT << 8) | MPI2_HEADER_VERSION_DEV)
+
+
+/*****************************************************************************
+*
+*        IOC State Definitions
+*
+*****************************************************************************/
+
+#define MPI2_IOC_STATE_RESET               (0x00000000)
+#define MPI2_IOC_STATE_READY               (0x10000000)
+#define MPI2_IOC_STATE_OPERATIONAL         (0x20000000)
+#define MPI2_IOC_STATE_FAULT               (0x40000000)
+
+#define MPI2_IOC_STATE_MASK                (0xF0000000)
+#define MPI2_IOC_STATE_SHIFT               (28)
+
+/* Fault state range for prodcut specific codes */
+#define MPI2_FAULT_PRODUCT_SPECIFIC_MIN                 (0x0000)
+#define MPI2_FAULT_PRODUCT_SPECIFIC_MAX                 (0xEFFF)
+
+
+/*****************************************************************************
+*
+*        System Interface Register Definitions
+*
+*****************************************************************************/
+
+typedef volatile struct _MPI2_SYSTEM_INTERFACE_REGS
+{
+    U32         Doorbell;                   /* 0x00 */
+    U32         WriteSequence;              /* 0x04 */
+    U32         HostDiagnostic;             /* 0x08 */
+    U32         Reserved1;                  /* 0x0C */
+    U32         DiagRWData;                 /* 0x10 */
+    U32         DiagRWAddressLow;           /* 0x14 */
+    U32         DiagRWAddressHigh;          /* 0x18 */
+    U32         Reserved2[5];               /* 0x1C */
+    U32         HostInterruptStatus;        /* 0x30 */
+    U32         HostInterruptMask;          /* 0x34 */
+    U32         DCRData;                    /* 0x38 */
+    U32         DCRAddress;                 /* 0x3C */
+    U32         Reserved3[2];               /* 0x40 */
+    U32         ReplyFreeHostIndex;         /* 0x48 */
+    U32         Reserved4[8];               /* 0x4C */
+    U32         ReplyPostHostIndex;         /* 0x6C */
+    U32         Reserved5;                  /* 0x70 */
+    U32         HCBSize;                    /* 0x74 */
+    U32         HCBAddressLow;              /* 0x78 */
+    U32         HCBAddressHigh;             /* 0x7C */
+    U32         Reserved6[16];              /* 0x80 */
+    U32         RequestDescriptorPostLow;   /* 0xC0 */
+    U32         RequestDescriptorPostHigh;  /* 0xC4 */
+    U32         Reserved7[14];              /* 0xC8 */
+} MPI2_SYSTEM_INTERFACE_REGS, MPI2_POINTER PTR_MPI2_SYSTEM_INTERFACE_REGS,
+  Mpi2SystemInterfaceRegs_t, MPI2_POINTER pMpi2SystemInterfaceRegs_t;
+
+/*
+ * Defines for working with the Doorbell register.
+ */
+#define MPI2_DOORBELL_OFFSET                    (0x00000000)
+
+/* IOC --> System values */
+#define MPI2_DOORBELL_USED                      (0x08000000)
+#define MPI2_DOORBELL_WHO_INIT_MASK             (0x07000000)
+#define MPI2_DOORBELL_WHO_INIT_SHIFT            (24)
+#define MPI2_DOORBELL_FAULT_CODE_MASK           (0x0000FFFF)
+#define MPI2_DOORBELL_DATA_MASK                 (0x0000FFFF)
+
+/* System --> IOC values */
+#define MPI2_DOORBELL_FUNCTION_MASK             (0xFF000000)
+#define MPI2_DOORBELL_FUNCTION_SHIFT            (24)
+#define MPI2_DOORBELL_ADD_DWORDS_MASK           (0x00FF0000)
+#define MPI2_DOORBELL_ADD_DWORDS_SHIFT          (16)
+
+
+/*
+ * Defines for the WriteSequence register
+ */
+#define MPI2_WRITE_SEQUENCE_OFFSET              (0x00000004)
+#define MPI2_WRSEQ_KEY_VALUE_MASK               (0x0000000F)
+#define MPI2_WRSEQ_FLUSH_KEY_VALUE              (0x0)
+#define MPI2_WRSEQ_1ST_KEY_VALUE                (0xF)
+#define MPI2_WRSEQ_2ND_KEY_VALUE                (0x4)
+#define MPI2_WRSEQ_3RD_KEY_VALUE                (0xB)
+#define MPI2_WRSEQ_4TH_KEY_VALUE                (0x2)
+#define MPI2_WRSEQ_5TH_KEY_VALUE                (0x7)
+#define MPI2_WRSEQ_6TH_KEY_VALUE                (0xD)
+
+/*
+ * Defines for the HostDiagnostic register
+ */
+#define MPI2_HOST_DIAGNOSTIC_OFFSET             (0x00000008)
+
+#define MPI2_DIAG_BOOT_DEVICE_SELECT_MASK       (0x00001800)
+#define MPI2_DIAG_BOOT_DEVICE_SELECT_DEFAULT    (0x00000000)
+#define MPI2_DIAG_BOOT_DEVICE_SELECT_HCDW       (0x00000800)
+
+#define MPI2_DIAG_CLEAR_FLASH_BAD_SIG           (0x00000400)
+#define MPI2_DIAG_FORCE_HCB_ON_RESET            (0x00000200)
+#define MPI2_DIAG_HCB_MODE                      (0x00000100)
+#define MPI2_DIAG_DIAG_WRITE_ENABLE             (0x00000080)
+#define MPI2_DIAG_FLASH_BAD_SIG                 (0x00000040)
+#define MPI2_DIAG_RESET_HISTORY                 (0x00000020)
+#define MPI2_DIAG_DIAG_RW_ENABLE                (0x00000010)
+#define MPI2_DIAG_RESET_ADAPTER                 (0x00000004)
+#define MPI2_DIAG_HOLD_IOC_RESET                (0x00000002)
+
+/*
+ * Offsets for DiagRWData and address
+ */
+#define MPI2_DIAG_RW_DATA_OFFSET                (0x00000010)
+#define MPI2_DIAG_RW_ADDRESS_LOW_OFFSET         (0x00000014)
+#define MPI2_DIAG_RW_ADDRESS_HIGH_OFFSET        (0x00000018)
+
+/*
+ * Defines for the HostInterruptStatus register
+ */
+#define MPI2_HOST_INTERRUPT_STATUS_OFFSET       (0x00000030)
+#define MPI2_HIS_SYS2IOC_DB_STATUS              (0x80000000)
+#define MPI2_HIS_IOP_DOORBELL_STATUS            MPI2_HIS_SYS2IOC_DB_STATUS
+#define MPI2_HIS_RESET_IRQ_STATUS               (0x40000000)
+#define MPI2_HIS_REPLY_DESCRIPTOR_INTERRUPT     (0x00000008)
+#define MPI2_HIS_IOC2SYS_DB_STATUS              (0x00000001)
+#define MPI2_HIS_DOORBELL_INTERRUPT             MPI2_HIS_IOC2SYS_DB_STATUS
+
+/*
+ * Defines for the HostInterruptMask register
+ */
+#define MPI2_HOST_INTERRUPT_MASK_OFFSET         (0x00000034)
+#define MPI2_HIM_RESET_IRQ_MASK                 (0x40000000)
+#define MPI2_HIM_REPLY_INT_MASK                 (0x00000008)
+#define MPI2_HIM_RIM                            MPI2_HIM_REPLY_INT_MASK
+#define MPI2_HIM_IOC2SYS_DB_MASK                (0x00000001)
+#define MPI2_HIM_DIM                            MPI2_HIM_IOC2SYS_DB_MASK
+
+/*
+ * Offsets for DCRData and address
+ */
+#define MPI2_DCR_DATA_OFFSET                    (0x00000038)
+#define MPI2_DCR_ADDRESS_OFFSET                 (0x0000003C)
+
+/*
+ * Offset for the Reply Free Queue
+ */
+#define MPI2_REPLY_FREE_HOST_INDEX_OFFSET       (0x00000048)
+
+/*
+ * Offset for the Reply Descriptor Post Queue
+ */
+#define MPI2_REPLY_POST_HOST_INDEX_OFFSET       (0x0000006C)
+
+/*
+ * Defines for the HCBSize and address
+ */
+#define MPI2_HCB_SIZE_OFFSET                    (0x00000074)
+#define MPI2_HCB_SIZE_SIZE_MASK                 (0xFFFFF000)
+#define MPI2_HCB_SIZE_HCB_ENABLE                (0x00000001)
+
+#define MPI2_HCB_ADDRESS_LOW_OFFSET             (0x00000078)
+#define MPI2_HCB_ADDRESS_HIGH_OFFSET            (0x0000007C)
+
+/*
+ * Offsets for the Request Queue
+ */
+#define MPI2_REQUEST_DESCRIPTOR_POST_LOW_OFFSET     (0x000000C0)
+#define MPI2_REQUEST_DESCRIPTOR_POST_HIGH_OFFSET    (0x000000C4)
+
+
+/*****************************************************************************
+*
+*        Message Descriptors
+*
+*****************************************************************************/
+
+/* Request Descriptors */
+
+/* Default Request Descriptor */
+typedef struct _MPI2_DEFAULT_REQUEST_DESCRIPTOR
+{
+    U8              RequestFlags;               /* 0x00 */
+    U8              VF_ID;                      /* 0x01 */
+    U16             SMID;                       /* 0x02 */
+    U16             LMID;                       /* 0x04 */
+    U16             DescriptorTypeDependent;    /* 0x06 */
+} MPI2_DEFAULT_REQUEST_DESCRIPTOR,
+  MPI2_POINTER PTR_MPI2_DEFAULT_REQUEST_DESCRIPTOR,
+  Mpi2DefaultRequestDescriptor_t, MPI2_POINTER pMpi2DefaultRequestDescriptor_t;
+
+/* defines for the RequestFlags field */
+#define MPI2_REQ_DESCRIPT_FLAGS_TYPE_MASK               (0x0E)
+#define MPI2_REQ_DESCRIPT_FLAGS_SCSI_IO                 (0x00)
+#define MPI2_REQ_DESCRIPT_FLAGS_SCSI_TARGET             (0x02)
+#define MPI2_REQ_DESCRIPT_FLAGS_HIGH_PRIORITY           (0x06)
+#define MPI2_REQ_DESCRIPT_FLAGS_DEFAULT_TYPE            (0x08)
+
+#define MPI2_REQ_DESCRIPT_FLAGS_IOC_FIFO_MARKER (0x01)
+
+
+/* High Priority Request Descriptor */
+typedef struct _MPI2_HIGH_PRIORITY_REQUEST_DESCRIPTOR
+{
+    U8              RequestFlags;               /* 0x00 */
+    U8              VF_ID;                      /* 0x01 */
+    U16             SMID;                       /* 0x02 */
+    U16             LMID;                       /* 0x04 */
+    U16             Reserved1;                  /* 0x06 */
+} MPI2_HIGH_PRIORITY_REQUEST_DESCRIPTOR,
+  MPI2_POINTER PTR_MPI2_HIGH_PRIORITY_REQUEST_DESCRIPTOR,
+  Mpi2HighPriorityRequestDescriptor_t,
+  MPI2_POINTER pMpi2HighPriorityRequestDescriptor_t;
+
+
+/* SCSI IO Request Descriptor */
+typedef struct _MPI2_SCSI_IO_REQUEST_DESCRIPTOR
+{
+    U8              RequestFlags;               /* 0x00 */
+    U8              VF_ID;                      /* 0x01 */
+    U16             SMID;                       /* 0x02 */
+    U16             LMID;                       /* 0x04 */
+    U16             DevHandle;                  /* 0x06 */
+} MPI2_SCSI_IO_REQUEST_DESCRIPTOR,
+  MPI2_POINTER PTR_MPI2_SCSI_IO_REQUEST_DESCRIPTOR,
+  Mpi2SCSIIORequestDescriptor_t, MPI2_POINTER pMpi2SCSIIORequestDescriptor_t;
+
+
+/* SCSI Target Request Descriptor */
+typedef struct _MPI2_SCSI_TARGET_REQUEST_DESCRIPTOR
+{
+    U8              RequestFlags;               /* 0x00 */
+    U8              VF_ID;                      /* 0x01 */
+    U16             SMID;                       /* 0x02 */
+    U16             LMID;                       /* 0x04 */
+    U16             IoIndex;                    /* 0x06 */
+} MPI2_SCSI_TARGET_REQUEST_DESCRIPTOR,
+  MPI2_POINTER PTR_MPI2_SCSI_TARGET_REQUEST_DESCRIPTOR,
+  Mpi2SCSITargetRequestDescriptor_t,
+  MPI2_POINTER pMpi2SCSITargetRequestDescriptor_t;
+
+/* union of Request Descriptors */
+typedef union _MPI2_REQUEST_DESCRIPTOR_UNION
+{
+    MPI2_DEFAULT_REQUEST_DESCRIPTOR         Default;
+    MPI2_HIGH_PRIORITY_REQUEST_DESCRIPTOR   HighPriority;
+    MPI2_SCSI_IO_REQUEST_DESCRIPTOR         SCSIIO;
+    MPI2_SCSI_TARGET_REQUEST_DESCRIPTOR     SCSITarget;
+    U64                                     Words;
+} MPI2_REQUEST_DESCRIPTOR_UNION, MPI2_POINTER PTR_MPI2_REQUEST_DESCRIPTOR_UNION,
+  Mpi2RequestDescriptorUnion_t, MPI2_POINTER pMpi2RequestDescriptorUnion_t;
+
+
+/* Reply Descriptors */
+
+/* Default Reply Descriptor */
+typedef struct _MPI2_DEFAULT_REPLY_DESCRIPTOR
+{
+    U8              ReplyFlags;                 /* 0x00 */
+    U8              VF_ID;                      /* 0x01 */
+    U16             DescriptorTypeDependent1;   /* 0x02 */
+    U32             DescriptorTypeDependent2;   /* 0x04 */
+} MPI2_DEFAULT_REPLY_DESCRIPTOR, MPI2_POINTER PTR_MPI2_DEFAULT_REPLY_DESCRIPTOR,
+  Mpi2DefaultReplyDescriptor_t, MPI2_POINTER pMpi2DefaultReplyDescriptor_t;
+
+/* defines for the ReplyFlags field */
+#define MPI2_RPY_DESCRIPT_FLAGS_TYPE_MASK               (0x0F)
+#define MPI2_RPY_DESCRIPT_FLAGS_SCSI_IO_SUCCESS         (0x00)
+#define MPI2_RPY_DESCRIPT_FLAGS_ADDRESS_REPLY           (0x01)
+#define MPI2_RPY_DESCRIPT_FLAGS_TARGETASSIST_SUCCESS    (0x02)
+#define MPI2_RPY_DESCRIPT_FLAGS_TARGET_COMMAND_BUFFER   (0x03)
+#define MPI2_RPY_DESCRIPT_FLAGS_UNUSED                  (0x0F)
+
+/* values for marking a reply descriptor as unused */
+#define MPI2_RPY_DESCRIPT_UNUSED_WORD0_MARK             (0xFFFFFFFF)
+#define MPI2_RPY_DESCRIPT_UNUSED_WORD1_MARK             (0xFFFFFFFF)
+
+/* Address Reply Descriptor */
+typedef struct _MPI2_ADDRESS_REPLY_DESCRIPTOR
+{
+    U8              ReplyFlags;                 /* 0x00 */
+    U8              VF_ID;                      /* 0x01 */
+    U16             SMID;                       /* 0x02 */
+    U32             ReplyFrameAddress;          /* 0x04 */
+} MPI2_ADDRESS_REPLY_DESCRIPTOR, MPI2_POINTER PTR_MPI2_ADDRESS_REPLY_DESCRIPTOR,
+  Mpi2AddressReplyDescriptor_t, MPI2_POINTER pMpi2AddressReplyDescriptor_t;
+
+#define MPI2_ADDRESS_REPLY_SMID_INVALID                 (0x00)
+
+
+/* SCSI IO Success Reply Descriptor */
+typedef struct _MPI2_SCSI_IO_SUCCESS_REPLY_DESCRIPTOR
+{
+    U8              ReplyFlags;                 /* 0x00 */
+    U8              VF_ID;                      /* 0x01 */
+    U16             SMID;                       /* 0x02 */
+    U16             TaskTag;                    /* 0x04 */
+    U16             DevHandle;                  /* 0x06 */
+} MPI2_SCSI_IO_SUCCESS_REPLY_DESCRIPTOR,
+  MPI2_POINTER PTR_MPI2_SCSI_IO_SUCCESS_REPLY_DESCRIPTOR,
+  Mpi2SCSIIOSuccessReplyDescriptor_t,
+  MPI2_POINTER pMpi2SCSIIOSuccessReplyDescriptor_t;
+
+
+/* TargetAssist Success Reply Descriptor */
+typedef struct _MPI2_TARGETASSIST_SUCCESS_REPLY_DESCRIPTOR
+{
+    U8              ReplyFlags;                 /* 0x00 */
+    U8              VF_ID;                      /* 0x01 */
+    U16             SMID;                       /* 0x02 */
+    U8              SequenceNumber;             /* 0x04 */
+    U8              Reserved1;                  /* 0x05 */
+    U16             IoIndex;                    /* 0x06 */
+} MPI2_TARGETASSIST_SUCCESS_REPLY_DESCRIPTOR,
+  MPI2_POINTER PTR_MPI2_TARGETASSIST_SUCCESS_REPLY_DESCRIPTOR,
+  Mpi2TargetAssistSuccessReplyDescriptor_t,
+  MPI2_POINTER pMpi2TargetAssistSuccessReplyDescriptor_t;
+
+
+/* Target Command Buffer Reply Descriptor */
+typedef struct _MPI2_TARGET_COMMAND_BUFFER_REPLY_DESCRIPTOR
+{
+    U8              ReplyFlags;                 /* 0x00 */
+    U8              VF_ID;                      /* 0x01 */
+    U8              VP_ID;                      /* 0x02 */
+    U8              Flags;                      /* 0x03 */
+    U16             InitiatorDevHandle;         /* 0x04 */
+    U16             IoIndex;                    /* 0x06 */
+} MPI2_TARGET_COMMAND_BUFFER_REPLY_DESCRIPTOR,
+  MPI2_POINTER PTR_MPI2_TARGET_COMMAND_BUFFER_REPLY_DESCRIPTOR,
+  Mpi2TargetCommandBufferReplyDescriptor_t,
+  MPI2_POINTER pMpi2TargetCommandBufferReplyDescriptor_t;
+
+/* defines for Flags field */
+#define MPI2_RPY_DESCRIPT_TCB_FLAGS_PHYNUM_MASK     (0x3F)
+
+
+/* union of Reply Descriptors */
+typedef union _MPI2_REPLY_DESCRIPTORS_UNION
+{
+    MPI2_DEFAULT_REPLY_DESCRIPTOR               Default;
+    MPI2_ADDRESS_REPLY_DESCRIPTOR               AddressReply;
+    MPI2_SCSI_IO_SUCCESS_REPLY_DESCRIPTOR       SCSIIOSuccess;
+    MPI2_TARGETASSIST_SUCCESS_REPLY_DESCRIPTOR  TargetAssistSuccess;
+    MPI2_TARGET_COMMAND_BUFFER_REPLY_DESCRIPTOR TargetCommandBuffer;
+    U64                                         Words;
+} MPI2_REPLY_DESCRIPTORS_UNION, MPI2_POINTER PTR_MPI2_REPLY_DESCRIPTORS_UNION,
+  Mpi2ReplyDescriptorsUnion_t, MPI2_POINTER pMpi2ReplyDescriptorsUnion_t;
+
+
+
+/*****************************************************************************
+*
+*        Message Functions
+*              0x80 -> 0x8F reserved for private message use per product
+*
+*
+*****************************************************************************/
+
+#define MPI2_FUNCTION_SCSI_IO_REQUEST               (0x00) /* SCSI IO */
+#define MPI2_FUNCTION_SCSI_TASK_MGMT                (0x01) /* SCSI Task Management */
+#define MPI2_FUNCTION_IOC_INIT                      (0x02) /* IOC Init */
+#define MPI2_FUNCTION_IOC_FACTS                     (0x03) /* IOC Facts */
+#define MPI2_FUNCTION_CONFIG                        (0x04) /* Configuration */
+#define MPI2_FUNCTION_PORT_FACTS                    (0x05) /* Port Facts */
+#define MPI2_FUNCTION_PORT_ENABLE                   (0x06) /* Port Enable */
+#define MPI2_FUNCTION_EVENT_NOTIFICATION            (0x07) /* Event Notification */
+#define MPI2_FUNCTION_EVENT_ACK                     (0x08) /* Event Acknowledge */
+#define MPI2_FUNCTION_FW_DOWNLOAD                   (0x09) /* FW Download */
+#define MPI2_FUNCTION_TARGET_ASSIST                 (0x0B) /* Target Assist */
+#define MPI2_FUNCTION_TARGET_STATUS_SEND            (0x0C) /* Target Status Send */
+#define MPI2_FUNCTION_TARGET_MODE_ABORT             (0x0D) /* Target Mode Abort */
+#define MPI2_FUNCTION_FW_UPLOAD                     (0x12) /* FW Upload */
+#define MPI2_FUNCTION_RAID_ACTION                   (0x15) /* RAID Action */
+#define MPI2_FUNCTION_RAID_SCSI_IO_PASSTHROUGH      (0x16) /* SCSI IO RAID Passthrough */
+#define MPI2_FUNCTION_TOOLBOX                       (0x17) /* Toolbox */
+#define MPI2_FUNCTION_SCSI_ENCLOSURE_PROCESSOR      (0x18) /* SCSI Enclosure Processor */
+#define MPI2_FUNCTION_SMP_PASSTHROUGH               (0x1A) /* SMP Passthrough */
+#define MPI2_FUNCTION_SAS_IO_UNIT_CONTROL           (0x1B) /* SAS IO Unit Control */
+#define MPI2_FUNCTION_SATA_PASSTHROUGH              (0x1C) /* SATA Passthrough */
+#define MPI2_FUNCTION_DIAG_BUFFER_POST              (0x1D) /* Diagnostic Buffer Post */
+#define MPI2_FUNCTION_DIAG_RELEASE                  (0x1E) /* Diagnostic Release */
+#define MPI2_FUNCTION_TARGET_CMD_BUF_BASE_POST      (0x24) /* Target Command Buffer Post Base */
+#define MPI2_FUNCTION_TARGET_CMD_BUF_LIST_POST      (0x25) /* Target Command Buffer Post List */
+
+
+
+/* Doorbell functions */
+#define MPI2_FUNCTION_IOC_MESSAGE_UNIT_RESET        (0x40)
+/* #define MPI2_FUNCTION_IO_UNIT_RESET                 (0x41) */
+#define MPI2_FUNCTION_HANDSHAKE                     (0x42)
+
+
+/*****************************************************************************
+*
+*        IOC Status Values
+*
+*****************************************************************************/
+
+/* mask for IOCStatus status value */
+#define MPI2_IOCSTATUS_MASK                     (0x7FFF)
+
+/****************************************************************************
+*  Common IOCStatus values for all replies
+****************************************************************************/
+
+#define MPI2_IOCSTATUS_SUCCESS                      (0x0000)
+#define MPI2_IOCSTATUS_INVALID_FUNCTION             (0x0001)
+#define MPI2_IOCSTATUS_BUSY                         (0x0002)
+#define MPI2_IOCSTATUS_INVALID_SGL                  (0x0003)
+#define MPI2_IOCSTATUS_INTERNAL_ERROR               (0x0004)
+#define MPI2_IOCSTATUS_INVALID_VPID                 (0x0005)
+#define MPI2_IOCSTATUS_INSUFFICIENT_RESOURCES       (0x0006)
+#define MPI2_IOCSTATUS_INVALID_FIELD                (0x0007)
+#define MPI2_IOCSTATUS_INVALID_STATE                (0x0008)
+#define MPI2_IOCSTATUS_OP_STATE_NOT_SUPPORTED       (0x0009)
+
+/****************************************************************************
+*  Config IOCStatus values
+****************************************************************************/
+
+#define MPI2_IOCSTATUS_CONFIG_INVALID_ACTION        (0x0020)
+#define MPI2_IOCSTATUS_CONFIG_INVALID_TYPE          (0x0021)
+#define MPI2_IOCSTATUS_CONFIG_INVALID_PAGE          (0x0022)
+#define MPI2_IOCSTATUS_CONFIG_INVALID_DATA          (0x0023)
+#define MPI2_IOCSTATUS_CONFIG_NO_DEFAULTS           (0x0024)
+#define MPI2_IOCSTATUS_CONFIG_CANT_COMMIT           (0x0025)
+
+/****************************************************************************
+*  SCSI IO Reply
+****************************************************************************/
+
+#define MPI2_IOCSTATUS_SCSI_RECOVERED_ERROR         (0x0040)
+#define MPI2_IOCSTATUS_SCSI_INVALID_DEVHANDLE       (0x0042)
+#define MPI2_IOCSTATUS_SCSI_DEVICE_NOT_THERE        (0x0043)
+#define MPI2_IOCSTATUS_SCSI_DATA_OVERRUN            (0x0044)
+#define MPI2_IOCSTATUS_SCSI_DATA_UNDERRUN           (0x0045)
+#define MPI2_IOCSTATUS_SCSI_IO_DATA_ERROR           (0x0046)
+#define MPI2_IOCSTATUS_SCSI_PROTOCOL_ERROR          (0x0047)
+#define MPI2_IOCSTATUS_SCSI_TASK_TERMINATED         (0x0048)
+#define MPI2_IOCSTATUS_SCSI_RESIDUAL_MISMATCH       (0x0049)
+#define MPI2_IOCSTATUS_SCSI_TASK_MGMT_FAILED        (0x004A)
+#define MPI2_IOCSTATUS_SCSI_IOC_TERMINATED          (0x004B)
+#define MPI2_IOCSTATUS_SCSI_EXT_TERMINATED          (0x004C)
+
+/****************************************************************************
+*  For use by SCSI Initiator and SCSI Target end-to-end data protection
+****************************************************************************/
+
+#define MPI2_IOCSTATUS_EEDP_GUARD_ERROR             (0x004D)
+#define MPI2_IOCSTATUS_EEDP_REF_TAG_ERROR           (0x004E)
+#define MPI2_IOCSTATUS_EEDP_APP_TAG_ERROR           (0x004F)
+
+/****************************************************************************
+*  SCSI Target values
+****************************************************************************/
+
+#define MPI2_IOCSTATUS_TARGET_INVALID_IO_INDEX      (0x0062)
+#define MPI2_IOCSTATUS_TARGET_ABORTED               (0x0063)
+#define MPI2_IOCSTATUS_TARGET_NO_CONN_RETRYABLE     (0x0064)
+#define MPI2_IOCSTATUS_TARGET_NO_CONNECTION         (0x0065)
+#define MPI2_IOCSTATUS_TARGET_XFER_COUNT_MISMATCH   (0x006A)
+#define MPI2_IOCSTATUS_TARGET_DATA_OFFSET_ERROR     (0x006D)
+#define MPI2_IOCSTATUS_TARGET_TOO_MUCH_WRITE_DATA   (0x006E)
+#define MPI2_IOCSTATUS_TARGET_IU_TOO_SHORT          (0x006F)
+#define MPI2_IOCSTATUS_TARGET_ACK_NAK_TIMEOUT       (0x0070)
+#define MPI2_IOCSTATUS_TARGET_NAK_RECEIVED          (0x0071)
+
+/****************************************************************************
+*  Serial Attached SCSI values
+****************************************************************************/
+
+#define MPI2_IOCSTATUS_SAS_SMP_REQUEST_FAILED       (0x0090)
+#define MPI2_IOCSTATUS_SAS_SMP_DATA_OVERRUN         (0x0091)
+
+/****************************************************************************
+*  Diagnostic Buffer Post / Diagnostic Release values
+****************************************************************************/
+
+#define MPI2_IOCSTATUS_DIAGNOSTIC_RELEASED          (0x00A0)
+
+
+/****************************************************************************
+*  IOCStatus flag to indicate that log info is available
+****************************************************************************/
+
+#define MPI2_IOCSTATUS_FLAG_LOG_INFO_AVAILABLE  (0x8000)
+
+/****************************************************************************
+*  IOCLogInfo Types
+****************************************************************************/
+
+#define MPI2_IOCLOGINFO_TYPE_MASK               (0xF0000000)
+#define MPI2_IOCLOGINFO_TYPE_SHIFT              (28)
+#define MPI2_IOCLOGINFO_TYPE_NONE               (0x0)
+#define MPI2_IOCLOGINFO_TYPE_SCSI               (0x1)
+#define MPI2_IOCLOGINFO_TYPE_FC                 (0x2)
+#define MPI2_IOCLOGINFO_TYPE_SAS                (0x3)
+#define MPI2_IOCLOGINFO_TYPE_ISCSI              (0x4)
+#define MPI2_IOCLOGINFO_LOG_DATA_MASK           (0x0FFFFFFF)
+
+
+/*****************************************************************************
+*
+*        Standard Message Structures
+*
+*****************************************************************************/
+
+/****************************************************************************
+* Request Message Header for all request messages
+****************************************************************************/
+
+typedef struct _MPI2_REQUEST_HEADER
+{
+    U16             FunctionDependent1;         /* 0x00 */
+    U8              ChainOffset;                /* 0x02 */
+    U8              Function;                   /* 0x03 */
+    U16             FunctionDependent2;         /* 0x04 */
+    U8              FunctionDependent3;         /* 0x06 */
+    U8              MsgFlags;                   /* 0x07 */
+    U8              VP_ID;                      /* 0x08 */
+    U8              VF_ID;                      /* 0x09 */
+    U16             Reserved1;                  /* 0x0A */
+} MPI2_REQUEST_HEADER, MPI2_POINTER PTR_MPI2_REQUEST_HEADER,
+  MPI2RequestHeader_t, MPI2_POINTER pMPI2RequestHeader_t;
+
+
+/****************************************************************************
+*  Default Reply
+****************************************************************************/
+
+typedef struct _MPI2_DEFAULT_REPLY
+{
+    U16             FunctionDependent1;         /* 0x00 */
+    U8              MsgLength;                  /* 0x02 */
+    U8              Function;                   /* 0x03 */
+    U16             FunctionDependent2;         /* 0x04 */
+    U8              FunctionDependent3;         /* 0x06 */
+    U8              MsgFlags;                   /* 0x07 */
+    U8              VP_ID;                      /* 0x08 */
+    U8              VF_ID;                      /* 0x09 */
+    U16             Reserved1;                  /* 0x0A */
+    U16             FunctionDependent5;         /* 0x0C */
+    U16             IOCStatus;                  /* 0x0E */
+    U32             IOCLogInfo;                 /* 0x10 */
+} MPI2_DEFAULT_REPLY, MPI2_POINTER PTR_MPI2_DEFAULT_REPLY,
+  MPI2DefaultReply_t, MPI2_POINTER pMPI2DefaultReply_t;
+
+
+/* common version structure/union used in messages and configuration pages */
+
+typedef struct _MPI2_VERSION_STRUCT
+{
+    U8                      Dev;                        /* 0x00 */
+    U8                      Unit;                       /* 0x01 */
+    U8                      Minor;                      /* 0x02 */
+    U8                      Major;                      /* 0x03 */
+} MPI2_VERSION_STRUCT;
+
+typedef union _MPI2_VERSION_UNION
+{
+    MPI2_VERSION_STRUCT     Struct;
+    U32                     Word;
+} MPI2_VERSION_UNION;
+
+
+/* LUN field defines, common to many structures */
+#define MPI2_LUN_FIRST_LEVEL_ADDRESSING             (0x0000FFFF)
+#define MPI2_LUN_SECOND_LEVEL_ADDRESSING            (0xFFFF0000)
+#define MPI2_LUN_THIRD_LEVEL_ADDRESSING             (0x0000FFFF)
+#define MPI2_LUN_FOURTH_LEVEL_ADDRESSING            (0xFFFF0000)
+#define MPI2_LUN_LEVEL_1_WORD                       (0xFF00)
+#define MPI2_LUN_LEVEL_1_DWORD                      (0x0000FF00)
+
+
+/*****************************************************************************
+*
+*        Fusion-MPT MPI Scatter Gather Elements
+*
+*****************************************************************************/
+
+/****************************************************************************
+*  MPI Simple Element structures
+****************************************************************************/
+
+typedef struct _MPI2_SGE_SIMPLE32
+{
+    U32                     FlagsLength;
+    U32                     Address;
+} MPI2_SGE_SIMPLE32, MPI2_POINTER PTR_MPI2_SGE_SIMPLE32,
+  Mpi2SGESimple32_t, MPI2_POINTER pMpi2SGESimple32_t;
+
+typedef struct _MPI2_SGE_SIMPLE64
+{
+    U32                     FlagsLength;
+    U64                     Address;
+} MPI2_SGE_SIMPLE64, MPI2_POINTER PTR_MPI2_SGE_SIMPLE64,
+  Mpi2SGESimple64_t, MPI2_POINTER pMpi2SGESimple64_t;
+
+typedef struct _MPI2_SGE_SIMPLE_UNION
+{
+    U32                     FlagsLength;
+    union
+    {
+        U32                 Address32;
+        U64                 Address64;
+    } u;
+} MPI2_SGE_SIMPLE_UNION, MPI2_POINTER PTR_MPI2_SGE_SIMPLE_UNION,
+  Mpi2SGESimpleUnion_t, MPI2_POINTER pMpi2SGESimpleUnion_t;
+
+
+/****************************************************************************
+*  MPI Chain Element structures
+****************************************************************************/
+
+typedef struct _MPI2_SGE_CHAIN32
+{
+    U16                     Length;
+    U8                      NextChainOffset;
+    U8                      Flags;
+    U32                     Address;
+} MPI2_SGE_CHAIN32, MPI2_POINTER PTR_MPI2_SGE_CHAIN32,
+  Mpi2SGEChain32_t, MPI2_POINTER pMpi2SGEChain32_t;
+
+typedef struct _MPI2_SGE_CHAIN64
+{
+    U16                     Length;
+    U8                      NextChainOffset;
+    U8                      Flags;
+    U64                     Address;
+} MPI2_SGE_CHAIN64, MPI2_POINTER PTR_MPI2_SGE_CHAIN64,
+  Mpi2SGEChain64_t, MPI2_POINTER pMpi2SGEChain64_t;
+
+typedef struct _MPI2_SGE_CHAIN_UNION
+{
+    U16                     Length;
+    U8                      NextChainOffset;
+    U8                      Flags;
+    union
+    {
+        U32                 Address32;
+        U64                 Address64;
+    } u;
+} MPI2_SGE_CHAIN_UNION, MPI2_POINTER PTR_MPI2_SGE_CHAIN_UNION,
+  Mpi2SGEChainUnion_t, MPI2_POINTER pMpi2SGEChainUnion_t;
+
+
+/****************************************************************************
+*  MPI Transaction Context Element structures
+****************************************************************************/
+
+typedef struct _MPI2_SGE_TRANSACTION32
+{
+    U8                      Reserved;
+    U8                      ContextSize;
+    U8                      DetailsLength;
+    U8                      Flags;
+    U32                     TransactionContext[1];
+    U32                     TransactionDetails[1];
+} MPI2_SGE_TRANSACTION32, MPI2_POINTER PTR_MPI2_SGE_TRANSACTION32,
+  Mpi2SGETransaction32_t, MPI2_POINTER pMpi2SGETransaction32_t;
+
+typedef struct _MPI2_SGE_TRANSACTION64
+{
+    U8                      Reserved;
+    U8                      ContextSize;
+    U8                      DetailsLength;
+    U8                      Flags;
+    U32                     TransactionContext[2];
+    U32                     TransactionDetails[1];
+} MPI2_SGE_TRANSACTION64, MPI2_POINTER PTR_MPI2_SGE_TRANSACTION64,
+  Mpi2SGETransaction64_t, MPI2_POINTER pMpi2SGETransaction64_t;
+
+typedef struct _MPI2_SGE_TRANSACTION96
+{
+    U8                      Reserved;
+    U8                      ContextSize;
+    U8                      DetailsLength;
+    U8                      Flags;
+    U32                     TransactionContext[3];
+    U32                     TransactionDetails[1];
+} MPI2_SGE_TRANSACTION96, MPI2_POINTER PTR_MPI2_SGE_TRANSACTION96,
+  Mpi2SGETransaction96_t, MPI2_POINTER pMpi2SGETransaction96_t;
+
+typedef struct _MPI2_SGE_TRANSACTION128
+{
+    U8                      Reserved;
+    U8                      ContextSize;
+    U8                      DetailsLength;
+    U8                      Flags;
+    U32                     TransactionContext[4];
+    U32                     TransactionDetails[1];
+} MPI2_SGE_TRANSACTION128, MPI2_POINTER PTR_MPI2_SGE_TRANSACTION128,
+  Mpi2SGETransaction_t128, MPI2_POINTER pMpi2SGETransaction_t128;
+
+typedef struct _MPI2_SGE_TRANSACTION_UNION
+{
+    U8                      Reserved;
+    U8                      ContextSize;
+    U8                      DetailsLength;
+    U8                      Flags;
+    union
+    {
+        U32                 TransactionContext32[1];
+        U32                 TransactionContext64[2];
+        U32                 TransactionContext96[3];
+        U32                 TransactionContext128[4];
+    } u;
+    U32                     TransactionDetails[1];
+} MPI2_SGE_TRANSACTION_UNION, MPI2_POINTER PTR_MPI2_SGE_TRANSACTION_UNION,
+  Mpi2SGETransactionUnion_t, MPI2_POINTER pMpi2SGETransactionUnion_t;
+
+
+/****************************************************************************
+*  MPI SGE union for IO SGL's
+****************************************************************************/
+
+typedef struct _MPI2_MPI_SGE_IO_UNION
+{
+    union
+    {
+        MPI2_SGE_SIMPLE_UNION   Simple;
+        MPI2_SGE_CHAIN_UNION    Chain;
+    } u;
+} MPI2_MPI_SGE_IO_UNION, MPI2_POINTER PTR_MPI2_MPI_SGE_IO_UNION,
+  Mpi2MpiSGEIOUnion_t, MPI2_POINTER pMpi2MpiSGEIOUnion_t;
+
+
+/****************************************************************************
+*  MPI SGE union for SGL's with Simple and Transaction elements
+****************************************************************************/
+
+typedef struct _MPI2_SGE_TRANS_SIMPLE_UNION
+{
+    union
+    {
+        MPI2_SGE_SIMPLE_UNION       Simple;
+        MPI2_SGE_TRANSACTION_UNION  Transaction;
+    } u;
+} MPI2_SGE_TRANS_SIMPLE_UNION, MPI2_POINTER PTR_MPI2_SGE_TRANS_SIMPLE_UNION,
+  Mpi2SGETransSimpleUnion_t, MPI2_POINTER pMpi2SGETransSimpleUnion_t;
+
+
+/****************************************************************************
+*  All MPI SGE types union
+****************************************************************************/
+
+typedef struct _MPI2_MPI_SGE_UNION
+{
+    union
+    {
+        MPI2_SGE_SIMPLE_UNION       Simple;
+        MPI2_SGE_CHAIN_UNION        Chain;
+        MPI2_SGE_TRANSACTION_UNION  Transaction;
+    } u;
+} MPI2_MPI_SGE_UNION, MPI2_POINTER PTR_MPI2_MPI_SGE_UNION,
+  Mpi2MpiSgeUnion_t, MPI2_POINTER pMpi2MpiSgeUnion_t;
+
+
+/****************************************************************************
+*  MPI SGE field definition and masks
+****************************************************************************/
+
+/* Flags field bit definitions */
+
+#define MPI2_SGE_FLAGS_LAST_ELEMENT             (0x80)
+#define MPI2_SGE_FLAGS_END_OF_BUFFER            (0x40)
+#define MPI2_SGE_FLAGS_ELEMENT_TYPE_MASK        (0x30)
+#define MPI2_SGE_FLAGS_LOCAL_ADDRESS            (0x08)
+#define MPI2_SGE_FLAGS_DIRECTION                (0x04)
+#define MPI2_SGE_FLAGS_ADDRESS_SIZE             (0x02)
+#define MPI2_SGE_FLAGS_END_OF_LIST              (0x01)
+
+#define MPI2_SGE_FLAGS_SHIFT                    (24)
+
+#define MPI2_SGE_LENGTH_MASK                    (0x00FFFFFF)
+#define MPI2_SGE_CHAIN_LENGTH_MASK              (0x0000FFFF)
+
+/* Element Type */
+
+#define MPI2_SGE_FLAGS_TRANSACTION_ELEMENT      (0x00)
+#define MPI2_SGE_FLAGS_SIMPLE_ELEMENT           (0x10)
+#define MPI2_SGE_FLAGS_CHAIN_ELEMENT            (0x30)
+#define MPI2_SGE_FLAGS_ELEMENT_MASK             (0x30)
+
+/* Address location */
+
+#define MPI2_SGE_FLAGS_SYSTEM_ADDRESS           (0x00)
+
+/* Direction */
+
+#define MPI2_SGE_FLAGS_IOC_TO_HOST              (0x00)
+#define MPI2_SGE_FLAGS_HOST_TO_IOC              (0x04)
+
+/* Address Size */
+
+#define MPI2_SGE_FLAGS_32_BIT_ADDRESSING        (0x00)
+#define MPI2_SGE_FLAGS_64_BIT_ADDRESSING        (0x02)
+
+/* Context Size */
+
+#define MPI2_SGE_FLAGS_32_BIT_CONTEXT           (0x00)
+#define MPI2_SGE_FLAGS_64_BIT_CONTEXT           (0x02)
+#define MPI2_SGE_FLAGS_96_BIT_CONTEXT           (0x04)
+#define MPI2_SGE_FLAGS_128_BIT_CONTEXT          (0x06)
+
+#define MPI2_SGE_CHAIN_OFFSET_MASK              (0x00FF0000)
+#define MPI2_SGE_CHAIN_OFFSET_SHIFT             (16)
+
+/****************************************************************************
+*  MPI SGE operation Macros
+****************************************************************************/
+
+/* SIMPLE FlagsLength manipulations... */
+#define MPI2_SGE_SET_FLAGS(f)          ((U32)(f) << MPI2_SGE_FLAGS_SHIFT)
+#define MPI2_SGE_GET_FLAGS(f)          (((f) & ~MPI2_SGE_LENGTH_MASK) >> MPI2_SGE_FLAGS_SHIFT)
+#define MPI2_SGE_LENGTH(f)             ((f) & MPI2_SGE_LENGTH_MASK)
+#define MPI2_SGE_CHAIN_LENGTH(f)       ((f) & MPI2_SGE_CHAIN_LENGTH_MASK)
+
+#define MPI2_SGE_SET_FLAGS_LENGTH(f,l) (MPI2_SGE_SET_FLAGS(f) | MPI2_SGE_LENGTH(l))
+
+#define MPI2_pSGE_GET_FLAGS(psg)            MPI2_SGE_GET_FLAGS((psg)->FlagsLength)
+#define MPI2_pSGE_GET_LENGTH(psg)           MPI2_SGE_LENGTH((psg)->FlagsLength)
+#define MPI2_pSGE_SET_FLAGS_LENGTH(psg,f,l) (psg)->FlagsLength = MPI2_SGE_SET_FLAGS_LENGTH(f,l)
+
+/* CAUTION - The following are READ-MODIFY-WRITE! */
+#define MPI2_pSGE_SET_FLAGS(psg,f)      (psg)->FlagsLength |= MPI2_SGE_SET_FLAGS(f)
+#define MPI2_pSGE_SET_LENGTH(psg,l)     (psg)->FlagsLength |= MPI2_SGE_LENGTH(l)
+
+#define MPI2_GET_CHAIN_OFFSET(x)    ((x & MPI2_SGE_CHAIN_OFFSET_MASK) >> MPI2_SGE_CHAIN_OFFSET_SHIFT)
+
+
+/*****************************************************************************
+*
+*        Fusion-MPT IEEE Scatter Gather Elements
+*
+*****************************************************************************/
+
+/****************************************************************************
+*  IEEE Simple Element structures
+****************************************************************************/
+
+typedef struct _MPI2_IEEE_SGE_SIMPLE32
+{
+    U32                     Address;
+    U32                     FlagsLength;
+} MPI2_IEEE_SGE_SIMPLE32, MPI2_POINTER PTR_MPI2_IEEE_SGE_SIMPLE32,
+  Mpi2IeeeSgeSimple32_t, MPI2_POINTER pMpi2IeeeSgeSimple32_t;
+
+typedef struct _MPI2_IEEE_SGE_SIMPLE64
+{
+    U64                     Address;
+    U32                     Length;
+    U16                     Reserved1;
+    U8                      Reserved2;
+    U8                      Flags;
+} MPI2_IEEE_SGE_SIMPLE64, MPI2_POINTER PTR_MPI2_IEEE_SGE_SIMPLE64,
+  Mpi2IeeeSgeSimple64_t, MPI2_POINTER pMpi2IeeeSgeSimple64_t;
+
+typedef union _MPI2_IEEE_SGE_SIMPLE_UNION
+{
+    MPI2_IEEE_SGE_SIMPLE32  Simple32;
+    MPI2_IEEE_SGE_SIMPLE64  Simple64;
+} MPI2_IEEE_SGE_SIMPLE_UNION, MPI2_POINTER PTR_MPI2_IEEE_SGE_SIMPLE_UNION,
+  Mpi2IeeeSgeSimpleUnion_t, MPI2_POINTER pMpi2IeeeSgeSimpleUnion_t;
+
+
+/****************************************************************************
+*  IEEE Chain Element structures
+****************************************************************************/
+
+typedef MPI2_IEEE_SGE_SIMPLE32  MPI2_IEEE_SGE_CHAIN32;
+
+typedef MPI2_IEEE_SGE_SIMPLE64  MPI2_IEEE_SGE_CHAIN64;
+
+typedef union _MPI2_IEEE_SGE_CHAIN_UNION
+{
+    MPI2_IEEE_SGE_CHAIN32   Chain32;
+    MPI2_IEEE_SGE_CHAIN64   Chain64;
+} MPI2_IEEE_SGE_CHAIN_UNION, MPI2_POINTER PTR_MPI2_IEEE_SGE_CHAIN_UNION,
+  Mpi2IeeeSgeChainUnion_t, MPI2_POINTER pMpi2IeeeSgeChainUnion_t;
+
+
+/****************************************************************************
+*  All IEEE SGE types union
+****************************************************************************/
+
+typedef struct _MPI2_IEEE_SGE_UNION
+{
+    union
+    {
+        MPI2_IEEE_SGE_SIMPLE_UNION  Simple;
+        MPI2_IEEE_SGE_CHAIN_UNION   Chain;
+    } u;
+} MPI2_IEEE_SGE_UNION, MPI2_POINTER PTR_MPI2_IEEE_SGE_UNION,
+  Mpi2IeeeSgeUnion_t, MPI2_POINTER pMpi2IeeeSgeUnion_t;
+
+
+/****************************************************************************
+*  IEEE SGE field definitions and masks
+****************************************************************************/
+
+/* Flags field bit definitions */
+
+#define MPI2_IEEE_SGE_FLAGS_ELEMENT_TYPE_MASK   (0x80)
+
+#define MPI2_IEEE32_SGE_FLAGS_SHIFT             (24)
+
+#define MPI2_IEEE32_SGE_LENGTH_MASK             (0x00FFFFFF)
+
+/* Element Type */
+
+#define MPI2_IEEE_SGE_FLAGS_SIMPLE_ELEMENT      (0x00)
+#define MPI2_IEEE_SGE_FLAGS_CHAIN_ELEMENT       (0x80)
+
+/* 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_IOCPLB_ADDR         (0x02)
+#define MPI2_IEEE_SGE_FLAGS_IOCPLBNTA_ADDR      (0x03)
+
+
+/****************************************************************************
+*  IEEE SGE operation Macros
+****************************************************************************/
+
+/* SIMPLE FlagsLength manipulations... */
+#define MPI2_IEEE32_SGE_SET_FLAGS(f)     ((U32)(f) << MPI2_IEEE32_SGE_FLAGS_SHIFT)
+#define MPI2_IEEE32_SGE_GET_FLAGS(f)     (((f) & ~MPI2_IEEE32_SGE_LENGTH_MASK) >> MPI2_IEEE32_SGE_FLAGS_SHIFT)
+#define MPI2_IEEE32_SGE_LENGTH(f)        ((f) & MPI2_IEEE32_SGE_LENGTH_MASK)
+
+#define MPI2_IEEE32_SGE_SET_FLAGS_LENGTH(f, l)      (MPI2_IEEE32_SGE_SET_FLAGS(f) | MPI2_IEEE32_SGE_LENGTH(l))
+
+#define MPI2_IEEE32_pSGE_GET_FLAGS(psg)             MPI2_IEEE32_SGE_GET_FLAGS((psg)->FlagsLength)
+#define MPI2_IEEE32_pSGE_GET_LENGTH(psg)            MPI2_IEEE32_SGE_LENGTH((psg)->FlagsLength)
+#define MPI2_IEEE32_pSGE_SET_FLAGS_LENGTH(psg,f,l)  (psg)->FlagsLength = MPI2_IEEE32_SGE_SET_FLAGS_LENGTH(f,l)
+
+/* CAUTION - The following are READ-MODIFY-WRITE! */
+#define MPI2_IEEE32_pSGE_SET_FLAGS(psg,f)    (psg)->FlagsLength |= MPI2_IEEE32_SGE_SET_FLAGS(f)
+#define MPI2_IEEE32_pSGE_SET_LENGTH(psg,l)   (psg)->FlagsLength |= MPI2_IEEE32_SGE_LENGTH(l)
+
+
+
+
+/*****************************************************************************
+*
+*        Fusion-MPT MPI/IEEE Scatter Gather Unions
+*
+*****************************************************************************/
+
+typedef union _MPI2_SIMPLE_SGE_UNION
+{
+    MPI2_SGE_SIMPLE_UNION       MpiSimple;
+    MPI2_IEEE_SGE_SIMPLE_UNION  IeeeSimple;
+} MPI2_SIMPLE_SGE_UNION, MPI2_POINTER PTR_MPI2_SIMPLE_SGE_UNION,
+  Mpi2SimpleSgeUntion_t, MPI2_POINTER pMpi2SimpleSgeUntion_t;
+
+
+typedef union _MPI2_SGE_IO_UNION
+{
+    MPI2_SGE_SIMPLE_UNION       MpiSimple;
+    MPI2_SGE_CHAIN_UNION        MpiChain;
+    MPI2_IEEE_SGE_SIMPLE_UNION  IeeeSimple;
+    MPI2_IEEE_SGE_CHAIN_UNION   IeeeChain;
+} MPI2_SGE_IO_UNION, MPI2_POINTER PTR_MPI2_SGE_IO_UNION,
+  Mpi2SGEIOUnion_t, MPI2_POINTER pMpi2SGEIOUnion_t;
+
+
+/****************************************************************************
+*
+*  Values for SGLFlags field, used in many request messages with an SGL
+*
+****************************************************************************/
+
+/* values for MPI SGL Data Location Address Space subfield */
+#define MPI2_SGLFLAGS_ADDRESS_SPACE_MASK            (0x0C)
+#define MPI2_SGLFLAGS_SYSTEM_ADDRESS_SPACE          (0x00)
+#define MPI2_SGLFLAGS_IOCDDR_ADDRESS_SPACE          (0x04)
+#define MPI2_SGLFLAGS_IOCPLB_ADDRESS_SPACE          (0x08)
+#define MPI2_SGLFLAGS_IOCPLBNTA_ADDRESS_SPACE       (0x0C)
+/* values for SGL Type subfield */
+#define MPI2_SGLFLAGS_SGL_TYPE_MASK                 (0x03)
+#define MPI2_SGLFLAGS_SGL_TYPE_MPI                  (0x00)
+#define MPI2_SGLFLAGS_SGL_TYPE_IEEE32               (0x01)
+#define MPI2_SGLFLAGS_SGL_TYPE_IEEE64               (0x02)
+
+
+#endif
+
diff --git a/drivers/scsi/mpt2sas/mpi/mpi2_cnfg.h b/drivers/scsi/mpt2sas/mpi/mpi2_cnfg.h
new file mode 100644 (file)
index 0000000..2f27cf6
--- /dev/null
@@ -0,0 +1,2151 @@
+/*
+ *  Copyright (c) 2000-2009 LSI Corporation.
+ *
+ *
+ *           Name:  mpi2_cnfg.h
+ *          Title:  MPI Configuration messages and pages
+ *  Creation Date:  November 10, 2006
+ *
+ *    mpi2_cnfg.h Version:  02.00.10
+ *
+ *  Version History
+ *  ---------------
+ *
+ *  Date      Version   Description
+ *  --------  --------  ------------------------------------------------------
+ *  04-30-07  02.00.00  Corresponds to Fusion-MPT MPI Specification Rev A.
+ *  06-04-07  02.00.01  Added defines for SAS IO Unit Page 2 PhyFlags.
+ *                      Added Manufacturing Page 11.
+ *                      Added MPI2_SAS_EXPANDER0_FLAGS_CONNECTOR_END_DEVICE
+ *                      define.
+ *  06-26-07  02.00.02  Adding generic structure for product-specific
+ *                      Manufacturing pages: MPI2_CONFIG_PAGE_MANUFACTURING_PS.
+ *                      Rework of BIOS Page 2 configuration page.
+ *                      Fixed MPI2_BIOSPAGE2_BOOT_DEVICE to be a union of the
+ *                      forms.
+ *                      Added configuration pages IOC Page 8 and Driver
+ *                      Persistent Mapping Page 0.
+ *  08-31-07  02.00.03  Modified configuration pages dealing with Integrated
+ *                      RAID (Manufacturing Page 4, RAID Volume Pages 0 and 1,
+ *                      RAID Physical Disk Pages 0 and 1, RAID Configuration
+ *                      Page 0).
+ *                      Added new value for AccessStatus field of SAS Device
+ *                      Page 0 (_SATA_NEEDS_INITIALIZATION).
+ *  10-31-07  02.00.04  Added missing SEPDevHandle field to
+ *                      MPI2_CONFIG_PAGE_SAS_ENCLOSURE_0.
+ *  12-18-07  02.00.05  Modified IO Unit Page 0 to use 32-bit version fields for
+ *                      NVDATA.
+ *                      Modified IOC Page 7 to use masks and added field for
+ *                      SASBroadcastPrimitiveMasks.
+ *                      Added MPI2_CONFIG_PAGE_BIOS_4.
+ *                      Added MPI2_CONFIG_PAGE_LOG_0.
+ *  02-29-08  02.00.06  Modified various names to make them 32-character unique.
+ *                      Added SAS Device IDs.
+ *                      Updated Integrated RAID configuration pages including
+ *                      Manufacturing Page 4, IOC Page 6, and RAID Configuration
+ *                      Page 0.
+ *  05-21-08  02.00.07  Added define MPI2_MANPAGE4_MIX_SSD_SAS_SATA.
+ *                      Added define MPI2_MANPAGE4_PHYSDISK_128MB_COERCION.
+ *                      Fixed define MPI2_IOCPAGE8_FLAGS_ENCLOSURE_SLOT_MAPPING.
+ *                      Added missing MaxNumRoutedSasAddresses field to
+ *                      MPI2_CONFIG_PAGE_EXPANDER_0.
+ *                      Added SAS Port Page 0.
+ *                      Modified structure layout for
+ *                      MPI2_CONFIG_PAGE_DRIVER_MAPPING_0.
+ *  06-27-08  02.00.08  Changed MPI2_CONFIG_PAGE_RD_PDISK_1 to use
+ *                      MPI2_RAID_PHYS_DISK1_PATH_MAX to size the array.
+ *  10-02-08  02.00.09  Changed MPI2_RAID_PGAD_CONFIGNUM_MASK from 0x0000FFFF
+ *                      to 0x000000FF.
+ *                      Added two new values for the Physical Disk Coercion Size
+ *                      bits in the Flags field of Manufacturing Page 4.
+ *                      Added product-specific Manufacturing pages 16 to 31.
+ *                      Modified Flags bits for controlling write cache on SATA
+ *                      drives in IO Unit Page 1.
+ *                      Added new bit to AdditionalControlFlags of SAS IO Unit
+ *                      Page 1 to control Invalid Topology Correction.
+ *                      Added additional defines for RAID Volume Page 0
+ *                      VolumeStatusFlags field.
+ *                      Modified meaning of RAID Volume Page 0 VolumeSettings
+ *                      define for auto-configure of hot-swap drives.
+ *                      Added SupportedPhysDisks field to RAID Volume Page 1 and
+ *                      added related defines.
+ *                      Added PhysDiskAttributes field (and related defines) to
+ *                      RAID Physical Disk Page 0.
+ *                      Added MPI2_SAS_PHYINFO_PHY_VACANT define.
+ *                      Added three new DiscoveryStatus bits for SAS IO Unit
+ *                      Page 0 and SAS Expander Page 0.
+ *                      Removed multiplexing information from SAS IO Unit pages.
+ *                      Added BootDeviceWaitTime field to SAS IO Unit Page 4.
+ *                      Removed Zone Address Resolved bit from PhyInfo and from
+ *                      Expander Page 0 Flags field.
+ *                      Added two new AccessStatus values to SAS Device Page 0
+ *                      for indicating routing problems. Added 3 reserved words
+ *                      to this page.
+ *  01-19-09  02.00.10  Fixed defines for GPIOVal field of IO Unit Page 3.
+ *                      Inserted missing reserved field into structure for IOC
+ *                      Page 6.
+ *                      Added more pending task bits to RAID Volume Page 0
+ *                      VolumeStatusFlags defines.
+ *                      Added MPI2_PHYSDISK0_STATUS_FLAG_NOT_CERTIFIED define.
+ *                      Added a new DiscoveryStatus bit for SAS IO Unit Page 0
+ *                      and SAS Expander Page 0 to flag a downstream initiator
+ *                      when in simplified routing mode.
+ *                      Removed SATA Init Failure defines for DiscoveryStatus
+ *                      fields of SAS IO Unit Page 0 and SAS Expander Page 0.
+ *                      Added MPI2_SAS_DEVICE0_ASTATUS_DEVICE_BLOCKED define.
+ *                      Added PortGroups, DmaGroup, and ControlGroup fields to
+ *                      SAS Device Page 0.
+ *  --------------------------------------------------------------------------
+ */
+
+#ifndef MPI2_CNFG_H
+#define MPI2_CNFG_H
+
+/*****************************************************************************
+*   Configuration Page Header and defines
+*****************************************************************************/
+
+/* Config Page Header */
+typedef struct _MPI2_CONFIG_PAGE_HEADER
+{
+    U8                 PageVersion;                /* 0x00 */
+    U8                 PageLength;                 /* 0x01 */
+    U8                 PageNumber;                 /* 0x02 */
+    U8                 PageType;                   /* 0x03 */
+} MPI2_CONFIG_PAGE_HEADER, MPI2_POINTER PTR_MPI2_CONFIG_PAGE_HEADER,
+  Mpi2ConfigPageHeader_t, MPI2_POINTER pMpi2ConfigPageHeader_t;
+
+typedef union _MPI2_CONFIG_PAGE_HEADER_UNION
+{
+   MPI2_CONFIG_PAGE_HEADER  Struct;
+   U8                       Bytes[4];
+   U16                      Word16[2];
+   U32                      Word32;
+} MPI2_CONFIG_PAGE_HEADER_UNION, MPI2_POINTER PTR_MPI2_CONFIG_PAGE_HEADER_UNION,
+  Mpi2ConfigPageHeaderUnion, MPI2_POINTER pMpi2ConfigPageHeaderUnion;
+
+/* Extended Config Page Header */
+typedef struct _MPI2_CONFIG_EXTENDED_PAGE_HEADER
+{
+    U8                  PageVersion;                /* 0x00 */
+    U8                  Reserved1;                  /* 0x01 */
+    U8                  PageNumber;                 /* 0x02 */
+    U8                  PageType;                   /* 0x03 */
+    U16                 ExtPageLength;              /* 0x04 */
+    U8                  ExtPageType;                /* 0x06 */
+    U8                  Reserved2;                  /* 0x07 */
+} MPI2_CONFIG_EXTENDED_PAGE_HEADER,
+  MPI2_POINTER PTR_MPI2_CONFIG_EXTENDED_PAGE_HEADER,
+  Mpi2ConfigExtendedPageHeader_t, MPI2_POINTER pMpi2ConfigExtendedPageHeader_t;
+
+typedef union _MPI2_CONFIG_EXT_PAGE_HEADER_UNION
+{
+   MPI2_CONFIG_PAGE_HEADER          Struct;
+   MPI2_CONFIG_EXTENDED_PAGE_HEADER Ext;
+   U8                               Bytes[8];
+   U16                              Word16[4];
+   U32                              Word32[2];
+} MPI2_CONFIG_EXT_PAGE_HEADER_UNION, MPI2_POINTER PTR_MPI2_CONFIG_EXT_PAGE_HEADER_UNION,
+  Mpi2ConfigPageExtendedHeaderUnion, MPI2_POINTER pMpi2ConfigPageExtendedHeaderUnion;
+
+
+/* PageType field values */
+#define MPI2_CONFIG_PAGEATTR_READ_ONLY              (0x00)
+#define MPI2_CONFIG_PAGEATTR_CHANGEABLE             (0x10)
+#define MPI2_CONFIG_PAGEATTR_PERSISTENT             (0x20)
+#define MPI2_CONFIG_PAGEATTR_MASK                   (0xF0)
+
+#define MPI2_CONFIG_PAGETYPE_IO_UNIT                (0x00)
+#define MPI2_CONFIG_PAGETYPE_IOC                    (0x01)
+#define MPI2_CONFIG_PAGETYPE_BIOS                   (0x02)
+#define MPI2_CONFIG_PAGETYPE_RAID_VOLUME            (0x08)
+#define MPI2_CONFIG_PAGETYPE_MANUFACTURING          (0x09)
+#define MPI2_CONFIG_PAGETYPE_RAID_PHYSDISK          (0x0A)
+#define MPI2_CONFIG_PAGETYPE_EXTENDED               (0x0F)
+#define MPI2_CONFIG_PAGETYPE_MASK                   (0x0F)
+
+#define MPI2_CONFIG_TYPENUM_MASK                    (0x0FFF)
+
+
+/* ExtPageType field values */
+#define MPI2_CONFIG_EXTPAGETYPE_SAS_IO_UNIT         (0x10)
+#define MPI2_CONFIG_EXTPAGETYPE_SAS_EXPANDER        (0x11)
+#define MPI2_CONFIG_EXTPAGETYPE_SAS_DEVICE          (0x12)
+#define MPI2_CONFIG_EXTPAGETYPE_SAS_PHY             (0x13)
+#define MPI2_CONFIG_EXTPAGETYPE_LOG                 (0x14)
+#define MPI2_CONFIG_EXTPAGETYPE_ENCLOSURE           (0x15)
+#define MPI2_CONFIG_EXTPAGETYPE_RAID_CONFIG         (0x16)
+#define MPI2_CONFIG_EXTPAGETYPE_DRIVER_MAPPING      (0x17)
+#define MPI2_CONFIG_EXTPAGETYPE_SAS_PORT            (0x18)
+
+
+/*****************************************************************************
+*   PageAddress defines
+*****************************************************************************/
+
+/* RAID Volume PageAddress format */
+#define MPI2_RAID_VOLUME_PGAD_FORM_MASK             (0xF0000000)
+#define MPI2_RAID_VOLUME_PGAD_FORM_GET_NEXT_HANDLE  (0x00000000)
+#define MPI2_RAID_VOLUME_PGAD_FORM_HANDLE           (0x10000000)
+
+#define MPI2_RAID_VOLUME_PGAD_HANDLE_MASK           (0x0000FFFF)
+
+
+/* RAID Physical Disk PageAddress format */
+#define MPI2_PHYSDISK_PGAD_FORM_MASK                    (0xF0000000)
+#define MPI2_PHYSDISK_PGAD_FORM_GET_NEXT_PHYSDISKNUM    (0x00000000)
+#define MPI2_PHYSDISK_PGAD_FORM_PHYSDISKNUM             (0x10000000)
+#define MPI2_PHYSDISK_PGAD_FORM_DEVHANDLE               (0x20000000)
+
+#define MPI2_PHYSDISK_PGAD_PHYSDISKNUM_MASK             (0x000000FF)
+#define MPI2_PHYSDISK_PGAD_DEVHANDLE_MASK               (0x0000FFFF)
+
+
+/* SAS Expander PageAddress format */
+#define MPI2_SAS_EXPAND_PGAD_FORM_MASK              (0xF0000000)
+#define MPI2_SAS_EXPAND_PGAD_FORM_GET_NEXT_HNDL     (0x00000000)
+#define MPI2_SAS_EXPAND_PGAD_FORM_HNDL_PHY_NUM      (0x10000000)
+#define MPI2_SAS_EXPAND_PGAD_FORM_HNDL              (0x20000000)
+
+#define MPI2_SAS_EXPAND_PGAD_HANDLE_MASK            (0x0000FFFF)
+#define MPI2_SAS_EXPAND_PGAD_PHYNUM_MASK            (0x00FF0000)
+#define MPI2_SAS_EXPAND_PGAD_PHYNUM_SHIFT           (16)
+
+
+/* SAS Device PageAddress format */
+#define MPI2_SAS_DEVICE_PGAD_FORM_MASK              (0xF0000000)
+#define MPI2_SAS_DEVICE_PGAD_FORM_GET_NEXT_HANDLE   (0x00000000)
+#define MPI2_SAS_DEVICE_PGAD_FORM_HANDLE            (0x20000000)
+
+#define MPI2_SAS_DEVICE_PGAD_HANDLE_MASK            (0x0000FFFF)
+
+
+/* SAS PHY PageAddress format */
+#define MPI2_SAS_PHY_PGAD_FORM_MASK                 (0xF0000000)
+#define MPI2_SAS_PHY_PGAD_FORM_PHY_NUMBER           (0x00000000)
+#define MPI2_SAS_PHY_PGAD_FORM_PHY_TBL_INDEX        (0x10000000)
+
+#define MPI2_SAS_PHY_PGAD_PHY_NUMBER_MASK           (0x000000FF)
+#define MPI2_SAS_PHY_PGAD_PHY_TBL_INDEX_MASK        (0x0000FFFF)
+
+
+/* SAS Port PageAddress format */
+#define MPI2_SASPORT_PGAD_FORM_MASK                 (0xF0000000)
+#define MPI2_SASPORT_PGAD_FORM_GET_NEXT_PORT        (0x00000000)
+#define MPI2_SASPORT_PGAD_FORM_PORT_NUM             (0x10000000)
+
+#define MPI2_SASPORT_PGAD_PORTNUMBER_MASK           (0x00000FFF)
+
+
+/* SAS Enclosure PageAddress format */
+#define MPI2_SAS_ENCLOS_PGAD_FORM_MASK              (0xF0000000)
+#define MPI2_SAS_ENCLOS_PGAD_FORM_GET_NEXT_HANDLE   (0x00000000)
+#define MPI2_SAS_ENCLOS_PGAD_FORM_HANDLE            (0x10000000)
+
+#define MPI2_SAS_ENCLOS_PGAD_HANDLE_MASK            (0x0000FFFF)
+
+
+/* RAID Configuration PageAddress format */
+#define MPI2_RAID_PGAD_FORM_MASK                    (0xF0000000)
+#define MPI2_RAID_PGAD_FORM_GET_NEXT_CONFIGNUM      (0x00000000)
+#define MPI2_RAID_PGAD_FORM_CONFIGNUM               (0x10000000)
+#define MPI2_RAID_PGAD_FORM_ACTIVE_CONFIG           (0x20000000)
+
+#define MPI2_RAID_PGAD_CONFIGNUM_MASK               (0x000000FF)
+
+
+/* Driver Persistent Mapping PageAddress format */
+#define MPI2_DPM_PGAD_FORM_MASK                     (0xF0000000)
+#define MPI2_DPM_PGAD_FORM_ENTRY_RANGE              (0x00000000)
+
+#define MPI2_DPM_PGAD_ENTRY_COUNT_MASK              (0x0FFF0000)
+#define MPI2_DPM_PGAD_ENTRY_COUNT_SHIFT             (16)
+#define MPI2_DPM_PGAD_START_ENTRY_MASK              (0x0000FFFF)
+
+
+/****************************************************************************
+*   Configuration messages
+****************************************************************************/
+
+/* Configuration Request Message */
+typedef struct _MPI2_CONFIG_REQUEST
+{
+    U8                      Action;                     /* 0x00 */
+    U8                      SGLFlags;                   /* 0x01 */
+    U8                      ChainOffset;                /* 0x02 */
+    U8                      Function;                   /* 0x03 */
+    U16                     ExtPageLength;              /* 0x04 */
+    U8                      ExtPageType;                /* 0x06 */
+    U8                      MsgFlags;                   /* 0x07 */
+    U8                      VP_ID;                      /* 0x08 */
+    U8                      VF_ID;                      /* 0x09 */
+    U16                     Reserved1;                  /* 0x0A */
+    U32                     Reserved2;                  /* 0x0C */
+    U32                     Reserved3;                  /* 0x10 */
+    MPI2_CONFIG_PAGE_HEADER Header;                     /* 0x14 */
+    U32                     PageAddress;                /* 0x18 */
+    MPI2_SGE_IO_UNION       PageBufferSGE;              /* 0x1C */
+} MPI2_CONFIG_REQUEST, MPI2_POINTER PTR_MPI2_CONFIG_REQUEST,
+  Mpi2ConfigRequest_t, MPI2_POINTER pMpi2ConfigRequest_t;
+
+/* values for the Action field */
+#define MPI2_CONFIG_ACTION_PAGE_HEADER              (0x00)
+#define MPI2_CONFIG_ACTION_PAGE_READ_CURRENT        (0x01)
+#define MPI2_CONFIG_ACTION_PAGE_WRITE_CURRENT       (0x02)
+#define MPI2_CONFIG_ACTION_PAGE_DEFAULT             (0x03)
+#define MPI2_CONFIG_ACTION_PAGE_WRITE_NVRAM         (0x04)
+#define MPI2_CONFIG_ACTION_PAGE_READ_DEFAULT        (0x05)
+#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 */
+
+
+/* Config Reply Message */
+typedef struct _MPI2_CONFIG_REPLY
+{
+    U8                      Action;                     /* 0x00 */
+    U8                      SGLFlags;                   /* 0x01 */
+    U8                      MsgLength;                  /* 0x02 */
+    U8                      Function;                   /* 0x03 */
+    U16                     ExtPageLength;              /* 0x04 */
+    U8                      ExtPageType;                /* 0x06 */
+    U8                      MsgFlags;                   /* 0x07 */
+    U8                      VP_ID;                      /* 0x08 */
+    U8                      VF_ID;                      /* 0x09 */
+    U16                     Reserved1;                  /* 0x0A */
+    U16                     Reserved2;                  /* 0x0C */
+    U16                     IOCStatus;                  /* 0x0E */
+    U32                     IOCLogInfo;                 /* 0x10 */
+    MPI2_CONFIG_PAGE_HEADER Header;                     /* 0x14 */
+} MPI2_CONFIG_REPLY, MPI2_POINTER PTR_MPI2_CONFIG_REPLY,
+  Mpi2ConfigReply_t, MPI2_POINTER pMpi2ConfigReply_t;
+
+
+
+/*****************************************************************************
+*
+*               C o n f i g u r a t i o n    P a g e s
+*
+*****************************************************************************/
+
+/****************************************************************************
+*   Manufacturing Config pages
+****************************************************************************/
+
+#define MPI2_MFGPAGE_VENDORID_LSI                   (0x1000)
+
+/* SAS */
+#define MPI2_MFGPAGE_DEVID_SAS2004                  (0x0070)
+#define MPI2_MFGPAGE_DEVID_SAS2008                  (0x0072)
+#define MPI2_MFGPAGE_DEVID_SAS2108_1                (0x0074)
+#define MPI2_MFGPAGE_DEVID_SAS2108_2                (0x0076)
+#define MPI2_MFGPAGE_DEVID_SAS2108_3                (0x0077)
+#define MPI2_MFGPAGE_DEVID_SAS2116_1                (0x0064)
+#define MPI2_MFGPAGE_DEVID_SAS2116_2                (0x0065)
+
+
+/* Manufacturing Page 0 */
+
+typedef struct _MPI2_CONFIG_PAGE_MAN_0
+{
+    MPI2_CONFIG_PAGE_HEADER Header;                     /* 0x00 */
+    U8                      ChipName[16];               /* 0x04 */
+    U8                      ChipRevision[8];            /* 0x14 */
+    U8                      BoardName[16];              /* 0x1C */
+    U8                      BoardAssembly[16];          /* 0x2C */
+    U8                      BoardTracerNumber[16];      /* 0x3C */
+} MPI2_CONFIG_PAGE_MAN_0,
+  MPI2_POINTER PTR_MPI2_CONFIG_PAGE_MAN_0,
+  Mpi2ManufacturingPage0_t, MPI2_POINTER pMpi2ManufacturingPage0_t;
+
+#define MPI2_MANUFACTURING0_PAGEVERSION                (0x00)
+
+
+/* Manufacturing Page 1 */
+
+typedef struct _MPI2_CONFIG_PAGE_MAN_1
+{
+    MPI2_CONFIG_PAGE_HEADER Header;                     /* 0x00 */
+    U8                      VPD[256];                   /* 0x04 */
+} MPI2_CONFIG_PAGE_MAN_1,
+  MPI2_POINTER PTR_MPI2_CONFIG_PAGE_MAN_1,
+  Mpi2ManufacturingPage1_t, MPI2_POINTER pMpi2ManufacturingPage1_t;
+
+#define MPI2_MANUFACTURING1_PAGEVERSION                (0x00)
+
+
+typedef struct _MPI2_CHIP_REVISION_ID
+{
+    U16 DeviceID;                                       /* 0x00 */
+    U8  PCIRevisionID;                                  /* 0x02 */
+    U8  Reserved;                                       /* 0x03 */
+} MPI2_CHIP_REVISION_ID, MPI2_POINTER PTR_MPI2_CHIP_REVISION_ID,
+  Mpi2ChipRevisionId_t, MPI2_POINTER pMpi2ChipRevisionId_t;
+
+
+/* Manufacturing Page 2 */
+
+/*
+ * Host code (drivers, BIOS, utilities, etc.) should leave this define set to
+ * one and check Header.PageLength at runtime.
+ */
+#ifndef MPI2_MAN_PAGE_2_HW_SETTINGS_WORDS
+#define MPI2_MAN_PAGE_2_HW_SETTINGS_WORDS   (1)
+#endif
+
+typedef struct _MPI2_CONFIG_PAGE_MAN_2
+{
+    MPI2_CONFIG_PAGE_HEADER Header;                     /* 0x00 */
+    MPI2_CHIP_REVISION_ID   ChipId;                     /* 0x04 */
+    U32                     HwSettings[MPI2_MAN_PAGE_2_HW_SETTINGS_WORDS];/* 0x08 */
+} MPI2_CONFIG_PAGE_MAN_2,
+  MPI2_POINTER PTR_MPI2_CONFIG_PAGE_MAN_2,
+  Mpi2ManufacturingPage2_t, MPI2_POINTER pMpi2ManufacturingPage2_t;
+
+#define MPI2_MANUFACTURING2_PAGEVERSION                 (0x00)
+
+
+/* Manufacturing Page 3 */
+
+/*
+ * Host code (drivers, BIOS, utilities, etc.) should leave this define set to
+ * one and check Header.PageLength at runtime.
+ */
+#ifndef MPI2_MAN_PAGE_3_INFO_WORDS
+#define MPI2_MAN_PAGE_3_INFO_WORDS          (1)
+#endif
+
+typedef struct _MPI2_CONFIG_PAGE_MAN_3
+{
+    MPI2_CONFIG_PAGE_HEADER             Header;         /* 0x00 */
+    MPI2_CHIP_REVISION_ID               ChipId;         /* 0x04 */
+    U32                                 Info[MPI2_MAN_PAGE_3_INFO_WORDS];/* 0x08 */
+} MPI2_CONFIG_PAGE_MAN_3,
+  MPI2_POINTER PTR_MPI2_CONFIG_PAGE_MAN_3,
+  Mpi2ManufacturingPage3_t, MPI2_POINTER pMpi2ManufacturingPage3_t;
+
+#define MPI2_MANUFACTURING3_PAGEVERSION                 (0x00)
+
+
+/* Manufacturing Page 4 */
+
+typedef struct _MPI2_MANPAGE4_PWR_SAVE_SETTINGS
+{
+    U8                          PowerSaveFlags;                 /* 0x00 */
+    U8                          InternalOperationsSleepTime;    /* 0x01 */
+    U8                          InternalOperationsRunTime;      /* 0x02 */
+    U8                          HostIdleTime;                   /* 0x03 */
+} MPI2_MANPAGE4_PWR_SAVE_SETTINGS,
+  MPI2_POINTER PTR_MPI2_MANPAGE4_PWR_SAVE_SETTINGS,
+  Mpi2ManPage4PwrSaveSettings_t, MPI2_POINTER pMpi2ManPage4PwrSaveSettings_t;
+
+/* defines for the PowerSaveFlags field */
+#define MPI2_MANPAGE4_MASK_POWERSAVE_MODE               (0x03)
+#define MPI2_MANPAGE4_POWERSAVE_MODE_DISABLED           (0x00)
+#define MPI2_MANPAGE4_CUSTOM_POWERSAVE_MODE             (0x01)
+#define MPI2_MANPAGE4_FULL_POWERSAVE_MODE               (0x02)
+
+typedef struct _MPI2_CONFIG_PAGE_MAN_4
+{
+    MPI2_CONFIG_PAGE_HEADER             Header;                 /* 0x00 */
+    U32                                 Reserved1;              /* 0x04 */
+    U32                                 Flags;                  /* 0x08 */
+    U8                                  InquirySize;            /* 0x0C */
+    U8                                  Reserved2;              /* 0x0D */
+    U16                                 Reserved3;              /* 0x0E */
+    U8                                  InquiryData[56];        /* 0x10 */
+    U32                                 RAID0VolumeSettings;    /* 0x48 */
+    U32                                 RAID1EVolumeSettings;   /* 0x4C */
+    U32                                 RAID1VolumeSettings;    /* 0x50 */
+    U32                                 RAID10VolumeSettings;   /* 0x54 */
+    U32                                 Reserved4;              /* 0x58 */
+    U32                                 Reserved5;              /* 0x5C */
+    MPI2_MANPAGE4_PWR_SAVE_SETTINGS     PowerSaveSettings;      /* 0x60 */
+    U8                                  MaxOCEDisks;            /* 0x64 */
+    U8                                  ResyncRate;             /* 0x65 */
+    U16                                 DataScrubDuration;      /* 0x66 */
+    U8                                  MaxHotSpares;           /* 0x68 */
+    U8                                  MaxPhysDisksPerVol;     /* 0x69 */
+    U8                                  MaxPhysDisks;           /* 0x6A */
+    U8                                  MaxVolumes;             /* 0x6B */
+} MPI2_CONFIG_PAGE_MAN_4,
+  MPI2_POINTER PTR_MPI2_CONFIG_PAGE_MAN_4,
+  Mpi2ManufacturingPage4_t, MPI2_POINTER pMpi2ManufacturingPage4_t;
+
+#define MPI2_MANUFACTURING4_PAGEVERSION                 (0x0A)
+
+/* Manufacturing Page 4 Flags field */
+#define MPI2_MANPAGE4_METADATA_SIZE_MASK                (0x00030000)
+#define MPI2_MANPAGE4_METADATA_512MB                    (0x00000000)
+
+#define MPI2_MANPAGE4_MIX_SSD_SAS_SATA                  (0x00008000)
+#define MPI2_MANPAGE4_MIX_SSD_AND_NON_SSD               (0x00004000)
+#define MPI2_MANPAGE4_HIDE_PHYSDISK_NON_IR              (0x00002000)
+
+#define MPI2_MANPAGE4_MASK_PHYSDISK_COERCION            (0x00001C00)
+#define MPI2_MANPAGE4_PHYSDISK_COERCION_1GB             (0x00000000)
+#define MPI2_MANPAGE4_PHYSDISK_128MB_COERCION           (0x00000400)
+#define MPI2_MANPAGE4_PHYSDISK_ADAPTIVE_COERCION        (0x00000800)
+#define MPI2_MANPAGE4_PHYSDISK_ZERO_COERCION            (0x00000C00)
+
+#define MPI2_MANPAGE4_MASK_BAD_BLOCK_MARKING            (0x00000300)
+#define MPI2_MANPAGE4_DEFAULT_BAD_BLOCK_MARKING         (0x00000000)
+#define MPI2_MANPAGE4_TABLE_BAD_BLOCK_MARKING           (0x00000100)
+#define MPI2_MANPAGE4_WRITE_LONG_BAD_BLOCK_MARKING      (0x00000200)
+
+#define MPI2_MANPAGE4_FORCE_OFFLINE_FAILOVER            (0x00000080)
+#define MPI2_MANPAGE4_RAID10_DISABLE                    (0x00000040)
+#define MPI2_MANPAGE4_RAID1E_DISABLE                    (0x00000020)
+#define MPI2_MANPAGE4_RAID1_DISABLE                     (0x00000010)
+#define MPI2_MANPAGE4_RAID0_DISABLE                     (0x00000008)
+#define MPI2_MANPAGE4_IR_MODEPAGE8_DISABLE              (0x00000004)
+#define MPI2_MANPAGE4_IM_RESYNC_CACHE_ENABLE            (0x00000002)
+#define MPI2_MANPAGE4_IR_NO_MIX_SAS_SATA                (0x00000001)
+
+
+/* Manufacturing Page 5 */
+
+/*
+ * Host code (drivers, BIOS, utilities, etc.) should leave this define set to
+ * one and check Header.PageLength or NumPhys at runtime.
+ */
+#ifndef MPI2_MAN_PAGE_5_PHY_ENTRIES
+#define MPI2_MAN_PAGE_5_PHY_ENTRIES         (1)
+#endif
+
+typedef struct _MPI2_MANUFACTURING5_ENTRY
+{
+    U64                                 WWID;           /* 0x00 */
+    U64                                 DeviceName;     /* 0x08 */
+} MPI2_MANUFACTURING5_ENTRY, MPI2_POINTER PTR_MPI2_MANUFACTURING5_ENTRY,
+  Mpi2Manufacturing5Entry_t, MPI2_POINTER pMpi2Manufacturing5Entry_t;
+
+typedef struct _MPI2_CONFIG_PAGE_MAN_5
+{
+    MPI2_CONFIG_PAGE_HEADER             Header;         /* 0x00 */
+    U8                                  NumPhys;        /* 0x04 */
+    U8                                  Reserved1;      /* 0x05 */
+    U16                                 Reserved2;      /* 0x06 */
+    U32                                 Reserved3;      /* 0x08 */
+    U32                                 Reserved4;      /* 0x0C */
+    MPI2_MANUFACTURING5_ENTRY           Phy[MPI2_MAN_PAGE_5_PHY_ENTRIES];/* 0x08 */
+} MPI2_CONFIG_PAGE_MAN_5,
+  MPI2_POINTER PTR_MPI2_CONFIG_PAGE_MAN_5,
+  Mpi2ManufacturingPage5_t, MPI2_POINTER pMpi2ManufacturingPage5_t;
+
+#define MPI2_MANUFACTURING5_PAGEVERSION                 (0x03)
+
+
+/* Manufacturing Page 6 */
+
+typedef struct _MPI2_CONFIG_PAGE_MAN_6
+{
+    MPI2_CONFIG_PAGE_HEADER         Header;             /* 0x00 */
+    U32                             ProductSpecificInfo;/* 0x04 */
+} MPI2_CONFIG_PAGE_MAN_6,
+  MPI2_POINTER PTR_MPI2_CONFIG_PAGE_MAN_6,
+  Mpi2ManufacturingPage6_t, MPI2_POINTER pMpi2ManufacturingPage6_t;
+
+#define MPI2_MANUFACTURING6_PAGEVERSION                 (0x00)
+
+
+/* Manufacturing Page 7 */
+
+typedef struct _MPI2_MANPAGE7_CONNECTOR_INFO
+{
+    U32                         Pinout;                 /* 0x00 */
+    U8                          Connector[16];          /* 0x04 */
+    U8                          Location;               /* 0x14 */
+    U8                          Reserved1;              /* 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)
+
+/* defines for the Location field */
+#define MPI2_MANPAGE7_LOCATION_UNKNOWN                  (0x01)
+#define MPI2_MANPAGE7_LOCATION_INTERNAL                 (0x02)
+#define MPI2_MANPAGE7_LOCATION_EXTERNAL                 (0x04)
+#define MPI2_MANPAGE7_LOCATION_SWITCHABLE               (0x08)
+#define MPI2_MANPAGE7_LOCATION_AUTO                     (0x10)
+#define MPI2_MANPAGE7_LOCATION_NOT_PRESENT              (0x20)
+#define MPI2_MANPAGE7_LOCATION_NOT_CONNECTED            (0x80)
+
+/*
+ * Host code (drivers, BIOS, utilities, etc.) should leave this define set to
+ * one and check NumPhys at runtime.
+ */
+#ifndef MPI2_MANPAGE7_CONNECTOR_INFO_MAX
+#define MPI2_MANPAGE7_CONNECTOR_INFO_MAX  (1)
+#endif
+
+typedef struct _MPI2_CONFIG_PAGE_MAN_7
+{
+    MPI2_CONFIG_PAGE_HEADER         Header;             /* 0x00 */
+    U32                             Reserved1;          /* 0x04 */
+    U32                             Reserved2;          /* 0x08 */
+    U32                             Flags;              /* 0x0C */
+    U8                              EnclosureName[16];  /* 0x10 */
+    U8                              NumPhys;            /* 0x20 */
+    U8                              Reserved3;          /* 0x21 */
+    U16                             Reserved4;          /* 0x22 */
+    MPI2_MANPAGE7_CONNECTOR_INFO    ConnectorInfo[MPI2_MANPAGE7_CONNECTOR_INFO_MAX]; /* 0x24 */
+} MPI2_CONFIG_PAGE_MAN_7,
+  MPI2_POINTER PTR_MPI2_CONFIG_PAGE_MAN_7,
+  Mpi2ManufacturingPage7_t, MPI2_POINTER pMpi2ManufacturingPage7_t;
+
+#define MPI2_MANUFACTURING7_PAGEVERSION                 (0x00)
+
+/* defines for the Flags field */
+#define MPI2_MANPAGE7_FLAG_USE_SLOT_INFO                (0x00000001)
+
+
+/*
+ * Generic structure to use for product-specific manufacturing pages
+ * (currently Manufacturing Page 8 through Manufacturing Page 31).
+ */
+
+typedef struct _MPI2_CONFIG_PAGE_MAN_PS
+{
+    MPI2_CONFIG_PAGE_HEADER         Header;             /* 0x00 */
+    U32                             ProductSpecificInfo;/* 0x04 */
+} MPI2_CONFIG_PAGE_MAN_PS,
+  MPI2_POINTER PTR_MPI2_CONFIG_PAGE_MAN_PS,
+  Mpi2ManufacturingPagePS_t, MPI2_POINTER pMpi2ManufacturingPagePS_t;
+
+#define MPI2_MANUFACTURING8_PAGEVERSION                 (0x00)
+#define MPI2_MANUFACTURING9_PAGEVERSION                 (0x00)
+#define MPI2_MANUFACTURING10_PAGEVERSION                (0x00)
+#define MPI2_MANUFACTURING11_PAGEVERSION                (0x00)
+#define MPI2_MANUFACTURING12_PAGEVERSION                (0x00)
+#define MPI2_MANUFACTURING13_PAGEVERSION                (0x00)
+#define MPI2_MANUFACTURING14_PAGEVERSION                (0x00)
+#define MPI2_MANUFACTURING15_PAGEVERSION                (0x00)
+#define MPI2_MANUFACTURING16_PAGEVERSION                (0x00)
+#define MPI2_MANUFACTURING17_PAGEVERSION                (0x00)
+#define MPI2_MANUFACTURING18_PAGEVERSION                (0x00)
+#define MPI2_MANUFACTURING19_PAGEVERSION                (0x00)
+#define MPI2_MANUFACTURING20_PAGEVERSION                (0x00)
+#define MPI2_MANUFACTURING21_PAGEVERSION                (0x00)
+#define MPI2_MANUFACTURING22_PAGEVERSION                (0x00)
+#define MPI2_MANUFACTURING23_PAGEVERSION                (0x00)
+#define MPI2_MANUFACTURING24_PAGEVERSION                (0x00)
+#define MPI2_MANUFACTURING25_PAGEVERSION                (0x00)
+#define MPI2_MANUFACTURING26_PAGEVERSION                (0x00)
+#define MPI2_MANUFACTURING27_PAGEVERSION                (0x00)
+#define MPI2_MANUFACTURING28_PAGEVERSION                (0x00)
+#define MPI2_MANUFACTURING29_PAGEVERSION                (0x00)
+#define MPI2_MANUFACTURING30_PAGEVERSION                (0x00)
+#define MPI2_MANUFACTURING31_PAGEVERSION                (0x00)
+
+
+/****************************************************************************
+*   IO Unit Config Pages
+****************************************************************************/
+
+/* IO Unit Page 0 */
+
+typedef struct _MPI2_CONFIG_PAGE_IO_UNIT_0
+{
+    MPI2_CONFIG_PAGE_HEADER Header;                     /* 0x00 */
+    U64                     UniqueValue;                /* 0x04 */
+    MPI2_VERSION_UNION      NvdataVersionDefault;       /* 0x08 */
+    MPI2_VERSION_UNION      NvdataVersionPersistent;    /* 0x0A */
+} MPI2_CONFIG_PAGE_IO_UNIT_0, MPI2_POINTER PTR_MPI2_CONFIG_PAGE_IO_UNIT_0,
+  Mpi2IOUnitPage0_t, MPI2_POINTER pMpi2IOUnitPage0_t;
+
+#define MPI2_IOUNITPAGE0_PAGEVERSION                    (0x02)
+
+
+/* IO Unit Page 1 */
+
+typedef struct _MPI2_CONFIG_PAGE_IO_UNIT_1
+{
+    MPI2_CONFIG_PAGE_HEADER Header;                     /* 0x00 */
+    U32                     Flags;                      /* 0x04 */
+} MPI2_CONFIG_PAGE_IO_UNIT_1, MPI2_POINTER PTR_MPI2_CONFIG_PAGE_IO_UNIT_1,
+  Mpi2IOUnitPage1_t, MPI2_POINTER pMpi2IOUnitPage1_t;
+
+#define MPI2_IOUNITPAGE1_PAGEVERSION                    (0x04)
+
+/* IO Unit Page 1 Flags defines */
+#define MPI2_IOUNITPAGE1_MASK_SATA_WRITE_CACHE          (0x00000600)
+#define MPI2_IOUNITPAGE1_ENABLE_SATA_WRITE_CACHE        (0x00000000)
+#define MPI2_IOUNITPAGE1_DISABLE_SATA_WRITE_CACHE       (0x00000200)
+#define MPI2_IOUNITPAGE1_UNCHANGED_SATA_WRITE_CACHE     (0x00000400)
+#define MPI2_IOUNITPAGE1_NATIVE_COMMAND_Q_DISABLE       (0x00000100)
+#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.
+ */
+#ifndef MPI2_IO_UNIT_PAGE_3_GPIO_VAL_MAX
+#define MPI2_IO_UNIT_PAGE_3_GPIO_VAL_MAX    (1)
+#endif
+
+typedef struct _MPI2_CONFIG_PAGE_IO_UNIT_3
+{
+    MPI2_CONFIG_PAGE_HEADER Header;                                   /* 0x00 */
+    U8                      GPIOCount;                                /* 0x04 */
+    U8                      Reserved1;                                /* 0x05 */
+    U16                     Reserved2;                                /* 0x06 */
+    U16                     GPIOVal[MPI2_IO_UNIT_PAGE_3_GPIO_VAL_MAX];/* 0x08 */
+} MPI2_CONFIG_PAGE_IO_UNIT_3, MPI2_POINTER PTR_MPI2_CONFIG_PAGE_IO_UNIT_3,
+  Mpi2IOUnitPage3_t, MPI2_POINTER pMpi2IOUnitPage3_t;
+
+#define MPI2_IOUNITPAGE3_PAGEVERSION                    (0x01)
+
+/* defines for IO Unit Page 3 GPIOVal field */
+#define MPI2_IOUNITPAGE3_GPIO_FUNCTION_MASK             (0xFFFC)
+#define MPI2_IOUNITPAGE3_GPIO_FUNCTION_SHIFT            (2)
+#define MPI2_IOUNITPAGE3_GPIO_SETTING_OFF               (0x0000)
+#define MPI2_IOUNITPAGE3_GPIO_SETTING_ON                (0x0001)
+
+
+/****************************************************************************
+*   IOC Config Pages
+****************************************************************************/
+
+/* IOC Page 0 */
+
+typedef struct _MPI2_CONFIG_PAGE_IOC_0
+{
+    MPI2_CONFIG_PAGE_HEADER Header;                     /* 0x00 */
+    U32                     Reserved1;                  /* 0x04 */
+    U32                     Reserved2;                  /* 0x08 */
+    U16                     VendorID;                   /* 0x0C */
+    U16                     DeviceID;                   /* 0x0E */
+    U8                      RevisionID;                 /* 0x10 */
+    U8                      Reserved3;                  /* 0x11 */
+    U16                     Reserved4;                  /* 0x12 */
+    U32                     ClassCode;                  /* 0x14 */
+    U16                     SubsystemVendorID;          /* 0x18 */
+    U16                     SubsystemID;                /* 0x1A */
+} MPI2_CONFIG_PAGE_IOC_0, MPI2_POINTER PTR_MPI2_CONFIG_PAGE_IOC_0,
+  Mpi2IOCPage0_t, MPI2_POINTER pMpi2IOCPage0_t;
+
+#define MPI2_IOCPAGE0_PAGEVERSION                       (0x02)
+
+
+/* IOC Page 1 */
+
+typedef struct _MPI2_CONFIG_PAGE_IOC_1
+{
+    MPI2_CONFIG_PAGE_HEADER Header;                     /* 0x00 */
+    U32                     Flags;                      /* 0x04 */
+    U32                     CoalescingTimeout;          /* 0x08 */
+    U8                      CoalescingDepth;            /* 0x0C */
+    U8                      PCISlotNum;                 /* 0x0D */
+    U8                      PCIBusNum;                  /* 0x0E */
+    U8                      PCIDomainSegment;           /* 0x0F */
+    U32                     Reserved1;                  /* 0x10 */
+    U32                     Reserved2;                  /* 0x14 */
+} MPI2_CONFIG_PAGE_IOC_1, MPI2_POINTER PTR_MPI2_CONFIG_PAGE_IOC_1,
+  Mpi2IOCPage1_t, MPI2_POINTER pMpi2IOCPage1_t;
+
+#define MPI2_IOCPAGE1_PAGEVERSION                       (0x05)
+
+/* defines for IOC Page 1 Flags field */
+#define MPI2_IOCPAGE1_REPLY_COALESCING                  (0x00000001)
+
+#define MPI2_IOCPAGE1_PCISLOTNUM_UNKNOWN                (0xFF)
+#define MPI2_IOCPAGE1_PCIBUSNUM_UNKNOWN                 (0xFF)
+#define MPI2_IOCPAGE1_PCIDOMAIN_UNKNOWN                 (0xFF)
+
+/* IOC Page 6 */
+
+typedef struct _MPI2_CONFIG_PAGE_IOC_6
+{
+    MPI2_CONFIG_PAGE_HEADER Header;                         /* 0x00 */
+    U32                     CapabilitiesFlags;              /* 0x04 */
+    U8                      MaxDrivesRAID0;                 /* 0x08 */
+    U8                      MaxDrivesRAID1;                 /* 0x09 */
+    U8                      MaxDrivesRAID1E;                /* 0x0A */
+    U8                      MaxDrivesRAID10;                /* 0x0B */
+    U8                      MinDrivesRAID0;                 /* 0x0C */
+    U8                      MinDrivesRAID1;                 /* 0x0D */
+    U8                      MinDrivesRAID1E;                /* 0x0E */
+    U8                      MinDrivesRAID10;                /* 0x0F */
+    U32                     Reserved1;                      /* 0x10 */
+    U8                      MaxGlobalHotSpares;             /* 0x14 */
+    U8                      MaxPhysDisks;                   /* 0x15 */
+    U8                      MaxVolumes;                     /* 0x16 */
+    U8                      MaxConfigs;                     /* 0x17 */
+    U8                      MaxOCEDisks;                    /* 0x18 */
+    U8                      Reserved2;                      /* 0x19 */
+    U16                     Reserved3;                      /* 0x1A */
+    U32                     SupportedStripeSizeMapRAID0;    /* 0x1C */
+    U32                     SupportedStripeSizeMapRAID1E;   /* 0x20 */
+    U32                     SupportedStripeSizeMapRAID10;   /* 0x24 */
+    U32                     Reserved4;                      /* 0x28 */
+    U32                     Reserved5;                      /* 0x2C */
+    U16                     DefaultMetadataSize;            /* 0x30 */
+    U16                     Reserved6;                      /* 0x32 */
+    U16                     MaxBadBlockTableEntries;        /* 0x34 */
+    U16                     Reserved7;                      /* 0x36 */
+    U32                     IRNvsramVersion;                /* 0x38 */
+} MPI2_CONFIG_PAGE_IOC_6, MPI2_POINTER PTR_MPI2_CONFIG_PAGE_IOC_6,
+  Mpi2IOCPage6_t, MPI2_POINTER pMpi2IOCPage6_t;
+
+#define MPI2_IOCPAGE6_PAGEVERSION                       (0x04)
+
+/* defines for IOC Page 6 CapabilitiesFlags */
+#define MPI2_IOCPAGE6_CAP_FLAGS_RAID10_SUPPORT          (0x00000010)
+#define MPI2_IOCPAGE6_CAP_FLAGS_RAID1_SUPPORT           (0x00000008)
+#define MPI2_IOCPAGE6_CAP_FLAGS_RAID1E_SUPPORT          (0x00000004)
+#define MPI2_IOCPAGE6_CAP_FLAGS_RAID0_SUPPORT           (0x00000002)
+#define MPI2_IOCPAGE6_CAP_FLAGS_GLOBAL_HOT_SPARE        (0x00000001)
+
+
+/* IOC Page 7 */
+
+#define MPI2_IOCPAGE7_EVENTMASK_WORDS       (4)
+
+typedef struct _MPI2_CONFIG_PAGE_IOC_7
+{
+    MPI2_CONFIG_PAGE_HEADER Header;                     /* 0x00 */
+    U32                     Reserved1;                  /* 0x04 */
+    U32                     EventMasks[MPI2_IOCPAGE7_EVENTMASK_WORDS];/* 0x08 */
+    U16                     SASBroadcastPrimitiveMasks; /* 0x18 */
+    U16                     Reserved2;                  /* 0x1A */
+    U32                     Reserved3;                  /* 0x1C */
+} MPI2_CONFIG_PAGE_IOC_7, MPI2_POINTER PTR_MPI2_CONFIG_PAGE_IOC_7,
+  Mpi2IOCPage7_t, MPI2_POINTER pMpi2IOCPage7_t;
+
+#define MPI2_IOCPAGE7_PAGEVERSION                       (0x01)
+
+
+/* IOC Page 8 */
+
+typedef struct _MPI2_CONFIG_PAGE_IOC_8
+{
+    MPI2_CONFIG_PAGE_HEADER Header;                     /* 0x00 */
+    U8                      NumDevsPerEnclosure;        /* 0x04 */
+    U8                      Reserved1;                  /* 0x05 */
+    U16                     Reserved2;                  /* 0x06 */
+    U16                     MaxPersistentEntries;       /* 0x08 */
+    U16                     MaxNumPhysicalMappedIDs;    /* 0x0A */
+    U16                     Flags;                      /* 0x0C */
+    U16                     Reserved3;                  /* 0x0E */
+    U16                     IRVolumeMappingFlags;       /* 0x10 */
+    U16                     Reserved4;                  /* 0x12 */
+    U32                     Reserved5;                  /* 0x14 */
+} MPI2_CONFIG_PAGE_IOC_8, MPI2_POINTER PTR_MPI2_CONFIG_PAGE_IOC_8,
+  Mpi2IOCPage8_t, MPI2_POINTER pMpi2IOCPage8_t;
+
+#define MPI2_IOCPAGE8_PAGEVERSION                       (0x00)
+
+/* defines for IOC Page 8 Flags field */
+#define MPI2_IOCPAGE8_FLAGS_DA_START_SLOT_1             (0x00000020)
+#define MPI2_IOCPAGE8_FLAGS_RESERVED_TARGETID_0         (0x00000010)
+
+#define MPI2_IOCPAGE8_FLAGS_MASK_MAPPING_MODE           (0x0000000E)
+#define MPI2_IOCPAGE8_FLAGS_DEVICE_PERSISTENCE_MAPPING  (0x00000000)
+#define MPI2_IOCPAGE8_FLAGS_ENCLOSURE_SLOT_MAPPING      (0x00000002)
+
+#define MPI2_IOCPAGE8_FLAGS_DISABLE_PERSISTENT_MAPPING  (0x00000001)
+#define MPI2_IOCPAGE8_FLAGS_ENABLE_PERSISTENT_MAPPING   (0x00000000)
+
+/* defines for IOC Page 8 IRVolumeMappingFlags */
+#define MPI2_IOCPAGE8_IRFLAGS_MASK_VOLUME_MAPPING_MODE  (0x00000003)
+#define MPI2_IOCPAGE8_IRFLAGS_LOW_VOLUME_MAPPING        (0x00000000)
+#define MPI2_IOCPAGE8_IRFLAGS_HIGH_VOLUME_MAPPING       (0x00000001)
+
+
+/****************************************************************************
+*   BIOS Config Pages
+****************************************************************************/
+
+/* BIOS Page 1 */
+
+typedef struct _MPI2_CONFIG_PAGE_BIOS_1
+{
+    MPI2_CONFIG_PAGE_HEADER Header;                     /* 0x00 */
+    U32                     BiosOptions;                /* 0x04 */
+    U32                     IOCSettings;                /* 0x08 */
+    U32                     Reserved1;                  /* 0x0C */
+    U32                     DeviceSettings;             /* 0x10 */
+    U16                     NumberOfDevices;            /* 0x14 */
+    U16                     Reserved2;                  /* 0x16 */
+    U16                     IOTimeoutBlockDevicesNonRM; /* 0x18 */
+    U16                     IOTimeoutSequential;        /* 0x1A */
+    U16                     IOTimeoutOther;             /* 0x1C */
+    U16                     IOTimeoutBlockDevicesRM;    /* 0x1E */
+} MPI2_CONFIG_PAGE_BIOS_1, MPI2_POINTER PTR_MPI2_CONFIG_PAGE_BIOS_1,
+  Mpi2BiosPage1_t, MPI2_POINTER pMpi2BiosPage1_t;
+
+#define MPI2_BIOSPAGE1_PAGEVERSION                      (0x04)
+
+/* values for BIOS Page 1 BiosOptions field */
+#define MPI2_BIOSPAGE1_OPTIONS_DISABLE_BIOS             (0x00000001)
+
+/* values for BIOS Page 1 IOCSettings field */
+#define MPI2_BIOSPAGE1_IOCSET_MASK_BOOT_PREFERENCE      (0x00030000)
+#define MPI2_BIOSPAGE1_IOCSET_ENCLOSURE_SLOT_BOOT       (0x00000000)
+#define MPI2_BIOSPAGE1_IOCSET_SAS_ADDRESS_BOOT          (0x00010000)
+
+#define MPI2_BIOSPAGE1_IOCSET_MASK_RM_SETTING           (0x000000C0)
+#define MPI2_BIOSPAGE1_IOCSET_NONE_RM_SETTING           (0x00000000)
+#define MPI2_BIOSPAGE1_IOCSET_BOOT_RM_SETTING           (0x00000040)
+#define MPI2_BIOSPAGE1_IOCSET_MEDIA_RM_SETTING          (0x00000080)
+
+#define MPI2_BIOSPAGE1_IOCSET_MASK_ADAPTER_SUPPORT      (0x00000030)
+#define MPI2_BIOSPAGE1_IOCSET_NO_SUPPORT                (0x00000000)
+#define MPI2_BIOSPAGE1_IOCSET_BIOS_SUPPORT              (0x00000010)
+#define MPI2_BIOSPAGE1_IOCSET_OS_SUPPORT                (0x00000020)
+#define MPI2_BIOSPAGE1_IOCSET_ALL_SUPPORT               (0x00000030)
+
+#define MPI2_BIOSPAGE1_IOCSET_ALTERNATE_CHS             (0x00000008)
+
+/* values for BIOS Page 1 DeviceSettings field */
+#define MPI2_BIOSPAGE1_DEVSET_DISABLE_SMART_POLLING     (0x00000010)
+#define MPI2_BIOSPAGE1_DEVSET_DISABLE_SEQ_LUN           (0x00000008)
+#define MPI2_BIOSPAGE1_DEVSET_DISABLE_RM_LUN            (0x00000004)
+#define MPI2_BIOSPAGE1_DEVSET_DISABLE_NON_RM_LUN        (0x00000002)
+#define MPI2_BIOSPAGE1_DEVSET_DISABLE_OTHER_LUN         (0x00000001)
+
+
+/* BIOS Page 2 */
+
+typedef struct _MPI2_BOOT_DEVICE_ADAPTER_ORDER
+{
+    U32         Reserved1;                              /* 0x00 */
+    U32         Reserved2;                              /* 0x04 */
+    U32         Reserved3;                              /* 0x08 */
+    U32         Reserved4;                              /* 0x0C */
+    U32         Reserved5;                              /* 0x10 */
+    U32         Reserved6;                              /* 0x14 */
+} MPI2_BOOT_DEVICE_ADAPTER_ORDER,
+  MPI2_POINTER PTR_MPI2_BOOT_DEVICE_ADAPTER_ORDER,
+  Mpi2BootDeviceAdapterOrder_t, MPI2_POINTER pMpi2BootDeviceAdapterOrder_t;
+
+typedef struct _MPI2_BOOT_DEVICE_SAS_WWID
+{
+    U64         SASAddress;                             /* 0x00 */
+    U8          LUN[8];                                 /* 0x08 */
+    U32         Reserved1;                              /* 0x10 */
+    U32         Reserved2;                              /* 0x14 */
+} MPI2_BOOT_DEVICE_SAS_WWID, MPI2_POINTER PTR_MPI2_BOOT_DEVICE_SAS_WWID,
+  Mpi2BootDeviceSasWwid_t, MPI2_POINTER pMpi2BootDeviceSasWwid_t;
+
+typedef struct _MPI2_BOOT_DEVICE_ENCLOSURE_SLOT
+{
+    U64         EnclosureLogicalID;                     /* 0x00 */
+    U32         Reserved1;                              /* 0x08 */
+    U32         Reserved2;                              /* 0x0C */
+    U16         SlotNumber;                             /* 0x10 */
+    U16         Reserved3;                              /* 0x12 */
+    U32         Reserved4;                              /* 0x14 */
+} MPI2_BOOT_DEVICE_ENCLOSURE_SLOT,
+  MPI2_POINTER PTR_MPI2_BOOT_DEVICE_ENCLOSURE_SLOT,
+  Mpi2BootDeviceEnclosureSlot_t, MPI2_POINTER pMpi2BootDeviceEnclosureSlot_t;
+
+typedef struct _MPI2_BOOT_DEVICE_DEVICE_NAME
+{
+    U64         DeviceName;                             /* 0x00 */
+    U8          LUN[8];                                 /* 0x08 */
+    U32         Reserved1;                              /* 0x10 */
+    U32         Reserved2;                              /* 0x14 */
+} MPI2_BOOT_DEVICE_DEVICE_NAME, MPI2_POINTER PTR_MPI2_BOOT_DEVICE_DEVICE_NAME,
+  Mpi2BootDeviceDeviceName_t, MPI2_POINTER pMpi2BootDeviceDeviceName_t;
+
+typedef union _MPI2_MPI2_BIOSPAGE2_BOOT_DEVICE
+{
+    MPI2_BOOT_DEVICE_ADAPTER_ORDER  AdapterOrder;
+    MPI2_BOOT_DEVICE_SAS_WWID       SasWwid;
+    MPI2_BOOT_DEVICE_ENCLOSURE_SLOT EnclosureSlot;
+    MPI2_BOOT_DEVICE_DEVICE_NAME    DeviceName;
+} MPI2_BIOSPAGE2_BOOT_DEVICE, MPI2_POINTER PTR_MPI2_BIOSPAGE2_BOOT_DEVICE,
+  Mpi2BiosPage2BootDevice_t, MPI2_POINTER pMpi2BiosPage2BootDevice_t;
+
+typedef struct _MPI2_CONFIG_PAGE_BIOS_2
+{
+    MPI2_CONFIG_PAGE_HEADER     Header;                 /* 0x00 */
+    U32                         Reserved1;              /* 0x04 */
+    U32                         Reserved2;              /* 0x08 */
+    U32                         Reserved3;              /* 0x0C */
+    U32                         Reserved4;              /* 0x10 */
+    U32                         Reserved5;              /* 0x14 */
+    U32                         Reserved6;              /* 0x18 */
+    U8                          ReqBootDeviceForm;      /* 0x1C */
+    U8                          Reserved7;              /* 0x1D */
+    U16                         Reserved8;              /* 0x1E */
+    MPI2_BIOSPAGE2_BOOT_DEVICE  RequestedBootDevice;    /* 0x20 */
+    U8                          ReqAltBootDeviceForm;   /* 0x38 */
+    U8                          Reserved9;              /* 0x39 */
+    U16                         Reserved10;             /* 0x3A */
+    MPI2_BIOSPAGE2_BOOT_DEVICE  RequestedAltBootDevice; /* 0x3C */
+    U8                          CurrentBootDeviceForm;  /* 0x58 */
+    U8                          Reserved11;             /* 0x59 */
+    U16                         Reserved12;             /* 0x5A */
+    MPI2_BIOSPAGE2_BOOT_DEVICE  CurrentBootDevice;      /* 0x58 */
+} MPI2_CONFIG_PAGE_BIOS_2, MPI2_POINTER PTR_MPI2_CONFIG_PAGE_BIOS_2,
+  Mpi2BiosPage2_t, MPI2_POINTER pMpi2BiosPage2_t;
+
+#define MPI2_BIOSPAGE2_PAGEVERSION                      (0x04)
+
+/* values for BIOS Page 2 BootDeviceForm fields */
+#define MPI2_BIOSPAGE2_FORM_MASK                        (0x0F)
+#define MPI2_BIOSPAGE2_FORM_NO_DEVICE_SPECIFIED         (0x00)
+#define MPI2_BIOSPAGE2_FORM_SAS_WWID                    (0x05)
+#define MPI2_BIOSPAGE2_FORM_ENCLOSURE_SLOT              (0x06)
+#define MPI2_BIOSPAGE2_FORM_DEVICE_NAME                 (0x07)
+
+
+/* BIOS Page 3 */
+
+typedef struct _MPI2_ADAPTER_INFO
+{
+    U8      PciBusNumber;                               /* 0x00 */
+    U8      PciDeviceAndFunctionNumber;                 /* 0x01 */
+    U16     AdapterFlags;                               /* 0x02 */
+} MPI2_ADAPTER_INFO, MPI2_POINTER PTR_MPI2_ADAPTER_INFO,
+  Mpi2AdapterInfo_t, MPI2_POINTER pMpi2AdapterInfo_t;
+
+#define MPI2_ADAPTER_INFO_FLAGS_EMBEDDED                (0x0001)
+#define MPI2_ADAPTER_INFO_FLAGS_INIT_STATUS             (0x0002)
+
+typedef struct _MPI2_CONFIG_PAGE_BIOS_3
+{
+    MPI2_CONFIG_PAGE_HEADER Header;                     /* 0x00 */
+    U32                     GlobalFlags;                /* 0x04 */
+    U32                     BiosVersion;                /* 0x08 */
+    MPI2_ADAPTER_INFO       AdapterOrder[4];            /* 0x0C */
+    U32                     Reserved1;                  /* 0x1C */
+} MPI2_CONFIG_PAGE_BIOS_3, MPI2_POINTER PTR_MPI2_CONFIG_PAGE_BIOS_3,
+  Mpi2BiosPage3_t, MPI2_POINTER pMpi2BiosPage3_t;
+
+#define MPI2_BIOSPAGE3_PAGEVERSION                      (0x00)
+
+/* values for BIOS Page 3 GlobalFlags */
+#define MPI2_BIOSPAGE3_FLAGS_PAUSE_ON_ERROR             (0x00000002)
+#define MPI2_BIOSPAGE3_FLAGS_VERBOSE_ENABLE             (0x00000004)
+#define MPI2_BIOSPAGE3_FLAGS_HOOK_INT_40_DISABLE        (0x00000010)
+
+#define MPI2_BIOSPAGE3_FLAGS_DEV_LIST_DISPLAY_MASK      (0x000000E0)
+#define MPI2_BIOSPAGE3_FLAGS_INSTALLED_DEV_DISPLAY      (0x00000000)
+#define MPI2_BIOSPAGE3_FLAGS_ADAPTER_DISPLAY            (0x00000020)
+#define MPI2_BIOSPAGE3_FLAGS_ADAPTER_DEV_DISPLAY        (0x00000040)
+
+
+/* BIOS Page 4 */
+
+/*
+ * Host code (drivers, BIOS, utilities, etc.) should leave this define set to
+ * one and check Header.PageLength or NumPhys at runtime.
+ */
+#ifndef MPI2_BIOS_PAGE_4_PHY_ENTRIES
+#define MPI2_BIOS_PAGE_4_PHY_ENTRIES        (1)
+#endif
+
+typedef struct _MPI2_BIOS4_ENTRY
+{
+    U64                     ReassignmentWWID;       /* 0x00 */
+    U64                     ReassignmentDeviceName; /* 0x08 */
+} MPI2_BIOS4_ENTRY, MPI2_POINTER PTR_MPI2_BIOS4_ENTRY,
+  Mpi2MBios4Entry_t, MPI2_POINTER pMpi2Bios4Entry_t;
+
+typedef struct _MPI2_CONFIG_PAGE_BIOS_4
+{
+    MPI2_CONFIG_PAGE_HEADER Header;                             /* 0x00 */
+    U8                      NumPhys;                            /* 0x04 */
+    U8                      Reserved1;                          /* 0x05 */
+    U16                     Reserved2;                          /* 0x06 */
+    MPI2_BIOS4_ENTRY        Phy[MPI2_BIOS_PAGE_4_PHY_ENTRIES];  /* 0x08 */
+} MPI2_CONFIG_PAGE_BIOS_4, MPI2_POINTER PTR_MPI2_CONFIG_PAGE_BIOS_4,
+  Mpi2BiosPage4_t, MPI2_POINTER pMpi2BiosPage4_t;
+
+#define MPI2_BIOSPAGE4_PAGEVERSION                      (0x01)
+
+
+/****************************************************************************
+*   RAID Volume Config Pages
+****************************************************************************/
+
+/* RAID Volume Page 0 */
+
+typedef struct _MPI2_RAIDVOL0_PHYS_DISK
+{
+    U8                      RAIDSetNum;                 /* 0x00 */
+    U8                      PhysDiskMap;                /* 0x01 */
+    U8                      PhysDiskNum;                /* 0x02 */
+    U8                      Reserved;                   /* 0x03 */
+} MPI2_RAIDVOL0_PHYS_DISK, MPI2_POINTER PTR_MPI2_RAIDVOL0_PHYS_DISK,
+  Mpi2RaidVol0PhysDisk_t, MPI2_POINTER pMpi2RaidVol0PhysDisk_t;
+
+/* defines for the PhysDiskMap field */
+#define MPI2_RAIDVOL0_PHYSDISK_PRIMARY                  (0x01)
+#define MPI2_RAIDVOL0_PHYSDISK_SECONDARY                (0x02)
+
+typedef struct _MPI2_RAIDVOL0_SETTINGS
+{
+    U16                     Settings;                   /* 0x00 */
+    U8                      HotSparePool;               /* 0x01 */
+    U8                      Reserved;                   /* 0x02 */
+} MPI2_RAIDVOL0_SETTINGS, MPI2_POINTER PTR_MPI2_RAIDVOL0_SETTINGS,
+  Mpi2RaidVol0Settings_t, MPI2_POINTER pMpi2RaidVol0Settings_t;
+
+/* RAID Volume Page 0 HotSparePool defines, also used in RAID Physical Disk */
+#define MPI2_RAID_HOT_SPARE_POOL_0                      (0x01)
+#define MPI2_RAID_HOT_SPARE_POOL_1                      (0x02)
+#define MPI2_RAID_HOT_SPARE_POOL_2                      (0x04)
+#define MPI2_RAID_HOT_SPARE_POOL_3                      (0x08)
+#define MPI2_RAID_HOT_SPARE_POOL_4                      (0x10)
+#define MPI2_RAID_HOT_SPARE_POOL_5                      (0x20)
+#define MPI2_RAID_HOT_SPARE_POOL_6                      (0x40)
+#define MPI2_RAID_HOT_SPARE_POOL_7                      (0x80)
+
+/* RAID Volume Page 0 VolumeSettings defines */
+#define MPI2_RAIDVOL0_SETTING_USE_PRODUCT_ID_SUFFIX     (0x0008)
+#define MPI2_RAIDVOL0_SETTING_AUTO_CONFIG_HSWAP_DISABLE (0x0004)
+
+#define MPI2_RAIDVOL0_SETTING_MASK_WRITE_CACHING        (0x0003)
+#define MPI2_RAIDVOL0_SETTING_UNCHANGED                 (0x0000)
+#define MPI2_RAIDVOL0_SETTING_DISABLE_WRITE_CACHING     (0x0001)
+#define MPI2_RAIDVOL0_SETTING_ENABLE_WRITE_CACHING      (0x0002)
+
+/*
+ * Host code (drivers, BIOS, utilities, etc.) should leave this define set to
+ * one and check Header.PageLength at runtime.
+ */
+#ifndef MPI2_RAID_VOL_PAGE_0_PHYSDISK_MAX
+#define MPI2_RAID_VOL_PAGE_0_PHYSDISK_MAX       (1)
+#endif
+
+typedef struct _MPI2_CONFIG_PAGE_RAID_VOL_0
+{
+    MPI2_CONFIG_PAGE_HEADER Header;                     /* 0x00 */
+    U16                     DevHandle;                  /* 0x04 */
+    U8                      VolumeState;                /* 0x06 */
+    U8                      VolumeType;                 /* 0x07 */
+    U32                     VolumeStatusFlags;          /* 0x08 */
+    MPI2_RAIDVOL0_SETTINGS  VolumeSettings;             /* 0x0C */
+    U64                     MaxLBA;                     /* 0x10 */
+    U32                     StripeSize;                 /* 0x18 */
+    U16                     BlockSize;                  /* 0x1C */
+    U16                     Reserved1;                  /* 0x1E */
+    U8                      SupportedPhysDisks;         /* 0x20 */
+    U8                      ResyncRate;                 /* 0x21 */
+    U16                     DataScrubDuration;          /* 0x22 */
+    U8                      NumPhysDisks;               /* 0x24 */
+    U8                      Reserved2;                  /* 0x25 */
+    U8                      Reserved3;                  /* 0x26 */
+    U8                      InactiveStatus;             /* 0x27 */
+    MPI2_RAIDVOL0_PHYS_DISK PhysDisk[MPI2_RAID_VOL_PAGE_0_PHYSDISK_MAX]; /* 0x28 */
+} MPI2_CONFIG_PAGE_RAID_VOL_0, MPI2_POINTER PTR_MPI2_CONFIG_PAGE_RAID_VOL_0,
+  Mpi2RaidVolPage0_t, MPI2_POINTER pMpi2RaidVolPage0_t;
+
+#define MPI2_RAIDVOLPAGE0_PAGEVERSION           (0x0A)
+
+/* values for RAID VolumeState */
+#define MPI2_RAID_VOL_STATE_MISSING                         (0x00)
+#define MPI2_RAID_VOL_STATE_FAILED                          (0x01)
+#define MPI2_RAID_VOL_STATE_INITIALIZING                    (0x02)
+#define MPI2_RAID_VOL_STATE_ONLINE                          (0x03)
+#define MPI2_RAID_VOL_STATE_DEGRADED                        (0x04)
+#define MPI2_RAID_VOL_STATE_OPTIMAL                         (0x05)
+
+/* values for RAID VolumeType */
+#define MPI2_RAID_VOL_TYPE_RAID0                            (0x00)
+#define MPI2_RAID_VOL_TYPE_RAID1E                           (0x01)
+#define MPI2_RAID_VOL_TYPE_RAID1                            (0x02)
+#define MPI2_RAID_VOL_TYPE_RAID10                           (0x05)
+#define MPI2_RAID_VOL_TYPE_UNKNOWN                          (0xFF)
+
+/* values for RAID Volume Page 0 VolumeStatusFlags field */
+#define MPI2_RAIDVOL0_STATUS_FLAG_PENDING_RESYNC            (0x02000000)
+#define MPI2_RAIDVOL0_STATUS_FLAG_BACKG_INIT_PENDING        (0x01000000)
+#define MPI2_RAIDVOL0_STATUS_FLAG_MDC_PENDING               (0x00800000)
+#define MPI2_RAIDVOL0_STATUS_FLAG_USER_CONSIST_PENDING      (0x00400000)
+#define MPI2_RAIDVOL0_STATUS_FLAG_MAKE_DATA_CONSISTENT      (0x00200000)
+#define MPI2_RAIDVOL0_STATUS_FLAG_DATA_SCRUB                (0x00100000)
+#define MPI2_RAIDVOL0_STATUS_FLAG_CONSISTENCY_CHECK         (0x00080000)
+#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_OCE_ALLOWED               (0x00000040)
+#define MPI2_RAIDVOL0_STATUS_FLAG_BGI_COMPLETE              (0x00000020)
+#define MPI2_RAIDVOL0_STATUS_FLAG_1E_OFFSET_MIRROR          (0x00000000)
+#define MPI2_RAIDVOL0_STATUS_FLAG_1E_ADJACENT_MIRROR        (0x00000010)
+#define MPI2_RAIDVOL0_STATUS_FLAG_BAD_BLOCK_TABLE_FULL      (0x00000008)
+#define MPI2_RAIDVOL0_STATUS_FLAG_VOLUME_INACTIVE           (0x00000004)
+#define MPI2_RAIDVOL0_STATUS_FLAG_QUIESCED                  (0x00000002)
+#define MPI2_RAIDVOL0_STATUS_FLAG_ENABLED                   (0x00000001)
+
+/* values for RAID Volume Page 0 SupportedPhysDisks field */
+#define MPI2_RAIDVOL0_SUPPORT_SOLID_STATE_DISKS             (0x08)
+#define MPI2_RAIDVOL0_SUPPORT_HARD_DISKS                    (0x04)
+#define MPI2_RAIDVOL0_SUPPORT_SAS_PROTOCOL                  (0x02)
+#define MPI2_RAIDVOL0_SUPPORT_SATA_PROTOCOL                 (0x01)
+
+/* values for RAID Volume Page 0 InactiveStatus field */
+#define MPI2_RAIDVOLPAGE0_UNKNOWN_INACTIVE                  (0x00)
+#define MPI2_RAIDVOLPAGE0_STALE_METADATA_INACTIVE           (0x01)
+#define MPI2_RAIDVOLPAGE0_FOREIGN_VOLUME_INACTIVE           (0x02)
+#define MPI2_RAIDVOLPAGE0_INSUFFICIENT_RESOURCE_INACTIVE    (0x03)
+#define MPI2_RAIDVOLPAGE0_CLONE_VOLUME_INACTIVE             (0x04)
+#define MPI2_RAIDVOLPAGE0_INSUFFICIENT_METADATA_INACTIVE    (0x05)
+#define MPI2_RAIDVOLPAGE0_PREVIOUSLY_DELETED                (0x06)
+
+
+/* RAID Volume Page 1 */
+
+typedef struct _MPI2_CONFIG_PAGE_RAID_VOL_1
+{
+    MPI2_CONFIG_PAGE_HEADER Header;                     /* 0x00 */
+    U16                     DevHandle;                  /* 0x04 */
+    U16                     Reserved0;                  /* 0x06 */
+    U8                      GUID[24];                   /* 0x08 */
+    U8                      Name[16];                   /* 0x20 */
+    U64                     WWID;                       /* 0x30 */
+    U32                     Reserved1;                  /* 0x38 */
+    U32                     Reserved2;                  /* 0x3C */
+} MPI2_CONFIG_PAGE_RAID_VOL_1, MPI2_POINTER PTR_MPI2_CONFIG_PAGE_RAID_VOL_1,
+  Mpi2RaidVolPage1_t, MPI2_POINTER pMpi2RaidVolPage1_t;
+
+#define MPI2_RAIDVOLPAGE1_PAGEVERSION           (0x03)
+
+
+/****************************************************************************
+*   RAID Physical Disk Config Pages
+****************************************************************************/
+
+/* RAID Physical Disk Page 0 */
+
+typedef struct _MPI2_RAIDPHYSDISK0_SETTINGS
+{
+    U16                     Reserved1;                  /* 0x00 */
+    U8                      HotSparePool;               /* 0x02 */
+    U8                      Reserved2;                  /* 0x03 */
+} MPI2_RAIDPHYSDISK0_SETTINGS, MPI2_POINTER PTR_MPI2_RAIDPHYSDISK0_SETTINGS,
+  Mpi2RaidPhysDisk0Settings_t, MPI2_POINTER pMpi2RaidPhysDisk0Settings_t;
+
+/* use MPI2_RAID_HOT_SPARE_POOL_ defines for the HotSparePool field */
+
+typedef struct _MPI2_RAIDPHYSDISK0_INQUIRY_DATA
+{
+    U8                      VendorID[8];                /* 0x00 */
+    U8                      ProductID[16];              /* 0x08 */
+    U8                      ProductRevLevel[4];         /* 0x18 */
+    U8                      SerialNum[32];              /* 0x1C */
+} MPI2_RAIDPHYSDISK0_INQUIRY_DATA,
+  MPI2_POINTER PTR_MPI2_RAIDPHYSDISK0_INQUIRY_DATA,
+  Mpi2RaidPhysDisk0InquiryData_t, MPI2_POINTER pMpi2RaidPhysDisk0InquiryData_t;
+
+typedef struct _MPI2_CONFIG_PAGE_RD_PDISK_0
+{
+    MPI2_CONFIG_PAGE_HEADER         Header;                     /* 0x00 */
+    U16                             DevHandle;                  /* 0x04 */
+    U8                              Reserved1;                  /* 0x06 */
+    U8                              PhysDiskNum;                /* 0x07 */
+    MPI2_RAIDPHYSDISK0_SETTINGS     PhysDiskSettings;           /* 0x08 */
+    U32                             Reserved2;                  /* 0x0C */
+    MPI2_RAIDPHYSDISK0_INQUIRY_DATA InquiryData;                /* 0x10 */
+    U32                             Reserved3;                  /* 0x4C */
+    U8                              PhysDiskState;              /* 0x50 */
+    U8                              OfflineReason;              /* 0x51 */
+    U8                              IncompatibleReason;         /* 0x52 */
+    U8                              PhysDiskAttributes;         /* 0x53 */
+    U32                             PhysDiskStatusFlags;        /* 0x54 */
+    U64                             DeviceMaxLBA;               /* 0x58 */
+    U64                             HostMaxLBA;                 /* 0x60 */
+    U64                             CoercedMaxLBA;              /* 0x68 */
+    U16                             BlockSize;                  /* 0x70 */
+    U16                             Reserved5;                  /* 0x72 */
+    U32                             Reserved6;                  /* 0x74 */
+} MPI2_CONFIG_PAGE_RD_PDISK_0,
+  MPI2_POINTER PTR_MPI2_CONFIG_PAGE_RD_PDISK_0,
+  Mpi2RaidPhysDiskPage0_t, MPI2_POINTER pMpi2RaidPhysDiskPage0_t;
+
+#define MPI2_RAIDPHYSDISKPAGE0_PAGEVERSION          (0x05)
+
+/* PhysDiskState defines */
+#define MPI2_RAID_PD_STATE_NOT_CONFIGURED               (0x00)
+#define MPI2_RAID_PD_STATE_NOT_COMPATIBLE               (0x01)
+#define MPI2_RAID_PD_STATE_OFFLINE                      (0x02)
+#define MPI2_RAID_PD_STATE_ONLINE                       (0x03)
+#define MPI2_RAID_PD_STATE_HOT_SPARE                    (0x04)
+#define MPI2_RAID_PD_STATE_DEGRADED                     (0x05)
+#define MPI2_RAID_PD_STATE_REBUILDING                   (0x06)
+#define MPI2_RAID_PD_STATE_OPTIMAL                      (0x07)
+
+/* OfflineReason defines */
+#define MPI2_PHYSDISK0_ONLINE                           (0x00)
+#define MPI2_PHYSDISK0_OFFLINE_MISSING                  (0x01)
+#define MPI2_PHYSDISK0_OFFLINE_FAILED                   (0x03)
+#define MPI2_PHYSDISK0_OFFLINE_INITIALIZING             (0x04)
+#define MPI2_PHYSDISK0_OFFLINE_REQUESTED                (0x05)
+#define MPI2_PHYSDISK0_OFFLINE_FAILED_REQUESTED         (0x06)
+#define MPI2_PHYSDISK0_OFFLINE_OTHER                    (0xFF)
+
+/* IncompatibleReason defines */
+#define MPI2_PHYSDISK0_COMPATIBLE                       (0x00)
+#define MPI2_PHYSDISK0_INCOMPATIBLE_PROTOCOL            (0x01)
+#define MPI2_PHYSDISK0_INCOMPATIBLE_BLOCKSIZE           (0x02)
+#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_UNKNOWN             (0xFF)
+
+/* PhysDiskAttributes defines */
+#define MPI2_PHYSDISK0_ATTRIB_SOLID_STATE_DRIVE         (0x08)
+#define MPI2_PHYSDISK0_ATTRIB_HARD_DISK_DRIVE           (0x04)
+#define MPI2_PHYSDISK0_ATTRIB_SAS_PROTOCOL              (0x02)
+#define MPI2_PHYSDISK0_ATTRIB_SATA_PROTOCOL             (0x01)
+
+/* PhysDiskStatusFlags defines */
+#define MPI2_PHYSDISK0_STATUS_FLAG_NOT_CERTIFIED        (0x00000040)
+#define MPI2_PHYSDISK0_STATUS_FLAG_OCE_TARGET           (0x00000020)
+#define MPI2_PHYSDISK0_STATUS_FLAG_WRITE_CACHE_ENABLED  (0x00000010)
+#define MPI2_PHYSDISK0_STATUS_FLAG_OPTIMAL_PREVIOUS     (0x00000000)
+#define MPI2_PHYSDISK0_STATUS_FLAG_NOT_OPTIMAL_PREVIOUS (0x00000008)
+#define MPI2_PHYSDISK0_STATUS_FLAG_INACTIVE_VOLUME      (0x00000004)
+#define MPI2_PHYSDISK0_STATUS_FLAG_QUIESCED             (0x00000002)
+#define MPI2_PHYSDISK0_STATUS_FLAG_OUT_OF_SYNC          (0x00000001)
+
+
+/* RAID Physical Disk Page 1 */
+
+/*
+ * Host code (drivers, BIOS, utilities, etc.) should leave this define set to
+ * one and check Header.PageLength or NumPhysDiskPaths at runtime.
+ */
+#ifndef MPI2_RAID_PHYS_DISK1_PATH_MAX
+#define MPI2_RAID_PHYS_DISK1_PATH_MAX   (1)
+#endif
+
+typedef struct _MPI2_RAIDPHYSDISK1_PATH
+{
+    U16             DevHandle;          /* 0x00 */
+    U16             Reserved1;          /* 0x02 */
+    U64             WWID;               /* 0x04 */
+    U64             OwnerWWID;          /* 0x0C */
+    U8              OwnerIdentifier;    /* 0x14 */
+    U8              Reserved2;          /* 0x15 */
+    U16             Flags;              /* 0x16 */
+} MPI2_RAIDPHYSDISK1_PATH, MPI2_POINTER PTR_MPI2_RAIDPHYSDISK1_PATH,
+  Mpi2RaidPhysDisk1Path_t, MPI2_POINTER pMpi2RaidPhysDisk1Path_t;
+
+/* RAID Physical Disk Page 1 Physical Disk Path Flags field defines */
+#define MPI2_RAID_PHYSDISK1_FLAG_PRIMARY        (0x0004)
+#define MPI2_RAID_PHYSDISK1_FLAG_BROKEN         (0x0002)
+#define MPI2_RAID_PHYSDISK1_FLAG_INVALID        (0x0001)
+
+typedef struct _MPI2_CONFIG_PAGE_RD_PDISK_1
+{
+    MPI2_CONFIG_PAGE_HEADER         Header;                     /* 0x00 */
+    U8                              NumPhysDiskPaths;           /* 0x04 */
+    U8                              PhysDiskNum;                /* 0x05 */
+    U16                             Reserved1;                  /* 0x06 */
+    U32                             Reserved2;                  /* 0x08 */
+    MPI2_RAIDPHYSDISK1_PATH         PhysicalDiskPath[MPI2_RAID_PHYS_DISK1_PATH_MAX];/* 0x0C */
+} MPI2_CONFIG_PAGE_RD_PDISK_1,
+  MPI2_POINTER PTR_MPI2_CONFIG_PAGE_RD_PDISK_1,
+  Mpi2RaidPhysDiskPage1_t, MPI2_POINTER pMpi2RaidPhysDiskPage1_t;
+
+#define MPI2_RAIDPHYSDISKPAGE1_PAGEVERSION          (0x02)
+
+
+/****************************************************************************
+*   values for fields used by several types of SAS Config Pages
+****************************************************************************/
+
+/* values for NegotiatedLinkRates fields */
+#define MPI2_SAS_NEG_LINK_RATE_MASK_LOGICAL             (0xF0)
+#define MPI2_SAS_NEG_LINK_RATE_SHIFT_LOGICAL            (4)
+#define MPI2_SAS_NEG_LINK_RATE_MASK_PHYSICAL            (0x0F)
+/* link rates used for Negotiated Physical and Logical Link Rate */
+#define MPI2_SAS_NEG_LINK_RATE_UNKNOWN_LINK_RATE        (0x00)
+#define MPI2_SAS_NEG_LINK_RATE_PHY_DISABLED             (0x01)
+#define MPI2_SAS_NEG_LINK_RATE_NEGOTIATION_FAILED       (0x02)
+#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_1_5                      (0x08)
+#define MPI2_SAS_NEG_LINK_RATE_3_0                      (0x09)
+#define MPI2_SAS_NEG_LINK_RATE_6_0                      (0x0A)
+
+
+/* values for AttachedPhyInfo fields */
+#define MPI2_SAS_APHYINFO_INSIDE_ZPSDS_PERSISTENT       (0x00000040)
+#define MPI2_SAS_APHYINFO_REQUESTED_INSIDE_ZPSDS        (0x00000020)
+#define MPI2_SAS_APHYINFO_BREAK_REPLY_CAPABLE           (0x00000010)
+
+#define MPI2_SAS_APHYINFO_REASON_MASK                   (0x0000000F)
+#define MPI2_SAS_APHYINFO_REASON_UNKNOWN                (0x00000000)
+#define MPI2_SAS_APHYINFO_REASON_POWER_ON               (0x00000001)
+#define MPI2_SAS_APHYINFO_REASON_HARD_RESET             (0x00000002)
+#define MPI2_SAS_APHYINFO_REASON_SMP_PHY_CONTROL        (0x00000003)
+#define MPI2_SAS_APHYINFO_REASON_LOSS_OF_SYNC           (0x00000004)
+#define MPI2_SAS_APHYINFO_REASON_MULTIPLEXING_SEQ       (0x00000005)
+#define MPI2_SAS_APHYINFO_REASON_IT_NEXUS_LOSS_TIMER    (0x00000006)
+#define MPI2_SAS_APHYINFO_REASON_BREAK_TIMEOUT          (0x00000007)
+#define MPI2_SAS_APHYINFO_REASON_PHY_TEST_STOPPED       (0x00000008)
+
+
+/* values for PhyInfo fields */
+#define MPI2_SAS_PHYINFO_PHY_VACANT                     (0x80000000)
+#define MPI2_SAS_PHYINFO_CHANGED_REQ_INSIDE_ZPSDS       (0x04000000)
+#define MPI2_SAS_PHYINFO_INSIDE_ZPSDS_PERSISTENT        (0x02000000)
+#define MPI2_SAS_PHYINFO_REQ_INSIDE_ZPSDS               (0x01000000)
+#define MPI2_SAS_PHYINFO_ZONE_GROUP_PERSISTENT          (0x00400000)
+#define MPI2_SAS_PHYINFO_INSIDE_ZPSDS                   (0x00200000)
+#define MPI2_SAS_PHYINFO_ZONING_ENABLED                 (0x00100000)
+
+#define MPI2_SAS_PHYINFO_REASON_MASK                    (0x000F0000)
+#define MPI2_SAS_PHYINFO_REASON_UNKNOWN                 (0x00000000)
+#define MPI2_SAS_PHYINFO_REASON_POWER_ON                (0x00010000)
+#define MPI2_SAS_PHYINFO_REASON_HARD_RESET              (0x00020000)
+#define MPI2_SAS_PHYINFO_REASON_SMP_PHY_CONTROL         (0x00030000)
+#define MPI2_SAS_PHYINFO_REASON_LOSS_OF_SYNC            (0x00040000)
+#define MPI2_SAS_PHYINFO_REASON_MULTIPLEXING_SEQ        (0x00050000)
+#define MPI2_SAS_PHYINFO_REASON_IT_NEXUS_LOSS_TIMER     (0x00060000)
+#define MPI2_SAS_PHYINFO_REASON_BREAK_TIMEOUT           (0x00070000)
+#define MPI2_SAS_PHYINFO_REASON_PHY_TEST_STOPPED        (0x00080000)
+
+#define MPI2_SAS_PHYINFO_MULTIPLEXING_SUPPORTED         (0x00008000)
+#define MPI2_SAS_PHYINFO_SATA_PORT_ACTIVE               (0x00004000)
+#define MPI2_SAS_PHYINFO_SATA_PORT_SELECTOR_PRESENT     (0x00002000)
+#define MPI2_SAS_PHYINFO_VIRTUAL_PHY                    (0x00001000)
+
+#define MPI2_SAS_PHYINFO_MASK_PARTIAL_PATHWAY_TIME      (0x00000F00)
+#define MPI2_SAS_PHYINFO_SHIFT_PARTIAL_PATHWAY_TIME     (8)
+
+#define MPI2_SAS_PHYINFO_MASK_ROUTING_ATTRIBUTE         (0x000000F0)
+#define MPI2_SAS_PHYINFO_DIRECT_ROUTING                 (0x00000000)
+#define MPI2_SAS_PHYINFO_SUBTRACTIVE_ROUTING            (0x00000010)
+#define MPI2_SAS_PHYINFO_TABLE_ROUTING                  (0x00000020)
+
+
+/* values for SAS ProgrammedLinkRate fields */
+#define MPI2_SAS_PRATE_MAX_RATE_MASK                    (0xF0)
+#define MPI2_SAS_PRATE_MAX_RATE_NOT_PROGRAMMABLE        (0x00)
+#define MPI2_SAS_PRATE_MAX_RATE_1_5                     (0x80)
+#define MPI2_SAS_PRATE_MAX_RATE_3_0                     (0x90)
+#define MPI2_SAS_PRATE_MAX_RATE_6_0                     (0xA0)
+#define MPI2_SAS_PRATE_MIN_RATE_MASK                    (0x0F)
+#define MPI2_SAS_PRATE_MIN_RATE_NOT_PROGRAMMABLE        (0x00)
+#define MPI2_SAS_PRATE_MIN_RATE_1_5                     (0x08)
+#define MPI2_SAS_PRATE_MIN_RATE_3_0                     (0x09)
+#define MPI2_SAS_PRATE_MIN_RATE_6_0                     (0x0A)
+
+
+/* values for SAS HwLinkRate fields */
+#define MPI2_SAS_HWRATE_MAX_RATE_MASK                   (0xF0)
+#define MPI2_SAS_HWRATE_MAX_RATE_1_5                    (0x80)
+#define MPI2_SAS_HWRATE_MAX_RATE_3_0                    (0x90)
+#define MPI2_SAS_HWRATE_MAX_RATE_6_0                    (0xA0)
+#define MPI2_SAS_HWRATE_MIN_RATE_MASK                   (0x0F)
+#define MPI2_SAS_HWRATE_MIN_RATE_1_5                    (0x08)
+#define MPI2_SAS_HWRATE_MIN_RATE_3_0                    (0x09)
+#define MPI2_SAS_HWRATE_MIN_RATE_6_0                    (0x0A)
+
+
+
+/****************************************************************************
+*   SAS IO Unit Config Pages
+****************************************************************************/
+
+/* SAS IO Unit Page 0 */
+
+typedef struct _MPI2_SAS_IO_UNIT0_PHY_DATA
+{
+    U8          Port;                   /* 0x00 */
+    U8          PortFlags;              /* 0x01 */
+    U8          PhyFlags;               /* 0x02 */
+    U8          NegotiatedLinkRate;     /* 0x03 */
+    U32         ControllerPhyDeviceInfo;/* 0x04 */
+    U16         AttachedDevHandle;      /* 0x08 */
+    U16         ControllerDevHandle;    /* 0x0A */
+    U32         DiscoveryStatus;        /* 0x0C */
+    U32         Reserved;               /* 0x10 */
+} MPI2_SAS_IO_UNIT0_PHY_DATA, MPI2_POINTER PTR_MPI2_SAS_IO_UNIT0_PHY_DATA,
+  Mpi2SasIOUnit0PhyData_t, MPI2_POINTER pMpi2SasIOUnit0PhyData_t;
+
+/*
+ * Host code (drivers, BIOS, utilities, etc.) should leave this define set to
+ * one and check Header.ExtPageLength or NumPhys at runtime.
+ */
+#ifndef MPI2_SAS_IOUNIT0_PHY_MAX
+#define MPI2_SAS_IOUNIT0_PHY_MAX        (1)
+#endif
+
+typedef struct _MPI2_CONFIG_PAGE_SASIOUNIT_0
+{
+    MPI2_CONFIG_EXTENDED_PAGE_HEADER    Header;                             /* 0x00 */
+    U32                                 Reserved1;                          /* 0x08 */
+    U8                                  NumPhys;                            /* 0x0C */
+    U8                                  Reserved2;                          /* 0x0D */
+    U16                                 Reserved3;                          /* 0x0E */
+    MPI2_SAS_IO_UNIT0_PHY_DATA          PhyData[MPI2_SAS_IOUNIT0_PHY_MAX];  /* 0x10 */
+} MPI2_CONFIG_PAGE_SASIOUNIT_0,
+  MPI2_POINTER PTR_MPI2_CONFIG_PAGE_SASIOUNIT_0,
+  Mpi2SasIOUnitPage0_t, MPI2_POINTER pMpi2SasIOUnitPage0_t;
+
+#define MPI2_SASIOUNITPAGE0_PAGEVERSION                     (0x05)
+
+/* values for SAS IO Unit Page 0 PortFlags */
+#define MPI2_SASIOUNIT0_PORTFLAGS_DISCOVERY_IN_PROGRESS     (0x08)
+#define MPI2_SASIOUNIT0_PORTFLAGS_AUTO_PORT_CONFIG          (0x01)
+
+/* values for SAS IO Unit Page 0 PhyFlags */
+#define MPI2_SASIOUNIT0_PHYFLAGS_ZONING_ENABLED             (0x10)
+#define MPI2_SASIOUNIT0_PHYFLAGS_PHY_DISABLED               (0x08)
+
+/* use MPI2_SAS_NEG_LINK_RATE_ defines for the NegotiatedLinkRate field */
+
+/* see mpi2_sas.h for values for SAS IO Unit Page 0 ControllerPhyDeviceInfo values */
+
+/* values for SAS IO Unit Page 0 DiscoveryStatus */
+#define MPI2_SASIOUNIT0_DS_MAX_ENCLOSURES_EXCEED            (0x80000000)
+#define MPI2_SASIOUNIT0_DS_MAX_EXPANDERS_EXCEED             (0x40000000)
+#define MPI2_SASIOUNIT0_DS_MAX_DEVICES_EXCEED               (0x20000000)
+#define MPI2_SASIOUNIT0_DS_MAX_TOPO_PHYS_EXCEED             (0x10000000)
+#define MPI2_SASIOUNIT0_DS_DOWNSTREAM_INITIATOR             (0x08000000)
+#define MPI2_SASIOUNIT0_DS_MULTI_SUBTRACTIVE_SUBTRACTIVE    (0x00008000)
+#define MPI2_SASIOUNIT0_DS_EXP_MULTI_SUBTRACTIVE            (0x00004000)
+#define MPI2_SASIOUNIT0_DS_MULTI_PORT_DOMAIN                (0x00002000)
+#define MPI2_SASIOUNIT0_DS_TABLE_TO_SUBTRACTIVE_LINK        (0x00001000)
+#define MPI2_SASIOUNIT0_DS_UNSUPPORTED_DEVICE               (0x00000800)
+#define MPI2_SASIOUNIT0_DS_TABLE_LINK                       (0x00000400)
+#define MPI2_SASIOUNIT0_DS_SUBTRACTIVE_LINK                 (0x00000200)
+#define MPI2_SASIOUNIT0_DS_SMP_CRC_ERROR                    (0x00000100)
+#define MPI2_SASIOUNIT0_DS_SMP_FUNCTION_FAILED              (0x00000080)
+#define MPI2_SASIOUNIT0_DS_INDEX_NOT_EXIST                  (0x00000040)
+#define MPI2_SASIOUNIT0_DS_OUT_ROUTE_ENTRIES                (0x00000020)
+#define MPI2_SASIOUNIT0_DS_SMP_TIMEOUT                      (0x00000010)
+#define MPI2_SASIOUNIT0_DS_MULTIPLE_PORTS                   (0x00000004)
+#define MPI2_SASIOUNIT0_DS_UNADDRESSABLE_DEVICE             (0x00000002)
+#define MPI2_SASIOUNIT0_DS_LOOP_DETECTED                    (0x00000001)
+
+
+/* SAS IO Unit Page 1 */
+
+typedef struct _MPI2_SAS_IO_UNIT1_PHY_DATA
+{
+    U8          Port;                       /* 0x00 */
+    U8          PortFlags;                  /* 0x01 */
+    U8          PhyFlags;                   /* 0x02 */
+    U8          MaxMinLinkRate;             /* 0x03 */
+    U32         ControllerPhyDeviceInfo;    /* 0x04 */
+    U16         MaxTargetPortConnectTime;   /* 0x08 */
+    U16         Reserved1;                  /* 0x0A */
+} MPI2_SAS_IO_UNIT1_PHY_DATA, MPI2_POINTER PTR_MPI2_SAS_IO_UNIT1_PHY_DATA,
+  Mpi2SasIOUnit1PhyData_t, MPI2_POINTER pMpi2SasIOUnit1PhyData_t;
+
+/*
+ * Host code (drivers, BIOS, utilities, etc.) should leave this define set to
+ * one and check Header.ExtPageLength or NumPhys at runtime.
+ */
+#ifndef MPI2_SAS_IOUNIT1_PHY_MAX
+#define MPI2_SAS_IOUNIT1_PHY_MAX        (1)
+#endif
+
+typedef struct _MPI2_CONFIG_PAGE_SASIOUNIT_1
+{
+    MPI2_CONFIG_EXTENDED_PAGE_HEADER    Header;                             /* 0x00 */
+    U16                                 ControlFlags;                       /* 0x08 */
+    U16                                 SASNarrowMaxQueueDepth;             /* 0x0A */
+    U16                                 AdditionalControlFlags;             /* 0x0C */
+    U16                                 SASWideMaxQueueDepth;               /* 0x0E */
+    U8                                  NumPhys;                            /* 0x10 */
+    U8                                  SATAMaxQDepth;                      /* 0x11 */
+    U8                                  ReportDeviceMissingDelay;           /* 0x12 */
+    U8                                  IODeviceMissingDelay;               /* 0x13 */
+    MPI2_SAS_IO_UNIT1_PHY_DATA          PhyData[MPI2_SAS_IOUNIT1_PHY_MAX];  /* 0x14 */
+} MPI2_CONFIG_PAGE_SASIOUNIT_1,
+  MPI2_POINTER PTR_MPI2_CONFIG_PAGE_SASIOUNIT_1,
+  Mpi2SasIOUnitPage1_t, MPI2_POINTER pMpi2SasIOUnitPage1_t;
+
+#define MPI2_SASIOUNITPAGE1_PAGEVERSION     (0x09)
+
+/* values for SAS IO Unit Page 1 ControlFlags */
+#define MPI2_SASIOUNIT1_CONTROL_DEVICE_SELF_TEST                    (0x8000)
+#define MPI2_SASIOUNIT1_CONTROL_SATA_3_0_MAX                        (0x4000)
+#define MPI2_SASIOUNIT1_CONTROL_SATA_1_5_MAX                        (0x2000)
+#define MPI2_SASIOUNIT1_CONTROL_SATA_SW_PRESERVE                    (0x1000)
+
+#define MPI2_SASIOUNIT1_CONTROL_MASK_DEV_SUPPORT                    (0x0600)
+#define MPI2_SASIOUNIT1_CONTROL_SHIFT_DEV_SUPPORT                   (9)
+#define MPI2_SASIOUNIT1_CONTROL_DEV_SUPPORT_BOTH                    (0x0)
+#define MPI2_SASIOUNIT1_CONTROL_DEV_SAS_SUPPORT                     (0x1)
+#define MPI2_SASIOUNIT1_CONTROL_DEV_SATA_SUPPORT                    (0x2)
+
+#define MPI2_SASIOUNIT1_CONTROL_SATA_48BIT_LBA_REQUIRED             (0x0080)
+#define MPI2_SASIOUNIT1_CONTROL_SATA_SMART_REQUIRED                 (0x0040)
+#define MPI2_SASIOUNIT1_CONTROL_SATA_NCQ_REQUIRED                   (0x0020)
+#define MPI2_SASIOUNIT1_CONTROL_SATA_FUA_REQUIRED                   (0x0010)
+#define MPI2_SASIOUNIT1_CONTROL_TABLE_SUBTRACTIVE_ILLEGAL           (0x0008)
+#define MPI2_SASIOUNIT1_CONTROL_SUBTRACTIVE_ILLEGAL                 (0x0004)
+#define MPI2_SASIOUNIT1_CONTROL_FIRST_LVL_DISC_ONLY                 (0x0002)
+#define MPI2_SASIOUNIT1_CONTROL_CLEAR_AFFILIATION                   (0x0001)
+
+/* values for SAS IO Unit Page 1 AdditionalControlFlags */
+#define MPI2_SASIOUNIT1_ACONTROL_MULTI_PORT_DOMAIN_ILLEGAL          (0x0080)
+#define MPI2_SASIOUNIT1_ACONTROL_SATA_ASYNCHROUNOUS_NOTIFICATION    (0x0040)
+#define MPI2_SASIOUNIT1_ACONTROL_INVALID_TOPOLOGY_CORRECTION        (0x0020)
+#define MPI2_SASIOUNIT1_ACONTROL_PORT_ENABLE_ONLY_SATA_LINK_RESET   (0x0010)
+#define MPI2_SASIOUNIT1_ACONTROL_OTHER_AFFILIATION_SATA_LINK_RESET  (0x0008)
+#define MPI2_SASIOUNIT1_ACONTROL_SELF_AFFILIATION_SATA_LINK_RESET   (0x0004)
+#define MPI2_SASIOUNIT1_ACONTROL_NO_AFFILIATION_SATA_LINK_RESET     (0x0002)
+#define MPI2_SASIOUNIT1_ACONTROL_ALLOW_TABLE_TO_TABLE               (0x0001)
+
+/* defines for SAS IO Unit Page 1 ReportDeviceMissingDelay */
+#define MPI2_SASIOUNIT1_REPORT_MISSING_TIMEOUT_MASK                 (0x7F)
+#define MPI2_SASIOUNIT1_REPORT_MISSING_UNIT_16                      (0x80)
+
+/* values for SAS IO Unit Page 1 PortFlags */
+#define MPI2_SASIOUNIT1_PORT_FLAGS_AUTO_PORT_CONFIG                 (0x01)
+
+/* values for SAS IO Unit Page 2 PhyFlags */
+#define MPI2_SASIOUNIT1_PHYFLAGS_ZONING_ENABLE                      (0x10)
+#define MPI2_SASIOUNIT1_PHYFLAGS_PHY_DISABLE                        (0x08)
+
+/* values for SAS IO Unit Page 0 MaxMinLinkRate */
+#define MPI2_SASIOUNIT1_MAX_RATE_MASK                               (0xF0)
+#define MPI2_SASIOUNIT1_MAX_RATE_1_5                                (0x80)
+#define MPI2_SASIOUNIT1_MAX_RATE_3_0                                (0x90)
+#define MPI2_SASIOUNIT1_MAX_RATE_6_0                                (0xA0)
+#define MPI2_SASIOUNIT1_MIN_RATE_MASK                               (0x0F)
+#define MPI2_SASIOUNIT1_MIN_RATE_1_5                                (0x08)
+#define MPI2_SASIOUNIT1_MIN_RATE_3_0                                (0x09)
+#define MPI2_SASIOUNIT1_MIN_RATE_6_0                                (0x0A)
+
+/* see mpi2_sas.h for values for SAS IO Unit Page 1 ControllerPhyDeviceInfo values */
+
+
+/* SAS IO Unit Page 4 */
+
+typedef struct _MPI2_SAS_IOUNIT4_SPINUP_GROUP
+{
+    U8          MaxTargetSpinup;            /* 0x00 */
+    U8          SpinupDelay;                /* 0x01 */
+    U16         Reserved1;                  /* 0x02 */
+} MPI2_SAS_IOUNIT4_SPINUP_GROUP, MPI2_POINTER PTR_MPI2_SAS_IOUNIT4_SPINUP_GROUP,
+  Mpi2SasIOUnit4SpinupGroup_t, MPI2_POINTER pMpi2SasIOUnit4SpinupGroup_t;
+
+/*
+ * Host code (drivers, BIOS, utilities, etc.) should leave this define set to
+ * four and check Header.ExtPageLength or NumPhys at runtime.
+ */
+#ifndef MPI2_SAS_IOUNIT4_PHY_MAX
+#define MPI2_SAS_IOUNIT4_PHY_MAX        (4)
+#endif
+
+typedef struct _MPI2_CONFIG_PAGE_SASIOUNIT_4
+{
+    MPI2_CONFIG_EXTENDED_PAGE_HEADER    Header;                         /* 0x00 */
+    MPI2_SAS_IOUNIT4_SPINUP_GROUP       SpinupGroupParameters[4];       /* 0x08 */
+    U32                                 Reserved1;                      /* 0x18 */
+    U32                                 Reserved2;                      /* 0x1C */
+    U32                                 Reserved3;                      /* 0x20 */
+    U8                                  BootDeviceWaitTime;             /* 0x24 */
+    U8                                  Reserved4;                      /* 0x25 */
+    U16                                 Reserved5;                      /* 0x26 */
+    U8                                  NumPhys;                        /* 0x28 */
+    U8                                  PEInitialSpinupDelay;           /* 0x29 */
+    U8                                  PEReplyDelay;                   /* 0x2A */
+    U8                                  Flags;                          /* 0x2B */
+    U8                                  PHY[MPI2_SAS_IOUNIT4_PHY_MAX];  /* 0x2C */
+} MPI2_CONFIG_PAGE_SASIOUNIT_4,
+  MPI2_POINTER PTR_MPI2_CONFIG_PAGE_SASIOUNIT_4,
+  Mpi2SasIOUnitPage4_t, MPI2_POINTER pMpi2SasIOUnitPage4_t;
+
+#define MPI2_SASIOUNITPAGE4_PAGEVERSION     (0x02)
+
+/* defines for Flags field */
+#define MPI2_SASIOUNIT4_FLAGS_AUTO_PORTENABLE               (0x01)
+
+/* defines for PHY field */
+#define MPI2_SASIOUNIT4_PHY_SPINUP_GROUP_MASK               (0x03)
+
+
+/****************************************************************************
+*   SAS Expander Config Pages
+****************************************************************************/
+
+/* SAS Expander Page 0 */
+
+typedef struct _MPI2_CONFIG_PAGE_EXPANDER_0
+{
+    MPI2_CONFIG_EXTENDED_PAGE_HEADER    Header;                     /* 0x00 */
+    U8                                  PhysicalPort;               /* 0x08 */
+    U8                                  ReportGenLength;            /* 0x09 */
+    U16                                 EnclosureHandle;            /* 0x0A */
+    U64                                 SASAddress;                 /* 0x0C */
+    U32                                 DiscoveryStatus;            /* 0x14 */
+    U16                                 DevHandle;                  /* 0x18 */
+    U16                                 ParentDevHandle;            /* 0x1A */
+    U16                                 ExpanderChangeCount;        /* 0x1C */
+    U16                                 ExpanderRouteIndexes;       /* 0x1E */
+    U8                                  NumPhys;                    /* 0x20 */
+    U8                                  SASLevel;                   /* 0x21 */
+    U16                                 Flags;                      /* 0x22 */
+    U16                                 STPBusInactivityTimeLimit;  /* 0x24 */
+    U16                                 STPMaxConnectTimeLimit;     /* 0x26 */
+    U16                                 STP_SMP_NexusLossTime;      /* 0x28 */
+    U16                                 MaxNumRoutedSasAddresses;   /* 0x2A */
+    U64                                 ActiveZoneManagerSASAddress;/* 0x2C */
+    U16                                 ZoneLockInactivityLimit;    /* 0x34 */
+    U16                                 Reserved1;                  /* 0x36 */
+} MPI2_CONFIG_PAGE_EXPANDER_0, MPI2_POINTER PTR_MPI2_CONFIG_PAGE_EXPANDER_0,
+  Mpi2ExpanderPage0_t, MPI2_POINTER pMpi2ExpanderPage0_t;
+
+#define MPI2_SASEXPANDER0_PAGEVERSION       (0x05)
+
+/* values for SAS Expander Page 0 DiscoveryStatus field */
+#define MPI2_SAS_EXPANDER0_DS_MAX_ENCLOSURES_EXCEED         (0x80000000)
+#define MPI2_SAS_EXPANDER0_DS_MAX_EXPANDERS_EXCEED          (0x40000000)
+#define MPI2_SAS_EXPANDER0_DS_MAX_DEVICES_EXCEED            (0x20000000)
+#define MPI2_SAS_EXPANDER0_DS_MAX_TOPO_PHYS_EXCEED          (0x10000000)
+#define MPI2_SAS_EXPANDER0_DS_DOWNSTREAM_INITIATOR          (0x08000000)
+#define MPI2_SAS_EXPANDER0_DS_MULTI_SUBTRACTIVE_SUBTRACTIVE (0x00008000)
+#define MPI2_SAS_EXPANDER0_DS_EXP_MULTI_SUBTRACTIVE         (0x00004000)
+#define MPI2_SAS_EXPANDER0_DS_MULTI_PORT_DOMAIN             (0x00002000)
+#define MPI2_SAS_EXPANDER0_DS_TABLE_TO_SUBTRACTIVE_LINK     (0x00001000)
+#define MPI2_SAS_EXPANDER0_DS_UNSUPPORTED_DEVICE            (0x00000800)
+#define MPI2_SAS_EXPANDER0_DS_TABLE_LINK                    (0x00000400)
+#define MPI2_SAS_EXPANDER0_DS_SUBTRACTIVE_LINK              (0x00000200)
+#define MPI2_SAS_EXPANDER0_DS_SMP_CRC_ERROR                 (0x00000100)
+#define MPI2_SAS_EXPANDER0_DS_SMP_FUNCTION_FAILED           (0x00000080)
+#define MPI2_SAS_EXPANDER0_DS_INDEX_NOT_EXIST               (0x00000040)
+#define MPI2_SAS_EXPANDER0_DS_OUT_ROUTE_ENTRIES             (0x00000020)
+#define MPI2_SAS_EXPANDER0_DS_SMP_TIMEOUT                   (0x00000010)
+#define MPI2_SAS_EXPANDER0_DS_MULTIPLE_PORTS                (0x00000004)
+#define MPI2_SAS_EXPANDER0_DS_UNADDRESSABLE_DEVICE          (0x00000002)
+#define MPI2_SAS_EXPANDER0_DS_LOOP_DETECTED                 (0x00000001)
+
+/* values for SAS Expander Page 0 Flags field */
+#define MPI2_SAS_EXPANDER0_FLAGS_ZONE_LOCKED                (0x1000)
+#define MPI2_SAS_EXPANDER0_FLAGS_SUPPORTED_PHYSICAL_PRES    (0x0800)
+#define MPI2_SAS_EXPANDER0_FLAGS_ASSERTED_PHYSICAL_PRES     (0x0400)
+#define MPI2_SAS_EXPANDER0_FLAGS_ZONING_SUPPORT             (0x0200)
+#define MPI2_SAS_EXPANDER0_FLAGS_ENABLED_ZONING             (0x0100)
+#define MPI2_SAS_EXPANDER0_FLAGS_TABLE_TO_TABLE_SUPPORT     (0x0080)
+#define MPI2_SAS_EXPANDER0_FLAGS_CONNECTOR_END_DEVICE       (0x0010)
+#define MPI2_SAS_EXPANDER0_FLAGS_OTHERS_CONFIG              (0x0004)
+#define MPI2_SAS_EXPANDER0_FLAGS_CONFIG_IN_PROGRESS         (0x0002)
+#define MPI2_SAS_EXPANDER0_FLAGS_ROUTE_TABLE_CONFIG         (0x0001)
+
+
+/* SAS Expander Page 1 */
+
+typedef struct _MPI2_CONFIG_PAGE_EXPANDER_1
+{
+    MPI2_CONFIG_EXTENDED_PAGE_HEADER    Header;                     /* 0x00 */
+    U8                                  PhysicalPort;               /* 0x08 */
+    U8                                  Reserved1;                  /* 0x09 */
+    U16                                 Reserved2;                  /* 0x0A */
+    U8                                  NumPhys;                    /* 0x0C */
+    U8                                  Phy;                        /* 0x0D */
+    U16                                 NumTableEntriesProgrammed;  /* 0x0E */
+    U8                                  ProgrammedLinkRate;         /* 0x10 */
+    U8                                  HwLinkRate;                 /* 0x11 */
+    U16                                 AttachedDevHandle;          /* 0x12 */
+    U32                                 PhyInfo;                    /* 0x14 */
+    U32                                 AttachedDeviceInfo;         /* 0x18 */
+    U16                                 ExpanderDevHandle;          /* 0x1C */
+    U8                                  ChangeCount;                /* 0x1E */
+    U8                                  NegotiatedLinkRate;         /* 0x1F */
+    U8                                  PhyIdentifier;              /* 0x20 */
+    U8                                  AttachedPhyIdentifier;      /* 0x21 */
+    U8                                  Reserved3;                  /* 0x22 */
+    U8                                  DiscoveryInfo;              /* 0x23 */
+    U32                                 AttachedPhyInfo;            /* 0x24 */
+    U8                                  ZoneGroup;                  /* 0x28 */
+    U8                                  SelfConfigStatus;           /* 0x29 */
+    U16                                 Reserved4;                  /* 0x2A */
+} MPI2_CONFIG_PAGE_EXPANDER_1, MPI2_POINTER PTR_MPI2_CONFIG_PAGE_EXPANDER_1,
+  Mpi2ExpanderPage1_t, MPI2_POINTER pMpi2ExpanderPage1_t;
+
+#define MPI2_SASEXPANDER1_PAGEVERSION       (0x02)
+
+/* use MPI2_SAS_PRATE_ defines for the ProgrammedLinkRate field */
+
+/* use MPI2_SAS_HWRATE_ defines for the HwLinkRate field */
+
+/* use MPI2_SAS_PHYINFO_ for the PhyInfo field */
+
+/* see mpi2_sas.h for the MPI2_SAS_DEVICE_INFO_ defines used for the AttachedDeviceInfo field */
+
+/* use MPI2_SAS_NEG_LINK_RATE_ defines for the NegotiatedLinkRate field */
+
+/* use MPI2_SAS_APHYINFO_ defines for AttachedPhyInfo field */
+
+/* values for SAS Expander Page 1 DiscoveryInfo field */
+#define MPI2_SAS_EXPANDER1_DISCINFO_BAD_PHY_DISABLED    (0x04)
+#define MPI2_SAS_EXPANDER1_DISCINFO_LINK_STATUS_CHANGE  (0x02)
+#define MPI2_SAS_EXPANDER1_DISCINFO_NO_ROUTING_ENTRIES  (0x01)
+
+
+/****************************************************************************
+*   SAS Device Config Pages
+****************************************************************************/
+
+/* SAS Device Page 0 */
+
+typedef struct _MPI2_CONFIG_PAGE_SAS_DEV_0
+{
+    MPI2_CONFIG_EXTENDED_PAGE_HEADER    Header;                 /* 0x00 */
+    U16                                 Slot;                   /* 0x08 */
+    U16                                 EnclosureHandle;        /* 0x0A */
+    U64                                 SASAddress;             /* 0x0C */
+    U16                                 ParentDevHandle;        /* 0x14 */
+    U8                                  PhyNum;                 /* 0x16 */
+    U8                                  AccessStatus;           /* 0x17 */
+    U16                                 DevHandle;              /* 0x18 */
+    U8                                  AttachedPhyIdentifier;  /* 0x1A */
+    U8                                  ZoneGroup;              /* 0x1B */
+    U32                                 DeviceInfo;             /* 0x1C */
+    U16                                 Flags;                  /* 0x20 */
+    U8                                  PhysicalPort;           /* 0x22 */
+    U8                                  MaxPortConnections;     /* 0x23 */
+    U64                                 DeviceName;             /* 0x24 */
+    U8                                  PortGroups;             /* 0x2C */
+    U8                                  DmaGroup;               /* 0x2D */
+    U8                                  ControlGroup;           /* 0x2E */
+    U8                                  Reserved1;              /* 0x2F */
+    U32                                 Reserved2;              /* 0x30 */
+    U32                                 Reserved3;              /* 0x34 */
+} MPI2_CONFIG_PAGE_SAS_DEV_0, MPI2_POINTER PTR_MPI2_CONFIG_PAGE_SAS_DEV_0,
+  Mpi2SasDevicePage0_t, MPI2_POINTER pMpi2SasDevicePage0_t;
+
+#define MPI2_SASDEVICE0_PAGEVERSION         (0x08)
+
+/* values for SAS Device Page 0 AccessStatus field */
+#define MPI2_SAS_DEVICE0_ASTATUS_NO_ERRORS                  (0x00)
+#define MPI2_SAS_DEVICE0_ASTATUS_SATA_INIT_FAILED           (0x01)
+#define MPI2_SAS_DEVICE0_ASTATUS_SATA_CAPABILITY_FAILED     (0x02)
+#define MPI2_SAS_DEVICE0_ASTATUS_SATA_AFFILIATION_CONFLICT  (0x03)
+#define MPI2_SAS_DEVICE0_ASTATUS_SATA_NEEDS_INITIALIZATION  (0x04)
+#define MPI2_SAS_DEVICE0_ASTATUS_ROUTE_NOT_ADDRESSABLE      (0x05)
+#define MPI2_SAS_DEVICE0_ASTATUS_SMP_ERROR_NOT_ADDRESSABLE  (0x06)
+#define MPI2_SAS_DEVICE0_ASTATUS_DEVICE_BLOCKED             (0x07)
+/* specific values for SATA Init failures */
+#define MPI2_SAS_DEVICE0_ASTATUS_SIF_UNKNOWN                (0x10)
+#define MPI2_SAS_DEVICE0_ASTATUS_SIF_AFFILIATION_CONFLICT   (0x11)
+#define MPI2_SAS_DEVICE0_ASTATUS_SIF_DIAG                   (0x12)
+#define MPI2_SAS_DEVICE0_ASTATUS_SIF_IDENTIFICATION         (0x13)
+#define MPI2_SAS_DEVICE0_ASTATUS_SIF_CHECK_POWER            (0x14)
+#define MPI2_SAS_DEVICE0_ASTATUS_SIF_PIO_SN                 (0x15)
+#define MPI2_SAS_DEVICE0_ASTATUS_SIF_MDMA_SN                (0x16)
+#define MPI2_SAS_DEVICE0_ASTATUS_SIF_UDMA_SN                (0x17)
+#define MPI2_SAS_DEVICE0_ASTATUS_SIF_ZONING_VIOLATION       (0x18)
+#define MPI2_SAS_DEVICE0_ASTATUS_SIF_NOT_ADDRESSABLE        (0x19)
+#define MPI2_SAS_DEVICE0_ASTATUS_SIF_MAX                    (0x1F)
+
+/* see mpi2_sas.h for values for SAS Device Page 0 DeviceInfo values */
+
+/* values for SAS Device Page 0 Flags field */
+#define MPI2_SAS_DEVICE0_FLAGS_SATA_ASYNCHRONOUS_NOTIFY     (0x0400)
+#define MPI2_SAS_DEVICE0_FLAGS_SATA_SW_PRESERVE             (0x0200)
+#define MPI2_SAS_DEVICE0_FLAGS_UNSUPPORTED_DEVICE           (0x0100)
+#define MPI2_SAS_DEVICE0_FLAGS_SATA_48BIT_LBA_SUPPORTED     (0x0080)
+#define MPI2_SAS_DEVICE0_FLAGS_SATA_SMART_SUPPORTED         (0x0040)
+#define MPI2_SAS_DEVICE0_FLAGS_SATA_NCQ_SUPPORTED           (0x0020)
+#define MPI2_SAS_DEVICE0_FLAGS_SATA_FUA_SUPPORTED           (0x0010)
+#define MPI2_SAS_DEVICE0_FLAGS_PORT_SELECTOR_ATTACH         (0x0008)
+#define MPI2_SAS_DEVICE0_FLAGS_DEVICE_PRESENT               (0x0001)
+
+
+/* SAS Device Page 1 */
+
+typedef struct _MPI2_CONFIG_PAGE_SAS_DEV_1
+{
+    MPI2_CONFIG_EXTENDED_PAGE_HEADER    Header;                 /* 0x00 */
+    U32                                 Reserved1;              /* 0x08 */
+    U64                                 SASAddress;             /* 0x0C */
+    U32                                 Reserved2;              /* 0x14 */
+    U16                                 DevHandle;              /* 0x18 */
+    U16                                 Reserved3;              /* 0x1A */
+    U8                                  InitialRegDeviceFIS[20];/* 0x1C */
+} MPI2_CONFIG_PAGE_SAS_DEV_1, MPI2_POINTER PTR_MPI2_CONFIG_PAGE_SAS_DEV_1,
+  Mpi2SasDevicePage1_t, MPI2_POINTER pMpi2SasDevicePage1_t;
+
+#define MPI2_SASDEVICE1_PAGEVERSION         (0x01)
+
+
+/****************************************************************************
+*   SAS PHY Config Pages
+****************************************************************************/
+
+/* SAS PHY Page 0 */
+
+typedef struct _MPI2_CONFIG_PAGE_SAS_PHY_0
+{
+    MPI2_CONFIG_EXTENDED_PAGE_HEADER    Header;                 /* 0x00 */
+    U16                                 OwnerDevHandle;         /* 0x08 */
+    U16                                 Reserved1;              /* 0x0A */
+    U16                                 AttachedDevHandle;      /* 0x0C */
+    U8                                  AttachedPhyIdentifier;  /* 0x0E */
+    U8                                  Reserved2;              /* 0x0F */
+    U32                                 AttachedPhyInfo;        /* 0x10 */
+    U8                                  ProgrammedLinkRate;     /* 0x14 */
+    U8                                  HwLinkRate;             /* 0x15 */
+    U8                                  ChangeCount;            /* 0x16 */
+    U8                                  Flags;                  /* 0x17 */
+    U32                                 PhyInfo;                /* 0x18 */
+    U8                                  NegotiatedLinkRate;     /* 0x1C */
+    U8                                  Reserved3;              /* 0x1D */
+    U16                                 Reserved4;              /* 0x1E */
+} MPI2_CONFIG_PAGE_SAS_PHY_0, MPI2_POINTER PTR_MPI2_CONFIG_PAGE_SAS_PHY_0,
+  Mpi2SasPhyPage0_t, MPI2_POINTER pMpi2SasPhyPage0_t;
+
+#define MPI2_SASPHY0_PAGEVERSION            (0x03)
+
+/* use MPI2_SAS_PRATE_ defines for the ProgrammedLinkRate field */
+
+/* use MPI2_SAS_HWRATE_ defines for the HwLinkRate field */
+
+/* values for SAS PHY Page 0 Flags field */
+#define MPI2_SAS_PHY0_FLAGS_SGPIO_DIRECT_ATTACH_ENC             (0x01)
+
+/* use MPI2_SAS_APHYINFO_ defines for AttachedPhyInfo field */
+
+/* use MPI2_SAS_NEG_LINK_RATE_ defines for the NegotiatedLinkRate field */
+
+/* use MPI2_SAS_PHYINFO_ for the PhyInfo field */
+
+
+/* SAS PHY Page 1 */
+
+typedef struct _MPI2_CONFIG_PAGE_SAS_PHY_1
+{
+    MPI2_CONFIG_EXTENDED_PAGE_HEADER    Header;                     /* 0x00 */
+    U32                                 Reserved1;                  /* 0x08 */
+    U32                                 InvalidDwordCount;          /* 0x0C */
+    U32                                 RunningDisparityErrorCount; /* 0x10 */
+    U32                                 LossDwordSynchCount;        /* 0x14 */
+    U32                                 PhyResetProblemCount;       /* 0x18 */
+} MPI2_CONFIG_PAGE_SAS_PHY_1, MPI2_POINTER PTR_MPI2_CONFIG_PAGE_SAS_PHY_1,
+  Mpi2SasPhyPage1_t, MPI2_POINTER pMpi2SasPhyPage1_t;
+
+#define MPI2_SASPHY1_PAGEVERSION            (0x01)
+
+
+/****************************************************************************
+*   SAS Port Config Pages
+****************************************************************************/
+
+/* SAS Port Page 0 */
+
+typedef struct _MPI2_CONFIG_PAGE_SAS_PORT_0
+{
+    MPI2_CONFIG_EXTENDED_PAGE_HEADER    Header;                     /* 0x00 */
+    U8                                  PortNumber;                 /* 0x08 */
+    U8                                  PhysicalPort;               /* 0x09 */
+    U8                                  PortWidth;                  /* 0x0A */
+    U8                                  PhysicalPortWidth;          /* 0x0B */
+    U8                                  ZoneGroup;                  /* 0x0C */
+    U8                                  Reserved1;                  /* 0x0D */
+    U16                                 Reserved2;                  /* 0x0E */
+    U64                                 SASAddress;                 /* 0x10 */
+    U32                                 DeviceInfo;                 /* 0x18 */
+    U32                                 Reserved3;                  /* 0x1C */
+    U32                                 Reserved4;                  /* 0x20 */
+} MPI2_CONFIG_PAGE_SAS_PORT_0, MPI2_POINTER PTR_MPI2_CONFIG_PAGE_SAS_PORT_0,
+  Mpi2SasPortPage0_t, MPI2_POINTER pMpi2SasPortPage0_t;
+
+#define MPI2_SASPORT0_PAGEVERSION           (0x00)
+
+/* see mpi2_sas.h for values for SAS Port Page 0 DeviceInfo values */
+
+
+/****************************************************************************
+*   SAS Enclosure Config Pages
+****************************************************************************/
+
+/* SAS Enclosure Page 0 */
+
+typedef struct _MPI2_CONFIG_PAGE_SAS_ENCLOSURE_0
+{
+    MPI2_CONFIG_EXTENDED_PAGE_HEADER    Header;                     /* 0x00 */
+    U32                                 Reserved1;                  /* 0x08 */
+    U64                                 EnclosureLogicalID;         /* 0x0C */
+    U16                                 Flags;                      /* 0x14 */
+    U16                                 EnclosureHandle;            /* 0x16 */
+    U16                                 NumSlots;                   /* 0x18 */
+    U16                                 StartSlot;                  /* 0x1A */
+    U16                                 Reserved2;                  /* 0x1C */
+    U16                                 SEPDevHandle;               /* 0x1E */
+    U32                                 Reserved3;                  /* 0x20 */
+    U32                                 Reserved4;                  /* 0x24 */
+} MPI2_CONFIG_PAGE_SAS_ENCLOSURE_0,
+  MPI2_POINTER PTR_MPI2_CONFIG_PAGE_SAS_ENCLOSURE_0,
+  Mpi2SasEnclosurePage0_t, MPI2_POINTER pMpi2SasEnclosurePage0_t;
+
+#define MPI2_SASENCLOSURE0_PAGEVERSION      (0x03)
+
+/* values for SAS Enclosure Page 0 Flags field */
+#define MPI2_SAS_ENCLS0_FLAGS_MNG_MASK              (0x000F)
+#define MPI2_SAS_ENCLS0_FLAGS_MNG_UNKNOWN           (0x0000)
+#define MPI2_SAS_ENCLS0_FLAGS_MNG_IOC_SES           (0x0001)
+#define MPI2_SAS_ENCLS0_FLAGS_MNG_IOC_SGPIO         (0x0002)
+#define MPI2_SAS_ENCLS0_FLAGS_MNG_EXP_SGPIO         (0x0003)
+#define MPI2_SAS_ENCLS0_FLAGS_MNG_SES_ENCLOSURE     (0x0004)
+#define MPI2_SAS_ENCLS0_FLAGS_MNG_IOC_GPIO          (0x0005)
+
+
+/****************************************************************************
+*   Log Config Page
+****************************************************************************/
+
+/* Log Page 0 */
+
+/*
+ * Host code (drivers, BIOS, utilities, etc.) should leave this define set to
+ * one and check Header.ExtPageLength or NumPhys at runtime.
+ */
+#ifndef MPI2_LOG_0_NUM_LOG_ENTRIES
+#define MPI2_LOG_0_NUM_LOG_ENTRIES          (1)
+#endif
+
+#define MPI2_LOG_0_LOG_DATA_LENGTH          (0x1C)
+
+typedef struct _MPI2_LOG_0_ENTRY
+{
+    U64         TimeStamp;                          /* 0x00 */
+    U32         Reserved1;                          /* 0x08 */
+    U16         LogSequence;                        /* 0x0C */
+    U16         LogEntryQualifier;                  /* 0x0E */
+    U8          VP_ID;                              /* 0x10 */
+    U8          VF_ID;                              /* 0x11 */
+    U16         Reserved2;                          /* 0x12 */
+    U8          LogData[MPI2_LOG_0_LOG_DATA_LENGTH];/* 0x14 */
+} MPI2_LOG_0_ENTRY, MPI2_POINTER PTR_MPI2_LOG_0_ENTRY,
+  Mpi2Log0Entry_t, MPI2_POINTER pMpi2Log0Entry_t;
+
+/* values for Log Page 0 LogEntry LogEntryQualifier field */
+#define MPI2_LOG_0_ENTRY_QUAL_ENTRY_UNUSED          (0x0000)
+#define MPI2_LOG_0_ENTRY_QUAL_POWER_ON_RESET        (0x0001)
+#define MPI2_LOG_0_ENTRY_QUAL_TIMESTAMP_UPDATE      (0x0002)
+#define MPI2_LOG_0_ENTRY_QUAL_MIN_IMPLEMENT_SPEC    (0x8000)
+#define MPI2_LOG_0_ENTRY_QUAL_MAX_IMPLEMENT_SPEC    (0xFFFF)
+
+typedef struct _MPI2_CONFIG_PAGE_LOG_0
+{
+    MPI2_CONFIG_EXTENDED_PAGE_HEADER    Header;                     /* 0x00 */
+    U32                                 Reserved1;                  /* 0x08 */
+    U32                                 Reserved2;                  /* 0x0C */
+    U16                                 NumLogEntries;              /* 0x10 */
+    U16                                 Reserved3;                  /* 0x12 */
+    MPI2_LOG_0_ENTRY                    LogEntry[MPI2_LOG_0_NUM_LOG_ENTRIES]; /* 0x14 */
+} MPI2_CONFIG_PAGE_LOG_0, MPI2_POINTER PTR_MPI2_CONFIG_PAGE_LOG_0,
+  Mpi2LogPage0_t, MPI2_POINTER pMpi2LogPage0_t;
+
+#define MPI2_LOG_0_PAGEVERSION              (0x02)
+
+
+/****************************************************************************
+*   RAID Config Page
+****************************************************************************/
+
+/* RAID Page 0 */
+
+/*
+ * Host code (drivers, BIOS, utilities, etc.) should leave this define set to
+ * one and check Header.ExtPageLength or NumPhys at runtime.
+ */
+#ifndef MPI2_RAIDCONFIG0_MAX_ELEMENTS
+#define MPI2_RAIDCONFIG0_MAX_ELEMENTS       (1)
+#endif
+
+typedef struct _MPI2_RAIDCONFIG0_CONFIG_ELEMENT
+{
+    U16                     ElementFlags;               /* 0x00 */
+    U16                     VolDevHandle;               /* 0x02 */
+    U8                      HotSparePool;               /* 0x04 */
+    U8                      PhysDiskNum;                /* 0x05 */
+    U16                     PhysDiskDevHandle;          /* 0x06 */
+} MPI2_RAIDCONFIG0_CONFIG_ELEMENT,
+  MPI2_POINTER PTR_MPI2_RAIDCONFIG0_CONFIG_ELEMENT,
+  Mpi2RaidConfig0ConfigElement_t, MPI2_POINTER pMpi2RaidConfig0ConfigElement_t;
+
+/* values for the ElementFlags field */
+#define MPI2_RAIDCONFIG0_EFLAGS_MASK_ELEMENT_TYPE       (0x000F)
+#define MPI2_RAIDCONFIG0_EFLAGS_VOLUME_ELEMENT          (0x0000)
+#define MPI2_RAIDCONFIG0_EFLAGS_VOL_PHYS_DISK_ELEMENT   (0x0001)
+#define MPI2_RAIDCONFIG0_EFLAGS_HOT_SPARE_ELEMENT       (0x0002)
+#define MPI2_RAIDCONFIG0_EFLAGS_OCE_ELEMENT             (0x0003)
+
+
+typedef struct _MPI2_CONFIG_PAGE_RAID_CONFIGURATION_0
+{
+    MPI2_CONFIG_EXTENDED_PAGE_HEADER    Header;                     /* 0x00 */
+    U8                                  NumHotSpares;               /* 0x08 */
+    U8                                  NumPhysDisks;               /* 0x09 */
+    U8                                  NumVolumes;                 /* 0x0A */
+    U8                                  ConfigNum;                  /* 0x0B */
+    U32                                 Flags;                      /* 0x0C */
+    U8                                  ConfigGUID[24];             /* 0x10 */
+    U32                                 Reserved1;                  /* 0x28 */
+    U8                                  NumElements;                /* 0x2C */
+    U8                                  Reserved2;                  /* 0x2D */
+    U16                                 Reserved3;                  /* 0x2E */
+    MPI2_RAIDCONFIG0_CONFIG_ELEMENT     ConfigElement[MPI2_RAIDCONFIG0_MAX_ELEMENTS]; /* 0x30 */
+} MPI2_CONFIG_PAGE_RAID_CONFIGURATION_0,
+  MPI2_POINTER PTR_MPI2_CONFIG_PAGE_RAID_CONFIGURATION_0,
+  Mpi2RaidConfigurationPage0_t, MPI2_POINTER pMpi2RaidConfigurationPage0_t;
+
+#define MPI2_RAIDCONFIG0_PAGEVERSION            (0x00)
+
+/* values for RAID Configuration Page 0 Flags field */
+#define MPI2_RAIDCONFIG0_FLAG_FOREIGN_CONFIG        (0x00000001)
+
+
+/****************************************************************************
+*   Driver Persistent Mapping Config Pages
+****************************************************************************/
+
+/* Driver Persistent Mapping Page 0 */
+
+typedef struct _MPI2_CONFIG_PAGE_DRIVER_MAP0_ENTRY
+{
+    U64                                 PhysicalIdentifier;         /* 0x00 */
+    U16                                 MappingInformation;         /* 0x08 */
+    U16                                 DeviceIndex;                /* 0x0A */
+    U32                                 PhysicalBitsMapping;        /* 0x0C */
+    U32                                 Reserved1;                  /* 0x10 */
+} MPI2_CONFIG_PAGE_DRIVER_MAP0_ENTRY,
+  MPI2_POINTER PTR_MPI2_CONFIG_PAGE_DRIVER_MAP0_ENTRY,
+  Mpi2DriverMap0Entry_t, MPI2_POINTER pMpi2DriverMap0Entry_t;
+
+typedef struct _MPI2_CONFIG_PAGE_DRIVER_MAPPING_0
+{
+    MPI2_CONFIG_EXTENDED_PAGE_HEADER    Header;                     /* 0x00 */
+    MPI2_CONFIG_PAGE_DRIVER_MAP0_ENTRY  Entry;                      /* 0x08 */
+} MPI2_CONFIG_PAGE_DRIVER_MAPPING_0,
+  MPI2_POINTER PTR_MPI2_CONFIG_PAGE_DRIVER_MAPPING_0,
+  Mpi2DriverMappingPage0_t, MPI2_POINTER pMpi2DriverMappingPage0_t;
+
+#define MPI2_DRIVERMAPPING0_PAGEVERSION         (0x00)
+
+/* values for Driver Persistent Mapping Page 0 MappingInformation field */
+#define MPI2_DRVMAP0_MAPINFO_SLOT_MASK              (0x07F0)
+#define MPI2_DRVMAP0_MAPINFO_SLOT_SHIFT             (4)
+#define MPI2_DRVMAP0_MAPINFO_MISSING_MASK           (0x000F)
+
+
+#endif
+
diff --git a/drivers/scsi/mpt2sas/mpi/mpi2_init.h b/drivers/scsi/mpt2sas/mpi/mpi2_init.h
new file mode 100644 (file)
index 0000000..f1115f0
--- /dev/null
@@ -0,0 +1,420 @@
+/*
+ *  Copyright (c) 2000-2008 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.06
+ *
+ *  Version History
+ *  ---------------
+ *
+ *  Date      Version   Description
+ *  --------  --------  ------------------------------------------------------
+ *  04-30-07  02.00.00  Corresponds to Fusion-MPT MPI Specification Rev A.
+ *  10-31-07  02.00.01  Fixed name for pMpi2SCSITaskManagementRequest_t.
+ *  12-18-07  02.00.02  Modified Task Management Target Reset Method defines.
+ *  02-29-08  02.00.03  Added Query Task Set and Query Unit Attention.
+ *  03-03-08  02.00.04  Fixed name of struct _MPI2_SCSI_TASK_MANAGE_REPLY.
+ *  05-21-08  02.00.05  Fixed typo in name of Mpi2SepRequest_t.
+ *  10-02-08  02.00.06  Removed Untagged and No Disconnect values from SCSI IO
+ *                      Control field Task Attribute flags.
+ *                      Moved LUN field defines to mpi2.h becasue they are
+ *                      common to many structures.
+ *  --------------------------------------------------------------------------
+ */
+
+#ifndef MPI2_INIT_H
+#define MPI2_INIT_H
+
+/*****************************************************************************
+*
+*               SCSI Initiator Messages
+*
+*****************************************************************************/
+
+/****************************************************************************
+*  SCSI IO messages and associated structures
+****************************************************************************/
+
+typedef struct
+{
+    U8                      CDB[20];                    /* 0x00 */
+    U32                     PrimaryReferenceTag;        /* 0x14 */
+    U16                     PrimaryApplicationTag;      /* 0x18 */
+    U16                     PrimaryApplicationTagMask;  /* 0x1A */
+    U32                     TransferLength;             /* 0x1C */
+} 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];
+    MPI2_SCSI_IO_CDB_EEDP32 EEDP32;
+    MPI2_SGE_SIMPLE_UNION   SGE;
+} MPI2_SCSI_IO_CDB_UNION, MPI2_POINTER PTR_MPI2_SCSI_IO_CDB_UNION,
+  Mpi2ScsiIoCdb_t, MPI2_POINTER pMpi2ScsiIoCdb_t;
+
+/* SCSI IO Request Message */
+typedef struct _MPI2_SCSI_IO_REQUEST
+{
+    U16                     DevHandle;                      /* 0x00 */
+    U8                      ChainOffset;                    /* 0x02 */
+    U8                      Function;                       /* 0x03 */
+    U16                     Reserved1;                      /* 0x04 */
+    U8                      Reserved2;                      /* 0x06 */
+    U8                      MsgFlags;                       /* 0x07 */
+    U8                      VP_ID;                          /* 0x08 */
+    U8                      VF_ID;                          /* 0x09 */
+    U16                     Reserved3;                      /* 0x0A */
+    U32                     SenseBufferLowAddress;          /* 0x0C */
+    U16                     SGLFlags;                       /* 0x10 */
+    U8                      SenseBufferLength;              /* 0x12 */
+    U8                      Reserved4;                      /* 0x13 */
+    U8                      SGLOffset0;                     /* 0x14 */
+    U8                      SGLOffset1;                     /* 0x15 */
+    U8                      SGLOffset2;                     /* 0x16 */
+    U8                      SGLOffset3;                     /* 0x17 */
+    U32                     SkipCount;                      /* 0x18 */
+    U32                     DataLength;                     /* 0x1C */
+    U32                     BidirectionalDataLength;        /* 0x20 */
+    U16                     IoFlags;                        /* 0x24 */
+    U16                     EEDPFlags;                      /* 0x26 */
+    U32                     EEDPBlockSize;                  /* 0x28 */
+    U32                     SecondaryReferenceTag;          /* 0x2C */
+    U16                     SecondaryApplicationTag;        /* 0x30 */
+    U16                     ApplicationTagTranslationMask;  /* 0x32 */
+    U8                      LUN[8];                         /* 0x34 */
+    U32                     Control;                        /* 0x3C */
+    MPI2_SCSI_IO_CDB_UNION  CDB;                            /* 0x40 */
+    MPI2_SGE_IO_UNION       SGL;                            /* 0x60 */
+} MPI2_SCSI_IO_REQUEST, MPI2_POINTER PTR_MPI2_SCSI_IO_REQUEST,
+  Mpi2SCSIIORequest_t, MPI2_POINTER pMpi2SCSIIORequest_t;
+
+/* SCSI IO MsgFlags bits */
+
+/* MsgFlags for SenseBufferAddressSpace */
+#define MPI2_SCSIIO_MSGFLAGS_MASK_SENSE_ADDR        (0x0C)
+#define MPI2_SCSIIO_MSGFLAGS_SYSTEM_SENSE_ADDR      (0x00)
+#define MPI2_SCSIIO_MSGFLAGS_IOCDDR_SENSE_ADDR      (0x04)
+#define MPI2_SCSIIO_MSGFLAGS_IOCPLB_SENSE_ADDR      (0x08)
+#define MPI2_SCSIIO_MSGFLAGS_IOCPLBNTA_SENSE_ADDR   (0x0C)
+
+/* SCSI IO SGLFlags bits */
+
+/* base values for Data Location Address Space */
+#define MPI2_SCSIIO_SGLFLAGS_ADDR_MASK              (0x0C)
+#define MPI2_SCSIIO_SGLFLAGS_SYSTEM_ADDR            (0x00)
+#define MPI2_SCSIIO_SGLFLAGS_IOCDDR_ADDR            (0x04)
+#define MPI2_SCSIIO_SGLFLAGS_IOCPLB_ADDR            (0x08)
+#define MPI2_SCSIIO_SGLFLAGS_IOCPLBNTA_ADDR         (0x0C)
+
+/* base values for Type */
+#define MPI2_SCSIIO_SGLFLAGS_TYPE_MASK              (0x03)
+#define MPI2_SCSIIO_SGLFLAGS_TYPE_MPI               (0x00)
+#define MPI2_SCSIIO_SGLFLAGS_TYPE_IEEE32            (0x01)
+#define MPI2_SCSIIO_SGLFLAGS_TYPE_IEEE64            (0x02)
+
+/* shift values for each sub-field */
+#define MPI2_SCSIIO_SGLFLAGS_SGL3_SHIFT             (12)
+#define MPI2_SCSIIO_SGLFLAGS_SGL2_SHIFT             (8)
+#define MPI2_SCSIIO_SGLFLAGS_SGL1_SHIFT             (4)
+#define MPI2_SCSIIO_SGLFLAGS_SGL0_SHIFT             (0)
+
+/* SCSI IO IoFlags bits */
+
+/* Large CDB Address Space */
+#define MPI2_SCSIIO_CDB_ADDR_MASK                   (0x6000)
+#define MPI2_SCSIIO_CDB_ADDR_SYSTEM                 (0x0000)
+#define MPI2_SCSIIO_CDB_ADDR_IOCDDR                 (0x2000)
+#define MPI2_SCSIIO_CDB_ADDR_IOCPLB                 (0x4000)
+#define MPI2_SCSIIO_CDB_ADDR_IOCPLBNTA              (0x6000)
+
+#define MPI2_SCSIIO_IOFLAGS_LARGE_CDB               (0x1000)
+#define MPI2_SCSIIO_IOFLAGS_BIDIRECTIONAL           (0x0800)
+#define MPI2_SCSIIO_IOFLAGS_MULTICAST               (0x0400)
+#define MPI2_SCSIIO_IOFLAGS_CMD_DETERMINES_DATA_DIR (0x0200)
+#define MPI2_SCSIIO_IOFLAGS_CDBLENGTH_MASK          (0x01FF)
+
+/* SCSI IO EEDPFlags bits */
+
+#define MPI2_SCSIIO_EEDPFLAGS_INC_PRI_REFTAG        (0x8000)
+#define MPI2_SCSIIO_EEDPFLAGS_INC_SEC_REFTAG        (0x4000)
+#define MPI2_SCSIIO_EEDPFLAGS_INC_PRI_APPTAG        (0x2000)
+#define MPI2_SCSIIO_EEDPFLAGS_INC_SEC_APPTAG        (0x1000)
+
+#define MPI2_SCSIIO_EEDPFLAGS_CHECK_REFTAG          (0x0400)
+#define MPI2_SCSIIO_EEDPFLAGS_CHECK_APPTAG          (0x0200)
+#define MPI2_SCSIIO_EEDPFLAGS_CHECK_GUARD           (0x0100)
+
+#define MPI2_SCSIIO_EEDPFLAGS_PASSTHRU_REFTAG       (0x0008)
+
+#define MPI2_SCSIIO_EEDPFLAGS_MASK_OP               (0x0007)
+#define MPI2_SCSIIO_EEDPFLAGS_NOOP_OP               (0x0000)
+#define MPI2_SCSIIO_EEDPFLAGS_CHECK_OP              (0x0001)
+#define MPI2_SCSIIO_EEDPFLAGS_STRIP_OP              (0x0002)
+#define MPI2_SCSIIO_EEDPFLAGS_CHECK_REMOVE_OP       (0x0003)
+#define MPI2_SCSIIO_EEDPFLAGS_INSERT_OP             (0x0004)
+#define MPI2_SCSIIO_EEDPFLAGS_REPLACE_OP            (0x0006)
+#define MPI2_SCSIIO_EEDPFLAGS_CHECK_REGEN_OP        (0x0007)
+
+/* SCSI IO LUN fields: use MPI2_LUN_ from mpi2.h */
+
+/* SCSI IO Control bits */
+#define MPI2_SCSIIO_CONTROL_ADDCDBLEN_MASK      (0xFC000000)
+#define MPI2_SCSIIO_CONTROL_ADDCDBLEN_SHIFT     (26)
+
+#define MPI2_SCSIIO_CONTROL_DATADIRECTION_MASK  (0x03000000)
+#define MPI2_SCSIIO_CONTROL_NODATATRANSFER      (0x00000000)
+#define MPI2_SCSIIO_CONTROL_WRITE               (0x01000000)
+#define MPI2_SCSIIO_CONTROL_READ                (0x02000000)
+#define MPI2_SCSIIO_CONTROL_BIDIRECTIONAL       (0x03000000)
+
+#define MPI2_SCSIIO_CONTROL_TASKPRI_MASK        (0x00007800)
+#define MPI2_SCSIIO_CONTROL_TASKPRI_SHIFT       (11)
+
+#define MPI2_SCSIIO_CONTROL_TASKATTRIBUTE_MASK  (0x00000700)
+#define MPI2_SCSIIO_CONTROL_SIMPLEQ             (0x00000000)
+#define MPI2_SCSIIO_CONTROL_HEADOFQ             (0x00000100)
+#define MPI2_SCSIIO_CONTROL_ORDEREDQ            (0x00000200)
+#define MPI2_SCSIIO_CONTROL_ACAQ                (0x00000400)
+
+#define MPI2_SCSIIO_CONTROL_TLR_MASK            (0x000000C0)
+#define MPI2_SCSIIO_CONTROL_NO_TLR              (0x00000000)
+#define MPI2_SCSIIO_CONTROL_TLR_ON              (0x00000040)
+#define MPI2_SCSIIO_CONTROL_TLR_OFF             (0x00000080)
+
+
+/* SCSI IO Error Reply Message */
+typedef struct _MPI2_SCSI_IO_REPLY
+{
+    U16                     DevHandle;                      /* 0x00 */
+    U8                      MsgLength;                      /* 0x02 */
+    U8                      Function;                       /* 0x03 */
+    U16                     Reserved1;                      /* 0x04 */
+    U8                      Reserved2;                      /* 0x06 */
+    U8                      MsgFlags;                       /* 0x07 */
+    U8                      VP_ID;                          /* 0x08 */
+    U8                      VF_ID;                          /* 0x09 */
+    U16                     Reserved3;                      /* 0x0A */
+    U8                      SCSIStatus;                     /* 0x0C */
+    U8                      SCSIState;                      /* 0x0D */
+    U16                     IOCStatus;                      /* 0x0E */
+    U32                     IOCLogInfo;                     /* 0x10 */
+    U32                     TransferCount;                  /* 0x14 */
+    U32                     SenseCount;                     /* 0x18 */
+    U32                     ResponseInfo;                   /* 0x1C */
+    U16                     TaskTag;                        /* 0x20 */
+    U16                     Reserved4;                      /* 0x22 */
+    U32                     BidirectionalTransferCount;     /* 0x24 */
+    U32                     Reserved5;                      /* 0x28 */
+    U32                     Reserved6;                      /* 0x2C */
+} MPI2_SCSI_IO_REPLY, MPI2_POINTER PTR_MPI2_SCSI_IO_REPLY,
+  Mpi2SCSIIOReply_t, MPI2_POINTER pMpi2SCSIIOReply_t;
+
+/* SCSI IO Reply SCSIStatus values (SAM-4 status codes) */
+
+#define MPI2_SCSI_STATUS_GOOD                   (0x00)
+#define MPI2_SCSI_STATUS_CHECK_CONDITION        (0x02)
+#define MPI2_SCSI_STATUS_CONDITION_MET          (0x04)
+#define MPI2_SCSI_STATUS_BUSY                   (0x08)
+#define MPI2_SCSI_STATUS_INTERMEDIATE           (0x10)
+#define MPI2_SCSI_STATUS_INTERMEDIATE_CONDMET   (0x14)
+#define MPI2_SCSI_STATUS_RESERVATION_CONFLICT   (0x18)
+#define MPI2_SCSI_STATUS_COMMAND_TERMINATED     (0x22) /* obsolete */
+#define MPI2_SCSI_STATUS_TASK_SET_FULL          (0x28)
+#define MPI2_SCSI_STATUS_ACA_ACTIVE             (0x30)
+#define MPI2_SCSI_STATUS_TASK_ABORTED           (0x40)
+
+/* SCSI IO Reply SCSIState flags */
+
+#define MPI2_SCSI_STATE_RESPONSE_INFO_VALID     (0x10)
+#define MPI2_SCSI_STATE_TERMINATED              (0x08)
+#define MPI2_SCSI_STATE_NO_SCSI_STATUS          (0x04)
+#define MPI2_SCSI_STATE_AUTOSENSE_FAILED        (0x02)
+#define MPI2_SCSI_STATE_AUTOSENSE_VALID         (0x01)
+
+#define MPI2_SCSI_TASKTAG_UNKNOWN               (0xFFFF)
+
+
+/****************************************************************************
+*  SCSI Task Management messages
+****************************************************************************/
+
+/* SCSI Task Management Request Message */
+typedef struct _MPI2_SCSI_TASK_MANAGE_REQUEST
+{
+    U16                     DevHandle;                      /* 0x00 */
+    U8                      ChainOffset;                    /* 0x02 */
+    U8                      Function;                       /* 0x03 */
+    U8                      Reserved1;                      /* 0x04 */
+    U8                      TaskType;                       /* 0x05 */
+    U8                      Reserved2;                      /* 0x06 */
+    U8                      MsgFlags;                       /* 0x07 */
+    U8                      VP_ID;                          /* 0x08 */
+    U8                      VF_ID;                          /* 0x09 */
+    U16                     Reserved3;                      /* 0x0A */
+    U8                      LUN[8];                         /* 0x0C */
+    U32                     Reserved4[7];                   /* 0x14 */
+    U16                     TaskMID;                        /* 0x30 */
+    U16                     Reserved5;                      /* 0x32 */
+} MPI2_SCSI_TASK_MANAGE_REQUEST,
+  MPI2_POINTER PTR_MPI2_SCSI_TASK_MANAGE_REQUEST,
+  Mpi2SCSITaskManagementRequest_t,
+  MPI2_POINTER pMpi2SCSITaskManagementRequest_t;
+
+/* TaskType values */
+
+#define MPI2_SCSITASKMGMT_TASKTYPE_ABORT_TASK           (0x01)
+#define MPI2_SCSITASKMGMT_TASKTYPE_ABRT_TASK_SET        (0x02)
+#define MPI2_SCSITASKMGMT_TASKTYPE_TARGET_RESET         (0x03)
+#define MPI2_SCSITASKMGMT_TASKTYPE_LOGICAL_UNIT_RESET   (0x05)
+#define MPI2_SCSITASKMGMT_TASKTYPE_CLEAR_TASK_SET       (0x06)
+#define MPI2_SCSITASKMGMT_TASKTYPE_QUERY_TASK           (0x07)
+#define MPI2_SCSITASKMGMT_TASKTYPE_CLR_ACA              (0x08)
+#define MPI2_SCSITASKMGMT_TASKTYPE_QRY_TASK_SET         (0x09)
+#define MPI2_SCSITASKMGMT_TASKTYPE_QRY_UNIT_ATTENTION   (0x0A)
+
+/* MsgFlags bits */
+
+#define MPI2_SCSITASKMGMT_MSGFLAGS_MASK_TARGET_RESET    (0x18)
+#define MPI2_SCSITASKMGMT_MSGFLAGS_LINK_RESET           (0x00)
+#define MPI2_SCSITASKMGMT_MSGFLAGS_NEXUS_RESET_SRST     (0x08)
+#define MPI2_SCSITASKMGMT_MSGFLAGS_SAS_HARD_LINK_RESET  (0x10)
+
+#define MPI2_SCSITASKMGMT_MSGFLAGS_DO_NOT_SEND_TASK_IU  (0x01)
+
+
+
+/* SCSI Task Management Reply Message */
+typedef struct _MPI2_SCSI_TASK_MANAGE_REPLY
+{
+    U16                     DevHandle;                      /* 0x00 */
+    U8                      MsgLength;                      /* 0x02 */
+    U8                      Function;                       /* 0x03 */
+    U8                      ResponseCode;                   /* 0x04 */
+    U8                      TaskType;                       /* 0x05 */
+    U8                      Reserved1;                      /* 0x06 */
+    U8                      MsgFlags;                       /* 0x07 */
+    U8                      VP_ID;                          /* 0x08 */
+    U8                      VF_ID;                          /* 0x09 */
+    U16                     Reserved2;                      /* 0x0A */
+    U16                     Reserved3;                      /* 0x0C */
+    U16                     IOCStatus;                      /* 0x0E */
+    U32                     IOCLogInfo;                     /* 0x10 */
+    U32                     TerminationCount;               /* 0x14 */
+} MPI2_SCSI_TASK_MANAGE_REPLY,
+  MPI2_POINTER PTR_MPI2_SCSI_TASK_MANAGE_REPLY,
+  Mpi2SCSITaskManagementReply_t, MPI2_POINTER pMpi2SCSIManagementReply_t;
+
+/* ResponseCode values */
+
+#define MPI2_SCSITASKMGMT_RSP_TM_COMPLETE               (0x00)
+#define MPI2_SCSITASKMGMT_RSP_INVALID_FRAME             (0x02)
+#define MPI2_SCSITASKMGMT_RSP_TM_NOT_SUPPORTED          (0x04)
+#define MPI2_SCSITASKMGMT_RSP_TM_FAILED                 (0x05)
+#define MPI2_SCSITASKMGMT_RSP_TM_SUCCEEDED              (0x08)
+#define MPI2_SCSITASKMGMT_RSP_TM_INVALID_LUN            (0x09)
+#define MPI2_SCSITASKMGMT_RSP_IO_QUEUED_ON_IOC          (0x80)
+
+
+/****************************************************************************
+*  SCSI Enclosure Processor messages
+****************************************************************************/
+
+/* SCSI Enclosure Processor Request Message */
+typedef struct _MPI2_SEP_REQUEST
+{
+    U16                     DevHandle;          /* 0x00 */
+    U8                      ChainOffset;        /* 0x02 */
+    U8                      Function;           /* 0x03 */
+    U8                      Action;             /* 0x04 */
+    U8                      Flags;              /* 0x05 */
+    U8                      Reserved1;          /* 0x06 */
+    U8                      MsgFlags;           /* 0x07 */
+    U8                      VP_ID;              /* 0x08 */
+    U8                      VF_ID;              /* 0x09 */
+    U16                     Reserved2;          /* 0x0A */
+    U32                     SlotStatus;         /* 0x0C */
+    U32                     Reserved3;          /* 0x10 */
+    U32                     Reserved4;          /* 0x14 */
+    U32                     Reserved5;          /* 0x18 */
+    U16                     Slot;               /* 0x1C */
+    U16                     EnclosureHandle;    /* 0x1E */
+} MPI2_SEP_REQUEST, MPI2_POINTER PTR_MPI2_SEP_REQUEST,
+  Mpi2SepRequest_t, MPI2_POINTER pMpi2SepRequest_t;
+
+/* Action defines */
+#define MPI2_SEP_REQ_ACTION_WRITE_STATUS                (0x00)
+#define MPI2_SEP_REQ_ACTION_READ_STATUS                 (0x01)
+
+/* Flags defines */
+#define MPI2_SEP_REQ_FLAGS_DEVHANDLE_ADDRESS            (0x00)
+#define MPI2_SEP_REQ_FLAGS_ENCLOSURE_SLOT_ADDRESS       (0x01)
+
+/* SlotStatus defines */
+#define MPI2_SEP_REQ_SLOTSTATUS_REQUEST_REMOVE          (0x00040000)
+#define MPI2_SEP_REQ_SLOTSTATUS_IDENTIFY_REQUEST        (0x00020000)
+#define MPI2_SEP_REQ_SLOTSTATUS_REBUILD_STOPPED         (0x00000200)
+#define MPI2_SEP_REQ_SLOTSTATUS_HOT_SPARE               (0x00000100)
+#define MPI2_SEP_REQ_SLOTSTATUS_UNCONFIGURED            (0x00000080)
+#define MPI2_SEP_REQ_SLOTSTATUS_PREDICTED_FAULT         (0x00000040)
+#define MPI2_SEP_REQ_SLOTSTATUS_DEV_REBUILDING          (0x00000004)
+#define MPI2_SEP_REQ_SLOTSTATUS_DEV_FAULTY              (0x00000002)
+#define MPI2_SEP_REQ_SLOTSTATUS_NO_ERROR                (0x00000001)
+
+
+/* SCSI Enclosure Processor Reply Message */
+typedef struct _MPI2_SEP_REPLY
+{
+    U16                     DevHandle;          /* 0x00 */
+    U8                      MsgLength;          /* 0x02 */
+    U8                      Function;           /* 0x03 */
+    U8                      Action;             /* 0x04 */
+    U8                      Flags;              /* 0x05 */
+    U8                      Reserved1;          /* 0x06 */
+    U8                      MsgFlags;           /* 0x07 */
+    U8                      VP_ID;              /* 0x08 */
+    U8                      VF_ID;              /* 0x09 */
+    U16                     Reserved2;          /* 0x0A */
+    U16                     Reserved3;          /* 0x0C */
+    U16                     IOCStatus;          /* 0x0E */
+    U32                     IOCLogInfo;         /* 0x10 */
+    U32                     SlotStatus;         /* 0x14 */
+    U32                     Reserved4;          /* 0x18 */
+    U16                     Slot;               /* 0x1C */
+    U16                     EnclosureHandle;    /* 0x1E */
+} MPI2_SEP_REPLY, MPI2_POINTER PTR_MPI2_SEP_REPLY,
+  Mpi2SepReply_t, MPI2_POINTER pMpi2SepReply_t;
+
+/* SlotStatus defines */
+#define MPI2_SEP_REPLY_SLOTSTATUS_REMOVE_READY          (0x00040000)
+#define MPI2_SEP_REPLY_SLOTSTATUS_IDENTIFY_REQUEST      (0x00020000)
+#define MPI2_SEP_REPLY_SLOTSTATUS_REBUILD_STOPPED       (0x00000200)
+#define MPI2_SEP_REPLY_SLOTSTATUS_HOT_SPARE             (0x00000100)
+#define MPI2_SEP_REPLY_SLOTSTATUS_UNCONFIGURED          (0x00000080)
+#define MPI2_SEP_REPLY_SLOTSTATUS_PREDICTED_FAULT       (0x00000040)
+#define MPI2_SEP_REPLY_SLOTSTATUS_DEV_REBUILDING        (0x00000004)
+#define MPI2_SEP_REPLY_SLOTSTATUS_DEV_FAULTY            (0x00000002)
+#define MPI2_SEP_REPLY_SLOTSTATUS_NO_ERROR              (0x00000001)
+
+
+#endif
+
+
diff --git a/drivers/scsi/mpt2sas/mpi/mpi2_ioc.h b/drivers/scsi/mpt2sas/mpi/mpi2_ioc.h
new file mode 100644 (file)
index 0000000..8c5d818
--- /dev/null
@@ -0,0 +1,1295 @@
+/*
+ *  Copyright (c) 2000-2009 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.10
+ *
+ *  Version History
+ *  ---------------
+ *
+ *  Date      Version   Description
+ *  --------  --------  ------------------------------------------------------
+ *  04-30-07  02.00.00  Corresponds to Fusion-MPT MPI Specification Rev A.
+ *  06-04-07  02.00.01  In IOCFacts Reply structure, renamed MaxDevices to
+ *                      MaxTargets.
+ *                      Added TotalImageSize field to FWDownload Request.
+ *                      Added reserved words to FWUpload Request.
+ *  06-26-07  02.00.02  Added IR Configuration Change List Event.
+ *  08-31-07  02.00.03  Removed SystemReplyQueueDepth field from the IOCInit
+ *                      request and replaced it with
+ *                      ReplyDescriptorPostQueueDepth and ReplyFreeQueueDepth.
+ *                      Replaced the MinReplyQueueDepth field of the IOCFacts
+ *                      reply with MaxReplyDescriptorPostQueueDepth.
+ *                      Added MPI2_RDPQ_DEPTH_MIN define to specify the minimum
+ *                      depth for the Reply Descriptor Post Queue.
+ *                      Added SASAddress field to Initiator Device Table
+ *                      Overflow Event data.
+ *  10-31-07  02.00.04  Added ReasonCode MPI2_EVENT_SAS_INIT_RC_NOT_RESPONDING
+ *                      for SAS Initiator Device Status Change Event data.
+ *                      Modified Reason Code defines for SAS Topology Change
+ *                      List Event data, including adding a bit for PHY Vacant
+ *                      status, and adding a mask for the Reason Code.
+ *                      Added define for
+ *                      MPI2_EVENT_SAS_TOPO_ES_DELAY_NOT_RESPONDING.
+ *                      Added define for MPI2_EXT_IMAGE_TYPE_MEGARAID.
+ *  12-18-07  02.00.05  Added Boot Status defines for the IOCExceptions field of
+ *                      the IOCFacts Reply.
+ *                      Removed MPI2_IOCFACTS_CAPABILITY_EXTENDED_BUFFER define.
+ *                      Moved MPI2_VERSION_UNION to mpi2.h.
+ *                      Changed MPI2_EVENT_NOTIFICATION_REQUEST to use masks
+ *                      instead of enables, and added SASBroadcastPrimitiveMasks
+ *                      field.
+ *                      Added Log Entry Added Event and related structure.
+ *  02-29-08  02.00.06  Added define MPI2_IOCFACTS_CAPABILITY_INTEGRATED_RAID.
+ *                      Removed define MPI2_IOCFACTS_PROTOCOL_SMP_TARGET.
+ *                      Added MaxVolumes and MaxPersistentEntries fields to
+ *                      IOCFacts reply.
+ *                      Added ProtocalFlags and IOCCapabilities fields to
+ *                      MPI2_FW_IMAGE_HEADER.
+ *                      Removed MPI2_PORTENABLE_FLAGS_ENABLE_SINGLE_PORT.
+ *  03-03-08  02.00.07  Fixed MPI2_FW_IMAGE_HEADER by changing Reserved26 to
+ *                      a U16 (from a U32).
+ *                      Removed extra 's' from EventMasks name.
+ *  06-27-08  02.00.08  Fixed an offset in a comment.
+ *  10-02-08  02.00.09  Removed SystemReplyFrameSize from MPI2_IOC_INIT_REQUEST.
+ *                      Removed CurReplyFrameSize from MPI2_IOC_FACTS_REPLY and
+ *                      renamed MinReplyFrameSize to ReplyFrameSize.
+ *                      Added MPI2_IOCFACTS_EXCEPT_IR_FOREIGN_CONFIG_MAX.
+ *                      Added two new RAIDOperation values for Integrated RAID
+ *                      Operations Status Event data.
+ *                      Added four new IR Configuration Change List Event data
+ *                      ReasonCode values.
+ *                      Added two new ReasonCode defines for SAS Device Status
+ *                      Change Event data.
+ *                      Added three new DiscoveryStatus bits for the SAS
+ *                      Discovery event data.
+ *                      Added Multiplexing Status Change bit to the PhyStatus
+ *                      field of the SAS Topology Change List event data.
+ *                      Removed define for MPI2_INIT_IMAGE_BOOTFLAGS_XMEMCOPY.
+ *                      BootFlags are now product-specific.
+ *                      Added defines for the indivdual signature bytes
+ *                      for MPI2_INIT_IMAGE_FOOTER.
+ *  01-19-09  02.00.10  Added MPI2_IOCFACTS_CAPABILITY_EVENT_REPLAY define.
+ *                      Added MPI2_EVENT_SAS_DISC_DS_DOWNSTREAM_INITIATOR
+ *                      define.
+ *                      Added MPI2_EVENT_SAS_DEV_STAT_RC_SATA_INIT_FAILURE
+ *                      define.
+ *                      Removed MPI2_EVENT_SAS_DISC_DS_SATA_INIT_FAILURE define.
+ *  --------------------------------------------------------------------------
+ */
+
+#ifndef MPI2_IOC_H
+#define MPI2_IOC_H
+
+/*****************************************************************************
+*
+*               IOC Messages
+*
+*****************************************************************************/
+
+/****************************************************************************
+*  IOCInit message
+****************************************************************************/
+
+/* IOCInit Request message */
+typedef struct _MPI2_IOC_INIT_REQUEST
+{
+    U8                      WhoInit;                        /* 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 */
+    U16                     MsgVersion;                     /* 0x0C */
+    U16                     HeaderVersion;                  /* 0x0E */
+    U32                     Reserved5;                      /* 0x10 */
+    U32                     Reserved6;                      /* 0x14 */
+    U16                     Reserved7;                      /* 0x18 */
+    U16                     SystemRequestFrameSize;         /* 0x1A */
+    U16                     ReplyDescriptorPostQueueDepth;  /* 0x1C */
+    U16                     ReplyFreeQueueDepth;            /* 0x1E */
+    U32                     SenseBufferAddressHigh;         /* 0x20 */
+    U32                     SystemReplyAddressHigh;         /* 0x24 */
+    U64                     SystemRequestFrameBaseAddress;  /* 0x28 */
+    U64                     ReplyDescriptorPostQueueAddress;/* 0x30 */
+    U64                     ReplyFreeQueueAddress;          /* 0x38 */
+    U64                     TimeStamp;                      /* 0x40 */
+} MPI2_IOC_INIT_REQUEST, MPI2_POINTER PTR_MPI2_IOC_INIT_REQUEST,
+  Mpi2IOCInitRequest_t, MPI2_POINTER pMpi2IOCInitRequest_t;
+
+/* WhoInit values */
+#define MPI2_WHOINIT_NOT_INITIALIZED            (0x00)
+#define MPI2_WHOINIT_SYSTEM_BIOS                (0x01)
+#define MPI2_WHOINIT_ROM_BIOS                   (0x02)
+#define MPI2_WHOINIT_PCI_PEER                   (0x03)
+#define MPI2_WHOINIT_HOST_DRIVER                (0x04)
+#define MPI2_WHOINIT_MANUFACTURER               (0x05)
+
+/* MsgVersion */
+#define MPI2_IOCINIT_MSGVERSION_MAJOR_MASK      (0xFF00)
+#define MPI2_IOCINIT_MSGVERSION_MAJOR_SHIFT     (8)
+#define MPI2_IOCINIT_MSGVERSION_MINOR_MASK      (0x00FF)
+#define MPI2_IOCINIT_MSGVERSION_MINOR_SHIFT     (0)
+
+/* HeaderVersion */
+#define MPI2_IOCINIT_HDRVERSION_UNIT_MASK       (0xFF00)
+#define MPI2_IOCINIT_HDRVERSION_UNIT_SHIFT      (8)
+#define MPI2_IOCINIT_HDRVERSION_DEV_MASK        (0x00FF)
+#define MPI2_IOCINIT_HDRVERSION_DEV_SHIFT       (0)
+
+/* minimum depth for the Reply Descriptor Post Queue */
+#define MPI2_RDPQ_DEPTH_MIN                     (16)
+
+
+/* IOCInit Reply message */
+typedef struct _MPI2_IOC_INIT_REPLY
+{
+    U8                      WhoInit;                        /* 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_IOC_INIT_REPLY, MPI2_POINTER PTR_MPI2_IOC_INIT_REPLY,
+  Mpi2IOCInitReply_t, MPI2_POINTER pMpi2IOCInitReply_t;
+
+
+/****************************************************************************
+*  IOCFacts message
+****************************************************************************/
+
+/* IOCFacts Request message */
+typedef struct _MPI2_IOC_FACTS_REQUEST
+{
+    U16                     Reserved1;                      /* 0x00 */
+    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 */
+} MPI2_IOC_FACTS_REQUEST, MPI2_POINTER PTR_MPI2_IOC_FACTS_REQUEST,
+  Mpi2IOCFactsRequest_t, MPI2_POINTER pMpi2IOCFactsRequest_t;
+
+
+/* IOCFacts Reply message */
+typedef struct _MPI2_IOC_FACTS_REPLY
+{
+    U16                     MsgVersion;                     /* 0x00 */
+    U8                      MsgLength;                      /* 0x02 */
+    U8                      Function;                       /* 0x03 */
+    U16                     HeaderVersion;                  /* 0x04 */
+    U8                      IOCNumber;                      /* 0x06 */
+    U8                      MsgFlags;                       /* 0x07 */
+    U8                      VP_ID;                          /* 0x08 */
+    U8                      VF_ID;                          /* 0x09 */
+    U16                     Reserved1;                      /* 0x0A */
+    U16                     IOCExceptions;                  /* 0x0C */
+    U16                     IOCStatus;                      /* 0x0E */
+    U32                     IOCLogInfo;                     /* 0x10 */
+    U8                      MaxChainDepth;                  /* 0x14 */
+    U8                      WhoInit;                        /* 0x15 */
+    U8                      NumberOfPorts;                  /* 0x16 */
+    U8                      Reserved2;                      /* 0x17 */
+    U16                     RequestCredit;                  /* 0x18 */
+    U16                     ProductID;                      /* 0x1A */
+    U32                     IOCCapabilities;                /* 0x1C */
+    MPI2_VERSION_UNION      FWVersion;                      /* 0x20 */
+    U16                     IOCRequestFrameSize;            /* 0x24 */
+    U16                     Reserved3;                      /* 0x26 */
+    U16                     MaxInitiators;                  /* 0x28 */
+    U16                     MaxTargets;                     /* 0x2A */
+    U16                     MaxSasExpanders;                /* 0x2C */
+    U16                     MaxEnclosures;                  /* 0x2E */
+    U16                     ProtocolFlags;                  /* 0x30 */
+    U16                     HighPriorityCredit;             /* 0x32 */
+    U16                     MaxReplyDescriptorPostQueueDepth; /* 0x34 */
+    U8                      ReplyFrameSize;                 /* 0x36 */
+    U8                      MaxVolumes;                     /* 0x37 */
+    U16                     MaxDevHandle;                   /* 0x38 */
+    U16                     MaxPersistentEntries;           /* 0x3A */
+    U32                     Reserved4;                      /* 0x3C */
+} MPI2_IOC_FACTS_REPLY, MPI2_POINTER PTR_MPI2_IOC_FACTS_REPLY,
+  Mpi2IOCFactsReply_t, MPI2_POINTER pMpi2IOCFactsReply_t;
+
+/* MsgVersion */
+#define MPI2_IOCFACTS_MSGVERSION_MAJOR_MASK             (0xFF00)
+#define MPI2_IOCFACTS_MSGVERSION_MAJOR_SHIFT            (8)
+#define MPI2_IOCFACTS_MSGVERSION_MINOR_MASK             (0x00FF)
+#define MPI2_IOCFACTS_MSGVERSION_MINOR_SHIFT            (0)
+
+/* HeaderVersion */
+#define MPI2_IOCFACTS_HDRVERSION_UNIT_MASK              (0xFF00)
+#define MPI2_IOCFACTS_HDRVERSION_UNIT_SHIFT             (8)
+#define MPI2_IOCFACTS_HDRVERSION_DEV_MASK               (0x00FF)
+#define MPI2_IOCFACTS_HDRVERSION_DEV_SHIFT              (0)
+
+/* IOCExceptions */
+#define MPI2_IOCFACTS_EXCEPT_IR_FOREIGN_CONFIG_MAX      (0x0100)
+
+#define MPI2_IOCFACTS_EXCEPT_BOOTSTAT_MASK              (0x00E0)
+#define MPI2_IOCFACTS_EXCEPT_BOOTSTAT_GOOD              (0x0000)
+#define MPI2_IOCFACTS_EXCEPT_BOOTSTAT_BACKUP            (0x0020)
+#define MPI2_IOCFACTS_EXCEPT_BOOTSTAT_RESTORED          (0x0040)
+#define MPI2_IOCFACTS_EXCEPT_BOOTSTAT_CORRUPT_BACKUP    (0x0060)
+
+#define MPI2_IOCFACTS_EXCEPT_METADATA_UNSUPPORTED       (0x0010)
+#define MPI2_IOCFACTS_EXCEPT_MANUFACT_CHECKSUM_FAIL     (0x0008)
+#define MPI2_IOCFACTS_EXCEPT_FW_CHECKSUM_FAIL           (0x0004)
+#define MPI2_IOCFACTS_EXCEPT_RAID_CONFIG_INVALID        (0x0002)
+#define MPI2_IOCFACTS_EXCEPT_CONFIG_CHECKSUM_FAIL       (0x0001)
+
+/* defines for WhoInit field are after the IOCInit Request */
+
+/* ProductID field uses MPI2_FW_HEADER_PID_ */
+
+/* IOCCapabilities */
+#define MPI2_IOCFACTS_CAPABILITY_EVENT_REPLAY           (0x00002000)
+#define MPI2_IOCFACTS_CAPABILITY_INTEGRATED_RAID        (0x00001000)
+#define MPI2_IOCFACTS_CAPABILITY_TLR                    (0x00000800)
+#define MPI2_IOCFACTS_CAPABILITY_MULTICAST              (0x00000100)
+#define MPI2_IOCFACTS_CAPABILITY_BIDIRECTIONAL_TARGET   (0x00000080)
+#define MPI2_IOCFACTS_CAPABILITY_EEDP                   (0x00000040)
+#define MPI2_IOCFACTS_CAPABILITY_SNAPSHOT_BUFFER        (0x00000010)
+#define MPI2_IOCFACTS_CAPABILITY_DIAG_TRACE_BUFFER      (0x00000008)
+#define MPI2_IOCFACTS_CAPABILITY_TASK_SET_FULL_HANDLING (0x00000004)
+
+/* ProtocolFlags */
+#define MPI2_IOCFACTS_PROTOCOL_SCSI_TARGET              (0x0001)
+#define MPI2_IOCFACTS_PROTOCOL_SCSI_INITIATOR           (0x0002)
+
+
+/****************************************************************************
+*  PortFacts message
+****************************************************************************/
+
+/* PortFacts Request message */
+typedef struct _MPI2_PORT_FACTS_REQUEST
+{
+    U16                     Reserved1;                      /* 0x00 */
+    U8                      ChainOffset;                    /* 0x02 */
+    U8                      Function;                       /* 0x03 */
+    U16                     Reserved2;                      /* 0x04 */
+    U8                      PortNumber;                     /* 0x06 */
+    U8                      MsgFlags;                       /* 0x07 */
+    U8                      VP_ID;                          /* 0x08 */
+    U8                      VF_ID;                          /* 0x09 */
+    U16                     Reserved3;                      /* 0x0A */
+} MPI2_PORT_FACTS_REQUEST, MPI2_POINTER PTR_MPI2_PORT_FACTS_REQUEST,
+  Mpi2PortFactsRequest_t, MPI2_POINTER pMpi2PortFactsRequest_t;
+
+/* PortFacts Reply message */
+typedef struct _MPI2_PORT_FACTS_REPLY
+{
+    U16                     Reserved1;                      /* 0x00 */
+    U8                      MsgLength;                      /* 0x02 */
+    U8                      Function;                       /* 0x03 */
+    U16                     Reserved2;                      /* 0x04 */
+    U8                      PortNumber;                     /* 0x06 */
+    U8                      MsgFlags;                       /* 0x07 */
+    U8                      VP_ID;                          /* 0x08 */
+    U8                      VF_ID;                          /* 0x09 */
+    U16                     Reserved3;                      /* 0x0A */
+    U16                     Reserved4;                      /* 0x0C */
+    U16                     IOCStatus;                      /* 0x0E */
+    U32                     IOCLogInfo;                     /* 0x10 */
+    U8                      Reserved5;                      /* 0x14 */
+    U8                      PortType;                       /* 0x15 */
+    U16                     Reserved6;                      /* 0x16 */
+    U16                     MaxPostedCmdBuffers;            /* 0x18 */
+    U16                     Reserved7;                      /* 0x1A */
+} MPI2_PORT_FACTS_REPLY, MPI2_POINTER PTR_MPI2_PORT_FACTS_REPLY,
+  Mpi2PortFactsReply_t, MPI2_POINTER pMpi2PortFactsReply_t;
+
+/* PortType values */
+#define MPI2_PORTFACTS_PORTTYPE_INACTIVE            (0x00)
+#define MPI2_PORTFACTS_PORTTYPE_FC                  (0x10)
+#define MPI2_PORTFACTS_PORTTYPE_ISCSI               (0x20)
+#define MPI2_PORTFACTS_PORTTYPE_SAS_PHYSICAL        (0x30)
+#define MPI2_PORTFACTS_PORTTYPE_SAS_VIRTUAL         (0x31)
+
+
+/****************************************************************************
+*  PortEnable message
+****************************************************************************/
+
+/* PortEnable Request message */
+typedef struct _MPI2_PORT_ENABLE_REQUEST
+{
+    U16                     Reserved1;                      /* 0x00 */
+    U8                      ChainOffset;                    /* 0x02 */
+    U8                      Function;                       /* 0x03 */
+    U8                      Reserved2;                      /* 0x04 */
+    U8                      PortFlags;                      /* 0x05 */
+    U8                      Reserved3;                      /* 0x06 */
+    U8                      MsgFlags;                       /* 0x07 */
+    U8                      VP_ID;                          /* 0x08 */
+    U8                      VF_ID;                          /* 0x09 */
+    U16                     Reserved4;                      /* 0x0A */
+} MPI2_PORT_ENABLE_REQUEST, MPI2_POINTER PTR_MPI2_PORT_ENABLE_REQUEST,
+  Mpi2PortEnableRequest_t, MPI2_POINTER pMpi2PortEnableRequest_t;
+
+
+/* PortEnable Reply message */
+typedef struct _MPI2_PORT_ENABLE_REPLY
+{
+    U16                     Reserved1;                      /* 0x00 */
+    U8                      MsgLength;                      /* 0x02 */
+    U8                      Function;                       /* 0x03 */
+    U8                      Reserved2;                      /* 0x04 */
+    U8                      PortFlags;                      /* 0x05 */
+    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_PORT_ENABLE_REPLY, MPI2_POINTER PTR_MPI2_PORT_ENABLE_REPLY,
+  Mpi2PortEnableReply_t, MPI2_POINTER pMpi2PortEnableReply_t;
+
+
+/****************************************************************************
+*  EventNotification message
+****************************************************************************/
+
+/* EventNotification Request message */
+#define MPI2_EVENT_NOTIFY_EVENTMASK_WORDS           (4)
+
+typedef struct _MPI2_EVENT_NOTIFICATION_REQUEST
+{
+    U16                     Reserved1;                      /* 0x00 */
+    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 */
+    U32                     Reserved5;                      /* 0x0C */
+    U32                     Reserved6;                      /* 0x10 */
+    U32                     EventMasks[MPI2_EVENT_NOTIFY_EVENTMASK_WORDS];/* 0x14 */
+    U16                     SASBroadcastPrimitiveMasks;     /* 0x24 */
+    U16                     Reserved7;                      /* 0x26 */
+    U32                     Reserved8;                      /* 0x28 */
+} MPI2_EVENT_NOTIFICATION_REQUEST,
+  MPI2_POINTER PTR_MPI2_EVENT_NOTIFICATION_REQUEST,
+  Mpi2EventNotificationRequest_t, MPI2_POINTER pMpi2EventNotificationRequest_t;
+
+
+/* EventNotification Reply message */
+typedef struct _MPI2_EVENT_NOTIFICATION_REPLY
+{
+    U16                     EventDataLength;                /* 0x00 */
+    U8                      MsgLength;                      /* 0x02 */
+    U8                      Function;                       /* 0x03 */
+    U16                     Reserved1;                      /* 0x04 */
+    U8                      AckRequired;                    /* 0x06 */
+    U8                      MsgFlags;                       /* 0x07 */
+    U8                      VP_ID;                          /* 0x08 */
+    U8                      VF_ID;                          /* 0x09 */
+    U16                     Reserved2;                      /* 0x0A */
+    U16                     Reserved3;                      /* 0x0C */
+    U16                     IOCStatus;                      /* 0x0E */
+    U32                     IOCLogInfo;                     /* 0x10 */
+    U16                     Event;                          /* 0x14 */
+    U16                     Reserved4;                      /* 0x16 */
+    U32                     EventContext;                   /* 0x18 */
+    U32                     EventData[1];                   /* 0x1C */
+} MPI2_EVENT_NOTIFICATION_REPLY, MPI2_POINTER PTR_MPI2_EVENT_NOTIFICATION_REPLY,
+  Mpi2EventNotificationReply_t, MPI2_POINTER pMpi2EventNotificationReply_t;
+
+/* AckRequired */
+#define MPI2_EVENT_NOTIFICATION_ACK_NOT_REQUIRED    (0x00)
+#define MPI2_EVENT_NOTIFICATION_ACK_REQUIRED        (0x01)
+
+/* Event */
+#define MPI2_EVENT_LOG_DATA                         (0x0001)
+#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_SAS_DEVICE_STATUS_CHANGE         (0x000F)
+#define MPI2_EVENT_IR_OPERATION_STATUS              (0x0014)
+#define MPI2_EVENT_SAS_DISCOVERY                    (0x0016)
+#define MPI2_EVENT_SAS_BROADCAST_PRIMITIVE          (0x0017)
+#define MPI2_EVENT_SAS_INIT_DEVICE_STATUS_CHANGE    (0x0018)
+#define MPI2_EVENT_SAS_INIT_TABLE_OVERFLOW          (0x0019)
+#define MPI2_EVENT_SAS_TOPOLOGY_CHANGE_LIST         (0x001C)
+#define MPI2_EVENT_SAS_ENCL_DEVICE_STATUS_CHANGE    (0x001D)
+#define MPI2_EVENT_IR_VOLUME                        (0x001E)
+#define MPI2_EVENT_IR_PHYSICAL_DISK                 (0x001F)
+#define MPI2_EVENT_IR_CONFIGURATION_CHANGE_LIST     (0x0020)
+#define MPI2_EVENT_LOG_ENTRY_ADDED                  (0x0021)
+
+
+/* Log Entry Added Event data */
+
+/* the following structure matches MPI2_LOG_0_ENTRY in mpi2_cnfg.h */
+#define MPI2_EVENT_DATA_LOG_DATA_LENGTH             (0x1C)
+
+typedef struct _MPI2_EVENT_DATA_LOG_ENTRY_ADDED
+{
+    U64         TimeStamp;                          /* 0x00 */
+    U32         Reserved1;                          /* 0x08 */
+    U16         LogSequence;                        /* 0x0C */
+    U16         LogEntryQualifier;                  /* 0x0E */
+    U8          VP_ID;                              /* 0x10 */
+    U8          VF_ID;                              /* 0x11 */
+    U16         Reserved2;                          /* 0x12 */
+    U8          LogData[MPI2_EVENT_DATA_LOG_DATA_LENGTH];/* 0x14 */
+} MPI2_EVENT_DATA_LOG_ENTRY_ADDED,
+  MPI2_POINTER PTR_MPI2_EVENT_DATA_LOG_ENTRY_ADDED,
+  Mpi2EventDataLogEntryAdded_t, MPI2_POINTER pMpi2EventDataLogEntryAdded_t;
+
+/* Hard Reset Received Event data */
+
+typedef struct _MPI2_EVENT_DATA_HARD_RESET_RECEIVED
+{
+    U8                      Reserved1;                      /* 0x00 */
+    U8                      Port;                           /* 0x01 */
+    U16                     Reserved2;                      /* 0x02 */
+} MPI2_EVENT_DATA_HARD_RESET_RECEIVED,
+  MPI2_POINTER PTR_MPI2_EVENT_DATA_HARD_RESET_RECEIVED,
+  Mpi2EventDataHardResetReceived_t,
+  MPI2_POINTER pMpi2EventDataHardResetReceived_t;
+
+/* Task Set Full Event data */
+
+typedef struct _MPI2_EVENT_DATA_TASK_SET_FULL
+{
+    U16                     DevHandle;                      /* 0x00 */
+    U16                     CurrentDepth;                   /* 0x02 */
+} MPI2_EVENT_DATA_TASK_SET_FULL, MPI2_POINTER PTR_MPI2_EVENT_DATA_TASK_SET_FULL,
+  Mpi2EventDataTaskSetFull_t, MPI2_POINTER pMpi2EventDataTaskSetFull_t;
+
+
+/* SAS Device Status Change Event data */
+
+typedef struct _MPI2_EVENT_DATA_SAS_DEVICE_STATUS_CHANGE
+{
+    U16                     TaskTag;                        /* 0x00 */
+    U8                      ReasonCode;                     /* 0x02 */
+    U8                      Reserved1;                      /* 0x03 */
+    U8                      ASC;                            /* 0x04 */
+    U8                      ASCQ;                           /* 0x05 */
+    U16                     DevHandle;                      /* 0x06 */
+    U32                     Reserved2;                      /* 0x08 */
+    U64                     SASAddress;                     /* 0x0C */
+    U8                      LUN[8];                         /* 0x14 */
+} MPI2_EVENT_DATA_SAS_DEVICE_STATUS_CHANGE,
+  MPI2_POINTER PTR_MPI2_EVENT_DATA_SAS_DEVICE_STATUS_CHANGE,
+  Mpi2EventDataSasDeviceStatusChange_t,
+  MPI2_POINTER pMpi2EventDataSasDeviceStatusChange_t;
+
+/* SAS Device Status Change Event data ReasonCode values */
+#define MPI2_EVENT_SAS_DEV_STAT_RC_SMART_DATA               (0x05)
+#define MPI2_EVENT_SAS_DEV_STAT_RC_UNSUPPORTED              (0x07)
+#define MPI2_EVENT_SAS_DEV_STAT_RC_INTERNAL_DEVICE_RESET    (0x08)
+#define MPI2_EVENT_SAS_DEV_STAT_RC_TASK_ABORT_INTERNAL      (0x09)
+#define MPI2_EVENT_SAS_DEV_STAT_RC_ABORT_TASK_SET_INTERNAL  (0x0A)
+#define MPI2_EVENT_SAS_DEV_STAT_RC_CLEAR_TASK_SET_INTERNAL  (0x0B)
+#define MPI2_EVENT_SAS_DEV_STAT_RC_QUERY_TASK_INTERNAL      (0x0C)
+#define MPI2_EVENT_SAS_DEV_STAT_RC_ASYNC_NOTIFICATION       (0x0D)
+#define MPI2_EVENT_SAS_DEV_STAT_RC_CMP_INTERNAL_DEV_RESET   (0x0E)
+#define MPI2_EVENT_SAS_DEV_STAT_RC_CMP_TASK_ABORT_INTERNAL  (0x0F)
+#define MPI2_EVENT_SAS_DEV_STAT_RC_SATA_INIT_FAILURE        (0x10)
+
+
+/* Integrated RAID Operation Status Event data */
+
+typedef struct _MPI2_EVENT_DATA_IR_OPERATION_STATUS
+{
+    U16                     VolDevHandle;               /* 0x00 */
+    U16                     Reserved1;                  /* 0x02 */
+    U8                      RAIDOperation;              /* 0x04 */
+    U8                      PercentComplete;            /* 0x05 */
+    U16                     Reserved2;                  /* 0x06 */
+    U32                     Resereved3;                 /* 0x08 */
+} MPI2_EVENT_DATA_IR_OPERATION_STATUS,
+  MPI2_POINTER PTR_MPI2_EVENT_DATA_IR_OPERATION_STATUS,
+  Mpi2EventDataIrOperationStatus_t,
+  MPI2_POINTER pMpi2EventDataIrOperationStatus_t;
+
+/* Integrated RAID Operation Status Event data RAIDOperation values */
+#define MPI2_EVENT_IR_RAIDOP_RESYNC                     (0x00)
+#define MPI2_EVENT_IR_RAIDOP_ONLINE_CAP_EXPANSION       (0x01)
+#define MPI2_EVENT_IR_RAIDOP_CONSISTENCY_CHECK          (0x02)
+#define MPI2_EVENT_IR_RAIDOP_BACKGROUND_INIT            (0x03)
+#define MPI2_EVENT_IR_RAIDOP_MAKE_DATA_CONSISTENT       (0x04)
+
+
+/* Integrated RAID Volume Event data */
+
+typedef struct _MPI2_EVENT_DATA_IR_VOLUME
+{
+    U16                     VolDevHandle;               /* 0x00 */
+    U8                      ReasonCode;                 /* 0x02 */
+    U8                      Reserved1;                  /* 0x03 */
+    U32                     NewValue;                   /* 0x04 */
+    U32                     PreviousValue;              /* 0x08 */
+} MPI2_EVENT_DATA_IR_VOLUME, MPI2_POINTER PTR_MPI2_EVENT_DATA_IR_VOLUME,
+  Mpi2EventDataIrVolume_t, MPI2_POINTER pMpi2EventDataIrVolume_t;
+
+/* Integrated RAID Volume Event data ReasonCode values */
+#define MPI2_EVENT_IR_VOLUME_RC_SETTINGS_CHANGED        (0x01)
+#define MPI2_EVENT_IR_VOLUME_RC_STATUS_FLAGS_CHANGED    (0x02)
+#define MPI2_EVENT_IR_VOLUME_RC_STATE_CHANGED           (0x03)
+
+
+/* Integrated RAID Physical Disk Event data */
+
+typedef struct _MPI2_EVENT_DATA_IR_PHYSICAL_DISK
+{
+    U16                     Reserved1;                  /* 0x00 */
+    U8                      ReasonCode;                 /* 0x02 */
+    U8                      PhysDiskNum;                /* 0x03 */
+    U16                     PhysDiskDevHandle;          /* 0x04 */
+    U16                     Reserved2;                  /* 0x06 */
+    U16                     Slot;                       /* 0x08 */
+    U16                     EnclosureHandle;            /* 0x0A */
+    U32                     NewValue;                   /* 0x0C */
+    U32                     PreviousValue;              /* 0x10 */
+} MPI2_EVENT_DATA_IR_PHYSICAL_DISK,
+  MPI2_POINTER PTR_MPI2_EVENT_DATA_IR_PHYSICAL_DISK,
+  Mpi2EventDataIrPhysicalDisk_t, MPI2_POINTER pMpi2EventDataIrPhysicalDisk_t;
+
+/* Integrated RAID Physical Disk Event data ReasonCode values */
+#define MPI2_EVENT_IR_PHYSDISK_RC_SETTINGS_CHANGED      (0x01)
+#define MPI2_EVENT_IR_PHYSDISK_RC_STATUS_FLAGS_CHANGED  (0x02)
+#define MPI2_EVENT_IR_PHYSDISK_RC_STATE_CHANGED         (0x03)
+
+
+/* Integrated RAID Configuration Change List Event data */
+
+/*
+ * Host code (drivers, BIOS, utilities, etc.) should leave this define set to
+ * one and check NumElements at runtime.
+ */
+#ifndef MPI2_EVENT_IR_CONFIG_ELEMENT_COUNT
+#define MPI2_EVENT_IR_CONFIG_ELEMENT_COUNT          (1)
+#endif
+
+typedef struct _MPI2_EVENT_IR_CONFIG_ELEMENT
+{
+    U16                     ElementFlags;               /* 0x00 */
+    U16                     VolDevHandle;               /* 0x02 */
+    U8                      ReasonCode;                 /* 0x04 */
+    U8                      PhysDiskNum;                /* 0x05 */
+    U16                     PhysDiskDevHandle;          /* 0x06 */
+} MPI2_EVENT_IR_CONFIG_ELEMENT, MPI2_POINTER PTR_MPI2_EVENT_IR_CONFIG_ELEMENT,
+  Mpi2EventIrConfigElement_t, MPI2_POINTER pMpi2EventIrConfigElement_t;
+
+/* IR Configuration Change List Event data ElementFlags values */
+#define MPI2_EVENT_IR_CHANGE_EFLAGS_ELEMENT_TYPE_MASK   (0x000F)
+#define MPI2_EVENT_IR_CHANGE_EFLAGS_VOLUME_ELEMENT      (0x0000)
+#define MPI2_EVENT_IR_CHANGE_EFLAGS_VOLPHYSDISK_ELEMENT (0x0001)
+#define MPI2_EVENT_IR_CHANGE_EFLAGS_HOTSPARE_ELEMENT    (0x0002)
+
+/* IR Configuration Change List Event data ReasonCode values */
+#define MPI2_EVENT_IR_CHANGE_RC_ADDED                   (0x01)
+#define MPI2_EVENT_IR_CHANGE_RC_REMOVED                 (0x02)
+#define MPI2_EVENT_IR_CHANGE_RC_NO_CHANGE               (0x03)
+#define MPI2_EVENT_IR_CHANGE_RC_HIDE                    (0x04)
+#define MPI2_EVENT_IR_CHANGE_RC_UNHIDE                  (0x05)
+#define MPI2_EVENT_IR_CHANGE_RC_VOLUME_CREATED          (0x06)
+#define MPI2_EVENT_IR_CHANGE_RC_VOLUME_DELETED          (0x07)
+#define MPI2_EVENT_IR_CHANGE_RC_PD_CREATED              (0x08)
+#define MPI2_EVENT_IR_CHANGE_RC_PD_DELETED              (0x09)
+
+typedef struct _MPI2_EVENT_DATA_IR_CONFIG_CHANGE_LIST
+{
+    U8                              NumElements;        /* 0x00 */
+    U8                              Reserved1;          /* 0x01 */
+    U8                              Reserved2;          /* 0x02 */
+    U8                              ConfigNum;          /* 0x03 */
+    U32                             Flags;              /* 0x04 */
+    MPI2_EVENT_IR_CONFIG_ELEMENT    ConfigElement[MPI2_EVENT_IR_CONFIG_ELEMENT_COUNT];    /* 0x08 */
+} MPI2_EVENT_DATA_IR_CONFIG_CHANGE_LIST,
+  MPI2_POINTER PTR_MPI2_EVENT_DATA_IR_CONFIG_CHANGE_LIST,
+  Mpi2EventDataIrConfigChangeList_t,
+  MPI2_POINTER pMpi2EventDataIrConfigChangeList_t;
+
+/* IR Configuration Change List Event data Flags values */
+#define MPI2_EVENT_IR_CHANGE_FLAGS_FOREIGN_CONFIG   (0x00000001)
+
+
+/* SAS Discovery Event data */
+
+typedef struct _MPI2_EVENT_DATA_SAS_DISCOVERY
+{
+    U8                      Flags;                      /* 0x00 */
+    U8                      ReasonCode;                 /* 0x01 */
+    U8                      PhysicalPort;               /* 0x02 */
+    U8                      Reserved1;                  /* 0x03 */
+    U32                     DiscoveryStatus;            /* 0x04 */
+} MPI2_EVENT_DATA_SAS_DISCOVERY,
+  MPI2_POINTER PTR_MPI2_EVENT_DATA_SAS_DISCOVERY,
+  Mpi2EventDataSasDiscovery_t, MPI2_POINTER pMpi2EventDataSasDiscovery_t;
+
+/* SAS Discovery Event data Flags values */
+#define MPI2_EVENT_SAS_DISC_DEVICE_CHANGE                   (0x02)
+#define MPI2_EVENT_SAS_DISC_IN_PROGRESS                     (0x01)
+
+/* SAS Discovery Event data ReasonCode values */
+#define MPI2_EVENT_SAS_DISC_RC_STARTED                      (0x01)
+#define MPI2_EVENT_SAS_DISC_RC_COMPLETED                    (0x02)
+
+/* SAS Discovery Event data DiscoveryStatus values */
+#define MPI2_EVENT_SAS_DISC_DS_MAX_ENCLOSURES_EXCEED            (0x80000000)
+#define MPI2_EVENT_SAS_DISC_DS_MAX_EXPANDERS_EXCEED             (0x40000000)
+#define MPI2_EVENT_SAS_DISC_DS_MAX_DEVICES_EXCEED               (0x20000000)
+#define MPI2_EVENT_SAS_DISC_DS_MAX_TOPO_PHYS_EXCEED             (0x10000000)
+#define MPI2_EVENT_SAS_DISC_DS_DOWNSTREAM_INITIATOR             (0x08000000)
+#define MPI2_EVENT_SAS_DISC_DS_MULTI_SUBTRACTIVE_SUBTRACTIVE    (0x00008000)
+#define MPI2_EVENT_SAS_DISC_DS_EXP_MULTI_SUBTRACTIVE            (0x00004000)
+#define MPI2_EVENT_SAS_DISC_DS_MULTI_PORT_DOMAIN                (0x00002000)
+#define MPI2_EVENT_SAS_DISC_DS_TABLE_TO_SUBTRACTIVE_LINK        (0x00001000)
+#define MPI2_EVENT_SAS_DISC_DS_UNSUPPORTED_DEVICE               (0x00000800)
+#define MPI2_EVENT_SAS_DISC_DS_TABLE_LINK                       (0x00000400)
+#define MPI2_EVENT_SAS_DISC_DS_SUBTRACTIVE_LINK                 (0x00000200)
+#define MPI2_EVENT_SAS_DISC_DS_SMP_CRC_ERROR                    (0x00000100)
+#define MPI2_EVENT_SAS_DISC_DS_SMP_FUNCTION_FAILED              (0x00000080)
+#define MPI2_EVENT_SAS_DISC_DS_INDEX_NOT_EXIST                  (0x00000040)
+#define MPI2_EVENT_SAS_DISC_DS_OUT_ROUTE_ENTRIES                (0x00000020)
+#define MPI2_EVENT_SAS_DISC_DS_SMP_TIMEOUT                      (0x00000010)
+#define MPI2_EVENT_SAS_DISC_DS_MULTIPLE_PORTS                   (0x00000004)
+#define MPI2_EVENT_SAS_DISC_DS_UNADDRESSABLE_DEVICE             (0x00000002)
+#define MPI2_EVENT_SAS_DISC_DS_LOOP_DETECTED                    (0x00000001)
+
+
+/* SAS Broadcast Primitive Event data */
+
+typedef struct _MPI2_EVENT_DATA_SAS_BROADCAST_PRIMITIVE
+{
+    U8                      PhyNum;                     /* 0x00 */
+    U8                      Port;                       /* 0x01 */
+    U8                      PortWidth;                  /* 0x02 */
+    U8                      Primitive;                  /* 0x03 */
+} MPI2_EVENT_DATA_SAS_BROADCAST_PRIMITIVE,
+  MPI2_POINTER PTR_MPI2_EVENT_DATA_SAS_BROADCAST_PRIMITIVE,
+  Mpi2EventDataSasBroadcastPrimitive_t,
+  MPI2_POINTER pMpi2EventDataSasBroadcastPrimitive_t;
+
+/* defines for the Primitive field */
+#define MPI2_EVENT_PRIMITIVE_CHANGE                         (0x01)
+#define MPI2_EVENT_PRIMITIVE_SES                            (0x02)
+#define MPI2_EVENT_PRIMITIVE_EXPANDER                       (0x03)
+#define MPI2_EVENT_PRIMITIVE_ASYNCHRONOUS_EVENT             (0x04)
+#define MPI2_EVENT_PRIMITIVE_RESERVED3                      (0x05)
+#define MPI2_EVENT_PRIMITIVE_RESERVED4                      (0x06)
+#define MPI2_EVENT_PRIMITIVE_CHANGE0_RESERVED               (0x07)
+#define MPI2_EVENT_PRIMITIVE_CHANGE1_RESERVED               (0x08)
+
+
+/* SAS Initiator Device Status Change Event data */
+
+typedef struct _MPI2_EVENT_DATA_SAS_INIT_DEV_STATUS_CHANGE
+{
+    U8                      ReasonCode;                 /* 0x00 */
+    U8                      PhysicalPort;               /* 0x01 */
+    U16                     DevHandle;                  /* 0x02 */
+    U64                     SASAddress;                 /* 0x04 */
+} MPI2_EVENT_DATA_SAS_INIT_DEV_STATUS_CHANGE,
+  MPI2_POINTER PTR_MPI2_EVENT_DATA_SAS_INIT_DEV_STATUS_CHANGE,
+  Mpi2EventDataSasInitDevStatusChange_t,
+  MPI2_POINTER pMpi2EventDataSasInitDevStatusChange_t;
+
+/* SAS Initiator Device Status Change event ReasonCode values */
+#define MPI2_EVENT_SAS_INIT_RC_ADDED                (0x01)
+#define MPI2_EVENT_SAS_INIT_RC_NOT_RESPONDING       (0x02)
+
+
+/* SAS Initiator Device Table Overflow Event data */
+
+typedef struct _MPI2_EVENT_DATA_SAS_INIT_TABLE_OVERFLOW
+{
+    U16                     MaxInit;                    /* 0x00 */
+    U16                     CurrentInit;                /* 0x02 */
+    U64                     SASAddress;                 /* 0x04 */
+} MPI2_EVENT_DATA_SAS_INIT_TABLE_OVERFLOW,
+  MPI2_POINTER PTR_MPI2_EVENT_DATA_SAS_INIT_TABLE_OVERFLOW,
+  Mpi2EventDataSasInitTableOverflow_t,
+  MPI2_POINTER pMpi2EventDataSasInitTableOverflow_t;
+
+
+/* SAS Topology Change List Event data */
+
+/*
+ * Host code (drivers, BIOS, utilities, etc.) should leave this define set to
+ * one and check NumEntries at runtime.
+ */
+#ifndef MPI2_EVENT_SAS_TOPO_PHY_COUNT
+#define MPI2_EVENT_SAS_TOPO_PHY_COUNT           (1)
+#endif
+
+typedef struct _MPI2_EVENT_SAS_TOPO_PHY_ENTRY
+{
+    U16                     AttachedDevHandle;          /* 0x00 */
+    U8                      LinkRate;                   /* 0x02 */
+    U8                      PhyStatus;                  /* 0x03 */
+} MPI2_EVENT_SAS_TOPO_PHY_ENTRY, MPI2_POINTER PTR_MPI2_EVENT_SAS_TOPO_PHY_ENTRY,
+  Mpi2EventSasTopoPhyEntry_t, MPI2_POINTER pMpi2EventSasTopoPhyEntry_t;
+
+typedef struct _MPI2_EVENT_DATA_SAS_TOPOLOGY_CHANGE_LIST
+{
+    U16                             EnclosureHandle;            /* 0x00 */
+    U16                             ExpanderDevHandle;          /* 0x02 */
+    U8                              NumPhys;                    /* 0x04 */
+    U8                              Reserved1;                  /* 0x05 */
+    U16                             Reserved2;                  /* 0x06 */
+    U8                              NumEntries;                 /* 0x08 */
+    U8                              StartPhyNum;                /* 0x09 */
+    U8                              ExpStatus;                  /* 0x0A */
+    U8                              PhysicalPort;               /* 0x0B */
+    MPI2_EVENT_SAS_TOPO_PHY_ENTRY   PHY[MPI2_EVENT_SAS_TOPO_PHY_COUNT]; /* 0x0C*/
+} MPI2_EVENT_DATA_SAS_TOPOLOGY_CHANGE_LIST,
+  MPI2_POINTER PTR_MPI2_EVENT_DATA_SAS_TOPOLOGY_CHANGE_LIST,
+  Mpi2EventDataSasTopologyChangeList_t,
+  MPI2_POINTER pMpi2EventDataSasTopologyChangeList_t;
+
+/* values for the ExpStatus field */
+#define MPI2_EVENT_SAS_TOPO_ES_ADDED                        (0x01)
+#define MPI2_EVENT_SAS_TOPO_ES_NOT_RESPONDING               (0x02)
+#define MPI2_EVENT_SAS_TOPO_ES_RESPONDING                   (0x03)
+#define MPI2_EVENT_SAS_TOPO_ES_DELAY_NOT_RESPONDING         (0x04)
+
+/* defines for the LinkRate field */
+#define MPI2_EVENT_SAS_TOPO_LR_CURRENT_MASK                 (0xF0)
+#define MPI2_EVENT_SAS_TOPO_LR_CURRENT_SHIFT                (4)
+#define MPI2_EVENT_SAS_TOPO_LR_PREV_MASK                    (0x0F)
+#define MPI2_EVENT_SAS_TOPO_LR_PREV_SHIFT                   (0)
+
+#define MPI2_EVENT_SAS_TOPO_LR_UNKNOWN_LINK_RATE            (0x00)
+#define MPI2_EVENT_SAS_TOPO_LR_PHY_DISABLED                 (0x01)
+#define MPI2_EVENT_SAS_TOPO_LR_NEGOTIATION_FAILED           (0x02)
+#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_RATE_1_5                     (0x08)
+#define MPI2_EVENT_SAS_TOPO_LR_RATE_3_0                     (0x09)
+#define MPI2_EVENT_SAS_TOPO_LR_RATE_6_0                     (0x0A)
+
+/* values for the PhyStatus field */
+#define MPI2_EVENT_SAS_TOPO_PHYSTATUS_VACANT                (0x80)
+#define MPI2_EVENT_SAS_TOPO_PS_MULTIPLEX_CHANGE             (0x10)
+/* values for the PhyStatus ReasonCode sub-field */
+#define MPI2_EVENT_SAS_TOPO_RC_MASK                         (0x0F)
+#define MPI2_EVENT_SAS_TOPO_RC_TARG_ADDED                   (0x01)
+#define MPI2_EVENT_SAS_TOPO_RC_TARG_NOT_RESPONDING          (0x02)
+#define MPI2_EVENT_SAS_TOPO_RC_PHY_CHANGED                  (0x03)
+#define MPI2_EVENT_SAS_TOPO_RC_NO_CHANGE                    (0x04)
+#define MPI2_EVENT_SAS_TOPO_RC_DELAY_NOT_RESPONDING         (0x05)
+
+
+/* SAS Enclosure Device Status Change Event data */
+
+typedef struct _MPI2_EVENT_DATA_SAS_ENCL_DEV_STATUS_CHANGE
+{
+    U16                     EnclosureHandle;            /* 0x00 */
+    U8                      ReasonCode;                 /* 0x02 */
+    U8                      PhysicalPort;               /* 0x03 */
+    U64                     EnclosureLogicalID;         /* 0x04 */
+    U16                     NumSlots;                   /* 0x0C */
+    U16                     StartSlot;                  /* 0x0E */
+    U32                     PhyBits;                    /* 0x10 */
+} MPI2_EVENT_DATA_SAS_ENCL_DEV_STATUS_CHANGE,
+  MPI2_POINTER PTR_MPI2_EVENT_DATA_SAS_ENCL_DEV_STATUS_CHANGE,
+  Mpi2EventDataSasEnclDevStatusChange_t,
+  MPI2_POINTER pMpi2EventDataSasEnclDevStatusChange_t;
+
+/* SAS Enclosure Device Status Change event ReasonCode values */
+#define MPI2_EVENT_SAS_ENCL_RC_ADDED                (0x01)
+#define MPI2_EVENT_SAS_ENCL_RC_NOT_RESPONDING       (0x02)
+
+
+/****************************************************************************
+*  EventAck message
+****************************************************************************/
+
+/* EventAck Request message */
+typedef struct _MPI2_EVENT_ACK_REQUEST
+{
+    U16                     Reserved1;                      /* 0x00 */
+    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 */
+    U16                     Event;                          /* 0x0C */
+    U16                     Reserved5;                      /* 0x0E */
+    U32                     EventContext;                   /* 0x10 */
+} MPI2_EVENT_ACK_REQUEST, MPI2_POINTER PTR_MPI2_EVENT_ACK_REQUEST,
+  Mpi2EventAckRequest_t, MPI2_POINTER pMpi2EventAckRequest_t;
+
+
+/* EventAck Reply message */
+typedef struct _MPI2_EVENT_ACK_REPLY
+{
+    U16                     Reserved1;                      /* 0x00 */
+    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_EVENT_ACK_REPLY, MPI2_POINTER PTR_MPI2_EVENT_ACK_REPLY,
+  Mpi2EventAckReply_t, MPI2_POINTER pMpi2EventAckReply_t;
+
+
+/****************************************************************************
+*  FWDownload message
+****************************************************************************/
+
+/* FWDownload Request message */
+typedef struct _MPI2_FW_DOWNLOAD_REQUEST
+{
+    U8                      ImageType;                  /* 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 */
+    U32                     TotalImageSize;             /* 0x0C */
+    U32                     Reserved5;                  /* 0x10 */
+    MPI2_MPI_SGE_UNION      SGL;                        /* 0x14 */
+} MPI2_FW_DOWNLOAD_REQUEST, MPI2_POINTER PTR_MPI2_FW_DOWNLOAD_REQUEST,
+  Mpi2FWDownloadRequest, MPI2_POINTER pMpi2FWDownloadRequest;
+
+#define MPI2_FW_DOWNLOAD_MSGFLGS_LAST_SEGMENT   (0x01)
+
+#define MPI2_FW_DOWNLOAD_ITYPE_FW                   (0x01)
+#define MPI2_FW_DOWNLOAD_ITYPE_BIOS                 (0x02)
+#define MPI2_FW_DOWNLOAD_ITYPE_MANUFACTURING        (0x06)
+#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_COMMON_BOOT_BLOCK    (0x0B)
+
+/* FWDownload TransactionContext Element */
+typedef struct _MPI2_FW_DOWNLOAD_TCSGE
+{
+    U8                      Reserved1;                  /* 0x00 */
+    U8                      ContextSize;                /* 0x01 */
+    U8                      DetailsLength;              /* 0x02 */
+    U8                      Flags;                      /* 0x03 */
+    U32                     Reserved2;                  /* 0x04 */
+    U32                     ImageOffset;                /* 0x08 */
+    U32                     ImageSize;                  /* 0x0C */
+} MPI2_FW_DOWNLOAD_TCSGE, MPI2_POINTER PTR_MPI2_FW_DOWNLOAD_TCSGE,
+  Mpi2FWDownloadTCSGE_t, MPI2_POINTER pMpi2FWDownloadTCSGE_t;
+
+/* FWDownload Reply message */
+typedef struct _MPI2_FW_DOWNLOAD_REPLY
+{
+    U8                      ImageType;                  /* 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_FW_DOWNLOAD_REPLY, MPI2_POINTER PTR_MPI2_FW_DOWNLOAD_REPLY,
+  Mpi2FWDownloadReply_t, MPI2_POINTER pMpi2FWDownloadReply_t;
+
+
+/****************************************************************************
+*  FWUpload message
+****************************************************************************/
+
+/* FWUpload Request message */
+typedef struct _MPI2_FW_UPLOAD_REQUEST
+{
+    U8                      ImageType;                  /* 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 */
+    U32                     Reserved5;                  /* 0x0C */
+    U32                     Reserved6;                  /* 0x10 */
+    MPI2_MPI_SGE_UNION      SGL;                        /* 0x14 */
+} MPI2_FW_UPLOAD_REQUEST, MPI2_POINTER PTR_MPI2_FW_UPLOAD_REQUEST,
+  Mpi2FWUploadRequest_t, MPI2_POINTER pMpi2FWUploadRequest_t;
+
+#define MPI2_FW_UPLOAD_ITYPE_FW_CURRENT         (0x00)
+#define MPI2_FW_UPLOAD_ITYPE_FW_FLASH           (0x01)
+#define MPI2_FW_UPLOAD_ITYPE_BIOS_FLASH         (0x02)
+#define MPI2_FW_UPLOAD_ITYPE_FW_BACKUP          (0x05)
+#define MPI2_FW_UPLOAD_ITYPE_MANUFACTURING      (0x06)
+#define MPI2_FW_UPLOAD_ITYPE_CONFIG_1           (0x07)
+#define MPI2_FW_UPLOAD_ITYPE_CONFIG_2           (0x08)
+#define MPI2_FW_UPLOAD_ITYPE_MEGARAID           (0x09)
+#define MPI2_FW_UPLOAD_ITYPE_COMPLETE           (0x0A)
+#define MPI2_FW_UPLOAD_ITYPE_COMMON_BOOT_BLOCK  (0x0B)
+
+typedef struct _MPI2_FW_UPLOAD_TCSGE
+{
+    U8                      Reserved1;                  /* 0x00 */
+    U8                      ContextSize;                /* 0x01 */
+    U8                      DetailsLength;              /* 0x02 */
+    U8                      Flags;                      /* 0x03 */
+    U32                     Reserved2;                  /* 0x04 */
+    U32                     ImageOffset;                /* 0x08 */
+    U32                     ImageSize;                  /* 0x0C */
+} MPI2_FW_UPLOAD_TCSGE, MPI2_POINTER PTR_MPI2_FW_UPLOAD_TCSGE,
+  Mpi2FWUploadTCSGE_t, MPI2_POINTER pMpi2FWUploadTCSGE_t;
+
+/* FWUpload Reply message */
+typedef struct _MPI2_FW_UPLOAD_REPLY
+{
+    U8                      ImageType;                  /* 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 */
+    U32                     ActualImageSize;            /* 0x14 */
+} MPI2_FW_UPLOAD_REPLY, MPI2_POINTER PTR_MPI2_FW_UPLOAD_REPLY,
+  Mpi2FWUploadReply_t, MPI2_POINTER pMPi2FWUploadReply_t;
+
+
+/* FW Image Header */
+typedef struct _MPI2_FW_IMAGE_HEADER
+{
+    U32                     Signature;                  /* 0x00 */
+    U32                     Signature0;                 /* 0x04 */
+    U32                     Signature1;                 /* 0x08 */
+    U32                     Signature2;                 /* 0x0C */
+    MPI2_VERSION_UNION      MPIVersion;                 /* 0x10 */
+    MPI2_VERSION_UNION      FWVersion;                  /* 0x14 */
+    MPI2_VERSION_UNION      NVDATAVersion;              /* 0x18 */
+    MPI2_VERSION_UNION      PackageVersion;             /* 0x1C */
+    U16                     VendorID;                   /* 0x20 */
+    U16                     ProductID;                  /* 0x22 */
+    U16                     ProtocolFlags;              /* 0x24 */
+    U16                     Reserved26;                 /* 0x26 */
+    U32                     IOCCapabilities;            /* 0x28 */
+    U32                     ImageSize;                  /* 0x2C */
+    U32                     NextImageHeaderOffset;      /* 0x30 */
+    U32                     Checksum;                   /* 0x34 */
+    U32                     Reserved38;                 /* 0x38 */
+    U32                     Reserved3C;                 /* 0x3C */
+    U32                     Reserved40;                 /* 0x40 */
+    U32                     Reserved44;                 /* 0x44 */
+    U32                     Reserved48;                 /* 0x48 */
+    U32                     Reserved4C;                 /* 0x4C */
+    U32                     Reserved50;                 /* 0x50 */
+    U32                     Reserved54;                 /* 0x54 */
+    U32                     Reserved58;                 /* 0x58 */
+    U32                     Reserved5C;                 /* 0x5C */
+    U32                     Reserved60;                 /* 0x60 */
+    U32                     FirmwareVersionNameWhat;    /* 0x64 */
+    U8                      FirmwareVersionName[32];    /* 0x68 */
+    U32                     VendorNameWhat;             /* 0x88 */
+    U8                      VendorName[32];             /* 0x8C */
+    U32                     PackageNameWhat;            /* 0x88 */
+    U8                      PackageName[32];            /* 0x8C */
+    U32                     ReservedD0;                 /* 0xD0 */
+    U32                     ReservedD4;                 /* 0xD4 */
+    U32                     ReservedD8;                 /* 0xD8 */
+    U32                     ReservedDC;                 /* 0xDC */
+    U32                     ReservedE0;                 /* 0xE0 */
+    U32                     ReservedE4;                 /* 0xE4 */
+    U32                     ReservedE8;                 /* 0xE8 */
+    U32                     ReservedEC;                 /* 0xEC */
+    U32                     ReservedF0;                 /* 0xF0 */
+    U32                     ReservedF4;                 /* 0xF4 */
+    U32                     ReservedF8;                 /* 0xF8 */
+    U32                     ReservedFC;                 /* 0xFC */
+} MPI2_FW_IMAGE_HEADER, MPI2_POINTER PTR_MPI2_FW_IMAGE_HEADER,
+  Mpi2FWImageHeader_t, MPI2_POINTER pMpi2FWImageHeader_t;
+
+/* Signature field */
+#define MPI2_FW_HEADER_SIGNATURE_OFFSET         (0x00)
+#define MPI2_FW_HEADER_SIGNATURE_MASK           (0xFF000000)
+#define MPI2_FW_HEADER_SIGNATURE                (0xEA000000)
+
+/* Signature0 field */
+#define MPI2_FW_HEADER_SIGNATURE0_OFFSET        (0x04)
+#define MPI2_FW_HEADER_SIGNATURE0               (0x5AFAA55A)
+
+/* Signature1 field */
+#define MPI2_FW_HEADER_SIGNATURE1_OFFSET        (0x08)
+#define MPI2_FW_HEADER_SIGNATURE1               (0xA55AFAA5)
+
+/* Signature2 field */
+#define MPI2_FW_HEADER_SIGNATURE2_OFFSET        (0x0C)
+#define MPI2_FW_HEADER_SIGNATURE2               (0x5AA55AFA)
+
+
+/* defines for using the ProductID field */
+#define MPI2_FW_HEADER_PID_TYPE_MASK            (0xF000)
+#define MPI2_FW_HEADER_PID_TYPE_SAS             (0x2000)
+
+#define MPI2_FW_HEADER_PID_PROD_MASK            (0x0F00)
+#define MPI2_FW_HEADER_PID_PROD_A               (0x0000)
+
+#define MPI2_FW_HEADER_PID_FAMILY_MASK          (0x00FF)
+/* SAS */
+#define MPI2_FW_HEADER_PID_FAMILY_2108_SAS      (0x0010)
+
+/* use MPI2_IOCFACTS_PROTOCOL_ defines for ProtocolFlags field */
+
+/* use MPI2_IOCFACTS_CAPABILITY_ defines for IOCCapabilities field */
+
+
+#define MPI2_FW_HEADER_IMAGESIZE_OFFSET         (0x2C)
+#define MPI2_FW_HEADER_NEXTIMAGE_OFFSET         (0x30)
+#define MPI2_FW_HEADER_VERNMHWAT_OFFSET         (0x64)
+
+#define MPI2_FW_HEADER_WHAT_SIGNATURE           (0x29232840)
+
+#define MPI2_FW_HEADER_SIZE                     (0x100)
+
+
+/* Extended Image Header */
+typedef struct _MPI2_EXT_IMAGE_HEADER
+
+{
+    U8                      ImageType;                  /* 0x00 */
+    U8                      Reserved1;                  /* 0x01 */
+    U16                     Reserved2;                  /* 0x02 */
+    U32                     Checksum;                   /* 0x04 */
+    U32                     ImageSize;                  /* 0x08 */
+    U32                     NextImageHeaderOffset;      /* 0x0C */
+    U32                     PackageVersion;             /* 0x10 */
+    U32                     Reserved3;                  /* 0x14 */
+    U32                     Reserved4;                  /* 0x18 */
+    U32                     Reserved5;                  /* 0x1C */
+    U8                      IdentifyString[32];         /* 0x20 */
+} MPI2_EXT_IMAGE_HEADER, MPI2_POINTER PTR_MPI2_EXT_IMAGE_HEADER,
+  Mpi2ExtImageHeader_t, MPI2_POINTER pMpi2ExtImageHeader_t;
+
+/* useful offsets */
+#define MPI2_EXT_IMAGE_IMAGETYPE_OFFSET         (0x00)
+#define MPI2_EXT_IMAGE_IMAGESIZE_OFFSET         (0x08)
+#define MPI2_EXT_IMAGE_NEXTIMAGE_OFFSET         (0x0C)
+
+#define MPI2_EXT_IMAGE_HEADER_SIZE              (0x40)
+
+/* defines for the ImageType field */
+#define MPI2_EXT_IMAGE_TYPE_UNSPECIFIED         (0x00)
+#define MPI2_EXT_IMAGE_TYPE_FW                  (0x01)
+#define MPI2_EXT_IMAGE_TYPE_NVDATA              (0x03)
+#define MPI2_EXT_IMAGE_TYPE_BOOTLOADER          (0x04)
+#define MPI2_EXT_IMAGE_TYPE_INITIALIZATION      (0x05)
+#define MPI2_EXT_IMAGE_TYPE_FLASH_LAYOUT        (0x06)
+#define MPI2_EXT_IMAGE_TYPE_SUPPORTED_DEVICES   (0x07)
+#define MPI2_EXT_IMAGE_TYPE_MEGARAID            (0x08)
+
+#define MPI2_EXT_IMAGE_TYPE_MAX                 (MPI2_EXT_IMAGE_TYPE_MEGARAID)
+
+
+
+/* FLASH Layout Extended Image Data */
+
+/*
+ * Host code (drivers, BIOS, utilities, etc.) should leave this define set to
+ * one and check RegionsPerLayout at runtime.
+ */
+#ifndef MPI2_FLASH_NUMBER_OF_REGIONS
+#define MPI2_FLASH_NUMBER_OF_REGIONS        (1)
+#endif
+
+/*
+ * Host code (drivers, BIOS, utilities, etc.) should leave this define set to
+ * one and check NumberOfLayouts at runtime.
+ */
+#ifndef MPI2_FLASH_NUMBER_OF_LAYOUTS
+#define MPI2_FLASH_NUMBER_OF_LAYOUTS        (1)
+#endif
+
+typedef struct _MPI2_FLASH_REGION
+{
+    U8                      RegionType;                 /* 0x00 */
+    U8                      Reserved1;                  /* 0x01 */
+    U16                     Reserved2;                  /* 0x02 */
+    U32                     RegionOffset;               /* 0x04 */
+    U32                     RegionSize;                 /* 0x08 */
+    U32                     Reserved3;                  /* 0x0C */
+} MPI2_FLASH_REGION, MPI2_POINTER PTR_MPI2_FLASH_REGION,
+  Mpi2FlashRegion_t, MPI2_POINTER pMpi2FlashRegion_t;
+
+typedef struct _MPI2_FLASH_LAYOUT
+{
+    U32                     FlashSize;                  /* 0x00 */
+    U32                     Reserved1;                  /* 0x04 */
+    U32                     Reserved2;                  /* 0x08 */
+    U32                     Reserved3;                  /* 0x0C */
+    MPI2_FLASH_REGION       Region[MPI2_FLASH_NUMBER_OF_REGIONS];/* 0x10 */
+} MPI2_FLASH_LAYOUT, MPI2_POINTER PTR_MPI2_FLASH_LAYOUT,
+  Mpi2FlashLayout_t, MPI2_POINTER pMpi2FlashLayout_t;
+
+typedef struct _MPI2_FLASH_LAYOUT_DATA
+{
+    U8                      ImageRevision;              /* 0x00 */
+    U8                      Reserved1;                  /* 0x01 */
+    U8                      SizeOfRegion;               /* 0x02 */
+    U8                      Reserved2;                  /* 0x03 */
+    U16                     NumberOfLayouts;            /* 0x04 */
+    U16                     RegionsPerLayout;           /* 0x06 */
+    U16                     MinimumSectorAlignment;     /* 0x08 */
+    U16                     Reserved3;                  /* 0x0A */
+    U32                     Reserved4;                  /* 0x0C */
+    MPI2_FLASH_LAYOUT       Layout[MPI2_FLASH_NUMBER_OF_LAYOUTS];/* 0x10 */
+} MPI2_FLASH_LAYOUT_DATA, MPI2_POINTER PTR_MPI2_FLASH_LAYOUT_DATA,
+  Mpi2FlashLayoutData_t, MPI2_POINTER pMpi2FlashLayoutData_t;
+
+/* defines for the RegionType field */
+#define MPI2_FLASH_REGION_UNUSED                (0x00)
+#define MPI2_FLASH_REGION_FIRMWARE              (0x01)
+#define MPI2_FLASH_REGION_BIOS                  (0x02)
+#define MPI2_FLASH_REGION_NVDATA                (0x03)
+#define MPI2_FLASH_REGION_FIRMWARE_BACKUP       (0x05)
+#define MPI2_FLASH_REGION_MFG_INFORMATION       (0x06)
+#define MPI2_FLASH_REGION_CONFIG_1              (0x07)
+#define MPI2_FLASH_REGION_CONFIG_2              (0x08)
+#define MPI2_FLASH_REGION_MEGARAID              (0x09)
+#define MPI2_FLASH_REGION_INIT                  (0x0A)
+
+/* ImageRevision */
+#define MPI2_FLASH_LAYOUT_IMAGE_REVISION        (0x00)
+
+
+
+/* Supported Devices Extended Image Data */
+
+/*
+ * Host code (drivers, BIOS, utilities, etc.) should leave this define set to
+ * one and check NumberOfDevices at runtime.
+ */
+#ifndef MPI2_SUPPORTED_DEVICES_IMAGE_NUM_DEVICES
+#define MPI2_SUPPORTED_DEVICES_IMAGE_NUM_DEVICES    (1)
+#endif
+
+typedef struct _MPI2_SUPPORTED_DEVICE
+{
+    U16                     DeviceID;                   /* 0x00 */
+    U16                     VendorID;                   /* 0x02 */
+    U16                     DeviceIDMask;               /* 0x04 */
+    U16                     Reserved1;                  /* 0x06 */
+    U8                      LowPCIRev;                  /* 0x08 */
+    U8                      HighPCIRev;                 /* 0x09 */
+    U16                     Reserved2;                  /* 0x0A */
+    U32                     Reserved3;                  /* 0x0C */
+} MPI2_SUPPORTED_DEVICE, MPI2_POINTER PTR_MPI2_SUPPORTED_DEVICE,
+  Mpi2SupportedDevice_t, MPI2_POINTER pMpi2SupportedDevice_t;
+
+typedef struct _MPI2_SUPPORTED_DEVICES_DATA
+{
+    U8                      ImageRevision;              /* 0x00 */
+    U8                      Reserved1;                  /* 0x01 */
+    U8                      NumberOfDevices;            /* 0x02 */
+    U8                      Reserved2;                  /* 0x03 */
+    U32                     Reserved3;                  /* 0x04 */
+    MPI2_SUPPORTED_DEVICE   SupportedDevice[MPI2_SUPPORTED_DEVICES_IMAGE_NUM_DEVICES]; /* 0x08 */
+} MPI2_SUPPORTED_DEVICES_DATA, MPI2_POINTER PTR_MPI2_SUPPORTED_DEVICES_DATA,
+  Mpi2SupportedDevicesData_t, MPI2_POINTER pMpi2SupportedDevicesData_t;
+
+/* ImageRevision */
+#define MPI2_SUPPORTED_DEVICES_IMAGE_REVISION   (0x00)
+
+
+/* Init Extended Image Data */
+
+typedef struct _MPI2_INIT_IMAGE_FOOTER
+
+{
+    U32                     BootFlags;                  /* 0x00 */
+    U32                     ImageSize;                  /* 0x04 */
+    U32                     Signature0;                 /* 0x08 */
+    U32                     Signature1;                 /* 0x0C */
+    U32                     Signature2;                 /* 0x10 */
+    U32                     ResetVector;                /* 0x14 */
+} MPI2_INIT_IMAGE_FOOTER, MPI2_POINTER PTR_MPI2_INIT_IMAGE_FOOTER,
+  Mpi2InitImageFooter_t, MPI2_POINTER pMpi2InitImageFooter_t;
+
+/* defines for the BootFlags field */
+#define MPI2_INIT_IMAGE_BOOTFLAGS_OFFSET        (0x00)
+
+/* defines for the ImageSize field */
+#define MPI2_INIT_IMAGE_IMAGESIZE_OFFSET        (0x04)
+
+/* defines for the Signature0 field */
+#define MPI2_INIT_IMAGE_SIGNATURE0_OFFSET       (0x08)
+#define MPI2_INIT_IMAGE_SIGNATURE0              (0x5AA55AEA)
+
+/* defines for the Signature1 field */
+#define MPI2_INIT_IMAGE_SIGNATURE1_OFFSET       (0x0C)
+#define MPI2_INIT_IMAGE_SIGNATURE1              (0xA55AEAA5)
+
+/* defines for the Signature2 field */
+#define MPI2_INIT_IMAGE_SIGNATURE2_OFFSET       (0x10)
+#define MPI2_INIT_IMAGE_SIGNATURE2              (0x5AEAA55A)
+
+/* Signature fields as individual bytes */
+#define MPI2_INIT_IMAGE_SIGNATURE_BYTE_0        (0xEA)
+#define MPI2_INIT_IMAGE_SIGNATURE_BYTE_1        (0x5A)
+#define MPI2_INIT_IMAGE_SIGNATURE_BYTE_2        (0xA5)
+#define MPI2_INIT_IMAGE_SIGNATURE_BYTE_3        (0x5A)
+
+#define MPI2_INIT_IMAGE_SIGNATURE_BYTE_4        (0xA5)
+#define MPI2_INIT_IMAGE_SIGNATURE_BYTE_5        (0xEA)
+#define MPI2_INIT_IMAGE_SIGNATURE_BYTE_6        (0x5A)
+#define MPI2_INIT_IMAGE_SIGNATURE_BYTE_7        (0xA5)
+
+#define MPI2_INIT_IMAGE_SIGNATURE_BYTE_8        (0x5A)
+#define MPI2_INIT_IMAGE_SIGNATURE_BYTE_9        (0xA5)
+#define MPI2_INIT_IMAGE_SIGNATURE_BYTE_A        (0xEA)
+#define MPI2_INIT_IMAGE_SIGNATURE_BYTE_B        (0x5A)
+
+/* defines for the ResetVector field */
+#define MPI2_INIT_IMAGE_RESETVECTOR_OFFSET      (0x14)
+
+
+#endif
+
diff --git a/drivers/scsi/mpt2sas/mpi/mpi2_raid.h b/drivers/scsi/mpt2sas/mpi/mpi2_raid.h
new file mode 100644 (file)
index 0000000..7134816
--- /dev/null
@@ -0,0 +1,295 @@
+/*
+ *  Copyright (c) 2000-2008 LSI Corporation.
+ *
+ *
+ *           Name:  mpi2_raid.h
+ *          Title:  MPI Integrated RAID messages and structures
+ *  Creation Date:  April 26, 2007
+ *
+ *    mpi2_raid.h Version:  02.00.03
+ *
+ *  Version History
+ *  ---------------
+ *
+ *  Date      Version   Description
+ *  --------  --------  ------------------------------------------------------
+ *  04-30-07  02.00.00  Corresponds to Fusion-MPT MPI Specification Rev A.
+ *  08-31-07  02.00.01  Modifications to RAID Action request and reply,
+ *                      including the Actions and ActionData.
+ *  02-29-08  02.00.02  Added MPI2_RAID_ACTION_ADATA_DISABL_FULL_REBUILD.
+ *  05-21-08  02.00.03  Added MPI2_RAID_VOL_CREATION_NUM_PHYSDISKS so that
+ *                      the PhysDisk array in MPI2_RAID_VOLUME_CREATION_STRUCT
+ *                      can be sized by the build environment.
+ *  --------------------------------------------------------------------------
+ */
+
+#ifndef MPI2_RAID_H
+#define MPI2_RAID_H
+
+/*****************************************************************************
+*
+*               Integrated RAID Messages
+*
+*****************************************************************************/
+
+/****************************************************************************
+*  RAID Action messages
+****************************************************************************/
+
+/* ActionDataWord defines for use with MPI2_RAID_ACTION_DELETE_VOLUME action */
+#define MPI2_RAID_ACTION_ADATA_KEEP_LBA0            (0x00000000)
+#define MPI2_RAID_ACTION_ADATA_ZERO_LBA0            (0x00000001)
+
+/* use MPI2_RAIDVOL0_SETTING_ defines from mpi2_cnfg.h for MPI2_RAID_ACTION_CHANGE_VOL_WRITE_CACHE action */
+
+/* ActionDataWord defines for use with MPI2_RAID_ACTION_DISABLE_ALL_VOLUMES action */
+#define MPI2_RAID_ACTION_ADATA_DISABL_FULL_REBUILD  (0x00000001)
+
+/* ActionDataWord for MPI2_RAID_ACTION_SET_RAID_FUNCTION_RATE Action */
+typedef struct _MPI2_RAID_ACTION_RATE_DATA
+{
+    U8              RateToChange;               /* 0x00 */
+    U8              RateOrMode;                 /* 0x01 */
+    U16             DataScrubDuration;          /* 0x02 */
+} MPI2_RAID_ACTION_RATE_DATA, MPI2_POINTER PTR_MPI2_RAID_ACTION_RATE_DATA,
+  Mpi2RaidActionRateData_t, MPI2_POINTER pMpi2RaidActionRateData_t;
+
+#define MPI2_RAID_ACTION_SET_RATE_RESYNC            (0x00)
+#define MPI2_RAID_ACTION_SET_RATE_DATA_SCRUB        (0x01)
+#define MPI2_RAID_ACTION_SET_RATE_POWERSAVE_MODE    (0x02)
+
+/* ActionDataWord for MPI2_RAID_ACTION_START_RAID_FUNCTION Action */
+typedef struct _MPI2_RAID_ACTION_START_RAID_FUNCTION
+{
+    U8              RAIDFunction;                       /* 0x00 */
+    U8              Flags;                              /* 0x01 */
+    U16             Reserved1;                          /* 0x02 */
+} MPI2_RAID_ACTION_START_RAID_FUNCTION,
+  MPI2_POINTER PTR_MPI2_RAID_ACTION_START_RAID_FUNCTION,
+  Mpi2RaidActionStartRaidFunction_t,
+  MPI2_POINTER pMpi2RaidActionStartRaidFunction_t;
+
+/* defines for the RAIDFunction field */
+#define MPI2_RAID_ACTION_START_BACKGROUND_INIT      (0x00)
+#define MPI2_RAID_ACTION_START_ONLINE_CAP_EXPANSION (0x01)
+#define MPI2_RAID_ACTION_START_CONSISTENCY_CHECK    (0x02)
+
+/* defines for the Flags field */
+#define MPI2_RAID_ACTION_START_NEW                  (0x00)
+#define MPI2_RAID_ACTION_START_RESUME               (0x01)
+
+/* ActionDataWord for MPI2_RAID_ACTION_STOP_RAID_FUNCTION Action */
+typedef struct _MPI2_RAID_ACTION_STOP_RAID_FUNCTION
+{
+    U8              RAIDFunction;                       /* 0x00 */
+    U8              Flags;                              /* 0x01 */
+    U16             Reserved1;                          /* 0x02 */
+} MPI2_RAID_ACTION_STOP_RAID_FUNCTION,
+  MPI2_POINTER PTR_MPI2_RAID_ACTION_STOP_RAID_FUNCTION,
+  Mpi2RaidActionStopRaidFunction_t,
+  MPI2_POINTER pMpi2RaidActionStopRaidFunction_t;
+
+/* defines for the RAIDFunction field */
+#define MPI2_RAID_ACTION_STOP_BACKGROUND_INIT       (0x00)
+#define MPI2_RAID_ACTION_STOP_ONLINE_CAP_EXPANSION  (0x01)
+#define MPI2_RAID_ACTION_STOP_CONSISTENCY_CHECK     (0x02)
+
+/* defines for the Flags field */
+#define MPI2_RAID_ACTION_STOP_ABORT                 (0x00)
+#define MPI2_RAID_ACTION_STOP_PAUSE                 (0x01)
+
+/* ActionDataWord for MPI2_RAID_ACTION_CREATE_HOT_SPARE Action */
+typedef struct _MPI2_RAID_ACTION_HOT_SPARE
+{
+    U8              HotSparePool;               /* 0x00 */
+    U8              Reserved1;                  /* 0x01 */
+    U16             DevHandle;                  /* 0x02 */
+} MPI2_RAID_ACTION_HOT_SPARE, MPI2_POINTER PTR_MPI2_RAID_ACTION_HOT_SPARE,
+  Mpi2RaidActionHotSpare_t, MPI2_POINTER pMpi2RaidActionHotSpare_t;
+
+/* ActionDataWord for MPI2_RAID_ACTION_DEVICE_FW_UPDATE_MODE Action */
+typedef struct _MPI2_RAID_ACTION_FW_UPDATE_MODE
+{
+    U8              Flags;                              /* 0x00 */
+    U8              DeviceFirmwareUpdateModeTimeout;    /* 0x01 */
+    U16             Reserved1;                          /* 0x02 */
+} MPI2_RAID_ACTION_FW_UPDATE_MODE,
+  MPI2_POINTER PTR_MPI2_RAID_ACTION_FW_UPDATE_MODE,
+  Mpi2RaidActionFwUpdateMode_t, MPI2_POINTER pMpi2RaidActionFwUpdateMode_t;
+
+/* ActionDataWord defines for use with MPI2_RAID_ACTION_DEVICE_FW_UPDATE_MODE action */
+#define MPI2_RAID_ACTION_ADATA_DISABLE_FW_UPDATE        (0x00)
+#define MPI2_RAID_ACTION_ADATA_ENABLE_FW_UPDATE         (0x01)
+
+typedef union _MPI2_RAID_ACTION_DATA
+{
+    U32                                     Word;
+    MPI2_RAID_ACTION_RATE_DATA              Rates;
+    MPI2_RAID_ACTION_START_RAID_FUNCTION    StartRaidFunction;
+    MPI2_RAID_ACTION_STOP_RAID_FUNCTION     StopRaidFunction;
+    MPI2_RAID_ACTION_HOT_SPARE              HotSpare;
+    MPI2_RAID_ACTION_FW_UPDATE_MODE         FwUpdateMode;
+} MPI2_RAID_ACTION_DATA, MPI2_POINTER PTR_MPI2_RAID_ACTION_DATA,
+  Mpi2RaidActionData_t, MPI2_POINTER pMpi2RaidActionData_t;
+
+
+/* RAID Action Request Message */
+typedef struct _MPI2_RAID_ACTION_REQUEST
+{
+    U8                      Action;                         /* 0x00 */
+    U8                      Reserved1;                      /* 0x01 */
+    U8                      ChainOffset;                    /* 0x02 */
+    U8                      Function;                       /* 0x03 */
+    U16                     VolDevHandle;                   /* 0x04 */
+    U8                      PhysDiskNum;                    /* 0x06 */
+    U8                      MsgFlags;                       /* 0x07 */
+    U8                      VP_ID;                          /* 0x08 */
+    U8                      VF_ID;                          /* 0x09 */
+    U16                     Reserved2;                      /* 0x0A */
+    U32                     Reserved3;                      /* 0x0C */
+    MPI2_RAID_ACTION_DATA   ActionDataWord;                 /* 0x10 */
+    MPI2_SGE_SIMPLE_UNION   ActionDataSGE;                  /* 0x14 */
+} MPI2_RAID_ACTION_REQUEST, MPI2_POINTER PTR_MPI2_RAID_ACTION_REQUEST,
+  Mpi2RaidActionRequest_t, MPI2_POINTER pMpi2RaidActionRequest_t;
+
+/* RAID Action request Action values */
+
+#define MPI2_RAID_ACTION_INDICATOR_STRUCT           (0x01)
+#define MPI2_RAID_ACTION_CREATE_VOLUME              (0x02)
+#define MPI2_RAID_ACTION_DELETE_VOLUME              (0x03)
+#define MPI2_RAID_ACTION_DISABLE_ALL_VOLUMES        (0x04)
+#define MPI2_RAID_ACTION_ENABLE_ALL_VOLUMES         (0x05)
+#define MPI2_RAID_ACTION_PHYSDISK_OFFLINE           (0x0A)
+#define MPI2_RAID_ACTION_PHYSDISK_ONLINE            (0x0B)
+#define MPI2_RAID_ACTION_FAIL_PHYSDISK              (0x0F)
+#define MPI2_RAID_ACTION_ACTIVATE_VOLUME            (0x11)
+#define MPI2_RAID_ACTION_DEVICE_FW_UPDATE_MODE      (0x15)
+#define MPI2_RAID_ACTION_CHANGE_VOL_WRITE_CACHE     (0x17)
+#define MPI2_RAID_ACTION_SET_VOLUME_NAME            (0x18)
+#define MPI2_RAID_ACTION_SET_RAID_FUNCTION_RATE     (0x19)
+#define MPI2_RAID_ACTION_ENABLE_FAILED_VOLUME       (0x1C)
+#define MPI2_RAID_ACTION_CREATE_HOT_SPARE           (0x1D)
+#define MPI2_RAID_ACTION_DELETE_HOT_SPARE           (0x1E)
+#define MPI2_RAID_ACTION_SYSTEM_SHUTDOWN_INITIATED  (0x20)
+#define MPI2_RAID_ACTION_START_RAID_FUNCTION        (0x21)
+#define MPI2_RAID_ACTION_STOP_RAID_FUNCTION         (0x22)
+
+
+/* RAID Volume Creation Structure */
+
+/*
+ * The following define can be customized for the targeted product.
+ */
+#ifndef MPI2_RAID_VOL_CREATION_NUM_PHYSDISKS
+#define MPI2_RAID_VOL_CREATION_NUM_PHYSDISKS        (1)
+#endif
+
+typedef struct _MPI2_RAID_VOLUME_PHYSDISK
+{
+    U8                      RAIDSetNum;                     /* 0x00 */
+    U8                      PhysDiskMap;                    /* 0x01 */
+    U16                     PhysDiskDevHandle;              /* 0x02 */
+} MPI2_RAID_VOLUME_PHYSDISK, MPI2_POINTER PTR_MPI2_RAID_VOLUME_PHYSDISK,
+  Mpi2RaidVolumePhysDisk_t, MPI2_POINTER pMpi2RaidVolumePhysDisk_t;
+
+/* defines for the PhysDiskMap field */
+#define MPI2_RAIDACTION_PHYSDISK_PRIMARY            (0x01)
+#define MPI2_RAIDACTION_PHYSDISK_SECONDARY          (0x02)
+
+typedef struct _MPI2_RAID_VOLUME_CREATION_STRUCT
+{
+    U8                          NumPhysDisks;               /* 0x00 */
+    U8                          VolumeType;                 /* 0x01 */
+    U16                         Reserved1;                  /* 0x02 */
+    U32                         VolumeCreationFlags;        /* 0x04 */
+    U32                         VolumeSettings;             /* 0x08 */
+    U8                          Reserved2;                  /* 0x0C */
+    U8                          ResyncRate;                 /* 0x0D */
+    U16                         DataScrubDuration;          /* 0x0E */
+    U64                         VolumeMaxLBA;               /* 0x10 */
+    U32                         StripeSize;                 /* 0x18 */
+    U8                          Name[16];                   /* 0x1C */
+    MPI2_RAID_VOLUME_PHYSDISK   PhysDisk[MPI2_RAID_VOL_CREATION_NUM_PHYSDISKS];/* 0x2C */
+} MPI2_RAID_VOLUME_CREATION_STRUCT,
+  MPI2_POINTER PTR_MPI2_RAID_VOLUME_CREATION_STRUCT,
+  Mpi2RaidVolumeCreationStruct_t, MPI2_POINTER pMpi2RaidVolumeCreationStruct_t;
+
+/* use MPI2_RAID_VOL_TYPE_ defines from mpi2_cnfg.h for VolumeType */
+
+/* defines for the VolumeCreationFlags field */
+#define MPI2_RAID_VOL_CREATION_USE_DEFAULT_SETTINGS (0x80)
+#define MPI2_RAID_VOL_CREATION_BACKGROUND_INIT      (0x04)
+#define MPI2_RAID_VOL_CREATION_LOW_LEVEL_INIT       (0x02)
+#define MPI2_RAID_VOL_CREATION_MIGRATE_DATA         (0x01)
+
+
+/* RAID Online Capacity Expansion Structure */
+
+typedef struct _MPI2_RAID_ONLINE_CAPACITY_EXPANSION
+{
+    U32                     Flags;                          /* 0x00 */
+    U16                     DevHandle0;                     /* 0x04 */
+    U16                     Reserved1;                      /* 0x06 */
+    U16                     DevHandle1;                     /* 0x08 */
+    U16                     Reserved2;                      /* 0x0A */
+} MPI2_RAID_ONLINE_CAPACITY_EXPANSION,
+  MPI2_POINTER PTR_MPI2_RAID_ONLINE_CAPACITY_EXPANSION,
+  Mpi2RaidOnlineCapacityExpansion_t,
+  MPI2_POINTER pMpi2RaidOnlineCapacityExpansion_t;
+
+
+/* RAID Volume Indicator Structure */
+
+typedef struct _MPI2_RAID_VOL_INDICATOR
+{
+    U64                     TotalBlocks;                    /* 0x00 */
+    U64                     BlocksRemaining;                /* 0x08 */
+    U32                     Flags;                          /* 0x10 */
+} MPI2_RAID_VOL_INDICATOR, MPI2_POINTER PTR_MPI2_RAID_VOL_INDICATOR,
+  Mpi2RaidVolIndicator_t, MPI2_POINTER pMpi2RaidVolIndicator_t;
+
+/* defines for RAID Volume Indicator Flags field */
+#define MPI2_RAID_VOL_FLAGS_OP_MASK                 (0x0000000F)
+#define MPI2_RAID_VOL_FLAGS_OP_BACKGROUND_INIT      (0x00000000)
+#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)
+
+
+/* RAID Action Reply ActionData union */
+typedef union _MPI2_RAID_ACTION_REPLY_DATA
+{
+    U32                     Word[5];
+    MPI2_RAID_VOL_INDICATOR RaidVolumeIndicator;
+    U16                     VolDevHandle;
+    U8                      VolumeState;
+    U8                      PhysDiskNum;
+} MPI2_RAID_ACTION_REPLY_DATA, MPI2_POINTER PTR_MPI2_RAID_ACTION_REPLY_DATA,
+  Mpi2RaidActionReplyData_t, MPI2_POINTER pMpi2RaidActionReplyData_t;
+
+/* use MPI2_RAIDVOL0_SETTING_ defines from mpi2_cnfg.h for MPI2_RAID_ACTION_CHANGE_VOL_WRITE_CACHE action */
+
+
+/* RAID Action Reply Message */
+typedef struct _MPI2_RAID_ACTION_REPLY
+{
+    U8                          Action;                     /* 0x00 */
+    U8                          Reserved1;                  /* 0x01 */
+    U8                          MsgLength;                  /* 0x02 */
+    U8                          Function;                   /* 0x03 */
+    U16                         VolDevHandle;               /* 0x04 */
+    U8                          PhysDiskNum;                /* 0x06 */
+    U8                          MsgFlags;                   /* 0x07 */
+    U8                          VP_ID;                      /* 0x08 */
+    U8                          VF_ID;                      /* 0x09 */
+    U16                         Reserved2;                  /* 0x0A */
+    U16                         Reserved3;                  /* 0x0C */
+    U16                         IOCStatus;                  /* 0x0E */
+    U32                         IOCLogInfo;                 /* 0x10 */
+    MPI2_RAID_ACTION_REPLY_DATA ActionData;                 /* 0x14 */
+} MPI2_RAID_ACTION_REPLY, MPI2_POINTER PTR_MPI2_RAID_ACTION_REPLY,
+  Mpi2RaidActionReply_t, MPI2_POINTER pMpi2RaidActionReply_t;
+
+
+#endif
+
diff --git a/drivers/scsi/mpt2sas/mpi/mpi2_sas.h b/drivers/scsi/mpt2sas/mpi/mpi2_sas.h
new file mode 100644 (file)
index 0000000..8a42b13
--- /dev/null
@@ -0,0 +1,282 @@
+/*
+ *  Copyright (c) 2000-2007 LSI Corporation.
+ *
+ *
+ *           Name:  mpi2_sas.h
+ *          Title:  MPI Serial Attached SCSI structures and definitions
+ *  Creation Date:  February 9, 2007
+ *
+ *  mpi2.h Version:  02.00.02
+ *
+ *  Version History
+ *  ---------------
+ *
+ *  Date      Version   Description
+ *  --------  --------  ------------------------------------------------------
+ *  04-30-07  02.00.00  Corresponds to Fusion-MPT MPI Specification Rev A.
+ *  06-26-07  02.00.01  Added Clear All Persistent Operation to SAS IO Unit
+ *                      Control Request.
+ *  10-02-08  02.00.02  Added Set IOC Parameter Operation to SAS IO Unit Control
+ *                      Request.
+ *  --------------------------------------------------------------------------
+ */
+
+#ifndef MPI2_SAS_H
+#define MPI2_SAS_H
+
+/*
+ * Values for SASStatus.
+ */
+#define MPI2_SASSTATUS_SUCCESS                          (0x00)
+#define MPI2_SASSTATUS_UNKNOWN_ERROR                    (0x01)
+#define MPI2_SASSTATUS_INVALID_FRAME                    (0x02)
+#define MPI2_SASSTATUS_UTC_BAD_DEST                     (0x03)
+#define MPI2_SASSTATUS_UTC_BREAK_RECEIVED               (0x04)
+#define MPI2_SASSTATUS_UTC_CONNECT_RATE_NOT_SUPPORTED   (0x05)
+#define MPI2_SASSTATUS_UTC_PORT_LAYER_REQUEST           (0x06)
+#define MPI2_SASSTATUS_UTC_PROTOCOL_NOT_SUPPORTED       (0x07)
+#define MPI2_SASSTATUS_UTC_STP_RESOURCES_BUSY           (0x08)
+#define MPI2_SASSTATUS_UTC_WRONG_DESTINATION            (0x09)
+#define MPI2_SASSTATUS_SHORT_INFORMATION_UNIT           (0x0A)
+#define MPI2_SASSTATUS_LONG_INFORMATION_UNIT            (0x0B)
+#define MPI2_SASSTATUS_XFER_RDY_INCORRECT_WRITE_DATA    (0x0C)
+#define MPI2_SASSTATUS_XFER_RDY_REQUEST_OFFSET_ERROR    (0x0D)
+#define MPI2_SASSTATUS_XFER_RDY_NOT_EXPECTED            (0x0E)
+#define MPI2_SASSTATUS_DATA_INCORRECT_DATA_LENGTH       (0x0F)
+#define MPI2_SASSTATUS_DATA_TOO_MUCH_READ_DATA          (0x10)
+#define MPI2_SASSTATUS_DATA_OFFSET_ERROR                (0x11)
+#define MPI2_SASSTATUS_SDSF_NAK_RECEIVED                (0x12)
+#define MPI2_SASSTATUS_SDSF_CONNECTION_FAILED           (0x13)
+#define MPI2_SASSTATUS_INITIATOR_RESPONSE_TIMEOUT       (0x14)
+
+
+/*
+ * Values for the SAS DeviceInfo field used in SAS Device Status Change Event
+ * data and SAS Configuration pages.
+ */
+#define MPI2_SAS_DEVICE_INFO_SEP                (0x00004000)
+#define MPI2_SAS_DEVICE_INFO_ATAPI_DEVICE       (0x00002000)
+#define MPI2_SAS_DEVICE_INFO_LSI_DEVICE         (0x00001000)
+#define MPI2_SAS_DEVICE_INFO_DIRECT_ATTACH      (0x00000800)
+#define MPI2_SAS_DEVICE_INFO_SSP_TARGET         (0x00000400)
+#define MPI2_SAS_DEVICE_INFO_STP_TARGET         (0x00000200)
+#define MPI2_SAS_DEVICE_INFO_SMP_TARGET         (0x00000100)
+#define MPI2_SAS_DEVICE_INFO_SATA_DEVICE        (0x00000080)
+#define MPI2_SAS_DEVICE_INFO_SSP_INITIATOR      (0x00000040)
+#define MPI2_SAS_DEVICE_INFO_STP_INITIATOR      (0x00000020)
+#define MPI2_SAS_DEVICE_INFO_SMP_INITIATOR      (0x00000010)
+#define MPI2_SAS_DEVICE_INFO_SATA_HOST          (0x00000008)
+
+#define MPI2_SAS_DEVICE_INFO_MASK_DEVICE_TYPE   (0x00000007)
+#define MPI2_SAS_DEVICE_INFO_NO_DEVICE          (0x00000000)
+#define MPI2_SAS_DEVICE_INFO_END_DEVICE         (0x00000001)
+#define MPI2_SAS_DEVICE_INFO_EDGE_EXPANDER      (0x00000002)
+#define MPI2_SAS_DEVICE_INFO_FANOUT_EXPANDER    (0x00000003)
+
+
+/*****************************************************************************
+*
+*        SAS Messages
+*
+*****************************************************************************/
+
+/****************************************************************************
+*  SMP Passthrough messages
+****************************************************************************/
+
+/* SMP Passthrough Request Message */
+typedef struct _MPI2_SMP_PASSTHROUGH_REQUEST
+{
+    U8                      PassthroughFlags;   /* 0x00 */
+    U8                      PhysicalPort;       /* 0x01 */
+    U8                      ChainOffset;        /* 0x02 */
+    U8                      Function;           /* 0x03 */
+    U16                     RequestDataLength;  /* 0x04 */
+    U8                      SGLFlags;           /* 0x06 */
+    U8                      MsgFlags;           /* 0x07 */
+    U8                      VP_ID;              /* 0x08 */
+    U8                      VF_ID;              /* 0x09 */
+    U16                     Reserved1;          /* 0x0A */
+    U32                     Reserved2;          /* 0x0C */
+    U64                     SASAddress;         /* 0x10 */
+    U32                     Reserved3;          /* 0x18 */
+    U32                     Reserved4;          /* 0x1C */
+    MPI2_SIMPLE_SGE_UNION   SGL;                /* 0x20 */
+} MPI2_SMP_PASSTHROUGH_REQUEST, MPI2_POINTER PTR_MPI2_SMP_PASSTHROUGH_REQUEST,
+  Mpi2SmpPassthroughRequest_t, MPI2_POINTER pMpi2SmpPassthroughRequest_t;
+
+/* 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 */
+
+
+/* SMP Passthrough Reply Message */
+typedef struct _MPI2_SMP_PASSTHROUGH_REPLY
+{
+    U8                      PassthroughFlags;   /* 0x00 */
+    U8                      PhysicalPort;       /* 0x01 */
+    U8                      MsgLength;          /* 0x02 */
+    U8                      Function;           /* 0x03 */
+    U16                     ResponseDataLength; /* 0x04 */
+    U8                      SGLFlags;           /* 0x06 */
+    U8                      MsgFlags;           /* 0x07 */
+    U8                      VP_ID;              /* 0x08 */
+    U8                      VF_ID;              /* 0x09 */
+    U16                     Reserved1;          /* 0x0A */
+    U8                      Reserved2;          /* 0x0C */
+    U8                      SASStatus;          /* 0x0D */
+    U16                     IOCStatus;          /* 0x0E */
+    U32                     IOCLogInfo;         /* 0x10 */
+    U32                     Reserved3;          /* 0x14 */
+    U8                      ResponseData[4];    /* 0x18 */
+} MPI2_SMP_PASSTHROUGH_REPLY, MPI2_POINTER PTR_MPI2_SMP_PASSTHROUGH_REPLY,
+  Mpi2SmpPassthroughReply_t, MPI2_POINTER pMpi2SmpPassthroughReply_t;
+
+/* values for PassthroughFlags field */
+#define MPI2_SMP_PT_REPLY_PT_FLAGS_IMMEDIATE    (0x80)
+
+/* values for SASStatus field are at the top of this file */
+
+
+/****************************************************************************
+*  SATA Passthrough messages
+****************************************************************************/
+
+/* SATA Passthrough Request Message */
+typedef struct _MPI2_SATA_PASSTHROUGH_REQUEST
+{
+    U16                     DevHandle;          /* 0x00 */
+    U8                      ChainOffset;        /* 0x02 */
+    U8                      Function;           /* 0x03 */
+    U16                     PassthroughFlags;   /* 0x04 */
+    U8                      SGLFlags;           /* 0x06 */
+    U8                      MsgFlags;           /* 0x07 */
+    U8                      VP_ID;              /* 0x08 */
+    U8                      VF_ID;              /* 0x09 */
+    U16                     Reserved1;          /* 0x0A */
+    U32                     Reserved2;          /* 0x0C */
+    U32                     Reserved3;          /* 0x10 */
+    U32                     Reserved4;          /* 0x14 */
+    U32                     DataLength;         /* 0x18 */
+    U8                      CommandFIS[20];     /* 0x1C */
+    MPI2_SIMPLE_SGE_UNION   SGL;                /* 0x20 */
+} MPI2_SATA_PASSTHROUGH_REQUEST, MPI2_POINTER PTR_MPI2_SATA_PASSTHROUGH_REQUEST,
+  Mpi2SataPassthroughRequest_t, MPI2_POINTER pMpi2SataPassthroughRequest_t;
+
+/* values for PassthroughFlags field */
+#define MPI2_SATA_PT_REQ_PT_FLAGS_EXECUTE_DIAG      (0x0100)
+#define MPI2_SATA_PT_REQ_PT_FLAGS_DMA               (0x0020)
+#define MPI2_SATA_PT_REQ_PT_FLAGS_PIO               (0x0010)
+#define MPI2_SATA_PT_REQ_PT_FLAGS_UNSPECIFIED_VU    (0x0004)
+#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 */
+
+
+/* SATA Passthrough Reply Message */
+typedef struct _MPI2_SATA_PASSTHROUGH_REPLY
+{
+    U16                     DevHandle;          /* 0x00 */
+    U8                      MsgLength;          /* 0x02 */
+    U8                      Function;           /* 0x03 */
+    U16                     PassthroughFlags;   /* 0x04 */
+    U8                      SGLFlags;           /* 0x06 */
+    U8                      MsgFlags;           /* 0x07 */
+    U8                      VP_ID;              /* 0x08 */
+    U8                      VF_ID;              /* 0x09 */
+    U16                     Reserved1;          /* 0x0A */
+    U8                      Reserved2;          /* 0x0C */
+    U8                      SASStatus;          /* 0x0D */
+    U16                     IOCStatus;          /* 0x0E */
+    U32                     IOCLogInfo;         /* 0x10 */
+    U8                      StatusFIS[20];      /* 0x14 */
+    U32                     StatusControlRegisters; /* 0x28 */
+    U32                     TransferCount;      /* 0x2C */
+} MPI2_SATA_PASSTHROUGH_REPLY, MPI2_POINTER PTR_MPI2_SATA_PASSTHROUGH_REPLY,
+  Mpi2SataPassthroughReply_t, MPI2_POINTER pMpi2SataPassthroughReply_t;
+
+/* values for SASStatus field are at the top of this file */
+
+
+/****************************************************************************
+*  SAS IO Unit Control messages
+****************************************************************************/
+
+/* SAS IO Unit Control Request Message */
+typedef struct _MPI2_SAS_IOUNIT_CONTROL_REQUEST
+{
+    U8                      Operation;          /* 0x00 */
+    U8                      Reserved1;          /* 0x01 */
+    U8                      ChainOffset;        /* 0x02 */
+    U8                      Function;           /* 0x03 */
+    U16                     DevHandle;          /* 0x04 */
+    U8                      IOCParameter;       /* 0x06 */
+    U8                      MsgFlags;           /* 0x07 */
+    U8                      VP_ID;              /* 0x08 */
+    U8                      VF_ID;              /* 0x09 */
+    U16                     Reserved3;          /* 0x0A */
+    U16                     Reserved4;          /* 0x0C */
+    U8                      PhyNum;             /* 0x0E */
+    U8                      PrimFlags;          /* 0x0F */
+    U32                     Primitive;          /* 0x10 */
+    U8                      LookupMethod;       /* 0x14 */
+    U8                      Reserved5;          /* 0x15 */
+    U16                     SlotNumber;         /* 0x16 */
+    U64                     LookupAddress;      /* 0x18 */
+    U32                     IOCParameterValue;  /* 0x20 */
+    U32                     Reserved7;          /* 0x24 */
+    U32                     Reserved8;          /* 0x28 */
+} MPI2_SAS_IOUNIT_CONTROL_REQUEST,
+  MPI2_POINTER PTR_MPI2_SAS_IOUNIT_CONTROL_REQUEST,
+  Mpi2SasIoUnitControlRequest_t, MPI2_POINTER pMpi2SasIoUnitControlRequest_t;
+
+/* values for the Operation field */
+#define MPI2_SAS_OP_CLEAR_ALL_PERSISTENT        (0x02)
+#define MPI2_SAS_OP_PHY_LINK_RESET              (0x06)
+#define MPI2_SAS_OP_PHY_HARD_RESET              (0x07)
+#define MPI2_SAS_OP_PHY_CLEAR_ERROR_LOG         (0x08)
+#define MPI2_SAS_OP_SEND_PRIMITIVE              (0x0A)
+#define MPI2_SAS_OP_FORCE_FULL_DISCOVERY        (0x0B)
+#define MPI2_SAS_OP_TRANSMIT_PORT_SELECT_SIGNAL (0x0C)
+#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_PRODUCT_SPECIFIC_MIN        (0x80)
+
+/* values for the PrimFlags field */
+#define MPI2_SAS_PRIMFLAGS_SINGLE               (0x08)
+#define MPI2_SAS_PRIMFLAGS_TRIPLE               (0x02)
+#define MPI2_SAS_PRIMFLAGS_REDUNDANT            (0x01)
+
+/* values for the LookupMethod field */
+#define MPI2_SAS_LOOKUP_METHOD_SAS_ADDRESS          (0x01)
+#define MPI2_SAS_LOOKUP_METHOD_SAS_ENCLOSURE_SLOT   (0x02)
+#define MPI2_SAS_LOOKUP_METHOD_SAS_DEVICE_NAME      (0x03)
+
+
+/* SAS IO Unit Control Reply Message */
+typedef struct _MPI2_SAS_IOUNIT_CONTROL_REPLY
+{
+    U8                      Operation;          /* 0x00 */
+    U8                      Reserved1;          /* 0x01 */
+    U8                      MsgLength;          /* 0x02 */
+    U8                      Function;           /* 0x03 */
+    U16                     DevHandle;          /* 0x04 */
+    U8                      IOCParameter;       /* 0x06 */
+    U8                      MsgFlags;           /* 0x07 */
+    U8                      VP_ID;              /* 0x08 */
+    U8                      VF_ID;              /* 0x09 */
+    U16                     Reserved3;          /* 0x0A */
+    U16                     Reserved4;          /* 0x0C */
+    U16                     IOCStatus;          /* 0x0E */
+    U32                     IOCLogInfo;         /* 0x10 */
+} MPI2_SAS_IOUNIT_CONTROL_REPLY,
+  MPI2_POINTER PTR_MPI2_SAS_IOUNIT_CONTROL_REPLY,
+  Mpi2SasIoUnitControlReply_t, MPI2_POINTER pMpi2SasIoUnitControlReply_t;
+
+
+#endif
+
+
diff --git a/drivers/scsi/mpt2sas/mpi/mpi2_tool.h b/drivers/scsi/mpt2sas/mpi/mpi2_tool.h
new file mode 100644 (file)
index 0000000..2ff4e93
--- /dev/null
@@ -0,0 +1,249 @@
+/*
+ *  Copyright (c) 2000-2008 LSI Corporation.
+ *
+ *
+ *           Name:  mpi2_tool.h
+ *          Title:  MPI diagnostic tool structures and definitions
+ *  Creation Date:  March 26, 2007
+ *
+ *    mpi2_tool.h Version:  02.00.02
+ *
+ *  Version History
+ *  ---------------
+ *
+ *  Date      Version   Description
+ *  --------  --------  ------------------------------------------------------
+ *  04-30-07  02.00.00  Corresponds to Fusion-MPT MPI Specification Rev A.
+ *  12-18-07  02.00.01  Added Diagnostic Buffer Post and Diagnostic Release
+ *                      structures and defines.
+ *  02-29-08  02.00.02  Modified various names to make them 32-character unique.
+ *  --------------------------------------------------------------------------
+ */
+
+#ifndef MPI2_TOOL_H
+#define MPI2_TOOL_H
+
+/*****************************************************************************
+*
+*               Toolbox Messages
+*
+*****************************************************************************/
+
+/* defines for the Tools */
+#define MPI2_TOOLBOX_CLEAN_TOOL                     (0x00)
+#define MPI2_TOOLBOX_MEMORY_MOVE_TOOL               (0x01)
+#define MPI2_TOOLBOX_BEACON_TOOL                    (0x05)
+
+/****************************************************************************
+*  Toolbox reply
+****************************************************************************/
+
+typedef struct _MPI2_TOOLBOX_REPLY
+{
+    U8                      Tool;                       /* 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_TOOLBOX_REPLY, MPI2_POINTER PTR_MPI2_TOOLBOX_REPLY,
+  Mpi2ToolboxReply_t, MPI2_POINTER pMpi2ToolboxReply_t;
+
+
+/****************************************************************************
+*  Toolbox Clean Tool request
+****************************************************************************/
+
+typedef struct _MPI2_TOOLBOX_CLEAN_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 */
+    U32                     Flags;                      /* 0x0C */
+   } MPI2_TOOLBOX_CLEAN_REQUEST, MPI2_POINTER PTR_MPI2_TOOLBOX_CLEAN_REQUEST,
+  Mpi2ToolboxCleanRequest_t, MPI2_POINTER pMpi2ToolboxCleanRequest_t;
+
+/* values for the Flags field */
+#define MPI2_TOOLBOX_CLEAN_BOOT_SERVICES            (0x80000000)
+#define MPI2_TOOLBOX_CLEAN_PERSIST_MANUFACT_PAGES   (0x40000000)
+#define MPI2_TOOLBOX_CLEAN_OTHER_PERSIST_PAGES      (0x20000000)
+#define MPI2_TOOLBOX_CLEAN_FW_CURRENT               (0x10000000)
+#define MPI2_TOOLBOX_CLEAN_FW_BACKUP                (0x08000000)
+#define MPI2_TOOLBOX_CLEAN_MEGARAID                 (0x02000000)
+#define MPI2_TOOLBOX_CLEAN_INITIALIZATION           (0x01000000)
+#define MPI2_TOOLBOX_CLEAN_FLASH                    (0x00000004)
+#define MPI2_TOOLBOX_CLEAN_SEEPROM                  (0x00000002)
+#define MPI2_TOOLBOX_CLEAN_NVSRAM                   (0x00000001)
+
+
+/****************************************************************************
+*  Toolbox Memory Move request
+****************************************************************************/
+
+typedef struct _MPI2_TOOLBOX_MEM_MOVE_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 */
+    MPI2_SGE_SIMPLE_UNION   SGL;                        /* 0x0C */
+} MPI2_TOOLBOX_MEM_MOVE_REQUEST, MPI2_POINTER PTR_MPI2_TOOLBOX_MEM_MOVE_REQUEST,
+  Mpi2ToolboxMemMoveRequest_t, MPI2_POINTER pMpi2ToolboxMemMoveRequest_t;
+
+
+/****************************************************************************
+*  Toolbox Beacon Tool request
+****************************************************************************/
+
+typedef struct _MPI2_TOOLBOX_BEACON_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                      Reserved5;                  /* 0x0C */
+    U8                      PhysicalPort;               /* 0x0D */
+    U8                      Reserved6;                  /* 0x0E */
+    U8                      Flags;                      /* 0x0F */
+} MPI2_TOOLBOX_BEACON_REQUEST, MPI2_POINTER PTR_MPI2_TOOLBOX_BEACON_REQUEST,
+  Mpi2ToolboxBeaconRequest_t, MPI2_POINTER pMpi2ToolboxBeaconRequest_t;
+
+/* values for the Flags field */
+#define MPI2_TOOLBOX_FLAGS_BEACONMODE_OFF       (0x00)
+#define MPI2_TOOLBOX_FLAGS_BEACONMODE_ON        (0x01)
+
+
+/*****************************************************************************
+*
+*       Diagnostic Buffer Messages
+*
+*****************************************************************************/
+
+
+/****************************************************************************
+*  Diagnostic Buffer Post request
+****************************************************************************/
+
+typedef struct _MPI2_DIAG_BUFFER_POST_REQUEST
+{
+    U8                      Reserved1;                  /* 0x00 */
+    U8                      BufferType;                 /* 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 */
+    U64                     BufferAddress;              /* 0x0C */
+    U32                     BufferLength;               /* 0x14 */
+    U32                     Reserved5;                  /* 0x18 */
+    U32                     Reserved6;                  /* 0x1C */
+    U32                     Flags;                      /* 0x20 */
+    U32                     ProductSpecific[23];        /* 0x24 */
+} MPI2_DIAG_BUFFER_POST_REQUEST, MPI2_POINTER PTR_MPI2_DIAG_BUFFER_POST_REQUEST,
+  Mpi2DiagBufferPostRequest_t, MPI2_POINTER pMpi2DiagBufferPostRequest_t;
+
+/* values for the BufferType field */
+#define MPI2_DIAG_BUF_TYPE_TRACE                    (0x00)
+#define MPI2_DIAG_BUF_TYPE_SNAPSHOT                 (0x01)
+/* count of the number of buffer types */
+#define MPI2_DIAG_BUF_TYPE_COUNT                    (0x02)
+
+
+/****************************************************************************
+*  Diagnostic Buffer Post reply
+****************************************************************************/
+
+typedef struct _MPI2_DIAG_BUFFER_POST_REPLY
+{
+    U8                      Reserved1;                  /* 0x00 */
+    U8                      BufferType;                 /* 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 */
+    U32                     TransferLength;             /* 0x14 */
+} MPI2_DIAG_BUFFER_POST_REPLY, MPI2_POINTER PTR_MPI2_DIAG_BUFFER_POST_REPLY,
+  Mpi2DiagBufferPostReply_t, MPI2_POINTER pMpi2DiagBufferPostReply_t;
+
+
+/****************************************************************************
+*  Diagnostic Release request
+****************************************************************************/
+
+typedef struct _MPI2_DIAG_RELEASE_REQUEST
+{
+    U8                      Reserved1;                  /* 0x00 */
+    U8                      BufferType;                 /* 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 */
+} MPI2_DIAG_RELEASE_REQUEST, MPI2_POINTER PTR_MPI2_DIAG_RELEASE_REQUEST,
+  Mpi2DiagReleaseRequest_t, MPI2_POINTER pMpi2DiagReleaseRequest_t;
+
+
+/****************************************************************************
+*  Diagnostic Buffer Post reply
+****************************************************************************/
+
+typedef struct _MPI2_DIAG_RELEASE_REPLY
+{
+    U8                      Reserved1;                  /* 0x00 */
+    U8                      BufferType;                 /* 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_DIAG_RELEASE_REPLY, MPI2_POINTER PTR_MPI2_DIAG_RELEASE_REPLY,
+  Mpi2DiagReleaseReply_t, MPI2_POINTER pMpi2DiagReleaseReply_t;
+
+
+#endif
+
diff --git a/drivers/scsi/mpt2sas/mpi/mpi2_type.h b/drivers/scsi/mpt2sas/mpi/mpi2_type.h
new file mode 100644 (file)
index 0000000..cfde017
--- /dev/null
@@ -0,0 +1,61 @@
+/*
+ *  Copyright (c) 2000-2007 LSI Corporation.
+ *
+ *
+ *           Name:  mpi2_type.h
+ *          Title:  MPI basic type definitions
+ *  Creation Date:  August 16, 2006
+ *
+ *    mpi2_type.h Version:  02.00.00
+ *
+ *  Version History
+ *  ---------------
+ *
+ *  Date      Version   Description
+ *  --------  --------  ------------------------------------------------------
+ *  04-30-07  02.00.00  Corresponds to Fusion-MPT MPI Specification Rev A.
+ *  --------------------------------------------------------------------------
+ */
+
+#ifndef MPI2_TYPE_H
+#define MPI2_TYPE_H
+
+
+/*******************************************************************************
+ * Define MPI2_POINTER if it hasn't already been defined. By default
+ * MPI2_POINTER is defined to be a near pointer. MPI2_POINTER can be defined as
+ * a far pointer by defining MPI2_POINTER as "far *" before this header file is
+ * included.
+ */
+#ifndef MPI2_POINTER
+#define MPI2_POINTER     *
+#endif
+
+/* the basic types may have already been included by mpi_type.h */
+#ifndef MPI_TYPE_H
+/*****************************************************************************
+*
+*               Basic Types
+*
+*****************************************************************************/
+
+typedef u8 U8;
+typedef __le16 U16;
+typedef __le32 U32;
+typedef __le64 U64 __attribute__((aligned(4)));
+
+/*****************************************************************************
+*
+*               Pointer Types
+*
+*****************************************************************************/
+
+typedef U8      *PU8;
+typedef U16     *PU16;
+typedef U32     *PU32;
+typedef U64     *PU64;
+
+#endif
+
+#endif
+
diff --git a/drivers/scsi/mpt2sas/mpt2sas_base.c b/drivers/scsi/mpt2sas/mpt2sas_base.c
new file mode 100644 (file)
index 0000000..52427a8
--- /dev/null
@@ -0,0 +1,3435 @@
+/*
+ * This is the Fusion MPT base driver providing common API layer interface
+ * for access to MPT (Message Passing Technology) firmware.
+ *
+ * This code is based on drivers/scsi/mpt2sas/mpt2_base.c
+ * Copyright (C) 2007-2008  LSI Corporation
+ *  (mailto:DL-MPTFusionLinux@lsi.com)
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * NO WARRANTY
+ * THE PROGRAM IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OR
+ * CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED INCLUDING, WITHOUT
+ * LIMITATION, ANY WARRANTIES OR CONDITIONS OF TITLE, NON-INFRINGEMENT,
+ * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. Each Recipient is
+ * solely responsible for determining the appropriateness of using and
+ * distributing the Program and assumes all risks associated with its
+ * exercise of rights under this Agreement, including but not limited to
+ * the risks and costs of program errors, damage to or loss of data,
+ * programs or equipment, and unavailability or interruption of operations.
+
+ * DISCLAIMER OF LIABILITY
+ * NEITHER RECIPIENT NOR ANY CONTRIBUTORS SHALL HAVE ANY LIABILITY FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING WITHOUT LIMITATION LOST PROFITS), 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 OR DISTRIBUTION OF THE PROGRAM OR THE EXERCISE OF ANY RIGHTS GRANTED
+ * HEREUNDER, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGES
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301,
+ * USA.
+ */
+
+#include <linux/version.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/errno.h>
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <linux/types.h>
+#include <linux/pci.h>
+#include <linux/kdev_t.h>
+#include <linux/blkdev.h>
+#include <linux/delay.h>
+#include <linux/interrupt.h>
+#include <linux/dma-mapping.h>
+#include <linux/sort.h>
+#include <linux/io.h>
+
+#include "mpt2sas_base.h"
+
+static MPT_CALLBACK    mpt_callbacks[MPT_MAX_CALLBACKS];
+
+#define FAULT_POLLING_INTERVAL 1000 /* in milliseconds */
+#define MPT2SAS_MAX_REQUEST_QUEUE 500 /* maximum controller queue depth */
+
+static int max_queue_depth = -1;
+module_param(max_queue_depth, int, 0);
+MODULE_PARM_DESC(max_queue_depth, " max controller queue depth ");
+
+static int max_sgl_entries = -1;
+module_param(max_sgl_entries, int, 0);
+MODULE_PARM_DESC(max_sgl_entries, " max sg entries ");
+
+static int msix_disable = -1;
+module_param(msix_disable, int, 0);
+MODULE_PARM_DESC(msix_disable, " disable msix routed interrupts (default=0)");
+
+/**
+ * _base_fault_reset_work - workq handling ioc fault conditions
+ * @work: input argument, used to derive ioc
+ * Context: sleep.
+ *
+ * Return nothing.
+ */
+static void
+_base_fault_reset_work(struct work_struct *work)
+{
+       struct MPT2SAS_ADAPTER *ioc =
+           container_of(work, struct MPT2SAS_ADAPTER, fault_reset_work.work);
+       unsigned long    flags;
+       u32 doorbell;
+       int rc;
+
+       spin_lock_irqsave(&ioc->ioc_reset_in_progress_lock, flags);
+       if (ioc->ioc_reset_in_progress)
+               goto rearm_timer;
+       spin_unlock_irqrestore(&ioc->ioc_reset_in_progress_lock, flags);
+
+       doorbell = mpt2sas_base_get_iocstate(ioc, 0);
+       if ((doorbell & MPI2_IOC_STATE_MASK) == MPI2_IOC_STATE_FAULT) {
+               rc = mpt2sas_base_hard_reset_handler(ioc, CAN_SLEEP,
+                   FORCE_BIG_HAMMER);
+               printk(MPT2SAS_WARN_FMT "%s: hard reset: %s\n", ioc->name,
+                   __func__, (rc == 0) ? "success" : "failed");
+               doorbell = mpt2sas_base_get_iocstate(ioc, 0);
+               if ((doorbell & MPI2_IOC_STATE_MASK) == MPI2_IOC_STATE_FAULT)
+                       mpt2sas_base_fault_info(ioc, doorbell &
+                           MPI2_DOORBELL_DATA_MASK);
+       }
+
+       spin_lock_irqsave(&ioc->ioc_reset_in_progress_lock, flags);
+ rearm_timer:
+       if (ioc->fault_reset_work_q)
+               queue_delayed_work(ioc->fault_reset_work_q,
+                   &ioc->fault_reset_work,
+                   msecs_to_jiffies(FAULT_POLLING_INTERVAL));
+       spin_unlock_irqrestore(&ioc->ioc_reset_in_progress_lock, flags);
+}
+
+#ifdef CONFIG_SCSI_MPT2SAS_LOGGING
+/**
+ * _base_sas_ioc_info - verbose translation of the ioc status
+ * @ioc: pointer to scsi command object
+ * @mpi_reply: reply mf payload returned from firmware
+ * @request_hdr: request mf
+ *
+ * Return nothing.
+ */
+static void
+_base_sas_ioc_info(struct MPT2SAS_ADAPTER *ioc, MPI2DefaultReply_t *mpi_reply,
+     MPI2RequestHeader_t *request_hdr)
+{
+       u16 ioc_status = le16_to_cpu(mpi_reply->IOCStatus) &
+           MPI2_IOCSTATUS_MASK;
+       char *desc = NULL;
+       u16 frame_sz;
+       char *func_str = NULL;
+
+       /* SCSI_IO, RAID_PASS are handled from _scsih_scsi_ioc_info */
+       if (request_hdr->Function == MPI2_FUNCTION_SCSI_IO_REQUEST ||
+           request_hdr->Function == MPI2_FUNCTION_RAID_SCSI_IO_PASSTHROUGH ||
+           request_hdr->Function == MPI2_FUNCTION_EVENT_NOTIFICATION)
+               return;
+
+       switch (ioc_status) {
+
+/****************************************************************************
+*  Common IOCStatus values for all replies
+****************************************************************************/
+
+       case MPI2_IOCSTATUS_INVALID_FUNCTION:
+               desc = "invalid function";
+               break;
+       case MPI2_IOCSTATUS_BUSY:
+               desc = "busy";
+               break;
+       case MPI2_IOCSTATUS_INVALID_SGL:
+               desc = "invalid sgl";
+               break;
+       case MPI2_IOCSTATUS_INTERNAL_ERROR:
+               desc = "internal error";
+               break;
+       case MPI2_IOCSTATUS_INVALID_VPID:
+               desc = "invalid vpid";
+               break;
+       case MPI2_IOCSTATUS_INSUFFICIENT_RESOURCES:
+               desc = "insufficient resources";
+               break;
+       case MPI2_IOCSTATUS_INVALID_FIELD:
+               desc = "invalid field";
+               break;
+       case MPI2_IOCSTATUS_INVALID_STATE:
+               desc = "invalid state";
+               break;
+       case MPI2_IOCSTATUS_OP_STATE_NOT_SUPPORTED:
+               desc = "op state not supported";
+               break;
+
+/****************************************************************************
+*  Config IOCStatus values
+****************************************************************************/
+
+       case MPI2_IOCSTATUS_CONFIG_INVALID_ACTION:
+               desc = "config invalid action";
+               break;
+       case MPI2_IOCSTATUS_CONFIG_INVALID_TYPE:
+               desc = "config invalid type";
+               break;
+       case MPI2_IOCSTATUS_CONFIG_INVALID_PAGE:
+               desc = "config invalid page";
+               break;
+       case MPI2_IOCSTATUS_CONFIG_INVALID_DATA:
+               desc = "config invalid data";
+               break;
+       case MPI2_IOCSTATUS_CONFIG_NO_DEFAULTS:
+               desc = "config no defaults";
+               break;
+       case MPI2_IOCSTATUS_CONFIG_CANT_COMMIT:
+               desc = "config cant commit";
+               break;
+
+/****************************************************************************
+*  SCSI IO Reply
+****************************************************************************/
+
+       case MPI2_IOCSTATUS_SCSI_RECOVERED_ERROR:
+       case MPI2_IOCSTATUS_SCSI_INVALID_DEVHANDLE:
+       case MPI2_IOCSTATUS_SCSI_DEVICE_NOT_THERE:
+       case MPI2_IOCSTATUS_SCSI_DATA_OVERRUN:
+       case MPI2_IOCSTATUS_SCSI_DATA_UNDERRUN:
+       case MPI2_IOCSTATUS_SCSI_IO_DATA_ERROR:
+       case MPI2_IOCSTATUS_SCSI_PROTOCOL_ERROR:
+       case MPI2_IOCSTATUS_SCSI_TASK_TERMINATED:
+       case MPI2_IOCSTATUS_SCSI_RESIDUAL_MISMATCH:
+       case MPI2_IOCSTATUS_SCSI_TASK_MGMT_FAILED:
+       case MPI2_IOCSTATUS_SCSI_IOC_TERMINATED:
+       case MPI2_IOCSTATUS_SCSI_EXT_TERMINATED:
+               break;
+
+/****************************************************************************
+*  For use by SCSI Initiator and SCSI Target end-to-end data protection
+****************************************************************************/
+
+       case MPI2_IOCSTATUS_EEDP_GUARD_ERROR:
+               desc = "eedp guard error";
+               break;
+       case MPI2_IOCSTATUS_EEDP_REF_TAG_ERROR:
+               desc = "eedp ref tag error";
+               break;
+       case MPI2_IOCSTATUS_EEDP_APP_TAG_ERROR:
+               desc = "eedp app tag error";
+               break;
+
+/****************************************************************************
+*  SCSI Target values
+****************************************************************************/
+
+       case MPI2_IOCSTATUS_TARGET_INVALID_IO_INDEX:
+               desc = "target invalid io index";
+               break;
+       case MPI2_IOCSTATUS_TARGET_ABORTED:
+               desc = "target aborted";
+               break;
+       case MPI2_IOCSTATUS_TARGET_NO_CONN_RETRYABLE:
+               desc = "target no conn retryable";
+               break;
+       case MPI2_IOCSTATUS_TARGET_NO_CONNECTION:
+               desc = "target no connection";
+               break;
+       case MPI2_IOCSTATUS_TARGET_XFER_COUNT_MISMATCH:
+               desc = "target xfer count mismatch";
+               break;
+       case MPI2_IOCSTATUS_TARGET_DATA_OFFSET_ERROR:
+               desc = "target data offset error";
+               break;
+       case MPI2_IOCSTATUS_TARGET_TOO_MUCH_WRITE_DATA:
+               desc = "target too much write data";
+               break;
+       case MPI2_IOCSTATUS_TARGET_IU_TOO_SHORT:
+               desc = "target iu too short";
+               break;
+       case MPI2_IOCSTATUS_TARGET_ACK_NAK_TIMEOUT:
+               desc = "target ack nak timeout";
+               break;
+       case MPI2_IOCSTATUS_TARGET_NAK_RECEIVED:
+               desc = "target nak received";
+               break;
+
+/****************************************************************************
+*  Serial Attached SCSI values
+****************************************************************************/
+
+       case MPI2_IOCSTATUS_SAS_SMP_REQUEST_FAILED:
+               desc = "smp request failed";
+               break;
+       case MPI2_IOCSTATUS_SAS_SMP_DATA_OVERRUN:
+               desc = "smp data overrun";
+               break;
+
+/****************************************************************************
+*  Diagnostic Buffer Post / Diagnostic Release values
+****************************************************************************/
+
+       case MPI2_IOCSTATUS_DIAGNOSTIC_RELEASED:
+               desc = "diagnostic released";
+               break;
+       default:
+               break;
+       }
+
+       if (!desc)
+               return;
+
+       switch (request_hdr->Function) {
+       case MPI2_FUNCTION_CONFIG:
+               frame_sz = sizeof(Mpi2ConfigRequest_t) + ioc->sge_size;
+               func_str = "config_page";
+               break;
+       case MPI2_FUNCTION_SCSI_TASK_MGMT:
+               frame_sz = sizeof(Mpi2SCSITaskManagementRequest_t);
+               func_str = "task_mgmt";
+               break;
+       case MPI2_FUNCTION_SAS_IO_UNIT_CONTROL:
+               frame_sz = sizeof(Mpi2SasIoUnitControlRequest_t);
+               func_str = "sas_iounit_ctl";
+               break;
+       case MPI2_FUNCTION_SCSI_ENCLOSURE_PROCESSOR:
+               frame_sz = sizeof(Mpi2SepRequest_t);
+               func_str = "enclosure";
+               break;
+       case MPI2_FUNCTION_IOC_INIT:
+               frame_sz = sizeof(Mpi2IOCInitRequest_t);
+               func_str = "ioc_init";
+               break;
+       case MPI2_FUNCTION_PORT_ENABLE:
+               frame_sz = sizeof(Mpi2PortEnableRequest_t);
+               func_str = "port_enable";
+               break;
+       case MPI2_FUNCTION_SMP_PASSTHROUGH:
+               frame_sz = sizeof(Mpi2SmpPassthroughRequest_t) + ioc->sge_size;
+               func_str = "smp_passthru";
+               break;
+       default:
+               frame_sz = 32;
+               func_str = "unknown";
+               break;
+       }
+
+       printk(MPT2SAS_WARN_FMT "ioc_status: %s(0x%04x), request(0x%p),"
+           " (%s)\n", ioc->name, desc, ioc_status, request_hdr, func_str);
+
+       _debug_dump_mf(request_hdr, frame_sz/4);
+}
+
+/**
+ * _base_display_event_data - verbose translation of firmware asyn events
+ * @ioc: pointer to scsi command object
+ * @mpi_reply: reply mf payload returned from firmware
+ *
+ * Return nothing.
+ */
+static void
+_base_display_event_data(struct MPT2SAS_ADAPTER *ioc,
+    Mpi2EventNotificationReply_t *mpi_reply)
+{
+       char *desc = NULL;
+       u16 event;
+
+       if (!(ioc->logging_level & MPT_DEBUG_EVENTS))
+               return;
+
+       event = le16_to_cpu(mpi_reply->Event);
+
+       switch (event) {
+       case MPI2_EVENT_LOG_DATA:
+               desc = "Log Data";
+               break;
+       case MPI2_EVENT_STATE_CHANGE:
+               desc = "Status Change";
+               break;
+       case MPI2_EVENT_HARD_RESET_RECEIVED:
+               desc = "Hard Reset Received";
+               break;
+       case MPI2_EVENT_EVENT_CHANGE:
+               desc = "Event Change";
+               break;
+       case MPI2_EVENT_TASK_SET_FULL:
+               desc = "Task Set Full";
+               break;
+       case MPI2_EVENT_SAS_DEVICE_STATUS_CHANGE:
+               desc = "Device Status Change";
+               break;
+       case MPI2_EVENT_IR_OPERATION_STATUS:
+               desc = "IR Operation Status";
+               break;
+       case MPI2_EVENT_SAS_DISCOVERY:
+               desc =  "Discovery";
+               break;
+       case MPI2_EVENT_SAS_BROADCAST_PRIMITIVE:
+               desc = "SAS Broadcast Primitive";
+               break;
+       case MPI2_EVENT_SAS_INIT_DEVICE_STATUS_CHANGE:
+               desc = "SAS Init Device Status Change";
+               break;
+       case MPI2_EVENT_SAS_INIT_TABLE_OVERFLOW:
+               desc = "SAS Init Table Overflow";
+               break;
+       case MPI2_EVENT_SAS_TOPOLOGY_CHANGE_LIST:
+               desc = "SAS Topology Change List";
+               break;
+       case MPI2_EVENT_SAS_ENCL_DEVICE_STATUS_CHANGE:
+               desc = "SAS Enclosure Device Status Change";
+               break;
+       case MPI2_EVENT_IR_VOLUME:
+               desc = "IR Volume";
+               break;
+       case MPI2_EVENT_IR_PHYSICAL_DISK:
+               desc = "IR Physical Disk";
+               break;
+       case MPI2_EVENT_IR_CONFIGURATION_CHANGE_LIST:
+               desc = "IR Configuration Change List";
+               break;
+       case MPI2_EVENT_LOG_ENTRY_ADDED:
+               desc = "Log Entry Added";
+               break;
+       }
+
+       if (!desc)
+               return;
+
+       printk(MPT2SAS_INFO_FMT "%s\n", ioc->name, desc);
+}
+#endif
+
+/**
+ * _base_sas_log_info - verbose translation of firmware log info
+ * @ioc: pointer to scsi command object
+ * @log_info: log info
+ *
+ * Return nothing.
+ */
+static void
+_base_sas_log_info(struct MPT2SAS_ADAPTER *ioc , u32 log_info)
+{
+       union loginfo_type {
+               u32     loginfo;
+               struct {
+                       u32     subcode:16;
+                       u32     code:8;
+                       u32     originator:4;
+                       u32     bus_type:4;
+               } dw;
+       };
+       union loginfo_type sas_loginfo;
+       char *originator_str = NULL;
+
+       sas_loginfo.loginfo = log_info;
+       if (sas_loginfo.dw.bus_type != 3 /*SAS*/)
+               return;
+
+       /* eat the loginfos associated with task aborts */
+       if (ioc->ignore_loginfos && (log_info == 30050000 || log_info ==
+           0x31140000 || log_info == 0x31130000))
+               return;
+
+       switch (sas_loginfo.dw.originator) {
+       case 0:
+               originator_str = "IOP";
+               break;
+       case 1:
+               originator_str = "PL";
+               break;
+       case 2:
+               originator_str = "IR";
+               break;
+       }
+
+       printk(MPT2SAS_WARN_FMT "log_info(0x%08x): originator(%s), "
+           "code(0x%02x), sub_code(0x%04x)\n", ioc->name, log_info,
+            originator_str, sas_loginfo.dw.code,
+            sas_loginfo.dw.subcode);
+}
+
+/**
+ * mpt2sas_base_fault_info - verbose translation of firmware FAULT code
+ * @ioc: pointer to scsi command object
+ * @fault_code: fault code
+ *
+ * Return nothing.
+ */
+void
+mpt2sas_base_fault_info(struct MPT2SAS_ADAPTER *ioc , u16 fault_code)
+{
+       printk(MPT2SAS_ERR_FMT "fault_state(0x%04x)!\n",
+           ioc->name, fault_code);
+}
+
+/**
+ * _base_display_reply_info -
+ * @ioc: pointer to scsi command object
+ * @smid: system request message index
+ * @VF_ID: virtual function id
+ * @reply: reply message frame(lower 32bit addr)
+ *
+ * Return nothing.
+ */
+static void
+_base_display_reply_info(struct MPT2SAS_ADAPTER *ioc, u16 smid, u8 VF_ID,
+    u32 reply)
+{
+       MPI2DefaultReply_t *mpi_reply;
+       u16 ioc_status;
+
+       mpi_reply = mpt2sas_base_get_reply_virt_addr(ioc, reply);
+       ioc_status = le16_to_cpu(mpi_reply->IOCStatus);
+#ifdef CONFIG_SCSI_MPT2SAS_LOGGING
+       if ((ioc_status & MPI2_IOCSTATUS_MASK) &&
+           (ioc->logging_level & MPT_DEBUG_REPLY)) {
+               _base_sas_ioc_info(ioc , mpi_reply,
+                  mpt2sas_base_get_msg_frame(ioc, smid));
+       }
+#endif
+       if (ioc_status & MPI2_IOCSTATUS_FLAG_LOG_INFO_AVAILABLE)
+               _base_sas_log_info(ioc, le32_to_cpu(mpi_reply->IOCLogInfo));
+}
+
+/**
+ * mpt2sas_base_done - base internal command completion routine
+ * @ioc: pointer to scsi command object
+ * @smid: system request message index
+ * @VF_ID: virtual function id
+ * @reply: reply message frame(lower 32bit addr)
+ *
+ * Return nothing.
+ */
+void
+mpt2sas_base_done(struct MPT2SAS_ADAPTER *ioc, u16 smid, u8 VF_ID, u32 reply)
+{
+       MPI2DefaultReply_t *mpi_reply;
+
+       mpi_reply = mpt2sas_base_get_reply_virt_addr(ioc, reply);
+       if (mpi_reply && mpi_reply->Function == MPI2_FUNCTION_EVENT_ACK)
+               return;
+
+       if (ioc->base_cmds.status == MPT2_CMD_NOT_USED)
+               return;
+
+       ioc->base_cmds.status |= MPT2_CMD_COMPLETE;
+       if (mpi_reply) {
+               ioc->base_cmds.status |= MPT2_CMD_REPLY_VALID;
+               memcpy(ioc->base_cmds.reply, mpi_reply, mpi_reply->MsgLength*4);
+       }
+       ioc->base_cmds.status &= ~MPT2_CMD_PENDING;
+       complete(&ioc->base_cmds.done);
+}
+
+/**
+ * _base_async_event - main callback handler for firmware asyn events
+ * @ioc: pointer to scsi command object
+ * @VF_ID: virtual function id
+ * @reply: reply message frame(lower 32bit addr)
+ *
+ * Return nothing.
+ */
+static void
+_base_async_event(struct MPT2SAS_ADAPTER *ioc, u8 VF_ID, u32 reply)
+{
+       Mpi2EventNotificationReply_t *mpi_reply;
+       Mpi2EventAckRequest_t *ack_request;
+       u16 smid;
+
+       mpi_reply = mpt2sas_base_get_reply_virt_addr(ioc, reply);
+       if (!mpi_reply)
+               return;
+       if (mpi_reply->Function != MPI2_FUNCTION_EVENT_NOTIFICATION)
+               return;
+#ifdef CONFIG_SCSI_MPT2SAS_LOGGING
+       _base_display_event_data(ioc, mpi_reply);
+#endif
+       if (!(mpi_reply->AckRequired & MPI2_EVENT_NOTIFICATION_ACK_REQUIRED))
+               goto out;
+       smid = mpt2sas_base_get_smid(ioc, ioc->base_cb_idx);
+       if (!smid) {
+               printk(MPT2SAS_ERR_FMT "%s: failed obtaining a smid\n",
+                   ioc->name, __func__);
+               goto out;
+       }
+
+       ack_request = mpt2sas_base_get_msg_frame(ioc, smid);
+       memset(ack_request, 0, sizeof(Mpi2EventAckRequest_t));
+       ack_request->Function = MPI2_FUNCTION_EVENT_ACK;
+       ack_request->Event = mpi_reply->Event;
+       ack_request->EventContext = mpi_reply->EventContext;
+       ack_request->VF_ID = VF_ID;
+       mpt2sas_base_put_smid_default(ioc, smid, VF_ID);
+
+ out:
+
+       /* scsih callback handler */
+       mpt2sas_scsih_event_callback(ioc, VF_ID, reply);
+
+       /* ctl callback handler */
+       mpt2sas_ctl_event_callback(ioc, VF_ID, reply);
+}
+
+/**
+ * _base_mask_interrupts - disable interrupts
+ * @ioc: pointer to scsi command object
+ *
+ * Disabling ResetIRQ, Reply and Doorbell Interrupts
+ *
+ * Return nothing.
+ */
+static void
+_base_mask_interrupts(struct MPT2SAS_ADAPTER *ioc)
+{
+       u32 him_register;
+
+       ioc->mask_interrupts = 1;
+       him_register = readl(&ioc->chip->HostInterruptMask);
+       him_register |= MPI2_HIM_DIM + MPI2_HIM_RIM + MPI2_HIM_RESET_IRQ_MASK;
+       writel(him_register, &ioc->chip->HostInterruptMask);
+       readl(&ioc->chip->HostInterruptMask);
+}
+
+/**
+ * _base_unmask_interrupts - enable interrupts
+ * @ioc: pointer to scsi command object
+ *
+ * Enabling only Reply Interrupts
+ *
+ * Return nothing.
+ */
+static void
+_base_unmask_interrupts(struct MPT2SAS_ADAPTER *ioc)
+{
+       u32 him_register;
+
+       writel(0, &ioc->chip->HostInterruptStatus);
+       him_register = readl(&ioc->chip->HostInterruptMask);
+       him_register &= ~MPI2_HIM_RIM;
+       writel(him_register, &ioc->chip->HostInterruptMask);
+       ioc->mask_interrupts = 0;
+}
+
+/**
+ * _base_interrupt - MPT adapter (IOC) specific interrupt handler.
+ * @irq: irq number (not used)
+ * @bus_id: bus identifier cookie == pointer to MPT_ADAPTER structure
+ * @r: pt_regs pointer (not used)
+ *
+ * Return IRQ_HANDLE if processed, else IRQ_NONE.
+ */
+static irqreturn_t
+_base_interrupt(int irq, void *bus_id)
+{
+       u32 post_index, post_index_next, completed_cmds;
+       u8 request_desript_type;
+       u16 smid;
+       u8 cb_idx;
+       u32 reply;
+       u8 VF_ID;
+       int i;
+       struct MPT2SAS_ADAPTER *ioc = bus_id;
+
+       if (ioc->mask_interrupts)
+               return IRQ_NONE;
+
+       post_index = ioc->reply_post_host_index;
+       request_desript_type = ioc->reply_post_free[post_index].
+           Default.ReplyFlags & MPI2_RPY_DESCRIPT_FLAGS_TYPE_MASK;
+       if (request_desript_type == MPI2_RPY_DESCRIPT_FLAGS_UNUSED)
+               return IRQ_NONE;
+
+       completed_cmds = 0;
+       do {
+               if (ioc->reply_post_free[post_index].Words == ~0ULL)
+                       goto out;
+               reply = 0;
+               cb_idx = 0xFF;
+               smid = le16_to_cpu(ioc->reply_post_free[post_index].
+                   Default.DescriptorTypeDependent1);
+               VF_ID = ioc->reply_post_free[post_index].
+                   Default.VF_ID;
+               if (request_desript_type ==
+                   MPI2_RPY_DESCRIPT_FLAGS_ADDRESS_REPLY) {
+                       reply = le32_to_cpu(ioc->reply_post_free[post_index].
+                           AddressReply.ReplyFrameAddress);
+               } else if (request_desript_type ==
+                   MPI2_RPY_DESCRIPT_FLAGS_TARGET_COMMAND_BUFFER)
+                       goto next;
+               else if (request_desript_type ==
+                   MPI2_RPY_DESCRIPT_FLAGS_TARGETASSIST_SUCCESS)
+                       goto next;
+               if (smid)
+                       cb_idx = ioc->scsi_lookup[smid - 1].cb_idx;
+               if (smid && cb_idx != 0xFF) {
+                       mpt_callbacks[cb_idx](ioc, smid, VF_ID, reply);
+                       if (reply)
+                               _base_display_reply_info(ioc, smid, VF_ID,
+                                   reply);
+                       mpt2sas_base_free_smid(ioc, smid);
+               }
+               if (!smid)
+                       _base_async_event(ioc, VF_ID, reply);
+
+               /* reply free queue handling */
+               if (reply) {
+                       ioc->reply_free_host_index =
+                           (ioc->reply_free_host_index ==
+                           (ioc->reply_free_queue_depth - 1)) ?
+                           0 : ioc->reply_free_host_index + 1;
+                       ioc->reply_free[ioc->reply_free_host_index] =
+                           cpu_to_le32(reply);
+                       writel(ioc->reply_free_host_index,
+                           &ioc->chip->ReplyFreeHostIndex);
+                       wmb();
+               }
+
+ next:
+               post_index_next = (post_index == (ioc->reply_post_queue_depth -
+                   1)) ? 0 : post_index + 1;
+               request_desript_type =
+                   ioc->reply_post_free[post_index_next].Default.ReplyFlags
+                   & MPI2_RPY_DESCRIPT_FLAGS_TYPE_MASK;
+               completed_cmds++;
+               if (request_desript_type == MPI2_RPY_DESCRIPT_FLAGS_UNUSED)
+                       goto out;
+               post_index = post_index_next;
+       } while (1);
+
+ out:
+
+       if (!completed_cmds)
+               return IRQ_NONE;
+
+       /* reply post descriptor handling */
+       post_index_next = ioc->reply_post_host_index;
+       for (i = 0 ; i < completed_cmds; i++) {
+               post_index = post_index_next;
+               /* poison the reply post descriptor */
+               ioc->reply_post_free[post_index_next].Words = ~0ULL;
+               post_index_next = (post_index ==
+                   (ioc->reply_post_queue_depth - 1))
+                   ? 0 : post_index + 1;
+       }
+       ioc->reply_post_host_index = post_index_next;
+       writel(post_index_next, &ioc->chip->ReplyPostHostIndex);
+       wmb();
+       return IRQ_HANDLED;
+}
+
+/**
+ * mpt2sas_base_release_callback_handler - clear interupt callback handler
+ * @cb_idx: callback index
+ *
+ * Return nothing.
+ */
+void
+mpt2sas_base_release_callback_handler(u8 cb_idx)
+{
+       mpt_callbacks[cb_idx] = NULL;
+}
+
+/**
+ * mpt2sas_base_register_callback_handler - obtain index for the interrupt callback handler
+ * @cb_func: callback function
+ *
+ * Returns cb_func.
+ */
+u8
+mpt2sas_base_register_callback_handler(MPT_CALLBACK cb_func)
+{
+       u8 cb_idx;
+
+       for (cb_idx = MPT_MAX_CALLBACKS-1; cb_idx; cb_idx--)
+               if (mpt_callbacks[cb_idx] == NULL)
+                       break;
+
+       mpt_callbacks[cb_idx] = cb_func;
+       return cb_idx;
+}
+
+/**
+ * mpt2sas_base_initialize_callback_handler - initialize the interrupt callback handler
+ *
+ * Return nothing.
+ */
+void
+mpt2sas_base_initialize_callback_handler(void)
+{
+       u8 cb_idx;
+
+       for (cb_idx = 0; cb_idx < MPT_MAX_CALLBACKS; cb_idx++)
+               mpt2sas_base_release_callback_handler(cb_idx);
+}
+
+/**
+ * mpt2sas_base_build_zero_len_sge - build zero length sg entry
+ * @ioc: per adapter object
+ * @paddr: virtual address for SGE
+ *
+ * Create a zero length scatter gather entry to insure the IOCs hardware has
+ * something to use if the target device goes brain dead and tries
+ * to send data even when none is asked for.
+ *
+ * Return nothing.
+ */
+void
+mpt2sas_base_build_zero_len_sge(struct MPT2SAS_ADAPTER *ioc, void *paddr)
+{
+       u32 flags_length = (u32)((MPI2_SGE_FLAGS_LAST_ELEMENT |
+           MPI2_SGE_FLAGS_END_OF_BUFFER | MPI2_SGE_FLAGS_END_OF_LIST |
+           MPI2_SGE_FLAGS_SIMPLE_ELEMENT) <<
+           MPI2_SGE_FLAGS_SHIFT);
+       ioc->base_add_sg_single(paddr, flags_length, -1);
+}
+
+/**
+ * _base_add_sg_single_32 - Place a simple 32 bit SGE at address pAddr.
+ * @paddr: virtual address for SGE
+ * @flags_length: SGE flags and data transfer length
+ * @dma_addr: Physical address
+ *
+ * Return nothing.
+ */
+static void
+_base_add_sg_single_32(void *paddr, u32 flags_length, dma_addr_t dma_addr)
+{
+       Mpi2SGESimple32_t *sgel = paddr;
+
+       flags_length |= (MPI2_SGE_FLAGS_32_BIT_ADDRESSING |
+           MPI2_SGE_FLAGS_SYSTEM_ADDRESS) << MPI2_SGE_FLAGS_SHIFT;
+       sgel->FlagsLength = cpu_to_le32(flags_length);
+       sgel->Address = cpu_to_le32(dma_addr);
+}
+
+
+/**
+ * _base_add_sg_single_64 - Place a simple 64 bit SGE at address pAddr.
+ * @paddr: virtual address for SGE
+ * @flags_length: SGE flags and data transfer length
+ * @dma_addr: Physical address
+ *
+ * Return nothing.
+ */
+static void
+_base_add_sg_single_64(void *paddr, u32 flags_length, dma_addr_t dma_addr)
+{
+       Mpi2SGESimple64_t *sgel = paddr;
+
+       flags_length |= (MPI2_SGE_FLAGS_64_BIT_ADDRESSING |
+           MPI2_SGE_FLAGS_SYSTEM_ADDRESS) << MPI2_SGE_FLAGS_SHIFT;
+       sgel->FlagsLength = cpu_to_le32(flags_length);
+       sgel->Address = cpu_to_le64(dma_addr);
+}
+
+#define convert_to_kb(x) ((x) << (PAGE_SHIFT - 10))
+
+/**
+ * _base_config_dma_addressing - set dma addressing
+ * @ioc: per adapter object
+ * @pdev: PCI device struct
+ *
+ * Returns 0 for success, non-zero for failure.
+ */
+static int
+_base_config_dma_addressing(struct MPT2SAS_ADAPTER *ioc, struct pci_dev *pdev)
+{
+       struct sysinfo s;
+       char *desc = NULL;
+
+       if (sizeof(dma_addr_t) > 4) {
+               const uint64_t required_mask =
+                   dma_get_required_mask(&pdev->dev);
+               if ((required_mask > DMA_32BIT_MASK) && !pci_set_dma_mask(pdev,
+                   DMA_64BIT_MASK) && !pci_set_consistent_dma_mask(pdev,
+                   DMA_64BIT_MASK)) {
+                       ioc->base_add_sg_single = &_base_add_sg_single_64;
+                       ioc->sge_size = sizeof(Mpi2SGESimple64_t);
+                       desc = "64";
+                       goto out;
+               }
+       }
+
+       if (!pci_set_dma_mask(pdev, DMA_32BIT_MASK)
+           && !pci_set_consistent_dma_mask(pdev, DMA_32BIT_MASK)) {
+               ioc->base_add_sg_single = &_base_add_sg_single_32;
+               ioc->sge_size = sizeof(Mpi2SGESimple32_t);
+               desc = "32";
+       } else
+               return -ENODEV;
+
+ out:
+       si_meminfo(&s);
+       printk(MPT2SAS_INFO_FMT "%s BIT PCI BUS DMA ADDRESSING SUPPORTED, "
+           "total mem (%ld kB)\n", ioc->name, desc, convert_to_kb(s.totalram));
+
+       return 0;
+}
+
+/**
+ * _base_save_msix_table - backup msix vector table
+ * @ioc: per adapter object
+ *
+ * This address an errata where diag reset clears out the table
+ */
+static void
+_base_save_msix_table(struct MPT2SAS_ADAPTER *ioc)
+{
+       int i;
+
+       if (!ioc->msix_enable || ioc->msix_table_backup == NULL)
+               return;
+
+       for (i = 0; i < ioc->msix_vector_count; i++)
+               ioc->msix_table_backup[i] = ioc->msix_table[i];
+}
+
+/**
+ * _base_restore_msix_table - this restores the msix vector table
+ * @ioc: per adapter object
+ *
+ */
+static void
+_base_restore_msix_table(struct MPT2SAS_ADAPTER *ioc)
+{
+       int i;
+
+       if (!ioc->msix_enable || ioc->msix_table_backup == NULL)
+               return;
+
+       for (i = 0; i < ioc->msix_vector_count; i++)
+               ioc->msix_table[i] = ioc->msix_table_backup[i];
+}
+
+/**
+ * _base_check_enable_msix - checks MSIX capabable.
+ * @ioc: per adapter object
+ *
+ * Check to see if card is capable of MSIX, and set number
+ * of avaliable msix vectors
+ */
+static int
+_base_check_enable_msix(struct MPT2SAS_ADAPTER *ioc)
+{
+       int base;
+       u16 message_control;
+       u32 msix_table_offset;
+
+       base = pci_find_capability(ioc->pdev, PCI_CAP_ID_MSIX);
+       if (!base) {
+               dfailprintk(ioc, printk(MPT2SAS_INFO_FMT "msix not "
+                   "supported\n", ioc->name));
+               return -EINVAL;
+       }
+
+       /* get msix vector count */
+       pci_read_config_word(ioc->pdev, base + 2, &message_control);
+       ioc->msix_vector_count = (message_control & 0x3FF) + 1;
+
+       /* get msix table  */
+       pci_read_config_dword(ioc->pdev, base + 4, &msix_table_offset);
+       msix_table_offset &= 0xFFFFFFF8;
+       ioc->msix_table = (u32 *)((void *)ioc->chip + msix_table_offset);
+
+       dinitprintk(ioc, printk(MPT2SAS_INFO_FMT "msix is supported, "
+           "vector_count(%d), table_offset(0x%08x), table(%p)\n", ioc->name,
+           ioc->msix_vector_count, msix_table_offset, ioc->msix_table));
+       return 0;
+}
+
+/**
+ * _base_disable_msix - disables msix
+ * @ioc: per adapter object
+ *
+ */
+static void
+_base_disable_msix(struct MPT2SAS_ADAPTER *ioc)
+{
+       if (ioc->msix_enable) {
+               pci_disable_msix(ioc->pdev);
+               kfree(ioc->msix_table_backup);
+               ioc->msix_table_backup = NULL;
+               ioc->msix_enable = 0;
+       }
+}
+
+/**
+ * _base_enable_msix - enables msix, failback to io_apic
+ * @ioc: per adapter object
+ *
+ */
+static int
+_base_enable_msix(struct MPT2SAS_ADAPTER *ioc)
+{
+       struct msix_entry entries;
+       int r;
+       u8 try_msix = 0;
+
+       if (msix_disable == -1 || msix_disable == 0)
+               try_msix = 1;
+
+       if (!try_msix)
+               goto try_ioapic;
+
+       if (_base_check_enable_msix(ioc) != 0)
+               goto try_ioapic;
+
+       ioc->msix_table_backup = kcalloc(ioc->msix_vector_count,
+           sizeof(u32), GFP_KERNEL);
+       if (!ioc->msix_table_backup) {
+               dfailprintk(ioc, printk(MPT2SAS_INFO_FMT "allocation for "
+                   "msix_table_backup failed!!!\n", ioc->name));
+               goto try_ioapic;
+       }
+
+       memset(&entries, 0, sizeof(struct msix_entry));
+       r = pci_enable_msix(ioc->pdev, &entries, 1);
+       if (r) {
+               dfailprintk(ioc, printk(MPT2SAS_INFO_FMT "pci_enable_msix "
+                   "failed (r=%d) !!!\n", ioc->name, r));
+               goto try_ioapic;
+       }
+
+       r = request_irq(entries.vector, _base_interrupt, IRQF_SHARED,
+           ioc->name, ioc);
+       if (r) {
+               dfailprintk(ioc, printk(MPT2SAS_INFO_FMT "unable to allocate "
+                   "interrupt %d !!!\n", ioc->name, entries.vector));
+               pci_disable_msix(ioc->pdev);
+               goto try_ioapic;
+       }
+
+       ioc->pci_irq = entries.vector;
+       ioc->msix_enable = 1;
+       return 0;
+
+/* failback to io_apic interrupt routing */
+ try_ioapic:
+
+       r = request_irq(ioc->pdev->irq, _base_interrupt, IRQF_SHARED,
+           ioc->name, ioc);
+       if (r) {
+               printk(MPT2SAS_ERR_FMT "unable to allocate interrupt %d!\n",
+                   ioc->name, ioc->pdev->irq);
+               r = -EBUSY;
+               goto out_fail;
+       }
+
+       ioc->pci_irq = ioc->pdev->irq;
+       return 0;
+
+ out_fail:
+       return r;
+}
+
+/**
+ * mpt2sas_base_map_resources - map in controller resources (io/irq/memap)
+ * @ioc: per adapter object
+ *
+ * Returns 0 for success, non-zero for failure.
+ */
+int
+mpt2sas_base_map_resources(struct MPT2SAS_ADAPTER *ioc)
+{
+       struct pci_dev *pdev = ioc->pdev;
+       u32 memap_sz;
+       u32 pio_sz;
+       int i, r = 0;
+
+       dinitprintk(ioc, printk(MPT2SAS_DEBUG_FMT "%s\n",
+           ioc->name, __func__));
+
+       ioc->bars = pci_select_bars(pdev, IORESOURCE_MEM);
+       if (pci_enable_device_mem(pdev)) {
+               printk(MPT2SAS_WARN_FMT "pci_enable_device_mem: "
+                   "failed\n", ioc->name);
+               return -ENODEV;
+       }
+
+
+       if (pci_request_selected_regions(pdev, ioc->bars,
+           MPT2SAS_DRIVER_NAME)) {
+               printk(MPT2SAS_WARN_FMT "pci_request_selected_regions: "
+                   "failed\n", ioc->name);
+               r = -ENODEV;
+               goto out_fail;
+       }
+
+       pci_set_master(pdev);
+
+       if (_base_config_dma_addressing(ioc, pdev) != 0) {
+               printk(MPT2SAS_WARN_FMT "no suitable DMA mask for %s\n",
+                   ioc->name, pci_name(pdev));
+               r = -ENODEV;
+               goto out_fail;
+       }
+
+       for (i = 0, memap_sz = 0, pio_sz = 0 ; i < DEVICE_COUNT_RESOURCE; i++) {
+               if (pci_resource_flags(pdev, i) & PCI_BASE_ADDRESS_SPACE_IO) {
+                       if (pio_sz)
+                               continue;
+                       ioc->pio_chip = pci_resource_start(pdev, i);
+                       pio_sz = pci_resource_len(pdev, i);
+               } else {
+                       if (memap_sz)
+                               continue;
+                       ioc->chip_phys = pci_resource_start(pdev, i);
+                       memap_sz = pci_resource_len(pdev, i);
+                       ioc->chip = ioremap(ioc->chip_phys, memap_sz);
+                       if (ioc->chip == NULL) {
+                               printk(MPT2SAS_ERR_FMT "unable to map adapter "
+                                   "memory!\n", ioc->name);
+                               r = -EINVAL;
+                               goto out_fail;
+                       }
+               }
+       }
+
+       pci_set_drvdata(pdev, ioc->shost);
+       _base_mask_interrupts(ioc);
+       r = _base_enable_msix(ioc);
+       if (r)
+               goto out_fail;
+
+       printk(MPT2SAS_INFO_FMT "%s: IRQ %d\n",
+           ioc->name,  ((ioc->msix_enable) ? "PCI-MSI-X enabled" :
+           "IO-APIC enabled"), ioc->pci_irq);
+       printk(MPT2SAS_INFO_FMT "iomem(0x%lx), mapped(0x%p), size(%d)\n",
+           ioc->name, ioc->chip_phys, ioc->chip, memap_sz);
+       printk(MPT2SAS_INFO_FMT "ioport(0x%lx), size(%d)\n",
+           ioc->name, ioc->pio_chip, pio_sz);
+
+       return 0;
+
+ out_fail:
+       if (ioc->chip_phys)
+               iounmap(ioc->chip);
+       ioc->chip_phys = 0;
+       ioc->pci_irq = -1;
+       pci_release_selected_regions(ioc->pdev, ioc->bars);
+       pci_disable_device(pdev);
+       pci_set_drvdata(pdev, NULL);
+       return r;
+}
+
+/**
+ * mpt2sas_base_get_msg_frame_dma - obtain request mf pointer phys addr
+ * @ioc: per adapter object
+ * @smid: system request message index(smid zero is invalid)
+ *
+ * Returns phys pointer to message frame.
+ */
+dma_addr_t
+mpt2sas_base_get_msg_frame_dma(struct MPT2SAS_ADAPTER *ioc, u16 smid)
+{
+       return ioc->request_dma + (smid * ioc->request_sz);
+}
+
+/**
+ * mpt2sas_base_get_msg_frame - obtain request mf pointer
+ * @ioc: per adapter object
+ * @smid: system request message index(smid zero is invalid)
+ *
+ * Returns virt pointer to message frame.
+ */
+void *
+mpt2sas_base_get_msg_frame(struct MPT2SAS_ADAPTER *ioc, u16 smid)
+{
+       return (void *)(ioc->request + (smid * ioc->request_sz));
+}
+
+/**
+ * mpt2sas_base_get_sense_buffer - obtain a sense buffer assigned to a mf request
+ * @ioc: per adapter object
+ * @smid: system request message index
+ *
+ * Returns virt pointer to sense buffer.
+ */
+void *
+mpt2sas_base_get_sense_buffer(struct MPT2SAS_ADAPTER *ioc, u16 smid)
+{
+       return (void *)(ioc->sense + ((smid - 1) * SCSI_SENSE_BUFFERSIZE));
+}
+
+/**
+ * mpt2sas_base_get_sense_buffer_dma - obtain a sense buffer assigned to a mf request
+ * @ioc: per adapter object
+ * @smid: system request message index
+ *
+ * Returns phys pointer to sense buffer.
+ */
+dma_addr_t
+mpt2sas_base_get_sense_buffer_dma(struct MPT2SAS_ADAPTER *ioc, u16 smid)
+{
+       return ioc->sense_dma + ((smid - 1) * SCSI_SENSE_BUFFERSIZE);
+}
+
+/**
+ * mpt2sas_base_get_reply_virt_addr - obtain reply frames virt address
+ * @ioc: per adapter object
+ * @phys_addr: lower 32 physical addr of the reply
+ *
+ * Converts 32bit lower physical addr into a virt address.
+ */
+void *
+mpt2sas_base_get_reply_virt_addr(struct MPT2SAS_ADAPTER *ioc, u32 phys_addr)
+{
+       if (!phys_addr)
+               return NULL;
+       return ioc->reply + (phys_addr - (u32)ioc->reply_dma);
+}
+
+/**
+ * mpt2sas_base_get_smid - obtain a free smid
+ * @ioc: per adapter object
+ * @cb_idx: callback index
+ *
+ * Returns smid (zero is invalid)
+ */
+u16
+mpt2sas_base_get_smid(struct MPT2SAS_ADAPTER *ioc, u8 cb_idx)
+{
+       unsigned long flags;
+       struct request_tracker *request;
+       u16 smid;
+
+       spin_lock_irqsave(&ioc->scsi_lookup_lock, flags);
+       if (list_empty(&ioc->free_list)) {
+               spin_unlock_irqrestore(&ioc->scsi_lookup_lock, flags);
+               printk(MPT2SAS_ERR_FMT "%s: smid not available\n",
+                   ioc->name, __func__);
+               return 0;
+       }
+
+       request = list_entry(ioc->free_list.next,
+           struct request_tracker, tracker_list);
+       request->cb_idx = cb_idx;
+       smid = request->smid;
+       list_del(&request->tracker_list);
+       spin_unlock_irqrestore(&ioc->scsi_lookup_lock, flags);
+       return smid;
+}
+
+
+/**
+ * mpt2sas_base_free_smid - put smid back on free_list
+ * @ioc: per adapter object
+ * @smid: system request message index
+ *
+ * Return nothing.
+ */
+void
+mpt2sas_base_free_smid(struct MPT2SAS_ADAPTER *ioc, u16 smid)
+{
+       unsigned long flags;
+
+       spin_lock_irqsave(&ioc->scsi_lookup_lock, flags);
+       ioc->scsi_lookup[smid - 1].cb_idx = 0xFF;
+       list_add_tail(&ioc->scsi_lookup[smid - 1].tracker_list,
+           &ioc->free_list);
+       spin_unlock_irqrestore(&ioc->scsi_lookup_lock, flags);
+
+       /*
+        * See _wait_for_commands_to_complete() call with regards to this code.
+        */
+       if (ioc->shost_recovery && ioc->pending_io_count) {
+               if (ioc->pending_io_count == 1)
+                       wake_up(&ioc->reset_wq);
+               ioc->pending_io_count--;
+       }
+}
+
+/**
+ * _base_writeq - 64 bit write to MMIO
+ * @ioc: per adapter object
+ * @b: data payload
+ * @addr: address in MMIO space
+ * @writeq_lock: spin lock
+ *
+ * Glue for handling an atomic 64 bit word to MMIO. This special handling takes
+ * care of 32 bit environment where its not quarenteed to send the entire word
+ * in one transfer.
+ */
+#ifndef writeq
+static inline void _base_writeq(__u64 b, volatile void __iomem *addr,
+    spinlock_t *writeq_lock)
+{
+       unsigned long flags;
+       __u64 data_out = cpu_to_le64(b);
+
+       spin_lock_irqsave(writeq_lock, flags);
+       writel((u32)(data_out), addr);
+       writel((u32)(data_out >> 32), (addr + 4));
+       spin_unlock_irqrestore(writeq_lock, flags);
+}
+#else
+static inline void _base_writeq(__u64 b, volatile void __iomem *addr,
+    spinlock_t *writeq_lock)
+{
+       writeq(cpu_to_le64(b), addr);
+}
+#endif
+
+/**
+ * mpt2sas_base_put_smid_scsi_io - send SCSI_IO request to firmware
+ * @ioc: per adapter object
+ * @smid: system request message index
+ * @vf_id: virtual function id
+ * @handle: device handle
+ *
+ * Return nothing.
+ */
+void
+mpt2sas_base_put_smid_scsi_io(struct MPT2SAS_ADAPTER *ioc, u16 smid, u8 vf_id,
+    u16 handle)
+{
+       Mpi2RequestDescriptorUnion_t descriptor;
+       u64 *request = (u64 *)&descriptor;
+
+
+       descriptor.SCSIIO.RequestFlags = MPI2_REQ_DESCRIPT_FLAGS_SCSI_IO;
+       descriptor.SCSIIO.VF_ID = vf_id;
+       descriptor.SCSIIO.SMID = cpu_to_le16(smid);
+       descriptor.SCSIIO.DevHandle = cpu_to_le16(handle);
+       descriptor.SCSIIO.LMID = 0;
+       _base_writeq(*request, &ioc->chip->RequestDescriptorPostLow,
+           &ioc->scsi_lookup_lock);
+}
+
+
+/**
+ * mpt2sas_base_put_smid_hi_priority - send Task Managment request to firmware
+ * @ioc: per adapter object
+ * @smid: system request message index
+ * @vf_id: virtual function id
+ *
+ * Return nothing.
+ */
+void
+mpt2sas_base_put_smid_hi_priority(struct MPT2SAS_ADAPTER *ioc, u16 smid,
+    u8 vf_id)
+{
+       Mpi2RequestDescriptorUnion_t descriptor;
+       u64 *request = (u64 *)&descriptor;
+
+       descriptor.HighPriority.RequestFlags =
+           MPI2_REQ_DESCRIPT_FLAGS_HIGH_PRIORITY;
+       descriptor.HighPriority.VF_ID = vf_id;
+       descriptor.HighPriority.SMID = cpu_to_le16(smid);
+       descriptor.HighPriority.LMID = 0;
+       descriptor.HighPriority.Reserved1 = 0;
+       _base_writeq(*request, &ioc->chip->RequestDescriptorPostLow,
+           &ioc->scsi_lookup_lock);
+}
+
+/**
+ * mpt2sas_base_put_smid_default - Default, primarily used for config pages
+ * @ioc: per adapter object
+ * @smid: system request message index
+ * @vf_id: virtual function id
+ *
+ * Return nothing.
+ */
+void
+mpt2sas_base_put_smid_default(struct MPT2SAS_ADAPTER *ioc, u16 smid, u8 vf_id)
+{
+       Mpi2RequestDescriptorUnion_t descriptor;
+       u64 *request = (u64 *)&descriptor;
+
+       descriptor.Default.RequestFlags = MPI2_REQ_DESCRIPT_FLAGS_DEFAULT_TYPE;
+       descriptor.Default.VF_ID = vf_id;
+       descriptor.Default.SMID = cpu_to_le16(smid);
+       descriptor.Default.LMID = 0;
+       descriptor.Default.DescriptorTypeDependent = 0;
+       _base_writeq(*request, &ioc->chip->RequestDescriptorPostLow,
+           &ioc->scsi_lookup_lock);
+}
+
+/**
+ * mpt2sas_base_put_smid_target_assist - send Target Assist/Status to firmware
+ * @ioc: per adapter object
+ * @smid: system request message index
+ * @vf_id: virtual function id
+ * @io_index: value used to track the IO
+ *
+ * Return nothing.
+ */
+void
+mpt2sas_base_put_smid_target_assist(struct MPT2SAS_ADAPTER *ioc, u16 smid,
+    u8 vf_id, u16 io_index)
+{
+       Mpi2RequestDescriptorUnion_t descriptor;
+       u64 *request = (u64 *)&descriptor;
+
+       descriptor.SCSITarget.RequestFlags =
+           MPI2_REQ_DESCRIPT_FLAGS_SCSI_TARGET;
+       descriptor.SCSITarget.VF_ID = vf_id;
+       descriptor.SCSITarget.SMID = cpu_to_le16(smid);
+       descriptor.SCSITarget.LMID = 0;
+       descriptor.SCSITarget.IoIndex = cpu_to_le16(io_index);
+       _base_writeq(*request, &ioc->chip->RequestDescriptorPostLow,
+           &ioc->scsi_lookup_lock);
+}
+
+/**
+ * _base_display_ioc_capabilities - Disply IOC's capabilities.
+ * @ioc: per adapter object
+ *
+ * Return nothing.
+ */
+static void
+_base_display_ioc_capabilities(struct MPT2SAS_ADAPTER *ioc)
+{
+       int i = 0;
+       char desc[16];
+       u8 revision;
+       u32 iounit_pg1_flags;
+
+       pci_read_config_byte(ioc->pdev, PCI_CLASS_REVISION, &revision);
+       strncpy(desc, ioc->manu_pg0.ChipName, 16);
+       printk(MPT2SAS_INFO_FMT "%s: FWVersion(%02d.%02d.%02d.%02d), "
+          "ChipRevision(0x%02x), BiosVersion(%02d.%02d.%02d.%02d)\n",
+           ioc->name, desc,
+          (ioc->facts.FWVersion.Word & 0xFF000000) >> 24,
+          (ioc->facts.FWVersion.Word & 0x00FF0000) >> 16,
+          (ioc->facts.FWVersion.Word & 0x0000FF00) >> 8,
+          ioc->facts.FWVersion.Word & 0x000000FF,
+          revision,
+          (ioc->bios_pg3.BiosVersion & 0xFF000000) >> 24,
+          (ioc->bios_pg3.BiosVersion & 0x00FF0000) >> 16,
+          (ioc->bios_pg3.BiosVersion & 0x0000FF00) >> 8,
+           ioc->bios_pg3.BiosVersion & 0x000000FF);
+
+       printk(MPT2SAS_INFO_FMT "Protocol=(", ioc->name);
+
+       if (ioc->facts.ProtocolFlags & MPI2_IOCFACTS_PROTOCOL_SCSI_INITIATOR) {
+               printk("Initiator");
+               i++;
+       }
+
+       if (ioc->facts.ProtocolFlags & MPI2_IOCFACTS_PROTOCOL_SCSI_TARGET) {
+               printk("%sTarget", i ? "," : "");
+               i++;
+       }
+
+       i = 0;
+       printk("), ");
+       printk("Capabilities=(");
+
+       if (ioc->facts.IOCCapabilities &
+           MPI2_IOCFACTS_CAPABILITY_INTEGRATED_RAID) {
+               printk("Raid");
+               i++;
+       }
+
+       if (ioc->facts.IOCCapabilities & MPI2_IOCFACTS_CAPABILITY_TLR) {
+               printk("%sTLR", i ? "," : "");
+               i++;
+       }
+
+       if (ioc->facts.IOCCapabilities & MPI2_IOCFACTS_CAPABILITY_MULTICAST) {
+               printk("%sMulticast", i ? "," : "");
+               i++;
+       }
+
+       if (ioc->facts.IOCCapabilities &
+           MPI2_IOCFACTS_CAPABILITY_BIDIRECTIONAL_TARGET) {
+               printk("%sBIDI Target", i ? "," : "");
+               i++;
+       }
+
+       if (ioc->facts.IOCCapabilities & MPI2_IOCFACTS_CAPABILITY_EEDP) {
+               printk("%sEEDP", i ? "," : "");
+               i++;
+       }
+
+       if (ioc->facts.IOCCapabilities &
+           MPI2_IOCFACTS_CAPABILITY_SNAPSHOT_BUFFER) {
+               printk("%sSnapshot Buffer", i ? "," : "");
+               i++;
+       }
+
+       if (ioc->facts.IOCCapabilities &
+           MPI2_IOCFACTS_CAPABILITY_DIAG_TRACE_BUFFER) {
+               printk("%sDiag Trace Buffer", i ? "," : "");
+               i++;
+       }
+
+       if (ioc->facts.IOCCapabilities &
+           MPI2_IOCFACTS_CAPABILITY_TASK_SET_FULL_HANDLING) {
+               printk("%sTask Set Full", i ? "," : "");
+               i++;
+       }
+
+       iounit_pg1_flags = le32_to_cpu(ioc->iounit_pg1.Flags);
+       if (!(iounit_pg1_flags & MPI2_IOUNITPAGE1_NATIVE_COMMAND_Q_DISABLE)) {
+               printk("%sNCQ", i ? "," : "");
+               i++;
+       }
+
+       printk(")\n");
+}
+
+/**
+ * _base_static_config_pages - static start of day config pages
+ * @ioc: per adapter object
+ *
+ * Return nothing.
+ */
+static void
+_base_static_config_pages(struct MPT2SAS_ADAPTER *ioc)
+{
+       Mpi2ConfigReply_t mpi_reply;
+       u32 iounit_pg1_flags;
+
+       mpt2sas_config_get_manufacturing_pg0(ioc, &mpi_reply, &ioc->manu_pg0);
+       mpt2sas_config_get_bios_pg2(ioc, &mpi_reply, &ioc->bios_pg2);
+       mpt2sas_config_get_bios_pg3(ioc, &mpi_reply, &ioc->bios_pg3);
+       mpt2sas_config_get_ioc_pg8(ioc, &mpi_reply, &ioc->ioc_pg8);
+       mpt2sas_config_get_iounit_pg0(ioc, &mpi_reply, &ioc->iounit_pg0);
+       mpt2sas_config_get_iounit_pg1(ioc, &mpi_reply, &ioc->iounit_pg1);
+       _base_display_ioc_capabilities(ioc);
+
+       /*
+        * Enable task_set_full handling in iounit_pg1 when the
+        * facts capabilities indicate that its supported.
+        */
+       iounit_pg1_flags = le32_to_cpu(ioc->iounit_pg1.Flags);
+       if ((ioc->facts.IOCCapabilities &
+           MPI2_IOCFACTS_CAPABILITY_TASK_SET_FULL_HANDLING))
+               iounit_pg1_flags &=
+                   ~MPI2_IOUNITPAGE1_DISABLE_TASK_SET_FULL_HANDLING;
+       else
+               iounit_pg1_flags |=
+                   MPI2_IOUNITPAGE1_DISABLE_TASK_SET_FULL_HANDLING;
+       ioc->iounit_pg1.Flags = cpu_to_le32(iounit_pg1_flags);
+       mpt2sas_config_set_iounit_pg1(ioc, &mpi_reply, ioc->iounit_pg1);
+}
+
+/**
+ * _base_release_memory_pools - release memory
+ * @ioc: per adapter object
+ *
+ * Free memory allocated from _base_allocate_memory_pools.
+ *
+ * Return nothing.
+ */
+static void
+_base_release_memory_pools(struct MPT2SAS_ADAPTER *ioc)
+{
+       dexitprintk(ioc, printk(MPT2SAS_DEBUG_FMT "%s\n", ioc->name,
+           __func__));
+
+       if (ioc->request) {
+               pci_free_consistent(ioc->pdev, ioc->request_dma_sz,
+                   ioc->request,  ioc->request_dma);
+               dexitprintk(ioc, printk(MPT2SAS_INFO_FMT "request_pool(0x%p)"
+                   ": free\n", ioc->name, ioc->request));
+               ioc->request = NULL;
+       }
+
+       if (ioc->sense) {
+               pci_pool_free(ioc->sense_dma_pool, ioc->sense, ioc->sense_dma);
+               if (ioc->sense_dma_pool)
+                       pci_pool_destroy(ioc->sense_dma_pool);
+               dexitprintk(ioc, printk(MPT2SAS_INFO_FMT "sense_pool(0x%p)"
+                   ": free\n", ioc->name, ioc->sense));
+               ioc->sense = NULL;
+       }
+
+       if (ioc->reply) {
+               pci_pool_free(ioc->reply_dma_pool, ioc->reply, ioc->reply_dma);
+               if (ioc->reply_dma_pool)
+                       pci_pool_destroy(ioc->reply_dma_pool);
+               dexitprintk(ioc, printk(MPT2SAS_INFO_FMT "reply_pool(0x%p)"
+                    ": free\n", ioc->name, ioc->reply));
+               ioc->reply = NULL;
+       }
+
+       if (ioc->reply_free) {
+               pci_pool_free(ioc->reply_free_dma_pool, ioc->reply_free,
+                   ioc->reply_free_dma);
+               if (ioc->reply_free_dma_pool)
+                       pci_pool_destroy(ioc->reply_free_dma_pool);
+               dexitprintk(ioc, printk(MPT2SAS_INFO_FMT "reply_free_pool"
+                   "(0x%p): free\n", ioc->name, ioc->reply_free));
+               ioc->reply_free = NULL;
+       }
+
+       if (ioc->reply_post_free) {
+               pci_pool_free(ioc->reply_post_free_dma_pool,
+                   ioc->reply_post_free, ioc->reply_post_free_dma);
+               if (ioc->reply_post_free_dma_pool)
+                       pci_pool_destroy(ioc->reply_post_free_dma_pool);
+               dexitprintk(ioc, printk(MPT2SAS_INFO_FMT
+                   "reply_post_free_pool(0x%p): free\n", ioc->name,
+                   ioc->reply_post_free));
+               ioc->reply_post_free = NULL;
+       }
+
+       if (ioc->config_page) {
+               dexitprintk(ioc, printk(MPT2SAS_INFO_FMT
+                   "config_page(0x%p): free\n", ioc->name,
+                   ioc->config_page));
+               pci_free_consistent(ioc->pdev, ioc->config_page_sz,
+                   ioc->config_page, ioc->config_page_dma);
+       }
+
+       kfree(ioc->scsi_lookup);
+}
+
+
+/**
+ * _base_allocate_memory_pools - allocate start of day memory pools
+ * @ioc: per adapter object
+ * @sleep_flag: CAN_SLEEP or NO_SLEEP
+ *
+ * Returns 0 success, anything else error
+ */
+static int
+_base_allocate_memory_pools(struct MPT2SAS_ADAPTER *ioc,  int sleep_flag)
+{
+       Mpi2IOCFactsReply_t *facts;
+       u32 queue_size, queue_diff;
+       u16 max_sge_elements;
+       u16 num_of_reply_frames;
+       u16 chains_needed_per_io;
+       u32 sz, total_sz;
+       u16 i;
+       u32 retry_sz;
+       u16 max_request_credit;
+
+       dinitprintk(ioc, printk(MPT2SAS_DEBUG_FMT "%s\n", ioc->name,
+           __func__));
+
+       retry_sz = 0;
+       facts = &ioc->facts;
+
+       /* command line tunables  for max sgl entries */
+       if (max_sgl_entries != -1) {
+               ioc->shost->sg_tablesize = (max_sgl_entries <
+                   MPT2SAS_SG_DEPTH) ? max_sgl_entries :
+                   MPT2SAS_SG_DEPTH;
+       } else {
+               ioc->shost->sg_tablesize = MPT2SAS_SG_DEPTH;
+       }
+
+       /* command line tunables  for max controller queue depth */
+       if (max_queue_depth != -1) {
+               max_request_credit = (max_queue_depth < facts->RequestCredit)
+                   ? max_queue_depth : facts->RequestCredit;
+       } else {
+               max_request_credit = (facts->RequestCredit >
+                   MPT2SAS_MAX_REQUEST_QUEUE) ? MPT2SAS_MAX_REQUEST_QUEUE :
+                   facts->RequestCredit;
+       }
+       ioc->request_depth = max_request_credit;
+
+       /* request frame size */
+       ioc->request_sz = facts->IOCRequestFrameSize * 4;
+
+       /* reply frame size */
+       ioc->reply_sz = facts->ReplyFrameSize * 4;
+
+ retry_allocation:
+       total_sz = 0;
+       /* calculate number of sg elements left over in the 1st frame */
+       max_sge_elements = ioc->request_sz - ((sizeof(Mpi2SCSIIORequest_t) -
+           sizeof(Mpi2SGEIOUnion_t)) + ioc->sge_size);
+       ioc->max_sges_in_main_message = max_sge_elements/ioc->sge_size;
+
+       /* now do the same for a chain buffer */
+       max_sge_elements = ioc->request_sz - ioc->sge_size;
+       ioc->max_sges_in_chain_message = max_sge_elements/ioc->sge_size;
+
+       ioc->chain_offset_value_for_main_message =
+           ((sizeof(Mpi2SCSIIORequest_t) - sizeof(Mpi2SGEIOUnion_t)) +
+            (ioc->max_sges_in_chain_message * ioc->sge_size)) / 4;
+
+       /*
+        *  MPT2SAS_SG_DEPTH = CONFIG_FUSION_MAX_SGE
+        */
+       chains_needed_per_io = ((ioc->shost->sg_tablesize -
+          ioc->max_sges_in_main_message)/ioc->max_sges_in_chain_message)
+           + 1;
+       if (chains_needed_per_io > facts->MaxChainDepth) {
+               chains_needed_per_io = facts->MaxChainDepth;
+               ioc->shost->sg_tablesize = min_t(u16,
+               ioc->max_sges_in_main_message + (ioc->max_sges_in_chain_message
+               * chains_needed_per_io), ioc->shost->sg_tablesize);
+       }
+       ioc->chains_needed_per_io = chains_needed_per_io;
+
+       /* reply free queue sizing - taking into account for events */
+       num_of_reply_frames = ioc->request_depth + 32;
+
+       /* number of replies frames can't be a multiple of 16 */
+       /* decrease number of reply frames by 1 */
+       if (!(num_of_reply_frames % 16))
+               num_of_reply_frames--;
+
+       /* calculate number of reply free queue entries
+        *  (must be multiple of 16)
+        */
+
+       /* (we know reply_free_queue_depth is not a multiple of 16) */
+       queue_size = num_of_reply_frames;
+       queue_size += 16 - (queue_size % 16);
+       ioc->reply_free_queue_depth = queue_size;
+
+       /* reply descriptor post queue sizing */
+       /* this size should be the number of request frames + number of reply
+        * frames
+        */
+
+       queue_size = ioc->request_depth + num_of_reply_frames + 1;
+       /* round up to 16 byte boundary */
+       if (queue_size % 16)
+               queue_size += 16 - (queue_size % 16);
+
+       /* check against IOC maximum reply post queue depth */
+       if (queue_size > facts->MaxReplyDescriptorPostQueueDepth) {
+               queue_diff = queue_size -
+                   facts->MaxReplyDescriptorPostQueueDepth;
+
+               /* round queue_diff up to multiple of 16 */
+               if (queue_diff % 16)
+                       queue_diff += 16 - (queue_diff % 16);
+
+               /* adjust request_depth, reply_free_queue_depth,
+                * and queue_size
+                */
+               ioc->request_depth -= queue_diff;
+               ioc->reply_free_queue_depth -= queue_diff;
+               queue_size -= queue_diff;
+       }
+       ioc->reply_post_queue_depth = queue_size;
+
+       /* max scsi host queue depth */
+       ioc->shost->can_queue = ioc->request_depth - INTERNAL_CMDS_COUNT;
+       dinitprintk(ioc, printk(MPT2SAS_INFO_FMT "scsi host queue: depth"
+           "(%d)\n", ioc->name, ioc->shost->can_queue));
+
+       dinitprintk(ioc, printk(MPT2SAS_INFO_FMT "scatter gather: "
+           "sge_in_main_msg(%d), sge_per_chain(%d), sge_per_io(%d), "
+           "chains_per_io(%d)\n", ioc->name, ioc->max_sges_in_main_message,
+           ioc->max_sges_in_chain_message, ioc->shost->sg_tablesize,
+           ioc->chains_needed_per_io));
+
+       /* contiguous pool for request and chains, 16 byte align, one extra "
+        * "frame for smid=0
+        */
+       ioc->chain_depth = ioc->chains_needed_per_io * ioc->request_depth;
+       sz = ((ioc->request_depth + 1 + ioc->chain_depth) * ioc->request_sz);
+
+       ioc->request_dma_sz = sz;
+       ioc->request = pci_alloc_consistent(ioc->pdev, sz, &ioc->request_dma);
+       if (!ioc->request) {
+               printk(MPT2SAS_ERR_FMT "request pool: pci_alloc_consistent "
+                   "failed: req_depth(%d), chains_per_io(%d), frame_sz(%d), "
+                   "total(%d kB)\n", ioc->name, ioc->request_depth,
+                   ioc->chains_needed_per_io, ioc->request_sz, sz/1024);
+               if (ioc->request_depth < MPT2SAS_SAS_QUEUE_DEPTH)
+                       goto out;
+               retry_sz += 64;
+               ioc->request_depth = max_request_credit - retry_sz;
+               goto retry_allocation;
+       }
+
+       if (retry_sz)
+               printk(MPT2SAS_ERR_FMT "request pool: pci_alloc_consistent "
+                   "succeed: req_depth(%d), chains_per_io(%d), frame_sz(%d), "
+                   "total(%d kb)\n", ioc->name, ioc->request_depth,
+                   ioc->chains_needed_per_io, ioc->request_sz, sz/1024);
+
+       ioc->chain = ioc->request + ((ioc->request_depth + 1) *
+           ioc->request_sz);
+       ioc->chain_dma = ioc->request_dma + ((ioc->request_depth + 1) *
+           ioc->request_sz);
+       dinitprintk(ioc, printk(MPT2SAS_INFO_FMT "request pool(0x%p): "
+           "depth(%d), frame_size(%d), pool_size(%d kB)\n", ioc->name,
+           ioc->request, ioc->request_depth, ioc->request_sz,
+           ((ioc->request_depth + 1) * ioc->request_sz)/1024));
+       dinitprintk(ioc, printk(MPT2SAS_INFO_FMT "chain pool(0x%p): depth"
+           "(%d), frame_size(%d), pool_size(%d kB)\n", ioc->name, ioc->chain,
+           ioc->chain_depth, ioc->request_sz, ((ioc->chain_depth *
+           ioc->request_sz))/1024));
+       dinitprintk(ioc, printk(MPT2SAS_INFO_FMT "request pool: dma(0x%llx)\n",
+           ioc->name, (unsigned long long) ioc->request_dma));
+       total_sz += sz;
+
+       ioc->scsi_lookup = kcalloc(ioc->request_depth,
+           sizeof(struct request_tracker), GFP_KERNEL);
+       if (!ioc->scsi_lookup) {
+               printk(MPT2SAS_ERR_FMT "scsi_lookup: kcalloc failed\n",
+                   ioc->name);
+               goto out;
+       }
+
+        /* initialize some bits */
+       for (i = 0; i < ioc->request_depth; i++)
+               ioc->scsi_lookup[i].smid = i + 1;
+
+       /* sense buffers, 4 byte align */
+       sz = ioc->request_depth * SCSI_SENSE_BUFFERSIZE;
+       ioc->sense_dma_pool = pci_pool_create("sense pool", ioc->pdev, sz, 4,
+           0);
+       if (!ioc->sense_dma_pool) {
+               printk(MPT2SAS_ERR_FMT "sense pool: pci_pool_create failed\n",
+                   ioc->name);
+               goto out;
+       }
+       ioc->sense = pci_pool_alloc(ioc->sense_dma_pool , GFP_KERNEL,
+           &ioc->sense_dma);
+       if (!ioc->sense) {
+               printk(MPT2SAS_ERR_FMT "sense pool: pci_pool_alloc failed\n",
+                   ioc->name);
+               goto out;
+       }
+       dinitprintk(ioc, printk(MPT2SAS_INFO_FMT
+           "sense pool(0x%p): depth(%d), element_size(%d), pool_size"
+           "(%d kB)\n", ioc->name, ioc->sense, ioc->request_depth,
+           SCSI_SENSE_BUFFERSIZE, sz/1024));
+       dinitprintk(ioc, printk(MPT2SAS_INFO_FMT "sense_dma(0x%llx)\n",
+           ioc->name, (unsigned long long)ioc->sense_dma));
+       total_sz += sz;
+
+       /* reply pool, 4 byte align */
+       sz = ioc->reply_free_queue_depth * ioc->reply_sz;
+       ioc->reply_dma_pool = pci_pool_create("reply pool", ioc->pdev, sz, 4,
+           0);
+       if (!ioc->reply_dma_pool) {
+               printk(MPT2SAS_ERR_FMT "reply pool: pci_pool_create failed\n",
+                   ioc->name);
+               goto out;
+       }
+       ioc->reply = pci_pool_alloc(ioc->reply_dma_pool , GFP_KERNEL,
+           &ioc->reply_dma);
+       if (!ioc->reply) {
+               printk(MPT2SAS_ERR_FMT "reply pool: pci_pool_alloc failed\n",
+                   ioc->name);
+               goto out;
+       }
+       dinitprintk(ioc, printk(MPT2SAS_INFO_FMT "reply pool(0x%p): depth"
+           "(%d), frame_size(%d), pool_size(%d kB)\n", ioc->name, ioc->reply,
+           ioc->reply_free_queue_depth, ioc->reply_sz, sz/1024));
+       dinitprintk(ioc, printk(MPT2SAS_INFO_FMT "reply_dma(0x%llx)\n",
+           ioc->name, (unsigned long long)ioc->reply_dma));
+       total_sz += sz;
+
+       /* reply free queue, 16 byte align */
+       sz = ioc->reply_free_queue_depth * 4;
+       ioc->reply_free_dma_pool = pci_pool_create("reply_free pool",
+           ioc->pdev, sz, 16, 0);
+       if (!ioc->reply_free_dma_pool) {
+               printk(MPT2SAS_ERR_FMT "reply_free pool: pci_pool_create "
+                   "failed\n", ioc->name);
+               goto out;
+       }
+       ioc->reply_free = pci_pool_alloc(ioc->reply_free_dma_pool , GFP_KERNEL,
+           &ioc->reply_free_dma);
+       if (!ioc->reply_free) {
+               printk(MPT2SAS_ERR_FMT "reply_free pool: pci_pool_alloc "
+                   "failed\n", ioc->name);
+               goto out;
+       }
+       memset(ioc->reply_free, 0, sz);
+       dinitprintk(ioc, printk(MPT2SAS_INFO_FMT "reply_free pool(0x%p): "
+           "depth(%d), element_size(%d), pool_size(%d kB)\n", ioc->name,
+           ioc->reply_free, ioc->reply_free_queue_depth, 4, sz/1024));
+       dinitprintk(ioc, printk(MPT2SAS_INFO_FMT "reply_free_dma"
+           "(0x%llx)\n", ioc->name, (unsigned long long)ioc->reply_free_dma));
+       total_sz += sz;
+
+       /* reply post queue, 16 byte align */
+       sz = ioc->reply_post_queue_depth * sizeof(Mpi2DefaultReplyDescriptor_t);
+       ioc->reply_post_free_dma_pool = pci_pool_create("reply_post_free pool",
+           ioc->pdev, sz, 16, 0);
+       if (!ioc->reply_post_free_dma_pool) {
+               printk(MPT2SAS_ERR_FMT "reply_post_free pool: pci_pool_create "
+                   "failed\n", ioc->name);
+               goto out;
+       }
+       ioc->reply_post_free = pci_pool_alloc(ioc->reply_post_free_dma_pool ,
+           GFP_KERNEL, &ioc->reply_post_free_dma);
+       if (!ioc->reply_post_free) {
+               printk(MPT2SAS_ERR_FMT "reply_post_free pool: pci_pool_alloc "
+                   "failed\n", ioc->name);
+               goto out;
+       }
+       memset(ioc->reply_post_free, 0, sz);
+       dinitprintk(ioc, printk(MPT2SAS_INFO_FMT "reply post free pool"
+           "(0x%p): depth(%d), element_size(%d), pool_size(%d kB)\n",
+           ioc->name, ioc->reply_post_free, ioc->reply_post_queue_depth, 8,
+           sz/1024));
+       dinitprintk(ioc, printk(MPT2SAS_INFO_FMT "reply_post_free_dma = "
+           "(0x%llx)\n", ioc->name, (unsigned long long)
+           ioc->reply_post_free_dma));
+       total_sz += sz;
+
+       ioc->config_page_sz = 512;
+       ioc->config_page = pci_alloc_consistent(ioc->pdev,
+           ioc->config_page_sz, &ioc->config_page_dma);
+       if (!ioc->config_page) {
+               printk(MPT2SAS_ERR_FMT "config page: pci_pool_alloc "
+                   "failed\n", ioc->name);
+               goto out;
+       }
+       dinitprintk(ioc, printk(MPT2SAS_INFO_FMT "config page(0x%p): size"
+           "(%d)\n", ioc->name, ioc->config_page, ioc->config_page_sz));
+       dinitprintk(ioc, printk(MPT2SAS_INFO_FMT "config_page_dma"
+           "(0x%llx)\n", ioc->name, (unsigned long long)ioc->config_page_dma));
+       total_sz += ioc->config_page_sz;
+
+       printk(MPT2SAS_INFO_FMT "Allocated physical memory: size(%d kB)\n",
+           ioc->name, total_sz/1024);
+       printk(MPT2SAS_INFO_FMT "Current Controller Queue Depth(%d), "
+           "Max Controller Queue Depth(%d)\n",
+           ioc->name, ioc->shost->can_queue, facts->RequestCredit);
+       printk(MPT2SAS_INFO_FMT "Scatter Gather Elements per IO(%d)\n",
+           ioc->name, ioc->shost->sg_tablesize);
+       return 0;
+
+ out:
+       _base_release_memory_pools(ioc);
+       return -ENOMEM;
+}
+
+
+/**
+ * mpt2sas_base_get_iocstate - Get the current state of a MPT adapter.
+ * @ioc: Pointer to MPT_ADAPTER structure
+ * @cooked: Request raw or cooked IOC state
+ *
+ * Returns all IOC Doorbell register bits if cooked==0, else just the
+ * Doorbell bits in MPI_IOC_STATE_MASK.
+ */
+u32
+mpt2sas_base_get_iocstate(struct MPT2SAS_ADAPTER *ioc, int cooked)
+{
+       u32 s, sc;
+
+       s = readl(&ioc->chip->Doorbell);
+       sc = s & MPI2_IOC_STATE_MASK;
+       return cooked ? sc : s;
+}
+
+/**
+ * _base_wait_on_iocstate - waiting on a particular ioc state
+ * @ioc_state: controller state { READY, OPERATIONAL, or RESET }
+ * @timeout: timeout in second
+ * @sleep_flag: CAN_SLEEP or NO_SLEEP
+ *
+ * Returns 0 for success, non-zero for failure.
+ */
+static int
+_base_wait_on_iocstate(struct MPT2SAS_ADAPTER *ioc, u32 ioc_state, int timeout,
+    int sleep_flag)
+{
+       u32 count, cntdn;
+       u32 current_state;
+
+       count = 0;
+       cntdn = (sleep_flag == CAN_SLEEP) ? 1000*timeout : 2000*timeout;
+       do {
+               current_state = mpt2sas_base_get_iocstate(ioc, 1);
+               if (current_state == ioc_state)
+                       return 0;
+               if (count && current_state == MPI2_IOC_STATE_FAULT)
+                       break;
+               if (sleep_flag == CAN_SLEEP)
+                       msleep(1);
+               else
+                       udelay(500);
+               count++;
+       } while (--cntdn);
+
+       return current_state;
+}
+
+/**
+ * _base_wait_for_doorbell_int - waiting for controller interrupt(generated by
+ * a write to the doorbell)
+ * @ioc: per adapter object
+ * @timeout: timeout in second
+ * @sleep_flag: CAN_SLEEP or NO_SLEEP
+ *
+ * Returns 0 for success, non-zero for failure.
+ *
+ * Notes: MPI2_HIS_IOC2SYS_DB_STATUS - set to one when IOC writes to doorbell.
+ */
+static int
+_base_wait_for_doorbell_int(struct MPT2SAS_ADAPTER *ioc, int timeout,
+    int sleep_flag)
+{
+       u32 cntdn, count;
+       u32 int_status;
+
+       count = 0;
+       cntdn = (sleep_flag == CAN_SLEEP) ? 1000*timeout : 2000*timeout;
+       do {
+               int_status = readl(&ioc->chip->HostInterruptStatus);
+               if (int_status & MPI2_HIS_IOC2SYS_DB_STATUS) {
+                       dhsprintk(ioc, printk(MPT2SAS_DEBUG_FMT "%s: "
+                           "successfull count(%d), timeout(%d)\n", ioc->name,
+                           __func__, count, timeout));
+                       return 0;
+               }
+               if (sleep_flag == CAN_SLEEP)
+                       msleep(1);
+               else
+                       udelay(500);
+               count++;
+       } while (--cntdn);
+
+       printk(MPT2SAS_ERR_FMT "%s: failed due to timeout count(%d), "
+           "int_status(%x)!\n", ioc->name, __func__, count, int_status);
+       return -EFAULT;
+}
+
+/**
+ * _base_wait_for_doorbell_ack - waiting for controller to read the doorbell.
+ * @ioc: per adapter object
+ * @timeout: timeout in second
+ * @sleep_flag: CAN_SLEEP or NO_SLEEP
+ *
+ * Returns 0 for success, non-zero for failure.
+ *
+ * Notes: MPI2_HIS_SYS2IOC_DB_STATUS - set to one when host writes to
+ * doorbell.
+ */
+static int
+_base_wait_for_doorbell_ack(struct MPT2SAS_ADAPTER *ioc, int timeout,
+    int sleep_flag)
+{
+       u32 cntdn, count;
+       u32 int_status;
+       u32 doorbell;
+
+       count = 0;
+       cntdn = (sleep_flag == CAN_SLEEP) ? 1000*timeout : 2000*timeout;
+       do {
+               int_status = readl(&ioc->chip->HostInterruptStatus);
+               if (!(int_status & MPI2_HIS_SYS2IOC_DB_STATUS)) {
+                       dhsprintk(ioc, printk(MPT2SAS_DEBUG_FMT "%s: "
+                           "successfull count(%d), timeout(%d)\n", ioc->name,
+                           __func__, count, timeout));
+                       return 0;
+               } else if (int_status & MPI2_HIS_IOC2SYS_DB_STATUS) {
+                       doorbell = readl(&ioc->chip->Doorbell);
+                       if ((doorbell & MPI2_IOC_STATE_MASK) ==
+                           MPI2_IOC_STATE_FAULT) {
+                               mpt2sas_base_fault_info(ioc , doorbell);
+                               return -EFAULT;
+                       }
+               } else if (int_status == 0xFFFFFFFF)
+                       goto out;
+
+               if (sleep_flag == CAN_SLEEP)
+                       msleep(1);
+               else
+                       udelay(500);
+               count++;
+       } while (--cntdn);
+
+ out:
+       printk(MPT2SAS_ERR_FMT "%s: failed due to timeout count(%d), "
+           "int_status(%x)!\n", ioc->name, __func__, count, int_status);
+       return -EFAULT;
+}
+
+/**
+ * _base_wait_for_doorbell_not_used - waiting for doorbell to not be in use
+ * @ioc: per adapter object
+ * @timeout: timeout in second
+ * @sleep_flag: CAN_SLEEP or NO_SLEEP
+ *
+ * Returns 0 for success, non-zero for failure.
+ *
+ */
+static int
+_base_wait_for_doorbell_not_used(struct MPT2SAS_ADAPTER *ioc, int timeout,
+    int sleep_flag)
+{
+       u32 cntdn, count;
+       u32 doorbell_reg;
+
+       count = 0;
+       cntdn = (sleep_flag == CAN_SLEEP) ? 1000*timeout : 2000*timeout;
+       do {
+               doorbell_reg = readl(&ioc->chip->Doorbell);
+               if (!(doorbell_reg & MPI2_DOORBELL_USED)) {
+                       dhsprintk(ioc, printk(MPT2SAS_DEBUG_FMT "%s: "
+                           "successfull count(%d), timeout(%d)\n", ioc->name,
+                           __func__, count, timeout));
+                       return 0;
+               }
+               if (sleep_flag == CAN_SLEEP)
+                       msleep(1);
+               else
+                       udelay(500);
+               count++;
+       } while (--cntdn);
+
+       printk(MPT2SAS_ERR_FMT "%s: failed due to timeout count(%d), "
+           "doorbell_reg(%x)!\n", ioc->name, __func__, count, doorbell_reg);
+       return -EFAULT;
+}
+
+/**
+ * _base_send_ioc_reset - send doorbell reset
+ * @ioc: per adapter object
+ * @reset_type: currently only supports: MPI2_FUNCTION_IOC_MESSAGE_UNIT_RESET
+ * @timeout: timeout in second
+ * @sleep_flag: CAN_SLEEP or NO_SLEEP
+ *
+ * Returns 0 for success, non-zero for failure.
+ */
+static int
+_base_send_ioc_reset(struct MPT2SAS_ADAPTER *ioc, u8 reset_type, int timeout,
+    int sleep_flag)
+{
+       u32 ioc_state;
+       int r = 0;
+
+       if (reset_type != MPI2_FUNCTION_IOC_MESSAGE_UNIT_RESET) {
+               printk(MPT2SAS_ERR_FMT "%s: unknown reset_type\n",
+                   ioc->name, __func__);
+               return -EFAULT;
+       }
+
+       if (!(ioc->facts.IOCCapabilities &
+          MPI2_IOCFACTS_CAPABILITY_EVENT_REPLAY))
+               return -EFAULT;
+
+       printk(MPT2SAS_INFO_FMT "sending message unit reset !!\n", ioc->name);
+
+       writel(reset_type << MPI2_DOORBELL_FUNCTION_SHIFT,
+           &ioc->chip->Doorbell);
+       if ((_base_wait_for_doorbell_ack(ioc, 15, sleep_flag))) {
+               r = -EFAULT;
+               goto out;
+       }
+       ioc_state = _base_wait_on_iocstate(ioc, MPI2_IOC_STATE_READY,
+           timeout, sleep_flag);
+       if (ioc_state) {
+               printk(MPT2SAS_ERR_FMT "%s: failed going to ready state "
+                   " (ioc_state=0x%x)\n", ioc->name, __func__, ioc_state);
+               r = -EFAULT;
+               goto out;
+       }
+ out:
+       printk(MPT2SAS_INFO_FMT "message unit reset: %s\n",
+           ioc->name, ((r == 0) ? "SUCCESS" : "FAILED"));
+       return r;
+}
+
+/**
+ * _base_handshake_req_reply_wait - send request thru doorbell interface
+ * @ioc: per adapter object
+ * @request_bytes: request length
+ * @request: pointer having request payload
+ * @reply_bytes: reply length
+ * @reply: pointer to reply payload
+ * @timeout: timeout in second
+ * @sleep_flag: CAN_SLEEP or NO_SLEEP
+ *
+ * Returns 0 for success, non-zero for failure.
+ */
+static int
+_base_handshake_req_reply_wait(struct MPT2SAS_ADAPTER *ioc, int request_bytes,
+    u32 *request, int reply_bytes, u16 *reply, int timeout, int sleep_flag)
+{
+       MPI2DefaultReply_t *default_reply = (MPI2DefaultReply_t *)reply;
+       int i;
+       u8 failed;
+       u16 dummy;
+       u32 *mfp;
+
+       /* make sure doorbell is not in use */
+       if ((readl(&ioc->chip->Doorbell) & MPI2_DOORBELL_USED)) {
+               printk(MPT2SAS_ERR_FMT "doorbell is in use "
+                   " (line=%d)\n", ioc->name, __LINE__);
+               return -EFAULT;
+       }
+
+       /* clear pending doorbell interrupts from previous state changes */
+       if (readl(&ioc->chip->HostInterruptStatus) &
+           MPI2_HIS_IOC2SYS_DB_STATUS)
+               writel(0, &ioc->chip->HostInterruptStatus);
+
+       /* send message to ioc */
+       writel(((MPI2_FUNCTION_HANDSHAKE<<MPI2_DOORBELL_FUNCTION_SHIFT) |
+           ((request_bytes/4)<<MPI2_DOORBELL_ADD_DWORDS_SHIFT)),
+           &ioc->chip->Doorbell);
+
+       if ((_base_wait_for_doorbell_int(ioc, 5, sleep_flag))) {
+               printk(MPT2SAS_ERR_FMT "doorbell handshake "
+                  "int failed (line=%d)\n", ioc->name, __LINE__);
+               return -EFAULT;
+       }
+       writel(0, &ioc->chip->HostInterruptStatus);
+
+       if ((_base_wait_for_doorbell_ack(ioc, 5, sleep_flag))) {
+               printk(MPT2SAS_ERR_FMT "doorbell handshake "
+                   "ack failed (line=%d)\n", ioc->name, __LINE__);
+               return -EFAULT;
+       }
+
+       /* send message 32-bits at a time */
+       for (i = 0, failed = 0; i < request_bytes/4 && !failed; i++) {
+               writel(cpu_to_le32(request[i]), &ioc->chip->Doorbell);
+               if ((_base_wait_for_doorbell_ack(ioc, 5, sleep_flag)))
+                       failed = 1;
+       }
+
+       if (failed) {
+               printk(MPT2SAS_ERR_FMT "doorbell handshake "
+                   "sending request failed (line=%d)\n", ioc->name, __LINE__);
+               return -EFAULT;
+       }
+
+       /* now wait for the reply */
+       if ((_base_wait_for_doorbell_int(ioc, timeout, sleep_flag))) {
+               printk(MPT2SAS_ERR_FMT "doorbell handshake "
+                  "int failed (line=%d)\n", ioc->name, __LINE__);
+               return -EFAULT;
+       }
+
+       /* read the first two 16-bits, it gives the total length of the reply */
+       reply[0] = le16_to_cpu(readl(&ioc->chip->Doorbell)
+           & MPI2_DOORBELL_DATA_MASK);
+       writel(0, &ioc->chip->HostInterruptStatus);
+       if ((_base_wait_for_doorbell_int(ioc, 5, sleep_flag))) {
+               printk(MPT2SAS_ERR_FMT "doorbell handshake "
+                  "int failed (line=%d)\n", ioc->name, __LINE__);
+               return -EFAULT;
+       }
+       reply[1] = le16_to_cpu(readl(&ioc->chip->Doorbell)
+           & MPI2_DOORBELL_DATA_MASK);
+       writel(0, &ioc->chip->HostInterruptStatus);
+
+       for (i = 2; i < default_reply->MsgLength * 2; i++)  {
+               if ((_base_wait_for_doorbell_int(ioc, 5, sleep_flag))) {
+                       printk(MPT2SAS_ERR_FMT "doorbell "
+                           "handshake int failed (line=%d)\n", ioc->name,
+                           __LINE__);
+                       return -EFAULT;
+               }
+               if (i >=  reply_bytes/2) /* overflow case */
+                       dummy = readl(&ioc->chip->Doorbell);
+               else
+                       reply[i] = le16_to_cpu(readl(&ioc->chip->Doorbell)
+                           & MPI2_DOORBELL_DATA_MASK);
+               writel(0, &ioc->chip->HostInterruptStatus);
+       }
+
+       _base_wait_for_doorbell_int(ioc, 5, sleep_flag);
+       if (_base_wait_for_doorbell_not_used(ioc, 5, sleep_flag) != 0) {
+               dhsprintk(ioc, printk(MPT2SAS_INFO_FMT "doorbell is in use "
+                   " (line=%d)\n", ioc->name, __LINE__));
+       }
+       writel(0, &ioc->chip->HostInterruptStatus);
+
+       if (ioc->logging_level & MPT_DEBUG_INIT) {
+               mfp = (u32 *)reply;
+               printk(KERN_DEBUG "\toffset:data\n");
+               for (i = 0; i < reply_bytes/4; i++)
+                       printk(KERN_DEBUG "\t[0x%02x]:%08x\n", i*4,
+                           le32_to_cpu(mfp[i]));
+       }
+       return 0;
+}
+
+/**
+ * mpt2sas_base_sas_iounit_control - send sas iounit control to FW
+ * @ioc: per adapter object
+ * @mpi_reply: the reply payload from FW
+ * @mpi_request: the request payload sent to FW
+ *
+ * The SAS IO Unit Control Request message allows the host to perform low-level
+ * operations, such as resets on the PHYs of the IO Unit, also allows the host
+ * to obtain the IOC assigned device handles for a device if it has other
+ * identifying information about the device, in addition allows the host to
+ * remove IOC resources associated with the device.
+ *
+ * Returns 0 for success, non-zero for failure.
+ */
+int
+mpt2sas_base_sas_iounit_control(struct MPT2SAS_ADAPTER *ioc,
+    Mpi2SasIoUnitControlReply_t *mpi_reply,
+    Mpi2SasIoUnitControlRequest_t *mpi_request)
+{
+       u16 smid;
+       u32 ioc_state;
+       unsigned long timeleft;
+       u8 issue_reset;
+       int rc;
+       void *request;
+       u16 wait_state_count;
+
+       dinitprintk(ioc, printk(MPT2SAS_DEBUG_FMT "%s\n", ioc->name,
+           __func__));
+
+       mutex_lock(&ioc->base_cmds.mutex);
+
+       if (ioc->base_cmds.status != MPT2_CMD_NOT_USED) {
+               printk(MPT2SAS_ERR_FMT "%s: base_cmd in use\n",
+                   ioc->name, __func__);
+               rc = -EAGAIN;
+               goto out;
+       }
+
+       wait_state_count = 0;
+       ioc_state = mpt2sas_base_get_iocstate(ioc, 1);
+       while (ioc_state != MPI2_IOC_STATE_OPERATIONAL) {
+               if (wait_state_count++ == 10) {
+                       printk(MPT2SAS_ERR_FMT
+                           "%s: failed due to ioc not operational\n",
+                           ioc->name, __func__);
+                       rc = -EFAULT;
+                       goto out;
+               }
+               ssleep(1);
+               ioc_state = mpt2sas_base_get_iocstate(ioc, 1);
+               printk(MPT2SAS_INFO_FMT "%s: waiting for "
+                   "operational state(count=%d)\n", ioc->name,
+                   __func__, wait_state_count);
+       }
+
+       smid = mpt2sas_base_get_smid(ioc, ioc->base_cb_idx);
+       if (!smid) {
+               printk(MPT2SAS_ERR_FMT "%s: failed obtaining a smid\n",
+                   ioc->name, __func__);
+               rc = -EAGAIN;
+               goto out;
+       }
+
+       rc = 0;
+       ioc->base_cmds.status = MPT2_CMD_PENDING;
+       request = mpt2sas_base_get_msg_frame(ioc, smid);
+       ioc->base_cmds.smid = smid;
+       memcpy(request, mpi_request, sizeof(Mpi2SasIoUnitControlRequest_t));
+       if (mpi_request->Operation == MPI2_SAS_OP_PHY_HARD_RESET ||
+           mpi_request->Operation == MPI2_SAS_OP_PHY_LINK_RESET)
+               ioc->ioc_link_reset_in_progress = 1;
+       mpt2sas_base_put_smid_default(ioc, smid, mpi_request->VF_ID);
+       timeleft = wait_for_completion_timeout(&ioc->base_cmds.done,
+           msecs_to_jiffies(10000));
+       if ((mpi_request->Operation == MPI2_SAS_OP_PHY_HARD_RESET ||
+           mpi_request->Operation == MPI2_SAS_OP_PHY_LINK_RESET) &&
+           ioc->ioc_link_reset_in_progress)
+               ioc->ioc_link_reset_in_progress = 0;
+       if (!(ioc->base_cmds.status & MPT2_CMD_COMPLETE)) {
+               printk(MPT2SAS_ERR_FMT "%s: timeout\n",
+                   ioc->name, __func__);
+               _debug_dump_mf(mpi_request,
+                   sizeof(Mpi2SasIoUnitControlRequest_t)/4);
+               if (!(ioc->base_cmds.status & MPT2_CMD_RESET))
+                       issue_reset = 1;
+               goto issue_host_reset;
+       }
+       if (ioc->base_cmds.status & MPT2_CMD_REPLY_VALID)
+               memcpy(mpi_reply, ioc->base_cmds.reply,
+                   sizeof(Mpi2SasIoUnitControlReply_t));
+       else
+               memset(mpi_reply, 0, sizeof(Mpi2SasIoUnitControlReply_t));
+       ioc->base_cmds.status = MPT2_CMD_NOT_USED;
+       goto out;
+
+ issue_host_reset:
+       if (issue_reset)
+               mpt2sas_base_hard_reset_handler(ioc, CAN_SLEEP,
+                   FORCE_BIG_HAMMER);
+       ioc->base_cmds.status = MPT2_CMD_NOT_USED;
+       rc = -EFAULT;
+ out:
+       mutex_unlock(&ioc->base_cmds.mutex);
+       return rc;
+}
+
+
+/**
+ * mpt2sas_base_scsi_enclosure_processor - sending request to sep device
+ * @ioc: per adapter object
+ * @mpi_reply: the reply payload from FW
+ * @mpi_request: the request payload sent to FW
+ *
+ * The SCSI Enclosure Processor request message causes the IOC to
+ * communicate with SES devices to control LED status signals.
+ *
+ * Returns 0 for success, non-zero for failure.
+ */
+int
+mpt2sas_base_scsi_enclosure_processor(struct MPT2SAS_ADAPTER *ioc,
+    Mpi2SepReply_t *mpi_reply, Mpi2SepRequest_t *mpi_request)
+{
+       u16 smid;
+       u32 ioc_state;
+       unsigned long timeleft;
+       u8 issue_reset;
+       int rc;
+       void *request;
+       u16 wait_state_count;
+
+       dinitprintk(ioc, printk(MPT2SAS_DEBUG_FMT "%s\n", ioc->name,
+           __func__));
+
+       mutex_lock(&ioc->base_cmds.mutex);
+
+       if (ioc->base_cmds.status != MPT2_CMD_NOT_USED) {
+               printk(MPT2SAS_ERR_FMT "%s: base_cmd in use\n",
+                   ioc->name, __func__);
+               rc = -EAGAIN;
+               goto out;
+       }
+
+       wait_state_count = 0;
+       ioc_state = mpt2sas_base_get_iocstate(ioc, 1);
+       while (ioc_state != MPI2_IOC_STATE_OPERATIONAL) {
+               if (wait_state_count++ == 10) {
+                       printk(MPT2SAS_ERR_FMT
+                           "%s: failed due to ioc not operational\n",
+                           ioc->name, __func__);
+                       rc = -EFAULT;
+                       goto out;
+               }
+               ssleep(1);
+               ioc_state = mpt2sas_base_get_iocstate(ioc, 1);
+               printk(MPT2SAS_INFO_FMT "%s: waiting for "
+                   "operational state(count=%d)\n", ioc->name,
+                   __func__, wait_state_count);
+       }
+
+       smid = mpt2sas_base_get_smid(ioc, ioc->base_cb_idx);
+       if (!smid) {
+               printk(MPT2SAS_ERR_FMT "%s: failed obtaining a smid\n",
+                   ioc->name, __func__);
+               rc = -EAGAIN;
+               goto out;
+       }
+
+       rc = 0;
+       ioc->base_cmds.status = MPT2_CMD_PENDING;
+       request = mpt2sas_base_get_msg_frame(ioc, smid);
+       ioc->base_cmds.smid = smid;
+       memcpy(request, mpi_request, sizeof(Mpi2SepReply_t));
+       mpt2sas_base_put_smid_default(ioc, smid, mpi_request->VF_ID);
+       timeleft = wait_for_completion_timeout(&ioc->base_cmds.done,
+           msecs_to_jiffies(10000));
+       if (!(ioc->base_cmds.status & MPT2_CMD_COMPLETE)) {
+               printk(MPT2SAS_ERR_FMT "%s: timeout\n",
+                   ioc->name, __func__);
+               _debug_dump_mf(mpi_request,
+                   sizeof(Mpi2SepRequest_t)/4);
+               if (!(ioc->base_cmds.status & MPT2_CMD_RESET))
+                       issue_reset = 1;
+               goto issue_host_reset;
+       }
+       if (ioc->base_cmds.status & MPT2_CMD_REPLY_VALID)
+               memcpy(mpi_reply, ioc->base_cmds.reply,
+                   sizeof(Mpi2SepReply_t));
+       else
+               memset(mpi_reply, 0, sizeof(Mpi2SepReply_t));
+       ioc->base_cmds.status = MPT2_CMD_NOT_USED;
+       goto out;
+
+ issue_host_reset:
+       if (issue_reset)
+               mpt2sas_base_hard_reset_handler(ioc, CAN_SLEEP,
+                   FORCE_BIG_HAMMER);
+       ioc->base_cmds.status = MPT2_CMD_NOT_USED;
+       rc = -EFAULT;
+ out:
+       mutex_unlock(&ioc->base_cmds.mutex);
+       return rc;
+}
+
+/**
+ * _base_get_port_facts - obtain port facts reply and save in ioc
+ * @ioc: per adapter object
+ * @sleep_flag: CAN_SLEEP or NO_SLEEP
+ *
+ * Returns 0 for success, non-zero for failure.
+ */
+static int
+_base_get_port_facts(struct MPT2SAS_ADAPTER *ioc, int port, int sleep_flag)
+{
+       Mpi2PortFactsRequest_t mpi_request;
+       Mpi2PortFactsReply_t mpi_reply, *pfacts;
+       int mpi_reply_sz, mpi_request_sz, r;
+
+       dinitprintk(ioc, printk(MPT2SAS_DEBUG_FMT "%s\n", ioc->name,
+           __func__));
+
+       mpi_reply_sz = sizeof(Mpi2PortFactsReply_t);
+       mpi_request_sz = sizeof(Mpi2PortFactsRequest_t);
+       memset(&mpi_request, 0, mpi_request_sz);
+       mpi_request.Function = MPI2_FUNCTION_PORT_FACTS;
+       mpi_request.PortNumber = port;
+       r = _base_handshake_req_reply_wait(ioc, mpi_request_sz,
+           (u32 *)&mpi_request, mpi_reply_sz, (u16 *)&mpi_reply, 5, CAN_SLEEP);
+
+       if (r != 0) {
+               printk(MPT2SAS_ERR_FMT "%s: handshake failed (r=%d)\n",
+                   ioc->name, __func__, r);
+               return r;
+       }
+
+       pfacts = &ioc->pfacts[port];
+       memset(pfacts, 0, sizeof(Mpi2PortFactsReply_t));
+       pfacts->PortNumber = mpi_reply.PortNumber;
+       pfacts->VP_ID = mpi_reply.VP_ID;
+       pfacts->VF_ID = mpi_reply.VF_ID;
+       pfacts->MaxPostedCmdBuffers =
+           le16_to_cpu(mpi_reply.MaxPostedCmdBuffers);
+
+       return 0;
+}
+
+/**
+ * _base_get_ioc_facts - obtain ioc facts reply and save in ioc
+ * @ioc: per adapter object
+ * @sleep_flag: CAN_SLEEP or NO_SLEEP
+ *
+ * Returns 0 for success, non-zero for failure.
+ */
+static int
+_base_get_ioc_facts(struct MPT2SAS_ADAPTER *ioc, int sleep_flag)
+{
+       Mpi2IOCFactsRequest_t mpi_request;
+       Mpi2IOCFactsReply_t mpi_reply, *facts;
+       int mpi_reply_sz, mpi_request_sz, r;
+
+       dinitprintk(ioc, printk(MPT2SAS_DEBUG_FMT "%s\n", ioc->name,
+           __func__));
+
+       mpi_reply_sz = sizeof(Mpi2IOCFactsReply_t);
+       mpi_request_sz = sizeof(Mpi2IOCFactsRequest_t);
+       memset(&mpi_request, 0, mpi_request_sz);
+       mpi_request.Function = MPI2_FUNCTION_IOC_FACTS;
+       r = _base_handshake_req_reply_wait(ioc, mpi_request_sz,
+           (u32 *)&mpi_request, mpi_reply_sz, (u16 *)&mpi_reply, 5, CAN_SLEEP);
+
+       if (r != 0) {
+               printk(MPT2SAS_ERR_FMT "%s: handshake failed (r=%d)\n",
+                   ioc->name, __func__, r);
+               return r;
+       }
+
+       facts = &ioc->facts;
+       memset(facts, 0, sizeof(Mpi2IOCFactsReply_t));
+       facts->MsgVersion = le16_to_cpu(mpi_reply.MsgVersion);
+       facts->HeaderVersion = le16_to_cpu(mpi_reply.HeaderVersion);
+       facts->VP_ID = mpi_reply.VP_ID;
+       facts->VF_ID = mpi_reply.VF_ID;
+       facts->IOCExceptions = le16_to_cpu(mpi_reply.IOCExceptions);
+       facts->MaxChainDepth = mpi_reply.MaxChainDepth;
+       facts->WhoInit = mpi_reply.WhoInit;
+       facts->NumberOfPorts = mpi_reply.NumberOfPorts;
+       facts->RequestCredit = le16_to_cpu(mpi_reply.RequestCredit);
+       facts->MaxReplyDescriptorPostQueueDepth =
+           le16_to_cpu(mpi_reply.MaxReplyDescriptorPostQueueDepth);
+       facts->ProductID = le16_to_cpu(mpi_reply.ProductID);
+       facts->IOCCapabilities = le32_to_cpu(mpi_reply.IOCCapabilities);
+       if ((facts->IOCCapabilities & MPI2_IOCFACTS_CAPABILITY_INTEGRATED_RAID))
+               ioc->ir_firmware = 1;
+       facts->FWVersion.Word = le32_to_cpu(mpi_reply.FWVersion.Word);
+       facts->IOCRequestFrameSize =
+           le16_to_cpu(mpi_reply.IOCRequestFrameSize);
+       facts->MaxInitiators = le16_to_cpu(mpi_reply.MaxInitiators);
+       facts->MaxTargets = le16_to_cpu(mpi_reply.MaxTargets);
+       ioc->shost->max_id = -1;
+       facts->MaxSasExpanders = le16_to_cpu(mpi_reply.MaxSasExpanders);
+       facts->MaxEnclosures = le16_to_cpu(mpi_reply.MaxEnclosures);
+       facts->ProtocolFlags = le16_to_cpu(mpi_reply.ProtocolFlags);
+       facts->HighPriorityCredit =
+           le16_to_cpu(mpi_reply.HighPriorityCredit);
+       facts->ReplyFrameSize = mpi_reply.ReplyFrameSize;
+       facts->MaxDevHandle = le16_to_cpu(mpi_reply.MaxDevHandle);
+
+       dinitprintk(ioc, printk(MPT2SAS_INFO_FMT "hba queue depth(%d), "
+           "max chains per io(%d)\n", ioc->name, facts->RequestCredit,
+           facts->MaxChainDepth));
+       dinitprintk(ioc, printk(MPT2SAS_INFO_FMT "request frame size(%d), "
+           "reply frame size(%d)\n", ioc->name,
+           facts->IOCRequestFrameSize * 4, facts->ReplyFrameSize * 4));
+       return 0;
+}
+
+/**
+ * _base_send_ioc_init - send ioc_init to firmware
+ * @ioc: per adapter object
+ * @VF_ID: virtual function id
+ * @sleep_flag: CAN_SLEEP or NO_SLEEP
+ *
+ * Returns 0 for success, non-zero for failure.
+ */
+static int
+_base_send_ioc_init(struct MPT2SAS_ADAPTER *ioc, u8 VF_ID, int sleep_flag)
+{
+       Mpi2IOCInitRequest_t mpi_request;
+       Mpi2IOCInitReply_t mpi_reply;
+       int r;
+
+       dinitprintk(ioc, printk(MPT2SAS_DEBUG_FMT "%s\n", ioc->name,
+           __func__));
+
+       memset(&mpi_request, 0, sizeof(Mpi2IOCInitRequest_t));
+       mpi_request.Function = MPI2_FUNCTION_IOC_INIT;
+       mpi_request.WhoInit = MPI2_WHOINIT_HOST_DRIVER;
+       mpi_request.VF_ID = VF_ID;
+       mpi_request.MsgVersion = cpu_to_le16(MPI2_VERSION);
+       mpi_request.HeaderVersion = cpu_to_le16(MPI2_HEADER_VERSION);
+
+       /* In MPI Revision I (0xA), the SystemReplyFrameSize(offset 0x18) was
+        * removed and made reserved.  For those with older firmware will need
+        * this fix. It was decided that the Reply and Request frame sizes are
+        * the same.
+        */
+       if ((ioc->facts.HeaderVersion >> 8) < 0xA) {
+               mpi_request.Reserved7 = cpu_to_le16(ioc->reply_sz);
+/*             mpi_request.SystemReplyFrameSize =
+ *              cpu_to_le16(ioc->reply_sz);
+ */
+       }
+
+       mpi_request.SystemRequestFrameSize = cpu_to_le16(ioc->request_sz/4);
+       mpi_request.ReplyDescriptorPostQueueDepth =
+           cpu_to_le16(ioc->reply_post_queue_depth);
+       mpi_request.ReplyFreeQueueDepth =
+           cpu_to_le16(ioc->reply_free_queue_depth);
+
+#if BITS_PER_LONG > 32
+       mpi_request.SenseBufferAddressHigh =
+           cpu_to_le32(ioc->sense_dma >> 32);
+       mpi_request.SystemReplyAddressHigh =
+           cpu_to_le32(ioc->reply_dma >> 32);
+       mpi_request.SystemRequestFrameBaseAddress =
+           cpu_to_le64(ioc->request_dma);
+       mpi_request.ReplyFreeQueueAddress =
+           cpu_to_le64(ioc->reply_free_dma);
+       mpi_request.ReplyDescriptorPostQueueAddress =
+           cpu_to_le64(ioc->reply_post_free_dma);
+#else
+       mpi_request.SystemRequestFrameBaseAddress =
+           cpu_to_le32(ioc->request_dma);
+       mpi_request.ReplyFreeQueueAddress =
+           cpu_to_le32(ioc->reply_free_dma);
+       mpi_request.ReplyDescriptorPostQueueAddress =
+           cpu_to_le32(ioc->reply_post_free_dma);
+#endif
+
+       if (ioc->logging_level & MPT_DEBUG_INIT) {
+               u32 *mfp;
+               int i;
+
+               mfp = (u32 *)&mpi_request;
+               printk(KERN_DEBUG "\toffset:data\n");
+               for (i = 0; i < sizeof(Mpi2IOCInitRequest_t)/4; i++)
+                       printk(KERN_DEBUG "\t[0x%02x]:%08x\n", i*4,
+                           le32_to_cpu(mfp[i]));
+       }
+
+       r = _base_handshake_req_reply_wait(ioc,
+           sizeof(Mpi2IOCInitRequest_t), (u32 *)&mpi_request,
+           sizeof(Mpi2IOCInitReply_t), (u16 *)&mpi_reply, 10,
+           sleep_flag);
+
+       if (r != 0) {
+               printk(MPT2SAS_ERR_FMT "%s: handshake failed (r=%d)\n",
+                   ioc->name, __func__, r);
+               return r;
+       }
+
+       if (mpi_reply.IOCStatus != MPI2_IOCSTATUS_SUCCESS ||
+           mpi_reply.IOCLogInfo) {
+               printk(MPT2SAS_ERR_FMT "%s: failed\n", ioc->name, __func__);
+               r = -EIO;
+       }
+
+       return 0;
+}
+
+/**
+ * _base_send_port_enable - send port_enable(discovery stuff) to firmware
+ * @ioc: per adapter object
+ * @VF_ID: virtual function id
+ * @sleep_flag: CAN_SLEEP or NO_SLEEP
+ *
+ * Returns 0 for success, non-zero for failure.
+ */
+static int
+_base_send_port_enable(struct MPT2SAS_ADAPTER *ioc, u8 VF_ID, int sleep_flag)
+{
+       Mpi2PortEnableRequest_t *mpi_request;
+       u32 ioc_state;
+       unsigned long timeleft;
+       int r = 0;
+       u16 smid;
+
+       printk(MPT2SAS_INFO_FMT "sending port enable !!\n", ioc->name);
+
+       if (ioc->base_cmds.status & MPT2_CMD_PENDING) {
+               printk(MPT2SAS_ERR_FMT "%s: internal command already in use\n",
+                   ioc->name, __func__);
+               return -EAGAIN;
+       }
+
+       smid = mpt2sas_base_get_smid(ioc, ioc->base_cb_idx);
+       if (!smid) {
+               printk(MPT2SAS_ERR_FMT "%s: failed obtaining a smid\n",
+                   ioc->name, __func__);
+               return -EAGAIN;
+       }
+
+       ioc->base_cmds.status = MPT2_CMD_PENDING;
+       mpi_request = mpt2sas_base_get_msg_frame(ioc, smid);
+       ioc->base_cmds.smid = smid;
+       memset(mpi_request, 0, sizeof(Mpi2PortEnableRequest_t));
+       mpi_request->Function = MPI2_FUNCTION_PORT_ENABLE;
+       mpi_request->VF_ID = VF_ID;
+
+       mpt2sas_base_put_smid_default(ioc, smid, VF_ID);
+       timeleft = wait_for_completion_timeout(&ioc->base_cmds.done,
+           300*HZ);
+       if (!(ioc->base_cmds.status & MPT2_CMD_COMPLETE)) {
+               printk(MPT2SAS_ERR_FMT "%s: timeout\n",
+                   ioc->name, __func__);
+               _debug_dump_mf(mpi_request,
+                   sizeof(Mpi2PortEnableRequest_t)/4);
+               if (ioc->base_cmds.status & MPT2_CMD_RESET)
+                       r = -EFAULT;
+               else
+                       r = -ETIME;
+               goto out;
+       } else
+               dinitprintk(ioc, printk(MPT2SAS_DEBUG_FMT "%s: complete\n",
+                   ioc->name, __func__));
+
+       ioc_state = _base_wait_on_iocstate(ioc, MPI2_IOC_STATE_OPERATIONAL,
+           60, sleep_flag);
+       if (ioc_state) {
+               printk(MPT2SAS_ERR_FMT "%s: failed going to operational state "
+                   " (ioc_state=0x%x)\n", ioc->name, __func__, ioc_state);
+               r = -EFAULT;
+       }
+ out:
+       ioc->base_cmds.status = MPT2_CMD_NOT_USED;
+       printk(MPT2SAS_INFO_FMT "port enable: %s\n",
+           ioc->name, ((r == 0) ? "SUCCESS" : "FAILED"));
+       return r;
+}
+
+/**
+ * _base_unmask_events - turn on notification for this event
+ * @ioc: per adapter object
+ * @event: firmware event
+ *
+ * The mask is stored in ioc->event_masks.
+ */
+static void
+_base_unmask_events(struct MPT2SAS_ADAPTER *ioc, u16 event)
+{
+       u32 desired_event;
+
+       if (event >= 128)
+               return;
+
+       desired_event = (1 << (event % 32));
+
+       if (event < 32)
+               ioc->event_masks[0] &= ~desired_event;
+       else if (event < 64)
+               ioc->event_masks[1] &= ~desired_event;
+       else if (event < 96)
+               ioc->event_masks[2] &= ~desired_event;
+       else if (event < 128)
+               ioc->event_masks[3] &= ~desired_event;
+}
+
+/**
+ * _base_event_notification - send event notification
+ * @ioc: per adapter object
+ * @VF_ID: virtual function id
+ * @sleep_flag: CAN_SLEEP or NO_SLEEP
+ *
+ * Returns 0 for success, non-zero for failure.
+ */
+static int
+_base_event_notification(struct MPT2SAS_ADAPTER *ioc, u8 VF_ID, int sleep_flag)
+{
+       Mpi2EventNotificationRequest_t *mpi_request;
+       unsigned long timeleft;
+       u16 smid;
+       int r = 0;
+       int i;
+
+       dinitprintk(ioc, printk(MPT2SAS_DEBUG_FMT "%s\n", ioc->name,
+           __func__));
+
+       if (ioc->base_cmds.status & MPT2_CMD_PENDING) {
+               printk(MPT2SAS_ERR_FMT "%s: internal command already in use\n",
+                   ioc->name, __func__);
+               return -EAGAIN;
+       }
+
+       smid = mpt2sas_base_get_smid(ioc, ioc->base_cb_idx);
+       if (!smid) {
+               printk(MPT2SAS_ERR_FMT "%s: failed obtaining a smid\n",
+                   ioc->name, __func__);
+               return -EAGAIN;
+       }
+       ioc->base_cmds.status = MPT2_CMD_PENDING;
+       mpi_request = mpt2sas_base_get_msg_frame(ioc, smid);
+       ioc->base_cmds.smid = smid;
+       memset(mpi_request, 0, sizeof(Mpi2EventNotificationRequest_t));
+       mpi_request->Function = MPI2_FUNCTION_EVENT_NOTIFICATION;
+       mpi_request->VF_ID = VF_ID;
+       for (i = 0; i < MPI2_EVENT_NOTIFY_EVENTMASK_WORDS; i++)
+               mpi_request->EventMasks[i] =
+                   le32_to_cpu(ioc->event_masks[i]);
+       mpt2sas_base_put_smid_default(ioc, smid, VF_ID);
+       timeleft = wait_for_completion_timeout(&ioc->base_cmds.done, 30*HZ);
+       if (!(ioc->base_cmds.status & MPT2_CMD_COMPLETE)) {
+               printk(MPT2SAS_ERR_FMT "%s: timeout\n",
+                   ioc->name, __func__);
+               _debug_dump_mf(mpi_request,
+                   sizeof(Mpi2EventNotificationRequest_t)/4);
+               if (ioc->base_cmds.status & MPT2_CMD_RESET)
+                       r = -EFAULT;
+               else
+                       r = -ETIME;
+       } else
+               dinitprintk(ioc, printk(MPT2SAS_DEBUG_FMT "%s: complete\n",
+                   ioc->name, __func__));
+       ioc->base_cmds.status = MPT2_CMD_NOT_USED;
+       return r;
+}
+
+/**
+ * mpt2sas_base_validate_event_type - validating event types
+ * @ioc: per adapter object
+ * @event: firmware event
+ *
+ * This will turn on firmware event notification when application
+ * ask for that event. We don't mask events that are already enabled.
+ */
+void
+mpt2sas_base_validate_event_type(struct MPT2SAS_ADAPTER *ioc, u32 *event_type)
+{
+       int i, j;
+       u32 event_mask, desired_event;
+       u8 send_update_to_fw;
+
+       for (i = 0, send_update_to_fw = 0; i <
+           MPI2_EVENT_NOTIFY_EVENTMASK_WORDS; i++) {
+               event_mask = ~event_type[i];
+               desired_event = 1;
+               for (j = 0; j < 32; j++) {
+                       if (!(event_mask & desired_event) &&
+                           (ioc->event_masks[i] & desired_event)) {
+                               ioc->event_masks[i] &= ~desired_event;
+                               send_update_to_fw = 1;
+                       }
+                       desired_event = (desired_event << 1);
+               }
+       }
+
+       if (!send_update_to_fw)
+               return;
+
+       mutex_lock(&ioc->base_cmds.mutex);
+       _base_event_notification(ioc, 0, CAN_SLEEP);
+       mutex_unlock(&ioc->base_cmds.mutex);
+}
+
+/**
+ * _base_diag_reset - the "big hammer" start of day reset
+ * @ioc: per adapter object
+ * @sleep_flag: CAN_SLEEP or NO_SLEEP
+ *
+ * Returns 0 for success, non-zero for failure.
+ */
+static int
+_base_diag_reset(struct MPT2SAS_ADAPTER *ioc, int sleep_flag)
+{
+       u32 host_diagnostic;
+       u32 ioc_state;
+       u32 count;
+       u32 hcb_size;
+
+       printk(MPT2SAS_INFO_FMT "sending diag reset !!\n", ioc->name);
+
+       _base_save_msix_table(ioc);
+
+       drsprintk(ioc, printk(MPT2SAS_DEBUG_FMT "clear interrupts\n",
+           ioc->name));
+       writel(0, &ioc->chip->HostInterruptStatus);
+
+       count = 0;
+       do {
+               /* Write magic sequence to WriteSequence register
+                * Loop until in diagnostic mode
+                */
+               drsprintk(ioc, printk(MPT2SAS_DEBUG_FMT "write magic "
+                   "sequence\n", ioc->name));
+               writel(MPI2_WRSEQ_FLUSH_KEY_VALUE, &ioc->chip->WriteSequence);
+               writel(MPI2_WRSEQ_1ST_KEY_VALUE, &ioc->chip->WriteSequence);
+               writel(MPI2_WRSEQ_2ND_KEY_VALUE, &ioc->chip->WriteSequence);
+               writel(MPI2_WRSEQ_3RD_KEY_VALUE, &ioc->chip->WriteSequence);
+               writel(MPI2_WRSEQ_4TH_KEY_VALUE, &ioc->chip->WriteSequence);
+               writel(MPI2_WRSEQ_5TH_KEY_VALUE, &ioc->chip->WriteSequence);
+               writel(MPI2_WRSEQ_6TH_KEY_VALUE, &ioc->chip->WriteSequence);
+
+               /* wait 100 msec */
+               if (sleep_flag == CAN_SLEEP)
+                       msleep(100);
+               else
+                       mdelay(100);
+
+               if (count++ > 20)
+                       goto out;
+
+               host_diagnostic = readl(&ioc->chip->HostDiagnostic);
+               drsprintk(ioc, printk(MPT2SAS_DEBUG_FMT "wrote magic "
+                   "sequence: count(%d), host_diagnostic(0x%08x)\n",
+                   ioc->name, count, host_diagnostic));
+
+       } while ((host_diagnostic & MPI2_DIAG_DIAG_WRITE_ENABLE) == 0);
+
+       hcb_size = readl(&ioc->chip->HCBSize);
+
+       drsprintk(ioc, printk(MPT2SAS_DEBUG_FMT "diag reset: issued\n",
+           ioc->name));
+       writel(host_diagnostic | MPI2_DIAG_RESET_ADAPTER,
+            &ioc->chip->HostDiagnostic);
+
+       /* don't access any registers for 50 milliseconds */
+       msleep(50);
+
+       /* 300 second max wait */
+       for (count = 0; count < 3000000 ; count++) {
+
+               host_diagnostic = readl(&ioc->chip->HostDiagnostic);
+
+               if (host_diagnostic == 0xFFFFFFFF)
+                       goto out;
+               if (!(host_diagnostic & MPI2_DIAG_RESET_ADAPTER))
+                       break;
+
+               /* wait 100 msec */
+               if (sleep_flag == CAN_SLEEP)
+                       msleep(1);
+               else
+                       mdelay(1);
+       }
+
+       if (host_diagnostic & MPI2_DIAG_HCB_MODE) {
+
+               drsprintk(ioc, printk(MPT2SAS_DEBUG_FMT "restart the adapter "
+                   "assuming the HCB Address points to good F/W\n",
+                   ioc->name));
+               host_diagnostic &= ~MPI2_DIAG_BOOT_DEVICE_SELECT_MASK;
+               host_diagnostic |= MPI2_DIAG_BOOT_DEVICE_SELECT_HCDW;
+               writel(host_diagnostic, &ioc->chip->HostDiagnostic);
+
+               drsprintk(ioc, printk(MPT2SAS_DEBUG_FMT
+                   "re-enable the HCDW\n", ioc->name));
+               writel(hcb_size | MPI2_HCB_SIZE_HCB_ENABLE,
+                   &ioc->chip->HCBSize);
+       }
+
+       drsprintk(ioc, printk(MPT2SAS_DEBUG_FMT "restart the adapter\n",
+           ioc->name));
+       writel(host_diagnostic & ~MPI2_DIAG_HOLD_IOC_RESET,
+           &ioc->chip->HostDiagnostic);
+
+       drsprintk(ioc, printk(MPT2SAS_DEBUG_FMT "disable writes to the "
+           "diagnostic register\n", ioc->name));
+       writel(MPI2_WRSEQ_FLUSH_KEY_VALUE, &ioc->chip->WriteSequence);
+
+       drsprintk(ioc, printk(MPT2SAS_DEBUG_FMT "Wait for FW to go to the "
+           "READY state\n", ioc->name));
+       ioc_state = _base_wait_on_iocstate(ioc, MPI2_IOC_STATE_READY, 20,
+           sleep_flag);
+       if (ioc_state) {
+               printk(MPT2SAS_ERR_FMT "%s: failed going to ready state "
+                   " (ioc_state=0x%x)\n", ioc->name, __func__, ioc_state);
+               goto out;
+       }
+
+       _base_restore_msix_table(ioc);
+       printk(MPT2SAS_INFO_FMT "diag reset: SUCCESS\n", ioc->name);
+       return 0;
+
+ out:
+       printk(MPT2SAS_ERR_FMT "diag reset: FAILED\n", ioc->name);
+       return -EFAULT;
+}
+
+/**
+ * _base_make_ioc_ready - put controller in READY state
+ * @ioc: per adapter object
+ * @sleep_flag: CAN_SLEEP or NO_SLEEP
+ * @type: FORCE_BIG_HAMMER or SOFT_RESET
+ *
+ * Returns 0 for success, non-zero for failure.
+ */
+static int
+_base_make_ioc_ready(struct MPT2SAS_ADAPTER *ioc, int sleep_flag,
+    enum reset_type type)
+{
+       u32 ioc_state;
+
+       dinitprintk(ioc, printk(MPT2SAS_DEBUG_FMT "%s\n", ioc->name,
+           __func__));
+
+       ioc_state = mpt2sas_base_get_iocstate(ioc, 0);
+       dhsprintk(ioc, printk(MPT2SAS_DEBUG_FMT "%s: ioc_state(0x%08x)\n",
+           ioc->name, __func__, ioc_state));
+
+       if ((ioc_state & MPI2_IOC_STATE_MASK) == MPI2_IOC_STATE_READY)
+               return 0;
+
+       if (ioc_state & MPI2_DOORBELL_USED) {
+               dhsprintk(ioc, printk(MPT2SAS_DEBUG_FMT "unexpected doorbell "
+                   "active!\n", ioc->name));
+               goto issue_diag_reset;
+       }
+
+       if ((ioc_state & MPI2_IOC_STATE_MASK) == MPI2_IOC_STATE_FAULT) {
+               mpt2sas_base_fault_info(ioc, ioc_state &
+                   MPI2_DOORBELL_DATA_MASK);
+               goto issue_diag_reset;
+       }
+
+       if (type == FORCE_BIG_HAMMER)
+               goto issue_diag_reset;
+
+       if ((ioc_state & MPI2_IOC_STATE_MASK) == MPI2_IOC_STATE_OPERATIONAL)
+               if (!(_base_send_ioc_reset(ioc,
+                   MPI2_FUNCTION_IOC_MESSAGE_UNIT_RESET, 15, CAN_SLEEP)))
+                       return 0;
+
+ issue_diag_reset:
+       return _base_diag_reset(ioc, CAN_SLEEP);
+}
+
+/**
+ * _base_make_ioc_operational - put controller in OPERATIONAL state
+ * @ioc: per adapter object
+ * @VF_ID: virtual function id
+ * @sleep_flag: CAN_SLEEP or NO_SLEEP
+ *
+ * Returns 0 for success, non-zero for failure.
+ */
+static int
+_base_make_ioc_operational(struct MPT2SAS_ADAPTER *ioc, u8 VF_ID,
+    int sleep_flag)
+{
+       int r, i;
+       unsigned long   flags;
+       u32 reply_address;
+
+       dinitprintk(ioc, printk(MPT2SAS_DEBUG_FMT "%s\n", ioc->name,
+           __func__));
+
+       /* initialize the scsi lookup free list */
+       spin_lock_irqsave(&ioc->scsi_lookup_lock, flags);
+       INIT_LIST_HEAD(&ioc->free_list);
+       for (i = 0; i < ioc->request_depth; i++) {
+               ioc->scsi_lookup[i].cb_idx = 0xFF;
+               list_add_tail(&ioc->scsi_lookup[i].tracker_list,
+                   &ioc->free_list);
+       }
+       spin_unlock_irqrestore(&ioc->scsi_lookup_lock, flags);
+
+       /* initialize Reply Free Queue */
+       for (i = 0, reply_address = (u32)ioc->reply_dma ;
+           i < ioc->reply_free_queue_depth ; i++, reply_address +=
+           ioc->reply_sz)
+               ioc->reply_free[i] = cpu_to_le32(reply_address);
+
+       /* initialize Reply Post Free Queue */
+       for (i = 0; i < ioc->reply_post_queue_depth; i++)
+               ioc->reply_post_free[i].Words = ~0ULL;
+
+       r = _base_send_ioc_init(ioc, VF_ID, sleep_flag);
+       if (r)
+               return r;
+
+       /* initialize the index's */
+       ioc->reply_free_host_index = ioc->reply_free_queue_depth - 1;
+       ioc->reply_post_host_index = 0;
+       writel(ioc->reply_free_host_index, &ioc->chip->ReplyFreeHostIndex);
+       writel(0, &ioc->chip->ReplyPostHostIndex);
+
+       _base_unmask_interrupts(ioc);
+       r = _base_event_notification(ioc, VF_ID, sleep_flag);
+       if (r)
+               return r;
+
+       if (sleep_flag == CAN_SLEEP)
+               _base_static_config_pages(ioc);
+
+       r = _base_send_port_enable(ioc, VF_ID, sleep_flag);
+       if (r)
+               return r;
+
+       return r;
+}
+
+/**
+ * mpt2sas_base_free_resources - free resources controller resources (io/irq/memap)
+ * @ioc: per adapter object
+ *
+ * Return nothing.
+ */
+void
+mpt2sas_base_free_resources(struct MPT2SAS_ADAPTER *ioc)
+{
+       struct pci_dev *pdev = ioc->pdev;
+
+       dexitprintk(ioc, printk(MPT2SAS_DEBUG_FMT "%s\n", ioc->name,
+           __func__));
+
+       _base_mask_interrupts(ioc);
+       _base_make_ioc_ready(ioc, CAN_SLEEP, SOFT_RESET);
+       if (ioc->pci_irq) {
+               synchronize_irq(pdev->irq);
+               free_irq(ioc->pci_irq, ioc);
+       }
+       _base_disable_msix(ioc);
+       if (ioc->chip_phys)
+               iounmap(ioc->chip);
+       ioc->pci_irq = -1;
+       ioc->chip_phys = 0;
+       pci_release_selected_regions(ioc->pdev, ioc->bars);
+       pci_disable_device(pdev);
+       pci_set_drvdata(pdev, NULL);
+       return;
+}
+
+/**
+ * mpt2sas_base_attach - attach controller instance
+ * @ioc: per adapter object
+ *
+ * Returns 0 for success, non-zero for failure.
+ */
+int
+mpt2sas_base_attach(struct MPT2SAS_ADAPTER *ioc)
+{
+       int r, i;
+       unsigned long    flags;
+
+       dinitprintk(ioc, printk(MPT2SAS_DEBUG_FMT "%s\n", ioc->name,
+           __func__));
+
+       r = mpt2sas_base_map_resources(ioc);
+       if (r)
+               return r;
+
+       r = _base_make_ioc_ready(ioc, CAN_SLEEP, SOFT_RESET);
+       if (r)
+               goto out_free_resources;
+
+       r = _base_get_ioc_facts(ioc, CAN_SLEEP);
+       if (r)
+               goto out_free_resources;
+
+       r = _base_allocate_memory_pools(ioc, CAN_SLEEP);
+       if (r)
+               goto out_free_resources;
+
+       init_waitqueue_head(&ioc->reset_wq);
+
+       /* base internal command bits */
+       mutex_init(&ioc->base_cmds.mutex);
+       init_completion(&ioc->base_cmds.done);
+       ioc->base_cmds.reply = kzalloc(ioc->reply_sz, GFP_KERNEL);
+       ioc->base_cmds.status = MPT2_CMD_NOT_USED;
+
+       /* transport internal command bits */
+       ioc->transport_cmds.reply = kzalloc(ioc->reply_sz, GFP_KERNEL);
+       ioc->transport_cmds.status = MPT2_CMD_NOT_USED;
+       mutex_init(&ioc->transport_cmds.mutex);
+       init_completion(&ioc->transport_cmds.done);
+
+       /* task management internal command bits */
+       ioc->tm_cmds.reply = kzalloc(ioc->reply_sz, GFP_KERNEL);
+       ioc->tm_cmds.status = MPT2_CMD_NOT_USED;
+       mutex_init(&ioc->tm_cmds.mutex);
+       init_completion(&ioc->tm_cmds.done);
+
+       /* config page internal command bits */
+       ioc->config_cmds.reply = kzalloc(ioc->reply_sz, GFP_KERNEL);
+       ioc->config_cmds.status = MPT2_CMD_NOT_USED;
+       mutex_init(&ioc->config_cmds.mutex);
+       init_completion(&ioc->config_cmds.done);
+
+       /* ctl module internal command bits */
+       ioc->ctl_cmds.reply = kzalloc(ioc->reply_sz, GFP_KERNEL);
+       ioc->ctl_cmds.status = MPT2_CMD_NOT_USED;
+       mutex_init(&ioc->ctl_cmds.mutex);
+       init_completion(&ioc->ctl_cmds.done);
+
+       for (i = 0; i < MPI2_EVENT_NOTIFY_EVENTMASK_WORDS; i++)
+               ioc->event_masks[i] = -1;
+
+       /* here we enable the events we care about */
+       _base_unmask_events(ioc, MPI2_EVENT_SAS_DISCOVERY);
+       _base_unmask_events(ioc, MPI2_EVENT_SAS_BROADCAST_PRIMITIVE);
+       _base_unmask_events(ioc, MPI2_EVENT_SAS_TOPOLOGY_CHANGE_LIST);
+       _base_unmask_events(ioc, MPI2_EVENT_SAS_DEVICE_STATUS_CHANGE);
+       _base_unmask_events(ioc, MPI2_EVENT_SAS_ENCL_DEVICE_STATUS_CHANGE);
+       _base_unmask_events(ioc, MPI2_EVENT_IR_CONFIGURATION_CHANGE_LIST);
+       _base_unmask_events(ioc, MPI2_EVENT_IR_VOLUME);
+       _base_unmask_events(ioc, MPI2_EVENT_IR_PHYSICAL_DISK);
+       _base_unmask_events(ioc, MPI2_EVENT_IR_OPERATION_STATUS);
+       _base_unmask_events(ioc, MPI2_EVENT_TASK_SET_FULL);
+       _base_unmask_events(ioc, MPI2_EVENT_LOG_ENTRY_ADDED);
+
+       ioc->pfacts = kcalloc(ioc->facts.NumberOfPorts,
+           sizeof(Mpi2PortFactsReply_t), GFP_KERNEL);
+       if (!ioc->pfacts)
+               goto out_free_resources;
+
+       for (i = 0 ; i < ioc->facts.NumberOfPorts; i++) {
+               r = _base_get_port_facts(ioc, i, CAN_SLEEP);
+               if (r)
+                       goto out_free_resources;
+       }
+       r = _base_make_ioc_operational(ioc, 0, CAN_SLEEP);
+       if (r)
+               goto out_free_resources;
+
+       /* initialize fault polling */
+       INIT_DELAYED_WORK(&ioc->fault_reset_work, _base_fault_reset_work);
+       snprintf(ioc->fault_reset_work_q_name,
+           sizeof(ioc->fault_reset_work_q_name), "poll_%d_status", ioc->id);
+       ioc->fault_reset_work_q =
+               create_singlethread_workqueue(ioc->fault_reset_work_q_name);
+       if (!ioc->fault_reset_work_q) {
+               printk(MPT2SAS_ERR_FMT "%s: failed (line=%d)\n",
+                   ioc->name, __func__, __LINE__);
+                       goto out_free_resources;
+       }
+       spin_lock_irqsave(&ioc->ioc_reset_in_progress_lock, flags);
+       if (ioc->fault_reset_work_q)
+               queue_delayed_work(ioc->fault_reset_work_q,
+                   &ioc->fault_reset_work,
+                   msecs_to_jiffies(FAULT_POLLING_INTERVAL));
+       spin_unlock_irqrestore(&ioc->ioc_reset_in_progress_lock, flags);
+       return 0;
+
+ out_free_resources:
+
+       ioc->remove_host = 1;
+       mpt2sas_base_free_resources(ioc);
+       _base_release_memory_pools(ioc);
+       kfree(ioc->tm_cmds.reply);
+       kfree(ioc->transport_cmds.reply);
+       kfree(ioc->config_cmds.reply);
+       kfree(ioc->base_cmds.reply);
+       kfree(ioc->ctl_cmds.reply);
+       kfree(ioc->pfacts);
+       ioc->ctl_cmds.reply = NULL;
+       ioc->base_cmds.reply = NULL;
+       ioc->tm_cmds.reply = NULL;
+       ioc->transport_cmds.reply = NULL;
+       ioc->config_cmds.reply = NULL;
+       ioc->pfacts = NULL;
+       return r;
+}
+
+
+/**
+ * mpt2sas_base_detach - remove controller instance
+ * @ioc: per adapter object
+ *
+ * Return nothing.
+ */
+void
+mpt2sas_base_detach(struct MPT2SAS_ADAPTER *ioc)
+{
+       unsigned long    flags;
+       struct workqueue_struct *wq;
+
+       dexitprintk(ioc, printk(MPT2SAS_DEBUG_FMT "%s\n", ioc->name,
+           __func__));
+
+       spin_lock_irqsave(&ioc->ioc_reset_in_progress_lock, flags);
+       wq = ioc->fault_reset_work_q;
+       ioc->fault_reset_work_q = NULL;
+       spin_unlock_irqrestore(&ioc->ioc_reset_in_progress_lock, flags);
+       if (!cancel_delayed_work(&ioc->fault_reset_work))
+               flush_workqueue(wq);
+       destroy_workqueue(wq);
+
+       mpt2sas_base_free_resources(ioc);
+       _base_release_memory_pools(ioc);
+       kfree(ioc->pfacts);
+       kfree(ioc->ctl_cmds.reply);
+       kfree(ioc->base_cmds.reply);
+       kfree(ioc->tm_cmds.reply);
+       kfree(ioc->transport_cmds.reply);
+       kfree(ioc->config_cmds.reply);
+}
+
+/**
+ * _base_reset_handler - reset callback handler (for base)
+ * @ioc: per adapter object
+ * @reset_phase: phase
+ *
+ * The handler for doing any required cleanup or initialization.
+ *
+ * The reset phase can be MPT2_IOC_PRE_RESET, MPT2_IOC_AFTER_RESET,
+ * MPT2_IOC_DONE_RESET
+ *
+ * Return nothing.
+ */
+static void
+_base_reset_handler(struct MPT2SAS_ADAPTER *ioc, int reset_phase)
+{
+       switch (reset_phase) {
+       case MPT2_IOC_PRE_RESET:
+               dtmprintk(ioc, printk(MPT2SAS_DEBUG_FMT "%s: "
+                   "MPT2_IOC_PRE_RESET\n", ioc->name, __func__));
+               break;
+       case MPT2_IOC_AFTER_RESET:
+               dtmprintk(ioc, printk(MPT2SAS_DEBUG_FMT "%s: "
+                   "MPT2_IOC_AFTER_RESET\n", ioc->name, __func__));
+               if (ioc->transport_cmds.status & MPT2_CMD_PENDING) {
+                       ioc->transport_cmds.status |= MPT2_CMD_RESET;
+                       mpt2sas_base_free_smid(ioc, ioc->transport_cmds.smid);
+                       complete(&ioc->transport_cmds.done);
+               }
+               if (ioc->base_cmds.status & MPT2_CMD_PENDING) {
+                       ioc->base_cmds.status |= MPT2_CMD_RESET;
+                       mpt2sas_base_free_smid(ioc, ioc->base_cmds.smid);
+                       complete(&ioc->base_cmds.done);
+               }
+               if (ioc->config_cmds.status & MPT2_CMD_PENDING) {
+                       ioc->config_cmds.status |= MPT2_CMD_RESET;
+                       mpt2sas_base_free_smid(ioc, ioc->config_cmds.smid);
+                       complete(&ioc->config_cmds.done);
+               }
+               break;
+       case MPT2_IOC_DONE_RESET:
+               dtmprintk(ioc, printk(MPT2SAS_DEBUG_FMT "%s: "
+                   "MPT2_IOC_DONE_RESET\n", ioc->name, __func__));
+               break;
+       }
+       mpt2sas_scsih_reset_handler(ioc, reset_phase);
+       mpt2sas_ctl_reset_handler(ioc, reset_phase);
+}
+
+/**
+ * _wait_for_commands_to_complete - reset controller
+ * @ioc: Pointer to MPT_ADAPTER structure
+ * @sleep_flag: CAN_SLEEP or NO_SLEEP
+ *
+ * This function waiting(3s) for all pending commands to complete
+ * prior to putting controller in reset.
+ */
+static void
+_wait_for_commands_to_complete(struct MPT2SAS_ADAPTER *ioc, int sleep_flag)
+{
+       u32 ioc_state;
+       unsigned long flags;
+       u16 i;
+
+       ioc->pending_io_count = 0;
+       if (sleep_flag != CAN_SLEEP)
+               return;
+
+       ioc_state = mpt2sas_base_get_iocstate(ioc, 0);
+       if ((ioc_state & MPI2_IOC_STATE_MASK) != MPI2_IOC_STATE_OPERATIONAL)
+               return;
+
+       /* pending command count */
+       spin_lock_irqsave(&ioc->scsi_lookup_lock, flags);
+       for (i = 0; i < ioc->request_depth; i++)
+               if (ioc->scsi_lookup[i].cb_idx != 0xFF)
+                       ioc->pending_io_count++;
+       spin_unlock_irqrestore(&ioc->scsi_lookup_lock, flags);
+
+       if (!ioc->pending_io_count)
+               return;
+
+       /* wait for pending commands to complete */
+       wait_event_timeout(ioc->reset_wq, ioc->pending_io_count == 0, 3 * HZ);
+}
+
+/**
+ * mpt2sas_base_hard_reset_handler - reset controller
+ * @ioc: Pointer to MPT_ADAPTER structure
+ * @sleep_flag: CAN_SLEEP or NO_SLEEP
+ * @type: FORCE_BIG_HAMMER or SOFT_RESET
+ *
+ * Returns 0 for success, non-zero for failure.
+ */
+int
+mpt2sas_base_hard_reset_handler(struct MPT2SAS_ADAPTER *ioc, int sleep_flag,
+    enum reset_type type)
+{
+       int r, i;
+       unsigned long flags;
+
+       dtmprintk(ioc, printk(MPT2SAS_DEBUG_FMT "%s: enter\n", ioc->name,
+           __func__));
+
+       spin_lock_irqsave(&ioc->ioc_reset_in_progress_lock, flags);
+       if (ioc->ioc_reset_in_progress) {
+               spin_unlock_irqrestore(&ioc->ioc_reset_in_progress_lock, flags);
+               printk(MPT2SAS_ERR_FMT "%s: busy\n",
+                   ioc->name, __func__);
+               return -EBUSY;
+       }
+       ioc->ioc_reset_in_progress = 1;
+       ioc->shost_recovery = 1;
+       if (ioc->shost->shost_state == SHOST_RUNNING) {
+               /* set back to SHOST_RUNNING in mpt2sas_scsih.c */
+               scsi_host_set_state(ioc->shost, SHOST_RECOVERY);
+               printk(MPT2SAS_INFO_FMT "putting controller into "
+                   "SHOST_RECOVERY\n", ioc->name);
+       }
+       spin_unlock_irqrestore(&ioc->ioc_reset_in_progress_lock, flags);
+
+       _base_reset_handler(ioc, MPT2_IOC_PRE_RESET);
+       _wait_for_commands_to_complete(ioc, sleep_flag);
+       _base_mask_interrupts(ioc);
+       r = _base_make_ioc_ready(ioc, sleep_flag, type);
+       if (r)
+               goto out;
+       _base_reset_handler(ioc, MPT2_IOC_AFTER_RESET);
+       for (i = 0 ; i < ioc->facts.NumberOfPorts; i++)
+               r = _base_make_ioc_operational(ioc, ioc->pfacts[i].VF_ID,
+                   sleep_flag);
+       if (!r)
+               _base_reset_handler(ioc, MPT2_IOC_DONE_RESET);
+ out:
+       dtmprintk(ioc, printk(MPT2SAS_DEBUG_FMT "%s: %s\n",
+           ioc->name, __func__, ((r == 0) ? "SUCCESS" : "FAILED")));
+
+       spin_lock_irqsave(&ioc->ioc_reset_in_progress_lock, flags);
+       ioc->ioc_reset_in_progress = 0;
+       spin_unlock_irqrestore(&ioc->ioc_reset_in_progress_lock, flags);
+       return r;
+}
diff --git a/drivers/scsi/mpt2sas/mpt2sas_base.h b/drivers/scsi/mpt2sas/mpt2sas_base.h
new file mode 100644 (file)
index 0000000..11fc17f
--- /dev/null
@@ -0,0 +1,779 @@
+/*
+ * This is the Fusion MPT base driver providing common API layer interface
+ * for access to MPT (Message Passing Technology) firmware.
+ *
+ * This code is based on drivers/scsi/mpt2sas/mpt2_base.h
+ * Copyright (C) 2007-2008  LSI Corporation
+ *  (mailto:DL-MPTFusionLinux@lsi.com)
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * NO WARRANTY
+ * THE PROGRAM IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OR
+ * CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED INCLUDING, WITHOUT
+ * LIMITATION, ANY WARRANTIES OR CONDITIONS OF TITLE, NON-INFRINGEMENT,
+ * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. Each Recipient is
+ * solely responsible for determining the appropriateness of using and
+ * distributing the Program and assumes all risks associated with its
+ * exercise of rights under this Agreement, including but not limited to
+ * the risks and costs of program errors, damage to or loss of data,
+ * programs or equipment, and unavailability or interruption of operations.
+
+ * DISCLAIMER OF LIABILITY
+ * NEITHER RECIPIENT NOR ANY CONTRIBUTORS SHALL HAVE ANY LIABILITY FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING WITHOUT LIMITATION LOST PROFITS), 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 OR DISTRIBUTION OF THE PROGRAM OR THE EXERCISE OF ANY RIGHTS GRANTED
+ * HEREUNDER, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGES
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301,
+ * USA.
+ */
+
+#ifndef MPT2SAS_BASE_H_INCLUDED
+#define MPT2SAS_BASE_H_INCLUDED
+
+#include "mpi/mpi2_type.h"
+#include "mpi/mpi2.h"
+#include "mpi/mpi2_ioc.h"
+#include "mpi/mpi2_cnfg.h"
+#include "mpi/mpi2_init.h"
+#include "mpi/mpi2_raid.h"
+#include "mpi/mpi2_tool.h"
+#include "mpi/mpi2_sas.h"
+
+#include <scsi/scsi.h>
+#include <scsi/scsi_cmnd.h>
+#include <scsi/scsi_device.h>
+#include <scsi/scsi_host.h>
+#include <scsi/scsi_tcq.h>
+#include <scsi/scsi_transport_sas.h>
+#include <scsi/scsi_dbg.h>
+
+#include "mpt2sas_debug.h"
+
+/* driver versioning info */
+#define MPT2SAS_DRIVER_NAME            "mpt2sas"
+#define MPT2SAS_AUTHOR "LSI Corporation <DL-MPTFusionLinux@lsi.com>"
+#define MPT2SAS_DESCRIPTION    "LSI MPT Fusion SAS 2.0 Device Driver"
+#define MPT2SAS_DRIVER_VERSION         "00.100.11.15"
+#define MPT2SAS_MAJOR_VERSION          00
+#define MPT2SAS_MINOR_VERSION          100
+#define MPT2SAS_BUILD_VERSION          11
+#define MPT2SAS_RELEASE_VERSION                15
+
+/*
+ * Set MPT2SAS_SG_DEPTH value based on user input.
+ */
+#ifdef CONFIG_SCSI_MPT2SAS_MAX_SGE
+#if     CONFIG_SCSI_MPT2SAS_MAX_SGE  < 16
+#define MPT2SAS_SG_DEPTH       16
+#elif CONFIG_SCSI_MPT2SAS_MAX_SGE  > 128
+#define MPT2SAS_SG_DEPTH       128
+#else
+#define MPT2SAS_SG_DEPTH       CONFIG_SCSI_MPT2SAS_MAX_SGE
+#endif
+#else
+#define MPT2SAS_SG_DEPTH       128 /* MAX_HW_SEGMENTS */
+#endif
+
+
+/*
+ * Generic Defines
+ */
+#define MPT2SAS_SATA_QUEUE_DEPTH       32
+#define MPT2SAS_SAS_QUEUE_DEPTH                254
+#define MPT2SAS_RAID_QUEUE_DEPTH       128
+
+#define MPT_NAME_LENGTH                        32      /* generic length of strings */
+#define MPT_STRING_LENGTH              64
+
+#define        MPT_MAX_CALLBACKS               16
+
+#define         CAN_SLEEP                      1
+#define  NO_SLEEP                      0
+
+#define INTERNAL_CMDS_COUNT            10      /* reserved cmds */
+
+#define MPI2_HIM_MASK                  0xFFFFFFFF /* mask every bit*/
+
+#define MPT2SAS_INVALID_DEVICE_HANDLE  0xFFFF
+
+
+/*
+ * reset phases
+ */
+#define MPT2_IOC_PRE_RESET             1 /* prior to host reset */
+#define MPT2_IOC_AFTER_RESET           2 /* just after host reset */
+#define MPT2_IOC_DONE_RESET            3 /* links re-initialized */
+
+/*
+ * logging format
+ */
+#define MPT2SAS_FMT                    "%s: "
+#define MPT2SAS_DEBUG_FMT              KERN_DEBUG MPT2SAS_FMT
+#define MPT2SAS_INFO_FMT               KERN_INFO MPT2SAS_FMT
+#define MPT2SAS_NOTE_FMT               KERN_NOTICE MPT2SAS_FMT
+#define MPT2SAS_WARN_FMT               KERN_WARNING MPT2SAS_FMT
+#define MPT2SAS_ERR_FMT                        KERN_ERR MPT2SAS_FMT
+
+/*
+ * per target private data
+ */
+#define MPT_TARGET_FLAGS_RAID_COMPONENT        0x01
+#define MPT_TARGET_FLAGS_VOLUME                0x02
+#define MPT_TARGET_FLAGS_DELETED       0x04
+
+/**
+ * struct MPT2SAS_TARGET - starget private hostdata
+ * @starget: starget object
+ * @sas_address: target sas address
+ * @handle: device handle
+ * @num_luns: number luns
+ * @flags: MPT_TARGET_FLAGS_XXX flags
+ * @deleted: target flaged for deletion
+ * @tm_busy: target is busy with TM request.
+ */
+struct MPT2SAS_TARGET {
+       struct scsi_target *starget;
+       u64     sas_address;
+       u16     handle;
+       int     num_luns;
+       u32     flags;
+       u8      deleted;
+       u8      tm_busy;
+};
+
+/*
+ * per device private data
+ */
+#define MPT_DEVICE_FLAGS_INIT          0x01
+#define MPT_DEVICE_TLR_ON              0x02
+
+/**
+ * struct MPT2SAS_DEVICE - sdev private hostdata
+ * @sas_target: starget private hostdata
+ * @lun: lun number
+ * @flags: MPT_DEVICE_XXX flags
+ * @configured_lun: lun is configured
+ * @block: device is in SDEV_BLOCK state
+ * @tlr_snoop_check: flag used in determining whether to disable TLR
+ */
+struct MPT2SAS_DEVICE {
+       struct MPT2SAS_TARGET *sas_target;
+       unsigned int    lun;
+       u32     flags;
+       u8      configured_lun;
+       u8      block;
+       u8      tlr_snoop_check;
+};
+
+#define MPT2_CMD_NOT_USED      0x8000  /* free */
+#define MPT2_CMD_COMPLETE      0x0001  /* completed */
+#define MPT2_CMD_PENDING       0x0002  /* pending */
+#define MPT2_CMD_REPLY_VALID   0x0004  /* reply is valid */
+#define MPT2_CMD_RESET         0x0008  /* host reset dropped the command */
+
+/**
+ * struct _internal_cmd - internal commands struct
+ * @mutex: mutex
+ * @done: completion
+ * @reply: reply message pointer
+ * @status: MPT2_CMD_XXX status
+ * @smid: system message id
+ */
+struct _internal_cmd {
+       struct mutex mutex;
+       struct completion done;
+       void    *reply;
+       u16     status;
+       u16     smid;
+};
+
+/*
+ * SAS Topology Structures
+ */
+
+/**
+ * struct _sas_device - attached device information
+ * @list: sas device list
+ * @starget: starget object
+ * @sas_address: device sas address
+ * @device_name: retrieved from the SAS IDENTIFY frame.
+ * @handle: device handle
+ * @parent_handle: handle to parent device
+ * @enclosure_handle: enclosure handle
+ * @enclosure_logical_id: enclosure logical identifier
+ * @volume_handle: volume handle (valid when hidden raid member)
+ * @volume_wwid: volume unique identifier
+ * @device_info: bitfield provides detailed info about the device
+ * @id: target id
+ * @channel: target channel
+ * @slot: number number
+ * @hidden_raid_component: set to 1 when this is a raid member
+ * @responding: used in _scsih_sas_device_mark_responding
+ */
+struct _sas_device {
+       struct list_head list;
+       struct scsi_target *starget;
+       u64     sas_address;
+       u64     device_name;
+       u16     handle;
+       u16     parent_handle;
+       u16     enclosure_handle;
+       u64     enclosure_logical_id;
+       u16     volume_handle;
+       u64     volume_wwid;
+       u32     device_info;
+       int     id;
+       int     channel;
+       u16     slot;
+       u8      hidden_raid_component;
+       u8      responding;
+};
+
+/**
+ * struct _raid_device - raid volume link list
+ * @list: sas device list
+ * @starget: starget object
+ * @sdev: scsi device struct (volumes are single lun)
+ * @wwid: unique identifier for the volume
+ * @handle: device handle
+ * @id: target id
+ * @channel: target channel
+ * @volume_type: the raid level
+ * @device_info: bitfield provides detailed info about the hidden components
+ * @num_pds: number of hidden raid components
+ * @responding: used in _scsih_raid_device_mark_responding
+ */
+struct _raid_device {
+       struct list_head list;
+       struct scsi_target *starget;
+       struct scsi_device *sdev;
+       u64     wwid;
+       u16     handle;
+       int     id;
+       int     channel;
+       u8      volume_type;
+       u32     device_info;
+       u8      num_pds;
+       u8      responding;
+};
+
+/**
+ * struct _boot_device - boot device info
+ * @is_raid: flag to indicate whether this is volume
+ * @device: holds pointer for either struct _sas_device or
+ *     struct _raid_device
+ */
+struct _boot_device {
+       u8 is_raid;
+       void *device;
+};
+
+/**
+ * struct _sas_port - wide/narrow sas port information
+ * @port_list: list of ports belonging to expander
+ * @handle: device handle for this port
+ * @sas_address: sas address of this port
+ * @num_phys: number of phys belonging to this port
+ * @remote_identify: attached device identification
+ * @rphy: sas transport rphy object
+ * @port: sas transport wide/narrow port object
+ * @phy_list: _sas_phy list objects belonging to this port
+ */
+struct _sas_port {
+       struct list_head port_list;
+       u16     handle;
+       u64     sas_address;
+       u8      num_phys;
+       struct sas_identify remote_identify;
+       struct sas_rphy *rphy;
+       struct sas_port *port;
+       struct list_head phy_list;
+};
+
+/**
+ * struct _sas_phy - phy information
+ * @port_siblings: list of phys belonging to a port
+ * @identify: phy identification
+ * @remote_identify: attached device identification
+ * @phy: sas transport phy object
+ * @phy_id: unique phy id
+ * @handle: device handle for this phy
+ * @attached_handle: device handle for attached device
+ */
+struct _sas_phy {
+       struct list_head port_siblings;
+       struct sas_identify identify;
+       struct sas_identify remote_identify;
+       struct sas_phy *phy;
+       u8      phy_id;
+       u16     handle;
+       u16     attached_handle;
+};
+
+/**
+ * struct _sas_node - sas_host/expander information
+ * @list: list of expanders
+ * @parent_dev: parent device class
+ * @num_phys: number phys belonging to this sas_host/expander
+ * @sas_address: sas address of this sas_host/expander
+ * @handle: handle for this sas_host/expander
+ * @parent_handle: parent handle
+ * @enclosure_handle: handle for this a member of an enclosure
+ * @device_info: bitwise defining capabilities of this sas_host/expander
+ * @responding: used in _scsih_expander_device_mark_responding
+ * @phy: a list of phys that make up this sas_host/expander
+ * @sas_port_list: list of ports attached to this sas_host/expander
+ */
+struct _sas_node {
+       struct list_head list;
+       struct device *parent_dev;
+       u8      num_phys;
+       u64     sas_address;
+       u16     handle;
+       u16     parent_handle;
+       u16     enclosure_handle;
+       u64     enclosure_logical_id;
+       u8      responding;
+       struct  _sas_phy *phy;
+       struct list_head sas_port_list;
+};
+
+/**
+ * enum reset_type - reset state
+ * @FORCE_BIG_HAMMER: issue diagnostic reset
+ * @SOFT_RESET: issue message_unit_reset, if fails to to big hammer
+ */
+enum reset_type {
+       FORCE_BIG_HAMMER,
+       SOFT_RESET,
+};
+
+/**
+ * struct request_tracker - firmware request tracker
+ * @smid: system message id
+ * @scmd: scsi request pointer
+ * @cb_idx: callback index
+ * @chain_list: list of chains associated to this IO
+ * @tracker_list: list of free request (ioc->free_list)
+ */
+struct request_tracker {
+       u16     smid;
+       struct scsi_cmnd *scmd;
+       u8      cb_idx;
+       struct list_head tracker_list;
+};
+
+typedef void (*MPT_ADD_SGE)(void *paddr, u32 flags_length, dma_addr_t dma_addr);
+
+/**
+ * struct MPT2SAS_ADAPTER - per adapter struct
+ * @list: ioc_list
+ * @shost: shost object
+ * @id: unique adapter id
+ * @pci_irq: irq number
+ * @name: generic ioc string
+ * @tmp_string: tmp string used for logging
+ * @pdev: pci pdev object
+ * @chip: memory mapped register space
+ * @chip_phys: physical addrss prior to mapping
+ * @pio_chip: I/O mapped register space
+ * @logging_level: see mpt2sas_debug.h
+ * @ir_firmware: IR firmware present
+ * @bars: bitmask of BAR's that must be configured
+ * @mask_interrupts: ignore interrupt
+ * @fault_reset_work_q_name: fw fault work queue
+ * @fault_reset_work_q: ""
+ * @fault_reset_work: ""
+ * @firmware_event_name: fw event work queue
+ * @firmware_event_thread: ""
+ * @fw_events_off: flag to turn off fw event handling
+ * @fw_event_lock:
+ * @fw_event_list: list of fw events
+ * @aen_event_read_flag: event log was read
+ * @broadcast_aen_busy: broadcast aen waiting to be serviced
+ * @ioc_reset_in_progress: host reset in progress
+ * @ioc_reset_in_progress_lock:
+ * @ioc_link_reset_in_progress: phy/hard reset in progress
+ * @ignore_loginfos: ignore loginfos during task managment
+ * @remove_host: flag for when driver unloads, to avoid sending dev resets
+ * @wait_for_port_enable_to_complete:
+ * @msix_enable: flag indicating msix is enabled
+ * @msix_vector_count: number msix vectors
+ * @msix_table: virt address to the msix table
+ * @msix_table_backup: backup msix table
+ * @scsi_io_cb_idx: shost generated commands
+ * @tm_cb_idx: task management commands
+ * @transport_cb_idx: transport internal commands
+ * @ctl_cb_idx: clt internal commands
+ * @base_cb_idx: base internal commands
+ * @config_cb_idx: base internal commands
+ * @base_cmds:
+ * @transport_cmds:
+ * @tm_cmds:
+ * @ctl_cmds:
+ * @config_cmds:
+ * @base_add_sg_single: handler for either 32/64 bit sgl's
+ * @event_type: bits indicating which events to log
+ * @event_context: unique id for each logged event
+ * @event_log: event log pointer
+ * @event_masks: events that are masked
+ * @facts: static facts data
+ * @pfacts: static port facts data
+ * @manu_pg0: static manufacturing page 0
+ * @bios_pg2: static bios page 2
+ * @bios_pg3: static bios page 3
+ * @ioc_pg8: static ioc page 8
+ * @iounit_pg0: static iounit page 0
+ * @iounit_pg1: static iounit page 1
+ * @sas_hba: sas host object
+ * @sas_expander_list: expander object list
+ * @sas_node_lock:
+ * @sas_device_list: sas device object list
+ * @sas_device_init_list: sas device object list (used only at init time)
+ * @sas_device_lock:
+ * @io_missing_delay: time for IO completed by fw when PDR enabled
+ * @device_missing_delay: time for device missing by fw when PDR enabled
+ * @config_page_sz: config page size
+ * @config_page: reserve memory for config page payload
+ * @config_page_dma:
+ * @sge_size: sg element size for either 32/64 bit
+ * @request_depth: hba request queue depth
+ * @request_sz: per request frame size
+ * @request: pool of request frames
+ * @request_dma:
+ * @request_dma_sz:
+ * @scsi_lookup: firmware request tracker list
+ * @scsi_lookup_lock:
+ * @free_list: free list of request
+ * @chain: pool of chains
+ * @pending_io_count:
+ * @reset_wq:
+ * @chain_dma:
+ * @max_sges_in_main_message: number sg elements in main message
+ * @max_sges_in_chain_message: number sg elements per chain
+ * @chains_needed_per_io: max chains per io
+ * @chain_offset_value_for_main_message: location 1st sg in main
+ * @chain_depth: total chains allocated
+ * @sense: pool of sense
+ * @sense_dma:
+ * @sense_dma_pool:
+ * @reply_depth: hba reply queue depth:
+ * @reply_sz: per reply frame size:
+ * @reply: pool of replys:
+ * @reply_dma:
+ * @reply_dma_pool:
+ * @reply_free_queue_depth: reply free depth
+ * @reply_free: pool for reply free queue (32 bit addr)
+ * @reply_free_dma:
+ * @reply_free_dma_pool:
+ * @reply_free_host_index: tail index in pool to insert free replys
+ * @reply_post_queue_depth: reply post queue depth
+ * @reply_post_free: pool for reply post (64bit descriptor)
+ * @reply_post_free_dma:
+ * @reply_post_free_dma_pool:
+ * @reply_post_host_index: head index in the pool where FW completes IO
+ */
+struct MPT2SAS_ADAPTER {
+       struct list_head list;
+       struct Scsi_Host *shost;
+       u8              id;
+       u32             pci_irq;
+       char            name[MPT_NAME_LENGTH];
+       char            tmp_string[MPT_STRING_LENGTH];
+       struct pci_dev  *pdev;
+       Mpi2SystemInterfaceRegs_t __iomem *chip;
+       unsigned long   chip_phys;
+       unsigned long   pio_chip;
+       int             logging_level;
+       u8              ir_firmware;
+       int             bars;
+       u8              mask_interrupts;
+
+       /* fw fault handler */
+       char            fault_reset_work_q_name[20];
+       struct workqueue_struct *fault_reset_work_q;
+       struct delayed_work fault_reset_work;
+
+       /* fw event handler */
+       char            firmware_event_name[20];
+       struct workqueue_struct *firmware_event_thread;
+       u8              fw_events_off;
+       spinlock_t      fw_event_lock;
+       struct list_head fw_event_list;
+
+        /* misc flags */
+       int             aen_event_read_flag;
+       u8              broadcast_aen_busy;
+       u8              ioc_reset_in_progress;
+       u8              shost_recovery;
+       spinlock_t      ioc_reset_in_progress_lock;
+       u8              ioc_link_reset_in_progress;
+       u8              ignore_loginfos;
+       u8              remove_host;
+       u8              wait_for_port_enable_to_complete;
+
+       u8              msix_enable;
+       u16             msix_vector_count;
+       u32             *msix_table;
+       u32             *msix_table_backup;
+
+       /* internal commands, callback index */
+       u8              scsi_io_cb_idx;
+       u8              tm_cb_idx;
+       u8              transport_cb_idx;
+       u8              ctl_cb_idx;
+       u8              base_cb_idx;
+       u8              config_cb_idx;
+       struct _internal_cmd base_cmds;
+       struct _internal_cmd transport_cmds;
+       struct _internal_cmd tm_cmds;
+       struct _internal_cmd ctl_cmds;
+       struct _internal_cmd config_cmds;
+
+       MPT_ADD_SGE     base_add_sg_single;
+
+       /* event log */
+       u32             event_type[MPI2_EVENT_NOTIFY_EVENTMASK_WORDS];
+       u32             event_context;
+       void            *event_log;
+       u32             event_masks[MPI2_EVENT_NOTIFY_EVENTMASK_WORDS];
+
+       /* static config pages */
+       Mpi2IOCFactsReply_t facts;
+       Mpi2PortFactsReply_t *pfacts;
+       Mpi2ManufacturingPage0_t manu_pg0;
+       Mpi2BiosPage2_t bios_pg2;
+       Mpi2BiosPage3_t bios_pg3;
+       Mpi2IOCPage8_t ioc_pg8;
+       Mpi2IOUnitPage0_t iounit_pg0;
+       Mpi2IOUnitPage1_t iounit_pg1;
+
+       struct _boot_device req_boot_device;
+       struct _boot_device req_alt_boot_device;
+       struct _boot_device current_boot_device;
+
+       /* sas hba, expander, and device list */
+       struct _sas_node sas_hba;
+       struct list_head sas_expander_list;
+       spinlock_t      sas_node_lock;
+       struct list_head sas_device_list;
+       struct list_head sas_device_init_list;
+       spinlock_t      sas_device_lock;
+       struct list_head raid_device_list;
+       spinlock_t      raid_device_lock;
+       u8              io_missing_delay;
+       u16             device_missing_delay;
+       int             sas_id;
+
+       /* config page */
+       u16             config_page_sz;
+       void            *config_page;
+       dma_addr_t      config_page_dma;
+
+       /* request */
+       u16             sge_size;
+       u16             request_depth;
+       u16             request_sz;
+       u8              *request;
+       dma_addr_t      request_dma;
+       u32             request_dma_sz;
+       struct request_tracker *scsi_lookup;
+       spinlock_t scsi_lookup_lock;
+       struct list_head free_list;
+       int             pending_io_count;
+       wait_queue_head_t reset_wq;
+
+       /* chain */
+       u8              *chain;
+       dma_addr_t      chain_dma;
+       u16             max_sges_in_main_message;
+       u16             max_sges_in_chain_message;
+       u16             chains_needed_per_io;
+       u16             chain_offset_value_for_main_message;
+       u16             chain_depth;
+
+       /* sense */
+       u8              *sense;
+       dma_addr_t      sense_dma;
+       struct dma_pool *sense_dma_pool;
+
+       /* reply */
+       u16             reply_sz;
+       u8              *reply;
+       dma_addr_t      reply_dma;
+       struct dma_pool *reply_dma_pool;
+
+       /* reply free queue */
+       u16             reply_free_queue_depth;
+       u32             *reply_free;
+       dma_addr_t      reply_free_dma;
+       struct dma_pool *reply_free_dma_pool;
+       u32             reply_free_host_index;
+
+       /* reply post queue */
+       u16             reply_post_queue_depth;
+       Mpi2ReplyDescriptorsUnion_t *reply_post_free;
+       dma_addr_t      reply_post_free_dma;
+       struct dma_pool *reply_post_free_dma_pool;
+       u32             reply_post_host_index;
+
+       /* diag buffer support */
+       u8              *diag_buffer[MPI2_DIAG_BUF_TYPE_COUNT];
+       u32             diag_buffer_sz[MPI2_DIAG_BUF_TYPE_COUNT];
+       dma_addr_t      diag_buffer_dma[MPI2_DIAG_BUF_TYPE_COUNT];
+       u8              diag_buffer_status[MPI2_DIAG_BUF_TYPE_COUNT];
+       u32             unique_id[MPI2_DIAG_BUF_TYPE_COUNT];
+       u32             product_specific[MPI2_DIAG_BUF_TYPE_COUNT][23];
+       u32             diagnostic_flags[MPI2_DIAG_BUF_TYPE_COUNT];
+};
+
+typedef void (*MPT_CALLBACK)(struct MPT2SAS_ADAPTER *ioc, u16 smid, u8 VF_ID,
+    u32 reply);
+
+
+/* base shared API */
+extern struct list_head ioc_list;
+
+int mpt2sas_base_attach(struct MPT2SAS_ADAPTER *ioc);
+void mpt2sas_base_detach(struct MPT2SAS_ADAPTER *ioc);
+int mpt2sas_base_map_resources(struct MPT2SAS_ADAPTER *ioc);
+void mpt2sas_base_free_resources(struct MPT2SAS_ADAPTER *ioc);
+int mpt2sas_base_hard_reset_handler(struct MPT2SAS_ADAPTER *ioc, int sleep_flag,
+    enum reset_type type);
+
+void *mpt2sas_base_get_msg_frame(struct MPT2SAS_ADAPTER *ioc, u16 smid);
+void *mpt2sas_base_get_sense_buffer(struct MPT2SAS_ADAPTER *ioc, u16 smid);
+void mpt2sas_base_build_zero_len_sge(struct MPT2SAS_ADAPTER *ioc, void *paddr);
+dma_addr_t mpt2sas_base_get_msg_frame_dma(struct MPT2SAS_ADAPTER *ioc, u16 smid);
+dma_addr_t mpt2sas_base_get_sense_buffer_dma(struct MPT2SAS_ADAPTER *ioc, u16 smid);
+
+u16 mpt2sas_base_get_smid(struct MPT2SAS_ADAPTER *ioc, u8 cb_idx);
+void mpt2sas_base_free_smid(struct MPT2SAS_ADAPTER *ioc, u16 smid);
+void mpt2sas_base_put_smid_scsi_io(struct MPT2SAS_ADAPTER *ioc, u16 smid, u8 vf_id,
+    u16 handle);
+void mpt2sas_base_put_smid_hi_priority(struct MPT2SAS_ADAPTER *ioc, u16 smid, u8 vf_id);
+void mpt2sas_base_put_smid_target_assist(struct MPT2SAS_ADAPTER *ioc, u16 smid,
+    u8 vf_id, u16 io_index);
+void mpt2sas_base_put_smid_default(struct MPT2SAS_ADAPTER *ioc, u16 smid, u8 vf_id);
+void mpt2sas_base_initialize_callback_handler(void);
+u8 mpt2sas_base_register_callback_handler(MPT_CALLBACK cb_func);
+void mpt2sas_base_release_callback_handler(u8 cb_idx);
+
+void mpt2sas_base_done(struct MPT2SAS_ADAPTER *ioc, u16 smid, u8 VF_ID, u32 reply);
+void *mpt2sas_base_get_reply_virt_addr(struct MPT2SAS_ADAPTER *ioc, u32 phys_addr);
+
+u32 mpt2sas_base_get_iocstate(struct MPT2SAS_ADAPTER *ioc, int cooked);
+
+void mpt2sas_base_fault_info(struct MPT2SAS_ADAPTER *ioc , u16 fault_code);
+int mpt2sas_base_sas_iounit_control(struct MPT2SAS_ADAPTER *ioc,
+    Mpi2SasIoUnitControlReply_t *mpi_reply, Mpi2SasIoUnitControlRequest_t
+    *mpi_request);
+int mpt2sas_base_scsi_enclosure_processor(struct MPT2SAS_ADAPTER *ioc,
+    Mpi2SepReply_t *mpi_reply, Mpi2SepRequest_t *mpi_request);
+void mpt2sas_base_validate_event_type(struct MPT2SAS_ADAPTER *ioc, u32 *event_type);
+
+/* scsih shared API */
+void mpt2sas_scsih_issue_tm(struct MPT2SAS_ADAPTER *ioc, u16 handle, uint lun,
+    u8 type, u16 smid_task, ulong timeout);
+void mpt2sas_scsih_set_tm_flag(struct MPT2SAS_ADAPTER *ioc, u16 handle);
+void mpt2sas_scsih_clear_tm_flag(struct MPT2SAS_ADAPTER *ioc, u16 handle);
+struct _sas_node *mpt2sas_scsih_expander_find_by_handle(struct MPT2SAS_ADAPTER *ioc,
+    u16 handle);
+struct _sas_node *mpt2sas_scsih_expander_find_by_sas_address(struct MPT2SAS_ADAPTER
+    *ioc, u64 sas_address);
+struct _sas_device *mpt2sas_scsih_sas_device_find_by_sas_address(
+    struct MPT2SAS_ADAPTER *ioc, u64 sas_address);
+
+void mpt2sas_scsih_event_callback(struct MPT2SAS_ADAPTER *ioc, u8 VF_ID, u32 reply);
+void mpt2sas_scsih_reset_handler(struct MPT2SAS_ADAPTER *ioc, int reset_phase);
+
+/* config shared API */
+void mpt2sas_config_done(struct MPT2SAS_ADAPTER *ioc, u16 smid, u8 VF_ID, u32 reply);
+int mpt2sas_config_get_number_hba_phys(struct MPT2SAS_ADAPTER *ioc, u8 *num_phys);
+int mpt2sas_config_get_manufacturing_pg0(struct MPT2SAS_ADAPTER *ioc,
+    Mpi2ConfigReply_t *mpi_reply, Mpi2ManufacturingPage0_t *config_page);
+int mpt2sas_config_get_bios_pg2(struct MPT2SAS_ADAPTER *ioc, Mpi2ConfigReply_t
+    *mpi_reply, Mpi2BiosPage2_t *config_page);
+int mpt2sas_config_get_bios_pg3(struct MPT2SAS_ADAPTER *ioc, Mpi2ConfigReply_t
+    *mpi_reply, Mpi2BiosPage3_t *config_page);
+int mpt2sas_config_get_iounit_pg0(struct MPT2SAS_ADAPTER *ioc, Mpi2ConfigReply_t
+    *mpi_reply, Mpi2IOUnitPage0_t *config_page);
+int mpt2sas_config_get_sas_device_pg0(struct MPT2SAS_ADAPTER *ioc, Mpi2ConfigReply_t
+    *mpi_reply, Mpi2SasDevicePage0_t *config_page, u32 form, u32 handle);
+int mpt2sas_config_get_sas_device_pg1(struct MPT2SAS_ADAPTER *ioc, Mpi2ConfigReply_t
+    *mpi_reply, Mpi2SasDevicePage1_t *config_page, u32 form, u32 handle);
+int mpt2sas_config_get_sas_iounit_pg0(struct MPT2SAS_ADAPTER *ioc, Mpi2ConfigReply_t
+    *mpi_reply, Mpi2SasIOUnitPage0_t *config_page, u16 sz);
+int mpt2sas_config_get_iounit_pg1(struct MPT2SAS_ADAPTER *ioc, Mpi2ConfigReply_t
+    *mpi_reply, Mpi2IOUnitPage1_t *config_page);
+int mpt2sas_config_set_iounit_pg1(struct MPT2SAS_ADAPTER *ioc, Mpi2ConfigReply_t
+    *mpi_reply, Mpi2IOUnitPage1_t config_page);
+int mpt2sas_config_get_sas_iounit_pg1(struct MPT2SAS_ADAPTER *ioc, Mpi2ConfigReply_t
+    *mpi_reply, Mpi2SasIOUnitPage1_t *config_page, u16 sz);
+int mpt2sas_config_get_ioc_pg8(struct MPT2SAS_ADAPTER *ioc, Mpi2ConfigReply_t
+    *mpi_reply, Mpi2IOCPage8_t *config_page);
+int mpt2sas_config_get_expander_pg0(struct MPT2SAS_ADAPTER *ioc, Mpi2ConfigReply_t
+    *mpi_reply, Mpi2ExpanderPage0_t *config_page, u32 form, u32 handle);
+int mpt2sas_config_get_expander_pg1(struct MPT2SAS_ADAPTER *ioc, Mpi2ConfigReply_t
+    *mpi_reply, Mpi2ExpanderPage1_t *config_page, u32 phy_number, u16 handle);
+int mpt2sas_config_get_enclosure_pg0(struct MPT2SAS_ADAPTER *ioc, Mpi2ConfigReply_t
+    *mpi_reply, Mpi2SasEnclosurePage0_t *config_page, u32 form, u32 handle);
+int mpt2sas_config_get_phy_pg0(struct MPT2SAS_ADAPTER *ioc, Mpi2ConfigReply_t
+    *mpi_reply, Mpi2SasPhyPage0_t *config_page, u32 phy_number);
+int mpt2sas_config_get_phy_pg1(struct MPT2SAS_ADAPTER *ioc, Mpi2ConfigReply_t
+    *mpi_reply, Mpi2SasPhyPage1_t *config_page, u32 phy_number);
+int mpt2sas_config_get_raid_volume_pg1(struct MPT2SAS_ADAPTER *ioc, Mpi2ConfigReply_t
+    *mpi_reply, Mpi2RaidVolPage1_t *config_page, u32 form, u32 handle);
+int mpt2sas_config_get_number_pds(struct MPT2SAS_ADAPTER *ioc, u16 handle, u8 *num_pds);
+int mpt2sas_config_get_raid_volume_pg0(struct MPT2SAS_ADAPTER *ioc, Mpi2ConfigReply_t
+    *mpi_reply, Mpi2RaidVolPage0_t *config_page, u32 form, u32 handle, u16 sz);
+int mpt2sas_config_get_phys_disk_pg0(struct MPT2SAS_ADAPTER *ioc, Mpi2ConfigReply_t
+    *mpi_reply, Mpi2RaidPhysDiskPage0_t *config_page, u32 form,
+    u32 form_specific);
+int mpt2sas_config_get_volume_handle(struct MPT2SAS_ADAPTER *ioc, u16 pd_handle,
+    u16 *volume_handle);
+int mpt2sas_config_get_volume_wwid(struct MPT2SAS_ADAPTER *ioc, u16 volume_handle,
+    u64 *wwid);
+
+/* ctl shared API */
+extern struct device_attribute *mpt2sas_host_attrs[];
+extern struct device_attribute *mpt2sas_dev_attrs[];
+void mpt2sas_ctl_init(void);
+void mpt2sas_ctl_exit(void);
+void mpt2sas_ctl_done(struct MPT2SAS_ADAPTER *ioc, u16 smid, u8 VF_ID, u32 reply);
+void mpt2sas_ctl_reset_handler(struct MPT2SAS_ADAPTER *ioc, int reset_phase);
+void mpt2sas_ctl_event_callback(struct MPT2SAS_ADAPTER *ioc, u8 VF_ID, u32 reply);
+void mpt2sas_ctl_add_to_event_log(struct MPT2SAS_ADAPTER *ioc,
+    Mpi2EventNotificationReply_t *mpi_reply);
+
+/* transport shared API */
+void mpt2sas_transport_done(struct MPT2SAS_ADAPTER *ioc, u16 smid, u8 VF_ID, u32 reply);
+struct _sas_port *mpt2sas_transport_port_add(struct MPT2SAS_ADAPTER *ioc,
+    u16 handle, u16 parent_handle);
+void mpt2sas_transport_port_remove(struct MPT2SAS_ADAPTER *ioc, u64 sas_address,
+    u16 parent_handle);
+int mpt2sas_transport_add_host_phy(struct MPT2SAS_ADAPTER *ioc, struct _sas_phy
+    *mpt2sas_phy, Mpi2SasPhyPage0_t phy_pg0, struct device *parent_dev);
+int mpt2sas_transport_add_expander_phy(struct MPT2SAS_ADAPTER *ioc, struct _sas_phy
+    *mpt2sas_phy, Mpi2ExpanderPage1_t expander_pg1, struct device *parent_dev);
+void mpt2sas_transport_update_phy_link_change(struct MPT2SAS_ADAPTER *ioc, u16 handle,
+   u16 attached_handle, u8 phy_number, u8 link_rate);
+extern struct sas_function_template mpt2sas_transport_functions;
+extern struct scsi_transport_template *mpt2sas_transport_template;
+
+#endif /* MPT2SAS_BASE_H_INCLUDED */
diff --git a/drivers/scsi/mpt2sas/mpt2sas_config.c b/drivers/scsi/mpt2sas/mpt2sas_config.c
new file mode 100644 (file)
index 0000000..58cfb97
--- /dev/null
@@ -0,0 +1,1873 @@
+/*
+ * This module provides common API for accessing firmware configuration pages
+ *
+ * This code is based on drivers/scsi/mpt2sas/mpt2_base.c
+ * Copyright (C) 2007-2008  LSI Corporation
+ *  (mailto:DL-MPTFusionLinux@lsi.com)
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * NO WARRANTY
+ * THE PROGRAM IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OR
+ * CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED INCLUDING, WITHOUT
+ * LIMITATION, ANY WARRANTIES OR CONDITIONS OF TITLE, NON-INFRINGEMENT,
+ * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. Each Recipient is
+ * solely responsible for determining the appropriateness of using and
+ * distributing the Program and assumes all risks associated with its
+ * exercise of rights under this Agreement, including but not limited to
+ * the risks and costs of program errors, damage to or loss of data,
+ * programs or equipment, and unavailability or interruption of operations.
+
+ * DISCLAIMER OF LIABILITY
+ * NEITHER RECIPIENT NOR ANY CONTRIBUTORS SHALL HAVE ANY LIABILITY FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING WITHOUT LIMITATION LOST PROFITS), 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 OR DISTRIBUTION OF THE PROGRAM OR THE EXERCISE OF ANY RIGHTS GRANTED
+ * HEREUNDER, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGES
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301,
+ * USA.
+ */
+
+#include <linux/version.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/errno.h>
+#include <linux/blkdev.h>
+#include <linux/sched.h>
+#include <linux/workqueue.h>
+#include <linux/delay.h>
+#include <linux/pci.h>
+
+#include "mpt2sas_base.h"
+
+/* local definitions */
+
+/* Timeout for config page request (in seconds) */
+#define MPT2_CONFIG_PAGE_DEFAULT_TIMEOUT 15
+
+/* Common sgl flags for READING a config page. */
+#define MPT2_CONFIG_COMMON_SGLFLAGS ((MPI2_SGE_FLAGS_SIMPLE_ELEMENT | \
+    MPI2_SGE_FLAGS_LAST_ELEMENT | MPI2_SGE_FLAGS_END_OF_BUFFER \
+    | MPI2_SGE_FLAGS_END_OF_LIST) << MPI2_SGE_FLAGS_SHIFT)
+
+/* Common sgl flags for WRITING a config page. */
+#define MPT2_CONFIG_COMMON_WRITE_SGLFLAGS ((MPI2_SGE_FLAGS_SIMPLE_ELEMENT | \
+    MPI2_SGE_FLAGS_LAST_ELEMENT | MPI2_SGE_FLAGS_END_OF_BUFFER \
+    | MPI2_SGE_FLAGS_END_OF_LIST | MPI2_SGE_FLAGS_HOST_TO_IOC) \
+    << MPI2_SGE_FLAGS_SHIFT)
+
+/**
+ * struct config_request - obtain dma memory via routine
+ * @config_page_sz: size
+ * @config_page: virt pointer
+ * @config_page_dma: phys pointer
+ *
+ */
+struct config_request{
+       u16                     config_page_sz;
+       void                    *config_page;
+       dma_addr_t              config_page_dma;
+};
+
+#ifdef CONFIG_SCSI_MPT2SAS_LOGGING
+/**
+ * _config_display_some_debug - debug routine
+ * @ioc: per adapter object
+ * @smid: system request message index
+ * @calling_function_name: string pass from calling function
+ * @mpi_reply: reply message frame
+ * Context: none.
+ *
+ * Function for displaying debug info helpfull when debugging issues
+ * in this module.
+ */
+static void
+_config_display_some_debug(struct MPT2SAS_ADAPTER *ioc, u16 smid,
+    char *calling_function_name, MPI2DefaultReply_t *mpi_reply)
+{
+       Mpi2ConfigRequest_t *mpi_request;
+       char *desc = NULL;
+
+       if (!(ioc->logging_level & MPT_DEBUG_CONFIG))
+               return;
+
+       mpi_request = mpt2sas_base_get_msg_frame(ioc, smid);
+       switch (mpi_request->Header.PageType & MPI2_CONFIG_PAGETYPE_MASK) {
+       case MPI2_CONFIG_PAGETYPE_IO_UNIT:
+               desc = "io_unit";
+               break;
+       case MPI2_CONFIG_PAGETYPE_IOC:
+               desc = "ioc";
+               break;
+       case MPI2_CONFIG_PAGETYPE_BIOS:
+               desc = "bios";
+               break;
+       case MPI2_CONFIG_PAGETYPE_RAID_VOLUME:
+               desc = "raid_volume";
+               break;
+       case MPI2_CONFIG_PAGETYPE_MANUFACTURING:
+               desc = "manufaucturing";
+               break;
+       case MPI2_CONFIG_PAGETYPE_RAID_PHYSDISK:
+               desc = "physdisk";
+               break;
+       case MPI2_CONFIG_PAGETYPE_EXTENDED:
+               switch (mpi_request->ExtPageType) {
+               case MPI2_CONFIG_EXTPAGETYPE_SAS_IO_UNIT:
+                       desc = "sas_io_unit";
+                       break;
+               case MPI2_CONFIG_EXTPAGETYPE_SAS_EXPANDER:
+                       desc = "sas_expander";
+                       break;
+               case MPI2_CONFIG_EXTPAGETYPE_SAS_DEVICE:
+                       desc = "sas_device";
+                       break;
+               case MPI2_CONFIG_EXTPAGETYPE_SAS_PHY:
+                       desc = "sas_phy";
+                       break;
+               case MPI2_CONFIG_EXTPAGETYPE_LOG:
+                       desc = "log";
+                       break;
+               case MPI2_CONFIG_EXTPAGETYPE_ENCLOSURE:
+                       desc = "enclosure";
+                       break;
+               case MPI2_CONFIG_EXTPAGETYPE_RAID_CONFIG:
+                       desc = "raid_config";
+                       break;
+               case MPI2_CONFIG_EXTPAGETYPE_DRIVER_MAPPING:
+                       desc = "driver_mappping";
+                       break;
+               }
+               break;
+       }
+
+       if (!desc)
+               return;
+
+       printk(MPT2SAS_DEBUG_FMT "%s: %s(%d), action(%d), form(0x%08x), "
+           "smid(%d)\n", ioc->name, calling_function_name, desc,
+           mpi_request->Header.PageNumber, mpi_request->Action,
+           le32_to_cpu(mpi_request->PageAddress), smid);
+
+       if (!mpi_reply)
+               return;
+
+       if (mpi_reply->IOCStatus || mpi_reply->IOCLogInfo)
+               printk(MPT2SAS_DEBUG_FMT
+                   "\tiocstatus(0x%04x), loginfo(0x%08x)\n",
+                   ioc->name, le16_to_cpu(mpi_reply->IOCStatus),
+                   le32_to_cpu(mpi_reply->IOCLogInfo));
+}
+#endif
+
+/**
+ * mpt2sas_config_done - config page completion routine
+ * @ioc: per adapter object
+ * @smid: system request message index
+ * @VF_ID: virtual function id
+ * @reply: reply message frame(lower 32bit addr)
+ * Context: none.
+ *
+ * The callback handler when using _config_request.
+ *
+ * Return nothing.
+ */
+void
+mpt2sas_config_done(struct MPT2SAS_ADAPTER *ioc, u16 smid, u8 VF_ID, u32 reply)
+{
+       MPI2DefaultReply_t *mpi_reply;
+
+       if (ioc->config_cmds.status == MPT2_CMD_NOT_USED)
+               return;
+       if (ioc->config_cmds.smid != smid)
+               return;
+       ioc->config_cmds.status |= MPT2_CMD_COMPLETE;
+       mpi_reply =  mpt2sas_base_get_reply_virt_addr(ioc, reply);
+       if (mpi_reply) {
+               ioc->config_cmds.status |= MPT2_CMD_REPLY_VALID;
+               memcpy(ioc->config_cmds.reply, mpi_reply,
+                   mpi_reply->MsgLength*4);
+       }
+       ioc->config_cmds.status &= ~MPT2_CMD_PENDING;
+#ifdef CONFIG_SCSI_MPT2SAS_LOGGING
+       _config_display_some_debug(ioc, smid, "config_done", mpi_reply);
+#endif
+       complete(&ioc->config_cmds.done);
+}
+
+/**
+ * _config_request - main routine for sending config page requests
+ * @ioc: per adapter object
+ * @mpi_request: request message frame
+ * @mpi_reply: reply mf payload returned from firmware
+ * @timeout: timeout in seconds
+ * Context: sleep, the calling function needs to acquire the config_cmds.mutex
+ *
+ * A generic API for config page requests to firmware.
+ *
+ * The ioc->config_cmds.status flag should be MPT2_CMD_NOT_USED before calling
+ * this API.
+ *
+ * The callback index is set inside `ioc->config_cb_idx.
+ *
+ * Returns 0 for success, non-zero for failure.
+ */
+static int
+_config_request(struct MPT2SAS_ADAPTER *ioc, Mpi2ConfigRequest_t
+    *mpi_request, Mpi2ConfigReply_t *mpi_reply, int timeout)
+{
+       u16 smid;
+       u32 ioc_state;
+       unsigned long timeleft;
+       Mpi2ConfigRequest_t *config_request;
+       int r;
+       u8 retry_count;
+       u8 issue_reset;
+       u16 wait_state_count;
+
+       if (ioc->config_cmds.status != MPT2_CMD_NOT_USED) {
+               printk(MPT2SAS_ERR_FMT "%s: config_cmd in use\n",
+                   ioc->name, __func__);
+               return -EAGAIN;
+       }
+       retry_count = 0;
+
+ retry_config:
+       wait_state_count = 0;
+       ioc_state = mpt2sas_base_get_iocstate(ioc, 1);
+       while (ioc_state != MPI2_IOC_STATE_OPERATIONAL) {
+               if (wait_state_count++ == MPT2_CONFIG_PAGE_DEFAULT_TIMEOUT) {
+                       printk(MPT2SAS_ERR_FMT
+                           "%s: failed due to ioc not operational\n",
+                           ioc->name, __func__);
+                       ioc->config_cmds.status = MPT2_CMD_NOT_USED;
+                       return -EFAULT;
+               }
+               ssleep(1);
+               ioc_state = mpt2sas_base_get_iocstate(ioc, 1);
+               printk(MPT2SAS_INFO_FMT "%s: waiting for "
+                   "operational state(count=%d)\n", ioc->name,
+                   __func__, wait_state_count);
+       }
+       if (wait_state_count)
+               printk(MPT2SAS_INFO_FMT "%s: ioc is operational\n",
+                   ioc->name, __func__);
+
+       smid = mpt2sas_base_get_smid(ioc, ioc->config_cb_idx);
+       if (!smid) {
+               printk(MPT2SAS_ERR_FMT "%s: failed obtaining a smid\n",
+                   ioc->name, __func__);
+               ioc->config_cmds.status = MPT2_CMD_NOT_USED;
+               return -EAGAIN;
+       }
+
+       r = 0;
+       memset(mpi_reply, 0, sizeof(Mpi2ConfigReply_t));
+       ioc->config_cmds.status = MPT2_CMD_PENDING;
+       config_request = mpt2sas_base_get_msg_frame(ioc, smid);
+       ioc->config_cmds.smid = smid;
+       memcpy(config_request, mpi_request, sizeof(Mpi2ConfigRequest_t));
+#ifdef CONFIG_SCSI_MPT2SAS_LOGGING
+       _config_display_some_debug(ioc, smid, "config_request", NULL);
+#endif
+       mpt2sas_base_put_smid_default(ioc, smid, config_request->VF_ID);
+       timeleft = wait_for_completion_timeout(&ioc->config_cmds.done,
+           timeout*HZ);
+       if (!(ioc->config_cmds.status & MPT2_CMD_COMPLETE)) {
+               printk(MPT2SAS_ERR_FMT "%s: timeout\n",
+                   ioc->name, __func__);
+               _debug_dump_mf(mpi_request,
+                   sizeof(Mpi2ConfigRequest_t)/4);
+               if (!(ioc->config_cmds.status & MPT2_CMD_RESET))
+                       issue_reset = 1;
+               goto issue_host_reset;
+       }
+       if (ioc->config_cmds.status & MPT2_CMD_REPLY_VALID)
+               memcpy(mpi_reply, ioc->config_cmds.reply,
+                   sizeof(Mpi2ConfigReply_t));
+       if (retry_count)
+               printk(MPT2SAS_INFO_FMT "%s: retry completed!!\n",
+                   ioc->name, __func__);
+       ioc->config_cmds.status = MPT2_CMD_NOT_USED;
+       return r;
+
+ issue_host_reset:
+       if (issue_reset)
+               mpt2sas_base_hard_reset_handler(ioc, CAN_SLEEP,
+                   FORCE_BIG_HAMMER);
+       ioc->config_cmds.status = MPT2_CMD_NOT_USED;
+       if (!retry_count) {
+               printk(MPT2SAS_INFO_FMT "%s: attempting retry\n",
+                   ioc->name, __func__);
+               retry_count++;
+               goto retry_config;
+       }
+       return -EFAULT;
+}
+
+/**
+ * _config_alloc_config_dma_memory - obtain physical memory
+ * @ioc: per adapter object
+ * @mem: struct config_request
+ *
+ * A wrapper for obtaining dma-able memory for config page request.
+ *
+ * Returns 0 for success, non-zero for failure.
+ */
+static int
+_config_alloc_config_dma_memory(struct MPT2SAS_ADAPTER *ioc,
+    struct config_request *mem)
+{
+       int r = 0;
+
+       mem->config_page = pci_alloc_consistent(ioc->pdev, mem->config_page_sz,
+           &mem->config_page_dma);
+       if (!mem->config_page)
+               r = -ENOMEM;
+       return r;
+}
+
+/**
+ * _config_free_config_dma_memory - wrapper to free the memory
+ * @ioc: per adapter object
+ * @mem: struct config_request
+ *
+ * A wrapper to free dma-able memory when using _config_alloc_config_dma_memory.
+ *
+ * Returns 0 for success, non-zero for failure.
+ */
+static void
+_config_free_config_dma_memory(struct MPT2SAS_ADAPTER *ioc,
+    struct config_request *mem)
+{
+       pci_free_consistent(ioc->pdev, mem->config_page_sz, mem->config_page,
+           mem->config_page_dma);
+}
+
+/**
+ * mpt2sas_config_get_manufacturing_pg0 - obtain manufacturing page 0
+ * @ioc: 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
+mpt2sas_config_get_manufacturing_pg0(struct MPT2SAS_ADAPTER *ioc,
+    Mpi2ConfigReply_t *mpi_reply, Mpi2ManufacturingPage0_t *config_page)
+{
+       Mpi2ConfigRequest_t mpi_request;
+       int r;
+       struct config_request mem;
+
+       mutex_lock(&ioc->config_cmds.mutex);
+       memset(config_page, 0, sizeof(Mpi2ManufacturingPage0_t));
+       memset(&mpi_request, 0, sizeof(Mpi2ConfigRequest_t));
+       mpi_request.Function = MPI2_FUNCTION_CONFIG;
+       mpi_request.Action = MPI2_CONFIG_ACTION_PAGE_HEADER;
+       mpi_request.Header.PageType = MPI2_CONFIG_PAGETYPE_MANUFACTURING;
+       mpi_request.Header.PageNumber = 0;
+       mpi_request.Header.PageVersion = MPI2_MANUFACTURING0_PAGEVERSION;
+       mpt2sas_base_build_zero_len_sge(ioc, &mpi_request.PageBufferSGE);
+       r = _config_request(ioc, &mpi_request, mpi_reply,
+           MPT2_CONFIG_PAGE_DEFAULT_TIMEOUT);
+       if (r)
+               goto out;
+
+       mpi_request.Action = MPI2_CONFIG_ACTION_PAGE_READ_CURRENT;
+       mpi_request.Header.PageVersion = mpi_reply->Header.PageVersion;
+       mpi_request.Header.PageNumber = mpi_reply->Header.PageNumber;
+       mpi_request.Header.PageType = mpi_reply->Header.PageType;
+       mpi_request.Header.PageLength = mpi_reply->Header.PageLength;
+       mem.config_page_sz = le16_to_cpu(mpi_reply->Header.PageLength) * 4;
+       if (mem.config_page_sz > ioc->config_page_sz) {
+               r = _config_alloc_config_dma_memory(ioc, &mem);
+               if (r)
+                       goto out;
+       } else {
+               mem.config_page_dma = ioc->config_page_dma;
+               mem.config_page = ioc->config_page;
+       }
+       ioc->base_add_sg_single(&mpi_request.PageBufferSGE,
+           MPT2_CONFIG_COMMON_SGLFLAGS | mem.config_page_sz,
+           mem.config_page_dma);
+       r = _config_request(ioc, &mpi_request, mpi_reply,
+           MPT2_CONFIG_PAGE_DEFAULT_TIMEOUT);
+       if (!r)
+               memcpy(config_page, mem.config_page,
+                   min_t(u16, mem.config_page_sz,
+                   sizeof(Mpi2ManufacturingPage0_t)));
+
+       if (mem.config_page_sz > ioc->config_page_sz)
+               _config_free_config_dma_memory(ioc, &mem);
+
+ out:
+       mutex_unlock(&ioc->config_cmds.mutex);
+       return r;
+}
+
+/**
+ * mpt2sas_config_get_bios_pg2 - obtain bios page 2
+ * @ioc: 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
+mpt2sas_config_get_bios_pg2(struct MPT2SAS_ADAPTER *ioc,
+    Mpi2ConfigReply_t *mpi_reply, Mpi2BiosPage2_t *config_page)
+{
+       Mpi2ConfigRequest_t mpi_request;
+       int r;
+       struct config_request mem;
+
+       mutex_lock(&ioc->config_cmds.mutex);
+       memset(config_page, 0, sizeof(Mpi2BiosPage2_t));
+       memset(&mpi_request, 0, sizeof(Mpi2ConfigRequest_t));
+       mpi_request.Function = MPI2_FUNCTION_CONFIG;
+       mpi_request.Action = MPI2_CONFIG_ACTION_PAGE_HEADER;
+       mpi_request.Header.PageType = MPI2_CONFIG_PAGETYPE_BIOS;
+       mpi_request.Header.PageNumber = 2;
+       mpi_request.Header.PageVersion = MPI2_BIOSPAGE2_PAGEVERSION;
+       mpt2sas_base_build_zero_len_sge(ioc, &mpi_request.PageBufferSGE);
+       r = _config_request(ioc, &mpi_request, mpi_reply,
+           MPT2_CONFIG_PAGE_DEFAULT_TIMEOUT);
+       if (r)
+               goto out;
+
+       mpi_request.Action = MPI2_CONFIG_ACTION_PAGE_READ_CURRENT;
+       mpi_request.Header.PageVersion = mpi_reply->Header.PageVersion;
+       mpi_request.Header.PageNumber = mpi_reply->Header.PageNumber;
+       mpi_request.Header.PageType = mpi_reply->Header.PageType;
+       mpi_request.Header.PageLength = mpi_reply->Header.PageLength;
+       mem.config_page_sz = le16_to_cpu(mpi_reply->Header.PageLength) * 4;
+       if (mem.config_page_sz > ioc->config_page_sz) {
+               r = _config_alloc_config_dma_memory(ioc, &mem);
+               if (r)
+                       goto out;
+       } else {
+               mem.config_page_dma = ioc->config_page_dma;
+               mem.config_page = ioc->config_page;
+       }
+       ioc->base_add_sg_single(&mpi_request.PageBufferSGE,
+           MPT2_CONFIG_COMMON_SGLFLAGS | mem.config_page_sz,
+           mem.config_page_dma);
+       r = _config_request(ioc, &mpi_request, mpi_reply,
+           MPT2_CONFIG_PAGE_DEFAULT_TIMEOUT);
+       if (!r)
+               memcpy(config_page, mem.config_page,
+                   min_t(u16, mem.config_page_sz,
+                   sizeof(Mpi2BiosPage2_t)));
+
+       if (mem.config_page_sz > ioc->config_page_sz)
+               _config_free_config_dma_memory(ioc, &mem);
+
+ out:
+       mutex_unlock(&ioc->config_cmds.mutex);
+       return r;
+}
+
+/**
+ * mpt2sas_config_get_bios_pg3 - obtain bios page 3
+ * @ioc: 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
+mpt2sas_config_get_bios_pg3(struct MPT2SAS_ADAPTER *ioc, Mpi2ConfigReply_t
+    *mpi_reply, Mpi2BiosPage3_t *config_page)
+{
+       Mpi2ConfigRequest_t mpi_request;
+       int r;
+       struct config_request mem;
+
+       mutex_lock(&ioc->config_cmds.mutex);
+       memset(config_page, 0, sizeof(Mpi2BiosPage3_t));
+       memset(&mpi_request, 0, sizeof(Mpi2ConfigRequest_t));
+       mpi_request.Function = MPI2_FUNCTION_CONFIG;
+       mpi_request.Action = MPI2_CONFIG_ACTION_PAGE_HEADER;
+       mpi_request.Header.PageType = MPI2_CONFIG_PAGETYPE_BIOS;
+       mpi_request.Header.PageNumber = 3;
+       mpi_request.Header.PageVersion = MPI2_BIOSPAGE3_PAGEVERSION;
+       mpt2sas_base_build_zero_len_sge(ioc, &mpi_request.PageBufferSGE);
+       r = _config_request(ioc, &mpi_request, mpi_reply,
+           MPT2_CONFIG_PAGE_DEFAULT_TIMEOUT);
+       if (r)
+               goto out;
+
+       mpi_request.Action = MPI2_CONFIG_ACTION_PAGE_READ_CURRENT;
+       mpi_request.Header.PageVersion = mpi_reply->Header.PageVersion;
+       mpi_request.Header.PageNumber = mpi_reply->Header.PageNumber;
+       mpi_request.Header.PageType = mpi_reply->Header.PageType;
+       mpi_request.Header.PageLength = mpi_reply->Header.PageLength;
+       mem.config_page_sz = le16_to_cpu(mpi_reply->Header.PageLength) * 4;
+       if (mem.config_page_sz > ioc->config_page_sz) {
+               r = _config_alloc_config_dma_memory(ioc, &mem);
+               if (r)
+                       goto out;
+       } else {
+               mem.config_page_dma = ioc->config_page_dma;
+               mem.config_page = ioc->config_page;
+       }
+       ioc->base_add_sg_single(&mpi_request.PageBufferSGE,
+           MPT2_CONFIG_COMMON_SGLFLAGS | mem.config_page_sz,
+           mem.config_page_dma);
+       r = _config_request(ioc, &mpi_request, mpi_reply,
+           MPT2_CONFIG_PAGE_DEFAULT_TIMEOUT);
+       if (!r)
+               memcpy(config_page, mem.config_page,
+                   min_t(u16, mem.config_page_sz,
+                   sizeof(Mpi2BiosPage3_t)));
+
+       if (mem.config_page_sz > ioc->config_page_sz)
+               _config_free_config_dma_memory(ioc, &mem);
+
+ out:
+       mutex_unlock(&ioc->config_cmds.mutex);
+       return r;
+}
+
+/**
+ * mpt2sas_config_get_iounit_pg0 - obtain iounit page 0
+ * @ioc: 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
+mpt2sas_config_get_iounit_pg0(struct MPT2SAS_ADAPTER *ioc,
+    Mpi2ConfigReply_t *mpi_reply, Mpi2IOUnitPage0_t *config_page)
+{
+       Mpi2ConfigRequest_t mpi_request;
+       int r;
+       struct config_request mem;
+
+       mutex_lock(&ioc->config_cmds.mutex);
+       memset(config_page, 0, sizeof(Mpi2IOUnitPage0_t));
+       memset(&mpi_request, 0, sizeof(Mpi2ConfigRequest_t));
+       mpi_request.Function = MPI2_FUNCTION_CONFIG;
+       mpi_request.Action = MPI2_CONFIG_ACTION_PAGE_HEADER;
+       mpi_request.Header.PageType = MPI2_CONFIG_PAGETYPE_IO_UNIT;
+       mpi_request.Header.PageNumber = 0;
+       mpi_request.Header.PageVersion = MPI2_IOUNITPAGE0_PAGEVERSION;
+       mpt2sas_base_build_zero_len_sge(ioc, &mpi_request.PageBufferSGE);
+       r = _config_request(ioc, &mpi_request, mpi_reply,
+           MPT2_CONFIG_PAGE_DEFAULT_TIMEOUT);
+       if (r)
+               goto out;
+
+       mpi_request.Action = MPI2_CONFIG_ACTION_PAGE_READ_CURRENT;
+       mpi_request.Header.PageVersion = mpi_reply->Header.PageVersion;
+       mpi_request.Header.PageNumber = mpi_reply->Header.PageNumber;
+       mpi_request.Header.PageType = mpi_reply->Header.PageType;
+       mpi_request.Header.PageLength = mpi_reply->Header.PageLength;
+       mem.config_page_sz = le16_to_cpu(mpi_reply->Header.PageLength) * 4;
+       if (mem.config_page_sz > ioc->config_page_sz) {
+               r = _config_alloc_config_dma_memory(ioc, &mem);
+               if (r)
+                       goto out;
+       } else {
+               mem.config_page_dma = ioc->config_page_dma;
+               mem.config_page = ioc->config_page;
+       }
+       ioc->base_add_sg_single(&mpi_request.PageBufferSGE,
+           MPT2_CONFIG_COMMON_SGLFLAGS | mem.config_page_sz,
+           mem.config_page_dma);
+       r = _config_request(ioc, &mpi_request, mpi_reply,
+           MPT2_CONFIG_PAGE_DEFAULT_TIMEOUT);
+       if (!r)
+               memcpy(config_page, mem.config_page,
+                   min_t(u16, mem.config_page_sz,
+                   sizeof(Mpi2IOUnitPage0_t)));
+
+       if (mem.config_page_sz > ioc->config_page_sz)
+               _config_free_config_dma_memory(ioc, &mem);
+
+ out:
+       mutex_unlock(&ioc->config_cmds.mutex);
+       return r;
+}
+
+/**
+ * mpt2sas_config_get_iounit_pg1 - obtain iounit page 1
+ * @ioc: 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
+mpt2sas_config_get_iounit_pg1(struct MPT2SAS_ADAPTER *ioc,
+    Mpi2ConfigReply_t *mpi_reply, Mpi2IOUnitPage1_t *config_page)
+{
+       Mpi2ConfigRequest_t mpi_request;
+       int r;
+       struct config_request mem;
+
+       mutex_lock(&ioc->config_cmds.mutex);
+       memset(config_page, 0, sizeof(Mpi2IOUnitPage1_t));
+       memset(&mpi_request, 0, sizeof(Mpi2ConfigRequest_t));
+       mpi_request.Function = MPI2_FUNCTION_CONFIG;
+       mpi_request.Action = MPI2_CONFIG_ACTION_PAGE_HEADER;
+       mpi_request.Header.PageType = MPI2_CONFIG_PAGETYPE_IO_UNIT;
+       mpi_request.Header.PageNumber = 1;
+       mpi_request.Header.PageVersion = MPI2_IOUNITPAGE1_PAGEVERSION;
+       mpt2sas_base_build_zero_len_sge(ioc, &mpi_request.PageBufferSGE);
+       r = _config_request(ioc, &mpi_request, mpi_reply,
+           MPT2_CONFIG_PAGE_DEFAULT_TIMEOUT);
+       if (r)
+               goto out;
+
+       mpi_request.Action = MPI2_CONFIG_ACTION_PAGE_READ_CURRENT;
+       mpi_request.Header.PageVersion = mpi_reply->Header.PageVersion;
+       mpi_request.Header.PageNumber = mpi_reply->Header.PageNumber;
+       mpi_request.Header.PageType = mpi_reply->Header.PageType;
+       mpi_request.Header.PageLength = mpi_reply->Header.PageLength;
+       mem.config_page_sz = le16_to_cpu(mpi_reply->Header.PageLength) * 4;
+       if (mem.config_page_sz > ioc->config_page_sz) {
+               r = _config_alloc_config_dma_memory(ioc, &mem);
+               if (r)
+                       goto out;
+       } else {
+               mem.config_page_dma = ioc->config_page_dma;
+               mem.config_page = ioc->config_page;
+       }
+       ioc->base_add_sg_single(&mpi_request.PageBufferSGE,
+           MPT2_CONFIG_COMMON_SGLFLAGS | mem.config_page_sz,
+           mem.config_page_dma);
+       r = _config_request(ioc, &mpi_request, mpi_reply,
+           MPT2_CONFIG_PAGE_DEFAULT_TIMEOUT);
+       if (!r)
+               memcpy(config_page, mem.config_page,
+                   min_t(u16, mem.config_page_sz,
+                   sizeof(Mpi2IOUnitPage1_t)));
+
+       if (mem.config_page_sz > ioc->config_page_sz)
+               _config_free_config_dma_memory(ioc, &mem);
+
+ out:
+       mutex_unlock(&ioc->config_cmds.mutex);
+       return r;
+}
+
+/**
+ * mpt2sas_config_set_iounit_pg1 - set iounit page 1
+ * @ioc: 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
+mpt2sas_config_set_iounit_pg1(struct MPT2SAS_ADAPTER *ioc,
+    Mpi2ConfigReply_t *mpi_reply, Mpi2IOUnitPage1_t config_page)
+{
+       Mpi2ConfigRequest_t mpi_request;
+       int r;
+       struct config_request mem;
+
+       mutex_lock(&ioc->config_cmds.mutex);
+       memset(&mpi_request, 0, sizeof(Mpi2ConfigRequest_t));
+       mpi_request.Function = MPI2_FUNCTION_CONFIG;
+       mpi_request.Action = MPI2_CONFIG_ACTION_PAGE_HEADER;
+       mpi_request.Header.PageType = MPI2_CONFIG_PAGETYPE_IO_UNIT;
+       mpi_request.Header.PageNumber = 1;
+       mpi_request.Header.PageVersion = MPI2_IOUNITPAGE1_PAGEVERSION;
+       mpt2sas_base_build_zero_len_sge(ioc, &mpi_request.PageBufferSGE);
+       r = _config_request(ioc, &mpi_request, mpi_reply,
+           MPT2_CONFIG_PAGE_DEFAULT_TIMEOUT);
+       if (r)
+               goto out;
+
+       mpi_request.Action = MPI2_CONFIG_ACTION_PAGE_WRITE_CURRENT;
+       mpi_request.Header.PageVersion = mpi_reply->Header.PageVersion;
+       mpi_request.Header.PageNumber = mpi_reply->Header.PageNumber;
+       mpi_request.Header.PageType = mpi_reply->Header.PageType;
+       mpi_request.Header.PageLength = mpi_reply->Header.PageLength;
+       mem.config_page_sz = le16_to_cpu(mpi_reply->Header.PageLength) * 4;
+       if (mem.config_page_sz > ioc->config_page_sz) {
+               r = _config_alloc_config_dma_memory(ioc, &mem);
+               if (r)
+                       goto out;
+       } else {
+               mem.config_page_dma = ioc->config_page_dma;
+               mem.config_page = ioc->config_page;
+       }
+
+       memset(mem.config_page, 0, mem.config_page_sz);
+       memcpy(mem.config_page, &config_page,
+           sizeof(Mpi2IOUnitPage1_t));
+
+       ioc->base_add_sg_single(&mpi_request.PageBufferSGE,
+           MPT2_CONFIG_COMMON_WRITE_SGLFLAGS | mem.config_page_sz,
+           mem.config_page_dma);
+       r = _config_request(ioc, &mpi_request, mpi_reply,
+           MPT2_CONFIG_PAGE_DEFAULT_TIMEOUT);
+
+       if (mem.config_page_sz > ioc->config_page_sz)
+               _config_free_config_dma_memory(ioc, &mem);
+
+ out:
+       mutex_unlock(&ioc->config_cmds.mutex);
+       return r;
+}
+
+/**
+ * mpt2sas_config_get_ioc_pg8 - obtain ioc page 8
+ * @ioc: 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
+mpt2sas_config_get_ioc_pg8(struct MPT2SAS_ADAPTER *ioc,
+    Mpi2ConfigReply_t *mpi_reply, Mpi2IOCPage8_t *config_page)
+{
+       Mpi2ConfigRequest_t mpi_request;
+       int r;
+       struct config_request mem;
+
+       mutex_lock(&ioc->config_cmds.mutex);
+       memset(config_page, 0, sizeof(Mpi2IOCPage8_t));
+       memset(&mpi_request, 0, sizeof(Mpi2ConfigRequest_t));
+       mpi_request.Function = MPI2_FUNCTION_CONFIG;
+       mpi_request.Action = MPI2_CONFIG_ACTION_PAGE_HEADER;
+       mpi_request.Header.PageType = MPI2_CONFIG_PAGETYPE_IOC;
+       mpi_request.Header.PageNumber = 8;
+       mpi_request.Header.PageVersion = MPI2_IOCPAGE8_PAGEVERSION;
+       mpt2sas_base_build_zero_len_sge(ioc, &mpi_request.PageBufferSGE);
+       r = _config_request(ioc, &mpi_request, mpi_reply,
+           MPT2_CONFIG_PAGE_DEFAULT_TIMEOUT);
+       if (r)
+               goto out;
+
+       mpi_request.Action = MPI2_CONFIG_ACTION_PAGE_READ_CURRENT;
+       mpi_request.Header.PageVersion = mpi_reply->Header.PageVersion;
+       mpi_request.Header.PageNumber = mpi_reply->Header.PageNumber;
+       mpi_request.Header.PageType = mpi_reply->Header.PageType;
+       mpi_request.Header.PageLength = mpi_reply->Header.PageLength;
+       mem.config_page_sz = le16_to_cpu(mpi_reply->Header.PageLength) * 4;
+       if (mem.config_page_sz > ioc->config_page_sz) {
+               r = _config_alloc_config_dma_memory(ioc, &mem);
+               if (r)
+                       goto out;
+       } else {
+               mem.config_page_dma = ioc->config_page_dma;
+               mem.config_page = ioc->config_page;
+       }
+       ioc->base_add_sg_single(&mpi_request.PageBufferSGE,
+           MPT2_CONFIG_COMMON_SGLFLAGS | mem.config_page_sz,
+           mem.config_page_dma);
+       r = _config_request(ioc, &mpi_request, mpi_reply,
+           MPT2_CONFIG_PAGE_DEFAULT_TIMEOUT);
+       if (!r)
+               memcpy(config_page, mem.config_page,
+                   min_t(u16, mem.config_page_sz,
+                   sizeof(Mpi2IOCPage8_t)));
+
+       if (mem.config_page_sz > ioc->config_page_sz)
+               _config_free_config_dma_memory(ioc, &mem);
+
+ out:
+       mutex_unlock(&ioc->config_cmds.mutex);
+       return r;
+}
+
+/**
+ * mpt2sas_config_get_sas_device_pg0 - obtain sas device page 0
+ * @ioc: 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
+mpt2sas_config_get_sas_device_pg0(struct MPT2SAS_ADAPTER *ioc, Mpi2ConfigReply_t
+    *mpi_reply, Mpi2SasDevicePage0_t *config_page, u32 form, u32 handle)
+{
+       Mpi2ConfigRequest_t mpi_request;
+       int r;
+       struct config_request mem;
+
+       mutex_lock(&ioc->config_cmds.mutex);
+       memset(config_page, 0, sizeof(Mpi2SasDevicePage0_t));
+       memset(&mpi_request, 0, sizeof(Mpi2ConfigRequest_t));
+       mpi_request.Function = MPI2_FUNCTION_CONFIG;
+       mpi_request.Action = MPI2_CONFIG_ACTION_PAGE_HEADER;
+       mpi_request.Header.PageType = MPI2_CONFIG_PAGETYPE_EXTENDED;
+       mpi_request.ExtPageType = MPI2_CONFIG_EXTPAGETYPE_SAS_DEVICE;
+       mpi_request.Header.PageVersion = MPI2_SASDEVICE0_PAGEVERSION;
+       mpi_request.Header.PageNumber = 0;
+       mpt2sas_base_build_zero_len_sge(ioc, &mpi_request.PageBufferSGE);
+       r = _config_request(ioc, &mpi_request, mpi_reply,
+           MPT2_CONFIG_PAGE_DEFAULT_TIMEOUT);
+       if (r)
+               goto out;
+
+       mpi_request.PageAddress = cpu_to_le32(form | handle);
+       mpi_request.Action = MPI2_CONFIG_ACTION_PAGE_READ_CURRENT;
+       mpi_request.Header.PageVersion = mpi_reply->Header.PageVersion;
+       mpi_request.Header.PageNumber = mpi_reply->Header.PageNumber;
+       mpi_request.Header.PageType = mpi_reply->Header.PageType;
+       mpi_request.ExtPageLength = mpi_reply->ExtPageLength;
+       mpi_request.ExtPageType = mpi_reply->ExtPageType;
+       mem.config_page_sz = le16_to_cpu(mpi_reply->ExtPageLength) * 4;
+       if (mem.config_page_sz > ioc->config_page_sz) {
+               r = _config_alloc_config_dma_memory(ioc, &mem);
+               if (r)
+                       goto out;
+       } else {
+               mem.config_page_dma = ioc->config_page_dma;
+               mem.config_page = ioc->config_page;
+       }
+       ioc->base_add_sg_single(&mpi_request.PageBufferSGE,
+           MPT2_CONFIG_COMMON_SGLFLAGS | mem.config_page_sz,
+           mem.config_page_dma);
+       r = _config_request(ioc, &mpi_request, mpi_reply,
+           MPT2_CONFIG_PAGE_DEFAULT_TIMEOUT);
+       if (!r)
+               memcpy(config_page, mem.config_page,
+                   min_t(u16, mem.config_page_sz,
+                   sizeof(Mpi2SasDevicePage0_t)));
+
+       if (mem.config_page_sz > ioc->config_page_sz)
+               _config_free_config_dma_memory(ioc, &mem);
+
+ out:
+       mutex_unlock(&ioc->config_cmds.mutex);
+       return r;
+}
+
+/**
+ * mpt2sas_config_get_sas_device_pg1 - obtain sas device page 1
+ * @ioc: 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
+mpt2sas_config_get_sas_device_pg1(struct MPT2SAS_ADAPTER *ioc, Mpi2ConfigReply_t
+    *mpi_reply, Mpi2SasDevicePage1_t *config_page, u32 form, u32 handle)
+{
+       Mpi2ConfigRequest_t mpi_request;
+       int r;
+       struct config_request mem;
+
+       mutex_lock(&ioc->config_cmds.mutex);
+       memset(config_page, 0, sizeof(Mpi2SasDevicePage1_t));
+       memset(&mpi_request, 0, sizeof(Mpi2ConfigRequest_t));
+       mpi_request.Function = MPI2_FUNCTION_CONFIG;
+       mpi_request.Action = MPI2_CONFIG_ACTION_PAGE_HEADER;
+       mpi_request.Header.PageType = MPI2_CONFIG_PAGETYPE_EXTENDED;
+       mpi_request.ExtPageType = MPI2_CONFIG_EXTPAGETYPE_SAS_DEVICE;
+       mpi_request.Header.PageVersion = MPI2_SASDEVICE1_PAGEVERSION;
+       mpi_request.Header.PageNumber = 1;
+       mpt2sas_base_build_zero_len_sge(ioc, &mpi_request.PageBufferSGE);
+       r = _config_request(ioc, &mpi_request, mpi_reply,
+           MPT2_CONFIG_PAGE_DEFAULT_TIMEOUT);
+       if (r)
+               goto out;
+
+       mpi_request.PageAddress = cpu_to_le32(form | handle);
+       mpi_request.Action = MPI2_CONFIG_ACTION_PAGE_READ_CURRENT;
+       mpi_request.Header.PageVersion = mpi_reply->Header.PageVersion;
+       mpi_request.Header.PageNumber = mpi_reply->Header.PageNumber;
+       mpi_request.Header.PageType = mpi_reply->Header.PageType;
+       mpi_request.ExtPageLength = mpi_reply->ExtPageLength;
+       mpi_request.ExtPageType = mpi_reply->ExtPageType;
+       mem.config_page_sz = le16_to_cpu(mpi_reply->ExtPageLength) * 4;
+       if (mem.config_page_sz > ioc->config_page_sz) {
+               r = _config_alloc_config_dma_memory(ioc, &mem);
+               if (r)
+                       goto out;
+       } else {
+               mem.config_page_dma = ioc->config_page_dma;
+               mem.config_page = ioc->config_page;
+       }
+       ioc->base_add_sg_single(&mpi_request.PageBufferSGE,
+           MPT2_CONFIG_COMMON_SGLFLAGS | mem.config_page_sz,
+           mem.config_page_dma);
+       r = _config_request(ioc, &mpi_request, mpi_reply,
+           MPT2_CONFIG_PAGE_DEFAULT_TIMEOUT);
+       if (!r)
+               memcpy(config_page, mem.config_page,
+                   min_t(u16, mem.config_page_sz,
+                   sizeof(Mpi2SasDevicePage1_t)));
+
+       if (mem.config_page_sz > ioc->config_page_sz)
+               _config_free_config_dma_memory(ioc, &mem);
+
+ out:
+       mutex_unlock(&ioc->config_cmds.mutex);
+       return r;
+}
+
+/**
+ * mpt2sas_config_get_number_hba_phys - obtain number of phys on the host
+ * @ioc: per adapter object
+ * @num_phys: pointer returned with the number of phys
+ * Context: sleep.
+ *
+ * Returns 0 for success, non-zero for failure.
+ */
+int
+mpt2sas_config_get_number_hba_phys(struct MPT2SAS_ADAPTER *ioc, u8 *num_phys)
+{
+       Mpi2ConfigRequest_t mpi_request;
+       int r;
+       struct config_request mem;
+       u16 ioc_status;
+       Mpi2ConfigReply_t mpi_reply;
+       Mpi2SasIOUnitPage0_t config_page;
+
+       mutex_lock(&ioc->config_cmds.mutex);
+       memset(&mpi_request, 0, sizeof(Mpi2ConfigRequest_t));
+       mpi_request.Function = MPI2_FUNCTION_CONFIG;
+       mpi_request.Action = MPI2_CONFIG_ACTION_PAGE_HEADER;
+       mpi_request.Header.PageType = MPI2_CONFIG_PAGETYPE_EXTENDED;
+       mpi_request.ExtPageType = MPI2_CONFIG_EXTPAGETYPE_SAS_IO_UNIT;
+       mpi_request.Header.PageNumber = 0;
+       mpi_request.Header.PageVersion = MPI2_SASIOUNITPAGE0_PAGEVERSION;
+       mpt2sas_base_build_zero_len_sge(ioc, &mpi_request.PageBufferSGE);
+       r = _config_request(ioc, &mpi_request, &mpi_reply,
+           MPT2_CONFIG_PAGE_DEFAULT_TIMEOUT);
+       if (r)
+               goto out;
+
+       mpi_request.Action = MPI2_CONFIG_ACTION_PAGE_READ_CURRENT;
+       mpi_request.Header.PageVersion = mpi_reply.Header.PageVersion;
+       mpi_request.Header.PageNumber = mpi_reply.Header.PageNumber;
+       mpi_request.Header.PageType = mpi_reply.Header.PageType;
+       mpi_request.ExtPageLength = mpi_reply.ExtPageLength;
+       mpi_request.ExtPageType = mpi_reply.ExtPageType;
+       mem.config_page_sz = le16_to_cpu(mpi_reply.ExtPageLength) * 4;
+       if (mem.config_page_sz > ioc->config_page_sz) {
+               r = _config_alloc_config_dma_memory(ioc, &mem);
+               if (r)
+                       goto out;
+       } else {
+               mem.config_page_dma = ioc->config_page_dma;
+               mem.config_page = ioc->config_page;
+       }
+       ioc->base_add_sg_single(&mpi_request.PageBufferSGE,
+           MPT2_CONFIG_COMMON_SGLFLAGS | mem.config_page_sz,
+           mem.config_page_dma);
+       r = _config_request(ioc, &mpi_request, &mpi_reply,
+           MPT2_CONFIG_PAGE_DEFAULT_TIMEOUT);
+       if (!r) {
+               ioc_status = le16_to_cpu(mpi_reply.IOCStatus) &
+                   MPI2_IOCSTATUS_MASK;
+               if (ioc_status == MPI2_IOCSTATUS_SUCCESS) {
+                       memcpy(&config_page, mem.config_page,
+                           min_t(u16, mem.config_page_sz,
+                           sizeof(Mpi2SasIOUnitPage0_t)));
+                       *num_phys = config_page.NumPhys;
+               }
+       }
+
+       if (mem.config_page_sz > ioc->config_page_sz)
+               _config_free_config_dma_memory(ioc, &mem);
+
+ out:
+       mutex_unlock(&ioc->config_cmds.mutex);
+       return r;
+}
+
+/**
+ * mpt2sas_config_get_sas_iounit_pg0 - obtain sas iounit page 0
+ * @ioc: 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.
+ *
+ * Calling function should call config_get_number_hba_phys prior to
+ * this function, so enough memory is allocated for config_page.
+ *
+ * Returns 0 for success, non-zero for failure.
+ */
+int
+mpt2sas_config_get_sas_iounit_pg0(struct MPT2SAS_ADAPTER *ioc, Mpi2ConfigReply_t
+    *mpi_reply, Mpi2SasIOUnitPage0_t *config_page, u16 sz)
+{
+       Mpi2ConfigRequest_t mpi_request;
+       int r;
+       struct config_request mem;
+
+       mutex_lock(&ioc->config_cmds.mutex);
+       memset(config_page, 0, sz);
+       memset(&mpi_request, 0, sizeof(Mpi2ConfigRequest_t));
+       mpi_request.Function = MPI2_FUNCTION_CONFIG;
+       mpi_request.Action = MPI2_CONFIG_ACTION_PAGE_HEADER;
+       mpi_request.Header.PageType = MPI2_CONFIG_PAGETYPE_EXTENDED;
+       mpi_request.ExtPageType = MPI2_CONFIG_EXTPAGETYPE_SAS_IO_UNIT;
+       mpi_request.Header.PageNumber = 0;
+       mpi_request.Header.PageVersion = MPI2_SASIOUNITPAGE0_PAGEVERSION;
+       mpt2sas_base_build_zero_len_sge(ioc, &mpi_request.PageBufferSGE);
+       r = _config_request(ioc, &mpi_request, mpi_reply,
+           MPT2_CONFIG_PAGE_DEFAULT_TIMEOUT);
+       if (r)
+               goto out;
+
+       mpi_request.Action = MPI2_CONFIG_ACTION_PAGE_READ_CURRENT;
+       mpi_request.Header.PageVersion = mpi_reply->Header.PageVersion;
+       mpi_request.Header.PageNumber = mpi_reply->Header.PageNumber;
+       mpi_request.Header.PageType = mpi_reply->Header.PageType;
+       mpi_request.ExtPageLength = mpi_reply->ExtPageLength;
+       mpi_request.ExtPageType = mpi_reply->ExtPageType;
+       mem.config_page_sz = le16_to_cpu(mpi_reply->ExtPageLength) * 4;
+       if (mem.config_page_sz > ioc->config_page_sz) {
+               r = _config_alloc_config_dma_memory(ioc, &mem);
+               if (r)
+                       goto out;
+       } else {
+               mem.config_page_dma = ioc->config_page_dma;
+               mem.config_page = ioc->config_page;
+       }
+       ioc->base_add_sg_single(&mpi_request.PageBufferSGE,
+           MPT2_CONFIG_COMMON_SGLFLAGS | mem.config_page_sz,
+           mem.config_page_dma);
+       r = _config_request(ioc, &mpi_request, mpi_reply,
+           MPT2_CONFIG_PAGE_DEFAULT_TIMEOUT);
+       if (!r)
+               memcpy(config_page, mem.config_page,
+                   min_t(u16, sz, mem.config_page_sz));
+
+       if (mem.config_page_sz > ioc->config_page_sz)
+               _config_free_config_dma_memory(ioc, &mem);
+
+ out:
+       mutex_unlock(&ioc->config_cmds.mutex);
+       return r;
+}
+
+/**
+ * mpt2sas_config_get_sas_iounit_pg1 - obtain sas iounit page 0
+ * @ioc: 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.
+ *
+ * Calling function should call config_get_number_hba_phys prior to
+ * this function, so enough memory is allocated for config_page.
+ *
+ * Returns 0 for success, non-zero for failure.
+ */
+int
+mpt2sas_config_get_sas_iounit_pg1(struct MPT2SAS_ADAPTER *ioc, Mpi2ConfigReply_t
+    *mpi_reply, Mpi2SasIOUnitPage1_t *config_page, u16 sz)
+{
+       Mpi2ConfigRequest_t mpi_request;
+       int r;
+       struct config_request mem;
+
+       mutex_lock(&ioc->config_cmds.mutex);
+       memset(config_page, 0, sz);
+       memset(&mpi_request, 0, sizeof(Mpi2ConfigRequest_t));
+       mpi_request.Function = MPI2_FUNCTION_CONFIG;
+       mpi_request.Action = MPI2_CONFIG_ACTION_PAGE_HEADER;
+       mpi_request.Header.PageType = MPI2_CONFIG_PAGETYPE_EXTENDED;
+       mpi_request.ExtPageType = MPI2_CONFIG_EXTPAGETYPE_SAS_IO_UNIT;
+       mpi_request.Header.PageNumber = 1;
+       mpi_request.Header.PageVersion = MPI2_SASIOUNITPAGE0_PAGEVERSION;
+       mpt2sas_base_build_zero_len_sge(ioc, &mpi_request.PageBufferSGE);
+       r = _config_request(ioc, &mpi_request, mpi_reply,
+           MPT2_CONFIG_PAGE_DEFAULT_TIMEOUT);
+       if (r)
+               goto out;
+
+       mpi_request.Action = MPI2_CONFIG_ACTION_PAGE_READ_CURRENT;
+       mpi_request.Header.PageVersion = mpi_reply->Header.PageVersion;
+       mpi_request.Header.PageNumber = mpi_reply->Header.PageNumber;
+       mpi_request.Header.PageType = mpi_reply->Header.PageType;
+       mpi_request.ExtPageLength = mpi_reply->ExtPageLength;
+       mpi_request.ExtPageType = mpi_reply->ExtPageType;
+       mem.config_page_sz = le16_to_cpu(mpi_reply->ExtPageLength) * 4;
+       if (mem.config_page_sz > ioc->config_page_sz) {
+               r = _config_alloc_config_dma_memory(ioc, &mem);
+               if (r)
+                       goto out;
+       } else {
+               mem.config_page_dma = ioc->config_page_dma;
+               mem.config_page = ioc->config_page;
+       }
+       ioc->base_add_sg_single(&mpi_request.PageBufferSGE,
+           MPT2_CONFIG_COMMON_SGLFLAGS | mem.config_page_sz,
+           mem.config_page_dma);
+       r = _config_request(ioc, &mpi_request, mpi_reply,
+           MPT2_CONFIG_PAGE_DEFAULT_TIMEOUT);
+       if (!r)
+               memcpy(config_page, mem.config_page,
+                   min_t(u16, sz, mem.config_page_sz));
+
+       if (mem.config_page_sz > ioc->config_page_sz)
+               _config_free_config_dma_memory(ioc, &mem);
+
+ out:
+       mutex_unlock(&ioc->config_cmds.mutex);
+       return r;
+}
+
+/**
+ * mpt2sas_config_get_expander_pg0 - obtain expander page 0
+ * @ioc: 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: expander handle
+ * Context: sleep.
+ *
+ * Returns 0 for success, non-zero for failure.
+ */
+int
+mpt2sas_config_get_expander_pg0(struct MPT2SAS_ADAPTER *ioc, Mpi2ConfigReply_t
+    *mpi_reply, Mpi2ExpanderPage0_t *config_page, u32 form, u32 handle)
+{
+       Mpi2ConfigRequest_t mpi_request;
+       int r;
+       struct config_request mem;
+
+       mutex_lock(&ioc->config_cmds.mutex);
+       memset(config_page, 0, sizeof(Mpi2ExpanderPage0_t));
+       memset(&mpi_request, 0, sizeof(Mpi2ConfigRequest_t));
+       mpi_request.Function = MPI2_FUNCTION_CONFIG;
+       mpi_request.Action = MPI2_CONFIG_ACTION_PAGE_HEADER;
+       mpi_request.Header.PageType = MPI2_CONFIG_PAGETYPE_EXTENDED;
+       mpi_request.ExtPageType = MPI2_CONFIG_EXTPAGETYPE_SAS_EXPANDER;
+       mpi_request.Header.PageNumber = 0;
+       mpi_request.Header.PageVersion = MPI2_SASEXPANDER0_PAGEVERSION;
+       mpt2sas_base_build_zero_len_sge(ioc, &mpi_request.PageBufferSGE);
+       r = _config_request(ioc, &mpi_request, mpi_reply,
+           MPT2_CONFIG_PAGE_DEFAULT_TIMEOUT);
+       if (r)
+               goto out;
+
+       mpi_request.PageAddress = cpu_to_le32(form | handle);
+       mpi_request.Action = MPI2_CONFIG_ACTION_PAGE_READ_CURRENT;
+       mpi_request.Header.PageVersion = mpi_reply->Header.PageVersion;
+       mpi_request.Header.PageNumber = mpi_reply->Header.PageNumber;
+       mpi_request.Header.PageType = mpi_reply->Header.PageType;
+       mpi_request.ExtPageLength = mpi_reply->ExtPageLength;
+       mpi_request.ExtPageType = mpi_reply->ExtPageType;
+       mem.config_page_sz = le16_to_cpu(mpi_reply->ExtPageLength) * 4;
+       if (mem.config_page_sz > ioc->config_page_sz) {
+               r = _config_alloc_config_dma_memory(ioc, &mem);
+               if (r)
+                       goto out;
+       } else {
+               mem.config_page_dma = ioc->config_page_dma;
+               mem.config_page = ioc->config_page;
+       }
+       ioc->base_add_sg_single(&mpi_request.PageBufferSGE,
+           MPT2_CONFIG_COMMON_SGLFLAGS | mem.config_page_sz,
+           mem.config_page_dma);
+       r = _config_request(ioc, &mpi_request, mpi_reply,
+           MPT2_CONFIG_PAGE_DEFAULT_TIMEOUT);
+       if (!r)
+               memcpy(config_page, mem.config_page,
+                   min_t(u16, mem.config_page_sz,
+                   sizeof(Mpi2ExpanderPage0_t)));
+
+       if (mem.config_page_sz > ioc->config_page_sz)
+               _config_free_config_dma_memory(ioc, &mem);
+
+ out:
+       mutex_unlock(&ioc->config_cmds.mutex);
+       return r;
+}
+
+/**
+ * mpt2sas_config_get_expander_pg1 - obtain expander page 1
+ * @ioc: per adapter object
+ * @mpi_reply: reply mf payload returned from firmware
+ * @config_page: contents of the config page
+ * @phy_number: phy number
+ * @handle: expander handle
+ * Context: sleep.
+ *
+ * Returns 0 for success, non-zero for failure.
+ */
+int
+mpt2sas_config_get_expander_pg1(struct MPT2SAS_ADAPTER *ioc, Mpi2ConfigReply_t
+    *mpi_reply, Mpi2ExpanderPage1_t *config_page, u32 phy_number,
+    u16 handle)
+{
+       Mpi2ConfigRequest_t mpi_request;
+       int r;
+       struct config_request mem;
+
+       mutex_lock(&ioc->config_cmds.mutex);
+       memset(config_page, 0, sizeof(Mpi2ExpanderPage1_t));
+       memset(&mpi_request, 0, sizeof(Mpi2ConfigRequest_t));
+       mpi_request.Function = MPI2_FUNCTION_CONFIG;
+       mpi_request.Action = MPI2_CONFIG_ACTION_PAGE_HEADER;
+       mpi_request.Header.PageType = MPI2_CONFIG_PAGETYPE_EXTENDED;
+       mpi_request.ExtPageType = MPI2_CONFIG_EXTPAGETYPE_SAS_EXPANDER;
+       mpi_request.Header.PageNumber = 1;
+       mpi_request.Header.PageVersion = MPI2_SASEXPANDER1_PAGEVERSION;
+       mpt2sas_base_build_zero_len_sge(ioc, &mpi_request.PageBufferSGE);
+       r = _config_request(ioc, &mpi_request, mpi_reply,
+           MPT2_CONFIG_PAGE_DEFAULT_TIMEOUT);
+       if (r)
+               goto out;
+
+       mpi_request.PageAddress =
+           cpu_to_le32(MPI2_SAS_EXPAND_PGAD_FORM_HNDL_PHY_NUM |
+           (phy_number << MPI2_SAS_EXPAND_PGAD_PHYNUM_SHIFT) | handle);
+       mpi_request.Action = MPI2_CONFIG_ACTION_PAGE_READ_CURRENT;
+       mpi_request.Header.PageVersion = mpi_reply->Header.PageVersion;
+       mpi_request.Header.PageNumber = mpi_reply->Header.PageNumber;
+       mpi_request.Header.PageType = mpi_reply->Header.PageType;
+       mpi_request.ExtPageLength = mpi_reply->ExtPageLength;
+       mpi_request.ExtPageType = mpi_reply->ExtPageType;
+       mem.config_page_sz = le16_to_cpu(mpi_reply->ExtPageLength) * 4;
+       if (mem.config_page_sz > ioc->config_page_sz) {
+               r = _config_alloc_config_dma_memory(ioc, &mem);
+               if (r)
+                       goto out;
+       } else {
+               mem.config_page_dma = ioc->config_page_dma;
+               mem.config_page = ioc->config_page;
+       }
+       ioc->base_add_sg_single(&mpi_request.PageBufferSGE,
+           MPT2_CONFIG_COMMON_SGLFLAGS | mem.config_page_sz,
+           mem.config_page_dma);
+       r = _config_request(ioc, &mpi_request, mpi_reply,
+           MPT2_CONFIG_PAGE_DEFAULT_TIMEOUT);
+       if (!r)
+               memcpy(config_page, mem.config_page,
+                   min_t(u16, mem.config_page_sz,
+                   sizeof(Mpi2ExpanderPage1_t)));
+
+       if (mem.config_page_sz > ioc->config_page_sz)
+               _config_free_config_dma_memory(ioc, &mem);
+
+ out:
+       mutex_unlock(&ioc->config_cmds.mutex);
+       return r;
+}
+
+/**
+ * mpt2sas_config_get_enclosure_pg0 - obtain enclosure page 0
+ * @ioc: 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: expander handle
+ * Context: sleep.
+ *
+ * Returns 0 for success, non-zero for failure.
+ */
+int
+mpt2sas_config_get_enclosure_pg0(struct MPT2SAS_ADAPTER *ioc, Mpi2ConfigReply_t
+    *mpi_reply, Mpi2SasEnclosurePage0_t *config_page, u32 form, u32 handle)
+{
+       Mpi2ConfigRequest_t mpi_request;
+       int r;
+       struct config_request mem;
+
+       mutex_lock(&ioc->config_cmds.mutex);
+       memset(config_page, 0, sizeof(Mpi2SasEnclosurePage0_t));
+       memset(&mpi_request, 0, sizeof(Mpi2ConfigRequest_t));
+       mpi_request.Function = MPI2_FUNCTION_CONFIG;
+       mpi_request.Action = MPI2_CONFIG_ACTION_PAGE_HEADER;
+       mpi_request.Header.PageType = MPI2_CONFIG_PAGETYPE_EXTENDED;
+       mpi_request.ExtPageType = MPI2_CONFIG_EXTPAGETYPE_ENCLOSURE;
+       mpi_request.Header.PageNumber = 0;
+       mpi_request.Header.PageVersion = MPI2_SASENCLOSURE0_PAGEVERSION;
+       mpt2sas_base_build_zero_len_sge(ioc, &mpi_request.PageBufferSGE);
+       r = _config_request(ioc, &mpi_request, mpi_reply,
+           MPT2_CONFIG_PAGE_DEFAULT_TIMEOUT);
+       if (r)
+               goto out;
+
+       mpi_request.PageAddress = cpu_to_le32(form | handle);
+       mpi_request.Action = MPI2_CONFIG_ACTION_PAGE_READ_CURRENT;
+       mpi_request.Header.PageVersion = mpi_reply->Header.PageVersion;
+       mpi_request.Header.PageNumber = mpi_reply->Header.PageNumber;
+       mpi_request.Header.PageType = mpi_reply->Header.PageType;
+       mpi_request.ExtPageLength = mpi_reply->ExtPageLength;
+       mpi_request.ExtPageType = mpi_reply->ExtPageType;
+       mem.config_page_sz = le16_to_cpu(mpi_reply->ExtPageLength) * 4;
+       if (mem.config_page_sz > ioc->config_page_sz) {
+               r = _config_alloc_config_dma_memory(ioc, &mem);
+               if (r)
+                       goto out;
+       } else {
+               mem.config_page_dma = ioc->config_page_dma;
+               mem.config_page = ioc->config_page;
+       }
+       ioc->base_add_sg_single(&mpi_request.PageBufferSGE,
+           MPT2_CONFIG_COMMON_SGLFLAGS | mem.config_page_sz,
+           mem.config_page_dma);
+       r = _config_request(ioc, &mpi_request, mpi_reply,
+           MPT2_CONFIG_PAGE_DEFAULT_TIMEOUT);
+       if (!r)
+               memcpy(config_page, mem.config_page,
+                   min_t(u16, mem.config_page_sz,
+                   sizeof(Mpi2SasEnclosurePage0_t)));
+
+       if (mem.config_page_sz > ioc->config_page_sz)
+               _config_free_config_dma_memory(ioc, &mem);
+
+ out:
+       mutex_unlock(&ioc->config_cmds.mutex);
+       return r;
+}
+
+/**
+ * mpt2sas_config_get_phy_pg0 - obtain phy page 0
+ * @ioc: per adapter object
+ * @mpi_reply: reply mf payload returned from firmware
+ * @config_page: contents of the config page
+ * @phy_number: phy number
+ * Context: sleep.
+ *
+ * Returns 0 for success, non-zero for failure.
+ */
+int
+mpt2sas_config_get_phy_pg0(struct MPT2SAS_ADAPTER *ioc, Mpi2ConfigReply_t
+    *mpi_reply, Mpi2SasPhyPage0_t *config_page, u32 phy_number)
+{
+       Mpi2ConfigRequest_t mpi_request;
+       int r;
+       struct config_request mem;
+
+       mutex_lock(&ioc->config_cmds.mutex);
+       memset(config_page, 0, sizeof(Mpi2SasPhyPage0_t));
+       memset(&mpi_request, 0, sizeof(Mpi2ConfigRequest_t));
+       mpi_request.Function = MPI2_FUNCTION_CONFIG;
+       mpi_request.Action = MPI2_CONFIG_ACTION_PAGE_HEADER;
+       mpi_request.Header.PageType = MPI2_CONFIG_PAGETYPE_EXTENDED;
+       mpi_request.ExtPageType = MPI2_CONFIG_EXTPAGETYPE_SAS_PHY;
+       mpi_request.Header.PageNumber = 0;
+       mpi_request.Header.PageVersion = MPI2_SASPHY0_PAGEVERSION;
+       mpt2sas_base_build_zero_len_sge(ioc, &mpi_request.PageBufferSGE);
+       r = _config_request(ioc, &mpi_request, mpi_reply,
+           MPT2_CONFIG_PAGE_DEFAULT_TIMEOUT);
+       if (r)
+               goto out;
+
+       mpi_request.PageAddress =
+           cpu_to_le32(MPI2_SAS_PHY_PGAD_FORM_PHY_NUMBER | phy_number);
+       mpi_request.Action = MPI2_CONFIG_ACTION_PAGE_READ_CURRENT;
+       mpi_request.Header.PageVersion = mpi_reply->Header.PageVersion;
+       mpi_request.Header.PageNumber = mpi_reply->Header.PageNumber;
+       mpi_request.Header.PageType = mpi_reply->Header.PageType;
+       mpi_request.ExtPageLength = mpi_reply->ExtPageLength;
+       mpi_request.ExtPageType = mpi_reply->ExtPageType;
+       mem.config_page_sz = le16_to_cpu(mpi_reply->ExtPageLength) * 4;
+       if (mem.config_page_sz > ioc->config_page_sz) {
+               r = _config_alloc_config_dma_memory(ioc, &mem);
+               if (r)
+                       goto out;
+       } else {
+               mem.config_page_dma = ioc->config_page_dma;
+               mem.config_page = ioc->config_page;
+       }
+       ioc->base_add_sg_single(&mpi_request.PageBufferSGE,
+           MPT2_CONFIG_COMMON_SGLFLAGS | mem.config_page_sz,
+           mem.config_page_dma);
+       r = _config_request(ioc, &mpi_request, mpi_reply,
+           MPT2_CONFIG_PAGE_DEFAULT_TIMEOUT);
+       if (!r)
+               memcpy(config_page, mem.config_page,
+                   min_t(u16, mem.config_page_sz,
+                   sizeof(Mpi2SasPhyPage0_t)));
+
+       if (mem.config_page_sz > ioc->config_page_sz)
+               _config_free_config_dma_memory(ioc, &mem);
+
+ out:
+       mutex_unlock(&ioc->config_cmds.mutex);
+       return r;
+}
+
+/**
+ * mpt2sas_config_get_phy_pg1 - obtain phy page 1
+ * @ioc: per adapter object
+ * @mpi_reply: reply mf payload returned from firmware
+ * @config_page: contents of the config page
+ * @phy_number: phy number
+ * Context: sleep.
+ *
+ * Returns 0 for success, non-zero for failure.
+ */
+int
+mpt2sas_config_get_phy_pg1(struct MPT2SAS_ADAPTER *ioc, Mpi2ConfigReply_t
+    *mpi_reply, Mpi2SasPhyPage1_t *config_page, u32 phy_number)
+{
+       Mpi2ConfigRequest_t mpi_request;
+       int r;
+       struct config_request mem;
+
+       mutex_lock(&ioc->config_cmds.mutex);
+       memset(config_page, 0, sizeof(Mpi2SasPhyPage1_t));
+       memset(&mpi_request, 0, sizeof(Mpi2ConfigRequest_t));
+       mpi_request.Function = MPI2_FUNCTION_CONFIG;
+       mpi_request.Action = MPI2_CONFIG_ACTION_PAGE_HEADER;
+       mpi_request.Header.PageType = MPI2_CONFIG_PAGETYPE_EXTENDED;
+       mpi_request.ExtPageType = MPI2_CONFIG_EXTPAGETYPE_SAS_PHY;
+       mpi_request.Header.PageNumber = 1;
+       mpi_request.Header.PageVersion = MPI2_SASPHY1_PAGEVERSION;
+       mpt2sas_base_build_zero_len_sge(ioc, &mpi_request.PageBufferSGE);
+       r = _config_request(ioc, &mpi_request, mpi_reply,
+           MPT2_CONFIG_PAGE_DEFAULT_TIMEOUT);
+       if (r)
+               goto out;
+
+       mpi_request.PageAddress =
+           cpu_to_le32(MPI2_SAS_PHY_PGAD_FORM_PHY_NUMBER | phy_number);
+       mpi_request.Action = MPI2_CONFIG_ACTION_PAGE_READ_CURRENT;
+       mpi_request.Header.PageVersion = mpi_reply->Header.PageVersion;
+       mpi_request.Header.PageNumber = mpi_reply->Header.PageNumber;
+       mpi_request.Header.PageType = mpi_reply->Header.PageType;
+       mpi_request.ExtPageLength = mpi_reply->ExtPageLength;
+       mpi_request.ExtPageType = mpi_reply->ExtPageType;
+       mem.config_page_sz = le16_to_cpu(mpi_reply->ExtPageLength) * 4;
+       if (mem.config_page_sz > ioc->config_page_sz) {
+               r = _config_alloc_config_dma_memory(ioc, &mem);
+               if (r)
+                       goto out;
+       } else {
+               mem.config_page_dma = ioc->config_page_dma;
+               mem.config_page = ioc->config_page;
+       }
+       ioc->base_add_sg_single(&mpi_request.PageBufferSGE,
+           MPT2_CONFIG_COMMON_SGLFLAGS | mem.config_page_sz,
+           mem.config_page_dma);
+       r = _config_request(ioc, &mpi_request, mpi_reply,
+           MPT2_CONFIG_PAGE_DEFAULT_TIMEOUT);
+       if (!r)
+               memcpy(config_page, mem.config_page,
+                   min_t(u16, mem.config_page_sz,
+                   sizeof(Mpi2SasPhyPage1_t)));
+
+       if (mem.config_page_sz > ioc->config_page_sz)
+               _config_free_config_dma_memory(ioc, &mem);
+
+ out:
+       mutex_unlock(&ioc->config_cmds.mutex);
+       return r;
+}
+
+/**
+ * mpt2sas_config_get_raid_volume_pg1 - obtain raid volume page 1
+ * @ioc: 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: volume handle
+ * Context: sleep.
+ *
+ * Returns 0 for success, non-zero for failure.
+ */
+int
+mpt2sas_config_get_raid_volume_pg1(struct MPT2SAS_ADAPTER *ioc,
+    Mpi2ConfigReply_t *mpi_reply, Mpi2RaidVolPage1_t *config_page, u32 form,
+    u32 handle)
+{
+       Mpi2ConfigRequest_t mpi_request;
+       int r;
+       struct config_request mem;
+
+       mutex_lock(&ioc->config_cmds.mutex);
+       memset(config_page, 0, sizeof(Mpi2RaidVolPage1_t));
+       memset(&mpi_request, 0, sizeof(Mpi2ConfigRequest_t));
+       mpi_request.Function = MPI2_FUNCTION_CONFIG;
+       mpi_request.Action = MPI2_CONFIG_ACTION_PAGE_HEADER;
+       mpi_request.Header.PageType = MPI2_CONFIG_PAGETYPE_RAID_VOLUME;
+       mpi_request.Header.PageNumber = 1;
+       mpi_request.Header.PageVersion = MPI2_RAIDVOLPAGE1_PAGEVERSION;
+       mpt2sas_base_build_zero_len_sge(ioc, &mpi_request.PageBufferSGE);
+       r = _config_request(ioc, &mpi_request, mpi_reply,
+           MPT2_CONFIG_PAGE_DEFAULT_TIMEOUT);
+       if (r)
+               goto out;
+
+       mpi_request.PageAddress = cpu_to_le32(form | handle);
+       mpi_request.Action = MPI2_CONFIG_ACTION_PAGE_READ_CURRENT;
+       mpi_request.Header.PageVersion = mpi_reply->Header.PageVersion;
+       mpi_request.Header.PageNumber = mpi_reply->Header.PageNumber;
+       mpi_request.Header.PageType = mpi_reply->Header.PageType;
+       mpi_request.Header.PageLength = mpi_reply->Header.PageLength;
+       mem.config_page_sz = le16_to_cpu(mpi_reply->Header.PageLength) * 4;
+       if (mem.config_page_sz > ioc->config_page_sz) {
+               r = _config_alloc_config_dma_memory(ioc, &mem);
+               if (r)
+                       goto out;
+       } else {
+               mem.config_page_dma = ioc->config_page_dma;
+               mem.config_page = ioc->config_page;
+       }
+       ioc->base_add_sg_single(&mpi_request.PageBufferSGE,
+           MPT2_CONFIG_COMMON_SGLFLAGS | mem.config_page_sz,
+           mem.config_page_dma);
+       r = _config_request(ioc, &mpi_request, mpi_reply,
+           MPT2_CONFIG_PAGE_DEFAULT_TIMEOUT);
+       if (!r)
+               memcpy(config_page, mem.config_page,
+                   min_t(u16, mem.config_page_sz,
+                   sizeof(Mpi2RaidVolPage1_t)));
+
+       if (mem.config_page_sz > ioc->config_page_sz)
+               _config_free_config_dma_memory(ioc, &mem);
+
+ out:
+       mutex_unlock(&ioc->config_cmds.mutex);
+       return r;
+}
+
+/**
+ * mpt2sas_config_get_number_pds - obtain number of phys disk assigned to volume
+ * @ioc: per adapter object
+ * @handle: volume handle
+ * @num_pds: returns pds count
+ * Context: sleep.
+ *
+ * Returns 0 for success, non-zero for failure.
+ */
+int
+mpt2sas_config_get_number_pds(struct MPT2SAS_ADAPTER *ioc, u16 handle,
+    u8 *num_pds)
+{
+       Mpi2ConfigRequest_t mpi_request;
+       Mpi2RaidVolPage0_t *config_page;
+       Mpi2ConfigReply_t mpi_reply;
+       int r;
+       struct config_request mem;
+       u16 ioc_status;
+
+       mutex_lock(&ioc->config_cmds.mutex);
+       memset(&mpi_request, 0, sizeof(Mpi2ConfigRequest_t));
+       *num_pds = 0;
+       mpi_request.Function = MPI2_FUNCTION_CONFIG;
+       mpi_request.Action = MPI2_CONFIG_ACTION_PAGE_HEADER;
+       mpi_request.Header.PageType = MPI2_CONFIG_PAGETYPE_RAID_VOLUME;
+       mpi_request.Header.PageNumber = 0;
+       mpi_request.Header.PageVersion = MPI2_RAIDVOLPAGE0_PAGEVERSION;
+       mpt2sas_base_build_zero_len_sge(ioc, &mpi_request.PageBufferSGE);
+       r = _config_request(ioc, &mpi_request, &mpi_reply,
+           MPT2_CONFIG_PAGE_DEFAULT_TIMEOUT);
+       if (r)
+               goto out;
+
+       mpi_request.PageAddress =
+           cpu_to_le32(MPI2_RAID_VOLUME_PGAD_FORM_HANDLE | handle);
+       mpi_request.Action = MPI2_CONFIG_ACTION_PAGE_READ_CURRENT;
+       mpi_request.Header.PageVersion = mpi_reply.Header.PageVersion;
+       mpi_request.Header.PageNumber = mpi_reply.Header.PageNumber;
+       mpi_request.Header.PageType = mpi_reply.Header.PageType;
+       mpi_request.Header.PageLength = mpi_reply.Header.PageLength;
+       mem.config_page_sz = le16_to_cpu(mpi_reply.Header.PageLength) * 4;
+       if (mem.config_page_sz > ioc->config_page_sz) {
+               r = _config_alloc_config_dma_memory(ioc, &mem);
+               if (r)
+                       goto out;
+       } else {
+               mem.config_page_dma = ioc->config_page_dma;
+               mem.config_page = ioc->config_page;
+       }
+       ioc->base_add_sg_single(&mpi_request.PageBufferSGE,
+           MPT2_CONFIG_COMMON_SGLFLAGS | mem.config_page_sz,
+           mem.config_page_dma);
+       r = _config_request(ioc, &mpi_request, &mpi_reply,
+           MPT2_CONFIG_PAGE_DEFAULT_TIMEOUT);
+       if (!r) {
+               ioc_status = le16_to_cpu(mpi_reply.IOCStatus) &
+                   MPI2_IOCSTATUS_MASK;
+               if (ioc_status == MPI2_IOCSTATUS_SUCCESS) {
+                       config_page = mem.config_page;
+                       *num_pds = config_page->NumPhysDisks;
+               }
+       }
+
+       if (mem.config_page_sz > ioc->config_page_sz)
+               _config_free_config_dma_memory(ioc, &mem);
+
+ out:
+       mutex_unlock(&ioc->config_cmds.mutex);
+       return r;
+}
+
+/**
+ * mpt2sas_config_get_raid_volume_pg0 - obtain raid volume page 0
+ * @ioc: 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: volume handle
+ * @sz: size of buffer passed in config_page
+ * Context: sleep.
+ *
+ * Returns 0 for success, non-zero for failure.
+ */
+int
+mpt2sas_config_get_raid_volume_pg0(struct MPT2SAS_ADAPTER *ioc,
+    Mpi2ConfigReply_t *mpi_reply, Mpi2RaidVolPage0_t *config_page, u32 form,
+    u32 handle, u16 sz)
+{
+       Mpi2ConfigRequest_t mpi_request;
+       int r;
+       struct config_request mem;
+
+       mutex_lock(&ioc->config_cmds.mutex);
+       memset(&mpi_request, 0, sizeof(Mpi2ConfigRequest_t));
+       memset(config_page, 0, sz);
+       mpi_request.Function = MPI2_FUNCTION_CONFIG;
+       mpi_request.Action = MPI2_CONFIG_ACTION_PAGE_HEADER;
+       mpi_request.Header.PageType = MPI2_CONFIG_PAGETYPE_RAID_VOLUME;
+       mpi_request.Header.PageNumber = 0;
+       mpi_request.Header.PageVersion = MPI2_RAIDVOLPAGE0_PAGEVERSION;
+       mpt2sas_base_build_zero_len_sge(ioc, &mpi_request.PageBufferSGE);
+       r = _config_request(ioc, &mpi_request, mpi_reply,
+           MPT2_CONFIG_PAGE_DEFAULT_TIMEOUT);
+       if (r)
+               goto out;
+
+       mpi_request.PageAddress = cpu_to_le32(form | handle);
+       mpi_request.Action = MPI2_CONFIG_ACTION_PAGE_READ_CURRENT;
+       mpi_request.Header.PageVersion = mpi_reply->Header.PageVersion;
+       mpi_request.Header.PageNumber = mpi_reply->Header.PageNumber;
+       mpi_request.Header.PageType = mpi_reply->Header.PageType;
+       mpi_request.Header.PageLength = mpi_reply->Header.PageLength;
+       mem.config_page_sz = le16_to_cpu(mpi_reply->Header.PageLength) * 4;
+       if (mem.config_page_sz > ioc->config_page_sz) {
+               r = _config_alloc_config_dma_memory(ioc, &mem);
+               if (r)
+                       goto out;
+       } else {
+               mem.config_page_dma = ioc->config_page_dma;
+               mem.config_page = ioc->config_page;
+       }
+       ioc->base_add_sg_single(&mpi_request.PageBufferSGE,
+           MPT2_CONFIG_COMMON_SGLFLAGS | mem.config_page_sz,
+           mem.config_page_dma);
+       r = _config_request(ioc, &mpi_request, mpi_reply,
+           MPT2_CONFIG_PAGE_DEFAULT_TIMEOUT);
+       if (!r)
+               memcpy(config_page, mem.config_page,
+                   min_t(u16, sz, mem.config_page_sz));
+
+       if (mem.config_page_sz > ioc->config_page_sz)
+               _config_free_config_dma_memory(ioc, &mem);
+
+ out:
+       mutex_unlock(&ioc->config_cmds.mutex);
+       return r;
+}
+
+/**
+ * mpt2sas_config_get_phys_disk_pg0 - obtain phys disk page 0
+ * @ioc: per adapter object
+ * @mpi_reply: reply mf payload returned from firmware
+ * @config_page: contents of the config page
+ * @form: GET_NEXT_PHYSDISKNUM, PHYSDISKNUM, DEVHANDLE
+ * @form_specific: specific to the form
+ * Context: sleep.
+ *
+ * Returns 0 for success, non-zero for failure.
+ */
+int
+mpt2sas_config_get_phys_disk_pg0(struct MPT2SAS_ADAPTER *ioc, Mpi2ConfigReply_t
+    *mpi_reply, Mpi2RaidPhysDiskPage0_t *config_page, u32 form,
+    u32 form_specific)
+{
+       Mpi2ConfigRequest_t mpi_request;
+       int r;
+       struct config_request mem;
+
+       mutex_lock(&ioc->config_cmds.mutex);
+       memset(&mpi_request, 0, sizeof(Mpi2ConfigRequest_t));
+       memset(config_page, 0, sizeof(Mpi2RaidPhysDiskPage0_t));
+       mpi_request.Function = MPI2_FUNCTION_CONFIG;
+       mpi_request.Action = MPI2_CONFIG_ACTION_PAGE_HEADER;
+       mpi_request.Header.PageType = MPI2_CONFIG_PAGETYPE_RAID_PHYSDISK;
+       mpi_request.Header.PageNumber = 0;
+       mpi_request.Header.PageVersion = MPI2_RAIDPHYSDISKPAGE0_PAGEVERSION;
+       mpt2sas_base_build_zero_len_sge(ioc, &mpi_request.PageBufferSGE);
+       r = _config_request(ioc, &mpi_request, mpi_reply,
+           MPT2_CONFIG_PAGE_DEFAULT_TIMEOUT);
+       if (r)
+               goto out;
+
+       mpi_request.PageAddress = cpu_to_le32(form | form_specific);
+       mpi_request.Action = MPI2_CONFIG_ACTION_PAGE_READ_CURRENT;
+       mpi_request.Header.PageVersion = mpi_reply->Header.PageVersion;
+       mpi_request.Header.PageNumber = mpi_reply->Header.PageNumber;
+       mpi_request.Header.PageType = mpi_reply->Header.PageType;
+       mpi_request.Header.PageLength = mpi_reply->Header.PageLength;
+       mem.config_page_sz = le16_to_cpu(mpi_reply->Header.PageLength) * 4;
+       if (mem.config_page_sz > ioc->config_page_sz) {
+               r = _config_alloc_config_dma_memory(ioc, &mem);
+               if (r)
+                       goto out;
+       } else {
+               mem.config_page_dma = ioc->config_page_dma;
+               mem.config_page = ioc->config_page;
+       }
+       ioc->base_add_sg_single(&mpi_request.PageBufferSGE,
+           MPT2_CONFIG_COMMON_SGLFLAGS | mem.config_page_sz,
+           mem.config_page_dma);
+       r = _config_request(ioc, &mpi_request, mpi_reply,
+           MPT2_CONFIG_PAGE_DEFAULT_TIMEOUT);
+       if (!r)
+               memcpy(config_page, mem.config_page,
+                   min_t(u16, mem.config_page_sz,
+                   sizeof(Mpi2RaidPhysDiskPage0_t)));
+
+       if (mem.config_page_sz > ioc->config_page_sz)
+               _config_free_config_dma_memory(ioc, &mem);
+
+ out:
+       mutex_unlock(&ioc->config_cmds.mutex);
+       return r;
+}
+
+/**
+ * mpt2sas_config_get_volume_handle - returns volume handle for give hidden raid components
+ * @ioc: per adapter object
+ * @pd_handle: phys disk handle
+ * @volume_handle: volume handle
+ * Context: sleep.
+ *
+ * Returns 0 for success, non-zero for failure.
+ */
+int
+mpt2sas_config_get_volume_handle(struct MPT2SAS_ADAPTER *ioc, u16 pd_handle,
+    u16 *volume_handle)
+{
+       Mpi2RaidConfigurationPage0_t *config_page;
+       Mpi2ConfigRequest_t mpi_request;
+       Mpi2ConfigReply_t mpi_reply;
+       int r, i;
+       struct config_request mem;
+       u16 ioc_status;
+
+       mutex_lock(&ioc->config_cmds.mutex);
+       *volume_handle = 0;
+       memset(&mpi_request, 0, sizeof(Mpi2ConfigRequest_t));
+       mpi_request.Function = MPI2_FUNCTION_CONFIG;
+       mpi_request.Action = MPI2_CONFIG_ACTION_PAGE_HEADER;
+       mpi_request.Header.PageType = MPI2_CONFIG_PAGETYPE_EXTENDED;
+       mpi_request.ExtPageType = MPI2_CONFIG_EXTPAGETYPE_RAID_CONFIG;
+       mpi_request.Header.PageVersion = MPI2_RAIDCONFIG0_PAGEVERSION;
+       mpi_request.Header.PageNumber = 0;
+       mpt2sas_base_build_zero_len_sge(ioc, &mpi_request.PageBufferSGE);
+       r = _config_request(ioc, &mpi_request, &mpi_reply,
+           MPT2_CONFIG_PAGE_DEFAULT_TIMEOUT);
+       if (r)
+               goto out;
+
+       mpi_request.PageAddress =
+           cpu_to_le32(MPI2_RAID_PGAD_FORM_ACTIVE_CONFIG);
+       mpi_request.Action = MPI2_CONFIG_ACTION_PAGE_READ_CURRENT;
+       mpi_request.Header.PageVersion = mpi_reply.Header.PageVersion;
+       mpi_request.Header.PageNumber = mpi_reply.Header.PageNumber;
+       mpi_request.Header.PageType = mpi_reply.Header.PageType;
+       mpi_request.ExtPageLength = mpi_reply.ExtPageLength;
+       mpi_request.ExtPageType = mpi_reply.ExtPageType;
+       mem.config_page_sz = le16_to_cpu(mpi_reply.ExtPageLength) * 4;
+       if (mem.config_page_sz > ioc->config_page_sz) {
+               r = _config_alloc_config_dma_memory(ioc, &mem);
+               if (r)
+                       goto out;
+       } else {
+               mem.config_page_dma = ioc->config_page_dma;
+               mem.config_page = ioc->config_page;
+       }
+       ioc->base_add_sg_single(&mpi_request.PageBufferSGE,
+           MPT2_CONFIG_COMMON_SGLFLAGS | mem.config_page_sz,
+           mem.config_page_dma);
+       r = _config_request(ioc, &mpi_request, &mpi_reply,
+           MPT2_CONFIG_PAGE_DEFAULT_TIMEOUT);
+       if (r)
+               goto out;
+
+       r = -1;
+       ioc_status = le16_to_cpu(mpi_reply.IOCStatus) & MPI2_IOCSTATUS_MASK;
+       if (ioc_status != MPI2_IOCSTATUS_SUCCESS)
+               goto done;
+       config_page = mem.config_page;
+       for (i = 0; i < config_page->NumElements; i++) {
+               if ((config_page->ConfigElement[i].ElementFlags &
+                   MPI2_RAIDCONFIG0_EFLAGS_MASK_ELEMENT_TYPE) !=
+                   MPI2_RAIDCONFIG0_EFLAGS_VOL_PHYS_DISK_ELEMENT)
+                       continue;
+               if (config_page->ConfigElement[i].PhysDiskDevHandle ==
+                   pd_handle) {
+                       *volume_handle = le16_to_cpu(config_page->
+                           ConfigElement[i].VolDevHandle);
+                       r = 0;
+                       goto done;
+               }
+       }
+
+ done:
+       if (mem.config_page_sz > ioc->config_page_sz)
+               _config_free_config_dma_memory(ioc, &mem);
+
+ out:
+       mutex_unlock(&ioc->config_cmds.mutex);
+       return r;
+}
+
+/**
+ * mpt2sas_config_get_volume_wwid - returns wwid given the volume handle
+ * @ioc: per adapter object
+ * @volume_handle: volume handle
+ * @wwid: volume wwid
+ * Context: sleep.
+ *
+ * Returns 0 for success, non-zero for failure.
+ */
+int
+mpt2sas_config_get_volume_wwid(struct MPT2SAS_ADAPTER *ioc, u16 volume_handle,
+    u64 *wwid)
+{
+       Mpi2ConfigReply_t mpi_reply;
+       Mpi2RaidVolPage1_t raid_vol_pg1;
+
+       *wwid = 0;
+       if (!(mpt2sas_config_get_raid_volume_pg1(ioc, &mpi_reply,
+           &raid_vol_pg1, MPI2_RAID_VOLUME_PGAD_FORM_HANDLE,
+           volume_handle))) {
+               *wwid = le64_to_cpu(raid_vol_pg1.WWID);
+               return 0;
+       } else
+               return -1;
+}
diff --git a/drivers/scsi/mpt2sas/mpt2sas_ctl.c b/drivers/scsi/mpt2sas/mpt2sas_ctl.c
new file mode 100644 (file)
index 0000000..4fbe3f8
--- /dev/null
@@ -0,0 +1,2516 @@
+/*
+ * Management Module Support for MPT (Message Passing Technology) based
+ * controllers
+ *
+ * This code is based on drivers/scsi/mpt2sas/mpt2_ctl.c
+ * Copyright (C) 2007-2008  LSI Corporation
+ *  (mailto:DL-MPTFusionLinux@lsi.com)
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * NO WARRANTY
+ * THE PROGRAM IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OR
+ * CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED INCLUDING, WITHOUT
+ * LIMITATION, ANY WARRANTIES OR CONDITIONS OF TITLE, NON-INFRINGEMENT,
+ * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. Each Recipient is
+ * solely responsible for determining the appropriateness of using and
+ * distributing the Program and assumes all risks associated with its
+ * exercise of rights under this Agreement, including but not limited to
+ * the risks and costs of program errors, damage to or loss of data,
+ * programs or equipment, and unavailability or interruption of operations.
+
+ * DISCLAIMER OF LIABILITY
+ * NEITHER RECIPIENT NOR ANY CONTRIBUTORS SHALL HAVE ANY LIABILITY FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING WITHOUT LIMITATION LOST PROFITS), 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 OR DISTRIBUTION OF THE PROGRAM OR THE EXERCISE OF ANY RIGHTS GRANTED
+ * HEREUNDER, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGES
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301,
+ * USA.
+ */
+
+#include <linux/version.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/errno.h>
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <linux/types.h>
+#include <linux/pci.h>
+#include <linux/delay.h>
+#include <linux/smp_lock.h>
+#include <linux/compat.h>
+#include <linux/poll.h>
+
+#include <linux/io.h>
+#include <linux/uaccess.h>
+
+#include "mpt2sas_base.h"
+#include "mpt2sas_ctl.h"
+
+static struct fasync_struct *async_queue;
+static DECLARE_WAIT_QUEUE_HEAD(ctl_poll_wait);
+
+/**
+ * enum block_state - blocking state
+ * @NON_BLOCKING: non blocking
+ * @BLOCKING: blocking
+ *
+ * These states are for ioctls that need to wait for a response
+ * from firmware, so they probably require sleep.
+ */
+enum block_state {
+       NON_BLOCKING,
+       BLOCKING,
+};
+
+#ifdef CONFIG_SCSI_MPT2SAS_LOGGING
+/**
+ * _ctl_display_some_debug - debug routine
+ * @ioc: per adapter object
+ * @smid: system request message index
+ * @calling_function_name: string pass from calling function
+ * @mpi_reply: reply message frame
+ * Context: none.
+ *
+ * Function for displaying debug info helpfull when debugging issues
+ * in this module.
+ */
+static void
+_ctl_display_some_debug(struct MPT2SAS_ADAPTER *ioc, u16 smid,
+    char *calling_function_name, MPI2DefaultReply_t *mpi_reply)
+{
+       Mpi2ConfigRequest_t *mpi_request;
+       char *desc = NULL;
+
+       if (!(ioc->logging_level & MPT_DEBUG_IOCTL))
+               return;
+
+       mpi_request = mpt2sas_base_get_msg_frame(ioc, smid);
+       switch (mpi_request->Function) {
+       case MPI2_FUNCTION_SCSI_IO_REQUEST:
+       {
+               Mpi2SCSIIORequest_t *scsi_request =
+                   (Mpi2SCSIIORequest_t *)mpi_request;
+
+               snprintf(ioc->tmp_string, MPT_STRING_LENGTH,
+                   "scsi_io, cmd(0x%02x), cdb_len(%d)",
+                   scsi_request->CDB.CDB32[0],
+                   le16_to_cpu(scsi_request->IoFlags) & 0xF);
+               desc = ioc->tmp_string;
+               break;
+       }
+       case MPI2_FUNCTION_SCSI_TASK_MGMT:
+               desc = "task_mgmt";
+               break;
+       case MPI2_FUNCTION_IOC_INIT:
+               desc = "ioc_init";
+               break;
+       case MPI2_FUNCTION_IOC_FACTS:
+               desc = "ioc_facts";
+               break;
+       case MPI2_FUNCTION_CONFIG:
+       {
+               Mpi2ConfigRequest_t *config_request =
+                   (Mpi2ConfigRequest_t *)mpi_request;
+
+               snprintf(ioc->tmp_string, MPT_STRING_LENGTH,
+                   "config, type(0x%02x), ext_type(0x%02x), number(%d)",
+                   (config_request->Header.PageType &
+                    MPI2_CONFIG_PAGETYPE_MASK), config_request->ExtPageType,
+                   config_request->Header.PageNumber);
+               desc = ioc->tmp_string;
+               break;
+       }
+       case MPI2_FUNCTION_PORT_FACTS:
+               desc = "port_facts";
+               break;
+       case MPI2_FUNCTION_PORT_ENABLE:
+               desc = "port_enable";
+               break;
+       case MPI2_FUNCTION_EVENT_NOTIFICATION:
+               desc = "event_notification";
+               break;
+       case MPI2_FUNCTION_FW_DOWNLOAD:
+               desc = "fw_download";
+               break;
+       case MPI2_FUNCTION_FW_UPLOAD:
+               desc = "fw_upload";
+               break;
+       case MPI2_FUNCTION_RAID_ACTION:
+               desc = "raid_action";
+               break;
+       case MPI2_FUNCTION_RAID_SCSI_IO_PASSTHROUGH:
+       {
+               Mpi2SCSIIORequest_t *scsi_request =
+                   (Mpi2SCSIIORequest_t *)mpi_request;
+
+               snprintf(ioc->tmp_string, MPT_STRING_LENGTH,
+                   "raid_pass, cmd(0x%02x), cdb_len(%d)",
+                   scsi_request->CDB.CDB32[0],
+                   le16_to_cpu(scsi_request->IoFlags) & 0xF);
+               desc = ioc->tmp_string;
+               break;
+       }
+       case MPI2_FUNCTION_SAS_IO_UNIT_CONTROL:
+               desc = "sas_iounit_cntl";
+               break;
+       case MPI2_FUNCTION_SATA_PASSTHROUGH:
+               desc = "sata_pass";
+               break;
+       case MPI2_FUNCTION_DIAG_BUFFER_POST:
+               desc = "diag_buffer_post";
+               break;
+       case MPI2_FUNCTION_DIAG_RELEASE:
+               desc = "diag_release";
+               break;
+       case MPI2_FUNCTION_SMP_PASSTHROUGH:
+               desc = "smp_passthrough";
+               break;
+       }
+
+       if (!desc)
+               return;
+
+       printk(MPT2SAS_DEBUG_FMT "%s: %s, smid(%d)\n",
+           ioc->name, calling_function_name, desc, smid);
+
+       if (!mpi_reply)
+               return;
+
+       if (mpi_reply->IOCStatus || mpi_reply->IOCLogInfo)
+               printk(MPT2SAS_DEBUG_FMT
+                   "\tiocstatus(0x%04x), loginfo(0x%08x)\n",
+                   ioc->name, le16_to_cpu(mpi_reply->IOCStatus),
+                   le32_to_cpu(mpi_reply->IOCLogInfo));
+
+       if (mpi_request->Function == MPI2_FUNCTION_SCSI_IO_REQUEST ||
+           mpi_request->Function ==
+           MPI2_FUNCTION_RAID_SCSI_IO_PASSTHROUGH) {
+               Mpi2SCSIIOReply_t *scsi_reply =
+                   (Mpi2SCSIIOReply_t *)mpi_reply;
+               if (scsi_reply->SCSIState || scsi_reply->SCSIStatus)
+                       printk(MPT2SAS_DEBUG_FMT
+                           "\tscsi_state(0x%02x), scsi_status"
+                           "(0x%02x)\n", ioc->name,
+                           scsi_reply->SCSIState,
+                           scsi_reply->SCSIStatus);
+       }
+}
+#endif
+
+/**
+ * mpt2sas_ctl_done - ctl module completion routine
+ * @ioc: per adapter object
+ * @smid: system request message index
+ * @VF_ID: virtual function id
+ * @reply: reply message frame(lower 32bit addr)
+ * Context: none.
+ *
+ * The callback handler when using ioc->ctl_cb_idx.
+ *
+ * Return nothing.
+ */
+void
+mpt2sas_ctl_done(struct MPT2SAS_ADAPTER *ioc, u16 smid, u8 VF_ID, u32 reply)
+{
+       MPI2DefaultReply_t *mpi_reply;
+
+       if (ioc->ctl_cmds.status == MPT2_CMD_NOT_USED)
+               return;
+       if (ioc->ctl_cmds.smid != smid)
+               return;
+       ioc->ctl_cmds.status |= MPT2_CMD_COMPLETE;
+       mpi_reply = mpt2sas_base_get_reply_virt_addr(ioc, reply);
+       if (mpi_reply) {
+               memcpy(ioc->ctl_cmds.reply, mpi_reply, mpi_reply->MsgLength*4);
+               ioc->ctl_cmds.status |= MPT2_CMD_REPLY_VALID;
+       }
+#ifdef CONFIG_SCSI_MPT2SAS_LOGGING
+       _ctl_display_some_debug(ioc, smid, "ctl_done", mpi_reply);
+#endif
+       ioc->ctl_cmds.status &= ~MPT2_CMD_PENDING;
+       complete(&ioc->ctl_cmds.done);
+}
+
+/**
+ * _ctl_check_event_type - determines when an event needs logging
+ * @ioc: per adapter object
+ * @event: firmware event
+ *
+ * The bitmask in ioc->event_type[] indicates which events should be
+ * be saved in the driver event_log.  This bitmask is set by application.
+ *
+ * Returns 1 when event should be captured, or zero means no match.
+ */
+static int
+_ctl_check_event_type(struct MPT2SAS_ADAPTER *ioc, u16 event)
+{
+       u16 i;
+       u32 desired_event;
+
+       if (event >= 128 || !event || !ioc->event_log)
+               return 0;
+
+       desired_event = (1 << (event % 32));
+       if (!desired_event)
+               desired_event = 1;
+       i = event / 32;
+       return desired_event & ioc->event_type[i];
+}
+
+/**
+ * mpt2sas_ctl_add_to_event_log - add event
+ * @ioc: per adapter object
+ * @mpi_reply: reply message frame
+ *
+ * Return nothing.
+ */
+void
+mpt2sas_ctl_add_to_event_log(struct MPT2SAS_ADAPTER *ioc,
+    Mpi2EventNotificationReply_t *mpi_reply)
+{
+       struct MPT2_IOCTL_EVENTS *event_log;
+       u16 event;
+       int i;
+       u32 sz, event_data_sz;
+       u8 send_aen = 0;
+
+       if (!ioc->event_log)
+               return;
+
+       event = le16_to_cpu(mpi_reply->Event);
+
+       if (_ctl_check_event_type(ioc, event)) {
+
+               /* insert entry into circular event_log */
+               i = ioc->event_context % MPT2SAS_CTL_EVENT_LOG_SIZE;
+               event_log = ioc->event_log;
+               event_log[i].event = event;
+               event_log[i].context = ioc->event_context++;
+
+               event_data_sz = le16_to_cpu(mpi_reply->EventDataLength)*4;
+               sz = min_t(u32, event_data_sz, MPT2_EVENT_DATA_SIZE);
+               memset(event_log[i].data, 0, MPT2_EVENT_DATA_SIZE);
+               memcpy(event_log[i].data, mpi_reply->EventData, sz);
+               send_aen = 1;
+       }
+
+       /* This aen_event_read_flag flag is set until the
+        * application has read the event log.
+        * For MPI2_EVENT_LOG_ENTRY_ADDED, we always notify.
+        */
+       if (event == MPI2_EVENT_LOG_ENTRY_ADDED ||
+           (send_aen && !ioc->aen_event_read_flag)) {
+               ioc->aen_event_read_flag = 1;
+               wake_up_interruptible(&ctl_poll_wait);
+               if (async_queue)
+                       kill_fasync(&async_queue, SIGIO, POLL_IN);
+       }
+}
+
+/**
+ * mpt2sas_ctl_event_callback - firmware event handler (called at ISR time)
+ * @ioc: per adapter object
+ * @VF_ID: virtual function id
+ * @reply: reply message frame(lower 32bit addr)
+ * Context: interrupt.
+ *
+ * This function merely adds a new work task into ioc->firmware_event_thread.
+ * The tasks are worked from _firmware_event_work in user context.
+ *
+ * Return nothing.
+ */
+void
+mpt2sas_ctl_event_callback(struct MPT2SAS_ADAPTER *ioc, u8 VF_ID, u32 reply)
+{
+       Mpi2EventNotificationReply_t *mpi_reply;
+
+       mpi_reply = mpt2sas_base_get_reply_virt_addr(ioc, reply);
+       mpt2sas_ctl_add_to_event_log(ioc, mpi_reply);
+}
+
+/**
+ * _ctl_verify_adapter - validates ioc_number passed from application
+ * @ioc: per adapter object
+ * @iocpp: The ioc pointer is returned in this.
+ *
+ * Return (-1) means error, else ioc_number.
+ */
+static int
+_ctl_verify_adapter(int ioc_number, struct MPT2SAS_ADAPTER **iocpp)
+{
+       struct MPT2SAS_ADAPTER *ioc;
+
+       list_for_each_entry(ioc, &ioc_list, list) {
+               if (ioc->id != ioc_number)
+                       continue;
+               *iocpp = ioc;
+               return ioc_number;
+       }
+       *iocpp = NULL;
+       return -1;
+}
+
+/**
+ * mpt2sas_ctl_reset_handler - reset callback handler (for ctl)
+ * @ioc: per adapter object
+ * @reset_phase: phase
+ *
+ * The handler for doing any required cleanup or initialization.
+ *
+ * The reset phase can be MPT2_IOC_PRE_RESET, MPT2_IOC_AFTER_RESET,
+ * MPT2_IOC_DONE_RESET
+ */
+void
+mpt2sas_ctl_reset_handler(struct MPT2SAS_ADAPTER *ioc, int reset_phase)
+{
+       switch (reset_phase) {
+       case MPT2_IOC_PRE_RESET:
+               dtmprintk(ioc, printk(MPT2SAS_DEBUG_FMT "%s: "
+                   "MPT2_IOC_PRE_RESET\n", ioc->name, __func__));
+               break;
+       case MPT2_IOC_AFTER_RESET:
+               dtmprintk(ioc, printk(MPT2SAS_DEBUG_FMT "%s: "
+                   "MPT2_IOC_AFTER_RESET\n", ioc->name, __func__));
+               if (ioc->ctl_cmds.status & MPT2_CMD_PENDING) {
+                       ioc->ctl_cmds.status |= MPT2_CMD_RESET;
+                       mpt2sas_base_free_smid(ioc, ioc->ctl_cmds.smid);
+                       complete(&ioc->ctl_cmds.done);
+               }
+               break;
+       case MPT2_IOC_DONE_RESET:
+               dtmprintk(ioc, printk(MPT2SAS_DEBUG_FMT "%s: "
+                   "MPT2_IOC_DONE_RESET\n", ioc->name, __func__));
+               break;
+       }
+}
+
+/**
+ * _ctl_fasync -
+ * @fd -
+ * @filep -
+ * @mode -
+ *
+ * Called when application request fasyn callback handler.
+ */
+static int
+_ctl_fasync(int fd, struct file *filep, int mode)
+{
+       return fasync_helper(fd, filep, mode, &async_queue);
+}
+
+/**
+ * _ctl_release -
+ * @inode -
+ * @filep -
+ *
+ * Called when application releases the fasyn callback handler.
+ */
+static int
+_ctl_release(struct inode *inode, struct file *filep)
+{
+       return fasync_helper(-1, filep, 0, &async_queue);
+}
+
+/**
+ * _ctl_poll -
+ * @file -
+ * @wait -
+ *
+ */
+static unsigned int
+_ctl_poll(struct file *filep, poll_table *wait)
+{
+       struct MPT2SAS_ADAPTER *ioc;
+
+       poll_wait(filep, &ctl_poll_wait, wait);
+
+       list_for_each_entry(ioc, &ioc_list, list) {
+               if (ioc->aen_event_read_flag)
+                       return POLLIN | POLLRDNORM;
+       }
+       return 0;
+}
+
+/**
+ * _ctl_do_task_abort - assign an active smid to the abort_task
+ * @ioc: per adapter object
+ * @karg - (struct mpt2_ioctl_command)
+ * @tm_request - pointer to mf from user space
+ *
+ * Returns 0 when an smid if found, else fail.
+ * during failure, the reply frame is filled.
+ */
+static int
+_ctl_do_task_abort(struct MPT2SAS_ADAPTER *ioc, struct mpt2_ioctl_command *karg,
+    Mpi2SCSITaskManagementRequest_t *tm_request)
+{
+       u8 found = 0;
+       u16 i;
+       u16 handle;
+       struct scsi_cmnd *scmd;
+       struct MPT2SAS_DEVICE *priv_data;
+       unsigned long flags;
+       Mpi2SCSITaskManagementReply_t *tm_reply;
+       u32 sz;
+       u32 lun;
+
+       lun = scsilun_to_int((struct scsi_lun *)tm_request->LUN);
+
+       handle = le16_to_cpu(tm_request->DevHandle);
+       spin_lock_irqsave(&ioc->scsi_lookup_lock, flags);
+       for (i = ioc->request_depth; i && !found; i--) {
+               scmd = ioc->scsi_lookup[i - 1].scmd;
+               if (scmd == NULL || scmd->device == NULL ||
+                   scmd->device->hostdata == NULL)
+                       continue;
+               if (lun != scmd->device->lun)
+                       continue;
+               priv_data = scmd->device->hostdata;
+               if (priv_data->sas_target == NULL)
+                       continue;
+               if (priv_data->sas_target->handle != handle)
+                       continue;
+               tm_request->TaskMID = cpu_to_le16(ioc->scsi_lookup[i - 1].smid);
+               found = 1;
+       }
+       spin_unlock_irqrestore(&ioc->scsi_lookup_lock, flags);
+
+       if (!found) {
+               dctlprintk(ioc, printk(MPT2SAS_DEBUG_FMT "ABORT_TASK: "
+                   "DevHandle(0x%04x), lun(%d), no active mid!!\n", ioc->name,
+                   tm_request->DevHandle, lun));
+               tm_reply = ioc->ctl_cmds.reply;
+               tm_reply->DevHandle = tm_request->DevHandle;
+               tm_reply->Function = MPI2_FUNCTION_SCSI_TASK_MGMT;
+               tm_reply->TaskType = MPI2_SCSITASKMGMT_TASKTYPE_ABORT_TASK;
+               tm_reply->MsgLength = sizeof(Mpi2SCSITaskManagementReply_t)/4;
+               tm_reply->VP_ID = tm_request->VP_ID;
+               tm_reply->VF_ID = tm_request->VF_ID;
+               sz = min_t(u32, karg->max_reply_bytes, ioc->reply_sz);
+               if (copy_to_user(karg->reply_frame_buf_ptr, ioc->ctl_cmds.reply,
+                   sz))
+                       printk(KERN_ERR "failure at %s:%d/%s()!\n", __FILE__,
+                           __LINE__, __func__);
+               return 1;
+       }
+
+       dctlprintk(ioc, printk(MPT2SAS_DEBUG_FMT "ABORT_TASK: "
+           "DevHandle(0x%04x), lun(%d), smid(%d)\n", ioc->name,
+           tm_request->DevHandle, lun, tm_request->TaskMID));
+       return 0;
+}
+
+/**
+ * _ctl_do_mpt_command - main handler for MPT2COMMAND opcode
+ * @ioc: per adapter object
+ * @karg - (struct mpt2_ioctl_command)
+ * @mf - pointer to mf in user space
+ * @state - NON_BLOCKING or BLOCKING
+ */
+static long
+_ctl_do_mpt_command(struct MPT2SAS_ADAPTER *ioc,
+    struct mpt2_ioctl_command karg, void __user *mf, enum block_state state)
+{
+       MPI2RequestHeader_t *mpi_request;
+       MPI2DefaultReply_t *mpi_reply;
+       u32 ioc_state;
+       u16 ioc_status;
+       u16 smid;
+       unsigned long timeout, timeleft;
+       u8 issue_reset;
+       u32 sz;
+       void *psge;
+       void *priv_sense = NULL;
+       void *data_out = NULL;
+       dma_addr_t data_out_dma;
+       size_t data_out_sz = 0;
+       void *data_in = NULL;
+       dma_addr_t data_in_dma;
+       size_t data_in_sz = 0;
+       u32 sgl_flags;
+       long ret;
+       u16 wait_state_count;
+
+       issue_reset = 0;
+
+       if (state == NON_BLOCKING && !mutex_trylock(&ioc->ctl_cmds.mutex))
+               return -EAGAIN;
+       else if (mutex_lock_interruptible(&ioc->ctl_cmds.mutex))
+               return -ERESTARTSYS;
+
+       if (ioc->ctl_cmds.status != MPT2_CMD_NOT_USED) {
+               printk(MPT2SAS_ERR_FMT "%s: ctl_cmd in use\n",
+                   ioc->name, __func__);
+               ret = -EAGAIN;
+               goto out;
+       }
+
+       wait_state_count = 0;
+       ioc_state = mpt2sas_base_get_iocstate(ioc, 1);
+       while (ioc_state != MPI2_IOC_STATE_OPERATIONAL) {
+               if (wait_state_count++ == 10) {
+                       printk(MPT2SAS_ERR_FMT
+                           "%s: failed due to ioc not operational\n",
+                           ioc->name, __func__);
+                       ret = -EFAULT;
+                       goto out;
+               }
+               ssleep(1);
+               ioc_state = mpt2sas_base_get_iocstate(ioc, 1);
+               printk(MPT2SAS_INFO_FMT "%s: waiting for "
+                   "operational state(count=%d)\n", ioc->name,
+                   __func__, wait_state_count);
+       }
+       if (wait_state_count)
+               printk(MPT2SAS_INFO_FMT "%s: ioc is operational\n",
+                   ioc->name, __func__);
+
+       smid = mpt2sas_base_get_smid(ioc, ioc->ctl_cb_idx);
+       if (!smid) {
+               printk(MPT2SAS_ERR_FMT "%s: failed obtaining a smid\n",
+                   ioc->name, __func__);
+               ret = -EAGAIN;
+               goto out;
+       }
+
+       ret = 0;
+       ioc->ctl_cmds.status = MPT2_CMD_PENDING;
+       memset(ioc->ctl_cmds.reply, 0, ioc->reply_sz);
+       mpi_request = mpt2sas_base_get_msg_frame(ioc, smid);
+       ioc->ctl_cmds.smid = smid;
+       data_out_sz = karg.data_out_size;
+       data_in_sz = karg.data_in_size;
+
+       /* copy in request message frame from user */
+       if (copy_from_user(mpi_request, mf, karg.data_sge_offset*4)) {
+               printk(KERN_ERR "failure at %s:%d/%s()!\n", __FILE__, __LINE__,
+                   __func__);
+               ret = -EFAULT;
+               mpt2sas_base_free_smid(ioc, smid);
+               goto out;
+       }
+
+       if (mpi_request->Function == MPI2_FUNCTION_SCSI_IO_REQUEST ||
+           mpi_request->Function == MPI2_FUNCTION_RAID_SCSI_IO_PASSTHROUGH) {
+               if (!mpi_request->FunctionDependent1 ||
+                   mpi_request->FunctionDependent1 >
+                   cpu_to_le16(ioc->facts.MaxDevHandle)) {
+                       ret = -EINVAL;
+                       mpt2sas_base_free_smid(ioc, smid);
+                       goto out;
+               }
+       }
+
+       /* obtain dma-able memory for data transfer */
+       if (data_out_sz) /* WRITE */ {
+               data_out = pci_alloc_consistent(ioc->pdev, data_out_sz,
+                   &data_out_dma);
+               if (!data_out) {
+                       printk(KERN_ERR "failure at %s:%d/%s()!\n", __FILE__,
+                           __LINE__, __func__);
+                       ret = -ENOMEM;
+                       mpt2sas_base_free_smid(ioc, smid);
+                       goto out;
+               }
+               if (copy_from_user(data_out, karg.data_out_buf_ptr,
+                       data_out_sz)) {
+                       printk(KERN_ERR "failure at %s:%d/%s()!\n", __FILE__,
+                           __LINE__, __func__);
+                       ret =  -EFAULT;
+                       mpt2sas_base_free_smid(ioc, smid);
+                       goto out;
+               }
+       }
+
+       if (data_in_sz) /* READ */ {
+               data_in = pci_alloc_consistent(ioc->pdev, data_in_sz,
+                   &data_in_dma);
+               if (!data_in) {
+                       printk(KERN_ERR "failure at %s:%d/%s()!\n", __FILE__,
+                           __LINE__, __func__);
+                       ret = -ENOMEM;
+                       mpt2sas_base_free_smid(ioc, smid);
+                       goto out;
+               }
+       }
+
+       /* add scatter gather elements */
+       psge = (void *)mpi_request + (karg.data_sge_offset*4);
+
+       if (!data_out_sz && !data_in_sz) {
+               mpt2sas_base_build_zero_len_sge(ioc, psge);
+       } else if (data_out_sz && data_in_sz) {
+               /* WRITE sgel first */
+               sgl_flags = (MPI2_SGE_FLAGS_SIMPLE_ELEMENT |
+                   MPI2_SGE_FLAGS_END_OF_BUFFER | MPI2_SGE_FLAGS_HOST_TO_IOC);
+               sgl_flags = sgl_flags << MPI2_SGE_FLAGS_SHIFT;
+               ioc->base_add_sg_single(psge, sgl_flags |
+                   data_out_sz, data_out_dma);
+
+               /* incr sgel */
+               psge += ioc->sge_size;
+
+               /* READ sgel last */
+               sgl_flags = (MPI2_SGE_FLAGS_SIMPLE_ELEMENT |
+                   MPI2_SGE_FLAGS_LAST_ELEMENT | MPI2_SGE_FLAGS_END_OF_BUFFER |
+                   MPI2_SGE_FLAGS_END_OF_LIST);
+               sgl_flags = sgl_flags << MPI2_SGE_FLAGS_SHIFT;
+               ioc->base_add_sg_single(psge, sgl_flags |
+                   data_in_sz, data_in_dma);
+       } else if (data_out_sz) /* WRITE */ {
+               sgl_flags = (MPI2_SGE_FLAGS_SIMPLE_ELEMENT |
+                   MPI2_SGE_FLAGS_LAST_ELEMENT | MPI2_SGE_FLAGS_END_OF_BUFFER |
+                   MPI2_SGE_FLAGS_END_OF_LIST | MPI2_SGE_FLAGS_HOST_TO_IOC);
+               sgl_flags = sgl_flags << MPI2_SGE_FLAGS_SHIFT;
+               ioc->base_add_sg_single(psge, sgl_flags |
+                   data_out_sz, data_out_dma);
+       } else if (data_in_sz) /* READ */ {
+               sgl_flags = (MPI2_SGE_FLAGS_SIMPLE_ELEMENT |
+                   MPI2_SGE_FLAGS_LAST_ELEMENT | MPI2_SGE_FLAGS_END_OF_BUFFER |
+                   MPI2_SGE_FLAGS_END_OF_LIST);
+               sgl_flags = sgl_flags << MPI2_SGE_FLAGS_SHIFT;
+               ioc->base_add_sg_single(psge, sgl_flags |
+                   data_in_sz, data_in_dma);
+       }
+
+       /* send command to firmware */
+#ifdef CONFIG_SCSI_MPT2SAS_LOGGING
+       _ctl_display_some_debug(ioc, smid, "ctl_request", NULL);
+#endif
+
+       switch (mpi_request->Function) {
+       case MPI2_FUNCTION_SCSI_IO_REQUEST:
+       case MPI2_FUNCTION_RAID_SCSI_IO_PASSTHROUGH:
+       {
+               Mpi2SCSIIORequest_t *scsiio_request =
+                   (Mpi2SCSIIORequest_t *)mpi_request;
+               scsiio_request->SenseBufferLowAddress =
+                   (u32)mpt2sas_base_get_sense_buffer_dma(ioc, smid);
+               priv_sense = mpt2sas_base_get_sense_buffer(ioc, smid);
+               memset(priv_sense, 0, SCSI_SENSE_BUFFERSIZE);
+               mpt2sas_base_put_smid_scsi_io(ioc, smid, 0,
+                   le16_to_cpu(mpi_request->FunctionDependent1));
+               break;
+       }
+       case MPI2_FUNCTION_SCSI_TASK_MGMT:
+       {
+               Mpi2SCSITaskManagementRequest_t *tm_request =
+                   (Mpi2SCSITaskManagementRequest_t *)mpi_request;
+
+               if (tm_request->TaskType ==
+                   MPI2_SCSITASKMGMT_TASKTYPE_ABORT_TASK) {
+                       if (_ctl_do_task_abort(ioc, &karg, tm_request))
+                               goto out;
+               }
+
+               mutex_lock(&ioc->tm_cmds.mutex);
+               mpt2sas_scsih_set_tm_flag(ioc, le16_to_cpu(
+                   tm_request->DevHandle));
+               mpt2sas_base_put_smid_hi_priority(ioc, smid,
+                   mpi_request->VF_ID);
+               break;
+       }
+       case MPI2_FUNCTION_SMP_PASSTHROUGH:
+       {
+               Mpi2SmpPassthroughRequest_t *smp_request =
+                   (Mpi2SmpPassthroughRequest_t *)mpi_request;
+               u8 *data;
+
+               /* ioc determines which port to use */
+               smp_request->PhysicalPort = 0xFF;
+               if (smp_request->PassthroughFlags &
+                   MPI2_SMP_PT_REQ_PT_FLAGS_IMMEDIATE)
+                       data = (u8 *)&smp_request->SGL;
+               else
+                       data = data_out;
+
+               if (data[1] == 0x91 && (data[10] == 1 || data[10] == 2)) {
+                       ioc->ioc_link_reset_in_progress = 1;
+                       ioc->ignore_loginfos = 1;
+               }
+               mpt2sas_base_put_smid_default(ioc, smid, mpi_request->VF_ID);
+               break;
+       }
+       case MPI2_FUNCTION_SAS_IO_UNIT_CONTROL:
+       {
+               Mpi2SasIoUnitControlRequest_t *sasiounit_request =
+                   (Mpi2SasIoUnitControlRequest_t *)mpi_request;
+
+               if (sasiounit_request->Operation == MPI2_SAS_OP_PHY_HARD_RESET
+                   || sasiounit_request->Operation ==
+                   MPI2_SAS_OP_PHY_LINK_RESET) {
+                       ioc->ioc_link_reset_in_progress = 1;
+                       ioc->ignore_loginfos = 1;
+               }
+               mpt2sas_base_put_smid_default(ioc, smid, mpi_request->VF_ID);
+               break;
+       }
+       default:
+               mpt2sas_base_put_smid_default(ioc, smid, mpi_request->VF_ID);
+               break;
+       }
+
+       if (karg.timeout < MPT2_IOCTL_DEFAULT_TIMEOUT)
+               timeout = MPT2_IOCTL_DEFAULT_TIMEOUT;
+       else
+               timeout = karg.timeout;
+       timeleft = wait_for_completion_timeout(&ioc->ctl_cmds.done,
+           timeout*HZ);
+       if (mpi_request->Function == MPI2_FUNCTION_SCSI_TASK_MGMT) {
+               Mpi2SCSITaskManagementRequest_t *tm_request =
+                   (Mpi2SCSITaskManagementRequest_t *)mpi_request;
+               mutex_unlock(&ioc->tm_cmds.mutex);
+               mpt2sas_scsih_clear_tm_flag(ioc, le16_to_cpu(
+                   tm_request->DevHandle));
+       } else if ((mpi_request->Function == MPI2_FUNCTION_SMP_PASSTHROUGH ||
+           mpi_request->Function == MPI2_FUNCTION_SAS_IO_UNIT_CONTROL) &&
+               ioc->ioc_link_reset_in_progress) {
+               ioc->ioc_link_reset_in_progress = 0;
+               ioc->ignore_loginfos = 0;
+       }
+       if (!(ioc->ctl_cmds.status & MPT2_CMD_COMPLETE)) {
+               printk(MPT2SAS_ERR_FMT "%s: timeout\n", ioc->name,
+                   __func__);
+               _debug_dump_mf(mpi_request, karg.data_sge_offset);
+               if (!(ioc->ctl_cmds.status & MPT2_CMD_RESET))
+                       issue_reset = 1;
+               goto issue_host_reset;
+       }
+
+       mpi_reply = ioc->ctl_cmds.reply;
+       ioc_status = le16_to_cpu(mpi_reply->IOCStatus) & MPI2_IOCSTATUS_MASK;
+
+#ifdef CONFIG_SCSI_MPT2SAS_LOGGING
+       if (mpi_reply->Function == MPI2_FUNCTION_SCSI_TASK_MGMT &&
+           (ioc->logging_level & MPT_DEBUG_TM)) {
+               Mpi2SCSITaskManagementReply_t *tm_reply =
+                   (Mpi2SCSITaskManagementReply_t *)mpi_reply;
+
+               printk(MPT2SAS_DEBUG_FMT "TASK_MGMT: "
+                   "IOCStatus(0x%04x), IOCLogInfo(0x%08x), "
+                   "TerminationCount(0x%08x)\n", ioc->name,
+                   tm_reply->IOCStatus, tm_reply->IOCLogInfo,
+                   tm_reply->TerminationCount);
+       }
+#endif
+       /* copy out xdata to user */
+       if (data_in_sz) {
+               if (copy_to_user(karg.data_in_buf_ptr, data_in,
+                   data_in_sz)) {
+                       printk(KERN_ERR "failure at %s:%d/%s()!\n", __FILE__,
+                           __LINE__, __func__);
+                       ret = -ENODATA;
+                       goto out;
+               }
+       }
+
+       /* copy out reply message frame to user */
+       if (karg.max_reply_bytes) {
+               sz = min_t(u32, karg.max_reply_bytes, ioc->reply_sz);
+               if (copy_to_user(karg.reply_frame_buf_ptr, ioc->ctl_cmds.reply,
+                   sz)) {
+                       printk(KERN_ERR "failure at %s:%d/%s()!\n", __FILE__,
+                           __LINE__, __func__);
+                       ret = -ENODATA;
+                       goto out;
+               }
+       }
+
+       /* copy out sense to user */
+       if (karg.max_sense_bytes && (mpi_request->Function ==
+           MPI2_FUNCTION_SCSI_IO_REQUEST || mpi_request->Function ==
+           MPI2_FUNCTION_RAID_SCSI_IO_PASSTHROUGH)) {
+               sz = min_t(u32, karg.max_sense_bytes, SCSI_SENSE_BUFFERSIZE);
+               if (copy_to_user(karg.sense_data_ptr, priv_sense, sz)) {
+                       printk(KERN_ERR "failure at %s:%d/%s()!\n", __FILE__,
+                           __LINE__, __func__);
+                       ret = -ENODATA;
+                       goto out;
+               }
+       }
+
+ issue_host_reset:
+       if (issue_reset) {
+               if ((mpi_request->Function == MPI2_FUNCTION_SCSI_IO_REQUEST ||
+                   mpi_request->Function ==
+                   MPI2_FUNCTION_RAID_SCSI_IO_PASSTHROUGH)) {
+                       printk(MPT2SAS_INFO_FMT "issue target reset: handle "
+                           "= (0x%04x)\n", ioc->name,
+                           mpi_request->FunctionDependent1);
+                       mutex_lock(&ioc->tm_cmds.mutex);
+                       mpt2sas_scsih_issue_tm(ioc,
+                           mpi_request->FunctionDependent1, 0,
+                           MPI2_SCSITASKMGMT_TASKTYPE_TARGET_RESET, 0, 10);
+                       ioc->tm_cmds.status = MPT2_CMD_NOT_USED;
+                       mutex_unlock(&ioc->tm_cmds.mutex);
+               } else
+                       mpt2sas_base_hard_reset_handler(ioc, CAN_SLEEP,
+                           FORCE_BIG_HAMMER);
+       }
+
+ out:
+
+       /* free memory associated with sg buffers */
+       if (data_in)
+               pci_free_consistent(ioc->pdev, data_in_sz, data_in,
+                   data_in_dma);
+
+       if (data_out)
+               pci_free_consistent(ioc->pdev, data_out_sz, data_out,
+                   data_out_dma);
+
+       ioc->ctl_cmds.status = MPT2_CMD_NOT_USED;
+       mutex_unlock(&ioc->ctl_cmds.mutex);
+       return ret;
+}
+
+/**
+ * _ctl_getiocinfo - main handler for MPT2IOCINFO opcode
+ * @arg - user space buffer containing ioctl content
+ */
+static long
+_ctl_getiocinfo(void __user *arg)
+{
+       struct mpt2_ioctl_iocinfo karg;
+       struct MPT2SAS_ADAPTER *ioc;
+       u8 revision;
+
+       if (copy_from_user(&karg, arg, sizeof(karg))) {
+               printk(KERN_ERR "failure at %s:%d/%s()!\n",
+                   __FILE__, __LINE__, __func__);
+               return -EFAULT;
+       }
+       if (_ctl_verify_adapter(karg.hdr.ioc_number, &ioc) == -1 || !ioc)
+               return -ENODEV;
+
+       dctlprintk(ioc, printk(MPT2SAS_DEBUG_FMT "%s: enter\n", ioc->name,
+           __func__));
+
+       memset(&karg, 0 , sizeof(karg));
+       karg.adapter_type = MPT2_IOCTL_INTERFACE_SAS2;
+       if (ioc->pfacts)
+               karg.port_number = ioc->pfacts[0].PortNumber;
+       pci_read_config_byte(ioc->pdev, PCI_CLASS_REVISION, &revision);
+       karg.hw_rev = revision;
+       karg.pci_id = ioc->pdev->device;
+       karg.subsystem_device = ioc->pdev->subsystem_device;
+       karg.subsystem_vendor = ioc->pdev->subsystem_vendor;
+       karg.pci_information.u.bits.bus = ioc->pdev->bus->number;
+       karg.pci_information.u.bits.device = PCI_SLOT(ioc->pdev->devfn);
+       karg.pci_information.u.bits.function = PCI_FUNC(ioc->pdev->devfn);
+       karg.pci_information.segment_id = pci_domain_nr(ioc->pdev->bus);
+       karg.firmware_version = ioc->facts.FWVersion.Word;
+       strncpy(karg.driver_version, MPT2SAS_DRIVER_VERSION,
+           MPT2_IOCTL_VERSION_LENGTH);
+       karg.driver_version[MPT2_IOCTL_VERSION_LENGTH - 1] = '\0';
+       karg.bios_version = le32_to_cpu(ioc->bios_pg3.BiosVersion);
+
+       if (copy_to_user(arg, &karg, sizeof(karg))) {
+               printk(KERN_ERR "failure at %s:%d/%s()!\n",
+                   __FILE__, __LINE__, __func__);
+               return -EFAULT;
+       }
+       return 0;
+}
+
+/**
+ * _ctl_eventquery - main handler for MPT2EVENTQUERY opcode
+ * @arg - user space buffer containing ioctl content
+ */
+static long
+_ctl_eventquery(void __user *arg)
+{
+       struct mpt2_ioctl_eventquery karg;
+       struct MPT2SAS_ADAPTER *ioc;
+
+       if (copy_from_user(&karg, arg, sizeof(karg))) {
+               printk(KERN_ERR "failure at %s:%d/%s()!\n",
+                   __FILE__, __LINE__, __func__);
+               return -EFAULT;
+       }
+       if (_ctl_verify_adapter(karg.hdr.ioc_number, &ioc) == -1 || !ioc)
+               return -ENODEV;
+
+       dctlprintk(ioc, printk(MPT2SAS_DEBUG_FMT "%s: enter\n", ioc->name,
+           __func__));
+
+       karg.event_entries = MPT2SAS_CTL_EVENT_LOG_SIZE;
+       memcpy(karg.event_types, ioc->event_type,
+           MPI2_EVENT_NOTIFY_EVENTMASK_WORDS * sizeof(u32));
+
+       if (copy_to_user(arg, &karg, sizeof(karg))) {
+               printk(KERN_ERR "failure at %s:%d/%s()!\n",
+                   __FILE__, __LINE__, __func__);
+               return -EFAULT;
+       }
+       return 0;
+}
+
+/**
+ * _ctl_eventenable - main handler for MPT2EVENTENABLE opcode
+ * @arg - user space buffer containing ioctl content
+ */
+static long
+_ctl_eventenable(void __user *arg)
+{
+       struct mpt2_ioctl_eventenable karg;
+       struct MPT2SAS_ADAPTER *ioc;
+
+       if (copy_from_user(&karg, arg, sizeof(karg))) {
+               printk(KERN_ERR "failure at %s:%d/%s()!\n",
+                   __FILE__, __LINE__, __func__);
+               return -EFAULT;
+       }
+       if (_ctl_verify_adapter(karg.hdr.ioc_number, &ioc) == -1 || !ioc)
+               return -ENODEV;
+
+       dctlprintk(ioc, printk(MPT2SAS_DEBUG_FMT "%s: enter\n", ioc->name,
+           __func__));
+
+       if (ioc->event_log)
+               return 0;
+       memcpy(ioc->event_type, karg.event_types,
+           MPI2_EVENT_NOTIFY_EVENTMASK_WORDS * sizeof(u32));
+       mpt2sas_base_validate_event_type(ioc, ioc->event_type);
+
+       /* initialize event_log */
+       ioc->event_context = 0;
+       ioc->aen_event_read_flag = 0;
+       ioc->event_log = kcalloc(MPT2SAS_CTL_EVENT_LOG_SIZE,
+           sizeof(struct MPT2_IOCTL_EVENTS), GFP_KERNEL);
+       if (!ioc->event_log) {
+               printk(KERN_ERR "failure at %s:%d/%s()!\n",
+                   __FILE__, __LINE__, __func__);
+               return -ENOMEM;
+       }
+       return 0;
+}
+
+/**
+ * _ctl_eventreport - main handler for MPT2EVENTREPORT opcode
+ * @arg - user space buffer containing ioctl content
+ */
+static long
+_ctl_eventreport(void __user *arg)
+{
+       struct mpt2_ioctl_eventreport karg;
+       struct MPT2SAS_ADAPTER *ioc;
+       u32 number_bytes, max_events, max;
+       struct mpt2_ioctl_eventreport __user *uarg = arg;
+
+       if (copy_from_user(&karg, arg, sizeof(karg))) {
+               printk(KERN_ERR "failure at %s:%d/%s()!\n",
+                   __FILE__, __LINE__, __func__);
+               return -EFAULT;
+       }
+       if (_ctl_verify_adapter(karg.hdr.ioc_number, &ioc) == -1 || !ioc)
+               return -ENODEV;
+
+       dctlprintk(ioc, printk(MPT2SAS_DEBUG_FMT "%s: enter\n", ioc->name,
+           __func__));
+
+       number_bytes = karg.hdr.max_data_size -
+           sizeof(struct mpt2_ioctl_header);
+       max_events = number_bytes/sizeof(struct MPT2_IOCTL_EVENTS);
+       max = min_t(u32, MPT2SAS_CTL_EVENT_LOG_SIZE, max_events);
+
+       /* If fewer than 1 event is requested, there must have
+        * been some type of error.
+        */
+       if (!max || !ioc->event_log)
+               return -ENODATA;
+
+       number_bytes = max * sizeof(struct MPT2_IOCTL_EVENTS);
+       if (copy_to_user(uarg->event_data, ioc->event_log, number_bytes)) {
+               printk(KERN_ERR "failure at %s:%d/%s()!\n",
+                   __FILE__, __LINE__, __func__);
+               return -EFAULT;
+       }
+
+       /* reset flag so SIGIO can restart */
+       ioc->aen_event_read_flag = 0;
+       return 0;
+}
+
+/**
+ * _ctl_do_reset - main handler for MPT2HARDRESET opcode
+ * @arg - user space buffer containing ioctl content
+ */
+static long
+_ctl_do_reset(void __user *arg)
+{
+       struct mpt2_ioctl_diag_reset karg;
+       struct MPT2SAS_ADAPTER *ioc;
+       int retval;
+
+       if (copy_from_user(&karg, arg, sizeof(karg))) {
+               printk(KERN_ERR "failure at %s:%d/%s()!\n",
+                   __FILE__, __LINE__, __func__);
+               return -EFAULT;
+       }
+       if (_ctl_verify_adapter(karg.hdr.ioc_number, &ioc) == -1 || !ioc)
+               return -ENODEV;
+
+       dctlprintk(ioc, printk(MPT2SAS_DEBUG_FMT "%s: enter\n", ioc->name,
+           __func__));
+
+       retval = mpt2sas_base_hard_reset_handler(ioc, CAN_SLEEP,
+           FORCE_BIG_HAMMER);
+       printk(MPT2SAS_INFO_FMT "host reset: %s\n",
+           ioc->name, ((!retval) ? "SUCCESS" : "FAILED"));
+       return 0;
+}
+
+/**
+ * _ctl_btdh_search_sas_device - searching for sas device
+ * @ioc: per adapter object
+ * @btdh: btdh ioctl payload
+ */
+static int
+_ctl_btdh_search_sas_device(struct MPT2SAS_ADAPTER *ioc,
+    struct mpt2_ioctl_btdh_mapping *btdh)
+{
+       struct _sas_device *sas_device;
+       unsigned long flags;
+       int rc = 0;
+
+       if (list_empty(&ioc->sas_device_list))
+               return rc;
+
+       spin_lock_irqsave(&ioc->sas_device_lock, flags);
+       list_for_each_entry(sas_device, &ioc->sas_device_list, list) {
+               if (btdh->bus == 0xFFFFFFFF && btdh->id == 0xFFFFFFFF &&
+                   btdh->handle == sas_device->handle) {
+                       btdh->bus = sas_device->channel;
+                       btdh->id = sas_device->id;
+                       rc = 1;
+                       goto out;
+               } else if (btdh->bus == sas_device->channel && btdh->id ==
+                   sas_device->id && btdh->handle == 0xFFFF) {
+                       btdh->handle = sas_device->handle;
+                       rc = 1;
+                       goto out;
+               }
+       }
+ out:
+       spin_unlock_irqrestore(&ioc->sas_device_lock, flags);
+       return rc;
+}
+
+/**
+ * _ctl_btdh_search_raid_device - searching for raid device
+ * @ioc: per adapter object
+ * @btdh: btdh ioctl payload
+ */
+static int
+_ctl_btdh_search_raid_device(struct MPT2SAS_ADAPTER *ioc,
+    struct mpt2_ioctl_btdh_mapping *btdh)
+{
+       struct _raid_device *raid_device;
+       unsigned long flags;
+       int rc = 0;
+
+       if (list_empty(&ioc->raid_device_list))
+               return rc;
+
+       spin_lock_irqsave(&ioc->raid_device_lock, flags);
+       list_for_each_entry(raid_device, &ioc->raid_device_list, list) {
+               if (btdh->bus == 0xFFFFFFFF && btdh->id == 0xFFFFFFFF &&
+                   btdh->handle == raid_device->handle) {
+                       btdh->bus = raid_device->channel;
+                       btdh->id = raid_device->id;
+                       rc = 1;
+                       goto out;
+               } else if (btdh->bus == raid_device->channel && btdh->id ==
+                   raid_device->id && btdh->handle == 0xFFFF) {
+                       btdh->handle = raid_device->handle;
+                       rc = 1;
+                       goto out;
+               }
+       }
+ out:
+       spin_unlock_irqrestore(&ioc->raid_device_lock, flags);
+       return rc;
+}
+
+/**
+ * _ctl_btdh_mapping - main handler for MPT2BTDHMAPPING opcode
+ * @arg - user space buffer containing ioctl content
+ */
+static long
+_ctl_btdh_mapping(void __user *arg)
+{
+       struct mpt2_ioctl_btdh_mapping karg;
+       struct MPT2SAS_ADAPTER *ioc;
+       int rc;
+
+       if (copy_from_user(&karg, arg, sizeof(karg))) {
+               printk(KERN_ERR "failure at %s:%d/%s()!\n",
+                   __FILE__, __LINE__, __func__);
+               return -EFAULT;
+       }
+       if (_ctl_verify_adapter(karg.hdr.ioc_number, &ioc) == -1 || !ioc)
+               return -ENODEV;
+
+       dctlprintk(ioc, printk(MPT2SAS_DEBUG_FMT "%s\n", ioc->name,
+           __func__));
+
+       rc = _ctl_btdh_search_sas_device(ioc, &karg);
+       if (!rc)
+               _ctl_btdh_search_raid_device(ioc, &karg);
+
+       if (copy_to_user(arg, &karg, sizeof(karg))) {
+               printk(KERN_ERR "failure at %s:%d/%s()!\n",
+                   __FILE__, __LINE__, __func__);
+               return -EFAULT;
+       }
+       return 0;
+}
+
+/**
+ * _ctl_diag_capability - return diag buffer capability
+ * @ioc: per adapter object
+ * @buffer_type: specifies either TRACE or SNAPSHOT
+ *
+ * returns 1 when diag buffer support is enabled in firmware
+ */
+static u8
+_ctl_diag_capability(struct MPT2SAS_ADAPTER *ioc, u8 buffer_type)
+{
+       u8 rc = 0;
+
+       switch (buffer_type) {
+       case MPI2_DIAG_BUF_TYPE_TRACE:
+               if (ioc->facts.IOCCapabilities &
+                   MPI2_IOCFACTS_CAPABILITY_DIAG_TRACE_BUFFER)
+                       rc = 1;
+               break;
+       case MPI2_DIAG_BUF_TYPE_SNAPSHOT:
+               if (ioc->facts.IOCCapabilities &
+                   MPI2_IOCFACTS_CAPABILITY_SNAPSHOT_BUFFER)
+                       rc = 1;
+               break;
+       }
+
+       return rc;
+}
+
+/**
+ * _ctl_diag_register - application register with driver
+ * @arg - user space buffer containing ioctl content
+ * @state - NON_BLOCKING or BLOCKING
+ *
+ * This will allow the driver to setup any required buffers that will be
+ * needed by firmware to communicate with the driver.
+ */
+static long
+_ctl_diag_register(void __user *arg, enum block_state state)
+{
+       struct mpt2_diag_register karg;
+       struct MPT2SAS_ADAPTER *ioc;
+       int rc, i;
+       void *request_data = NULL;
+       dma_addr_t request_data_dma;
+       u32 request_data_sz = 0;
+       Mpi2DiagBufferPostRequest_t *mpi_request;
+       Mpi2DiagBufferPostReply_t *mpi_reply;
+       u8 buffer_type;
+       unsigned long timeleft;
+       u16 smid;
+       u16 ioc_status;
+       u8 issue_reset = 0;
+
+       if (copy_from_user(&karg, arg, sizeof(karg))) {
+               printk(KERN_ERR "failure at %s:%d/%s()!\n",
+                   __FILE__, __LINE__, __func__);
+               return -EFAULT;
+       }
+       if (_ctl_verify_adapter(karg.hdr.ioc_number, &ioc) == -1 || !ioc)
+               return -ENODEV;
+
+       dctlprintk(ioc, printk(MPT2SAS_DEBUG_FMT "%s\n", ioc->name,
+           __func__));
+
+       buffer_type = karg.buffer_type;
+       if (!_ctl_diag_capability(ioc, buffer_type)) {
+               printk(MPT2SAS_ERR_FMT "%s: doesn't have capability for "
+                   "buffer_type(0x%02x)\n", ioc->name, __func__, buffer_type);
+               return -EPERM;
+       }
+
+       if (ioc->diag_buffer_status[buffer_type] &
+           MPT2_DIAG_BUFFER_IS_REGISTERED) {
+               printk(MPT2SAS_ERR_FMT "%s: already has a registered "
+                   "buffer for buffer_type(0x%02x)\n", ioc->name, __func__,
+                   buffer_type);
+               return -EINVAL;
+       }
+
+       if (karg.requested_buffer_size % 4)  {
+               printk(MPT2SAS_ERR_FMT "%s: the requested_buffer_size "
+                   "is not 4 byte aligned\n", ioc->name, __func__);
+               return -EINVAL;
+       }
+
+       if (state == NON_BLOCKING && !mutex_trylock(&ioc->ctl_cmds.mutex))
+               return -EAGAIN;
+       else if (mutex_lock_interruptible(&ioc->ctl_cmds.mutex))
+               return -ERESTARTSYS;
+
+       if (ioc->ctl_cmds.status != MPT2_CMD_NOT_USED) {
+               printk(MPT2SAS_ERR_FMT "%s: ctl_cmd in use\n",
+                   ioc->name, __func__);
+               rc = -EAGAIN;
+               goto out;
+       }
+
+       smid = mpt2sas_base_get_smid(ioc, ioc->ctl_cb_idx);
+       if (!smid) {
+               printk(MPT2SAS_ERR_FMT "%s: failed obtaining a smid\n",
+                   ioc->name, __func__);
+               rc = -EAGAIN;
+               goto out;
+       }
+
+       rc = 0;
+       ioc->ctl_cmds.status = MPT2_CMD_PENDING;
+       memset(ioc->ctl_cmds.reply, 0, ioc->reply_sz);
+       mpi_request = mpt2sas_base_get_msg_frame(ioc, smid);
+       ioc->ctl_cmds.smid = smid;
+
+       request_data = ioc->diag_buffer[buffer_type];
+       request_data_sz = karg.requested_buffer_size;
+       ioc->unique_id[buffer_type] = karg.unique_id;
+       ioc->diag_buffer_status[buffer_type] = 0;
+       memcpy(ioc->product_specific[buffer_type], karg.product_specific,
+           MPT2_PRODUCT_SPECIFIC_DWORDS);
+       ioc->diagnostic_flags[buffer_type] = karg.diagnostic_flags;
+
+       if (request_data) {
+               request_data_dma = ioc->diag_buffer_dma[buffer_type];
+               if (request_data_sz != ioc->diag_buffer_sz[buffer_type]) {
+                       pci_free_consistent(ioc->pdev,
+                           ioc->diag_buffer_sz[buffer_type],
+                           request_data, request_data_dma);
+                       request_data = NULL;
+               }
+       }
+
+       if (request_data == NULL) {
+               ioc->diag_buffer_sz[buffer_type] = 0;
+               ioc->diag_buffer_dma[buffer_type] = 0;
+               request_data = pci_alloc_consistent(
+                       ioc->pdev, request_data_sz, &request_data_dma);
+               if (request_data == NULL) {
+                       printk(MPT2SAS_ERR_FMT "%s: failed allocating memory"
+                           " for diag buffers, requested size(%d)\n",
+                           ioc->name, __func__, request_data_sz);
+                       mpt2sas_base_free_smid(ioc, smid);
+                       return -ENOMEM;
+               }
+               ioc->diag_buffer[buffer_type] = request_data;
+               ioc->diag_buffer_sz[buffer_type] = request_data_sz;
+               ioc->diag_buffer_dma[buffer_type] = request_data_dma;
+       }
+
+       mpi_request->Function = MPI2_FUNCTION_DIAG_BUFFER_POST;
+       mpi_request->BufferType = karg.buffer_type;
+       mpi_request->Flags = cpu_to_le32(karg.diagnostic_flags);
+       mpi_request->BufferAddress = cpu_to_le64(request_data_dma);
+       mpi_request->BufferLength = cpu_to_le32(request_data_sz);
+
+       dctlprintk(ioc, printk(MPT2SAS_DEBUG_FMT "%s: diag_buffer(0x%p), "
+           "dma(0x%llx), sz(%d)\n", ioc->name, __func__, request_data,
+           (unsigned long long)request_data_dma, mpi_request->BufferLength));
+
+       for (i = 0; i < MPT2_PRODUCT_SPECIFIC_DWORDS; i++)
+               mpi_request->ProductSpecific[i] =
+                       cpu_to_le32(ioc->product_specific[buffer_type][i]);
+
+       mpt2sas_base_put_smid_default(ioc, smid, mpi_request->VF_ID);
+       timeleft = wait_for_completion_timeout(&ioc->ctl_cmds.done,
+           MPT2_IOCTL_DEFAULT_TIMEOUT*HZ);
+
+       if (!(ioc->ctl_cmds.status & MPT2_CMD_COMPLETE)) {
+               printk(MPT2SAS_ERR_FMT "%s: timeout\n", ioc->name,
+                   __func__);
+               _debug_dump_mf(mpi_request,
+                   sizeof(Mpi2DiagBufferPostRequest_t)/4);
+               if (!(ioc->ctl_cmds.status & MPT2_CMD_RESET))
+                       issue_reset = 1;
+               goto issue_host_reset;
+       }
+
+       /* process the completed Reply Message Frame */
+       if ((ioc->ctl_cmds.status & MPT2_CMD_REPLY_VALID) == 0) {
+               printk(MPT2SAS_ERR_FMT "%s: no reply message\n",
+                   ioc->name, __func__);
+               rc = -EFAULT;
+               goto out;
+       }
+
+       mpi_reply = ioc->ctl_cmds.reply;
+       ioc_status = le16_to_cpu(mpi_reply->IOCStatus) & MPI2_IOCSTATUS_MASK;
+
+       if (ioc_status == MPI2_IOCSTATUS_SUCCESS) {
+               ioc->diag_buffer_status[buffer_type] |=
+                       MPT2_DIAG_BUFFER_IS_REGISTERED;
+               dctlprintk(ioc, printk(MPT2SAS_DEBUG_FMT "%s: success\n",
+                   ioc->name, __func__));
+       } else {
+               printk(MPT2SAS_DEBUG_FMT "%s: ioc_status(0x%04x) "
+                   "log_info(0x%08x)\n", ioc->name, __func__,
+                   ioc_status, mpi_reply->IOCLogInfo);
+               rc = -EFAULT;
+       }
+
+ issue_host_reset:
+       if (issue_reset)
+               mpt2sas_base_hard_reset_handler(ioc, CAN_SLEEP,
+                   FORCE_BIG_HAMMER);
+
+ out:
+
+       if (rc && request_data)
+               pci_free_consistent(ioc->pdev, request_data_sz,
+                   request_data, request_data_dma);
+
+       ioc->ctl_cmds.status = MPT2_CMD_NOT_USED;
+       mutex_unlock(&ioc->ctl_cmds.mutex);
+       return rc;
+}
+
+/**
+ * _ctl_diag_unregister - application unregister with driver
+ * @arg - user space buffer containing ioctl content
+ *
+ * This will allow the driver to cleanup any memory allocated for diag
+ * messages and to free up any resources.
+ */
+static long
+_ctl_diag_unregister(void __user *arg)
+{
+       struct mpt2_diag_unregister karg;
+       struct MPT2SAS_ADAPTER *ioc;
+       void *request_data;
+       dma_addr_t request_data_dma;
+       u32 request_data_sz;
+       u8 buffer_type;
+
+       if (copy_from_user(&karg, arg, sizeof(karg))) {
+               printk(KERN_ERR "failure at %s:%d/%s()!\n",
+                   __FILE__, __LINE__, __func__);
+               return -EFAULT;
+       }
+       if (_ctl_verify_adapter(karg.hdr.ioc_number, &ioc) == -1 || !ioc)
+               return -ENODEV;
+
+       dctlprintk(ioc, printk(MPT2SAS_DEBUG_FMT "%s\n", ioc->name,
+           __func__));
+
+       buffer_type = karg.unique_id & 0x000000ff;
+       if (!_ctl_diag_capability(ioc, buffer_type)) {
+               printk(MPT2SAS_ERR_FMT "%s: doesn't have capability for "
+                   "buffer_type(0x%02x)\n", ioc->name, __func__, buffer_type);
+               return -EPERM;
+       }
+
+       if ((ioc->diag_buffer_status[buffer_type] &
+           MPT2_DIAG_BUFFER_IS_REGISTERED) == 0) {
+               printk(MPT2SAS_ERR_FMT "%s: buffer_type(0x%02x) is not "
+                   "registered\n", ioc->name, __func__, buffer_type);
+               return -EINVAL;
+       }
+       if ((ioc->diag_buffer_status[buffer_type] &
+           MPT2_DIAG_BUFFER_IS_RELEASED) == 0) {
+               printk(MPT2SAS_ERR_FMT "%s: buffer_type(0x%02x) has not been "
+                   "released\n", ioc->name, __func__, buffer_type);
+               return -EINVAL;
+       }
+
+       if (karg.unique_id != ioc->unique_id[buffer_type]) {
+               printk(MPT2SAS_ERR_FMT "%s: unique_id(0x%08x) is not "
+                   "registered\n", ioc->name, __func__, karg.unique_id);
+               return -EINVAL;
+       }
+
+       request_data = ioc->diag_buffer[buffer_type];
+       if (!request_data) {
+               printk(MPT2SAS_ERR_FMT "%s: doesn't have memory allocated for "
+                   "buffer_type(0x%02x)\n", ioc->name, __func__, buffer_type);
+               return -ENOMEM;
+       }
+
+       request_data_sz = ioc->diag_buffer_sz[buffer_type];
+       request_data_dma = ioc->diag_buffer_dma[buffer_type];
+       pci_free_consistent(ioc->pdev, request_data_sz,
+           request_data, request_data_dma);
+       ioc->diag_buffer[buffer_type] = NULL;
+       ioc->diag_buffer_status[buffer_type] = 0;
+       return 0;
+}
+
+/**
+ * _ctl_diag_query - query relevant info associated with diag buffers
+ * @arg - user space buffer containing ioctl content
+ *
+ * The application will send only buffer_type and unique_id.  Driver will
+ * inspect unique_id first, if valid, fill in all the info.  If unique_id is
+ * 0x00, the driver will return info specified by Buffer Type.
+ */
+static long
+_ctl_diag_query(void __user *arg)
+{
+       struct mpt2_diag_query karg;
+       struct MPT2SAS_ADAPTER *ioc;
+       void *request_data;
+       int i;
+       u8 buffer_type;
+
+       if (copy_from_user(&karg, arg, sizeof(karg))) {
+               printk(KERN_ERR "failure at %s:%d/%s()!\n",
+                   __FILE__, __LINE__, __func__);
+               return -EFAULT;
+       }
+       if (_ctl_verify_adapter(karg.hdr.ioc_number, &ioc) == -1 || !ioc)
+               return -ENODEV;
+
+       dctlprintk(ioc, printk(MPT2SAS_DEBUG_FMT "%s\n", ioc->name,
+           __func__));
+
+       karg.application_flags = 0;
+       buffer_type = karg.buffer_type;
+
+       if (!_ctl_diag_capability(ioc, buffer_type)) {
+               printk(MPT2SAS_ERR_FMT "%s: doesn't have capability for "
+                   "buffer_type(0x%02x)\n", ioc->name, __func__, buffer_type);
+               return -EPERM;
+       }
+
+       if ((ioc->diag_buffer_status[buffer_type] &
+           MPT2_DIAG_BUFFER_IS_REGISTERED) == 0) {
+               printk(MPT2SAS_ERR_FMT "%s: buffer_type(0x%02x) is not "
+                   "registered\n", ioc->name, __func__, buffer_type);
+               return -EINVAL;
+       }
+
+       if (karg.unique_id & 0xffffff00) {
+               if (karg.unique_id != ioc->unique_id[buffer_type]) {
+                       printk(MPT2SAS_ERR_FMT "%s: unique_id(0x%08x) is not "
+                           "registered\n", ioc->name, __func__,
+                           karg.unique_id);
+                       return -EINVAL;
+               }
+       }
+
+       request_data = ioc->diag_buffer[buffer_type];
+       if (!request_data) {
+               printk(MPT2SAS_ERR_FMT "%s: doesn't have buffer for "
+                   "buffer_type(0x%02x)\n", ioc->name, __func__, buffer_type);
+               return -ENOMEM;
+       }
+
+       if (ioc->diag_buffer_status[buffer_type] & MPT2_DIAG_BUFFER_IS_RELEASED)
+               karg.application_flags = (MPT2_APP_FLAGS_APP_OWNED |
+                   MPT2_APP_FLAGS_BUFFER_VALID);
+       else
+               karg.application_flags = (MPT2_APP_FLAGS_APP_OWNED |
+                   MPT2_APP_FLAGS_BUFFER_VALID |
+                   MPT2_APP_FLAGS_FW_BUFFER_ACCESS);
+
+       for (i = 0; i < MPT2_PRODUCT_SPECIFIC_DWORDS; i++)
+               karg.product_specific[i] =
+                   ioc->product_specific[buffer_type][i];
+
+       karg.total_buffer_size = ioc->diag_buffer_sz[buffer_type];
+       karg.driver_added_buffer_size = 0;
+       karg.unique_id = ioc->unique_id[buffer_type];
+       karg.diagnostic_flags = ioc->diagnostic_flags[buffer_type];
+
+       if (copy_to_user(arg, &karg, sizeof(struct mpt2_diag_query))) {
+               printk(MPT2SAS_ERR_FMT "%s: unable to write mpt2_diag_query "
+                   "data @ %p\n", ioc->name, __func__, arg);
+               return -EFAULT;
+       }
+       return 0;
+}
+
+/**
+ * _ctl_diag_release - request to send Diag Release Message to firmware
+ * @arg - user space buffer containing ioctl content
+ * @state - NON_BLOCKING or BLOCKING
+ *
+ * This allows ownership of the specified buffer to returned to the driver,
+ * allowing an application to read the buffer without fear that firmware is
+ * overwritting information in the buffer.
+ */
+static long
+_ctl_diag_release(void __user *arg, enum block_state state)
+{
+       struct mpt2_diag_release karg;
+       struct MPT2SAS_ADAPTER *ioc;
+       void *request_data;
+       int rc;
+       Mpi2DiagReleaseRequest_t *mpi_request;
+       Mpi2DiagReleaseReply_t *mpi_reply;
+       u8 buffer_type;
+       unsigned long timeleft;
+       u16 smid;
+       u16 ioc_status;
+       u8 issue_reset = 0;
+
+       if (copy_from_user(&karg, arg, sizeof(karg))) {
+               printk(KERN_ERR "failure at %s:%d/%s()!\n",
+                   __FILE__, __LINE__, __func__);
+               return -EFAULT;
+       }
+       if (_ctl_verify_adapter(karg.hdr.ioc_number, &ioc) == -1 || !ioc)
+               return -ENODEV;
+
+       dctlprintk(ioc, printk(MPT2SAS_DEBUG_FMT "%s\n", ioc->name,
+           __func__));
+
+       buffer_type = karg.unique_id & 0x000000ff;
+       if (!_ctl_diag_capability(ioc, buffer_type)) {
+               printk(MPT2SAS_ERR_FMT "%s: doesn't have capability for "
+                   "buffer_type(0x%02x)\n", ioc->name, __func__, buffer_type);
+               return -EPERM;
+       }
+
+       if ((ioc->diag_buffer_status[buffer_type] &
+           MPT2_DIAG_BUFFER_IS_REGISTERED) == 0) {
+               printk(MPT2SAS_ERR_FMT "%s: buffer_type(0x%02x) is not "
+                   "registered\n", ioc->name, __func__, buffer_type);
+               return -EINVAL;
+       }
+
+       if (karg.unique_id != ioc->unique_id[buffer_type]) {
+               printk(MPT2SAS_ERR_FMT "%s: unique_id(0x%08x) is not "
+                   "registered\n", ioc->name, __func__, karg.unique_id);
+               return -EINVAL;
+       }
+
+       if (ioc->diag_buffer_status[buffer_type] &
+           MPT2_DIAG_BUFFER_IS_RELEASED) {
+               printk(MPT2SAS_ERR_FMT "%s: buffer_type(0x%02x) "
+                   "is already released\n", ioc->name, __func__,
+                   buffer_type);
+               return 0;
+       }
+
+       request_data = ioc->diag_buffer[buffer_type];
+
+       if (!request_data) {
+               printk(MPT2SAS_ERR_FMT "%s: doesn't have memory allocated for "
+                   "buffer_type(0x%02x)\n", ioc->name, __func__, buffer_type);
+               return -ENOMEM;
+       }
+
+       if (state == NON_BLOCKING && !mutex_trylock(&ioc->ctl_cmds.mutex))
+               return -EAGAIN;
+       else if (mutex_lock_interruptible(&ioc->ctl_cmds.mutex))
+               return -ERESTARTSYS;
+
+       if (ioc->ctl_cmds.status != MPT2_CMD_NOT_USED) {
+               printk(MPT2SAS_ERR_FMT "%s: ctl_cmd in use\n",
+                   ioc->name, __func__);
+               rc = -EAGAIN;
+               goto out;
+       }
+
+       smid = mpt2sas_base_get_smid(ioc, ioc->ctl_cb_idx);
+       if (!smid) {
+               printk(MPT2SAS_ERR_FMT "%s: failed obtaining a smid\n",
+                   ioc->name, __func__);
+               rc = -EAGAIN;
+               goto out;
+       }
+
+       rc = 0;
+       ioc->ctl_cmds.status = MPT2_CMD_PENDING;
+       memset(ioc->ctl_cmds.reply, 0, ioc->reply_sz);
+       mpi_request = mpt2sas_base_get_msg_frame(ioc, smid);
+       ioc->ctl_cmds.smid = smid;
+
+       mpi_request->Function = MPI2_FUNCTION_DIAG_RELEASE;
+       mpi_request->BufferType = buffer_type;
+
+       mpt2sas_base_put_smid_default(ioc, smid, mpi_request->VF_ID);
+       timeleft = wait_for_completion_timeout(&ioc->ctl_cmds.done,
+           MPT2_IOCTL_DEFAULT_TIMEOUT*HZ);
+
+       if (!(ioc->ctl_cmds.status & MPT2_CMD_COMPLETE)) {
+               printk(MPT2SAS_ERR_FMT "%s: timeout\n", ioc->name,
+                   __func__);
+               _debug_dump_mf(mpi_request,
+                   sizeof(Mpi2DiagReleaseRequest_t)/4);
+               if (!(ioc->ctl_cmds.status & MPT2_CMD_RESET))
+                       issue_reset = 1;
+               goto issue_host_reset;
+       }
+
+       /* process the completed Reply Message Frame */
+       if ((ioc->ctl_cmds.status & MPT2_CMD_REPLY_VALID) == 0) {
+               printk(MPT2SAS_ERR_FMT "%s: no reply message\n",
+                   ioc->name, __func__);
+               rc = -EFAULT;
+               goto out;
+       }
+
+       mpi_reply = ioc->ctl_cmds.reply;
+       ioc_status = le16_to_cpu(mpi_reply->IOCStatus) & MPI2_IOCSTATUS_MASK;
+
+       if (ioc_status == MPI2_IOCSTATUS_SUCCESS) {
+               ioc->diag_buffer_status[buffer_type] |=
+                   MPT2_DIAG_BUFFER_IS_RELEASED;
+               dctlprintk(ioc, printk(MPT2SAS_DEBUG_FMT "%s: success\n",
+                   ioc->name, __func__));
+       } else {
+               printk(MPT2SAS_DEBUG_FMT "%s: ioc_status(0x%04x) "
+                   "log_info(0x%08x)\n", ioc->name, __func__,
+                   ioc_status, mpi_reply->IOCLogInfo);
+               rc = -EFAULT;
+       }
+
+ issue_host_reset:
+       if (issue_reset)
+               mpt2sas_base_hard_reset_handler(ioc, CAN_SLEEP,
+                   FORCE_BIG_HAMMER);
+
+ out:
+
+       ioc->ctl_cmds.status = MPT2_CMD_NOT_USED;
+       mutex_unlock(&ioc->ctl_cmds.mutex);
+       return rc;
+}
+
+/**
+ * _ctl_diag_read_buffer - request for copy of the diag buffer
+ * @arg - user space buffer containing ioctl content
+ * @state - NON_BLOCKING or BLOCKING
+ */
+static long
+_ctl_diag_read_buffer(void __user *arg, enum block_state state)
+{
+       struct mpt2_diag_read_buffer karg;
+       struct mpt2_diag_read_buffer __user *uarg = arg;
+       struct MPT2SAS_ADAPTER *ioc;
+       void *request_data, *diag_data;
+       Mpi2DiagBufferPostRequest_t *mpi_request;
+       Mpi2DiagBufferPostReply_t *mpi_reply;
+       int rc, i;
+       u8 buffer_type;
+       unsigned long timeleft;
+       u16 smid;
+       u16 ioc_status;
+       u8 issue_reset = 0;
+
+       if (copy_from_user(&karg, arg, sizeof(karg))) {
+               printk(KERN_ERR "failure at %s:%d/%s()!\n",
+                   __FILE__, __LINE__, __func__);
+               return -EFAULT;
+       }
+       if (_ctl_verify_adapter(karg.hdr.ioc_number, &ioc) == -1 || !ioc)
+               return -ENODEV;
+
+       dctlprintk(ioc, printk(MPT2SAS_DEBUG_FMT "%s\n", ioc->name,
+           __func__));
+
+       buffer_type = karg.unique_id & 0x000000ff;
+       if (!_ctl_diag_capability(ioc, buffer_type)) {
+               printk(MPT2SAS_ERR_FMT "%s: doesn't have capability for "
+                   "buffer_type(0x%02x)\n", ioc->name, __func__, buffer_type);
+               return -EPERM;
+       }
+
+       if (karg.unique_id != ioc->unique_id[buffer_type]) {
+               printk(MPT2SAS_ERR_FMT "%s: unique_id(0x%08x) is not "
+                   "registered\n", ioc->name, __func__, karg.unique_id);
+               return -EINVAL;
+       }
+
+       request_data = ioc->diag_buffer[buffer_type];
+       if (!request_data) {
+               printk(MPT2SAS_ERR_FMT "%s: doesn't have buffer for "
+                   "buffer_type(0x%02x)\n", ioc->name, __func__, buffer_type);
+               return -ENOMEM;
+       }
+
+       if ((karg.starting_offset % 4) || (karg.bytes_to_read % 4)) {
+               printk(MPT2SAS_ERR_FMT "%s: either the starting_offset "
+                   "or bytes_to_read are not 4 byte aligned\n", ioc->name,
+                   __func__);
+               return -EINVAL;
+       }
+
+       diag_data = (void *)(request_data + karg.starting_offset);
+       dctlprintk(ioc, printk(MPT2SAS_DEBUG_FMT "%s: diag_buffer(%p), "
+           "offset(%d), sz(%d)\n", ioc->name, __func__,
+           diag_data, karg.starting_offset, karg.bytes_to_read));
+
+       if (copy_to_user((void __user *)uarg->diagnostic_data,
+           diag_data, karg.bytes_to_read)) {
+               printk(MPT2SAS_ERR_FMT "%s: Unable to write "
+                   "mpt_diag_read_buffer_t data @ %p\n", ioc->name,
+                   __func__, diag_data);
+               return -EFAULT;
+       }
+
+       if ((karg.flags & MPT2_FLAGS_REREGISTER) == 0)
+               return 0;
+
+       dctlprintk(ioc, printk(MPT2SAS_DEBUG_FMT "%s: Reregister "
+               "buffer_type(0x%02x)\n", ioc->name, __func__, buffer_type));
+       if ((ioc->diag_buffer_status[buffer_type] &
+           MPT2_DIAG_BUFFER_IS_RELEASED) == 0) {
+               dctlprintk(ioc, printk(MPT2SAS_DEBUG_FMT "%s: "
+                   "buffer_type(0x%02x) is still registered\n", ioc->name,
+                    __func__, buffer_type));
+               return 0;
+       }
+       /* Get a free request frame and save the message context.
+       */
+       if (state == NON_BLOCKING && !mutex_trylock(&ioc->ctl_cmds.mutex))
+               return -EAGAIN;
+       else if (mutex_lock_interruptible(&ioc->ctl_cmds.mutex))
+               return -ERESTARTSYS;
+
+       if (ioc->ctl_cmds.status != MPT2_CMD_NOT_USED) {
+               printk(MPT2SAS_ERR_FMT "%s: ctl_cmd in use\n",
+                   ioc->name, __func__);
+               rc = -EAGAIN;
+               goto out;
+       }
+
+       smid = mpt2sas_base_get_smid(ioc, ioc->ctl_cb_idx);
+       if (!smid) {
+               printk(MPT2SAS_ERR_FMT "%s: failed obtaining a smid\n",
+                   ioc->name, __func__);
+               rc = -EAGAIN;
+               goto out;
+       }
+
+       rc = 0;
+       ioc->ctl_cmds.status = MPT2_CMD_PENDING;
+       memset(ioc->ctl_cmds.reply, 0, ioc->reply_sz);
+       mpi_request = mpt2sas_base_get_msg_frame(ioc, smid);
+       ioc->ctl_cmds.smid = smid;
+
+       mpi_request->Function = MPI2_FUNCTION_DIAG_BUFFER_POST;
+       mpi_request->BufferType = buffer_type;
+       mpi_request->BufferLength =
+           cpu_to_le32(ioc->diag_buffer_sz[buffer_type]);
+       mpi_request->BufferAddress =
+           cpu_to_le64(ioc->diag_buffer_dma[buffer_type]);
+       for (i = 0; i < MPT2_PRODUCT_SPECIFIC_DWORDS; i++)
+               mpi_request->ProductSpecific[i] =
+                       cpu_to_le32(ioc->product_specific[buffer_type][i]);
+
+       mpt2sas_base_put_smid_default(ioc, smid, mpi_request->VF_ID);
+       timeleft = wait_for_completion_timeout(&ioc->ctl_cmds.done,
+           MPT2_IOCTL_DEFAULT_TIMEOUT*HZ);
+
+       if (!(ioc->ctl_cmds.status & MPT2_CMD_COMPLETE)) {
+               printk(MPT2SAS_ERR_FMT "%s: timeout\n", ioc->name,
+                   __func__);
+               _debug_dump_mf(mpi_request,
+                   sizeof(Mpi2DiagBufferPostRequest_t)/4);
+               if (!(ioc->ctl_cmds.status & MPT2_CMD_RESET))
+                       issue_reset = 1;
+               goto issue_host_reset;
+       }
+
+       /* process the completed Reply Message Frame */
+       if ((ioc->ctl_cmds.status & MPT2_CMD_REPLY_VALID) == 0) {
+               printk(MPT2SAS_ERR_FMT "%s: no reply message\n",
+                   ioc->name, __func__);
+               rc = -EFAULT;
+               goto out;
+       }
+
+       mpi_reply = ioc->ctl_cmds.reply;
+       ioc_status = le16_to_cpu(mpi_reply->IOCStatus) & MPI2_IOCSTATUS_MASK;
+
+       if (ioc_status == MPI2_IOCSTATUS_SUCCESS) {
+               ioc->diag_buffer_status[buffer_type] |=
+                   MPT2_DIAG_BUFFER_IS_REGISTERED;
+               dctlprintk(ioc, printk(MPT2SAS_DEBUG_FMT "%s: success\n",
+                   ioc->name, __func__));
+       } else {
+               printk(MPT2SAS_DEBUG_FMT "%s: ioc_status(0x%04x) "
+                   "log_info(0x%08x)\n", ioc->name, __func__,
+                   ioc_status, mpi_reply->IOCLogInfo);
+               rc = -EFAULT;
+       }
+
+ issue_host_reset:
+       if (issue_reset)
+               mpt2sas_base_hard_reset_handler(ioc, CAN_SLEEP,
+                   FORCE_BIG_HAMMER);
+
+ out:
+
+       ioc->ctl_cmds.status = MPT2_CMD_NOT_USED;
+       mutex_unlock(&ioc->ctl_cmds.mutex);
+       return rc;
+}
+
+/**
+ * _ctl_ioctl_main - main ioctl entry point
+ * @file - (struct file)
+ * @cmd - ioctl opcode
+ * @arg -
+ */
+static long
+_ctl_ioctl_main(struct file *file, unsigned int cmd, void __user *arg)
+{
+       enum block_state state;
+       long ret = -EINVAL;
+       unsigned long flags;
+
+       state = (file->f_flags & O_NONBLOCK) ? NON_BLOCKING :
+           BLOCKING;
+
+       switch (cmd) {
+       case MPT2IOCINFO:
+               if (_IOC_SIZE(cmd) == sizeof(struct mpt2_ioctl_iocinfo))
+                       ret = _ctl_getiocinfo(arg);
+               break;
+       case MPT2COMMAND:
+       {
+               struct mpt2_ioctl_command karg;
+               struct mpt2_ioctl_command __user *uarg;
+               struct MPT2SAS_ADAPTER *ioc;
+
+               if (copy_from_user(&karg, arg, sizeof(karg))) {
+                       printk(KERN_ERR "failure at %s:%d/%s()!\n",
+                           __FILE__, __LINE__, __func__);
+                       return -EFAULT;
+               }
+
+               if (_ctl_verify_adapter(karg.hdr.ioc_number, &ioc) == -1 ||
+                   !ioc)
+                       return -ENODEV;
+
+               spin_lock_irqsave(&ioc->ioc_reset_in_progress_lock, flags);
+               if (ioc->shost_recovery) {
+                       spin_unlock_irqrestore(&ioc->ioc_reset_in_progress_lock,
+                           flags);
+                       return -EAGAIN;
+               }
+               spin_unlock_irqrestore(&ioc->ioc_reset_in_progress_lock, flags);
+
+               if (_IOC_SIZE(cmd) == sizeof(struct mpt2_ioctl_command)) {
+                       uarg = arg;
+                       ret = _ctl_do_mpt_command(ioc, karg, &uarg->mf, state);
+               }
+               break;
+       }
+       case MPT2EVENTQUERY:
+               if (_IOC_SIZE(cmd) == sizeof(struct mpt2_ioctl_eventquery))
+                       ret = _ctl_eventquery(arg);
+               break;
+       case MPT2EVENTENABLE:
+               if (_IOC_SIZE(cmd) == sizeof(struct mpt2_ioctl_eventenable))
+                       ret = _ctl_eventenable(arg);
+               break;
+       case MPT2EVENTREPORT:
+               ret = _ctl_eventreport(arg);
+               break;
+       case MPT2HARDRESET:
+               if (_IOC_SIZE(cmd) == sizeof(struct mpt2_ioctl_diag_reset))
+                       ret = _ctl_do_reset(arg);
+               break;
+       case MPT2BTDHMAPPING:
+               if (_IOC_SIZE(cmd) == sizeof(struct mpt2_ioctl_btdh_mapping))
+                       ret = _ctl_btdh_mapping(arg);
+               break;
+       case MPT2DIAGREGISTER:
+               if (_IOC_SIZE(cmd) == sizeof(struct mpt2_diag_register))
+                       ret = _ctl_diag_register(arg, state);
+               break;
+       case MPT2DIAGUNREGISTER:
+               if (_IOC_SIZE(cmd) == sizeof(struct mpt2_diag_unregister))
+                       ret = _ctl_diag_unregister(arg);
+               break;
+       case MPT2DIAGQUERY:
+               if (_IOC_SIZE(cmd) == sizeof(struct mpt2_diag_query))
+                       ret = _ctl_diag_query(arg);
+               break;
+       case MPT2DIAGRELEASE:
+               if (_IOC_SIZE(cmd) == sizeof(struct mpt2_diag_release))
+                       ret = _ctl_diag_release(arg, state);
+               break;
+       case MPT2DIAGREADBUFFER:
+               if (_IOC_SIZE(cmd) == sizeof(struct mpt2_diag_read_buffer))
+                       ret = _ctl_diag_read_buffer(arg, state);
+               break;
+       default:
+       {
+               struct mpt2_ioctl_command karg;
+               struct MPT2SAS_ADAPTER *ioc;
+
+               if (copy_from_user(&karg, arg, sizeof(karg))) {
+                       printk(KERN_ERR "failure at %s:%d/%s()!\n",
+                           __FILE__, __LINE__, __func__);
+                       return -EFAULT;
+               }
+
+               if (_ctl_verify_adapter(karg.hdr.ioc_number, &ioc) == -1 ||
+                   !ioc)
+                       return -ENODEV;
+
+               dctlprintk(ioc, printk(MPT2SAS_DEBUG_FMT
+                   "unsupported ioctl opcode(0x%08x)\n", ioc->name, cmd));
+               break;
+       }
+       }
+       return ret;
+}
+
+/**
+ * _ctl_ioctl - main ioctl entry point (unlocked)
+ * @file - (struct file)
+ * @cmd - ioctl opcode
+ * @arg -
+ */
+static long
+_ctl_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
+{
+       long ret;
+       lock_kernel();
+       ret = _ctl_ioctl_main(file, cmd, (void __user *)arg);
+       unlock_kernel();
+       return ret;
+}
+
+#ifdef CONFIG_COMPAT
+/**
+ * _ctl_compat_mpt_command - convert 32bit pointers to 64bit.
+ * @file - (struct file)
+ * @cmd - ioctl opcode
+ * @arg - (struct mpt2_ioctl_command32)
+ *
+ * MPT2COMMAND32 - Handle 32bit applications running on 64bit os.
+ */
+static long
+_ctl_compat_mpt_command(struct file *file, unsigned cmd, unsigned long arg)
+{
+       struct mpt2_ioctl_command32 karg32;
+       struct mpt2_ioctl_command32 __user *uarg;
+       struct mpt2_ioctl_command karg;
+       struct MPT2SAS_ADAPTER *ioc;
+       enum block_state state;
+       unsigned long flags;
+
+       if (_IOC_SIZE(cmd) != sizeof(struct mpt2_ioctl_command32))
+               return -EINVAL;
+
+       uarg = (struct mpt2_ioctl_command32 __user *) arg;
+
+       if (copy_from_user(&karg32, (char __user *)arg, sizeof(karg32))) {
+               printk(KERN_ERR "failure at %s:%d/%s()!\n",
+                   __FILE__, __LINE__, __func__);
+               return -EFAULT;
+       }
+       if (_ctl_verify_adapter(karg32.hdr.ioc_number, &ioc) == -1 || !ioc)
+               return -ENODEV;
+
+       spin_lock_irqsave(&ioc->ioc_reset_in_progress_lock, flags);
+       if (ioc->shost_recovery) {
+               spin_unlock_irqrestore(&ioc->ioc_reset_in_progress_lock,
+                   flags);
+               return -EAGAIN;
+       }
+       spin_unlock_irqrestore(&ioc->ioc_reset_in_progress_lock, flags);
+
+       memset(&karg, 0, sizeof(struct mpt2_ioctl_command));
+       karg.hdr.ioc_number = karg32.hdr.ioc_number;
+       karg.hdr.port_number = karg32.hdr.port_number;
+       karg.hdr.max_data_size = karg32.hdr.max_data_size;
+       karg.timeout = karg32.timeout;
+       karg.max_reply_bytes = karg32.max_reply_bytes;
+       karg.data_in_size = karg32.data_in_size;
+       karg.data_out_size = karg32.data_out_size;
+       karg.max_sense_bytes = karg32.max_sense_bytes;
+       karg.data_sge_offset = karg32.data_sge_offset;
+       memcpy(&karg.reply_frame_buf_ptr, &karg32.reply_frame_buf_ptr,
+           sizeof(uint32_t));
+       memcpy(&karg.data_in_buf_ptr, &karg32.data_in_buf_ptr,
+           sizeof(uint32_t));
+       memcpy(&karg.data_out_buf_ptr, &karg32.data_out_buf_ptr,
+           sizeof(uint32_t));
+       memcpy(&karg.sense_data_ptr, &karg32.sense_data_ptr,
+           sizeof(uint32_t));
+       state = (file->f_flags & O_NONBLOCK) ? NON_BLOCKING : BLOCKING;
+       return _ctl_do_mpt_command(ioc, karg, &uarg->mf, state);
+}
+
+/**
+ * _ctl_ioctl_compat - main ioctl entry point (compat)
+ * @file -
+ * @cmd -
+ * @arg -
+ *
+ * This routine handles 32 bit applications in 64bit os.
+ */
+static long
+_ctl_ioctl_compat(struct file *file, unsigned cmd, unsigned long arg)
+{
+       long ret;
+       lock_kernel();
+       if (cmd == MPT2COMMAND32)
+               ret = _ctl_compat_mpt_command(file, cmd, arg);
+       else
+               ret = _ctl_ioctl_main(file, cmd, (void __user *)arg);
+       unlock_kernel();
+       return ret;
+}
+#endif
+
+/* scsi host attributes */
+
+/**
+ * _ctl_version_fw_show - firmware version
+ * @cdev - pointer to embedded class device
+ * @buf - the buffer returned
+ *
+ * A sysfs 'read-only' shost attribute.
+ */
+static ssize_t
+_ctl_version_fw_show(struct device *cdev, struct device_attribute *attr,
+    char *buf)
+{
+       struct Scsi_Host *shost = class_to_shost(cdev);
+       struct MPT2SAS_ADAPTER *ioc = shost_priv(shost);
+
+       return snprintf(buf, PAGE_SIZE, "%02d.%02d.%02d.%02d\n",
+           (ioc->facts.FWVersion.Word & 0xFF000000) >> 24,
+           (ioc->facts.FWVersion.Word & 0x00FF0000) >> 16,
+           (ioc->facts.FWVersion.Word & 0x0000FF00) >> 8,
+           ioc->facts.FWVersion.Word & 0x000000FF);
+}
+static DEVICE_ATTR(version_fw, S_IRUGO, _ctl_version_fw_show, NULL);
+
+/**
+ * _ctl_version_bios_show - bios version
+ * @cdev - pointer to embedded class device
+ * @buf - the buffer returned
+ *
+ * A sysfs 'read-only' shost attribute.
+ */
+static ssize_t
+_ctl_version_bios_show(struct device *cdev, struct device_attribute *attr,
+    char *buf)
+{
+       struct Scsi_Host *shost = class_to_shost(cdev);
+       struct MPT2SAS_ADAPTER *ioc = shost_priv(shost);
+
+       u32 version = le32_to_cpu(ioc->bios_pg3.BiosVersion);
+
+       return snprintf(buf, PAGE_SIZE, "%02d.%02d.%02d.%02d\n",
+           (version & 0xFF000000) >> 24,
+           (version & 0x00FF0000) >> 16,
+           (version & 0x0000FF00) >> 8,
+           version & 0x000000FF);
+}
+static DEVICE_ATTR(version_bios, S_IRUGO, _ctl_version_bios_show, NULL);
+
+/**
+ * _ctl_version_mpi_show - MPI (message passing interface) version
+ * @cdev - pointer to embedded class device
+ * @buf - the buffer returned
+ *
+ * A sysfs 'read-only' shost attribute.
+ */
+static ssize_t
+_ctl_version_mpi_show(struct device *cdev, struct device_attribute *attr,
+    char *buf)
+{
+       struct Scsi_Host *shost = class_to_shost(cdev);
+       struct MPT2SAS_ADAPTER *ioc = shost_priv(shost);
+
+       return snprintf(buf, PAGE_SIZE, "%03x.%02x\n",
+           ioc->facts.MsgVersion, ioc->facts.HeaderVersion >> 8);
+}
+static DEVICE_ATTR(version_mpi, S_IRUGO, _ctl_version_mpi_show, NULL);
+
+/**
+ * _ctl_version_product_show - product name
+ * @cdev - pointer to embedded class device
+ * @buf - the buffer returned
+ *
+ * A sysfs 'read-only' shost attribute.
+ */
+static ssize_t
+_ctl_version_product_show(struct device *cdev, struct device_attribute *attr,
+    char *buf)
+{
+       struct Scsi_Host *shost = class_to_shost(cdev);
+       struct MPT2SAS_ADAPTER *ioc = shost_priv(shost);
+
+       return snprintf(buf, 16, "%s\n", ioc->manu_pg0.ChipName);
+}
+static DEVICE_ATTR(version_product, S_IRUGO,
+   _ctl_version_product_show, NULL);
+
+/**
+ * _ctl_version_nvdata_persistent_show - ndvata persistent version
+ * @cdev - pointer to embedded class device
+ * @buf - the buffer returned
+ *
+ * A sysfs 'read-only' shost attribute.
+ */
+static ssize_t
+_ctl_version_nvdata_persistent_show(struct device *cdev,
+    struct device_attribute *attr, char *buf)
+{
+       struct Scsi_Host *shost = class_to_shost(cdev);
+       struct MPT2SAS_ADAPTER *ioc = shost_priv(shost);
+
+       return snprintf(buf, PAGE_SIZE, "%02xh\n",
+           le16_to_cpu(ioc->iounit_pg0.NvdataVersionPersistent.Word));
+}
+static DEVICE_ATTR(version_nvdata_persistent, S_IRUGO,
+    _ctl_version_nvdata_persistent_show, NULL);
+
+/**
+ * _ctl_version_nvdata_default_show - nvdata default version
+ * @cdev - pointer to embedded class device
+ * @buf - the buffer returned
+ *
+ * A sysfs 'read-only' shost attribute.
+ */
+static ssize_t
+_ctl_version_nvdata_default_show(struct device *cdev,
+    struct device_attribute *attr, char *buf)
+{
+       struct Scsi_Host *shost = class_to_shost(cdev);
+       struct MPT2SAS_ADAPTER *ioc = shost_priv(shost);
+
+       return snprintf(buf, PAGE_SIZE, "%02xh\n",
+           le16_to_cpu(ioc->iounit_pg0.NvdataVersionDefault.Word));
+}
+static DEVICE_ATTR(version_nvdata_default, S_IRUGO,
+    _ctl_version_nvdata_default_show, NULL);
+
+/**
+ * _ctl_board_name_show - board name
+ * @cdev - pointer to embedded class device
+ * @buf - the buffer returned
+ *
+ * A sysfs 'read-only' shost attribute.
+ */
+static ssize_t
+_ctl_board_name_show(struct device *cdev, struct device_attribute *attr,
+    char *buf)
+{
+       struct Scsi_Host *shost = class_to_shost(cdev);
+       struct MPT2SAS_ADAPTER *ioc = shost_priv(shost);
+
+       return snprintf(buf, 16, "%s\n", ioc->manu_pg0.BoardName);
+}
+static DEVICE_ATTR(board_name, S_IRUGO, _ctl_board_name_show, NULL);
+
+/**
+ * _ctl_board_assembly_show - board assembly name
+ * @cdev - pointer to embedded class device
+ * @buf - the buffer returned
+ *
+ * A sysfs 'read-only' shost attribute.
+ */
+static ssize_t
+_ctl_board_assembly_show(struct device *cdev, struct device_attribute *attr,
+    char *buf)
+{
+       struct Scsi_Host *shost = class_to_shost(cdev);
+       struct MPT2SAS_ADAPTER *ioc = shost_priv(shost);
+
+       return snprintf(buf, 16, "%s\n", ioc->manu_pg0.BoardAssembly);
+}
+static DEVICE_ATTR(board_assembly, S_IRUGO,
+    _ctl_board_assembly_show, NULL);
+
+/**
+ * _ctl_board_tracer_show - board tracer number
+ * @cdev - pointer to embedded class device
+ * @buf - the buffer returned
+ *
+ * A sysfs 'read-only' shost attribute.
+ */
+static ssize_t
+_ctl_board_tracer_show(struct device *cdev, struct device_attribute *attr,
+    char *buf)
+{
+       struct Scsi_Host *shost = class_to_shost(cdev);
+       struct MPT2SAS_ADAPTER *ioc = shost_priv(shost);
+
+       return snprintf(buf, 16, "%s\n", ioc->manu_pg0.BoardTracerNumber);
+}
+static DEVICE_ATTR(board_tracer, S_IRUGO,
+    _ctl_board_tracer_show, NULL);
+
+/**
+ * _ctl_io_delay_show - io missing delay
+ * @cdev - pointer to embedded class device
+ * @buf - the buffer returned
+ *
+ * This is for firmware implemention for deboucing device
+ * removal events.
+ *
+ * A sysfs 'read-only' shost attribute.
+ */
+static ssize_t
+_ctl_io_delay_show(struct device *cdev, struct device_attribute *attr,
+    char *buf)
+{
+       struct Scsi_Host *shost = class_to_shost(cdev);
+       struct MPT2SAS_ADAPTER *ioc = shost_priv(shost);
+
+       return snprintf(buf, PAGE_SIZE, "%02d\n", ioc->io_missing_delay);
+}
+static DEVICE_ATTR(io_delay, S_IRUGO,
+    _ctl_io_delay_show, NULL);
+
+/**
+ * _ctl_device_delay_show - device missing delay
+ * @cdev - pointer to embedded class device
+ * @buf - the buffer returned
+ *
+ * This is for firmware implemention for deboucing device
+ * removal events.
+ *
+ * A sysfs 'read-only' shost attribute.
+ */
+static ssize_t
+_ctl_device_delay_show(struct device *cdev, struct device_attribute *attr,
+    char *buf)
+{
+       struct Scsi_Host *shost = class_to_shost(cdev);
+       struct MPT2SAS_ADAPTER *ioc = shost_priv(shost);
+
+       return snprintf(buf, PAGE_SIZE, "%02d\n", ioc->device_missing_delay);
+}
+static DEVICE_ATTR(device_delay, S_IRUGO,
+    _ctl_device_delay_show, NULL);
+
+/**
+ * _ctl_fw_queue_depth_show - global credits
+ * @cdev - pointer to embedded class device
+ * @buf - the buffer returned
+ *
+ * This is firmware queue depth limit
+ *
+ * A sysfs 'read-only' shost attribute.
+ */
+static ssize_t
+_ctl_fw_queue_depth_show(struct device *cdev, struct device_attribute *attr,
+    char *buf)
+{
+       struct Scsi_Host *shost = class_to_shost(cdev);
+       struct MPT2SAS_ADAPTER *ioc = shost_priv(shost);
+
+       return snprintf(buf, PAGE_SIZE, "%02d\n", ioc->facts.RequestCredit);
+}
+static DEVICE_ATTR(fw_queue_depth, S_IRUGO,
+    _ctl_fw_queue_depth_show, NULL);
+
+/**
+ * _ctl_sas_address_show - sas address
+ * @cdev - pointer to embedded class device
+ * @buf - the buffer returned
+ *
+ * This is the controller sas address
+ *
+ * A sysfs 'read-only' shost attribute.
+ */
+static ssize_t
+_ctl_host_sas_address_show(struct device *cdev, struct device_attribute *attr,
+    char *buf)
+{
+       struct Scsi_Host *shost = class_to_shost(cdev);
+       struct MPT2SAS_ADAPTER *ioc = shost_priv(shost);
+
+       return snprintf(buf, PAGE_SIZE, "0x%016llx\n",
+           (unsigned long long)ioc->sas_hba.sas_address);
+}
+static DEVICE_ATTR(host_sas_address, S_IRUGO,
+    _ctl_host_sas_address_show, NULL);
+
+/**
+ * _ctl_logging_level_show - logging level
+ * @cdev - pointer to embedded class device
+ * @buf - the buffer returned
+ *
+ * A sysfs 'read/write' shost attribute.
+ */
+static ssize_t
+_ctl_logging_level_show(struct device *cdev, struct device_attribute *attr,
+    char *buf)
+{
+       struct Scsi_Host *shost = class_to_shost(cdev);
+       struct MPT2SAS_ADAPTER *ioc = shost_priv(shost);
+
+       return snprintf(buf, PAGE_SIZE, "%08xh\n", ioc->logging_level);
+}
+static ssize_t
+_ctl_logging_level_store(struct device *cdev, struct device_attribute *attr,
+    const char *buf, size_t count)
+{
+       struct Scsi_Host *shost = class_to_shost(cdev);
+       struct MPT2SAS_ADAPTER *ioc = shost_priv(shost);
+       int val = 0;
+
+       if (sscanf(buf, "%x", &val) != 1)
+               return -EINVAL;
+
+       ioc->logging_level = val;
+       printk(MPT2SAS_INFO_FMT "logging_level=%08xh\n", ioc->name,
+           ioc->logging_level);
+       return strlen(buf);
+}
+static DEVICE_ATTR(logging_level, S_IRUGO | S_IWUSR,
+    _ctl_logging_level_show, _ctl_logging_level_store);
+
+struct device_attribute *mpt2sas_host_attrs[] = {
+       &dev_attr_version_fw,
+       &dev_attr_version_bios,
+       &dev_attr_version_mpi,
+       &dev_attr_version_product,
+       &dev_attr_version_nvdata_persistent,
+       &dev_attr_version_nvdata_default,
+       &dev_attr_board_name,
+       &dev_attr_board_assembly,
+       &dev_attr_board_tracer,
+       &dev_attr_io_delay,
+       &dev_attr_device_delay,
+       &dev_attr_logging_level,
+       &dev_attr_fw_queue_depth,
+       &dev_attr_host_sas_address,
+       NULL,
+};
+
+/* device attributes */
+
+/**
+ * _ctl_device_sas_address_show - sas address
+ * @cdev - pointer to embedded class device
+ * @buf - the buffer returned
+ *
+ * This is the sas address for the target
+ *
+ * A sysfs 'read-only' shost attribute.
+ */
+static ssize_t
+_ctl_device_sas_address_show(struct device *dev, struct device_attribute *attr,
+    char *buf)
+{
+       struct scsi_device *sdev = to_scsi_device(dev);
+       struct MPT2SAS_DEVICE *sas_device_priv_data = sdev->hostdata;
+
+       return snprintf(buf, PAGE_SIZE, "0x%016llx\n",
+           (unsigned long long)sas_device_priv_data->sas_target->sas_address);
+}
+static DEVICE_ATTR(sas_address, S_IRUGO, _ctl_device_sas_address_show, NULL);
+
+/**
+ * _ctl_device_handle_show - device handle
+ * @cdev - pointer to embedded class device
+ * @buf - the buffer returned
+ *
+ * This is the firmware assigned device handle
+ *
+ * A sysfs 'read-only' shost attribute.
+ */
+static ssize_t
+_ctl_device_handle_show(struct device *dev, struct device_attribute *attr,
+    char *buf)
+{
+       struct scsi_device *sdev = to_scsi_device(dev);
+       struct MPT2SAS_DEVICE *sas_device_priv_data = sdev->hostdata;
+
+       return snprintf(buf, PAGE_SIZE, "0x%04x\n",
+           sas_device_priv_data->sas_target->handle);
+}
+static DEVICE_ATTR(sas_device_handle, S_IRUGO, _ctl_device_handle_show, NULL);
+
+struct device_attribute *mpt2sas_dev_attrs[] = {
+       &dev_attr_sas_address,
+       &dev_attr_sas_device_handle,
+       NULL,
+};
+
+static const struct file_operations ctl_fops = {
+       .owner = THIS_MODULE,
+       .unlocked_ioctl = _ctl_ioctl,
+       .release = _ctl_release,
+       .poll = _ctl_poll,
+       .fasync = _ctl_fasync,
+#ifdef CONFIG_COMPAT
+       .compat_ioctl = _ctl_ioctl_compat,
+#endif
+};
+
+static struct miscdevice ctl_dev = {
+       .minor  = MPT2SAS_MINOR,
+       .name   = MPT2SAS_DEV_NAME,
+       .fops   = &ctl_fops,
+};
+
+/**
+ * mpt2sas_ctl_init - main entry point for ctl.
+ *
+ */
+void
+mpt2sas_ctl_init(void)
+{
+       async_queue = NULL;
+       if (misc_register(&ctl_dev) < 0)
+               printk(KERN_ERR "%s can't register misc device [minor=%d]\n",
+                   MPT2SAS_DRIVER_NAME, MPT2SAS_MINOR);
+
+       init_waitqueue_head(&ctl_poll_wait);
+}
+
+/**
+ * mpt2sas_ctl_exit - exit point for ctl
+ *
+ */
+void
+mpt2sas_ctl_exit(void)
+{
+       struct MPT2SAS_ADAPTER *ioc;
+       int i;
+
+       list_for_each_entry(ioc, &ioc_list, list) {
+
+               /* free memory associated to diag buffers */
+               for (i = 0; i < MPI2_DIAG_BUF_TYPE_COUNT; i++) {
+                       if (!ioc->diag_buffer[i])
+                               continue;
+                       pci_free_consistent(ioc->pdev, ioc->diag_buffer_sz[i],
+                           ioc->diag_buffer[i], ioc->diag_buffer_dma[i]);
+                       ioc->diag_buffer[i] = NULL;
+                       ioc->diag_buffer_status[i] = 0;
+               }
+
+               kfree(ioc->event_log);
+       }
+       misc_deregister(&ctl_dev);
+}
+
diff --git a/drivers/scsi/mpt2sas/mpt2sas_ctl.h b/drivers/scsi/mpt2sas/mpt2sas_ctl.h
new file mode 100644 (file)
index 0000000..dbb6c0c
--- /dev/null
@@ -0,0 +1,416 @@
+/*
+ * Management Module Support for MPT (Message Passing Technology) based
+ * controllers
+ *
+ * This code is based on drivers/scsi/mpt2sas/mpt2_ctl.h
+ * Copyright (C) 2007-2008  LSI Corporation
+ *  (mailto:DL-MPTFusionLinux@lsi.com)
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * NO WARRANTY
+ * THE PROGRAM IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OR
+ * CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED INCLUDING, WITHOUT
+ * LIMITATION, ANY WARRANTIES OR CONDITIONS OF TITLE, NON-INFRINGEMENT,
+ * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. Each Recipient is
+ * solely responsible for determining the appropriateness of using and
+ * distributing the Program and assumes all risks associated with its
+ * exercise of rights under this Agreement, including but not limited to
+ * the risks and costs of program errors, damage to or loss of data,
+ * programs or equipment, and unavailability or interruption of operations.
+
+ * DISCLAIMER OF LIABILITY
+ * NEITHER RECIPIENT NOR ANY CONTRIBUTORS SHALL HAVE ANY LIABILITY FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING WITHOUT LIMITATION LOST PROFITS), 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 OR DISTRIBUTION OF THE PROGRAM OR THE EXERCISE OF ANY RIGHTS GRANTED
+ * HEREUNDER, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGES
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301,
+ * USA.
+ */
+
+#ifndef MPT2SAS_CTL_H_INCLUDED
+#define MPT2SAS_CTL_H_INCLUDED
+
+#ifdef __KERNEL__
+#include <linux/miscdevice.h>
+#endif
+
+#define MPT2SAS_DEV_NAME       "mpt2ctl"
+#define MPT2_MAGIC_NUMBER      'm'
+#define MPT2_IOCTL_DEFAULT_TIMEOUT (10) /* in seconds */
+
+/**
+ * IOCTL opcodes
+ */
+#define MPT2IOCINFO    _IOWR(MPT2_MAGIC_NUMBER, 17, \
+    struct mpt2_ioctl_iocinfo)
+#define MPT2COMMAND    _IOWR(MPT2_MAGIC_NUMBER, 20, \
+    struct mpt2_ioctl_command)
+#ifdef CONFIG_COMPAT
+#define MPT2COMMAND32  _IOWR(MPT2_MAGIC_NUMBER, 20, \
+    struct mpt2_ioctl_command32)
+#endif
+#define MPT2EVENTQUERY _IOWR(MPT2_MAGIC_NUMBER, 21, \
+    struct mpt2_ioctl_eventquery)
+#define MPT2EVENTENABLE        _IOWR(MPT2_MAGIC_NUMBER, 22, \
+    struct mpt2_ioctl_eventenable)
+#define MPT2EVENTREPORT        _IOWR(MPT2_MAGIC_NUMBER, 23, \
+    struct mpt2_ioctl_eventreport)
+#define MPT2HARDRESET  _IOWR(MPT2_MAGIC_NUMBER, 24, \
+    struct mpt2_ioctl_diag_reset)
+#define MPT2BTDHMAPPING        _IOWR(MPT2_MAGIC_NUMBER, 31, \
+    struct mpt2_ioctl_btdh_mapping)
+
+/* diag buffer support */
+#define MPT2DIAGREGISTER _IOWR(MPT2_MAGIC_NUMBER, 26, \
+    struct mpt2_diag_register)
+#define MPT2DIAGRELEASE        _IOWR(MPT2_MAGIC_NUMBER, 27, \
+    struct mpt2_diag_release)
+#define MPT2DIAGUNREGISTER _IOWR(MPT2_MAGIC_NUMBER, 28, \
+    struct mpt2_diag_unregister)
+#define MPT2DIAGQUERY  _IOWR(MPT2_MAGIC_NUMBER, 29, \
+    struct mpt2_diag_query)
+#define MPT2DIAGREADBUFFER _IOWR(MPT2_MAGIC_NUMBER, 30, \
+    struct mpt2_diag_read_buffer)
+
+/**
+ * struct mpt2_ioctl_header - main header structure
+ * @ioc_number -  IOC unit number
+ * @port_number - IOC port number
+ * @max_data_size - maximum number bytes to transfer on read
+ */
+struct mpt2_ioctl_header {
+       uint32_t ioc_number;
+       uint32_t port_number;
+       uint32_t max_data_size;
+};
+
+/**
+ * struct mpt2_ioctl_diag_reset - diagnostic reset
+ * @hdr - generic header
+ */
+struct mpt2_ioctl_diag_reset {
+       struct mpt2_ioctl_header hdr;
+};
+
+
+/**
+ * struct mpt2_ioctl_pci_info - pci device info
+ * @device - pci device id
+ * @function - pci function id
+ * @bus - pci bus id
+ * @segment_id - pci segment id
+ */
+struct mpt2_ioctl_pci_info {
+       union {
+               struct {
+                       uint32_t device:5;
+                       uint32_t function:3;
+                       uint32_t bus:24;
+               } bits;
+               uint32_t  word;
+       } u;
+       uint32_t segment_id;
+};
+
+
+#define MPT2_IOCTL_INTERFACE_SCSI      (0x00)
+#define MPT2_IOCTL_INTERFACE_FC                (0x01)
+#define MPT2_IOCTL_INTERFACE_FC_IP     (0x02)
+#define MPT2_IOCTL_INTERFACE_SAS       (0x03)
+#define MPT2_IOCTL_INTERFACE_SAS2      (0x04)
+#define MPT2_IOCTL_VERSION_LENGTH      (32)
+
+/**
+ * struct mpt2_ioctl_iocinfo - generic controller info
+ * @hdr - generic header
+ * @adapter_type - type of adapter (spi, fc, sas)
+ * @port_number - port number
+ * @pci_id - PCI Id
+ * @hw_rev - hardware revision
+ * @sub_system_device - PCI subsystem Device ID
+ * @sub_system_vendor - PCI subsystem Vendor ID
+ * @rsvd0 - reserved
+ * @firmware_version - firmware version
+ * @bios_version - BIOS version
+ * @driver_version - driver version - 32 ASCII characters
+ * @rsvd1 - reserved
+ * @scsi_id - scsi id of adapter 0
+ * @rsvd2 - reserved
+ * @pci_information - pci info (2nd revision)
+ */
+struct mpt2_ioctl_iocinfo {
+       struct mpt2_ioctl_header hdr;
+       uint32_t adapter_type;
+       uint32_t port_number;
+       uint32_t pci_id;
+       uint32_t hw_rev;
+       uint32_t subsystem_device;
+       uint32_t subsystem_vendor;
+       uint32_t rsvd0;
+       uint32_t firmware_version;
+       uint32_t bios_version;
+       uint8_t driver_version[MPT2_IOCTL_VERSION_LENGTH];
+       uint8_t rsvd1;
+       uint8_t scsi_id;
+       uint16_t rsvd2;
+       struct mpt2_ioctl_pci_info pci_information;
+};
+
+
+/* number of event log entries */
+#define MPT2SAS_CTL_EVENT_LOG_SIZE (50)
+
+/**
+ * struct mpt2_ioctl_eventquery - query event count and type
+ * @hdr - generic header
+ * @event_entries - number of events returned by get_event_report
+ * @rsvd - reserved
+ * @event_types - type of events currently being captured
+ */
+struct mpt2_ioctl_eventquery {
+       struct mpt2_ioctl_header hdr;
+       uint16_t event_entries;
+       uint16_t rsvd;
+       uint32_t event_types[MPI2_EVENT_NOTIFY_EVENTMASK_WORDS];
+};
+
+/**
+ * struct mpt2_ioctl_eventenable - enable/disable event capturing
+ * @hdr - generic header
+ * @event_types - toggle off/on type of events to be captured
+ */
+struct mpt2_ioctl_eventenable {
+       struct mpt2_ioctl_header hdr;
+       uint32_t event_types[4];
+};
+
+#define MPT2_EVENT_DATA_SIZE (192)
+/**
+ * struct MPT2_IOCTL_EVENTS -
+ * @event - the event that was reported
+ * @context - unique value for each event assigned by driver
+ * @data - event data returned in fw reply message
+ */
+struct MPT2_IOCTL_EVENTS {
+       uint32_t event;
+       uint32_t context;
+       uint8_t data[MPT2_EVENT_DATA_SIZE];
+};
+
+/**
+ * struct mpt2_ioctl_eventreport - returing event log
+ * @hdr - generic header
+ * @event_data - (see struct MPT2_IOCTL_EVENTS)
+ */
+struct mpt2_ioctl_eventreport {
+       struct mpt2_ioctl_header hdr;
+       struct MPT2_IOCTL_EVENTS event_data[1];
+};
+
+/**
+ * struct mpt2_ioctl_command - generic mpt firmware passthru ioclt
+ * @hdr - generic header
+ * @timeout - command timeout in seconds. (if zero then use driver default
+ *  value).
+ * @reply_frame_buf_ptr - reply location
+ * @data_in_buf_ptr - destination for read
+ * @data_out_buf_ptr - data source for write
+ * @sense_data_ptr - sense data location
+ * @max_reply_bytes - maximum number of reply bytes to be sent to app.
+ * @data_in_size - number bytes for data transfer in (read)
+ * @data_out_size - number bytes for data transfer out (write)
+ * @max_sense_bytes - maximum number of bytes for auto sense buffers
+ * @data_sge_offset - offset in words from the start of the request message to
+ * the first SGL
+ * @mf[1];
+ */
+struct mpt2_ioctl_command {
+       struct mpt2_ioctl_header hdr;
+       uint32_t timeout;
+       void __user *reply_frame_buf_ptr;
+       void __user *data_in_buf_ptr;
+       void __user *data_out_buf_ptr;
+       void __user *sense_data_ptr;
+       uint32_t max_reply_bytes;
+       uint32_t data_in_size;
+       uint32_t data_out_size;
+       uint32_t max_sense_bytes;
+       uint32_t data_sge_offset;
+       uint8_t mf[1];
+};
+
+#ifdef CONFIG_COMPAT
+struct mpt2_ioctl_command32 {
+       struct mpt2_ioctl_header hdr;
+       uint32_t timeout;
+       uint32_t reply_frame_buf_ptr;
+       uint32_t data_in_buf_ptr;
+       uint32_t data_out_buf_ptr;
+       uint32_t sense_data_ptr;
+       uint32_t max_reply_bytes;
+       uint32_t data_in_size;
+       uint32_t data_out_size;
+       uint32_t max_sense_bytes;
+       uint32_t data_sge_offset;
+       uint8_t mf[1];
+};
+#endif
+
+/**
+ * struct mpt2_ioctl_btdh_mapping - mapping info
+ * @hdr - generic header
+ * @id - target device identification number
+ * @bus - SCSI bus number that the target device exists on
+ * @handle - device handle for the target device
+ * @rsvd - reserved
+ *
+ * To obtain a bus/id the application sets
+ * handle to valid handle, and bus/id to 0xFFFF.
+ *
+ * To obtain the device handle the application sets
+ * bus/id valid value, and the handle to 0xFFFF.
+ */
+struct mpt2_ioctl_btdh_mapping {
+       struct mpt2_ioctl_header hdr;
+       uint32_t id;
+       uint32_t bus;
+       uint16_t handle;
+       uint16_t rsvd;
+};
+
+
+/* status bits for ioc->diag_buffer_status */
+#define MPT2_DIAG_BUFFER_IS_REGISTERED         (0x01)
+#define MPT2_DIAG_BUFFER_IS_RELEASED   (0x02)
+
+/* application flags for mpt2_diag_register, mpt2_diag_query */
+#define MPT2_APP_FLAGS_APP_OWNED       (0x0001)
+#define MPT2_APP_FLAGS_BUFFER_VALID    (0x0002)
+#define MPT2_APP_FLAGS_FW_BUFFER_ACCESS        (0x0004)
+
+/* flags for mpt2_diag_read_buffer */
+#define MPT2_FLAGS_REREGISTER          (0x0001)
+
+#define MPT2_PRODUCT_SPECIFIC_DWORDS           23
+
+/**
+ * struct mpt2_diag_register - application register with driver
+ * @hdr - generic header
+ * @reserved -
+ * @buffer_type - specifies either TRACE or SNAPSHOT
+ * @application_flags - misc flags
+ * @diagnostic_flags - specifies flags affecting command processing
+ * @product_specific - product specific information
+ * @requested_buffer_size - buffers size in bytes
+ * @unique_id - tag specified by application that is used to signal ownership
+ *  of the buffer.
+ *
+ * This will allow the driver to setup any required buffers that will be
+ * needed by firmware to communicate with the driver.
+ */
+struct mpt2_diag_register {
+       struct mpt2_ioctl_header hdr;
+       uint8_t reserved;
+       uint8_t buffer_type;
+       uint16_t application_flags;
+       uint32_t diagnostic_flags;
+       uint32_t product_specific[MPT2_PRODUCT_SPECIFIC_DWORDS];
+       uint32_t requested_buffer_size;
+       uint32_t unique_id;
+};
+
+/**
+ * struct mpt2_diag_unregister - application unregister with driver
+ * @hdr - generic header
+ * @unique_id - tag uniquely identifies the buffer to be unregistered
+ *
+ * This will allow the driver to cleanup any memory allocated for diag
+ * messages and to free up any resources.
+ */
+struct mpt2_diag_unregister {
+       struct mpt2_ioctl_header hdr;
+       uint32_t unique_id;
+};
+
+/**
+ * struct mpt2_diag_query - query relevant info associated with diag buffers
+ * @hdr - generic header
+ * @reserved -
+ * @buffer_type - specifies either TRACE or SNAPSHOT
+ * @application_flags - misc flags
+ * @diagnostic_flags - specifies flags affecting command processing
+ * @product_specific - product specific information
+ * @total_buffer_size - diag buffer size in bytes
+ * @driver_added_buffer_size - size of extra space appended to end of buffer
+ * @unique_id - unique id associated with this buffer.
+ *
+ * The application will send only buffer_type and unique_id.  Driver will
+ * inspect unique_id first, if valid, fill in all the info.  If unique_id is
+ * 0x00, the driver will return info specified by Buffer Type.
+ */
+struct mpt2_diag_query {
+       struct mpt2_ioctl_header hdr;
+       uint8_t reserved;
+       uint8_t buffer_type;
+       uint16_t application_flags;
+       uint32_t diagnostic_flags;
+       uint32_t product_specific[MPT2_PRODUCT_SPECIFIC_DWORDS];
+       uint32_t total_buffer_size;
+       uint32_t driver_added_buffer_size;
+       uint32_t unique_id;
+};
+
+/**
+ * struct mpt2_diag_release -  request to send Diag Release Message to firmware
+ * @hdr - generic header
+ * @unique_id - tag uniquely identifies the buffer to be released
+ *
+ * This allows ownership of the specified buffer to returned to the driver,
+ * allowing an application to read the buffer without fear that firmware is
+ * overwritting information in the buffer.
+ */
+struct mpt2_diag_release {
+       struct mpt2_ioctl_header hdr;
+       uint32_t unique_id;
+};
+
+/**
+ * struct mpt2_diag_read_buffer - request for copy of the diag buffer
+ * @hdr - generic header
+ * @status -
+ * @reserved -
+ * @flags - misc flags
+ * @starting_offset - starting offset within drivers buffer where to start
+ *  reading data at into the specified application buffer
+ * @bytes_to_read - number of bytes to copy from the drivers buffer into the
+ *  application buffer starting at starting_offset.
+ * @unique_id - unique id associated with this buffer.
+ * @diagnostic_data - data payload
+ */
+struct mpt2_diag_read_buffer {
+       struct mpt2_ioctl_header hdr;
+       uint8_t status;
+       uint8_t reserved;
+       uint16_t flags;
+       uint32_t starting_offset;
+       uint32_t bytes_to_read;
+       uint32_t unique_id;
+       uint32_t diagnostic_data[1];
+};
+
+#endif /* MPT2SAS_CTL_H_INCLUDED */
diff --git a/drivers/scsi/mpt2sas/mpt2sas_debug.h b/drivers/scsi/mpt2sas/mpt2sas_debug.h
new file mode 100644 (file)
index 0000000..ad32509
--- /dev/null
@@ -0,0 +1,181 @@
+/*
+ * Logging Support for MPT (Message Passing Technology) based controllers
+ *
+ * This code is based on drivers/scsi/mpt2sas/mpt2_debug.c
+ * Copyright (C) 2007-2008  LSI Corporation
+ *  (mailto:DL-MPTFusionLinux@lsi.com)
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * NO WARRANTY
+ * THE PROGRAM IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OR
+ * CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED INCLUDING, WITHOUT
+ * LIMITATION, ANY WARRANTIES OR CONDITIONS OF TITLE, NON-INFRINGEMENT,
+ * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. Each Recipient is
+ * solely responsible for determining the appropriateness of using and
+ * distributing the Program and assumes all risks associated with its
+ * exercise of rights under this Agreement, including but not limited to
+ * the risks and costs of program errors, damage to or loss of data,
+ * programs or equipment, and unavailability or interruption of operations.
+
+ * DISCLAIMER OF LIABILITY
+ * NEITHER RECIPIENT NOR ANY CONTRIBUTORS SHALL HAVE ANY LIABILITY FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING WITHOUT LIMITATION LOST PROFITS), 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 OR DISTRIBUTION OF THE PROGRAM OR THE EXERCISE OF ANY RIGHTS GRANTED
+ * HEREUNDER, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGES
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301,
+ * USA.
+ */
+
+#ifndef MPT2SAS_DEBUG_H_INCLUDED
+#define MPT2SAS_DEBUG_H_INCLUDED
+
+#define MPT_DEBUG                      0x00000001
+#define MPT_DEBUG_MSG_FRAME            0x00000002
+#define MPT_DEBUG_SG                   0x00000004
+#define MPT_DEBUG_EVENTS               0x00000008
+#define MPT_DEBUG_EVENT_WORK_TASK      0x00000010
+#define MPT_DEBUG_INIT                 0x00000020
+#define MPT_DEBUG_EXIT                 0x00000040
+#define MPT_DEBUG_FAIL                 0x00000080
+#define MPT_DEBUG_TM                   0x00000100
+#define MPT_DEBUG_REPLY                        0x00000200
+#define MPT_DEBUG_HANDSHAKE            0x00000400
+#define MPT_DEBUG_CONFIG               0x00000800
+#define MPT_DEBUG_DL                   0x00001000
+#define MPT_DEBUG_RESET                        0x00002000
+#define MPT_DEBUG_SCSI                 0x00004000
+#define MPT_DEBUG_IOCTL                        0x00008000
+#define MPT_DEBUG_CSMISAS              0x00010000
+#define MPT_DEBUG_SAS                  0x00020000
+#define MPT_DEBUG_TRANSPORT            0x00040000
+#define MPT_DEBUG_TASK_SET_FULL                0x00080000
+
+#define MPT_DEBUG_TARGET_MODE          0x00100000
+
+
+/*
+ * CONFIG_SCSI_MPT2SAS_LOGGING - enabled in Kconfig
+ */
+
+#ifdef CONFIG_SCSI_MPT2SAS_LOGGING
+#define MPT_CHECK_LOGGING(IOC, CMD, BITS)                      \
+{                                                              \
+       if (IOC->logging_level & BITS)                          \
+               CMD;                                            \
+}
+#else
+#define MPT_CHECK_LOGGING(IOC, CMD, BITS)
+#endif /* CONFIG_SCSI_MPT2SAS_LOGGING */
+
+
+/*
+ * debug macros
+ */
+
+#define dprintk(IOC, CMD)                      \
+       MPT_CHECK_LOGGING(IOC, CMD, MPT_DEBUG)
+
+#define dsgprintk(IOC, CMD)                    \
+       MPT_CHECK_LOGGING(IOC, CMD, MPT_DEBUG_SG)
+
+#define devtprintk(IOC, CMD)                   \
+       MPT_CHECK_LOGGING(IOC, CMD, MPT_DEBUG_EVENTS)
+
+#define dewtprintk(IOC, CMD)           \
+       MPT_CHECK_LOGGING(IOC, CMD, MPT_DEBUG_EVENT_WORK_TASK)
+
+#define dinitprintk(IOC, CMD)                  \
+       MPT_CHECK_LOGGING(IOC, CMD, MPT_DEBUG_INIT)
+
+#define dexitprintk(IOC, CMD)                  \
+       MPT_CHECK_LOGGING(IOC, CMD, MPT_DEBUG_EXIT)
+
+#define dfailprintk(IOC, CMD)                  \
+       MPT_CHECK_LOGGING(IOC, CMD, MPT_DEBUG_FAIL)
+
+#define dtmprintk(IOC, CMD)                    \
+       MPT_CHECK_LOGGING(IOC, CMD, MPT_DEBUG_TM)
+
+#define dreplyprintk(IOC, CMD)                 \
+       MPT_CHECK_LOGGING(IOC, CMD, MPT_DEBUG_REPLY)
+
+#define dhsprintk(IOC, CMD)                    \
+       MPT_CHECK_LOGGING(IOC, CMD, MPT_DEBUG_HANDSHAKE)
+
+#define dcprintk(IOC, CMD)                     \
+       MPT_CHECK_LOGGING(IOC, CMD, MPT_DEBUG_CONFIG)
+
+#define ddlprintk(IOC, CMD)                    \
+       MPT_CHECK_LOGGING(IOC, CMD, MPT_DEBUG_DL)
+
+#define drsprintk(IOC, CMD)                    \
+       MPT_CHECK_LOGGING(IOC, CMD, MPT_DEBUG_RESET)
+
+#define dsprintk(IOC, CMD)                     \
+       MPT_CHECK_LOGGING(IOC, CMD, MPT_DEBUG_SCSI)
+
+#define dctlprintk(IOC, CMD)                   \
+       MPT_CHECK_LOGGING(IOC, CMD, MPT_DEBUG_IOCTL)
+
+#define dcsmisasprintk(IOC, CMD)               \
+       MPT_CHECK_LOGGING(IOC, CMD, MPT_DEBUG_CSMISAS)
+
+#define dsasprintk(IOC, CMD)                   \
+       MPT_CHECK_LOGGING(IOC, CMD, MPT_DEBUG_SAS)
+
+#define dsastransport(IOC, CMD)                \
+       MPT_CHECK_LOGGING(IOC, CMD, MPT_DEBUG_SAS_WIDE)
+
+#define dmfprintk(IOC, CMD)                    \
+       MPT_CHECK_LOGGING(IOC, CMD, MPT_DEBUG_MSG_FRAME)
+
+#define dtsfprintk(IOC, CMD)                   \
+       MPT_CHECK_LOGGING(IOC, CMD, MPT_DEBUG_TASK_SET_FULL)
+
+#define dtransportprintk(IOC, CMD)                     \
+       MPT_CHECK_LOGGING(IOC, CMD, MPT_DEBUG_TRANSPORT)
+
+#define dTMprintk(IOC, CMD)                    \
+       MPT_CHECK_LOGGING(IOC, CMD, MPT_DEBUG_TARGET_MODE)
+
+/* inline functions for dumping debug data*/
+#ifdef CONFIG_SCSI_MPT2SAS_LOGGING
+/**
+ * _debug_dump_mf - print message frame contents
+ * @mpi_request: pointer to message frame
+ * @sz: number of dwords
+ */
+static inline void
+_debug_dump_mf(void *mpi_request, int sz)
+{
+       int i;
+       u32 *mfp = (u32 *)mpi_request;
+
+       printk(KERN_INFO "mf:\n\t");
+       for (i = 0; i < sz; i++) {
+               if (i && ((i % 8) == 0))
+                       printk("\n\t");
+               printk("%08x ", le32_to_cpu(mfp[i]));
+       }
+       printk("\n");
+}
+#else
+#define _debug_dump_mf(mpi_request, sz)
+#endif /* CONFIG_SCSI_MPT2SAS_LOGGING */
+
+#endif /* MPT2SAS_DEBUG_H_INCLUDED */
diff --git a/drivers/scsi/mpt2sas/mpt2sas_scsih.c b/drivers/scsi/mpt2sas/mpt2sas_scsih.c
new file mode 100644 (file)
index 0000000..50865a8
--- /dev/null
@@ -0,0 +1,5687 @@
+/*
+ * Scsi Host Layer for MPT (Message Passing Technology) based controllers
+ *
+ * This code is based on drivers/scsi/mpt2sas/mpt2_scsih.c
+ * Copyright (C) 2007-2008  LSI Corporation
+ *  (mailto:DL-MPTFusionLinux@lsi.com)
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * NO WARRANTY
+ * THE PROGRAM IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OR
+ * CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED INCLUDING, WITHOUT
+ * LIMITATION, ANY WARRANTIES OR CONDITIONS OF TITLE, NON-INFRINGEMENT,
+ * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. Each Recipient is
+ * solely responsible for determining the appropriateness of using and
+ * distributing the Program and assumes all risks associated with its
+ * exercise of rights under this Agreement, including but not limited to
+ * the risks and costs of program errors, damage to or loss of data,
+ * programs or equipment, and unavailability or interruption of operations.
+
+ * DISCLAIMER OF LIABILITY
+ * NEITHER RECIPIENT NOR ANY CONTRIBUTORS SHALL HAVE ANY LIABILITY FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING WITHOUT LIMITATION LOST PROFITS), 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 OR DISTRIBUTION OF THE PROGRAM OR THE EXERCISE OF ANY RIGHTS GRANTED
+ * HEREUNDER, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGES
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301,
+ * USA.
+ */
+
+#include <linux/version.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/errno.h>
+#include <linux/blkdev.h>
+#include <linux/sched.h>
+#include <linux/workqueue.h>
+#include <linux/delay.h>
+#include <linux/pci.h>
+#include <linux/interrupt.h>
+
+#include "mpt2sas_base.h"
+
+MODULE_AUTHOR(MPT2SAS_AUTHOR);
+MODULE_DESCRIPTION(MPT2SAS_DESCRIPTION);
+MODULE_LICENSE("GPL");
+MODULE_VERSION(MPT2SAS_DRIVER_VERSION);
+
+#define RAID_CHANNEL 1
+
+/* forward proto's */
+static void _scsih_expander_node_remove(struct MPT2SAS_ADAPTER *ioc,
+    struct _sas_node *sas_expander);
+static void _firmware_event_work(struct work_struct *work);
+
+/* global parameters */
+LIST_HEAD(ioc_list);
+
+/* local parameters */
+static u32 logging_level;
+static u8 scsi_io_cb_idx = -1;
+static u8 tm_cb_idx = -1;
+static u8 ctl_cb_idx = -1;
+static u8 base_cb_idx = -1;
+static u8 transport_cb_idx = -1;
+static u8 config_cb_idx = -1;
+static int mpt_ids;
+
+/* command line options */
+MODULE_PARM_DESC(logging_level, " bits for enabling additional logging info "
+    "(default=0)");
+
+/* scsi-mid layer global parmeter is max_report_luns, which is 511 */
+#define MPT2SAS_MAX_LUN (16895)
+static int max_lun = MPT2SAS_MAX_LUN;
+module_param(max_lun, int, 0);
+MODULE_PARM_DESC(max_lun, " max lun, default=16895 ");
+
+/**
+ * struct sense_info - common structure for obtaining sense keys
+ * @skey: sense key
+ * @asc: additional sense code
+ * @ascq: additional sense code qualifier
+ */
+struct sense_info {
+       u8 skey;
+       u8 asc;
+       u8 ascq;
+};
+
+
+#define MPT2SAS_RESCAN_AFTER_HOST_RESET (0xFFFF)
+/**
+ * struct fw_event_work - firmware event struct
+ * @list: link list framework
+ * @work: work object (ioc->fault_reset_work_q)
+ * @ioc: per adapter object
+ * @VF_ID: virtual function id
+ * @host_reset_handling: handling events during host reset
+ * @ignore: flag meaning this event has been marked to ignore
+ * @event: firmware event MPI2_EVENT_XXX defined in mpt2_ioc.h
+ * @event_data: reply event data payload follows
+ *
+ * This object stored on ioc->fw_event_list.
+ */
+struct fw_event_work {
+       struct list_head        list;
+       struct delayed_work     work;
+       struct MPT2SAS_ADAPTER *ioc;
+       u8                      VF_ID;
+       u8                      host_reset_handling;
+       u8                      ignore;
+       u16                     event;
+       void                    *event_data;
+};
+
+/**
+ * struct _scsi_io_transfer - scsi io transfer
+ * @handle: sas device handle (assigned by firmware)
+ * @is_raid: flag set for hidden raid components
+ * @dir: DMA_TO_DEVICE, DMA_FROM_DEVICE,
+ * @data_length: data transfer length
+ * @data_dma: dma pointer to data
+ * @sense: sense data
+ * @lun: lun number
+ * @cdb_length: cdb length
+ * @cdb: cdb contents
+ * @valid_reply: flag set for reply message
+ * @timeout: timeout for this command
+ * @sense_length: sense length
+ * @ioc_status: ioc status
+ * @scsi_state: scsi state
+ * @scsi_status: scsi staus
+ * @log_info: log information
+ * @transfer_length: data length transfer when there is a reply message
+ *
+ * Used for sending internal scsi commands to devices within this module.
+ * Refer to _scsi_send_scsi_io().
+ */
+struct _scsi_io_transfer {
+       u16     handle;
+       u8      is_raid;
+       enum dma_data_direction dir;
+       u32     data_length;
+       dma_addr_t data_dma;
+       u8      sense[SCSI_SENSE_BUFFERSIZE];
+       u32     lun;
+       u8      cdb_length;
+       u8      cdb[32];
+       u8      timeout;
+       u8      valid_reply;
+  /* the following bits are only valid when 'valid_reply = 1' */
+       u32     sense_length;
+       u16     ioc_status;
+       u8      scsi_state;
+       u8      scsi_status;
+       u32     log_info;
+       u32     transfer_length;
+};
+
+/*
+ * The pci device ids are defined in mpi/mpi2_cnfg.h.
+ */
+static struct pci_device_id scsih_pci_table[] = {
+       { MPI2_MFGPAGE_VENDORID_LSI, MPI2_MFGPAGE_DEVID_SAS2004,
+               PCI_ANY_ID, PCI_ANY_ID },
+       /* Falcon ~ 2008*/
+       { MPI2_MFGPAGE_VENDORID_LSI, MPI2_MFGPAGE_DEVID_SAS2008,
+               PCI_ANY_ID, PCI_ANY_ID },
+       /* Liberator ~ 2108 */
+       { MPI2_MFGPAGE_VENDORID_LSI, MPI2_MFGPAGE_DEVID_SAS2108_1,
+               PCI_ANY_ID, PCI_ANY_ID },
+       { MPI2_MFGPAGE_VENDORID_LSI, MPI2_MFGPAGE_DEVID_SAS2108_2,
+               PCI_ANY_ID, PCI_ANY_ID },
+       { MPI2_MFGPAGE_VENDORID_LSI, MPI2_MFGPAGE_DEVID_SAS2108_3,
+               PCI_ANY_ID, PCI_ANY_ID },
+       { MPI2_MFGPAGE_VENDORID_LSI, MPI2_MFGPAGE_DEVID_SAS2116_1,
+               PCI_ANY_ID, PCI_ANY_ID },
+       { MPI2_MFGPAGE_VENDORID_LSI, MPI2_MFGPAGE_DEVID_SAS2116_2,
+               PCI_ANY_ID, PCI_ANY_ID },
+       {0}     /* Terminating entry */
+};
+MODULE_DEVICE_TABLE(pci, scsih_pci_table);
+
+/**
+ * scsih_set_debug_level - global setting of ioc->logging_level.
+ *
+ * Note: The logging levels are defined in mpt2sas_debug.h.
+ */
+static int
+scsih_set_debug_level(const char *val, struct kernel_param *kp)
+{
+       int ret = param_set_int(val, kp);
+       struct MPT2SAS_ADAPTER *ioc;
+
+       if (ret)
+               return ret;
+
+       printk(KERN_INFO "setting logging_level(0x%08x)\n", logging_level);
+       list_for_each_entry(ioc, &ioc_list, list)
+               ioc->logging_level = logging_level;
+       return 0;
+}
+module_param_call(logging_level, scsih_set_debug_level, param_get_int,
+    &logging_level, 0644);
+
+/**
+ * _scsih_srch_boot_sas_address - search based on sas_address
+ * @sas_address: sas address
+ * @boot_device: boot device object from bios page 2
+ *
+ * Returns 1 when there's a match, 0 means no match.
+ */
+static inline int
+_scsih_srch_boot_sas_address(u64 sas_address,
+    Mpi2BootDeviceSasWwid_t *boot_device)
+{
+       return (sas_address == le64_to_cpu(boot_device->SASAddress)) ?  1 : 0;
+}
+
+/**
+ * _scsih_srch_boot_device_name - search based on device name
+ * @device_name: device name specified in INDENTIFY fram
+ * @boot_device: boot device object from bios page 2
+ *
+ * Returns 1 when there's a match, 0 means no match.
+ */
+static inline int
+_scsih_srch_boot_device_name(u64 device_name,
+    Mpi2BootDeviceDeviceName_t *boot_device)
+{
+       return (device_name == le64_to_cpu(boot_device->DeviceName)) ? 1 : 0;
+}
+
+/**
+ * _scsih_srch_boot_encl_slot - search based on enclosure_logical_id/slot
+ * @enclosure_logical_id: enclosure logical id
+ * @slot_number: slot number
+ * @boot_device: boot device object from bios page 2
+ *
+ * Returns 1 when there's a match, 0 means no match.
+ */
+static inline int
+_scsih_srch_boot_encl_slot(u64 enclosure_logical_id, u16 slot_number,
+    Mpi2BootDeviceEnclosureSlot_t *boot_device)
+{
+       return (enclosure_logical_id == le64_to_cpu(boot_device->
+           EnclosureLogicalID) && slot_number == le16_to_cpu(boot_device->
+           SlotNumber)) ? 1 : 0;
+}
+
+/**
+ * _scsih_is_boot_device - search for matching boot device.
+ * @sas_address: sas address
+ * @device_name: device name specified in INDENTIFY fram
+ * @enclosure_logical_id: enclosure logical id
+ * @slot_number: slot number
+ * @form: specifies boot device form
+ * @boot_device: boot device object from bios page 2
+ *
+ * Returns 1 when there's a match, 0 means no match.
+ */
+static int
+_scsih_is_boot_device(u64 sas_address, u64 device_name,
+    u64 enclosure_logical_id, u16 slot, u8 form,
+    Mpi2BiosPage2BootDevice_t *boot_device)
+{
+       int rc = 0;
+
+       switch (form) {
+       case MPI2_BIOSPAGE2_FORM_SAS_WWID:
+               if (!sas_address)
+                       break;
+               rc = _scsih_srch_boot_sas_address(
+                   sas_address, &boot_device->SasWwid);
+               break;
+       case MPI2_BIOSPAGE2_FORM_ENCLOSURE_SLOT:
+               if (!enclosure_logical_id)
+                       break;
+               rc = _scsih_srch_boot_encl_slot(
+                   enclosure_logical_id,
+                   slot, &boot_device->EnclosureSlot);
+               break;
+       case MPI2_BIOSPAGE2_FORM_DEVICE_NAME:
+               if (!device_name)
+                       break;
+               rc = _scsih_srch_boot_device_name(
+                   device_name, &boot_device->DeviceName);
+               break;
+       case MPI2_BIOSPAGE2_FORM_NO_DEVICE_SPECIFIED:
+               break;
+       }
+
+       return rc;
+}
+
+/**
+ * _scsih_determine_boot_device - determine boot device.
+ * @ioc: per adapter object
+ * @device: either sas_device or raid_device object
+ * @is_raid: [flag] 1 = raid object, 0 = sas object
+ *
+ * Determines whether this device should be first reported device to
+ * to scsi-ml or sas transport, this purpose is for persistant boot device.
+ * There are primary, alternate, and current entries in bios page 2. The order
+ * priority is primary, alternate, then current.  This routine saves
+ * the corresponding device object and is_raid flag in the ioc object.
+ * The saved data to be used later in _scsih_probe_boot_devices().
+ */
+static void
+_scsih_determine_boot_device(struct MPT2SAS_ADAPTER *ioc,
+    void *device, u8 is_raid)
+{
+       struct _sas_device *sas_device;
+       struct _raid_device *raid_device;
+       u64 sas_address;
+       u64 device_name;
+       u64 enclosure_logical_id;
+       u16 slot;
+
+        /* only process this function when driver loads */
+       if (!ioc->wait_for_port_enable_to_complete)
+               return;
+
+       if (!is_raid) {
+               sas_device = device;
+               sas_address = sas_device->sas_address;
+               device_name = sas_device->device_name;
+               enclosure_logical_id = sas_device->enclosure_logical_id;
+               slot = sas_device->slot;
+       } else {
+               raid_device = device;
+               sas_address = raid_device->wwid;
+               device_name = 0;
+               enclosure_logical_id = 0;
+               slot = 0;
+       }
+
+       if (!ioc->req_boot_device.device) {
+               if (_scsih_is_boot_device(sas_address, device_name,
+                   enclosure_logical_id, slot,
+                   (ioc->bios_pg2.ReqBootDeviceForm &
+                   MPI2_BIOSPAGE2_FORM_MASK),
+                   &ioc->bios_pg2.RequestedBootDevice)) {
+                       dinitprintk(ioc, printk(MPT2SAS_DEBUG_FMT
+                          "%s: req_boot_device(0x%016llx)\n",
+                           ioc->name, __func__,
+                           (unsigned long long)sas_address));
+                       ioc->req_boot_device.device = device;
+                       ioc->req_boot_device.is_raid = is_raid;
+               }
+       }
+
+       if (!ioc->req_alt_boot_device.device) {
+               if (_scsih_is_boot_device(sas_address, device_name,
+                   enclosure_logical_id, slot,
+                   (ioc->bios_pg2.ReqAltBootDeviceForm &
+                   MPI2_BIOSPAGE2_FORM_MASK),
+                   &ioc->bios_pg2.RequestedAltBootDevice)) {
+                       dinitprintk(ioc, printk(MPT2SAS_DEBUG_FMT
+                          "%s: req_alt_boot_device(0x%016llx)\n",
+                           ioc->name, __func__,
+                           (unsigned long long)sas_address));
+                       ioc->req_alt_boot_device.device = device;
+                       ioc->req_alt_boot_device.is_raid = is_raid;
+               }
+       }
+
+       if (!ioc->current_boot_device.device) {
+               if (_scsih_is_boot_device(sas_address, device_name,
+                   enclosure_logical_id, slot,
+                   (ioc->bios_pg2.CurrentBootDeviceForm &
+                   MPI2_BIOSPAGE2_FORM_MASK),
+                   &ioc->bios_pg2.CurrentBootDevice)) {
+                       dinitprintk(ioc, printk(MPT2SAS_DEBUG_FMT
+                          "%s: current_boot_device(0x%016llx)\n",
+                           ioc->name, __func__,
+                           (unsigned long long)sas_address));
+                       ioc->current_boot_device.device = device;
+                       ioc->current_boot_device.is_raid = is_raid;
+               }
+       }
+}
+
+/**
+ * mpt2sas_scsih_sas_device_find_by_sas_address - sas device search
+ * @ioc: per adapter object
+ * @sas_address: sas address
+ * Context: Calling function should acquire ioc->sas_device_lock
+ *
+ * This searches for sas_device based on sas_address, then return sas_device
+ * object.
+ */
+struct _sas_device *
+mpt2sas_scsih_sas_device_find_by_sas_address(struct MPT2SAS_ADAPTER *ioc,
+    u64 sas_address)
+{
+       struct _sas_device *sas_device, *r;
+
+       r = NULL;
+       /* check the sas_device_init_list */
+       list_for_each_entry(sas_device, &ioc->sas_device_init_list,
+           list) {
+               if (sas_device->sas_address != sas_address)
+                       continue;
+               r = sas_device;
+               goto out;
+       }
+
+       /* then check the sas_device_list */
+       list_for_each_entry(sas_device, &ioc->sas_device_list, list) {
+               if (sas_device->sas_address != sas_address)
+                       continue;
+               r = sas_device;
+               goto out;
+       }
+ out:
+       return r;
+}
+
+/**
+ * _scsih_sas_device_find_by_handle - sas device search
+ * @ioc: per adapter object
+ * @handle: sas device handle (assigned by firmware)
+ * Context: Calling function should acquire ioc->sas_device_lock
+ *
+ * This searches for sas_device based on sas_address, then return sas_device
+ * object.
+ */
+static struct _sas_device *
+_scsih_sas_device_find_by_handle(struct MPT2SAS_ADAPTER *ioc, u16 handle)
+{
+       struct _sas_device *sas_device, *r;
+
+       r = NULL;
+       if (ioc->wait_for_port_enable_to_complete) {
+               list_for_each_entry(sas_device, &ioc->sas_device_init_list,
+                   list) {
+                       if (sas_device->handle != handle)
+                               continue;
+                       r = sas_device;
+                       goto out;
+               }
+       } else {
+               list_for_each_entry(sas_device, &ioc->sas_device_list, list) {
+                       if (sas_device->handle != handle)
+                               continue;
+                       r = sas_device;
+                       goto out;
+               }
+       }
+
+ out:
+       return r;
+}
+
+/**
+ * _scsih_sas_device_remove - remove sas_device from list.
+ * @ioc: per adapter object
+ * @sas_device: the sas_device object
+ * Context: This function will acquire ioc->sas_device_lock.
+ *
+ * Removing object and freeing associated memory from the ioc->sas_device_list.
+ */
+static void
+_scsih_sas_device_remove(struct MPT2SAS_ADAPTER *ioc,
+    struct _sas_device *sas_device)
+{
+       unsigned long flags;
+
+       spin_lock_irqsave(&ioc->sas_device_lock, flags);
+       list_del(&sas_device->list);
+       memset(sas_device, 0, sizeof(struct _sas_device));
+       kfree(sas_device);
+       spin_unlock_irqrestore(&ioc->sas_device_lock, flags);
+}
+
+/**
+ * _scsih_sas_device_add - insert sas_device to the list.
+ * @ioc: per adapter object
+ * @sas_device: the sas_device object
+ * Context: This function will acquire ioc->sas_device_lock.
+ *
+ * Adding new object to the ioc->sas_device_list.
+ */
+static void
+_scsih_sas_device_add(struct MPT2SAS_ADAPTER *ioc,
+    struct _sas_device *sas_device)
+{
+       unsigned long flags;
+       u16 handle, parent_handle;
+       u64 sas_address;
+
+       dewtprintk(ioc, printk(MPT2SAS_DEBUG_FMT "%s: handle"
+           "(0x%04x), sas_addr(0x%016llx)\n", ioc->name, __func__,
+           sas_device->handle, (unsigned long long)sas_device->sas_address));
+
+       spin_lock_irqsave(&ioc->sas_device_lock, flags);
+       list_add_tail(&sas_device->list, &ioc->sas_device_list);
+       spin_unlock_irqrestore(&ioc->sas_device_lock, flags);
+
+       handle = sas_device->handle;
+       parent_handle = sas_device->parent_handle;
+       sas_address = sas_device->sas_address;
+       if (!mpt2sas_transport_port_add(ioc, handle, parent_handle)) {
+               _scsih_sas_device_remove(ioc, sas_device);
+       } else if (!sas_device->starget) {
+               mpt2sas_transport_port_remove(ioc, sas_address, parent_handle);
+               _scsih_sas_device_remove(ioc, sas_device);
+       }
+}
+
+/**
+ * _scsih_sas_device_init_add - insert sas_device to the list.
+ * @ioc: per adapter object
+ * @sas_device: the sas_device object
+ * Context: This function will acquire ioc->sas_device_lock.
+ *
+ * Adding new object at driver load time to the ioc->sas_device_init_list.
+ */
+static void
+_scsih_sas_device_init_add(struct MPT2SAS_ADAPTER *ioc,
+    struct _sas_device *sas_device)
+{
+       unsigned long flags;
+
+       dewtprintk(ioc, printk(MPT2SAS_DEBUG_FMT "%s: handle"
+           "(0x%04x), sas_addr(0x%016llx)\n", ioc->name, __func__,
+           sas_device->handle, (unsigned long long)sas_device->sas_address));
+
+       spin_lock_irqsave(&ioc->sas_device_lock, flags);
+       list_add_tail(&sas_device->list, &ioc->sas_device_init_list);
+       spin_unlock_irqrestore(&ioc->sas_device_lock, flags);
+       _scsih_determine_boot_device(ioc, sas_device, 0);
+}
+
+/**
+ * mpt2sas_scsih_expander_find_by_handle - expander device search
+ * @ioc: per adapter object
+ * @handle: expander handle (assigned by firmware)
+ * Context: Calling function should acquire ioc->sas_device_lock
+ *
+ * This searches for expander device based on handle, then returns the
+ * sas_node object.
+ */
+struct _sas_node *
+mpt2sas_scsih_expander_find_by_handle(struct MPT2SAS_ADAPTER *ioc, u16 handle)
+{
+       struct _sas_node *sas_expander, *r;
+
+       r = NULL;
+       list_for_each_entry(sas_expander, &ioc->sas_expander_list, list) {
+               if (sas_expander->handle != handle)
+                       continue;
+               r = sas_expander;
+               goto out;
+       }
+ out:
+       return r;
+}
+
+/**
+ * _scsih_raid_device_find_by_id - raid device search
+ * @ioc: per adapter object
+ * @id: sas device target id
+ * @channel: sas device channel
+ * Context: Calling function should acquire ioc->raid_device_lock
+ *
+ * This searches for raid_device based on target id, then return raid_device
+ * object.
+ */
+static struct _raid_device *
+_scsih_raid_device_find_by_id(struct MPT2SAS_ADAPTER *ioc, int id, int channel)
+{
+       struct _raid_device *raid_device, *r;
+
+       r = NULL;
+       list_for_each_entry(raid_device, &ioc->raid_device_list, list) {
+               if (raid_device->id == id && raid_device->channel == channel) {
+                       r = raid_device;
+                       goto out;
+               }
+       }
+
+ out:
+       return r;
+}
+
+/**
+ * _scsih_raid_device_find_by_handle - raid device search
+ * @ioc: per adapter object
+ * @handle: sas device handle (assigned by firmware)
+ * Context: Calling function should acquire ioc->raid_device_lock
+ *
+ * This searches for raid_device based on handle, then return raid_device
+ * object.
+ */
+static struct _raid_device *
+_scsih_raid_device_find_by_handle(struct MPT2SAS_ADAPTER *ioc, u16 handle)
+{
+       struct _raid_device *raid_device, *r;
+
+       r = NULL;
+       list_for_each_entry(raid_device, &ioc->raid_device_list, list) {
+               if (raid_device->handle != handle)
+                       continue;
+               r = raid_device;
+               goto out;
+       }
+
+ out:
+       return r;
+}
+
+/**
+ * _scsih_raid_device_find_by_wwid - raid device search
+ * @ioc: per adapter object
+ * @handle: sas device handle (assigned by firmware)
+ * Context: Calling function should acquire ioc->raid_device_lock
+ *
+ * This searches for raid_device based on wwid, then return raid_device
+ * object.
+ */
+static struct _raid_device *
+_scsih_raid_device_find_by_wwid(struct MPT2SAS_ADAPTER *ioc, u64 wwid)
+{
+       struct _raid_device *raid_device, *r;
+
+       r = NULL;
+       list_for_each_entry(raid_device, &ioc->raid_device_list, list) {
+               if (raid_device->wwid != wwid)
+                       continue;
+               r = raid_device;
+               goto out;
+       }
+
+ out:
+       return r;
+}
+
+/**
+ * _scsih_raid_device_add - add raid_device object
+ * @ioc: per adapter object
+ * @raid_device: raid_device object
+ *
+ * This is added to the raid_device_list link list.
+ */
+static void
+_scsih_raid_device_add(struct MPT2SAS_ADAPTER *ioc,
+    struct _raid_device *raid_device)
+{
+       unsigned long flags;
+
+       dewtprintk(ioc, printk(MPT2SAS_DEBUG_FMT "%s: handle"
+           "(0x%04x), wwid(0x%016llx)\n", ioc->name, __func__,
+           raid_device->handle, (unsigned long long)raid_device->wwid));
+
+       spin_lock_irqsave(&ioc->raid_device_lock, flags);
+       list_add_tail(&raid_device->list, &ioc->raid_device_list);
+       spin_unlock_irqrestore(&ioc->raid_device_lock, flags);
+}
+
+/**
+ * _scsih_raid_device_remove - delete raid_device object
+ * @ioc: per adapter object
+ * @raid_device: raid_device object
+ *
+ * This is removed from the raid_device_list link list.
+ */
+static void
+_scsih_raid_device_remove(struct MPT2SAS_ADAPTER *ioc,
+    struct _raid_device *raid_device)
+{
+       unsigned long flags;
+
+       spin_lock_irqsave(&ioc->raid_device_lock, flags);
+       list_del(&raid_device->list);
+       memset(raid_device, 0, sizeof(struct _raid_device));
+       kfree(raid_device);
+       spin_unlock_irqrestore(&ioc->raid_device_lock, flags);
+}
+
+/**
+ * mpt2sas_scsih_expander_find_by_sas_address - expander device search
+ * @ioc: per adapter object
+ * @sas_address: sas address
+ * Context: Calling function should acquire ioc->sas_node_lock.
+ *
+ * This searches for expander device based on sas_address, then returns the
+ * sas_node object.
+ */
+struct _sas_node *
+mpt2sas_scsih_expander_find_by_sas_address(struct MPT2SAS_ADAPTER *ioc,
+    u64 sas_address)
+{
+       struct _sas_node *sas_expander, *r;
+
+       r = NULL;
+       list_for_each_entry(sas_expander, &ioc->sas_expander_list, list) {
+               if (sas_expander->sas_address != sas_address)
+                       continue;
+               r = sas_expander;
+               goto out;
+       }
+ out:
+       return r;
+}
+
+/**
+ * _scsih_expander_node_add - insert expander device to the list.
+ * @ioc: per adapter object
+ * @sas_expander: the sas_device object
+ * Context: This function will acquire ioc->sas_node_lock.
+ *
+ * Adding new object to the ioc->sas_expander_list.
+ *
+ * Return nothing.
+ */
+static void
+_scsih_expander_node_add(struct MPT2SAS_ADAPTER *ioc,
+    struct _sas_node *sas_expander)
+{
+       unsigned long flags;
+
+       spin_lock_irqsave(&ioc->sas_node_lock, flags);
+       list_add_tail(&sas_expander->list, &ioc->sas_expander_list);
+       spin_unlock_irqrestore(&ioc->sas_node_lock, flags);
+}
+
+/**
+ * _scsih_is_end_device - determines if device is an end device
+ * @device_info: bitfield providing information about the device.
+ * Context: none
+ *
+ * Returns 1 if end device.
+ */
+static int
+_scsih_is_end_device(u32 device_info)
+{
+       if (device_info & MPI2_SAS_DEVICE_INFO_END_DEVICE &&
+               ((device_info & MPI2_SAS_DEVICE_INFO_SSP_TARGET) |
+               (device_info & MPI2_SAS_DEVICE_INFO_STP_TARGET) |
+               (device_info & MPI2_SAS_DEVICE_INFO_SATA_DEVICE)))
+               return 1;
+       else
+               return 0;
+}
+
+/**
+ * _scsih_scsi_lookup_get - returns scmd entry
+ * @ioc: per adapter object
+ * @smid: system request message index
+ * Context: This function will acquire ioc->scsi_lookup_lock.
+ *
+ * Returns the smid stored scmd pointer.
+ */
+static struct scsi_cmnd *
+_scsih_scsi_lookup_get(struct MPT2SAS_ADAPTER *ioc, u16 smid)
+{
+       unsigned long   flags;
+       struct scsi_cmnd *scmd;
+
+       spin_lock_irqsave(&ioc->scsi_lookup_lock, flags);
+       scmd = ioc->scsi_lookup[smid - 1].scmd;
+       spin_unlock_irqrestore(&ioc->scsi_lookup_lock, flags);
+       return scmd;
+}
+
+/**
+ * mptscsih_getclear_scsi_lookup - returns scmd entry
+ * @ioc: per adapter object
+ * @smid: system request message index
+ * Context: This function will acquire ioc->scsi_lookup_lock.
+ *
+ * Returns the smid stored scmd pointer, as well as clearing the scmd pointer.
+ */
+static struct scsi_cmnd *
+_scsih_scsi_lookup_getclear(struct MPT2SAS_ADAPTER *ioc, u16 smid)
+{
+       unsigned long   flags;
+       struct scsi_cmnd *scmd;
+
+       spin_lock_irqsave(&ioc->scsi_lookup_lock, flags);
+       scmd = ioc->scsi_lookup[smid - 1].scmd;
+       ioc->scsi_lookup[smid - 1].scmd = NULL;
+       spin_unlock_irqrestore(&ioc->scsi_lookup_lock, flags);
+       return scmd;
+}
+
+/**
+ * _scsih_scsi_lookup_set - updates scmd entry in lookup
+ * @ioc: per adapter object
+ * @smid: system request message index
+ * @scmd: pointer to scsi command object
+ * Context: This function will acquire ioc->scsi_lookup_lock.
+ *
+ * This will save scmd pointer in the scsi_lookup array.
+ *
+ * Return nothing.
+ */
+static void
+_scsih_scsi_lookup_set(struct MPT2SAS_ADAPTER *ioc, u16 smid,
+    struct scsi_cmnd *scmd)
+{
+       unsigned long   flags;
+
+       spin_lock_irqsave(&ioc->scsi_lookup_lock, flags);
+       ioc->scsi_lookup[smid - 1].scmd = scmd;
+       spin_unlock_irqrestore(&ioc->scsi_lookup_lock, flags);
+}
+
+/**
+ * _scsih_scsi_lookup_find_by_scmd - scmd lookup
+ * @ioc: per adapter object
+ * @smid: system request message index
+ * @scmd: pointer to scsi command object
+ * Context: This function will acquire ioc->scsi_lookup_lock.
+ *
+ * This will search for a scmd pointer in the scsi_lookup array,
+ * returning the revelent smid.  A returned value of zero means invalid.
+ */
+static u16
+_scsih_scsi_lookup_find_by_scmd(struct MPT2SAS_ADAPTER *ioc, struct scsi_cmnd
+    *scmd)
+{
+       u16 smid;
+       unsigned long   flags;
+       int i;
+
+       spin_lock_irqsave(&ioc->scsi_lookup_lock, flags);
+       smid = 0;
+       for (i = 0; i < ioc->request_depth; i++) {
+               if (ioc->scsi_lookup[i].scmd == scmd) {
+                       smid = i + 1;
+                       goto out;
+               }
+       }
+ out:
+       spin_unlock_irqrestore(&ioc->scsi_lookup_lock, flags);
+       return smid;
+}
+
+/**
+ * _scsih_scsi_lookup_find_by_target - search for matching channel:id
+ * @ioc: per adapter object
+ * @id: target id
+ * @channel: channel
+ * Context: This function will acquire ioc->scsi_lookup_lock.
+ *
+ * This will search for a matching channel:id in the scsi_lookup array,
+ * returning 1 if found.
+ */
+static u8
+_scsih_scsi_lookup_find_by_target(struct MPT2SAS_ADAPTER *ioc, int id,
+    int channel)
+{
+       u8 found;
+       unsigned long   flags;
+       int i;
+
+       spin_lock_irqsave(&ioc->scsi_lookup_lock, flags);
+       found = 0;
+       for (i = 0 ; i < ioc->request_depth; i++) {
+               if (ioc->scsi_lookup[i].scmd &&
+                   (ioc->scsi_lookup[i].scmd->device->id == id &&
+                   ioc->scsi_lookup[i].scmd->device->channel == channel)) {
+                       found = 1;
+                       goto out;
+               }
+       }
+ out:
+       spin_unlock_irqrestore(&ioc->scsi_lookup_lock, flags);
+       return found;
+}
+
+/**
+ * _scsih_get_chain_buffer_dma - obtain block of chains (dma address)
+ * @ioc: per adapter object
+ * @smid: system request message index
+ *
+ * Returns phys pointer to chain buffer.
+ */
+static dma_addr_t
+_scsih_get_chain_buffer_dma(struct MPT2SAS_ADAPTER *ioc, u16 smid)
+{
+       return ioc->chain_dma + ((smid - 1) * (ioc->request_sz *
+           ioc->chains_needed_per_io));
+}
+
+/**
+ * _scsih_get_chain_buffer - obtain block of chains assigned to a mf request
+ * @ioc: per adapter object
+ * @smid: system request message index
+ *
+ * Returns virt pointer to chain buffer.
+ */
+static void *
+_scsih_get_chain_buffer(struct MPT2SAS_ADAPTER *ioc, u16 smid)
+{
+       return (void *)(ioc->chain + ((smid - 1) * (ioc->request_sz *
+           ioc->chains_needed_per_io)));
+}
+
+/**
+ * _scsih_build_scatter_gather - main sg creation routine
+ * @ioc: per adapter object
+ * @scmd: scsi command
+ * @smid: system request message index
+ * Context: none.
+ *
+ * The main routine that builds scatter gather table from a given
+ * scsi request sent via the .queuecommand main handler.
+ *
+ * Returns 0 success, anything else error
+ */
+static int
+_scsih_build_scatter_gather(struct MPT2SAS_ADAPTER *ioc,
+    struct scsi_cmnd *scmd, u16 smid)
+{
+       Mpi2SCSIIORequest_t *mpi_request;
+       dma_addr_t chain_dma;
+       struct scatterlist *sg_scmd;
+       void *sg_local, *chain;
+       u32 chain_offset;
+       u32 chain_length;
+       u32 chain_flags;
+       u32 sges_left;
+       u32 sges_in_segment;
+       u32 sgl_flags;
+       u32 sgl_flags_last_element;
+       u32 sgl_flags_end_buffer;
+
+       mpi_request = mpt2sas_base_get_msg_frame(ioc, smid);
+
+       /* init scatter gather flags */
+       sgl_flags = MPI2_SGE_FLAGS_SIMPLE_ELEMENT;
+       if (scmd->sc_data_direction == DMA_TO_DEVICE)
+               sgl_flags |= MPI2_SGE_FLAGS_HOST_TO_IOC;
+       sgl_flags_last_element = (sgl_flags | MPI2_SGE_FLAGS_LAST_ELEMENT)
+           << MPI2_SGE_FLAGS_SHIFT;
+       sgl_flags_end_buffer = (sgl_flags | MPI2_SGE_FLAGS_LAST_ELEMENT |
+           MPI2_SGE_FLAGS_END_OF_BUFFER | MPI2_SGE_FLAGS_END_OF_LIST)
+           << MPI2_SGE_FLAGS_SHIFT;
+       sgl_flags = sgl_flags << MPI2_SGE_FLAGS_SHIFT;
+
+       sg_scmd = scsi_sglist(scmd);
+       sges_left = scsi_dma_map(scmd);
+       if (!sges_left) {
+               sdev_printk(KERN_ERR, scmd->device, "pci_map_sg"
+               " failed: request for %d bytes!\n", scsi_bufflen(scmd));
+               return -ENOMEM;
+       }
+
+       sg_local = &mpi_request->SGL;
+       sges_in_segment = ioc->max_sges_in_main_message;
+       if (sges_left <= sges_in_segment)
+               goto fill_in_last_segment;
+
+       mpi_request->ChainOffset = (offsetof(Mpi2SCSIIORequest_t, SGL) +
+           (sges_in_segment * ioc->sge_size))/4;
+
+       /* fill in main message segment when there is a chain following */
+       while (sges_in_segment) {
+               if (sges_in_segment == 1)
+                       ioc->base_add_sg_single(sg_local,
+                           sgl_flags_last_element | sg_dma_len(sg_scmd),
+                           sg_dma_address(sg_scmd));
+               else
+                       ioc->base_add_sg_single(sg_local, sgl_flags |
+                           sg_dma_len(sg_scmd), sg_dma_address(sg_scmd));
+               sg_scmd = sg_next(sg_scmd);
+               sg_local += ioc->sge_size;
+               sges_left--;
+               sges_in_segment--;
+       }
+
+       /* initializing the chain flags and pointers */
+       chain_flags = MPI2_SGE_FLAGS_CHAIN_ELEMENT << MPI2_SGE_FLAGS_SHIFT;
+       chain = _scsih_get_chain_buffer(ioc, smid);
+       chain_dma = _scsih_get_chain_buffer_dma(ioc, smid);
+       do {
+               sges_in_segment = (sges_left <=
+                   ioc->max_sges_in_chain_message) ? sges_left :
+                   ioc->max_sges_in_chain_message;
+               chain_offset = (sges_left == sges_in_segment) ?
+                   0 : (sges_in_segment * ioc->sge_size)/4;
+               chain_length = sges_in_segment * ioc->sge_size;
+               if (chain_offset) {
+                       chain_offset = chain_offset <<
+                           MPI2_SGE_CHAIN_OFFSET_SHIFT;
+                       chain_length += ioc->sge_size;
+               }
+               ioc->base_add_sg_single(sg_local, chain_flags | chain_offset |
+                   chain_length, chain_dma);
+               sg_local = chain;
+               if (!chain_offset)
+                       goto fill_in_last_segment;
+
+               /* fill in chain segments */
+               while (sges_in_segment) {
+                       if (sges_in_segment == 1)
+                               ioc->base_add_sg_single(sg_local,
+                                   sgl_flags_last_element |
+                                   sg_dma_len(sg_scmd),
+                                   sg_dma_address(sg_scmd));
+                       else
+                               ioc->base_add_sg_single(sg_local, sgl_flags |
+                                   sg_dma_len(sg_scmd),
+                                   sg_dma_address(sg_scmd));
+                       sg_scmd = sg_next(sg_scmd);
+                       sg_local += ioc->sge_size;
+                       sges_left--;
+                       sges_in_segment--;
+               }
+
+               chain_dma += ioc->request_sz;
+               chain += ioc->request_sz;
+       } while (1);
+
+
+ fill_in_last_segment:
+
+       /* fill the last segment */
+       while (sges_left) {
+               if (sges_left == 1)
+                       ioc->base_add_sg_single(sg_local, sgl_flags_end_buffer |
+                           sg_dma_len(sg_scmd), sg_dma_address(sg_scmd));
+               else
+                       ioc->base_add_sg_single(sg_local, sgl_flags |
+                           sg_dma_len(sg_scmd), sg_dma_address(sg_scmd));
+               sg_scmd = sg_next(sg_scmd);
+               sg_local += ioc->sge_size;
+               sges_left--;
+       }
+
+       return 0;
+}
+
+/**
+ * scsih_change_queue_depth - setting device queue depth
+ * @sdev: scsi device struct
+ * @qdepth: requested queue depth
+ *
+ * Returns queue depth.
+ */
+static int
+scsih_change_queue_depth(struct scsi_device *sdev, int qdepth)
+{
+       struct Scsi_Host *shost = sdev->host;
+       int max_depth;
+       int tag_type;
+
+       max_depth = shost->can_queue;
+       if (!sdev->tagged_supported)
+               max_depth = 1;
+       if (qdepth > max_depth)
+               qdepth = max_depth;
+       tag_type = (qdepth == 1) ? 0 : MSG_SIMPLE_TAG;
+       scsi_adjust_queue_depth(sdev, tag_type, qdepth);
+
+       if (sdev->inquiry_len > 7)
+               sdev_printk(KERN_INFO, sdev, "qdepth(%d), tagged(%d), "
+               "simple(%d), ordered(%d), scsi_level(%d), cmd_que(%d)\n",
+               sdev->queue_depth, sdev->tagged_supported, sdev->simple_tags,
+               sdev->ordered_tags, sdev->scsi_level,
+               (sdev->inquiry[7] & 2) >> 1);
+
+       return sdev->queue_depth;
+}
+
+/**
+ * scsih_change_queue_depth - changing device queue tag type
+ * @sdev: scsi device struct
+ * @tag_type: requested tag type
+ *
+ * Returns queue tag type.
+ */
+static int
+scsih_change_queue_type(struct scsi_device *sdev, int tag_type)
+{
+       if (sdev->tagged_supported) {
+               scsi_set_tag_type(sdev, tag_type);
+               if (tag_type)
+                       scsi_activate_tcq(sdev, sdev->queue_depth);
+               else
+                       scsi_deactivate_tcq(sdev, sdev->queue_depth);
+       } else
+               tag_type = 0;
+
+       return tag_type;
+}
+
+/**
+ * scsih_target_alloc - target add routine
+ * @starget: scsi target struct
+ *
+ * Returns 0 if ok. Any other return is assumed to be an error and
+ * the device is ignored.
+ */
+static int
+scsih_target_alloc(struct scsi_target *starget)
+{
+       struct Scsi_Host *shost = dev_to_shost(&starget->dev);
+       struct MPT2SAS_ADAPTER *ioc = shost_priv(shost);
+       struct MPT2SAS_TARGET *sas_target_priv_data;
+       struct _sas_device *sas_device;
+       struct _raid_device *raid_device;
+       unsigned long flags;
+       struct sas_rphy *rphy;
+
+       sas_target_priv_data = kzalloc(sizeof(struct scsi_target), GFP_KERNEL);
+       if (!sas_target_priv_data)
+               return -ENOMEM;
+
+       starget->hostdata = sas_target_priv_data;
+       sas_target_priv_data->starget = starget;
+       sas_target_priv_data->handle = MPT2SAS_INVALID_DEVICE_HANDLE;
+
+       /* RAID volumes */
+       if (starget->channel == RAID_CHANNEL) {
+               spin_lock_irqsave(&ioc->raid_device_lock, flags);
+               raid_device = _scsih_raid_device_find_by_id(ioc, starget->id,
+                   starget->channel);
+               if (raid_device) {
+                       sas_target_priv_data->handle = raid_device->handle;
+                       sas_target_priv_data->sas_address = raid_device->wwid;
+                       sas_target_priv_data->flags |= MPT_TARGET_FLAGS_VOLUME;
+                       raid_device->starget = starget;
+               }
+               spin_unlock_irqrestore(&ioc->raid_device_lock, flags);
+               return 0;
+       }
+
+       /* sas/sata devices */
+       spin_lock_irqsave(&ioc->sas_device_lock, flags);
+       rphy = dev_to_rphy(starget->dev.parent);
+       sas_device = mpt2sas_scsih_sas_device_find_by_sas_address(ioc,
+          rphy->identify.sas_address);
+
+       if (sas_device) {
+               sas_target_priv_data->handle = sas_device->handle;
+               sas_target_priv_data->sas_address = sas_device->sas_address;
+               sas_device->starget = starget;
+               sas_device->id = starget->id;
+               sas_device->channel = starget->channel;
+               if (sas_device->hidden_raid_component)
+                       sas_target_priv_data->flags |=
+                           MPT_TARGET_FLAGS_RAID_COMPONENT;
+       }
+       spin_unlock_irqrestore(&ioc->sas_device_lock, flags);
+
+       return 0;
+}
+
+/**
+ * scsih_target_destroy - target destroy routine
+ * @starget: scsi target struct
+ *
+ * Returns nothing.
+ */
+static void
+scsih_target_destroy(struct scsi_target *starget)
+{
+       struct Scsi_Host *shost = dev_to_shost(&starget->dev);
+       struct MPT2SAS_ADAPTER *ioc = shost_priv(shost);
+       struct MPT2SAS_TARGET *sas_target_priv_data;
+       struct _sas_device *sas_device;
+       struct _raid_device *raid_device;
+       unsigned long flags;
+       struct sas_rphy *rphy;
+
+       sas_target_priv_data = starget->hostdata;
+       if (!sas_target_priv_data)
+               return;
+
+       if (starget->channel == RAID_CHANNEL) {
+               spin_lock_irqsave(&ioc->raid_device_lock, flags);
+               raid_device = _scsih_raid_device_find_by_id(ioc, starget->id,
+                   starget->channel);
+               if (raid_device) {
+                       raid_device->starget = NULL;
+                       raid_device->sdev = NULL;
+               }
+               spin_unlock_irqrestore(&ioc->raid_device_lock, flags);
+               goto out;
+       }
+
+       spin_lock_irqsave(&ioc->sas_device_lock, flags);
+       rphy = dev_to_rphy(starget->dev.parent);
+       sas_device = mpt2sas_scsih_sas_device_find_by_sas_address(ioc,
+          rphy->identify.sas_address);
+       if (sas_device)
+               sas_device->starget = NULL;
+
+       spin_unlock_irqrestore(&ioc->sas_device_lock, flags);
+
+ out:
+       kfree(sas_target_priv_data);
+       starget->hostdata = NULL;
+}
+
+/**
+ * scsih_slave_alloc - device add routine
+ * @sdev: scsi device struct
+ *
+ * Returns 0 if ok. Any other return is assumed to be an error and
+ * the device is ignored.
+ */
+static int
+scsih_slave_alloc(struct scsi_device *sdev)
+{
+       struct Scsi_Host *shost;
+       struct MPT2SAS_ADAPTER *ioc;
+       struct MPT2SAS_TARGET *sas_target_priv_data;
+       struct MPT2SAS_DEVICE *sas_device_priv_data;
+       struct scsi_target *starget;
+       struct _raid_device *raid_device;
+       struct _sas_device *sas_device;
+       unsigned long flags;
+
+       sas_device_priv_data = kzalloc(sizeof(struct scsi_device), GFP_KERNEL);
+       if (!sas_device_priv_data)
+               return -ENOMEM;
+
+       sas_device_priv_data->lun = sdev->lun;
+       sas_device_priv_data->flags = MPT_DEVICE_FLAGS_INIT;
+
+       starget = scsi_target(sdev);
+       sas_target_priv_data = starget->hostdata;
+       sas_target_priv_data->num_luns++;
+       sas_device_priv_data->sas_target = sas_target_priv_data;
+       sdev->hostdata = sas_device_priv_data;
+       if ((sas_target_priv_data->flags & MPT_TARGET_FLAGS_RAID_COMPONENT))
+               sdev->no_uld_attach = 1;
+
+       shost = dev_to_shost(&starget->dev);
+       ioc = shost_priv(shost);
+       if (starget->channel == RAID_CHANNEL) {
+               spin_lock_irqsave(&ioc->raid_device_lock, flags);
+               raid_device = _scsih_raid_device_find_by_id(ioc,
+                   starget->id, starget->channel);
+               if (raid_device)
+                       raid_device->sdev = sdev; /* raid is single lun */
+               spin_unlock_irqrestore(&ioc->raid_device_lock, flags);
+       } else {
+               /* set TLR bit for SSP devices */
+               if (!(ioc->facts.IOCCapabilities &
+                    MPI2_IOCFACTS_CAPABILITY_TLR))
+                       goto out;
+               spin_lock_irqsave(&ioc->sas_device_lock, flags);
+               sas_device = mpt2sas_scsih_sas_device_find_by_sas_address(ioc,
+                  sas_device_priv_data->sas_target->sas_address);
+               spin_unlock_irqrestore(&ioc->sas_device_lock, flags);
+               if (sas_device && sas_device->device_info &
+                   MPI2_SAS_DEVICE_INFO_SSP_TARGET)
+                       sas_device_priv_data->flags |= MPT_DEVICE_TLR_ON;
+       }
+
+ out:
+       return 0;
+}
+
+/**
+ * scsih_slave_destroy - device destroy routine
+ * @sdev: scsi device struct
+ *
+ * Returns nothing.
+ */
+static void
+scsih_slave_destroy(struct scsi_device *sdev)
+{
+       struct MPT2SAS_TARGET *sas_target_priv_data;
+       struct scsi_target *starget;
+
+       if (!sdev->hostdata)
+               return;
+
+       starget = scsi_target(sdev);
+       sas_target_priv_data = starget->hostdata;
+       sas_target_priv_data->num_luns--;
+       kfree(sdev->hostdata);
+       sdev->hostdata = NULL;
+}
+
+/**
+ * scsih_display_sata_capabilities - sata capabilities
+ * @ioc: per adapter object
+ * @sas_device: the sas_device object
+ * @sdev: scsi device struct
+ */
+static void
+scsih_display_sata_capabilities(struct MPT2SAS_ADAPTER *ioc,
+    struct _sas_device *sas_device, struct scsi_device *sdev)
+{
+       Mpi2ConfigReply_t mpi_reply;
+       Mpi2SasDevicePage0_t sas_device_pg0;
+       u32 ioc_status;
+       u16 flags;
+       u32 device_info;
+
+       if ((mpt2sas_config_get_sas_device_pg0(ioc, &mpi_reply, &sas_device_pg0,
+           MPI2_SAS_DEVICE_PGAD_FORM_HANDLE, sas_device->handle))) {
+               printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
+                   ioc->name, __FILE__, __LINE__, __func__);
+               return;
+       }
+
+       ioc_status = le16_to_cpu(mpi_reply.IOCStatus) &
+           MPI2_IOCSTATUS_MASK;
+       if (ioc_status != MPI2_IOCSTATUS_SUCCESS) {
+               printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
+                   ioc->name, __FILE__, __LINE__, __func__);
+               return;
+       }
+
+       flags = le16_to_cpu(sas_device_pg0.Flags);
+       device_info = le16_to_cpu(sas_device_pg0.DeviceInfo);
+
+       sdev_printk(KERN_INFO, sdev,
+           "atapi(%s), ncq(%s), asyn_notify(%s), smart(%s), fua(%s), "
+           "sw_preserve(%s)\n",
+           (device_info & MPI2_SAS_DEVICE_INFO_ATAPI_DEVICE) ? "y" : "n",
+           (flags & MPI2_SAS_DEVICE0_FLAGS_SATA_NCQ_SUPPORTED) ? "y" : "n",
+           (flags & MPI2_SAS_DEVICE0_FLAGS_SATA_ASYNCHRONOUS_NOTIFY) ? "y" :
+           "n",
+           (flags & MPI2_SAS_DEVICE0_FLAGS_SATA_SMART_SUPPORTED) ? "y" : "n",
+           (flags & MPI2_SAS_DEVICE0_FLAGS_SATA_FUA_SUPPORTED) ? "y" : "n",
+           (flags & MPI2_SAS_DEVICE0_FLAGS_SATA_SW_PRESERVE) ? "y" : "n");
+}
+
+/**
+ * _scsih_get_volume_capabilities - volume capabilities
+ * @ioc: per adapter object
+ * @sas_device: the raid_device object
+ */
+static void
+_scsih_get_volume_capabilities(struct MPT2SAS_ADAPTER *ioc,
+    struct _raid_device *raid_device)
+{
+       Mpi2RaidVolPage0_t *vol_pg0;
+       Mpi2RaidPhysDiskPage0_t pd_pg0;
+       Mpi2SasDevicePage0_t sas_device_pg0;
+       Mpi2ConfigReply_t mpi_reply;
+       u16 sz;
+       u8 num_pds;
+
+       if ((mpt2sas_config_get_number_pds(ioc, raid_device->handle,
+           &num_pds)) || !num_pds) {
+               printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
+                   ioc->name, __FILE__, __LINE__, __func__);
+               return;
+       }
+
+       raid_device->num_pds = num_pds;
+       sz = offsetof(Mpi2RaidVolPage0_t, PhysDisk) + (num_pds *
+           sizeof(Mpi2RaidVol0PhysDisk_t));
+       vol_pg0 = kzalloc(sz, GFP_KERNEL);
+       if (!vol_pg0) {
+               printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
+                   ioc->name, __FILE__, __LINE__, __func__);
+               return;
+       }
+
+       if ((mpt2sas_config_get_raid_volume_pg0(ioc, &mpi_reply, vol_pg0,
+            MPI2_RAID_VOLUME_PGAD_FORM_HANDLE, raid_device->handle, sz))) {
+               printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
+                   ioc->name, __FILE__, __LINE__, __func__);
+               kfree(vol_pg0);
+               return;
+       }
+
+       raid_device->volume_type = vol_pg0->VolumeType;
+
+       /* figure out what the underlying devices are by
+        * obtaining the device_info bits for the 1st device
+        */
+       if (!(mpt2sas_config_get_phys_disk_pg0(ioc, &mpi_reply,
+           &pd_pg0, MPI2_PHYSDISK_PGAD_FORM_PHYSDISKNUM,
+           vol_pg0->PhysDisk[0].PhysDiskNum))) {
+               if (!(mpt2sas_config_get_sas_device_pg0(ioc, &mpi_reply,
+                   &sas_device_pg0, MPI2_SAS_DEVICE_PGAD_FORM_HANDLE,
+                   le16_to_cpu(pd_pg0.DevHandle)))) {
+                       raid_device->device_info =
+                           le32_to_cpu(sas_device_pg0.DeviceInfo);
+               }
+       }
+
+       kfree(vol_pg0);
+}
+
+/**
+ * scsih_slave_configure - device configure routine.
+ * @sdev: scsi device struct
+ *
+ * Returns 0 if ok. Any other return is assumed to be an error and
+ * the device is ignored.
+ */
+static int
+scsih_slave_configure(struct scsi_device *sdev)
+{
+       struct Scsi_Host *shost = sdev->host;
+       struct MPT2SAS_ADAPTER *ioc = shost_priv(shost);
+       struct MPT2SAS_DEVICE *sas_device_priv_data;
+       struct MPT2SAS_TARGET *sas_target_priv_data;
+       struct _sas_device *sas_device;
+       struct _raid_device *raid_device;
+       unsigned long flags;
+       int qdepth;
+       u8 ssp_target = 0;
+       char *ds = "";
+       char *r_level = "";
+
+       qdepth = 1;
+       sas_device_priv_data = sdev->hostdata;
+       sas_device_priv_data->configured_lun = 1;
+       sas_device_priv_data->flags &= ~MPT_DEVICE_FLAGS_INIT;
+       sas_target_priv_data = sas_device_priv_data->sas_target;
+
+       /* raid volume handling */
+       if (sas_target_priv_data->flags & MPT_TARGET_FLAGS_VOLUME) {
+
+               spin_lock_irqsave(&ioc->raid_device_lock, flags);
+               raid_device = _scsih_raid_device_find_by_handle(ioc,
+                    sas_target_priv_data->handle);
+               spin_unlock_irqrestore(&ioc->raid_device_lock, flags);
+               if (!raid_device) {
+                       printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
+                           ioc->name, __FILE__, __LINE__, __func__);
+                       return 0;
+               }
+
+               _scsih_get_volume_capabilities(ioc, raid_device);
+
+               /* RAID Queue Depth Support
+                * IS volume = underlying qdepth of drive type, either
+                *    MPT2SAS_SAS_QUEUE_DEPTH or MPT2SAS_SATA_QUEUE_DEPTH
+                * IM/IME/R10 = 128 (MPT2SAS_RAID_QUEUE_DEPTH)
+                */
+               if (raid_device->device_info &
+                   MPI2_SAS_DEVICE_INFO_SSP_TARGET) {
+                       qdepth = MPT2SAS_SAS_QUEUE_DEPTH;
+                       ds = "SSP";
+               } else {
+                       qdepth = MPT2SAS_SATA_QUEUE_DEPTH;
+                        if (raid_device->device_info &
+                           MPI2_SAS_DEVICE_INFO_SATA_DEVICE)
+                               ds = "SATA";
+                       else
+                               ds = "STP";
+               }
+
+               switch (raid_device->volume_type) {
+               case MPI2_RAID_VOL_TYPE_RAID0:
+                       r_level = "RAID0";
+                       break;
+               case MPI2_RAID_VOL_TYPE_RAID1E:
+                       qdepth = MPT2SAS_RAID_QUEUE_DEPTH;
+                       r_level = "RAID1E";
+                       break;
+               case MPI2_RAID_VOL_TYPE_RAID1:
+                       qdepth = MPT2SAS_RAID_QUEUE_DEPTH;
+                       r_level = "RAID1";
+                       break;
+               case MPI2_RAID_VOL_TYPE_RAID10:
+                       qdepth = MPT2SAS_RAID_QUEUE_DEPTH;
+                       r_level = "RAID10";
+                       break;
+               case MPI2_RAID_VOL_TYPE_UNKNOWN:
+               default:
+                       qdepth = MPT2SAS_RAID_QUEUE_DEPTH;
+                       r_level = "RAIDX";
+                       break;
+               }
+
+               sdev_printk(KERN_INFO, sdev, "%s: "
+                   "handle(0x%04x), wwid(0x%016llx), pd_count(%d), type(%s)\n",
+                   r_level, raid_device->handle,
+                   (unsigned long long)raid_device->wwid,
+                   raid_device->num_pds, ds);
+               scsih_change_queue_depth(sdev, qdepth);
+               return 0;
+       }
+
+       /* non-raid handling */
+       spin_lock_irqsave(&ioc->sas_device_lock, flags);
+       sas_device = mpt2sas_scsih_sas_device_find_by_sas_address(ioc,
+          sas_device_priv_data->sas_target->sas_address);
+       spin_unlock_irqrestore(&ioc->sas_device_lock, flags);
+       if (sas_device) {
+               if (sas_target_priv_data->flags &
+                   MPT_TARGET_FLAGS_RAID_COMPONENT) {
+                       mpt2sas_config_get_volume_handle(ioc,
+                           sas_device->handle, &sas_device->volume_handle);
+                       mpt2sas_config_get_volume_wwid(ioc,
+                           sas_device->volume_handle,
+                           &sas_device->volume_wwid);
+               }
+               if (sas_device->device_info & MPI2_SAS_DEVICE_INFO_SSP_TARGET) {
+                       qdepth = MPT2SAS_SAS_QUEUE_DEPTH;
+                       ssp_target = 1;
+                       ds = "SSP";
+               } else {
+                       qdepth = MPT2SAS_SATA_QUEUE_DEPTH;
+                       if (sas_device->device_info &
+                           MPI2_SAS_DEVICE_INFO_STP_TARGET)
+                               ds = "STP";
+                       else if (sas_device->device_info &
+                           MPI2_SAS_DEVICE_INFO_SATA_DEVICE)
+                               ds = "SATA";
+               }
+
+               sdev_printk(KERN_INFO, sdev, "%s: handle(0x%04x), "
+                   "sas_addr(0x%016llx), device_name(0x%016llx)\n",
+                   ds, sas_device->handle,
+                   (unsigned long long)sas_device->sas_address,
+                   (unsigned long long)sas_device->device_name);
+               sdev_printk(KERN_INFO, sdev, "%s: "
+                   "enclosure_logical_id(0x%016llx), slot(%d)\n", ds,
+                   (unsigned long long) sas_device->enclosure_logical_id,
+                   sas_device->slot);
+
+               if (!ssp_target)
+                       scsih_display_sata_capabilities(ioc, sas_device, sdev);
+       }
+
+       scsih_change_queue_depth(sdev, qdepth);
+
+       if (ssp_target)
+               sas_read_port_mode_page(sdev);
+       return 0;
+}
+
+/**
+ * scsih_bios_param - fetch head, sector, cylinder info for a disk
+ * @sdev: scsi device struct
+ * @bdev: pointer to block device context
+ * @capacity: device size (in 512 byte sectors)
+ * @params: three element array to place output:
+ *              params[0] number of heads (max 255)
+ *              params[1] number of sectors (max 63)
+ *              params[2] number of cylinders
+ *
+ * Return nothing.
+ */
+static int
+scsih_bios_param(struct scsi_device *sdev, struct block_device *bdev,
+    sector_t capacity, int params[])
+{
+       int             heads;
+       int             sectors;
+       sector_t        cylinders;
+       ulong           dummy;
+
+       heads = 64;
+       sectors = 32;
+
+       dummy = heads * sectors;
+       cylinders = capacity;
+       sector_div(cylinders, dummy);
+
+       /*
+        * Handle extended translation size for logical drives
+        * > 1Gb
+        */
+       if ((ulong)capacity >= 0x200000) {
+               heads = 255;
+               sectors = 63;
+               dummy = heads * sectors;
+               cylinders = capacity;
+               sector_div(cylinders, dummy);
+       }
+
+       /* return result */
+       params[0] = heads;
+       params[1] = sectors;
+       params[2] = cylinders;
+
+       return 0;
+}
+
+/**
+ * _scsih_response_code - translation of device response code
+ * @ioc: per adapter object
+ * @response_code: response code returned by the device
+ *
+ * Return nothing.
+ */
+static void
+_scsih_response_code(struct MPT2SAS_ADAPTER *ioc, u8 response_code)
+{
+       char *desc;
+
+       switch (response_code) {
+       case MPI2_SCSITASKMGMT_RSP_TM_COMPLETE:
+               desc = "task management request completed";
+               break;
+       case MPI2_SCSITASKMGMT_RSP_INVALID_FRAME:
+               desc = "invalid frame";
+               break;
+       case MPI2_SCSITASKMGMT_RSP_TM_NOT_SUPPORTED:
+               desc = "task management request not supported";
+               break;
+       case MPI2_SCSITASKMGMT_RSP_TM_FAILED:
+               desc = "task management request failed";
+               break;
+       case MPI2_SCSITASKMGMT_RSP_TM_SUCCEEDED:
+               desc = "task management request succeeded";
+               break;
+       case MPI2_SCSITASKMGMT_RSP_TM_INVALID_LUN:
+               desc = "invalid lun";
+               break;
+       case 0xA:
+               desc = "overlapped tag attempted";
+               break;
+       case MPI2_SCSITASKMGMT_RSP_IO_QUEUED_ON_IOC:
+               desc = "task queued, however not sent to target";
+               break;
+       default:
+               desc = "unknown";
+               break;
+       }
+       printk(MPT2SAS_WARN_FMT "response_code(0x%01x): %s\n",
+               ioc->name, response_code, desc);
+}
+
+/**
+ * scsih_tm_done - tm completion routine
+ * @ioc: per adapter object
+ * @smid: system request message index
+ * @VF_ID: virtual function id
+ * @reply: reply message frame(lower 32bit addr)
+ * Context: none.
+ *
+ * The callback handler when using scsih_issue_tm.
+ *
+ * Return nothing.
+ */
+static void
+scsih_tm_done(struct MPT2SAS_ADAPTER *ioc, u16 smid, u8 VF_ID, u32 reply)
+{
+       MPI2DefaultReply_t *mpi_reply;
+
+       if (ioc->tm_cmds.status == MPT2_CMD_NOT_USED)
+               return;
+       if (ioc->tm_cmds.smid != smid)
+               return;
+       ioc->tm_cmds.status |= MPT2_CMD_COMPLETE;
+       mpi_reply =  mpt2sas_base_get_reply_virt_addr(ioc, reply);
+       if (mpi_reply) {
+               memcpy(ioc->tm_cmds.reply, mpi_reply, mpi_reply->MsgLength*4);
+               ioc->tm_cmds.status |= MPT2_CMD_REPLY_VALID;
+       }
+       ioc->tm_cmds.status &= ~MPT2_CMD_PENDING;
+       complete(&ioc->tm_cmds.done);
+}
+
+/**
+ * mpt2sas_scsih_set_tm_flag - set per target tm_busy
+ * @ioc: per adapter object
+ * @handle: device handle
+ *
+ * During taskmangement request, we need to freeze the device queue.
+ */
+void
+mpt2sas_scsih_set_tm_flag(struct MPT2SAS_ADAPTER *ioc, u16 handle)
+{
+       struct MPT2SAS_DEVICE *sas_device_priv_data;
+       struct scsi_device *sdev;
+       u8 skip = 0;
+
+       shost_for_each_device(sdev, ioc->shost) {
+               if (skip)
+                       continue;
+               sas_device_priv_data = sdev->hostdata;
+               if (!sas_device_priv_data)
+                       continue;
+               if (sas_device_priv_data->sas_target->handle == handle) {
+                       sas_device_priv_data->sas_target->tm_busy = 1;
+                       skip = 1;
+                       ioc->ignore_loginfos = 1;
+               }
+       }
+}
+
+/**
+ * mpt2sas_scsih_clear_tm_flag - clear per target tm_busy
+ * @ioc: per adapter object
+ * @handle: device handle
+ *
+ * During taskmangement request, we need to freeze the device queue.
+ */
+void
+mpt2sas_scsih_clear_tm_flag(struct MPT2SAS_ADAPTER *ioc, u16 handle)
+{
+       struct MPT2SAS_DEVICE *sas_device_priv_data;
+       struct scsi_device *sdev;
+       u8 skip = 0;
+
+       shost_for_each_device(sdev, ioc->shost) {
+               if (skip)
+                       continue;
+               sas_device_priv_data = sdev->hostdata;
+               if (!sas_device_priv_data)
+                       continue;
+               if (sas_device_priv_data->sas_target->handle == handle) {
+                       sas_device_priv_data->sas_target->tm_busy = 0;
+                       skip = 1;
+                       ioc->ignore_loginfos = 0;
+               }
+       }
+}
+
+/**
+ * mpt2sas_scsih_issue_tm - main routine for sending tm requests
+ * @ioc: per adapter struct
+ * @device_handle: device handle
+ * @lun: lun number
+ * @type: MPI2_SCSITASKMGMT_TASKTYPE__XXX (defined in mpi2_init.h)
+ * @smid_task: smid assigned to the task
+ * @timeout: timeout in seconds
+ * Context: The calling function needs to acquire the tm_cmds.mutex
+ *
+ * A generic API for sending task management requests to firmware.
+ *
+ * The ioc->tm_cmds.status flag should be MPT2_CMD_NOT_USED before calling
+ * this API.
+ *
+ * The callback index is set inside `ioc->tm_cb_idx`.
+ *
+ * Return nothing.
+ */
+void
+mpt2sas_scsih_issue_tm(struct MPT2SAS_ADAPTER *ioc, u16 handle, uint lun,
+    u8 type, u16 smid_task, ulong timeout)
+{
+       Mpi2SCSITaskManagementRequest_t *mpi_request;
+       Mpi2SCSITaskManagementReply_t *mpi_reply;
+       u16 smid = 0;
+       u32 ioc_state;
+       unsigned long timeleft;
+       u8 VF_ID = 0;
+       unsigned long flags;
+
+       spin_lock_irqsave(&ioc->ioc_reset_in_progress_lock, flags);
+       if (ioc->tm_cmds.status != MPT2_CMD_NOT_USED ||
+           ioc->shost_recovery) {
+               spin_unlock_irqrestore(&ioc->ioc_reset_in_progress_lock, flags);
+               printk(MPT2SAS_INFO_FMT "%s: host reset in progress!\n",
+                   __func__, ioc->name);
+               return;
+       }
+       spin_unlock_irqrestore(&ioc->ioc_reset_in_progress_lock, flags);
+
+       ioc_state = mpt2sas_base_get_iocstate(ioc, 0);
+       if (ioc_state & MPI2_DOORBELL_USED) {
+               dhsprintk(ioc, printk(MPT2SAS_DEBUG_FMT "unexpected doorbell "
+                   "active!\n", ioc->name));
+               goto issue_host_reset;
+       }
+
+       if ((ioc_state & MPI2_IOC_STATE_MASK) == MPI2_IOC_STATE_FAULT) {
+               mpt2sas_base_fault_info(ioc, ioc_state &
+                   MPI2_DOORBELL_DATA_MASK);
+               goto issue_host_reset;
+       }
+
+       smid = mpt2sas_base_get_smid(ioc, ioc->tm_cb_idx);
+       if (!smid) {
+               printk(MPT2SAS_ERR_FMT "%s: failed obtaining a smid\n",
+                   ioc->name, __func__);
+               return;
+       }
+
+       dtmprintk(ioc, printk(MPT2SAS_INFO_FMT "sending tm: handle(0x%04x),"
+           " task_type(0x%02x), smid(%d)\n", ioc->name, handle, type, smid));
+       ioc->tm_cmds.status = MPT2_CMD_PENDING;
+       mpi_request = mpt2sas_base_get_msg_frame(ioc, smid);
+       ioc->tm_cmds.smid = smid;
+       memset(mpi_request, 0, sizeof(Mpi2SCSITaskManagementRequest_t));
+       mpi_request->Function = MPI2_FUNCTION_SCSI_TASK_MGMT;
+       mpi_request->DevHandle = cpu_to_le16(handle);
+       mpi_request->TaskType = type;
+       mpi_request->TaskMID = cpu_to_le16(smid_task);
+       int_to_scsilun(lun, (struct scsi_lun *)mpi_request->LUN);
+       mpt2sas_scsih_set_tm_flag(ioc, handle);
+       mpt2sas_base_put_smid_hi_priority(ioc, smid, VF_ID);
+       timeleft = wait_for_completion_timeout(&ioc->tm_cmds.done, timeout*HZ);
+       mpt2sas_scsih_clear_tm_flag(ioc, handle);
+       if (!(ioc->tm_cmds.status & MPT2_CMD_COMPLETE)) {
+               printk(MPT2SAS_ERR_FMT "%s: timeout\n",
+                   ioc->name, __func__);
+               _debug_dump_mf(mpi_request,
+                   sizeof(Mpi2SCSITaskManagementRequest_t)/4);
+               if (!(ioc->tm_cmds.status & MPT2_CMD_RESET))
+                       goto issue_host_reset;
+       }
+
+       if (ioc->tm_cmds.status & MPT2_CMD_REPLY_VALID) {
+               mpi_reply = ioc->tm_cmds.reply;
+               dtmprintk(ioc, printk(MPT2SAS_INFO_FMT "complete tm: "
+                   "ioc_status(0x%04x), loginfo(0x%08x), term_count(0x%08x)\n",
+                   ioc->name, le16_to_cpu(mpi_reply->IOCStatus),
+                   le32_to_cpu(mpi_reply->IOCLogInfo),
+                   le32_to_cpu(mpi_reply->TerminationCount)));
+               if (ioc->logging_level & MPT_DEBUG_TM)
+                       _scsih_response_code(ioc, mpi_reply->ResponseCode);
+       }
+       return;
+ issue_host_reset:
+       mpt2sas_base_hard_reset_handler(ioc, CAN_SLEEP, FORCE_BIG_HAMMER);
+}
+
+/**
+ * scsih_abort - eh threads main abort routine
+ * @sdev: scsi device struct
+ *
+ * Returns SUCCESS if command aborted else FAILED
+ */
+static int
+scsih_abort(struct scsi_cmnd *scmd)
+{
+       struct MPT2SAS_ADAPTER *ioc = shost_priv(scmd->device->host);
+       struct MPT2SAS_DEVICE *sas_device_priv_data;
+       u16 smid;
+       u16 handle;
+       int r;
+       struct scsi_cmnd *scmd_lookup;
+
+       printk(MPT2SAS_INFO_FMT "attempting task abort! scmd(%p)\n",
+           ioc->name, scmd);
+       scsi_print_command(scmd);
+
+       sas_device_priv_data = scmd->device->hostdata;
+       if (!sas_device_priv_data || !sas_device_priv_data->sas_target) {
+               printk(MPT2SAS_INFO_FMT "device been deleted! scmd(%p)\n",
+                   ioc->name, scmd);
+               scmd->result = DID_NO_CONNECT << 16;
+               scmd->scsi_done(scmd);
+               r = SUCCESS;
+               goto out;
+       }
+
+       /* search for the command */
+       smid = _scsih_scsi_lookup_find_by_scmd(ioc, scmd);
+       if (!smid) {
+               scmd->result = DID_RESET << 16;
+               r = SUCCESS;
+               goto out;
+       }
+
+       /* for hidden raid components and volumes this is not supported */
+       if (sas_device_priv_data->sas_target->flags &
+           MPT_TARGET_FLAGS_RAID_COMPONENT ||
+           sas_device_priv_data->sas_target->flags & MPT_TARGET_FLAGS_VOLUME) {
+               scmd->result = DID_RESET << 16;
+               r = FAILED;
+               goto out;
+       }
+
+       mutex_lock(&ioc->tm_cmds.mutex);
+       handle = sas_device_priv_data->sas_target->handle;
+       mpt2sas_scsih_issue_tm(ioc, handle, sas_device_priv_data->lun,
+           MPI2_SCSITASKMGMT_TASKTYPE_ABORT_TASK, smid, 30);
+
+       /* sanity check - see whether command actually completed */
+       scmd_lookup = _scsih_scsi_lookup_get(ioc, smid);
+       if (scmd_lookup && (scmd_lookup->serial_number == scmd->serial_number))
+               r = FAILED;
+       else
+               r = SUCCESS;
+       ioc->tm_cmds.status = MPT2_CMD_NOT_USED;
+       mutex_unlock(&ioc->tm_cmds.mutex);
+
+ out:
+       printk(MPT2SAS_INFO_FMT "task abort: %s scmd(%p)\n",
+           ioc->name, ((r == SUCCESS) ? "SUCCESS" : "FAILED"), scmd);
+       return r;
+}
+
+
+/**
+ * scsih_dev_reset - eh threads main device reset routine
+ * @sdev: scsi device struct
+ *
+ * Returns SUCCESS if command aborted else FAILED
+ */
+static int
+scsih_dev_reset(struct scsi_cmnd *scmd)
+{
+       struct MPT2SAS_ADAPTER *ioc = shost_priv(scmd->device->host);
+       struct MPT2SAS_DEVICE *sas_device_priv_data;
+       struct _sas_device *sas_device;
+       unsigned long flags;
+       u16     handle;
+       int r;
+
+       printk(MPT2SAS_INFO_FMT "attempting target reset! scmd(%p)\n",
+           ioc->name, scmd);
+       scsi_print_command(scmd);
+
+       sas_device_priv_data = scmd->device->hostdata;
+       if (!sas_device_priv_data || !sas_device_priv_data->sas_target) {
+               printk(MPT2SAS_INFO_FMT "device been deleted! scmd(%p)\n",
+                   ioc->name, scmd);
+               scmd->result = DID_NO_CONNECT << 16;
+               scmd->scsi_done(scmd);
+               r = SUCCESS;
+               goto out;
+       }
+
+       /* for hidden raid components obtain the volume_handle */
+       handle = 0;
+       if (sas_device_priv_data->sas_target->flags &
+           MPT_TARGET_FLAGS_RAID_COMPONENT) {
+               spin_lock_irqsave(&ioc->sas_device_lock, flags);
+               sas_device = _scsih_sas_device_find_by_handle(ioc,
+                  sas_device_priv_data->sas_target->handle);
+               if (sas_device)
+                       handle = sas_device->volume_handle;
+               spin_unlock_irqrestore(&ioc->sas_device_lock, flags);
+       } else
+               handle = sas_device_priv_data->sas_target->handle;
+
+       if (!handle) {
+               scmd->result = DID_RESET << 16;
+               r = FAILED;
+               goto out;
+       }
+
+       mutex_lock(&ioc->tm_cmds.mutex);
+       mpt2sas_scsih_issue_tm(ioc, handle, 0,
+           MPI2_SCSITASKMGMT_TASKTYPE_TARGET_RESET, 0, 30);
+
+       /*
+        *  sanity check see whether all commands to this target been
+        *  completed
+        */
+       if (_scsih_scsi_lookup_find_by_target(ioc, scmd->device->id,
+           scmd->device->channel))
+               r = FAILED;
+       else
+               r = SUCCESS;
+       ioc->tm_cmds.status = MPT2_CMD_NOT_USED;
+       mutex_unlock(&ioc->tm_cmds.mutex);
+
+ out:
+       printk(MPT2SAS_INFO_FMT "target reset: %s scmd(%p)\n",
+           ioc->name, ((r == SUCCESS) ? "SUCCESS" : "FAILED"), scmd);
+       return r;
+}
+
+/**
+ * scsih_abort - eh threads main host reset routine
+ * @sdev: scsi device struct
+ *
+ * Returns SUCCESS if command aborted else FAILED
+ */
+static int
+scsih_host_reset(struct scsi_cmnd *scmd)
+{
+       struct MPT2SAS_ADAPTER *ioc = shost_priv(scmd->device->host);
+       int r, retval;
+
+       printk(MPT2SAS_INFO_FMT "attempting host reset! scmd(%p)\n",
+           ioc->name, scmd);
+       scsi_print_command(scmd);
+
+       retval = mpt2sas_base_hard_reset_handler(ioc, CAN_SLEEP,
+           FORCE_BIG_HAMMER);
+       r = (retval < 0) ? FAILED : SUCCESS;
+       printk(MPT2SAS_INFO_FMT "host reset: %s scmd(%p)\n",
+           ioc->name, ((r == SUCCESS) ? "SUCCESS" : "FAILED"), scmd);
+
+       return r;
+}
+
+/**
+ * _scsih_fw_event_add - insert and queue up fw_event
+ * @ioc: per adapter object
+ * @fw_event: object describing the event
+ * Context: This function will acquire ioc->fw_event_lock.
+ *
+ * This adds the firmware event object into link list, then queues it up to
+ * be processed from user context.
+ *
+ * Return nothing.
+ */
+static void
+_scsih_fw_event_add(struct MPT2SAS_ADAPTER *ioc, struct fw_event_work *fw_event)
+{
+       unsigned long flags;
+
+       if (ioc->firmware_event_thread == NULL)
+               return;
+
+       spin_lock_irqsave(&ioc->fw_event_lock, flags);
+       list_add_tail(&fw_event->list, &ioc->fw_event_list);
+       INIT_DELAYED_WORK(&fw_event->work, _firmware_event_work);
+       queue_delayed_work(ioc->firmware_event_thread, &fw_event->work, 1);
+       spin_unlock_irqrestore(&ioc->fw_event_lock, flags);
+}
+
+/**
+ * _scsih_fw_event_free - delete fw_event
+ * @ioc: per adapter object
+ * @fw_event: object describing the event
+ * Context: This function will acquire ioc->fw_event_lock.
+ *
+ * This removes firmware event object from link list, frees associated memory.
+ *
+ * Return nothing.
+ */
+static void
+_scsih_fw_event_free(struct MPT2SAS_ADAPTER *ioc, struct fw_event_work
+    *fw_event)
+{
+       unsigned long flags;
+
+       spin_lock_irqsave(&ioc->fw_event_lock, flags);
+       list_del(&fw_event->list);
+       kfree(fw_event->event_data);
+       kfree(fw_event);
+       spin_unlock_irqrestore(&ioc->fw_event_lock, flags);
+}
+
+/**
+ * _scsih_fw_event_add - requeue an event
+ * @ioc: per adapter object
+ * @fw_event: object describing the event
+ * Context: This function will acquire ioc->fw_event_lock.
+ *
+ * Return nothing.
+ */
+static void
+_scsih_fw_event_requeue(struct MPT2SAS_ADAPTER *ioc, struct fw_event_work
+    *fw_event, unsigned long delay)
+{
+       unsigned long flags;
+       if (ioc->firmware_event_thread == NULL)
+               return;
+
+       spin_lock_irqsave(&ioc->fw_event_lock, flags);
+       queue_delayed_work(ioc->firmware_event_thread, &fw_event->work, delay);
+       spin_unlock_irqrestore(&ioc->fw_event_lock, flags);
+}
+
+/**
+ * _scsih_fw_event_off - turn flag off preventing event handling
+ * @ioc: per adapter object
+ *
+ * Used to prevent handling of firmware events during adapter reset
+ * driver unload.
+ *
+ * Return nothing.
+ */
+static void
+_scsih_fw_event_off(struct MPT2SAS_ADAPTER *ioc)
+{
+       unsigned long flags;
+
+       spin_lock_irqsave(&ioc->fw_event_lock, flags);
+       ioc->fw_events_off = 1;
+       spin_unlock_irqrestore(&ioc->fw_event_lock, flags);
+
+}
+
+/**
+ * _scsih_fw_event_on - turn flag on allowing firmware event handling
+ * @ioc: per adapter object
+ *
+ * Returns nothing.
+ */
+static void
+_scsih_fw_event_on(struct MPT2SAS_ADAPTER *ioc)
+{
+       unsigned long flags;
+
+       spin_lock_irqsave(&ioc->fw_event_lock, flags);
+       ioc->fw_events_off = 0;
+       spin_unlock_irqrestore(&ioc->fw_event_lock, flags);
+}
+
+/**
+ * _scsih_ublock_io_device - set the device state to SDEV_RUNNING
+ * @ioc: per adapter object
+ * @handle: device handle
+ *
+ * During device pull we need to appropiately set the sdev state.
+ */
+static void
+_scsih_ublock_io_device(struct MPT2SAS_ADAPTER *ioc, u16 handle)
+{
+       struct MPT2SAS_DEVICE *sas_device_priv_data;
+       struct scsi_device *sdev;
+
+       shost_for_each_device(sdev, ioc->shost) {
+               sas_device_priv_data = sdev->hostdata;
+               if (!sas_device_priv_data)
+                       continue;
+               if (!sas_device_priv_data->block)
+                       continue;
+               if (sas_device_priv_data->sas_target->handle == handle) {
+                       dewtprintk(ioc, sdev_printk(KERN_INFO, sdev,
+                           MPT2SAS_INFO_FMT "SDEV_RUNNING: "
+                           "handle(0x%04x)\n", ioc->name, handle));
+                       sas_device_priv_data->block = 0;
+                       scsi_device_set_state(sdev, SDEV_RUNNING);
+               }
+       }
+}
+
+/**
+ * _scsih_block_io_device - set the device state to SDEV_BLOCK
+ * @ioc: per adapter object
+ * @handle: device handle
+ *
+ * During device pull we need to appropiately set the sdev state.
+ */
+static void
+_scsih_block_io_device(struct MPT2SAS_ADAPTER *ioc, u16 handle)
+{
+       struct MPT2SAS_DEVICE *sas_device_priv_data;
+       struct scsi_device *sdev;
+
+       shost_for_each_device(sdev, ioc->shost) {
+               sas_device_priv_data = sdev->hostdata;
+               if (!sas_device_priv_data)
+                       continue;
+               if (sas_device_priv_data->block)
+                       continue;
+               if (sas_device_priv_data->sas_target->handle == handle) {
+                       dewtprintk(ioc, sdev_printk(KERN_INFO, sdev,
+                           MPT2SAS_INFO_FMT "SDEV_BLOCK: "
+                           "handle(0x%04x)\n", ioc->name, handle));
+                       sas_device_priv_data->block = 1;
+                       scsi_device_set_state(sdev, SDEV_BLOCK);
+               }
+       }
+}
+
+/**
+ * _scsih_block_io_to_children_attached_to_ex
+ * @ioc: per adapter object
+ * @sas_expander: the sas_device object
+ *
+ * This routine set sdev state to SDEV_BLOCK for all devices
+ * attached to this expander. This function called when expander is
+ * pulled.
+ */
+static void
+_scsih_block_io_to_children_attached_to_ex(struct MPT2SAS_ADAPTER *ioc,
+    struct _sas_node *sas_expander)
+{
+       struct _sas_port *mpt2sas_port;
+       struct _sas_device *sas_device;
+       struct _sas_node *expander_sibling;
+       unsigned long flags;
+
+       if (!sas_expander)
+               return;
+
+       list_for_each_entry(mpt2sas_port,
+          &sas_expander->sas_port_list, port_list) {
+               if (mpt2sas_port->remote_identify.device_type ==
+                   SAS_END_DEVICE) {
+                       spin_lock_irqsave(&ioc->sas_device_lock, flags);
+                       sas_device =
+                           mpt2sas_scsih_sas_device_find_by_sas_address(ioc,
+                          mpt2sas_port->remote_identify.sas_address);
+                       spin_unlock_irqrestore(&ioc->sas_device_lock, flags);
+                       if (!sas_device)
+                               continue;
+                       _scsih_block_io_device(ioc, sas_device->handle);
+               }
+       }
+
+       list_for_each_entry(mpt2sas_port,
+          &sas_expander->sas_port_list, port_list) {
+
+               if (mpt2sas_port->remote_identify.device_type ==
+                   MPI2_SAS_DEVICE_INFO_EDGE_EXPANDER ||
+                   mpt2sas_port->remote_identify.device_type ==
+                   MPI2_SAS_DEVICE_INFO_FANOUT_EXPANDER) {
+
+                       spin_lock_irqsave(&ioc->sas_node_lock, flags);
+                       expander_sibling =
+                           mpt2sas_scsih_expander_find_by_sas_address(
+                           ioc, mpt2sas_port->remote_identify.sas_address);
+                       spin_unlock_irqrestore(&ioc->sas_node_lock, flags);
+                       _scsih_block_io_to_children_attached_to_ex(ioc,
+                           expander_sibling);
+               }
+       }
+}
+
+/**
+ * _scsih_block_io_to_children_attached_directly
+ * @ioc: per adapter object
+ * @event_data: topology change event data
+ *
+ * This routine set sdev state to SDEV_BLOCK for all devices
+ * direct attached during device pull.
+ */
+static void
+_scsih_block_io_to_children_attached_directly(struct MPT2SAS_ADAPTER *ioc,
+    Mpi2EventDataSasTopologyChangeList_t *event_data)
+{
+       int i;
+       u16 handle;
+       u16 reason_code;
+       u8 phy_number;
+
+       for (i = 0; i < event_data->NumEntries; i++) {
+               handle = le16_to_cpu(event_data->PHY[i].AttachedDevHandle);
+               if (!handle)
+                       continue;
+               phy_number = event_data->StartPhyNum + i;
+               reason_code = event_data->PHY[i].PhyStatus &
+                   MPI2_EVENT_SAS_TOPO_RC_MASK;
+               if (reason_code == MPI2_EVENT_SAS_TOPO_RC_DELAY_NOT_RESPONDING)
+                       _scsih_block_io_device(ioc, handle);
+       }
+}
+
+/**
+ * _scsih_check_topo_delete_events - sanity check on topo events
+ * @ioc: per adapter object
+ * @event_data: the event data payload
+ *
+ * This routine added to better handle cable breaker.
+ *
+ * This handles the case where driver recieves multiple expander
+ * add and delete events in a single shot.  When there is a delete event
+ * the routine will void any pending add events waiting in the event queue.
+ *
+ * Return nothing.
+ */
+static void
+_scsih_check_topo_delete_events(struct MPT2SAS_ADAPTER *ioc,
+    Mpi2EventDataSasTopologyChangeList_t *event_data)
+{
+       struct fw_event_work *fw_event;
+       Mpi2EventDataSasTopologyChangeList_t *local_event_data;
+       u16 expander_handle;
+       struct _sas_node *sas_expander;
+       unsigned long flags;
+
+       expander_handle = le16_to_cpu(event_data->ExpanderDevHandle);
+       if (expander_handle < ioc->sas_hba.num_phys) {
+               _scsih_block_io_to_children_attached_directly(ioc, event_data);
+               return;
+       }
+
+       if (event_data->ExpStatus == MPI2_EVENT_SAS_TOPO_ES_DELAY_NOT_RESPONDING
+        || event_data->ExpStatus == MPI2_EVENT_SAS_TOPO_ES_NOT_RESPONDING) {
+               spin_lock_irqsave(&ioc->sas_node_lock, flags);
+               sas_expander = mpt2sas_scsih_expander_find_by_handle(ioc,
+                   expander_handle);
+               spin_unlock_irqrestore(&ioc->sas_node_lock, flags);
+               _scsih_block_io_to_children_attached_to_ex(ioc, sas_expander);
+       } else if (event_data->ExpStatus == MPI2_EVENT_SAS_TOPO_ES_RESPONDING)
+               _scsih_block_io_to_children_attached_directly(ioc, event_data);
+
+       if (event_data->ExpStatus != MPI2_EVENT_SAS_TOPO_ES_NOT_RESPONDING)
+               return;
+
+       /* mark ignore flag for pending events */
+       spin_lock_irqsave(&ioc->fw_event_lock, flags);
+       list_for_each_entry(fw_event, &ioc->fw_event_list, list) {
+               if (fw_event->event != MPI2_EVENT_SAS_TOPOLOGY_CHANGE_LIST ||
+                   fw_event->ignore)
+                       continue;
+               local_event_data = fw_event->event_data;
+               if (local_event_data->ExpStatus ==
+                   MPI2_EVENT_SAS_TOPO_ES_ADDED ||
+                   local_event_data->ExpStatus ==
+                   MPI2_EVENT_SAS_TOPO_ES_RESPONDING) {
+                       if (le16_to_cpu(local_event_data->ExpanderDevHandle) ==
+                           expander_handle) {
+                               dewtprintk(ioc, printk(MPT2SAS_DEBUG_FMT
+                                   "setting ignoring flag\n", ioc->name));
+                               fw_event->ignore = 1;
+                       }
+               }
+       }
+       spin_unlock_irqrestore(&ioc->fw_event_lock, flags);
+}
+
+/**
+ * _scsih_queue_rescan - queue a topology rescan from user context
+ * @ioc: per adapter object
+ *
+ * Return nothing.
+ */
+static void
+_scsih_queue_rescan(struct MPT2SAS_ADAPTER *ioc)
+{
+       struct fw_event_work *fw_event;
+
+       if (ioc->wait_for_port_enable_to_complete)
+               return;
+       fw_event = kzalloc(sizeof(struct fw_event_work), GFP_ATOMIC);
+       if (!fw_event)
+               return;
+       fw_event->event = MPT2SAS_RESCAN_AFTER_HOST_RESET;
+       fw_event->ioc = ioc;
+       _scsih_fw_event_add(ioc, fw_event);
+}
+
+/**
+ * _scsih_flush_running_cmds - completing outstanding commands.
+ * @ioc: per adapter object
+ *
+ * The flushing out of all pending scmd commands following host reset,
+ * where all IO is dropped to the floor.
+ *
+ * Return nothing.
+ */
+static void
+_scsih_flush_running_cmds(struct MPT2SAS_ADAPTER *ioc)
+{
+       struct scsi_cmnd *scmd;
+       u16 smid;
+       u16 count = 0;
+
+       for (smid = 1; smid <= ioc->request_depth; smid++) {
+               scmd = _scsih_scsi_lookup_getclear(ioc, smid);
+               if (!scmd)
+                       continue;
+               count++;
+               mpt2sas_base_free_smid(ioc, smid);
+               scsi_dma_unmap(scmd);
+               scmd->result = DID_RESET << 16;
+               scmd->scsi_done(scmd);
+       }
+       dtmprintk(ioc, printk(MPT2SAS_INFO_FMT "completing %d cmds\n",
+           ioc->name, count));
+}
+
+/**
+ * mpt2sas_scsih_reset_handler - reset callback handler (for scsih)
+ * @ioc: per adapter object
+ * @reset_phase: phase
+ *
+ * The handler for doing any required cleanup or initialization.
+ *
+ * The reset phase can be MPT2_IOC_PRE_RESET, MPT2_IOC_AFTER_RESET,
+ * MPT2_IOC_DONE_RESET
+ *
+ * Return nothing.
+ */
+void
+mpt2sas_scsih_reset_handler(struct MPT2SAS_ADAPTER *ioc, int reset_phase)
+{
+       switch (reset_phase) {
+       case MPT2_IOC_PRE_RESET:
+               dtmprintk(ioc, printk(MPT2SAS_DEBUG_FMT "%s: "
+                   "MPT2_IOC_PRE_RESET\n", ioc->name, __func__));
+               _scsih_fw_event_off(ioc);
+               break;
+       case MPT2_IOC_AFTER_RESET:
+               dtmprintk(ioc, printk(MPT2SAS_DEBUG_FMT "%s: "
+                   "MPT2_IOC_AFTER_RESET\n", ioc->name, __func__));
+               if (ioc->tm_cmds.status & MPT2_CMD_PENDING) {
+                       ioc->tm_cmds.status |= MPT2_CMD_RESET;
+                       mpt2sas_base_free_smid(ioc, ioc->tm_cmds.smid);
+                       complete(&ioc->tm_cmds.done);
+               }
+               _scsih_fw_event_on(ioc);
+               _scsih_flush_running_cmds(ioc);
+               break;
+       case MPT2_IOC_DONE_RESET:
+               dtmprintk(ioc, printk(MPT2SAS_DEBUG_FMT "%s: "
+                   "MPT2_IOC_DONE_RESET\n", ioc->name, __func__));
+               _scsih_queue_rescan(ioc);
+               break;
+       }
+}
+
+/**
+ * scsih_qcmd - main scsi request entry point
+ * @scmd: pointer to scsi command object
+ * @done: function pointer to be invoked on completion
+ *
+ * The callback index is set inside `ioc->scsi_io_cb_idx`.
+ *
+ * Returns 0 on success.  If there's a failure, return either:
+ * SCSI_MLQUEUE_DEVICE_BUSY if the device queue is full, or
+ * SCSI_MLQUEUE_HOST_BUSY if the entire host queue is full
+ */
+static int
+scsih_qcmd(struct scsi_cmnd *scmd, void (*done)(struct scsi_cmnd *))
+{
+       struct MPT2SAS_ADAPTER *ioc = shost_priv(scmd->device->host);
+       struct MPT2SAS_DEVICE *sas_device_priv_data;
+       struct MPT2SAS_TARGET *sas_target_priv_data;
+       Mpi2SCSIIORequest_t *mpi_request;
+       u32 mpi_control;
+       u16 smid;
+       unsigned long flags;
+
+       scmd->scsi_done = done;
+       sas_device_priv_data = scmd->device->hostdata;
+       if (!sas_device_priv_data) {
+               scmd->result = DID_NO_CONNECT << 16;
+               scmd->scsi_done(scmd);
+               return 0;
+       }
+
+       sas_target_priv_data = sas_device_priv_data->sas_target;
+       if (!sas_target_priv_data || sas_target_priv_data->handle ==
+           MPT2SAS_INVALID_DEVICE_HANDLE || sas_target_priv_data->deleted) {
+               scmd->result = DID_NO_CONNECT << 16;
+               scmd->scsi_done(scmd);
+               return 0;
+       }
+
+       /* see if we are busy with task managment stuff */
+       spin_lock_irqsave(&ioc->ioc_reset_in_progress_lock, flags);
+       if (sas_target_priv_data->tm_busy ||
+           ioc->shost_recovery || ioc->ioc_link_reset_in_progress) {
+               spin_unlock_irqrestore(&ioc->ioc_reset_in_progress_lock, flags);
+               return SCSI_MLQUEUE_HOST_BUSY;
+       }
+       spin_unlock_irqrestore(&ioc->ioc_reset_in_progress_lock, flags);
+
+       if (scmd->sc_data_direction == DMA_FROM_DEVICE)
+               mpi_control = MPI2_SCSIIO_CONTROL_READ;
+       else if (scmd->sc_data_direction == DMA_TO_DEVICE)
+               mpi_control = MPI2_SCSIIO_CONTROL_WRITE;
+       else
+               mpi_control = MPI2_SCSIIO_CONTROL_NODATATRANSFER;
+
+       /* set tags */
+       if (!(sas_device_priv_data->flags & MPT_DEVICE_FLAGS_INIT)) {
+               if (scmd->device->tagged_supported) {
+                       if (scmd->device->ordered_tags)
+                               mpi_control |= MPI2_SCSIIO_CONTROL_ORDEREDQ;
+                       else
+                               mpi_control |= MPI2_SCSIIO_CONTROL_SIMPLEQ;
+               } else
+/* MPI Revision I (UNIT = 0xA) - removed MPI2_SCSIIO_CONTROL_UNTAGGED */
+/*                     mpi_control |= MPI2_SCSIIO_CONTROL_UNTAGGED;
+ */
+                       mpi_control |= (0x500);
+
+       } else
+               mpi_control |= MPI2_SCSIIO_CONTROL_SIMPLEQ;
+
+       if ((sas_device_priv_data->flags & MPT_DEVICE_TLR_ON))
+               mpi_control |= MPI2_SCSIIO_CONTROL_TLR_ON;
+
+       smid = mpt2sas_base_get_smid(ioc, ioc->scsi_io_cb_idx);
+       if (!smid) {
+               printk(MPT2SAS_ERR_FMT "%s: failed obtaining a smid\n",
+                   ioc->name, __func__);
+               goto out;
+       }
+       mpi_request = mpt2sas_base_get_msg_frame(ioc, smid);
+       memset(mpi_request, 0, sizeof(Mpi2SCSIIORequest_t));
+       mpi_request->Function = MPI2_FUNCTION_SCSI_IO_REQUEST;
+       if (sas_device_priv_data->sas_target->flags &
+           MPT_TARGET_FLAGS_RAID_COMPONENT)
+               mpi_request->Function = MPI2_FUNCTION_RAID_SCSI_IO_PASSTHROUGH;
+       else
+               mpi_request->Function = MPI2_FUNCTION_SCSI_IO_REQUEST;
+       mpi_request->DevHandle =
+           cpu_to_le16(sas_device_priv_data->sas_target->handle);
+       mpi_request->DataLength = cpu_to_le32(scsi_bufflen(scmd));
+       mpi_request->Control = cpu_to_le32(mpi_control);
+       mpi_request->IoFlags = cpu_to_le16(scmd->cmd_len);
+       mpi_request->MsgFlags = MPI2_SCSIIO_MSGFLAGS_SYSTEM_SENSE_ADDR;
+       mpi_request->SenseBufferLength = SCSI_SENSE_BUFFERSIZE;
+       mpi_request->SenseBufferLowAddress =
+           (u32)mpt2sas_base_get_sense_buffer_dma(ioc, smid);
+       mpi_request->SGLOffset0 = offsetof(Mpi2SCSIIORequest_t, SGL) / 4;
+       mpi_request->SGLFlags = cpu_to_le16(MPI2_SCSIIO_SGLFLAGS_TYPE_MPI +
+           MPI2_SCSIIO_SGLFLAGS_SYSTEM_ADDR);
+
+       int_to_scsilun(sas_device_priv_data->lun, (struct scsi_lun *)
+           mpi_request->LUN);
+       memcpy(mpi_request->CDB.CDB32, scmd->cmnd, scmd->cmd_len);
+
+       if (!mpi_request->DataLength) {
+               mpt2sas_base_build_zero_len_sge(ioc, &mpi_request->SGL);
+       } else {
+               if (_scsih_build_scatter_gather(ioc, scmd, smid)) {
+                       mpt2sas_base_free_smid(ioc, smid);
+                       goto out;
+               }
+       }
+
+       _scsih_scsi_lookup_set(ioc, smid, scmd);
+       mpt2sas_base_put_smid_scsi_io(ioc, smid, 0,
+           sas_device_priv_data->sas_target->handle);
+       return 0;
+
+ out:
+       return SCSI_MLQUEUE_HOST_BUSY;
+}
+
+/**
+ * _scsih_normalize_sense - normalize descriptor and fixed format sense data
+ * @sense_buffer: sense data returned by target
+ * @data: normalized skey/asc/ascq
+ *
+ * Return nothing.
+ */
+static void
+_scsih_normalize_sense(char *sense_buffer, struct sense_info *data)
+{
+       if ((sense_buffer[0] & 0x7F) >= 0x72) {
+               /* descriptor format */
+               data->skey = sense_buffer[1] & 0x0F;
+               data->asc = sense_buffer[2];
+               data->ascq = sense_buffer[3];
+       } else {
+               /* fixed format */
+               data->skey = sense_buffer[2] & 0x0F;
+               data->asc = sense_buffer[12];
+               data->ascq = sense_buffer[13];
+       }
+}
+
+#ifdef CONFIG_SCSI_MPT2SAS_LOGGING
+/**
+ * _scsih_scsi_ioc_info - translated non-succesfull SCSI_IO request
+ * @ioc: per adapter object
+ * @scmd: pointer to scsi command object
+ * @mpi_reply: reply mf payload returned from firmware
+ *
+ * scsi_status - SCSI Status code returned from target device
+ * scsi_state - state info associated with SCSI_IO determined by ioc
+ * ioc_status - ioc supplied status info
+ *
+ * Return nothing.
+ */
+static void
+_scsih_scsi_ioc_info(struct MPT2SAS_ADAPTER *ioc, struct scsi_cmnd *scmd,
+    Mpi2SCSIIOReply_t *mpi_reply, u16 smid)
+{
+       u32 response_info;
+       u8 *response_bytes;
+       u16 ioc_status = le16_to_cpu(mpi_reply->IOCStatus) &
+           MPI2_IOCSTATUS_MASK;
+       u8 scsi_state = mpi_reply->SCSIState;
+       u8 scsi_status = mpi_reply->SCSIStatus;
+       char *desc_ioc_state = NULL;
+       char *desc_scsi_status = NULL;
+       char *desc_scsi_state = ioc->tmp_string;
+
+       switch (ioc_status) {
+       case MPI2_IOCSTATUS_SUCCESS:
+               desc_ioc_state = "success";
+               break;
+       case MPI2_IOCSTATUS_INVALID_FUNCTION:
+               desc_ioc_state = "invalid function";
+               break;
+       case MPI2_IOCSTATUS_SCSI_RECOVERED_ERROR:
+               desc_ioc_state = "scsi recovered error";
+               break;
+       case MPI2_IOCSTATUS_SCSI_INVALID_DEVHANDLE:
+               desc_ioc_state = "scsi invalid dev handle";
+               break;
+       case MPI2_IOCSTATUS_SCSI_DEVICE_NOT_THERE:
+               desc_ioc_state = "scsi device not there";
+               break;
+       case MPI2_IOCSTATUS_SCSI_DATA_OVERRUN:
+               desc_ioc_state = "scsi data overrun";
+               break;
+       case MPI2_IOCSTATUS_SCSI_DATA_UNDERRUN:
+               desc_ioc_state = "scsi data underrun";
+               break;
+       case MPI2_IOCSTATUS_SCSI_IO_DATA_ERROR:
+               desc_ioc_state = "scsi io data error";
+               break;
+       case MPI2_IOCSTATUS_SCSI_PROTOCOL_ERROR:
+               desc_ioc_state = "scsi protocol error";
+               break;
+       case MPI2_IOCSTATUS_SCSI_TASK_TERMINATED:
+               desc_ioc_state = "scsi task terminated";
+               break;
+       case MPI2_IOCSTATUS_SCSI_RESIDUAL_MISMATCH:
+               desc_ioc_state = "scsi residual mismatch";
+               break;
+       case MPI2_IOCSTATUS_SCSI_TASK_MGMT_FAILED:
+               desc_ioc_state = "scsi task mgmt failed";
+               break;
+       case MPI2_IOCSTATUS_SCSI_IOC_TERMINATED:
+               desc_ioc_state = "scsi ioc terminated";
+               break;
+       case MPI2_IOCSTATUS_SCSI_EXT_TERMINATED:
+               desc_ioc_state = "scsi ext terminated";
+               break;
+       default:
+               desc_ioc_state = "unknown";
+               break;
+       }
+
+       switch (scsi_status) {
+       case MPI2_SCSI_STATUS_GOOD:
+               desc_scsi_status = "good";
+               break;
+       case MPI2_SCSI_STATUS_CHECK_CONDITION:
+               desc_scsi_status = "check condition";
+               break;
+       case MPI2_SCSI_STATUS_CONDITION_MET:
+               desc_scsi_status = "condition met";
+               break;
+       case MPI2_SCSI_STATUS_BUSY:
+               desc_scsi_status = "busy";
+               break;
+       case MPI2_SCSI_STATUS_INTERMEDIATE:
+               desc_scsi_status = "intermediate";
+               break;
+       case MPI2_SCSI_STATUS_INTERMEDIATE_CONDMET:
+               desc_scsi_status = "intermediate condmet";
+               break;
+       case MPI2_SCSI_STATUS_RESERVATION_CONFLICT:
+               desc_scsi_status = "reservation conflict";
+               break;
+       case MPI2_SCSI_STATUS_COMMAND_TERMINATED:
+               desc_scsi_status = "command terminated";
+               break;
+       case MPI2_SCSI_STATUS_TASK_SET_FULL:
+               desc_scsi_status = "task set full";
+               break;
+       case MPI2_SCSI_STATUS_ACA_ACTIVE:
+               desc_scsi_status = "aca active";
+               break;
+       case MPI2_SCSI_STATUS_TASK_ABORTED:
+               desc_scsi_status = "task aborted";
+               break;
+       default:
+               desc_scsi_status = "unknown";
+               break;
+       }
+
+       desc_scsi_state[0] = '\0';
+       if (!scsi_state)
+               desc_scsi_state = " ";
+       if (scsi_state & MPI2_SCSI_STATE_RESPONSE_INFO_VALID)
+               strcat(desc_scsi_state, "response info ");
+       if (scsi_state & MPI2_SCSI_STATE_TERMINATED)
+               strcat(desc_scsi_state, "state terminated ");
+       if (scsi_state & MPI2_SCSI_STATE_NO_SCSI_STATUS)
+               strcat(desc_scsi_state, "no status ");
+       if (scsi_state & MPI2_SCSI_STATE_AUTOSENSE_FAILED)
+               strcat(desc_scsi_state, "autosense failed ");
+       if (scsi_state & MPI2_SCSI_STATE_AUTOSENSE_VALID)
+               strcat(desc_scsi_state, "autosense valid ");
+
+       scsi_print_command(scmd);
+       printk(MPT2SAS_WARN_FMT "\tdev handle(0x%04x), "
+           "ioc_status(%s)(0x%04x), smid(%d)\n", ioc->name,
+           le16_to_cpu(mpi_reply->DevHandle), desc_ioc_state,
+               ioc_status, smid);
+       printk(MPT2SAS_WARN_FMT "\trequest_len(%d), underflow(%d), "
+           "resid(%d)\n", ioc->name, scsi_bufflen(scmd), scmd->underflow,
+           scsi_get_resid(scmd));
+       printk(MPT2SAS_WARN_FMT "\ttag(%d), transfer_count(%d), "
+           "sc->result(0x%08x)\n", ioc->name, le16_to_cpu(mpi_reply->TaskTag),
+           le32_to_cpu(mpi_reply->TransferCount), scmd->result);
+       printk(MPT2SAS_WARN_FMT "\tscsi_status(%s)(0x%02x), "
+           "scsi_state(%s)(0x%02x)\n", ioc->name, desc_scsi_status,
+           scsi_status, desc_scsi_state, scsi_state);
+
+       if (scsi_state & MPI2_SCSI_STATE_AUTOSENSE_VALID) {
+               struct sense_info data;
+               _scsih_normalize_sense(scmd->sense_buffer, &data);
+               printk(MPT2SAS_WARN_FMT "\t[sense_key,asc,ascq]: "
+                   "[0x%02x,0x%02x,0x%02x]\n", ioc->name, data.skey,
+                   data.asc, data.ascq);
+       }
+
+       if (scsi_state & MPI2_SCSI_STATE_RESPONSE_INFO_VALID) {
+               response_info = le32_to_cpu(mpi_reply->ResponseInfo);
+               response_bytes = (u8 *)&response_info;
+               _scsih_response_code(ioc, response_bytes[3]);
+       }
+}
+#endif
+
+/**
+ * _scsih_smart_predicted_fault - illuminate Fault LED
+ * @ioc: per adapter object
+ * @handle: device handle
+ *
+ * Return nothing.
+ */
+static void
+_scsih_smart_predicted_fault(struct MPT2SAS_ADAPTER *ioc, u16 handle)
+{
+       Mpi2SepReply_t mpi_reply;
+       Mpi2SepRequest_t mpi_request;
+       struct scsi_target *starget;
+       struct MPT2SAS_TARGET *sas_target_priv_data;
+       Mpi2EventNotificationReply_t *event_reply;
+       Mpi2EventDataSasDeviceStatusChange_t *event_data;
+       struct _sas_device *sas_device;
+       ssize_t sz;
+       unsigned long flags;
+
+       /* only handle non-raid devices */
+       spin_lock_irqsave(&ioc->sas_device_lock, flags);
+       sas_device = _scsih_sas_device_find_by_handle(ioc, handle);
+       if (!sas_device) {
+               spin_unlock_irqrestore(&ioc->sas_device_lock, flags);
+               return;
+       }
+       starget = sas_device->starget;
+       sas_target_priv_data = starget->hostdata;
+
+       if ((sas_target_priv_data->flags & MPT_TARGET_FLAGS_RAID_COMPONENT) ||
+          ((sas_target_priv_data->flags & MPT_TARGET_FLAGS_VOLUME))) {
+               spin_unlock_irqrestore(&ioc->sas_device_lock, flags);
+               return;
+       }
+       starget_printk(KERN_WARNING, starget, "predicted fault\n");
+       spin_unlock_irqrestore(&ioc->sas_device_lock, flags);
+
+       if (ioc->pdev->subsystem_vendor == PCI_VENDOR_ID_IBM) {
+               memset(&mpi_request, 0, sizeof(Mpi2SepRequest_t));
+               mpi_request.Function = MPI2_FUNCTION_SCSI_ENCLOSURE_PROCESSOR;
+               mpi_request.Action = MPI2_SEP_REQ_ACTION_WRITE_STATUS;
+               mpi_request.SlotStatus =
+                   MPI2_SEP_REQ_SLOTSTATUS_PREDICTED_FAULT;
+               mpi_request.DevHandle = cpu_to_le16(handle);
+               mpi_request.Flags = MPI2_SEP_REQ_FLAGS_DEVHANDLE_ADDRESS;
+               if ((mpt2sas_base_scsi_enclosure_processor(ioc, &mpi_reply,
+                   &mpi_request)) != 0) {
+                       printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
+                           ioc->name, __FILE__, __LINE__, __func__);
+                       return;
+               }
+
+               if (mpi_reply.IOCStatus || mpi_reply.IOCLogInfo) {
+                       dewtprintk(ioc, printk(MPT2SAS_INFO_FMT
+                           "enclosure_processor: ioc_status (0x%04x), "
+                           "loginfo(0x%08x)\n", ioc->name,
+                           le16_to_cpu(mpi_reply.IOCStatus),
+                           le32_to_cpu(mpi_reply.IOCLogInfo)));
+                       return;
+               }
+       }
+
+       /* insert into event log */
+       sz = offsetof(Mpi2EventNotificationReply_t, EventData) +
+            sizeof(Mpi2EventDataSasDeviceStatusChange_t);
+       event_reply = kzalloc(sz, GFP_KERNEL);
+       if (!event_reply) {
+               printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
+                   ioc->name, __FILE__, __LINE__, __func__);
+               return;
+       }
+
+       event_reply->Function = MPI2_FUNCTION_EVENT_NOTIFICATION;
+       event_reply->Event =
+           cpu_to_le16(MPI2_EVENT_SAS_DEVICE_STATUS_CHANGE);
+       event_reply->MsgLength = sz/4;
+       event_reply->EventDataLength =
+           cpu_to_le16(sizeof(Mpi2EventDataSasDeviceStatusChange_t)/4);
+       event_data = (Mpi2EventDataSasDeviceStatusChange_t *)
+           event_reply->EventData;
+       event_data->ReasonCode = MPI2_EVENT_SAS_DEV_STAT_RC_SMART_DATA;
+       event_data->ASC = 0x5D;
+       event_data->DevHandle = cpu_to_le16(handle);
+       event_data->SASAddress = cpu_to_le64(sas_target_priv_data->sas_address);
+       mpt2sas_ctl_add_to_event_log(ioc, event_reply);
+       kfree(event_reply);
+}
+
+/**
+ * scsih_io_done - scsi request callback
+ * @ioc: per adapter object
+ * @smid: system request message index
+ * @VF_ID: virtual function id
+ * @reply: reply message frame(lower 32bit addr)
+ *
+ * Callback handler when using scsih_qcmd.
+ *
+ * Return nothing.
+ */
+static void
+scsih_io_done(struct MPT2SAS_ADAPTER *ioc, u16 smid, u8 VF_ID, u32 reply)
+{
+       Mpi2SCSIIORequest_t *mpi_request;
+       Mpi2SCSIIOReply_t *mpi_reply;
+       struct scsi_cmnd *scmd;
+       u16 ioc_status;
+       u32 xfer_cnt;
+       u8 scsi_state;
+       u8 scsi_status;
+       u32 log_info;
+       struct MPT2SAS_DEVICE *sas_device_priv_data;
+       u32 response_code;
+
+       mpi_reply = mpt2sas_base_get_reply_virt_addr(ioc, reply);
+       scmd = _scsih_scsi_lookup_getclear(ioc, smid);
+       if (scmd == NULL)
+               return;
+
+       mpi_request = mpt2sas_base_get_msg_frame(ioc, smid);
+
+       if (mpi_reply == NULL) {
+               scmd->result = DID_OK << 16;
+               goto out;
+       }
+
+       sas_device_priv_data = scmd->device->hostdata;
+       if (!sas_device_priv_data || !sas_device_priv_data->sas_target ||
+            sas_device_priv_data->sas_target->deleted) {
+               scmd->result = DID_NO_CONNECT << 16;
+               goto out;
+       }
+
+       /* turning off TLR */
+       if (!sas_device_priv_data->tlr_snoop_check) {
+               sas_device_priv_data->tlr_snoop_check++;
+               if (sas_device_priv_data->flags & MPT_DEVICE_TLR_ON) {
+                       response_code = (le32_to_cpu(mpi_reply->ResponseInfo)
+                           >> 24);
+                       if (response_code ==
+                           MPI2_SCSITASKMGMT_RSP_INVALID_FRAME)
+                               sas_device_priv_data->flags &=
+                                   ~MPT_DEVICE_TLR_ON;
+               }
+       }
+
+       xfer_cnt = le32_to_cpu(mpi_reply->TransferCount);
+       scsi_set_resid(scmd, scsi_bufflen(scmd) - xfer_cnt);
+       ioc_status = le16_to_cpu(mpi_reply->IOCStatus);
+       if (ioc_status & MPI2_IOCSTATUS_FLAG_LOG_INFO_AVAILABLE)
+               log_info =  le32_to_cpu(mpi_reply->IOCLogInfo);
+       else
+               log_info = 0;
+       ioc_status &= MPI2_IOCSTATUS_MASK;
+       scsi_state = mpi_reply->SCSIState;
+       scsi_status = mpi_reply->SCSIStatus;
+
+       if (ioc_status == MPI2_IOCSTATUS_SCSI_DATA_UNDERRUN && xfer_cnt == 0 &&
+           (scsi_status == MPI2_SCSI_STATUS_BUSY ||
+            scsi_status == MPI2_SCSI_STATUS_RESERVATION_CONFLICT ||
+            scsi_status == MPI2_SCSI_STATUS_TASK_SET_FULL)) {
+               ioc_status = MPI2_IOCSTATUS_SUCCESS;
+       }
+
+       if (scsi_state & MPI2_SCSI_STATE_AUTOSENSE_VALID) {
+               struct sense_info data;
+               const void *sense_data = mpt2sas_base_get_sense_buffer(ioc,
+                   smid);
+               memcpy(scmd->sense_buffer, sense_data,
+                   le32_to_cpu(mpi_reply->SenseCount));
+               _scsih_normalize_sense(scmd->sense_buffer, &data);
+               /* failure prediction threshold exceeded */
+               if (data.asc == 0x5D)
+                       _scsih_smart_predicted_fault(ioc,
+                           le16_to_cpu(mpi_reply->DevHandle));
+       }
+
+       switch (ioc_status) {
+       case MPI2_IOCSTATUS_BUSY:
+       case MPI2_IOCSTATUS_INSUFFICIENT_RESOURCES:
+               scmd->result = SAM_STAT_BUSY;
+               break;
+
+       case MPI2_IOCSTATUS_SCSI_DEVICE_NOT_THERE:
+               scmd->result = DID_NO_CONNECT << 16;
+               break;
+
+       case MPI2_IOCSTATUS_SCSI_IOC_TERMINATED:
+               if (sas_device_priv_data->block) {
+                       scmd->result = (DID_BUS_BUSY << 16);
+                       break;
+               }
+
+       case MPI2_IOCSTATUS_SCSI_TASK_TERMINATED:
+       case MPI2_IOCSTATUS_SCSI_EXT_TERMINATED:
+               scmd->result = DID_RESET << 16;
+               break;
+
+       case MPI2_IOCSTATUS_SCSI_RESIDUAL_MISMATCH:
+               if ((xfer_cnt == 0) || (scmd->underflow > xfer_cnt))
+                       scmd->result = DID_SOFT_ERROR << 16;
+               else
+                       scmd->result = (DID_OK << 16) | scsi_status;
+               break;
+
+       case MPI2_IOCSTATUS_SCSI_DATA_UNDERRUN:
+               scmd->result = (DID_OK << 16) | scsi_status;
+
+               if ((scsi_state & MPI2_SCSI_STATE_AUTOSENSE_VALID))
+                       break;
+
+               if (xfer_cnt < scmd->underflow) {
+                       if (scsi_status == SAM_STAT_BUSY)
+                               scmd->result = SAM_STAT_BUSY;
+                       else
+                               scmd->result = DID_SOFT_ERROR << 16;
+               } else if (scsi_state & (MPI2_SCSI_STATE_AUTOSENSE_FAILED |
+                    MPI2_SCSI_STATE_NO_SCSI_STATUS))
+                       scmd->result = DID_SOFT_ERROR << 16;
+               else if (scsi_state & MPI2_SCSI_STATE_TERMINATED)
+                       scmd->result = DID_RESET << 16;
+               else if (!xfer_cnt && scmd->cmnd[0] == REPORT_LUNS) {
+                       mpi_reply->SCSIState = MPI2_SCSI_STATE_AUTOSENSE_VALID;
+                       mpi_reply->SCSIStatus = SAM_STAT_CHECK_CONDITION;
+                       scmd->result = (DRIVER_SENSE << 24) |
+                           SAM_STAT_CHECK_CONDITION;
+                       scmd->sense_buffer[0] = 0x70;
+                       scmd->sense_buffer[2] = ILLEGAL_REQUEST;
+                       scmd->sense_buffer[12] = 0x20;
+                       scmd->sense_buffer[13] = 0;
+               }
+               break;
+
+       case MPI2_IOCSTATUS_SCSI_DATA_OVERRUN:
+               scsi_set_resid(scmd, 0);
+       case MPI2_IOCSTATUS_SCSI_RECOVERED_ERROR:
+       case MPI2_IOCSTATUS_SUCCESS:
+               scmd->result = (DID_OK << 16) | scsi_status;
+               if (scsi_state & (MPI2_SCSI_STATE_AUTOSENSE_FAILED |
+                    MPI2_SCSI_STATE_NO_SCSI_STATUS))
+                       scmd->result = DID_SOFT_ERROR << 16;
+               else if (scsi_state & MPI2_SCSI_STATE_TERMINATED)
+                       scmd->result = DID_RESET << 16;
+               break;
+
+       case MPI2_IOCSTATUS_SCSI_PROTOCOL_ERROR:
+       case MPI2_IOCSTATUS_INVALID_FUNCTION:
+       case MPI2_IOCSTATUS_INVALID_SGL:
+       case MPI2_IOCSTATUS_INTERNAL_ERROR:
+       case MPI2_IOCSTATUS_INVALID_FIELD:
+       case MPI2_IOCSTATUS_INVALID_STATE:
+       case MPI2_IOCSTATUS_SCSI_IO_DATA_ERROR:
+       case MPI2_IOCSTATUS_SCSI_TASK_MGMT_FAILED:
+       default:
+               scmd->result = DID_SOFT_ERROR << 16;
+               break;
+
+       }
+
+#ifdef CONFIG_SCSI_MPT2SAS_LOGGING
+       if (scmd->result && (ioc->logging_level & MPT_DEBUG_REPLY))
+               _scsih_scsi_ioc_info(ioc , scmd, mpi_reply, smid);
+#endif
+
+ out:
+       scsi_dma_unmap(scmd);
+       scmd->scsi_done(scmd);
+}
+
+/**
+ * _scsih_link_change - process phy link changes
+ * @ioc: per adapter object
+ * @handle: phy handle
+ * @attached_handle: valid for devices attached to link
+ * @phy_number: phy number
+ * @link_rate: new link rate
+ * Context: user.
+ *
+ * Return nothing.
+ */
+static void
+_scsih_link_change(struct MPT2SAS_ADAPTER *ioc, u16 handle, u16 attached_handle,
+   u8 phy_number, u8 link_rate)
+{
+       mpt2sas_transport_update_phy_link_change(ioc, handle, attached_handle,
+           phy_number, link_rate);
+}
+
+/**
+ * _scsih_sas_host_refresh - refreshing sas host object contents
+ * @ioc: per adapter object
+ * @update: update link information
+ * Context: user
+ *
+ * During port enable, fw will send topology events for every device. Its
+ * possible that the handles may change from the previous setting, so this
+ * code keeping handles updating if changed.
+ *
+ * Return nothing.
+ */
+static void
+_scsih_sas_host_refresh(struct MPT2SAS_ADAPTER *ioc, u8 update)
+{
+       u16 sz;
+       u16 ioc_status;
+       int i;
+       Mpi2ConfigReply_t mpi_reply;
+       Mpi2SasIOUnitPage0_t *sas_iounit_pg0 = NULL;
+
+       dtmprintk(ioc, printk(MPT2SAS_INFO_FMT
+           "updating handles for sas_host(0x%016llx)\n",
+           ioc->name, (unsigned long long)ioc->sas_hba.sas_address));
+
+       sz = offsetof(Mpi2SasIOUnitPage0_t, PhyData) + (ioc->sas_hba.num_phys
+           * sizeof(Mpi2SasIOUnit0PhyData_t));
+       sas_iounit_pg0 = kzalloc(sz, GFP_KERNEL);
+       if (!sas_iounit_pg0) {
+               printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
+                   ioc->name, __FILE__, __LINE__, __func__);
+               return;
+       }
+       if (!(mpt2sas_config_get_sas_iounit_pg0(ioc, &mpi_reply,
+           sas_iounit_pg0, sz))) {
+               ioc_status = le16_to_cpu(mpi_reply.IOCStatus) &
+                   MPI2_IOCSTATUS_MASK;
+               if (ioc_status != MPI2_IOCSTATUS_SUCCESS)
+                       goto out;
+               for (i = 0; i < ioc->sas_hba.num_phys ; i++) {
+                       ioc->sas_hba.phy[i].handle =
+                           le16_to_cpu(sas_iounit_pg0->PhyData[i].
+                               ControllerDevHandle);
+                       if (update)
+                               _scsih_link_change(ioc,
+                                   ioc->sas_hba.phy[i].handle,
+                                   le16_to_cpu(sas_iounit_pg0->PhyData[i].
+                                   AttachedDevHandle), i,
+                                   sas_iounit_pg0->PhyData[i].
+                                   NegotiatedLinkRate >> 4);
+               }
+       }
+
+ out:
+       kfree(sas_iounit_pg0);
+}
+
+/**
+ * _scsih_sas_host_add - create sas host object
+ * @ioc: per adapter object
+ *
+ * Creating host side data object, stored in ioc->sas_hba
+ *
+ * Return nothing.
+ */
+static void
+_scsih_sas_host_add(struct MPT2SAS_ADAPTER *ioc)
+{
+       int i;
+       Mpi2ConfigReply_t mpi_reply;
+       Mpi2SasIOUnitPage0_t *sas_iounit_pg0 = NULL;
+       Mpi2SasIOUnitPage1_t *sas_iounit_pg1 = NULL;
+       Mpi2SasPhyPage0_t phy_pg0;
+       Mpi2SasDevicePage0_t sas_device_pg0;
+       Mpi2SasEnclosurePage0_t enclosure_pg0;
+       u16 ioc_status;
+       u16 sz;
+       u16 device_missing_delay;
+
+       mpt2sas_config_get_number_hba_phys(ioc, &ioc->sas_hba.num_phys);
+       if (!ioc->sas_hba.num_phys) {
+               printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
+                   ioc->name, __FILE__, __LINE__, __func__);
+               return;
+       }
+
+       /* sas_iounit page 0 */
+       sz = offsetof(Mpi2SasIOUnitPage0_t, PhyData) + (ioc->sas_hba.num_phys *
+           sizeof(Mpi2SasIOUnit0PhyData_t));
+       sas_iounit_pg0 = kzalloc(sz, GFP_KERNEL);
+       if (!sas_iounit_pg0) {
+               printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
+                   ioc->name, __FILE__, __LINE__, __func__);
+               return;
+       }
+       if ((mpt2sas_config_get_sas_iounit_pg0(ioc, &mpi_reply,
+           sas_iounit_pg0, sz))) {
+               printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
+                   ioc->name, __FILE__, __LINE__, __func__);
+               goto out;
+       }
+       ioc_status = le16_to_cpu(mpi_reply.IOCStatus) &
+           MPI2_IOCSTATUS_MASK;
+       if (ioc_status != MPI2_IOCSTATUS_SUCCESS) {
+               printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
+                   ioc->name, __FILE__, __LINE__, __func__);
+               goto out;
+       }
+
+       /* sas_iounit page 1 */
+       sz = offsetof(Mpi2SasIOUnitPage1_t, PhyData) + (ioc->sas_hba.num_phys *
+           sizeof(Mpi2SasIOUnit1PhyData_t));
+       sas_iounit_pg1 = kzalloc(sz, GFP_KERNEL);
+       if (!sas_iounit_pg1) {
+               printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
+                   ioc->name, __FILE__, __LINE__, __func__);
+               goto out;
+       }
+       if ((mpt2sas_config_get_sas_iounit_pg1(ioc, &mpi_reply,
+           sas_iounit_pg1, sz))) {
+               printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
+                   ioc->name, __FILE__, __LINE__, __func__);
+               goto out;
+       }
+       ioc_status = le16_to_cpu(mpi_reply.IOCStatus) &
+           MPI2_IOCSTATUS_MASK;
+       if (ioc_status != MPI2_IOCSTATUS_SUCCESS) {
+               printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
+                   ioc->name, __FILE__, __LINE__, __func__);
+               goto out;
+       }
+
+       ioc->io_missing_delay =
+           le16_to_cpu(sas_iounit_pg1->IODeviceMissingDelay);
+       device_missing_delay =
+           le16_to_cpu(sas_iounit_pg1->ReportDeviceMissingDelay);
+       if (device_missing_delay & MPI2_SASIOUNIT1_REPORT_MISSING_UNIT_16)
+               ioc->device_missing_delay = (device_missing_delay &
+                   MPI2_SASIOUNIT1_REPORT_MISSING_TIMEOUT_MASK) * 16;
+       else
+               ioc->device_missing_delay = device_missing_delay &
+                   MPI2_SASIOUNIT1_REPORT_MISSING_TIMEOUT_MASK;
+
+       ioc->sas_hba.parent_dev = &ioc->shost->shost_gendev;
+       ioc->sas_hba.phy = kcalloc(ioc->sas_hba.num_phys,
+           sizeof(struct _sas_phy), GFP_KERNEL);
+       if (!ioc->sas_hba.phy) {
+               printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
+                   ioc->name, __FILE__, __LINE__, __func__);
+               goto out;
+       }
+       for (i = 0; i < ioc->sas_hba.num_phys ; i++) {
+               if ((mpt2sas_config_get_phy_pg0(ioc, &mpi_reply, &phy_pg0,
+                   i))) {
+                       printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
+                           ioc->name, __FILE__, __LINE__, __func__);
+                       goto out;
+               }
+               ioc_status = le16_to_cpu(mpi_reply.IOCStatus) &
+                   MPI2_IOCSTATUS_MASK;
+               if (ioc_status != MPI2_IOCSTATUS_SUCCESS) {
+                       printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
+                           ioc->name, __FILE__, __LINE__, __func__);
+                       goto out;
+               }
+               ioc->sas_hba.phy[i].handle =
+                   le16_to_cpu(sas_iounit_pg0->PhyData[i].ControllerDevHandle);
+               ioc->sas_hba.phy[i].phy_id = i;
+               mpt2sas_transport_add_host_phy(ioc, &ioc->sas_hba.phy[i],
+                   phy_pg0, ioc->sas_hba.parent_dev);
+       }
+       if ((mpt2sas_config_get_sas_device_pg0(ioc, &mpi_reply, &sas_device_pg0,
+           MPI2_SAS_DEVICE_PGAD_FORM_HANDLE, ioc->sas_hba.phy[0].handle))) {
+               printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
+                   ioc->name, __FILE__, __LINE__, __func__);
+               goto out;
+       }
+       ioc->sas_hba.handle = le16_to_cpu(sas_device_pg0.DevHandle);
+       ioc->sas_hba.enclosure_handle =
+           le16_to_cpu(sas_device_pg0.EnclosureHandle);
+       ioc->sas_hba.sas_address = le64_to_cpu(sas_device_pg0.SASAddress);
+       printk(MPT2SAS_INFO_FMT "host_add: handle(0x%04x), "
+           "sas_addr(0x%016llx), phys(%d)\n", ioc->name, ioc->sas_hba.handle,
+           (unsigned long long) ioc->sas_hba.sas_address,
+           ioc->sas_hba.num_phys) ;
+
+       if (ioc->sas_hba.enclosure_handle) {
+               if (!(mpt2sas_config_get_enclosure_pg0(ioc, &mpi_reply,
+                   &enclosure_pg0,
+                  MPI2_SAS_ENCLOS_PGAD_FORM_HANDLE,
+                  ioc->sas_hba.enclosure_handle))) {
+                       ioc->sas_hba.enclosure_logical_id =
+                           le64_to_cpu(enclosure_pg0.EnclosureLogicalID);
+               }
+       }
+
+ out:
+       kfree(sas_iounit_pg1);
+       kfree(sas_iounit_pg0);
+}
+
+/**
+ * _scsih_expander_add -  creating expander object
+ * @ioc: per adapter object
+ * @handle: expander handle
+ *
+ * Creating expander object, stored in ioc->sas_expander_list.
+ *
+ * Return 0 for success, else error.
+ */
+static int
+_scsih_expander_add(struct MPT2SAS_ADAPTER *ioc, u16 handle)
+{
+       struct _sas_node *sas_expander;
+       Mpi2ConfigReply_t mpi_reply;
+       Mpi2ExpanderPage0_t expander_pg0;
+       Mpi2ExpanderPage1_t expander_pg1;
+       Mpi2SasEnclosurePage0_t enclosure_pg0;
+       u32 ioc_status;
+       u16 parent_handle;
+       __le64 sas_address;
+       int i;
+       unsigned long flags;
+       struct _sas_port *mpt2sas_port;
+       int rc = 0;
+
+       if (!handle)
+               return -1;
+
+       if ((mpt2sas_config_get_expander_pg0(ioc, &mpi_reply, &expander_pg0,
+           MPI2_SAS_EXPAND_PGAD_FORM_HNDL, handle))) {
+               printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
+                   ioc->name, __FILE__, __LINE__, __func__);
+               return -1;
+       }
+
+       ioc_status = le16_to_cpu(mpi_reply.IOCStatus) &
+           MPI2_IOCSTATUS_MASK;
+       if (ioc_status != MPI2_IOCSTATUS_SUCCESS) {
+               printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
+                   ioc->name, __FILE__, __LINE__, __func__);
+               return -1;
+       }
+
+       /* handle out of order topology events */
+       parent_handle = le16_to_cpu(expander_pg0.ParentDevHandle);
+       if (parent_handle >= ioc->sas_hba.num_phys) {
+               spin_lock_irqsave(&ioc->sas_node_lock, flags);
+               sas_expander = mpt2sas_scsih_expander_find_by_handle(ioc,
+                   parent_handle);
+               spin_unlock_irqrestore(&ioc->sas_node_lock, flags);
+               if (!sas_expander) {
+                       rc = _scsih_expander_add(ioc, parent_handle);
+                       if (rc != 0)
+                               return rc;
+               }
+       }
+
+       sas_address = le64_to_cpu(expander_pg0.SASAddress);
+
+       spin_lock_irqsave(&ioc->sas_node_lock, flags);
+       sas_expander = mpt2sas_scsih_expander_find_by_sas_address(ioc,
+           sas_address);
+       spin_unlock_irqrestore(&ioc->sas_node_lock, flags);
+
+       if (sas_expander)
+               return 0;
+
+       sas_expander = kzalloc(sizeof(struct _sas_node),
+           GFP_KERNEL);
+       if (!sas_expander) {
+               printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
+                   ioc->name, __FILE__, __LINE__, __func__);
+               return -1;
+       }
+
+       sas_expander->handle = handle;
+       sas_expander->num_phys = expander_pg0.NumPhys;
+       sas_expander->parent_handle = parent_handle;
+       sas_expander->enclosure_handle =
+           le16_to_cpu(expander_pg0.EnclosureHandle);
+       sas_expander->sas_address = sas_address;
+
+       printk(MPT2SAS_INFO_FMT "expander_add: handle(0x%04x),"
+           " parent(0x%04x), sas_addr(0x%016llx), phys(%d)\n", ioc->name,
+           handle, sas_expander->parent_handle, (unsigned long long)
+           sas_expander->sas_address, sas_expander->num_phys);
+
+       if (!sas_expander->num_phys)
+               goto out_fail;
+       sas_expander->phy = kcalloc(sas_expander->num_phys,
+           sizeof(struct _sas_phy), GFP_KERNEL);
+       if (!sas_expander->phy) {
+               printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
+                   ioc->name, __FILE__, __LINE__, __func__);
+               rc = -1;
+               goto out_fail;
+       }
+
+       INIT_LIST_HEAD(&sas_expander->sas_port_list);
+       mpt2sas_port = mpt2sas_transport_port_add(ioc, handle,
+           sas_expander->parent_handle);
+       if (!mpt2sas_port) {
+               printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
+                   ioc->name, __FILE__, __LINE__, __func__);
+               rc = -1;
+               goto out_fail;
+       }
+       sas_expander->parent_dev = &mpt2sas_port->rphy->dev;
+
+       for (i = 0 ; i < sas_expander->num_phys ; i++) {
+               if ((mpt2sas_config_get_expander_pg1(ioc, &mpi_reply,
+                   &expander_pg1, i, handle))) {
+                       printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
+                           ioc->name, __FILE__, __LINE__, __func__);
+                       continue;
+               }
+               sas_expander->phy[i].handle = handle;
+               sas_expander->phy[i].phy_id = i;
+               mpt2sas_transport_add_expander_phy(ioc, &sas_expander->phy[i],
+                   expander_pg1, sas_expander->parent_dev);
+       }
+
+       if (sas_expander->enclosure_handle) {
+               if (!(mpt2sas_config_get_enclosure_pg0(ioc, &mpi_reply,
+                   &enclosure_pg0, MPI2_SAS_ENCLOS_PGAD_FORM_HANDLE,
+                  sas_expander->enclosure_handle))) {
+                       sas_expander->enclosure_logical_id =
+                           le64_to_cpu(enclosure_pg0.EnclosureLogicalID);
+               }
+       }
+
+       _scsih_expander_node_add(ioc, sas_expander);
+        return 0;
+
+ out_fail:
+
+       if (sas_expander)
+               kfree(sas_expander->phy);
+       kfree(sas_expander);
+       return rc;
+}
+
+/**
+ * _scsih_expander_remove - removing expander object
+ * @ioc: per adapter object
+ * @handle: expander handle
+ *
+ * Return nothing.
+ */
+static void
+_scsih_expander_remove(struct MPT2SAS_ADAPTER *ioc, u16 handle)
+{
+       struct _sas_node *sas_expander;
+       unsigned long flags;
+
+       spin_lock_irqsave(&ioc->sas_node_lock, flags);
+       sas_expander = mpt2sas_scsih_expander_find_by_handle(ioc, handle);
+       spin_unlock_irqrestore(&ioc->sas_node_lock, flags);
+       _scsih_expander_node_remove(ioc, sas_expander);
+}
+
+/**
+ * _scsih_add_device -  creating sas device object
+ * @ioc: per adapter object
+ * @handle: sas device handle
+ * @phy_num: phy number end device attached to
+ * @is_pd: is this hidden raid component
+ *
+ * Creating end device object, stored in ioc->sas_device_list.
+ *
+ * Returns 0 for success, non-zero for failure.
+ */
+static int
+_scsih_add_device(struct MPT2SAS_ADAPTER *ioc, u16 handle, u8 phy_num, u8 is_pd)
+{
+       Mpi2ConfigReply_t mpi_reply;
+       Mpi2SasDevicePage0_t sas_device_pg0;
+       Mpi2SasEnclosurePage0_t enclosure_pg0;
+       struct _sas_device *sas_device;
+       u32 ioc_status;
+       __le64 sas_address;
+       u32 device_info;
+       unsigned long flags;
+
+       if ((mpt2sas_config_get_sas_device_pg0(ioc, &mpi_reply, &sas_device_pg0,
+           MPI2_SAS_DEVICE_PGAD_FORM_HANDLE, handle))) {
+               printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
+                   ioc->name, __FILE__, __LINE__, __func__);
+               return -1;
+       }
+
+       ioc_status = le16_to_cpu(mpi_reply.IOCStatus) &
+           MPI2_IOCSTATUS_MASK;
+       if (ioc_status != MPI2_IOCSTATUS_SUCCESS) {
+               printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
+                   ioc->name, __FILE__, __LINE__, __func__);
+               return -1;
+       }
+
+       /* check if device is present */
+       if (!(le16_to_cpu(sas_device_pg0.Flags) &
+           MPI2_SAS_DEVICE0_FLAGS_DEVICE_PRESENT)) {
+               printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
+                   ioc->name, __FILE__, __LINE__, __func__);
+               printk(MPT2SAS_ERR_FMT "Flags = 0x%04x\n",
+                   ioc->name, le16_to_cpu(sas_device_pg0.Flags));
+               return -1;
+       }
+
+       /* check if there were any issus with discovery */
+       if (sas_device_pg0.AccessStatus ==
+           MPI2_SAS_DEVICE0_ASTATUS_SATA_INIT_FAILED) {
+               printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
+                   ioc->name, __FILE__, __LINE__, __func__);
+               printk(MPT2SAS_ERR_FMT "AccessStatus = 0x%02x\n",
+                   ioc->name, sas_device_pg0.AccessStatus);
+               return -1;
+       }
+
+       /* check if this is end device */
+       device_info = le32_to_cpu(sas_device_pg0.DeviceInfo);
+       if (!(_scsih_is_end_device(device_info))) {
+               printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
+                   ioc->name, __FILE__, __LINE__, __func__);
+               return -1;
+       }
+
+       sas_address = le64_to_cpu(sas_device_pg0.SASAddress);
+
+       spin_lock_irqsave(&ioc->sas_device_lock, flags);
+       sas_device = mpt2sas_scsih_sas_device_find_by_sas_address(ioc,
+           sas_address);
+       spin_unlock_irqrestore(&ioc->sas_device_lock, flags);
+
+       if (sas_device) {
+               _scsih_ublock_io_device(ioc, handle);
+               return 0;
+       }
+
+       sas_device = kzalloc(sizeof(struct _sas_device),
+           GFP_KERNEL);
+       if (!sas_device) {
+               printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
+                   ioc->name, __FILE__, __LINE__, __func__);
+               return -1;
+       }
+
+       sas_device->handle = handle;
+       sas_device->parent_handle =
+           le16_to_cpu(sas_device_pg0.ParentDevHandle);
+       sas_device->enclosure_handle =
+           le16_to_cpu(sas_device_pg0.EnclosureHandle);
+       sas_device->slot =
+           le16_to_cpu(sas_device_pg0.Slot);
+       sas_device->device_info = device_info;
+       sas_device->sas_address = sas_address;
+       sas_device->hidden_raid_component = is_pd;
+
+       /* get enclosure_logical_id */
+       if (!(mpt2sas_config_get_enclosure_pg0(ioc, &mpi_reply, &enclosure_pg0,
+          MPI2_SAS_ENCLOS_PGAD_FORM_HANDLE,
+          sas_device->enclosure_handle))) {
+               sas_device->enclosure_logical_id =
+                   le64_to_cpu(enclosure_pg0.EnclosureLogicalID);
+       }
+
+       /* get device name */
+       sas_device->device_name = le64_to_cpu(sas_device_pg0.DeviceName);
+
+       if (ioc->wait_for_port_enable_to_complete)
+               _scsih_sas_device_init_add(ioc, sas_device);
+       else
+               _scsih_sas_device_add(ioc, sas_device);
+
+       return 0;
+}
+
+/**
+ * _scsih_remove_device -  removing sas device object
+ * @ioc: per adapter object
+ * @handle: sas device handle
+ *
+ * Return nothing.
+ */
+static void
+_scsih_remove_device(struct MPT2SAS_ADAPTER *ioc, u16 handle)
+{
+       struct MPT2SAS_TARGET *sas_target_priv_data;
+       struct _sas_device *sas_device;
+       unsigned long flags;
+       Mpi2SasIoUnitControlReply_t mpi_reply;
+       Mpi2SasIoUnitControlRequest_t mpi_request;
+       u16 device_handle;
+
+       /* lookup sas_device */
+       spin_lock_irqsave(&ioc->sas_device_lock, flags);
+       sas_device = _scsih_sas_device_find_by_handle(ioc, handle);
+       if (!sas_device) {
+               spin_unlock_irqrestore(&ioc->sas_device_lock, flags);
+               return;
+       }
+
+       dewtprintk(ioc, printk(MPT2SAS_INFO_FMT "%s: enter: handle"
+           "(0x%04x)\n", ioc->name, __func__, handle));
+
+       if (sas_device->starget && sas_device->starget->hostdata) {
+               sas_target_priv_data = sas_device->starget->hostdata;
+               sas_target_priv_data->deleted = 1;
+       }
+       spin_unlock_irqrestore(&ioc->sas_device_lock, flags);
+
+       if (ioc->remove_host)
+               goto out;
+
+       /* Target Reset to flush out all the outstanding IO */
+       device_handle = (sas_device->hidden_raid_component) ?
+           sas_device->volume_handle : handle;
+       if (device_handle) {
+               dewtprintk(ioc, printk(MPT2SAS_INFO_FMT "issue target reset: "
+                   "handle(0x%04x)\n", ioc->name, device_handle));
+               mutex_lock(&ioc->tm_cmds.mutex);
+               mpt2sas_scsih_issue_tm(ioc, device_handle, 0,
+                   MPI2_SCSITASKMGMT_TASKTYPE_TARGET_RESET, 0, 10);
+               ioc->tm_cmds.status = MPT2_CMD_NOT_USED;
+               mutex_unlock(&ioc->tm_cmds.mutex);
+               dewtprintk(ioc, printk(MPT2SAS_INFO_FMT "issue target reset "
+                   "done: handle(0x%04x)\n", ioc->name, device_handle));
+       }
+
+       /* SAS_IO_UNIT_CNTR - send REMOVE_DEVICE */
+       dewtprintk(ioc, printk(MPT2SAS_INFO_FMT "sas_iounit: handle"
+           "(0x%04x)\n", ioc->name, handle));
+       memset(&mpi_request, 0, sizeof(Mpi2SasIoUnitControlRequest_t));
+       mpi_request.Function = MPI2_FUNCTION_SAS_IO_UNIT_CONTROL;
+       mpi_request.Operation = MPI2_SAS_OP_REMOVE_DEVICE;
+       mpi_request.DevHandle = handle;
+       mpi_request.VF_ID = 0;
+       if ((mpt2sas_base_sas_iounit_control(ioc, &mpi_reply,
+           &mpi_request)) != 0) {
+               printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
+                   ioc->name, __FILE__, __LINE__, __func__);
+       }
+
+       dewtprintk(ioc, printk(MPT2SAS_INFO_FMT "sas_iounit: ioc_status"
+           "(0x%04x), loginfo(0x%08x)\n", ioc->name,
+           le16_to_cpu(mpi_reply.IOCStatus),
+           le32_to_cpu(mpi_reply.IOCLogInfo)));
+
+ out:
+       mpt2sas_transport_port_remove(ioc, sas_device->sas_address,
+           sas_device->parent_handle);
+
+       printk(MPT2SAS_INFO_FMT "removing handle(0x%04x), sas_addr"
+           "(0x%016llx)\n", ioc->name, sas_device->handle,
+           (unsigned long long) sas_device->sas_address);
+       _scsih_sas_device_remove(ioc, sas_device);
+
+       dewtprintk(ioc, printk(MPT2SAS_INFO_FMT "%s: exit: handle"
+           "(0x%04x)\n", ioc->name, __func__, handle));
+}
+
+#ifdef CONFIG_SCSI_MPT2SAS_LOGGING
+/**
+ * _scsih_sas_topology_change_event_debug - debug for topology event
+ * @ioc: per adapter object
+ * @event_data: event data payload
+ * Context: user.
+ */
+static void
+_scsih_sas_topology_change_event_debug(struct MPT2SAS_ADAPTER *ioc,
+    Mpi2EventDataSasTopologyChangeList_t *event_data)
+{
+       int i;
+       u16 handle;
+       u16 reason_code;
+       u8 phy_number;
+       char *status_str = NULL;
+       char link_rate[25];
+
+       switch (event_data->ExpStatus) {
+       case MPI2_EVENT_SAS_TOPO_ES_ADDED:
+               status_str = "add";
+               break;
+       case MPI2_EVENT_SAS_TOPO_ES_NOT_RESPONDING:
+               status_str = "remove";
+               break;
+       case MPI2_EVENT_SAS_TOPO_ES_RESPONDING:
+               status_str =  "responding";
+               break;
+       case MPI2_EVENT_SAS_TOPO_ES_DELAY_NOT_RESPONDING:
+               status_str = "remove delay";
+               break;
+       default:
+               status_str = "unknown status";
+               break;
+       }
+       printk(MPT2SAS_DEBUG_FMT "sas topology change: (%s)\n",
+           ioc->name, status_str);
+       printk(KERN_DEBUG "\thandle(0x%04x), enclosure_handle(0x%04x) "
+           "start_phy(%02d), count(%d)\n",
+           le16_to_cpu(event_data->ExpanderDevHandle),
+           le16_to_cpu(event_data->EnclosureHandle),
+           event_data->StartPhyNum, event_data->NumEntries);
+       for (i = 0; i < event_data->NumEntries; i++) {
+               handle = le16_to_cpu(event_data->PHY[i].AttachedDevHandle);
+               if (!handle)
+                       continue;
+               phy_number = event_data->StartPhyNum + i;
+               reason_code = event_data->PHY[i].PhyStatus &
+                   MPI2_EVENT_SAS_TOPO_RC_MASK;
+               switch (reason_code) {
+               case MPI2_EVENT_SAS_TOPO_RC_TARG_ADDED:
+                       snprintf(link_rate, 25, ": add, link(0x%02x)",
+                           (event_data->PHY[i].LinkRate >> 4));
+                       status_str = link_rate;
+                       break;
+               case MPI2_EVENT_SAS_TOPO_RC_TARG_NOT_RESPONDING:
+                       status_str = ": remove";
+                       break;
+               case MPI2_EVENT_SAS_TOPO_RC_DELAY_NOT_RESPONDING:
+                       status_str = ": remove_delay";
+                       break;
+               case MPI2_EVENT_SAS_TOPO_RC_PHY_CHANGED:
+                       snprintf(link_rate, 25, ": link(0x%02x)",
+                           (event_data->PHY[i].LinkRate >> 4));
+                       status_str = link_rate;
+                       break;
+               case MPI2_EVENT_SAS_TOPO_RC_NO_CHANGE:
+                       status_str = ": responding";
+                       break;
+               default:
+                       status_str = ": unknown";
+                       break;
+               }
+               printk(KERN_DEBUG "\tphy(%02d), attached_handle(0x%04x)%s\n",
+                   phy_number, handle, status_str);
+       }
+}
+#endif
+
+/**
+ * _scsih_sas_topology_change_event - handle topology changes
+ * @ioc: per adapter object
+ * @VF_ID:
+ * @event_data: event data payload
+ * fw_event:
+ * Context: user.
+ *
+ */
+static void
+_scsih_sas_topology_change_event(struct MPT2SAS_ADAPTER *ioc, u8 VF_ID,
+    Mpi2EventDataSasTopologyChangeList_t *event_data,
+    struct fw_event_work *fw_event)
+{
+       int i;
+       u16 parent_handle, handle;
+       u16 reason_code;
+       u8 phy_number;
+       struct _sas_node *sas_expander;
+       unsigned long flags;
+       u8 link_rate_;
+
+#ifdef CONFIG_SCSI_MPT2SAS_LOGGING
+       if (ioc->logging_level & MPT_DEBUG_EVENT_WORK_TASK)
+               _scsih_sas_topology_change_event_debug(ioc, event_data);
+#endif
+
+       if (!ioc->sas_hba.num_phys)
+               _scsih_sas_host_add(ioc);
+       else
+               _scsih_sas_host_refresh(ioc, 0);
+
+       if (fw_event->ignore) {
+               dewtprintk(ioc, printk(MPT2SAS_DEBUG_FMT "ignoring expander "
+                   "event\n", ioc->name));
+               return;
+       }
+
+       parent_handle = le16_to_cpu(event_data->ExpanderDevHandle);
+
+       /* handle expander add */
+       if (event_data->ExpStatus == MPI2_EVENT_SAS_TOPO_ES_ADDED)
+               if (_scsih_expander_add(ioc, parent_handle) != 0)
+                       return;
+
+       /* handle siblings events */
+       for (i = 0; i < event_data->NumEntries; i++) {
+               if (fw_event->ignore) {
+                       dewtprintk(ioc, printk(MPT2SAS_DEBUG_FMT "ignoring "
+                           "expander event\n", ioc->name));
+                       return;
+               }
+               if (event_data->PHY[i].PhyStatus &
+                   MPI2_EVENT_SAS_TOPO_PHYSTATUS_VACANT)
+                       continue;
+               handle = le16_to_cpu(event_data->PHY[i].AttachedDevHandle);
+               if (!handle)
+                       continue;
+               phy_number = event_data->StartPhyNum + i;
+               reason_code = event_data->PHY[i].PhyStatus &
+                   MPI2_EVENT_SAS_TOPO_RC_MASK;
+               link_rate_ = event_data->PHY[i].LinkRate >> 4;
+               switch (reason_code) {
+               case MPI2_EVENT_SAS_TOPO_RC_PHY_CHANGED:
+               case MPI2_EVENT_SAS_TOPO_RC_TARG_ADDED:
+                       if (!parent_handle) {
+                               if (phy_number < ioc->sas_hba.num_phys)
+                                       _scsih_link_change(ioc,
+                                          ioc->sas_hba.phy[phy_number].handle,
+                                          handle, phy_number, link_rate_);
+                       } else {
+                               spin_lock_irqsave(&ioc->sas_node_lock, flags);
+                               sas_expander =
+                                   mpt2sas_scsih_expander_find_by_handle(ioc,
+                                       parent_handle);
+                               spin_unlock_irqrestore(&ioc->sas_node_lock,
+                                   flags);
+                               if (sas_expander) {
+                                       if (phy_number < sas_expander->num_phys)
+                                               _scsih_link_change(ioc,
+                                                  sas_expander->
+                                                  phy[phy_number].handle,
+                                                  handle, phy_number,
+                                                  link_rate_);
+                               }
+                       }
+                       if (reason_code == MPI2_EVENT_SAS_TOPO_RC_PHY_CHANGED) {
+                               if (link_rate_ >= MPI2_SAS_NEG_LINK_RATE_1_5)
+                                       _scsih_ublock_io_device(ioc, handle);
+                       }
+                       if (reason_code == MPI2_EVENT_SAS_TOPO_RC_TARG_ADDED) {
+                               if (link_rate_ < MPI2_SAS_NEG_LINK_RATE_1_5)
+                                       break;
+                               _scsih_add_device(ioc, handle, phy_number, 0);
+                       }
+                       break;
+               case MPI2_EVENT_SAS_TOPO_RC_TARG_NOT_RESPONDING:
+                       _scsih_remove_device(ioc, handle);
+                       break;
+               }
+       }
+
+       /* handle expander removal */
+       if (event_data->ExpStatus == MPI2_EVENT_SAS_TOPO_ES_NOT_RESPONDING)
+               _scsih_expander_remove(ioc, parent_handle);
+
+}
+
+#ifdef CONFIG_SCSI_MPT2SAS_LOGGING
+/**
+ * _scsih_sas_device_status_change_event_debug - debug for device event
+ * @event_data: event data payload
+ * Context: user.
+ *
+ * Return nothing.
+ */
+static void
+_scsih_sas_device_status_change_event_debug(struct MPT2SAS_ADAPTER *ioc,
+    Mpi2EventDataSasDeviceStatusChange_t *event_data)
+{
+       char *reason_str = NULL;
+
+       switch (event_data->ReasonCode) {
+       case MPI2_EVENT_SAS_DEV_STAT_RC_SMART_DATA:
+               reason_str = "smart data";
+               break;
+       case MPI2_EVENT_SAS_DEV_STAT_RC_UNSUPPORTED:
+               reason_str = "unsupported device discovered";
+               break;
+       case MPI2_EVENT_SAS_DEV_STAT_RC_INTERNAL_DEVICE_RESET:
+               reason_str = "internal device reset";
+               break;
+       case MPI2_EVENT_SAS_DEV_STAT_RC_TASK_ABORT_INTERNAL:
+               reason_str = "internal task abort";
+               break;
+       case MPI2_EVENT_SAS_DEV_STAT_RC_ABORT_TASK_SET_INTERNAL:
+               reason_str = "internal task abort set";
+               break;
+       case MPI2_EVENT_SAS_DEV_STAT_RC_CLEAR_TASK_SET_INTERNAL:
+               reason_str = "internal clear task set";
+               break;
+       case MPI2_EVENT_SAS_DEV_STAT_RC_QUERY_TASK_INTERNAL:
+               reason_str = "internal query task";
+               break;
+       case MPI2_EVENT_SAS_DEV_STAT_RC_SATA_INIT_FAILURE:
+               reason_str = "sata init failure";
+               break;
+       case MPI2_EVENT_SAS_DEV_STAT_RC_CMP_INTERNAL_DEV_RESET:
+               reason_str = "internal device reset complete";
+               break;
+       case MPI2_EVENT_SAS_DEV_STAT_RC_CMP_TASK_ABORT_INTERNAL:
+               reason_str = "internal task abort complete";
+               break;
+       case MPI2_EVENT_SAS_DEV_STAT_RC_ASYNC_NOTIFICATION:
+               reason_str = "internal async notification";
+               break;
+       default:
+               reason_str = "unknown reason";
+               break;
+       }
+       printk(MPT2SAS_DEBUG_FMT "device status change: (%s)\n"
+           "\thandle(0x%04x), sas address(0x%016llx)", ioc->name,
+           reason_str, le16_to_cpu(event_data->DevHandle),
+           (unsigned long long)le64_to_cpu(event_data->SASAddress));
+       if (event_data->ReasonCode == MPI2_EVENT_SAS_DEV_STAT_RC_SMART_DATA)
+               printk(MPT2SAS_DEBUG_FMT ", ASC(0x%x), ASCQ(0x%x)\n", ioc->name,
+                   event_data->ASC, event_data->ASCQ);
+       printk(KERN_INFO "\n");
+}
+#endif
+
+/**
+ * _scsih_sas_device_status_change_event - handle device status change
+ * @ioc: per adapter object
+ * @VF_ID:
+ * @event_data: event data payload
+ * Context: user.
+ *
+ * Return nothing.
+ */
+static void
+_scsih_sas_device_status_change_event(struct MPT2SAS_ADAPTER *ioc, u8 VF_ID,
+    Mpi2EventDataSasDeviceStatusChange_t *event_data)
+{
+#ifdef CONFIG_SCSI_MPT2SAS_LOGGING
+       if (ioc->logging_level & MPT_DEBUG_EVENT_WORK_TASK)
+               _scsih_sas_device_status_change_event_debug(ioc, event_data);
+#endif
+}
+
+#ifdef CONFIG_SCSI_MPT2SAS_LOGGING
+/**
+ * _scsih_sas_enclosure_dev_status_change_event_debug - debug for enclosure event
+ * @ioc: per adapter object
+ * @event_data: event data payload
+ * Context: user.
+ *
+ * Return nothing.
+ */
+static void
+_scsih_sas_enclosure_dev_status_change_event_debug(struct MPT2SAS_ADAPTER *ioc,
+    Mpi2EventDataSasEnclDevStatusChange_t *event_data)
+{
+       char *reason_str = NULL;
+
+       switch (event_data->ReasonCode) {
+       case MPI2_EVENT_SAS_ENCL_RC_ADDED:
+               reason_str = "enclosure add";
+               break;
+       case MPI2_EVENT_SAS_ENCL_RC_NOT_RESPONDING:
+               reason_str = "enclosure remove";
+               break;
+       default:
+               reason_str = "unknown reason";
+               break;
+       }
+
+       printk(MPT2SAS_DEBUG_FMT "enclosure status change: (%s)\n"
+           "\thandle(0x%04x), enclosure logical id(0x%016llx)"
+           " number slots(%d)\n", ioc->name, reason_str,
+           le16_to_cpu(event_data->EnclosureHandle),
+           (unsigned long long)le64_to_cpu(event_data->EnclosureLogicalID),
+           le16_to_cpu(event_data->StartSlot));
+}
+#endif
+
+/**
+ * _scsih_sas_enclosure_dev_status_change_event - handle enclosure events
+ * @ioc: per adapter object
+ * @VF_ID:
+ * @event_data: event data payload
+ * Context: user.
+ *
+ * Return nothing.
+ */
+static void
+_scsih_sas_enclosure_dev_status_change_event(struct MPT2SAS_ADAPTER *ioc,
+    u8 VF_ID, Mpi2EventDataSasEnclDevStatusChange_t *event_data)
+{
+#ifdef CONFIG_SCSI_MPT2SAS_LOGGING
+       if (ioc->logging_level & MPT_DEBUG_EVENT_WORK_TASK)
+               _scsih_sas_enclosure_dev_status_change_event_debug(ioc,
+                    event_data);
+#endif
+}
+
+/**
+ * _scsih_sas_broadcast_primative_event - handle broadcast events
+ * @ioc: per adapter object
+ * @event_data: event data payload
+ * Context: user.
+ *
+ * Return nothing.
+ */
+static void
+_scsih_sas_broadcast_primative_event(struct MPT2SAS_ADAPTER *ioc, u8 VF_ID,
+    Mpi2EventDataSasBroadcastPrimitive_t *event_data)
+{
+       struct scsi_cmnd *scmd;
+       u16 smid, handle;
+       u32 lun;
+       struct MPT2SAS_DEVICE *sas_device_priv_data;
+       u32 termination_count;
+       u32 query_count;
+       Mpi2SCSITaskManagementReply_t *mpi_reply;
+
+       dewtprintk(ioc, printk(MPT2SAS_DEBUG_FMT "broadcast primative: "
+           "phy number(%d), width(%d)\n", ioc->name, event_data->PhyNum,
+           event_data->PortWidth));
+
+       dtmprintk(ioc, printk(MPT2SAS_DEBUG_FMT "%s: enter\n", ioc->name,
+           __func__));
+
+       mutex_lock(&ioc->tm_cmds.mutex);
+       termination_count = 0;
+       query_count = 0;
+       mpi_reply = ioc->tm_cmds.reply;
+       for (smid = 1; smid <= ioc->request_depth; smid++) {
+               scmd = _scsih_scsi_lookup_get(ioc, smid);
+               if (!scmd)
+                       continue;
+               sas_device_priv_data = scmd->device->hostdata;
+               if (!sas_device_priv_data || !sas_device_priv_data->sas_target)
+                       continue;
+                /* skip hidden raid components */
+               if (sas_device_priv_data->sas_target->flags &
+                   MPT_TARGET_FLAGS_RAID_COMPONENT)
+                       continue;
+                /* skip volumes */
+               if (sas_device_priv_data->sas_target->flags &
+                   MPT_TARGET_FLAGS_VOLUME)
+                       continue;
+
+               handle = sas_device_priv_data->sas_target->handle;
+               lun = sas_device_priv_data->lun;
+               query_count++;
+
+               mpt2sas_scsih_issue_tm(ioc, handle, lun,
+                   MPI2_SCSITASKMGMT_TASKTYPE_QUERY_TASK, smid, 30);
+               termination_count += le32_to_cpu(mpi_reply->TerminationCount);
+
+               if ((mpi_reply->IOCStatus == MPI2_IOCSTATUS_SUCCESS) &&
+                   (mpi_reply->ResponseCode ==
+                    MPI2_SCSITASKMGMT_RSP_TM_SUCCEEDED ||
+                    mpi_reply->ResponseCode ==
+                    MPI2_SCSITASKMGMT_RSP_IO_QUEUED_ON_IOC))
+                       continue;
+
+               mpt2sas_scsih_issue_tm(ioc, handle, lun,
+                   MPI2_SCSITASKMGMT_TASKTYPE_ABRT_TASK_SET, smid, 30);
+               termination_count += le32_to_cpu(mpi_reply->TerminationCount);
+       }
+       ioc->tm_cmds.status = MPT2_CMD_NOT_USED;
+       ioc->broadcast_aen_busy = 0;
+       mutex_unlock(&ioc->tm_cmds.mutex);
+
+       dtmprintk(ioc, printk(MPT2SAS_DEBUG_FMT
+           "%s - exit, query_count = %d termination_count = %d\n",
+           ioc->name, __func__, query_count, termination_count));
+}
+
+/**
+ * _scsih_sas_discovery_event - handle discovery events
+ * @ioc: per adapter object
+ * @event_data: event data payload
+ * Context: user.
+ *
+ * Return nothing.
+ */
+static void
+_scsih_sas_discovery_event(struct MPT2SAS_ADAPTER *ioc, u8 VF_ID,
+    Mpi2EventDataSasDiscovery_t *event_data)
+{
+#ifdef CONFIG_SCSI_MPT2SAS_LOGGING
+       if (ioc->logging_level & MPT_DEBUG_EVENT_WORK_TASK) {
+               printk(MPT2SAS_DEBUG_FMT "discovery event: (%s)", ioc->name,
+                   (event_data->ReasonCode == MPI2_EVENT_SAS_DISC_RC_STARTED) ?
+                   "start" : "stop");
+       if (event_data->DiscoveryStatus)
+               printk(MPT2SAS_DEBUG_FMT ", discovery_status(0x%08x)",
+                   ioc->name, le32_to_cpu(event_data->DiscoveryStatus));
+       printk("\n");
+       }
+#endif
+
+       if (event_data->ReasonCode == MPI2_EVENT_SAS_DISC_RC_STARTED &&
+           !ioc->sas_hba.num_phys)
+               _scsih_sas_host_add(ioc);
+}
+
+/**
+ * _scsih_reprobe_lun - reprobing lun
+ * @sdev: scsi device struct
+ * @no_uld_attach: sdev->no_uld_attach flag setting
+ *
+ **/
+static void
+_scsih_reprobe_lun(struct scsi_device *sdev, void *no_uld_attach)
+{
+       int rc;
+
+       sdev->no_uld_attach = no_uld_attach ? 1 : 0;
+       sdev_printk(KERN_INFO, sdev, "%s raid component\n",
+           sdev->no_uld_attach ? "hidding" : "exposing");
+       rc = scsi_device_reprobe(sdev);
+}
+
+/**
+ * _scsih_reprobe_target - reprobing target
+ * @starget: scsi target struct
+ * @no_uld_attach: sdev->no_uld_attach flag setting
+ *
+ * Note: no_uld_attach flag determines whether the disk device is attached
+ * to block layer. A value of `1` means to not attach.
+ **/
+static void
+_scsih_reprobe_target(struct scsi_target *starget, int no_uld_attach)
+{
+       struct MPT2SAS_TARGET *sas_target_priv_data = starget->hostdata;
+
+       if (no_uld_attach)
+               sas_target_priv_data->flags |= MPT_TARGET_FLAGS_RAID_COMPONENT;
+       else
+               sas_target_priv_data->flags &= ~MPT_TARGET_FLAGS_RAID_COMPONENT;
+
+       starget_for_each_device(starget, no_uld_attach ? (void *)1 : NULL,
+           _scsih_reprobe_lun);
+}
+/**
+ * _scsih_sas_volume_add - add new volume
+ * @ioc: per adapter object
+ * @element: IR config element data
+ * Context: user.
+ *
+ * Return nothing.
+ */
+static void
+_scsih_sas_volume_add(struct MPT2SAS_ADAPTER *ioc,
+    Mpi2EventIrConfigElement_t *element)
+{
+       struct _raid_device *raid_device;
+       unsigned long flags;
+       u64 wwid;
+       u16 handle = le16_to_cpu(element->VolDevHandle);
+       int rc;
+
+#if 0 /* RAID_HACKS */
+       if (le32_to_cpu(event_data->Flags) &
+           MPI2_EVENT_IR_CHANGE_FLAGS_FOREIGN_CONFIG)
+               return;
+#endif
+
+       mpt2sas_config_get_volume_wwid(ioc, handle, &wwid);
+       if (!wwid) {
+               printk(MPT2SAS_ERR_FMT
+                   "failure at %s:%d/%s()!\n", ioc->name,
+                   __FILE__, __LINE__, __func__);
+               return;
+       }
+
+       spin_lock_irqsave(&ioc->raid_device_lock, flags);
+       raid_device = _scsih_raid_device_find_by_wwid(ioc, wwid);
+       spin_unlock_irqrestore(&ioc->raid_device_lock, flags);
+
+       if (raid_device)
+               return;
+
+       raid_device = kzalloc(sizeof(struct _raid_device), GFP_KERNEL);
+       if (!raid_device) {
+               printk(MPT2SAS_ERR_FMT
+                   "failure at %s:%d/%s()!\n", ioc->name,
+                   __FILE__, __LINE__, __func__);
+               return;
+       }
+
+       raid_device->id = ioc->sas_id++;
+       raid_device->channel = RAID_CHANNEL;
+       raid_device->handle = handle;
+       raid_device->wwid = wwid;
+       _scsih_raid_device_add(ioc, raid_device);
+       if (!ioc->wait_for_port_enable_to_complete) {
+               rc = scsi_add_device(ioc->shost, RAID_CHANNEL,
+                   raid_device->id, 0);
+               if (rc)
+                       _scsih_raid_device_remove(ioc, raid_device);
+       } else
+               _scsih_determine_boot_device(ioc, raid_device, 1);
+}
+
+/**
+ * _scsih_sas_volume_delete - delete volume
+ * @ioc: per adapter object
+ * @element: IR config element data
+ * Context: user.
+ *
+ * Return nothing.
+ */
+static void
+_scsih_sas_volume_delete(struct MPT2SAS_ADAPTER *ioc,
+    Mpi2EventIrConfigElement_t *element)
+{
+       struct _raid_device *raid_device;
+       u16 handle = le16_to_cpu(element->VolDevHandle);
+       unsigned long flags;
+       struct MPT2SAS_TARGET *sas_target_priv_data;
+
+#if 0 /* RAID_HACKS */
+       if (le32_to_cpu(event_data->Flags) &
+           MPI2_EVENT_IR_CHANGE_FLAGS_FOREIGN_CONFIG)
+               return;
+#endif
+
+       spin_lock_irqsave(&ioc->raid_device_lock, flags);
+       raid_device = _scsih_raid_device_find_by_handle(ioc, handle);
+       spin_unlock_irqrestore(&ioc->raid_device_lock, flags);
+       if (!raid_device)
+               return;
+       if (raid_device->starget) {
+               sas_target_priv_data = raid_device->starget->hostdata;
+               sas_target_priv_data->deleted = 1;
+               scsi_remove_target(&raid_device->starget->dev);
+       }
+       _scsih_raid_device_remove(ioc, raid_device);
+}
+
+/**
+ * _scsih_sas_pd_expose - expose pd component to /dev/sdX
+ * @ioc: per adapter object
+ * @element: IR config element data
+ * Context: user.
+ *
+ * Return nothing.
+ */
+static void
+_scsih_sas_pd_expose(struct MPT2SAS_ADAPTER *ioc,
+    Mpi2EventIrConfigElement_t *element)
+{
+       struct _sas_device *sas_device;
+       unsigned long flags;
+       u16 handle = le16_to_cpu(element->PhysDiskDevHandle);
+
+       spin_lock_irqsave(&ioc->sas_device_lock, flags);
+       sas_device = _scsih_sas_device_find_by_handle(ioc, handle);
+       spin_unlock_irqrestore(&ioc->sas_device_lock, flags);
+       if (!sas_device)
+               return;
+
+       /* exposing raid component */
+       sas_device->volume_handle = 0;
+       sas_device->volume_wwid = 0;
+       sas_device->hidden_raid_component = 0;
+       _scsih_reprobe_target(sas_device->starget, 0);
+}
+
+/**
+ * _scsih_sas_pd_hide - hide pd component from /dev/sdX
+ * @ioc: per adapter object
+ * @element: IR config element data
+ * Context: user.
+ *
+ * Return nothing.
+ */
+static void
+_scsih_sas_pd_hide(struct MPT2SAS_ADAPTER *ioc,
+    Mpi2EventIrConfigElement_t *element)
+{
+       struct _sas_device *sas_device;
+       unsigned long flags;
+       u16 handle = le16_to_cpu(element->PhysDiskDevHandle);
+
+       spin_lock_irqsave(&ioc->sas_device_lock, flags);
+       sas_device = _scsih_sas_device_find_by_handle(ioc, handle);
+       spin_unlock_irqrestore(&ioc->sas_device_lock, flags);
+       if (!sas_device)
+               return;
+
+       /* hiding raid component */
+       mpt2sas_config_get_volume_handle(ioc, handle,
+           &sas_device->volume_handle);
+       mpt2sas_config_get_volume_wwid(ioc, sas_device->volume_handle,
+           &sas_device->volume_wwid);
+       sas_device->hidden_raid_component = 1;
+       _scsih_reprobe_target(sas_device->starget, 1);
+}
+
+/**
+ * _scsih_sas_pd_delete - delete pd component
+ * @ioc: per adapter object
+ * @element: IR config element data
+ * Context: user.
+ *
+ * Return nothing.
+ */
+static void
+_scsih_sas_pd_delete(struct MPT2SAS_ADAPTER *ioc,
+    Mpi2EventIrConfigElement_t *element)
+{
+       struct _sas_device *sas_device;
+       unsigned long flags;
+       u16 handle = le16_to_cpu(element->PhysDiskDevHandle);
+
+       spin_lock_irqsave(&ioc->sas_device_lock, flags);
+       sas_device = _scsih_sas_device_find_by_handle(ioc, handle);
+       spin_unlock_irqrestore(&ioc->sas_device_lock, flags);
+       if (!sas_device)
+               return;
+       _scsih_remove_device(ioc, handle);
+}
+
+/**
+ * _scsih_sas_pd_add - remove pd component
+ * @ioc: per adapter object
+ * @element: IR config element data
+ * Context: user.
+ *
+ * Return nothing.
+ */
+static void
+_scsih_sas_pd_add(struct MPT2SAS_ADAPTER *ioc,
+    Mpi2EventIrConfigElement_t *element)
+{
+       struct _sas_device *sas_device;
+       unsigned long flags;
+       u16 handle = le16_to_cpu(element->PhysDiskDevHandle);
+
+       spin_lock_irqsave(&ioc->sas_device_lock, flags);
+       sas_device = _scsih_sas_device_find_by_handle(ioc, handle);
+       spin_unlock_irqrestore(&ioc->sas_device_lock, flags);
+       if (sas_device)
+               sas_device->hidden_raid_component = 1;
+       else
+               _scsih_add_device(ioc, handle, 0, 1);
+}
+
+#ifdef CONFIG_SCSI_MPT2SAS_LOGGING
+/**
+ * _scsih_sas_ir_config_change_event_debug - debug for IR Config Change events
+ * @ioc: per adapter object
+ * @event_data: event data payload
+ * Context: user.
+ *
+ * Return nothing.
+ */
+static void
+_scsih_sas_ir_config_change_event_debug(struct MPT2SAS_ADAPTER *ioc,
+    Mpi2EventDataIrConfigChangeList_t *event_data)
+{
+       Mpi2EventIrConfigElement_t *element;
+       u8 element_type;
+       int i;
+       char *reason_str = NULL, *element_str = NULL;
+
+       element = (Mpi2EventIrConfigElement_t *)&event_data->ConfigElement[0];
+
+       printk(MPT2SAS_DEBUG_FMT "raid config change: (%s), elements(%d)\n",
+           ioc->name, (le32_to_cpu(event_data->Flags) &
+           MPI2_EVENT_IR_CHANGE_FLAGS_FOREIGN_CONFIG) ?
+           "foreign" : "native", event_data->NumElements);
+       for (i = 0; i < event_data->NumElements; i++, element++) {
+               switch (element->ReasonCode) {
+               case MPI2_EVENT_IR_CHANGE_RC_ADDED:
+                       reason_str = "add";
+                       break;
+               case MPI2_EVENT_IR_CHANGE_RC_REMOVED:
+                       reason_str = "remove";
+                       break;
+               case MPI2_EVENT_IR_CHANGE_RC_NO_CHANGE:
+                       reason_str = "no change";
+                       break;
+               case MPI2_EVENT_IR_CHANGE_RC_HIDE:
+                       reason_str = "hide";
+                       break;
+               case MPI2_EVENT_IR_CHANGE_RC_UNHIDE:
+                       reason_str = "unhide";
+                       break;
+               case MPI2_EVENT_IR_CHANGE_RC_VOLUME_CREATED:
+                       reason_str = "volume_created";
+                       break;
+               case MPI2_EVENT_IR_CHANGE_RC_VOLUME_DELETED:
+                       reason_str = "volume_deleted";
+                       break;
+               case MPI2_EVENT_IR_CHANGE_RC_PD_CREATED:
+                       reason_str = "pd_created";
+                       break;
+               case MPI2_EVENT_IR_CHANGE_RC_PD_DELETED:
+                       reason_str = "pd_deleted";
+                       break;
+               default:
+                       reason_str = "unknown reason";
+                       break;
+               }
+               element_type = le16_to_cpu(element->ElementFlags) &
+                   MPI2_EVENT_IR_CHANGE_EFLAGS_ELEMENT_TYPE_MASK;
+               switch (element_type) {
+               case MPI2_EVENT_IR_CHANGE_EFLAGS_VOLUME_ELEMENT:
+                       element_str = "volume";
+                       break;
+               case MPI2_EVENT_IR_CHANGE_EFLAGS_VOLPHYSDISK_ELEMENT:
+                       element_str = "phys disk";
+                       break;
+               case MPI2_EVENT_IR_CHANGE_EFLAGS_HOTSPARE_ELEMENT:
+                       element_str = "hot spare";
+                       break;
+               default:
+                       element_str = "unknown element";
+                       break;
+               }
+               printk(KERN_DEBUG "\t(%s:%s), vol handle(0x%04x), "
+                   "pd handle(0x%04x), pd num(0x%02x)\n", element_str,
+                   reason_str, le16_to_cpu(element->VolDevHandle),
+                   le16_to_cpu(element->PhysDiskDevHandle),
+                   element->PhysDiskNum);
+       }
+}
+#endif
+
+/**
+ * _scsih_sas_ir_config_change_event - handle ir configuration change events
+ * @ioc: per adapter object
+ * @VF_ID:
+ * @event_data: event data payload
+ * Context: user.
+ *
+ * Return nothing.
+ */
+static void
+_scsih_sas_ir_config_change_event(struct MPT2SAS_ADAPTER *ioc, u8 VF_ID,
+    Mpi2EventDataIrConfigChangeList_t *event_data)
+{
+       Mpi2EventIrConfigElement_t *element;
+       int i;
+
+#ifdef CONFIG_SCSI_MPT2SAS_LOGGING
+       if (ioc->logging_level & MPT_DEBUG_EVENT_WORK_TASK)
+               _scsih_sas_ir_config_change_event_debug(ioc, event_data);
+
+#endif
+
+       element = (Mpi2EventIrConfigElement_t *)&event_data->ConfigElement[0];
+       for (i = 0; i < event_data->NumElements; i++, element++) {
+
+               switch (element->ReasonCode) {
+               case MPI2_EVENT_IR_CHANGE_RC_VOLUME_CREATED:
+               case MPI2_EVENT_IR_CHANGE_RC_ADDED:
+                       _scsih_sas_volume_add(ioc, element);
+                       break;
+               case MPI2_EVENT_IR_CHANGE_RC_VOLUME_DELETED:
+               case MPI2_EVENT_IR_CHANGE_RC_REMOVED:
+                       _scsih_sas_volume_delete(ioc, element);
+                       break;
+               case MPI2_EVENT_IR_CHANGE_RC_PD_CREATED:
+                       _scsih_sas_pd_hide(ioc, element);
+                       break;
+               case MPI2_EVENT_IR_CHANGE_RC_PD_DELETED:
+                       _scsih_sas_pd_expose(ioc, element);
+                       break;
+               case MPI2_EVENT_IR_CHANGE_RC_HIDE:
+                       _scsih_sas_pd_add(ioc, element);
+                       break;
+               case MPI2_EVENT_IR_CHANGE_RC_UNHIDE:
+                       _scsih_sas_pd_delete(ioc, element);
+                       break;
+               }
+       }
+}
+
+/**
+ * _scsih_sas_ir_volume_event - IR volume event
+ * @ioc: per adapter object
+ * @event_data: event data payload
+ * Context: user.
+ *
+ * Return nothing.
+ */
+static void
+_scsih_sas_ir_volume_event(struct MPT2SAS_ADAPTER *ioc, u8 VF_ID,
+    Mpi2EventDataIrVolume_t *event_data)
+{
+       u64 wwid;
+       unsigned long flags;
+       struct _raid_device *raid_device;
+       u16 handle;
+       u32 state;
+       int rc;
+       struct MPT2SAS_TARGET *sas_target_priv_data;
+
+       if (event_data->ReasonCode != MPI2_EVENT_IR_VOLUME_RC_STATE_CHANGED)
+               return;
+
+       handle = le16_to_cpu(event_data->VolDevHandle);
+       state = le32_to_cpu(event_data->NewValue);
+       dewtprintk(ioc, printk(MPT2SAS_DEBUG_FMT "%s: handle(0x%04x), "
+           "old(0x%08x), new(0x%08x)\n", ioc->name, __func__,  handle,
+           le32_to_cpu(event_data->PreviousValue), state));
+
+       spin_lock_irqsave(&ioc->raid_device_lock, flags);
+       raid_device = _scsih_raid_device_find_by_handle(ioc, handle);
+       spin_unlock_irqrestore(&ioc->raid_device_lock, flags);
+
+       switch (state) {
+       case MPI2_RAID_VOL_STATE_MISSING:
+       case MPI2_RAID_VOL_STATE_FAILED:
+               if (!raid_device)
+                       break;
+               if (raid_device->starget) {
+                       sas_target_priv_data = raid_device->starget->hostdata;
+                       sas_target_priv_data->deleted = 1;
+                       scsi_remove_target(&raid_device->starget->dev);
+               }
+               _scsih_raid_device_remove(ioc, raid_device);
+               break;
+
+       case MPI2_RAID_VOL_STATE_ONLINE:
+       case MPI2_RAID_VOL_STATE_DEGRADED:
+       case MPI2_RAID_VOL_STATE_OPTIMAL:
+               if (raid_device)
+                       break;
+
+               mpt2sas_config_get_volume_wwid(ioc, handle, &wwid);
+               if (!wwid) {
+                       printk(MPT2SAS_ERR_FMT
+                           "failure at %s:%d/%s()!\n", ioc->name,
+                           __FILE__, __LINE__, __func__);
+                       break;
+               }
+
+               raid_device = kzalloc(sizeof(struct _raid_device), GFP_KERNEL);
+               if (!raid_device) {
+                       printk(MPT2SAS_ERR_FMT
+                           "failure at %s:%d/%s()!\n", ioc->name,
+                           __FILE__, __LINE__, __func__);
+                       break;
+               }
+
+               raid_device->id = ioc->sas_id++;
+               raid_device->channel = RAID_CHANNEL;
+               raid_device->handle = handle;
+               raid_device->wwid = wwid;
+               _scsih_raid_device_add(ioc, raid_device);
+               rc = scsi_add_device(ioc->shost, RAID_CHANNEL,
+                   raid_device->id, 0);
+               if (rc)
+                       _scsih_raid_device_remove(ioc, raid_device);
+               break;
+
+       case MPI2_RAID_VOL_STATE_INITIALIZING:
+       default:
+               break;
+       }
+}
+
+/**
+ * _scsih_sas_ir_physical_disk_event - PD event
+ * @ioc: per adapter object
+ * @event_data: event data payload
+ * Context: user.
+ *
+ * Return nothing.
+ */
+static void
+_scsih_sas_ir_physical_disk_event(struct MPT2SAS_ADAPTER *ioc, u8 VF_ID,
+   Mpi2EventDataIrPhysicalDisk_t *event_data)
+{
+       u16 handle;
+       u32 state;
+       struct _sas_device *sas_device;
+       unsigned long flags;
+
+       if (event_data->ReasonCode != MPI2_EVENT_IR_PHYSDISK_RC_STATE_CHANGED)
+               return;
+
+       handle = le16_to_cpu(event_data->PhysDiskDevHandle);
+       state = le32_to_cpu(event_data->NewValue);
+
+       dewtprintk(ioc, printk(MPT2SAS_DEBUG_FMT "%s: handle(0x%04x), "
+           "old(0x%08x), new(0x%08x)\n", ioc->name, __func__,  handle,
+           le32_to_cpu(event_data->PreviousValue), state));
+
+       spin_lock_irqsave(&ioc->sas_device_lock, flags);
+       sas_device = _scsih_sas_device_find_by_handle(ioc, handle);
+       spin_unlock_irqrestore(&ioc->sas_device_lock, flags);
+
+       switch (state) {
+#if 0
+       case MPI2_RAID_PD_STATE_OFFLINE:
+               if (sas_device)
+                       _scsih_remove_device(ioc, handle);
+               break;
+#endif
+       case MPI2_RAID_PD_STATE_ONLINE:
+       case MPI2_RAID_PD_STATE_DEGRADED:
+       case MPI2_RAID_PD_STATE_REBUILDING:
+       case MPI2_RAID_PD_STATE_OPTIMAL:
+               if (sas_device)
+                       sas_device->hidden_raid_component = 1;
+               else
+                       _scsih_add_device(ioc, handle, 0, 1);
+               break;
+
+       case MPI2_RAID_PD_STATE_NOT_CONFIGURED:
+       case MPI2_RAID_PD_STATE_NOT_COMPATIBLE:
+       case MPI2_RAID_PD_STATE_HOT_SPARE:
+       default:
+               break;
+       }
+}
+
+#ifdef CONFIG_SCSI_MPT2SAS_LOGGING
+/**
+ * _scsih_sas_ir_operation_status_event_debug - debug for IR op event
+ * @ioc: per adapter object
+ * @event_data: event data payload
+ * Context: user.
+ *
+ * Return nothing.
+ */
+static void
+_scsih_sas_ir_operation_status_event_debug(struct MPT2SAS_ADAPTER *ioc,
+    Mpi2EventDataIrOperationStatus_t *event_data)
+{
+       char *reason_str = NULL;
+
+       switch (event_data->RAIDOperation) {
+       case MPI2_EVENT_IR_RAIDOP_RESYNC:
+               reason_str = "resync";
+               break;
+       case MPI2_EVENT_IR_RAIDOP_ONLINE_CAP_EXPANSION:
+               reason_str = "online capacity expansion";
+               break;
+       case MPI2_EVENT_IR_RAIDOP_CONSISTENCY_CHECK:
+               reason_str = "consistency check";
+               break;
+       default:
+               reason_str = "unknown reason";
+               break;
+       }
+
+       printk(MPT2SAS_INFO_FMT "raid operational status: (%s)"
+           "\thandle(0x%04x), percent complete(%d)\n",
+           ioc->name, reason_str,
+           le16_to_cpu(event_data->VolDevHandle),
+           event_data->PercentComplete);
+}
+#endif
+
+/**
+ * _scsih_sas_ir_operation_status_event - handle RAID operation events
+ * @ioc: per adapter object
+ * @VF_ID:
+ * @event_data: event data payload
+ * Context: user.
+ *
+ * Return nothing.
+ */
+static void
+_scsih_sas_ir_operation_status_event(struct MPT2SAS_ADAPTER *ioc, u8 VF_ID,
+    Mpi2EventDataIrOperationStatus_t *event_data)
+{
+#ifdef CONFIG_SCSI_MPT2SAS_LOGGING
+       if (ioc->logging_level & MPT_DEBUG_EVENT_WORK_TASK)
+               _scsih_sas_ir_operation_status_event_debug(ioc, event_data);
+#endif
+}
+
+/**
+ * _scsih_task_set_full - handle task set full
+ * @ioc: per adapter object
+ * @event_data: event data payload
+ * Context: user.
+ *
+ * Throttle back qdepth.
+ */
+static void
+_scsih_task_set_full(struct MPT2SAS_ADAPTER *ioc, u8 VF_ID,
+    Mpi2EventDataTaskSetFull_t *event_data)
+{
+       unsigned long flags;
+       struct _sas_device *sas_device;
+       static struct _raid_device *raid_device;
+       struct scsi_device *sdev;
+       int depth;
+       u16 current_depth;
+       u16 handle;
+       int id, channel;
+       u64 sas_address;
+
+       current_depth = le16_to_cpu(event_data->CurrentDepth);
+       handle = le16_to_cpu(event_data->DevHandle);
+       spin_lock_irqsave(&ioc->sas_device_lock, flags);
+       sas_device = _scsih_sas_device_find_by_handle(ioc, handle);
+       if (!sas_device) {
+               spin_unlock_irqrestore(&ioc->sas_device_lock, flags);
+               return;
+       }
+       spin_unlock_irqrestore(&ioc->sas_device_lock, flags);
+       id = sas_device->id;
+       channel = sas_device->channel;
+       sas_address = sas_device->sas_address;
+
+       /* if hidden raid component, then change to volume characteristics */
+       if (sas_device->hidden_raid_component && sas_device->volume_handle) {
+               spin_lock_irqsave(&ioc->raid_device_lock, flags);
+               raid_device = _scsih_raid_device_find_by_handle(
+                   ioc, sas_device->volume_handle);
+               spin_unlock_irqrestore(&ioc->raid_device_lock, flags);
+               if (raid_device) {
+                       id = raid_device->id;
+                       channel = raid_device->channel;
+                       handle = raid_device->handle;
+                       sas_address = raid_device->wwid;
+               }
+       }
+
+       if (ioc->logging_level & MPT_DEBUG_TASK_SET_FULL)
+               starget_printk(KERN_DEBUG, sas_device->starget, "task set "
+                   "full: handle(0x%04x), sas_addr(0x%016llx), depth(%d)\n",
+                   handle, (unsigned long long)sas_address, current_depth);
+
+       shost_for_each_device(sdev, ioc->shost) {
+               if (sdev->id == id && sdev->channel == channel) {
+                       if (current_depth > sdev->queue_depth) {
+                               if (ioc->logging_level &
+                                   MPT_DEBUG_TASK_SET_FULL)
+                                       sdev_printk(KERN_INFO, sdev, "strange "
+                                           "observation, the queue depth is"
+                                           " (%d) meanwhile fw queue depth "
+                                           "is (%d)\n", sdev->queue_depth,
+                                           current_depth);
+                               continue;
+                       }
+                       depth = scsi_track_queue_full(sdev,
+                           current_depth - 1);
+                       if (depth > 0)
+                               sdev_printk(KERN_INFO, sdev, "Queue depth "
+                                   "reduced to (%d)\n", depth);
+                       else if (depth < 0)
+                               sdev_printk(KERN_INFO, sdev, "Tagged Command "
+                                   "Queueing is being disabled\n");
+                       else if (depth == 0)
+                               if (ioc->logging_level &
+                                    MPT_DEBUG_TASK_SET_FULL)
+                                       sdev_printk(KERN_INFO, sdev,
+                                            "Queue depth not changed yet\n");
+               }
+       }
+}
+
+/**
+ * _scsih_mark_responding_sas_device - mark a sas_devices as responding
+ * @ioc: per adapter object
+ * @sas_address: sas address
+ * @slot: enclosure slot id
+ * @handle: device handle
+ *
+ * After host reset, find out whether devices are still responding.
+ * Used in _scsi_remove_unresponsive_sas_devices.
+ *
+ * Return nothing.
+ */
+static void
+_scsih_mark_responding_sas_device(struct MPT2SAS_ADAPTER *ioc, u64 sas_address,
+    u16 slot, u16 handle)
+{
+       struct MPT2SAS_TARGET *sas_target_priv_data;
+       struct scsi_target *starget;
+       struct _sas_device *sas_device;
+       unsigned long flags;
+
+       spin_lock_irqsave(&ioc->sas_device_lock, flags);
+       list_for_each_entry(sas_device, &ioc->sas_device_list, list) {
+               if (sas_device->sas_address == sas_address &&
+                   sas_device->slot == slot && sas_device->starget) {
+                       sas_device->responding = 1;
+                       starget_printk(KERN_INFO, sas_device->starget,
+                           "handle(0x%04x), sas_addr(0x%016llx), enclosure "
+                           "logical id(0x%016llx), slot(%d)\n", handle,
+                           (unsigned long long)sas_device->sas_address,
+                           (unsigned long long)
+                           sas_device->enclosure_logical_id,
+                           sas_device->slot);
+                       if (sas_device->handle == handle)
+                               goto out;
+                       printk(KERN_INFO "\thandle changed from(0x%04x)!!!\n",
+                           sas_device->handle);
+                       sas_device->handle = handle;
+                       starget = sas_device->starget;
+                       sas_target_priv_data = starget->hostdata;
+                       sas_target_priv_data->handle = handle;
+                       goto out;
+               }
+       }
+ out:
+       spin_unlock_irqrestore(&ioc->sas_device_lock, flags);
+}
+
+/**
+ * _scsih_search_responding_sas_devices -
+ * @ioc: per adapter object
+ *
+ * After host reset, find out whether devices are still responding.
+ * If not remove.
+ *
+ * Return nothing.
+ */
+static void
+_scsih_search_responding_sas_devices(struct MPT2SAS_ADAPTER *ioc)
+{
+       Mpi2SasDevicePage0_t sas_device_pg0;
+       Mpi2ConfigReply_t mpi_reply;
+       u16 ioc_status;
+       __le64 sas_address;
+       u16 handle;
+       u32 device_info;
+       u16 slot;
+
+       printk(MPT2SAS_INFO_FMT "%s\n", ioc->name, __func__);
+
+       if (list_empty(&ioc->sas_device_list))
+               return;
+
+       handle = 0xFFFF;
+       while (!(mpt2sas_config_get_sas_device_pg0(ioc, &mpi_reply,
+           &sas_device_pg0, MPI2_SAS_DEVICE_PGAD_FORM_GET_NEXT_HANDLE,
+           handle))) {
+               ioc_status = le16_to_cpu(mpi_reply.IOCStatus) &
+                   MPI2_IOCSTATUS_MASK;
+               if (ioc_status == MPI2_IOCSTATUS_CONFIG_INVALID_PAGE)
+                       break;
+               handle = le16_to_cpu(sas_device_pg0.DevHandle);
+               device_info = le32_to_cpu(sas_device_pg0.DeviceInfo);
+               if (!(_scsih_is_end_device(device_info)))
+                       continue;
+               sas_address = le64_to_cpu(sas_device_pg0.SASAddress);
+               slot = le16_to_cpu(sas_device_pg0.Slot);
+               _scsih_mark_responding_sas_device(ioc, sas_address, slot,
+                   handle);
+       }
+}
+
+/**
+ * _scsih_mark_responding_raid_device - mark a raid_device as responding
+ * @ioc: per adapter object
+ * @wwid: world wide identifier for raid volume
+ * @handle: device handle
+ *
+ * After host reset, find out whether devices are still responding.
+ * Used in _scsi_remove_unresponsive_raid_devices.
+ *
+ * Return nothing.
+ */
+static void
+_scsih_mark_responding_raid_device(struct MPT2SAS_ADAPTER *ioc, u64 wwid,
+    u16 handle)
+{
+       struct MPT2SAS_TARGET *sas_target_priv_data;
+       struct scsi_target *starget;
+       struct _raid_device *raid_device;
+       unsigned long flags;
+
+       spin_lock_irqsave(&ioc->raid_device_lock, flags);
+       list_for_each_entry(raid_device, &ioc->raid_device_list, list) {
+               if (raid_device->wwid == wwid && raid_device->starget) {
+                       raid_device->responding = 1;
+                       starget_printk(KERN_INFO, raid_device->starget,
+                           "handle(0x%04x), wwid(0x%016llx)\n", handle,
+                           (unsigned long long)raid_device->wwid);
+                       if (raid_device->handle == handle)
+                               goto out;
+                       printk(KERN_INFO "\thandle changed from(0x%04x)!!!\n",
+                           raid_device->handle);
+                       raid_device->handle = handle;
+                       starget = raid_device->starget;
+                       sas_target_priv_data = starget->hostdata;
+                       sas_target_priv_data->handle = handle;
+                       goto out;
+               }
+       }
+ out:
+       spin_unlock_irqrestore(&ioc->raid_device_lock, flags);
+}
+
+/**
+ * _scsih_search_responding_raid_devices -
+ * @ioc: per adapter object
+ *
+ * After host reset, find out whether devices are still responding.
+ * If not remove.
+ *
+ * Return nothing.
+ */
+static void
+_scsih_search_responding_raid_devices(struct MPT2SAS_ADAPTER *ioc)
+{
+       Mpi2RaidVolPage1_t volume_pg1;
+       Mpi2ConfigReply_t mpi_reply;
+       u16 ioc_status;
+       u16 handle;
+
+       printk(MPT2SAS_INFO_FMT "%s\n", ioc->name, __func__);
+
+       if (list_empty(&ioc->raid_device_list))
+               return;
+
+       handle = 0xFFFF;
+       while (!(mpt2sas_config_get_raid_volume_pg1(ioc, &mpi_reply,
+           &volume_pg1, MPI2_RAID_VOLUME_PGAD_FORM_GET_NEXT_HANDLE, handle))) {
+               ioc_status = le16_to_cpu(mpi_reply.IOCStatus) &
+                   MPI2_IOCSTATUS_MASK;
+               if (ioc_status == MPI2_IOCSTATUS_CONFIG_INVALID_PAGE)
+                       break;
+               handle = le16_to_cpu(volume_pg1.DevHandle);
+               _scsih_mark_responding_raid_device(ioc,
+                   le64_to_cpu(volume_pg1.WWID), handle);
+       }
+}
+
+/**
+ * _scsih_mark_responding_expander - mark a expander as responding
+ * @ioc: per adapter object
+ * @sas_address: sas address
+ * @handle:
+ *
+ * After host reset, find out whether devices are still responding.
+ * Used in _scsi_remove_unresponsive_expanders.
+ *
+ * Return nothing.
+ */
+static void
+_scsih_mark_responding_expander(struct MPT2SAS_ADAPTER *ioc, u64 sas_address,
+     u16 handle)
+{
+       struct _sas_node *sas_expander;
+       unsigned long flags;
+
+       spin_lock_irqsave(&ioc->sas_node_lock, flags);
+       list_for_each_entry(sas_expander, &ioc->sas_expander_list, list) {
+               if (sas_expander->sas_address == sas_address) {
+                       sas_expander->responding = 1;
+                       if (sas_expander->handle != handle) {
+                               printk(KERN_INFO "old handle(0x%04x)\n",
+                                   sas_expander->handle);
+                               sas_expander->handle = handle;
+                       }
+                       goto out;
+               }
+       }
+ out:
+       spin_unlock_irqrestore(&ioc->sas_node_lock, flags);
+}
+
+/**
+ * _scsih_search_responding_expanders -
+ * @ioc: per adapter object
+ *
+ * After host reset, find out whether devices are still responding.
+ * If not remove.
+ *
+ * Return nothing.
+ */
+static void
+_scsih_search_responding_expanders(struct MPT2SAS_ADAPTER *ioc)
+{
+       Mpi2ExpanderPage0_t expander_pg0;
+       Mpi2ConfigReply_t mpi_reply;
+       u16 ioc_status;
+       __le64 sas_address;
+       u16 handle;
+
+       printk(MPT2SAS_INFO_FMT "%s\n", ioc->name, __func__);
+
+       if (list_empty(&ioc->sas_expander_list))
+               return;
+
+       handle = 0xFFFF;
+       while (!(mpt2sas_config_get_expander_pg0(ioc, &mpi_reply, &expander_pg0,
+           MPI2_SAS_EXPAND_PGAD_FORM_GET_NEXT_HNDL, handle))) {
+
+               ioc_status = le16_to_cpu(mpi_reply.IOCStatus) &
+                   MPI2_IOCSTATUS_MASK;
+               if (ioc_status == MPI2_IOCSTATUS_CONFIG_INVALID_PAGE)
+                       break;
+
+               handle = le16_to_cpu(expander_pg0.DevHandle);
+               sas_address = le64_to_cpu(expander_pg0.SASAddress);
+               printk(KERN_INFO "\texpander present: handle(0x%04x), "
+                   "sas_addr(0x%016llx)\n", handle,
+                   (unsigned long long)sas_address);
+               _scsih_mark_responding_expander(ioc, sas_address, handle);
+       }
+
+}
+
+/**
+ * _scsih_remove_unresponding_devices - removing unresponding devices
+ * @ioc: per adapter object
+ *
+ * Return nothing.
+ */
+static void
+_scsih_remove_unresponding_devices(struct MPT2SAS_ADAPTER *ioc)
+{
+       struct _sas_device *sas_device, *sas_device_next;
+       struct _sas_node *sas_expander, *sas_expander_next;
+       struct _raid_device *raid_device, *raid_device_next;
+       unsigned long flags;
+
+       _scsih_search_responding_sas_devices(ioc);
+       _scsih_search_responding_raid_devices(ioc);
+       _scsih_search_responding_expanders(ioc);
+
+       spin_lock_irqsave(&ioc->ioc_reset_in_progress_lock, flags);
+       ioc->shost_recovery = 0;
+       if (ioc->shost->shost_state == SHOST_RECOVERY) {
+               printk(MPT2SAS_INFO_FMT "putting controller into "
+                   "SHOST_RUNNING\n", ioc->name);
+               scsi_host_set_state(ioc->shost, SHOST_RUNNING);
+       }
+       spin_unlock_irqrestore(&ioc->ioc_reset_in_progress_lock, flags);
+
+       list_for_each_entry_safe(sas_device, sas_device_next,
+           &ioc->sas_device_list, list) {
+               if (sas_device->responding) {
+                       sas_device->responding = 0;
+                       continue;
+               }
+               if (sas_device->starget)
+                       starget_printk(KERN_INFO, sas_device->starget,
+                           "removing: handle(0x%04x), sas_addr(0x%016llx), "
+                           "enclosure logical id(0x%016llx), slot(%d)\n",
+                           sas_device->handle,
+                           (unsigned long long)sas_device->sas_address,
+                           (unsigned long long)
+                           sas_device->enclosure_logical_id,
+                           sas_device->slot);
+               _scsih_remove_device(ioc, sas_device->handle);
+       }
+
+       list_for_each_entry_safe(raid_device, raid_device_next,
+           &ioc->raid_device_list, list) {
+               if (raid_device->responding) {
+                       raid_device->responding = 0;
+                       continue;
+               }
+               if (raid_device->starget) {
+                       starget_printk(KERN_INFO, raid_device->starget,
+                           "removing: handle(0x%04x), wwid(0x%016llx)\n",
+                             raid_device->handle,
+                           (unsigned long long)raid_device->wwid);
+                       scsi_remove_target(&raid_device->starget->dev);
+               }
+               _scsih_raid_device_remove(ioc, raid_device);
+       }
+
+       list_for_each_entry_safe(sas_expander, sas_expander_next,
+           &ioc->sas_expander_list, list) {
+               if (sas_expander->responding) {
+                       sas_expander->responding = 0;
+                       continue;
+               }
+               printk("\tremoving expander: handle(0x%04x), "
+                   " sas_addr(0x%016llx)\n", sas_expander->handle,
+                   (unsigned long long)sas_expander->sas_address);
+               _scsih_expander_remove(ioc, sas_expander->handle);
+       }
+}
+
+/**
+ * _firmware_event_work - delayed task for processing firmware events
+ * @ioc: per adapter object
+ * @work: equal to the fw_event_work object
+ * Context: user.
+ *
+ * Return nothing.
+ */
+static void
+_firmware_event_work(struct work_struct *work)
+{
+       struct fw_event_work *fw_event = container_of(work,
+           struct fw_event_work, work.work);
+       unsigned long flags;
+       struct MPT2SAS_ADAPTER *ioc = fw_event->ioc;
+
+       /* This is invoked by calling _scsih_queue_rescan(). */
+       if (fw_event->event == MPT2SAS_RESCAN_AFTER_HOST_RESET) {
+               _scsih_fw_event_free(ioc, fw_event);
+               _scsih_sas_host_refresh(ioc, 1);
+               _scsih_remove_unresponding_devices(ioc);
+               return;
+       }
+
+       /* the queue is being flushed so ignore this event */
+       spin_lock_irqsave(&ioc->fw_event_lock, flags);
+       if (ioc->fw_events_off || ioc->remove_host) {
+               spin_unlock_irqrestore(&ioc->fw_event_lock, flags);
+               _scsih_fw_event_free(ioc, fw_event);
+               return;
+       }
+       spin_unlock_irqrestore(&ioc->fw_event_lock, flags);
+
+       spin_lock_irqsave(&ioc->ioc_reset_in_progress_lock, flags);
+       if (ioc->shost_recovery) {
+               spin_unlock_irqrestore(&ioc->ioc_reset_in_progress_lock, flags);
+               _scsih_fw_event_requeue(ioc, fw_event, 1000);
+               return;
+       }
+       spin_unlock_irqrestore(&ioc->ioc_reset_in_progress_lock, flags);
+
+       switch (fw_event->event) {
+       case MPI2_EVENT_SAS_TOPOLOGY_CHANGE_LIST:
+               _scsih_sas_topology_change_event(ioc, fw_event->VF_ID,
+                   fw_event->event_data, fw_event);
+               break;
+       case MPI2_EVENT_SAS_DEVICE_STATUS_CHANGE:
+               _scsih_sas_device_status_change_event(ioc, fw_event->VF_ID,
+                   fw_event->event_data);
+               break;
+       case MPI2_EVENT_SAS_DISCOVERY:
+               _scsih_sas_discovery_event(ioc, fw_event->VF_ID,
+                   fw_event->event_data);
+               break;
+       case MPI2_EVENT_SAS_BROADCAST_PRIMITIVE:
+               _scsih_sas_broadcast_primative_event(ioc, fw_event->VF_ID,
+                   fw_event->event_data);
+               break;
+       case MPI2_EVENT_SAS_ENCL_DEVICE_STATUS_CHANGE:
+               _scsih_sas_enclosure_dev_status_change_event(ioc,
+                   fw_event->VF_ID, fw_event->event_data);
+               break;
+       case MPI2_EVENT_IR_CONFIGURATION_CHANGE_LIST:
+               _scsih_sas_ir_config_change_event(ioc, fw_event->VF_ID,
+                   fw_event->event_data);
+               break;
+       case MPI2_EVENT_IR_VOLUME:
+               _scsih_sas_ir_volume_event(ioc, fw_event->VF_ID,
+                   fw_event->event_data);
+               break;
+       case MPI2_EVENT_IR_PHYSICAL_DISK:
+               _scsih_sas_ir_physical_disk_event(ioc, fw_event->VF_ID,
+                   fw_event->event_data);
+               break;
+       case MPI2_EVENT_IR_OPERATION_STATUS:
+               _scsih_sas_ir_operation_status_event(ioc, fw_event->VF_ID,
+                   fw_event->event_data);
+               break;
+       case MPI2_EVENT_TASK_SET_FULL:
+               _scsih_task_set_full(ioc, fw_event->VF_ID,
+                   fw_event->event_data);
+               break;
+       }
+       _scsih_fw_event_free(ioc, fw_event);
+}
+
+/**
+ * mpt2sas_scsih_event_callback - firmware event handler (called at ISR time)
+ * @ioc: per adapter object
+ * @VF_ID: virtual function id
+ * @reply: reply message frame(lower 32bit addr)
+ * Context: interrupt.
+ *
+ * This function merely adds a new work task into ioc->firmware_event_thread.
+ * The tasks are worked from _firmware_event_work in user context.
+ *
+ * Return nothing.
+ */
+void
+mpt2sas_scsih_event_callback(struct MPT2SAS_ADAPTER *ioc, u8 VF_ID, u32 reply)
+{
+       struct fw_event_work *fw_event;
+       Mpi2EventNotificationReply_t *mpi_reply;
+       unsigned long flags;
+       u16 event;
+
+       /* events turned off due to host reset or driver unloading */
+       spin_lock_irqsave(&ioc->fw_event_lock, flags);
+       if (ioc->fw_events_off || ioc->remove_host) {
+               spin_unlock_irqrestore(&ioc->fw_event_lock, flags);
+               return;
+       }
+       spin_unlock_irqrestore(&ioc->fw_event_lock, flags);
+
+       mpi_reply =  mpt2sas_base_get_reply_virt_addr(ioc, reply);
+       event = le16_to_cpu(mpi_reply->Event);
+
+       switch (event) {
+       /* handle these */
+       case MPI2_EVENT_SAS_BROADCAST_PRIMITIVE:
+       {
+               Mpi2EventDataSasBroadcastPrimitive_t *baen_data =
+                   (Mpi2EventDataSasBroadcastPrimitive_t *)
+                   mpi_reply->EventData;
+
+               if (baen_data->Primitive !=
+                   MPI2_EVENT_PRIMITIVE_ASYNCHRONOUS_EVENT ||
+                   ioc->broadcast_aen_busy)
+                       return;
+               ioc->broadcast_aen_busy = 1;
+               break;
+       }
+
+       case MPI2_EVENT_SAS_TOPOLOGY_CHANGE_LIST:
+               _scsih_check_topo_delete_events(ioc,
+                   (Mpi2EventDataSasTopologyChangeList_t *)
+                   mpi_reply->EventData);
+               break;
+
+       case MPI2_EVENT_SAS_DEVICE_STATUS_CHANGE:
+       case MPI2_EVENT_IR_OPERATION_STATUS:
+       case MPI2_EVENT_SAS_DISCOVERY:
+       case MPI2_EVENT_SAS_ENCL_DEVICE_STATUS_CHANGE:
+       case MPI2_EVENT_IR_VOLUME:
+       case MPI2_EVENT_IR_PHYSICAL_DISK:
+       case MPI2_EVENT_IR_CONFIGURATION_CHANGE_LIST:
+       case MPI2_EVENT_TASK_SET_FULL:
+               break;
+
+       default: /* ignore the rest */
+               return;
+       }
+
+       fw_event = kzalloc(sizeof(struct fw_event_work), GFP_ATOMIC);
+       if (!fw_event) {
+               printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
+                   ioc->name, __FILE__, __LINE__, __func__);
+               return;
+       }
+       fw_event->event_data =
+           kzalloc(mpi_reply->EventDataLength*4, GFP_ATOMIC);
+       if (!fw_event->event_data) {
+               printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
+                   ioc->name, __FILE__, __LINE__, __func__);
+               kfree(fw_event);
+               return;
+       }
+
+       memcpy(fw_event->event_data, mpi_reply->EventData,
+           mpi_reply->EventDataLength*4);
+       fw_event->ioc = ioc;
+       fw_event->VF_ID = VF_ID;
+       fw_event->event = event;
+       _scsih_fw_event_add(ioc, fw_event);
+}
+
+/* shost template */
+static struct scsi_host_template scsih_driver_template = {
+       .module                         = THIS_MODULE,
+       .name                           = "Fusion MPT SAS Host",
+       .proc_name                      = MPT2SAS_DRIVER_NAME,
+       .queuecommand                   = scsih_qcmd,
+       .target_alloc                   = scsih_target_alloc,
+       .slave_alloc                    = scsih_slave_alloc,
+       .slave_configure                = scsih_slave_configure,
+       .target_destroy                 = scsih_target_destroy,
+       .slave_destroy                  = scsih_slave_destroy,
+       .change_queue_depth             = scsih_change_queue_depth,
+       .change_queue_type              = scsih_change_queue_type,
+       .eh_abort_handler               = scsih_abort,
+       .eh_device_reset_handler        = scsih_dev_reset,
+       .eh_host_reset_handler          = scsih_host_reset,
+       .bios_param                     = scsih_bios_param,
+       .can_queue                      = 1,
+       .this_id                        = -1,
+       .sg_tablesize                   = MPT2SAS_SG_DEPTH,
+       .max_sectors                    = 8192,
+       .cmd_per_lun                    = 7,
+       .use_clustering                 = ENABLE_CLUSTERING,
+       .shost_attrs                    = mpt2sas_host_attrs,
+       .sdev_attrs                     = mpt2sas_dev_attrs,
+};
+
+/**
+ * _scsih_expander_node_remove - removing expander device from list.
+ * @ioc: per adapter object
+ * @sas_expander: the sas_device object
+ * Context: Calling function should acquire ioc->sas_node_lock.
+ *
+ * Removing object and freeing associated memory from the
+ * ioc->sas_expander_list.
+ *
+ * Return nothing.
+ */
+static void
+_scsih_expander_node_remove(struct MPT2SAS_ADAPTER *ioc,
+    struct _sas_node *sas_expander)
+{
+       struct _sas_port *mpt2sas_port;
+       struct _sas_device *sas_device;
+       struct _sas_node *expander_sibling;
+       unsigned long flags;
+
+       if (!sas_expander)
+               return;
+
+       /* remove sibling ports attached to this expander */
+ retry_device_search:
+       list_for_each_entry(mpt2sas_port,
+          &sas_expander->sas_port_list, port_list) {
+               if (mpt2sas_port->remote_identify.device_type ==
+                   SAS_END_DEVICE) {
+                       spin_lock_irqsave(&ioc->sas_device_lock, flags);
+                       sas_device =
+                           mpt2sas_scsih_sas_device_find_by_sas_address(ioc,
+                          mpt2sas_port->remote_identify.sas_address);
+                       spin_unlock_irqrestore(&ioc->sas_device_lock, flags);
+                       if (!sas_device)
+                               continue;
+                       _scsih_remove_device(ioc, sas_device->handle);
+                       goto retry_device_search;
+               }
+       }
+
+ retry_expander_search:
+       list_for_each_entry(mpt2sas_port,
+          &sas_expander->sas_port_list, port_list) {
+
+               if (mpt2sas_port->remote_identify.device_type ==
+                   MPI2_SAS_DEVICE_INFO_EDGE_EXPANDER ||
+                   mpt2sas_port->remote_identify.device_type ==
+                   MPI2_SAS_DEVICE_INFO_FANOUT_EXPANDER) {
+
+                       spin_lock_irqsave(&ioc->sas_node_lock, flags);
+                       expander_sibling =
+                           mpt2sas_scsih_expander_find_by_sas_address(
+                           ioc, mpt2sas_port->remote_identify.sas_address);
+                       spin_unlock_irqrestore(&ioc->sas_node_lock, flags);
+                       if (!expander_sibling)
+                               continue;
+                       _scsih_expander_remove(ioc, expander_sibling->handle);
+                       goto retry_expander_search;
+               }
+       }
+
+       mpt2sas_transport_port_remove(ioc, sas_expander->sas_address,
+           sas_expander->parent_handle);
+
+       printk(MPT2SAS_INFO_FMT "expander_remove: handle"
+          "(0x%04x), sas_addr(0x%016llx)\n", ioc->name,
+           sas_expander->handle, (unsigned long long)
+           sas_expander->sas_address);
+
+       list_del(&sas_expander->list);
+       kfree(sas_expander->phy);
+       kfree(sas_expander);
+}
+
+/**
+ * scsih_remove - detach and remove add host
+ * @pdev: PCI device struct
+ *
+ * Return nothing.
+ */
+static void __devexit
+scsih_remove(struct pci_dev *pdev)
+{
+       struct Scsi_Host *shost = pci_get_drvdata(pdev);
+       struct MPT2SAS_ADAPTER *ioc = shost_priv(shost);
+       struct _sas_port *mpt2sas_port;
+       struct _sas_device *sas_device;
+       struct _sas_node *expander_sibling;
+       struct workqueue_struct *wq;
+       unsigned long flags;
+
+       ioc->remove_host = 1;
+       _scsih_fw_event_off(ioc);
+
+       spin_lock_irqsave(&ioc->fw_event_lock, flags);
+       wq = ioc->firmware_event_thread;
+       ioc->firmware_event_thread = NULL;
+       spin_unlock_irqrestore(&ioc->fw_event_lock, flags);
+       if (wq)
+               destroy_workqueue(wq);
+
+       /* free ports attached to the sas_host */
+ retry_again:
+       list_for_each_entry(mpt2sas_port,
+          &ioc->sas_hba.sas_port_list, port_list) {
+               if (mpt2sas_port->remote_identify.device_type ==
+                   SAS_END_DEVICE) {
+                       sas_device =
+                           mpt2sas_scsih_sas_device_find_by_sas_address(ioc,
+                          mpt2sas_port->remote_identify.sas_address);
+                       if (sas_device) {
+                               _scsih_remove_device(ioc, sas_device->handle);
+                               goto retry_again;
+                       }
+               } else {
+                       expander_sibling =
+                           mpt2sas_scsih_expander_find_by_sas_address(ioc,
+                           mpt2sas_port->remote_identify.sas_address);
+                       if (expander_sibling) {
+                               _scsih_expander_remove(ioc,
+                                   expander_sibling->handle);
+                               goto retry_again;
+                       }
+               }
+       }
+
+       /* free phys attached to the sas_host */
+       if (ioc->sas_hba.num_phys) {
+               kfree(ioc->sas_hba.phy);
+               ioc->sas_hba.phy = NULL;
+               ioc->sas_hba.num_phys = 0;
+       }
+
+       sas_remove_host(shost);
+       mpt2sas_base_detach(ioc);
+       list_del(&ioc->list);
+       scsi_remove_host(shost);
+       scsi_host_put(shost);
+}
+
+/**
+ * _scsih_probe_boot_devices - reports 1st device
+ * @ioc: per adapter object
+ *
+ * If specified in bios page 2, this routine reports the 1st
+ * device scsi-ml or sas transport for persistent boot device
+ * purposes.  Please refer to function _scsih_determine_boot_device()
+ */
+static void
+_scsih_probe_boot_devices(struct MPT2SAS_ADAPTER *ioc)
+{
+       u8 is_raid;
+       void *device;
+       struct _sas_device *sas_device;
+       struct _raid_device *raid_device;
+       u16 handle, parent_handle;
+       u64 sas_address;
+       unsigned long flags;
+       int rc;
+
+       device = NULL;
+       if (ioc->req_boot_device.device) {
+               device =  ioc->req_boot_device.device;
+               is_raid = ioc->req_boot_device.is_raid;
+       } else if (ioc->req_alt_boot_device.device) {
+               device =  ioc->req_alt_boot_device.device;
+               is_raid = ioc->req_alt_boot_device.is_raid;
+       } else if (ioc->current_boot_device.device) {
+               device =  ioc->current_boot_device.device;
+               is_raid = ioc->current_boot_device.is_raid;
+       }
+
+       if (!device)
+               return;
+
+       if (is_raid) {
+               raid_device = device;
+               rc = scsi_add_device(ioc->shost, RAID_CHANNEL,
+                   raid_device->id, 0);
+               if (rc)
+                       _scsih_raid_device_remove(ioc, raid_device);
+       } else {
+               sas_device = device;
+               handle = sas_device->handle;
+               parent_handle = sas_device->parent_handle;
+               sas_address = sas_device->sas_address;
+               spin_lock_irqsave(&ioc->sas_device_lock, flags);
+               list_move_tail(&sas_device->list, &ioc->sas_device_list);
+               spin_unlock_irqrestore(&ioc->sas_device_lock, flags);
+               if (!mpt2sas_transport_port_add(ioc, sas_device->handle,
+                   sas_device->parent_handle)) {
+                       _scsih_sas_device_remove(ioc, sas_device);
+               } else if (!sas_device->starget) {
+                       mpt2sas_transport_port_remove(ioc, sas_address,
+                           parent_handle);
+                       _scsih_sas_device_remove(ioc, sas_device);
+               }
+       }
+}
+
+/**
+ * _scsih_probe_raid - reporting raid volumes to scsi-ml
+ * @ioc: per adapter object
+ *
+ * Called during initial loading of the driver.
+ */
+static void
+_scsih_probe_raid(struct MPT2SAS_ADAPTER *ioc)
+{
+       struct _raid_device *raid_device, *raid_next;
+       int rc;
+
+       list_for_each_entry_safe(raid_device, raid_next,
+           &ioc->raid_device_list, list) {
+               if (raid_device->starget)
+                       continue;
+               rc = scsi_add_device(ioc->shost, RAID_CHANNEL,
+                   raid_device->id, 0);
+               if (rc)
+                       _scsih_raid_device_remove(ioc, raid_device);
+       }
+}
+
+/**
+ * _scsih_probe_sas - reporting raid volumes to sas transport
+ * @ioc: per adapter object
+ *
+ * Called during initial loading of the driver.
+ */
+static void
+_scsih_probe_sas(struct MPT2SAS_ADAPTER *ioc)
+{
+       struct _sas_device *sas_device, *next;
+       unsigned long flags;
+       u16 handle, parent_handle;
+       u64 sas_address;
+
+       /* SAS Device List */
+       list_for_each_entry_safe(sas_device, next, &ioc->sas_device_init_list,
+           list) {
+               spin_lock_irqsave(&ioc->sas_device_lock, flags);
+               list_move_tail(&sas_device->list, &ioc->sas_device_list);
+               spin_unlock_irqrestore(&ioc->sas_device_lock, flags);
+
+               handle = sas_device->handle;
+               parent_handle = sas_device->parent_handle;
+               sas_address = sas_device->sas_address;
+               if (!mpt2sas_transport_port_add(ioc, handle, parent_handle)) {
+                       _scsih_sas_device_remove(ioc, sas_device);
+               } else if (!sas_device->starget) {
+                       mpt2sas_transport_port_remove(ioc, sas_address,
+                           parent_handle);
+                       _scsih_sas_device_remove(ioc, sas_device);
+               }
+       }
+}
+
+/**
+ * _scsih_probe_devices - probing for devices
+ * @ioc: per adapter object
+ *
+ * Called during initial loading of the driver.
+ */
+static void
+_scsih_probe_devices(struct MPT2SAS_ADAPTER *ioc)
+{
+       u16 volume_mapping_flags =
+           le16_to_cpu(ioc->ioc_pg8.IRVolumeMappingFlags) &
+           MPI2_IOCPAGE8_IRFLAGS_MASK_VOLUME_MAPPING_MODE;
+
+       if (!(ioc->facts.ProtocolFlags & MPI2_IOCFACTS_PROTOCOL_SCSI_INITIATOR))
+               return;  /* return when IOC doesn't support initiator mode */
+
+       _scsih_probe_boot_devices(ioc);
+
+       if (ioc->ir_firmware) {
+               if ((volume_mapping_flags &
+                    MPI2_IOCPAGE8_IRFLAGS_HIGH_VOLUME_MAPPING)) {
+                       _scsih_probe_sas(ioc);
+                       _scsih_probe_raid(ioc);
+               } else {
+                       _scsih_probe_raid(ioc);
+                       _scsih_probe_sas(ioc);
+               }
+       } else
+               _scsih_probe_sas(ioc);
+}
+
+/**
+ * scsih_probe - attach and add scsi host
+ * @pdev: PCI device struct
+ * @id: pci device id
+ *
+ * Returns 0 success, anything else error.
+ */
+static int
+scsih_probe(struct pci_dev *pdev, const struct pci_device_id *id)
+{
+       struct MPT2SAS_ADAPTER *ioc;
+       struct Scsi_Host *shost;
+
+       shost = scsi_host_alloc(&scsih_driver_template,
+           sizeof(struct MPT2SAS_ADAPTER));
+       if (!shost)
+               return -ENODEV;
+
+       /* init local params */
+       ioc = shost_priv(shost);
+       memset(ioc, 0, sizeof(struct MPT2SAS_ADAPTER));
+       INIT_LIST_HEAD(&ioc->list);
+       list_add_tail(&ioc->list, &ioc_list);
+       ioc->shost = shost;
+       ioc->id = mpt_ids++;
+       sprintf(ioc->name, "%s%d", MPT2SAS_DRIVER_NAME, ioc->id);
+       ioc->pdev = pdev;
+       ioc->scsi_io_cb_idx = scsi_io_cb_idx;
+       ioc->tm_cb_idx = tm_cb_idx;
+       ioc->ctl_cb_idx = ctl_cb_idx;
+       ioc->base_cb_idx = base_cb_idx;
+       ioc->transport_cb_idx = transport_cb_idx;
+       ioc->config_cb_idx = config_cb_idx;
+       ioc->logging_level = logging_level;
+       /* misc semaphores and spin locks */
+       spin_lock_init(&ioc->ioc_reset_in_progress_lock);
+       spin_lock_init(&ioc->scsi_lookup_lock);
+       spin_lock_init(&ioc->sas_device_lock);
+       spin_lock_init(&ioc->sas_node_lock);
+       spin_lock_init(&ioc->fw_event_lock);
+       spin_lock_init(&ioc->raid_device_lock);
+
+       INIT_LIST_HEAD(&ioc->sas_device_list);
+       INIT_LIST_HEAD(&ioc->sas_device_init_list);
+       INIT_LIST_HEAD(&ioc->sas_expander_list);
+       INIT_LIST_HEAD(&ioc->fw_event_list);
+       INIT_LIST_HEAD(&ioc->raid_device_list);
+       INIT_LIST_HEAD(&ioc->sas_hba.sas_port_list);
+
+       /* init shost parameters */
+       shost->max_cmd_len = 16;
+       shost->max_lun = max_lun;
+       shost->transportt = mpt2sas_transport_template;
+       shost->unique_id = ioc->id;
+
+       if ((scsi_add_host(shost, &pdev->dev))) {
+               printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
+                   ioc->name, __FILE__, __LINE__, __func__);
+               list_del(&ioc->list);
+               goto out_add_shost_fail;
+       }
+
+       /* event thread */
+       snprintf(ioc->firmware_event_name, sizeof(ioc->firmware_event_name),
+           "fw_event%d", ioc->id);
+       ioc->firmware_event_thread = create_singlethread_workqueue(
+           ioc->firmware_event_name);
+       if (!ioc->firmware_event_thread) {
+               printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
+                   ioc->name, __FILE__, __LINE__, __func__);
+               goto out_thread_fail;
+       }
+
+       ioc->wait_for_port_enable_to_complete = 1;
+       if ((mpt2sas_base_attach(ioc))) {
+               printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
+                   ioc->name, __FILE__, __LINE__, __func__);
+               goto out_attach_fail;
+       }
+
+       ioc->wait_for_port_enable_to_complete = 0;
+       _scsih_probe_devices(ioc);
+       return 0;
+
+ out_attach_fail:
+       destroy_workqueue(ioc->firmware_event_thread);
+ out_thread_fail:
+       list_del(&ioc->list);
+       scsi_remove_host(shost);
+ out_add_shost_fail:
+       return -ENODEV;
+}
+
+#ifdef CONFIG_PM
+/**
+ * scsih_suspend - power management suspend main entry point
+ * @pdev: PCI device struct
+ * @state: PM state change to (usually PCI_D3)
+ *
+ * Returns 0 success, anything else error.
+ */
+static int
+scsih_suspend(struct pci_dev *pdev, pm_message_t state)
+{
+       struct Scsi_Host *shost = pci_get_drvdata(pdev);
+       struct MPT2SAS_ADAPTER *ioc = shost_priv(shost);
+       u32 device_state;
+
+       flush_scheduled_work();
+       scsi_block_requests(shost);
+       device_state = pci_choose_state(pdev, state);
+       printk(MPT2SAS_INFO_FMT "pdev=0x%p, slot=%s, entering "
+           "operating state [D%d]\n", ioc->name, pdev,
+           pci_name(pdev), device_state);
+
+       mpt2sas_base_free_resources(ioc);
+       pci_save_state(pdev);
+       pci_disable_device(pdev);
+       pci_set_power_state(pdev, device_state);
+       return 0;
+}
+
+/**
+ * scsih_resume - power management resume main entry point
+ * @pdev: PCI device struct
+ *
+ * Returns 0 success, anything else error.
+ */
+static int
+scsih_resume(struct pci_dev *pdev)
+{
+       struct Scsi_Host *shost = pci_get_drvdata(pdev);
+       struct MPT2SAS_ADAPTER *ioc = shost_priv(shost);
+       u32 device_state = pdev->current_state;
+       int r;
+
+       printk(MPT2SAS_INFO_FMT "pdev=0x%p, slot=%s, previous "
+           "operating state [D%d]\n", ioc->name, pdev,
+           pci_name(pdev), device_state);
+
+       pci_set_power_state(pdev, PCI_D0);
+       pci_enable_wake(pdev, PCI_D0, 0);
+       pci_restore_state(pdev);
+       ioc->pdev = pdev;
+       r = mpt2sas_base_map_resources(ioc);
+       if (r)
+               return r;
+
+       mpt2sas_base_hard_reset_handler(ioc, CAN_SLEEP, SOFT_RESET);
+       scsi_unblock_requests(shost);
+       return 0;
+}
+#endif /* CONFIG_PM */
+
+
+static struct pci_driver scsih_driver = {
+       .name           = MPT2SAS_DRIVER_NAME,
+       .id_table       = scsih_pci_table,
+       .probe          = scsih_probe,
+       .remove         = __devexit_p(scsih_remove),
+#ifdef CONFIG_PM
+       .suspend        = scsih_suspend,
+       .resume         = scsih_resume,
+#endif
+};
+
+
+/**
+ * scsih_init - main entry point for this driver.
+ *
+ * Returns 0 success, anything else error.
+ */
+static int __init
+scsih_init(void)
+{
+       int error;
+
+       mpt_ids = 0;
+       printk(KERN_INFO "%s version %s loaded\n", MPT2SAS_DRIVER_NAME,
+           MPT2SAS_DRIVER_VERSION);
+
+       mpt2sas_transport_template =
+           sas_attach_transport(&mpt2sas_transport_functions);
+       if (!mpt2sas_transport_template)
+               return -ENODEV;
+
+       mpt2sas_base_initialize_callback_handler();
+
+        /* queuecommand callback hander */
+       scsi_io_cb_idx = mpt2sas_base_register_callback_handler(scsih_io_done);
+
+       /* task managment callback handler */
+       tm_cb_idx = mpt2sas_base_register_callback_handler(scsih_tm_done);
+
+       /* base internal commands callback handler */
+       base_cb_idx = mpt2sas_base_register_callback_handler(mpt2sas_base_done);
+
+       /* transport internal commands callback handler */
+       transport_cb_idx = mpt2sas_base_register_callback_handler(
+           mpt2sas_transport_done);
+
+       /* configuration page API internal commands callback handler */
+       config_cb_idx = mpt2sas_base_register_callback_handler(
+           mpt2sas_config_done);
+
+       /* ctl module callback handler */
+       ctl_cb_idx = mpt2sas_base_register_callback_handler(mpt2sas_ctl_done);
+
+       mpt2sas_ctl_init();
+
+       error = pci_register_driver(&scsih_driver);
+       if (error)
+               sas_release_transport(mpt2sas_transport_template);
+
+       return error;
+}
+
+/**
+ * scsih_exit - exit point for this driver (when it is a module).
+ *
+ * Returns 0 success, anything else error.
+ */
+static void __exit
+scsih_exit(void)
+{
+       printk(KERN_INFO "mpt2sas version %s unloading\n",
+           MPT2SAS_DRIVER_VERSION);
+
+       pci_unregister_driver(&scsih_driver);
+
+       sas_release_transport(mpt2sas_transport_template);
+       mpt2sas_base_release_callback_handler(scsi_io_cb_idx);
+       mpt2sas_base_release_callback_handler(tm_cb_idx);
+       mpt2sas_base_release_callback_handler(base_cb_idx);
+       mpt2sas_base_release_callback_handler(transport_cb_idx);
+       mpt2sas_base_release_callback_handler(config_cb_idx);
+       mpt2sas_base_release_callback_handler(ctl_cb_idx);
+
+       mpt2sas_ctl_exit();
+}
+
+module_init(scsih_init);
+module_exit(scsih_exit);
diff --git a/drivers/scsi/mpt2sas/mpt2sas_transport.c b/drivers/scsi/mpt2sas/mpt2sas_transport.c
new file mode 100644 (file)
index 0000000..e03dc0b
--- /dev/null
@@ -0,0 +1,1211 @@
+/*
+ * SAS Transport Layer for MPT (Message Passing Technology) based controllers
+ *
+ * This code is based on drivers/scsi/mpt2sas/mpt2_transport.c
+ * Copyright (C) 2007-2008  LSI Corporation
+ *  (mailto:DL-MPTFusionLinux@lsi.com)
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * NO WARRANTY
+ * THE PROGRAM IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OR
+ * CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED INCLUDING, WITHOUT
+ * LIMITATION, ANY WARRANTIES OR CONDITIONS OF TITLE, NON-INFRINGEMENT,
+ * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. Each Recipient is
+ * solely responsible for determining the appropriateness of using and
+ * distributing the Program and assumes all risks associated with its
+ * exercise of rights under this Agreement, including but not limited to
+ * the risks and costs of program errors, damage to or loss of data,
+ * programs or equipment, and unavailability or interruption of operations.
+
+ * DISCLAIMER OF LIABILITY
+ * NEITHER RECIPIENT NOR ANY CONTRIBUTORS SHALL HAVE ANY LIABILITY FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING WITHOUT LIMITATION LOST PROFITS), 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 OR DISTRIBUTION OF THE PROGRAM OR THE EXERCISE OF ANY RIGHTS GRANTED
+ * HEREUNDER, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGES
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301,
+ * USA.
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/errno.h>
+#include <linux/sched.h>
+#include <linux/workqueue.h>
+#include <linux/delay.h>
+#include <linux/pci.h>
+
+#include <scsi/scsi.h>
+#include <scsi/scsi_cmnd.h>
+#include <scsi/scsi_device.h>
+#include <scsi/scsi_host.h>
+#include <scsi/scsi_transport_sas.h>
+#include <scsi/scsi_dbg.h>
+
+#include "mpt2sas_base.h"
+/**
+ * _transport_sas_node_find_by_handle - sas node search
+ * @ioc: per adapter object
+ * @handle: expander or hba handle (assigned by firmware)
+ * Context: Calling function should acquire ioc->sas_node_lock.
+ *
+ * Search for either hba phys or expander device based on handle, then returns
+ * the sas_node object.
+ */
+static struct _sas_node *
+_transport_sas_node_find_by_handle(struct MPT2SAS_ADAPTER *ioc, u16 handle)
+{
+       int i;
+
+       for (i = 0; i < ioc->sas_hba.num_phys; i++)
+               if (ioc->sas_hba.phy[i].handle == handle)
+                       return &ioc->sas_hba;
+
+       return mpt2sas_scsih_expander_find_by_handle(ioc, handle);
+}
+
+/**
+ * _transport_convert_phy_link_rate -
+ * @link_rate: link rate returned from mpt firmware
+ *
+ * Convert link_rate from mpi fusion into sas_transport form.
+ */
+static enum sas_linkrate
+_transport_convert_phy_link_rate(u8 link_rate)
+{
+       enum sas_linkrate rc;
+
+       switch (link_rate) {
+       case MPI2_SAS_NEG_LINK_RATE_1_5:
+               rc = SAS_LINK_RATE_1_5_GBPS;
+               break;
+       case MPI2_SAS_NEG_LINK_RATE_3_0:
+               rc = SAS_LINK_RATE_3_0_GBPS;
+               break;
+       case MPI2_SAS_NEG_LINK_RATE_6_0:
+               rc = SAS_LINK_RATE_6_0_GBPS;
+               break;
+       case MPI2_SAS_NEG_LINK_RATE_PHY_DISABLED:
+               rc = SAS_PHY_DISABLED;
+               break;
+       case MPI2_SAS_NEG_LINK_RATE_NEGOTIATION_FAILED:
+               rc = SAS_LINK_RATE_FAILED;
+               break;
+       case MPI2_SAS_NEG_LINK_RATE_PORT_SELECTOR:
+               rc = SAS_SATA_PORT_SELECTOR;
+               break;
+       case MPI2_SAS_NEG_LINK_RATE_SMP_RESET_IN_PROGRESS:
+               rc = SAS_PHY_RESET_IN_PROGRESS;
+               break;
+       default:
+       case MPI2_SAS_NEG_LINK_RATE_SATA_OOB_COMPLETE:
+       case MPI2_SAS_NEG_LINK_RATE_UNKNOWN_LINK_RATE:
+               rc = SAS_LINK_RATE_UNKNOWN;
+               break;
+       }
+       return rc;
+}
+
+/**
+ * _transport_set_identify - set identify for phys and end devices
+ * @ioc: per adapter object
+ * @handle: device handle
+ * @identify: sas identify info
+ *
+ * Populates sas identify info.
+ *
+ * Returns 0 for success, non-zero for failure.
+ */
+static int
+_transport_set_identify(struct MPT2SAS_ADAPTER *ioc, u16 handle,
+    struct sas_identify *identify)
+{
+       Mpi2SasDevicePage0_t sas_device_pg0;
+       Mpi2ConfigReply_t mpi_reply;
+       u32 device_info;
+       u32 ioc_status;
+
+       if ((mpt2sas_config_get_sas_device_pg0(ioc, &mpi_reply, &sas_device_pg0,
+           MPI2_SAS_DEVICE_PGAD_FORM_HANDLE, handle))) {
+               printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
+                   ioc->name, __FILE__, __LINE__, __func__);
+               return -1;
+       }
+
+       ioc_status = le16_to_cpu(mpi_reply.IOCStatus) &
+           MPI2_IOCSTATUS_MASK;
+       if (ioc_status != MPI2_IOCSTATUS_SUCCESS) {
+               printk(MPT2SAS_ERR_FMT "handle(0x%04x), ioc_status(0x%04x)"
+                   "\nfailure at %s:%d/%s()!\n", ioc->name, handle, ioc_status,
+                    __FILE__, __LINE__, __func__);
+               return -1;
+       }
+
+       memset(identify, 0, sizeof(identify));
+       device_info = le32_to_cpu(sas_device_pg0.DeviceInfo);
+
+       /* sas_address */
+       identify->sas_address = le64_to_cpu(sas_device_pg0.SASAddress);
+
+       /* device_type */
+       switch (device_info & MPI2_SAS_DEVICE_INFO_MASK_DEVICE_TYPE) {
+       case MPI2_SAS_DEVICE_INFO_NO_DEVICE:
+               identify->device_type = SAS_PHY_UNUSED;
+               break;
+       case MPI2_SAS_DEVICE_INFO_END_DEVICE:
+               identify->device_type = SAS_END_DEVICE;
+               break;
+       case MPI2_SAS_DEVICE_INFO_EDGE_EXPANDER:
+               identify->device_type = SAS_EDGE_EXPANDER_DEVICE;
+               break;
+       case MPI2_SAS_DEVICE_INFO_FANOUT_EXPANDER:
+               identify->device_type = SAS_FANOUT_EXPANDER_DEVICE;
+               break;
+       }
+
+       /* initiator_port_protocols */
+       if (device_info & MPI2_SAS_DEVICE_INFO_SSP_INITIATOR)
+               identify->initiator_port_protocols |= SAS_PROTOCOL_SSP;
+       if (device_info & MPI2_SAS_DEVICE_INFO_STP_INITIATOR)
+               identify->initiator_port_protocols |= SAS_PROTOCOL_STP;
+       if (device_info & MPI2_SAS_DEVICE_INFO_SMP_INITIATOR)
+               identify->initiator_port_protocols |= SAS_PROTOCOL_SMP;
+       if (device_info & MPI2_SAS_DEVICE_INFO_SATA_HOST)
+               identify->initiator_port_protocols |= SAS_PROTOCOL_SATA;
+
+       /* target_port_protocols */
+       if (device_info & MPI2_SAS_DEVICE_INFO_SSP_TARGET)
+               identify->target_port_protocols |= SAS_PROTOCOL_SSP;
+       if (device_info & MPI2_SAS_DEVICE_INFO_STP_TARGET)
+               identify->target_port_protocols |= SAS_PROTOCOL_STP;
+       if (device_info & MPI2_SAS_DEVICE_INFO_SMP_TARGET)
+               identify->target_port_protocols |= SAS_PROTOCOL_SMP;
+       if (device_info & MPI2_SAS_DEVICE_INFO_SATA_DEVICE)
+               identify->target_port_protocols |= SAS_PROTOCOL_SATA;
+
+       return 0;
+}
+
+/**
+ * mpt2sas_transport_done -  internal transport layer callback handler.
+ * @ioc: per adapter object
+ * @smid: system request message index
+ * @VF_ID: virtual function id
+ * @reply: reply message frame(lower 32bit addr)
+ *
+ * Callback handler when sending internal generated transport cmds.
+ * The callback index passed is `ioc->transport_cb_idx`
+ *
+ * Return nothing.
+ */
+void
+mpt2sas_transport_done(struct MPT2SAS_ADAPTER *ioc, u16 smid, u8 VF_ID,
+    u32 reply)
+{
+       MPI2DefaultReply_t *mpi_reply;
+
+       mpi_reply =  mpt2sas_base_get_reply_virt_addr(ioc, reply);
+       if (ioc->transport_cmds.status == MPT2_CMD_NOT_USED)
+               return;
+       if (ioc->transport_cmds.smid != smid)
+               return;
+       ioc->transport_cmds.status |= MPT2_CMD_COMPLETE;
+       if (mpi_reply) {
+               memcpy(ioc->transport_cmds.reply, mpi_reply,
+                   mpi_reply->MsgLength*4);
+               ioc->transport_cmds.status |= MPT2_CMD_REPLY_VALID;
+       }
+       ioc->transport_cmds.status &= ~MPT2_CMD_PENDING;
+       complete(&ioc->transport_cmds.done);
+}
+
+/* report manufacture request structure */
+struct rep_manu_request{
+       u8 smp_frame_type;
+       u8 function;
+       u8 reserved;
+       u8 request_length;
+};
+
+/* report manufacture reply structure */
+struct rep_manu_reply{
+       u8 smp_frame_type; /* 0x41 */
+       u8 function; /* 0x01 */
+       u8 function_result;
+       u8 response_length;
+       u16 expander_change_count;
+       u8 reserved0[2];
+       u8 sas_format:1;
+       u8 reserved1:7;
+       u8 reserved2[3];
+       u8 vendor_id[SAS_EXPANDER_VENDOR_ID_LEN];
+       u8 product_id[SAS_EXPANDER_PRODUCT_ID_LEN];
+       u8 product_rev[SAS_EXPANDER_PRODUCT_REV_LEN];
+       u8 component_vendor_id[SAS_EXPANDER_COMPONENT_VENDOR_ID_LEN];
+       u16 component_id;
+       u8 component_revision_id;
+       u8 reserved3;
+       u8 vendor_specific[8];
+};
+
+/**
+ * transport_expander_report_manufacture - obtain SMP report_manufacture
+ * @ioc: per adapter object
+ * @sas_address: expander sas address
+ * @edev: the sas_expander_device object
+ *
+ * Fills in the sas_expander_device object when SMP port is created.
+ *
+ * Returns 0 for success, non-zero for failure.
+ */
+static int
+transport_expander_report_manufacture(struct MPT2SAS_ADAPTER *ioc,
+    u64 sas_address, struct sas_expander_device *edev)
+{
+       Mpi2SmpPassthroughRequest_t *mpi_request;
+       Mpi2SmpPassthroughReply_t *mpi_reply;
+       struct rep_manu_reply *manufacture_reply;
+       struct rep_manu_request *manufacture_request;
+       int rc;
+       u16 smid;
+       u32 ioc_state;
+       unsigned long timeleft;
+       void *psge;
+       u32 sgl_flags;
+       u8 issue_reset = 0;
+       unsigned long flags;
+       void *data_out = NULL;
+       dma_addr_t data_out_dma;
+       u32 sz;
+       u64 *sas_address_le;
+       u16 wait_state_count;
+
+       spin_lock_irqsave(&ioc->ioc_reset_in_progress_lock, flags);
+       if (ioc->ioc_reset_in_progress) {
+               spin_unlock_irqrestore(&ioc->ioc_reset_in_progress_lock, flags);
+               printk(MPT2SAS_INFO_FMT "%s: host reset in progress!\n",
+                   __func__, ioc->name);
+               return -EFAULT;
+       }
+       spin_unlock_irqrestore(&ioc->ioc_reset_in_progress_lock, flags);
+
+       mutex_lock(&ioc->transport_cmds.mutex);
+
+       if (ioc->transport_cmds.status != MPT2_CMD_NOT_USED) {
+               printk(MPT2SAS_ERR_FMT "%s: transport_cmds in use\n",
+                   ioc->name, __func__);
+               rc = -EAGAIN;
+               goto out;
+       }
+       ioc->transport_cmds.status = MPT2_CMD_PENDING;
+
+       wait_state_count = 0;
+       ioc_state = mpt2sas_base_get_iocstate(ioc, 1);
+       while (ioc_state != MPI2_IOC_STATE_OPERATIONAL) {
+               if (wait_state_count++ == 10) {
+                       printk(MPT2SAS_ERR_FMT
+                           "%s: failed due to ioc not operational\n",
+                           ioc->name, __func__);
+                       rc = -EFAULT;
+                       goto out;
+               }
+               ssleep(1);
+               ioc_state = mpt2sas_base_get_iocstate(ioc, 1);
+               printk(MPT2SAS_INFO_FMT "%s: waiting for "
+                   "operational state(count=%d)\n", ioc->name,
+                   __func__, wait_state_count);
+       }
+       if (wait_state_count)
+               printk(MPT2SAS_INFO_FMT "%s: ioc is operational\n",
+                   ioc->name, __func__);
+
+       smid = mpt2sas_base_get_smid(ioc, ioc->transport_cb_idx);
+       if (!smid) {
+               printk(MPT2SAS_ERR_FMT "%s: failed obtaining a smid\n",
+                   ioc->name, __func__);
+               rc = -EAGAIN;
+               goto out;
+       }
+
+       rc = 0;
+       mpi_request = mpt2sas_base_get_msg_frame(ioc, smid);
+       ioc->transport_cmds.smid = smid;
+
+       sz = sizeof(struct rep_manu_request) + sizeof(struct rep_manu_reply);
+       data_out = pci_alloc_consistent(ioc->pdev, sz, &data_out_dma);
+
+       if (!data_out) {
+               printk(KERN_ERR "failure at %s:%d/%s()!\n", __FILE__,
+                   __LINE__, __func__);
+               rc = -ENOMEM;
+               mpt2sas_base_free_smid(ioc, smid);
+               goto out;
+       }
+
+       manufacture_request = data_out;
+       manufacture_request->smp_frame_type = 0x40;
+       manufacture_request->function = 1;
+       manufacture_request->reserved = 0;
+       manufacture_request->request_length = 0;
+
+       memset(mpi_request, 0, sizeof(Mpi2SmpPassthroughRequest_t));
+       mpi_request->Function = MPI2_FUNCTION_SMP_PASSTHROUGH;
+       mpi_request->PhysicalPort = 0xFF;
+       sas_address_le = (u64 *)&mpi_request->SASAddress;
+       *sas_address_le = cpu_to_le64(sas_address);
+       mpi_request->RequestDataLength = sizeof(struct rep_manu_request);
+       psge = &mpi_request->SGL;
+
+       /* WRITE sgel first */
+       sgl_flags = (MPI2_SGE_FLAGS_SIMPLE_ELEMENT |
+           MPI2_SGE_FLAGS_END_OF_BUFFER | MPI2_SGE_FLAGS_HOST_TO_IOC);
+       sgl_flags = sgl_flags << MPI2_SGE_FLAGS_SHIFT;
+       ioc->base_add_sg_single(psge, sgl_flags |
+           sizeof(struct rep_manu_request), data_out_dma);
+
+       /* incr sgel */
+       psge += ioc->sge_size;
+
+       /* READ sgel last */
+       sgl_flags = (MPI2_SGE_FLAGS_SIMPLE_ELEMENT |
+           MPI2_SGE_FLAGS_LAST_ELEMENT | MPI2_SGE_FLAGS_END_OF_BUFFER |
+           MPI2_SGE_FLAGS_END_OF_LIST);
+       sgl_flags = sgl_flags << MPI2_SGE_FLAGS_SHIFT;
+       ioc->base_add_sg_single(psge, sgl_flags |
+           sizeof(struct rep_manu_reply), data_out_dma +
+           sizeof(struct rep_manu_request));
+
+       dtransportprintk(ioc, printk(MPT2SAS_DEBUG_FMT "report_manufacture - "
+           "send to sas_addr(0x%016llx)\n", ioc->name,
+           (unsigned long long)sas_address));
+       mpt2sas_base_put_smid_default(ioc, smid, 0 /* VF_ID */);
+       timeleft = wait_for_completion_timeout(&ioc->transport_cmds.done,
+           10*HZ);
+
+       if (!(ioc->transport_cmds.status & MPT2_CMD_COMPLETE)) {
+               printk(MPT2SAS_ERR_FMT "%s: timeout\n",
+                   ioc->name, __func__);
+               _debug_dump_mf(mpi_request,
+                   sizeof(Mpi2SmpPassthroughRequest_t)/4);
+               if (!(ioc->transport_cmds.status & MPT2_CMD_RESET))
+                       issue_reset = 1;
+               goto issue_host_reset;
+       }
+
+       dtransportprintk(ioc, printk(MPT2SAS_DEBUG_FMT "report_manufacture - "
+           "complete\n", ioc->name));
+
+       if (ioc->transport_cmds.status & MPT2_CMD_REPLY_VALID) {
+               u8 *tmp;
+
+               mpi_reply = ioc->transport_cmds.reply;
+
+               dtransportprintk(ioc, printk(MPT2SAS_DEBUG_FMT
+                   "report_manufacture - reply data transfer size(%d)\n",
+                   ioc->name, le16_to_cpu(mpi_reply->ResponseDataLength)));
+
+               if (le16_to_cpu(mpi_reply->ResponseDataLength) !=
+                   sizeof(struct rep_manu_reply))
+                       goto out;
+
+               manufacture_reply = data_out + sizeof(struct rep_manu_request);
+               strncpy(edev->vendor_id, manufacture_reply->vendor_id,
+                    SAS_EXPANDER_VENDOR_ID_LEN);
+               strncpy(edev->product_id, manufacture_reply->product_id,
+                    SAS_EXPANDER_PRODUCT_ID_LEN);
+               strncpy(edev->product_rev, manufacture_reply->product_rev,
+                    SAS_EXPANDER_PRODUCT_REV_LEN);
+               edev->level = manufacture_reply->sas_format;
+               if (manufacture_reply->sas_format) {
+                       strncpy(edev->component_vendor_id,
+                           manufacture_reply->component_vendor_id,
+                            SAS_EXPANDER_COMPONENT_VENDOR_ID_LEN);
+                       tmp = (u8 *)&manufacture_reply->component_id;
+                       edev->component_id = tmp[0] << 8 | tmp[1];
+                       edev->component_revision_id =
+                           manufacture_reply->component_revision_id;
+               }
+       } else
+               dtransportprintk(ioc, printk(MPT2SAS_DEBUG_FMT
+                   "report_manufacture - no reply\n", ioc->name));
+
+ issue_host_reset:
+       if (issue_reset)
+               mpt2sas_base_hard_reset_handler(ioc, CAN_SLEEP,
+                   FORCE_BIG_HAMMER);
+ out:
+       ioc->transport_cmds.status = MPT2_CMD_NOT_USED;
+       if (data_out)
+               pci_free_consistent(ioc->pdev, sz, data_out, data_out_dma);
+
+       mutex_unlock(&ioc->transport_cmds.mutex);
+       return rc;
+}
+
+/**
+ * mpt2sas_transport_port_add - insert port to the list
+ * @ioc: per adapter object
+ * @handle: handle of attached device
+ * @parent_handle: parent handle(either hba or expander)
+ * Context: This function will acquire ioc->sas_node_lock.
+ *
+ * Adding new port object to the sas_node->sas_port_list.
+ *
+ * Returns mpt2sas_port.
+ */
+struct _sas_port *
+mpt2sas_transport_port_add(struct MPT2SAS_ADAPTER *ioc, u16 handle,
+    u16 parent_handle)
+{
+       struct _sas_phy *mpt2sas_phy, *next;
+       struct _sas_port *mpt2sas_port;
+       unsigned long flags;
+       struct _sas_node *sas_node;
+       struct sas_rphy *rphy;
+       int i;
+       struct sas_port *port;
+
+       if (!parent_handle)
+               return NULL;
+
+       mpt2sas_port = kzalloc(sizeof(struct _sas_port),
+           GFP_KERNEL);
+       if (!mpt2sas_port) {
+               printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
+                   ioc->name, __FILE__, __LINE__, __func__);
+               return NULL;
+       }
+
+       INIT_LIST_HEAD(&mpt2sas_port->port_list);
+       INIT_LIST_HEAD(&mpt2sas_port->phy_list);
+       spin_lock_irqsave(&ioc->sas_node_lock, flags);
+       sas_node = _transport_sas_node_find_by_handle(ioc, parent_handle);
+       spin_unlock_irqrestore(&ioc->sas_node_lock, flags);
+
+       if (!sas_node) {
+               printk(MPT2SAS_ERR_FMT "%s: Could not find parent(0x%04x)!\n",
+                   ioc->name, __func__, parent_handle);
+               goto out_fail;
+       }
+
+       mpt2sas_port->handle = parent_handle;
+       mpt2sas_port->sas_address = sas_node->sas_address;
+       if ((_transport_set_identify(ioc, handle,
+           &mpt2sas_port->remote_identify))) {
+               printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
+                   ioc->name, __FILE__, __LINE__, __func__);
+               goto out_fail;
+       }
+
+       if (mpt2sas_port->remote_identify.device_type == SAS_PHY_UNUSED) {
+               printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
+                   ioc->name, __FILE__, __LINE__, __func__);
+               goto out_fail;
+       }
+
+       for (i = 0; i < sas_node->num_phys; i++) {
+               if (sas_node->phy[i].remote_identify.sas_address !=
+                   mpt2sas_port->remote_identify.sas_address)
+                       continue;
+               list_add_tail(&sas_node->phy[i].port_siblings,
+                   &mpt2sas_port->phy_list);
+               mpt2sas_port->num_phys++;
+       }
+
+       if (!mpt2sas_port->num_phys) {
+               printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
+                   ioc->name, __FILE__, __LINE__, __func__);
+               goto out_fail;
+       }
+
+       port = sas_port_alloc_num(sas_node->parent_dev);
+       if ((sas_port_add(port))) {
+               printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
+                   ioc->name, __FILE__, __LINE__, __func__);
+               goto out_fail;
+       }
+
+       list_for_each_entry(mpt2sas_phy, &mpt2sas_port->phy_list,
+           port_siblings) {
+               if ((ioc->logging_level & MPT_DEBUG_TRANSPORT))
+                       dev_printk(KERN_INFO, &port->dev, "add: handle(0x%04x)"
+                           ", sas_addr(0x%016llx), phy(%d)\n", handle,
+                           (unsigned long long)
+                           mpt2sas_port->remote_identify.sas_address,
+                           mpt2sas_phy->phy_id);
+               sas_port_add_phy(port, mpt2sas_phy->phy);
+       }
+
+       mpt2sas_port->port = port;
+       if (mpt2sas_port->remote_identify.device_type == SAS_END_DEVICE)
+               rphy = sas_end_device_alloc(port);
+       else
+               rphy = sas_expander_alloc(port,
+                   mpt2sas_port->remote_identify.device_type);
+
+       rphy->identify = mpt2sas_port->remote_identify;
+       if ((sas_rphy_add(rphy))) {
+               printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
+                   ioc->name, __FILE__, __LINE__, __func__);
+       }
+       if ((ioc->logging_level & MPT_DEBUG_TRANSPORT))
+               dev_printk(KERN_INFO, &rphy->dev, "add: handle(0x%04x), "
+                   "sas_addr(0x%016llx)\n", handle,
+                   (unsigned long long)
+                   mpt2sas_port->remote_identify.sas_address);
+       mpt2sas_port->rphy = rphy;
+       spin_lock_irqsave(&ioc->sas_node_lock, flags);
+       list_add_tail(&mpt2sas_port->port_list, &sas_node->sas_port_list);
+       spin_unlock_irqrestore(&ioc->sas_node_lock, flags);
+
+       /* fill in report manufacture */
+       if (mpt2sas_port->remote_identify.device_type ==
+           MPI2_SAS_DEVICE_INFO_EDGE_EXPANDER ||
+           mpt2sas_port->remote_identify.device_type ==
+           MPI2_SAS_DEVICE_INFO_FANOUT_EXPANDER)
+               transport_expander_report_manufacture(ioc,
+                   mpt2sas_port->remote_identify.sas_address,
+                   rphy_to_expander_device(rphy));
+
+       return mpt2sas_port;
+
+ out_fail:
+       list_for_each_entry_safe(mpt2sas_phy, next, &mpt2sas_port->phy_list,
+           port_siblings)
+               list_del(&mpt2sas_phy->port_siblings);
+       kfree(mpt2sas_port);
+       return NULL;
+}
+
+/**
+ * mpt2sas_transport_port_remove - remove port from the list
+ * @ioc: per adapter object
+ * @sas_address: sas address of attached device
+ * @parent_handle: handle to the upstream parent(either hba or expander)
+ * Context: This function will acquire ioc->sas_node_lock.
+ *
+ * Removing object and freeing associated memory from the
+ * ioc->sas_port_list.
+ *
+ * Return nothing.
+ */
+void
+mpt2sas_transport_port_remove(struct MPT2SAS_ADAPTER *ioc, u64 sas_address,
+    u16 parent_handle)
+{
+       int i;
+       unsigned long flags;
+       struct _sas_port *mpt2sas_port, *next;
+       struct _sas_node *sas_node;
+       u8 found = 0;
+       struct _sas_phy *mpt2sas_phy, *next_phy;
+
+       spin_lock_irqsave(&ioc->sas_node_lock, flags);
+       sas_node = _transport_sas_node_find_by_handle(ioc, parent_handle);
+       spin_unlock_irqrestore(&ioc->sas_node_lock, flags);
+       if (!sas_node)
+               return;
+       list_for_each_entry_safe(mpt2sas_port, next, &sas_node->sas_port_list,
+           port_list) {
+               if (mpt2sas_port->remote_identify.sas_address != sas_address)
+                       continue;
+               found = 1;
+               list_del(&mpt2sas_port->port_list);
+               goto out;
+       }
+ out:
+       if (!found)
+               return;
+
+       for (i = 0; i < sas_node->num_phys; i++) {
+               if (sas_node->phy[i].remote_identify.sas_address == sas_address)
+                       memset(&sas_node->phy[i].remote_identify, 0 ,
+                           sizeof(struct sas_identify));
+       }
+
+       list_for_each_entry_safe(mpt2sas_phy, next_phy,
+           &mpt2sas_port->phy_list, port_siblings) {
+               if ((ioc->logging_level & MPT_DEBUG_TRANSPORT))
+                       dev_printk(KERN_INFO, &mpt2sas_port->port->dev,
+                           "remove: parent_handle(0x%04x), "
+                           "sas_addr(0x%016llx), phy(%d)\n", parent_handle,
+                           (unsigned long long)
+                           mpt2sas_port->remote_identify.sas_address,
+                           mpt2sas_phy->phy_id);
+               sas_port_delete_phy(mpt2sas_port->port, mpt2sas_phy->phy);
+               list_del(&mpt2sas_phy->port_siblings);
+       }
+       sas_port_delete(mpt2sas_port->port);
+       kfree(mpt2sas_port);
+}
+
+/**
+ * mpt2sas_transport_add_host_phy - report sas_host phy to transport
+ * @ioc: per adapter object
+ * @mpt2sas_phy: mpt2sas per phy object
+ * @phy_pg0: sas phy page 0
+ * @parent_dev: parent device class object
+ *
+ * Returns 0 for success, non-zero for failure.
+ */
+int
+mpt2sas_transport_add_host_phy(struct MPT2SAS_ADAPTER *ioc, struct _sas_phy
+    *mpt2sas_phy, Mpi2SasPhyPage0_t phy_pg0, struct device *parent_dev)
+{
+       struct sas_phy *phy;
+       int phy_index = mpt2sas_phy->phy_id;
+
+
+       INIT_LIST_HEAD(&mpt2sas_phy->port_siblings);
+       phy = sas_phy_alloc(parent_dev, phy_index);
+       if (!phy) {
+               printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
+                   ioc->name, __FILE__, __LINE__, __func__);
+               return -1;
+       }
+       if ((_transport_set_identify(ioc, mpt2sas_phy->handle,
+           &mpt2sas_phy->identify))) {
+               printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
+                   ioc->name, __FILE__, __LINE__, __func__);
+               return -1;
+       }
+       phy->identify = mpt2sas_phy->identify;
+       mpt2sas_phy->attached_handle = le16_to_cpu(phy_pg0.AttachedDevHandle);
+       if (mpt2sas_phy->attached_handle)
+               _transport_set_identify(ioc, mpt2sas_phy->attached_handle,
+                   &mpt2sas_phy->remote_identify);
+       phy->identify.phy_identifier = mpt2sas_phy->phy_id;
+       phy->negotiated_linkrate = _transport_convert_phy_link_rate(
+           phy_pg0.NegotiatedLinkRate & MPI2_SAS_NEG_LINK_RATE_MASK_PHYSICAL);
+       phy->minimum_linkrate_hw = _transport_convert_phy_link_rate(
+           phy_pg0.HwLinkRate & MPI2_SAS_HWRATE_MIN_RATE_MASK);
+       phy->maximum_linkrate_hw = _transport_convert_phy_link_rate(
+           phy_pg0.HwLinkRate >> 4);
+       phy->minimum_linkrate = _transport_convert_phy_link_rate(
+           phy_pg0.ProgrammedLinkRate & MPI2_SAS_PRATE_MIN_RATE_MASK);
+       phy->maximum_linkrate = _transport_convert_phy_link_rate(
+           phy_pg0.ProgrammedLinkRate >> 4);
+
+       if ((sas_phy_add(phy))) {
+               printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
+                   ioc->name, __FILE__, __LINE__, __func__);
+               sas_phy_free(phy);
+               return -1;
+       }
+       if ((ioc->logging_level & MPT_DEBUG_TRANSPORT))
+               dev_printk(KERN_INFO, &phy->dev,
+                   "add: handle(0x%04x), sas_addr(0x%016llx)\n"
+                   "\tattached_handle(0x%04x), sas_addr(0x%016llx)\n",
+                   mpt2sas_phy->handle, (unsigned long long)
+                   mpt2sas_phy->identify.sas_address,
+                   mpt2sas_phy->attached_handle,
+                   (unsigned long long)
+                   mpt2sas_phy->remote_identify.sas_address);
+       mpt2sas_phy->phy = phy;
+       return 0;
+}
+
+
+/**
+ * mpt2sas_transport_add_expander_phy - report expander phy to transport
+ * @ioc: per adapter object
+ * @mpt2sas_phy: mpt2sas per phy object
+ * @expander_pg1: expander page 1
+ * @parent_dev: parent device class object
+ *
+ * Returns 0 for success, non-zero for failure.
+ */
+int
+mpt2sas_transport_add_expander_phy(struct MPT2SAS_ADAPTER *ioc, struct _sas_phy
+    *mpt2sas_phy, Mpi2ExpanderPage1_t expander_pg1, struct device *parent_dev)
+{
+       struct sas_phy *phy;
+       int phy_index = mpt2sas_phy->phy_id;
+
+       INIT_LIST_HEAD(&mpt2sas_phy->port_siblings);
+       phy = sas_phy_alloc(parent_dev, phy_index);
+       if (!phy) {
+               printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
+                   ioc->name, __FILE__, __LINE__, __func__);
+               return -1;
+       }
+       if ((_transport_set_identify(ioc, mpt2sas_phy->handle,
+           &mpt2sas_phy->identify))) {
+               printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
+                   ioc->name, __FILE__, __LINE__, __func__);
+               return -1;
+       }
+       phy->identify = mpt2sas_phy->identify;
+       mpt2sas_phy->attached_handle =
+           le16_to_cpu(expander_pg1.AttachedDevHandle);
+       if (mpt2sas_phy->attached_handle)
+               _transport_set_identify(ioc, mpt2sas_phy->attached_handle,
+                   &mpt2sas_phy->remote_identify);
+       phy->identify.phy_identifier = mpt2sas_phy->phy_id;
+       phy->negotiated_linkrate = _transport_convert_phy_link_rate(
+           expander_pg1.NegotiatedLinkRate &
+           MPI2_SAS_NEG_LINK_RATE_MASK_PHYSICAL);
+       phy->minimum_linkrate_hw = _transport_convert_phy_link_rate(
+           expander_pg1.HwLinkRate & MPI2_SAS_HWRATE_MIN_RATE_MASK);
+       phy->maximum_linkrate_hw = _transport_convert_phy_link_rate(
+           expander_pg1.HwLinkRate >> 4);
+       phy->minimum_linkrate = _transport_convert_phy_link_rate(
+           expander_pg1.ProgrammedLinkRate & MPI2_SAS_PRATE_MIN_RATE_MASK);
+       phy->maximum_linkrate = _transport_convert_phy_link_rate(
+           expander_pg1.ProgrammedLinkRate >> 4);
+
+       if ((sas_phy_add(phy))) {
+               printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
+                   ioc->name, __FILE__, __LINE__, __func__);
+               sas_phy_free(phy);
+               return -1;
+       }
+       if ((ioc->logging_level & MPT_DEBUG_TRANSPORT))
+               dev_printk(KERN_INFO, &phy->dev,
+                   "add: handle(0x%04x), sas_addr(0x%016llx)\n"
+                   "\tattached_handle(0x%04x), sas_addr(0x%016llx)\n",
+                   mpt2sas_phy->handle, (unsigned long long)
+                   mpt2sas_phy->identify.sas_address,
+                   mpt2sas_phy->attached_handle,
+                   (unsigned long long)
+                   mpt2sas_phy->remote_identify.sas_address);
+       mpt2sas_phy->phy = phy;
+       return 0;
+}
+
+/**
+ * mpt2sas_transport_update_phy_link_change - refreshing phy link changes and attached devices
+ * @ioc: per adapter object
+ * @handle: handle to sas_host or expander
+ * @attached_handle: attached device handle
+ * @phy_numberv: phy number
+ * @link_rate: new link rate
+ *
+ * Returns nothing.
+ */
+void
+mpt2sas_transport_update_phy_link_change(struct MPT2SAS_ADAPTER *ioc,
+    u16 handle, u16 attached_handle, u8 phy_number, u8 link_rate)
+{
+       unsigned long flags;
+       struct _sas_node *sas_node;
+       struct _sas_phy *mpt2sas_phy;
+
+       spin_lock_irqsave(&ioc->sas_node_lock, flags);
+       sas_node = _transport_sas_node_find_by_handle(ioc, handle);
+       spin_unlock_irqrestore(&ioc->sas_node_lock, flags);
+       if (!sas_node)
+               return;
+
+       mpt2sas_phy = &sas_node->phy[phy_number];
+       mpt2sas_phy->attached_handle = attached_handle;
+       if (attached_handle && (link_rate >= MPI2_SAS_NEG_LINK_RATE_1_5))
+               _transport_set_identify(ioc, mpt2sas_phy->attached_handle,
+                   &mpt2sas_phy->remote_identify);
+       else
+               memset(&mpt2sas_phy->remote_identify, 0 , sizeof(struct
+                   sas_identify));
+
+       if (mpt2sas_phy->phy)
+               mpt2sas_phy->phy->negotiated_linkrate =
+                   _transport_convert_phy_link_rate(link_rate);
+
+       if ((ioc->logging_level & MPT_DEBUG_TRANSPORT))
+               dev_printk(KERN_INFO, &mpt2sas_phy->phy->dev,
+                   "refresh: handle(0x%04x), sas_addr(0x%016llx),\n"
+                   "\tlink_rate(0x%02x), phy(%d)\n"
+                   "\tattached_handle(0x%04x), sas_addr(0x%016llx)\n",
+                   handle, (unsigned long long)
+                   mpt2sas_phy->identify.sas_address, link_rate,
+                   phy_number, attached_handle,
+                   (unsigned long long)
+                   mpt2sas_phy->remote_identify.sas_address);
+}
+
+static inline void *
+phy_to_ioc(struct sas_phy *phy)
+{
+       struct Scsi_Host *shost = dev_to_shost(phy->dev.parent);
+       return shost_priv(shost);
+}
+
+static inline void *
+rphy_to_ioc(struct sas_rphy *rphy)
+{
+       struct Scsi_Host *shost = dev_to_shost(rphy->dev.parent->parent);
+       return shost_priv(shost);
+}
+
+/**
+ * transport_get_linkerrors -
+ * @phy: The sas phy object
+ *
+ * Only support sas_host direct attached phys.
+ * Returns 0 for success, non-zero for failure.
+ *
+ */
+static int
+transport_get_linkerrors(struct sas_phy *phy)
+{
+       struct MPT2SAS_ADAPTER *ioc = phy_to_ioc(phy);
+       struct _sas_phy *mpt2sas_phy;
+       Mpi2ConfigReply_t mpi_reply;
+       Mpi2SasPhyPage1_t phy_pg1;
+       int i;
+
+       for (i = 0, mpt2sas_phy = NULL; i < ioc->sas_hba.num_phys &&
+           !mpt2sas_phy; i++) {
+               if (ioc->sas_hba.phy[i].phy != phy)
+                       continue;
+               mpt2sas_phy = &ioc->sas_hba.phy[i];
+       }
+
+       if (!mpt2sas_phy) /* this phy not on sas_host */
+               return -EINVAL;
+
+       if ((mpt2sas_config_get_phy_pg1(ioc, &mpi_reply, &phy_pg1,
+                   mpt2sas_phy->phy_id))) {
+               printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
+                   ioc->name, __FILE__, __LINE__, __func__);
+               return -ENXIO;
+       }
+
+       if (mpi_reply.IOCStatus || mpi_reply.IOCLogInfo)
+               printk(MPT2SAS_INFO_FMT "phy(%d), ioc_status"
+                   "(0x%04x), loginfo(0x%08x)\n", ioc->name,
+                   mpt2sas_phy->phy_id,
+                   le16_to_cpu(mpi_reply.IOCStatus),
+                   le32_to_cpu(mpi_reply.IOCLogInfo));
+
+       phy->invalid_dword_count = le32_to_cpu(phy_pg1.InvalidDwordCount);
+       phy->running_disparity_error_count =
+           le32_to_cpu(phy_pg1.RunningDisparityErrorCount);
+       phy->loss_of_dword_sync_count =
+           le32_to_cpu(phy_pg1.LossDwordSynchCount);
+       phy->phy_reset_problem_count =
+           le32_to_cpu(phy_pg1.PhyResetProblemCount);
+       return 0;
+}
+
+/**
+ * transport_get_enclosure_identifier -
+ * @phy: The sas phy object
+ *
+ * Obtain the enclosure logical id for an expander.
+ * Returns 0 for success, non-zero for failure.
+ */
+static int
+transport_get_enclosure_identifier(struct sas_rphy *rphy, u64 *identifier)
+{
+       struct MPT2SAS_ADAPTER *ioc = rphy_to_ioc(rphy);
+       struct _sas_node *sas_expander;
+       unsigned long flags;
+
+       spin_lock_irqsave(&ioc->sas_node_lock, flags);
+       sas_expander = mpt2sas_scsih_expander_find_by_sas_address(ioc,
+           rphy->identify.sas_address);
+       spin_unlock_irqrestore(&ioc->sas_node_lock, flags);
+
+       if (!sas_expander)
+               return -ENXIO;
+
+       *identifier = sas_expander->enclosure_logical_id;
+       return 0;
+}
+
+/**
+ * transport_get_bay_identifier -
+ * @phy: The sas phy object
+ *
+ * Returns the slot id for a device that resides inside an enclosure.
+ */
+static int
+transport_get_bay_identifier(struct sas_rphy *rphy)
+{
+       struct MPT2SAS_ADAPTER *ioc = rphy_to_ioc(rphy);
+       struct _sas_device *sas_device;
+       unsigned long flags;
+
+       spin_lock_irqsave(&ioc->sas_device_lock, flags);
+       sas_device = mpt2sas_scsih_sas_device_find_by_sas_address(ioc,
+           rphy->identify.sas_address);
+       spin_unlock_irqrestore(&ioc->sas_device_lock, flags);
+
+       if (!sas_device)
+               return -ENXIO;
+
+       return sas_device->slot;
+}
+
+/**
+ * transport_phy_reset -
+ * @phy: The sas phy object
+ * @hard_reset:
+ *
+ * Only support sas_host direct attached phys.
+ * Returns 0 for success, non-zero for failure.
+ */
+static int
+transport_phy_reset(struct sas_phy *phy, int hard_reset)
+{
+       struct MPT2SAS_ADAPTER *ioc = phy_to_ioc(phy);
+       struct _sas_phy *mpt2sas_phy;
+       Mpi2SasIoUnitControlReply_t mpi_reply;
+       Mpi2SasIoUnitControlRequest_t mpi_request;
+       int i;
+
+       for (i = 0, mpt2sas_phy = NULL; i < ioc->sas_hba.num_phys &&
+           !mpt2sas_phy; i++) {
+               if (ioc->sas_hba.phy[i].phy != phy)
+                       continue;
+               mpt2sas_phy = &ioc->sas_hba.phy[i];
+       }
+
+       if (!mpt2sas_phy) /* this phy not on sas_host */
+               return -EINVAL;
+
+       memset(&mpi_request, 0, sizeof(Mpi2SasIoUnitControlReply_t));
+       mpi_request.Function = MPI2_FUNCTION_SAS_IO_UNIT_CONTROL;
+       mpi_request.Operation = hard_reset ?
+           MPI2_SAS_OP_PHY_HARD_RESET : MPI2_SAS_OP_PHY_LINK_RESET;
+       mpi_request.PhyNum = mpt2sas_phy->phy_id;
+
+       if ((mpt2sas_base_sas_iounit_control(ioc, &mpi_reply, &mpi_request))) {
+               printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
+                   ioc->name, __FILE__, __LINE__, __func__);
+               return -ENXIO;
+       }
+
+       if (mpi_reply.IOCStatus || mpi_reply.IOCLogInfo)
+               printk(MPT2SAS_INFO_FMT "phy(%d), ioc_status"
+                   "(0x%04x), loginfo(0x%08x)\n", ioc->name,
+                   mpt2sas_phy->phy_id,
+                   le16_to_cpu(mpi_reply.IOCStatus),
+                   le32_to_cpu(mpi_reply.IOCLogInfo));
+
+       return 0;
+}
+
+/**
+ * transport_smp_handler - transport portal for smp passthru
+ * @shost: shost object
+ * @rphy: sas transport rphy object
+ * @req:
+ *
+ * This used primarily for smp_utils.
+ * Example:
+ *           smp_rep_general /sys/class/bsg/expander-5:0
+ */
+static int
+transport_smp_handler(struct Scsi_Host *shost, struct sas_rphy *rphy,
+    struct request *req)
+{
+       struct MPT2SAS_ADAPTER *ioc = shost_priv(shost);
+       Mpi2SmpPassthroughRequest_t *mpi_request;
+       Mpi2SmpPassthroughReply_t *mpi_reply;
+       int rc;
+       u16 smid;
+       u32 ioc_state;
+       unsigned long timeleft;
+       void *psge;
+       u32 sgl_flags;
+       u8 issue_reset = 0;
+       unsigned long flags;
+       dma_addr_t dma_addr_in = 0;
+       dma_addr_t dma_addr_out = 0;
+       u16 wait_state_count;
+       struct request *rsp = req->next_rq;
+
+       if (!rsp) {
+               printk(MPT2SAS_ERR_FMT "%s: the smp response space is "
+                   "missing\n", ioc->name, __func__);
+               return -EINVAL;
+       }
+
+       /* do we need to support multiple segments? */
+       if (req->bio->bi_vcnt > 1 || rsp->bio->bi_vcnt > 1) {
+               printk(MPT2SAS_ERR_FMT "%s: multiple segments req %u %u, "
+                   "rsp %u %u\n", ioc->name, __func__, req->bio->bi_vcnt,
+                   req->data_len, rsp->bio->bi_vcnt, rsp->data_len);
+               return -EINVAL;
+       }
+
+       spin_lock_irqsave(&ioc->ioc_reset_in_progress_lock, flags);
+       if (ioc->ioc_reset_in_progress) {
+               spin_unlock_irqrestore(&ioc->ioc_reset_in_progress_lock, flags);
+               printk(MPT2SAS_INFO_FMT "%s: host reset in progress!\n",
+                   __func__, ioc->name);
+               return -EFAULT;
+       }
+       spin_unlock_irqrestore(&ioc->ioc_reset_in_progress_lock, flags);
+
+       rc = mutex_lock_interruptible(&ioc->transport_cmds.mutex);
+       if (rc)
+               return rc;
+
+       if (ioc->transport_cmds.status != MPT2_CMD_NOT_USED) {
+               printk(MPT2SAS_ERR_FMT "%s: transport_cmds in use\n", ioc->name,
+                   __func__);
+               rc = -EAGAIN;
+               goto out;
+       }
+       ioc->transport_cmds.status = MPT2_CMD_PENDING;
+
+       wait_state_count = 0;
+       ioc_state = mpt2sas_base_get_iocstate(ioc, 1);
+       while (ioc_state != MPI2_IOC_STATE_OPERATIONAL) {
+               if (wait_state_count++ == 10) {
+                       printk(MPT2SAS_ERR_FMT
+                           "%s: failed due to ioc not operational\n",
+                           ioc->name, __func__);
+                       rc = -EFAULT;
+                       goto out;
+               }
+               ssleep(1);
+               ioc_state = mpt2sas_base_get_iocstate(ioc, 1);
+               printk(MPT2SAS_INFO_FMT "%s: waiting for "
+                   "operational state(count=%d)\n", ioc->name,
+                   __func__, wait_state_count);
+       }
+       if (wait_state_count)
+               printk(MPT2SAS_INFO_FMT "%s: ioc is operational\n",
+                   ioc->name, __func__);
+
+       smid = mpt2sas_base_get_smid(ioc, ioc->transport_cb_idx);
+       if (!smid) {
+               printk(MPT2SAS_ERR_FMT "%s: failed obtaining a smid\n",
+                   ioc->name, __func__);
+               rc = -EAGAIN;
+               goto out;
+       }
+
+       rc = 0;
+       mpi_request = mpt2sas_base_get_msg_frame(ioc, smid);
+       ioc->transport_cmds.smid = smid;
+
+       memset(mpi_request, 0, sizeof(Mpi2SmpPassthroughRequest_t));
+       mpi_request->Function = MPI2_FUNCTION_SMP_PASSTHROUGH;
+       mpi_request->PhysicalPort = 0xFF;
+       *((u64 *)&mpi_request->SASAddress) = (rphy) ?
+           cpu_to_le64(rphy->identify.sas_address) :
+           cpu_to_le64(ioc->sas_hba.sas_address);
+       mpi_request->RequestDataLength = cpu_to_le16(req->data_len - 4);
+       psge = &mpi_request->SGL;
+
+       /* WRITE sgel first */
+       sgl_flags = (MPI2_SGE_FLAGS_SIMPLE_ELEMENT |
+           MPI2_SGE_FLAGS_END_OF_BUFFER | MPI2_SGE_FLAGS_HOST_TO_IOC);
+       sgl_flags = sgl_flags << MPI2_SGE_FLAGS_SHIFT;
+       dma_addr_out = pci_map_single(ioc->pdev, bio_data(req->bio),
+             req->data_len, PCI_DMA_BIDIRECTIONAL);
+       if (!dma_addr_out) {
+               mpt2sas_base_free_smid(ioc, le16_to_cpu(smid));
+               goto unmap;
+       }
+
+       ioc->base_add_sg_single(psge, sgl_flags | (req->data_len - 4),
+           dma_addr_out);
+
+       /* incr sgel */
+       psge += ioc->sge_size;
+
+       /* READ sgel last */
+       sgl_flags = (MPI2_SGE_FLAGS_SIMPLE_ELEMENT |
+           MPI2_SGE_FLAGS_LAST_ELEMENT | MPI2_SGE_FLAGS_END_OF_BUFFER |
+           MPI2_SGE_FLAGS_END_OF_LIST);
+       sgl_flags = sgl_flags << MPI2_SGE_FLAGS_SHIFT;
+       dma_addr_in =  pci_map_single(ioc->pdev, bio_data(rsp->bio),
+             rsp->data_len, PCI_DMA_BIDIRECTIONAL);
+       if (!dma_addr_in) {
+               mpt2sas_base_free_smid(ioc, le16_to_cpu(smid));
+               goto unmap;
+       }
+
+       ioc->base_add_sg_single(psge, sgl_flags | (rsp->data_len + 4),
+           dma_addr_in);
+
+       dtransportprintk(ioc, printk(MPT2SAS_DEBUG_FMT "%s - "
+           "sending smp request\n", ioc->name, __func__));
+
+       mpt2sas_base_put_smid_default(ioc, smid, 0 /* VF_ID */);
+       timeleft = wait_for_completion_timeout(&ioc->transport_cmds.done,
+           10*HZ);
+
+       if (!(ioc->transport_cmds.status & MPT2_CMD_COMPLETE)) {
+               printk(MPT2SAS_ERR_FMT "%s : timeout\n",
+                   __func__, ioc->name);
+               _debug_dump_mf(mpi_request,
+                   sizeof(Mpi2SmpPassthroughRequest_t)/4);
+               if (!(ioc->transport_cmds.status & MPT2_CMD_RESET))
+                       issue_reset = 1;
+               goto issue_host_reset;
+       }
+
+       dtransportprintk(ioc, printk(MPT2SAS_DEBUG_FMT "%s - "
+           "complete\n", ioc->name, __func__));
+
+       if (ioc->transport_cmds.status & MPT2_CMD_REPLY_VALID) {
+
+               mpi_reply = ioc->transport_cmds.reply;
+
+               dtransportprintk(ioc, printk(MPT2SAS_DEBUG_FMT
+                   "%s - reply data transfer size(%d)\n",
+                   ioc->name, __func__,
+                   le16_to_cpu(mpi_reply->ResponseDataLength)));
+
+               memcpy(req->sense, mpi_reply, sizeof(*mpi_reply));
+               req->sense_len = sizeof(*mpi_reply);
+               req->data_len = 0;
+               rsp->data_len -= mpi_reply->ResponseDataLength;
+
+       } else {
+               dtransportprintk(ioc, printk(MPT2SAS_DEBUG_FMT
+                   "%s - no reply\n", ioc->name, __func__));
+               rc = -ENXIO;
+       }
+
+ issue_host_reset:
+       if (issue_reset) {
+               mpt2sas_base_hard_reset_handler(ioc, CAN_SLEEP,
+                   FORCE_BIG_HAMMER);
+               rc = -ETIMEDOUT;
+       }
+
+ unmap:
+       if (dma_addr_out)
+               pci_unmap_single(ioc->pdev, dma_addr_out, req->data_len,
+                   PCI_DMA_BIDIRECTIONAL);
+       if (dma_addr_in)
+               pci_unmap_single(ioc->pdev, dma_addr_in, rsp->data_len,
+                   PCI_DMA_BIDIRECTIONAL);
+
+ out:
+       ioc->transport_cmds.status = MPT2_CMD_NOT_USED;
+       mutex_unlock(&ioc->transport_cmds.mutex);
+       return rc;
+}
+
+struct sas_function_template mpt2sas_transport_functions = {
+       .get_linkerrors         = transport_get_linkerrors,
+       .get_enclosure_identifier = transport_get_enclosure_identifier,
+       .get_bay_identifier     = transport_get_bay_identifier,
+       .phy_reset              = transport_phy_reset,
+       .smp_handler            = transport_smp_handler,
+};
+
+struct scsi_transport_template *mpt2sas_transport_template;