summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--share/man/man4/Makefile1
-rw-r--r--share/man/man4/mpr.4229
-rw-r--r--sys/amd64/conf/GENERIC1
-rw-r--r--sys/conf/files11
-rw-r--r--sys/dev/mpr/mpi/mpi2.h1257
-rw-r--r--sys/dev/mpr/mpi/mpi2_cnfg.h3169
-rw-r--r--sys/dev/mpr/mpi/mpi2_hbd.h152
-rw-r--r--sys/dev/mpr/mpi/mpi2_history.txt619
-rw-r--r--sys/dev/mpr/mpi/mpi2_init.h614
-rw-r--r--sys/dev/mpr/mpi/mpi2_ioc.h1856
-rw-r--r--sys/dev/mpr/mpi/mpi2_ra.h118
-rw-r--r--sys/dev/mpr/mpi/mpi2_raid.h406
-rw-r--r--sys/dev/mpr/mpi/mpi2_sas.h346
-rw-r--r--sys/dev/mpr/mpi/mpi2_targ.h600
-rw-r--r--sys/dev/mpr/mpi/mpi2_tool.h546
-rw-r--r--sys/dev/mpr/mpi/mpi2_type.h131
-rw-r--r--sys/dev/mpr/mpr.c2797
-rw-r--r--sys/dev/mpr/mpr_config.c1302
-rw-r--r--sys/dev/mpr/mpr_ioctl.h386
-rw-r--r--sys/dev/mpr/mpr_mapping.c2269
-rw-r--r--sys/dev/mpr/mpr_mapping.h71
-rw-r--r--sys/dev/mpr/mpr_pci.c350
-rw-r--r--sys/dev/mpr/mpr_sas.c3413
-rw-r--r--sys/dev/mpr/mpr_sas.h168
-rw-r--r--sys/dev/mpr/mpr_sas_lsi.c1210
-rw-r--r--sys/dev/mpr/mpr_table.c516
-rw-r--r--sys/dev/mpr/mpr_table.h53
-rw-r--r--sys/dev/mpr/mpr_user.c2453
-rw-r--r--sys/dev/mpr/mprvar.h766
-rw-r--r--sys/i386/conf/GENERIC1
-rw-r--r--sys/i386/conf/XEN2
-rw-r--r--sys/ia64/conf/GENERIC2
-rw-r--r--sys/mips/conf/OCTEON11
-rw-r--r--sys/modules/Makefile1
-rw-r--r--sys/modules/mpr/Makefile18
-rw-r--r--sys/sparc64/conf/GENERIC1
36 files changed, 25835 insertions, 1 deletions
diff --git a/share/man/man4/Makefile b/share/man/man4/Makefile
index 799acde..59aaa59 100644
--- a/share/man/man4/Makefile
+++ b/share/man/man4/Makefile
@@ -259,6 +259,7 @@ MAN= aac.4 \
mod_cc.4 \
mos.4 \
mouse.4 \
+ mpr.4 \
mps.4 \
mpt.4 \
msk.4 \
diff --git a/share/man/man4/mpr.4 b/share/man/man4/mpr.4
new file mode 100644
index 0000000..4a42fa1
--- /dev/null
+++ b/share/man/man4/mpr.4
@@ -0,0 +1,229 @@
+.\"
+.\" Copyright (c) 2010 Spectra Logic Corporation
+.\" Copyright (c) 2014 LSI Corp
+.\" All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions, and the following disclaimer,
+.\" without modification.
+.\" 2. Redistributions in binary form must reproduce at minimum a disclaimer
+.\" substantially similar to the "NO WARRANTY" disclaimer below
+.\" ("Disclaimer") and any redistribution must be conditioned upon
+.\" including a substantially similar Disclaimer requirement for further
+.\" binary redistribution.
+.\"
+.\" NO WARRANTY
+.\" THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+.\" "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+.\" LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR
+.\" A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+.\" HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+.\" STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
+.\" IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+.\" POSSIBILITY OF SUCH DAMAGES.
+.\"
+.\" mpr driver man page.
+.\"
+.\" Author: Ken Merry <ken@FreeBSD.org>
+.\" Author: Stephen McConnell <stephen.mcconnell@lsi.com>
+.\"
+.\" $Id$
+.\" $FreeBSD$
+.\"
+.Dd May 2, 2014
+.Dt MPR 4
+.Os
+.Sh NAME
+.Nm mpr
+.Nd "LSI Fusion-MPT 3 IT/IR 12Gb/s Serial Attached SCSI/SATA driver"
+.Sh SYNOPSIS
+To compile this driver into the kernel, place the following lines in your
+kernel configuration file:
+.Bd -ragged -offset indent
+.Cd "device pci"
+.Cd "device scbus"
+.Cd "device mpr"
+.Ed
+.Pp
+Alternatively, to load the driver as a
+module at boot time, place the following line in
+.Xr loader.conf 5 :
+.Bd -literal -offset indent
+mpr_load="YES"
+.Ed
+.Sh DESCRIPTION
+The
+.Nm
+driver provides support for LSI Fusion-MPT 3 IT/IR
+.Tn SAS
+controllers.
+.Sh HARDWARE
+The following controllers are supported by the
+.Nm
+driver:
+.Pp
+.Bl -bullet -compact
+.It
+LSI SAS 3004 (4 Port SAS)
+.It
+LSI SAS 3008 (8 Port SAS)
+.It
+LSI SAS 3108 (8 Port SAS)
+.El
+.Sh CONFIGURATION
+To disable MSI interrupts for all
+.Nm
+driver instances, set the following tunable value in
+.Xr loader.conf 5 :
+.Bd -literal -offset indent
+hw.mpr.disable_msi=1
+.Ed
+.Pp
+To disable MSI interrupts for a specific
+.Nm
+driver instance, set the following tunable value in
+.Xr loader.conf 5 :
+.Bd -literal -offset indent
+dev.mpr.X.disable_msi=1
+.Ed
+.Pp
+where X is the adapter number.
+.Pp
+To disable MSI-X interrupts for all
+.Nm
+driver instances, set the following tunable value in
+.Xr loader.conf 5 :
+.Bd -literal -offset indent
+hw.mpr.disable_msix=1
+.Ed
+.Pp
+To disable MSI-X interrupts for a specific
+.Nm
+driver instance, set the following tunable value in
+.Xr loader.conf 5 :
+.Bd -literal -offset indent
+dev.mpr.X.disable_msix=1
+.Ed
+.Pp
+To set the maximum number of DMA chains allocated for all adapters, set
+the following variable in
+.Xr loader.conf 5 :
+.Bd -literal -offset indent
+hw.mpr.max_chains=NNNN
+.Ed
+.Pp
+To set the maximum number of DMA chains allocated for a specific adapter,
+set the following variable in
+.Xr loader.conf 5 :
+.Bd -literal -offset indent
+dev.mpr.X.max_chains=NNNN
+.Ed
+.Pp
+This variable may also be viewed via
+.Xr sysctl 8
+to see the maximum set for a given adapter.
+.Pp
+The current number of free chain frames may be seen via the
+dev.mpr.X.chain_free
+.Xr sysctl 8
+variable.
+.Pp
+The lowest number of free chain frames may be seen via the
+dev.mpr.X.chain_free_lowwater
+.Xr sysctl 8
+variable.
+.Pp
+The current number of active I/O commands is shown in the
+dev.mpr.X.io_cmds_active
+.Xr sysctl 8
+variable.
+.Pp
+The maximum number of active I/O commands seen since boot is shown in the
+dev.mpr.X.io_cmds_highwater
+.Xr sysctl 8
+variable.
+.Pp
+Devices can be excluded from
+.Nm
+control for all adapters by setting the following variable in
+.Xr loader.conf 5 :
+.Bd -literal -offset indent
+hw.mpr.exclude_ids=Y
+.Ed
+.Pp
+where Y is the target ID of the device.
+If more than one device is to be
+excluded, target ID's are separated by commas.
+.Pp
+Devices can be excluded from
+.Nm
+control for a specific adapter by setting the following variable in
+.Xr loader.conf 5 :
+.Bd -literal -offset indent
+dev.mpr.X.exclude_ids=Y
+.Ed
+.Pp
+where X is the adapter number and Y is the target ID of the device.
+If more
+than one device is to be excluded, target ID's are separated by commas.
+.Sh DEBUGGING
+To enable debugging prints from the
+.Nm
+driver, set the
+.Bd -literal -offset indent
+hw.mpr.X.debug_level
+.Ed
+.Pp
+variable, where X is the adapter number, either in
+.Xr loader.conf 5
+or via
+.Xr sysctl 8 .
+The following bits have the described effects:
+.Bd -literal -offset indent
+0x0001 Enable informational prints.
+0x0002 Enable prints for driver faults.
+0x0004 Enable prints for controller events.
+0x0008 Enable prints for controller logging.
+0x0010 Enable prints for tracing recovery operations.
+0x0020 Enable prints for parameter errors and programming bugs.
+0x0040 Enable prints for system initialization operations.
+0x0080 Enable prints for more detailed information.
+0x0100 Enable prints for user-generated commands.
+0x0200 Enable prints for device mapping.
+0x0400 Enable prints for tracing through driver functions.
+.Ed
+.Sh SEE ALSO
+.Xr cam 4 ,
+.Xr cd 4 ,
+.Xr ch 4 ,
+.Xr da 4 ,
+.Xr mps 4 ,
+.Xr mpt 4 ,
+.Xr pci 4 ,
+.Xr sa 4 ,
+.Xr scsi 4 ,
+.Xr targ 4 ,
+.Xr loader.conf 5 ,
+.Xr sysctl 8
+.Sh HISTORY
+The
+.Nm
+driver first appeared in FreeBSD 9.3.
+.Sh AUTHORS
+The
+.Nm
+driver was originally written by
+.An -nosplit
+.An Scott Long Aq scottl@FreeBSD.org .
+It has been improved and tested by LSI Corporation.
+.Pp
+This man page was written by
+.An Ken Merry Aq ken@FreeBSD.org
+with additional input from
+.An Stephen McConnell Aq stephen.mcconnell@lsi.com .
diff --git a/sys/amd64/conf/GENERIC b/sys/amd64/conf/GENERIC
index 195e33e..2bc14db 100644
--- a/sys/amd64/conf/GENERIC
+++ b/sys/amd64/conf/GENERIC
@@ -111,6 +111,7 @@ device isp # Qlogic family
#device ispfw # Firmware for QLogic HBAs- normally a module
device mpt # LSI-Logic MPT-Fusion
device mps # LSI-Logic MPT-Fusion 2
+device mpr # LSI-Logic MPT-Fusion 3
#device ncr # NCR/Symbios Logic
device sym # NCR/Symbios Logic (newer chipsets + those of `ncr')
device trm # Tekram DC395U/UW/F DC315U adapters
diff --git a/sys/conf/files b/sys/conf/files
index bb8d139..283b018 100644
--- a/sys/conf/files
+++ b/sys/conf/files
@@ -1841,6 +1841,17 @@ dev/mmc/mmcbr_if.m standard
dev/mmc/mmcbus_if.m standard
dev/mmc/mmcsd.c optional mmcsd
dev/mn/if_mn.c optional mn pci
+dev/mpr/mpr.c optional mpr
+dev/mpr/mpr_config.c optional mpr
+# XXX Work around clang warning, until maintainer approves fix.
+dev/mpr/mpr_mapping.c optional mpr \
+ compile-with "${NORMAL_C} ${NO_WSOMETIMES_UNINITIALIZED}"
+dev/mpr/mpr_pci.c optional mpr pci
+dev/mpr/mpr_sas.c optional mpr \
+ compile-with "${NORMAL_C} ${NO_WUNNEEDED_INTERNAL_DECL}"
+dev/mpr/mpr_sas_lsi.c optional mpr
+dev/mpr/mpr_table.c optional mpr
+dev/mpr/mpr_user.c optional mpr
dev/mps/mps.c optional mps
dev/mps/mps_config.c optional mps
# XXX Work around clang warning, until maintainer approves fix.
diff --git a/sys/dev/mpr/mpi/mpi2.h b/sys/dev/mpr/mpi/mpi2.h
new file mode 100644
index 0000000..10f17ab
--- /dev/null
+++ b/sys/dev/mpr/mpi/mpi2.h
@@ -0,0 +1,1257 @@
+/*-
+ * Copyright (c) 2013 LSI Corp.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the author nor the names of any co-contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * LSI MPT-Fusion Host Adapter FreeBSD
+ *
+ * $FreeBSD$
+ */
+
+/*
+ * Copyright (c) 2000-2013 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.33
+ *
+ * NOTE: Names (typedefs, defines, etc.) beginning with an MPI25 or Mpi25
+ * prefix are for use only on MPI v2.5 products, and must not be used
+ * with MPI v2.0 products. Unless otherwise noted, names beginning with
+ * MPI2 or Mpi2 are for use with both MPI v2.0 and MPI v2.5 products.
+ *
+ * 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.
+ * 05-06-09 02.00.12 Bumped MPI2_HEADER_VERSION_UNIT.
+ * In all request and reply descriptors, replaced VF_ID
+ * field with MSIxIndex field.
+ * Removed DevHandle field from
+ * MPI2_SCSI_IO_SUCCESS_REPLY_DESCRIPTOR and made those
+ * bytes reserved.
+ * Added RAID Accelerator functionality.
+ * 07-30-09 02.00.13 Bumped MPI2_HEADER_VERSION_UNIT.
+ * 10-28-09 02.00.14 Bumped MPI2_HEADER_VERSION_UNIT.
+ * Added MSI-x index mask and shift for Reply Post Host
+ * Index register.
+ * Added function code for Host Based Discovery Action.
+ * 02-10-10 02.00.15 Bumped MPI2_HEADER_VERSION_UNIT.
+ * Added define for MPI2_FUNCTION_PWR_MGMT_CONTROL.
+ * Added defines for product-specific range of message
+ * function codes, 0xF0 to 0xFF.
+ * 05-12-10 02.00.16 Bumped MPI2_HEADER_VERSION_UNIT.
+ * Added alternative defines for the SGE Direction bit.
+ * 08-11-10 02.00.17 Bumped MPI2_HEADER_VERSION_UNIT.
+ * 11-10-10 02.00.18 Bumped MPI2_HEADER_VERSION_UNIT.
+ * Added MPI2_IEEE_SGE_FLAGS_SYSTEMPLBCPI_ADDR define.
+ * 02-23-11 02.00.19 Bumped MPI2_HEADER_VERSION_UNIT.
+ * Added MPI2_FUNCTION_SEND_HOST_MESSAGE.
+ * 03-09-11 02.00.20 Bumped MPI2_HEADER_VERSION_UNIT.
+ * 05-25-11 02.00.21 Bumped MPI2_HEADER_VERSION_UNIT.
+ * 08-24-11 02.00.22 Bumped MPI2_HEADER_VERSION_UNIT.
+ * 11-18-11 02.00.23 Bumped MPI2_HEADER_VERSION_UNIT.
+ * Incorporating additions for MPI v2.5.
+ * 02-06-12 02.00.24 Bumped MPI2_HEADER_VERSION_UNIT.
+ * 03-29-12 02.00.25 Bumped MPI2_HEADER_VERSION_UNIT.
+ * Added Hard Reset delay timings.
+ * 07-10-12 02.00.26 Bumped MPI2_HEADER_VERSION_UNIT.
+ * 07-26-12 02.00.27 Bumped MPI2_HEADER_VERSION_UNIT.
+ * 11-27-12 02.00.28 Bumped MPI2_HEADER_VERSION_UNIT.
+ * 12-20-12 02.00.29 Bumped MPI2_HEADER_VERSION_UNIT.
+ * Added MPI25_SUP_REPLY_POST_HOST_INDEX_OFFSET.
+ * 04-09-13 02.00.30 Bumped MPI2_HEADER_VERSION_UNIT.
+ * 04-17-13 02.00.31 Bumped MPI2_HEADER_VERSION_UNIT.
+ * 08-19-13 02.00.32 Bumped MPI2_HEADER_VERSION_UNIT.
+ * 12-05-13 02.00.33 Bumped MPI2_HEADER_VERSION_UNIT.
+ * --------------------------------------------------------------------------
+ */
+
+#ifndef MPI2_H
+#define MPI2_H
+
+
+/*****************************************************************************
+*
+* MPI Version Definitions
+*
+*****************************************************************************/
+
+#define MPI2_VERSION_MAJOR_MASK (0xFF00)
+#define MPI2_VERSION_MAJOR_SHIFT (8)
+#define MPI2_VERSION_MINOR_MASK (0x00FF)
+#define MPI2_VERSION_MINOR_SHIFT (0)
+
+/* major version for all MPI v2.x */
+#define MPI2_VERSION_MAJOR (0x02)
+
+/* minor version for MPI v2.0 compatible products */
+#define MPI2_VERSION_MINOR (0x00)
+#define MPI2_VERSION ((MPI2_VERSION_MAJOR << MPI2_VERSION_MAJOR_SHIFT) | \
+ MPI2_VERSION_MINOR)
+#define MPI2_VERSION_02_00 (0x0200)
+
+
+/* minor version for MPI v2.5 compatible products */
+#define MPI25_VERSION_MINOR (0x05)
+#define MPI25_VERSION ((MPI2_VERSION_MAJOR << MPI2_VERSION_MAJOR_SHIFT) | \
+ MPI25_VERSION_MINOR)
+#define MPI2_VERSION_02_05 (0x0205)
+
+
+/* Unit and Dev versioning for this MPI header set */
+#define MPI2_HEADER_VERSION_UNIT (0x21)
+#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)
+
+/*
+ * Defines for the Reply Descriptor Post Queue
+ */
+#define MPI2_REPLY_POST_HOST_INDEX_OFFSET (0x0000006C)
+#define MPI2_REPLY_POST_HOST_INDEX_MASK (0x00FFFFFF)
+#define MPI2_RPHI_MSIX_INDEX_MASK (0xFF000000)
+#define MPI2_RPHI_MSIX_INDEX_SHIFT (24)
+#define MPI25_SUP_REPLY_POST_HOST_INDEX_OFFSET (0x0000030C) /* MPI v2.5 only */
+
+
+/*
+ * 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)
+
+
+/* Hard Reset delay timings */
+#define MPI2_HARD_RESET_PCIE_FIRST_READ_DELAY_MICRO_SEC (50000)
+#define MPI2_HARD_RESET_PCIE_RESET_READ_WINDOW_MICRO_SEC (255000)
+#define MPI2_HARD_RESET_PCIE_SECOND_READ_DELAY_MICRO_SEC (256000)
+
+/*****************************************************************************
+*
+* Message Descriptors
+*
+*****************************************************************************/
+
+/* Request Descriptors */
+
+/* Default Request Descriptor */
+typedef struct _MPI2_DEFAULT_REQUEST_DESCRIPTOR
+{
+ U8 RequestFlags; /* 0x00 */
+ U8 MSIxIndex; /* 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_RAID_ACCELERATOR (0x0A)
+#define MPI25_REQ_DESCRIPT_FLAGS_FAST_PATH_SCSI_IO (0x0C)
+
+#define MPI2_REQ_DESCRIPT_FLAGS_IOC_FIFO_MARKER (0x01)
+
+
+/* High Priority Request Descriptor */
+typedef struct _MPI2_HIGH_PRIORITY_REQUEST_DESCRIPTOR
+{
+ U8 RequestFlags; /* 0x00 */
+ U8 MSIxIndex; /* 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 MSIxIndex; /* 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 MSIxIndex; /* 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;
+
+
+/* RAID Accelerator Request Descriptor */
+typedef struct _MPI2_RAID_ACCEL_REQUEST_DESCRIPTOR
+{
+ U8 RequestFlags; /* 0x00 */
+ U8 MSIxIndex; /* 0x01 */
+ U16 SMID; /* 0x02 */
+ U16 LMID; /* 0x04 */
+ U16 Reserved; /* 0x06 */
+} MPI2_RAID_ACCEL_REQUEST_DESCRIPTOR,
+ MPI2_POINTER PTR_MPI2_RAID_ACCEL_REQUEST_DESCRIPTOR,
+ Mpi2RAIDAcceleratorRequestDescriptor_t,
+ MPI2_POINTER pMpi2RAIDAcceleratorRequestDescriptor_t;
+
+
+/* Fast Path SCSI IO Request Descriptor */
+typedef MPI2_SCSI_IO_REQUEST_DESCRIPTOR
+ MPI25_FP_SCSI_IO_REQUEST_DESCRIPTOR,
+ MPI2_POINTER PTR_MPI25_FP_SCSI_IO_REQUEST_DESCRIPTOR,
+ Mpi25FastPathSCSIIORequestDescriptor_t,
+ MPI2_POINTER pMpi25FastPathSCSIIORequestDescriptor_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;
+ MPI2_RAID_ACCEL_REQUEST_DESCRIPTOR RAIDAccelerator;
+ MPI25_FP_SCSI_IO_REQUEST_DESCRIPTOR FastPathSCSIIO;
+ 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 MSIxIndex; /* 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_RAID_ACCELERATOR_SUCCESS (0x05)
+#define MPI25_RPY_DESCRIPT_FLAGS_FAST_PATH_SCSI_IO_SUCCESS (0x06)
+#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 MSIxIndex; /* 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 MSIxIndex; /* 0x01 */
+ U16 SMID; /* 0x02 */
+ U16 TaskTag; /* 0x04 */
+ U16 Reserved1; /* 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 MSIxIndex; /* 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 MSIxIndex; /* 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)
+
+
+/* RAID Accelerator Success Reply Descriptor */
+typedef struct _MPI2_RAID_ACCELERATOR_SUCCESS_REPLY_DESCRIPTOR
+{
+ U8 ReplyFlags; /* 0x00 */
+ U8 MSIxIndex; /* 0x01 */
+ U16 SMID; /* 0x02 */
+ U32 Reserved; /* 0x04 */
+} MPI2_RAID_ACCELERATOR_SUCCESS_REPLY_DESCRIPTOR,
+ MPI2_POINTER PTR_MPI2_RAID_ACCELERATOR_SUCCESS_REPLY_DESCRIPTOR,
+ Mpi2RAIDAcceleratorSuccessReplyDescriptor_t,
+ MPI2_POINTER pMpi2RAIDAcceleratorSuccessReplyDescriptor_t;
+
+
+/* Fast Path SCSI IO Success Reply Descriptor */
+typedef MPI2_SCSI_IO_SUCCESS_REPLY_DESCRIPTOR
+ MPI25_FP_SCSI_IO_SUCCESS_REPLY_DESCRIPTOR,
+ MPI2_POINTER PTR_MPI25_FP_SCSI_IO_SUCCESS_REPLY_DESCRIPTOR,
+ Mpi25FastPathSCSIIOSuccessReplyDescriptor_t,
+ MPI2_POINTER pMpi25FastPathSCSIIOSuccessReplyDescriptor_t;
+
+
+/* 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;
+ MPI2_RAID_ACCELERATOR_SUCCESS_REPLY_DESCRIPTOR RAIDAcceleratorSuccess;
+ MPI25_FP_SCSI_IO_SUCCESS_REPLY_DESCRIPTOR FastPathSCSIIOSuccess;
+ U64 Words;
+} MPI2_REPLY_DESCRIPTORS_UNION, MPI2_POINTER PTR_MPI2_REPLY_DESCRIPTORS_UNION,
+ Mpi2ReplyDescriptorsUnion_t, MPI2_POINTER pMpi2ReplyDescriptorsUnion_t;
+
+
+
+/*****************************************************************************
+*
+* Message Functions
+*
+*****************************************************************************/
+
+#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 */
+#define MPI2_FUNCTION_RAID_ACCELERATOR (0x2C) /* RAID Accelerator */
+#define MPI2_FUNCTION_HOST_BASED_DISCOVERY_ACTION (0x2F) /* Host Based Discovery Action */
+#define MPI2_FUNCTION_PWR_MGMT_CONTROL (0x30) /* Power Management Control */
+#define MPI2_FUNCTION_SEND_HOST_MESSAGE (0x31) /* Send Host Message */
+#define MPI2_FUNCTION_MIN_PRODUCT_SPECIFIC (0xF0) /* beginning of product-specific range */
+#define MPI2_FUNCTION_MAX_PRODUCT_SPECIFIC (0xFF) /* end of product-specific range */
+
+
+
+/* Doorbell functions */
+#define MPI2_FUNCTION_IOC_MESSAGE_UNIT_RESET (0x40)
+#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)
+
+/****************************************************************************
+* RAID Accelerator values
+****************************************************************************/
+
+#define MPI2_IOCSTATUS_RAID_ACCEL_ERROR (0x00B0)
+
+/****************************************************************************
+* 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 - for MPI v2.0 products only
+****************************************************************************/
+
+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 - for MPI v2.0 products only
+****************************************************************************/
+
+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 - for MPI v2.0 products only
+****************************************************************************/
+
+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 - for MPI v2.0 products only
+****************************************************************************/
+
+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) /* for MPI v2.0 products only */
+#define MPI2_SGE_FLAGS_SIMPLE_ELEMENT (0x10)
+#define MPI2_SGE_FLAGS_CHAIN_ELEMENT (0x30) /* for MPI v2.0 products only */
+#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)
+
+#define MPI2_SGE_FLAGS_DEST (MPI2_SGE_FLAGS_IOC_TO_HOST)
+#define MPI2_SGE_FLAGS_SOURCE (MPI2_SGE_FLAGS_HOST_TO_IOC)
+
+/* Address Size */
+
+#define MPI2_SGE_FLAGS_32_BIT_ADDRESSING (0x00)
+#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
+****************************************************************************/
+
+/* MPI2_IEEE_SGE_SIMPLE32 is for MPI v2.0 products only */
+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
+****************************************************************************/
+
+/* MPI2_IEEE_SGE_CHAIN32 is for MPI v2.0 products only */
+typedef MPI2_IEEE_SGE_SIMPLE32 MPI2_IEEE_SGE_CHAIN32;
+
+/* MPI2_IEEE_SGE_CHAIN64 is for MPI v2.0 products only */
+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;
+
+/* MPI25_IEEE_SGE_CHAIN64 is for MPI v2.5 products only */
+typedef struct _MPI25_IEEE_SGE_CHAIN64
+{
+ U64 Address;
+ U32 Length;
+ U16 Reserved1;
+ U8 NextChainOffset;
+ U8 Flags;
+} MPI25_IEEE_SGE_CHAIN64, MPI2_POINTER PTR_MPI25_IEEE_SGE_CHAIN64,
+ Mpi25IeeeSgeChain64_t, MPI2_POINTER pMpi25IeeeSgeChain64_t;
+
+
+/****************************************************************************
+* All IEEE SGE types union
+****************************************************************************/
+
+/* MPI2_IEEE_SGE_UNION is for MPI v2.0 products only */
+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 union for IO SGL's
+****************************************************************************/
+
+typedef union _MPI25_SGE_IO_UNION
+{
+ MPI2_IEEE_SGE_SIMPLE64 IeeeSimple;
+ MPI25_IEEE_SGE_CHAIN64 IeeeChain;
+} MPI25_SGE_IO_UNION, MPI2_POINTER PTR_MPI25_SGE_IO_UNION,
+ Mpi25SGEIOUnion_t, MPI2_POINTER pMpi25SGEIOUnion_t;
+
+
+/****************************************************************************
+* IEEE SGE field definitions and masks
+****************************************************************************/
+
+/* Flags field bit definitions */
+
+#define MPI2_IEEE_SGE_FLAGS_ELEMENT_TYPE_MASK (0x80)
+#define MPI25_IEEE_SGE_FLAGS_END_OF_LIST (0x40)
+
+#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) /* for MPI v2.0, use in IEEE Simple Element only; for MPI v2.5, use in IEEE Simple or Chain element */
+#define MPI2_IEEE_SGE_FLAGS_IOCDDR_ADDR (0x01) /* use in IEEE Simple Element only */
+#define MPI2_IEEE_SGE_FLAGS_IOCPLB_ADDR (0x02)
+#define MPI2_IEEE_SGE_FLAGS_IOCPLBNTA_ADDR (0x03) /* for MPI v2.0, use in IEEE Simple Element only; for MPI v2.5, use in IEEE Simple or Chain element */
+#define MPI2_IEEE_SGE_FLAGS_SYSTEMPLBPCI_ADDR (0x03) /* use in MPI v2.0 IEEE Chain Element only */
+#define MPI2_IEEE_SGE_FLAGS_SYSTEMPLBCPI_ADDR (MPI2_IEEE_SGE_FLAGS_SYSTEMPLBPCI_ADDR) /* typo in name */
+
+/****************************************************************************
+* 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) /* MPI v2.0 products only */
+#define MPI2_SGLFLAGS_SGL_TYPE_IEEE64 (0x02)
+
+
+#endif
+
diff --git a/sys/dev/mpr/mpi/mpi2_cnfg.h b/sys/dev/mpr/mpi/mpi2_cnfg.h
new file mode 100644
index 0000000..d82750f
--- /dev/null
+++ b/sys/dev/mpr/mpi/mpi2_cnfg.h
@@ -0,0 +1,3169 @@
+/*-
+ * Copyright (c) 2013 LSI Corp.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the author nor the names of any co-contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * LSI MPT-Fusion Host Adapter FreeBSD
+ *
+ * $FreeBSD$
+ */
+
+/*
+ * Copyright (c) 2000-2013 LSI Corporation.
+ *
+ *
+ * Name: mpi2_cnfg.h
+ * Title: MPI Configuration messages and pages
+ * Creation Date: November 10, 2006
+ *
+ * mpi2_cnfg.h Version: 02.00.27
+ *
+ * NOTE: Names (typedefs, defines, etc.) beginning with an MPI25 or Mpi25
+ * prefix are for use only on MPI v2.5 products, and must not be used
+ * with MPI v2.0 products. Unless otherwise noted, names beginning with
+ * MPI2 or Mpi2 are for use with both MPI v2.0 and MPI v2.5 products.
+ *
+ * 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.
+ * 05-06-09 02.00.11 Added structures and defines for IO Unit Page 5 and IO
+ * Unit Page 6.
+ * Added expander reduced functionality data to SAS
+ * Expander Page 0.
+ * Added SAS PHY Page 2 and SAS PHY Page 3.
+ * 07-30-09 02.00.12 Added IO Unit Page 7.
+ * Added new device ids.
+ * Added SAS IO Unit Page 5.
+ * Added partial and slumber power management capable flags
+ * to SAS Device Page 0 Flags field.
+ * Added PhyInfo defines for power condition.
+ * Added Ethernet configuration pages.
+ * 10-28-09 02.00.13 Added MPI2_IOUNITPAGE1_ENABLE_HOST_BASED_DISCOVERY.
+ * Added SAS PHY Page 4 structure and defines.
+ * 02-10-10 02.00.14 Modified the comments for the configuration page
+ * structures that contain an array of data. The host
+ * should use the "count" field in the page data (e.g. the
+ * NumPhys field) to determine the number of valid elements
+ * in the array.
+ * Added/modified some MPI2_MFGPAGE_DEVID_SAS defines.
+ * Added PowerManagementCapabilities to IO Unit Page 7.
+ * Added PortWidthModGroup field to
+ * MPI2_SAS_IO_UNIT5_PHY_PM_SETTINGS.
+ * Added MPI2_CONFIG_PAGE_SASIOUNIT_6 and related defines.
+ * Added MPI2_CONFIG_PAGE_SASIOUNIT_7 and related defines.
+ * Added MPI2_CONFIG_PAGE_SASIOUNIT_8 and related defines.
+ * 05-12-10 02.00.15 Added MPI2_RAIDVOL0_STATUS_FLAG_VOL_NOT_CONSISTENT
+ * define.
+ * Added MPI2_PHYSDISK0_INCOMPATIBLE_MEDIA_TYPE define.
+ * Added MPI2_SAS_NEG_LINK_RATE_UNSUPPORTED_PHY define.
+ * 08-11-10 02.00.16 Removed IO Unit Page 1 device path (multi-pathing)
+ * defines.
+ * 11-10-10 02.00.17 Added ReceptacleID field (replacing Reserved1) to
+ * MPI2_MANPAGE7_CONNECTOR_INFO and reworked defines for
+ * the Pinout field.
+ * Added BoardTemperature and BoardTemperatureUnits fields
+ * to MPI2_CONFIG_PAGE_IO_UNIT_7.
+ * Added MPI2_CONFIG_EXTPAGETYPE_EXT_MANUFACTURING define
+ * and MPI2_CONFIG_PAGE_EXT_MAN_PS structure.
+ * 02-23-11 02.00.18 Added ProxyVF_ID field to MPI2_CONFIG_REQUEST.
+ * Added IO Unit Page 8, IO Unit Page 9,
+ * and IO Unit Page 10.
+ * Added SASNotifyPrimitiveMasks field to
+ * MPI2_CONFIG_PAGE_IOC_7.
+ * 03-09-11 02.00.19 Fixed IO Unit Page 10 (to match the spec).
+ * 05-25-11 02.00.20 Cleaned up a few comments.
+ * 08-24-11 02.00.21 Marked the IO Unit Page 7 PowerManagementCapabilities
+ * for PCIe link as obsolete.
+ * Added SpinupFlags field containing a Disable Spin-up bit
+ * to the MPI2_SAS_IOUNIT4_SPINUP_GROUP fields of SAS IO
+ * Unit Page 4.
+ * 11-18-11 02.00.22 Added define MPI2_IOCPAGE6_CAP_FLAGS_4K_SECTORS_SUPPORT.
+ * Added UEFIVersion field to BIOS Page 1 and defined new
+ * BiosOptions bits.
+ * Incorporating additions for MPI v2.5.
+ * 11-27-12 02.00.23 Added MPI2_MANPAGE7_FLAG_EVENTREPLAY_SLOT_ORDER.
+ * Added MPI2_BIOSPAGE1_OPTIONS_MASK_OEM_ID.
+ * 12-20-12 02.00.24 Marked MPI2_SASIOUNIT1_CONTROL_CLEAR_AFFILIATION as
+ * obsolete for MPI v2.5 and later.
+ * Added some defines for 12G SAS speeds.
+ * 04-09-13 02.00.25 Added MPI2_IOUNITPAGE1_ATA_SECURITY_FREEZE_LOCK.
+ * Fixed MPI2_IOUNITPAGE5_DMA_CAP_MASK_MAX_REQUESTS to
+ * match the specification.
+ * 08-19-13 02.00.26 Added reserved words to MPI2_CONFIG_PAGE_IO_UNIT_7 for
+ * future use.
+ * 12-05-13 02.00.27 Added MPI2_MANPAGE7_FLAG_BASE_ENCLOSURE_LEVEL for
+ * MPI2_CONFIG_PAGE_MAN_7.
+ * Added EnclosureLevel and ConnectorName fields to
+ * MPI2_CONFIG_PAGE_SAS_DEV_0.
+ * Added MPI2_SAS_DEVICE0_FLAGS_ENCL_LEVEL_VALID for
+ * MPI2_CONFIG_PAGE_SAS_DEV_0.
+ * Added EnclosureLevel field to
+ * MPI2_CONFIG_PAGE_SAS_ENCLOSURE_0.
+ * Added MPI2_SAS_ENCLS0_FLAGS_ENCL_LEVEL_VALID for
+ * MPI2_CONFIG_PAGE_SAS_ENCLOSURE_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)
+#define MPI2_CONFIG_EXTPAGETYPE_ETHERNET (0x19)
+#define MPI2_CONFIG_EXTPAGETYPE_EXT_MANUFACTURING (0x1A)
+
+
+/*****************************************************************************
+* 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)
+
+
+/* Ethernet PageAddress format */
+#define MPI2_ETHERNET_PGAD_FORM_MASK (0xF0000000)
+#define MPI2_ETHERNET_PGAD_FORM_IF_NUM (0x00000000)
+
+#define MPI2_ETHERNET_PGAD_IF_NUMBER_MASK (0x000000FF)
+
+
+
+/****************************************************************************
+* 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 */
+ U8 Reserved2; /* 0x0C */
+ U8 ProxyVF_ID; /* 0x0D */
+ U16 Reserved4; /* 0x0E */
+ 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)
+
+/* use MPI2_SGLFLAGS_ defines from mpi2.h for the SGLFlags field */
+
+
+/* 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)
+
+/* MPI v2.0 SAS products */
+#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)
+
+#define MPI2_MFGPAGE_DEVID_SSS6200 (0x007E)
+
+#define MPI2_MFGPAGE_DEVID_SAS2208_1 (0x0080)
+#define MPI2_MFGPAGE_DEVID_SAS2208_2 (0x0081)
+#define MPI2_MFGPAGE_DEVID_SAS2208_3 (0x0082)
+#define MPI2_MFGPAGE_DEVID_SAS2208_4 (0x0083)
+#define MPI2_MFGPAGE_DEVID_SAS2208_5 (0x0084)
+#define MPI2_MFGPAGE_DEVID_SAS2208_6 (0x0085)
+#define MPI2_MFGPAGE_DEVID_SAS2308_1 (0x0086)
+#define MPI2_MFGPAGE_DEVID_SAS2308_2 (0x0087)
+#define MPI2_MFGPAGE_DEVID_SAS2308_3 (0x006E)
+
+/* MPI v2.5 SAS products */
+#define MPI25_MFGPAGE_DEVID_SAS3004 (0x0096)
+#define MPI25_MFGPAGE_DEVID_SAS3008 (0x0097)
+#define MPI25_MFGPAGE_DEVID_SAS3108_1 (0x0090)
+#define MPI25_MFGPAGE_DEVID_SAS3108_2 (0x0091)
+#define MPI25_MFGPAGE_DEVID_SAS3108_5 (0x0094)
+#define MPI25_MFGPAGE_DEVID_SAS3108_6 (0x0095)
+
+
+
+
+/* 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 the value returned for 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 ReceptacleID; /* 0x15 */
+ U16 Slot; /* 0x16 */
+ U32 Reserved2; /* 0x18 */
+} MPI2_MANPAGE7_CONNECTOR_INFO, MPI2_POINTER PTR_MPI2_MANPAGE7_CONNECTOR_INFO,
+ Mpi2ManPage7ConnectorInfo_t, MPI2_POINTER pMpi2ManPage7ConnectorInfo_t;
+
+/* defines for the Pinout field */
+#define MPI2_MANPAGE7_PINOUT_LANE_MASK (0x0000FF00)
+#define MPI2_MANPAGE7_PINOUT_LANE_SHIFT (8)
+
+#define MPI2_MANPAGE7_PINOUT_TYPE_MASK (0x000000FF)
+#define MPI2_MANPAGE7_PINOUT_TYPE_UNKNOWN (0x00)
+#define MPI2_MANPAGE7_PINOUT_SATA_SINGLE (0x01)
+#define MPI2_MANPAGE7_PINOUT_SFF_8482 (0x02)
+#define MPI2_MANPAGE7_PINOUT_SFF_8486 (0x03)
+#define MPI2_MANPAGE7_PINOUT_SFF_8484 (0x04)
+#define MPI2_MANPAGE7_PINOUT_SFF_8087 (0x05)
+#define MPI2_MANPAGE7_PINOUT_SFF_8643_4I (0x06)
+#define MPI2_MANPAGE7_PINOUT_SFF_8643_8I (0x07)
+#define MPI2_MANPAGE7_PINOUT_SFF_8470 (0x08)
+#define MPI2_MANPAGE7_PINOUT_SFF_8088 (0x09)
+#define MPI2_MANPAGE7_PINOUT_SFF_8644_4X (0x0A)
+#define MPI2_MANPAGE7_PINOUT_SFF_8644_8X (0x0B)
+#define MPI2_MANPAGE7_PINOUT_SFF_8644_16X (0x0C)
+#define MPI2_MANPAGE7_PINOUT_SFF_8436 (0x0D)
+
+/* defines for the Location field */
+#define MPI2_MANPAGE7_LOCATION_UNKNOWN (0x01)
+#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 the value returned for 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 (0x01)
+
+/* defines for the Flags field */
+#define MPI2_MANPAGE7_FLAG_BASE_ENCLOSURE_LEVEL (0x00000008)
+#define MPI2_MANPAGE7_FLAG_EVENTREPLAY_SLOT_ORDER (0x00000002)
+#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_ATA_SECURITY_FREEZE_LOCK (0x00004000)
+#define MPI25_IOUNITPAGE1_NEW_DEVICE_FAST_PATH_DISABLE (0x00002000)
+#define MPI25_IOUNITPAGE1_DISABLE_FAST_PATH (0x00001000)
+#define MPI2_IOUNITPAGE1_ENABLE_HOST_BASED_DISCOVERY (0x00000800)
+#define MPI2_IOUNITPAGE1_MASK_SATA_WRITE_CACHE (0x00000600)
+#define MPI2_IOUNITPAGE1_SATA_WRITE_CACHE_SHIFT (9)
+#define MPI2_IOUNITPAGE1_ENABLE_SATA_WRITE_CACHE (0x00000000)
+#define MPI2_IOUNITPAGE1_DISABLE_SATA_WRITE_CACHE (0x00000200)
+#define MPI2_IOUNITPAGE1_UNCHANGED_SATA_WRITE_CACHE (0x00000400)
+#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)
+
+
+/* IO Unit Page 3 */
+
+/*
+ * Host code (drivers, BIOS, utilities, etc.) should leave this define set to
+ * one and check the value returned for GPIOCount at runtime.
+ */
+#ifndef MPI2_IO_UNIT_PAGE_3_GPIO_VAL_MAX
+#define MPI2_IO_UNIT_PAGE_3_GPIO_VAL_MAX (1)
+#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)
+
+
+/* IO Unit Page 5 */
+
+/*
+ * Upper layer code (drivers, utilities, etc.) should leave this define set to
+ * one and check the value returned for NumDmaEngines at runtime.
+ */
+#ifndef MPI2_IOUNITPAGE5_DMAENGINE_ENTRIES
+#define MPI2_IOUNITPAGE5_DMAENGINE_ENTRIES (1)
+#endif
+
+typedef struct _MPI2_CONFIG_PAGE_IO_UNIT_5
+{
+ MPI2_CONFIG_PAGE_HEADER Header; /* 0x00 */
+ U64 RaidAcceleratorBufferBaseAddress; /* 0x04 */
+ U64 RaidAcceleratorBufferSize; /* 0x0C */
+ U64 RaidAcceleratorControlBaseAddress; /* 0x14 */
+ U8 RAControlSize; /* 0x1C */
+ U8 NumDmaEngines; /* 0x1D */
+ U8 RAMinControlSize; /* 0x1E */
+ U8 RAMaxControlSize; /* 0x1F */
+ U32 Reserved1; /* 0x20 */
+ U32 Reserved2; /* 0x24 */
+ U32 Reserved3; /* 0x28 */
+ U32 DmaEngineCapabilities[MPI2_IOUNITPAGE5_DMAENGINE_ENTRIES]; /* 0x2C */
+} MPI2_CONFIG_PAGE_IO_UNIT_5, MPI2_POINTER PTR_MPI2_CONFIG_PAGE_IO_UNIT_5,
+ Mpi2IOUnitPage5_t, MPI2_POINTER pMpi2IOUnitPage5_t;
+
+#define MPI2_IOUNITPAGE5_PAGEVERSION (0x00)
+
+/* defines for IO Unit Page 5 DmaEngineCapabilities field */
+#define MPI2_IOUNITPAGE5_DMA_CAP_MASK_MAX_REQUESTS (0xFFFF0000)
+#define MPI2_IOUNITPAGE5_DMA_CAP_SHIFT_MAX_REQUESTS (16)
+
+#define MPI2_IOUNITPAGE5_DMA_CAP_EEDP (0x0008)
+#define MPI2_IOUNITPAGE5_DMA_CAP_PARITY_GENERATION (0x0004)
+#define MPI2_IOUNITPAGE5_DMA_CAP_HASHING (0x0002)
+#define MPI2_IOUNITPAGE5_DMA_CAP_ENCRYPTION (0x0001)
+
+
+/* IO Unit Page 6 */
+
+typedef struct _MPI2_CONFIG_PAGE_IO_UNIT_6
+{
+ MPI2_CONFIG_PAGE_HEADER Header; /* 0x00 */
+ U16 Flags; /* 0x04 */
+ U8 RAHostControlSize; /* 0x06 */
+ U8 Reserved0; /* 0x07 */
+ U64 RaidAcceleratorHostControlBaseAddress; /* 0x08 */
+ U32 Reserved1; /* 0x10 */
+ U32 Reserved2; /* 0x14 */
+ U32 Reserved3; /* 0x18 */
+} MPI2_CONFIG_PAGE_IO_UNIT_6, MPI2_POINTER PTR_MPI2_CONFIG_PAGE_IO_UNIT_6,
+ Mpi2IOUnitPage6_t, MPI2_POINTER pMpi2IOUnitPage6_t;
+
+#define MPI2_IOUNITPAGE6_PAGEVERSION (0x00)
+
+/* defines for IO Unit Page 6 Flags field */
+#define MPI2_IOUNITPAGE6_FLAGS_ENABLE_RAID_ACCELERATOR (0x0001)
+
+
+/* IO Unit Page 7 */
+
+typedef struct _MPI2_CONFIG_PAGE_IO_UNIT_7
+{
+ MPI2_CONFIG_PAGE_HEADER Header; /* 0x00 */
+ U8 CurrentPowerMode; /* 0x04 */ /* reserved in MPI 2.0 */
+ U8 PreviousPowerMode; /* 0x05 */ /* reserved in MPI 2.0 */
+ U8 PCIeWidth; /* 0x06 */
+ U8 PCIeSpeed; /* 0x07 */
+ U32 ProcessorState; /* 0x08 */
+ U32 PowerManagementCapabilities; /* 0x0C */
+ U16 IOCTemperature; /* 0x10 */
+ U8 IOCTemperatureUnits; /* 0x12 */
+ U8 IOCSpeed; /* 0x13 */
+ U16 BoardTemperature; /* 0x14 */
+ U8 BoardTemperatureUnits; /* 0x16 */
+ U8 Reserved3; /* 0x17 */
+ U32 Reserved4; /* 0x18 */
+ U32 Reserved5; /* 0x1C */
+ U32 Reserved6; /* 0x20 */
+ U32 Reserved7; /* 0x24 */
+} MPI2_CONFIG_PAGE_IO_UNIT_7, MPI2_POINTER PTR_MPI2_CONFIG_PAGE_IO_UNIT_7,
+ Mpi2IOUnitPage7_t, MPI2_POINTER pMpi2IOUnitPage7_t;
+
+#define MPI2_IOUNITPAGE7_PAGEVERSION (0x04)
+
+/* defines for IO Unit Page 7 CurrentPowerMode and PreviousPowerMode fields */
+#define MPI25_IOUNITPAGE7_PM_INIT_MASK (0xC0)
+#define MPI25_IOUNITPAGE7_PM_INIT_UNAVAILABLE (0x00)
+#define MPI25_IOUNITPAGE7_PM_INIT_HOST (0x40)
+#define MPI25_IOUNITPAGE7_PM_INIT_IO_UNIT (0x80)
+#define MPI25_IOUNITPAGE7_PM_INIT_PCIE_DPA (0xC0)
+
+#define MPI25_IOUNITPAGE7_PM_MODE_MASK (0x07)
+#define MPI25_IOUNITPAGE7_PM_MODE_UNAVAILABLE (0x00)
+#define MPI25_IOUNITPAGE7_PM_MODE_UNKNOWN (0x01)
+#define MPI25_IOUNITPAGE7_PM_MODE_FULL_POWER (0x04)
+#define MPI25_IOUNITPAGE7_PM_MODE_REDUCED_POWER (0x05)
+#define MPI25_IOUNITPAGE7_PM_MODE_STANDBY (0x06)
+
+
+/* defines for IO Unit Page 7 PCIeWidth field */
+#define MPI2_IOUNITPAGE7_PCIE_WIDTH_X1 (0x01)
+#define MPI2_IOUNITPAGE7_PCIE_WIDTH_X2 (0x02)
+#define MPI2_IOUNITPAGE7_PCIE_WIDTH_X4 (0x04)
+#define MPI2_IOUNITPAGE7_PCIE_WIDTH_X8 (0x08)
+
+/* defines for IO Unit Page 7 PCIeSpeed field */
+#define MPI2_IOUNITPAGE7_PCIE_SPEED_2_5_GBPS (0x00)
+#define MPI2_IOUNITPAGE7_PCIE_SPEED_5_0_GBPS (0x01)
+#define MPI2_IOUNITPAGE7_PCIE_SPEED_8_0_GBPS (0x02)
+
+/* defines for IO Unit Page 7 ProcessorState field */
+#define MPI2_IOUNITPAGE7_PSTATE_MASK_SECOND (0x0000000F)
+#define MPI2_IOUNITPAGE7_PSTATE_SHIFT_SECOND (0)
+
+#define MPI2_IOUNITPAGE7_PSTATE_NOT_PRESENT (0x00)
+#define MPI2_IOUNITPAGE7_PSTATE_DISABLED (0x01)
+#define MPI2_IOUNITPAGE7_PSTATE_ENABLED (0x02)
+
+/* defines for IO Unit Page 7 PowerManagementCapabilities field */
+#define MPI25_IOUNITPAGE7_PMCAP_DPA_FULL_PWR_MODE (0x00400000)
+#define MPI25_IOUNITPAGE7_PMCAP_DPA_REDUCED_PWR_MODE (0x00200000)
+#define MPI25_IOUNITPAGE7_PMCAP_DPA_STANDBY_MODE (0x00100000)
+#define MPI25_IOUNITPAGE7_PMCAP_HOST_FULL_PWR_MODE (0x00040000)
+#define MPI25_IOUNITPAGE7_PMCAP_HOST_REDUCED_PWR_MODE (0x00020000)
+#define MPI25_IOUNITPAGE7_PMCAP_HOST_STANDBY_MODE (0x00010000)
+#define MPI25_IOUNITPAGE7_PMCAP_IO_FULL_PWR_MODE (0x00004000)
+#define MPI25_IOUNITPAGE7_PMCAP_IO_REDUCED_PWR_MODE (0x00002000)
+#define MPI25_IOUNITPAGE7_PMCAP_IO_STANDBY_MODE (0x00001000)
+#define MPI2_IOUNITPAGE7_PMCAP_HOST_12_5_PCT_IOCSPEED (0x00000400)
+#define MPI2_IOUNITPAGE7_PMCAP_HOST_25_0_PCT_IOCSPEED (0x00000200)
+#define MPI2_IOUNITPAGE7_PMCAP_HOST_50_0_PCT_IOCSPEED (0x00000100)
+#define MPI25_IOUNITPAGE7_PMCAP_IO_12_5_PCT_IOCSPEED (0x00000040)
+#define MPI25_IOUNITPAGE7_PMCAP_IO_25_0_PCT_IOCSPEED (0x00000020)
+#define MPI25_IOUNITPAGE7_PMCAP_IO_50_0_PCT_IOCSPEED (0x00000010)
+#define MPI2_IOUNITPAGE7_PMCAP_HOST_WIDTH_CHANGE_PCIE (0x00000008) /* obsolete */
+#define MPI2_IOUNITPAGE7_PMCAP_HOST_SPEED_CHANGE_PCIE (0x00000004) /* obsolete */
+#define MPI25_IOUNITPAGE7_PMCAP_IO_WIDTH_CHANGE_PCIE (0x00000002) /* obsolete */
+#define MPI25_IOUNITPAGE7_PMCAP_IO_SPEED_CHANGE_PCIE (0x00000001) /* obsolete */
+
+/* obsolete names for the PowerManagementCapabilities bits (above) */
+#define MPI2_IOUNITPAGE7_PMCAP_12_5_PCT_IOCSPEED (0x00000400)
+#define MPI2_IOUNITPAGE7_PMCAP_25_0_PCT_IOCSPEED (0x00000200)
+#define MPI2_IOUNITPAGE7_PMCAP_50_0_PCT_IOCSPEED (0x00000100)
+#define MPI2_IOUNITPAGE7_PMCAP_PCIE_WIDTH_CHANGE (0x00000008) /* obsolete */
+#define MPI2_IOUNITPAGE7_PMCAP_PCIE_SPEED_CHANGE (0x00000004) /* obsolete */
+
+
+/* defines for IO Unit Page 7 IOCTemperatureUnits field */
+#define MPI2_IOUNITPAGE7_IOC_TEMP_NOT_PRESENT (0x00)
+#define MPI2_IOUNITPAGE7_IOC_TEMP_FAHRENHEIT (0x01)
+#define MPI2_IOUNITPAGE7_IOC_TEMP_CELSIUS (0x02)
+
+/* defines for IO Unit Page 7 IOCSpeed field */
+#define MPI2_IOUNITPAGE7_IOC_SPEED_FULL (0x01)
+#define MPI2_IOUNITPAGE7_IOC_SPEED_HALF (0x02)
+#define MPI2_IOUNITPAGE7_IOC_SPEED_QUARTER (0x04)
+#define MPI2_IOUNITPAGE7_IOC_SPEED_EIGHTH (0x08)
+
+/* defines for IO Unit Page 7 BoardTemperatureUnits field */
+#define MPI2_IOUNITPAGE7_BOARD_TEMP_NOT_PRESENT (0x00)
+#define MPI2_IOUNITPAGE7_BOARD_TEMP_FAHRENHEIT (0x01)
+#define MPI2_IOUNITPAGE7_BOARD_TEMP_CELSIUS (0x02)
+
+
+/* IO Unit Page 8 */
+
+#define MPI2_IOUNIT8_NUM_THRESHOLDS (4)
+
+typedef struct _MPI2_IOUNIT8_SENSOR
+{
+ U16 Flags; /* 0x00 */
+ U16 Reserved1; /* 0x02 */
+ U16 Threshold[MPI2_IOUNIT8_NUM_THRESHOLDS]; /* 0x04 */
+ U32 Reserved2; /* 0x0C */
+ U32 Reserved3; /* 0x10 */
+ U32 Reserved4; /* 0x14 */
+} MPI2_IOUNIT8_SENSOR, MPI2_POINTER PTR_MPI2_IOUNIT8_SENSOR,
+ Mpi2IOUnit8Sensor_t, MPI2_POINTER pMpi2IOUnit8Sensor_t;
+
+/* defines for IO Unit Page 8 Sensor Flags field */
+#define MPI2_IOUNIT8_SENSOR_FLAGS_T3_ENABLE (0x0008)
+#define MPI2_IOUNIT8_SENSOR_FLAGS_T2_ENABLE (0x0004)
+#define MPI2_IOUNIT8_SENSOR_FLAGS_T1_ENABLE (0x0002)
+#define MPI2_IOUNIT8_SENSOR_FLAGS_T0_ENABLE (0x0001)
+
+/*
+ * Host code (drivers, BIOS, utilities, etc.) should leave this define set to
+ * one and check the value returned for NumSensors at runtime.
+ */
+#ifndef MPI2_IOUNITPAGE8_SENSOR_ENTRIES
+#define MPI2_IOUNITPAGE8_SENSOR_ENTRIES (1)
+#endif
+
+typedef struct _MPI2_CONFIG_PAGE_IO_UNIT_8
+{
+ MPI2_CONFIG_PAGE_HEADER Header; /* 0x00 */
+ U32 Reserved1; /* 0x04 */
+ U32 Reserved2; /* 0x08 */
+ U8 NumSensors; /* 0x0C */
+ U8 PollingInterval; /* 0x0D */
+ U16 Reserved3; /* 0x0E */
+ MPI2_IOUNIT8_SENSOR Sensor[MPI2_IOUNITPAGE8_SENSOR_ENTRIES];/* 0x10 */
+} MPI2_CONFIG_PAGE_IO_UNIT_8, MPI2_POINTER PTR_MPI2_CONFIG_PAGE_IO_UNIT_8,
+ Mpi2IOUnitPage8_t, MPI2_POINTER pMpi2IOUnitPage8_t;
+
+#define MPI2_IOUNITPAGE8_PAGEVERSION (0x00)
+
+
+/* IO Unit Page 9 */
+
+typedef struct _MPI2_IOUNIT9_SENSOR
+{
+ U16 CurrentTemperature; /* 0x00 */
+ U16 Reserved1; /* 0x02 */
+ U8 Flags; /* 0x04 */
+ U8 Reserved2; /* 0x05 */
+ U16 Reserved3; /* 0x06 */
+ U32 Reserved4; /* 0x08 */
+ U32 Reserved5; /* 0x0C */
+} MPI2_IOUNIT9_SENSOR, MPI2_POINTER PTR_MPI2_IOUNIT9_SENSOR,
+ Mpi2IOUnit9Sensor_t, MPI2_POINTER pMpi2IOUnit9Sensor_t;
+
+/* defines for IO Unit Page 9 Sensor Flags field */
+#define MPI2_IOUNIT9_SENSOR_FLAGS_TEMP_VALID (0x01)
+
+/*
+ * Host code (drivers, BIOS, utilities, etc.) should leave this define set to
+ * one and check the value returned for NumSensors at runtime.
+ */
+#ifndef MPI2_IOUNITPAGE9_SENSOR_ENTRIES
+#define MPI2_IOUNITPAGE9_SENSOR_ENTRIES (1)
+#endif
+
+typedef struct _MPI2_CONFIG_PAGE_IO_UNIT_9
+{
+ MPI2_CONFIG_PAGE_HEADER Header; /* 0x00 */
+ U32 Reserved1; /* 0x04 */
+ U32 Reserved2; /* 0x08 */
+ U8 NumSensors; /* 0x0C */
+ U8 Reserved4; /* 0x0D */
+ U16 Reserved3; /* 0x0E */
+ MPI2_IOUNIT9_SENSOR Sensor[MPI2_IOUNITPAGE9_SENSOR_ENTRIES];/* 0x10 */
+} MPI2_CONFIG_PAGE_IO_UNIT_9, MPI2_POINTER PTR_MPI2_CONFIG_PAGE_IO_UNIT_9,
+ Mpi2IOUnitPage9_t, MPI2_POINTER pMpi2IOUnitPage9_t;
+
+#define MPI2_IOUNITPAGE9_PAGEVERSION (0x00)
+
+
+/* IO Unit Page 10 */
+
+typedef struct _MPI2_IOUNIT10_FUNCTION
+{
+ U8 CreditPercent; /* 0x00 */
+ U8 Reserved1; /* 0x01 */
+ U16 Reserved2; /* 0x02 */
+} MPI2_IOUNIT10_FUNCTION, MPI2_POINTER PTR_MPI2_IOUNIT10_FUNCTION,
+ Mpi2IOUnit10Function_t, MPI2_POINTER pMpi2IOUnit10Function_t;
+
+/*
+ * Host code (drivers, BIOS, utilities, etc.) should leave this define set to
+ * one and check the value returned for NumFunctions at runtime.
+ */
+#ifndef MPI2_IOUNITPAGE10_FUNCTION_ENTRIES
+#define MPI2_IOUNITPAGE10_FUNCTION_ENTRIES (1)
+#endif
+
+typedef struct _MPI2_CONFIG_PAGE_IO_UNIT_10
+{
+ MPI2_CONFIG_PAGE_HEADER Header; /* 0x00 */
+ U8 NumFunctions; /* 0x04 */
+ U8 Reserved1; /* 0x05 */
+ U16 Reserved2; /* 0x06 */
+ U32 Reserved3; /* 0x08 */
+ U32 Reserved4; /* 0x0C */
+ MPI2_IOUNIT10_FUNCTION Function[MPI2_IOUNITPAGE10_FUNCTION_ENTRIES]; /* 0x10 */
+} MPI2_CONFIG_PAGE_IO_UNIT_10, MPI2_POINTER PTR_MPI2_CONFIG_PAGE_IO_UNIT_10,
+ Mpi2IOUnitPage10_t, MPI2_POINTER pMpi2IOUnitPage10_t;
+
+#define MPI2_IOUNITPAGE10_PAGEVERSION (0x01)
+
+
+
+/****************************************************************************
+* 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 (0x05)
+
+/* defines for IOC Page 6 CapabilitiesFlags */
+#define MPI2_IOCPAGE6_CAP_FLAGS_4K_SECTORS_SUPPORT (0x00000020)
+#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 SASNotifyPrimitiveMasks; /* 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 (0x02)
+
+
+/* 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 UEFIVersion; /* 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 (0x05)
+
+/* values for BIOS Page 1 BiosOptions field */
+#define MPI2_BIOSPAGE1_OPTIONS_MASK_OEM_ID (0x000000F0)
+#define MPI2_BIOSPAGE1_OPTIONS_LSI_OEM_ID (0x00000000)
+
+#define MPI2_BIOSPAGE1_OPTIONS_MASK_UEFI_HII_REGISTRATION (0x00000006)
+#define MPI2_BIOSPAGE1_OPTIONS_ENABLE_UEFI_HII (0x00000000)
+#define MPI2_BIOSPAGE1_OPTIONS_DISABLE_UEFI_HII (0x00000002)
+#define MPI2_BIOSPAGE1_OPTIONS_VERSION_CHECK_UEFI_HII (0x00000004)
+
+#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)
+
+/* defines for BIOS Page 1 UEFIVersion field */
+#define MPI2_BIOSPAGE1_UEFI_VER_MAJOR_MASK (0xFF00)
+#define MPI2_BIOSPAGE1_UEFI_VER_MAJOR_SHIFT (8)
+#define MPI2_BIOSPAGE1_UEFI_VER_MINOR_MASK (0x00FF)
+#define MPI2_BIOSPAGE1_UEFI_VER_MINOR_SHIFT (0)
+
+
+
+/* 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 the value returned for 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 the value returned for NumPhysDisks 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_VOL_NOT_CONSISTENT (0x00000080)
+#define MPI2_RAIDVOL0_STATUS_FLAG_OCE_ALLOWED (0x00000040)
+#define MPI2_RAIDVOL0_STATUS_FLAG_BGI_COMPLETE (0x00000020)
+#define MPI2_RAIDVOL0_STATUS_FLAG_1E_OFFSET_MIRROR (0x00000000)
+#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_MEDIA_TYPE (0x06)
+#define MPI2_PHYSDISK0_INCOMPATIBLE_UNKNOWN (0xFF)
+
+/* PhysDiskAttributes defines */
+#define MPI2_PHYSDISK0_ATTRIB_MEDIA_MASK (0x0C)
+#define MPI2_PHYSDISK0_ATTRIB_SOLID_STATE_DRIVE (0x08)
+#define MPI2_PHYSDISK0_ATTRIB_HARD_DISK_DRIVE (0x04)
+
+#define MPI2_PHYSDISK0_ATTRIB_PROTOCOL_MASK (0x03)
+#define MPI2_PHYSDISK0_ATTRIB_SAS_PROTOCOL (0x02)
+#define MPI2_PHYSDISK0_ATTRIB_SATA_PROTOCOL (0x01)
+
+/* 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 the value returned for 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_UNSUPPORTED_PHY (0x06)
+#define MPI2_SAS_NEG_LINK_RATE_1_5 (0x08)
+#define MPI2_SAS_NEG_LINK_RATE_3_0 (0x09)
+#define MPI2_SAS_NEG_LINK_RATE_6_0 (0x0A)
+#define MPI25_SAS_NEG_LINK_RATE_12_0 (0x0B)
+
+
+/* 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_PHY_POWER_CONDITION_MASK (0x18000000)
+#define MPI2_SAS_PHYINFO_SHIFT_PHY_POWER_CONDITION (27)
+#define MPI2_SAS_PHYINFO_PHY_POWER_ACTIVE (0x00000000)
+#define MPI2_SAS_PHYINFO_PHY_POWER_PARTIAL (0x08000000)
+#define MPI2_SAS_PHYINFO_PHY_POWER_SLUMBER (0x10000000)
+
+#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 MPI25_SAS_PRATE_MAX_RATE_12_0 (0xB0)
+#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)
+#define MPI25_SAS_PRATE_MIN_RATE_12_0 (0x0B)
+
+
+/* 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 MPI25_SAS_HWRATE_MAX_RATE_12_0 (0xB0)
+#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)
+#define MPI25_SAS_HWRATE_MIN_RATE_12_0 (0x0B)
+
+
+
+/****************************************************************************
+* 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 the value returned for 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 the value returned for 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) /* MPI v2.0 only. Obsolete in MPI v2.5 and later. */
+#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) /* MPI v2.0 only. Obsolete in MPI v2.5 and later. */
+
+/* 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 1 PhyFlags */
+#define MPI2_SASIOUNIT1_PHYFLAGS_ZONING_ENABLE (0x10)
+#define MPI2_SASIOUNIT1_PHYFLAGS_PHY_DISABLE (0x08)
+
+/* values for SAS IO Unit Page 1 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 MPI25_SASIOUNIT1_MAX_RATE_12_0 (0xB0)
+#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)
+#define MPI25_SASIOUNIT1_MIN_RATE_12_0 (0x0B)
+
+/* 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 */
+ U8 SpinupFlags; /* 0x02 */
+ U8 Reserved1; /* 0x03 */
+} MPI2_SAS_IOUNIT4_SPINUP_GROUP, MPI2_POINTER PTR_MPI2_SAS_IOUNIT4_SPINUP_GROUP,
+ Mpi2SasIOUnit4SpinupGroup_t, MPI2_POINTER pMpi2SasIOUnit4SpinupGroup_t;
+
+/* defines for SAS IO Unit Page 4 SpinupFlags */
+#define MPI2_SASIOUNIT4_SPINUP_DISABLE_FLAG (0x01)
+
+
+/*
+ * Host code (drivers, BIOS, utilities, etc.) should leave this define set to
+ * one and check the value returned for 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 IO Unit Page 5 */
+
+typedef struct _MPI2_SAS_IO_UNIT5_PHY_PM_SETTINGS
+{
+ U8 ControlFlags; /* 0x00 */
+ U8 PortWidthModGroup; /* 0x01 */
+ U16 InactivityTimerExponent; /* 0x02 */
+ U8 SATAPartialTimeout; /* 0x04 */
+ U8 Reserved2; /* 0x05 */
+ U8 SATASlumberTimeout; /* 0x06 */
+ U8 Reserved3; /* 0x07 */
+ U8 SASPartialTimeout; /* 0x08 */
+ U8 Reserved4; /* 0x09 */
+ U8 SASSlumberTimeout; /* 0x0A */
+ U8 Reserved5; /* 0x0B */
+} MPI2_SAS_IO_UNIT5_PHY_PM_SETTINGS,
+ MPI2_POINTER PTR_MPI2_SAS_IO_UNIT5_PHY_PM_SETTINGS,
+ Mpi2SasIOUnit5PhyPmSettings_t, MPI2_POINTER pMpi2SasIOUnit5PhyPmSettings_t;
+
+/* defines for ControlFlags field */
+#define MPI2_SASIOUNIT5_CONTROL_SAS_SLUMBER_ENABLE (0x08)
+#define MPI2_SASIOUNIT5_CONTROL_SAS_PARTIAL_ENABLE (0x04)
+#define MPI2_SASIOUNIT5_CONTROL_SATA_SLUMBER_ENABLE (0x02)
+#define MPI2_SASIOUNIT5_CONTROL_SATA_PARTIAL_ENABLE (0x01)
+
+/* defines for PortWidthModeGroup field */
+#define MPI2_SASIOUNIT5_PWMG_DISABLE (0xFF)
+
+/* defines for InactivityTimerExponent field */
+#define MPI2_SASIOUNIT5_ITE_MASK_SAS_SLUMBER (0x7000)
+#define MPI2_SASIOUNIT5_ITE_SHIFT_SAS_SLUMBER (12)
+#define MPI2_SASIOUNIT5_ITE_MASK_SAS_PARTIAL (0x0700)
+#define MPI2_SASIOUNIT5_ITE_SHIFT_SAS_PARTIAL (8)
+#define MPI2_SASIOUNIT5_ITE_MASK_SATA_SLUMBER (0x0070)
+#define MPI2_SASIOUNIT5_ITE_SHIFT_SATA_SLUMBER (4)
+#define MPI2_SASIOUNIT5_ITE_MASK_SATA_PARTIAL (0x0007)
+#define MPI2_SASIOUNIT5_ITE_SHIFT_SATA_PARTIAL (0)
+
+#define MPI2_SASIOUNIT5_ITE_TEN_SECONDS (7)
+#define MPI2_SASIOUNIT5_ITE_ONE_SECOND (6)
+#define MPI2_SASIOUNIT5_ITE_HUNDRED_MILLISECONDS (5)
+#define MPI2_SASIOUNIT5_ITE_TEN_MILLISECONDS (4)
+#define MPI2_SASIOUNIT5_ITE_ONE_MILLISECOND (3)
+#define MPI2_SASIOUNIT5_ITE_HUNDRED_MICROSECONDS (2)
+#define MPI2_SASIOUNIT5_ITE_TEN_MICROSECONDS (1)
+#define MPI2_SASIOUNIT5_ITE_ONE_MICROSECOND (0)
+
+/*
+ * Host code (drivers, BIOS, utilities, etc.) should leave this define set to
+ * one and check the value returned for NumPhys at runtime.
+ */
+#ifndef MPI2_SAS_IOUNIT5_PHY_MAX
+#define MPI2_SAS_IOUNIT5_PHY_MAX (1)
+#endif
+
+typedef struct _MPI2_CONFIG_PAGE_SASIOUNIT_5
+{
+ MPI2_CONFIG_EXTENDED_PAGE_HEADER Header; /* 0x00 */
+ U8 NumPhys; /* 0x08 */
+ U8 Reserved1; /* 0x09 */
+ U16 Reserved2; /* 0x0A */
+ U32 Reserved3; /* 0x0C */
+ MPI2_SAS_IO_UNIT5_PHY_PM_SETTINGS SASPhyPowerManagementSettings[MPI2_SAS_IOUNIT5_PHY_MAX]; /* 0x10 */
+} MPI2_CONFIG_PAGE_SASIOUNIT_5,
+ MPI2_POINTER PTR_MPI2_CONFIG_PAGE_SASIOUNIT_5,
+ Mpi2SasIOUnitPage5_t, MPI2_POINTER pMpi2SasIOUnitPage5_t;
+
+#define MPI2_SASIOUNITPAGE5_PAGEVERSION (0x01)
+
+
+/* SAS IO Unit Page 6 */
+
+typedef struct _MPI2_SAS_IO_UNIT6_PORT_WIDTH_MOD_GROUP_STATUS
+{
+ U8 CurrentStatus; /* 0x00 */
+ U8 CurrentModulation; /* 0x01 */
+ U8 CurrentUtilization; /* 0x02 */
+ U8 Reserved1; /* 0x03 */
+ U32 Reserved2; /* 0x04 */
+} MPI2_SAS_IO_UNIT6_PORT_WIDTH_MOD_GROUP_STATUS,
+ MPI2_POINTER PTR_MPI2_SAS_IO_UNIT6_PORT_WIDTH_MOD_GROUP_STATUS,
+ Mpi2SasIOUnit6PortWidthModGroupStatus_t,
+ MPI2_POINTER pMpi2SasIOUnit6PortWidthModGroupStatus_t;
+
+/* defines for CurrentStatus field */
+#define MPI2_SASIOUNIT6_STATUS_UNAVAILABLE (0x00)
+#define MPI2_SASIOUNIT6_STATUS_UNCONFIGURED (0x01)
+#define MPI2_SASIOUNIT6_STATUS_INVALID_CONFIG (0x02)
+#define MPI2_SASIOUNIT6_STATUS_LINK_DOWN (0x03)
+#define MPI2_SASIOUNIT6_STATUS_OBSERVATION_ONLY (0x04)
+#define MPI2_SASIOUNIT6_STATUS_INACTIVE (0x05)
+#define MPI2_SASIOUNIT6_STATUS_ACTIVE_IOUNIT (0x06)
+#define MPI2_SASIOUNIT6_STATUS_ACTIVE_HOST (0x07)
+
+/* defines for CurrentModulation field */
+#define MPI2_SASIOUNIT6_MODULATION_25_PERCENT (0x00)
+#define MPI2_SASIOUNIT6_MODULATION_50_PERCENT (0x01)
+#define MPI2_SASIOUNIT6_MODULATION_75_PERCENT (0x02)
+#define MPI2_SASIOUNIT6_MODULATION_100_PERCENT (0x03)
+
+/*
+ * Host code (drivers, BIOS, utilities, etc.) should leave this define set to
+ * one and check the value returned for NumGroups at runtime.
+ */
+#ifndef MPI2_SAS_IOUNIT6_GROUP_MAX
+#define MPI2_SAS_IOUNIT6_GROUP_MAX (1)
+#endif
+
+typedef struct _MPI2_CONFIG_PAGE_SASIOUNIT_6
+{
+ MPI2_CONFIG_EXTENDED_PAGE_HEADER Header; /* 0x00 */
+ U32 Reserved1; /* 0x08 */
+ U32 Reserved2; /* 0x0C */
+ U8 NumGroups; /* 0x10 */
+ U8 Reserved3; /* 0x11 */
+ U16 Reserved4; /* 0x12 */
+ MPI2_SAS_IO_UNIT6_PORT_WIDTH_MOD_GROUP_STATUS
+ PortWidthModulationGroupStatus[MPI2_SAS_IOUNIT6_GROUP_MAX]; /* 0x14 */
+} MPI2_CONFIG_PAGE_SASIOUNIT_6,
+ MPI2_POINTER PTR_MPI2_CONFIG_PAGE_SASIOUNIT_6,
+ Mpi2SasIOUnitPage6_t, MPI2_POINTER pMpi2SasIOUnitPage6_t;
+
+#define MPI2_SASIOUNITPAGE6_PAGEVERSION (0x00)
+
+
+/* SAS IO Unit Page 7 */
+
+typedef struct _MPI2_SAS_IO_UNIT7_PORT_WIDTH_MOD_GROUP_SETTINGS
+{
+ U8 Flags; /* 0x00 */
+ U8 Reserved1; /* 0x01 */
+ U16 Reserved2; /* 0x02 */
+ U8 Threshold75Pct; /* 0x04 */
+ U8 Threshold50Pct; /* 0x05 */
+ U8 Threshold25Pct; /* 0x06 */
+ U8 Reserved3; /* 0x07 */
+} MPI2_SAS_IO_UNIT7_PORT_WIDTH_MOD_GROUP_SETTINGS,
+ MPI2_POINTER PTR_MPI2_SAS_IO_UNIT7_PORT_WIDTH_MOD_GROUP_SETTINGS,
+ Mpi2SasIOUnit7PortWidthModGroupSettings_t,
+ MPI2_POINTER pMpi2SasIOUnit7PortWidthModGroupSettings_t;
+
+/* defines for Flags field */
+#define MPI2_SASIOUNIT7_FLAGS_ENABLE_PORT_WIDTH_MODULATION (0x01)
+
+
+/*
+ * Host code (drivers, BIOS, utilities, etc.) should leave this define set to
+ * one and check the value returned for NumGroups at runtime.
+ */
+#ifndef MPI2_SAS_IOUNIT7_GROUP_MAX
+#define MPI2_SAS_IOUNIT7_GROUP_MAX (1)
+#endif
+
+typedef struct _MPI2_CONFIG_PAGE_SASIOUNIT_7
+{
+ MPI2_CONFIG_EXTENDED_PAGE_HEADER Header; /* 0x00 */
+ U8 SamplingInterval; /* 0x08 */
+ U8 WindowLength; /* 0x09 */
+ U16 Reserved1; /* 0x0A */
+ U32 Reserved2; /* 0x0C */
+ U32 Reserved3; /* 0x10 */
+ U8 NumGroups; /* 0x14 */
+ U8 Reserved4; /* 0x15 */
+ U16 Reserved5; /* 0x16 */
+ MPI2_SAS_IO_UNIT7_PORT_WIDTH_MOD_GROUP_SETTINGS
+ PortWidthModulationGroupSettings[MPI2_SAS_IOUNIT7_GROUP_MAX]; /* 0x18 */
+} MPI2_CONFIG_PAGE_SASIOUNIT_7,
+ MPI2_POINTER PTR_MPI2_CONFIG_PAGE_SASIOUNIT_7,
+ Mpi2SasIOUnitPage7_t, MPI2_POINTER pMpi2SasIOUnitPage7_t;
+
+#define MPI2_SASIOUNITPAGE7_PAGEVERSION (0x00)
+
+
+/* SAS IO Unit Page 8 */
+
+typedef struct _MPI2_CONFIG_PAGE_SASIOUNIT_8
+{
+ MPI2_CONFIG_EXTENDED_PAGE_HEADER Header; /* 0x00 */
+ U32 Reserved1; /* 0x08 */
+ U32 PowerManagementCapabilities; /* 0x0C */
+ U8 TxRxSleepStatus; /* 0x10 */ /* reserved in MPI 2.0 */
+ U8 Reserved2; /* 0x11 */
+ U16 Reserved3; /* 0x12 */
+} MPI2_CONFIG_PAGE_SASIOUNIT_8,
+ MPI2_POINTER PTR_MPI2_CONFIG_PAGE_SASIOUNIT_8,
+ Mpi2SasIOUnitPage8_t, MPI2_POINTER pMpi2SasIOUnitPage8_t;
+
+#define MPI2_SASIOUNITPAGE8_PAGEVERSION (0x00)
+
+/* defines for PowerManagementCapabilities field */
+#define MPI2_SASIOUNIT8_PM_HOST_PORT_WIDTH_MOD (0x00001000)
+#define MPI2_SASIOUNIT8_PM_HOST_SAS_SLUMBER_MODE (0x00000800)
+#define MPI2_SASIOUNIT8_PM_HOST_SAS_PARTIAL_MODE (0x00000400)
+#define MPI2_SASIOUNIT8_PM_HOST_SATA_SLUMBER_MODE (0x00000200)
+#define MPI2_SASIOUNIT8_PM_HOST_SATA_PARTIAL_MODE (0x00000100)
+#define MPI2_SASIOUNIT8_PM_IOUNIT_PORT_WIDTH_MOD (0x00000010)
+#define MPI2_SASIOUNIT8_PM_IOUNIT_SAS_SLUMBER_MODE (0x00000008)
+#define MPI2_SASIOUNIT8_PM_IOUNIT_SAS_PARTIAL_MODE (0x00000004)
+#define MPI2_SASIOUNIT8_PM_IOUNIT_SATA_SLUMBER_MODE (0x00000002)
+#define MPI2_SASIOUNIT8_PM_IOUNIT_SATA_PARTIAL_MODE (0x00000001)
+
+/* defines for TxRxSleepStatus field */
+#define MPI25_SASIOUNIT8_TXRXSLEEP_UNSUPPORTED (0x00)
+#define MPI25_SASIOUNIT8_TXRXSLEEP_DISENGAGED (0x01)
+#define MPI25_SASIOUNIT8_TXRXSLEEP_ACTIVE (0x02)
+#define MPI25_SASIOUNIT8_TXRXSLEEP_SHUTDOWN (0x03)
+
+
+
+/* SAS IO Unit Page 16 */
+
+typedef struct _MPI2_CONFIG_PAGE_SASIOUNIT16
+{
+ MPI2_CONFIG_EXTENDED_PAGE_HEADER Header; /* 0x00 */
+ U64 TimeStamp; /* 0x08 */
+ U32 Reserved1; /* 0x10 */
+ U32 Reserved2; /* 0x14 */
+ U32 FastPathPendedRequests; /* 0x18 */
+ U32 FastPathUnPendedRequests; /* 0x1C */
+ U32 FastPathHostRequestStarts; /* 0x20 */
+ U32 FastPathFirmwareRequestStarts; /* 0x24 */
+ U32 FastPathHostCompletions; /* 0x28 */
+ U32 FastPathFirmwareCompletions; /* 0x2C */
+ U32 NonFastPathRequestStarts; /* 0x30 */
+ U32 NonFastPathHostCompletions; /* 0x30 */
+} MPI2_CONFIG_PAGE_SASIOUNIT16,
+ MPI2_POINTER PTR_MPI2_CONFIG_PAGE_SASIOUNIT16,
+ Mpi2SasIOUnitPage16_t, MPI2_POINTER pMpi2SasIOUnitPage16_t;
+
+#define MPI2_SASIOUNITPAGE16_PAGEVERSION (0x00)
+
+
+/****************************************************************************
+* 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 */
+ U8 TimeToReducedFunc; /* 0x38 */
+ U8 InitialTimeToReducedFunc; /* 0x39 */
+ U8 MaxReducedFuncTime; /* 0x3A */
+ U8 Reserved2; /* 0x3B */
+} MPI2_CONFIG_PAGE_EXPANDER_0, MPI2_POINTER PTR_MPI2_CONFIG_PAGE_EXPANDER_0,
+ Mpi2ExpanderPage0_t, MPI2_POINTER pMpi2ExpanderPage0_t;
+
+#define MPI2_SASEXPANDER0_PAGEVERSION (0x06)
+
+/* 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_REDUCED_FUNCTIONALITY (0x2000)
+#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 */
+
+/* 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)
+
+/* use MPI2_SAS_APHYINFO_ defines for AttachedPhyInfo field */
+
+
+/****************************************************************************
+* 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 EnclosureLevel; /* 0x2F */
+ U8 ConnectorName[4]; /* 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 (0x09)
+
+/* 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_UNAUTHORIZED_DEVICE (0x8000)
+#define MPI25_SAS_DEVICE0_FLAGS_ENABLED_FAST_PATH (0x4000)
+#define MPI25_SAS_DEVICE0_FLAGS_FAST_PATH_CAPABLE (0x2000)
+#define MPI2_SAS_DEVICE0_FLAGS_SLUMBER_PM_CAPABLE (0x1000)
+#define MPI2_SAS_DEVICE0_FLAGS_PARTIAL_PM_CAPABLE (0x0800)
+#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_ENCL_LEVEL_VALID (0x0002)
+#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_APHYINFO_ defines for AttachedPhyInfo field */
+
+/* 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_PHYINFO_ for the PhyInfo field */
+
+/* use MPI2_SAS_NEG_LINK_RATE_ defines for the NegotiatedLinkRate 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 PHY Page 2 */
+
+typedef struct _MPI2_SASPHY2_PHY_EVENT
+{
+ U8 PhyEventCode; /* 0x00 */
+ U8 Reserved1; /* 0x01 */
+ U16 Reserved2; /* 0x02 */
+ U32 PhyEventInfo; /* 0x04 */
+} MPI2_SASPHY2_PHY_EVENT, MPI2_POINTER PTR_MPI2_SASPHY2_PHY_EVENT,
+ Mpi2SasPhy2PhyEvent_t, MPI2_POINTER pMpi2SasPhy2PhyEvent_t;
+
+/* use MPI2_SASPHY3_EVENT_CODE_ for the PhyEventCode field */
+
+
+/*
+ * Host code (drivers, BIOS, utilities, etc.) should leave this define set to
+ * one and check the value returned for NumPhyEvents at runtime.
+ */
+#ifndef MPI2_SASPHY2_PHY_EVENT_MAX
+#define MPI2_SASPHY2_PHY_EVENT_MAX (1)
+#endif
+
+typedef struct _MPI2_CONFIG_PAGE_SAS_PHY_2
+{
+ MPI2_CONFIG_EXTENDED_PAGE_HEADER Header; /* 0x00 */
+ U32 Reserved1; /* 0x08 */
+ U8 NumPhyEvents; /* 0x0C */
+ U8 Reserved2; /* 0x0D */
+ U16 Reserved3; /* 0x0E */
+ MPI2_SASPHY2_PHY_EVENT PhyEvent[MPI2_SASPHY2_PHY_EVENT_MAX]; /* 0x10 */
+} MPI2_CONFIG_PAGE_SAS_PHY_2, MPI2_POINTER PTR_MPI2_CONFIG_PAGE_SAS_PHY_2,
+ Mpi2SasPhyPage2_t, MPI2_POINTER pMpi2SasPhyPage2_t;
+
+#define MPI2_SASPHY2_PAGEVERSION (0x00)
+
+
+/* SAS PHY Page 3 */
+
+typedef struct _MPI2_SASPHY3_PHY_EVENT_CONFIG
+{
+ U8 PhyEventCode; /* 0x00 */
+ U8 Reserved1; /* 0x01 */
+ U16 Reserved2; /* 0x02 */
+ U8 CounterType; /* 0x04 */
+ U8 ThresholdWindow; /* 0x05 */
+ U8 TimeUnits; /* 0x06 */
+ U8 Reserved3; /* 0x07 */
+ U32 EventThreshold; /* 0x08 */
+ U16 ThresholdFlags; /* 0x0C */
+ U16 Reserved4; /* 0x0E */
+} MPI2_SASPHY3_PHY_EVENT_CONFIG, MPI2_POINTER PTR_MPI2_SASPHY3_PHY_EVENT_CONFIG,
+ Mpi2SasPhy3PhyEventConfig_t, MPI2_POINTER pMpi2SasPhy3PhyEventConfig_t;
+
+/* values for PhyEventCode field */
+#define MPI2_SASPHY3_EVENT_CODE_NO_EVENT (0x00)
+#define MPI2_SASPHY3_EVENT_CODE_INVALID_DWORD (0x01)
+#define MPI2_SASPHY3_EVENT_CODE_RUNNING_DISPARITY_ERROR (0x02)
+#define MPI2_SASPHY3_EVENT_CODE_LOSS_DWORD_SYNC (0x03)
+#define MPI2_SASPHY3_EVENT_CODE_PHY_RESET_PROBLEM (0x04)
+#define MPI2_SASPHY3_EVENT_CODE_ELASTICITY_BUF_OVERFLOW (0x05)
+#define MPI2_SASPHY3_EVENT_CODE_RX_ERROR (0x06)
+#define MPI2_SASPHY3_EVENT_CODE_RX_ADDR_FRAME_ERROR (0x20)
+#define MPI2_SASPHY3_EVENT_CODE_TX_AC_OPEN_REJECT (0x21)
+#define MPI2_SASPHY3_EVENT_CODE_RX_AC_OPEN_REJECT (0x22)
+#define MPI2_SASPHY3_EVENT_CODE_TX_RC_OPEN_REJECT (0x23)
+#define MPI2_SASPHY3_EVENT_CODE_RX_RC_OPEN_REJECT (0x24)
+#define MPI2_SASPHY3_EVENT_CODE_RX_AIP_PARTIAL_WAITING_ON (0x25)
+#define MPI2_SASPHY3_EVENT_CODE_RX_AIP_CONNECT_WAITING_ON (0x26)
+#define MPI2_SASPHY3_EVENT_CODE_TX_BREAK (0x27)
+#define MPI2_SASPHY3_EVENT_CODE_RX_BREAK (0x28)
+#define MPI2_SASPHY3_EVENT_CODE_BREAK_TIMEOUT (0x29)
+#define MPI2_SASPHY3_EVENT_CODE_CONNECTION (0x2A)
+#define MPI2_SASPHY3_EVENT_CODE_PEAKTX_PATHWAY_BLOCKED (0x2B)
+#define MPI2_SASPHY3_EVENT_CODE_PEAKTX_ARB_WAIT_TIME (0x2C)
+#define MPI2_SASPHY3_EVENT_CODE_PEAK_ARB_WAIT_TIME (0x2D)
+#define MPI2_SASPHY3_EVENT_CODE_PEAK_CONNECT_TIME (0x2E)
+#define MPI2_SASPHY3_EVENT_CODE_TX_SSP_FRAMES (0x40)
+#define MPI2_SASPHY3_EVENT_CODE_RX_SSP_FRAMES (0x41)
+#define MPI2_SASPHY3_EVENT_CODE_TX_SSP_ERROR_FRAMES (0x42)
+#define MPI2_SASPHY3_EVENT_CODE_RX_SSP_ERROR_FRAMES (0x43)
+#define MPI2_SASPHY3_EVENT_CODE_TX_CREDIT_BLOCKED (0x44)
+#define MPI2_SASPHY3_EVENT_CODE_RX_CREDIT_BLOCKED (0x45)
+#define MPI2_SASPHY3_EVENT_CODE_TX_SATA_FRAMES (0x50)
+#define MPI2_SASPHY3_EVENT_CODE_RX_SATA_FRAMES (0x51)
+#define MPI2_SASPHY3_EVENT_CODE_SATA_OVERFLOW (0x52)
+#define MPI2_SASPHY3_EVENT_CODE_TX_SMP_FRAMES (0x60)
+#define MPI2_SASPHY3_EVENT_CODE_RX_SMP_FRAMES (0x61)
+#define MPI2_SASPHY3_EVENT_CODE_RX_SMP_ERROR_FRAMES (0x63)
+#define MPI2_SASPHY3_EVENT_CODE_HOTPLUG_TIMEOUT (0xD0)
+#define MPI2_SASPHY3_EVENT_CODE_MISALIGNED_MUX_PRIMITIVE (0xD1)
+#define MPI2_SASPHY3_EVENT_CODE_RX_AIP (0xD2)
+
+/* values for the CounterType field */
+#define MPI2_SASPHY3_COUNTER_TYPE_WRAPPING (0x00)
+#define MPI2_SASPHY3_COUNTER_TYPE_SATURATING (0x01)
+#define MPI2_SASPHY3_COUNTER_TYPE_PEAK_VALUE (0x02)
+
+/* values for the TimeUnits field */
+#define MPI2_SASPHY3_TIME_UNITS_10_MICROSECONDS (0x00)
+#define MPI2_SASPHY3_TIME_UNITS_100_MICROSECONDS (0x01)
+#define MPI2_SASPHY3_TIME_UNITS_1_MILLISECOND (0x02)
+#define MPI2_SASPHY3_TIME_UNITS_10_MILLISECONDS (0x03)
+
+/* values for the ThresholdFlags field */
+#define MPI2_SASPHY3_TFLAGS_PHY_RESET (0x0002)
+#define MPI2_SASPHY3_TFLAGS_EVENT_NOTIFY (0x0001)
+
+/*
+ * Host code (drivers, BIOS, utilities, etc.) should leave this define set to
+ * one and check the value returned for NumPhyEvents at runtime.
+ */
+#ifndef MPI2_SASPHY3_PHY_EVENT_MAX
+#define MPI2_SASPHY3_PHY_EVENT_MAX (1)
+#endif
+
+typedef struct _MPI2_CONFIG_PAGE_SAS_PHY_3
+{
+ MPI2_CONFIG_EXTENDED_PAGE_HEADER Header; /* 0x00 */
+ U32 Reserved1; /* 0x08 */
+ U8 NumPhyEvents; /* 0x0C */
+ U8 Reserved2; /* 0x0D */
+ U16 Reserved3; /* 0x0E */
+ MPI2_SASPHY3_PHY_EVENT_CONFIG PhyEventConfig[MPI2_SASPHY3_PHY_EVENT_MAX]; /* 0x10 */
+} MPI2_CONFIG_PAGE_SAS_PHY_3, MPI2_POINTER PTR_MPI2_CONFIG_PAGE_SAS_PHY_3,
+ Mpi2SasPhyPage3_t, MPI2_POINTER pMpi2SasPhyPage3_t;
+
+#define MPI2_SASPHY3_PAGEVERSION (0x00)
+
+
+/* SAS PHY Page 4 */
+
+typedef struct _MPI2_CONFIG_PAGE_SAS_PHY_4
+{
+ MPI2_CONFIG_EXTENDED_PAGE_HEADER Header; /* 0x00 */
+ U16 Reserved1; /* 0x08 */
+ U8 Reserved2; /* 0x0A */
+ U8 Flags; /* 0x0B */
+ U8 InitialFrame[28]; /* 0x0C */
+} MPI2_CONFIG_PAGE_SAS_PHY_4, MPI2_POINTER PTR_MPI2_CONFIG_PAGE_SAS_PHY_4,
+ Mpi2SasPhyPage4_t, MPI2_POINTER pMpi2SasPhyPage4_t;
+
+#define MPI2_SASPHY4_PAGEVERSION (0x00)
+
+/* values for the Flags field */
+#define MPI2_SASPHY4_FLAGS_FRAME_VALID (0x02)
+#define MPI2_SASPHY4_FLAGS_SATA_FRAME (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 */
+ U8 Reserved2; /* 0x1C */
+ U8 EnclosureLevel; /* 0x1D */
+ 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 (0x04)
+
+/* values for SAS Enclosure Page 0 Flags field */
+#define MPI2_SAS_ENCLS0_FLAGS_ENCL_LEVEL_VALID (0x0010)
+#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 the value returned for NumLogEntries 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 the value returned for NumElements 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)
+
+
+/****************************************************************************
+* Ethernet Config Pages
+****************************************************************************/
+
+/* Ethernet Page 0 */
+
+/* IP address (union of IPv4 and IPv6) */
+typedef union _MPI2_ETHERNET_IP_ADDR
+{
+ U32 IPv4Addr;
+ U32 IPv6Addr[4];
+} MPI2_ETHERNET_IP_ADDR, MPI2_POINTER PTR_MPI2_ETHERNET_IP_ADDR,
+ Mpi2EthernetIpAddr_t, MPI2_POINTER pMpi2EthernetIpAddr_t;
+
+#define MPI2_ETHERNET_HOST_NAME_LENGTH (32)
+
+typedef struct _MPI2_CONFIG_PAGE_ETHERNET_0
+{
+ MPI2_CONFIG_EXTENDED_PAGE_HEADER Header; /* 0x00 */
+ U8 NumInterfaces; /* 0x08 */
+ U8 Reserved0; /* 0x09 */
+ U16 Reserved1; /* 0x0A */
+ U32 Status; /* 0x0C */
+ U8 MediaState; /* 0x10 */
+ U8 Reserved2; /* 0x11 */
+ U16 Reserved3; /* 0x12 */
+ U8 MacAddress[6]; /* 0x14 */
+ U8 Reserved4; /* 0x1A */
+ U8 Reserved5; /* 0x1B */
+ MPI2_ETHERNET_IP_ADDR IpAddress; /* 0x1C */
+ MPI2_ETHERNET_IP_ADDR SubnetMask; /* 0x2C */
+ MPI2_ETHERNET_IP_ADDR GatewayIpAddress; /* 0x3C */
+ MPI2_ETHERNET_IP_ADDR DNS1IpAddress; /* 0x4C */
+ MPI2_ETHERNET_IP_ADDR DNS2IpAddress; /* 0x5C */
+ MPI2_ETHERNET_IP_ADDR DhcpIpAddress; /* 0x6C */
+ U8 HostName[MPI2_ETHERNET_HOST_NAME_LENGTH];/* 0x7C */
+} MPI2_CONFIG_PAGE_ETHERNET_0, MPI2_POINTER PTR_MPI2_CONFIG_PAGE_ETHERNET_0,
+ Mpi2EthernetPage0_t, MPI2_POINTER pMpi2EthernetPage0_t;
+
+#define MPI2_ETHERNETPAGE0_PAGEVERSION (0x00)
+
+/* values for Ethernet Page 0 Status field */
+#define MPI2_ETHPG0_STATUS_IPV6_CAPABLE (0x80000000)
+#define MPI2_ETHPG0_STATUS_IPV4_CAPABLE (0x40000000)
+#define MPI2_ETHPG0_STATUS_CONSOLE_CONNECTED (0x20000000)
+#define MPI2_ETHPG0_STATUS_DEFAULT_IF (0x00000100)
+#define MPI2_ETHPG0_STATUS_FW_DWNLD_ENABLED (0x00000080)
+#define MPI2_ETHPG0_STATUS_TELNET_ENABLED (0x00000040)
+#define MPI2_ETHPG0_STATUS_SSH2_ENABLED (0x00000020)
+#define MPI2_ETHPG0_STATUS_DHCP_CLIENT_ENABLED (0x00000010)
+#define MPI2_ETHPG0_STATUS_IPV6_ENABLED (0x00000008)
+#define MPI2_ETHPG0_STATUS_IPV4_ENABLED (0x00000004)
+#define MPI2_ETHPG0_STATUS_IPV6_ADDRESSES (0x00000002)
+#define MPI2_ETHPG0_STATUS_ETH_IF_ENABLED (0x00000001)
+
+/* values for Ethernet Page 0 MediaState field */
+#define MPI2_ETHPG0_MS_DUPLEX_MASK (0x80)
+#define MPI2_ETHPG0_MS_HALF_DUPLEX (0x00)
+#define MPI2_ETHPG0_MS_FULL_DUPLEX (0x80)
+
+#define MPI2_ETHPG0_MS_CONNECT_SPEED_MASK (0x07)
+#define MPI2_ETHPG0_MS_NOT_CONNECTED (0x00)
+#define MPI2_ETHPG0_MS_10MBIT (0x01)
+#define MPI2_ETHPG0_MS_100MBIT (0x02)
+#define MPI2_ETHPG0_MS_1GBIT (0x03)
+
+
+/* Ethernet Page 1 */
+
+typedef struct _MPI2_CONFIG_PAGE_ETHERNET_1
+{
+ MPI2_CONFIG_EXTENDED_PAGE_HEADER Header; /* 0x00 */
+ U32 Reserved0; /* 0x08 */
+ U32 Flags; /* 0x0C */
+ U8 MediaState; /* 0x10 */
+ U8 Reserved1; /* 0x11 */
+ U16 Reserved2; /* 0x12 */
+ U8 MacAddress[6]; /* 0x14 */
+ U8 Reserved3; /* 0x1A */
+ U8 Reserved4; /* 0x1B */
+ MPI2_ETHERNET_IP_ADDR StaticIpAddress; /* 0x1C */
+ MPI2_ETHERNET_IP_ADDR StaticSubnetMask; /* 0x2C */
+ MPI2_ETHERNET_IP_ADDR StaticGatewayIpAddress; /* 0x3C */
+ MPI2_ETHERNET_IP_ADDR StaticDNS1IpAddress; /* 0x4C */
+ MPI2_ETHERNET_IP_ADDR StaticDNS2IpAddress; /* 0x5C */
+ U32 Reserved5; /* 0x6C */
+ U32 Reserved6; /* 0x70 */
+ U32 Reserved7; /* 0x74 */
+ U32 Reserved8; /* 0x78 */
+ U8 HostName[MPI2_ETHERNET_HOST_NAME_LENGTH];/* 0x7C */
+} MPI2_CONFIG_PAGE_ETHERNET_1, MPI2_POINTER PTR_MPI2_CONFIG_PAGE_ETHERNET_1,
+ Mpi2EthernetPage1_t, MPI2_POINTER pMpi2EthernetPage1_t;
+
+#define MPI2_ETHERNETPAGE1_PAGEVERSION (0x00)
+
+/* values for Ethernet Page 1 Flags field */
+#define MPI2_ETHPG1_FLAG_SET_DEFAULT_IF (0x00000100)
+#define MPI2_ETHPG1_FLAG_ENABLE_FW_DOWNLOAD (0x00000080)
+#define MPI2_ETHPG1_FLAG_ENABLE_TELNET (0x00000040)
+#define MPI2_ETHPG1_FLAG_ENABLE_SSH2 (0x00000020)
+#define MPI2_ETHPG1_FLAG_ENABLE_DHCP_CLIENT (0x00000010)
+#define MPI2_ETHPG1_FLAG_ENABLE_IPV6 (0x00000008)
+#define MPI2_ETHPG1_FLAG_ENABLE_IPV4 (0x00000004)
+#define MPI2_ETHPG1_FLAG_USE_IPV6_ADDRESSES (0x00000002)
+#define MPI2_ETHPG1_FLAG_ENABLE_ETH_IF (0x00000001)
+
+/* values for Ethernet Page 1 MediaState field */
+#define MPI2_ETHPG1_MS_DUPLEX_MASK (0x80)
+#define MPI2_ETHPG1_MS_HALF_DUPLEX (0x00)
+#define MPI2_ETHPG1_MS_FULL_DUPLEX (0x80)
+
+#define MPI2_ETHPG1_MS_DATA_RATE_MASK (0x07)
+#define MPI2_ETHPG1_MS_DATA_RATE_AUTO (0x00)
+#define MPI2_ETHPG1_MS_DATA_RATE_10MBIT (0x01)
+#define MPI2_ETHPG1_MS_DATA_RATE_100MBIT (0x02)
+#define MPI2_ETHPG1_MS_DATA_RATE_1GBIT (0x03)
+
+
+/****************************************************************************
+* Extended Manufacturing Config Pages
+****************************************************************************/
+
+/*
+ * Generic structure to use for product-specific extended manufacturing pages
+ * (currently Extended Manufacturing Page 40 through Extended Manufacturing
+ * Page 60).
+ */
+
+typedef struct _MPI2_CONFIG_PAGE_EXT_MAN_PS
+{
+ MPI2_CONFIG_EXTENDED_PAGE_HEADER Header; /* 0x00 */
+ U32 ProductSpecificInfo; /* 0x08 */
+} MPI2_CONFIG_PAGE_EXT_MAN_PS,
+ MPI2_POINTER PTR_MPI2_CONFIG_PAGE_EXT_MAN_PS,
+ Mpi2ExtManufacturingPagePS_t, MPI2_POINTER pMpi2ExtManufacturingPagePS_t;
+
+/* PageVersion should be provided by product-specific code */
+
+#endif
+
diff --git a/sys/dev/mpr/mpi/mpi2_hbd.h b/sys/dev/mpr/mpi/mpi2_hbd.h
new file mode 100644
index 0000000..d0cc09f
--- /dev/null
+++ b/sys/dev/mpr/mpi/mpi2_hbd.h
@@ -0,0 +1,152 @@
+/*-
+ * Copyright (c) 2013 LSI Corp.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the author nor the names of any co-contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * LSI MPT-Fusion Host Adapter FreeBSD
+ *
+ * $FreeBSD$
+ */
+
+/*
+ * Copyright (c) 2009-2011 LSI Corporation.
+ *
+ *
+ * Name: mpi2_hbd.h
+ * Title: MPI Host Based Discovery messages and structures
+ * Creation Date: October 21, 2009
+ *
+ * mpi2_hbd.h Version: 02.00.02
+ *
+ * NOTE: Names (typedefs, defines, etc.) beginning with an MPI25 or Mpi25
+ * prefix are for use only on MPI v2.5 products, and must not be used
+ * with MPI v2.0 products. Unless otherwise noted, names beginning with
+ * MPI2 or Mpi2 are for use with both MPI v2.0 and MPI v2.5 products.
+ *
+ * Version History
+ * ---------------
+ *
+ * Date Version Description
+ * -------- -------- ------------------------------------------------------
+ * 10-28-09 02.00.00 Initial version.
+ * 08-11-10 02.00.01 Removed PortGroups, DmaGroup, and ControlGroup from
+ * HBD Action request, replaced by AdditionalInfo field.
+ * 11-18-11 02.00.02 Incorporating additions for MPI v2.5.
+ * --------------------------------------------------------------------------
+ */
+
+#ifndef MPI2_HBD_H
+#define MPI2_HBD_H
+
+/****************************************************************************
+* Host Based Discovery Action messages
+****************************************************************************/
+
+/* Host Based Discovery Action Request Message */
+typedef struct _MPI2_HBD_ACTION_REQUEST
+{
+ U8 Operation; /* 0x00 */
+ U8 Reserved1; /* 0x01 */
+ U8 ChainOffset; /* 0x02 */
+ U8 Function; /* 0x03 */
+ U16 DevHandle; /* 0x04 */
+ U8 Reserved2; /* 0x06 */
+ U8 MsgFlags; /* 0x07 */
+ U8 VP_ID; /* 0x08 */
+ U8 VF_ID; /* 0x09 */
+ U16 Reserved3; /* 0x0A */
+ U32 Reserved4; /* 0x0C */
+ U64 SASAddress; /* 0x10 */
+ U32 Reserved5; /* 0x18 */
+ U32 HbdDeviceInfo; /* 0x1C */
+ U16 ParentDevHandle; /* 0x20 */
+ U16 MaxQDepth; /* 0x22 */
+ U8 FirstPhyIdentifier; /* 0x24 */
+ U8 Port; /* 0x25 */
+ U8 MaxConnections; /* 0x26 */
+ U8 MaxRate; /* 0x27 */
+ U32 AdditionalInfo; /* 0x28 */
+ U16 InitialAWT; /* 0x2C */
+ U16 Reserved7; /* 0x2E */
+ U32 Reserved8; /* 0x30 */
+} MPI2_HBD_ACTION_REQUEST, MPI2_POINTER PTR_MPI2_HBD_ACTION_REQUEST,
+ Mpi2HbdActionRequest_t, MPI2_POINTER pMpi2HbdActionRequest_t;
+
+/* values for the Operation field */
+#define MPI2_HBD_OP_ADD_DEVICE (0x01)
+#define MPI2_HBD_OP_REMOVE_DEVICE (0x02)
+#define MPI2_HBD_OP_UPDATE_DEVICE (0x03)
+
+/* values for the HbdDeviceInfo field */
+#define MPI2_HBD_DEVICE_INFO_VIRTUAL_DEVICE (0x00004000)
+#define MPI2_HBD_DEVICE_INFO_ATAPI_DEVICE (0x00002000)
+#define MPI2_HBD_DEVICE_INFO_DIRECT_ATTACH (0x00000800)
+#define MPI2_HBD_DEVICE_INFO_SSP_TARGET (0x00000400)
+#define MPI2_HBD_DEVICE_INFO_STP_TARGET (0x00000200)
+#define MPI2_HBD_DEVICE_INFO_SMP_TARGET (0x00000100)
+#define MPI2_HBD_DEVICE_INFO_SATA_DEVICE (0x00000080)
+#define MPI2_HBD_DEVICE_INFO_SSP_INITIATOR (0x00000040)
+#define MPI2_HBD_DEVICE_INFO_STP_INITIATOR (0x00000020)
+#define MPI2_HBD_DEVICE_INFO_SMP_INITIATOR (0x00000010)
+#define MPI2_HBD_DEVICE_INFO_SATA_HOST (0x00000008)
+
+#define MPI2_HBD_DEVICE_INFO_MASK_DEVICE_TYPE (0x00000007)
+#define MPI2_HBD_DEVICE_INFO_NO_DEVICE (0x00000000)
+#define MPI2_HBD_DEVICE_INFO_END_DEVICE (0x00000001)
+#define MPI2_HBD_DEVICE_INFO_EDGE_EXPANDER (0x00000002)
+#define MPI2_HBD_DEVICE_INFO_FANOUT_EXPANDER (0x00000003)
+
+/* values for the MaxRate field */
+#define MPI2_HBD_MAX_RATE_MASK (0x0F)
+#define MPI2_HBD_MAX_RATE_1_5 (0x08)
+#define MPI2_HBD_MAX_RATE_3_0 (0x09)
+#define MPI2_HBD_MAX_RATE_6_0 (0x0A)
+#define MPI25_HBD_MAX_RATE_12_0 (0x0B)
+
+
+/* Host Based Discovery Action Reply Message */
+typedef struct _MPI2_HBD_ACTION_REPLY
+{
+ U8 Operation; /* 0x00 */
+ U8 Reserved1; /* 0x01 */
+ U8 MsgLength; /* 0x02 */
+ U8 Function; /* 0x03 */
+ U16 DevHandle; /* 0x04 */
+ U8 Reserved2; /* 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_HBD_ACTION_REPLY, MPI2_POINTER PTR_MPI2_HBD_ACTION_REPLY,
+ Mpi2HbdActionReply_t, MPI2_POINTER pMpi2HbdActionReply_t;
+
+
+#endif
+
+
diff --git a/sys/dev/mpr/mpi/mpi2_history.txt b/sys/dev/mpr/mpi/mpi2_history.txt
new file mode 100644
index 0000000..296b75b
--- /dev/null
+++ b/sys/dev/mpr/mpi/mpi2_history.txt
@@ -0,0 +1,619 @@
+/*-
+ * Copyright (c) 2013 LSI Corp.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the author nor the names of any co-contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * LSI MPT-Fusion Host Adapter FreeBSD
+ *
+ * $FreeBSD$
+ */
+
+ ==============================
+ Fusion-MPT MPI 2.0 / 2.5 Header File Change History
+ ==============================
+
+ Copyright (c) 2000-2013 LSI Corporation.
+
+ ---------------------------------------
+ Header Set Release Version: 02.00.33
+ Header Set Release Date: 12-05-13
+ ---------------------------------------
+
+ Filename Current version Prior version
+ ---------- --------------- -------------
+ mpi2.h 02.00.33 02.00.32
+ mpi2_cnfg.h 02.00.27 02.00.26
+ mpi2_init.h 02.00.15 02.00.15
+ mpi2_ioc.h 02.00.24 02.00.23
+ mpi2_raid.h 02.00.10 02.00.10
+ mpi2_sas.h 02.00.08 02.00.08
+ mpi2_targ.h 02.00.06 02.00.06
+ mpi2_tool.h 02.00.11 02.00.11
+ mpi2_type.h 02.00.00 02.00.00
+ mpi2_ra.h 02.00.00 02.00.00
+ mpi2_hbd.h 02.00.02 02.00.02
+ mpi2_history.txt 02.00.33 02.00.32
+
+
+ * Date Version Description
+ * -------- -------- ------------------------------------------------------
+
+mpi2.h
+ * 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.
+ * 05-06-09 02.00.12 Bumped MPI2_HEADER_VERSION_UNIT.
+ * In all request and reply descriptors, replaced VF_ID
+ * field with MSIxIndex field.
+ * Removed DevHandle field from
+ * MPI2_SCSI_IO_SUCCESS_REPLY_DESCRIPTOR and made those
+ * bytes reserved.
+ * Added RAID Accelerator functionality.
+ * 07-30-09 02.00.13 Bumped MPI2_HEADER_VERSION_UNIT.
+ * 10-28-09 02.00.14 Bumped MPI2_HEADER_VERSION_UNIT.
+ * Added MSI-x index mask and shift for Reply Post Host
+ * Index register.
+ * Added function code for Host Based Discovery Action.
+ * 02-10-10 02.00.15 Bumped MPI2_HEADER_VERSION_UNIT.
+ * Added define for MPI2_FUNCTION_PWR_MGMT_CONTROL.
+ * Added defines for product-specific range of message
+ * function codes, 0xF0 to 0xFF.
+ * 05-12-10 02.00.16 Bumped MPI2_HEADER_VERSION_UNIT.
+ * Added alternative defines for the SGE Direction bit.
+ * 08-11-10 02.00.17 Bumped MPI2_HEADER_VERSION_UNIT.
+ * 11-10-10 02.00.18 Bumped MPI2_HEADER_VERSION_UNIT.
+ * Added MPI2_IEEE_SGE_FLAGS_SYSTEMPLBCPI_ADDR define.
+ * 02-23-11 02.00.19 Bumped MPI2_HEADER_VERSION_UNIT.
+ * Added MPI2_FUNCTION_SEND_HOST_MESSAGE.
+ * 03-09-11 02.00.20 Bumped MPI2_HEADER_VERSION_UNIT.
+ * 05-25-11 02.00.21 Bumped MPI2_HEADER_VERSION_UNIT.
+ * 08-24-11 02.00.22 Bumped MPI2_HEADER_VERSION_UNIT.
+ * 11-18-11 02.00.23 Bumped MPI2_HEADER_VERSION_UNIT.
+ * Incorporating additions for MPI v2.5.
+ * 02-06-12 02.00.24 Bumped MPI2_HEADER_VERSION_UNIT.
+ * 03-29-12 02.00.25 Bumped MPI2_HEADER_VERSION_UNIT.
+ * Added Hard Reset delay timings.
+ * 07-10-12 02.00.26 Bumped MPI2_HEADER_VERSION_UNIT.
+ * 07-26-12 02.00.27 Bumped MPI2_HEADER_VERSION_UNIT.
+ * 11-27-12 02.00.28 Bumped MPI2_HEADER_VERSION_UNIT.
+ * 12-20-12 02.00.29 Bumped MPI2_HEADER_VERSION_UNIT.
+ * Added MPI25_SUP_REPLY_POST_HOST_INDEX_OFFSET.
+ * 04-09-13 02.00.30 Bumped MPI2_HEADER_VERSION_UNIT.
+ * 04-17-13 02.00.31 Bumped MPI2_HEADER_VERSION_UNIT.
+ * 08-19-13 02.00.32 Bumped MPI2_HEADER_VERSION_UNIT.
+ * 12-05-13 02.00.33 Bumped MPI2_HEADER_VERSION_UNIT.
+ * --------------------------------------------------------------------------
+
+mpi2_cnfg.h
+ * 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 SupportedPhysDisks field to RAID Volume Page 1 and
+ * added related defines.
+ * 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 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.
+ * 05-06-09 02.00.11 Added structures and defines for IO Unit Page 5 and IO
+ * Unit Page 6.
+ * Added expander reduced functionality data to SAS
+ * Expander Page 0.
+ * Added SAS PHY Page 2 and SAS PHY Page 3.
+ * 07-30-09 02.00.12 Added IO Unit Page 7.
+ * Added new device ids.
+ * Added SAS IO Unit Page 5.
+ * Added partial and slumber power management capable flags
+ * to SAS Device Page 0 Flags field.
+ * Added PhyInfo defines for power condition.
+ * Added Ethernet configuration pages.
+ * 10-28-09 02.00.13 Added MPI2_IOUNITPAGE1_ENABLE_HOST_BASED_DISCOVERY.
+ * Added SAS PHY Page 4 structure and defines.
+ * 02-10-10 02.00.14 Modified the comments for the configuration page
+ * structures that contain an array of data. The host
+ * should use the "count" field in the page data (e.g. the
+ * NumPhys field) to determine the number of valid elements
+ * in the array.
+ * Added/modified some MPI2_MFGPAGE_DEVID_SAS defines.
+ * Added PowerManagementCapabilities to IO Unit Page 7.
+ * Added PortWidthModGroup field to
+ * MPI2_SAS_IO_UNIT5_PHY_PM_SETTINGS.
+ * Added MPI2_CONFIG_PAGE_SASIOUNIT_6 and related defines.
+ * Added MPI2_CONFIG_PAGE_SASIOUNIT_7 and related defines.
+ * Added MPI2_CONFIG_PAGE_SASIOUNIT_8 and related defines.
+ * 05-12-10 02.00.15 Added MPI2_RAIDVOL0_STATUS_FLAG_VOL_NOT_CONSISTENT
+ * define.
+ * Added MPI2_PHYSDISK0_INCOMPATIBLE_MEDIA_TYPE define.
+ * Added MPI2_SAS_NEG_LINK_RATE_UNSUPPORTED_PHY define.
+ * 08-11-10 02.00.16 Removed IO Unit Page 1 device path (multi-pathing)
+ * defines.
+ * 11-10-10 02.00.17 Added ReceptacleID field (replacing Reserved1) to
+ * MPI2_MANPAGE7_CONNECTOR_INFO and reworked defines for
+ * the Pinout field.
+ * Added BoardTemperature and BoardTemperatureUnits fields
+ * to MPI2_CONFIG_PAGE_IO_UNIT_7.
+ * Added MPI2_CONFIG_EXTPAGETYPE_EXT_MANUFACTURING define
+ * and MPI2_CONFIG_PAGE_EXT_MAN_PS structure.
+ * 02-23-11 02.00.18 Added ProxyVF_ID field to MPI2_CONFIG_REQUEST.
+ * Added IO Unit Page 8, IO Unit Page 9,
+ * and IO Unit Page 10.
+ * Added SASNotifyPrimitiveMasks field to
+ * MPI2_CONFIG_PAGE_IOC_7.
+ * 03-09-11 02.00.19 Fixed IO Unit Page 10 (to match the spec).
+ * 05-25-11 02.00.20 Cleaned up a few comments.
+ * 08-24-11 02.00.21 Marked the IO Unit Page 7 PowerManagementCapabilities
+ * for PCIe link as obsolete.
+ * Added SpinupFlags field containing a Disable Spin-up bit
+ * to the MPI2_SAS_IOUNIT4_SPINUP_GROUP fields of SAS IO
+ * Unit Page 4.
+ * 11-18-11 02.00.22 Added define MPI2_IOCPAGE6_CAP_FLAGS_4K_SECTORS_SUPPORT.
+ * Added UEFIVersion field to BIOS Page 1 and defined new
+ * BiosOptions bits.
+ * Incorporating additions for MPI v2.5.
+ * 11-27-12 02.00.23 Added MPI2_MANPAGE7_FLAG_EVENTREPLAY_SLOT_ORDER.
+ * Added MPI2_BIOSPAGE1_OPTIONS_MASK_OEM_ID.
+ * 12-20-12 02.00.24 Marked MPI2_SASIOUNIT1_CONTROL_CLEAR_AFFILIATION as
+ * obsolete for MPI v2.5 and later.
+ * Added some defines for 12G SAS speeds.
+ * 04-09-13 02.00.25 Added MPI2_IOUNITPAGE1_ATA_SECURITY_FREEZE_LOCK.
+ * Fixed MPI2_IOUNITPAGE5_DMA_CAP_MASK_MAX_REQUESTS to
+ * match the specification.
+ * 08-19-13 02.00.26 Added reserved words to MPI2_CONFIG_PAGE_IO_UNIT_7 for
+ * future use.
+ * 12-05-13 02.00.27 Added MPI2_MANPAGE7_FLAG_BASE_ENCLOSURE_LEVEL for
+ * MPI2_CONFIG_PAGE_MAN_7.
+ * Added EnclosureLevel and ConnectorName fields to
+ * MPI2_CONFIG_PAGE_SAS_DEV_0.
+ * Added MPI2_SAS_DEVICE0_FLAGS_ENCL_LEVEL_VALID for
+ * MPI2_CONFIG_PAGE_SAS_DEV_0.
+ * Added EnclosureLevel field to
+ * MPI2_CONFIG_PAGE_SAS_ENCLOSURE_0.
+ * Added MPI2_SAS_ENCLS0_FLAGS_ENCL_LEVEL_VALID for
+ * MPI2_CONFIG_PAGE_SAS_ENCLOSURE_0.
+ * --------------------------------------------------------------------------
+
+mpi2_init.h
+ * 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.
+ * 05-06-09 02.00.07 Changed task management type of Query Unit Attention to
+ * Query Asynchronous Event.
+ * Defined two new bits in the SlotStatus field of the SCSI
+ * Enclosure Processor Request and Reply.
+ * 10-28-09 02.00.08 Added defines for decoding the ResponseInfo bytes for
+ * both SCSI IO Error Reply and SCSI Task Management Reply.
+ * Added ResponseInfo field to MPI2_SCSI_TASK_MANAGE_REPLY.
+ * Added MPI2_SCSITASKMGMT_RSP_TM_OVERLAPPED_TAG define.
+ * 02-10-10 02.00.09 Removed unused structure that had "#if 0" around it.
+ * 05-12-10 02.00.10 Added optional vendor-unique region to SCSI IO Request.
+ * 11-10-10 02.00.11 Added MPI2_SCSIIO_NUM_SGLOFFSETS define.
+ * 11-18-11 02.00.12 Incorporating additions for MPI v2.5.
+ * 02-06-12 02.00.13 Added alternate defines for Task Priority / Command
+ * Priority to match SAM-4.
+ * Added EEDPErrorOffset to MPI2_SCSI_IO_REPLY.
+ * 07-10-12 02.00.14 Added MPI2_SCSIIO_CONTROL_SHIFT_DATADIRECTION.
+ * --------------------------------------------------------------------------
+
+mpi2_ioc.h
+ * 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.
+ * 05-06-09 02.00.11 Added MPI2_IOCFACTS_CAPABILITY_RAID_ACCELERATOR define.
+ * Added MPI2_IOCFACTS_CAPABILITY_MSI_X_INDEX define.
+ * Added two new reason codes for SAS Device Status Change
+ * Event.
+ * Added new event: SAS PHY Counter.
+ * 07-30-09 02.00.12 Added GPIO Interrupt event define and structure.
+ * Added MPI2_IOCFACTS_CAPABILITY_EXTENDED_BUFFER define.
+ * Added new product id family for 2208.
+ * 10-28-09 02.00.13 Added HostMSIxVectors field to MPI2_IOC_INIT_REQUEST.
+ * Added MaxMSIxVectors field to MPI2_IOC_FACTS_REPLY.
+ * Added MinDevHandle field to MPI2_IOC_FACTS_REPLY.
+ * Added MPI2_IOCFACTS_CAPABILITY_HOST_BASED_DISCOVERY.
+ * Added MPI2_EVENT_HOST_BASED_DISCOVERY_PHY define.
+ * Added MPI2_EVENT_SAS_TOPO_ES_NO_EXPANDER define.
+ * Added Host Based Discovery Phy Event data.
+ * Added defines for ProductID Product field
+ * (MPI2_FW_HEADER_PID_).
+ * Modified values for SAS ProductID Family
+ * (MPI2_FW_HEADER_PID_FAMILY_).
+ * 02-10-10 02.00.14 Added SAS Quiesce Event structure and defines.
+ * Added PowerManagementControl Request structures and
+ * defines.
+ * 05-12-10 02.00.15 Marked Task Set Full Event as obsolete.
+ * Added MPI2_EVENT_SAS_TOPO_LR_UNSUPPORTED_PHY define.
+ * 11-10-10 02.00.16 Added MPI2_FW_DOWNLOAD_ITYPE_MIN_PRODUCT_SPECIFIC.
+ * 02-23-11 02.00.17 Added SAS NOTIFY Primitive event, and added
+ * SASNotifyPrimitiveMasks field to
+ * MPI2_EVENT_NOTIFICATION_REQUEST.
+ * Added Temperature Threshold Event.
+ * Added Host Message Event.
+ * Added Send Host Message request and reply.
+ * 05-25-11 02.00.18 For Extended Image Header, added
+ * MPI2_EXT_IMAGE_TYPE_MIN_PRODUCT_SPECIFIC and
+ * MPI2_EXT_IMAGE_TYPE_MAX_PRODUCT_SPECIFIC defines.
+ * Deprecated MPI2_EXT_IMAGE_TYPE_MAX define.
+ * 08-24-11 02.00.19 Added PhysicalPort field to
+ * MPI2_EVENT_DATA_SAS_DEVICE_STATUS_CHANGE structure.
+ * Marked MPI2_PM_CONTROL_FEATURE_PCIE_LINK as obsolete.
+ * 11-18-11 02.00.20 Incorporating additions for MPI v2.5.
+ * 03-29-12 02.00.21 Added a product specific range to event values.
+ * 07-26-12 02.00.22 Added MPI2_IOCFACTS_EXCEPT_PARTIAL_MEMORY_FAILURE.
+ * Added ElapsedSeconds field to
+ * MPI2_EVENT_DATA_IR_OPERATION_STATUS.
+ * 08-19-13 02.00.23 For IOCInit, added MPI2_IOCINIT_MSGFLAG_RDPQ_ARRAY_MODE
+ * and MPI2_IOC_INIT_RDPQ_ARRAY_ENTRY.
+ * Added MPI2_IOCFACTS_CAPABILITY_RDPQ_ARRAY_CAPABLE.
+ * Added MPI2_FW_DOWNLOAD_ITYPE_PUBLIC_KEY.
+ * Added Encrypted Hash Extended Image.
+ * 12-05-13 02.00.24 Added MPI25_HASH_IMAGE_TYPE_BIOS.
+ * --------------------------------------------------------------------------
+
+mpi2_raid.h
+ * 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.
+ * 07-30-09 02.00.04 Added proper define for the Use Default Settings bit of
+ * VolumeCreationFlags and marked the old one as obsolete.
+ * 05-12-10 02.00.05 Added MPI2_RAID_VOL_FLAGS_OP_MDC define.
+ * 08-24-10 02.00.06 Added MPI2_RAID_ACTION_COMPATIBILITY_CHECK along with
+ * related structures and defines.
+ * Added product-specific range to RAID Action values.
+ * 11-18-11 02.00.07 Incorporating additions for MPI v2.5.
+ * 02-06-12 02.00.08 Added MPI2_RAID_ACTION_PHYSDISK_HIDDEN.
+ * 07-26-12 02.00.09 Added ElapsedSeconds field to MPI2_RAID_VOL_INDICATOR.
+ * Added MPI2_RAID_VOL_FLAGS_ELAPSED_SECONDS_VALID define.
+ * 04-17-13 02.00.10 Added MPI25_RAID_ACTION_ADATA_ALLOW_PI.
+ * --------------------------------------------------------------------------
+
+mpi2_sas.h
+ * 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.
+ * 10-28-09 02.00.03 Changed the type of SGL in MPI2_SATA_PASSTHROUGH_REQUEST
+ * to MPI2_SGE_IO_UNION since it supports chained SGLs.
+ * 05-12-10 02.00.04 Modified some comments.
+ * 08-11-10 02.00.05 Added NCQ operations to SAS IO Unit Control.
+ * 11-18-11 02.00.06 Incorporating additions for MPI v2.5.
+ * 07-10-12 02.00.07 Added MPI2_SATA_PT_SGE_UNION for use in the SATA
+ * Passthrough Request message.
+ * 08-19-13 02.00.08 Made MPI2_SAS_OP_TRANSMIT_PORT_SELECT_SIGNAL obsolete
+ * for anything newer than MPI v2.0.
+ * --------------------------------------------------------------------------
+
+mpi2_targ.h
+ * 04-30-07 02.00.00 Corresponds to Fusion-MPT MPI Specification Rev A.
+ * 08-31-07 02.00.01 Added Command Buffer Data Location Address Space bits to
+ * BufferPostFlags field of CommandBufferPostBase Request.
+ * 02-29-08 02.00.02 Modified various names to make them 32-character unique.
+ * 10-02-08 02.00.03 Removed NextCmdBufferOffset from
+ * MPI2_TARGET_CMD_BUF_POST_BASE_REQUEST.
+ * Target Status Send Request only takes a single SGE for
+ * response data.
+ * 02-10-10 02.00.04 Added comment to MPI2_TARGET_SSP_RSP_IU structure.
+ * 11-18-11 02.00.05 Incorporating additions for MPI v2.5.
+ * 11-27-12 02.00.06 Added InitiatorDevHandle field to MPI2_TARGET_MODE_ABORT
+ * request message structure.
+ * Added AbortType MPI2_TARGET_MODE_ABORT_DEVHANDLE and
+ * MPI2_TARGET_MODE_ABORT_ALL_COMMANDS.
+ * --------------------------------------------------------------------------
+
+mpi2_tool.h
+ * 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.
+ * 05-06-09 02.00.03 Added ISTWI Read Write Tool and Diagnostic CLI Tool.
+ * 07-30-09 02.00.04 Added ExtendedType field to DiagnosticBufferPost request
+ * and reply messages.
+ * Added MPI2_DIAG_BUF_TYPE_EXTENDED.
+ * Incremented MPI2_DIAG_BUF_TYPE_COUNT.
+ * 05-12-10 02.00.05 Added Diagnostic Data Upload tool.
+ * 08-11-10 02.00.06 Added defines that were missing for Diagnostic Buffer
+ * Post Request.
+ * 05-25-11 02.00.07 Added Flags field and related defines to
+ * MPI2_TOOLBOX_ISTWI_READ_WRITE_REQUEST.
+ * 11-18-11 02.00.08 Incorporating additions for MPI v2.5.
+ * 07-10-12 02.00.09 Add MPI v2.5 Toolbox Diagnostic CLI Tool Request
+ * message.
+ * 07-26-12 02.00.10 Modified MPI2_TOOLBOX_DIAGNOSTIC_CLI_REQUEST so that
+ * it uses MPI Chain SGE as well as MPI Simple SGE.
+ * 08-19-13 02.00.11 Added MPI2_TOOLBOX_TEXT_DISPLAY_TOOL and related info.
+ * --------------------------------------------------------------------------
+
+mpi2_type.h
+ * 04-30-07 02.00.00 Corresponds to Fusion-MPT MPI Specification Rev A.
+ * --------------------------------------------------------------------------
+
+mpi2_ra.h
+ * 05-06-09 02.00.00 Initial version.
+ * --------------------------------------------------------------------------
+
+mpi2_hbd.h
+ * 10-28-09 02.00.00 Initial version.
+ * 08-11-10 02.00.01 Removed PortGroups, DmaGroup, and ControlGroup from
+ * HBD Action request, replaced by AdditionalInfo field.
+ * 11-18-11 02.00.02 Incorporating additions for MPI v2.5.
+ * --------------------------------------------------------------------------
+
+
+mpi2_history.txt Parts list history
+
+Filename 02.00.33 02.00.32 02.00.31 02.00.30
+---------- -------- -------- -------- --------
+mpi2.h 02.00.33 02.00.32 02.00.31 02.00.30
+mpi2_cnfg.h 02.00.27 02.00.26 02.00.25 02.00.25
+mpi2_init.h 02.00.15 02.00.15 02.00.15 02.00.15
+mpi2_ioc.h 02.00.24 02.00.23 02.00.22 02.00.22
+mpi2_raid.h 02.00.10 02.00.10 02.00.10 02.00.09
+mpi2_sas.h 02.00.08 02.00.08 02.00.07 02.00.07
+mpi2_targ.h 02.00.06 02.00.06 02.00.06 02.00.06
+mpi2_tool.h 02.00.11 02.00.11 02.00.10 02.00.10
+mpi2_type.h 02.00.00 02.00.00 02.00.00 02.00.00
+mpi2_ra.h 02.00.00 02.00.00 02.00.00 02.00.00
+mpi2_hbd.h 02.00.02 02.00.02 02.00.02 02.00.02
+
+Filename 02.00.29 02.00.28 02.00.27 02.00.26 02.00.25 02.00.24
+---------- -------- -------- -------- -------- -------- --------
+mpi2.h 02.00.29 02.00.28 02.00.27 02.00.26 02.00.25 02.00.24
+mpi2_cnfg.h 02.00.24 02.00.23 02.00.22 02.00.22 02.00.22 02.00.22
+mpi2_init.h 02.00.14 02.00.14 02.00.14 02.00.14 02.00.13 02.00.13
+mpi2_ioc.h 02.00.22 02.00.22 02.00.22 02.00.21 02.00.21 02.00.20
+mpi2_raid.h 02.00.09 02.00.09 02.00.09 02.00.08 02.00.08 02.00.08
+mpi2_sas.h 02.00.07 02.00.07 02.00.07 02.00.07 02.00.06 02.00.06
+mpi2_targ.h 02.00.06 02.00.06 02.00.05 02.00.05 02.00.05 02.00.05
+mpi2_tool.h 02.00.10 02.00.10 02.00.10 02.00.09 02.00.08 02.00.08
+mpi2_type.h 02.00.00 02.00.00 02.00.00 02.00.00 02.00.00 02.00.00
+mpi2_ra.h 02.00.00 02.00.00 02.00.00 02.00.00 02.00.00 02.00.00
+mpi2_hbd.h 02.00.02 02.00.02 02.00.02 02.00.02 02.00.02 02.00.02
+
+Filename 02.00.23 02.00.22 02.00.21 02.00.20 02.00.19 02.00.18
+---------- -------- -------- -------- -------- -------- --------
+mpi2.h 02.00.23 02.00.22 02.00.21 02.00.20 02.00.19 02.00.18
+mpi2_cnfg.h 02.00.22 02.00.21 02.00.20 02.00.19 02.00.18 02.00.17
+mpi2_init.h 02.00.12 02.00.11 02.00.11 02.00.11 02.00.11 02.00.11
+mpi2_ioc.h 02.00.20 02.00.19 02.00.18 02.00.17 02.00.17 02.00.16
+mpi2_raid.h 02.00.07 02.00.06 02.00.05 02.00.05 02.00.05 02.00.05
+mpi2_sas.h 02.00.06 02.00.05 02.00.05 02.00.05 02.00.05 02.00.05
+mpi2_targ.h 02.00.05 02.00.04 02.00.04 02.00.04 02.00.04 02.00.04
+mpi2_tool.h 02.00.08 02.00.07 02.00.07 02.00.06 02.00.06 02.00.06
+mpi2_type.h 02.00.00 02.00.00 02.00.00 02.00.00 02.00.00 02.00.00
+mpi2_ra.h 02.00.00 02.00.00 02.00.00 02.00.00 02.00.00 02.00.00
+mpi2_hbd.h 02.00.02 02.00.01 02.00.01 02.00.01 02.00.01 02.00.01
+
+Filename 02.00.17 02.00.16 02.00.15 02.00.14 02.00.13 02.00.12
+---------- -------- -------- -------- -------- -------- --------
+mpi2.h 02.00.17 02.00.16 02.00.15 02.00.14 02.00.13 02.00.12
+mpi2_cnfg.h 02.00.16 02.00.15 02.00.14 02.00.13 02.00.12 02.00.11
+mpi2_init.h 02.00.10 02.00.10 02.00.09 02.00.08 02.00.07 02.00.07
+mpi2_ioc.h 02.00.15 02.00.15 02.00.14 02.00.13 02.00.12 02.00.11
+mpi2_raid.h 02.00.05 02.00.05 02.00.04 02.00.04 02.00.04 02.00.03
+mpi2_sas.h 02.00.05 02.00.04 02.00.03 02.00.03 02.00.02 02.00.02
+mpi2_targ.h 02.00.04 02.00.04 02.00.04 02.00.03 02.00.03 02.00.03
+mpi2_tool.h 02.00.06 02.00.05 02.00.04 02.00.04 02.00.04 02.00.03
+mpi2_type.h 02.00.00 02.00.00 02.00.00 02.00.00 02.00.00 02.00.00
+mpi2_ra.h 02.00.00 02.00.00 02.00.00 02.00.00 02.00.00 02.00.00
+mpi2_hbd.h 02.00.01 02.00.00 02.00.00 02.00.00
+
+Filename 02.00.11 02.00.10 02.00.09 02.00.08 02.00.07 02.00.06
+---------- -------- -------- -------- -------- -------- --------
+mpi2.h 02.00.11 02.00.10 02.00.09 02.00.08 02.00.07 02.00.06
+mpi2_cnfg.h 02.00.10 02.00.09 02.00.08 02.00.07 02.00.06 02.00.06
+mpi2_init.h 02.00.06 02.00.06 02.00.05 02.00.05 02.00.04 02.00.03
+mpi2_ioc.h 02.00.10 02.00.09 02.00.08 02.00.07 02.00.07 02.00.06
+mpi2_raid.h 02.00.03 02.00.03 02.00.03 02.00.03 02.00.02 02.00.02
+mpi2_sas.h 02.00.02 02.00.02 02.00.01 02.00.01 02.00.01 02.00.01
+mpi2_targ.h 02.00.03 02.00.03 02.00.02 02.00.02 02.00.02 02.00.02
+mpi2_tool.h 02.00.02 02.00.02 02.00.02 02.00.02 02.00.02 02.00.02
+mpi2_type.h 02.00.00 02.00.00 02.00.00 02.00.00 02.00.00 02.00.00
+
+Filename 02.00.05 02.00.04 02.00.03 02.00.02 02.00.01 02.00.00
+---------- -------- -------- -------- -------- -------- --------
+mpi2.h 02.00.05 02.00.04 02.00.03 02.00.02 02.00.01 02.00.00
+mpi2_cnfg.h 02.00.05 02.00.04 02.00.03 02.00.02 02.00.01 02.00.00
+mpi2_init.h 02.00.02 02.00.01 02.00.00 02.00.00 02.00.00 02.00.00
+mpi2_ioc.h 02.00.05 02.00.04 02.00.03 02.00.02 02.00.01 02.00.00
+mpi2_raid.h 02.00.01 02.00.01 02.00.01 02.00.00 02.00.00 02.00.00
+mpi2_sas.h 02.00.01 02.00.01 02.00.01 02.00.01 02.00.00 02.00.00
+mpi2_targ.h 02.00.01 02.00.01 02.00.01 02.00.00 02.00.00 02.00.00
+mpi2_tool.h 02.00.01 02.00.00 02.00.00 02.00.00 02.00.00 02.00.00
+mpi2_type.h 02.00.00 02.00.00 02.00.00 02.00.00 02.00.00 02.00.00
+
diff --git a/sys/dev/mpr/mpi/mpi2_init.h b/sys/dev/mpr/mpi/mpi2_init.h
new file mode 100644
index 0000000..62b0cfe
--- /dev/null
+++ b/sys/dev/mpr/mpi/mpi2_init.h
@@ -0,0 +1,614 @@
+/*-
+ * Copyright (c) 2013 LSI Corp.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the author nor the names of any co-contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * LSI MPT-Fusion Host Adapter FreeBSD
+ *
+ * $FreeBSD$
+ */
+
+/*
+ * Copyright (c) 2000-2013 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.15
+ *
+ * NOTE: Names (typedefs, defines, etc.) beginning with an MPI25 or Mpi25
+ * prefix are for use only on MPI v2.5 products, and must not be used
+ * with MPI v2.0 products. Unless otherwise noted, names beginning with
+ * MPI2 or Mpi2 are for use with both MPI v2.0 and MPI v2.5 products.
+ *
+ * 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.
+ * 05-06-09 02.00.07 Changed task management type of Query Unit Attention to
+ * Query Asynchronous Event.
+ * Defined two new bits in the SlotStatus field of the SCSI
+ * Enclosure Processor Request and Reply.
+ * 10-28-09 02.00.08 Added defines for decoding the ResponseInfo bytes for
+ * both SCSI IO Error Reply and SCSI Task Management Reply.
+ * Added ResponseInfo field to MPI2_SCSI_TASK_MANAGE_REPLY.
+ * Added MPI2_SCSITASKMGMT_RSP_TM_OVERLAPPED_TAG define.
+ * 02-10-10 02.00.09 Removed unused structure that had "#if 0" around it.
+ * 05-12-10 02.00.10 Added optional vendor-unique region to SCSI IO Request.
+ * 11-10-10 02.00.11 Added MPI2_SCSIIO_NUM_SGLOFFSETS define.
+ * 11-18-11 02.00.12 Incorporating additions for MPI v2.5.
+ * 02-06-12 02.00.13 Added alternate defines for Task Priority / Command
+ * Priority to match SAM-4.
+ * Added EEDPErrorOffset to MPI2_SCSI_IO_REPLY.
+ * 07-10-12 02.00.14 Added MPI2_SCSIIO_CONTROL_SHIFT_DATADIRECTION.
+ * 04-09-13 02.00.15 Added SCSIStatusQualifier field to MPI2_SCSI_IO_REPLY,
+ * replacing the Reserved4 field.
+ * --------------------------------------------------------------------------
+ */
+
+#ifndef MPI2_INIT_H
+#define MPI2_INIT_H
+
+/*****************************************************************************
+*
+* SCSI Initiator Messages
+*
+*****************************************************************************/
+
+/****************************************************************************
+* SCSI IO messages and associated structures
+****************************************************************************/
+
+typedef struct _MPI2_SCSI_IO_CDB_EEDP32
+{
+ 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;
+
+/* MPI v2.0 CDB field */
+typedef union _MPI2_SCSI_IO_CDB_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;
+
+/* MPI v2.0 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 */
+
+#ifdef MPI2_SCSI_IO_VENDOR_UNIQUE_REGION /* typically this is left undefined */
+ MPI2_SCSI_IO_VENDOR_UNIQUE VendorRegion;
+#endif
+
+ MPI2_SGE_IO_UNION SGL; /* 0x60 */
+
+} MPI2_SCSI_IO_REQUEST, MPI2_POINTER PTR_MPI2_SCSI_IO_REQUEST,
+ Mpi2SCSIIORequest_t, MPI2_POINTER pMpi2SCSIIORequest_t;
+
+/* 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)
+
+/* number of SGLOffset fields */
+#define MPI2_SCSIIO_NUM_SGLOFFSETS (4)
+
+/* 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_SHIFT_DATADIRECTION (24)
+#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)
+/* alternate name for the previous field; called Command Priority in SAM-4 */
+#define MPI2_SCSIIO_CONTROL_CMDPRI_MASK (0x00007800)
+#define MPI2_SCSIIO_CONTROL_CMDPRI_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)
+
+
+/* MPI v2.5 CDB field */
+typedef union _MPI25_SCSI_IO_CDB_UNION
+{
+ U8 CDB32[32];
+ MPI2_SCSI_IO_CDB_EEDP32 EEDP32;
+ MPI2_IEEE_SGE_SIMPLE64 SGE;
+} MPI25_SCSI_IO_CDB_UNION, MPI2_POINTER PTR_MPI25_SCSI_IO_CDB_UNION,
+ Mpi25ScsiIoCdb_t, MPI2_POINTER pMpi25ScsiIoCdb_t;
+
+/* MPI v2.5 SCSI IO Request Message */
+typedef struct _MPI25_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 */
+ U8 DMAFlags; /* 0x10 */
+ U8 Reserved5; /* 0x11 */
+ 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 */
+ U16 EEDPBlockSize; /* 0x28 */
+ U16 Reserved6; /* 0x2A */
+ U32 SecondaryReferenceTag; /* 0x2C */
+ U16 SecondaryApplicationTag; /* 0x30 */
+ U16 ApplicationTagTranslationMask; /* 0x32 */
+ U8 LUN[8]; /* 0x34 */
+ U32 Control; /* 0x3C */
+ MPI25_SCSI_IO_CDB_UNION CDB; /* 0x40 */
+
+#ifdef MPI25_SCSI_IO_VENDOR_UNIQUE_REGION /* typically this is left undefined */
+ MPI25_SCSI_IO_VENDOR_UNIQUE VendorRegion;
+#endif
+
+ MPI25_SGE_IO_UNION SGL; /* 0x60 */
+
+} MPI25_SCSI_IO_REQUEST, MPI2_POINTER PTR_MPI25_SCSI_IO_REQUEST,
+ Mpi25SCSIIORequest_t, MPI2_POINTER pMpi25SCSIIORequest_t;
+
+/* use MPI2_SCSIIO_MSGFLAGS_ defines for the MsgFlags field */
+
+/* Defines for the DMAFlags field
+ * Each setting affects 4 SGLS, from SGL0 to SGL3.
+ * D = Data
+ * C = Cache DIF
+ * I = Interleaved
+ * H = Host DIF
+ */
+#define MPI25_SCSIIO_DMAFLAGS_OP_MASK (0x0F)
+#define MPI25_SCSIIO_DMAFLAGS_OP_D_D_D_D (0x00)
+#define MPI25_SCSIIO_DMAFLAGS_OP_D_D_D_C (0x01)
+#define MPI25_SCSIIO_DMAFLAGS_OP_D_D_D_I (0x02)
+#define MPI25_SCSIIO_DMAFLAGS_OP_D_D_C_C (0x03)
+#define MPI25_SCSIIO_DMAFLAGS_OP_D_D_C_I (0x04)
+#define MPI25_SCSIIO_DMAFLAGS_OP_D_D_I_I (0x05)
+#define MPI25_SCSIIO_DMAFLAGS_OP_D_C_C_C (0x06)
+#define MPI25_SCSIIO_DMAFLAGS_OP_D_C_C_I (0x07)
+#define MPI25_SCSIIO_DMAFLAGS_OP_D_C_I_I (0x08)
+#define MPI25_SCSIIO_DMAFLAGS_OP_D_I_I_I (0x09)
+#define MPI25_SCSIIO_DMAFLAGS_OP_D_H_D_D (0x0A)
+#define MPI25_SCSIIO_DMAFLAGS_OP_D_H_D_C (0x0B)
+#define MPI25_SCSIIO_DMAFLAGS_OP_D_H_D_I (0x0C)
+#define MPI25_SCSIIO_DMAFLAGS_OP_D_H_C_C (0x0D)
+#define MPI25_SCSIIO_DMAFLAGS_OP_D_H_C_I (0x0E)
+#define MPI25_SCSIIO_DMAFLAGS_OP_D_H_I_I (0x0F)
+
+/* number of SGLOffset fields */
+#define MPI25_SCSIIO_NUM_SGLOFFSETS (4)
+
+/* defines for the IoFlags field */
+#define MPI25_SCSIIO_IOFLAGS_IO_PATH_MASK (0xC000)
+#define MPI25_SCSIIO_IOFLAGS_NORMAL_PATH (0x0000)
+#define MPI25_SCSIIO_IOFLAGS_FAST_PATH (0x4000)
+
+#define MPI25_SCSIIO_IOFLAGS_LARGE_CDB (0x1000)
+#define MPI25_SCSIIO_IOFLAGS_BIDIRECTIONAL (0x0800)
+#define MPI25_SCSIIO_IOFLAGS_CDBLENGTH_MASK (0x01FF)
+
+/* MPI v2.5 defines for the EEDPFlags bits */
+/* use MPI2_SCSIIO_EEDPFLAGS_ defines for the other EEDPFlags bits */
+#define MPI25_SCSIIO_EEDPFLAGS_ESCAPE_MODE_MASK (0x00C0)
+#define MPI25_SCSIIO_EEDPFLAGS_COMPATIBLE_MODE (0x0000)
+#define MPI25_SCSIIO_EEDPFLAGS_DO_NOT_DISABLE_MODE (0x0040)
+#define MPI25_SCSIIO_EEDPFLAGS_APPTAG_DISABLE_MODE (0x0080)
+#define MPI25_SCSIIO_EEDPFLAGS_APPTAG_REFTAG_DISABLE_MODE (0x00C0)
+
+#define MPI25_SCSIIO_EEDPFLAGS_HOST_GUARD_METHOD_MASK (0x0030)
+#define MPI25_SCSIIO_EEDPFLAGS_T10_CRC_HOST_GUARD (0x0000)
+#define MPI25_SCSIIO_EEDPFLAGS_IP_CHKSUM_HOST_GUARD (0x0010)
+
+/* use MPI2_LUN_ defines from mpi2.h for the LUN field */
+
+/* use MPI2_SCSIIO_CONTROL_ defines for the Control field */
+
+
+/* NOTE: The SCSI IO Reply is nearly the same for MPI 2.0 and MPI 2.5, so
+ * MPI2_SCSI_IO_REPLY is used for both.
+ */
+
+/* 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 SCSIStatusQualifier; /* 0x22 */
+ U32 BidirectionalTransferCount; /* 0x24 */
+ U32 EEDPErrorOffset; /* 0x28 */ /* MPI 2.5 only; Reserved in MPI 2.0 */
+ 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)
+
+/* masks and shifts for the ResponseInfo field */
+
+#define MPI2_SCSI_RI_MASK_REASONCODE (0x000000FF)
+#define MPI2_SCSI_RI_SHIFT_REASONCODE (0)
+
+#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_ASYNC_EVENT (0x0A)
+
+/* obsolete TaskType name */
+#define MPI2_SCSITASKMGMT_TASKTYPE_QRY_UNIT_ATTENTION (MPI2_SCSITASKMGMT_TASKTYPE_QRY_ASYNC_EVENT)
+
+/* 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 */
+ U32 ResponseInfo; /* 0x18 */
+} 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_TM_OVERLAPPED_TAG (0x0A)
+#define MPI2_SCSITASKMGMT_RSP_IO_QUEUED_ON_IOC (0x80)
+
+/* masks and shifts for the ResponseInfo field */
+
+#define MPI2_SCSITASKMGMT_RI_MASK_REASONCODE (0x000000FF)
+#define MPI2_SCSITASKMGMT_RI_SHIFT_REASONCODE (0)
+#define MPI2_SCSITASKMGMT_RI_MASK_ARI2 (0x0000FF00)
+#define MPI2_SCSITASKMGMT_RI_SHIFT_ARI2 (8)
+#define MPI2_SCSITASKMGMT_RI_MASK_ARI1 (0x00FF0000)
+#define MPI2_SCSITASKMGMT_RI_SHIFT_ARI1 (16)
+#define MPI2_SCSITASKMGMT_RI_MASK_ARI0 (0xFF000000)
+#define MPI2_SCSITASKMGMT_RI_SHIFT_ARI0 (24)
+
+
+/****************************************************************************
+* 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_IN_CRITICAL_ARRAY (0x00000010)
+#define MPI2_SEP_REQ_SLOTSTATUS_IN_FAILED_ARRAY (0x00000008)
+#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_IN_CRITICAL_ARRAY (0x00000010)
+#define MPI2_SEP_REPLY_SLOTSTATUS_IN_FAILED_ARRAY (0x00000008)
+#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/sys/dev/mpr/mpi/mpi2_ioc.h b/sys/dev/mpr/mpi/mpi2_ioc.h
new file mode 100644
index 0000000..38a46f5
--- /dev/null
+++ b/sys/dev/mpr/mpi/mpi2_ioc.h
@@ -0,0 +1,1856 @@
+/*-
+ * Copyright (c) 2013 LSI Corp.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the author nor the names of any co-contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * LSI MPT-Fusion Host Adapter FreeBSD
+ *
+ * $FreeBSD$
+ */
+
+/*
+ * Copyright (c) 2000-2013 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.24
+ *
+ * NOTE: Names (typedefs, defines, etc.) beginning with an MPI25 or Mpi25
+ * prefix are for use only on MPI v2.5 products, and must not be used
+ * with MPI v2.0 products. Unless otherwise noted, names beginning with
+ * MPI2 or Mpi2 are for use with both MPI v2.0 and MPI v2.5 products.
+ *
+ * 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.
+ * 05-06-09 02.00.11 Added MPI2_IOCFACTS_CAPABILITY_RAID_ACCELERATOR define.
+ * Added MPI2_IOCFACTS_CAPABILITY_MSI_X_INDEX define.
+ * Added two new reason codes for SAS Device Status Change
+ * Event.
+ * Added new event: SAS PHY Counter.
+ * 07-30-09 02.00.12 Added GPIO Interrupt event define and structure.
+ * Added MPI2_IOCFACTS_CAPABILITY_EXTENDED_BUFFER define.
+ * Added new product id family for 2208.
+ * 10-28-09 02.00.13 Added HostMSIxVectors field to MPI2_IOC_INIT_REQUEST.
+ * Added MaxMSIxVectors field to MPI2_IOC_FACTS_REPLY.
+ * Added MinDevHandle field to MPI2_IOC_FACTS_REPLY.
+ * Added MPI2_IOCFACTS_CAPABILITY_HOST_BASED_DISCOVERY.
+ * Added MPI2_EVENT_HOST_BASED_DISCOVERY_PHY define.
+ * Added MPI2_EVENT_SAS_TOPO_ES_NO_EXPANDER define.
+ * Added Host Based Discovery Phy Event data.
+ * Added defines for ProductID Product field
+ * (MPI2_FW_HEADER_PID_).
+ * Modified values for SAS ProductID Family
+ * (MPI2_FW_HEADER_PID_FAMILY_).
+ * 02-10-10 02.00.14 Added SAS Quiesce Event structure and defines.
+ * Added PowerManagementControl Request structures and
+ * defines.
+ * 05-12-10 02.00.15 Marked Task Set Full Event as obsolete.
+ * Added MPI2_EVENT_SAS_TOPO_LR_UNSUPPORTED_PHY define.
+ * 11-10-10 02.00.16 Added MPI2_FW_DOWNLOAD_ITYPE_MIN_PRODUCT_SPECIFIC.
+ * 02-23-11 02.00.17 Added SAS NOTIFY Primitive event, and added
+ * SASNotifyPrimitiveMasks field to
+ * MPI2_EVENT_NOTIFICATION_REQUEST.
+ * Added Temperature Threshold Event.
+ * Added Host Message Event.
+ * Added Send Host Message request and reply.
+ * 05-25-11 02.00.18 For Extended Image Header, added
+ * MPI2_EXT_IMAGE_TYPE_MIN_PRODUCT_SPECIFIC and
+ * MPI2_EXT_IMAGE_TYPE_MAX_PRODUCT_SPECIFIC defines.
+ * Deprecated MPI2_EXT_IMAGE_TYPE_MAX define.
+ * 08-24-11 02.00.19 Added PhysicalPort field to
+ * MPI2_EVENT_DATA_SAS_DEVICE_STATUS_CHANGE structure.
+ * Marked MPI2_PM_CONTROL_FEATURE_PCIE_LINK as obsolete.
+ * 11-18-11 02.00.20 Incorporating additions for MPI v2.5.
+ * 03-29-12 02.00.21 Added a product specific range to event values.
+ * 07-26-12 02.00.22 Added MPI2_IOCFACTS_EXCEPT_PARTIAL_MEMORY_FAILURE.
+ * Added ElapsedSeconds field to
+ * MPI2_EVENT_DATA_IR_OPERATION_STATUS.
+ * 08-19-13 02.00.23 For IOCInit, added MPI2_IOCINIT_MSGFLAG_RDPQ_ARRAY_MODE
+ * and MPI2_IOC_INIT_RDPQ_ARRAY_ENTRY.
+ * Added MPI2_IOCFACTS_CAPABILITY_RDPQ_ARRAY_CAPABLE.
+ * Added MPI2_FW_DOWNLOAD_ITYPE_PUBLIC_KEY.
+ * Added Encrypted Hash Extended Image.
+ * 12-05-13 02.00.24 Added MPI25_HASH_IMAGE_TYPE_BIOS.
+ * --------------------------------------------------------------------------
+ */
+
+#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 */
+ U16 Reserved6; /* 0x14 */
+ U8 Reserved7; /* 0x16 */
+ U8 HostMSIxVectors; /* 0x17 */
+ U16 Reserved8; /* 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)
+
+/* MsgFlags */
+#define MPI2_IOCINIT_MSGFLAG_RDPQ_ARRAY_MODE (0x01)
+
+/* 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 a Reply Descriptor Post Queue */
+#define MPI2_RDPQ_DEPTH_MIN (16)
+
+/* Reply Descriptor Post Queue Array Entry */
+typedef struct _MPI2_IOC_INIT_RDPQ_ARRAY_ENTRY
+{
+ U64 RDPQBaseAddress; /* 0x00 */
+ U32 Reserved1; /* 0x08 */
+ U32 Reserved2; /* 0x0C */
+} MPI2_IOC_INIT_RDPQ_ARRAY_ENTRY,
+ MPI2_POINTER PTR_MPI2_IOC_INIT_RDPQ_ARRAY_ENTRY,
+ Mpi2IOCInitRDPQArrayEntry, MPI2_POINTER pMpi2IOCInitRDPQArrayEntry;
+
+/* 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 MaxMSIxVectors; /* 0x17 */
+ U16 RequestCredit; /* 0x18 */
+ U16 ProductID; /* 0x1A */
+ U32 IOCCapabilities; /* 0x1C */
+ MPI2_VERSION_UNION FWVersion; /* 0x20 */
+ U16 IOCRequestFrameSize; /* 0x24 */
+ U16 IOCMaxChainSegmentSize; /* 0x26 */ /* MPI 2.5 only; Reserved in MPI 2.0 */
+ 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 */
+ U16 MinDevHandle; /* 0x3C */
+ U16 Reserved4; /* 0x3E */
+} 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_PARTIAL_MEMORY_FAILURE (0x0200)
+#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_RDPQ_ARRAY_CAPABLE (0x00040000)
+#define MPI25_IOCFACTS_CAPABILITY_FAST_PATH_CAPABLE (0x00020000)
+#define MPI2_IOCFACTS_CAPABILITY_HOST_BASED_DISCOVERY (0x00010000)
+#define MPI2_IOCFACTS_CAPABILITY_MSI_X_INDEX (0x00008000)
+#define MPI2_IOCFACTS_CAPABILITY_RAID_ACCELERATOR (0x00004000)
+#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_EXTENDED_BUFFER (0x00000020)
+#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 SASNotifyPrimitiveMasks; /* 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) /* obsolete */
+#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)
+#define MPI2_EVENT_SAS_PHY_COUNTER (0x0022)
+#define MPI2_EVENT_GPIO_INTERRUPT (0x0023)
+#define MPI2_EVENT_HOST_BASED_DISCOVERY_PHY (0x0024)
+#define MPI2_EVENT_SAS_QUIESCE (0x0025)
+#define MPI2_EVENT_SAS_NOTIFY_PRIMITIVE (0x0026)
+#define MPI2_EVENT_TEMP_THRESHOLD (0x0027)
+#define MPI2_EVENT_HOST_MESSAGE (0x0028)
+#define MPI2_EVENT_POWER_PERFORMANCE_CHANGE (0x0029)
+#define MPI2_EVENT_MIN_PRODUCT_SPECIFIC (0x006E)
+#define MPI2_EVENT_MAX_PRODUCT_SPECIFIC (0x007F)
+
+
+/* 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;
+
+
+/* GPIO Interrupt Event data */
+
+typedef struct _MPI2_EVENT_DATA_GPIO_INTERRUPT
+{
+ U8 GPIONum; /* 0x00 */
+ U8 Reserved1; /* 0x01 */
+ U16 Reserved2; /* 0x02 */
+} MPI2_EVENT_DATA_GPIO_INTERRUPT,
+ MPI2_POINTER PTR_MPI2_EVENT_DATA_GPIO_INTERRUPT,
+ Mpi2EventDataGpioInterrupt_t, MPI2_POINTER pMpi2EventDataGpioInterrupt_t;
+
+
+/* Temperature Threshold Event data */
+
+typedef struct _MPI2_EVENT_DATA_TEMPERATURE
+{
+ U16 Status; /* 0x00 */
+ U8 SensorNum; /* 0x02 */
+ U8 Reserved1; /* 0x03 */
+ U16 CurrentTemperature; /* 0x04 */
+ U16 Reserved2; /* 0x06 */
+ U32 Reserved3; /* 0x08 */
+ U32 Reserved4; /* 0x0C */
+} MPI2_EVENT_DATA_TEMPERATURE,
+ MPI2_POINTER PTR_MPI2_EVENT_DATA_TEMPERATURE,
+ Mpi2EventDataTemperature_t, MPI2_POINTER pMpi2EventDataTemperature_t;
+
+/* Temperature Threshold Event data Status bits */
+#define MPI2_EVENT_TEMPERATURE3_EXCEEDED (0x0008)
+#define MPI2_EVENT_TEMPERATURE2_EXCEEDED (0x0004)
+#define MPI2_EVENT_TEMPERATURE1_EXCEEDED (0x0002)
+#define MPI2_EVENT_TEMPERATURE0_EXCEEDED (0x0001)
+
+
+/* Host Message Event data */
+
+typedef struct _MPI2_EVENT_DATA_HOST_MESSAGE
+{
+ U8 SourceVF_ID; /* 0x00 */
+ U8 Reserved1; /* 0x01 */
+ U16 Reserved2; /* 0x02 */
+ U32 Reserved3; /* 0x04 */
+ U32 HostData[1]; /* 0x08 */
+} MPI2_EVENT_DATA_HOST_MESSAGE, MPI2_POINTER PTR_MPI2_EVENT_DATA_HOST_MESSAGE,
+ Mpi2EventDataHostMessage_t, MPI2_POINTER pMpi2EventDataHostMessage_t;
+
+
+/* Power Performance Change Event */
+
+typedef struct _MPI2_EVENT_DATA_POWER_PERF_CHANGE
+{
+ U8 CurrentPowerMode; /* 0x00 */
+ U8 PreviousPowerMode; /* 0x01 */
+ U16 Reserved1; /* 0x02 */
+} MPI2_EVENT_DATA_POWER_PERF_CHANGE,
+ MPI2_POINTER PTR_MPI2_EVENT_DATA_POWER_PERF_CHANGE,
+ Mpi2EventDataPowerPerfChange_t, MPI2_POINTER pMpi2EventDataPowerPerfChange_t;
+
+/* defines for CurrentPowerMode and PreviousPowerMode fields */
+#define MPI2_EVENT_PM_INIT_MASK (0xC0)
+#define MPI2_EVENT_PM_INIT_UNAVAILABLE (0x00)
+#define MPI2_EVENT_PM_INIT_HOST (0x40)
+#define MPI2_EVENT_PM_INIT_IO_UNIT (0x80)
+#define MPI2_EVENT_PM_INIT_PCIE_DPA (0xC0)
+
+#define MPI2_EVENT_PM_MODE_MASK (0x07)
+#define MPI2_EVENT_PM_MODE_UNAVAILABLE (0x00)
+#define MPI2_EVENT_PM_MODE_UNKNOWN (0x01)
+#define MPI2_EVENT_PM_MODE_FULL_POWER (0x04)
+#define MPI2_EVENT_PM_MODE_REDUCED_POWER (0x05)
+#define MPI2_EVENT_PM_MODE_STANDBY (0x06)
+
+
+/* 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 */
+/* this event is obsolete */
+
+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 PhysicalPort; /* 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)
+#define MPI2_EVENT_SAS_DEV_STAT_RC_EXPANDER_REDUCED_FUNCTIONALITY (0x11)
+#define MPI2_EVENT_SAS_DEV_STAT_RC_CMP_EXPANDER_REDUCED_FUNCTIONALITY (0x12)
+
+
+/* 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 ElapsedSeconds; /* 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 Notify Primitive Event data */
+
+typedef struct _MPI2_EVENT_DATA_SAS_NOTIFY_PRIMITIVE
+{
+ U8 PhyNum; /* 0x00 */
+ U8 Port; /* 0x01 */
+ U8 Reserved1; /* 0x02 */
+ U8 Primitive; /* 0x03 */
+} MPI2_EVENT_DATA_SAS_NOTIFY_PRIMITIVE,
+ MPI2_POINTER PTR_MPI2_EVENT_DATA_SAS_NOTIFY_PRIMITIVE,
+ Mpi2EventDataSasNotifyPrimitive_t,
+ MPI2_POINTER pMpi2EventDataSasNotifyPrimitive_t;
+
+/* defines for the Primitive field */
+#define MPI2_EVENT_NOTIFY_ENABLE_SPINUP (0x01)
+#define MPI2_EVENT_NOTIFY_POWER_LOSS_EXPECTED (0x02)
+#define MPI2_EVENT_NOTIFY_RESERVED1 (0x03)
+#define MPI2_EVENT_NOTIFY_RESERVED2 (0x04)
+
+
+/* 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_NO_EXPANDER (0x00)
+#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_UNSUPPORTED_PHY (0x06)
+#define MPI2_EVENT_SAS_TOPO_LR_RATE_1_5 (0x08)
+#define MPI2_EVENT_SAS_TOPO_LR_RATE_3_0 (0x09)
+#define MPI2_EVENT_SAS_TOPO_LR_RATE_6_0 (0x0A)
+#define MPI25_EVENT_SAS_TOPO_LR_RATE_12_0 (0x0B)
+
+/* 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)
+
+
+/* SAS PHY Counter Event data */
+
+typedef struct _MPI2_EVENT_DATA_SAS_PHY_COUNTER
+{
+ U64 TimeStamp; /* 0x00 */
+ U32 Reserved1; /* 0x08 */
+ U8 PhyEventCode; /* 0x0C */
+ U8 PhyNum; /* 0x0D */
+ U16 Reserved2; /* 0x0E */
+ U32 PhyEventInfo; /* 0x10 */
+ U8 CounterType; /* 0x14 */
+ U8 ThresholdWindow; /* 0x15 */
+ U8 TimeUnits; /* 0x16 */
+ U8 Reserved3; /* 0x17 */
+ U32 EventThreshold; /* 0x18 */
+ U16 ThresholdFlags; /* 0x1C */
+ U16 Reserved4; /* 0x1E */
+} MPI2_EVENT_DATA_SAS_PHY_COUNTER,
+ MPI2_POINTER PTR_MPI2_EVENT_DATA_SAS_PHY_COUNTER,
+ Mpi2EventDataSasPhyCounter_t, MPI2_POINTER pMpi2EventDataSasPhyCounter_t;
+
+/* use MPI2_SASPHY3_EVENT_CODE_ values from mpi2_cnfg.h for the PhyEventCode field */
+
+/* use MPI2_SASPHY3_COUNTER_TYPE_ values from mpi2_cnfg.h for the CounterType field */
+
+/* use MPI2_SASPHY3_TIME_UNITS_ values from mpi2_cnfg.h for the TimeUnits field */
+
+/* use MPI2_SASPHY3_TFLAGS_ values from mpi2_cnfg.h for the ThresholdFlags field */
+
+
+/* SAS Quiesce Event data */
+
+typedef struct _MPI2_EVENT_DATA_SAS_QUIESCE
+{
+ U8 ReasonCode; /* 0x00 */
+ U8 Reserved1; /* 0x01 */
+ U16 Reserved2; /* 0x02 */
+ U32 Reserved3; /* 0x04 */
+} MPI2_EVENT_DATA_SAS_QUIESCE,
+ MPI2_POINTER PTR_MPI2_EVENT_DATA_SAS_QUIESCE,
+ Mpi2EventDataSasQuiesce_t, MPI2_POINTER pMpi2EventDataSasQuiesce_t;
+
+/* SAS Quiesce Event data ReasonCode values */
+#define MPI2_EVENT_SAS_QUIESCE_RC_STARTED (0x01)
+#define MPI2_EVENT_SAS_QUIESCE_RC_COMPLETED (0x02)
+
+
+/* Host Based Discovery Phy Event data */
+
+typedef struct _MPI2_EVENT_HBD_PHY_SAS
+{
+ U8 Flags; /* 0x00 */
+ U8 NegotiatedLinkRate; /* 0x01 */
+ U8 PhyNum; /* 0x02 */
+ U8 PhysicalPort; /* 0x03 */
+ U32 Reserved1; /* 0x04 */
+ U8 InitialFrame[28]; /* 0x08 */
+} MPI2_EVENT_HBD_PHY_SAS, MPI2_POINTER PTR_MPI2_EVENT_HBD_PHY_SAS,
+ Mpi2EventHbdPhySas_t, MPI2_POINTER pMpi2EventHbdPhySas_t;
+
+/* values for the Flags field */
+#define MPI2_EVENT_HBD_SAS_FLAGS_FRAME_VALID (0x02)
+#define MPI2_EVENT_HBD_SAS_FLAGS_SATA_FRAME (0x01)
+
+/* use MPI2_SAS_NEG_LINK_RATE_ defines from mpi2_cnfg.h for the NegotiatedLinkRate field */
+
+typedef union _MPI2_EVENT_HBD_DESCRIPTOR
+{
+ MPI2_EVENT_HBD_PHY_SAS Sas;
+} MPI2_EVENT_HBD_DESCRIPTOR, MPI2_POINTER PTR_MPI2_EVENT_HBD_DESCRIPTOR,
+ Mpi2EventHbdDescriptor_t, MPI2_POINTER pMpi2EventHbdDescriptor_t;
+
+typedef struct _MPI2_EVENT_DATA_HBD_PHY
+{
+ U8 DescriptorType; /* 0x00 */
+ U8 Reserved1; /* 0x01 */
+ U16 Reserved2; /* 0x02 */
+ U32 Reserved3; /* 0x04 */
+ MPI2_EVENT_HBD_DESCRIPTOR Descriptor; /* 0x08 */
+} MPI2_EVENT_DATA_HBD_PHY, MPI2_POINTER PTR_MPI2_EVENT_DATA_HBD_PHY,
+ Mpi2EventDataHbdPhy_t, MPI2_POINTER pMpi2EventDataMpi2EventDataHbdPhy_t;
+
+/* values for the DescriptorType field */
+#define MPI2_EVENT_HBD_DT_SAS (0x01)
+
+
+
+/****************************************************************************
+* 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;
+
+
+/****************************************************************************
+* SendHostMessage message
+****************************************************************************/
+
+/* SendHostMessage Request message */
+typedef struct _MPI2_SEND_HOST_MESSAGE_REQUEST
+{
+ U16 HostDataLength; /* 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 */
+ U8 Reserved4; /* 0x0C */
+ U8 DestVF_ID; /* 0x0D */
+ U16 Reserved5; /* 0x0E */
+ U32 Reserved6; /* 0x10 */
+ U32 Reserved7; /* 0x14 */
+ U32 Reserved8; /* 0x18 */
+ U32 Reserved9; /* 0x1C */
+ U32 Reserved10; /* 0x20 */
+ U32 HostData[1]; /* 0x24 */
+} MPI2_SEND_HOST_MESSAGE_REQUEST,
+ MPI2_POINTER PTR_MPI2_SEND_HOST_MESSAGE_REQUEST,
+ Mpi2SendHostMessageRequest_t, MPI2_POINTER pMpi2SendHostMessageRequest_t;
+
+
+/* SendHostMessage Reply message */
+typedef struct _MPI2_SEND_HOST_MESSAGE_REPLY
+{
+ U16 HostDataLength; /* 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 */
+ U16 Reserved4; /* 0x0C */
+ U16 IOCStatus; /* 0x0E */
+ U32 IOCLogInfo; /* 0x10 */
+} MPI2_SEND_HOST_MESSAGE_REPLY, MPI2_POINTER PTR_MPI2_SEND_HOST_MESSAGE_REPLY,
+ Mpi2SendHostMessageReply_t, MPI2_POINTER pMpi2SendHostMessageReply_t;
+
+
+/****************************************************************************
+* FWDownload message
+****************************************************************************/
+
+/* MPI v2.0 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_COMPLETE (0x0A)
+#define MPI2_FW_DOWNLOAD_ITYPE_COMMON_BOOT_BLOCK (0x0B)
+#define MPI2_FW_DOWNLOAD_ITYPE_PUBLIC_KEY (0x0C) /* MPI v2.5 and newer */
+#define MPI2_FW_DOWNLOAD_ITYPE_MIN_PRODUCT_SPECIFIC (0xF0)
+
+/* MPI v2.0 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;
+
+
+/* MPI v2.5 FWDownload Request message */
+typedef struct _MPI25_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 */
+ U32 Reserved6; /* 0x14 */
+ U32 ImageOffset; /* 0x18 */
+ U32 ImageSize; /* 0x1C */
+ MPI25_SGE_IO_UNION SGL; /* 0x20 */
+} MPI25_FW_DOWNLOAD_REQUEST, MPI2_POINTER PTR_MPI25_FW_DOWNLOAD_REQUEST,
+ Mpi25FWDownloadRequest, MPI2_POINTER pMpi25FWDownloadRequest;
+
+
+/* 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
+****************************************************************************/
+
+/* MPI v2.0 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)
+
+/* MPI v2.0 FWUpload TransactionContext Element */
+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;
+
+
+/* MPI v2.5 FWUpload Request message */
+typedef struct _MPI25_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 */
+ U32 Reserved7; /* 0x14 */
+ U32 ImageOffset; /* 0x18 */
+ U32 ImageSize; /* 0x1C */
+ MPI25_SGE_IO_UNION SGL; /* 0x20 */
+} MPI25_FW_UPLOAD_REQUEST, MPI2_POINTER PTR_MPI25_FW_UPLOAD_REQUEST,
+ Mpi25FWUploadRequest_t, MPI2_POINTER pMpi25FWUploadRequest_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_PROD_TARGET_INITIATOR_SCSI (0x0200)
+#define MPI2_FW_HEADER_PID_PROD_IR_SCSI (0x0700)
+
+
+#define MPI2_FW_HEADER_PID_FAMILY_MASK (0x00FF)
+/* SAS ProductID Family bits */
+#define MPI2_FW_HEADER_PID_FAMILY_2108_SAS (0x0013)
+#define MPI2_FW_HEADER_PID_FAMILY_2208_SAS (0x0014)
+#define MPI25_FW_HEADER_PID_FAMILY_3108_SAS (0x0021)
+
+/* 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_ENCRYPTED_HASH (0x09) /* MPI v2.5 and newer */
+#define MPI2_EXT_IMAGE_TYPE_MIN_PRODUCT_SPECIFIC (0x80)
+#define MPI2_EXT_IMAGE_TYPE_MAX_PRODUCT_SPECIFIC (0xFF)
+
+#define MPI2_EXT_IMAGE_TYPE_MAX (MPI2_EXT_IMAGE_TYPE_MAX_PRODUCT_SPECIFIC) /* deprecated */
+
+
+
+/* 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)
+
+
+/* Encrypted Hash Extended Image Data */
+
+typedef struct _MPI25_ENCRYPTED_HASH_ENTRY
+{
+ U8 HashImageType; /* 0x00 */
+ U8 HashAlgorithm; /* 0x01 */
+ U8 EncryptionAlgorithm; /* 0x02 */
+ U8 Reserved1; /* 0x03 */
+ U32 Reserved2; /* 0x04 */
+ U32 EncryptedHash[1]; /* 0x08 */ /* variable length */
+} MPI25_ENCRYPTED_HASH_ENTRY, MPI2_POINTER PTR_MPI25_ENCRYPTED_HASH_ENTRY,
+ Mpi25EncryptedHashEntry_t, MPI2_POINTER pMpi25EncryptedHashEntry_t;
+
+/* values for HashImageType */
+#define MPI25_HASH_IMAGE_TYPE_UNUSED (0x00)
+#define MPI25_HASH_IMAGE_TYPE_FIRMWARE (0x01)
+#define MPI25_HASH_IMAGE_TYPE_BIOS (0x02)
+
+/* values for HashAlgorithm */
+#define MPI25_HASH_ALGORITHM_UNUSED (0x00)
+#define MPI25_HASH_ALGORITHM_SHA256 (0x01)
+
+/* values for EncryptionAlgorithm */
+#define MPI25_ENCRYPTION_ALG_UNUSED (0x00)
+#define MPI25_ENCRYPTION_ALG_RSA256 (0x01)
+
+typedef struct _MPI25_ENCRYPTED_HASH_DATA
+{
+ U8 ImageVersion; /* 0x00 */
+ U8 NumHash; /* 0x01 */
+ U16 Reserved1; /* 0x02 */
+ U32 Reserved2; /* 0x04 */
+ MPI25_ENCRYPTED_HASH_ENTRY EncryptedHashEntry[1]; /* 0x08 */ /* variable number of entries */
+} MPI25_ENCRYPTED_HASH_DATA, MPI2_POINTER PTR_MPI25_ENCRYPTED_HASH_DATA,
+ Mpi25EncryptedHashData_t, MPI2_POINTER pMpi25EncryptedHashData_t;
+
+/****************************************************************************
+* PowerManagementControl message
+****************************************************************************/
+
+/* PowerManagementControl Request message */
+typedef struct _MPI2_PWR_MGMT_CONTROL_REQUEST
+{
+ U8 Feature; /* 0x00 */
+ U8 Reserved1; /* 0x01 */
+ U8 ChainOffset; /* 0x02 */
+ U8 Function; /* 0x03 */
+ U16 Reserved2; /* 0x04 */
+ U8 Reserved3; /* 0x06 */
+ U8 MsgFlags; /* 0x07 */
+ U8 VP_ID; /* 0x08 */
+ U8 VF_ID; /* 0x09 */
+ U16 Reserved4; /* 0x0A */
+ U8 Parameter1; /* 0x0C */
+ U8 Parameter2; /* 0x0D */
+ U8 Parameter3; /* 0x0E */
+ U8 Parameter4; /* 0x0F */
+ U32 Reserved5; /* 0x10 */
+ U32 Reserved6; /* 0x14 */
+} MPI2_PWR_MGMT_CONTROL_REQUEST, MPI2_POINTER PTR_MPI2_PWR_MGMT_CONTROL_REQUEST,
+ Mpi2PwrMgmtControlRequest_t, MPI2_POINTER pMpi2PwrMgmtControlRequest_t;
+
+/* defines for the Feature field */
+#define MPI2_PM_CONTROL_FEATURE_DA_PHY_POWER_COND (0x01)
+#define MPI2_PM_CONTROL_FEATURE_PORT_WIDTH_MODULATION (0x02)
+#define MPI2_PM_CONTROL_FEATURE_PCIE_LINK (0x03) /* obsolete */
+#define MPI2_PM_CONTROL_FEATURE_IOC_SPEED (0x04)
+#define MPI2_PM_CONTROL_FEATURE_GLOBAL_PWR_MGMT_MODE (0x05) /* reserved in MPI 2.0 */
+#define MPI2_PM_CONTROL_FEATURE_MIN_PRODUCT_SPECIFIC (0x80)
+#define MPI2_PM_CONTROL_FEATURE_MAX_PRODUCT_SPECIFIC (0xFF)
+
+/* parameter usage for the MPI2_PM_CONTROL_FEATURE_DA_PHY_POWER_COND Feature */
+/* Parameter1 contains a PHY number */
+/* Parameter2 indicates power condition action using these defines */
+#define MPI2_PM_CONTROL_PARAM2_PARTIAL (0x01)
+#define MPI2_PM_CONTROL_PARAM2_SLUMBER (0x02)
+#define MPI2_PM_CONTROL_PARAM2_EXIT_PWR_MGMT (0x03)
+/* Parameter3 and Parameter4 are reserved */
+
+/* parameter usage for the MPI2_PM_CONTROL_FEATURE_PORT_WIDTH_MODULATION Feature */
+/* Parameter1 contains SAS port width modulation group number */
+/* Parameter2 indicates IOC action using these defines */
+#define MPI2_PM_CONTROL_PARAM2_REQUEST_OWNERSHIP (0x01)
+#define MPI2_PM_CONTROL_PARAM2_CHANGE_MODULATION (0x02)
+#define MPI2_PM_CONTROL_PARAM2_RELINQUISH_OWNERSHIP (0x03)
+/* Parameter3 indicates desired modulation level using these defines */
+#define MPI2_PM_CONTROL_PARAM3_25_PERCENT (0x00)
+#define MPI2_PM_CONTROL_PARAM3_50_PERCENT (0x01)
+#define MPI2_PM_CONTROL_PARAM3_75_PERCENT (0x02)
+#define MPI2_PM_CONTROL_PARAM3_100_PERCENT (0x03)
+/* Parameter4 is reserved */
+
+/* this next set (_PCIE_LINK) is obsolete */
+/* parameter usage for the MPI2_PM_CONTROL_FEATURE_PCIE_LINK Feature */
+/* Parameter1 indicates desired PCIe link speed using these defines */
+#define MPI2_PM_CONTROL_PARAM1_PCIE_2_5_GBPS (0x00) /* obsolete */
+#define MPI2_PM_CONTROL_PARAM1_PCIE_5_0_GBPS (0x01) /* obsolete */
+#define MPI2_PM_CONTROL_PARAM1_PCIE_8_0_GBPS (0x02) /* obsolete */
+/* Parameter2 indicates desired PCIe link width using these defines */
+#define MPI2_PM_CONTROL_PARAM2_WIDTH_X1 (0x01) /* obsolete */
+#define MPI2_PM_CONTROL_PARAM2_WIDTH_X2 (0x02) /* obsolete */
+#define MPI2_PM_CONTROL_PARAM2_WIDTH_X4 (0x04) /* obsolete */
+#define MPI2_PM_CONTROL_PARAM2_WIDTH_X8 (0x08) /* obsolete */
+/* Parameter3 and Parameter4 are reserved */
+
+/* parameter usage for the MPI2_PM_CONTROL_FEATURE_IOC_SPEED Feature */
+/* Parameter1 indicates desired IOC hardware clock speed using these defines */
+#define MPI2_PM_CONTROL_PARAM1_FULL_IOC_SPEED (0x01)
+#define MPI2_PM_CONTROL_PARAM1_HALF_IOC_SPEED (0x02)
+#define MPI2_PM_CONTROL_PARAM1_QUARTER_IOC_SPEED (0x04)
+#define MPI2_PM_CONTROL_PARAM1_EIGHTH_IOC_SPEED (0x08)
+/* Parameter2, Parameter3, and Parameter4 are reserved */
+
+/* parameter usage for the MPI2_PM_CONTROL_FEATURE_GLOBAL_PWR_MGMT_MODE Feature */
+/* Parameter1 indicates host action regarding global power management mode */
+#define MPI2_PM_CONTROL_PARAM1_TAKE_CONTROL (0x01)
+#define MPI2_PM_CONTROL_PARAM1_CHANGE_GLOBAL_MODE (0x02)
+#define MPI2_PM_CONTROL_PARAM1_RELEASE_CONTROL (0x03)
+/* Parameter2 indicates the requested global power management mode */
+#define MPI2_PM_CONTROL_PARAM2_FULL_PWR_PERF (0x01)
+#define MPI2_PM_CONTROL_PARAM2_REDUCED_PWR_PERF (0x08)
+#define MPI2_PM_CONTROL_PARAM2_STANDBY (0x40)
+/* Parameter3 and Parameter4 are reserved */
+
+
+/* PowerManagementControl Reply message */
+typedef struct _MPI2_PWR_MGMT_CONTROL_REPLY
+{
+ U8 Feature; /* 0x00 */
+ U8 Reserved1; /* 0x01 */
+ U8 MsgLength; /* 0x02 */
+ U8 Function; /* 0x03 */
+ U16 Reserved2; /* 0x04 */
+ U8 Reserved3; /* 0x06 */
+ U8 MsgFlags; /* 0x07 */
+ U8 VP_ID; /* 0x08 */
+ U8 VF_ID; /* 0x09 */
+ U16 Reserved4; /* 0x0A */
+ U16 Reserved5; /* 0x0C */
+ U16 IOCStatus; /* 0x0E */
+ U32 IOCLogInfo; /* 0x10 */
+} MPI2_PWR_MGMT_CONTROL_REPLY, MPI2_POINTER PTR_MPI2_PWR_MGMT_CONTROL_REPLY,
+ Mpi2PwrMgmtControlReply_t, MPI2_POINTER pMpi2PwrMgmtControlReply_t;
+
+
+#endif
+
diff --git a/sys/dev/mpr/mpi/mpi2_ra.h b/sys/dev/mpr/mpi/mpi2_ra.h
new file mode 100644
index 0000000..76db06b
--- /dev/null
+++ b/sys/dev/mpr/mpi/mpi2_ra.h
@@ -0,0 +1,118 @@
+/*-
+ * Copyright (c) 2013 LSI Corp.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the author nor the names of any co-contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * LSI MPT-Fusion Host Adapter FreeBSD
+ *
+ * $FreeBSD$
+ */
+
+/*
+ * Copyright (c) 2009 LSI Corporation.
+ *
+ *
+ * Name: mpi2_ra.h
+ * Title: MPI RAID Accelerator messages and structures
+ * Creation Date: April 13, 2009
+ *
+ * mpi2_ra.h Version: 02.00.00
+ *
+ * Version History
+ * ---------------
+ *
+ * Date Version Description
+ * -------- -------- ------------------------------------------------------
+ * 05-06-09 02.00.00 Initial version.
+ * --------------------------------------------------------------------------
+ */
+
+#ifndef MPI2_RA_H
+#define MPI2_RA_H
+
+/* generic structure for RAID Accelerator Control Block */
+typedef struct _MPI2_RAID_ACCELERATOR_CONTROL_BLOCK
+{
+ U32 Reserved[8]; /* 0x00 */
+ U32 RaidAcceleratorCDB[1]; /* 0x20 */
+} MPI2_RAID_ACCELERATOR_CONTROL_BLOCK,
+ MPI2_POINTER PTR_MPI2_RAID_ACCELERATOR_CONTROL_BLOCK,
+ Mpi2RAIDAcceleratorControlBlock_t,
+ MPI2_POINTER pMpi2RAIDAcceleratorControlBlock_t;
+
+
+/******************************************************************************
+*
+* RAID Accelerator Messages
+*
+*******************************************************************************/
+
+/* RAID Accelerator Request Message */
+typedef struct _MPI2_RAID_ACCELERATOR_REQUEST
+{
+ U16 Reserved0; /* 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 */
+ U64 RaidAcceleratorControlBlockAddress; /* 0x0C */
+ U8 DmaEngineNumber; /* 0x14 */
+ U8 Reserved4; /* 0x15 */
+ U16 Reserved5; /* 0x16 */
+ U32 Reserved6; /* 0x18 */
+ U32 Reserved7; /* 0x1C */
+ U32 Reserved8; /* 0x20 */
+} MPI2_RAID_ACCELERATOR_REQUEST, MPI2_POINTER PTR_MPI2_RAID_ACCELERATOR_REQUEST,
+ Mpi2RAIDAcceleratorRequest_t, MPI2_POINTER pMpi2RAIDAcceleratorRequest_t;
+
+
+/* RAID Accelerator Error Reply Message */
+typedef struct _MPI2_RAID_ACCELERATOR_REPLY
+{
+ U16 Reserved0; /* 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 */
+ U16 Reserved4; /* 0x0C */
+ U16 IOCStatus; /* 0x0E */
+ U32 IOCLogInfo; /* 0x10 */
+ U32 ProductSpecificData[3]; /* 0x14 */
+} MPI2_RAID_ACCELERATOR_REPLY, MPI2_POINTER PTR_MPI2_RAID_ACCELERATOR_REPLY,
+ Mpi2RAIDAcceleratorReply_t, MPI2_POINTER pMpi2RAIDAcceleratorReply_t;
+
+
+#endif
+
+
diff --git a/sys/dev/mpr/mpi/mpi2_raid.h b/sys/dev/mpr/mpi/mpi2_raid.h
new file mode 100644
index 0000000..c6bb598
--- /dev/null
+++ b/sys/dev/mpr/mpi/mpi2_raid.h
@@ -0,0 +1,406 @@
+/*-
+ * Copyright (c) 2013 LSI Corp.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the author nor the names of any co-contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * LSI MPT-Fusion Host Adapter FreeBSD
+ *
+ * $FreeBSD$
+ */
+
+/*
+ * Copyright (c) 2000-2013 LSI Corporation.
+ *
+ *
+ * Name: mpi2_raid.h
+ * Title: MPI Integrated RAID messages and structures
+ * Creation Date: April 26, 2007
+ *
+ * mpi2_raid.h Version: 02.00.10
+ *
+ * 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.
+ * 07-30-09 02.00.04 Added proper define for the Use Default Settings bit of
+ * VolumeCreationFlags and marked the old one as obsolete.
+ * 05-12-10 02.00.05 Added MPI2_RAID_VOL_FLAGS_OP_MDC define.
+ * 08-24-10 02.00.06 Added MPI2_RAID_ACTION_COMPATIBILITY_CHECK along with
+ * related structures and defines.
+ * Added product-specific range to RAID Action values.
+ * 11-18-11 02.00.07 Incorporating additions for MPI v2.5.
+ * 02-06-12 02.00.08 Added MPI2_RAID_ACTION_PHYSDISK_HIDDEN.
+ * 07-26-12 02.00.09 Added ElapsedSeconds field to MPI2_RAID_VOL_INDICATOR.
+ * Added MPI2_RAID_VOL_FLAGS_ELAPSED_SECONDS_VALID define.
+ * 04-17-13 02.00.10 Added MPI25_RAID_ACTION_ADATA_ALLOW_PI.
+ * --------------------------------------------------------------------------
+ */
+
+#ifndef MPI2_RAID_H
+#define MPI2_RAID_H
+
+/*****************************************************************************
+*
+* Integrated RAID Messages
+*
+*****************************************************************************/
+
+/****************************************************************************
+* RAID Action messages
+****************************************************************************/
+
+/* ActionDataWord defines for use with MPI2_RAID_ACTION_CREATE_VOLUME action */
+#define MPI25_RAID_ACTION_ADATA_ALLOW_PI (0x80000000)
+
+/* 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)
+#define MPI2_RAID_ACTION_COMPATIBILITY_CHECK (0x23)
+#define MPI2_RAID_ACTION_PHYSDISK_HIDDEN (0x24)
+#define MPI2_RAID_ACTION_MIN_PRODUCT_SPECIFIC (0x80)
+#define MPI2_RAID_ACTION_MAX_PRODUCT_SPECIFIC (0xFF)
+
+
+/* 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_DEFAULT_SETTINGS (0x80000000)
+#define MPI2_RAID_VOL_CREATION_BACKGROUND_INIT (0x00000004) /* MPI 2.0 only */
+#define MPI2_RAID_VOL_CREATION_LOW_LEVEL_INIT (0x00000002)
+#define MPI2_RAID_VOL_CREATION_MIGRATE_DATA (0x00000001)
+/* The following is an obsolete define.
+ * It must be shifted left 24 bits in order to set the proper bit.
+ */
+#define MPI2_RAID_VOL_CREATION_USE_DEFAULT_SETTINGS (0x80)
+
+
+/* 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 Compatibility Input Structure */
+
+typedef struct _MPI2_RAID_COMPATIBILITY_INPUT_STRUCT
+{
+ U16 SourceDevHandle; /* 0x00 */
+ U16 CandidateDevHandle; /* 0x02 */
+ U32 Flags; /* 0x04 */
+ U32 Reserved1; /* 0x08 */
+ U32 Reserved2; /* 0x0C */
+} MPI2_RAID_COMPATIBILITY_INPUT_STRUCT,
+ MPI2_POINTER PTR_MPI2_RAID_COMPATIBILITY_INPUT_STRUCT,
+ Mpi2RaidCompatibilityInputStruct_t,
+ MPI2_POINTER pMpi2RaidCompatibilityInputStruct_t;
+
+/* defines for RAID Compatibility Structure Flags field */
+#define MPI2_RAID_COMPAT_SOURCE_IS_VOLUME_FLAG (0x00000002)
+#define MPI2_RAID_COMPAT_REPORT_SOURCE_INFO_FLAG (0x00000001)
+
+
+/* RAID Volume Indicator Structure */
+
+typedef struct _MPI2_RAID_VOL_INDICATOR
+{
+ U64 TotalBlocks; /* 0x00 */
+ U64 BlocksRemaining; /* 0x08 */
+ U32 Flags; /* 0x10 */
+ U32 ElapsedSeconds; /* 0x14 */
+} 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_ELAPSED_SECONDS_VALID (0x80000000)
+
+#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)
+#define MPI2_RAID_VOL_FLAGS_OP_MDC (0x00000004)
+
+
+/* RAID Compatibility Result Structure */
+
+typedef struct _MPI2_RAID_COMPATIBILITY_RESULT_STRUCT
+{
+ U8 State; /* 0x00 */
+ U8 Reserved1; /* 0x01 */
+ U16 Reserved2; /* 0x02 */
+ U32 GenericAttributes; /* 0x04 */
+ U32 OEMSpecificAttributes; /* 0x08 */
+ U32 Reserved3; /* 0x0C */
+ U32 Reserved4; /* 0x10 */
+} MPI2_RAID_COMPATIBILITY_RESULT_STRUCT,
+ MPI2_POINTER PTR_MPI2_RAID_COMPATIBILITY_RESULT_STRUCT,
+ Mpi2RaidCompatibilityResultStruct_t,
+ MPI2_POINTER pMpi2RaidCompatibilityResultStruct_t;
+
+/* defines for RAID Compatibility Result Structure State field */
+#define MPI2_RAID_COMPAT_STATE_COMPATIBLE (0x00)
+#define MPI2_RAID_COMPAT_STATE_NOT_COMPATIBLE (0x01)
+
+/* defines for RAID Compatibility Result Structure GenericAttributes field */
+#define MPI2_RAID_COMPAT_GENATTRIB_4K_SECTOR (0x00000010)
+
+#define MPI2_RAID_COMPAT_GENATTRIB_MEDIA_MASK (0x0000000C)
+#define MPI2_RAID_COMPAT_GENATTRIB_SOLID_STATE_DRIVE (0x00000008)
+#define MPI2_RAID_COMPAT_GENATTRIB_HARD_DISK_DRIVE (0x00000004)
+
+#define MPI2_RAID_COMPAT_GENATTRIB_PROTOCOL_MASK (0x00000003)
+#define MPI2_RAID_COMPAT_GENATTRIB_SAS_PROTOCOL (0x00000002)
+#define MPI2_RAID_COMPAT_GENATTRIB_SATA_PROTOCOL (0x00000001)
+
+
+/* RAID Action Reply ActionData union */
+typedef union _MPI2_RAID_ACTION_REPLY_DATA
+{
+ U32 Word[6];
+ MPI2_RAID_VOL_INDICATOR RaidVolumeIndicator;
+ U16 VolDevHandle;
+ U8 VolumeState;
+ U8 PhysDiskNum;
+ MPI2_RAID_COMPATIBILITY_RESULT_STRUCT RaidCompatibilityResult;
+} 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/sys/dev/mpr/mpi/mpi2_sas.h b/sys/dev/mpr/mpi/mpi2_sas.h
new file mode 100644
index 0000000..2a107f1
--- /dev/null
+++ b/sys/dev/mpr/mpi/mpi2_sas.h
@@ -0,0 +1,346 @@
+/*-
+ * Copyright (c) 2013 LSI Corp.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the author nor the names of any co-contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * LSI MPT-Fusion Host Adapter FreeBSD
+ *
+ * $FreeBSD$
+ */
+
+/*
+ * Copyright (c) 2000-2013 LSI Corporation.
+ *
+ *
+ * Name: mpi2_sas.h
+ * Title: MPI Serial Attached SCSI structures and definitions
+ * Creation Date: February 9, 2007
+ *
+ * mpi2_sas.h Version: 02.00.08
+ *
+ * NOTE: Names (typedefs, defines, etc.) beginning with an MPI25 or Mpi25
+ * prefix are for use only on MPI v2.5 products, and must not be used
+ * with MPI v2.0 products. Unless otherwise noted, names beginning with
+ * MPI2 or Mpi2 are for use with both MPI v2.0 and MPI v2.5 products.
+ *
+ * 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.
+ * 10-28-09 02.00.03 Changed the type of SGL in MPI2_SATA_PASSTHROUGH_REQUEST
+ * to MPI2_SGE_IO_UNION since it supports chained SGLs.
+ * 05-12-10 02.00.04 Modified some comments.
+ * 08-11-10 02.00.05 Added NCQ operations to SAS IO Unit Control.
+ * 11-18-11 02.00.06 Incorporating additions for MPI v2.5.
+ * 07-10-12 02.00.07 Added MPI2_SATA_PT_SGE_UNION for use in the SATA
+ * Passthrough Request message.
+ * 08-19-13 02.00.08 Made MPI2_SAS_OP_TRANSMIT_PORT_SELECT_SIGNAL obsolete
+ * for anything newer than MPI v2.0.
+ * --------------------------------------------------------------------------
+ */
+
+#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 */ /* MPI v2.0 only. Reserved on MPI v2.5. */
+ 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 */ /* MPI v2.5: IEEE Simple 64 elements only */
+} 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)
+
+/* MPI v2.0: use MPI2_SGLFLAGS_ defines from mpi2.h for the SGLFlags field */
+
+
+/* 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
+****************************************************************************/
+
+typedef union _MPI2_SATA_PT_SGE_UNION
+{
+ MPI2_SGE_SIMPLE_UNION MpiSimple; /* MPI v2.0 only */
+ MPI2_SGE_CHAIN_UNION MpiChain; /* MPI v2.0 only */
+ MPI2_IEEE_SGE_SIMPLE_UNION IeeeSimple;
+ MPI2_IEEE_SGE_CHAIN_UNION IeeeChain; /* MPI v2.0 only */
+ MPI25_IEEE_SGE_CHAIN64 IeeeChain64; /* MPI v2.5 only */
+} MPI2_SATA_PT_SGE_UNION, MPI2_POINTER PTR_MPI2_SATA_PT_SGE_UNION,
+ Mpi2SataPTSGEUnion_t, MPI2_POINTER pMpi2SataPTSGEUnion_t;
+
+
+/* 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 */ /* MPI v2.0 only. Reserved on MPI v2.5. */
+ 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_SATA_PT_SGE_UNION SGL; /* 0x30 */ /* MPI v2.5: IEEE 64 elements only */
+} 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)
+
+/* MPI v2.0: use MPI2_SGLFLAGS_ defines from mpi2.h for the SGLFlags field */
+
+
+/* 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) /* MPI v2.0 only */
+#define MPI2_SAS_OP_REMOVE_DEVICE (0x0D)
+#define MPI2_SAS_OP_LOOKUP_MAPPING (0x0E)
+#define MPI2_SAS_OP_SET_IOC_PARAMETER (0x0F)
+#define MPI25_SAS_OP_ENABLE_FP_DEVICE (0x10)
+#define MPI25_SAS_OP_DISABLE_FP_DEVICE (0x11)
+#define MPI25_SAS_OP_ENABLE_FP_ALL (0x12)
+#define MPI25_SAS_OP_DISABLE_FP_ALL (0x13)
+#define MPI2_SAS_OP_DEV_ENABLE_NCQ (0x14)
+#define MPI2_SAS_OP_DEV_DISABLE_NCQ (0x15)
+#define MPI2_SAS_OP_PRODUCT_SPECIFIC_MIN (0x80)
+
+/* values for the PrimFlags field */
+#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/sys/dev/mpr/mpi/mpi2_targ.h b/sys/dev/mpr/mpi/mpi2_targ.h
new file mode 100644
index 0000000..506e64f
--- /dev/null
+++ b/sys/dev/mpr/mpi/mpi2_targ.h
@@ -0,0 +1,600 @@
+/*-
+ * Copyright (c) 2013 LSI Corp.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the author nor the names of any co-contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * LSI MPT-Fusion Host Adapter FreeBSD
+ *
+ * $FreeBSD$
+ */
+
+/*
+ * Copyright (c) 2000-2012 LSI Corporation.
+ *
+ *
+ * Name: mpi2_targ.h
+ * Title: MPI Target mode messages and structures
+ * Creation Date: September 8, 2006
+ *
+ * mpi2_targ.h Version: 02.00.06
+ *
+ * NOTE: Names (typedefs, defines, etc.) beginning with an MPI25 or Mpi25
+ * prefix are for use only on MPI v2.5 products, and must not be used
+ * with MPI v2.0 products. Unless otherwise noted, names beginning with
+ * MPI2 or Mpi2 are for use with both MPI v2.0 and MPI v2.5 products.
+ *
+ * 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 Added Command Buffer Data Location Address Space bits to
+ * BufferPostFlags field of CommandBufferPostBase Request.
+ * 02-29-08 02.00.02 Modified various names to make them 32-character unique.
+ * 10-02-08 02.00.03 Removed NextCmdBufferOffset from
+ * MPI2_TARGET_CMD_BUF_POST_BASE_REQUEST.
+ * Target Status Send Request only takes a single SGE for
+ * response data.
+ * 02-10-10 02.00.04 Added comment to MPI2_TARGET_SSP_RSP_IU structure.
+ * 11-18-11 02.00.05 Incorporating additions for MPI v2.5.
+ * 11-27-12 02.00.06 Added InitiatorDevHandle field to MPI2_TARGET_MODE_ABORT
+ * request message structure.
+ * Added AbortType MPI2_TARGET_MODE_ABORT_DEVHANDLE and
+ * MPI2_TARGET_MODE_ABORT_ALL_COMMANDS.
+ * --------------------------------------------------------------------------
+ */
+
+#ifndef MPI2_TARG_H
+#define MPI2_TARG_H
+
+
+/******************************************************************************
+*
+* SCSI Target Messages
+*
+*******************************************************************************/
+
+/****************************************************************************
+* Target Command Buffer Post Base Request
+****************************************************************************/
+
+typedef struct _MPI2_TARGET_CMD_BUF_POST_BASE_REQUEST
+{
+ U8 BufferPostFlags; /* 0x00 */
+ U8 Reserved1; /* 0x01 */
+ U8 ChainOffset; /* 0x02 */
+ U8 Function; /* 0x03 */
+ U16 TotalCmdBuffers; /* 0x04 */
+ U8 Reserved; /* 0x06 */
+ U8 MsgFlags; /* 0x07 */
+ U8 VP_ID; /* 0x08 */
+ U8 VF_ID; /* 0x09 */
+ U16 Reserved2; /* 0x0A */
+ U32 Reserved3; /* 0x0C */
+ U16 CmdBufferLength; /* 0x10 */
+ U16 Reserved4; /* 0x12 */
+ U32 BaseAddressLow; /* 0x14 */
+ U32 BaseAddressHigh; /* 0x18 */
+} MPI2_TARGET_CMD_BUF_POST_BASE_REQUEST,
+ MPI2_POINTER PTR_MPI2_TARGET_CMD_BUF_POST_BASE_REQUEST,
+ Mpi2TargetCmdBufferPostBaseRequest_t,
+ MPI2_POINTER pMpi2TargetCmdBufferPostBaseRequest_t;
+
+/* values for the BufferPostflags field */
+#define MPI2_CMD_BUF_POST_BASE_ADDRESS_SPACE_MASK (0x0C)
+#define MPI2_CMD_BUF_POST_BASE_SYSTEM_ADDRESS_SPACE (0x00)
+#define MPI2_CMD_BUF_POST_BASE_IOCDDR_ADDRESS_SPACE (0x04)
+#define MPI2_CMD_BUF_POST_BASE_IOCPLB_ADDRESS_SPACE (0x08)
+#define MPI2_CMD_BUF_POST_BASE_IOCPLBNTA_ADDRESS_SPACE (0x0C)
+
+#define MPI2_CMD_BUF_POST_BASE_FLAGS_AUTO_POST_ALL (0x01)
+
+
+/****************************************************************************
+* Target Command Buffer Post List Request
+****************************************************************************/
+
+typedef struct _MPI2_TARGET_CMD_BUF_POST_LIST_REQUEST
+{
+ U16 Reserved; /* 0x00 */
+ U8 ChainOffset; /* 0x02 */
+ U8 Function; /* 0x03 */
+ U16 CmdBufferCount; /* 0x04 */
+ U8 Reserved1; /* 0x06 */
+ U8 MsgFlags; /* 0x07 */
+ U8 VP_ID; /* 0x08 */
+ U8 VF_ID; /* 0x09 */
+ U16 Reserved2; /* 0x0A */
+ U32 Reserved3; /* 0x0C */
+ U16 IoIndex[2]; /* 0x10 */
+} MPI2_TARGET_CMD_BUF_POST_LIST_REQUEST,
+ MPI2_POINTER PTR_MPI2_TARGET_CMD_BUF_POST_LIST_REQUEST,
+ Mpi2TargetCmdBufferPostListRequest_t,
+ MPI2_POINTER pMpi2TargetCmdBufferPostListRequest_t;
+
+/****************************************************************************
+* Target Command Buffer Post Base List Reply
+****************************************************************************/
+
+typedef struct _MPI2_TARGET_BUF_POST_BASE_LIST_REPLY
+{
+ U8 Flags; /* 0x00 */
+ U8 Reserved; /* 0x01 */
+ 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 */
+ U16 Reserved4; /* 0x0C */
+ U16 IOCStatus; /* 0x0E */
+ U32 IOCLogInfo; /* 0x10 */
+ U16 IoIndex; /* 0x14 */
+ U16 Reserved5; /* 0x16 */
+ U32 Reserved6; /* 0x18 */
+} MPI2_TARGET_BUF_POST_BASE_LIST_REPLY,
+ MPI2_POINTER PTR_MPI2_TARGET_BUF_POST_BASE_LIST_REPLY,
+ Mpi2TargetCmdBufferPostBaseListReply_t,
+ MPI2_POINTER pMpi2TargetCmdBufferPostBaseListReply_t;
+
+/* Flags defines */
+#define MPI2_CMD_BUF_POST_REPLY_IOINDEX_VALID (0x01)
+
+
+/****************************************************************************
+* Command Buffer Formats (with 16 byte CDB)
+****************************************************************************/
+
+typedef struct _MPI2_TARGET_SSP_CMD_BUFFER
+{
+ U8 FrameType; /* 0x00 */
+ U8 Reserved1; /* 0x01 */
+ U16 InitiatorConnectionTag; /* 0x02 */
+ U32 HashedSourceSASAddress; /* 0x04 */
+ U16 Reserved2; /* 0x08 */
+ U16 Flags; /* 0x0A */
+ U32 Reserved3; /* 0x0C */
+ U16 Tag; /* 0x10 */
+ U16 TargetPortTransferTag; /* 0x12 */
+ U32 DataOffset; /* 0x14 */
+ /* COMMAND information unit starts here */
+ U8 LogicalUnitNumber[8]; /* 0x18 */
+ U8 Reserved4; /* 0x20 */
+ U8 TaskAttribute; /* lower 3 bits */ /* 0x21 */
+ U8 Reserved5; /* 0x22 */
+ U8 AdditionalCDBLength; /* upper 5 bits */ /* 0x23 */
+ U8 CDB[16]; /* 0x24 */
+ /* Additional CDB bytes extend past the CDB field */
+} MPI2_TARGET_SSP_CMD_BUFFER, MPI2_POINTER PTR_MPI2_TARGET_SSP_CMD_BUFFER,
+ Mpi2TargetSspCmdBuffer, MPI2_POINTER pMp2iTargetSspCmdBuffer;
+
+typedef struct _MPI2_TARGET_SSP_TASK_BUFFER
+{
+ U8 FrameType; /* 0x00 */
+ U8 Reserved1; /* 0x01 */
+ U16 InitiatorConnectionTag; /* 0x02 */
+ U32 HashedSourceSASAddress; /* 0x04 */
+ U16 Reserved2; /* 0x08 */
+ U16 Flags; /* 0x0A */
+ U32 Reserved3; /* 0x0C */
+ U16 Tag; /* 0x10 */
+ U16 TargetPortTransferTag; /* 0x12 */
+ U32 DataOffset; /* 0x14 */
+ /* TASK information unit starts here */
+ U8 LogicalUnitNumber[8]; /* 0x18 */
+ U16 Reserved4; /* 0x20 */
+ U8 TaskManagementFunction; /* 0x22 */
+ U8 Reserved5; /* 0x23 */
+ U16 ManagedTaskTag; /* 0x24 */
+ U16 Reserved6; /* 0x26 */
+ U32 Reserved7; /* 0x28 */
+ U32 Reserved8; /* 0x2C */
+ U32 Reserved9; /* 0x30 */
+} MPI2_TARGET_SSP_TASK_BUFFER, MPI2_POINTER PTR_MPI2_TARGET_SSP_TASK_BUFFER,
+ Mpi2TargetSspTaskBuffer, MPI2_POINTER pMpi2TargetSspTaskBuffer;
+
+/* mask and shift for HashedSourceSASAddress field */
+#define MPI2_TARGET_HASHED_SAS_ADDRESS_MASK (0xFFFFFF00)
+#define MPI2_TARGET_HASHED_SAS_ADDRESS_SHIFT (8)
+
+
+/****************************************************************************
+* MPI v2.0 Target Assist Request
+****************************************************************************/
+
+typedef struct _MPI2_TARGET_ASSIST_REQUEST
+{
+ U8 Reserved1; /* 0x00 */
+ U8 TargetAssistFlags; /* 0x01 */
+ U8 ChainOffset; /* 0x02 */
+ U8 Function; /* 0x03 */
+ U16 QueueTag; /* 0x04 */
+ U8 Reserved2; /* 0x06 */
+ U8 MsgFlags; /* 0x07 */
+ U8 VP_ID; /* 0x08 */
+ U8 VF_ID; /* 0x09 */
+ U16 Reserved3; /* 0x0A */
+ U16 IoIndex; /* 0x0C */
+ U16 InitiatorConnectionTag; /* 0x0E */
+ U16 SGLFlags; /* 0x10 */
+ U8 SequenceNumber; /* 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 */
+ U32 PrimaryReferenceTag; /* 0x34 */
+ U16 PrimaryApplicationTag; /* 0x38 */
+ U16 PrimaryApplicationTagMask; /* 0x3A */
+ U32 RelativeOffset; /* 0x3C */
+ U32 Reserved5; /* 0x40 */
+ U32 Reserved6; /* 0x44 */
+ U32 Reserved7; /* 0x48 */
+ U32 Reserved8; /* 0x4C */
+ MPI2_SGE_IO_UNION SGL[1]; /* 0x50 */
+} MPI2_TARGET_ASSIST_REQUEST, MPI2_POINTER PTR_MPI2_TARGET_ASSIST_REQUEST,
+ Mpi2TargetAssistRequest_t, MPI2_POINTER pMpi2TargetAssistRequest_t;
+
+/* Target Assist TargetAssistFlags bits */
+
+#define MPI2_TARGET_ASSIST_FLAGS_REPOST_CMD_BUFFER (0x80)
+#define MPI2_TARGET_ASSIST_FLAGS_TLR (0x10)
+#define MPI2_TARGET_ASSIST_FLAGS_RETRANSMIT (0x04)
+#define MPI2_TARGET_ASSIST_FLAGS_AUTO_STATUS (0x02)
+#define MPI2_TARGET_ASSIST_FLAGS_DATA_DIRECTION (0x01)
+
+/* Target Assist SGLFlags bits */
+
+/* base values for Data Location Address Space */
+#define MPI2_TARGET_ASSIST_SGLFLAGS_ADDR_MASK (0x0C)
+#define MPI2_TARGET_ASSIST_SGLFLAGS_SYSTEM_ADDR (0x00)
+#define MPI2_TARGET_ASSIST_SGLFLAGS_IOCDDR_ADDR (0x04)
+#define MPI2_TARGET_ASSIST_SGLFLAGS_IOCPLB_ADDR (0x08)
+#define MPI2_TARGET_ASSIST_SGLFLAGS_PLBNTA_ADDR (0x0C)
+
+/* base values for Type */
+#define MPI2_TARGET_ASSIST_SGLFLAGS_TYPE_MASK (0x03)
+#define MPI2_TARGET_ASSIST_SGLFLAGS_MPI_TYPE (0x00)
+#define MPI2_TARGET_ASSIST_SGLFLAGS_32IEEE_TYPE (0x01)
+#define MPI2_TARGET_ASSIST_SGLFLAGS_64IEEE_TYPE (0x02)
+
+/* shift values for each sub-field */
+#define MPI2_TARGET_ASSIST_SGLFLAGS_SGL3_SHIFT (12)
+#define MPI2_TARGET_ASSIST_SGLFLAGS_SGL2_SHIFT (8)
+#define MPI2_TARGET_ASSIST_SGLFLAGS_SGL1_SHIFT (4)
+#define MPI2_TARGET_ASSIST_SGLFLAGS_SGL0_SHIFT (0)
+
+/* Target Assist IoFlags bits */
+
+#define MPI2_TARGET_ASSIST_IOFLAGS_BIDIRECTIONAL (0x0800)
+#define MPI2_TARGET_ASSIST_IOFLAGS_MULTICAST (0x0400)
+#define MPI2_TARGET_ASSIST_IOFLAGS_RECEIVE_FIRST (0x0200)
+
+/* Target Assist EEDPFlags bits */
+
+#define MPI2_TA_EEDPFLAGS_INC_PRI_REFTAG (0x8000)
+#define MPI2_TA_EEDPFLAGS_INC_SEC_REFTAG (0x4000)
+#define MPI2_TA_EEDPFLAGS_INC_PRI_APPTAG (0x2000)
+#define MPI2_TA_EEDPFLAGS_INC_SEC_APPTAG (0x1000)
+
+#define MPI2_TA_EEDPFLAGS_CHECK_REFTAG (0x0400)
+#define MPI2_TA_EEDPFLAGS_CHECK_APPTAG (0x0200)
+#define MPI2_TA_EEDPFLAGS_CHECK_GUARD (0x0100)
+
+#define MPI2_TA_EEDPFLAGS_PASSTHRU_REFTAG (0x0008)
+
+#define MPI2_TA_EEDPFLAGS_MASK_OP (0x0007)
+#define MPI2_TA_EEDPFLAGS_NOOP_OP (0x0000)
+#define MPI2_TA_EEDPFLAGS_CHECK_OP (0x0001)
+#define MPI2_TA_EEDPFLAGS_STRIP_OP (0x0002)
+#define MPI2_TA_EEDPFLAGS_CHECK_REMOVE_OP (0x0003)
+#define MPI2_TA_EEDPFLAGS_INSERT_OP (0x0004)
+#define MPI2_TA_EEDPFLAGS_REPLACE_OP (0x0006)
+#define MPI2_TA_EEDPFLAGS_CHECK_REGEN_OP (0x0007)
+
+
+/****************************************************************************
+* MPI v2.5 Target Assist Request
+****************************************************************************/
+
+typedef struct _MPI25_TARGET_ASSIST_REQUEST
+{
+ U8 Reserved1; /* 0x00 */
+ U8 TargetAssistFlags; /* 0x01 */
+ U8 ChainOffset; /* 0x02 */
+ U8 Function; /* 0x03 */
+ U16 QueueTag; /* 0x04 */
+ U8 Reserved2; /* 0x06 */
+ U8 MsgFlags; /* 0x07 */
+ U8 VP_ID; /* 0x08 */
+ U8 VF_ID; /* 0x09 */
+ U16 Reserved3; /* 0x0A */
+ U16 IoIndex; /* 0x0C */
+ U16 InitiatorConnectionTag; /* 0x0E */
+ U8 DMAFlags; /* 0x10 */
+ U8 Reserved9; /* 0x11 */
+ U8 SequenceNumber; /* 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 */
+ U16 EEDPBlockSize; /* 0x28 */
+ U16 Reserved10; /* 0x2A */
+ U32 SecondaryReferenceTag; /* 0x2C */
+ U16 SecondaryApplicationTag; /* 0x30 */
+ U16 ApplicationTagTranslationMask; /* 0x32 */
+ U32 PrimaryReferenceTag; /* 0x34 */
+ U16 PrimaryApplicationTag; /* 0x38 */
+ U16 PrimaryApplicationTagMask; /* 0x3A */
+ U32 RelativeOffset; /* 0x3C */
+ U32 Reserved5; /* 0x40 */
+ U32 Reserved6; /* 0x44 */
+ U32 Reserved7; /* 0x48 */
+ U32 Reserved8; /* 0x4C */
+ MPI25_SGE_IO_UNION SGL; /* 0x50 */
+} MPI25_TARGET_ASSIST_REQUEST, MPI2_POINTER PTR_MPI25_TARGET_ASSIST_REQUEST,
+ Mpi25TargetAssistRequest_t, MPI2_POINTER pMpi25TargetAssistRequest_t;
+
+/* use MPI2_TARGET_ASSIST_FLAGS_ defines for the Flags field */
+
+/* Defines for the DMAFlags field
+ * Each setting affects 4 SGLS, from SGL0 to SGL3.
+ * D = Data
+ * C = Cache DIF
+ * I = Interleaved
+ * H = Host DIF
+ */
+#define MPI25_TA_DMAFLAGS_OP_MASK (0x0F)
+#define MPI25_TA_DMAFLAGS_OP_D_D_D_D (0x00)
+#define MPI25_TA_DMAFLAGS_OP_D_D_D_C (0x01)
+#define MPI25_TA_DMAFLAGS_OP_D_D_D_I (0x02)
+#define MPI25_TA_DMAFLAGS_OP_D_D_C_C (0x03)
+#define MPI25_TA_DMAFLAGS_OP_D_D_C_I (0x04)
+#define MPI25_TA_DMAFLAGS_OP_D_D_I_I (0x05)
+#define MPI25_TA_DMAFLAGS_OP_D_C_C_C (0x06)
+#define MPI25_TA_DMAFLAGS_OP_D_C_C_I (0x07)
+#define MPI25_TA_DMAFLAGS_OP_D_C_I_I (0x08)
+#define MPI25_TA_DMAFLAGS_OP_D_I_I_I (0x09)
+#define MPI25_TA_DMAFLAGS_OP_D_H_D_D (0x0A)
+#define MPI25_TA_DMAFLAGS_OP_D_H_D_C (0x0B)
+#define MPI25_TA_DMAFLAGS_OP_D_H_D_I (0x0C)
+#define MPI25_TA_DMAFLAGS_OP_D_H_C_C (0x0D)
+#define MPI25_TA_DMAFLAGS_OP_D_H_C_I (0x0E)
+#define MPI25_TA_DMAFLAGS_OP_D_H_I_I (0x0F)
+
+/* defines for the IoFlags field */
+#define MPI25_TARGET_ASSIST_IOFLAGS_BIDIRECTIONAL (0x0800)
+#define MPI25_TARGET_ASSIST_IOFLAGS_RECEIVE_FIRST (0x0200)
+
+/* defines for the EEDPFlags field */
+#define MPI25_TA_EEDPFLAGS_INC_PRI_REFTAG (0x8000)
+#define MPI25_TA_EEDPFLAGS_INC_SEC_REFTAG (0x4000)
+#define MPI25_TA_EEDPFLAGS_INC_PRI_APPTAG (0x2000)
+#define MPI25_TA_EEDPFLAGS_INC_SEC_APPTAG (0x1000)
+
+#define MPI25_TA_EEDPFLAGS_CHECK_REFTAG (0x0400)
+#define MPI25_TA_EEDPFLAGS_CHECK_APPTAG (0x0200)
+#define MPI25_TA_EEDPFLAGS_CHECK_GUARD (0x0100)
+
+#define MPI25_TA_EEDPFLAGS_ESCAPE_MODE_MASK (0x00C0)
+#define MPI25_TA_EEDPFLAGS_COMPATIBLE_MODE (0x0000)
+#define MPI25_TA_EEDPFLAGS_DO_NOT_DISABLE_MODE (0x0040)
+#define MPI25_TA_EEDPFLAGS_APPTAG_DISABLE_MODE (0x0080)
+#define MPI25_TA_EEDPFLAGS_APPTAG_REFTAG_DISABLE_MODE (0x00C0)
+
+#define MPI25_TA_EEDPFLAGS_HOST_GUARD_METHOD_MASK (0x0030)
+#define MPI25_TA_EEDPFLAGS_T10_CRC_HOST_GUARD (0x0000)
+#define MPI25_TA_EEDPFLAGS_IP_CHKSUM_HOST_GUARD (0x0010)
+
+#define MPI25_TA_EEDPFLAGS_PASSTHRU_REFTAG (0x0008)
+
+#define MPI25_TA_EEDPFLAGS_MASK_OP (0x0007)
+#define MPI25_TA_EEDPFLAGS_NOOP_OP (0x0000)
+#define MPI25_TA_EEDPFLAGS_CHECK_OP (0x0001)
+#define MPI25_TA_EEDPFLAGS_STRIP_OP (0x0002)
+#define MPI25_TA_EEDPFLAGS_CHECK_REMOVE_OP (0x0003)
+#define MPI25_TA_EEDPFLAGS_INSERT_OP (0x0004)
+#define MPI25_TA_EEDPFLAGS_REPLACE_OP (0x0006)
+#define MPI25_TA_EEDPFLAGS_CHECK_REGEN_OP (0x0007)
+
+
+/****************************************************************************
+* Target Status Send Request
+****************************************************************************/
+
+typedef struct _MPI2_TARGET_STATUS_SEND_REQUEST
+{
+ U8 Reserved1; /* 0x00 */
+ U8 StatusFlags; /* 0x01 */
+ U8 ChainOffset; /* 0x02 */
+ U8 Function; /* 0x03 */
+ U16 QueueTag; /* 0x04 */
+ U8 Reserved2; /* 0x06 */
+ U8 MsgFlags; /* 0x07 */
+ U8 VP_ID; /* 0x08 */
+ U8 VF_ID; /* 0x09 */
+ U16 Reserved3; /* 0x0A */
+ U16 IoIndex; /* 0x0C */
+ U16 InitiatorConnectionTag; /* 0x0E */
+ U16 SGLFlags; /* 0x10 */ /* MPI v2.0 only. Reserved on MPI v2.5. */
+ U16 Reserved4; /* 0x12 */
+ U8 SGLOffset0; /* 0x14 */
+ U8 Reserved5; /* 0x15 */
+ U16 Reserved6; /* 0x16 */
+ U32 Reserved7; /* 0x18 */
+ U32 Reserved8; /* 0x1C */
+ MPI2_SIMPLE_SGE_UNION StatusDataSGE; /* 0x20 */ /* MPI v2.5: This must be an IEEE Simple Element 64. */
+} MPI2_TARGET_STATUS_SEND_REQUEST,
+ MPI2_POINTER PTR_MPI2_TARGET_STATUS_SEND_REQUEST,
+ Mpi2TargetStatusSendRequest_t, MPI2_POINTER pMpi2TargetStatusSendRequest_t;
+
+/* Target Status Send StatusFlags bits */
+
+#define MPI2_TSS_FLAGS_REPOST_CMD_BUFFER (0x80)
+#define MPI2_TSS_FLAGS_RETRANSMIT (0x04)
+#define MPI2_TSS_FLAGS_AUTO_GOOD_STATUS (0x01)
+
+/* Target Status Send SGLFlags bits - MPI v2.0 only */
+/* Data Location Address Space */
+#define MPI2_TSS_SGLFLAGS_ADDR_MASK (0x0C)
+#define MPI2_TSS_SGLFLAGS_SYSTEM_ADDR (0x00)
+#define MPI2_TSS_SGLFLAGS_IOCDDR_ADDR (0x04)
+#define MPI2_TSS_SGLFLAGS_IOCPLB_ADDR (0x08)
+#define MPI2_TSS_SGLFLAGS_IOCPLBNTA_ADDR (0x0C)
+/* Type */
+#define MPI2_TSS_SGLFLAGS_TYPE_MASK (0x03)
+#define MPI2_TSS_SGLFLAGS_MPI_TYPE (0x00)
+#define MPI2_TSS_SGLFLAGS_IEEE32_TYPE (0x01)
+#define MPI2_TSS_SGLFLAGS_IEEE64_TYPE (0x02)
+
+
+
+/*
+ * NOTE: The SSP status IU is big-endian. When used on a little-endian system,
+ * this structure properly orders the bytes.
+ */
+typedef struct _MPI2_TARGET_SSP_RSP_IU
+{
+ U32 Reserved0[6]; /* reserved for SSP header */ /* 0x00 */
+
+ /* start of RESPONSE information unit */
+ U32 Reserved1; /* 0x18 */
+ U32 Reserved2; /* 0x1C */
+ U16 Reserved3; /* 0x20 */
+ U8 DataPres; /* lower 2 bits */ /* 0x22 */
+ U8 Status; /* 0x23 */
+ U32 Reserved4; /* 0x24 */
+ U32 SenseDataLength; /* 0x28 */
+ U32 ResponseDataLength; /* 0x2C */
+
+ /* start of Response or Sense Data (size may vary dynamically) */
+ U8 ResponseSenseData[4]; /* 0x30 */
+} MPI2_TARGET_SSP_RSP_IU, MPI2_POINTER PTR_MPI2_TARGET_SSP_RSP_IU,
+ Mpi2TargetSspRspIu_t, MPI2_POINTER pMpi2TargetSspRspIu_t;
+
+
+/****************************************************************************
+* Target Standard Reply - used with Target Assist or Target Status Send
+****************************************************************************/
+
+typedef struct _MPI2_TARGET_STANDARD_REPLY
+{
+ U16 Reserved; /* 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 */
+ U16 Reserved4; /* 0x0C */
+ U16 IOCStatus; /* 0x0E */
+ U32 IOCLogInfo; /* 0x10 */
+ U16 IoIndex; /* 0x14 */
+ U16 Reserved5; /* 0x16 */
+ U32 TransferCount; /* 0x18 */
+ U32 BidirectionalTransferCount; /* 0x1C */
+} MPI2_TARGET_STANDARD_REPLY, MPI2_POINTER PTR_MPI2_TARGET_STANDARD_REPLY,
+ Mpi2TargetErrorReply_t, MPI2_POINTER pMpi2TargetErrorReply_t;
+
+
+/****************************************************************************
+* Target Mode Abort Request
+****************************************************************************/
+
+typedef struct _MPI2_TARGET_MODE_ABORT_REQUEST
+{
+ U8 AbortType; /* 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 IoIndexToAbort; /* 0x0C */
+ U16 InitiatorDevHandle; /* 0x0E */
+ U32 MidToAbort; /* 0x10 */
+} MPI2_TARGET_MODE_ABORT, MPI2_POINTER PTR_MPI2_TARGET_MODE_ABORT,
+ Mpi2TargetModeAbort_t, MPI2_POINTER pMpi2TargetModeAbort_t;
+
+/* Target Mode Abort AbortType values */
+
+#define MPI2_TARGET_MODE_ABORT_ALL_CMD_BUFFERS (0x00)
+#define MPI2_TARGET_MODE_ABORT_ALL_IO (0x01)
+#define MPI2_TARGET_MODE_ABORT_EXACT_IO (0x02)
+#define MPI2_TARGET_MODE_ABORT_EXACT_IO_REQUEST (0x03)
+#define MPI2_TARGET_MODE_ABORT_IO_REQUEST_AND_IO (0x04)
+#define MPI2_TARGET_MODE_ABORT_DEVHANDLE (0x05)
+#define MPI2_TARGET_MODE_ABORT_ALL_COMMANDS (0x06)
+
+
+/****************************************************************************
+* Target Mode Abort Reply
+****************************************************************************/
+
+typedef struct _MPI2_TARGET_MODE_ABORT_REPLY
+{
+ U16 Reserved; /* 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 */
+ U16 Reserved4; /* 0x0C */
+ U16 IOCStatus; /* 0x0E */
+ U32 IOCLogInfo; /* 0x10 */
+ U32 AbortCount; /* 0x14 */
+} MPI2_TARGET_MODE_ABORT_REPLY, MPI2_POINTER PTR_MPI2_TARGET_MODE_ABORT_REPLY,
+ Mpi2TargetModeAbortReply_t, MPI2_POINTER pMpi2TargetModeAbortReply_t;
+
+
+#endif
+
diff --git a/sys/dev/mpr/mpi/mpi2_tool.h b/sys/dev/mpr/mpi/mpi2_tool.h
new file mode 100644
index 0000000..94542cc
--- /dev/null
+++ b/sys/dev/mpr/mpi/mpi2_tool.h
@@ -0,0 +1,546 @@
+/*-
+ * Copyright (c) 2013 LSI Corp.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the author nor the names of any co-contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * LSI MPT-Fusion Host Adapter FreeBSD
+ *
+ * $FreeBSD$
+ */
+
+/*
+ * Copyright (c) 2000-2013 LSI Corporation.
+ *
+ *
+ * Name: mpi2_tool.h
+ * Title: MPI diagnostic tool structures and definitions
+ * Creation Date: March 26, 2007
+ *
+ * mpi2_tool.h Version: 02.00.11
+ *
+ * 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.
+ * 05-06-09 02.00.03 Added ISTWI Read Write Tool and Diagnostic CLI Tool.
+ * 07-30-09 02.00.04 Added ExtendedType field to DiagnosticBufferPost request
+ * and reply messages.
+ * Added MPI2_DIAG_BUF_TYPE_EXTENDED.
+ * Incremented MPI2_DIAG_BUF_TYPE_COUNT.
+ * 05-12-10 02.00.05 Added Diagnostic Data Upload tool.
+ * 08-11-10 02.00.06 Added defines that were missing for Diagnostic Buffer
+ * Post Request.
+ * 05-25-11 02.00.07 Added Flags field and related defines to
+ * MPI2_TOOLBOX_ISTWI_READ_WRITE_REQUEST.
+ * 11-18-11 02.00.08 Incorporating additions for MPI v2.5.
+ * 07-10-12 02.00.09 Add MPI v2.5 Toolbox Diagnostic CLI Tool Request
+ * message.
+ * 07-26-12 02.00.10 Modified MPI2_TOOLBOX_DIAGNOSTIC_CLI_REQUEST so that
+ * it uses MPI Chain SGE as well as MPI Simple SGE.
+ * 08-19-13 02.00.11 Added MPI2_TOOLBOX_TEXT_DISPLAY_TOOL and related info.
+ * --------------------------------------------------------------------------
+ */
+
+#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_DIAG_DATA_UPLOAD_TOOL (0x02)
+#define MPI2_TOOLBOX_ISTWI_READ_WRITE_TOOL (0x03)
+#define MPI2_TOOLBOX_BEACON_TOOL (0x05)
+#define MPI2_TOOLBOX_DIAGNOSTIC_CLI_TOOL (0x06)
+#define MPI2_TOOLBOX_TEXT_DISPLAY_TOOL (0x07)
+
+
+/****************************************************************************
+* 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 Diagnostic Data Upload request
+****************************************************************************/
+
+typedef struct _MPI2_TOOLBOX_DIAG_DATA_UPLOAD_REQUEST
+{
+ U8 Tool; /* 0x00 */
+ U8 Reserved1; /* 0x01 */
+ U8 ChainOffset; /* 0x02 */
+ U8 Function; /* 0x03 */
+ U16 Reserved2; /* 0x04 */
+ U8 Reserved3; /* 0x06 */
+ U8 MsgFlags; /* 0x07 */
+ U8 VP_ID; /* 0x08 */
+ U8 VF_ID; /* 0x09 */
+ U16 Reserved4; /* 0x0A */
+ U8 SGLFlags; /* 0x0C */
+ U8 Reserved5; /* 0x0D */
+ U16 Reserved6; /* 0x0E */
+ U32 Flags; /* 0x10 */
+ U32 DataLength; /* 0x14 */
+ MPI2_SGE_SIMPLE_UNION SGL; /* 0x18 */
+} MPI2_TOOLBOX_DIAG_DATA_UPLOAD_REQUEST,
+ MPI2_POINTER PTR_MPI2_TOOLBOX_DIAG_DATA_UPLOAD_REQUEST,
+ Mpi2ToolboxDiagDataUploadRequest_t,
+ MPI2_POINTER pMpi2ToolboxDiagDataUploadRequest_t;
+
+/* use MPI2_SGLFLAGS_ defines from mpi2.h for the SGLFlags field */
+
+
+typedef struct _MPI2_DIAG_DATA_UPLOAD_HEADER
+{
+ U32 DiagDataLength; /* 00h */
+ U8 FormatCode; /* 04h */
+ U8 Reserved1; /* 05h */
+ U16 Reserved2; /* 06h */
+} MPI2_DIAG_DATA_UPLOAD_HEADER, MPI2_POINTER PTR_MPI2_DIAG_DATA_UPLOAD_HEADER,
+ Mpi2DiagDataUploadHeader_t, MPI2_POINTER pMpi2DiagDataUploadHeader_t;
+
+
+/****************************************************************************
+* Toolbox ISTWI Read Write Tool
+****************************************************************************/
+
+/* Toolbox ISTWI Read Write Tool request message */
+typedef struct _MPI2_TOOLBOX_ISTWI_READ_WRITE_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 Reserved5; /* 0x0C */
+ U32 Reserved6; /* 0x10 */
+ U8 DevIndex; /* 0x14 */
+ U8 Action; /* 0x15 */
+ U8 SGLFlags; /* 0x16 */
+ U8 Flags; /* 0x17 */
+ U16 TxDataLength; /* 0x18 */
+ U16 RxDataLength; /* 0x1A */
+ U32 Reserved8; /* 0x1C */
+ U32 Reserved9; /* 0x20 */
+ U32 Reserved10; /* 0x24 */
+ U32 Reserved11; /* 0x28 */
+ U32 Reserved12; /* 0x2C */
+ MPI2_SGE_SIMPLE_UNION SGL; /* 0x30 */
+} MPI2_TOOLBOX_ISTWI_READ_WRITE_REQUEST,
+ MPI2_POINTER PTR_MPI2_TOOLBOX_ISTWI_READ_WRITE_REQUEST,
+ Mpi2ToolboxIstwiReadWriteRequest_t,
+ MPI2_POINTER pMpi2ToolboxIstwiReadWriteRequest_t;
+
+/* values for the Action field */
+#define MPI2_TOOL_ISTWI_ACTION_READ_DATA (0x01)
+#define MPI2_TOOL_ISTWI_ACTION_WRITE_DATA (0x02)
+#define MPI2_TOOL_ISTWI_ACTION_SEQUENCE (0x03)
+#define MPI2_TOOL_ISTWI_ACTION_RESERVE_BUS (0x10)
+#define MPI2_TOOL_ISTWI_ACTION_RELEASE_BUS (0x11)
+#define MPI2_TOOL_ISTWI_ACTION_RESET (0x12)
+
+/* use MPI2_SGLFLAGS_ defines from mpi2.h for the SGLFlags field */
+
+/* values for the Flags field */
+#define MPI2_TOOL_ISTWI_FLAG_AUTO_RESERVE_RELEASE (0x80)
+#define MPI2_TOOL_ISTWI_FLAG_PAGE_ADDR_MASK (0x07)
+
+
+/* Toolbox ISTWI Read Write Tool reply message */
+typedef struct _MPI2_TOOLBOX_ISTWI_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 */
+ U8 DevIndex; /* 0x14 */
+ U8 Action; /* 0x15 */
+ U8 IstwiStatus; /* 0x16 */
+ U8 Reserved6; /* 0x17 */
+ U16 TxDataCount; /* 0x18 */
+ U16 RxDataCount; /* 0x1A */
+} MPI2_TOOLBOX_ISTWI_REPLY, MPI2_POINTER PTR_MPI2_TOOLBOX_ISTWI_REPLY,
+ Mpi2ToolboxIstwiReply_t, MPI2_POINTER pMpi2ToolboxIstwiReply_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)
+
+
+/****************************************************************************
+* Toolbox Diagnostic CLI Tool
+****************************************************************************/
+
+#define MPI2_TOOLBOX_DIAG_CLI_CMD_LENGTH (0x5C)
+
+/* MPI v2.0 Toolbox Diagnostic CLI Tool request message */
+typedef struct _MPI2_TOOLBOX_DIAGNOSTIC_CLI_REQUEST
+{
+ U8 Tool; /* 0x00 */
+ U8 Reserved1; /* 0x01 */
+ U8 ChainOffset; /* 0x02 */
+ U8 Function; /* 0x03 */
+ U16 Reserved2; /* 0x04 */
+ U8 Reserved3; /* 0x06 */
+ U8 MsgFlags; /* 0x07 */
+ U8 VP_ID; /* 0x08 */
+ U8 VF_ID; /* 0x09 */
+ U16 Reserved4; /* 0x0A */
+ U8 SGLFlags; /* 0x0C */
+ U8 Reserved5; /* 0x0D */
+ U16 Reserved6; /* 0x0E */
+ U32 DataLength; /* 0x10 */
+ U8 DiagnosticCliCommand[MPI2_TOOLBOX_DIAG_CLI_CMD_LENGTH]; /* 0x14 */
+ MPI2_MPI_SGE_IO_UNION SGL; /* 0x70 */
+} MPI2_TOOLBOX_DIAGNOSTIC_CLI_REQUEST,
+ MPI2_POINTER PTR_MPI2_TOOLBOX_DIAGNOSTIC_CLI_REQUEST,
+ Mpi2ToolboxDiagnosticCliRequest_t,
+ MPI2_POINTER pMpi2ToolboxDiagnosticCliRequest_t;
+
+/* use MPI2_SGLFLAGS_ defines from mpi2.h for the SGLFlags field */
+
+
+/* MPI v2.5 Toolbox Diagnostic CLI Tool request message */
+typedef struct _MPI25_TOOLBOX_DIAGNOSTIC_CLI_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 Reserved5; /* 0x0C */
+ U32 DataLength; /* 0x10 */
+ U8 DiagnosticCliCommand[MPI2_TOOLBOX_DIAG_CLI_CMD_LENGTH]; /* 0x14 */
+ MPI25_SGE_IO_UNION SGL; /* 0x70 */
+} MPI25_TOOLBOX_DIAGNOSTIC_CLI_REQUEST,
+ MPI2_POINTER PTR_MPI25_TOOLBOX_DIAGNOSTIC_CLI_REQUEST,
+ Mpi25ToolboxDiagnosticCliRequest_t,
+ MPI2_POINTER pMpi25ToolboxDiagnosticCliRequest_t;
+
+
+/* Toolbox Diagnostic CLI Tool reply message */
+typedef struct _MPI2_TOOLBOX_DIAGNOSTIC_CLI_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 */
+ U32 ReturnedDataLength; /* 0x14 */
+} MPI2_TOOLBOX_DIAGNOSTIC_CLI_REPLY,
+ MPI2_POINTER PTR_MPI2_TOOLBOX_DIAG_CLI_REPLY,
+ Mpi2ToolboxDiagnosticCliReply_t,
+ MPI2_POINTER pMpi2ToolboxDiagnosticCliReply_t;
+
+
+/****************************************************************************
+* Toolbox Console Text Display Tool
+****************************************************************************/
+
+/* Toolbox Console Text Display Tool request message */
+typedef struct _MPI2_TOOLBOX_TEXT_DISPLAY_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 Console; /* 0x0C */
+ U8 Flags; /* 0x0D */
+ U16 Reserved6; /* 0x0E */
+ U8 TextToDisplay[4]; /* 0x10 */ /* actual length determined at runtime based on frame size */
+} MPI2_TOOLBOX_TEXT_DISPLAY_REQUEST,
+ MPI2_POINTER PTR_MPI2_TOOLBOX_TEXT_DISPLAY_REQUEST,
+ Mpi2ToolboxTextDisplayRequest_t,
+ MPI2_POINTER pMpi2ToolboxTextDisplayRequest_t;
+
+/* defines for the Console field */
+#define MPI2_TOOLBOX_CONSOLE_TYPE_MASK (0xF0)
+#define MPI2_TOOLBOX_CONSOLE_TYPE_DEFAULT (0x00)
+#define MPI2_TOOLBOX_CONSOLE_TYPE_UART (0x10)
+#define MPI2_TOOLBOX_CONSOLE_TYPE_ETHERNET (0x20)
+
+#define MPI2_TOOLBOX_CONSOLE_NUMBER_MASK (0x0F)
+
+/* defines for the Flags field */
+#define MPI2_TOOLBOX_CONSOLE_FLAG_TIMESTAMP (0x01)
+
+
+
+/*****************************************************************************
+*
+* Diagnostic Buffer Messages
+*
+*****************************************************************************/
+
+
+/****************************************************************************
+* Diagnostic Buffer Post request
+****************************************************************************/
+
+typedef struct _MPI2_DIAG_BUFFER_POST_REQUEST
+{
+ U8 ExtendedType; /* 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 ExtendedType field */
+#define MPI2_DIAG_EXTENDED_TYPE_UTILIZATION (0x02)
+
+/* values for the BufferType field */
+#define MPI2_DIAG_BUF_TYPE_TRACE (0x00)
+#define MPI2_DIAG_BUF_TYPE_SNAPSHOT (0x01)
+#define MPI2_DIAG_BUF_TYPE_EXTENDED (0x02)
+/* count of the number of buffer types */
+#define MPI2_DIAG_BUF_TYPE_COUNT (0x03)
+
+/* values for the Flags field */
+#define MPI2_DIAG_BUF_FLAG_RELEASE_ON_FULL (0x00000002) /* for MPI v2.0 products only */
+#define MPI2_DIAG_BUF_FLAG_IMMEDIATE_RELEASE (0x00000001)
+
+
+/****************************************************************************
+* Diagnostic Buffer Post reply
+****************************************************************************/
+
+typedef struct _MPI2_DIAG_BUFFER_POST_REPLY
+{
+ U8 ExtendedType; /* 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/sys/dev/mpr/mpi/mpi2_type.h b/sys/dev/mpr/mpi/mpi2_type.h
new file mode 100644
index 0000000..da3aefb
--- /dev/null
+++ b/sys/dev/mpr/mpi/mpi2_type.h
@@ -0,0 +1,131 @@
+/*-
+ * Copyright (c) 2013 LSI Corp.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the author nor the names of any co-contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * LSI MPT-Fusion Host Adapter FreeBSD
+ *
+ * $FreeBSD$
+ */
+
+/*
+ * 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 signed char S8;
+typedef unsigned char U8;
+typedef signed short S16;
+typedef unsigned short U16;
+
+#ifdef __FreeBSD__
+
+typedef int32_t S32;
+typedef uint32_t U32;
+
+#else
+
+#if defined(unix) || defined(__arm) || defined(ALPHA) || defined(__PPC__) || defined(__ppc)
+
+ typedef signed int S32;
+ typedef unsigned int U32;
+
+#else
+
+ typedef signed long S32;
+ typedef unsigned long U32;
+
+#endif
+#endif
+
+typedef struct _S64
+{
+ U32 Low;
+ S32 High;
+} S64;
+
+typedef struct _U64
+{
+ U32 Low;
+ U32 High;
+} U64;
+
+
+/*****************************************************************************
+*
+* Pointer Types
+*
+*****************************************************************************/
+
+typedef S8 *PS8;
+typedef U8 *PU8;
+typedef S16 *PS16;
+typedef U16 *PU16;
+typedef S32 *PS32;
+typedef U32 *PU32;
+typedef S64 *PS64;
+typedef U64 *PU64;
+
+#endif
+
+#endif
+
diff --git a/sys/dev/mpr/mpr.c b/sys/dev/mpr/mpr.c
new file mode 100644
index 0000000..fe187a5
--- /dev/null
+++ b/sys/dev/mpr/mpr.c
@@ -0,0 +1,2797 @@
+/*-
+ * Copyright (c) 2009 Yahoo! Inc.
+ * Copyright (c) 2012-2014 LSI Corp.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+/* Communications core for LSI MPT2 */
+
+/* TODO Move headers to mprvar */
+#include <sys/types.h>
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/kernel.h>
+#include <sys/selinfo.h>
+#include <sys/lock.h>
+#include <sys/mutex.h>
+#include <sys/module.h>
+#include <sys/bus.h>
+#include <sys/conf.h>
+#include <sys/bio.h>
+#include <sys/malloc.h>
+#include <sys/uio.h>
+#include <sys/sysctl.h>
+#include <sys/queue.h>
+#include <sys/kthread.h>
+#include <sys/taskqueue.h>
+#include <sys/endian.h>
+#include <sys/eventhandler.h>
+
+#include <machine/bus.h>
+#include <machine/resource.h>
+#include <sys/rman.h>
+#include <sys/proc.h>
+
+#include <dev/pci/pcivar.h>
+
+#include <cam/cam.h>
+#include <cam/scsi/scsi_all.h>
+
+#include <dev/mpr/mpi/mpi2_type.h>
+#include <dev/mpr/mpi/mpi2.h>
+#include <dev/mpr/mpi/mpi2_ioc.h>
+#include <dev/mpr/mpi/mpi2_sas.h>
+#include <dev/mpr/mpi/mpi2_cnfg.h>
+#include <dev/mpr/mpi/mpi2_init.h>
+#include <dev/mpr/mpi/mpi2_tool.h>
+#include <dev/mpr/mpr_ioctl.h>
+#include <dev/mpr/mprvar.h>
+#include <dev/mpr/mpr_table.h>
+#include <dev/mpr/mpr_sas.h>
+
+static int mpr_diag_reset(struct mpr_softc *sc, int sleep_flag);
+static int mpr_init_queues(struct mpr_softc *sc);
+static int mpr_message_unit_reset(struct mpr_softc *sc, int sleep_flag);
+static int mpr_transition_operational(struct mpr_softc *sc);
+static int mpr_iocfacts_allocate(struct mpr_softc *sc, uint8_t attaching);
+static void mpr_iocfacts_free(struct mpr_softc *sc);
+static void mpr_startup(void *arg);
+static int mpr_send_iocinit(struct mpr_softc *sc);
+static int mpr_alloc_queues(struct mpr_softc *sc);
+static int mpr_alloc_replies(struct mpr_softc *sc);
+static int mpr_alloc_requests(struct mpr_softc *sc);
+static int mpr_attach_log(struct mpr_softc *sc);
+static __inline void mpr_complete_command(struct mpr_softc *sc,
+ struct mpr_command *cm);
+static void mpr_dispatch_event(struct mpr_softc *sc, uintptr_t data,
+ MPI2_EVENT_NOTIFICATION_REPLY *reply);
+static void mpr_config_complete(struct mpr_softc *sc,
+ struct mpr_command *cm);
+static void mpr_periodic(void *);
+static int mpr_reregister_events(struct mpr_softc *sc);
+static void mpr_enqueue_request(struct mpr_softc *sc,
+ struct mpr_command *cm);
+static int mpr_get_iocfacts(struct mpr_softc *sc,
+ MPI2_IOC_FACTS_REPLY *facts);
+static int mpr_wait_db_ack(struct mpr_softc *sc, int timeout, int sleep_flag);
+SYSCTL_NODE(_hw, OID_AUTO, mpr, CTLFLAG_RD, 0, "MPR Driver Parameters");
+
+MALLOC_DEFINE(M_MPR, "mpr", "mpr driver memory");
+
+/*
+ * Do a "Diagnostic Reset" aka a hard reset. This should get the chip out of
+ * any state and back to its initialization state machine.
+ */
+static char mpt2_reset_magic[] = { 0x00, 0x0f, 0x04, 0x0b, 0x02, 0x07, 0x0d };
+
+/*
+ * Added this union to smoothly convert le64toh cm->cm_desc.Words.
+ * Compiler only supports unint64_t to be passed as an argument.
+ * Otherwise it will through this error:
+ * "aggregate value used where an integer was expected"
+ */
+typedef union _reply_descriptor {
+ u64 word;
+ struct {
+ u32 low;
+ u32 high;
+ } u;
+}reply_descriptor,address_descriptor;
+
+/* Rate limit chain-fail messages to 1 per minute */
+static struct timeval mpr_chainfail_interval = { 60, 0 };
+
+/*
+ * sleep_flag can be either CAN_SLEEP or NO_SLEEP.
+ * If this function is called from process context, it can sleep
+ * and there is no harm to sleep, in case if this fuction is called
+ * from Interrupt handler, we can not sleep and need NO_SLEEP flag set.
+ * based on sleep flags driver will call either msleep, pause or DELAY.
+ * msleep and pause are of same variant, but pause is used when mpr_mtx
+ * is not hold by driver.
+ */
+static int
+mpr_diag_reset(struct mpr_softc *sc,int sleep_flag)
+{
+ uint32_t reg;
+ int i, error, tries = 0;
+ uint8_t first_wait_done = FALSE;
+
+ mpr_dprint(sc, MPR_TRACE, "%s\n", __func__);
+
+ /* Clear any pending interrupts */
+ mpr_regwrite(sc, MPI2_HOST_INTERRUPT_STATUS_OFFSET, 0x0);
+
+ /*
+ * Force NO_SLEEP for threads prohibited to sleep
+ * e.a Thread from interrupt handler are prohibited to sleep.
+ */
+#if __FreeBSD_version >= 1000029
+ if (curthread->td_no_sleeping)
+#else //__FreeBSD_version < 1000029
+ if (curthread->td_pflags & TDP_NOSLEEPING)
+#endif //__FreeBSD_version >= 1000029
+ sleep_flag = NO_SLEEP;
+
+ /* Push the magic sequence */
+ error = ETIMEDOUT;
+ while (tries++ < 20) {
+ for (i = 0; i < sizeof(mpt2_reset_magic); i++)
+ mpr_regwrite(sc, MPI2_WRITE_SEQUENCE_OFFSET,
+ mpt2_reset_magic[i]);
+
+ /* wait 100 msec */
+ if (mtx_owned(&sc->mpr_mtx) && sleep_flag == CAN_SLEEP)
+ msleep(&sc->msleep_fake_chan, &sc->mpr_mtx, 0,
+ "mprdiag", hz/10);
+ else if (sleep_flag == CAN_SLEEP)
+ pause("mprdiag", hz/10);
+ else
+ DELAY(100 * 1000);
+
+ reg = mpr_regread(sc, MPI2_HOST_DIAGNOSTIC_OFFSET);
+ if (reg & MPI2_DIAG_DIAG_WRITE_ENABLE) {
+ error = 0;
+ break;
+ }
+ }
+ if (error)
+ return (error);
+
+ /* Send the actual reset. XXX need to refresh the reg? */
+ mpr_regwrite(sc, MPI2_HOST_DIAGNOSTIC_OFFSET,
+ reg | MPI2_DIAG_RESET_ADAPTER);
+
+ /* Wait up to 300 seconds in 50ms intervals */
+ error = ETIMEDOUT;
+ for (i = 0; i < 6000; i++) {
+ /*
+ * Wait 50 msec. If this is the first time through, wait 256
+ * msec to satisfy Diag Reset timing requirements.
+ */
+ if (first_wait_done) {
+ if (mtx_owned(&sc->mpr_mtx) && sleep_flag == CAN_SLEEP)
+ msleep(&sc->msleep_fake_chan, &sc->mpr_mtx, 0,
+ "mprdiag", hz/20);
+ else if (sleep_flag == CAN_SLEEP)
+ pause("mprdiag", hz/20);
+ else
+ DELAY(50 * 1000);
+ } else {
+ DELAY(256 * 1000);
+ first_wait_done = TRUE;
+ }
+ /*
+ * Check for the RESET_ADAPTER bit to be cleared first, then
+ * wait for the RESET state to be cleared, which takes a little
+ * longer.
+ */
+ reg = mpr_regread(sc, MPI2_HOST_DIAGNOSTIC_OFFSET);
+ if (reg & MPI2_DIAG_RESET_ADAPTER) {
+ continue;
+ }
+ reg = mpr_regread(sc, MPI2_DOORBELL_OFFSET);
+ if ((reg & MPI2_IOC_STATE_MASK) != MPI2_IOC_STATE_RESET) {
+ error = 0;
+ break;
+ }
+ }
+ if (error)
+ return (error);
+
+ mpr_regwrite(sc, MPI2_WRITE_SEQUENCE_OFFSET, 0x0);
+
+ return (0);
+}
+
+static int
+mpr_message_unit_reset(struct mpr_softc *sc, int sleep_flag)
+{
+
+ MPR_FUNCTRACE(sc);
+
+ mpr_regwrite(sc, MPI2_DOORBELL_OFFSET,
+ MPI2_FUNCTION_IOC_MESSAGE_UNIT_RESET <<
+ MPI2_DOORBELL_FUNCTION_SHIFT);
+
+ if (mpr_wait_db_ack(sc, 5, sleep_flag) != 0) {
+ mpr_dprint(sc, MPR_FAULT, "Doorbell handshake failed : <%s>\n",
+ __func__);
+ return (ETIMEDOUT);
+ }
+
+ return (0);
+}
+
+static int
+mpr_transition_ready(struct mpr_softc *sc)
+{
+ uint32_t reg, state;
+ int error, tries = 0;
+ int sleep_flags;
+
+ MPR_FUNCTRACE(sc);
+ /* If we are in attach call, do not sleep */
+ sleep_flags = (sc->mpr_flags & MPR_FLAGS_ATTACH_DONE)
+ ? CAN_SLEEP : NO_SLEEP;
+
+ error = 0;
+ while (tries++ < 1200) {
+ reg = mpr_regread(sc, MPI2_DOORBELL_OFFSET);
+ mpr_dprint(sc, MPR_INIT, "Doorbell= 0x%x\n", reg);
+
+ /*
+ * Ensure the IOC is ready to talk. If it's not, try
+ * resetting it.
+ */
+ if (reg & MPI2_DOORBELL_USED) {
+ mpr_diag_reset(sc, sleep_flags);
+ DELAY(50000);
+ continue;
+ }
+
+ /* Is the adapter owned by another peer? */
+ if ((reg & MPI2_DOORBELL_WHO_INIT_MASK) ==
+ (MPI2_WHOINIT_PCI_PEER << MPI2_DOORBELL_WHO_INIT_SHIFT)) {
+ device_printf(sc->mpr_dev, "IOC is under the control "
+ "of another peer host, aborting initialization.\n");
+ return (ENXIO);
+ }
+
+ state = reg & MPI2_IOC_STATE_MASK;
+ if (state == MPI2_IOC_STATE_READY) {
+ /* Ready to go! */
+ error = 0;
+ break;
+ } else if (state == MPI2_IOC_STATE_FAULT) {
+ mpr_dprint(sc, MPR_FAULT, "IOC in fault state 0x%x\n",
+ state & MPI2_DOORBELL_FAULT_CODE_MASK);
+ mpr_diag_reset(sc, sleep_flags);
+ } else if (state == MPI2_IOC_STATE_OPERATIONAL) {
+ /* Need to take ownership */
+ mpr_message_unit_reset(sc, sleep_flags);
+ } else if (state == MPI2_IOC_STATE_RESET) {
+ /* Wait a bit, IOC might be in transition */
+ mpr_dprint(sc, MPR_FAULT,
+ "IOC in unexpected reset state\n");
+ } else {
+ mpr_dprint(sc, MPR_FAULT,
+ "IOC in unknown state 0x%x\n", state);
+ error = EINVAL;
+ break;
+ }
+
+ /* Wait 50ms for things to settle down. */
+ DELAY(50000);
+ }
+
+ if (error)
+ device_printf(sc->mpr_dev, "Cannot transition IOC to ready\n");
+
+ return (error);
+}
+
+static int
+mpr_transition_operational(struct mpr_softc *sc)
+{
+ uint32_t reg, state;
+ int error;
+
+ MPR_FUNCTRACE(sc);
+
+ error = 0;
+ reg = mpr_regread(sc, MPI2_DOORBELL_OFFSET);
+ mpr_dprint(sc, MPR_INIT, "Doorbell= 0x%x\n", reg);
+
+ state = reg & MPI2_IOC_STATE_MASK;
+ if (state != MPI2_IOC_STATE_READY) {
+ if ((error = mpr_transition_ready(sc)) != 0) {
+ mpr_dprint(sc, MPR_FAULT,
+ "%s failed to transition ready\n", __func__);
+ return (error);
+ }
+ }
+
+ error = mpr_send_iocinit(sc);
+ return (error);
+}
+
+/*
+ * This is called during attach and when re-initializing due to a Diag Reset.
+ * IOC Facts is used to allocate many of the structures needed by the driver.
+ * If called from attach, de-allocation is not required because the driver has
+ * not allocated any structures yet, but if called from a Diag Reset, previously
+ * allocated structures based on IOC Facts will need to be freed and re-
+ * allocated bases on the latest IOC Facts.
+ */
+static int
+mpr_iocfacts_allocate(struct mpr_softc *sc, uint8_t attaching)
+{
+ int error, i;
+ Mpi2IOCFactsReply_t saved_facts;
+ uint8_t saved_mode, reallocating;
+ struct mprsas_lun *lun, *lun_tmp;
+ struct mprsas_target *targ;
+
+ mpr_dprint(sc, MPR_TRACE, "%s\n", __func__);
+
+ /* Save old IOC Facts and then only reallocate if Facts have changed */
+ if (!attaching) {
+ bcopy(sc->facts, &saved_facts, sizeof(MPI2_IOC_FACTS_REPLY));
+ }
+
+ /*
+ * Get IOC Facts. In all cases throughout this function, panic if doing
+ * a re-initialization and only return the error if attaching so the OS
+ * can handle it.
+ */
+ if ((error = mpr_get_iocfacts(sc, sc->facts)) != 0) {
+ if (attaching) {
+ mpr_dprint(sc, MPR_FAULT, "%s failed to get IOC Facts "
+ "with error %d\n", __func__, error);
+ return (error);
+ } else {
+ panic("%s failed to get IOC Facts with error %d\n",
+ __func__, error);
+ }
+ }
+
+ mpr_print_iocfacts(sc, sc->facts);
+
+ snprintf(sc->fw_version, sizeof(sc->fw_version),
+ "%02d.%02d.%02d.%02d",
+ sc->facts->FWVersion.Struct.Major,
+ sc->facts->FWVersion.Struct.Minor,
+ sc->facts->FWVersion.Struct.Unit,
+ sc->facts->FWVersion.Struct.Dev);
+
+ mpr_printf(sc, "Firmware: %s, Driver: %s\n", sc->fw_version,
+ MPR_DRIVER_VERSION);
+ mpr_printf(sc, "IOCCapabilities: %b\n", sc->facts->IOCCapabilities,
+ "\20" "\3ScsiTaskFull" "\4DiagTrace" "\5SnapBuf" "\6ExtBuf"
+ "\7EEDP" "\10BiDirTarg" "\11Multicast" "\14TransRetry" "\15IR"
+ "\16EventReplay" "\17RaidAccel" "\20MSIXIndex" "\21HostDisc");
+
+ /*
+ * If the chip doesn't support event replay then a hard reset will be
+ * required to trigger a full discovery. Do the reset here then
+ * retransition to Ready. A hard reset might have already been done,
+ * but it doesn't hurt to do it again. Only do this if attaching, not
+ * for a Diag Reset.
+ */
+ if (attaching) {
+ if ((sc->facts->IOCCapabilities &
+ MPI2_IOCFACTS_CAPABILITY_EVENT_REPLAY) == 0) {
+ mpr_diag_reset(sc, NO_SLEEP);
+ if ((error = mpr_transition_ready(sc)) != 0) {
+ mpr_dprint(sc, MPR_FAULT, "%s failed to "
+ "transition to ready with error %d\n",
+ __func__, error);
+ return (error);
+ }
+ }
+ }
+
+ /*
+ * Set flag if IR Firmware is loaded. If the RAID Capability has
+ * changed from the previous IOC Facts, log a warning, but only if
+ * checking this after a Diag Reset and not during attach.
+ */
+ saved_mode = sc->ir_firmware;
+ if (sc->facts->IOCCapabilities &
+ MPI2_IOCFACTS_CAPABILITY_INTEGRATED_RAID)
+ sc->ir_firmware = 1;
+ if (!attaching) {
+ if (sc->ir_firmware != saved_mode) {
+ mpr_dprint(sc, MPR_FAULT, "%s new IR/IT mode in IOC "
+ "Facts does not match previous mode\n", __func__);
+ }
+ }
+
+ /* Only deallocate and reallocate if relevant IOC Facts have changed */
+ reallocating = FALSE;
+ if ((!attaching) &&
+ ((saved_facts.MsgVersion != sc->facts->MsgVersion) ||
+ (saved_facts.HeaderVersion != sc->facts->HeaderVersion) ||
+ (saved_facts.MaxChainDepth != sc->facts->MaxChainDepth) ||
+ (saved_facts.RequestCredit != sc->facts->RequestCredit) ||
+ (saved_facts.ProductID != sc->facts->ProductID) ||
+ (saved_facts.IOCCapabilities != sc->facts->IOCCapabilities) ||
+ (saved_facts.IOCRequestFrameSize !=
+ sc->facts->IOCRequestFrameSize) ||
+ (saved_facts.MaxTargets != sc->facts->MaxTargets) ||
+ (saved_facts.MaxSasExpanders != sc->facts->MaxSasExpanders) ||
+ (saved_facts.MaxEnclosures != sc->facts->MaxEnclosures) ||
+ (saved_facts.HighPriorityCredit != sc->facts->HighPriorityCredit) ||
+ (saved_facts.MaxReplyDescriptorPostQueueDepth !=
+ sc->facts->MaxReplyDescriptorPostQueueDepth) ||
+ (saved_facts.ReplyFrameSize != sc->facts->ReplyFrameSize) ||
+ (saved_facts.MaxVolumes != sc->facts->MaxVolumes) ||
+ (saved_facts.MaxPersistentEntries !=
+ sc->facts->MaxPersistentEntries))) {
+ reallocating = TRUE;
+ }
+
+ /*
+ * Some things should be done if attaching or re-allocating after a Diag
+ * Reset, but are not needed after a Diag Reset if the FW has not
+ * changed.
+ */
+ if (attaching || reallocating) {
+ /*
+ * Check if controller supports FW diag buffers and set flag to
+ * enable each type.
+ */
+ if (sc->facts->IOCCapabilities &
+ MPI2_IOCFACTS_CAPABILITY_DIAG_TRACE_BUFFER)
+ sc->fw_diag_buffer_list[MPI2_DIAG_BUF_TYPE_TRACE].
+ enabled = TRUE;
+ if (sc->facts->IOCCapabilities &
+ MPI2_IOCFACTS_CAPABILITY_SNAPSHOT_BUFFER)
+ sc->fw_diag_buffer_list[MPI2_DIAG_BUF_TYPE_SNAPSHOT].
+ enabled = TRUE;
+ if (sc->facts->IOCCapabilities &
+ MPI2_IOCFACTS_CAPABILITY_EXTENDED_BUFFER)
+ sc->fw_diag_buffer_list[MPI2_DIAG_BUF_TYPE_EXTENDED].
+ enabled = TRUE;
+
+ /*
+ * Set flag if EEDP is supported and if TLR is supported.
+ */
+ if (sc->facts->IOCCapabilities & MPI2_IOCFACTS_CAPABILITY_EEDP)
+ sc->eedp_enabled = TRUE;
+ if (sc->facts->IOCCapabilities & MPI2_IOCFACTS_CAPABILITY_TLR)
+ sc->control_TLR = TRUE;
+
+ /*
+ * Size the queues. Since the reply queues always need one free
+ * entry, we'll just deduct one reply message here.
+ */
+ sc->num_reqs = MIN(MPR_REQ_FRAMES, sc->facts->RequestCredit);
+ sc->num_replies = MIN(MPR_REPLY_FRAMES + MPR_EVT_REPLY_FRAMES,
+ sc->facts->MaxReplyDescriptorPostQueueDepth) - 1;
+
+ /*
+ * Initialize all Tail Queues
+ */
+ TAILQ_INIT(&sc->req_list);
+ TAILQ_INIT(&sc->high_priority_req_list);
+ TAILQ_INIT(&sc->chain_list);
+ TAILQ_INIT(&sc->tm_list);
+ }
+
+ /*
+ * If doing a Diag Reset and the FW is significantly different
+ * (reallocating will be set above in IOC Facts comparison), then all
+ * buffers based on the IOC Facts will need to be freed before they are
+ * reallocated.
+ */
+ if (reallocating) {
+ mpr_iocfacts_free(sc);
+
+ /*
+ * The number of targets is based on IOC Facts, so free all of
+ * the allocated LUNs for each target and then the target buffer
+ * itself.
+ */
+ for (i=0; i< saved_facts.MaxTargets; i++) {
+ targ = &sc->sassc->targets[i];
+ SLIST_FOREACH_SAFE(lun, &targ->luns, lun_link,
+ lun_tmp) {
+ free(lun, M_MPR);
+ }
+ }
+ free(sc->sassc->targets, M_MPR);
+
+ sc->sassc->targets = malloc(sizeof(struct mprsas_target) *
+ sc->facts->MaxTargets, M_MPR, M_WAITOK|M_ZERO);
+ if (!sc->sassc->targets) {
+ panic("%s failed to alloc targets with error %d\n",
+ __func__, ENOMEM);
+ }
+ }
+
+ /*
+ * Any deallocation has been completed. Now start reallocating
+ * if needed. Will only need to reallocate if attaching or if the new
+ * IOC Facts are different from the previous IOC Facts after a Diag
+ * Reset. Targets have already been allocated above if needed.
+ */
+ if (attaching || reallocating) {
+ if (((error = mpr_alloc_queues(sc)) != 0) ||
+ ((error = mpr_alloc_replies(sc)) != 0) ||
+ ((error = mpr_alloc_requests(sc)) != 0)) {
+ if (attaching ) {
+ mpr_dprint(sc, MPR_FAULT, "%s failed to alloc "
+ "queues with error %d\n", __func__, error);
+ mpr_free(sc);
+ return (error);
+ } else {
+ panic("%s failed to alloc queues with error "
+ "%d\n", __func__, error);
+ }
+ }
+ }
+
+ /* Always initialize the queues */
+ bzero(sc->free_queue, sc->fqdepth * 4);
+ mpr_init_queues(sc);
+
+ /*
+ * Always get the chip out of the reset state, but only panic if not
+ * attaching. If attaching and there is an error, that is handled by
+ * the OS.
+ */
+ error = mpr_transition_operational(sc);
+ if (error != 0) {
+ if (attaching) {
+ mpr_printf(sc, "%s failed to transition to "
+ "operational with error %d\n", __func__, error);
+ mpr_free(sc);
+ return (error);
+ } else {
+ panic("%s failed to transition to operational with "
+ "error %d\n", __func__, error);
+ }
+ }
+
+ /*
+ * Finish the queue initialization.
+ * These are set here instead of in mpr_init_queues() because the
+ * IOC resets these values during the state transition in
+ * mpr_transition_operational(). The free index is set to 1
+ * because the corresponding index in the IOC is set to 0, and the
+ * IOC treats the queues as full if both are set to the same value.
+ * Hence the reason that the queue can't hold all of the possible
+ * replies.
+ */
+ sc->replypostindex = 0;
+ mpr_regwrite(sc, MPI2_REPLY_FREE_HOST_INDEX_OFFSET, sc->replyfreeindex);
+ mpr_regwrite(sc, MPI2_REPLY_POST_HOST_INDEX_OFFSET, 0);
+
+ /*
+ * Attach the subsystems so they can prepare their event masks.
+ */
+ /* XXX Should be dynamic so that IM/IR and user modules can attach */
+ if (attaching) {
+ if (((error = mpr_attach_log(sc)) != 0) ||
+ ((error = mpr_attach_sas(sc)) != 0) ||
+ ((error = mpr_attach_user(sc)) != 0)) {
+ mpr_printf(sc, "%s failed to attach all subsystems: "
+ "error %d\n", __func__, error);
+ mpr_free(sc);
+ return (error);
+ }
+
+ if ((error = mpr_pci_setup_interrupts(sc)) != 0) {
+ mpr_printf(sc, "%s failed to setup interrupts\n",
+ __func__);
+ mpr_free(sc);
+ return (error);
+ }
+ }
+
+ return (error);
+}
+
+/*
+ * This is called if memory is being free (during detach for example) and when
+ * buffers need to be reallocated due to a Diag Reset.
+ */
+static void
+mpr_iocfacts_free(struct mpr_softc *sc)
+{
+ struct mpr_command *cm;
+ int i;
+
+ mpr_dprint(sc, MPR_TRACE, "%s\n", __func__);
+
+ if (sc->free_busaddr != 0)
+ bus_dmamap_unload(sc->queues_dmat, sc->queues_map);
+ if (sc->free_queue != NULL)
+ bus_dmamem_free(sc->queues_dmat, sc->free_queue,
+ sc->queues_map);
+ if (sc->queues_dmat != NULL)
+ bus_dma_tag_destroy(sc->queues_dmat);
+
+ if (sc->chain_busaddr != 0)
+ bus_dmamap_unload(sc->chain_dmat, sc->chain_map);
+ if (sc->chain_frames != NULL)
+ bus_dmamem_free(sc->chain_dmat, sc->chain_frames,
+ sc->chain_map);
+ if (sc->chain_dmat != NULL)
+ bus_dma_tag_destroy(sc->chain_dmat);
+
+ if (sc->sense_busaddr != 0)
+ bus_dmamap_unload(sc->sense_dmat, sc->sense_map);
+ if (sc->sense_frames != NULL)
+ bus_dmamem_free(sc->sense_dmat, sc->sense_frames,
+ sc->sense_map);
+ if (sc->sense_dmat != NULL)
+ bus_dma_tag_destroy(sc->sense_dmat);
+
+ if (sc->reply_busaddr != 0)
+ bus_dmamap_unload(sc->reply_dmat, sc->reply_map);
+ if (sc->reply_frames != NULL)
+ bus_dmamem_free(sc->reply_dmat, sc->reply_frames,
+ sc->reply_map);
+ if (sc->reply_dmat != NULL)
+ bus_dma_tag_destroy(sc->reply_dmat);
+
+ if (sc->req_busaddr != 0)
+ bus_dmamap_unload(sc->req_dmat, sc->req_map);
+ if (sc->req_frames != NULL)
+ bus_dmamem_free(sc->req_dmat, sc->req_frames, sc->req_map);
+ if (sc->req_dmat != NULL)
+ bus_dma_tag_destroy(sc->req_dmat);
+
+ if (sc->chains != NULL)
+ free(sc->chains, M_MPR);
+ if (sc->commands != NULL) {
+ for (i = 1; i < sc->num_reqs; i++) {
+ cm = &sc->commands[i];
+ bus_dmamap_destroy(sc->buffer_dmat, cm->cm_dmamap);
+ }
+ free(sc->commands, M_MPR);
+ }
+ if (sc->buffer_dmat != NULL)
+ bus_dma_tag_destroy(sc->buffer_dmat);
+}
+
+/*
+ * The terms diag reset and hard reset are used interchangeably in the MPI
+ * docs to mean resetting the controller chip. In this code diag reset
+ * cleans everything up, and the hard reset function just sends the reset
+ * sequence to the chip. This should probably be refactored so that every
+ * subsystem gets a reset notification of some sort, and can clean up
+ * appropriately.
+ */
+int
+mpr_reinit(struct mpr_softc *sc)
+{
+ int error;
+ struct mprsas_softc *sassc;
+
+ sassc = sc->sassc;
+
+ MPR_FUNCTRACE(sc);
+
+ mtx_assert(&sc->mpr_mtx, MA_OWNED);
+
+ if (sc->mpr_flags & MPR_FLAGS_DIAGRESET) {
+ mpr_dprint(sc, MPR_INIT, "%s reset already in progress\n",
+ __func__);
+ return 0;
+ }
+
+ mpr_dprint(sc, MPR_INFO, "Reinitializing controller,\n");
+ /* make sure the completion callbacks can recognize they're getting
+ * a NULL cm_reply due to a reset.
+ */
+ sc->mpr_flags |= MPR_FLAGS_DIAGRESET;
+
+ /*
+ * Mask interrupts here.
+ */
+ mpr_dprint(sc, MPR_INIT, "%s mask interrupts\n", __func__);
+ mpr_mask_intr(sc);
+
+ error = mpr_diag_reset(sc, CAN_SLEEP);
+ if (error != 0) {
+ panic("%s hard reset failed with error %d\n", __func__, error);
+ }
+
+ /* Restore the PCI state, including the MSI-X registers */
+ mpr_pci_restore(sc);
+
+ /* Give the I/O subsystem special priority to get itself prepared */
+ mprsas_handle_reinit(sc);
+
+ /*
+ * Get IOC Facts and allocate all structures based on this information.
+ * The attach function will also call mpr_iocfacts_allocate at startup.
+ * If relevant values have changed in IOC Facts, this function will free
+ * all of the memory based on IOC Facts and reallocate that memory.
+ */
+ if ((error = mpr_iocfacts_allocate(sc, FALSE)) != 0) {
+ panic("%s IOC Facts based allocation failed with error %d\n",
+ __func__, error);
+ }
+
+ /*
+ * Mapping structures will be re-allocated after getting IOC Page8, so
+ * free these structures here.
+ */
+ mpr_mapping_exit(sc);
+
+ /*
+ * The static page function currently read is IOC Page8. Others can be
+ * added in future. It's possible that the values in IOC Page8 have
+ * changed after a Diag Reset due to user modification, so always read
+ * these. Interrupts are masked, so unmask them before getting config
+ * pages.
+ */
+ mpr_unmask_intr(sc);
+ sc->mpr_flags &= ~MPR_FLAGS_DIAGRESET;
+ mpr_base_static_config_pages(sc);
+
+ /*
+ * Some mapping info is based in IOC Page8 data, so re-initialize the
+ * mapping tables.
+ */
+ mpr_mapping_initialize(sc);
+
+ /*
+ * Restart will reload the event masks clobbered by the reset, and
+ * then enable the port.
+ */
+ mpr_reregister_events(sc);
+
+ /* the end of discovery will release the simq, so we're done. */
+ mpr_dprint(sc, MPR_INFO, "%s finished sc %p post %u free %u\n",
+ __func__, sc, sc->replypostindex, sc->replyfreeindex);
+ mprsas_release_simq_reinit(sassc);
+
+ return 0;
+}
+
+/* Wait for the chip to ACK a word that we've put into its FIFO
+ * Wait for <timeout> seconds. In single loop wait for busy loop
+ * for 500 microseconds.
+ * Total is [ 0.5 * (2000 * <timeout>) ] in miliseconds.
+ * */
+static int
+mpr_wait_db_ack(struct mpr_softc *sc, 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 = mpr_regread(sc, MPI2_HOST_INTERRUPT_STATUS_OFFSET);
+ if (!(int_status & MPI2_HIS_SYS2IOC_DB_STATUS)) {
+ mpr_dprint(sc, MPR_INIT, "%s: successful count(%d), "
+ "timeout(%d)\n", __func__, count, timeout);
+ return 0;
+ } else if (int_status & MPI2_HIS_IOC2SYS_DB_STATUS) {
+ doorbell = mpr_regread(sc, MPI2_DOORBELL_OFFSET);
+ if ((doorbell & MPI2_IOC_STATE_MASK) ==
+ MPI2_IOC_STATE_FAULT) {
+ mpr_dprint(sc, MPR_FAULT,
+ "fault_state(0x%04x)!\n", doorbell);
+ return (EFAULT);
+ }
+ } else if (int_status == 0xFFFFFFFF)
+ goto out;
+
+ /*
+ * If it can sleep, sleep for 1 milisecond, else busy loop for
+ * 0.5 milisecond
+ */
+ if (mtx_owned(&sc->mpr_mtx) && sleep_flag == CAN_SLEEP)
+ msleep(&sc->msleep_fake_chan, &sc->mpr_mtx, 0, "mprdba", hz/1000);
+ else if (sleep_flag == CAN_SLEEP)
+ pause("mprdba", hz/1000);
+ else
+ DELAY(500);
+ count++;
+ } while (--cntdn);
+
+ out:
+ mpr_dprint(sc, MPR_FAULT, "%s: failed due to timeout count(%d), "
+ "int_status(%x)!\n", __func__, count, int_status);
+ return (ETIMEDOUT);
+}
+
+/* Wait for the chip to signal that the next word in its FIFO can be fetched */
+static int
+mpr_wait_db_int(struct mpr_softc *sc)
+{
+ int retry;
+
+ for (retry = 0; retry < MPR_DB_MAX_WAIT; retry++) {
+ if ((mpr_regread(sc, MPI2_HOST_INTERRUPT_STATUS_OFFSET) &
+ MPI2_HIS_IOC2SYS_DB_STATUS) != 0)
+ return (0);
+ DELAY(2000);
+ }
+ return (ETIMEDOUT);
+}
+
+/* Step through the synchronous command state machine, i.e. "Doorbell mode" */
+static int
+mpr_request_sync(struct mpr_softc *sc, void *req, MPI2_DEFAULT_REPLY *reply,
+ int req_sz, int reply_sz, int timeout)
+{
+ uint32_t *data32;
+ uint16_t *data16;
+ int i, count, ioc_sz, residual;
+ int sleep_flags = CAN_SLEEP;
+
+#if __FreeBSD_version >= 1000029
+ if (curthread->td_no_sleeping)
+#else //__FreeBSD_version < 1000029
+ if (curthread->td_pflags & TDP_NOSLEEPING)
+#endif //__FreeBSD_version >= 1000029
+ sleep_flags = NO_SLEEP;
+
+ /* Step 1 */
+ mpr_regwrite(sc, MPI2_HOST_INTERRUPT_STATUS_OFFSET, 0x0);
+
+ /* Step 2 */
+ if (mpr_regread(sc, MPI2_DOORBELL_OFFSET) & MPI2_DOORBELL_USED)
+ return (EBUSY);
+
+ /* Step 3
+ * Announce that a message is coming through the doorbell. Messages
+ * are pushed at 32bit words, so round up if needed.
+ */
+ count = (req_sz + 3) / 4;
+ mpr_regwrite(sc, MPI2_DOORBELL_OFFSET,
+ (MPI2_FUNCTION_HANDSHAKE << MPI2_DOORBELL_FUNCTION_SHIFT) |
+ (count << MPI2_DOORBELL_ADD_DWORDS_SHIFT));
+
+ /* Step 4 */
+ if (mpr_wait_db_int(sc) ||
+ (mpr_regread(sc, MPI2_DOORBELL_OFFSET) & MPI2_DOORBELL_USED) == 0) {
+ mpr_dprint(sc, MPR_FAULT, "Doorbell failed to activate\n");
+ return (ENXIO);
+ }
+ mpr_regwrite(sc, MPI2_HOST_INTERRUPT_STATUS_OFFSET, 0x0);
+ if (mpr_wait_db_ack(sc, 5, sleep_flags) != 0) {
+ mpr_dprint(sc, MPR_FAULT, "Doorbell handshake failed\n");
+ return (ENXIO);
+ }
+
+ /* Step 5 */
+ /* Clock out the message data synchronously in 32-bit dwords*/
+ data32 = (uint32_t *)req;
+ for (i = 0; i < count; i++) {
+ mpr_regwrite(sc, MPI2_DOORBELL_OFFSET, htole32(data32[i]));
+ if (mpr_wait_db_ack(sc, 5, sleep_flags) != 0) {
+ mpr_dprint(sc, MPR_FAULT,
+ "Timeout while writing doorbell\n");
+ return (ENXIO);
+ }
+ }
+
+ /* Step 6 */
+ /* Clock in the reply in 16-bit words. The total length of the
+ * message is always in the 4th byte, so clock out the first 2 words
+ * manually, then loop the rest.
+ */
+ data16 = (uint16_t *)reply;
+ if (mpr_wait_db_int(sc) != 0) {
+ mpr_dprint(sc, MPR_FAULT, "Timeout reading doorbell 0\n");
+ return (ENXIO);
+ }
+ data16[0] =
+ mpr_regread(sc, MPI2_DOORBELL_OFFSET) & MPI2_DOORBELL_DATA_MASK;
+ mpr_regwrite(sc, MPI2_HOST_INTERRUPT_STATUS_OFFSET, 0x0);
+ if (mpr_wait_db_int(sc) != 0) {
+ mpr_dprint(sc, MPR_FAULT, "Timeout reading doorbell 1\n");
+ return (ENXIO);
+ }
+ data16[1] =
+ mpr_regread(sc, MPI2_DOORBELL_OFFSET) & MPI2_DOORBELL_DATA_MASK;
+ mpr_regwrite(sc, MPI2_HOST_INTERRUPT_STATUS_OFFSET, 0x0);
+
+ /* Number of 32bit words in the message */
+ ioc_sz = reply->MsgLength;
+
+ /*
+ * Figure out how many 16bit words to clock in without overrunning.
+ * The precision loss with dividing reply_sz can safely be
+ * ignored because the messages can only be multiples of 32bits.
+ */
+ residual = 0;
+ count = MIN((reply_sz / 4), ioc_sz) * 2;
+ if (count < ioc_sz * 2) {
+ residual = ioc_sz * 2 - count;
+ mpr_dprint(sc, MPR_ERROR, "Driver error, throwing away %d "
+ "residual message words\n", residual);
+ }
+
+ for (i = 2; i < count; i++) {
+ if (mpr_wait_db_int(sc) != 0) {
+ mpr_dprint(sc, MPR_FAULT,
+ "Timeout reading doorbell %d\n", i);
+ return (ENXIO);
+ }
+ data16[i] = mpr_regread(sc, MPI2_DOORBELL_OFFSET) &
+ MPI2_DOORBELL_DATA_MASK;
+ mpr_regwrite(sc, MPI2_HOST_INTERRUPT_STATUS_OFFSET, 0x0);
+ }
+
+ /*
+ * Pull out residual words that won't fit into the provided buffer.
+ * This keeps the chip from hanging due to a driver programming
+ * error.
+ */
+ while (residual--) {
+ if (mpr_wait_db_int(sc) != 0) {
+ mpr_dprint(sc, MPR_FAULT, "Timeout reading doorbell\n");
+ return (ENXIO);
+ }
+ (void)mpr_regread(sc, MPI2_DOORBELL_OFFSET);
+ mpr_regwrite(sc, MPI2_HOST_INTERRUPT_STATUS_OFFSET, 0x0);
+ }
+
+ /* Step 7 */
+ if (mpr_wait_db_int(sc) != 0) {
+ mpr_dprint(sc, MPR_FAULT, "Timeout waiting to exit doorbell\n");
+ return (ENXIO);
+ }
+ if (mpr_regread(sc, MPI2_DOORBELL_OFFSET) & MPI2_DOORBELL_USED)
+ mpr_dprint(sc, MPR_FAULT, "Warning, doorbell still active\n");
+ mpr_regwrite(sc, MPI2_HOST_INTERRUPT_STATUS_OFFSET, 0x0);
+
+ return (0);
+}
+
+static void
+mpr_enqueue_request(struct mpr_softc *sc, struct mpr_command *cm)
+{
+ reply_descriptor rd;
+
+ MPR_FUNCTRACE(sc);
+ mpr_dprint(sc, MPR_TRACE, "%s SMID %u cm %p ccb %p\n", __func__,
+ cm->cm_desc.Default.SMID, cm, cm->cm_ccb);
+
+ if (sc->mpr_flags & MPR_FLAGS_ATTACH_DONE && !(sc->mpr_flags &
+ MPR_FLAGS_SHUTDOWN))
+ mtx_assert(&sc->mpr_mtx, MA_OWNED);
+
+ if (++sc->io_cmds_active > sc->io_cmds_highwater)
+ sc->io_cmds_highwater++;
+
+ rd.u.low = cm->cm_desc.Words.Low;
+ rd.u.high = cm->cm_desc.Words.High;
+ rd.word = htole64(rd.word);
+ /* TODO-We may need to make below regwrite atomic */
+ mpr_regwrite(sc, MPI2_REQUEST_DESCRIPTOR_POST_LOW_OFFSET,
+ rd.u.low);
+ mpr_regwrite(sc, MPI2_REQUEST_DESCRIPTOR_POST_HIGH_OFFSET,
+ rd.u.high);
+}
+
+/*
+ * Just the FACTS, ma'am.
+ */
+static int
+mpr_get_iocfacts(struct mpr_softc *sc, MPI2_IOC_FACTS_REPLY *facts)
+{
+ MPI2_DEFAULT_REPLY *reply;
+ MPI2_IOC_FACTS_REQUEST request;
+ int error, req_sz, reply_sz;
+
+ MPR_FUNCTRACE(sc);
+
+ req_sz = sizeof(MPI2_IOC_FACTS_REQUEST);
+ reply_sz = sizeof(MPI2_IOC_FACTS_REPLY);
+ reply = (MPI2_DEFAULT_REPLY *)facts;
+
+ bzero(&request, req_sz);
+ request.Function = MPI2_FUNCTION_IOC_FACTS;
+ error = mpr_request_sync(sc, &request, reply, req_sz, reply_sz, 5);
+
+ return (error);
+}
+
+static int
+mpr_send_iocinit(struct mpr_softc *sc)
+{
+ MPI2_IOC_INIT_REQUEST init;
+ MPI2_DEFAULT_REPLY reply;
+ int req_sz, reply_sz, error;
+ struct timeval now;
+ uint64_t time_in_msec;
+
+ MPR_FUNCTRACE(sc);
+
+ req_sz = sizeof(MPI2_IOC_INIT_REQUEST);
+ reply_sz = sizeof(MPI2_IOC_INIT_REPLY);
+ bzero(&init, req_sz);
+ bzero(&reply, reply_sz);
+
+ /*
+ * Fill in the init block. Note that most addresses are
+ * deliberately in the lower 32bits of memory. This is a micro-
+ * optimzation for PCI/PCIX, though it's not clear if it helps PCIe.
+ */
+ init.Function = MPI2_FUNCTION_IOC_INIT;
+ init.WhoInit = MPI2_WHOINIT_HOST_DRIVER;
+ init.MsgVersion = htole16(MPI2_VERSION);
+ init.HeaderVersion = htole16(MPI2_HEADER_VERSION);
+ init.SystemRequestFrameSize = htole16(sc->facts->IOCRequestFrameSize);
+ init.ReplyDescriptorPostQueueDepth = htole16(sc->pqdepth);
+ init.ReplyFreeQueueDepth = htole16(sc->fqdepth);
+ init.SenseBufferAddressHigh = 0;
+ init.SystemReplyAddressHigh = 0;
+ init.SystemRequestFrameBaseAddress.High = 0;
+ init.SystemRequestFrameBaseAddress.Low =
+ htole32((uint32_t)sc->req_busaddr);
+ init.ReplyDescriptorPostQueueAddress.High = 0;
+ init.ReplyDescriptorPostQueueAddress.Low =
+ htole32((uint32_t)sc->post_busaddr);
+ init.ReplyFreeQueueAddress.High = 0;
+ init.ReplyFreeQueueAddress.Low = htole32((uint32_t)sc->free_busaddr);
+ getmicrotime(&now);
+ time_in_msec = (now.tv_sec * 1000 + now.tv_usec/1000);
+ init.TimeStamp.High = htole32((time_in_msec >> 32) & 0xFFFFFFFF);
+ init.TimeStamp.Low = htole32(time_in_msec & 0xFFFFFFFF);
+
+ error = mpr_request_sync(sc, &init, &reply, req_sz, reply_sz, 5);
+ if ((reply.IOCStatus & MPI2_IOCSTATUS_MASK) != MPI2_IOCSTATUS_SUCCESS)
+ error = ENXIO;
+
+ mpr_dprint(sc, MPR_INIT, "IOCInit status= 0x%x\n", reply.IOCStatus);
+ return (error);
+}
+
+void
+mpr_memaddr_cb(void *arg, bus_dma_segment_t *segs, int nsegs, int error)
+{
+ bus_addr_t *addr;
+
+ addr = arg;
+ *addr = segs[0].ds_addr;
+}
+
+static int
+mpr_alloc_queues(struct mpr_softc *sc)
+{
+ bus_addr_t queues_busaddr;
+ uint8_t *queues;
+ int qsize, fqsize, pqsize;
+
+ /*
+ * The reply free queue contains 4 byte entries in multiples of 16 and
+ * aligned on a 16 byte boundary. There must always be an unused entry.
+ * This queue supplies fresh reply frames for the firmware to use.
+ *
+ * The reply descriptor post queue contains 8 byte entries in
+ * multiples of 16 and aligned on a 16 byte boundary. This queue
+ * contains filled-in reply frames sent from the firmware to the host.
+ *
+ * These two queues are allocated together for simplicity.
+ */
+ sc->fqdepth = roundup2((sc->num_replies + 1), 16);
+ sc->pqdepth = roundup2((sc->num_replies + 1), 16);
+ fqsize= sc->fqdepth * 4;
+ pqsize = sc->pqdepth * 8;
+ qsize = fqsize + pqsize;
+
+ if (bus_dma_tag_create( sc->mpr_parent_dmat, /* parent */
+ 16, 0, /* algnmnt, boundary */
+ BUS_SPACE_MAXADDR_32BIT,/* lowaddr */
+ BUS_SPACE_MAXADDR, /* highaddr */
+ NULL, NULL, /* filter, filterarg */
+ qsize, /* maxsize */
+ 1, /* nsegments */
+ qsize, /* maxsegsize */
+ 0, /* flags */
+ NULL, NULL, /* lockfunc, lockarg */
+ &sc->queues_dmat)) {
+ device_printf(sc->mpr_dev, "Cannot allocate queues DMA tag\n");
+ return (ENOMEM);
+ }
+ if (bus_dmamem_alloc(sc->queues_dmat, (void **)&queues, BUS_DMA_NOWAIT,
+ &sc->queues_map)) {
+ device_printf(sc->mpr_dev, "Cannot allocate queues memory\n");
+ return (ENOMEM);
+ }
+ bzero(queues, qsize);
+ bus_dmamap_load(sc->queues_dmat, sc->queues_map, queues, qsize,
+ mpr_memaddr_cb, &queues_busaddr, 0);
+
+ sc->free_queue = (uint32_t *)queues;
+ sc->free_busaddr = queues_busaddr;
+ sc->post_queue = (MPI2_REPLY_DESCRIPTORS_UNION *)(queues + fqsize);
+ sc->post_busaddr = queues_busaddr + fqsize;
+
+ return (0);
+}
+
+static int
+mpr_alloc_replies(struct mpr_softc *sc)
+{
+ int rsize, num_replies;
+
+ /*
+ * sc->num_replies should be one less than sc->fqdepth. We need to
+ * allocate space for sc->fqdepth replies, but only sc->num_replies
+ * replies can be used at once.
+ */
+ num_replies = max(sc->fqdepth, sc->num_replies);
+
+ rsize = sc->facts->ReplyFrameSize * num_replies * 4;
+ if (bus_dma_tag_create( sc->mpr_parent_dmat, /* parent */
+ 4, 0, /* algnmnt, boundary */
+ BUS_SPACE_MAXADDR_32BIT,/* lowaddr */
+ BUS_SPACE_MAXADDR, /* highaddr */
+ NULL, NULL, /* filter, filterarg */
+ rsize, /* maxsize */
+ 1, /* nsegments */
+ rsize, /* maxsegsize */
+ 0, /* flags */
+ NULL, NULL, /* lockfunc, lockarg */
+ &sc->reply_dmat)) {
+ device_printf(sc->mpr_dev, "Cannot allocate replies DMA tag\n");
+ return (ENOMEM);
+ }
+ if (bus_dmamem_alloc(sc->reply_dmat, (void **)&sc->reply_frames,
+ BUS_DMA_NOWAIT, &sc->reply_map)) {
+ device_printf(sc->mpr_dev, "Cannot allocate replies memory\n");
+ return (ENOMEM);
+ }
+ bzero(sc->reply_frames, rsize);
+ bus_dmamap_load(sc->reply_dmat, sc->reply_map, sc->reply_frames, rsize,
+ mpr_memaddr_cb, &sc->reply_busaddr, 0);
+
+ return (0);
+}
+
+static int
+mpr_alloc_requests(struct mpr_softc *sc)
+{
+ struct mpr_command *cm;
+ struct mpr_chain *chain;
+ int i, rsize, nsegs;
+
+ rsize = sc->facts->IOCRequestFrameSize * sc->num_reqs * 4;
+ if (bus_dma_tag_create( sc->mpr_parent_dmat, /* parent */
+ 16, 0, /* algnmnt, boundary */
+ BUS_SPACE_MAXADDR_32BIT,/* lowaddr */
+ BUS_SPACE_MAXADDR, /* highaddr */
+ NULL, NULL, /* filter, filterarg */
+ rsize, /* maxsize */
+ 1, /* nsegments */
+ rsize, /* maxsegsize */
+ 0, /* flags */
+ NULL, NULL, /* lockfunc, lockarg */
+ &sc->req_dmat)) {
+ device_printf(sc->mpr_dev, "Cannot allocate request DMA tag\n");
+ return (ENOMEM);
+ }
+ if (bus_dmamem_alloc(sc->req_dmat, (void **)&sc->req_frames,
+ BUS_DMA_NOWAIT, &sc->req_map)) {
+ device_printf(sc->mpr_dev, "Cannot allocate request memory\n");
+ return (ENOMEM);
+ }
+ bzero(sc->req_frames, rsize);
+ bus_dmamap_load(sc->req_dmat, sc->req_map, sc->req_frames, rsize,
+ mpr_memaddr_cb, &sc->req_busaddr, 0);
+
+ rsize = sc->facts->IOCRequestFrameSize * sc->max_chains * 4;
+ if (bus_dma_tag_create( sc->mpr_parent_dmat, /* parent */
+ 16, 0, /* algnmnt, boundary */
+ BUS_SPACE_MAXADDR, /* lowaddr */
+ BUS_SPACE_MAXADDR, /* highaddr */
+ NULL, NULL, /* filter, filterarg */
+ rsize, /* maxsize */
+ 1, /* nsegments */
+ rsize, /* maxsegsize */
+ 0, /* flags */
+ NULL, NULL, /* lockfunc, lockarg */
+ &sc->chain_dmat)) {
+ device_printf(sc->mpr_dev, "Cannot allocate chain DMA tag\n");
+ return (ENOMEM);
+ }
+ if (bus_dmamem_alloc(sc->chain_dmat, (void **)&sc->chain_frames,
+ BUS_DMA_NOWAIT, &sc->chain_map)) {
+ device_printf(sc->mpr_dev, "Cannot allocate chain memory\n");
+ return (ENOMEM);
+ }
+ bzero(sc->chain_frames, rsize);
+ bus_dmamap_load(sc->chain_dmat, sc->chain_map, sc->chain_frames, rsize,
+ mpr_memaddr_cb, &sc->chain_busaddr, 0);
+
+ rsize = MPR_SENSE_LEN * sc->num_reqs;
+ if (bus_dma_tag_create( sc->mpr_parent_dmat, /* parent */
+ 1, 0, /* algnmnt, boundary */
+ BUS_SPACE_MAXADDR_32BIT,/* lowaddr */
+ BUS_SPACE_MAXADDR, /* highaddr */
+ NULL, NULL, /* filter, filterarg */
+ rsize, /* maxsize */
+ 1, /* nsegments */
+ rsize, /* maxsegsize */
+ 0, /* flags */
+ NULL, NULL, /* lockfunc, lockarg */
+ &sc->sense_dmat)) {
+ device_printf(sc->mpr_dev, "Cannot allocate sense DMA tag\n");
+ return (ENOMEM);
+ }
+ if (bus_dmamem_alloc(sc->sense_dmat, (void **)&sc->sense_frames,
+ BUS_DMA_NOWAIT, &sc->sense_map)) {
+ device_printf(sc->mpr_dev, "Cannot allocate sense memory\n");
+ return (ENOMEM);
+ }
+ bzero(sc->sense_frames, rsize);
+ bus_dmamap_load(sc->sense_dmat, sc->sense_map, sc->sense_frames, rsize,
+ mpr_memaddr_cb, &sc->sense_busaddr, 0);
+
+ sc->chains = malloc(sizeof(struct mpr_chain) * sc->max_chains, M_MPR,
+ M_WAITOK | M_ZERO);
+ if (!sc->chains) {
+ device_printf(sc->mpr_dev, "Cannot allocate memory %s %d\n",
+ __func__, __LINE__);
+ return (ENOMEM);
+ }
+ for (i = 0; i < sc->max_chains; i++) {
+ chain = &sc->chains[i];
+ chain->chain = (MPI2_SGE_IO_UNION *)(sc->chain_frames +
+ i * sc->facts->IOCRequestFrameSize * 4);
+ chain->chain_busaddr = sc->chain_busaddr +
+ i * sc->facts->IOCRequestFrameSize * 4;
+ mpr_free_chain(sc, chain);
+ sc->chain_free_lowwater++;
+ }
+
+ /* XXX Need to pick a more precise value */
+ nsegs = (MAXPHYS / PAGE_SIZE) + 1;
+ if (bus_dma_tag_create( sc->mpr_parent_dmat, /* parent */
+ 1, 0, /* algnmnt, boundary */
+ BUS_SPACE_MAXADDR, /* lowaddr */
+ BUS_SPACE_MAXADDR, /* highaddr */
+ NULL, NULL, /* filter, filterarg */
+ BUS_SPACE_MAXSIZE_32BIT,/* maxsize */
+ nsegs, /* nsegments */
+ BUS_SPACE_MAXSIZE_32BIT,/* maxsegsize */
+ BUS_DMA_ALLOCNOW, /* flags */
+ busdma_lock_mutex, /* lockfunc */
+ &sc->mpr_mtx, /* lockarg */
+ &sc->buffer_dmat)) {
+ device_printf(sc->mpr_dev, "Cannot allocate buffer DMA tag\n");
+ return (ENOMEM);
+ }
+
+ /*
+ * SMID 0 cannot be used as a free command per the firmware spec.
+ * Just drop that command instead of risking accounting bugs.
+ */
+ sc->commands = malloc(sizeof(struct mpr_command) * sc->num_reqs,
+ M_MPR, M_WAITOK | M_ZERO);
+ if (!sc->commands) {
+ device_printf(sc->mpr_dev, "Cannot allocate memory %s %d\n",
+ __func__, __LINE__);
+ return (ENOMEM);
+ }
+ for (i = 1; i < sc->num_reqs; i++) {
+ cm = &sc->commands[i];
+ cm->cm_req = sc->req_frames +
+ i * sc->facts->IOCRequestFrameSize * 4;
+ cm->cm_req_busaddr = sc->req_busaddr +
+ i * sc->facts->IOCRequestFrameSize * 4;
+ cm->cm_sense = &sc->sense_frames[i];
+ cm->cm_sense_busaddr = sc->sense_busaddr + i * MPR_SENSE_LEN;
+ cm->cm_desc.Default.SMID = i;
+ cm->cm_sc = sc;
+ TAILQ_INIT(&cm->cm_chain_list);
+ callout_init_mtx(&cm->cm_callout, &sc->mpr_mtx, 0);
+
+ /* XXX Is a failure here a critical problem? */
+ if (bus_dmamap_create(sc->buffer_dmat, 0, &cm->cm_dmamap) == 0)
+ if (i <= sc->facts->HighPriorityCredit)
+ mpr_free_high_priority_command(sc, cm);
+ else
+ mpr_free_command(sc, cm);
+ else {
+ panic("failed to allocate command %d\n", i);
+ sc->num_reqs = i;
+ break;
+ }
+ }
+
+ return (0);
+}
+
+static int
+mpr_init_queues(struct mpr_softc *sc)
+{
+ int i;
+
+ memset((uint8_t *)sc->post_queue, 0xff, sc->pqdepth * 8);
+
+ /*
+ * According to the spec, we need to use one less reply than we
+ * have space for on the queue. So sc->num_replies (the number we
+ * use) should be less than sc->fqdepth (allocated size).
+ */
+ if (sc->num_replies >= sc->fqdepth)
+ return (EINVAL);
+
+ /*
+ * Initialize all of the free queue entries.
+ */
+ for (i = 0; i < sc->fqdepth; i++)
+ sc->free_queue[i] = sc->reply_busaddr + (i * sc->facts->ReplyFrameSize * 4);
+ sc->replyfreeindex = sc->num_replies;
+
+ return (0);
+}
+
+/* Get the driver parameter tunables. Lowest priority are the driver defaults.
+ * Next are the global settings, if they exist. Highest are the per-unit
+ * settings, if they exist.
+ */
+static void
+mpr_get_tunables(struct mpr_softc *sc)
+{
+ char tmpstr[80];
+
+ /* XXX default to some debugging for now */
+ sc->mpr_debug = MPR_INFO | MPR_FAULT;
+ sc->disable_msix = 0;
+ sc->disable_msi = 0;
+ sc->max_chains = MPR_CHAIN_FRAMES;
+
+ /*
+ * Grab the global variables.
+ */
+ TUNABLE_INT_FETCH("hw.mpr.debug_level", &sc->mpr_debug);
+ TUNABLE_INT_FETCH("hw.mpr.disable_msix", &sc->disable_msix);
+ TUNABLE_INT_FETCH("hw.mpr.disable_msi", &sc->disable_msi);
+ TUNABLE_INT_FETCH("hw.mpr.max_chains", &sc->max_chains);
+
+ /* Grab the unit-instance variables */
+ snprintf(tmpstr, sizeof(tmpstr), "dev.mpr.%d.debug_level",
+ device_get_unit(sc->mpr_dev));
+ TUNABLE_INT_FETCH(tmpstr, &sc->mpr_debug);
+
+ snprintf(tmpstr, sizeof(tmpstr), "dev.mpr.%d.disable_msix",
+ device_get_unit(sc->mpr_dev));
+ TUNABLE_INT_FETCH(tmpstr, &sc->disable_msix);
+
+ snprintf(tmpstr, sizeof(tmpstr), "dev.mpr.%d.disable_msi",
+ device_get_unit(sc->mpr_dev));
+ TUNABLE_INT_FETCH(tmpstr, &sc->disable_msi);
+
+ snprintf(tmpstr, sizeof(tmpstr), "dev.mpr.%d.max_chains",
+ device_get_unit(sc->mpr_dev));
+ TUNABLE_INT_FETCH(tmpstr, &sc->max_chains);
+
+ bzero(sc->exclude_ids, sizeof(sc->exclude_ids));
+ snprintf(tmpstr, sizeof(tmpstr), "dev.mpr.%d.exclude_ids",
+ device_get_unit(sc->mpr_dev));
+ TUNABLE_STR_FETCH(tmpstr, sc->exclude_ids, sizeof(sc->exclude_ids));
+}
+
+static void
+mpr_setup_sysctl(struct mpr_softc *sc)
+{
+ struct sysctl_ctx_list *sysctl_ctx = NULL;
+ struct sysctl_oid *sysctl_tree = NULL;
+ char tmpstr[80], tmpstr2[80];
+
+ /*
+ * Setup the sysctl variable so the user can change the debug level
+ * on the fly.
+ */
+ snprintf(tmpstr, sizeof(tmpstr), "MPR controller %d",
+ device_get_unit(sc->mpr_dev));
+ snprintf(tmpstr2, sizeof(tmpstr2), "%d", device_get_unit(sc->mpr_dev));
+
+ sysctl_ctx = device_get_sysctl_ctx(sc->mpr_dev);
+ if (sysctl_ctx != NULL)
+ sysctl_tree = device_get_sysctl_tree(sc->mpr_dev);
+
+ if (sysctl_tree == NULL) {
+ sysctl_ctx_init(&sc->sysctl_ctx);
+ sc->sysctl_tree = SYSCTL_ADD_NODE(&sc->sysctl_ctx,
+ SYSCTL_STATIC_CHILDREN(_hw_mpr), OID_AUTO, tmpstr2,
+ CTLFLAG_RD, 0, tmpstr);
+ if (sc->sysctl_tree == NULL)
+ return;
+ sysctl_ctx = &sc->sysctl_ctx;
+ sysctl_tree = sc->sysctl_tree;
+ }
+
+ SYSCTL_ADD_INT(sysctl_ctx, SYSCTL_CHILDREN(sysctl_tree),
+ OID_AUTO, "debug_level", CTLFLAG_RW, &sc->mpr_debug, 0,
+ "mpr debug level");
+
+ SYSCTL_ADD_INT(sysctl_ctx, SYSCTL_CHILDREN(sysctl_tree),
+ OID_AUTO, "disable_msix", CTLFLAG_RD, &sc->disable_msix, 0,
+ "Disable the use of MSI-X interrupts");
+
+ SYSCTL_ADD_INT(sysctl_ctx, SYSCTL_CHILDREN(sysctl_tree),
+ OID_AUTO, "disable_msi", CTLFLAG_RD, &sc->disable_msi, 0,
+ "Disable the use of MSI interrupts");
+
+ SYSCTL_ADD_STRING(sysctl_ctx, SYSCTL_CHILDREN(sysctl_tree),
+ OID_AUTO, "firmware_version", CTLFLAG_RW, &sc->fw_version,
+ strlen(sc->fw_version), "firmware version");
+
+ SYSCTL_ADD_STRING(sysctl_ctx, SYSCTL_CHILDREN(sysctl_tree),
+ OID_AUTO, "driver_version", CTLFLAG_RW, MPR_DRIVER_VERSION,
+ strlen(MPR_DRIVER_VERSION), "driver version");
+
+ SYSCTL_ADD_INT(sysctl_ctx, SYSCTL_CHILDREN(sysctl_tree),
+ OID_AUTO, "io_cmds_active", CTLFLAG_RD,
+ &sc->io_cmds_active, 0, "number of currently active commands");
+
+ SYSCTL_ADD_INT(sysctl_ctx, SYSCTL_CHILDREN(sysctl_tree),
+ OID_AUTO, "io_cmds_highwater", CTLFLAG_RD,
+ &sc->io_cmds_highwater, 0, "maximum active commands seen");
+
+ SYSCTL_ADD_INT(sysctl_ctx, SYSCTL_CHILDREN(sysctl_tree),
+ OID_AUTO, "chain_free", CTLFLAG_RD,
+ &sc->chain_free, 0, "number of free chain elements");
+
+ SYSCTL_ADD_INT(sysctl_ctx, SYSCTL_CHILDREN(sysctl_tree),
+ OID_AUTO, "chain_free_lowwater", CTLFLAG_RD,
+ &sc->chain_free_lowwater, 0,"lowest number of free chain elements");
+
+ SYSCTL_ADD_INT(sysctl_ctx, SYSCTL_CHILDREN(sysctl_tree),
+ OID_AUTO, "max_chains", CTLFLAG_RD,
+ &sc->max_chains, 0,"maximum chain frames that will be allocated");
+
+#if __FreeBSD_version >= 900030
+ SYSCTL_ADD_UQUAD(sysctl_ctx, SYSCTL_CHILDREN(sysctl_tree),
+ OID_AUTO, "chain_alloc_fail", CTLFLAG_RD,
+ &sc->chain_alloc_fail, "chain allocation failures");
+#endif //FreeBSD_version >= 900030
+}
+
+int
+mpr_attach(struct mpr_softc *sc)
+{
+ int error;
+
+ mpr_get_tunables(sc);
+
+ MPR_FUNCTRACE(sc);
+
+ mtx_init(&sc->mpr_mtx, "MPR lock", NULL, MTX_DEF);
+ callout_init_mtx(&sc->periodic, &sc->mpr_mtx, 0);
+ TAILQ_INIT(&sc->event_list);
+ timevalclear(&sc->lastfail);
+
+ if ((error = mpr_transition_ready(sc)) != 0) {
+ mpr_printf(sc, "%s failed to transition ready\n", __func__);
+ return (error);
+ }
+
+ sc->facts = malloc(sizeof(MPI2_IOC_FACTS_REPLY), M_MPR,
+ M_ZERO|M_NOWAIT);
+ if (!sc->facts) {
+ device_printf(sc->mpr_dev, "Cannot allocate memory %s %d\n",
+ __func__, __LINE__);
+ return (ENOMEM);
+ }
+
+ /*
+ * Get IOC Facts and allocate all structures based on this information.
+ * A Diag Reset will also call mpr_iocfacts_allocate and re-read the IOC
+ * Facts. If relevant values have changed in IOC Facts, this function
+ * will free all of the memory based on IOC Facts and reallocate that
+ * memory. If this fails, any allocated memory should already be freed.
+ */
+ if ((error = mpr_iocfacts_allocate(sc, TRUE)) != 0) {
+ mpr_dprint(sc, MPR_FAULT, "%s IOC Facts based allocation "
+ "failed with error %d\n", __func__, error);
+ return (error);
+ }
+
+ /* Start the periodic watchdog check on the IOC Doorbell */
+ mpr_periodic(sc);
+
+ /*
+ * The portenable will kick off discovery events that will drive the
+ * rest of the initialization process. The CAM/SAS module will
+ * hold up the boot sequence until discovery is complete.
+ */
+ sc->mpr_ich.ich_func = mpr_startup;
+ sc->mpr_ich.ich_arg = sc;
+ if (config_intrhook_establish(&sc->mpr_ich) != 0) {
+ mpr_dprint(sc, MPR_ERROR, "Cannot establish MPR config hook\n");
+ error = EINVAL;
+ }
+
+ /*
+ * Allow IR to shutdown gracefully when shutdown occurs.
+ */
+ sc->shutdown_eh = EVENTHANDLER_REGISTER(shutdown_final,
+ mprsas_ir_shutdown, sc, SHUTDOWN_PRI_DEFAULT);
+
+ if (sc->shutdown_eh == NULL)
+ mpr_dprint(sc, MPR_ERROR, "shutdown event registration "
+ "failed\n");
+
+ mpr_setup_sysctl(sc);
+
+ sc->mpr_flags |= MPR_FLAGS_ATTACH_DONE;
+
+ return (error);
+}
+
+/* Run through any late-start handlers. */
+static void
+mpr_startup(void *arg)
+{
+ struct mpr_softc *sc;
+
+ sc = (struct mpr_softc *)arg;
+
+ mpr_lock(sc);
+ mpr_unmask_intr(sc);
+
+ /* initialize device mapping tables */
+ mpr_base_static_config_pages(sc);
+ mpr_mapping_initialize(sc);
+ mprsas_startup(sc);
+ mpr_unlock(sc);
+}
+
+/* Periodic watchdog. Is called with the driver lock already held. */
+static void
+mpr_periodic(void *arg)
+{
+ struct mpr_softc *sc;
+ uint32_t db;
+
+ sc = (struct mpr_softc *)arg;
+ if (sc->mpr_flags & MPR_FLAGS_SHUTDOWN)
+ return;
+
+ db = mpr_regread(sc, MPI2_DOORBELL_OFFSET);
+ if ((db & MPI2_IOC_STATE_MASK) == MPI2_IOC_STATE_FAULT) {
+ if ((db & MPI2_DOORBELL_FAULT_CODE_MASK) ==
+ IFAULT_IOP_OVER_TEMP_THRESHOLD_EXCEEDED) {
+ panic("TEMPERATURE FAULT: STOPPING.");
+ }
+ mpr_dprint(sc, MPR_FAULT, "IOC Fault 0x%08x, Resetting\n", db);
+ mpr_reinit(sc);
+ }
+
+ callout_reset(&sc->periodic, MPR_PERIODIC_DELAY * hz, mpr_periodic, sc);
+}
+
+static void
+mpr_log_evt_handler(struct mpr_softc *sc, uintptr_t data,
+ MPI2_EVENT_NOTIFICATION_REPLY *event)
+{
+ MPI2_EVENT_DATA_LOG_ENTRY_ADDED *entry;
+
+ mpr_print_event(sc, event);
+
+ switch (event->Event) {
+ case MPI2_EVENT_LOG_DATA:
+ mpr_dprint(sc, MPR_EVENT, "MPI2_EVENT_LOG_DATA:\n");
+ if (sc->mpr_debug & MPR_EVENT)
+ hexdump(event->EventData, event->EventDataLength, NULL,
+ 0);
+ break;
+ case MPI2_EVENT_LOG_ENTRY_ADDED:
+ entry = (MPI2_EVENT_DATA_LOG_ENTRY_ADDED *)event->EventData;
+ mpr_dprint(sc, MPR_EVENT, "MPI2_EVENT_LOG_ENTRY_ADDED event "
+ "0x%x Sequence %d:\n", entry->LogEntryQualifier,
+ entry->LogSequence);
+ break;
+ default:
+ break;
+ }
+ return;
+}
+
+static int
+mpr_attach_log(struct mpr_softc *sc)
+{
+ uint8_t events[16];
+
+ bzero(events, 16);
+ setbit(events, MPI2_EVENT_LOG_DATA);
+ setbit(events, MPI2_EVENT_LOG_ENTRY_ADDED);
+
+ mpr_register_events(sc, events, mpr_log_evt_handler, NULL,
+ &sc->mpr_log_eh);
+
+ return (0);
+}
+
+static int
+mpr_detach_log(struct mpr_softc *sc)
+{
+
+ if (sc->mpr_log_eh != NULL)
+ mpr_deregister_events(sc, sc->mpr_log_eh);
+ return (0);
+}
+
+/*
+ * Free all of the driver resources and detach submodules. Should be called
+ * without the lock held.
+ */
+int
+mpr_free(struct mpr_softc *sc)
+{
+ int error;
+
+ /* Turn off the watchdog */
+ mpr_lock(sc);
+ sc->mpr_flags |= MPR_FLAGS_SHUTDOWN;
+ mpr_unlock(sc);
+ /* Lock must not be held for this */
+ callout_drain(&sc->periodic);
+
+ if (((error = mpr_detach_log(sc)) != 0) ||
+ ((error = mpr_detach_sas(sc)) != 0))
+ return (error);
+
+ mpr_detach_user(sc);
+
+ /* Put the IOC back in the READY state. */
+ mpr_lock(sc);
+ if ((error = mpr_transition_ready(sc)) != 0) {
+ mpr_unlock(sc);
+ return (error);
+ }
+ mpr_unlock(sc);
+
+ if (sc->facts != NULL)
+ free(sc->facts, M_MPR);
+
+ /*
+ * Free all buffers that are based on IOC Facts. A Diag Reset may need
+ * to free these buffers too.
+ */
+ mpr_iocfacts_free(sc);
+
+ if (sc->sysctl_tree != NULL)
+ sysctl_ctx_free(&sc->sysctl_ctx);
+
+ /* Deregister the shutdown function */
+ if (sc->shutdown_eh != NULL)
+ EVENTHANDLER_DEREGISTER(shutdown_final, sc->shutdown_eh);
+
+ mtx_destroy(&sc->mpr_mtx);
+
+ return (0);
+}
+
+static __inline void
+mpr_complete_command(struct mpr_softc *sc, struct mpr_command *cm)
+{
+ MPR_FUNCTRACE(sc);
+
+ if (cm == NULL) {
+ mpr_dprint(sc, MPR_ERROR, "Completing NULL command\n");
+ return;
+ }
+
+ if (cm->cm_flags & MPR_CM_FLAGS_POLLED)
+ cm->cm_flags |= MPR_CM_FLAGS_COMPLETE;
+
+ if (cm->cm_complete != NULL) {
+ mpr_dprint(sc, MPR_TRACE,
+ "%s cm %p calling cm_complete %p data %p reply %p\n",
+ __func__, cm, cm->cm_complete, cm->cm_complete_data,
+ cm->cm_reply);
+ cm->cm_complete(sc, cm);
+ }
+
+ if (cm->cm_flags & MPR_CM_FLAGS_WAKEUP) {
+ mpr_dprint(sc, MPR_TRACE, "waking up %p\n", cm);
+ wakeup(cm);
+ }
+
+ if (sc->io_cmds_active != 0) {
+ sc->io_cmds_active--;
+ } else {
+ mpr_dprint(sc, MPR_ERROR, "Warning: io_cmds_active is "
+ "out of sync - resynching to 0\n");
+ }
+}
+
+static void
+mpr_sas_log_info(struct mpr_softc *sc , 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;
+
+ /* each nexus loss loginfo */
+ if (log_info == 0x31170000)
+ return;
+
+ /* eat the loginfos associated with task aborts */
+ if ((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;
+ }
+
+ mpr_dprint(sc, MPR_INFO, "log_info(0x%08x): originator(%s), "
+ "code(0x%02x), sub_code(0x%04x)\n", log_info,
+ originator_str, sas_loginfo.dw.code,
+ sas_loginfo.dw.subcode);
+}
+
+static void
+mpr_display_reply_info(struct mpr_softc *sc, uint8_t *reply)
+{
+ MPI2DefaultReply_t *mpi_reply;
+ u16 sc_status;
+
+ mpi_reply = (MPI2DefaultReply_t*)reply;
+ sc_status = le16toh(mpi_reply->IOCStatus);
+ if (sc_status & MPI2_IOCSTATUS_FLAG_LOG_INFO_AVAILABLE)
+ mpr_sas_log_info(sc, le32toh(mpi_reply->IOCLogInfo));
+}
+
+void
+mpr_intr(void *data)
+{
+ struct mpr_softc *sc;
+ uint32_t status;
+
+ sc = (struct mpr_softc *)data;
+ mpr_dprint(sc, MPR_TRACE, "%s\n", __func__);
+
+ /*
+ * Check interrupt status register to flush the bus. This is
+ * needed for both INTx interrupts and driver-driven polling
+ */
+ status = mpr_regread(sc, MPI2_HOST_INTERRUPT_STATUS_OFFSET);
+ if ((status & MPI2_HIS_REPLY_DESCRIPTOR_INTERRUPT) == 0)
+ return;
+
+ mpr_lock(sc);
+ mpr_intr_locked(data);
+ mpr_unlock(sc);
+ return;
+}
+
+/*
+ * In theory, MSI/MSIX interrupts shouldn't need to read any registers on the
+ * chip. Hopefully this theory is correct.
+ */
+void
+mpr_intr_msi(void *data)
+{
+ struct mpr_softc *sc;
+
+ sc = (struct mpr_softc *)data;
+ mpr_dprint(sc, MPR_TRACE, "%s\n", __func__);
+ mpr_lock(sc);
+ mpr_intr_locked(data);
+ mpr_unlock(sc);
+ return;
+}
+
+/*
+ * The locking is overly broad and simplistic, but easy to deal with for now.
+ */
+void
+mpr_intr_locked(void *data)
+{
+ MPI2_REPLY_DESCRIPTORS_UNION *desc;
+ struct mpr_softc *sc;
+ struct mpr_command *cm = NULL;
+ uint8_t flags;
+ u_int pq;
+ MPI2_DIAG_RELEASE_REPLY *rel_rep;
+ mpr_fw_diagnostic_buffer_t *pBuffer;
+
+ sc = (struct mpr_softc *)data;
+
+ pq = sc->replypostindex;
+ mpr_dprint(sc, MPR_TRACE,
+ "%s sc %p starting with replypostindex %u\n",
+ __func__, sc, sc->replypostindex);
+
+ for ( ;; ) {
+ cm = NULL;
+ desc = &sc->post_queue[sc->replypostindex];
+ flags = desc->Default.ReplyFlags &
+ MPI2_RPY_DESCRIPT_FLAGS_TYPE_MASK;
+ if ((flags == MPI2_RPY_DESCRIPT_FLAGS_UNUSED) ||
+ (le32toh(desc->Words.High) == 0xffffffff))
+ break;
+
+ /* increment the replypostindex now, so that event handlers
+ * and cm completion handlers which decide to do a diag
+ * reset can zero it without it getting incremented again
+ * afterwards, and we break out of this loop on the next
+ * iteration since the reply post queue has been cleared to
+ * 0xFF and all descriptors look unused (which they are).
+ */
+ if (++sc->replypostindex >= sc->pqdepth)
+ sc->replypostindex = 0;
+
+ switch (flags) {
+ case MPI2_RPY_DESCRIPT_FLAGS_SCSI_IO_SUCCESS:
+ case MPI25_RPY_DESCRIPT_FLAGS_FAST_PATH_SCSI_IO_SUCCESS:
+ cm = &sc->commands[le16toh(desc->SCSIIOSuccess.SMID)];
+ cm->cm_reply = NULL;
+ break;
+ case MPI2_RPY_DESCRIPT_FLAGS_ADDRESS_REPLY:
+ {
+ uint32_t baddr;
+ uint8_t *reply;
+
+ /*
+ * Re-compose the reply address from the address
+ * sent back from the chip. The ReplyFrameAddress
+ * is the lower 32 bits of the physical address of
+ * particular reply frame. Convert that address to
+ * host format, and then use that to provide the
+ * offset against the virtual address base
+ * (sc->reply_frames).
+ */
+ baddr = le32toh(desc->AddressReply.ReplyFrameAddress);
+ reply = sc->reply_frames +
+ (baddr - ((uint32_t)sc->reply_busaddr));
+ /*
+ * Make sure the reply we got back is in a valid
+ * range. If not, go ahead and panic here, since
+ * we'll probably panic as soon as we deference the
+ * reply pointer anyway.
+ */
+ if ((reply < sc->reply_frames)
+ || (reply > (sc->reply_frames +
+ (sc->fqdepth * sc->facts->ReplyFrameSize * 4)))) {
+ printf("%s: WARNING: reply %p out of range!\n",
+ __func__, reply);
+ printf("%s: reply_frames %p, fqdepth %d, "
+ "frame size %d\n", __func__,
+ sc->reply_frames, sc->fqdepth,
+ sc->facts->ReplyFrameSize * 4);
+ printf("%s: baddr %#x,\n", __func__, baddr);
+ /* LSI-TODO. See Linux Code for Graceful exit */
+ panic("Reply address out of range");
+ }
+ if (le16toh(desc->AddressReply.SMID) == 0) {
+ if (((MPI2_DEFAULT_REPLY *)reply)->Function ==
+ MPI2_FUNCTION_DIAG_BUFFER_POST) {
+ /*
+ * If SMID is 0 for Diag Buffer Post,
+ * this implies that the reply is due to
+ * a release function with a status that
+ * the buffer has been released. Set
+ * the buffer flags accordingly.
+ */
+ rel_rep =
+ (MPI2_DIAG_RELEASE_REPLY *)reply;
+ if (le16toh(rel_rep->IOCStatus) ==
+ MPI2_IOCSTATUS_DIAGNOSTIC_RELEASED)
+ {
+ pBuffer =
+ &sc->fw_diag_buffer_list[
+ rel_rep->BufferType];
+ pBuffer->valid_data = TRUE;
+ pBuffer->owned_by_firmware =
+ FALSE;
+ pBuffer->immediate = FALSE;
+ }
+ } else
+ mpr_dispatch_event(sc, baddr,
+ (MPI2_EVENT_NOTIFICATION_REPLY *)
+ reply);
+ } else {
+ cm = &sc->commands[
+ le16toh(desc->AddressReply.SMID)];
+ cm->cm_reply = reply;
+ cm->cm_reply_data =
+ le32toh(desc->AddressReply.
+ ReplyFrameAddress);
+ }
+ break;
+ }
+ case MPI2_RPY_DESCRIPT_FLAGS_TARGETASSIST_SUCCESS:
+ case MPI2_RPY_DESCRIPT_FLAGS_TARGET_COMMAND_BUFFER:
+ case MPI2_RPY_DESCRIPT_FLAGS_RAID_ACCELERATOR_SUCCESS:
+ default:
+ /* Unhandled */
+ mpr_dprint(sc, MPR_ERROR, "Unhandled reply 0x%x\n",
+ desc->Default.ReplyFlags);
+ cm = NULL;
+ break;
+ }
+
+ if (cm != NULL) {
+ // Print Error reply frame
+ if (cm->cm_reply)
+ mpr_display_reply_info(sc,cm->cm_reply);
+ mpr_complete_command(sc, cm);
+ }
+
+ desc->Words.Low = 0xffffffff;
+ desc->Words.High = 0xffffffff;
+ }
+
+ if (pq != sc->replypostindex) {
+ mpr_dprint(sc, MPR_TRACE,
+ "%s sc %p writing postindex %d\n",
+ __func__, sc, sc->replypostindex);
+ mpr_regwrite(sc, MPI2_REPLY_POST_HOST_INDEX_OFFSET,
+ sc->replypostindex);
+ }
+
+ return;
+}
+
+static void
+mpr_dispatch_event(struct mpr_softc *sc, uintptr_t data,
+ MPI2_EVENT_NOTIFICATION_REPLY *reply)
+{
+ struct mpr_event_handle *eh;
+ int event, handled = 0;
+
+ event = le16toh(reply->Event);
+ TAILQ_FOREACH(eh, &sc->event_list, eh_list) {
+ if (isset(eh->mask, event)) {
+ eh->callback(sc, data, reply);
+ handled++;
+ }
+ }
+
+ if (handled == 0)
+ mpr_dprint(sc, MPR_EVENT, "Unhandled event 0x%x\n",
+ le16toh(event));
+
+ /*
+ * This is the only place that the event/reply should be freed.
+ * Anything wanting to hold onto the event data should have
+ * already copied it into their own storage.
+ */
+ mpr_free_reply(sc, data);
+}
+
+static void
+mpr_reregister_events_complete(struct mpr_softc *sc, struct mpr_command *cm)
+{
+ mpr_dprint(sc, MPR_TRACE, "%s\n", __func__);
+
+ if (cm->cm_reply)
+ mpr_print_event(sc,
+ (MPI2_EVENT_NOTIFICATION_REPLY *)cm->cm_reply);
+
+ mpr_free_command(sc, cm);
+
+ /* next, send a port enable */
+ mprsas_startup(sc);
+}
+
+/*
+ * For both register_events and update_events, the caller supplies a bitmap
+ * of events that it _wants_. These functions then turn that into a bitmask
+ * suitable for the controller.
+ */
+int
+mpr_register_events(struct mpr_softc *sc, uint8_t *mask,
+ mpr_evt_callback_t *cb, void *data, struct mpr_event_handle **handle)
+{
+ struct mpr_event_handle *eh;
+ int error = 0;
+
+ eh = malloc(sizeof(struct mpr_event_handle), M_MPR, M_WAITOK|M_ZERO);
+ if (!eh) {
+ device_printf(sc->mpr_dev, "Cannot allocate memory %s %d\n",
+ __func__, __LINE__);
+ return (ENOMEM);
+ }
+ eh->callback = cb;
+ eh->data = data;
+ TAILQ_INSERT_TAIL(&sc->event_list, eh, eh_list);
+ if (mask != NULL)
+ error = mpr_update_events(sc, eh, mask);
+ *handle = eh;
+
+ return (error);
+}
+
+int
+mpr_update_events(struct mpr_softc *sc, struct mpr_event_handle *handle,
+ uint8_t *mask)
+{
+ MPI2_EVENT_NOTIFICATION_REQUEST *evtreq;
+ MPI2_EVENT_NOTIFICATION_REPLY *reply;
+ struct mpr_command *cm;
+ struct mpr_event_handle *eh;
+ int error, i;
+
+ mpr_dprint(sc, MPR_TRACE, "%s\n", __func__);
+
+ if ((mask != NULL) && (handle != NULL))
+ bcopy(mask, &handle->mask[0], 16);
+ memset(sc->event_mask, 0xff, 16);
+
+ TAILQ_FOREACH(eh, &sc->event_list, eh_list) {
+ for (i = 0; i < 16; i++)
+ sc->event_mask[i] &= ~eh->mask[i];
+ }
+
+ if ((cm = mpr_alloc_command(sc)) == NULL)
+ return (EBUSY);
+ evtreq = (MPI2_EVENT_NOTIFICATION_REQUEST *)cm->cm_req;
+ evtreq->Function = MPI2_FUNCTION_EVENT_NOTIFICATION;
+ evtreq->MsgFlags = 0;
+ evtreq->SASBroadcastPrimitiveMasks = 0;
+#ifdef MPR_DEBUG_ALL_EVENTS
+ {
+ u_char fullmask[16];
+ memset(fullmask, 0x00, 16);
+ bcopy(fullmask, (uint8_t *)&evtreq->EventMasks, 16);
+ }
+#else
+ bcopy(sc->event_mask, (uint8_t *)&evtreq->EventMasks, 16);
+#endif
+ cm->cm_desc.Default.RequestFlags = MPI2_REQ_DESCRIPT_FLAGS_DEFAULT_TYPE;
+ cm->cm_data = NULL;
+
+ error = mpr_request_polled(sc, cm);
+ reply = (MPI2_EVENT_NOTIFICATION_REPLY *)cm->cm_reply;
+ if ((reply == NULL) ||
+ (reply->IOCStatus & MPI2_IOCSTATUS_MASK) != MPI2_IOCSTATUS_SUCCESS)
+ error = ENXIO;
+
+ if(reply)
+ mpr_print_event(sc, reply);
+
+ mpr_dprint(sc, MPR_TRACE, "%s finished error %d\n", __func__, error);
+
+ mpr_free_command(sc, cm);
+ return (error);
+}
+
+static int
+mpr_reregister_events(struct mpr_softc *sc)
+{
+ MPI2_EVENT_NOTIFICATION_REQUEST *evtreq;
+ struct mpr_command *cm;
+ struct mpr_event_handle *eh;
+ int error, i;
+
+ mpr_dprint(sc, MPR_TRACE, "%s\n", __func__);
+
+ /* first, reregister events */
+
+ memset(sc->event_mask, 0xff, 16);
+
+ TAILQ_FOREACH(eh, &sc->event_list, eh_list) {
+ for (i = 0; i < 16; i++)
+ sc->event_mask[i] &= ~eh->mask[i];
+ }
+
+ if ((cm = mpr_alloc_command(sc)) == NULL)
+ return (EBUSY);
+ evtreq = (MPI2_EVENT_NOTIFICATION_REQUEST *)cm->cm_req;
+ evtreq->Function = MPI2_FUNCTION_EVENT_NOTIFICATION;
+ evtreq->MsgFlags = 0;
+ evtreq->SASBroadcastPrimitiveMasks = 0;
+#ifdef MPR_DEBUG_ALL_EVENTS
+ {
+ u_char fullmask[16];
+ memset(fullmask, 0x00, 16);
+ bcopy(fullmask, (uint8_t *)&evtreq->EventMasks, 16);
+ }
+#else
+ bcopy(sc->event_mask, (uint8_t *)&evtreq->EventMasks, 16);
+#endif
+ cm->cm_desc.Default.RequestFlags = MPI2_REQ_DESCRIPT_FLAGS_DEFAULT_TYPE;
+ cm->cm_data = NULL;
+ cm->cm_complete = mpr_reregister_events_complete;
+
+ error = mpr_map_command(sc, cm);
+
+ mpr_dprint(sc, MPR_TRACE, "%s finished with error %d\n", __func__,
+ error);
+ return (error);
+}
+
+int
+mpr_deregister_events(struct mpr_softc *sc, struct mpr_event_handle *handle)
+{
+
+ TAILQ_REMOVE(&sc->event_list, handle, eh_list);
+ free(handle, M_MPR);
+ return (mpr_update_events(sc, NULL, NULL));
+}
+
+/*
+ * Add a chain element as the next SGE for the specified command.
+ * Reset cm_sge and cm_sgesize to indicate all the available space. Chains are
+ * only required for IEEE commands. Therefore there is no code for commands
+ * that have the MPR_CM_FLAGS_SGE_SIMPLE flag set (and those commands shouldn't
+ * be requesting chains).
+ */
+static int
+mpr_add_chain(struct mpr_command *cm, int segsleft)
+{
+ struct mpr_softc *sc = cm->cm_sc;
+ MPI2_REQUEST_HEADER *req;
+ MPI25_IEEE_SGE_CHAIN64 *ieee_sgc;
+ struct mpr_chain *chain;
+ int space, sgc_size, current_segs, rem_segs, segs_per_frame;
+ uint8_t next_chain_offset = 0;
+
+ /*
+ * Fail if a command is requesting a chain for SIMPLE SGE's. For SAS3
+ * only IEEE commands should be requesting chains. Return some error
+ * code other than 0.
+ */
+ if (cm->cm_flags & MPR_CM_FLAGS_SGE_SIMPLE) {
+//SLM-test
+printf("Trying to add a chain element to an MPI SGL\n");
+ mpr_dprint(sc, MPR_ERROR, "A chain element cannot be added to "
+ "an MPI SGL.\n");
+ return(ENOBUFS);
+ }
+
+ sgc_size = sizeof(MPI25_IEEE_SGE_CHAIN64);
+ if (cm->cm_sglsize < sgc_size)
+ panic("MPR: Need SGE Error Code\n");
+
+ chain = mpr_alloc_chain(cm->cm_sc);
+ if (chain == NULL)
+ return (ENOBUFS);
+
+ space = (int)cm->cm_sc->facts->IOCRequestFrameSize * 4;
+
+ /*
+ * Note: a double-linked list is used to make it easier to walk for
+ * debugging.
+ */
+ TAILQ_INSERT_TAIL(&cm->cm_chain_list, chain, chain_link);
+
+ /*
+ * Need to know if the number of frames left is more than 1 or not. If
+ * more than 1 frame is required, NextChainOffset will need to be set,
+ * which will just be the last segment of the frame.
+ */
+ rem_segs = 0;
+ if (cm->cm_sglsize < (sgc_size * segsleft)) {
+ /*
+ * rem_segs is the number of segements remaining after the
+ * segments that will go into the current frame. Since it is
+ * known that at least one more frame is required, account for
+ * the chain element. To know if more than one more frame is
+ * required, just check if there will be a remainder after using
+ * the current frame (with this chain) and the next frame. If
+ * so the NextChainOffset must be the last element of the next
+ * frame.
+ */
+ current_segs = (cm->cm_sglsize / sgc_size) - 1;
+ rem_segs = segsleft - current_segs;
+ segs_per_frame = space / sgc_size;
+ if (rem_segs > segs_per_frame) {
+ next_chain_offset = segs_per_frame - 1;
+ }
+ }
+ ieee_sgc = &((MPI25_SGE_IO_UNION *)cm->cm_sge)->IeeeChain;
+ ieee_sgc->Length = next_chain_offset ? htole32((uint32_t)space) :
+ htole32((uint32_t)rem_segs * (uint32_t)sgc_size);
+ ieee_sgc->NextChainOffset = next_chain_offset;
+ ieee_sgc->Flags = (MPI2_IEEE_SGE_FLAGS_CHAIN_ELEMENT |
+ MPI2_IEEE_SGE_FLAGS_SYSTEM_ADDR);
+ ieee_sgc->Address.Low = htole32(chain->chain_busaddr);
+ ieee_sgc->Address.High = htole32(chain->chain_busaddr >> 32);
+ cm->cm_sge = &((MPI25_SGE_IO_UNION *)chain->chain)->IeeeSimple;
+ req = (MPI2_REQUEST_HEADER *)cm->cm_req;
+ req->ChainOffset = ((sc->facts->IOCRequestFrameSize * 4) -
+ sgc_size) >> 4;
+
+ cm->cm_sglsize = space;
+ return (0);
+}
+
+/*
+ * Add one scatter-gather element to the scatter-gather list for a command.
+ * Maintain cm_sglsize and cm_sge as the remaining size and pointer to the next
+ * SGE to fill in, respectively. In Gen3, the MPI SGL does not have a chain,
+ * so don't consider any chain additions.
+ */
+int
+mpr_push_sge(struct mpr_command *cm, MPI2_SGE_SIMPLE64 *sge, size_t len,
+ int segsleft)
+{
+ uint32_t saved_buf_len, saved_address_low, saved_address_high;
+ u32 sge_flags;
+
+ /*
+ * case 1: >=1 more segment, no room for anything (error)
+ * case 2: 1 more segment and enough room for it
+ */
+
+ if (cm->cm_sglsize < (segsleft * sizeof(MPI2_SGE_SIMPLE64))) {
+ mpr_dprint(cm->cm_sc, MPR_ERROR,
+ "%s: warning: Not enough room for MPI SGL in frame.\n",
+ __func__);
+ return(ENOBUFS);
+ }
+
+ KASSERT(segsleft == 1,
+ ("segsleft cannot be more than 1 for an MPI SGL; segsleft = %d\n",
+ segsleft));
+
+ /*
+ * There is one more segment left to add for the MPI SGL and there is
+ * enough room in the frame to add it. This is the normal case because
+ * MPI SGL's don't have chains, otherwise something is wrong.
+ *
+ * If this is a bi-directional request, need to account for that
+ * here. Save the pre-filled sge values. These will be used
+ * either for the 2nd SGL or for a single direction SGL. If
+ * cm_out_len is non-zero, this is a bi-directional request, so
+ * fill in the OUT SGL first, then the IN SGL, otherwise just
+ * fill in the IN SGL. Note that at this time, when filling in
+ * 2 SGL's for a bi-directional request, they both use the same
+ * DMA buffer (same cm command).
+ */
+ saved_buf_len = sge->FlagsLength & 0x00FFFFFF;
+ saved_address_low = sge->Address.Low;
+ saved_address_high = sge->Address.High;
+ if (cm->cm_out_len) {
+ sge->FlagsLength = cm->cm_out_len |
+ ((uint32_t)(MPI2_SGE_FLAGS_SIMPLE_ELEMENT |
+ MPI2_SGE_FLAGS_END_OF_BUFFER |
+ MPI2_SGE_FLAGS_HOST_TO_IOC |
+ MPI2_SGE_FLAGS_64_BIT_ADDRESSING) <<
+ MPI2_SGE_FLAGS_SHIFT);
+ cm->cm_sglsize -= len;
+ /* Endian Safe code */
+ sge_flags = sge->FlagsLength;
+ sge->FlagsLength = htole32(sge_flags);
+ sge->Address.High = htole32(sge->Address.High);
+ sge->Address.Low = htole32(sge->Address.Low);
+ bcopy(sge, cm->cm_sge, len);
+ cm->cm_sge = (MPI2_SGE_IO_UNION *)((uintptr_t)cm->cm_sge + len);
+ }
+ sge->FlagsLength = saved_buf_len |
+ ((uint32_t)(MPI2_SGE_FLAGS_SIMPLE_ELEMENT |
+ MPI2_SGE_FLAGS_END_OF_BUFFER |
+ MPI2_SGE_FLAGS_LAST_ELEMENT |
+ MPI2_SGE_FLAGS_END_OF_LIST |
+ MPI2_SGE_FLAGS_64_BIT_ADDRESSING) <<
+ MPI2_SGE_FLAGS_SHIFT);
+ if (cm->cm_flags & MPR_CM_FLAGS_DATAIN) {
+ sge->FlagsLength |=
+ ((uint32_t)(MPI2_SGE_FLAGS_IOC_TO_HOST) <<
+ MPI2_SGE_FLAGS_SHIFT);
+ } else {
+ sge->FlagsLength |=
+ ((uint32_t)(MPI2_SGE_FLAGS_HOST_TO_IOC) <<
+ MPI2_SGE_FLAGS_SHIFT);
+ }
+ sge->Address.Low = saved_address_low;
+ sge->Address.High = saved_address_high;
+
+ cm->cm_sglsize -= len;
+ /* Endian Safe code */
+ sge_flags = sge->FlagsLength;
+ sge->FlagsLength = htole32(sge_flags);
+ sge->Address.High = htole32(sge->Address.High);
+ sge->Address.Low = htole32(sge->Address.Low);
+ bcopy(sge, cm->cm_sge, len);
+ cm->cm_sge = (MPI2_SGE_IO_UNION *)((uintptr_t)cm->cm_sge + len);
+ return (0);
+}
+
+/*
+ * Add one IEEE scatter-gather element (chain or simple) to the IEEE scatter-
+ * gather list for a command. Maintain cm_sglsize and cm_sge as the
+ * remaining size and pointer to the next SGE to fill in, respectively.
+ */
+int
+mpr_push_ieee_sge(struct mpr_command *cm, void *sgep, int segsleft)
+{
+ MPI2_IEEE_SGE_SIMPLE64 *sge = sgep;
+ int error, ieee_sge_size = sizeof(MPI25_SGE_IO_UNION);
+ uint32_t saved_buf_len, saved_address_low, saved_address_high;
+ uint32_t sge_length;
+
+ /*
+ * case 1: No room for chain or segment (error).
+ * case 2: Two or more segments left but only room for chain.
+ * case 3: Last segment and room for it, so set flags.
+ */
+
+ /*
+ * There should be room for at least one element, or there is a big
+ * problem.
+ */
+ if (cm->cm_sglsize < ieee_sge_size)
+ panic("MPR: Need SGE Error Code\n");
+
+ if ((segsleft >= 2) && (cm->cm_sglsize < (ieee_sge_size * 2))) {
+ if ((error = mpr_add_chain(cm, segsleft)) != 0)
+ return (error);
+ }
+
+ if (segsleft == 1) {
+ /*
+ * If this is a bi-directional request, need to account for that
+ * here. Save the pre-filled sge values. These will be used
+ * either for the 2nd SGL or for a single direction SGL. If
+ * cm_out_len is non-zero, this is a bi-directional request, so
+ * fill in the OUT SGL first, then the IN SGL, otherwise just
+ * fill in the IN SGL. Note that at this time, when filling in
+ * 2 SGL's for a bi-directional request, they both use the same
+ * DMA buffer (same cm command).
+ */
+ saved_buf_len = sge->Length;
+ saved_address_low = sge->Address.Low;
+ saved_address_high = sge->Address.High;
+ if (cm->cm_out_len) {
+ sge->Length = cm->cm_out_len;
+ sge->Flags = (MPI2_IEEE_SGE_FLAGS_SIMPLE_ELEMENT |
+ MPI2_IEEE_SGE_FLAGS_SYSTEM_ADDR);
+ cm->cm_sglsize -= ieee_sge_size;
+ /* Endian Safe code */
+ sge_length = sge->Length;
+ sge->Length = htole32(sge_length);
+ sge->Address.High = htole32(sge->Address.High);
+ sge->Address.Low = htole32(sge->Address.Low);
+ bcopy(sgep, cm->cm_sge, ieee_sge_size);
+ cm->cm_sge =
+ (MPI25_SGE_IO_UNION *)((uintptr_t)cm->cm_sge +
+ ieee_sge_size);
+ }
+ sge->Length = saved_buf_len;
+ sge->Flags = (MPI2_IEEE_SGE_FLAGS_SIMPLE_ELEMENT |
+ MPI2_IEEE_SGE_FLAGS_SYSTEM_ADDR |
+ MPI25_IEEE_SGE_FLAGS_END_OF_LIST);
+ sge->Address.Low = saved_address_low;
+ sge->Address.High = saved_address_high;
+ }
+
+ cm->cm_sglsize -= ieee_sge_size;
+ /* Endian Safe code */
+ sge_length = sge->Length;
+ sge->Length = htole32(sge_length);
+ sge->Address.High = htole32(sge->Address.High);
+ sge->Address.Low = htole32(sge->Address.Low);
+ bcopy(sgep, cm->cm_sge, ieee_sge_size);
+ cm->cm_sge = (MPI25_SGE_IO_UNION *)((uintptr_t)cm->cm_sge +
+ ieee_sge_size);
+ return (0);
+}
+
+/*
+ * Add one dma segment to the scatter-gather list for a command.
+ */
+int
+mpr_add_dmaseg(struct mpr_command *cm, vm_paddr_t pa, size_t len, u_int flags,
+ int segsleft)
+{
+ MPI2_SGE_SIMPLE64 sge;
+ MPI2_IEEE_SGE_SIMPLE64 ieee_sge;
+
+ if (!(cm->cm_flags & MPR_CM_FLAGS_SGE_SIMPLE)) {
+ ieee_sge.Flags = (MPI2_IEEE_SGE_FLAGS_SIMPLE_ELEMENT |
+ MPI2_IEEE_SGE_FLAGS_SYSTEM_ADDR);
+ ieee_sge.Length = len;
+ mpr_from_u64(pa, &ieee_sge.Address);
+
+ return (mpr_push_ieee_sge(cm, &ieee_sge, segsleft));
+ } else {
+ /*
+ * This driver always uses 64-bit address elements for
+ * simplicity.
+ */
+ flags |= MPI2_SGE_FLAGS_SIMPLE_ELEMENT |
+ MPI2_SGE_FLAGS_64_BIT_ADDRESSING;
+ /* Set Endian safe macro in mpr_push_sge */
+ sge.FlagsLength = len | (flags << MPI2_SGE_FLAGS_SHIFT);
+ mpr_from_u64(pa, &sge.Address);
+
+ return (mpr_push_sge(cm, &sge, sizeof sge, segsleft));
+ }
+}
+
+static void
+mpr_data_cb(void *arg, bus_dma_segment_t *segs, int nsegs, int error)
+{
+ struct mpr_softc *sc;
+ struct mpr_command *cm;
+ u_int i, dir, sflags;
+
+ cm = (struct mpr_command *)arg;
+ sc = cm->cm_sc;
+
+ /*
+ * In this case, just print out a warning and let the chip tell the
+ * user they did the wrong thing.
+ */
+ if ((cm->cm_max_segs != 0) && (nsegs > cm->cm_max_segs)) {
+ mpr_dprint(sc, MPR_ERROR,
+ "%s: warning: busdma returned %d segments, "
+ "more than the %d allowed\n", __func__, nsegs,
+ cm->cm_max_segs);
+ }
+
+ /*
+ * Set up DMA direction flags. Bi-directional requests are also handled
+ * here. In that case, both direction flags will be set.
+ */
+ sflags = 0;
+ if (cm->cm_flags & MPR_CM_FLAGS_SMP_PASS) {
+ /*
+ * We have to add a special case for SMP passthrough, there
+ * is no easy way to generically handle it. The first
+ * S/G element is used for the command (therefore the
+ * direction bit needs to be set). The second one is used
+ * for the reply. We'll leave it to the caller to make
+ * sure we only have two buffers.
+ */
+ /*
+ * Even though the busdma man page says it doesn't make
+ * sense to have both direction flags, it does in this case.
+ * We have one s/g element being accessed in each direction.
+ */
+ dir = BUS_DMASYNC_PREWRITE | BUS_DMASYNC_PREREAD;
+
+ /*
+ * Set the direction flag on the first buffer in the SMP
+ * passthrough request. We'll clear it for the second one.
+ */
+ sflags |= MPI2_SGE_FLAGS_DIRECTION |
+ MPI2_SGE_FLAGS_END_OF_BUFFER;
+ } else if (cm->cm_flags & MPR_CM_FLAGS_DATAOUT) {
+ sflags |= MPI2_SGE_FLAGS_HOST_TO_IOC;
+ dir = BUS_DMASYNC_PREWRITE;
+ } else
+ dir = BUS_DMASYNC_PREREAD;
+
+ for (i = 0; i < nsegs; i++) {
+ if ((cm->cm_flags & MPR_CM_FLAGS_SMP_PASS) && (i != 0)) {
+ sflags &= ~MPI2_SGE_FLAGS_DIRECTION;
+ }
+ error = mpr_add_dmaseg(cm, segs[i].ds_addr, segs[i].ds_len,
+ sflags, nsegs - i);
+ if (error != 0) {
+ /* Resource shortage, roll back! */
+ if (ratecheck(&sc->lastfail, &mpr_chainfail_interval))
+ mpr_dprint(sc, MPR_INFO, "Out of chain frames, "
+ "consider increasing hw.mpr.max_chains.\n");
+ cm->cm_flags |= MPR_CM_FLAGS_CHAIN_FAILED;
+ mpr_complete_command(sc, cm);
+ return;
+ }
+ }
+
+ bus_dmamap_sync(sc->buffer_dmat, cm->cm_dmamap, dir);
+ mpr_enqueue_request(sc, cm);
+
+ return;
+}
+
+static void
+mpr_data_cb2(void *arg, bus_dma_segment_t *segs, int nsegs, bus_size_t mapsize,
+ int error)
+{
+ mpr_data_cb(arg, segs, nsegs, error);
+}
+
+/*
+ * This is the routine to enqueue commands ansynchronously.
+ * Note that the only error path here is from bus_dmamap_load(), which can
+ * return EINPROGRESS if it is waiting for resources. Other than this, it's
+ * assumed that if you have a command in-hand, then you have enough credits
+ * to use it.
+ */
+int
+mpr_map_command(struct mpr_softc *sc, struct mpr_command *cm)
+{
+ int error = 0;
+
+ if (cm->cm_flags & MPR_CM_FLAGS_USE_UIO) {
+ error = bus_dmamap_load_uio(sc->buffer_dmat, cm->cm_dmamap,
+ &cm->cm_uio, mpr_data_cb2, cm, 0);
+ } else if (cm->cm_flags & MPR_CM_FLAGS_USE_CCB) {
+ error = bus_dmamap_load_ccb(sc->buffer_dmat, cm->cm_dmamap,
+ cm->cm_data, mpr_data_cb, cm, 0);
+ } else if ((cm->cm_data != NULL) && (cm->cm_length != 0)) {
+ error = bus_dmamap_load(sc->buffer_dmat, cm->cm_dmamap,
+ cm->cm_data, cm->cm_length, mpr_data_cb, cm, 0);
+ } else {
+ /* Add a zero-length element as needed */
+ if (cm->cm_sge != NULL)
+ mpr_add_dmaseg(cm, 0, 0, 0, 1);
+ mpr_enqueue_request(sc, cm);
+ }
+
+ return (error);
+}
+
+/*
+ * This is the routine to enqueue commands synchronously. An error of
+ * EINPROGRESS from mpr_map_command() is ignored since the command will
+ * be executed and enqueued automatically. Other errors come from msleep().
+ */
+int
+mpr_wait_command(struct mpr_softc *sc, struct mpr_command *cm, int timeout,
+ int sleep_flag)
+{
+ int error, rc;
+ struct timeval cur_time, start_time;
+
+ if (sc->mpr_flags & MPR_FLAGS_DIAGRESET)
+ return EBUSY;
+
+ cm->cm_complete = NULL;
+ cm->cm_flags |= (MPR_CM_FLAGS_WAKEUP + MPR_CM_FLAGS_POLLED);
+ error = mpr_map_command(sc, cm);
+ if ((error != 0) && (error != EINPROGRESS))
+ return (error);
+
+ // Check for context and wait for 50 mSec at a time until time has
+ // expired or the command has finished. If msleep can't be used, need
+ // to poll.
+#if __FreeBSD_version >= 1000029
+ if (curthread->td_no_sleeping)
+#else //__FreeBSD_version < 1000029
+ if (curthread->td_pflags & TDP_NOSLEEPING)
+#endif //__FreeBSD_version >= 1000029
+ sleep_flag = NO_SLEEP;
+ getmicrotime(&start_time);
+ if (mtx_owned(&sc->mpr_mtx) && sleep_flag == CAN_SLEEP) {
+ error = msleep(cm, &sc->mpr_mtx, 0, "mprwait", timeout*hz);
+ } else {
+ while ((cm->cm_flags & MPR_CM_FLAGS_COMPLETE) == 0) {
+ mpr_intr_locked(sc);
+ if (sleep_flag == CAN_SLEEP)
+ pause("mprwait", hz/20);
+ else
+ DELAY(50000);
+
+ getmicrotime(&cur_time);
+ if ((cur_time.tv_sec - start_time.tv_sec) > timeout) {
+ error = EWOULDBLOCK;
+ break;
+ }
+ }
+ }
+
+ if (error == EWOULDBLOCK) {
+ mpr_dprint(sc, MPR_FAULT, "Calling Reinit from %s\n", __func__);
+ rc = mpr_reinit(sc);
+ mpr_dprint(sc, MPR_FAULT, "Reinit %s\n", (rc == 0) ? "success" :
+ "failed");
+ error = ETIMEDOUT;
+ }
+ return (error);
+}
+
+/*
+ * This is the routine to enqueue a command synchonously and poll for
+ * completion. Its use should be rare.
+ */
+int
+mpr_request_polled(struct mpr_softc *sc, struct mpr_command *cm)
+{
+ int error, timeout = 0, rc;
+ struct timeval cur_time, start_time;
+
+ error = 0;
+
+ cm->cm_flags |= MPR_CM_FLAGS_POLLED;
+ cm->cm_complete = NULL;
+ mpr_map_command(sc, cm);
+
+ getmicrotime(&start_time);
+ while ((cm->cm_flags & MPR_CM_FLAGS_COMPLETE) == 0) {
+ mpr_intr_locked(sc);
+
+ if (mtx_owned(&sc->mpr_mtx))
+ msleep(&sc->msleep_fake_chan, &sc->mpr_mtx, 0,
+ "mprpoll", hz/20);
+ else
+ pause("mprpoll", hz/20);
+
+ /*
+ * Check for real-time timeout and fail if more than 60 seconds.
+ */
+ getmicrotime(&cur_time);
+ timeout = cur_time.tv_sec - start_time.tv_sec;
+ if (timeout > 60) {
+ mpr_dprint(sc, MPR_FAULT, "polling failed\n");
+ error = ETIMEDOUT;
+ break;
+ }
+ }
+
+ if(error) {
+ mpr_dprint(sc, MPR_FAULT, "Calling Reinit from %s\n", __func__);
+ rc = mpr_reinit(sc);
+ mpr_dprint(sc, MPR_FAULT, "Reinit %s\n", (rc == 0) ?
+ "success" : "failed");
+ }
+ return (error);
+}
+
+/*
+ * The MPT driver had a verbose interface for config pages. In this driver,
+ * reduce it to much simplier terms, similar to the Linux driver.
+ */
+int
+mpr_read_config_page(struct mpr_softc *sc, struct mpr_config_params *params)
+{
+ MPI2_CONFIG_REQUEST *req;
+ struct mpr_command *cm;
+ int error;
+
+ if (sc->mpr_flags & MPR_FLAGS_BUSY) {
+ return (EBUSY);
+ }
+
+ cm = mpr_alloc_command(sc);
+ if (cm == NULL) {
+ return (EBUSY);
+ }
+
+ req = (MPI2_CONFIG_REQUEST *)cm->cm_req;
+ req->Function = MPI2_FUNCTION_CONFIG;
+ req->Action = params->action;
+ req->SGLFlags = 0;
+ req->ChainOffset = 0;
+ req->PageAddress = params->page_address;
+ if (params->hdr.Struct.PageType == MPI2_CONFIG_PAGETYPE_EXTENDED) {
+ MPI2_CONFIG_EXTENDED_PAGE_HEADER *hdr;
+
+ hdr = &params->hdr.Ext;
+ req->ExtPageType = hdr->ExtPageType;
+ req->ExtPageLength = hdr->ExtPageLength;
+ req->Header.PageType = MPI2_CONFIG_PAGETYPE_EXTENDED;
+ req->Header.PageLength = 0; /* Must be set to zero */
+ req->Header.PageNumber = hdr->PageNumber;
+ req->Header.PageVersion = hdr->PageVersion;
+ } else {
+ MPI2_CONFIG_PAGE_HEADER *hdr;
+
+ hdr = &params->hdr.Struct;
+ req->Header.PageType = hdr->PageType;
+ req->Header.PageNumber = hdr->PageNumber;
+ req->Header.PageLength = hdr->PageLength;
+ req->Header.PageVersion = hdr->PageVersion;
+ }
+
+ cm->cm_data = params->buffer;
+ cm->cm_length = params->length;
+ cm->cm_sge = &req->PageBufferSGE;
+ cm->cm_sglsize = sizeof(MPI2_SGE_IO_UNION);
+ cm->cm_flags = MPR_CM_FLAGS_SGE_SIMPLE | MPR_CM_FLAGS_DATAIN;
+ cm->cm_desc.Default.RequestFlags = MPI2_REQ_DESCRIPT_FLAGS_DEFAULT_TYPE;
+
+ cm->cm_complete_data = params;
+ if (params->callback != NULL) {
+ cm->cm_complete = mpr_config_complete;
+ return (mpr_map_command(sc, cm));
+ } else {
+ error = mpr_wait_command(sc, cm, 0, CAN_SLEEP);
+ if (error) {
+ mpr_dprint(sc, MPR_FAULT,
+ "Error %d reading config page\n", error);
+ mpr_free_command(sc, cm);
+ return (error);
+ }
+ mpr_config_complete(sc, cm);
+ }
+
+ return (0);
+}
+
+int
+mpr_write_config_page(struct mpr_softc *sc, struct mpr_config_params *params)
+{
+ return (EINVAL);
+}
+
+static void
+mpr_config_complete(struct mpr_softc *sc, struct mpr_command *cm)
+{
+ MPI2_CONFIG_REPLY *reply;
+ struct mpr_config_params *params;
+
+ MPR_FUNCTRACE(sc);
+ params = cm->cm_complete_data;
+
+ if (cm->cm_data != NULL) {
+ bus_dmamap_sync(sc->buffer_dmat, cm->cm_dmamap,
+ BUS_DMASYNC_POSTREAD);
+ bus_dmamap_unload(sc->buffer_dmat, cm->cm_dmamap);
+ }
+
+ /*
+ * XXX KDM need to do more error recovery? This results in the
+ * device in question not getting probed.
+ */
+ if ((cm->cm_flags & MPR_CM_FLAGS_ERROR_MASK) != 0) {
+ params->status = MPI2_IOCSTATUS_BUSY;
+ goto done;
+ }
+
+ reply = (MPI2_CONFIG_REPLY *)cm->cm_reply;
+ if (reply == NULL) {
+ params->status = MPI2_IOCSTATUS_BUSY;
+ goto done;
+ }
+ params->status = reply->IOCStatus;
+ if (params->hdr.Ext.ExtPageType != 0) {
+ params->hdr.Ext.ExtPageType = reply->ExtPageType;
+ params->hdr.Ext.ExtPageLength = reply->ExtPageLength;
+ } else {
+ params->hdr.Struct.PageType = reply->Header.PageType;
+ params->hdr.Struct.PageNumber = reply->Header.PageNumber;
+ params->hdr.Struct.PageLength = reply->Header.PageLength;
+ params->hdr.Struct.PageVersion = reply->Header.PageVersion;
+ }
+
+done:
+ mpr_free_command(sc, cm);
+ if (params->callback != NULL)
+ params->callback(sc, params);
+
+ return;
+}
diff --git a/sys/dev/mpr/mpr_config.c b/sys/dev/mpr/mpr_config.c
new file mode 100644
index 0000000..1254516
--- /dev/null
+++ b/sys/dev/mpr/mpr_config.c
@@ -0,0 +1,1302 @@
+/*-
+ * Copyright (c) 2011-2014 LSI Corp.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * LSI MPT-Fusion Host Adapter FreeBSD
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+/* TODO Move headers to mprvar */
+#include <sys/types.h>
+#include <sys/param.h>
+#include <sys/lock.h>
+#include <sys/mutex.h>
+#include <sys/systm.h>
+#include <sys/kernel.h>
+#include <sys/malloc.h>
+#include <sys/kthread.h>
+#include <sys/taskqueue.h>
+#include <sys/bus.h>
+#include <sys/endian.h>
+#include <sys/sysctl.h>
+#include <sys/eventhandler.h>
+#include <sys/uio.h>
+#include <machine/bus.h>
+#include <machine/resource.h>
+#include <dev/mpr/mpi/mpi2_type.h>
+#include <dev/mpr/mpi/mpi2.h>
+#include <dev/mpr/mpi/mpi2_ioc.h>
+#include <dev/mpr/mpi/mpi2_sas.h>
+#include <dev/mpr/mpi/mpi2_cnfg.h>
+#include <dev/mpr/mpi/mpi2_init.h>
+#include <dev/mpr/mpi/mpi2_tool.h>
+#include <dev/mpr/mpr_ioctl.h>
+#include <dev/mpr/mprvar.h>
+
+/**
+ * mpr_config_get_ioc_pg8 - obtain ioc page 8
+ * @sc: per adapter object
+ * @mpi_reply: reply mf payload returned from firmware
+ * @config_page: contents of the config page
+ * Context: sleep.
+ *
+ * Returns 0 for success, non-zero for failure.
+ */
+int
+mpr_config_get_ioc_pg8(struct mpr_softc *sc, Mpi2ConfigReply_t *mpi_reply,
+ Mpi2IOCPage8_t *config_page)
+{
+ MPI2_CONFIG_REQUEST *request;
+ MPI2_CONFIG_REPLY *reply;
+ struct mpr_command *cm;
+ MPI2_CONFIG_PAGE_IOC_8 *page = NULL;
+ int error = 0;
+ u16 ioc_status;
+
+ mpr_dprint(sc, MPR_TRACE, "%s\n", __func__);
+
+ if ((cm = mpr_alloc_command(sc)) == NULL) {
+ printf("%s: command alloc failed @ line %d\n", __func__,
+ __LINE__);
+ error = EBUSY;
+ goto out;
+ }
+ request = (MPI2_CONFIG_REQUEST *)cm->cm_req;
+ bzero(request, sizeof(MPI2_CONFIG_REQUEST));
+ request->Function = MPI2_FUNCTION_CONFIG;
+ request->Action = MPI2_CONFIG_ACTION_PAGE_HEADER;
+ request->Header.PageType = MPI2_CONFIG_PAGETYPE_IOC;
+ request->Header.PageNumber = 8;
+ request->Header.PageVersion = MPI2_IOCPAGE8_PAGEVERSION;
+ cm->cm_desc.Default.RequestFlags = MPI2_REQ_DESCRIPT_FLAGS_DEFAULT_TYPE;
+ cm->cm_data = NULL;
+ error = mpr_wait_command(sc, cm, 60, CAN_SLEEP);
+ reply = (MPI2_CONFIG_REPLY *)cm->cm_reply;
+ if (error || (reply == NULL)) {
+ /* FIXME */
+ /*
+ * If the request returns an error then we need to do a diag
+ * reset
+ */
+ printf("%s: request for header completed with error %d",
+ __func__, error);
+ error = ENXIO;
+ goto out;
+ }
+ ioc_status = le16toh(reply->IOCStatus) & MPI2_IOCSTATUS_MASK;
+ bcopy(reply, mpi_reply, sizeof(MPI2_CONFIG_REPLY));
+ if (ioc_status != MPI2_IOCSTATUS_SUCCESS) {
+ /* FIXME */
+ /*
+ * If the request returns an error then we need to do a diag
+ * reset
+ */
+ printf("%s: header read with error; iocstatus = 0x%x\n",
+ __func__, ioc_status);
+ error = ENXIO;
+ goto out;
+ }
+ /* We have to do free and alloc for the reply-free and reply-post
+ * counters to match - Need to review the reply FIFO handling.
+ */
+ mpr_free_command(sc, cm);
+
+ if ((cm = mpr_alloc_command(sc)) == NULL) {
+ printf("%s: command alloc failed @ line %d\n", __func__,
+ __LINE__);
+ error = EBUSY;
+ goto out;
+ }
+ request = (MPI2_CONFIG_REQUEST *)cm->cm_req;
+ bzero(request, sizeof(MPI2_CONFIG_REQUEST));
+ request->Function = MPI2_FUNCTION_CONFIG;
+ request->Action = MPI2_CONFIG_ACTION_PAGE_READ_CURRENT;
+ request->Header.PageType = MPI2_CONFIG_PAGETYPE_IOC;
+ request->Header.PageNumber = 8;
+ request->Header.PageVersion = MPI2_IOCPAGE8_PAGEVERSION;
+ request->Header.PageLength = mpi_reply->Header.PageLength;
+ cm->cm_length = le16toh(mpi_reply->Header.PageLength) * 4;
+ cm->cm_sge = &request->PageBufferSGE;
+ cm->cm_sglsize = sizeof(MPI2_SGE_IO_UNION);
+ cm->cm_flags = MPR_CM_FLAGS_SGE_SIMPLE | MPR_CM_FLAGS_DATAIN;
+ cm->cm_desc.Default.RequestFlags = MPI2_REQ_DESCRIPT_FLAGS_DEFAULT_TYPE;
+ page = malloc((cm->cm_length), M_MPR, M_ZERO | M_NOWAIT);
+ if (!page) {
+ printf("%s: page alloc failed\n", __func__);
+ error = ENOMEM;
+ goto out;
+ }
+ cm->cm_data = page;
+
+ error = mpr_wait_command(sc, cm, 60, CAN_SLEEP);
+ reply = (MPI2_CONFIG_REPLY *)cm->cm_reply;
+ if (error || (reply == NULL)) {
+ /* FIXME */
+ /*
+ * If the request returns an error then we need to do a diag
+ * reset
+ */
+ printf("%s: request for page completed with error %d",
+ __func__, error);
+ error = ENXIO;
+ goto out;
+ }
+ ioc_status = le16toh(reply->IOCStatus) & MPI2_IOCSTATUS_MASK;
+ bcopy(reply, mpi_reply, sizeof(MPI2_CONFIG_REPLY));
+ if (ioc_status != MPI2_IOCSTATUS_SUCCESS) {
+ /* FIXME */
+ /*
+ * If the request returns an error then we need to do a diag
+ * reset
+ */
+ printf("%s: page read with error; iocstatus = 0x%x\n",
+ __func__, ioc_status);
+ error = ENXIO;
+ goto out;
+ }
+ bcopy(page, config_page, MIN(cm->cm_length, (sizeof(Mpi2IOCPage8_t))));
+
+out:
+ free(page, M_MPR);
+ if (cm)
+ mpr_free_command(sc, cm);
+ return (error);
+}
+
+/**
+ * mpr_config_get_iounit_pg8 - obtain iounit page 8
+ * @sc: per adapter object
+ * @mpi_reply: reply mf payload returned from firmware
+ * @config_page: contents of the config page
+ * Context: sleep.
+ *
+ * Returns 0 for success, non-zero for failure.
+ */
+int
+mpr_config_get_iounit_pg8(struct mpr_softc *sc, Mpi2ConfigReply_t *mpi_reply,
+ Mpi2IOUnitPage8_t *config_page)
+{
+ MPI2_CONFIG_REQUEST *request;
+ MPI2_CONFIG_REPLY *reply;
+ struct mpr_command *cm;
+ MPI2_CONFIG_PAGE_IO_UNIT_8 *page = NULL;
+ int error = 0;
+ u16 ioc_status;
+
+ mpr_dprint(sc, MPR_TRACE, "%s\n", __func__);
+
+ if ((cm = mpr_alloc_command(sc)) == NULL) {
+ printf("%s: command alloc failed @ line %d\n", __func__,
+ __LINE__);
+ error = EBUSY;
+ goto out;
+ }
+ request = (MPI2_CONFIG_REQUEST *)cm->cm_req;
+ bzero(request, sizeof(MPI2_CONFIG_REQUEST));
+ request->Function = MPI2_FUNCTION_CONFIG;
+ request->Action = MPI2_CONFIG_ACTION_PAGE_HEADER;
+ request->Header.PageType = MPI2_CONFIG_PAGETYPE_IO_UNIT;
+ request->Header.PageNumber = 8;
+ request->Header.PageVersion = MPI2_IOUNITPAGE8_PAGEVERSION;
+ cm->cm_desc.Default.RequestFlags = MPI2_REQ_DESCRIPT_FLAGS_DEFAULT_TYPE;
+ cm->cm_data = NULL;
+ error = mpr_wait_command(sc, cm, 60, CAN_SLEEP);
+ reply = (MPI2_CONFIG_REPLY *)cm->cm_reply;
+ if (error || (reply == NULL)) {
+ /* FIXME */
+ /*
+ * If the request returns an error then we need to do a diag
+ * reset
+ */
+ printf("%s: request for header completed with error %d",
+ __func__, error);
+ error = ENXIO;
+ goto out;
+ }
+ ioc_status = le16toh(reply->IOCStatus) & MPI2_IOCSTATUS_MASK;
+ bcopy(reply, mpi_reply, sizeof(MPI2_CONFIG_REPLY));
+ if (ioc_status != MPI2_IOCSTATUS_SUCCESS) {
+ /* FIXME */
+ /*
+ * If the request returns an error then we need to do a diag
+ * reset
+ */
+ printf("%s: header read with error; iocstatus = 0x%x\n",
+ __func__, ioc_status);
+ error = ENXIO;
+ goto out;
+ }
+ /* We have to do free and alloc for the reply-free and reply-post
+ * counters to match - Need to review the reply FIFO handling.
+ */
+ mpr_free_command(sc, cm);
+
+ if ((cm = mpr_alloc_command(sc)) == NULL) {
+ printf("%s: command alloc failed @ line %d\n", __func__,
+ __LINE__);
+ error = EBUSY;
+ goto out;
+ }
+ request = (MPI2_CONFIG_REQUEST *)cm->cm_req;
+ bzero(request, sizeof(MPI2_CONFIG_REQUEST));
+ request->Function = MPI2_FUNCTION_CONFIG;
+ request->Action = MPI2_CONFIG_ACTION_PAGE_READ_CURRENT;
+ request->Header.PageType = MPI2_CONFIG_PAGETYPE_IO_UNIT;
+ request->Header.PageNumber = 8;
+ request->Header.PageVersion = MPI2_IOUNITPAGE8_PAGEVERSION;
+ request->Header.PageLength = mpi_reply->Header.PageLength;
+ cm->cm_length = le16toh(mpi_reply->Header.PageLength) * 4;
+ cm->cm_sge = &request->PageBufferSGE;
+ cm->cm_sglsize = sizeof(MPI2_SGE_IO_UNION);
+ cm->cm_flags = MPR_CM_FLAGS_SGE_SIMPLE | MPR_CM_FLAGS_DATAIN;
+ cm->cm_desc.Default.RequestFlags = MPI2_REQ_DESCRIPT_FLAGS_DEFAULT_TYPE;
+ page = malloc((cm->cm_length), M_MPR, M_ZERO | M_NOWAIT);
+ if (!page) {
+ printf("%s: page alloc failed\n", __func__);
+ error = ENOMEM;
+ goto out;
+ }
+ cm->cm_data = page;
+
+ error = mpr_wait_command(sc, cm, 60, CAN_SLEEP);
+ reply = (MPI2_CONFIG_REPLY *)cm->cm_reply;
+ if (error || (reply == NULL)) {
+ /* FIXME */
+ /*
+ * If the request returns an error then we need to do a diag
+ * reset
+ */
+ printf("%s: request for page completed with error %d",
+ __func__, error);
+ error = ENXIO;
+ goto out;
+ }
+ ioc_status = le16toh(reply->IOCStatus) & MPI2_IOCSTATUS_MASK;
+ bcopy(reply, mpi_reply, sizeof(MPI2_CONFIG_REPLY));
+ if (ioc_status != MPI2_IOCSTATUS_SUCCESS) {
+ /* FIXME */
+ /*
+ * If the request returns an error then we need to do a diag
+ * reset
+ */
+ printf("%s: page read with error; iocstatus = 0x%x\n",
+ __func__, ioc_status);
+ error = ENXIO;
+ goto out;
+ }
+ bcopy(page, config_page, MIN(cm->cm_length,
+ (sizeof(Mpi2IOUnitPage8_t))));
+
+out:
+ free(page, M_MPR);
+ if (cm)
+ mpr_free_command(sc, cm);
+ return (error);
+}
+
+/**
+ * mpr_base_static_config_pages - static start of day config pages.
+ * @sc: per adapter object
+ *
+ * Return nothing.
+ */
+void
+mpr_base_static_config_pages(struct mpr_softc *sc)
+{
+ Mpi2ConfigReply_t mpi_reply;
+ int retry;
+
+ retry = 0;
+ while (mpr_config_get_ioc_pg8(sc, &mpi_reply, &sc->ioc_pg8)) {
+ retry++;
+ if (retry > 5) {
+ /* We need to Handle this situation */
+ /*FIXME*/
+ break;
+ }
+ }
+ retry = 0;
+ while (mpr_config_get_iounit_pg8(sc, &mpi_reply, &sc->iounit_pg8)) {
+ retry++;
+ if (retry > 5) {
+ /* We need to Handle this situation */
+ /*FIXME*/
+ break;
+ }
+ }
+}
+
+/**
+ * mpr_config_get_dpm_pg0 - obtain driver persistent mapping page0
+ * @sc: per adapter object
+ * @mpi_reply: reply mf payload returned from firmware
+ * @config_page: contents of the config page
+ * @sz: size of buffer passed in config_page
+ * Context: sleep.
+ *
+ * Returns 0 for success, non-zero for failure.
+ */
+int
+mpr_config_get_dpm_pg0(struct mpr_softc *sc, Mpi2ConfigReply_t *mpi_reply,
+ Mpi2DriverMappingPage0_t *config_page, u16 sz)
+{
+ MPI2_CONFIG_REQUEST *request;
+ MPI2_CONFIG_REPLY *reply;
+ struct mpr_command *cm;
+ Mpi2DriverMappingPage0_t *page = NULL;
+ int error = 0;
+ u16 ioc_status;
+
+ mpr_dprint(sc, MPR_TRACE, "%s\n", __func__);
+
+ memset(config_page, 0, sz);
+ if ((cm = mpr_alloc_command(sc)) == NULL) {
+ printf("%s: command alloc failed @ line %d\n", __func__,
+ __LINE__);
+ error = EBUSY;
+ goto out;
+ }
+ request = (MPI2_CONFIG_REQUEST *)cm->cm_req;
+ bzero(request, sizeof(MPI2_CONFIG_REQUEST));
+ request->Function = MPI2_FUNCTION_CONFIG;
+ request->Action = MPI2_CONFIG_ACTION_PAGE_HEADER;
+ request->Header.PageType = MPI2_CONFIG_PAGETYPE_EXTENDED;
+ request->ExtPageType = MPI2_CONFIG_EXTPAGETYPE_DRIVER_MAPPING;
+ request->Header.PageNumber = 0;
+ request->Header.PageVersion = MPI2_DRIVERMAPPING0_PAGEVERSION;
+ request->PageAddress = sc->max_dpm_entries <<
+ MPI2_DPM_PGAD_ENTRY_COUNT_SHIFT;
+ cm->cm_desc.Default.RequestFlags = MPI2_REQ_DESCRIPT_FLAGS_DEFAULT_TYPE;
+ cm->cm_data = NULL;
+ error = mpr_wait_command(sc, cm, 60, CAN_SLEEP);
+ reply = (MPI2_CONFIG_REPLY *)cm->cm_reply;
+ if (error || (reply == NULL)) {
+ /* FIXME */
+ /*
+ * If the request returns an error then we need to do a diag
+ * reset
+ */
+ printf("%s: request for header completed with error %d",
+ __func__, error);
+ error = ENXIO;
+ goto out;
+ }
+ ioc_status = le16toh(reply->IOCStatus) & MPI2_IOCSTATUS_MASK;
+ bcopy(reply, mpi_reply, sizeof(MPI2_CONFIG_REPLY));
+ if (ioc_status != MPI2_IOCSTATUS_SUCCESS) {
+ /* FIXME */
+ /*
+ * If the request returns an error then we need to do a diag
+ * reset
+ */
+ printf("%s: header read with error; iocstatus = 0x%x\n",
+ __func__, ioc_status);
+ error = ENXIO;
+ goto out;
+ }
+ /* We have to do free and alloc for the reply-free and reply-post
+ * counters to match - Need to review the reply FIFO handling.
+ */
+ mpr_free_command(sc, cm);
+
+ if ((cm = mpr_alloc_command(sc)) == NULL) {
+ printf("%s: command alloc failed @ line %d\n", __func__,
+ __LINE__);
+ error = EBUSY;
+ goto out;
+ }
+ request = (MPI2_CONFIG_REQUEST *)cm->cm_req;
+ bzero(request, sizeof(MPI2_CONFIG_REQUEST));
+ request->Function = MPI2_FUNCTION_CONFIG;
+ request->Action = MPI2_CONFIG_ACTION_PAGE_READ_NVRAM;
+ request->Header.PageType = MPI2_CONFIG_PAGETYPE_EXTENDED;
+ request->ExtPageType = MPI2_CONFIG_EXTPAGETYPE_DRIVER_MAPPING;
+ request->Header.PageNumber = 0;
+ request->Header.PageVersion = MPI2_DRIVERMAPPING0_PAGEVERSION;
+ request->PageAddress = sc->max_dpm_entries <<
+ MPI2_DPM_PGAD_ENTRY_COUNT_SHIFT;
+ request->ExtPageLength = mpi_reply->ExtPageLength;
+ cm->cm_length = le16toh(request->ExtPageLength) * 4;
+ cm->cm_sge = &request->PageBufferSGE;
+ cm->cm_sglsize = sizeof(MPI2_SGE_IO_UNION);
+ cm->cm_flags = MPR_CM_FLAGS_SGE_SIMPLE | MPR_CM_FLAGS_DATAIN;
+ cm->cm_desc.Default.RequestFlags = MPI2_REQ_DESCRIPT_FLAGS_DEFAULT_TYPE;
+ page = malloc(cm->cm_length, M_MPR, M_ZERO|M_NOWAIT);
+ if (!page) {
+ printf("%s: page alloc failed\n", __func__);
+ error = ENOMEM;
+ goto out;
+ }
+ cm->cm_data = page;
+ error = mpr_wait_command(sc, cm, 60, CAN_SLEEP);
+ reply = (MPI2_CONFIG_REPLY *)cm->cm_reply;
+ if (error || (reply == NULL)) {
+ /* FIXME */
+ /*
+ * If the request returns an error then we need to do a diag
+ * reset
+ */
+ printf("%s: request for page completed with error %d",
+ __func__, error);
+ error = ENXIO;
+ goto out;
+ }
+ ioc_status = le16toh(reply->IOCStatus) & MPI2_IOCSTATUS_MASK;
+ bcopy(reply, mpi_reply, sizeof(MPI2_CONFIG_REPLY));
+ if (ioc_status != MPI2_IOCSTATUS_SUCCESS) {
+ /* FIXME */
+ /*
+ * If the request returns an error then we need to do a diag
+ * reset
+ */
+ printf("%s: page read with error; iocstatus = 0x%x\n",
+ __func__, ioc_status);
+ error = ENXIO;
+ goto out;
+ }
+ bcopy(page, config_page, MIN(cm->cm_length, sz));
+out:
+ free(page, M_MPR);
+ if (cm)
+ mpr_free_command(sc, cm);
+ return (error);
+}
+
+/**
+ * mpr_config_set_dpm_pg0 - write an entry in driver persistent mapping page0
+ * @sc: per adapter object
+ * @mpi_reply: reply mf payload returned from firmware
+ * @config_page: contents of the config page
+ * @entry_idx: entry index in DPM Page0 to be modified
+ * Context: sleep.
+ *
+ * Returns 0 for success, non-zero for failure.
+ */
+
+int mpr_config_set_dpm_pg0(struct mpr_softc *sc, Mpi2ConfigReply_t *mpi_reply,
+ Mpi2DriverMappingPage0_t *config_page, u16 entry_idx)
+{
+ MPI2_CONFIG_REQUEST *request;
+ MPI2_CONFIG_REPLY *reply;
+ struct mpr_command *cm;
+ MPI2_CONFIG_PAGE_DRIVER_MAPPING_0 *page = NULL;
+ int error = 0;
+ u16 ioc_status;
+
+ mpr_dprint(sc, MPR_TRACE, "%s\n", __func__);
+
+ if ((cm = mpr_alloc_command(sc)) == NULL) {
+ printf("%s: command alloc failed @ line %d\n", __func__,
+ __LINE__);
+ error = EBUSY;
+ goto out;
+ }
+ request = (MPI2_CONFIG_REQUEST *)cm->cm_req;
+ bzero(request, sizeof(MPI2_CONFIG_REQUEST));
+ request->Function = MPI2_FUNCTION_CONFIG;
+ request->Action = MPI2_CONFIG_ACTION_PAGE_HEADER;
+ request->Header.PageType = MPI2_CONFIG_PAGETYPE_EXTENDED;
+ request->ExtPageType = MPI2_CONFIG_EXTPAGETYPE_DRIVER_MAPPING;
+ request->Header.PageNumber = 0;
+ request->Header.PageVersion = MPI2_DRIVERMAPPING0_PAGEVERSION;
+ /* We can remove below two lines ????*/
+ request->PageAddress = 1 << MPI2_DPM_PGAD_ENTRY_COUNT_SHIFT;
+ request->PageAddress |= htole16(entry_idx);
+ cm->cm_desc.Default.RequestFlags = MPI2_REQ_DESCRIPT_FLAGS_DEFAULT_TYPE;
+ cm->cm_data = NULL;
+ error = mpr_wait_command(sc, cm, 60, CAN_SLEEP);
+ reply = (MPI2_CONFIG_REPLY *)cm->cm_reply;
+ if (error || (reply == NULL)) {
+ /* FIXME */
+ /*
+ * If the request returns an error then we need to do a diag
+ * reset
+ */
+ printf("%s: request for header completed with error %d",
+ __func__, error);
+ error = ENXIO;
+ goto out;
+ }
+ ioc_status = le16toh(reply->IOCStatus) & MPI2_IOCSTATUS_MASK;
+ bcopy(reply, mpi_reply, sizeof(MPI2_CONFIG_REPLY));
+ if (ioc_status != MPI2_IOCSTATUS_SUCCESS) {
+ /* FIXME */
+ /*
+ * If the request returns an error then we need to do a diag
+ * reset
+ */
+ printf("%s: header read with error; iocstatus = 0x%x\n",
+ __func__, ioc_status);
+ error = ENXIO;
+ goto out;
+ }
+ /* We have to do free and alloc for the reply-free and reply-post
+ * counters to match - Need to review the reply FIFO handling.
+ */
+ mpr_free_command(sc, cm);
+
+ if ((cm = mpr_alloc_command(sc)) == NULL) {
+ printf("%s: command alloc failed @ line %d\n", __func__,
+ __LINE__);
+ error = EBUSY;
+ goto out;
+ }
+ request = (MPI2_CONFIG_REQUEST *)cm->cm_req;
+ bzero(request, sizeof(MPI2_CONFIG_REQUEST));
+ request->Function = MPI2_FUNCTION_CONFIG;
+ request->Action = MPI2_CONFIG_ACTION_PAGE_WRITE_NVRAM;
+ request->Header.PageType = MPI2_CONFIG_PAGETYPE_EXTENDED;
+ request->ExtPageType = MPI2_CONFIG_EXTPAGETYPE_DRIVER_MAPPING;
+ request->Header.PageNumber = 0;
+ request->Header.PageVersion = MPI2_DRIVERMAPPING0_PAGEVERSION;
+ request->ExtPageLength = mpi_reply->ExtPageLength;
+ request->PageAddress = 1 << MPI2_DPM_PGAD_ENTRY_COUNT_SHIFT;
+ request->PageAddress |= htole16(entry_idx);
+ cm->cm_length = le16toh(mpi_reply->ExtPageLength) * 4;
+ cm->cm_sge = &request->PageBufferSGE;
+ cm->cm_sglsize = sizeof(MPI2_SGE_IO_UNION);
+ cm->cm_flags = MPR_CM_FLAGS_SGE_SIMPLE | MPR_CM_FLAGS_DATAOUT;
+ cm->cm_desc.Default.RequestFlags = MPI2_REQ_DESCRIPT_FLAGS_DEFAULT_TYPE;
+ page = malloc(cm->cm_length, M_MPR, M_ZERO | M_NOWAIT);
+ if (!page) {
+ printf("%s: page alloc failed\n", __func__);
+ error = ENOMEM;
+ goto out;
+ }
+ bcopy(config_page, page, MIN(cm->cm_length,
+ (sizeof(Mpi2DriverMappingPage0_t))));
+ cm->cm_data = page;
+ error = mpr_wait_command(sc, cm, 60, CAN_SLEEP);
+ reply = (MPI2_CONFIG_REPLY *)cm->cm_reply;
+ if (error || (reply == NULL)) {
+ /* FIXME */
+ /*
+ * If the request returns an error then we need to do a diag
+ * reset
+ */
+ printf("%s: request to write page completed with error %d",
+ __func__, error);
+ error = ENXIO;
+ goto out;
+ }
+ ioc_status = le16toh(reply->IOCStatus) & MPI2_IOCSTATUS_MASK;
+ bcopy(reply, mpi_reply, sizeof(MPI2_CONFIG_REPLY));
+ if (ioc_status != MPI2_IOCSTATUS_SUCCESS) {
+ /* FIXME */
+ /*
+ * If the request returns an error then we need to do a diag
+ * reset
+ */
+ printf("%s: page written with error; iocstatus = 0x%x\n",
+ __func__, ioc_status);
+ error = ENXIO;
+ goto out;
+ }
+out:
+ free(page, M_MPR);
+ if (cm)
+ mpr_free_command(sc, cm);
+ return (error);
+}
+
+/**
+ * mpr_config_get_sas_device_pg0 - obtain sas device page 0
+ * @sc: per adapter object
+ * @mpi_reply: reply mf payload returned from firmware
+ * @config_page: contents of the config page
+ * @form: GET_NEXT_HANDLE or HANDLE
+ * @handle: device handle
+ * Context: sleep.
+ *
+ * Returns 0 for success, non-zero for failure.
+ */
+int
+mpr_config_get_sas_device_pg0(struct mpr_softc *sc, Mpi2ConfigReply_t
+ *mpi_reply, Mpi2SasDevicePage0_t *config_page, u32 form, u16 handle)
+{
+ MPI2_CONFIG_REQUEST *request;
+ MPI2_CONFIG_REPLY *reply;
+ struct mpr_command *cm;
+ Mpi2SasDevicePage0_t *page = NULL;
+ int error = 0;
+ u16 ioc_status;
+
+ mpr_dprint(sc, MPR_TRACE, "%s\n", __func__);
+
+ if ((cm = mpr_alloc_command(sc)) == NULL) {
+ printf("%s: command alloc failed @ line %d\n", __func__,
+ __LINE__);
+ error = EBUSY;
+ goto out;
+ }
+ request = (MPI2_CONFIG_REQUEST *)cm->cm_req;
+ bzero(request, sizeof(MPI2_CONFIG_REQUEST));
+ request->Function = MPI2_FUNCTION_CONFIG;
+ request->Action = MPI2_CONFIG_ACTION_PAGE_HEADER;
+ request->Header.PageType = MPI2_CONFIG_PAGETYPE_EXTENDED;
+ request->ExtPageType = MPI2_CONFIG_EXTPAGETYPE_SAS_DEVICE;
+ request->Header.PageNumber = 0;
+ request->Header.PageVersion = MPI2_SASDEVICE0_PAGEVERSION;
+ cm->cm_desc.Default.RequestFlags = MPI2_REQ_DESCRIPT_FLAGS_DEFAULT_TYPE;
+ cm->cm_data = NULL;
+ error = mpr_wait_command(sc, cm, 60, CAN_SLEEP);
+ reply = (MPI2_CONFIG_REPLY *)cm->cm_reply;
+ if (error || (reply == NULL)) {
+ /* FIXME */
+ /*
+ * If the request returns an error then we need to do a diag
+ * reset
+ */
+ printf("%s: request for header completed with error %d",
+ __func__, error);
+ error = ENXIO;
+ goto out;
+ }
+ ioc_status = le16toh(reply->IOCStatus) & MPI2_IOCSTATUS_MASK;
+ bcopy(reply, mpi_reply, sizeof(MPI2_CONFIG_REPLY));
+ if (ioc_status != MPI2_IOCSTATUS_SUCCESS) {
+ /* FIXME */
+ /*
+ * If the request returns an error then we need to do a diag
+ * reset
+ */
+ printf("%s: header read with error; iocstatus = 0x%x\n",
+ __func__, ioc_status);
+ error = ENXIO;
+ goto out;
+ }
+ /* We have to do free and alloc for the reply-free and reply-post
+ * counters to match - Need to review the reply FIFO handling.
+ */
+ mpr_free_command(sc, cm);
+
+ if ((cm = mpr_alloc_command(sc)) == NULL) {
+ printf("%s: command alloc failed @ line %d\n", __func__,
+ __LINE__);
+ error = EBUSY;
+ goto out;
+ }
+ request = (MPI2_CONFIG_REQUEST *)cm->cm_req;
+ bzero(request, sizeof(MPI2_CONFIG_REQUEST));
+ request->Function = MPI2_FUNCTION_CONFIG;
+ request->Action = MPI2_CONFIG_ACTION_PAGE_READ_CURRENT;
+ request->Header.PageType = MPI2_CONFIG_PAGETYPE_EXTENDED;
+ request->ExtPageType = MPI2_CONFIG_EXTPAGETYPE_SAS_DEVICE;
+ request->Header.PageNumber = 0;
+ request->Header.PageVersion = MPI2_SASDEVICE0_PAGEVERSION;
+ request->ExtPageLength = mpi_reply->ExtPageLength;
+ request->PageAddress = htole32(form | handle);
+ cm->cm_length = le16toh(mpi_reply->ExtPageLength) * 4;
+ cm->cm_sge = &request->PageBufferSGE;
+ cm->cm_sglsize = sizeof(MPI2_SGE_IO_UNION);
+ cm->cm_flags = MPR_CM_FLAGS_SGE_SIMPLE | MPR_CM_FLAGS_DATAIN;
+ cm->cm_desc.Default.RequestFlags = MPI2_REQ_DESCRIPT_FLAGS_DEFAULT_TYPE;
+ page = malloc(cm->cm_length, M_MPR, M_ZERO | M_NOWAIT);
+ if (!page) {
+ printf("%s: page alloc failed\n", __func__);
+ error = ENOMEM;
+ goto out;
+ }
+ cm->cm_data = page;
+
+ error = mpr_wait_command(sc, cm, 60, CAN_SLEEP);
+ reply = (MPI2_CONFIG_REPLY *)cm->cm_reply;
+ if (error || (reply == NULL)) {
+ /* FIXME */
+ /*
+ * If the request returns an error then we need to do a diag
+ * reset
+ */
+ printf("%s: request for page completed with error %d",
+ __func__, error);
+ error = ENXIO;
+ goto out;
+ }
+ ioc_status = le16toh(reply->IOCStatus) & MPI2_IOCSTATUS_MASK;
+ bcopy(reply, mpi_reply, sizeof(MPI2_CONFIG_REPLY));
+ if (ioc_status != MPI2_IOCSTATUS_SUCCESS) {
+ /* FIXME */
+ /*
+ * If the request returns an error then we need to do a diag
+ * reset
+ */
+ printf("%s: page read with error; iocstatus = 0x%x\n",
+ __func__, ioc_status);
+ error = ENXIO;
+ goto out;
+ }
+ bcopy(page, config_page, MIN(cm->cm_length,
+ sizeof(Mpi2SasDevicePage0_t)));
+out:
+ free(page, M_MPR);
+ if (cm)
+ mpr_free_command(sc, cm);
+ return (error);
+}
+
+/**
+ * mpr_config_get_bios_pg3 - obtain BIOS page 3
+ * @sc: per adapter object
+ * @mpi_reply: reply mf payload returned from firmware
+ * @config_page: contents of the config page
+ * Context: sleep.
+ *
+ * Returns 0 for success, non-zero for failure.
+ */
+int
+mpr_config_get_bios_pg3(struct mpr_softc *sc, Mpi2ConfigReply_t *mpi_reply,
+ Mpi2BiosPage3_t *config_page)
+{
+ MPI2_CONFIG_REQUEST *request;
+ MPI2_CONFIG_REPLY *reply;
+ struct mpr_command *cm;
+ Mpi2BiosPage3_t *page = NULL;
+ int error = 0;
+ u16 ioc_status;
+
+ mpr_dprint(sc, MPR_TRACE, "%s\n", __func__);
+
+ if ((cm = mpr_alloc_command(sc)) == NULL) {
+ printf("%s: command alloc failed @ line %d\n", __func__,
+ __LINE__);
+ error = EBUSY;
+ goto out;
+ }
+ request = (MPI2_CONFIG_REQUEST *)cm->cm_req;
+ bzero(request, sizeof(MPI2_CONFIG_REQUEST));
+ request->Function = MPI2_FUNCTION_CONFIG;
+ request->Action = MPI2_CONFIG_ACTION_PAGE_HEADER;
+ request->Header.PageType = MPI2_CONFIG_PAGETYPE_BIOS;
+ request->Header.PageNumber = 3;
+ request->Header.PageVersion = MPI2_BIOSPAGE3_PAGEVERSION;
+ cm->cm_desc.Default.RequestFlags = MPI2_REQ_DESCRIPT_FLAGS_DEFAULT_TYPE;
+ cm->cm_data = NULL;
+ error = mpr_wait_command(sc, cm, 60, CAN_SLEEP);
+ reply = (MPI2_CONFIG_REPLY *)cm->cm_reply;
+ if (error || (reply == NULL)) {
+ /* FIXME */
+ /*
+ * If the request returns an error then we need to do a diag
+ * reset
+ */
+ printf("%s: request for header completed with error %d",
+ __func__, error);
+ error = ENXIO;
+ goto out;
+ }
+ ioc_status = le16toh(reply->IOCStatus) & MPI2_IOCSTATUS_MASK;
+ bcopy(reply, mpi_reply, sizeof(MPI2_CONFIG_REPLY));
+ if (ioc_status != MPI2_IOCSTATUS_SUCCESS) {
+ /* FIXME */
+ /*
+ * If the request returns an error then we need to do a diag
+ * reset
+ */
+ printf("%s: header read with error; iocstatus = 0x%x\n",
+ __func__, ioc_status);
+ error = ENXIO;
+ goto out;
+ }
+ /* We have to do free and alloc for the reply-free and reply-post
+ * counters to match - Need to review the reply FIFO handling.
+ */
+ mpr_free_command(sc, cm);
+
+ if ((cm = mpr_alloc_command(sc)) == NULL) {
+ printf("%s: command alloc failed @ line %d\n", __func__,
+ __LINE__);
+ error = EBUSY;
+ goto out;
+ }
+ request = (MPI2_CONFIG_REQUEST *)cm->cm_req;
+ bzero(request, sizeof(MPI2_CONFIG_REQUEST));
+ request->Function = MPI2_FUNCTION_CONFIG;
+ request->Action = MPI2_CONFIG_ACTION_PAGE_READ_CURRENT;
+ request->Header.PageType = MPI2_CONFIG_PAGETYPE_BIOS;
+ request->Header.PageNumber = 3;
+ request->Header.PageVersion = MPI2_BIOSPAGE3_PAGEVERSION;
+ request->Header.PageLength = mpi_reply->Header.PageLength;
+ cm->cm_length = le16toh(mpi_reply->Header.PageLength) * 4;
+ cm->cm_sge = &request->PageBufferSGE;
+ cm->cm_sglsize = sizeof(MPI2_SGE_IO_UNION);
+ cm->cm_flags = MPR_CM_FLAGS_SGE_SIMPLE | MPR_CM_FLAGS_DATAIN;
+ cm->cm_desc.Default.RequestFlags = MPI2_REQ_DESCRIPT_FLAGS_DEFAULT_TYPE;
+ page = malloc(cm->cm_length, M_MPR, M_ZERO | M_NOWAIT);
+ if (!page) {
+ printf("%s: page alloc failed\n", __func__);
+ error = ENOMEM;
+ goto out;
+ }
+ cm->cm_data = page;
+
+ error = mpr_wait_command(sc, cm, 60, CAN_SLEEP);
+ reply = (MPI2_CONFIG_REPLY *)cm->cm_reply;
+ if (error || (reply == NULL)) {
+ /* FIXME */
+ /*
+ * If the request returns an error then we need to do a diag
+ * reset
+ */
+ printf("%s: request for page completed with error %d",
+ __func__, error);
+ error = ENXIO;
+ goto out;
+ }
+ ioc_status = le16toh(reply->IOCStatus) & MPI2_IOCSTATUS_MASK;
+ bcopy(reply, mpi_reply, sizeof(MPI2_CONFIG_REPLY));
+ if (ioc_status != MPI2_IOCSTATUS_SUCCESS) {
+ /* FIXME */
+ /*
+ * If the request returns an error then we need to do a diag
+ * reset
+ */
+ printf("%s: page read with error; iocstatus = 0x%x\n",
+ __func__, ioc_status);
+ error = ENXIO;
+ goto out;
+ }
+ bcopy(page, config_page, MIN(cm->cm_length, sizeof(Mpi2BiosPage3_t)));
+out:
+ free(page, M_MPR);
+ if (cm)
+ mpr_free_command(sc, cm);
+ return (error);
+}
+
+/**
+ * mpr_config_get_raid_volume_pg0 - obtain raid volume page 0
+ * @sc: per adapter object
+ * @mpi_reply: reply mf payload returned from firmware
+ * @config_page: contents of the config page
+ * @page_address: form and handle value used to get page
+ * Context: sleep.
+ *
+ * Returns 0 for success, non-zero for failure.
+ */
+int
+mpr_config_get_raid_volume_pg0(struct mpr_softc *sc, Mpi2ConfigReply_t
+ *mpi_reply, Mpi2RaidVolPage0_t *config_page, u32 page_address)
+{
+ MPI2_CONFIG_REQUEST *request;
+ MPI2_CONFIG_REPLY *reply;
+ struct mpr_command *cm;
+ Mpi2RaidVolPage0_t *page = NULL;
+ int error = 0;
+ u16 ioc_status;
+
+ mpr_dprint(sc, MPR_TRACE, "%s\n", __func__);
+
+ if ((cm = mpr_alloc_command(sc)) == NULL) {
+ printf("%s: command alloc failed @ line %d\n", __func__,
+ __LINE__);
+ error = EBUSY;
+ goto out;
+ }
+ request = (MPI2_CONFIG_REQUEST *)cm->cm_req;
+ bzero(request, sizeof(MPI2_CONFIG_REQUEST));
+ request->Function = MPI2_FUNCTION_CONFIG;
+ request->Action = MPI2_CONFIG_ACTION_PAGE_HEADER;
+ request->Header.PageType = MPI2_CONFIG_PAGETYPE_RAID_VOLUME;
+ request->Header.PageNumber = 0;
+ request->Header.PageVersion = MPI2_RAIDVOLPAGE0_PAGEVERSION;
+ cm->cm_desc.Default.RequestFlags = MPI2_REQ_DESCRIPT_FLAGS_DEFAULT_TYPE;
+ cm->cm_data = NULL;
+
+ /*
+ * This page must be polled because the IOC isn't ready yet when this
+ * page is needed.
+ */
+ error = mpr_request_polled(sc, cm);
+ reply = (MPI2_CONFIG_REPLY *)cm->cm_reply;
+ if (error || (reply == NULL)) {
+ /* FIXME */
+ /* If the poll returns error then we need to do diag reset */
+ printf("%s: poll for header completed with error %d",
+ __func__, error);
+ error = ENXIO;
+ goto out;
+ }
+ ioc_status = le16toh(reply->IOCStatus) & MPI2_IOCSTATUS_MASK;
+ bcopy(reply, mpi_reply, sizeof(MPI2_CONFIG_REPLY));
+ if (ioc_status != MPI2_IOCSTATUS_SUCCESS) {
+ /* FIXME */
+ /* If the poll returns error then we need to do diag reset */
+ printf("%s: header read with error; iocstatus = 0x%x\n",
+ __func__, ioc_status);
+ error = ENXIO;
+ goto out;
+ }
+ /* We have to do free and alloc for the reply-free and reply-post
+ * counters to match - Need to review the reply FIFO handling.
+ */
+ mpr_free_command(sc, cm);
+
+ if ((cm = mpr_alloc_command(sc)) == NULL) {
+ printf("%s: command alloc failed @ line %d\n", __func__,
+ __LINE__);
+ error = EBUSY;
+ goto out;
+ }
+ request = (MPI2_CONFIG_REQUEST *)cm->cm_req;
+ bzero(request, sizeof(MPI2_CONFIG_REQUEST));
+ request->Function = MPI2_FUNCTION_CONFIG;
+ request->Action = MPI2_CONFIG_ACTION_PAGE_READ_CURRENT;
+ request->Header.PageType = MPI2_CONFIG_PAGETYPE_RAID_VOLUME;
+ request->Header.PageNumber = 0;
+ request->Header.PageLength = mpi_reply->Header.PageLength;
+ request->Header.PageVersion = mpi_reply->Header.PageVersion;
+ request->PageAddress = page_address;
+ cm->cm_length = le16toh(mpi_reply->Header.PageLength) * 4;
+ cm->cm_sge = &request->PageBufferSGE;
+ cm->cm_sglsize = sizeof(MPI2_SGE_IO_UNION);
+ cm->cm_flags = MPR_CM_FLAGS_SGE_SIMPLE | MPR_CM_FLAGS_DATAIN;
+ cm->cm_desc.Default.RequestFlags = MPI2_REQ_DESCRIPT_FLAGS_DEFAULT_TYPE;
+ page = malloc(cm->cm_length, M_MPR, M_ZERO | M_NOWAIT);
+ if (!page) {
+ printf("%s: page alloc failed\n", __func__);
+ error = ENOMEM;
+ goto out;
+ }
+ cm->cm_data = page;
+
+ /*
+ * This page must be polled because the IOC isn't ready yet when this
+ * page is needed.
+ */
+ error = mpr_request_polled(sc, cm);
+ reply = (MPI2_CONFIG_REPLY *)cm->cm_reply;
+ if (error || (reply == NULL)) {
+ /* FIXME */
+ /* If the poll returns error then we need to do diag reset */
+ printf("%s: poll for page completed with error %d",
+ __func__, error);
+ error = ENXIO;
+ goto out;
+ }
+ ioc_status = le16toh(reply->IOCStatus) & MPI2_IOCSTATUS_MASK;
+ bcopy(reply, mpi_reply, sizeof(MPI2_CONFIG_REPLY));
+ if (ioc_status != MPI2_IOCSTATUS_SUCCESS) {
+ /* FIXME */
+ /* If the poll returns error then we need to do diag reset */
+ printf("%s: page read with error; iocstatus = 0x%x\n",
+ __func__, ioc_status);
+ error = ENXIO;
+ goto out;
+ }
+ bcopy(page, config_page, cm->cm_length);
+out:
+ free(page, M_MPR);
+ if (cm)
+ mpr_free_command(sc, cm);
+ return (error);
+}
+
+/**
+ * mpr_config_get_raid_volume_pg1 - obtain raid volume page 1
+ * @sc: per adapter object
+ * @mpi_reply: reply mf payload returned from firmware
+ * @config_page: contents of the config page
+ * @form: GET_NEXT_HANDLE or HANDLE
+ * @handle: volume handle
+ * Context: sleep.
+ *
+ * Returns 0 for success, non-zero for failure.
+ */
+int
+mpr_config_get_raid_volume_pg1(struct mpr_softc *sc, Mpi2ConfigReply_t
+ *mpi_reply, Mpi2RaidVolPage1_t *config_page, u32 form, u16 handle)
+{
+ MPI2_CONFIG_REQUEST *request;
+ MPI2_CONFIG_REPLY *reply;
+ struct mpr_command *cm;
+ Mpi2RaidVolPage1_t *page = NULL;
+ int error = 0;
+ u16 ioc_status;
+
+ mpr_dprint(sc, MPR_TRACE, "%s\n", __func__);
+
+ if ((cm = mpr_alloc_command(sc)) == NULL) {
+ printf("%s: command alloc failed @ line %d\n", __func__,
+ __LINE__);
+ error = EBUSY;
+ goto out;
+ }
+ request = (MPI2_CONFIG_REQUEST *)cm->cm_req;
+ bzero(request, sizeof(MPI2_CONFIG_REQUEST));
+ request->Function = MPI2_FUNCTION_CONFIG;
+ request->Action = MPI2_CONFIG_ACTION_PAGE_HEADER;
+ request->Header.PageType = MPI2_CONFIG_PAGETYPE_RAID_VOLUME;
+ request->Header.PageNumber = 1;
+ request->Header.PageVersion = MPI2_RAIDVOLPAGE1_PAGEVERSION;
+ cm->cm_desc.Default.RequestFlags = MPI2_REQ_DESCRIPT_FLAGS_DEFAULT_TYPE;
+ cm->cm_data = NULL;
+ error = mpr_wait_command(sc, cm, 60, CAN_SLEEP);
+ reply = (MPI2_CONFIG_REPLY *)cm->cm_reply;
+ if (error || (reply == NULL)) {
+ /* FIXME */
+ /*
+ * If the request returns an error then we need to do a diag
+ * reset
+ */
+ printf("%s: request for header completed with error %d",
+ __func__, error);
+ error = ENXIO;
+ goto out;
+ }
+ ioc_status = le16toh(reply->IOCStatus) & MPI2_IOCSTATUS_MASK;
+ bcopy(reply, mpi_reply, sizeof(MPI2_CONFIG_REPLY));
+ if (ioc_status != MPI2_IOCSTATUS_SUCCESS) {
+ /* FIXME */
+ /*
+ * If the request returns an error then we need to do a diag
+ * reset
+ */
+ printf("%s: header read with error; iocstatus = 0x%x\n",
+ __func__, ioc_status);
+ error = ENXIO;
+ goto out;
+ }
+ /* We have to do free and alloc for the reply-free and reply-post
+ * counters to match - Need to review the reply FIFO handling.
+ */
+ mpr_free_command(sc, cm);
+
+ if ((cm = mpr_alloc_command(sc)) == NULL) {
+ printf("%s: command alloc failed @ line %d\n", __func__,
+ __LINE__);
+ error = EBUSY;
+ goto out;
+ }
+ request = (MPI2_CONFIG_REQUEST *)cm->cm_req;
+ bzero(request, sizeof(MPI2_CONFIG_REQUEST));
+ request->Function = MPI2_FUNCTION_CONFIG;
+ request->Action = MPI2_CONFIG_ACTION_PAGE_READ_CURRENT;
+ request->Header.PageType = MPI2_CONFIG_PAGETYPE_RAID_VOLUME;
+ request->Header.PageNumber = 1;
+ request->Header.PageLength = mpi_reply->Header.PageLength;
+ request->Header.PageVersion = mpi_reply->Header.PageVersion;
+ request->PageAddress = htole32(form | handle);
+ cm->cm_length = le16toh(mpi_reply->Header.PageLength) * 4;
+ cm->cm_sge = &request->PageBufferSGE;
+ cm->cm_sglsize = sizeof(MPI2_SGE_IO_UNION);
+ cm->cm_flags = MPR_CM_FLAGS_SGE_SIMPLE | MPR_CM_FLAGS_DATAIN;
+ cm->cm_desc.Default.RequestFlags = MPI2_REQ_DESCRIPT_FLAGS_DEFAULT_TYPE;
+ page = malloc(cm->cm_length, M_MPR, M_ZERO | M_NOWAIT);
+ if (!page) {
+ printf("%s: page alloc failed\n", __func__);
+ error = ENOMEM;
+ goto out;
+ }
+ cm->cm_data = page;
+
+ error = mpr_wait_command(sc, cm, 60, CAN_SLEEP);
+ reply = (MPI2_CONFIG_REPLY *)cm->cm_reply;
+ if (error || (reply == NULL)) {
+ /* FIXME */
+ /*
+ * If the request returns an error then we need to do a diag
+ * reset
+ */
+ printf("%s: request for page completed with error %d",
+ __func__, error);
+ error = ENXIO;
+ goto out;
+ }
+ ioc_status = le16toh(reply->IOCStatus) & MPI2_IOCSTATUS_MASK;
+ bcopy(reply, mpi_reply, sizeof(MPI2_CONFIG_REPLY));
+ if (ioc_status != MPI2_IOCSTATUS_SUCCESS) {
+ /* FIXME */
+ /*
+ * If the request returns an error then we need to do a diag
+ * reset
+ */
+ printf("%s: page read with error; iocstatus = 0x%x\n",
+ __func__, ioc_status);
+ error = ENXIO;
+ goto out;
+ }
+ bcopy(page, config_page, MIN(cm->cm_length,
+ sizeof(Mpi2RaidVolPage1_t)));
+out:
+ free(page, M_MPR);
+ if (cm)
+ mpr_free_command(sc, cm);
+ return (error);
+}
+
+/**
+ * mpr_config_get_volume_wwid - returns wwid given the volume handle
+ * @sc: per adapter object
+ * @volume_handle: volume handle
+ * @wwid: volume wwid
+ * Context: sleep.
+ *
+ * Returns 0 for success, non-zero for failure.
+ */
+int
+mpr_config_get_volume_wwid(struct mpr_softc *sc, u16 volume_handle, u64 *wwid)
+{
+ Mpi2ConfigReply_t mpi_reply;
+ Mpi2RaidVolPage1_t raid_vol_pg1;
+
+ *wwid = 0;
+ if (!(mpr_config_get_raid_volume_pg1(sc, &mpi_reply, &raid_vol_pg1,
+ MPI2_RAID_VOLUME_PGAD_FORM_HANDLE, volume_handle))) {
+ *wwid = le64toh((u64)raid_vol_pg1.WWID.High << 32 |
+ raid_vol_pg1.WWID.Low);
+ return 0;
+ } else
+ return -1;
+}
+
+/**
+ * mpr_config_get_pd_pg0 - obtain raid phys disk page 0
+ * @sc: per adapter object
+ * @mpi_reply: reply mf payload returned from firmware
+ * @config_page: contents of the config page
+ * @page_address: form and handle value used to get page
+ * Context: sleep.
+ *
+ * Returns 0 for success, non-zero for failure.
+ */
+int
+mpr_config_get_raid_pd_pg0(struct mpr_softc *sc, Mpi2ConfigReply_t *mpi_reply,
+ Mpi2RaidPhysDiskPage0_t *config_page, u32 page_address)
+{
+ MPI2_CONFIG_REQUEST *request;
+ MPI2_CONFIG_REPLY *reply;
+ struct mpr_command *cm;
+ Mpi2RaidPhysDiskPage0_t *page = NULL;
+ int error = 0;
+ u16 ioc_status;
+
+ mpr_dprint(sc, MPR_TRACE, "%s\n", __func__);
+
+ if ((cm = mpr_alloc_command(sc)) == NULL) {
+ printf("%s: command alloc failed @ line %d\n", __func__,
+ __LINE__);
+ error = EBUSY;
+ goto out;
+ }
+ request = (MPI2_CONFIG_REQUEST *)cm->cm_req;
+ bzero(request, sizeof(MPI2_CONFIG_REQUEST));
+ request->Function = MPI2_FUNCTION_CONFIG;
+ request->Action = MPI2_CONFIG_ACTION_PAGE_HEADER;
+ request->Header.PageType = MPI2_CONFIG_PAGETYPE_RAID_PHYSDISK;
+ request->Header.PageNumber = 0;
+ request->Header.PageVersion = MPI2_RAIDPHYSDISKPAGE0_PAGEVERSION;
+ cm->cm_desc.Default.RequestFlags = MPI2_REQ_DESCRIPT_FLAGS_DEFAULT_TYPE;
+ cm->cm_data = NULL;
+
+ /*
+ * This page must be polled because the IOC isn't ready yet when this
+ * page is needed.
+ */
+ error = mpr_request_polled(sc, cm);
+ reply = (MPI2_CONFIG_REPLY *)cm->cm_reply;
+ if (error || (reply == NULL)) {
+ /* FIXME */
+ /* If the poll returns error then we need to do diag reset */
+ printf("%s: poll for header completed with error %d",
+ __func__, error);
+ error = ENXIO;
+ goto out;
+ }
+ ioc_status = le16toh(reply->IOCStatus) & MPI2_IOCSTATUS_MASK;
+ bcopy(reply, mpi_reply, sizeof(MPI2_CONFIG_REPLY));
+ if (ioc_status != MPI2_IOCSTATUS_SUCCESS) {
+ /* FIXME */
+ /* If the poll returns error then we need to do diag reset */
+ printf("%s: header read with error; iocstatus = 0x%x\n",
+ __func__, ioc_status);
+ error = ENXIO;
+ goto out;
+ }
+ /* We have to do free and alloc for the reply-free and reply-post
+ * counters to match - Need to review the reply FIFO handling.
+ */
+ mpr_free_command(sc, cm);
+
+ if ((cm = mpr_alloc_command(sc)) == NULL) {
+ printf("%s: command alloc failed @ line %d\n", __func__,
+ __LINE__);
+ error = EBUSY;
+ goto out;
+ }
+ request = (MPI2_CONFIG_REQUEST *)cm->cm_req;
+ bzero(request, sizeof(MPI2_CONFIG_REQUEST));
+ request->Function = MPI2_FUNCTION_CONFIG;
+ request->Action = MPI2_CONFIG_ACTION_PAGE_READ_CURRENT;
+ request->Header.PageType = MPI2_CONFIG_PAGETYPE_RAID_PHYSDISK;
+ request->Header.PageNumber = 0;
+ request->Header.PageLength = mpi_reply->Header.PageLength;
+ request->Header.PageVersion = mpi_reply->Header.PageVersion;
+ request->PageAddress = page_address;
+ cm->cm_length = le16toh(mpi_reply->Header.PageLength) * 4;
+ cm->cm_sge = &request->PageBufferSGE;
+ cm->cm_sglsize = sizeof(MPI2_SGE_IO_UNION);
+ cm->cm_flags = MPR_CM_FLAGS_SGE_SIMPLE | MPR_CM_FLAGS_DATAIN;
+ cm->cm_desc.Default.RequestFlags = MPI2_REQ_DESCRIPT_FLAGS_DEFAULT_TYPE;
+ page = malloc(cm->cm_length, M_MPR, M_ZERO | M_NOWAIT);
+ if (!page) {
+ printf("%s: page alloc failed\n", __func__);
+ error = ENOMEM;
+ goto out;
+ }
+ cm->cm_data = page;
+
+ /*
+ * This page must be polled because the IOC isn't ready yet when this
+ * page is needed.
+ */
+ error = mpr_request_polled(sc, cm);
+ reply = (MPI2_CONFIG_REPLY *)cm->cm_reply;
+ if (error || (reply == NULL)) {
+ /* FIXME */
+ /* If the poll returns error then we need to do diag reset */
+ printf("%s: poll for page completed with error %d",
+ __func__, error);
+ error = ENXIO;
+ goto out;
+ }
+ ioc_status = le16toh(reply->IOCStatus) & MPI2_IOCSTATUS_MASK;
+ bcopy(reply, mpi_reply, sizeof(MPI2_CONFIG_REPLY));
+ if (ioc_status != MPI2_IOCSTATUS_SUCCESS) {
+ /* FIXME */
+ /* If the poll returns error then we need to do diag reset */
+ printf("%s: page read with error; iocstatus = 0x%x\n",
+ __func__, ioc_status);
+ error = ENXIO;
+ goto out;
+ }
+ bcopy(page, config_page, MIN(cm->cm_length,
+ sizeof(Mpi2RaidPhysDiskPage0_t)));
+out:
+ free(page, M_MPR);
+ if (cm)
+ mpr_free_command(sc, cm);
+ return (error);
+}
diff --git a/sys/dev/mpr/mpr_ioctl.h b/sys/dev/mpr/mpr_ioctl.h
new file mode 100644
index 0000000..5ec482f
--- /dev/null
+++ b/sys/dev/mpr/mpr_ioctl.h
@@ -0,0 +1,386 @@
+/*-
+ * Copyright (c) 2008 Yahoo!, Inc.
+ * All rights reserved.
+ * Written by: John Baldwin <jhb@FreeBSD.org>
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the author nor the names of any co-contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * LSI MPT-Fusion Host Adapter FreeBSD userland interface
+ *
+ * $FreeBSD$
+ */
+/*-
+ * Copyright (c) 2011-2014 LSI Corp.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * LSI MPT-Fusion Host Adapter FreeBSD
+ *
+ * $FreeBSD$
+ */
+
+#ifndef _MPR_IOCTL_H_
+#define _MPR_IOCTL_H_
+
+#include <dev/mpr/mpi/mpi2_type.h>
+#include <dev/mpr/mpi/mpi2.h>
+#include <dev/mpr/mpi/mpi2_cnfg.h>
+#include <dev/mpr/mpi/mpi2_sas.h>
+
+/*
+ * For the read header requests, the header should include the page
+ * type or extended page type, page number, and page version. The
+ * buffer and length are unused. The completed header is returned in
+ * the 'header' member.
+ *
+ * For the read page and write page requests, 'buf' should point to a
+ * buffer of 'len' bytes which holds the entire page (including the
+ * header).
+ *
+ * All requests specify the page address in 'page_address'.
+ */
+struct mpr_cfg_page_req {
+ MPI2_CONFIG_PAGE_HEADER header;
+ uint32_t page_address;
+ void *buf;
+ int len;
+ uint16_t ioc_status;
+};
+
+struct mpr_ext_cfg_page_req {
+ MPI2_CONFIG_EXTENDED_PAGE_HEADER header;
+ uint32_t page_address;
+ void *buf;
+ int len;
+ uint16_t ioc_status;
+};
+
+struct mpr_raid_action {
+ uint8_t action;
+ uint8_t volume_bus;
+ uint8_t volume_id;
+ uint8_t phys_disk_num;
+ uint32_t action_data_word;
+ void *buf;
+ int len;
+ uint32_t volume_status;
+ uint32_t action_data[4];
+ uint16_t action_status;
+ uint16_t ioc_status;
+ uint8_t write;
+};
+
+struct mpr_usr_command {
+ void *req;
+ uint32_t req_len;
+ void *rpl;
+ uint32_t rpl_len;
+ void *buf;
+ int len;
+ uint32_t flags;
+};
+
+typedef struct mpr_pci_bits
+{
+ union {
+ struct {
+ uint32_t DeviceNumber :5;
+ uint32_t FunctionNumber :3;
+ uint32_t BusNumber :24;
+ } bits;
+ uint32_t AsDWORD;
+ } u;
+ uint32_t PciSegmentId;
+} mpr_pci_bits_t;
+
+/*
+ * The following is the MPRIOCTL_GET_ADAPTER_DATA data structure. This data
+ * structure is setup so that we hopefully are properly aligned for both
+ * 32-bit and 64-bit mode applications.
+ *
+ * Adapter Type - Value = 6 = SCSI Protocol through SAS-3 adapter
+ *
+ * MPI Port Number - The PCI Function number for this device
+ *
+ * PCI Device HW Id - The PCI device number for this device
+ *
+ */
+#define MPRIOCTL_ADAPTER_TYPE_SAS3 6
+typedef struct mpr_adapter_data
+{
+ uint32_t StructureLength;
+ uint32_t AdapterType;
+ uint32_t MpiPortNumber;
+ uint32_t PCIDeviceHwId;
+ uint32_t PCIDeviceHwRev;
+ uint32_t SubSystemId;
+ uint32_t SubsystemVendorId;
+ uint32_t Reserved1;
+ uint32_t MpiFirmwareVersion;
+ uint32_t BiosVersion;
+ uint8_t DriverVersion[32];
+ uint8_t Reserved2;
+ uint8_t ScsiId;
+ uint16_t Reserved3;
+ mpr_pci_bits_t PciInformation;
+} mpr_adapter_data_t;
+
+
+typedef struct mpr_update_flash
+{
+ uint64_t PtrBuffer;
+ uint32_t ImageChecksum;
+ uint32_t ImageOffset;
+ uint32_t ImageSize;
+ uint32_t ImageType;
+} mpr_update_flash_t;
+
+
+#define MPR_PASS_THRU_DIRECTION_NONE 0
+#define MPR_PASS_THRU_DIRECTION_READ 1
+#define MPR_PASS_THRU_DIRECTION_WRITE 2
+#define MPR_PASS_THRU_DIRECTION_BOTH 3
+
+typedef struct mpr_pass_thru
+{
+ uint64_t PtrRequest;
+ uint64_t PtrReply;
+ uint64_t PtrData;
+ uint32_t RequestSize;
+ uint32_t ReplySize;
+ uint32_t DataSize;
+ uint32_t DataDirection;
+ uint64_t PtrDataOut;
+ uint32_t DataOutSize;
+ uint32_t Timeout;
+} mpr_pass_thru_t;
+
+
+/*
+ * Event queue defines
+ */
+#define MPR_EVENT_QUEUE_SIZE (50) /* Max Events stored in driver */
+#define MPR_MAX_EVENT_DATA_LENGTH (48) /* Size of each event in Dwords */
+
+typedef struct mpr_event_query
+{
+ uint16_t Entries;
+ uint16_t Reserved;
+ uint32_t Types[4];
+} mpr_event_query_t;
+
+typedef struct mpr_event_enable
+{
+ uint32_t Types[4];
+} mpr_event_enable_t;
+
+/*
+ * Event record entry for ioctl.
+ */
+typedef struct mpr_event_entry
+{
+ uint32_t Type;
+ uint32_t Number;
+ uint32_t Data[MPR_MAX_EVENT_DATA_LENGTH];
+} mpr_event_entry_t;
+
+typedef struct mpr_event_report
+{
+ uint32_t Size;
+ uint64_t PtrEvents;
+} mpr_event_report_t;
+
+
+typedef struct mpr_pci_info
+{
+ uint32_t BusNumber;
+ uint8_t DeviceNumber;
+ uint8_t FunctionNumber;
+ uint16_t InterruptVector;
+ uint8_t PciHeader[256];
+} mpr_pci_info_t;
+
+
+typedef struct mpr_diag_action
+{
+ uint32_t Action;
+ uint32_t Length;
+ uint64_t PtrDiagAction;
+ uint32_t ReturnCode;
+} mpr_diag_action_t;
+
+#define MPR_FW_DIAGNOSTIC_UID_NOT_FOUND (0xFF)
+
+#define MPR_FW_DIAG_NEW (0x806E6577)
+
+#define MPR_FW_DIAG_TYPE_REGISTER (0x00000001)
+#define MPR_FW_DIAG_TYPE_UNREGISTER (0x00000002)
+#define MPR_FW_DIAG_TYPE_QUERY (0x00000003)
+#define MPR_FW_DIAG_TYPE_READ_BUFFER (0x00000004)
+#define MPR_FW_DIAG_TYPE_RELEASE (0x00000005)
+
+#define MPR_FW_DIAG_INVALID_UID (0x00000000)
+
+#define MPR_DIAG_SUCCESS 0
+#define MPR_DIAG_FAILURE 1
+
+#define MPR_FW_DIAG_ERROR_SUCCESS (0x00000000)
+#define MPR_FW_DIAG_ERROR_FAILURE (0x00000001)
+#define MPR_FW_DIAG_ERROR_INVALID_PARAMETER (0x00000002)
+#define MPR_FW_DIAG_ERROR_POST_FAILED (0x00000010)
+#define MPR_FW_DIAG_ERROR_INVALID_UID (0x00000011)
+#define MPR_FW_DIAG_ERROR_RELEASE_FAILED (0x00000012)
+#define MPR_FW_DIAG_ERROR_NO_BUFFER (0x00000013)
+#define MPR_FW_DIAG_ERROR_ALREADY_RELEASED (0x00000014)
+
+
+typedef struct mpr_fw_diag_register
+{
+ uint8_t ExtendedType;
+ uint8_t BufferType;
+ uint16_t ApplicationFlags;
+ uint32_t DiagnosticFlags;
+ uint32_t ProductSpecific[23];
+ uint32_t RequestedBufferSize;
+ uint32_t UniqueId;
+} mpr_fw_diag_register_t;
+
+typedef struct mpr_fw_diag_unregister
+{
+ uint32_t UniqueId;
+} mpr_fw_diag_unregister_t;
+
+#define MPR_FW_DIAG_FLAG_APP_OWNED (0x0001)
+#define MPR_FW_DIAG_FLAG_BUFFER_VALID (0x0002)
+#define MPR_FW_DIAG_FLAG_FW_BUFFER_ACCESS (0x0004)
+
+typedef struct mpr_fw_diag_query
+{
+ uint8_t ExtendedType;
+ uint8_t BufferType;
+ uint16_t ApplicationFlags;
+ uint32_t DiagnosticFlags;
+ uint32_t ProductSpecific[23];
+ uint32_t TotalBufferSize;
+ uint32_t DriverAddedBufferSize;
+ uint32_t UniqueId;
+} mpr_fw_diag_query_t;
+
+typedef struct mpr_fw_diag_release
+{
+ uint32_t UniqueId;
+} mpr_fw_diag_release_t;
+
+#define MPR_FW_DIAG_FLAG_REREGISTER (0x0001)
+#define MPR_FW_DIAG_FLAG_FORCE_RELEASE (0x0002)
+
+typedef struct mpr_diag_read_buffer
+{
+ uint8_t Status;
+ uint8_t Reserved;
+ uint16_t Flags;
+ uint32_t StartingOffset;
+ uint32_t BytesToRead;
+ uint32_t UniqueId;
+ uint64_t PtrDataBuffer;
+} mpr_diag_read_buffer_t;
+
+/*
+ * Register Access
+ */
+#define REG_IO_READ 1
+#define REG_IO_WRITE 2
+#define REG_MEM_READ 3
+#define REG_MEM_WRITE 4
+
+typedef struct mpr_reg_access
+{
+ uint32_t Command;
+ uint32_t RegOffset;
+ uint32_t RegData;
+} mpr_reg_access_t;
+
+typedef struct mpr_btdh_mapping
+{
+ uint16_t TargetID;
+ uint16_t Bus;
+ uint16_t DevHandle;
+ uint16_t Reserved;
+} mpr_btdh_mapping_t;
+
+#define MPRIO_MPR_COMMAND_FLAG_VERBOSE 0x01
+#define MPRIO_MPR_COMMAND_FLAG_DEBUG 0x02
+#define MPRIO_READ_CFG_HEADER _IOWR('M', 200, struct mpr_cfg_page_req)
+#define MPRIO_READ_CFG_PAGE _IOWR('M', 201, struct mpr_cfg_page_req)
+#define MPRIO_READ_EXT_CFG_HEADER _IOWR('M', 202, struct mpr_ext_cfg_page_req)
+#define MPRIO_READ_EXT_CFG_PAGE _IOWR('M', 203, struct mpr_ext_cfg_page_req)
+#define MPRIO_WRITE_CFG_PAGE _IOWR('M', 204, struct mpr_cfg_page_req)
+#define MPRIO_RAID_ACTION _IOWR('M', 205, struct mpr_raid_action)
+#define MPRIO_MPR_COMMAND _IOWR('M', 210, struct mpr_usr_command)
+
+#define MPTIOCTL ('I')
+#define MPTIOCTL_GET_ADAPTER_DATA _IOWR(MPTIOCTL, 1,\
+ struct mpr_adapter_data)
+#define MPTIOCTL_UPDATE_FLASH _IOWR(MPTIOCTL, 2,\
+ struct mpr_update_flash)
+#define MPTIOCTL_RESET_ADAPTER _IO(MPTIOCTL, 3)
+#define MPTIOCTL_PASS_THRU _IOWR(MPTIOCTL, 4,\
+ struct mpr_pass_thru)
+#define MPTIOCTL_EVENT_QUERY _IOWR(MPTIOCTL, 5,\
+ struct mpr_event_query)
+#define MPTIOCTL_EVENT_ENABLE _IOWR(MPTIOCTL, 6,\
+ struct mpr_event_enable)
+#define MPTIOCTL_EVENT_REPORT _IOWR(MPTIOCTL, 7,\
+ struct mpr_event_report)
+#define MPTIOCTL_GET_PCI_INFO _IOWR(MPTIOCTL, 8,\
+ struct mpr_pci_info)
+#define MPTIOCTL_DIAG_ACTION _IOWR(MPTIOCTL, 9,\
+ struct mpr_diag_action)
+#define MPTIOCTL_REG_ACCESS _IOWR(MPTIOCTL, 10,\
+ struct mpr_reg_access)
+#define MPTIOCTL_BTDH_MAPPING _IOWR(MPTIOCTL, 11,\
+ struct mpr_btdh_mapping)
+
+#endif /* !_MPR_IOCTL_H_ */
diff --git a/sys/dev/mpr/mpr_mapping.c b/sys/dev/mpr/mpr_mapping.c
new file mode 100644
index 0000000..7f0fc00
--- /dev/null
+++ b/sys/dev/mpr/mpr_mapping.c
@@ -0,0 +1,2269 @@
+/*-
+ * Copyright (c) 2011-2014 LSI Corp.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * LSI MPT-Fusion Host Adapter FreeBSD
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+/* TODO Move headers to mprvar */
+#include <sys/types.h>
+#include <sys/param.h>
+#include <sys/lock.h>
+#include <sys/mutex.h>
+#include <sys/systm.h>
+#include <sys/kernel.h>
+#include <sys/malloc.h>
+#include <sys/kthread.h>
+#include <sys/taskqueue.h>
+#include <sys/bus.h>
+#include <sys/endian.h>
+#include <sys/sysctl.h>
+#include <sys/eventhandler.h>
+#include <sys/uio.h>
+#include <machine/bus.h>
+#include <machine/resource.h>
+#include <dev/mpr/mpi/mpi2_type.h>
+#include <dev/mpr/mpi/mpi2.h>
+#include <dev/mpr/mpi/mpi2_ioc.h>
+#include <dev/mpr/mpi/mpi2_sas.h>
+#include <dev/mpr/mpi/mpi2_cnfg.h>
+#include <dev/mpr/mpi/mpi2_init.h>
+#include <dev/mpr/mpi/mpi2_tool.h>
+#include <dev/mpr/mpr_ioctl.h>
+#include <dev/mpr/mprvar.h>
+#include <dev/mpr/mpr_mapping.h>
+
+/**
+ * _mapping_clear_entry - Clear a particular mapping entry.
+ * @map_entry: map table entry
+ *
+ * Returns nothing.
+ */
+static inline void
+_mapping_clear_map_entry(struct dev_mapping_table *map_entry)
+{
+ map_entry->physical_id = 0;
+ map_entry->device_info = 0;
+ map_entry->phy_bits = 0;
+ map_entry->dpm_entry_num = MPR_DPM_BAD_IDX;
+ map_entry->dev_handle = 0;
+ map_entry->channel = -1;
+ map_entry->id = -1;
+ map_entry->missing_count = 0;
+ map_entry->init_complete = 0;
+ map_entry->TLR_bits = (u8)MPI2_SCSIIO_CONTROL_NO_TLR;
+}
+
+/**
+ * _mapping_clear_enc_entry - Clear a particular enclosure table entry.
+ * @enc_entry: enclosure table entry
+ *
+ * Returns nothing.
+ */
+static inline void
+_mapping_clear_enc_entry(struct enc_mapping_table *enc_entry)
+{
+ enc_entry->enclosure_id = 0;
+ enc_entry->start_index = MPR_MAPTABLE_BAD_IDX;
+ enc_entry->phy_bits = 0;
+ enc_entry->dpm_entry_num = MPR_DPM_BAD_IDX;
+ enc_entry->enc_handle = 0;
+ enc_entry->num_slots = 0;
+ enc_entry->start_slot = 0;
+ enc_entry->missing_count = 0;
+ enc_entry->removal_flag = 0;
+ enc_entry->skip_search = 0;
+ enc_entry->init_complete = 0;
+}
+
+/**
+ * _mapping_commit_enc_entry - write a particular enc entry in DPM page0.
+ * @sc: per adapter object
+ * @enc_entry: enclosure table entry
+ *
+ * Returns 0 for success, non-zero for failure.
+ */
+static int
+_mapping_commit_enc_entry(struct mpr_softc *sc,
+ struct enc_mapping_table *et_entry)
+{
+ Mpi2DriverMap0Entry_t *dpm_entry;
+ struct dev_mapping_table *mt_entry;
+ Mpi2ConfigReply_t mpi_reply;
+ Mpi2DriverMappingPage0_t config_page;
+
+ if (!sc->is_dpm_enable)
+ return 0;
+
+ memset(&config_page, 0, sizeof(Mpi2DriverMappingPage0_t));
+ memcpy(&config_page.Header, (u8 *) sc->dpm_pg0,
+ sizeof(MPI2_CONFIG_EXTENDED_PAGE_HEADER));
+ dpm_entry = (Mpi2DriverMap0Entry_t *)((u8 *)sc->dpm_pg0 +
+ sizeof(MPI2_CONFIG_EXTENDED_PAGE_HEADER));
+ dpm_entry += et_entry->dpm_entry_num;
+ dpm_entry->PhysicalIdentifier.Low =
+ ( 0xFFFFFFFF & et_entry->enclosure_id);
+ dpm_entry->PhysicalIdentifier.High =
+ ( et_entry->enclosure_id >> 32);
+ mt_entry = &sc->mapping_table[et_entry->start_index];
+ dpm_entry->DeviceIndex = htole16(mt_entry->id);
+ dpm_entry->MappingInformation = et_entry->num_slots;
+ dpm_entry->MappingInformation <<= MPI2_DRVMAP0_MAPINFO_SLOT_SHIFT;
+ dpm_entry->MappingInformation |= et_entry->missing_count;
+ dpm_entry->MappingInformation = htole16(dpm_entry->MappingInformation);
+ dpm_entry->PhysicalBitsMapping = htole32(et_entry->phy_bits);
+ dpm_entry->Reserved1 = 0;
+
+ memcpy(&config_page.Entry, (u8 *)dpm_entry,
+ sizeof(Mpi2DriverMap0Entry_t));
+ if (mpr_config_set_dpm_pg0(sc, &mpi_reply, &config_page,
+ et_entry->dpm_entry_num)) {
+ printf("%s: write of dpm entry %d for enclosure failed\n",
+ __func__, et_entry->dpm_entry_num);
+ dpm_entry->MappingInformation = le16toh(dpm_entry->
+ MappingInformation);
+ dpm_entry->DeviceIndex = le16toh(dpm_entry->DeviceIndex);
+ dpm_entry->PhysicalBitsMapping =
+ le32toh(dpm_entry->PhysicalBitsMapping);
+ return -1;
+ }
+ dpm_entry->MappingInformation = le16toh(dpm_entry->
+ MappingInformation);
+ dpm_entry->DeviceIndex = le16toh(dpm_entry->DeviceIndex);
+ dpm_entry->PhysicalBitsMapping =
+ le32toh(dpm_entry->PhysicalBitsMapping);
+ return 0;
+}
+
+/**
+ * _mapping_commit_map_entry - write a particular map table entry in DPM page0.
+ * @sc: per adapter object
+ * @enc_entry: enclosure table entry
+ *
+ * Returns 0 for success, non-zero for failure.
+ */
+
+static int
+_mapping_commit_map_entry(struct mpr_softc *sc,
+ struct dev_mapping_table *mt_entry)
+{
+ Mpi2DriverMap0Entry_t *dpm_entry;
+ Mpi2ConfigReply_t mpi_reply;
+ Mpi2DriverMappingPage0_t config_page;
+
+ if (!sc->is_dpm_enable)
+ return 0;
+
+ memset(&config_page, 0, sizeof(Mpi2DriverMappingPage0_t));
+ memcpy(&config_page.Header, (u8 *)sc->dpm_pg0,
+ sizeof(MPI2_CONFIG_EXTENDED_PAGE_HEADER));
+ dpm_entry = (Mpi2DriverMap0Entry_t *)((u8 *) sc->dpm_pg0 +
+ sizeof(MPI2_CONFIG_EXTENDED_PAGE_HEADER));
+ dpm_entry = dpm_entry + mt_entry->dpm_entry_num;
+ dpm_entry->PhysicalIdentifier.Low = (0xFFFFFFFF &
+ mt_entry->physical_id);
+ dpm_entry->PhysicalIdentifier.High = (mt_entry->physical_id >> 32);
+ dpm_entry->DeviceIndex = htole16(mt_entry->id);
+ dpm_entry->MappingInformation = htole16(mt_entry->missing_count);
+ dpm_entry->PhysicalBitsMapping = 0;
+ dpm_entry->Reserved1 = 0;
+ dpm_entry->MappingInformation = htole16(dpm_entry->MappingInformation);
+ memcpy(&config_page.Entry, (u8 *)dpm_entry,
+ sizeof(Mpi2DriverMap0Entry_t));
+ if (mpr_config_set_dpm_pg0(sc, &mpi_reply, &config_page,
+ mt_entry->dpm_entry_num)) {
+ printf("%s: write of dpm entry %d for device failed\n",
+ __func__, mt_entry->dpm_entry_num);
+ dpm_entry->MappingInformation = le16toh(dpm_entry->
+ MappingInformation);
+ dpm_entry->DeviceIndex = le16toh(dpm_entry->DeviceIndex);
+ return -1;
+ }
+
+ dpm_entry->MappingInformation = le16toh(dpm_entry->MappingInformation);
+ dpm_entry->DeviceIndex = le16toh(dpm_entry->DeviceIndex);
+ return 0;
+}
+
+/**
+ * _mapping_get_ir_maprange - get start and end index for IR map range.
+ * @sc: per adapter object
+ * @start_idx: place holder for start index
+ * @end_idx: place holder for end index
+ *
+ * The IR volumes can be mapped either at start or end of the mapping table
+ * this function gets the detail of where IR volume mapping starts and ends
+ * in the device mapping table
+ *
+ * Returns nothing.
+ */
+static void
+_mapping_get_ir_maprange(struct mpr_softc *sc, u32 *start_idx, u32 *end_idx)
+{
+ u16 volume_mapping_flags;
+ u16 ioc_pg8_flags = le16toh(sc->ioc_pg8.Flags);
+
+ volume_mapping_flags = le16toh(sc->ioc_pg8.IRVolumeMappingFlags) &
+ MPI2_IOCPAGE8_IRFLAGS_MASK_VOLUME_MAPPING_MODE;
+ if (volume_mapping_flags == MPI2_IOCPAGE8_IRFLAGS_LOW_VOLUME_MAPPING) {
+ *start_idx = 0;
+ if (ioc_pg8_flags & MPI2_IOCPAGE8_FLAGS_RESERVED_TARGETID_0)
+ *start_idx = 1;
+ } else
+ *start_idx = sc->max_devices - sc->max_volumes;
+ *end_idx = *start_idx + sc->max_volumes - 1;
+}
+
+/**
+ * _mapping_get_enc_idx_from_id - get enclosure index from enclosure ID
+ * @sc: per adapter object
+ * @enc_id: enclosure logical identifier
+ *
+ * Returns the index of enclosure entry on success or bad index.
+ */
+static u8
+_mapping_get_enc_idx_from_id(struct mpr_softc *sc, u64 enc_id,
+ u64 phy_bits)
+{
+ struct enc_mapping_table *et_entry;
+ u8 enc_idx = 0;
+
+ for (enc_idx = 0; enc_idx < sc->num_enc_table_entries; enc_idx++) {
+ et_entry = &sc->enclosure_table[enc_idx];
+ if ((et_entry->enclosure_id == le64toh(enc_id)) &&
+ (!et_entry->phy_bits || (et_entry->phy_bits &
+ le32toh(phy_bits))))
+ return enc_idx;
+ }
+ return MPR_ENCTABLE_BAD_IDX;
+}
+
+/**
+ * _mapping_get_enc_idx_from_handle - get enclosure index from handle
+ * @sc: per adapter object
+ * @enc_id: enclosure handle
+ *
+ * Returns the index of enclosure entry on success or bad index.
+ */
+static u8
+_mapping_get_enc_idx_from_handle(struct mpr_softc *sc, u16 handle)
+{
+ struct enc_mapping_table *et_entry;
+ u8 enc_idx = 0;
+
+ for (enc_idx = 0; enc_idx < sc->num_enc_table_entries; enc_idx++) {
+ et_entry = &sc->enclosure_table[enc_idx];
+ if (et_entry->missing_count)
+ continue;
+ if (et_entry->enc_handle == handle)
+ return enc_idx;
+ }
+ return MPR_ENCTABLE_BAD_IDX;
+}
+
+/**
+ * _mapping_get_high_missing_et_idx - get missing enclosure index
+ * @sc: per adapter object
+ *
+ * Search through the enclosure table and identifies the enclosure entry
+ * with high missing count and returns it's index
+ *
+ * Returns the index of enclosure entry on success or bad index.
+ */
+static u8
+_mapping_get_high_missing_et_idx(struct mpr_softc *sc)
+{
+ struct enc_mapping_table *et_entry;
+ u8 high_missing_count = 0;
+ u8 enc_idx, high_idx = MPR_ENCTABLE_BAD_IDX;
+
+ for (enc_idx = 0; enc_idx < sc->num_enc_table_entries; enc_idx++) {
+ et_entry = &sc->enclosure_table[enc_idx];
+ if ((et_entry->missing_count > high_missing_count) &&
+ !et_entry->skip_search) {
+ high_missing_count = et_entry->missing_count;
+ high_idx = enc_idx;
+ }
+ }
+ return high_idx;
+}
+
+/**
+ * _mapping_get_high_missing_mt_idx - get missing map table index
+ * @sc: per adapter object
+ *
+ * Search through the map table and identifies the device entry
+ * with high missing count and returns it's index
+ *
+ * Returns the index of map table entry on success or bad index.
+ */
+static u32
+_mapping_get_high_missing_mt_idx(struct mpr_softc *sc)
+{
+ u32 map_idx, high_idx = MPR_ENCTABLE_BAD_IDX;
+ u8 high_missing_count = 0;
+ u32 start_idx, end_idx, start_idx_ir = 0, end_idx_ir;
+ struct dev_mapping_table *mt_entry;
+ u16 ioc_pg8_flags = le16toh(sc->ioc_pg8.Flags);
+
+ start_idx = 0;
+ end_idx = sc->max_devices;
+ if (ioc_pg8_flags & MPI2_IOCPAGE8_FLAGS_RESERVED_TARGETID_0)
+ start_idx = 1;
+ if (sc->ir_firmware) {
+ _mapping_get_ir_maprange(sc, &start_idx_ir, &end_idx_ir);
+ if (start_idx == start_idx_ir)
+ start_idx = end_idx_ir + 1;
+ else
+ end_idx = start_idx_ir;
+ }
+ mt_entry = &sc->mapping_table[start_idx];
+ for (map_idx = start_idx; map_idx < end_idx; map_idx++, mt_entry++) {
+ if (mt_entry->missing_count > high_missing_count) {
+ high_missing_count = mt_entry->missing_count;
+ high_idx = map_idx;
+ }
+ }
+ return high_idx;
+}
+
+/**
+ * _mapping_get_ir_mt_idx_from_wwid - get map table index from volume WWID
+ * @sc: per adapter object
+ * @wwid: world wide unique ID of the volume
+ *
+ * Returns the index of map table entry on success or bad index.
+ */
+static u32
+_mapping_get_ir_mt_idx_from_wwid(struct mpr_softc *sc, u64 wwid)
+{
+ u32 start_idx, end_idx, map_idx;
+ struct dev_mapping_table *mt_entry;
+
+ _mapping_get_ir_maprange(sc, &start_idx, &end_idx);
+ mt_entry = &sc->mapping_table[start_idx];
+ for (map_idx = start_idx; map_idx <= end_idx; map_idx++, mt_entry++)
+ if (mt_entry->physical_id == wwid)
+ return map_idx;
+
+ return MPR_MAPTABLE_BAD_IDX;
+}
+
+/**
+ * _mapping_get_mt_idx_from_id - get map table index from a device ID
+ * @sc: per adapter object
+ * @dev_id: device identifer (SAS Address)
+ *
+ * Returns the index of map table entry on success or bad index.
+ */
+static u32
+_mapping_get_mt_idx_from_id(struct mpr_softc *sc, u64 dev_id)
+{
+ u32 map_idx;
+ struct dev_mapping_table *mt_entry;
+
+ for (map_idx = 0; map_idx < sc->max_devices; map_idx++) {
+ mt_entry = &sc->mapping_table[map_idx];
+ if (mt_entry->physical_id == dev_id)
+ return map_idx;
+ }
+ return MPR_MAPTABLE_BAD_IDX;
+}
+
+/**
+ * _mapping_get_ir_mt_idx_from_handle - get map table index from volume handle
+ * @sc: per adapter object
+ * @wwid: volume device handle
+ *
+ * Returns the index of map table entry on success or bad index.
+ */
+static u32
+_mapping_get_ir_mt_idx_from_handle(struct mpr_softc *sc, u16 volHandle)
+{
+ u32 start_idx, end_idx, map_idx;
+ struct dev_mapping_table *mt_entry;
+
+ _mapping_get_ir_maprange(sc, &start_idx, &end_idx);
+ mt_entry = &sc->mapping_table[start_idx];
+ for (map_idx = start_idx; map_idx <= end_idx; map_idx++, mt_entry++)
+ if (mt_entry->dev_handle == volHandle)
+ return map_idx;
+
+ return MPR_MAPTABLE_BAD_IDX;
+}
+
+/**
+ * _mapping_get_mt_idx_from_handle - get map table index from handle
+ * @sc: per adapter object
+ * @dev_id: device handle
+ *
+ * Returns the index of map table entry on success or bad index.
+ */
+static u32
+_mapping_get_mt_idx_from_handle(struct mpr_softc *sc, u16 handle)
+{
+ u32 map_idx;
+ struct dev_mapping_table *mt_entry;
+
+ for (map_idx = 0; map_idx < sc->max_devices; map_idx++) {
+ mt_entry = &sc->mapping_table[map_idx];
+ if (mt_entry->dev_handle == handle)
+ return map_idx;
+ }
+ return MPR_MAPTABLE_BAD_IDX;
+}
+
+/**
+ * _mapping_get_free_ir_mt_idx - get first free index for a volume
+ * @sc: per adapter object
+ *
+ * Search through mapping table for free index for a volume and if no free
+ * index then looks for a volume with high mapping index
+ *
+ * Returns the index of map table entry on success or bad index.
+ */
+static u32
+_mapping_get_free_ir_mt_idx(struct mpr_softc *sc)
+{
+ u8 high_missing_count = 0;
+ u32 start_idx, end_idx, map_idx;
+ u32 high_idx = MPR_MAPTABLE_BAD_IDX;
+ struct dev_mapping_table *mt_entry;
+
+ _mapping_get_ir_maprange(sc, &start_idx, &end_idx);
+
+ mt_entry = &sc->mapping_table[start_idx];
+ for (map_idx = start_idx; map_idx <= end_idx; map_idx++, mt_entry++)
+ if (!(mt_entry->device_info & MPR_MAP_IN_USE))
+ return map_idx;
+
+ mt_entry = &sc->mapping_table[start_idx];
+ for (map_idx = start_idx; map_idx <= end_idx; map_idx++, mt_entry++) {
+ if (mt_entry->missing_count > high_missing_count) {
+ high_missing_count = mt_entry->missing_count;
+ high_idx = map_idx;
+ }
+ }
+ return high_idx;
+}
+
+/**
+ * _mapping_get_free_mt_idx - get first free index for a device
+ * @sc: per adapter object
+ * @start_idx: offset in the table to start search
+ *
+ * Returns the index of map table entry on success or bad index.
+ */
+static u32
+_mapping_get_free_mt_idx(struct mpr_softc *sc, u32 start_idx)
+{
+ u32 map_idx, max_idx = sc->max_devices;
+ struct dev_mapping_table *mt_entry = &sc->mapping_table[start_idx];
+ u16 volume_mapping_flags;
+
+ volume_mapping_flags = le16toh(sc->ioc_pg8.IRVolumeMappingFlags) &
+ MPI2_IOCPAGE8_IRFLAGS_MASK_VOLUME_MAPPING_MODE;
+ if (sc->ir_firmware && (volume_mapping_flags ==
+ MPI2_IOCPAGE8_IRFLAGS_HIGH_VOLUME_MAPPING))
+ max_idx -= sc->max_volumes;
+ for (map_idx = start_idx; map_idx < max_idx; map_idx++, mt_entry++)
+ if (!(mt_entry->device_info & (MPR_MAP_IN_USE |
+ MPR_DEV_RESERVED)))
+ return map_idx;
+
+ return MPR_MAPTABLE_BAD_IDX;
+}
+
+/**
+ * _mapping_get_dpm_idx_from_id - get DPM index from ID
+ * @sc: per adapter object
+ * @id: volume WWID or enclosure ID or device ID
+ *
+ * Returns the index of DPM entry on success or bad index.
+ */
+static u16
+_mapping_get_dpm_idx_from_id(struct mpr_softc *sc, u64 id, u32 phy_bits)
+{
+ u16 entry_num;
+ uint64_t PhysicalIdentifier;
+ Mpi2DriverMap0Entry_t *dpm_entry;
+
+ dpm_entry = (Mpi2DriverMap0Entry_t *)((u8 *)sc->dpm_pg0 +
+ sizeof(MPI2_CONFIG_EXTENDED_PAGE_HEADER));
+ PhysicalIdentifier = dpm_entry->PhysicalIdentifier.High;
+ PhysicalIdentifier = (PhysicalIdentifier << 32) |
+ dpm_entry->PhysicalIdentifier.Low;
+ for (entry_num = 0; entry_num < sc->max_dpm_entries; entry_num++,
+ dpm_entry++)
+ if ((id == PhysicalIdentifier) &&
+ (!phy_bits || !dpm_entry->PhysicalBitsMapping ||
+ (phy_bits & dpm_entry->PhysicalBitsMapping)))
+ return entry_num;
+
+ return MPR_DPM_BAD_IDX;
+}
+
+
+/**
+ * _mapping_get_free_dpm_idx - get first available DPM index
+ * @sc: per adapter object
+ *
+ * Returns the index of DPM entry on success or bad index.
+ */
+static u32
+_mapping_get_free_dpm_idx(struct mpr_softc *sc)
+{
+ u16 entry_num;
+
+ for (entry_num = 0; entry_num < sc->max_dpm_entries; entry_num++) {
+ if (!sc->dpm_entry_used[entry_num])
+ return entry_num;
+ }
+ return MPR_DPM_BAD_IDX;
+}
+
+/**
+ * _mapping_update_ir_missing_cnt - Updates missing count for a volume
+ * @sc: per adapter object
+ * @map_idx: map table index of the volume
+ * @element: IR configuration change element
+ * @wwid: IR volume ID.
+ *
+ * Updates the missing count in the map table and in the DPM entry for a volume
+ *
+ * Returns nothing.
+ */
+static void
+_mapping_update_ir_missing_cnt(struct mpr_softc *sc, u32 map_idx,
+ Mpi2EventIrConfigElement_t *element, u64 wwid)
+{
+ struct dev_mapping_table *mt_entry;
+ u8 missing_cnt, reason = element->ReasonCode;
+ u16 dpm_idx;
+ Mpi2DriverMap0Entry_t *dpm_entry;
+
+ if (!sc->is_dpm_enable)
+ return;
+ mt_entry = &sc->mapping_table[map_idx];
+ if (reason == MPI2_EVENT_IR_CHANGE_RC_ADDED) {
+ mt_entry->missing_count = 0;
+ } else if (reason == MPI2_EVENT_IR_CHANGE_RC_VOLUME_CREATED) {
+ mt_entry->missing_count = 0;
+ mt_entry->init_complete = 0;
+ } else if ((reason == MPI2_EVENT_IR_CHANGE_RC_REMOVED) ||
+ (reason == MPI2_EVENT_IR_CHANGE_RC_VOLUME_DELETED)) {
+ if (!mt_entry->init_complete) {
+ if (mt_entry->missing_count < MPR_MAX_MISSING_COUNT)
+ mt_entry->missing_count++;
+ else
+ mt_entry->init_complete = 1;
+ }
+ if (!mt_entry->missing_count)
+ mt_entry->missing_count++;
+ mt_entry->dev_handle = 0;
+ }
+
+ dpm_idx = mt_entry->dpm_entry_num;
+ if (dpm_idx == MPR_DPM_BAD_IDX) {
+ if ((reason == MPI2_EVENT_IR_CHANGE_RC_ADDED) ||
+ (reason == MPI2_EVENT_IR_CHANGE_RC_REMOVED))
+ dpm_idx = _mapping_get_dpm_idx_from_id(sc,
+ mt_entry->physical_id, 0);
+ else if (reason == MPI2_EVENT_IR_CHANGE_RC_VOLUME_DELETED)
+ return;
+ }
+ if (dpm_idx != MPR_DPM_BAD_IDX) {
+ dpm_entry = (Mpi2DriverMap0Entry_t *)((u8 *)sc->dpm_pg0 +
+ sizeof(MPI2_CONFIG_EXTENDED_PAGE_HEADER));
+ dpm_entry += dpm_idx;
+ missing_cnt = dpm_entry->MappingInformation &
+ MPI2_DRVMAP0_MAPINFO_MISSING_MASK;
+ if ((mt_entry->physical_id ==
+ le64toh((u64)dpm_entry->PhysicalIdentifier.High |
+ dpm_entry->PhysicalIdentifier.Low)) && (missing_cnt ==
+ mt_entry->missing_count))
+ mt_entry->init_complete = 1;
+ } else {
+ dpm_idx = _mapping_get_free_dpm_idx(sc);
+ mt_entry->init_complete = 0;
+ }
+
+ if ((dpm_idx != MPR_DPM_BAD_IDX) && !mt_entry->init_complete) {
+ mt_entry->init_complete = 1;
+ mt_entry->dpm_entry_num = dpm_idx;
+ dpm_entry = (Mpi2DriverMap0Entry_t *)((u8 *)sc->dpm_pg0 +
+ sizeof(MPI2_CONFIG_EXTENDED_PAGE_HEADER));
+ dpm_entry += dpm_idx;
+ dpm_entry->PhysicalIdentifier.Low =
+ (0xFFFFFFFF & mt_entry->physical_id);
+ dpm_entry->PhysicalIdentifier.High =
+ (mt_entry->physical_id >> 32);
+ dpm_entry->DeviceIndex = map_idx;
+ dpm_entry->MappingInformation = mt_entry->missing_count;
+ dpm_entry->PhysicalBitsMapping = 0;
+ dpm_entry->Reserved1 = 0;
+ sc->dpm_flush_entry[dpm_idx] = 1;
+ sc->dpm_entry_used[dpm_idx] = 1;
+ } else if (dpm_idx == MPR_DPM_BAD_IDX) {
+ printf("%s: no space to add entry in DPM table\n", __func__);
+ mt_entry->init_complete = 1;
+ }
+}
+
+/**
+ * _mapping_add_to_removal_table - mark an entry for removal
+ * @sc: per adapter object
+ * @handle: Handle of enclosures/device/volume
+ *
+ * Adds the handle or DPM entry number in removal table.
+ *
+ * Returns nothing.
+ */
+static void
+_mapping_add_to_removal_table(struct mpr_softc *sc, u16 handle,
+ u16 dpm_idx)
+{
+ struct map_removal_table *remove_entry;
+ u32 i;
+ u16 ioc_pg8_flags = le16toh(sc->ioc_pg8.Flags);
+
+ remove_entry = sc->removal_table;
+
+ for (i = 0; i < sc->max_devices; i++, remove_entry++) {
+ if (remove_entry->dev_handle || remove_entry->dpm_entry_num !=
+ MPR_DPM_BAD_IDX)
+ continue;
+ if ((ioc_pg8_flags & MPI2_IOCPAGE8_FLAGS_MASK_MAPPING_MODE) ==
+ MPI2_IOCPAGE8_FLAGS_ENCLOSURE_SLOT_MAPPING) {
+ if (dpm_idx)
+ remove_entry->dpm_entry_num = dpm_idx;
+ if (remove_entry->dpm_entry_num == MPR_DPM_BAD_IDX)
+ remove_entry->dev_handle = handle;
+ } else if ((ioc_pg8_flags &
+ MPI2_IOCPAGE8_FLAGS_MASK_MAPPING_MODE) ==
+ MPI2_IOCPAGE8_FLAGS_DEVICE_PERSISTENCE_MAPPING)
+ remove_entry->dev_handle = handle;
+ break;
+ }
+
+}
+
+/**
+ * _mapping_update_missing_count - Update missing count for a device
+ * @sc: per adapter object
+ * @topo_change: Topology change event entry
+ *
+ * Search through the topology change list and if any device is found not
+ * responding it's associated map table entry and DPM entry is updated
+ *
+ * Returns nothing.
+ */
+static void
+_mapping_update_missing_count(struct mpr_softc *sc,
+ struct _map_topology_change *topo_change)
+{
+ u16 ioc_pg8_flags = le16toh(sc->ioc_pg8.Flags);
+ u8 entry;
+ struct _map_phy_change *phy_change;
+ u32 map_idx;
+ struct dev_mapping_table *mt_entry;
+ Mpi2DriverMap0Entry_t *dpm_entry;
+
+ for (entry = 0; entry < topo_change->num_entries; entry++) {
+ phy_change = &topo_change->phy_details[entry];
+ if (!phy_change->dev_handle || (phy_change->reason !=
+ MPI2_EVENT_SAS_TOPO_RC_TARG_NOT_RESPONDING))
+ continue;
+ map_idx = _mapping_get_mt_idx_from_handle(sc, phy_change->
+ dev_handle);
+ phy_change->is_processed = 1;
+ if (map_idx == MPR_MAPTABLE_BAD_IDX) {
+ printf("%s: device is already removed from mapping "
+ "table\n", __func__);
+ continue;
+ }
+ mt_entry = &sc->mapping_table[map_idx];
+ if (!mt_entry->init_complete) {
+ if (mt_entry->missing_count < MPR_MAX_MISSING_COUNT)
+ mt_entry->missing_count++;
+ else
+ mt_entry->init_complete = 1;
+ }
+ if (!mt_entry->missing_count)
+ mt_entry->missing_count++;
+ _mapping_add_to_removal_table(sc, mt_entry->dev_handle, 0);
+ mt_entry->dev_handle = 0;
+
+ if (((ioc_pg8_flags & MPI2_IOCPAGE8_FLAGS_MASK_MAPPING_MODE) ==
+ MPI2_IOCPAGE8_FLAGS_DEVICE_PERSISTENCE_MAPPING) &&
+ sc->is_dpm_enable && !mt_entry->init_complete &&
+ mt_entry->dpm_entry_num != MPR_DPM_BAD_IDX) {
+ dpm_entry =
+ (Mpi2DriverMap0Entry_t *) ((u8 *)sc->dpm_pg0 +
+ sizeof(MPI2_CONFIG_EXTENDED_PAGE_HEADER));
+ dpm_entry += mt_entry->dpm_entry_num;
+ dpm_entry->MappingInformation = mt_entry->missing_count;
+ sc->dpm_flush_entry[mt_entry->dpm_entry_num] = 1;
+ }
+ mt_entry->init_complete = 1;
+ }
+}
+
+/**
+ * _mapping_find_enc_map_space -find map table entries for enclosure
+ * @sc: per adapter object
+ * @et_entry: enclosure entry
+ *
+ * Search through the mapping table defragment it and provide contiguous
+ * space in map table for a particular enclosure entry
+ *
+ * Returns start index in map table or bad index.
+ */
+static u32
+_mapping_find_enc_map_space(struct mpr_softc *sc,
+ struct enc_mapping_table *et_entry)
+{
+ u16 vol_mapping_flags;
+ u32 skip_count, end_of_table, map_idx, enc_idx;
+ u16 num_found;
+ u32 start_idx = MPR_MAPTABLE_BAD_IDX;
+ struct dev_mapping_table *mt_entry;
+ struct enc_mapping_table *enc_entry;
+ unsigned char done_flag = 0, found_space;
+ u16 max_num_phy_ids = le16toh(sc->ioc_pg8.MaxNumPhysicalMappedIDs);
+
+ skip_count = sc->num_rsvd_entries;
+ num_found = 0;
+
+ vol_mapping_flags = le16toh(sc->ioc_pg8.IRVolumeMappingFlags) &
+ MPI2_IOCPAGE8_IRFLAGS_MASK_VOLUME_MAPPING_MODE;
+
+ if (!sc->ir_firmware)
+ end_of_table = sc->max_devices;
+ else if (vol_mapping_flags == MPI2_IOCPAGE8_IRFLAGS_LOW_VOLUME_MAPPING)
+ end_of_table = sc->max_devices;
+ else
+ end_of_table = sc->max_devices - sc->max_volumes;
+
+ for (map_idx = (max_num_phy_ids + skip_count);
+ map_idx < end_of_table; map_idx++) {
+ mt_entry = &sc->mapping_table[map_idx];
+ if ((et_entry->enclosure_id == mt_entry->physical_id) &&
+ (!mt_entry->phy_bits || (mt_entry->phy_bits &
+ et_entry->phy_bits))) {
+ num_found += 1;
+ if (num_found == et_entry->num_slots) {
+ start_idx = (map_idx - num_found) + 1;
+ return start_idx;
+ }
+ } else
+ num_found = 0;
+ }
+ for (map_idx = (max_num_phy_ids + skip_count);
+ map_idx < end_of_table; map_idx++) {
+ mt_entry = &sc->mapping_table[map_idx];
+ if (!(mt_entry->device_info & MPR_DEV_RESERVED)) {
+ num_found += 1;
+ if (num_found == et_entry->num_slots) {
+ start_idx = (map_idx - num_found) + 1;
+ return start_idx;
+ }
+ } else
+ num_found = 0;
+ }
+
+ while (!done_flag) {
+ enc_idx = _mapping_get_high_missing_et_idx(sc);
+ if (enc_idx == MPR_ENCTABLE_BAD_IDX)
+ return MPR_MAPTABLE_BAD_IDX;
+ enc_entry = &sc->enclosure_table[enc_idx];
+ /*VSP FIXME*/
+ enc_entry->skip_search = 1;
+ mt_entry = &sc->mapping_table[enc_entry->start_index];
+ for (map_idx = enc_entry->start_index; map_idx <
+ (enc_entry->start_index + enc_entry->num_slots); map_idx++,
+ mt_entry++)
+ mt_entry->device_info &= ~MPR_DEV_RESERVED;
+ found_space = 0;
+ for (map_idx = (max_num_phy_ids +
+ skip_count); map_idx < end_of_table; map_idx++) {
+ mt_entry = &sc->mapping_table[map_idx];
+ if (!(mt_entry->device_info & MPR_DEV_RESERVED)) {
+ num_found += 1;
+ if (num_found == et_entry->num_slots) {
+ start_idx = (map_idx - num_found) + 1;
+ found_space = 1;
+ }
+ } else
+ num_found = 0;
+ }
+
+ if (!found_space)
+ continue;
+ for (map_idx = start_idx; map_idx < (start_idx + num_found);
+ map_idx++) {
+ enc_entry = sc->enclosure_table;
+ for (enc_idx = 0; enc_idx < sc->num_enc_table_entries;
+ enc_idx++, enc_entry++) {
+ if (map_idx < enc_entry->start_index ||
+ map_idx > (enc_entry->start_index +
+ enc_entry->num_slots))
+ continue;
+ if (!enc_entry->removal_flag) {
+ enc_entry->removal_flag = 1;
+ _mapping_add_to_removal_table(sc, 0,
+ enc_entry->dpm_entry_num);
+ }
+ mt_entry = &sc->mapping_table[map_idx];
+ if (mt_entry->device_info &
+ MPR_MAP_IN_USE) {
+ _mapping_add_to_removal_table(sc,
+ mt_entry->dev_handle, 0);
+ _mapping_clear_map_entry(mt_entry);
+ }
+ if (map_idx == (enc_entry->start_index +
+ enc_entry->num_slots - 1))
+ _mapping_clear_enc_entry(et_entry);
+ }
+ }
+ enc_entry = sc->enclosure_table;
+ for (enc_idx = 0; enc_idx < sc->num_enc_table_entries;
+ enc_idx++, enc_entry++) {
+ if (!enc_entry->removal_flag) {
+ mt_entry = &sc->mapping_table[enc_entry->
+ start_index];
+ for (map_idx = enc_entry->start_index; map_idx <
+ (enc_entry->start_index +
+ enc_entry->num_slots); map_idx++,
+ mt_entry++)
+ mt_entry->device_info |=
+ MPR_DEV_RESERVED;
+ et_entry->skip_search = 0;
+ }
+ }
+ done_flag = 1;
+ }
+ return start_idx;
+}
+
+/**
+ * _mapping_get_dev_info -get information about newly added devices
+ * @sc: per adapter object
+ * @topo_change: Topology change event entry
+ *
+ * Search through the topology change event list and issues sas device pg0
+ * requests for the newly added device and reserved entries in tables
+ *
+ * Returns nothing
+ */
+static void
+_mapping_get_dev_info(struct mpr_softc *sc,
+ struct _map_topology_change *topo_change)
+{
+ u16 ioc_pg8_flags = le16toh(sc->ioc_pg8.Flags);
+ Mpi2ConfigReply_t mpi_reply;
+ Mpi2SasDevicePage0_t sas_device_pg0;
+ u8 entry, enc_idx, phy_idx;
+ u32 map_idx, index, device_info;
+ struct _map_phy_change *phy_change, *tmp_phy_change;
+ uint64_t sas_address;
+ struct enc_mapping_table *et_entry;
+ struct dev_mapping_table *mt_entry;
+ u8 add_code = MPI2_EVENT_SAS_TOPO_RC_TARG_ADDED;
+ int rc;
+
+ for (entry = 0; entry < topo_change->num_entries; entry++) {
+ phy_change = &topo_change->phy_details[entry];
+ if (phy_change->is_processed || !phy_change->dev_handle ||
+ phy_change->reason != MPI2_EVENT_SAS_TOPO_RC_TARG_ADDED)
+ continue;
+ if (mpr_config_get_sas_device_pg0(sc, &mpi_reply,
+ &sas_device_pg0, MPI2_SAS_DEVICE_PGAD_FORM_HANDLE,
+ phy_change->dev_handle)) {
+ phy_change->is_processed = 1;
+ continue;
+ }
+
+ device_info = le32toh(sas_device_pg0.DeviceInfo);
+ if ((ioc_pg8_flags & MPI2_IOCPAGE8_FLAGS_MASK_MAPPING_MODE) ==
+ MPI2_IOCPAGE8_FLAGS_DEVICE_PERSISTENCE_MAPPING) {
+ if ((device_info & MPI2_SAS_DEVICE_INFO_END_DEVICE) &&
+ (device_info & MPI2_SAS_DEVICE_INFO_SATA_DEVICE)) {
+ rc = mprsas_get_sas_address_for_sata_disk(sc,
+ &sas_address, phy_change->dev_handle,
+ device_info);
+ if (rc) {
+ printf("%s: failed to compute the "
+ "hashed SAS Address for SATA "
+ "device with handle 0x%04x\n",
+ __func__, phy_change->dev_handle);
+ sas_address =
+ sas_device_pg0.SASAddress.High;
+ sas_address = (sas_address << 32) |
+ sas_device_pg0.SASAddress.Low;
+ }
+ mpr_dprint(sc, MPR_INFO, "SAS Address for SATA "
+ "device = %jx\n", sas_address);
+ } else {
+ sas_address =
+ sas_device_pg0.SASAddress.High;
+ sas_address = (sas_address << 32) |
+ sas_device_pg0.SASAddress.Low;
+ }
+ } else {
+ sas_address = sas_device_pg0.SASAddress.High;
+ sas_address = (sas_address << 32) |
+ sas_device_pg0.SASAddress.Low;
+ }
+ phy_change->physical_id = sas_address;
+ phy_change->slot = le16toh(sas_device_pg0.Slot);
+ phy_change->device_info =
+ le32toh(sas_device_pg0.DeviceInfo);
+
+ if ((ioc_pg8_flags & MPI2_IOCPAGE8_FLAGS_MASK_MAPPING_MODE) ==
+ MPI2_IOCPAGE8_FLAGS_ENCLOSURE_SLOT_MAPPING) {
+ enc_idx = _mapping_get_enc_idx_from_handle(sc,
+ topo_change->enc_handle);
+ if (enc_idx == MPR_ENCTABLE_BAD_IDX) {
+ phy_change->is_processed = 1;
+ printf("%s: failed to add the device with "
+ "handle 0x%04x because the enclosure is "
+ "not in the mapping table\n", __func__,
+ phy_change->dev_handle);
+ continue;
+ }
+ if (!((phy_change->device_info &
+ MPI2_SAS_DEVICE_INFO_END_DEVICE) &&
+ (phy_change->device_info &
+ (MPI2_SAS_DEVICE_INFO_SSP_TARGET |
+ MPI2_SAS_DEVICE_INFO_STP_TARGET |
+ MPI2_SAS_DEVICE_INFO_SATA_DEVICE)))) {
+ phy_change->is_processed = 1;
+ continue;
+ }
+ et_entry = &sc->enclosure_table[enc_idx];
+ if (et_entry->start_index != MPR_MAPTABLE_BAD_IDX)
+ continue;
+ if (!topo_change->exp_handle) {
+ map_idx = sc->num_rsvd_entries;
+ et_entry->start_index = map_idx;
+ } else {
+ map_idx = _mapping_find_enc_map_space(sc,
+ et_entry);
+ et_entry->start_index = map_idx;
+ if (et_entry->start_index ==
+ MPR_MAPTABLE_BAD_IDX) {
+ phy_change->is_processed = 1;
+ for (phy_idx = 0; phy_idx <
+ topo_change->num_entries;
+ phy_idx++) {
+ tmp_phy_change =
+ &topo_change->phy_details
+ [phy_idx];
+ if (tmp_phy_change->reason ==
+ add_code)
+ tmp_phy_change->
+ is_processed = 1;
+ }
+ break;
+ }
+ }
+ mt_entry = &sc->mapping_table[map_idx];
+ for (index = map_idx; index < (et_entry->num_slots
+ + map_idx); index++, mt_entry++) {
+ mt_entry->device_info = MPR_DEV_RESERVED;
+ mt_entry->physical_id = et_entry->enclosure_id;
+ mt_entry->phy_bits = et_entry->phy_bits;
+ }
+ }
+ }
+}
+
+/**
+ * _mapping_set_mid_to_eid -set map table data from enclosure table
+ * @sc: per adapter object
+ * @et_entry: enclosure entry
+ *
+ * Returns nothing
+ */
+static inline void
+_mapping_set_mid_to_eid(struct mpr_softc *sc,
+ struct enc_mapping_table *et_entry)
+{
+ struct dev_mapping_table *mt_entry;
+ u16 slots = et_entry->num_slots, map_idx;
+ u32 start_idx = et_entry->start_index;
+ if (start_idx != MPR_MAPTABLE_BAD_IDX) {
+ mt_entry = &sc->mapping_table[start_idx];
+ for (map_idx = 0; map_idx < slots; map_idx++, mt_entry++)
+ mt_entry->physical_id = et_entry->enclosure_id;
+ }
+}
+
+/**
+ * _mapping_clear_removed_entries - mark the entries to be cleared
+ * @sc: per adapter object
+ *
+ * Search through the removal table and mark the entries which needs to be
+ * flushed to DPM and also updates the map table and enclosure table by
+ * clearing the corresponding entries.
+ *
+ * Returns nothing
+ */
+static void
+_mapping_clear_removed_entries(struct mpr_softc *sc)
+{
+ u32 remove_idx;
+ struct map_removal_table *remove_entry;
+ Mpi2DriverMap0Entry_t *dpm_entry;
+ u8 done_flag = 0, num_entries, m, i;
+ struct enc_mapping_table *et_entry, *from, *to;
+ u16 ioc_pg8_flags = le16toh(sc->ioc_pg8.Flags);
+
+ if (sc->is_dpm_enable) {
+ remove_entry = sc->removal_table;
+ for (remove_idx = 0; remove_idx < sc->max_devices;
+ remove_idx++, remove_entry++) {
+ if (remove_entry->dpm_entry_num != MPR_DPM_BAD_IDX) {
+ dpm_entry = (Mpi2DriverMap0Entry_t *)
+ ((u8 *) sc->dpm_pg0 +
+ sizeof(MPI2_CONFIG_EXTENDED_PAGE_HEADER));
+ dpm_entry += remove_entry->dpm_entry_num;
+ dpm_entry->PhysicalIdentifier.Low = 0;
+ dpm_entry->PhysicalIdentifier.High = 0;
+ dpm_entry->DeviceIndex = 0;
+ dpm_entry->MappingInformation = 0;
+ dpm_entry->PhysicalBitsMapping = 0;
+ sc->dpm_flush_entry[remove_entry->
+ dpm_entry_num] = 1;
+ sc->dpm_entry_used[remove_entry->dpm_entry_num]
+ = 0;
+ remove_entry->dpm_entry_num = MPR_DPM_BAD_IDX;
+ }
+ }
+ }
+ if ((ioc_pg8_flags & MPI2_IOCPAGE8_FLAGS_MASK_MAPPING_MODE) ==
+ MPI2_IOCPAGE8_FLAGS_ENCLOSURE_SLOT_MAPPING) {
+ num_entries = sc->num_enc_table_entries;
+ while (!done_flag) {
+ done_flag = 1;
+ et_entry = sc->enclosure_table;
+ for (i = 0; i < num_entries; i++, et_entry++) {
+ if (!et_entry->enc_handle && et_entry->
+ init_complete) {
+ done_flag = 0;
+ if (i != (num_entries - 1)) {
+ from = &sc->enclosure_table
+ [i+1];
+ to = &sc->enclosure_table[i];
+ for (m = i; m < (num_entries -
+ 1); m++, from++, to++) {
+ _mapping_set_mid_to_eid
+ (sc, to);
+ *to = *from;
+ }
+ _mapping_clear_enc_entry(to);
+ sc->num_enc_table_entries--;
+ num_entries =
+ sc->num_enc_table_entries;
+ } else {
+ _mapping_clear_enc_entry
+ (et_entry);
+ sc->num_enc_table_entries--;
+ num_entries =
+ sc->num_enc_table_entries;
+ }
+ }
+ }
+ }
+ }
+}
+
+/**
+ * _mapping_add_new_device -Add the new device into mapping table
+ * @sc: per adapter object
+ * @topo_change: Topology change event entry
+ *
+ * Search through the topology change event list and updates map table,
+ * enclosure table and DPM pages for for the newly added devices.
+ *
+ * Returns nothing
+ */
+static void
+_mapping_add_new_device(struct mpr_softc *sc,
+ struct _map_topology_change *topo_change)
+{
+ u8 enc_idx, missing_cnt, is_removed = 0;
+ u16 dpm_idx;
+ u32 search_idx, map_idx;
+ u32 entry;
+ struct dev_mapping_table *mt_entry;
+ struct enc_mapping_table *et_entry;
+ struct _map_phy_change *phy_change;
+ u16 ioc_pg8_flags = le16toh(sc->ioc_pg8.Flags);
+ Mpi2DriverMap0Entry_t *dpm_entry;
+ uint64_t temp64_var;
+ u8 map_shift = MPI2_DRVMAP0_MAPINFO_SLOT_SHIFT;
+ u8 hdr_sz = sizeof(MPI2_CONFIG_EXTENDED_PAGE_HEADER);
+ u16 max_num_phy_ids = le16toh(sc->ioc_pg8.MaxNumPhysicalMappedIDs);
+
+ for (entry = 0; entry < topo_change->num_entries; entry++) {
+ phy_change = &topo_change->phy_details[entry];
+ if (phy_change->is_processed)
+ continue;
+ if (phy_change->reason != MPI2_EVENT_SAS_TOPO_RC_TARG_ADDED ||
+ !phy_change->dev_handle) {
+ phy_change->is_processed = 1;
+ continue;
+ }
+ if ((ioc_pg8_flags & MPI2_IOCPAGE8_FLAGS_MASK_MAPPING_MODE) ==
+ MPI2_IOCPAGE8_FLAGS_ENCLOSURE_SLOT_MAPPING) {
+ enc_idx = _mapping_get_enc_idx_from_handle
+ (sc, topo_change->enc_handle);
+ if (enc_idx == MPR_ENCTABLE_BAD_IDX) {
+ phy_change->is_processed = 1;
+ printf("%s: failed to add the device with "
+ "handle 0x%04x because the enclosure is "
+ "not in the mapping table\n", __func__,
+ phy_change->dev_handle);
+ continue;
+ }
+ et_entry = &sc->enclosure_table[enc_idx];
+ if (et_entry->start_index == MPR_MAPTABLE_BAD_IDX) {
+ phy_change->is_processed = 1;
+ if (!sc->mt_full_retry) {
+ sc->mt_add_device_failed = 1;
+ continue;
+ }
+ printf("%s: failed to add the device with "
+ "handle 0x%04x because there is no free "
+ "space available in the mapping table\n",
+ __func__, phy_change->dev_handle);
+ continue;
+ }
+ map_idx = et_entry->start_index + phy_change->slot -
+ et_entry->start_slot;
+ mt_entry = &sc->mapping_table[map_idx];
+ mt_entry->physical_id = phy_change->physical_id;
+ mt_entry->channel = 0;
+ mt_entry->id = map_idx;
+ mt_entry->dev_handle = phy_change->dev_handle;
+ mt_entry->missing_count = 0;
+ mt_entry->dpm_entry_num = et_entry->dpm_entry_num;
+ mt_entry->device_info = phy_change->device_info |
+ (MPR_DEV_RESERVED | MPR_MAP_IN_USE);
+ if (sc->is_dpm_enable) {
+ dpm_idx = et_entry->dpm_entry_num;
+ if (dpm_idx == MPR_DPM_BAD_IDX)
+ dpm_idx = _mapping_get_dpm_idx_from_id
+ (sc, et_entry->enclosure_id,
+ et_entry->phy_bits);
+ if (dpm_idx == MPR_DPM_BAD_IDX) {
+ dpm_idx = _mapping_get_free_dpm_idx(sc);
+ if (dpm_idx != MPR_DPM_BAD_IDX) {
+ dpm_entry =
+ (Mpi2DriverMap0Entry_t *)
+ ((u8 *) sc->dpm_pg0 +
+ hdr_sz);
+ dpm_entry += dpm_idx;
+ dpm_entry->
+ PhysicalIdentifier.Low =
+ (0xFFFFFFFF &
+ et_entry->enclosure_id);
+ dpm_entry->
+ PhysicalIdentifier.High =
+ ( et_entry->enclosure_id
+ >> 32);
+ dpm_entry->DeviceIndex =
+ (U16)et_entry->start_index;
+ dpm_entry->MappingInformation =
+ et_entry->num_slots;
+ dpm_entry->MappingInformation
+ <<= map_shift;
+ dpm_entry->PhysicalBitsMapping
+ = et_entry->phy_bits;
+ et_entry->dpm_entry_num =
+ dpm_idx;
+ /* FIXME Do I need to set the dpm_idxin mt_entry too */
+ sc->dpm_entry_used[dpm_idx] = 1;
+ sc->dpm_flush_entry[dpm_idx] =
+ 1;
+ phy_change->is_processed = 1;
+ } else {
+ phy_change->is_processed = 1;
+ mpr_dprint(sc, MPR_INFO, "%s: "
+ "failed to add the device "
+ "with handle 0x%04x to "
+ "persistent table because "
+ "there is no free space "
+ "available\n", __func__,
+ phy_change->dev_handle);
+ }
+ } else {
+ et_entry->dpm_entry_num = dpm_idx;
+ mt_entry->dpm_entry_num = dpm_idx;
+ }
+ }
+ /* FIXME Why not mt_entry too? */
+ et_entry->init_complete = 1;
+ } else if ((ioc_pg8_flags &
+ MPI2_IOCPAGE8_FLAGS_MASK_MAPPING_MODE) ==
+ MPI2_IOCPAGE8_FLAGS_DEVICE_PERSISTENCE_MAPPING) {
+ map_idx = _mapping_get_mt_idx_from_id
+ (sc, phy_change->physical_id);
+ if (map_idx == MPR_MAPTABLE_BAD_IDX) {
+ search_idx = sc->num_rsvd_entries;
+ if (topo_change->exp_handle)
+ search_idx += max_num_phy_ids;
+ map_idx = _mapping_get_free_mt_idx(sc,
+ search_idx);
+ }
+ if (map_idx == MPR_MAPTABLE_BAD_IDX) {
+ map_idx = _mapping_get_high_missing_mt_idx(sc);
+ if (map_idx != MPR_MAPTABLE_BAD_IDX) {
+ mt_entry = &sc->mapping_table[map_idx];
+ if (mt_entry->dev_handle) {
+ _mapping_add_to_removal_table
+ (sc, mt_entry->dev_handle,
+ 0);
+ is_removed = 1;
+ }
+ mt_entry->init_complete = 0;
+ }
+ }
+ if (map_idx != MPR_MAPTABLE_BAD_IDX) {
+ mt_entry = &sc->mapping_table[map_idx];
+ mt_entry->physical_id = phy_change->physical_id;
+ mt_entry->channel = 0;
+ mt_entry->id = map_idx;
+ mt_entry->dev_handle = phy_change->dev_handle;
+ mt_entry->missing_count = 0;
+ mt_entry->device_info = phy_change->device_info
+ | (MPR_DEV_RESERVED | MPR_MAP_IN_USE);
+ } else {
+ phy_change->is_processed = 1;
+ if (!sc->mt_full_retry) {
+ sc->mt_add_device_failed = 1;
+ continue;
+ }
+ printf("%s: failed to add the device with "
+ "handle 0x%04x because there is no free "
+ "space available in the mapping table\n",
+ __func__, phy_change->dev_handle);
+ continue;
+ }
+ if (sc->is_dpm_enable) {
+ if (mt_entry->dpm_entry_num !=
+ MPR_DPM_BAD_IDX) {
+ dpm_idx = mt_entry->dpm_entry_num;
+ dpm_entry = (Mpi2DriverMap0Entry_t *)
+ ((u8 *)sc->dpm_pg0 + hdr_sz);
+ dpm_entry += dpm_idx;
+ missing_cnt = dpm_entry->
+ MappingInformation &
+ MPI2_DRVMAP0_MAPINFO_MISSING_MASK;
+ temp64_var = dpm_entry->
+ PhysicalIdentifier.High;
+ temp64_var = (temp64_var << 32) |
+ dpm_entry->PhysicalIdentifier.Low;
+ if ((mt_entry->physical_id ==
+ temp64_var) && !missing_cnt)
+ mt_entry->init_complete = 1;
+ } else {
+ dpm_idx = _mapping_get_free_dpm_idx(sc);
+ mt_entry->init_complete = 0;
+ }
+ if (dpm_idx != MPR_DPM_BAD_IDX &&
+ !mt_entry->init_complete) {
+ mt_entry->init_complete = 1;
+ mt_entry->dpm_entry_num = dpm_idx;
+ dpm_entry = (Mpi2DriverMap0Entry_t *)
+ ((u8 *)sc->dpm_pg0 + hdr_sz);
+ dpm_entry += dpm_idx;
+ dpm_entry->PhysicalIdentifier.Low =
+ (0xFFFFFFFF &
+ mt_entry->physical_id);
+ dpm_entry->PhysicalIdentifier.High =
+ (mt_entry->physical_id >> 32);
+ dpm_entry->DeviceIndex = (U16) map_idx;
+ dpm_entry->MappingInformation = 0;
+ dpm_entry->PhysicalBitsMapping = 0;
+ sc->dpm_entry_used[dpm_idx] = 1;
+ sc->dpm_flush_entry[dpm_idx] = 1;
+ phy_change->is_processed = 1;
+ } else if (dpm_idx == MPR_DPM_BAD_IDX) {
+ phy_change->is_processed = 1;
+ mpr_dprint(sc, MPR_INFO, "%s: "
+ "failed to add the device "
+ "with handle 0x%04x to "
+ "persistent table because "
+ "there is no free space "
+ "available\n", __func__,
+ phy_change->dev_handle);
+ }
+ }
+ mt_entry->init_complete = 1;
+ }
+
+ phy_change->is_processed = 1;
+ }
+ if (is_removed)
+ _mapping_clear_removed_entries(sc);
+}
+
+/**
+ * _mapping_flush_dpm_pages -Flush the DPM pages to NVRAM
+ * @sc: per adapter object
+ *
+ * Returns nothing
+ */
+static void
+_mapping_flush_dpm_pages(struct mpr_softc *sc)
+{
+ Mpi2DriverMap0Entry_t *dpm_entry;
+ Mpi2ConfigReply_t mpi_reply;
+ Mpi2DriverMappingPage0_t config_page;
+ u16 entry_num;
+
+ for (entry_num = 0; entry_num < sc->max_dpm_entries; entry_num++) {
+ if (!sc->dpm_flush_entry[entry_num])
+ continue;
+ memset(&config_page, 0, sizeof(Mpi2DriverMappingPage0_t));
+ memcpy(&config_page.Header, (u8 *)sc->dpm_pg0,
+ sizeof(MPI2_CONFIG_EXTENDED_PAGE_HEADER));
+ dpm_entry = (Mpi2DriverMap0Entry_t *) ((u8 *)sc->dpm_pg0 +
+ sizeof(MPI2_CONFIG_EXTENDED_PAGE_HEADER));
+ dpm_entry += entry_num;
+ dpm_entry->MappingInformation = htole16(dpm_entry->
+ MappingInformation);
+ dpm_entry->DeviceIndex = htole16(dpm_entry->DeviceIndex);
+ dpm_entry->PhysicalBitsMapping = htole32(dpm_entry->
+ PhysicalBitsMapping);
+ memcpy(&config_page.Entry, (u8 *)dpm_entry,
+ sizeof(Mpi2DriverMap0Entry_t));
+ /* TODO-How to handle failed writes? */
+ if (mpr_config_set_dpm_pg0(sc, &mpi_reply, &config_page,
+ entry_num)) {
+ printf("%s: write of dpm entry %d for device failed\n",
+ __func__, entry_num);
+ } else
+ sc->dpm_flush_entry[entry_num] = 0;
+ dpm_entry->MappingInformation = le16toh(dpm_entry->
+ MappingInformation);
+ dpm_entry->DeviceIndex = le16toh(dpm_entry->DeviceIndex);
+ dpm_entry->PhysicalBitsMapping = le32toh(dpm_entry->
+ PhysicalBitsMapping);
+ }
+}
+
+/**
+ * _mapping_allocate_memory- allocates the memory required for mapping tables
+ * @sc: per adapter object
+ *
+ * Allocates the memory for all the tables required for host mapping
+ *
+ * Return 0 on success or non-zero on failure.
+ */
+int
+mpr_mapping_allocate_memory(struct mpr_softc *sc)
+{
+ uint32_t dpm_pg0_sz;
+
+ sc->mapping_table = malloc((sizeof(struct dev_mapping_table) *
+ sc->max_devices), M_MPR, M_ZERO|M_NOWAIT);
+ if (!sc->mapping_table)
+ goto free_resources;
+
+ sc->removal_table = malloc((sizeof(struct map_removal_table) *
+ sc->max_devices), M_MPR, M_ZERO|M_NOWAIT);
+ if (!sc->removal_table)
+ goto free_resources;
+
+ sc->enclosure_table = malloc((sizeof(struct enc_mapping_table) *
+ sc->max_enclosures), M_MPR, M_ZERO|M_NOWAIT);
+ if (!sc->enclosure_table)
+ goto free_resources;
+
+ sc->dpm_entry_used = malloc((sizeof(u8) * sc->max_dpm_entries),
+ M_MPR, M_ZERO|M_NOWAIT);
+ if (!sc->dpm_entry_used)
+ goto free_resources;
+
+ sc->dpm_flush_entry = malloc((sizeof(u8) * sc->max_dpm_entries),
+ M_MPR, M_ZERO|M_NOWAIT);
+ if (!sc->dpm_flush_entry)
+ goto free_resources;
+
+ dpm_pg0_sz = sizeof(MPI2_CONFIG_EXTENDED_PAGE_HEADER) +
+ (sc->max_dpm_entries * sizeof(MPI2_CONFIG_PAGE_DRIVER_MAP0_ENTRY));
+
+ sc->dpm_pg0 = malloc(dpm_pg0_sz, M_MPR, M_ZERO|M_NOWAIT);
+ if (!sc->dpm_pg0) {
+ printf("%s: memory alloc failed for dpm page; disabling dpm\n",
+ __func__);
+ sc->is_dpm_enable = 0;
+ }
+
+ return 0;
+
+free_resources:
+ free(sc->mapping_table, M_MPR);
+ free(sc->removal_table, M_MPR);
+ free(sc->enclosure_table, M_MPR);
+ free(sc->dpm_entry_used, M_MPR);
+ free(sc->dpm_flush_entry, M_MPR);
+ free(sc->dpm_pg0, M_MPR);
+ printf("%s: device initialization failed due to failure in mapping "
+ "table memory allocation\n", __func__);
+ return -1;
+}
+
+/**
+ * mpr_mapping_free_memory- frees the memory allocated for mapping tables
+ * @sc: per adapter object
+ *
+ * Returns nothing.
+ */
+void
+mpr_mapping_free_memory(struct mpr_softc *sc)
+{
+ free(sc->mapping_table, M_MPR);
+ free(sc->removal_table, M_MPR);
+ free(sc->enclosure_table, M_MPR);
+ free(sc->dpm_entry_used, M_MPR);
+ free(sc->dpm_flush_entry, M_MPR);
+ free(sc->dpm_pg0, M_MPR);
+}
+
+
+static void
+_mapping_process_dpm_pg0(struct mpr_softc *sc)
+{
+ u8 missing_cnt, enc_idx;
+ u16 slot_id, entry_num, num_slots;
+ u32 map_idx, dev_idx, start_idx, end_idx;
+ struct dev_mapping_table *mt_entry;
+ Mpi2DriverMap0Entry_t *dpm_entry;
+ u16 ioc_pg8_flags = le16toh(sc->ioc_pg8.Flags);
+ u16 max_num_phy_ids = le16toh(sc->ioc_pg8.MaxNumPhysicalMappedIDs);
+ struct enc_mapping_table *et_entry;
+ u64 physical_id;
+ u32 phy_bits = 0;
+
+ if (sc->ir_firmware)
+ _mapping_get_ir_maprange(sc, &start_idx, &end_idx);
+
+ dpm_entry = (Mpi2DriverMap0Entry_t *) ((uint8_t *) sc->dpm_pg0 +
+ sizeof(MPI2_CONFIG_EXTENDED_PAGE_HEADER));
+ for (entry_num = 0; entry_num < sc->max_dpm_entries; entry_num++,
+ dpm_entry++) {
+ physical_id = dpm_entry->PhysicalIdentifier.High;
+ physical_id = (physical_id << 32) |
+ dpm_entry->PhysicalIdentifier.Low;
+ if (!physical_id) {
+ sc->dpm_entry_used[entry_num] = 0;
+ continue;
+ }
+ sc->dpm_entry_used[entry_num] = 1;
+ dpm_entry->MappingInformation = le16toh(dpm_entry->
+ MappingInformation);
+ missing_cnt = dpm_entry->MappingInformation &
+ MPI2_DRVMAP0_MAPINFO_MISSING_MASK;
+ dev_idx = le16toh(dpm_entry->DeviceIndex);
+ phy_bits = le32toh(dpm_entry->PhysicalBitsMapping);
+ if (sc->ir_firmware && (dev_idx >= start_idx) &&
+ (dev_idx <= end_idx)) {
+ mt_entry = &sc->mapping_table[dev_idx];
+ mt_entry->physical_id = dpm_entry->PhysicalIdentifier.High;
+ mt_entry->physical_id = (mt_entry->physical_id << 32) |
+ dpm_entry->PhysicalIdentifier.Low;
+ mt_entry->channel = MPR_RAID_CHANNEL;
+ mt_entry->id = dev_idx;
+ mt_entry->missing_count = missing_cnt;
+ mt_entry->dpm_entry_num = entry_num;
+ mt_entry->device_info = MPR_DEV_RESERVED;
+ continue;
+ }
+ if ((ioc_pg8_flags & MPI2_IOCPAGE8_FLAGS_MASK_MAPPING_MODE) ==
+ MPI2_IOCPAGE8_FLAGS_ENCLOSURE_SLOT_MAPPING) {
+ if (dev_idx < (sc->num_rsvd_entries +
+ max_num_phy_ids)) {
+ slot_id = 0;
+ if (ioc_pg8_flags &
+ MPI2_IOCPAGE8_FLAGS_DA_START_SLOT_1)
+ slot_id = 1;
+ num_slots = max_num_phy_ids;
+ } else {
+ slot_id = 0;
+ num_slots = dpm_entry->MappingInformation &
+ MPI2_DRVMAP0_MAPINFO_SLOT_MASK;
+ num_slots >>= MPI2_DRVMAP0_MAPINFO_SLOT_SHIFT;
+ }
+ enc_idx = sc->num_enc_table_entries;
+ if (enc_idx >= sc->max_enclosures) {
+ printf("%s: enclosure entries exceed max "
+ "enclosures of %d\n", __func__,
+ sc->max_enclosures);
+ break;
+ }
+ sc->num_enc_table_entries++;
+ et_entry = &sc->enclosure_table[enc_idx];
+ physical_id = dpm_entry->PhysicalIdentifier.High;
+ et_entry->enclosure_id = (physical_id << 32) |
+ dpm_entry->PhysicalIdentifier.Low;
+ et_entry->start_index = dev_idx;
+ et_entry->dpm_entry_num = entry_num;
+ et_entry->num_slots = num_slots;
+ et_entry->start_slot = slot_id;
+ et_entry->missing_count = missing_cnt;
+ et_entry->phy_bits = phy_bits;
+
+ mt_entry = &sc->mapping_table[dev_idx];
+ for (map_idx = dev_idx; map_idx < (dev_idx + num_slots);
+ map_idx++, mt_entry++) {
+ if (mt_entry->dpm_entry_num !=
+ MPR_DPM_BAD_IDX) {
+ printf("%s: conflict in mapping table "
+ "for enclosure %d\n", __func__,
+ enc_idx);
+ break;
+ }
+ physical_id = dpm_entry->PhysicalIdentifier.High;
+ mt_entry->physical_id = (physical_id << 32) |
+ dpm_entry->PhysicalIdentifier.Low;
+ mt_entry->phy_bits = phy_bits;
+ mt_entry->channel = 0;
+ mt_entry->id = dev_idx;
+ mt_entry->dpm_entry_num = entry_num;
+ mt_entry->missing_count = missing_cnt;
+ mt_entry->device_info = MPR_DEV_RESERVED;
+ }
+ } else if ((ioc_pg8_flags &
+ MPI2_IOCPAGE8_FLAGS_MASK_MAPPING_MODE) ==
+ MPI2_IOCPAGE8_FLAGS_DEVICE_PERSISTENCE_MAPPING) {
+ map_idx = dev_idx;
+ mt_entry = &sc->mapping_table[map_idx];
+ if (mt_entry->dpm_entry_num != MPR_DPM_BAD_IDX) {
+ printf("%s: conflict in mapping table for "
+ "device %d\n", __func__, map_idx);
+ break;
+ }
+ physical_id = dpm_entry->PhysicalIdentifier.High;
+ mt_entry->physical_id = (physical_id << 32) |
+ dpm_entry->PhysicalIdentifier.Low;
+ mt_entry->phy_bits = phy_bits;
+ mt_entry->channel = 0;
+ mt_entry->id = dev_idx;
+ mt_entry->missing_count = missing_cnt;
+ mt_entry->dpm_entry_num = entry_num;
+ mt_entry->device_info = MPR_DEV_RESERVED;
+ }
+ } /*close the loop for DPM table */
+}
+
+/*
+ * mpr_mapping_check_devices - start of the day check for device availabilty
+ * @sc: per adapter object
+ * @sleep_flag: Flag indicating whether this function can sleep or not
+ *
+ * Returns nothing.
+ */
+void
+mpr_mapping_check_devices(struct mpr_softc *sc, int sleep_flag)
+{
+ u32 i;
+/* u32 cntdn, i;
+ u32 timeout = 60;*/
+ struct dev_mapping_table *mt_entry;
+ u16 ioc_pg8_flags = le16toh(sc->ioc_pg8.Flags);
+ struct enc_mapping_table *et_entry;
+ u32 start_idx, end_idx;
+
+ /* We need to ucomment this when this function is called
+ * from the port enable complete */
+#if 0
+ sc->track_mapping_events = 0;
+ cntdn = (sleep_flag == CAN_SLEEP) ? 1000*timeout : 2000*timeout;
+ do {
+ if (!sc->pending_map_events)
+ break;
+ if (sleep_flag == CAN_SLEEP)
+ pause("mpr_pause", (hz/1000));/* 1msec sleep */
+ else
+ DELAY(500); /* 500 useconds delay */
+ } while (--cntdn);
+
+
+ if (!cntdn)
+ printf("%s: there are %d"
+ " pending events after %d seconds of delay\n",
+ __func__, sc->pending_map_events, timeout);
+#endif
+ sc->pending_map_events = 0;
+
+ if ((ioc_pg8_flags & MPI2_IOCPAGE8_FLAGS_MASK_MAPPING_MODE) ==
+ MPI2_IOCPAGE8_FLAGS_ENCLOSURE_SLOT_MAPPING) {
+ et_entry = sc->enclosure_table;
+ for (i = 0; i < sc->num_enc_table_entries; i++, et_entry++) {
+ if (!et_entry->init_complete) {
+ if (et_entry->missing_count <
+ MPR_MAX_MISSING_COUNT) {
+ et_entry->missing_count++;
+ if (et_entry->dpm_entry_num !=
+ MPR_DPM_BAD_IDX)
+ _mapping_commit_enc_entry(sc,
+ et_entry);
+ }
+ et_entry->init_complete = 1;
+ }
+ }
+ if (!sc->ir_firmware)
+ return;
+ _mapping_get_ir_maprange(sc, &start_idx, &end_idx);
+ mt_entry = &sc->mapping_table[start_idx];
+ for (i = start_idx; i < (end_idx + 1); i++, mt_entry++) {
+ if (mt_entry->device_info & MPR_DEV_RESERVED
+ && !mt_entry->physical_id)
+ mt_entry->init_complete = 1;
+ else if (mt_entry->device_info & MPR_DEV_RESERVED) {
+ if (!mt_entry->init_complete) {
+ if (mt_entry->missing_count <
+ MPR_MAX_MISSING_COUNT) {
+ mt_entry->missing_count++;
+ if (mt_entry->dpm_entry_num !=
+ MPR_DPM_BAD_IDX)
+ _mapping_commit_map_entry(sc,
+ mt_entry);
+ }
+ mt_entry->init_complete = 1;
+ }
+ }
+ }
+ } else if ((ioc_pg8_flags & MPI2_IOCPAGE8_FLAGS_MASK_MAPPING_MODE) ==
+ MPI2_IOCPAGE8_FLAGS_DEVICE_PERSISTENCE_MAPPING) {
+ mt_entry = sc->mapping_table;
+ for (i = 0; i < sc->max_devices; i++, mt_entry++) {
+ if (mt_entry->device_info & MPR_DEV_RESERVED
+ && !mt_entry->physical_id)
+ mt_entry->init_complete = 1;
+ else if (mt_entry->device_info & MPR_DEV_RESERVED) {
+ if (!mt_entry->init_complete) {
+ if (mt_entry->missing_count <
+ MPR_MAX_MISSING_COUNT) {
+ mt_entry->missing_count++;
+ if (mt_entry->dpm_entry_num !=
+ MPR_DPM_BAD_IDX)
+ _mapping_commit_map_entry(sc,
+ mt_entry);
+ }
+ mt_entry->init_complete = 1;
+ }
+ }
+ }
+ }
+}
+
+
+/**
+ * mpr_mapping_is_reinit_required - check whether event replay required
+ * @sc: per adapter object
+ *
+ * Checks the per ioc flags and decide whether reinit of events required
+ *
+ * Returns 1 for reinit of ioc 0 for not.
+ */
+int mpr_mapping_is_reinit_required(struct mpr_softc *sc)
+{
+ if (!sc->mt_full_retry && sc->mt_add_device_failed) {
+ sc->mt_full_retry = 1;
+ sc->mt_add_device_failed = 0;
+ _mapping_flush_dpm_pages(sc);
+ return 1;
+ }
+ sc->mt_full_retry = 1;
+ return 0;
+}
+
+/**
+ * mpr_mapping_initialize - initialize mapping tables
+ * @sc: per adapter object
+ *
+ * Read controller persitant mapping tables into internal data area.
+ *
+ * Return 0 for success or non-zero for failure.
+ */
+int
+mpr_mapping_initialize(struct mpr_softc *sc)
+{
+ uint16_t volume_mapping_flags, dpm_pg0_sz;
+ uint32_t i;
+ Mpi2ConfigReply_t mpi_reply;
+ int error;
+ uint8_t retry_count;
+ uint16_t ioc_pg8_flags = le16toh(sc->ioc_pg8.Flags);
+
+ /* The additional 1 accounts for the virtual enclosure
+ * created for the controller
+ */
+ sc->max_enclosures = sc->facts->MaxEnclosures + 1;
+ sc->max_expanders = sc->facts->MaxSasExpanders;
+ sc->max_volumes = sc->facts->MaxVolumes;
+ sc->max_devices = sc->facts->MaxTargets + sc->max_volumes;
+ sc->pending_map_events = 0;
+ sc->num_enc_table_entries = 0;
+ sc->num_rsvd_entries = 0;
+ sc->num_channels = 1;
+ sc->max_dpm_entries = sc->ioc_pg8.MaxPersistentEntries;
+ sc->is_dpm_enable = (sc->max_dpm_entries) ? 1 : 0;
+ sc->track_mapping_events = 0;
+
+ if (ioc_pg8_flags & MPI2_IOCPAGE8_FLAGS_DISABLE_PERSISTENT_MAPPING)
+ sc->is_dpm_enable = 0;
+
+ if (ioc_pg8_flags & MPI2_IOCPAGE8_FLAGS_RESERVED_TARGETID_0)
+ sc->num_rsvd_entries = 1;
+
+ volume_mapping_flags = sc->ioc_pg8.IRVolumeMappingFlags &
+ MPI2_IOCPAGE8_IRFLAGS_MASK_VOLUME_MAPPING_MODE;
+ if (sc->ir_firmware && (volume_mapping_flags ==
+ MPI2_IOCPAGE8_IRFLAGS_LOW_VOLUME_MAPPING))
+ sc->num_rsvd_entries += sc->max_volumes;
+
+ error = mpr_mapping_allocate_memory(sc);
+ if (error)
+ return (error);
+
+ for (i = 0; i < sc->max_devices; i++)
+ _mapping_clear_map_entry(sc->mapping_table + i);
+
+ for (i = 0; i < sc->max_enclosures; i++)
+ _mapping_clear_enc_entry(sc->enclosure_table + i);
+
+ for (i = 0; i < sc->max_devices; i++) {
+ sc->removal_table[i].dev_handle = 0;
+ sc->removal_table[i].dpm_entry_num = MPR_DPM_BAD_IDX;
+ }
+
+ memset(sc->dpm_entry_used, 0, sc->max_dpm_entries);
+ memset(sc->dpm_flush_entry, 0, sc->max_dpm_entries);
+
+ if (sc->is_dpm_enable) {
+ dpm_pg0_sz = sizeof(MPI2_CONFIG_EXTENDED_PAGE_HEADER) +
+ (sc->max_dpm_entries *
+ sizeof(MPI2_CONFIG_PAGE_DRIVER_MAP0_ENTRY));
+ retry_count = 0;
+
+retry_read_dpm:
+ if (mpr_config_get_dpm_pg0(sc, &mpi_reply, sc->dpm_pg0,
+ dpm_pg0_sz)) {
+ printf("%s: dpm page read failed; disabling dpm\n",
+ __func__);
+ if (retry_count < 3) {
+ retry_count++;
+ goto retry_read_dpm;
+ }
+ sc->is_dpm_enable = 0;
+ }
+ }
+
+ if (sc->is_dpm_enable)
+ _mapping_process_dpm_pg0(sc);
+
+ sc->track_mapping_events = 1;
+ return 0;
+}
+
+/**
+ * mpr_mapping_exit - clear mapping table and associated memory
+ * @sc: per adapter object
+ *
+ * Returns nothing.
+ */
+void
+mpr_mapping_exit(struct mpr_softc *sc)
+{
+ _mapping_flush_dpm_pages(sc);
+ mpr_mapping_free_memory(sc);
+}
+
+/**
+ * mpr_mapping_get_sas_id - assign a target id for sas device
+ * @sc: per adapter object
+ * @sas_address: sas address of the device
+ * @handle: device handle
+ *
+ * Returns valid ID on success or BAD_ID.
+ */
+unsigned int
+mpr_mapping_get_sas_id(struct mpr_softc *sc, uint64_t sas_address, u16 handle)
+{
+ u32 map_idx;
+ struct dev_mapping_table *mt_entry;
+
+ for (map_idx = 0; map_idx < sc->max_devices; map_idx++) {
+ mt_entry = &sc->mapping_table[map_idx];
+ if (mt_entry->dev_handle == handle && mt_entry->physical_id ==
+ sas_address)
+ return mt_entry->id;
+ }
+
+ return MPR_MAP_BAD_ID;
+}
+
+/**
+ * mpr_mapping_get_sas_id_from_handle - find a target id in mapping table using
+ * only the dev handle. This is just a wrapper function for the local function
+ * _mapping_get_mt_idx_from_handle.
+ * @sc: per adapter object
+ * @handle: device handle
+ *
+ * Returns valid ID on success or BAD_ID.
+ */
+unsigned int
+mpr_mapping_get_sas_id_from_handle(struct mpr_softc *sc, u16 handle)
+{
+ return (_mapping_get_mt_idx_from_handle(sc, handle));
+}
+
+/**
+ * mpr_mapping_get_raid_id - assign a target id for raid device
+ * @sc: per adapter object
+ * @wwid: world wide identifier for raid volume
+ * @handle: device handle
+ *
+ * Returns valid ID on success or BAD_ID.
+ */
+unsigned int
+mpr_mapping_get_raid_id(struct mpr_softc *sc, u64 wwid, u16 handle)
+{
+ u32 map_idx;
+ struct dev_mapping_table *mt_entry;
+
+ for (map_idx = 0; map_idx < sc->max_devices; map_idx++) {
+ mt_entry = &sc->mapping_table[map_idx];
+ if (mt_entry->dev_handle == handle && mt_entry->physical_id ==
+ wwid)
+ return mt_entry->id;
+ }
+
+ return MPR_MAP_BAD_ID;
+}
+
+/**
+ * mpr_mapping_get_raid_id_from_handle - find raid device in mapping table
+ * using only the volume dev handle. This is just a wrapper function for the
+ * local function _mapping_get_ir_mt_idx_from_handle.
+ * @sc: per adapter object
+ * @volHandle: volume device handle
+ *
+ * Returns valid ID on success or BAD_ID.
+ */
+unsigned int
+mpr_mapping_get_raid_id_from_handle(struct mpr_softc *sc, u16 volHandle)
+{
+ return (_mapping_get_ir_mt_idx_from_handle(sc, volHandle));
+}
+
+/**
+ * mpr_mapping_enclosure_dev_status_change_event - handle enclosure events
+ * @sc: per adapter object
+ * @event_data: event data payload
+ *
+ * Return nothing.
+ */
+void
+mpr_mapping_enclosure_dev_status_change_event(struct mpr_softc *sc,
+ Mpi2EventDataSasEnclDevStatusChange_t *event_data)
+{
+ u8 enc_idx, missing_count;
+ struct enc_mapping_table *et_entry;
+ Mpi2DriverMap0Entry_t *dpm_entry;
+ u16 ioc_pg8_flags = le16toh(sc->ioc_pg8.Flags);
+ u8 map_shift = MPI2_DRVMAP0_MAPINFO_SLOT_SHIFT;
+ u8 update_phy_bits = 0;
+ u32 saved_phy_bits;
+ uint64_t temp64_var;
+
+ if ((ioc_pg8_flags & MPI2_IOCPAGE8_FLAGS_MASK_MAPPING_MODE) !=
+ MPI2_IOCPAGE8_FLAGS_ENCLOSURE_SLOT_MAPPING)
+ goto out;
+
+ dpm_entry = (Mpi2DriverMap0Entry_t *)((u8 *)sc->dpm_pg0 +
+ sizeof(MPI2_CONFIG_EXTENDED_PAGE_HEADER));
+
+ if (event_data->ReasonCode == MPI2_EVENT_SAS_ENCL_RC_ADDED) {
+ if (!event_data->NumSlots) {
+ printf("%s: enclosure with handle = 0x%x reported 0 "
+ "slots\n", __func__,
+ le16toh(event_data->EnclosureHandle));
+ goto out;
+ }
+ temp64_var = event_data->EnclosureLogicalID.High;
+ temp64_var = (temp64_var << 32) |
+ event_data->EnclosureLogicalID.Low;
+ enc_idx = _mapping_get_enc_idx_from_id(sc, temp64_var,
+ event_data->PhyBits);
+ if (enc_idx != MPR_ENCTABLE_BAD_IDX) {
+ et_entry = &sc->enclosure_table[enc_idx];
+ if (et_entry->init_complete &&
+ !et_entry->missing_count) {
+ printf("%s: enclosure %d is already present "
+ "with handle = 0x%x\n",__func__, enc_idx,
+ et_entry->enc_handle);
+ goto out;
+ }
+ et_entry->enc_handle = le16toh(event_data->
+ EnclosureHandle);
+ et_entry->start_slot = le16toh(event_data->StartSlot);
+ saved_phy_bits = et_entry->phy_bits;
+ et_entry->phy_bits |= le32toh(event_data->PhyBits);
+ if (saved_phy_bits != et_entry->phy_bits)
+ update_phy_bits = 1;
+ if (et_entry->missing_count || update_phy_bits) {
+ et_entry->missing_count = 0;
+ if (sc->is_dpm_enable &&
+ et_entry->dpm_entry_num !=
+ MPR_DPM_BAD_IDX) {
+ dpm_entry += et_entry->dpm_entry_num;
+ missing_count =
+ (u8)(dpm_entry->MappingInformation &
+ MPI2_DRVMAP0_MAPINFO_MISSING_MASK);
+ if (!et_entry->init_complete && (
+ missing_count || update_phy_bits)) {
+ dpm_entry->MappingInformation
+ = et_entry->num_slots;
+ dpm_entry->MappingInformation
+ <<= map_shift;
+ dpm_entry->PhysicalBitsMapping
+ = et_entry->phy_bits;
+ sc->dpm_flush_entry[et_entry->
+ dpm_entry_num] = 1;
+ }
+ }
+ }
+ } else {
+ enc_idx = sc->num_enc_table_entries;
+ if (enc_idx >= sc->max_enclosures) {
+ printf("%s: enclosure can not be added; "
+ "mapping table is full\n", __func__);
+ goto out;
+ }
+ sc->num_enc_table_entries++;
+ et_entry = &sc->enclosure_table[enc_idx];
+ et_entry->enc_handle = le16toh(event_data->
+ EnclosureHandle);
+ et_entry->enclosure_id = event_data->
+ EnclosureLogicalID.High;
+ et_entry->enclosure_id = ( et_entry->enclosure_id <<
+ 32) | event_data->EnclosureLogicalID.Low;
+ et_entry->start_index = MPR_MAPTABLE_BAD_IDX;
+ et_entry->dpm_entry_num = MPR_DPM_BAD_IDX;
+ et_entry->num_slots = le16toh(event_data->NumSlots);
+ et_entry->start_slot = le16toh(event_data->StartSlot);
+ et_entry->phy_bits = le32toh(event_data->PhyBits);
+ }
+ et_entry->init_complete = 1;
+ } else if (event_data->ReasonCode ==
+ MPI2_EVENT_SAS_ENCL_RC_NOT_RESPONDING) {
+ enc_idx = _mapping_get_enc_idx_from_handle(sc,
+ le16toh(event_data->EnclosureHandle));
+ if (enc_idx == MPR_ENCTABLE_BAD_IDX) {
+ printf("%s: cannot unmap enclosure %d because it has "
+ "already been deleted", __func__, enc_idx);
+ goto out;
+ }
+ et_entry = &sc->enclosure_table[enc_idx];
+ if (!et_entry->init_complete) {
+ if (et_entry->missing_count < MPR_MAX_MISSING_COUNT)
+ et_entry->missing_count++;
+ else
+ et_entry->init_complete = 1;
+ }
+ if (!et_entry->missing_count)
+ et_entry->missing_count++;
+ if (sc->is_dpm_enable && !et_entry->init_complete &&
+ et_entry->dpm_entry_num != MPR_DPM_BAD_IDX) {
+ dpm_entry += et_entry->dpm_entry_num;
+ dpm_entry->MappingInformation = et_entry->num_slots;
+ dpm_entry->MappingInformation <<= map_shift;
+ dpm_entry->MappingInformation |=
+ et_entry->missing_count;
+ sc->dpm_flush_entry[et_entry->dpm_entry_num] = 1;
+ }
+ et_entry->init_complete = 1;
+ }
+
+out:
+ _mapping_flush_dpm_pages(sc);
+ if (sc->pending_map_events)
+ sc->pending_map_events--;
+}
+
+/**
+ * mpr_mapping_topology_change_event - handle topology change events
+ * @sc: per adapter object
+ * @event_data: event data payload
+ *
+ * Returns nothing.
+ */
+void
+mpr_mapping_topology_change_event(struct mpr_softc *sc,
+ Mpi2EventDataSasTopologyChangeList_t *event_data)
+{
+ struct _map_topology_change topo_change;
+ struct _map_phy_change *phy_change;
+ Mpi2EventSasTopoPhyEntry_t *event_phy_change;
+ u8 i, num_entries;
+
+ topo_change.enc_handle = le16toh(event_data->EnclosureHandle);
+ topo_change.exp_handle = le16toh(event_data->ExpanderDevHandle);
+ num_entries = event_data->NumEntries;
+ topo_change.num_entries = num_entries;
+ topo_change.start_phy_num = event_data->StartPhyNum;
+ topo_change.num_phys = event_data->NumPhys;
+ topo_change.exp_status = event_data->ExpStatus;
+ event_phy_change = event_data->PHY;
+ topo_change.phy_details = NULL;
+
+ if (!num_entries)
+ goto out;
+ phy_change = malloc(sizeof(struct _map_phy_change) * num_entries,
+ M_MPR, M_NOWAIT|M_ZERO);
+ topo_change.phy_details = phy_change;
+ if (!phy_change)
+ goto out;
+ for (i = 0; i < num_entries; i++, event_phy_change++, phy_change++) {
+ phy_change->dev_handle = le16toh(event_phy_change->
+ AttachedDevHandle);
+ phy_change->reason = event_phy_change->PhyStatus &
+ MPI2_EVENT_SAS_TOPO_RC_MASK;
+ }
+ _mapping_update_missing_count(sc, &topo_change);
+ _mapping_get_dev_info(sc, &topo_change);
+ _mapping_clear_removed_entries(sc);
+ _mapping_add_new_device(sc, &topo_change);
+
+out:
+ free(topo_change.phy_details, M_MPR);
+ _mapping_flush_dpm_pages(sc);
+ if (sc->pending_map_events)
+ sc->pending_map_events--;
+}
+
+/**
+ * _mapping_check_update_ir_mt_idx - Check and update IR map table index
+ * @sc: per adapter object
+ * @event_data: event data payload
+ * @evt_idx: current event index
+ * @map_idx: current index and the place holder for new map table index
+ * @wwid_table: world wide name for volumes in the element table
+ *
+ * pass through IR events and find whether any events matches and if so
+ * tries to find new index if not returns failure
+ *
+ * Returns 0 on success and 1 on failure
+ */
+static int
+_mapping_check_update_ir_mt_idx(struct mpr_softc *sc,
+ Mpi2EventDataIrConfigChangeList_t *event_data, int evt_idx, u32 *map_idx,
+ u64 *wwid_table)
+{
+ struct dev_mapping_table *mt_entry;
+ u32 st_idx, end_idx, mt_idx = *map_idx;
+ u8 match = 0;
+ Mpi2EventIrConfigElement_t *element;
+ u16 element_flags;
+ int i;
+
+ mt_entry = &sc->mapping_table[mt_idx];
+ _mapping_get_ir_maprange(sc, &st_idx, &end_idx);
+search_again:
+ match = 0;
+ for (i = evt_idx + 1; i < event_data->NumElements; i++) {
+ element = (Mpi2EventIrConfigElement_t *)
+ &event_data->ConfigElement[i];
+ element_flags = le16toh(element->ElementFlags);
+ if ((element_flags &
+ MPI2_EVENT_IR_CHANGE_EFLAGS_ELEMENT_TYPE_MASK) !=
+ MPI2_EVENT_IR_CHANGE_EFLAGS_VOLUME_ELEMENT)
+ continue;
+ if (element->ReasonCode == MPI2_EVENT_IR_CHANGE_RC_ADDED ||
+ element->ReasonCode ==
+ MPI2_EVENT_IR_CHANGE_RC_VOLUME_CREATED) {
+ if (mt_entry->physical_id == wwid_table[i]) {
+ match = 1;
+ break;
+ }
+ }
+ }
+
+ if (match) {
+ do {
+ mt_idx++;
+ if (mt_idx > end_idx)
+ return 1;
+ mt_entry = &sc->mapping_table[mt_idx];
+ } while (mt_entry->device_info & MPR_MAP_IN_USE);
+ goto search_again;
+ }
+ *map_idx = mt_idx;
+ return 0;
+}
+
+/**
+ * mpr_mapping_ir_config_change_event - handle IR config change list events
+ * @sc: per adapter object
+ * @event_data: event data payload
+ *
+ * Returns nothing.
+ */
+void
+mpr_mapping_ir_config_change_event(struct mpr_softc *sc,
+ Mpi2EventDataIrConfigChangeList_t *event_data)
+{
+ Mpi2EventIrConfigElement_t *element;
+ int i;
+ u64 *wwid_table;
+ u32 map_idx, flags;
+ struct dev_mapping_table *mt_entry;
+ u16 element_flags;
+ u8 log_full_error = 0;
+
+ wwid_table = malloc(sizeof(u64) * event_data->NumElements, M_MPR,
+ M_NOWAIT | M_ZERO);
+ if (!wwid_table)
+ goto out;
+ element = (Mpi2EventIrConfigElement_t *)&event_data->ConfigElement[0];
+ flags = le32toh(event_data->Flags);
+ for (i = 0; i < event_data->NumElements; i++, element++) {
+ element_flags = le16toh(element->ElementFlags);
+ if ((element->ReasonCode != MPI2_EVENT_IR_CHANGE_RC_ADDED) &&
+ (element->ReasonCode != MPI2_EVENT_IR_CHANGE_RC_REMOVED) &&
+ (element->ReasonCode != MPI2_EVENT_IR_CHANGE_RC_NO_CHANGE)
+ && (element->ReasonCode !=
+ MPI2_EVENT_IR_CHANGE_RC_VOLUME_CREATED))
+ continue;
+ if ((element_flags &
+ MPI2_EVENT_IR_CHANGE_EFLAGS_ELEMENT_TYPE_MASK) ==
+ MPI2_EVENT_IR_CHANGE_EFLAGS_VOLUME_ELEMENT) {
+ mpr_config_get_volume_wwid(sc,
+ le16toh(element->VolDevHandle), &wwid_table[i]);
+ map_idx = _mapping_get_ir_mt_idx_from_wwid(sc,
+ wwid_table[i]);
+ if (map_idx != MPR_MAPTABLE_BAD_IDX) {
+ mt_entry = &sc->mapping_table[map_idx];
+ mt_entry->device_info |= MPR_MAP_IN_USE;
+ }
+ }
+ }
+ if (flags == MPI2_EVENT_IR_CHANGE_FLAGS_FOREIGN_CONFIG)
+ goto out;
+ else {
+ element = (Mpi2EventIrConfigElement_t *)&event_data->
+ ConfigElement[0];
+ for (i = 0; i < event_data->NumElements; i++, element++) {
+ if (element->ReasonCode ==
+ MPI2_EVENT_IR_CHANGE_RC_ADDED ||
+ element->ReasonCode ==
+ MPI2_EVENT_IR_CHANGE_RC_VOLUME_CREATED) {
+ map_idx = _mapping_get_ir_mt_idx_from_wwid
+ (sc, wwid_table[i]);
+ if (map_idx != MPR_MAPTABLE_BAD_IDX) {
+ mt_entry = &sc->mapping_table[map_idx];
+ mt_entry->channel = MPR_RAID_CHANNEL;
+ mt_entry->id = map_idx;
+ mt_entry->dev_handle = le16toh
+ (element->VolDevHandle);
+ mt_entry->device_info =
+ MPR_DEV_RESERVED | MPR_MAP_IN_USE;
+ _mapping_update_ir_missing_cnt(sc,
+ map_idx, element, wwid_table[i]);
+ continue;
+ }
+ map_idx = _mapping_get_free_ir_mt_idx(sc);
+ if (map_idx == MPR_MAPTABLE_BAD_IDX)
+ log_full_error = 1;
+ else if (i < (event_data->NumElements - 1)) {
+ log_full_error =
+ _mapping_check_update_ir_mt_idx
+ (sc, event_data, i, &map_idx,
+ wwid_table);
+ }
+ if (log_full_error) {
+ printf("%s: no space to add the RAID "
+ "volume with handle 0x%04x in "
+ "mapping table\n", __func__, le16toh
+ (element->VolDevHandle));
+ continue;
+ }
+ mt_entry = &sc->mapping_table[map_idx];
+ mt_entry->physical_id = wwid_table[i];
+ mt_entry->channel = MPR_RAID_CHANNEL;
+ mt_entry->id = map_idx;
+ mt_entry->dev_handle = le16toh(element->
+ VolDevHandle);
+ mt_entry->device_info = MPR_DEV_RESERVED |
+ MPR_MAP_IN_USE;
+ mt_entry->init_complete = 0;
+ _mapping_update_ir_missing_cnt(sc, map_idx,
+ element, wwid_table[i]);
+ } else if (element->ReasonCode ==
+ MPI2_EVENT_IR_CHANGE_RC_REMOVED) {
+ map_idx = _mapping_get_ir_mt_idx_from_wwid(sc,
+ wwid_table[i]);
+ if (map_idx == MPR_MAPTABLE_BAD_IDX) {
+ printf("%s: failed to remove a volume "
+ "because it has already been "
+ "removed\n", __func__);
+ continue;
+ }
+ _mapping_update_ir_missing_cnt(sc, map_idx,
+ element, wwid_table[i]);
+ } else if (element->ReasonCode ==
+ MPI2_EVENT_IR_CHANGE_RC_VOLUME_DELETED) {
+ map_idx = _mapping_get_mt_idx_from_handle(sc,
+ le16toh(element->VolDevHandle));
+ if (map_idx == MPR_MAPTABLE_BAD_IDX) {
+ printf("%s: failed to remove volume "
+ "with handle 0x%04x because it has "
+ "already been removed\n", __func__,
+ le16toh(element->VolDevHandle));
+ continue;
+ }
+ mt_entry = &sc->mapping_table[map_idx];
+ _mapping_update_ir_missing_cnt(sc, map_idx,
+ element, mt_entry->physical_id);
+ }
+ }
+ }
+
+out:
+ _mapping_flush_dpm_pages(sc);
+ free(wwid_table, M_MPR);
+ if (sc->pending_map_events)
+ sc->pending_map_events--;
+}
diff --git a/sys/dev/mpr/mpr_mapping.h b/sys/dev/mpr/mpr_mapping.h
new file mode 100644
index 0000000..3250c42
--- /dev/null
+++ b/sys/dev/mpr/mpr_mapping.h
@@ -0,0 +1,71 @@
+/*-
+ * Copyright (c) 2011-2014 LSI Corp.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * LSI MPT-Fusion Host Adapter FreeBSD
+ *
+ * $FreeBSD$
+ */
+
+#ifndef _MPR_MAPPING_H
+#define _MPR_MAPPING_H
+
+/**
+ * struct _map_phy_change - PHY entries recieved in Topology change list
+ * @physical_id: SAS address of the device attached with the associate PHY
+ * @device_info: bitfield provides detailed info about the device
+ * @dev_handle: device handle for the device pointed by this entry
+ * @slot: slot ID
+ * @is_processed: Flag to indicate whether this entry is processed or not
+ */
+struct _map_phy_change {
+ uint64_t physical_id;
+ uint32_t device_info;
+ uint16_t dev_handle;
+ uint16_t slot;
+ uint8_t reason;
+ uint8_t is_processed;
+};
+
+/**
+ * struct _map_topology_change - entries to be removed from mapping table
+ * @dpm_entry_num: index of this device in device persistent map table
+ * @dev_handle: device handle for the device pointed by this entry
+ */
+struct _map_topology_change {
+ uint16_t enc_handle;
+ uint16_t exp_handle;
+ uint8_t num_entries;
+ uint8_t start_phy_num;
+ uint8_t num_phys;
+ uint8_t exp_status;
+ struct _map_phy_change *phy_details;
+};
+
+
+extern int
+mprsas_get_sas_address_for_sata_disk(struct mpr_softc *ioc,
+ u64 *sas_address, u16 handle, u32 device_info);
+
+#endif
diff --git a/sys/dev/mpr/mpr_pci.c b/sys/dev/mpr/mpr_pci.c
new file mode 100644
index 0000000..e19f33a
--- /dev/null
+++ b/sys/dev/mpr/mpr_pci.c
@@ -0,0 +1,350 @@
+/*-
+ * Copyright (c) 2009 Yahoo! Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+/* PCI/PCI-X/PCIe bus interface for the LSI MPT2 controllers */
+
+/* TODO Move headers to mprvar */
+#include <sys/types.h>
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/kernel.h>
+#include <sys/module.h>
+#include <sys/bus.h>
+#include <sys/conf.h>
+#include <sys/malloc.h>
+#include <sys/sysctl.h>
+#include <sys/uio.h>
+
+#include <machine/bus.h>
+#include <machine/resource.h>
+#include <sys/rman.h>
+
+#include <dev/pci/pcireg.h>
+#include <dev/pci/pcivar.h>
+#include <dev/pci/pci_private.h>
+
+#include <dev/mpr/mpi/mpi2_type.h>
+#include <dev/mpr/mpi/mpi2.h>
+#include <dev/mpr/mpi/mpi2_ioc.h>
+#include <dev/mpr/mpi/mpi2_cnfg.h>
+#include <dev/mpr/mpi/mpi2_tool.h>
+
+#include <sys/queue.h>
+#include <sys/kthread.h>
+#include <dev/mpr/mpr_ioctl.h>
+#include <dev/mpr/mprvar.h>
+
+static int mpr_pci_probe(device_t);
+static int mpr_pci_attach(device_t);
+static int mpr_pci_detach(device_t);
+static int mpr_pci_suspend(device_t);
+static int mpr_pci_resume(device_t);
+static void mpr_pci_free(struct mpr_softc *);
+static int mpr_alloc_msix(struct mpr_softc *sc, int msgs);
+static int mpr_alloc_msi(struct mpr_softc *sc, int msgs);
+
+static device_method_t mpr_methods[] = {
+ DEVMETHOD(device_probe, mpr_pci_probe),
+ DEVMETHOD(device_attach, mpr_pci_attach),
+ DEVMETHOD(device_detach, mpr_pci_detach),
+ DEVMETHOD(device_suspend, mpr_pci_suspend),
+ DEVMETHOD(device_resume, mpr_pci_resume),
+ DEVMETHOD(bus_print_child, bus_generic_print_child),
+ DEVMETHOD(bus_driver_added, bus_generic_driver_added),
+ { 0, 0 }
+};
+
+static driver_t mpr_pci_driver = {
+ "mpr",
+ mpr_methods,
+ sizeof(struct mpr_softc)
+};
+
+static devclass_t mpr_devclass;
+DRIVER_MODULE(mpr, pci, mpr_pci_driver, mpr_devclass, 0, 0);
+MODULE_DEPEND(mpr, cam, 1, 1, 1);
+
+struct mpr_ident {
+ uint16_t vendor;
+ uint16_t device;
+ uint16_t subvendor;
+ uint16_t subdevice;
+ u_int flags;
+ const char *desc;
+} mpr_identifiers[] = {
+ { MPI2_MFGPAGE_VENDORID_LSI, MPI25_MFGPAGE_DEVID_SAS3004,
+ 0xffff, 0xffff, 0, "LSI SAS3004" },
+ { MPI2_MFGPAGE_VENDORID_LSI, MPI25_MFGPAGE_DEVID_SAS3008,
+ 0xffff, 0xffff, 0, "LSI SAS3008" },
+ { MPI2_MFGPAGE_VENDORID_LSI, MPI25_MFGPAGE_DEVID_SAS3108_1,
+ 0xffff, 0xffff, 0, "LSI SAS3108_1" },
+ { MPI2_MFGPAGE_VENDORID_LSI, MPI25_MFGPAGE_DEVID_SAS3108_2,
+ 0xffff, 0xffff, 0, "LSI SAS3108_2" },
+ { MPI2_MFGPAGE_VENDORID_LSI, MPI25_MFGPAGE_DEVID_SAS3108_5,
+ 0xffff, 0xffff, 0, "LSI SAS3108_5" },
+ { MPI2_MFGPAGE_VENDORID_LSI, MPI25_MFGPAGE_DEVID_SAS3108_6,
+ 0xffff, 0xffff, 0, "LSI SAS3108_6" },
+ { 0, 0, 0, 0, 0, NULL }
+};
+
+static struct mpr_ident *
+mpr_find_ident(device_t dev)
+{
+ struct mpr_ident *m;
+
+ for (m = mpr_identifiers; m->vendor != 0; m++) {
+ if (m->vendor != pci_get_vendor(dev))
+ continue;
+ if (m->device != pci_get_device(dev))
+ continue;
+ if ((m->subvendor != 0xffff) &&
+ (m->subvendor != pci_get_subvendor(dev)))
+ continue;
+ if ((m->subdevice != 0xffff) &&
+ (m->subdevice != pci_get_subdevice(dev)))
+ continue;
+ return (m);
+ }
+
+ return (NULL);
+}
+
+static int
+mpr_pci_probe(device_t dev)
+{
+ struct mpr_ident *id;
+
+ if ((id = mpr_find_ident(dev)) != NULL) {
+ device_set_desc(dev, id->desc);
+ return (BUS_PROBE_DEFAULT);
+ }
+ return (ENXIO);
+}
+
+static int
+mpr_pci_attach(device_t dev)
+{
+ struct mpr_softc *sc;
+ struct mpr_ident *m;
+ int error;
+
+ sc = device_get_softc(dev);
+ bzero(sc, sizeof(*sc));
+ sc->mpr_dev = dev;
+ m = mpr_find_ident(dev);
+ sc->mpr_flags = m->flags;
+
+ /* Twiddle basic PCI config bits for a sanity check */
+ pci_enable_busmaster(dev);
+
+ /* Allocate the System Interface Register Set */
+ sc->mpr_regs_rid = PCIR_BAR(1);
+ if ((sc->mpr_regs_resource = bus_alloc_resource_any(dev,
+ SYS_RES_MEMORY, &sc->mpr_regs_rid, RF_ACTIVE)) == NULL) {
+ mpr_printf(sc, "Cannot allocate PCI registers\n");
+ return (ENXIO);
+ }
+ sc->mpr_btag = rman_get_bustag(sc->mpr_regs_resource);
+ sc->mpr_bhandle = rman_get_bushandle(sc->mpr_regs_resource);
+
+ /* Allocate the parent DMA tag */
+ if (bus_dma_tag_create( bus_get_dma_tag(dev), /* parent */
+ 1, 0, /* algnmnt, boundary */
+ BUS_SPACE_MAXADDR, /* lowaddr */
+ BUS_SPACE_MAXADDR, /* highaddr */
+ NULL, NULL, /* filter, filterarg */
+ BUS_SPACE_MAXSIZE_32BIT,/* maxsize */
+ BUS_SPACE_UNRESTRICTED, /* nsegments */
+ BUS_SPACE_MAXSIZE_32BIT,/* maxsegsize */
+ 0, /* flags */
+ NULL, NULL, /* lockfunc, lockarg */
+ &sc->mpr_parent_dmat)) {
+ mpr_printf(sc, "Cannot allocate parent DMA tag\n");
+ mpr_pci_free(sc);
+ return (ENOMEM);
+ }
+
+ if ((error = mpr_attach(sc)) != 0)
+ mpr_pci_free(sc);
+
+ return (error);
+}
+
+int
+mpr_pci_setup_interrupts(struct mpr_softc *sc)
+{
+ device_t dev;
+ int i, error, msgs;
+
+ dev = sc->mpr_dev;
+ error = ENXIO;
+ if ((sc->disable_msix == 0) &&
+ ((msgs = pci_msix_count(dev)) >= MPR_MSI_COUNT))
+ error = mpr_alloc_msix(sc, MPR_MSI_COUNT);
+ if ((error != 0) && (sc->disable_msi == 0) &&
+ ((msgs = pci_msi_count(dev)) >= MPR_MSI_COUNT))
+ error = mpr_alloc_msi(sc, MPR_MSI_COUNT);
+
+ if (error != 0) {
+ sc->mpr_flags |= MPR_FLAGS_INTX;
+ sc->mpr_irq_rid[0] = 0;
+ sc->mpr_irq[0] = bus_alloc_resource_any(dev, SYS_RES_IRQ,
+ &sc->mpr_irq_rid[0], RF_SHAREABLE | RF_ACTIVE);
+ if (sc->mpr_irq[0] == NULL) {
+ mpr_printf(sc, "Cannot allocate INTx interrupt\n");
+ return (ENXIO);
+ }
+ error = bus_setup_intr(dev, sc->mpr_irq[0],
+ INTR_TYPE_BIO | INTR_MPSAFE, NULL, mpr_intr, sc,
+ &sc->mpr_intrhand[0]);
+ if (error)
+ mpr_printf(sc, "Cannot setup INTx interrupt\n");
+ } else {
+ sc->mpr_flags |= MPR_FLAGS_MSI;
+ for (i = 0; i < MPR_MSI_COUNT; i++) {
+ sc->mpr_irq_rid[i] = i + 1;
+ sc->mpr_irq[i] = bus_alloc_resource_any(dev,
+ SYS_RES_IRQ, &sc->mpr_irq_rid[i], RF_ACTIVE);
+ if (sc->mpr_irq[i] == NULL) {
+ mpr_printf(sc,
+ "Cannot allocate MSI interrupt\n");
+ return (ENXIO);
+ }
+ error = bus_setup_intr(dev, sc->mpr_irq[i],
+ INTR_TYPE_BIO | INTR_MPSAFE, NULL, mpr_intr_msi,
+ sc, &sc->mpr_intrhand[i]);
+ if (error) {
+ mpr_printf(sc,
+ "Cannot setup MSI interrupt %d\n", i);
+ break;
+ }
+ }
+ }
+
+ return (error);
+}
+
+static int
+mpr_pci_detach(device_t dev)
+{
+ struct mpr_softc *sc;
+ int error;
+
+ sc = device_get_softc(dev);
+
+ if ((error = mpr_free(sc)) != 0)
+ return (error);
+
+ mpr_pci_free(sc);
+ return (0);
+}
+
+static void
+mpr_pci_free(struct mpr_softc *sc)
+{
+ int i;
+
+ if (sc->mpr_parent_dmat != NULL) {
+ bus_dma_tag_destroy(sc->mpr_parent_dmat);
+ }
+
+ if (sc->mpr_flags & MPR_FLAGS_MSI) {
+ for (i = 0; i < MPR_MSI_COUNT; i++) {
+ if (sc->mpr_irq[i] != NULL) {
+ bus_teardown_intr(sc->mpr_dev, sc->mpr_irq[i],
+ sc->mpr_intrhand[i]);
+ bus_release_resource(sc->mpr_dev, SYS_RES_IRQ,
+ sc->mpr_irq_rid[i], sc->mpr_irq[i]);
+ }
+ }
+ pci_release_msi(sc->mpr_dev);
+ }
+
+ if (sc->mpr_flags & MPR_FLAGS_INTX) {
+ bus_teardown_intr(sc->mpr_dev, sc->mpr_irq[0],
+ sc->mpr_intrhand[0]);
+ bus_release_resource(sc->mpr_dev, SYS_RES_IRQ,
+ sc->mpr_irq_rid[0], sc->mpr_irq[0]);
+ }
+
+ if (sc->mpr_regs_resource != NULL) {
+ bus_release_resource(sc->mpr_dev, SYS_RES_MEMORY,
+ sc->mpr_regs_rid, sc->mpr_regs_resource);
+ }
+
+ return;
+}
+
+static int
+mpr_pci_suspend(device_t dev)
+{
+ return (EINVAL);
+}
+
+static int
+mpr_pci_resume(device_t dev)
+{
+ return (EINVAL);
+}
+
+static int
+mpr_alloc_msix(struct mpr_softc *sc, int msgs)
+{
+ int error;
+
+ error = pci_alloc_msix(sc->mpr_dev, &msgs);
+ return (error);
+}
+
+static int
+mpr_alloc_msi(struct mpr_softc *sc, int msgs)
+{
+ int error;
+
+ error = pci_alloc_msi(sc->mpr_dev, &msgs);
+ return (error);
+}
+
+int
+mpr_pci_restore(struct mpr_softc *sc)
+{
+ struct pci_devinfo *dinfo;
+
+ mpr_dprint(sc, MPR_TRACE, "%s\n", __func__);
+
+ dinfo = device_get_ivars(sc->mpr_dev);
+ if (dinfo == NULL) {
+ mpr_dprint(sc, MPR_FAULT, "%s: NULL dinfo\n", __func__);
+ return (EINVAL);
+ }
+
+ pci_cfg_restore(sc->mpr_dev, dinfo);
+ return (0);
+}
+
diff --git a/sys/dev/mpr/mpr_sas.c b/sys/dev/mpr/mpr_sas.c
new file mode 100644
index 0000000..55bde0e
--- /dev/null
+++ b/sys/dev/mpr/mpr_sas.c
@@ -0,0 +1,3413 @@
+/*-
+ * Copyright (c) 2009 Yahoo! Inc.
+ * Copyright (c) 2011-2014 LSI Corp.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+/* Communications core for LSI MPT2 */
+
+/* TODO Move headers to mprvar */
+#include <sys/types.h>
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/kernel.h>
+#include <sys/selinfo.h>
+#include <sys/module.h>
+#include <sys/bus.h>
+#include <sys/conf.h>
+#include <sys/bio.h>
+#include <sys/malloc.h>
+#include <sys/uio.h>
+#include <sys/sysctl.h>
+#include <sys/endian.h>
+#include <sys/queue.h>
+#include <sys/kthread.h>
+#include <sys/taskqueue.h>
+#include <sys/sbuf.h>
+
+#include <machine/bus.h>
+#include <machine/resource.h>
+#include <sys/rman.h>
+
+#include <machine/stdarg.h>
+
+#include <cam/cam.h>
+#include <cam/cam_ccb.h>
+#include <cam/cam_debug.h>
+#include <cam/cam_sim.h>
+#include <cam/cam_xpt_sim.h>
+#include <cam/cam_xpt_periph.h>
+#include <cam/cam_periph.h>
+#include <cam/scsi/scsi_all.h>
+#include <cam/scsi/scsi_message.h>
+#if __FreeBSD_version >= 900026
+#include <cam/scsi/smp_all.h>
+#endif
+
+#include <dev/mpr/mpi/mpi2_type.h>
+#include <dev/mpr/mpi/mpi2.h>
+#include <dev/mpr/mpi/mpi2_ioc.h>
+#include <dev/mpr/mpi/mpi2_sas.h>
+#include <dev/mpr/mpi/mpi2_cnfg.h>
+#include <dev/mpr/mpi/mpi2_init.h>
+#include <dev/mpr/mpi/mpi2_tool.h>
+#include <dev/mpr/mpr_ioctl.h>
+#include <dev/mpr/mprvar.h>
+#include <dev/mpr/mpr_table.h>
+#include <dev/mpr/mpr_sas.h>
+
+#define MPRSAS_DISCOVERY_TIMEOUT 20
+#define MPRSAS_MAX_DISCOVERY_TIMEOUTS 10 /* 200 seconds */
+
+/*
+ * static array to check SCSI OpCode for EEDP protection bits
+ */
+#define PRO_R MPI2_SCSIIO_EEDPFLAGS_CHECK_REMOVE_OP
+#define PRO_W MPI2_SCSIIO_EEDPFLAGS_INSERT_OP
+#define PRO_V MPI2_SCSIIO_EEDPFLAGS_INSERT_OP
+static uint8_t op_code_prot[256] = {
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, PRO_R, 0, PRO_W, 0, 0, 0, PRO_W, PRO_V,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, PRO_W, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, PRO_R, 0, PRO_W, 0, 0, 0, PRO_W, PRO_V,
+ 0, 0, 0, PRO_W, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, PRO_R, 0, PRO_W, 0, 0, 0, PRO_W, PRO_V,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
+};
+
+MALLOC_DEFINE(M_MPRSAS, "MPRSAS", "MPR SAS memory");
+
+static void mprsas_remove_device(struct mpr_softc *, struct mpr_command *);
+static void mprsas_remove_complete(struct mpr_softc *, struct mpr_command *);
+static void mprsas_action(struct cam_sim *sim, union ccb *ccb);
+static void mprsas_poll(struct cam_sim *sim);
+static void mprsas_scsiio_timeout(void *data);
+static void mprsas_abort_complete(struct mpr_softc *sc,
+ struct mpr_command *cm);
+static void mprsas_action_scsiio(struct mprsas_softc *, union ccb *);
+static void mprsas_scsiio_complete(struct mpr_softc *, struct mpr_command *);
+static void mprsas_action_resetdev(struct mprsas_softc *, union ccb *);
+static void mprsas_resetdev_complete(struct mpr_softc *,
+ struct mpr_command *);
+static int mprsas_send_abort(struct mpr_softc *sc, struct mpr_command *tm,
+ struct mpr_command *cm);
+static int mprsas_send_reset(struct mpr_softc *sc, struct mpr_command *tm,
+ uint8_t type);
+static void mprsas_async(void *callback_arg, uint32_t code,
+ struct cam_path *path, void *arg);
+static void mprsas_prepare_ssu(struct mpr_softc *sc, struct cam_path *path,
+ struct ccb_getdev *cgd);
+#if (__FreeBSD_version < 901503) || \
+ ((__FreeBSD_version >= 1000000) && (__FreeBSD_version < 1000006))
+static void mprsas_check_eedp(struct mpr_softc *sc, struct cam_path *path,
+ struct ccb_getdev *cgd);
+static void mprsas_read_cap_done(struct cam_periph *periph,
+ union ccb *done_ccb);
+#endif
+static int mprsas_send_portenable(struct mpr_softc *sc);
+static void mprsas_portenable_complete(struct mpr_softc *sc,
+ struct mpr_command *cm);
+
+#if __FreeBSD_version >= 900026
+static void
+mprsas_smpio_complete(struct mpr_softc *sc, struct mpr_command *cm);
+static void mprsas_send_smpcmd(struct mprsas_softc *sassc,
+ union ccb *ccb, uint64_t sasaddr);
+static void
+mprsas_action_smpio(struct mprsas_softc *sassc, union ccb *ccb);
+#endif
+
+struct mprsas_target *
+mprsas_find_target_by_handle(struct mprsas_softc *sassc, int start,
+ uint16_t handle)
+{
+ struct mprsas_target *target;
+ int i;
+
+ for (i = start; i < sassc->maxtargets; i++) {
+ target = &sassc->targets[i];
+ if (target->handle == handle)
+ return (target);
+ }
+
+ return (NULL);
+}
+
+/* we need to freeze the simq during attach and diag reset, to avoid failing
+ * commands before device handles have been found by discovery. Since
+ * discovery involves reading config pages and possibly sending commands,
+ * discovery actions may continue even after we receive the end of discovery
+ * event, so refcount discovery actions instead of assuming we can unfreeze
+ * the simq when we get the event.
+ */
+void
+mprsas_startup_increment(struct mprsas_softc *sassc)
+{
+ MPR_FUNCTRACE(sassc->sc);
+
+ if ((sassc->flags & MPRSAS_IN_STARTUP) != 0) {
+ if (sassc->startup_refcount++ == 0) {
+ /* just starting, freeze the simq */
+ mpr_dprint(sassc->sc, MPR_INIT,
+ "%s freezing simq\n", __func__);
+#if __FreeBSD_version >= 1000039
+ xpt_hold_boot();
+#endif
+ xpt_freeze_simq(sassc->sim, 1);
+ }
+ mpr_dprint(sassc->sc, MPR_INIT, "%s refcount %u\n", __func__,
+ sassc->startup_refcount);
+ }
+}
+
+void
+mprsas_release_simq_reinit(struct mprsas_softc *sassc)
+{
+ if (sassc->flags & MPRSAS_QUEUE_FROZEN) {
+ sassc->flags &= ~MPRSAS_QUEUE_FROZEN;
+ xpt_release_simq(sassc->sim, 1);
+ mpr_dprint(sassc->sc, MPR_INFO, "Unfreezing SIM queue\n");
+ }
+}
+
+void
+mprsas_startup_decrement(struct mprsas_softc *sassc)
+{
+ MPR_FUNCTRACE(sassc->sc);
+
+ if ((sassc->flags & MPRSAS_IN_STARTUP) != 0) {
+ if (--sassc->startup_refcount == 0) {
+ /* finished all discovery-related actions, release
+ * the simq and rescan for the latest topology.
+ */
+ mpr_dprint(sassc->sc, MPR_INIT,
+ "%s releasing simq\n", __func__);
+ sassc->flags &= ~MPRSAS_IN_STARTUP;
+ xpt_release_simq(sassc->sim, 1);
+#if __FreeBSD_version >= 1000039
+ xpt_release_boot();
+#else
+ mprsas_rescan_target(sassc->sc, NULL);
+#endif
+ }
+ mpr_dprint(sassc->sc, MPR_INIT, "%s refcount %u\n", __func__,
+ sassc->startup_refcount);
+ }
+}
+
+/* LSI's firmware requires us to stop sending commands when we're doing task
+ * management, so refcount the TMs and keep the simq frozen when any are in
+ * use.
+ */
+struct mpr_command *
+mprsas_alloc_tm(struct mpr_softc *sc)
+{
+ struct mpr_command *tm;
+
+ MPR_FUNCTRACE(sc);
+ tm = mpr_alloc_high_priority_command(sc);
+ if (tm != NULL) {
+ if (sc->sassc->tm_count++ == 0) {
+ mpr_dprint(sc, MPR_RECOVERY,
+ "%s freezing simq\n", __func__);
+ xpt_freeze_simq(sc->sassc->sim, 1);
+ }
+ mpr_dprint(sc, MPR_RECOVERY, "%s tm_count %u\n", __func__,
+ sc->sassc->tm_count);
+ }
+ return tm;
+}
+
+void
+mprsas_free_tm(struct mpr_softc *sc, struct mpr_command *tm)
+{
+ mpr_dprint(sc, MPR_TRACE, "%s", __func__);
+ if (tm == NULL)
+ return;
+
+ /* if there are no TMs in use, we can release the simq. We use our
+ * own refcount so that it's easier for a diag reset to cleanup and
+ * release the simq.
+ */
+ if (--sc->sassc->tm_count == 0) {
+ mpr_dprint(sc, MPR_RECOVERY, "%s releasing simq\n", __func__);
+ xpt_release_simq(sc->sassc->sim, 1);
+ }
+ mpr_dprint(sc, MPR_RECOVERY, "%s tm_count %u\n", __func__,
+ sc->sassc->tm_count);
+
+ mpr_free_high_priority_command(sc, tm);
+}
+
+void
+mprsas_rescan_target(struct mpr_softc *sc, struct mprsas_target *targ)
+{
+ struct mprsas_softc *sassc = sc->sassc;
+ path_id_t pathid;
+ target_id_t targetid;
+ union ccb *ccb;
+
+ MPR_FUNCTRACE(sc);
+ pathid = cam_sim_path(sassc->sim);
+ if (targ == NULL)
+ targetid = CAM_TARGET_WILDCARD;
+ else
+ targetid = targ - sassc->targets;
+
+ /*
+ * Allocate a CCB and schedule a rescan.
+ */
+ ccb = xpt_alloc_ccb_nowait();
+ if (ccb == NULL) {
+ mpr_dprint(sc, MPR_ERROR, "unable to alloc CCB for rescan\n");
+ return;
+ }
+
+ if (xpt_create_path(&ccb->ccb_h.path, NULL, pathid,
+ targetid, CAM_LUN_WILDCARD) != CAM_REQ_CMP) {
+ mpr_dprint(sc, MPR_ERROR, "unable to create path for rescan\n");
+ xpt_free_ccb(ccb);
+ return;
+ }
+
+ if (targetid == CAM_TARGET_WILDCARD)
+ ccb->ccb_h.func_code = XPT_SCAN_BUS;
+ else
+ ccb->ccb_h.func_code = XPT_SCAN_TGT;
+
+ mpr_dprint(sc, MPR_TRACE, "%s targetid %u\n", __func__, targetid);
+ xpt_rescan(ccb);
+}
+
+static void
+mprsas_log_command(struct mpr_command *cm, u_int level, const char *fmt, ...)
+{
+ struct sbuf sb;
+ va_list ap;
+ char str[192];
+ char path_str[64];
+
+ if (cm == NULL)
+ return;
+
+ /* No need to be in here if debugging isn't enabled */
+ if ((cm->cm_sc->mpr_debug & level) == 0)
+ return;
+
+ sbuf_new(&sb, str, sizeof(str), 0);
+
+ va_start(ap, fmt);
+
+ if (cm->cm_ccb != NULL) {
+ xpt_path_string(cm->cm_ccb->csio.ccb_h.path, path_str,
+ sizeof(path_str));
+ sbuf_cat(&sb, path_str);
+ if (cm->cm_ccb->ccb_h.func_code == XPT_SCSI_IO) {
+ scsi_command_string(&cm->cm_ccb->csio, &sb);
+ sbuf_printf(&sb, "length %d ",
+ cm->cm_ccb->csio.dxfer_len);
+ }
+ } else {
+ sbuf_printf(&sb, "(noperiph:%s%d:%u:%u:%u): ",
+ cam_sim_name(cm->cm_sc->sassc->sim),
+ cam_sim_unit(cm->cm_sc->sassc->sim),
+ cam_sim_bus(cm->cm_sc->sassc->sim),
+ cm->cm_targ ? cm->cm_targ->tid : 0xFFFFFFFF,
+ cm->cm_lun);
+ }
+
+ sbuf_printf(&sb, "SMID %u ", cm->cm_desc.Default.SMID);
+ sbuf_vprintf(&sb, fmt, ap);
+ sbuf_finish(&sb);
+ mpr_dprint_field(cm->cm_sc, level, "%s", sbuf_data(&sb));
+
+ va_end(ap);
+}
+
+static void
+mprsas_remove_volume(struct mpr_softc *sc, struct mpr_command *tm)
+{
+ MPI2_SCSI_TASK_MANAGE_REPLY *reply;
+ struct mprsas_target *targ;
+ uint16_t handle;
+
+ MPR_FUNCTRACE(sc);
+
+ reply = (MPI2_SCSI_TASK_MANAGE_REPLY *)tm->cm_reply;
+ handle = (uint16_t)(uintptr_t)tm->cm_complete_data;
+ targ = tm->cm_targ;
+
+ if (reply == NULL) {
+ /* XXX retry the remove after the diag reset completes? */
+ mpr_dprint(sc, MPR_FAULT, "%s NULL reply resetting device "
+ "0x%04x\n", __func__, handle);
+ mprsas_free_tm(sc, tm);
+ return;
+ }
+
+ if (reply->IOCStatus != MPI2_IOCSTATUS_SUCCESS) {
+ mpr_dprint(sc, MPR_FAULT, "IOCStatus = 0x%x while resetting "
+ "device 0x%x\n", reply->IOCStatus, handle);
+ mprsas_free_tm(sc, tm);
+ return;
+ }
+
+ mpr_dprint(sc, MPR_XINFO, "Reset aborted %u commands\n",
+ reply->TerminationCount);
+ mpr_free_reply(sc, tm->cm_reply_data);
+ tm->cm_reply = NULL; /* Ensures the reply won't get re-freed */
+
+ mpr_dprint(sc, MPR_XINFO, "clearing target %u handle 0x%04x\n",
+ targ->tid, handle);
+
+ /*
+ * Don't clear target if remove fails because things will get confusing.
+ * Leave the devname and sasaddr intact so that we know to avoid reusing
+ * this target id if possible, and so we can assign the same target id
+ * to this device if it comes back in the future.
+ */
+ if (reply->IOCStatus == MPI2_IOCSTATUS_SUCCESS) {
+ targ = tm->cm_targ;
+ targ->handle = 0x0;
+ targ->encl_handle = 0x0;
+ targ->encl_level_valid = 0x0;
+ targ->encl_level = 0x0;
+ targ->connector_name[0] = ' ';
+ targ->connector_name[1] = ' ';
+ targ->connector_name[2] = ' ';
+ targ->connector_name[3] = ' ';
+ targ->encl_slot = 0x0;
+ targ->exp_dev_handle = 0x0;
+ targ->phy_num = 0x0;
+ targ->linkrate = 0x0;
+ targ->devinfo = 0x0;
+ targ->flags = 0x0;
+ targ->scsi_req_desc_type = 0;
+ }
+
+ mprsas_free_tm(sc, tm);
+}
+
+
+/*
+ * No Need to call "MPI2_SAS_OP_REMOVE_DEVICE" For Volume removal.
+ * Otherwise Volume Delete is same as Bare Drive Removal.
+ */
+void
+mprsas_prepare_volume_remove(struct mprsas_softc *sassc, uint16_t handle)
+{
+ MPI2_SCSI_TASK_MANAGE_REQUEST *req;
+ struct mpr_softc *sc;
+ struct mpr_command *cm;
+ struct mprsas_target *targ = NULL;
+
+ MPR_FUNCTRACE(sassc->sc);
+ sc = sassc->sc;
+
+ targ = mprsas_find_target_by_handle(sassc, 0, handle);
+ if (targ == NULL) {
+ /* FIXME: what is the action? */
+ /* We don't know about this device? */
+ mpr_dprint(sc, MPR_ERROR,
+ "%s %d : invalid handle 0x%x \n", __func__,__LINE__, handle);
+ return;
+ }
+
+ targ->flags |= MPRSAS_TARGET_INREMOVAL;
+
+ cm = mprsas_alloc_tm(sc);
+ if (cm == NULL) {
+ mpr_dprint(sc, MPR_ERROR,
+ "%s: command alloc failure\n", __func__);
+ return;
+ }
+
+ mprsas_rescan_target(sc, targ);
+
+ req = (MPI2_SCSI_TASK_MANAGE_REQUEST *)cm->cm_req;
+ req->DevHandle = targ->handle;
+ req->Function = MPI2_FUNCTION_SCSI_TASK_MGMT;
+ req->TaskType = MPI2_SCSITASKMGMT_TASKTYPE_TARGET_RESET;
+
+ /* SAS Hard Link Reset / SATA Link Reset */
+ req->MsgFlags = MPI2_SCSITASKMGMT_MSGFLAGS_LINK_RESET;
+
+ cm->cm_targ = targ;
+ cm->cm_data = NULL;
+ cm->cm_desc.HighPriority.RequestFlags =
+ MPI2_REQ_DESCRIPT_FLAGS_HIGH_PRIORITY;
+ cm->cm_complete = mprsas_remove_volume;
+ cm->cm_complete_data = (void *)(uintptr_t)handle;
+ mpr_map_command(sc, cm);
+}
+
+/*
+ * The MPT2 firmware performs debounce on the link to avoid transient link
+ * errors and false removals. When it does decide that link has been lost
+ * and a device needs to go away, it expects that the host will perform a
+ * target reset and then an op remove. The reset has the side-effect of
+ * aborting any outstanding requests for the device, which is required for
+ * the op-remove to succeed. It's not clear if the host should check for
+ * the device coming back alive after the reset.
+ */
+void
+mprsas_prepare_remove(struct mprsas_softc *sassc, uint16_t handle)
+{
+ MPI2_SCSI_TASK_MANAGE_REQUEST *req;
+ struct mpr_softc *sc;
+ struct mpr_command *cm;
+ struct mprsas_target *targ = NULL;
+
+ MPR_FUNCTRACE(sassc->sc);
+
+ sc = sassc->sc;
+
+ targ = mprsas_find_target_by_handle(sassc, 0, handle);
+ if (targ == NULL) {
+ /* FIXME: what is the action? */
+ /* We don't know about this device? */
+ mpr_dprint(sc, MPR_ERROR, "%s : invalid handle 0x%x \n",
+ __func__, handle);
+ return;
+ }
+
+ targ->flags |= MPRSAS_TARGET_INREMOVAL;
+
+ cm = mprsas_alloc_tm(sc);
+ if (cm == NULL) {
+ mpr_dprint(sc, MPR_ERROR, "%s: command alloc failure\n",
+ __func__);
+ return;
+ }
+
+ mprsas_rescan_target(sc, targ);
+
+ req = (MPI2_SCSI_TASK_MANAGE_REQUEST *)cm->cm_req;
+ memset(req, 0, sizeof(*req));
+ req->DevHandle = htole16(targ->handle);
+ req->Function = MPI2_FUNCTION_SCSI_TASK_MGMT;
+ req->TaskType = MPI2_SCSITASKMGMT_TASKTYPE_TARGET_RESET;
+
+ /* SAS Hard Link Reset / SATA Link Reset */
+ req->MsgFlags = MPI2_SCSITASKMGMT_MSGFLAGS_LINK_RESET;
+
+ cm->cm_targ = targ;
+ cm->cm_data = NULL;
+ cm->cm_desc.HighPriority.RequestFlags =
+ MPI2_REQ_DESCRIPT_FLAGS_HIGH_PRIORITY;
+ cm->cm_complete = mprsas_remove_device;
+ cm->cm_complete_data = (void *)(uintptr_t)handle;
+ mpr_map_command(sc, cm);
+}
+
+static void
+mprsas_remove_device(struct mpr_softc *sc, struct mpr_command *tm)
+{
+ MPI2_SCSI_TASK_MANAGE_REPLY *reply;
+ MPI2_SAS_IOUNIT_CONTROL_REQUEST *req;
+ struct mprsas_target *targ;
+ struct mpr_command *next_cm;
+ uint16_t handle;
+
+ MPR_FUNCTRACE(sc);
+
+ reply = (MPI2_SCSI_TASK_MANAGE_REPLY *)tm->cm_reply;
+ handle = (uint16_t)(uintptr_t)tm->cm_complete_data;
+ targ = tm->cm_targ;
+
+ /*
+ * Currently there should be no way we can hit this case. It only
+ * happens when we have a failure to allocate chain frames, and
+ * task management commands don't have S/G lists.
+ */
+ if ((tm->cm_flags & MPR_CM_FLAGS_ERROR_MASK) != 0) {
+ mpr_dprint(sc, MPR_ERROR, "%s: cm_flags = %#x for remove of "
+ "handle %#04x! This should not happen!\n", __func__,
+ tm->cm_flags, handle);
+ mprsas_free_tm(sc, tm);
+ return;
+ }
+
+ if (reply == NULL) {
+ /* XXX retry the remove after the diag reset completes? */
+ mpr_dprint(sc, MPR_FAULT, "%s NULL reply resetting device "
+ "0x%04x\n", __func__, handle);
+ mprsas_free_tm(sc, tm);
+ return;
+ }
+
+ if (le16toh(reply->IOCStatus) != MPI2_IOCSTATUS_SUCCESS) {
+ mpr_dprint(sc, MPR_FAULT, "IOCStatus = 0x%x while resetting "
+ "device 0x%x\n", le16toh(reply->IOCStatus), handle);
+ mprsas_free_tm(sc, tm);
+ return;
+ }
+
+ mpr_dprint(sc, MPR_XINFO, "Reset aborted %u commands\n",
+ le32toh(reply->TerminationCount));
+ mpr_free_reply(sc, tm->cm_reply_data);
+ tm->cm_reply = NULL; /* Ensures the reply won't get re-freed */
+
+ /* Reuse the existing command */
+ req = (MPI2_SAS_IOUNIT_CONTROL_REQUEST *)tm->cm_req;
+ memset(req, 0, sizeof(*req));
+ req->Function = MPI2_FUNCTION_SAS_IO_UNIT_CONTROL;
+ req->Operation = MPI2_SAS_OP_REMOVE_DEVICE;
+ req->DevHandle = htole16(handle);
+ tm->cm_data = NULL;
+ tm->cm_desc.Default.RequestFlags = MPI2_REQ_DESCRIPT_FLAGS_DEFAULT_TYPE;
+ tm->cm_complete = mprsas_remove_complete;
+ tm->cm_complete_data = (void *)(uintptr_t)handle;
+
+ mpr_map_command(sc, tm);
+
+ mpr_dprint(sc, MPR_XINFO, "clearing target %u handle 0x%04x\n",
+ targ->tid, handle);
+ if (targ->encl_level_valid) {
+ mpr_dprint(sc, MPR_XINFO, "At enclosure level %d, slot %d, "
+ "connector name (%4s)\n", targ->encl_level, targ->encl_slot,
+ targ->connector_name);
+ }
+ TAILQ_FOREACH_SAFE(tm, &targ->commands, cm_link, next_cm) {
+ union ccb *ccb;
+
+ mpr_dprint(sc, MPR_XINFO, "Completing missed command %p\n", tm);
+ ccb = tm->cm_complete_data;
+ ccb->ccb_h.status = CAM_DEV_NOT_THERE;
+ mprsas_scsiio_complete(sc, tm);
+ }
+}
+
+static void
+mprsas_remove_complete(struct mpr_softc *sc, struct mpr_command *tm)
+{
+ MPI2_SAS_IOUNIT_CONTROL_REPLY *reply;
+ uint16_t handle;
+ struct mprsas_target *targ;
+ struct mprsas_lun *lun;
+
+ MPR_FUNCTRACE(sc);
+
+ reply = (MPI2_SAS_IOUNIT_CONTROL_REPLY *)tm->cm_reply;
+ handle = (uint16_t)(uintptr_t)tm->cm_complete_data;
+
+ /*
+ * Currently there should be no way we can hit this case. It only
+ * happens when we have a failure to allocate chain frames, and
+ * task management commands don't have S/G lists.
+ */
+ if ((tm->cm_flags & MPR_CM_FLAGS_ERROR_MASK) != 0) {
+ mpr_dprint(sc, MPR_XINFO, "%s: cm_flags = %#x for remove of "
+ "handle %#04x! This should not happen!\n", __func__,
+ tm->cm_flags, handle);
+ mprsas_free_tm(sc, tm);
+ return;
+ }
+
+ if (reply == NULL) {
+ /* most likely a chip reset */
+ mpr_dprint(sc, MPR_FAULT, "%s NULL reply removing device "
+ "0x%04x\n", __func__, handle);
+ mprsas_free_tm(sc, tm);
+ return;
+ }
+
+ mpr_dprint(sc, MPR_XINFO, "%s on handle 0x%04x, IOCStatus= 0x%x\n",
+ __func__, handle, le16toh(reply->IOCStatus));
+
+ /*
+ * Don't clear target if remove fails because things will get confusing.
+ * Leave the devname and sasaddr intact so that we know to avoid reusing
+ * this target id if possible, and so we can assign the same target id
+ * to this device if it comes back in the future.
+ */
+ if (le16toh(reply->IOCStatus) == MPI2_IOCSTATUS_SUCCESS) {
+ targ = tm->cm_targ;
+ targ->handle = 0x0;
+ targ->encl_handle = 0x0;
+ targ->encl_level_valid = 0x0;
+ targ->encl_level = 0x0;
+ targ->connector_name[0] = ' ';
+ targ->connector_name[1] = ' ';
+ targ->connector_name[2] = ' ';
+ targ->connector_name[3] = ' ';
+ targ->encl_slot = 0x0;
+ targ->exp_dev_handle = 0x0;
+ targ->phy_num = 0x0;
+ targ->linkrate = 0x0;
+ targ->devinfo = 0x0;
+ targ->flags = 0x0;
+ targ->scsi_req_desc_type = 0;
+
+ while (!SLIST_EMPTY(&targ->luns)) {
+ lun = SLIST_FIRST(&targ->luns);
+ SLIST_REMOVE_HEAD(&targ->luns, lun_link);
+ free(lun, M_MPR);
+ }
+ }
+
+ mprsas_free_tm(sc, tm);
+}
+
+static int
+mprsas_register_events(struct mpr_softc *sc)
+{
+ uint8_t events[16];
+
+ bzero(events, 16);
+ setbit(events, MPI2_EVENT_SAS_DEVICE_STATUS_CHANGE);
+ setbit(events, MPI2_EVENT_SAS_DISCOVERY);
+ setbit(events, MPI2_EVENT_SAS_BROADCAST_PRIMITIVE);
+ setbit(events, MPI2_EVENT_SAS_INIT_DEVICE_STATUS_CHANGE);
+ setbit(events, MPI2_EVENT_SAS_INIT_TABLE_OVERFLOW);
+ setbit(events, MPI2_EVENT_SAS_TOPOLOGY_CHANGE_LIST);
+ setbit(events, MPI2_EVENT_SAS_ENCL_DEVICE_STATUS_CHANGE);
+ setbit(events, MPI2_EVENT_IR_CONFIGURATION_CHANGE_LIST);
+ setbit(events, MPI2_EVENT_IR_VOLUME);
+ setbit(events, MPI2_EVENT_IR_PHYSICAL_DISK);
+ setbit(events, MPI2_EVENT_IR_OPERATION_STATUS);
+ setbit(events, MPI2_EVENT_TEMP_THRESHOLD);
+
+ mpr_register_events(sc, events, mprsas_evt_handler, NULL,
+ &sc->sassc->mprsas_eh);
+
+ return (0);
+}
+
+int
+mpr_attach_sas(struct mpr_softc *sc)
+{
+ struct mprsas_softc *sassc;
+ cam_status status;
+ int unit, error = 0;
+
+ MPR_FUNCTRACE(sc);
+
+ sassc = malloc(sizeof(struct mprsas_softc), M_MPR, M_WAITOK|M_ZERO);
+ if (!sassc) {
+ device_printf(sc->mpr_dev, "Cannot allocate memory %s %d\n",
+ __func__, __LINE__);
+ return (ENOMEM);
+ }
+
+ /*
+ * XXX MaxTargets could change during a reinit. since we don't
+ * resize the targets[] array during such an event, cache the value
+ * of MaxTargets here so that we don't get into trouble later. This
+ * should move into the reinit logic.
+ */
+ sassc->maxtargets = sc->facts->MaxTargets;
+ sassc->targets = malloc(sizeof(struct mprsas_target) *
+ sassc->maxtargets, M_MPR, M_WAITOK|M_ZERO);
+ if (!sassc->targets) {
+ device_printf(sc->mpr_dev, "Cannot allocate memory %s %d\n",
+ __func__, __LINE__);
+ free(sassc, M_MPR);
+ return (ENOMEM);
+ }
+ sc->sassc = sassc;
+ sassc->sc = sc;
+
+ if ((sassc->devq = cam_simq_alloc(sc->num_reqs)) == NULL) {
+ mpr_dprint(sc, MPR_ERROR, "Cannot allocate SIMQ\n");
+ error = ENOMEM;
+ goto out;
+ }
+
+ unit = device_get_unit(sc->mpr_dev);
+ sassc->sim = cam_sim_alloc(mprsas_action, mprsas_poll, "mpr", sassc,
+ unit, &sc->mpr_mtx, sc->num_reqs, sc->num_reqs, sassc->devq);
+ if (sassc->sim == NULL) {
+ mpr_dprint(sc, MPR_ERROR, "Cannot allocate SIM\n");
+ error = EINVAL;
+ goto out;
+ }
+
+ TAILQ_INIT(&sassc->ev_queue);
+
+ /* Initialize taskqueue for Event Handling */
+ TASK_INIT(&sassc->ev_task, 0, mprsas_firmware_event_work, sc);
+ sassc->ev_tq = taskqueue_create("mpr_taskq", M_NOWAIT | M_ZERO,
+ taskqueue_thread_enqueue, &sassc->ev_tq);
+
+ /* Run the task queue with lowest priority */
+ taskqueue_start_threads(&sassc->ev_tq, 1, 255, "%s taskq",
+ device_get_nameunit(sc->mpr_dev));
+
+ mpr_lock(sc);
+
+ /*
+ * XXX There should be a bus for every port on the adapter, but since
+ * we're just going to fake the topology for now, we'll pretend that
+ * everything is just a target on a single bus.
+ */
+ if ((error = xpt_bus_register(sassc->sim, sc->mpr_dev, 0)) != 0) {
+ mpr_dprint(sc, MPR_ERROR, "Error %d registering SCSI bus\n",
+ error);
+ mpr_unlock(sc);
+ goto out;
+ }
+
+ /*
+ * Assume that discovery events will start right away. Freezing
+ *
+ * Hold off boot until discovery is complete.
+ */
+ sassc->flags |= MPRSAS_IN_STARTUP | MPRSAS_IN_DISCOVERY;
+ sc->sassc->startup_refcount = 0;
+ mprsas_startup_increment(sassc);
+
+ callout_init(&sassc->discovery_callout, 1 /*mprafe*/);
+
+ sassc->tm_count = 0;
+
+ /*
+ * Register for async events so we can determine the EEDP
+ * capabilities of devices.
+ */
+ status = xpt_create_path(&sassc->path, /*periph*/NULL,
+ cam_sim_path(sc->sassc->sim), CAM_TARGET_WILDCARD,
+ CAM_LUN_WILDCARD);
+ if (status != CAM_REQ_CMP) {
+ mpr_printf(sc, "Error %#x creating sim path\n", status);
+ sassc->path = NULL;
+ } else {
+ int event;
+
+#if (__FreeBSD_version >= 1000006) || \
+ ((__FreeBSD_version >= 901503) && (__FreeBSD_version < 1000000))
+ event = AC_ADVINFO_CHANGED | AC_FOUND_DEVICE;
+#else
+ event = AC_FOUND_DEVICE;
+#endif
+ status = xpt_register_async(event, mprsas_async, sc,
+ sassc->path);
+ if (status != CAM_REQ_CMP) {
+ mpr_dprint(sc, MPR_ERROR,
+ "Error %#x registering async handler for "
+ "AC_ADVINFO_CHANGED events\n", status);
+ xpt_free_path(sassc->path);
+ sassc->path = NULL;
+ }
+ }
+ if (status != CAM_REQ_CMP) {
+ /*
+ * EEDP use is the exception, not the rule.
+ * Warn the user, but do not fail to attach.
+ */
+ mpr_printf(sc, "EEDP capabilities disabled.\n");
+ }
+
+ mpr_unlock(sc);
+
+ mprsas_register_events(sc);
+out:
+ if (error)
+ mpr_detach_sas(sc);
+ return (error);
+}
+
+int
+mpr_detach_sas(struct mpr_softc *sc)
+{
+ struct mprsas_softc *sassc;
+ struct mprsas_lun *lun, *lun_tmp;
+ struct mprsas_target *targ;
+ int i;
+
+ MPR_FUNCTRACE(sc);
+
+ if (sc->sassc == NULL)
+ return (0);
+
+ sassc = sc->sassc;
+ mpr_deregister_events(sc, sassc->mprsas_eh);
+
+ /*
+ * Drain and free the event handling taskqueue with the lock
+ * unheld so that any parallel processing tasks drain properly
+ * without deadlocking.
+ */
+ if (sassc->ev_tq != NULL)
+ taskqueue_free(sassc->ev_tq);
+
+ /* Make sure CAM doesn't wedge if we had to bail out early. */
+ mpr_lock(sc);
+
+ /* Deregister our async handler */
+ if (sassc->path != NULL) {
+ xpt_register_async(0, mprsas_async, sc, sassc->path);
+ xpt_free_path(sassc->path);
+ sassc->path = NULL;
+ }
+
+ if (sassc->flags & MPRSAS_IN_STARTUP)
+ xpt_release_simq(sassc->sim, 1);
+
+ if (sassc->sim != NULL) {
+ xpt_bus_deregister(cam_sim_path(sassc->sim));
+ cam_sim_free(sassc->sim, FALSE);
+ }
+
+ sassc->flags |= MPRSAS_SHUTDOWN;
+ mpr_unlock(sc);
+
+ if (sassc->devq != NULL)
+ cam_simq_free(sassc->devq);
+
+ for (i = 0; i < sassc->maxtargets; i++) {
+ targ = &sassc->targets[i];
+ SLIST_FOREACH_SAFE(lun, &targ->luns, lun_link, lun_tmp) {
+ free(lun, M_MPR);
+ }
+ }
+ free(sassc->targets, M_MPR);
+ free(sassc, M_MPR);
+ sc->sassc = NULL;
+
+ return (0);
+}
+
+void
+mprsas_discovery_end(struct mprsas_softc *sassc)
+{
+ struct mpr_softc *sc = sassc->sc;
+
+ MPR_FUNCTRACE(sc);
+
+ if (sassc->flags & MPRSAS_DISCOVERY_TIMEOUT_PENDING)
+ callout_stop(&sassc->discovery_callout);
+
+}
+
+static void
+mprsas_action(struct cam_sim *sim, union ccb *ccb)
+{
+ struct mprsas_softc *sassc;
+
+ sassc = cam_sim_softc(sim);
+
+ MPR_FUNCTRACE(sassc->sc);
+ mpr_dprint(sassc->sc, MPR_TRACE, "%s func 0x%x\n", __func__,
+ ccb->ccb_h.func_code);
+ mtx_assert(&sassc->sc->mpr_mtx, MA_OWNED);
+
+ switch (ccb->ccb_h.func_code) {
+ case XPT_PATH_INQ:
+ {
+ struct ccb_pathinq *cpi = &ccb->cpi;
+
+ cpi->version_num = 1;
+ cpi->hba_inquiry = PI_SDTR_ABLE|PI_TAG_ABLE|PI_WIDE_16;
+ cpi->target_sprt = 0;
+#if __FreeBSD_version >= 1000039
+ cpi->hba_misc = PIM_NOBUSRESET | PIM_UNMAPPED | PIM_NOSCAN;
+#else
+ cpi->hba_misc = PIM_NOBUSRESET | PIM_UNMAPPED;
+#endif
+ cpi->hba_eng_cnt = 0;
+ cpi->max_target = sassc->maxtargets - 1;
+ cpi->max_lun = 255;
+ cpi->initiator_id = sassc->maxtargets - 1;
+ strncpy(cpi->sim_vid, "FreeBSD", SIM_IDLEN);
+ strncpy(cpi->hba_vid, "LSILogic", HBA_IDLEN);
+ strncpy(cpi->dev_name, cam_sim_name(sim), DEV_IDLEN);
+ cpi->unit_number = cam_sim_unit(sim);
+ cpi->bus_id = cam_sim_bus(sim);
+ /*
+ * XXXSLM-I think this needs to change based on config page or
+ * something instead of hardcoded to 150000.
+ */
+ cpi->base_transfer_speed = 150000;
+ cpi->transport = XPORT_SAS;
+ cpi->transport_version = 0;
+ cpi->protocol = PROTO_SCSI;
+ cpi->protocol_version = SCSI_REV_SPC;
+#if __FreeBSD_version >= 800001
+ /*
+ * XXXSLM-probably need to base this number on max SGL's and
+ * page size.
+ */
+ cpi->maxio = 256 * 1024;
+#endif
+ cpi->ccb_h.status = CAM_REQ_CMP;
+ break;
+ }
+ case XPT_GET_TRAN_SETTINGS:
+ {
+ struct ccb_trans_settings *cts;
+ struct ccb_trans_settings_sas *sas;
+ struct ccb_trans_settings_scsi *scsi;
+ struct mprsas_target *targ;
+
+ cts = &ccb->cts;
+ sas = &cts->xport_specific.sas;
+ scsi = &cts->proto_specific.scsi;
+
+ KASSERT(cts->ccb_h.target_id < sassc->maxtargets,
+ ("Target %d out of bounds in XPT_GET_TRAN_SETTINGS\n",
+ cts->ccb_h.target_id));
+ targ = &sassc->targets[cts->ccb_h.target_id];
+ if (targ->handle == 0x0) {
+ cts->ccb_h.status = CAM_DEV_NOT_THERE;
+ break;
+ }
+
+ cts->protocol_version = SCSI_REV_SPC2;
+ cts->transport = XPORT_SAS;
+ cts->transport_version = 0;
+
+ sas->valid = CTS_SAS_VALID_SPEED;
+ switch (targ->linkrate) {
+ case 0x08:
+ sas->bitrate = 150000;
+ break;
+ case 0x09:
+ sas->bitrate = 300000;
+ break;
+ case 0x0a:
+ sas->bitrate = 600000;
+ break;
+ default:
+ sas->valid = 0;
+ }
+
+ cts->protocol = PROTO_SCSI;
+ scsi->valid = CTS_SCSI_VALID_TQ;
+ scsi->flags = CTS_SCSI_FLAGS_TAG_ENB;
+
+ cts->ccb_h.status = CAM_REQ_CMP;
+ break;
+ }
+ case XPT_CALC_GEOMETRY:
+ cam_calc_geometry(&ccb->ccg, /*extended*/1);
+ ccb->ccb_h.status = CAM_REQ_CMP;
+ break;
+ case XPT_RESET_DEV:
+ mpr_dprint(sassc->sc, MPR_XINFO,
+ "mprsas_action XPT_RESET_DEV\n");
+ mprsas_action_resetdev(sassc, ccb);
+ return;
+ case XPT_RESET_BUS:
+ case XPT_ABORT:
+ case XPT_TERM_IO:
+ mpr_dprint(sassc->sc, MPR_XINFO,
+ "mprsas_action faking success for abort or reset\n");
+ ccb->ccb_h.status = CAM_REQ_CMP;
+ break;
+ case XPT_SCSI_IO:
+ mprsas_action_scsiio(sassc, ccb);
+ return;
+#if __FreeBSD_version >= 900026
+ case XPT_SMP_IO:
+ mprsas_action_smpio(sassc, ccb);
+ return;
+#endif
+ default:
+ ccb->ccb_h.status = CAM_FUNC_NOTAVAIL;
+ break;
+ }
+ xpt_done(ccb);
+
+}
+
+static void
+mprsas_announce_reset(struct mpr_softc *sc, uint32_t ac_code,
+ target_id_t target_id, lun_id_t lun_id)
+{
+ path_id_t path_id = cam_sim_path(sc->sassc->sim);
+ struct cam_path *path;
+
+ mpr_dprint(sc, MPR_XINFO, "%s code %x target %d lun %jx\n", __func__,
+ ac_code, target_id, (uintmax_t)lun_id);
+
+ if (xpt_create_path(&path, NULL,
+ path_id, target_id, lun_id) != CAM_REQ_CMP) {
+ mpr_dprint(sc, MPR_ERROR, "unable to create path for reset "
+ "notification\n");
+ return;
+ }
+
+ xpt_async(ac_code, path, NULL);
+ xpt_free_path(path);
+}
+
+static void
+mprsas_complete_all_commands(struct mpr_softc *sc)
+{
+ struct mpr_command *cm;
+ int i;
+ int completed;
+
+ MPR_FUNCTRACE(sc);
+ mtx_assert(&sc->mpr_mtx, MA_OWNED);
+
+ /* complete all commands with a NULL reply */
+ for (i = 1; i < sc->num_reqs; i++) {
+ cm = &sc->commands[i];
+ cm->cm_reply = NULL;
+ completed = 0;
+
+ if (cm->cm_flags & MPR_CM_FLAGS_POLLED)
+ cm->cm_flags |= MPR_CM_FLAGS_COMPLETE;
+
+ if (cm->cm_complete != NULL) {
+ mprsas_log_command(cm, MPR_RECOVERY,
+ "completing cm %p state %x ccb %p for diag reset\n",
+ cm, cm->cm_state, cm->cm_ccb);
+ cm->cm_complete(sc, cm);
+ completed = 1;
+ }
+
+ if (cm->cm_flags & MPR_CM_FLAGS_WAKEUP) {
+ mprsas_log_command(cm, MPR_RECOVERY,
+ "waking up cm %p state %x ccb %p for diag reset\n",
+ cm, cm->cm_state, cm->cm_ccb);
+ wakeup(cm);
+ completed = 1;
+ }
+
+ if ((completed == 0) && (cm->cm_state != MPR_CM_STATE_FREE)) {
+ /* this should never happen, but if it does, log */
+ mprsas_log_command(cm, MPR_RECOVERY,
+ "cm %p state %x flags 0x%x ccb %p during diag "
+ "reset\n", cm, cm->cm_state, cm->cm_flags,
+ cm->cm_ccb);
+ }
+ }
+}
+
+void
+mprsas_handle_reinit(struct mpr_softc *sc)
+{
+ int i;
+
+ /* Go back into startup mode and freeze the simq, so that CAM
+ * doesn't send any commands until after we've rediscovered all
+ * targets and found the proper device handles for them.
+ *
+ * After the reset, portenable will trigger discovery, and after all
+ * discovery-related activities have finished, the simq will be
+ * released.
+ */
+ mpr_dprint(sc, MPR_INIT, "%s startup\n", __func__);
+ sc->sassc->flags |= MPRSAS_IN_STARTUP;
+ sc->sassc->flags |= MPRSAS_IN_DISCOVERY;
+ mprsas_startup_increment(sc->sassc);
+
+ /* notify CAM of a bus reset */
+ mprsas_announce_reset(sc, AC_BUS_RESET, CAM_TARGET_WILDCARD,
+ CAM_LUN_WILDCARD);
+
+ /* complete and cleanup after all outstanding commands */
+ mprsas_complete_all_commands(sc);
+
+ mpr_dprint(sc, MPR_INIT, "%s startup %u tm %u after command "
+ "completion\n", __func__, sc->sassc->startup_refcount,
+ sc->sassc->tm_count);
+
+ /* zero all the target handles, since they may change after the
+ * reset, and we have to rediscover all the targets and use the new
+ * handles.
+ */
+ for (i = 0; i < sc->sassc->maxtargets; i++) {
+ if (sc->sassc->targets[i].outstanding != 0)
+ mpr_dprint(sc, MPR_INIT, "target %u outstanding %u\n",
+ i, sc->sassc->targets[i].outstanding);
+ sc->sassc->targets[i].handle = 0x0;
+ sc->sassc->targets[i].exp_dev_handle = 0x0;
+ sc->sassc->targets[i].outstanding = 0;
+ sc->sassc->targets[i].flags = MPRSAS_TARGET_INDIAGRESET;
+ }
+}
+static void
+mprsas_tm_timeout(void *data)
+{
+ struct mpr_command *tm = data;
+ struct mpr_softc *sc = tm->cm_sc;
+
+ mtx_assert(&sc->mpr_mtx, MA_OWNED);
+
+ mprsas_log_command(tm, MPR_INFO|MPR_RECOVERY,
+ "task mgmt %p timed out\n", tm);
+ mpr_reinit(sc);
+}
+
+static void
+mprsas_logical_unit_reset_complete(struct mpr_softc *sc,
+ struct mpr_command *tm)
+{
+ MPI2_SCSI_TASK_MANAGE_REPLY *reply;
+ MPI2_SCSI_TASK_MANAGE_REQUEST *req;
+ unsigned int cm_count = 0;
+ struct mpr_command *cm;
+ struct mprsas_target *targ;
+
+ callout_stop(&tm->cm_callout);
+
+ req = (MPI2_SCSI_TASK_MANAGE_REQUEST *)tm->cm_req;
+ reply = (MPI2_SCSI_TASK_MANAGE_REPLY *)tm->cm_reply;
+ targ = tm->cm_targ;
+
+ /*
+ * Currently there should be no way we can hit this case. It only
+ * happens when we have a failure to allocate chain frames, and
+ * task management commands don't have S/G lists.
+ */
+ if ((tm->cm_flags & MPR_CM_FLAGS_ERROR_MASK) != 0) {
+ mpr_dprint(sc, MPR_ERROR, "%s: cm_flags = %#x for LUN reset! "
+ "This should not happen!\n", __func__, tm->cm_flags);
+ mprsas_free_tm(sc, tm);
+ return;
+ }
+
+ if (reply == NULL) {
+ mprsas_log_command(tm, MPR_RECOVERY,
+ "NULL reset reply for tm %p\n", tm);
+ if ((sc->mpr_flags & MPR_FLAGS_DIAGRESET) != 0) {
+ /* this completion was due to a reset, just cleanup */
+ targ->flags &= ~MPRSAS_TARGET_INRESET;
+ targ->tm = NULL;
+ mprsas_free_tm(sc, tm);
+ }
+ else {
+ /* we should have gotten a reply. */
+ mpr_reinit(sc);
+ }
+ return;
+ }
+
+ mprsas_log_command(tm, MPR_RECOVERY,
+ "logical unit reset status 0x%x code 0x%x count %u\n",
+ le16toh(reply->IOCStatus), le32toh(reply->ResponseCode),
+ le32toh(reply->TerminationCount));
+
+ /* See if there are any outstanding commands for this LUN.
+ * This could be made more efficient by using a per-LU data
+ * structure of some sort.
+ */
+ TAILQ_FOREACH(cm, &targ->commands, cm_link) {
+ if (cm->cm_lun == tm->cm_lun)
+ cm_count++;
+ }
+
+ if (cm_count == 0) {
+ mprsas_log_command(tm, MPR_RECOVERY|MPR_INFO,
+ "logical unit %u finished recovery after reset\n",
+ tm->cm_lun, tm);
+
+ mprsas_announce_reset(sc, AC_SENT_BDR, tm->cm_targ->tid,
+ tm->cm_lun);
+
+ /* we've finished recovery for this logical unit. check and
+ * see if some other logical unit has a timedout command
+ * that needs to be processed.
+ */
+ cm = TAILQ_FIRST(&targ->timedout_commands);
+ if (cm) {
+ mprsas_send_abort(sc, tm, cm);
+ }
+ else {
+ targ->tm = NULL;
+ mprsas_free_tm(sc, tm);
+ }
+ }
+ else {
+ /* if we still have commands for this LUN, the reset
+ * effectively failed, regardless of the status reported.
+ * Escalate to a target reset.
+ */
+ mprsas_log_command(tm, MPR_RECOVERY,
+ "logical unit reset complete for tm %p, but still have %u "
+ "command(s)\n", tm, cm_count);
+ mprsas_send_reset(sc, tm,
+ MPI2_SCSITASKMGMT_TASKTYPE_TARGET_RESET);
+ }
+}
+
+static void
+mprsas_target_reset_complete(struct mpr_softc *sc, struct mpr_command *tm)
+{
+ MPI2_SCSI_TASK_MANAGE_REPLY *reply;
+ MPI2_SCSI_TASK_MANAGE_REQUEST *req;
+ struct mprsas_target *targ;
+
+ callout_stop(&tm->cm_callout);
+
+ req = (MPI2_SCSI_TASK_MANAGE_REQUEST *)tm->cm_req;
+ reply = (MPI2_SCSI_TASK_MANAGE_REPLY *)tm->cm_reply;
+ targ = tm->cm_targ;
+
+ /*
+ * Currently there should be no way we can hit this case. It only
+ * happens when we have a failure to allocate chain frames, and
+ * task management commands don't have S/G lists.
+ */
+ if ((tm->cm_flags & MPR_CM_FLAGS_ERROR_MASK) != 0) {
+ mpr_dprint(sc, MPR_ERROR,"%s: cm_flags = %#x for target reset! "
+ "This should not happen!\n", __func__, tm->cm_flags);
+ mprsas_free_tm(sc, tm);
+ return;
+ }
+
+ if (reply == NULL) {
+ mprsas_log_command(tm, MPR_RECOVERY,
+ "NULL reset reply for tm %p\n", tm);
+ if ((sc->mpr_flags & MPR_FLAGS_DIAGRESET) != 0) {
+ /* this completion was due to a reset, just cleanup */
+ targ->flags &= ~MPRSAS_TARGET_INRESET;
+ targ->tm = NULL;
+ mprsas_free_tm(sc, tm);
+ }
+ else {
+ /* we should have gotten a reply. */
+ mpr_reinit(sc);
+ }
+ return;
+ }
+
+ mprsas_log_command(tm, MPR_RECOVERY,
+ "target reset status 0x%x code 0x%x count %u\n",
+ le16toh(reply->IOCStatus), le32toh(reply->ResponseCode),
+ le32toh(reply->TerminationCount));
+
+ targ->flags &= ~MPRSAS_TARGET_INRESET;
+
+ if (targ->outstanding == 0) {
+ /* we've finished recovery for this target and all
+ * of its logical units.
+ */
+ mprsas_log_command(tm, MPR_RECOVERY|MPR_INFO,
+ "recovery finished after target reset\n");
+
+ mprsas_announce_reset(sc, AC_SENT_BDR, tm->cm_targ->tid,
+ CAM_LUN_WILDCARD);
+
+ targ->tm = NULL;
+ mprsas_free_tm(sc, tm);
+ }
+ else {
+ /* after a target reset, if this target still has
+ * outstanding commands, the reset effectively failed,
+ * regardless of the status reported. escalate.
+ */
+ mprsas_log_command(tm, MPR_RECOVERY,
+ "target reset complete for tm %p, but still have %u "
+ "command(s)\n", tm, targ->outstanding);
+ mpr_reinit(sc);
+ }
+}
+
+#define MPR_RESET_TIMEOUT 30
+
+static int
+mprsas_send_reset(struct mpr_softc *sc, struct mpr_command *tm, uint8_t type)
+{
+ MPI2_SCSI_TASK_MANAGE_REQUEST *req;
+ struct mprsas_target *target;
+ int err;
+
+ target = tm->cm_targ;
+ if (target->handle == 0) {
+ mpr_dprint(sc, MPR_ERROR,"%s null devhandle for target_id %d\n",
+ __func__, target->tid);
+ return -1;
+ }
+
+ req = (MPI2_SCSI_TASK_MANAGE_REQUEST *)tm->cm_req;
+ req->DevHandle = htole16(target->handle);
+ req->Function = MPI2_FUNCTION_SCSI_TASK_MGMT;
+ req->TaskType = type;
+
+ if (type == MPI2_SCSITASKMGMT_TASKTYPE_LOGICAL_UNIT_RESET) {
+ /* XXX Need to handle invalid LUNs */
+ MPR_SET_LUN(req->LUN, tm->cm_lun);
+ tm->cm_targ->logical_unit_resets++;
+ mprsas_log_command(tm, MPR_RECOVERY|MPR_INFO,
+ "sending logical unit reset\n");
+ tm->cm_complete = mprsas_logical_unit_reset_complete;
+ }
+ else if (type == MPI2_SCSITASKMGMT_TASKTYPE_TARGET_RESET) {
+ /*
+ * Target reset method =
+ * SAS Hard Link Reset / SATA Link Reset
+ */
+ req->MsgFlags = MPI2_SCSITASKMGMT_MSGFLAGS_LINK_RESET;
+ tm->cm_targ->target_resets++;
+ tm->cm_targ->flags |= MPRSAS_TARGET_INRESET;
+ mprsas_log_command(tm, MPR_RECOVERY|MPR_INFO,
+ "sending target reset\n");
+ tm->cm_complete = mprsas_target_reset_complete;
+ }
+ else {
+ mpr_dprint(sc, MPR_ERROR, "unexpected reset type 0x%x\n", type);
+ return -1;
+ }
+
+ mpr_dprint(sc, MPR_XINFO, "to target %u handle 0x%04x\n", target->tid,
+ target->handle);
+ if (target->encl_level_valid) {
+ mpr_dprint(sc, MPR_XINFO, "At enclosure level %d, slot %d, "
+ "connector name (%4s)\n", target->encl_level,
+ target->encl_slot, target->connector_name);
+ }
+
+ tm->cm_data = NULL;
+ tm->cm_desc.HighPriority.RequestFlags =
+ MPI2_REQ_DESCRIPT_FLAGS_HIGH_PRIORITY;
+ tm->cm_complete_data = (void *)tm;
+
+ callout_reset(&tm->cm_callout, MPR_RESET_TIMEOUT * hz,
+ mprsas_tm_timeout, tm);
+
+ err = mpr_map_command(sc, tm);
+ if (err)
+ mprsas_log_command(tm, MPR_RECOVERY,
+ "error %d sending reset type %u\n",
+ err, type);
+
+ return err;
+}
+
+
+static void
+mprsas_abort_complete(struct mpr_softc *sc, struct mpr_command *tm)
+{
+ struct mpr_command *cm;
+ MPI2_SCSI_TASK_MANAGE_REPLY *reply;
+ MPI2_SCSI_TASK_MANAGE_REQUEST *req;
+ struct mprsas_target *targ;
+
+ callout_stop(&tm->cm_callout);
+
+ req = (MPI2_SCSI_TASK_MANAGE_REQUEST *)tm->cm_req;
+ reply = (MPI2_SCSI_TASK_MANAGE_REPLY *)tm->cm_reply;
+ targ = tm->cm_targ;
+
+ /*
+ * Currently there should be no way we can hit this case. It only
+ * happens when we have a failure to allocate chain frames, and
+ * task management commands don't have S/G lists.
+ */
+ if ((tm->cm_flags & MPR_CM_FLAGS_ERROR_MASK) != 0) {
+ mprsas_log_command(tm, MPR_RECOVERY,
+ "cm_flags = %#x for abort %p TaskMID %u!\n",
+ tm->cm_flags, tm, le16toh(req->TaskMID));
+ mprsas_free_tm(sc, tm);
+ return;
+ }
+
+ if (reply == NULL) {
+ mprsas_log_command(tm, MPR_RECOVERY,
+ "NULL abort reply for tm %p TaskMID %u\n",
+ tm, le16toh(req->TaskMID));
+ if ((sc->mpr_flags & MPR_FLAGS_DIAGRESET) != 0) {
+ /* this completion was due to a reset, just cleanup */
+ targ->tm = NULL;
+ mprsas_free_tm(sc, tm);
+ }
+ else {
+ /* we should have gotten a reply. */
+ mpr_reinit(sc);
+ }
+ return;
+ }
+
+ mprsas_log_command(tm, MPR_RECOVERY,
+ "abort TaskMID %u status 0x%x code 0x%x count %u\n",
+ le16toh(req->TaskMID),
+ le16toh(reply->IOCStatus), le32toh(reply->ResponseCode),
+ le32toh(reply->TerminationCount));
+
+ cm = TAILQ_FIRST(&tm->cm_targ->timedout_commands);
+ if (cm == NULL) {
+ /* if there are no more timedout commands, we're done with
+ * error recovery for this target.
+ */
+ mprsas_log_command(tm, MPR_RECOVERY,
+ "finished recovery after aborting TaskMID %u\n",
+ le16toh(req->TaskMID));
+
+ targ->tm = NULL;
+ mprsas_free_tm(sc, tm);
+ }
+ else if (le16toh(req->TaskMID) != cm->cm_desc.Default.SMID) {
+ /* abort success, but we have more timedout commands to abort */
+ mprsas_log_command(tm, MPR_RECOVERY,
+ "continuing recovery after aborting TaskMID %u\n",
+ le16toh(req->TaskMID));
+
+ mprsas_send_abort(sc, tm, cm);
+ }
+ else {
+ /* we didn't get a command completion, so the abort
+ * failed as far as we're concerned. escalate.
+ */
+ mprsas_log_command(tm, MPR_RECOVERY,
+ "abort failed for TaskMID %u tm %p\n",
+ le16toh(req->TaskMID), tm);
+
+ mprsas_send_reset(sc, tm,
+ MPI2_SCSITASKMGMT_TASKTYPE_LOGICAL_UNIT_RESET);
+ }
+}
+
+#define MPR_ABORT_TIMEOUT 5
+
+static int
+mprsas_send_abort(struct mpr_softc *sc, struct mpr_command *tm,
+ struct mpr_command *cm)
+{
+ MPI2_SCSI_TASK_MANAGE_REQUEST *req;
+ struct mprsas_target *targ;
+ int err;
+
+ targ = cm->cm_targ;
+ if (targ->handle == 0) {
+ mpr_dprint(sc, MPR_ERROR,"%s null devhandle for target_id %d\n",
+ __func__, cm->cm_ccb->ccb_h.target_id);
+ return -1;
+ }
+
+ mprsas_log_command(tm, MPR_RECOVERY|MPR_INFO,
+ "Aborting command %p\n", cm);
+
+ req = (MPI2_SCSI_TASK_MANAGE_REQUEST *)tm->cm_req;
+ req->DevHandle = htole16(targ->handle);
+ req->Function = MPI2_FUNCTION_SCSI_TASK_MGMT;
+ req->TaskType = MPI2_SCSITASKMGMT_TASKTYPE_ABORT_TASK;
+
+ /* XXX Need to handle invalid LUNs */
+ MPR_SET_LUN(req->LUN, cm->cm_ccb->ccb_h.target_lun);
+
+ req->TaskMID = htole16(cm->cm_desc.Default.SMID);
+
+ tm->cm_data = NULL;
+ tm->cm_desc.HighPriority.RequestFlags =
+ MPI2_REQ_DESCRIPT_FLAGS_HIGH_PRIORITY;
+ tm->cm_complete = mprsas_abort_complete;
+ tm->cm_complete_data = (void *)tm;
+ tm->cm_targ = cm->cm_targ;
+ tm->cm_lun = cm->cm_lun;
+
+ callout_reset(&tm->cm_callout, MPR_ABORT_TIMEOUT * hz,
+ mprsas_tm_timeout, tm);
+
+ targ->aborts++;
+
+ err = mpr_map_command(sc, tm);
+ if (err)
+ mprsas_log_command(tm, MPR_RECOVERY,
+ "error %d sending abort for cm %p SMID %u\n",
+ err, cm, req->TaskMID);
+ return err;
+}
+
+
+static void
+mprsas_scsiio_timeout(void *data)
+{
+ struct mpr_softc *sc;
+ struct mpr_command *cm;
+ struct mprsas_target *targ;
+
+ cm = (struct mpr_command *)data;
+ sc = cm->cm_sc;
+
+ MPR_FUNCTRACE(sc);
+ mtx_assert(&sc->mpr_mtx, MA_OWNED);
+
+ mpr_dprint(sc, MPR_XINFO, "Timeout checking cm %p\n", cm);
+
+ /*
+ * Run the interrupt handler to make sure it's not pending. This
+ * isn't perfect because the command could have already completed
+ * and been re-used, though this is unlikely.
+ */
+ mpr_intr_locked(sc);
+ if (cm->cm_state == MPR_CM_STATE_FREE) {
+ mprsas_log_command(cm, MPR_XINFO,
+ "SCSI command %p almost timed out\n", cm);
+ return;
+ }
+
+ if (cm->cm_ccb == NULL) {
+ mpr_dprint(sc, MPR_ERROR, "command timeout with NULL ccb\n");
+ return;
+ }
+
+ targ = cm->cm_targ;
+ targ->timeouts++;
+
+ mprsas_log_command(cm, MPR_XINFO, "command timeout cm %p ccb %p "
+ "target %u, handle(0x%04x)\n", cm, cm->cm_ccb, targ->tid,
+ targ->handle);
+ if (targ->encl_level_valid) {
+ mpr_dprint(sc, MPR_XINFO, "At enclosure level %d, slot %d, "
+ "connector name (%4s)\n", targ->encl_level, targ->encl_slot,
+ targ->connector_name);
+ }
+
+ /* XXX first, check the firmware state, to see if it's still
+ * operational. if not, do a diag reset.
+ */
+
+ cm->cm_ccb->ccb_h.status = CAM_CMD_TIMEOUT;
+ cm->cm_state = MPR_CM_STATE_TIMEDOUT;
+ TAILQ_INSERT_TAIL(&targ->timedout_commands, cm, cm_recovery);
+
+ if (targ->tm != NULL) {
+ /* target already in recovery, just queue up another
+ * timedout command to be processed later.
+ */
+ mpr_dprint(sc, MPR_RECOVERY, "queued timedout cm %p for "
+ "processing by tm %p\n", cm, targ->tm);
+ }
+ else if ((targ->tm = mprsas_alloc_tm(sc)) != NULL) {
+ mpr_dprint(sc, MPR_RECOVERY, "timedout cm %p allocated tm %p\n",
+ cm, targ->tm);
+
+ /* start recovery by aborting the first timedout command */
+ mprsas_send_abort(sc, targ->tm, cm);
+ }
+ else {
+ /* XXX queue this target up for recovery once a TM becomes
+ * available. The firmware only has a limited number of
+ * HighPriority credits for the high priority requests used
+ * for task management, and we ran out.
+ *
+ * Isilon: don't worry about this for now, since we have
+ * more credits than disks in an enclosure, and limit
+ * ourselves to one TM per target for recovery.
+ */
+ mpr_dprint(sc, MPR_RECOVERY,
+ "timedout cm %p failed to allocate a tm\n", cm);
+ }
+}
+
+static void
+mprsas_action_scsiio(struct mprsas_softc *sassc, union ccb *ccb)
+{
+ MPI2_SCSI_IO_REQUEST *req;
+ struct ccb_scsiio *csio;
+ struct mpr_softc *sc;
+ struct mprsas_target *targ;
+ struct mprsas_lun *lun;
+ struct mpr_command *cm;
+ uint8_t i, lba_byte, *ref_tag_addr;
+ uint16_t eedp_flags;
+ uint32_t mpi_control;
+
+ sc = sassc->sc;
+ MPR_FUNCTRACE(sc);
+ mtx_assert(&sc->mpr_mtx, MA_OWNED);
+
+ csio = &ccb->csio;
+ targ = &sassc->targets[csio->ccb_h.target_id];
+ mpr_dprint(sc, MPR_TRACE, "ccb %p target flag %x\n", ccb, targ->flags);
+ if (targ->handle == 0x0) {
+ mpr_dprint(sc, MPR_ERROR, "%s NULL handle for target %u\n",
+ __func__, csio->ccb_h.target_id);
+ csio->ccb_h.status = CAM_DEV_NOT_THERE;
+ xpt_done(ccb);
+ return;
+ }
+ if (targ->flags & MPR_TARGET_FLAGS_RAID_COMPONENT) {
+ mpr_dprint(sc, MPR_TRACE, "%s Raid component no SCSI IO "
+ "supported %u\n", __func__, csio->ccb_h.target_id);
+ csio->ccb_h.status = CAM_DEV_NOT_THERE;
+ xpt_done(ccb);
+ return;
+ }
+ /*
+ * Sometimes, it is possible to get a command that is not "In
+ * Progress" and was actually aborted by the upper layer. Check for
+ * this here and complete the command without error.
+ */
+ if (ccb->ccb_h.status != CAM_REQ_INPROG) {
+ mpr_dprint(sc, MPR_TRACE, "%s Command is not in progress for "
+ "target %u\n", __func__, csio->ccb_h.target_id);
+ xpt_done(ccb);
+ return;
+ }
+ /*
+ * If devinfo is 0 this will be a volume. In that case don't tell CAM
+ * that the volume has timed out. We want volumes to be enumerated
+ * until they are deleted/removed, not just failed.
+ */
+ if (targ->flags & MPRSAS_TARGET_INREMOVAL) {
+ if (targ->devinfo == 0)
+ csio->ccb_h.status = CAM_REQ_CMP;
+ else
+ csio->ccb_h.status = CAM_SEL_TIMEOUT;
+ xpt_done(ccb);
+ return;
+ }
+
+ if ((sc->mpr_flags & MPR_FLAGS_SHUTDOWN) != 0) {
+ mpr_dprint(sc, MPR_TRACE, "%s shutting down\n", __func__);
+ csio->ccb_h.status = CAM_DEV_NOT_THERE;
+ xpt_done(ccb);
+ return;
+ }
+
+ cm = mpr_alloc_command(sc);
+ if (cm == NULL || (sc->mpr_flags & MPR_FLAGS_DIAGRESET)) {
+ if (cm != NULL) {
+ mpr_free_command(sc, cm);
+ }
+ if ((sassc->flags & MPRSAS_QUEUE_FROZEN) == 0) {
+ xpt_freeze_simq(sassc->sim, 1);
+ sassc->flags |= MPRSAS_QUEUE_FROZEN;
+ }
+ ccb->ccb_h.status &= ~CAM_SIM_QUEUED;
+ ccb->ccb_h.status |= CAM_REQUEUE_REQ;
+ xpt_done(ccb);
+ return;
+ }
+
+ req = (MPI2_SCSI_IO_REQUEST *)cm->cm_req;
+ bzero(req, sizeof(*req));
+ req->DevHandle = htole16(targ->handle);
+ req->Function = MPI2_FUNCTION_SCSI_IO_REQUEST;
+ req->MsgFlags = 0;
+ req->SenseBufferLowAddress = htole32(cm->cm_sense_busaddr);
+ req->SenseBufferLength = MPR_SENSE_LEN;
+ req->SGLFlags = 0;
+ req->ChainOffset = 0;
+ req->SGLOffset0 = 24; /* 32bit word offset to the SGL */
+ req->SGLOffset1= 0;
+ req->SGLOffset2= 0;
+ req->SGLOffset3= 0;
+ req->SkipCount = 0;
+ req->DataLength = htole32(csio->dxfer_len);
+ req->BidirectionalDataLength = 0;
+ req->IoFlags = htole16(csio->cdb_len);
+ req->EEDPFlags = 0;
+
+ /* Note: BiDirectional transfers are not supported */
+ switch (csio->ccb_h.flags & CAM_DIR_MASK) {
+ case CAM_DIR_IN:
+ mpi_control = MPI2_SCSIIO_CONTROL_READ;
+ cm->cm_flags |= MPR_CM_FLAGS_DATAIN;
+ break;
+ case CAM_DIR_OUT:
+ mpi_control = MPI2_SCSIIO_CONTROL_WRITE;
+ cm->cm_flags |= MPR_CM_FLAGS_DATAOUT;
+ break;
+ case CAM_DIR_NONE:
+ default:
+ mpi_control = MPI2_SCSIIO_CONTROL_NODATATRANSFER;
+ break;
+ }
+
+ if (csio->cdb_len == 32)
+ mpi_control |= 4 << MPI2_SCSIIO_CONTROL_ADDCDBLEN_SHIFT;
+ /*
+ * It looks like the hardware doesn't require an explicit tag
+ * number for each transaction. SAM Task Management not supported
+ * at the moment.
+ */
+ switch (csio->tag_action) {
+ case MSG_HEAD_OF_Q_TAG:
+ mpi_control |= MPI2_SCSIIO_CONTROL_HEADOFQ;
+ break;
+ case MSG_ORDERED_Q_TAG:
+ mpi_control |= MPI2_SCSIIO_CONTROL_ORDEREDQ;
+ break;
+ case MSG_ACA_TASK:
+ mpi_control |= MPI2_SCSIIO_CONTROL_ACAQ;
+ break;
+ case CAM_TAG_ACTION_NONE:
+ case MSG_SIMPLE_Q_TAG:
+ default:
+ mpi_control |= MPI2_SCSIIO_CONTROL_SIMPLEQ;
+ break;
+ }
+ mpi_control |= sc->mapping_table[csio->ccb_h.target_id].TLR_bits;
+ req->Control = htole32(mpi_control);
+
+ if (MPR_SET_LUN(req->LUN, csio->ccb_h.target_lun) != 0) {
+ mpr_free_command(sc, cm);
+ ccb->ccb_h.status = CAM_LUN_INVALID;
+ xpt_done(ccb);
+ return;
+ }
+
+ if (csio->ccb_h.flags & CAM_CDB_POINTER)
+ bcopy(csio->cdb_io.cdb_ptr, &req->CDB.CDB32[0], csio->cdb_len);
+ else
+ bcopy(csio->cdb_io.cdb_bytes, &req->CDB.CDB32[0],csio->cdb_len);
+ req->IoFlags = htole16(csio->cdb_len);
+
+ /*
+ * Check if EEDP is supported and enabled. If it is then check if the
+ * SCSI opcode could be using EEDP. If so, make sure the LUN exists and
+ * is formatted for EEDP support. If all of this is true, set CDB up
+ * for EEDP transfer.
+ */
+ eedp_flags = op_code_prot[req->CDB.CDB32[0]];
+ if (sc->eedp_enabled && eedp_flags) {
+ SLIST_FOREACH(lun, &targ->luns, lun_link) {
+ if (lun->lun_id == csio->ccb_h.target_lun) {
+ break;
+ }
+ }
+
+ if ((lun != NULL) && (lun->eedp_formatted)) {
+ req->EEDPBlockSize = htole16(lun->eedp_block_size);
+ eedp_flags |= (MPI2_SCSIIO_EEDPFLAGS_INC_PRI_REFTAG |
+ MPI2_SCSIIO_EEDPFLAGS_CHECK_REFTAG |
+ MPI2_SCSIIO_EEDPFLAGS_CHECK_GUARD);
+ req->EEDPFlags = htole16(eedp_flags);
+
+ /*
+ * If CDB less than 32, fill in Primary Ref Tag with
+ * low 4 bytes of LBA. If CDB is 32, tag stuff is
+ * already there. Also, set protection bit. FreeBSD
+ * currently does not support CDBs bigger than 16, but
+ * the code doesn't hurt, and will be here for the
+ * future.
+ */
+ if (csio->cdb_len != 32) {
+ lba_byte = (csio->cdb_len == 16) ? 6 : 2;
+ ref_tag_addr = (uint8_t *)&req->CDB.EEDP32.
+ PrimaryReferenceTag;
+ for (i = 0; i < 4; i++) {
+ *ref_tag_addr =
+ req->CDB.CDB32[lba_byte + i];
+ ref_tag_addr++;
+ }
+ req->CDB.EEDP32.PrimaryReferenceTag =
+ htole32(req->
+ CDB.EEDP32.PrimaryReferenceTag);
+ req->CDB.EEDP32.PrimaryApplicationTagMask =
+ 0xFFFF;
+ req->CDB.CDB32[1] = (req->CDB.CDB32[1] & 0x1F) |
+ 0x20;
+ } else {
+ eedp_flags |=
+ MPI2_SCSIIO_EEDPFLAGS_INC_PRI_APPTAG;
+ req->EEDPFlags = htole16(eedp_flags);
+ req->CDB.CDB32[10] = (req->CDB.CDB32[10] &
+ 0x1F) | 0x20;
+ }
+ }
+ }
+
+ cm->cm_length = csio->dxfer_len;
+ if (cm->cm_length != 0) {
+ cm->cm_data = ccb;
+ cm->cm_flags |= MPR_CM_FLAGS_USE_CCB;
+ } else {
+ cm->cm_data = NULL;
+ }
+ cm->cm_sge = &req->SGL;
+ cm->cm_sglsize = (32 - 24) * 4;
+ cm->cm_complete = mprsas_scsiio_complete;
+ cm->cm_complete_data = ccb;
+ cm->cm_targ = targ;
+ cm->cm_lun = csio->ccb_h.target_lun;
+ cm->cm_ccb = ccb;
+ /*
+ * If using FP desc type, need to set a bit in IoFlags (SCSI IO is 0)
+ * and set descriptor type.
+ */
+ if (targ->scsi_req_desc_type ==
+ MPI25_REQ_DESCRIPT_FLAGS_FAST_PATH_SCSI_IO) {
+ req->IoFlags |= MPI25_SCSIIO_IOFLAGS_FAST_PATH;
+ cm->cm_desc.FastPathSCSIIO.RequestFlags =
+ MPI25_REQ_DESCRIPT_FLAGS_FAST_PATH_SCSI_IO;
+ cm->cm_desc.FastPathSCSIIO.DevHandle = htole16(targ->handle);
+ } else {
+ cm->cm_desc.SCSIIO.RequestFlags =
+ MPI2_REQ_DESCRIPT_FLAGS_SCSI_IO;
+ cm->cm_desc.SCSIIO.DevHandle = htole16(targ->handle);
+ }
+
+ callout_reset(&cm->cm_callout, (ccb->ccb_h.timeout * hz) / 1000,
+ mprsas_scsiio_timeout, cm);
+
+ targ->issued++;
+ targ->outstanding++;
+ TAILQ_INSERT_TAIL(&targ->commands, cm, cm_link);
+ ccb->ccb_h.status |= CAM_SIM_QUEUED;
+
+ mprsas_log_command(cm, MPR_XINFO, "%s cm %p ccb %p outstanding %u\n",
+ __func__, cm, ccb, targ->outstanding);
+
+ mpr_map_command(sc, cm);
+ return;
+}
+
+static void
+mpr_response_code(struct mpr_softc *sc, 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;
+ }
+ mpr_dprint(sc, MPR_XINFO, "response_code(0x%01x): %s\n", response_code,
+ desc);
+}
+
+/**
+ * mpr_sc_failed_io_info - translated non-succesfull SCSI_IO request
+ */
+static void
+mpr_sc_failed_io_info(struct mpr_softc *sc, struct ccb_scsiio *csio,
+ Mpi2SCSIIOReply_t *mpi_reply, struct mprsas_target *targ)
+{
+ u32 response_info;
+ u8 *response_bytes;
+ u16 ioc_status = le16toh(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 = sc->tmp_string;
+ u32 log_info = le32toh(mpi_reply->IOCLogInfo);
+
+ if (log_info == 0x31170000)
+ return;
+
+ 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;
+ case MPI2_IOCSTATUS_EEDP_GUARD_ERROR:
+ desc_ioc_state = "eedp guard error";
+ break;
+ case MPI2_IOCSTATUS_EEDP_REF_TAG_ERROR:
+ desc_ioc_state = "eedp ref tag error";
+ break;
+ case MPI2_IOCSTATUS_EEDP_APP_TAG_ERROR:
+ desc_ioc_state = "eedp app tag error";
+ 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 ");
+
+ mpr_dprint(sc, MPR_XINFO, "\thandle(0x%04x), ioc_status(%s)(0x%04x)\n",
+ le16toh(mpi_reply->DevHandle), desc_ioc_state, ioc_status);
+ if (targ->encl_level_valid) {
+ mpr_dprint(sc, MPR_XINFO, "At enclosure level %d, slot %d, "
+ "connector name (%4s)\n", targ->encl_level, targ->encl_slot,
+ targ->connector_name);
+ }
+ /* We can add more detail about underflow data here
+ * TO-DO
+ * */
+ mpr_dprint(sc, MPR_XINFO, "\tscsi_status(%s)(0x%02x), "
+ "scsi_state(%s)(0x%02x)\n", desc_scsi_status, scsi_status,
+ desc_scsi_state, scsi_state);
+
+ if (sc->mpr_debug & MPR_XINFO &&
+ scsi_state & MPI2_SCSI_STATE_AUTOSENSE_VALID) {
+ mpr_dprint(sc, MPR_XINFO, "-> Sense Buffer Data : Start :\n");
+ scsi_sense_print(csio);
+ mpr_dprint(sc, MPR_XINFO, "-> Sense Buffer Data : End :\n");
+ }
+
+ if (scsi_state & MPI2_SCSI_STATE_RESPONSE_INFO_VALID) {
+ response_info = le32toh(mpi_reply->ResponseInfo);
+ response_bytes = (u8 *)&response_info;
+ mpr_response_code(sc,response_bytes[0]);
+ }
+}
+
+static void
+mprsas_scsiio_complete(struct mpr_softc *sc, struct mpr_command *cm)
+{
+ MPI2_SCSI_IO_REPLY *rep;
+ union ccb *ccb;
+ struct ccb_scsiio *csio;
+ struct mprsas_softc *sassc;
+ struct scsi_vpd_supported_page_list *vpd_list = NULL;
+ u8 *TLR_bits, TLR_on;
+ int dir = 0, i;
+ u16 alloc_len;
+
+ MPR_FUNCTRACE(sc);
+ mpr_dprint(sc, MPR_TRACE,
+ "cm %p SMID %u ccb %p reply %p outstanding %u\n", cm,
+ cm->cm_desc.Default.SMID, cm->cm_ccb, cm->cm_reply,
+ cm->cm_targ->outstanding);
+
+ callout_stop(&cm->cm_callout);
+ mtx_assert(&sc->mpr_mtx, MA_OWNED);
+
+ sassc = sc->sassc;
+ ccb = cm->cm_complete_data;
+ csio = &ccb->csio;
+ rep = (MPI2_SCSI_IO_REPLY *)cm->cm_reply;
+ /*
+ * XXX KDM if the chain allocation fails, does it matter if we do
+ * the sync and unload here? It is simpler to do it in every case,
+ * assuming it doesn't cause problems.
+ */
+ if (cm->cm_data != NULL) {
+ if (cm->cm_flags & MPR_CM_FLAGS_DATAIN)
+ dir = BUS_DMASYNC_POSTREAD;
+ else if (cm->cm_flags & MPR_CM_FLAGS_DATAOUT)
+ dir = BUS_DMASYNC_POSTWRITE;
+ bus_dmamap_sync(sc->buffer_dmat, cm->cm_dmamap, dir);
+ bus_dmamap_unload(sc->buffer_dmat, cm->cm_dmamap);
+ }
+
+ cm->cm_targ->completed++;
+ cm->cm_targ->outstanding--;
+ TAILQ_REMOVE(&cm->cm_targ->commands, cm, cm_link);
+ ccb->ccb_h.status &= ~(CAM_STATUS_MASK | CAM_SIM_QUEUED);
+
+ if (cm->cm_state == MPR_CM_STATE_TIMEDOUT) {
+ TAILQ_REMOVE(&cm->cm_targ->timedout_commands, cm, cm_recovery);
+ if (cm->cm_reply != NULL)
+ mprsas_log_command(cm, MPR_RECOVERY,
+ "completed timedout cm %p ccb %p during recovery "
+ "ioc %x scsi %x state %x xfer %u\n", cm, cm->cm_ccb,
+ le16toh(rep->IOCStatus), rep->SCSIStatus,
+ rep->SCSIState, le32toh(rep->TransferCount));
+ else
+ mprsas_log_command(cm, MPR_RECOVERY,
+ "completed timedout cm %p ccb %p during recovery\n",
+ cm, cm->cm_ccb);
+ } else if (cm->cm_targ->tm != NULL) {
+ if (cm->cm_reply != NULL)
+ mprsas_log_command(cm, MPR_RECOVERY,
+ "completed cm %p ccb %p during recovery "
+ "ioc %x scsi %x state %x xfer %u\n",
+ cm, cm->cm_ccb, le16toh(rep->IOCStatus),
+ rep->SCSIStatus, rep->SCSIState,
+ le32toh(rep->TransferCount));
+ else
+ mprsas_log_command(cm, MPR_RECOVERY,
+ "completed cm %p ccb %p during recovery\n",
+ cm, cm->cm_ccb);
+ } else if ((sc->mpr_flags & MPR_FLAGS_DIAGRESET) != 0) {
+ mprsas_log_command(cm, MPR_RECOVERY,
+ "reset completed cm %p ccb %p\n", cm, cm->cm_ccb);
+ }
+
+ if ((cm->cm_flags & MPR_CM_FLAGS_ERROR_MASK) != 0) {
+ /*
+ * We ran into an error after we tried to map the command,
+ * so we're getting a callback without queueing the command
+ * to the hardware. So we set the status here, and it will
+ * be retained below. We'll go through the "fast path",
+ * because there can be no reply when we haven't actually
+ * gone out to the hardware.
+ */
+ ccb->ccb_h.status = CAM_REQUEUE_REQ;
+
+ /*
+ * Currently the only error included in the mask is
+ * MPR_CM_FLAGS_CHAIN_FAILED, which means we're out of
+ * chain frames. We need to freeze the queue until we get
+ * a command that completed without this error, which will
+ * hopefully have some chain frames attached that we can
+ * use. If we wanted to get smarter about it, we would
+ * only unfreeze the queue in this condition when we're
+ * sure that we're getting some chain frames back. That's
+ * probably unnecessary.
+ */
+ if ((sassc->flags & MPRSAS_QUEUE_FROZEN) == 0) {
+ xpt_freeze_simq(sassc->sim, 1);
+ sassc->flags |= MPRSAS_QUEUE_FROZEN;
+ mpr_dprint(sc, MPR_INFO, "Error sending command, "
+ "freezing SIM queue\n");
+ }
+ }
+
+ /*
+ * If this is a Start Stop Unit command and it was issued by the driver
+ * during shutdown, decrement the refcount to account for all of the
+ * commands that were sent. All SSU commands should be completed before
+ * shutdown completes, meaning SSU_refcount will be 0 after SSU_started
+ * is TRUE.
+ */
+ if (sc->SSU_started && (csio->cdb_io.cdb_bytes[0] == START_STOP_UNIT)) {
+ mpr_dprint(sc, MPR_INFO, "Decrementing SSU count.\n");
+ sc->SSU_refcount--;
+ }
+
+ /* Take the fast path to completion */
+ if (cm->cm_reply == NULL) {
+ if ((ccb->ccb_h.status & CAM_STATUS_MASK) == CAM_REQ_INPROG) {
+ if ((sc->mpr_flags & MPR_FLAGS_DIAGRESET) != 0)
+ ccb->ccb_h.status = CAM_SCSI_BUS_RESET;
+ else {
+ ccb->ccb_h.status = CAM_REQ_CMP;
+ ccb->csio.scsi_status = SCSI_STATUS_OK;
+ }
+ if (sassc->flags & MPRSAS_QUEUE_FROZEN) {
+ ccb->ccb_h.status |= CAM_RELEASE_SIMQ;
+ sassc->flags &= ~MPRSAS_QUEUE_FROZEN;
+ mpr_dprint(sc, MPR_XINFO,
+ "Unfreezing SIM queue\n");
+ }
+ }
+
+ /*
+ * There are two scenarios where the status won't be
+ * CAM_REQ_CMP. The first is if MPR_CM_FLAGS_ERROR_MASK is
+ * set, the second is in the MPR_FLAGS_DIAGRESET above.
+ */
+ if ((ccb->ccb_h.status & CAM_STATUS_MASK) != CAM_REQ_CMP) {
+ /*
+ * Freeze the dev queue so that commands are
+ * executed in the correct order with after error
+ * recovery.
+ */
+ ccb->ccb_h.status |= CAM_DEV_QFRZN;
+ xpt_freeze_devq(ccb->ccb_h.path, /*count*/ 1);
+ }
+ mpr_free_command(sc, cm);
+ xpt_done(ccb);
+ return;
+ }
+
+ mprsas_log_command(cm, MPR_XINFO,
+ "ioc %x scsi %x state %x xfer %u\n",
+ le16toh(rep->IOCStatus), rep->SCSIStatus, rep->SCSIState,
+ le32toh(rep->TransferCount));
+
+ switch (le16toh(rep->IOCStatus) & MPI2_IOCSTATUS_MASK) {
+ case MPI2_IOCSTATUS_SCSI_DATA_UNDERRUN:
+ csio->resid = cm->cm_length - le32toh(rep->TransferCount);
+ /* FALLTHROUGH */
+ case MPI2_IOCSTATUS_SUCCESS:
+ case MPI2_IOCSTATUS_SCSI_RECOVERED_ERROR:
+
+ if ((le16toh(rep->IOCStatus) & MPI2_IOCSTATUS_MASK) ==
+ MPI2_IOCSTATUS_SCSI_RECOVERED_ERROR)
+ mprsas_log_command(cm, MPR_XINFO, "recovered error\n");
+
+ /* Completion failed at the transport level. */
+ if (rep->SCSIState & (MPI2_SCSI_STATE_NO_SCSI_STATUS |
+ MPI2_SCSI_STATE_TERMINATED)) {
+ ccb->ccb_h.status = CAM_REQ_CMP_ERR;
+ break;
+ }
+
+ /* In a modern packetized environment, an autosense failure
+ * implies that there's not much else that can be done to
+ * recover the command.
+ */
+ if (rep->SCSIState & MPI2_SCSI_STATE_AUTOSENSE_FAILED) {
+ ccb->ccb_h.status = CAM_AUTOSENSE_FAIL;
+ break;
+ }
+
+ /*
+ * CAM doesn't care about SAS Response Info data, but if this is
+ * the state check if TLR should be done. If not, clear the
+ * TLR_bits for the target.
+ */
+ if ((rep->SCSIState & MPI2_SCSI_STATE_RESPONSE_INFO_VALID) &&
+ ((le32toh(rep->ResponseInfo) & MPI2_SCSI_RI_MASK_REASONCODE)
+ == MPR_SCSI_RI_INVALID_FRAME)) {
+ sc->mapping_table[csio->ccb_h.target_id].TLR_bits =
+ (u8)MPI2_SCSIIO_CONTROL_NO_TLR;
+ }
+
+ /*
+ * Intentionally override the normal SCSI status reporting
+ * for these two cases. These are likely to happen in a
+ * multi-initiator environment, and we want to make sure that
+ * CAM retries these commands rather than fail them.
+ */
+ if ((rep->SCSIStatus == MPI2_SCSI_STATUS_COMMAND_TERMINATED) ||
+ (rep->SCSIStatus == MPI2_SCSI_STATUS_TASK_ABORTED)) {
+ ccb->ccb_h.status = CAM_REQ_ABORTED;
+ break;
+ }
+
+ /* Handle normal status and sense */
+ csio->scsi_status = rep->SCSIStatus;
+ if (rep->SCSIStatus == MPI2_SCSI_STATUS_GOOD)
+ ccb->ccb_h.status = CAM_REQ_CMP;
+ else
+ ccb->ccb_h.status = CAM_SCSI_STATUS_ERROR;
+
+ if (rep->SCSIState & MPI2_SCSI_STATE_AUTOSENSE_VALID) {
+ int sense_len, returned_sense_len;
+
+ returned_sense_len = min(le32toh(rep->SenseCount),
+ sizeof(struct scsi_sense_data));
+ if (returned_sense_len < csio->sense_len)
+ csio->sense_resid = csio->sense_len -
+ returned_sense_len;
+ else
+ csio->sense_resid = 0;
+
+ sense_len = min(returned_sense_len,
+ csio->sense_len - csio->sense_resid);
+ bzero(&csio->sense_data, sizeof(csio->sense_data));
+ bcopy(cm->cm_sense, &csio->sense_data, sense_len);
+ ccb->ccb_h.status |= CAM_AUTOSNS_VALID;
+ }
+
+ /*
+ * Check if this is an INQUIRY command. If it's a VPD inquiry,
+ * and it's page code 0 (Supported Page List), and there is
+ * inquiry data, and this is for a sequential access device, and
+ * the device is an SSP target, and TLR is supported by the
+ * controller, turn the TLR_bits value ON if page 0x90 is
+ * supported.
+ */
+ if ((csio->cdb_io.cdb_bytes[0] == INQUIRY) &&
+ (csio->cdb_io.cdb_bytes[1] & SI_EVPD) &&
+ (csio->cdb_io.cdb_bytes[2] == SVPD_SUPPORTED_PAGE_LIST) &&
+ ((csio->ccb_h.flags & CAM_DATA_MASK) == CAM_DATA_VADDR) &&
+ (csio->data_ptr != NULL) && (((uint8_t *)cm->cm_data)[0] ==
+ T_SEQUENTIAL) && (sc->control_TLR) &&
+ (sc->mapping_table[csio->ccb_h.target_id].device_info &
+ MPI2_SAS_DEVICE_INFO_SSP_TARGET)) {
+ vpd_list = (struct scsi_vpd_supported_page_list *)
+ csio->data_ptr;
+ TLR_bits = &sc->mapping_table[csio->ccb_h.target_id].
+ TLR_bits;
+ *TLR_bits = (u8)MPI2_SCSIIO_CONTROL_NO_TLR;
+ TLR_on = (u8)MPI2_SCSIIO_CONTROL_TLR_ON;
+ alloc_len = ((u16)csio->cdb_io.cdb_bytes[3] << 8) +
+ csio->cdb_io.cdb_bytes[4];
+ for (i = 0; i < MIN(vpd_list->length, alloc_len); i++) {
+ if (vpd_list->list[i] == 0x90) {
+ *TLR_bits = TLR_on;
+ break;
+ }
+ }
+ }
+ break;
+ case MPI2_IOCSTATUS_SCSI_INVALID_DEVHANDLE:
+ case MPI2_IOCSTATUS_SCSI_DEVICE_NOT_THERE:
+ /*
+ * If devinfo is 0 this will be a volume. In that case don't
+ * tell CAM that the volume is not there. We want volumes to
+ * be enumerated until they are deleted/removed, not just
+ * failed.
+ */
+ if (cm->cm_targ->devinfo == 0)
+ ccb->ccb_h.status = CAM_REQ_CMP;
+ else
+ ccb->ccb_h.status = CAM_DEV_NOT_THERE;
+ break;
+ case MPI2_IOCSTATUS_INVALID_SGL:
+ mpr_print_scsiio_cmd(sc, cm);
+ ccb->ccb_h.status = CAM_UNREC_HBA_ERROR;
+ break;
+ case MPI2_IOCSTATUS_SCSI_TASK_TERMINATED:
+ /*
+ * This is one of the responses that comes back when an I/O
+ * has been aborted. If it is because of a timeout that we
+ * initiated, just set the status to CAM_CMD_TIMEOUT.
+ * Otherwise set it to CAM_REQ_ABORTED. The effect on the
+ * command is the same (it gets retried, subject to the
+ * retry counter), the only difference is what gets printed
+ * on the console.
+ */
+ if (cm->cm_state == MPR_CM_STATE_TIMEDOUT)
+ ccb->ccb_h.status = CAM_CMD_TIMEOUT;
+ else
+ ccb->ccb_h.status = CAM_REQ_ABORTED;
+ break;
+ case MPI2_IOCSTATUS_SCSI_DATA_OVERRUN:
+ /* resid is ignored for this condition */
+ csio->resid = 0;
+ ccb->ccb_h.status = CAM_DATA_RUN_ERR;
+ break;
+ case MPI2_IOCSTATUS_SCSI_IOC_TERMINATED:
+ case MPI2_IOCSTATUS_SCSI_EXT_TERMINATED:
+ /*
+ * Since these are generally external (i.e. hopefully
+ * transient transport-related) errors, retry these without
+ * decrementing the retry count.
+ */
+ ccb->ccb_h.status = CAM_REQUEUE_REQ;
+ mprsas_log_command(cm, MPR_INFO,
+ "terminated ioc %x scsi %x state %x xfer %u\n",
+ le16toh(rep->IOCStatus), rep->SCSIStatus, rep->SCSIState,
+ le32toh(rep->TransferCount));
+ break;
+ case MPI2_IOCSTATUS_INVALID_FUNCTION:
+ case MPI2_IOCSTATUS_INTERNAL_ERROR:
+ case MPI2_IOCSTATUS_INVALID_VPID:
+ case MPI2_IOCSTATUS_INVALID_FIELD:
+ case MPI2_IOCSTATUS_INVALID_STATE:
+ case MPI2_IOCSTATUS_OP_STATE_NOT_SUPPORTED:
+ case MPI2_IOCSTATUS_SCSI_IO_DATA_ERROR:
+ case MPI2_IOCSTATUS_SCSI_PROTOCOL_ERROR:
+ case MPI2_IOCSTATUS_SCSI_RESIDUAL_MISMATCH:
+ case MPI2_IOCSTATUS_SCSI_TASK_MGMT_FAILED:
+ default:
+ mprsas_log_command(cm, MPR_XINFO,
+ "completed ioc %x scsi %x state %x xfer %u\n",
+ le16toh(rep->IOCStatus), rep->SCSIStatus, rep->SCSIState,
+ le32toh(rep->TransferCount));
+ csio->resid = cm->cm_length;
+ ccb->ccb_h.status = CAM_REQ_CMP_ERR;
+ break;
+ }
+
+ mpr_sc_failed_io_info(sc, csio, rep, cm->cm_targ);
+
+ if (sassc->flags & MPRSAS_QUEUE_FROZEN) {
+ ccb->ccb_h.status |= CAM_RELEASE_SIMQ;
+ sassc->flags &= ~MPRSAS_QUEUE_FROZEN;
+ mpr_dprint(sc, MPR_XINFO, "Command completed, unfreezing SIM "
+ "queue\n");
+ }
+
+ if ((ccb->ccb_h.status & CAM_STATUS_MASK) != CAM_REQ_CMP) {
+ ccb->ccb_h.status |= CAM_DEV_QFRZN;
+ xpt_freeze_devq(ccb->ccb_h.path, /*count*/ 1);
+ }
+
+ mpr_free_command(sc, cm);
+ xpt_done(ccb);
+}
+
+#if __FreeBSD_version >= 900026
+static void
+mprsas_smpio_complete(struct mpr_softc *sc, struct mpr_command *cm)
+{
+ MPI2_SMP_PASSTHROUGH_REPLY *rpl;
+ MPI2_SMP_PASSTHROUGH_REQUEST *req;
+ uint64_t sasaddr;
+ union ccb *ccb;
+
+ ccb = cm->cm_complete_data;
+
+ /*
+ * Currently there should be no way we can hit this case. It only
+ * happens when we have a failure to allocate chain frames, and SMP
+ * commands require two S/G elements only. That should be handled
+ * in the standard request size.
+ */
+ if ((cm->cm_flags & MPR_CM_FLAGS_ERROR_MASK) != 0) {
+ mpr_dprint(sc, MPR_ERROR,"%s: cm_flags = %#x on SMP request!\n",
+ __func__, cm->cm_flags);
+ ccb->ccb_h.status = CAM_REQ_CMP_ERR;
+ goto bailout;
+ }
+
+ rpl = (MPI2_SMP_PASSTHROUGH_REPLY *)cm->cm_reply;
+ if (rpl == NULL) {
+ mpr_dprint(sc, MPR_ERROR, "%s: NULL cm_reply!\n", __func__);
+ ccb->ccb_h.status = CAM_REQ_CMP_ERR;
+ goto bailout;
+ }
+
+ req = (MPI2_SMP_PASSTHROUGH_REQUEST *)cm->cm_req;
+ sasaddr = le32toh(req->SASAddress.Low);
+ sasaddr |= ((uint64_t)(le32toh(req->SASAddress.High))) << 32;
+
+ if ((le16toh(rpl->IOCStatus) & MPI2_IOCSTATUS_MASK) !=
+ MPI2_IOCSTATUS_SUCCESS ||
+ rpl->SASStatus != MPI2_SASSTATUS_SUCCESS) {
+ mpr_dprint(sc, MPR_XINFO, "%s: IOCStatus %04x SASStatus %02x\n",
+ __func__, le16toh(rpl->IOCStatus), rpl->SASStatus);
+ ccb->ccb_h.status = CAM_REQ_CMP_ERR;
+ goto bailout;
+ }
+
+ mpr_dprint(sc, MPR_XINFO, "%s: SMP request to SAS address "
+ "%#jx completed successfully\n", __func__, (uintmax_t)sasaddr);
+
+ if (ccb->smpio.smp_response[2] == SMP_FR_ACCEPTED)
+ ccb->ccb_h.status = CAM_REQ_CMP;
+ else
+ ccb->ccb_h.status = CAM_SMP_STATUS_ERROR;
+
+bailout:
+ /*
+ * We sync in both directions because we had DMAs in the S/G list
+ * in both directions.
+ */
+ bus_dmamap_sync(sc->buffer_dmat, cm->cm_dmamap,
+ BUS_DMASYNC_POSTREAD | BUS_DMASYNC_POSTWRITE);
+ bus_dmamap_unload(sc->buffer_dmat, cm->cm_dmamap);
+ mpr_free_command(sc, cm);
+ xpt_done(ccb);
+}
+
+static void
+mprsas_send_smpcmd(struct mprsas_softc *sassc, union ccb *ccb,
+ uint64_t sasaddr)
+{
+ struct mpr_command *cm;
+ uint8_t *request, *response;
+ MPI2_SMP_PASSTHROUGH_REQUEST *req;
+ struct mpr_softc *sc;
+ struct sglist *sg;
+ int error;
+
+ sc = sassc->sc;
+ sg = NULL;
+ error = 0;
+
+#if __FreeBSD_version >= 1000029
+ switch (ccb->ccb_h.flags & CAM_DATA_MASK) {
+ case CAM_DATA_PADDR:
+ case CAM_DATA_SG_PADDR:
+ /*
+ * XXX We don't yet support physical addresses here.
+ */
+ mpr_dprint(sc, MPR_ERROR, "%s: physical addresses not "
+ "supported\n", __func__);
+ ccb->ccb_h.status = CAM_REQ_INVALID;
+ xpt_done(ccb);
+ return;
+ case CAM_DATA_SG:
+ /*
+ * The chip does not support more than one buffer for the
+ * request or response.
+ */
+ if ((ccb->smpio.smp_request_sglist_cnt > 1)
+ || (ccb->smpio.smp_response_sglist_cnt > 1)) {
+ mpr_dprint(sc, MPR_ERROR,
+ "%s: multiple request or response buffer segments "
+ "not supported for SMP\n", __func__);
+ ccb->ccb_h.status = CAM_REQ_INVALID;
+ xpt_done(ccb);
+ return;
+ }
+
+ /*
+ * The CAM_SCATTER_VALID flag was originally implemented
+ * for the XPT_SCSI_IO CCB, which only has one data pointer.
+ * We have two. So, just take that flag to mean that we
+ * might have S/G lists, and look at the S/G segment count
+ * to figure out whether that is the case for each individual
+ * buffer.
+ */
+ if (ccb->smpio.smp_request_sglist_cnt != 0) {
+ bus_dma_segment_t *req_sg;
+
+ req_sg = (bus_dma_segment_t *)ccb->smpio.smp_request;
+ request = (uint8_t *)(uintptr_t)req_sg[0].ds_addr;
+ } else
+ request = ccb->smpio.smp_request;
+
+ if (ccb->smpio.smp_response_sglist_cnt != 0) {
+ bus_dma_segment_t *rsp_sg;
+
+ rsp_sg = (bus_dma_segment_t *)ccb->smpio.smp_response;
+ response = (uint8_t *)(uintptr_t)rsp_sg[0].ds_addr;
+ } else
+ response = ccb->smpio.smp_response;
+ break;
+ case CAM_DATA_VADDR:
+ request = ccb->smpio.smp_request;
+ response = ccb->smpio.smp_response;
+ break;
+ default:
+ ccb->ccb_h.status = CAM_REQ_INVALID;
+ xpt_done(ccb);
+ return;
+ }
+#else //__FreeBSD_version < 1000029
+ /*
+ * XXX We don't yet support physical addresses here.
+ */
+ if (ccb->ccb_h.flags & (CAM_DATA_PHYS|CAM_SG_LIST_PHYS)) {
+ mpr_printf(sc, "%s: physical addresses not supported\n",
+ __func__);
+ ccb->ccb_h.status = CAM_REQ_INVALID;
+ xpt_done(ccb);
+ return;
+ }
+
+ /*
+ * If the user wants to send an S/G list, check to make sure they
+ * have single buffers.
+ */
+ if (ccb->ccb_h.flags & CAM_SCATTER_VALID) {
+ /*
+ * The chip does not support more than one buffer for the
+ * request or response.
+ */
+ if ((ccb->smpio.smp_request_sglist_cnt > 1)
+ || (ccb->smpio.smp_response_sglist_cnt > 1)) {
+ mpr_dprint(sc, MPR_ERROR, "%s: multiple request or "
+ "response buffer segments not supported for SMP\n",
+ __func__);
+ ccb->ccb_h.status = CAM_REQ_INVALID;
+ xpt_done(ccb);
+ return;
+ }
+
+ /*
+ * The CAM_SCATTER_VALID flag was originally implemented
+ * for the XPT_SCSI_IO CCB, which only has one data pointer.
+ * We have two. So, just take that flag to mean that we
+ * might have S/G lists, and look at the S/G segment count
+ * to figure out whether that is the case for each individual
+ * buffer.
+ */
+ if (ccb->smpio.smp_request_sglist_cnt != 0) {
+ bus_dma_segment_t *req_sg;
+
+ req_sg = (bus_dma_segment_t *)ccb->smpio.smp_request;
+ request = (uint8_t *)req_sg[0].ds_addr;
+ } else
+ request = ccb->smpio.smp_request;
+
+ if (ccb->smpio.smp_response_sglist_cnt != 0) {
+ bus_dma_segment_t *rsp_sg;
+
+ rsp_sg = (bus_dma_segment_t *)ccb->smpio.smp_response;
+ response = (uint8_t *)rsp_sg[0].ds_addr;
+ } else
+ response = ccb->smpio.smp_response;
+ } else {
+ request = ccb->smpio.smp_request;
+ response = ccb->smpio.smp_response;
+ }
+#endif //__FreeBSD_version >= 1000029
+
+ cm = mpr_alloc_command(sc);
+ if (cm == NULL) {
+ mpr_dprint(sc, MPR_ERROR,
+ "%s: cannot allocate command\n", __func__);
+ ccb->ccb_h.status = CAM_RESRC_UNAVAIL;
+ xpt_done(ccb);
+ return;
+ }
+
+ req = (MPI2_SMP_PASSTHROUGH_REQUEST *)cm->cm_req;
+ bzero(req, sizeof(*req));
+ req->Function = MPI2_FUNCTION_SMP_PASSTHROUGH;
+
+ /* Allow the chip to use any route to this SAS address. */
+ req->PhysicalPort = 0xff;
+
+ req->RequestDataLength = htole16(ccb->smpio.smp_request_len);
+ req->SGLFlags =
+ MPI2_SGLFLAGS_SYSTEM_ADDRESS_SPACE | MPI2_SGLFLAGS_SGL_TYPE_MPI;
+
+ mpr_dprint(sc, MPR_XINFO, "%s: sending SMP request to SAS address "
+ "%#jx\n", __func__, (uintmax_t)sasaddr);
+
+ mpr_init_sge(cm, req, &req->SGL);
+
+ /*
+ * Set up a uio to pass into mpr_map_command(). This allows us to
+ * do one map command, and one busdma call in there.
+ */
+ cm->cm_uio.uio_iov = cm->cm_iovec;
+ cm->cm_uio.uio_iovcnt = 2;
+ cm->cm_uio.uio_segflg = UIO_SYSSPACE;
+
+ /*
+ * The read/write flag isn't used by busdma, but set it just in
+ * case. This isn't exactly accurate, either, since we're going in
+ * both directions.
+ */
+ cm->cm_uio.uio_rw = UIO_WRITE;
+
+ cm->cm_iovec[0].iov_base = request;
+ cm->cm_iovec[0].iov_len = le16toh(req->RequestDataLength);
+ cm->cm_iovec[1].iov_base = response;
+ cm->cm_iovec[1].iov_len = ccb->smpio.smp_response_len;
+
+ cm->cm_uio.uio_resid = cm->cm_iovec[0].iov_len +
+ cm->cm_iovec[1].iov_len;
+
+ /*
+ * Trigger a warning message in mpr_data_cb() for the user if we
+ * wind up exceeding two S/G segments. The chip expects one
+ * segment for the request and another for the response.
+ */
+ cm->cm_max_segs = 2;
+
+ cm->cm_desc.Default.RequestFlags = MPI2_REQ_DESCRIPT_FLAGS_DEFAULT_TYPE;
+ cm->cm_complete = mprsas_smpio_complete;
+ cm->cm_complete_data = ccb;
+
+ /*
+ * Tell the mapping code that we're using a uio, and that this is
+ * an SMP passthrough request. There is a little special-case
+ * logic there (in mpr_data_cb()) to handle the bidirectional
+ * transfer.
+ */
+ cm->cm_flags |= MPR_CM_FLAGS_USE_UIO | MPR_CM_FLAGS_SMP_PASS |
+ MPR_CM_FLAGS_DATAIN | MPR_CM_FLAGS_DATAOUT;
+
+ /* The chip data format is little endian. */
+ req->SASAddress.High = htole32(sasaddr >> 32);
+ req->SASAddress.Low = htole32(sasaddr);
+
+ /*
+ * XXX Note that we don't have a timeout/abort mechanism here.
+ * From the manual, it looks like task management requests only
+ * work for SCSI IO and SATA passthrough requests. We may need to
+ * have a mechanism to retry requests in the event of a chip reset
+ * at least. Hopefully the chip will insure that any errors short
+ * of that are relayed back to the driver.
+ */
+ error = mpr_map_command(sc, cm);
+ if ((error != 0) && (error != EINPROGRESS)) {
+ mpr_dprint(sc, MPR_ERROR, "%s: error %d returned from "
+ "mpr_map_command()\n", __func__, error);
+ goto bailout_error;
+ }
+
+ return;
+
+bailout_error:
+ mpr_free_command(sc, cm);
+ ccb->ccb_h.status = CAM_RESRC_UNAVAIL;
+ xpt_done(ccb);
+ return;
+}
+
+static void
+mprsas_action_smpio(struct mprsas_softc *sassc, union ccb *ccb)
+{
+ struct mpr_softc *sc;
+ struct mprsas_target *targ;
+ uint64_t sasaddr = 0;
+
+ sc = sassc->sc;
+
+ /*
+ * Make sure the target exists.
+ */
+ KASSERT(ccb->ccb_h.target_id < sassc->maxtargets,
+ ("Target %d out of bounds in XPT_SMP_IO\n", ccb->ccb_h.target_id));
+ targ = &sassc->targets[ccb->ccb_h.target_id];
+ if (targ->handle == 0x0) {
+ mpr_dprint(sc, MPR_ERROR, "%s: target %d does not exist!\n",
+ __func__, ccb->ccb_h.target_id);
+ ccb->ccb_h.status = CAM_SEL_TIMEOUT;
+ xpt_done(ccb);
+ return;
+ }
+
+ /*
+ * If this device has an embedded SMP target, we'll talk to it
+ * directly.
+ * figure out what the expander's address is.
+ */
+ if ((targ->devinfo & MPI2_SAS_DEVICE_INFO_SMP_TARGET) != 0)
+ sasaddr = targ->sasaddr;
+
+ /*
+ * If we don't have a SAS address for the expander yet, try
+ * grabbing it from the page 0x83 information cached in the
+ * transport layer for this target. LSI expanders report the
+ * expander SAS address as the port-associated SAS address in
+ * Inquiry VPD page 0x83. Maxim expanders don't report it in page
+ * 0x83.
+ *
+ * XXX KDM disable this for now, but leave it commented out so that
+ * it is obvious that this is another possible way to get the SAS
+ * address.
+ *
+ * The parent handle method below is a little more reliable, and
+ * the other benefit is that it works for devices other than SES
+ * devices. So you can send a SMP request to a da(4) device and it
+ * will get routed to the expander that device is attached to.
+ * (Assuming the da(4) device doesn't contain an SMP target...)
+ */
+#if 0
+ if (sasaddr == 0)
+ sasaddr = xpt_path_sas_addr(ccb->ccb_h.path);
+#endif
+
+ /*
+ * If we still don't have a SAS address for the expander, look for
+ * the parent device of this device, which is probably the expander.
+ */
+ if (sasaddr == 0) {
+#ifdef OLD_MPR_PROBE
+ struct mprsas_target *parent_target;
+#endif
+
+ if (targ->parent_handle == 0x0) {
+ mpr_dprint(sc, MPR_ERROR, "%s: handle %d does not have "
+ "a valid parent handle!\n", __func__, targ->handle);
+ ccb->ccb_h.status = CAM_DEV_NOT_THERE;
+ goto bailout;
+ }
+#ifdef OLD_MPR_PROBE
+ parent_target = mprsas_find_target_by_handle(sassc, 0,
+ targ->parent_handle);
+
+ if (parent_target == NULL) {
+ mpr_dprint(sc, MPR_ERROR, "%s: handle %d does not have "
+ "a valid parent target!\n", __func__, targ->handle);
+ ccb->ccb_h.status = CAM_DEV_NOT_THERE;
+ goto bailout;
+ }
+
+ if ((parent_target->devinfo &
+ MPI2_SAS_DEVICE_INFO_SMP_TARGET) == 0) {
+ mpr_dprint(sc, MPR_ERROR, "%s: handle %d parent %d "
+ "does not have an SMP target!\n", __func__,
+ targ->handle, parent_target->handle);
+ ccb->ccb_h.status = CAM_DEV_NOT_THERE;
+ goto bailout;
+
+ }
+
+ sasaddr = parent_target->sasaddr;
+#else /* OLD_MPR_PROBE */
+ if ((targ->parent_devinfo &
+ MPI2_SAS_DEVICE_INFO_SMP_TARGET) == 0) {
+ mpr_dprint(sc, MPR_ERROR, "%s: handle %d parent %d "
+ "does not have an SMP target!\n", __func__,
+ targ->handle, targ->parent_handle);
+ ccb->ccb_h.status = CAM_DEV_NOT_THERE;
+ goto bailout;
+
+ }
+ if (targ->parent_sasaddr == 0x0) {
+ mpr_dprint(sc, MPR_ERROR, "%s: handle %d parent handle "
+ "%d does not have a valid SAS address!\n", __func__,
+ targ->handle, targ->parent_handle);
+ ccb->ccb_h.status = CAM_DEV_NOT_THERE;
+ goto bailout;
+ }
+
+ sasaddr = targ->parent_sasaddr;
+#endif /* OLD_MPR_PROBE */
+
+ }
+
+ if (sasaddr == 0) {
+ mpr_dprint(sc, MPR_INFO, "%s: unable to find SAS address for "
+ "handle %d\n", __func__, targ->handle);
+ ccb->ccb_h.status = CAM_DEV_NOT_THERE;
+ goto bailout;
+ }
+ mprsas_send_smpcmd(sassc, ccb, sasaddr);
+
+ return;
+
+bailout:
+ xpt_done(ccb);
+
+}
+#endif //__FreeBSD_version >= 900026
+
+static void
+mprsas_action_resetdev(struct mprsas_softc *sassc, union ccb *ccb)
+{
+ MPI2_SCSI_TASK_MANAGE_REQUEST *req;
+ struct mpr_softc *sc;
+ struct mpr_command *tm;
+ struct mprsas_target *targ;
+
+ MPR_FUNCTRACE(sassc->sc);
+ mtx_assert(&sassc->sc->mpr_mtx, MA_OWNED);
+
+ KASSERT(ccb->ccb_h.target_id < sassc->maxtargets,
+ ("Target %d out of bounds in XPT_RESET_DEV\n",
+ ccb->ccb_h.target_id));
+ sc = sassc->sc;
+ tm = mpr_alloc_command(sc);
+ if (tm == NULL) {
+ mpr_dprint(sc, MPR_ERROR,
+ "command alloc failure in mprsas_action_resetdev\n");
+ ccb->ccb_h.status = CAM_RESRC_UNAVAIL;
+ xpt_done(ccb);
+ return;
+ }
+
+ targ = &sassc->targets[ccb->ccb_h.target_id];
+ req = (MPI2_SCSI_TASK_MANAGE_REQUEST *)tm->cm_req;
+ req->DevHandle = htole16(targ->handle);
+ req->Function = MPI2_FUNCTION_SCSI_TASK_MGMT;
+ req->TaskType = MPI2_SCSITASKMGMT_TASKTYPE_TARGET_RESET;
+
+ /* SAS Hard Link Reset / SATA Link Reset */
+ req->MsgFlags = MPI2_SCSITASKMGMT_MSGFLAGS_LINK_RESET;
+
+ tm->cm_data = NULL;
+ tm->cm_desc.HighPriority.RequestFlags =
+ MPI2_REQ_DESCRIPT_FLAGS_HIGH_PRIORITY;
+ tm->cm_complete = mprsas_resetdev_complete;
+ tm->cm_complete_data = ccb;
+ tm->cm_targ = targ;
+ mpr_map_command(sc, tm);
+}
+
+static void
+mprsas_resetdev_complete(struct mpr_softc *sc, struct mpr_command *tm)
+{
+ MPI2_SCSI_TASK_MANAGE_REPLY *resp;
+ union ccb *ccb;
+
+ MPR_FUNCTRACE(sc);
+ mtx_assert(&sc->mpr_mtx, MA_OWNED);
+
+ resp = (MPI2_SCSI_TASK_MANAGE_REPLY *)tm->cm_reply;
+ ccb = tm->cm_complete_data;
+
+ /*
+ * Currently there should be no way we can hit this case. It only
+ * happens when we have a failure to allocate chain frames, and
+ * task management commands don't have S/G lists.
+ */
+ if ((tm->cm_flags & MPR_CM_FLAGS_ERROR_MASK) != 0) {
+ MPI2_SCSI_TASK_MANAGE_REQUEST *req;
+
+ req = (MPI2_SCSI_TASK_MANAGE_REQUEST *)tm->cm_req;
+
+ mpr_dprint(sc, MPR_ERROR, "%s: cm_flags = %#x for reset of "
+ "handle %#04x! This should not happen!\n", __func__,
+ tm->cm_flags, req->DevHandle);
+ ccb->ccb_h.status = CAM_REQ_CMP_ERR;
+ goto bailout;
+ }
+
+ mpr_dprint(sc, MPR_XINFO,
+ "%s: IOCStatus = 0x%x ResponseCode = 0x%x\n", __func__,
+ le16toh(resp->IOCStatus), le32toh(resp->ResponseCode));
+
+ if (le32toh(resp->ResponseCode) == MPI2_SCSITASKMGMT_RSP_TM_COMPLETE) {
+ ccb->ccb_h.status = CAM_REQ_CMP;
+ mprsas_announce_reset(sc, AC_SENT_BDR, tm->cm_targ->tid,
+ CAM_LUN_WILDCARD);
+ }
+ else
+ ccb->ccb_h.status = CAM_REQ_CMP_ERR;
+
+bailout:
+
+ mprsas_free_tm(sc, tm);
+ xpt_done(ccb);
+}
+
+static void
+mprsas_poll(struct cam_sim *sim)
+{
+ struct mprsas_softc *sassc;
+
+ sassc = cam_sim_softc(sim);
+
+ if (sassc->sc->mpr_debug & MPR_TRACE) {
+ /* frequent debug messages during a panic just slow
+ * everything down too much.
+ */
+ mpr_printf(sassc->sc, "%s clearing MPR_TRACE\n", __func__);
+ sassc->sc->mpr_debug &= ~MPR_TRACE;
+ }
+
+ mpr_intr_locked(sassc->sc);
+}
+
+static void
+mprsas_async(void *callback_arg, uint32_t code, struct cam_path *path,
+ void *arg)
+{
+ struct mpr_softc *sc;
+
+ sc = (struct mpr_softc *)callback_arg;
+
+ switch (code) {
+#if (__FreeBSD_version >= 1000006) || \
+ ((__FreeBSD_version >= 901503) && (__FreeBSD_version < 1000000))
+ case AC_ADVINFO_CHANGED: {
+ struct mprsas_target *target;
+ struct mprsas_softc *sassc;
+ struct scsi_read_capacity_data_long rcap_buf;
+ struct ccb_dev_advinfo cdai;
+ struct mprsas_lun *lun;
+ lun_id_t lunid;
+ int found_lun;
+ uintptr_t buftype;
+
+ buftype = (uintptr_t)arg;
+
+ found_lun = 0;
+ sassc = sc->sassc;
+
+ /*
+ * We're only interested in read capacity data changes.
+ */
+ if (buftype != CDAI_TYPE_RCAPLONG)
+ break;
+
+ /*
+ * We should have a handle for this, but check to make sure.
+ */
+ KASSERT(xpt_path_target_id(path) < sassc->maxtargets,
+ ("Target %d out of bounds in mprsas_async\n",
+ xpt_path_target_id(path)));
+ target = &sassc->targets[xpt_path_target_id(path)];
+ if (target->handle == 0)
+ break;
+
+ lunid = xpt_path_lun_id(path);
+
+ SLIST_FOREACH(lun, &target->luns, lun_link) {
+ if (lun->lun_id == lunid) {
+ found_lun = 1;
+ break;
+ }
+ }
+
+ if (found_lun == 0) {
+ lun = malloc(sizeof(struct mprsas_lun), M_MPR,
+ M_NOWAIT | M_ZERO);
+ if (lun == NULL) {
+ mpr_dprint(sc, MPR_ERROR, "Unable to alloc "
+ "LUN for EEDP support.\n");
+ break;
+ }
+ lun->lun_id = lunid;
+ SLIST_INSERT_HEAD(&target->luns, lun, lun_link);
+ }
+
+ bzero(&rcap_buf, sizeof(rcap_buf));
+ xpt_setup_ccb(&cdai.ccb_h, path, CAM_PRIORITY_NORMAL);
+ cdai.ccb_h.func_code = XPT_DEV_ADVINFO;
+ cdai.ccb_h.flags = CAM_DIR_IN;
+ cdai.buftype = CDAI_TYPE_RCAPLONG;
+ cdai.flags = 0;
+ cdai.bufsiz = sizeof(rcap_buf);
+ cdai.buf = (uint8_t *)&rcap_buf;
+ xpt_action((union ccb *)&cdai);
+ if ((cdai.ccb_h.status & CAM_DEV_QFRZN) != 0)
+ cam_release_devq(cdai.ccb_h.path, 0, 0, 0, FALSE);
+
+ if (((cdai.ccb_h.status & CAM_STATUS_MASK) == CAM_REQ_CMP)
+ && (rcap_buf.prot & SRC16_PROT_EN)) {
+ lun->eedp_formatted = TRUE;
+ lun->eedp_block_size = scsi_4btoul(rcap_buf.length);
+ } else {
+ lun->eedp_formatted = FALSE;
+ lun->eedp_block_size = 0;
+ }
+ break;
+ }
+#endif
+ case AC_FOUND_DEVICE: {
+ struct ccb_getdev *cgd;
+
+ cgd = arg;
+ mprsas_prepare_ssu(sc, path, cgd);
+#if (__FreeBSD_version < 901503) || \
+ ((__FreeBSD_version >= 1000000) && (__FreeBSD_version < 1000006))
+ mprsas_check_eedp(sc, path, cgd);
+#endif
+ break;
+ }
+ default:
+ break;
+ }
+}
+
+static void
+mprsas_prepare_ssu(struct mpr_softc *sc, struct cam_path *path,
+ struct ccb_getdev *cgd)
+{
+ struct mprsas_softc *sassc = sc->sassc;
+ path_id_t pathid;
+ target_id_t targetid;
+ lun_id_t lunid;
+ struct mprsas_target *target;
+ struct mprsas_lun *lun;
+ uint8_t found_lun;
+
+ sassc = sc->sassc;
+ pathid = cam_sim_path(sassc->sim);
+ targetid = xpt_path_target_id(path);
+ lunid = xpt_path_lun_id(path);
+
+ KASSERT(targetid < sassc->maxtargets,
+ ("Target %d out of bounds in mprsas_prepare_ssu\n", targetid));
+ target = &sassc->targets[targetid];
+ if (target->handle == 0x0)
+ return;
+
+ /*
+ * If LUN is already in list, don't create a new one.
+ */
+ found_lun = FALSE;
+ SLIST_FOREACH(lun, &target->luns, lun_link) {
+ if (lun->lun_id == lunid) {
+ found_lun = TRUE;
+ break;
+ }
+ }
+ if (!found_lun) {
+ lun = malloc(sizeof(struct mprsas_lun), M_MPR,
+ M_NOWAIT | M_ZERO);
+ if (lun == NULL) {
+ mpr_dprint(sc, MPR_ERROR, "Unable to alloc LUN for "
+ "preparing SSU.\n");
+ return;
+ }
+ lun->lun_id = lunid;
+ SLIST_INSERT_HEAD(&target->luns, lun, lun_link);
+ }
+
+ /*
+ * If this is a SATA direct-access end device, mark it so that a SCSI
+ * StartStopUnit command will be sent to it when the driver is being
+ * shutdown.
+ */
+ if (((cgd->inq_data.device & 0x1F) == T_DIRECT) &&
+ (target->devinfo & MPI2_SAS_DEVICE_INFO_SATA_DEVICE) &&
+ ((target->devinfo & MPI2_SAS_DEVICE_INFO_MASK_DEVICE_TYPE) ==
+ MPI2_SAS_DEVICE_INFO_END_DEVICE)) {
+ lun->stop_at_shutdown = TRUE;
+ }
+}
+
+#if (__FreeBSD_version < 901503) || \
+ ((__FreeBSD_version >= 1000000) && (__FreeBSD_version < 1000006))
+static void
+mprsas_check_eedp(struct mpr_softc *sc, struct cam_path *path,
+ struct ccb_getdev *cgd)
+{
+ struct mprsas_softc *sassc = sc->sassc;
+ struct ccb_scsiio *csio;
+ struct scsi_read_capacity_16 *scsi_cmd;
+ struct scsi_read_capacity_eedp *rcap_buf;
+ path_id_t pathid;
+ target_id_t targetid;
+ lun_id_t lunid;
+ union ccb *ccb;
+ struct cam_path *local_path;
+ struct mprsas_target *target;
+ struct mprsas_lun *lun;
+ uint8_t found_lun;
+ char path_str[64];
+
+ sassc = sc->sassc;
+ pathid = cam_sim_path(sassc->sim);
+ targetid = xpt_path_target_id(path);
+ lunid = xpt_path_lun_id(path);
+
+ KASSERT(targetid < sassc->maxtargets,
+ ("Target %d out of bounds in mprsas_check_eedp\n", targetid));
+ target = &sassc->targets[targetid];
+ if (target->handle == 0x0)
+ return;
+
+ /*
+ * Determine if the device is EEDP capable.
+ *
+ * If this flag is set in the inquiry data, the device supports
+ * protection information, and must support the 16 byte read capacity
+ * command, otherwise continue without sending read cap 16
+ */
+ if ((cgd->inq_data.spc3_flags & SPC3_SID_PROTECT) == 0)
+ return;
+
+ /*
+ * Issue a READ CAPACITY 16 command. This info is used to determine if
+ * the LUN is formatted for EEDP support.
+ */
+ ccb = xpt_alloc_ccb_nowait();
+ if (ccb == NULL) {
+ mpr_dprint(sc, MPR_ERROR, "Unable to alloc CCB for EEDP "
+ "support.\n");
+ return;
+ }
+
+ if (xpt_create_path(&local_path, xpt_periph, pathid, targetid, lunid)
+ != CAM_REQ_CMP) {
+ mpr_dprint(sc, MPR_ERROR, "Unable to create path for EEDP "
+ "support\n");
+ xpt_free_ccb(ccb);
+ return;
+ }
+
+ /*
+ * If LUN is already in list, don't create a new one.
+ */
+ found_lun = FALSE;
+ SLIST_FOREACH(lun, &target->luns, lun_link) {
+ if (lun->lun_id == lunid) {
+ found_lun = TRUE;
+ break;
+ }
+ }
+ if (!found_lun) {
+ lun = malloc(sizeof(struct mprsas_lun), M_MPR,
+ M_NOWAIT | M_ZERO);
+ if (lun == NULL) {
+ mpr_dprint(sc, MPR_ERROR, "Unable to alloc LUN for "
+ "EEDP support.\n");
+ xpt_free_path(local_path);
+ xpt_free_ccb(ccb);
+ return;
+ }
+ lun->lun_id = lunid;
+ SLIST_INSERT_HEAD(&target->luns, lun, lun_link);
+ }
+
+ xpt_path_string(local_path, path_str, sizeof(path_str));
+ mpr_dprint(sc, MPR_INFO, "Sending read cap: path %s handle %d\n",
+ path_str, target->handle);
+
+ /*
+ * Issue a READ CAPACITY 16 command for the LUN. The
+ * mprsas_read_cap_done function will load the read cap info into the
+ * LUN struct.
+ */
+ rcap_buf = malloc(sizeof(struct scsi_read_capacity_eedp), M_MPR,
+ M_NOWAIT | M_ZERO);
+ if (rcap_buf == NULL) {
+ mpr_dprint(sc, MPR_FAULT, "Unable to alloc read capacity "
+ "buffer for EEDP support.\n");
+ xpt_free_path(ccb->ccb_h.path);
+ xpt_free_ccb(ccb);
+ return;
+ }
+ xpt_setup_ccb(&ccb->ccb_h, local_path, CAM_PRIORITY_XPT);
+ csio = &ccb->csio;
+ csio->ccb_h.func_code = XPT_SCSI_IO;
+ csio->ccb_h.flags = CAM_DIR_IN;
+ csio->ccb_h.retry_count = 4;
+ csio->ccb_h.cbfcnp = mprsas_read_cap_done;
+ csio->ccb_h.timeout = 60000;
+ csio->data_ptr = (uint8_t *)rcap_buf;
+ csio->dxfer_len = sizeof(struct scsi_read_capacity_eedp);
+ csio->sense_len = MPR_SENSE_LEN;
+ csio->cdb_len = sizeof(*scsi_cmd);
+ csio->tag_action = MSG_SIMPLE_Q_TAG;
+
+ scsi_cmd = (struct scsi_read_capacity_16 *)&csio->cdb_io.cdb_bytes;
+ bzero(scsi_cmd, sizeof(*scsi_cmd));
+ scsi_cmd->opcode = 0x9E;
+ scsi_cmd->service_action = SRC16_SERVICE_ACTION;
+ ((uint8_t *)scsi_cmd)[13] = sizeof(struct scsi_read_capacity_eedp);
+
+ ccb->ccb_h.ppriv_ptr1 = sassc;
+ xpt_action(ccb);
+}
+
+static void
+mprsas_read_cap_done(struct cam_periph *periph, union ccb *done_ccb)
+{
+ struct mprsas_softc *sassc;
+ struct mprsas_target *target;
+ struct mprsas_lun *lun;
+ struct scsi_read_capacity_eedp *rcap_buf;
+
+ if (done_ccb == NULL)
+ return;
+
+ /* Driver need to release devq, it Scsi command is
+ * generated by driver internally.
+ * Currently there is a single place where driver
+ * calls scsi command internally. In future if driver
+ * calls more scsi command internally, it needs to release
+ * devq internally, since those command will not go back to
+ * cam_periph.
+ */
+ if ((done_ccb->ccb_h.status & CAM_DEV_QFRZN) ) {
+ done_ccb->ccb_h.status &= ~CAM_DEV_QFRZN;
+ xpt_release_devq(done_ccb->ccb_h.path,
+ /*count*/ 1, /*run_queue*/TRUE);
+ }
+
+ rcap_buf = (struct scsi_read_capacity_eedp *)done_ccb->csio.data_ptr;
+
+ /*
+ * Get the LUN ID for the path and look it up in the LUN list for the
+ * target.
+ */
+ sassc = (struct mprsas_softc *)done_ccb->ccb_h.ppriv_ptr1;
+ KASSERT(done_ccb->ccb_h.target_id < sassc->maxtargets,
+ ("Target %d out of bounds in mprsas_read_cap_done\n",
+ done_ccb->ccb_h.target_id));
+ target = &sassc->targets[done_ccb->ccb_h.target_id];
+ SLIST_FOREACH(lun, &target->luns, lun_link) {
+ if (lun->lun_id != done_ccb->ccb_h.target_lun)
+ continue;
+
+ /*
+ * Got the LUN in the target's LUN list. Fill it in with EEDP
+ * info. If the READ CAP 16 command had some SCSI error (common
+ * if command is not supported), mark the lun as not supporting
+ * EEDP and set the block size to 0.
+ */
+ if (((done_ccb->ccb_h.status & CAM_STATUS_MASK) != CAM_REQ_CMP)
+ || (done_ccb->csio.scsi_status != SCSI_STATUS_OK)) {
+ lun->eedp_formatted = FALSE;
+ lun->eedp_block_size = 0;
+ break;
+ }
+
+ if (rcap_buf->protect & 0x01) {
+ mpr_dprint(sassc->sc, MPR_INFO, "LUN %d for "
+ "target ID %d is formatted for EEDP "
+ "support.\n", done_ccb->ccb_h.target_lun,
+ done_ccb->ccb_h.target_id);
+ lun->eedp_formatted = TRUE;
+ lun->eedp_block_size = scsi_4btoul(rcap_buf->length);
+ }
+ break;
+ }
+
+ // Finished with this CCB and path.
+ free(rcap_buf, M_MPR);
+ xpt_free_path(done_ccb->ccb_h.path);
+ xpt_free_ccb(done_ccb);
+}
+#endif /* (__FreeBSD_version < 901503) || \
+ ((__FreeBSD_version >= 1000000) && (__FreeBSD_version < 1000006)) */
+
+int
+mprsas_startup(struct mpr_softc *sc)
+{
+ /*
+ * Send the port enable message and set the wait_for_port_enable flag.
+ * This flag helps to keep the simq frozen until all discovery events
+ * are processed.
+ */
+ sc->wait_for_port_enable = 1;
+ mprsas_send_portenable(sc);
+ return (0);
+}
+
+static int
+mprsas_send_portenable(struct mpr_softc *sc)
+{
+ MPI2_PORT_ENABLE_REQUEST *request;
+ struct mpr_command *cm;
+
+ MPR_FUNCTRACE(sc);
+
+ if ((cm = mpr_alloc_command(sc)) == NULL)
+ return (EBUSY);
+ request = (MPI2_PORT_ENABLE_REQUEST *)cm->cm_req;
+ request->Function = MPI2_FUNCTION_PORT_ENABLE;
+ request->MsgFlags = 0;
+ request->VP_ID = 0;
+ cm->cm_desc.Default.RequestFlags = MPI2_REQ_DESCRIPT_FLAGS_DEFAULT_TYPE;
+ cm->cm_complete = mprsas_portenable_complete;
+ cm->cm_data = NULL;
+ cm->cm_sge = NULL;
+
+ mpr_map_command(sc, cm);
+ mpr_dprint(sc, MPR_XINFO,
+ "mpr_send_portenable finished cm %p req %p complete %p\n",
+ cm, cm->cm_req, cm->cm_complete);
+ return (0);
+}
+
+static void
+mprsas_portenable_complete(struct mpr_softc *sc, struct mpr_command *cm)
+{
+ MPI2_PORT_ENABLE_REPLY *reply;
+ struct mprsas_softc *sassc;
+
+ MPR_FUNCTRACE(sc);
+ sassc = sc->sassc;
+
+ /*
+ * Currently there should be no way we can hit this case. It only
+ * happens when we have a failure to allocate chain frames, and
+ * port enable commands don't have S/G lists.
+ */
+ if ((cm->cm_flags & MPR_CM_FLAGS_ERROR_MASK) != 0) {
+ mpr_dprint(sc, MPR_ERROR, "%s: cm_flags = %#x for port enable! "
+ "This should not happen!\n", __func__, cm->cm_flags);
+ }
+
+ reply = (MPI2_PORT_ENABLE_REPLY *)cm->cm_reply;
+ if (reply == NULL)
+ mpr_dprint(sc, MPR_FAULT, "Portenable NULL reply\n");
+ else if (le16toh(reply->IOCStatus & MPI2_IOCSTATUS_MASK) !=
+ MPI2_IOCSTATUS_SUCCESS)
+ mpr_dprint(sc, MPR_FAULT, "Portenable failed\n");
+
+ mpr_free_command(sc, cm);
+ if (sc->mpr_ich.ich_arg != NULL) {
+ mpr_dprint(sc, MPR_XINFO, "disestablish config intrhook\n");
+ config_intrhook_disestablish(&sc->mpr_ich);
+ sc->mpr_ich.ich_arg = NULL;
+ }
+
+ /*
+ * Done waiting for port enable to complete. Decrement the refcount.
+ * If refcount is 0, discovery is complete and a rescan of the bus can
+ * take place.
+ */
+ sc->wait_for_port_enable = 0;
+ sc->port_enable_complete = 1;
+ wakeup(&sc->port_enable_complete);
+ mprsas_startup_decrement(sassc);
+}
+
+int
+mprsas_check_id(struct mprsas_softc *sassc, int id)
+{
+ struct mpr_softc *sc = sassc->sc;
+ char *ids;
+ char *name;
+
+ ids = &sc->exclude_ids[0];
+ while((name = strsep(&ids, ",")) != NULL) {
+ if (name[0] == '\0')
+ continue;
+ if (strtol(name, NULL, 0) == (long)id)
+ return (1);
+ }
+
+ return (0);
+}
diff --git a/sys/dev/mpr/mpr_sas.h b/sys/dev/mpr/mpr_sas.h
new file mode 100644
index 0000000..9d3116a
--- /dev/null
+++ b/sys/dev/mpr/mpr_sas.h
@@ -0,0 +1,168 @@
+/*-
+ * Copyright (c) 2011-2014 LSI Corp.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * LSI MPT-Fusion Host Adapter FreeBSD
+ *
+ * $FreeBSD$
+ */
+
+struct mpr_fw_event_work;
+
+struct mprsas_lun {
+ SLIST_ENTRY(mprsas_lun) lun_link;
+ lun_id_t lun_id;
+ uint8_t eedp_formatted;
+ uint32_t eedp_block_size;
+ uint8_t stop_at_shutdown;
+};
+
+struct mprsas_target {
+ uint16_t handle;
+ uint8_t linkrate;
+ uint8_t encl_level_valid;
+ uint8_t encl_level;
+ char connector_name[4];
+ uint64_t devname;
+ uint32_t devinfo;
+ uint16_t encl_handle;
+ uint16_t encl_slot;
+ uint8_t flags;
+#define MPRSAS_TARGET_INABORT (1 << 0)
+#define MPRSAS_TARGET_INRESET (1 << 1)
+#define MPRSAS_TARGET_INDIAGRESET (1 << 2)
+#define MPRSAS_TARGET_INREMOVAL (1 << 3)
+#define MPR_TARGET_FLAGS_RAID_COMPONENT (1 << 4)
+#define MPR_TARGET_FLAGS_VOLUME (1 << 5)
+#define MPRSAS_TARGET_INRECOVERY (MPRSAS_TARGET_INABORT | \
+ MPRSAS_TARGET_INRESET | MPRSAS_TARGET_INCHIPRESET)
+
+#define MPRSAS_TARGET_ADD (1 << 29)
+#define MPRSAS_TARGET_REMOVE (1 << 30)
+ uint16_t tid;
+ SLIST_HEAD(, mprsas_lun) luns;
+ TAILQ_HEAD(, mpr_command) commands;
+ struct mpr_command *tm;
+ TAILQ_HEAD(, mpr_command) timedout_commands;
+ uint16_t exp_dev_handle;
+ uint16_t phy_num;
+ uint64_t sasaddr;
+ uint16_t parent_handle;
+ uint64_t parent_sasaddr;
+ uint32_t parent_devinfo;
+ struct sysctl_ctx_list sysctl_ctx;
+ struct sysctl_oid *sysctl_tree;
+ TAILQ_ENTRY(mprsas_target) sysctl_link;
+ uint64_t issued;
+ uint64_t completed;
+ unsigned int outstanding;
+ unsigned int timeouts;
+ unsigned int aborts;
+ unsigned int logical_unit_resets;
+ unsigned int target_resets;
+ uint8_t scsi_req_desc_type;
+};
+
+struct mprsas_softc {
+ struct mpr_softc *sc;
+ u_int flags;
+#define MPRSAS_IN_DISCOVERY (1 << 0)
+#define MPRSAS_IN_STARTUP (1 << 1)
+#define MPRSAS_DISCOVERY_TIMEOUT_PENDING (1 << 2)
+#define MPRSAS_QUEUE_FROZEN (1 << 3)
+#define MPRSAS_SHUTDOWN (1 << 4)
+#define MPRSAS_SCANTHREAD (1 << 5)
+ u_int maxtargets;
+ struct mprsas_target *targets;
+ struct cam_devq *devq;
+ struct cam_sim *sim;
+ struct cam_path *path;
+ struct intr_config_hook sas_ich;
+ struct callout discovery_callout;
+ struct mpr_event_handle *mprsas_eh;
+
+ u_int startup_refcount;
+ u_int tm_count;
+ struct proc *sysctl_proc;
+
+ struct taskqueue *ev_tq;
+ struct task ev_task;
+ TAILQ_HEAD(, mpr_fw_event_work) ev_queue;
+};
+
+MALLOC_DECLARE(M_MPRSAS);
+
+/*
+ * Abstracted so that the driver can be backwards and forwards compatible
+ * with future versions of CAM that will provide this functionality.
+ */
+#define MPR_SET_LUN(lun, ccblun) \
+ mprsas_set_lun(lun, ccblun)
+
+static __inline int
+mprsas_set_lun(uint8_t *lun, u_int ccblun)
+{
+ uint64_t *newlun;
+
+ newlun = (uint64_t *)lun;
+ *newlun = 0;
+ if (ccblun <= 0xff) {
+ /* Peripheral device address method, LUN is 0 to 255 */
+ lun[1] = ccblun;
+ } else if (ccblun <= 0x3fff) {
+ /* Flat space address method, LUN is <= 16383 */
+ scsi_ulto2b(ccblun, lun);
+ lun[0] |= 0x40;
+ } else if (ccblun <= 0xffffff) {
+ /* Extended flat space address method, LUN is <= 16777215 */
+ scsi_ulto3b(ccblun, &lun[1]);
+ /* Extended Flat space address method */
+ lun[0] = 0xc0;
+ /* Length = 1, i.e. LUN is 3 bytes long */
+ lun[0] |= 0x10;
+ /* Extended Address Method */
+ lun[0] |= 0x02;
+ } else {
+ return (EINVAL);
+ }
+
+ return (0);
+}
+
+#define MPR_SET_SINGLE_LUN(req, lun) \
+do { \
+ bzero((req)->LUN, 8); \
+ (req)->LUN[1] = lun; \
+} while(0)
+
+void mprsas_rescan_target(struct mpr_softc *sc, struct mprsas_target *targ);
+void mprsas_discovery_end(struct mprsas_softc *sassc);
+void mprsas_startup_increment(struct mprsas_softc *sassc);
+void mprsas_startup_decrement(struct mprsas_softc *sassc);
+void mprsas_release_simq_reinit(struct mprsas_softc *sassc);
+
+struct mpr_command * mprsas_alloc_tm(struct mpr_softc *sc);
+void mprsas_free_tm(struct mpr_softc *sc, struct mpr_command *tm);
+void mprsas_firmware_event_work(void *arg, int pending);
+int mprsas_check_id(struct mprsas_softc *sassc, int id);
diff --git a/sys/dev/mpr/mpr_sas_lsi.c b/sys/dev/mpr/mpr_sas_lsi.c
new file mode 100644
index 0000000..cf5be2b
--- /dev/null
+++ b/sys/dev/mpr/mpr_sas_lsi.c
@@ -0,0 +1,1210 @@
+/*-
+ * Copyright (c) 2011-2014 LSI Corp.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * LSI MPT-Fusion Host Adapter FreeBSD
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+/* Communications core for LSI MPT2 */
+
+/* TODO Move headers to mprvar */
+#include <sys/types.h>
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/kernel.h>
+#include <sys/selinfo.h>
+#include <sys/module.h>
+#include <sys/bus.h>
+#include <sys/conf.h>
+#include <sys/bio.h>
+#include <sys/malloc.h>
+#include <sys/uio.h>
+#include <sys/sysctl.h>
+#include <sys/endian.h>
+#include <sys/queue.h>
+#include <sys/kthread.h>
+#include <sys/taskqueue.h>
+#include <sys/sbuf.h>
+
+#include <machine/bus.h>
+#include <machine/resource.h>
+#include <sys/rman.h>
+
+#include <machine/stdarg.h>
+
+#include <cam/cam.h>
+#include <cam/cam_ccb.h>
+#include <cam/cam_debug.h>
+#include <cam/cam_sim.h>
+#include <cam/cam_xpt_sim.h>
+#include <cam/cam_xpt_periph.h>
+#include <cam/cam_periph.h>
+#include <cam/scsi/scsi_all.h>
+#include <cam/scsi/scsi_message.h>
+
+#include <dev/mpr/mpi/mpi2_type.h>
+#include <dev/mpr/mpi/mpi2.h>
+#include <dev/mpr/mpi/mpi2_ioc.h>
+#include <dev/mpr/mpi/mpi2_sas.h>
+#include <dev/mpr/mpi/mpi2_cnfg.h>
+#include <dev/mpr/mpi/mpi2_init.h>
+#include <dev/mpr/mpi/mpi2_raid.h>
+#include <dev/mpr/mpi/mpi2_tool.h>
+#include <dev/mpr/mpr_ioctl.h>
+#include <dev/mpr/mprvar.h>
+#include <dev/mpr/mpr_table.h>
+#include <dev/mpr/mpr_sas.h>
+
+/* For Hashed SAS Address creation for SATA Drives */
+#define MPT2SAS_SN_LEN 20
+#define MPT2SAS_MN_LEN 40
+
+struct mpr_fw_event_work {
+ u16 event;
+ void *event_data;
+ TAILQ_ENTRY(mpr_fw_event_work) ev_link;
+};
+
+union _sata_sas_address {
+ u8 wwid[8];
+ struct {
+ u32 high;
+ u32 low;
+ } word;
+};
+
+/*
+ * define the IDENTIFY DEVICE structure
+ */
+struct _ata_identify_device_data {
+ u16 reserved1[10]; /* 0-9 */
+ u16 serial_number[10]; /* 10-19 */
+ u16 reserved2[7]; /* 20-26 */
+ u16 model_number[20]; /* 27-46*/
+ u16 reserved3[209]; /* 47-255*/
+};
+static u32 event_count;
+static void mprsas_fw_work(struct mpr_softc *sc,
+ struct mpr_fw_event_work *fw_event);
+static void mprsas_fw_event_free(struct mpr_softc *,
+ struct mpr_fw_event_work *);
+static int mprsas_add_device(struct mpr_softc *sc, u16 handle, u8 linkrate);
+static int mprsas_get_sata_identify(struct mpr_softc *sc, u16 handle,
+ Mpi2SataPassthroughReply_t *mpi_reply, char *id_buffer, int sz,
+ u32 devinfo);
+int mprsas_get_sas_address_for_sata_disk(struct mpr_softc *sc,
+ u64 *sas_address, u16 handle, u32 device_info);
+static int mprsas_volume_add(struct mpr_softc *sc,
+ u16 handle);
+static void mprsas_SSU_to_SATA_devices(struct mpr_softc *sc);
+static void mprsas_stop_unit_done(struct cam_periph *periph,
+ union ccb *done_ccb);
+
+void
+mprsas_evt_handler(struct mpr_softc *sc, uintptr_t data,
+ MPI2_EVENT_NOTIFICATION_REPLY *event)
+{
+ struct mpr_fw_event_work *fw_event;
+ u16 sz;
+
+ mpr_dprint(sc, MPR_TRACE, "%s\n", __func__);
+ mpr_print_evt_sas(sc, event);
+ mprsas_record_event(sc, event);
+
+ fw_event = malloc(sizeof(struct mpr_fw_event_work), M_MPR,
+ M_ZERO|M_NOWAIT);
+ if (!fw_event) {
+ printf("%s: allocate failed for fw_event\n", __func__);
+ return;
+ }
+ sz = le16toh(event->EventDataLength) * 4;
+ fw_event->event_data = malloc(sz, M_MPR, M_ZERO|M_NOWAIT);
+ if (!fw_event->event_data) {
+ printf("%s: allocate failed for event_data\n", __func__);
+ free(fw_event, M_MPR);
+ return;
+ }
+
+ bcopy(event->EventData, fw_event->event_data, sz);
+ fw_event->event = event->Event;
+ if ((event->Event == MPI2_EVENT_SAS_TOPOLOGY_CHANGE_LIST ||
+ event->Event == MPI2_EVENT_SAS_ENCL_DEVICE_STATUS_CHANGE ||
+ event->Event == MPI2_EVENT_IR_CONFIGURATION_CHANGE_LIST) &&
+ sc->track_mapping_events)
+ sc->pending_map_events++;
+
+ /*
+ * When wait_for_port_enable flag is set, make sure that all the events
+ * are processed. Increment the startup_refcount and decrement it after
+ * events are processed.
+ */
+ if ((event->Event == MPI2_EVENT_SAS_TOPOLOGY_CHANGE_LIST ||
+ event->Event == MPI2_EVENT_IR_CONFIGURATION_CHANGE_LIST) &&
+ sc->wait_for_port_enable)
+ mprsas_startup_increment(sc->sassc);
+
+ TAILQ_INSERT_TAIL(&sc->sassc->ev_queue, fw_event, ev_link);
+ taskqueue_enqueue(sc->sassc->ev_tq, &sc->sassc->ev_task);
+
+}
+
+static void
+mprsas_fw_event_free(struct mpr_softc *sc, struct mpr_fw_event_work *fw_event)
+{
+
+ free(fw_event->event_data, M_MPR);
+ free(fw_event, M_MPR);
+}
+
+/**
+ * _mpr_fw_work - delayed task for processing firmware events
+ * @sc: per adapter object
+ * @fw_event: The fw_event_work object
+ * Context: user.
+ *
+ * Return nothing.
+ */
+static void
+mprsas_fw_work(struct mpr_softc *sc, struct mpr_fw_event_work *fw_event)
+{
+ struct mprsas_softc *sassc;
+ sassc = sc->sassc;
+
+ mpr_dprint(sc, MPR_EVENT, "(%d)->(%s) Working on Event: [%x]\n",
+ event_count++, __func__, fw_event->event);
+ switch (fw_event->event) {
+ case MPI2_EVENT_SAS_TOPOLOGY_CHANGE_LIST:
+ {
+ MPI2_EVENT_DATA_SAS_TOPOLOGY_CHANGE_LIST *data;
+ MPI2_EVENT_SAS_TOPO_PHY_ENTRY *phy;
+ int i;
+
+ data = (MPI2_EVENT_DATA_SAS_TOPOLOGY_CHANGE_LIST *)
+ fw_event->event_data;
+
+ mpr_mapping_topology_change_event(sc, fw_event->event_data);
+
+ for (i = 0; i < data->NumEntries; i++) {
+ phy = &data->PHY[i];
+ switch (phy->PhyStatus & MPI2_EVENT_SAS_TOPO_RC_MASK) {
+ case MPI2_EVENT_SAS_TOPO_RC_TARG_ADDED:
+ if (mprsas_add_device(sc,
+ le16toh(phy->AttachedDevHandle),
+ phy->LinkRate)) {
+ printf("%s: failed to add device with "
+ "handle 0x%x\n", __func__,
+ le16toh(phy->AttachedDevHandle));
+ mprsas_prepare_remove(sassc, le16toh(
+ phy->AttachedDevHandle));
+ }
+ break;
+ case MPI2_EVENT_SAS_TOPO_RC_TARG_NOT_RESPONDING:
+ mprsas_prepare_remove(sassc, le16toh(
+ phy->AttachedDevHandle));
+ break;
+ case MPI2_EVENT_SAS_TOPO_RC_PHY_CHANGED:
+ case MPI2_EVENT_SAS_TOPO_RC_NO_CHANGE:
+ case MPI2_EVENT_SAS_TOPO_RC_DELAY_NOT_RESPONDING:
+ default:
+ break;
+ }
+ }
+ /*
+ * refcount was incremented for this event in
+ * mprsas_evt_handler. Decrement it here because the event has
+ * been processed.
+ */
+ mprsas_startup_decrement(sassc);
+ break;
+ }
+ case MPI2_EVENT_SAS_DISCOVERY:
+ {
+ MPI2_EVENT_DATA_SAS_DISCOVERY *data;
+
+ data = (MPI2_EVENT_DATA_SAS_DISCOVERY *)fw_event->event_data;
+
+ if (data->ReasonCode & MPI2_EVENT_SAS_DISC_RC_STARTED)
+ mpr_dprint(sc, MPR_TRACE,"SAS discovery start "
+ "event\n");
+ if (data->ReasonCode & MPI2_EVENT_SAS_DISC_RC_COMPLETED) {
+ mpr_dprint(sc, MPR_TRACE,"SAS discovery stop event\n");
+ sassc->flags &= ~MPRSAS_IN_DISCOVERY;
+ mprsas_discovery_end(sassc);
+ }
+ break;
+ }
+ case MPI2_EVENT_SAS_ENCL_DEVICE_STATUS_CHANGE:
+ {
+ Mpi2EventDataSasEnclDevStatusChange_t *data;
+ data = (Mpi2EventDataSasEnclDevStatusChange_t *)
+ fw_event->event_data;
+ mpr_mapping_enclosure_dev_status_change_event(sc,
+ fw_event->event_data);
+ break;
+ }
+ case MPI2_EVENT_IR_CONFIGURATION_CHANGE_LIST:
+ {
+ Mpi2EventIrConfigElement_t *element;
+ int i;
+ u8 foreign_config, reason;
+ u16 elementType;
+ Mpi2EventDataIrConfigChangeList_t *event_data;
+ struct mprsas_target *targ;
+ unsigned int id;
+
+ event_data = fw_event->event_data;
+ foreign_config = (le32toh(event_data->Flags) &
+ MPI2_EVENT_IR_CHANGE_FLAGS_FOREIGN_CONFIG) ? 1 : 0;
+
+ element =
+ (Mpi2EventIrConfigElement_t *)&event_data->ConfigElement[0];
+ id = mpr_mapping_get_raid_id_from_handle(sc,
+ element->VolDevHandle);
+
+ mpr_mapping_ir_config_change_event(sc, event_data);
+ for (i = 0; i < event_data->NumElements; i++, element++) {
+ reason = element->ReasonCode;
+ elementType = le16toh(element->ElementFlags) &
+ MPI2_EVENT_IR_CHANGE_EFLAGS_ELEMENT_TYPE_MASK;
+ /*
+ * check for element type of Phys Disk or Hot Spare
+ */
+ if ((elementType !=
+ MPI2_EVENT_IR_CHANGE_EFLAGS_VOLPHYSDISK_ELEMENT)
+ && (elementType !=
+ MPI2_EVENT_IR_CHANGE_EFLAGS_HOTSPARE_ELEMENT))
+ // do next element
+ goto skip_fp_send;
+
+ /*
+ * check for reason of Hide, Unhide, PD Created, or PD
+ * Deleted
+ */
+ if ((reason != MPI2_EVENT_IR_CHANGE_RC_HIDE) &&
+ (reason != MPI2_EVENT_IR_CHANGE_RC_UNHIDE) &&
+ (reason != MPI2_EVENT_IR_CHANGE_RC_PD_CREATED) &&
+ (reason != MPI2_EVENT_IR_CHANGE_RC_PD_DELETED))
+ goto skip_fp_send;
+
+ // check for a reason of Hide or PD Created
+ if ((reason == MPI2_EVENT_IR_CHANGE_RC_HIDE) ||
+ (reason == MPI2_EVENT_IR_CHANGE_RC_PD_CREATED))
+ {
+ // build RAID Action message
+ Mpi2RaidActionRequest_t *action;
+ Mpi2RaidActionReply_t *reply;
+ struct mpr_command *cm;
+ int error = 0;
+ if ((cm = mpr_alloc_command(sc)) == NULL) {
+ printf("%s: command alloc failed\n",
+ __func__);
+ return;
+ }
+
+ mpr_dprint(sc, MPR_INFO, "Sending FP action "
+ "from "
+ "MPI2_EVENT_IR_CONFIGURATION_CHANGE_LIST "
+ ":\n");
+ action = (MPI2_RAID_ACTION_REQUEST *)cm->cm_req;
+ action->Function = MPI2_FUNCTION_RAID_ACTION;
+ action->Action =
+ MPI2_RAID_ACTION_PHYSDISK_HIDDEN;
+ action->PhysDiskNum = element->PhysDiskNum;
+ cm->cm_desc.Default.RequestFlags =
+ MPI2_REQ_DESCRIPT_FLAGS_DEFAULT_TYPE;
+ error = mpr_request_polled(sc, cm);
+ reply = (Mpi2RaidActionReply_t *)cm->cm_reply;
+ if (error || (reply == NULL)) {
+ /* FIXME */
+ /*
+ * If the poll returns error then we
+ * need to do diag reset
+ */
+ printf("%s: poll for page completed "
+ "with error %d", __func__, error);
+ }
+ if (reply && (le16toh(reply->IOCStatus) &
+ MPI2_IOCSTATUS_MASK) !=
+ MPI2_IOCSTATUS_SUCCESS) {
+ mpr_dprint(sc, MPR_INFO, "%s: error "
+ "sending RaidActionPage; iocstatus "
+ "= 0x%x\n", __func__,
+ le16toh(reply->IOCStatus));
+ }
+
+ if (cm)
+ mpr_free_command(sc, cm);
+ }
+skip_fp_send:
+ mpr_dprint(sc, MPR_INFO, "Received "
+ "MPI2_EVENT_IR_CONFIGURATION_CHANGE_LIST Reason "
+ "code %x:\n", element->ReasonCode);
+ switch (element->ReasonCode) {
+ case MPI2_EVENT_IR_CHANGE_RC_VOLUME_CREATED:
+ case MPI2_EVENT_IR_CHANGE_RC_ADDED:
+ if (!foreign_config) {
+ if (mprsas_volume_add(sc,
+ le16toh(element->VolDevHandle))) {
+ printf("%s: failed to add RAID "
+ "volume with handle 0x%x\n",
+ __func__, le16toh(element->
+ VolDevHandle));
+ }
+ }
+ break;
+ case MPI2_EVENT_IR_CHANGE_RC_VOLUME_DELETED:
+ case MPI2_EVENT_IR_CHANGE_RC_REMOVED:
+ /*
+ * Rescan after volume is deleted or removed.
+ */
+ if (!foreign_config) {
+ if (id == MPR_MAP_BAD_ID) {
+ printf("%s: could not get ID "
+ "for volume with handle "
+ "0x%04x\n", __func__,
+ le16toh(element->
+ VolDevHandle));
+ break;
+ }
+
+ targ = &sassc->targets[id];
+ targ->handle = 0x0;
+ targ->encl_slot = 0x0;
+ targ->encl_handle = 0x0;
+ targ->encl_level_valid = 0x0;
+ targ->encl_level = 0x0;
+ targ->connector_name[0] = ' ';
+ targ->connector_name[1] = ' ';
+ targ->connector_name[2] = ' ';
+ targ->connector_name[3] = ' ';
+ targ->exp_dev_handle = 0x0;
+ targ->phy_num = 0x0;
+ targ->linkrate = 0x0;
+ mprsas_rescan_target(sc, targ);
+ printf("RAID target id 0x%x removed\n",
+ targ->tid);
+ }
+ break;
+ case MPI2_EVENT_IR_CHANGE_RC_PD_CREATED:
+ case MPI2_EVENT_IR_CHANGE_RC_HIDE:
+ /*
+ * Phys Disk of a volume has been created. Hide
+ * it from the OS.
+ */
+ targ = mprsas_find_target_by_handle(sassc, 0,
+ element->PhysDiskDevHandle);
+ if (targ == NULL)
+ break;
+ targ->flags |= MPR_TARGET_FLAGS_RAID_COMPONENT;
+ mprsas_rescan_target(sc, targ);
+
+ break;
+ case MPI2_EVENT_IR_CHANGE_RC_PD_DELETED:
+ /*
+ * Phys Disk of a volume has been deleted.
+ * Expose it to the OS.
+ */
+ if (mprsas_add_device(sc,
+ le16toh(element->PhysDiskDevHandle), 0)) {
+ printf("%s: failed to add device with "
+ "handle 0x%x\n", __func__,
+ le16toh(element->
+ PhysDiskDevHandle));
+ mprsas_prepare_remove(sassc,
+ le16toh(element->
+ PhysDiskDevHandle));
+ }
+ break;
+ }
+ }
+ /*
+ * refcount was incremented for this event in
+ * mprsas_evt_handler. Decrement it here because the event has
+ * been processed.
+ */
+ mprsas_startup_decrement(sassc);
+ break;
+ }
+ case MPI2_EVENT_IR_VOLUME:
+ {
+ Mpi2EventDataIrVolume_t *event_data = fw_event->event_data;
+
+ /*
+ * Informational only.
+ */
+ mpr_dprint(sc, MPR_EVENT, "Received IR Volume event:\n");
+ switch (event_data->ReasonCode) {
+ case MPI2_EVENT_IR_VOLUME_RC_SETTINGS_CHANGED:
+ mpr_dprint(sc, MPR_EVENT, " Volume Settings "
+ "changed from 0x%x to 0x%x for Volome with "
+ "handle 0x%x", le32toh(event_data->PreviousValue),
+ le32toh(event_data->NewValue),
+ le16toh(event_data->VolDevHandle));
+ break;
+ case MPI2_EVENT_IR_VOLUME_RC_STATUS_FLAGS_CHANGED:
+ mpr_dprint(sc, MPR_EVENT, " Volume Status "
+ "changed from 0x%x to 0x%x for Volome with "
+ "handle 0x%x", le32toh(event_data->PreviousValue),
+ le32toh(event_data->NewValue),
+ le16toh(event_data->VolDevHandle));
+ break;
+ case MPI2_EVENT_IR_VOLUME_RC_STATE_CHANGED:
+ mpr_dprint(sc, MPR_EVENT, " Volume State "
+ "changed from 0x%x to 0x%x for Volome with "
+ "handle 0x%x", le32toh(event_data->PreviousValue),
+ le32toh(event_data->NewValue),
+ le16toh(event_data->VolDevHandle));
+ u32 state;
+ struct mprsas_target *targ;
+ state = le32toh(event_data->NewValue);
+ switch (state) {
+ case MPI2_RAID_VOL_STATE_MISSING:
+ case MPI2_RAID_VOL_STATE_FAILED:
+ mprsas_prepare_volume_remove(sassc,
+ event_data->VolDevHandle);
+ break;
+
+ case MPI2_RAID_VOL_STATE_ONLINE:
+ case MPI2_RAID_VOL_STATE_DEGRADED:
+ case MPI2_RAID_VOL_STATE_OPTIMAL:
+ targ =
+ mprsas_find_target_by_handle(sassc,
+ 0, event_data->VolDevHandle);
+ if (targ) {
+ printf("%s %d: Volume handle "
+ "0x%x is already added \n",
+ __func__, __LINE__,
+ event_data->VolDevHandle);
+ break;
+ }
+ if (mprsas_volume_add(sc,
+ le16toh(event_data->
+ VolDevHandle))) {
+ printf("%s: failed to add RAID "
+ "volume with handle 0x%x\n",
+ __func__, le16toh(
+ event_data->VolDevHandle));
+ }
+ break;
+ default:
+ break;
+ }
+ break;
+ default:
+ break;
+ }
+ break;
+ }
+ case MPI2_EVENT_IR_PHYSICAL_DISK:
+ {
+ Mpi2EventDataIrPhysicalDisk_t *event_data =
+ fw_event->event_data;
+ struct mprsas_target *targ;
+
+ /*
+ * Informational only.
+ */
+ mpr_dprint(sc, MPR_EVENT, "Received IR Phys Disk event:\n");
+ switch (event_data->ReasonCode) {
+ case MPI2_EVENT_IR_PHYSDISK_RC_SETTINGS_CHANGED:
+ mpr_dprint(sc, MPR_EVENT, " Phys Disk Settings "
+ "changed from 0x%x to 0x%x for Phys Disk Number "
+ "%d and handle 0x%x at Enclosure handle 0x%x, Slot "
+ "%d", le32toh(event_data->PreviousValue),
+ le32toh(event_data->NewValue),
+ event_data->PhysDiskNum,
+ le16toh(event_data->PhysDiskDevHandle),
+ le16toh(event_data->EnclosureHandle),
+ le16toh(event_data->Slot));
+ break;
+ case MPI2_EVENT_IR_PHYSDISK_RC_STATUS_FLAGS_CHANGED:
+ mpr_dprint(sc, MPR_EVENT, " Phys Disk Status changed "
+ "from 0x%x to 0x%x for Phys Disk Number %d and "
+ "handle 0x%x at Enclosure handle 0x%x, Slot %d",
+ le32toh(event_data->PreviousValue),
+ le32toh(event_data->NewValue),
+ event_data->PhysDiskNum,
+ le16toh(event_data->PhysDiskDevHandle),
+ le16toh(event_data->EnclosureHandle),
+ le16toh(event_data->Slot));
+ break;
+ case MPI2_EVENT_IR_PHYSDISK_RC_STATE_CHANGED:
+ mpr_dprint(sc, MPR_EVENT, " Phys Disk State changed "
+ "from 0x%x to 0x%x for Phys Disk Number %d and "
+ "handle 0x%x at Enclosure handle 0x%x, Slot %d",
+ le32toh(event_data->PreviousValue),
+ le32toh(event_data->NewValue),
+ event_data->PhysDiskNum,
+ le16toh(event_data->PhysDiskDevHandle),
+ le16toh(event_data->EnclosureHandle),
+ le16toh(event_data->Slot));
+ switch (event_data->NewValue) {
+ case MPI2_RAID_PD_STATE_ONLINE:
+ case MPI2_RAID_PD_STATE_DEGRADED:
+ case MPI2_RAID_PD_STATE_REBUILDING:
+ case MPI2_RAID_PD_STATE_OPTIMAL:
+ case MPI2_RAID_PD_STATE_HOT_SPARE:
+ targ = mprsas_find_target_by_handle(
+ sassc, 0,
+ event_data->PhysDiskDevHandle);
+ if (targ) {
+ targ->flags |=
+ MPR_TARGET_FLAGS_RAID_COMPONENT;
+ printf("%s %d: Found Target "
+ "for handle 0x%x.\n",
+ __func__, __LINE__ ,
+ event_data->
+ PhysDiskDevHandle);
+ }
+ break;
+ case MPI2_RAID_PD_STATE_OFFLINE:
+ case MPI2_RAID_PD_STATE_NOT_CONFIGURED:
+ case MPI2_RAID_PD_STATE_NOT_COMPATIBLE:
+ default:
+ targ = mprsas_find_target_by_handle(
+ sassc, 0,
+ event_data->PhysDiskDevHandle);
+ if (targ) {
+ targ->flags |=
+ ~MPR_TARGET_FLAGS_RAID_COMPONENT;
+ printf("%s %d: Found Target "
+ "for handle 0x%x. \n",
+ __func__, __LINE__ ,
+ event_data->
+ PhysDiskDevHandle);
+ }
+ break;
+ }
+ default:
+ break;
+ }
+ break;
+ }
+ case MPI2_EVENT_IR_OPERATION_STATUS:
+ {
+ Mpi2EventDataIrOperationStatus_t *event_data =
+ fw_event->event_data;
+
+ /*
+ * Informational only.
+ */
+ mpr_dprint(sc, MPR_EVENT, "Received IR Op Status event:\n");
+ mpr_dprint(sc, MPR_EVENT, " RAID Operation of %d is %d "
+ "percent complete for Volume with handle 0x%x",
+ event_data->RAIDOperation, event_data->PercentComplete,
+ le16toh(event_data->VolDevHandle));
+ break;
+ }
+ case MPI2_EVENT_TEMP_THRESHOLD:
+ {
+ pMpi2EventDataTemperature_t temp_event;
+
+ temp_event = (pMpi2EventDataTemperature_t)fw_event->event_data;
+
+ /*
+ * The Temp Sensor Count must be greater than the event's Sensor
+ * Num to be valid. If valid, print the temp thresholds that
+ * have been exceeded.
+ */
+ if (sc->iounit_pg8.NumSensors > temp_event->SensorNum) {
+ mpr_dprint(sc, MPR_FAULT, "Temperature Threshold flags "
+ "%s %s %s %s exceeded for Sensor: %d !!!\n",
+ ((temp_event->Status & 0x01) == 1) ? "0 " : " ",
+ ((temp_event->Status & 0x02) == 2) ? "1 " : " ",
+ ((temp_event->Status & 0x04) == 4) ? "2 " : " ",
+ ((temp_event->Status & 0x08) == 8) ? "3 " : " ",
+ temp_event->SensorNum);
+ mpr_dprint(sc, MPR_FAULT, "Current Temp in Celsius: "
+ "%d\n", temp_event->CurrentTemperature);
+ }
+ break;
+ }
+ case MPI2_EVENT_SAS_DEVICE_STATUS_CHANGE:
+ case MPI2_EVENT_SAS_BROADCAST_PRIMITIVE:
+ default:
+ mpr_dprint(sc, MPR_TRACE,"Unhandled event 0x%0X\n",
+ fw_event->event);
+ break;
+
+ }
+ mpr_dprint(sc, MPR_EVENT, "(%d)->(%s) Event Free: [%x]\n", event_count,
+ __func__, fw_event->event);
+ mprsas_fw_event_free(sc, fw_event);
+}
+
+void
+mprsas_firmware_event_work(void *arg, int pending)
+{
+ struct mpr_fw_event_work *fw_event;
+ struct mpr_softc *sc;
+
+ sc = (struct mpr_softc *)arg;
+ mpr_lock(sc);
+ while ((fw_event = TAILQ_FIRST(&sc->sassc->ev_queue)) != NULL) {
+ TAILQ_REMOVE(&sc->sassc->ev_queue, fw_event, ev_link);
+ mprsas_fw_work(sc, fw_event);
+ }
+ mpr_unlock(sc);
+}
+
+static int
+mprsas_add_device(struct mpr_softc *sc, u16 handle, u8 linkrate){
+ char devstring[80];
+ struct mprsas_softc *sassc;
+ struct mprsas_target *targ;
+ Mpi2ConfigReply_t mpi_reply;
+ Mpi2SasDevicePage0_t config_page;
+ uint64_t sas_address, sata_sas_address;
+ uint64_t parent_sas_address = 0;
+ u16 ioc_pg8_flags = le16toh(sc->ioc_pg8.Flags);
+ u32 device_info, parent_devinfo = 0;
+ unsigned int id;
+ int ret;
+ int error = 0;
+ struct mprsas_lun *lun;
+
+ sassc = sc->sassc;
+ mprsas_startup_increment(sassc);
+ if ((mpr_config_get_sas_device_pg0(sc, &mpi_reply, &config_page,
+ MPI2_SAS_DEVICE_PGAD_FORM_HANDLE, handle))) {
+ printf("%s: error reading SAS device page0\n", __func__);
+ error = ENXIO;
+ goto out;
+ }
+
+ device_info = le32toh(config_page.DeviceInfo);
+
+ if (((device_info & MPI2_SAS_DEVICE_INFO_SMP_TARGET) == 0)
+ && (le16toh(config_page.ParentDevHandle) != 0)) {
+ Mpi2ConfigReply_t tmp_mpi_reply;
+ Mpi2SasDevicePage0_t parent_config_page;
+
+ if ((mpr_config_get_sas_device_pg0(sc, &tmp_mpi_reply,
+ &parent_config_page, MPI2_SAS_DEVICE_PGAD_FORM_HANDLE,
+ le16toh(config_page.ParentDevHandle)))) {
+ printf("%s: error reading SAS device %#x page0\n",
+ __func__, le16toh(config_page.ParentDevHandle));
+ } else {
+ parent_sas_address = parent_config_page.SASAddress.High;
+ parent_sas_address = (parent_sas_address << 32) |
+ parent_config_page.SASAddress.Low;
+ parent_devinfo = le32toh(parent_config_page.DeviceInfo);
+ }
+ }
+ /* TODO Check proper endianess */
+ sas_address = config_page.SASAddress.High;
+ sas_address = (sas_address << 32) |
+ config_page.SASAddress.Low;
+
+ if ((ioc_pg8_flags & MPI2_IOCPAGE8_FLAGS_MASK_MAPPING_MODE)
+ == MPI2_IOCPAGE8_FLAGS_DEVICE_PERSISTENCE_MAPPING) {
+ if (device_info & MPI2_SAS_DEVICE_INFO_SATA_DEVICE) {
+ ret = mprsas_get_sas_address_for_sata_disk(sc,
+ &sata_sas_address, handle, device_info);
+ if (!ret)
+ id = mpr_mapping_get_sas_id(sc,
+ sata_sas_address, handle);
+ else
+ id = mpr_mapping_get_sas_id(sc,
+ sas_address, handle);
+ } else
+ id = mpr_mapping_get_sas_id(sc, sas_address,
+ handle);
+ } else
+ id = mpr_mapping_get_sas_id(sc, sas_address, handle);
+
+ if (id == MPR_MAP_BAD_ID) {
+ printf("failure at %s:%d/%s()! Could not get ID for device "
+ "with handle 0x%04x\n", __FILE__, __LINE__, __func__,
+ handle);
+ error = ENXIO;
+ goto out;
+ }
+
+ if (mprsas_check_id(sassc, id) != 0) {
+ device_printf(sc->mpr_dev, "Excluding target id %d\n", id);
+ error = ENXIO;
+ goto out;
+ }
+
+ mpr_dprint(sc, MPR_MAPPING, "SAS Address from SAS device page0 = %jx\n",
+ sas_address);
+ targ = &sassc->targets[id];
+ targ->devinfo = device_info;
+ targ->devname = le32toh(config_page.DeviceName.High);
+ targ->devname = (targ->devname << 32) |
+ le32toh(config_page.DeviceName.Low);
+ targ->encl_handle = le16toh(config_page.EnclosureHandle);
+ targ->encl_slot = le16toh(config_page.Slot);
+ targ->encl_level = config_page.EnclosureLevel;
+ targ->connector_name[0] = config_page.ConnectorName[0];
+ targ->connector_name[1] = config_page.ConnectorName[1];
+ targ->connector_name[2] = config_page.ConnectorName[2];
+ targ->connector_name[3] = config_page.ConnectorName[3];
+ targ->handle = handle;
+ targ->parent_handle = le16toh(config_page.ParentDevHandle);
+ targ->sasaddr = mpr_to_u64(&config_page.SASAddress);
+ targ->parent_sasaddr = le64toh(parent_sas_address);
+ targ->parent_devinfo = parent_devinfo;
+ targ->tid = id;
+ targ->linkrate = (linkrate>>4);
+ targ->flags = 0;
+ if (le16toh(config_page.Flags) &
+ MPI25_SAS_DEVICE0_FLAGS_FAST_PATH_CAPABLE) {
+ targ->scsi_req_desc_type =
+ MPI25_REQ_DESCRIPT_FLAGS_FAST_PATH_SCSI_IO;
+ }
+ if (le16toh(config_page.Flags) &
+ MPI2_SAS_DEVICE0_FLAGS_ENCL_LEVEL_VALID) {
+ targ->encl_level_valid = TRUE;
+ }
+ TAILQ_INIT(&targ->commands);
+ TAILQ_INIT(&targ->timedout_commands);
+ while (!SLIST_EMPTY(&targ->luns)) {
+ lun = SLIST_FIRST(&targ->luns);
+ SLIST_REMOVE_HEAD(&targ->luns, lun_link);
+ free(lun, M_MPR);
+ }
+ SLIST_INIT(&targ->luns);
+
+ mpr_describe_devinfo(targ->devinfo, devstring, 80);
+ mpr_dprint(sc, (MPR_XINFO|MPR_MAPPING), "Found device <%s> <%s> "
+ "handle<0x%04x> enclosureHandle<0x%04x> slot %d\n", devstring,
+ mpr_describe_table(mpr_linkrate_names, targ->linkrate),
+ targ->handle, targ->encl_handle, targ->encl_slot);
+ if (targ->encl_level_valid) {
+ mpr_dprint(sc, (MPR_XINFO|MPR_MAPPING), "At enclosure level %d "
+ "and connector name (%4s)\n", targ->encl_level,
+ targ->connector_name);
+ }
+#if __FreeBSD_version < 1000039
+ if ((sassc->flags & MPRSAS_IN_STARTUP) == 0)
+#endif
+ mprsas_rescan_target(sc, targ);
+ mpr_dprint(sc, MPR_MAPPING, "Target id 0x%x added\n", targ->tid);
+out:
+ mprsas_startup_decrement(sassc);
+ return (error);
+
+}
+
+int
+mprsas_get_sas_address_for_sata_disk(struct mpr_softc *sc,
+ u64 *sas_address, u16 handle, u32 device_info)
+{
+ Mpi2SataPassthroughReply_t mpi_reply;
+ int i, rc, try_count;
+ u32 *bufferptr;
+ union _sata_sas_address hash_address;
+ struct _ata_identify_device_data ata_identify;
+ u8 buffer[MPT2SAS_MN_LEN + MPT2SAS_SN_LEN];
+ u32 ioc_status;
+ u8 sas_status;
+
+ memset(&ata_identify, 0, sizeof(ata_identify));
+ try_count = 0;
+ do {
+ rc = mprsas_get_sata_identify(sc, handle, &mpi_reply,
+ (char *)&ata_identify, sizeof(ata_identify), device_info);
+ try_count++;
+ ioc_status = le16toh(mpi_reply.IOCStatus)
+ & MPI2_IOCSTATUS_MASK;
+ sas_status = mpi_reply.SASStatus;
+ } while ((rc == -EAGAIN || ioc_status || sas_status) &&
+ (try_count < 5));
+
+ if (rc == 0 && !ioc_status && !sas_status) {
+ mpr_dprint(sc, MPR_MAPPING, "%s: got SATA identify "
+ "successfully for handle = 0x%x with try_count = %d\n",
+ __func__, handle, try_count);
+ } else {
+ mpr_dprint(sc, MPR_MAPPING, "%s: handle = 0x%x failed\n",
+ __func__, handle);
+ return -1;
+ }
+ /* Copy & byteswap the 40 byte model number to a buffer */
+ for (i = 0; i < MPT2SAS_MN_LEN; i += 2) {
+ buffer[i] = ((u8 *)ata_identify.model_number)[i + 1];
+ buffer[i + 1] = ((u8 *)ata_identify.model_number)[i];
+ }
+ /* Copy & byteswap the 20 byte serial number to a buffer */
+ for (i = 0; i < MPT2SAS_SN_LEN; i += 2) {
+ buffer[MPT2SAS_MN_LEN + i] =
+ ((u8 *)ata_identify.serial_number)[i + 1];
+ buffer[MPT2SAS_MN_LEN + i + 1] =
+ ((u8 *)ata_identify.serial_number)[i];
+ }
+ bufferptr = (u32 *)buffer;
+ /* There are 60 bytes to hash down to 8. 60 isn't divisible by 8,
+ * so loop through the first 56 bytes (7*8),
+ * and then add in the last dword.
+ */
+ hash_address.word.low = 0;
+ hash_address.word.high = 0;
+ for (i = 0; (i < ((MPT2SAS_MN_LEN+MPT2SAS_SN_LEN)/8)); i++) {
+ hash_address.word.low += *bufferptr;
+ bufferptr++;
+ hash_address.word.high += *bufferptr;
+ bufferptr++;
+ }
+ /* Add the last dword */
+ hash_address.word.low += *bufferptr;
+ /* Make sure the hash doesn't start with 5, because it could clash
+ * with a SAS address. Change 5 to a D.
+ */
+ if ((hash_address.word.high & 0x000000F0) == (0x00000050))
+ hash_address.word.high |= 0x00000080;
+ *sas_address = (u64)hash_address.wwid[0] << 56 |
+ (u64)hash_address.wwid[1] << 48 | (u64)hash_address.wwid[2] << 40 |
+ (u64)hash_address.wwid[3] << 32 | (u64)hash_address.wwid[4] << 24 |
+ (u64)hash_address.wwid[5] << 16 | (u64)hash_address.wwid[6] << 8 |
+ (u64)hash_address.wwid[7];
+ return 0;
+}
+
+static int
+mprsas_get_sata_identify(struct mpr_softc *sc, u16 handle,
+ Mpi2SataPassthroughReply_t *mpi_reply, char *id_buffer, int sz, u32 devinfo)
+{
+ Mpi2SataPassthroughRequest_t *mpi_request;
+ Mpi2SataPassthroughReply_t *reply;
+ struct mpr_command *cm;
+ char *buffer;
+ int error = 0;
+
+ buffer = malloc( sz, M_MPR, M_NOWAIT | M_ZERO);
+ if (!buffer)
+ return ENOMEM;
+
+ if ((cm = mpr_alloc_command(sc)) == NULL) {
+ free(buffer, M_MPR);
+ return (EBUSY);
+ }
+ mpi_request = (MPI2_SATA_PASSTHROUGH_REQUEST *)cm->cm_req;
+ bzero(mpi_request,sizeof(MPI2_SATA_PASSTHROUGH_REQUEST));
+ mpi_request->Function = MPI2_FUNCTION_SATA_PASSTHROUGH;
+ mpi_request->VF_ID = 0;
+ mpi_request->DevHandle = htole16(handle);
+ mpi_request->PassthroughFlags = (MPI2_SATA_PT_REQ_PT_FLAGS_PIO |
+ MPI2_SATA_PT_REQ_PT_FLAGS_READ);
+ mpi_request->DataLength = htole32(sz);
+ mpi_request->CommandFIS[0] = 0x27;
+ mpi_request->CommandFIS[1] = 0x80;
+ mpi_request->CommandFIS[2] = (devinfo &
+ MPI2_SAS_DEVICE_INFO_ATAPI_DEVICE) ? 0xA1 : 0xEC;
+ cm->cm_sge = &mpi_request->SGL;
+ cm->cm_sglsize = sizeof(MPI2_SGE_IO_UNION);
+ cm->cm_flags = MPR_CM_FLAGS_DATAIN;
+ cm->cm_desc.Default.RequestFlags = MPI2_REQ_DESCRIPT_FLAGS_DEFAULT_TYPE;
+ cm->cm_data = buffer;
+ cm->cm_length = htole32(sz);
+ error = mpr_wait_command(sc, cm, 60, CAN_SLEEP);
+ reply = (Mpi2SataPassthroughReply_t *)cm->cm_reply;
+ if (error || (reply == NULL)) {
+ /* FIXME */
+ /*
+ * If the request returns an error then we need to do a diag
+ * reset
+ */
+ printf("%s: request for page completed with error %d",
+ __func__, error);
+ error = ENXIO;
+ goto out;
+ }
+ bcopy(buffer, id_buffer, sz);
+ bcopy(reply, mpi_reply, sizeof(Mpi2SataPassthroughReply_t));
+ if ((le16toh(reply->IOCStatus) & MPI2_IOCSTATUS_MASK) !=
+ MPI2_IOCSTATUS_SUCCESS) {
+ printf("%s: error reading SATA PASSTHRU; iocstatus = 0x%x\n",
+ __func__, reply->IOCStatus);
+ error = ENXIO;
+ goto out;
+ }
+out:
+ mpr_free_command(sc, cm);
+ free(buffer, M_MPR);
+ return (error);
+}
+
+static int
+mprsas_volume_add(struct mpr_softc *sc, u16 handle)
+{
+ struct mprsas_softc *sassc;
+ struct mprsas_target *targ;
+ u64 wwid;
+ unsigned int id;
+ int error = 0;
+ struct mprsas_lun *lun;
+
+ sassc = sc->sassc;
+ mprsas_startup_increment(sassc);
+ /* wwid is endian safe */
+ mpr_config_get_volume_wwid(sc, handle, &wwid);
+ if (!wwid) {
+ printf("%s: invalid WWID; cannot add volume to mapping table\n",
+ __func__);
+ error = ENXIO;
+ goto out;
+ }
+
+ id = mpr_mapping_get_raid_id(sc, wwid, handle);
+ if (id == MPR_MAP_BAD_ID) {
+ printf("%s: could not get ID for volume with handle 0x%04x and "
+ "WWID 0x%016llx\n", __func__, handle,
+ (unsigned long long)wwid);
+ error = ENXIO;
+ goto out;
+ }
+
+ targ = &sassc->targets[id];
+ targ->tid = id;
+ targ->handle = handle;
+ targ->devname = wwid;
+ TAILQ_INIT(&targ->commands);
+ TAILQ_INIT(&targ->timedout_commands);
+ while (!SLIST_EMPTY(&targ->luns)) {
+ lun = SLIST_FIRST(&targ->luns);
+ SLIST_REMOVE_HEAD(&targ->luns, lun_link);
+ free(lun, M_MPR);
+ }
+ SLIST_INIT(&targ->luns);
+#if __FreeBSD_version < 1000039
+ if ((sassc->flags & MPRSAS_IN_STARTUP) == 0)
+#endif
+ mprsas_rescan_target(sc, targ);
+ mpr_dprint(sc, MPR_MAPPING, "RAID target id %d added (WWID = 0x%jx)\n",
+ targ->tid, wwid);
+out:
+ mprsas_startup_decrement(sassc);
+ return (error);
+}
+
+/**
+ * mprsas_SSU_to_SATA_devices
+ * @sc: per adapter object
+ *
+ * Looks through the target list and issues a StartStopUnit SCSI command to each
+ * SATA direct-access device. This helps to ensure that data corruption is
+ * avoided when the system is being shut down. This must be called after the IR
+ * System Shutdown RAID Action is sent if in IR mode.
+ *
+ * Return nothing.
+ */
+static void
+mprsas_SSU_to_SATA_devices(struct mpr_softc *sc)
+{
+ struct mprsas_softc *sassc = sc->sassc;
+ union ccb *ccb;
+ path_id_t pathid = cam_sim_path(sassc->sim);
+ target_id_t targetid;
+ struct mprsas_target *target;
+ struct mprsas_lun *lun;
+ char path_str[64];
+ struct timeval cur_time, start_time;
+
+ /*
+ * For each LUN of each target, issue a StartStopUnit command to stop
+ * the device.
+ */
+ sc->SSU_started = TRUE;
+ sc->SSU_refcount = 0;
+ for (targetid = 0; targetid < sc->facts->MaxTargets; targetid++) {
+ target = &sassc->targets[targetid];
+ if (target->handle == 0x0) {
+ continue;
+ }
+
+ SLIST_FOREACH(lun, &target->luns, lun_link) {
+ ccb = xpt_alloc_ccb_nowait();
+ if (ccb == NULL) {
+ mpr_dprint(sc, MPR_FAULT, "Unable to alloc "
+ "CCB to stop unit.\n");
+ return;
+ }
+
+ /*
+ * The stop_at_shutdown flag will be set if this LUN is
+ * a SATA direct-access end device.
+ */
+ if (lun->stop_at_shutdown) {
+ if (xpt_create_path(&ccb->ccb_h.path,
+ xpt_periph, pathid, targetid,
+ lun->lun_id) != CAM_REQ_CMP) {
+ mpr_dprint(sc, MPR_FAULT, "Unable to "
+ "create LUN path to stop unit.\n");
+ xpt_free_ccb(ccb);
+ return;
+ }
+ xpt_path_string(ccb->ccb_h.path, path_str,
+ sizeof(path_str));
+
+ mpr_dprint(sc, MPR_INFO, "Sending StopUnit: "
+ "path %s handle %d\n", path_str,
+ target->handle);
+
+ /*
+ * Issue a START STOP UNIT command for the LUN.
+ * Increment the SSU counter to be used to
+ * count the number of required replies.
+ */
+ mpr_dprint(sc, MPR_INFO, "Incrementing SSU "
+ "count\n");
+ sc->SSU_refcount++;
+ ccb->ccb_h.target_id =
+ xpt_path_target_id(ccb->ccb_h.path);
+ ccb->ccb_h.target_lun = lun->lun_id;
+ ccb->ccb_h.ppriv_ptr1 = sassc;
+ scsi_start_stop(&ccb->csio,
+ /*retries*/0,
+ mprsas_stop_unit_done,
+ MSG_SIMPLE_Q_TAG,
+ /*start*/FALSE,
+ /*load/eject*/0,
+ /*immediate*/FALSE,
+ MPR_SENSE_LEN,
+ /*timeout*/10000);
+ xpt_action(ccb);
+ }
+ }
+ }
+
+ /*
+ * Wait until all of the SSU commands have completed or time has
+ * expired (60 seconds). pause for 100ms each time through. If any
+ * command times out, the target will be reset in the SCSI command
+ * timeout routine.
+ */
+ getmicrotime(&start_time);
+ while (sc->SSU_refcount) {
+ pause("mprwait", hz/10);
+
+ getmicrotime(&cur_time);
+ if ((cur_time.tv_sec - start_time.tv_sec) > 60) {
+ mpr_dprint(sc, MPR_FAULT, "Time has expired waiting "
+ "for SSU commands to complete.\n");
+ break;
+ }
+ }
+}
+
+static void
+mprsas_stop_unit_done(struct cam_periph *periph, union ccb *done_ccb)
+{
+ struct mprsas_softc *sassc;
+ char path_str[64];
+
+ sassc = (struct mprsas_softc *)done_ccb->ccb_h.ppriv_ptr1;
+
+ xpt_path_string(done_ccb->ccb_h.path, path_str, sizeof(path_str));
+ mpr_dprint(sassc->sc, MPR_INFO, "Completing stop unit for %s\n",
+ path_str);
+
+ if (done_ccb == NULL)
+ return;
+
+ /*
+ * Nothing more to do except free the CCB and path. If the command
+ * timed out, an abort reset, then target reset will be issued during
+ * the SCSI Command process.
+ */
+ xpt_free_path(done_ccb->ccb_h.path);
+ xpt_free_ccb(done_ccb);
+}
+
+/**
+ * mprsas_ir_shutdown - IR shutdown notification
+ * @sc: per adapter object
+ *
+ * Sending RAID Action to alert the Integrated RAID subsystem of the IOC that
+ * the host system is shutting down.
+ *
+ * Return nothing.
+ */
+void
+mprsas_ir_shutdown(struct mpr_softc *sc)
+{
+ u16 volume_mapping_flags;
+ u16 ioc_pg8_flags = le16toh(sc->ioc_pg8.Flags);
+ struct dev_mapping_table *mt_entry;
+ u32 start_idx, end_idx;
+ unsigned int id, found_volume = 0;
+ struct mpr_command *cm;
+ Mpi2RaidActionRequest_t *action;
+
+ mpr_dprint(sc, MPR_TRACE, "%s\n", __func__);
+
+ /* is IR firmware build loaded? */
+ if (!sc->ir_firmware)
+ goto out;
+
+ /* are there any volumes? Look at IR target IDs. */
+ // TODO-later, this should be looked up in the RAID config structure
+ // when it is implemented.
+ volume_mapping_flags = le16toh(sc->ioc_pg8.IRVolumeMappingFlags) &
+ MPI2_IOCPAGE8_IRFLAGS_MASK_VOLUME_MAPPING_MODE;
+ if (volume_mapping_flags == MPI2_IOCPAGE8_IRFLAGS_LOW_VOLUME_MAPPING) {
+ start_idx = 0;
+ if (ioc_pg8_flags & MPI2_IOCPAGE8_FLAGS_RESERVED_TARGETID_0)
+ start_idx = 1;
+ } else
+ start_idx = sc->max_devices - sc->max_volumes;
+ end_idx = start_idx + sc->max_volumes - 1;
+
+ for (id = start_idx; id < end_idx; id++) {
+ mt_entry = &sc->mapping_table[id];
+ if ((mt_entry->physical_id != 0) &&
+ (mt_entry->missing_count == 0)) {
+ found_volume = 1;
+ break;
+ }
+ }
+
+ if (!found_volume)
+ goto out;
+
+ if ((cm = mpr_alloc_command(sc)) == NULL) {
+ printf("%s: command alloc failed\n", __func__);
+ goto out;
+ }
+
+ action = (MPI2_RAID_ACTION_REQUEST *)cm->cm_req;
+ action->Function = MPI2_FUNCTION_RAID_ACTION;
+ action->Action = MPI2_RAID_ACTION_SYSTEM_SHUTDOWN_INITIATED;
+ cm->cm_desc.Default.RequestFlags = MPI2_REQ_DESCRIPT_FLAGS_DEFAULT_TYPE;
+ mpr_lock(sc);
+ mpr_wait_command(sc, cm, 5, CAN_SLEEP);
+ mpr_unlock(sc);
+
+ /*
+ * Don't check for reply, just leave.
+ */
+ if (cm)
+ mpr_free_command(sc, cm);
+
+out:
+ mprsas_SSU_to_SATA_devices(sc);
+}
diff --git a/sys/dev/mpr/mpr_table.c b/sys/dev/mpr/mpr_table.c
new file mode 100644
index 0000000..b1e12b3
--- /dev/null
+++ b/sys/dev/mpr/mpr_table.c
@@ -0,0 +1,516 @@
+/*-
+ * Copyright (c) 2009 Yahoo! Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+/* Debugging tables for MPT2 */
+
+/* TODO Move headers to mprvar */
+#include <sys/types.h>
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/kernel.h>
+#include <sys/selinfo.h>
+#include <sys/module.h>
+#include <sys/bus.h>
+#include <sys/conf.h>
+#include <sys/bio.h>
+#include <sys/malloc.h>
+#include <sys/uio.h>
+#include <sys/sysctl.h>
+#include <sys/queue.h>
+#include <sys/kthread.h>
+#include <sys/taskqueue.h>
+
+#include <machine/bus.h>
+#include <machine/resource.h>
+#include <sys/rman.h>
+
+#include <cam/scsi/scsi_all.h>
+
+#include <dev/mpr/mpi/mpi2_type.h>
+#include <dev/mpr/mpi/mpi2.h>
+#include <dev/mpr/mpi/mpi2_ioc.h>
+#include <dev/mpr/mpi/mpi2_cnfg.h>
+#include <dev/mpr/mpi/mpi2_init.h>
+#include <dev/mpr/mpi/mpi2_tool.h>
+#include <dev/mpr/mpr_ioctl.h>
+#include <dev/mpr/mprvar.h>
+#include <dev/mpr/mpr_table.h>
+
+char *
+mpr_describe_table(struct mpr_table_lookup *table, u_int code)
+{
+ int i;
+
+ for (i = 0; table[i].string != NULL; i++) {
+ if (table[i].code == code)
+ return(table[i].string);
+ }
+ return(table[i+1].string);
+}
+
+struct mpr_table_lookup mpr_event_names[] = {
+ {"LogData", 0x01},
+ {"StateChange", 0x02},
+ {"HardResetReceived", 0x05},
+ {"EventChange", 0x0a},
+ {"TaskSetFull", 0x0e},
+ {"SasDeviceStatusChange", 0x0f},
+ {"IrOperationStatus", 0x14},
+ {"SasDiscovery", 0x16},
+ {"SasBroadcastPrimitive", 0x17},
+ {"SasInitDeviceStatusChange", 0x18},
+ {"SasInitTableOverflow", 0x19},
+ {"SasTopologyChangeList", 0x1c},
+ {"SasEnclDeviceStatusChange", 0x1d},
+ {"IrVolume", 0x1e},
+ {"IrPhysicalDisk", 0x1f},
+ {"IrConfigurationChangeList", 0x20},
+ {"LogEntryAdded", 0x21},
+ {"SasPhyCounter", 0x22},
+ {"GpioInterrupt", 0x23},
+ {"HbdPhyEvent", 0x24},
+ {NULL, 0},
+ {"Unknown Event", 0}
+};
+
+struct mpr_table_lookup mpr_phystatus_names[] = {
+ {"NewTargetAdded", 0x01},
+ {"TargetGone", 0x02},
+ {"PHYLinkStatusChange", 0x03},
+ {"PHYLinkStatusUnchanged", 0x04},
+ {"TargetMissing", 0x05},
+ {NULL, 0},
+ {"Unknown Status", 0}
+};
+
+struct mpr_table_lookup mpr_linkrate_names[] = {
+ {"PHY disabled", 0x01},
+ {"Speed Negotiation Failed", 0x02},
+ {"SATA OOB Complete", 0x03},
+ {"SATA Port Selector", 0x04},
+ {"SMP Reset in Progress", 0x05},
+ {"1.5Gbps", 0x08},
+ {"3.0Gbps", 0x09},
+ {"6.0Gbps", 0x0a},
+ {NULL, 0},
+ {"LinkRate Unknown", 0x00}
+};
+
+struct mpr_table_lookup mpr_sasdev0_devtype[] = {
+ {"End Device", 0x01},
+ {"Edge Expander", 0x02},
+ {"Fanout Expander", 0x03},
+ {NULL, 0},
+ {"No Device", 0x00}
+};
+
+struct mpr_table_lookup mpr_phyinfo_reason_names[] = {
+ {"Power On", 0x01},
+ {"Hard Reset", 0x02},
+ {"SMP Phy Control Link Reset", 0x03},
+ {"Loss DWORD Sync", 0x04},
+ {"Multiplex Sequence", 0x05},
+ {"I-T Nexus Loss Timer", 0x06},
+ {"Break Timeout Timer", 0x07},
+ {"PHY Test Function", 0x08},
+ {NULL, 0},
+ {"Unknown Reason", 0x00}
+};
+
+struct mpr_table_lookup mpr_whoinit_names[] = {
+ {"System BIOS", 0x01},
+ {"ROM BIOS", 0x02},
+ {"PCI Peer", 0x03},
+ {"Host Driver", 0x04},
+ {"Manufacturing", 0x05},
+ {NULL, 0},
+ {"Not Initialized", 0x00}
+};
+
+struct mpr_table_lookup mpr_sasdisc_reason[] = {
+ {"Discovery Started", 0x01},
+ {"Discovery Complete", 0x02},
+ {NULL, 0},
+ {"Unknown", 0x00}
+};
+
+struct mpr_table_lookup mpr_sastopo_exp[] = {
+ {"Added", 0x01},
+ {"Not Responding", 0x02},
+ {"Responding", 0x03},
+ {"Delay Not Responding", 0x04},
+ {NULL, 0},
+ {"Unknown", 0x00}
+};
+
+struct mpr_table_lookup mpr_sasdev_reason[] = {
+ {"SMART Data", 0x05},
+ {"Unsupported", 0x07},
+ {"Internal Device Reset", 0x08},
+ {"Task Abort Internal", 0x09},
+ {"Abort Task Set Internal", 0x0a},
+ {"Clear Task Set Internal", 0x0b},
+ {"Query Task Internal", 0x0c},
+ {"Async Notification", 0x0d},
+ {"Cmp Internal Device Reset", 0x0e},
+ {"Cmp Task Abort Internal", 0x0f},
+ {"Sata Init Failure", 0x10},
+ {NULL, 0},
+ {"Unknown", 0x00}
+};
+
+void
+mpr_describe_devinfo(uint32_t devinfo, char *string, int len)
+{
+ snprintf(string, len, "%b,%s", devinfo,
+ "\20" "\4SataHost" "\5SmpInit" "\6StpInit" "\7SspInit"
+ "\10SataDev" "\11SmpTarg" "\12StpTarg" "\13SspTarg" "\14Direct"
+ "\15LsiDev" "\16AtapiDev" "\17SepDev",
+ mpr_describe_table(mpr_sasdev0_devtype, devinfo & 0x03));
+}
+
+void
+mpr_print_iocfacts(struct mpr_softc *sc, MPI2_IOC_FACTS_REPLY *facts)
+{
+
+ MPR_PRINTFIELD_START(sc, "IOCFacts");
+ MPR_PRINTFIELD(sc, facts, MsgVersion, 0x%x);
+ MPR_PRINTFIELD(sc, facts, HeaderVersion, 0x%x);
+ MPR_PRINTFIELD(sc, facts, IOCNumber, %d);
+ MPR_PRINTFIELD(sc, facts, IOCExceptions, 0x%x);
+ MPR_PRINTFIELD(sc, facts, MaxChainDepth, %d);
+ mpr_dprint_field(sc, MPR_XINFO, "WhoInit: %s\n",
+ mpr_describe_table(mpr_whoinit_names, facts->WhoInit));
+ MPR_PRINTFIELD(sc, facts, NumberOfPorts, %d);
+ MPR_PRINTFIELD(sc, facts, RequestCredit, %d);
+ MPR_PRINTFIELD(sc, facts, ProductID, 0x%x);
+ mpr_dprint_field(sc, MPR_XINFO, "IOCCapabilities: %b\n",
+ facts->IOCCapabilities, "\20" "\3ScsiTaskFull" "\4DiagTrace"
+ "\5SnapBuf" "\6ExtBuf" "\7EEDP" "\10BiDirTarg" "\11Multicast"
+ "\14TransRetry" "\15IR" "\16EventReplay" "\17RaidAccel"
+ "\20MSIXIndex" "\21HostDisc");
+ mpr_dprint_field(sc, MPR_XINFO, "FWVersion= %d-%d-%d-%d\n",
+ facts->FWVersion.Struct.Major,
+ facts->FWVersion.Struct.Minor,
+ facts->FWVersion.Struct.Unit,
+ facts->FWVersion.Struct.Dev);
+ MPR_PRINTFIELD(sc, facts, IOCRequestFrameSize, %d);
+ MPR_PRINTFIELD(sc, facts, MaxInitiators, %d);
+ MPR_PRINTFIELD(sc, facts, MaxTargets, %d);
+ MPR_PRINTFIELD(sc, facts, MaxSasExpanders, %d);
+ MPR_PRINTFIELD(sc, facts, MaxEnclosures, %d);
+ mpr_dprint_field(sc, MPR_XINFO, "ProtocolFlags: %b\n",
+ facts->ProtocolFlags, "\20" "\1ScsiTarg" "\2ScsiInit");
+ MPR_PRINTFIELD(sc, facts, HighPriorityCredit, %d);
+ MPR_PRINTFIELD(sc, facts, MaxReplyDescriptorPostQueueDepth, %d);
+ MPR_PRINTFIELD(sc, facts, ReplyFrameSize, %d);
+ MPR_PRINTFIELD(sc, facts, MaxVolumes, %d);
+ MPR_PRINTFIELD(sc, facts, MaxDevHandle, %d);
+ MPR_PRINTFIELD(sc, facts, MaxPersistentEntries, %d);
+}
+
+void
+mpr_print_portfacts(struct mpr_softc *sc, MPI2_PORT_FACTS_REPLY *facts)
+{
+
+ MPR_PRINTFIELD_START(sc, "PortFacts");
+ MPR_PRINTFIELD(sc, facts, PortNumber, %d);
+ MPR_PRINTFIELD(sc, facts, PortType, 0x%x);
+ MPR_PRINTFIELD(sc, facts, MaxPostedCmdBuffers, %d);
+}
+
+void
+mpr_print_event(struct mpr_softc *sc, MPI2_EVENT_NOTIFICATION_REPLY *event)
+{
+
+ MPR_EVENTFIELD_START(sc, "EventReply");
+ MPR_EVENTFIELD(sc, event, EventDataLength, %d);
+ MPR_EVENTFIELD(sc, event, AckRequired, %d);
+ mpr_dprint_field(sc, MPR_EVENT, "Event: %s (0x%x)\n",
+ mpr_describe_table(mpr_event_names, event->Event), event->Event);
+ MPR_EVENTFIELD(sc, event, EventContext, 0x%x);
+}
+
+void
+mpr_print_sasdev0(struct mpr_softc *sc, MPI2_CONFIG_PAGE_SAS_DEV_0 *buf)
+{
+ MPR_PRINTFIELD_START(sc, "SAS Device Page 0");
+ MPR_PRINTFIELD(sc, buf, Slot, %d);
+ MPR_PRINTFIELD(sc, buf, EnclosureHandle, 0x%x);
+ mpr_dprint_field(sc, MPR_XINFO, "SASAddress: 0x%jx\n",
+ mpr_to_u64(&buf->SASAddress));
+ MPR_PRINTFIELD(sc, buf, ParentDevHandle, 0x%x);
+ MPR_PRINTFIELD(sc, buf, PhyNum, %d);
+ MPR_PRINTFIELD(sc, buf, AccessStatus, 0x%x);
+ MPR_PRINTFIELD(sc, buf, DevHandle, 0x%x);
+ MPR_PRINTFIELD(sc, buf, AttachedPhyIdentifier, 0x%x);
+ MPR_PRINTFIELD(sc, buf, ZoneGroup, %d);
+ mpr_dprint_field(sc, MPR_XINFO, "DeviceInfo: %b,%s\n", buf->DeviceInfo,
+ "\20" "\4SataHost" "\5SmpInit" "\6StpInit" "\7SspInit"
+ "\10SataDev" "\11SmpTarg" "\12StpTarg" "\13SspTarg" "\14Direct"
+ "\15LsiDev" "\16AtapiDev" "\17SepDev",
+ mpr_describe_table(mpr_sasdev0_devtype, buf->DeviceInfo & 0x03));
+ MPR_PRINTFIELD(sc, buf, Flags, 0x%x);
+ MPR_PRINTFIELD(sc, buf, PhysicalPort, %d);
+ MPR_PRINTFIELD(sc, buf, MaxPortConnections, %d);
+ mpr_dprint_field(sc, MPR_XINFO, "DeviceName: 0x%jx\n",
+ mpr_to_u64(&buf->DeviceName));
+ MPR_PRINTFIELD(sc, buf, PortGroups, %d);
+ MPR_PRINTFIELD(sc, buf, DmaGroup, %d);
+ MPR_PRINTFIELD(sc, buf, ControlGroup, %d);
+}
+
+void
+mpr_print_evt_sas(struct mpr_softc *sc, MPI2_EVENT_NOTIFICATION_REPLY *event)
+{
+
+ mpr_print_event(sc, event);
+
+ switch(event->Event) {
+ case MPI2_EVENT_SAS_DISCOVERY:
+ {
+ MPI2_EVENT_DATA_SAS_DISCOVERY *data;
+
+ data = (MPI2_EVENT_DATA_SAS_DISCOVERY *)&event->EventData;
+ mpr_dprint_field(sc, MPR_EVENT, "Flags: %b\n", data->Flags,
+ "\20" "\1InProgress" "\2DeviceChange");
+ mpr_dprint_field(sc, MPR_EVENT, "ReasonCode: %s\n",
+ mpr_describe_table(mpr_sasdisc_reason, data->ReasonCode));
+ MPR_EVENTFIELD(sc, data, PhysicalPort, %d);
+ mpr_dprint_field(sc, MPR_EVENT, "DiscoveryStatus: %b\n",
+ data->DiscoveryStatus, "\20"
+ "\1Loop" "\2UnaddressableDev" "\3DupSasAddr" "\5SmpTimeout"
+ "\6ExpRouteFull" "\7RouteIndexError" "\10SmpFailed"
+ "\11SmpCrcError" "\12SubSubLink" "\13TableTableLink"
+ "\14UnsupDevice" "\15TableSubLink" "\16MultiDomain"
+ "\17MultiSub" "\20MultiSubSub" "\34DownstreamInit"
+ "\35MaxPhys" "\36MaxTargs" "\37MaxExpanders"
+ "\40MaxEnclosures");
+ break;
+ }
+ case MPI2_EVENT_SAS_TOPOLOGY_CHANGE_LIST:
+ {
+ MPI2_EVENT_DATA_SAS_TOPOLOGY_CHANGE_LIST *data;
+ MPI2_EVENT_SAS_TOPO_PHY_ENTRY *phy;
+ int i, phynum;
+
+ data = (MPI2_EVENT_DATA_SAS_TOPOLOGY_CHANGE_LIST *)
+ &event->EventData;
+ MPR_EVENTFIELD(sc, data, EnclosureHandle, 0x%x);
+ MPR_EVENTFIELD(sc, data, ExpanderDevHandle, 0x%x);
+ MPR_EVENTFIELD(sc, data, NumPhys, %d);
+ MPR_EVENTFIELD(sc, data, NumEntries, %d);
+ MPR_EVENTFIELD(sc, data, StartPhyNum, %d);
+ mpr_dprint_field(sc, MPR_EVENT, "ExpStatus: %s (0x%x)\n",
+ mpr_describe_table(mpr_sastopo_exp, data->ExpStatus),
+ data->ExpStatus);
+ MPR_EVENTFIELD(sc, data, PhysicalPort, %d);
+ for (i = 0; i < data->NumEntries; i++) {
+ phy = &data->PHY[i];
+ phynum = data->StartPhyNum + i;
+ mpr_dprint_field(sc, MPR_EVENT,
+ "PHY[%d].AttachedDevHandle: 0x%04x\n", phynum,
+ phy->AttachedDevHandle);
+ mpr_dprint_field(sc, MPR_EVENT,
+ "PHY[%d].LinkRate: %s (0x%x)\n", phynum,
+ mpr_describe_table(mpr_linkrate_names,
+ (phy->LinkRate >> 4) & 0xf), phy->LinkRate);
+ mpr_dprint_field(sc,MPR_EVENT,"PHY[%d].PhyStatus: "
+ "%s\n", phynum,
+ mpr_describe_table(mpr_phystatus_names,
+ phy->PhyStatus));
+ }
+ break;
+ }
+ case MPI2_EVENT_SAS_ENCL_DEVICE_STATUS_CHANGE:
+ {
+ MPI2_EVENT_DATA_SAS_ENCL_DEV_STATUS_CHANGE *data;
+
+ data = (MPI2_EVENT_DATA_SAS_ENCL_DEV_STATUS_CHANGE *)
+ &event->EventData;
+ MPR_EVENTFIELD(sc, data, EnclosureHandle, 0x%x);
+ mpr_dprint_field(sc, MPR_EVENT, "ReasonCode: %s\n",
+ mpr_describe_table(mpr_sastopo_exp, data->ReasonCode));
+ MPR_EVENTFIELD(sc, data, PhysicalPort, %d);
+ MPR_EVENTFIELD(sc, data, NumSlots, %d);
+ MPR_EVENTFIELD(sc, data, StartSlot, %d);
+ MPR_EVENTFIELD(sc, data, PhyBits, 0x%x);
+ break;
+ }
+ case MPI2_EVENT_SAS_DEVICE_STATUS_CHANGE:
+ {
+ MPI2_EVENT_DATA_SAS_DEVICE_STATUS_CHANGE *data;
+
+ data = (MPI2_EVENT_DATA_SAS_DEVICE_STATUS_CHANGE *)
+ &event->EventData;
+ MPR_EVENTFIELD(sc, data, TaskTag, 0x%x);
+ mpr_dprint_field(sc, MPR_EVENT, "ReasonCode: %s\n",
+ mpr_describe_table(mpr_sasdev_reason, data->ReasonCode));
+ MPR_EVENTFIELD(sc, data, ASC, 0x%x);
+ MPR_EVENTFIELD(sc, data, ASCQ, 0x%x);
+ MPR_EVENTFIELD(sc, data, DevHandle, 0x%x);
+ mpr_dprint_field(sc, MPR_EVENT, "SASAddress: 0x%jx\n",
+ mpr_to_u64(&data->SASAddress));
+ }
+ default:
+ break;
+ }
+}
+
+void
+mpr_print_expander1(struct mpr_softc *sc, MPI2_CONFIG_PAGE_EXPANDER_1 *buf)
+{
+ MPR_PRINTFIELD_START(sc, "SAS Expander Page 1 #%d", buf->Phy);
+ MPR_PRINTFIELD(sc, buf, PhysicalPort, %d);
+ MPR_PRINTFIELD(sc, buf, NumPhys, %d);
+ MPR_PRINTFIELD(sc, buf, Phy, %d);
+ MPR_PRINTFIELD(sc, buf, NumTableEntriesProgrammed, %d);
+ mpr_dprint_field(sc, MPR_XINFO, "ProgrammedLinkRate: %s (0x%x)\n",
+ mpr_describe_table(mpr_linkrate_names,
+ (buf->ProgrammedLinkRate >> 4) & 0xf), buf->ProgrammedLinkRate);
+ mpr_dprint_field(sc, MPR_XINFO, "HwLinkRate: %s (0x%x)\n",
+ mpr_describe_table(mpr_linkrate_names,
+ (buf->HwLinkRate >> 4) & 0xf), buf->HwLinkRate);
+ MPR_PRINTFIELD(sc, buf, AttachedDevHandle, 0x%04x);
+ mpr_dprint_field(sc, MPR_XINFO, "PhyInfo Reason: %s (0x%x)\n",
+ mpr_describe_table(mpr_phyinfo_reason_names,
+ (buf->PhyInfo >> 16) & 0xf), buf->PhyInfo);
+ mpr_dprint_field(sc, MPR_XINFO, "AttachedDeviceInfo: %b,%s\n",
+ buf->AttachedDeviceInfo, "\20" "\4SATAhost" "\5SMPinit" "\6STPinit"
+ "\7SSPinit" "\10SATAdev" "\11SMPtarg" "\12STPtarg" "\13SSPtarg"
+ "\14Direct" "\15LSIdev" "\16ATAPIdev" "\17SEPdev",
+ mpr_describe_table(mpr_sasdev0_devtype,
+ buf->AttachedDeviceInfo & 0x03));
+ MPR_PRINTFIELD(sc, buf, ExpanderDevHandle, 0x%04x);
+ MPR_PRINTFIELD(sc, buf, ChangeCount, %d);
+ mpr_dprint_field(sc, MPR_XINFO, "NegotiatedLinkRate: %s (0x%x)\n",
+ mpr_describe_table(mpr_linkrate_names,
+ buf->NegotiatedLinkRate & 0xf), buf->NegotiatedLinkRate);
+ MPR_PRINTFIELD(sc, buf, PhyIdentifier, %d);
+ MPR_PRINTFIELD(sc, buf, AttachedPhyIdentifier, %d);
+ MPR_PRINTFIELD(sc, buf, DiscoveryInfo, 0x%x);
+ MPR_PRINTFIELD(sc, buf, AttachedPhyInfo, 0x%x);
+ mpr_dprint_field(sc, MPR_XINFO, "AttachedPhyInfo Reason: %s (0x%x)\n",
+ mpr_describe_table(mpr_phyinfo_reason_names,
+ buf->AttachedPhyInfo & 0xf), buf->AttachedPhyInfo);
+ MPR_PRINTFIELD(sc, buf, ZoneGroup, %d);
+ MPR_PRINTFIELD(sc, buf, SelfConfigStatus, 0x%x);
+}
+
+void
+mpr_print_sasphy0(struct mpr_softc *sc, MPI2_CONFIG_PAGE_SAS_PHY_0 *buf)
+{
+ MPR_PRINTFIELD_START(sc, "SAS PHY Page 0");
+ MPR_PRINTFIELD(sc, buf, OwnerDevHandle, 0x%04x);
+ MPR_PRINTFIELD(sc, buf, AttachedDevHandle, 0x%04x);
+ MPR_PRINTFIELD(sc, buf, AttachedPhyIdentifier, %d);
+ mpr_dprint_field(sc, MPR_XINFO, "AttachedPhyInfo Reason: %s (0x%x)\n",
+ mpr_describe_table(mpr_phyinfo_reason_names,
+ buf->AttachedPhyInfo & 0xf), buf->AttachedPhyInfo);
+ mpr_dprint_field(sc, MPR_XINFO, "ProgrammedLinkRate: %s (0x%x)\n",
+ mpr_describe_table(mpr_linkrate_names,
+ (buf->ProgrammedLinkRate >> 4) & 0xf), buf->ProgrammedLinkRate);
+ mpr_dprint_field(sc, MPR_XINFO, "HwLinkRate: %s (0x%x)\n",
+ mpr_describe_table(mpr_linkrate_names,
+ (buf->HwLinkRate >> 4) & 0xf), buf->HwLinkRate);
+ MPR_PRINTFIELD(sc, buf, ChangeCount, %d);
+ MPR_PRINTFIELD(sc, buf, Flags, 0x%x);
+ mpr_dprint_field(sc, MPR_XINFO, "PhyInfo Reason: %s (0x%x)\n",
+ mpr_describe_table(mpr_phyinfo_reason_names,
+ (buf->PhyInfo >> 16) & 0xf), buf->PhyInfo);
+ mpr_dprint_field(sc, MPR_XINFO, "NegotiatedLinkRate: %s (0x%x)\n",
+ mpr_describe_table(mpr_linkrate_names,
+ buf->NegotiatedLinkRate & 0xf), buf->NegotiatedLinkRate);
+}
+
+void
+mpr_print_sgl(struct mpr_softc *sc, struct mpr_command *cm, int offset)
+{
+ MPI2_IEEE_SGE_SIMPLE64 *ieee_sge;
+ MPI25_IEEE_SGE_CHAIN64 *ieee_sgc;
+ MPI2_SGE_SIMPLE64 *sge;
+ MPI2_REQUEST_HEADER *req;
+ struct mpr_chain *chain = NULL;
+ char *frame;
+ u_int i = 0, flags, length;
+
+ req = (MPI2_REQUEST_HEADER *)cm->cm_req;
+ frame = (char *)cm->cm_req;
+ ieee_sge = (MPI2_IEEE_SGE_SIMPLE64 *)&frame[offset * 4];
+ sge = (MPI2_SGE_SIMPLE64 *)&frame[offset * 4];
+ printf("SGL for command %p\n", cm);
+
+ hexdump(frame, 128, NULL, 0);
+ while ((frame != NULL) && (!(cm->cm_flags & MPR_CM_FLAGS_SGE_SIMPLE))) {
+ flags = ieee_sge->Flags;
+ length = le32toh(ieee_sge->Length);
+ printf("IEEE seg%d flags=0x%02x len=0x%08x addr=0x%016jx\n", i,
+ flags, length, mpr_to_u64(&ieee_sge->Address));
+ if (flags & MPI25_IEEE_SGE_FLAGS_END_OF_LIST)
+ break;
+ ieee_sge++;
+ i++;
+ if (flags & MPI2_IEEE_SGE_FLAGS_CHAIN_ELEMENT) {
+ ieee_sgc = (MPI25_IEEE_SGE_CHAIN64 *)ieee_sge;
+ printf("IEEE chain flags=0x%x len=0x%x Offset=0x%x "
+ "Address=0x%016jx\n", ieee_sgc->Flags,
+ le32toh(ieee_sgc->Length),
+ ieee_sgc->NextChainOffset,
+ mpr_to_u64(&ieee_sgc->Address));
+ if (chain == NULL)
+ chain = TAILQ_FIRST(&cm->cm_chain_list);
+ else
+ chain = TAILQ_NEXT(chain, chain_link);
+ frame = (char *)chain->chain;
+ ieee_sge = (MPI2_IEEE_SGE_SIMPLE64 *)frame;
+ hexdump(frame, 128, NULL, 0);
+ }
+ }
+ while ((frame != NULL) && (cm->cm_flags & MPR_CM_FLAGS_SGE_SIMPLE)) {
+ flags = le32toh(sge->FlagsLength) >> MPI2_SGE_FLAGS_SHIFT;
+ printf("seg%d flags=0x%02x len=0x%06x addr=0x%016jx\n", i,
+ flags, le32toh(sge->FlagsLength) & 0xffffff,
+ mpr_to_u64(&sge->Address));
+ if (flags & (MPI2_SGE_FLAGS_END_OF_LIST |
+ MPI2_SGE_FLAGS_END_OF_BUFFER))
+ break;
+ sge++;
+ i++;
+ }
+}
+
+void
+mpr_print_scsiio_cmd(struct mpr_softc *sc, struct mpr_command *cm)
+{
+ MPI2_SCSI_IO_REQUEST *req;
+
+ req = (MPI2_SCSI_IO_REQUEST *)cm->cm_req;
+ mpr_print_sgl(sc, cm, req->SGLOffset0);
+}
+
diff --git a/sys/dev/mpr/mpr_table.h b/sys/dev/mpr/mpr_table.h
new file mode 100644
index 0000000..6539232
--- /dev/null
+++ b/sys/dev/mpr/mpr_table.h
@@ -0,0 +1,53 @@
+/*-
+ * Copyright (c) 2009 Yahoo! Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+
+#ifndef _MPR_TABLE_H
+#define _MPR_TABLE_H
+
+struct mpr_table_lookup {
+ char *string;
+ u_int code;
+};
+
+char * mpr_describe_table(struct mpr_table_lookup *table, u_int code);
+void mpr_describe_devinfo(uint32_t devinfo, char *string, int len);
+
+extern struct mpr_table_lookup mpr_event_names[];
+extern struct mpr_table_lookup mpr_phystatus_names[];
+extern struct mpr_table_lookup mpr_linkrate_names[];
+
+void mpr_print_iocfacts(struct mpr_softc *, MPI2_IOC_FACTS_REPLY *);
+void mpr_print_portfacts(struct mpr_softc *, MPI2_PORT_FACTS_REPLY *);
+void mpr_print_event(struct mpr_softc *, MPI2_EVENT_NOTIFICATION_REPLY *);
+void mpr_print_sasdev0(struct mpr_softc *, MPI2_CONFIG_PAGE_SAS_DEV_0 *);
+void mpr_print_evt_sas(struct mpr_softc *, MPI2_EVENT_NOTIFICATION_REPLY *);
+void mpr_print_expander1(struct mpr_softc *, MPI2_CONFIG_PAGE_EXPANDER_1 *);
+void mpr_print_sasphy0(struct mpr_softc *, MPI2_CONFIG_PAGE_SAS_PHY_0 *);
+void mpr_print_sgl(struct mpr_softc *, struct mpr_command *, int);
+void mpr_print_scsiio_cmd(struct mpr_softc *, struct mpr_command *);
+#endif
diff --git a/sys/dev/mpr/mpr_user.c b/sys/dev/mpr/mpr_user.c
new file mode 100644
index 0000000..3f46b14
--- /dev/null
+++ b/sys/dev/mpr/mpr_user.c
@@ -0,0 +1,2453 @@
+/*-
+ * Copyright (c) 2008 Yahoo!, Inc.
+ * All rights reserved.
+ * Written by: John Baldwin <jhb@FreeBSD.org>
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the author nor the names of any co-contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * LSI MPT-Fusion Host Adapter FreeBSD userland interface
+ */
+/*-
+ * Copyright (c) 2011-2014 LSI Corp.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * LSI MPT-Fusion Host Adapter FreeBSD
+ *
+ * $FreeBSD$
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include "opt_compat.h"
+
+/* TODO Move headers to mprvar */
+#include <sys/types.h>
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/kernel.h>
+#include <sys/selinfo.h>
+#include <sys/module.h>
+#include <sys/bus.h>
+#include <sys/conf.h>
+#include <sys/bio.h>
+#include <sys/malloc.h>
+#include <sys/uio.h>
+#include <sys/sysctl.h>
+#include <sys/ioccom.h>
+#include <sys/endian.h>
+#include <sys/queue.h>
+#include <sys/kthread.h>
+#include <sys/taskqueue.h>
+#include <sys/proc.h>
+#include <sys/sysent.h>
+
+#include <machine/bus.h>
+#include <machine/resource.h>
+#include <sys/rman.h>
+
+#include <cam/cam.h>
+#include <cam/scsi/scsi_all.h>
+
+#include <dev/mpr/mpi/mpi2_type.h>
+#include <dev/mpr/mpi/mpi2.h>
+#include <dev/mpr/mpi/mpi2_ioc.h>
+#include <dev/mpr/mpi/mpi2_cnfg.h>
+#include <dev/mpr/mpi/mpi2_init.h>
+#include <dev/mpr/mpi/mpi2_tool.h>
+#include <dev/mpr/mpr_ioctl.h>
+#include <dev/mpr/mprvar.h>
+#include <dev/mpr/mpr_table.h>
+#include <dev/mpr/mpr_sas.h>
+#include <dev/pci/pcivar.h>
+#include <dev/pci/pcireg.h>
+
+static d_open_t mpr_open;
+static d_close_t mpr_close;
+static d_ioctl_t mpr_ioctl_devsw;
+
+static struct cdevsw mpr_cdevsw = {
+ .d_version = D_VERSION,
+ .d_flags = 0,
+ .d_open = mpr_open,
+ .d_close = mpr_close,
+ .d_ioctl = mpr_ioctl_devsw,
+ .d_name = "mpr",
+};
+
+typedef int (mpr_user_f)(struct mpr_command *, struct mpr_usr_command *);
+static mpr_user_f mpi_pre_ioc_facts;
+static mpr_user_f mpi_pre_port_facts;
+static mpr_user_f mpi_pre_fw_download;
+static mpr_user_f mpi_pre_fw_upload;
+static mpr_user_f mpi_pre_sata_passthrough;
+static mpr_user_f mpi_pre_smp_passthrough;
+static mpr_user_f mpi_pre_config;
+static mpr_user_f mpi_pre_sas_io_unit_control;
+
+static int mpr_user_read_cfg_header(struct mpr_softc *,
+ struct mpr_cfg_page_req *);
+static int mpr_user_read_cfg_page(struct mpr_softc *,
+ struct mpr_cfg_page_req *, void *);
+static int mpr_user_read_extcfg_header(struct mpr_softc *,
+ struct mpr_ext_cfg_page_req *);
+static int mpr_user_read_extcfg_page(struct mpr_softc *,
+ struct mpr_ext_cfg_page_req *, void *);
+static int mpr_user_write_cfg_page(struct mpr_softc *,
+ struct mpr_cfg_page_req *, void *);
+static int mpr_user_setup_request(struct mpr_command *,
+ struct mpr_usr_command *);
+static int mpr_user_command(struct mpr_softc *, struct mpr_usr_command *);
+
+static int mpr_user_pass_thru(struct mpr_softc *sc, mpr_pass_thru_t *data);
+static void mpr_user_get_adapter_data(struct mpr_softc *sc,
+ mpr_adapter_data_t *data);
+static void mpr_user_read_pci_info(struct mpr_softc *sc,
+ mpr_pci_info_t *data);
+static uint8_t mpr_get_fw_diag_buffer_number(struct mpr_softc *sc,
+ uint32_t unique_id);
+static int mpr_post_fw_diag_buffer(struct mpr_softc *sc,
+ mpr_fw_diagnostic_buffer_t *pBuffer, uint32_t *return_code);
+static int mpr_release_fw_diag_buffer(struct mpr_softc *sc,
+ mpr_fw_diagnostic_buffer_t *pBuffer, uint32_t *return_code,
+ uint32_t diag_type);
+static int mpr_diag_register(struct mpr_softc *sc,
+ mpr_fw_diag_register_t *diag_register, uint32_t *return_code);
+static int mpr_diag_unregister(struct mpr_softc *sc,
+ mpr_fw_diag_unregister_t *diag_unregister, uint32_t *return_code);
+static int mpr_diag_query(struct mpr_softc *sc,
+ mpr_fw_diag_query_t *diag_query, uint32_t *return_code);
+static int mpr_diag_read_buffer(struct mpr_softc *sc,
+ mpr_diag_read_buffer_t *diag_read_buffer, uint8_t *ioctl_buf,
+ uint32_t *return_code);
+static int mpr_diag_release(struct mpr_softc *sc,
+ mpr_fw_diag_release_t *diag_release, uint32_t *return_code);
+static int mpr_do_diag_action(struct mpr_softc *sc, uint32_t action,
+ uint8_t *diag_action, uint32_t length, uint32_t *return_code);
+static int mpr_user_diag_action(struct mpr_softc *sc,
+ mpr_diag_action_t *data);
+static void mpr_user_event_query(struct mpr_softc *sc,
+ mpr_event_query_t *data);
+static void mpr_user_event_enable(struct mpr_softc *sc,
+ mpr_event_enable_t *data);
+static int mpr_user_event_report(struct mpr_softc *sc,
+ mpr_event_report_t *data);
+static int mpr_user_reg_access(struct mpr_softc *sc, mpr_reg_access_t *data);
+static int mpr_user_btdh(struct mpr_softc *sc, mpr_btdh_mapping_t *data);
+
+static MALLOC_DEFINE(M_MPRUSER, "mpr_user", "Buffers for mpr(4) ioctls");
+
+/* Macros from compat/freebsd32/freebsd32.h */
+#define PTRIN(v) (void *)(uintptr_t)(v)
+#define PTROUT(v) (uint32_t)(uintptr_t)(v)
+
+#define CP(src,dst,fld) do { (dst).fld = (src).fld; } while (0)
+#define PTRIN_CP(src,dst,fld) \
+ do { (dst).fld = PTRIN((src).fld); } while (0)
+#define PTROUT_CP(src,dst,fld) \
+ do { (dst).fld = PTROUT((src).fld); } while (0)
+
+/*
+ * MPI functions that support IEEE SGLs for SAS3.
+ */
+static uint8_t ieee_sgl_func_list[] = {
+ MPI2_FUNCTION_SCSI_IO_REQUEST,
+ MPI2_FUNCTION_RAID_SCSI_IO_PASSTHROUGH,
+ MPI2_FUNCTION_SMP_PASSTHROUGH,
+ MPI2_FUNCTION_SATA_PASSTHROUGH,
+ MPI2_FUNCTION_FW_UPLOAD,
+ MPI2_FUNCTION_FW_DOWNLOAD,
+ MPI2_FUNCTION_TARGET_ASSIST,
+ MPI2_FUNCTION_TARGET_STATUS_SEND,
+ MPI2_FUNCTION_TOOLBOX
+};
+
+int
+mpr_attach_user(struct mpr_softc *sc)
+{
+ int unit;
+
+ unit = device_get_unit(sc->mpr_dev);
+ sc->mpr_cdev = make_dev(&mpr_cdevsw, unit, UID_ROOT, GID_OPERATOR,
+ 0640, "mpr_%d", unit);
+ if (sc->mpr_cdev == NULL) {
+ return (ENOMEM);
+ }
+ sc->mpr_cdev->si_drv1 = sc;
+ return (0);
+}
+
+void
+mpr_detach_user(struct mpr_softc *sc)
+{
+
+ /* XXX: do a purge of pending requests? */
+ if (sc->mpr_cdev != NULL)
+ destroy_dev(sc->mpr_cdev);
+}
+
+static int
+mpr_open(struct cdev *dev, int flags, int fmt, struct thread *td)
+{
+
+ return (0);
+}
+
+static int
+mpr_close(struct cdev *dev, int flags, int fmt, struct thread *td)
+{
+
+ return (0);
+}
+
+static int
+mpr_user_read_cfg_header(struct mpr_softc *sc,
+ struct mpr_cfg_page_req *page_req)
+{
+ MPI2_CONFIG_PAGE_HEADER *hdr;
+ struct mpr_config_params params;
+ int error;
+
+ hdr = &params.hdr.Struct;
+ params.action = MPI2_CONFIG_ACTION_PAGE_HEADER;
+ params.page_address = le32toh(page_req->page_address);
+ hdr->PageVersion = 0;
+ hdr->PageLength = 0;
+ hdr->PageNumber = page_req->header.PageNumber;
+ hdr->PageType = page_req->header.PageType;
+ params.buffer = NULL;
+ params.length = 0;
+ params.callback = NULL;
+
+ if ((error = mpr_read_config_page(sc, &params)) != 0) {
+ /*
+ * Leave the request. Without resetting the chip, it's
+ * still owned by it and we'll just get into trouble
+ * freeing it now. Mark it as abandoned so that if it
+ * shows up later it can be freed.
+ */
+ mpr_printf(sc, "read_cfg_header timed out\n");
+ return (ETIMEDOUT);
+ }
+
+ page_req->ioc_status = htole16(params.status);
+ if ((page_req->ioc_status & MPI2_IOCSTATUS_MASK) ==
+ MPI2_IOCSTATUS_SUCCESS) {
+ bcopy(hdr, &page_req->header, sizeof(page_req->header));
+ }
+
+ return (0);
+}
+
+static int
+mpr_user_read_cfg_page(struct mpr_softc *sc,
+ struct mpr_cfg_page_req *page_req,
+ void *buf)
+{
+ MPI2_CONFIG_PAGE_HEADER *reqhdr, *hdr;
+ struct mpr_config_params params;
+ int error;
+
+ reqhdr = buf;
+ hdr = &params.hdr.Struct;
+ hdr->PageVersion = reqhdr->PageVersion;
+ hdr->PageLength = reqhdr->PageLength;
+ hdr->PageNumber = reqhdr->PageNumber;
+ hdr->PageType = reqhdr->PageType & MPI2_CONFIG_PAGETYPE_MASK;
+ params.action = MPI2_CONFIG_ACTION_PAGE_READ_CURRENT;
+ params.page_address = le32toh(page_req->page_address);
+ params.buffer = buf;
+ params.length = le32toh(page_req->len);
+ params.callback = NULL;
+
+ if ((error = mpr_read_config_page(sc, &params)) != 0) {
+ mpr_printf(sc, "mpr_user_read_cfg_page timed out\n");
+ return (ETIMEDOUT);
+ }
+
+ page_req->ioc_status = htole16(params.status);
+ return (0);
+}
+
+static int
+mpr_user_read_extcfg_header(struct mpr_softc *sc,
+ struct mpr_ext_cfg_page_req *ext_page_req)
+{
+ MPI2_CONFIG_EXTENDED_PAGE_HEADER *hdr;
+ struct mpr_config_params params;
+ int error;
+
+ hdr = &params.hdr.Ext;
+ params.action = MPI2_CONFIG_ACTION_PAGE_HEADER;
+ hdr->PageVersion = ext_page_req->header.PageVersion;
+ hdr->PageType = MPI2_CONFIG_PAGETYPE_EXTENDED;
+ hdr->ExtPageLength = 0;
+ hdr->PageNumber = ext_page_req->header.PageNumber;
+ hdr->ExtPageType = ext_page_req->header.ExtPageType;
+ params.page_address = le32toh(ext_page_req->page_address);
+ if ((error = mpr_read_config_page(sc, &params)) != 0) {
+ /*
+ * Leave the request. Without resetting the chip, it's
+ * still owned by it and we'll just get into trouble
+ * freeing it now. Mark it as abandoned so that if it
+ * shows up later it can be freed.
+ */
+ mpr_printf(sc, "mpr_user_read_extcfg_header timed out\n");
+ return (ETIMEDOUT);
+ }
+
+ ext_page_req->ioc_status = htole16(params.status);
+ if ((ext_page_req->ioc_status & MPI2_IOCSTATUS_MASK) ==
+ MPI2_IOCSTATUS_SUCCESS) {
+ ext_page_req->header.PageVersion = hdr->PageVersion;
+ ext_page_req->header.PageNumber = hdr->PageNumber;
+ ext_page_req->header.PageType = hdr->PageType;
+ ext_page_req->header.ExtPageLength = hdr->ExtPageLength;
+ ext_page_req->header.ExtPageType = hdr->ExtPageType;
+ }
+
+ return (0);
+}
+
+static int
+mpr_user_read_extcfg_page(struct mpr_softc *sc,
+ struct mpr_ext_cfg_page_req *ext_page_req, void *buf)
+{
+ MPI2_CONFIG_EXTENDED_PAGE_HEADER *reqhdr, *hdr;
+ struct mpr_config_params params;
+ int error;
+
+ reqhdr = buf;
+ hdr = &params.hdr.Ext;
+ params.action = MPI2_CONFIG_ACTION_PAGE_READ_CURRENT;
+ params.page_address = le32toh(ext_page_req->page_address);
+ hdr->PageVersion = reqhdr->PageVersion;
+ hdr->PageNumber = reqhdr->PageNumber;
+ hdr->PageType = MPI2_CONFIG_PAGETYPE_EXTENDED;
+ hdr->ExtPageType = reqhdr->ExtPageType;
+ hdr->ExtPageLength = reqhdr->ExtPageLength;
+ params.buffer = buf;
+ params.length = le32toh(ext_page_req->len);
+ params.callback = NULL;
+
+ if ((error = mpr_read_config_page(sc, &params)) != 0) {
+ mpr_printf(sc, "mpr_user_read_extcfg_page timed out\n");
+ return (ETIMEDOUT);
+ }
+
+ ext_page_req->ioc_status = htole16(params.status);
+ return (0);
+}
+
+static int
+mpr_user_write_cfg_page(struct mpr_softc *sc,
+ struct mpr_cfg_page_req *page_req, void *buf)
+{
+ MPI2_CONFIG_PAGE_HEADER *reqhdr, *hdr;
+ struct mpr_config_params params;
+ u_int hdr_attr;
+ int error;
+
+ reqhdr = buf;
+ hdr = &params.hdr.Struct;
+ hdr_attr = reqhdr->PageType & MPI2_CONFIG_PAGEATTR_MASK;
+ if (hdr_attr != MPI2_CONFIG_PAGEATTR_CHANGEABLE &&
+ hdr_attr != MPI2_CONFIG_PAGEATTR_PERSISTENT) {
+ mpr_printf(sc, "page type 0x%x not changeable\n",
+ reqhdr->PageType & MPI2_CONFIG_PAGETYPE_MASK);
+ return (EINVAL);
+ }
+
+ /*
+ * There isn't any point in restoring stripped out attributes
+ * if you then mask them going down to issue the request.
+ */
+
+ hdr->PageVersion = reqhdr->PageVersion;
+ hdr->PageLength = reqhdr->PageLength;
+ hdr->PageNumber = reqhdr->PageNumber;
+ hdr->PageType = reqhdr->PageType;
+ params.action = MPI2_CONFIG_ACTION_PAGE_WRITE_CURRENT;
+ params.page_address = le32toh(page_req->page_address);
+ params.buffer = buf;
+ params.length = le32toh(page_req->len);
+ params.callback = NULL;
+
+ if ((error = mpr_write_config_page(sc, &params)) != 0) {
+ mpr_printf(sc, "mpr_write_cfg_page timed out\n");
+ return (ETIMEDOUT);
+ }
+
+ page_req->ioc_status = htole16(params.status);
+ return (0);
+}
+
+void
+mpr_init_sge(struct mpr_command *cm, void *req, void *sge)
+{
+ int off, space;
+
+ space = (int)cm->cm_sc->facts->IOCRequestFrameSize * 4;
+ off = (uintptr_t)sge - (uintptr_t)req;
+
+ KASSERT(off < space, ("bad pointers %p %p, off %d, space %d",
+ req, sge, off, space));
+
+ cm->cm_sge = sge;
+ cm->cm_sglsize = space - off;
+}
+
+/*
+ * Prepare the mpr_command for an IOC_FACTS request.
+ */
+static int
+mpi_pre_ioc_facts(struct mpr_command *cm, struct mpr_usr_command *cmd)
+{
+ MPI2_IOC_FACTS_REQUEST *req = (void *)cm->cm_req;
+ MPI2_IOC_FACTS_REPLY *rpl;
+
+ if (cmd->req_len != sizeof *req)
+ return (EINVAL);
+ if (cmd->rpl_len != sizeof *rpl)
+ return (EINVAL);
+
+ cm->cm_sge = NULL;
+ cm->cm_sglsize = 0;
+ return (0);
+}
+
+/*
+ * Prepare the mpr_command for a PORT_FACTS request.
+ */
+static int
+mpi_pre_port_facts(struct mpr_command *cm, struct mpr_usr_command *cmd)
+{
+ MPI2_PORT_FACTS_REQUEST *req = (void *)cm->cm_req;
+ MPI2_PORT_FACTS_REPLY *rpl;
+
+ if (cmd->req_len != sizeof *req)
+ return (EINVAL);
+ if (cmd->rpl_len != sizeof *rpl)
+ return (EINVAL);
+
+ cm->cm_sge = NULL;
+ cm->cm_sglsize = 0;
+ return (0);
+}
+
+/*
+ * Prepare the mpr_command for a FW_DOWNLOAD request.
+ */
+static int
+mpi_pre_fw_download(struct mpr_command *cm, struct mpr_usr_command *cmd)
+{
+ MPI25_FW_DOWNLOAD_REQUEST *req = (void *)cm->cm_req;
+ MPI2_FW_DOWNLOAD_REPLY *rpl;
+ int error;
+
+ if (cmd->req_len != sizeof *req)
+ return (EINVAL);
+ if (cmd->rpl_len != sizeof *rpl)
+ return (EINVAL);
+
+ if (cmd->len == 0)
+ return (EINVAL);
+
+ error = copyin(cmd->buf, cm->cm_data, cmd->len);
+ if (error != 0)
+ return (error);
+
+ mpr_init_sge(cm, req, &req->SGL);
+
+ /*
+ * For now, the F/W image must be provided in a single request.
+ */
+ if ((req->MsgFlags & MPI2_FW_DOWNLOAD_MSGFLGS_LAST_SEGMENT) == 0)
+ return (EINVAL);
+ if (req->TotalImageSize != cmd->len)
+ return (EINVAL);
+
+ req->ImageOffset = 0;
+ req->ImageSize = cmd->len;
+
+ cm->cm_flags |= MPR_CM_FLAGS_DATAOUT;
+
+ return (mpr_push_ieee_sge(cm, &req->SGL, 0));
+}
+
+/*
+ * Prepare the mpr_command for a FW_UPLOAD request.
+ */
+static int
+mpi_pre_fw_upload(struct mpr_command *cm, struct mpr_usr_command *cmd)
+{
+ MPI25_FW_UPLOAD_REQUEST *req = (void *)cm->cm_req;
+ MPI2_FW_UPLOAD_REPLY *rpl;
+
+ if (cmd->req_len != sizeof *req)
+ return (EINVAL);
+ if (cmd->rpl_len != sizeof *rpl)
+ return (EINVAL);
+
+ mpr_init_sge(cm, req, &req->SGL);
+ if (cmd->len == 0) {
+ /* Perhaps just asking what the size of the fw is? */
+ return (0);
+ }
+
+ req->ImageOffset = 0;
+ req->ImageSize = cmd->len;
+
+ return (mpr_push_ieee_sge(cm, &req->SGL, 0));
+}
+
+/*
+ * Prepare the mpr_command for a SATA_PASSTHROUGH request.
+ */
+static int
+mpi_pre_sata_passthrough(struct mpr_command *cm, struct mpr_usr_command *cmd)
+{
+ MPI2_SATA_PASSTHROUGH_REQUEST *req = (void *)cm->cm_req;
+ MPI2_SATA_PASSTHROUGH_REPLY *rpl;
+
+ if (cmd->req_len != sizeof *req)
+ return (EINVAL);
+ if (cmd->rpl_len != sizeof *rpl)
+ return (EINVAL);
+
+ mpr_init_sge(cm, req, &req->SGL);
+ return (0);
+}
+
+/*
+ * Prepare the mpr_command for a SMP_PASSTHROUGH request.
+ */
+static int
+mpi_pre_smp_passthrough(struct mpr_command *cm, struct mpr_usr_command *cmd)
+{
+ MPI2_SMP_PASSTHROUGH_REQUEST *req = (void *)cm->cm_req;
+ MPI2_SMP_PASSTHROUGH_REPLY *rpl;
+
+ if (cmd->req_len != sizeof *req)
+ return (EINVAL);
+ if (cmd->rpl_len != sizeof *rpl)
+ return (EINVAL);
+
+ mpr_init_sge(cm, req, &req->SGL);
+ return (0);
+}
+
+/*
+ * Prepare the mpr_command for a CONFIG request.
+ */
+static int
+mpi_pre_config(struct mpr_command *cm, struct mpr_usr_command *cmd)
+{
+ MPI2_CONFIG_REQUEST *req = (void *)cm->cm_req;
+ MPI2_CONFIG_REPLY *rpl;
+
+ if (cmd->req_len != sizeof *req)
+ return (EINVAL);
+ if (cmd->rpl_len != sizeof *rpl)
+ return (EINVAL);
+
+ mpr_init_sge(cm, req, &req->PageBufferSGE);
+ return (0);
+}
+
+/*
+ * Prepare the mpr_command for a SAS_IO_UNIT_CONTROL request.
+ */
+static int
+mpi_pre_sas_io_unit_control(struct mpr_command *cm,
+ struct mpr_usr_command *cmd)
+{
+
+ cm->cm_sge = NULL;
+ cm->cm_sglsize = 0;
+ return (0);
+}
+
+/*
+ * A set of functions to prepare an mpr_command for the various
+ * supported requests.
+ */
+struct mpr_user_func {
+ U8 Function;
+ mpr_user_f *f_pre;
+} mpr_user_func_list[] = {
+ { MPI2_FUNCTION_IOC_FACTS, mpi_pre_ioc_facts },
+ { MPI2_FUNCTION_PORT_FACTS, mpi_pre_port_facts },
+ { MPI2_FUNCTION_FW_DOWNLOAD, mpi_pre_fw_download },
+ { MPI2_FUNCTION_FW_UPLOAD, mpi_pre_fw_upload },
+ { MPI2_FUNCTION_SATA_PASSTHROUGH, mpi_pre_sata_passthrough },
+ { MPI2_FUNCTION_SMP_PASSTHROUGH, mpi_pre_smp_passthrough},
+ { MPI2_FUNCTION_CONFIG, mpi_pre_config},
+ { MPI2_FUNCTION_SAS_IO_UNIT_CONTROL, mpi_pre_sas_io_unit_control },
+ { 0xFF, NULL } /* list end */
+};
+
+static int
+mpr_user_setup_request(struct mpr_command *cm, struct mpr_usr_command *cmd)
+{
+ MPI2_REQUEST_HEADER *hdr = (MPI2_REQUEST_HEADER *)cm->cm_req;
+ struct mpr_user_func *f;
+
+ for (f = mpr_user_func_list; f->f_pre != NULL; f++) {
+ if (hdr->Function == f->Function)
+ return (f->f_pre(cm, cmd));
+ }
+ return (EINVAL);
+}
+
+static int
+mpr_user_command(struct mpr_softc *sc, struct mpr_usr_command *cmd)
+{
+ MPI2_REQUEST_HEADER *hdr;
+ MPI2_DEFAULT_REPLY *rpl;
+ void *buf = NULL;
+ struct mpr_command *cm = NULL;
+ int err = 0;
+ int sz;
+
+ mpr_lock(sc);
+ cm = mpr_alloc_command(sc);
+
+ if (cm == NULL) {
+ mpr_printf(sc, "%s: no mpr requests\n", __func__);
+ err = ENOMEM;
+ goto Ret;
+ }
+ mpr_unlock(sc);
+
+ hdr = (MPI2_REQUEST_HEADER *)cm->cm_req;
+
+ mpr_dprint(sc, MPR_USER, "%s: req %p %d rpl %p %d\n", __func__,
+ cmd->req, cmd->req_len, cmd->rpl, cmd->rpl_len);
+
+ if (cmd->req_len > (int)sc->facts->IOCRequestFrameSize * 4) {
+ err = EINVAL;
+ goto RetFreeUnlocked;
+ }
+ err = copyin(cmd->req, hdr, cmd->req_len);
+ if (err != 0)
+ goto RetFreeUnlocked;
+
+ mpr_dprint(sc, MPR_USER, "%s: Function %02X MsgFlags %02X\n", __func__,
+ hdr->Function, hdr->MsgFlags);
+
+ if (cmd->len > 0) {
+ buf = malloc(cmd->len, M_MPRUSER, M_WAITOK|M_ZERO);
+ if (!buf) {
+ mpr_printf(sc, "Cannot allocate memory %s %d\n",
+ __func__, __LINE__);
+ return (ENOMEM);
+ }
+ cm->cm_data = buf;
+ cm->cm_length = cmd->len;
+ } else {
+ cm->cm_data = NULL;
+ cm->cm_length = 0;
+ }
+
+ cm->cm_flags = MPR_CM_FLAGS_SGE_SIMPLE;
+ cm->cm_desc.Default.RequestFlags = MPI2_REQ_DESCRIPT_FLAGS_DEFAULT_TYPE;
+
+ err = mpr_user_setup_request(cm, cmd);
+ if (err == EINVAL) {
+ mpr_printf(sc, "%s: unsupported parameter or unsupported "
+ "function in request (function = 0x%X)\n", __func__,
+ hdr->Function);
+ }
+ if (err != 0)
+ goto RetFreeUnlocked;
+
+ mpr_lock(sc);
+ err = mpr_wait_command(sc, cm, 30, CAN_SLEEP);
+
+ if (err) {
+ mpr_printf(sc, "%s: invalid request: error %d\n",
+ __func__, err);
+ goto Ret;
+ }
+
+ rpl = (MPI2_DEFAULT_REPLY *)cm->cm_reply;
+ if (rpl != NULL)
+ sz = rpl->MsgLength * 4;
+ else
+ sz = 0;
+
+ if (sz > cmd->rpl_len) {
+ mpr_printf(sc, "%s: user reply buffer (%d) smaller than "
+ "returned buffer (%d)\n", __func__, cmd->rpl_len, sz);
+ sz = cmd->rpl_len;
+ }
+
+ mpr_unlock(sc);
+ copyout(rpl, cmd->rpl, sz);
+ if (buf != NULL)
+ copyout(buf, cmd->buf, cmd->len);
+ mpr_dprint(sc, MPR_USER, "%s: reply size %d\n", __func__, sz);
+
+RetFreeUnlocked:
+ mpr_lock(sc);
+ if (cm != NULL)
+ mpr_free_command(sc, cm);
+Ret:
+ mpr_unlock(sc);
+ if (buf != NULL)
+ free(buf, M_MPRUSER);
+ return (err);
+}
+
+static int
+mpr_user_pass_thru(struct mpr_softc *sc, mpr_pass_thru_t *data)
+{
+ MPI2_REQUEST_HEADER *hdr, tmphdr;
+ MPI2_DEFAULT_REPLY *rpl;
+ struct mpr_command *cm = NULL;
+ int i, err = 0, dir = 0, sz;
+ uint8_t tool, function = 0;
+ u_int sense_len;
+ struct mprsas_target *targ = NULL;
+
+ /*
+ * Only allow one passthru command at a time. Use the MPR_FLAGS_BUSY
+ * bit to denote that a passthru is being processed.
+ */
+ mpr_lock(sc);
+ if (sc->mpr_flags & MPR_FLAGS_BUSY) {
+ mpr_dprint(sc, MPR_USER, "%s: Only one passthru command "
+ "allowed at a single time.", __func__);
+ mpr_unlock(sc);
+ return (EBUSY);
+ }
+ sc->mpr_flags |= MPR_FLAGS_BUSY;
+ mpr_unlock(sc);
+
+ /*
+ * Do some validation on data direction. Valid cases are:
+ * 1) DataSize is 0 and direction is NONE
+ * 2) DataSize is non-zero and one of:
+ * a) direction is READ or
+ * b) direction is WRITE or
+ * c) direction is BOTH and DataOutSize is non-zero
+ * If valid and the direction is BOTH, change the direction to READ.
+ * if valid and the direction is not BOTH, make sure DataOutSize is 0.
+ */
+ if (((data->DataSize == 0) &&
+ (data->DataDirection == MPR_PASS_THRU_DIRECTION_NONE)) ||
+ ((data->DataSize != 0) &&
+ ((data->DataDirection == MPR_PASS_THRU_DIRECTION_READ) ||
+ (data->DataDirection == MPR_PASS_THRU_DIRECTION_WRITE) ||
+ ((data->DataDirection == MPR_PASS_THRU_DIRECTION_BOTH) &&
+ (data->DataOutSize != 0))))) {
+ if (data->DataDirection == MPR_PASS_THRU_DIRECTION_BOTH)
+ data->DataDirection = MPR_PASS_THRU_DIRECTION_READ;
+ else
+ data->DataOutSize = 0;
+ } else
+ return (EINVAL);
+
+ mpr_dprint(sc, MPR_USER, "%s: req 0x%jx %d rpl 0x%jx %d "
+ "data in 0x%jx %d data out 0x%jx %d data dir %d\n", __func__,
+ data->PtrRequest, data->RequestSize, data->PtrReply,
+ data->ReplySize, data->PtrData, data->DataSize,
+ data->PtrDataOut, data->DataOutSize, data->DataDirection);
+
+ /*
+ * copy in the header so we know what we're dealing with before we
+ * commit to allocating a command for it.
+ */
+ err = copyin(PTRIN(data->PtrRequest), &tmphdr, data->RequestSize);
+ if (err != 0)
+ goto RetFreeUnlocked;
+
+ if (data->RequestSize > (int)sc->facts->IOCRequestFrameSize * 4) {
+ err = EINVAL;
+ goto RetFreeUnlocked;
+ }
+
+ function = tmphdr.Function;
+ mpr_dprint(sc, MPR_USER, "%s: Function %02X MsgFlags %02X\n", __func__,
+ function, tmphdr.MsgFlags);
+
+ /*
+ * Handle a passthru TM request.
+ */
+ if (function == MPI2_FUNCTION_SCSI_TASK_MGMT) {
+ MPI2_SCSI_TASK_MANAGE_REQUEST *task;
+
+ mpr_lock(sc);
+ cm = mprsas_alloc_tm(sc);
+ if (cm == NULL) {
+ err = EINVAL;
+ goto Ret;
+ }
+
+ /* Copy the header in. Only a small fixup is needed. */
+ task = (MPI2_SCSI_TASK_MANAGE_REQUEST *)cm->cm_req;
+ bcopy(&tmphdr, task, data->RequestSize);
+ task->TaskMID = cm->cm_desc.Default.SMID;
+
+ cm->cm_data = NULL;
+ cm->cm_desc.HighPriority.RequestFlags = MPI2_REQ_DESCRIPT_FLAGS_HIGH_PRIORITY;
+ cm->cm_complete = NULL;
+ cm->cm_complete_data = NULL;
+
+ err = mpr_wait_command(sc, cm, 30, CAN_SLEEP);
+
+ if (err != 0) {
+ err = EIO;
+ mpr_dprint(sc, MPR_FAULT, "%s: task management failed",
+ __func__);
+ }
+ /*
+ * Copy the reply data and sense data to user space.
+ */
+ if (cm->cm_reply != NULL) {
+ rpl = (MPI2_DEFAULT_REPLY *)cm->cm_reply;
+ sz = rpl->MsgLength * 4;
+
+ if (sz > data->ReplySize) {
+ mpr_printf(sc, "%s: user reply buffer (%d) "
+ "smaller than returned buffer (%d)\n",
+ __func__, data->ReplySize, sz);
+ }
+ mpr_unlock(sc);
+ copyout(cm->cm_reply, PTRIN(data->PtrReply),
+ data->ReplySize);
+ mpr_lock(sc);
+ }
+ mprsas_free_tm(sc, cm);
+ goto Ret;
+ }
+
+ mpr_lock(sc);
+ cm = mpr_alloc_command(sc);
+
+ if (cm == NULL) {
+ mpr_printf(sc, "%s: no mpr requests\n", __func__);
+ err = ENOMEM;
+ goto Ret;
+ }
+ mpr_unlock(sc);
+
+ hdr = (MPI2_REQUEST_HEADER *)cm->cm_req;
+ bcopy(&tmphdr, hdr, data->RequestSize);
+
+ /*
+ * Do some checking to make sure the IOCTL request contains a valid
+ * request. Then set the SGL info.
+ */
+ mpr_init_sge(cm, hdr, (void *)((uint8_t *)hdr + data->RequestSize));
+
+ /*
+ * Set up for read, write or both. From check above, DataOutSize will
+ * be 0 if direction is READ or WRITE, but it will have some non-zero
+ * value if the direction is BOTH. So, just use the biggest size to get
+ * the cm_data buffer size. If direction is BOTH, 2 SGLs need to be set
+ * up; the first is for the request and the second will contain the
+ * response data. cm_out_len needs to be set here and this will be used
+ * when the SGLs are set up.
+ */
+ cm->cm_data = NULL;
+ cm->cm_length = MAX(data->DataSize, data->DataOutSize);
+ cm->cm_out_len = data->DataOutSize;
+ cm->cm_flags = 0;
+ if (cm->cm_length != 0) {
+ cm->cm_data = malloc(cm->cm_length, M_MPRUSER, M_WAITOK |
+ M_ZERO);
+ if (cm->cm_data == NULL) {
+ mpr_dprint(sc, MPR_FAULT, "%s: alloc failed for IOCTL "
+ "passthru length %d\n", __func__, cm->cm_length);
+ } else {
+ cm->cm_flags = MPR_CM_FLAGS_DATAIN;
+ if (data->DataOutSize) {
+ cm->cm_flags |= MPR_CM_FLAGS_DATAOUT;
+ err = copyin(PTRIN(data->PtrDataOut),
+ cm->cm_data, data->DataOutSize);
+ } else if (data->DataDirection ==
+ MPR_PASS_THRU_DIRECTION_WRITE) {
+ cm->cm_flags = MPR_CM_FLAGS_DATAOUT;
+ err = copyin(PTRIN(data->PtrData),
+ cm->cm_data, data->DataSize);
+ }
+ if (err != 0)
+ mpr_dprint(sc, MPR_FAULT, "%s: failed to copy "
+ "IOCTL data from user space\n", __func__);
+ }
+ }
+ /*
+ * Set this flag only if processing a command that does not need an
+ * IEEE SGL. The CLI Tool within the Toolbox uses IEEE SGLs, so clear
+ * the flag only for that tool if processing a Toolbox function.
+ */
+ cm->cm_flags |= MPR_CM_FLAGS_SGE_SIMPLE;
+ for (i = 0; i < sizeof (ieee_sgl_func_list); i++) {
+ if (function == ieee_sgl_func_list[i]) {
+ if (function == MPI2_FUNCTION_TOOLBOX)
+ {
+ tool = (uint8_t)hdr->FunctionDependent1;
+ if (tool != MPI2_TOOLBOX_DIAGNOSTIC_CLI_TOOL)
+ break;
+ }
+ cm->cm_flags &= ~MPR_CM_FLAGS_SGE_SIMPLE;
+ break;
+ }
+ }
+ cm->cm_desc.Default.RequestFlags = MPI2_REQ_DESCRIPT_FLAGS_DEFAULT_TYPE;
+
+ /*
+ * Set up Sense buffer and SGL offset for IO passthru. SCSI IO request
+ * uses SCSI IO or Fast Path SCSI IO descriptor.
+ */
+ if ((function == MPI2_FUNCTION_SCSI_IO_REQUEST) ||
+ (function == MPI2_FUNCTION_RAID_SCSI_IO_PASSTHROUGH)) {
+ MPI2_SCSI_IO_REQUEST *scsi_io_req;
+
+ scsi_io_req = (MPI2_SCSI_IO_REQUEST *)hdr;
+ /*
+ * Put SGE for data and data_out buffer at the end of
+ * scsi_io_request message header (64 bytes in total).
+ * Following above SGEs, the residual space will be used by
+ * sense data.
+ */
+ scsi_io_req->SenseBufferLength = (uint8_t)(data->RequestSize -
+ 64);
+ scsi_io_req->SenseBufferLowAddress =
+ htole32(cm->cm_sense_busaddr);
+
+ /*
+ * Set SGLOffset0 value. This is the number of dwords that SGL
+ * is offset from the beginning of MPI2_SCSI_IO_REQUEST struct.
+ */
+ scsi_io_req->SGLOffset0 = 24;
+
+ /*
+ * Setup descriptor info. RAID passthrough must use the
+ * default request descriptor which is already set, so if this
+ * is a SCSI IO request, change the descriptor to SCSI IO or
+ * Fast Path SCSI IO. Also, if this is a SCSI IO request,
+ * handle the reply in the mprsas_scsio_complete function.
+ */
+ if (function == MPI2_FUNCTION_SCSI_IO_REQUEST) {
+ targ = mprsas_find_target_by_handle(sc->sassc, 0,
+ scsi_io_req->DevHandle);
+
+ if (!targ) {
+ printf("No Target found for handle %d\n",
+ scsi_io_req->DevHandle);
+ err = EINVAL;
+ goto RetFreeUnlocked;
+ }
+
+ if (targ->scsi_req_desc_type ==
+ MPI25_REQ_DESCRIPT_FLAGS_FAST_PATH_SCSI_IO) {
+ cm->cm_desc.FastPathSCSIIO.RequestFlags =
+ MPI25_REQ_DESCRIPT_FLAGS_FAST_PATH_SCSI_IO;
+ cm->cm_desc.FastPathSCSIIO.DevHandle =
+ scsi_io_req->DevHandle;
+ scsi_io_req->IoFlags |=
+ MPI25_SCSIIO_IOFLAGS_FAST_PATH;
+ } else {
+ cm->cm_desc.SCSIIO.RequestFlags =
+ MPI2_REQ_DESCRIPT_FLAGS_SCSI_IO;
+ cm->cm_desc.SCSIIO.DevHandle =
+ scsi_io_req->DevHandle;
+ }
+
+ /*
+ * Make sure the DevHandle is not 0 because this is a
+ * likely error.
+ */
+ if (scsi_io_req->DevHandle == 0) {
+ err = EINVAL;
+ goto RetFreeUnlocked;
+ }
+ }
+ }
+
+ mpr_lock(sc);
+
+ err = mpr_wait_command(sc, cm, 30, CAN_SLEEP);
+
+ if (err) {
+ mpr_printf(sc, "%s: invalid request: error %d\n", __func__,
+ err);
+ mpr_unlock(sc);
+ goto RetFreeUnlocked;
+ }
+
+ /*
+ * Sync the DMA data, if any. Then copy the data to user space.
+ */
+ if (cm->cm_data != NULL) {
+ if (cm->cm_flags & MPR_CM_FLAGS_DATAIN)
+ dir = BUS_DMASYNC_POSTREAD;
+ else if (cm->cm_flags & MPR_CM_FLAGS_DATAOUT)
+ dir = BUS_DMASYNC_POSTWRITE;;
+ bus_dmamap_sync(sc->buffer_dmat, cm->cm_dmamap, dir);
+ bus_dmamap_unload(sc->buffer_dmat, cm->cm_dmamap);
+
+ if (cm->cm_flags & MPR_CM_FLAGS_DATAIN) {
+ mpr_unlock(sc);
+ err = copyout(cm->cm_data,
+ PTRIN(data->PtrData), data->DataSize);
+ mpr_lock(sc);
+ if (err != 0)
+ mpr_dprint(sc, MPR_FAULT, "%s: failed to copy "
+ "IOCTL data to user space\n", __func__);
+ }
+ }
+
+ /*
+ * Copy the reply data and sense data to user space.
+ */
+ if (cm->cm_reply != NULL) {
+ rpl = (MPI2_DEFAULT_REPLY *)cm->cm_reply;
+ sz = rpl->MsgLength * 4;
+
+ if (sz > data->ReplySize) {
+ mpr_printf(sc, "%s: user reply buffer (%d) smaller "
+ "than returned buffer (%d)\n", __func__,
+ data->ReplySize, sz);
+ }
+ mpr_unlock(sc);
+ copyout(cm->cm_reply, PTRIN(data->PtrReply), data->ReplySize);
+ mpr_lock(sc);
+
+ if ((function == MPI2_FUNCTION_SCSI_IO_REQUEST) ||
+ (function == MPI2_FUNCTION_RAID_SCSI_IO_PASSTHROUGH)) {
+ if (((MPI2_SCSI_IO_REPLY *)rpl)->SCSIState &
+ MPI2_SCSI_STATE_AUTOSENSE_VALID) {
+ sense_len =
+ MIN((le32toh(((MPI2_SCSI_IO_REPLY *)rpl)->
+ SenseCount)), sizeof(struct
+ scsi_sense_data));
+ mpr_unlock(sc);
+ copyout(cm->cm_sense, cm->cm_req + 64,
+ sense_len);
+ mpr_lock(sc);
+ }
+ }
+ }
+ mpr_unlock(sc);
+
+RetFreeUnlocked:
+ mpr_lock(sc);
+
+ if (cm != NULL) {
+ if (cm->cm_data)
+ free(cm->cm_data, M_MPRUSER);
+ mpr_free_command(sc, cm);
+ }
+Ret:
+ sc->mpr_flags &= ~MPR_FLAGS_BUSY;
+ mpr_unlock(sc);
+
+ return (err);
+}
+
+static void
+mpr_user_get_adapter_data(struct mpr_softc *sc, mpr_adapter_data_t *data)
+{
+ Mpi2ConfigReply_t mpi_reply;
+ Mpi2BiosPage3_t config_page;
+
+ /*
+ * Use the PCI interface functions to get the Bus, Device, and Function
+ * information.
+ */
+ data->PciInformation.u.bits.BusNumber = pci_get_bus(sc->mpr_dev);
+ data->PciInformation.u.bits.DeviceNumber = pci_get_slot(sc->mpr_dev);
+ data->PciInformation.u.bits.FunctionNumber =
+ pci_get_function(sc->mpr_dev);
+
+ /*
+ * Get the FW version that should already be saved in IOC Facts.
+ */
+ data->MpiFirmwareVersion = sc->facts->FWVersion.Word;
+
+ /*
+ * General device info.
+ */
+ data->AdapterType = MPRIOCTL_ADAPTER_TYPE_SAS3;
+ data->PCIDeviceHwId = pci_get_device(sc->mpr_dev);
+ data->PCIDeviceHwRev = pci_read_config(sc->mpr_dev, PCIR_REVID, 1);
+ data->SubSystemId = pci_get_subdevice(sc->mpr_dev);
+ data->SubsystemVendorId = pci_get_subvendor(sc->mpr_dev);
+
+ /*
+ * Get the driver version.
+ */
+ strcpy((char *)&data->DriverVersion[0], MPR_DRIVER_VERSION);
+
+ /*
+ * Need to get BIOS Config Page 3 for the BIOS Version.
+ */
+ data->BiosVersion = 0;
+ mpr_lock(sc);
+ if (mpr_config_get_bios_pg3(sc, &mpi_reply, &config_page))
+ printf("%s: Error while retrieving BIOS Version\n", __func__);
+ else
+ data->BiosVersion = config_page.BiosVersion;
+ mpr_unlock(sc);
+}
+
+static void
+mpr_user_read_pci_info(struct mpr_softc *sc, mpr_pci_info_t *data)
+{
+ int i;
+
+ /*
+ * Use the PCI interface functions to get the Bus, Device, and Function
+ * information.
+ */
+ data->BusNumber = pci_get_bus(sc->mpr_dev);
+ data->DeviceNumber = pci_get_slot(sc->mpr_dev);
+ data->FunctionNumber = pci_get_function(sc->mpr_dev);
+
+ /*
+ * Now get the interrupt vector and the pci header. The vector can
+ * only be 0 right now. The header is the first 256 bytes of config
+ * space.
+ */
+ data->InterruptVector = 0;
+ for (i = 0; i < sizeof (data->PciHeader); i++) {
+ data->PciHeader[i] = pci_read_config(sc->mpr_dev, i, 1);
+ }
+}
+
+static uint8_t
+mpr_get_fw_diag_buffer_number(struct mpr_softc *sc, uint32_t unique_id)
+{
+ uint8_t index;
+
+ for (index = 0; index < MPI2_DIAG_BUF_TYPE_COUNT; index++) {
+ if (sc->fw_diag_buffer_list[index].unique_id == unique_id) {
+ return (index);
+ }
+ }
+
+ return (MPR_FW_DIAGNOSTIC_UID_NOT_FOUND);
+}
+
+static int
+mpr_post_fw_diag_buffer(struct mpr_softc *sc,
+ mpr_fw_diagnostic_buffer_t *pBuffer, uint32_t *return_code)
+{
+ MPI2_DIAG_BUFFER_POST_REQUEST *req;
+ MPI2_DIAG_BUFFER_POST_REPLY *reply;
+ struct mpr_command *cm = NULL;
+ int i, status;
+
+ /*
+ * If buffer is not enabled, just leave.
+ */
+ *return_code = MPR_FW_DIAG_ERROR_POST_FAILED;
+ if (!pBuffer->enabled) {
+ return (MPR_DIAG_FAILURE);
+ }
+
+ /*
+ * Clear some flags initially.
+ */
+ pBuffer->force_release = FALSE;
+ pBuffer->valid_data = FALSE;
+ pBuffer->owned_by_firmware = FALSE;
+
+ /*
+ * Get a command.
+ */
+ cm = mpr_alloc_command(sc);
+ if (cm == NULL) {
+ mpr_printf(sc, "%s: no mpr requests\n", __func__);
+ return (MPR_DIAG_FAILURE);
+ }
+
+ /*
+ * Build the request for releasing the FW Diag Buffer and send it.
+ */
+ req = (MPI2_DIAG_BUFFER_POST_REQUEST *)cm->cm_req;
+ req->Function = MPI2_FUNCTION_DIAG_BUFFER_POST;
+ req->BufferType = pBuffer->buffer_type;
+ req->ExtendedType = pBuffer->extended_type;
+ req->BufferLength = pBuffer->size;
+ for (i = 0; i < (sizeof(req->ProductSpecific) / 4); i++)
+ req->ProductSpecific[i] = pBuffer->product_specific[i];
+ mpr_from_u64(sc->fw_diag_busaddr, &req->BufferAddress);
+ cm->cm_data = NULL;
+ cm->cm_length = 0;
+ cm->cm_desc.Default.RequestFlags = MPI2_REQ_DESCRIPT_FLAGS_DEFAULT_TYPE;
+ cm->cm_complete_data = NULL;
+
+ /*
+ * Send command synchronously.
+ */
+ status = mpr_wait_command(sc, cm, 30, CAN_SLEEP);
+ if (status) {
+ mpr_printf(sc, "%s: invalid request: error %d\n", __func__,
+ status);
+ status = MPR_DIAG_FAILURE;
+ goto done;
+ }
+
+ /*
+ * Process POST reply.
+ */
+ reply = (MPI2_DIAG_BUFFER_POST_REPLY *)cm->cm_reply;
+ if (reply->IOCStatus != MPI2_IOCSTATUS_SUCCESS) {
+ status = MPR_DIAG_FAILURE;
+ mpr_dprint(sc, MPR_FAULT, "%s: post of FW Diag Buffer failed "
+ "with IOCStatus = 0x%x, IOCLogInfo = 0x%x and "
+ "TransferLength = 0x%x\n", __func__, reply->IOCStatus,
+ reply->IOCLogInfo, reply->TransferLength);
+ goto done;
+ }
+
+ /*
+ * Post was successful.
+ */
+ pBuffer->valid_data = TRUE;
+ pBuffer->owned_by_firmware = TRUE;
+ *return_code = MPR_FW_DIAG_ERROR_SUCCESS;
+ status = MPR_DIAG_SUCCESS;
+
+done:
+ mpr_free_command(sc, cm);
+ return (status);
+}
+
+static int
+mpr_release_fw_diag_buffer(struct mpr_softc *sc,
+ mpr_fw_diagnostic_buffer_t *pBuffer, uint32_t *return_code,
+ uint32_t diag_type)
+{
+ MPI2_DIAG_RELEASE_REQUEST *req;
+ MPI2_DIAG_RELEASE_REPLY *reply;
+ struct mpr_command *cm = NULL;
+ int status;
+
+ /*
+ * If buffer is not enabled, just leave.
+ */
+ *return_code = MPR_FW_DIAG_ERROR_RELEASE_FAILED;
+ if (!pBuffer->enabled) {
+ mpr_dprint(sc, MPR_USER, "%s: This buffer type is not "
+ "supported by the IOC", __func__);
+ return (MPR_DIAG_FAILURE);
+ }
+
+ /*
+ * Clear some flags initially.
+ */
+ pBuffer->force_release = FALSE;
+ pBuffer->valid_data = FALSE;
+ pBuffer->owned_by_firmware = FALSE;
+
+ /*
+ * Get a command.
+ */
+ cm = mpr_alloc_command(sc);
+ if (cm == NULL) {
+ mpr_printf(sc, "%s: no mpr requests\n", __func__);
+ return (MPR_DIAG_FAILURE);
+ }
+
+ /*
+ * Build the request for releasing the FW Diag Buffer and send it.
+ */
+ req = (MPI2_DIAG_RELEASE_REQUEST *)cm->cm_req;
+ req->Function = MPI2_FUNCTION_DIAG_RELEASE;
+ req->BufferType = pBuffer->buffer_type;
+ cm->cm_data = NULL;
+ cm->cm_length = 0;
+ cm->cm_desc.Default.RequestFlags = MPI2_REQ_DESCRIPT_FLAGS_DEFAULT_TYPE;
+ cm->cm_complete_data = NULL;
+
+ /*
+ * Send command synchronously.
+ */
+ status = mpr_wait_command(sc, cm, 30, CAN_SLEEP);
+ if (status) {
+ mpr_printf(sc, "%s: invalid request: error %d\n", __func__,
+ status);
+ status = MPR_DIAG_FAILURE;
+ goto done;
+ }
+
+ /*
+ * Process RELEASE reply.
+ */
+ reply = (MPI2_DIAG_RELEASE_REPLY *)cm->cm_reply;
+ if ((reply->IOCStatus != MPI2_IOCSTATUS_SUCCESS) ||
+ pBuffer->owned_by_firmware) {
+ status = MPR_DIAG_FAILURE;
+ mpr_dprint(sc, MPR_FAULT, "%s: release of FW Diag Buffer "
+ "failed with IOCStatus = 0x%x and IOCLogInfo = 0x%x\n",
+ __func__, reply->IOCStatus, reply->IOCLogInfo);
+ goto done;
+ }
+
+ /*
+ * Release was successful.
+ */
+ *return_code = MPR_FW_DIAG_ERROR_SUCCESS;
+ status = MPR_DIAG_SUCCESS;
+
+ /*
+ * If this was for an UNREGISTER diag type command, clear the unique ID.
+ */
+ if (diag_type == MPR_FW_DIAG_TYPE_UNREGISTER) {
+ pBuffer->unique_id = MPR_FW_DIAG_INVALID_UID;
+ }
+
+done:
+ return (status);
+}
+
+static int
+mpr_diag_register(struct mpr_softc *sc,
+ mpr_fw_diag_register_t *diag_register, uint32_t *return_code)
+{
+ mpr_fw_diagnostic_buffer_t *pBuffer;
+ uint8_t extended_type, buffer_type, i;
+ uint32_t buffer_size;
+ uint32_t unique_id;
+ int status;
+
+ extended_type = diag_register->ExtendedType;
+ buffer_type = diag_register->BufferType;
+ buffer_size = diag_register->RequestedBufferSize;
+ unique_id = diag_register->UniqueId;
+
+ /*
+ * Check for valid buffer type
+ */
+ if (buffer_type >= MPI2_DIAG_BUF_TYPE_COUNT) {
+ *return_code = MPR_FW_DIAG_ERROR_INVALID_PARAMETER;
+ return (MPR_DIAG_FAILURE);
+ }
+
+ /*
+ * Get the current buffer and look up the unique ID. The unique ID
+ * should not be found. If it is, the ID is already in use.
+ */
+ i = mpr_get_fw_diag_buffer_number(sc, unique_id);
+ pBuffer = &sc->fw_diag_buffer_list[buffer_type];
+ if (i != MPR_FW_DIAGNOSTIC_UID_NOT_FOUND) {
+ *return_code = MPR_FW_DIAG_ERROR_INVALID_UID;
+ return (MPR_DIAG_FAILURE);
+ }
+
+ /*
+ * The buffer's unique ID should not be registered yet, and the given
+ * unique ID cannot be 0.
+ */
+ if ((pBuffer->unique_id != MPR_FW_DIAG_INVALID_UID) ||
+ (unique_id == MPR_FW_DIAG_INVALID_UID)) {
+ *return_code = MPR_FW_DIAG_ERROR_INVALID_UID;
+ return (MPR_DIAG_FAILURE);
+ }
+
+ /*
+ * If this buffer is already posted as immediate, just change owner.
+ */
+ if (pBuffer->immediate && pBuffer->owned_by_firmware &&
+ (pBuffer->unique_id == MPR_FW_DIAG_INVALID_UID)) {
+ pBuffer->immediate = FALSE;
+ pBuffer->unique_id = unique_id;
+ return (MPR_DIAG_SUCCESS);
+ }
+
+ /*
+ * Post a new buffer after checking if it's enabled. The DMA buffer
+ * that is allocated will be contiguous (nsegments = 1).
+ */
+ if (!pBuffer->enabled) {
+ *return_code = MPR_FW_DIAG_ERROR_NO_BUFFER;
+ return (MPR_DIAG_FAILURE);
+ }
+ if (bus_dma_tag_create( sc->mpr_parent_dmat, /* parent */
+ 1, 0, /* algnmnt, boundary */
+ BUS_SPACE_MAXADDR_32BIT,/* lowaddr */
+ BUS_SPACE_MAXADDR, /* highaddr */
+ NULL, NULL, /* filter, filterarg */
+ buffer_size, /* maxsize */
+ 1, /* nsegments */
+ buffer_size, /* maxsegsize */
+ 0, /* flags */
+ NULL, NULL, /* lockfunc, lockarg */
+ &sc->fw_diag_dmat)) {
+ device_printf(sc->mpr_dev, "Cannot allocate FW diag buffer DMA "
+ "tag\n");
+ return (ENOMEM);
+ }
+ if (bus_dmamem_alloc(sc->fw_diag_dmat, (void **)&sc->fw_diag_buffer,
+ BUS_DMA_NOWAIT, &sc->fw_diag_map)) {
+ device_printf(sc->mpr_dev, "Cannot allocate FW diag buffer "
+ "memory\n");
+ return (ENOMEM);
+ }
+ bzero(sc->fw_diag_buffer, buffer_size);
+ bus_dmamap_load(sc->fw_diag_dmat, sc->fw_diag_map, sc->fw_diag_buffer,
+ buffer_size, mpr_memaddr_cb, &sc->fw_diag_busaddr, 0);
+ pBuffer->size = buffer_size;
+
+ /*
+ * Copy the given info to the diag buffer and post the buffer.
+ */
+ pBuffer->buffer_type = buffer_type;
+ pBuffer->immediate = FALSE;
+ if (buffer_type == MPI2_DIAG_BUF_TYPE_TRACE) {
+ for (i = 0; i < (sizeof (pBuffer->product_specific) / 4);
+ i++) {
+ pBuffer->product_specific[i] =
+ diag_register->ProductSpecific[i];
+ }
+ }
+ pBuffer->extended_type = extended_type;
+ pBuffer->unique_id = unique_id;
+ status = mpr_post_fw_diag_buffer(sc, pBuffer, return_code);
+
+ /*
+ * In case there was a failure, free the DMA buffer.
+ */
+ if (status == MPR_DIAG_FAILURE) {
+ if (sc->fw_diag_busaddr != 0)
+ bus_dmamap_unload(sc->fw_diag_dmat, sc->fw_diag_map);
+ if (sc->fw_diag_buffer != NULL)
+ bus_dmamem_free(sc->fw_diag_dmat, sc->fw_diag_buffer,
+ sc->fw_diag_map);
+ if (sc->fw_diag_dmat != NULL)
+ bus_dma_tag_destroy(sc->fw_diag_dmat);
+ }
+
+ return (status);
+}
+
+static int
+mpr_diag_unregister(struct mpr_softc *sc,
+ mpr_fw_diag_unregister_t *diag_unregister, uint32_t *return_code)
+{
+ mpr_fw_diagnostic_buffer_t *pBuffer;
+ uint8_t i;
+ uint32_t unique_id;
+ int status;
+
+ unique_id = diag_unregister->UniqueId;
+
+ /*
+ * Get the current buffer and look up the unique ID. The unique ID
+ * should be there.
+ */
+ i = mpr_get_fw_diag_buffer_number(sc, unique_id);
+ if (i == MPR_FW_DIAGNOSTIC_UID_NOT_FOUND) {
+ *return_code = MPR_FW_DIAG_ERROR_INVALID_UID;
+ return (MPR_DIAG_FAILURE);
+ }
+
+ pBuffer = &sc->fw_diag_buffer_list[i];
+
+ /*
+ * Try to release the buffer from FW before freeing it. If release
+ * fails, don't free the DMA buffer in case FW tries to access it
+ * later. If buffer is not owned by firmware, can't release it.
+ */
+ if (!pBuffer->owned_by_firmware) {
+ status = MPR_DIAG_SUCCESS;
+ } else {
+ status = mpr_release_fw_diag_buffer(sc, pBuffer, return_code,
+ MPR_FW_DIAG_TYPE_UNREGISTER);
+ }
+
+ /*
+ * At this point, return the current status no matter what happens with
+ * the DMA buffer.
+ */
+ pBuffer->unique_id = MPR_FW_DIAG_INVALID_UID;
+ if (status == MPR_DIAG_SUCCESS) {
+ if (sc->fw_diag_busaddr != 0)
+ bus_dmamap_unload(sc->fw_diag_dmat, sc->fw_diag_map);
+ if (sc->fw_diag_buffer != NULL)
+ bus_dmamem_free(sc->fw_diag_dmat, sc->fw_diag_buffer,
+ sc->fw_diag_map);
+ if (sc->fw_diag_dmat != NULL)
+ bus_dma_tag_destroy(sc->fw_diag_dmat);
+ }
+
+ return (status);
+}
+
+static int
+mpr_diag_query(struct mpr_softc *sc, mpr_fw_diag_query_t *diag_query,
+ uint32_t *return_code)
+{
+ mpr_fw_diagnostic_buffer_t *pBuffer;
+ uint8_t i;
+ uint32_t unique_id;
+
+ unique_id = diag_query->UniqueId;
+
+ /*
+ * If ID is valid, query on ID.
+ * If ID is invalid, query on buffer type.
+ */
+ if (unique_id == MPR_FW_DIAG_INVALID_UID) {
+ i = diag_query->BufferType;
+ if (i >= MPI2_DIAG_BUF_TYPE_COUNT) {
+ *return_code = MPR_FW_DIAG_ERROR_INVALID_UID;
+ return (MPR_DIAG_FAILURE);
+ }
+ } else {
+ i = mpr_get_fw_diag_buffer_number(sc, unique_id);
+ if (i == MPR_FW_DIAGNOSTIC_UID_NOT_FOUND) {
+ *return_code = MPR_FW_DIAG_ERROR_INVALID_UID;
+ return (MPR_DIAG_FAILURE);
+ }
+ }
+
+ /*
+ * Fill query structure with the diag buffer info.
+ */
+ pBuffer = &sc->fw_diag_buffer_list[i];
+ diag_query->BufferType = pBuffer->buffer_type;
+ diag_query->ExtendedType = pBuffer->extended_type;
+ if (diag_query->BufferType == MPI2_DIAG_BUF_TYPE_TRACE) {
+ for (i = 0; i < (sizeof(diag_query->ProductSpecific) / 4);
+ i++) {
+ diag_query->ProductSpecific[i] =
+ pBuffer->product_specific[i];
+ }
+ }
+ diag_query->TotalBufferSize = pBuffer->size;
+ diag_query->DriverAddedBufferSize = 0;
+ diag_query->UniqueId = pBuffer->unique_id;
+ diag_query->ApplicationFlags = 0;
+ diag_query->DiagnosticFlags = 0;
+
+ /*
+ * Set/Clear application flags
+ */
+ if (pBuffer->immediate) {
+ diag_query->ApplicationFlags &= ~MPR_FW_DIAG_FLAG_APP_OWNED;
+ } else {
+ diag_query->ApplicationFlags |= MPR_FW_DIAG_FLAG_APP_OWNED;
+ }
+ if (pBuffer->valid_data || pBuffer->owned_by_firmware) {
+ diag_query->ApplicationFlags |= MPR_FW_DIAG_FLAG_BUFFER_VALID;
+ } else {
+ diag_query->ApplicationFlags &= ~MPR_FW_DIAG_FLAG_BUFFER_VALID;
+ }
+ if (pBuffer->owned_by_firmware) {
+ diag_query->ApplicationFlags |=
+ MPR_FW_DIAG_FLAG_FW_BUFFER_ACCESS;
+ } else {
+ diag_query->ApplicationFlags &=
+ ~MPR_FW_DIAG_FLAG_FW_BUFFER_ACCESS;
+ }
+
+ return (MPR_DIAG_SUCCESS);
+}
+
+static int
+mpr_diag_read_buffer(struct mpr_softc *sc,
+ mpr_diag_read_buffer_t *diag_read_buffer, uint8_t *ioctl_buf,
+ uint32_t *return_code)
+{
+ mpr_fw_diagnostic_buffer_t *pBuffer;
+ uint8_t i, *pData;
+ uint32_t unique_id;
+ int status;
+
+ unique_id = diag_read_buffer->UniqueId;
+
+ /*
+ * Get the current buffer and look up the unique ID. The unique ID
+ * should be there.
+ */
+ i = mpr_get_fw_diag_buffer_number(sc, unique_id);
+ if (i == MPR_FW_DIAGNOSTIC_UID_NOT_FOUND) {
+ *return_code = MPR_FW_DIAG_ERROR_INVALID_UID;
+ return (MPR_DIAG_FAILURE);
+ }
+
+ pBuffer = &sc->fw_diag_buffer_list[i];
+
+ /*
+ * Make sure requested read is within limits
+ */
+ if (diag_read_buffer->StartingOffset + diag_read_buffer->BytesToRead >
+ pBuffer->size) {
+ *return_code = MPR_FW_DIAG_ERROR_INVALID_PARAMETER;
+ return (MPR_DIAG_FAILURE);
+ }
+
+ /*
+ * Copy the requested data from DMA to the diag_read_buffer. The DMA
+ * buffer that was allocated is one contiguous buffer.
+ */
+ pData = (uint8_t *)(sc->fw_diag_buffer +
+ diag_read_buffer->StartingOffset);
+ if (copyout(pData, ioctl_buf, diag_read_buffer->BytesToRead) != 0)
+ return (MPR_DIAG_FAILURE);
+ diag_read_buffer->Status = 0;
+
+ /*
+ * Set or clear the Force Release flag.
+ */
+ if (pBuffer->force_release) {
+ diag_read_buffer->Flags |= MPR_FW_DIAG_FLAG_FORCE_RELEASE;
+ } else {
+ diag_read_buffer->Flags &= ~MPR_FW_DIAG_FLAG_FORCE_RELEASE;
+ }
+
+ /*
+ * If buffer is to be reregistered, make sure it's not already owned by
+ * firmware first.
+ */
+ status = MPR_DIAG_SUCCESS;
+ if (!pBuffer->owned_by_firmware) {
+ if (diag_read_buffer->Flags & MPR_FW_DIAG_FLAG_REREGISTER) {
+ status = mpr_post_fw_diag_buffer(sc, pBuffer,
+ return_code);
+ }
+ }
+
+ return (status);
+}
+
+static int
+mpr_diag_release(struct mpr_softc *sc, mpr_fw_diag_release_t *diag_release,
+ uint32_t *return_code)
+{
+ mpr_fw_diagnostic_buffer_t *pBuffer;
+ uint8_t i;
+ uint32_t unique_id;
+ int status;
+
+ unique_id = diag_release->UniqueId;
+
+ /*
+ * Get the current buffer and look up the unique ID. The unique ID
+ * should be there.
+ */
+ i = mpr_get_fw_diag_buffer_number(sc, unique_id);
+ if (i == MPR_FW_DIAGNOSTIC_UID_NOT_FOUND) {
+ *return_code = MPR_FW_DIAG_ERROR_INVALID_UID;
+ return (MPR_DIAG_FAILURE);
+ }
+
+ pBuffer = &sc->fw_diag_buffer_list[i];
+
+ /*
+ * If buffer is not owned by firmware, it's already been released.
+ */
+ if (!pBuffer->owned_by_firmware) {
+ *return_code = MPR_FW_DIAG_ERROR_ALREADY_RELEASED;
+ return (MPR_DIAG_FAILURE);
+ }
+
+ /*
+ * Release the buffer.
+ */
+ status = mpr_release_fw_diag_buffer(sc, pBuffer, return_code,
+ MPR_FW_DIAG_TYPE_RELEASE);
+ return (status);
+}
+
+static int
+mpr_do_diag_action(struct mpr_softc *sc, uint32_t action,
+ uint8_t *diag_action, uint32_t length, uint32_t *return_code)
+{
+ mpr_fw_diag_register_t diag_register;
+ mpr_fw_diag_unregister_t diag_unregister;
+ mpr_fw_diag_query_t diag_query;
+ mpr_diag_read_buffer_t diag_read_buffer;
+ mpr_fw_diag_release_t diag_release;
+ int status = MPR_DIAG_SUCCESS;
+ uint32_t original_return_code;
+
+ original_return_code = *return_code;
+ *return_code = MPR_FW_DIAG_ERROR_SUCCESS;
+
+ switch (action) {
+ case MPR_FW_DIAG_TYPE_REGISTER:
+ if (!length) {
+ *return_code =
+ MPR_FW_DIAG_ERROR_INVALID_PARAMETER;
+ status = MPR_DIAG_FAILURE;
+ break;
+ }
+ if (copyin(diag_action, &diag_register,
+ sizeof(diag_register)) != 0)
+ return (MPR_DIAG_FAILURE);
+ status = mpr_diag_register(sc, &diag_register,
+ return_code);
+ break;
+
+ case MPR_FW_DIAG_TYPE_UNREGISTER:
+ if (length < sizeof(diag_unregister)) {
+ *return_code =
+ MPR_FW_DIAG_ERROR_INVALID_PARAMETER;
+ status = MPR_DIAG_FAILURE;
+ break;
+ }
+ if (copyin(diag_action, &diag_unregister,
+ sizeof(diag_unregister)) != 0)
+ return (MPR_DIAG_FAILURE);
+ status = mpr_diag_unregister(sc, &diag_unregister,
+ return_code);
+ break;
+
+ case MPR_FW_DIAG_TYPE_QUERY:
+ if (length < sizeof (diag_query)) {
+ *return_code =
+ MPR_FW_DIAG_ERROR_INVALID_PARAMETER;
+ status = MPR_DIAG_FAILURE;
+ break;
+ }
+ if (copyin(diag_action, &diag_query, sizeof(diag_query))
+ != 0)
+ return (MPR_DIAG_FAILURE);
+ status = mpr_diag_query(sc, &diag_query, return_code);
+ if (status == MPR_DIAG_SUCCESS)
+ if (copyout(&diag_query, diag_action,
+ sizeof (diag_query)) != 0)
+ return (MPR_DIAG_FAILURE);
+ break;
+
+ case MPR_FW_DIAG_TYPE_READ_BUFFER:
+ if (copyin(diag_action, &diag_read_buffer,
+ sizeof(diag_read_buffer)) != 0)
+ return (MPR_DIAG_FAILURE);
+ if (length < diag_read_buffer.BytesToRead) {
+ *return_code =
+ MPR_FW_DIAG_ERROR_INVALID_PARAMETER;
+ status = MPR_DIAG_FAILURE;
+ break;
+ }
+ status = mpr_diag_read_buffer(sc, &diag_read_buffer,
+ PTRIN(diag_read_buffer.PtrDataBuffer),
+ return_code);
+ if (status == MPR_DIAG_SUCCESS) {
+ if (copyout(&diag_read_buffer, diag_action,
+ sizeof(diag_read_buffer) -
+ sizeof(diag_read_buffer.PtrDataBuffer)) !=
+ 0)
+ return (MPR_DIAG_FAILURE);
+ }
+ break;
+
+ case MPR_FW_DIAG_TYPE_RELEASE:
+ if (length < sizeof(diag_release)) {
+ *return_code =
+ MPR_FW_DIAG_ERROR_INVALID_PARAMETER;
+ status = MPR_DIAG_FAILURE;
+ break;
+ }
+ if (copyin(diag_action, &diag_release,
+ sizeof(diag_release)) != 0)
+ return (MPR_DIAG_FAILURE);
+ status = mpr_diag_release(sc, &diag_release,
+ return_code);
+ break;
+
+ default:
+ *return_code = MPR_FW_DIAG_ERROR_INVALID_PARAMETER;
+ status = MPR_DIAG_FAILURE;
+ break;
+ }
+
+ if ((status == MPR_DIAG_FAILURE) &&
+ (original_return_code == MPR_FW_DIAG_NEW) &&
+ (*return_code != MPR_FW_DIAG_ERROR_SUCCESS))
+ status = MPR_DIAG_SUCCESS;
+
+ return (status);
+}
+
+static int
+mpr_user_diag_action(struct mpr_softc *sc, mpr_diag_action_t *data)
+{
+ int status;
+
+ /*
+ * Only allow one diag action at one time.
+ */
+ if (sc->mpr_flags & MPR_FLAGS_BUSY) {
+ mpr_dprint(sc, MPR_USER, "%s: Only one FW diag command "
+ "allowed at a single time.", __func__);
+ return (EBUSY);
+ }
+ sc->mpr_flags |= MPR_FLAGS_BUSY;
+
+ /*
+ * Send diag action request
+ */
+ if (data->Action == MPR_FW_DIAG_TYPE_REGISTER ||
+ data->Action == MPR_FW_DIAG_TYPE_UNREGISTER ||
+ data->Action == MPR_FW_DIAG_TYPE_QUERY ||
+ data->Action == MPR_FW_DIAG_TYPE_READ_BUFFER ||
+ data->Action == MPR_FW_DIAG_TYPE_RELEASE) {
+ status = mpr_do_diag_action(sc, data->Action,
+ PTRIN(data->PtrDiagAction), data->Length,
+ &data->ReturnCode);
+ } else
+ status = EINVAL;
+
+ sc->mpr_flags &= ~MPR_FLAGS_BUSY;
+ return (status);
+}
+
+/*
+ * Copy the event recording mask and the event queue size out. For
+ * clarification, the event recording mask (events_to_record) is not the same
+ * thing as the event mask (event_mask). events_to_record has a bit set for
+ * every event type that is to be recorded by the driver, and event_mask has a
+ * bit cleared for every event that is allowed into the driver from the IOC.
+ * They really have nothing to do with each other.
+ */
+static void
+mpr_user_event_query(struct mpr_softc *sc, mpr_event_query_t *data)
+{
+ uint8_t i;
+
+ mpr_lock(sc);
+ data->Entries = MPR_EVENT_QUEUE_SIZE;
+
+ for (i = 0; i < 4; i++) {
+ data->Types[i] = sc->events_to_record[i];
+ }
+ mpr_unlock(sc);
+}
+
+/*
+ * Set the driver's event mask according to what's been given. See
+ * mpr_user_event_query for explanation of the event recording mask and the IOC
+ * event mask. It's the app's responsibility to enable event logging by setting
+ * the bits in events_to_record. Initially, no events will be logged.
+ */
+static void
+mpr_user_event_enable(struct mpr_softc *sc, mpr_event_enable_t *data)
+{
+ uint8_t i;
+
+ mpr_lock(sc);
+ for (i = 0; i < 4; i++) {
+ sc->events_to_record[i] = data->Types[i];
+ }
+ mpr_unlock(sc);
+}
+
+/*
+ * Copy out the events that have been recorded, up to the max events allowed.
+ */
+static int
+mpr_user_event_report(struct mpr_softc *sc, mpr_event_report_t *data)
+{
+ int status = 0;
+ uint32_t size;
+
+ mpr_lock(sc);
+ size = data->Size;
+ if ((size >= sizeof(sc->recorded_events)) && (status == 0)) {
+ mpr_unlock(sc);
+ if (copyout((void *)sc->recorded_events,
+ PTRIN(data->PtrEvents), size) != 0)
+ status = EFAULT;
+ mpr_lock(sc);
+ } else {
+ /*
+ * data->Size value is not large enough to copy event data.
+ */
+ status = EFAULT;
+ }
+
+ /*
+ * Change size value to match the number of bytes that were copied.
+ */
+ if (status == 0)
+ data->Size = sizeof(sc->recorded_events);
+ mpr_unlock(sc);
+
+ return (status);
+}
+
+/*
+ * Record events into the driver from the IOC if they are not masked.
+ */
+void
+mprsas_record_event(struct mpr_softc *sc,
+ MPI2_EVENT_NOTIFICATION_REPLY *event_reply)
+{
+ uint32_t event;
+ int i, j;
+ uint16_t event_data_len;
+ boolean_t sendAEN = FALSE;
+
+ event = event_reply->Event;
+
+ /*
+ * Generate a system event to let anyone who cares know that a
+ * LOG_ENTRY_ADDED event has occurred. This is sent no matter what the
+ * event mask is set to.
+ */
+ if (event == MPI2_EVENT_LOG_ENTRY_ADDED) {
+ sendAEN = TRUE;
+ }
+
+ /*
+ * Record the event only if its corresponding bit is set in
+ * events_to_record. event_index is the index into recorded_events and
+ * event_number is the overall number of an event being recorded since
+ * start-of-day. event_index will roll over; event_number will never
+ * roll over.
+ */
+ i = (uint8_t)(event / 32);
+ j = (uint8_t)(event % 32);
+ if ((i < 4) && ((1 << j) & sc->events_to_record[i])) {
+ i = sc->event_index;
+ sc->recorded_events[i].Type = event;
+ sc->recorded_events[i].Number = ++sc->event_number;
+ bzero(sc->recorded_events[i].Data, MPR_MAX_EVENT_DATA_LENGTH *
+ 4);
+ event_data_len = event_reply->EventDataLength;
+
+ if (event_data_len > 0) {
+ /*
+ * Limit data to size in m_event entry
+ */
+ if (event_data_len > MPR_MAX_EVENT_DATA_LENGTH) {
+ event_data_len = MPR_MAX_EVENT_DATA_LENGTH;
+ }
+ for (j = 0; j < event_data_len; j++) {
+ sc->recorded_events[i].Data[j] =
+ event_reply->EventData[j];
+ }
+
+ /*
+ * check for index wrap-around
+ */
+ if (++i == MPR_EVENT_QUEUE_SIZE) {
+ i = 0;
+ }
+ sc->event_index = (uint8_t)i;
+
+ /*
+ * Set flag to send the event.
+ */
+ sendAEN = TRUE;
+ }
+ }
+
+ /*
+ * Generate a system event if flag is set to let anyone who cares know
+ * that an event has occurred.
+ */
+ if (sendAEN) {
+//SLM-how to send a system event (see kqueue, kevent)
+// (void) ddi_log_sysevent(mpt->m_dip, DDI_VENDOR_LSI, "MPT_SAS",
+// "SAS", NULL, NULL, DDI_NOSLEEP);
+ }
+}
+
+static int
+mpr_user_reg_access(struct mpr_softc *sc, mpr_reg_access_t *data)
+{
+ int status = 0;
+
+ switch (data->Command) {
+ /*
+ * IO access is not supported.
+ */
+ case REG_IO_READ:
+ case REG_IO_WRITE:
+ mpr_dprint(sc, MPR_USER, "IO access is not supported. "
+ "Use memory access.");
+ status = EINVAL;
+ break;
+
+ case REG_MEM_READ:
+ data->RegData = mpr_regread(sc, data->RegOffset);
+ break;
+
+ case REG_MEM_WRITE:
+ mpr_regwrite(sc, data->RegOffset, data->RegData);
+ break;
+
+ default:
+ status = EINVAL;
+ break;
+ }
+
+ return (status);
+}
+
+static int
+mpr_user_btdh(struct mpr_softc *sc, mpr_btdh_mapping_t *data)
+{
+ uint8_t bt2dh = FALSE;
+ uint8_t dh2bt = FALSE;
+ uint16_t dev_handle, bus, target;
+
+ bus = data->Bus;
+ target = data->TargetID;
+ dev_handle = data->DevHandle;
+
+ /*
+ * When DevHandle is 0xFFFF and Bus/Target are not 0xFFFF, use Bus/
+ * Target to get DevHandle. When Bus/Target are 0xFFFF and DevHandle is
+ * not 0xFFFF, use DevHandle to get Bus/Target. Anything else is
+ * invalid.
+ */
+ if ((bus == 0xFFFF) && (target == 0xFFFF) && (dev_handle != 0xFFFF))
+ dh2bt = TRUE;
+ if ((dev_handle == 0xFFFF) && (bus != 0xFFFF) && (target != 0xFFFF))
+ bt2dh = TRUE;
+ if (!dh2bt && !bt2dh)
+ return (EINVAL);
+
+ /*
+ * Only handle bus of 0. Make sure target is within range.
+ */
+ if (bt2dh) {
+ if (bus != 0)
+ return (EINVAL);
+
+ if (target > sc->max_devices) {
+ mpr_dprint(sc, MPR_FAULT, "Target ID is out of range "
+ "for Bus/Target to DevHandle mapping.");
+ return (EINVAL);
+ }
+ dev_handle = sc->mapping_table[target].dev_handle;
+ if (dev_handle)
+ data->DevHandle = dev_handle;
+ } else {
+ bus = 0;
+ target = mpr_mapping_get_sas_id_from_handle(sc, dev_handle);
+ data->Bus = bus;
+ data->TargetID = target;
+ }
+
+ return (0);
+}
+
+static int
+mpr_ioctl(struct cdev *dev, u_long cmd, void *arg, int flag,
+ struct thread *td)
+{
+ struct mpr_softc *sc;
+ struct mpr_cfg_page_req *page_req;
+ struct mpr_ext_cfg_page_req *ext_page_req;
+ void *mpr_page;
+ int error, msleep_ret;
+
+ mpr_page = NULL;
+ sc = dev->si_drv1;
+ page_req = (void *)arg;
+ ext_page_req = (void *)arg;
+
+ switch (cmd) {
+ case MPRIO_READ_CFG_HEADER:
+ mpr_lock(sc);
+ error = mpr_user_read_cfg_header(sc, page_req);
+ mpr_unlock(sc);
+ break;
+ case MPRIO_READ_CFG_PAGE:
+ mpr_page = malloc(page_req->len, M_MPRUSER, M_WAITOK | M_ZERO);
+ if (!mpr_page) {
+ mpr_printf(sc, "Cannot allocate memory %s %d\n",
+ __func__, __LINE__);
+ return (ENOMEM);
+ }
+ error = copyin(page_req->buf, mpr_page,
+ sizeof(MPI2_CONFIG_PAGE_HEADER));
+ if (error)
+ break;
+ mpr_lock(sc);
+ error = mpr_user_read_cfg_page(sc, page_req, mpr_page);
+ mpr_unlock(sc);
+ if (error)
+ break;
+ error = copyout(mpr_page, page_req->buf, page_req->len);
+ break;
+ case MPRIO_READ_EXT_CFG_HEADER:
+ mpr_lock(sc);
+ error = mpr_user_read_extcfg_header(sc, ext_page_req);
+ mpr_unlock(sc);
+ break;
+ case MPRIO_READ_EXT_CFG_PAGE:
+ mpr_page = malloc(ext_page_req->len, M_MPRUSER,
+ M_WAITOK | M_ZERO);
+ if (!mpr_page) {
+ mpr_printf(sc, "Cannot allocate memory %s %d\n",
+ __func__, __LINE__);
+ return (ENOMEM);
+ }
+ error = copyin(ext_page_req->buf, mpr_page,
+ sizeof(MPI2_CONFIG_EXTENDED_PAGE_HEADER));
+ if (error)
+ break;
+ mpr_lock(sc);
+ error = mpr_user_read_extcfg_page(sc, ext_page_req, mpr_page);
+ mpr_unlock(sc);
+ if (error)
+ break;
+ error = copyout(mpr_page, ext_page_req->buf, ext_page_req->len);
+ break;
+ case MPRIO_WRITE_CFG_PAGE:
+ mpr_page = malloc(page_req->len, M_MPRUSER, M_WAITOK|M_ZERO);
+ if (!mpr_page) {
+ mpr_printf(sc, "Cannot allocate memory %s %d\n",
+ __func__, __LINE__);
+ return (ENOMEM);
+ }
+ error = copyin(page_req->buf, mpr_page, page_req->len);
+ if (error)
+ break;
+ mpr_lock(sc);
+ error = mpr_user_write_cfg_page(sc, page_req, mpr_page);
+ mpr_unlock(sc);
+ break;
+ case MPRIO_MPR_COMMAND:
+ error = mpr_user_command(sc, (struct mpr_usr_command *)arg);
+ break;
+ case MPTIOCTL_PASS_THRU:
+ /*
+ * The user has requested to pass through a command to be
+ * executed by the MPT firmware. Call our routine which does
+ * this. Only allow one passthru IOCTL at one time.
+ */
+ error = mpr_user_pass_thru(sc, (mpr_pass_thru_t *)arg);
+ break;
+ case MPTIOCTL_GET_ADAPTER_DATA:
+ /*
+ * The user has requested to read adapter data. Call our
+ * routine which does this.
+ */
+ error = 0;
+ mpr_user_get_adapter_data(sc, (mpr_adapter_data_t *)arg);
+ break;
+ case MPTIOCTL_GET_PCI_INFO:
+ /*
+ * The user has requested to read pci info. Call
+ * our routine which does this.
+ */
+ mpr_lock(sc);
+ error = 0;
+ mpr_user_read_pci_info(sc, (mpr_pci_info_t *)arg);
+ mpr_unlock(sc);
+ break;
+ case MPTIOCTL_RESET_ADAPTER:
+ mpr_lock(sc);
+ sc->port_enable_complete = 0;
+ uint32_t reinit_start = time_uptime;
+ error = mpr_reinit(sc);
+ /* Sleep for 300 second. */
+ msleep_ret = msleep(&sc->port_enable_complete, &sc->mpr_mtx,
+ PRIBIO, "mpr_porten", 300 * hz);
+ mpr_unlock(sc);
+ if (msleep_ret)
+ printf("Port Enable did not complete after Diag "
+ "Reset msleep error %d.\n", msleep_ret);
+ else
+ mpr_dprint(sc, MPR_USER, "Hard Reset with Port Enable "
+ "completed in %d seconds.\n",
+ (uint32_t)(time_uptime - reinit_start));
+ break;
+ case MPTIOCTL_DIAG_ACTION:
+ /*
+ * The user has done a diag buffer action. Call our routine
+ * which does this. Only allow one diag action at one time.
+ */
+ mpr_lock(sc);
+ error = mpr_user_diag_action(sc, (mpr_diag_action_t *)arg);
+ mpr_unlock(sc);
+ break;
+ case MPTIOCTL_EVENT_QUERY:
+ /*
+ * The user has done an event query. Call our routine which does
+ * this.
+ */
+ error = 0;
+ mpr_user_event_query(sc, (mpr_event_query_t *)arg);
+ break;
+ case MPTIOCTL_EVENT_ENABLE:
+ /*
+ * The user has done an event enable. Call our routine which
+ * does this.
+ */
+ error = 0;
+ mpr_user_event_enable(sc, (mpr_event_enable_t *)arg);
+ break;
+ case MPTIOCTL_EVENT_REPORT:
+ /*
+ * The user has done an event report. Call our routine which
+ * does this.
+ */
+ error = mpr_user_event_report(sc, (mpr_event_report_t *)arg);
+ break;
+ case MPTIOCTL_REG_ACCESS:
+ /*
+ * The user has requested register access. Call our routine
+ * which does this.
+ */
+ mpr_lock(sc);
+ error = mpr_user_reg_access(sc, (mpr_reg_access_t *)arg);
+ mpr_unlock(sc);
+ break;
+ case MPTIOCTL_BTDH_MAPPING:
+ /*
+ * The user has requested to translate a bus/target to a
+ * DevHandle or a DevHandle to a bus/target. Call our routine
+ * which does this.
+ */
+ error = mpr_user_btdh(sc, (mpr_btdh_mapping_t *)arg);
+ break;
+ default:
+ error = ENOIOCTL;
+ break;
+ }
+
+ if (mpr_page != NULL)
+ free(mpr_page, M_MPRUSER);
+
+ return (error);
+}
+
+#ifdef COMPAT_FREEBSD32
+
+struct mpr_cfg_page_req32 {
+ MPI2_CONFIG_PAGE_HEADER header;
+ uint32_t page_address;
+ uint32_t buf;
+ int len;
+ uint16_t ioc_status;
+};
+
+struct mpr_ext_cfg_page_req32 {
+ MPI2_CONFIG_EXTENDED_PAGE_HEADER header;
+ uint32_t page_address;
+ uint32_t buf;
+ int len;
+ uint16_t ioc_status;
+};
+
+struct mpr_raid_action32 {
+ uint8_t action;
+ uint8_t volume_bus;
+ uint8_t volume_id;
+ uint8_t phys_disk_num;
+ uint32_t action_data_word;
+ uint32_t buf;
+ int len;
+ uint32_t volume_status;
+ uint32_t action_data[4];
+ uint16_t action_status;
+ uint16_t ioc_status;
+ uint8_t write;
+};
+
+struct mpr_usr_command32 {
+ uint32_t req;
+ uint32_t req_len;
+ uint32_t rpl;
+ uint32_t rpl_len;
+ uint32_t buf;
+ int len;
+ uint32_t flags;
+};
+
+#define MPRIO_READ_CFG_HEADER32 _IOWR('M', 200, struct mpr_cfg_page_req32)
+#define MPRIO_READ_CFG_PAGE32 _IOWR('M', 201, struct mpr_cfg_page_req32)
+#define MPRIO_READ_EXT_CFG_HEADER32 _IOWR('M', 202, struct mpr_ext_cfg_page_req32)
+#define MPRIO_READ_EXT_CFG_PAGE32 _IOWR('M', 203, struct mpr_ext_cfg_page_req32)
+#define MPRIO_WRITE_CFG_PAGE32 _IOWR('M', 204, struct mpr_cfg_page_req32)
+#define MPRIO_RAID_ACTION32 _IOWR('M', 205, struct mpr_raid_action32)
+#define MPRIO_MPR_COMMAND32 _IOWR('M', 210, struct mpr_usr_command32)
+
+static int
+mpr_ioctl32(struct cdev *dev, u_long cmd32, void *_arg, int flag,
+ struct thread *td)
+{
+ struct mpr_cfg_page_req32 *page32 = _arg;
+ struct mpr_ext_cfg_page_req32 *ext32 = _arg;
+ struct mpr_raid_action32 *raid32 = _arg;
+ struct mpr_usr_command32 *user32 = _arg;
+ union {
+ struct mpr_cfg_page_req page;
+ struct mpr_ext_cfg_page_req ext;
+ struct mpr_raid_action raid;
+ struct mpr_usr_command user;
+ } arg;
+ u_long cmd;
+ int error;
+
+ switch (cmd32) {
+ case MPRIO_READ_CFG_HEADER32:
+ case MPRIO_READ_CFG_PAGE32:
+ case MPRIO_WRITE_CFG_PAGE32:
+ if (cmd32 == MPRIO_READ_CFG_HEADER32)
+ cmd = MPRIO_READ_CFG_HEADER;
+ else if (cmd32 == MPRIO_READ_CFG_PAGE32)
+ cmd = MPRIO_READ_CFG_PAGE;
+ else
+ cmd = MPRIO_WRITE_CFG_PAGE;
+ CP(*page32, arg.page, header);
+ CP(*page32, arg.page, page_address);
+ PTRIN_CP(*page32, arg.page, buf);
+ CP(*page32, arg.page, len);
+ CP(*page32, arg.page, ioc_status);
+ break;
+
+ case MPRIO_READ_EXT_CFG_HEADER32:
+ case MPRIO_READ_EXT_CFG_PAGE32:
+ if (cmd32 == MPRIO_READ_EXT_CFG_HEADER32)
+ cmd = MPRIO_READ_EXT_CFG_HEADER;
+ else
+ cmd = MPRIO_READ_EXT_CFG_PAGE;
+ CP(*ext32, arg.ext, header);
+ CP(*ext32, arg.ext, page_address);
+ PTRIN_CP(*ext32, arg.ext, buf);
+ CP(*ext32, arg.ext, len);
+ CP(*ext32, arg.ext, ioc_status);
+ break;
+
+ case MPRIO_RAID_ACTION32:
+ cmd = MPRIO_RAID_ACTION;
+ CP(*raid32, arg.raid, action);
+ CP(*raid32, arg.raid, volume_bus);
+ CP(*raid32, arg.raid, volume_id);
+ CP(*raid32, arg.raid, phys_disk_num);
+ CP(*raid32, arg.raid, action_data_word);
+ PTRIN_CP(*raid32, arg.raid, buf);
+ CP(*raid32, arg.raid, len);
+ CP(*raid32, arg.raid, volume_status);
+ bcopy(raid32->action_data, arg.raid.action_data,
+ sizeof arg.raid.action_data);
+ CP(*raid32, arg.raid, ioc_status);
+ CP(*raid32, arg.raid, write);
+ break;
+
+ case MPRIO_MPR_COMMAND32:
+ cmd = MPRIO_MPR_COMMAND;
+ PTRIN_CP(*user32, arg.user, req);
+ CP(*user32, arg.user, req_len);
+ PTRIN_CP(*user32, arg.user, rpl);
+ CP(*user32, arg.user, rpl_len);
+ PTRIN_CP(*user32, arg.user, buf);
+ CP(*user32, arg.user, len);
+ CP(*user32, arg.user, flags);
+ break;
+ default:
+ return (ENOIOCTL);
+ }
+
+ error = mpr_ioctl(dev, cmd, &arg, flag, td);
+ if (error == 0 && (cmd32 & IOC_OUT) != 0) {
+ switch (cmd32) {
+ case MPRIO_READ_CFG_HEADER32:
+ case MPRIO_READ_CFG_PAGE32:
+ case MPRIO_WRITE_CFG_PAGE32:
+ CP(arg.page, *page32, header);
+ CP(arg.page, *page32, page_address);
+ PTROUT_CP(arg.page, *page32, buf);
+ CP(arg.page, *page32, len);
+ CP(arg.page, *page32, ioc_status);
+ break;
+
+ case MPRIO_READ_EXT_CFG_HEADER32:
+ case MPRIO_READ_EXT_CFG_PAGE32:
+ CP(arg.ext, *ext32, header);
+ CP(arg.ext, *ext32, page_address);
+ PTROUT_CP(arg.ext, *ext32, buf);
+ CP(arg.ext, *ext32, len);
+ CP(arg.ext, *ext32, ioc_status);
+ break;
+
+ case MPRIO_RAID_ACTION32:
+ CP(arg.raid, *raid32, action);
+ CP(arg.raid, *raid32, volume_bus);
+ CP(arg.raid, *raid32, volume_id);
+ CP(arg.raid, *raid32, phys_disk_num);
+ CP(arg.raid, *raid32, action_data_word);
+ PTROUT_CP(arg.raid, *raid32, buf);
+ CP(arg.raid, *raid32, len);
+ CP(arg.raid, *raid32, volume_status);
+ bcopy(arg.raid.action_data, raid32->action_data,
+ sizeof arg.raid.action_data);
+ CP(arg.raid, *raid32, ioc_status);
+ CP(arg.raid, *raid32, write);
+ break;
+
+ case MPRIO_MPR_COMMAND32:
+ PTROUT_CP(arg.user, *user32, req);
+ CP(arg.user, *user32, req_len);
+ PTROUT_CP(arg.user, *user32, rpl);
+ CP(arg.user, *user32, rpl_len);
+ PTROUT_CP(arg.user, *user32, buf);
+ CP(arg.user, *user32, len);
+ CP(arg.user, *user32, flags);
+ break;
+ }
+ }
+
+ return (error);
+}
+#endif /* COMPAT_FREEBSD32 */
+
+static int
+mpr_ioctl_devsw(struct cdev *dev, u_long com, caddr_t arg, int flag,
+ struct thread *td)
+{
+#ifdef COMPAT_FREEBSD32
+ if (SV_CURPROC_FLAG(SV_ILP32))
+ return (mpr_ioctl32(dev, com, arg, flag, td));
+#endif
+ return (mpr_ioctl(dev, com, arg, flag, td));
+}
diff --git a/sys/dev/mpr/mprvar.h b/sys/dev/mpr/mprvar.h
new file mode 100644
index 0000000..9752dcd
--- /dev/null
+++ b/sys/dev/mpr/mprvar.h
@@ -0,0 +1,766 @@
+/*-
+ * Copyright (c) 2009 Yahoo! Inc.
+ * Copyright (c) 2011-2014 LSI Corp.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+
+#ifndef _MPRVAR_H
+#define _MPRVAR_H
+
+#define MPR_DRIVER_VERSION "05.255.05.00-fbsd"
+
+#define MPR_DB_MAX_WAIT 2500
+
+#define MPR_REQ_FRAMES 1024
+#define MPR_EVT_REPLY_FRAMES 32
+#define MPR_REPLY_FRAMES MPR_REQ_FRAMES
+#define MPR_CHAIN_FRAMES 2048
+#define MPR_SENSE_LEN SSD_FULL_SIZE
+#define MPR_MSI_COUNT 1
+#define MPR_SGE64_SIZE 12
+#define MPR_SGE32_SIZE 8
+#define MPR_SGC_SIZE 8
+
+#define MPR_FUNCTRACE(sc) \
+ mpr_dprint((sc), MPR_TRACE, "%s\n", __func__)
+
+#define CAN_SLEEP 1
+#define NO_SLEEP 0
+
+#define MPR_PERIODIC_DELAY 1 /* 1 second heartbeat/watchdog check */
+
+#define IFAULT_IOP_OVER_TEMP_THRESHOLD_EXCEEDED 0x2810
+
+#define MPR_SCSI_RI_INVALID_FRAME (0x00000002)
+#define MPR_STRING_LENGTH 64
+
+#include <sys/endian.h>
+
+/*
+ * host mapping related macro definitions
+ */
+#define MPR_MAPTABLE_BAD_IDX 0xFFFFFFFF
+#define MPR_DPM_BAD_IDX 0xFFFF
+#define MPR_ENCTABLE_BAD_IDX 0xFF
+#define MPR_MAX_MISSING_COUNT 0x0F
+#define MPR_DEV_RESERVED 0x20000000
+#define MPR_MAP_IN_USE 0x10000000
+#define MPR_RAID_CHANNEL 1
+#define MPR_MAP_BAD_ID 0xFFFFFFFF
+
+typedef uint8_t u8;
+typedef uint16_t u16;
+typedef uint32_t u32;
+typedef uint64_t u64;
+
+/**
+ * struct dev_mapping_table - device mapping information
+ * @physical_id: SAS address for drives or WWID for RAID volumes
+ * @device_info: bitfield provides detailed info about the device
+ * @phy_bits: bitfields indicating controller phys
+ * @dpm_entry_num: index of this device in device persistent map table
+ * @dev_handle: device handle for the device pointed by this entry
+ * @channel: target channel
+ * @id: target id
+ * @missing_count: number of times the device not detected by driver
+ * @hide_flag: Hide this physical disk/not (foreign configuration)
+ * @init_complete: Whether the start of the day checks completed or not
+ * @TLR_bits: Turn TLR support on or off
+ */
+struct dev_mapping_table {
+ u64 physical_id;
+ u32 device_info;
+ u32 phy_bits;
+ u16 dpm_entry_num;
+ u16 dev_handle;
+ u8 reserved1;
+ u8 channel;
+ u16 id;
+ u8 missing_count;
+ u8 init_complete;
+ u8 TLR_bits;
+ u8 reserved2;
+};
+
+/**
+ * struct enc_mapping_table - mapping information about an enclosure
+ * @enclosure_id: Logical ID of this enclosure
+ * @start_index: index to the entry in dev_mapping_table
+ * @phy_bits: bitfields indicating controller phys
+ * @dpm_entry_num: index of this enclosure in device persistent map table
+ * @enc_handle: device handle for the enclosure pointed by this entry
+ * @num_slots: number of slots in the enclosure
+ * @start_slot: Starting slot id
+ * @missing_count: number of times the device not detected by driver
+ * @removal_flag: used to mark the device for removal
+ * @skip_search: used as a flag to include/exclude enclosure for search
+ * @init_complete: Whether the start of the day checks completed or not
+ */
+struct enc_mapping_table {
+ u64 enclosure_id;
+ u32 start_index;
+ u32 phy_bits;
+ u16 dpm_entry_num;
+ u16 enc_handle;
+ u16 num_slots;
+ u16 start_slot;
+ u8 missing_count;
+ u8 removal_flag;
+ u8 skip_search;
+ u8 init_complete;
+};
+
+/**
+ * struct map_removal_table - entries to be removed from mapping table
+ * @dpm_entry_num: index of this device in device persistent map table
+ * @dev_handle: device handle for the device pointed by this entry
+ */
+struct map_removal_table{
+ u16 dpm_entry_num;
+ u16 dev_handle;
+};
+
+typedef struct mpr_fw_diagnostic_buffer {
+ size_t size;
+ uint8_t extended_type;
+ uint8_t buffer_type;
+ uint8_t force_release;
+ uint32_t product_specific[23];
+ uint8_t immediate;
+ uint8_t enabled;
+ uint8_t valid_data;
+ uint8_t owned_by_firmware;
+ uint32_t unique_id;
+} mpr_fw_diagnostic_buffer_t;
+
+struct mpr_softc;
+struct mpr_command;
+struct mprsas_softc;
+union ccb;
+struct mprsas_target;
+struct mpr_column_map;
+
+MALLOC_DECLARE(M_MPR);
+
+typedef void mpr_evt_callback_t(struct mpr_softc *, uintptr_t,
+ MPI2_EVENT_NOTIFICATION_REPLY *reply);
+typedef void mpr_command_callback_t(struct mpr_softc *, struct mpr_command *cm);
+
+struct mpr_chain {
+ TAILQ_ENTRY(mpr_chain) chain_link;
+ void *chain;
+ uint64_t chain_busaddr;
+};
+
+/*
+ * This needs to be at least 2 to support SMP passthrough.
+ */
+#define MPR_IOVEC_COUNT 2
+
+struct mpr_command {
+ TAILQ_ENTRY(mpr_command) cm_link;
+ TAILQ_ENTRY(mpr_command) cm_recovery;
+ struct mpr_softc *cm_sc;
+ union ccb *cm_ccb;
+ void *cm_data;
+ u_int cm_length;
+ u_int cm_out_len;
+ struct uio cm_uio;
+ struct iovec cm_iovec[MPR_IOVEC_COUNT];
+ u_int cm_max_segs;
+ u_int cm_sglsize;
+ void *cm_sge;
+ uint8_t *cm_req;
+ uint8_t *cm_reply;
+ uint32_t cm_reply_data;
+ mpr_command_callback_t *cm_complete;
+ void *cm_complete_data;
+ struct mprsas_target *cm_targ;
+ MPI2_REQUEST_DESCRIPTOR_UNION cm_desc;
+ u_int cm_lun;
+ u_int cm_flags;
+#define MPR_CM_FLAGS_POLLED (1 << 0)
+#define MPR_CM_FLAGS_COMPLETE (1 << 1)
+#define MPR_CM_FLAGS_SGE_SIMPLE (1 << 2)
+#define MPR_CM_FLAGS_DATAOUT (1 << 3)
+#define MPR_CM_FLAGS_DATAIN (1 << 4)
+#define MPR_CM_FLAGS_WAKEUP (1 << 5)
+#define MPR_CM_FLAGS_USE_UIO (1 << 6)
+#define MPR_CM_FLAGS_SMP_PASS (1 << 7)
+#define MPR_CM_FLAGS_CHAIN_FAILED (1 << 8)
+#define MPR_CM_FLAGS_ERROR_MASK MPR_CM_FLAGS_CHAIN_FAILED
+#define MPR_CM_FLAGS_USE_CCB (1 << 9)
+ u_int cm_state;
+#define MPR_CM_STATE_FREE 0
+#define MPR_CM_STATE_BUSY 1
+#define MPR_CM_STATE_TIMEDOUT 2
+ bus_dmamap_t cm_dmamap;
+ struct scsi_sense_data *cm_sense;
+ TAILQ_HEAD(, mpr_chain) cm_chain_list;
+ uint32_t cm_req_busaddr;
+ uint32_t cm_sense_busaddr;
+ struct callout cm_callout;
+};
+
+struct mpr_column_map {
+ uint16_t dev_handle;
+ uint8_t phys_disk_num;
+};
+
+struct mpr_event_handle {
+ TAILQ_ENTRY(mpr_event_handle) eh_list;
+ mpr_evt_callback_t *callback;
+ void *data;
+ uint8_t mask[16];
+};
+
+struct mpr_softc {
+ device_t mpr_dev;
+ struct cdev *mpr_cdev;
+ u_int mpr_flags;
+#define MPR_FLAGS_INTX (1 << 0)
+#define MPR_FLAGS_MSI (1 << 1)
+#define MPR_FLAGS_BUSY (1 << 2)
+#define MPR_FLAGS_SHUTDOWN (1 << 3)
+#define MPR_FLAGS_DIAGRESET (1 << 4)
+#define MPR_FLAGS_ATTACH_DONE (1 << 5)
+ u_int mpr_debug;
+ u_int disable_msix;
+ u_int disable_msi;
+ int tm_cmds_active;
+ int io_cmds_active;
+ int io_cmds_highwater;
+ int chain_free;
+ int max_chains;
+ int chain_free_lowwater;
+#if __FreeBSD_version >= 900030
+ uint64_t chain_alloc_fail;
+#endif
+ struct sysctl_ctx_list sysctl_ctx;
+ struct sysctl_oid *sysctl_tree;
+ char fw_version[16];
+ struct mpr_command *commands;
+ struct mpr_chain *chains;
+ struct callout periodic;
+
+ struct mprsas_softc *sassc;
+ char tmp_string[MPR_STRING_LENGTH];
+ TAILQ_HEAD(, mpr_command) req_list;
+ TAILQ_HEAD(, mpr_command) high_priority_req_list;
+ TAILQ_HEAD(, mpr_chain) chain_list;
+ TAILQ_HEAD(, mpr_command) tm_list;
+ int replypostindex;
+ int replyfreeindex;
+
+ struct resource *mpr_regs_resource;
+ bus_space_handle_t mpr_bhandle;
+ bus_space_tag_t mpr_btag;
+ int mpr_regs_rid;
+
+ bus_dma_tag_t mpr_parent_dmat;
+ bus_dma_tag_t buffer_dmat;
+
+ MPI2_IOC_FACTS_REPLY *facts;
+ int num_reqs;
+ int num_replies;
+ int fqdepth; /* Free queue */
+ int pqdepth; /* Post queue */
+
+ uint8_t event_mask[16];
+ TAILQ_HEAD(, mpr_event_handle) event_list;
+ struct mpr_event_handle *mpr_log_eh;
+
+ struct mtx mpr_mtx;
+ struct intr_config_hook mpr_ich;
+ struct resource *mpr_irq[MPR_MSI_COUNT];
+ void *mpr_intrhand[MPR_MSI_COUNT];
+ int mpr_irq_rid[MPR_MSI_COUNT];
+
+ uint8_t *req_frames;
+ bus_addr_t req_busaddr;
+ bus_dma_tag_t req_dmat;
+ bus_dmamap_t req_map;
+
+ uint8_t *reply_frames;
+ bus_addr_t reply_busaddr;
+ bus_dma_tag_t reply_dmat;
+ bus_dmamap_t reply_map;
+
+ struct scsi_sense_data *sense_frames;
+ bus_addr_t sense_busaddr;
+ bus_dma_tag_t sense_dmat;
+ bus_dmamap_t sense_map;
+
+ uint8_t *chain_frames;
+ bus_addr_t chain_busaddr;
+ bus_dma_tag_t chain_dmat;
+ bus_dmamap_t chain_map;
+
+ MPI2_REPLY_DESCRIPTORS_UNION *post_queue;
+ bus_addr_t post_busaddr;
+ uint32_t *free_queue;
+ bus_addr_t free_busaddr;
+ bus_dma_tag_t queues_dmat;
+ bus_dmamap_t queues_map;
+
+ uint8_t *fw_diag_buffer;
+ bus_addr_t fw_diag_busaddr;
+ bus_dma_tag_t fw_diag_dmat;
+ bus_dmamap_t fw_diag_map;
+
+ uint8_t ir_firmware;
+
+ /* static config pages */
+ Mpi2IOCPage8_t ioc_pg8;
+ Mpi2IOUnitPage8_t iounit_pg8;
+
+ /* host mapping support */
+ struct dev_mapping_table *mapping_table;
+ struct enc_mapping_table *enclosure_table;
+ struct map_removal_table *removal_table;
+ uint8_t *dpm_entry_used;
+ uint8_t *dpm_flush_entry;
+ Mpi2DriverMappingPage0_t *dpm_pg0;
+ uint16_t max_devices;
+ uint16_t max_enclosures;
+ uint16_t max_expanders;
+ uint8_t max_volumes;
+ uint8_t num_enc_table_entries;
+ uint8_t num_rsvd_entries;
+ uint8_t num_channels;
+ uint16_t max_dpm_entries;
+ uint8_t is_dpm_enable;
+ uint8_t track_mapping_events;
+ uint32_t pending_map_events;
+ uint8_t mt_full_retry;
+ uint8_t mt_add_device_failed;
+
+ /* FW diag Buffer List */
+ mpr_fw_diagnostic_buffer_t
+ fw_diag_buffer_list[MPI2_DIAG_BUF_TYPE_COUNT];
+
+ /* Event Recording IOCTL support */
+ uint32_t events_to_record[4];
+ mpr_event_entry_t recorded_events[MPR_EVENT_QUEUE_SIZE];
+ uint8_t event_index;
+ uint32_t event_number;
+
+ /* EEDP and TLR support */
+ uint8_t eedp_enabled;
+ uint8_t control_TLR;
+
+ /* Shutdown Event Handler */
+ eventhandler_tag shutdown_eh;
+
+ /* To track topo events during reset */
+#define MPR_DIAG_RESET_TIMEOUT 300000
+ uint8_t wait_for_port_enable;
+ uint8_t port_enable_complete;
+ uint8_t msleep_fake_chan;
+
+ /* StartStopUnit command handling at shutdown */
+ uint32_t SSU_refcount;
+ uint8_t SSU_started;
+
+ char exclude_ids[80];
+ struct timeval lastfail;
+};
+
+struct mpr_config_params {
+ MPI2_CONFIG_EXT_PAGE_HEADER_UNION hdr;
+ u_int action;
+ u_int page_address; /* Attributes, not a phys address */
+ u_int status;
+ void *buffer;
+ u_int length;
+ int timeout;
+ void (*callback)(struct mpr_softc *, struct mpr_config_params *);
+ void *cbdata;
+};
+
+struct scsi_read_capacity_eedp
+{
+ uint8_t addr[8];
+ uint8_t length[4];
+ uint8_t protect;
+};
+
+static __inline uint32_t
+mpr_regread(struct mpr_softc *sc, uint32_t offset)
+{
+ return (bus_space_read_4(sc->mpr_btag, sc->mpr_bhandle, offset));
+}
+
+static __inline void
+mpr_regwrite(struct mpr_softc *sc, uint32_t offset, uint32_t val)
+{
+ bus_space_write_4(sc->mpr_btag, sc->mpr_bhandle, offset, val);
+}
+
+/* free_queue must have Little Endian address
+ * TODO- cm_reply_data is unwanted. We can remove it.
+ * */
+static __inline void
+mpr_free_reply(struct mpr_softc *sc, uint32_t busaddr)
+{
+ if (++sc->replyfreeindex >= sc->fqdepth)
+ sc->replyfreeindex = 0;
+ sc->free_queue[sc->replyfreeindex] = htole32(busaddr);
+ mpr_regwrite(sc, MPI2_REPLY_FREE_HOST_INDEX_OFFSET, sc->replyfreeindex);
+}
+
+static __inline struct mpr_chain *
+mpr_alloc_chain(struct mpr_softc *sc)
+{
+ struct mpr_chain *chain;
+
+ if ((chain = TAILQ_FIRST(&sc->chain_list)) != NULL) {
+ TAILQ_REMOVE(&sc->chain_list, chain, chain_link);
+ sc->chain_free--;
+ if (sc->chain_free < sc->chain_free_lowwater)
+ sc->chain_free_lowwater = sc->chain_free;
+ }
+#if __FreeBSD_version >= 900030
+ else
+ sc->chain_alloc_fail++;
+#endif
+ return (chain);
+}
+
+static __inline void
+mpr_free_chain(struct mpr_softc *sc, struct mpr_chain *chain)
+{
+#if 0
+ bzero(chain->chain, 128);
+#endif
+ sc->chain_free++;
+ TAILQ_INSERT_TAIL(&sc->chain_list, chain, chain_link);
+}
+
+static __inline void
+mpr_free_command(struct mpr_softc *sc, struct mpr_command *cm)
+{
+ struct mpr_chain *chain, *chain_temp;
+
+ if (cm->cm_reply != NULL)
+ mpr_free_reply(sc, cm->cm_reply_data);
+ cm->cm_reply = NULL;
+ cm->cm_flags = 0;
+ cm->cm_complete = NULL;
+ cm->cm_complete_data = NULL;
+ cm->cm_ccb = NULL;
+ cm->cm_targ = NULL;
+ cm->cm_max_segs = 0;
+ cm->cm_lun = 0;
+ cm->cm_state = MPR_CM_STATE_FREE;
+ cm->cm_data = NULL;
+ cm->cm_length = 0;
+ cm->cm_out_len = 0;
+ cm->cm_sglsize = 0;
+ cm->cm_sge = NULL;
+
+ TAILQ_FOREACH_SAFE(chain, &cm->cm_chain_list, chain_link, chain_temp) {
+ TAILQ_REMOVE(&cm->cm_chain_list, chain, chain_link);
+ mpr_free_chain(sc, chain);
+ }
+ TAILQ_INSERT_TAIL(&sc->req_list, cm, cm_link);
+}
+
+static __inline struct mpr_command *
+mpr_alloc_command(struct mpr_softc *sc)
+{
+ struct mpr_command *cm;
+
+ cm = TAILQ_FIRST(&sc->req_list);
+ if (cm == NULL)
+ return (NULL);
+
+ TAILQ_REMOVE(&sc->req_list, cm, cm_link);
+ KASSERT(cm->cm_state == MPR_CM_STATE_FREE, ("mpr: Allocating busy command\n"));
+ cm->cm_state = MPR_CM_STATE_BUSY;
+ return (cm);
+}
+
+static __inline void
+mpr_free_high_priority_command(struct mpr_softc *sc, struct mpr_command *cm)
+{
+ struct mpr_chain *chain, *chain_temp;
+
+ if (cm->cm_reply != NULL)
+ mpr_free_reply(sc, cm->cm_reply_data);
+ cm->cm_reply = NULL;
+ cm->cm_flags = 0;
+ cm->cm_complete = NULL;
+ cm->cm_complete_data = NULL;
+ cm->cm_ccb = NULL;
+ cm->cm_targ = NULL;
+ cm->cm_lun = 0;
+ cm->cm_state = MPR_CM_STATE_FREE;
+ TAILQ_FOREACH_SAFE(chain, &cm->cm_chain_list, chain_link, chain_temp) {
+ TAILQ_REMOVE(&cm->cm_chain_list, chain, chain_link);
+ mpr_free_chain(sc, chain);
+ }
+ TAILQ_INSERT_TAIL(&sc->high_priority_req_list, cm, cm_link);
+}
+
+static __inline struct mpr_command *
+mpr_alloc_high_priority_command(struct mpr_softc *sc)
+{
+ struct mpr_command *cm;
+
+ cm = TAILQ_FIRST(&sc->high_priority_req_list);
+ if (cm == NULL)
+ return (NULL);
+
+ TAILQ_REMOVE(&sc->high_priority_req_list, cm, cm_link);
+ KASSERT(cm->cm_state == MPR_CM_STATE_FREE, ("mpr: Allocating busy command\n"));
+ cm->cm_state = MPR_CM_STATE_BUSY;
+ return (cm);
+}
+
+static __inline void
+mpr_lock(struct mpr_softc *sc)
+{
+ mtx_lock(&sc->mpr_mtx);
+}
+
+static __inline void
+mpr_unlock(struct mpr_softc *sc)
+{
+ mtx_unlock(&sc->mpr_mtx);
+}
+
+#define MPR_INFO (1 << 0) /* Basic info */
+#define MPR_FAULT (1 << 1) /* Hardware faults */
+#define MPR_EVENT (1 << 2) /* Event data from the controller */
+#define MPR_LOG (1 << 3) /* Log data from the controller */
+#define MPR_RECOVERY (1 << 4) /* Command error recovery tracing */
+#define MPR_ERROR (1 << 5) /* Parameter errors, programming bugs */
+#define MPR_INIT (1 << 6) /* Things related to system init */
+#define MPR_XINFO (1 << 7) /* More detailed/noisy info */
+#define MPR_USER (1 << 8) /* Trace user-generated commands */
+#define MPR_MAPPING (1 << 9) /* Trace device mappings */
+#define MPR_TRACE (1 << 10) /* Function-by-function trace */
+
+#define mpr_printf(sc, args...) \
+ device_printf((sc)->mpr_dev, ##args)
+
+#define mpr_vprintf(sc, args...) \
+do { \
+ if (bootverbose) \
+ mpr_printf(sc, ##args); \
+} while (0)
+
+#define mpr_dprint(sc, level, msg, args...) \
+do { \
+ if ((sc)->mpr_debug & level) \
+ device_printf((sc)->mpr_dev, msg, ##args); \
+} while (0)
+
+#define mpr_dprint_field(sc, level, msg, args...) \
+do { \
+ if ((sc)->mpr_debug & level) \
+ printf("\t" msg, ##args); \
+} while (0)
+
+#define MPR_PRINTFIELD_START(sc, tag...) \
+ mpr_dprint((sc), MPR_INFO, ##tag); \
+ mpr_dprint_field((sc), MPR_INFO, ":\n")
+#define MPR_PRINTFIELD_END(sc, tag) \
+ mpr_dprint((sc), MPR_INFO, tag "\n")
+#define MPR_PRINTFIELD(sc, facts, attr, fmt) \
+ mpr_dprint_field((sc), MPR_INFO, #attr ": " #fmt "\n", (facts)->attr)
+
+#define MPR_EVENTFIELD_START(sc, tag...) \
+ mpr_dprint((sc), MPR_EVENT, ##tag); \
+ mpr_dprint_field((sc), MPR_EVENT, ":\n")
+#define MPR_EVENTFIELD(sc, facts, attr, fmt) \
+ mpr_dprint_field((sc), MPR_EVENT, #attr ": " #fmt "\n", (facts)->attr)
+
+#define CAN_SLEEP 1
+#define NO_SLEEP 0
+
+static __inline void
+mpr_from_u64(uint64_t data, U64 *mpr)
+{
+ (mpr)->High = htole32((uint32_t)((data) >> 32));
+ (mpr)->Low = htole32((uint32_t)((data) & 0xffffffff));
+}
+
+static __inline uint64_t
+mpr_to_u64(U64 *data)
+{
+
+ return (((uint64_t)le32toh(data->High) << 32) | le32toh(data->Low));
+}
+
+static __inline void
+mpr_mask_intr(struct mpr_softc *sc)
+{
+ uint32_t mask;
+
+ mask = mpr_regread(sc, MPI2_HOST_INTERRUPT_MASK_OFFSET);
+ mask |= MPI2_HIM_REPLY_INT_MASK;
+ mpr_regwrite(sc, MPI2_HOST_INTERRUPT_MASK_OFFSET, mask);
+}
+
+static __inline void
+mpr_unmask_intr(struct mpr_softc *sc)
+{
+ uint32_t mask;
+
+ mask = mpr_regread(sc, MPI2_HOST_INTERRUPT_MASK_OFFSET);
+ mask &= ~MPI2_HIM_REPLY_INT_MASK;
+ mpr_regwrite(sc, MPI2_HOST_INTERRUPT_MASK_OFFSET, mask);
+}
+
+int mpr_pci_setup_interrupts(struct mpr_softc *sc);
+int mpr_pci_restore(struct mpr_softc *sc);
+
+int mpr_attach(struct mpr_softc *sc);
+int mpr_free(struct mpr_softc *sc);
+void mpr_intr(void *);
+void mpr_intr_msi(void *);
+void mpr_intr_locked(void *);
+int mpr_register_events(struct mpr_softc *, uint8_t *, mpr_evt_callback_t *,
+ void *, struct mpr_event_handle **);
+int mpr_restart(struct mpr_softc *);
+int mpr_update_events(struct mpr_softc *, struct mpr_event_handle *,
+ uint8_t *);
+int mpr_deregister_events(struct mpr_softc *, struct mpr_event_handle *);
+int mpr_push_sge(struct mpr_command *, MPI2_SGE_SIMPLE64 *, size_t, int);
+int mpr_push_ieee_sge(struct mpr_command *, void *, int);
+int mpr_add_dmaseg(struct mpr_command *, vm_paddr_t, size_t, u_int, int);
+int mpr_attach_sas(struct mpr_softc *sc);
+int mpr_detach_sas(struct mpr_softc *sc);
+int mpr_read_config_page(struct mpr_softc *, struct mpr_config_params *);
+int mpr_write_config_page(struct mpr_softc *, struct mpr_config_params *);
+void mpr_memaddr_cb(void *, bus_dma_segment_t *, int , int );
+void mpr_init_sge(struct mpr_command *cm, void *req, void *sge);
+int mpr_attach_user(struct mpr_softc *);
+void mpr_detach_user(struct mpr_softc *);
+void mprsas_record_event(struct mpr_softc *sc,
+ MPI2_EVENT_NOTIFICATION_REPLY *event_reply);
+
+int mpr_map_command(struct mpr_softc *sc, struct mpr_command *cm);
+int mpr_wait_command(struct mpr_softc *sc, struct mpr_command *cm,
+ int timeout, int sleep_flag);
+int mpr_request_polled(struct mpr_softc *sc, struct mpr_command *cm);
+
+int mpr_config_get_bios_pg3(struct mpr_softc *sc, Mpi2ConfigReply_t
+ *mpi_reply, Mpi2BiosPage3_t *config_page);
+int mpr_config_get_raid_volume_pg0(struct mpr_softc *sc, Mpi2ConfigReply_t
+ *mpi_reply, Mpi2RaidVolPage0_t *config_page, u32 page_address);
+int mpr_config_get_ioc_pg8(struct mpr_softc *sc, Mpi2ConfigReply_t *,
+ Mpi2IOCPage8_t *);
+int mpr_config_get_iounit_pg8(struct mpr_softc *sc,
+ Mpi2ConfigReply_t *mpi_reply, Mpi2IOUnitPage8_t *config_page);
+int mpr_config_get_sas_device_pg0(struct mpr_softc *, Mpi2ConfigReply_t *,
+ Mpi2SasDevicePage0_t *, u32 , u16 );
+int mpr_config_get_dpm_pg0(struct mpr_softc *, Mpi2ConfigReply_t *,
+ Mpi2DriverMappingPage0_t *, u16 );
+int mpr_config_get_raid_volume_pg1(struct mpr_softc *sc,
+ Mpi2ConfigReply_t *mpi_reply, Mpi2RaidVolPage1_t *config_page, u32 form,
+ u16 handle);
+int mpr_config_get_volume_wwid(struct mpr_softc *sc, u16 volume_handle,
+ u64 *wwid);
+int mpr_config_get_raid_pd_pg0(struct mpr_softc *sc,
+ Mpi2ConfigReply_t *mpi_reply, Mpi2RaidPhysDiskPage0_t *config_page,
+ u32 page_address);
+void mprsas_ir_shutdown(struct mpr_softc *sc);
+
+int mpr_reinit(struct mpr_softc *sc);
+void mprsas_handle_reinit(struct mpr_softc *sc);
+
+void mpr_base_static_config_pages(struct mpr_softc *sc);
+
+int mpr_mapping_initialize(struct mpr_softc *);
+void mpr_mapping_topology_change_event(struct mpr_softc *,
+ Mpi2EventDataSasTopologyChangeList_t *);
+int mpr_mapping_is_reinit_required(struct mpr_softc *);
+void mpr_mapping_free_memory(struct mpr_softc *sc);
+int mpr_config_set_dpm_pg0(struct mpr_softc *, Mpi2ConfigReply_t *,
+ Mpi2DriverMappingPage0_t *, u16 );
+void mpr_mapping_exit(struct mpr_softc *);
+void mpr_mapping_check_devices(struct mpr_softc *, int);
+int mpr_mapping_allocate_memory(struct mpr_softc *sc);
+unsigned int mpr_mapping_get_sas_id(struct mpr_softc *, uint64_t , u16);
+unsigned int mpr_mapping_get_sas_id_from_handle(struct mpr_softc *sc,
+ u16 handle);
+unsigned int mpr_mapping_get_raid_id(struct mpr_softc *sc, u64 wwid,
+ u16 handle);
+unsigned int mpr_mapping_get_raid_id_from_handle(struct mpr_softc *sc,
+ u16 volHandle);
+void mpr_mapping_enclosure_dev_status_change_event(struct mpr_softc *,
+ Mpi2EventDataSasEnclDevStatusChange_t *event_data);
+void mpr_mapping_ir_config_change_event(struct mpr_softc *sc,
+ Mpi2EventDataIrConfigChangeList_t *event_data);
+
+void mprsas_evt_handler(struct mpr_softc *sc, uintptr_t data,
+ MPI2_EVENT_NOTIFICATION_REPLY *event);
+void mprsas_prepare_remove(struct mprsas_softc *sassc, uint16_t handle);
+void mprsas_prepare_volume_remove(struct mprsas_softc *sassc,
+ uint16_t handle);
+int mprsas_startup(struct mpr_softc *sc);
+struct mprsas_target * mprsas_find_target_by_handle(struct mprsas_softc *,
+ int, uint16_t);
+
+SYSCTL_DECL(_hw_mpr);
+
+/* Compatibility shims for different OS versions */
+#if __FreeBSD_version >= 800001
+#define mpr_kproc_create(func, farg, proc_ptr, flags, stackpgs, fmtstr, arg) \
+ kproc_create(func, farg, proc_ptr, flags, stackpgs, fmtstr, arg)
+#define mpr_kproc_exit(arg) kproc_exit(arg)
+#else
+#define mpr_kproc_create(func, farg, proc_ptr, flags, stackpgs, fmtstr, arg) \
+ kthread_create(func, farg, proc_ptr, flags, stackpgs, fmtstr, arg)
+#define mpr_kproc_exit(arg) kthread_exit(arg)
+#endif
+
+#if defined(CAM_PRIORITY_XPT)
+#define MPR_PRIORITY_XPT CAM_PRIORITY_XPT
+#else
+#define MPR_PRIORITY_XPT 5
+#endif
+
+#if __FreeBSD_version < 800107
+// Prior to FreeBSD-8.0 scp3_flags was not defined.
+#define spc3_flags reserved
+
+#define SPC3_SID_PROTECT 0x01
+#define SPC3_SID_3PC 0x08
+#define SPC3_SID_TPGS_MASK 0x30
+#define SPC3_SID_TPGS_IMPLICIT 0x10
+#define SPC3_SID_TPGS_EXPLICIT 0x20
+#define SPC3_SID_ACC 0x40
+#define SPC3_SID_SCCS 0x80
+
+#define CAM_PRIORITY_NORMAL CAM_PRIORITY_NONE
+#endif
+
+#endif
+
diff --git a/sys/i386/conf/GENERIC b/sys/i386/conf/GENERIC
index 61523c48..3b86ea5 100644
--- a/sys/i386/conf/GENERIC
+++ b/sys/i386/conf/GENERIC
@@ -113,6 +113,7 @@ device isp # Qlogic family
#device ispfw # Firmware for QLogic HBAs- normally a module
device mpt # LSI-Logic MPT-Fusion
device mps # LSI-Logic MPT-Fusion 2
+device mpr # LSI-Logic MPT-Fusion 3
#device ncr # NCR/Symbios Logic
device sym # NCR/Symbios Logic (newer chipsets + those of `ncr')
device trm # Tekram DC395U/UW/F DC315U adapters
diff --git a/sys/i386/conf/XEN b/sys/i386/conf/XEN
index 3a43ca0..748f89c 100644
--- a/sys/i386/conf/XEN
+++ b/sys/i386/conf/XEN
@@ -7,7 +7,7 @@ cpu I686_CPU
ident XEN
makeoptions DEBUG=-gdwarf-2 # Build kernel with gdb(1) debug symbols
-makeoptions WITHOUT_MODULES="aha ahb amd ctl cxgb dpt drm drm2 hptnr hptmv ida malo mps mwl nve rdma sound sym trm xfs"
+makeoptions WITHOUT_MODULES="aha ahb amd ctl cxgb dpt drm drm2 hptnr hptmv ida malo mpr mps mwl nve rdma sound sym trm xfs"
options SCHED_ULE # ULE scheduler
options PREEMPTION # Enable kernel thread preemption
diff --git a/sys/ia64/conf/GENERIC b/sys/ia64/conf/GENERIC
index 4efad6a0..f5203cf 100644
--- a/sys/ia64/conf/GENERIC
+++ b/sys/ia64/conf/GENERIC
@@ -86,6 +86,8 @@ device ahd # AHA39320/29320 and AIC79xx devices
device hptiop # Highpoint RocketRaid 3xxx series
device isp # Qlogic family
device mpt # LSI-Logic MPT-Fusion
+device mps # LSI-Logic MPT-Fusion 2
+device mpr # LSI-Logic MPT-Fusion 3
device sym # NCR/Symbios Logic
# RAID controllers interfaced to the SCSI subsystem
diff --git a/sys/mips/conf/OCTEON1 b/sys/mips/conf/OCTEON1
index dfe5208..8f32bbe 100644
--- a/sys/mips/conf/OCTEON1
+++ b/sys/mips/conf/OCTEON1
@@ -129,6 +129,7 @@ device isp # Qlogic family
#device ispfw # Firmware for QLogic HBAs- normally a module
device mpt # LSI-Logic MPT-Fusion
device mps # LSI-Logic MPT-Fusion 2
+device mpr # LSI-Logic MPT-Fusion 3
#device ncr # NCR/Symbios Logic
device trm # Tekram DC395U/UW/F DC315U adapters
diff --git a/sys/modules/Makefile b/sys/modules/Makefile
index 8810a07..bce70b5 100644
--- a/sys/modules/Makefile
+++ b/sys/modules/Makefile
@@ -216,6 +216,7 @@ SUBDIR= \
${_mly} \
mmc \
mmcsd \
+ mpr \
mps \
mpt \
mqueue \
diff --git a/sys/modules/mpr/Makefile b/sys/modules/mpr/Makefile
new file mode 100644
index 0000000..2fb7a391
--- /dev/null
+++ b/sys/modules/mpr/Makefile
@@ -0,0 +1,18 @@
+# $FreeBSD$
+
+.PATH: ${.CURDIR}/../../dev/mpr
+
+KMOD= mpr
+SRCS= mpr_pci.c mpr.c mpr_sas.c mpr_table.c mpr_user.c
+SRCS+= mpr_config.c mpr_mapping.c mpr_sas_lsi.c
+SRCS+= opt_cam.h opt_compat.h
+SRCS+= device_if.h bus_if.h pci_if.h
+
+#CFLAGS += -DMPR_DEBUG
+
+.include <bsd.kmod.mk>
+
+CWARNFLAGS.mpr_sas.c= ${NO_WUNNEEDED_INTERNAL_DECL}
+# XXX Work around clang warning, until maintainer approves fix.
+CWARNFLAGS.mpr_mapping.c= ${NO_WSOMETIMES_UNINITIALIZED}
+CWARNFLAGS+= ${CWARNFLAGS.${.IMPSRC:T}}
diff --git a/sys/sparc64/conf/GENERIC b/sys/sparc64/conf/GENERIC
index c891911..bbf4f01 100644
--- a/sys/sparc64/conf/GENERIC
+++ b/sys/sparc64/conf/GENERIC
@@ -101,6 +101,7 @@ device isp # Qlogic family
device ispfw # Firmware module for Qlogic host adapters
device mpt # LSI-Logic MPT-Fusion
device mps # LSI-Logic MPT-Fusion 2
+device mpr # LSI-Logic MPT-Fusion 3
device sym # NCR/Symbios/LSI Logic 53C8XX/53C1010/53C1510D
# ATA/SCSI peripherals
OpenPOWER on IntegriCloud