diff options
Diffstat (limited to 'drivers/scsi/mpt2sas')
-rw-r--r-- | drivers/scsi/mpt2sas/mpi/mpi2.h | 5 | ||||
-rw-r--r-- | drivers/scsi/mpt2sas/mpi/mpi2_cnfg.h | 274 | ||||
-rw-r--r-- | drivers/scsi/mpt2sas/mpi/mpi2_ioc.h | 18 | ||||
-rw-r--r-- | drivers/scsi/mpt2sas/mpi/mpi2_raid.h | 14 | ||||
-rw-r--r-- | drivers/scsi/mpt2sas/mpi/mpi2_tool.h | 16 | ||||
-rw-r--r-- | drivers/scsi/mpt2sas/mpt2sas_base.c | 152 | ||||
-rw-r--r-- | drivers/scsi/mpt2sas/mpt2sas_base.h | 37 | ||||
-rw-r--r-- | drivers/scsi/mpt2sas/mpt2sas_ctl.c | 197 | ||||
-rw-r--r-- | drivers/scsi/mpt2sas/mpt2sas_ctl.h | 4 | ||||
-rw-r--r-- | drivers/scsi/mpt2sas/mpt2sas_scsih.c | 819 | ||||
-rw-r--r-- | drivers/scsi/mpt2sas/mpt2sas_transport.c | 86 |
11 files changed, 1206 insertions, 416 deletions
diff --git a/drivers/scsi/mpt2sas/mpi/mpi2.h b/drivers/scsi/mpt2sas/mpi/mpi2.h index f9f6c0839276..914168105297 100644 --- a/drivers/scsi/mpt2sas/mpi/mpi2.h +++ b/drivers/scsi/mpt2sas/mpi/mpi2.h @@ -8,7 +8,7 @@ * scatter/gather formats. * Creation Date: June 21, 2006 * - * mpi2.h Version: 02.00.12 + * mpi2.h Version: 02.00.13 * * Version History * --------------- @@ -52,6 +52,7 @@ * MPI2_SCSI_IO_SUCCESS_REPLY_DESCRIPTOR and made those * bytes reserved. * Added RAID Accelerator functionality. + * 07-30-09 02.00.13 Bumped MPI2_HEADER_VERSION_UNIT. * -------------------------------------------------------------------------- */ @@ -77,7 +78,7 @@ #define MPI2_VERSION_02_00 (0x0200) /* versioning for this MPI header set */ -#define MPI2_HEADER_VERSION_UNIT (0x0C) +#define MPI2_HEADER_VERSION_UNIT (0x0D) #define MPI2_HEADER_VERSION_DEV (0x00) #define MPI2_HEADER_VERSION_UNIT_MASK (0xFF00) #define MPI2_HEADER_VERSION_UNIT_SHIFT (8) diff --git a/drivers/scsi/mpt2sas/mpi/mpi2_cnfg.h b/drivers/scsi/mpt2sas/mpi/mpi2_cnfg.h index ab47c4679640..1611c57a6fdf 100644 --- a/drivers/scsi/mpt2sas/mpi/mpi2_cnfg.h +++ b/drivers/scsi/mpt2sas/mpi/mpi2_cnfg.h @@ -6,7 +6,7 @@ * Title: MPI Configuration messages and pages * Creation Date: November 10, 2006 * - * mpi2_cnfg.h Version: 02.00.11 + * mpi2_cnfg.h Version: 02.00.12 * * Version History * --------------- @@ -100,6 +100,13 @@ * Added expander reduced functionality data to SAS * Expander Page 0. * Added SAS PHY Page 2 and SAS PHY Page 3. + * 07-30-09 02.00.12 Added IO Unit Page 7. + * Added new device ids. + * Added SAS IO Unit Page 5. + * Added partial and slumber power management capable flags + * to SAS Device Page 0 Flags field. + * Added PhyInfo defines for power condition. + * Added Ethernet configuration pages. * -------------------------------------------------------------------------- */ @@ -182,6 +189,7 @@ typedef union _MPI2_CONFIG_EXT_PAGE_HEADER_UNION #define MPI2_CONFIG_EXTPAGETYPE_RAID_CONFIG (0x16) #define MPI2_CONFIG_EXTPAGETYPE_DRIVER_MAPPING (0x17) #define MPI2_CONFIG_EXTPAGETYPE_SAS_PORT (0x18) +#define MPI2_CONFIG_EXTPAGETYPE_ETHERNET (0x19) /***************************************************************************** @@ -268,6 +276,14 @@ typedef union _MPI2_CONFIG_EXT_PAGE_HEADER_UNION #define MPI2_DPM_PGAD_START_ENTRY_MASK (0x0000FFFF) +/* Ethernet PageAddress format */ +#define MPI2_ETHERNET_PGAD_FORM_MASK (0xF0000000) +#define MPI2_ETHERNET_PGAD_FORM_IF_NUM (0x00000000) + +#define MPI2_ETHERNET_PGAD_IF_NUMBER_MASK (0x000000FF) + + + /**************************************************************************** * Configuration messages ****************************************************************************/ @@ -349,6 +365,15 @@ typedef struct _MPI2_CONFIG_REPLY #define MPI2_MFGPAGE_DEVID_SAS2116_1 (0x0064) #define MPI2_MFGPAGE_DEVID_SAS2116_2 (0x0065) +#define MPI2_MFGPAGE_DEVID_SAS2208_1 (0x0080) +#define MPI2_MFGPAGE_DEVID_SAS2208_2 (0x0081) +#define MPI2_MFGPAGE_DEVID_SAS2208_3 (0x0082) +#define MPI2_MFGPAGE_DEVID_SAS2208_4 (0x0083) +#define MPI2_MFGPAGE_DEVID_SAS2208_5 (0x0084) +#define MPI2_MFGPAGE_DEVID_SAS2208_6 (0x0085) +#define MPI2_MFGPAGE_DEVID_SAS2208_7 (0x0086) +#define MPI2_MFGPAGE_DEVID_SAS2208_8 (0x0087) + /* Manufacturing Page 0 */ @@ -787,6 +812,56 @@ typedef struct _MPI2_CONFIG_PAGE_IO_UNIT_6 { #define MPI2_IOUNITPAGE6_FLAGS_ENABLE_RAID_ACCELERATOR (0x0001) +/* IO Unit Page 7 */ + +typedef struct _MPI2_CONFIG_PAGE_IO_UNIT_7 { + MPI2_CONFIG_PAGE_HEADER Header; /* 0x00 */ + U16 Reserved1; /* 0x04 */ + U8 PCIeWidth; /* 0x06 */ + U8 PCIeSpeed; /* 0x07 */ + U32 ProcessorState; /* 0x08 */ + U32 Reserved2; /* 0x0C */ + U16 IOCTemperature; /* 0x10 */ + U8 IOCTemperatureUnits; /* 0x12 */ + U8 IOCSpeed; /* 0x13 */ + U32 Reserved3; /* 0x14 */ +} MPI2_CONFIG_PAGE_IO_UNIT_7, MPI2_POINTER PTR_MPI2_CONFIG_PAGE_IO_UNIT_7, + Mpi2IOUnitPage7_t, MPI2_POINTER pMpi2IOUnitPage7_t; + +#define MPI2_IOUNITPAGE7_PAGEVERSION (0x00) + +/* defines for IO Unit Page 7 PCIeWidth field */ +#define MPI2_IOUNITPAGE7_PCIE_WIDTH_X1 (0x01) +#define MPI2_IOUNITPAGE7_PCIE_WIDTH_X2 (0x02) +#define MPI2_IOUNITPAGE7_PCIE_WIDTH_X4 (0x04) +#define MPI2_IOUNITPAGE7_PCIE_WIDTH_X8 (0x08) + +/* defines for IO Unit Page 7 PCIeSpeed field */ +#define MPI2_IOUNITPAGE7_PCIE_SPEED_2_5_GBPS (0x00) +#define MPI2_IOUNITPAGE7_PCIE_SPEED_5_0_GBPS (0x01) +#define MPI2_IOUNITPAGE7_PCIE_SPEED_8_0_GBPS (0x02) + +/* defines for IO Unit Page 7 ProcessorState field */ +#define MPI2_IOUNITPAGE7_PSTATE_MASK_SECOND (0x0000000F) +#define MPI2_IOUNITPAGE7_PSTATE_SHIFT_SECOND (0) + +#define MPI2_IOUNITPAGE7_PSTATE_NOT_PRESENT (0x00) +#define MPI2_IOUNITPAGE7_PSTATE_DISABLED (0x01) +#define MPI2_IOUNITPAGE7_PSTATE_ENABLED (0x02) + +/* defines for IO Unit Page 7 IOCTemperatureUnits field */ +#define MPI2_IOUNITPAGE7_IOC_TEMP_NOT_PRESENT (0x00) +#define MPI2_IOUNITPAGE7_IOC_TEMP_FAHRENHEIT (0x01) +#define MPI2_IOUNITPAGE7_IOC_TEMP_CELSIUS (0x02) + +/* defines for IO Unit Page 7 IOCSpeed field */ +#define MPI2_IOUNITPAGE7_IOC_SPEED_FULL (0x01) +#define MPI2_IOUNITPAGE7_IOC_SPEED_HALF (0x02) +#define MPI2_IOUNITPAGE7_IOC_SPEED_QUARTER (0x04) +#define MPI2_IOUNITPAGE7_IOC_SPEED_EIGHTH (0x08) + + + /**************************************************************************** * IOC Config Pages ****************************************************************************/ @@ -1470,6 +1545,12 @@ typedef struct _MPI2_CONFIG_PAGE_RD_PDISK_1 /* values for PhyInfo fields */ #define MPI2_SAS_PHYINFO_PHY_VACANT (0x80000000) + +#define MPI2_SAS_PHYINFO_PHY_POWER_CONDITION_MASK (0x18000000) +#define MPI2_SAS_PHYINFO_PHY_POWER_ACTIVE (0x00000000) +#define MPI2_SAS_PHYINFO_PHY_POWER_PARTIAL (0x08000000) +#define MPI2_SAS_PHYINFO_PHY_POWER_SLUMBER (0x10000000) + #define MPI2_SAS_PHYINFO_CHANGED_REQ_INSIDE_ZPSDS (0x04000000) #define MPI2_SAS_PHYINFO_INSIDE_ZPSDS_PERSISTENT (0x02000000) #define MPI2_SAS_PHYINFO_REQ_INSIDE_ZPSDS (0x01000000) @@ -1682,11 +1763,11 @@ typedef struct _MPI2_CONFIG_PAGE_SASIOUNIT_1 /* values for SAS IO Unit Page 1 PortFlags */ #define MPI2_SASIOUNIT1_PORT_FLAGS_AUTO_PORT_CONFIG (0x01) -/* values for SAS IO Unit Page 2 PhyFlags */ +/* values for SAS IO Unit Page 1 PhyFlags */ #define MPI2_SASIOUNIT1_PHYFLAGS_ZONING_ENABLE (0x10) #define MPI2_SASIOUNIT1_PHYFLAGS_PHY_DISABLE (0x08) -/* values for SAS IO Unit Page 0 MaxMinLinkRate */ +/* values for SAS IO Unit Page 1 MaxMinLinkRate */ #define MPI2_SASIOUNIT1_MAX_RATE_MASK (0xF0) #define MPI2_SASIOUNIT1_MAX_RATE_1_5 (0x80) #define MPI2_SASIOUNIT1_MAX_RATE_3_0 (0x90) @@ -1745,6 +1826,74 @@ typedef struct _MPI2_CONFIG_PAGE_SASIOUNIT_4 #define MPI2_SASIOUNIT4_PHY_SPINUP_GROUP_MASK (0x03) +/* SAS IO Unit Page 5 */ + +typedef struct _MPI2_SAS_IO_UNIT5_PHY_PM_SETTINGS { + U8 ControlFlags; /* 0x00 */ + U8 Reserved1; /* 0x01 */ + U16 InactivityTimerExponent; /* 0x02 */ + U8 SATAPartialTimeout; /* 0x04 */ + U8 Reserved2; /* 0x05 */ + U8 SATASlumberTimeout; /* 0x06 */ + U8 Reserved3; /* 0x07 */ + U8 SASPartialTimeout; /* 0x08 */ + U8 Reserved4; /* 0x09 */ + U8 SASSlumberTimeout; /* 0x0A */ + U8 Reserved5; /* 0x0B */ +} MPI2_SAS_IO_UNIT5_PHY_PM_SETTINGS, + MPI2_POINTER PTR_MPI2_SAS_IO_UNIT5_PHY_PM_SETTINGS, + Mpi2SasIOUnit5PhyPmSettings_t, MPI2_POINTER pMpi2SasIOUnit5PhyPmSettings_t; + +/* defines for ControlFlags field */ +#define MPI2_SASIOUNIT5_CONTROL_SAS_SLUMBER_ENABLE (0x08) +#define MPI2_SASIOUNIT5_CONTROL_SAS_PARTIAL_ENABLE (0x04) +#define MPI2_SASIOUNIT5_CONTROL_SATA_SLUMBER_ENABLE (0x02) +#define MPI2_SASIOUNIT5_CONTROL_SATA_PARTIAL_ENABLE (0x01) + +/* defines for InactivityTimerExponent field */ +#define MPI2_SASIOUNIT5_ITE_MASK_SAS_SLUMBER (0x7000) +#define MPI2_SASIOUNIT5_ITE_SHIFT_SAS_SLUMBER (12) +#define MPI2_SASIOUNIT5_ITE_MASK_SAS_PARTIAL (0x0700) +#define MPI2_SASIOUNIT5_ITE_SHIFT_SAS_PARTIAL (8) +#define MPI2_SASIOUNIT5_ITE_MASK_SATA_SLUMBER (0x0070) +#define MPI2_SASIOUNIT5_ITE_SHIFT_SATA_SLUMBER (4) +#define MPI2_SASIOUNIT5_ITE_MASK_SATA_PARTIAL (0x0007) +#define MPI2_SASIOUNIT5_ITE_SHIFT_SATA_PARTIAL (0) + +#define MPI2_SASIOUNIT5_ITE_TEN_SECONDS (7) +#define MPI2_SASIOUNIT5_ITE_ONE_SECOND (6) +#define MPI2_SASIOUNIT5_ITE_HUNDRED_MILLISECONDS (5) +#define MPI2_SASIOUNIT5_ITE_TEN_MILLISECONDS (4) +#define MPI2_SASIOUNIT5_ITE_ONE_MILLISECOND (3) +#define MPI2_SASIOUNIT5_ITE_HUNDRED_MICROSECONDS (2) +#define MPI2_SASIOUNIT5_ITE_TEN_MICROSECONDS (1) +#define MPI2_SASIOUNIT5_ITE_ONE_MICROSECOND (0) + +/* + * Host code (drivers, BIOS, utilities, etc.) should leave this define set to + * one and check Header.ExtPageLength or NumPhys at runtime. + */ +#ifndef MPI2_SAS_IOUNIT5_PHY_MAX +#define MPI2_SAS_IOUNIT5_PHY_MAX (1) +#endif + +typedef struct _MPI2_CONFIG_PAGE_SASIOUNIT_5 { + MPI2_CONFIG_EXTENDED_PAGE_HEADER Header; /* 0x00 */ + U8 NumPhys; /* 0x08 */ + U8 Reserved1; /* 0x09 */ + U16 Reserved2; /* 0x0A */ + U32 Reserved3; /* 0x0C */ + MPI2_SAS_IO_UNIT5_PHY_PM_SETTINGS SASPhyPowerManagementSettings + [MPI2_SAS_IOUNIT5_PHY_MAX]; /* 0x10 */ +} MPI2_CONFIG_PAGE_SASIOUNIT_5, + MPI2_POINTER PTR_MPI2_CONFIG_PAGE_SASIOUNIT_5, + Mpi2SasIOUnitPage5_t, MPI2_POINTER pMpi2SasIOUnitPage5_t; + +#define MPI2_SASIOUNITPAGE5_PAGEVERSION (0x00) + + + + /**************************************************************************** * SAS Expander Config Pages ****************************************************************************/ @@ -1927,6 +2076,8 @@ typedef struct _MPI2_CONFIG_PAGE_SAS_DEV_0 /* see mpi2_sas.h for values for SAS Device Page 0 DeviceInfo values */ /* values for SAS Device Page 0 Flags field */ +#define MPI2_SAS_DEVICE0_FLAGS_SLUMBER_PM_CAPABLE (0x1000) +#define MPI2_SAS_DEVICE0_FLAGS_PARTIAL_PM_CAPABLE (0x0800) #define MPI2_SAS_DEVICE0_FLAGS_SATA_ASYNCHRONOUS_NOTIFY (0x0400) #define MPI2_SAS_DEVICE0_FLAGS_SATA_SW_PRESERVE (0x0200) #define MPI2_SAS_DEVICE0_FLAGS_UNSUPPORTED_DEVICE (0x0100) @@ -2343,5 +2494,122 @@ typedef struct _MPI2_CONFIG_PAGE_DRIVER_MAPPING_0 #define MPI2_DRVMAP0_MAPINFO_MISSING_MASK (0x000F) +/**************************************************************************** +* Ethernet Config Pages +****************************************************************************/ + +/* Ethernet Page 0 */ + +/* IP address (union of IPv4 and IPv6) */ +typedef union _MPI2_ETHERNET_IP_ADDR { + U32 IPv4Addr; + U32 IPv6Addr[4]; +} MPI2_ETHERNET_IP_ADDR, MPI2_POINTER PTR_MPI2_ETHERNET_IP_ADDR, + Mpi2EthernetIpAddr_t, MPI2_POINTER pMpi2EthernetIpAddr_t; + +#define MPI2_ETHERNET_HOST_NAME_LENGTH (32) + +typedef struct _MPI2_CONFIG_PAGE_ETHERNET_0 { + MPI2_CONFIG_EXTENDED_PAGE_HEADER Header; /* 0x00 */ + U8 NumInterfaces; /* 0x08 */ + U8 Reserved0; /* 0x09 */ + U16 Reserved1; /* 0x0A */ + U32 Status; /* 0x0C */ + U8 MediaState; /* 0x10 */ + U8 Reserved2; /* 0x11 */ + U16 Reserved3; /* 0x12 */ + U8 MacAddress[6]; /* 0x14 */ + U8 Reserved4; /* 0x1A */ + U8 Reserved5; /* 0x1B */ + MPI2_ETHERNET_IP_ADDR IpAddress; /* 0x1C */ + MPI2_ETHERNET_IP_ADDR SubnetMask; /* 0x2C */ + MPI2_ETHERNET_IP_ADDR GatewayIpAddress; /* 0x3C */ + MPI2_ETHERNET_IP_ADDR DNS1IpAddress; /* 0x4C */ + MPI2_ETHERNET_IP_ADDR DNS2IpAddress; /* 0x5C */ + MPI2_ETHERNET_IP_ADDR DhcpIpAddress; /* 0x6C */ + U8 HostName + [MPI2_ETHERNET_HOST_NAME_LENGTH];/* 0x7C */ +} MPI2_CONFIG_PAGE_ETHERNET_0, MPI2_POINTER PTR_MPI2_CONFIG_PAGE_ETHERNET_0, + Mpi2EthernetPage0_t, MPI2_POINTER pMpi2EthernetPage0_t; + +#define MPI2_ETHERNETPAGE0_PAGEVERSION (0x00) + +/* values for Ethernet Page 0 Status field */ +#define MPI2_ETHPG0_STATUS_IPV6_CAPABLE (0x80000000) +#define MPI2_ETHPG0_STATUS_IPV4_CAPABLE (0x40000000) +#define MPI2_ETHPG0_STATUS_CONSOLE_CONNECTED (0x20000000) +#define MPI2_ETHPG0_STATUS_DEFAULT_IF (0x00000100) +#define MPI2_ETHPG0_STATUS_FW_DWNLD_ENABLED (0x00000080) +#define MPI2_ETHPG0_STATUS_TELNET_ENABLED (0x00000040) +#define MPI2_ETHPG0_STATUS_SSH2_ENABLED (0x00000020) +#define MPI2_ETHPG0_STATUS_DHCP_CLIENT_ENABLED (0x00000010) +#define MPI2_ETHPG0_STATUS_IPV6_ENABLED (0x00000008) +#define MPI2_ETHPG0_STATUS_IPV4_ENABLED (0x00000004) +#define MPI2_ETHPG0_STATUS_IPV6_ADDRESSES (0x00000002) +#define MPI2_ETHPG0_STATUS_ETH_IF_ENABLED (0x00000001) + +/* values for Ethernet Page 0 MediaState field */ +#define MPI2_ETHPG0_MS_DUPLEX_MASK (0x80) +#define MPI2_ETHPG0_MS_HALF_DUPLEX (0x00) +#define MPI2_ETHPG0_MS_FULL_DUPLEX (0x80) + +#define MPI2_ETHPG0_MS_CONNECT_SPEED_MASK (0x07) +#define MPI2_ETHPG0_MS_NOT_CONNECTED (0x00) +#define MPI2_ETHPG0_MS_10MBIT (0x01) +#define MPI2_ETHPG0_MS_100MBIT (0x02) +#define MPI2_ETHPG0_MS_1GBIT (0x03) + + +/* Ethernet Page 1 */ + +typedef struct _MPI2_CONFIG_PAGE_ETHERNET_1 { + MPI2_CONFIG_EXTENDED_PAGE_HEADER Header; /* 0x00 */ + U32 Reserved0; /* 0x08 */ + U32 Flags; /* 0x0C */ + U8 MediaState; /* 0x10 */ + U8 Reserved1; /* 0x11 */ + U16 Reserved2; /* 0x12 */ + U8 MacAddress[6]; /* 0x14 */ + U8 Reserved3; /* 0x1A */ + U8 Reserved4; /* 0x1B */ + MPI2_ETHERNET_IP_ADDR StaticIpAddress; /* 0x1C */ + MPI2_ETHERNET_IP_ADDR StaticSubnetMask; /* 0x2C */ + MPI2_ETHERNET_IP_ADDR StaticGatewayIpAddress; /* 0x3C */ + MPI2_ETHERNET_IP_ADDR StaticDNS1IpAddress; /* 0x4C */ + MPI2_ETHERNET_IP_ADDR StaticDNS2IpAddress; /* 0x5C */ + U32 Reserved5; /* 0x6C */ + U32 Reserved6; /* 0x70 */ + U32 Reserved7; /* 0x74 */ + U32 Reserved8; /* 0x78 */ + U8 HostName + [MPI2_ETHERNET_HOST_NAME_LENGTH];/* 0x7C */ +} MPI2_CONFIG_PAGE_ETHERNET_1, MPI2_POINTER PTR_MPI2_CONFIG_PAGE_ETHERNET_1, + Mpi2EthernetPage1_t, MPI2_POINTER pMpi2EthernetPage1_t; + +#define MPI2_ETHERNETPAGE1_PAGEVERSION (0x00) + +/* values for Ethernet Page 1 Flags field */ +#define MPI2_ETHPG1_FLAG_SET_DEFAULT_IF (0x00000100) +#define MPI2_ETHPG1_FLAG_ENABLE_FW_DOWNLOAD (0x00000080) +#define MPI2_ETHPG1_FLAG_ENABLE_TELNET (0x00000040) +#define MPI2_ETHPG1_FLAG_ENABLE_SSH2 (0x00000020) +#define MPI2_ETHPG1_FLAG_ENABLE_DHCP_CLIENT (0x00000010) +#define MPI2_ETHPG1_FLAG_ENABLE_IPV6 (0x00000008) +#define MPI2_ETHPG1_FLAG_ENABLE_IPV4 (0x00000004) +#define MPI2_ETHPG1_FLAG_USE_IPV6_ADDRESSES (0x00000002) +#define MPI2_ETHPG1_FLAG_ENABLE_ETH_IF (0x00000001) + +/* values for Ethernet Page 1 MediaState field */ +#define MPI2_ETHPG1_MS_DUPLEX_MASK (0x80) +#define MPI2_ETHPG1_MS_HALF_DUPLEX (0x00) +#define MPI2_ETHPG1_MS_FULL_DUPLEX (0x80) + +#define MPI2_ETHPG1_MS_DATA_RATE_MASK (0x07) +#define MPI2_ETHPG1_MS_DATA_RATE_AUTO (0x00) +#define MPI2_ETHPG1_MS_DATA_RATE_10MBIT (0x01) +#define MPI2_ETHPG1_MS_DATA_RATE_100MBIT (0x02) +#define MPI2_ETHPG1_MS_DATA_RATE_1GBIT (0x03) + + #endif diff --git a/drivers/scsi/mpt2sas/mpi/mpi2_ioc.h b/drivers/scsi/mpt2sas/mpi/mpi2_ioc.h index c294128bdeb4..ea51ce868690 100644 --- a/drivers/scsi/mpt2sas/mpi/mpi2_ioc.h +++ b/drivers/scsi/mpt2sas/mpi/mpi2_ioc.h @@ -6,7 +6,7 @@ * Title: MPI IOC, Port, Event, FW Download, and FW Upload messages * Creation Date: October 11, 2006 * - * mpi2_ioc.h Version: 02.00.11 + * mpi2_ioc.h Version: 02.00.12 * * Version History * --------------- @@ -84,6 +84,9 @@ * Added two new reason codes for SAS Device Status Change * Event. * Added new event: SAS PHY Counter. + * 07-30-09 02.00.12 Added GPIO Interrupt event define and structure. + * Added MPI2_IOCFACTS_CAPABILITY_EXTENDED_BUFFER define. + * Added new product id family for 2208. * -------------------------------------------------------------------------- */ @@ -274,6 +277,7 @@ typedef struct _MPI2_IOC_FACTS_REPLY #define MPI2_IOCFACTS_CAPABILITY_MULTICAST (0x00000100) #define MPI2_IOCFACTS_CAPABILITY_BIDIRECTIONAL_TARGET (0x00000080) #define MPI2_IOCFACTS_CAPABILITY_EEDP (0x00000040) +#define MPI2_IOCFACTS_CAPABILITY_EXTENDED_BUFFER (0x00000020) #define MPI2_IOCFACTS_CAPABILITY_SNAPSHOT_BUFFER (0x00000010) #define MPI2_IOCFACTS_CAPABILITY_DIAG_TRACE_BUFFER (0x00000008) #define MPI2_IOCFACTS_CAPABILITY_TASK_SET_FULL_HANDLING (0x00000004) @@ -448,6 +452,7 @@ typedef struct _MPI2_EVENT_NOTIFICATION_REPLY #define MPI2_EVENT_IR_CONFIGURATION_CHANGE_LIST (0x0020) #define MPI2_EVENT_LOG_ENTRY_ADDED (0x0021) #define MPI2_EVENT_SAS_PHY_COUNTER (0x0022) +#define MPI2_EVENT_GPIO_INTERRUPT (0x0023) /* Log Entry Added Event data */ @@ -469,6 +474,16 @@ typedef struct _MPI2_EVENT_DATA_LOG_ENTRY_ADDED MPI2_POINTER PTR_MPI2_EVENT_DATA_LOG_ENTRY_ADDED, Mpi2EventDataLogEntryAdded_t, MPI2_POINTER pMpi2EventDataLogEntryAdded_t; +/* GPIO Interrupt Event data */ + +typedef struct _MPI2_EVENT_DATA_GPIO_INTERRUPT { + U8 GPIONum; /* 0x00 */ + U8 Reserved1; /* 0x01 */ + U16 Reserved2; /* 0x02 */ +} MPI2_EVENT_DATA_GPIO_INTERRUPT, + MPI2_POINTER PTR_MPI2_EVENT_DATA_GPIO_INTERRUPT, + Mpi2EventDataGpioInterrupt_t, MPI2_POINTER pMpi2EventDataGpioInterrupt_t; + /* Hard Reset Received Event data */ typedef struct _MPI2_EVENT_DATA_HARD_RESET_RECEIVED @@ -1117,6 +1132,7 @@ typedef struct _MPI2_FW_IMAGE_HEADER #define MPI2_FW_HEADER_PID_FAMILY_MASK (0x00FF) /* SAS */ #define MPI2_FW_HEADER_PID_FAMILY_2108_SAS (0x0010) +#define MPI2_FW_HEADER_PID_FAMILY_2208_SAS (0x0011) /* use MPI2_IOCFACTS_PROTOCOL_ defines for ProtocolFlags field */ diff --git a/drivers/scsi/mpt2sas/mpi/mpi2_raid.h b/drivers/scsi/mpt2sas/mpi/mpi2_raid.h index 7134816d9046..5160c33d2a00 100644 --- a/drivers/scsi/mpt2sas/mpi/mpi2_raid.h +++ b/drivers/scsi/mpt2sas/mpi/mpi2_raid.h @@ -6,7 +6,7 @@ * Title: MPI Integrated RAID messages and structures * Creation Date: April 26, 2007 * - * mpi2_raid.h Version: 02.00.03 + * mpi2_raid.h Version: 02.00.04 * * Version History * --------------- @@ -20,6 +20,8 @@ * 05-21-08 02.00.03 Added MPI2_RAID_VOL_CREATION_NUM_PHYSDISKS so that * the PhysDisk array in MPI2_RAID_VOLUME_CREATION_STRUCT * can be sized by the build environment. + * 07-30-09 02.00.04 Added proper define for the Use Default Settings bit of + * VolumeCreationFlags and marked the old one as obsolete. * -------------------------------------------------------------------------- */ @@ -217,10 +219,14 @@ typedef struct _MPI2_RAID_VOLUME_CREATION_STRUCT /* use MPI2_RAID_VOL_TYPE_ defines from mpi2_cnfg.h for VolumeType */ /* defines for the VolumeCreationFlags field */ +#define MPI2_RAID_VOL_CREATION_DEFAULT_SETTINGS (0x80000000) +#define MPI2_RAID_VOL_CREATION_BACKGROUND_INIT (0x00000004) +#define MPI2_RAID_VOL_CREATION_LOW_LEVEL_INIT (0x00000002) +#define MPI2_RAID_VOL_CREATION_MIGRATE_DATA (0x00000001) +/* The following is an obsolete define. + * It must be shifted left 24 bits in order to set the proper bit. + */ #define MPI2_RAID_VOL_CREATION_USE_DEFAULT_SETTINGS (0x80) -#define MPI2_RAID_VOL_CREATION_BACKGROUND_INIT (0x04) -#define MPI2_RAID_VOL_CREATION_LOW_LEVEL_INIT (0x02) -#define MPI2_RAID_VOL_CREATION_MIGRATE_DATA (0x01) /* RAID Online Capacity Expansion Structure */ diff --git a/drivers/scsi/mpt2sas/mpi/mpi2_tool.h b/drivers/scsi/mpt2sas/mpi/mpi2_tool.h index 007e950f7bfa..73fcdbf92632 100644 --- a/drivers/scsi/mpt2sas/mpi/mpi2_tool.h +++ b/drivers/scsi/mpt2sas/mpi/mpi2_tool.h @@ -6,7 +6,7 @@ * Title: MPI diagnostic tool structures and definitions * Creation Date: March 26, 2007 * - * mpi2_tool.h Version: 02.00.03 + * mpi2_tool.h Version: 02.00.04 * * Version History * --------------- @@ -18,6 +18,10 @@ * structures and defines. * 02-29-08 02.00.02 Modified various names to make them 32-character unique. * 05-06-09 02.00.03 Added ISTWI Read Write Tool and Diagnostic CLI Tool. + * 07-30-09 02.00.04 Added ExtendedType field to DiagnosticBufferPost request + * and reply messages. + * Added MPI2_DIAG_BUF_TYPE_EXTENDED. + * Incremented MPI2_DIAG_BUF_TYPE_COUNT. * -------------------------------------------------------------------------- */ @@ -282,7 +286,7 @@ typedef struct _MPI2_TOOLBOX_DIAGNOSTIC_CLI_REPLY { typedef struct _MPI2_DIAG_BUFFER_POST_REQUEST { - U8 Reserved1; /* 0x00 */ + U8 ExtendedType; /* 0x00 */ U8 BufferType; /* 0x01 */ U8 ChainOffset; /* 0x02 */ U8 Function; /* 0x03 */ @@ -301,11 +305,15 @@ typedef struct _MPI2_DIAG_BUFFER_POST_REQUEST } MPI2_DIAG_BUFFER_POST_REQUEST, MPI2_POINTER PTR_MPI2_DIAG_BUFFER_POST_REQUEST, Mpi2DiagBufferPostRequest_t, MPI2_POINTER pMpi2DiagBufferPostRequest_t; +/* values for the ExtendedType field */ +#define MPI2_DIAG_EXTENDED_TYPE_UTILIZATION (0x02) + /* values for the BufferType field */ #define MPI2_DIAG_BUF_TYPE_TRACE (0x00) #define MPI2_DIAG_BUF_TYPE_SNAPSHOT (0x01) +#define MPI2_DIAG_BUF_TYPE_EXTENDED (0x02) /* count of the number of buffer types */ -#define MPI2_DIAG_BUF_TYPE_COUNT (0x02) +#define MPI2_DIAG_BUF_TYPE_COUNT (0x03) /**************************************************************************** @@ -314,7 +322,7 @@ typedef struct _MPI2_DIAG_BUFFER_POST_REQUEST typedef struct _MPI2_DIAG_BUFFER_POST_REPLY { - U8 Reserved1; /* 0x00 */ + U8 ExtendedType; /* 0x00 */ U8 BufferType; /* 0x01 */ U8 MsgLength; /* 0x02 */ U8 Function; /* 0x03 */ diff --git a/drivers/scsi/mpt2sas/mpt2sas_base.c b/drivers/scsi/mpt2sas/mpt2sas_base.c index 670241efa4b5..6422e258fd52 100644 --- a/drivers/scsi/mpt2sas/mpt2sas_base.c +++ b/drivers/scsi/mpt2sas/mpt2sas_base.c @@ -57,6 +57,7 @@ #include <linux/dma-mapping.h> #include <linux/sort.h> #include <linux/io.h> +#include <linux/time.h> #include "mpt2sas_base.h" @@ -77,6 +78,44 @@ static int msix_disable = -1; module_param(msix_disable, int, 0); MODULE_PARM_DESC(msix_disable, " disable msix routed interrupts (default=0)"); +/* diag_buffer_enable is bitwise + * bit 0 set = TRACE + * bit 1 set = SNAPSHOT + * bit 2 set = EXTENDED + * + * Either bit can be set, or both + */ +static int diag_buffer_enable; +module_param(diag_buffer_enable, int, 0); +MODULE_PARM_DESC(diag_buffer_enable, " post diag buffers " + "(TRACE=1/SNAPSHOT=2/EXTENDED=4/default=0)"); + +int mpt2sas_fwfault_debug; +MODULE_PARM_DESC(mpt2sas_fwfault_debug, " enable detection of firmware fault " + "and halt firmware - (default=0)"); + +/** + * _scsih_set_fwfault_debug - global setting of ioc->fwfault_debug. + * + */ +static int +_scsih_set_fwfault_debug(const char *val, struct kernel_param *kp) +{ + int ret = param_set_int(val, kp); + struct MPT2SAS_ADAPTER *ioc; + + if (ret) + return ret; + + printk(KERN_INFO "setting logging_level(0x%08x)\n", + mpt2sas_fwfault_debug); + list_for_each_entry(ioc, &mpt2sas_ioc_list, list) + ioc->fwfault_debug = mpt2sas_fwfault_debug; + return 0; +} +module_param_call(mpt2sas_fwfault_debug, _scsih_set_fwfault_debug, + param_get_int, &mpt2sas_fwfault_debug, 0644); + /** * _base_fault_reset_work - workq handling ioc fault conditions * @work: input argument, used to derive ioc @@ -121,7 +160,7 @@ _base_fault_reset_work(struct work_struct *work) /** * mpt2sas_base_start_watchdog - start the fault_reset_work_q - * @ioc: pointer to scsi command object + * @ioc: per adapter object * Context: sleep. * * Return nothing. @@ -155,7 +194,7 @@ mpt2sas_base_start_watchdog(struct MPT2SAS_ADAPTER *ioc) /** * mpt2sas_base_stop_watchdog - stop the fault_reset_work_q - * @ioc: pointer to scsi command object + * @ioc: per adapter object * Context: sleep. * * Return nothing. @@ -177,10 +216,55 @@ mpt2sas_base_stop_watchdog(struct MPT2SAS_ADAPTER *ioc) } } +/** + * mpt2sas_base_fault_info - verbose translation of firmware FAULT code + * @ioc: per adapter object + * @fault_code: fault code + * + * Return nothing. + */ +void +mpt2sas_base_fault_info(struct MPT2SAS_ADAPTER *ioc , u16 fault_code) +{ + printk(MPT2SAS_ERR_FMT "fault_state(0x%04x)!\n", + ioc->name, fault_code); +} + +/** + * mpt2sas_halt_firmware - halt's mpt controller firmware + * @ioc: per adapter object + * + * For debugging timeout related issues. Writing 0xCOFFEE00 + * to the doorbell register will halt controller firmware. With + * the purpose to stop both driver and firmware, the enduser can + * obtain a ring buffer from controller UART. + */ +void +mpt2sas_halt_firmware(struct MPT2SAS_ADAPTER *ioc) +{ + u32 doorbell; + + if (!ioc->fwfault_debug) + return; + + dump_stack(); + + doorbell = readl(&ioc->chip->Doorbell); + if ((doorbell & MPI2_IOC_STATE_MASK) == MPI2_IOC_STATE_FAULT) + mpt2sas_base_fault_info(ioc , doorbell); + else { + writel(0xC0FFEE00, &ioc->chip->Doorbell); + printk(MPT2SAS_ERR_FMT "Firmware is halted due to command " + "timeout\n", ioc->name); + } + + panic("panic in %s\n", __func__); +} + #ifdef CONFIG_SCSI_MPT2SAS_LOGGING /** * _base_sas_ioc_info - verbose translation of the ioc status - * @ioc: pointer to scsi command object + * @ioc: per adapter object * @mpi_reply: reply mf payload returned from firmware * @request_hdr: request mf * @@ -394,7 +478,7 @@ _base_sas_ioc_info(struct MPT2SAS_ADAPTER *ioc, MPI2DefaultReply_t *mpi_reply, /** * _base_display_event_data - verbose translation of firmware asyn events - * @ioc: pointer to scsi command object + * @ioc: per adapter object * @mpi_reply: reply mf payload returned from firmware * * Return nothing. @@ -474,7 +558,7 @@ _base_display_event_data(struct MPT2SAS_ADAPTER *ioc, /** * _base_sas_log_info - verbose translation of firmware log info - * @ioc: pointer to scsi command object + * @ioc: per adapter object * @log_info: log info * * Return nothing. @@ -526,22 +610,8 @@ _base_sas_log_info(struct MPT2SAS_ADAPTER *ioc , u32 log_info) } /** - * mpt2sas_base_fault_info - verbose translation of firmware FAULT code - * @ioc: pointer to scsi command object - * @fault_code: fault code - * - * Return nothing. - */ -void -mpt2sas_base_fault_info(struct MPT2SAS_ADAPTER *ioc , u16 fault_code) -{ - printk(MPT2SAS_ERR_FMT "fault_state(0x%04x)!\n", - ioc->name, fault_code); -} - -/** * _base_display_reply_info - - * @ioc: pointer to scsi command object + * @ioc: per adapter object * @smid: system request message index * @msix_index: MSIX table index supplied by the OS * @reply: reply message frame(lower 32bit addr) @@ -570,7 +640,7 @@ _base_display_reply_info(struct MPT2SAS_ADAPTER *ioc, u16 smid, u8 msix_index, /** * mpt2sas_base_done - base internal command completion routine - * @ioc: pointer to scsi command object + * @ioc: per adapter object * @smid: system request message index * @msix_index: MSIX table index supplied by the OS * @reply: reply message frame(lower 32bit addr) @@ -603,7 +673,7 @@ mpt2sas_base_done(struct MPT2SAS_ADAPTER *ioc, u16 smid, u8 msix_index, /** * _base_async_event - main callback handler for firmware asyn events - * @ioc: pointer to scsi command object + * @ioc: per adapter object * @msix_index: MSIX table index supplied by the OS * @reply: reply message frame(lower 32bit addr) * @@ -684,7 +754,7 @@ _base_get_cb_idx(struct MPT2SAS_ADAPTER *ioc, u16 smid) /** * _base_mask_interrupts - disable interrupts - * @ioc: pointer to scsi command object + * @ioc: per adapter object * * Disabling ResetIRQ, Reply and Doorbell Interrupts * @@ -704,7 +774,7 @@ _base_mask_interrupts(struct MPT2SAS_ADAPTER *ioc) /** * _base_unmask_interrupts - enable interrupts - * @ioc: pointer to scsi command object + * @ioc: per adapter object * * Enabling only Reply Interrupts * @@ -1258,12 +1328,13 @@ mpt2sas_base_get_sense_buffer(struct MPT2SAS_ADAPTER *ioc, u16 smid) * @ioc: per adapter object * @smid: system request message index * - * Returns phys pointer to sense buffer. + * Returns phys pointer to the low 32bit address of the sense buffer. */ -dma_addr_t +__le32 mpt2sas_base_get_sense_buffer_dma(struct MPT2SAS_ADAPTER *ioc, u16 smid) { - return ioc->sense_dma + ((smid - 1) * SCSI_SENSE_BUFFERSIZE); + return cpu_to_le32(ioc->sense_dma + + ((smid - 1) * SCSI_SENSE_BUFFERSIZE)); } /** @@ -1697,6 +1768,12 @@ _base_display_ioc_capabilities(struct MPT2SAS_ADAPTER *ioc) } if (ioc->facts.IOCCapabilities & + MPI2_IOCFACTS_CAPABILITY_EXTENDED_BUFFER) { + printk(KERN_INFO "%sDiag Extended Buffer", i ? "," : ""); + i++; + } + + if (ioc->facts.IOCCapabilities & MPI2_IOCFACTS_CAPABILITY_TASK_SET_FULL_HANDLING) { printk("%sTask Set Full", i ? "," : ""); i++; @@ -2871,6 +2948,8 @@ _base_send_ioc_init(struct MPT2SAS_ADAPTER *ioc, int sleep_flag) Mpi2IOCInitRequest_t mpi_request; Mpi2IOCInitReply_t mpi_reply; int r; + struct timeval current_time; + u16 ioc_status; dinitprintk(ioc, printk(MPT2SAS_DEBUG_FMT "%s\n", ioc->name, __func__)); @@ -2921,6 +3000,13 @@ _base_send_ioc_init(struct MPT2SAS_ADAPTER *ioc, int sleep_flag) cpu_to_le32(ioc->reply_post_free_dma); #endif + /* This time stamp specifies number of milliseconds + * since epoch ~ midnight January 1, 1970. + */ + do_gettimeofday(¤t_time); + mpi_request.TimeStamp = (current_time.tv_sec * 1000) + + (current_time.tv_usec >> 3); + if (ioc->logging_level & MPT_DEBUG_INIT) { u32 *mfp; int i; @@ -2943,7 +3029,8 @@ _base_send_ioc_init(struct MPT2SAS_ADAPTER *ioc, int sleep_flag) return r; } - if (mpi_reply.IOCStatus != MPI2_IOCSTATUS_SUCCESS || + ioc_status = le16_to_cpu(mpi_reply.IOCStatus) & MPI2_IOCSTATUS_MASK; + if (ioc_status != MPI2_IOCSTATUS_SUCCESS || mpi_reply.IOCLogInfo) { printk(MPT2SAS_ERR_FMT "%s: failed\n", ioc->name, __func__); r = -EIO; @@ -3461,11 +3548,11 @@ mpt2sas_base_attach(struct MPT2SAS_ADAPTER *ioc) return r; pci_set_drvdata(ioc->pdev, ioc->shost); - r = _base_make_ioc_ready(ioc, CAN_SLEEP, SOFT_RESET); + r = _base_get_ioc_facts(ioc, CAN_SLEEP); if (r) goto out_free_resources; - r = _base_get_ioc_facts(ioc, CAN_SLEEP); + r = _base_make_ioc_ready(ioc, CAN_SLEEP, SOFT_RESET); if (r) goto out_free_resources; @@ -3531,6 +3618,8 @@ mpt2sas_base_attach(struct MPT2SAS_ADAPTER *ioc) goto out_free_resources; mpt2sas_base_start_watchdog(ioc); + if (diag_buffer_enable != 0) + mpt2sas_enable_diag_buffer(ioc, diag_buffer_enable); return 0; out_free_resources: @@ -3684,6 +3773,9 @@ mpt2sas_base_hard_reset_handler(struct MPT2SAS_ADAPTER *ioc, int sleep_flag, dtmprintk(ioc, printk(MPT2SAS_DEBUG_FMT "%s: enter\n", ioc->name, __func__)); + if (mpt2sas_fwfault_debug) + mpt2sas_halt_firmware(ioc); + spin_lock_irqsave(&ioc->ioc_reset_in_progress_lock, flags); if (ioc->shost_recovery) { spin_unlock_irqrestore(&ioc->ioc_reset_in_progress_lock, flags); diff --git a/drivers/scsi/mpt2sas/mpt2sas_base.h b/drivers/scsi/mpt2sas/mpt2sas_base.h index 0cf6bc236e4d..bb4f14656afa 100644 --- a/drivers/scsi/mpt2sas/mpt2sas_base.h +++ b/drivers/scsi/mpt2sas/mpt2sas_base.h @@ -69,8 +69,8 @@ #define MPT2SAS_DRIVER_NAME "mpt2sas" #define MPT2SAS_AUTHOR "LSI Corporation <DL-MPTFusionLinux@lsi.com>" #define MPT2SAS_DESCRIPTION "LSI MPT Fusion SAS 2.0 Device Driver" -#define MPT2SAS_DRIVER_VERSION "02.100.03.00" -#define MPT2SAS_MAJOR_VERSION 02 +#define MPT2SAS_DRIVER_VERSION "03.100.03.00" +#define MPT2SAS_MAJOR_VERSION 03 #define MPT2SAS_MINOR_VERSION 100 #define MPT2SAS_BUILD_VERSION 03 #define MPT2SAS_RELEASE_VERSION 00 @@ -278,7 +278,7 @@ struct _internal_cmd { * @sas_address: device sas address * @device_name: retrieved from the SAS IDENTIFY frame. * @handle: device handle - * @parent_handle: handle to parent device + * @sas_address_parent: sas address of parent expander or sas host * @enclosure_handle: enclosure handle * @enclosure_logical_id: enclosure logical identifier * @volume_handle: volume handle (valid when hidden raid member) @@ -296,7 +296,7 @@ struct _sas_device { u64 sas_address; u64 device_name; u16 handle; - u16 parent_handle; + u64 sas_address_parent; u16 enclosure_handle; u64 enclosure_logical_id; u16 volume_handle; @@ -352,8 +352,6 @@ struct _boot_device { /** * struct _sas_port - wide/narrow sas port information * @port_list: list of ports belonging to expander - * @handle: device handle for this port - * @sas_address: sas address of this port * @num_phys: number of phys belonging to this port * @remote_identify: attached device identification * @rphy: sas transport rphy object @@ -362,8 +360,6 @@ struct _boot_device { */ struct _sas_port { struct list_head port_list; - u16 handle; - u64 sas_address; u8 num_phys; struct sas_identify remote_identify; struct sas_rphy *rphy; @@ -398,7 +394,7 @@ struct _sas_phy { * @num_phys: number phys belonging to this sas_host/expander * @sas_address: sas address of this sas_host/expander * @handle: handle for this sas_host/expander - * @parent_handle: parent handle + * @sas_address_parent: sas address of parent expander or sas host * @enclosure_handle: handle for this a member of an enclosure * @device_info: bitwise defining capabilities of this sas_host/expander * @responding: used in _scsih_expander_device_mark_responding @@ -411,7 +407,7 @@ struct _sas_node { u8 num_phys; u64 sas_address; u16 handle; - u16 parent_handle; + u64 sas_address_parent; u16 enclosure_handle; u64 enclosure_logical_id; u8 responding; @@ -470,6 +466,7 @@ typedef void (*MPT_ADD_SGE)(void *paddr, u32 flags_length, dma_addr_t dma_addr); * @chip_phys: physical addrss prior to mapping * @pio_chip: I/O mapped register space * @logging_level: see mpt2sas_debug.h + * @fwfault_debug: debuging FW timeouts * @ir_firmware: IR firmware present * @bars: bitmask of BAR's that must be configured * @mask_interrupts: ignore interrupt @@ -495,12 +492,14 @@ typedef void (*MPT_ADD_SGE)(void *paddr, u32 flags_length, dma_addr_t dma_addr); * @msix_table_backup: backup msix table * @scsi_io_cb_idx: shost generated commands * @tm_cb_idx: task management commands + * @scsih_cb_idx: scsih internal commands * @transport_cb_idx: transport internal commands * @ctl_cb_idx: clt internal commands * @base_cb_idx: base internal commands * @config_cb_idx: base internal commands * @base_cmds: * @transport_cmds: + * @scsih_cmds: * @tm_cmds: * @ctl_cmds: * @config_cmds: @@ -591,6 +590,7 @@ struct MPT2SAS_ADAPTER { unsigned long chip_phys; unsigned long pio_chip; int logging_level; + int fwfault_debug; u8 ir_firmware; int bars; u8 mask_interrupts; @@ -626,6 +626,7 @@ struct MPT2SAS_ADAPTER { u8 scsi_io_cb_idx; u8 tm_cb_idx; u8 transport_cb_idx; + u8 scsih_cb_idx; u8 ctl_cb_idx; u8 base_cb_idx; u8 config_cb_idx; @@ -633,6 +634,7 @@ struct MPT2SAS_ADAPTER { u8 tm_sas_control_cb_idx; struct _internal_cmd base_cmds; struct _internal_cmd transport_cmds; + struct _internal_cmd scsih_cmds; struct _internal_cmd tm_cmds; struct _internal_cmd ctl_cmds; struct _internal_cmd config_cmds; @@ -773,7 +775,7 @@ int mpt2sas_base_hard_reset_handler(struct MPT2SAS_ADAPTER *ioc, int sleep_flag, void *mpt2sas_base_get_msg_frame(struct MPT2SAS_ADAPTER *ioc, u16 smid); void *mpt2sas_base_get_sense_buffer(struct MPT2SAS_ADAPTER *ioc, u16 smid); void mpt2sas_base_build_zero_len_sge(struct MPT2SAS_ADAPTER *ioc, void *paddr); -dma_addr_t mpt2sas_base_get_sense_buffer_dma(struct MPT2SAS_ADAPTER *ioc, +__le32 mpt2sas_base_get_sense_buffer_dma(struct MPT2SAS_ADAPTER *ioc, u16 smid); /* hi-priority queue */ @@ -807,6 +809,8 @@ int mpt2sas_base_scsi_enclosure_processor(struct MPT2SAS_ADAPTER *ioc, Mpi2SepReply_t *mpi_reply, Mpi2SepRequest_t *mpi_request); void mpt2sas_base_validate_event_type(struct MPT2SAS_ADAPTER *ioc, u32 *event_type); +void mpt2sas_halt_firmware(struct MPT2SAS_ADAPTER *ioc); + /* scsih shared API */ u8 mpt2sas_scsih_event_callback(struct MPT2SAS_ADAPTER *ioc, u8 msix_index, u32 reply); @@ -886,19 +890,22 @@ u8 mpt2sas_ctl_event_callback(struct MPT2SAS_ADAPTER *ioc, u8 msix_index, void mpt2sas_ctl_add_to_event_log(struct MPT2SAS_ADAPTER *ioc, Mpi2EventNotificationReply_t *mpi_reply); +void mpt2sas_enable_diag_buffer(struct MPT2SAS_ADAPTER *ioc, + u8 bits_to_regsiter); + /* transport shared API */ u8 mpt2sas_transport_done(struct MPT2SAS_ADAPTER *ioc, u16 smid, u8 msix_index, u32 reply); struct _sas_port *mpt2sas_transport_port_add(struct MPT2SAS_ADAPTER *ioc, - u16 handle, u16 parent_handle); + u16 handle, u64 sas_address); void mpt2sas_transport_port_remove(struct MPT2SAS_ADAPTER *ioc, u64 sas_address, - u16 parent_handle); + u64 sas_address_parent); int mpt2sas_transport_add_host_phy(struct MPT2SAS_ADAPTER *ioc, struct _sas_phy *mpt2sas_phy, Mpi2SasPhyPage0_t phy_pg0, struct device *parent_dev); int mpt2sas_transport_add_expander_phy(struct MPT2SAS_ADAPTER *ioc, struct _sas_phy *mpt2sas_phy, Mpi2ExpanderPage1_t expander_pg1, struct device *parent_dev); -void mpt2sas_transport_update_links(struct MPT2SAS_ADAPTER *ioc, u16 handle, - u16 attached_handle, u8 phy_number, u8 link_rate); +void mpt2sas_transport_update_links(struct MPT2SAS_ADAPTER *ioc, + u64 sas_address, u16 handle, u8 phy_number, u8 link_rate); extern struct sas_function_template mpt2sas_transport_functions; extern struct scsi_transport_template *mpt2sas_transport_template; extern int scsi_internal_device_block(struct scsi_device *sdev); diff --git a/drivers/scsi/mpt2sas/mpt2sas_ctl.c b/drivers/scsi/mpt2sas/mpt2sas_ctl.c index 57d724633906..84a124f8e21f 100644 --- a/drivers/scsi/mpt2sas/mpt2sas_ctl.c +++ b/drivers/scsi/mpt2sas/mpt2sas_ctl.c @@ -740,7 +740,7 @@ _ctl_do_mpt_command(struct MPT2SAS_ADAPTER *ioc, Mpi2SCSIIORequest_t *scsiio_request = (Mpi2SCSIIORequest_t *)mpi_request; scsiio_request->SenseBufferLowAddress = - (u32)mpt2sas_base_get_sense_buffer_dma(ioc, smid); + mpt2sas_base_get_sense_buffer_dma(ioc, smid); priv_sense = mpt2sas_base_get_sense_buffer(ioc, smid); memset(priv_sense, 0, SCSI_SENSE_BUFFERSIZE); mpt2sas_base_put_smid_scsi_io(ioc, smid, @@ -848,8 +848,9 @@ _ctl_do_mpt_command(struct MPT2SAS_ADAPTER *ioc, printk(MPT2SAS_DEBUG_FMT "TASK_MGMT: " "IOCStatus(0x%04x), IOCLogInfo(0x%08x), " "TerminationCount(0x%08x)\n", ioc->name, - tm_reply->IOCStatus, tm_reply->IOCLogInfo, - tm_reply->TerminationCount); + le16_to_cpu(tm_reply->IOCStatus), + le32_to_cpu(tm_reply->IOCLogInfo), + le32_to_cpu(tm_reply->TerminationCount)); } #endif /* copy out xdata to user */ @@ -896,6 +897,7 @@ _ctl_do_mpt_command(struct MPT2SAS_ADAPTER *ioc, printk(MPT2SAS_INFO_FMT "issue target reset: handle " "= (0x%04x)\n", ioc->name, mpi_request->FunctionDependent1); + mpt2sas_halt_firmware(ioc); mutex_lock(&ioc->tm_cmds.mutex); mpt2sas_scsih_issue_tm(ioc, mpi_request->FunctionDependent1, 0, @@ -1229,7 +1231,7 @@ _ctl_btdh_mapping(void __user *arg) /** * _ctl_diag_capability - return diag buffer capability * @ioc: per adapter object - * @buffer_type: specifies either TRACE or SNAPSHOT + * @buffer_type: specifies either TRACE, SNAPSHOT, or EXTENDED * * returns 1 when diag buffer support is enabled in firmware */ @@ -1249,24 +1251,25 @@ _ctl_diag_capability(struct MPT2SAS_ADAPTER *ioc, u8 buffer_type) MPI2_IOCFACTS_CAPABILITY_SNAPSHOT_BUFFER) rc = 1; break; + case MPI2_DIAG_BUF_TYPE_EXTENDED: + if (ioc->facts.IOCCapabilities & + MPI2_IOCFACTS_CAPABILITY_EXTENDED_BUFFER) + rc = 1; } return rc; } /** - * _ctl_diag_register - application register with driver - * @arg - user space buffer containing ioctl content - * @state - NON_BLOCKING or BLOCKING + * _ctl_diag_register_2 - wrapper for registering diag buffer support + * @ioc: per adapter object + * @diag_register: the diag_register struct passed in from user space * - * This will allow the driver to setup any required buffers that will be - * needed by firmware to communicate with the driver. */ static long -_ctl_diag_register(void __user *arg, enum block_state state) +_ctl_diag_register_2(struct MPT2SAS_ADAPTER *ioc, + struct mpt2_diag_register *diag_register) { - struct mpt2_diag_register karg; - struct MPT2SAS_ADAPTER *ioc; int rc, i; void *request_data = NULL; dma_addr_t request_data_dma; @@ -1279,18 +1282,17 @@ _ctl_diag_register(void __user *arg, enum block_state state) u16 ioc_status; u8 issue_reset = 0; - if (copy_from_user(&karg, arg, sizeof(karg))) { - printk(KERN_ERR "failure at %s:%d/%s()!\n", - __FILE__, __LINE__, __func__); - return -EFAULT; - } - if (_ctl_verify_adapter(karg.hdr.ioc_number, &ioc) == -1 || !ioc) - return -ENODEV; - dctlprintk(ioc, printk(MPT2SAS_DEBUG_FMT "%s\n", ioc->name, __func__)); - buffer_type = karg.buffer_type; + if (ioc->ctl_cmds.status != MPT2_CMD_NOT_USED) { + printk(MPT2SAS_ERR_FMT "%s: ctl_cmd in use\n", + ioc->name, __func__); + rc = -EAGAIN; + goto out; + } + + buffer_type = diag_register->buffer_type; if (!_ctl_diag_capability(ioc, buffer_type)) { printk(MPT2SAS_ERR_FMT "%s: doesn't have capability for " "buffer_type(0x%02x)\n", ioc->name, __func__, buffer_type); @@ -1305,24 +1307,12 @@ _ctl_diag_register(void __user *arg, enum block_state state) return -EINVAL; } - if (karg.requested_buffer_size % 4) { + if (diag_register->requested_buffer_size % 4) { printk(MPT2SAS_ERR_FMT "%s: the requested_buffer_size " "is not 4 byte aligned\n", ioc->name, __func__); return -EINVAL; } - if (state == NON_BLOCKING && !mutex_trylock(&ioc->ctl_cmds.mutex)) - return -EAGAIN; - else if (mutex_lock_interruptible(&ioc->ctl_cmds.mutex)) - return -ERESTARTSYS; - - if (ioc->ctl_cmds.status != MPT2_CMD_NOT_USED) { - printk(MPT2SAS_ERR_FMT "%s: ctl_cmd in use\n", - ioc->name, __func__); - rc = -EAGAIN; - goto out; - } - smid = mpt2sas_base_get_smid(ioc, ioc->ctl_cb_idx); if (!smid) { printk(MPT2SAS_ERR_FMT "%s: failed obtaining a smid\n", @@ -1338,12 +1328,12 @@ _ctl_diag_register(void __user *arg, enum block_state state) ioc->ctl_cmds.smid = smid; request_data = ioc->diag_buffer[buffer_type]; - request_data_sz = karg.requested_buffer_size; - ioc->unique_id[buffer_type] = karg.unique_id; + request_data_sz = diag_register->requested_buffer_size; + ioc->unique_id[buffer_type] = diag_register->unique_id; ioc->diag_buffer_status[buffer_type] = 0; - memcpy(ioc->product_specific[buffer_type], karg.product_specific, - MPT2_PRODUCT_SPECIFIC_DWORDS); - ioc->diagnostic_flags[buffer_type] = karg.diagnostic_flags; + memcpy(ioc->product_specific[buffer_type], + diag_register->product_specific, MPT2_PRODUCT_SPECIFIC_DWORDS); + ioc->diagnostic_flags[buffer_type] = diag_register->diagnostic_flags; if (request_data) { request_data_dma = ioc->diag_buffer_dma[buffer_type]; @@ -1373,8 +1363,8 @@ _ctl_diag_register(void __user *arg, enum block_state state) } mpi_request->Function = MPI2_FUNCTION_DIAG_BUFFER_POST; - mpi_request->BufferType = karg.buffer_type; - mpi_request->Flags = cpu_to_le32(karg.diagnostic_flags); + mpi_request->BufferType = diag_register->buffer_type; + mpi_request->Flags = cpu_to_le32(diag_register->diagnostic_flags); mpi_request->BufferAddress = cpu_to_le64(request_data_dma); mpi_request->BufferLength = cpu_to_le32(request_data_sz); mpi_request->VF_ID = 0; /* TODO */ @@ -1422,7 +1412,7 @@ _ctl_diag_register(void __user *arg, enum block_state state) } else { printk(MPT2SAS_DEBUG_FMT "%s: ioc_status(0x%04x) " "log_info(0x%08x)\n", ioc->name, __func__, - ioc_status, mpi_reply->IOCLogInfo); + ioc_status, le32_to_cpu(mpi_reply->IOCLogInfo)); rc = -EFAULT; } @@ -1438,6 +1428,83 @@ _ctl_diag_register(void __user *arg, enum block_state state) request_data, request_data_dma); ioc->ctl_cmds.status = MPT2_CMD_NOT_USED; + return rc; +} + +/** + * mpt2sas_enable_diag_buffer - enabling diag_buffers support driver load time + * @ioc: per adapter object + * @bits_to_register: bitwise field where trace is bit 0, and snapshot is bit 1 + * + * This is called when command line option diag_buffer_enable is enabled + * at driver load time. + */ +void +mpt2sas_enable_diag_buffer(struct MPT2SAS_ADAPTER *ioc, u8 bits_to_register) +{ + struct mpt2_diag_register diag_register; + + memset(&diag_register, 0, sizeof(struct mpt2_diag_register)); + + if (bits_to_register & 1) { + printk(MPT2SAS_INFO_FMT "registering trace buffer support\n", + ioc->name); + diag_register.buffer_type = MPI2_DIAG_BUF_TYPE_TRACE; + /* register for 1MB buffers */ + diag_register.requested_buffer_size = (1024 * 1024); + diag_register.unique_id = 0x7075900; + _ctl_diag_register_2(ioc, &diag_register); + } + + if (bits_to_register & 2) { + printk(MPT2SAS_INFO_FMT "registering snapshot buffer support\n", + ioc->name); + diag_register.buffer_type = MPI2_DIAG_BUF_TYPE_SNAPSHOT; + /* register for 2MB buffers */ + diag_register.requested_buffer_size = 2 * (1024 * 1024); + diag_register.unique_id = 0x7075901; + _ctl_diag_register_2(ioc, &diag_register); + } + + if (bits_to_register & 4) { + printk(MPT2SAS_INFO_FMT "registering extended buffer support\n", + ioc->name); + diag_register.buffer_type = MPI2_DIAG_BUF_TYPE_EXTENDED; + /* register for 2MB buffers */ + diag_register.requested_buffer_size = 2 * (1024 * 1024); + diag_register.unique_id = 0x7075901; + _ctl_diag_register_2(ioc, &diag_register); + } +} + +/** + * _ctl_diag_register - application register with driver + * @arg - user space buffer containing ioctl content + * @state - NON_BLOCKING or BLOCKING + * + * This will allow the driver to setup any required buffers that will be + * needed by firmware to communicate with the driver. + */ +static long +_ctl_diag_register(void __user *arg, enum block_state state) +{ + struct mpt2_diag_register karg; + struct MPT2SAS_ADAPTER *ioc; + long rc; + + if (copy_from_user(&karg, arg, sizeof(karg))) { + printk(KERN_ERR "failure at %s:%d/%s()!\n", + __FILE__, __LINE__, __func__); + return -EFAULT; + } + if (_ctl_verify_adapter(karg.hdr.ioc_number, &ioc) == -1 || !ioc) + return -ENODEV; + + if (state == NON_BLOCKING && !mutex_trylock(&ioc->ctl_cmds.mutex)) + return -EAGAIN; + else if (mutex_lock_interruptible(&ioc->ctl_cmds.mutex)) + return -ERESTARTSYS; + rc = _ctl_diag_register_2(ioc, &karg); mutex_unlock(&ioc->ctl_cmds.mutex); return rc; } @@ -1600,7 +1667,7 @@ _ctl_diag_query(void __user *arg) /** * _ctl_send_release - Diag Release Message * @ioc: per adapter object - * @buffer_type - specifies either TRACE or SNAPSHOT + * @buffer_type - specifies either TRACE, SNAPSHOT, or EXTENDED * @issue_reset - specifies whether host reset is required. * */ @@ -1690,7 +1757,7 @@ _ctl_send_release(struct MPT2SAS_ADAPTER *ioc, u8 buffer_type, u8 *issue_reset) } else { printk(MPT2SAS_DEBUG_FMT "%s: ioc_status(0x%04x) " "log_info(0x%08x)\n", ioc->name, __func__, - ioc_status, mpi_reply->IOCLogInfo); + ioc_status, le32_to_cpu(mpi_reply->IOCLogInfo)); rc = -EFAULT; } @@ -1951,7 +2018,7 @@ _ctl_diag_read_buffer(void __user *arg, enum block_state state) } else { printk(MPT2SAS_DEBUG_FMT "%s: ioc_status(0x%04x) " "log_info(0x%08x)\n", ioc->name, __func__, - ioc_status, mpi_reply->IOCLogInfo); + ioc_status, le32_to_cpu(mpi_reply->IOCLogInfo)); rc = -EFAULT; } @@ -2474,6 +2541,43 @@ _ctl_logging_level_store(struct device *cdev, struct device_attribute *attr, static DEVICE_ATTR(logging_level, S_IRUGO | S_IWUSR, _ctl_logging_level_show, _ctl_logging_level_store); +/* device attributes */ +/* + * _ctl_fwfault_debug_show - show/store fwfault_debug + * @cdev - pointer to embedded class device + * @buf - the buffer returned + * + * mpt2sas_fwfault_debug is command line option + * A sysfs 'read/write' shost attribute. + */ +static ssize_t +_ctl_fwfault_debug_show(struct device *cdev, + struct device_attribute *attr, char *buf) +{ + struct Scsi_Host *shost = class_to_shost(cdev); + struct MPT2SAS_ADAPTER *ioc = shost_priv(shost); + + return snprintf(buf, PAGE_SIZE, "%d\n", ioc->fwfault_debug); +} +static ssize_t +_ctl_fwfault_debug_store(struct device *cdev, + struct device_attribute *attr, const char *buf, size_t count) +{ + struct Scsi_Host *shost = class_to_shost(cdev); + struct MPT2SAS_ADAPTER *ioc = shost_priv(shost); + int val = 0; + + if (sscanf(buf, "%d", &val) != 1) + return -EINVAL; + + ioc->fwfault_debug = val; + printk(MPT2SAS_INFO_FMT "fwfault_debug=%d\n", ioc->name, + ioc->fwfault_debug); + return strlen(buf); +} +static DEVICE_ATTR(fwfault_debug, S_IRUGO | S_IWUSR, + _ctl_fwfault_debug_show, _ctl_fwfault_debug_store); + struct device_attribute *mpt2sas_host_attrs[] = { &dev_attr_version_fw, &dev_attr_version_bios, @@ -2487,13 +2591,12 @@ struct device_attribute *mpt2sas_host_attrs[] = { &dev_attr_io_delay, &dev_attr_device_delay, &dev_attr_logging_level, + &dev_attr_fwfault_debug, &dev_attr_fw_queue_depth, &dev_attr_host_sas_address, NULL, }; -/* device attributes */ - /** * _ctl_device_sas_address_show - sas address * @cdev - pointer to embedded class device diff --git a/drivers/scsi/mpt2sas/mpt2sas_ctl.h b/drivers/scsi/mpt2sas/mpt2sas_ctl.h index 211f296dd191..8a5eeb1a5c84 100644 --- a/drivers/scsi/mpt2sas/mpt2sas_ctl.h +++ b/drivers/scsi/mpt2sas/mpt2sas_ctl.h @@ -313,7 +313,7 @@ struct mpt2_ioctl_btdh_mapping { * struct mpt2_diag_register - application register with driver * @hdr - generic header * @reserved - - * @buffer_type - specifies either TRACE or SNAPSHOT + * @buffer_type - specifies either TRACE, SNAPSHOT, or EXTENDED * @application_flags - misc flags * @diagnostic_flags - specifies flags affecting command processing * @product_specific - product specific information @@ -352,7 +352,7 @@ struct mpt2_diag_unregister { * struct mpt2_diag_query - query relevant info associated with diag buffers * @hdr - generic header * @reserved - - * @buffer_type - specifies either TRACE or SNAPSHOT + * @buffer_type - specifies either TRACE, SNAPSHOT, or EXTENDED * @application_flags - misc flags * @diagnostic_flags - specifies flags affecting command processing * @product_specific - product specific information diff --git a/drivers/scsi/mpt2sas/mpt2sas_scsih.c b/drivers/scsi/mpt2sas/mpt2sas_scsih.c index 756e509d495c..efabea1a3ce4 100644 --- a/drivers/scsi/mpt2sas/mpt2sas_scsih.c +++ b/drivers/scsi/mpt2sas/mpt2sas_scsih.c @@ -76,6 +76,7 @@ static u8 tm_cb_idx = -1; static u8 ctl_cb_idx = -1; static u8 base_cb_idx = -1; static u8 transport_cb_idx = -1; +static u8 scsih_cb_idx = -1; static u8 config_cb_idx = -1; static int mpt_ids; @@ -196,10 +197,28 @@ static struct pci_device_id scsih_pci_table[] = { PCI_ANY_ID, PCI_ANY_ID }, { MPI2_MFGPAGE_VENDORID_LSI, MPI2_MFGPAGE_DEVID_SAS2108_3, PCI_ANY_ID, PCI_ANY_ID }, + /* Meteor ~ 2116 */ { MPI2_MFGPAGE_VENDORID_LSI, MPI2_MFGPAGE_DEVID_SAS2116_1, PCI_ANY_ID, PCI_ANY_ID }, { MPI2_MFGPAGE_VENDORID_LSI, MPI2_MFGPAGE_DEVID_SAS2116_2, PCI_ANY_ID, PCI_ANY_ID }, + /* Thunderbolt ~ 2208 */ + { MPI2_MFGPAGE_VENDORID_LSI, MPI2_MFGPAGE_DEVID_SAS2208_1, + PCI_ANY_ID, PCI_ANY_ID }, + { MPI2_MFGPAGE_VENDORID_LSI, MPI2_MFGPAGE_DEVID_SAS2208_2, + PCI_ANY_ID, PCI_ANY_ID }, + { MPI2_MFGPAGE_VENDORID_LSI, MPI2_MFGPAGE_DEVID_SAS2208_3, + PCI_ANY_ID, PCI_ANY_ID }, + { MPI2_MFGPAGE_VENDORID_LSI, MPI2_MFGPAGE_DEVID_SAS2208_4, + PCI_ANY_ID, PCI_ANY_ID }, + { MPI2_MFGPAGE_VENDORID_LSI, MPI2_MFGPAGE_DEVID_SAS2208_5, + PCI_ANY_ID, PCI_ANY_ID }, + { MPI2_MFGPAGE_VENDORID_LSI, MPI2_MFGPAGE_DEVID_SAS2208_6, + PCI_ANY_ID, PCI_ANY_ID }, + { MPI2_MFGPAGE_VENDORID_LSI, MPI2_MFGPAGE_DEVID_SAS2208_7, + PCI_ANY_ID, PCI_ANY_ID }, + { MPI2_MFGPAGE_VENDORID_LSI, MPI2_MFGPAGE_DEVID_SAS2208_8, + PCI_ANY_ID, PCI_ANY_ID }, {0} /* Terminating entry */ }; MODULE_DEVICE_TABLE(pci, scsih_pci_table); @@ -317,6 +336,47 @@ _scsih_is_boot_device(u64 sas_address, u64 device_name, } /** + * _scsih_get_sas_address - set the sas_address for given device handle + * @handle: device handle + * @sas_address: sas address + * + * Returns 0 success, non-zero when failure + */ +static int +_scsih_get_sas_address(struct MPT2SAS_ADAPTER *ioc, u16 handle, + u64 *sas_address) +{ + Mpi2SasDevicePage0_t sas_device_pg0; + Mpi2ConfigReply_t mpi_reply; + u32 ioc_status; + + if (handle <= ioc->sas_hba.num_phys) { + *sas_address = ioc->sas_hba.sas_address; + return 0; + } else + *sas_address = 0; + + if ((mpt2sas_config_get_sas_device_pg0(ioc, &mpi_reply, &sas_device_pg0, + MPI2_SAS_DEVICE_PGAD_FORM_HANDLE, handle))) { + printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n", + ioc->name, __FILE__, __LINE__, __func__); + return -ENXIO; + } + + ioc_status = le16_to_cpu(mpi_reply.IOCStatus) & + MPI2_IOCSTATUS_MASK; + if (ioc_status != MPI2_IOCSTATUS_SUCCESS) { + printk(MPT2SAS_ERR_FMT "handle(0x%04x), ioc_status(0x%04x)" + "\nfailure at %s:%d/%s()!\n", ioc->name, handle, ioc_status, + __FILE__, __LINE__, __func__); + return -EIO; + } + + *sas_address = le64_to_cpu(sas_device_pg0.SASAddress); + return 0; +} + +/** * _scsih_determine_boot_device - determine boot device. * @ioc: per adapter object * @device: either sas_device or raid_device object @@ -510,8 +570,6 @@ _scsih_sas_device_add(struct MPT2SAS_ADAPTER *ioc, struct _sas_device *sas_device) { unsigned long flags; - u16 handle, parent_handle; - u64 sas_address; dewtprintk(ioc, printk(MPT2SAS_DEBUG_FMT "%s: handle" "(0x%04x), sas_addr(0x%016llx)\n", ioc->name, __func__, @@ -521,10 +579,8 @@ _scsih_sas_device_add(struct MPT2SAS_ADAPTER *ioc, list_add_tail(&sas_device->list, &ioc->sas_device_list); spin_unlock_irqrestore(&ioc->sas_device_lock, flags); - handle = sas_device->handle; - parent_handle = sas_device->parent_handle; - sas_address = sas_device->sas_address; - if (!mpt2sas_transport_port_add(ioc, handle, parent_handle)) + if (!mpt2sas_transport_port_add(ioc, sas_device->handle, + sas_device->sas_address_parent)) _scsih_sas_device_remove(ioc, sas_device); } @@ -553,31 +609,6 @@ _scsih_sas_device_init_add(struct MPT2SAS_ADAPTER *ioc, } /** - * mpt2sas_scsih_expander_find_by_handle - expander device search - * @ioc: per adapter object - * @handle: expander handle (assigned by firmware) - * Context: Calling function should acquire ioc->sas_device_lock - * - * This searches for expander device based on handle, then returns the - * sas_node object. - */ -struct _sas_node * -mpt2sas_scsih_expander_find_by_handle(struct MPT2SAS_ADAPTER *ioc, u16 handle) -{ - struct _sas_node *sas_expander, *r; - - r = NULL; - list_for_each_entry(sas_expander, &ioc->sas_expander_list, list) { - if (sas_expander->handle != handle) - continue; - r = sas_expander; - goto out; - } - out: - return r; -} - -/** * _scsih_raid_device_find_by_id - raid device search * @ioc: per adapter object * @id: sas device target id @@ -699,6 +730,31 @@ _scsih_raid_device_remove(struct MPT2SAS_ADAPTER *ioc, } /** + * mpt2sas_scsih_expander_find_by_handle - expander device search + * @ioc: per adapter object + * @handle: expander handle (assigned by firmware) + * Context: Calling function should acquire ioc->sas_device_lock + * + * This searches for expander device based on handle, then returns the + * sas_node object. + */ +struct _sas_node * +mpt2sas_scsih_expander_find_by_handle(struct MPT2SAS_ADAPTER *ioc, u16 handle) +{ + struct _sas_node *sas_expander, *r; + + r = NULL; + list_for_each_entry(sas_expander, &ioc->sas_expander_list, list) { + if (sas_expander->handle != handle) + continue; + r = sas_expander; + goto out; + } + out: + return r; +} + +/** * mpt2sas_scsih_expander_find_by_sas_address - expander device search * @ioc: per adapter object * @sas_address: sas address @@ -1043,17 +1099,46 @@ _scsih_build_scatter_gather(struct MPT2SAS_ADAPTER *ioc, * _scsih_change_queue_depth - setting device queue depth * @sdev: scsi device struct * @qdepth: requested queue depth + * @reason: calling context * * Returns queue depth. */ static int -_scsih_change_queue_depth(struct scsi_device *sdev, int qdepth) +_scsih_change_queue_depth(struct scsi_device *sdev, int qdepth, int reason) { struct Scsi_Host *shost = sdev->host; int max_depth; int tag_type; + struct MPT2SAS_ADAPTER *ioc = shost_priv(shost); + struct MPT2SAS_DEVICE *sas_device_priv_data; + struct MPT2SAS_TARGET *sas_target_priv_data; + struct _sas_device *sas_device; + unsigned long flags; + + if (reason != SCSI_QDEPTH_DEFAULT) + return -EOPNOTSUPP; max_depth = shost->can_queue; + + /* limit max device queue for SATA to 32 */ + sas_device_priv_data = sdev->hostdata; + if (!sas_device_priv_data) + goto not_sata; + sas_target_priv_data = sas_device_priv_data->sas_target; + if (!sas_target_priv_data) + goto not_sata; + if ((sas_target_priv_data->flags & MPT_TARGET_FLAGS_VOLUME)) + goto not_sata; + spin_lock_irqsave(&ioc->sas_device_lock, flags); + sas_device = mpt2sas_scsih_sas_device_find_by_sas_address(ioc, + sas_device_priv_data->sas_target->sas_address); + spin_unlock_irqrestore(&ioc->sas_device_lock, flags); + if (sas_device && sas_device->device_info & + MPI2_SAS_DEVICE_INFO_SATA_DEVICE) + max_depth = MPT2SAS_SATA_QUEUE_DEPTH; + + not_sata: + if (!sdev->tagged_supported) max_depth = 1; if (qdepth > max_depth) @@ -1488,7 +1573,7 @@ _scsih_slave_configure(struct scsi_device *sdev) r_level, raid_device->handle, (unsigned long long)raid_device->wwid, raid_device->num_pds, ds); - _scsih_change_queue_depth(sdev, qdepth); + _scsih_change_queue_depth(sdev, qdepth, SCSI_QDEPTH_DEFAULT); return 0; } @@ -1534,7 +1619,7 @@ _scsih_slave_configure(struct scsi_device *sdev) _scsih_display_sata_capabilities(ioc, sas_device, sdev); } - _scsih_change_queue_depth(sdev, qdepth); + _scsih_change_queue_depth(sdev, qdepth, SCSI_QDEPTH_DEFAULT); if (ssp_target) sas_read_port_mode_page(sdev); @@ -1874,6 +1959,8 @@ _scsih_abort(struct scsi_cmnd *scmd) goto out; } + mpt2sas_halt_firmware(ioc); + mutex_lock(&ioc->tm_cmds.mutex); handle = sas_device_priv_data->sas_target->handle; mpt2sas_scsih_issue_tm(ioc, handle, sas_device_priv_data->lun, @@ -2297,7 +2384,6 @@ _scsih_block_io_to_children_attached_directly(struct MPT2SAS_ADAPTER *ioc, u16 handle; u16 reason_code; u8 phy_number; - u8 link_rate; for (i = 0; i < event_data->NumEntries; i++) { handle = le16_to_cpu(event_data->PHY[i].AttachedDevHandle); @@ -2308,11 +2394,6 @@ _scsih_block_io_to_children_attached_directly(struct MPT2SAS_ADAPTER *ioc, MPI2_EVENT_SAS_TOPO_RC_MASK; if (reason_code == MPI2_EVENT_SAS_TOPO_RC_DELAY_NOT_RESPONDING) _scsih_block_io_device(ioc, handle); - if (reason_code == MPI2_EVENT_SAS_TOPO_RC_PHY_CHANGED) { - link_rate = event_data->PHY[i].LinkRate >> 4; - if (link_rate >= MPI2_SAS_NEG_LINK_RATE_1_5) - _scsih_ublock_io_device(ioc, handle); - } } } @@ -2349,16 +2430,10 @@ _scsih_tm_tr_send(struct MPT2SAS_ADAPTER *ioc, u16 handle) spin_lock_irqsave(&ioc->sas_device_lock, flags); sas_device = _scsih_sas_device_find_by_handle(ioc, handle); - if (!sas_device) { - spin_unlock_irqrestore(&ioc->sas_device_lock, flags); - printk(MPT2SAS_ERR_FMT "%s: failed finding sas_device\n", - ioc->name, __func__); - return; - } spin_unlock_irqrestore(&ioc->sas_device_lock, flags); /* skip is hidden raid component */ - if (sas_device->hidden_raid_component) + if (sas_device && sas_device->hidden_raid_component) return; smid = mpt2sas_base_get_smid_hpr(ioc, ioc->tm_tr_cb_idx); @@ -2371,18 +2446,31 @@ _scsih_tm_tr_send(struct MPT2SAS_ADAPTER *ioc, u16 handle) delayed_tr->state = MPT2SAS_REQ_SAS_CNTRL; list_add_tail(&delayed_tr->list, &ioc->delayed_tr_list); - if (sas_device->starget) + if (sas_device && sas_device->starget) { dewtprintk(ioc, starget_printk(KERN_INFO, sas_device->starget, "DELAYED:tr:handle(0x%04x), " - "(open)\n", sas_device->handle)); + "(open)\n", handle)); + } else { + dewtprintk(ioc, printk(MPT2SAS_INFO_FMT + "DELAYED:tr:handle(0x%04x), (open)\n", + ioc->name, handle)); + } return; } - if (sas_device->starget && sas_device->starget->hostdata) { - sas_target_priv_data = sas_device->starget->hostdata; - sas_target_priv_data->tm_busy = 1; - dewtprintk(ioc, starget_printk(KERN_INFO, sas_device->starget, - "tr:handle(0x%04x), (open)\n", sas_device->handle)); + if (sas_device) { + sas_device->state |= MPTSAS_STATE_TR_SEND; + sas_device->state |= MPT2SAS_REQ_SAS_CNTRL; + if (sas_device->starget && sas_device->starget->hostdata) { + sas_target_priv_data = sas_device->starget->hostdata; + sas_target_priv_data->tm_busy = 1; + dewtprintk(ioc, starget_printk(KERN_INFO, + sas_device->starget, "tr:handle(0x%04x), (open)\n", + handle)); + } + } else { + dewtprintk(ioc, printk(MPT2SAS_INFO_FMT + "tr:handle(0x%04x), (open)\n", ioc->name, handle)); } mpi_request = mpt2sas_base_get_msg_frame(ioc, smid); @@ -2390,8 +2478,6 @@ _scsih_tm_tr_send(struct MPT2SAS_ADAPTER *ioc, u16 handle) mpi_request->Function = MPI2_FUNCTION_SCSI_TASK_MGMT; mpi_request->DevHandle = cpu_to_le16(handle); mpi_request->TaskType = MPI2_SCSITASKMGMT_TASKTYPE_TARGET_RESET; - sas_device->state |= MPTSAS_STATE_TR_SEND; - sas_device->state |= MPT2SAS_REQ_SAS_CNTRL; mpt2sas_base_put_smid_hi_priority(ioc, smid); } @@ -2426,21 +2512,25 @@ _scsih_sas_control_complete(struct MPT2SAS_ADAPTER *ioc, u16 smid, spin_lock_irqsave(&ioc->sas_device_lock, flags); sas_device = _scsih_sas_device_find_by_handle(ioc, handle); - if (!sas_device) { - spin_unlock_irqrestore(&ioc->sas_device_lock, flags); - printk(MPT2SAS_ERR_FMT "%s: failed finding sas_device\n", - ioc->name, __func__); - return 1; - } - sas_device->state |= MPTSAS_STATE_CNTRL_COMPLETE; spin_unlock_irqrestore(&ioc->sas_device_lock, flags); - if (sas_device->starget) - dewtprintk(ioc, starget_printk(KERN_INFO, sas_device->starget, + if (sas_device) { + sas_device->state |= MPTSAS_STATE_CNTRL_COMPLETE; + if (sas_device->starget) + dewtprintk(ioc, starget_printk(KERN_INFO, + sas_device->starget, + "sc_complete:handle(0x%04x), " + "ioc_status(0x%04x), loginfo(0x%08x)\n", + handle, le16_to_cpu(mpi_reply->IOCStatus), + le32_to_cpu(mpi_reply->IOCLogInfo))); + } else { + dewtprintk(ioc, printk(MPT2SAS_INFO_FMT "sc_complete:handle(0x%04x), " "ioc_status(0x%04x), loginfo(0x%08x)\n", - handle, le16_to_cpu(mpi_reply->IOCStatus), + ioc->name, handle, le16_to_cpu(mpi_reply->IOCStatus), le32_to_cpu(mpi_reply->IOCLogInfo))); + } + return 1; } @@ -2478,28 +2568,33 @@ _scsih_tm_tr_complete(struct MPT2SAS_ADAPTER *ioc, u16 smid, u8 msix_index, handle = le16_to_cpu(mpi_reply->DevHandle); spin_lock_irqsave(&ioc->sas_device_lock, flags); sas_device = _scsih_sas_device_find_by_handle(ioc, handle); - if (!sas_device) { - spin_unlock_irqrestore(&ioc->sas_device_lock, flags); - printk(MPT2SAS_ERR_FMT "%s: failed finding sas_device\n", - ioc->name, __func__); - return 1; - } - sas_device->state |= MPTSAS_STATE_TR_COMPLETE; spin_unlock_irqrestore(&ioc->sas_device_lock, flags); - if (sas_device->starget) - dewtprintk(ioc, starget_printk(KERN_INFO, sas_device->starget, - "tr_complete:handle(0x%04x), (%s) ioc_status(0x%04x), " - "loginfo(0x%08x), completed(%d)\n", - sas_device->handle, (sas_device->state & - MPT2SAS_REQ_SAS_CNTRL) ? "open" : "active", - le16_to_cpu(mpi_reply->IOCStatus), + if (sas_device) { + sas_device->state |= MPTSAS_STATE_TR_COMPLETE; + if (sas_device->starget) { + dewtprintk(ioc, starget_printk(KERN_INFO, + sas_device->starget, "tr_complete:handle(0x%04x), " + "(%s) ioc_status(0x%04x), loginfo(0x%08x), " + "completed(%d)\n", sas_device->handle, + (sas_device->state & MPT2SAS_REQ_SAS_CNTRL) ? + "open" : "active", + le16_to_cpu(mpi_reply->IOCStatus), + le32_to_cpu(mpi_reply->IOCLogInfo), + le32_to_cpu(mpi_reply->TerminationCount))); + if (sas_device->starget->hostdata) { + sas_target_priv_data = + sas_device->starget->hostdata; + sas_target_priv_data->tm_busy = 0; + } + } + } else { + dewtprintk(ioc, printk(MPT2SAS_INFO_FMT + "tr_complete:handle(0x%04x), (open) ioc_status(0x%04x), " + "loginfo(0x%08x), completed(%d)\n", ioc->name, + handle, le16_to_cpu(mpi_reply->IOCStatus), le32_to_cpu(mpi_reply->IOCLogInfo), le32_to_cpu(mpi_reply->TerminationCount))); - - if (sas_device->starget && sas_device->starget->hostdata) { - sas_target_priv_data = sas_device->starget->hostdata; - sas_target_priv_data->tm_busy = 0; } if (!list_empty(&ioc->delayed_tr_list)) { @@ -2514,8 +2609,7 @@ _scsih_tm_tr_complete(struct MPT2SAS_ADAPTER *ioc, u16 smid, u8 msix_index, } else rc = 1; - - if (!(sas_device->state & MPT2SAS_REQ_SAS_CNTRL)) + if (sas_device && !(sas_device->state & MPT2SAS_REQ_SAS_CNTRL)) return rc; if (ioc->shost_recovery) { @@ -2531,12 +2625,14 @@ _scsih_tm_tr_complete(struct MPT2SAS_ADAPTER *ioc, u16 smid, u8 msix_index, return rc; } + if (sas_device) + sas_device->state |= MPTSAS_STATE_CNTRL_SEND; + mpi_request = mpt2sas_base_get_msg_frame(ioc, smid_sas_ctrl); memset(mpi_request, 0, sizeof(Mpi2SasIoUnitControlRequest_t)); mpi_request->Function = MPI2_FUNCTION_SAS_IO_UNIT_CONTROL; mpi_request->Operation = MPI2_SAS_OP_REMOVE_DEVICE; mpi_request->DevHandle = mpi_reply->DevHandle; - sas_device->state |= MPTSAS_STATE_CNTRL_SEND; mpt2sas_base_put_smid_default(ioc, smid_sas_ctrl); return rc; } @@ -2678,8 +2774,6 @@ _scsih_setup_eedp(struct scsi_cmnd *scmd, Mpi2SCSIIORequest_t *mpi_request) else return; - mpi_request->EEDPBlockSize = scmd->device->sector_size; - switch (prot_type) { case SCSI_PROT_DIF_TYPE1: @@ -2687,8 +2781,7 @@ _scsih_setup_eedp(struct scsi_cmnd *scmd, Mpi2SCSIIORequest_t *mpi_request) * enable ref/guard checking * auto increment ref tag */ - mpi_request->EEDPFlags = eedp_flags | - MPI2_SCSIIO_EEDPFLAGS_INC_PRI_REFTAG | + eedp_flags |= MPI2_SCSIIO_EEDPFLAGS_INC_PRI_REFTAG | MPI2_SCSIIO_EEDPFLAGS_CHECK_REFTAG | MPI2_SCSIIO_EEDPFLAGS_CHECK_GUARD; mpi_request->CDB.EEDP32.PrimaryReferenceTag = @@ -2701,11 +2794,11 @@ _scsih_setup_eedp(struct scsi_cmnd *scmd, Mpi2SCSIIORequest_t *mpi_request) /* * enable guard checking */ - mpi_request->EEDPFlags = eedp_flags | - MPI2_SCSIIO_EEDPFLAGS_CHECK_GUARD; - + eedp_flags |= MPI2_SCSIIO_EEDPFLAGS_CHECK_GUARD; break; } + mpi_request->EEDPBlockSize = cpu_to_le32(scmd->device->sector_size); + mpi_request->EEDPFlags = cpu_to_le16(eedp_flags); } /** @@ -2788,7 +2881,7 @@ _scsih_qcmd(struct scsi_cmnd *scmd, void (*done)(struct scsi_cmnd *)) } /* see if we are busy with task managment stuff */ - if (sas_target_priv_data->tm_busy) + if (sas_device_priv_data->block || sas_target_priv_data->tm_busy) return SCSI_MLQUEUE_DEVICE_BUSY; else if (ioc->shost_recovery || ioc->ioc_link_reset_in_progress) return SCSI_MLQUEUE_HOST_BUSY; @@ -2842,7 +2935,7 @@ _scsih_qcmd(struct scsi_cmnd *scmd, void (*done)(struct scsi_cmnd *)) mpi_request->MsgFlags = MPI2_SCSIIO_MSGFLAGS_SYSTEM_SENSE_ADDR; mpi_request->SenseBufferLength = SCSI_SENSE_BUFFERSIZE; mpi_request->SenseBufferLowAddress = - (u32)mpt2sas_base_get_sense_buffer_dma(ioc, smid); + mpt2sas_base_get_sense_buffer_dma(ioc, smid); mpi_request->SGLOffset0 = offsetof(Mpi2SCSIIORequest_t, SGL) / 4; mpi_request->SGLFlags = cpu_to_le16(MPI2_SCSIIO_SGLFLAGS_TYPE_MPI + MPI2_SCSIIO_SGLFLAGS_SYSTEM_ADDR); @@ -3059,7 +3152,7 @@ _scsih_scsi_ioc_info(struct MPT2SAS_ADAPTER *ioc, struct scsi_cmnd *scmd, if (scsi_state & MPI2_SCSI_STATE_RESPONSE_INFO_VALID) { response_info = le32_to_cpu(mpi_reply->ResponseInfo); response_bytes = (u8 *)&response_info; - _scsih_response_code(ioc, response_bytes[3]); + _scsih_response_code(ioc, response_bytes[0]); } } #endif @@ -3177,7 +3270,7 @@ _scsih_io_done(struct MPT2SAS_ADAPTER *ioc, u16 smid, u8 msix_index, u32 reply) u8 scsi_status; u32 log_info; struct MPT2SAS_DEVICE *sas_device_priv_data; - u32 response_code; + u32 response_code = 0; mpi_reply = mpt2sas_base_get_reply_virt_addr(ioc, reply); scmd = _scsih_scsi_lookup_get(ioc, smid); @@ -3199,16 +3292,16 @@ _scsih_io_done(struct MPT2SAS_ADAPTER *ioc, u16 smid, u8 msix_index, u32 reply) } /* turning off TLR */ + scsi_state = mpi_reply->SCSIState; + if (scsi_state & MPI2_SCSI_STATE_RESPONSE_INFO_VALID) + response_code = + le32_to_cpu(mpi_reply->ResponseInfo) & 0xFF; if (!sas_device_priv_data->tlr_snoop_check) { sas_device_priv_data->tlr_snoop_check++; - if (sas_device_priv_data->flags & MPT_DEVICE_TLR_ON) { - response_code = (le32_to_cpu(mpi_reply->ResponseInfo) - >> 24); - if (response_code == - MPI2_SCSITASKMGMT_RSP_INVALID_FRAME) - sas_device_priv_data->flags &= - ~MPT_DEVICE_TLR_ON; - } + if ((sas_device_priv_data->flags & MPT_DEVICE_TLR_ON) && + response_code == MPI2_SCSITASKMGMT_RSP_INVALID_FRAME) + sas_device_priv_data->flags &= + ~MPT_DEVICE_TLR_ON; } xfer_cnt = le32_to_cpu(mpi_reply->TransferCount); @@ -3219,7 +3312,6 @@ _scsih_io_done(struct MPT2SAS_ADAPTER *ioc, u16 smid, u8 msix_index, u32 reply) else log_info = 0; ioc_status &= MPI2_IOCSTATUS_MASK; - scsi_state = mpi_reply->SCSIState; scsi_status = mpi_reply->SCSIStatus; if (ioc_status == MPI2_IOCSTATUS_SCSI_DATA_UNDERRUN && xfer_cnt == 0 && @@ -3255,10 +3347,9 @@ _scsih_io_done(struct MPT2SAS_ADAPTER *ioc, u16 smid, u8 msix_index, u32 reply) case MPI2_IOCSTATUS_SCSI_IOC_TERMINATED: if (sas_device_priv_data->block) { - scmd->result = (DID_BUS_BUSY << 16); - break; + scmd->result = DID_TRANSPORT_DISRUPTED << 16; + goto out; } - case MPI2_IOCSTATUS_SCSI_TASK_TERMINATED: case MPI2_IOCSTATUS_SCSI_EXT_TERMINATED: scmd->result = DID_RESET << 16; @@ -3304,8 +3395,10 @@ _scsih_io_done(struct MPT2SAS_ADAPTER *ioc, u16 smid, u8 msix_index, u32 reply) case MPI2_IOCSTATUS_SCSI_RECOVERED_ERROR: case MPI2_IOCSTATUS_SUCCESS: scmd->result = (DID_OK << 16) | scsi_status; - if (scsi_state & (MPI2_SCSI_STATE_AUTOSENSE_FAILED | - MPI2_SCSI_STATE_NO_SCSI_STATUS)) + if (response_code == + MPI2_SCSITASKMGMT_RSP_INVALID_FRAME || + (scsi_state & (MPI2_SCSI_STATE_AUTOSENSE_FAILED | + MPI2_SCSI_STATE_NO_SCSI_STATUS))) scmd->result = DID_SOFT_ERROR << 16; else if (scsi_state & MPI2_SCSI_STATE_TERMINATED) scmd->result = DID_RESET << 16; @@ -3344,7 +3437,6 @@ _scsih_io_done(struct MPT2SAS_ADAPTER *ioc, u16 smid, u8 msix_index, u32 reply) /** * _scsih_sas_host_refresh - refreshing sas host object contents * @ioc: per adapter object - * @update: update link information * Context: user * * During port enable, fw will send topology events for every device. Its @@ -3354,13 +3446,14 @@ _scsih_io_done(struct MPT2SAS_ADAPTER *ioc, u16 smid, u8 msix_index, u32 reply) * Return nothing. */ static void -_scsih_sas_host_refresh(struct MPT2SAS_ADAPTER *ioc, u8 update) +_scsih_sas_host_refresh(struct MPT2SAS_ADAPTER *ioc) { u16 sz; u16 ioc_status; int i; Mpi2ConfigReply_t mpi_reply; Mpi2SasIOUnitPage0_t *sas_iounit_pg0 = NULL; + u16 attached_handle; dtmprintk(ioc, printk(MPT2SAS_INFO_FMT "updating handles for sas_host(0x%016llx)\n", @@ -3374,27 +3467,24 @@ _scsih_sas_host_refresh(struct MPT2SAS_ADAPTER *ioc, u8 update) ioc->name, __FILE__, __LINE__, __func__); return; } - if (!(mpt2sas_config_get_sas_iounit_pg0(ioc, &mpi_reply, - sas_iounit_pg0, sz))) { - ioc_status = le16_to_cpu(mpi_reply.IOCStatus) & - MPI2_IOCSTATUS_MASK; - if (ioc_status != MPI2_IOCSTATUS_SUCCESS) - goto out; - for (i = 0; i < ioc->sas_hba.num_phys ; i++) { - ioc->sas_hba.phy[i].handle = - le16_to_cpu(sas_iounit_pg0->PhyData[i]. - ControllerDevHandle); - if (update) - mpt2sas_transport_update_links( - ioc, - ioc->sas_hba.phy[i].handle, - le16_to_cpu(sas_iounit_pg0->PhyData[i]. - AttachedDevHandle), i, - sas_iounit_pg0->PhyData[i]. - NegotiatedLinkRate >> 4); - } - } + if ((mpt2sas_config_get_sas_iounit_pg0(ioc, &mpi_reply, + sas_iounit_pg0, sz)) != 0) + goto out; + ioc_status = le16_to_cpu(mpi_reply.IOCStatus) & MPI2_IOCSTATUS_MASK; + if (ioc_status != MPI2_IOCSTATUS_SUCCESS) + goto out; + for (i = 0; i < ioc->sas_hba.num_phys ; i++) { + if (i == 0) + ioc->sas_hba.handle = le16_to_cpu(sas_iounit_pg0-> + PhyData[0].ControllerDevHandle); + ioc->sas_hba.phy[i].handle = ioc->sas_hba.handle; + attached_handle = le16_to_cpu(sas_iounit_pg0->PhyData[i]. + AttachedDevHandle); + mpt2sas_transport_update_links(ioc, ioc->sas_hba.sas_address, + attached_handle, i, sas_iounit_pg0->PhyData[i]. + NegotiatedLinkRate >> 4); + } out: kfree(sas_iounit_pg0); } @@ -3507,19 +3597,21 @@ _scsih_sas_host_add(struct MPT2SAS_ADAPTER *ioc) ioc->name, __FILE__, __LINE__, __func__); goto out; } - ioc->sas_hba.phy[i].handle = - le16_to_cpu(sas_iounit_pg0->PhyData[i].ControllerDevHandle); + + if (i == 0) + ioc->sas_hba.handle = le16_to_cpu(sas_iounit_pg0-> + PhyData[0].ControllerDevHandle); + ioc->sas_hba.phy[i].handle = ioc->sas_hba.handle; ioc->sas_hba.phy[i].phy_id = i; mpt2sas_transport_add_host_phy(ioc, &ioc->sas_hba.phy[i], phy_pg0, ioc->sas_hba.parent_dev); } if ((mpt2sas_config_get_sas_device_pg0(ioc, &mpi_reply, &sas_device_pg0, - MPI2_SAS_DEVICE_PGAD_FORM_HANDLE, ioc->sas_hba.phy[0].handle))) { + MPI2_SAS_DEVICE_PGAD_FORM_HANDLE, ioc->sas_hba.handle))) { printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n", ioc->name, __FILE__, __LINE__, __func__); goto out; } - ioc->sas_hba.handle = le16_to_cpu(sas_device_pg0.DevHandle); ioc->sas_hba.enclosure_handle = le16_to_cpu(sas_device_pg0.EnclosureHandle); ioc->sas_hba.sas_address = le64_to_cpu(sas_device_pg0.SASAddress); @@ -3562,7 +3654,7 @@ _scsih_expander_add(struct MPT2SAS_ADAPTER *ioc, u16 handle) Mpi2SasEnclosurePage0_t enclosure_pg0; u32 ioc_status; u16 parent_handle; - __le64 sas_address; + __le64 sas_address, sas_address_parent = 0; int i; unsigned long flags; struct _sas_port *mpt2sas_port = NULL; @@ -3591,10 +3683,16 @@ _scsih_expander_add(struct MPT2SAS_ADAPTER *ioc, u16 handle) /* handle out of order topology events */ parent_handle = le16_to_cpu(expander_pg0.ParentDevHandle); - if (parent_handle >= ioc->sas_hba.num_phys) { + if (_scsih_get_sas_address(ioc, parent_handle, &sas_address_parent) + != 0) { + printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n", + ioc->name, __FILE__, __LINE__, __func__); + return -1; + } + if (sas_address_parent != ioc->sas_hba.sas_address) { spin_lock_irqsave(&ioc->sas_node_lock, flags); - sas_expander = mpt2sas_scsih_expander_find_by_handle(ioc, - parent_handle); + sas_expander = mpt2sas_scsih_expander_find_by_sas_address(ioc, + sas_address_parent); spin_unlock_irqrestore(&ioc->sas_node_lock, flags); if (!sas_expander) { rc = _scsih_expander_add(ioc, parent_handle); @@ -3622,14 +3720,12 @@ _scsih_expander_add(struct MPT2SAS_ADAPTER *ioc, u16 handle) sas_expander->handle = handle; sas_expander->num_phys = expander_pg0.NumPhys; - sas_expander->parent_handle = parent_handle; - sas_expander->enclosure_handle = - le16_to_cpu(expander_pg0.EnclosureHandle); + sas_expander->sas_address_parent = sas_address_parent; sas_expander->sas_address = sas_address; printk(MPT2SAS_INFO_FMT "expander_add: handle(0x%04x)," " parent(0x%04x), sas_addr(0x%016llx), phys(%d)\n", ioc->name, - handle, sas_expander->parent_handle, (unsigned long long) + handle, parent_handle, (unsigned long long) sas_expander->sas_address, sas_expander->num_phys); if (!sas_expander->num_phys) @@ -3645,7 +3741,7 @@ _scsih_expander_add(struct MPT2SAS_ADAPTER *ioc, u16 handle) INIT_LIST_HEAD(&sas_expander->sas_port_list); mpt2sas_port = mpt2sas_transport_port_add(ioc, handle, - sas_expander->parent_handle); + sas_address_parent); if (!mpt2sas_port) { printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n", ioc->name, __FILE__, __LINE__, __func__); @@ -3691,20 +3787,54 @@ _scsih_expander_add(struct MPT2SAS_ADAPTER *ioc, u16 handle) if (mpt2sas_port) mpt2sas_transport_port_remove(ioc, sas_expander->sas_address, - sas_expander->parent_handle); + sas_address_parent); kfree(sas_expander); return rc; } /** + * _scsih_done - scsih callback handler. + * @ioc: per adapter object + * @smid: system request message index + * @msix_index: MSIX table index supplied by the OS + * @reply: reply message frame(lower 32bit addr) + * + * Callback handler when sending internal generated message frames. + * The callback index passed is `ioc->scsih_cb_idx` + * + * Return 1 meaning mf should be freed from _base_interrupt + * 0 means the mf is freed from this function. + */ +static u8 +_scsih_done(struct MPT2SAS_ADAPTER *ioc, u16 smid, u8 msix_index, u32 reply) +{ + MPI2DefaultReply_t *mpi_reply; + + mpi_reply = mpt2sas_base_get_reply_virt_addr(ioc, reply); + if (ioc->scsih_cmds.status == MPT2_CMD_NOT_USED) + return 1; + if (ioc->scsih_cmds.smid != smid) + return 1; + ioc->scsih_cmds.status |= MPT2_CMD_COMPLETE; + if (mpi_reply) { + memcpy(ioc->scsih_cmds.reply, mpi_reply, + mpi_reply->MsgLength*4); + ioc->scsih_cmds.status |= MPT2_CMD_REPLY_VALID; + } + ioc->scsih_cmds.status &= ~MPT2_CMD_PENDING; + complete(&ioc->scsih_cmds.done); + return 1; +} + +/** * _scsih_expander_remove - removing expander object * @ioc: per adapter object - * @handle: expander handle + * @sas_address: expander sas_address * * Return nothing. */ static void -_scsih_expander_remove(struct MPT2SAS_ADAPTER *ioc, u16 handle) +_scsih_expander_remove(struct MPT2SAS_ADAPTER *ioc, u64 sas_address) { struct _sas_node *sas_expander; unsigned long flags; @@ -3713,7 +3843,8 @@ _scsih_expander_remove(struct MPT2SAS_ADAPTER *ioc, u16 handle) return; spin_lock_irqsave(&ioc->sas_node_lock, flags); - sas_expander = mpt2sas_scsih_expander_find_by_handle(ioc, handle); + sas_expander = mpt2sas_scsih_expander_find_by_sas_address(ioc, + sas_address); spin_unlock_irqrestore(&ioc->sas_node_lock, flags); _scsih_expander_node_remove(ioc, sas_expander); } @@ -3805,8 +3936,11 @@ _scsih_add_device(struct MPT2SAS_ADAPTER *ioc, u16 handle, u8 phy_num, u8 is_pd) } sas_device->handle = handle; - sas_device->parent_handle = - le16_to_cpu(sas_device_pg0.ParentDevHandle); + if (_scsih_get_sas_address(ioc, le16_to_cpu + (sas_device_pg0.ParentDevHandle), + &sas_device->sas_address_parent) != 0) + printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n", + ioc->name, __FILE__, __LINE__, __func__); sas_device->enclosure_handle = le16_to_cpu(sas_device_pg0.EnclosureHandle); sas_device->slot = @@ -3836,43 +3970,39 @@ _scsih_add_device(struct MPT2SAS_ADAPTER *ioc, u16 handle, u8 phy_num, u8 is_pd) /** * _scsih_remove_device - removing sas device object * @ioc: per adapter object - * @handle: sas device handle + * @sas_device: the sas_device object * * Return nothing. */ static void -_scsih_remove_device(struct MPT2SAS_ADAPTER *ioc, u16 handle) +_scsih_remove_device(struct MPT2SAS_ADAPTER *ioc, struct _sas_device + *sas_device) { struct MPT2SAS_TARGET *sas_target_priv_data; - struct _sas_device *sas_device; - unsigned long flags; Mpi2SasIoUnitControlReply_t mpi_reply; Mpi2SasIoUnitControlRequest_t mpi_request; - u16 device_handle; + u16 device_handle, handle; - /* lookup sas_device */ - spin_lock_irqsave(&ioc->sas_device_lock, flags); - sas_device = _scsih_sas_device_find_by_handle(ioc, handle); - if (!sas_device) { - spin_unlock_irqrestore(&ioc->sas_device_lock, flags); + if (!sas_device) return; - } - dewtprintk(ioc, printk(MPT2SAS_INFO_FMT "%s: enter: handle" - "(0x%04x)\n", ioc->name, __func__, handle)); + handle = sas_device->handle; + dewtprintk(ioc, printk(MPT2SAS_INFO_FMT "%s: enter: handle(0x%04x)," + " sas_addr(0x%016llx)\n", ioc->name, __func__, handle, + (unsigned long long) sas_device->sas_address)); if (sas_device->starget && sas_device->starget->hostdata) { sas_target_priv_data = sas_device->starget->hostdata; sas_target_priv_data->deleted = 1; } - spin_unlock_irqrestore(&ioc->sas_device_lock, flags); - if (ioc->remove_host) + if (ioc->remove_host || ioc->shost_recovery || !handle) goto out; if ((sas_device->state & MPTSAS_STATE_TR_COMPLETE)) { dewtprintk(ioc, printk(MPT2SAS_INFO_FMT "\tskip " - "target_reset handle(0x%04x)\n", ioc->name, handle)); + "target_reset handle(0x%04x)\n", ioc->name, + handle)); goto skip_tr; } @@ -3925,10 +4055,10 @@ _scsih_remove_device(struct MPT2SAS_ADAPTER *ioc, u16 handle) _scsih_ublock_io_device(ioc, handle); mpt2sas_transport_port_remove(ioc, sas_device->sas_address, - sas_device->parent_handle); + sas_device->sas_address_parent); printk(MPT2SAS_INFO_FMT "removing handle(0x%04x), sas_addr" - "(0x%016llx)\n", ioc->name, sas_device->handle, + "(0x%016llx)\n", ioc->name, handle, (unsigned long long) sas_device->sas_address); _scsih_sas_device_remove(ioc, sas_device); @@ -3952,7 +4082,7 @@ _scsih_sas_topology_change_event_debug(struct MPT2SAS_ADAPTER *ioc, u16 reason_code; u8 phy_number; char *status_str = NULL; - char link_rate[25]; + u8 link_rate, prev_link_rate; switch (event_data->ExpStatus) { case MPI2_EVENT_SAS_TOPO_ES_ADDED: @@ -3962,6 +4092,7 @@ _scsih_sas_topology_change_event_debug(struct MPT2SAS_ADAPTER *ioc, status_str = "remove"; break; case MPI2_EVENT_SAS_TOPO_ES_RESPONDING: + case 0: status_str = "responding"; break; case MPI2_EVENT_SAS_TOPO_ES_DELAY_NOT_RESPONDING: @@ -3987,30 +4118,30 @@ _scsih_sas_topology_change_event_debug(struct MPT2SAS_ADAPTER *ioc, MPI2_EVENT_SAS_TOPO_RC_MASK; switch (reason_code) { case MPI2_EVENT_SAS_TOPO_RC_TARG_ADDED: - snprintf(link_rate, 25, ": add, link(0x%02x)", - (event_data->PHY[i].LinkRate >> 4)); - status_str = link_rate; + status_str = "target add"; break; case MPI2_EVENT_SAS_TOPO_RC_TARG_NOT_RESPONDING: - status_str = ": remove"; + status_str = "target remove"; break; case MPI2_EVENT_SAS_TOPO_RC_DELAY_NOT_RESPONDING: - status_str = ": remove_delay"; + status_str = "delay target remove"; break; case MPI2_EVENT_SAS_TOPO_RC_PHY_CHANGED: - snprintf(link_rate, 25, ": link(0x%02x)", - (event_data->PHY[i].LinkRate >> 4)); - status_str = link_rate; + status_str = "link rate change"; break; case MPI2_EVENT_SAS_TOPO_RC_NO_CHANGE: - status_str = ": responding"; + status_str = "target responding"; break; default: - status_str = ": unknown"; + status_str = "unknown"; break; } - printk(KERN_DEBUG "\tphy(%02d), attached_handle(0x%04x)%s\n", - phy_number, handle, status_str); + link_rate = event_data->PHY[i].LinkRate >> 4; + prev_link_rate = event_data->PHY[i].LinkRate & 0xF; + printk(KERN_DEBUG "\tphy(%02d), attached_handle(0x%04x): %s:" + " link rate: new(0x%02x), old(0x%02x)\n", phy_number, + handle, status_str, link_rate, prev_link_rate); + } } #endif @@ -4031,8 +4162,10 @@ _scsih_sas_topology_change_event(struct MPT2SAS_ADAPTER *ioc, u16 reason_code; u8 phy_number; struct _sas_node *sas_expander; + struct _sas_device *sas_device; + u64 sas_address; unsigned long flags; - u8 link_rate_; + u8 link_rate, prev_link_rate; Mpi2EventDataSasTopologyChangeList_t *event_data = fw_event->event_data; #ifdef CONFIG_SCSI_MPT2SAS_LOGGING @@ -4040,10 +4173,13 @@ _scsih_sas_topology_change_event(struct MPT2SAS_ADAPTER *ioc, _scsih_sas_topology_change_event_debug(ioc, event_data); #endif + if (ioc->shost_recovery) + return; + if (!ioc->sas_hba.num_phys) _scsih_sas_host_add(ioc); else - _scsih_sas_host_refresh(ioc, 0); + _scsih_sas_host_refresh(ioc); if (fw_event->ignore) { dewtprintk(ioc, printk(MPT2SAS_DEBUG_FMT "ignoring expander " @@ -4058,6 +4194,17 @@ _scsih_sas_topology_change_event(struct MPT2SAS_ADAPTER *ioc, if (_scsih_expander_add(ioc, parent_handle) != 0) return; + spin_lock_irqsave(&ioc->sas_node_lock, flags); + sas_expander = mpt2sas_scsih_expander_find_by_handle(ioc, + parent_handle); + spin_unlock_irqrestore(&ioc->sas_node_lock, flags); + if (sas_expander) + sas_address = sas_expander->sas_address; + else if (parent_handle < ioc->sas_hba.num_phys) + sas_address = ioc->sas_hba.sas_address; + else + return; + /* handle siblings events */ for (i = 0; i < event_data->NumEntries; i++) { if (fw_event->ignore) { @@ -4077,48 +4224,47 @@ _scsih_sas_topology_change_event(struct MPT2SAS_ADAPTER *ioc, handle = le16_to_cpu(event_data->PHY[i].AttachedDevHandle); if (!handle) continue; - link_rate_ = event_data->PHY[i].LinkRate >> 4; + link_rate = event_data->PHY[i].LinkRate >> 4; + prev_link_rate = event_data->PHY[i].LinkRate & 0xF; switch (reason_code) { case MPI2_EVENT_SAS_TOPO_RC_PHY_CHANGED: + + if (link_rate == prev_link_rate) + break; + + mpt2sas_transport_update_links(ioc, sas_address, + handle, phy_number, link_rate); + + if (link_rate >= MPI2_SAS_NEG_LINK_RATE_1_5) + _scsih_ublock_io_device(ioc, handle); + break; case MPI2_EVENT_SAS_TOPO_RC_TARG_ADDED: - if (!parent_handle) { - if (phy_number < ioc->sas_hba.num_phys) - mpt2sas_transport_update_links( - ioc, - ioc->sas_hba.phy[phy_number].handle, - handle, phy_number, link_rate_); - } else { - spin_lock_irqsave(&ioc->sas_node_lock, flags); - sas_expander = - mpt2sas_scsih_expander_find_by_handle(ioc, - parent_handle); - spin_unlock_irqrestore(&ioc->sas_node_lock, - flags); - if (sas_expander) { - if (phy_number < sas_expander->num_phys) - mpt2sas_transport_update_links( - ioc, - sas_expander-> - phy[phy_number].handle, - handle, phy_number, - link_rate_); - } - } - if (reason_code == MPI2_EVENT_SAS_TOPO_RC_TARG_ADDED) { - if (link_rate_ < MPI2_SAS_NEG_LINK_RATE_1_5) - break; - _scsih_add_device(ioc, handle, phy_number, 0); - } + + mpt2sas_transport_update_links(ioc, sas_address, + handle, phy_number, link_rate); + + _scsih_add_device(ioc, handle, phy_number, 0); break; case MPI2_EVENT_SAS_TOPO_RC_TARG_NOT_RESPONDING: - _scsih_remove_device(ioc, handle); + + spin_lock_irqsave(&ioc->sas_device_lock, flags); + sas_device = _scsih_sas_device_find_by_handle(ioc, + handle); + if (!sas_device) { + spin_unlock_irqrestore(&ioc->sas_device_lock, + flags); + break; + } + spin_unlock_irqrestore(&ioc->sas_device_lock, flags); + _scsih_remove_device(ioc, sas_device); break; } } /* handle expander removal */ - if (event_data->ExpStatus == MPI2_EVENT_SAS_TOPO_ES_NOT_RESPONDING) - _scsih_expander_remove(ioc, parent_handle); + if (event_data->ExpStatus == MPI2_EVENT_SAS_TOPO_ES_NOT_RESPONDING && + sas_expander) + _scsih_expander_remove(ioc, sas_address); } @@ -4170,6 +4316,12 @@ _scsih_sas_device_status_change_event_debug(struct MPT2SAS_ADAPTER *ioc, case MPI2_EVENT_SAS_DEV_STAT_RC_ASYNC_NOTIFICATION: reason_str = "internal async notification"; break; + case MPI2_EVENT_SAS_DEV_STAT_RC_EXPANDER_REDUCED_FUNCTIONALITY: + reason_str = "expander reduced functionality"; + break; + case MPI2_EVENT_SAS_DEV_STAT_RC_CMP_EXPANDER_REDUCED_FUNCTIONALITY: + reason_str = "expander reduced functionality complete"; + break; default: reason_str = "unknown reason"; break; @@ -4197,11 +4349,43 @@ static void _scsih_sas_device_status_change_event(struct MPT2SAS_ADAPTER *ioc, struct fw_event_work *fw_event) { + struct MPT2SAS_TARGET *target_priv_data; + struct _sas_device *sas_device; + __le64 sas_address; + unsigned long flags; + Mpi2EventDataSasDeviceStatusChange_t *event_data = + fw_event->event_data; + #ifdef CONFIG_SCSI_MPT2SAS_LOGGING if (ioc->logging_level & MPT_DEBUG_EVENT_WORK_TASK) _scsih_sas_device_status_change_event_debug(ioc, - fw_event->event_data); + event_data); #endif + + if (!(event_data->ReasonCode == + MPI2_EVENT_SAS_DEV_STAT_RC_INTERNAL_DEVICE_RESET && + event_data->ReasonCode == + MPI2_EVENT_SAS_DEV_STAT_RC_CMP_INTERNAL_DEV_RESET)) + return; + + spin_lock_irqsave(&ioc->sas_device_lock, flags); + sas_address = le64_to_cpu(event_data->SASAddress); + sas_device = mpt2sas_scsih_sas_device_find_by_sas_address(ioc, + sas_address); + spin_unlock_irqrestore(&ioc->sas_device_lock, flags); + + if (!sas_device || !sas_device->starget) + return; + + target_priv_data = sas_device->starget->hostdata; + if (!target_priv_data) + return; + + if (event_data->ReasonCode == + MPI2_EVENT_SAS_DEV_STAT_RC_INTERNAL_DEVICE_RESET) + target_priv_data->tm_busy = 1; + else + target_priv_data->tm_busy = 0; } #ifdef CONFIG_SCSI_MPT2SAS_LOGGING @@ -4281,6 +4465,7 @@ _scsih_sas_broadcast_primative_event(struct MPT2SAS_ADAPTER *ioc, #ifdef CONFIG_SCSI_MPT2SAS_LOGGING Mpi2EventDataSasBroadcastPrimitive_t *event_data = fw_event->event_data; #endif + u16 ioc_status; dewtprintk(ioc, printk(MPT2SAS_DEBUG_FMT "broadcast primative: " "phy number(%d), width(%d)\n", ioc->name, event_data->PhyNum, event_data->PortWidth)); @@ -4314,8 +4499,9 @@ _scsih_sas_broadcast_primative_event(struct MPT2SAS_ADAPTER *ioc, mpt2sas_scsih_issue_tm(ioc, handle, lun, MPI2_SCSITASKMGMT_TASKTYPE_QUERY_TASK, smid, 30); ioc->tm_cmds.status = MPT2_CMD_NOT_USED; - - if ((mpi_reply->IOCStatus == MPI2_IOCSTATUS_SUCCESS) && + ioc_status = le16_to_cpu(mpi_reply->IOCStatus) + & MPI2_IOCSTATUS_MASK; + if ((ioc_status == MPI2_IOCSTATUS_SUCCESS) && (mpi_reply->ResponseCode == MPI2_SCSITASKMGMT_RSP_TM_SUCCEEDED || mpi_reply->ResponseCode == @@ -4570,7 +4756,7 @@ _scsih_sas_pd_delete(struct MPT2SAS_ADAPTER *ioc, spin_unlock_irqrestore(&ioc->sas_device_lock, flags); if (!sas_device) return; - _scsih_remove_device(ioc, handle); + _scsih_remove_device(ioc, sas_device); } /** @@ -4591,6 +4777,8 @@ _scsih_sas_pd_add(struct MPT2SAS_ADAPTER *ioc, Mpi2ConfigReply_t mpi_reply; Mpi2SasDevicePage0_t sas_device_pg0; u32 ioc_status; + u64 sas_address; + u16 parent_handle; spin_lock_irqsave(&ioc->sas_device_lock, flags); sas_device = _scsih_sas_device_find_by_handle(ioc, handle); @@ -4615,9 +4803,10 @@ _scsih_sas_pd_add(struct MPT2SAS_ADAPTER *ioc, return; } - mpt2sas_transport_update_links(ioc, - le16_to_cpu(sas_device_pg0.ParentDevHandle), - handle, sas_device_pg0.PhyNum, MPI2_SAS_NEG_LINK_RATE_1_5); + parent_handle = le16_to_cpu(sas_device_pg0.ParentDevHandle); + if (!_scsih_get_sas_address(ioc, parent_handle, &sas_address)) + mpt2sas_transport_update_links(ioc, sas_address, handle, + sas_device_pg0.PhyNum, MPI2_SAS_NEG_LINK_RATE_1_5); _scsih_add_device(ioc, handle, 0, 1); } @@ -4857,7 +5046,7 @@ static void _scsih_sas_ir_physical_disk_event(struct MPT2SAS_ADAPTER *ioc, struct fw_event_work *fw_event) { - u16 handle; + u16 handle, parent_handle; u32 state; struct _sas_device *sas_device; unsigned long flags; @@ -4865,6 +5054,7 @@ _scsih_sas_ir_physical_disk_event(struct MPT2SAS_ADAPTER *ioc, Mpi2SasDevicePage0_t sas_device_pg0; u32 ioc_status; Mpi2EventDataIrPhysicalDisk_t *event_data = fw_event->event_data; + u64 sas_address; if (event_data->ReasonCode != MPI2_EVENT_IR_PHYSDISK_RC_STATE_CHANGED) return; @@ -4906,9 +5096,10 @@ _scsih_sas_ir_physical_disk_event(struct MPT2SAS_ADAPTER *ioc, return; } - mpt2sas_transport_update_links(ioc, - le16_to_cpu(sas_device_pg0.ParentDevHandle), - handle, sas_device_pg0.PhyNum, MPI2_SAS_NEG_LINK_RATE_1_5); + parent_handle = le16_to_cpu(sas_device_pg0.ParentDevHandle); + if (!_scsih_get_sas_address(ioc, parent_handle, &sas_address)) + mpt2sas_transport_update_links(ioc, sas_address, handle, + sas_device_pg0.PhyNum, MPI2_SAS_NEG_LINK_RATE_1_5); _scsih_add_device(ioc, handle, 0, 1); @@ -4948,11 +5139,17 @@ _scsih_sas_ir_operation_status_event_debug(struct MPT2SAS_ADAPTER *ioc, case MPI2_EVENT_IR_RAIDOP_CONSISTENCY_CHECK: reason_str = "consistency check"; break; - default: - reason_str = "unknown reason"; + case MPI2_EVENT_IR_RAIDOP_BACKGROUND_INIT: + reason_str = "background init"; + break; + case MPI2_EVENT_IR_RAIDOP_MAKE_DATA_CONSISTENT: + reason_str = "make data consistent"; break; } + if (!reason_str) + return; + printk(MPT2SAS_INFO_FMT "raid operational status: (%s)" "\thandle(0x%04x), percent complete(%d)\n", ioc->name, reason_str, @@ -5252,18 +5449,23 @@ _scsih_mark_responding_expander(struct MPT2SAS_ADAPTER *ioc, u64 sas_address, { struct _sas_node *sas_expander; unsigned long flags; + int i; spin_lock_irqsave(&ioc->sas_node_lock, flags); list_for_each_entry(sas_expander, &ioc->sas_expander_list, list) { - if (sas_expander->sas_address == sas_address) { - sas_expander->responding = 1; - if (sas_expander->handle != handle) { - printk(KERN_INFO "old handle(0x%04x)\n", - sas_expander->handle); - sas_expander->handle = handle; - } + if (sas_expander->sas_address != sas_address) + continue; + sas_expander->responding = 1; + if (sas_expander->handle == handle) goto out; - } + printk(KERN_INFO "\texpander(0x%016llx): handle changed" + " from(0x%04x) to (0x%04x)!!!\n", + (unsigned long long)sas_expander->sas_address, + sas_expander->handle, handle); + sas_expander->handle = handle; + for (i = 0 ; i < sas_expander->num_phys ; i++) + sas_expander->phy[i].handle = handle; + goto out; } out: spin_unlock_irqrestore(&ioc->sas_node_lock, flags); @@ -5340,7 +5542,9 @@ _scsih_remove_unresponding_devices(struct MPT2SAS_ADAPTER *ioc) (unsigned long long) sas_device->enclosure_logical_id, sas_device->slot); - _scsih_remove_device(ioc, sas_device->handle); + /* invalidate the device handle */ + sas_device->handle = 0; + _scsih_remove_device(ioc, sas_device); } list_for_each_entry_safe(raid_device, raid_device_next, @@ -5366,7 +5570,7 @@ _scsih_remove_unresponding_devices(struct MPT2SAS_ADAPTER *ioc) sas_expander->responding = 0; continue; } - _scsih_expander_remove(ioc, sas_expander->handle); + _scsih_expander_remove(ioc, sas_expander->sas_address); goto retry_expander_search; } } @@ -5406,7 +5610,7 @@ mpt2sas_scsih_reset_handler(struct MPT2SAS_ADAPTER *ioc, int reset_phase) case MPT2_IOC_DONE_RESET: dtmprintk(ioc, printk(MPT2SAS_DEBUG_FMT "%s: " "MPT2_IOC_DONE_RESET\n", ioc->name, __func__)); - _scsih_sas_host_refresh(ioc, 0); + _scsih_sas_host_refresh(ioc); _scsih_search_responding_sas_devices(ioc); _scsih_search_responding_raid_devices(ioc); _scsih_search_responding_expanders(ioc); @@ -5646,7 +5850,7 @@ _scsih_expander_node_remove(struct MPT2SAS_ADAPTER *ioc, spin_unlock_irqrestore(&ioc->sas_device_lock, flags); if (!sas_device) continue; - _scsih_remove_device(ioc, sas_device->handle); + _scsih_remove_device(ioc, sas_device); if (ioc->shost_recovery) return; goto retry_device_search; @@ -5669,7 +5873,8 @@ _scsih_expander_node_remove(struct MPT2SAS_ADAPTER *ioc, spin_unlock_irqrestore(&ioc->sas_node_lock, flags); if (!expander_sibling) continue; - _scsih_expander_remove(ioc, expander_sibling->handle); + _scsih_expander_remove(ioc, + expander_sibling->sas_address); if (ioc->shost_recovery) return; goto retry_expander_search; @@ -5677,7 +5882,7 @@ _scsih_expander_node_remove(struct MPT2SAS_ADAPTER *ioc, } mpt2sas_transport_port_remove(ioc, sas_expander->sas_address, - sas_expander->parent_handle); + sas_expander->sas_address_parent); printk(MPT2SAS_INFO_FMT "expander_remove: handle" "(0x%04x), sas_addr(0x%016llx)\n", ioc->name, @@ -5690,9 +5895,99 @@ _scsih_expander_node_remove(struct MPT2SAS_ADAPTER *ioc, } /** + * _scsih_ir_shutdown - IR shutdown notification + * @ioc: per adapter object + * + * Sending RAID Action to alert the Integrated RAID subsystem of the IOC that + * the host system is shutting down. + * + * Return nothing. + */ +static void +_scsih_ir_shutdown(struct MPT2SAS_ADAPTER *ioc) +{ + Mpi2RaidActionRequest_t *mpi_request; + Mpi2RaidActionReply_t *mpi_reply; + u16 smid; + + /* is IR firmware build loaded ? */ + if (!ioc->ir_firmware) + return; + + /* are there any volumes ? */ + if (list_empty(&ioc->raid_device_list)) + return; + + mutex_lock(&ioc->scsih_cmds.mutex); + + if (ioc->scsih_cmds.status != MPT2_CMD_NOT_USED) { + printk(MPT2SAS_ERR_FMT "%s: scsih_cmd in use\n", + ioc->name, __func__); + goto out; + } + ioc->scsih_cmds.status = MPT2_CMD_PENDING; + + smid = mpt2sas_base_get_smid(ioc, ioc->scsih_cb_idx); + if (!smid) { + printk(MPT2SAS_ERR_FMT "%s: failed obtaining a smid\n", + ioc->name, __func__); + ioc->scsih_cmds.status = MPT2_CMD_NOT_USED; + goto out; + } + + mpi_request = mpt2sas_base_get_msg_frame(ioc, smid); + ioc->scsih_cmds.smid = smid; + memset(mpi_request, 0, sizeof(Mpi2RaidActionRequest_t)); + + mpi_request->Function = MPI2_FUNCTION_RAID_ACTION; + mpi_request->Action = MPI2_RAID_ACTION_SYSTEM_SHUTDOWN_INITIATED; + + printk(MPT2SAS_INFO_FMT "IR shutdown (sending)\n", ioc->name); + init_completion(&ioc->scsih_cmds.done); + mpt2sas_base_put_smid_default(ioc, smid); + wait_for_completion_timeout(&ioc->scsih_cmds.done, 10*HZ); + + if (!(ioc->scsih_cmds.status & MPT2_CMD_COMPLETE)) { + printk(MPT2SAS_ERR_FMT "%s: timeout\n", + ioc->name, __func__); + goto out; + } + + if (ioc->scsih_cmds.status & MPT2_CMD_REPLY_VALID) { + mpi_reply = ioc->scsih_cmds.reply; + + printk(MPT2SAS_INFO_FMT "IR shutdown (complete): " + "ioc_status(0x%04x), loginfo(0x%08x)\n", + ioc->name, le16_to_cpu(mpi_reply->IOCStatus), + le32_to_cpu(mpi_reply->IOCLogInfo)); + } + + out: + ioc->scsih_cmds.status = MPT2_CMD_NOT_USED; + mutex_unlock(&ioc->scsih_cmds.mutex); +} + +/** + * _scsih_shutdown - routine call during system shutdown + * @pdev: PCI device struct + * + * Return nothing. + */ +static void +_scsih_shutdown(struct pci_dev *pdev) +{ + struct Scsi_Host *shost = pci_get_drvdata(pdev); + struct MPT2SAS_ADAPTER *ioc = shost_priv(shost); + + _scsih_ir_shutdown(ioc); + mpt2sas_base_detach(ioc); +} + +/** * _scsih_remove - detach and remove add host * @pdev: PCI device struct * + * Routine called when unloading the driver. * Return nothing. */ static void __devexit @@ -5726,7 +6021,7 @@ _scsih_remove(struct pci_dev *pdev) mpt2sas_scsih_sas_device_find_by_sas_address(ioc, mpt2sas_port->remote_identify.sas_address); if (sas_device) { - _scsih_remove_device(ioc, sas_device->handle); + _scsih_remove_device(ioc, sas_device); goto retry_again; } } else { @@ -5735,7 +6030,7 @@ _scsih_remove(struct pci_dev *pdev) mpt2sas_port->remote_identify.sas_address); if (expander_sibling) { _scsih_expander_remove(ioc, - expander_sibling->handle); + expander_sibling->sas_address); goto retry_again; } } @@ -5749,7 +6044,7 @@ _scsih_remove(struct pci_dev *pdev) } sas_remove_host(shost); - mpt2sas_base_detach(ioc); + _scsih_shutdown(pdev); list_del(&ioc->list); scsi_remove_host(shost); scsi_host_put(shost); @@ -5770,7 +6065,8 @@ _scsih_probe_boot_devices(struct MPT2SAS_ADAPTER *ioc) void *device; struct _sas_device *sas_device; struct _raid_device *raid_device; - u16 handle, parent_handle; + u16 handle; + u64 sas_address_parent; u64 sas_address; unsigned long flags; int rc; @@ -5799,17 +6095,17 @@ _scsih_probe_boot_devices(struct MPT2SAS_ADAPTER *ioc) } else { sas_device = device; handle = sas_device->handle; - parent_handle = sas_device->parent_handle; + sas_address_parent = sas_device->sas_address_parent; sas_address = sas_device->sas_address; spin_lock_irqsave(&ioc->sas_device_lock, flags); list_move_tail(&sas_device->list, &ioc->sas_device_list); spin_unlock_irqrestore(&ioc->sas_device_lock, flags); if (!mpt2sas_transport_port_add(ioc, sas_device->handle, - sas_device->parent_handle)) { + sas_device->sas_address_parent)) { _scsih_sas_device_remove(ioc, sas_device); } else if (!sas_device->starget) { mpt2sas_transport_port_remove(ioc, sas_address, - parent_handle); + sas_address_parent); _scsih_sas_device_remove(ioc, sas_device); } } @@ -5849,8 +6145,6 @@ _scsih_probe_sas(struct MPT2SAS_ADAPTER *ioc) { struct _sas_device *sas_device, *next; unsigned long flags; - u16 handle, parent_handle; - u64 sas_address; /* SAS Device List */ list_for_each_entry_safe(sas_device, next, &ioc->sas_device_init_list, @@ -5859,14 +6153,13 @@ _scsih_probe_sas(struct MPT2SAS_ADAPTER *ioc) list_move_tail(&sas_device->list, &ioc->sas_device_list); spin_unlock_irqrestore(&ioc->sas_device_lock, flags); - handle = sas_device->handle; - parent_handle = sas_device->parent_handle; - sas_address = sas_device->sas_address; - if (!mpt2sas_transport_port_add(ioc, handle, parent_handle)) { + if (!mpt2sas_transport_port_add(ioc, sas_device->handle, + sas_device->sas_address_parent)) { _scsih_sas_device_remove(ioc, sas_device); } else if (!sas_device->starget) { - mpt2sas_transport_port_remove(ioc, sas_address, - parent_handle); + mpt2sas_transport_port_remove(ioc, + sas_device->sas_address, + sas_device->sas_address_parent); _scsih_sas_device_remove(ioc, sas_device); } } @@ -5935,6 +6228,7 @@ _scsih_probe(struct pci_dev *pdev, const struct pci_device_id *id) ioc->ctl_cb_idx = ctl_cb_idx; ioc->base_cb_idx = base_cb_idx; ioc->transport_cb_idx = transport_cb_idx; + ioc->scsih_cb_idx = scsih_cb_idx; ioc->config_cb_idx = config_cb_idx; ioc->tm_tr_cb_idx = tm_tr_cb_idx; ioc->tm_sas_control_cb_idx = tm_sas_control_cb_idx; @@ -6072,6 +6366,7 @@ static struct pci_driver scsih_driver = { .id_table = scsih_pci_table, .probe = _scsih_probe, .remove = __devexit_p(_scsih_remove), + .shutdown = _scsih_shutdown, #ifdef CONFIG_PM .suspend = _scsih_suspend, .resume = _scsih_resume, @@ -6113,6 +6408,9 @@ _scsih_init(void) transport_cb_idx = mpt2sas_base_register_callback_handler( mpt2sas_transport_done); + /* scsih internal commands callback handler */ + scsih_cb_idx = mpt2sas_base_register_callback_handler(_scsih_done); + /* configuration page API internal commands callback handler */ config_cb_idx = mpt2sas_base_register_callback_handler( mpt2sas_config_done); @@ -6152,6 +6450,7 @@ _scsih_exit(void) mpt2sas_base_release_callback_handler(tm_cb_idx); mpt2sas_base_release_callback_handler(base_cb_idx); mpt2sas_base_release_callback_handler(transport_cb_idx); + mpt2sas_base_release_callback_handler(scsih_cb_idx); mpt2sas_base_release_callback_handler(config_cb_idx); mpt2sas_base_release_callback_handler(ctl_cb_idx); diff --git a/drivers/scsi/mpt2sas/mpt2sas_transport.c b/drivers/scsi/mpt2sas/mpt2sas_transport.c index eb98188c7f3f..3a82872bad44 100644 --- a/drivers/scsi/mpt2sas/mpt2sas_transport.c +++ b/drivers/scsi/mpt2sas/mpt2sas_transport.c @@ -59,24 +59,23 @@ #include "mpt2sas_base.h" /** - * _transport_sas_node_find_by_handle - sas node search + * _transport_sas_node_find_by_sas_address - sas node search * @ioc: per adapter object - * @handle: expander or hba handle (assigned by firmware) + * @sas_address: sas address of expander or sas host * Context: Calling function should acquire ioc->sas_node_lock. * * Search for either hba phys or expander device based on handle, then returns * the sas_node object. */ static struct _sas_node * -_transport_sas_node_find_by_handle(struct MPT2SAS_ADAPTER *ioc, u16 handle) +_transport_sas_node_find_by_sas_address(struct MPT2SAS_ADAPTER *ioc, + u64 sas_address) { - int i; - - for (i = 0; i < ioc->sas_hba.num_phys; i++) - if (ioc->sas_hba.phy[i].handle == handle) - return &ioc->sas_hba; - - return mpt2sas_scsih_expander_find_by_handle(ioc, handle); + if (ioc->sas_hba.sas_address == sas_address) + return &ioc->sas_hba; + else + return mpt2sas_scsih_expander_find_by_sas_address(ioc, + sas_address); } /** @@ -259,8 +258,7 @@ struct rep_manu_reply{ u8 response_length; u16 expander_change_count; u8 reserved0[2]; - u8 sas_format:1; - u8 reserved1:7; + u8 sas_format; u8 reserved2[3]; u8 vendor_id[SAS_EXPANDER_VENDOR_ID_LEN]; u8 product_id[SAS_EXPANDER_PRODUCT_ID_LEN]; @@ -375,7 +373,8 @@ _transport_expander_report_manufacture(struct MPT2SAS_ADAPTER *ioc, mpi_request->VP_ID = 0; sas_address_le = (u64 *)&mpi_request->SASAddress; *sas_address_le = cpu_to_le64(sas_address); - mpi_request->RequestDataLength = sizeof(struct rep_manu_request); + mpi_request->RequestDataLength = + cpu_to_le16(sizeof(struct rep_manu_request)); psge = &mpi_request->SGL; /* WRITE sgel first */ @@ -438,8 +437,8 @@ _transport_expander_report_manufacture(struct MPT2SAS_ADAPTER *ioc, SAS_EXPANDER_PRODUCT_ID_LEN); strncpy(edev->product_rev, manufacture_reply->product_rev, SAS_EXPANDER_PRODUCT_REV_LEN); - edev->level = manufacture_reply->sas_format; - if (manufacture_reply->sas_format) { + edev->level = manufacture_reply->sas_format & 1; + if (edev->level) { strncpy(edev->component_vendor_id, manufacture_reply->component_vendor_id, SAS_EXPANDER_COMPONENT_VENDOR_ID_LEN); @@ -469,7 +468,7 @@ _transport_expander_report_manufacture(struct MPT2SAS_ADAPTER *ioc, * mpt2sas_transport_port_add - insert port to the list * @ioc: per adapter object * @handle: handle of attached device - * @parent_handle: parent handle(either hba or expander) + * @sas_address: sas address of parent expander or sas host * Context: This function will acquire ioc->sas_node_lock. * * Adding new port object to the sas_node->sas_port_list. @@ -478,7 +477,7 @@ _transport_expander_report_manufacture(struct MPT2SAS_ADAPTER *ioc, */ struct _sas_port * mpt2sas_transport_port_add(struct MPT2SAS_ADAPTER *ioc, u16 handle, - u16 parent_handle) + u64 sas_address) { struct _sas_phy *mpt2sas_phy, *next; struct _sas_port *mpt2sas_port; @@ -488,9 +487,6 @@ mpt2sas_transport_port_add(struct MPT2SAS_ADAPTER *ioc, u16 handle, int i; struct sas_port *port; - if (!parent_handle) - return NULL; - mpt2sas_port = kzalloc(sizeof(struct _sas_port), GFP_KERNEL); if (!mpt2sas_port) { @@ -502,17 +498,16 @@ mpt2sas_transport_port_add(struct MPT2SAS_ADAPTER *ioc, u16 handle, INIT_LIST_HEAD(&mpt2sas_port->port_list); INIT_LIST_HEAD(&mpt2sas_port->phy_list); spin_lock_irqsave(&ioc->sas_node_lock, flags); - sas_node = _transport_sas_node_find_by_handle(ioc, parent_handle); + sas_node = _transport_sas_node_find_by_sas_address(ioc, sas_address); spin_unlock_irqrestore(&ioc->sas_node_lock, flags); if (!sas_node) { - printk(MPT2SAS_ERR_FMT "%s: Could not find parent(0x%04x)!\n", - ioc->name, __func__, parent_handle); + printk(MPT2SAS_ERR_FMT "%s: Could not find " + "parent sas_address(0x%016llx)!\n", ioc->name, + __func__, (unsigned long long)sas_address); goto out_fail; } - mpt2sas_port->handle = parent_handle; - mpt2sas_port->sas_address = sas_node->sas_address; if ((_transport_set_identify(ioc, handle, &mpt2sas_port->remote_identify))) { printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n", @@ -604,7 +599,7 @@ mpt2sas_transport_port_add(struct MPT2SAS_ADAPTER *ioc, u16 handle, * mpt2sas_transport_port_remove - remove port from the list * @ioc: per adapter object * @sas_address: sas address of attached device - * @parent_handle: handle to the upstream parent(either hba or expander) + * @sas_address_parent: sas address of parent expander or sas host * Context: This function will acquire ioc->sas_node_lock. * * Removing object and freeing associated memory from the @@ -614,7 +609,7 @@ mpt2sas_transport_port_add(struct MPT2SAS_ADAPTER *ioc, u16 handle, */ void mpt2sas_transport_port_remove(struct MPT2SAS_ADAPTER *ioc, u64 sas_address, - u16 parent_handle) + u64 sas_address_parent) { int i; unsigned long flags; @@ -624,7 +619,8 @@ mpt2sas_transport_port_remove(struct MPT2SAS_ADAPTER *ioc, u64 sas_address, struct _sas_phy *mpt2sas_phy, *next_phy; spin_lock_irqsave(&ioc->sas_node_lock, flags); - sas_node = _transport_sas_node_find_by_handle(ioc, parent_handle); + sas_node = _transport_sas_node_find_by_sas_address(ioc, + sas_address_parent); spin_unlock_irqrestore(&ioc->sas_node_lock, flags); if (!sas_node) return; @@ -650,8 +646,7 @@ mpt2sas_transport_port_remove(struct MPT2SAS_ADAPTER *ioc, u64 sas_address, &mpt2sas_port->phy_list, port_siblings) { if ((ioc->logging_level & MPT_DEBUG_TRANSPORT)) dev_printk(KERN_INFO, &mpt2sas_port->port->dev, - "remove: parent_handle(0x%04x), " - "sas_addr(0x%016llx), phy(%d)\n", parent_handle, + "remove: sas_addr(0x%016llx), phy(%d)\n", (unsigned long long) mpt2sas_port->remote_identify.sas_address, mpt2sas_phy->phy_id); @@ -799,8 +794,8 @@ mpt2sas_transport_add_expander_phy(struct MPT2SAS_ADAPTER *ioc, struct _sas_phy /** * mpt2sas_transport_update_links - refreshing phy link changes * @ioc: per adapter object - * @handle: handle to sas_host or expander - * @attached_handle: attached device handle + * @sas_address: sas address of parent expander or sas host + * @handle: attached device handle * @phy_numberv: phy number * @link_rate: new link rate * @@ -808,28 +803,25 @@ mpt2sas_transport_add_expander_phy(struct MPT2SAS_ADAPTER *ioc, struct _sas_phy */ void mpt2sas_transport_update_links(struct MPT2SAS_ADAPTER *ioc, - u16 handle, u16 attached_handle, u8 phy_number, u8 link_rate) + u64 sas_address, u16 handle, u8 phy_number, u8 link_rate) { unsigned long flags; struct _sas_node *sas_node; struct _sas_phy *mpt2sas_phy; - if (ioc->shost_recovery) { - printk(MPT2SAS_INFO_FMT "%s: host reset in progress!\n", - __func__, ioc->name); + if (ioc->shost_recovery) return; - } spin_lock_irqsave(&ioc->sas_node_lock, flags); - sas_node = _transport_sas_node_find_by_handle(ioc, handle); + sas_node = _transport_sas_node_find_by_sas_address(ioc, sas_address); spin_unlock_irqrestore(&ioc->sas_node_lock, flags); if (!sas_node) return; mpt2sas_phy = &sas_node->phy[phy_number]; - mpt2sas_phy->attached_handle = attached_handle; - if (attached_handle && (link_rate >= MPI2_SAS_NEG_LINK_RATE_1_5)) - _transport_set_identify(ioc, mpt2sas_phy->attached_handle, + mpt2sas_phy->attached_handle = handle; + if (handle && (link_rate >= MPI2_SAS_NEG_LINK_RATE_1_5)) + _transport_set_identify(ioc, handle, &mpt2sas_phy->remote_identify); else memset(&mpt2sas_phy->remote_identify, 0 , sizeof(struct @@ -841,13 +833,11 @@ mpt2sas_transport_update_links(struct MPT2SAS_ADAPTER *ioc, if ((ioc->logging_level & MPT_DEBUG_TRANSPORT)) dev_printk(KERN_INFO, &mpt2sas_phy->phy->dev, - "refresh: handle(0x%04x), sas_addr(0x%016llx),\n" + "refresh: parent sas_addr(0x%016llx),\n" "\tlink_rate(0x%02x), phy(%d)\n" "\tattached_handle(0x%04x), sas_addr(0x%016llx)\n", - handle, (unsigned long long) - mpt2sas_phy->identify.sas_address, link_rate, - phy_number, attached_handle, - (unsigned long long) + (unsigned long long)sas_address, + link_rate, phy_number, handle, (unsigned long long) mpt2sas_phy->remote_identify.sas_address); } @@ -1126,7 +1116,7 @@ _transport_smp_handler(struct Scsi_Host *shost, struct sas_rphy *rphy, dma_addr_out = pci_map_single(ioc->pdev, bio_data(req->bio), blk_rq_bytes(req), PCI_DMA_BIDIRECTIONAL); if (!dma_addr_out) { - mpt2sas_base_free_smid(ioc, le16_to_cpu(smid)); + mpt2sas_base_free_smid(ioc, smid); goto unmap; } @@ -1144,7 +1134,7 @@ _transport_smp_handler(struct Scsi_Host *shost, struct sas_rphy *rphy, dma_addr_in = pci_map_single(ioc->pdev, bio_data(rsp->bio), blk_rq_bytes(rsp), PCI_DMA_BIDIRECTIONAL); if (!dma_addr_in) { - mpt2sas_base_free_smid(ioc, le16_to_cpu(smid)); + mpt2sas_base_free_smid(ioc, smid); goto unmap; } |