提交 64d37f3f 编写于 作者: X Xingui Yang 提交者: Yongqiang Liu

scsi: hisi_sas: Release resource directly in hisi_sas_abort_task() when NCQ error

driver inclusion
category: bugfix
bugzilla: https://gitee.com/openeuler/kernel/issues/I5SXSB
CVE: NA

------------------------------------------------

When the port is detached, EH will clear ATA_EH_RESET in ehc->i.action when
call ata_eh_reset(), and device reset won't be executed.

As the disk won't return other I/Os normally after NCQ Error. In addition,
the abort operation is added, then resource release is safe, so release NCQ
command lldd resource directly in hisi_sas_abort_task() when NCQ error
without soft reset to make sure read log command can be executed success
later. But Soft reset still need to be used in other scenario.
Signed-off-by: NXingui Yang <yangxingui@huawei.com>
Reviewed-by: Nkang fenglong <kangfenglong@huawei.com>
Signed-off-by: NYongqiang Liu <liuyongqiang13@huawei.com>
上级 f32bc74e
...@@ -101,6 +101,7 @@ enum { ...@@ -101,6 +101,7 @@ enum {
enum dev_status { enum dev_status {
HISI_SAS_DEV_INIT, HISI_SAS_DEV_INIT,
HISI_SAS_DEV_NORMAL, HISI_SAS_DEV_NORMAL,
HISI_SAS_DEV_NCQ_ERR,
}; };
enum { enum {
......
...@@ -1673,7 +1673,7 @@ static int hisi_sas_abort_task(struct sas_task *task) ...@@ -1673,7 +1673,7 @@ static int hisi_sas_abort_task(struct sas_task *task)
task->task_state_flags |= SAS_TASK_STATE_ABORTED; task->task_state_flags |= SAS_TASK_STATE_ABORTED;
spin_unlock_irqrestore(&task->task_state_lock, flags); spin_unlock_irqrestore(&task->task_state_lock, flags);
if (task->lldd_task && task->task_proto & SAS_PROTOCOL_SSP) { if (slot && task->task_proto & SAS_PROTOCOL_SSP) {
struct scsi_cmnd *cmnd = task->uldd_task; struct scsi_cmnd *cmnd = task->uldd_task;
u32 tag = slot->idx; u32 tag = slot->idx;
int rc2; int rc2;
...@@ -1706,8 +1706,7 @@ static int hisi_sas_abort_task(struct sas_task *task) ...@@ -1706,8 +1706,7 @@ static int hisi_sas_abort_task(struct sas_task *task)
} else if (task->task_proto & SAS_PROTOCOL_SATA || } else if (task->task_proto & SAS_PROTOCOL_SATA ||
task->task_proto & SAS_PROTOCOL_STP) { task->task_proto & SAS_PROTOCOL_STP) {
if (task->dev->dev_type == SAS_SATA_DEV) { if (task->dev->dev_type == SAS_SATA_DEV) {
struct ata_port *ap = device->sata_dev.ap; struct ata_queued_cmd *qc = task->uldd_task;
struct ata_link *link = &ap->link;
rc = hisi_sas_internal_task_abort(hisi_hba, device, rc = hisi_sas_internal_task_abort(hisi_hba, device,
HISI_SAS_INT_ABT_DEV, 0); HISI_SAS_INT_ABT_DEV, 0);
...@@ -1717,14 +1716,19 @@ static int hisi_sas_abort_task(struct sas_task *task) ...@@ -1717,14 +1716,19 @@ static int hisi_sas_abort_task(struct sas_task *task)
} }
hisi_sas_dereg_device(hisi_hba, device); hisi_sas_dereg_device(hisi_hba, device);
if (link->eh_info.action & ATA_EH_RESET) { /*
slot->task = NULL; * If an ATA internal command times out in ATA EH, it
* need to execute soft reset, so check the scsicmd
*/
if ((sas_dev->dev_status == HISI_SAS_DEV_NCQ_ERR) &&
qc && qc->scsicmd) {
hisi_sas_do_release_task(hisi_hba, task, slot);
rc = TMF_RESP_FUNC_COMPLETE; rc = TMF_RESP_FUNC_COMPLETE;
} else { } else {
rc = hisi_sas_softreset_ata_disk(device); rc = hisi_sas_softreset_ata_disk(device);
} }
} }
} else if (task->lldd_task && task->task_proto & SAS_PROTOCOL_SMP) { } else if (slot && task->task_proto & SAS_PROTOCOL_SMP) {
/* SMP */ /* SMP */
u32 tag = slot->idx; u32 tag = slot->idx;
struct hisi_sas_cq *cq = &hisi_hba->cq[slot->dlvry_queue]; struct hisi_sas_cq *cq = &hisi_hba->cq[slot->dlvry_queue];
...@@ -1843,8 +1847,12 @@ static int hisi_sas_I_T_nexus_reset(struct domain_device *device) ...@@ -1843,8 +1847,12 @@ static int hisi_sas_I_T_nexus_reset(struct domain_device *device)
{ {
struct hisi_hba *hisi_hba = dev_to_hisi_hba(device); struct hisi_hba *hisi_hba = dev_to_hisi_hba(device);
struct device *dev = hisi_hba->dev; struct device *dev = hisi_hba->dev;
struct hisi_sas_device *sas_dev = device->lldd_dev;
int rc; int rc;
if (sas_dev->dev_status == HISI_SAS_DEV_NCQ_ERR)
sas_dev->dev_status = HISI_SAS_DEV_NORMAL;
rc = hisi_sas_internal_task_abort(hisi_hba, device, rc = hisi_sas_internal_task_abort(hisi_hba, device,
HISI_SAS_INT_ABT_DEV, 0); HISI_SAS_INT_ABT_DEV, 0);
if (rc < 0) { if (rc < 0) {
......
...@@ -398,6 +398,8 @@ ...@@ -398,6 +398,8 @@
#define CMPLT_HDR_CMPLT_MSK (0x3 << CMPLT_HDR_CMPLT_OFF) #define CMPLT_HDR_CMPLT_MSK (0x3 << CMPLT_HDR_CMPLT_OFF)
#define CMPLT_HDR_ERROR_PHASE_OFF 2 #define CMPLT_HDR_ERROR_PHASE_OFF 2
#define CMPLT_HDR_ERROR_PHASE_MSK (0xff << CMPLT_HDR_ERROR_PHASE_OFF) #define CMPLT_HDR_ERROR_PHASE_MSK (0xff << CMPLT_HDR_ERROR_PHASE_OFF)
/* bit[9:2] Error Phase */
#define ERR_PHASE_RESPONSE_FRAME_REV_STAGE BIT(8)
#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_OFF 11
...@@ -423,6 +425,10 @@ ...@@ -423,6 +425,10 @@
#define CMPLT_HDR_SATA_DISK_ERR_MSK (0x1 << COMLT_HDR_SATA_DISK_ERR_OFF) #define CMPLT_HDR_SATA_DISK_ERR_MSK (0x1 << COMLT_HDR_SATA_DISK_ERR_OFF)
#define CMPLT_HDR_IO_IN_TARGET_OFF 17 #define CMPLT_HDR_IO_IN_TARGET_OFF 17
#define CMPLT_HDR_IO_IN_TARGET_MSK (0x1 << CMPLT_HDR_IO_IN_TARGET_OFF) #define CMPLT_HDR_IO_IN_TARGET_MSK (0x1 << CMPLT_HDR_IO_IN_TARGET_OFF)
/* bit[23:18] ERR_FIS_ATA_STATUS */
#define FIS_ATA_STATUS_ERR BIT(18)
/* bit[31:24] ERR_FIS_TYPE */
#define FIS_TYPE_SDB BIT(31)
/* ITCT header */ /* ITCT header */
/* qw0 */ /* qw0 */
...@@ -2247,6 +2253,18 @@ static void hisi_sas_set_sense_data(struct sas_task *task, ...@@ -2247,6 +2253,18 @@ static void hisi_sas_set_sense_data(struct sas_task *task,
} }
} }
static bool is_ncq_err(struct hisi_sas_complete_v3_hdr *complete_hdr)
{
u32 dw0, dw3;
dw0 = le32_to_cpu(complete_hdr->dw0);
dw3 = le32_to_cpu(complete_hdr->dw3);
return (dw0 & ERR_PHASE_RESPONSE_FRAME_REV_STAGE) &&
(dw3 & FIS_TYPE_SDB) &&
(dw3 & FIS_ATA_STATUS_ERR);
}
static void static void
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)
...@@ -2582,6 +2600,10 @@ static void cq_tasklet_v3_hw(unsigned long val) ...@@ -2582,6 +2600,10 @@ static void cq_tasklet_v3_hw(unsigned long val)
dev_err(dev, "erroneous completion disk err dev id=%d sas_addr=0x%llx CQ hdr: 0x%x 0x%x 0x%x 0x%x\n", dev_err(dev, "erroneous completion disk err dev id=%d sas_addr=0x%llx CQ hdr: 0x%x 0x%x 0x%x 0x%x\n",
device_id, itct->sas_addr, dw0, dw1, device_id, itct->sas_addr, dw0, dw1,
complete_hdr->act, dw3); complete_hdr->act, dw3);
if (is_ncq_err(complete_hdr))
sas_dev->dev_status = HISI_SAS_DEV_NCQ_ERR;
link->eh_info.err_mask |= AC_ERR_DEV; link->eh_info.err_mask |= AC_ERR_DEV;
link->eh_info.action |= ATA_EH_RESET; link->eh_info.action |= ATA_EH_RESET;
ata_link_abort(link); ata_link_abort(link);
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册