scsi: hisi_sas: Modify v3 HW SSP underflow error processing

[ Upstream commit 62413199cd6d2906c121c2dfa3d7b82fd05f08db ]

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>
Stable-dep-of: f5393a5602ca ("scsi: hisi_sas: Fix normally completed I/O analysed as failed")
Signed-off-by: Sasha Levin <sashal@kernel.org>
This commit is contained in:
Xingui Yang
2022-02-24 19:51:29 +08:00
committed by Greg Kroah-Hartman
parent d84e5d445a
commit 6342206051

View File

@@ -392,6 +392,8 @@
#define CMPLT_HDR_ERROR_PHASE_MSK (0xff << CMPLT_HDR_ERROR_PHASE_OFF) #define CMPLT_HDR_ERROR_PHASE_MSK (0xff << CMPLT_HDR_ERROR_PHASE_OFF)
#define CMPLT_HDR_RSPNS_XFRD_OFF 10 #define CMPLT_HDR_RSPNS_XFRD_OFF 10
#define CMPLT_HDR_RSPNS_XFRD_MSK (0x1 << CMPLT_HDR_RSPNS_XFRD_OFF) #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_OFF 12
#define CMPLT_HDR_ERX_MSK (0x1 << CMPLT_HDR_ERX_OFF) #define CMPLT_HDR_ERX_MSK (0x1 << CMPLT_HDR_ERX_OFF)
#define CMPLT_HDR_ABORT_STAT_OFF 13 #define CMPLT_HDR_ABORT_STAT_OFF 13
@@ -2115,7 +2117,7 @@ static irqreturn_t fatal_axi_int_v3_hw(int irq_no, void *p)
return IRQ_HANDLED; return IRQ_HANDLED;
} }
static void static bool
slot_err_v3_hw(struct hisi_hba *hisi_hba, struct sas_task *task, slot_err_v3_hw(struct hisi_hba *hisi_hba, struct sas_task *task,
struct hisi_sas_slot *slot) struct hisi_sas_slot *slot)
{ {
@@ -2133,6 +2135,15 @@ slot_err_v3_hw(struct hisi_hba *hisi_hba, struct sas_task *task,
switch (task->task_proto) { switch (task->task_proto) {
case SAS_PROTOCOL_SSP: case SAS_PROTOCOL_SSP:
if (dma_rx_err_type & RX_DATA_LEN_UNDERFLOW_MSK) { 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->residual = trans_tx_fail_type;
ts->stat = SAS_DATA_UNDERRUN; ts->stat = SAS_DATA_UNDERRUN;
} else if (dw3 & CMPLT_HDR_IO_IN_TARGET_MSK) { } else if (dw3 & CMPLT_HDR_IO_IN_TARGET_MSK) {
@@ -2164,6 +2175,7 @@ slot_err_v3_hw(struct hisi_hba *hisi_hba, struct sas_task *task,
default: default:
break; break;
} }
return true;
} }
static void slot_complete_v3_hw(struct hisi_hba *hisi_hba, static void slot_complete_v3_hw(struct hisi_hba *hisi_hba,
@@ -2238,19 +2250,20 @@ static void slot_complete_v3_hw(struct hisi_hba *hisi_hba,
if ((dw0 & CMPLT_HDR_CMPLT_MSK) == 0x3) { if ((dw0 & CMPLT_HDR_CMPLT_MSK) == 0x3) {
u32 *error_info = hisi_sas_status_buf_addr_mem(slot); u32 *error_info = hisi_sas_status_buf_addr_mem(slot);
slot_err_v3_hw(hisi_hba, task, slot); if (slot_err_v3_hw(hisi_hba, task, slot)) {
if (ts->stat != SAS_DATA_UNDERRUN) 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", 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, slot->idx, task, sas_dev->device_id,
SAS_ADDR(device->sas_addr), SAS_ADDR(device->sas_addr),
dw0, dw1, complete_hdr->act, dw3, dw0, dw1, complete_hdr->act, dw3,
error_info[0], error_info[1], error_info[0], error_info[1],
error_info[2], error_info[3]); error_info[2], error_info[3]);
if (unlikely(slot->abort)) { if (unlikely(slot->abort)) {
sas_task_abort(task); sas_task_abort(task);
return; return;
}
goto out;
} }
goto out;
} }
switch (task->task_proto) { switch (task->task_proto) {