diff options
Diffstat (limited to 'drivers/scsi/mpt3sas')
-rw-r--r-- | drivers/scsi/mpt3sas/mpi/mpi2.h | 43 | ||||
-rw-r--r-- | drivers/scsi/mpt3sas/mpi/mpi2_cnfg.h | 564 | ||||
-rw-r--r-- | drivers/scsi/mpt3sas/mpi/mpi2_init.h | 11 | ||||
-rw-r--r-- | drivers/scsi/mpt3sas/mpi/mpi2_ioc.h | 282 | ||||
-rw-r--r-- | drivers/scsi/mpt3sas/mpi/mpi2_pci.h | 111 | ||||
-rw-r--r-- | drivers/scsi/mpt3sas/mpi/mpi2_tool.h | 14 | ||||
-rw-r--r-- | drivers/scsi/mpt3sas/mpt3sas_base.c | 660 | ||||
-rw-r--r-- | drivers/scsi/mpt3sas/mpt3sas_base.h | 177 | ||||
-rw-r--r-- | drivers/scsi/mpt3sas/mpt3sas_config.c | 100 | ||||
-rw-r--r-- | drivers/scsi/mpt3sas/mpt3sas_ctl.c | 164 | ||||
-rw-r--r-- | drivers/scsi/mpt3sas/mpt3sas_scsih.c | 2219 | ||||
-rw-r--r-- | drivers/scsi/mpt3sas/mpt3sas_warpdrive.c | 2 |
12 files changed, 4027 insertions, 320 deletions
diff --git a/drivers/scsi/mpt3sas/mpi/mpi2.h b/drivers/scsi/mpt3sas/mpi/mpi2.h index 2608011cc7f1..b015c30d2c32 100644 --- a/drivers/scsi/mpt3sas/mpi/mpi2.h +++ b/drivers/scsi/mpt3sas/mpi/mpi2.h @@ -9,7 +9,7 @@ * scatter/gather formats. * Creation Date: June 21, 2006 * - * mpi2.h Version: 02.00.42 + * mpi2.h Version: 02.00.48 * * 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 @@ -104,6 +104,16 @@ * 08-25-15 02.00.40 Bumped MPI2_HEADER_VERSION_UNIT. * 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. + * 11-23-16 02.00.47 Bumped MPI2_HEADER_VERSION_UNIT. + * 02-03-17 02.00.48 Bumped MPI2_HEADER_VERSION_UNIT. * -------------------------------------------------------------------------- */ @@ -143,7 +153,7 @@ #define MPI2_VERSION_02_06 (0x0206) /*Unit and Dev versioning for this MPI header set */ -#define MPI2_HEADER_VERSION_UNIT (0x2A) +#define MPI2_HEADER_VERSION_UNIT (0x30) #define MPI2_HEADER_VERSION_DEV (0x00) #define MPI2_HEADER_VERSION_UNIT_MASK (0xFF00) #define MPI2_HEADER_VERSION_UNIT_SHIFT (8) @@ -250,6 +260,12 @@ typedef volatile struct _MPI2_SYSTEM_INTERFACE_REGS { #define MPI2_DIAG_BOOT_DEVICE_SELECT_DEFAULT (0x00000000) #define MPI2_DIAG_BOOT_DEVICE_SELECT_HCDW (0x00000800) +/* Defines for V7A/V7R HostDiagnostic Register */ +#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) @@ -368,6 +384,7 @@ typedef struct _MPI2_DEFAULT_REQUEST_DESCRIPTOR { #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) @@ -426,6 +443,13 @@ typedef MPI2_SCSI_IO_REQUEST_DESCRIPTOR Mpi25FastPathSCSIIORequestDescriptor_t, *pMpi25FastPathSCSIIORequestDescriptor_t; +/*PCIe Encapsulated Request Descriptor */ +typedef MPI2_SCSI_IO_REQUEST_DESCRIPTOR + MPI26_PCIE_ENCAPSULATED_REQUEST_DESCRIPTOR, + *PTR_MPI26_PCIE_ENCAPSULATED_REQUEST_DESCRIPTOR, + Mpi26PCIeEncapsulatedRequestDescriptor_t, + *pMpi26PCIeEncapsulatedRequestDescriptor_t; + /*union of Request Descriptors */ typedef union _MPI2_REQUEST_DESCRIPTOR_UNION { MPI2_DEFAULT_REQUEST_DESCRIPTOR Default; @@ -434,6 +458,7 @@ typedef union _MPI2_REQUEST_DESCRIPTOR_UNION { 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, *PTR_MPI2_REQUEST_DESCRIPTOR_UNION, @@ -451,6 +476,7 @@ typedef union _MPI2_REQUEST_DESCRIPTOR_UNION { * 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 */ @@ -488,6 +514,7 @@ typedef struct _MPI2_DEFAULT_REPLY_DESCRIPTOR { #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 */ @@ -566,6 +593,13 @@ typedef MPI2_SCSI_IO_SUCCESS_REPLY_DESCRIPTOR Mpi25FastPathSCSIIOSuccessReplyDescriptor_t, *pMpi25FastPathSCSIIOSuccessReplyDescriptor_t; +/*PCIe Encapsulated Success Reply Descriptor */ +typedef MPI2_RAID_ACCELERATOR_SUCCESS_REPLY_DESCRIPTOR + MPI26_PCIE_ENCAPSULATED_SUCCESS_REPLY_DESCRIPTOR, + *PTR_MPI26_PCIE_ENCAPSULATED_SUCCESS_REPLY_DESCRIPTOR, + Mpi26PCIeEncapsulatedSuccessReplyDescriptor_t, + *pMpi26PCIeEncapsulatedSuccessReplyDescriptor_t; + /*union of Reply Descriptors */ typedef union _MPI2_REPLY_DESCRIPTORS_UNION { MPI2_DEFAULT_REPLY_DESCRIPTOR Default; @@ -575,6 +609,8 @@ typedef union _MPI2_REPLY_DESCRIPTORS_UNION { 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, *PTR_MPI2_REPLY_DESCRIPTORS_UNION, @@ -617,6 +653,7 @@ typedef union _MPI2_REPLY_DESCRIPTORS_UNION { #define MPI2_FUNCTION_HOST_BASED_DISCOVERY_ACTION (0x2F) #define MPI2_FUNCTION_PWR_MGMT_CONTROL (0x30) #define MPI2_FUNCTION_SEND_HOST_MESSAGE (0x31) +#define MPI2_FUNCTION_NVME_ENCAPSULATED (0x33) #define MPI2_FUNCTION_MIN_PRODUCT_SPECIFIC (0xF0) #define MPI2_FUNCTION_MAX_PRODUCT_SPECIFIC (0xFF) @@ -1163,6 +1200,8 @@ typedef union _MPI25_SGE_IO_UNION { #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 */ diff --git a/drivers/scsi/mpt3sas/mpi/mpi2_cnfg.h b/drivers/scsi/mpt3sas/mpi/mpi2_cnfg.h index 036c9cf61032..ee117106d0f7 100644 --- a/drivers/scsi/mpt3sas/mpi/mpi2_cnfg.h +++ b/drivers/scsi/mpt3sas/mpi/mpi2_cnfg.h @@ -7,7 +7,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.40 * * 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 @@ -190,6 +190,35 @@ * MPI2_CONFIG_PAGE_BIOS_1. * 08-25-15 02.00.34 Bumped Header Version. * 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. + * 02-02-17 02.00.40 Added MPI2_MANPAGE7_SLOT_UNKNOWN. + * Added ChassisSlot field to SAS Enclosure Page 0. + * Added ChassisSlot Valid bit (bit 5) to the Flags field + * in SAS Enclosure Page 0. * -------------------------------------------------------------------------- */ @@ -273,6 +302,10 @@ typedef union _MPI2_CONFIG_EXT_PAGE_HEADER_UNION { #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) +#define MPI2_CONFIG_EXTPAGETYPE_PCIE_SWITCH (0x1C) +#define MPI2_CONFIG_EXTPAGETYPE_PCIE_DEVICE (0x1D) +#define MPI2_CONFIG_EXTPAGETYPE_PCIE_LINK (0x1E) /***************************************************************************** @@ -340,6 +373,12 @@ typedef union _MPI2_CONFIG_EXT_PAGE_HEADER_UNION { #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) @@ -366,6 +405,33 @@ typedef union _MPI2_CONFIG_EXT_PAGE_HEADER_UNION { #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 ****************************************************************************/ @@ -485,6 +551,12 @@ typedef struct _MPI2_CONFIG_REPLY { #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 */ @@ -727,6 +799,12 @@ typedef struct _MPI2_MANPAGE7_CONNECTOR_INFO { #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) @@ -737,6 +815,9 @@ typedef struct _MPI2_MANPAGE7_CONNECTOR_INFO { #define MPI2_MANPAGE7_LOCATION_NOT_PRESENT (0x20) #define MPI2_MANPAGE7_LOCATION_NOT_CONNECTED (0x80) +/*defines for the Slot field */ +#define MPI2_MANPAGE7_SLOT_UNKNOWN (0xFFFF) + /* *Host code (drivers, BIOS, utilities, etc.) should leave this define set to *one and check the value returned for NumPhys at runtime. @@ -1000,11 +1081,13 @@ typedef struct _MPI2_CONFIG_PAGE_IO_UNIT_7 { #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) @@ -1971,6 +2054,7 @@ typedef struct _MPI2_CONFIG_PAGE_RD_PDISK_1 { #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 */ @@ -2038,12 +2122,14 @@ typedef struct _MPI2_CONFIG_PAGE_RD_PDISK_1 { #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 */ @@ -2052,11 +2138,13 @@ typedef struct _MPI2_CONFIG_PAGE_RD_PDISK_1 { #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) @@ -2241,11 +2329,13 @@ typedef struct _MPI2_CONFIG_PAGE_SASIOUNIT_1 { #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 */ @@ -3159,37 +3249,29 @@ typedef struct _MPI2_CONFIG_PAGE_SAS_PORT_0 { /*SAS Enclosure Page 0 */ typedef struct _MPI2_CONFIG_PAGE_SAS_ENCLOSURE_0 { - MPI2_CONFIG_EXTENDED_PAGE_HEADER - Header; /*0x00 */ - U32 - Reserved1; /*0x08 */ - U64 - EnclosureLogicalID; /*0x0C */ - U16 - Flags; /*0x14 */ - U16 - EnclosureHandle; /*0x16 */ - U16 - NumSlots; /*0x18 */ - U16 - StartSlot; /*0x1A */ - U8 - Reserved2; /*0x1C */ - U8 - EnclosureLevel; /*0x1D */ - U16 - SEPDevHandle; /*0x1E */ - U32 - Reserved3; /*0x20 */ - U32 - Reserved4; /*0x24 */ + MPI2_CONFIG_EXTENDED_PAGE_HEADER Header; /*0x00 */ + U32 Reserved1; /*0x08 */ + U64 EnclosureLogicalID; /*0x0C */ + U16 Flags; /*0x14 */ + U16 EnclosureHandle; /*0x16 */ + U16 NumSlots; /*0x18 */ + U16 StartSlot; /*0x1A */ + U8 ChassisSlot; /*0x1C */ + U8 EnclosureLeve; /*0x1D */ + U16 SEPDevHandle; /*0x1E */ + U32 Reserved3; /*0x20 */ + U32 Reserved4; /*0x24 */ } MPI2_CONFIG_PAGE_SAS_ENCLOSURE_0, *PTR_MPI2_CONFIG_PAGE_SAS_ENCLOSURE_0, - Mpi2SasEnclosurePage0_t, *pMpi2SasEnclosurePage0_t; + Mpi2SasEnclosurePage0_t, *pMpi2SasEnclosurePage0_t, + MPI26_CONFIG_PAGE_ENCLOSURE_0, + *PTR_MPI26_CONFIG_PAGE_ENCLOSURE_0, + Mpi26EnclosurePage0_t, *pMpi26EnclosurePage0_t; #define MPI2_SASENCLOSURE0_PAGEVERSION (0x04) /*values for SAS Enclosure Page 0 Flags field */ +#define MPI2_SAS_ENCLS0_FLAGS_CHASSIS_SLOT_VALID (0x0020) #define MPI2_SAS_ENCLS0_FLAGS_ENCL_LEVEL_VALID (0x0010) #define MPI2_SAS_ENCLS0_FLAGS_MNG_MASK (0x000F) #define MPI2_SAS_ENCLS0_FLAGS_MNG_UNKNOWN (0x0000) @@ -3199,6 +3281,18 @@ typedef struct _MPI2_CONFIG_PAGE_SAS_ENCLOSURE_0 { #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_CHASSIS_SLOT_VALID (0x0020) +#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 @@ -3498,4 +3592,422 @@ typedef struct _MPI2_CONFIG_PAGE_EXT_MAN_PS { /*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, + *PTR_MPI26_PCIE_IO_UNIT0_PHY_DATA, + Mpi26PCIeIOUnit0PhyData_t, *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, + *PTR_MPI26_CONFIG_PAGE_PIOUNIT_0, + Mpi26PCIeIOUnitPage0_t, *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, + *PTR_MPI26_PCIE_IO_UNIT1_PHY_DATA, + Mpi26PCIeIOUnit1PhyData_t, *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, + *PTR_MPI26_CONFIG_PAGE_PIOUNIT_1, + Mpi26PCIeIOUnitPage1_t, *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, *PTR_MPI26_CONFIG_PAGE_PSWITCH_0, + Mpi26PCIeSwitchPage0_t, *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, *PTR_MPI26_CONFIG_PAGE_PSWITCH_1, + Mpi26PCIeSwitchPage1_t, *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, *PTR_MPI26_CONFIG_PAGE_PCIEDEV_0, + Mpi26PCIeDevicePage0_t, *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, *PTR_MPI26_CONFIG_PAGE_PCIEDEV_2, + Mpi26PCIeDevicePage2_t, *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, *PTR_MPI26_CONFIG_PAGE_PCIELINK_1, + Mpi26PcieLinkPage1_t, *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, *PTR_MPI26_PCIELINK2_LINK_EVENT, + Mpi26PcieLink2LinkEvent_t, *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, *PTR_MPI26_CONFIG_PAGE_PCIELINK_2, + Mpi26PcieLinkPage2_t, *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, *PTR_MPI26_PCIELINK3_LINK_EVENT_CONFIG, + Mpi26PcieLink3LinkEventConfig_t, *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, *PTR_MPI26_CONFIG_PAGE_PCIELINK_3, + Mpi26PcieLinkPage3_t, *pMpi26PcieLinkPage3_t; + +#define MPI26_PCIELINK3_PAGEVERSION (0x00) + + #endif diff --git a/drivers/scsi/mpt3sas/mpi/mpi2_init.h b/drivers/scsi/mpt3sas/mpi/mpi2_init.h index 38b2c879bf0f..948a3ba682d7 100644 --- a/drivers/scsi/mpt3sas/mpi/mpi2_init.h +++ b/drivers/scsi/mpt3sas/mpi/mpi2_init.h @@ -7,7 +7,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 @@ -55,6 +55,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. * -------------------------------------------------------------------------- */ @@ -374,6 +376,11 @@ typedef struct _MPI2_SCSI_IO_REPLY { } MPI2_SCSI_IO_REPLY, *PTR_MPI2_SCSI_IO_REPLY, Mpi2SCSIIOReply_t, *pMpi2SCSIIOReply_t; +/*SCSI IO Reply MsgFlags bits */ +#define MPI26_SCSIIO_REPLY_MSGFLAGS_REFTAG_OBSERVED_VALID (0x01) +#define MPI26_SCSIIO_REPLY_MSGFLAGS_GUARD_OBSERVED_VALID (0x02) +#define MPI26_SCSIIO_REPLY_MSGFLAGS_APPTAG_OBSERVED_VALID (0x04) + /*SCSI IO Reply SCSIStatus values (SAM-4 status codes) */ #define MPI2_SCSI_STATUS_GOOD (0x00) @@ -447,11 +454,13 @@ typedef struct _MPI2_SCSI_TASK_MANAGE_REQUEST { /*MsgFlags bits */ #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_NEXUS_RESET_SRST (0x08) #define MPI2_SCSITASKMGMT_MSGFLAGS_SAS_HARD_LINK_RESET (0x10) #define MPI2_SCSITASKMGMT_MSGFLAGS_DO_NOT_SEND_TASK_IU (0x01) +#define MPI26_SCSITASKMGMT_MSGFLAGS_PROTOCOL_LVL_RST_PCIE (0x18) /*SCSI Task Management Reply Message */ typedef struct _MPI2_SCSI_TASK_MANAGE_REPLY { diff --git a/drivers/scsi/mpt3sas/mpi/mpi2_ioc.h b/drivers/scsi/mpt3sas/mpi/mpi2_ioc.h index 673cf05f94dc..cc2aff7aa67b 100644 --- a/drivers/scsi/mpt3sas/mpi/mpi2_ioc.h +++ b/drivers/scsi/mpt3sas/mpi/mpi2_ioc.h @@ -7,7 +7,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.32 * * 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 @@ -141,7 +141,32 @@ * Added MPI26_FW_HEADER_PID_FAMILY_3324_SAS and * MPI26_FW_HEADER_PID_FAMILY_3516_SAS. * Added MPI26_CTRL_OP_SHUTDOWN. - * 08-25-15 02.00.27 Added IC ARCH Class based signature defines + * 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. + * 11-23-16 02.00.31 Added MPI2_EVENT_SAS_DEVICE_DISCOVERY_ERROR and + * MPI25_EVENT_DATA_SAS_DEVICE_DISCOVERY_ERROR. + * 02-02-17 02.00.32 Added MPI2_FW_DOWNLOAD_ITYPE_CBB_BACKUP. + * Added MPI25_EVENT_DATA_ACTIVE_CABLE_EXCEPT and related + * defines for the ReasonCode field. * -------------------------------------------------------------------------- */ @@ -213,6 +238,9 @@ typedef struct _MPI2_IOC_INIT_REQUEST { #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) @@ -300,6 +328,10 @@ typedef struct _MPI2_IOC_FACTS_REPLY { U16 MinDevHandle; /*0x3C */ U8 CurrentHostPageSize; /* 0x3E */ U8 Reserved4; /* 0x3F */ + U8 SGEModifierMask; /*0x40 */ + U8 SGEModifierValue; /*0x41 */ + U8 SGEModifierShift; /*0x42 */ + U8 Reserved5; /*0x43 */ } MPI2_IOC_FACTS_REPLY, *PTR_MPI2_IOC_FACTS_REPLY, Mpi2IOCFactsReply_t, *pMpi2IOCFactsReply_t; @@ -316,6 +348,7 @@ typedef struct _MPI2_IOC_FACTS_REPLY { #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) @@ -336,6 +369,7 @@ typedef struct _MPI2_IOC_FACTS_REPLY { /*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) @@ -354,6 +388,7 @@ typedef struct _MPI2_IOC_FACTS_REPLY { #define MPI2_IOCFACTS_CAPABILITY_TASK_SET_FULL_HANDLING (0x00000004) /*ProtocolFlags */ +#define MPI2_IOCFACTS_PROTOCOL_NVME_DEVICES (0x0008) #define MPI2_IOCFACTS_PROTOCOL_SCSI_INITIATOR (0x0002) #define MPI2_IOCFACTS_PROTOCOL_SCSI_TARGET (0x0001) @@ -403,6 +438,8 @@ typedef struct _MPI2_PORT_FACTS_REPLY { #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) + /**************************************************************************** * PortEnable message @@ -509,6 +546,7 @@ typedef struct _MPI2_EVENT_NOTIFICATION_REPLY { #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) #define MPI2_EVENT_IR_VOLUME (0x001E) #define MPI2_EVENT_IR_PHYSICAL_DISK (0x001F) #define MPI2_EVENT_IR_CONFIGURATION_CHANGE_LIST (0x0020) @@ -521,7 +559,12 @@ typedef struct _MPI2_EVENT_NOTIFICATION_REPLY { #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) +#define MPI2_EVENT_PCIE_ENUMERATION (0x0031) +#define MPI2_EVENT_PCIE_TOPOLOGY_CHANGE_LIST (0x0032) +#define MPI2_EVENT_PCIE_LINK_COUNTER (0x0033) #define MPI2_EVENT_ACTIVE_CABLE_EXCEPTION (0x0034) +#define MPI2_EVENT_SAS_DEVICE_DISCOVERY_ERROR (0x0035) #define MPI2_EVENT_MIN_PRODUCT_SPECIFIC (0x006E) #define MPI2_EVENT_MAX_PRODUCT_SPECIFIC (0x007F) @@ -618,11 +661,20 @@ typedef struct _MPI26_EVENT_DATA_ACTIVE_CABLE_EXCEPT { U8 ReasonCode; /* 0x04 */ U8 ReceptacleID; /* 0x05 */ U16 Reserved1; /* 0x06 */ -} MPI26_EVENT_DATA_ACTIVE_CABLE_EXCEPT, +} MPI25_EVENT_DATA_ACTIVE_CABLE_EXCEPT, + *PTR_MPI25_EVENT_DATA_ACTIVE_CABLE_EXCEPT, + Mpi25EventDataActiveCableExcept_t, + *pMpi25EventDataActiveCableExcept_t, + MPI26_EVENT_DATA_ACTIVE_CABLE_EXCEPT, *PTR_MPI26_EVENT_DATA_ACTIVE_CABLE_EXCEPT, Mpi26EventDataActiveCableExcept_t, *pMpi26EventDataActiveCableExcept_t; +/*MPI2.5 defines for the ReasonCode field */ +#define MPI25_EVENT_ACTIVE_CABLE_INSUFFICIENT_POWER (0x00) +#define MPI25_EVENT_ACTIVE_CABLE_PRESENT (0x01) +#define MPI25_EVENT_ACTIVE_CABLE_DEGRADED (0x02) + /* defines for ReasonCode field */ #define MPI26_EVENT_ACTIVE_CABLE_INSUFFICIENT_POWER (0x00) #define MPI26_EVENT_ACTIVE_CABLE_PRESENT (0x01) @@ -958,6 +1010,7 @@ typedef struct _MPI2_EVENT_DATA_SAS_TOPOLOGY_CHANGE_LIST { #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) @@ -983,12 +1036,37 @@ typedef struct _MPI2_EVENT_DATA_SAS_ENCL_DEV_STATUS_CHANGE { } MPI2_EVENT_DATA_SAS_ENCL_DEV_STATUS_CHANGE, *PTR_MPI2_EVENT_DATA_SAS_ENCL_DEV_STATUS_CHANGE, Mpi2EventDataSasEnclDevStatusChange_t, - *pMpi2EventDataSasEnclDevStatusChange_t; + *pMpi2EventDataSasEnclDevStatusChange_t, + MPI26_EVENT_DATA_ENCL_DEV_STATUS_CHANGE, + *PTR_MPI26_EVENT_DATA_ENCL_DEV_STATUS_CHANGE, + Mpi26EventDataEnclDevStatusChange_t, + *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) + + +typedef struct _MPI25_EVENT_DATA_SAS_DEVICE_DISCOVERY_ERROR { + U16 DevHandle; /*0x00 */ + U8 ReasonCode; /*0x02 */ + U8 PhysicalPort; /*0x03 */ + U32 Reserved1[2]; /*0x04 */ + U64 SASAddress; /*0x0C */ + U32 Reserved2[2]; /*0x14 */ +} MPI25_EVENT_DATA_SAS_DEVICE_DISCOVERY_ERROR, + *PTR_MPI25_EVENT_DATA_SAS_DEVICE_DISCOVERY_ERROR, + Mpi25EventDataSasDeviceDiscoveryError_t, + *pMpi25EventDataSasDeviceDiscoveryError_t; + +/*SAS Device Discovery Error Event data ReasonCode values */ +#define MPI25_EVENT_SAS_DISC_ERR_SMP_FAILED (0x01) +#define MPI25_EVENT_SAS_DISC_ERR_SMP_TIMEOUT (0x02) + /*SAS PHY Counter Event data */ typedef struct _MPI2_EVENT_DATA_SAS_PHY_COUNTER { @@ -1074,6 +1152,174 @@ typedef struct _MPI2_EVENT_DATA_HBD_PHY { /*values for the DescriptorType field */ #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, + *PTR_MPI26_EVENT_DATA_PCIE_DEVICE_STATUS_CHANGE, + Mpi26EventDataPCIeDeviceStatusChange_t, + *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, + *PTR_MPI26_EVENT_DATA_PCIE_ENUMERATION, + Mpi26EventDataPCIeEnumeration_t, + *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, + *PTR_MPI26_EVENT_PCIE_TOPO_PORT_ENTRY, + Mpi26EventPCIeTopoPortEntry_t, + *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, + *PTR_MPI26_EVENT_DATA_PCIE_TOPOLOGY_CHANGE_LIST, + Mpi26EventDataPCIeTopologyChangeList_t, + *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, + *PTR_MPI26_EVENT_DATA_PCIE_LINK_COUNTER, + Mpi26EventDataPcieLinkCounter_t, *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 ****************************************************************************/ @@ -1191,6 +1437,14 @@ typedef struct _MPI2_FW_DOWNLOAD_REQUEST { #define MPI2_FW_DOWNLOAD_ITYPE_COMPLETE (0x0A) #define MPI2_FW_DOWNLOAD_ITYPE_COMMON_BOOT_BLOCK (0x0B) #define MPI2_FW_DOWNLOAD_ITYPE_PUBLIC_KEY (0x0C) +#define MPI2_FW_DOWNLOAD_ITYPE_CBB_BACKUP (0x0D) +#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 */ @@ -1277,6 +1531,14 @@ typedef struct _MPI2_FW_UPLOAD_REQUEST { #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 { @@ -1395,10 +1657,13 @@ typedef struct _MPI2_FW_IMAGE_HEADER { #define MPI26_FW_HEADER_SIGNATURE0_ARC_1 (0x00) #define MPI26_FW_HEADER_SIGNATURE0_ARC_2 (0x01) /* legacy (0x5AEAA55A) */ +#define MPI26_FW_HEADER_SIGNATURE0_ARC_3 (0x02) #define MPI26_FW_HEADER_SIGNATURE0 \ (MPI26_FW_HEADER_SIGNATURE0_BASE+MPI26_FW_HEADER_SIGNATURE0_ARC_0) #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) @@ -1542,6 +1807,13 @@ typedef struct _MPI2_FLASH_LAYOUT_DATA { #define MPI2_FLASH_REGION_COMMON_BOOT_BLOCK (0x0A) #define MPI2_FLASH_REGION_INIT (MPI2_FLASH_REGION_COMMON_BOOT_BLOCK) #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) @@ -1826,6 +2098,8 @@ typedef struct _MPI26_IOUNIT_CONTROL_REQUEST { #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 */ diff --git a/drivers/scsi/mpt3sas/mpi/mpi2_pci.h b/drivers/scsi/mpt3sas/mpi/mpi2_pci.h new file mode 100644 index 000000000000..f0281f943ec9 --- /dev/null +++ b/drivers/scsi/mpt3sas/mpi/mpi2_pci.h @@ -0,0 +1,111 @@ +/* + * Copyright 2012-2015 Avago Technologies. All rights reserved. + * + * + * Name: mpi2_pci.h + * Title: MPI PCIe Attached Devices structures and definitions. + * Creation Date: October 9, 2012 + * + * mpi2_pci.h Version: 02.00.02 + * + * NOTE: Names (typedefs, defines, etc.) beginning with an MPI25 or Mpi25 + * prefix are for use only on MPI v2.5 products, and must not be used + * with MPI v2.0 products. Unless otherwise noted, names beginning with + * MPI2 or Mpi2 are for use with both MPI v2.0 and MPI v2.5 products. + * + * Version History + * --------------- + * + * Date Version Description + * -------- -------- ------------------------------------------------------ + * 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. + * -------------------------------------------------------------------------- + */ + +#ifndef MPI2_PCI_H +#define MPI2_PCI_H + + +/* + *Values for the PCIe DeviceInfo field used in PCIe Device Status Change Event + *data and PCIe Configuration pages. + */ +#define MPI26_PCIE_DEVINFO_DIRECT_ATTACH (0x00000010) + +#define MPI26_PCIE_DEVINFO_MASK_DEVICE_TYPE (0x0000000F) +#define MPI26_PCIE_DEVINFO_NO_DEVICE (0x00000000) +#define MPI26_PCIE_DEVINFO_PCI_SWITCH (0x00000001) +#define MPI26_PCIE_DEVINFO_NVME (0x00000003) + + +/**************************************************************************** +* NVMe Encapsulated message +****************************************************************************/ + +/*NVME Encapsulated Request Message */ +typedef struct _MPI26_NVME_ENCAPSULATED_REQUEST { + U16 DevHandle; /*0x00 */ + U8 ChainOffset; /*0x02 */ + U8 Function; /*0x03 */ + U16 EncapsulatedCommandLength; /*0x04 */ + U8 Reserved1; /*0x06 */ + U8 MsgFlags; /*0x07 */ + U8 VP_ID; /*0x08 */ + U8 VF_ID; /*0x09 */ + U16 Reserved2; /*0x0A */ + U32 Reserved3; /*0x0C */ + U64 ErrorResponseBaseAddress; /*0x10 */ + U16 ErrorResponseAllocationLength; /*0x18 */ + U16 Flags; /*0x1A */ + U32 DataLength; /*0x1C */ + U8 NVMe_Command[4]; /*0x20 */ + +} MPI26_NVME_ENCAPSULATED_REQUEST, *PTR_MPI26_NVME_ENCAPSULATED_REQUEST, + Mpi26NVMeEncapsulatedRequest_t, *pMpi26NVMeEncapsulatedRequest_t; + +/*defines for the Flags field */ +#define MPI26_NVME_FLAGS_FORCE_ADMIN_ERR_RESP (0x0020) +/*Submission Queue Type*/ +#define MPI26_NVME_FLAGS_SUBMISSIONQ_MASK (0x0010) +#define MPI26_NVME_FLAGS_SUBMISSIONQ_IO (0x0000) +#define MPI26_NVME_FLAGS_SUBMISSIONQ_ADMIN (0x0010) +/*Error Response Address Space */ +#define MPI26_NVME_FLAGS_MASK_ERROR_RSP_ADDR (0x000C) +#define MPI26_NVME_FLAGS_SYSTEM_RSP_ADDR (0x0000) +#define MPI26_NVME_FLAGS_IOCPLB_RSP_ADDR (0x0008) +#define MPI26_NVME_FLAGS_IOCPLBNTA_RSP_ADDR (0x000C) +/*Data Direction*/ +#define MPI26_NVME_FLAGS_DATADIRECTION_MASK (0x0003) +#define MPI26_NVME_FLAGS_NODATATRANSFER (0x0000) +#define MPI26_NVME_FLAGS_WRITE (0x0001) +#define MPI26_NVME_FLAGS_READ (0x0002) +#define MPI26_NVME_FLAGS_BIDIRECTIONAL (0x0003) + + +/*NVMe Encapuslated Reply Message */ +typedef struct _MPI26_NVME_ENCAPSULATED_ERROR_REPLY { + U16 DevHandle; /*0x00 */ + U8 MsgLength; /*0x02 */ + U8 Function; /*0x03 */ + U16 EncapsulatedCommandLength; /*0x04 */ + U8 Reserved1; /*0x06 */ + U8 MsgFlags; /*0x07 */ + U8 VP_ID; /*0x08 */ + U8 VF_ID; /*0x09 */ + U16 Reserved2; /*0x0A */ + U16 Reserved3; /*0x0C */ + U16 IOCStatus; /*0x0E */ + U32 IOCLogInfo; /*0x10 */ + U16 ErrorResponseCount; /*0x14 */ + U16 Reserved4; /*0x16 */ +} MPI26_NVME_ENCAPSULATED_ERROR_REPLY, + *PTR_MPI26_NVME_ENCAPSULATED_ERROR_REPLY, + Mpi26NVMeEncapsulatedErrorReply_t, + *pMpi26NVMeEncapsulatedErrorReply_t; + + +#endif diff --git a/drivers/scsi/mpt3sas/mpi/mpi2_tool.h b/drivers/scsi/mpt3sas/mpi/mpi2_tool.h index 593765a4ddb8..629296ee9236 100644 --- a/drivers/scsi/mpt3sas/mpi/mpi2_tool.h +++ b/drivers/scsi/mpt3sas/mpi/mpi2_tool.h @@ -7,7 +7,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 * --------------- @@ -36,6 +36,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. * -------------------------------------------------------------------------- */ @@ -106,6 +108,16 @@ typedef struct _MPI2_TOOLBOX_CLEAN_REQUEST { #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) diff --git a/drivers/scsi/mpt3sas/mpt3sas_base.c b/drivers/scsi/mpt3sas/mpt3sas_base.c index 87999905bca3..8027de465d47 100644 --- a/drivers/scsi/mpt3sas/mpt3sas_base.c +++ b/drivers/scsi/mpt3sas/mpt3sas_base.c @@ -59,6 +59,7 @@ #include <linux/time.h> #include <linux/ktime.h> #include <linux/kthread.h> +#include <asm/page.h> /* To get host page size per arch */ #include <linux/aer.h> @@ -105,7 +106,7 @@ _base_get_ioc_facts(struct MPT3SAS_ADAPTER *ioc); * */ static int -_scsih_set_fwfault_debug(const char *val, struct kernel_param *kp) +_scsih_set_fwfault_debug(const char *val, const struct kernel_param *kp) { int ret = param_set_int(val, kp); struct MPT3SAS_ADAPTER *ioc; @@ -556,6 +557,11 @@ _base_sas_ioc_info(struct MPT3SAS_ADAPTER *ioc, MPI2DefaultReply_t *mpi_reply, frame_sz = sizeof(Mpi2SmpPassthroughRequest_t) + ioc->sge_size; func_str = "smp_passthru"; break; + case MPI2_FUNCTION_NVME_ENCAPSULATED: + frame_sz = sizeof(Mpi26NVMeEncapsulatedRequest_t) + + ioc->sge_size; + func_str = "nvme_encapsulated"; + break; default: frame_sz = 32; func_str = "unknown"; @@ -655,7 +661,27 @@ _base_display_event_data(struct MPT3SAS_ADAPTER *ioc, desc = "Temperature Threshold"; break; case MPI2_EVENT_ACTIVE_CABLE_EXCEPTION: - desc = "Active cable exception"; + desc = "Cable Event"; + break; + case MPI2_EVENT_PCIE_DEVICE_STATUS_CHANGE: + desc = "PCIE Device Status Change"; + break; + case MPI2_EVENT_PCIE_ENUMERATION: + { + Mpi26EventDataPCIeEnumeration_t *event_data = + (Mpi26EventDataPCIeEnumeration_t *)mpi_reply->EventData; + pr_info(MPT3SAS_FMT "PCIE Enumeration: (%s)", ioc->name, + (event_data->ReasonCode == + MPI26_EVENT_PCIE_ENUM_RC_STARTED) ? + "start" : "stop"); + if (event_data->EnumerationStatus) + pr_info("enumeration_status(0x%08x)", + le32_to_cpu(event_data->EnumerationStatus)); + pr_info("\n"); + return; + } + case MPI2_EVENT_PCIE_TOPOLOGY_CHANGE_LIST: + desc = "PCIE Topology Change List"; break; } @@ -984,7 +1010,9 @@ _base_interrupt(int irq, void *bus_id) if (request_desript_type == MPI25_RPY_DESCRIPT_FLAGS_FAST_PATH_SCSI_IO_SUCCESS || request_desript_type == - MPI2_RPY_DESCRIPT_FLAGS_SCSI_IO_SUCCESS) { + MPI2_RPY_DESCRIPT_FLAGS_SCSI_IO_SUCCESS || + request_desript_type == + MPI26_RPY_DESCRIPT_FLAGS_PCIE_ENCAPSULATED_SUCCESS) { cb_idx = _base_get_cb_idx(ioc, smid); if ((likely(cb_idx < MPT_MAX_CALLBACKS)) && (likely(mpt_callbacks[cb_idx] != NULL))) { @@ -1347,6 +1375,433 @@ _base_build_sg(struct MPT3SAS_ADAPTER *ioc, void *psge, /* IEEE format sgls */ /** + * _base_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 at the beginning of a 4KB physical memory page, and the offset + * describes where within that 4KB 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 4KB page. + * + * Each PRP element normally describes 4KB of 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 4KB page, then the + * first PRP element will contain a non-zero offset indicating where the region + * begins within the 4KB page. The last memory segment may end before the end + * of the 4KB 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. + * + * @ioc: per adapter object + * @smid: system request message index for getting asscociated SGL + * @nvme_encap_request: the NVMe request msg frame pointer + * @data_out_dma: physical address for WRITES + * @data_out_sz: data xfer size for WRITES + * @data_in_dma: physical address for READS + * @data_in_sz: data xfer size for READS + * + * Returns nothing. + */ +static void +_base_build_nvme_prp(struct MPT3SAS_ADAPTER *ioc, u16 smid, + Mpi26NVMeEncapsulatedRequest_t *nvme_encap_request, + dma_addr_t data_out_dma, size_t data_out_sz, dma_addr_t data_in_dma, + size_t data_in_sz) +{ + int prp_size = NVME_PRP_SIZE; + __le64 *prp_entry, *prp1_entry, *prp2_entry; + __le64 *prp_page; + dma_addr_t prp_entry_dma, prp_page_dma, dma_addr; + u32 offset, entry_len; + u32 page_mask_result, page_mask; + size_t length; + + /* + * 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 = (__le64 *)(nvme_encap_request->NVMe_Command + + NVME_CMD_PRP1_OFFSET); + prp2_entry = (__le64 *)(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 = (__le64 *)mpt3sas_base_get_pcie_sgl(ioc, smid); + prp_page_dma = mpt3sas_base_get_pcie_sgl_dma(ioc, smid); + + /* + * 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 = ioc->page_size - 1; + page_mask_result = (uintptr_t)((u8 *)prp_page + prp_size) & page_mask; + if (!page_mask_result) { + /* Bump up to next page boundary. */ + prp_page = (__le64 *)((u8 *)prp_page + prp_size); + prp_page_dma = prp_page_dma + prp_size; + } + + /* + * Set PRP physical pointer, which initially points to the current PRP + * DMA memory page. + */ + prp_entry_dma = prp_page_dma; + + /* Get physical address and length of the data buffer. */ + if (data_in_sz) { + dma_addr = data_in_dma; + length = data_in_sz; + } else { + dma_addr = data_out_dma; + 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 = (prp_entry_dma + 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_dma++; + *prp_entry = cpu_to_le64(prp_entry_dma); + prp_entry++; + } + + /* Need to handle if entry will be part of a page. */ + offset = dma_addr & page_mask; + entry_len = ioc->page_size - offset; + + if (prp_entry == prp1_entry) { + /* + * Must fill in the first PRP pointer (PRP1) before + * moving on. + */ + *prp1_entry = cpu_to_le64(dma_addr); + + /* + * 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 > ioc->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 = cpu_to_le64(prp_entry_dma); + + /* + * 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 = cpu_to_le64(dma_addr); + } + } 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 = cpu_to_le64(dma_addr); + prp_entry++; + prp_entry_dma++; + } + + /* + * Bump the phys address of the command's data buffer by the + * entry_len. + */ + dma_addr += entry_len; + + /* Decrement length accounting for last partial page. */ + if (entry_len > length) + length = 0; + else + length -= entry_len; + } +} + +/** + * base_make_prp_nvme - + * Prepare PRPs(Physical Region Page)- SGLs specific to NVMe drives only + * + * @ioc: per adapter object + * @scmd: SCSI command from the mid-layer + * @mpi_request: mpi request + * @smid: msg Index + * @sge_count: scatter gather element count. + * + * Returns: true: PRPs are built + * false: IEEE SGLs needs to be built + */ +static void +base_make_prp_nvme(struct MPT3SAS_ADAPTER *ioc, + struct scsi_cmnd *scmd, + Mpi25SCSIIORequest_t *mpi_request, + u16 smid, int sge_count) +{ + int sge_len, num_prp_in_chain = 0; + Mpi25IeeeSgeChain64_t *main_chain_element, *ptr_first_sgl; + __le64 *curr_buff; + dma_addr_t msg_dma, sge_addr, offset; + u32 page_mask, page_mask_result; + struct scatterlist *sg_scmd; + u32 first_prp_len; + int data_len = scsi_bufflen(scmd); + u32 nvme_pg_size; + + nvme_pg_size = max_t(u32, ioc->page_size, NVME_PRP_PAGE_SIZE); + /* + * Nvme has a very convoluted prp format. One prp is required + * for each page or partial page. Driver need to split up OS sg_list + * entries if it is longer than one page or cross a page + * boundary. Driver 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 as 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. + */ + page_mask = nvme_pg_size - 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)&mpi_request->SGL; + /* + * For NVMe the chain element needs to be the 2nd SG entry in the main + * message. + */ + main_chain_element = (Mpi25IeeeSgeChain64_t *) + ((u8 *)main_chain_element + sizeof(MPI25_IEEE_SGE_CHAIN64)); + + /* + * For the PRP entries, use the specially allocated buffer of + * contiguous memory. Normal chain buffers can't be used + * because each chain buffer would need to be the size of an OS + * page (4k). + */ + curr_buff = mpt3sas_base_get_pcie_sgl(ioc, smid); + msg_dma = mpt3sas_base_get_pcie_sgl_dma(ioc, smid); + + main_chain_element->Address = cpu_to_le64(msg_dma); + 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; + + /* Build first prp, sge need not to be page aligned*/ + ptr_first_sgl = (pMpi25IeeeSgeChain64_t)&mpi_request->SGL; + sg_scmd = scsi_sglist(scmd); + sge_addr = sg_dma_address(sg_scmd); + sge_len = sg_dma_len(sg_scmd); + + offset = sge_addr & page_mask; + first_prp_len = nvme_pg_size - offset; + + ptr_first_sgl->Address = cpu_to_le64(sge_addr); + ptr_first_sgl->Length = cpu_to_le32(first_prp_len); + + data_len -= first_prp_len; + + if (sge_len > first_prp_len) { + sge_addr += first_prp_len; + sge_len -= first_prp_len; + } else if (data_len && (sge_len == first_prp_len)) { + sg_scmd = sg_next(sg_scmd); + sge_addr = sg_dma_address(sg_scmd); + sge_len = sg_dma_len(sg_scmd); + } + + for (;;) { + offset = sge_addr & page_mask; + + /* Put PRP pointer due to page boundary*/ + page_mask_result = (uintptr_t)(curr_buff + 1) & page_mask; + if (unlikely(!page_mask_result)) { + scmd_printk(KERN_NOTICE, + scmd, "page boundary curr_buff: 0x%p\n", + curr_buff); + msg_dma += 8; + *curr_buff = cpu_to_le64(msg_dma); + curr_buff++; + num_prp_in_chain++; + } + + *curr_buff = cpu_to_le64(sge_addr); + curr_buff++; + msg_dma += 8; + num_prp_in_chain++; + + sge_addr += nvme_pg_size; + sge_len -= nvme_pg_size; + data_len -= nvme_pg_size; + + if (data_len <= 0) + break; + + if (sge_len > 0) + continue; + + sg_scmd = sg_next(sg_scmd); + sge_addr = sg_dma_address(sg_scmd); + sge_len = sg_dma_len(sg_scmd); + } + + main_chain_element->Length = + cpu_to_le32(num_prp_in_chain * sizeof(u64)); + return; +} + +static bool +base_is_prp_possible(struct MPT3SAS_ADAPTER *ioc, + struct _pcie_device *pcie_device, struct scsi_cmnd *scmd, int sge_count) +{ + u32 data_length = 0; + struct scatterlist *sg_scmd; + bool build_prp = true; + + data_length = scsi_bufflen(scmd); + sg_scmd = scsi_sglist(scmd); + + /* If Datalenth is <= 16K and number of SGE’s entries are <= 2 + * we built IEEE SGL + */ + if ((data_length <= NVME_PRP_PAGE_SIZE*4) && (sge_count <= 2)) + build_prp = false; + + return build_prp; +} + +/** + * _base_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 special 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. + * @ioc: per adapter object + * @mpi_request: mf request pointer + * @smid: system request message index + * @scmd: scsi command + * @pcie_device: points to the PCIe device's info + * + * Returns 0 if native SGL was built, 1 if no SGL was built + */ +static int +_base_check_pcie_native_sgl(struct MPT3SAS_ADAPTER *ioc, + Mpi25SCSIIORequest_t *mpi_request, u16 smid, struct scsi_cmnd *scmd, + struct _pcie_device *pcie_device) +{ + struct scatterlist *sg_scmd; + int sges_left; + + /* Get the SG list pointer and info. */ + sg_scmd = scsi_sglist(scmd); + sges_left = scsi_dma_map(scmd); + if (sges_left < 0) { + sdev_printk(KERN_ERR, scmd->device, + "scsi_dma_map failed: request for %d bytes!\n", + scsi_bufflen(scmd)); + return 1; + } + + /* Check if we need to build a native SG list. */ + if (base_is_prp_possible(ioc, pcie_device, + scmd, sges_left) == 0) { + /* We built a native SG list, just return. */ + goto out; + } + + /* + * Build native NVMe PRP. + */ + base_make_prp_nvme(ioc, scmd, mpi_request, + smid, sges_left); + + return 0; +out: + scsi_dma_unmap(scmd); + return 1; +} + +/** * _base_add_sg_single_ieee - add sg element for IEEE format * @paddr: virtual address for SGE * @flags: SGE flags @@ -1391,9 +1846,11 @@ _base_build_zero_len_sge_ieee(struct MPT3SAS_ADAPTER *ioc, void *paddr) /** * _base_build_sg_scmd - main sg creation routine + * pcie_device is unused here! * @ioc: per adapter object * @scmd: scsi command * @smid: system request message index + * @unused: unused pcie_device pointer * Context: none. * * The main routine that builds scatter gather table from a given @@ -1403,7 +1860,7 @@ _base_build_zero_len_sge_ieee(struct MPT3SAS_ADAPTER *ioc, void *paddr) */ static int _base_build_sg_scmd(struct MPT3SAS_ADAPTER *ioc, - struct scsi_cmnd *scmd, u16 smid) + struct scsi_cmnd *scmd, u16 smid, struct _pcie_device *unused) { Mpi2SCSIIORequest_t *mpi_request; dma_addr_t chain_dma; @@ -1537,6 +1994,8 @@ _base_build_sg_scmd(struct MPT3SAS_ADAPTER *ioc, * @ioc: per adapter object * @scmd: scsi command * @smid: system request message index + * @pcie_device: Pointer to pcie_device. If set, the pcie native sgl will be + * constructed on need. * Context: none. * * The main routine that builds scatter gather table from a given @@ -1546,9 +2005,9 @@ _base_build_sg_scmd(struct MPT3SAS_ADAPTER *ioc, */ static int _base_build_sg_scmd_ieee(struct MPT3SAS_ADAPTER *ioc, - struct scsi_cmnd *scmd, u16 smid) + struct scsi_cmnd *scmd, u16 smid, struct _pcie_device *pcie_device) { - Mpi2SCSIIORequest_t *mpi_request; + Mpi25SCSIIORequest_t *mpi_request; dma_addr_t chain_dma; struct scatterlist *sg_scmd; void *sg_local, *chain; @@ -1571,6 +2030,13 @@ _base_build_sg_scmd_ieee(struct MPT3SAS_ADAPTER *ioc, chain_sgl_flags = MPI2_IEEE_SGE_FLAGS_CHAIN_ELEMENT | MPI2_IEEE_SGE_FLAGS_SYSTEM_ADDR; + /* Check if we need to build a native SG list. */ + if ((pcie_device) && (_base_check_pcie_native_sgl(ioc, mpi_request, + smid, scmd, pcie_device) == 0)) { + /* We built a native SG list, just return. */ + return 0; + } + sg_scmd = scsi_sglist(scmd); sges_left = scsi_dma_map(scmd); if (sges_left < 0) { @@ -1582,12 +2048,12 @@ _base_build_sg_scmd_ieee(struct MPT3SAS_ADAPTER *ioc, sg_local = &mpi_request->SGL; sges_in_segment = (ioc->request_sz - - offsetof(Mpi2SCSIIORequest_t, SGL))/ioc->sge_size_ieee; + offsetof(Mpi25SCSIIORequest_t, SGL))/ioc->sge_size_ieee; if (sges_left <= sges_in_segment) goto fill_in_last_segment; mpi_request->ChainOffset = (sges_in_segment - 1 /* chain element */) + - (offsetof(Mpi2SCSIIORequest_t, SGL)/ioc->sge_size_ieee); + (offsetof(Mpi25SCSIIORequest_t, SGL)/ioc->sge_size_ieee); /* fill in main message segment when there is a chain following */ while (sges_in_segment > 1) { @@ -1990,7 +2456,7 @@ _base_enable_msix(struct MPT3SAS_ADAPTER *ioc) ioc->cpu_count, max_msix_vectors); if (!ioc->rdpq_array_enable && max_msix_vectors == -1) - local_max_msix_vectors = 8; + local_max_msix_vectors = (reset_devices) ? 1 : 8; else local_max_msix_vectors = max_msix_vectors; @@ -2267,6 +2733,32 @@ mpt3sas_base_get_sense_buffer_dma(struct MPT3SAS_ADAPTER *ioc, u16 smid) } /** + * mpt3sas_base_get_pcie_sgl - obtain a PCIe SGL virt addr + * @ioc: per adapter object + * @smid: system request message index + * + * Returns virt pointer to a PCIe SGL. + */ +void * +mpt3sas_base_get_pcie_sgl(struct MPT3SAS_ADAPTER *ioc, u16 smid) +{ + return (void *)(ioc->scsi_lookup[smid - 1].pcie_sg_list.pcie_sgl); +} + +/** + * mpt3sas_base_get_pcie_sgl_dma - obtain a PCIe SGL dma addr + * @ioc: per adapter object + * @smid: system request message index + * + * Returns phys pointer to the address of the PCIe buffer. + */ +dma_addr_t +mpt3sas_base_get_pcie_sgl_dma(struct MPT3SAS_ADAPTER *ioc, u16 smid) +{ + return ioc->scsi_lookup[smid - 1].pcie_sg_list.pcie_sgl_dma; +} + +/** * mpt3sas_base_get_reply_virt_addr - obtain reply frames virt address * @ioc: per adapter object * @phys_addr: lower 32 physical addr of the reply @@ -2544,6 +3036,30 @@ _base_put_smid_hi_priority(struct MPT3SAS_ADAPTER *ioc, u16 smid, } /** + * _base_put_smid_nvme_encap - send NVMe encapsulated request to + * firmware + * @ioc: per adapter object + * @smid: system request message index + * + * Return nothing. + */ +static void +_base_put_smid_nvme_encap(struct MPT3SAS_ADAPTER *ioc, u16 smid) +{ + Mpi2RequestDescriptorUnion_t descriptor; + u64 *request = (u64 *)&descriptor; + + descriptor.Default.RequestFlags = + MPI26_REQ_DESCRIPT_FLAGS_PCIE_ENCAPSULATED; + descriptor.Default.MSIxIndex = _base_get_msix_index(ioc); + descriptor.Default.SMID = cpu_to_le16(smid); + descriptor.Default.LMID = 0; + descriptor.Default.DescriptorTypeDependent = 0; + _base_writeq(*request, &ioc->chip->RequestDescriptorPostLow, + &ioc->scsi_lookup_lock); +} + +/** * _base_put_smid_default - Default, primarily used for config pages * @ioc: per adapter object * @smid: system request message index @@ -2634,6 +3150,27 @@ _base_put_smid_hi_priority_atomic(struct MPT3SAS_ADAPTER *ioc, u16 smid, } /** + * _base_put_smid_nvme_encap_atomic - send NVMe encapsulated request to + * firmware using Atomic Request Descriptor + * @ioc: per adapter object + * @smid: system request message index + * + * Return nothing. + */ +static void +_base_put_smid_nvme_encap_atomic(struct MPT3SAS_ADAPTER *ioc, u16 smid) +{ + Mpi26AtomicRequestDescriptor_t descriptor; + u32 *request = (u32 *)&descriptor; + + descriptor.RequestFlags = MPI26_REQ_DESCRIPT_FLAGS_PCIE_ENCAPSULATED; + descriptor.MSIxIndex = _base_get_msix_index(ioc); + descriptor.SMID = cpu_to_le16(smid); + + writel(cpu_to_le32(*request), &ioc->chip->AtomicRequestDescriptorPost); +} + +/** * _base_put_smid_default - Default, primarily used for config pages * use Atomic Request Descriptor * @ioc: per adapter object @@ -2945,6 +3482,11 @@ _base_display_ioc_capabilities(struct MPT3SAS_ADAPTER *ioc) _base_display_OEMs_branding(ioc); + if (ioc->facts.ProtocolFlags & MPI2_IOCFACTS_PROTOCOL_NVME_DEVICES) { + pr_info("%sNVMe", i ? "," : ""); + i++; + } + pr_info(MPT3SAS_FMT "Protocol=(", ioc->name); if (ioc->facts.ProtocolFlags & MPI2_IOCFACTS_PROTOCOL_SCSI_INITIATOR) { @@ -3245,6 +3787,17 @@ _base_release_memory_pools(struct MPT3SAS_ADAPTER *ioc) kfree(ioc->reply_post); } + if (ioc->pcie_sgl_dma_pool) { + for (i = 0; i < ioc->scsiio_depth; i++) { + if (ioc->scsi_lookup[i].pcie_sg_list.pcie_sgl) + pci_pool_free(ioc->pcie_sgl_dma_pool, + ioc->scsi_lookup[i].pcie_sg_list.pcie_sgl, + ioc->scsi_lookup[i].pcie_sg_list.pcie_sgl_dma); + } + if (ioc->pcie_sgl_dma_pool) + pci_pool_destroy(ioc->pcie_sgl_dma_pool); + } + if (ioc->config_page) { dexitprintk(ioc, pr_info(MPT3SAS_FMT "config_page(0x%p): free\n", ioc->name, @@ -3286,7 +3839,7 @@ _base_allocate_memory_pools(struct MPT3SAS_ADAPTER *ioc) u16 chains_needed_per_io; u32 sz, total_sz, reply_post_free_sz; u32 retry_sz; - u16 max_request_credit; + u16 max_request_credit, nvme_blocks_needed; unsigned short sg_tablesize; u16 sge_size; int i; @@ -3308,6 +3861,11 @@ _base_allocate_memory_pools(struct MPT3SAS_ADAPTER *ioc) sg_tablesize = MPT3SAS_SG_DEPTH; } + /* max sgl entries <= MPT_KDUMP_MIN_PHYS_SEGMENTS in KDUMP mode */ + if (reset_devices) + sg_tablesize = min_t(unsigned short, sg_tablesize, + MPT_KDUMP_MIN_PHYS_SEGMENTS); + if (sg_tablesize < MPT_MIN_PHYS_SEGMENTS) sg_tablesize = MPT_MIN_PHYS_SEGMENTS; else if (sg_tablesize > MPT_MAX_PHYS_SEGMENTS) { @@ -3340,7 +3898,10 @@ _base_allocate_memory_pools(struct MPT3SAS_ADAPTER *ioc) ioc->internal_depth, facts->RequestCredit); if (max_request_credit > MAX_HBA_QUEUE_DEPTH) max_request_credit = MAX_HBA_QUEUE_DEPTH; - } else + } else if (reset_devices) + max_request_credit = min_t(u16, facts->RequestCredit, + (MPT3SAS_KDUMP_SCSI_IO_DEPTH + ioc->internal_depth)); + else max_request_credit = min_t(u16, facts->RequestCredit, MAX_HBA_QUEUE_DEPTH); @@ -3622,7 +4183,52 @@ _base_allocate_memory_pools(struct MPT3SAS_ADAPTER *ioc) "internal(0x%p): depth(%d), start smid(%d)\n", ioc->name, ioc->internal, ioc->internal_depth, ioc->internal_smid)); + /* + * The number of NVMe page sized blocks needed is: + * (((sg_tablesize * 8) - 1) / (page_size - 8)) + 1 + * ((sg_tablesize * 8) - 1) is the max PRP's minus the first PRP entry + * that is placed in the main message frame. 8 is the size of each PRP + * entry or PRP list pointer entry. 8 is subtracted from page_size + * because of the PRP list pointer entry at the end of a page, so this + * is not counted as a PRP entry. The 1 added page is a round up. + * + * To avoid allocation failures due to the amount of memory that could + * be required for NVMe PRP's, only each set of NVMe blocks will be + * contiguous, so a new set is allocated for each possible I/O. + */ + if (ioc->facts.ProtocolFlags & MPI2_IOCFACTS_PROTOCOL_NVME_DEVICES) { + nvme_blocks_needed = + (ioc->shost->sg_tablesize * NVME_PRP_SIZE) - 1; + nvme_blocks_needed /= (ioc->page_size - NVME_PRP_SIZE); + nvme_blocks_needed++; + + sz = nvme_blocks_needed * ioc->page_size; + ioc->pcie_sgl_dma_pool = + pci_pool_create("PCIe SGL pool", ioc->pdev, sz, 16, 0); + if (!ioc->pcie_sgl_dma_pool) { + pr_info(MPT3SAS_FMT + "PCIe SGL pool: pci_pool_create failed\n", + ioc->name); + goto out; + } + for (i = 0; i < ioc->scsiio_depth; i++) { + ioc->scsi_lookup[i].pcie_sg_list.pcie_sgl = + pci_pool_alloc(ioc->pcie_sgl_dma_pool, + GFP_KERNEL, + &ioc->scsi_lookup[i].pcie_sg_list.pcie_sgl_dma); + if (!ioc->scsi_lookup[i].pcie_sg_list.pcie_sgl) { + pr_info(MPT3SAS_FMT + "PCIe SGL pool: pci_pool_alloc failed\n", + ioc->name); + goto out; + } + } + dinitprintk(ioc, pr_info(MPT3SAS_FMT "PCIe sgl pool depth(%d), " + "element_size(%d), pool_size(%d kB)\n", ioc->name, + ioc->scsiio_depth, sz, (sz * ioc->scsiio_depth)/1024)); + total_sz += sz * ioc->scsiio_depth; + } /* sense buffers, 4 byte align */ sz = ioc->scsiio_depth * SCSI_SENSE_BUFFERSIZE; ioc->sense_dma_pool = dma_pool_create("sense pool", &ioc->pdev->dev, sz, @@ -4446,7 +5052,7 @@ _base_get_ioc_facts(struct MPT3SAS_ADAPTER *ioc) if ((facts->IOCCapabilities & MPI2_IOCFACTS_CAPABILITY_INTEGRATED_RAID)) ioc->ir_firmware = 1; if ((facts->IOCCapabilities & - MPI2_IOCFACTS_CAPABILITY_RDPQ_ARRAY_CAPABLE)) + MPI2_IOCFACTS_CAPABILITY_RDPQ_ARRAY_CAPABLE) && (!reset_devices)) ioc->rdpq_array_capable = 1; if (facts->IOCCapabilities & MPI26_IOCFACTS_CAPABILITY_ATOMIC_REQ) ioc->atomic_desc_capable = 1; @@ -4467,6 +5073,19 @@ _base_get_ioc_facts(struct MPT3SAS_ADAPTER *ioc) le16_to_cpu(mpi_reply.HighPriorityCredit); facts->ReplyFrameSize = mpi_reply.ReplyFrameSize; facts->MaxDevHandle = le16_to_cpu(mpi_reply.MaxDevHandle); + facts->CurrentHostPageSize = mpi_reply.CurrentHostPageSize; + + /* + * Get the Page Size from IOC Facts. If it's 0, default to 4k. + */ + ioc->page_size = 1 << facts->CurrentHostPageSize; + if (ioc->page_size == 1) { + pr_info(MPT3SAS_FMT "CurrentHostPageSize is 0: Setting " + "default host page size to 4k\n", ioc->name); + ioc->page_size = 1 << MPT3SAS_HOST_PAGE_SIZE_4K; + } + dinitprintk(ioc, pr_info(MPT3SAS_FMT "CurrentHostPageSize(%d)\n", + ioc->name, facts->CurrentHostPageSize)); dinitprintk(ioc, pr_info(MPT3SAS_FMT "hba queue depth(%d), max chains per io(%d)\n", @@ -4506,6 +5125,7 @@ _base_send_ioc_init(struct MPT3SAS_ADAPTER *ioc) mpi_request.VP_ID = 0; mpi_request.MsgVersion = cpu_to_le16(ioc->hba_mpi_version_belonged); mpi_request.HeaderVersion = cpu_to_le16(MPI2_HEADER_VERSION); + mpi_request.HostPageSize = MPT3SAS_HOST_PAGE_SIZE_4K; if (_base_is_controller_msix_enabled(ioc)) mpi_request.HostMSIxVectors = ioc->reply_queue_count; @@ -5374,6 +5994,7 @@ mpt3sas_base_attach(struct MPT3SAS_ADAPTER *ioc) */ ioc->build_sg_scmd = &_base_build_sg_scmd_ieee; ioc->build_sg = &_base_build_sg_ieee; + ioc->build_nvme_prp = &_base_build_nvme_prp; ioc->build_zero_len_sge = &_base_build_zero_len_sge_ieee; ioc->sge_size_ieee = sizeof(Mpi2IeeeSgeSimple64_t); @@ -5385,11 +6006,13 @@ mpt3sas_base_attach(struct MPT3SAS_ADAPTER *ioc) ioc->put_smid_scsi_io = &_base_put_smid_scsi_io_atomic; ioc->put_smid_fast_path = &_base_put_smid_fast_path_atomic; ioc->put_smid_hi_priority = &_base_put_smid_hi_priority_atomic; + ioc->put_smid_nvme_encap = &_base_put_smid_nvme_encap_atomic; } else { ioc->put_smid_default = &_base_put_smid_default; ioc->put_smid_scsi_io = &_base_put_smid_scsi_io; ioc->put_smid_fast_path = &_base_put_smid_fast_path; ioc->put_smid_hi_priority = &_base_put_smid_hi_priority; + ioc->put_smid_nvme_encap = &_base_put_smid_nvme_encap; } @@ -5517,9 +6140,16 @@ mpt3sas_base_attach(struct MPT3SAS_ADAPTER *ioc) _base_unmask_events(ioc, MPI2_EVENT_IR_OPERATION_STATUS); _base_unmask_events(ioc, MPI2_EVENT_LOG_ENTRY_ADDED); _base_unmask_events(ioc, MPI2_EVENT_TEMP_THRESHOLD); - if (ioc->hba_mpi_version_belonged == MPI26_VERSION) - _base_unmask_events(ioc, MPI2_EVENT_ACTIVE_CABLE_EXCEPTION); - + _base_unmask_events(ioc, MPI2_EVENT_ACTIVE_CABLE_EXCEPTION); + if (ioc->hba_mpi_version_belonged == MPI26_VERSION) { + if (ioc->is_gen35_ioc) { + _base_unmask_events(ioc, + MPI2_EVENT_PCIE_DEVICE_STATUS_CHANGE); + _base_unmask_events(ioc, MPI2_EVENT_PCIE_ENUMERATION); + _base_unmask_events(ioc, + MPI2_EVENT_PCIE_TOPOLOGY_CHANGE_LIST); + } + } r = _base_make_ioc_operational(ioc); if (r) goto out_free_resources; diff --git a/drivers/scsi/mpt3sas/mpt3sas_base.h b/drivers/scsi/mpt3sas/mpt3sas_base.h index a77bb7dc12b1..60f42ca3954f 100644 --- a/drivers/scsi/mpt3sas/mpt3sas_base.h +++ b/drivers/scsi/mpt3sas/mpt3sas_base.h @@ -54,6 +54,7 @@ #include "mpi/mpi2_raid.h" #include "mpi/mpi2_tool.h" #include "mpi/mpi2_sas.h" +#include "mpi/mpi2_pci.h" #include <scsi/scsi.h> #include <scsi/scsi_cmnd.h> @@ -73,8 +74,8 @@ #define MPT3SAS_DRIVER_NAME "mpt3sas" #define MPT3SAS_AUTHOR "Avago Technologies <MPT-FusionLinux.pdl@avagotech.com>" #define MPT3SAS_DESCRIPTION "LSI MPT Fusion SAS 3.0 Device Driver" -#define MPT3SAS_DRIVER_VERSION "15.100.00.00" -#define MPT3SAS_MAJOR_VERSION 15 +#define MPT3SAS_DRIVER_VERSION "17.100.00.00" +#define MPT3SAS_MAJOR_VERSION 17 #define MPT3SAS_MINOR_VERSION 100 #define MPT3SAS_BUILD_VERSION 0 #define MPT3SAS_RELEASE_VERSION 00 @@ -92,6 +93,7 @@ */ #define MPT_MAX_PHYS_SEGMENTS SG_CHUNK_SIZE #define MPT_MIN_PHYS_SEGMENTS 16 +#define MPT_KDUMP_MIN_PHYS_SEGMENTS 32 #ifdef CONFIG_SCSI_MPT3SAS_MAX_SGE #define MPT3SAS_SG_DEPTH CONFIG_SCSI_MPT3SAS_MAX_SGE @@ -111,9 +113,11 @@ #define MPT3SAS_SATA_QUEUE_DEPTH 32 #define MPT3SAS_SAS_QUEUE_DEPTH 254 #define MPT3SAS_RAID_QUEUE_DEPTH 128 +#define MPT3SAS_KDUMP_SCSI_IO_DEPTH 200 #define MPT3SAS_RAID_MAX_SECTORS 8192 - +#define MPT3SAS_HOST_PAGE_SIZE_4K 12 +#define MPT3SAS_NVME_QUEUE_DEPTH 128 #define MPT_NAME_LENGTH 32 /* generic length of strings */ #define MPT_STRING_LENGTH 64 @@ -131,6 +135,15 @@ #define DEFAULT_NUM_FWCHAIN_ELEMTS 8 /* + * NVMe defines + */ +#define NVME_PRP_SIZE 8 /* PRP size */ +#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 NVME_PRP_PAGE_SIZE 4096 /* Page size */ + +/* * reset phases */ #define MPT3_IOC_PRE_RESET 1 /* prior to host reset */ @@ -159,6 +172,7 @@ #define MPT_TARGET_FLAGS_VOLUME 0x02 #define MPT_TARGET_FLAGS_DELETED 0x04 #define MPT_TARGET_FASTPATH_IO 0x08 +#define MPT_TARGET_FLAGS_PCIE_DEVICE 0x10 #define SAS2_PCI_DEVICE_B0_REVISION (0x01) #define SAS3_PCI_DEVICE_C0_REVISION (0x02) @@ -357,7 +371,8 @@ struct Mpi2ManufacturingPage11_t { * @flags: MPT_TARGET_FLAGS_XXX flags * @deleted: target flaged for deletion * @tm_busy: target is busy with TM request. - * @sdev: The sas_device associated with this target + * @sas_dev: The sas_device associated with this target + * @pcie_dev: The pcie device associated with this target */ struct MPT3SAS_TARGET { struct scsi_target *starget; @@ -368,7 +383,8 @@ struct MPT3SAS_TARGET { u32 flags; u8 deleted; u8 tm_busy; - struct _sas_device *sdev; + struct _sas_device *sas_dev; + struct _pcie_device *pcie_dev; }; @@ -467,6 +483,8 @@ struct _internal_cmd { * @pfa_led_on: flag for PFA LED status * @pend_sas_rphy_add: flag to check if device is in sas_rphy_add() * addition routine. + * @chassis_slot: chassis slot + * @is_chassis_slot_valid: chassis slot valid or not */ struct _sas_device { struct list_head list; @@ -489,6 +507,8 @@ struct _sas_device { u8 pfa_led_on; u8 pend_sas_rphy_add; u8 enclosure_level; + u8 chassis_slot; + u8 is_chassis_slot_valid; u8 connector_name[5]; struct kref refcount; }; @@ -508,6 +528,89 @@ static inline void sas_device_put(struct _sas_device *s) kref_put(&s->refcount, sas_device_free); } +/* + * struct _pcie_device - attached PCIe device information + * @list: pcie device list + * @starget: starget object + * @wwid: device WWID + * @handle: device handle + * @device_info: bitfield provides detailed info about the device + * @id: target id + * @channel: target channel + * @slot: slot number + * @port_num: port number + * @responding: used in _scsih_pcie_device_mark_responding + * @fast_path: fast path feature enable bit + * @nvme_mdts: MaximumDataTransferSize from PCIe Device Page 2 for + * NVMe device only + * @enclosure_handle: enclosure handle + * @enclosure_logical_id: enclosure logical identifier + * @enclosure_level: The level of device's enclosure from the controller + * @connector_name: ASCII value of the Connector's name + * @serial_number: pointer of serial number string allocated runtime + * @refcount: reference count for deletion + */ +struct _pcie_device { + struct list_head list; + struct scsi_target *starget; + u64 wwid; + u16 handle; + u32 device_info; + int id; + int channel; + u16 slot; + u8 port_num; + u8 responding; + u8 fast_path; + u32 nvme_mdts; + u16 enclosure_handle; + u64 enclosure_logical_id; + u8 enclosure_level; + u8 connector_name[4]; + u8 *serial_number; + struct kref refcount; +}; +/** + * pcie_device_get - Increment the pcie device reference count + * + * @p: pcie_device object + * + * When ever this function called it will increment the + * reference count of the pcie device for which this function called. + * + */ +static inline void pcie_device_get(struct _pcie_device *p) +{ + kref_get(&p->refcount); +} + +/** + * pcie_device_free - Release the pcie device object + * @r - kref object + * + * Free's the pcie device object. It will be called when reference count + * reaches to zero. + */ +static inline void pcie_device_free(struct kref *r) +{ + kfree(container_of(r, struct _pcie_device, refcount)); +} + +/** + * pcie_device_put - Decrement the pcie device reference count + * + * @p: pcie_device object + * + * When ever this function called it will decrement the + * reference count of the pcie device for which this function called. + * + * When refernce count reaches to Zero, this will call pcie_device_free to the + * pcie_device object. + */ +static inline void pcie_device_put(struct _pcie_device *p) +{ + kref_put(&p->refcount, pcie_device_free); +} /** * struct _raid_device - raid volume link list * @list: sas device list @@ -556,12 +659,13 @@ struct _raid_device { /** * struct _boot_device - boot device info - * @is_raid: flag to indicate whether this is volume - * @device: holds pointer for either struct _sas_device or - * struct _raid_device + * + * @channel: sas, raid, or pcie channel + * @device: holds pointer for struct _sas_device, struct _raid_device or + * struct _pcie_device */ struct _boot_device { - u8 is_raid; + int channel; void *device; }; @@ -644,6 +748,16 @@ enum reset_type { }; /** + * struct pcie_sg_list - PCIe SGL buffer (contiguous per I/O) + * @pcie_sgl: PCIe native SGL for NVMe devices + * @pcie_sgl_dma: physical address + */ +struct pcie_sg_list { + void *pcie_sgl; + dma_addr_t pcie_sgl_dma; +}; + +/** * struct chain_tracker - firmware chain tracker * @chain_buffer: chain buffer * @chain_buffer_dma: physical address @@ -669,6 +783,7 @@ struct scsiio_tracker { struct scsi_cmnd *scmd; u8 cb_idx; u8 direct_io; + struct pcie_sg_list pcie_sg_list; struct list_head chain_list; struct list_head tracker_list; u16 msix_io; @@ -742,13 +857,19 @@ typedef void (*MPT_ADD_SGE)(void *paddr, u32 flags_length, dma_addr_t dma_addr); /* SAS3.0 support */ typedef int (*MPT_BUILD_SG_SCMD)(struct MPT3SAS_ADAPTER *ioc, - struct scsi_cmnd *scmd, u16 smid); + struct scsi_cmnd *scmd, u16 smid, struct _pcie_device *pcie_device); typedef void (*MPT_BUILD_SG)(struct MPT3SAS_ADAPTER *ioc, void *psge, dma_addr_t data_out_dma, size_t data_out_sz, dma_addr_t data_in_dma, size_t data_in_sz); typedef void (*MPT_BUILD_ZERO_LEN_SGE)(struct MPT3SAS_ADAPTER *ioc, void *paddr); +/* SAS3.5 support */ +typedef void (*NVME_BUILD_PRP)(struct MPT3SAS_ADAPTER *ioc, u16 smid, + Mpi26NVMeEncapsulatedRequest_t *nvme_encap_request, + dma_addr_t data_out_dma, size_t data_out_sz, dma_addr_t data_in_dma, + size_t data_in_sz); + /* To support atomic and non atomic descriptors*/ typedef void (*PUT_SMID_IO_FP_HIP) (struct MPT3SAS_ADAPTER *ioc, u16 smid, u16 funcdep); @@ -791,6 +912,7 @@ struct mpt3sas_facts { u16 MaxDevHandle; u16 MaxPersistentEntries; u16 MinDevHandle; + u8 CurrentHostPageSize; }; struct mpt3sas_port_facts { @@ -825,6 +947,8 @@ typedef void (*MPT3SAS_FLUSH_RUNNING_CMDS)(struct MPT3SAS_ADAPTER *ioc); * @bars: bitmask of BAR's that must be configured * @mask_interrupts: ignore interrupt * @dma_mask: used to set the consistent dma mask + * @pci_access_mutex: Mutex to synchronize ioctl, sysfs show path and + * pci resource handling * @fault_reset_work_q_name: fw fault work queue * @fault_reset_work_q: "" * @fault_reset_work: "" @@ -888,9 +1012,13 @@ typedef void (*MPT3SAS_FLUSH_RUNNING_CMDS)(struct MPT3SAS_ADAPTER *ioc); * @sas_device_list: sas device object list * @sas_device_init_list: sas device object list (used only at init time) * @sas_device_lock: + * @pcie_device_list: pcie device object list + * @pcie_device_init_list: pcie device object list (used only at init time) + * @pcie_device_lock: * @io_missing_delay: time for IO completed by fw when PDR enabled * @device_missing_delay: time for device missing by fw when PDR enabled * @sas_id : used for setting volume target IDs + * @pcie_target_id: used for setting pcie target IDs * @blocking_handles: bitmask used to identify which devices need blocking * @pd_handles : bitmask for PD handles * @pd_handles_sz : size of pd_handle bitmask @@ -1056,6 +1184,9 @@ struct MPT3SAS_ADAPTER { MPT_BUILD_SG build_sg_mpi; MPT_BUILD_ZERO_LEN_SGE build_zero_len_sge_mpi; + /* function ptr for NVMe PRP elements only */ + NVME_BUILD_PRP build_nvme_prp; + /* event log */ u32 event_type[MPI2_EVENT_NOTIFY_EVENTMASK_WORDS]; u32 event_context; @@ -1086,11 +1217,16 @@ struct MPT3SAS_ADAPTER { struct list_head sas_device_list; struct list_head sas_device_init_list; spinlock_t sas_device_lock; + struct list_head pcie_device_list; + struct list_head pcie_device_init_list; + spinlock_t pcie_device_lock; + struct list_head raid_device_list; spinlock_t raid_device_lock; u8 io_missing_delay; u16 device_missing_delay; int sas_id; + int pcie_target_id; void *blocking_handles; void *pd_handles; @@ -1119,6 +1255,11 @@ struct MPT3SAS_ADAPTER { int pending_io_count; wait_queue_head_t reset_wq; + /* PCIe SGL */ + struct dma_pool *pcie_sgl_dma_pool; + /* Host Page Size */ + u32 page_size; + /* chain */ struct chain_tracker *chain_lookup; struct list_head free_chain_list; @@ -1216,6 +1357,7 @@ struct MPT3SAS_ADAPTER { PUT_SMID_IO_FP_HIP put_smid_fast_path; PUT_SMID_IO_FP_HIP put_smid_hi_priority; PUT_SMID_DEFAULT put_smid_default; + PUT_SMID_DEFAULT put_smid_nvme_encap; }; @@ -1252,7 +1394,8 @@ void *mpt3sas_base_get_msg_frame(struct MPT3SAS_ADAPTER *ioc, u16 smid); void *mpt3sas_base_get_sense_buffer(struct MPT3SAS_ADAPTER *ioc, u16 smid); __le32 mpt3sas_base_get_sense_buffer_dma(struct MPT3SAS_ADAPTER *ioc, u16 smid); - +void *mpt3sas_base_get_pcie_sgl(struct MPT3SAS_ADAPTER *ioc, u16 smid); +dma_addr_t mpt3sas_base_get_pcie_sgl_dma(struct MPT3SAS_ADAPTER *ioc, u16 smid); void mpt3sas_base_sync_reply_irqs(struct MPT3SAS_ADAPTER *ioc); /* hi-priority queue */ @@ -1321,6 +1464,10 @@ struct _sas_device *mpt3sas_get_sdev_by_addr( struct MPT3SAS_ADAPTER *ioc, u64 sas_address); struct _sas_device *__mpt3sas_get_sdev_by_addr( struct MPT3SAS_ADAPTER *ioc, u64 sas_address); +struct _sas_device *mpt3sas_get_sdev_by_handle(struct MPT3SAS_ADAPTER *ioc, + u16 handle); +struct _pcie_device *mpt3sas_get_pdev_by_handle(struct MPT3SAS_ADAPTER *ioc, + u16 handle); void mpt3sas_port_enable_complete(struct MPT3SAS_ADAPTER *ioc); struct _raid_device * @@ -1359,6 +1506,12 @@ int mpt3sas_config_get_sas_device_pg0(struct MPT3SAS_ADAPTER *ioc, int mpt3sas_config_get_sas_device_pg1(struct MPT3SAS_ADAPTER *ioc, Mpi2ConfigReply_t *mpi_reply, Mpi2SasDevicePage1_t *config_page, u32 form, u32 handle); +int mpt3sas_config_get_pcie_device_pg0(struct MPT3SAS_ADAPTER *ioc, + Mpi2ConfigReply_t *mpi_reply, Mpi26PCIeDevicePage0_t *config_page, + u32 form, u32 handle); +int mpt3sas_config_get_pcie_device_pg2(struct MPT3SAS_ADAPTER *ioc, + Mpi2ConfigReply_t *mpi_reply, Mpi26PCIeDevicePage2_t *config_page, + u32 form, u32 handle); int mpt3sas_config_get_sas_iounit_pg0(struct MPT3SAS_ADAPTER *ioc, Mpi2ConfigReply_t *mpi_reply, Mpi2SasIOUnitPage0_t *config_page, u16 sz); @@ -1466,7 +1619,7 @@ void mpt3sas_scsi_direct_io_set(struct MPT3SAS_ADAPTER *ioc, u16 smid, u8 direct_io); void mpt3sas_setup_direct_io(struct MPT3SAS_ADAPTER *ioc, struct scsi_cmnd *scmd, - struct _raid_device *raid_device, Mpi2SCSIIORequest_t *mpi_request, + struct _raid_device *raid_device, Mpi25SCSIIORequest_t *mpi_request, u16 smid); /* NCQ Prio Handling Check */ diff --git a/drivers/scsi/mpt3sas/mpt3sas_config.c b/drivers/scsi/mpt3sas/mpt3sas_config.c index dd6270125614..1c747cf419d5 100644 --- a/drivers/scsi/mpt3sas/mpt3sas_config.c +++ b/drivers/scsi/mpt3sas/mpt3sas_config.c @@ -150,6 +150,24 @@ _config_display_some_debug(struct MPT3SAS_ADAPTER *ioc, u16 smid, case MPI2_CONFIG_EXTPAGETYPE_DRIVER_MAPPING: desc = "driver_mapping"; break; + case MPI2_CONFIG_EXTPAGETYPE_SAS_PORT: + desc = "sas_port"; + break; + case MPI2_CONFIG_EXTPAGETYPE_EXT_MANUFACTURING: + desc = "ext_manufacturing"; + break; + case MPI2_CONFIG_EXTPAGETYPE_PCIE_IO_UNIT: + desc = "pcie_io_unit"; + break; + case MPI2_CONFIG_EXTPAGETYPE_PCIE_SWITCH: + desc = "pcie_switch"; + break; + case MPI2_CONFIG_EXTPAGETYPE_PCIE_DEVICE: + desc = "pcie_device"; + break; + case MPI2_CONFIG_EXTPAGETYPE_PCIE_LINK: + desc = "pcie_link"; + break; } break; } @@ -1053,6 +1071,88 @@ mpt3sas_config_get_sas_device_pg1(struct MPT3SAS_ADAPTER *ioc, } /** + * mpt3sas_config_get_pcie_device_pg0 - obtain pcie device page 0 + * @ioc: per adapter object + * @mpi_reply: reply mf payload returned from firmware + * @config_page: contents of the config page + * @form: GET_NEXT_HANDLE or HANDLE + * @handle: device handle + * Context: sleep. + * + * Returns 0 for success, non-zero for failure. + */ +int +mpt3sas_config_get_pcie_device_pg0(struct MPT3SAS_ADAPTER *ioc, + Mpi2ConfigReply_t *mpi_reply, Mpi26PCIeDevicePage0_t *config_page, + u32 form, u32 handle) +{ + Mpi2ConfigRequest_t mpi_request; + int r; + + memset(&mpi_request, 0, sizeof(Mpi2ConfigRequest_t)); + mpi_request.Function = MPI2_FUNCTION_CONFIG; + mpi_request.Action = MPI2_CONFIG_ACTION_PAGE_HEADER; + mpi_request.Header.PageType = MPI2_CONFIG_PAGETYPE_EXTENDED; + mpi_request.ExtPageType = MPI2_CONFIG_EXTPAGETYPE_PCIE_DEVICE; + mpi_request.Header.PageVersion = MPI26_PCIEDEVICE0_PAGEVERSION; + mpi_request.Header.PageNumber = 0; + ioc->build_zero_len_sge_mpi(ioc, &mpi_request.PageBufferSGE); + r = _config_request(ioc, &mpi_request, mpi_reply, + MPT3_CONFIG_PAGE_DEFAULT_TIMEOUT, NULL, 0); + if (r) + goto out; + + mpi_request.PageAddress = cpu_to_le32(form | handle); + mpi_request.Action = MPI2_CONFIG_ACTION_PAGE_READ_CURRENT; + r = _config_request(ioc, &mpi_request, mpi_reply, + MPT3_CONFIG_PAGE_DEFAULT_TIMEOUT, config_page, + sizeof(*config_page)); +out: + return r; +} + +/** + * mpt3sas_config_get_pcie_device_pg2 - obtain pcie device page 2 + * @ioc: per adapter object + * @mpi_reply: reply mf payload returned from firmware + * @config_page: contents of the config page + * @form: GET_NEXT_HANDLE or HANDLE + * @handle: device handle + * Context: sleep. + * + * Returns 0 for success, non-zero for failure. + */ +int +mpt3sas_config_get_pcie_device_pg2(struct MPT3SAS_ADAPTER *ioc, + Mpi2ConfigReply_t *mpi_reply, Mpi26PCIeDevicePage2_t *config_page, + u32 form, u32 handle) +{ + Mpi2ConfigRequest_t mpi_request; + int r; + + memset(&mpi_request, 0, sizeof(Mpi2ConfigRequest_t)); + mpi_request.Function = MPI2_FUNCTION_CONFIG; + mpi_request.Action = MPI2_CONFIG_ACTION_PAGE_HEADER; + mpi_request.Header.PageType = MPI2_CONFIG_PAGETYPE_EXTENDED; + mpi_request.ExtPageType = MPI2_CONFIG_EXTPAGETYPE_PCIE_DEVICE; + mpi_request.Header.PageVersion = MPI26_PCIEDEVICE2_PAGEVERSION; + mpi_request.Header.PageNumber = 2; + ioc->build_zero_len_sge_mpi(ioc, &mpi_request.PageBufferSGE); + r = _config_request(ioc, &mpi_request, mpi_reply, + MPT3_CONFIG_PAGE_DEFAULT_TIMEOUT, NULL, 0); + if (r) + goto out; + + mpi_request.PageAddress = cpu_to_le32(form | handle); + mpi_request.Action = MPI2_CONFIG_ACTION_PAGE_READ_CURRENT; + r = _config_request(ioc, &mpi_request, mpi_reply, + MPT3_CONFIG_PAGE_DEFAULT_TIMEOUT, config_page, + sizeof(*config_page)); +out: + return r; +} + +/** * mpt3sas_config_get_number_hba_phys - obtain number of phys on the host * @ioc: per adapter object * @num_phys: pointer returned with the number of phys diff --git a/drivers/scsi/mpt3sas/mpt3sas_ctl.c b/drivers/scsi/mpt3sas/mpt3sas_ctl.c index bdffb692bded..b4c374b08e5e 100644 --- a/drivers/scsi/mpt3sas/mpt3sas_ctl.c +++ b/drivers/scsi/mpt3sas/mpt3sas_ctl.c @@ -79,32 +79,6 @@ enum block_state { }; /** - * _ctl_sas_device_find_by_handle - sas device search - * @ioc: per adapter object - * @handle: sas device handle (assigned by firmware) - * Context: Calling function should acquire ioc->sas_device_lock - * - * This searches for sas_device based on sas_address, then return sas_device - * object. - */ -static struct _sas_device * -_ctl_sas_device_find_by_handle(struct MPT3SAS_ADAPTER *ioc, u16 handle) -{ - struct _sas_device *sas_device, *r; - - r = NULL; - list_for_each_entry(sas_device, &ioc->sas_device_list, list) { - if (sas_device->handle != handle) - continue; - r = sas_device; - goto out; - } - - out: - return r; -} - -/** * _ctl_display_some_debug - debug routine * @ioc: per adapter object * @smid: system request message index @@ -229,10 +203,9 @@ _ctl_display_some_debug(struct MPT3SAS_ADAPTER *ioc, u16 smid, Mpi2SCSIIOReply_t *scsi_reply = (Mpi2SCSIIOReply_t *)mpi_reply; struct _sas_device *sas_device = NULL; - unsigned long flags; + struct _pcie_device *pcie_device = NULL; - spin_lock_irqsave(&ioc->sas_device_lock, flags); - sas_device = _ctl_sas_device_find_by_handle(ioc, + sas_device = mpt3sas_get_sdev_by_handle(ioc, le16_to_cpu(scsi_reply->DevHandle)); if (sas_device) { pr_warn(MPT3SAS_FMT "\tsas_address(0x%016llx), phy(%d)\n", @@ -242,8 +215,25 @@ _ctl_display_some_debug(struct MPT3SAS_ADAPTER *ioc, u16 smid, "\tenclosure_logical_id(0x%016llx), slot(%d)\n", ioc->name, (unsigned long long) sas_device->enclosure_logical_id, sas_device->slot); + sas_device_put(sas_device); + } + if (!sas_device) { + pcie_device = mpt3sas_get_pdev_by_handle(ioc, + le16_to_cpu(scsi_reply->DevHandle)); + if (pcie_device) { + pr_warn(MPT3SAS_FMT + "\tWWID(0x%016llx), port(%d)\n", ioc->name, + (unsigned long long)pcie_device->wwid, + pcie_device->port_num); + if (pcie_device->enclosure_handle != 0) + pr_warn(MPT3SAS_FMT + "\tenclosure_logical_id(0x%016llx), slot(%d)\n", + ioc->name, (unsigned long long) + pcie_device->enclosure_logical_id, + pcie_device->slot); + pcie_device_put(pcie_device); + } } - spin_unlock_irqrestore(&ioc->sas_device_lock, flags); if (scsi_reply->SCSIState || scsi_reply->SCSIStatus) pr_info(MPT3SAS_FMT "\tscsi_state(0x%02x), scsi_status" @@ -272,6 +262,7 @@ mpt3sas_ctl_done(struct MPT3SAS_ADAPTER *ioc, u16 smid, u8 msix_index, { MPI2DefaultReply_t *mpi_reply; Mpi2SCSIIOReply_t *scsiio_reply; + Mpi26NVMeEncapsulatedErrorReply_t *nvme_error_reply; const void *sense_data; u32 sz; @@ -298,7 +289,20 @@ mpt3sas_ctl_done(struct MPT3SAS_ADAPTER *ioc, u16 smid, u8 msix_index, memcpy(ioc->ctl_cmds.sense, sense_data, sz); } } + /* + * Get Error Response data for NVMe device. The ctl_cmds.sense + * buffer is used to store the Error Response data. + */ + if (mpi_reply->Function == MPI2_FUNCTION_NVME_ENCAPSULATED) { + nvme_error_reply = + (Mpi26NVMeEncapsulatedErrorReply_t *)mpi_reply; + sz = min_t(u32, NVME_ERROR_RESPONSE_SIZE, + le32_to_cpu(nvme_error_reply->ErrorResponseCount)); + sense_data = mpt3sas_base_get_sense_buffer(ioc, smid); + memcpy(ioc->ctl_cmds.sense, sense_data, sz); + } } + _ctl_display_some_debug(ioc, smid, "ctl_done", mpi_reply); ioc->ctl_cmds.status &= ~MPT3_CMD_PENDING; complete(&ioc->ctl_cmds.done); @@ -640,11 +644,12 @@ _ctl_do_mpt_command(struct MPT3SAS_ADAPTER *ioc, struct mpt3_ioctl_command karg, { MPI2RequestHeader_t *mpi_request = NULL, *request; MPI2DefaultReply_t *mpi_reply; + Mpi26NVMeEncapsulatedRequest_t *nvme_encap_request = NULL; u32 ioc_state; u16 smid; unsigned long timeout; u8 issue_reset; - u32 sz; + u32 sz, sz_arg; void *psge; void *data_out = NULL; dma_addr_t data_out_dma = 0; @@ -741,7 +746,8 @@ _ctl_do_mpt_command(struct MPT3SAS_ADAPTER *ioc, struct mpt3_ioctl_command karg, if (mpi_request->Function == MPI2_FUNCTION_SCSI_IO_REQUEST || mpi_request->Function == MPI2_FUNCTION_RAID_SCSI_IO_PASSTHROUGH || mpi_request->Function == MPI2_FUNCTION_SCSI_TASK_MGMT || - mpi_request->Function == MPI2_FUNCTION_SATA_PASSTHROUGH) { + mpi_request->Function == MPI2_FUNCTION_SATA_PASSTHROUGH || + mpi_request->Function == MPI2_FUNCTION_NVME_ENCAPSULATED) { device_handle = le16_to_cpu(mpi_request->FunctionDependent1); if (!device_handle || (device_handle > @@ -792,6 +798,38 @@ _ctl_do_mpt_command(struct MPT3SAS_ADAPTER *ioc, struct mpt3_ioctl_command karg, init_completion(&ioc->ctl_cmds.done); switch (mpi_request->Function) { + case MPI2_FUNCTION_NVME_ENCAPSULATED: + { + nvme_encap_request = (Mpi26NVMeEncapsulatedRequest_t *)request; + /* + * Get the Physical Address of the sense buffer. + * Use Error Response buffer address 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. + */ + nvme_encap_request->ErrorResponseBaseAddress = ioc->sense_dma & + 0xFFFFFFFF00000000; + nvme_encap_request->ErrorResponseBaseAddress |= + (U64)mpt3sas_base_get_sense_buffer_dma(ioc, smid); + nvme_encap_request->ErrorResponseAllocationLength = + NVME_ERROR_RESPONSE_SIZE; + memset(ioc->ctl_cmds.sense, 0, NVME_ERROR_RESPONSE_SIZE); + ioc->build_nvme_prp(ioc, smid, nvme_encap_request, + data_out_dma, data_out_sz, data_in_dma, data_in_sz); + if (test_bit(device_handle, ioc->device_remove_in_progress)) { + dtmprintk(ioc, pr_info(MPT3SAS_FMT "handle(0x%04x) :" + "ioctl failed due to device removal in progress\n", + ioc->name, device_handle)); + mpt3sas_base_free_smid(ioc, smid); + ret = -EINVAL; + goto out; + } + ioc->put_smid_nvme_encap(ioc, smid); + break; + } case MPI2_FUNCTION_SCSI_IO_REQUEST: case MPI2_FUNCTION_RAID_SCSI_IO_PASSTHROUGH: { @@ -1007,15 +1045,25 @@ _ctl_do_mpt_command(struct MPT3SAS_ADAPTER *ioc, struct mpt3_ioctl_command karg, } } - /* copy out sense to user */ + /* copy out sense/NVMe Error Response to user */ if (karg.max_sense_bytes && (mpi_request->Function == MPI2_FUNCTION_SCSI_IO_REQUEST || mpi_request->Function == - MPI2_FUNCTION_RAID_SCSI_IO_PASSTHROUGH)) { - sz = min_t(u32, karg.max_sense_bytes, SCSI_SENSE_BUFFERSIZE); + MPI2_FUNCTION_RAID_SCSI_IO_PASSTHROUGH || mpi_request->Function == + MPI2_FUNCTION_NVME_ENCAPSULATED)) { + if (karg.sense_data_ptr == NULL) { + pr_info(MPT3SAS_FMT "Response buffer provided" + " by application is NULL; Response data will" + " not be returned.\n", ioc->name); + goto out; + } + sz_arg = (mpi_request->Function == + MPI2_FUNCTION_NVME_ENCAPSULATED) ? NVME_ERROR_RESPONSE_SIZE : + SCSI_SENSE_BUFFERSIZE; + sz = min_t(u32, karg.max_sense_bytes, sz_arg); if (copy_to_user(karg.sense_data_ptr, ioc->ctl_cmds.sense, sz)) { pr_err("failure at %s:%d/%s()!\n", __FILE__, - __LINE__, __func__); + __LINE__, __func__); ret = -ENODATA; goto out; } @@ -1065,12 +1113,6 @@ _ctl_getiocinfo(struct MPT3SAS_ADAPTER *ioc, void __user *arg) { struct mpt3_ioctl_iocinfo karg; - if (copy_from_user(&karg, arg, sizeof(karg))) { - pr_err("failure at %s:%d/%s()!\n", - __FILE__, __LINE__, __func__); - return -EFAULT; - } - dctlprintk(ioc, pr_info(MPT3SAS_FMT "%s: enter\n", ioc->name, __func__)); @@ -1295,6 +1337,42 @@ _ctl_btdh_search_sas_device(struct MPT3SAS_ADAPTER *ioc, } /** + * _ctl_btdh_search_pcie_device - searching for pcie device + * @ioc: per adapter object + * @btdh: btdh ioctl payload + */ +static int +_ctl_btdh_search_pcie_device(struct MPT3SAS_ADAPTER *ioc, + struct mpt3_ioctl_btdh_mapping *btdh) +{ + struct _pcie_device *pcie_device; + unsigned long flags; + int rc = 0; + + if (list_empty(&ioc->pcie_device_list)) + return rc; + + spin_lock_irqsave(&ioc->pcie_device_lock, flags); + list_for_each_entry(pcie_device, &ioc->pcie_device_list, list) { + if (btdh->bus == 0xFFFFFFFF && btdh->id == 0xFFFFFFFF && + btdh->handle == pcie_device->handle) { + btdh->bus = pcie_device->channel; + btdh->id = pcie_device->id; + rc = 1; + goto out; + } else if (btdh->bus == pcie_device->channel && btdh->id == + pcie_device->id && btdh->handle == 0xFFFF) { + btdh->handle = pcie_device->handle; + rc = 1; + goto out; + } + } + out: + spin_unlock_irqrestore(&ioc->pcie_device_lock, flags); + return rc; +} + +/** * _ctl_btdh_search_raid_device - searching for raid device * @ioc: per adapter object * @btdh: btdh ioctl payload @@ -1352,6 +1430,8 @@ _ctl_btdh_mapping(struct MPT3SAS_ADAPTER *ioc, void __user *arg) rc = _ctl_btdh_search_sas_device(ioc, &karg); if (!rc) + rc = _ctl_btdh_search_pcie_device(ioc, &karg); + if (!rc) _ctl_btdh_search_raid_device(ioc, &karg); if (copy_to_user(arg, &karg, sizeof(karg))) { diff --git a/drivers/scsi/mpt3sas/mpt3sas_scsih.c b/drivers/scsi/mpt3sas/mpt3sas_scsih.c index 22998cbd538f..b258f210120a 100644 --- a/drivers/scsi/mpt3sas/mpt3sas_scsih.c +++ b/drivers/scsi/mpt3sas/mpt3sas_scsih.c @@ -60,6 +60,9 @@ #include "mpt3sas_base.h" #define RAID_CHANNEL 1 + +#define PCIE_CHANNEL 2 + /* forward proto's */ static void _scsih_expander_node_remove(struct MPT3SAS_ADAPTER *ioc, struct _sas_node *sas_expander); @@ -69,7 +72,11 @@ static void _scsih_remove_device(struct MPT3SAS_ADAPTER *ioc, struct _sas_device *sas_device); static int _scsih_add_device(struct MPT3SAS_ADAPTER *ioc, u16 handle, u8 retry_count, u8 is_pd); - +static int _scsih_pcie_add_device(struct MPT3SAS_ADAPTER *ioc, u16 handle); +static void _scsih_pcie_device_remove_from_sml(struct MPT3SAS_ADAPTER *ioc, + struct _pcie_device *pcie_device); +static void +_scsih_pcie_check_device(struct MPT3SAS_ADAPTER *ioc, u16 handle); static u8 _scsih_check_for_pending_tm(struct MPT3SAS_ADAPTER *ioc, u16 smid); /* global parameters */ @@ -281,7 +288,7 @@ struct _scsi_io_transfer { * Note: The logging levels are defined in mpt3sas_debug.h. */ static int -_scsih_set_debug_level(const char *val, struct kernel_param *kp) +_scsih_set_debug_level(const char *val, const struct kernel_param *kp) { int ret = param_set_int(val, kp); struct MPT3SAS_ADAPTER *ioc; @@ -406,11 +413,6 @@ _scsih_get_sas_address(struct MPT3SAS_ADAPTER *ioc, u16 handle, *sas_address = 0; - if (handle <= ioc->sas_hba.num_phys) { - *sas_address = ioc->sas_hba.sas_address; - return 0; - } - if ((mpt3sas_config_get_sas_device_pg0(ioc, &mpi_reply, &sas_device_pg0, MPI2_SAS_DEVICE_PGAD_FORM_HANDLE, handle))) { pr_err(MPT3SAS_FMT "failure at %s:%d/%s()!\n", ioc->name, @@ -420,7 +422,15 @@ _scsih_get_sas_address(struct MPT3SAS_ADAPTER *ioc, u16 handle, ioc_status = le16_to_cpu(mpi_reply.IOCStatus) & MPI2_IOCSTATUS_MASK; if (ioc_status == MPI2_IOCSTATUS_SUCCESS) { - *sas_address = le64_to_cpu(sas_device_pg0.SASAddress); + /* For HBA, vSES doesn't return HBA SAS address. Instead return + * vSES's sas address. + */ + if ((handle <= ioc->sas_hba.num_phys) && + (!(le32_to_cpu(sas_device_pg0.DeviceInfo) & + MPI2_SAS_DEVICE_INFO_SEP))) + *sas_address = ioc->sas_hba.sas_address; + else + *sas_address = le64_to_cpu(sas_device_pg0.SASAddress); return 0; } @@ -439,21 +449,22 @@ _scsih_get_sas_address(struct MPT3SAS_ADAPTER *ioc, u16 handle, /** * _scsih_determine_boot_device - determine boot device. * @ioc: per adapter object - * @device: either sas_device or raid_device object - * @is_raid: [flag] 1 = raid object, 0 = sas object + * @device: sas_device or pcie_device object + * @channel: SAS or PCIe channel * * Determines whether this device should be first reported device to * to scsi-ml or sas transport, this purpose is for persistent boot device. * There are primary, alternate, and current entries in bios page 2. The order * priority is primary, alternate, then current. This routine saves - * the corresponding device object and is_raid flag in the ioc object. + * the corresponding device object. * The saved data to be used later in _scsih_probe_boot_devices(). */ static void -_scsih_determine_boot_device(struct MPT3SAS_ADAPTER *ioc, - void *device, u8 is_raid) +_scsih_determine_boot_device(struct MPT3SAS_ADAPTER *ioc, void *device, + u32 channel) { struct _sas_device *sas_device; + struct _pcie_device *pcie_device; struct _raid_device *raid_device; u64 sas_address; u64 device_name; @@ -468,18 +479,24 @@ _scsih_determine_boot_device(struct MPT3SAS_ADAPTER *ioc, if (!ioc->bios_pg3.BiosVersion) return; - if (!is_raid) { - sas_device = device; - sas_address = sas_device->sas_address; - device_name = sas_device->device_name; - enclosure_logical_id = sas_device->enclosure_logical_id; - slot = sas_device->slot; - } else { + if (channel == RAID_CHANNEL) { raid_device = device; sas_address = raid_device->wwid; device_name = 0; enclosure_logical_id = 0; slot = 0; + } else if (channel == PCIE_CHANNEL) { + pcie_device = device; + sas_address = pcie_device->wwid; + device_name = 0; + enclosure_logical_id = 0; + slot = 0; + } else { + sas_device = device; + sas_address = sas_device->sas_address; + device_name = sas_device->device_name; + enclosure_logical_id = sas_device->enclosure_logical_id; + slot = sas_device->slot; } if (!ioc->req_boot_device.device) { @@ -493,7 +510,7 @@ _scsih_determine_boot_device(struct MPT3SAS_ADAPTER *ioc, ioc->name, __func__, (unsigned long long)sas_address)); ioc->req_boot_device.device = device; - ioc->req_boot_device.is_raid = is_raid; + ioc->req_boot_device.channel = channel; } } @@ -508,7 +525,7 @@ _scsih_determine_boot_device(struct MPT3SAS_ADAPTER *ioc, ioc->name, __func__, (unsigned long long)sas_address)); ioc->req_alt_boot_device.device = device; - ioc->req_alt_boot_device.is_raid = is_raid; + ioc->req_alt_boot_device.channel = channel; } } @@ -523,7 +540,7 @@ _scsih_determine_boot_device(struct MPT3SAS_ADAPTER *ioc, ioc->name, __func__, (unsigned long long)sas_address)); ioc->current_boot_device.device = device; - ioc->current_boot_device.is_raid = is_raid; + ioc->current_boot_device.channel = channel; } } } @@ -536,7 +553,7 @@ __mpt3sas_get_sdev_from_target(struct MPT3SAS_ADAPTER *ioc, assert_spin_locked(&ioc->sas_device_lock); - ret = tgt_priv->sdev; + ret = tgt_priv->sas_dev; if (ret) sas_device_get(ret); @@ -557,6 +574,44 @@ mpt3sas_get_sdev_from_target(struct MPT3SAS_ADAPTER *ioc, return ret; } +static struct _pcie_device * +__mpt3sas_get_pdev_from_target(struct MPT3SAS_ADAPTER *ioc, + struct MPT3SAS_TARGET *tgt_priv) +{ + struct _pcie_device *ret; + + assert_spin_locked(&ioc->pcie_device_lock); + + ret = tgt_priv->pcie_dev; + if (ret) + pcie_device_get(ret); + + return ret; +} + +/** + * mpt3sas_get_pdev_from_target - pcie device search + * @ioc: per adapter object + * @tgt_priv: starget private object + * + * Context: This function will acquire ioc->pcie_device_lock and will release + * before returning the pcie_device object. + * + * This searches for pcie_device from target, then return pcie_device object. + */ +static struct _pcie_device * +mpt3sas_get_pdev_from_target(struct MPT3SAS_ADAPTER *ioc, + struct MPT3SAS_TARGET *tgt_priv) +{ + struct _pcie_device *ret; + unsigned long flags; + + spin_lock_irqsave(&ioc->pcie_device_lock, flags); + ret = __mpt3sas_get_pdev_from_target(ioc, tgt_priv); + spin_unlock_irqrestore(&ioc->pcie_device_lock, flags); + + return ret; +} struct _sas_device * __mpt3sas_get_sdev_by_addr(struct MPT3SAS_ADAPTER *ioc, @@ -636,7 +691,7 @@ found_device: * This searches for sas_device based on sas_address, then return sas_device * object. */ -static struct _sas_device * +struct _sas_device * mpt3sas_get_sdev_by_handle(struct MPT3SAS_ADAPTER *ioc, u16 handle) { struct _sas_device *sas_device; @@ -650,6 +705,69 @@ mpt3sas_get_sdev_by_handle(struct MPT3SAS_ADAPTER *ioc, u16 handle) } /** + * _scsih_display_enclosure_chassis_info - display device location info + * @ioc: per adapter object + * @sas_device: per sas device object + * @sdev: scsi device struct + * @starget: scsi target struct + * + * Returns nothing. + */ +static void +_scsih_display_enclosure_chassis_info(struct MPT3SAS_ADAPTER *ioc, + struct _sas_device *sas_device, struct scsi_device *sdev, + struct scsi_target *starget) +{ + if (sdev) { + if (sas_device->enclosure_handle != 0) + sdev_printk(KERN_INFO, sdev, + "enclosure logical id (0x%016llx), slot(%d) \n", + (unsigned long long) + sas_device->enclosure_logical_id, + sas_device->slot); + if (sas_device->connector_name[0] != '\0') + sdev_printk(KERN_INFO, sdev, + "enclosure level(0x%04x), connector name( %s)\n", + sas_device->enclosure_level, + sas_device->connector_name); + if (sas_device->is_chassis_slot_valid) + sdev_printk(KERN_INFO, sdev, "chassis slot(0x%04x)\n", + sas_device->chassis_slot); + } else if (starget) { + if (sas_device->enclosure_handle != 0) + starget_printk(KERN_INFO, starget, + "enclosure logical id(0x%016llx), slot(%d) \n", + (unsigned long long) + sas_device->enclosure_logical_id, + sas_device->slot); + if (sas_device->connector_name[0] != '\0') + starget_printk(KERN_INFO, starget, + "enclosure level(0x%04x), connector name( %s)\n", + sas_device->enclosure_level, + sas_device->connector_name); + if (sas_device->is_chassis_slot_valid) + starget_printk(KERN_INFO, starget, + "chassis slot(0x%04x)\n", + sas_device->chassis_slot); + } else { + if (sas_device->enclosure_handle != 0) + pr_info(MPT3SAS_FMT + "enclosure logical id(0x%016llx), slot(%d) \n", + ioc->name, (unsigned long long) + sas_device->enclosure_logical_id, + sas_device->slot); + if (sas_device->connector_name[0] != '\0') + pr_info(MPT3SAS_FMT + "enclosure level(0x%04x), connector name( %s)\n", + ioc->name, sas_device->enclosure_level, + sas_device->connector_name); + if (sas_device->is_chassis_slot_valid) + pr_info(MPT3SAS_FMT "chassis slot(0x%04x)\n", + ioc->name, sas_device->chassis_slot); + } +} + +/** * _scsih_sas_device_remove - remove sas_device from list. * @ioc: per adapter object * @sas_device: the sas_device object @@ -670,17 +788,7 @@ _scsih_sas_device_remove(struct MPT3SAS_ADAPTER *ioc, ioc->name, sas_device->handle, (unsigned long long) sas_device->sas_address); - if (sas_device->enclosure_handle != 0) - pr_info(MPT3SAS_FMT - "removing enclosure logical id(0x%016llx), slot(%d)\n", - ioc->name, (unsigned long long) - sas_device->enclosure_logical_id, sas_device->slot); - - if (sas_device->connector_name[0] != '\0') - pr_info(MPT3SAS_FMT - "removing enclosure level(0x%04x), connector name( %s)\n", - ioc->name, sas_device->enclosure_level, - sas_device->connector_name); + _scsih_display_enclosure_chassis_info(ioc, sas_device, NULL, NULL); /* * The lock serializes access to the list, but we still need to verify @@ -772,17 +880,8 @@ _scsih_sas_device_add(struct MPT3SAS_ADAPTER *ioc, ioc->name, __func__, sas_device->handle, (unsigned long long)sas_device->sas_address)); - if (sas_device->enclosure_handle != 0) - dewtprintk(ioc, pr_info(MPT3SAS_FMT - "%s: enclosure logical id(0x%016llx), slot( %d)\n", - ioc->name, __func__, (unsigned long long) - sas_device->enclosure_logical_id, sas_device->slot)); - - if (sas_device->connector_name[0] != '\0') - dewtprintk(ioc, pr_info(MPT3SAS_FMT - "%s: enclosure level(0x%04x), connector name( %s)\n", - ioc->name, __func__, - sas_device->enclosure_level, sas_device->connector_name)); + dewtprintk(ioc, _scsih_display_enclosure_chassis_info(ioc, sas_device, + NULL, NULL)); spin_lock_irqsave(&ioc->sas_device_lock, flags); sas_device_get(sas_device); @@ -832,17 +931,8 @@ _scsih_sas_device_init_add(struct MPT3SAS_ADAPTER *ioc, __func__, sas_device->handle, (unsigned long long)sas_device->sas_address)); - if (sas_device->enclosure_handle != 0) - dewtprintk(ioc, pr_info(MPT3SAS_FMT - "%s: enclosure logical id(0x%016llx), slot( %d)\n", - ioc->name, __func__, (unsigned long long) - sas_device->enclosure_logical_id, sas_device->slot)); - - if (sas_device->connector_name[0] != '\0') - dewtprintk(ioc, pr_info(MPT3SAS_FMT - "%s: enclosure level(0x%04x), connector name( %s)\n", - ioc->name, __func__, sas_device->enclosure_level, - sas_device->connector_name)); + dewtprintk(ioc, _scsih_display_enclosure_chassis_info(ioc, sas_device, + NULL, NULL)); spin_lock_irqsave(&ioc->sas_device_lock, flags); sas_device_get(sas_device); @@ -851,6 +941,282 @@ _scsih_sas_device_init_add(struct MPT3SAS_ADAPTER *ioc, spin_unlock_irqrestore(&ioc->sas_device_lock, flags); } + +static struct _pcie_device * +__mpt3sas_get_pdev_by_wwid(struct MPT3SAS_ADAPTER *ioc, u64 wwid) +{ + struct _pcie_device *pcie_device; + + assert_spin_locked(&ioc->pcie_device_lock); + + list_for_each_entry(pcie_device, &ioc->pcie_device_list, list) + if (pcie_device->wwid == wwid) + goto found_device; + + list_for_each_entry(pcie_device, &ioc->pcie_device_init_list, list) + if (pcie_device->wwid == wwid) + goto found_device; + + return NULL; + +found_device: + pcie_device_get(pcie_device); + return pcie_device; +} + + +/** + * mpt3sas_get_pdev_by_wwid - pcie device search + * @ioc: per adapter object + * @wwid: wwid + * + * Context: This function will acquire ioc->pcie_device_lock and will release + * before returning the pcie_device object. + * + * This searches for pcie_device based on wwid, then return pcie_device object. + */ +static struct _pcie_device * +mpt3sas_get_pdev_by_wwid(struct MPT3SAS_ADAPTER *ioc, u64 wwid) +{ + struct _pcie_device *pcie_device; + unsigned long flags; + + spin_lock_irqsave(&ioc->pcie_device_lock, flags); + pcie_device = __mpt3sas_get_pdev_by_wwid(ioc, wwid); + spin_unlock_irqrestore(&ioc->pcie_device_lock, flags); + + return pcie_device; +} + + +static struct _pcie_device * +__mpt3sas_get_pdev_by_idchannel(struct MPT3SAS_ADAPTER *ioc, int id, + int channel) +{ + struct _pcie_device *pcie_device; + + assert_spin_locked(&ioc->pcie_device_lock); + + list_for_each_entry(pcie_device, &ioc->pcie_device_list, list) + if (pcie_device->id == id && pcie_device->channel == channel) + goto found_device; + + list_for_each_entry(pcie_device, &ioc->pcie_device_init_list, list) + if (pcie_device->id == id && pcie_device->channel == channel) + goto found_device; + + return NULL; + +found_device: + pcie_device_get(pcie_device); + return pcie_device; +} + +static struct _pcie_device * +__mpt3sas_get_pdev_by_handle(struct MPT3SAS_ADAPTER *ioc, u16 handle) +{ + struct _pcie_device *pcie_device; + + assert_spin_locked(&ioc->pcie_device_lock); + + list_for_each_entry(pcie_device, &ioc->pcie_device_list, list) + if (pcie_device->handle == handle) + goto found_device; + + list_for_each_entry(pcie_device, &ioc->pcie_device_init_list, list) + if (pcie_device->handle == handle) + goto found_device; + + return NULL; + +found_device: + pcie_device_get(pcie_device); + return pcie_device; +} + + +/** + * mpt3sas_get_pdev_by_handle - pcie device search + * @ioc: per adapter object + * @handle: Firmware device handle + * + * Context: This function will acquire ioc->pcie_device_lock and will release + * before returning the pcie_device object. + * + * This searches for pcie_device based on handle, then return pcie_device + * object. + */ +struct _pcie_device * +mpt3sas_get_pdev_by_handle(struct MPT3SAS_ADAPTER *ioc, u16 handle) +{ + struct _pcie_device *pcie_device; + unsigned long flags; + + spin_lock_irqsave(&ioc->pcie_device_lock, flags); + pcie_device = __mpt3sas_get_pdev_by_handle(ioc, handle); + spin_unlock_irqrestore(&ioc->pcie_device_lock, flags); + + return pcie_device; +} + +/** + * _scsih_pcie_device_remove - remove pcie_device from list. + * @ioc: per adapter object + * @pcie_device: the pcie_device object + * Context: This function will acquire ioc->pcie_device_lock. + * + * If pcie_device is on the list, remove it and decrement its reference count. + */ +static void +_scsih_pcie_device_remove(struct MPT3SAS_ADAPTER *ioc, + struct _pcie_device *pcie_device) +{ + unsigned long flags; + int was_on_pcie_device_list = 0; + + if (!pcie_device) + return; + pr_info(MPT3SAS_FMT + "removing handle(0x%04x), wwid(0x%016llx)\n", + ioc->name, pcie_device->handle, + (unsigned long long) pcie_device->wwid); + if (pcie_device->enclosure_handle != 0) + pr_info(MPT3SAS_FMT + "removing enclosure logical id(0x%016llx), slot(%d)\n", + ioc->name, + (unsigned long long)pcie_device->enclosure_logical_id, + pcie_device->slot); + if (pcie_device->connector_name[0] != '\0') + pr_info(MPT3SAS_FMT + "removing enclosure level(0x%04x), connector name( %s)\n", + ioc->name, pcie_device->enclosure_level, + pcie_device->connector_name); + + spin_lock_irqsave(&ioc->pcie_device_lock, flags); + if (!list_empty(&pcie_device->list)) { + list_del_init(&pcie_device->list); + was_on_pcie_device_list = 1; + } + spin_unlock_irqrestore(&ioc->pcie_device_lock, flags); + if (was_on_pcie_device_list) { + kfree(pcie_device->serial_number); + pcie_device_put(pcie_device); + } +} + + +/** + * _scsih_pcie_device_remove_by_handle - removing pcie device object by handle + * @ioc: per adapter object + * @handle: device handle + * + * Return nothing. + */ +static void +_scsih_pcie_device_remove_by_handle(struct MPT3SAS_ADAPTER *ioc, u16 handle) +{ + struct _pcie_device *pcie_device; + unsigned long flags; + int was_on_pcie_device_list = 0; + + if (ioc->shost_recovery) + return; + + spin_lock_irqsave(&ioc->pcie_device_lock, flags); + pcie_device = __mpt3sas_get_pdev_by_handle(ioc, handle); + if (pcie_device) { + if (!list_empty(&pcie_device->list)) { + list_del_init(&pcie_device->list); + was_on_pcie_device_list = 1; + pcie_device_put(pcie_device); + } + } + spin_unlock_irqrestore(&ioc->pcie_device_lock, flags); + if (was_on_pcie_device_list) { + _scsih_pcie_device_remove_from_sml(ioc, pcie_device); + pcie_device_put(pcie_device); + } +} + +/** + * _scsih_pcie_device_add - add pcie_device object + * @ioc: per adapter object + * @pcie_device: pcie_device object + * + * This is added to the pcie_device_list link list. + */ +static void +_scsih_pcie_device_add(struct MPT3SAS_ADAPTER *ioc, + struct _pcie_device *pcie_device) +{ + unsigned long flags; + + dewtprintk(ioc, pr_info(MPT3SAS_FMT + "%s: handle (0x%04x), wwid(0x%016llx)\n", ioc->name, __func__, + pcie_device->handle, (unsigned long long)pcie_device->wwid)); + if (pcie_device->enclosure_handle != 0) + dewtprintk(ioc, pr_info(MPT3SAS_FMT + "%s: enclosure logical id(0x%016llx), slot( %d)\n", + ioc->name, __func__, + (unsigned long long)pcie_device->enclosure_logical_id, + pcie_device->slot)); + if (pcie_device->connector_name[0] != '\0') + dewtprintk(ioc, pr_info(MPT3SAS_FMT + "%s: enclosure level(0x%04x), connector name( %s)\n", + ioc->name, __func__, pcie_device->enclosure_level, + pcie_device->connector_name)); + + spin_lock_irqsave(&ioc->pcie_device_lock, flags); + pcie_device_get(pcie_device); + list_add_tail(&pcie_device->list, &ioc->pcie_device_list); + spin_unlock_irqrestore(&ioc->pcie_device_lock, flags); + + if (scsi_add_device(ioc->shost, PCIE_CHANNEL, pcie_device->id, 0)) { + _scsih_pcie_device_remove(ioc, pcie_device); + } else if (!pcie_device->starget) { + if (!ioc->is_driver_loading) { +/*TODO-- Need to find out whether this condition will occur or not*/ + clear_bit(pcie_device->handle, ioc->pend_os_device_add); + } + } else + clear_bit(pcie_device->handle, ioc->pend_os_device_add); +} + +/* + * _scsih_pcie_device_init_add - insert pcie_device to the init list. + * @ioc: per adapter object + * @pcie_device: the pcie_device object + * Context: This function will acquire ioc->pcie_device_lock. + * + * Adding new object at driver load time to the ioc->pcie_device_init_list. + */ +static void +_scsih_pcie_device_init_add(struct MPT3SAS_ADAPTER *ioc, + struct _pcie_device *pcie_device) +{ + unsigned long flags; + + dewtprintk(ioc, pr_info(MPT3SAS_FMT + "%s: handle (0x%04x), wwid(0x%016llx)\n", ioc->name, __func__, + pcie_device->handle, (unsigned long long)pcie_device->wwid)); + if (pcie_device->enclosure_handle != 0) + dewtprintk(ioc, pr_info(MPT3SAS_FMT + "%s: enclosure logical id(0x%016llx), slot( %d)\n", + ioc->name, __func__, + (unsigned long long)pcie_device->enclosure_logical_id, + pcie_device->slot)); + if (pcie_device->connector_name[0] != '\0') + dewtprintk(ioc, pr_info(MPT3SAS_FMT + "%s: enclosure level(0x%04x), connector name( %s)\n", + ioc->name, __func__, pcie_device->enclosure_level, + pcie_device->connector_name)); + + spin_lock_irqsave(&ioc->pcie_device_lock, flags); + pcie_device_get(pcie_device); + list_add_tail(&pcie_device->list, &ioc->pcie_device_init_list); + _scsih_determine_boot_device(ioc, pcie_device, PCIE_CHANNEL); + spin_unlock_irqrestore(&ioc->pcie_device_lock, flags); +} /** * _scsih_raid_device_find_by_id - raid device search * @ioc: per adapter object @@ -1062,6 +1428,23 @@ _scsih_is_end_device(u32 device_info) } /** + * _scsih_is_nvme_device - determines if device is an nvme device + * @device_info: bitfield providing information about the device. + * Context: none + * + * Returns 1 if nvme device. + */ +static int +_scsih_is_nvme_device(u32 device_info) +{ + if ((device_info & MPI26_PCIE_DEVINFO_MASK_DEVICE_TYPE) + == MPI26_PCIE_DEVINFO_NVME) + return 1; + else + return 0; +} + +/** * _scsih_scsi_lookup_get - returns scmd entry * @ioc: per adapter object * @smid: system request message index @@ -1278,6 +1661,7 @@ scsih_target_alloc(struct scsi_target *starget) struct MPT3SAS_TARGET *sas_target_priv_data; struct _sas_device *sas_device; struct _raid_device *raid_device; + struct _pcie_device *pcie_device; unsigned long flags; struct sas_rphy *rphy; @@ -1307,6 +1691,28 @@ scsih_target_alloc(struct scsi_target *starget) return 0; } + /* PCIe devices */ + if (starget->channel == PCIE_CHANNEL) { + spin_lock_irqsave(&ioc->pcie_device_lock, flags); + pcie_device = __mpt3sas_get_pdev_by_idchannel(ioc, starget->id, + starget->channel); + if (pcie_device) { + sas_target_priv_data->handle = pcie_device->handle; + sas_target_priv_data->sas_address = pcie_device->wwid; + sas_target_priv_data->pcie_dev = pcie_device; + pcie_device->starget = starget; + pcie_device->id = starget->id; + pcie_device->channel = starget->channel; + sas_target_priv_data->flags |= + MPT_TARGET_FLAGS_PCIE_DEVICE; + if (pcie_device->fast_path) + sas_target_priv_data->flags |= + MPT_TARGET_FASTPATH_IO; + } + spin_unlock_irqrestore(&ioc->pcie_device_lock, flags); + return 0; + } + /* sas/sata devices */ spin_lock_irqsave(&ioc->sas_device_lock, flags); rphy = dev_to_rphy(starget->dev.parent); @@ -1316,7 +1722,7 @@ scsih_target_alloc(struct scsi_target *starget) if (sas_device) { sas_target_priv_data->handle = sas_device->handle; sas_target_priv_data->sas_address = sas_device->sas_address; - sas_target_priv_data->sdev = sas_device; + sas_target_priv_data->sas_dev = sas_device; sas_device->starget = starget; sas_device->id = starget->id; sas_device->channel = starget->channel; @@ -1324,7 +1730,8 @@ scsih_target_alloc(struct scsi_target *starget) sas_target_priv_data->flags |= MPT_TARGET_FLAGS_RAID_COMPONENT; if (sas_device->fast_path) - sas_target_priv_data->flags |= MPT_TARGET_FASTPATH_IO; + sas_target_priv_data->flags |= + MPT_TARGET_FASTPATH_IO; } spin_unlock_irqrestore(&ioc->sas_device_lock, flags); @@ -1345,7 +1752,9 @@ scsih_target_destroy(struct scsi_target *starget) struct MPT3SAS_TARGET *sas_target_priv_data; struct _sas_device *sas_device; struct _raid_device *raid_device; + struct _pcie_device *pcie_device; unsigned long flags; + struct sas_rphy *rphy; sas_target_priv_data = starget->hostdata; if (!sas_target_priv_data) @@ -1363,7 +1772,29 @@ scsih_target_destroy(struct scsi_target *starget) goto out; } + if (starget->channel == PCIE_CHANNEL) { + spin_lock_irqsave(&ioc->pcie_device_lock, flags); + pcie_device = __mpt3sas_get_pdev_from_target(ioc, + sas_target_priv_data); + if (pcie_device && (pcie_device->starget == starget) && + (pcie_device->id == starget->id) && + (pcie_device->channel == starget->channel)) + pcie_device->starget = NULL; + + if (pcie_device) { + /* + * Corresponding get() is in _scsih_target_alloc() + */ + sas_target_priv_data->pcie_dev = NULL; + pcie_device_put(pcie_device); + pcie_device_put(pcie_device); + } + spin_unlock_irqrestore(&ioc->pcie_device_lock, flags); + goto out; + } + spin_lock_irqsave(&ioc->sas_device_lock, flags); + rphy = dev_to_rphy(starget->dev.parent); sas_device = __mpt3sas_get_sdev_from_target(ioc, sas_target_priv_data); if (sas_device && (sas_device->starget == starget) && (sas_device->id == starget->id) && @@ -1374,7 +1805,7 @@ scsih_target_destroy(struct scsi_target *starget) /* * Corresponding get() is in _scsih_target_alloc() */ - sas_target_priv_data->sdev = NULL; + sas_target_priv_data->sas_dev = NULL; sas_device_put(sas_device); sas_device_put(sas_device); @@ -1403,6 +1834,7 @@ scsih_slave_alloc(struct scsi_device *sdev) struct scsi_target *starget; struct _raid_device *raid_device; struct _sas_device *sas_device; + struct _pcie_device *pcie_device; unsigned long flags; sas_device_priv_data = kzalloc(sizeof(*sas_device_priv_data), @@ -1431,8 +1863,22 @@ scsih_slave_alloc(struct scsi_device *sdev) raid_device->sdev = sdev; /* raid is single lun */ spin_unlock_irqrestore(&ioc->raid_device_lock, flags); } + if (starget->channel == PCIE_CHANNEL) { + spin_lock_irqsave(&ioc->pcie_device_lock, flags); + pcie_device = __mpt3sas_get_pdev_by_wwid(ioc, + sas_target_priv_data->sas_address); + if (pcie_device && (pcie_device->starget == NULL)) { + sdev_printk(KERN_INFO, sdev, + "%s : pcie_device->starget set to starget @ %d\n", + __func__, __LINE__); + pcie_device->starget = starget; + } + + if (pcie_device) + pcie_device_put(pcie_device); + spin_unlock_irqrestore(&ioc->pcie_device_lock, flags); - if (!(sas_target_priv_data->flags & MPT_TARGET_FLAGS_VOLUME)) { + } else if (!(sas_target_priv_data->flags & MPT_TARGET_FLAGS_VOLUME)) { spin_lock_irqsave(&ioc->sas_device_lock, flags); sas_device = __mpt3sas_get_sdev_by_addr(ioc, sas_target_priv_data->sas_address); @@ -1466,6 +1912,7 @@ scsih_slave_destroy(struct scsi_device *sdev) struct Scsi_Host *shost; struct MPT3SAS_ADAPTER *ioc; struct _sas_device *sas_device; + struct _pcie_device *pcie_device; unsigned long flags; if (!sdev->hostdata) @@ -1478,7 +1925,19 @@ scsih_slave_destroy(struct scsi_device *sdev) shost = dev_to_shost(&starget->dev); ioc = shost_priv(shost); - if (!(sas_target_priv_data->flags & MPT_TARGET_FLAGS_VOLUME)) { + if (sas_target_priv_data->flags & MPT_TARGET_FLAGS_PCIE_DEVICE) { + spin_lock_irqsave(&ioc->pcie_device_lock, flags); + pcie_device = __mpt3sas_get_pdev_from_target(ioc, + sas_target_priv_data); + if (pcie_device && !sas_target_priv_data->num_luns) + pcie_device->starget = NULL; + + if (pcie_device) + pcie_device_put(pcie_device); + + spin_unlock_irqrestore(&ioc->pcie_device_lock, flags); + + } else if (!(sas_target_priv_data->flags & MPT_TARGET_FLAGS_VOLUME)) { spin_lock_irqsave(&ioc->sas_device_lock, flags); sas_device = __mpt3sas_get_sdev_from_target(ioc, sas_target_priv_data); @@ -1562,6 +2021,14 @@ scsih_is_raid(struct device *dev) return (sdev->channel == RAID_CHANNEL) ? 1 : 0; } +static int +scsih_is_nvme(struct device *dev) +{ + struct scsi_device *sdev = to_scsi_device(dev); + + return (sdev->channel == PCIE_CHANNEL) ? 1 : 0; +} + /** * scsih_get_resync - get raid volume resync percent complete * @dev the device struct object @@ -1837,6 +2304,7 @@ scsih_slave_configure(struct scsi_device *sdev) struct MPT3SAS_DEVICE *sas_device_priv_data; struct MPT3SAS_TARGET *sas_target_priv_data; struct _sas_device *sas_device; + struct _pcie_device *pcie_device; struct _raid_device *raid_device; unsigned long flags; int qdepth; @@ -1967,6 +2435,55 @@ scsih_slave_configure(struct scsi_device *sdev) } } + /* PCIe handling */ + if (sas_target_priv_data->flags & MPT_TARGET_FLAGS_PCIE_DEVICE) { + spin_lock_irqsave(&ioc->pcie_device_lock, flags); + pcie_device = __mpt3sas_get_pdev_by_wwid(ioc, + sas_device_priv_data->sas_target->sas_address); + if (!pcie_device) { + spin_unlock_irqrestore(&ioc->pcie_device_lock, flags); + dfailprintk(ioc, pr_warn(MPT3SAS_FMT + "failure at %s:%d/%s()!\n", ioc->name, __FILE__, + __LINE__, __func__)); + return 1; + } + + qdepth = MPT3SAS_NVME_QUEUE_DEPTH; + ds = "NVMe"; + sdev_printk(KERN_INFO, sdev, + "%s: handle(0x%04x), wwid(0x%016llx), port(%d)\n", + ds, handle, (unsigned long long)pcie_device->wwid, + pcie_device->port_num); + if (pcie_device->enclosure_handle != 0) + sdev_printk(KERN_INFO, sdev, + "%s: enclosure logical id(0x%016llx), slot(%d)\n", + ds, + (unsigned long long)pcie_device->enclosure_logical_id, + pcie_device->slot); + if (pcie_device->connector_name[0] != '\0') + sdev_printk(KERN_INFO, sdev, + "%s: enclosure level(0x%04x)," + "connector name( %s)\n", ds, + pcie_device->enclosure_level, + pcie_device->connector_name); + pcie_device_put(pcie_device); + spin_unlock_irqrestore(&ioc->pcie_device_lock, flags); + scsih_change_queue_depth(sdev, qdepth); + + if (pcie_device->nvme_mdts) + blk_queue_max_hw_sectors(sdev->request_queue, + pcie_device->nvme_mdts/512); + /* Enable QUEUE_FLAG_NOMERGES flag, so that IOs won't be + ** merged and can eliminate holes created during merging + ** operation. + **/ + queue_flag_set_unlocked(QUEUE_FLAG_NOMERGES, + sdev->request_queue); + blk_queue_virt_boundary(sdev->request_queue, + ioc->page_size - 1); + return 0; + } + spin_lock_irqsave(&ioc->sas_device_lock, flags); sas_device = __mpt3sas_get_sdev_by_addr(ioc, sas_device_priv_data->sas_target->sas_address); @@ -2005,16 +2522,8 @@ scsih_slave_configure(struct scsi_device *sdev) "sas_addr(0x%016llx), phy(%d), device_name(0x%016llx)\n", ds, handle, (unsigned long long)sas_device->sas_address, sas_device->phy, (unsigned long long)sas_device->device_name); - if (sas_device->enclosure_handle != 0) - sdev_printk(KERN_INFO, sdev, - "%s: enclosure_logical_id(0x%016llx), slot(%d)\n", - ds, (unsigned long long) - sas_device->enclosure_logical_id, sas_device->slot); - if (sas_device->connector_name[0] != '\0') - sdev_printk(KERN_INFO, sdev, - "%s: enclosure level(0x%04x), connector name( %s)\n", - ds, sas_device->enclosure_level, - sas_device->connector_name); + + _scsih_display_enclosure_chassis_info(NULL, sas_device, sdev, NULL); sas_device_put(sas_device); spin_unlock_irqrestore(&ioc->sas_device_lock, flags); @@ -2400,6 +2909,7 @@ _scsih_tm_display_info(struct MPT3SAS_ADAPTER *ioc, struct scsi_cmnd *scmd) struct scsi_target *starget = scmd->device->sdev_target; struct MPT3SAS_TARGET *priv_target = starget->hostdata; struct _sas_device *sas_device = NULL; + struct _pcie_device *pcie_device = NULL; unsigned long flags; char *device_str = NULL; @@ -2416,6 +2926,31 @@ _scsih_tm_display_info(struct MPT3SAS_ADAPTER *ioc, struct scsi_cmnd *scmd) "%s handle(0x%04x), %s wwid(0x%016llx)\n", device_str, priv_target->handle, device_str, (unsigned long long)priv_target->sas_address); + + } else if (priv_target->flags & MPT_TARGET_FLAGS_PCIE_DEVICE) { + spin_lock_irqsave(&ioc->pcie_device_lock, flags); + pcie_device = __mpt3sas_get_pdev_from_target(ioc, priv_target); + if (pcie_device) { + starget_printk(KERN_INFO, starget, + "handle(0x%04x), wwid(0x%016llx), port(%d)\n", + pcie_device->handle, + (unsigned long long)pcie_device->wwid, + pcie_device->port_num); + if (pcie_device->enclosure_handle != 0) + starget_printk(KERN_INFO, starget, + "enclosure logical id(0x%016llx), slot(%d)\n", + (unsigned long long) + pcie_device->enclosure_logical_id, + pcie_device->slot); + if (pcie_device->connector_name[0] != '\0') + starget_printk(KERN_INFO, starget, + "enclosure level(0x%04x), connector name( %s)\n", + pcie_device->enclosure_level, + pcie_device->connector_name); + pcie_device_put(pcie_device); + } + spin_unlock_irqrestore(&ioc->pcie_device_lock, flags); + } else { spin_lock_irqsave(&ioc->sas_device_lock, flags); sas_device = __mpt3sas_get_sdev_from_target(ioc, priv_target); @@ -2433,17 +2968,9 @@ _scsih_tm_display_info(struct MPT3SAS_ADAPTER *ioc, struct scsi_cmnd *scmd) sas_device->handle, (unsigned long long)sas_device->sas_address, sas_device->phy); - if (sas_device->enclosure_handle != 0) - starget_printk(KERN_INFO, starget, - "enclosure_logical_id(0x%016llx), slot(%d)\n", - (unsigned long long) - sas_device->enclosure_logical_id, - sas_device->slot); - if (sas_device->connector_name[0] != '\0') - starget_printk(KERN_INFO, starget, - "enclosure level(0x%04x),connector name(%s)\n", - sas_device->enclosure_level, - sas_device->connector_name); + + _scsih_display_enclosure_chassis_info(NULL, sas_device, + NULL, starget); sas_device_put(sas_device); } @@ -3007,8 +3534,6 @@ _scsih_block_io_device(struct MPT3SAS_ADAPTER *ioc, u16 handle) struct _sas_device *sas_device; sas_device = mpt3sas_get_sdev_by_handle(ioc, handle); - if (!sas_device) - return; shost_for_each_device(sdev, ioc->shost) { sas_device_priv_data = sdev->hostdata; @@ -3018,7 +3543,7 @@ _scsih_block_io_device(struct MPT3SAS_ADAPTER *ioc, u16 handle) continue; if (sas_device_priv_data->block) continue; - if (sas_device->pend_sas_rphy_add) + if (sas_device && sas_device->pend_sas_rphy_add) continue; if (sas_device_priv_data->ignore_delay_remove) { sdev_printk(KERN_INFO, sdev, @@ -3029,7 +3554,8 @@ _scsih_block_io_device(struct MPT3SAS_ADAPTER *ioc, u16 handle) _scsih_internal_device_block(sdev, sas_device_priv_data); } - sas_device_put(sas_device); + if (sas_device) + sas_device_put(sas_device); } /** @@ -3113,6 +3639,33 @@ _scsih_block_io_to_children_attached_directly(struct MPT3SAS_ADAPTER *ioc, } /** + * _scsih_block_io_to_pcie_children_attached_directly + * @ioc: per adapter object + * @event_data: topology change event data + * + * This routine set sdev state to SDEV_BLOCK for all devices + * direct attached during device pull/reconnect. + */ +static void +_scsih_block_io_to_pcie_children_attached_directly(struct MPT3SAS_ADAPTER *ioc, + Mpi26EventDataPCIeTopologyChangeList_t *event_data) +{ + int i; + u16 handle; + u16 reason_code; + + for (i = 0; i < event_data->NumEntries; i++) { + handle = + le16_to_cpu(event_data->PortEntry[i].AttachedDevHandle); + if (!handle) + continue; + reason_code = event_data->PortEntry[i].PortStatus; + if (reason_code == + MPI26_EVENT_PCIE_TOPO_PS_DELAY_NOT_RESPONDING) + _scsih_block_io_device(ioc, handle); + } +} +/** * _scsih_tm_tr_send - send task management request * @ioc: per adapter object * @handle: device handle @@ -3133,18 +3686,14 @@ _scsih_tm_tr_send(struct MPT3SAS_ADAPTER *ioc, u16 handle) Mpi2SCSITaskManagementRequest_t *mpi_request; u16 smid; struct _sas_device *sas_device = NULL; + struct _pcie_device *pcie_device = NULL; struct MPT3SAS_TARGET *sas_target_priv_data = NULL; u64 sas_address = 0; unsigned long flags; struct _tr_list *delayed_tr; u32 ioc_state; - if (ioc->remove_host) { - dewtprintk(ioc, pr_info(MPT3SAS_FMT - "%s: host has been removed: handle(0x%04x)\n", - __func__, ioc->name, handle)); - return; - } else if (ioc->pci_error_recovery) { + if (ioc->pci_error_recovery) { dewtprintk(ioc, pr_info(MPT3SAS_FMT "%s: host in pci error recovery: handle(0x%04x)\n", __func__, ioc->name, @@ -3175,24 +3724,52 @@ _scsih_tm_tr_send(struct MPT3SAS_ADAPTER *ioc, u16 handle) sas_address = sas_device->sas_address; } spin_unlock_irqrestore(&ioc->sas_device_lock, flags); - + if (!sas_device) { + spin_lock_irqsave(&ioc->pcie_device_lock, flags); + pcie_device = __mpt3sas_get_pdev_by_handle(ioc, handle); + if (pcie_device && pcie_device->starget && + pcie_device->starget->hostdata) { + sas_target_priv_data = pcie_device->starget->hostdata; + sas_target_priv_data->deleted = 1; + sas_address = pcie_device->wwid; + } + spin_unlock_irqrestore(&ioc->pcie_device_lock, flags); + } if (sas_target_priv_data) { dewtprintk(ioc, pr_info(MPT3SAS_FMT "setting delete flag: handle(0x%04x), sas_addr(0x%016llx)\n", ioc->name, handle, (unsigned long long)sas_address)); - if (sas_device->enclosure_handle != 0) - dewtprintk(ioc, pr_info(MPT3SAS_FMT - "setting delete flag:enclosure logical id(0x%016llx)," - " slot(%d)\n", ioc->name, (unsigned long long) - sas_device->enclosure_logical_id, - sas_device->slot)); - if (sas_device->connector_name[0] != '\0') - dewtprintk(ioc, pr_info(MPT3SAS_FMT - "setting delete flag: enclosure level(0x%04x)," - " connector name( %s)\n", ioc->name, - sas_device->enclosure_level, - sas_device->connector_name)); + if (sas_device) { + if (sas_device->enclosure_handle != 0) + dewtprintk(ioc, pr_info(MPT3SAS_FMT + "setting delete flag:enclosure logical " + "id(0x%016llx), slot(%d)\n", ioc->name, + (unsigned long long) + sas_device->enclosure_logical_id, + sas_device->slot)); + if (sas_device->connector_name[0] != '\0') + dewtprintk(ioc, pr_info(MPT3SAS_FMT + "setting delete flag: enclosure " + "level(0x%04x), connector name( %s)\n", + ioc->name, sas_device->enclosure_level, + sas_device->connector_name)); + } else if (pcie_device) { + if (pcie_device->enclosure_handle != 0) + dewtprintk(ioc, pr_info(MPT3SAS_FMT + "setting delete flag: logical " + "id(0x%016llx), slot(%d)\n", ioc->name, + (unsigned long long) + pcie_device->enclosure_logical_id, + pcie_device->slot)); + if (pcie_device->connector_name[0] != '\0') + dewtprintk(ioc, pr_info(MPT3SAS_FMT + "setting delete flag:, enclosure " + "level(0x%04x), " + "connector name( %s)\n", ioc->name, + pcie_device->enclosure_level, + pcie_device->connector_name)); + } _scsih_ublock_io_device(ioc, sas_address); sas_target_priv_data->handle = MPT3SAS_INVALID_DEVICE_HANDLE; } @@ -3227,6 +3804,8 @@ _scsih_tm_tr_send(struct MPT3SAS_ADAPTER *ioc, u16 handle) out: if (sas_device) sas_device_put(sas_device); + if (pcie_device) + pcie_device_put(pcie_device); } /** @@ -3731,6 +4310,81 @@ _scsih_check_topo_delete_events(struct MPT3SAS_ADAPTER *ioc, } /** + * _scsih_check_pcie_topo_remove_events - sanity check on topo + * events + * @ioc: per adapter object + * @event_data: the event data payload + * + * This handles the case where driver receives multiple switch + * or device add and delete events in a single shot. When there + * is a delete event the routine will void any pending add + * events waiting in the event queue. + * + * Return nothing. + */ +static void +_scsih_check_pcie_topo_remove_events(struct MPT3SAS_ADAPTER *ioc, + Mpi26EventDataPCIeTopologyChangeList_t *event_data) +{ + struct fw_event_work *fw_event; + Mpi26EventDataPCIeTopologyChangeList_t *local_event_data; + unsigned long flags; + int i, reason_code; + u16 handle, switch_handle; + + for (i = 0; i < event_data->NumEntries; i++) { + handle = + le16_to_cpu(event_data->PortEntry[i].AttachedDevHandle); + if (!handle) + continue; + reason_code = event_data->PortEntry[i].PortStatus; + if (reason_code == MPI26_EVENT_PCIE_TOPO_PS_NOT_RESPONDING) + _scsih_tm_tr_send(ioc, handle); + } + + switch_handle = le16_to_cpu(event_data->SwitchDevHandle); + if (!switch_handle) { + _scsih_block_io_to_pcie_children_attached_directly( + ioc, event_data); + return; + } + /* TODO We are not supporting cascaded PCIe Switch removal yet*/ + if ((event_data->SwitchStatus + == MPI26_EVENT_PCIE_TOPO_SS_DELAY_NOT_RESPONDING) || + (event_data->SwitchStatus == + MPI26_EVENT_PCIE_TOPO_SS_RESPONDING)) + _scsih_block_io_to_pcie_children_attached_directly( + ioc, event_data); + + if (event_data->SwitchStatus != MPI2_EVENT_SAS_TOPO_ES_NOT_RESPONDING) + return; + + /* mark ignore flag for pending events */ + spin_lock_irqsave(&ioc->fw_event_lock, flags); + list_for_each_entry(fw_event, &ioc->fw_event_list, list) { + if (fw_event->event != MPI2_EVENT_PCIE_TOPOLOGY_CHANGE_LIST || + fw_event->ignore) + continue; + local_event_data = + (Mpi26EventDataPCIeTopologyChangeList_t *) + fw_event->event_data; + if (local_event_data->SwitchStatus == + MPI2_EVENT_SAS_TOPO_ES_ADDED || + local_event_data->SwitchStatus == + MPI2_EVENT_SAS_TOPO_ES_RESPONDING) { + if (le16_to_cpu(local_event_data->SwitchDevHandle) == + switch_handle) { + dewtprintk(ioc, pr_info(MPT3SAS_FMT + "setting ignoring flag for switch event\n", + ioc->name)); + fw_event->ignore = 1; + } + } + } + spin_unlock_irqrestore(&ioc->fw_event_lock, flags); +} + +/** * _scsih_set_volume_delete_flag - setting volume delete flag * @ioc: per adapter object * @handle: device handle @@ -3979,7 +4633,7 @@ _scsih_flush_running_cmds(struct MPT3SAS_ADAPTER *ioc) */ static void _scsih_setup_eedp(struct MPT3SAS_ADAPTER *ioc, struct scsi_cmnd *scmd, - Mpi2SCSIIORequest_t *mpi_request) + Mpi25SCSIIORequest_t *mpi_request) { u16 eedp_flags; unsigned char prot_op = scsi_get_prot_op(scmd); @@ -4082,7 +4736,8 @@ scsih_qcmd(struct Scsi_Host *shost, struct scsi_cmnd *scmd) struct _raid_device *raid_device; struct request *rq = scmd->request; int class; - Mpi2SCSIIORequest_t *mpi_request; + Mpi25SCSIIORequest_t *mpi_request; + struct _pcie_device *pcie_device = NULL; u32 mpi_control; u16 smid; u16 handle; @@ -4159,8 +4814,9 @@ scsih_qcmd(struct Scsi_Host *shost, struct scsi_cmnd *scmd) /* Make sure Device is not raid volume. * We do not expose raid functionality to upper layer for warpdrive. */ - if (!ioc->is_warpdrive && !scsih_is_raid(&scmd->device->sdev_gendev) - && sas_is_tlr_enabled(scmd->device) && scmd->cmd_len != 32) + if (((!ioc->is_warpdrive && !scsih_is_raid(&scmd->device->sdev_gendev)) + && !scsih_is_nvme(&scmd->device->sdev_gendev)) + && sas_is_tlr_enabled(scmd->device) && scmd->cmd_len != 32) mpi_control |= MPI2_SCSIIO_CONTROL_TLR_ON; smid = mpt3sas_base_get_smid_scsiio(ioc, ioc->scsi_io_cb_idx, scmd); @@ -4170,7 +4826,7 @@ scsih_qcmd(struct Scsi_Host *shost, struct scsi_cmnd *scmd) goto out; } mpi_request = mpt3sas_base_get_msg_frame(ioc, smid); - memset(mpi_request, 0, sizeof(Mpi2SCSIIORequest_t)); + memset(mpi_request, 0, ioc->request_sz); _scsih_setup_eedp(ioc, scmd, mpi_request); if (scmd->cmd_len == 32) @@ -4189,13 +4845,14 @@ scsih_qcmd(struct Scsi_Host *shost, struct scsi_cmnd *scmd) mpi_request->SenseBufferLength = SCSI_SENSE_BUFFERSIZE; mpi_request->SenseBufferLowAddress = mpt3sas_base_get_sense_buffer_dma(ioc, smid); - mpi_request->SGLOffset0 = offsetof(Mpi2SCSIIORequest_t, SGL) / 4; + mpi_request->SGLOffset0 = offsetof(Mpi25SCSIIORequest_t, SGL) / 4; int_to_scsilun(sas_device_priv_data->lun, (struct scsi_lun *) mpi_request->LUN); memcpy(mpi_request->CDB.CDB32, scmd->cmnd, scmd->cmd_len); if (mpi_request->DataLength) { - if (ioc->build_sg_scmd(ioc, scmd, smid)) { + pcie_device = sas_target_priv_data->pcie_dev; + if (ioc->build_sg_scmd(ioc, scmd, smid, pcie_device)) { mpt3sas_base_free_smid(ioc, smid); goto out; } @@ -4204,8 +4861,8 @@ scsih_qcmd(struct Scsi_Host *shost, struct scsi_cmnd *scmd) raid_device = sas_target_priv_data->raid_device; if (raid_device && raid_device->direct_io_enabled) - mpt3sas_setup_direct_io(ioc, scmd, raid_device, mpi_request, - smid); + mpt3sas_setup_direct_io(ioc, scmd, + raid_device, mpi_request, smid); if (likely(mpi_request->Function == MPI2_FUNCTION_SCSI_IO_REQUEST)) { if (sas_target_priv_data->flags & MPT_TARGET_FASTPATH_IO) { @@ -4273,6 +4930,7 @@ _scsih_scsi_ioc_info(struct MPT3SAS_ADAPTER *ioc, struct scsi_cmnd *scmd, char *desc_scsi_state = ioc->tmp_string; u32 log_info = le32_to_cpu(mpi_reply->IOCLogInfo); struct _sas_device *sas_device = NULL; + struct _pcie_device *pcie_device = NULL; struct scsi_target *starget = scmd->device->sdev_target; struct MPT3SAS_TARGET *priv_target = starget->hostdata; char *device_str = NULL; @@ -4405,6 +5063,28 @@ _scsih_scsi_ioc_info(struct MPT3SAS_ADAPTER *ioc, struct scsi_cmnd *scmd, if (priv_target->flags & MPT_TARGET_FLAGS_VOLUME) { pr_warn(MPT3SAS_FMT "\t%s wwid(0x%016llx)\n", ioc->name, device_str, (unsigned long long)priv_target->sas_address); + } else if (priv_target->flags & MPT_TARGET_FLAGS_PCIE_DEVICE) { + pcie_device = mpt3sas_get_pdev_from_target(ioc, priv_target); + if (pcie_device) { + pr_info(MPT3SAS_FMT "\twwid(0x%016llx), port(%d)\n", + ioc->name, + (unsigned long long)pcie_device->wwid, + pcie_device->port_num); + if (pcie_device->enclosure_handle != 0) + pr_info(MPT3SAS_FMT + "\tenclosure logical id(0x%016llx), " + "slot(%d)\n", ioc->name, + (unsigned long long) + pcie_device->enclosure_logical_id, + pcie_device->slot); + if (pcie_device->connector_name[0]) + pr_info(MPT3SAS_FMT + "\tenclosure level(0x%04x)," + "connector name( %s)\n", + ioc->name, pcie_device->enclosure_level, + pcie_device->connector_name); + pcie_device_put(pcie_device); + } } else { sas_device = mpt3sas_get_sdev_from_target(ioc, priv_target); if (sas_device) { @@ -4412,19 +5092,9 @@ _scsih_scsi_ioc_info(struct MPT3SAS_ADAPTER *ioc, struct scsi_cmnd *scmd, "\tsas_address(0x%016llx), phy(%d)\n", ioc->name, (unsigned long long) sas_device->sas_address, sas_device->phy); - if (sas_device->enclosure_handle != 0) - pr_warn(MPT3SAS_FMT - "\tenclosure_logical_id(0x%016llx)," - "slot(%d)\n", ioc->name, - (unsigned long long) - sas_device->enclosure_logical_id, - sas_device->slot); - if (sas_device->connector_name[0]) - pr_warn(MPT3SAS_FMT - "\tenclosure level(0x%04x)," - " connector name( %s)\n", ioc->name, - sas_device->enclosure_level, - sas_device->connector_name); + + _scsih_display_enclosure_chassis_info(ioc, sas_device, + NULL, NULL); sas_device_put(sas_device); } @@ -4451,11 +5121,10 @@ _scsih_scsi_ioc_info(struct MPT3SAS_ADAPTER *ioc, struct scsi_cmnd *scmd, struct sense_info data; _scsih_normalize_sense(scmd->sense_buffer, &data); pr_warn(MPT3SAS_FMT - "\t[sense_key,asc,ascq]: [0x%02x,0x%02x,0x%02x], count(%d)\n", - ioc->name, data.skey, - data.asc, data.ascq, le32_to_cpu(mpi_reply->SenseCount)); + "\t[sense_key,asc,ascq]: [0x%02x,0x%02x,0x%02x], count(%d)\n", + ioc->name, data.skey, + data.asc, data.ascq, le32_to_cpu(mpi_reply->SenseCount)); } - if (scsi_state & MPI2_SCSI_STATE_RESPONSE_INFO_VALID) { response_info = le32_to_cpu(mpi_reply->ResponseInfo); response_bytes = (u8 *)&response_info; @@ -4602,16 +5271,8 @@ _scsih_smart_predicted_fault(struct MPT3SAS_ADAPTER *ioc, u16 handle) ((sas_target_priv_data->flags & MPT_TARGET_FLAGS_VOLUME))) goto out_unlock; - if (sas_device->enclosure_handle != 0) - starget_printk(KERN_INFO, starget, "predicted fault, " - "enclosure logical id(0x%016llx), slot(%d)\n", - (unsigned long long)sas_device->enclosure_logical_id, - sas_device->slot); - if (sas_device->connector_name[0] != '\0') - starget_printk(KERN_WARNING, starget, "predicted fault, " - "enclosure level(0x%04x), connector name( %s)\n", - sas_device->enclosure_level, - sas_device->connector_name); + _scsih_display_enclosure_chassis_info(NULL, sas_device, NULL, starget); + spin_unlock_irqrestore(&ioc->sas_device_lock, flags); if (ioc->pdev->subsystem_vendor == PCI_VENDOR_ID_IBM) @@ -4666,7 +5327,7 @@ out_unlock: static u8 _scsih_io_done(struct MPT3SAS_ADAPTER *ioc, u16 smid, u8 msix_index, u32 reply) { - Mpi2SCSIIORequest_t *mpi_request; + Mpi25SCSIIORequest_t *mpi_request; Mpi2SCSIIOReply_t *mpi_reply; struct scsi_cmnd *scmd; u16 ioc_status; @@ -4731,9 +5392,10 @@ _scsih_io_done(struct MPT3SAS_ADAPTER *ioc, u16 smid, u8 msix_index, u32 reply) le32_to_cpu(mpi_reply->ResponseInfo) & 0xFF; if (!sas_device_priv_data->tlr_snoop_check) { sas_device_priv_data->tlr_snoop_check++; - if (!ioc->is_warpdrive && + if ((!ioc->is_warpdrive && !scsih_is_raid(&scmd->device->sdev_gendev) && - sas_is_tlr_enabled(scmd->device) && + !scsih_is_nvme(&scmd->device->sdev_gendev)) + && sas_is_tlr_enabled(scmd->device) && response_code == MPI2_SCSITASKMGMT_RSP_INVALID_FRAME) { sas_disable_tlr(scmd->device); sdev_printk(KERN_INFO, scmd->device, "TLR disabled\n"); @@ -4804,6 +5466,11 @@ _scsih_io_done(struct MPT3SAS_ADAPTER *ioc, u16 smid, u8 msix_index, u32 reply) } else if (log_info == VIRTUAL_IO_FAILED_RETRY) { scmd->result = DID_RESET << 16; break; + } else if ((scmd->device->channel == RAID_CHANNEL) && + (scsi_state == (MPI2_SCSI_STATE_TERMINATED | + MPI2_SCSI_STATE_NO_SCSI_STATUS))) { + scmd->result = DID_RESET << 16; + break; } scmd->result = DID_SOFT_ERROR << 16; break; @@ -5274,8 +5941,6 @@ mpt3sas_expander_remove(struct MPT3SAS_ADAPTER *ioc, u64 sas_address) spin_lock_irqsave(&ioc->sas_node_lock, flags); sas_expander = mpt3sas_scsih_expander_find_by_sas_address(ioc, sas_address); - if (sas_expander) - list_del(&sas_expander->list); spin_unlock_irqrestore(&ioc->sas_node_lock, flags); if (sas_expander) _scsih_expander_node_remove(ioc, sas_expander); @@ -5386,6 +6051,52 @@ _scsih_check_access_status(struct MPT3SAS_ADAPTER *ioc, u64 sas_address, } /** + * _scsih_get_enclosure_logicalid_chassis_slot - get device's + * EnclosureLogicalID and ChassisSlot information. + * @ioc: per adapter object + * @sas_device_pg0: SAS device page0 + * @sas_device: per sas device object + * + * Returns nothing. + */ +static void +_scsih_get_enclosure_logicalid_chassis_slot(struct MPT3SAS_ADAPTER *ioc, + Mpi2SasDevicePage0_t *sas_device_pg0, struct _sas_device *sas_device) +{ + Mpi2ConfigReply_t mpi_reply; + Mpi2SasEnclosurePage0_t enclosure_pg0; + + if (!sas_device_pg0 || !sas_device) + return; + + sas_device->enclosure_handle = + le16_to_cpu(sas_device_pg0->EnclosureHandle); + sas_device->is_chassis_slot_valid = 0; + + if (!le16_to_cpu(sas_device_pg0->EnclosureHandle)) + return; + + if (mpt3sas_config_get_enclosure_pg0(ioc, &mpi_reply, + &enclosure_pg0, MPI2_SAS_ENCLOS_PGAD_FORM_HANDLE, + le16_to_cpu(sas_device_pg0->EnclosureHandle))) { + pr_err(MPT3SAS_FMT + "Enclosure Pg0 read failed for handle(0x%04x)\n", + ioc->name, le16_to_cpu(sas_device_pg0->EnclosureHandle)); + return; + } + + sas_device->enclosure_logical_id = + le64_to_cpu(enclosure_pg0.EnclosureLogicalID); + + if (le16_to_cpu(enclosure_pg0.Flags) & + MPI2_SAS_ENCLS0_FLAGS_CHASSIS_SLOT_VALID) { + sas_device->is_chassis_slot_valid = 1; + sas_device->chassis_slot = enclosure_pg0.ChassisSlot; + } +} + + +/** * _scsih_check_device - checking device responsiveness * @ioc: per adapter object * @parent_sas_address: sas address of parent expander or sas host @@ -5409,7 +6120,6 @@ _scsih_check_device(struct MPT3SAS_ADAPTER *ioc, struct MPT3SAS_TARGET *sas_target_priv_data; u32 device_info; - if ((mpt3sas_config_get_sas_device_pg0(ioc, &mpi_reply, &sas_device_pg0, MPI2_SAS_DEVICE_PGAD_FORM_HANDLE, handle))) return; @@ -5456,6 +6166,9 @@ _scsih_check_device(struct MPT3SAS_ADAPTER *ioc, sas_device->enclosure_level = 0; sas_device->connector_name[0] = '\0'; } + + _scsih_get_enclosure_logicalid_chassis_slot(ioc, + &sas_device_pg0, sas_device); } /* check if device is present */ @@ -5507,6 +6220,7 @@ _scsih_add_device(struct MPT3SAS_ADAPTER *ioc, u16 handle, u8 phy_num, u32 ioc_status; u64 sas_address; u32 device_info; + int encl_pg0_rc = -1; if ((mpt3sas_config_get_sas_device_pg0(ioc, &mpi_reply, &sas_device_pg0, MPI2_SAS_DEVICE_PGAD_FORM_HANDLE, handle))) { @@ -5551,6 +6265,16 @@ _scsih_add_device(struct MPT3SAS_ADAPTER *ioc, u16 handle, u8 phy_num, return -1; } + if (sas_device_pg0.EnclosureHandle) { + encl_pg0_rc = mpt3sas_config_get_enclosure_pg0(ioc, &mpi_reply, + &enclosure_pg0, MPI2_SAS_ENCLOS_PGAD_FORM_HANDLE, + sas_device_pg0.EnclosureHandle); + if (encl_pg0_rc) + pr_info(MPT3SAS_FMT + "Enclosure Pg0 read failed for handle(0x%04x)\n", + ioc->name, sas_device_pg0.EnclosureHandle); + } + sas_device = kzalloc(sizeof(struct _sas_device), GFP_KERNEL); if (!sas_device) { @@ -5588,13 +6312,21 @@ _scsih_add_device(struct MPT3SAS_ADAPTER *ioc, u16 handle, u8 phy_num, sas_device->enclosure_level = 0; sas_device->connector_name[0] = '\0'; } - /* get enclosure_logical_id */ - if (sas_device->enclosure_handle && !(mpt3sas_config_get_enclosure_pg0( - ioc, &mpi_reply, &enclosure_pg0, MPI2_SAS_ENCLOS_PGAD_FORM_HANDLE, - sas_device->enclosure_handle))) + + /* get enclosure_logical_id & chassis_slot */ + sas_device->is_chassis_slot_valid = 0; + if (encl_pg0_rc == 0) { sas_device->enclosure_logical_id = le64_to_cpu(enclosure_pg0.EnclosureLogicalID); + if (le16_to_cpu(enclosure_pg0.Flags) & + MPI2_SAS_ENCLS0_FLAGS_CHASSIS_SLOT_VALID) { + sas_device->is_chassis_slot_valid = 1; + sas_device->chassis_slot = + enclosure_pg0.ChassisSlot; + } + } + /* get device name */ sas_device->device_name = le64_to_cpu(sas_device_pg0.DeviceName); @@ -5625,23 +6357,15 @@ _scsih_remove_device(struct MPT3SAS_ADAPTER *ioc, _scsih_turn_off_pfa_led(ioc, sas_device); sas_device->pfa_led_on = 0; } + dewtprintk(ioc, pr_info(MPT3SAS_FMT "%s: enter: handle(0x%04x), sas_addr(0x%016llx)\n", ioc->name, __func__, sas_device->handle, (unsigned long long) sas_device->sas_address)); - if (sas_device->enclosure_handle != 0) - dewtprintk(ioc, pr_info(MPT3SAS_FMT - "%s: enter: enclosure logical id(0x%016llx), slot(%d)\n", - ioc->name, __func__, - (unsigned long long)sas_device->enclosure_logical_id, - sas_device->slot)); - if (sas_device->connector_name[0] != '\0') - dewtprintk(ioc, pr_info(MPT3SAS_FMT - "%s: enter: enclosure level(0x%04x), connector name( %s)\n", - ioc->name, __func__, - sas_device->enclosure_level, - sas_device->connector_name)); + + dewtprintk(ioc, _scsih_display_enclosure_chassis_info(ioc, sas_device, + NULL, NULL)); if (sas_device->starget && sas_device->starget->hostdata) { sas_target_priv_data = sas_device->starget->hostdata; @@ -5660,34 +6384,16 @@ _scsih_remove_device(struct MPT3SAS_ADAPTER *ioc, "removing handle(0x%04x), sas_addr(0x%016llx)\n", ioc->name, sas_device->handle, (unsigned long long) sas_device->sas_address); - if (sas_device->enclosure_handle != 0) - pr_info(MPT3SAS_FMT - "removing : enclosure logical id(0x%016llx), slot(%d)\n", - ioc->name, - (unsigned long long)sas_device->enclosure_logical_id, - sas_device->slot); - if (sas_device->connector_name[0] != '\0') - pr_info(MPT3SAS_FMT - "removing enclosure level(0x%04x), connector name( %s)\n", - ioc->name, sas_device->enclosure_level, - sas_device->connector_name); + + _scsih_display_enclosure_chassis_info(ioc, sas_device, NULL, NULL); dewtprintk(ioc, pr_info(MPT3SAS_FMT "%s: exit: handle(0x%04x), sas_addr(0x%016llx)\n", ioc->name, __func__, sas_device->handle, (unsigned long long) sas_device->sas_address)); - if (sas_device->enclosure_handle != 0) - dewtprintk(ioc, pr_info(MPT3SAS_FMT - "%s: exit: enclosure logical id(0x%016llx), slot(%d)\n", - ioc->name, __func__, - (unsigned long long)sas_device->enclosure_logical_id, - sas_device->slot)); - if (sas_device->connector_name[0] != '\0') - dewtprintk(ioc, pr_info(MPT3SAS_FMT - "%s: exit: enclosure level(0x%04x), connector name(%s)\n", - ioc->name, __func__, sas_device->enclosure_level, - sas_device->connector_name)); + dewtprintk(ioc, _scsih_display_enclosure_chassis_info(ioc, sas_device, + NULL, NULL)); } /** @@ -6028,7 +6734,705 @@ out: sas_device_put(sas_device); spin_unlock_irqrestore(&ioc->sas_device_lock, flags); +} + + +/** + * _scsih_check_pcie_access_status - check access flags + * @ioc: per adapter object + * @wwid: wwid + * @handle: sas device handle + * @access_flags: errors returned during discovery of the device + * + * Return 0 for success, else failure + */ +static u8 +_scsih_check_pcie_access_status(struct MPT3SAS_ADAPTER *ioc, u64 wwid, + u16 handle, u8 access_status) +{ + u8 rc = 1; + char *desc = NULL; + + switch (access_status) { + case MPI26_PCIEDEV0_ASTATUS_NO_ERRORS: + case MPI26_PCIEDEV0_ASTATUS_NEEDS_INITIALIZATION: + rc = 0; + break; + case MPI26_PCIEDEV0_ASTATUS_CAPABILITY_FAILED: + desc = "PCIe device capability failed"; + break; + case MPI26_PCIEDEV0_ASTATUS_DEVICE_BLOCKED: + desc = "PCIe device blocked"; + break; + case MPI26_PCIEDEV0_ASTATUS_MEMORY_SPACE_ACCESS_FAILED: + desc = "PCIe device mem space access failed"; + break; + case MPI26_PCIEDEV0_ASTATUS_UNSUPPORTED_DEVICE: + desc = "PCIe device unsupported"; + break; + case MPI26_PCIEDEV0_ASTATUS_MSIX_REQUIRED: + desc = "PCIe device MSIx Required"; + break; + case MPI26_PCIEDEV0_ASTATUS_INIT_FAIL_MAX: + desc = "PCIe device init fail max"; + break; + case MPI26_PCIEDEV0_ASTATUS_UNKNOWN: + desc = "PCIe device status unknown"; + break; + case MPI26_PCIEDEV0_ASTATUS_NVME_READY_TIMEOUT: + desc = "nvme ready timeout"; + break; + case MPI26_PCIEDEV0_ASTATUS_NVME_DEVCFG_UNSUPPORTED: + desc = "nvme device configuration unsupported"; + break; + case MPI26_PCIEDEV0_ASTATUS_NVME_IDENTIFY_FAILED: + desc = "nvme identify failed"; + break; + case MPI26_PCIEDEV0_ASTATUS_NVME_QCONFIG_FAILED: + desc = "nvme qconfig failed"; + break; + case MPI26_PCIEDEV0_ASTATUS_NVME_QCREATION_FAILED: + desc = "nvme qcreation failed"; + break; + case MPI26_PCIEDEV0_ASTATUS_NVME_EVENTCFG_FAILED: + desc = "nvme eventcfg failed"; + break; + case MPI26_PCIEDEV0_ASTATUS_NVME_GET_FEATURE_STAT_FAILED: + desc = "nvme get feature stat failed"; + break; + case MPI26_PCIEDEV0_ASTATUS_NVME_IDLE_TIMEOUT: + desc = "nvme idle timeout"; + break; + case MPI26_PCIEDEV0_ASTATUS_NVME_FAILURE_STATUS: + desc = "nvme failure status"; + break; + default: + pr_err(MPT3SAS_FMT + " NVMe discovery error(0x%02x): wwid(0x%016llx)," + "handle(0x%04x)\n", ioc->name, access_status, + (unsigned long long)wwid, handle); + return rc; + } + + if (!rc) + return rc; + + pr_info(MPT3SAS_FMT + "NVMe discovery error(%s): wwid(0x%016llx), handle(0x%04x)\n", + ioc->name, desc, + (unsigned long long)wwid, handle); + return rc; +} + +/** + * _scsih_pcie_device_remove_from_sml - removing pcie device + * from SML and free up associated memory + * @ioc: per adapter object + * @pcie_device: the pcie_device object + * + * Return nothing. + */ +static void +_scsih_pcie_device_remove_from_sml(struct MPT3SAS_ADAPTER *ioc, + struct _pcie_device *pcie_device) +{ + struct MPT3SAS_TARGET *sas_target_priv_data; + + dewtprintk(ioc, pr_info(MPT3SAS_FMT + "%s: enter: handle(0x%04x), wwid(0x%016llx)\n", ioc->name, __func__, + pcie_device->handle, (unsigned long long) + pcie_device->wwid)); + if (pcie_device->enclosure_handle != 0) + dewtprintk(ioc, pr_info(MPT3SAS_FMT + "%s: enter: enclosure logical id(0x%016llx), slot(%d)\n", + ioc->name, __func__, + (unsigned long long)pcie_device->enclosure_logical_id, + pcie_device->slot)); + if (pcie_device->connector_name[0] != '\0') + dewtprintk(ioc, pr_info(MPT3SAS_FMT + "%s: enter: enclosure level(0x%04x), connector name( %s)\n", + ioc->name, __func__, + pcie_device->enclosure_level, + pcie_device->connector_name)); + + if (pcie_device->starget && pcie_device->starget->hostdata) { + sas_target_priv_data = pcie_device->starget->hostdata; + sas_target_priv_data->deleted = 1; + _scsih_ublock_io_device(ioc, pcie_device->wwid); + sas_target_priv_data->handle = MPT3SAS_INVALID_DEVICE_HANDLE; + } + + pr_info(MPT3SAS_FMT + "removing handle(0x%04x), wwid (0x%016llx)\n", + ioc->name, pcie_device->handle, + (unsigned long long) pcie_device->wwid); + if (pcie_device->enclosure_handle != 0) + pr_info(MPT3SAS_FMT + "removing : enclosure logical id(0x%016llx), slot(%d)\n", + ioc->name, + (unsigned long long)pcie_device->enclosure_logical_id, + pcie_device->slot); + if (pcie_device->connector_name[0] != '\0') + pr_info(MPT3SAS_FMT + "removing: enclosure level(0x%04x), connector name( %s)\n", + ioc->name, pcie_device->enclosure_level, + pcie_device->connector_name); + + if (pcie_device->starget) + scsi_remove_target(&pcie_device->starget->dev); + dewtprintk(ioc, pr_info(MPT3SAS_FMT + "%s: exit: handle(0x%04x), wwid(0x%016llx)\n", ioc->name, __func__, + pcie_device->handle, (unsigned long long) + pcie_device->wwid)); + if (pcie_device->enclosure_handle != 0) + dewtprintk(ioc, pr_info(MPT3SAS_FMT + "%s: exit: enclosure logical id(0x%016llx), slot(%d)\n", + ioc->name, __func__, + (unsigned long long)pcie_device->enclosure_logical_id, + pcie_device->slot)); + if (pcie_device->connector_name[0] != '\0') + dewtprintk(ioc, pr_info(MPT3SAS_FMT + "%s: exit: enclosure level(0x%04x), connector name( %s)\n", + ioc->name, __func__, pcie_device->enclosure_level, + pcie_device->connector_name)); + + kfree(pcie_device->serial_number); +} + + +/** + * _scsih_pcie_check_device - checking device responsiveness + * @ioc: per adapter object + * @handle: attached device handle + * + * Returns nothing. + */ +static void +_scsih_pcie_check_device(struct MPT3SAS_ADAPTER *ioc, u16 handle) +{ + Mpi2ConfigReply_t mpi_reply; + Mpi26PCIeDevicePage0_t pcie_device_pg0; + u32 ioc_status; + struct _pcie_device *pcie_device; + u64 wwid; + unsigned long flags; + struct scsi_target *starget; + struct MPT3SAS_TARGET *sas_target_priv_data; + u32 device_info; + + if ((mpt3sas_config_get_pcie_device_pg0(ioc, &mpi_reply, + &pcie_device_pg0, MPI26_PCIE_DEVICE_PGAD_FORM_HANDLE, handle))) + return; + + ioc_status = le16_to_cpu(mpi_reply.IOCStatus) & MPI2_IOCSTATUS_MASK; + if (ioc_status != MPI2_IOCSTATUS_SUCCESS) + return; + + /* check if this is end device */ + device_info = le32_to_cpu(pcie_device_pg0.DeviceInfo); + if (!(_scsih_is_nvme_device(device_info))) + return; + + wwid = le64_to_cpu(pcie_device_pg0.WWID); + spin_lock_irqsave(&ioc->pcie_device_lock, flags); + pcie_device = __mpt3sas_get_pdev_by_wwid(ioc, wwid); + + if (!pcie_device) { + spin_unlock_irqrestore(&ioc->pcie_device_lock, flags); + return; + } + + if (unlikely(pcie_device->handle != handle)) { + starget = pcie_device->starget; + sas_target_priv_data = starget->hostdata; + starget_printk(KERN_INFO, starget, + "handle changed from(0x%04x) to (0x%04x)!!!\n", + pcie_device->handle, handle); + sas_target_priv_data->handle = handle; + pcie_device->handle = handle; + + if (le32_to_cpu(pcie_device_pg0.Flags) & + MPI26_PCIEDEV0_FLAGS_ENCL_LEVEL_VALID) { + pcie_device->enclosure_level = + pcie_device_pg0.EnclosureLevel; + memcpy(&pcie_device->connector_name[0], + &pcie_device_pg0.ConnectorName[0], 4); + } else { + pcie_device->enclosure_level = 0; + pcie_device->connector_name[0] = '\0'; + } + } + + /* check if device is present */ + if (!(le32_to_cpu(pcie_device_pg0.Flags) & + MPI26_PCIEDEV0_FLAGS_DEVICE_PRESENT)) { + pr_info(MPT3SAS_FMT + "device is not present handle(0x%04x), flags!!!\n", + ioc->name, handle); + spin_unlock_irqrestore(&ioc->pcie_device_lock, flags); + pcie_device_put(pcie_device); + return; + } + + /* check if there were any issues with discovery */ + if (_scsih_check_pcie_access_status(ioc, wwid, handle, + pcie_device_pg0.AccessStatus)) { + spin_unlock_irqrestore(&ioc->pcie_device_lock, flags); + pcie_device_put(pcie_device); + return; + } + + spin_unlock_irqrestore(&ioc->pcie_device_lock, flags); + pcie_device_put(pcie_device); + + _scsih_ublock_io_device(ioc, wwid); + + return; +} + +/** + * _scsih_pcie_add_device - creating pcie device object + * @ioc: per adapter object + * @handle: pcie device handle + * + * Creating end device object, stored in ioc->pcie_device_list. + * + * Return 1 means queue the event later, 0 means complete the event + */ +static int +_scsih_pcie_add_device(struct MPT3SAS_ADAPTER *ioc, u16 handle) +{ + Mpi26PCIeDevicePage0_t pcie_device_pg0; + Mpi26PCIeDevicePage2_t pcie_device_pg2; + Mpi2ConfigReply_t mpi_reply; + Mpi2SasEnclosurePage0_t enclosure_pg0; + struct _pcie_device *pcie_device; + u32 pcie_device_type; + u32 ioc_status; + u64 wwid; + + if ((mpt3sas_config_get_pcie_device_pg0(ioc, &mpi_reply, + &pcie_device_pg0, MPI26_PCIE_DEVICE_PGAD_FORM_HANDLE, handle))) { + pr_err(MPT3SAS_FMT "failure at %s:%d/%s()!\n", + ioc->name, __FILE__, __LINE__, __func__); + return 0; + } + ioc_status = le16_to_cpu(mpi_reply.IOCStatus) & + MPI2_IOCSTATUS_MASK; + if (ioc_status != MPI2_IOCSTATUS_SUCCESS) { + pr_err(MPT3SAS_FMT + "failure at %s:%d/%s()!\n", + ioc->name, __FILE__, __LINE__, __func__); + return 0; + } + + set_bit(handle, ioc->pend_os_device_add); + wwid = le64_to_cpu(pcie_device_pg0.WWID); + + /* check if device is present */ + if (!(le32_to_cpu(pcie_device_pg0.Flags) & + MPI26_PCIEDEV0_FLAGS_DEVICE_PRESENT)) { + pr_err(MPT3SAS_FMT + "device is not present handle(0x04%x)!!!\n", + ioc->name, handle); + return 0; + } + + /* check if there were any issues with discovery */ + if (_scsih_check_pcie_access_status(ioc, wwid, handle, + pcie_device_pg0.AccessStatus)) + return 0; + + if (!(_scsih_is_nvme_device(le32_to_cpu(pcie_device_pg0.DeviceInfo)))) + return 0; + + pcie_device = mpt3sas_get_pdev_by_wwid(ioc, wwid); + if (pcie_device) { + clear_bit(handle, ioc->pend_os_device_add); + pcie_device_put(pcie_device); + return 0; + } + + pcie_device = kzalloc(sizeof(struct _pcie_device), GFP_KERNEL); + if (!pcie_device) { + pr_err(MPT3SAS_FMT "failure at %s:%d/%s()!\n", + ioc->name, __FILE__, __LINE__, __func__); + return 0; + } + + kref_init(&pcie_device->refcount); + pcie_device->id = ioc->pcie_target_id++; + pcie_device->channel = PCIE_CHANNEL; + pcie_device->handle = handle; + pcie_device->device_info = le32_to_cpu(pcie_device_pg0.DeviceInfo); + pcie_device->wwid = wwid; + pcie_device->port_num = pcie_device_pg0.PortNum; + pcie_device->fast_path = (le32_to_cpu(pcie_device_pg0.Flags) & + MPI26_PCIEDEV0_FLAGS_FAST_PATH_CAPABLE) ? 1 : 0; + pcie_device_type = pcie_device->device_info & + MPI26_PCIE_DEVINFO_MASK_DEVICE_TYPE; + + pcie_device->enclosure_handle = + le16_to_cpu(pcie_device_pg0.EnclosureHandle); + if (pcie_device->enclosure_handle != 0) + pcie_device->slot = le16_to_cpu(pcie_device_pg0.Slot); + + if (le16_to_cpu(pcie_device_pg0.Flags) & + MPI26_PCIEDEV0_FLAGS_ENCL_LEVEL_VALID) { + pcie_device->enclosure_level = pcie_device_pg0.EnclosureLevel; + memcpy(&pcie_device->connector_name[0], + &pcie_device_pg0.ConnectorName[0], 4); + } else { + pcie_device->enclosure_level = 0; + pcie_device->connector_name[0] = '\0'; + } + + /* get enclosure_logical_id */ + if (pcie_device->enclosure_handle && + !(mpt3sas_config_get_enclosure_pg0(ioc, &mpi_reply, + &enclosure_pg0, MPI2_SAS_ENCLOS_PGAD_FORM_HANDLE, + pcie_device->enclosure_handle))) + pcie_device->enclosure_logical_id = + le64_to_cpu(enclosure_pg0.EnclosureLogicalID); + + /* TODO -- Add device name once FW supports it */ + if (mpt3sas_config_get_pcie_device_pg2(ioc, &mpi_reply, + &pcie_device_pg2, MPI2_SAS_DEVICE_PGAD_FORM_HANDLE, handle)) { + pr_err(MPT3SAS_FMT "failure at %s:%d/%s()!\n", + ioc->name, __FILE__, __LINE__, __func__); + kfree(pcie_device); + return 0; + } + + ioc_status = le16_to_cpu(mpi_reply.IOCStatus) & MPI2_IOCSTATUS_MASK; + if (ioc_status != MPI2_IOCSTATUS_SUCCESS) { + pr_err(MPT3SAS_FMT "failure at %s:%d/%s()!\n", + ioc->name, __FILE__, __LINE__, __func__); + kfree(pcie_device); + return 0; + } + pcie_device->nvme_mdts = + le32_to_cpu(pcie_device_pg2.MaximumDataTransferSize); + + if (ioc->wait_for_discovery_to_complete) + _scsih_pcie_device_init_add(ioc, pcie_device); + else + _scsih_pcie_device_add(ioc, pcie_device); + + pcie_device_put(pcie_device); + return 0; +} + +/** + * _scsih_pcie_topology_change_event_debug - debug for topology + * event + * @ioc: per adapter object + * @event_data: event data payload + * Context: user. + */ +static void +_scsih_pcie_topology_change_event_debug(struct MPT3SAS_ADAPTER *ioc, + Mpi26EventDataPCIeTopologyChangeList_t *event_data) +{ + int i; + u16 handle; + u16 reason_code; + u8 port_number; + char *status_str = NULL; + u8 link_rate, prev_link_rate; + + switch (event_data->SwitchStatus) { + case MPI26_EVENT_PCIE_TOPO_SS_ADDED: + status_str = "add"; + break; + case MPI26_EVENT_PCIE_TOPO_SS_NOT_RESPONDING: + status_str = "remove"; + break; + case MPI26_EVENT_PCIE_TOPO_SS_RESPONDING: + case 0: + status_str = "responding"; + break; + case MPI26_EVENT_PCIE_TOPO_SS_DELAY_NOT_RESPONDING: + status_str = "remove delay"; + break; + default: + status_str = "unknown status"; + break; + } + pr_info(MPT3SAS_FMT "pcie topology change: (%s)\n", + ioc->name, status_str); + pr_info("\tswitch_handle(0x%04x), enclosure_handle(0x%04x)" + "start_port(%02d), count(%d)\n", + le16_to_cpu(event_data->SwitchDevHandle), + le16_to_cpu(event_data->EnclosureHandle), + event_data->StartPortNum, event_data->NumEntries); + for (i = 0; i < event_data->NumEntries; i++) { + handle = + le16_to_cpu(event_data->PortEntry[i].AttachedDevHandle); + if (!handle) + continue; + port_number = event_data->StartPortNum + i; + reason_code = event_data->PortEntry[i].PortStatus; + switch (reason_code) { + case MPI26_EVENT_PCIE_TOPO_PS_DEV_ADDED: + status_str = "target add"; + break; + case MPI26_EVENT_PCIE_TOPO_PS_NOT_RESPONDING: + status_str = "target remove"; + break; + case MPI26_EVENT_PCIE_TOPO_PS_DELAY_NOT_RESPONDING: + status_str = "delay target remove"; + break; + case MPI26_EVENT_PCIE_TOPO_PS_PORT_CHANGED: + status_str = "link rate change"; + break; + case MPI26_EVENT_PCIE_TOPO_PS_NO_CHANGE: + status_str = "target responding"; + break; + default: + status_str = "unknown"; + break; + } + link_rate = event_data->PortEntry[i].CurrentPortInfo & + MPI26_EVENT_PCIE_TOPO_PI_RATE_MASK; + prev_link_rate = event_data->PortEntry[i].PreviousPortInfo & + MPI26_EVENT_PCIE_TOPO_PI_RATE_MASK; + pr_info("\tport(%02d), attached_handle(0x%04x): %s:" + " link rate: new(0x%02x), old(0x%02x)\n", port_number, + handle, status_str, link_rate, prev_link_rate); + } +} + +/** + * _scsih_pcie_topology_change_event - handle PCIe topology + * changes + * @ioc: per adapter object + * @fw_event: The fw_event_work object + * Context: user. + * + */ +static int +_scsih_pcie_topology_change_event(struct MPT3SAS_ADAPTER *ioc, + struct fw_event_work *fw_event) +{ + int i; + u16 handle; + u16 reason_code; + u8 link_rate, prev_link_rate; + unsigned long flags; + int rc; + int requeue_event; + Mpi26EventDataPCIeTopologyChangeList_t *event_data = + (Mpi26EventDataPCIeTopologyChangeList_t *) fw_event->event_data; + struct _pcie_device *pcie_device; + + if (ioc->logging_level & MPT_DEBUG_EVENT_WORK_TASK) + _scsih_pcie_topology_change_event_debug(ioc, event_data); + + if (ioc->shost_recovery || ioc->remove_host || + ioc->pci_error_recovery) + return 0; + + if (fw_event->ignore) { + dewtprintk(ioc, pr_info(MPT3SAS_FMT "ignoring switch event\n", + ioc->name)); + return 0; + } + + /* handle siblings events */ + for (i = 0; i < event_data->NumEntries; i++) { + if (fw_event->ignore) { + dewtprintk(ioc, pr_info(MPT3SAS_FMT + "ignoring switch event\n", ioc->name)); + return 0; + } + if (ioc->remove_host || ioc->pci_error_recovery) + return 0; + reason_code = event_data->PortEntry[i].PortStatus; + handle = + le16_to_cpu(event_data->PortEntry[i].AttachedDevHandle); + if (!handle) + continue; + + link_rate = event_data->PortEntry[i].CurrentPortInfo + & MPI26_EVENT_PCIE_TOPO_PI_RATE_MASK; + prev_link_rate = event_data->PortEntry[i].PreviousPortInfo + & MPI26_EVENT_PCIE_TOPO_PI_RATE_MASK; + + switch (reason_code) { + case MPI26_EVENT_PCIE_TOPO_PS_PORT_CHANGED: + if (ioc->shost_recovery) + break; + if (link_rate == prev_link_rate) + break; + if (link_rate < MPI26_EVENT_PCIE_TOPO_PI_RATE_2_5) + break; + + _scsih_pcie_check_device(ioc, handle); + /* This code after this point handles the test case + * where a device has been added, however its returning + * BUSY for sometime. Then before the Device Missing + * Delay expires and the device becomes READY, the + * device is removed and added back. + */ + spin_lock_irqsave(&ioc->pcie_device_lock, flags); + pcie_device = __mpt3sas_get_pdev_by_handle(ioc, handle); + spin_unlock_irqrestore(&ioc->pcie_device_lock, flags); + + if (pcie_device) { + pcie_device_put(pcie_device); + break; + } + + if (!test_bit(handle, ioc->pend_os_device_add)) + break; + + dewtprintk(ioc, pr_info(MPT3SAS_FMT + "handle(0x%04x) device not found: convert " + "event to a device add\n", ioc->name, handle)); + event_data->PortEntry[i].PortStatus &= 0xF0; + event_data->PortEntry[i].PortStatus |= + MPI26_EVENT_PCIE_TOPO_PS_DEV_ADDED; + case MPI26_EVENT_PCIE_TOPO_PS_DEV_ADDED: + if (ioc->shost_recovery) + break; + if (link_rate < MPI26_EVENT_PCIE_TOPO_PI_RATE_2_5) + break; + + rc = _scsih_pcie_add_device(ioc, handle); + if (!rc) { + /* mark entry vacant */ + /* TODO This needs to be reviewed and fixed, + * we dont have an entry + * to make an event void like vacant + */ + event_data->PortEntry[i].PortStatus |= + MPI26_EVENT_PCIE_TOPO_PS_NO_CHANGE; + } + break; + case MPI26_EVENT_PCIE_TOPO_PS_NOT_RESPONDING: + _scsih_pcie_device_remove_by_handle(ioc, handle); + break; + } + } + return requeue_event; +} + +/** + * _scsih_pcie_device_status_change_event_debug - debug for + * device event + * @event_data: event data payload + * Context: user. + * + * Return nothing. + */ +static void +_scsih_pcie_device_status_change_event_debug(struct MPT3SAS_ADAPTER *ioc, + Mpi26EventDataPCIeDeviceStatusChange_t *event_data) +{ + char *reason_str = NULL; + + switch (event_data->ReasonCode) { + case MPI26_EVENT_PCIDEV_STAT_RC_SMART_DATA: + reason_str = "smart data"; + break; + case MPI26_EVENT_PCIDEV_STAT_RC_UNSUPPORTED: + reason_str = "unsupported device discovered"; + break; + case MPI26_EVENT_PCIDEV_STAT_RC_INTERNAL_DEVICE_RESET: + reason_str = "internal device reset"; + break; + case MPI26_EVENT_PCIDEV_STAT_RC_TASK_ABORT_INTERNAL: + reason_str = "internal task abort"; + break; + case MPI26_EVENT_PCIDEV_STAT_RC_ABORT_TASK_SET_INTERNAL: + reason_str = "internal task abort set"; + break; + case MPI26_EVENT_PCIDEV_STAT_RC_CLEAR_TASK_SET_INTERNAL: + reason_str = "internal clear task set"; + break; + case MPI26_EVENT_PCIDEV_STAT_RC_QUERY_TASK_INTERNAL: + reason_str = "internal query task"; + break; + case MPI26_EVENT_PCIDEV_STAT_RC_DEV_INIT_FAILURE: + reason_str = "device init failure"; + break; + case MPI26_EVENT_PCIDEV_STAT_RC_CMP_INTERNAL_DEV_RESET: + reason_str = "internal device reset complete"; + break; + case MPI26_EVENT_PCIDEV_STAT_RC_CMP_TASK_ABORT_INTERNAL: + reason_str = "internal task abort complete"; + break; + case MPI26_EVENT_PCIDEV_STAT_RC_ASYNC_NOTIFICATION: + reason_str = "internal async notification"; + break; + default: + reason_str = "unknown reason"; + break; + } + + pr_info(MPT3SAS_FMT "PCIE device status change: (%s)\n" + "\thandle(0x%04x), WWID(0x%016llx), tag(%d)", + ioc->name, reason_str, le16_to_cpu(event_data->DevHandle), + (unsigned long long)le64_to_cpu(event_data->WWID), + le16_to_cpu(event_data->TaskTag)); + if (event_data->ReasonCode == MPI26_EVENT_PCIDEV_STAT_RC_SMART_DATA) + pr_info(MPT3SAS_FMT ", ASC(0x%x), ASCQ(0x%x)\n", ioc->name, + event_data->ASC, event_data->ASCQ); + pr_info("\n"); +} + +/** + * _scsih_pcie_device_status_change_event - handle device status + * change + * @ioc: per adapter object + * @fw_event: The fw_event_work object + * Context: user. + * + * Return nothing. + */ +static void +_scsih_pcie_device_status_change_event(struct MPT3SAS_ADAPTER *ioc, + struct fw_event_work *fw_event) +{ + struct MPT3SAS_TARGET *target_priv_data; + struct _pcie_device *pcie_device; + u64 wwid; + unsigned long flags; + Mpi26EventDataPCIeDeviceStatusChange_t *event_data = + (Mpi26EventDataPCIeDeviceStatusChange_t *)fw_event->event_data; + if (ioc->logging_level & MPT_DEBUG_EVENT_WORK_TASK) + _scsih_pcie_device_status_change_event_debug(ioc, + event_data); + + if (event_data->ReasonCode != + MPI26_EVENT_PCIDEV_STAT_RC_INTERNAL_DEVICE_RESET && + event_data->ReasonCode != + MPI26_EVENT_PCIDEV_STAT_RC_CMP_INTERNAL_DEV_RESET) + return; + + spin_lock_irqsave(&ioc->pcie_device_lock, flags); + wwid = le64_to_cpu(event_data->WWID); + pcie_device = __mpt3sas_get_pdev_by_wwid(ioc, wwid); + + if (!pcie_device || !pcie_device->starget) + goto out; + + target_priv_data = pcie_device->starget->hostdata; + if (!target_priv_data) + goto out; + + if (event_data->ReasonCode == + MPI26_EVENT_PCIDEV_STAT_RC_INTERNAL_DEVICE_RESET) + target_priv_data->tm_busy = 1; + else + target_priv_data->tm_busy = 0; +out: + if (pcie_device) + pcie_device_put(pcie_device); + + spin_unlock_irqrestore(&ioc->pcie_device_lock, flags); } /** @@ -6282,6 +7686,35 @@ _scsih_sas_discovery_event(struct MPT3SAS_ADAPTER *ioc, } /** + * _scsih_pcie_enumeration_event - handle enumeration events + * @ioc: per adapter object + * @fw_event: The fw_event_work object + * Context: user. + * + * Return nothing. + */ +static void +_scsih_pcie_enumeration_event(struct MPT3SAS_ADAPTER *ioc, + struct fw_event_work *fw_event) +{ + Mpi26EventDataPCIeEnumeration_t *event_data = + (Mpi26EventDataPCIeEnumeration_t *)fw_event->event_data; + + if (!(ioc->logging_level & MPT_DEBUG_EVENT_WORK_TASK)) + return; + + pr_info(MPT3SAS_FMT "pcie enumeration event: (%s) Flag 0x%02x", + ioc->name, + (event_data->ReasonCode == MPI26_EVENT_PCIE_ENUM_RC_STARTED) ? + "started" : "completed", + event_data->Flags); + if (event_data->EnumerationStatus) + pr_cont("enumeration_status(0x%08x)", + le32_to_cpu(event_data->EnumerationStatus)); + pr_cont("\n"); +} + +/** * _scsih_ir_fastpath - turn on fastpath for IR physdisk * @ioc: per adapter object * @handle: device handle for physical disk @@ -7085,7 +8518,7 @@ Mpi2SasDevicePage0_t *sas_device_pg0) { struct MPT3SAS_TARGET *sas_target_priv_data = NULL; struct scsi_target *starget; - struct _sas_device *sas_device; + struct _sas_device *sas_device = NULL; unsigned long flags; spin_lock_irqsave(&ioc->sas_device_lock, flags); @@ -7126,6 +8559,9 @@ Mpi2SasDevicePage0_t *sas_device_pg0) sas_device->connector_name[0] = '\0'; } + _scsih_get_enclosure_logicalid_chassis_slot(ioc, + sas_device_pg0, sas_device); + if (sas_device->handle == sas_device_pg0->DevHandle) goto out; pr_info("\thandle changed from(0x%04x)!!!\n", @@ -7190,6 +8626,130 @@ _scsih_search_responding_sas_devices(struct MPT3SAS_ADAPTER *ioc) } /** + * _scsih_mark_responding_pcie_device - mark a pcie_device as responding + * @ioc: per adapter object + * @pcie_device_pg0: PCIe Device page 0 + * + * After host reset, find out whether devices are still responding. + * Used in _scsih_remove_unresponding_devices. + * + * Return nothing. + */ +static void +_scsih_mark_responding_pcie_device(struct MPT3SAS_ADAPTER *ioc, + Mpi26PCIeDevicePage0_t *pcie_device_pg0) +{ + struct MPT3SAS_TARGET *sas_target_priv_data = NULL; + struct scsi_target *starget; + struct _pcie_device *pcie_device; + unsigned long flags; + + spin_lock_irqsave(&ioc->pcie_device_lock, flags); + list_for_each_entry(pcie_device, &ioc->pcie_device_list, list) { + if ((pcie_device->wwid == pcie_device_pg0->WWID) && + (pcie_device->slot == pcie_device_pg0->Slot)) { + pcie_device->responding = 1; + starget = pcie_device->starget; + if (starget && starget->hostdata) { + sas_target_priv_data = starget->hostdata; + sas_target_priv_data->tm_busy = 0; + sas_target_priv_data->deleted = 0; + } else + sas_target_priv_data = NULL; + if (starget) { + starget_printk(KERN_INFO, starget, + "handle(0x%04x), wwid(0x%016llx) ", + pcie_device->handle, + (unsigned long long)pcie_device->wwid); + if (pcie_device->enclosure_handle != 0) + starget_printk(KERN_INFO, starget, + "enclosure logical id(0x%016llx), " + "slot(%d)\n", + (unsigned long long) + pcie_device->enclosure_logical_id, + pcie_device->slot); + } + + if (((le32_to_cpu(pcie_device_pg0->Flags)) & + MPI26_PCIEDEV0_FLAGS_ENCL_LEVEL_VALID) && + (ioc->hba_mpi_version_belonged != MPI2_VERSION)) { + pcie_device->enclosure_level = + pcie_device_pg0->EnclosureLevel; + memcpy(&pcie_device->connector_name[0], + &pcie_device_pg0->ConnectorName[0], 4); + } else { + pcie_device->enclosure_level = 0; + pcie_device->connector_name[0] = '\0'; + } + + if (pcie_device->handle == pcie_device_pg0->DevHandle) + goto out; + pr_info("\thandle changed from(0x%04x)!!!\n", + pcie_device->handle); + pcie_device->handle = pcie_device_pg0->DevHandle; + if (sas_target_priv_data) + sas_target_priv_data->handle = + pcie_device_pg0->DevHandle; + goto out; + } + } + + out: + spin_unlock_irqrestore(&ioc->pcie_device_lock, flags); +} + +/** + * _scsih_search_responding_pcie_devices - + * @ioc: per adapter object + * + * After host reset, find out whether devices are still responding. + * If not remove. + * + * Return nothing. + */ +static void +_scsih_search_responding_pcie_devices(struct MPT3SAS_ADAPTER *ioc) +{ + Mpi26PCIeDevicePage0_t pcie_device_pg0; + Mpi2ConfigReply_t mpi_reply; + u16 ioc_status; + u16 handle; + u32 device_info; + + pr_info(MPT3SAS_FMT "search for end-devices: start\n", ioc->name); + + if (list_empty(&ioc->pcie_device_list)) + goto out; + + handle = 0xFFFF; + while (!(mpt3sas_config_get_pcie_device_pg0(ioc, &mpi_reply, + &pcie_device_pg0, MPI26_PCIE_DEVICE_PGAD_FORM_GET_NEXT_HANDLE, + handle))) { + ioc_status = le16_to_cpu(mpi_reply.IOCStatus) & + MPI2_IOCSTATUS_MASK; + if (ioc_status != MPI2_IOCSTATUS_SUCCESS) { + pr_info(MPT3SAS_FMT "\tbreak from %s: " + "ioc_status(0x%04x), loginfo(0x%08x)\n", ioc->name, + __func__, ioc_status, + le32_to_cpu(mpi_reply.IOCLogInfo)); + break; + } + handle = le16_to_cpu(pcie_device_pg0.DevHandle); + device_info = le32_to_cpu(pcie_device_pg0.DeviceInfo); + if (!(_scsih_is_nvme_device(device_info))) + continue; + pcie_device_pg0.WWID = le64_to_cpu(pcie_device_pg0.WWID), + pcie_device_pg0.Slot = le16_to_cpu(pcie_device_pg0.Slot); + pcie_device_pg0.Flags = le32_to_cpu(pcie_device_pg0.Flags); + pcie_device_pg0.DevHandle = handle; + _scsih_mark_responding_pcie_device(ioc, &pcie_device_pg0); + } +out: + pr_info(MPT3SAS_FMT "search for PCIe end-devices: complete\n", + ioc->name); +} + +/** * _scsih_mark_responding_raid_device - mark a raid_device as responding * @ioc: per adapter object * @wwid: world wide identifier for raid volume @@ -7322,8 +8882,7 @@ _scsih_search_responding_raid_devices(struct MPT3SAS_ADAPTER *ioc) /** * _scsih_mark_responding_expander - mark a expander as responding * @ioc: per adapter object - * @sas_address: sas address - * @handle: + * @expander_pg0:SAS Expander Config Page0 * * After host reset, find out whether devices are still responding. * Used in _scsih_remove_unresponsive_expanders. @@ -7331,18 +8890,41 @@ _scsih_search_responding_raid_devices(struct MPT3SAS_ADAPTER *ioc) * Return nothing. */ static void -_scsih_mark_responding_expander(struct MPT3SAS_ADAPTER *ioc, u64 sas_address, - u16 handle) +_scsih_mark_responding_expander(struct MPT3SAS_ADAPTER *ioc, + Mpi2ExpanderPage0_t *expander_pg0) { - struct _sas_node *sas_expander; + struct _sas_node *sas_expander = NULL; unsigned long flags; - int i; + int i, encl_pg0_rc = -1; + Mpi2ConfigReply_t mpi_reply; + Mpi2SasEnclosurePage0_t enclosure_pg0; + u16 handle = le16_to_cpu(expander_pg0->DevHandle); + u64 sas_address = le64_to_cpu(expander_pg0->SASAddress); + + if (le16_to_cpu(expander_pg0->EnclosureHandle)) { + encl_pg0_rc = mpt3sas_config_get_enclosure_pg0(ioc, &mpi_reply, + &enclosure_pg0, MPI2_SAS_ENCLOS_PGAD_FORM_HANDLE, + le16_to_cpu(expander_pg0->EnclosureHandle)); + if (encl_pg0_rc) + pr_info(MPT3SAS_FMT + "Enclosure Pg0 read failed for handle(0x%04x)\n", + ioc->name, + le16_to_cpu(expander_pg0->EnclosureHandle)); + } spin_lock_irqsave(&ioc->sas_node_lock, flags); list_for_each_entry(sas_expander, &ioc->sas_expander_list, list) { if (sas_expander->sas_address != sas_address) continue; sas_expander->responding = 1; + + if (!encl_pg0_rc) + sas_expander->enclosure_logical_id = + le64_to_cpu(enclosure_pg0.EnclosureLogicalID); + + sas_expander->enclosure_handle = + le16_to_cpu(expander_pg0->EnclosureHandle); + if (sas_expander->handle == handle) goto out; pr_info("\texpander(0x%016llx): handle changed" \ @@ -7395,7 +8977,7 @@ _scsih_search_responding_expanders(struct MPT3SAS_ADAPTER *ioc) pr_info("\texpander present: handle(0x%04x), sas_addr(0x%016llx)\n", handle, (unsigned long long)sas_address); - _scsih_mark_responding_expander(ioc, sas_address, handle); + _scsih_mark_responding_expander(ioc, &expander_pg0); } out: @@ -7403,17 +8985,18 @@ _scsih_search_responding_expanders(struct MPT3SAS_ADAPTER *ioc) } /** - * _scsih_remove_unresponding_sas_devices - removing unresponding devices + * _scsih_remove_unresponding_devices - removing unresponding devices * @ioc: per adapter object * * Return nothing. */ static void -_scsih_remove_unresponding_sas_devices(struct MPT3SAS_ADAPTER *ioc) +_scsih_remove_unresponding_devices(struct MPT3SAS_ADAPTER *ioc) { struct _sas_device *sas_device, *sas_device_next; struct _sas_node *sas_expander, *sas_expander_next; struct _raid_device *raid_device, *raid_device_next; + struct _pcie_device *pcie_device, *pcie_device_next; struct list_head tmp_list; unsigned long flags; LIST_HEAD(head); @@ -7447,6 +9030,26 @@ _scsih_remove_unresponding_sas_devices(struct MPT3SAS_ADAPTER *ioc) sas_device_put(sas_device); } + pr_info(MPT3SAS_FMT + " Removing unresponding devices: pcie end-devices\n" + , ioc->name); + INIT_LIST_HEAD(&head); + spin_lock_irqsave(&ioc->pcie_device_lock, flags); + list_for_each_entry_safe(pcie_device, pcie_device_next, + &ioc->pcie_device_list, list) { + if (!pcie_device->responding) + list_move_tail(&pcie_device->list, &head); + else + pcie_device->responding = 0; + } + spin_unlock_irqrestore(&ioc->pcie_device_lock, flags); + + list_for_each_entry_safe(pcie_device, pcie_device_next, &head, list) { + _scsih_pcie_device_remove_from_sml(ioc, pcie_device); + list_del_init(&pcie_device->list); + pcie_device_put(pcie_device); + } + /* removing unresponding volumes */ if (ioc->ir_firmware) { pr_info(MPT3SAS_FMT "removing unresponding devices: volumes\n", @@ -7476,7 +9079,6 @@ _scsih_remove_unresponding_sas_devices(struct MPT3SAS_ADAPTER *ioc) spin_unlock_irqrestore(&ioc->sas_node_lock, flags); list_for_each_entry_safe(sas_expander, sas_expander_next, &tmp_list, list) { - list_del(&sas_expander->list); _scsih_expander_node_remove(ioc, sas_expander); } @@ -7520,6 +9122,7 @@ _scsih_scan_for_devices_after_reset(struct MPT3SAS_ADAPTER *ioc) { Mpi2ExpanderPage0_t expander_pg0; Mpi2SasDevicePage0_t sas_device_pg0; + Mpi26PCIeDevicePage0_t pcie_device_pg0; Mpi2RaidVolPage1_t volume_pg1; Mpi2RaidVolPage0_t volume_pg0; Mpi2RaidPhysDiskPage0_t pd_pg0; @@ -7530,6 +9133,7 @@ _scsih_scan_for_devices_after_reset(struct MPT3SAS_ADAPTER *ioc) u16 handle, parent_handle; u64 sas_address; struct _sas_device *sas_device; + struct _pcie_device *pcie_device; struct _sas_node *expander_device; static struct _raid_device *raid_device; u8 retry_count; @@ -7755,7 +9359,44 @@ _scsih_scan_for_devices_after_reset(struct MPT3SAS_ADAPTER *ioc) } pr_info(MPT3SAS_FMT "\tscan devices: end devices complete\n", ioc->name); + pr_info(MPT3SAS_FMT "\tscan devices: pcie end devices start\n", + ioc->name); + /* pcie devices */ + handle = 0xFFFF; + while (!(mpt3sas_config_get_pcie_device_pg0(ioc, &mpi_reply, + &pcie_device_pg0, MPI26_PCIE_DEVICE_PGAD_FORM_GET_NEXT_HANDLE, + handle))) { + ioc_status = le16_to_cpu(mpi_reply.IOCStatus) + & MPI2_IOCSTATUS_MASK; + if (ioc_status != MPI2_IOCSTATUS_SUCCESS) { + pr_info(MPT3SAS_FMT "\tbreak from pcie end device" + " scan: ioc_status(0x%04x), loginfo(0x%08x)\n", + ioc->name, ioc_status, + le32_to_cpu(mpi_reply.IOCLogInfo)); + break; + } + handle = le16_to_cpu(pcie_device_pg0.DevHandle); + if (!(_scsih_is_nvme_device( + le32_to_cpu(pcie_device_pg0.DeviceInfo)))) + continue; + pcie_device = mpt3sas_get_pdev_by_wwid(ioc, + le64_to_cpu(pcie_device_pg0.WWID)); + if (pcie_device) { + pcie_device_put(pcie_device); + continue; + } + retry_count = 0; + parent_handle = le16_to_cpu(pcie_device_pg0.ParentDevHandle); + _scsih_pcie_add_device(ioc, handle); + + pr_info(MPT3SAS_FMT "\tAFTER adding pcie end device: " + "handle (0x%04x), wwid(0x%016llx)\n", ioc->name, + handle, + (unsigned long long) le64_to_cpu(pcie_device_pg0.WWID)); + } + pr_info(MPT3SAS_FMT "\tpcie devices: pcie end devices complete\n", + ioc->name); pr_info(MPT3SAS_FMT "scan devices: complete\n", ioc->name); } /** @@ -7805,6 +9446,7 @@ mpt3sas_scsih_reset_handler(struct MPT3SAS_ADAPTER *ioc, int reset_phase) !ioc->sas_hba.num_phys)) { _scsih_prep_device_scan(ioc); _scsih_search_responding_sas_devices(ioc); + _scsih_search_responding_pcie_devices(ioc); _scsih_search_responding_raid_devices(ioc); _scsih_search_responding_expanders(ioc); _scsih_error_recovery_delete_devices(ioc); @@ -7849,7 +9491,7 @@ _mpt3sas_fw_work(struct MPT3SAS_ADAPTER *ioc, struct fw_event_work *fw_event) goto out; ssleep(1); } - _scsih_remove_unresponding_sas_devices(ioc); + _scsih_remove_unresponding_devices(ioc); _scsih_scan_for_devices_after_reset(ioc); break; case MPT3SAS_PORT_ENABLE_COMPLETE: @@ -7892,6 +9534,16 @@ _mpt3sas_fw_work(struct MPT3SAS_ADAPTER *ioc, struct fw_event_work *fw_event) case MPI2_EVENT_IR_OPERATION_STATUS: _scsih_sas_ir_operation_status_event(ioc, fw_event); break; + case MPI2_EVENT_PCIE_DEVICE_STATUS_CHANGE: + _scsih_pcie_device_status_change_event(ioc, fw_event); + break; + case MPI2_EVENT_PCIE_ENUMERATION: + _scsih_pcie_enumeration_event(ioc, fw_event); + break; + case MPI2_EVENT_PCIE_TOPOLOGY_CHANGE_LIST: + _scsih_pcie_topology_change_event(ioc, fw_event); + return; + break; } out: fw_event_work_put(fw_event); @@ -7982,6 +9634,11 @@ mpt3sas_scsih_event_callback(struct MPT3SAS_ADAPTER *ioc, u8 msix_index, (Mpi2EventDataSasTopologyChangeList_t *) mpi_reply->EventData); break; + case MPI2_EVENT_PCIE_TOPOLOGY_CHANGE_LIST: + _scsih_check_pcie_topo_remove_events(ioc, + (Mpi26EventDataPCIeTopologyChangeList_t *) + mpi_reply->EventData); + break; case MPI2_EVENT_IR_CONFIGURATION_CHANGE_LIST: _scsih_check_ir_config_unhide_events(ioc, (Mpi2EventDataIrConfigChangeList_t *) @@ -8044,6 +9701,8 @@ mpt3sas_scsih_event_callback(struct MPT3SAS_ADAPTER *ioc, u8 msix_index, case MPI2_EVENT_SAS_DISCOVERY: case MPI2_EVENT_SAS_ENCL_DEVICE_STATUS_CHANGE: case MPI2_EVENT_IR_PHYSICAL_DISK: + case MPI2_EVENT_PCIE_ENUMERATION: + case MPI2_EVENT_PCIE_DEVICE_STATUS_CHANGE: break; case MPI2_EVENT_TEMP_THRESHOLD: @@ -8056,19 +9715,21 @@ mpt3sas_scsih_event_callback(struct MPT3SAS_ADAPTER *ioc, u8 msix_index, (Mpi26EventDataActiveCableExcept_t *) mpi_reply->EventData; switch (ActiveCableEventData->ReasonCode) { case MPI26_EVENT_ACTIVE_CABLE_INSUFFICIENT_POWER: - pr_notice(MPT3SAS_FMT "Receptacle ID %d: This active cable" - " requires %d mW of power\n", ioc->name, - ActiveCableEventData->ReceptacleID, + pr_notice(MPT3SAS_FMT + "Currently an active cable with ReceptacleID %d\n", + ioc->name, ActiveCableEventData->ReceptacleID); + pr_notice("cannot be powered and devices connected\n"); + pr_notice("to this active cable will not be seen\n"); + pr_notice("This active cable requires %d mW of power\n", ActiveCableEventData->ActiveCablePowerRequirement); - pr_notice(MPT3SAS_FMT "Receptacle ID %d: Devices connected" - " to this active cable will not be seen\n", - ioc->name, ActiveCableEventData->ReceptacleID); break; case MPI26_EVENT_ACTIVE_CABLE_DEGRADED: - pr_notice(MPT3SAS_FMT "ReceptacleID %d: This cable", - ioc->name, ActiveCableEventData->ReceptacleID); - pr_notice(" is not running at an optimal speed(12 Gb/s)\n"); + pr_notice(MPT3SAS_FMT + "Currently a cable with ReceptacleID %d\n", + ioc->name, ActiveCableEventData->ReceptacleID); + pr_notice( + "is not running at optimal speed(12 Gb/s rate)\n"); break; } @@ -8100,7 +9761,6 @@ mpt3sas_scsih_event_callback(struct MPT3SAS_ADAPTER *ioc, u8 msix_index, * _scsih_expander_node_remove - removing expander device from list. * @ioc: per adapter object * @sas_expander: the sas_device object - * Context: Calling function should acquire ioc->sas_node_lock. * * Removing object and freeing associated memory from the * ioc->sas_expander_list. @@ -8112,6 +9772,7 @@ _scsih_expander_node_remove(struct MPT3SAS_ADAPTER *ioc, struct _sas_node *sas_expander) { struct _sas_port *mpt3sas_port, *next; + unsigned long flags; /* remove sibling ports attached to this expander */ list_for_each_entry_safe(mpt3sas_port, next, @@ -8139,6 +9800,10 @@ _scsih_expander_node_remove(struct MPT3SAS_ADAPTER *ioc, sas_expander->handle, (unsigned long long) sas_expander->sas_address); + spin_lock_irqsave(&ioc->sas_node_lock, flags); + list_del(&sas_expander->list); + spin_unlock_irqrestore(&ioc->sas_node_lock, flags); + kfree(sas_expander->phy); kfree(sas_expander); } @@ -8231,6 +9896,7 @@ static void scsih_remove(struct pci_dev *pdev) struct _sas_port *mpt3sas_port, *next_port; struct _raid_device *raid_device, *next; struct MPT3SAS_TARGET *sas_target_priv_data; + struct _pcie_device *pcie_device, *pcienext; struct workqueue_struct *wq; unsigned long flags; @@ -8259,6 +9925,12 @@ static void scsih_remove(struct pci_dev *pdev) (unsigned long long) raid_device->wwid); _scsih_raid_device_remove(ioc, raid_device); } + list_for_each_entry_safe(pcie_device, pcienext, &ioc->pcie_device_list, + list) { + _scsih_pcie_device_remove_from_sml(ioc, pcie_device); + list_del_init(&pcie_device->list); + pcie_device_put(pcie_device); + } /* free ports attached to the sas_host */ list_for_each_entry_safe(mpt3sas_port, next_port, @@ -8330,42 +10002,52 @@ scsih_shutdown(struct pci_dev *pdev) static void _scsih_probe_boot_devices(struct MPT3SAS_ADAPTER *ioc) { - u8 is_raid; + u32 channel; void *device; struct _sas_device *sas_device; struct _raid_device *raid_device; + struct _pcie_device *pcie_device; u16 handle; u64 sas_address_parent; u64 sas_address; unsigned long flags; int rc; + int tid; /* no Bios, return immediately */ if (!ioc->bios_pg3.BiosVersion) return; device = NULL; - is_raid = 0; if (ioc->req_boot_device.device) { device = ioc->req_boot_device.device; - is_raid = ioc->req_boot_device.is_raid; + channel = ioc->req_boot_device.channel; } else if (ioc->req_alt_boot_device.device) { device = ioc->req_alt_boot_device.device; - is_raid = ioc->req_alt_boot_device.is_raid; + channel = ioc->req_alt_boot_device.channel; } else if (ioc->current_boot_device.device) { device = ioc->current_boot_device.device; - is_raid = ioc->current_boot_device.is_raid; + channel = ioc->current_boot_device.channel; } if (!device) return; - if (is_raid) { + if (channel == RAID_CHANNEL) { raid_device = device; rc = scsi_add_device(ioc->shost, RAID_CHANNEL, raid_device->id, 0); if (rc) _scsih_raid_device_remove(ioc, raid_device); + } else if (channel == PCIE_CHANNEL) { + spin_lock_irqsave(&ioc->pcie_device_lock, flags); + pcie_device = device; + tid = pcie_device->id; + list_move_tail(&pcie_device->list, &ioc->pcie_device_list); + spin_unlock_irqrestore(&ioc->pcie_device_lock, flags); + rc = scsi_add_device(ioc->shost, PCIE_CHANNEL, tid, 0); + if (rc) + _scsih_pcie_device_remove(ioc, pcie_device); } else { spin_lock_irqsave(&ioc->sas_device_lock, flags); sas_device = device; @@ -8498,6 +10180,101 @@ _scsih_probe_sas(struct MPT3SAS_ADAPTER *ioc) } /** + * get_next_pcie_device - Get the next pcie device + * @ioc: per adapter object + * + * Get the next pcie device from pcie_device_init_list list. + * + * Returns pcie device structure if pcie_device_init_list list is not empty + * otherwise returns NULL + */ +static struct _pcie_device *get_next_pcie_device(struct MPT3SAS_ADAPTER *ioc) +{ + struct _pcie_device *pcie_device = NULL; + unsigned long flags; + + spin_lock_irqsave(&ioc->pcie_device_lock, flags); + if (!list_empty(&ioc->pcie_device_init_list)) { + pcie_device = list_first_entry(&ioc->pcie_device_init_list, + struct _pcie_device, list); + pcie_device_get(pcie_device); + } + spin_unlock_irqrestore(&ioc->pcie_device_lock, flags); + + return pcie_device; +} + +/** + * pcie_device_make_active - Add pcie device to pcie_device_list list + * @ioc: per adapter object + * @pcie_device: pcie device object + * + * Add the pcie device which has registered with SCSI Transport Later to + * pcie_device_list list + */ +static void pcie_device_make_active(struct MPT3SAS_ADAPTER *ioc, + struct _pcie_device *pcie_device) +{ + unsigned long flags; + + spin_lock_irqsave(&ioc->pcie_device_lock, flags); + + if (!list_empty(&pcie_device->list)) { + list_del_init(&pcie_device->list); + pcie_device_put(pcie_device); + } + pcie_device_get(pcie_device); + list_add_tail(&pcie_device->list, &ioc->pcie_device_list); + + spin_unlock_irqrestore(&ioc->pcie_device_lock, flags); +} + +/** + * _scsih_probe_pcie - reporting PCIe devices to scsi-ml + * @ioc: per adapter object + * + * Called during initial loading of the driver. + */ +static void +_scsih_probe_pcie(struct MPT3SAS_ADAPTER *ioc) +{ + struct _pcie_device *pcie_device; + int rc; + + /* PCIe Device List */ + while ((pcie_device = get_next_pcie_device(ioc))) { + if (pcie_device->starget) { + pcie_device_put(pcie_device); + continue; + } + rc = scsi_add_device(ioc->shost, PCIE_CHANNEL, + pcie_device->id, 0); + if (rc) { + _scsih_pcie_device_remove(ioc, pcie_device); + pcie_device_put(pcie_device); + continue; + } else if (!pcie_device->starget) { + /* + * When async scanning is enabled, its not possible to + * remove devices while scanning is turned on due to an + * oops in scsi_sysfs_add_sdev()->add_device()-> + * sysfs_addrm_start() + */ + if (!ioc->is_driver_loading) { + /* TODO-- Need to find out whether this condition will + * occur or not + */ + _scsih_pcie_device_remove(ioc, pcie_device); + pcie_device_put(pcie_device); + continue; + } + } + pcie_device_make_active(ioc, pcie_device); + pcie_device_put(pcie_device); + } +} + +/** * _scsih_probe_devices - probing for devices * @ioc: per adapter object * @@ -8525,8 +10302,10 @@ _scsih_probe_devices(struct MPT3SAS_ADAPTER *ioc) _scsih_probe_sas(ioc); _scsih_probe_raid(ioc); } - } else + } else { _scsih_probe_sas(ioc); + _scsih_probe_pcie(ioc); + } } /** @@ -8740,6 +10519,7 @@ _scsih_determine_hba_mpi_version(struct pci_dev *pdev) case MPI26_MFGPAGE_DEVID_SAS3516: case MPI26_MFGPAGE_DEVID_SAS3516_1: case MPI26_MFGPAGE_DEVID_SAS3416: + case MPI26_MFGPAGE_DEVID_SAS3616: return MPI26_VERSION; } return 0; @@ -8817,6 +10597,7 @@ _scsih_probe(struct pci_dev *pdev, const struct pci_device_id *id) case MPI26_MFGPAGE_DEVID_SAS3516: case MPI26_MFGPAGE_DEVID_SAS3516_1: case MPI26_MFGPAGE_DEVID_SAS3416: + case MPI26_MFGPAGE_DEVID_SAS3616: ioc->is_gen35_ioc = 1; break; default: @@ -8867,11 +10648,14 @@ _scsih_probe(struct pci_dev *pdev, const struct pci_device_id *id) spin_lock_init(&ioc->sas_node_lock); spin_lock_init(&ioc->fw_event_lock); spin_lock_init(&ioc->raid_device_lock); + spin_lock_init(&ioc->pcie_device_lock); spin_lock_init(&ioc->diag_trigger_lock); INIT_LIST_HEAD(&ioc->sas_device_list); INIT_LIST_HEAD(&ioc->sas_device_init_list); INIT_LIST_HEAD(&ioc->sas_expander_list); + INIT_LIST_HEAD(&ioc->pcie_device_list); + INIT_LIST_HEAD(&ioc->pcie_device_init_list); INIT_LIST_HEAD(&ioc->fw_event_list); INIT_LIST_HEAD(&ioc->raid_device_list); INIT_LIST_HEAD(&ioc->sas_hba.sas_port_list); @@ -9273,6 +11057,9 @@ static const struct pci_device_id mpt3sas_pci_table[] = { PCI_ANY_ID, PCI_ANY_ID }, { MPI2_MFGPAGE_VENDORID_LSI, MPI26_MFGPAGE_DEVID_SAS3416, PCI_ANY_ID, PCI_ANY_ID }, + /* Mercator ~ 3616*/ + { MPI2_MFGPAGE_VENDORID_LSI, MPI26_MFGPAGE_DEVID_SAS3616, + PCI_ANY_ID, PCI_ANY_ID }, {0} /* Terminating entry */ }; MODULE_DEVICE_TABLE(pci, mpt3sas_pci_table); diff --git a/drivers/scsi/mpt3sas/mpt3sas_warpdrive.c b/drivers/scsi/mpt3sas/mpt3sas_warpdrive.c index 540bd5005149..ced7d9f6274c 100644 --- a/drivers/scsi/mpt3sas/mpt3sas_warpdrive.c +++ b/drivers/scsi/mpt3sas/mpt3sas_warpdrive.c @@ -299,7 +299,7 @@ mpt3sas_scsi_direct_io_set(struct MPT3SAS_ADAPTER *ioc, u16 smid, u8 direct_io) */ void mpt3sas_setup_direct_io(struct MPT3SAS_ADAPTER *ioc, struct scsi_cmnd *scmd, - struct _raid_device *raid_device, Mpi2SCSIIORequest_t *mpi_request, + struct _raid_device *raid_device, Mpi25SCSIIORequest_t *mpi_request, u16 smid) { sector_t v_lba, p_lba, stripe_off, column, io_size; |