From: yangxingui yangxingui@huawei.com
driver inclusion category: bugfix bugzilla: NA CVE: NA
--------------------------- In the data underflow scenario, if correct sense data and response frame have been written to the host memory and the CQ RSPNS_GOOD bit is 0, then driver sends the sense data to the upper layer.
Signed-off-by: yangxingui yangxingui@huawei.com Reviewed-by: Xiang Chen chenxiang66@hisilicon.com Signed-off-by: Yang Yingliang yangyingliang@huawei.com --- drivers/scsi/hisi_sas/hisi_sas.h | 8 +++++-- drivers/scsi/hisi_sas/hisi_sas_main.c | 17 ------------- drivers/scsi/hisi_sas/hisi_sas_v3_hw.c | 33 ++++++++++++++++++++++---- 3 files changed, 34 insertions(+), 24 deletions(-)
diff --git a/drivers/scsi/hisi_sas/hisi_sas.h b/drivers/scsi/hisi_sas/hisi_sas.h index 193fc960d87fd..742ffcaeaa95c 100644 --- a/drivers/scsi/hisi_sas/hisi_sas.h +++ b/drivers/scsi/hisi_sas/hisi_sas.h @@ -102,6 +102,12 @@ enum hisi_sas_dev_type { HISI_SAS_DEV_TYPE_SATA, };
+enum datapres_field { + NO_DATA = 0, + RESPONSE_DATA = 1, + SENSE_DATA = 2, +}; + struct hisi_sas_hw_error { u32 irq_msk; u32 msk; @@ -571,8 +577,6 @@ extern void hisi_sas_free(struct hisi_hba *hisi_hba); extern u8 hisi_sas_get_ata_protocol(struct host_to_dev_fis *fis, int direction); extern struct hisi_sas_port *to_hisi_sas_port(struct asd_sas_port *sas_port); -extern void hisi_sas_set_sense_data(struct sas_task *task, - struct hisi_sas_slot *slot); extern void hisi_sas_sata_done(struct sas_task *task, struct hisi_sas_slot *slot); extern int hisi_sas_get_fw_info(struct hisi_hba *hisi_hba); diff --git a/drivers/scsi/hisi_sas/hisi_sas_main.c b/drivers/scsi/hisi_sas/hisi_sas_main.c index ea08d53c11495..67befcc033126 100644 --- a/drivers/scsi/hisi_sas/hisi_sas_main.c +++ b/drivers/scsi/hisi_sas/hisi_sas_main.c @@ -105,23 +105,6 @@ u8 hisi_sas_get_ata_protocol(struct host_to_dev_fis *fis, int direction) } EXPORT_SYMBOL_GPL(hisi_sas_get_ata_protocol);
-void hisi_sas_set_sense_data(struct sas_task *task, - struct hisi_sas_slot *slot) -{ - struct ssp_response_iu *iu = - hisi_sas_status_buf_addr_mem(slot) + - sizeof(struct hisi_sas_err_record); - if (iu->datapres == 2) { - struct task_status_struct *ts = &task->task_status; - - ts->buf_valid_size = - min_t(int, SAS_STATUS_BUF_SIZE, - be32_to_cpu(iu->sense_data_len)); - memcpy(ts->buf, iu->sense_data, ts->buf_valid_size); - } -} -EXPORT_SYMBOL_GPL(hisi_sas_set_sense_data); - void hisi_sas_sata_done(struct sas_task *task, struct hisi_sas_slot *slot) { diff --git a/drivers/scsi/hisi_sas/hisi_sas_v3_hw.c b/drivers/scsi/hisi_sas/hisi_sas_v3_hw.c index 06b4f2db62f7b..9ce1177a8e455 100644 --- a/drivers/scsi/hisi_sas/hisi_sas_v3_hw.c +++ b/drivers/scsi/hisi_sas/hisi_sas_v3_hw.c @@ -395,6 +395,8 @@ #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 @@ -2208,6 +2210,24 @@ static irqreturn_t fatal_axi_int_v3_hw(int irq_no, void *p) return IRQ_HANDLED; }
+static void hisi_sas_set_sense_data(struct sas_task *task, + struct hisi_sas_slot *slot) +{ + struct ssp_response_iu *iu = + hisi_sas_status_buf_addr_mem(slot) + + sizeof(struct hisi_sas_err_record); + if ((iu->status == SAM_STAT_CHECK_CONDITION) && + (iu->datapres == SENSE_DATA)) { + struct task_status_struct *ts = &task->task_status; + + ts->buf_valid_size = + min_t(int, SAS_STATUS_BUF_SIZE, + be32_to_cpu(iu->sense_data_len)); + memcpy(ts->buf, iu->sense_data, ts->buf_valid_size); + ts->stat = SAM_STAT_CHECK_CONDITION; + } +} + static void slot_err_v3_hw(struct hisi_hba *hisi_hba, struct sas_task *task, struct hisi_sas_slot *slot) @@ -2224,17 +2244,20 @@ slot_err_v3_hw(struct hisi_hba *hisi_hba, struct sas_task *task,
switch (task->task_proto) { case SAS_PROTOCOL_SSP: - if (complete_hdr->dw3 & CMPLT_HDR_IO_IN_TARGET_MSK) { - ts->stat = SAS_QUEUE_FULL; - slot->abort = 1; - } else if (dma_rx_err_type & RX_DATA_LEN_UNDERFLOW_MSK) { + if (dma_rx_err_type & RX_DATA_LEN_UNDERFLOW_MSK) { ts->residual = trans_tx_fail_type; ts->stat = SAS_DATA_UNDERRUN; + if ((!(complete_hdr->dw0 & CMPLT_HDR_RSPNS_GOOD_MSK)) && + (complete_hdr->dw0 & CMPLT_HDR_RSPNS_XFRD_MSK)) { + hisi_sas_set_sense_data(task, slot); + } + } else if (complete_hdr->dw3 & CMPLT_HDR_IO_IN_TARGET_MSK) { + ts->stat = SAS_QUEUE_FULL; + slot->abort = 1; } else { ts->stat = SAS_OPEN_REJECT; ts->open_rej_reason = SAS_OREJ_RSVD_RETRY; } - hisi_sas_set_sense_data(task, slot); break; case SAS_PROTOCOL_SATA: case SAS_PROTOCOL_STP: