scsi: hisi_sas: Modify v3 HW SSP underflow error processing
authorXingui Yang <yangxingui@huawei.com>
Thu, 24 Feb 2022 11:51:29 +0000 (19:51 +0800)
committerMartin K. Petersen <martin.petersen@oracle.com>
Mon, 28 Feb 2022 02:46:41 +0000 (21:46 -0500)
In case of SSP underflow allow the response frame IU to be examined for
setting the response stat value rather than always setting
SAS_DATA_UNDERRUN.

This will mean that we call sas_ssp_task_response() in those scenarios and
may send sense data to upper layer.

Such a condition would be for bad blocks were we just reporting an
underflow error to upper layer, but now the sense data will tell
immediately that the media is faulty.

Link: https://lore.kernel.org/r/1645703489-87194-7-git-send-email-john.garry@huawei.com
Signed-off-by: Xingui Yang <yangxingui@huawei.com>
Signed-off-by: Qi Liu <liuqi115@huawei.com>
Signed-off-by: John Garry <john.garry@huawei.com>
Signed-off-by: Martin K. Petersen <martin.petersen@oracle.com>
drivers/scsi/hisi_sas/hisi_sas_v3_hw.c

index ad3e2db..914ae4e 100644 (file)
 #define CMPLT_HDR_ERROR_PHASE_MSK   (0xff << CMPLT_HDR_ERROR_PHASE_OFF)
 #define CMPLT_HDR_RSPNS_XFRD_OFF       10
 #define CMPLT_HDR_RSPNS_XFRD_MSK       (0x1 << CMPLT_HDR_RSPNS_XFRD_OFF)
+#define CMPLT_HDR_RSPNS_GOOD_OFF       11
+#define CMPLT_HDR_RSPNS_GOOD_MSK       (0x1 << CMPLT_HDR_RSPNS_GOOD_OFF)
 #define CMPLT_HDR_ERX_OFF              12
 #define CMPLT_HDR_ERX_MSK              (0x1 << CMPLT_HDR_ERX_OFF)
 #define CMPLT_HDR_ABORT_STAT_OFF       13
@@ -2140,7 +2142,7 @@ static irqreturn_t fatal_axi_int_v3_hw(int irq_no, void *p)
        return IRQ_HANDLED;
 }
 
-static void
+static bool
 slot_err_v3_hw(struct hisi_hba *hisi_hba, struct sas_task *task,
               struct hisi_sas_slot *slot)
 {
@@ -2158,6 +2160,15 @@ slot_err_v3_hw(struct hisi_hba *hisi_hba, struct sas_task *task,
        switch (task->task_proto) {
        case SAS_PROTOCOL_SSP:
                if (dma_rx_err_type & RX_DATA_LEN_UNDERFLOW_MSK) {
+                       /*
+                        * If returned response frame is incorrect because of data underflow,
+                        * but I/O information has been written to the host memory, we examine
+                        * response IU.
+                        */
+                       if (!(complete_hdr->dw0 & CMPLT_HDR_RSPNS_GOOD_MSK) &&
+                               (complete_hdr->dw0 & CMPLT_HDR_RSPNS_XFRD_MSK))
+                               return false;
+
                        ts->residual = trans_tx_fail_type;
                        ts->stat = SAS_DATA_UNDERRUN;
                } else if (dw3 & CMPLT_HDR_IO_IN_TARGET_MSK) {
@@ -2189,6 +2200,7 @@ slot_err_v3_hw(struct hisi_hba *hisi_hba, struct sas_task *task,
        default:
                break;
        }
+       return true;
 }
 
 static void slot_complete_v3_hw(struct hisi_hba *hisi_hba,
@@ -2262,19 +2274,20 @@ static void slot_complete_v3_hw(struct hisi_hba *hisi_hba,
        if ((dw0 & CMPLT_HDR_CMPLT_MSK) == 0x3) {
                u32 *error_info = hisi_sas_status_buf_addr_mem(slot);
 
-               slot_err_v3_hw(hisi_hba, task, slot);
-               if (ts->stat != SAS_DATA_UNDERRUN)
-                       dev_info(dev, "erroneous completion iptt=%d task=%pK dev id=%d addr=%016llx CQ hdr: 0x%x 0x%x 0x%x 0x%x Error info: 0x%x 0x%x 0x%x 0x%x\n",
-                                slot->idx, task, sas_dev->device_id,
-                                SAS_ADDR(device->sas_addr),
-                                dw0, dw1, complete_hdr->act, dw3,
-                                error_info[0], error_info[1],
-                                error_info[2], error_info[3]);
-               if (unlikely(slot->abort)) {
-                       sas_task_abort(task);
-                       return;
+               if (slot_err_v3_hw(hisi_hba, task, slot)) {
+                       if (ts->stat != SAS_DATA_UNDERRUN)
+                               dev_info(dev, "erroneous completion iptt=%d task=%pK dev id=%d addr=%016llx CQ hdr: 0x%x 0x%x 0x%x 0x%x Error info: 0x%x 0x%x 0x%x 0x%x\n",
+                                       slot->idx, task, sas_dev->device_id,
+                                       SAS_ADDR(device->sas_addr),
+                                       dw0, dw1, complete_hdr->act, dw3,
+                                       error_info[0], error_info[1],
+                                       error_info[2], error_info[3]);
+                       if (unlikely(slot->abort)) {
+                               sas_task_abort(task);
+                               return;
+                       }
+                       goto out;
                }
-               goto out;
        }
 
        switch (task->task_proto) {