summaryrefslogtreecommitdiff
path: root/drivers/scsi/mpi3mr
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/scsi/mpi3mr')
-rw-r--r--drivers/scsi/mpi3mr/mpi/mpi30_cnfg.h52
-rw-r--r--drivers/scsi/mpi3mr/mpi/mpi30_image.h41
-rw-r--r--drivers/scsi/mpi3mr/mpi/mpi30_init.h11
-rw-r--r--drivers/scsi/mpi3mr/mpi/mpi30_ioc.h59
-rw-r--r--drivers/scsi/mpi3mr/mpi/mpi30_tool.h45
-rw-r--r--drivers/scsi/mpi3mr/mpi/mpi30_transport.h22
-rw-r--r--drivers/scsi/mpi3mr/mpi3mr.h206
-rw-r--r--drivers/scsi/mpi3mr/mpi3mr_app.c1339
-rw-r--r--drivers/scsi/mpi3mr/mpi3mr_fw.c731
-rw-r--r--drivers/scsi/mpi3mr/mpi3mr_os.c651
-rw-r--r--drivers/scsi/mpi3mr/mpi3mr_transport.c111
11 files changed, 2921 insertions, 347 deletions
diff --git a/drivers/scsi/mpi3mr/mpi/mpi30_cnfg.h b/drivers/scsi/mpi3mr/mpi/mpi30_cnfg.h
index 35f81af40f51..96401eb7e231 100644
--- a/drivers/scsi/mpi3mr/mpi/mpi30_cnfg.h
+++ b/drivers/scsi/mpi3mr/mpi/mpi30_cnfg.h
@@ -19,6 +19,7 @@
#define MPI3_CONFIG_PAGETYPE_PCIE_SWITCH (0x31)
#define MPI3_CONFIG_PAGETYPE_PCIE_LINK (0x33)
#define MPI3_CONFIG_PAGEATTR_MASK (0xf0)
+#define MPI3_CONFIG_PAGEATTR_SHIFT (4)
#define MPI3_CONFIG_PAGEATTR_READ_ONLY (0x00)
#define MPI3_CONFIG_PAGEATTR_CHANGEABLE (0x10)
#define MPI3_CONFIG_PAGEATTR_PERSISTENT (0x20)
@@ -29,10 +30,13 @@
#define MPI3_CONFIG_ACTION_READ_PERSISTENT (0x04)
#define MPI3_CONFIG_ACTION_WRITE_PERSISTENT (0x05)
#define MPI3_DEVICE_PGAD_FORM_MASK (0xf0000000)
+#define MPI3_DEVICE_PGAD_FORM_SHIFT (28)
#define MPI3_DEVICE_PGAD_FORM_GET_NEXT_HANDLE (0x00000000)
#define MPI3_DEVICE_PGAD_FORM_HANDLE (0x20000000)
#define MPI3_DEVICE_PGAD_HANDLE_MASK (0x0000ffff)
+#define MPI3_DEVICE_PGAD_HANDLE_SHIFT (0)
#define MPI3_SAS_EXPAND_PGAD_FORM_MASK (0xf0000000)
+#define MPI3_SAS_EXPAND_PGAD_FORM_SHIFT (28)
#define MPI3_SAS_EXPAND_PGAD_FORM_GET_NEXT_HANDLE (0x00000000)
#define MPI3_SAS_EXPAND_PGAD_FORM_HANDLE_PHY_NUM (0x10000000)
#define MPI3_SAS_EXPAND_PGAD_FORM_HANDLE (0x20000000)
@@ -67,6 +71,7 @@
#define MPI3_SECURITY_PGAD_SLOT_GROUP_MASK (0x0000ff00)
#define MPI3_SECURITY_PGAD_SLOT_GROUP_SHIFT (8)
#define MPI3_SECURITY_PGAD_SLOT_MASK (0x000000ff)
+#define MPI3_INSTANCE_PGAD_INSTANCE_MASK (0x0000ffff)
struct mpi3_config_request {
__le16 host_tag;
u8 ioc_use_only02;
@@ -75,7 +80,8 @@ struct mpi3_config_request {
u8 ioc_use_only06;
u8 msg_flags;
__le16 change_count;
- __le16 reserved0a;
+ u8 proxy_ioc_number;
+ u8 reserved0b;
u8 page_version;
u8 page_number;
u8 page_type;
@@ -206,6 +212,9 @@ struct mpi3_config_page_header {
#define MPI3_MFGPAGE_DEVID_SAS5116_MPI_MGMT (0x00b5)
#define MPI3_MFGPAGE_DEVID_SAS5116_NVME_MGMT (0x00b6)
#define MPI3_MFGPAGE_DEVID_SAS5116_PCIE_SWITCH (0x00b8)
+#define MPI3_MFGPAGE_DEVID_SAS5248_MPI (0x00f0)
+#define MPI3_MFGPAGE_DEVID_SAS5248_MPI_NS (0x00f1)
+#define MPI3_MFGPAGE_DEVID_SAS5248_PCIE_SWITCH (0x00f2)
struct mpi3_man_page0 {
struct mpi3_config_page_header header;
u8 chip_revision[8];
@@ -309,6 +318,7 @@ struct mpi3_man6_gpio_entry {
#define MPI3_MAN6_GPIO_EXTINT_PARAM1_FLAGS_SOURCE_GENERIC (0x00)
#define MPI3_MAN6_GPIO_EXTINT_PARAM1_FLAGS_SOURCE_CABLE_MGMT (0x10)
#define MPI3_MAN6_GPIO_EXTINT_PARAM1_FLAGS_SOURCE_ACTIVE_CABLE_OVERCURRENT (0x20)
+#define MPI3_MAN6_GPIO_EXTINT_PARAM1_FLAGS_ACK_REQUIRED (0x02)
#define MPI3_MAN6_GPIO_EXTINT_PARAM1_FLAGS_TRIGGER_MASK (0x01)
#define MPI3_MAN6_GPIO_EXTINT_PARAM1_FLAGS_TRIGGER_EDGE (0x00)
#define MPI3_MAN6_GPIO_EXTINT_PARAM1_FLAGS_TRIGGER_LEVEL (0x01)
@@ -1073,6 +1083,8 @@ struct mpi3_io_unit_page8 {
#define MPI3_IOUNIT8_SBSTATE_SVN_UPDATE_PENDING (0x04)
#define MPI3_IOUNIT8_SBSTATE_KEY_UPDATE_PENDING (0x02)
#define MPI3_IOUNIT8_SBSTATE_SECURE_BOOT_ENABLED (0x01)
+#define MPI3_IOUNIT8_SBMODE_CURRENT_KEY_IOUNIT17 (0x10)
+#define MPI3_IOUNIT8_SBMODE_HARD_SECURE_RECERTIFIED (0x08)
struct mpi3_io_unit_page9 {
struct mpi3_config_page_header header;
__le32 flags;
@@ -1088,6 +1100,8 @@ struct mpi3_io_unit_page9 {
#define MPI3_IOUNIT9_FLAGS_UBM_ENCLOSURE_ORDER_BACKPLANE_TYPE (0x00000004)
#define MPI3_IOUNIT9_FLAGS_VDFIRST_ENABLED (0x00000001)
#define MPI3_IOUNIT9_FIRSTDEVICE_UNKNOWN (0xffff)
+#define MPI3_IOUNIT9_FIRSTDEVICE_IN_DRIVER_PAGE_0 (0xfffe)
+
struct mpi3_io_unit_page10 {
struct mpi3_config_page_header header;
u8 flags;
@@ -1223,6 +1237,19 @@ struct mpi3_io_unit_page15 {
#define MPI3_IOUNIT15_FLAGS_EPRSUPPORT_WITHOUT_POWER_BRAKE_GPIO (0x01)
#define MPI3_IOUNIT15_FLAGS_EPRSUPPORT_WITH_POWER_BRAKE_GPIO (0x02)
#define MPI3_IOUNIT15_NUMPOWERBUDGETDATA_POWER_BUDGETING_DISABLED (0x00)
+
+struct mpi3_io_unit_page17 {
+ struct mpi3_config_page_header header;
+ u8 num_instances;
+ u8 instance;
+ __le16 reserved0a;
+ __le32 reserved0c[4];
+ __le16 key_length;
+ u8 encryption_algorithm;
+ u8 reserved1f;
+ __le32 current_key[];
+};
+#define MPI3_IOUNIT17_PAGEVERSION (0x00)
struct mpi3_ioc_page0 {
struct mpi3_config_page_header header;
__le32 reserved08;
@@ -1310,21 +1337,26 @@ struct mpi3_driver_page0 {
u8 tur_interval;
u8 reserved10;
u8 security_key_timeout;
- __le16 reserved12;
+ __le16 first_device;
__le32 reserved14;
__le32 reserved18;
};
#define MPI3_DRIVER0_PAGEVERSION (0x00)
+#define MPI3_DRIVER0_BSDOPTS_DEVICEEXPOSURE_DISABLE (0x00000020)
+#define MPI3_DRIVER0_BSDOPTS_WRITECACHE_DISABLE (0x00000010)
#define MPI3_DRIVER0_BSDOPTS_HEADLESS_MODE_ENABLE (0x00000008)
#define MPI3_DRIVER0_BSDOPTS_DIS_HII_CONFIG_UTIL (0x00000004)
#define MPI3_DRIVER0_BSDOPTS_REGISTRATION_MASK (0x00000003)
#define MPI3_DRIVER0_BSDOPTS_REGISTRATION_IOC_AND_DEVS (0x00000000)
#define MPI3_DRIVER0_BSDOPTS_REGISTRATION_IOC_ONLY (0x00000001)
#define MPI3_DRIVER0_BSDOPTS_REGISTRATION_IOC_AND_INTERNAL_DEVS (0x00000002)
+#define MPI3_DRIVER0_FIRSTDEVICE_IGNORE1 (0x0000)
+#define MPI3_DRIVER0_FIRSTDEVICE_IGNORE2 (0xffff)
struct mpi3_driver_page1 {
struct mpi3_config_page_header header;
__le32 flags;
- __le32 reserved0c;
+ u8 time_stamp_update;
+ u8 reserved0d[3];
__le16 host_diag_trace_max_size;
__le16 host_diag_trace_min_size;
__le16 host_diag_trace_decrement_size;
@@ -1562,16 +1594,13 @@ struct mpi3_sas_io_unit0_phy_data {
__le32 reserved10;
};
-#ifndef MPI3_SAS_IO_UNIT0_PHY_MAX
-#define MPI3_SAS_IO_UNIT0_PHY_MAX (1)
-#endif
struct mpi3_sas_io_unit_page0 {
struct mpi3_config_page_header header;
__le32 reserved08;
u8 num_phys;
u8 init_status;
__le16 reserved0e;
- struct mpi3_sas_io_unit0_phy_data phy_data[MPI3_SAS_IO_UNIT0_PHY_MAX];
+ struct mpi3_sas_io_unit0_phy_data phy_data[];
};
#define MPI3_SASIOUNIT0_PAGEVERSION (0x00)
@@ -1603,9 +1632,6 @@ struct mpi3_sas_io_unit1_phy_data {
__le32 reserved08;
};
-#ifndef MPI3_SAS_IO_UNIT1_PHY_MAX
-#define MPI3_SAS_IO_UNIT1_PHY_MAX (1)
-#endif
struct mpi3_sas_io_unit_page1 {
struct mpi3_config_page_header header;
__le16 control_flags;
@@ -1615,7 +1641,7 @@ struct mpi3_sas_io_unit_page1 {
u8 num_phys;
u8 sata_max_q_depth;
__le16 reserved12;
- struct mpi3_sas_io_unit1_phy_data phy_data[MPI3_SAS_IO_UNIT1_PHY_MAX];
+ struct mpi3_sas_io_unit1_phy_data phy_data[];
};
#define MPI3_SASIOUNIT1_PAGEVERSION (0x00)
@@ -2350,6 +2376,10 @@ struct mpi3_device0_vd_format {
#define MPI3_DEVICE0_VD_DEVICE_INFO_SAS (0x0001)
#define MPI3_DEVICE0_VD_FLAGS_IO_THROTTLE_GROUP_QD_MASK (0xf000)
#define MPI3_DEVICE0_VD_FLAGS_IO_THROTTLE_GROUP_QD_SHIFT (12)
+#define MPI3_DEVICE0_VD_FLAGS_OSEXPOSURE_MASK (0x0003)
+#define MPI3_DEVICE0_VD_FLAGS_OSEXPOSURE_HDD (0x0000)
+#define MPI3_DEVICE0_VD_FLAGS_OSEXPOSURE_SSD (0x0001)
+#define MPI3_DEVICE0_VD_FLAGS_OSEXPOSURE_NO_GUIDANCE (0x0002)
union mpi3_device0_dev_spec_format {
struct mpi3_device0_sas_sata_format sas_sata_format;
struct mpi3_device0_pcie_format pcie_format;
diff --git a/drivers/scsi/mpi3mr/mpi/mpi30_image.h b/drivers/scsi/mpi3mr/mpi/mpi30_image.h
index 47035b811902..8d824107a678 100644
--- a/drivers/scsi/mpi3mr/mpi/mpi30_image.h
+++ b/drivers/scsi/mpi3mr/mpi/mpi30_image.h
@@ -66,7 +66,12 @@ struct mpi3_component_image_header {
#define MPI3_IMAGE_HEADER_SIGNATURE1_SMM (0x204d4d53)
#define MPI3_IMAGE_HEADER_SIGNATURE1_PSW (0x20575350)
#define MPI3_IMAGE_HEADER_SIGNATURE2_VALUE (0x50584546)
+#define MPI3_IMAGE_HEADER_FLAGS_SIGNED_UEFI_MASK (0x00000300)
+#define MPI3_IMAGE_HEADER_FLAGS_SIGNED_UEFI_SHIFT (8)
+#define MPI3_IMAGE_HEADER_FLAGS_CERT_CHAIN_FORMAT_MASK (0x000000c0)
+#define MPI3_IMAGE_HEADER_FLAGS_CERT_CHAIN_FORMAT_SHIFT (6)
#define MPI3_IMAGE_HEADER_FLAGS_DEVICE_KEY_BASIS_MASK (0x00000030)
+#define MPI3_IMAGE_HEADER_FLAGS_DEVICE_KEY_BASIS_SHIFT (4)
#define MPI3_IMAGE_HEADER_FLAGS_DEVICE_KEY_BASIS_CDI (0x00000000)
#define MPI3_IMAGE_HEADER_FLAGS_DEVICE_KEY_BASIS_DI (0x00000010)
#define MPI3_IMAGE_HEADER_FLAGS_SIGNED_NVDATA (0x00000008)
@@ -198,25 +203,29 @@ struct mpi3_supported_devices_data {
struct mpi3_supported_device supported_device[MPI3_SUPPORTED_DEVICE_MAX];
};
-#ifndef MPI3_ENCRYPTED_HASH_MAX
-#define MPI3_ENCRYPTED_HASH_MAX (1)
+#ifndef MPI3_PUBLIC_KEY_MAX
+#define MPI3_PUBLIC_KEY_MAX (1)
#endif
struct mpi3_encrypted_hash_entry {
u8 hash_image_type;
u8 hash_algorithm;
u8 encryption_algorithm;
- u8 reserved03;
- __le32 reserved04;
- __le32 encrypted_hash[MPI3_ENCRYPTED_HASH_MAX];
+ u8 flags;
+ __le16 public_key_size;
+ __le16 signature_size;
+ __le32 public_key[MPI3_PUBLIC_KEY_MAX];
};
-
-#define MPI3_HASH_IMAGE_TYPE_KEY_WITH_SIGNATURE (0x03)
+#define MPI3_HASH_IMAGE_TYPE_KEY_WITH_HASH (0x03)
+#define MPI3_HASH_IMAGE_TYPE_KEY_WITH_HASH_1_OF_2 (0x04)
+#define MPI3_HASH_IMAGE_TYPE_KEY_WITH_HASH_2_OF_2 (0x05)
#define MPI3_HASH_ALGORITHM_VERSION_MASK (0xe0)
+#define MPI3_HASH_ALGORITHM_VERSION_SHIFT (5)
#define MPI3_HASH_ALGORITHM_VERSION_NONE (0x00)
#define MPI3_HASH_ALGORITHM_VERSION_SHA1 (0x20)
#define MPI3_HASH_ALGORITHM_VERSION_SHA2 (0x40)
#define MPI3_HASH_ALGORITHM_VERSION_SHA3 (0x60)
#define MPI3_HASH_ALGORITHM_SIZE_MASK (0x1f)
+#define MPI3_HASH_ALGORITHM_SIZE_SHIFT (0)
#define MPI3_HASH_ALGORITHM_SIZE_UNUSED (0x00)
#define MPI3_HASH_ALGORITHM_SIZE_SHA256 (0x01)
#define MPI3_HASH_ALGORITHM_SIZE_SHA512 (0x02)
@@ -228,17 +237,13 @@ struct mpi3_encrypted_hash_entry {
#define MPI3_ENCRYPTION_ALGORITHM_RSA2048 (0x04)
#define MPI3_ENCRYPTION_ALGORITHM_RSA4096 (0x05)
#define MPI3_ENCRYPTION_ALGORITHM_RSA3072 (0x06)
-#ifndef MPI3_PUBLIC_KEY_MAX
-#define MPI3_PUBLIC_KEY_MAX (1)
-#endif
-struct mpi3_encrypted_key_with_hash_entry {
- u8 hash_image_type;
- u8 hash_algorithm;
- u8 encryption_algorithm;
- u8 reserved03;
- __le32 reserved04;
- __le32 public_key[MPI3_PUBLIC_KEY_MAX];
-};
+
+/* hierarchical signature system (hss) */
+#define MPI3_ENCRYPTION_ALGORITHM_ML_DSA_87 (0x0b)
+#define MPI3_ENCRYPTION_ALGORITHM_ML_DSA_65 (0x0c)
+#define MPI3_ENCRYPTION_ALGORITHM_ML_DSA_44 (0x0d)
+#define MPI3_ENCRYPTED_HASH_ENTRY_FLAGS_PAIRED_KEY_MASK (0x0f)
+#define MPI3_ENCRYPTED_HASH_ENTRY_FLAGS_PAIRED_KEY_SHIFT (0)
#ifndef MPI3_ENCRYPTED_HASH_ENTRY_MAX
#define MPI3_ENCRYPTED_HASH_ENTRY_MAX (1)
diff --git a/drivers/scsi/mpi3mr/mpi/mpi30_init.h b/drivers/scsi/mpi3mr/mpi/mpi30_init.h
index af86d12c8e49..bbef5bac92ed 100644
--- a/drivers/scsi/mpi3mr/mpi/mpi30_init.h
+++ b/drivers/scsi/mpi3mr/mpi/mpi30_init.h
@@ -38,23 +38,31 @@ struct mpi3_scsi_io_request {
#define MPI3_SCSIIO_MSGFLAGS_METASGL_VALID (0x80)
#define MPI3_SCSIIO_MSGFLAGS_DIVERT_TO_FIRMWARE (0x40)
#define MPI3_SCSIIO_FLAGS_LARGE_CDB (0x60000000)
+#define MPI3_SCSIIO_FLAGS_LARGE_CDB_MASK (0x60000000)
+#define MPI3_SCSIIO_FLAGS_LARGE_CDB_SHIFT (29)
+#define MPI3_SCSIIO_FLAGS_IOC_USE_ONLY_27_MASK (0x18000000)
+#define MPI3_SCSIIO_FLAGS_IOC_USE_ONLY_27_SHIFT (27)
#define MPI3_SCSIIO_FLAGS_CDB_16_OR_LESS (0x00000000)
#define MPI3_SCSIIO_FLAGS_CDB_GREATER_THAN_16 (0x20000000)
#define MPI3_SCSIIO_FLAGS_CDB_IN_SEPARATE_BUFFER (0x40000000)
#define MPI3_SCSIIO_FLAGS_TASKATTRIBUTE_MASK (0x07000000)
+#define MPI3_SCSIIO_FLAGS_TASKATTRIBUTE_SHIFT (24)
+#define MPI3_SCSIIO_FLAGS_DATADIRECTION_MASK (0x000c0000)
+#define MPI3_SCSIIO_FLAGS_DATADIRECTION_SHIFT (18)
#define MPI3_SCSIIO_FLAGS_TASKATTRIBUTE_SIMPLEQ (0x00000000)
#define MPI3_SCSIIO_FLAGS_TASKATTRIBUTE_HEADOFQ (0x01000000)
#define MPI3_SCSIIO_FLAGS_TASKATTRIBUTE_ORDEREDQ (0x02000000)
#define MPI3_SCSIIO_FLAGS_TASKATTRIBUTE_ACAQ (0x04000000)
#define MPI3_SCSIIO_FLAGS_CMDPRI_MASK (0x00f00000)
#define MPI3_SCSIIO_FLAGS_CMDPRI_SHIFT (20)
-#define MPI3_SCSIIO_FLAGS_DATADIRECTION_MASK (0x000c0000)
#define MPI3_SCSIIO_FLAGS_DATADIRECTION_NO_DATA_TRANSFER (0x00000000)
#define MPI3_SCSIIO_FLAGS_DATADIRECTION_WRITE (0x00040000)
#define MPI3_SCSIIO_FLAGS_DATADIRECTION_READ (0x00080000)
#define MPI3_SCSIIO_FLAGS_DMAOPERATION_MASK (0x00030000)
+#define MPI3_SCSIIO_FLAGS_DMAOPERATION_SHIFT (16)
#define MPI3_SCSIIO_FLAGS_DMAOPERATION_HOST_PI (0x00010000)
#define MPI3_SCSIIO_FLAGS_DIVERT_REASON_MASK (0x000000f0)
+#define MPI3_SCSIIO_FLAGS_DIVERT_REASON_SHIFT (4)
#define MPI3_SCSIIO_FLAGS_DIVERT_REASON_IO_THROTTLING (0x00000010)
#define MPI3_SCSIIO_FLAGS_DIVERT_REASON_WRITE_SAME_TOO_LARGE (0x00000020)
#define MPI3_SCSIIO_FLAGS_DIVERT_REASON_PROD_SPECIFIC (0x00000080)
@@ -99,6 +107,7 @@ struct mpi3_scsi_io_reply {
#define MPI3_SCSI_STATUS_ACA_ACTIVE (0x30)
#define MPI3_SCSI_STATUS_TASK_ABORTED (0x40)
#define MPI3_SCSI_STATE_SENSE_MASK (0x03)
+#define MPI3_SCSI_STATE_SENSE_SHIFT (0)
#define MPI3_SCSI_STATE_SENSE_VALID (0x00)
#define MPI3_SCSI_STATE_SENSE_FAILED (0x01)
#define MPI3_SCSI_STATE_SENSE_BUFF_Q_EMPTY (0x02)
diff --git a/drivers/scsi/mpi3mr/mpi/mpi30_ioc.h b/drivers/scsi/mpi3mr/mpi/mpi30_ioc.h
index 0cb24fc03620..b42933fcd423 100644
--- a/drivers/scsi/mpi3mr/mpi/mpi30_ioc.h
+++ b/drivers/scsi/mpi3mr/mpi/mpi30_ioc.h
@@ -27,9 +27,10 @@ struct mpi3_ioc_init_request {
__le64 sense_buffer_free_queue_address;
__le64 driver_information_address;
};
-
+#define MPI3_IOCINIT_MSGFLAGS_WRITESAMEDIVERT_SUPPORTED (0x08)
#define MPI3_IOCINIT_MSGFLAGS_SCSIIOSTATUSREPLY_SUPPORTED (0x04)
#define MPI3_IOCINIT_MSGFLAGS_HOSTMETADATA_MASK (0x03)
+#define MPI3_IOCINIT_MSGFLAGS_HOSTMETADATA_SHIFT (0)
#define MPI3_IOCINIT_MSGFLAGS_HOSTMETADATA_NOT_USED (0x00)
#define MPI3_IOCINIT_MSGFLAGS_HOSTMETADATA_SEPARATED (0x01)
#define MPI3_IOCINIT_MSGFLAGS_HOSTMETADATA_INLINE (0x02)
@@ -39,6 +40,13 @@ struct mpi3_ioc_init_request {
#define MPI3_WHOINIT_HOST_DRIVER (0x03)
#define MPI3_WHOINIT_MANUFACTURER (0x04)
+#define MPI3_IOCINIT_DRIVERCAP_OSEXPOSURE_MASK (0x00000003)
+#define MPI3_IOCINIT_DRIVERCAP_OSEXPOSURE_SHIFT (0)
+#define MPI3_IOCINIT_DRIVERCAP_OSEXPOSURE_NO_GUIDANCE (0x00000000)
+#define MPI3_IOCINIT_DRIVERCAP_OSEXPOSURE_NO_SPECIAL (0x00000001)
+#define MPI3_IOCINIT_DRIVERCAP_OSEXPOSURE_REPORT_AS_HDD (0x00000002)
+#define MPI3_IOCINIT_DRIVERCAP_OSEXPOSURE_REPORT_AS_SSD (0x00000003)
+
struct mpi3_ioc_facts_request {
__le16 host_tag;
u8 ioc_use_only02;
@@ -101,20 +109,24 @@ struct mpi3_ioc_facts_data {
__le16 max_io_throttle_group;
__le16 io_throttle_low;
__le16 io_throttle_high;
+ __le32 diag_fdl_size;
+ __le32 diag_tty_size;
};
#define MPI3_IOCFACTS_CAPABILITY_NON_SUPERVISOR_MASK (0x80000000)
+#define MPI3_IOCFACTS_CAPABILITY_NON_SUPERVISOR_SHIFT (31)
#define MPI3_IOCFACTS_CAPABILITY_SUPERVISOR_IOC (0x00000000)
#define MPI3_IOCFACTS_CAPABILITY_NON_SUPERVISOR_IOC (0x80000000)
#define MPI3_IOCFACTS_CAPABILITY_INT_COALESCE_MASK (0x00000600)
+#define MPI3_IOCFACTS_CAPABILITY_INT_COALESCE_SHIFT (9)
#define MPI3_IOCFACTS_CAPABILITY_INT_COALESCE_FIXED_THRESHOLD (0x00000000)
#define MPI3_IOCFACTS_CAPABILITY_INT_COALESCE_OUTSTANDING_IO (0x00000200)
-#define MPI3_IOCFACTS_CAPABILITY_COMPLETE_RESET_CAPABLE (0x00000100)
-#define MPI3_IOCFACTS_CAPABILITY_SEG_DIAG_TRACE_ENABLED (0x00000080)
-#define MPI3_IOCFACTS_CAPABILITY_SEG_DIAG_FW_ENABLED (0x00000040)
-#define MPI3_IOCFACTS_CAPABILITY_SEG_DIAG_DRIVER_ENABLED (0x00000020)
-#define MPI3_IOCFACTS_CAPABILITY_ADVANCED_HOST_PD_ENABLED (0x00000010)
-#define MPI3_IOCFACTS_CAPABILITY_RAID_CAPABLE (0x00000008)
-#define MPI3_IOCFACTS_CAPABILITY_MULTIPATH_ENABLED (0x00000002)
+#define MPI3_IOCFACTS_CAPABILITY_COMPLETE_RESET_SUPPORTED (0x00000100)
+#define MPI3_IOCFACTS_CAPABILITY_SEG_DIAG_TRACE_SUPPORTED (0x00000080)
+#define MPI3_IOCFACTS_CAPABILITY_SEG_DIAG_FW_SUPPORTED (0x00000040)
+#define MPI3_IOCFACTS_CAPABILITY_SEG_DIAG_DRIVER_SUPPORTED (0x00000020)
+#define MPI3_IOCFACTS_CAPABILITY_ADVANCED_HOST_PD_SUPPORTED (0x00000010)
+#define MPI3_IOCFACTS_CAPABILITY_RAID_SUPPORTED (0x00000008)
+#define MPI3_IOCFACTS_CAPABILITY_MULTIPATH_SUPPORTED (0x00000002)
#define MPI3_IOCFACTS_CAPABILITY_COALESCE_CTRL_SUPPORTED (0x00000001)
#define MPI3_IOCFACTS_PID_TYPE_MASK (0xf000)
#define MPI3_IOCFACTS_PID_TYPE_SHIFT (12)
@@ -126,6 +138,7 @@ struct mpi3_ioc_facts_data {
#define MPI3_IOCFACTS_EXCEPT_SAS_DISABLED (0x1000)
#define MPI3_IOCFACTS_EXCEPT_SAFE_MODE (0x0800)
#define MPI3_IOCFACTS_EXCEPT_SECURITY_KEY_MASK (0x0700)
+#define MPI3_IOCFACTS_EXCEPT_SECURITY_KEY_SHIFT (8)
#define MPI3_IOCFACTS_EXCEPT_SECURITY_KEY_NONE (0x0000)
#define MPI3_IOCFACTS_EXCEPT_SECURITY_KEY_LOCAL_VIA_MGMT (0x0100)
#define MPI3_IOCFACTS_EXCEPT_SECURITY_KEY_EXT_VIA_MGMT (0x0200)
@@ -138,7 +151,10 @@ struct mpi3_ioc_facts_data {
#define MPI3_IOCFACTS_EXCEPT_MANUFACT_CHECKSUM_FAIL (0x0020)
#define MPI3_IOCFACTS_EXCEPT_FW_CHECKSUM_FAIL (0x0010)
#define MPI3_IOCFACTS_EXCEPT_CONFIG_CHECKSUM_FAIL (0x0008)
+#define MPI3_IOCFACTS_EXCEPT_BLOCKING_BOOT_EVENT (0x0004)
+#define MPI3_IOCFACTS_EXCEPT_SECURITY_SELFTEST_FAILURE (0x0002)
#define MPI3_IOCFACTS_EXCEPT_BOOTSTAT_MASK (0x0001)
+#define MPI3_IOCFACTS_EXCEPT_BOOTSTAT_SHIFT (0)
#define MPI3_IOCFACTS_EXCEPT_BOOTSTAT_PRIMARY (0x0000)
#define MPI3_IOCFACTS_EXCEPT_BOOTSTAT_SECONDARY (0x0001)
#define MPI3_IOCFACTS_PROTOCOL_SAS (0x0010)
@@ -151,14 +167,18 @@ struct mpi3_ioc_facts_data {
#define MPI3_IOCFACTS_FLAGS_DMA_ADDRESS_WIDTH_MASK (0x0000ff00)
#define MPI3_IOCFACTS_FLAGS_DMA_ADDRESS_WIDTH_SHIFT (8)
#define MPI3_IOCFACTS_FLAGS_INITIAL_PORT_ENABLE_MASK (0x00000030)
+#define MPI3_IOCFACTS_FLAGS_INITIAL_PORT_ENABLE_SHIFT (4)
#define MPI3_IOCFACTS_FLAGS_INITIAL_PORT_ENABLE_NOT_STARTED (0x00000000)
#define MPI3_IOCFACTS_FLAGS_INITIAL_PORT_ENABLE_IN_PROGRESS (0x00000010)
#define MPI3_IOCFACTS_FLAGS_INITIAL_PORT_ENABLE_COMPLETE (0x00000020)
#define MPI3_IOCFACTS_FLAGS_PERSONALITY_MASK (0x0000000f)
+#define MPI3_IOCFACTS_FLAGS_PERSONALITY_SHIFT (0)
#define MPI3_IOCFACTS_FLAGS_PERSONALITY_EHBA (0x00000000)
#define MPI3_IOCFACTS_FLAGS_PERSONALITY_RAID_DDR (0x00000002)
#define MPI3_IOCFACTS_IO_THROTTLE_DATA_LENGTH_NOT_REQUIRED (0x0000)
#define MPI3_IOCFACTS_MAX_IO_THROTTLE_GROUP_NOT_REQUIRED (0x0000)
+#define MPI3_IOCFACTS_DIAGFDLSIZE_NOT_SUPPORTED (0x00000000)
+#define MPI3_IOCFACTS_DIAGTTYSIZE_NOT_SUPPORTED (0x00000000)
struct mpi3_mgmt_passthrough_request {
__le16 host_tag;
u8 ioc_use_only02;
@@ -192,6 +212,7 @@ struct mpi3_create_request_queue_request {
};
#define MPI3_CREATE_REQUEST_QUEUE_FLAGS_SEGMENTED_MASK (0x80)
+#define MPI3_CREATE_REQUEST_QUEUE_FLAGS_SEGMENTED_SHIFT (7)
#define MPI3_CREATE_REQUEST_QUEUE_FLAGS_SEGMENTED_SEGMENTED (0x80)
#define MPI3_CREATE_REQUEST_QUEUE_FLAGS_SEGMENTED_CONTIGUOUS (0x00)
#define MPI3_CREATE_REQUEST_QUEUE_SIZE_MINIMUM (2)
@@ -225,10 +246,12 @@ struct mpi3_create_reply_queue_request {
};
#define MPI3_CREATE_REPLY_QUEUE_FLAGS_SEGMENTED_MASK (0x80)
+#define MPI3_CREATE_REPLY_QUEUE_FLAGS_SEGMENTED_SHIFT (7)
#define MPI3_CREATE_REPLY_QUEUE_FLAGS_SEGMENTED_SEGMENTED (0x80)
#define MPI3_CREATE_REPLY_QUEUE_FLAGS_SEGMENTED_CONTIGUOUS (0x00)
#define MPI3_CREATE_REPLY_QUEUE_FLAGS_COALESCE_DISABLE (0x02)
#define MPI3_CREATE_REPLY_QUEUE_FLAGS_INT_ENABLE_MASK (0x01)
+#define MPI3_CREATE_REPLY_QUEUE_FLAGS_INT_ENABLE_SHIFT (0)
#define MPI3_CREATE_REPLY_QUEUE_FLAGS_INT_ENABLE_DISABLE (0x00)
#define MPI3_CREATE_REPLY_QUEUE_FLAGS_INT_ENABLE_ENABLE (0x01)
#define MPI3_CREATE_REPLY_QUEUE_SIZE_MINIMUM (2)
@@ -314,9 +337,11 @@ struct mpi3_event_notification_reply {
};
#define MPI3_EVENT_NOTIFY_MSGFLAGS_ACK_MASK (0x01)
+#define MPI3_EVENT_NOTIFY_MSGFLAGS_ACK_SHIFT (0)
#define MPI3_EVENT_NOTIFY_MSGFLAGS_ACK_REQUIRED (0x01)
#define MPI3_EVENT_NOTIFY_MSGFLAGS_ACK_NOT_REQUIRED (0x00)
#define MPI3_EVENT_NOTIFY_MSGFLAGS_EVENT_ORIGINALITY_MASK (0x02)
+#define MPI3_EVENT_NOTIFY_MSGFLAGS_EVENT_ORIGINALITY_SHIFT (1)
#define MPI3_EVENT_NOTIFY_MSGFLAGS_EVENT_ORIGINALITY_ORIGINAL (0x00)
#define MPI3_EVENT_NOTIFY_MSGFLAGS_EVENT_ORIGINALITY_REPLAY (0x02)
struct mpi3_event_data_gpio_interrupt {
@@ -449,9 +474,6 @@ struct mpi3_event_data_sas_notify_primitive {
#define MPI3_EVENT_NOTIFY_PRIMITIVE_POWER_LOSS_EXPECTED (0x02)
#define MPI3_EVENT_NOTIFY_PRIMITIVE_RESERVED1 (0x03)
#define MPI3_EVENT_NOTIFY_PRIMITIVE_RESERVED2 (0x04)
-#ifndef MPI3_EVENT_SAS_TOPO_PHY_COUNT
-#define MPI3_EVENT_SAS_TOPO_PHY_COUNT (1)
-#endif
struct mpi3_event_sas_topo_phy_entry {
__le16 attached_dev_handle;
u8 link_rate;
@@ -478,6 +500,7 @@ struct mpi3_event_sas_topo_phy_entry {
#define MPI3_EVENT_SAS_TOPO_PHY_STATUS_NO_EXIST (0x40)
#define MPI3_EVENT_SAS_TOPO_PHY_STATUS_VACANT (0x80)
#define MPI3_EVENT_SAS_TOPO_PHY_RC_MASK (0x0f)
+#define MPI3_EVENT_SAS_TOPO_PHY_RC_SHIFT (0)
#define MPI3_EVENT_SAS_TOPO_PHY_RC_TARG_NOT_RESPONDING (0x02)
#define MPI3_EVENT_SAS_TOPO_PHY_RC_PHY_CHANGED (0x03)
#define MPI3_EVENT_SAS_TOPO_PHY_RC_NO_CHANGE (0x04)
@@ -492,7 +515,7 @@ struct mpi3_event_data_sas_topology_change_list {
u8 start_phy_num;
u8 exp_status;
u8 io_unit_port;
- struct mpi3_event_sas_topo_phy_entry phy_entry[MPI3_EVENT_SAS_TOPO_PHY_COUNT];
+ struct mpi3_event_sas_topo_phy_entry phy_entry[] __counted_by(num_entries);
};
#define MPI3_EVENT_SAS_TOPO_ES_NO_EXPANDER (0x00)
@@ -541,9 +564,6 @@ struct mpi3_event_data_pcie_enumeration {
#define MPI3_EVENT_PCIE_ENUM_ES_MAX_SWITCHES_EXCEED (0x40000000)
#define MPI3_EVENT_PCIE_ENUM_ES_MAX_DEVICES_EXCEED (0x20000000)
#define MPI3_EVENT_PCIE_ENUM_ES_RESOURCES_EXHAUSTED (0x10000000)
-#ifndef MPI3_EVENT_PCIE_TOPO_PORT_COUNT
-#define MPI3_EVENT_PCIE_TOPO_PORT_COUNT (1)
-#endif
struct mpi3_event_pcie_topo_port_entry {
__le16 attached_dev_handle;
u8 port_status;
@@ -560,6 +580,7 @@ struct mpi3_event_pcie_topo_port_entry {
#define MPI3_EVENT_PCIE_TOPO_PS_DELAY_NOT_RESPONDING (0x05)
#define MPI3_EVENT_PCIE_TOPO_PS_RESPONDING (0x06)
#define MPI3_EVENT_PCIE_TOPO_PI_LANES_MASK (0xf0)
+#define MPI3_EVENT_PCIE_TOPO_PI_LANES_SHIFT (4)
#define MPI3_EVENT_PCIE_TOPO_PI_LANES_UNKNOWN (0x00)
#define MPI3_EVENT_PCIE_TOPO_PI_LANES_1 (0x10)
#define MPI3_EVENT_PCIE_TOPO_PI_LANES_2 (0x20)
@@ -567,6 +588,7 @@ struct mpi3_event_pcie_topo_port_entry {
#define MPI3_EVENT_PCIE_TOPO_PI_LANES_8 (0x40)
#define MPI3_EVENT_PCIE_TOPO_PI_LANES_16 (0x50)
#define MPI3_EVENT_PCIE_TOPO_PI_RATE_MASK (0x0f)
+#define MPI3_EVENT_PCIE_TOPO_PI_RATE_SHIFT (0)
#define MPI3_EVENT_PCIE_TOPO_PI_RATE_UNKNOWN (0x00)
#define MPI3_EVENT_PCIE_TOPO_PI_RATE_DISABLED (0x01)
#define MPI3_EVENT_PCIE_TOPO_PI_RATE_2_5 (0x02)
@@ -584,7 +606,7 @@ struct mpi3_event_data_pcie_topology_change_list {
u8 switch_status;
u8 io_unit_port;
__le32 reserved0c;
- struct mpi3_event_pcie_topo_port_entry port_entry[MPI3_EVENT_PCIE_TOPO_PORT_COUNT];
+ struct mpi3_event_pcie_topo_port_entry port_entry[] __counted_by(num_entries);
};
#define MPI3_EVENT_PCIE_TOPO_SS_NO_PCIE_SWITCH (0x00)
@@ -875,6 +897,7 @@ struct mpi3_pel_req_action_acknowledge {
};
#define MPI3_PELACKNOWLEDGE_MSGFLAGS_SAFE_MODE_EXIT_MASK (0x03)
+#define MPI3_PELACKNOWLEDGE_MSGFLAGS_SAFE_MODE_EXIT_SHIFT (0)
#define MPI3_PELACKNOWLEDGE_MSGFLAGS_SAFE_MODE_EXIT_NO_GUIDANCE (0x00)
#define MPI3_PELACKNOWLEDGE_MSGFLAGS_SAFE_MODE_EXIT_CONTINUE_OP (0x01)
#define MPI3_PELACKNOWLEDGE_MSGFLAGS_SAFE_MODE_EXIT_TRANSITION_TO_FAULT (0x02)
@@ -918,6 +941,7 @@ struct mpi3_ci_download_request {
#define MPI3_CI_DOWNLOAD_MSGFLAGS_FORCE_FMC_ENABLE (0x40)
#define MPI3_CI_DOWNLOAD_MSGFLAGS_SIGNED_NVDATA (0x20)
#define MPI3_CI_DOWNLOAD_MSGFLAGS_WRITE_CACHE_FLUSH_MASK (0x03)
+#define MPI3_CI_DOWNLOAD_MSGFLAGS_WRITE_CACHE_FLUSH_SHIFT (0)
#define MPI3_CI_DOWNLOAD_MSGFLAGS_WRITE_CACHE_FLUSH_FAST (0x00)
#define MPI3_CI_DOWNLOAD_MSGFLAGS_WRITE_CACHE_FLUSH_MEDIUM (0x01)
#define MPI3_CI_DOWNLOAD_MSGFLAGS_WRITE_CACHE_FLUSH_SLOW (0x02)
@@ -947,6 +971,7 @@ struct mpi3_ci_download_reply {
#define MPI3_CI_DOWNLOAD_FLAGS_OFFLINE_ACTIVATION_REQUIRED (0x20)
#define MPI3_CI_DOWNLOAD_FLAGS_KEY_UPDATE_PENDING (0x10)
#define MPI3_CI_DOWNLOAD_FLAGS_ACTIVATION_STATUS_MASK (0x0e)
+#define MPI3_CI_DOWNLOAD_FLAGS_ACTIVATION_STATUS_SHIFT (1)
#define MPI3_CI_DOWNLOAD_FLAGS_ACTIVATION_STATUS_NOT_NEEDED (0x00)
#define MPI3_CI_DOWNLOAD_FLAGS_ACTIVATION_STATUS_AWAITING (0x02)
#define MPI3_CI_DOWNLOAD_FLAGS_ACTIVATION_STATUS_ONLINE_PENDING (0x04)
@@ -970,9 +995,11 @@ struct mpi3_ci_upload_request {
};
#define MPI3_CI_UPLOAD_MSGFLAGS_LOCATION_MASK (0x01)
+#define MPI3_CI_UPLOAD_MSGFLAGS_LOCATION_SHIFT (0)
#define MPI3_CI_UPLOAD_MSGFLAGS_LOCATION_PRIMARY (0x00)
#define MPI3_CI_UPLOAD_MSGFLAGS_LOCATION_SECONDARY (0x01)
#define MPI3_CI_UPLOAD_MSGFLAGS_FORMAT_MASK (0x02)
+#define MPI3_CI_UPLOAD_MSGFLAGS_FORMAT_SHIFT (1)
#define MPI3_CI_UPLOAD_MSGFLAGS_FORMAT_FLASH (0x00)
#define MPI3_CI_UPLOAD_MSGFLAGS_FORMAT_EXECUTABLE (0x02)
#define MPI3_CTRL_OP_FORCE_FULL_DISCOVERY (0x01)
diff --git a/drivers/scsi/mpi3mr/mpi/mpi30_tool.h b/drivers/scsi/mpi3mr/mpi/mpi30_tool.h
new file mode 100644
index 000000000000..50a65b16a818
--- /dev/null
+++ b/drivers/scsi/mpi3mr/mpi/mpi30_tool.h
@@ -0,0 +1,45 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+/*
+ * Copyright 2016-2024 Broadcom Inc. All rights reserved.
+ */
+#ifndef MPI30_TOOL_H
+#define MPI30_TOOL_H 1
+
+#define MPI3_DIAG_BUFFER_TYPE_TRACE (0x01)
+#define MPI3_DIAG_BUFFER_TYPE_FW (0x02)
+#define MPI3_DIAG_BUFFER_ACTION_RELEASE (0x01)
+
+#define MPI3_DIAG_BUFFER_POST_MSGFLAGS_SEGMENTED (0x01)
+struct mpi3_diag_buffer_post_request {
+ __le16 host_tag;
+ u8 ioc_use_only02;
+ u8 function;
+ __le16 ioc_use_only04;
+ u8 ioc_use_only06;
+ u8 msg_flags;
+ __le16 change_count;
+ __le16 reserved0a;
+ u8 type;
+ u8 reserved0d;
+ __le16 reserved0e;
+ __le64 address;
+ __le32 length;
+ __le32 reserved1c;
+};
+
+struct mpi3_diag_buffer_manage_request {
+ __le16 host_tag;
+ u8 ioc_use_only02;
+ u8 function;
+ __le16 ioc_use_only04;
+ u8 ioc_use_only06;
+ u8 msg_flags;
+ __le16 change_count;
+ __le16 reserved0a;
+ u8 type;
+ u8 action;
+ __le16 reserved0e;
+};
+
+
+#endif
diff --git a/drivers/scsi/mpi3mr/mpi/mpi30_transport.h b/drivers/scsi/mpi3mr/mpi/mpi30_transport.h
index 1e0a3dcaf723..5c522e2531c3 100644
--- a/drivers/scsi/mpi3mr/mpi/mpi30_transport.h
+++ b/drivers/scsi/mpi3mr/mpi/mpi30_transport.h
@@ -18,7 +18,7 @@ union mpi3_version_union {
#define MPI3_VERSION_MAJOR (3)
#define MPI3_VERSION_MINOR (0)
-#define MPI3_VERSION_UNIT (28)
+#define MPI3_VERSION_UNIT (35)
#define MPI3_VERSION_DEV (0)
#define MPI3_DEVHANDLE_INVALID (0xffff)
struct mpi3_sysif_oper_queue_indexes {
@@ -80,6 +80,7 @@ struct mpi3_sysif_registers {
#define MPI3_SYSIF_IOC_CONFIG_OPER_RPY_ENT_SZ_SHIFT (20)
#define MPI3_SYSIF_IOC_CONFIG_OPER_REQ_ENT_SZ (0x000f0000)
#define MPI3_SYSIF_IOC_CONFIG_OPER_REQ_ENT_SZ_SHIFT (16)
+#define MPI3_SYSIF_IOC_CONFIG_SHUTDOWN_SHIFT (14)
#define MPI3_SYSIF_IOC_CONFIG_SHUTDOWN_MASK (0x0000c000)
#define MPI3_SYSIF_IOC_CONFIG_SHUTDOWN_NO (0x00000000)
#define MPI3_SYSIF_IOC_CONFIG_SHUTDOWN_NORMAL (0x00004000)
@@ -97,6 +98,7 @@ struct mpi3_sysif_registers {
#define MPI3_SYSIF_IOC_STATUS_READY (0x00000001)
#define MPI3_SYSIF_ADMIN_Q_NUM_ENTRIES_OFFSET (0x00000024)
#define MPI3_SYSIF_ADMIN_Q_NUM_ENTRIES_REQ_MASK (0x0fff)
+#define MPI3_SYSIF_ADMIN_Q_NUM_ENTRIES_REQ_SHIFT (0)
#define MPI3_SYSIF_ADMIN_Q_NUM_ENTRIES_REPLY_OFFSET (0x00000026)
#define MPI3_SYSIF_ADMIN_Q_NUM_ENTRIES_REPLY_MASK (0x0fff0000)
#define MPI3_SYSIF_ADMIN_Q_NUM_ENTRIES_REPLY_SHIFT (16)
@@ -106,6 +108,7 @@ struct mpi3_sysif_registers {
#define MPI3_SYSIF_ADMIN_REPLY_Q_ADDR_HIGH_OFFSET (0x00000034)
#define MPI3_SYSIF_COALESCE_CONTROL_OFFSET (0x00000040)
#define MPI3_SYSIF_COALESCE_CONTROL_ENABLE_MASK (0xc0000000)
+#define MPI3_SYSIF_COALESCE_CONTROL_ENABLE_SHIFT (30)
#define MPI3_SYSIF_COALESCE_CONTROL_ENABLE_NO_CHANGE (0x00000000)
#define MPI3_SYSIF_COALESCE_CONTROL_ENABLE_DISABLE (0x40000000)
#define MPI3_SYSIF_COALESCE_CONTROL_ENABLE_ENABLE (0xc0000000)
@@ -124,6 +127,7 @@ struct mpi3_sysif_registers {
#define MPI3_SYSIF_OPER_REPLY_Q_N_CI_OFFSET(N) (MPI3_SYSIF_OPER_REPLY_Q_CI_OFFSET + (((N) - 1) * 8))
#define MPI3_SYSIF_WRITE_SEQUENCE_OFFSET (0x00001c04)
#define MPI3_SYSIF_WRITE_SEQUENCE_KEY_VALUE_MASK (0x0000000f)
+#define MPI3_SYSIF_WRITE_SEQUENCE_KEY_VALUE_SHIFT (0)
#define MPI3_SYSIF_WRITE_SEQUENCE_KEY_VALUE_FLUSH (0x0)
#define MPI3_SYSIF_WRITE_SEQUENCE_KEY_VALUE_1ST (0xf)
#define MPI3_SYSIF_WRITE_SEQUENCE_KEY_VALUE_2ND (0x4)
@@ -133,6 +137,7 @@ struct mpi3_sysif_registers {
#define MPI3_SYSIF_WRITE_SEQUENCE_KEY_VALUE_6TH (0xd)
#define MPI3_SYSIF_HOST_DIAG_OFFSET (0x00001c08)
#define MPI3_SYSIF_HOST_DIAG_RESET_ACTION_MASK (0x00000700)
+#define MPI3_SYSIF_HOST_DIAG_RESET_ACTION_SHIFT (8)
#define MPI3_SYSIF_HOST_DIAG_RESET_ACTION_NO_RESET (0x00000000)
#define MPI3_SYSIF_HOST_DIAG_RESET_ACTION_SOFT_RESET (0x00000100)
#define MPI3_SYSIF_HOST_DIAG_RESET_ACTION_HOST_CONTROL_BOOT_RESET (0x00000200)
@@ -151,6 +156,7 @@ struct mpi3_sysif_registers {
#define MPI3_SYSIF_FAULT_FUNC_AREA_SHIFT (24)
#define MPI3_SYSIF_FAULT_FUNC_AREA_MPI_DEFINED (0x00000000)
#define MPI3_SYSIF_FAULT_CODE_MASK (0x0000ffff)
+#define MPI3_SYSIF_FAULT_CODE_SHIFT (0)
#define MPI3_SYSIF_FAULT_CODE_DIAG_FAULT_RESET (0x0000f000)
#define MPI3_SYSIF_FAULT_CODE_CI_ACTIVATION_RESET (0x0000f001)
#define MPI3_SYSIF_FAULT_CODE_SOFT_RESET_IN_PROGRESS (0x0000f002)
@@ -158,6 +164,7 @@ struct mpi3_sysif_registers {
#define MPI3_SYSIF_FAULT_CODE_SOFT_RESET_NEEDED (0x0000f004)
#define MPI3_SYSIF_FAULT_CODE_POWER_CYCLE_REQUIRED (0x0000f005)
#define MPI3_SYSIF_FAULT_CODE_TEMP_THRESHOLD_EXCEEDED (0x0000f006)
+#define MPI3_SYSIF_FAULT_CODE_INSUFFICIENT_PCI_SLOT_POWER (0x0000f007)
#define MPI3_SYSIF_FAULT_INFO0_OFFSET (0x00001c14)
#define MPI3_SYSIF_FAULT_INFO1_OFFSET (0x00001c18)
#define MPI3_SYSIF_FAULT_INFO2_OFFSET (0x00001c1c)
@@ -175,17 +182,20 @@ struct mpi3_sysif_registers {
#define MPI3_SYSIF_DIAG_RW_ADDRESS_HIGH_OFFSET (0x00001c5c)
#define MPI3_SYSIF_DIAG_RW_CONTROL_OFFSET (0x00001c60)
#define MPI3_SYSIF_DIAG_RW_CONTROL_LEN_MASK (0x00000030)
+#define MPI3_SYSIF_DIAG_RW_CONTROL_LEN_SHIFT (4)
#define MPI3_SYSIF_DIAG_RW_CONTROL_LEN_1BYTE (0x00000000)
#define MPI3_SYSIF_DIAG_RW_CONTROL_LEN_2BYTES (0x00000010)
#define MPI3_SYSIF_DIAG_RW_CONTROL_LEN_4BYTES (0x00000020)
#define MPI3_SYSIF_DIAG_RW_CONTROL_LEN_8BYTES (0x00000030)
#define MPI3_SYSIF_DIAG_RW_CONTROL_RESET (0x00000004)
#define MPI3_SYSIF_DIAG_RW_CONTROL_DIR_MASK (0x00000002)
+#define MPI3_SYSIF_DIAG_RW_CONTROL_DIR_SHIFT (1)
#define MPI3_SYSIF_DIAG_RW_CONTROL_DIR_READ (0x00000000)
#define MPI3_SYSIF_DIAG_RW_CONTROL_DIR_WRITE (0x00000002)
#define MPI3_SYSIF_DIAG_RW_CONTROL_START (0x00000001)
#define MPI3_SYSIF_DIAG_RW_STATUS_OFFSET (0x00001c62)
#define MPI3_SYSIF_DIAG_RW_STATUS_STATUS_MASK (0x0000000e)
+#define MPI3_SYSIF_DIAG_RW_STATUS_STATUS_SHIFT (1)
#define MPI3_SYSIF_DIAG_RW_STATUS_STATUS_SUCCESS (0x00000000)
#define MPI3_SYSIF_DIAG_RW_STATUS_STATUS_INV_ADDR (0x00000002)
#define MPI3_SYSIF_DIAG_RW_STATUS_STATUS_ACC_ERR (0x00000004)
@@ -206,7 +216,9 @@ struct mpi3_default_reply_descriptor {
};
#define MPI3_REPLY_DESCRIPT_FLAGS_PHASE_MASK (0x0001)
+#define MPI3_REPLY_DESCRIPT_FLAGS_PHASE_SHIFT (0)
#define MPI3_REPLY_DESCRIPT_FLAGS_TYPE_MASK (0xf000)
+#define MPI3_REPLY_DESCRIPT_FLAGS_TYPE_SHIFT (12)
#define MPI3_REPLY_DESCRIPT_FLAGS_TYPE_ADDRESS_REPLY (0x0000)
#define MPI3_REPLY_DESCRIPT_FLAGS_TYPE_SUCCESS (0x1000)
#define MPI3_REPLY_DESCRIPT_FLAGS_TYPE_TARGET_COMMAND_BUFFER (0x2000)
@@ -300,6 +312,7 @@ union mpi3_sge_union {
};
#define MPI3_SGE_FLAGS_ELEMENT_TYPE_MASK (0xf0)
+#define MPI3_SGE_FLAGS_ELEMENT_TYPE_SHIFT (4)
#define MPI3_SGE_FLAGS_ELEMENT_TYPE_SIMPLE (0x00)
#define MPI3_SGE_FLAGS_ELEMENT_TYPE_BIT_BUCKET (0x10)
#define MPI3_SGE_FLAGS_ELEMENT_TYPE_CHAIN (0x20)
@@ -308,6 +321,7 @@ union mpi3_sge_union {
#define MPI3_SGE_FLAGS_END_OF_LIST (0x08)
#define MPI3_SGE_FLAGS_END_OF_BUFFER (0x04)
#define MPI3_SGE_FLAGS_DLAS_MASK (0x03)
+#define MPI3_SGE_FLAGS_DLAS_SHIFT (0)
#define MPI3_SGE_FLAGS_DLAS_SYSTEM (0x00)
#define MPI3_SGE_FLAGS_DLAS_IOC_UDP (0x01)
#define MPI3_SGE_FLAGS_DLAS_IOC_CTL (0x02)
@@ -321,15 +335,18 @@ union mpi3_sge_union {
#define MPI3_EEDPFLAGS_CHK_APP_TAG (0x0200)
#define MPI3_EEDPFLAGS_CHK_GUARD (0x0100)
#define MPI3_EEDPFLAGS_ESC_MODE_MASK (0x00c0)
+#define MPI3_EEDPFLAGS_ESC_MODE_SHIFT (6)
#define MPI3_EEDPFLAGS_ESC_MODE_DO_NOT_DISABLE (0x0040)
#define MPI3_EEDPFLAGS_ESC_MODE_APPTAG_DISABLE (0x0080)
#define MPI3_EEDPFLAGS_ESC_MODE_APPTAG_REFTAG_DISABLE (0x00c0)
#define MPI3_EEDPFLAGS_HOST_GUARD_MASK (0x0030)
+#define MPI3_EEDPFLAGS_HOST_GUARD_SHIFT (4)
#define MPI3_EEDPFLAGS_HOST_GUARD_T10_CRC (0x0000)
#define MPI3_EEDPFLAGS_HOST_GUARD_IP_CHKSUM (0x0010)
#define MPI3_EEDPFLAGS_HOST_GUARD_OEM_SPECIFIC (0x0020)
#define MPI3_EEDPFLAGS_PT_REF_TAG (0x0008)
#define MPI3_EEDPFLAGS_EEDP_OP_MASK (0x0007)
+#define MPI3_EEDPFLAGS_EEDP_OP_SHIFT (0)
#define MPI3_EEDPFLAGS_EEDP_OP_CHECK (0x0001)
#define MPI3_EEDPFLAGS_EEDP_OP_STRIP (0x0002)
#define MPI3_EEDPFLAGS_EEDP_OP_CHECK_REMOVE (0x0003)
@@ -402,6 +419,7 @@ struct mpi3_default_reply {
#define MPI3_IOCSTATUS_LOG_INFO_AVAIL_MASK (0x8000)
#define MPI3_IOCSTATUS_LOG_INFO_AVAILABLE (0x8000)
#define MPI3_IOCSTATUS_STATUS_MASK (0x7fff)
+#define MPI3_IOCSTATUS_STATUS_SHIFT (0)
#define MPI3_IOCSTATUS_SUCCESS (0x0000)
#define MPI3_IOCSTATUS_INVALID_FUNCTION (0x0001)
#define MPI3_IOCSTATUS_BUSY (0x0002)
@@ -410,6 +428,7 @@ struct mpi3_default_reply {
#define MPI3_IOCSTATUS_INSUFFICIENT_RESOURCES (0x0006)
#define MPI3_IOCSTATUS_INVALID_FIELD (0x0007)
#define MPI3_IOCSTATUS_INVALID_STATE (0x0008)
+#define MPI3_IOCSTATUS_SHUTDOWN_ACTIVE (0x0009)
#define MPI3_IOCSTATUS_INSUFFICIENT_POWER (0x000a)
#define MPI3_IOCSTATUS_INVALID_CHANGE_COUNT (0x000b)
#define MPI3_IOCSTATUS_ALLOWED_CMD_BLOCK (0x000c)
@@ -467,4 +486,5 @@ struct mpi3_default_reply {
#define MPI3_IOCLOGINFO_TYPE_NONE (0x0)
#define MPI3_IOCLOGINFO_TYPE_SAS (0x3)
#define MPI3_IOCLOGINFO_LOG_DATA_MASK (0x0fffffff)
+#define MPI3_IOCLOGINFO_LOG_DATA_SHIFT (0)
#endif
diff --git a/drivers/scsi/mpi3mr/mpi3mr.h b/drivers/scsi/mpi3mr/mpi3mr.h
index 3de1ee05c44e..9bbc7cb98ca3 100644
--- a/drivers/scsi/mpi3mr/mpi3mr.h
+++ b/drivers/scsi/mpi3mr/mpi3mr.h
@@ -12,7 +12,6 @@
#include <linux/blkdev.h>
#include <linux/blk-mq.h>
-#include <linux/blk-mq-pci.h>
#include <linux/delay.h>
#include <linux/dmapool.h>
#include <linux/errno.h>
@@ -23,6 +22,7 @@
#include <linux/miscdevice.h>
#include <linux/module.h>
#include <linux/pci.h>
+#include <linux/aer.h>
#include <linux/poll.h>
#include <linux/sched.h>
#include <linux/slab.h>
@@ -30,7 +30,7 @@
#include <linux/uaccess.h>
#include <linux/utsname.h>
#include <linux/workqueue.h>
-#include <asm/unaligned.h>
+#include <linux/unaligned.h>
#include <scsi/scsi.h>
#include <scsi/scsi_cmnd.h>
#include <scsi/scsi_dbg.h>
@@ -47,6 +47,7 @@
#include "mpi/mpi30_ioc.h"
#include "mpi/mpi30_sas.h"
#include "mpi/mpi30_pci.h"
+#include "mpi/mpi30_tool.h"
#include "mpi3mr_debug.h"
/* Global list and lock for storing multiple adapters managed by the driver */
@@ -55,15 +56,15 @@ extern struct list_head mrioc_list;
extern int prot_mask;
extern atomic64_t event_counter;
-#define MPI3MR_DRIVER_VERSION "8.5.1.0.0"
-#define MPI3MR_DRIVER_RELDATE "5-December-2023"
+#define MPI3MR_DRIVER_VERSION "8.13.0.5.50"
+#define MPI3MR_DRIVER_RELDATE "20-February-2025"
#define MPI3MR_DRIVER_NAME "mpi3mr"
#define MPI3MR_DRIVER_LICENSE "GPL"
#define MPI3MR_DRIVER_AUTHOR "Broadcom Inc. <mpi3mr-linuxdrv.pdl@broadcom.com>"
#define MPI3MR_DRIVER_DESC "MPI3 Storage Controller Device Driver"
-#define MPI3MR_NAME_LENGTH 32
+#define MPI3MR_NAME_LENGTH 64
#define IOCNAME "%s: "
#define MPI3MR_DEFAULT_MAX_IO_SIZE (1 * 1024 * 1024)
@@ -79,13 +80,14 @@ extern atomic64_t event_counter;
/* Admin queue management definitions */
#define MPI3MR_ADMIN_REQ_Q_SIZE (2 * MPI3MR_PAGE_SIZE_4K)
-#define MPI3MR_ADMIN_REPLY_Q_SIZE (4 * MPI3MR_PAGE_SIZE_4K)
+#define MPI3MR_ADMIN_REPLY_Q_SIZE (8 * MPI3MR_PAGE_SIZE_4K)
#define MPI3MR_ADMIN_REQ_FRAME_SZ 128
#define MPI3MR_ADMIN_REPLY_FRAME_SZ 16
/* Operational queue management definitions */
#define MPI3MR_OP_REQ_Q_QD 512
#define MPI3MR_OP_REP_Q_QD 1024
+#define MPI3MR_OP_REP_Q_QD2K 2048
#define MPI3MR_OP_REP_Q_QD4K 4096
#define MPI3MR_OP_REQ_Q_SEG_SIZE 4096
#define MPI3MR_OP_REP_Q_SEG_SIZE 4096
@@ -128,11 +130,10 @@ extern atomic64_t event_counter;
#define MPI3MR_PREPARE_FOR_RESET_TIMEOUT 180
#define MPI3MR_RESET_ACK_TIMEOUT 30
#define MPI3MR_MUR_TIMEOUT 120
+#define MPI3MR_RESET_TIMEOUT 510
#define MPI3MR_WATCHDOG_INTERVAL 1000 /* in milli seconds */
-#define MPI3MR_DEFAULT_CFG_PAGE_SZ 1024 /* in bytes */
-
#define MPI3MR_RESET_TOPOLOGY_SETTLE_TIME 10
#define MPI3MR_SCMD_TIMEOUT (60 * HZ)
@@ -175,7 +176,7 @@ extern atomic64_t event_counter;
#define MPI3MR_DEFAULT_SDEV_QD 32
/* Definitions for Threaded IRQ poll*/
-#define MPI3MR_IRQ_POLL_SLEEP 2
+#define MPI3MR_IRQ_POLL_SLEEP 20
#define MPI3MR_IRQ_POLL_TRIGGER_IOCOUNT 8
/* Definitions for the controller security status*/
@@ -187,6 +188,31 @@ extern atomic64_t event_counter;
#define MPI3MR_HARD_SECURE_DEVICE 0x08
#define MPI3MR_TAMPERED_DEVICE 0x0C
+#define MPI3MR_DEFAULT_HDB_MAX_SZ (4 * 1024 * 1024)
+#define MPI3MR_DEFAULT_HDB_DEC_SZ (1 * 1024 * 1024)
+#define MPI3MR_DEFAULT_HDB_MIN_SZ (2 * 1024 * 1024)
+#define MPI3MR_MAX_NUM_HDB 2
+
+#define MPI3MR_HDB_TRIGGER_TYPE_UNKNOWN 0
+#define MPI3MR_HDB_TRIGGER_TYPE_FAULT 1
+#define MPI3MR_HDB_TRIGGER_TYPE_ELEMENT 2
+#define MPI3MR_HDB_TRIGGER_TYPE_GLOBAL 3
+#define MPI3MR_HDB_TRIGGER_TYPE_SOFT_RESET 4
+#define MPI3MR_HDB_TRIGGER_TYPE_FW_RELEASED 5
+
+#define MPI3MR_HDB_REFRESH_TYPE_RESERVED 0
+#define MPI3MR_HDB_REFRESH_TYPE_CURRENT 1
+#define MPI3MR_HDB_REFRESH_TYPE_DEFAULT 2
+#define MPI3MR_HDB_HDB_REFRESH_TYPE_PERSISTENT 3
+
+#define MPI3MR_DEFAULT_HDB_SZ (4 * 1024 * 1024)
+#define MPI3MR_MAX_NUM_HDB 2
+
+#define MPI3MR_HDB_QUERY_ELEMENT_TRIGGER_FORMAT_INDEX 0
+#define MPI3MR_HDB_QUERY_ELEMENT_TRIGGER_FORMAT_DATA 1
+
+#define MPI3MR_THRESHOLD_REPLY_COUNT 100
+
/* SGE Flag definition */
#define MPI3MR_SGEFLAGS_SYSTEM_SIMPLE_END_OF_LIST \
(MPI3_SGE_FLAGS_ELEMENT_TYPE_SIMPLE | MPI3_SGE_FLAGS_DLAS_SYSTEM | \
@@ -210,6 +236,8 @@ extern atomic64_t event_counter;
#define MPI3MR_WRITE_SAME_MAX_LEN_256_BLKS 256
#define MPI3MR_WRITE_SAME_MAX_LEN_2048_BLKS 2048
+#define MPI3MR_DRIVER_EVENT_PROCESS_TRIGGER (0xFFFD)
+
/**
* struct mpi3mr_nvme_pt_sge - Structure to store SGEs for NVMe
* Encapsulated commands.
@@ -289,11 +317,19 @@ enum mpi3mr_reset_reason {
MPI3MR_RESET_FROM_PELABORT_TIMEOUT = 22,
MPI3MR_RESET_FROM_SYSFS = 23,
MPI3MR_RESET_FROM_SYSFS_TIMEOUT = 24,
+ MPI3MR_RESET_FROM_DIAG_BUFFER_POST_TIMEOUT = 25,
+ MPI3MR_RESET_FROM_DIAG_BUFFER_RELEASE_TIMEOUT = 26,
MPI3MR_RESET_FROM_FIRMWARE = 27,
MPI3MR_RESET_FROM_CFG_REQ_TIMEOUT = 29,
MPI3MR_RESET_FROM_SAS_TRANSPORT_TIMEOUT = 30,
+ MPI3MR_RESET_FROM_TRIGGER = 31,
};
+#define MPI3MR_RESET_REASON_OSTYPE_LINUX 1
+#define MPI3MR_RESET_REASON_OSTYPE_SHIFT 28
+#define MPI3MR_RESET_REASON_IOCNUM_SHIFT 20
+
+
/* Queue type definitions */
enum queue_type {
MPI3MR_DEFAULT_QUEUE = 0,
@@ -323,6 +359,9 @@ struct mpi3mr_ioc_facts {
u32 ioc_capabilities;
struct mpi3mr_compimg_ver fw_ver;
u32 mpi_version;
+ u32 diag_trace_sz;
+ u32 diag_fw_sz;
+ u32 diag_drvr_sz;
u16 max_reqs;
u16 product_id;
u16 op_req_sz;
@@ -350,6 +389,7 @@ struct mpi3mr_ioc_facts {
u16 max_msix_vectors;
u8 personality;
u8 dma_mask;
+ bool max_req_limit;
u8 protocol_flags;
u8 sge_mod_mask;
u8 sge_mod_value;
@@ -419,6 +459,8 @@ struct op_req_qinfo {
* @enable_irq_poll: Flag to indicate polling is enabled
* @in_use: Queue is handled by poll/ISR
* @qtype: Type of queue (types defined in enum queue_type)
+ * @qfull_watermark: Watermark defined in reply queue to avoid
+ * reply queue full
*/
struct op_reply_qinfo {
u16 ci;
@@ -434,6 +476,7 @@ struct op_reply_qinfo {
bool enable_irq_poll;
atomic_t in_use;
enum queue_type qtype;
+ u16 qfull_watermark;
};
/**
@@ -480,6 +523,7 @@ struct mpi3mr_throttle_group_info {
/* HBA port flags */
#define MPI3MR_HBA_PORT_FLAG_DIRTY 0x01
+#define MPI3MR_HBA_PORT_FLAG_NEW 0x02
/* IOCTL data transfer sge*/
#define MPI3MR_NUM_IOCTL_SGE 256
@@ -501,8 +545,8 @@ struct mpi3mr_hba_port {
* @port_list: List of ports belonging to a SAS node
* @num_phys: Number of phys associated with port
* @marked_responding: used while refresing the sas ports
- * @lowest_phy: lowest phy ID of current sas port
- * @phy_mask: phy_mask of current sas port
+ * @lowest_phy: lowest phy ID of current sas port, valid for controller port
+ * @phy_mask: phy_mask of current sas port, valid for controller port
* @hba_port: HBA port entry
* @remote_identify: Attached device identification
* @rphy: SAS transport layer rphy object
@@ -849,6 +893,63 @@ struct mpi3mr_drv_cmd {
};
/**
+ * union mpi3mr_trigger_data - Trigger data information
+ * @fault: Fault code
+ * @global: Global trigger data
+ * @element: element trigger data
+ */
+union mpi3mr_trigger_data {
+ u16 fault;
+ u64 global;
+ union mpi3_driver2_trigger_element element;
+};
+
+/**
+ * struct trigger_event_data - store trigger related
+ * information.
+ *
+ * @trace_hdb: Trace diag buffer descriptor reference
+ * @fw_hdb: FW diag buffer descriptor reference
+ * @trigger_type: Trigger type
+ * @trigger_specific_data: Trigger specific data
+ * @snapdump: Snapdump enable or disable flag
+ */
+struct trigger_event_data {
+ struct diag_buffer_desc *trace_hdb;
+ struct diag_buffer_desc *fw_hdb;
+ u8 trigger_type;
+ union mpi3mr_trigger_data trigger_specific_data;
+ bool snapdump;
+};
+
+/**
+ * struct diag_buffer_desc - memory descriptor structure to
+ * store virtual, dma addresses, size, buffer status for host
+ * diagnostic buffers.
+ *
+ * @type: Buffer type
+ * @trigger_data: Trigger data
+ * @trigger_type: Trigger type
+ * @status: Buffer status
+ * @size: Buffer size
+ * @addr: Virtual address
+ * @dma_addr: Buffer DMA address
+ * @is_segmented: The buffer is segmented or not
+ * @disabled_after_reset: The buffer is disabled after reset
+ */
+struct diag_buffer_desc {
+ u8 type;
+ union mpi3mr_trigger_data trigger_data;
+ u8 trigger_type;
+ u8 status;
+ u32 size;
+ void *addr;
+ dma_addr_t dma_addr;
+ bool is_segmented;
+ bool disabled_after_reset;
+};
+
+/**
* struct dma_memory_desc - memory descriptor structure to store
* virtual address, dma address and size for any generic dma
* memory allocations in the driver.
@@ -931,6 +1032,8 @@ struct scmd_priv {
* @admin_reply_base: Admin reply queue base virtual address
* @admin_reply_dma: Admin reply queue base dma address
* @admin_reply_q_in_use: Queue is handled by poll/ISR
+ * @admin_pend_isr: Count of unprocessed admin ISR/poll calls
+ * due to another thread processing replies
* @ready_timeout: Controller ready timeout
* @intr_info: Interrupt cookie pointer
* @intr_info_count: Number of interrupt cookies
@@ -966,7 +1069,6 @@ struct scmd_priv {
* @sbq_lock: Sense buffer queue lock
* @sbq_host_index: Sense buffer queuehost index
* @event_masks: Event mask bitmap
- * @fwevt_worker_name: Firmware event worker thread name
* @fwevt_worker_thread: Firmware event worker thread
* @fwevt_lock: Firmware event lock
* @fwevt_list: Firmware event list
@@ -997,8 +1099,10 @@ struct scmd_priv {
* @evtack_cmds_bitmap: Event Ack bitmap
* @delayed_evtack_cmds_list: Delayed event acknowledgment list
* @ts_update_counter: Timestamp update counter
+ * @ts_update_interval: Timestamp update interval
* @reset_in_progress: Reset in progress flag
* @unrecoverable: Controller unrecoverable flag
+ * @io_admin_reset_sync: Manage state of I/O ops during an admin reset process
* @prev_reset_result: Result of previous reset
* @reset_mutex: Controller reset mutex
* @reset_waitq: Controller reset wait queue
@@ -1039,9 +1143,6 @@ struct scmd_priv {
* @io_throttle_low: I/O size to stop throttle in 512b blocks
* @num_io_throttle_group: Maximum number of throttle groups
* @throttle_groups: Pointer to throttle group info structures
- * @cfg_page: Default memory for configuration pages
- * @cfg_page_dma: Configuration page DMA address
- * @cfg_page_sz: Default configuration page memory size
* @sas_transport_enabled: SAS transport enabled or not
* @scsi_device_channel: Channel ID for SCSI devices
* @transport_cmds: Command tracker for SAS transport commands
@@ -1050,11 +1151,27 @@ struct scmd_priv {
* @sas_node_lock: Lock to protect SAS node list
* @hba_port_table_list: List of HBA Ports
* @enclosure_list: List of Enclosure objects
+ * @diag_buffers: Host diagnostic buffers
+ * @driver_pg2: Driver page 2 pointer
+ * @reply_trigger_present: Reply trigger present flag
+ * @event_trigger_present: Event trigger present flag
+ * @scsisense_trigger_present: Scsi sense trigger present flag
* @ioctl_dma_pool: DMA pool for IOCTL data buffers
* @ioctl_sge: DMA buffer descriptors for IOCTL data
* @ioctl_chain_sge: DMA buffer descriptor for IOCTL chain
* @ioctl_resp_sge: DMA buffer descriptor for Mgmt cmd response
* @ioctl_sges_allocated: Flag for IOCTL SGEs allocated or not
+ * @trace_release_trigger_active: Trace trigger active flag
+ * @fw_release_trigger_active: Fw release trigger active flag
+ * @snapdump_trigger_active: Snapdump trigger active flag
+ * @pci_err_recovery: PCI error recovery in progress
+ * @block_on_pci_err: Block IO during PCI error recovery
+ * @reply_qfull_count: Occurences of reply queue full avoidance kicking-in
+ * @prevent_reply_qfull: Enable reply queue prevention
+ * @seg_tb_support: Segmented trace buffer support
+ * @num_tb_segs: Number of Segments in Trace buffer
+ * @trace_buf_pool: DMA pool for Segmented trace buffer segments
+ * @trace_buf: Trace buffer segments memory descriptor
*/
struct mpi3mr_ioc {
struct list_head list;
@@ -1091,6 +1208,7 @@ struct mpi3mr_ioc {
void *admin_reply_base;
dma_addr_t admin_reply_dma;
atomic_t admin_reply_q_in_use;
+ atomic_t admin_pend_isr;
u32 ready_timeout;
@@ -1137,12 +1255,11 @@ struct mpi3mr_ioc {
u32 sbq_host_index;
u32 event_masks[MPI3_EVENT_NOTIFY_EVENTMASK_WORDS];
- char fwevt_worker_name[MPI3MR_NAME_LENGTH];
struct workqueue_struct *fwevt_worker_thread;
spinlock_t fwevt_lock;
struct list_head fwevt_list;
- char watchdog_work_q_name[20];
+ char watchdog_work_q_name[50];
struct workqueue_struct *watchdog_work_q;
struct delayed_work watchdog_work;
spinlock_t watchdog_lock;
@@ -1175,9 +1292,11 @@ struct mpi3mr_ioc {
unsigned long *evtack_cmds_bitmap;
struct list_head delayed_evtack_cmds_list;
- u32 ts_update_counter;
+ u16 ts_update_counter;
+ u16 ts_update_interval;
u8 reset_in_progress;
u8 unrecoverable;
+ u8 io_admin_reset_sync;
int prev_reset_result;
struct mutex reset_mutex;
wait_queue_head_t reset_waitq;
@@ -1228,10 +1347,6 @@ struct mpi3mr_ioc {
u16 num_io_throttle_group;
struct mpi3mr_throttle_group_info *throttle_groups;
- void *cfg_page;
- dma_addr_t cfg_page_dma;
- u16 cfg_page_sz;
-
u8 sas_transport_enabled;
u8 scsi_device_channel;
struct mpi3mr_drv_cmd transport_cmds;
@@ -1246,6 +1361,24 @@ struct mpi3mr_ioc {
struct dma_memory_desc ioctl_chain_sge;
struct dma_memory_desc ioctl_resp_sge;
bool ioctl_sges_allocated;
+ bool reply_trigger_present;
+ bool event_trigger_present;
+ bool scsisense_trigger_present;
+ struct diag_buffer_desc diag_buffers[MPI3MR_MAX_NUM_HDB];
+ struct mpi3_driver_page2 *driver_pg2;
+ spinlock_t trigger_lock;
+ bool snapdump_trigger_active;
+ bool trace_release_trigger_active;
+ bool fw_release_trigger_active;
+ bool pci_err_recovery;
+ bool block_on_pci_err;
+ atomic_t reply_qfull_count;
+ bool prevent_reply_qfull;
+ bool seg_tb_support;
+ u32 num_tb_segs;
+ struct dma_pool *trace_buf_pool;
+ struct segments *trace_buf;
+
};
/**
@@ -1336,7 +1469,7 @@ void mpi3mr_start_watchdog(struct mpi3mr_ioc *mrioc);
void mpi3mr_stop_watchdog(struct mpi3mr_ioc *mrioc);
int mpi3mr_soft_reset_handler(struct mpi3mr_ioc *mrioc,
- u32 reset_reason, u8 snapdump);
+ u16 reset_reason, u8 snapdump);
void mpi3mr_ioc_disable_intr(struct mpi3mr_ioc *mrioc);
void mpi3mr_ioc_enable_intr(struct mpi3mr_ioc *mrioc);
@@ -1348,7 +1481,6 @@ void mpi3mr_wait_for_host_io(struct mpi3mr_ioc *mrioc, u32 timeout);
void mpi3mr_cleanup_fwevt_list(struct mpi3mr_ioc *mrioc);
void mpi3mr_flush_host_io(struct mpi3mr_ioc *mrioc);
void mpi3mr_invalidate_devhandles(struct mpi3mr_ioc *mrioc);
-void mpi3mr_rfresh_tgtdevs(struct mpi3mr_ioc *mrioc);
void mpi3mr_flush_delayed_cmd_lists(struct mpi3mr_ioc *mrioc);
void mpi3mr_check_rh_fault_ioc(struct mpi3mr_ioc *mrioc, u32 reason_code);
void mpi3mr_print_fault_info(struct mpi3mr_ioc *mrioc);
@@ -1403,6 +1535,8 @@ int mpi3mr_cfg_set_sas_io_unit_pg1(struct mpi3mr_ioc *mrioc,
struct mpi3_sas_io_unit_page1 *sas_io_unit_pg1, u16 pg_sz);
int mpi3mr_cfg_get_driver_pg1(struct mpi3mr_ioc *mrioc,
struct mpi3_driver_page1 *driver_pg1, u16 pg_sz);
+int mpi3mr_cfg_get_driver_pg2(struct mpi3mr_ioc *mrioc,
+ struct mpi3_driver_page2 *driver_pg2, u16 pg_sz, u8 page_type);
u8 mpi3mr_is_expander_device(u16 device_info);
int mpi3mr_expander_add(struct mpi3mr_ioc *mrioc, u16 handle);
@@ -1436,4 +1570,28 @@ void mpi3mr_free_enclosure_list(struct mpi3mr_ioc *mrioc);
int mpi3mr_process_admin_reply_q(struct mpi3mr_ioc *mrioc);
void mpi3mr_expander_node_remove(struct mpi3mr_ioc *mrioc,
struct mpi3mr_sas_node *sas_expander);
+void mpi3mr_alloc_diag_bufs(struct mpi3mr_ioc *mrioc);
+int mpi3mr_post_diag_bufs(struct mpi3mr_ioc *mrioc);
+int mpi3mr_issue_diag_buf_release(struct mpi3mr_ioc *mrioc,
+ struct diag_buffer_desc *diag_buffer);
+void mpi3mr_release_diag_bufs(struct mpi3mr_ioc *mrioc, u8 skip_rel_action);
+void mpi3mr_set_trigger_data_in_hdb(struct diag_buffer_desc *hdb,
+ u8 type, union mpi3mr_trigger_data *trigger_data, bool force);
+int mpi3mr_refresh_trigger(struct mpi3mr_ioc *mrioc, u8 page_type);
+struct diag_buffer_desc *mpi3mr_diag_buffer_for_type(struct mpi3mr_ioc *mrioc,
+ u8 buf_type);
+int mpi3mr_issue_diag_buf_post(struct mpi3mr_ioc *mrioc,
+ struct diag_buffer_desc *diag_buffer);
+void mpi3mr_set_trigger_data_in_all_hdb(struct mpi3mr_ioc *mrioc,
+ u8 type, union mpi3mr_trigger_data *trigger_data, bool force);
+void mpi3mr_reply_trigger(struct mpi3mr_ioc *mrioc, u16 iocstatus,
+ u32 iocloginfo);
+void mpi3mr_hdb_trigger_data_event(struct mpi3mr_ioc *mrioc,
+ struct trigger_event_data *event_data);
+void mpi3mr_scsisense_trigger(struct mpi3mr_ioc *mrioc, u8 senseky, u8 asc,
+ u8 ascq);
+void mpi3mr_event_trigger(struct mpi3mr_ioc *mrioc, u8 event);
+void mpi3mr_global_trigger(struct mpi3mr_ioc *mrioc, u64 trigger_data);
+void mpi3mr_hdbstatuschg_evt_th(struct mpi3mr_ioc *mrioc,
+ struct mpi3_event_notification_reply *event_reply);
#endif /*MPI3MR_H_INCLUDED*/
diff --git a/drivers/scsi/mpi3mr/mpi3mr_app.c b/drivers/scsi/mpi3mr/mpi3mr_app.c
index 55d590b91947..f36663613950 100644
--- a/drivers/scsi/mpi3mr/mpi3mr_app.c
+++ b/drivers/scsi/mpi3mr/mpi3mr_app.c
@@ -12,6 +12,912 @@
#include <uapi/scsi/scsi_bsg_mpi3mr.h>
/**
+ * mpi3mr_alloc_trace_buffer: Allocate segmented trace buffer
+ * @mrioc: Adapter instance reference
+ * @trace_size: Trace buffer size
+ *
+ * Allocate either segmented memory pools or contiguous buffer
+ * based on the controller capability for the host trace
+ * buffer.
+ *
+ * Return: 0 on success, non-zero on failure.
+ */
+static int mpi3mr_alloc_trace_buffer(struct mpi3mr_ioc *mrioc, u32 trace_size)
+{
+ struct diag_buffer_desc *diag_buffer = &mrioc->diag_buffers[0];
+ int i, sz;
+ u64 *diag_buffer_list = NULL;
+ dma_addr_t diag_buffer_list_dma;
+ u32 seg_count;
+
+ if (mrioc->seg_tb_support) {
+ seg_count = (trace_size) / MPI3MR_PAGE_SIZE_4K;
+ trace_size = seg_count * MPI3MR_PAGE_SIZE_4K;
+
+ diag_buffer_list = dma_alloc_coherent(&mrioc->pdev->dev,
+ sizeof(u64) * seg_count,
+ &diag_buffer_list_dma, GFP_KERNEL);
+ if (!diag_buffer_list)
+ return -1;
+
+ mrioc->num_tb_segs = seg_count;
+
+ sz = sizeof(struct segments) * seg_count;
+ mrioc->trace_buf = kzalloc(sz, GFP_KERNEL);
+ if (!mrioc->trace_buf)
+ goto trace_buf_failed;
+
+ mrioc->trace_buf_pool = dma_pool_create("trace_buf pool",
+ &mrioc->pdev->dev, MPI3MR_PAGE_SIZE_4K, MPI3MR_PAGE_SIZE_4K,
+ 0);
+ if (!mrioc->trace_buf_pool) {
+ ioc_err(mrioc, "trace buf pool: dma_pool_create failed\n");
+ goto trace_buf_pool_failed;
+ }
+
+ for (i = 0; i < seg_count; i++) {
+ mrioc->trace_buf[i].segment =
+ dma_pool_zalloc(mrioc->trace_buf_pool, GFP_KERNEL,
+ &mrioc->trace_buf[i].segment_dma);
+ diag_buffer_list[i] =
+ (u64) mrioc->trace_buf[i].segment_dma;
+ if (!diag_buffer_list[i])
+ goto tb_seg_alloc_failed;
+ }
+
+ diag_buffer->addr = diag_buffer_list;
+ diag_buffer->dma_addr = diag_buffer_list_dma;
+ diag_buffer->is_segmented = true;
+
+ dprint_init(mrioc, "segmented trace diag buffer\n"
+ "is allocated successfully seg_count:%d\n", seg_count);
+ return 0;
+ } else {
+ diag_buffer->addr = dma_alloc_coherent(&mrioc->pdev->dev,
+ trace_size, &diag_buffer->dma_addr, GFP_KERNEL);
+ if (diag_buffer->addr) {
+ dprint_init(mrioc, "trace diag buffer is allocated successfully\n");
+ return 0;
+ }
+ return -1;
+ }
+
+tb_seg_alloc_failed:
+ if (mrioc->trace_buf_pool) {
+ for (i = 0; i < mrioc->num_tb_segs; i++) {
+ if (mrioc->trace_buf[i].segment) {
+ dma_pool_free(mrioc->trace_buf_pool,
+ mrioc->trace_buf[i].segment,
+ mrioc->trace_buf[i].segment_dma);
+ mrioc->trace_buf[i].segment = NULL;
+ }
+ mrioc->trace_buf[i].segment = NULL;
+ }
+ dma_pool_destroy(mrioc->trace_buf_pool);
+ mrioc->trace_buf_pool = NULL;
+ }
+trace_buf_pool_failed:
+ kfree(mrioc->trace_buf);
+ mrioc->trace_buf = NULL;
+trace_buf_failed:
+ if (diag_buffer_list)
+ dma_free_coherent(&mrioc->pdev->dev,
+ sizeof(u64) * mrioc->num_tb_segs,
+ diag_buffer_list, diag_buffer_list_dma);
+ return -1;
+}
+
+/**
+ * mpi3mr_alloc_diag_bufs - Allocate memory for diag buffers
+ * @mrioc: Adapter instance reference
+ *
+ * This functions checks whether the driver defined buffer sizes
+ * are greater than IOCFacts provided controller local buffer
+ * sizes and if the driver defined sizes are more then the
+ * driver allocates the specific buffer by reading driver page1
+ *
+ * Return: Nothing.
+ */
+void mpi3mr_alloc_diag_bufs(struct mpi3mr_ioc *mrioc)
+{
+ struct diag_buffer_desc *diag_buffer;
+ struct mpi3_driver_page1 driver_pg1;
+ u32 trace_dec_size, trace_min_size, fw_dec_size, fw_min_size,
+ trace_size, fw_size;
+ u16 pg_sz = sizeof(driver_pg1);
+ int retval = 0;
+ bool retry = false;
+
+ if (mrioc->diag_buffers[0].addr || mrioc->diag_buffers[1].addr)
+ return;
+
+ retval = mpi3mr_cfg_get_driver_pg1(mrioc, &driver_pg1, pg_sz);
+ if (retval) {
+ ioc_warn(mrioc,
+ "%s: driver page 1 read failed, allocating trace\n"
+ "and firmware diag buffers of default size\n", __func__);
+ trace_size = fw_size = MPI3MR_DEFAULT_HDB_MAX_SZ;
+ trace_dec_size = fw_dec_size = MPI3MR_DEFAULT_HDB_DEC_SZ;
+ trace_min_size = fw_min_size = MPI3MR_DEFAULT_HDB_MIN_SZ;
+
+ } else {
+ trace_size = driver_pg1.host_diag_trace_max_size * 1024;
+ trace_dec_size = driver_pg1.host_diag_trace_decrement_size
+ * 1024;
+ trace_min_size = driver_pg1.host_diag_trace_min_size * 1024;
+ fw_size = driver_pg1.host_diag_fw_max_size * 1024;
+ fw_dec_size = driver_pg1.host_diag_fw_decrement_size * 1024;
+ fw_min_size = driver_pg1.host_diag_fw_min_size * 1024;
+ dprint_init(mrioc,
+ "%s:trace diag buffer sizes read from driver\n"
+ "page1: maximum size = %dKB, decrement size = %dKB\n"
+ ", minimum size = %dKB\n", __func__, driver_pg1.host_diag_trace_max_size,
+ driver_pg1.host_diag_trace_decrement_size,
+ driver_pg1.host_diag_trace_min_size);
+ dprint_init(mrioc,
+ "%s:firmware diag buffer sizes read from driver\n"
+ "page1: maximum size = %dKB, decrement size = %dKB\n"
+ ", minimum size = %dKB\n", __func__, driver_pg1.host_diag_fw_max_size,
+ driver_pg1.host_diag_fw_decrement_size,
+ driver_pg1.host_diag_fw_min_size);
+ if ((trace_size == 0) && (fw_size == 0))
+ return;
+ }
+
+
+retry_trace:
+ diag_buffer = &mrioc->diag_buffers[0];
+ diag_buffer->type = MPI3_DIAG_BUFFER_TYPE_TRACE;
+ diag_buffer->status = MPI3MR_HDB_BUFSTATUS_NOT_ALLOCATED;
+ if ((mrioc->facts.diag_trace_sz < trace_size) && (trace_size >=
+ trace_min_size)) {
+ if (!retry)
+ dprint_init(mrioc,
+ "trying to allocate trace diag buffer of size = %dKB\n",
+ trace_size / 1024);
+ if ((!mrioc->seg_tb_support && (get_order(trace_size) > MAX_PAGE_ORDER)) ||
+ mpi3mr_alloc_trace_buffer(mrioc, trace_size)) {
+
+ retry = true;
+ trace_size -= trace_dec_size;
+ dprint_init(mrioc, "trace diag buffer allocation failed\n"
+ "retrying smaller size %dKB\n", trace_size / 1024);
+ goto retry_trace;
+ } else
+ diag_buffer->size = trace_size;
+ }
+
+ retry = false;
+retry_fw:
+
+ diag_buffer = &mrioc->diag_buffers[1];
+
+ diag_buffer->type = MPI3_DIAG_BUFFER_TYPE_FW;
+ diag_buffer->status = MPI3MR_HDB_BUFSTATUS_NOT_ALLOCATED;
+ if ((mrioc->facts.diag_fw_sz < fw_size) && (fw_size >= fw_min_size)) {
+ if (get_order(fw_size) <= MAX_PAGE_ORDER) {
+ diag_buffer->addr
+ = dma_alloc_coherent(&mrioc->pdev->dev, fw_size,
+ &diag_buffer->dma_addr,
+ GFP_KERNEL);
+ }
+ if (!retry)
+ dprint_init(mrioc,
+ "%s:trying to allocate firmware diag buffer of size = %dKB\n",
+ __func__, fw_size / 1024);
+ if (diag_buffer->addr) {
+ dprint_init(mrioc, "%s:firmware diag buffer allocated successfully\n",
+ __func__);
+ diag_buffer->size = fw_size;
+ } else {
+ retry = true;
+ fw_size -= fw_dec_size;
+ dprint_init(mrioc, "%s:trace diag buffer allocation failed,\n"
+ "retrying smaller size %dKB\n",
+ __func__, fw_size / 1024);
+ goto retry_fw;
+ }
+ }
+}
+
+/**
+ * mpi3mr_issue_diag_buf_post - Send diag buffer post req
+ * @mrioc: Adapter instance reference
+ * @diag_buffer: Diagnostic buffer descriptor
+ *
+ * Issue diagnostic buffer post MPI request through admin queue
+ * and wait for the completion of it or time out.
+ *
+ * Return: 0 on success, non-zero on failures.
+ */
+int mpi3mr_issue_diag_buf_post(struct mpi3mr_ioc *mrioc,
+ struct diag_buffer_desc *diag_buffer)
+{
+ struct mpi3_diag_buffer_post_request diag_buf_post_req;
+ u8 prev_status;
+ int retval = 0;
+
+ if (diag_buffer->disabled_after_reset) {
+ dprint_bsg_err(mrioc, "%s: skipping diag buffer posting\n"
+ "as it is disabled after reset\n", __func__);
+ return -1;
+ }
+
+ memset(&diag_buf_post_req, 0, sizeof(diag_buf_post_req));
+ mutex_lock(&mrioc->init_cmds.mutex);
+ if (mrioc->init_cmds.state & MPI3MR_CMD_PENDING) {
+ dprint_bsg_err(mrioc, "%s: command is in use\n", __func__);
+ mutex_unlock(&mrioc->init_cmds.mutex);
+ return -1;
+ }
+ mrioc->init_cmds.state = MPI3MR_CMD_PENDING;
+ mrioc->init_cmds.is_waiting = 1;
+ mrioc->init_cmds.callback = NULL;
+ diag_buf_post_req.host_tag = cpu_to_le16(MPI3MR_HOSTTAG_INITCMDS);
+ diag_buf_post_req.function = MPI3_FUNCTION_DIAG_BUFFER_POST;
+ diag_buf_post_req.type = diag_buffer->type;
+ diag_buf_post_req.address = le64_to_cpu(diag_buffer->dma_addr);
+ diag_buf_post_req.length = le32_to_cpu(diag_buffer->size);
+
+ if (diag_buffer->is_segmented)
+ diag_buf_post_req.msg_flags |= MPI3_DIAG_BUFFER_POST_MSGFLAGS_SEGMENTED;
+
+ dprint_bsg_info(mrioc, "%s: posting diag buffer type %d segmented:%d\n", __func__,
+ diag_buffer->type, diag_buffer->is_segmented);
+
+ prev_status = diag_buffer->status;
+ diag_buffer->status = MPI3MR_HDB_BUFSTATUS_POSTED_UNPAUSED;
+ init_completion(&mrioc->init_cmds.done);
+ retval = mpi3mr_admin_request_post(mrioc, &diag_buf_post_req,
+ sizeof(diag_buf_post_req), 1);
+ if (retval) {
+ dprint_bsg_err(mrioc, "%s: admin request post failed\n",
+ __func__);
+ goto out_unlock;
+ }
+ wait_for_completion_timeout(&mrioc->init_cmds.done,
+ (MPI3MR_INTADMCMD_TIMEOUT * HZ));
+ if (!(mrioc->init_cmds.state & MPI3MR_CMD_COMPLETE)) {
+ mrioc->init_cmds.is_waiting = 0;
+ dprint_bsg_err(mrioc, "%s: command timedout\n", __func__);
+ mpi3mr_check_rh_fault_ioc(mrioc,
+ MPI3MR_RESET_FROM_DIAG_BUFFER_POST_TIMEOUT);
+ retval = -1;
+ goto out_unlock;
+ }
+ if ((mrioc->init_cmds.ioc_status & MPI3_IOCSTATUS_STATUS_MASK)
+ != MPI3_IOCSTATUS_SUCCESS) {
+ dprint_bsg_err(mrioc,
+ "%s: command failed, buffer_type (%d) ioc_status(0x%04x) log_info(0x%08x)\n",
+ __func__, diag_buffer->type,
+ (mrioc->init_cmds.ioc_status & MPI3_IOCSTATUS_STATUS_MASK),
+ mrioc->init_cmds.ioc_loginfo);
+ retval = -1;
+ goto out_unlock;
+ }
+ dprint_bsg_info(mrioc, "%s: diag buffer type %d posted successfully\n",
+ __func__, diag_buffer->type);
+
+out_unlock:
+ if (retval)
+ diag_buffer->status = prev_status;
+ mrioc->init_cmds.state = MPI3MR_CMD_NOTUSED;
+ mutex_unlock(&mrioc->init_cmds.mutex);
+ return retval;
+}
+
+/**
+ * mpi3mr_post_diag_bufs - Post diag buffers to the controller
+ * @mrioc: Adapter instance reference
+ *
+ * This function calls helper function to post both trace and
+ * firmware buffers to the controller.
+ *
+ * Return: None
+ */
+int mpi3mr_post_diag_bufs(struct mpi3mr_ioc *mrioc)
+{
+ u8 i;
+ struct diag_buffer_desc *diag_buffer;
+
+ for (i = 0; i < MPI3MR_MAX_NUM_HDB; i++) {
+ diag_buffer = &mrioc->diag_buffers[i];
+ if (!(diag_buffer->addr))
+ continue;
+ if (mpi3mr_issue_diag_buf_post(mrioc, diag_buffer))
+ return -1;
+ }
+ return 0;
+}
+
+/**
+ * mpi3mr_issue_diag_buf_release - Send diag buffer release req
+ * @mrioc: Adapter instance reference
+ * @diag_buffer: Diagnostic buffer descriptor
+ *
+ * Issue diagnostic buffer manage MPI request with release
+ * action request through admin queue and wait for the
+ * completion of it or time out.
+ *
+ * Return: 0 on success, non-zero on failures.
+ */
+int mpi3mr_issue_diag_buf_release(struct mpi3mr_ioc *mrioc,
+ struct diag_buffer_desc *diag_buffer)
+{
+ struct mpi3_diag_buffer_manage_request diag_buf_manage_req;
+ int retval = 0;
+
+ if ((diag_buffer->status != MPI3MR_HDB_BUFSTATUS_POSTED_UNPAUSED) &&
+ (diag_buffer->status != MPI3MR_HDB_BUFSTATUS_POSTED_PAUSED))
+ return retval;
+
+ memset(&diag_buf_manage_req, 0, sizeof(diag_buf_manage_req));
+ mutex_lock(&mrioc->init_cmds.mutex);
+ if (mrioc->init_cmds.state & MPI3MR_CMD_PENDING) {
+ dprint_reset(mrioc, "%s: command is in use\n", __func__);
+ mutex_unlock(&mrioc->init_cmds.mutex);
+ return -1;
+ }
+ mrioc->init_cmds.state = MPI3MR_CMD_PENDING;
+ mrioc->init_cmds.is_waiting = 1;
+ mrioc->init_cmds.callback = NULL;
+ diag_buf_manage_req.host_tag = cpu_to_le16(MPI3MR_HOSTTAG_INITCMDS);
+ diag_buf_manage_req.function = MPI3_FUNCTION_DIAG_BUFFER_MANAGE;
+ diag_buf_manage_req.type = diag_buffer->type;
+ diag_buf_manage_req.action = MPI3_DIAG_BUFFER_ACTION_RELEASE;
+
+
+ dprint_reset(mrioc, "%s: releasing diag buffer type %d\n", __func__,
+ diag_buffer->type);
+ init_completion(&mrioc->init_cmds.done);
+ retval = mpi3mr_admin_request_post(mrioc, &diag_buf_manage_req,
+ sizeof(diag_buf_manage_req), 1);
+ if (retval) {
+ dprint_reset(mrioc, "%s: admin request post failed\n", __func__);
+ mpi3mr_set_trigger_data_in_hdb(diag_buffer,
+ MPI3MR_HDB_TRIGGER_TYPE_UNKNOWN, NULL, 1);
+ goto out_unlock;
+ }
+ wait_for_completion_timeout(&mrioc->init_cmds.done,
+ (MPI3MR_INTADMCMD_TIMEOUT * HZ));
+ if (!(mrioc->init_cmds.state & MPI3MR_CMD_COMPLETE)) {
+ mrioc->init_cmds.is_waiting = 0;
+ dprint_reset(mrioc, "%s: command timedout\n", __func__);
+ mpi3mr_check_rh_fault_ioc(mrioc,
+ MPI3MR_RESET_FROM_DIAG_BUFFER_RELEASE_TIMEOUT);
+ retval = -1;
+ goto out_unlock;
+ }
+ if ((mrioc->init_cmds.ioc_status & MPI3_IOCSTATUS_STATUS_MASK)
+ != MPI3_IOCSTATUS_SUCCESS) {
+ dprint_reset(mrioc,
+ "%s: command failed, buffer_type (%d) ioc_status(0x%04x) log_info(0x%08x)\n",
+ __func__, diag_buffer->type,
+ (mrioc->init_cmds.ioc_status & MPI3_IOCSTATUS_STATUS_MASK),
+ mrioc->init_cmds.ioc_loginfo);
+ retval = -1;
+ goto out_unlock;
+ }
+ dprint_reset(mrioc, "%s: diag buffer type %d released successfully\n",
+ __func__, diag_buffer->type);
+
+out_unlock:
+ mrioc->init_cmds.state = MPI3MR_CMD_NOTUSED;
+ mutex_unlock(&mrioc->init_cmds.mutex);
+ return retval;
+}
+
+/**
+ * mpi3mr_process_trigger - Generic HDB Trigger handler
+ * @mrioc: Adapter instance reference
+ * @trigger_type: Trigger type
+ * @trigger_data: Trigger data
+ * @trigger_flags: Trigger flags
+ *
+ * This function checks validity of HDB, triggers and based on
+ * trigger information, creates an event to be processed in the
+ * firmware event worker thread .
+ *
+ * This function should be called with trigger spinlock held
+ *
+ * Return: Nothing
+ */
+static void mpi3mr_process_trigger(struct mpi3mr_ioc *mrioc, u8 trigger_type,
+ union mpi3mr_trigger_data *trigger_data, u8 trigger_flags)
+{
+ struct trigger_event_data event_data;
+ struct diag_buffer_desc *trace_hdb = NULL;
+ struct diag_buffer_desc *fw_hdb = NULL;
+ u64 global_trigger;
+
+ trace_hdb = mpi3mr_diag_buffer_for_type(mrioc,
+ MPI3_DIAG_BUFFER_TYPE_TRACE);
+ if (trace_hdb &&
+ (trace_hdb->status != MPI3MR_HDB_BUFSTATUS_POSTED_UNPAUSED) &&
+ (trace_hdb->status != MPI3MR_HDB_BUFSTATUS_POSTED_PAUSED))
+ trace_hdb = NULL;
+
+ fw_hdb = mpi3mr_diag_buffer_for_type(mrioc, MPI3_DIAG_BUFFER_TYPE_FW);
+
+ if (fw_hdb &&
+ (fw_hdb->status != MPI3MR_HDB_BUFSTATUS_POSTED_UNPAUSED) &&
+ (fw_hdb->status != MPI3MR_HDB_BUFSTATUS_POSTED_PAUSED))
+ fw_hdb = NULL;
+
+ if (mrioc->snapdump_trigger_active || (mrioc->fw_release_trigger_active
+ && mrioc->trace_release_trigger_active) ||
+ (!trace_hdb && !fw_hdb) || (!mrioc->driver_pg2) ||
+ ((trigger_type == MPI3MR_HDB_TRIGGER_TYPE_ELEMENT)
+ && (!mrioc->driver_pg2->num_triggers)))
+ return;
+
+ memset(&event_data, 0, sizeof(event_data));
+ event_data.trigger_type = trigger_type;
+ memcpy(&event_data.trigger_specific_data, trigger_data,
+ sizeof(*trigger_data));
+ global_trigger = le64_to_cpu(mrioc->driver_pg2->global_trigger);
+
+ if (global_trigger & MPI3_DRIVER2_GLOBALTRIGGER_SNAPDUMP_ENABLED) {
+ event_data.snapdump = true;
+ event_data.trace_hdb = trace_hdb;
+ event_data.fw_hdb = fw_hdb;
+ mrioc->snapdump_trigger_active = true;
+ } else if (trigger_type == MPI3MR_HDB_TRIGGER_TYPE_GLOBAL) {
+ if ((trace_hdb) && (global_trigger &
+ MPI3_DRIVER2_GLOBALTRIGGER_DIAG_TRACE_RELEASE) &&
+ (!mrioc->trace_release_trigger_active)) {
+ event_data.trace_hdb = trace_hdb;
+ mrioc->trace_release_trigger_active = true;
+ }
+ if ((fw_hdb) && (global_trigger &
+ MPI3_DRIVER2_GLOBALTRIGGER_DIAG_FW_RELEASE) &&
+ (!mrioc->fw_release_trigger_active)) {
+ event_data.fw_hdb = fw_hdb;
+ mrioc->fw_release_trigger_active = true;
+ }
+ } else if (trigger_type == MPI3MR_HDB_TRIGGER_TYPE_ELEMENT) {
+ if ((trace_hdb) && (trigger_flags &
+ MPI3_DRIVER2_TRIGGER_FLAGS_DIAG_TRACE_RELEASE) &&
+ (!mrioc->trace_release_trigger_active)) {
+ event_data.trace_hdb = trace_hdb;
+ mrioc->trace_release_trigger_active = true;
+ }
+ if ((fw_hdb) && (trigger_flags &
+ MPI3_DRIVER2_TRIGGER_FLAGS_DIAG_FW_RELEASE) &&
+ (!mrioc->fw_release_trigger_active)) {
+ event_data.fw_hdb = fw_hdb;
+ mrioc->fw_release_trigger_active = true;
+ }
+ }
+
+ if (event_data.trace_hdb || event_data.fw_hdb)
+ mpi3mr_hdb_trigger_data_event(mrioc, &event_data);
+}
+
+/**
+ * mpi3mr_global_trigger - Global HDB trigger handler
+ * @mrioc: Adapter instance reference
+ * @trigger_data: Trigger data
+ *
+ * This function checks whether the given global trigger is
+ * enabled in the driver page 2 and if so calls generic trigger
+ * handler to queue event for HDB release.
+ *
+ * Return: Nothing
+ */
+void mpi3mr_global_trigger(struct mpi3mr_ioc *mrioc, u64 trigger_data)
+{
+ unsigned long flags;
+ union mpi3mr_trigger_data trigger_specific_data;
+
+ spin_lock_irqsave(&mrioc->trigger_lock, flags);
+ if (le64_to_cpu(mrioc->driver_pg2->global_trigger) & trigger_data) {
+ memset(&trigger_specific_data, 0,
+ sizeof(trigger_specific_data));
+ trigger_specific_data.global = trigger_data;
+ mpi3mr_process_trigger(mrioc, MPI3MR_HDB_TRIGGER_TYPE_GLOBAL,
+ &trigger_specific_data, 0);
+ }
+ spin_unlock_irqrestore(&mrioc->trigger_lock, flags);
+}
+
+/**
+ * mpi3mr_scsisense_trigger - SCSI sense HDB trigger handler
+ * @mrioc: Adapter instance reference
+ * @sensekey: Sense Key
+ * @asc: Additional Sense Code
+ * @ascq: Additional Sense Code Qualifier
+ *
+ * This function compares SCSI sense trigger values with driver
+ * page 2 values and calls generic trigger handler to release
+ * HDBs if match found
+ *
+ * Return: Nothing
+ */
+void mpi3mr_scsisense_trigger(struct mpi3mr_ioc *mrioc, u8 sensekey, u8 asc,
+ u8 ascq)
+{
+ struct mpi3_driver2_trigger_scsi_sense *scsi_sense_trigger = NULL;
+ u64 i = 0;
+ unsigned long flags;
+ u8 num_triggers, trigger_flags;
+
+ if (mrioc->scsisense_trigger_present) {
+ spin_lock_irqsave(&mrioc->trigger_lock, flags);
+ scsi_sense_trigger = (struct mpi3_driver2_trigger_scsi_sense *)
+ mrioc->driver_pg2->trigger;
+ num_triggers = mrioc->driver_pg2->num_triggers;
+ for (i = 0; i < num_triggers; i++, scsi_sense_trigger++) {
+ if (scsi_sense_trigger->type !=
+ MPI3_DRIVER2_TRIGGER_TYPE_SCSI_SENSE)
+ continue;
+ if (!(scsi_sense_trigger->sense_key ==
+ MPI3_DRIVER2_TRIGGER_SCSI_SENSE_SENSE_KEY_MATCH_ALL
+ || scsi_sense_trigger->sense_key == sensekey))
+ continue;
+ if (!(scsi_sense_trigger->asc ==
+ MPI3_DRIVER2_TRIGGER_SCSI_SENSE_ASC_MATCH_ALL ||
+ scsi_sense_trigger->asc == asc))
+ continue;
+ if (!(scsi_sense_trigger->ascq ==
+ MPI3_DRIVER2_TRIGGER_SCSI_SENSE_ASCQ_MATCH_ALL ||
+ scsi_sense_trigger->ascq == ascq))
+ continue;
+ trigger_flags = scsi_sense_trigger->flags;
+ mpi3mr_process_trigger(mrioc,
+ MPI3MR_HDB_TRIGGER_TYPE_ELEMENT,
+ (union mpi3mr_trigger_data *)scsi_sense_trigger,
+ trigger_flags);
+ break;
+ }
+ spin_unlock_irqrestore(&mrioc->trigger_lock, flags);
+ }
+}
+
+/**
+ * mpi3mr_event_trigger - MPI event HDB trigger handler
+ * @mrioc: Adapter instance reference
+ * @event: MPI Event
+ *
+ * This function compares event trigger values with driver page
+ * 2 values and calls generic trigger handler to release
+ * HDBs if match found.
+ *
+ * Return: Nothing
+ */
+void mpi3mr_event_trigger(struct mpi3mr_ioc *mrioc, u8 event)
+{
+ struct mpi3_driver2_trigger_event *event_trigger = NULL;
+ u64 i = 0;
+ unsigned long flags;
+ u8 num_triggers, trigger_flags;
+
+ if (mrioc->event_trigger_present) {
+ spin_lock_irqsave(&mrioc->trigger_lock, flags);
+ event_trigger = (struct mpi3_driver2_trigger_event *)
+ mrioc->driver_pg2->trigger;
+ num_triggers = mrioc->driver_pg2->num_triggers;
+
+ for (i = 0; i < num_triggers; i++, event_trigger++) {
+ if (event_trigger->type !=
+ MPI3_DRIVER2_TRIGGER_TYPE_EVENT)
+ continue;
+ if (event_trigger->event != event)
+ continue;
+ trigger_flags = event_trigger->flags;
+ mpi3mr_process_trigger(mrioc,
+ MPI3MR_HDB_TRIGGER_TYPE_ELEMENT,
+ (union mpi3mr_trigger_data *)event_trigger,
+ trigger_flags);
+ break;
+ }
+ spin_unlock_irqrestore(&mrioc->trigger_lock, flags);
+ }
+}
+
+/**
+ * mpi3mr_reply_trigger - MPI Reply HDB trigger handler
+ * @mrioc: Adapter instance reference
+ * @ioc_status: Masked value of IOC Status from MPI Reply
+ * @ioc_loginfo: IOC Log Info from MPI Reply
+ *
+ * This function compares IOC status and IOC log info trigger
+ * values with driver page 2 values and calls generic trigger
+ * handler to release HDBs if match found.
+ *
+ * Return: Nothing
+ */
+void mpi3mr_reply_trigger(struct mpi3mr_ioc *mrioc, u16 ioc_status,
+ u32 ioc_loginfo)
+{
+ struct mpi3_driver2_trigger_reply *reply_trigger = NULL;
+ u64 i = 0;
+ unsigned long flags;
+ u8 num_triggers, trigger_flags;
+
+ if (mrioc->reply_trigger_present) {
+ spin_lock_irqsave(&mrioc->trigger_lock, flags);
+ reply_trigger = (struct mpi3_driver2_trigger_reply *)
+ mrioc->driver_pg2->trigger;
+ num_triggers = mrioc->driver_pg2->num_triggers;
+ for (i = 0; i < num_triggers; i++, reply_trigger++) {
+ if (reply_trigger->type !=
+ MPI3_DRIVER2_TRIGGER_TYPE_REPLY)
+ continue;
+ if ((le16_to_cpu(reply_trigger->ioc_status) !=
+ ioc_status)
+ && (le16_to_cpu(reply_trigger->ioc_status) !=
+ MPI3_DRIVER2_TRIGGER_REPLY_IOCSTATUS_MATCH_ALL))
+ continue;
+ if ((le32_to_cpu(reply_trigger->ioc_log_info) !=
+ (le32_to_cpu(reply_trigger->ioc_log_info_mask) &
+ ioc_loginfo)))
+ continue;
+ trigger_flags = reply_trigger->flags;
+ mpi3mr_process_trigger(mrioc,
+ MPI3MR_HDB_TRIGGER_TYPE_ELEMENT,
+ (union mpi3mr_trigger_data *)reply_trigger,
+ trigger_flags);
+ break;
+ }
+ spin_unlock_irqrestore(&mrioc->trigger_lock, flags);
+ }
+}
+
+/**
+ * mpi3mr_get_num_trigger - Gets number of HDB triggers
+ * @mrioc: Adapter instance reference
+ * @num_triggers: Number of triggers
+ * @page_action: Page action
+ *
+ * This function reads number of triggers by reading driver page
+ * 2
+ *
+ * Return: 0 on success and proper error codes on failure
+ */
+static int mpi3mr_get_num_trigger(struct mpi3mr_ioc *mrioc, u8 *num_triggers,
+ u8 page_action)
+{
+ struct mpi3_driver_page2 drvr_page2;
+ int retval = 0;
+
+ *num_triggers = 0;
+
+ retval = mpi3mr_cfg_get_driver_pg2(mrioc, &drvr_page2,
+ sizeof(struct mpi3_driver_page2), page_action);
+
+ if (retval) {
+ dprint_init(mrioc, "%s: driver page 2 read failed\n", __func__);
+ return retval;
+ }
+ *num_triggers = drvr_page2.num_triggers;
+ return retval;
+}
+
+/**
+ * mpi3mr_refresh_trigger - Handler for Refresh trigger BSG
+ * @mrioc: Adapter instance reference
+ * @page_action: Page action
+ *
+ * This function caches the driver page 2 in the driver's memory
+ * by reading driver page 2 from the controller for a given page
+ * type and updates the HDB trigger values
+ *
+ * Return: 0 on success and proper error codes on failure
+ */
+int mpi3mr_refresh_trigger(struct mpi3mr_ioc *mrioc, u8 page_action)
+{
+ u16 pg_sz = sizeof(struct mpi3_driver_page2);
+ struct mpi3_driver_page2 *drvr_page2 = NULL;
+ u8 trigger_type, num_triggers;
+ int retval;
+ int i = 0;
+ unsigned long flags;
+
+ retval = mpi3mr_get_num_trigger(mrioc, &num_triggers, page_action);
+
+ if (retval)
+ goto out;
+
+ pg_sz = offsetof(struct mpi3_driver_page2, trigger) +
+ (num_triggers * sizeof(union mpi3_driver2_trigger_element));
+ drvr_page2 = kzalloc(pg_sz, GFP_KERNEL);
+ if (!drvr_page2) {
+ retval = -ENOMEM;
+ goto out;
+ }
+
+ retval = mpi3mr_cfg_get_driver_pg2(mrioc, drvr_page2, pg_sz, page_action);
+ if (retval) {
+ dprint_init(mrioc, "%s: driver page 2 read failed\n", __func__);
+ kfree(drvr_page2);
+ goto out;
+ }
+ spin_lock_irqsave(&mrioc->trigger_lock, flags);
+ kfree(mrioc->driver_pg2);
+ mrioc->driver_pg2 = drvr_page2;
+ mrioc->reply_trigger_present = false;
+ mrioc->event_trigger_present = false;
+ mrioc->scsisense_trigger_present = false;
+
+ for (i = 0; (i < mrioc->driver_pg2->num_triggers); i++) {
+ trigger_type = mrioc->driver_pg2->trigger[i].event.type;
+ switch (trigger_type) {
+ case MPI3_DRIVER2_TRIGGER_TYPE_REPLY:
+ mrioc->reply_trigger_present = true;
+ break;
+ case MPI3_DRIVER2_TRIGGER_TYPE_EVENT:
+ mrioc->event_trigger_present = true;
+ break;
+ case MPI3_DRIVER2_TRIGGER_TYPE_SCSI_SENSE:
+ mrioc->scsisense_trigger_present = true;
+ break;
+ default:
+ break;
+ }
+ }
+ spin_unlock_irqrestore(&mrioc->trigger_lock, flags);
+out:
+ return retval;
+}
+
+/**
+ * mpi3mr_release_diag_bufs - Release diag buffers
+ * @mrioc: Adapter instance reference
+ * @skip_rel_action: Skip release action and set buffer state
+ *
+ * This function calls helper function to release both trace and
+ * firmware buffers from the controller.
+ *
+ * Return: None
+ */
+void mpi3mr_release_diag_bufs(struct mpi3mr_ioc *mrioc, u8 skip_rel_action)
+{
+ u8 i;
+ struct diag_buffer_desc *diag_buffer;
+
+ for (i = 0; i < MPI3MR_MAX_NUM_HDB; i++) {
+ diag_buffer = &mrioc->diag_buffers[i];
+ if (!(diag_buffer->addr))
+ continue;
+ if (diag_buffer->status == MPI3MR_HDB_BUFSTATUS_RELEASED)
+ continue;
+ if (!skip_rel_action)
+ mpi3mr_issue_diag_buf_release(mrioc, diag_buffer);
+ diag_buffer->status = MPI3MR_HDB_BUFSTATUS_RELEASED;
+ atomic64_inc(&event_counter);
+ }
+}
+
+/**
+ * mpi3mr_set_trigger_data_in_hdb - Updates HDB trigger type and
+ * trigger data
+ *
+ * @hdb: HDB pointer
+ * @type: Trigger type
+ * @data: Trigger data
+ * @force: Trigger overwrite flag
+ * @trigger_data: Pointer to trigger data information
+ *
+ * Updates trigger type and trigger data based on parameter
+ * passed to this function
+ *
+ * Return: Nothing
+ */
+void mpi3mr_set_trigger_data_in_hdb(struct diag_buffer_desc *hdb,
+ u8 type, union mpi3mr_trigger_data *trigger_data, bool force)
+{
+ if ((!force) && (hdb->trigger_type != MPI3MR_HDB_TRIGGER_TYPE_UNKNOWN))
+ return;
+ hdb->trigger_type = type;
+ if (!trigger_data)
+ memset(&hdb->trigger_data, 0, sizeof(*trigger_data));
+ else
+ memcpy(&hdb->trigger_data, trigger_data, sizeof(*trigger_data));
+}
+
+/**
+ * mpi3mr_set_trigger_data_in_all_hdb - Updates HDB trigger type
+ * and trigger data for all HDB
+ *
+ * @mrioc: Adapter instance reference
+ * @type: Trigger type
+ * @data: Trigger data
+ * @force: Trigger overwrite flag
+ * @trigger_data: Pointer to trigger data information
+ *
+ * Updates trigger type and trigger data based on parameter
+ * passed to this function
+ *
+ * Return: Nothing
+ */
+void mpi3mr_set_trigger_data_in_all_hdb(struct mpi3mr_ioc *mrioc,
+ u8 type, union mpi3mr_trigger_data *trigger_data, bool force)
+{
+ struct diag_buffer_desc *hdb = NULL;
+
+ hdb = mpi3mr_diag_buffer_for_type(mrioc, MPI3_DIAG_BUFFER_TYPE_TRACE);
+ if (hdb)
+ mpi3mr_set_trigger_data_in_hdb(hdb, type, trigger_data, force);
+ hdb = mpi3mr_diag_buffer_for_type(mrioc, MPI3_DIAG_BUFFER_TYPE_FW);
+ if (hdb)
+ mpi3mr_set_trigger_data_in_hdb(hdb, type, trigger_data, force);
+}
+
+/**
+ * mpi3mr_hdbstatuschg_evt_th - HDB status change evt tophalf
+ * @mrioc: Adapter instance reference
+ * @event_reply: event data
+ *
+ * Modifies the status of the applicable diag buffer descriptors
+ *
+ * Return: Nothing
+ */
+void mpi3mr_hdbstatuschg_evt_th(struct mpi3mr_ioc *mrioc,
+ struct mpi3_event_notification_reply *event_reply)
+{
+ struct mpi3_event_data_diag_buffer_status_change *evtdata;
+ struct diag_buffer_desc *diag_buffer;
+
+ evtdata = (struct mpi3_event_data_diag_buffer_status_change *)
+ event_reply->event_data;
+
+ diag_buffer = mpi3mr_diag_buffer_for_type(mrioc, evtdata->type);
+ if (!diag_buffer)
+ return;
+ if ((diag_buffer->status != MPI3MR_HDB_BUFSTATUS_POSTED_UNPAUSED) &&
+ (diag_buffer->status != MPI3MR_HDB_BUFSTATUS_POSTED_PAUSED))
+ return;
+ switch (evtdata->reason_code) {
+ case MPI3_EVENT_DIAG_BUFFER_STATUS_CHANGE_RC_RELEASED:
+ {
+ diag_buffer->status = MPI3MR_HDB_BUFSTATUS_RELEASED;
+ mpi3mr_set_trigger_data_in_hdb(diag_buffer,
+ MPI3MR_HDB_TRIGGER_TYPE_FW_RELEASED, NULL, 0);
+ atomic64_inc(&event_counter);
+ break;
+ }
+ case MPI3_EVENT_DIAG_BUFFER_STATUS_CHANGE_RC_RESUMED:
+ {
+ diag_buffer->status = MPI3MR_HDB_BUFSTATUS_POSTED_UNPAUSED;
+ break;
+ }
+ case MPI3_EVENT_DIAG_BUFFER_STATUS_CHANGE_RC_PAUSED:
+ {
+ diag_buffer->status = MPI3MR_HDB_BUFSTATUS_POSTED_PAUSED;
+ break;
+ }
+ default:
+ dprint_event_th(mrioc, "%s: unknown reason_code(%d)\n",
+ __func__, evtdata->reason_code);
+ break;
+ }
+}
+
+/**
+ * mpi3mr_diag_buffer_for_type - returns buffer desc for type
+ * @mrioc: Adapter instance reference
+ * @buf_type: Diagnostic buffer type
+ *
+ * Identifies matching diag descriptor from mrioc for given diag
+ * buffer type.
+ *
+ * Return: diag buffer descriptor on success, NULL on failures.
+ */
+
+struct diag_buffer_desc *
+mpi3mr_diag_buffer_for_type(struct mpi3mr_ioc *mrioc, u8 buf_type)
+{
+ u8 i;
+
+ for (i = 0; i < MPI3MR_MAX_NUM_HDB; i++) {
+ if (mrioc->diag_buffers[i].type == buf_type)
+ return &mrioc->diag_buffers[i];
+ }
+ return NULL;
+}
+
+/**
* mpi3mr_bsg_pel_abort - sends PEL abort request
* @mrioc: Adapter instance reference
*
@@ -31,7 +937,7 @@ static int mpi3mr_bsg_pel_abort(struct mpi3mr_ioc *mrioc)
dprint_bsg_err(mrioc, "%s: reset in progress\n", __func__);
return -1;
}
- if (mrioc->stop_bsgs) {
+ if (mrioc->stop_bsgs || mrioc->block_on_pci_err) {
dprint_bsg_err(mrioc, "%s: bsgs are blocked\n", __func__);
return -1;
}
@@ -126,6 +1032,259 @@ static struct mpi3mr_ioc *mpi3mr_bsg_verify_adapter(int ioc_number)
}
/**
+ * mpi3mr_bsg_refresh_hdb_triggers - Refresh HDB trigger data
+ * @mrioc: Adapter instance reference
+ * @job: BSG Job pointer
+ *
+ * This function reads the controller trigger config page as
+ * defined by the input page type and refreshes the driver's
+ * local trigger information structures with the controller's
+ * config page data.
+ *
+ * Return: 0 on success and proper error codes on failure
+ */
+static long
+mpi3mr_bsg_refresh_hdb_triggers(struct mpi3mr_ioc *mrioc,
+ struct bsg_job *job)
+{
+ struct mpi3mr_bsg_out_refresh_hdb_triggers refresh_triggers;
+ uint32_t data_out_sz;
+ u8 page_action;
+ long rval = -EINVAL;
+
+ data_out_sz = job->request_payload.payload_len;
+
+ if (data_out_sz != sizeof(refresh_triggers)) {
+ dprint_bsg_err(mrioc, "%s: invalid size argument\n",
+ __func__);
+ return rval;
+ }
+
+ if (mrioc->unrecoverable) {
+ dprint_bsg_err(mrioc, "%s: unrecoverable controller\n",
+ __func__);
+ return -EFAULT;
+ }
+ if (mrioc->reset_in_progress) {
+ dprint_bsg_err(mrioc, "%s: reset in progress\n", __func__);
+ return -EAGAIN;
+ }
+
+ sg_copy_to_buffer(job->request_payload.sg_list,
+ job->request_payload.sg_cnt,
+ &refresh_triggers, sizeof(refresh_triggers));
+
+ switch (refresh_triggers.page_type) {
+ case MPI3MR_HDB_REFRESH_TYPE_CURRENT:
+ page_action = MPI3_CONFIG_ACTION_READ_CURRENT;
+ break;
+ case MPI3MR_HDB_REFRESH_TYPE_DEFAULT:
+ page_action = MPI3_CONFIG_ACTION_READ_DEFAULT;
+ break;
+ case MPI3MR_HDB_HDB_REFRESH_TYPE_PERSISTENT:
+ page_action = MPI3_CONFIG_ACTION_READ_PERSISTENT;
+ break;
+ default:
+ dprint_bsg_err(mrioc,
+ "%s: unsupported refresh trigger, page_type %d\n",
+ __func__, refresh_triggers.page_type);
+ return rval;
+ }
+ rval = mpi3mr_refresh_trigger(mrioc, page_action);
+
+ return rval;
+}
+
+/**
+ * mpi3mr_bsg_upload_hdb - Upload a specific HDB to user space
+ * @mrioc: Adapter instance reference
+ * @job: BSG Job pointer
+ *
+ * Return: 0 on success and proper error codes on failure
+ */
+static long mpi3mr_bsg_upload_hdb(struct mpi3mr_ioc *mrioc,
+ struct bsg_job *job)
+{
+ struct mpi3mr_bsg_out_upload_hdb upload_hdb;
+ struct diag_buffer_desc *diag_buffer;
+ uint32_t data_out_size;
+ uint32_t data_in_size;
+
+ data_out_size = job->request_payload.payload_len;
+ data_in_size = job->reply_payload.payload_len;
+
+ if (data_out_size != sizeof(upload_hdb)) {
+ dprint_bsg_err(mrioc, "%s: invalid size argument\n",
+ __func__);
+ return -EINVAL;
+ }
+
+ sg_copy_to_buffer(job->request_payload.sg_list,
+ job->request_payload.sg_cnt,
+ &upload_hdb, sizeof(upload_hdb));
+
+ if ((!upload_hdb.length) || (data_in_size != upload_hdb.length)) {
+ dprint_bsg_err(mrioc, "%s: invalid length argument\n",
+ __func__);
+ return -EINVAL;
+ }
+ diag_buffer = mpi3mr_diag_buffer_for_type(mrioc, upload_hdb.buf_type);
+ if ((!diag_buffer) || (!diag_buffer->addr)) {
+ dprint_bsg_err(mrioc, "%s: invalid buffer type %d\n",
+ __func__, upload_hdb.buf_type);
+ return -EINVAL;
+ }
+
+ if ((diag_buffer->status != MPI3MR_HDB_BUFSTATUS_RELEASED) &&
+ (diag_buffer->status != MPI3MR_HDB_BUFSTATUS_POSTED_PAUSED)) {
+ dprint_bsg_err(mrioc,
+ "%s: invalid buffer status %d for type %d\n",
+ __func__, diag_buffer->status, upload_hdb.buf_type);
+ return -EINVAL;
+ }
+
+ if ((upload_hdb.start_offset + upload_hdb.length) > diag_buffer->size) {
+ dprint_bsg_err(mrioc,
+ "%s: invalid start offset %d, length %d for type %d\n",
+ __func__, upload_hdb.start_offset, upload_hdb.length,
+ upload_hdb.buf_type);
+ return -EINVAL;
+ }
+ sg_copy_from_buffer(job->reply_payload.sg_list,
+ job->reply_payload.sg_cnt,
+ (diag_buffer->addr + upload_hdb.start_offset),
+ data_in_size);
+ return 0;
+}
+
+/**
+ * mpi3mr_bsg_repost_hdb - Re-post HDB
+ * @mrioc: Adapter instance reference
+ * @job: BSG job pointer
+ *
+ * This function retrieves the HDB descriptor corresponding to a
+ * given buffer type and if the HDB is in released status then
+ * posts the HDB with the firmware.
+ *
+ * Return: 0 on success and proper error codes on failure
+ */
+static long mpi3mr_bsg_repost_hdb(struct mpi3mr_ioc *mrioc,
+ struct bsg_job *job)
+{
+ struct mpi3mr_bsg_out_repost_hdb repost_hdb;
+ struct diag_buffer_desc *diag_buffer;
+ uint32_t data_out_sz;
+
+ data_out_sz = job->request_payload.payload_len;
+
+ if (data_out_sz != sizeof(repost_hdb)) {
+ dprint_bsg_err(mrioc, "%s: invalid size argument\n",
+ __func__);
+ return -EINVAL;
+ }
+ if (mrioc->unrecoverable) {
+ dprint_bsg_err(mrioc, "%s: unrecoverable controller\n",
+ __func__);
+ return -EFAULT;
+ }
+ if (mrioc->reset_in_progress) {
+ dprint_bsg_err(mrioc, "%s: reset in progress\n", __func__);
+ return -EAGAIN;
+ }
+
+ sg_copy_to_buffer(job->request_payload.sg_list,
+ job->request_payload.sg_cnt,
+ &repost_hdb, sizeof(repost_hdb));
+
+ diag_buffer = mpi3mr_diag_buffer_for_type(mrioc, repost_hdb.buf_type);
+ if ((!diag_buffer) || (!diag_buffer->addr)) {
+ dprint_bsg_err(mrioc, "%s: invalid buffer type %d\n",
+ __func__, repost_hdb.buf_type);
+ return -EINVAL;
+ }
+
+ if (diag_buffer->status != MPI3MR_HDB_BUFSTATUS_RELEASED) {
+ dprint_bsg_err(mrioc,
+ "%s: invalid buffer status %d for type %d\n",
+ __func__, diag_buffer->status, repost_hdb.buf_type);
+ return -EINVAL;
+ }
+
+ if (mpi3mr_issue_diag_buf_post(mrioc, diag_buffer)) {
+ dprint_bsg_err(mrioc, "%s: post failed for type %d\n",
+ __func__, repost_hdb.buf_type);
+ return -EFAULT;
+ }
+ mpi3mr_set_trigger_data_in_hdb(diag_buffer,
+ MPI3MR_HDB_TRIGGER_TYPE_UNKNOWN, NULL, 1);
+
+ return 0;
+}
+
+/**
+ * mpi3mr_bsg_query_hdb - Handler for query HDB command
+ * @mrioc: Adapter instance reference
+ * @job: BSG job pointer
+ *
+ * This function prepares and copies the host diagnostic buffer
+ * entries to the user buffer.
+ *
+ * Return: 0 on success and proper error codes on failure
+ */
+static long mpi3mr_bsg_query_hdb(struct mpi3mr_ioc *mrioc,
+ struct bsg_job *job)
+{
+ long rval = 0;
+ struct mpi3mr_bsg_in_hdb_status *hbd_status;
+ struct mpi3mr_hdb_entry *hbd_status_entry;
+ u32 length, min_length;
+ u8 i;
+ struct diag_buffer_desc *diag_buffer;
+ uint32_t data_in_sz = 0;
+
+ data_in_sz = job->request_payload.payload_len;
+
+ length = (sizeof(*hbd_status) + ((MPI3MR_MAX_NUM_HDB - 1) *
+ sizeof(*hbd_status_entry)));
+ hbd_status = kmalloc(length, GFP_KERNEL);
+ if (!hbd_status)
+ return -ENOMEM;
+ hbd_status_entry = &hbd_status->entry[0];
+
+ hbd_status->num_hdb_types = MPI3MR_MAX_NUM_HDB;
+ for (i = 0; i < MPI3MR_MAX_NUM_HDB; i++) {
+ diag_buffer = &mrioc->diag_buffers[i];
+ hbd_status_entry->buf_type = diag_buffer->type;
+ hbd_status_entry->status = diag_buffer->status;
+ hbd_status_entry->trigger_type = diag_buffer->trigger_type;
+ memcpy(&hbd_status_entry->trigger_data,
+ &diag_buffer->trigger_data,
+ sizeof(hbd_status_entry->trigger_data));
+ hbd_status_entry->size = (diag_buffer->size / 1024);
+ hbd_status_entry++;
+ }
+ hbd_status->element_trigger_format =
+ MPI3MR_HDB_QUERY_ELEMENT_TRIGGER_FORMAT_DATA;
+
+ if (data_in_sz < 4) {
+ dprint_bsg_err(mrioc, "%s: invalid size passed\n", __func__);
+ rval = -EINVAL;
+ goto out;
+ }
+ min_length = min(data_in_sz, length);
+ if (job->request_payload.payload_len >= min_length) {
+ sg_copy_from_buffer(job->request_payload.sg_list,
+ job->request_payload.sg_cnt,
+ hbd_status, min_length);
+ rval = 0;
+ }
+out:
+ kfree(hbd_status);
+ return rval;
+}
+
+
+/**
* mpi3mr_enable_logdata - Handler for log data enable
* @mrioc: Adapter instance reference
* @job: BSG job reference
@@ -424,6 +1583,9 @@ static long mpi3mr_bsg_adp_reset(struct mpi3mr_ioc *mrioc,
goto out;
}
+ if (mrioc->unrecoverable || mrioc->block_on_pci_err)
+ return -EINVAL;
+
sg_copy_to_buffer(job->request_payload.sg_list,
job->request_payload.sg_cnt,
&adpreset, sizeof(adpreset));
@@ -553,6 +1715,18 @@ static long mpi3mr_bsg_process_drv_cmds(struct bsg_job *job)
case MPI3MR_DRVBSG_OPCODE_PELENABLE:
rval = mpi3mr_bsg_pel_enable(mrioc, job);
break;
+ case MPI3MR_DRVBSG_OPCODE_QUERY_HDB:
+ rval = mpi3mr_bsg_query_hdb(mrioc, job);
+ break;
+ case MPI3MR_DRVBSG_OPCODE_REPOST_HDB:
+ rval = mpi3mr_bsg_repost_hdb(mrioc, job);
+ break;
+ case MPI3MR_DRVBSG_OPCODE_UPLOAD_HDB:
+ rval = mpi3mr_bsg_upload_hdb(mrioc, job);
+ break;
+ case MPI3MR_DRVBSG_OPCODE_REFRESH_HDB_TRIGGERS:
+ rval = mpi3mr_bsg_refresh_hdb_triggers(mrioc, job);
+ break;
case MPI3MR_DRVBSG_OPCODE_UNKNOWN:
default:
pr_err("%s: unsupported driver command opcode %d\n",
@@ -1241,7 +2415,17 @@ static long mpi3mr_bsg_process_mpt_cmds(struct bsg_job *job)
if (!mrioc)
return -ENODEV;
+ if (mutex_lock_interruptible(&mrioc->bsg_cmds.mutex))
+ return -ERESTARTSYS;
+
+ if (mrioc->bsg_cmds.state & MPI3MR_CMD_PENDING) {
+ dprint_bsg_err(mrioc, "%s: command is in use\n", __func__);
+ mutex_unlock(&mrioc->bsg_cmds.mutex);
+ return -EAGAIN;
+ }
+
if (!mrioc->ioctl_sges_allocated) {
+ mutex_unlock(&mrioc->bsg_cmds.mutex);
dprint_bsg_err(mrioc, "%s: DMA memory was not allocated\n",
__func__);
return -ENOMEM;
@@ -1251,13 +2435,16 @@ static long mpi3mr_bsg_process_mpt_cmds(struct bsg_job *job)
karg->timeout = MPI3MR_APP_DEFAULT_TIMEOUT;
mpi_req = kzalloc(MPI3MR_ADMIN_REQ_FRAME_SZ, GFP_KERNEL);
- if (!mpi_req)
+ if (!mpi_req) {
+ mutex_unlock(&mrioc->bsg_cmds.mutex);
return -ENOMEM;
+ }
mpi_header = (struct mpi3_request_header *)mpi_req;
bufcnt = karg->buf_entry_list.num_of_entries;
drv_bufs = kzalloc((sizeof(*drv_bufs) * bufcnt), GFP_KERNEL);
if (!drv_bufs) {
+ mutex_unlock(&mrioc->bsg_cmds.mutex);
rval = -ENOMEM;
goto out;
}
@@ -1265,6 +2452,7 @@ static long mpi3mr_bsg_process_mpt_cmds(struct bsg_job *job)
dout_buf = kzalloc(job->request_payload.payload_len,
GFP_KERNEL);
if (!dout_buf) {
+ mutex_unlock(&mrioc->bsg_cmds.mutex);
rval = -ENOMEM;
goto out;
}
@@ -1272,6 +2460,7 @@ static long mpi3mr_bsg_process_mpt_cmds(struct bsg_job *job)
din_buf = kzalloc(job->reply_payload.payload_len,
GFP_KERNEL);
if (!din_buf) {
+ mutex_unlock(&mrioc->bsg_cmds.mutex);
rval = -ENOMEM;
goto out;
}
@@ -1347,6 +2536,7 @@ static long mpi3mr_bsg_process_mpt_cmds(struct bsg_job *job)
(mpi_msg_size > MPI3MR_ADMIN_REQ_FRAME_SZ)) {
dprint_bsg_err(mrioc, "%s: invalid MPI message size\n",
__func__);
+ mutex_unlock(&mrioc->bsg_cmds.mutex);
rval = -EINVAL;
goto out;
}
@@ -1359,6 +2549,7 @@ static long mpi3mr_bsg_process_mpt_cmds(struct bsg_job *job)
if (invalid_be) {
dprint_bsg_err(mrioc, "%s: invalid buffer entries passed\n",
__func__);
+ mutex_unlock(&mrioc->bsg_cmds.mutex);
rval = -EINVAL;
goto out;
}
@@ -1366,12 +2557,14 @@ static long mpi3mr_bsg_process_mpt_cmds(struct bsg_job *job)
if (sgl_dout_iter > (dout_buf + job->request_payload.payload_len)) {
dprint_bsg_err(mrioc, "%s: data_out buffer length mismatch\n",
__func__);
+ mutex_unlock(&mrioc->bsg_cmds.mutex);
rval = -EINVAL;
goto out;
}
if (sgl_din_iter > (din_buf + job->reply_payload.payload_len)) {
dprint_bsg_err(mrioc, "%s: data_in buffer length mismatch\n",
__func__);
+ mutex_unlock(&mrioc->bsg_cmds.mutex);
rval = -EINVAL;
goto out;
}
@@ -1384,6 +2577,7 @@ static long mpi3mr_bsg_process_mpt_cmds(struct bsg_job *job)
dprint_bsg_err(mrioc, "%s:%d: invalid data transfer size passed for function 0x%x din_size = %d, dout_size = %d\n",
__func__, __LINE__, mpi_header->function, din_size,
dout_size);
+ mutex_unlock(&mrioc->bsg_cmds.mutex);
rval = -EINVAL;
goto out;
}
@@ -1392,6 +2586,7 @@ static long mpi3mr_bsg_process_mpt_cmds(struct bsg_job *job)
dprint_bsg_err(mrioc,
"%s:%d: invalid data transfer size passed for function 0x%x din_size=%d\n",
__func__, __LINE__, mpi_header->function, din_size);
+ mutex_unlock(&mrioc->bsg_cmds.mutex);
rval = -EINVAL;
goto out;
}
@@ -1399,6 +2594,7 @@ static long mpi3mr_bsg_process_mpt_cmds(struct bsg_job *job)
dprint_bsg_err(mrioc,
"%s:%d: invalid data transfer size passed for function 0x%x dout_size = %d\n",
__func__, __LINE__, mpi_header->function, dout_size);
+ mutex_unlock(&mrioc->bsg_cmds.mutex);
rval = -EINVAL;
goto out;
}
@@ -1409,6 +2605,7 @@ static long mpi3mr_bsg_process_mpt_cmds(struct bsg_job *job)
dprint_bsg_err(mrioc, "%s:%d: invalid message size passed:%d:%d:%d:%d\n",
__func__, __LINE__, din_cnt, dout_cnt, din_size,
dout_size);
+ mutex_unlock(&mrioc->bsg_cmds.mutex);
rval = -EINVAL;
goto out;
}
@@ -1456,6 +2653,7 @@ static long mpi3mr_bsg_process_mpt_cmds(struct bsg_job *job)
continue;
if (mpi3mr_map_data_buffer_dma(mrioc, drv_buf_iter, desc_count)) {
rval = -ENOMEM;
+ mutex_unlock(&mrioc->bsg_cmds.mutex);
dprint_bsg_err(mrioc, "%s:%d: mapping data buffers failed\n",
__func__, __LINE__);
goto out;
@@ -1468,20 +2666,11 @@ static long mpi3mr_bsg_process_mpt_cmds(struct bsg_job *job)
sense_buff_k = kzalloc(erbsz, GFP_KERNEL);
if (!sense_buff_k) {
rval = -ENOMEM;
+ mutex_unlock(&mrioc->bsg_cmds.mutex);
goto out;
}
}
- if (mutex_lock_interruptible(&mrioc->bsg_cmds.mutex)) {
- rval = -ERESTARTSYS;
- goto out;
- }
- if (mrioc->bsg_cmds.state & MPI3MR_CMD_PENDING) {
- rval = -EAGAIN;
- dprint_bsg_err(mrioc, "%s: command is in use\n", __func__);
- mutex_unlock(&mrioc->bsg_cmds.mutex);
- goto out;
- }
if (mrioc->unrecoverable) {
dprint_bsg_err(mrioc, "%s: unrecoverable controller\n",
__func__);
@@ -1495,7 +2684,7 @@ static long mpi3mr_bsg_process_mpt_cmds(struct bsg_job *job)
mutex_unlock(&mrioc->bsg_cmds.mutex);
goto out;
}
- if (mrioc->stop_bsgs) {
+ if (mrioc->stop_bsgs || mrioc->block_on_pci_err) {
dprint_bsg_err(mrioc, "%s: bsgs are blocked\n", __func__);
rval = -EAGAIN;
mutex_unlock(&mrioc->bsg_cmds.mutex);
@@ -1598,26 +2787,33 @@ static long mpi3mr_bsg_process_mpt_cmds(struct bsg_job *job)
rval = -EAGAIN;
if (mrioc->bsg_cmds.state & MPI3MR_CMD_RESET)
goto out_unlock;
- dprint_bsg_err(mrioc,
- "%s: bsg request timedout after %d seconds\n", __func__,
- karg->timeout);
- if (mrioc->logging_level & MPI3_DEBUG_BSG_ERROR) {
- dprint_dump(mpi_req, MPI3MR_ADMIN_REQ_FRAME_SZ,
+ if (((mpi_header->function != MPI3_FUNCTION_SCSI_IO) &&
+ (mpi_header->function != MPI3_FUNCTION_NVME_ENCAPSULATED))
+ || (mrioc->logging_level & MPI3_DEBUG_BSG_ERROR)) {
+ ioc_info(mrioc, "%s: bsg request timedout after %d seconds\n",
+ __func__, karg->timeout);
+ if (!(mrioc->logging_level & MPI3_DEBUG_BSG_INFO)) {
+ dprint_dump(mpi_req, MPI3MR_ADMIN_REQ_FRAME_SZ,
"bsg_mpi3_req");
if (mpi_header->function ==
- MPI3_BSG_FUNCTION_MGMT_PASSTHROUGH) {
+ MPI3_FUNCTION_MGMT_PASSTHROUGH) {
drv_buf_iter = &drv_bufs[0];
dprint_dump(drv_buf_iter->kern_buf,
rmc_size, "mpi3_mgmt_req");
+ }
}
}
if ((mpi_header->function == MPI3_BSG_FUNCTION_NVME_ENCAPSULATED) ||
- (mpi_header->function == MPI3_BSG_FUNCTION_SCSI_IO))
+ (mpi_header->function == MPI3_BSG_FUNCTION_SCSI_IO)) {
+ dprint_bsg_err(mrioc, "%s: bsg request timedout after %d seconds,\n"
+ "issuing target reset to (0x%04x)\n", __func__,
+ karg->timeout, mpi_header->function_dependent);
mpi3mr_issue_tm(mrioc,
MPI3_SCSITASKMGMT_TASKTYPE_TARGET_RESET,
mpi_header->function_dependent, 0,
MPI3MR_HOSTTAG_BLK_TMS, MPI3MR_RESETTM_TIMEOUT,
&mrioc->host_tm_cmds, &resp_code, NULL);
+ }
if (!(mrioc->bsg_cmds.state & MPI3MR_CMD_COMPLETE) &&
!(mrioc->bsg_cmds.state & MPI3MR_CMD_RESET))
mpi3mr_soft_reset_handler(mrioc,
@@ -1838,6 +3034,11 @@ void mpi3mr_bsg_init(struct mpi3mr_ioc *mrioc)
{
struct device *bsg_dev = &mrioc->bsg_dev;
struct device *parent = &mrioc->shost->shost_gendev;
+ struct queue_limits lim = {
+ .max_hw_sectors = MPI3MR_MAX_APP_XFER_SECTORS,
+ .max_segments = MPI3MR_MAX_APP_XFER_SEGMENTS,
+ };
+ struct request_queue *q;
device_initialize(bsg_dev);
@@ -1853,9 +3054,9 @@ void mpi3mr_bsg_init(struct mpi3mr_ioc *mrioc)
return;
}
- mrioc->bsg_queue = bsg_setup_queue(bsg_dev, dev_name(bsg_dev),
+ q = bsg_setup_queue(bsg_dev, dev_name(bsg_dev), &lim,
mpi3mr_bsg_request, NULL, 0);
- if (IS_ERR(mrioc->bsg_queue)) {
+ if (IS_ERR(q)) {
ioc_err(mrioc, "%s: bsg registration failed\n",
dev_name(bsg_dev));
device_del(bsg_dev);
@@ -1863,10 +3064,7 @@ void mpi3mr_bsg_init(struct mpi3mr_ioc *mrioc)
return;
}
- blk_queue_max_segments(mrioc->bsg_queue, MPI3MR_MAX_APP_XFER_SEGMENTS);
- blk_queue_max_hw_sectors(mrioc->bsg_queue, MPI3MR_MAX_APP_XFER_SECTORS);
-
- return;
+ mrioc->bsg_queue = q;
}
/**
@@ -1950,6 +3148,29 @@ reply_queue_count_show(struct device *dev, struct device_attribute *attr,
static DEVICE_ATTR_RO(reply_queue_count);
/**
+ * reply_qfull_count_show - Show reply qfull count
+ * @dev: class device
+ * @attr: Device attributes
+ * @buf: Buffer to copy
+ *
+ * Retrieves the current value of the reply_qfull_count from the mrioc structure and
+ * formats it as a string for display.
+ *
+ * Return: sysfs_emit() return
+ */
+static ssize_t
+reply_qfull_count_show(struct device *dev, struct device_attribute *attr,
+ char *buf)
+{
+ struct Scsi_Host *shost = class_to_shost(dev);
+ struct mpi3mr_ioc *mrioc = shost_priv(shost);
+
+ return sysfs_emit(buf, "%u\n", atomic_read(&mrioc->reply_qfull_count));
+}
+
+static DEVICE_ATTR_RO(reply_qfull_count);
+
+/**
* logging_level_show - Show controller debug level
* @dev: class device
* @attr: Device attributes
@@ -2023,7 +3244,8 @@ adp_state_show(struct device *dev, struct device_attribute *attr,
ioc_state = mpi3mr_get_iocstate(mrioc);
if (ioc_state == MRIOC_STATE_UNRECOVERABLE)
adp_state = MPI3MR_BSG_ADPSTATE_UNRECOVERABLE;
- else if ((mrioc->reset_in_progress) || (mrioc->stop_bsgs))
+ else if (mrioc->reset_in_progress || mrioc->stop_bsgs ||
+ mrioc->block_on_pci_err)
adp_state = MPI3MR_BSG_ADPSTATE_IN_RESET;
else if (ioc_state == MRIOC_STATE_FAULT)
adp_state = MPI3MR_BSG_ADPSTATE_FAULT;
@@ -2040,6 +3262,7 @@ static struct attribute *mpi3mr_host_attrs[] = {
&dev_attr_fw_queue_depth.attr,
&dev_attr_op_req_q_count.attr,
&dev_attr_reply_queue_count.attr,
+ &dev_attr_reply_qfull_count.attr,
&dev_attr_logging_level.attr,
&dev_attr_adp_state.attr,
NULL,
@@ -2158,10 +3381,72 @@ persistent_id_show(struct device *dev, struct device_attribute *attr,
}
static DEVICE_ATTR_RO(persistent_id);
+/**
+ * sas_ncq_prio_supported_show - Indicate if device supports NCQ priority
+ * @dev: pointer to embedded device
+ * @attr: sas_ncq_prio_supported attribute descriptor
+ * @buf: the buffer returned
+ *
+ * A sysfs 'read-only' sdev attribute, only works with SATA devices
+ */
+static ssize_t
+sas_ncq_prio_supported_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct scsi_device *sdev = to_scsi_device(dev);
+
+ return sysfs_emit(buf, "%d\n", sas_ata_ncq_prio_supported(sdev));
+}
+static DEVICE_ATTR_RO(sas_ncq_prio_supported);
+
+/**
+ * sas_ncq_prio_enable_show - send prioritized io commands to device
+ * @dev: pointer to embedded device
+ * @attr: sas_ncq_prio_enable attribute descriptor
+ * @buf: the buffer returned
+ *
+ * A sysfs 'read/write' sdev attribute, only works with SATA devices
+ */
+static ssize_t
+sas_ncq_prio_enable_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct scsi_device *sdev = to_scsi_device(dev);
+ struct mpi3mr_sdev_priv_data *sdev_priv_data = sdev->hostdata;
+
+ if (!sdev_priv_data)
+ return 0;
+
+ return sysfs_emit(buf, "%d\n", sdev_priv_data->ncq_prio_enable);
+}
+
+static ssize_t
+sas_ncq_prio_enable_store(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ struct scsi_device *sdev = to_scsi_device(dev);
+ struct mpi3mr_sdev_priv_data *sdev_priv_data = sdev->hostdata;
+ bool ncq_prio_enable = 0;
+
+ if (kstrtobool(buf, &ncq_prio_enable))
+ return -EINVAL;
+
+ if (!sas_ata_ncq_prio_supported(sdev))
+ return -EINVAL;
+
+ sdev_priv_data->ncq_prio_enable = ncq_prio_enable;
+
+ return strlen(buf);
+}
+static DEVICE_ATTR_RW(sas_ncq_prio_enable);
+
static struct attribute *mpi3mr_dev_attrs[] = {
&dev_attr_sas_address.attr,
&dev_attr_device_handle.attr,
&dev_attr_persistent_id.attr,
+ &dev_attr_sas_ncq_prio_supported.attr,
+ &dev_attr_sas_ncq_prio_enable.attr,
NULL,
};
diff --git a/drivers/scsi/mpi3mr/mpi3mr_fw.c b/drivers/scsi/mpi3mr/mpi3mr_fw.c
index 528f19f782f2..1d7901a8f0e4 100644
--- a/drivers/scsi/mpi3mr/mpi3mr_fw.c
+++ b/drivers/scsi/mpi3mr/mpi3mr_fw.c
@@ -11,13 +11,13 @@
#include <linux/io-64-nonatomic-lo-hi.h>
static int
-mpi3mr_issue_reset(struct mpi3mr_ioc *mrioc, u16 reset_type, u32 reset_reason);
+mpi3mr_issue_reset(struct mpi3mr_ioc *mrioc, u16 reset_type, u16 reset_reason);
static int mpi3mr_setup_admin_qpair(struct mpi3mr_ioc *mrioc);
static void mpi3mr_process_factsdata(struct mpi3mr_ioc *mrioc,
struct mpi3_ioc_facts_data *facts_data);
static void mpi3mr_pel_wait_complete(struct mpi3mr_ioc *mrioc,
struct mpi3mr_drv_cmd *drv_cmd);
-
+static int mpi3mr_check_op_admin_proc(struct mpi3mr_ioc *mrioc);
static int poll_queues;
module_param(poll_queues, int, 0444);
MODULE_PARM_DESC(poll_queues, "Number of queues for io_uring poll mode. (Range 1 - 126)");
@@ -174,6 +174,9 @@ static void mpi3mr_print_event_data(struct mpi3mr_ioc *mrioc,
char *desc = NULL;
u16 event;
+ if (!(mrioc->logging_level & MPI3_DEBUG_EVENT))
+ return;
+
event = event_reply->event;
switch (event) {
@@ -274,6 +277,9 @@ static void mpi3mr_print_event_data(struct mpi3mr_ioc *mrioc,
case MPI3_EVENT_PREPARE_FOR_RESET:
desc = "Prepare For Reset";
break;
+ case MPI3_EVENT_DIAGNOSTIC_BUFFER_STATUS_CHANGE:
+ desc = "Diagnostic Buffer Status Change";
+ break;
}
if (!desc)
@@ -342,13 +348,15 @@ static void mpi3mr_process_admin_reply_desc(struct mpi3mr_ioc *mrioc,
{
u16 reply_desc_type, host_tag = 0;
u16 ioc_status = MPI3_IOCSTATUS_SUCCESS;
- u32 ioc_loginfo = 0;
+ u16 masked_ioc_status = MPI3_IOCSTATUS_SUCCESS;
+ u32 ioc_loginfo = 0, sense_count = 0;
struct mpi3_status_reply_descriptor *status_desc;
struct mpi3_address_reply_descriptor *addr_desc;
struct mpi3_success_reply_descriptor *success_desc;
struct mpi3_default_reply *def_reply = NULL;
struct mpi3mr_drv_cmd *cmdptr = NULL;
struct mpi3_scsi_io_reply *scsi_reply;
+ struct scsi_sense_hdr sshdr;
u8 *sense_buf = NULL;
*reply_dma = 0;
@@ -362,7 +370,8 @@ static void mpi3mr_process_admin_reply_desc(struct mpi3mr_ioc *mrioc,
if (ioc_status &
MPI3_REPLY_DESCRIPT_STATUS_IOCSTATUS_LOGINFOAVAIL)
ioc_loginfo = le32_to_cpu(status_desc->ioc_log_info);
- ioc_status &= MPI3_REPLY_DESCRIPT_STATUS_IOCSTATUS_STATUS_MASK;
+ masked_ioc_status = ioc_status & MPI3_IOCSTATUS_STATUS_MASK;
+ mpi3mr_reply_trigger(mrioc, masked_ioc_status, ioc_loginfo);
break;
case MPI3_REPLY_DESCRIPT_FLAGS_TYPE_ADDRESS_REPLY:
addr_desc = (struct mpi3_address_reply_descriptor *)reply_desc;
@@ -375,12 +384,20 @@ static void mpi3mr_process_admin_reply_desc(struct mpi3mr_ioc *mrioc,
if (ioc_status &
MPI3_REPLY_DESCRIPT_STATUS_IOCSTATUS_LOGINFOAVAIL)
ioc_loginfo = le32_to_cpu(def_reply->ioc_log_info);
- ioc_status &= MPI3_REPLY_DESCRIPT_STATUS_IOCSTATUS_STATUS_MASK;
+ masked_ioc_status = ioc_status & MPI3_IOCSTATUS_STATUS_MASK;
if (def_reply->function == MPI3_FUNCTION_SCSI_IO) {
scsi_reply = (struct mpi3_scsi_io_reply *)def_reply;
sense_buf = mpi3mr_get_sensebuf_virt_addr(mrioc,
le64_to_cpu(scsi_reply->sense_data_buffer_address));
+ sense_count = le32_to_cpu(scsi_reply->sense_count);
+ if (sense_buf) {
+ scsi_normalize_sense(sense_buf, sense_count,
+ &sshdr);
+ mpi3mr_scsisense_trigger(mrioc, sshdr.sense_key,
+ sshdr.asc, sshdr.ascq);
+ }
}
+ mpi3mr_reply_trigger(mrioc, masked_ioc_status, ioc_loginfo);
break;
case MPI3_REPLY_DESCRIPT_FLAGS_TYPE_SUCCESS:
success_desc = (struct mpi3_success_reply_descriptor *)reply_desc;
@@ -395,7 +412,10 @@ static void mpi3mr_process_admin_reply_desc(struct mpi3mr_ioc *mrioc,
if (cmdptr->state & MPI3MR_CMD_PENDING) {
cmdptr->state |= MPI3MR_CMD_COMPLETE;
cmdptr->ioc_loginfo = ioc_loginfo;
- cmdptr->ioc_status = ioc_status;
+ if (host_tag == MPI3MR_HOSTTAG_BSG_CMDS)
+ cmdptr->ioc_status = ioc_status;
+ else
+ cmdptr->ioc_status = masked_ioc_status;
cmdptr->state &= ~MPI3MR_CMD_PENDING;
if (def_reply) {
cmdptr->state |= MPI3MR_CMD_REPLY_VALID;
@@ -426,11 +446,15 @@ int mpi3mr_process_admin_reply_q(struct mpi3mr_ioc *mrioc)
u32 admin_reply_ci = mrioc->admin_reply_ci;
u32 num_admin_replies = 0;
u64 reply_dma = 0;
+ u16 threshold_comps = 0;
struct mpi3_default_reply_descriptor *reply_desc;
- if (!atomic_add_unless(&mrioc->admin_reply_q_in_use, 1, 1))
+ if (!atomic_add_unless(&mrioc->admin_reply_q_in_use, 1, 1)) {
+ atomic_inc(&mrioc->admin_pend_isr);
return 0;
+ }
+ atomic_set(&mrioc->admin_pend_isr, 0);
reply_desc = (struct mpi3_default_reply_descriptor *)mrioc->admin_reply_base +
admin_reply_ci;
@@ -441,7 +465,7 @@ int mpi3mr_process_admin_reply_q(struct mpi3mr_ioc *mrioc)
}
do {
- if (mrioc->unrecoverable)
+ if (mrioc->unrecoverable || mrioc->io_admin_reset_sync)
break;
mrioc->admin_req_ci = le16_to_cpu(reply_desc->request_queue_ci);
@@ -449,6 +473,7 @@ int mpi3mr_process_admin_reply_q(struct mpi3mr_ioc *mrioc)
if (reply_dma)
mpi3mr_repost_reply_buf(mrioc, reply_dma);
num_admin_replies++;
+ threshold_comps++;
if (++admin_reply_ci == mrioc->num_admin_replies) {
admin_reply_ci = 0;
exp_phase ^= 1;
@@ -459,6 +484,11 @@ int mpi3mr_process_admin_reply_q(struct mpi3mr_ioc *mrioc)
if ((le16_to_cpu(reply_desc->reply_flags) &
MPI3_REPLY_DESCRIPT_FLAGS_PHASE_MASK) != exp_phase)
break;
+ if (threshold_comps == MPI3MR_THRESHOLD_REPLY_COUNT) {
+ writel(admin_reply_ci,
+ &mrioc->sysif_regs->admin_reply_queue_ci);
+ threshold_comps = 0;
+ }
} while (1);
writel(admin_reply_ci, &mrioc->sysif_regs->admin_reply_queue_ci);
@@ -512,7 +542,7 @@ int mpi3mr_process_op_reply_q(struct mpi3mr_ioc *mrioc,
u32 num_op_reply = 0;
u64 reply_dma = 0;
struct mpi3_default_reply_descriptor *reply_desc;
- u16 req_q_idx = 0, reply_qidx;
+ u16 req_q_idx = 0, reply_qidx, threshold_comps = 0;
reply_qidx = op_reply_q->qid - 1;
@@ -530,7 +560,7 @@ int mpi3mr_process_op_reply_q(struct mpi3mr_ioc *mrioc,
}
do {
- if (mrioc->unrecoverable)
+ if (mrioc->unrecoverable || mrioc->io_admin_reset_sync)
break;
req_q_idx = le16_to_cpu(reply_desc->request_queue_id) - 1;
@@ -539,10 +569,11 @@ int mpi3mr_process_op_reply_q(struct mpi3mr_ioc *mrioc,
WRITE_ONCE(op_req_q->ci, le16_to_cpu(reply_desc->request_queue_ci));
mpi3mr_process_op_reply_desc(mrioc, reply_desc, &reply_dma,
reply_qidx);
- atomic_dec(&op_reply_q->pend_ios);
+
if (reply_dma)
mpi3mr_repost_reply_buf(mrioc, reply_dma);
num_op_reply++;
+ threshold_comps++;
if (++reply_ci == op_reply_q->num_replies) {
reply_ci = 0;
@@ -564,13 +595,19 @@ int mpi3mr_process_op_reply_q(struct mpi3mr_ioc *mrioc,
break;
}
#endif
+ if (threshold_comps == MPI3MR_THRESHOLD_REPLY_COUNT) {
+ writel(reply_ci,
+ &mrioc->sysif_regs->oper_queue_indexes[reply_qidx].consumer_index);
+ atomic_sub(threshold_comps, &op_reply_q->pend_ios);
+ threshold_comps = 0;
+ }
} while (1);
writel(reply_ci,
&mrioc->sysif_regs->oper_queue_indexes[reply_qidx].consumer_index);
op_reply_q->ci = reply_ci;
op_reply_q->ephase = exp_phase;
-
+ atomic_sub(threshold_comps, &op_reply_q->pend_ios);
atomic_dec(&op_reply_q->in_use);
return num_op_reply;
}
@@ -595,7 +632,7 @@ int mpi3mr_blk_mq_poll(struct Scsi_Host *shost, unsigned int queue_num)
mrioc = (struct mpi3mr_ioc *)shost->hostdata;
if ((mrioc->reset_in_progress || mrioc->prepare_for_reset ||
- mrioc->unrecoverable))
+ mrioc->unrecoverable || mrioc->pci_err_recovery))
return 0;
num_entries = mpi3mr_process_op_reply_q(mrioc,
@@ -697,7 +734,7 @@ static irqreturn_t mpi3mr_isr_poll(int irq, void *privdata)
mpi3mr_process_op_reply_q(mrioc,
intr_info->op_reply_q);
- usleep_range(MPI3MR_IRQ_POLL_SLEEP, 10 * MPI3MR_IRQ_POLL_SLEEP);
+ usleep_range(MPI3MR_IRQ_POLL_SLEEP, MPI3MR_IRQ_POLL_SLEEP + 1);
} while (atomic_read(&intr_info->op_reply_q->pend_ios) &&
(num_op_reply < mrioc->max_host_ios));
@@ -938,6 +975,14 @@ static const struct {
},
{ MPI3MR_RESET_FROM_SYSFS, "sysfs invocation" },
{ MPI3MR_RESET_FROM_SYSFS_TIMEOUT, "sysfs TM timeout" },
+ {
+ MPI3MR_RESET_FROM_DIAG_BUFFER_POST_TIMEOUT,
+ "diagnostic buffer post timeout"
+ },
+ {
+ MPI3MR_RESET_FROM_DIAG_BUFFER_RELEASE_TIMEOUT,
+ "diagnostic buffer release timeout"
+ },
{ MPI3MR_RESET_FROM_FIRMWARE, "firmware asynchronous reset" },
{ MPI3MR_RESET_FROM_CFG_REQ_TIMEOUT, "configuration request timeout"},
{ MPI3MR_RESET_FROM_SAS_TRANSPORT_TIMEOUT, "timeout of a SAS transport layer request" },
@@ -997,6 +1042,36 @@ static const char *mpi3mr_reset_type_name(u16 reset_type)
}
/**
+ * mpi3mr_is_fault_recoverable - Read fault code and decide
+ * whether the controller can be recoverable
+ * @mrioc: Adapter instance reference
+ * Return: true if fault is recoverable, false otherwise.
+ */
+static inline bool mpi3mr_is_fault_recoverable(struct mpi3mr_ioc *mrioc)
+{
+ u32 fault;
+
+ fault = (readl(&mrioc->sysif_regs->fault) &
+ MPI3_SYSIF_FAULT_CODE_MASK);
+
+ switch (fault) {
+ case MPI3_SYSIF_FAULT_CODE_COMPLETE_RESET_NEEDED:
+ case MPI3_SYSIF_FAULT_CODE_POWER_CYCLE_REQUIRED:
+ ioc_warn(mrioc,
+ "controller requires system power cycle, marking controller as unrecoverable\n");
+ return false;
+ case MPI3_SYSIF_FAULT_CODE_INSUFFICIENT_PCI_SLOT_POWER:
+ ioc_warn(mrioc,
+ "controller faulted due to insufficient power,\n"
+ " try by connecting it to a different slot\n");
+ return false;
+ default:
+ break;
+ }
+ return true;
+}
+
+/**
* mpi3mr_print_fault_info - Display fault information
* @mrioc: Adapter instance reference
*
@@ -1195,7 +1270,7 @@ static inline void mpi3mr_clear_reset_history(struct mpi3mr_ioc *mrioc)
static int mpi3mr_issue_and_process_mur(struct mpi3mr_ioc *mrioc,
u32 reset_reason)
{
- u32 ioc_config, timeout, ioc_status;
+ u32 ioc_config, timeout, ioc_status, scratch_pad0;
int retval = -1;
ioc_info(mrioc, "Issuing Message unit Reset(MUR)\n");
@@ -1204,7 +1279,11 @@ static int mpi3mr_issue_and_process_mur(struct mpi3mr_ioc *mrioc,
return retval;
}
mpi3mr_clear_reset_history(mrioc);
- writel(reset_reason, &mrioc->sysif_regs->scratchpad[0]);
+ scratch_pad0 = ((MPI3MR_RESET_REASON_OSTYPE_LINUX <<
+ MPI3MR_RESET_REASON_OSTYPE_SHIFT) |
+ (mrioc->facts.ioc_num <<
+ MPI3MR_RESET_REASON_IOCNUM_SHIFT) | reset_reason);
+ writel(scratch_pad0, &mrioc->sysif_regs->scratchpad[0]);
ioc_config = readl(&mrioc->sysif_regs->ioc_configuration);
ioc_config &= ~MPI3_SYSIF_IOC_CONFIG_ENABLE_IOC;
writel(ioc_config, &mrioc->sysif_regs->ioc_configuration);
@@ -1229,7 +1308,7 @@ static int mpi3mr_issue_and_process_mur(struct mpi3mr_ioc *mrioc,
(ioc_config & MPI3_SYSIF_IOC_CONFIG_ENABLE_IOC)))
retval = 0;
- ioc_info(mrioc, "Base IOC Sts/Config after %s MUR is (0x%x)/(0x%x)\n",
+ ioc_info(mrioc, "Base IOC Sts/Config after %s MUR is (0x%08x)/(0x%08x)\n",
(!retval) ? "successful" : "failed", ioc_status, ioc_config);
return retval;
}
@@ -1276,12 +1355,25 @@ mpi3mr_revalidate_factsdata(struct mpi3mr_ioc *mrioc)
mrioc->shost->max_sectors * 512, mrioc->facts.max_data_length);
if ((mrioc->sas_transport_enabled) && (mrioc->facts.ioc_capabilities &
- MPI3_IOCFACTS_CAPABILITY_MULTIPATH_ENABLED))
+ MPI3_IOCFACTS_CAPABILITY_MULTIPATH_SUPPORTED))
ioc_err(mrioc,
"critical error: multipath capability is enabled at the\n"
"\tcontroller while sas transport support is enabled at the\n"
"\tdriver, please reboot the system or reload the driver\n");
+ if (mrioc->seg_tb_support) {
+ if (!(mrioc->facts.ioc_capabilities &
+ MPI3_IOCFACTS_CAPABILITY_SEG_DIAG_TRACE_SUPPORTED)) {
+ ioc_err(mrioc,
+ "critical error: previously enabled segmented trace\n"
+ " buffer capability is disabled after reset. Please\n"
+ " update the firmware or reboot the system or\n"
+ " reload the driver to enable trace diag buffer\n");
+ mrioc->diag_buffers[0].disabled_after_reset = true;
+ } else
+ mrioc->diag_buffers[0].disabled_after_reset = false;
+ }
+
if (mrioc->facts.max_devhandle > mrioc->dev_handle_bitmap_bits) {
removepend_bitmap = bitmap_zalloc(mrioc->facts.max_devhandle,
GFP_KERNEL);
@@ -1319,6 +1411,10 @@ static int mpi3mr_bring_ioc_ready(struct mpi3mr_ioc *mrioc)
int retval = 0;
enum mpi3mr_iocstate ioc_state;
u64 base_info;
+ u8 retry = 0;
+ u64 start_time, elapsed_time_sec;
+
+retry_bring_ioc_ready:
ioc_status = readl(&mrioc->sysif_regs->ioc_status);
ioc_config = readl(&mrioc->sysif_regs->ioc_configuration);
@@ -1326,6 +1422,11 @@ static int mpi3mr_bring_ioc_ready(struct mpi3mr_ioc *mrioc)
ioc_info(mrioc, "ioc_status(0x%08x), ioc_config(0x%08x), ioc_info(0x%016llx) at the bringup\n",
ioc_status, ioc_config, base_info);
+ if (!mpi3mr_is_fault_recoverable(mrioc)) {
+ mrioc->unrecoverable = 1;
+ goto out_device_not_present;
+ }
+
/*The timeout value is in 2sec unit, changing it to seconds*/
mrioc->ready_timeout =
((base_info & MPI3_SYSIF_IOC_INFO_LOW_TIMEOUT_MASK) >>
@@ -1337,26 +1438,23 @@ static int mpi3mr_bring_ioc_ready(struct mpi3mr_ioc *mrioc)
ioc_info(mrioc, "controller is in %s state during detection\n",
mpi3mr_iocstate_name(ioc_state));
- if (ioc_state == MRIOC_STATE_BECOMING_READY ||
- ioc_state == MRIOC_STATE_RESET_REQUESTED) {
- timeout = mrioc->ready_timeout * 10;
- do {
- msleep(100);
- } while (--timeout);
+ timeout = mrioc->ready_timeout * 10;
+
+ do {
+ ioc_state = mpi3mr_get_iocstate(mrioc);
+
+ if (ioc_state != MRIOC_STATE_BECOMING_READY &&
+ ioc_state != MRIOC_STATE_RESET_REQUESTED)
+ break;
if (!pci_device_is_present(mrioc->pdev)) {
mrioc->unrecoverable = 1;
- ioc_err(mrioc,
- "controller is not present while waiting to reset\n");
- retval = -1;
+ ioc_err(mrioc, "controller is not present while waiting to reset\n");
goto out_device_not_present;
}
- ioc_state = mpi3mr_get_iocstate(mrioc);
- ioc_info(mrioc,
- "controller is in %s state after waiting to reset\n",
- mpi3mr_iocstate_name(ioc_state));
- }
+ msleep(100);
+ } while (--timeout);
if (ioc_state == MRIOC_STATE_READY) {
ioc_info(mrioc, "issuing message unit reset (MUR) to bring to reset state\n");
@@ -1417,6 +1515,9 @@ static int mpi3mr_bring_ioc_ready(struct mpi3mr_ioc *mrioc)
ioc_config |= MPI3_SYSIF_IOC_CONFIG_ENABLE_IOC;
writel(ioc_config, &mrioc->sysif_regs->ioc_configuration);
+ if (retry == 0)
+ start_time = jiffies;
+
timeout = mrioc->ready_timeout * 10;
do {
ioc_state = mpi3mr_get_iocstate(mrioc);
@@ -1426,6 +1527,12 @@ static int mpi3mr_bring_ioc_ready(struct mpi3mr_ioc *mrioc)
mpi3mr_iocstate_name(ioc_state));
return 0;
}
+ ioc_status = readl(&mrioc->sysif_regs->ioc_status);
+ if ((ioc_status & MPI3_SYSIF_IOC_STATUS_RESET_HISTORY) ||
+ (ioc_status & MPI3_SYSIF_IOC_STATUS_FAULT)) {
+ mpi3mr_print_fault_info(mrioc);
+ goto out_failed;
+ }
if (!pci_device_is_present(mrioc->pdev)) {
mrioc->unrecoverable = 1;
ioc_err(mrioc,
@@ -1434,9 +1541,19 @@ static int mpi3mr_bring_ioc_ready(struct mpi3mr_ioc *mrioc)
goto out_device_not_present;
}
msleep(100);
- } while (--timeout);
+ elapsed_time_sec = jiffies_to_msecs(jiffies - start_time)/1000;
+ } while (elapsed_time_sec < mrioc->ready_timeout);
out_failed:
+ elapsed_time_sec = jiffies_to_msecs(jiffies - start_time)/1000;
+ if ((retry < 2) && (elapsed_time_sec < (mrioc->ready_timeout - 60))) {
+ retry++;
+
+ ioc_warn(mrioc, "retrying to bring IOC ready, retry_count:%d\n"
+ " elapsed time =%llu\n", retry, elapsed_time_sec);
+
+ goto retry_bring_ioc_ready;
+ }
ioc_state = mpi3mr_get_iocstate(mrioc);
ioc_err(mrioc,
"failed to bring to ready state, current state: %s\n",
@@ -1520,11 +1637,11 @@ static inline void mpi3mr_set_diagsave(struct mpi3mr_ioc *mrioc)
* Return: 0 on success, non-zero on failure.
*/
static int mpi3mr_issue_reset(struct mpi3mr_ioc *mrioc, u16 reset_type,
- u32 reset_reason)
+ u16 reset_reason)
{
int retval = -1;
u8 unlock_retry_count = 0;
- u32 host_diagnostic, ioc_status, ioc_config;
+ u32 host_diagnostic, ioc_status, ioc_config, scratch_pad0;
u32 timeout = MPI3MR_RESET_ACK_TIMEOUT * 10;
if ((reset_type != MPI3_SYSIF_HOST_DIAG_RESET_ACTION_SOFT_RESET) &&
@@ -1576,6 +1693,9 @@ static int mpi3mr_issue_reset(struct mpi3mr_ioc *mrioc, u16 reset_type,
unlock_retry_count, host_diagnostic);
} while (!(host_diagnostic & MPI3_SYSIF_HOST_DIAG_DIAG_WRITE_ENABLE));
+ scratch_pad0 = ((MPI3MR_RESET_REASON_OSTYPE_LINUX <<
+ MPI3MR_RESET_REASON_OSTYPE_SHIFT) | (mrioc->facts.ioc_num <<
+ MPI3MR_RESET_REASON_IOCNUM_SHIFT) | reset_reason);
writel(reset_reason, &mrioc->sysif_regs->scratchpad[0]);
writel(host_diagnostic | reset_type,
&mrioc->sysif_regs->host_diagnostic);
@@ -1616,7 +1736,7 @@ static int mpi3mr_issue_reset(struct mpi3mr_ioc *mrioc, u16 reset_type,
ioc_config = readl(&mrioc->sysif_regs->ioc_configuration);
ioc_status = readl(&mrioc->sysif_regs->ioc_status);
ioc_info(mrioc,
- "ioc_status/ioc_onfig after %s reset is (0x%x)/(0x%x)\n",
+ "ioc_status/ioc_config after %s reset is (0x%08x)/(0x%08x)\n",
(!retval)?"successful":"failed", ioc_status,
ioc_config);
if (retval)
@@ -1665,6 +1785,12 @@ int mpi3mr_admin_request_post(struct mpi3mr_ioc *mrioc, void *admin_req,
retval = -EAGAIN;
goto out;
}
+ if (mrioc->pci_err_recovery) {
+ ioc_err(mrioc, "admin request queue submission failed due to pci error recovery in progress\n");
+ retval = -EAGAIN;
+ goto out;
+ }
+
areq_entry = (u8 *)mrioc->admin_req_base +
(areq_pi * MPI3MR_ADMIN_REQ_FRAME_SZ);
memset(areq_entry, 0, MPI3MR_ADMIN_REQ_FRAME_SZ);
@@ -1997,15 +2123,22 @@ static int mpi3mr_create_op_reply_q(struct mpi3mr_ioc *mrioc, u16 qidx)
}
reply_qid = qidx + 1;
- op_reply_q->num_replies = MPI3MR_OP_REP_Q_QD;
- if ((mrioc->pdev->device == MPI3_MFGPAGE_DEVID_SAS4116) &&
- !mrioc->pdev->revision)
- op_reply_q->num_replies = MPI3MR_OP_REP_Q_QD4K;
+
+ if (mrioc->pdev->device == MPI3_MFGPAGE_DEVID_SAS4116) {
+ if (mrioc->pdev->revision)
+ op_reply_q->num_replies = MPI3MR_OP_REP_Q_QD;
+ else
+ op_reply_q->num_replies = MPI3MR_OP_REP_Q_QD4K;
+ } else
+ op_reply_q->num_replies = MPI3MR_OP_REP_Q_QD2K;
+
op_reply_q->ci = 0;
op_reply_q->ephase = 1;
atomic_set(&op_reply_q->pend_ios, 0);
atomic_set(&op_reply_q->in_use, 0);
op_reply_q->enable_irq_poll = false;
+ op_reply_q->qfull_watermark =
+ op_reply_q->num_replies - (MPI3MR_THRESHOLD_REPLY_COUNT * 2);
if (!op_reply_q->q_segments) {
retval = mpi3mr_alloc_op_reply_q_segments(mrioc, qidx);
@@ -2309,8 +2442,10 @@ int mpi3mr_op_request_post(struct mpi3mr_ioc *mrioc,
void *segment_base_addr;
u16 req_sz = mrioc->facts.op_req_sz;
struct segments *segments = op_req_q->q_segments;
+ struct op_reply_qinfo *op_reply_q = NULL;
reply_qidx = op_req_q->reply_qid - 1;
+ op_reply_q = mrioc->op_reply_qinfo + reply_qidx;
if (mrioc->unrecoverable)
return -EFAULT;
@@ -2335,6 +2470,20 @@ int mpi3mr_op_request_post(struct mpi3mr_ioc *mrioc,
retval = -EAGAIN;
goto out;
}
+ if (mrioc->pci_err_recovery) {
+ ioc_err(mrioc, "operational request queue submission failed due to pci error recovery in progress\n");
+ retval = -EAGAIN;
+ goto out;
+ }
+
+ /* Reply queue is nearing to get full, push back IOs to SML */
+ if ((mrioc->prevent_reply_qfull == true) &&
+ (atomic_read(&op_reply_q->pend_ios) >
+ (op_reply_q->qfull_watermark))) {
+ atomic_inc(&mrioc->reply_qfull_count);
+ retval = -EAGAIN;
+ goto out;
+ }
segment_base_addr = segments[pi / op_req_q->segment_qd].segment;
req_entry = (u8 *)segment_base_addr +
@@ -2380,6 +2529,7 @@ out:
void mpi3mr_check_rh_fault_ioc(struct mpi3mr_ioc *mrioc, u32 reason_code)
{
u32 ioc_status, host_diagnostic, timeout;
+ union mpi3mr_trigger_data trigger_data;
if (mrioc->unrecoverable) {
ioc_err(mrioc, "controller is unrecoverable\n");
@@ -2391,16 +2541,30 @@ void mpi3mr_check_rh_fault_ioc(struct mpi3mr_ioc *mrioc, u32 reason_code)
ioc_err(mrioc, "controller is not present\n");
return;
}
-
+ memset(&trigger_data, 0, sizeof(trigger_data));
ioc_status = readl(&mrioc->sysif_regs->ioc_status);
- if ((ioc_status & MPI3_SYSIF_IOC_STATUS_RESET_HISTORY) ||
- (ioc_status & MPI3_SYSIF_IOC_STATUS_FAULT)) {
+
+ if (ioc_status & MPI3_SYSIF_IOC_STATUS_RESET_HISTORY) {
+ mpi3mr_set_trigger_data_in_all_hdb(mrioc,
+ MPI3MR_HDB_TRIGGER_TYPE_FW_RELEASED, NULL, 0);
+ return;
+ } else if (ioc_status & MPI3_SYSIF_IOC_STATUS_FAULT) {
+ trigger_data.fault = (readl(&mrioc->sysif_regs->fault) &
+ MPI3_SYSIF_FAULT_CODE_MASK);
+
+ mpi3mr_set_trigger_data_in_all_hdb(mrioc,
+ MPI3MR_HDB_TRIGGER_TYPE_FAULT, &trigger_data, 0);
mpi3mr_print_fault_info(mrioc);
return;
}
+
mpi3mr_set_diagsave(mrioc);
mpi3mr_issue_reset(mrioc, MPI3_SYSIF_HOST_DIAG_RESET_ACTION_DIAG_FAULT,
reason_code);
+ trigger_data.fault = (readl(&mrioc->sysif_regs->fault) &
+ MPI3_SYSIF_FAULT_CODE_MASK);
+ mpi3mr_set_trigger_data_in_all_hdb(mrioc, MPI3MR_HDB_TRIGGER_TYPE_FAULT,
+ &trigger_data, 0);
timeout = MPI3_SYSIF_DIAG_SAVE_TIMEOUT * 10;
do {
host_diagnostic = readl(&mrioc->sysif_regs->host_diagnostic);
@@ -2580,10 +2744,11 @@ static void mpi3mr_watchdog_work(struct work_struct *work)
container_of(work, struct mpi3mr_ioc, watchdog_work.work);
unsigned long flags;
enum mpi3mr_iocstate ioc_state;
- u32 fault, host_diagnostic, ioc_status;
- u32 reset_reason = MPI3MR_RESET_FROM_FAULT_WATCH;
+ u32 host_diagnostic, ioc_status;
+ union mpi3mr_trigger_data trigger_data;
+ u16 reset_reason = MPI3MR_RESET_FROM_FAULT_WATCH;
- if (mrioc->reset_in_progress)
+ if (mrioc->reset_in_progress || mrioc->pci_err_recovery)
return;
if (!mrioc->unrecoverable && !pci_device_is_present(mrioc->pdev)) {
@@ -2598,7 +2763,16 @@ static void mpi3mr_watchdog_work(struct work_struct *work)
return;
}
- if (mrioc->ts_update_counter++ >= MPI3MR_TSUPDATE_INTERVAL) {
+ if (atomic_read(&mrioc->admin_pend_isr)) {
+ ioc_err(mrioc, "Unprocessed admin ISR instance found\n"
+ "flush admin replies\n");
+ mpi3mr_process_admin_reply_q(mrioc);
+ }
+
+ if (!(mrioc->facts.ioc_capabilities &
+ MPI3_IOCFACTS_CAPABILITY_NON_SUPERVISOR_IOC) &&
+ (mrioc->ts_update_counter++ >= mrioc->ts_update_interval)) {
+
mrioc->ts_update_counter = 0;
mpi3mr_sync_timestamp(mrioc);
}
@@ -2611,8 +2785,11 @@ static void mpi3mr_watchdog_work(struct work_struct *work)
return;
}
+ memset(&trigger_data, 0, sizeof(trigger_data));
ioc_status = readl(&mrioc->sysif_regs->ioc_status);
if (ioc_status & MPI3_SYSIF_IOC_STATUS_RESET_HISTORY) {
+ mpi3mr_set_trigger_data_in_all_hdb(mrioc,
+ MPI3MR_HDB_TRIGGER_TYPE_FW_RELEASED, NULL, 0);
mpi3mr_soft_reset_handler(mrioc, MPI3MR_RESET_FROM_FIRMWARE, 0);
return;
}
@@ -2622,7 +2799,9 @@ static void mpi3mr_watchdog_work(struct work_struct *work)
if (ioc_state != MRIOC_STATE_FAULT)
goto schedule_work;
- fault = readl(&mrioc->sysif_regs->fault) & MPI3_SYSIF_FAULT_CODE_MASK;
+ trigger_data.fault = readl(&mrioc->sysif_regs->fault) & MPI3_SYSIF_FAULT_CODE_MASK;
+ mpi3mr_set_trigger_data_in_all_hdb(mrioc,
+ MPI3MR_HDB_TRIGGER_TYPE_FAULT, &trigger_data, 0);
host_diagnostic = readl(&mrioc->sysif_regs->host_diagnostic);
if (host_diagnostic & MPI3_SYSIF_HOST_DIAG_SAVE_IN_PROGRESS) {
if (!mrioc->diagsave_timeout) {
@@ -2636,7 +2815,12 @@ static void mpi3mr_watchdog_work(struct work_struct *work)
mpi3mr_print_fault_info(mrioc);
mrioc->diagsave_timeout = 0;
- switch (fault) {
+ if (!mpi3mr_is_fault_recoverable(mrioc)) {
+ mrioc->unrecoverable = 1;
+ goto schedule_work;
+ }
+
+ switch (trigger_data.fault) {
case MPI3_SYSIF_FAULT_CODE_COMPLETE_RESET_NEEDED:
case MPI3_SYSIF_FAULT_CODE_POWER_CYCLE_REQUIRED:
ioc_warn(mrioc,
@@ -2682,8 +2866,8 @@ void mpi3mr_start_watchdog(struct mpi3mr_ioc *mrioc)
snprintf(mrioc->watchdog_work_q_name,
sizeof(mrioc->watchdog_work_q_name), "watchdog_%s%d", mrioc->name,
mrioc->id);
- mrioc->watchdog_work_q =
- create_singlethread_workqueue(mrioc->watchdog_work_q_name);
+ mrioc->watchdog_work_q = alloc_ordered_workqueue(
+ "%s", WQ_MEM_RECLAIM, mrioc->watchdog_work_q_name);
if (!mrioc->watchdog_work_q) {
ioc_err(mrioc, "%s: failed (line=%d)\n", __func__, __LINE__);
return;
@@ -2745,6 +2929,7 @@ static int mpi3mr_setup_admin_qpair(struct mpi3mr_ioc *mrioc)
mrioc->admin_reply_ci = 0;
mrioc->admin_reply_ephase = 1;
atomic_set(&mrioc->admin_reply_q_in_use, 0);
+ atomic_set(&mrioc->admin_pend_isr, 0);
if (!mrioc->admin_req_base) {
mrioc->admin_req_base = dma_alloc_coherent(&mrioc->pdev->dev,
@@ -2953,6 +3138,9 @@ static void mpi3mr_process_factsdata(struct mpi3mr_ioc *mrioc,
mrioc->facts.dma_mask = (facts_flags &
MPI3_IOCFACTS_FLAGS_DMA_ADDRESS_WIDTH_MASK) >>
MPI3_IOCFACTS_FLAGS_DMA_ADDRESS_WIDTH_SHIFT;
+ mrioc->facts.dma_mask = (facts_flags &
+ MPI3_IOCFACTS_FLAGS_DMA_ADDRESS_WIDTH_MASK) >>
+ MPI3_IOCFACTS_FLAGS_DMA_ADDRESS_WIDTH_SHIFT;
mrioc->facts.protocol_flags = facts_data->protocol_flags;
mrioc->facts.mpi_version = le32_to_cpu(facts_data->mpi_version.word);
mrioc->facts.max_reqs = le16_to_cpu(facts_data->max_outstanding_requests);
@@ -2996,7 +3184,11 @@ static void mpi3mr_process_factsdata(struct mpi3mr_ioc *mrioc,
mrioc->facts.sge_mod_shift = facts_data->sge_modifier_shift;
mrioc->facts.shutdown_timeout =
le16_to_cpu(facts_data->shutdown_timeout);
-
+ mrioc->facts.diag_trace_sz =
+ le32_to_cpu(facts_data->diag_trace_size);
+ mrioc->facts.diag_fw_sz =
+ le32_to_cpu(facts_data->diag_fw_size);
+ mrioc->facts.diag_drvr_sz = le32_to_cpu(facts_data->diag_driver_size);
mrioc->facts.max_dev_per_tg =
facts_data->max_devices_per_throttle_group;
mrioc->facts.io_throttle_data_length =
@@ -3302,6 +3494,8 @@ static int mpi3mr_issue_iocinit(struct mpi3mr_ioc *mrioc)
iocinit_req.msg_flags |=
MPI3_IOCINIT_MSGFLAGS_SCSIIOSTATUSREPLY_SUPPORTED;
+ iocinit_req.msg_flags |=
+ MPI3_IOCINIT_MSGFLAGS_WRITESAMEDIVERT_SUPPORTED;
init_completion(&mrioc->init_cmds.done);
retval = mpi3mr_admin_request_post(mrioc, &iocinit_req,
@@ -3668,15 +3862,126 @@ static const struct {
u32 capability;
char *name;
} mpi3mr_capabilities[] = {
- { MPI3_IOCFACTS_CAPABILITY_RAID_CAPABLE, "RAID" },
- { MPI3_IOCFACTS_CAPABILITY_MULTIPATH_ENABLED, "MultiPath" },
+ { MPI3_IOCFACTS_CAPABILITY_RAID_SUPPORTED, "RAID" },
+ { MPI3_IOCFACTS_CAPABILITY_MULTIPATH_SUPPORTED, "MultiPath" },
};
/**
+ * mpi3mr_repost_diag_bufs - repost host diag buffers
+ * @mrioc: Adapter instance reference
+ *
+ * repost firmware and trace diag buffers based on global
+ * trigger flag from driver page 2
+ *
+ * Return: 0 on success, non-zero on failures.
+ */
+static int mpi3mr_repost_diag_bufs(struct mpi3mr_ioc *mrioc)
+{
+ u64 global_trigger;
+ union mpi3mr_trigger_data prev_trigger_data;
+ struct diag_buffer_desc *trace_hdb = NULL;
+ struct diag_buffer_desc *fw_hdb = NULL;
+ int retval = 0;
+ bool trace_repost_needed = false;
+ bool fw_repost_needed = false;
+ u8 prev_trigger_type;
+
+ retval = mpi3mr_refresh_trigger(mrioc, MPI3_CONFIG_ACTION_READ_CURRENT);
+ if (retval)
+ return -1;
+
+ trace_hdb = mpi3mr_diag_buffer_for_type(mrioc,
+ MPI3_DIAG_BUFFER_TYPE_TRACE);
+
+ if (trace_hdb &&
+ trace_hdb->status != MPI3MR_HDB_BUFSTATUS_NOT_ALLOCATED &&
+ trace_hdb->trigger_type != MPI3MR_HDB_TRIGGER_TYPE_GLOBAL &&
+ trace_hdb->trigger_type != MPI3MR_HDB_TRIGGER_TYPE_ELEMENT)
+ trace_repost_needed = true;
+
+ fw_hdb = mpi3mr_diag_buffer_for_type(mrioc, MPI3_DIAG_BUFFER_TYPE_FW);
+
+ if (fw_hdb && fw_hdb->status != MPI3MR_HDB_BUFSTATUS_NOT_ALLOCATED &&
+ fw_hdb->trigger_type != MPI3MR_HDB_TRIGGER_TYPE_GLOBAL &&
+ fw_hdb->trigger_type != MPI3MR_HDB_TRIGGER_TYPE_ELEMENT)
+ fw_repost_needed = true;
+
+ if (trace_repost_needed || fw_repost_needed) {
+ global_trigger = le64_to_cpu(mrioc->driver_pg2->global_trigger);
+ if (global_trigger &
+ MPI3_DRIVER2_GLOBALTRIGGER_POST_DIAG_TRACE_DISABLED)
+ trace_repost_needed = false;
+ if (global_trigger &
+ MPI3_DRIVER2_GLOBALTRIGGER_POST_DIAG_FW_DISABLED)
+ fw_repost_needed = false;
+ }
+
+ if (trace_repost_needed) {
+ prev_trigger_type = trace_hdb->trigger_type;
+ memcpy(&prev_trigger_data, &trace_hdb->trigger_data,
+ sizeof(trace_hdb->trigger_data));
+ retval = mpi3mr_issue_diag_buf_post(mrioc, trace_hdb);
+ if (!retval) {
+ dprint_init(mrioc, "trace diag buffer reposted");
+ mpi3mr_set_trigger_data_in_hdb(trace_hdb,
+ MPI3MR_HDB_TRIGGER_TYPE_UNKNOWN, NULL, 1);
+ } else {
+ trace_hdb->trigger_type = prev_trigger_type;
+ memcpy(&trace_hdb->trigger_data, &prev_trigger_data,
+ sizeof(prev_trigger_data));
+ ioc_err(mrioc, "trace diag buffer repost failed");
+ return -1;
+ }
+ }
+
+ if (fw_repost_needed) {
+ prev_trigger_type = fw_hdb->trigger_type;
+ memcpy(&prev_trigger_data, &fw_hdb->trigger_data,
+ sizeof(fw_hdb->trigger_data));
+ retval = mpi3mr_issue_diag_buf_post(mrioc, fw_hdb);
+ if (!retval) {
+ dprint_init(mrioc, "firmware diag buffer reposted");
+ mpi3mr_set_trigger_data_in_hdb(fw_hdb,
+ MPI3MR_HDB_TRIGGER_TYPE_UNKNOWN, NULL, 1);
+ } else {
+ fw_hdb->trigger_type = prev_trigger_type;
+ memcpy(&fw_hdb->trigger_data, &prev_trigger_data,
+ sizeof(prev_trigger_data));
+ ioc_err(mrioc, "firmware diag buffer repost failed");
+ return -1;
+ }
+ }
+ return retval;
+}
+
+/**
+ * mpi3mr_read_tsu_interval - Update time stamp interval
+ * @mrioc: Adapter instance reference
+ *
+ * Update time stamp interval if its defined in driver page 1,
+ * otherwise use default value.
+ *
+ * Return: Nothing
+ */
+static void
+mpi3mr_read_tsu_interval(struct mpi3mr_ioc *mrioc)
+{
+ struct mpi3_driver_page1 driver_pg1;
+ u16 pg_sz = sizeof(driver_pg1);
+ int retval = 0;
+
+ mrioc->ts_update_interval = MPI3MR_TSUPDATE_INTERVAL;
+
+ retval = mpi3mr_cfg_get_driver_pg1(mrioc, &driver_pg1, pg_sz);
+ if (!retval && driver_pg1.time_stamp_update)
+ mrioc->ts_update_interval = (driver_pg1.time_stamp_update * 60);
+}
+
+/**
* mpi3mr_print_ioc_info - Display controller information
* @mrioc: Adapter instance reference
*
- * Display controller personalit, capability, supported
+ * Display controller personality, capability, supported
* protocols etc.
*
* Return: Nothing
@@ -3685,20 +3990,20 @@ static void
mpi3mr_print_ioc_info(struct mpi3mr_ioc *mrioc)
{
int i = 0, bytes_written = 0;
- char personality[16];
+ const char *personality;
char protocol[50] = {0};
char capabilities[100] = {0};
struct mpi3mr_compimg_ver *fwver = &mrioc->facts.fw_ver;
switch (mrioc->facts.personality) {
case MPI3_IOCFACTS_FLAGS_PERSONALITY_EHBA:
- strncpy(personality, "Enhanced HBA", sizeof(personality));
+ personality = "Enhanced HBA";
break;
case MPI3_IOCFACTS_FLAGS_PERSONALITY_RAID_DDR:
- strncpy(personality, "RAID", sizeof(personality));
+ personality = "RAID";
break;
default:
- strncpy(personality, "Unknown", sizeof(personality));
+ personality = "Unknown";
break;
}
@@ -3889,6 +4194,7 @@ static int mpi3mr_enable_events(struct mpi3mr_ioc *mrioc)
mpi3mr_unmask_events(mrioc, MPI3_EVENT_PREPARE_FOR_RESET);
mpi3mr_unmask_events(mrioc, MPI3_EVENT_CABLE_MGMT);
mpi3mr_unmask_events(mrioc, MPI3_EVENT_ENERGY_PACK_CHANGE);
+ mpi3mr_unmask_events(mrioc, MPI3_EVENT_DIAGNOSTIC_BUFFER_STATUS_CHANGE);
retval = mpi3mr_issue_event_notification(mrioc);
if (retval)
@@ -3951,13 +4257,20 @@ retry_init:
MPI3MR_HOST_IOS_KDUMP);
if (!(mrioc->facts.ioc_capabilities &
- MPI3_IOCFACTS_CAPABILITY_MULTIPATH_ENABLED)) {
+ MPI3_IOCFACTS_CAPABILITY_MULTIPATH_SUPPORTED)) {
mrioc->sas_transport_enabled = 1;
mrioc->scsi_device_channel = 1;
mrioc->shost->max_channel = 1;
mrioc->shost->transportt = mpi3mr_transport_template;
}
+ if (mrioc->facts.max_req_limit)
+ mrioc->prevent_reply_qfull = true;
+
+ if (mrioc->facts.ioc_capabilities &
+ MPI3_IOCFACTS_CAPABILITY_SEG_DIAG_TRACE_SUPPORTED)
+ mrioc->seg_tb_support = true;
+
mrioc->reply_sz = mrioc->facts.reply_sz;
retval = mpi3mr_check_reset_dma_mask(mrioc);
@@ -3967,22 +4280,21 @@ retry_init:
goto out_failed_noretry;
}
+ mpi3mr_read_tsu_interval(mrioc);
mpi3mr_print_ioc_info(mrioc);
- if (!mrioc->cfg_page) {
- dprint_init(mrioc, "allocating config page buffers\n");
- mrioc->cfg_page_sz = MPI3MR_DEFAULT_CFG_PAGE_SZ;
- mrioc->cfg_page = dma_alloc_coherent(&mrioc->pdev->dev,
- mrioc->cfg_page_sz, &mrioc->cfg_page_dma, GFP_KERNEL);
- if (!mrioc->cfg_page) {
- retval = -1;
- goto out_failed_noretry;
- }
- }
+ dprint_init(mrioc, "allocating host diag buffers\n");
+ mpi3mr_alloc_diag_bufs(mrioc);
dprint_init(mrioc, "allocating ioctl dma buffers\n");
mpi3mr_alloc_ioctl_dma_memory(mrioc);
+ dprint_init(mrioc, "posting host diag buffers\n");
+ retval = mpi3mr_post_diag_bufs(mrioc);
+
+ if (retval)
+ ioc_warn(mrioc, "failed to post host diag buffers\n");
+
if (!mrioc->init_cmds.reply) {
retval = mpi3mr_alloc_reply_sense_bufs(mrioc);
if (retval) {
@@ -4058,6 +4370,12 @@ retry_init:
goto out_failed;
}
+ retval = mpi3mr_refresh_trigger(mrioc, MPI3_CONFIG_ACTION_READ_CURRENT);
+ if (retval) {
+ ioc_err(mrioc, "failed to refresh triggers\n");
+ goto out_failed;
+ }
+
ioc_info(mrioc, "controller initialization completed successfully\n");
return retval;
out_failed:
@@ -4109,7 +4427,8 @@ retry_init:
goto out_failed_noretry;
}
- if (is_resume) {
+ mrioc->io_admin_reset_sync = 0;
+ if (is_resume || mrioc->block_on_pci_err) {
dprint_reset(mrioc, "setting up single ISR\n");
retval = mpi3mr_setup_isr(mrioc, 1);
if (retval) {
@@ -4133,8 +4452,20 @@ retry_init:
goto out_failed_noretry;
}
+ mpi3mr_read_tsu_interval(mrioc);
mpi3mr_print_ioc_info(mrioc);
+ if (is_resume) {
+ dprint_reset(mrioc, "posting host diag buffers\n");
+ retval = mpi3mr_post_diag_bufs(mrioc);
+ if (retval)
+ ioc_warn(mrioc, "failed to post host diag buffers\n");
+ } else {
+ retval = mpi3mr_repost_diag_bufs(mrioc);
+ if (retval)
+ ioc_warn(mrioc, "failed to re post host diag buffers\n");
+ }
+
dprint_reset(mrioc, "sending ioc_init\n");
retval = mpi3mr_issue_iocinit(mrioc);
if (retval) {
@@ -4149,7 +4480,7 @@ retry_init:
goto out_failed;
}
- if (is_resume) {
+ if (is_resume || mrioc->block_on_pci_err) {
dprint_reset(mrioc, "setting up multiple ISR\n");
retval = mpi3mr_setup_isr(mrioc, 0);
if (retval) {
@@ -4327,6 +4658,7 @@ void mpi3mr_memset_buffers(struct mpi3mr_ioc *mrioc)
if (mrioc->admin_reply_base)
memset(mrioc->admin_reply_base, 0, mrioc->admin_reply_q_sz);
atomic_set(&mrioc->admin_reply_q_in_use, 0);
+ atomic_set(&mrioc->admin_pend_isr, 0);
if (mrioc->init_cmds.reply) {
memset(mrioc->init_cmds.reply, 0, sizeof(*mrioc->init_cmds.reply));
@@ -4398,8 +4730,9 @@ void mpi3mr_memset_buffers(struct mpi3mr_ioc *mrioc)
*/
void mpi3mr_free_mem(struct mpi3mr_ioc *mrioc)
{
- u16 i;
+ u16 i, j;
struct mpi3mr_intr_info *intr_info;
+ struct diag_buffer_desc *diag_buffer;
mpi3mr_free_enclosure_list(mrioc);
mpi3mr_free_ioctl_dma_memory(mrioc);
@@ -4523,17 +4856,46 @@ void mpi3mr_free_mem(struct mpi3mr_ioc *mrioc)
mrioc->admin_req_base, mrioc->admin_req_dma);
mrioc->admin_req_base = NULL;
}
- if (mrioc->cfg_page) {
- dma_free_coherent(&mrioc->pdev->dev, mrioc->cfg_page_sz,
- mrioc->cfg_page, mrioc->cfg_page_dma);
- mrioc->cfg_page = NULL;
- }
+
if (mrioc->pel_seqnum_virt) {
dma_free_coherent(&mrioc->pdev->dev, mrioc->pel_seqnum_sz,
mrioc->pel_seqnum_virt, mrioc->pel_seqnum_dma);
mrioc->pel_seqnum_virt = NULL;
}
+ for (i = 0; i < MPI3MR_MAX_NUM_HDB; i++) {
+ diag_buffer = &mrioc->diag_buffers[i];
+ if ((i == 0) && mrioc->seg_tb_support) {
+ if (mrioc->trace_buf_pool) {
+ for (j = 0; j < mrioc->num_tb_segs; j++) {
+ if (mrioc->trace_buf[j].segment) {
+ dma_pool_free(mrioc->trace_buf_pool,
+ mrioc->trace_buf[j].segment,
+ mrioc->trace_buf[j].segment_dma);
+ mrioc->trace_buf[j].segment = NULL;
+ }
+
+ mrioc->trace_buf[j].segment = NULL;
+ }
+ dma_pool_destroy(mrioc->trace_buf_pool);
+ mrioc->trace_buf_pool = NULL;
+ }
+
+ kfree(mrioc->trace_buf);
+ mrioc->trace_buf = NULL;
+ diag_buffer->size = sizeof(u64) * mrioc->num_tb_segs;
+ }
+ if (diag_buffer->addr) {
+ dma_free_coherent(&mrioc->pdev->dev,
+ diag_buffer->size, diag_buffer->addr,
+ diag_buffer->dma_addr);
+ diag_buffer->addr = NULL;
+ diag_buffer->size = 0;
+ diag_buffer->type = 0;
+ diag_buffer->status = 0;
+ }
+ }
+
kfree(mrioc->throttle_groups);
mrioc->throttle_groups = NULL;
@@ -4600,7 +4962,7 @@ static void mpi3mr_issue_ioc_shutdown(struct mpi3mr_ioc *mrioc)
}
ioc_info(mrioc,
- "Base IOC Sts/Config after %s shutdown is (0x%x)/(0x%x)\n",
+ "Base IOC Sts/Config after %s shutdown is (0x%08x)/(0x%08x)\n",
(!retval) ? "successful" : "failed", ioc_status,
ioc_config);
}
@@ -4623,7 +4985,8 @@ void mpi3mr_cleanup_ioc(struct mpi3mr_ioc *mrioc)
ioc_state = mpi3mr_get_iocstate(mrioc);
- if ((!mrioc->unrecoverable) && (!mrioc->reset_in_progress) &&
+ if (!mrioc->unrecoverable && !mrioc->reset_in_progress &&
+ !mrioc->pci_err_recovery &&
(ioc_state == MRIOC_STATE_READY)) {
if (mpi3mr_issue_and_process_mur(mrioc,
MPI3MR_RESET_FROM_CTLR_CLEANUP))
@@ -4945,6 +5308,55 @@ cleanup_drv_cmd:
}
/**
+ * mpi3mr_check_op_admin_proc -
+ * @mrioc: Adapter instance reference
+ *
+ * Check if any of the operation reply queues
+ * or the admin reply queue are currently in use.
+ * If any queue is in use, this function waits for
+ * a maximum of 10 seconds for them to become available.
+ *
+ * Return: 0 on success, non-zero on failure.
+ */
+static int mpi3mr_check_op_admin_proc(struct mpi3mr_ioc *mrioc)
+{
+
+ u16 timeout = 10 * 10;
+ u16 elapsed_time = 0;
+ bool op_admin_in_use = false;
+
+ do {
+ op_admin_in_use = false;
+
+ /* Check admin_reply queue first to exit early */
+ if (atomic_read(&mrioc->admin_reply_q_in_use) == 1)
+ op_admin_in_use = true;
+ else {
+ /* Check op_reply queues */
+ int i;
+
+ for (i = 0; i < mrioc->num_queues; i++) {
+ if (atomic_read(&mrioc->op_reply_qinfo[i].in_use) == 1) {
+ op_admin_in_use = true;
+ break;
+ }
+ }
+ }
+
+ if (!op_admin_in_use)
+ break;
+
+ msleep(100);
+
+ } while (++elapsed_time < timeout);
+
+ if (op_admin_in_use)
+ return 1;
+
+ return 0;
+}
+
+/**
* mpi3mr_soft_reset_handler - Reset the controller
* @mrioc: Adapter instance reference
* @reset_reason: Reset reason code
@@ -4966,11 +5378,12 @@ cleanup_drv_cmd:
* Return: 0 on success, non-zero on failure.
*/
int mpi3mr_soft_reset_handler(struct mpi3mr_ioc *mrioc,
- u32 reset_reason, u8 snapdump)
+ u16 reset_reason, u8 snapdump)
{
int retval = 0, i;
unsigned long flags;
u32 host_diagnostic, timeout = MPI3_SYSIF_DIAG_SAVE_TIMEOUT * 10;
+ union mpi3mr_trigger_data trigger_data;
/* Block the reset handler until diag save in progress*/
dprint_reset(mrioc,
@@ -5003,10 +5416,16 @@ int mpi3mr_soft_reset_handler(struct mpi3mr_ioc *mrioc,
mrioc->reset_in_progress = 1;
mrioc->stop_bsgs = 1;
mrioc->prev_reset_result = -1;
+ memset(&trigger_data, 0, sizeof(trigger_data));
if ((!snapdump) && (reset_reason != MPI3MR_RESET_FROM_FAULT_WATCH) &&
(reset_reason != MPI3MR_RESET_FROM_FIRMWARE) &&
(reset_reason != MPI3MR_RESET_FROM_CIACTIV_FAULT)) {
+ mpi3mr_set_trigger_data_in_all_hdb(mrioc,
+ MPI3MR_HDB_TRIGGER_TYPE_SOFT_RESET, NULL, 0);
+ dprint_reset(mrioc,
+ "soft_reset_handler: releasing host diagnostic buffers\n");
+ mpi3mr_release_diag_bufs(mrioc, 0);
for (i = 0; i < MPI3_EVENT_NOTIFY_EVENTMASK_WORDS; i++)
mrioc->event_masks[i] = -1;
@@ -5017,12 +5436,15 @@ int mpi3mr_soft_reset_handler(struct mpi3mr_ioc *mrioc,
mpi3mr_wait_for_host_io(mrioc, MPI3MR_RESET_HOST_IOWAIT_TIMEOUT);
mpi3mr_ioc_disable_intr(mrioc);
+ mrioc->io_admin_reset_sync = 1;
if (snapdump) {
mpi3mr_set_diagsave(mrioc);
retval = mpi3mr_issue_reset(mrioc,
MPI3_SYSIF_HOST_DIAG_RESET_ACTION_DIAG_FAULT, reset_reason);
if (!retval) {
+ trigger_data.fault = (readl(&mrioc->sysif_regs->fault) &
+ MPI3_SYSIF_FAULT_CODE_MASK);
do {
host_diagnostic =
readl(&mrioc->sysif_regs->host_diagnostic);
@@ -5031,6 +5453,8 @@ int mpi3mr_soft_reset_handler(struct mpi3mr_ioc *mrioc,
break;
msleep(100);
} while (--timeout);
+ mpi3mr_set_trigger_data_in_all_hdb(mrioc,
+ MPI3MR_HDB_TRIGGER_TYPE_FAULT, &trigger_data, 0);
}
}
@@ -5040,6 +5464,16 @@ int mpi3mr_soft_reset_handler(struct mpi3mr_ioc *mrioc,
ioc_err(mrioc, "Failed to issue soft reset to the ioc\n");
goto out;
}
+
+ retval = mpi3mr_check_op_admin_proc(mrioc);
+ if (retval) {
+ ioc_err(mrioc, "Soft reset failed due to an Admin or I/O queue polling\n"
+ "thread still processing replies even after a 10 second\n"
+ "timeout. Marking the controller as unrecoverable!\n");
+
+ goto out;
+ }
+
if (mrioc->num_io_throttle_group !=
mrioc->facts.max_io_throttle_group) {
ioc_err(mrioc,
@@ -5066,6 +5500,15 @@ int mpi3mr_soft_reset_handler(struct mpi3mr_ioc *mrioc,
mrioc->prepare_for_reset_timeout_counter = 0;
}
mpi3mr_memset_buffers(mrioc);
+ mpi3mr_release_diag_bufs(mrioc, 1);
+ mrioc->fw_release_trigger_active = false;
+ mrioc->trace_release_trigger_active = false;
+ mrioc->snapdump_trigger_active = false;
+ mpi3mr_set_trigger_data_in_all_hdb(mrioc,
+ MPI3MR_HDB_TRIGGER_TYPE_SOFT_RESET, NULL, 0);
+
+ dprint_reset(mrioc,
+ "soft_reset_handler: reinitializing the controller\n");
retval = mpi3mr_reinit_ioc(mrioc, 0);
if (retval) {
pr_err(IOCNAME "reinit after soft reset failed: reason %d\n",
@@ -5102,6 +5545,7 @@ out:
mrioc->device_refresh_on = 0;
mrioc->unrecoverable = 1;
mrioc->reset_in_progress = 0;
+ mrioc->stop_bsgs = 0;
retval = -1;
mpi3mr_flush_cmds_for_unrecovered_controller(mrioc);
}
@@ -5112,55 +5556,6 @@ out:
return retval;
}
-
-/**
- * mpi3mr_free_config_dma_memory - free memory for config page
- * @mrioc: Adapter instance reference
- * @mem_desc: memory descriptor structure
- *
- * Check whether the size of the buffer specified by the memory
- * descriptor is greater than the default page size if so then
- * free the memory pointed by the descriptor.
- *
- * Return: Nothing.
- */
-static void mpi3mr_free_config_dma_memory(struct mpi3mr_ioc *mrioc,
- struct dma_memory_desc *mem_desc)
-{
- if ((mem_desc->size > mrioc->cfg_page_sz) && mem_desc->addr) {
- dma_free_coherent(&mrioc->pdev->dev, mem_desc->size,
- mem_desc->addr, mem_desc->dma_addr);
- mem_desc->addr = NULL;
- }
-}
-
-/**
- * mpi3mr_alloc_config_dma_memory - Alloc memory for config page
- * @mrioc: Adapter instance reference
- * @mem_desc: Memory descriptor to hold dma memory info
- *
- * This function allocates new dmaable memory or provides the
- * default config page dmaable memory based on the memory size
- * described by the descriptor.
- *
- * Return: 0 on success, non-zero on failure.
- */
-static int mpi3mr_alloc_config_dma_memory(struct mpi3mr_ioc *mrioc,
- struct dma_memory_desc *mem_desc)
-{
- if (mem_desc->size > mrioc->cfg_page_sz) {
- mem_desc->addr = dma_alloc_coherent(&mrioc->pdev->dev,
- mem_desc->size, &mem_desc->dma_addr, GFP_KERNEL);
- if (!mem_desc->addr)
- return -ENOMEM;
- } else {
- mem_desc->addr = mrioc->cfg_page;
- mem_desc->dma_addr = mrioc->cfg_page_dma;
- memset(mem_desc->addr, 0, mrioc->cfg_page_sz);
- }
- return 0;
-}
-
/**
* mpi3mr_post_cfg_req - Issue config requests and wait
* @mrioc: Adapter instance reference
@@ -5316,8 +5711,12 @@ static int mpi3mr_process_cfg_req(struct mpi3mr_ioc *mrioc,
cfg_req->page_length = cfg_hdr->page_length;
cfg_req->page_version = cfg_hdr->page_version;
}
- if (mpi3mr_alloc_config_dma_memory(mrioc, &mem_desc))
- goto out;
+
+ mem_desc.addr = dma_alloc_coherent(&mrioc->pdev->dev,
+ mem_desc.size, &mem_desc.dma_addr, GFP_KERNEL);
+
+ if (!mem_desc.addr)
+ return retval;
mpi3mr_add_sg_single(&cfg_req->sgl, sgl_flags, mem_desc.size,
mem_desc.dma_addr);
@@ -5346,7 +5745,12 @@ static int mpi3mr_process_cfg_req(struct mpi3mr_ioc *mrioc,
}
out:
- mpi3mr_free_config_dma_memory(mrioc, &mem_desc);
+ if (mem_desc.addr) {
+ dma_free_coherent(&mrioc->pdev->dev, mem_desc.size,
+ mem_desc.addr, mem_desc.dma_addr);
+ mem_desc.addr = NULL;
+ }
+
return retval;
}
@@ -5944,3 +6348,64 @@ int mpi3mr_cfg_get_driver_pg1(struct mpi3mr_ioc *mrioc,
out_failed:
return -1;
}
+
+/**
+ * mpi3mr_cfg_get_driver_pg2 - Read current driver page2
+ * @mrioc: Adapter instance reference
+ * @driver_pg2: Pointer to return driver page 2
+ * @pg_sz: Size of the memory allocated to the page pointer
+ * @page_action: Page action
+ *
+ * This is handler for config page read for the driver page2.
+ * This routine checks ioc_status to decide whether the page
+ * read is success or not.
+ *
+ * Return: 0 on success, non-zero on failure.
+ */
+int mpi3mr_cfg_get_driver_pg2(struct mpi3mr_ioc *mrioc,
+ struct mpi3_driver_page2 *driver_pg2, u16 pg_sz, u8 page_action)
+{
+ struct mpi3_config_page_header cfg_hdr;
+ struct mpi3_config_request cfg_req;
+ u16 ioc_status = 0;
+
+ memset(driver_pg2, 0, pg_sz);
+ memset(&cfg_hdr, 0, sizeof(cfg_hdr));
+ memset(&cfg_req, 0, sizeof(cfg_req));
+
+ cfg_req.function = MPI3_FUNCTION_CONFIG;
+ cfg_req.action = MPI3_CONFIG_ACTION_PAGE_HEADER;
+ cfg_req.page_type = MPI3_CONFIG_PAGETYPE_DRIVER;
+ cfg_req.page_number = 2;
+ cfg_req.page_address = 0;
+ cfg_req.page_version = MPI3_DRIVER2_PAGEVERSION;
+
+ if (mpi3mr_process_cfg_req(mrioc, &cfg_req, NULL,
+ MPI3MR_INTADMCMD_TIMEOUT, &ioc_status, &cfg_hdr, sizeof(cfg_hdr))) {
+ ioc_err(mrioc, "driver page2 header read failed\n");
+ goto out_failed;
+ }
+ if (ioc_status != MPI3_IOCSTATUS_SUCCESS) {
+ ioc_err(mrioc, "driver page2 header read failed with\n"
+ "ioc_status(0x%04x)\n",
+ ioc_status);
+ goto out_failed;
+ }
+ cfg_req.action = page_action;
+
+ if (mpi3mr_process_cfg_req(mrioc, &cfg_req, &cfg_hdr,
+ MPI3MR_INTADMCMD_TIMEOUT, &ioc_status, driver_pg2, pg_sz)) {
+ ioc_err(mrioc, "driver page2 read failed\n");
+ goto out_failed;
+ }
+ if (ioc_status != MPI3_IOCSTATUS_SUCCESS) {
+ ioc_err(mrioc, "driver page2 read failed with\n"
+ "ioc_status(0x%04x)\n",
+ ioc_status);
+ goto out_failed;
+ }
+ return 0;
+out_failed:
+ return -1;
+}
+
diff --git a/drivers/scsi/mpi3mr/mpi3mr_os.c b/drivers/scsi/mpi3mr/mpi3mr_os.c
index 73c831a97d27..ce444efd859e 100644
--- a/drivers/scsi/mpi3mr/mpi3mr_os.c
+++ b/drivers/scsi/mpi3mr/mpi3mr_os.c
@@ -242,6 +242,40 @@ static void mpi3mr_fwevt_add_to_list(struct mpi3mr_ioc *mrioc,
}
/**
+ * mpi3mr_hdb_trigger_data_event - Add hdb trigger data event to
+ * the list
+ * @mrioc: Adapter instance reference
+ * @event_data: Event data
+ *
+ * Add the given hdb trigger data event to the firmware event
+ * list.
+ *
+ * Return: Nothing.
+ */
+void mpi3mr_hdb_trigger_data_event(struct mpi3mr_ioc *mrioc,
+ struct trigger_event_data *event_data)
+{
+ struct mpi3mr_fwevt *fwevt;
+ u16 sz = sizeof(*event_data);
+
+ fwevt = mpi3mr_alloc_fwevt(sz);
+ if (!fwevt) {
+ ioc_warn(mrioc, "failed to queue hdb trigger data event\n");
+ return;
+ }
+
+ fwevt->mrioc = mrioc;
+ fwevt->event_id = MPI3MR_DRIVER_EVENT_PROCESS_TRIGGER;
+ fwevt->send_ack = 0;
+ fwevt->process_evt = 1;
+ fwevt->evt_ctx = 0;
+ fwevt->event_data_size = sz;
+ memcpy(fwevt->event_data, event_data, sz);
+
+ mpi3mr_fwevt_add_to_list(mrioc, fwevt);
+}
+
+/**
* mpi3mr_fwevt_del_from_list - Delete firmware event from list
* @mrioc: Adapter instance reference
* @fwevt: Firmware event reference
@@ -898,6 +932,8 @@ void mpi3mr_remove_tgtdev_from_host(struct mpi3mr_ioc *mrioc,
}
} else
mpi3mr_remove_tgtdev_from_sas_transport(mrioc, tgtdev);
+ mpi3mr_global_trigger(mrioc,
+ MPI3_DRIVER2_GLOBALTRIGGER_DEVICE_REMOVAL_ENABLED);
ioc_info(mrioc, "%s :Removed handle(0x%04x), wwid(0x%016llx)\n",
__func__, tgtdev->dev_handle, (unsigned long long)tgtdev->wwid);
@@ -920,7 +956,7 @@ static int mpi3mr_report_tgtdev_to_host(struct mpi3mr_ioc *mrioc,
int retval = 0;
struct mpi3mr_tgt_dev *tgtdev;
- if (mrioc->reset_in_progress)
+ if (mrioc->reset_in_progress || mrioc->pci_err_recovery)
return -1;
tgtdev = mpi3mr_get_tgtdev_by_perst_id(mrioc, perst_id);
@@ -949,6 +985,10 @@ static int mpi3mr_report_tgtdev_to_host(struct mpi3mr_ioc *mrioc,
goto out;
}
}
+ dprint_event_bh(mrioc,
+ "exposed target device with handle(0x%04x), perst_id(%d)\n",
+ tgtdev->dev_handle, perst_id);
+ goto out;
} else
mpi3mr_report_tgtdev_to_sas_transport(mrioc, tgtdev);
out:
@@ -986,6 +1026,25 @@ static int mpi3mr_change_queue_depth(struct scsi_device *sdev,
return retval;
}
+static void mpi3mr_configure_nvme_dev(struct mpi3mr_tgt_dev *tgt_dev,
+ struct queue_limits *lim)
+{
+ u8 pgsz = tgt_dev->dev_spec.pcie_inf.pgsz ? : MPI3MR_DEFAULT_PGSZEXP;
+
+ lim->max_hw_sectors = tgt_dev->dev_spec.pcie_inf.mdts / 512;
+ lim->virt_boundary_mask = (1 << pgsz) - 1;
+}
+
+static void mpi3mr_configure_tgt_dev(struct mpi3mr_tgt_dev *tgt_dev,
+ struct queue_limits *lim)
+{
+ if (tgt_dev->dev_type == MPI3_DEVICE_DEVFORM_PCIE &&
+ (tgt_dev->dev_spec.pcie_inf.dev_info &
+ MPI3_DEVICE0_PCIE_DEVICE_INFO_TYPE_MASK) ==
+ MPI3_DEVICE0_PCIE_DEVICE_INFO_TYPE_NVME_DEVICE)
+ mpi3mr_configure_nvme_dev(tgt_dev, lim);
+}
+
/**
* mpi3mr_update_sdev - Update SCSI device information
* @sdev: SCSI device reference
@@ -1001,35 +1060,21 @@ static void
mpi3mr_update_sdev(struct scsi_device *sdev, void *data)
{
struct mpi3mr_tgt_dev *tgtdev;
+ struct queue_limits lim;
tgtdev = (struct mpi3mr_tgt_dev *)data;
if (!tgtdev)
return;
mpi3mr_change_queue_depth(sdev, tgtdev->q_depth);
- switch (tgtdev->dev_type) {
- case MPI3_DEVICE_DEVFORM_PCIE:
- /*The block layer hw sector size = 512*/
- if ((tgtdev->dev_spec.pcie_inf.dev_info &
- MPI3_DEVICE0_PCIE_DEVICE_INFO_TYPE_MASK) ==
- MPI3_DEVICE0_PCIE_DEVICE_INFO_TYPE_NVME_DEVICE) {
- blk_queue_max_hw_sectors(sdev->request_queue,
- tgtdev->dev_spec.pcie_inf.mdts / 512);
- if (tgtdev->dev_spec.pcie_inf.pgsz == 0)
- blk_queue_virt_boundary(sdev->request_queue,
- ((1 << MPI3MR_DEFAULT_PGSZEXP) - 1));
- else
- blk_queue_virt_boundary(sdev->request_queue,
- ((1 << tgtdev->dev_spec.pcie_inf.pgsz) - 1));
- }
- break;
- default:
- break;
- }
+
+ lim = queue_limits_start_update(sdev->request_queue);
+ mpi3mr_configure_tgt_dev(tgtdev, &lim);
+ WARN_ON_ONCE(queue_limits_commit_update(sdev->request_queue, &lim));
}
/**
- * mpi3mr_rfresh_tgtdevs - Refresh target device exposure
+ * mpi3mr_refresh_tgtdevs - Refresh target device exposure
* @mrioc: Adapter instance reference
*
* This is executed post controller reset to identify any
@@ -1038,8 +1083,7 @@ mpi3mr_update_sdev(struct scsi_device *sdev, void *data)
*
* Return: Nothing.
*/
-
-void mpi3mr_rfresh_tgtdevs(struct mpi3mr_ioc *mrioc)
+static void mpi3mr_refresh_tgtdevs(struct mpi3mr_ioc *mrioc)
{
struct mpi3mr_tgt_dev *tgtdev, *tgtdev_next;
struct mpi3mr_stgt_priv_data *tgt_priv;
@@ -1047,8 +1091,8 @@ void mpi3mr_rfresh_tgtdevs(struct mpi3mr_ioc *mrioc)
dprint_reset(mrioc, "refresh target devices: check for removals\n");
list_for_each_entry_safe(tgtdev, tgtdev_next, &mrioc->tgtdev_list,
list) {
- if ((tgtdev->dev_handle == MPI3MR_INVALID_DEV_HANDLE) &&
- tgtdev->is_hidden &&
+ if (((tgtdev->dev_handle == MPI3MR_INVALID_DEV_HANDLE) ||
+ tgtdev->is_hidden) &&
tgtdev->host_exposed && tgtdev->starget &&
tgtdev->starget->hostdata) {
tgt_priv = tgtdev->starget->hostdata;
@@ -1304,9 +1348,9 @@ static void mpi3mr_devstatuschg_evt_bh(struct mpi3mr_ioc *mrioc,
(struct mpi3_event_data_device_status_change *)fwevt->event_data;
dev_handle = le16_to_cpu(evtdata->dev_handle);
- ioc_info(mrioc,
- "%s :device status change: handle(0x%04x): reason code(0x%x)\n",
- __func__, dev_handle, evtdata->reason_code);
+ dprint_event_bh(mrioc,
+ "processing device status change event bottom half for handle(0x%04x), rc(0x%02x)\n",
+ dev_handle, evtdata->reason_code);
switch (evtdata->reason_code) {
case MPI3_EVENT_DEV_STAT_RC_HIDDEN:
delete = 1;
@@ -1325,8 +1369,13 @@ static void mpi3mr_devstatuschg_evt_bh(struct mpi3mr_ioc *mrioc,
}
tgtdev = mpi3mr_get_tgtdev_by_handle(mrioc, dev_handle);
- if (!tgtdev)
+ if (!tgtdev) {
+ dprint_event_bh(mrioc,
+ "processing device status change event bottom half,\n"
+ "cannot identify target device for handle(0x%04x), rc(0x%02x)\n",
+ dev_handle, evtdata->reason_code);
goto out;
+ }
if (uhide) {
tgtdev->is_hidden = 0;
if (!tgtdev->host_exposed)
@@ -1366,12 +1415,17 @@ static void mpi3mr_devinfochg_evt_bh(struct mpi3mr_ioc *mrioc,
perst_id = le16_to_cpu(dev_pg0->persistent_id);
dev_handle = le16_to_cpu(dev_pg0->dev_handle);
- ioc_info(mrioc,
- "%s :Device info change: handle(0x%04x): persist_id(0x%x)\n",
- __func__, dev_handle, perst_id);
+ dprint_event_bh(mrioc,
+ "processing device info change event bottom half for handle(0x%04x), perst_id(%d)\n",
+ dev_handle, perst_id);
tgtdev = mpi3mr_get_tgtdev_by_handle(mrioc, dev_handle);
- if (!tgtdev)
+ if (!tgtdev) {
+ dprint_event_bh(mrioc,
+ "cannot identify target device for device info\n"
+ "change event handle(0x%04x), perst_id(%d)\n",
+ dev_handle, perst_id);
goto out;
+ }
mpi3mr_update_tgtdev(mrioc, tgtdev, dev_pg0, false);
if (!tgtdev->is_hidden && !tgtdev->host_exposed)
mpi3mr_report_tgtdev_to_host(mrioc, perst_id);
@@ -1430,6 +1484,62 @@ out:
}
/**
+ * mpi3mr_process_trigger_data_event_bh - Process trigger event
+ * data
+ * @mrioc: Adapter instance reference
+ * @event_data: Event data
+ *
+ * This function releases diage buffers or issues diag fault
+ * based on trigger conditions
+ *
+ * Return: Nothing
+ */
+static void mpi3mr_process_trigger_data_event_bh(struct mpi3mr_ioc *mrioc,
+ struct trigger_event_data *event_data)
+{
+ struct diag_buffer_desc *trace_hdb = event_data->trace_hdb;
+ struct diag_buffer_desc *fw_hdb = event_data->fw_hdb;
+ unsigned long flags;
+ int retval = 0;
+ u8 trigger_type = event_data->trigger_type;
+ union mpi3mr_trigger_data *trigger_data =
+ &event_data->trigger_specific_data;
+
+ if (event_data->snapdump) {
+ if (trace_hdb)
+ mpi3mr_set_trigger_data_in_hdb(trace_hdb, trigger_type,
+ trigger_data, 1);
+ if (fw_hdb)
+ mpi3mr_set_trigger_data_in_hdb(fw_hdb, trigger_type,
+ trigger_data, 1);
+ mpi3mr_soft_reset_handler(mrioc,
+ MPI3MR_RESET_FROM_TRIGGER, 1);
+ return;
+ }
+
+ if (trace_hdb) {
+ retval = mpi3mr_issue_diag_buf_release(mrioc, trace_hdb);
+ if (!retval) {
+ mpi3mr_set_trigger_data_in_hdb(trace_hdb, trigger_type,
+ trigger_data, 1);
+ }
+ spin_lock_irqsave(&mrioc->trigger_lock, flags);
+ mrioc->trace_release_trigger_active = false;
+ spin_unlock_irqrestore(&mrioc->trigger_lock, flags);
+ }
+ if (fw_hdb) {
+ retval = mpi3mr_issue_diag_buf_release(mrioc, fw_hdb);
+ if (!retval) {
+ mpi3mr_set_trigger_data_in_hdb(fw_hdb, trigger_type,
+ trigger_data, 1);
+ }
+ spin_lock_irqsave(&mrioc->trigger_lock, flags);
+ mrioc->fw_release_trigger_active = false;
+ spin_unlock_irqrestore(&mrioc->trigger_lock, flags);
+ }
+}
+
+/**
* mpi3mr_encldev_add_chg_evt_debug - debug for enclosure event
* @mrioc: Adapter instance reference
* @encl_pg0: Enclosure page 0.
@@ -1911,12 +2021,16 @@ static void mpi3mr_fwevt_bh(struct mpi3mr_ioc *mrioc,
struct mpi3_device_page0 *dev_pg0 = NULL;
u16 perst_id, handle, dev_info;
struct mpi3_device0_sas_sata_format *sasinf = NULL;
+ unsigned int timeout;
mpi3mr_fwevt_del_from_list(mrioc, fwevt);
mrioc->current_event = fwevt;
- if (mrioc->stop_drv_processing)
+ if (mrioc->stop_drv_processing) {
+ dprint_event_bh(mrioc, "ignoring event(0x%02x) in the bottom half handler\n"
+ "due to stop_drv_processing\n", fwevt->event_id);
goto out;
+ }
if (mrioc->unrecoverable) {
dprint_event_bh(mrioc,
@@ -1928,6 +2042,9 @@ static void mpi3mr_fwevt_bh(struct mpi3mr_ioc *mrioc,
if (!fwevt->process_evt)
goto evt_ack;
+ dprint_event_bh(mrioc, "processing event(0x%02x) in the bottom half handler\n",
+ fwevt->event_id);
+
switch (fwevt->event_id) {
case MPI3_EVENT_DEVICE_ADDED:
{
@@ -2001,8 +2118,18 @@ static void mpi3mr_fwevt_bh(struct mpi3mr_ioc *mrioc,
}
case MPI3_EVENT_WAIT_FOR_DEVICES_TO_REFRESH:
{
- while (mrioc->device_refresh_on)
+ timeout = MPI3MR_RESET_TIMEOUT * 2;
+ while ((mrioc->device_refresh_on || mrioc->block_on_pci_err) &&
+ !mrioc->unrecoverable && !mrioc->pci_err_recovery) {
msleep(500);
+ if (!timeout--) {
+ mrioc->unrecoverable = 1;
+ break;
+ }
+ }
+
+ if (mrioc->unrecoverable || mrioc->pci_err_recovery)
+ break;
dprint_event_bh(mrioc,
"scan for non responding and newly added devices after soft reset started\n");
@@ -2010,11 +2137,17 @@ static void mpi3mr_fwevt_bh(struct mpi3mr_ioc *mrioc,
mpi3mr_refresh_sas_ports(mrioc);
mpi3mr_refresh_expanders(mrioc);
}
- mpi3mr_rfresh_tgtdevs(mrioc);
+ mpi3mr_refresh_tgtdevs(mrioc);
ioc_info(mrioc,
"scan for non responding and newly added devices after soft reset completed\n");
break;
}
+ case MPI3MR_DRIVER_EVENT_PROCESS_TRIGGER:
+ {
+ mpi3mr_process_trigger_data_event_bh(mrioc,
+ (struct trigger_event_data *)fwevt->event_data);
+ break;
+ }
default:
break;
}
@@ -2650,6 +2783,9 @@ static void mpi3mr_devstatuschg_evt_th(struct mpi3mr_ioc *mrioc,
goto out;
dev_handle = le16_to_cpu(evtdata->dev_handle);
+ dprint_event_th(mrioc,
+ "device status change event top half with rc(0x%02x) for handle(0x%04x)\n",
+ evtdata->reason_code, dev_handle);
switch (evtdata->reason_code) {
case MPI3_EVENT_DEV_STAT_RC_INT_DEVICE_RESET_STRT:
@@ -2673,8 +2809,12 @@ static void mpi3mr_devstatuschg_evt_th(struct mpi3mr_ioc *mrioc,
}
tgtdev = mpi3mr_get_tgtdev_by_handle(mrioc, dev_handle);
- if (!tgtdev)
+ if (!tgtdev) {
+ dprint_event_th(mrioc,
+ "processing device status change event could not identify device for handle(0x%04x)\n",
+ dev_handle);
goto out;
+ }
if (hide)
tgtdev->is_hidden = hide;
if (tgtdev->starget && tgtdev->starget->hostdata) {
@@ -2750,13 +2890,13 @@ static void mpi3mr_energypackchg_evt_th(struct mpi3mr_ioc *mrioc,
u16 shutdown_timeout = le16_to_cpu(evtdata->shutdown_timeout);
if (shutdown_timeout <= 0) {
- ioc_warn(mrioc,
+ dprint_event_th(mrioc,
"%s :Invalid Shutdown Timeout received = %d\n",
__func__, shutdown_timeout);
return;
}
- ioc_info(mrioc,
+ dprint_event_th(mrioc,
"%s :Previous Shutdown Timeout Value = %d New Shutdown Timeout Value = %d\n",
__func__, mrioc->facts.shutdown_timeout, shutdown_timeout);
mrioc->facts.shutdown_timeout = shutdown_timeout;
@@ -2832,9 +2972,9 @@ void mpi3mr_add_event_wait_for_device_refresh(struct mpi3mr_ioc *mrioc)
* @mrioc: Adapter instance reference
* @event_reply: event data
*
- * Identify whteher the event has to handled and acknowledged
- * and either process the event in the tophalf and/or schedule a
- * bottom half through mpi3mr_fwevt_worker.
+ * Identifies whether the event has to be handled and acknowledged,
+ * and either processes the event in the top-half and/or schedule a
+ * bottom-half through mpi3mr_fwevt_worker().
*
* Return: Nothing
*/
@@ -2853,6 +2993,7 @@ void mpi3mr_os_handle_events(struct mpi3mr_ioc *mrioc,
ack_req = 1;
evt_type = event_reply->event;
+ mpi3mr_event_trigger(mrioc, event_reply->event);
switch (evt_type) {
case MPI3_EVENT_DEVICE_ADDED:
@@ -2860,9 +3001,11 @@ void mpi3mr_os_handle_events(struct mpi3mr_ioc *mrioc,
struct mpi3_device_page0 *dev_pg0 =
(struct mpi3_device_page0 *)event_reply->event_data;
if (mpi3mr_create_tgtdev(mrioc, dev_pg0))
- ioc_err(mrioc,
- "%s :Failed to add device in the device add event\n",
- __func__);
+ dprint_event_th(mrioc,
+ "failed to process device added event for handle(0x%04x),\n"
+ "perst_id(%d) in the event top half handler\n",
+ le16_to_cpu(dev_pg0->dev_handle),
+ le16_to_cpu(dev_pg0->persistent_id));
else
process_evt_bh = 1;
break;
@@ -2891,6 +3034,11 @@ void mpi3mr_os_handle_events(struct mpi3mr_ioc *mrioc,
ack_req = 0;
break;
}
+ case MPI3_EVENT_DIAGNOSTIC_BUFFER_STATUS_CHANGE:
+ {
+ mpi3mr_hdbstatuschg_evt_th(mrioc, event_reply);
+ break;
+ }
case MPI3_EVENT_DEVICE_INFO_CHANGED:
case MPI3_EVENT_LOG_DATA:
case MPI3_EVENT_ENCL_DEVICE_STATUS_CHANGE:
@@ -2920,11 +3068,15 @@ void mpi3mr_os_handle_events(struct mpi3mr_ioc *mrioc,
break;
}
if (process_evt_bh || ack_req) {
+ dprint_event_th(mrioc,
+ "scheduling bottom half handler for event(0x%02x),ack_required=%d\n",
+ evt_type, ack_req);
sz = event_reply->event_data_length * 4;
fwevt = mpi3mr_alloc_fwevt(sz);
if (!fwevt) {
- ioc_info(mrioc, "%s :failure at %s:%d/%s()!\n",
- __func__, __FILE__, __LINE__, __func__);
+ dprint_event_th(mrioc,
+ "failed to schedule bottom half handler for\n"
+ "event(0x%02x), ack_required=%d\n", evt_type, ack_req);
return;
}
@@ -3154,6 +3306,7 @@ void mpi3mr_process_op_reply_desc(struct mpi3mr_ioc *mrioc,
MPI3_REPLY_DESCRIPT_STATUS_IOCSTATUS_LOGINFOAVAIL)
ioc_loginfo = le32_to_cpu(status_desc->ioc_log_info);
ioc_status &= MPI3_REPLY_DESCRIPT_STATUS_IOCSTATUS_STATUS_MASK;
+ mpi3mr_reply_trigger(mrioc, ioc_status, ioc_loginfo);
break;
case MPI3_REPLY_DESCRIPT_FLAGS_TYPE_ADDRESS_REPLY:
addr_desc = (struct mpi3_address_reply_descriptor *)reply_desc;
@@ -3182,6 +3335,12 @@ void mpi3mr_process_op_reply_desc(struct mpi3mr_ioc *mrioc,
ioc_status &= MPI3_REPLY_DESCRIPT_STATUS_IOCSTATUS_STATUS_MASK;
if (sense_state == MPI3_SCSI_STATE_SENSE_BUFF_Q_EMPTY)
panic("%s: Ran out of sense buffers\n", mrioc->name);
+ if (sense_buf) {
+ scsi_normalize_sense(sense_buf, sense_count, &sshdr);
+ mpi3mr_scsisense_trigger(mrioc, sshdr.sense_key,
+ sshdr.asc, sshdr.ascq);
+ }
+ mpi3mr_reply_trigger(mrioc, ioc_status, ioc_loginfo);
break;
case MPI3_REPLY_DESCRIPT_FLAGS_TYPE_SUCCESS:
success_desc = (struct mpi3_success_reply_descriptor *)reply_desc;
@@ -3449,6 +3608,17 @@ static int mpi3mr_prepare_sg_scmd(struct mpi3mr_ioc *mrioc,
scmd->sc_data_direction);
priv->meta_sg_valid = 1; /* To unmap meta sg DMA */
} else {
+ /*
+ * Some firmware versions byte-swap the REPORT ZONES command
+ * reply from ATA-ZAC devices by directly accessing in the host
+ * buffer. This does not respect the default command DMA
+ * direction and causes IOMMU page faults on some architectures
+ * with an IOMMU enforcing write mappings (e.g. AMD hosts).
+ * Avoid such issue by making the REPORT ZONES buffer mapping
+ * bi-directional.
+ */
+ if (scmd->cmnd[0] == ZBC_IN && scmd->cmnd[1] == ZI_REPORT_ZONES)
+ scmd->sc_data_direction = DMA_BIDIRECTIONAL;
sg_scmd = scsi_sglist(scmd);
sges_left = scsi_dma_map(scmd);
}
@@ -3681,6 +3851,13 @@ int mpi3mr_issue_tm(struct mpi3mr_ioc *mrioc, u8 tm_type,
mutex_unlock(&drv_cmd->mutex);
goto out;
}
+ if (mrioc->block_on_pci_err) {
+ retval = -1;
+ dprint_tm(mrioc, "sending task management failed due to\n"
+ "pci error recovery in progress\n");
+ mutex_unlock(&drv_cmd->mutex);
+ goto out;
+ }
drv_cmd->state = MPI3MR_CMD_PENDING;
drv_cmd->is_waiting = 1;
@@ -3695,6 +3872,18 @@ int mpi3mr_issue_tm(struct mpi3mr_ioc *mrioc, u8 tm_type,
tgtdev = mpi3mr_get_tgtdev_by_handle(mrioc, handle);
if (scmd) {
+ if (tm_type == MPI3_SCSITASKMGMT_TASKTYPE_ABORT_TASK) {
+ cmd_priv = scsi_cmd_priv(scmd);
+ if (!cmd_priv)
+ goto out_unlock;
+
+ struct op_req_qinfo *op_req_q;
+
+ op_req_q = &mrioc->req_qinfo[cmd_priv->req_q_idx];
+ tm_req.task_host_tag = cpu_to_le16(cmd_priv->host_tag);
+ tm_req.task_request_queue_id =
+ cpu_to_le16(op_req_q->qid);
+ }
sdev = scmd->device;
sdev_priv_data = sdev->hostdata;
scsi_tgt_priv_data = ((sdev_priv_data) ?
@@ -3807,6 +3996,8 @@ int mpi3mr_issue_tm(struct mpi3mr_ioc *mrioc, u8 tm_type,
default:
break;
}
+ mpi3mr_global_trigger(mrioc,
+ MPI3_DRIVER2_GLOBALTRIGGER_TASK_MANAGEMENT_ENABLED);
out_unlock:
drv_cmd->state = MPI3MR_CMD_NOTUSED;
@@ -3896,7 +4087,7 @@ static void mpi3mr_map_queues(struct Scsi_Host *shost)
*/
map->queue_offset = qoff;
if (i != HCTX_TYPE_POLL)
- blk_mq_pci_map_queues(map, mrioc->pdev, offset);
+ blk_mq_map_hw_queues(map, &mrioc->pdev->dev, offset);
else
blk_mq_map_queues(map);
@@ -4064,6 +4255,7 @@ static int mpi3mr_eh_bus_reset(struct scsi_cmnd *scmd)
struct mpi3mr_sdev_priv_data *sdev_priv_data;
u8 dev_type = MPI3_DEVICE_DEVFORM_VD;
int retval = FAILED;
+ unsigned int timeout = MPI3MR_RESET_TIMEOUT;
sdev_priv_data = scmd->device->hostdata;
if (sdev_priv_data && sdev_priv_data->tgt_priv_data) {
@@ -4074,12 +4266,24 @@ static int mpi3mr_eh_bus_reset(struct scsi_cmnd *scmd)
if (dev_type == MPI3_DEVICE_DEVFORM_VD) {
mpi3mr_wait_for_host_io(mrioc,
MPI3MR_RAID_ERRREC_RESET_TIMEOUT);
- if (!mpi3mr_get_fw_pending_ios(mrioc))
+ if (!mpi3mr_get_fw_pending_ios(mrioc)) {
+ while (mrioc->reset_in_progress ||
+ mrioc->prepare_for_reset ||
+ mrioc->block_on_pci_err) {
+ ssleep(1);
+ if (!timeout--) {
+ retval = FAILED;
+ goto out;
+ }
+ }
retval = SUCCESS;
+ goto out;
+ }
}
if (retval == FAILED)
mpi3mr_print_pending_host_io(mrioc);
+out:
sdev_printk(KERN_INFO, scmd->device,
"Bus reset is %s for scmd(%p)\n",
((retval == SUCCESS) ? "SUCCESS" : "FAILED"), scmd);
@@ -4229,6 +4433,92 @@ out:
}
/**
+ * mpi3mr_eh_abort - Callback function for abort error handling
+ * @scmd: SCSI command reference
+ *
+ * Issues Abort Task Management if the command is in LLD scope
+ * and verifies if it is aborted successfully, and return status
+ * accordingly.
+ *
+ * Return: SUCCESS if the abort was successful, otherwise FAILED
+ */
+static int mpi3mr_eh_abort(struct scsi_cmnd *scmd)
+{
+ struct mpi3mr_ioc *mrioc = shost_priv(scmd->device->host);
+ struct mpi3mr_stgt_priv_data *stgt_priv_data;
+ struct mpi3mr_sdev_priv_data *sdev_priv_data;
+ struct scmd_priv *cmd_priv;
+ u16 dev_handle, timeout = MPI3MR_ABORTTM_TIMEOUT;
+ u8 resp_code = 0;
+ int retval = FAILED, ret = 0;
+ struct request *rq = scsi_cmd_to_rq(scmd);
+ unsigned long scmd_age_ms = jiffies_to_msecs(jiffies - scmd->jiffies_at_alloc);
+ unsigned long scmd_age_sec = scmd_age_ms / HZ;
+
+ sdev_printk(KERN_INFO, scmd->device,
+ "%s: attempting abort task for scmd(%p)\n", mrioc->name, scmd);
+
+ sdev_printk(KERN_INFO, scmd->device,
+ "%s: scmd(0x%p) is outstanding for %lus %lums, timeout %us, retries %d, allowed %d\n",
+ mrioc->name, scmd, scmd_age_sec, scmd_age_ms % HZ, rq->timeout / HZ,
+ scmd->retries, scmd->allowed);
+
+ scsi_print_command(scmd);
+
+ sdev_priv_data = scmd->device->hostdata;
+ if (!sdev_priv_data || !sdev_priv_data->tgt_priv_data) {
+ sdev_printk(KERN_INFO, scmd->device,
+ "%s: Device not available, Skip issuing abort task\n",
+ mrioc->name);
+ retval = SUCCESS;
+ goto out;
+ }
+
+ stgt_priv_data = sdev_priv_data->tgt_priv_data;
+ dev_handle = stgt_priv_data->dev_handle;
+
+ cmd_priv = scsi_cmd_priv(scmd);
+ if (!cmd_priv->in_lld_scope ||
+ cmd_priv->host_tag == MPI3MR_HOSTTAG_INVALID) {
+ sdev_printk(KERN_INFO, scmd->device,
+ "%s: scmd (0x%p) not in LLD scope, Skip issuing Abort Task\n",
+ mrioc->name, scmd);
+ retval = SUCCESS;
+ goto out;
+ }
+
+ if (stgt_priv_data->dev_removed) {
+ sdev_printk(KERN_INFO, scmd->device,
+ "%s: Device (handle = 0x%04x) removed, Skip issuing Abort Task\n",
+ mrioc->name, dev_handle);
+ retval = FAILED;
+ goto out;
+ }
+
+ ret = mpi3mr_issue_tm(mrioc, MPI3_SCSITASKMGMT_TASKTYPE_ABORT_TASK,
+ dev_handle, sdev_priv_data->lun_id, MPI3MR_HOSTTAG_BLK_TMS,
+ timeout, &mrioc->host_tm_cmds, &resp_code, scmd);
+
+ if (ret)
+ goto out;
+
+ if (cmd_priv->in_lld_scope) {
+ sdev_printk(KERN_INFO, scmd->device,
+ "%s: Abort task failed. scmd (0x%p) was not terminated\n",
+ mrioc->name, scmd);
+ goto out;
+ }
+
+ retval = SUCCESS;
+out:
+ sdev_printk(KERN_INFO, scmd->device,
+ "%s: Abort Task %s for scmd (0x%p)\n", mrioc->name,
+ ((retval == SUCCESS) ? "SUCCEEDED" : "FAILED"), scmd);
+
+ return retval;
+}
+
+/**
* mpi3mr_scan_start - Scan start callback handler
* @shost: SCSI host reference
*
@@ -4306,14 +4596,14 @@ static int mpi3mr_scan_finished(struct Scsi_Host *shost,
}
/**
- * mpi3mr_slave_destroy - Slave destroy callback handler
+ * mpi3mr_sdev_destroy - Slave destroy callback handler
* @sdev: SCSI device reference
*
* Cleanup and free per device(lun) private data.
*
* Return: Nothing.
*/
-static void mpi3mr_slave_destroy(struct scsi_device *sdev)
+static void mpi3mr_sdev_destroy(struct scsi_device *sdev)
{
struct Scsi_Host *shost;
struct mpi3mr_ioc *mrioc;
@@ -4393,15 +4683,17 @@ static void mpi3mr_target_destroy(struct scsi_target *starget)
}
/**
- * mpi3mr_slave_configure - Slave configure callback handler
+ * mpi3mr_sdev_configure - Slave configure callback handler
* @sdev: SCSI device reference
+ * @lim: queue limits
*
* Configure queue depth, max hardware sectors and virt boundary
* as required
*
* Return: 0 always.
*/
-static int mpi3mr_slave_configure(struct scsi_device *sdev)
+static int mpi3mr_sdev_configure(struct scsi_device *sdev,
+ struct queue_limits *lim)
{
struct scsi_target *starget;
struct Scsi_Host *shost;
@@ -4432,40 +4724,20 @@ static int mpi3mr_slave_configure(struct scsi_device *sdev)
sdev->eh_timeout = MPI3MR_EH_SCMD_TIMEOUT;
blk_queue_rq_timeout(sdev->request_queue, MPI3MR_SCMD_TIMEOUT);
- switch (tgt_dev->dev_type) {
- case MPI3_DEVICE_DEVFORM_PCIE:
- /*The block layer hw sector size = 512*/
- if ((tgt_dev->dev_spec.pcie_inf.dev_info &
- MPI3_DEVICE0_PCIE_DEVICE_INFO_TYPE_MASK) ==
- MPI3_DEVICE0_PCIE_DEVICE_INFO_TYPE_NVME_DEVICE) {
- blk_queue_max_hw_sectors(sdev->request_queue,
- tgt_dev->dev_spec.pcie_inf.mdts / 512);
- if (tgt_dev->dev_spec.pcie_inf.pgsz == 0)
- blk_queue_virt_boundary(sdev->request_queue,
- ((1 << MPI3MR_DEFAULT_PGSZEXP) - 1));
- else
- blk_queue_virt_boundary(sdev->request_queue,
- ((1 << tgt_dev->dev_spec.pcie_inf.pgsz) - 1));
- }
- break;
- default:
- break;
- }
-
+ mpi3mr_configure_tgt_dev(tgt_dev, lim);
mpi3mr_tgtdev_put(tgt_dev);
-
return retval;
}
/**
- * mpi3mr_slave_alloc -Slave alloc callback handler
+ * mpi3mr_sdev_init -Slave alloc callback handler
* @sdev: SCSI device reference
*
* Allocate per device(lun) private data and initialize it.
*
* Return: 0 on success -ENOMEM on memory allocation failure.
*/
-static int mpi3mr_slave_alloc(struct scsi_device *sdev)
+static int mpi3mr_sdev_init(struct scsi_device *sdev)
{
struct Scsi_Host *shost;
struct mpi3mr_ioc *mrioc;
@@ -4780,7 +5052,8 @@ static int mpi3mr_qcmd(struct Scsi_Host *shost,
goto out;
}
- if (mrioc->reset_in_progress) {
+ if (mrioc->reset_in_progress || mrioc->prepare_for_reset
+ || mrioc->block_on_pci_err) {
retval = SCSI_MLQUEUE_HOST_BUSY;
goto out;
}
@@ -4895,7 +5168,7 @@ static int mpi3mr_qcmd(struct Scsi_Host *shost,
MPI3_SCSIIO_MSGFLAGS_DIVERT_TO_FIRMWARE;
scsiio_flags |= MPI3_SCSIIO_FLAGS_DIVERT_REASON_IO_THROTTLING;
}
- scsiio_req->flags = cpu_to_le32(scsiio_flags);
+ scsiio_req->flags |= cpu_to_le32(scsiio_flags);
if (mpi3mr_op_request_post(mrioc, op_req_q,
scmd_priv_data->mpi3mr_scsiio_req)) {
@@ -4920,13 +5193,14 @@ static const struct scsi_host_template mpi3mr_driver_template = {
.proc_name = MPI3MR_DRIVER_NAME,
.queuecommand = mpi3mr_qcmd,
.target_alloc = mpi3mr_target_alloc,
- .slave_alloc = mpi3mr_slave_alloc,
- .slave_configure = mpi3mr_slave_configure,
+ .sdev_init = mpi3mr_sdev_init,
+ .sdev_configure = mpi3mr_sdev_configure,
.target_destroy = mpi3mr_target_destroy,
- .slave_destroy = mpi3mr_slave_destroy,
+ .sdev_destroy = mpi3mr_sdev_destroy,
.scan_finished = mpi3mr_scan_finished,
.scan_start = mpi3mr_scan_start,
.change_queue_depth = mpi3mr_change_queue_depth,
+ .eh_abort_handler = mpi3mr_eh_abort,
.eh_device_reset_handler = mpi3mr_eh_dev_reset,
.eh_target_reset_handler = mpi3mr_eh_target_reset,
.eh_bus_reset_handler = mpi3mr_eh_bus_reset,
@@ -5073,7 +5347,7 @@ mpi3mr_probe(struct pci_dev *pdev, const struct pci_device_id *id)
}
mrioc = shost_priv(shost);
- retval = ida_alloc_range(&mrioc_ida, 1, U8_MAX, GFP_KERNEL);
+ retval = ida_alloc_range(&mrioc_ida, 0, U8_MAX, GFP_KERNEL);
if (retval < 0)
goto id_alloc_failed;
mrioc->id = (u8)retval;
@@ -5092,6 +5366,7 @@ mpi3mr_probe(struct pci_dev *pdev, const struct pci_device_id *id)
spin_lock_init(&mrioc->watchdog_lock);
spin_lock_init(&mrioc->chain_buf_lock);
spin_lock_init(&mrioc->sas_node_lock);
+ spin_lock_init(&mrioc->trigger_lock);
INIT_LIST_HEAD(&mrioc->fwevt_list);
INIT_LIST_HEAD(&mrioc->tgtdev_list);
@@ -5174,10 +5449,8 @@ mpi3mr_probe(struct pci_dev *pdev, const struct pci_device_id *id)
else
scsi_host_set_guard(shost, SHOST_DIX_GUARD_CRC);
- snprintf(mrioc->fwevt_worker_name, sizeof(mrioc->fwevt_worker_name),
- "%s%d_fwevt_wrkr", mrioc->driver_name, mrioc->id);
mrioc->fwevt_worker_thread = alloc_ordered_workqueue(
- mrioc->fwevt_worker_name, 0);
+ "%s%d_fwevt_wrkr", 0, mrioc->driver_name, mrioc->id);
if (!mrioc->fwevt_worker_thread) {
ioc_err(mrioc, "failure at %s:%d/%s()!\n",
__FILE__, __LINE__, __func__);
@@ -5263,7 +5536,14 @@ static void mpi3mr_remove(struct pci_dev *pdev)
while (mrioc->reset_in_progress || mrioc->is_driver_loading)
ssleep(1);
- if (!pci_device_is_present(mrioc->pdev)) {
+ if (mrioc->block_on_pci_err) {
+ mrioc->block_on_pci_err = false;
+ scsi_unblock_requests(shost);
+ mrioc->unrecoverable = 1;
+ }
+
+ if (!pci_device_is_present(mrioc->pdev) ||
+ mrioc->pci_err_recovery) {
mrioc->unrecoverable = 1;
mpi3mr_flush_cmds_for_unrecovered_controller(mrioc);
}
@@ -5447,6 +5727,197 @@ mpi3mr_resume(struct device *dev)
return 0;
}
+/**
+ * mpi3mr_pcierr_error_detected - PCI error detected callback
+ * @pdev: PCI device instance
+ * @state: channel state
+ *
+ * This function is called by the PCI error recovery driver and
+ * based on the state passed the driver decides what actions to
+ * be recommended back to PCI driver.
+ *
+ * For all of the states if there is no valid mrioc or scsi host
+ * references in the PCI device then this function will return
+ * the result as disconnect.
+ *
+ * For normal state, this function will return the result as can
+ * recover.
+ *
+ * For frozen state, this function will block for any pending
+ * controller initialization or re-initialization to complete,
+ * stop any new interactions with the controller and return
+ * status as reset required.
+ *
+ * For permanent failure state, this function will mark the
+ * controller as unrecoverable and return status as disconnect.
+ *
+ * Returns: PCI_ERS_RESULT_NEED_RESET or CAN_RECOVER or
+ * DISCONNECT based on the controller state.
+ */
+static pci_ers_result_t
+mpi3mr_pcierr_error_detected(struct pci_dev *pdev, pci_channel_state_t state)
+{
+ struct Scsi_Host *shost;
+ struct mpi3mr_ioc *mrioc;
+ unsigned int timeout = MPI3MR_RESET_TIMEOUT;
+
+ dev_info(&pdev->dev, "%s: callback invoked state(%d)\n", __func__,
+ state);
+
+ shost = pci_get_drvdata(pdev);
+ mrioc = shost_priv(shost);
+
+ switch (state) {
+ case pci_channel_io_normal:
+ return PCI_ERS_RESULT_CAN_RECOVER;
+ case pci_channel_io_frozen:
+ mrioc->pci_err_recovery = true;
+ mrioc->block_on_pci_err = true;
+ do {
+ if (mrioc->reset_in_progress || mrioc->is_driver_loading)
+ ssleep(1);
+ else
+ break;
+ } while (--timeout);
+
+ if (!timeout) {
+ mrioc->pci_err_recovery = true;
+ mrioc->block_on_pci_err = true;
+ mrioc->unrecoverable = 1;
+ mpi3mr_stop_watchdog(mrioc);
+ mpi3mr_flush_cmds_for_unrecovered_controller(mrioc);
+ return PCI_ERS_RESULT_DISCONNECT;
+ }
+
+ scsi_block_requests(mrioc->shost);
+ mpi3mr_stop_watchdog(mrioc);
+ mpi3mr_cleanup_resources(mrioc);
+ return PCI_ERS_RESULT_NEED_RESET;
+ case pci_channel_io_perm_failure:
+ mrioc->pci_err_recovery = true;
+ mrioc->block_on_pci_err = true;
+ mrioc->unrecoverable = 1;
+ mpi3mr_stop_watchdog(mrioc);
+ mpi3mr_flush_cmds_for_unrecovered_controller(mrioc);
+ return PCI_ERS_RESULT_DISCONNECT;
+ default:
+ return PCI_ERS_RESULT_DISCONNECT;
+ }
+}
+
+/**
+ * mpi3mr_pcierr_slot_reset - Post slot reset callback
+ * @pdev: PCI device instance
+ *
+ * This function is called by the PCI error recovery driver
+ * after a slot or link reset issued by it for the recovery, the
+ * driver is expected to bring back the controller and
+ * initialize it.
+ *
+ * This function restores PCI state and reinitializes controller
+ * resources and the controller, this blocks for any pending
+ * reset to complete.
+ *
+ * Returns: PCI_ERS_RESULT_DISCONNECT on failure or
+ * PCI_ERS_RESULT_RECOVERED
+ */
+static pci_ers_result_t mpi3mr_pcierr_slot_reset(struct pci_dev *pdev)
+{
+ struct Scsi_Host *shost;
+ struct mpi3mr_ioc *mrioc;
+ unsigned int timeout = MPI3MR_RESET_TIMEOUT;
+
+ dev_info(&pdev->dev, "%s: callback invoked\n", __func__);
+
+ shost = pci_get_drvdata(pdev);
+ mrioc = shost_priv(shost);
+
+ do {
+ if (mrioc->reset_in_progress)
+ ssleep(1);
+ else
+ break;
+ } while (--timeout);
+
+ if (!timeout)
+ goto out_failed;
+
+ pci_restore_state(pdev);
+
+ if (mpi3mr_setup_resources(mrioc)) {
+ ioc_err(mrioc, "setup resources failed\n");
+ goto out_failed;
+ }
+ mrioc->unrecoverable = 0;
+ mrioc->pci_err_recovery = false;
+
+ if (mpi3mr_soft_reset_handler(mrioc, MPI3MR_RESET_FROM_FIRMWARE, 0))
+ goto out_failed;
+
+ return PCI_ERS_RESULT_RECOVERED;
+
+out_failed:
+ mrioc->unrecoverable = 1;
+ mrioc->block_on_pci_err = false;
+ scsi_unblock_requests(shost);
+ mpi3mr_start_watchdog(mrioc);
+ return PCI_ERS_RESULT_DISCONNECT;
+}
+
+/**
+ * mpi3mr_pcierr_resume - PCI error recovery resume
+ * callback
+ * @pdev: PCI device instance
+ *
+ * This function enables all I/O and IOCTLs post reset issued as
+ * part of the PCI error recovery
+ *
+ * Return: Nothing.
+ */
+static void mpi3mr_pcierr_resume(struct pci_dev *pdev)
+{
+ struct Scsi_Host *shost;
+ struct mpi3mr_ioc *mrioc;
+
+ dev_info(&pdev->dev, "%s: callback invoked\n", __func__);
+
+ shost = pci_get_drvdata(pdev);
+ mrioc = shost_priv(shost);
+
+ if (mrioc->block_on_pci_err) {
+ mrioc->block_on_pci_err = false;
+ scsi_unblock_requests(shost);
+ mpi3mr_start_watchdog(mrioc);
+ }
+}
+
+/**
+ * mpi3mr_pcierr_mmio_enabled - PCI error recovery callback
+ * @pdev: PCI device instance
+ *
+ * This is called only if mpi3mr_pcierr_error_detected returns
+ * PCI_ERS_RESULT_CAN_RECOVER.
+ *
+ * Return: PCI_ERS_RESULT_DISCONNECT when the controller is
+ * unrecoverable or when the shost/mrioc reference cannot be
+ * found, else return PCI_ERS_RESULT_RECOVERED
+ */
+static pci_ers_result_t mpi3mr_pcierr_mmio_enabled(struct pci_dev *pdev)
+{
+ struct Scsi_Host *shost;
+ struct mpi3mr_ioc *mrioc;
+
+ dev_info(&pdev->dev, "%s: callback invoked\n", __func__);
+
+ shost = pci_get_drvdata(pdev);
+ mrioc = shost_priv(shost);
+
+ if (mrioc->unrecoverable)
+ return PCI_ERS_RESULT_DISCONNECT;
+
+ return PCI_ERS_RESULT_RECOVERED;
+}
+
static const struct pci_device_id mpi3mr_pci_id_table[] = {
{
PCI_DEVICE_SUB(MPI3_MFGPAGE_VENDORID_BROADCOM,
@@ -5464,6 +5935,13 @@ static const struct pci_device_id mpi3mr_pci_id_table[] = {
};
MODULE_DEVICE_TABLE(pci, mpi3mr_pci_id_table);
+static const struct pci_error_handlers mpi3mr_err_handler = {
+ .error_detected = mpi3mr_pcierr_error_detected,
+ .mmio_enabled = mpi3mr_pcierr_mmio_enabled,
+ .slot_reset = mpi3mr_pcierr_slot_reset,
+ .resume = mpi3mr_pcierr_resume,
+};
+
static SIMPLE_DEV_PM_OPS(mpi3mr_pm_ops, mpi3mr_suspend, mpi3mr_resume);
static struct pci_driver mpi3mr_pci_driver = {
@@ -5472,6 +5950,7 @@ static struct pci_driver mpi3mr_pci_driver = {
.probe = mpi3mr_probe,
.remove = mpi3mr_remove,
.shutdown = mpi3mr_shutdown,
+ .err_handler = &mpi3mr_err_handler,
.driver.pm = &mpi3mr_pm_ops,
};
diff --git a/drivers/scsi/mpi3mr/mpi3mr_transport.c b/drivers/scsi/mpi3mr/mpi3mr_transport.c
index d32ad46318cb..c8d6ced5640e 100644
--- a/drivers/scsi/mpi3mr/mpi3mr_transport.c
+++ b/drivers/scsi/mpi3mr/mpi3mr_transport.c
@@ -7,6 +7,8 @@
*
*/
+#include <linux/vmalloc.h>
+
#include "mpi3mr.h"
/**
@@ -103,10 +105,10 @@ struct rep_manu_reply {
u8 reserved0[2];
u8 sas_format;
u8 reserved2[3];
- u8 vendor_id[SAS_EXPANDER_VENDOR_ID_LEN];
- u8 product_id[SAS_EXPANDER_PRODUCT_ID_LEN];
- u8 product_rev[SAS_EXPANDER_PRODUCT_REV_LEN];
- u8 component_vendor_id[SAS_EXPANDER_COMPONENT_VENDOR_ID_LEN];
+ u8 vendor_id[SAS_EXPANDER_VENDOR_ID_LEN] __nonstring;
+ u8 product_id[SAS_EXPANDER_PRODUCT_ID_LEN] __nonstring;
+ u8 product_rev[SAS_EXPANDER_PRODUCT_REV_LEN] __nonstring;
+ u8 component_vendor_id[SAS_EXPANDER_COMPONENT_VENDOR_ID_LEN] __nonstring;
u16 component_id;
u8 component_revision_id;
u8 reserved3;
@@ -149,6 +151,11 @@ static int mpi3mr_report_manufacture(struct mpi3mr_ioc *mrioc,
return -EFAULT;
}
+ if (mrioc->pci_err_recovery) {
+ ioc_err(mrioc, "%s: pci error recovery in progress!\n", __func__);
+ return -EFAULT;
+ }
+
data_out_sz = sizeof(struct rep_manu_request);
data_in_sz = sizeof(struct rep_manu_reply);
data_out = dma_alloc_coherent(&mrioc->pdev->dev,
@@ -209,17 +216,13 @@ static int mpi3mr_report_manufacture(struct mpi3mr_ioc *mrioc,
goto out;
}
- strscpy(edev->vendor_id, manufacture_reply->vendor_id,
- SAS_EXPANDER_VENDOR_ID_LEN);
- strscpy(edev->product_id, manufacture_reply->product_id,
- SAS_EXPANDER_PRODUCT_ID_LEN);
- strscpy(edev->product_rev, manufacture_reply->product_rev,
- SAS_EXPANDER_PRODUCT_REV_LEN);
+ memtostr(edev->vendor_id, manufacture_reply->vendor_id);
+ memtostr(edev->product_id, manufacture_reply->product_id);
+ memtostr(edev->product_rev, manufacture_reply->product_rev);
edev->level = manufacture_reply->sas_format & 1;
if (edev->level) {
- strscpy(edev->component_vendor_id,
- manufacture_reply->component_vendor_id,
- SAS_EXPANDER_COMPONENT_VENDOR_ID_LEN);
+ memtostr(edev->component_vendor_id,
+ manufacture_reply->component_vendor_id);
tmp = (u8 *)&manufacture_reply->component_id;
edev->component_id = tmp[0] << 8 | tmp[1];
edev->component_revision_id =
@@ -587,12 +590,13 @@ static enum sas_linkrate mpi3mr_convert_phy_link_rate(u8 link_rate)
* @mrioc: Adapter instance reference
* @mr_sas_port: Internal Port object
* @mr_sas_phy: Internal Phy object
+ * @host_node: Flag to indicate this is a host_node
*
* Return: None.
*/
static void mpi3mr_delete_sas_phy(struct mpi3mr_ioc *mrioc,
struct mpi3mr_sas_port *mr_sas_port,
- struct mpi3mr_sas_phy *mr_sas_phy)
+ struct mpi3mr_sas_phy *mr_sas_phy, u8 host_node)
{
u64 sas_address = mr_sas_port->remote_identify.sas_address;
@@ -602,9 +606,13 @@ static void mpi3mr_delete_sas_phy(struct mpi3mr_ioc *mrioc,
list_del(&mr_sas_phy->port_siblings);
mr_sas_port->num_phys--;
- mr_sas_port->phy_mask &= ~(1 << mr_sas_phy->phy_id);
- if (mr_sas_port->lowest_phy == mr_sas_phy->phy_id)
- mr_sas_port->lowest_phy = ffs(mr_sas_port->phy_mask) - 1;
+
+ if (host_node) {
+ mr_sas_port->phy_mask &= ~(1 << mr_sas_phy->phy_id);
+
+ if (mr_sas_port->lowest_phy == mr_sas_phy->phy_id)
+ mr_sas_port->lowest_phy = ffs(mr_sas_port->phy_mask) - 1;
+ }
sas_port_delete_phy(mr_sas_port->port, mr_sas_phy->phy);
mr_sas_phy->phy_belongs_to_port = 0;
}
@@ -614,12 +622,13 @@ static void mpi3mr_delete_sas_phy(struct mpi3mr_ioc *mrioc,
* @mrioc: Adapter instance reference
* @mr_sas_port: Internal Port object
* @mr_sas_phy: Internal Phy object
+ * @host_node: Flag to indicate this is a host_node
*
* Return: None.
*/
static void mpi3mr_add_sas_phy(struct mpi3mr_ioc *mrioc,
struct mpi3mr_sas_port *mr_sas_port,
- struct mpi3mr_sas_phy *mr_sas_phy)
+ struct mpi3mr_sas_phy *mr_sas_phy, u8 host_node)
{
u64 sas_address = mr_sas_port->remote_identify.sas_address;
@@ -629,9 +638,12 @@ static void mpi3mr_add_sas_phy(struct mpi3mr_ioc *mrioc,
list_add_tail(&mr_sas_phy->port_siblings, &mr_sas_port->phy_list);
mr_sas_port->num_phys++;
- mr_sas_port->phy_mask |= (1 << mr_sas_phy->phy_id);
- if (mr_sas_phy->phy_id < mr_sas_port->lowest_phy)
- mr_sas_port->lowest_phy = ffs(mr_sas_port->phy_mask) - 1;
+ if (host_node) {
+ mr_sas_port->phy_mask |= (1 << mr_sas_phy->phy_id);
+
+ if (mr_sas_phy->phy_id < mr_sas_port->lowest_phy)
+ mr_sas_port->lowest_phy = ffs(mr_sas_port->phy_mask) - 1;
+ }
sas_port_add_phy(mr_sas_port->port, mr_sas_phy->phy);
mr_sas_phy->phy_belongs_to_port = 1;
}
@@ -672,7 +684,7 @@ static void mpi3mr_add_phy_to_an_existing_port(struct mpi3mr_ioc *mrioc,
if (srch_phy == mr_sas_phy)
return;
}
- mpi3mr_add_sas_phy(mrioc, mr_sas_port, mr_sas_phy);
+ mpi3mr_add_sas_phy(mrioc, mr_sas_port, mr_sas_phy, mr_sas_node->host_node);
return;
}
}
@@ -733,7 +745,7 @@ static void mpi3mr_del_phy_from_an_existing_port(struct mpi3mr_ioc *mrioc,
mpi3mr_delete_sas_port(mrioc, mr_sas_port);
else
mpi3mr_delete_sas_phy(mrioc, mr_sas_port,
- mr_sas_phy);
+ mr_sas_phy, mr_sas_node->host_node);
return;
}
}
@@ -792,6 +804,12 @@ static int mpi3mr_set_identify(struct mpi3mr_ioc *mrioc, u16 handle,
return -EFAULT;
}
+ if (mrioc->pci_err_recovery) {
+ ioc_err(mrioc, "%s: pci error recovery in progress!\n",
+ __func__);
+ return -EFAULT;
+ }
+
if ((mpi3mr_cfg_get_dev_pg0(mrioc, &ioc_status, &device_pg0,
sizeof(device_pg0), MPI3_DEVICE_PGAD_FORM_HANDLE, handle))) {
ioc_err(mrioc, "%s: device page0 read failed\n", __func__);
@@ -1009,6 +1027,9 @@ mpi3mr_alloc_hba_port(struct mpi3mr_ioc *mrioc, u16 port_id)
hba_port->port_id = port_id;
ioc_info(mrioc, "hba_port entry: %p, port: %d is added to hba_port list\n",
hba_port, hba_port->port_id);
+ if (mrioc->reset_in_progress ||
+ mrioc->pci_err_recovery)
+ hba_port->flags = MPI3MR_HBA_PORT_FLAG_NEW;
list_add_tail(&hba_port->list, &mrioc->hba_port_table_list);
return hba_port;
}
@@ -1016,7 +1037,7 @@ mpi3mr_alloc_hba_port(struct mpi3mr_ioc *mrioc, u16 port_id)
/**
* mpi3mr_get_hba_port_by_id - find hba port by id
* @mrioc: Adapter instance reference
- * @port_id - Port ID to search
+ * @port_id: Port ID to search
*
* Return: mpi3mr_hba_port reference for the matched port
*/
@@ -1057,7 +1078,7 @@ void mpi3mr_update_links(struct mpi3mr_ioc *mrioc,
struct mpi3mr_sas_node *mr_sas_node;
struct mpi3mr_sas_phy *mr_sas_phy;
- if (mrioc->reset_in_progress)
+ if (mrioc->reset_in_progress || mrioc->pci_err_recovery)
return;
spin_lock_irqsave(&mrioc->sas_node_lock, flags);
@@ -1355,15 +1376,27 @@ static struct mpi3mr_sas_port *mpi3mr_sas_port_add(struct mpi3mr_ioc *mrioc,
mpi3mr_sas_port_sanity_check(mrioc, mr_sas_node,
mr_sas_port->remote_identify.sas_address, hba_port);
+ if (mr_sas_node->host_node && mr_sas_node->num_phys >=
+ sizeof(mr_sas_port->phy_mask) * 8)
+ ioc_info(mrioc, "max port count %u could be too high\n",
+ mr_sas_node->num_phys);
+
for (i = 0; i < mr_sas_node->num_phys; i++) {
if ((mr_sas_node->phy[i].remote_identify.sas_address !=
mr_sas_port->remote_identify.sas_address) ||
(mr_sas_node->phy[i].hba_port != hba_port))
continue;
+
+ if (mr_sas_node->host_node && (i >= sizeof(mr_sas_port->phy_mask) * 8)) {
+ ioc_warn(mrioc, "skipping port %u, max allowed value is %zu\n",
+ i, sizeof(mr_sas_port->phy_mask) * 8);
+ goto out_fail;
+ }
list_add_tail(&mr_sas_node->phy[i].port_siblings,
&mr_sas_port->phy_list);
mr_sas_port->num_phys++;
- mr_sas_port->phy_mask |= (1 << i);
+ if (mr_sas_node->host_node)
+ mr_sas_port->phy_mask |= (1 << i);
}
if (!mr_sas_port->num_phys) {
@@ -1372,7 +1405,8 @@ static struct mpi3mr_sas_port *mpi3mr_sas_port_add(struct mpi3mr_ioc *mrioc,
goto out_fail;
}
- mr_sas_port->lowest_phy = ffs(mr_sas_port->phy_mask) - 1;
+ if (mr_sas_node->host_node)
+ mr_sas_port->lowest_phy = ffs(mr_sas_port->phy_mask) - 1;
if (mr_sas_port->remote_identify.device_type == SAS_END_DEVICE) {
tgtdev = mpi3mr_get_tgtdev_by_addr(mrioc,
@@ -1970,7 +2004,7 @@ int mpi3mr_expander_add(struct mpi3mr_ioc *mrioc, u16 handle)
if (!handle)
return -1;
- if (mrioc->reset_in_progress)
+ if (mrioc->reset_in_progress || mrioc->pci_err_recovery)
return -1;
if ((mpi3mr_cfg_get_sas_exp_pg0(mrioc, &ioc_status, &expander_pg0,
@@ -2176,7 +2210,7 @@ void mpi3mr_expander_node_remove(struct mpi3mr_ioc *mrioc,
/* remove sibling ports attached to this expander */
list_for_each_entry_safe(mr_sas_port, next,
&sas_expander->sas_port_list, port_list) {
- if (mrioc->reset_in_progress)
+ if (mrioc->reset_in_progress || mrioc->pci_err_recovery)
return;
if (mr_sas_port->remote_identify.device_type ==
SAS_END_DEVICE)
@@ -2226,7 +2260,7 @@ void mpi3mr_expander_remove(struct mpi3mr_ioc *mrioc, u64 sas_address,
struct mpi3mr_sas_node *sas_expander;
unsigned long flags;
- if (mrioc->reset_in_progress)
+ if (mrioc->reset_in_progress || mrioc->pci_err_recovery)
return;
if (!hba_port)
@@ -2537,6 +2571,11 @@ static int mpi3mr_get_expander_phy_error_log(struct mpi3mr_ioc *mrioc,
return -EFAULT;
}
+ if (mrioc->pci_err_recovery) {
+ ioc_err(mrioc, "%s: pci error recovery in progress!\n", __func__);
+ return -EFAULT;
+ }
+
data_out_sz = sizeof(struct phy_error_log_request);
data_in_sz = sizeof(struct phy_error_log_reply);
sz = data_out_sz + data_in_sz;
@@ -2796,6 +2835,12 @@ mpi3mr_expander_phy_control(struct mpi3mr_ioc *mrioc,
return -EFAULT;
}
+ if (mrioc->pci_err_recovery) {
+ ioc_err(mrioc, "%s: pci error recovery in progress!\n",
+ __func__);
+ return -EFAULT;
+ }
+
data_out_sz = sizeof(struct phy_control_request);
data_in_sz = sizeof(struct phy_control_reply);
sz = data_out_sz + data_in_sz;
@@ -3219,6 +3264,12 @@ mpi3mr_transport_smp_handler(struct bsg_job *job, struct Scsi_Host *shost,
goto out;
}
+ if (mrioc->pci_err_recovery) {
+ ioc_err(mrioc, "%s: pci error recovery in progress!\n", __func__);
+ rc = -EFAULT;
+ goto out;
+ }
+
rc = mpi3mr_map_smp_buffer(&mrioc->pdev->dev, &job->request_payload,
&dma_addr_out, &dma_len_out, &addr_out);
if (rc)