Page MenuHomeFreeBSD

D10095.id26542.diff
No OneTemporary

D10095.id26542.diff

Index: sys/dev/mpr/mpi/mpi2.h
===================================================================
--- sys/dev/mpr/mpi/mpi2.h
+++ sys/dev/mpr/mpi/mpi2.h
@@ -44,7 +44,7 @@
* scatter/gather formats.
* Creation Date: June 21, 2006
*
- * mpi2.h Version: 02.00.42
+ * mpi2.h Version: 02.00.46
*
* 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
@@ -132,7 +132,8 @@
* Bumped MPI2_HEADER_VERSION_UNIT.
* 03-16-15 02.00.37 Updated for MPI v2.6.
* Bumped MPI2_HEADER_VERSION_UNIT.
- * Added Scratchpad registers to
+ * Added Scratchpad registers and
+ * AtomicRequestDescriptorPost register to
* MPI2_SYSTEM_INTERFACE_REGS.
* Added MPI2_DIAG_SBR_RELOAD.
* Added MPI2_IOCSTATUS_INSUFFICIENT_POWER.
@@ -142,6 +143,14 @@
* Added V7 HostDiagnostic register defines
* 12-15-15 02.00.41 Bumped MPI_HEADER_VERSION_UNIT
* 01-01-16 02.00.42 Bumped MPI_HEADER_VERSION_UNIT
+ * 04-05-16 02.00.43 Modified MPI26_DIAG_BOOT_DEVICE_SELECT defines
+ * to be unique within first 32 characters.
+ * Removed AHCI support.
+ * Removed SOP support.
+ * Bumped MPI2_HEADER_VERSION_UNIT.
+ * 04-10-16 02.00.44 Bumped MPI2_HEADER_VERSION_UNIT.
+ * 07-06-16 02.00.45 Bumped MPI2_HEADER_VERSION_UNIT.
+ * 09-02-16 02.00.46 Bumped MPI2_HEADER_VERSION_UNIT.
* --------------------------------------------------------------------------
*/
@@ -185,7 +194,7 @@
/* Unit and Dev versioning for this MPI header set */
-#define MPI2_HEADER_VERSION_UNIT (0x2A)
+#define MPI2_HEADER_VERSION_UNIT (0x2E)
#define MPI2_HEADER_VERSION_DEV (0x00)
#define MPI2_HEADER_VERSION_UNIT_MASK (0xFF00)
#define MPI2_HEADER_VERSION_UNIT_SHIFT (8)
@@ -245,7 +254,8 @@
U32 Scratchpad[4]; /* 0xB0 */
U32 RequestDescriptorPostLow; /* 0xC0 */
U32 RequestDescriptorPostHigh; /* 0xC4 */
- U32 Reserved7[14]; /* 0xC8 */
+ U32 AtomicRequestDescriptorPost;/* 0xC8 */ /* MPI v2.6 and later; reserved in earlier versions */
+ U32 Reserved7[13]; /* 0xCC */
} MPI2_SYSTEM_INTERFACE_REGS, MPI2_POINTER PTR_MPI2_SYSTEM_INTERFACE_REGS,
Mpi2SystemInterfaceRegs_t, MPI2_POINTER pMpi2SystemInterfaceRegs_t;
@@ -293,10 +303,11 @@
#define MPI2_DIAG_BOOT_DEVICE_SELECT_HCDW (0x00000800)
/* Defines for V7A/V7R HostDiagnostic Register */
-#define MPI26_DIAG_BOOT_DEVICE_SELECT_FLASH64 (0x00000000)
-#define MPI26_DIAG_BOOT_DEVICE_SELECT_HCDW64 (0x00000800)
-#define MPI26_DIAG_BOOT_DEVICE_SELECT_FLASH32 (0x00001000)
-#define MPI26_DIAG_BOOT_DEVICE_SELECT_HCDW32 (0x00001800)
+#define MPI26_DIAG_BOOT_DEVICE_SEL_64FLASH (0x00000000)
+#define MPI26_DIAG_BOOT_DEVICE_SEL_64HCDW (0x00000800)
+#define MPI26_DIAG_BOOT_DEVICE_SEL_32FLASH (0x00001000)
+#define MPI26_DIAG_BOOT_DEVICE_SEL_32HCDW (0x00001800)
+
#define MPI2_DIAG_CLEAR_FLASH_BAD_SIG (0x00000400)
#define MPI2_DIAG_FORCE_HCB_ON_RESET (0x00000200)
#define MPI2_DIAG_HCB_MODE (0x00000100)
@@ -379,6 +390,7 @@
*/
#define MPI2_REQUEST_DESCRIPTOR_POST_LOW_OFFSET (0x000000C0)
#define MPI2_REQUEST_DESCRIPTOR_POST_HIGH_OFFSET (0x000000C4)
+#define MPI26_ATOMIC_REQUEST_DESCRIPTOR_POST_OFFSET (0x000000C8)
/* Hard Reset delay timings */
@@ -415,6 +427,7 @@
#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 MPI26_REQ_DESCRIPT_FLAGS_PCIE_ENCAPSULATED (0x10)
#define MPI2_REQ_DESCRIPT_FLAGS_IOC_FIFO_MARKER (0x01)
@@ -482,6 +495,14 @@
MPI2_POINTER pMpi25FastPathSCSIIORequestDescriptor_t;
+/* PCIe Encapsulated Request Descriptor */
+typedef MPI2_SCSI_IO_REQUEST_DESCRIPTOR
+ MPI26_PCIE_ENCAPSULATED_REQUEST_DESCRIPTOR,
+ MPI2_POINTER PTR_MPI26_PCIE_ENCAPSULATED_REQUEST_DESCRIPTOR,
+ Mpi26PCIeEncapsulatedRequestDescriptor_t,
+ MPI2_POINTER pMpi26PCIeEncapsulatedRequestDescriptor_t;
+
+
/* union of Request Descriptors */
typedef union _MPI2_REQUEST_DESCRIPTOR_UNION
{
@@ -491,11 +512,35 @@
MPI2_SCSI_TARGET_REQUEST_DESCRIPTOR SCSITarget;
MPI2_RAID_ACCEL_REQUEST_DESCRIPTOR RAIDAccelerator;
MPI25_FP_SCSI_IO_REQUEST_DESCRIPTOR FastPathSCSIIO;
+ MPI26_PCIE_ENCAPSULATED_REQUEST_DESCRIPTOR PCIeEncapsulated;
U64 Words;
} MPI2_REQUEST_DESCRIPTOR_UNION, MPI2_POINTER PTR_MPI2_REQUEST_DESCRIPTOR_UNION,
Mpi2RequestDescriptorUnion_t, MPI2_POINTER pMpi2RequestDescriptorUnion_t;
+/* Atomic Request Descriptors */
+
+/*
+ * All Atomic Request Descriptors have the same format, so the following
+ * structure is used for all Atomic Request Descriptors:
+ * Atomic Default Request Descriptor
+ * Atomic High Priority Request Descriptor
+ * Atomic SCSI IO Request Descriptor
+ * Atomic SCSI Target Request Descriptor
+ * Atomic RAID Accelerator Request Descriptor
+ * Atomic Fast Path SCSI IO Request Descriptor
+ * Atomic PCIe Encapsulated Request Descriptor
+ */
+
+/* Atomic Request Descriptor */
+typedef struct _MPI26_ATOMIC_REQUEST_DESCRIPTOR
+{
+ U8 RequestFlags; /* 0x00 */
+ U8 MSIxIndex; /* 0x01 */
+ U16 SMID; /* 0x02 */
+} MPI26_ATOMIC_REQUEST_DESCRIPTOR,
+ MPI2_POINTER PTR_MPI26_ATOMIC_REQUEST_DESCRIPTOR,
+ Mpi26AtomicRequestDescriptor_t, MPI2_POINTER pMpi26AtomicRequestDescriptor_t;
/* for the RequestFlags field, use the same defines as MPI2_DEFAULT_REQUEST_DESCRIPTOR */
@@ -520,6 +565,7 @@
#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 MPI26_RPY_DESCRIPT_FLAGS_PCIE_ENCAPSULATED_SUCCESS (0x08)
#define MPI2_RPY_DESCRIPT_FLAGS_UNUSED (0x0F)
/* values for marking a reply descriptor as unused */
@@ -607,6 +653,14 @@
MPI2_POINTER pMpi25FastPathSCSIIOSuccessReplyDescriptor_t;
+/* PCIe Encapsulated Success Reply Descriptor */
+typedef MPI2_RAID_ACCELERATOR_SUCCESS_REPLY_DESCRIPTOR
+ MPI26_PCIE_ENCAPSULATED_SUCCESS_REPLY_DESCRIPTOR,
+ MPI2_POINTER PTR_MPI26_PCIE_ENCAPSULATED_SUCCESS_REPLY_DESCRIPTOR,
+ Mpi26PCIeEncapsulatedSuccessReplyDescriptor_t,
+ MPI2_POINTER pMpi26PCIeEncapsulatedSuccessReplyDescriptor_t;
+
+
/* union of Reply Descriptors */
typedef union _MPI2_REPLY_DESCRIPTORS_UNION
{
@@ -617,6 +671,7 @@
MPI2_TARGET_COMMAND_BUFFER_REPLY_DESCRIPTOR TargetCommandBuffer;
MPI2_RAID_ACCELERATOR_SUCCESS_REPLY_DESCRIPTOR RAIDAcceleratorSuccess;
MPI25_FP_SCSI_IO_SUCCESS_REPLY_DESCRIPTOR FastPathSCSIIOSuccess;
+ MPI26_PCIE_ENCAPSULATED_SUCCESS_REPLY_DESCRIPTOR PCIeEncapsulatedSuccess;
U64 Words;
} MPI2_REPLY_DESCRIPTORS_UNION, MPI2_POINTER PTR_MPI2_REPLY_DESCRIPTORS_UNION,
Mpi2ReplyDescriptorsUnion_t, MPI2_POINTER pMpi2ReplyDescriptorsUnion_t;
@@ -659,6 +714,7 @@
#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_NVME_ENCAPSULATED (0x33) /* NVMe Encapsulated (MPI v2.6) */
#define MPI2_FUNCTION_MIN_PRODUCT_SPECIFIC (0xF0) /* beginning of product-specific range */
#define MPI2_FUNCTION_MAX_PRODUCT_SPECIFIC (0xFF) /* end of product-specific range */
@@ -1232,6 +1288,8 @@
#define MPI26_IEEE_SGE_FLAGS_NSF_MASK (0x1C)
#define MPI26_IEEE_SGE_FLAGS_NSF_MPI_IEEE (0x00)
+#define MPI26_IEEE_SGE_FLAGS_NSF_NVME_PRP (0x08)
+#define MPI26_IEEE_SGE_FLAGS_NSF_NVME_SGL (0x10)
/* Data Location Address Space */
Index: sys/dev/mpr/mpi/mpi2_cnfg.h
===================================================================
--- sys/dev/mpr/mpi/mpi2_cnfg.h
+++ sys/dev/mpr/mpi/mpi2_cnfg.h
@@ -42,7 +42,7 @@
* Title: MPI Configuration messages and pages
* Creation Date: November 10, 2006
*
- * mpi2_cnfg.h Version: 02.00.35
+ * mpi2_cnfg.h Version: 02.00.39
*
* 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
@@ -223,9 +223,38 @@
* Flags field to IO Unit Page 7.
* Added IO Unit Page 11.
* Added new SAS Phy Event codes
+ * Added PCIe configuration pages.
+ * 03-19-15 02.00.32 Fixed PCIe Link Config page structure names to be
+ * unique in first 32 characters.
* 05-25-15 02.00.33 Added more defines for the BiosOptions field of
* MPI2_CONFIG_PAGE_BIOS_1.
+ * 08-25-15 02.00.34 Added PCIe Device Page 2 SGL format capability.
* 12-18-15 02.00.35 Added SATADeviceWaitTime to SAS IO Unit Page 4.
+ * 01-21-16 02.00.36 Added/modified MPI2_MFGPAGE_DEVID_SAS defines.
+ * Added Link field to PCIe Link Pages
+ * Added EnclosureLevel and ConnectorName to PCIe
+ * Device Page 0.
+ * Added define for PCIE IoUnit page 1 max rate shift.
+ * Added comment for reserved ExtPageTypes.
+ * Added SAS 4 22.5 gbs speed support.
+ * Added PCIe 4 16.0 GT/sec speec support.
+ * Removed AHCI support.
+ * Removed SOP support.
+ * Added NegotiatedLinkRate and NegotiatedPortWidth to
+ * PCIe device page 0.
+ * 04-10-16 02.00.37 Fixed MPI2_MFGPAGE_DEVID_SAS3616/3708 defines
+ * 07-01-16 02.00.38 Added Manufacturing page 7 Connector types.
+ * Changed declaration of ConnectorName in PCIe DevicePage0
+ * to match SAS DevicePage 0.
+ * Added SATADeviceWaitTime to IO Unit Page 11.
+ * Added MPI26_MFGPAGE_DEVID_SAS4008
+ * Added x16 PCIe width to IO Unit Page 7
+ * Added LINKFLAGS to control SRIS in PCIe IO Unit page 1
+ * phy data.
+ * Added InitStatus to PCIe IO Unit Page 1 header.
+ * 09-01-16 02.00.39 Added MPI26_CONFIG_PAGE_ENCLOSURE_0 and related defines.
+ * Added MPI26_ENCLOS_PGAD_FORM_GET_NEXT_HANDLE and
+ * MPI26_ENCLOS_PGAD_FORM_HANDLE page address formats.
* --------------------------------------------------------------------------
*/
@@ -310,6 +339,12 @@
#define MPI2_CONFIG_EXTPAGETYPE_SAS_PORT (0x18)
#define MPI2_CONFIG_EXTPAGETYPE_ETHERNET (0x19)
#define MPI2_CONFIG_EXTPAGETYPE_EXT_MANUFACTURING (0x1A)
+#define MPI2_CONFIG_EXTPAGETYPE_PCIE_IO_UNIT (0x1B) /* MPI v2.6 and later */
+#define MPI2_CONFIG_EXTPAGETYPE_PCIE_SWITCH (0x1C) /* MPI v2.6 and later */
+#define MPI2_CONFIG_EXTPAGETYPE_PCIE_DEVICE (0x1D) /* MPI v2.6 and later */
+#define MPI2_CONFIG_EXTPAGETYPE_PCIE_LINK (0x1E) /* MPI v2.6 and later */
+/* Product specific reserved values 0xE0 - 0xEF */
+/* Vendor specific reserved values 0xF0 - 0xFF */
/*****************************************************************************
@@ -377,6 +412,12 @@
#define MPI2_SAS_ENCLOS_PGAD_HANDLE_MASK (0x0000FFFF)
+/* Enclosure PageAddress format */
+#define MPI26_ENCLOS_PGAD_FORM_MASK (0xF0000000)
+#define MPI26_ENCLOS_PGAD_FORM_GET_NEXT_HANDLE (0x00000000)
+#define MPI26_ENCLOS_PGAD_FORM_HANDLE (0x10000000)
+
+#define MPI26_ENCLOS_PGAD_HANDLE_MASK (0x0000FFFF)
/* RAID Configuration PageAddress format */
#define MPI2_RAID_PGAD_FORM_MASK (0xF0000000)
@@ -403,6 +444,33 @@
#define MPI2_ETHERNET_PGAD_IF_NUMBER_MASK (0x000000FF)
+/* PCIe Switch PageAddress format */
+#define MPI26_PCIE_SWITCH_PGAD_FORM_MASK (0xF0000000)
+#define MPI26_PCIE_SWITCH_PGAD_FORM_GET_NEXT_HNDL (0x00000000)
+#define MPI26_PCIE_SWITCH_PGAD_FORM_HNDL_PORTNUM (0x10000000)
+#define MPI26_PCIE_SWITCH_EXPAND_PGAD_FORM_HNDL (0x20000000)
+
+#define MPI26_PCIE_SWITCH_PGAD_HANDLE_MASK (0x0000FFFF)
+#define MPI26_PCIE_SWITCH_PGAD_PORTNUM_MASK (0x00FF0000)
+#define MPI26_PCIE_SWITCH_PGAD_PORTNUM_SHIFT (16)
+
+
+/* PCIe Device PageAddress format */
+#define MPI26_PCIE_DEVICE_PGAD_FORM_MASK (0xF0000000)
+#define MPI26_PCIE_DEVICE_PGAD_FORM_GET_NEXT_HANDLE (0x00000000)
+#define MPI26_PCIE_DEVICE_PGAD_FORM_HANDLE (0x20000000)
+
+#define MPI26_PCIE_DEVICE_PGAD_HANDLE_MASK (0x0000FFFF)
+
+/* PCIe Link PageAddress format */
+#define MPI26_PCIE_LINK_PGAD_FORM_MASK (0xF0000000)
+#define MPI26_PCIE_LINK_PGAD_FORM_GET_NEXT_LINK (0x00000000)
+#define MPI26_PCIE_LINK_PGAD_FORM_LINK_NUM (0x10000000)
+
+#define MPI26_PCIE_DEVICE_PGAD_LINKNUM_MASK (0x000000FF)
+
+
+
/****************************************************************************
* Configuration messages
****************************************************************************/
@@ -518,6 +586,20 @@
#define MPI26_MFGPAGE_DEVID_SAS3324_3 (0x00C2)
#define MPI26_MFGPAGE_DEVID_SAS3324_4 (0x00C3)
+#define MPI26_MFGPAGE_DEVID_SAS3516 (0x00AA)
+#define MPI26_MFGPAGE_DEVID_SAS3516_1 (0x00AB)
+#define MPI26_MFGPAGE_DEVID_SAS3416 (0x00AC)
+#define MPI26_MFGPAGE_DEVID_SAS3508 (0x00AD)
+#define MPI26_MFGPAGE_DEVID_SAS3508_1 (0x00AE)
+#define MPI26_MFGPAGE_DEVID_SAS3408 (0x00AF)
+
+#define MPI26_MFGPAGE_DEVID_SAS3716 (0x00D0)
+#define MPI26_MFGPAGE_DEVID_SAS3616 (0x00D1)
+#define MPI26_MFGPAGE_DEVID_SAS3708 (0x00D2)
+
+#define MPI26_MFGPAGE_DEVID_SAS4008 (0x00A1)
+
+
/* Manufacturing Page 0 */
typedef struct _MPI2_CONFIG_PAGE_MAN_0
@@ -755,6 +837,12 @@
#define MPI2_MANPAGE7_PINOUT_SFF_8644_8X (0x0B)
#define MPI2_MANPAGE7_PINOUT_SFF_8644_16X (0x0C)
#define MPI2_MANPAGE7_PINOUT_SFF_8436 (0x0D)
+#define MPI2_MANPAGE7_PINOUT_SFF_8088_A (0x0E)
+#define MPI2_MANPAGE7_PINOUT_SFF_8643_16i (0x0F)
+#define MPI2_MANPAGE7_PINOUT_SFF_8654_4i (0x10)
+#define MPI2_MANPAGE7_PINOUT_SFF_8654_8i (0x11)
+#define MPI2_MANPAGE7_PINOUT_SFF_8611_4i (0x12)
+#define MPI2_MANPAGE7_PINOUT_SFF_8611_8i (0x13)
/* defines for the Location field */
#define MPI2_MANPAGE7_LOCATION_UNKNOWN (0x01)
@@ -1017,11 +1105,13 @@
#define MPI2_IOUNITPAGE7_PCIE_WIDTH_X2 (0x02)
#define MPI2_IOUNITPAGE7_PCIE_WIDTH_X4 (0x04)
#define MPI2_IOUNITPAGE7_PCIE_WIDTH_X8 (0x08)
+#define MPI2_IOUNITPAGE7_PCIE_WIDTH_X16 (0x10)
/* 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)
+#define MPI2_IOUNITPAGE7_PCIE_SPEED_16_0_GBPS (0x03)
/* defines for IO Unit Page 7 ProcessorState field */
#define MPI2_IOUNITPAGE7_PSTATE_MASK_SECOND (0x0000000F)
@@ -1079,6 +1169,7 @@
/* defines for IO Unit Page 7 Flags field */
#define MPI2_IOUNITPAGE7_FLAG_CABLE_POWER_EXC (0x01)
+
/* IO Unit Page 8 */
#define MPI2_IOUNIT8_NUM_THRESHOLDS (4)
@@ -1228,7 +1319,7 @@
U32 Reserved3; /* 0x1C */
U32 Reserved4; /* 0x20 */
U8 BootDeviceWaitTime; /* 0x24 */
- U8 Reserved5; /* 0x25 */
+ U8 SATADeviceWaitTime; /* 0x25 */
U16 Reserved6; /* 0x26 */
U8 NumPhys; /* 0x28 */
U8 PEInitialSpinupDelay; /* 0x29 */
@@ -1249,9 +1340,6 @@
-
-
-
/****************************************************************************
* IOC Config Pages
****************************************************************************/
@@ -1968,6 +2056,7 @@
#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)
+#define MPI26_SAS_NEG_LINK_RATE_22_5 (0x0C)
/* values for AttachedPhyInfo fields */
@@ -2035,12 +2124,14 @@
#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 MPI26_SAS_PRATE_MAX_RATE_22_5 (0xC0)
#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)
+#define MPI26_SAS_PRATE_MIN_RATE_22_5 (0x0C)
/* values for SAS HwLinkRate fields */
@@ -2049,11 +2140,13 @@
#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 MPI26_SAS_HWRATE_MAX_RATE_22_5 (0xC0)
#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)
+#define MPI26_SAS_HWRATE_MIN_RATE_22_5 (0x0C)
@@ -2227,11 +2320,13 @@
#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 MPI26_SASIOUNIT1_MAX_RATE_22_5 (0xC0)
#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)
+#define MPI26_SASIOUNIT1_MIN_RATE_22_5 (0x0C)
/* see mpi2_sas.h for values for SAS IO Unit Page 1 ControllerPhyDeviceInfo values */
@@ -2718,7 +2813,6 @@
#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
@@ -2885,7 +2979,6 @@
#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)
-
/* Following codes are product specific and in MPI v2.6 and later */
#define MPI2_SASPHY3_EVENT_CODE_LCARB_WAIT_TIME (0xD3)
#define MPI2_SASPHY3_EVENT_CODE_RCVD_CONN_RESP_WAIT_TIME (0xD4)
@@ -2898,7 +2991,6 @@
#define MPI2_SASPHY3_EVENT_CODE_SATA_RX_START_RECEIVE (0xDB)
#define MPI2_SASPHY3_EVENT_CODE_SMP_RX_START_RECEIVE (0xDC)
-
/* values for the CounterType field */
#define MPI2_SASPHY3_COUNTER_TYPE_WRAPPING (0x00)
#define MPI2_SASPHY3_COUNTER_TYPE_SATURATING (0x01)
@@ -2989,7 +3081,7 @@
* SAS Enclosure Config Pages
****************************************************************************/
-/* SAS Enclosure Page 0 */
+/* SAS Enclosure Page 0, Enclosure Page 0 */
typedef struct _MPI2_CONFIG_PAGE_SAS_ENCLOSURE_0
{
@@ -3007,7 +3099,10 @@
U32 Reserved4; /* 0x24 */
} MPI2_CONFIG_PAGE_SAS_ENCLOSURE_0,
MPI2_POINTER PTR_MPI2_CONFIG_PAGE_SAS_ENCLOSURE_0,
- Mpi2SasEnclosurePage0_t, MPI2_POINTER pMpi2SasEnclosurePage0_t;
+ Mpi2SasEnclosurePage0_t, MPI2_POINTER pMpi2SasEnclosurePage0_t,
+ MPI26_CONFIG_PAGE_ENCLOSURE_0,
+ MPI2_POINTER PTR_MPI26_CONFIG_PAGE_ENCLOSURE_0,
+ Mpi26EnclosurePage0_t, MPI2_POINTER pMpi26EnclosurePage0_t;
#define MPI2_SASENCLOSURE0_PAGEVERSION (0x04)
@@ -3021,6 +3116,17 @@
#define MPI2_SAS_ENCLS0_FLAGS_MNG_SES_ENCLOSURE (0x0004)
#define MPI2_SAS_ENCLS0_FLAGS_MNG_IOC_GPIO (0x0005)
+#define MPI26_ENCLOSURE0_PAGEVERSION (0x04)
+
+/* Values for Enclosure Page 0 Flags field */
+#define MPI26_ENCLS0_FLAGS_ENCL_LEVEL_VALID (0x0010)
+#define MPI26_ENCLS0_FLAGS_MNG_MASK (0x000F)
+#define MPI26_ENCLS0_FLAGS_MNG_UNKNOWN (0x0000)
+#define MPI26_ENCLS0_FLAGS_MNG_IOC_SES (0x0001)
+#define MPI26_ENCLS0_FLAGS_MNG_IOC_SGPIO (0x0002)
+#define MPI26_ENCLS0_FLAGS_MNG_EXP_SGPIO (0x0003)
+#define MPI26_ENCLS0_FLAGS_MNG_SES_ENCLOSURE (0x0004)
+#define MPI26_ENCLS0_FLAGS_MNG_IOC_GPIO (0x0005)
/****************************************************************************
* Log Config Page
@@ -3300,5 +3406,424 @@
/* PageVersion should be provided by product-specific code */
+
+/****************************************************************************
+* values for fields used by several types of PCIe Config Pages
+****************************************************************************/
+
+/* values for NegotiatedLinkRates fields */
+#define MPI26_PCIE_NEG_LINK_RATE_MASK_PHYSICAL (0x0F)
+/* link rates used for Negotiated Physical Link Rate */
+#define MPI26_PCIE_NEG_LINK_RATE_UNKNOWN (0x00)
+#define MPI26_PCIE_NEG_LINK_RATE_PHY_DISABLED (0x01)
+#define MPI26_PCIE_NEG_LINK_RATE_2_5 (0x02)
+#define MPI26_PCIE_NEG_LINK_RATE_5_0 (0x03)
+#define MPI26_PCIE_NEG_LINK_RATE_8_0 (0x04)
+#define MPI26_PCIE_NEG_LINK_RATE_16_0 (0x05)
+
+
+/****************************************************************************
+* PCIe IO Unit Config Pages (MPI v2.6 and later)
+****************************************************************************/
+
+/* PCIe IO Unit Page 0 */
+
+typedef struct _MPI26_PCIE_IO_UNIT0_PHY_DATA
+{
+ U8 Link; /* 0x00 */
+ U8 LinkFlags; /* 0x01 */
+ U8 PhyFlags; /* 0x02 */
+ U8 NegotiatedLinkRate; /* 0x03 */
+ U32 ControllerPhyDeviceInfo;/* 0x04 */
+ U16 AttachedDevHandle; /* 0x08 */
+ U16 ControllerDevHandle; /* 0x0A */
+ U32 EnumerationStatus; /* 0x0C */
+ U32 Reserved1; /* 0x10 */
+} MPI26_PCIE_IO_UNIT0_PHY_DATA, MPI2_POINTER PTR_MPI26_PCIE_IO_UNIT0_PHY_DATA,
+ Mpi26PCIeIOUnit0PhyData_t, MPI2_POINTER pMpi26PCIeIOUnit0PhyData_t;
+
+/*
+ * Host code (drivers, BIOS, utilities, etc.) should leave this define set to
+ * one and check the value returned for NumPhys at runtime.
+ */
+#ifndef MPI26_PCIE_IOUNIT0_PHY_MAX
+#define MPI26_PCIE_IOUNIT0_PHY_MAX (1)
+#endif
+
+typedef struct _MPI26_CONFIG_PAGE_PIOUNIT_0
+{
+ MPI2_CONFIG_EXTENDED_PAGE_HEADER Header; /* 0x00 */
+ U32 Reserved1; /* 0x08 */
+ U8 NumPhys; /* 0x0C */
+ U8 InitStatus; /* 0x0D */
+ U16 Reserved3; /* 0x0E */
+ MPI26_PCIE_IO_UNIT0_PHY_DATA PhyData[MPI26_PCIE_IOUNIT0_PHY_MAX]; /* 0x10 */
+} MPI26_CONFIG_PAGE_PIOUNIT_0,
+ MPI2_POINTER PTR_MPI26_CONFIG_PAGE_PIOUNIT_0,
+ Mpi26PCIeIOUnitPage0_t, MPI2_POINTER pMpi26PCIeIOUnitPage0_t;
+
+#define MPI26_PCIEIOUNITPAGE0_PAGEVERSION (0x00)
+
+/* values for PCIe IO Unit Page 0 LinkFlags */
+#define MPI26_PCIEIOUNIT0_LINKFLAGS_ENUMERATION_IN_PROGRESS (0x08)
+
+/* values for PCIe IO Unit Page 0 PhyFlags */
+#define MPI26_PCIEIOUNIT0_PHYFLAGS_PHY_DISABLED (0x08)
+
+/* use MPI26_PCIE_NEG_LINK_RATE_ defines for the NegotiatedLinkRate field */
+
+/* see mpi2_pci.h for values for PCIe IO Unit Page 0 ControllerPhyDeviceInfo values */
+
+/* values for PCIe IO Unit Page 0 EnumerationStatus */
+#define MPI26_PCIEIOUNIT0_ES_MAX_SWITCHES_EXCEEDED (0x40000000)
+#define MPI26_PCIEIOUNIT0_ES_MAX_DEVICES_EXCEEDED (0x20000000)
+
+
+/* PCIe IO Unit Page 1 */
+
+typedef struct _MPI26_PCIE_IO_UNIT1_PHY_DATA
+{
+ U8 Link; /* 0x00 */
+ U8 LinkFlags; /* 0x01 */
+ U8 PhyFlags; /* 0x02 */
+ U8 MaxMinLinkRate; /* 0x03 */
+ U32 ControllerPhyDeviceInfo; /* 0x04 */
+ U32 Reserved1; /* 0x08 */
+} MPI26_PCIE_IO_UNIT1_PHY_DATA, MPI2_POINTER PTR_MPI26_PCIE_IO_UNIT1_PHY_DATA,
+ Mpi26PCIeIOUnit1PhyData_t, MPI2_POINTER pMpi26PCIeIOUnit1PhyData_t;
+
+/* values for LinkFlags */
+#define MPI26_PCIEIOUNIT1_LINKFLAGS_DIS_SRIS (0x00)
+#define MPI26_PCIEIOUNIT1_LINKFLAGS_EN_SRIS (0x01)
+
+/*
+ * Host code (drivers, BIOS, utilities, etc.) should leave this define set to
+ * one and check the value returned for NumPhys at runtime.
+ */
+#ifndef MPI26_PCIE_IOUNIT1_PHY_MAX
+#define MPI26_PCIE_IOUNIT1_PHY_MAX (1)
+#endif
+
+typedef struct _MPI26_CONFIG_PAGE_PIOUNIT_1
+{
+ MPI2_CONFIG_EXTENDED_PAGE_HEADER Header; /* 0x00 */
+ U16 ControlFlags; /* 0x08 */
+ U16 Reserved; /* 0x0A */
+ U16 AdditionalControlFlags; /* 0x0C */
+ U16 NVMeMaxQueueDepth; /* 0x0E */
+ U8 NumPhys; /* 0x10 */
+ U8 Reserved1; /* 0x11 */
+ U16 Reserved2; /* 0x12 */
+ MPI26_PCIE_IO_UNIT1_PHY_DATA PhyData[MPI26_PCIE_IOUNIT1_PHY_MAX];/* 0x14 */
+} MPI26_CONFIG_PAGE_PIOUNIT_1,
+ MPI2_POINTER PTR_MPI26_CONFIG_PAGE_PIOUNIT_1,
+ Mpi26PCIeIOUnitPage1_t, MPI2_POINTER pMpi26PCIeIOUnitPage1_t;
+
+#define MPI26_PCIEIOUNITPAGE1_PAGEVERSION (0x00)
+
+/* values for PCIe IO Unit Page 1 PhyFlags */
+#define MPI26_PCIEIOUNIT1_PHYFLAGS_PHY_DISABLE (0x08)
+#define MPI26_PCIEIOUNIT1_PHYFLAGS_ENDPOINT_ONLY (0x01)
+
+/* values for PCIe IO Unit Page 1 MaxMinLinkRate */
+#define MPI26_PCIEIOUNIT1_MAX_RATE_MASK (0xF0)
+#define MPI26_PCIEIOUNIT1_MAX_RATE_SHIFT (4)
+#define MPI26_PCIEIOUNIT1_MAX_RATE_2_5 (0x20)
+#define MPI26_PCIEIOUNIT1_MAX_RATE_5_0 (0x30)
+#define MPI26_PCIEIOUNIT1_MAX_RATE_8_0 (0x40)
+#define MPI26_PCIEIOUNIT1_MAX_RATE_16_0 (0x50)
+
+/* see mpi2_pci.h for values for PCIe IO Unit Page 0 ControllerPhyDeviceInfo values */
+
+
+/****************************************************************************
+* PCIe Switch Config Pages (MPI v2.6 and later)
+****************************************************************************/
+
+/* PCIe Switch Page 0 */
+
+typedef struct _MPI26_CONFIG_PAGE_PSWITCH_0
+{
+ MPI2_CONFIG_EXTENDED_PAGE_HEADER Header; /* 0x00 */
+ U8 PhysicalPort; /* 0x08 */
+ U8 Reserved1; /* 0x09 */
+ U16 Reserved2; /* 0x0A */
+ U16 DevHandle; /* 0x0C */
+ U16 ParentDevHandle; /* 0x0E */
+ U8 NumPorts; /* 0x10 */
+ U8 PCIeLevel; /* 0x11 */
+ U16 Reserved3; /* 0x12 */
+ U32 Reserved4; /* 0x14 */
+ U32 Reserved5; /* 0x18 */
+ U32 Reserved6; /* 0x1C */
+} MPI26_CONFIG_PAGE_PSWITCH_0, MPI2_POINTER PTR_MPI26_CONFIG_PAGE_PSWITCH_0,
+ Mpi26PCIeSwitchPage0_t, MPI2_POINTER pMpi26PCIeSwitchPage0_t;
+
+#define MPI26_PCIESWITCH0_PAGEVERSION (0x00)
+
+
+/* PCIe Switch Page 1 */
+
+typedef struct _MPI26_CONFIG_PAGE_PSWITCH_1
+{
+ MPI2_CONFIG_EXTENDED_PAGE_HEADER Header; /* 0x00 */
+ U8 PhysicalPort; /* 0x08 */
+ U8 Reserved1; /* 0x09 */
+ U16 Reserved2; /* 0x0A */
+ U8 NumPorts; /* 0x0C */
+ U8 PortNum; /* 0x0D */
+ U16 AttachedDevHandle; /* 0x0E */
+ U16 SwitchDevHandle; /* 0x10 */
+ U8 NegotiatedPortWidth; /* 0x12 */
+ U8 NegotiatedLinkRate; /* 0x13 */
+ U32 Reserved4; /* 0x14 */
+ U32 Reserved5; /* 0x18 */
+} MPI26_CONFIG_PAGE_PSWITCH_1, MPI2_POINTER PTR_MPI26_CONFIG_PAGE_PSWITCH_1,
+ Mpi26PCIeSwitchPage1_t, MPI2_POINTER pMpi26PCIeSwitchPage1_t;
+
+#define MPI26_PCIESWITCH1_PAGEVERSION (0x00)
+
+/* use MPI26_PCIE_NEG_LINK_RATE_ defines for the NegotiatedLinkRate field */
+
+
+/****************************************************************************
+* PCIe Device Config Pages (MPI v2.6 and later)
+****************************************************************************/
+
+/* PCIe Device Page 0 */
+
+typedef struct _MPI26_CONFIG_PAGE_PCIEDEV_0
+{
+ MPI2_CONFIG_EXTENDED_PAGE_HEADER Header; /* 0x00 */
+ U16 Slot; /* 0x08 */
+ U16 EnclosureHandle; /* 0x0A */
+ U64 WWID; /* 0x0C */
+ U16 ParentDevHandle; /* 0x14 */
+ U8 PortNum; /* 0x16 */
+ U8 AccessStatus; /* 0x17 */
+ U16 DevHandle; /* 0x18 */
+ U8 PhysicalPort; /* 0x1A */
+ U8 Reserved1; /* 0x1B */
+ U32 DeviceInfo; /* 0x1C */
+ U32 Flags; /* 0x20 */
+ U8 SupportedLinkRates; /* 0x24 */
+ U8 MaxPortWidth; /* 0x25 */
+ U8 NegotiatedPortWidth; /* 0x26 */
+ U8 NegotiatedLinkRate; /* 0x27 */
+ U8 EnclosureLevel; /* 0x28 */
+ U8 Reserved2; /* 0x29 */
+ U16 Reserved3; /* 0x2A */
+ U8 ConnectorName[4]; /* 0x2C */
+ U32 Reserved4; /* 0x30 */
+ U32 Reserved5; /* 0x34 */
+} MPI26_CONFIG_PAGE_PCIEDEV_0, MPI2_POINTER PTR_MPI26_CONFIG_PAGE_PCIEDEV_0,
+ Mpi26PCIeDevicePage0_t, MPI2_POINTER pMpi26PCIeDevicePage0_t;
+
+#define MPI26_PCIEDEVICE0_PAGEVERSION (0x01)
+
+/* values for PCIe Device Page 0 AccessStatus field */
+#define MPI26_PCIEDEV0_ASTATUS_NO_ERRORS (0x00)
+#define MPI26_PCIEDEV0_ASTATUS_NEEDS_INITIALIZATION (0x04)
+#define MPI26_PCIEDEV0_ASTATUS_CAPABILITY_FAILED (0x02)
+#define MPI26_PCIEDEV0_ASTATUS_DEVICE_BLOCKED (0x07)
+#define MPI26_PCIEDEV0_ASTATUS_MEMORY_SPACE_ACCESS_FAILED (0x08)
+#define MPI26_PCIEDEV0_ASTATUS_UNSUPPORTED_DEVICE (0x09)
+#define MPI26_PCIEDEV0_ASTATUS_MSIX_REQUIRED (0x0A)
+#define MPI26_PCIEDEV0_ASTATUS_UNKNOWN (0x10)
+
+#define MPI26_PCIEDEV0_ASTATUS_NVME_READY_TIMEOUT (0x30)
+#define MPI26_PCIEDEV0_ASTATUS_NVME_DEVCFG_UNSUPPORTED (0x31)
+#define MPI26_PCIEDEV0_ASTATUS_NVME_IDENTIFY_FAILED (0x32)
+#define MPI26_PCIEDEV0_ASTATUS_NVME_QCONFIG_FAILED (0x33)
+#define MPI26_PCIEDEV0_ASTATUS_NVME_QCREATION_FAILED (0x34)
+#define MPI26_PCIEDEV0_ASTATUS_NVME_EVENTCFG_FAILED (0x35)
+#define MPI26_PCIEDEV0_ASTATUS_NVME_GET_FEATURE_STAT_FAILED (0x36)
+#define MPI26_PCIEDEV0_ASTATUS_NVME_IDLE_TIMEOUT (0x37)
+#define MPI26_PCIEDEV0_ASTATUS_NVME_FAILURE_STATUS (0x38)
+
+#define MPI26_PCIEDEV0_ASTATUS_INIT_FAIL_MAX (0x3F)
+
+/* see mpi2_pci.h for the MPI26_PCIE_DEVINFO_ defines used for the DeviceInfo field */
+
+/* values for PCIe Device Page 0 Flags field */
+#define MPI26_PCIEDEV0_FLAGS_UNAUTHORIZED_DEVICE (0x8000)
+#define MPI26_PCIEDEV0_FLAGS_ENABLED_FAST_PATH (0x4000)
+#define MPI26_PCIEDEV0_FLAGS_FAST_PATH_CAPABLE (0x2000)
+#define MPI26_PCIEDEV0_FLAGS_ASYNCHRONOUS_NOTIFICATION (0x0400)
+#define MPI26_PCIEDEV0_FLAGS_ATA_SW_PRESERVATION (0x0200)
+#define MPI26_PCIEDEV0_FLAGS_UNSUPPORTED_DEVICE (0x0100)
+#define MPI26_PCIEDEV0_FLAGS_ATA_48BIT_LBA_SUPPORTED (0x0080)
+#define MPI26_PCIEDEV0_FLAGS_ATA_SMART_SUPPORTED (0x0040)
+#define MPI26_PCIEDEV0_FLAGS_ATA_NCQ_SUPPORTED (0x0020)
+#define MPI26_PCIEDEV0_FLAGS_ATA_FUA_SUPPORTED (0x0010)
+#define MPI26_PCIEDEV0_FLAGS_ENCL_LEVEL_VALID (0x0002)
+#define MPI26_PCIEDEV0_FLAGS_DEVICE_PRESENT (0x0001)
+
+/* values for PCIe Device Page 0 SupportedLinkRates field */
+#define MPI26_PCIEDEV0_LINK_RATE_16_0_SUPPORTED (0x08)
+#define MPI26_PCIEDEV0_LINK_RATE_8_0_SUPPORTED (0x04)
+#define MPI26_PCIEDEV0_LINK_RATE_5_0_SUPPORTED (0x02)
+#define MPI26_PCIEDEV0_LINK_RATE_2_5_SUPPORTED (0x01)
+
+/* use MPI26_PCIE_NEG_LINK_RATE_ defines for the NegotiatedLinkRate field */
+
+
+/* PCIe Device Page 2 */
+
+typedef struct _MPI26_CONFIG_PAGE_PCIEDEV_2
+{
+ MPI2_CONFIG_EXTENDED_PAGE_HEADER Header; /* 0x00 */
+ U16 DevHandle; /* 0x08 */
+ U16 Reserved1; /* 0x0A */
+ U32 MaximumDataTransferSize;/* 0x0C */
+ U32 Capabilities; /* 0x10 */
+ U32 Reserved2; /* 0x14 */
+} MPI26_CONFIG_PAGE_PCIEDEV_2, MPI2_POINTER PTR_MPI26_CONFIG_PAGE_PCIEDEV_2,
+ Mpi26PCIeDevicePage2_t, MPI2_POINTER pMpi26PCIeDevicePage2_t;
+
+#define MPI26_PCIEDEVICE2_PAGEVERSION (0x00)
+
+/* defines for PCIe Device Page 2 Capabilities field */
+#define MPI26_PCIEDEV2_CAP_SGL_FORMAT (0x00000004)
+#define MPI26_PCIEDEV2_CAP_BIT_BUCKET_SUPPORT (0x00000002)
+#define MPI26_PCIEDEV2_CAP_SGL_SUPPORT (0x00000001)
+
+
+/****************************************************************************
+* PCIe Link Config Pages (MPI v2.6 and later)
+****************************************************************************/
+
+/* PCIe Link Page 1 */
+
+typedef struct _MPI26_CONFIG_PAGE_PCIELINK_1
+{
+ MPI2_CONFIG_EXTENDED_PAGE_HEADER Header; /* 0x00 */
+ U8 Link; /* 0x08 */
+ U8 Reserved1; /* 0x09 */
+ U16 Reserved2; /* 0x0A */
+ U32 CorrectableErrorCount; /* 0x0C */
+ U16 NonFatalErrorCount; /* 0x10 */
+ U16 Reserved3; /* 0x12 */
+ U16 FatalErrorCount; /* 0x14 */
+ U16 Reserved4; /* 0x16 */
+} MPI26_CONFIG_PAGE_PCIELINK_1, MPI2_POINTER PTR_MPI26_CONFIG_PAGE_PCIELINK_1,
+ Mpi26PcieLinkPage1_t, MPI2_POINTER pMpi26PcieLinkPage1_t;
+
+#define MPI26_PCIELINK1_PAGEVERSION (0x00)
+
+/* PCIe Link Page 2 */
+
+typedef struct _MPI26_PCIELINK2_LINK_EVENT
+{
+ U8 LinkEventCode; /* 0x00 */
+ U8 Reserved1; /* 0x01 */
+ U16 Reserved2; /* 0x02 */
+ U32 LinkEventInfo; /* 0x04 */
+} MPI26_PCIELINK2_LINK_EVENT, MPI2_POINTER PTR_MPI26_PCIELINK2_LINK_EVENT,
+ Mpi26PcieLink2LinkEvent_t, MPI2_POINTER pMpi26PcieLink2LinkEvent_t;
+
+/* use MPI26_PCIELINK3_EVTCODE_ for the LinkEventCode field */
+
+
+/*
+ * Host code (drivers, BIOS, utilities, etc.) should leave this define set to
+ * one and check the value returned for NumLinkEvents at runtime.
+ */
+#ifndef MPI26_PCIELINK2_LINK_EVENT_MAX
+#define MPI26_PCIELINK2_LINK_EVENT_MAX (1)
+#endif
+
+typedef struct _MPI26_CONFIG_PAGE_PCIELINK_2
+{
+ MPI2_CONFIG_EXTENDED_PAGE_HEADER Header; /* 0x00 */
+ U8 Link; /* 0x08 */
+ U8 Reserved1; /* 0x09 */
+ U16 Reserved2; /* 0x0A */
+ U8 NumLinkEvents; /* 0x0C */
+ U8 Reserved3; /* 0x0D */
+ U16 Reserved4; /* 0x0E */
+ MPI26_PCIELINK2_LINK_EVENT LinkEvent[MPI26_PCIELINK2_LINK_EVENT_MAX]; /* 0x10 */
+} MPI26_CONFIG_PAGE_PCIELINK_2, MPI2_POINTER PTR_MPI26_CONFIG_PAGE_PCIELINK_2,
+ Mpi26PcieLinkPage2_t, MPI2_POINTER pMpi26PcieLinkPage2_t;
+
+#define MPI26_PCIELINK2_PAGEVERSION (0x00)
+
+
+/* PCIe Link Page 3 */
+
+typedef struct _MPI26_PCIELINK3_LINK_EVENT_CONFIG
+{
+ U8 LinkEventCode; /* 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 */
+} MPI26_PCIELINK3_LINK_EVENT_CONFIG, MPI2_POINTER PTR_MPI26_PCIELINK3_LINK_EVENT_CONFIG,
+ Mpi26PcieLink3LinkEventConfig_t, MPI2_POINTER pMpi26PcieLink3LinkEventConfig_t;
+
+/* values for LinkEventCode field */
+#define MPI26_PCIELINK3_EVTCODE_NO_EVENT (0x00)
+#define MPI26_PCIELINK3_EVTCODE_CORRECTABLE_ERROR_RECEIVED (0x01)
+#define MPI26_PCIELINK3_EVTCODE_NON_FATAL_ERROR_RECEIVED (0x02)
+#define MPI26_PCIELINK3_EVTCODE_FATAL_ERROR_RECEIVED (0x03)
+#define MPI26_PCIELINK3_EVTCODE_DATA_LINK_ERROR_DETECTED (0x04)
+#define MPI26_PCIELINK3_EVTCODE_TRANSACTION_LAYER_ERROR_DETECTED (0x05)
+#define MPI26_PCIELINK3_EVTCODE_TLP_ECRC_ERROR_DETECTED (0x06)
+#define MPI26_PCIELINK3_EVTCODE_POISONED_TLP (0x07)
+#define MPI26_PCIELINK3_EVTCODE_RECEIVED_NAK_DLLP (0x08)
+#define MPI26_PCIELINK3_EVTCODE_SENT_NAK_DLLP (0x09)
+#define MPI26_PCIELINK3_EVTCODE_LTSSM_RECOVERY_STATE (0x0A)
+#define MPI26_PCIELINK3_EVTCODE_LTSSM_RXL0S_STATE (0x0B)
+#define MPI26_PCIELINK3_EVTCODE_LTSSM_TXL0S_STATE (0x0C)
+#define MPI26_PCIELINK3_EVTCODE_LTSSM_L1_STATE (0x0D)
+#define MPI26_PCIELINK3_EVTCODE_LTSSM_DISABLED_STATE (0x0E)
+#define MPI26_PCIELINK3_EVTCODE_LTSSM_HOT_RESET_STATE (0x0F)
+#define MPI26_PCIELINK3_EVTCODE_SYSTEM_ERROR (0x10)
+#define MPI26_PCIELINK3_EVTCODE_DECODE_ERROR (0x11)
+#define MPI26_PCIELINK3_EVTCODE_DISPARITY_ERROR (0x12)
+
+/* values for the CounterType field */
+#define MPI26_PCIELINK3_COUNTER_TYPE_WRAPPING (0x00)
+#define MPI26_PCIELINK3_COUNTER_TYPE_SATURATING (0x01)
+#define MPI26_PCIELINK3_COUNTER_TYPE_PEAK_VALUE (0x02)
+
+/* values for the TimeUnits field */
+#define MPI26_PCIELINK3_TM_UNITS_10_MICROSECONDS (0x00)
+#define MPI26_PCIELINK3_TM_UNITS_100_MICROSECONDS (0x01)
+#define MPI26_PCIELINK3_TM_UNITS_1_MILLISECOND (0x02)
+#define MPI26_PCIELINK3_TM_UNITS_10_MILLISECONDS (0x03)
+
+/* values for the ThresholdFlags field */
+#define MPI26_PCIELINK3_TFLAGS_EVENT_NOTIFY (0x0001)
+
+/*
+ * Host code (drivers, BIOS, utilities, etc.) should leave this define set to
+ * one and check the value returned for NumLinkEvents at runtime.
+ */
+#ifndef MPI26_PCIELINK3_LINK_EVENT_MAX
+#define MPI26_PCIELINK3_LINK_EVENT_MAX (1)
+#endif
+
+typedef struct _MPI26_CONFIG_PAGE_PCIELINK_3
+{
+ MPI2_CONFIG_EXTENDED_PAGE_HEADER Header; /* 0x00 */
+ U8 Link; /* 0x08 */
+ U8 Reserved1; /* 0x09 */
+ U16 Reserved2; /* 0x0A */
+ U8 NumLinkEvents; /* 0x0C */
+ U8 Reserved3; /* 0x0D */
+ U16 Reserved4; /* 0x0E */
+ MPI26_PCIELINK3_LINK_EVENT_CONFIG LinkEventConfig[MPI26_PCIELINK3_LINK_EVENT_MAX]; /* 0x10 */
+} MPI26_CONFIG_PAGE_PCIELINK_3, MPI2_POINTER PTR_MPI26_CONFIG_PAGE_PCIELINK_3,
+ Mpi26PcieLinkPage3_t, MPI2_POINTER pMpi26PcieLinkPage3_t;
+
+#define MPI26_PCIELINK3_PAGEVERSION (0x00)
+
+
#endif
Index: sys/dev/mpr/mpi/mpi2_hbd.h
===================================================================
--- sys/dev/mpr/mpi/mpi2_hbd.h
+++ sys/dev/mpr/mpi/mpi2_hbd.h
@@ -42,7 +42,7 @@
* Title: MPI Host Based Discovery messages and structures
* Creation Date: October 21, 2009
*
- * mpi2_hbd.h Version: 02.00.03
+ * mpi2_hbd.h Version: 02.00.04
*
* 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
@@ -59,6 +59,7 @@
* HBD Action request, replaced by AdditionalInfo field.
* 11-18-11 02.00.02 Incorporating additions for MPI v2.5.
* 11-18-14 02.00.03 Updated copyright information.
+ * 02-17-16 02.00.04 Added SAS 4 22.5 gbs speed support.
* --------------------------------------------------------------------------
*/
@@ -129,6 +130,7 @@
#define MPI2_HBD_MAX_RATE_3_0 (0x09)
#define MPI2_HBD_MAX_RATE_6_0 (0x0A)
#define MPI25_HBD_MAX_RATE_12_0 (0x0B)
+#define MPI26_HBD_MAX_RATE_22_5 (0x0C)
/* Host Based Discovery Action Reply Message */
Index: sys/dev/mpr/mpi/mpi2_history.txt
===================================================================
--- sys/dev/mpr/mpi/mpi2_history.txt
+++ sys/dev/mpr/mpi/mpi2_history.txt
@@ -41,24 +41,25 @@
All rights reserved.
---------------------------------------
- Header Set Release Version: 02.00.42
- Header Set Release Date: 01-04-16
+ Header Set Release Version: 02.00.46
+ Header Set Release Date: 09-07-16
---------------------------------------
Filename Current version Prior version
---------- --------------- -------------
- mpi2.h 02.00.42 02.00.41
- mpi2_cnfg.h 02.00.35 02.00.34
- mpi2_init.h 02.00.20 02.00.19
- mpi2_ioc.h 02.00.27 02.00.27
+ mpi2.h 02.00.46 02.00.45
+ mpi2_cnfg.h 02.00.39 02.00.38
+ mpi2_init.h 02.00.21 02.00.21
+ mpi2_ioc.h 02.00.30 02.00.29
mpi2_raid.h 02.00.11 02.00.11
mpi2_sas.h 02.00.10 02.00.10
mpi2_targ.h 02.00.09 02.00.09
- mpi2_tool.h 02.00.13 02.00.13
+ mpi2_tool.h 02.00.14 02.00.13
mpi2_type.h 02.00.01 02.00.01
mpi2_ra.h 02.00.01 02.00.01
- mpi2_hbd.h 02.00.03 02.00.03
- mpi2_history.txt 02.00.41 02.00.40
+ mpi2_hbd.h 02.00.04 02.00.04
+ mpi2_pci.h 02.00.02 02.00.02
+ mpi2_history.txt 02.00.43 02.00.43
* Date Version Description
@@ -141,7 +142,8 @@
* Bumped MPI2_HEADER_VERSION_UNIT.
* 03-16-15 02.00.37 Updated for MPI v2.6.
* Bumped MPI2_HEADER_VERSION_UNIT.
- * Added Scratchpad registers to
+ * Added Scratchpad registers and
+ * AtomicRequestDescriptorPost register to
* MPI2_SYSTEM_INTERFACE_REGS.
* Added MPI2_DIAG_SBR_RELOAD.
* Added MPI2_IOCSTATUS_INSUFFICIENT_POWER.
@@ -151,6 +153,14 @@
* Added V7 HostDiagnostic register defines
* 12-15-15 02.00.41 Bumped MPI_HEADER_VERSION_UNIT
* 01-04-16 02.00.42 Bumped MPI_HEADER_VERSION_UNIT
+ * 04-05-16 02.00.43 Modified MPI26_DIAG_BOOT_DEVICE_SELECT defines
+ * to be unique within first 32 characters.
+ * Removed AHCI support.
+ * Removed SOP support.
+ * Bumped MPI2_HEADER_VERSION_UNIT.
+ * 04-10-16 02.00.44 Bumped MPI2_HEADER_VERSION_UNIT.
+ * 07-06-16 02.00.45 Bumped MPI2_HEADER_VERSION_UNIT.
+ * 09-02-16 02.00.46 Bumped MPI2_HEADER_VERSION_UNIT.
* --------------------------------------------------------------------------
mpi2_cnfg.h
@@ -323,9 +333,38 @@
* Flags field to IO Unit Page 7.
* Added IO Unit Page 11.
* Added new SAS Phy Event codes
+ * Added PCIe configuration pages.
+ * 03-19-15 02.00.32 Fixed PCIe Link Config page structure names to be
+ * unique in first 32 characters.
* 05-25-15 02.00.33 Added more defines for the BiosOptions field of
* MPI2_CONFIG_PAGE_BIOS_1.
+ * 08-25-15 02.00.34 Added PCIe Device Page 2 SGL format capability.
* 12-18-15 02.00.35 Added SATADeviceWaitTime to SAS IO Unit Page 4.
+ * 01-21-16 02.00.36 Added/modified MPI2_MFGPAGE_DEVID_SAS defines.
+ * Added Link field to PCIe Link Pages
+ * Added EnclosureLevel and ConnectorName to PCIe
+ * Device Page 0.
+ * Added define for PCIE IoUnit page 1 max rate shift.
+ * Added comment for reserved ExtPageTypes.
+ * Added SAS 4 22.5 gbs speed support.
+ * Added PCIe 4 16.0 GT/sec speec support.
+ * Removed AHCI support.
+ * Removed SOP support.
+ * Added NegotiatedLinkRate and NegotiatedPortWidth to
+ * PCIe device page 0.
+ * 04-10-16 02.00.37 Fixed MPI2_MFGPAGE_DEVID_SAS3616/3708 defines
+ * 07-01-16 02.00.38 Added Manufacturing page 7 Connector types.
+ * Changed declaration of ConnectorName in PCIe DevicePage0
+ * to match SAS DevicePage 0.
+ * Added SATADeviceWaitTime to IO Unit Page 11.
+ * Added MPI26_MFGPAGE_DEVID_SAS4008
+ * Added x16 PCIe width to IO Unit Page 7
+ * Added LINKFLAGS to control SRIS in PCIe IO Unit page 1
+ * phy data.
+ * Added InitStatus to PCIe IO Unit Page 1 header.
+ * 09-01-16 02.00.39 Added MPI26_CONFIG_PAGE_ENCLOSURE_0 and related defines.
+ * Added MPI26_ENCLOS_PGAD_FORM_GET_NEXT_HANDLE and
+ * MPI26_ENCLOS_PGAD_FORM_HANDLE page address formats.
* --------------------------------------------------------------------------
mpi2_init.h
@@ -365,6 +404,8 @@
* 08-26-15 02.00.18 Added SCSITASKMGMT_MSGFLAGS for Target Reset.
* 12-18-15 02.00.19 Added EEDPObservedValue added to SCSI IO Reply message.
* 01-04-16 02.00.20 Modified EEDP reported values in SCSI IO Reply message.
+ * 01-21-16 02.00.21 Modified MPI26_SCSITASKMGMT_MSGFLAGS_PCIE* defines to
+ * be unique within first 32 characters.
* --------------------------------------------------------------------------
mpi2_ioc.h
@@ -491,9 +532,30 @@
* MPI26_EVENT_DATA_PCIE_LINK_COUNTER.
* Added MPI26_CTRL_OP_SHUTDOWN.
* Added MPI26_CTRL_OP_LINK_CLEAR_ERROR_LOG
- * Added MPI26_FW_HEADER_PID_FAMILY_3324_SAS
+ * Added MPI26_FW_HEADER_PID_FAMILY_3324_SAS and
+ * MPI26_FW_HEADER_PID_FAMILY_3516_SAS.
* 08-25-15 02.00.27 Added IC ARCH Class based signature defines.
- * --------------------------------------------------------------------------
+ * Added MPI26_EVENT_PCIE_ENUM_ES_RESOURCES_EXHAUSTED event.
+ * Added ConigurationFlags field to IOCInit message to
+ * support NVMe SGL format control.
+ * Added PCIe SRIOV support.
+ * 02-17-16 02.00.28 Added SAS 4 22.5 gbs speed support.
+ * Added PCIe 4 16.0 GT/sec speec support.
+ * Removed AHCI support.
+ * Removed SOP support.
+ * 07-01-16 02.00.29 Added Archclass for 4008 product.
+ * Added IOCException MPI2_IOCFACTS_EXCEPT_PCIE_DISABLED.
+ * 08-23-16 02.00.30 Added new defines for the ImageType field of FWDownload
+ * Request Message.
+ * Added new defines for the ImageType field of FWUpload
+ * Request Message.
+ * Added new values for the RegionType field in the Layout
+ * Data sections of the FLASH Layout Extended Image Data.
+ * Added new defines for the ReasonCode field of
+ * Active Cable Exception Event.
+ * Added MPI2_EVENT_ENCL_DEVICE_STATUS_CHANGE and
+ * MPI26_EVENT_DATA_ENCL_DEV_STATUS_CHANGE.
+ * --------------------------------------------------------------------------
mpi2_raid.h
* 04-30-07 02.00.00 Corresponds to Fusion-MPT MPI Specification Rev A.
@@ -581,6 +643,8 @@
* 08-19-13 02.00.11 Added MPI2_TOOLBOX_TEXT_DISPLAY_TOOL and related info.
* 01-08-14 02.00.12 Added MPI2_TOOLBOX_CLEAN_BIT26_PRODUCT_SPECIFIC.
* 11-18-14 02.00.13 Updated copyright information.
+ * 08-25-16 02.00.14 Added new values for the Flags field of Toolbox Clean
+ * Tool Request Message.
* --------------------------------------------------------------------------
mpi2_type.h
@@ -599,24 +663,33 @@
* HBD Action request, replaced by AdditionalInfo field.
* 11-18-11 02.00.02 Incorporating additions for MPI v2.5.
* 11-18-14 02.00.03 Updated copyright information.
+ * 02-17-16 02.00.04 Added SAS 4 22.5 gbs speed support.
* --------------------------------------------------------------------------
+mpi2_pci.h
+ * 03-16-15 02.00.00 Initial version.
+ * 02-17-16 02.00.01 Removed AHCI support.
+ * Removed SOP support.
+ * 07-01-16 02.00.02 Added MPI26_NVME_FLAGS_FORCE_ADMIN_ERR_RESP to
+ * NVME Encapsulated Request.
+ * --------------------------------------------------------------------------
mpi2_history.txt Parts list history
-Filename 02.00.42
----------- --------
-mpi2.h 02.00.42
-mpi2_cnfg.h 02.00.35
-mpi2_init.h 02.00.20
-mpi2_ioc.h 02.00.27
-mpi2_raid.h 02.00.11
-mpi2_sas.h 02.00.10
-mpi2_targ.h 02.00.09
-mpi2_tool.h 02.00.13
-mpi2_type.h 02.00.01
-mpi2_ra.h 02.00.01
-mpi2_hbd.h 02.00.03
+Filename 02.00.46 02.00.45 02.00.44 02.00.43 02.00.42
+---------- -------- -------- -------- -------- --------
+mpi2.h 02.00.46 02.00.45 02.00.44 02.00.43 02.00.42
+mpi2_cnfg.h 02.00.39 02.00.38 02.00.37 02.00.36 02.00.35
+mpi2_init.h 02.00.21 02.00.21 02.00.21 02.00.21 02.00.20
+mpi2_ioc.h 02.00.30 02.00.29 02.00.28 02.00.28 02.00.27
+mpi2_raid.h 02.00.11 02.00.11 02.00.11 02.00.11 02.00.11
+mpi2_sas.h 02.00.10 02.00.10 02.00.10 02.00.10 02.00.10
+mpi2_targ.h 02.00.09 02.00.09 02.00.09 02.00.09 02.00.09
+mpi2_tool.h 02.00.14 02.00.13 02.00.13 02.00.13 02.00.13
+mpi2_type.h 02.00.01 02.00.01 02.00.01 02.00.01 02.00.01
+mpi2_ra.h 02.00.01 02.00.01 02.00.01 02.00.01 02.00.01
+mpi2_hbd.h 02.00.04 02.00.04 02.00.04 02.00.04 02.00.03
+mpi2_pci.h 02.00.02 02.00.02 02.00.01 02.00.01 02.00.00
Filename 02.00.41 02.00.40 02.00.39 02.00.38 02.00.37 02.00.36
---------- -------- -------- -------- -------- -------- --------
@@ -631,6 +704,7 @@
mpi2_type.h 02.00.01 02.00.01 02.00.01 02.00.01 02.00.01 02.00.01
mpi2_ra.h 02.00.01 02.00.01 02.00.01 02.00.01 02.00.01 02.00.01
mpi2_hbd.h 02.00.03 02.00.03 02.00.03 02.00.03 02.00.03 02.00.03
+mpi2_pci.h 02.00.00 02.00.00 02.00.00 02.00.00 02.00.00
Filename 02.00.35 02.00.34 02.00.33 02.00.32 02.00.31 02.00.30
---------- -------- -------- -------- -------- -------- --------
Index: sys/dev/mpr/mpi/mpi2_init.h
===================================================================
--- sys/dev/mpr/mpi/mpi2_init.h
+++ sys/dev/mpr/mpi/mpi2_init.h
@@ -42,7 +42,7 @@
* Title: MPI SCSI initiator mode messages and structures
* Creation Date: June 23, 2006
*
- * mpi2_init.h Version: 02.00.20
+ * mpi2_init.h Version: 02.00.21
*
* 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
@@ -62,7 +62,7 @@
* 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
+ * Moved LUN field defines to mpi2.h because they are
* common to many structures.
* 05-06-09 02.00.07 Changed task management type of Query Unit Attention to
* Query Asynchronous Event.
@@ -90,6 +90,8 @@
* 08-26-15 02.00.18 Added SCSITASKMGMT_MSGFLAGS for Target Reset.
* 12-18-15 02.00.19 Added EEDPObservedValue added to SCSI IO Reply message.
* 01-04-16 02.00.20 Modified EEDP reported values in SCSI IO Reply message.
+ * 01-21-16 02.00.21 Modified MPI26_SCSITASKMGMT_MSGFLAGS_PCIE* defines to
+ * be unique within first 32 characters.
* --------------------------------------------------------------------------
*/
@@ -491,12 +493,13 @@
#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_MASK_TARGET_RESET (0x18)
+#define MPI26_SCSITASKMGMT_MSGFLAGS_HOT_RESET_PCIE (0x00)
+#define MPI2_SCSITASKMGMT_MSGFLAGS_LINK_RESET (0x00)
#define MPI2_SCSITASKMGMT_MSGFLAGS_DO_NOT_SEND_TASK_IU (0x01)
-#define MPI2_SCSITASKMGMT_MSGFLAGS_NEXUS_RESET_SRST (0x08)
-#define MPI2_SCSITASKMGMT_MSGFLAGS_SAS_HARD_LINK_RESET (0x10)
+#define MPI2_SCSITASKMGMT_MSGFLAGS_NEXUS_RESET_SRST (0x08)
+#define MPI2_SCSITASKMGMT_MSGFLAGS_SAS_HARD_LINK_RESET (0x10)
+#define MPI26_SCSITASKMGMT_MSGFLAGS_PROTOCOL_LVL_RST_PCIE (0x18)
/* SCSI Task Management Reply Message */
Index: sys/dev/mpr/mpi/mpi2_ioc.h
===================================================================
--- sys/dev/mpr/mpi/mpi2_ioc.h
+++ sys/dev/mpr/mpi/mpi2_ioc.h
@@ -42,7 +42,7 @@
* Title: MPI IOC, Port, Event, FW Download, and FW Upload messages
* Creation Date: October 11, 2006
*
- * mpi2_ioc.h Version: 02.00.27
+ * mpi2_ioc.h Version: 02.00.30
*
* 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
@@ -177,9 +177,29 @@
* MPI26_EVENT_DATA_PCIE_LINK_COUNTER.
* Added MPI26_CTRL_OP_SHUTDOWN.
* Added MPI26_CTRL_OP_LINK_CLEAR_ERROR_LOG
- * Added MPI26_FW_HEADER_PID_FAMILY_3324_SAS
- * 08-25-15 02.00.27 Added IC ARCH Class based signature defines
- *
+ * Added MPI26_FW_HEADER_PID_FAMILY_3324_SAS and
+ * MPI26_FW_HEADER_PID_FAMILY_3516_SAS.
+ * 08-25-15 02.00.27 Added IC ARCH Class based signature defines.
+ * Added MPI26_EVENT_PCIE_ENUM_ES_RESOURCES_EXHAUSTED event.
+ * Added ConigurationFlags field to IOCInit message to
+ * support NVMe SGL format control.
+ * Added PCIe SRIOV support.
+ * 02-17-16 02.00.28 Added SAS 4 22.5 gbs speed support.
+ * Added PCIe 4 16.0 GT/sec speec support.
+ * Removed AHCI support.
+ * Removed SOP support.
+ * 07-01-16 02.00.29 Added Archclass for 4008 product.
+ * Added IOCException MPI2_IOCFACTS_EXCEPT_PCIE_DISABLED
+ * 08-23-16 02.00.30 Added new defines for the ImageType field of FWDownload
+ * Request Message.
+ * Added new defines for the ImageType field of FWUpload
+ * Request Message.
+ * Added new values for the RegionType field in the Layout
+ * Data sections of the FLASH Layout Extended Image Data.
+ * Added new defines for the ReasonCode field of
+ * Active Cable Exception Event.
+ * Added MPI2_EVENT_ENCL_DEVICE_STATUS_CHANGE and
+ * MPI26_EVENT_DATA_ENCL_DEV_STATUS_CHANGE.
* --------------------------------------------------------------------------
*/
@@ -251,6 +271,9 @@
#define MPI2_IOCINIT_HDRVERSION_DEV_MASK (0x00FF)
#define MPI2_IOCINIT_HDRVERSION_DEV_SHIFT (0)
+/* ConfigurationFlags */
+#define MPI26_IOCINIT_CFGFLAGS_NVME_SGL_FORMAT (0x0001)
+
/* minimum depth for a Reply Descriptor Post Queue */
#define MPI2_RDPQ_DEPTH_MIN (16)
@@ -363,6 +386,7 @@
#define MPI2_IOCFACTS_HDRVERSION_DEV_SHIFT (0)
/* IOCExceptions */
+#define MPI2_IOCFACTS_EXCEPT_PCIE_DISABLED (0x0400)
#define MPI2_IOCFACTS_EXCEPT_PARTIAL_MEMORY_FAILURE (0x0200)
#define MPI2_IOCFACTS_EXCEPT_IR_FOREIGN_CONFIG_MAX (0x0100)
@@ -383,6 +407,8 @@
/* ProductID field uses MPI2_FW_HEADER_PID_ */
/* IOCCapabilities */
+#define MPI26_IOCFACTS_CAPABILITY_PCIE_SRIOV (0x00100000)
+#define MPI26_IOCFACTS_CAPABILITY_ATOMIC_REQ (0x00080000)
#define MPI2_IOCFACTS_CAPABILITY_RDPQ_ARRAY_CAPABLE (0x00040000)
#define MPI25_IOCFACTS_CAPABILITY_FAST_PATH_CAPABLE (0x00020000)
#define MPI2_IOCFACTS_CAPABILITY_HOST_BASED_DISCOVERY (0x00010000)
@@ -400,6 +426,7 @@
#define MPI2_IOCFACTS_CAPABILITY_TASK_SET_FULL_HANDLING (0x00000004)
/* ProtocolFlags */
+#define MPI2_IOCFACTS_PROTOCOL_NVME_DEVICES (0x0008) /* MPI v2.6 and later */
#define MPI2_IOCFACTS_PROTOCOL_SCSI_INITIATOR (0x0002)
#define MPI2_IOCFACTS_PROTOCOL_SCSI_TARGET (0x0001)
@@ -452,6 +479,7 @@
#define MPI2_PORTFACTS_PORTTYPE_ISCSI (0x20)
#define MPI2_PORTFACTS_PORTTYPE_SAS_PHYSICAL (0x30)
#define MPI2_PORTFACTS_PORTTYPE_SAS_VIRTUAL (0x31)
+#define MPI2_PORTFACTS_PORTTYPE_TRI_MODE (0x40) /* MPI v2.6 and later */
/****************************************************************************
@@ -564,6 +592,7 @@
#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_ENCL_DEVICE_STATUS_CHANGE (0x001D) /* MPI v2.6 and later */
#define MPI2_EVENT_IR_VOLUME (0x001E)
#define MPI2_EVENT_IR_PHYSICAL_DISK (0x001F)
#define MPI2_EVENT_IR_CONFIGURATION_CHANGE_LIST (0x0020)
@@ -576,6 +605,10 @@
#define MPI2_EVENT_TEMP_THRESHOLD (0x0027)
#define MPI2_EVENT_HOST_MESSAGE (0x0028)
#define MPI2_EVENT_POWER_PERFORMANCE_CHANGE (0x0029)
+#define MPI2_EVENT_PCIE_DEVICE_STATUS_CHANGE (0x0030) /* MPI v2.6 and later */
+#define MPI2_EVENT_PCIE_ENUMERATION (0x0031) /* MPI v2.6 and later */
+#define MPI2_EVENT_PCIE_TOPOLOGY_CHANGE_LIST (0x0032) /* MPI v2.6 and later */
+#define MPI2_EVENT_PCIE_LINK_COUNTER (0x0033) /* MPI v2.6 and later */
#define MPI2_EVENT_ACTIVE_CABLE_EXCEPTION (0x0034) /* MPI v2.6 and later */
#define MPI2_EVENT_MIN_PRODUCT_SPECIFIC (0x006E)
#define MPI2_EVENT_MAX_PRODUCT_SPECIFIC (0x007F)
@@ -688,11 +721,9 @@
MPI2_POINTER pMpi26EventDataActiveCableExcept_t;
/* defines for ReasonCode field */
-#define MPI26_EVENT_ACTIVE_CABLE_INSUFFICIENT_POWER (0x00)
-#define MPI26_EVENT_ACTIVE_CABLE_PRESENT (0x01)
-#define MPI26_EVENT_ACTIVE_CABLE_DEGRADED (0x02)
-
-
+#define MPI26_EVENT_ACTIVE_CABLE_INSUFFICIENT_POWER (0x00)
+#define MPI26_EVENT_ACTIVE_CABLE_PRESENT (0x01)
+#define MPI26_EVENT_ACTIVE_CABLE_DEGRADED (0x02)
/* Hard Reset Received Event data */
@@ -1048,6 +1079,7 @@
#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)
+#define MPI26_EVENT_SAS_TOPO_LR_RATE_22_5 (0x0C)
/* values for the PhyStatus field */
#define MPI2_EVENT_SAS_TOPO_PHYSTATUS_VACANT (0x80)
@@ -1075,12 +1107,19 @@
} 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;
+ MPI2_POINTER pMpi2EventDataSasEnclDevStatusChange_t,
+ MPI26_EVENT_DATA_ENCL_DEV_STATUS_CHANGE,
+ MPI2_POINTER PTR_MPI26_EVENT_DATA_ENCL_DEV_STATUS_CHANGE,
+ Mpi26EventDataEnclDevStatusChange_t,
+ MPI2_POINTER pMpi26EventDataEnclDevStatusChange_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)
+/* Enclosure Device Status Change event ReasonCode values */
+#define MPI26_EVENT_ENCL_RC_ADDED (0x01)
+#define MPI26_EVENT_ENCL_RC_NOT_RESPONDING (0x02)
/* SAS PHY Counter Event data */
@@ -1168,6 +1207,167 @@
#define MPI2_EVENT_HBD_DT_SAS (0x01)
+/* PCIe Device Status Change Event data (MPI v2.6 and later) */
+
+typedef struct _MPI26_EVENT_DATA_PCIE_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 WWID; /* 0x0C */
+ U8 LUN[8]; /* 0x14 */
+} MPI26_EVENT_DATA_PCIE_DEVICE_STATUS_CHANGE,
+ MPI2_POINTER PTR_MPI26_EVENT_DATA_PCIE_DEVICE_STATUS_CHANGE,
+ Mpi26EventDataPCIeDeviceStatusChange_t,
+ MPI2_POINTER pMpi26EventDataPCIeDeviceStatusChange_t;
+
+/* PCIe Device Status Change Event data ReasonCode values */
+#define MPI26_EVENT_PCIDEV_STAT_RC_SMART_DATA (0x05)
+#define MPI26_EVENT_PCIDEV_STAT_RC_UNSUPPORTED (0x07)
+#define MPI26_EVENT_PCIDEV_STAT_RC_INTERNAL_DEVICE_RESET (0x08)
+#define MPI26_EVENT_PCIDEV_STAT_RC_TASK_ABORT_INTERNAL (0x09)
+#define MPI26_EVENT_PCIDEV_STAT_RC_ABORT_TASK_SET_INTERNAL (0x0A)
+#define MPI26_EVENT_PCIDEV_STAT_RC_CLEAR_TASK_SET_INTERNAL (0x0B)
+#define MPI26_EVENT_PCIDEV_STAT_RC_QUERY_TASK_INTERNAL (0x0C)
+#define MPI26_EVENT_PCIDEV_STAT_RC_ASYNC_NOTIFICATION (0x0D)
+#define MPI26_EVENT_PCIDEV_STAT_RC_CMP_INTERNAL_DEV_RESET (0x0E)
+#define MPI26_EVENT_PCIDEV_STAT_RC_CMP_TASK_ABORT_INTERNAL (0x0F)
+#define MPI26_EVENT_PCIDEV_STAT_RC_DEV_INIT_FAILURE (0x10)
+
+
+/* PCIe Enumeration Event data (MPI v2.6 and later) */
+
+typedef struct _MPI26_EVENT_DATA_PCIE_ENUMERATION
+{
+ U8 Flags; /* 0x00 */
+ U8 ReasonCode; /* 0x01 */
+ U8 PhysicalPort; /* 0x02 */
+ U8 Reserved1; /* 0x03 */
+ U32 EnumerationStatus; /* 0x04 */
+} MPI26_EVENT_DATA_PCIE_ENUMERATION,
+ MPI2_POINTER PTR_MPI26_EVENT_DATA_PCIE_ENUMERATION,
+ Mpi26EventDataPCIeEnumeration_t,
+ MPI2_POINTER pMpi26EventDataPCIeEnumeration_t;
+
+/* PCIe Enumeration Event data Flags values */
+#define MPI26_EVENT_PCIE_ENUM_DEVICE_CHANGE (0x02)
+#define MPI26_EVENT_PCIE_ENUM_IN_PROGRESS (0x01)
+
+/* PCIe Enumeration Event data ReasonCode values */
+#define MPI26_EVENT_PCIE_ENUM_RC_STARTED (0x01)
+#define MPI26_EVENT_PCIE_ENUM_RC_COMPLETED (0x02)
+
+/* PCIe Enumeration Event data EnumerationStatus values */
+#define MPI26_EVENT_PCIE_ENUM_ES_MAX_SWITCHES_EXCEED (0x40000000)
+#define MPI26_EVENT_PCIE_ENUM_ES_MAX_DEVICES_EXCEED (0x20000000)
+#define MPI26_EVENT_PCIE_ENUM_ES_RESOURCES_EXHAUSTED (0x10000000)
+
+
+/* PCIe Topology Change List Event data (MPI v2.6 and later) */
+
+/*
+ * Host code (drivers, BIOS, utilities, etc.) should leave this define set to
+ * one and check NumEntries at runtime.
+ */
+#ifndef MPI26_EVENT_PCIE_TOPO_PORT_COUNT
+#define MPI26_EVENT_PCIE_TOPO_PORT_COUNT (1)
+#endif
+
+typedef struct _MPI26_EVENT_PCIE_TOPO_PORT_ENTRY
+{
+ U16 AttachedDevHandle; /* 0x00 */
+ U8 PortStatus; /* 0x02 */
+ U8 Reserved1; /* 0x03 */
+ U8 CurrentPortInfo; /* 0x04 */
+ U8 Reserved2; /* 0x05 */
+ U8 PreviousPortInfo; /* 0x06 */
+ U8 Reserved3; /* 0x07 */
+} MPI26_EVENT_PCIE_TOPO_PORT_ENTRY,
+ MPI2_POINTER PTR_MPI26_EVENT_PCIE_TOPO_PORT_ENTRY,
+ Mpi26EventPCIeTopoPortEntry_t,
+ MPI2_POINTER pMpi26EventPCIeTopoPortEntry_t;
+
+/* PCIe Topology Change List Event data PortStatus values */
+#define MPI26_EVENT_PCIE_TOPO_PS_DEV_ADDED (0x01)
+#define MPI26_EVENT_PCIE_TOPO_PS_NOT_RESPONDING (0x02)
+#define MPI26_EVENT_PCIE_TOPO_PS_PORT_CHANGED (0x03)
+#define MPI26_EVENT_PCIE_TOPO_PS_NO_CHANGE (0x04)
+#define MPI26_EVENT_PCIE_TOPO_PS_DELAY_NOT_RESPONDING (0x05)
+
+/* PCIe Topology Change List Event data defines for CurrentPortInfo and PreviousPortInfo */
+#define MPI26_EVENT_PCIE_TOPO_PI_LANE_MASK (0xF0)
+#define MPI26_EVENT_PCIE_TOPO_PI_LANES_UNKNOWN (0x00)
+#define MPI26_EVENT_PCIE_TOPO_PI_1_LANE (0x10)
+#define MPI26_EVENT_PCIE_TOPO_PI_2_LANES (0x20)
+#define MPI26_EVENT_PCIE_TOPO_PI_4_LANES (0x30)
+#define MPI26_EVENT_PCIE_TOPO_PI_8_LANES (0x40)
+
+#define MPI26_EVENT_PCIE_TOPO_PI_RATE_MASK (0x0F)
+#define MPI26_EVENT_PCIE_TOPO_PI_RATE_UNKNOWN (0x00)
+#define MPI26_EVENT_PCIE_TOPO_PI_RATE_DISABLED (0x01)
+#define MPI26_EVENT_PCIE_TOPO_PI_RATE_2_5 (0x02)
+#define MPI26_EVENT_PCIE_TOPO_PI_RATE_5_0 (0x03)
+#define MPI26_EVENT_PCIE_TOPO_PI_RATE_8_0 (0x04)
+#define MPI26_EVENT_PCIE_TOPO_PI_RATE_16_0 (0x05)
+
+typedef struct _MPI26_EVENT_DATA_PCIE_TOPOLOGY_CHANGE_LIST
+{
+ U16 EnclosureHandle; /* 0x00 */
+ U16 SwitchDevHandle; /* 0x02 */
+ U8 NumPorts; /* 0x04 */
+ U8 Reserved1; /* 0x05 */
+ U16 Reserved2; /* 0x06 */
+ U8 NumEntries; /* 0x08 */
+ U8 StartPortNum; /* 0x09 */
+ U8 SwitchStatus; /* 0x0A */
+ U8 PhysicalPort; /* 0x0B */
+ MPI26_EVENT_PCIE_TOPO_PORT_ENTRY PortEntry[MPI26_EVENT_PCIE_TOPO_PORT_COUNT]; /* 0x0C */
+} MPI26_EVENT_DATA_PCIE_TOPOLOGY_CHANGE_LIST,
+ MPI2_POINTER PTR_MPI26_EVENT_DATA_PCIE_TOPOLOGY_CHANGE_LIST,
+ Mpi26EventDataPCIeTopologyChangeList_t,
+ MPI2_POINTER pMpi26EventDataPCIeTopologyChangeList_t;
+
+/* PCIe Topology Change List Event data SwitchStatus values */
+#define MPI26_EVENT_PCIE_TOPO_SS_NO_PCIE_SWITCH (0x00)
+#define MPI26_EVENT_PCIE_TOPO_SS_ADDED (0x01)
+#define MPI26_EVENT_PCIE_TOPO_SS_NOT_RESPONDING (0x02)
+#define MPI26_EVENT_PCIE_TOPO_SS_RESPONDING (0x03)
+#define MPI26_EVENT_PCIE_TOPO_SS_DELAY_NOT_RESPONDING (0x04)
+
+/* PCIe Link Counter Event data (MPI v2.6 and later) */
+
+typedef struct _MPI26_EVENT_DATA_PCIE_LINK_COUNTER
+{
+ U64 TimeStamp; /* 0x00 */
+ U32 Reserved1; /* 0x08 */
+ U8 LinkEventCode; /* 0x0C */
+ U8 LinkNum; /* 0x0D */
+ U16 Reserved2; /* 0x0E */
+ U32 LinkEventInfo; /* 0x10 */
+ U8 CounterType; /* 0x14 */
+ U8 ThresholdWindow; /* 0x15 */
+ U8 TimeUnits; /* 0x16 */
+ U8 Reserved3; /* 0x17 */
+ U32 EventThreshold; /* 0x18 */
+ U16 ThresholdFlags; /* 0x1C */
+ U16 Reserved4; /* 0x1E */
+} MPI26_EVENT_DATA_PCIE_LINK_COUNTER,
+ MPI2_POINTER PTR_MPI26_EVENT_DATA_PCIE_LINK_COUNTER,
+ Mpi26EventDataPcieLinkCounter_t, MPI2_POINTER pMpi26EventDataPcieLinkCounter_t;
+
+
+/* use MPI26_PCIELINK3_EVTCODE_ values from mpi2_cnfg.h for the LinkEventCode field */
+
+/* use MPI26_PCIELINK3_COUNTER_TYPE_ values from mpi2_cnfg.h for the CounterType field */
+
+/* use MPI26_PCIELINK3_TIME_UNITS_ values from mpi2_cnfg.h for the TimeUnits field */
+
+/* use MPI26_PCIELINK3_TFLAGS_ values from mpi2_cnfg.h for the ThresholdFlags field */
+
/****************************************************************************
* EventAck message
****************************************************************************/
@@ -1293,6 +1493,13 @@
#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_SBR (0x0E)
+#define MPI2_FW_DOWNLOAD_ITYPE_SBR_BACKUP (0x0F)
+#define MPI2_FW_DOWNLOAD_ITYPE_HIIM (0x10)
+#define MPI2_FW_DOWNLOAD_ITYPE_HIIA (0x11)
+#define MPI2_FW_DOWNLOAD_ITYPE_CTLR (0x12)
+#define MPI2_FW_DOWNLOAD_ITYPE_IMR_FIRMWARE (0x13)
+#define MPI2_FW_DOWNLOAD_ITYPE_MR_NVDATA (0x14)
#define MPI2_FW_DOWNLOAD_ITYPE_MIN_PRODUCT_SPECIFIC (0xF0)
/* MPI v2.0 FWDownload TransactionContext Element */
@@ -1386,6 +1593,13 @@
#define MPI2_FW_UPLOAD_ITYPE_COMPLETE (0x0A)
#define MPI2_FW_UPLOAD_ITYPE_COMMON_BOOT_BLOCK (0x0B)
#define MPI2_FW_UPLOAD_ITYPE_CBB_BACKUP (0x0D)
+#define MPI2_FW_UPLOAD_ITYPE_SBR (0x0E)
+#define MPI2_FW_UPLOAD_ITYPE_SBR_BACKUP (0x0F)
+#define MPI2_FW_UPLOAD_ITYPE_HIIM (0x10)
+#define MPI2_FW_UPLOAD_ITYPE_HIIA (0x11)
+#define MPI2_FW_UPLOAD_ITYPE_CTLR (0x12)
+#define MPI2_FW_UPLOAD_ITYPE_IMR_FIRMWARE (0x13)
+#define MPI2_FW_UPLOAD_ITYPE_MR_NVDATA (0x14)
/* MPI v2.0 FWUpload TransactionContext Element */
typedef struct _MPI2_FW_UPLOAD_TCSGE
@@ -1509,8 +1723,10 @@
#define MPI26_FW_HEADER_SIGNATURE0_ARC_0 (0x5A)
#define MPI26_FW_HEADER_SIGNATURE0_ARC_1 (0x00)
#define MPI26_FW_HEADER_SIGNATURE0_ARC_2 (0x01)
+#define MPI26_FW_HEADER_SIGNATURE0_ARC_3 (0x02)
#define MPI26_FW_HEADER_SIGNATURE0 (MPI26_FW_HEADER_SIGNATURE0_BASE+MPI26_FW_HEADER_SIGNATURE0_ARC_0) // legacy (0x5AEAA55A)
#define MPI26_FW_HEADER_SIGNATURE0_3516 (MPI26_FW_HEADER_SIGNATURE0_BASE+MPI26_FW_HEADER_SIGNATURE0_ARC_1)
+#define MPI26_FW_HEADER_SIGNATURE0_4008 (MPI26_FW_HEADER_SIGNATURE0_BASE+MPI26_FW_HEADER_SIGNATURE0_ARC_3)
/* Signature1 field */
#define MPI2_FW_HEADER_SIGNATURE1_OFFSET (0x08)
@@ -1665,7 +1881,13 @@
#define MPI2_FLASH_REGION_COMMON_BOOT_BLOCK (0x0A)
#define MPI2_FLASH_REGION_INIT (MPI2_FLASH_REGION_COMMON_BOOT_BLOCK) /* older name */
#define MPI2_FLASH_REGION_CBB_BACKUP (0x0D)
-
+#define MPI2_FLASH_REGION_SBR (0x0E)
+#define MPI2_FLASH_REGION_SBR_BACKUP (0x0F)
+#define MPI2_FLASH_REGION_HIIM (0x10)
+#define MPI2_FLASH_REGION_HIIA (0x11)
+#define MPI2_FLASH_REGION_CTLR (0x12)
+#define MPI2_FLASH_REGION_IMR_FIRMWARE (0x13)
+#define MPI2_FLASH_REGION_MR_NVDATA (0x14)
/* ImageRevision */
#define MPI2_FLASH_LAYOUT_IMAGE_REVISION (0x00)
@@ -1960,6 +2182,8 @@
#define MPI26_CTRL_OP_DEV_ENABLE_PERSIST_CONNECTION (0x17)
#define MPI26_CTRL_OP_DEV_DISABLE_PERSIST_CONNECTION (0x18)
#define MPI26_CTRL_OP_DEV_CLOSE_PERSIST_CONNECTION (0x19)
+#define MPI26_CTRL_OP_ENABLE_NVME_SGL_FORMAT (0x1A)
+#define MPI26_CTRL_OP_DISABLE_NVME_SGL_FORMAT (0x1B)
#define MPI26_CTRL_OP_PRODUCT_SPECIFIC_MIN (0x80)
/* values for the PrimFlags field */
Index: sys/dev/mpr/mpi/mpi2_tool.h
===================================================================
--- sys/dev/mpr/mpi/mpi2_tool.h
+++ sys/dev/mpr/mpi/mpi2_tool.h
@@ -42,7 +42,7 @@
* Title: MPI diagnostic tool structures and definitions
* Creation Date: March 26, 2007
*
- * mpi2_tool.h Version: 02.00.13
+ * mpi2_tool.h Version: 02.00.14
*
* Version History
* ---------------
@@ -71,6 +71,8 @@
* 08-19-13 02.00.11 Added MPI2_TOOLBOX_TEXT_DISPLAY_TOOL and related info.
* 01-08-14 02.00.12 Added MPI2_TOOLBOX_CLEAN_BIT26_PRODUCT_SPECIFIC.
* 11-18-14 02.00.13 Updated copyright information.
+ * 08-25-16 02.00.14 Added new values for the Flags field of Toolbox Clean
+ * Tool Request Message.
* --------------------------------------------------------------------------
*/
@@ -145,6 +147,16 @@
#define MPI2_TOOLBOX_CLEAN_BIT26_PRODUCT_SPECIFIC (0x04000000)
#define MPI2_TOOLBOX_CLEAN_MEGARAID (0x02000000)
#define MPI2_TOOLBOX_CLEAN_INITIALIZATION (0x01000000)
+#define MPI2_TOOLBOX_CLEAN_SBR (0x00800000)
+#define MPI2_TOOLBOX_CLEAN_SBR_BACKUP (0x00400000)
+#define MPI2_TOOLBOX_CLEAN_HIIM (0x00200000)
+#define MPI2_TOOLBOX_CLEAN_HIIA (0x00100000)
+#define MPI2_TOOLBOX_CLEAN_CTLR (0x00080000)
+#define MPI2_TOOLBOX_CLEAN_IMR_FIRMWARE (0x00040000)
+#define MPI2_TOOLBOX_CLEAN_MR_NVDATA (0x00020000)
+#define MPI2_TOOLBOX_CLEAN_RESERVED_5_16 (0x0001FFE0)
+#define MPI2_TOOLBOX_CLEAN_ALL_BUT_MPB (0x00000010)
+#define MPI2_TOOLBOX_CLEAN_ENTIRE_FLASH (0x00000008)
#define MPI2_TOOLBOX_CLEAN_FLASH (0x00000004)
#define MPI2_TOOLBOX_CLEAN_SEEPROM (0x00000002)
#define MPI2_TOOLBOX_CLEAN_NVSRAM (0x00000001)
Index: sys/dev/mpr/mpr.c
===================================================================
--- sys/dev/mpr/mpr.c
+++ sys/dev/mpr/mpr.c
@@ -63,18 +63,21 @@
#include <dev/pci/pcivar.h>
#include <cam/cam.h>
+#include <cam/cam_ccb.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_pci.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);
@@ -87,6 +90,7 @@
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_alloc_nvme_prp_pages(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);
@@ -110,7 +114,7 @@
/*
* Added this union to smoothly convert le64toh cm->cm_desc.Words.
- * Compiler only supports unint64_t to be passed as an argument.
+ * Compiler only supports uint64_t to be passed as an argument.
* Otherwise it will through this error:
* "aggregate value used where an integer was expected"
*/
@@ -120,7 +124,7 @@
u32 low;
u32 high;
} u;
-}reply_descriptor,address_descriptor;
+} reply_descriptor, request_descriptor;
/* Rate limit chain-fail messages to 1 per minute */
static struct timeval mpr_chainfail_interval = { 60, 0 };
@@ -311,7 +315,6 @@
if (error)
device_printf(sc->mpr_dev, "Cannot transition IOC to ready\n");
-
return (error);
}
@@ -392,7 +395,8 @@
mpr_printf(sc, "IOCCapabilities: %b\n", sc->facts->IOCCapabilities,
"\20" "\3ScsiTaskFull" "\4DiagTrace" "\5SnapBuf" "\6ExtBuf"
"\7EEDP" "\10BiDirTarg" "\11Multicast" "\14TransRetry" "\15IR"
- "\16EventReplay" "\17RaidAccel" "\20MSIXIndex" "\21HostDisc");
+ "\16EventReplay" "\17RaidAccel" "\20MSIXIndex" "\21HostDisc"
+ "\22FastPath" "\23RDPQArray" "\24AtomicReqDesc" "\25PCIeSRIOV");
/*
* If the chip doesn't support event replay then a hard reset will be
@@ -480,12 +484,15 @@
enabled = TRUE;
/*
- * Set flag if EEDP is supported and if TLR is supported.
+ * Set flags for some supported items.
*/
if (sc->facts->IOCCapabilities & MPI2_IOCFACTS_CAPABILITY_EEDP)
sc->eedp_enabled = TRUE;
if (sc->facts->IOCCapabilities & MPI2_IOCFACTS_CAPABILITY_TLR)
sc->control_TLR = TRUE;
+ if (sc->facts->IOCCapabilities &
+ MPI26_IOCFACTS_CAPABILITY_ATOMIC_REQ)
+ sc->atomic_desc_capable = TRUE;
/*
* Size the queues. Since the reply queues always need one free
@@ -501,6 +508,7 @@
TAILQ_INIT(&sc->req_list);
TAILQ_INIT(&sc->high_priority_req_list);
TAILQ_INIT(&sc->chain_list);
+ TAILQ_INIT(&sc->prp_page_list);
TAILQ_INIT(&sc->tm_list);
}
@@ -634,6 +642,14 @@
if (sc->sense_dmat != NULL)
bus_dma_tag_destroy(sc->sense_dmat);
+ if (sc->prp_page_busaddr != 0)
+ bus_dmamap_unload(sc->prp_page_dmat, sc->prp_page_map);
+ if (sc->prp_pages != NULL)
+ bus_dmamem_free(sc->prp_page_dmat, sc->prp_pages,
+ sc->prp_page_map);
+ if (sc->prp_page_dmat != NULL)
+ bus_dma_tag_destroy(sc->prp_page_dmat);
+
if (sc->reply_busaddr != 0)
bus_dmamap_unload(sc->reply_dmat, sc->reply_map);
if (sc->reply_frames != NULL)
@@ -651,6 +667,8 @@
if (sc->chains != NULL)
free(sc->chains, M_MPR);
+ if (sc->prps != NULL)
+ free(sc->prps, M_MPR);
if (sc->commands != NULL) {
for (i = 1; i < sc->num_reqs; i++) {
cm = &sc->commands[i];
@@ -804,7 +822,7 @@
count++;
} while (--cntdn);
- out:
+out:
mpr_dprint(sc, MPR_FAULT, "%s: failed due to timeout count(%d), "
"int_status(%x)!\n", __func__, count, int_status);
return (ETIMEDOUT);
@@ -959,7 +977,7 @@
static void
mpr_enqueue_request(struct mpr_softc *sc, struct mpr_command *cm)
{
- reply_descriptor rd;
+ request_descriptor rd;
MPR_FUNCTRACE(sc);
mpr_dprint(sc, MPR_TRACE, "SMID %u cm %p ccb %p\n",
@@ -972,14 +990,19 @@
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);
+ if (sc->atomic_desc_capable) {
+ rd.u.low = cm->cm_desc.Words.Low;
+ mpr_regwrite(sc, MPI26_ATOMIC_REQUEST_DESCRIPTOR_POST_OFFSET,
+ rd.u.low);
+ } else {
+ rd.u.low = cm->cm_desc.Words.Low;
+ rd.u.high = cm->cm_desc.Words.High;
+ rd.word = htole64(rd.word);
+ mpr_regwrite(sc, MPI2_REQUEST_DESCRIPTOR_POST_LOW_OFFSET,
+ rd.u.low);
+ mpr_regwrite(sc, MPI2_REQUEST_DESCRIPTOR_POST_HIGH_OFFSET,
+ rd.u.high);
+ }
}
/*
@@ -1047,6 +1070,7 @@
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);
+ init.HostPageSize = HOST_PAGE_SIZE_4K;
error = mpr_request_sync(sc, &init, &reply, req_sz, reply_sz, 5);
if ((reply.IOCStatus & MPI2_IOCSTATUS_MASK) != MPI2_IOCSTATUS_SUCCESS)
@@ -1276,6 +1300,16 @@
sc->chain_free_lowwater++;
}
+ /*
+ * Allocate NVMe PRP Pages for NVMe SGL support only if the FW supports
+ * these devices.
+ */
+ if ((sc->facts->MsgVersion >= MPI2_VERSION_02_06) &&
+ (sc->facts->ProtocolFlags & MPI2_IOCFACTS_PROTOCOL_NVME_DEVICES)) {
+ if (mpr_alloc_nvme_prp_pages(sc) == ENOMEM)
+ return (ENOMEM);
+ }
+
/* XXX Need to pick a more precise value */
nsegs = (MAXPHYS / PAGE_SIZE) + 1;
if (bus_dma_tag_create( sc->mpr_parent_dmat, /* parent */
@@ -1316,15 +1350,17 @@
cm->cm_desc.Default.SMID = i;
cm->cm_sc = sc;
TAILQ_INIT(&cm->cm_chain_list);
+ TAILQ_INIT(&cm->cm_prp_page_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 (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 {
+ } else {
panic("failed to allocate command %d\n", i);
sc->num_reqs = i;
break;
@@ -1334,6 +1370,83 @@
return (0);
}
+/*
+ * Allocate contiguous buffers for PCIe NVMe devices for building native PRPs,
+ * which are scatter/gather lists for NVMe devices.
+ *
+ * This buffer must be contiguous due to the nature of how NVMe PRPs are built
+ * and translated by FW.
+ *
+ * returns ENOMEM if memory could not be allocated, otherwise returns 0.
+ */
+static int
+mpr_alloc_nvme_prp_pages(struct mpr_softc *sc)
+{
+ int PRPs_per_page, PRPs_required, pages_required;
+ int rsize, i;
+ struct mpr_prp_page *prp_page;
+
+ /*
+ * Assuming a MAX_IO_SIZE of 1MB and a PAGE_SIZE of 4k, the max number
+ * of PRPs (NVMe's Scatter/Gather Element) needed per I/O is:
+ * MAX_IO_SIZE / PAGE_SIZE = 256
+ *
+ * 1 PRP entry in main frame for PRP list pointer still leaves 255 PRPs
+ * required for the remainder of the 1MB I/O. 512 PRPs can fit into one
+ * page (4096 / 8 = 512), so only one page is required for each I/O.
+ *
+ * Each of these buffers will need to be contiguous. For simplicity,
+ * only one buffer is allocated here, which has all of the space
+ * required for the NVMe Queue Depth. If there are problems allocating
+ * this one buffer, this function will need to change to allocate
+ * individual, contiguous NVME_QDEPTH buffers.
+ *
+ */
+ PRPs_required = MPR_MAX_IO_SIZE / PAGE_SIZE;
+ PRPs_per_page = (PAGE_SIZE / PRP_ENTRY_SIZE) - 1;
+ pages_required = (PRPs_required / PRPs_per_page) + 1;
+
+ sc->prp_buffer_size = PAGE_SIZE * pages_required;
+ rsize = sc->prp_buffer_size * NVME_QDEPTH;
+ 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->prp_page_dmat)) {
+ device_printf(sc->mpr_dev, "Cannot allocate NVMe PRP DMA "
+ "tag\n");
+ return (ENOMEM);
+ }
+ if (bus_dmamem_alloc(sc->prp_page_dmat, (void **)&sc->prp_pages,
+ BUS_DMA_NOWAIT, &sc->prp_page_map)) {
+ device_printf(sc->mpr_dev, "Cannot allocate NVMe PRP memory\n");
+ return (ENOMEM);
+ }
+ bzero(sc->prp_pages, rsize);
+ bus_dmamap_load(sc->prp_page_dmat, sc->prp_page_map, sc->prp_pages,
+ rsize, mpr_memaddr_cb, &sc->prp_page_busaddr, 0);
+
+ sc->prps = malloc(sizeof(struct mpr_prp_page) * NVME_QDEPTH, M_MPR,
+ M_WAITOK | M_ZERO);
+ for (i = 0; i < NVME_QDEPTH; i++) {
+ prp_page = &sc->prps[i];
+ prp_page->prp_page = (uint64_t *)(sc->prp_pages +
+ i * sc->prp_buffer_size);
+ prp_page->prp_page_busaddr = (uint64_t)(sc->prp_page_busaddr +
+ i * sc->prp_buffer_size);
+ mpr_free_prp_page(sc, prp_page);
+ sc->prp_pages_free_lowwater++;
+ }
+
+ return (0);
+}
+
static int
mpr_init_queues(struct mpr_softc *sc)
{
@@ -1352,8 +1465,10 @@
/*
* 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);
+ 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);
@@ -1520,6 +1635,18 @@
SYSCTL_ADD_INT(sysctl_ctx, SYSCTL_CHILDREN(sysctl_tree),
OID_AUTO, "use_phy_num", CTLFLAG_RD, &sc->use_phynum, 0,
"Use the phy number for enumeration");
+
+ SYSCTL_ADD_INT(sysctl_ctx, SYSCTL_CHILDREN(sysctl_tree),
+ OID_AUTO, "prp_pages_free", CTLFLAG_RD,
+ &sc->prp_pages_free, 0, "number of free PRP pages");
+
+ SYSCTL_ADD_INT(sysctl_ctx, SYSCTL_CHILDREN(sysctl_tree),
+ OID_AUTO, "prp_pages_free_lowwater", CTLFLAG_RD,
+ &sc->prp_pages_free_lowwater, 0,"lowest number of free PRP pages");
+
+ SYSCTL_ADD_UQUAD(sysctl_ctx, SYSCTL_CHILDREN(sysctl_tree),
+ OID_AUTO, "prp_page_alloc_fail", CTLFLAG_RD,
+ &sc->prp_page_alloc_fail, "PRP page allocation failures");
}
int
@@ -1912,6 +2039,7 @@
switch (flags) {
case MPI2_RPY_DESCRIPT_FLAGS_SCSI_IO_SUCCESS:
case MPI25_RPY_DESCRIPT_FLAGS_FAST_PATH_SCSI_IO_SUCCESS:
+ case MPI26_RPY_DESCRIPT_FLAGS_PCIE_ENCAPSULATED_SUCCESS:
cm = &sc->commands[le16toh(desc->SCSIIOSuccess.SMID)];
cm->cm_reply = NULL;
break;
@@ -2200,6 +2328,519 @@
return (mpr_update_events(sc, NULL, NULL));
}
+/**
+* mpr_build_nvme_prp - This function is called for NVMe end devices to build a
+* native SGL (NVMe PRP). The native SGL is built starting in the first PRP entry
+* of the NVMe message (PRP1). If the data buffer is small enough to be described
+* entirely using PRP1, then PRP2 is not used. If needed, PRP2 is used to
+* describe a larger data buffer. If the data buffer is too large to describe
+* using the two PRP entriess inside the NVMe message, then PRP1 describes the
+* first data memory segment, and PRP2 contains a pointer to a PRP list located
+* elsewhere in memory to describe the remaining data memory segments. The PRP
+* list will be contiguous.
+
+* The native SGL for NVMe devices is a Physical Region Page (PRP). A PRP
+* consists of a list of PRP entries to describe a number of noncontigous
+* physical memory segments as a single memory buffer, just as a SGL does. Note
+* however, that this function is only used by the IOCTL call, so the memory
+* given will be guaranteed to be contiguous. There is no need to translate
+* non-contiguous SGL into a PRP in this case. All PRPs will describe contiguous
+* space that is one page size each.
+*
+* Each NVMe message contains two PRP entries. The first (PRP1) either contains
+* a PRP list pointer or a PRP element, depending upon the command. PRP2 contains
+* the second PRP element if the memory being described fits within 2 PRP
+* entries, or a PRP list pointer if the PRP spans more than two entries.
+*
+* A PRP list pointer contains the address of a PRP list, structured as a linear
+* array of PRP entries. Each PRP entry in this list describes a segment of
+* physical memory.
+*
+* Each 64-bit PRP entry comprises an address and an offset field. The address
+* always points to the beginning of a PAGE_SIZE physical memory page, and the
+* offset describes where within that page the memory segment begins. Only the
+* first element in a PRP list may contain a non-zero offest, implying that all
+* memory segments following the first begin at the start of a PAGE_SIZE page.
+*
+* Each PRP element normally describes a chunck of PAGE_SIZE physical memory,
+* with exceptions for the first and last elements in the list. If the memory
+* being described by the list begins at a non-zero offset within the first page,
+* then the first PRP element will contain a non-zero offset indicating where the
+* region begins within the page. The last memory segment may end before the end
+* of the PAGE_SIZE segment, depending upon the overall size of the memory being
+* described by the PRP list.
+*
+* Since PRP entries lack any indication of size, the overall data buffer length
+* is used to determine where the end of the data memory buffer is located, and
+* how many PRP entries are required to describe it.
+*
+* Returns nothing.
+*/
+void
+mpr_build_nvme_prp(struct mpr_softc *sc, struct mpr_command *cm,
+ Mpi26NVMeEncapsulatedRequest_t *nvme_encap_request, void *data,
+ uint32_t data_in_sz, uint32_t data_out_sz)
+{
+ int prp_size = PRP_ENTRY_SIZE;
+ uint64_t *prp_entry, *prp1_entry, *prp2_entry;
+ uint64_t *prp_entry_phys, *prp_page, *prp_page_phys;
+ uint32_t offset, entry_len, page_mask_result, page_mask;
+ bus_addr_t paddr;
+ size_t length;
+ struct mpr_prp_page *prp_page_info = NULL;
+
+ /*
+ * Not all commands require a data transfer. If no data, just return
+ * without constructing any PRP.
+ */
+ if (!data_in_sz && !data_out_sz)
+ return;
+
+ /*
+ * Set pointers to PRP1 and PRP2, which are in the NVMe command. PRP1 is
+ * located at a 24 byte offset from the start of the NVMe command. Then
+ * set the current PRP entry pointer to PRP1.
+ */
+ prp1_entry = (uint64_t *)(nvme_encap_request->NVMe_Command +
+ NVME_CMD_PRP1_OFFSET);
+ prp2_entry = (uint64_t *)(nvme_encap_request->NVMe_Command +
+ NVME_CMD_PRP2_OFFSET);
+ prp_entry = prp1_entry;
+
+ /*
+ * For the PRP entries, use the specially allocated buffer of
+ * contiguous memory. PRP Page allocation failures should not happen
+ * because there should be enough PRP page buffers to account for the
+ * possible NVMe QDepth.
+ */
+ prp_page_info = mpr_alloc_prp_page(sc);
+ KASSERT(prp_page_info != NULL, ("%s: There are no PRP Pages left to be "
+ "used for building a native NVMe SGL.\n", __func__));
+ prp_page = (uint64_t *)prp_page_info->prp_page;
+ prp_page_phys = (uint64_t *)(uintptr_t)prp_page_info->prp_page_busaddr;
+
+ /*
+ * Insert the allocated PRP page into the command's PRP page list. This
+ * will be freed when the command is freed.
+ */
+ TAILQ_INSERT_TAIL(&cm->cm_prp_page_list, prp_page_info, prp_page_link);
+
+ /*
+ * Check if we are within 1 entry of a page boundary we don't want our
+ * first entry to be a PRP List entry.
+ */
+ page_mask = PAGE_SIZE - 1;
+ page_mask_result = (uintptr_t)((uint8_t *)prp_page + prp_size) &
+ page_mask;
+ if (!page_mask_result)
+ {
+ /* Bump up to next page boundary. */
+ prp_page = (uint64_t *)((uint8_t *)prp_page + prp_size);
+ prp_page_phys = (uint64_t *)((uint8_t *)prp_page_phys +
+ prp_size);
+ }
+
+ /*
+ * Set PRP physical pointer, which initially points to the current PRP
+ * DMA memory page.
+ */
+ prp_entry_phys = prp_page_phys;
+
+ /* Get physical address and length of the data buffer. */
+ paddr = (bus_addr_t)data;
+ if (data_in_sz)
+ length = data_in_sz;
+ else
+ length = data_out_sz;
+
+ /* Loop while the length is not zero. */
+ while (length)
+ {
+ /*
+ * Check if we need to put a list pointer here if we are at page
+ * boundary - prp_size (8 bytes).
+ */
+ page_mask_result = (uintptr_t)((uint8_t *)prp_entry_phys +
+ prp_size) & page_mask;
+ if (!page_mask_result)
+ {
+ /*
+ * This is the last entry in a PRP List, so we need to
+ * put a PRP list pointer here. What this does is:
+ * - bump the current memory pointer to the next
+ * address, which will be the next full page.
+ * - set the PRP Entry to point to that page. This is
+ * now the PRP List pointer.
+ * - bump the PRP Entry pointer the start of the next
+ * page. Since all of this PRP memory is contiguous,
+ * no need to get a new page - it's just the next
+ * address.
+ */
+ prp_entry_phys++;
+ *prp_entry =
+ htole64((uint64_t)(uintptr_t)prp_entry_phys);
+ prp_entry++;
+ }
+
+ /* Need to handle if entry will be part of a page. */
+ offset = (uint32_t)paddr & page_mask;
+ entry_len = PAGE_SIZE - offset;
+
+ if (prp_entry == prp1_entry)
+ {
+ /*
+ * Must fill in the first PRP pointer (PRP1) before
+ * moving on.
+ */
+ *prp1_entry = htole64((uint64_t)paddr);
+
+ /*
+ * Now point to the second PRP entry within the
+ * command (PRP2).
+ */
+ prp_entry = prp2_entry;
+ }
+ else if (prp_entry == prp2_entry)
+ {
+ /*
+ * Should the PRP2 entry be a PRP List pointer or just a
+ * regular PRP pointer? If there is more than one more
+ * page of data, must use a PRP List pointer.
+ */
+ if (length > PAGE_SIZE)
+ {
+ /*
+ * PRP2 will contain a PRP List pointer because
+ * more PRP's are needed with this command. The
+ * list will start at the beginning of the
+ * contiguous buffer.
+ */
+ *prp2_entry =
+ htole64(
+ (uint64_t)(uintptr_t)prp_entry_phys);
+
+ /*
+ * The next PRP Entry will be the start of the
+ * first PRP List.
+ */
+ prp_entry = prp_page;
+ }
+ else
+ {
+ /*
+ * After this, the PRP Entries are complete.
+ * This command uses 2 PRP's and no PRP list.
+ */
+ *prp2_entry = htole64((uint64_t)paddr);
+ }
+ }
+ else
+ {
+ /*
+ * Put entry in list and bump the addresses.
+ *
+ * After PRP1 and PRP2 are filled in, this will fill in
+ * all remaining PRP entries in a PRP List, one per each
+ * time through the loop.
+ */
+ *prp_entry = htole64((uint64_t)paddr);
+ prp_entry++;
+ prp_entry_phys++;
+ }
+
+ /*
+ * Bump the phys address of the command's data buffer by the
+ * entry_len.
+ */
+ paddr += entry_len;
+
+ /* Decrement length accounting for last partial page. */
+ if (entry_len > length)
+ length = 0;
+ else
+ length -= entry_len;
+ }
+}
+
+/*
+ * mpr_check_pcie_native_sgl - This function is called for PCIe end devices to
+ * determine if the driver needs to build a native SGL. If so, that native SGL
+ * is built in the contiguous buffers allocated especially for PCIe SGL
+ * creation. If the driver will not build a native SGL, return TRUE and a
+ * normal IEEE SGL will be built. Currently this routine supports NVMe devices
+ * only.
+ *
+ * Returns FALSE (0) if native SGL was built, TRUE (1) if no SGL was built.
+ */
+static int
+mpr_check_pcie_native_sgl(struct mpr_softc *sc, struct mpr_command *cm,
+ bus_dma_segment_t *segs, int segs_left)
+{
+ uint32_t i, sge_dwords, length, offset, entry_len;
+ uint32_t num_entries, buff_len = 0, sges_in_segment;
+ uint32_t page_mask, page_mask_result, *curr_buff;
+ uint32_t *ptr_sgl, *ptr_first_sgl, first_page_offset;
+ uint32_t first_page_data_size, end_residual;
+ uint64_t *msg_phys;
+ bus_addr_t paddr;
+ int build_native_sgl = 0, first_prp_entry;
+ int prp_size = PRP_ENTRY_SIZE;
+ Mpi25IeeeSgeChain64_t *main_chain_element = NULL;
+ struct mpr_prp_page *prp_page_info = NULL;
+
+ mpr_dprint(sc, MPR_TRACE, "%s\n", __func__);
+
+ /*
+ * Add up the sizes of each segment length to get the total transfer
+ * size, which will be checked against the Maximum Data Transfer Size.
+ * If the data transfer length exceeds the MDTS for this device, just
+ * return 1 so a normal IEEE SGL will be built. F/W will break the I/O
+ * up into multiple I/O's. [nvme_mdts = 0 means unlimited]
+ */
+ for (i = 0; i < segs_left; i++)
+ buff_len += htole32(segs[i].ds_len);
+ if ((cm->cm_targ->MDTS > 0) && (buff_len > cm->cm_targ->MDTS))
+ return 1;
+
+ /* Create page_mask (to get offset within page) */
+ page_mask = PAGE_SIZE - 1;
+
+ /*
+ * Check if the number of elements exceeds the max number that can be
+ * put in the main message frame (H/W can only translate an SGL that
+ * is contained entirely in the main message frame).
+ */
+ sges_in_segment = (sc->facts->IOCRequestFrameSize -
+ offsetof(Mpi25SCSIIORequest_t, SGL)) / sizeof(MPI25_SGE_IO_UNION);
+ if (segs_left > sges_in_segment)
+ build_native_sgl = 1;
+ else
+ {
+ /*
+ * NVMe uses one PRP for each physical page (or part of physical
+ * page).
+ * if 4 pages or less then IEEE is OK
+ * if > 5 pages then we need to build a native SGL
+ * if > 4 and <= 5 pages, then check the physical address of
+ * the first SG entry, then if this first size in the page
+ * is >= the residual beyond 4 pages then use IEEE,
+ * otherwise use native SGL
+ */
+ if (buff_len > (PAGE_SIZE * 5))
+ build_native_sgl = 1;
+ else if ((buff_len > (PAGE_SIZE * 4)) &&
+ (buff_len <= (PAGE_SIZE * 5)) )
+ {
+ msg_phys = (uint64_t *)segs[0].ds_addr;
+ first_page_offset =
+ ((uint32_t)(uint64_t)(uintptr_t)msg_phys &
+ page_mask);
+ first_page_data_size = PAGE_SIZE - first_page_offset;
+ end_residual = buff_len % PAGE_SIZE;
+
+ /*
+ * If offset into first page pushes the end of the data
+ * beyond end of the 5th page, we need the extra PRP
+ * list.
+ */
+ if (first_page_data_size < end_residual)
+ build_native_sgl = 1;
+
+ /*
+ * Check if first SG entry size is < residual beyond 4
+ * pages.
+ */
+ if (htole32(segs[0].ds_len) <
+ (buff_len - (PAGE_SIZE * 4)))
+ build_native_sgl = 1;
+ }
+ }
+
+ /* check if native SGL is needed */
+ if (!build_native_sgl)
+ return 1;
+
+ /*
+ * Native SGL is needed.
+ * Put a chain element in main message frame that points to the first
+ * chain buffer.
+ *
+ * NOTE: The ChainOffset field must be 0 when using a chain pointer to
+ * a native SGL.
+ */
+
+ /* Set main message chain element pointer */
+ main_chain_element = (pMpi25IeeeSgeChain64_t)cm->cm_sge;
+
+ /*
+ * For NVMe the chain element needs to be the 2nd SGL entry in the main
+ * message.
+ */
+ main_chain_element = (Mpi25IeeeSgeChain64_t *)
+ ((uint8_t *)main_chain_element + sizeof(MPI25_IEEE_SGE_CHAIN64));
+
+ /*
+ * For the PRP entries, use the specially allocated buffer of
+ * contiguous memory. PRP Page allocation failures should not happen
+ * because there should be enough PRP page buffers to account for the
+ * possible NVMe QDepth.
+ */
+ prp_page_info = mpr_alloc_prp_page(sc);
+ KASSERT(prp_page_info != NULL, ("%s: There are no PRP Pages left to be "
+ "used for building a native NVMe SGL.\n", __func__));
+ curr_buff = (uint32_t *)prp_page_info->prp_page;
+ msg_phys = (uint64_t *)(uintptr_t)prp_page_info->prp_page_busaddr;
+
+ /*
+ * Insert the allocated PRP page into the command's PRP page list. This
+ * will be freed when the command is freed.
+ */
+ TAILQ_INSERT_TAIL(&cm->cm_prp_page_list, prp_page_info, prp_page_link);
+
+ /*
+ * Check if we are within 1 entry of a page boundary we don't want our
+ * first entry to be a PRP List entry.
+ */
+ page_mask_result = (uintptr_t)((uint8_t *)curr_buff + prp_size) &
+ page_mask;
+ if (!page_mask_result) {
+ /* Bump up to next page boundary. */
+ curr_buff = (uint32_t *)((uint8_t *)curr_buff + prp_size);
+ msg_phys = (uint64_t *)((uint8_t *)msg_phys + prp_size);
+ }
+
+ /* Fill in the chain element and make it an NVMe segment type. */
+ main_chain_element->Address.High =
+ htole32((uint32_t)((uint64_t)(uintptr_t)msg_phys >> 32));
+ main_chain_element->Address.Low =
+ htole32((uint32_t)(uintptr_t)msg_phys);
+ main_chain_element->NextChainOffset = 0;
+ main_chain_element->Flags = MPI2_IEEE_SGE_FLAGS_CHAIN_ELEMENT |
+ MPI2_IEEE_SGE_FLAGS_SYSTEM_ADDR |
+ MPI26_IEEE_SGE_FLAGS_NSF_NVME_PRP;
+
+ /* Set SGL pointer to start of contiguous PCIe buffer. */
+ ptr_sgl = curr_buff;
+ sge_dwords = 2;
+ num_entries = 0;
+
+ /*
+ * NVMe has a very convoluted PRP format. One PRP is required for each
+ * page or partial page. We need to split up OS SG entries if they are
+ * longer than one page or cross a page boundary. We also have to insert
+ * a PRP list pointer entry as the last entry in each physical page of
+ * the PRP list.
+ *
+ * NOTE: The first PRP "entry" is actually placed in the first SGL entry
+ * in the main message in IEEE 64 format. The 2nd entry in the main
+ * message is the chain element, and the rest of the PRP entries are
+ * built in the contiguous PCIe buffer.
+ */
+ first_prp_entry = 1;
+ ptr_first_sgl = (uint32_t *)cm->cm_sge;
+
+ for (i = 0; i < segs_left; i++) {
+ /* Get physical address and length of this SG entry. */
+ paddr = segs[i].ds_addr;
+ length = segs[i].ds_len;
+
+ /*
+ * Check whether a given SGE buffer lies on a non-PAGED
+ * boundary if this is not the first page. If so, this is not
+ * expected so have FW build the SGL.
+ */
+ if (i) {
+ if ((uint32_t)paddr & page_mask) {
+ mpr_dprint(sc, MPR_ERROR, "Unaligned SGE while "
+ "building NVMe PRPs, low address is 0x%x\n",
+ (uint32_t)paddr);
+ return 1;
+ }
+ }
+
+ /* Apart from last SGE, if any other SGE boundary is not page
+ * aligned then it means that hole exists. Existence of hole
+ * leads to data corruption. So fallback to IEEE SGEs.
+ */
+ if (i != (segs_left - 1)) {
+ if (((uint32_t)paddr + length) & page_mask) {
+ mpr_dprint(sc, MPR_ERROR, "Unaligned SGE "
+ "boundary while building NVMe PRPs, low "
+ "address: 0x%x and length: %u\n",
+ (uint32_t)paddr, length);
+ return 1;
+ }
+ }
+
+ /* Loop while the length is not zero. */
+ while (length) {
+ /*
+ * Check if we need to put a list pointer here if we are
+ * at page boundary - prp_size.
+ */
+ page_mask_result = (uintptr_t)((uint8_t *)ptr_sgl +
+ prp_size) & page_mask;
+ if (!page_mask_result) {
+ /*
+ * Need to put a PRP list pointer here.
+ */
+ msg_phys = (uint64_t *)((uint8_t *)msg_phys +
+ prp_size);
+ *ptr_sgl = htole32((uintptr_t)msg_phys);
+ *(ptr_sgl+1) = htole32((uint64_t)(uintptr_t)
+ msg_phys >> 32);
+ ptr_sgl += sge_dwords;
+ num_entries++;
+ }
+
+ /* Need to handle if entry will be part of a page. */
+ offset = (uint32_t)paddr & page_mask;
+ entry_len = PAGE_SIZE - offset;
+ if (first_prp_entry) {
+ /*
+ * Put IEEE entry in first SGE in main message.
+ * (Simple element, System addr, not end of
+ * list.)
+ */
+ *ptr_first_sgl = htole32((uint32_t)paddr);
+ *(ptr_first_sgl + 1) =
+ htole32((uint32_t)((uint64_t)paddr >> 32));
+ *(ptr_first_sgl + 2) = htole32(entry_len);
+ *(ptr_first_sgl + 3) = 0;
+
+ /* No longer the first PRP entry. */
+ first_prp_entry = 0;
+ } else {
+ /* Put entry in list. */
+ *ptr_sgl = htole32((uint32_t)paddr);
+ *(ptr_sgl + 1) =
+ htole32((uint32_t)((uint64_t)paddr >> 32));
+
+ /* Bump ptr_sgl, msg_phys, and num_entries. */
+ ptr_sgl += sge_dwords;
+ msg_phys = (uint64_t *)((uint8_t *)msg_phys +
+ prp_size);
+ num_entries++;
+ }
+
+ /* Bump the phys address by the entry_len. */
+ paddr += entry_len;
+
+ /* Decrement length accounting for last partial page. */
+ if (entry_len > length)
+ length = 0;
+ else
+ length -= entry_len;
+ }
+ }
+
+ /* Set chain element Length. */
+ main_chain_element->Length = htole32(num_entries * prp_size);
+
+ /* Return 0, indicating we built a native SGL. */
+ return 0;
+}
+
/*
* 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
@@ -2540,6 +3181,13 @@
} else
dir = BUS_DMASYNC_PREREAD;
+ /* Check if a native SG list is needed for an NVMe PCIe device. */
+ if (cm->cm_targ && cm->cm_targ->is_nvme &&
+ mpr_check_pcie_native_sgl(sc, cm, segs, nsegs) == 0) {
+ /* A native SG list was built, skip to end. */
+ goto out;
+ }
+
for (i = 0; i < nsegs; i++) {
if ((cm->cm_flags & MPR_CM_FLAGS_SMP_PASS) && (i != 0)) {
sflags &= ~MPI2_SGE_FLAGS_DIRECTION;
@@ -2557,6 +3205,7 @@
}
}
+out:
bus_dmamap_sync(sc->buffer_dmat, cm->cm_dmamap, dir);
mpr_enqueue_request(sc, cm);
Index: sys/dev/mpr/mpr_config.c
===================================================================
--- sys/dev/mpr/mpr_config.c
+++ sys/dev/mpr/mpr_config.c
@@ -51,6 +51,7 @@
#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_pci.h>
#include <dev/mpr/mpi/mpi2_cnfg.h>
#include <dev/mpr/mpi/mpi2_init.h>
#include <dev/mpr/mpi/mpi2_tool.h>
@@ -91,7 +92,7 @@
request->Action = MPI2_CONFIG_ACTION_PAGE_HEADER;
request->Header.PageType = MPI2_CONFIG_PAGETYPE_IOC;
request->Header.PageNumber = 8;
- request->Header.PageVersion = MPI2_IOCPAGE8_PAGEVERSION;
+ request->Header.PageLength = request->Header.PageVersion = 0;
cm->cm_desc.Default.RequestFlags = MPI2_REQ_DESCRIPT_FLAGS_DEFAULT_TYPE;
cm->cm_data = NULL;
error = mpr_wait_command(sc, cm, 60, CAN_SLEEP);
@@ -137,7 +138,7 @@
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.PageVersion = mpi_reply->Header.PageVersion;
request->Header.PageLength = mpi_reply->Header.PageLength;
cm->cm_length = le16toh(mpi_reply->Header.PageLength) * 4;
cm->cm_sge = &request->PageBufferSGE;
@@ -221,7 +222,7 @@
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;
+ request->Header.PageLength = request->Header.PageVersion = 0;
cm->cm_desc.Default.RequestFlags = MPI2_REQ_DESCRIPT_FLAGS_DEFAULT_TYPE;
cm->cm_data = NULL;
error = mpr_wait_command(sc, cm, 60, CAN_SLEEP);
@@ -267,7 +268,7 @@
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.PageVersion = mpi_reply->Header.PageVersion;
request->Header.PageLength = mpi_reply->Header.PageLength;
cm->cm_length = le16toh(mpi_reply->Header.PageLength) * 4;
cm->cm_sge = &request->PageBufferSGE;
@@ -387,7 +388,7 @@
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 = request->Header.PageVersion = 0;
request->PageAddress = sc->max_dpm_entries <<
MPI2_DPM_PGAD_ENTRY_COUNT_SHIFT;
cm->cm_desc.Default.RequestFlags = MPI2_REQ_DESCRIPT_FLAGS_DEFAULT_TYPE;
@@ -436,7 +437,7 @@
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->Header.PageVersion = mpi_reply->Header.PageVersion;
request->PageAddress = sc->max_dpm_entries <<
MPI2_DPM_PGAD_ENTRY_COUNT_SHIFT;
request->ExtPageLength = mpi_reply->ExtPageLength;
@@ -522,7 +523,7 @@
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 = request->Header.PageVersion = 0;
/* We can remove below two lines ????*/
request->PageAddress = 1 << MPI2_DPM_PGAD_ENTRY_COUNT_SHIFT;
request->PageAddress |= htole16(entry_idx);
@@ -572,7 +573,7 @@
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->Header.PageVersion = mpi_reply->Header.PageVersion;
request->ExtPageLength = mpi_reply->ExtPageLength;
request->PageAddress = 1 << MPI2_DPM_PGAD_ENTRY_COUNT_SHIFT;
request->PageAddress |= htole16(entry_idx);
@@ -660,7 +661,7 @@
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 = request->Header.PageVersion = 0;
cm->cm_desc.Default.RequestFlags = MPI2_REQ_DESCRIPT_FLAGS_DEFAULT_TYPE;
cm->cm_data = NULL;
error = mpr_wait_command(sc, cm, 60, CAN_SLEEP);
@@ -707,7 +708,7 @@
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->Header.PageVersion = mpi_reply->Header.PageVersion;
request->ExtPageLength = mpi_reply->ExtPageLength;
request->PageAddress = htole32(form | handle);
cm->cm_length = le16toh(mpi_reply->ExtPageLength) * 4;
@@ -759,6 +760,276 @@
}
/**
+ * mpr_config_get_pcie_device_pg0 - obtain PCIe 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_pcie_device_pg0(struct mpr_softc *sc, Mpi2ConfigReply_t
+ *mpi_reply, Mpi26PCIeDevicePage0_t *config_page, u32 form, u16 handle)
+{
+ MPI2_CONFIG_REQUEST *request;
+ MPI2_CONFIG_REPLY *reply;
+ struct mpr_command *cm;
+ Mpi26PCIeDevicePage0_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_PCIE_DEVICE;
+ request->Header.PageNumber = 0;
+ request->ExtPageLength = request->Header.PageVersion = 0;
+ 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_PCIE_DEVICE;
+ request->Header.PageNumber = 0;
+ request->Header.PageVersion = mpi_reply->Header.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(Mpi26PCIeDevicePage0_t)));
+out:
+ free(page, M_MPR);
+ if (cm)
+ mpr_free_command(sc, cm);
+ return (error);
+}
+
+/**
+ * mpr_config_get_pcie_device_pg2 - obtain PCIe device page 2
+ * @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_pcie_device_pg2(struct mpr_softc *sc, Mpi2ConfigReply_t
+ *mpi_reply, Mpi26PCIeDevicePage2_t *config_page, u32 form, u16 handle)
+{
+ MPI2_CONFIG_REQUEST *request;
+ MPI2_CONFIG_REPLY *reply;
+ struct mpr_command *cm;
+ Mpi26PCIeDevicePage2_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_PCIE_DEVICE;
+ request->Header.PageNumber = 2;
+ request->ExtPageLength = request->Header.PageVersion = 0;
+ 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_PCIE_DEVICE;
+ request->Header.PageNumber = 2;
+ request->Header.PageVersion = mpi_reply->Header.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(Mpi26PCIeDevicePage2_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
@@ -792,7 +1063,7 @@
request->Action = MPI2_CONFIG_ACTION_PAGE_HEADER;
request->Header.PageType = MPI2_CONFIG_PAGETYPE_BIOS;
request->Header.PageNumber = 3;
- request->Header.PageVersion = MPI2_BIOSPAGE3_PAGEVERSION;
+ request->Header.PageLength = request->Header.PageVersion = 0;
cm->cm_desc.Default.RequestFlags = MPI2_REQ_DESCRIPT_FLAGS_DEFAULT_TYPE;
cm->cm_data = NULL;
error = mpr_wait_command(sc, cm, 60, CAN_SLEEP);
@@ -838,7 +1109,7 @@
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.PageVersion = mpi_reply->Header.PageVersion;
request->Header.PageLength = mpi_reply->Header.PageLength;
cm->cm_length = le16toh(mpi_reply->Header.PageLength) * 4;
cm->cm_sge = &request->PageBufferSGE;
@@ -922,7 +1193,7 @@
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;
+ request->Header.PageLength = request->Header.PageVersion = 0;
cm->cm_desc.Default.RequestFlags = MPI2_REQ_DESCRIPT_FLAGS_DEFAULT_TYPE;
cm->cm_data = NULL;
@@ -1051,7 +1322,7 @@
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;
+ request->Header.PageLength = request->Header.PageVersion = 0;
cm->cm_desc.Default.RequestFlags = MPI2_REQ_DESCRIPT_FLAGS_DEFAULT_TYPE;
cm->cm_data = NULL;
error = mpr_wait_command(sc, cm, 60, CAN_SLEEP);
@@ -1208,7 +1479,7 @@
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;
+ request->Header.PageLength = request->Header.PageVersion = 0;
cm->cm_desc.Default.RequestFlags = MPI2_REQ_DESCRIPT_FLAGS_DEFAULT_TYPE;
cm->cm_data = NULL;
Index: sys/dev/mpr/mpr_mapping.h
===================================================================
--- sys/dev/mpr/mpr_mapping.h
+++ sys/dev/mpr/mpr_mapping.h
@@ -53,9 +53,36 @@
};
/**
- * struct _map_topology_change - entries to be removed from mapping table
- * @dpm_entry_num: index of this device in device persistent map table
+ * struct _map_port_change - PCIe Port entries received in PCIe Topology change
+ * list event
+ * @physical_id: WWID of the device attached to the associated port
+ * @device_info: bitfield provides detailed info about the device
+ * @MDTS: Maximum Data Transfer Size for 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_port_change {
+ uint64_t physical_id;
+ uint32_t device_info;
+ uint32_t MDTS;
+ uint16_t dev_handle;
+ uint16_t slot;
+ uint8_t reason;
+ uint8_t is_processed;
+ uint8_t reserved[2];
+};
+
+/**
+ * struct _map_topology_change - SAS/SATA entries to be removed from mapping
+ * table
+ * @enc_handle: enclosure handle where this device is located
+ * @exp_handle: expander handle where this device is located
+ * @num_entries: number of entries in the SAS Topology Change List event
+ * @start_phy_num: PHY number of the first PHY in the event data
+ * @num_phys: number of PHYs in the expander where this device is located
+ * @exp_status: status for the expander where this device is located
+ * @phy_details: more details about each PHY in the event data
*/
struct _map_topology_change {
uint16_t enc_handle;
@@ -67,6 +94,26 @@
struct _map_phy_change *phy_details;
};
+/**
+ * struct _map_pcie_topology_change - PCIe entries to be removed from mapping
+ * table
+ * @enc_handle: enclosure handle where this device is located
+ * @switch_dev_handle: PCIe switch device handle where this device is located
+ * @num_entries: number of entries in the PCIe Topology Change List event
+ * @start_port_num: port number of the first port in the event data
+ * @num_ports: number of ports in the PCIe switch device
+ * @switch_status: status for the PCIe switch where this device is located
+ * @port_details: more details about each Port in the event data
+ */
+struct _map_pcie_topology_change {
+ uint16_t enc_handle;
+ uint16_t switch_dev_handle;
+ uint8_t num_entries;
+ uint8_t start_port_num;
+ uint8_t num_ports;
+ uint8_t switch_status;
+ struct _map_port_change *port_details;
+};
extern int
mprsas_get_sas_address_for_sata_disk(struct mpr_softc *ioc,
Index: sys/dev/mpr/mpr_mapping.c
===================================================================
--- sys/dev/mpr/mpr_mapping.c
+++ sys/dev/mpr/mpr_mapping.c
@@ -51,6 +51,7 @@
#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_pci.h>
#include <dev/mpr/mpi/mpi2_cnfg.h>
#include <dev/mpr/mpi/mpi2_init.h>
#include <dev/mpr/mpi/mpi2_tool.h>
@@ -676,6 +677,55 @@
}
/**
+ * _mapping_inc_missing_count
+ * @sc: per adapter object
+ * @map_idx: index into the mapping table for the device that is missing
+ *
+ * Increment the missing count in the mapping table for a SAS, SATA, or PCIe
+ * device that is not responding. If Persitent Mapping is used, increment the
+ * DPM entry as well. Also, add this device to the removal table for possible
+ * removal if a new device is added.
+ *
+ * Returns nothing.
+ */
+static void
+_mapping_inc_missing_count(struct mpr_softc *sc, u32 map_idx)
+{
+ u16 ioc_pg8_flags = le16toh(sc->ioc_pg8.Flags);
+ struct dev_mapping_table *mt_entry;
+ Mpi2DriverMap0Entry_t *dpm_entry;
+
+ if (map_idx == MPR_MAPTABLE_BAD_IDX) {
+ mpr_dprint(sc, MPR_INFO, "%s: device is already removed from "
+ "mapping table\n", __func__);
+ return;
+ }
+ 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_update_missing_count - Update missing count for a device
* @sc: per adapter object
* @topo_change: Topology change event entry
@@ -689,12 +739,9 @@
_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];
@@ -704,35 +751,37 @@
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;
+ _mapping_inc_missing_count(sc, map_idx);
+ }
+}
- 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_update_pcie_missing_count - Update missing count for a PCIe device
+ * @sc: per adapter object
+ * @topo_change: Topology change event entry
+ *
+ * Search through the PCIe 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_pcie_missing_count(struct mpr_softc *sc,
+ struct _map_pcie_topology_change *topo_change)
+{
+ u8 entry;
+ struct _map_port_change *port_change;
+ u32 map_idx;
+
+ for (entry = 0; entry < topo_change->num_entries; entry++) {
+ port_change = &topo_change->port_details[entry];
+ if (!port_change->dev_handle || (port_change->reason !=
+ MPI26_EVENT_PCIE_TOPO_PS_NOT_RESPONDING))
+ continue;
+ map_idx = _mapping_get_mt_idx_from_handle(sc, port_change->
+ dev_handle);
+ port_change->is_processed = 1;
+ _mapping_inc_missing_count(sc, map_idx);
}
}
@@ -940,7 +989,7 @@
phy_change->physical_id = sas_address;
phy_change->slot = le16toh(sas_device_pg0.Slot);
- phy_change->device_info = le32toh(sas_device_pg0.DeviceInfo);
+ phy_change->device_info = device_info;
if ((ioc_pg8_flags & MPI2_IOCPAGE8_FLAGS_MASK_MAPPING_MODE) ==
MPI2_IOCPAGE8_FLAGS_ENCLOSURE_SLOT_MAPPING) {
@@ -990,12 +1039,118 @@
break;
}
}
+
+ /* Found space in enclosure for mapping entry */
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;
+ mt_entry->missing_count = 0;
+ }
+ }
+ }
+}
+
+/**
+ * _mapping_get_pcie_dev_info -get information about newly added PCIe devices
+ * @sc: per adapter object
+ * @topo_change: Topology change event entry
+ *
+ * Searches through the PCIe topology change event list and issues PCIe device
+ * pg0 requests for the newly added PCIe device. If the device is in an
+ * enclosure, search for available space in the enclosure mapping table for the
+ * device and reserve that space.
+ *
+ * Returns nothing
+ */
+static void
+_mapping_get_pcie_dev_info(struct mpr_softc *sc,
+ struct _map_pcie_topology_change *topo_change)
+{
+ u16 ioc_pg8_flags = le16toh(sc->ioc_pg8.Flags);
+ Mpi2ConfigReply_t mpi_reply;
+ Mpi26PCIeDevicePage0_t pcie_device_pg0;
+ u8 entry, enc_idx, port_idx;
+ u32 map_idx, index;
+ struct _map_port_change *port_change, *tmp_port_change;
+ uint64_t pcie_wwid;
+ struct enc_mapping_table *et_entry;
+ struct dev_mapping_table *mt_entry;
+ u8 add_code = MPI26_EVENT_PCIE_TOPO_PS_DEV_ADDED;
+
+ for (entry = 0; entry < topo_change->num_entries; entry++) {
+ port_change = &topo_change->port_details[entry];
+ if (port_change->is_processed || !port_change->dev_handle ||
+ port_change->reason != MPI26_EVENT_PCIE_TOPO_PS_DEV_ADDED)
+ continue;
+ if (mpr_config_get_pcie_device_pg0(sc, &mpi_reply,
+ &pcie_device_pg0, MPI26_PCIE_DEVICE_PGAD_FORM_HANDLE,
+ port_change->dev_handle)) {
+ port_change->is_processed = 1;
+ continue;
+ }
+
+ pcie_wwid = pcie_device_pg0.WWID.High;
+ pcie_wwid = (pcie_wwid << 32) | pcie_device_pg0.WWID.Low;
+ port_change->physical_id = pcie_wwid;
+ port_change->slot = le16toh(pcie_device_pg0.Slot);
+ port_change->device_info = le32toh(pcie_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) {
+ port_change->is_processed = 1;
+ mpr_dprint(sc, MPR_MAPPING, "%s: failed to add "
+ "the device with handle 0x%04x because the "
+ "enclosure is not in the mapping table\n",
+ __func__, port_change->dev_handle);
+ continue;
+ }
+ if (!(port_change->device_info &
+ MPI26_PCIE_DEVINFO_NVME)) {
+ port_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->switch_dev_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) {
+ port_change->is_processed = 1;
+ for (port_idx = 0; port_idx <
+ topo_change->num_entries;
+ port_idx++) {
+ tmp_port_change =
+ &topo_change->port_details
+ [port_idx];
+ if (tmp_port_change->reason ==
+ add_code)
+ tmp_port_change->
+ is_processed = 1;
+ }
+ break;
+ }
+ }
+
+ /* Found space in enclosure for mapping entry */
+ 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;
+ mt_entry->missing_count = 0;
}
}
}
@@ -1106,8 +1261,8 @@
* @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.
+ * Search through the topology change event list and update map table,
+ * enclosure table and DPM pages for the newly added devices.
*
* Returns nothing
*/
@@ -1144,10 +1299,10 @@
(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);
+ mpr_dprint(sc, MPR_ERROR, "%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];
@@ -1157,10 +1312,11 @@
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);
+ mpr_dprint(sc, MPR_INFO, "%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 -
@@ -1268,10 +1424,11 @@
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);
+ mpr_dprint(sc, MPR_INFO, "%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) {
@@ -1314,20 +1471,254 @@
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;
+ 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_add_new_pcie_device -Add the new PCIe device into mapping table
+ * @sc: per adapter object
+ * @topo_change: Topology change event entry
+ *
+ * Search through the PCIe topology change event list and update map table,
+ * enclosure table and DPM pages for the newly added devices.
+ *
+ * Returns nothing
+ */
+static void
+_mapping_add_new_pcie_device(struct mpr_softc *sc,
+ struct _map_pcie_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_port_change *port_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++) {
+ port_change = &topo_change->port_details[entry];
+ if (port_change->is_processed)
+ continue;
+ if (port_change->reason != MPI26_EVENT_PCIE_TOPO_PS_DEV_ADDED ||
+ !port_change->dev_handle) {
+ port_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) {
+ port_change->is_processed = 1;
+ mpr_dprint(sc, MPR_ERROR, "%s: failed to add "
+ "the device with handle 0x%04x because the "
+ "enclosure is not in the mapping table\n",
+ __func__, port_change->dev_handle);
+ continue;
+ }
+ et_entry = &sc->enclosure_table[enc_idx];
+ if (et_entry->start_index == MPR_MAPTABLE_BAD_IDX) {
+ port_change->is_processed = 1;
+ if (!sc->mt_full_retry) {
+ sc->mt_add_device_failed = 1;
+ continue;
+ }
+ mpr_dprint(sc, MPR_INFO, "%s: failed to add "
+ "the device with handle 0x%04x because "
+ "there is no free space available in the "
+ "mapping table\n", __func__,
+ port_change->dev_handle);
+ continue;
+ }
+ map_idx = et_entry->start_index + port_change->slot -
+ et_entry->start_slot;
+ mt_entry = &sc->mapping_table[map_idx];
+ mt_entry->physical_id = port_change->physical_id;
+ mt_entry->channel = 0;
+ mt_entry->id = map_idx;
+ mt_entry->dev_handle = port_change->dev_handle;
+ mt_entry->missing_count = 0;
+ mt_entry->dpm_entry_num = et_entry->dpm_entry_num;
+ mt_entry->device_info = port_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;
+ port_change->is_processed = 1;
+ } else {
+ port_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);
+ port_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, port_change->physical_id);
+ if (map_idx == MPR_MAPTABLE_BAD_IDX) {
+ search_idx = sc->num_rsvd_entries;
+ if (topo_change->switch_dev_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 =
+ port_change->physical_id;
+ mt_entry->channel = 0;
+ mt_entry->id = map_idx;
+ mt_entry->dev_handle = port_change->dev_handle;
+ mt_entry->missing_count = 0;
+ mt_entry->device_info =
+ port_change->device_info |
+ (MPR_DEV_RESERVED | MPR_MAP_IN_USE);
+ } else {
+ port_change->is_processed = 1;
+ if (!sc->mt_full_retry) {
+ sc->mt_add_device_failed = 1;
+ continue;
+ }
+ mpr_dprint(sc, MPR_INFO, "%s: failed to add "
+ "the device with handle 0x%04x because "
+ "there is no free space available in the "
+ "mapping table\n", __func__,
+ port_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;
+ port_change->is_processed = 1;
+ } else if (dpm_idx == MPR_DPM_BAD_IDX) {
+ port_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__,
+ port_change->dev_handle);
}
}
mt_entry->init_complete = 1;
}
- phy_change->is_processed = 1;
+ port_change->is_processed = 1;
}
if (is_removed)
_mapping_clear_removed_entries(sc);
@@ -2073,6 +2464,56 @@
}
/**
+ * mpr_mapping_pcie_topology_change_event - handle PCIe topology change events
+ * @sc: per adapter object
+ * @event_data: event data payload
+ *
+ * Returns nothing.
+ */
+void
+mpr_mapping_pcie_topology_change_event(struct mpr_softc *sc,
+ Mpi26EventDataPCIeTopologyChangeList_t *event_data)
+{
+ struct _map_pcie_topology_change topo_change;
+ struct _map_port_change *port_change;
+ Mpi26EventPCIeTopoPortEntry_t *event_port_change;
+ u8 i, num_entries;
+
+ topo_change.switch_dev_handle = le16toh(event_data->SwitchDevHandle);
+ topo_change.enc_handle = le16toh(event_data->EnclosureHandle);
+ num_entries = event_data->NumEntries;
+ topo_change.num_entries = num_entries;
+ topo_change.start_port_num = event_data->StartPortNum;
+ topo_change.num_ports = event_data->NumPorts;
+ topo_change.switch_status = event_data->SwitchStatus;
+ event_port_change = event_data->PortEntry;
+ topo_change.port_details = NULL;
+
+ if (!num_entries)
+ goto out;
+ port_change = malloc(sizeof(struct _map_port_change) * num_entries,
+ M_MPR, M_NOWAIT|M_ZERO);
+ topo_change.port_details = port_change;
+ if (!port_change)
+ goto out;
+ for (i = 0; i < num_entries; i++, event_port_change++, port_change++) {
+ port_change->dev_handle = le16toh(event_port_change->
+ AttachedDevHandle);
+ port_change->reason = event_port_change->PortStatus;
+ }
+ _mapping_update_pcie_missing_count(sc, &topo_change);
+ _mapping_get_pcie_dev_info(sc, &topo_change);
+ _mapping_clear_removed_entries(sc);
+ _mapping_add_new_pcie_device(sc, &topo_change);
+
+out:
+ free(topo_change.port_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
Index: sys/dev/mpr/mpr_pci.c
===================================================================
--- sys/dev/mpr/mpr_pci.c
+++ sys/dev/mpr/mpr_pci.c
@@ -54,6 +54,7 @@
#include <dev/mpr/mpi/mpi2_ioc.h>
#include <dev/mpr/mpi/mpi2_cnfg.h>
#include <dev/mpr/mpi/mpi2_tool.h>
+#include <dev/mpr/mpi/mpi2_pci.h>
#include <sys/queue.h>
#include <sys/kthread.h>
@@ -110,6 +111,10 @@
0xffff, 0xffff, 0, "Avago Technologies (LSI) SAS3108_5" },
{ MPI2_MFGPAGE_VENDORID_LSI, MPI25_MFGPAGE_DEVID_SAS3108_6,
0xffff, 0xffff, 0, "Avago Technologies (LSI) SAS3108_6" },
+ { MPI2_MFGPAGE_VENDORID_LSI, MPI26_MFGPAGE_DEVID_SAS3216,
+ 0xffff, 0xffff, 0, "Avago Technologies (LSI) SAS3216" },
+ { MPI2_MFGPAGE_VENDORID_LSI, MPI26_MFGPAGE_DEVID_SAS3224,
+ 0xffff, 0xffff, 0, "Avago Technologies (LSI) SAS3224" },
{ MPI2_MFGPAGE_VENDORID_LSI, MPI26_MFGPAGE_DEVID_SAS3316_1,
0xffff, 0xffff, 0, "Avago Technologies (LSI) SAS3316_1" },
{ MPI2_MFGPAGE_VENDORID_LSI, MPI26_MFGPAGE_DEVID_SAS3316_2,
@@ -118,10 +123,24 @@
0xffff, 0xffff, 0, "Avago Technologies (LSI) SAS3324_1" },
{ MPI2_MFGPAGE_VENDORID_LSI, MPI26_MFGPAGE_DEVID_SAS3324_2,
0xffff, 0xffff, 0, "Avago Technologies (LSI) SAS3324_2" },
- { MPI2_MFGPAGE_VENDORID_LSI, MPI26_MFGPAGE_DEVID_SAS3216,
- 0xffff, 0xffff, 0, "Avago Technologies (LSI) SAS3216" },
- { MPI2_MFGPAGE_VENDORID_LSI, MPI26_MFGPAGE_DEVID_SAS3224,
- 0xffff, 0xffff, 0, "Avago Technologies (LSI) SAS3224" },
+ { MPI2_MFGPAGE_VENDORID_LSI, MPI26_MFGPAGE_DEVID_SAS3408,
+ 0xffff, 0xffff, 0, "Avago Technologies (LSI) SAS3408" },
+ { MPI2_MFGPAGE_VENDORID_LSI, MPI26_MFGPAGE_DEVID_SAS3416,
+ 0xffff, 0xffff, 0, "Avago Technologies (LSI) SAS3416" },
+ { MPI2_MFGPAGE_VENDORID_LSI, MPI26_MFGPAGE_DEVID_SAS3508,
+ 0xffff, 0xffff, 0, "Avago Technologies (LSI) SAS3508" },
+ { MPI2_MFGPAGE_VENDORID_LSI, MPI26_MFGPAGE_DEVID_SAS3508_1,
+ 0xffff, 0xffff, 0, "Avago Technologies (LSI) SAS3508_1" },
+ { MPI2_MFGPAGE_VENDORID_LSI, MPI26_MFGPAGE_DEVID_SAS3516,
+ 0xffff, 0xffff, 0, "Avago Technologies (LSI) SAS3516" },
+ { MPI2_MFGPAGE_VENDORID_LSI, MPI26_MFGPAGE_DEVID_SAS3516_1,
+ 0xffff, 0xffff, 0, "Avago Technologies (LSI) SAS3516_1" },
+ { MPI2_MFGPAGE_VENDORID_LSI, MPI26_MFGPAGE_DEVID_SAS3616,
+ 0xffff, 0xffff, 0, "Avago Technologies (LSI) SAS3616" },
+ { MPI2_MFGPAGE_VENDORID_LSI, MPI26_MFGPAGE_DEVID_SAS3708,
+ 0xffff, 0xffff, 0, "Avago Technologies (LSI) SAS3708" },
+ { MPI2_MFGPAGE_VENDORID_LSI, MPI26_MFGPAGE_DEVID_SAS3716,
+ 0xffff, 0xffff, 0, "Avago Technologies (LSI) SAS3716" },
{ 0, 0, 0, 0, 0, NULL }
};
@@ -164,7 +183,7 @@
{
struct mpr_softc *sc;
struct mpr_ident *m;
- int error;
+ int error, i;
sc = device_get_softc(dev);
bzero(sc, sizeof(*sc));
@@ -175,13 +194,32 @@
/* 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) {
+ /* Set flag if this is a Gen3.5 IOC */
+ if ((m->device == MPI26_MFGPAGE_DEVID_SAS3508) ||
+ (m->device == MPI26_MFGPAGE_DEVID_SAS3508_1) ||
+ (m->device == MPI26_MFGPAGE_DEVID_SAS3408) ||
+ (m->device == MPI26_MFGPAGE_DEVID_SAS3516) ||
+ (m->device == MPI26_MFGPAGE_DEVID_SAS3516_1) ||
+ (m->device == MPI26_MFGPAGE_DEVID_SAS3416) ||
+ (m->device == MPI26_MFGPAGE_DEVID_SAS3716) ||
+ (m->device == MPI26_MFGPAGE_DEVID_SAS3616) ||
+ (m->device == MPI26_MFGPAGE_DEVID_SAS3708)) {
+ sc->mpr_flags |= MPR_FLAGS_GEN35_IOC;
+ }
+
+ for (i = 0; i < PCI_MAXMAPS_0; i++) {
+ sc->mpr_regs_rid = PCIR_BAR(i);
+
+ if ((sc->mpr_regs_resource = bus_alloc_resource_any(dev,
+ SYS_RES_MEMORY, &sc->mpr_regs_rid, RF_ACTIVE)) != NULL)
+ break;
+ }
+
+ if (sc->mpr_regs_resource == 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);
Index: sys/dev/mpr/mpr_sas.h
===================================================================
--- sys/dev/mpr/mpr_sas.h
+++ sys/dev/mpr/mpr_sas.h
@@ -83,6 +83,8 @@
uint8_t scsi_req_desc_type;
uint8_t stop_at_shutdown;
uint8_t supports_SSU;
+ uint8_t is_nvme;
+ uint32_t MDTS;
};
struct mprsas_softc {
Index: sys/dev/mpr/mpr_sas.c
===================================================================
--- sys/dev/mpr/mpr_sas.c
+++ sys/dev/mpr/mpr_sas.c
@@ -72,10 +72,13 @@
#include <cam/scsi/smp_all.h>
#endif
+#include <dev/nvme/nvme.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_pci.h>
#include <dev/mpr/mpi/mpi2_cnfg.h>
#include <dev/mpr/mpi/mpi2_init.h>
#include <dev/mpr/mpi/mpi2_tool.h>
@@ -477,13 +480,13 @@
}
/*
- * The MPT3 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.
+ * The 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)
@@ -705,7 +708,14 @@
setbit(events, MPI2_EVENT_IR_PHYSICAL_DISK);
setbit(events, MPI2_EVENT_IR_OPERATION_STATUS);
setbit(events, MPI2_EVENT_TEMP_THRESHOLD);
- setbit(events, MPI2_EVENT_ACTIVE_CABLE_EXCEPTION);
+ if (sc->facts->MsgVersion >= MPI2_VERSION_02_06) {
+ setbit(events, MPI2_EVENT_ACTIVE_CABLE_EXCEPTION);
+ if (sc->mpr_flags & MPR_FLAGS_GEN35_IOC) {
+ setbit(events, MPI2_EVENT_PCIE_DEVICE_STATUS_CHANGE);
+ setbit(events, MPI2_EVENT_PCIE_ENUMERATION);
+ setbit(events, MPI2_EVENT_PCIE_TOPOLOGY_CHANGE_LIST);
+ }
+ }
mpr_register_events(sc, events, mprsas_evt_handler, NULL,
&sc->sassc->mprsas_eh);
@@ -1679,6 +1689,151 @@
}
}
+/**
+ * mprsas_build_nvme_unmap - Build Native NVMe DSM command equivalent
+ * to SCSI Unmap.
+ * Return 0 - for success,
+ * 1 - to immediately return back the command with success status to CAM
+ * negative value - to fallback to firmware path i.e. issue scsi unmap
+ * to FW without any translation.
+ */
+static int
+mprsas_build_nvme_unmap(struct mpr_softc *sc, struct mpr_command *cm,
+ union ccb *ccb, struct mprsas_target *targ)
+{
+ Mpi26NVMeEncapsulatedRequest_t *req = NULL;
+ struct ccb_scsiio *csio;
+ struct unmap_parm_list *plist;
+ struct nvme_dsm_range *nvme_dsm_ranges = NULL;
+ struct nvme_command *c;
+ int i, res;
+ uint16_t ndesc, list_len, data_length;
+ struct mpr_prp_page *prp_page_info;
+ uint64_t nvme_dsm_ranges_dma_handle;
+
+ csio = &ccb->csio;
+ list_len = (ccb->csio.cdb_io.cdb_bytes[7] << 8 |
+ ccb->csio.cdb_io.cdb_bytes[8]);
+ if (!list_len) {
+ mpr_dprint(sc, MPR_ERROR, "Parameter list length is Zero\n");
+ return -EINVAL;
+ }
+
+ plist = malloc(csio->dxfer_len, M_MPR, M_ZERO|M_NOWAIT);
+ if (!plist) {
+ mpr_dprint(sc, MPR_ERROR, "Unable to allocate memory to "
+ "save UNMAP data\n");
+ return -ENOMEM;
+ }
+
+ /* Copy SCSI unmap data to a local buffer */
+ bcopy(csio->data_ptr, plist, csio->dxfer_len);
+
+ /* return back the unmap command to CAM with success status,
+ * if number of descripts is zero.
+ */
+ ndesc = be16toh(plist->unmap_blk_desc_data_len) >> 4;
+ if (!ndesc) {
+ mpr_dprint(sc, MPR_XINFO, "Number of descriptors in "
+ "UNMAP cmd is Zero\n");
+ res = 1;
+ goto out;
+ }
+
+ data_length = ndesc * sizeof(struct nvme_dsm_range);
+ if (data_length > targ->MDTS) {
+ mpr_dprint(sc, MPR_ERROR, "data length: %d is greater than "
+ "Device's MDTS: %d\n", data_length, targ->MDTS);
+ res = -EINVAL;
+ goto out;
+ }
+
+ prp_page_info = mpr_alloc_prp_page(sc);
+ KASSERT(prp_page_info != NULL, ("%s: There is no PRP Page for "
+ "UNMAP command.\n", __func__));
+
+ /*
+ * Insert the allocated PRP page into the command's PRP page list. This
+ * will be freed when the command is freed.
+ */
+ TAILQ_INSERT_TAIL(&cm->cm_prp_page_list, prp_page_info, prp_page_link);
+
+ nvme_dsm_ranges = (struct nvme_dsm_range *)prp_page_info->prp_page;
+ nvme_dsm_ranges_dma_handle = prp_page_info->prp_page_busaddr;
+
+ bzero(nvme_dsm_ranges, data_length);
+
+ /* Convert SCSI unmap's descriptor data to NVMe DSM specific Range data
+ * for each descriptors contained in SCSI UNMAP data.
+ */
+ for (i = 0; i < ndesc; i++) {
+ nvme_dsm_ranges[i].length =
+ htole32(be32toh(plist->desc[i].nlb));
+ nvme_dsm_ranges[i].starting_lba =
+ htole64(be64toh(plist->desc[i].slba));
+ nvme_dsm_ranges[i].attributes = 0;
+ }
+
+ /* Build MPI2.6's NVMe Encapsulated Request Message */
+ req = (Mpi26NVMeEncapsulatedRequest_t *)cm->cm_req;
+ bzero(req, sizeof(*req));
+ req->DevHandle = htole16(targ->handle);
+ req->Function = MPI2_FUNCTION_NVME_ENCAPSULATED;
+ req->Flags = MPI26_NVME_FLAGS_WRITE;
+ req->ErrorResponseBaseAddress.High =
+ htole32((uint32_t)((uint64_t)cm->cm_sense_busaddr >> 32));
+ req->ErrorResponseBaseAddress.Low =
+ htole32(cm->cm_sense_busaddr);
+ req->ErrorResponseAllocationLength =
+ htole16(sizeof(struct nvme_completion));
+ req->EncapsulatedCommandLength =
+ htole16(sizeof(struct nvme_command));
+ req->DataLength = htole32(data_length);
+
+ /* Build NVMe DSM command */
+ c = (struct nvme_command *) req->NVMe_Command;
+ c->opc = NVME_OPC_DATASET_MANAGEMENT;
+ c->nsid = htole32(csio->ccb_h.target_lun + 1);
+ c->cdw10 = htole32(ndesc - 1);
+ c->cdw11 = htole32(NVME_DSM_ATTR_DEALLOCATE);
+
+ cm->cm_length = data_length;
+ cm->cm_data = NULL;
+
+ 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;
+
+ cm->cm_desc.Default.RequestFlags =
+ MPI26_REQ_DESCRIPT_FLAGS_PCIE_ENCAPSULATED;
+
+#if __FreeBSD_version >= 1000029
+ callout_reset_sbt(&cm->cm_callout, SBT_1MS * ccb->ccb_h.timeout, 0,
+ mprsas_scsiio_timeout, cm, 0);
+#else //__FreeBSD_version < 1000029
+ callout_reset(&cm->cm_callout, (ccb->ccb_h.timeout * hz) / 1000,
+ mprsas_scsiio_timeout, cm);
+#endif //__FreeBSD_version >= 1000029
+
+ 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_build_nvme_prp(sc, cm, req, (void *)nvme_dsm_ranges_dma_handle, 0,
+ data_length);
+ mpr_map_command(sc, cm);
+
+out:
+ free(plist, M_MPR);
+ return 0;
+}
+
static void
mprsas_action_scsiio(struct mprsas_softc *sassc, union ccb *ccb)
{
@@ -1691,6 +1846,7 @@
uint8_t i, lba_byte, *ref_tag_addr;
uint16_t eedp_flags;
uint32_t mpi_control;
+ int rc;
sc = sassc->sc;
MPR_FUNCTRACE(sc);
@@ -1776,6 +1932,22 @@
return;
}
+ /* For NVME device's issue UNMAP command directly to NVME drives by
+ * constructing equivalent native NVMe DataSetManagement command.
+ */
+ if (ccb->csio.cdb_io.cdb_bytes[0] == UNMAP &&
+ targ->is_nvme &&
+ (csio->ccb_h.flags & CAM_DATA_MASK) == CAM_DATA_VADDR) {
+ rc = mprsas_build_nvme_unmap(sc, cm, ccb, targ);
+ if (rc == 1) { /* return command to CAM with success status */
+ mpr_free_command(sc, cm);
+ mprsas_set_ccbstatus(ccb, CAM_REQ_CMP);
+ xpt_done(ccb);
+ return;
+ } else if (!rc) /* Issued NVMe Encapsulated Request Message */
+ return;
+ }
+
req = (MPI2_SCSI_IO_REQUEST *)cm->cm_req;
bzero(req, sizeof(*req));
req->DevHandle = htole16(targ->handle);
@@ -1847,9 +2019,14 @@
if (csio->ccb_h.flags & CAM_CDB_POINTER)
bcopy(csio->cdb_io.cdb_ptr, &req->CDB.CDB32[0], csio->cdb_len);
else {
- KASSERT(csio->cdb_len <= IOCDBLEN,
- ("cdb_len %d is greater than IOCDBLEN but CAM_CDB_POINTER is not set",
- csio->cdb_len));
+//SLM-this is fixed in upstream driver by KASSERT check of cdb_len. Should
+//ask Alan Somers, who made the KASSERT fix, if ours is better.
+ if (csio->cdb_len > 16) {
+ mpr_free_command(sc, cm);
+ mprsas_set_ccbstatus(ccb, CAM_CCB_LEN_ERR);
+ xpt_done(ccb);
+ return;
+ }
bcopy(csio->cdb_io.cdb_bytes, &req->CDB.CDB32[0],csio->cdb_len);
}
req->IoFlags = htole16(csio->cdb_len);
@@ -1873,6 +2050,10 @@
eedp_flags |= (MPI2_SCSIIO_EEDPFLAGS_INC_PRI_REFTAG |
MPI2_SCSIIO_EEDPFLAGS_CHECK_REFTAG |
MPI2_SCSIIO_EEDPFLAGS_CHECK_GUARD);
+ if (sc->mpr_flags & MPR_FLAGS_GEN35_IOC) {
+ eedp_flags |=
+ MPI25_SCSIIO_EEDPFLAGS_APPTAG_DISABLE_MODE;
+ }
req->EEDPFlags = htole16(eedp_flags);
/*
@@ -1932,11 +2113,15 @@
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);
+ if (!sc->atomic_desc_capable) {
+ 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);
+ if (!sc->atomic_desc_capable)
+ cm->cm_desc.SCSIIO.DevHandle = htole16(targ->handle);
}
#if __FreeBSD_version >= 1000029
@@ -2159,6 +2344,200 @@
}
}
+/** mprsas_nvme_trans_status_code
+ *
+ * Convert Native NVMe command error status to
+ * equivalent SCSI error status.
+ *
+ * Returns appropriate scsi_status
+ */
+static u8
+mprsas_nvme_trans_status_code(struct nvme_status nvme_status,
+ struct mpr_command *cm)
+{
+ u8 status = MPI2_SCSI_STATUS_GOOD;
+ int skey, asc, ascq;
+ union ccb *ccb = cm->cm_complete_data;
+ int returned_sense_len;
+
+ status = MPI2_SCSI_STATUS_CHECK_CONDITION;
+ skey = SSD_KEY_ILLEGAL_REQUEST;
+ asc = SCSI_ASC_NO_SENSE;
+ ascq = SCSI_ASCQ_CAUSE_NOT_REPORTABLE;
+
+ switch (nvme_status.sct) {
+ case NVME_SCT_GENERIC:
+ switch (nvme_status.sc) {
+ case NVME_SC_SUCCESS:
+ status = MPI2_SCSI_STATUS_GOOD;
+ skey = SSD_KEY_NO_SENSE;
+ asc = SCSI_ASC_NO_SENSE;
+ ascq = SCSI_ASCQ_CAUSE_NOT_REPORTABLE;
+ break;
+ case NVME_SC_INVALID_OPCODE:
+ status = MPI2_SCSI_STATUS_CHECK_CONDITION;
+ skey = SSD_KEY_ILLEGAL_REQUEST;
+ asc = SCSI_ASC_ILLEGAL_COMMAND;
+ ascq = SCSI_ASCQ_CAUSE_NOT_REPORTABLE;
+ break;
+ case NVME_SC_INVALID_FIELD:
+ status = MPI2_SCSI_STATUS_CHECK_CONDITION;
+ skey = SSD_KEY_ILLEGAL_REQUEST;
+ asc = SCSI_ASC_INVALID_CDB;
+ ascq = SCSI_ASCQ_CAUSE_NOT_REPORTABLE;
+ break;
+ case NVME_SC_DATA_TRANSFER_ERROR:
+ status = MPI2_SCSI_STATUS_CHECK_CONDITION;
+ skey = SSD_KEY_MEDIUM_ERROR;
+ asc = SCSI_ASC_NO_SENSE;
+ ascq = SCSI_ASCQ_CAUSE_NOT_REPORTABLE;
+ break;
+ case NVME_SC_ABORTED_POWER_LOSS:
+ status = MPI2_SCSI_STATUS_TASK_ABORTED;
+ skey = SSD_KEY_ABORTED_COMMAND;
+ asc = SCSI_ASC_WARNING;
+ ascq = SCSI_ASCQ_POWER_LOSS_EXPECTED;
+ break;
+ case NVME_SC_INTERNAL_DEVICE_ERROR:
+ status = MPI2_SCSI_STATUS_CHECK_CONDITION;
+ skey = SSD_KEY_HARDWARE_ERROR;
+ asc = SCSI_ASC_INTERNAL_TARGET_FAILURE;
+ ascq = SCSI_ASCQ_CAUSE_NOT_REPORTABLE;
+ break;
+ case NVME_SC_ABORTED_BY_REQUEST:
+ case NVME_SC_ABORTED_SQ_DELETION:
+ case NVME_SC_ABORTED_FAILED_FUSED:
+ case NVME_SC_ABORTED_MISSING_FUSED:
+ status = MPI2_SCSI_STATUS_TASK_ABORTED;
+ skey = SSD_KEY_ABORTED_COMMAND;
+ asc = SCSI_ASC_NO_SENSE;
+ ascq = SCSI_ASCQ_CAUSE_NOT_REPORTABLE;
+ break;
+ case NVME_SC_INVALID_NAMESPACE_OR_FORMAT:
+ status = MPI2_SCSI_STATUS_CHECK_CONDITION;
+ skey = SSD_KEY_ILLEGAL_REQUEST;
+ asc = SCSI_ASC_ACCESS_DENIED_INVALID_LUN_ID;
+ ascq = SCSI_ASCQ_INVALID_LUN_ID;
+ break;
+ case NVME_SC_LBA_OUT_OF_RANGE:
+ status = MPI2_SCSI_STATUS_CHECK_CONDITION;
+ skey = SSD_KEY_ILLEGAL_REQUEST;
+ asc = SCSI_ASC_ILLEGAL_BLOCK;
+ ascq = SCSI_ASCQ_CAUSE_NOT_REPORTABLE;
+ break;
+ case NVME_SC_CAPACITY_EXCEEDED:
+ status = MPI2_SCSI_STATUS_CHECK_CONDITION;
+ skey = SSD_KEY_MEDIUM_ERROR;
+ asc = SCSI_ASC_NO_SENSE;
+ ascq = SCSI_ASCQ_CAUSE_NOT_REPORTABLE;
+ break;
+ case NVME_SC_NAMESPACE_NOT_READY:
+ status = MPI2_SCSI_STATUS_CHECK_CONDITION;
+ skey = SSD_KEY_NOT_READY;
+ asc = SCSI_ASC_LUN_NOT_READY;
+ ascq = SCSI_ASCQ_CAUSE_NOT_REPORTABLE;
+ break;
+ }
+ break;
+ case NVME_SCT_COMMAND_SPECIFIC:
+ switch (nvme_status.sc) {
+ case NVME_SC_INVALID_FORMAT:
+ status = MPI2_SCSI_STATUS_CHECK_CONDITION;
+ skey = SSD_KEY_ILLEGAL_REQUEST;
+ asc = SCSI_ASC_FORMAT_COMMAND_FAILED;
+ ascq = SCSI_ASCQ_FORMAT_COMMAND_FAILED;
+ break;
+ case NVME_SC_CONFLICTING_ATTRIBUTES:
+ status = MPI2_SCSI_STATUS_CHECK_CONDITION;
+ skey = SSD_KEY_ILLEGAL_REQUEST;
+ asc = SCSI_ASC_INVALID_CDB;
+ ascq = SCSI_ASCQ_CAUSE_NOT_REPORTABLE;
+ break;
+ }
+ break;
+ case NVME_SCT_MEDIA_ERROR:
+ switch (nvme_status.sc) {
+ case NVME_SC_WRITE_FAULTS:
+ status = MPI2_SCSI_STATUS_CHECK_CONDITION;
+ skey = SSD_KEY_MEDIUM_ERROR;
+ asc = SCSI_ASC_PERIPHERAL_DEV_WRITE_FAULT;
+ ascq = SCSI_ASCQ_CAUSE_NOT_REPORTABLE;
+ break;
+ case NVME_SC_UNRECOVERED_READ_ERROR:
+ status = MPI2_SCSI_STATUS_CHECK_CONDITION;
+ skey = SSD_KEY_MEDIUM_ERROR;
+ asc = SCSI_ASC_UNRECOVERED_READ_ERROR;
+ ascq = SCSI_ASCQ_CAUSE_NOT_REPORTABLE;
+ break;
+ case NVME_SC_GUARD_CHECK_ERROR:
+ status = MPI2_SCSI_STATUS_CHECK_CONDITION;
+ skey = SSD_KEY_MEDIUM_ERROR;
+ asc = SCSI_ASC_LOG_BLOCK_GUARD_CHECK_FAILED;
+ ascq = SCSI_ASCQ_LOG_BLOCK_GUARD_CHECK_FAILED;
+ break;
+ case NVME_SC_APPLICATION_TAG_CHECK_ERROR:
+ status = MPI2_SCSI_STATUS_CHECK_CONDITION;
+ skey = SSD_KEY_MEDIUM_ERROR;
+ asc = SCSI_ASC_LOG_BLOCK_APPTAG_CHECK_FAILED;
+ ascq = SCSI_ASCQ_LOG_BLOCK_APPTAG_CHECK_FAILED;
+ break;
+ case NVME_SC_REFERENCE_TAG_CHECK_ERROR:
+ status = MPI2_SCSI_STATUS_CHECK_CONDITION;
+ skey = SSD_KEY_MEDIUM_ERROR;
+ asc = SCSI_ASC_LOG_BLOCK_REFTAG_CHECK_FAILED;
+ ascq = SCSI_ASCQ_LOG_BLOCK_REFTAG_CHECK_FAILED;
+ break;
+ case NVME_SC_COMPARE_FAILURE:
+ status = MPI2_SCSI_STATUS_CHECK_CONDITION;
+ skey = SSD_KEY_MISCOMPARE;
+ asc = SCSI_ASC_MISCOMPARE_DURING_VERIFY;
+ ascq = SCSI_ASCQ_CAUSE_NOT_REPORTABLE;
+ break;
+ case NVME_SC_ACCESS_DENIED:
+ status = MPI2_SCSI_STATUS_CHECK_CONDITION;
+ skey = SSD_KEY_ILLEGAL_REQUEST;
+ asc = SCSI_ASC_ACCESS_DENIED_INVALID_LUN_ID;
+ ascq = SCSI_ASCQ_INVALID_LUN_ID;
+ break;
+ }
+ break;
+ }
+
+ returned_sense_len = sizeof(struct scsi_sense_data);
+ if (returned_sense_len < ccb->csio.sense_len)
+ ccb->csio.sense_resid = ccb->csio.sense_len -
+ returned_sense_len;
+ else
+ ccb->csio.sense_resid = 0;
+
+ scsi_set_sense_data(&ccb->csio.sense_data, SSD_TYPE_FIXED,
+ 1, skey, asc, ascq, SSD_ELEM_NONE);
+ ccb->ccb_h.status |= CAM_AUTOSNS_VALID;
+
+ return status;
+}
+
+/** mprsas_complete_nvme_unmap
+ *
+ * Complete native NVMe command issued using NVMe Encapsulated
+ * Request Message.
+ */
+static u8
+mprsas_complete_nvme_unmap(struct mpr_softc *sc, struct mpr_command *cm)
+{
+ Mpi26NVMeEncapsulatedErrorReply_t *mpi_reply;
+ struct nvme_completion *nvme_completion = NULL;
+ u8 scsi_status = MPI2_SCSI_STATUS_GOOD;
+
+ mpi_reply =(Mpi26NVMeEncapsulatedErrorReply_t *)cm->cm_reply;
+ if (le16toh(mpi_reply->ErrorResponseCount)){
+ nvme_completion = (struct nvme_completion *)cm->cm_sense;
+ scsi_status = mprsas_nvme_trans_status_code(
+ nvme_completion->status, cm);
+ }
+ return scsi_status;
+}
+
static void
mprsas_scsiio_complete(struct mpr_softc *sc, struct mpr_command *cm)
{
@@ -2313,6 +2692,14 @@
return;
}
+ target = &sassc->targets[target_id];
+ if (ccb->csio.cdb_io.cdb_bytes[0] == UNMAP &&
+ target->is_nvme &&
+ (csio->ccb_h.flags & CAM_DATA_MASK) == CAM_DATA_VADDR) {
+ rep->SCSIStatus = mprsas_complete_nvme_unmap(sc, cm);
+ ccb->csio.scsi_status = rep->SCSIStatus;
+ }
+
mprsas_log_command(cm, MPR_XINFO,
"ioc %x scsi %x state %x xfer %u\n",
le16toh(rep->IOCStatus), rep->SCSIStatus, rep->SCSIState,
@@ -2324,7 +2711,6 @@
/* 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");
@@ -2523,7 +2909,14 @@
rep->SCSIStatus, rep->SCSIState,
le32toh(rep->TransferCount));
csio->resid = cm->cm_length;
- mprsas_set_ccbstatus(ccb, CAM_REQ_CMP_ERR);
+
+ if (ccb->csio.cdb_io.cdb_bytes[0] == UNMAP &&
+ target->is_nvme &&
+ (csio->ccb_h.flags & CAM_DATA_MASK) == CAM_DATA_VADDR)
+ mprsas_set_ccbstatus(ccb, CAM_REQ_CMP);
+ else
+ mprsas_set_ccbstatus(ccb, CAM_REQ_CMP_ERR);
+
break;
}
Index: sys/dev/mpr/mpr_sas_lsi.c
===================================================================
--- sys/dev/mpr/mpr_sas_lsi.c
+++ sys/dev/mpr/mpr_sas_lsi.c
@@ -71,6 +71,7 @@
#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_pci.h>
#include <dev/mpr/mpi/mpi2_cnfg.h>
#include <dev/mpr/mpi/mpi2_init.h>
#include <dev/mpr/mpi/mpi2_raid.h>
@@ -116,6 +117,8 @@
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_add_pcie_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);
@@ -156,6 +159,7 @@
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_PCIE_TOPOLOGY_CHANGE_LIST ||
event->Event == MPI2_EVENT_SAS_ENCL_DEVICE_STATUS_CHANGE ||
event->Event == MPI2_EVENT_IR_CONFIGURATION_CHANGE_LIST) &&
sc->track_mapping_events)
@@ -167,13 +171,13 @@
* events are processed.
*/
if ((event->Event == MPI2_EVENT_SAS_TOPOLOGY_CHANGE_LIST ||
+ event->Event == MPI2_EVENT_PCIE_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
@@ -205,7 +209,7 @@
{
MPI2_EVENT_DATA_SAS_TOPOLOGY_CHANGE_LIST *data;
MPI2_EVENT_SAS_TOPO_PHY_ENTRY *phy;
- int i;
+ uint8_t i;
data = (MPI2_EVENT_DATA_SAS_TOPOLOGY_CHANGE_LIST *)
fw_event->event_data;
@@ -674,6 +678,60 @@
}
break;
}
+ case MPI2_EVENT_PCIE_TOPOLOGY_CHANGE_LIST:
+ {
+ MPI26_EVENT_DATA_PCIE_TOPOLOGY_CHANGE_LIST *data;
+ MPI26_EVENT_PCIE_TOPO_PORT_ENTRY *port_entry;
+ uint8_t i, link_rate;
+ uint16_t handle;
+
+ data = (MPI26_EVENT_DATA_PCIE_TOPOLOGY_CHANGE_LIST *)
+ fw_event->event_data;
+
+ mpr_mapping_pcie_topology_change_event(sc,
+ fw_event->event_data);
+
+ for (i = 0; i < data->NumEntries; i++) {
+ port_entry = &data->PortEntry[i];
+ handle = le16toh(port_entry->AttachedDevHandle);
+ link_rate = port_entry->CurrentPortInfo &
+ MPI26_EVENT_PCIE_TOPO_PI_RATE_MASK;
+ switch (port_entry->PortStatus) {
+ case MPI26_EVENT_PCIE_TOPO_PS_DEV_ADDED:
+ if (link_rate <
+ MPI26_EVENT_PCIE_TOPO_PI_RATE_2_5) {
+ mpr_dprint(sc, MPR_ERROR, "%s: Cannot "
+ "add PCIe device with handle 0x%x "
+ "with unknown link rate.\n",
+ __func__, handle);
+ break;
+ }
+ if (mprsas_add_pcie_device(sc, handle,
+ link_rate)) {
+ mpr_dprint(sc, MPR_ERROR, "%s: failed "
+ "to add PCIe device with handle "
+ "0x%x\n", __func__, handle);
+ mprsas_prepare_remove(sassc, handle);
+ }
+ break;
+ case MPI26_EVENT_PCIE_TOPO_PS_NOT_RESPONDING:
+ mprsas_prepare_remove(sassc, handle);
+ break;
+ case MPI26_EVENT_PCIE_TOPO_PS_PORT_CHANGED:
+ case MPI26_EVENT_PCIE_TOPO_PS_NO_CHANGE:
+ case MPI26_EVENT_PCIE_TOPO_PS_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_DEVICE_STATUS_CHANGE:
case MPI2_EVENT_SAS_BROADCAST_PRIMITIVE:
default:
@@ -703,7 +761,8 @@
}
static int
-mprsas_add_device(struct mpr_softc *sc, u16 handle, u8 linkrate){
+mprsas_add_device(struct mpr_softc *sc, u16 handle, u8 linkrate)
+{
char devstring[80];
struct mprsas_softc *sassc;
struct mprsas_target *targ;
@@ -779,8 +838,8 @@
if (sc->use_phynum != -1)
id = mpr_mapping_get_sas_id(sc, sas_address, handle);
if (id == MPR_MAP_BAD_ID) {
- if ((sc->use_phynum == 0)
- || ((id = config_page.PhyNum) > sassc->maxtargets)) {
+ if ((sc->use_phynum == 0) ||
+ ((id = config_page.PhyNum) > sassc->maxtargets)) {
mpr_dprint(sc, MPR_INFO, "failure at %s:%d/%s()! "
"Could not get ID for device with handle 0x%04x\n",
__FILE__, __LINE__, __func__, handle);
@@ -827,8 +886,10 @@
if (is_SATA_SSD) {
targ->flags = MPR_TARGET_IS_SATA_SSD;
}
- if (le16toh(config_page.Flags) &
- MPI25_SAS_DEVICE0_FLAGS_FAST_PATH_CAPABLE) {
+ if ((le16toh(config_page.Flags) &
+ MPI25_SAS_DEVICE0_FLAGS_ENABLED_FAST_PATH) &&
+ (le16toh(config_page.Flags) &
+ MPI25_SAS_DEVICE0_FLAGS_FAST_PATH_CAPABLE)) {
targ->scsi_req_desc_type =
MPI25_REQ_DESCRIPT_FLAGS_FAST_PATH_SCSI_IO;
}
@@ -908,7 +969,7 @@
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, u8 *is_SATA_SSD)
@@ -1140,6 +1201,141 @@
}
static int
+mprsas_add_pcie_device(struct mpr_softc *sc, u16 handle, u8 linkrate)
+{
+ char devstring[80];
+ struct mprsas_softc *sassc;
+ struct mprsas_target *targ;
+ Mpi2ConfigReply_t mpi_reply;
+ Mpi26PCIeDevicePage0_t config_page;
+ Mpi26PCIeDevicePage2_t config_page2;
+ uint64_t pcie_wwid, parent_wwid = 0;
+ u32 device_info, parent_devinfo = 0;
+ unsigned int id;
+ int error = 0;
+ struct mprsas_lun *lun;
+
+ sassc = sc->sassc;
+ mprsas_startup_increment(sassc);
+ if ((mpr_config_get_pcie_device_pg0(sc, &mpi_reply, &config_page,
+ MPI26_PCIE_DEVICE_PGAD_FORM_HANDLE, handle))) {
+ printf("%s: error reading PCIe device page0\n", __func__);
+ error = ENXIO;
+ goto out;
+ }
+
+ device_info = le32toh(config_page.DeviceInfo);
+
+ if (((device_info & MPI26_PCIE_DEVINFO_PCI_SWITCH) == 0)
+ && (le16toh(config_page.ParentDevHandle) != 0)) {
+ Mpi2ConfigReply_t tmp_mpi_reply;
+ Mpi26PCIeDevicePage0_t parent_config_page;
+
+ if ((mpr_config_get_pcie_device_pg0(sc, &tmp_mpi_reply,
+ &parent_config_page, MPI26_PCIE_DEVICE_PGAD_FORM_HANDLE,
+ le16toh(config_page.ParentDevHandle)))) {
+ printf("%s: error reading PCIe device %#x page0\n",
+ __func__, le16toh(config_page.ParentDevHandle));
+ } else {
+ parent_wwid = parent_config_page.WWID.High;
+ parent_wwid = (parent_wwid << 32) |
+ parent_config_page.WWID.Low;
+ parent_devinfo = le32toh(parent_config_page.DeviceInfo);
+ }
+ }
+ /* TODO Check proper endianness */
+ pcie_wwid = config_page.WWID.High;
+ pcie_wwid = (pcie_wwid << 32) | config_page.WWID.Low;
+ mpr_dprint(sc, MPR_INFO, "PCIe WWID from PCIe device page0 = %jx\n",
+ pcie_wwid);
+
+ if ((mpr_config_get_pcie_device_pg2(sc, &mpi_reply, &config_page2,
+ MPI26_PCIE_DEVICE_PGAD_FORM_HANDLE, handle))) {
+ printf("%s: error reading PCIe device page2\n", __func__);
+ error = ENXIO;
+ goto out;
+ }
+
+ id = mpr_mapping_get_sas_id(sc, pcie_wwid, 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, "WWID from PCIe device page0 = %jx\n",
+ pcie_wwid);
+ targ = &sassc->targets[id];
+ targ->devinfo = device_info;
+ targ->encl_handle = le16toh(config_page.EnclosureHandle);
+ targ->encl_slot = le16toh(config_page.Slot);
+ targ->encl_level = config_page.EnclosureLevel;
+ targ->connector_name[0] = ((char *)&config_page.ConnectorName)[0];
+ targ->connector_name[1] = ((char *)&config_page.ConnectorName)[1];
+ targ->connector_name[2] = ((char *)&config_page.ConnectorName)[2];
+ targ->connector_name[3] = ((char *)&config_page.ConnectorName)[3];
+ targ->is_nvme = device_info & MPI26_PCIE_DEVINFO_NVME;
+ targ->MDTS = config_page2.MaximumDataTransferSize;
+ /*
+ * Assume always TRUE for encl_level_valid because there is no valid
+ * flag for PCIe.
+ */
+ targ->encl_level_valid = TRUE;
+ targ->handle = handle;
+ targ->parent_handle = le16toh(config_page.ParentDevHandle);
+ targ->sasaddr = mpr_to_u64(&config_page.WWID);
+ targ->parent_sasaddr = le64toh(parent_wwid);
+ targ->parent_devinfo = parent_devinfo;
+ targ->tid = id;
+ targ->linkrate = linkrate;
+ targ->flags = 0;
+ if ((le16toh(config_page.Flags) &
+ MPI26_PCIEDEV0_FLAGS_ENABLED_FAST_PATH) &&
+ (le16toh(config_page.Flags) &
+ MPI26_PCIEDEV0_FLAGS_FAST_PATH_CAPABLE)) {
+ targ->scsi_req_desc_type =
+ MPI25_REQ_DESCRIPT_FLAGS_FAST_PATH_SCSI_IO;
+ }
+ 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_INFO|MPR_MAPPING), "Found PCIe device <%s> <%s> "
+ "handle<0x%04x> enclosureHandle<0x%04x> slot %d\n", devstring,
+ mpr_describe_table(mpr_pcie_linkrate_names, targ->linkrate),
+ targ->handle, targ->encl_handle, targ->encl_slot);
+ if (targ->encl_level_valid) {
+ mpr_dprint(sc, (MPR_INFO|MPR_MAPPING), "At enclosure level %d "
+ "and connector name (%4s)\n", targ->encl_level,
+ targ->connector_name);
+ }
+#if ((__FreeBSD_version >= 1000000) && (__FreeBSD_version < 1000039)) || \
+ (__FreeBSD_version < 902502)
+ 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);
+}
+
+static int
mprsas_volume_add(struct mpr_softc *sc, u16 handle)
{
struct mprsas_softc *sassc;
@@ -1235,8 +1431,8 @@
if (target->stop_at_shutdown) {
ccb = xpt_alloc_ccb_nowait();
if (ccb == NULL) {
- mpr_dprint(sc, MPR_FAULT, "Unable to alloc CCB to stop "
- "unit.\n");
+ mpr_dprint(sc, MPR_FAULT, "Unable to alloc CCB "
+ "to stop unit.\n");
return;
}
Index: sys/dev/mpr/mpr_table.h
===================================================================
--- sys/dev/mpr/mpr_table.h
+++ sys/dev/mpr/mpr_table.h
@@ -40,6 +40,7 @@
extern struct mpr_table_lookup mpr_event_names[];
extern struct mpr_table_lookup mpr_phystatus_names[];
extern struct mpr_table_lookup mpr_linkrate_names[];
+extern struct mpr_table_lookup mpr_pcie_linkrate_names[];
void _mpr_print_iocfacts(struct mpr_softc *, MPI2_IOC_FACTS_REPLY *);
void _mpr_print_portfacts(struct mpr_softc *, MPI2_PORT_FACTS_REPLY *);
Index: sys/dev/mpr/mpr_table.c
===================================================================
--- sys/dev/mpr/mpr_table.c
+++ sys/dev/mpr/mpr_table.c
@@ -58,6 +58,7 @@
#include <dev/mpr/mpi/mpi2_cnfg.h>
#include <dev/mpr/mpi/mpi2_init.h>
#include <dev/mpr/mpi/mpi2_tool.h>
+#include <dev/mpr/mpi/mpi2_pci.h>
#include <dev/mpr/mpr_ioctl.h>
#include <dev/mpr/mprvar.h>
#include <dev/mpr/mpr_table.h>
@@ -74,6 +75,7 @@
return(table[i+1].string);
}
+//SLM-Add new PCIe info to all of these tables
struct mpr_table_lookup mpr_event_names[] = {
{"LogData", 0x01},
{"StateChange", 0x02},
@@ -100,6 +102,10 @@
{"TempThreshold", 0x27},
{"HostMessage", 0x28},
{"PowerPerformanceChange", 0x29},
+ {"PCIeDeviceStatusChange", 0x30},
+ {"PCIeEnumeration", 0x31},
+ {"PCIeTopologyChangeList", 0x32},
+ {"PCIeLinkCounter", 0x33},
{"CableEvent", 0x34},
{NULL, 0},
{"Unknown Event", 0}
@@ -192,6 +198,16 @@
{"Unknown", 0x00}
};
+struct mpr_table_lookup mpr_pcie_linkrate_names[] = {
+ {"Port disabled", 0x01},
+ {"2.5GT/sec", 0x02},
+ {"5.0GT/sec", 0x03},
+ {"8.0GT/sec", 0x04},
+ {"16.0GT/sec", 0x05},
+ {NULL, 0},
+ {"LinkRate Unknown", 0x00}
+};
+
void
mpr_describe_devinfo(uint32_t devinfo, char *string, int len)
{
@@ -321,6 +337,7 @@
"\40MaxEnclosures");
break;
}
+//SLM-add for PCIE EVENT too
case MPI2_EVENT_SAS_TOPOLOGY_CHANGE_LIST:
{
MPI2_EVENT_DATA_SAS_TOPOLOGY_CHANGE_LIST *data;
Index: sys/dev/mpr/mpr_user.c
===================================================================
--- sys/dev/mpr/mpr_user.c
+++ sys/dev/mpr/mpr_user.c
@@ -99,6 +99,7 @@
#include <dev/mpr/mpi/mpi2_cnfg.h>
#include <dev/mpr/mpi/mpi2_init.h>
#include <dev/mpr/mpi/mpi2_tool.h>
+#include <dev/mpr/mpi/mpi2_pci.h>
#include <dev/mpr/mpr_ioctl.h>
#include <dev/mpr/mprvar.h>
#include <dev/mpr/mpr_table.h>
@@ -747,6 +748,8 @@
{
MPI2_REQUEST_HEADER *hdr, tmphdr;
MPI2_DEFAULT_REPLY *rpl;
+ Mpi26NVMeEncapsulatedErrorReply_t *nvme_error_reply = NULL;
+ Mpi26NVMeEncapsulatedRequest_t *nvme_encap_request = NULL;
struct mpr_command *cm = NULL;
int i, err = 0, dir = 0, sz;
uint8_t tool, function = 0;
@@ -923,8 +926,8 @@
cm->cm_data, data->DataSize);
}
if (err != 0)
- mpr_dprint(sc, MPR_FAULT, "%s: failed to copy "
- "IOCTL data from user space\n", __func__);
+ 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
@@ -946,6 +949,35 @@
}
cm->cm_desc.Default.RequestFlags = MPI2_REQ_DESCRIPT_FLAGS_DEFAULT_TYPE;
+ if (function == MPI2_FUNCTION_NVME_ENCAPSULATED) {
+ nvme_encap_request =
+ (Mpi26NVMeEncapsulatedRequest_t *)cm->cm_req;
+ cm->cm_desc.Default.RequestFlags =
+ MPI26_REQ_DESCRIPT_FLAGS_PCIE_ENCAPSULATED;
+
+ /*
+ * Get the Physical Address of the sense buffer.
+ * Save the user's Error Response buffer address and use that
+ * field to hold the sense buffer address.
+ * Clear the internal sense buffer, which will potentially hold
+ * the Completion Queue Entry on return, or 0 if no Entry.
+ * Build the PRPs and set direction bits.
+ * Send the request.
+ */
+ cm->nvme_error_response =
+ (uint64_t *)(uintptr_t)(((uint64_t)nvme_encap_request->
+ ErrorResponseBaseAddress.High << 32) |
+ (uint64_t)nvme_encap_request->
+ ErrorResponseBaseAddress.Low);
+ nvme_encap_request->ErrorResponseBaseAddress.High =
+ htole32((uint32_t)((uint64_t)cm->cm_sense_busaddr >> 32));
+ nvme_encap_request->ErrorResponseBaseAddress.Low =
+ htole32(cm->cm_sense_busaddr);
+ memset(cm->cm_sense, 0, NVME_ERROR_RESPONSE_SIZE);
+ mpr_build_nvme_prp(sc, cm, nvme_encap_request, cm->cm_data,
+ data->DataSize, data->DataOutSize);
+ }
+
/*
* Set up Sense buffer and SGL offset for IO passthru. SCSI IO request
* uses SCSI IO or Fast Path SCSI IO descriptor.
@@ -994,15 +1026,19 @@
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;
+ if (!sc->atomic_desc_capable) {
+ 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;
+ if (!sc->atomic_desc_capable) {
+ cm->cm_desc.SCSIIO.DevHandle =
+ scsi_io_req->DevHandle;
+ }
}
/*
@@ -1079,6 +1115,38 @@
mpr_lock(sc);
}
}
+
+ /*
+ * Copy out the NVMe Error Reponse to user. The Error Response
+ * buffer is given by the user, but a sense buffer is used to
+ * get that data from the IOC. The user's
+ * ErrorResponseBaseAddress is saved in the
+ * 'nvme_error_response' field before the command because that
+ * field is set to a sense buffer. When the command is
+ * complete, the Error Response data from the IOC is copied to
+ * that user address after it is checked for validity.
+ * Also note that 'sense' buffers are not defined for
+ * NVMe commands. Sense terminalogy is only used here so that
+ * the same IOCTL structure and sense buffers can be used for
+ * NVMe.
+ */
+ if (function == MPI2_FUNCTION_NVME_ENCAPSULATED) {
+ if (cm->nvme_error_response == NULL) {
+ mpr_dprint(sc, MPR_INFO, "NVMe Error Response "
+ "buffer is NULL. Response data will not be "
+ "returned.\n");
+ mpr_unlock(sc);
+ goto RetFreeUnlocked;
+ }
+
+ nvme_error_reply =
+ (Mpi26NVMeEncapsulatedErrorReply_t *)cm->cm_reply;
+ sz = MIN(le32toh(nvme_error_reply->ErrorResponseCount),
+ NVME_ERROR_RESPONSE_SIZE);
+ mpr_unlock(sc);
+ copyout(cm->cm_sense, cm->nvme_error_response, sz);
+ mpr_lock(sc);
+ }
}
mpr_unlock(sc);
@@ -2068,7 +2136,7 @@
return (EINVAL);
if (target > sc->max_devices) {
- mpr_dprint(sc, MPR_FAULT, "Target ID is out of range "
+ mpr_dprint(sc, MPR_XINFO, "Target ID is out of range "
"for Bus/Target to DevHandle mapping.");
return (EINVAL);
}
Index: sys/dev/mpr/mprvar.h
===================================================================
--- sys/dev/mpr/mprvar.h
+++ sys/dev/mpr/mprvar.h
@@ -33,10 +33,11 @@
#ifndef _MPRVAR_H
#define _MPRVAR_H
-#define MPR_DRIVER_VERSION "15.01.00.00-fbsd"
+#define MPR_DRIVER_VERSION "15.255.03.00"
#define MPR_DB_MAX_WAIT 2500
+#define MPR_MAX_IO_SIZE 0x100000
#define MPR_REQ_FRAMES 1024
#define MPR_EVT_REPLY_FRAMES 32
#define MPR_REPLY_FRAMES MPR_REQ_FRAMES
@@ -50,6 +51,17 @@
#define MPR_DEFAULT_CHAIN_SEG_SIZE 8
#define MPR_MAX_CHAIN_ELEMENT_SIZE 16
+/*
+ * PCIe NVMe Specific defines
+ */
+//SLM-for now just use the same value as a SAS disk
+#define NVME_QDEPTH MPR_REQ_FRAMES
+#define PRP_ENTRY_SIZE 8
+#define NVME_CMD_PRP1_OFFSET 24 /* PRP1 offset in NVMe cmd */
+#define NVME_CMD_PRP2_OFFSET 32 /* PRP2 offset in NVMe cmd */
+#define NVME_ERROR_RESPONSE_SIZE 16 /* Max NVME Error Response */
+#define HOST_PAGE_SIZE_4K 12
+
#define MPR_FUNCTRACE(sc) \
mpr_dprint((sc), MPR_TRACE, "%s\n", __func__)
@@ -184,6 +196,12 @@
uint64_t chain_busaddr;
};
+struct mpr_prp_page {
+ TAILQ_ENTRY(mpr_prp_page) prp_page_link;
+ uint64_t *prp_page;
+ uint64_t prp_page_busaddr;
+};
+
/*
* This needs to be at least 2 to support SMP passthrough.
*/
@@ -229,9 +247,11 @@
#define MPR_CM_STATE_TIMEDOUT 2
bus_dmamap_t cm_dmamap;
struct scsi_sense_data *cm_sense;
+ uint64_t *nvme_error_response;
TAILQ_HEAD(, mpr_chain) cm_chain_list;
+ TAILQ_HEAD(, mpr_prp_page) cm_prp_page_list;
uint32_t cm_req_busaddr;
- uint32_t cm_sense_busaddr;
+ bus_addr_t cm_sense_busaddr;
struct callout cm_callout;
};
@@ -257,9 +277,11 @@
#define MPR_FLAGS_SHUTDOWN (1 << 3)
#define MPR_FLAGS_DIAGRESET (1 << 4)
#define MPR_FLAGS_ATTACH_DONE (1 << 5)
+#define MPR_FLAGS_GEN35_IOC (1 << 6)
u_int mpr_debug;
u_int disable_msix;
u_int disable_msi;
+ u_int atomic_desc_capable;
int tm_cmds_active;
int io_cmds_active;
int io_cmds_highwater;
@@ -269,15 +291,20 @@
int chain_free_lowwater;
uint32_t chain_frame_size;
uint16_t chain_seg_size;
+ int prp_buffer_size;
+ int prp_pages_free;
+ int prp_pages_free_lowwater;
u_int enable_ssu;
int spinup_wait_time;
int use_phynum;
uint64_t chain_alloc_fail;
+ uint64_t prp_page_alloc_fail;
struct sysctl_ctx_list sysctl_ctx;
struct sysctl_oid *sysctl_tree;
char fw_version[16];
struct mpr_command *commands;
struct mpr_chain *chains;
+ struct mpr_prp_page *prps;
struct callout periodic;
struct mprsas_softc *sassc;
@@ -285,6 +312,7 @@
TAILQ_HEAD(, mpr_command) req_list;
TAILQ_HEAD(, mpr_command) high_priority_req_list;
TAILQ_HEAD(, mpr_chain) chain_list;
+ TAILQ_HEAD(, mpr_prp_page) prp_page_list;
TAILQ_HEAD(, mpr_command) tm_list;
int replypostindex;
int replyfreeindex;
@@ -333,6 +361,11 @@
bus_dma_tag_t chain_dmat;
bus_dmamap_t chain_map;
+ uint8_t *prp_pages;
+ bus_addr_t prp_page_busaddr;
+ bus_dma_tag_t prp_page_dmat;
+ bus_dmamap_t prp_page_map;
+
MPI2_REPLY_DESCRIPTORS_UNION *post_queue;
bus_addr_t post_busaddr;
uint32_t *free_queue;
@@ -471,10 +504,33 @@
TAILQ_INSERT_TAIL(&sc->chain_list, chain, chain_link);
}
+static __inline struct mpr_prp_page *
+mpr_alloc_prp_page(struct mpr_softc *sc)
+{
+ struct mpr_prp_page *prp_page;
+
+ if ((prp_page = TAILQ_FIRST(&sc->prp_page_list)) != NULL) {
+ TAILQ_REMOVE(&sc->prp_page_list, prp_page, prp_page_link);
+ sc->prp_pages_free--;
+ if (sc->prp_pages_free < sc->prp_pages_free_lowwater)
+ sc->prp_pages_free_lowwater = sc->prp_pages_free;
+ } else
+ sc->prp_page_alloc_fail++;
+ return (prp_page);
+}
+
+static __inline void
+mpr_free_prp_page(struct mpr_softc *sc, struct mpr_prp_page *prp_page)
+{
+ sc->prp_pages_free++;
+ TAILQ_INSERT_TAIL(&sc->prp_page_list, prp_page, prp_page_link);
+}
+
static __inline void
mpr_free_command(struct mpr_softc *sc, struct mpr_command *cm)
{
struct mpr_chain *chain, *chain_temp;
+ struct mpr_prp_page *prp_page, *prp_page_temp;
if (cm->cm_reply != NULL)
mpr_free_reply(sc, cm->cm_reply_data);
@@ -497,6 +553,11 @@
TAILQ_REMOVE(&cm->cm_chain_list, chain, chain_link);
mpr_free_chain(sc, chain);
}
+ TAILQ_FOREACH_SAFE(prp_page, &cm->cm_prp_page_list, prp_page_link,
+ prp_page_temp) {
+ TAILQ_REMOVE(&cm->cm_prp_page_list, prp_page, prp_page_link);
+ mpr_free_prp_page(sc, prp_page);
+ }
TAILQ_INSERT_TAIL(&sc->req_list, cm, cm_link);
}
@@ -510,7 +571,8 @@
return (NULL);
TAILQ_REMOVE(&sc->req_list, cm, cm_link);
- KASSERT(cm->cm_state == MPR_CM_STATE_FREE, ("mpr: Allocating busy command\n"));
+ KASSERT(cm->cm_state == MPR_CM_STATE_FREE, ("mpr: Allocating busy "
+ "command\n"));
cm->cm_state = MPR_CM_STATE_BUSY;
return (cm);
}
@@ -547,7 +609,8 @@
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"));
+ KASSERT(cm->cm_state == MPR_CM_STATE_FREE, ("mpr: Allocating busy "
+ "command\n"));
cm->cm_state = MPR_CM_STATE_BUSY;
return (cm);
}
@@ -653,6 +716,9 @@
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 *);
+void mpr_build_nvme_prp(struct mpr_softc *sc, struct mpr_command *cm,
+ Mpi26NVMeEncapsulatedRequest_t *nvme_encap_request, void *data,
+ uint32_t data_in_sz, uint32_t data_out_sz);
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);
@@ -682,6 +748,10 @@
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_pcie_device_pg0(struct mpr_softc *sc, Mpi2ConfigReply_t
+ *mpi_reply, Mpi26PCIeDevicePage0_t *config_page, u32 form, u16 handle);
+int mpr_config_get_pcie_device_pg2(struct mpr_softc *sc, Mpi2ConfigReply_t
+ *mpi_reply, Mpi26PCIeDevicePage2_t *config_page, u32 form, u16 handle);
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,
@@ -702,6 +772,8 @@
int mpr_mapping_initialize(struct mpr_softc *);
void mpr_mapping_topology_change_event(struct mpr_softc *,
Mpi2EventDataSasTopologyChangeList_t *);
+void mpr_mapping_pcie_topology_change_event(struct mpr_softc *sc,
+ Mpi26EventDataPCIeTopologyChangeList_t *event_data);
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 *,
@@ -769,5 +841,52 @@
#define CAM_PRIORITY_NORMAL CAM_PRIORITY_NONE
#endif
+/* Definitions for SCSI unmap translation to NVMe DSM command */
+
+/* UNMAP block descriptor structure */
+struct unmap_blk_desc {
+ uint64_t slba;
+ uint32_t nlb;
+ uint32_t resv;
+};
+
+/* UNMAP command's data */
+struct unmap_parm_list {
+ uint16_t unmap_data_len;
+ uint16_t unmap_blk_desc_data_len;
+ uint32_t resv;
+ struct unmap_blk_desc desc[0];
+};
+
+/* SCSI ADDITIONAL SENSE Codes */
+#define FIXED_SENSE_DATA 0x70
+#define SCSI_ASC_NO_SENSE 0x00
+#define SCSI_ASC_PERIPHERAL_DEV_WRITE_FAULT 0x03
+#define SCSI_ASC_LUN_NOT_READY 0x04
+#define SCSI_ASC_WARNING 0x0B
+#define SCSI_ASC_LOG_BLOCK_GUARD_CHECK_FAILED 0x10
+#define SCSI_ASC_LOG_BLOCK_APPTAG_CHECK_FAILED 0x10
+#define SCSI_ASC_LOG_BLOCK_REFTAG_CHECK_FAILED 0x10
+#define SCSI_ASC_UNRECOVERED_READ_ERROR 0x11
+#define SCSI_ASC_MISCOMPARE_DURING_VERIFY 0x1D
+#define SCSI_ASC_ACCESS_DENIED_INVALID_LUN_ID 0x20
+#define SCSI_ASC_ILLEGAL_COMMAND 0x20
+#define SCSI_ASC_ILLEGAL_BLOCK 0x21
+#define SCSI_ASC_INVALID_CDB 0x24
+#define SCSI_ASC_INVALID_LUN 0x25
+#define SCSI_ASC_INVALID_PARAMETER 0x26
+#define SCSI_ASC_FORMAT_COMMAND_FAILED 0x31
+#define SCSI_ASC_INTERNAL_TARGET_FAILURE 0x44
+
+/* SCSI ADDITIONAL SENSE Code Qualifiers */
+#define SCSI_ASCQ_CAUSE_NOT_REPORTABLE 0x00
+#define SCSI_ASCQ_FORMAT_COMMAND_FAILED 0x01
+#define SCSI_ASCQ_LOG_BLOCK_GUARD_CHECK_FAILED 0x01
+#define SCSI_ASCQ_LOG_BLOCK_APPTAG_CHECK_FAILED 0x02
+#define SCSI_ASCQ_LOG_BLOCK_REFTAG_CHECK_FAILED 0x03
+#define SCSI_ASCQ_FORMAT_IN_PROGRESS 0x04
+#define SCSI_ASCQ_POWER_LOSS_EXPECTED 0x08
+#define SCSI_ASCQ_INVALID_LUN_ID 0x09
+
#endif

File Metadata

Mime Type
text/plain
Expires
Fri, Feb 27, 2:10 PM (59 m, 37 s)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
29032395
Default Alt Text
D10095.id26542.diff (192 KB)

Event Timeline