scsi: pm80xx: Completing pending I/O after fatal error
authorRuksar Devadi <Ruksar.devadi@microchip.com>
Thu, 15 Apr 2021 10:33:50 +0000 (16:03 +0530)
committerMartin K. Petersen <martin.petersen@oracle.com>
Fri, 16 Apr 2021 02:28:59 +0000 (22:28 -0400)
When controller runs into fatal error, I/Os get stuck with no response,
handler event is defined to complete the pending I/Os (SAS task and
internal task) and also perform the cleanup for the drives.

Link: https://lore.kernel.org/r/20210415103352.3580-7-Viswas.G@microchip.com
Acked-by: Jack Wang <jinpu.wang@cloud.ionos.com>
Signed-off-by: Ruksar Devadi <Ruksar.devadi@microchip.com>
Signed-off-by: Viswas G <Viswas.G@microchip.com>
Signed-off-by: Ashokkumar N <Ashokkumar.N@microchip.com>
Signed-off-by: Martin K. Petersen <martin.petersen@oracle.com>
drivers/scsi/pm8001/pm8001_hwi.c
drivers/scsi/pm8001/pm8001_hwi.h
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 c1f9e7d0466b3ef7d9dce9a2e9cd48536236d23a..8ed505051657d97c7dae558f0561cbf4f91bd747 100644 (file)
@@ -1499,12 +1499,14 @@ void pm8001_work_fn(struct work_struct *work)
         * was cancelled. This nullification happens when the device
         * goes away.
         */
-       pm8001_dev = pw->data; /* Most stash device structure */
-       if ((pm8001_dev == NULL)
-        || ((pw->handler != IO_XFER_ERROR_BREAK)
-         && (pm8001_dev->dev_type == SAS_PHY_UNUSED))) {
-               kfree(pw);
-               return;
+       if (pw->handler != IO_FATAL_ERROR) {
+               pm8001_dev = pw->data; /* Most stash device structure */
+               if ((pm8001_dev == NULL)
+                || ((pw->handler != IO_XFER_ERROR_BREAK)
+                        && (pm8001_dev->dev_type == SAS_PHY_UNUSED))) {
+                       kfree(pw);
+                       return;
+               }
        }
 
        switch (pw->handler) {
@@ -1668,6 +1670,58 @@ void pm8001_work_fn(struct work_struct *work)
                dev = pm8001_dev->sas_device;
                pm8001_I_T_nexus_reset(dev);
                break;
+       case IO_FATAL_ERROR:
+       {
+               struct pm8001_hba_info *pm8001_ha = pw->pm8001_ha;
+               struct pm8001_ccb_info *ccb;
+               struct task_status_struct *ts;
+               struct sas_task *task;
+               int i;
+               u32 tag, device_id;
+
+               for (i = 0; ccb = NULL, i < PM8001_MAX_CCB; i++) {
+                       ccb = &pm8001_ha->ccb_info[i];
+                       task = ccb->task;
+                       ts = &task->task_status;
+                       tag = ccb->ccb_tag;
+                       /* check if tag is NULL */
+                       if (!tag) {
+                               pm8001_dbg(pm8001_ha, FAIL,
+                                       "tag Null\n");
+                               continue;
+                       }
+                       if (task != NULL) {
+                               dev = task->dev;
+                               if (!dev) {
+                                       pm8001_dbg(pm8001_ha, FAIL,
+                                               "dev is NULL\n");
+                                       continue;
+                               }
+                               /*complete sas task and update to top layer */
+                               pm8001_ccb_task_free(pm8001_ha, task, ccb, tag);
+                               ts->resp = SAS_TASK_COMPLETE;
+                               task->task_done(task);
+                       } else if (tag != 0xFFFFFFFF) {
+                               /* complete the internal commands/non-sas task */
+                               pm8001_dev = ccb->device;
+                               if (pm8001_dev->dcompletion) {
+                                       complete(pm8001_dev->dcompletion);
+                                       pm8001_dev->dcompletion = NULL;
+                               }
+                               complete(pm8001_ha->nvmd_completion);
+                               pm8001_tag_free(pm8001_ha, tag);
+                       }
+               }
+               /* Deregister all the device ids  */
+               for (i = 0; i < PM8001_MAX_DEVICES; i++) {
+                       pm8001_dev = &pm8001_ha->devices[i];
+                       device_id = pm8001_dev->device_id;
+                       if (device_id) {
+                               PM8001_CHIP_DISP->dereg_dev_req(pm8001_ha, device_id);
+                               pm8001_free_dev(pm8001_dev);
+                       }
+               }
+       }       break;
        }
        kfree(pw);
 }
index 6d91e2446542c78290dfba8f9e846380ccda3067..d1f3aa93325bf76c6b694b736419dbdb129ee74b 100644 (file)
@@ -805,6 +805,7 @@ struct set_dev_state_resp {
 #define IO_ABORT_IN_PROGRESS                           0x40
 #define IO_ABORT_DELAYED                               0x41
 #define IO_INVALID_LENGTH                              0x42
+#define IO_FATAL_ERROR                                 0x51
 
 /* WARNING: This error code must always be the last number.
  * If you add error code, modify this code also
index a773ee6e810b438305fc62be77cb92bb02720097..d28af413b93a227014e529addec26d2ff54ee68b 100644 (file)
@@ -590,7 +590,7 @@ struct pm8001_device *pm8001_find_dev(struct pm8001_hba_info *pm8001_ha,
        return NULL;
 }
 
-static void pm8001_free_dev(struct pm8001_device *pm8001_dev)
+void pm8001_free_dev(struct pm8001_device *pm8001_dev)
 {
        u32 id = pm8001_dev->id;
        memset(pm8001_dev, 0, sizeof(*pm8001_dev));
index 07d1ac287d43d3f972bb837fe666877f7aa34cb0..b5562f7fc7e53b7401be9d02b635416f6e4abd94 100644 (file)
@@ -726,6 +726,7 @@ 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);
+void pm8001_free_dev(struct pm8001_device *pm8001_dev);
 /* ctl shared API */
 extern struct device_attribute *pm8001_host_attrs[];
 
index f4f3956e658fa65806261fbdbdf7496d8065d91a..1c8dcdd5642c4741128169a2dedfeb767d3e1679 100644 (file)
@@ -4126,6 +4126,7 @@ static int process_oq(struct pm8001_hba_info *pm8001_ha, u8 vec)
                        pm8001_dbg(pm8001_ha, FAIL,
                                   "Firmware Fatal error! Regval:0x%x\n",
                                   regval);
+                       pm8001_handle_event(pm8001_ha, NULL, IO_FATAL_ERROR);
                        print_scratchpad_registers(pm8001_ha);
                        return ret;
                }
index 2c8e85cfdbc44f057bbf952cdb1b85e77d1c0d71..c7e5d93bea92439f06d50a520dd9a7c84e46a22f 100644 (file)
@@ -1272,6 +1272,7 @@ typedef struct SASProtocolTimerConfig SASProtocolTimerConfig_t;
 #define IO_OPEN_CNX_ERROR_IT_NEXUS_LOSS_OPEN_COLLIDE   0x47
 #define IO_OPEN_CNX_ERROR_IT_NEXUS_LOSS_PATHWAY_BLOCKED        0x48
 #define IO_DS_INVALID                                  0x49
+#define IO_FATAL_ERROR                                 0x51
 /* WARNING: the value is not contiguous from here */
 #define IO_XFER_ERR_LAST_PIO_DATAIN_CRC_ERR    0x52
 #define IO_XFER_DMA_ACTIVATE_TIMEOUT           0x53