195 lines
7.4 KiB
Diff
195 lines
7.4 KiB
Diff
From b8f5de9b6ec83c7aa33e502b3329f3fcb8df053e Mon Sep 17 00:00:00 2001
|
|
From: Luo Jiaxing <luojiaxing@huawei.com>
|
|
Date: Tue, 3 Aug 2021 14:48:04 +0800
|
|
Subject: [PATCH 080/108] scsi: hisi_sas: Reset controller for internal abort
|
|
timeout
|
|
|
|
mainline inclusion
|
|
from mainline-v5.14-rc1
|
|
commit 63ece9eb350312ee33327269480482dfac8555db
|
|
category: feature
|
|
bugzilla: https://gitee.com/src-openeuler/kernel/issues/I8F82P
|
|
|
|
Reference: https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=63ece9eb350312ee33327269480482dfac8555db
|
|
|
|
----------------------------------------------------------------------
|
|
|
|
If an internal task abort timeout occurs, the controller has developed a
|
|
fault, and needs to be reset to be recovered. However if a timeout occurs
|
|
during SCSI error handling, issuing a controller reset immediately may
|
|
conflict with the error handling.
|
|
|
|
To handle internal abort in these two scenarios, only queue the reset when
|
|
not in an error handling function. In the case of a timeout during error
|
|
handling, do nothing and rely on the inevitable ha nexus reset to reset the
|
|
controller.
|
|
|
|
Link: https://lore.kernel.org/r/1623058179-80434-5-git-send-email-john.garry@huawei.com
|
|
Signed-off-by: Luo Jiaxing <luojiaxing@huawei.com>
|
|
Signed-off-by: John Garry <john.garry@huawei.com>
|
|
Signed-off-by: Martin K. Petersen <martin.petersen@oracle.com>
|
|
Reviewed-by: Ouyangdelong <ouyangdelong@huawei.com>
|
|
Signed-off-by: Nifujia <nifujia1@hisilicon.com>
|
|
Signed-off-by: Zheng Zengkai <zhengzengkai@huawei.com>
|
|
Signed-off-by: YunYi Yang <yangyunyi2@huawei.com>
|
|
|
|
Conflicts:
|
|
drivers/scsi/hisi_sas/hisi_sas_main.c
|
|
---
|
|
drivers/scsi/hisi_sas/hisi_sas_main.c | 45 ++++++++++++++++++---------
|
|
1 file changed, 30 insertions(+), 15 deletions(-)
|
|
|
|
diff --git a/drivers/scsi/hisi_sas/hisi_sas_main.c b/drivers/scsi/hisi_sas/hisi_sas_main.c
|
|
index 281f03203f9f..434d8187e55c 100644
|
|
--- a/drivers/scsi/hisi_sas/hisi_sas_main.c
|
|
+++ b/drivers/scsi/hisi_sas/hisi_sas_main.c
|
|
@@ -20,7 +20,7 @@ static int hisi_sas_debug_issue_ssp_tmf(struct domain_device *device,
|
|
static int
|
|
hisi_sas_internal_task_abort(struct hisi_hba *hisi_hba,
|
|
struct domain_device *device,
|
|
- int abort_flag, int tag);
|
|
+ int abort_flag, int tag, bool rst_to_recover);
|
|
static int hisi_sas_softreset_ata_disk(struct domain_device *device);
|
|
static int hisi_sas_control_phy(struct asd_sas_phy *sas_phy, enum phy_func func,
|
|
void *funcdata);
|
|
@@ -1097,7 +1097,7 @@ static void hisi_sas_dev_gone(struct domain_device *device)
|
|
down(&hisi_hba->sem);
|
|
if (!test_bit(HISI_SAS_RESET_BIT, &hisi_hba->flags)) {
|
|
rc0 = hisi_sas_internal_task_abort(hisi_hba, device,
|
|
- HISI_SAS_INT_ABT_DEV, 0);
|
|
+ HISI_SAS_INT_ABT_DEV, 0, true);
|
|
|
|
hisi_sas_dereg_device(hisi_hba, device);
|
|
if (!list_empty(&sas_dev->list)) {
|
|
@@ -1564,7 +1564,8 @@ static void hisi_sas_terminate_stp_reject(struct hisi_hba *hisi_hba)
|
|
continue;
|
|
|
|
rc = hisi_sas_internal_task_abort(hisi_hba, device,
|
|
- HISI_SAS_INT_ABT_DEV, 0);
|
|
+ HISI_SAS_INT_ABT_DEV, 0,
|
|
+ false);
|
|
if (rc < 0)
|
|
dev_err(dev, "STP reject: abort dev failed %d\n", rc);
|
|
}
|
|
@@ -1724,7 +1725,8 @@ static int hisi_sas_abort_task(struct sas_task *task)
|
|
&tmf_task);
|
|
|
|
rc2 = hisi_sas_internal_task_abort(hisi_hba, device,
|
|
- HISI_SAS_INT_ABT_CMD, tag);
|
|
+ HISI_SAS_INT_ABT_CMD, tag,
|
|
+ false);
|
|
if (rc2 < 0) {
|
|
dev_err(dev, "abort task: internal abort (%d)\n", rc2);
|
|
return TMF_RESP_FUNC_FAILED;
|
|
@@ -1747,7 +1749,8 @@ static int hisi_sas_abort_task(struct sas_task *task)
|
|
struct ata_queued_cmd *qc = task->uldd_task;
|
|
|
|
rc = hisi_sas_internal_task_abort(hisi_hba, device,
|
|
- HISI_SAS_INT_ABT_DEV, 0);
|
|
+ HISI_SAS_INT_ABT_DEV,
|
|
+ 0, false);
|
|
if (rc < 0) {
|
|
dev_err(dev, "abort task: internal abort failed\n");
|
|
goto out;
|
|
@@ -1772,7 +1775,8 @@ static int hisi_sas_abort_task(struct sas_task *task)
|
|
struct hisi_sas_cq *cq = &hisi_hba->cq[slot->dlvry_queue];
|
|
|
|
rc = hisi_sas_internal_task_abort(hisi_hba, device,
|
|
- HISI_SAS_INT_ABT_CMD, tag);
|
|
+ HISI_SAS_INT_ABT_CMD, tag,
|
|
+ false);
|
|
if (((rc < 0) || (rc == TMF_RESP_FUNC_FAILED)) &&
|
|
task->lldd_task) {
|
|
/*
|
|
@@ -1798,7 +1802,7 @@ static int hisi_sas_abort_task_set(struct domain_device *device, u8 *lun)
|
|
int rc;
|
|
|
|
rc = hisi_sas_internal_task_abort(hisi_hba, device,
|
|
- HISI_SAS_INT_ABT_DEV, 0);
|
|
+ HISI_SAS_INT_ABT_DEV, 0, false);
|
|
if (rc < 0) {
|
|
dev_err(dev, "abort task set: internal abort rc=%d\n", rc);
|
|
return TMF_RESP_FUNC_FAILED;
|
|
@@ -1894,7 +1898,7 @@ static int hisi_sas_I_T_nexus_reset(struct domain_device *device)
|
|
sas_dev->dev_status = HISI_SAS_DEV_NORMAL;
|
|
|
|
rc = hisi_sas_internal_task_abort(hisi_hba, device,
|
|
- HISI_SAS_INT_ABT_DEV, 0);
|
|
+ HISI_SAS_INT_ABT_DEV, 0, false);
|
|
if (rc < 0) {
|
|
dev_err(dev, "I_T nexus reset: internal abort (%d)\n", rc);
|
|
return TMF_RESP_FUNC_FAILED;
|
|
@@ -1925,7 +1929,7 @@ static int hisi_sas_lu_reset(struct domain_device *device, u8 *lun)
|
|
|
|
/* Clear internal IO and then lu reset */
|
|
rc = hisi_sas_internal_task_abort(hisi_hba, device,
|
|
- HISI_SAS_INT_ABT_DEV, 0);
|
|
+ HISI_SAS_INT_ABT_DEV, 0, false);
|
|
if (rc < 0) {
|
|
dev_err(dev, "lu_reset: internal abort failed\n");
|
|
goto out;
|
|
@@ -2122,11 +2126,14 @@ hisi_sas_internal_abort_task_exec(struct hisi_hba *hisi_hba,
|
|
* @tag: tag of IO to be aborted (only relevant to single
|
|
* IO mode)
|
|
* @dq: delivery queue for this internal abort command
|
|
+ * @rst_to_recover: If rst_to_recover set, queue a controller
|
|
+ * reset if an internal abort times out.
|
|
*/
|
|
static int
|
|
_hisi_sas_internal_task_abort(struct hisi_hba *hisi_hba,
|
|
- struct domain_device *device,
|
|
- int abort_flag, int tag, struct hisi_sas_dq *dq)
|
|
+ struct domain_device *device, int abort_flag,
|
|
+ int tag, struct hisi_sas_dq *dq,
|
|
+ bool rst_to_recover)
|
|
{
|
|
struct sas_task *task;
|
|
struct hisi_sas_device *sas_dev = device->lldd_dev;
|
|
@@ -2182,7 +2189,13 @@ _hisi_sas_internal_task_abort(struct hisi_hba *hisi_hba,
|
|
synchronize_irq(cq->irq_no);
|
|
slot->task = NULL;
|
|
}
|
|
- dev_err(dev, "internal task abort: timeout and not done.\n");
|
|
+
|
|
+ if (rst_to_recover) {
|
|
+ dev_err(dev, "internal task abort: timeout and not done. Queuing reset.\n");
|
|
+ queue_work(hisi_hba->wq, &hisi_hba->rst_work);
|
|
+ } else {
|
|
+ dev_err(dev, "internal task abort: timeout and not done.\n");
|
|
+ }
|
|
|
|
res = -EIO;
|
|
goto exit;
|
|
@@ -2215,7 +2228,7 @@ _hisi_sas_internal_task_abort(struct hisi_hba *hisi_hba,
|
|
static int
|
|
hisi_sas_internal_task_abort(struct hisi_hba *hisi_hba,
|
|
struct domain_device *device,
|
|
- int abort_flag, int tag)
|
|
+ int abort_flag, int tag, bool rst_to_recover)
|
|
{
|
|
struct hisi_sas_slot *slot;
|
|
struct device *dev = hisi_hba->dev;
|
|
@@ -2227,7 +2240,8 @@ hisi_sas_internal_task_abort(struct hisi_hba *hisi_hba,
|
|
slot = &hisi_hba->slot_info[tag];
|
|
dq = &hisi_hba->dq[slot->dlvry_queue];
|
|
return _hisi_sas_internal_task_abort(hisi_hba, device,
|
|
- abort_flag, tag, dq);
|
|
+ abort_flag, tag, dq,
|
|
+ rst_to_recover);
|
|
case HISI_SAS_INT_ABT_DEV:
|
|
for (i = 0; i < hisi_hba->nvecs; i++) {
|
|
struct hisi_sas_cq *cq = &hisi_hba->cq[i];
|
|
@@ -2245,7 +2259,8 @@ hisi_sas_internal_task_abort(struct hisi_hba *hisi_hba,
|
|
continue;
|
|
dq = &hisi_hba->dq[i];
|
|
rc = _hisi_sas_internal_task_abort(hisi_hba, device,
|
|
- abort_flag, tag, dq);
|
|
+ abort_flag, tag,
|
|
+ dq, rst_to_recover);
|
|
if (rc)
|
|
return rc;
|
|
}
|
|
--
|
|
2.27.0
|
|
|