From e6d56756c53e62a83a3372e3480bebdd0d01d774 Mon Sep 17 00:00:00 2001
From: Xingui Yang <yangxingui@huawei.com>
Date: Tue, 15 Nov 2022 23:03:44 +0800
Subject: [PATCH 090/108] scsi: hisi_sas: Modify v3 HW SSP underflow error
 processing

mainline inclusion
from mainline-v5.18-rc1
commit 62413199cd6d2906c121c2dfa3d7b82fd05f08db
category: feature
bugzilla: https://gitee.com/src-openeuler/kernel/issues/I8F84O

Reference: https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=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>
Signed-off-by: xiabing <xiabing12@h-partners.com>
Reviewed-by: Xiang Chen <chenxiang66@hisilicon.com>
Reviewed-by: Jason Yan <yanaijie@huawei.com>
Signed-off-by: Zheng Zengkai <zhengzengkai@huawei.com>
Signed-off-by: YunYi Yang <yangyunyi2@huawei.com>

 Conflicts:
	drivers/scsi/hisi_sas/hisi_sas_v3_hw.c
---
 drivers/scsi/hisi_sas/hisi_sas_v3_hw.c | 113 ++++++++++++++-----------
 1 file changed, 62 insertions(+), 51 deletions(-)

diff --git a/drivers/scsi/hisi_sas/hisi_sas_v3_hw.c b/drivers/scsi/hisi_sas/hisi_sas_v3_hw.c
index adeddff88326..d56bca524f79 100644
--- a/drivers/scsi/hisi_sas/hisi_sas_v3_hw.c
+++ b/drivers/scsi/hisi_sas/hisi_sas_v3_hw.c
@@ -2333,7 +2333,7 @@ static void set_aborted_iptt(struct hisi_hba *hisi_hba,
 			1 << CFG_ABT_SET_IPTT_DONE_OFF);
 }
 
-static void
+static bool
 slot_err_v3_hw(struct hisi_hba *hisi_hba, struct sas_task *task,
 	       struct hisi_sas_slot *slot)
 {
@@ -2353,6 +2353,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;
 			if (!(dw0 & CMPLT_HDR_RSPNS_GOOD_MSK) &&
@@ -2401,6 +2410,7 @@ slot_err_v3_hw(struct hisi_hba *hisi_hba, struct sas_task *task,
 	default:
 		break;
 	}
+	return true;
 }
 
 static int ssp_need_spin_up(struct hisi_sas_slot *slot)
@@ -2502,61 +2512,62 @@ static void slot_complete_v3_hw(struct hisi_hba *hisi_hba,
 		struct hisi_sas_itct *itct = &hisi_hba->itct[device_id];
 
 		set_aborted_iptt(hisi_hba, slot);
-		slot_err_v3_hw(hisi_hba, task, slot);
-		dev_info(dev, "erroneous completion iptt=%d task=%pK dev id=%d addr%016llx sas_addr=0x%llx 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), itct->sas_addr,
-			 dw0, dw1,
-			 complete_hdr->act, dw3,
-			 error_info[0], error_info[1],
-			 error_info[2], error_info[3]);
-
-		if ((dw0 & CMPLT_HDR_RSPNS_XFRD_MSK) &&
-			(task->task_proto & SAS_PROTOCOL_SATA ||
-			task->task_proto & SAS_PROTOCOL_STP)) {
-			struct hisi_sas_status_buffer *status_buf =
+		if (slot_err_v3_hw(hisi_hba, task, slot)) {
+			dev_info(dev, "erroneous completion iptt=%d task=%pK dev id=%d addr%016llx sas_addr=0x%llx 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), itct->sas_addr,
+				 dw0, dw1,
+				 complete_hdr->act, dw3,
+				 error_info[0], error_info[1],
+				 error_info[2], error_info[3]);
+
+			if ((dw0 & CMPLT_HDR_RSPNS_XFRD_MSK) &&
+			    (task->task_proto & SAS_PROTOCOL_SATA ||
+			     task->task_proto & SAS_PROTOCOL_STP)) {
+				struct hisi_sas_status_buffer *status_buf =
 				hisi_sas_status_buf_addr_mem(slot);
-			u8 *iu = &status_buf->iu[0];
-			struct dev_to_host_fis *d2h =
-				(struct dev_to_host_fis *)iu;
+				u8 *iu = &status_buf->iu[0];
+				struct dev_to_host_fis *d2h =
+					(struct dev_to_host_fis *)iu;
 
-			dev_info(dev, "sata d2h status 0x%02x, error 0x%02x\n",
-				d2h->status, d2h->error);
-		}
+				dev_info(dev, "sata d2h status 0x%02x, error 0x%02x\n",
+					d2h->status, d2h->error);
+			}
 
-		if ((error_info[3] & RX_DATA_LEN_UNDERFLOW_MSK) &&
-			(task->task_proto == SAS_PROTOCOL_SSP)) {
-			/*print detail sense info when data underflow happened*/
-			bool rc;
-			int sb_len;
-			u8 *sense_buffer;
-			struct scsi_sense_hdr sshdr;
-			struct ssp_response_iu *iu =
-				hisi_sas_status_buf_addr_mem(slot) +
-				sizeof(struct hisi_sas_err_record);
-
-			sb_len = iu->sense_data_len;
-			sense_buffer = iu->sense_data;
-			rc = scsi_normalize_sense(sense_buffer, sb_len, &sshdr);
-			if (rc)
-				dev_info(dev, "data underflow, rsp_code:0x%x, sensekey:0x%x, ASC:0x%x, ASCQ:0x%x.\n",
-					sshdr.response_code,
-					sshdr.sense_key,
-					sshdr.asc,
-					sshdr.ascq);
-			else
-				dev_info(dev, "data underflow without sense, rsp_code:0x%02x.\n",
-					iu->resp_data[0]);
-		}
-		if (unlikely(slot->abort)) {
-			if (dev_is_sata(device) && task->ata_task.use_ncq)
-				hisi_sas_ata_device_link_abort(device);
-			else
-				sas_task_abort(task);
+			if ((error_info[3] & RX_DATA_LEN_UNDERFLOW_MSK) &&
+			    (task->task_proto == SAS_PROTOCOL_SSP)) {
+				/*print detail sense info when data underflow happened*/
+				bool rc;
+				int sb_len;
+				u8 *sense_buffer;
+				struct scsi_sense_hdr sshdr;
+				struct ssp_response_iu *iu =
+					hisi_sas_status_buf_addr_mem(slot) +
+					sizeof(struct hisi_sas_err_record);
+
+				sb_len = iu->sense_data_len;
+				sense_buffer = iu->sense_data;
+				rc = scsi_normalize_sense(sense_buffer, sb_len, &sshdr);
+				if (rc)
+					dev_info(dev, "data underflow, rsp_code:0x%x, sensekey:0x%x, ASC:0x%x, ASCQ:0x%x.\n",
+						 sshdr.response_code,
+						 sshdr.sense_key,
+						 sshdr.asc,
+						 sshdr.ascq);
+				else
+					dev_info(dev, "data underflow without sense, rsp_code:0x%02x.\n",
+						 iu->resp_data[0]);
+			}
+			if (unlikely(slot->abort)) {
+				if (dev_is_sata(device) && task->ata_task.use_ncq)
+					hisi_sas_ata_device_link_abort(device);
+				else
+					sas_task_abort(task);
 
-			return;
+				return;
+			}
+			goto out;
 		}
-		goto out;
 	}
 
 	switch (task->task_proto) {
-- 
2.27.0

