scsi: pm80xx: Check for fatal error
authorakshatzen <akshatzen@google.com>
Sat, 9 Jan 2021 12:38:43 +0000 (18:08 +0530)
committerMartin K. Petersen <martin.petersen@oracle.com>
Wed, 13 Jan 2021 05:02:01 +0000 (00:02 -0500)
When the controller runs into a fatal error, commands get stuck due to no
response. If the controller is in fatal error state, abort requests issued
to the controller get stuck too.

Check the controller state for fatal error conditions.

Link: https://lore.kernel.org/r/20210109123849.17098-3-Viswas.G@microchip.com
Acked-by: Jack Wang <jinpu.wang@cloud.ionos.com>
Signed-off-by: akshatzen <akshatzen@google.com>
Signed-off-by: Viswas G <Viswas.G@microchip.com>
Signed-off-by: Ruksar Devadi <Ruksar.devadi@microchip.com>
Signed-off-by: Radha Ramachandran <radha@google.com>
Signed-off-by: Martin K. Petersen <martin.petersen@oracle.com>
drivers/scsi/pm8001/pm8001_hwi.c
drivers/scsi/pm8001/pm8001_sas.c
drivers/scsi/pm8001/pm8001_sas.h
drivers/scsi/pm8001/pm80xx_hwi.c
drivers/scsi/pm8001/pm80xx_hwi.h

index c8d4d87..f147193 100644 (file)
@@ -4998,4 +4998,5 @@ const struct pm8001_dispatch pm8001_8001_dispatch = {
        .fw_flash_update_req    = pm8001_chip_fw_flash_update_req,
        .set_dev_state_req      = pm8001_chip_set_dev_state_req,
        .sas_re_init_req        = pm8001_chip_sas_re_initialization,
+       .fatal_errors           = pm80xx_fatal_errors,
 };
index d1e9dba..f8d142f 100644 (file)
@@ -1183,12 +1183,21 @@ int pm8001_abort_task(struct sas_task *task)
        int rc = TMF_RESP_FUNC_FAILED, ret;
        u32 phy_id;
        struct sas_task_slow slow_task;
+
        if (unlikely(!task || !task->lldd_task || !task->dev))
                return TMF_RESP_FUNC_FAILED;
+
        dev = task->dev;
        pm8001_dev = dev->lldd_dev;
        pm8001_ha = pm8001_find_ha_by_dev(dev);
        phy_id = pm8001_dev->attached_phy;
+
+       if (PM8001_CHIP_DISP->fatal_errors(pm8001_ha)) {
+               // If the controller is seeing fatal errors
+               // abort task will not get a response from the controller
+               return TMF_RESP_FUNC_FAILED;
+       }
+
        ret = pm8001_find_tag(task, &tag);
        if (ret == 0) {
                pm8001_info(pm8001_ha, "no tag for task:%p\n", task);
index f2c8cba..039ed91 100644 (file)
@@ -215,6 +215,7 @@ struct pm8001_dispatch {
        int (*sas_diag_execute_req)(struct pm8001_hba_info *pm8001_ha,
                u32 state);
        int (*sas_re_init_req)(struct pm8001_hba_info *pm8001_ha);
+       int (*fatal_errors)(struct pm8001_hba_info *pm8001_ha);
 };
 
 struct pm8001_chip_info {
@@ -725,6 +726,7 @@ ssize_t pm80xx_get_fatal_dump(struct device *cdev,
 ssize_t pm80xx_get_non_fatal_dump(struct device *cdev,
                struct device_attribute *attr, char *buf);
 ssize_t pm8001_get_gsm_dump(struct device *cdev, u32, char *buf);
+int pm80xx_fatal_errors(struct pm8001_hba_info *pm8001_ha);
 /* ctl shared API */
 extern struct device_attribute *pm8001_host_attrs[];
 
index 9c4b8b3..86a3d48 100644 (file)
@@ -1526,6 +1526,41 @@ static int mpi_uninit_check(struct pm8001_hba_info *pm8001_ha)
 }
 
 /**
+ * pm80xx_fatal_errors - returns non zero *ONLY* when fatal errors
+ * @pm8001_ha: our hba card information
+ *
+ * Fatal errors are recoverable only after a host reboot.
+ */
+int
+pm80xx_fatal_errors(struct pm8001_hba_info *pm8001_ha)
+{
+       int ret = 0;
+       u32 scratch_pad_rsvd0 = pm8001_cr32(pm8001_ha, 0,
+                                       MSGU_HOST_SCRATCH_PAD_6);
+       u32 scratch_pad_rsvd1 = pm8001_cr32(pm8001_ha, 0,
+                                       MSGU_HOST_SCRATCH_PAD_7);
+       u32 scratch_pad1 = pm8001_cr32(pm8001_ha, 0, MSGU_SCRATCH_PAD_1);
+       u32 scratch_pad2 = pm8001_cr32(pm8001_ha, 0, MSGU_SCRATCH_PAD_2);
+       u32 scratch_pad3 = pm8001_cr32(pm8001_ha, 0, MSGU_SCRATCH_PAD_3);
+
+       if (pm8001_ha->chip_id != chip_8006 &&
+                       pm8001_ha->chip_id != chip_8074 &&
+                       pm8001_ha->chip_id != chip_8076) {
+               return 0;
+       }
+
+       if (MSGU_SCRATCHPAD1_STATE_FATAL_ERROR(scratch_pad1)) {
+               pm8001_dbg(pm8001_ha, FAIL,
+                       "Fatal error SCRATCHPAD1 = 0x%x SCRATCHPAD2 = 0x%x SCRATCHPAD3 = 0x%x SCRATCHPAD_RSVD0 = 0x%x SCRATCHPAD_RSVD1 = 0x%x\n",
+                               scratch_pad1, scratch_pad2, scratch_pad3,
+                               scratch_pad_rsvd0, scratch_pad_rsvd1);
+               ret = 1;
+       }
+
+       return ret;
+}
+
+/**
  * pm8001_chip_soft_rst - soft reset the PM8001 chip, so that the clear all
  * the FW register status to the originated status.
  * @pm8001_ha: our hba card information
@@ -4959,4 +4994,5 @@ const struct pm8001_dispatch pm8001_80xx_dispatch = {
        .set_nvmd_req           = pm8001_chip_set_nvmd_req,
        .fw_flash_update_req    = pm8001_chip_fw_flash_update_req,
        .set_dev_state_req      = pm8001_chip_set_dev_state_req,
+       .fatal_errors           = pm80xx_fatal_errors,
 };
index 2b6b525..2c8e85c 100644 (file)
@@ -1368,6 +1368,19 @@ typedef struct SASProtocolTimerConfig SASProtocolTimerConfig_t;
 #define MSGU_HOST_SCRATCH_PAD_6                        0x6C
 #define MSGU_HOST_SCRATCH_PAD_7                        0x70
 
+#define MSGU_SCRATCHPAD1_RAAE_STATE_ERR(x) ((x & 0x3) == 0x2)
+#define MSGU_SCRATCHPAD1_ILA_STATE_ERR(x) (((x >> 2) & 0x3) == 0x2)
+#define MSGU_SCRATCHPAD1_BOOTLDR_STATE_ERR(x) ((((x >> 4) & 0x7) == 0x7) || \
+                                               (((x >> 4) & 0x7) == 0x4))
+#define MSGU_SCRATCHPAD1_IOP0_STATE_ERR(x) (((x >> 10) & 0x3) == 0x2)
+#define MSGU_SCRATCHPAD1_IOP1_STATE_ERR(x) (((x >> 12) & 0x3) == 0x2)
+#define MSGU_SCRATCHPAD1_STATE_FATAL_ERROR(x)  \
+                       (MSGU_SCRATCHPAD1_RAAE_STATE_ERR(x) ||      \
+                        MSGU_SCRATCHPAD1_ILA_STATE_ERR(x) ||       \
+                        MSGU_SCRATCHPAD1_BOOTLDR_STATE_ERR(x) ||   \
+                        MSGU_SCRATCHPAD1_IOP0_STATE_ERR(x) ||      \
+                        MSGU_SCRATCHPAD1_IOP1_STATE_ERR(x))
+
 /* bit definition for ODMR register */
 #define ODMR_MASK_ALL                  0xFFFFFFFF/* mask all
                                        interrupt vector */