From 44112922674b94a7d699dfff6307fc830018df7c Mon Sep 17 00:00:00 2001 From: John Garry Date: Mon, 17 Oct 2022 17:20:28 +0800 Subject: scsi: libsas: Add sas_ata_device_link_abort() Similar to how AHCI handles NCQ errors in ahci_error_intr() -> ata_port_abort() -> ata_do_link_abort(), add an NCQ error handler for LLDDs to call to initiate a link abort. This will mark all outstanding QCs as failed and kick-off EH. Note: A "force reset" argument is added for drivers which require the ATA error handling to always reset the device. A driver may require this feature for when SATA device per-SCSI cmnd resources are only released during reset for ATA EH. As such, we need an option to force reset to be done, regardless of what any EH autopsy decides. The SATA device FIS fields are set to indicate a device error from ata_eh_analyze_tf(). Suggested-by: Damien Le Moal Suggested-by: Niklas Cassel Signed-off-by: John Garry Link: https://lore.kernel.org/r/1665998435-199946-2-git-send-email-john.garry@huawei.com Tested-by: Damien Le Moal Tested-by: Niklas Cassel # pm80xx Reviewed-by: Jason Yan Signed-off-by: Martin K. Petersen --- drivers/scsi/libsas/sas_ata.c | 15 +++++++++++++++ include/scsi/sas_ata.h | 6 ++++++ 2 files changed, 21 insertions(+) diff --git a/drivers/scsi/libsas/sas_ata.c b/drivers/scsi/libsas/sas_ata.c index d35c9296f738..61f64d54e67d 100644 --- a/drivers/scsi/libsas/sas_ata.c +++ b/drivers/scsi/libsas/sas_ata.c @@ -861,6 +861,21 @@ void sas_ata_wait_eh(struct domain_device *dev) ata_port_wait_eh(ap); } +void sas_ata_device_link_abort(struct domain_device *device, bool force_reset) +{ + struct ata_port *ap = device->sata_dev.ap; + struct ata_link *link = &ap->link; + + device->sata_dev.fis[2] = ATA_ERR | ATA_DRDY; /* tf status */ + device->sata_dev.fis[3] = ATA_ABORTED; /* tf error */ + + link->eh_info.err_mask |= AC_ERR_DEV; + if (force_reset) + link->eh_info.action |= ATA_EH_RESET; + ata_link_abort(link); +} +EXPORT_SYMBOL_GPL(sas_ata_device_link_abort); + int sas_execute_ata_cmd(struct domain_device *device, u8 *fis, int force_phy_id) { struct sas_tmf_task tmf_task = {}; diff --git a/include/scsi/sas_ata.h b/include/scsi/sas_ata.h index a1df4f9d57a3..e47f0aec0722 100644 --- a/include/scsi/sas_ata.h +++ b/include/scsi/sas_ata.h @@ -32,6 +32,7 @@ void sas_probe_sata(struct asd_sas_port *port); void sas_suspend_sata(struct asd_sas_port *port); void sas_resume_sata(struct asd_sas_port *port); void sas_ata_end_eh(struct ata_port *ap); +void sas_ata_device_link_abort(struct domain_device *dev, bool force_reset); int sas_execute_ata_cmd(struct domain_device *device, u8 *fis, int force_phy_id); int sas_ata_wait_after_reset(struct domain_device *dev, unsigned long deadline); @@ -87,6 +88,11 @@ static inline void sas_ata_end_eh(struct ata_port *ap) { } +static inline void sas_ata_device_link_abort(struct domain_device *dev, + bool force_reset) +{ +} + static inline int sas_execute_ata_cmd(struct domain_device *device, u8 *fis, int force_phy_id) { -- cgit v1.2.3 From 4b329abc91800d23941ac773e69b322a13981ecb Mon Sep 17 00:00:00 2001 From: Xingui Yang Date: Mon, 17 Oct 2022 17:20:29 +0800 Subject: scsi: hisi_sas: Move slot variable definition in hisi_sas_abort_task() Each branch currently defines a slot variable independently, and it is neater to move it to the function head. Signed-off-by: Xingui Yang Signed-off-by: John Garry Link: https://lore.kernel.org/r/1665998435-199946-3-git-send-email-john.garry@huawei.com Signed-off-by: Martin K. Petersen --- drivers/scsi/hisi_sas/hisi_sas_main.c | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/drivers/scsi/hisi_sas/hisi_sas_main.c b/drivers/scsi/hisi_sas/hisi_sas_main.c index 699b07abb6b0..8303aa5eaf25 100644 --- a/drivers/scsi/hisi_sas/hisi_sas_main.c +++ b/drivers/scsi/hisi_sas/hisi_sas_main.c @@ -1547,6 +1547,7 @@ static int hisi_sas_abort_task(struct sas_task *task) struct hisi_sas_internal_abort_data internal_abort_data = { false }; struct domain_device *device = task->dev; struct hisi_sas_device *sas_dev = device->lldd_dev; + struct hisi_sas_slot *slot = task->lldd_task; struct hisi_hba *hisi_hba; struct device *dev; int rc = TMF_RESP_FUNC_FAILED; @@ -1560,7 +1561,6 @@ static int hisi_sas_abort_task(struct sas_task *task) spin_lock_irqsave(&task->task_state_lock, flags); if (task->task_state_flags & SAS_TASK_STATE_DONE) { - struct hisi_sas_slot *slot = task->lldd_task; struct hisi_sas_cq *cq; if (slot) { @@ -1578,8 +1578,7 @@ static int hisi_sas_abort_task(struct sas_task *task) task->task_state_flags |= SAS_TASK_STATE_ABORTED; spin_unlock_irqrestore(&task->task_state_lock, flags); - if (task->lldd_task && task->task_proto & SAS_PROTOCOL_SSP) { - struct hisi_sas_slot *slot = task->lldd_task; + if (slot && task->task_proto & SAS_PROTOCOL_SSP) { u16 tag = slot->idx; int rc2; @@ -1613,9 +1612,8 @@ static int hisi_sas_abort_task(struct sas_task *task) hisi_sas_dereg_device(hisi_hba, 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 */ - struct hisi_sas_slot *slot = task->lldd_task; u32 tag = slot->idx; struct hisi_sas_cq *cq = &hisi_hba->cq[slot->dlvry_queue]; -- cgit v1.2.3 From 930d97dabdd56681aef752a35475f0212a171741 Mon Sep 17 00:00:00 2001 From: Xingui Yang Date: Mon, 17 Oct 2022 17:20:30 +0800 Subject: scsi: hisi_sas: Add SATA_DISK_ERR bit handling for v3 hw When CQ header dw3 SATA_DISK_ERR is set it means this SATA disk is in error state and the current IPTT is invalid. An invalid IPTT does not correspond to any slot. In this scenario, new I/Os that delivered to disk will be rejected by the controller and all I/Os remaining in the disk should be aborted, which we add here with the sas_ata_device_link_abort() call. In hisi_sas_abort_task() we don't want to issue a soft reset as it may cause info to be lost in the target disk for the ATA EH autopsy. In this case, just release resources - the disk won't return other I/Os normally after NCQ Error, so this is safe. Signed-off-by: Xingui Yang Signed-off-by: John Garry Link: https://lore.kernel.org/r/1665998435-199946-4-git-send-email-john.garry@huawei.com Signed-off-by: Martin K. Petersen --- drivers/scsi/hisi_sas/hisi_sas.h | 1 + drivers/scsi/hisi_sas/hisi_sas_main.c | 18 ++++++++++++- drivers/scsi/hisi_sas/hisi_sas_v3_hw.c | 48 ++++++++++++++++++++++++++++++++-- 3 files changed, 64 insertions(+), 3 deletions(-) diff --git a/drivers/scsi/hisi_sas/hisi_sas.h b/drivers/scsi/hisi_sas/hisi_sas.h index 9aebf4a26b13..6f8a52a1b808 100644 --- a/drivers/scsi/hisi_sas/hisi_sas.h +++ b/drivers/scsi/hisi_sas/hisi_sas.h @@ -104,6 +104,7 @@ enum { enum dev_status { HISI_SAS_DEV_INIT, HISI_SAS_DEV_NORMAL, + HISI_SAS_DEV_NCQ_ERR, }; enum { diff --git a/drivers/scsi/hisi_sas/hisi_sas_main.c b/drivers/scsi/hisi_sas/hisi_sas_main.c index 8303aa5eaf25..4c37ae9eb6b6 100644 --- a/drivers/scsi/hisi_sas/hisi_sas_main.c +++ b/drivers/scsi/hisi_sas/hisi_sas_main.c @@ -1604,13 +1604,26 @@ static int hisi_sas_abort_task(struct sas_task *task) } else if (task->task_proto & SAS_PROTOCOL_SATA || task->task_proto & SAS_PROTOCOL_STP) { if (task->dev->dev_type == SAS_SATA_DEV) { + struct ata_queued_cmd *qc = task->uldd_task; + rc = hisi_sas_internal_task_abort_dev(sas_dev, false); if (rc < 0) { dev_err(dev, "abort task: internal abort failed\n"); goto out; } hisi_sas_dereg_device(hisi_hba, device); - rc = hisi_sas_softreset_ata_disk(device); + + /* + * 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; + } else { + rc = hisi_sas_softreset_ata_disk(device); + } } } else if (slot && task->task_proto & SAS_PROTOCOL_SMP) { /* SMP */ @@ -1727,6 +1740,9 @@ static int hisi_sas_I_T_nexus_reset(struct domain_device *device) struct device *dev = hisi_hba->dev; 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_dev(sas_dev, false); if (rc < 0) { dev_err(dev, "I_T nexus reset: internal abort (%d)\n", rc); diff --git a/drivers/scsi/hisi_sas/hisi_sas_v3_hw.c b/drivers/scsi/hisi_sas/hisi_sas_v3_hw.c index d56b4bfd2767..0ae8a60aaf93 100644 --- a/drivers/scsi/hisi_sas/hisi_sas_v3_hw.c +++ b/drivers/scsi/hisi_sas/hisi_sas_v3_hw.c @@ -404,6 +404,11 @@ #define CMPLT_HDR_CMPLT_MSK (0x3 << CMPLT_HDR_CMPLT_OFF) #define CMPLT_HDR_ERROR_PHASE_OFF 2 #define CMPLT_HDR_ERROR_PHASE_MSK (0xff << CMPLT_HDR_ERROR_PHASE_OFF) +/* bit[9:2] Error Phase */ +#define ERR_PHASE_RESPONSE_FRAME_REV_STAGE_OFF \ + 8 +#define ERR_PHASE_RESPONSE_FRAME_REV_STAGE_MSK \ + (0x1 << ERR_PHASE_RESPONSE_FRAME_REV_STAGE_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 @@ -423,8 +428,15 @@ #define CMPLT_HDR_DEV_ID_OFF 16 #define CMPLT_HDR_DEV_ID_MSK (0xffff << CMPLT_HDR_DEV_ID_OFF) /* dw3 */ +#define CMPLT_HDR_SATA_DISK_ERR_OFF 16 +#define CMPLT_HDR_SATA_DISK_ERR_MSK (0x1 << CMPLT_HDR_SATA_DISK_ERR_OFF) #define CMPLT_HDR_IO_IN_TARGET_OFF 17 #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_OFF 18 +#define FIS_ATA_STATUS_ERR_MSK (0x1 << FIS_ATA_STATUS_ERR_OFF) +#define FIS_TYPE_SDB_OFF 31 +#define FIS_TYPE_SDB_MSK (0x1 << FIS_TYPE_SDB_OFF) /* ITCT header */ /* qw0 */ @@ -2148,6 +2160,18 @@ static irqreturn_t fatal_axi_int_v3_hw(int irq_no, void *p) return IRQ_HANDLED; } +static bool is_ncq_err_v3_hw(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_MSK) && + (dw3 & FIS_TYPE_SDB_MSK) && + (dw3 & FIS_ATA_STATUS_ERR_MSK); +} + static bool slot_err_v3_hw(struct hisi_hba *hisi_hba, struct sas_task *task, struct hisi_sas_slot *slot) @@ -2381,14 +2405,34 @@ static irqreturn_t cq_thread_v3_hw(int irq_no, void *p) while (rd_point != wr_point) { struct hisi_sas_complete_v3_hdr *complete_hdr; struct device *dev = hisi_hba->dev; - u32 dw1; + u32 dw0, dw1, dw3; int iptt; complete_hdr = &complete_queue[rd_point]; + dw0 = le32_to_cpu(complete_hdr->dw0); dw1 = le32_to_cpu(complete_hdr->dw1); + dw3 = le32_to_cpu(complete_hdr->dw3); iptt = dw1 & CMPLT_HDR_IPTT_MSK; - if (likely(iptt < HISI_SAS_COMMAND_ENTRIES_V3_HW)) { + if (unlikely((dw0 & CMPLT_HDR_CMPLT_MSK) == 0x3) && + (dw3 & CMPLT_HDR_SATA_DISK_ERR_MSK)) { + int device_id = (dw1 & CMPLT_HDR_DEV_ID_MSK) >> + CMPLT_HDR_DEV_ID_OFF; + struct hisi_sas_itct *itct = + &hisi_hba->itct[device_id]; + struct hisi_sas_device *sas_dev = + &hisi_hba->devices[device_id]; + struct domain_device *device = sas_dev->sas_device; + + 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, + complete_hdr->act, dw3); + + if (is_ncq_err_v3_hw(complete_hdr)) + sas_dev->dev_status = HISI_SAS_DEV_NCQ_ERR; + + sas_ata_device_link_abort(device, true); + } else if (likely(iptt < HISI_SAS_COMMAND_ENTRIES_V3_HW)) { slot = &hisi_hba->slot_info[iptt]; slot->cmplt_queue_slot = rd_point; slot->cmplt_queue = queue; -- cgit v1.2.3 From 4ef4f1a6155571d3d53583a4e8e7ccbbec220b8a Mon Sep 17 00:00:00 2001 From: Xingui Yang Date: Mon, 17 Oct 2022 17:20:31 +0800 Subject: scsi: hisi_sas: Modify v3 HW SATA disk error state completion processing When an NCQ error occurs, the controller will abnormally complete the I/Os that are newly delivered to disk, and bit8 in CQ dw3 will be set which indicates that the SATA disk is in error state. The current processing flow is to set ts->stat to SAS_OPEN_REJECT and then sas_ata_task_done() will set FIS stat to ATA_ERR. After analyzing the I/O by ata_eh_analyze_tf(), err_mask will set to AC_ERR_HSM. If media error occurs for four times within 10 minutes and the chip rejects new I/Os for four times, NCQ will be disabled due to excessive errors, which is undesirable. Therefore, use sas_task_abort() to handle abnormally completed I/Os when SATA disk is in error state, as these abnormally completed I/Os are already processed by sas_ata_device_link_abort() and qc->flag are set to ATA_QCFLAG_FAILED. If sas_task_abort() is used, qc->err_mask will not be modified in EH. Unlike the current process flow, it will not increase the count of ECAT_TOUT_HSM and not turn off NCQ. Like other I/Os on the disk that do not have an error but do not return after the NCQ error, they are retried after the EH. Signed-off-by: Xingui Yang Signed-off-by: John Garry Link: https://lore.kernel.org/r/1665998435-199946-5-git-send-email-john.garry@huawei.com Signed-off-by: Martin K. Petersen --- drivers/scsi/hisi_sas/hisi_sas_v3_hw.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/drivers/scsi/hisi_sas/hisi_sas_v3_hw.c b/drivers/scsi/hisi_sas/hisi_sas_v3_hw.c index 0ae8a60aaf93..0c3fcb807806 100644 --- a/drivers/scsi/hisi_sas/hisi_sas_v3_hw.c +++ b/drivers/scsi/hisi_sas/hisi_sas_v3_hw.c @@ -428,6 +428,8 @@ #define CMPLT_HDR_DEV_ID_OFF 16 #define CMPLT_HDR_DEV_ID_MSK (0xffff << CMPLT_HDR_DEV_ID_OFF) /* dw3 */ +#define SATA_DISK_IN_ERROR_STATUS_OFF 8 +#define SATA_DISK_IN_ERROR_STATUS_MSK (0x1 << SATA_DISK_IN_ERROR_STATUS_OFF) #define CMPLT_HDR_SATA_DISK_ERR_OFF 16 #define CMPLT_HDR_SATA_DISK_ERR_MSK (0x1 << CMPLT_HDR_SATA_DISK_ERR_OFF) #define CMPLT_HDR_IO_IN_TARGET_OFF 17 @@ -2219,7 +2221,8 @@ slot_err_v3_hw(struct hisi_hba *hisi_hba, struct sas_task *task, } else if (dma_rx_err_type & RX_DATA_LEN_UNDERFLOW_MSK) { ts->residual = trans_tx_fail_type; ts->stat = SAS_DATA_UNDERRUN; - } else if (dw3 & CMPLT_HDR_IO_IN_TARGET_MSK) { + } else if ((dw3 & CMPLT_HDR_IO_IN_TARGET_MSK) || + (dw3 & SATA_DISK_IN_ERROR_STATUS_MSK)) { ts->stat = SAS_PHY_DOWN; slot->abort = 1; } else { -- cgit v1.2.3 From 0b639decf65160b1afd9993019be37d7869c0340 Mon Sep 17 00:00:00 2001 From: John Garry Date: Mon, 17 Oct 2022 17:20:32 +0800 Subject: scsi: pm8001: Modify task abort handling for SATA task When we try to abort a SATA task, the CCB of the task which we are trying to avoid may still complete. In this case, we should not touch the task associated with that CCB as we can race with libsas freeing the last later in sas_eh_handle_sas_errors() -> sas_eh_finish_cmd() for when TASK_IS_ABORTED is returned from sas_scsi_find_task() Signed-off-by: John Garry Link: https://lore.kernel.org/r/1665998435-199946-6-git-send-email-john.garry@huawei.com Tested-by: Damien Le Moal Tested-by: Niklas Cassel # pm80xx Acked-by: Jack Wang Signed-off-by: Martin K. Petersen --- drivers/scsi/pm8001/pm8001_hwi.c | 15 +++++++++++++-- drivers/scsi/pm8001/pm8001_sas.c | 8 ++++++++ drivers/scsi/pm8001/pm80xx_hwi.c | 14 ++++++++++---- 3 files changed, 31 insertions(+), 6 deletions(-) diff --git a/drivers/scsi/pm8001/pm8001_hwi.c b/drivers/scsi/pm8001/pm8001_hwi.c index 628b08ba6770..c0adc3a9d196 100644 --- a/drivers/scsi/pm8001/pm8001_hwi.c +++ b/drivers/scsi/pm8001/pm8001_hwi.c @@ -2295,7 +2295,9 @@ mpi_sata_completion(struct pm8001_hba_info *pm8001_ha, void *piomb) if (t->dev && (t->dev->lldd_dev)) pm8001_dev = t->dev->lldd_dev; } else { - pm8001_dbg(pm8001_ha, FAIL, "task null\n"); + pm8001_dbg(pm8001_ha, FAIL, "task null, freeing CCB tag %d\n", + ccb->ccb_tag); + pm8001_ccb_free(pm8001_ha, ccb); return; } @@ -2675,8 +2677,17 @@ static void mpi_sata_event(struct pm8001_hba_info *pm8001_ha, void *piomb) pm8001_dev = ccb->device; if (event) pm8001_dbg(pm8001_ha, FAIL, "sata IO status 0x%x\n", event); - if (unlikely(!t || !t->lldd_task || !t->dev)) + + if (unlikely(!t)) { + pm8001_dbg(pm8001_ha, FAIL, "task null, freeing CCB tag %d\n", + ccb->ccb_tag); + pm8001_ccb_free(pm8001_ha, ccb); return; + } + + if (unlikely(!t->lldd_task || !t->dev)) + return; + ts = &t->task_status; pm8001_dbg(pm8001_ha, DEVIO, "port_id:0x%x, device_id:0x%x, tag:0x%x, event:0x%x\n", diff --git a/drivers/scsi/pm8001/pm8001_sas.c b/drivers/scsi/pm8001/pm8001_sas.c index 8e3f2f9ddaac..d5ec29f69be3 100644 --- a/drivers/scsi/pm8001/pm8001_sas.c +++ b/drivers/scsi/pm8001/pm8001_sas.c @@ -983,6 +983,7 @@ int pm8001_query_task(struct sas_task *task) /* mandatory SAM-3, still need free task/ccb info, abort the specified task */ int pm8001_abort_task(struct sas_task *task) { + struct pm8001_ccb_info *ccb = task->lldd_task; unsigned long flags; u32 tag; struct domain_device *dev ; @@ -1113,6 +1114,13 @@ int pm8001_abort_task(struct sas_task *task) pm8001_dev, DS_OPERATIONAL); wait_for_completion(&completion); } else { + /* + * Ensure that if we see a completion for the ccb + * associated with the task which we are trying to + * abort then we should not touch the sas_task as it + * may race with libsas freeing it when return here. + */ + ccb->task = NULL; ret = sas_execute_internal_abort_single(dev, tag, 0, NULL); } rc = TMF_RESP_FUNC_COMPLETE; diff --git a/drivers/scsi/pm8001/pm80xx_hwi.c b/drivers/scsi/pm8001/pm80xx_hwi.c index f8b8624458f7..dd0e06983cd3 100644 --- a/drivers/scsi/pm8001/pm80xx_hwi.c +++ b/drivers/scsi/pm8001/pm80xx_hwi.c @@ -2396,7 +2396,9 @@ mpi_sata_completion(struct pm8001_hba_info *pm8001_ha, if (t->dev && (t->dev->lldd_dev)) pm8001_dev = t->dev->lldd_dev; } else { - pm8001_dbg(pm8001_ha, FAIL, "task null\n"); + pm8001_dbg(pm8001_ha, FAIL, "task null, freeing CCB tag %d\n", + ccb->ccb_tag); + pm8001_ccb_free(pm8001_ha, ccb); return; } @@ -2813,12 +2815,16 @@ static void mpi_sata_event(struct pm8001_hba_info *pm8001_ha, ccb = &pm8001_ha->ccb_info[tag]; t = ccb->task; pm8001_dev = ccb->device; - - if (unlikely(!t || !t->lldd_task || !t->dev)) { - pm8001_dbg(pm8001_ha, FAIL, "task or dev null\n"); + if (unlikely(!t)) { + pm8001_dbg(pm8001_ha, FAIL, "task null, freeing CCB tag %d\n", + ccb->ccb_tag); + pm8001_ccb_free(pm8001_ha, ccb); return; } + if (unlikely(!t->lldd_task || !t->dev)) + return; + ts = &t->task_status; pm8001_dbg(pm8001_ha, IOERR, "port_id:0x%x, tag:0x%x, event:0x%x\n", port_id, tag, event); -- cgit v1.2.3 From 811be570a9a8df96b4fd43ff00837b947bbaf49b Mon Sep 17 00:00:00 2001 From: John Garry Date: Mon, 17 Oct 2022 17:20:33 +0800 Subject: scsi: pm8001: Use sas_ata_device_link_abort() to handle NCQ errors In commit c6b9ef5779c3 ("[SCSI] pm80xx: NCQ error handling changes") the driver had support added to handle NCQ errors but much of what is done in this handling is duplicated from the libata EH. In that named commit we handle in 2x main steps: a. Issue read log ext10 to examine and clear the errors b. Issue SATA_ABORT all command Indeed, in libata EH, we do similar to above: a. ata_do_eh() -> ata_eh_autopsy() -> ata_eh_link_autopsy() -> ata_eh_analyze_ncq_error() -> ata_eh_read_log_10h() b. ata_do_eh() -> ata_eh_recover() which will issue a device soft reset or hard reset Since there is so much duplication, use sas_ata_device_link_abort() which will abort all pending IOs and kick of ATA EH which will do the steps, above. However we will not follow the advisory to send the SATA_ABORT all command after the autopsy in read log ext10. Indeed, in libsas EH, we already send a per-task SATA_ABORT command, and this is prior to the ATA EH kicking in and issuing the read log ext10 in the recovery process. I judge that this is ok as the SATA_ABORT command does not actually send any protocol on the link to abort I/O on the other side, so would not change any state on the disk (for the read log ext10 command). Signed-off-by: John Garry Link: https://lore.kernel.org/r/1665998435-199946-7-git-send-email-john.garry@huawei.com Tested-by: Damien Le Moal Tested-by: Niklas Cassel # pm80xx Acked-by: Jack Wang Signed-off-by: Martin K. Petersen --- drivers/scsi/pm8001/pm8001_hwi.c | 171 +++------------------------------------ drivers/scsi/pm8001/pm8001_sas.c | 6 -- drivers/scsi/pm8001/pm8001_sas.h | 5 -- drivers/scsi/pm8001/pm80xx_hwi.c | 163 ++----------------------------------- 4 files changed, 19 insertions(+), 326 deletions(-) diff --git a/drivers/scsi/pm8001/pm8001_hwi.c b/drivers/scsi/pm8001/pm8001_hwi.c index c0adc3a9d196..ec1a9ab61814 100644 --- a/drivers/scsi/pm8001/pm8001_hwi.c +++ b/drivers/scsi/pm8001/pm8001_hwi.c @@ -1724,7 +1724,14 @@ void pm8001_work_fn(struct work_struct *work) pm8001_free_dev(pm8001_dev); } } - } break; + } + break; + case IO_XFER_ERROR_ABORTED_NCQ_MODE: + { + dev = pm8001_dev->sas_device; + sas_ata_device_link_abort(dev, false); + } + break; } kfree(pw); } @@ -1748,110 +1755,6 @@ int pm8001_handle_event(struct pm8001_hba_info *pm8001_ha, void *data, return ret; } -static void pm8001_send_abort_all(struct pm8001_hba_info *pm8001_ha, - struct pm8001_device *pm8001_ha_dev) -{ - struct pm8001_ccb_info *ccb; - struct sas_task *task; - struct task_abort_req task_abort; - u32 opc = OPC_INB_SATA_ABORT; - int ret; - - pm8001_ha_dev->id |= NCQ_ABORT_ALL_FLAG; - pm8001_ha_dev->id &= ~NCQ_READ_LOG_FLAG; - - task = sas_alloc_slow_task(GFP_ATOMIC); - if (!task) { - pm8001_dbg(pm8001_ha, FAIL, "cannot allocate task\n"); - return; - } - - task->task_done = pm8001_task_done; - - ccb = pm8001_ccb_alloc(pm8001_ha, pm8001_ha_dev, task); - if (!ccb) { - sas_free_task(task); - return; - } - - memset(&task_abort, 0, sizeof(task_abort)); - task_abort.abort_all = cpu_to_le32(1); - task_abort.device_id = cpu_to_le32(pm8001_ha_dev->device_id); - task_abort.tag = cpu_to_le32(ccb->ccb_tag); - - ret = pm8001_mpi_build_cmd(pm8001_ha, 0, opc, &task_abort, - sizeof(task_abort), 0); - if (ret) { - sas_free_task(task); - pm8001_ccb_free(pm8001_ha, ccb); - } -} - -static void pm8001_send_read_log(struct pm8001_hba_info *pm8001_ha, - struct pm8001_device *pm8001_ha_dev) -{ - struct sata_start_req sata_cmd; - int res; - struct pm8001_ccb_info *ccb; - struct sas_task *task = NULL; - struct host_to_dev_fis fis; - struct domain_device *dev; - u32 opc = OPC_INB_SATA_HOST_OPSTART; - - task = sas_alloc_slow_task(GFP_ATOMIC); - if (!task) { - pm8001_dbg(pm8001_ha, FAIL, "cannot allocate task !!!\n"); - return; - } - task->task_done = pm8001_task_done; - - /* - * Allocate domain device by ourselves as libsas is not going to - * provide any. - */ - dev = kzalloc(sizeof(struct domain_device), GFP_ATOMIC); - if (!dev) { - sas_free_task(task); - pm8001_dbg(pm8001_ha, FAIL, - "Domain device cannot be allocated\n"); - return; - } - task->dev = dev; - task->dev->lldd_dev = pm8001_ha_dev; - - ccb = pm8001_ccb_alloc(pm8001_ha, pm8001_ha_dev, task); - if (!ccb) { - sas_free_task(task); - kfree(dev); - return; - } - - pm8001_ha_dev->id |= NCQ_READ_LOG_FLAG; - pm8001_ha_dev->id |= NCQ_2ND_RLE_FLAG; - - /* construct read log FIS */ - memset(&fis, 0, sizeof(struct host_to_dev_fis)); - fis.fis_type = 0x27; - fis.flags = 0x80; - fis.command = ATA_CMD_READ_LOG_EXT; - fis.lbal = 0x10; - fis.sector_count = 0x1; - - memset(&sata_cmd, 0, sizeof(sata_cmd)); - sata_cmd.tag = cpu_to_le32(ccb->ccb_tag); - sata_cmd.device_id = cpu_to_le32(pm8001_ha_dev->device_id); - sata_cmd.ncqtag_atap_dir_m = cpu_to_le32((0x1 << 7) | (0x5 << 9)); - memcpy(&sata_cmd.sata_fis, &fis, sizeof(struct host_to_dev_fis)); - - res = pm8001_mpi_build_cmd(pm8001_ha, 0, opc, &sata_cmd, - sizeof(sata_cmd), 0); - if (res) { - sas_free_task(task); - pm8001_ccb_free(pm8001_ha, ccb); - kfree(dev); - } -} - /** * mpi_ssp_completion- process the event that FW response to the SSP request. * @pm8001_ha: our hba card information @@ -2301,8 +2204,7 @@ mpi_sata_completion(struct pm8001_hba_info *pm8001_ha, void *piomb) return; } - if ((pm8001_dev && !(pm8001_dev->id & NCQ_READ_LOG_FLAG)) - && unlikely(!t || !t->lldd_task || !t->dev)) { + if (pm8001_dev && unlikely(!t || !t->lldd_task || !t->dev)) { pm8001_dbg(pm8001_ha, FAIL, "task or dev null\n"); return; } @@ -2360,15 +2262,6 @@ mpi_sata_completion(struct pm8001_hba_info *pm8001_ha, void *piomb) if (param == 0) { ts->resp = SAS_TASK_COMPLETE; ts->stat = SAS_SAM_STAT_GOOD; - /* check if response is for SEND READ LOG */ - if (pm8001_dev && - (pm8001_dev->id & NCQ_READ_LOG_FLAG)) { - pm8001_send_abort_all(pm8001_ha, pm8001_dev); - /* Free the tag */ - pm8001_tag_free(pm8001_ha, tag); - sas_free_task(t); - return; - } } else { u8 len; ts->resp = SAS_TASK_COMPLETE; @@ -2666,9 +2559,10 @@ static void mpi_sata_event(struct pm8001_hba_info *pm8001_ha, void *piomb) if (event == IO_XFER_ERROR_ABORTED_NCQ_MODE) { /* find device using device id */ pm8001_dev = pm8001_find_dev(pm8001_ha, dev_id); - /* send read log extension */ if (pm8001_dev) - pm8001_send_read_log(pm8001_ha, pm8001_dev); + pm8001_handle_event(pm8001_ha, + pm8001_dev, + IO_XFER_ERROR_ABORTED_NCQ_MODE); return; } @@ -3649,12 +3543,7 @@ int pm8001_mpi_task_abort_resp(struct pm8001_hba_info *pm8001_ha, void *piomb) pm8001_ccb_task_free(pm8001_ha, ccb); mb(); - if (pm8001_dev->id & NCQ_ABORT_ALL_FLAG) { - sas_free_task(t); - pm8001_dev->id &= ~NCQ_ABORT_ALL_FLAG; - } else { - t->task_done(t); - } + t->task_done(t); return 0; } @@ -4206,7 +4095,6 @@ static int pm8001_chip_sata_req(struct pm8001_hba_info *pm8001_ha, u64 phys_addr; u32 ATAP = 0x0; u32 dir; - unsigned long flags; u32 opc = OPC_INB_SATA_HOST_OPSTART; memset(&sata_cmd, 0, sizeof(sata_cmd)); @@ -4261,39 +4149,6 @@ static int pm8001_chip_sata_req(struct pm8001_hba_info *pm8001_ha, sata_cmd.esgl = 0; } - /* Check for read log for failed drive and return */ - if (sata_cmd.sata_fis.command == 0x2f) { - if (((pm8001_ha_dev->id & NCQ_READ_LOG_FLAG) || - (pm8001_ha_dev->id & NCQ_ABORT_ALL_FLAG) || - (pm8001_ha_dev->id & NCQ_2ND_RLE_FLAG))) { - struct task_status_struct *ts; - - pm8001_ha_dev->id &= 0xDFFFFFFF; - ts = &task->task_status; - - spin_lock_irqsave(&task->task_state_lock, flags); - ts->resp = SAS_TASK_COMPLETE; - ts->stat = SAS_SAM_STAT_GOOD; - task->task_state_flags &= ~SAS_TASK_STATE_PENDING; - task->task_state_flags |= SAS_TASK_STATE_DONE; - if (unlikely((task->task_state_flags & - SAS_TASK_STATE_ABORTED))) { - spin_unlock_irqrestore(&task->task_state_lock, - flags); - pm8001_dbg(pm8001_ha, FAIL, - "task 0x%p resp 0x%x stat 0x%x but aborted by upper layer\n", - task, ts->resp, - ts->stat); - pm8001_ccb_task_free(pm8001_ha, ccb); - } else { - spin_unlock_irqrestore(&task->task_state_lock, - flags); - pm8001_ccb_task_free_done(pm8001_ha, ccb); - return 0; - } - } - } - return pm8001_mpi_build_cmd(pm8001_ha, 0, opc, &sata_cmd, sizeof(sata_cmd), 0); } diff --git a/drivers/scsi/pm8001/pm8001_sas.c b/drivers/scsi/pm8001/pm8001_sas.c index d5ec29f69be3..2d84ae95a1f9 100644 --- a/drivers/scsi/pm8001/pm8001_sas.c +++ b/drivers/scsi/pm8001/pm8001_sas.c @@ -687,12 +687,6 @@ int pm8001_dev_found(struct domain_device *dev) return pm8001_dev_found_notify(dev); } -void pm8001_task_done(struct sas_task *task) -{ - del_timer(&task->slow_task->timer); - complete(&task->slow_task->completion); -} - #define PM8001_TASK_TIMEOUT 20 /** diff --git a/drivers/scsi/pm8001/pm8001_sas.h b/drivers/scsi/pm8001/pm8001_sas.h index b08f52673889..16a753d5e8a7 100644 --- a/drivers/scsi/pm8001/pm8001_sas.h +++ b/drivers/scsi/pm8001/pm8001_sas.h @@ -579,10 +579,6 @@ struct pm8001_fw_image_header { #define FLASH_UPDATE_DNLD_NOT_SUPPORTED 0x10 #define FLASH_UPDATE_DISABLED 0x11 -#define NCQ_READ_LOG_FLAG 0x80000000 -#define NCQ_ABORT_ALL_FLAG 0x40000000 -#define NCQ_2ND_RLE_FLAG 0x20000000 - /* Device states */ #define DS_OPERATIONAL 0x01 #define DS_PORT_IN_RESET 0x02 @@ -709,7 +705,6 @@ int pm8001_mpi_fw_flash_update_resp(struct pm8001_hba_info *pm8001_ha, int pm8001_mpi_general_event(struct pm8001_hba_info *pm8001_ha, void *piomb); int pm8001_mpi_task_abort_resp(struct pm8001_hba_info *pm8001_ha, void *piomb); struct sas_task *pm8001_alloc_task(void); -void pm8001_task_done(struct sas_task *task); void pm8001_free_task(struct sas_task *task); void pm8001_tag_free(struct pm8001_hba_info *pm8001_ha, u32 tag); struct pm8001_device *pm8001_find_dev(struct pm8001_hba_info *pm8001_ha, diff --git a/drivers/scsi/pm8001/pm80xx_hwi.c b/drivers/scsi/pm8001/pm80xx_hwi.c index dd0e06983cd3..4484c498bcb6 100644 --- a/drivers/scsi/pm8001/pm80xx_hwi.c +++ b/drivers/scsi/pm8001/pm80xx_hwi.c @@ -1778,113 +1778,6 @@ pm80xx_chip_interrupt_disable(struct pm8001_hba_info *pm8001_ha, u8 vec) pm80xx_chip_intx_interrupt_disable(pm8001_ha); } -static void pm80xx_send_abort_all(struct pm8001_hba_info *pm8001_ha, - struct pm8001_device *pm8001_ha_dev) -{ - struct pm8001_ccb_info *ccb; - struct sas_task *task; - struct task_abort_req task_abort; - u32 opc = OPC_INB_SATA_ABORT; - int ret; - - pm8001_ha_dev->id |= NCQ_ABORT_ALL_FLAG; - pm8001_ha_dev->id &= ~NCQ_READ_LOG_FLAG; - - task = sas_alloc_slow_task(GFP_ATOMIC); - if (!task) { - pm8001_dbg(pm8001_ha, FAIL, "cannot allocate task\n"); - return; - } - task->task_done = pm8001_task_done; - - ccb = pm8001_ccb_alloc(pm8001_ha, pm8001_ha_dev, task); - if (!ccb) { - sas_free_task(task); - return; - } - - memset(&task_abort, 0, sizeof(task_abort)); - task_abort.abort_all = cpu_to_le32(1); - task_abort.device_id = cpu_to_le32(pm8001_ha_dev->device_id); - task_abort.tag = cpu_to_le32(ccb->ccb_tag); - - ret = pm8001_mpi_build_cmd(pm8001_ha, 0, opc, &task_abort, - sizeof(task_abort), 0); - pm8001_dbg(pm8001_ha, FAIL, "Executing abort task end\n"); - if (ret) { - sas_free_task(task); - pm8001_ccb_free(pm8001_ha, ccb); - } -} - -static void pm80xx_send_read_log(struct pm8001_hba_info *pm8001_ha, - struct pm8001_device *pm8001_ha_dev) -{ - struct sata_start_req sata_cmd; - int res; - struct pm8001_ccb_info *ccb; - struct sas_task *task = NULL; - struct host_to_dev_fis fis; - struct domain_device *dev; - u32 opc = OPC_INB_SATA_HOST_OPSTART; - - task = sas_alloc_slow_task(GFP_ATOMIC); - if (!task) { - pm8001_dbg(pm8001_ha, FAIL, "cannot allocate task !!!\n"); - return; - } - task->task_done = pm8001_task_done; - - /* - * Allocate domain device by ourselves as libsas is not going to - * provide any. - */ - dev = kzalloc(sizeof(struct domain_device), GFP_ATOMIC); - if (!dev) { - sas_free_task(task); - pm8001_dbg(pm8001_ha, FAIL, - "Domain device cannot be allocated\n"); - return; - } - - task->dev = dev; - task->dev->lldd_dev = pm8001_ha_dev; - - ccb = pm8001_ccb_alloc(pm8001_ha, pm8001_ha_dev, task); - if (!ccb) { - sas_free_task(task); - kfree(dev); - return; - } - - pm8001_ha_dev->id |= NCQ_READ_LOG_FLAG; - pm8001_ha_dev->id |= NCQ_2ND_RLE_FLAG; - - memset(&sata_cmd, 0, sizeof(sata_cmd)); - - /* construct read log FIS */ - memset(&fis, 0, sizeof(struct host_to_dev_fis)); - fis.fis_type = 0x27; - fis.flags = 0x80; - fis.command = ATA_CMD_READ_LOG_EXT; - fis.lbal = 0x10; - fis.sector_count = 0x1; - - sata_cmd.tag = cpu_to_le32(ccb->ccb_tag); - sata_cmd.device_id = cpu_to_le32(pm8001_ha_dev->device_id); - sata_cmd.ncqtag_atap_dir_m_dad = cpu_to_le32(((0x1 << 7) | (0x5 << 9))); - memcpy(&sata_cmd.sata_fis, &fis, sizeof(struct host_to_dev_fis)); - - res = pm8001_mpi_build_cmd(pm8001_ha, 0, opc, &sata_cmd, - sizeof(sata_cmd), 0); - pm8001_dbg(pm8001_ha, FAIL, "Executing read log end\n"); - if (res) { - sas_free_task(task); - pm8001_ccb_free(pm8001_ha, ccb); - kfree(dev); - } -} - /** * mpi_ssp_completion - process the event that FW response to the SSP request. * @pm8001_ha: our hba card information @@ -2402,11 +2295,9 @@ mpi_sata_completion(struct pm8001_hba_info *pm8001_ha, return; } - if ((pm8001_dev && !(pm8001_dev->id & NCQ_READ_LOG_FLAG)) - && unlikely(!t || !t->lldd_task || !t->dev)) { - pm8001_dbg(pm8001_ha, FAIL, "task or dev null\n"); + + if (pm8001_dev && unlikely(!t->lldd_task || !t->dev)) return; - } ts = &t->task_status; @@ -2463,15 +2354,6 @@ mpi_sata_completion(struct pm8001_hba_info *pm8001_ha, if (param == 0) { ts->resp = SAS_TASK_COMPLETE; ts->stat = SAS_SAM_STAT_GOOD; - /* check if response is for SEND READ LOG */ - if (pm8001_dev && - (pm8001_dev->id & NCQ_READ_LOG_FLAG)) { - pm80xx_send_abort_all(pm8001_ha, pm8001_dev); - /* Free the tag */ - pm8001_tag_free(pm8001_ha, tag); - sas_free_task(t); - return; - } } else { u8 len; ts->resp = SAS_TASK_COMPLETE; @@ -2806,9 +2688,11 @@ static void mpi_sata_event(struct pm8001_hba_info *pm8001_ha, if (event == IO_XFER_ERROR_ABORTED_NCQ_MODE) { /* find device using device id */ pm8001_dev = pm8001_find_dev(pm8001_ha, dev_id); - /* send read log extension */ + /* send read log extension by aborting the link - libata does what we want */ if (pm8001_dev) - pm80xx_send_read_log(pm8001_ha, pm8001_dev); + pm8001_handle_event(pm8001_ha, + pm8001_dev, + IO_XFER_ERROR_ABORTED_NCQ_MODE); return; } @@ -4556,7 +4440,6 @@ static int pm80xx_chip_sata_req(struct pm8001_hba_info *pm8001_ha, u32 end_addr_high, end_addr_low; u32 ATAP = 0x0; u32 dir; - unsigned long flags; u32 opc = OPC_INB_SATA_HOST_OPSTART; memset(&sata_cmd, 0, sizeof(sata_cmd)); @@ -4735,40 +4618,6 @@ static int pm80xx_chip_sata_req(struct pm8001_hba_info *pm8001_ha, (task->ata_task.atapi_packet[15] << 24))); } - /* Check for read log for failed drive and return */ - if (sata_cmd.sata_fis.command == 0x2f) { - if (pm8001_ha_dev && ((pm8001_ha_dev->id & NCQ_READ_LOG_FLAG) || - (pm8001_ha_dev->id & NCQ_ABORT_ALL_FLAG) || - (pm8001_ha_dev->id & NCQ_2ND_RLE_FLAG))) { - struct task_status_struct *ts; - - pm8001_ha_dev->id &= 0xDFFFFFFF; - ts = &task->task_status; - - spin_lock_irqsave(&task->task_state_lock, flags); - ts->resp = SAS_TASK_COMPLETE; - ts->stat = SAS_SAM_STAT_GOOD; - task->task_state_flags &= ~SAS_TASK_STATE_PENDING; - task->task_state_flags |= SAS_TASK_STATE_DONE; - if (unlikely((task->task_state_flags & - SAS_TASK_STATE_ABORTED))) { - spin_unlock_irqrestore(&task->task_state_lock, - flags); - pm8001_dbg(pm8001_ha, FAIL, - "task 0x%p resp 0x%x stat 0x%x but aborted by upper layer\n", - task, ts->resp, - ts->stat); - pm8001_ccb_task_free(pm8001_ha, ccb); - return 0; - } else { - spin_unlock_irqrestore(&task->task_state_lock, - flags); - pm8001_ccb_task_free_done(pm8001_ha, ccb); - atomic_dec(&pm8001_ha_dev->running_req); - return 0; - } - } - } trace_pm80xx_request_issue(pm8001_ha->id, ccb->device ? ccb->device->attached_phy : PM8001_MAX_PHYS, ccb->ccb_tag, opc, -- cgit v1.2.3 From 8e8d43642f2f9bbed9e7823c6e5b6fd7c7fbc3dc Mon Sep 17 00:00:00 2001 From: John Garry Date: Mon, 17 Oct 2022 17:20:34 +0800 Subject: scsi: libsas: Make sas_{alloc, alloc_slow, free}_task() private We have no users outside libsas any longer, so make sas_alloc_task(), sas_alloc_slow_task(), and sas_free_task() private. Signed-off-by: John Garry Link: https://lore.kernel.org/r/1665998435-199946-8-git-send-email-john.garry@huawei.com Tested-by: Damien Le Moal Tested-by: Niklas Cassel # pm80xx Reviewed-by: Jason Yan Signed-off-by: Martin K. Petersen --- drivers/scsi/libsas/sas_init.c | 3 --- drivers/scsi/libsas/sas_internal.h | 4 ++++ include/scsi/libsas.h | 4 ---- 3 files changed, 4 insertions(+), 7 deletions(-) diff --git a/drivers/scsi/libsas/sas_init.c b/drivers/scsi/libsas/sas_init.c index e4f77072a58d..f2c05ebeb72f 100644 --- a/drivers/scsi/libsas/sas_init.c +++ b/drivers/scsi/libsas/sas_init.c @@ -35,7 +35,6 @@ struct sas_task *sas_alloc_task(gfp_t flags) return task; } -EXPORT_SYMBOL_GPL(sas_alloc_task); struct sas_task *sas_alloc_slow_task(gfp_t flags) { @@ -56,7 +55,6 @@ struct sas_task *sas_alloc_slow_task(gfp_t flags) return task; } -EXPORT_SYMBOL_GPL(sas_alloc_slow_task); void sas_free_task(struct sas_task *task) { @@ -65,7 +63,6 @@ void sas_free_task(struct sas_task *task) kmem_cache_free(sas_task_cache, task); } } -EXPORT_SYMBOL_GPL(sas_free_task); /*------------ SAS addr hash -----------*/ void sas_hash_addr(u8 *hashed, const u8 *sas_addr) diff --git a/drivers/scsi/libsas/sas_internal.h b/drivers/scsi/libsas/sas_internal.h index 8d0ad3abc7b5..b54bcf3c9a9d 100644 --- a/drivers/scsi/libsas/sas_internal.h +++ b/drivers/scsi/libsas/sas_internal.h @@ -52,6 +52,10 @@ void sas_unregister_phys(struct sas_ha_struct *sas_ha); struct asd_sas_event *sas_alloc_event(struct asd_sas_phy *phy, gfp_t gfp_flags); void sas_free_event(struct asd_sas_event *event); +struct sas_task *sas_alloc_task(gfp_t flags); +struct sas_task *sas_alloc_slow_task(gfp_t flags); +void sas_free_task(struct sas_task *task); + int sas_register_ports(struct sas_ha_struct *sas_ha); void sas_unregister_ports(struct sas_ha_struct *sas_ha); diff --git a/include/scsi/libsas.h b/include/scsi/libsas.h index 2dbead74a2af..f86b56bf7833 100644 --- a/include/scsi/libsas.h +++ b/include/scsi/libsas.h @@ -639,10 +639,6 @@ struct sas_task_slow { #define SAS_TASK_STATE_ABORTED 4 #define SAS_TASK_NEED_DEV_RESET 8 -extern struct sas_task *sas_alloc_task(gfp_t flags); -extern struct sas_task *sas_alloc_slow_task(gfp_t flags); -extern void sas_free_task(struct sas_task *task); - static inline bool sas_is_internal_abort(struct sas_task *task) { return task->task_proto == SAS_PROTOCOL_INTERNAL_ABORT; -- cgit v1.2.3 From cc22efbec0110181725b1f5f6778155a2e352522 Mon Sep 17 00:00:00 2001 From: John Garry Date: Mon, 17 Oct 2022 17:20:35 +0800 Subject: scsi: libsas: Update SATA dev FIS in sas_ata_task_done() In sas_ata_task_done(), for commands which complete with error we set the SATA dev FIS status field with ATA_ERR. In ata_eh_analyze_tf() this would be interpreted as a HSM error. Set ATA_DRDY, which will lead libata to judge as a device error, which is a safer bet. Signed-off-by: John Garry Link: https://lore.kernel.org/r/1665998435-199946-9-git-send-email-john.garry@huawei.com Reviewed-by: Niklas Cassel Signed-off-by: Martin K. Petersen --- drivers/scsi/libsas/sas_ata.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/scsi/libsas/sas_ata.c b/drivers/scsi/libsas/sas_ata.c index 61f64d54e67d..78e6046fb55a 100644 --- a/drivers/scsi/libsas/sas_ata.c +++ b/drivers/scsi/libsas/sas_ata.c @@ -139,8 +139,8 @@ static void sas_ata_task_done(struct sas_task *task) qc->flags |= ATA_QCFLAG_FAILED; } - dev->sata_dev.fis[3] = 0x04; /* status err */ - dev->sata_dev.fis[2] = ATA_ERR; + dev->sata_dev.fis[2] = ATA_ERR | ATA_DRDY; /* tf status */ + dev->sata_dev.fis[3] = ATA_ABORTED; /* tf error */ } } -- cgit v1.2.3 From b6da92356cd6106dd9e7e8e168e3b7df4fe37d5d Mon Sep 17 00:00:00 2001 From: Bart Van Assche Date: Fri, 14 Oct 2022 17:24:11 -0700 Subject: scsi: esas2r: Initialize two host template members implicitly Prepare for removing the 'proc_dir' and 'present' members from the SCSI host template by implicitly initializing 'present' and 'emulated' in 'driver_template'. Reviewed-by: John Garry Cc: Bradley Grove Cc: Christoph Hellwig Cc: Ming Lei Cc: Hannes Reinecke Cc: Mike Christie Cc: Krzysztof Kozlowski Signed-off-by: Bart Van Assche Link: https://lore.kernel.org/r/20221015002418.30955-2-bvanassche@acm.org Signed-off-by: Martin K. Petersen --- drivers/scsi/esas2r/esas2r_main.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/drivers/scsi/esas2r/esas2r_main.c b/drivers/scsi/esas2r/esas2r_main.c index 7a4eadad23d7..27f6e7ccded8 100644 --- a/drivers/scsi/esas2r/esas2r_main.c +++ b/drivers/scsi/esas2r/esas2r_main.c @@ -248,8 +248,6 @@ static struct scsi_host_template driver_template = { .sg_tablesize = SG_CHUNK_SIZE, .cmd_per_lun = ESAS2R_DEFAULT_CMD_PER_LUN, - .present = 0, - .emulated = 0, .proc_name = ESAS2R_DRVR_NAME, .change_queue_depth = scsi_change_queue_depth, .max_sectors = 0xFFFF, -- cgit v1.2.3 From 77916da7e4a0975bd2b93e5214295e3318886cdb Mon Sep 17 00:00:00 2001 From: Bart Van Assche Date: Fri, 14 Oct 2022 17:24:12 -0700 Subject: scsi: esas2r: Introduce scsi_template_proc_dir() Prepare for removing the 'proc_dir' and 'present' members from the SCSI host template. This commit does not change any functionality. Reviewed-by: John Garry Cc: Bradley Grove Cc: Christoph Hellwig Cc: Ming Lei Cc: Hannes Reinecke Cc: Mike Christie Cc: Krzysztof Kozlowski Signed-off-by: Bart Van Assche Link: https://lore.kernel.org/r/20221015002418.30955-3-bvanassche@acm.org Signed-off-by: Martin K. Petersen --- drivers/scsi/esas2r/esas2r_main.c | 17 +++++++++++------ drivers/scsi/scsi_proc.c | 11 +++++++++++ include/scsi/scsi_host.h | 6 ++++++ 3 files changed, 28 insertions(+), 6 deletions(-) diff --git a/drivers/scsi/esas2r/esas2r_main.c b/drivers/scsi/esas2r/esas2r_main.c index 27f6e7ccded8..d7a2c49ff5ee 100644 --- a/drivers/scsi/esas2r/esas2r_main.c +++ b/drivers/scsi/esas2r/esas2r_main.c @@ -635,10 +635,13 @@ static void __exit esas2r_exit(void) esas2r_log(ESAS2R_LOG_INFO, "%s called", __func__); if (esas2r_proc_major > 0) { + struct proc_dir_entry *proc_dir; + esas2r_log(ESAS2R_LOG_INFO, "unregister proc"); - remove_proc_entry(ATTONODE_NAME, - esas2r_proc_host->hostt->proc_dir); + proc_dir = scsi_template_proc_dir(esas2r_proc_host->hostt); + if (proc_dir) + remove_proc_entry(ATTONODE_NAME, proc_dir); unregister_chrdev(esas2r_proc_major, ESAS2R_DRVR_NAME); esas2r_proc_major = 0; @@ -728,11 +731,13 @@ const char *esas2r_info(struct Scsi_Host *sh) esas2r_proc_major); if (esas2r_proc_major > 0) { - struct proc_dir_entry *pde; + struct proc_dir_entry *proc_dir; + struct proc_dir_entry *pde = NULL; - pde = proc_create(ATTONODE_NAME, 0, - sh->hostt->proc_dir, - &esas2r_proc_ops); + proc_dir = scsi_template_proc_dir(sh->hostt); + if (proc_dir) + pde = proc_create(ATTONODE_NAME, 0, proc_dir, + &esas2r_proc_ops); if (!pde) { esas2r_log_dev(ESAS2R_LOG_WARN, diff --git a/drivers/scsi/scsi_proc.c b/drivers/scsi/scsi_proc.c index 95aee1ad1383..456b43097288 100644 --- a/drivers/scsi/scsi_proc.c +++ b/drivers/scsi/scsi_proc.c @@ -83,6 +83,17 @@ static int proc_scsi_host_open(struct inode *inode, struct file *file) 4 * PAGE_SIZE); } +/** + * scsi_template_proc_dir() - returns the procfs dir for a SCSI host template + * @sht: SCSI host template pointer. + */ +struct proc_dir_entry * +scsi_template_proc_dir(const struct scsi_host_template *sht) +{ + return sht->proc_dir; +} +EXPORT_SYMBOL_GPL(scsi_template_proc_dir); + static const struct proc_ops proc_scsi_ops = { .proc_open = proc_scsi_host_open, .proc_release = single_release, diff --git a/include/scsi/scsi_host.h b/include/scsi/scsi_host.h index fcf25f1642a3..3854ffcb0b3e 100644 --- a/include/scsi/scsi_host.h +++ b/include/scsi/scsi_host.h @@ -751,6 +751,12 @@ extern struct Scsi_Host *scsi_host_alloc(struct scsi_host_template *, int); extern int __must_check scsi_add_host_with_dma(struct Scsi_Host *, struct device *, struct device *); +#if defined(CONFIG_SCSI_PROC_FS) +struct proc_dir_entry * +scsi_template_proc_dir(const struct scsi_host_template *sht); +#else +#define scsi_template_proc_dir(sht) NULL +#endif extern void scsi_scan_host(struct Scsi_Host *); extern void scsi_rescan_device(struct device *); extern void scsi_remove_host(struct Scsi_Host *); -- cgit v1.2.3 From ecca3f9b16366e601a6748bf31e9fe227812248f Mon Sep 17 00:00:00 2001 From: Bart Van Assche Date: Fri, 14 Oct 2022 17:24:13 -0700 Subject: scsi: core: Fail host creation if creating the proc directory fails Users expect that the contents of /proc/scsi is in sync with the contents of /sys/class/scsi_host. Hence fail host creation if creating the proc directory fails. Suggested-by: John Garry Reviewed-by: John Garry Cc: Christoph Hellwig Cc: Ming Lei Cc: Hannes Reinecke Cc: Mike Christie Cc: Krzysztof Kozlowski Signed-off-by: Bart Van Assche Link: https://lore.kernel.org/r/20221015002418.30955-4-bvanassche@acm.org Signed-off-by: Martin K. Petersen --- drivers/scsi/hosts.c | 3 ++- drivers/scsi/scsi_priv.h | 4 ++-- drivers/scsi/scsi_proc.c | 13 +++++++++---- 3 files changed, 13 insertions(+), 7 deletions(-) diff --git a/drivers/scsi/hosts.c b/drivers/scsi/hosts.c index 9857dba09c95..12346e2297fd 100644 --- a/drivers/scsi/hosts.c +++ b/drivers/scsi/hosts.c @@ -519,7 +519,8 @@ struct Scsi_Host *scsi_host_alloc(struct scsi_host_template *sht, int privsize) "failed to create tmf workq\n"); goto fail; } - scsi_proc_hostdir_add(shost->hostt); + if (scsi_proc_hostdir_add(shost->hostt) < 0) + goto fail; return shost; fail: /* diff --git a/drivers/scsi/scsi_priv.h b/drivers/scsi/scsi_priv.h index c52de9a973e4..494f48e03e90 100644 --- a/drivers/scsi/scsi_priv.h +++ b/drivers/scsi/scsi_priv.h @@ -111,14 +111,14 @@ extern void scsi_evt_thread(struct work_struct *work); /* scsi_proc.c */ #ifdef CONFIG_SCSI_PROC_FS -extern void scsi_proc_hostdir_add(struct scsi_host_template *); +extern int scsi_proc_hostdir_add(struct scsi_host_template *); extern void scsi_proc_hostdir_rm(struct scsi_host_template *); extern void scsi_proc_host_add(struct Scsi_Host *); extern void scsi_proc_host_rm(struct Scsi_Host *); extern int scsi_init_procfs(void); extern void scsi_exit_procfs(void); #else -# define scsi_proc_hostdir_add(sht) do { } while (0) +# define scsi_proc_hostdir_add(sht) 0 # define scsi_proc_hostdir_rm(sht) do { } while (0) # define scsi_proc_host_add(shost) do { } while (0) # define scsi_proc_host_rm(shost) do { } while (0) diff --git a/drivers/scsi/scsi_proc.c b/drivers/scsi/scsi_proc.c index 456b43097288..1b09cea2a752 100644 --- a/drivers/scsi/scsi_proc.c +++ b/drivers/scsi/scsi_proc.c @@ -108,20 +108,25 @@ static const struct proc_ops proc_scsi_ops = { * * Sets sht->proc_dir to the new directory. */ - -void scsi_proc_hostdir_add(struct scsi_host_template *sht) +int scsi_proc_hostdir_add(struct scsi_host_template *sht) { + int ret = 0; + if (!sht->show_info) - return; + return 0; mutex_lock(&global_host_template_mutex); if (!sht->present++) { sht->proc_dir = proc_mkdir(sht->proc_name, proc_scsi); - if (!sht->proc_dir) + if (!sht->proc_dir) { printk(KERN_ERR "%s: proc_mkdir failed for %s\n", __func__, sht->proc_name); + ret = -ENOMEM; + } } mutex_unlock(&global_host_template_mutex); + + return ret; } /** -- cgit v1.2.3 From 036abd6140078b4125f60e731f28e15de708f87d Mon Sep 17 00:00:00 2001 From: Bart Van Assche Date: Fri, 14 Oct 2022 17:24:14 -0700 Subject: scsi: core: Introduce a new list for SCSI proc directory entries Instead of using scsi_host_template members to track the SCSI proc directory entries, track these entries in a list. This changes the time needed for looking up the proc dir pointer from O(1) into O(n). This is considered acceptable since the number of SCSI host adapter types per host is usually small (less than ten). This change has been tested by attaching two USB storage devices to a qemu host: $ grep -aH . /proc/scsi/usb-storage/* /proc/scsi/usb-storage/7: Host scsi7: usb-storage /proc/scsi/usb-storage/7: Vendor: QEMU /proc/scsi/usb-storage/7: Product: QEMU USB HARDDRIVE /proc/scsi/usb-storage/7:Serial Number: 1-0000:00:02.1:00.0-6 /proc/scsi/usb-storage/7: Protocol: Transparent SCSI /proc/scsi/usb-storage/7: Transport: Bulk /proc/scsi/usb-storage/7: Quirks: SANE_SENSE /proc/scsi/usb-storage/8: Host scsi8: usb-storage /proc/scsi/usb-storage/8: Vendor: QEMU /proc/scsi/usb-storage/8: Product: QEMU USB HARDDRIVE /proc/scsi/usb-storage/8:Serial Number: 1-0000:00:02.1:00.0-7 /proc/scsi/usb-storage/8: Protocol: Transparent SCSI /proc/scsi/usb-storage/8: Transport: Bulk /proc/scsi/usb-storage/8: Quirks: SANE_SENSE This commit prepares for constifying most SCSI host templates. Reviewed-by: John Garry Cc: Christoph Hellwig Cc: Ming Lei Cc: Hannes Reinecke Cc: Mike Christie Cc: Krzysztof Kozlowski Signed-off-by: Bart Van Assche Link: https://lore.kernel.org/r/20221015002418.30955-5-bvanassche@acm.org Signed-off-by: Martin K. Petersen --- drivers/scsi/scsi_priv.h | 4 +- drivers/scsi/scsi_proc.c | 121 +++++++++++++++++++++++++++++++++++++++-------- include/scsi/scsi_host.h | 12 ----- 3 files changed, 102 insertions(+), 35 deletions(-) diff --git a/drivers/scsi/scsi_priv.h b/drivers/scsi/scsi_priv.h index 494f48e03e90..96284a0e13fe 100644 --- a/drivers/scsi/scsi_priv.h +++ b/drivers/scsi/scsi_priv.h @@ -111,8 +111,8 @@ extern void scsi_evt_thread(struct work_struct *work); /* scsi_proc.c */ #ifdef CONFIG_SCSI_PROC_FS -extern int scsi_proc_hostdir_add(struct scsi_host_template *); -extern void scsi_proc_hostdir_rm(struct scsi_host_template *); +extern int scsi_proc_hostdir_add(const struct scsi_host_template *); +extern void scsi_proc_hostdir_rm(const struct scsi_host_template *); extern void scsi_proc_host_add(struct Scsi_Host *); extern void scsi_proc_host_rm(struct Scsi_Host *); extern int scsi_init_procfs(void); diff --git a/drivers/scsi/scsi_proc.c b/drivers/scsi/scsi_proc.c index 1b09cea2a752..4a6eb1741be0 100644 --- a/drivers/scsi/scsi_proc.c +++ b/drivers/scsi/scsi_proc.c @@ -43,8 +43,23 @@ static struct proc_dir_entry *proc_scsi; -/* Protect sht->present and sht->proc_dir */ +/* Protects scsi_proc_list */ static DEFINE_MUTEX(global_host_template_mutex); +static LIST_HEAD(scsi_proc_list); + +/** + * struct scsi_proc_entry - (host template, SCSI proc dir) association + * @entry: entry in scsi_proc_list. + * @sht: SCSI host template associated with the procfs directory. + * @proc_dir: procfs directory associated with the SCSI host template. + * @present: Number of SCSI hosts instantiated for @sht. + */ +struct scsi_proc_entry { + struct list_head entry; + const struct scsi_host_template *sht; + struct proc_dir_entry *proc_dir; + unsigned int present; +}; static ssize_t proc_scsi_host_write(struct file *file, const char __user *buf, size_t count, loff_t *ppos) @@ -83,6 +98,32 @@ static int proc_scsi_host_open(struct inode *inode, struct file *file) 4 * PAGE_SIZE); } +static struct scsi_proc_entry * +__scsi_lookup_proc_entry(const struct scsi_host_template *sht) +{ + struct scsi_proc_entry *e; + + lockdep_assert_held(&global_host_template_mutex); + + list_for_each_entry(e, &scsi_proc_list, entry) + if (e->sht == sht) + return e; + + return NULL; +} + +static struct scsi_proc_entry * +scsi_lookup_proc_entry(const struct scsi_host_template *sht) +{ + struct scsi_proc_entry *e; + + mutex_lock(&global_host_template_mutex); + e = __scsi_lookup_proc_entry(sht); + mutex_unlock(&global_host_template_mutex); + + return e; +} + /** * scsi_template_proc_dir() - returns the procfs dir for a SCSI host template * @sht: SCSI host template pointer. @@ -90,7 +131,9 @@ static int proc_scsi_host_open(struct inode *inode, struct file *file) struct proc_dir_entry * scsi_template_proc_dir(const struct scsi_host_template *sht) { - return sht->proc_dir; + struct scsi_proc_entry *e = scsi_lookup_proc_entry(sht); + + return e ? e->proc_dir : NULL; } EXPORT_SYMBOL_GPL(scsi_template_proc_dir); @@ -108,24 +151,41 @@ static const struct proc_ops proc_scsi_ops = { * * Sets sht->proc_dir to the new directory. */ -int scsi_proc_hostdir_add(struct scsi_host_template *sht) +int scsi_proc_hostdir_add(const struct scsi_host_template *sht) { - int ret = 0; + struct scsi_proc_entry *e; + int ret; if (!sht->show_info) return 0; mutex_lock(&global_host_template_mutex); - if (!sht->present++) { - sht->proc_dir = proc_mkdir(sht->proc_name, proc_scsi); - if (!sht->proc_dir) { - printk(KERN_ERR "%s: proc_mkdir failed for %s\n", - __func__, sht->proc_name); + e = __scsi_lookup_proc_entry(sht); + if (!e) { + e = kzalloc(sizeof(*e), GFP_KERNEL); + if (!e) { ret = -ENOMEM; + goto unlock; } } + if (e->present++) + goto success; + e->proc_dir = proc_mkdir(sht->proc_name, proc_scsi); + if (!e->proc_dir) { + printk(KERN_ERR "%s: proc_mkdir failed for %s\n", __func__, + sht->proc_name); + ret = -ENOMEM; + goto unlock; + } + e->sht = sht; + list_add_tail(&e->entry, &scsi_proc_list); +success: + e = NULL; + ret = 0; +unlock: mutex_unlock(&global_host_template_mutex); + kfree(e); return ret; } @@ -133,15 +193,19 @@ int scsi_proc_hostdir_add(struct scsi_host_template *sht) * scsi_proc_hostdir_rm - remove directory in /proc for a scsi host * @sht: owner of directory */ -void scsi_proc_hostdir_rm(struct scsi_host_template *sht) +void scsi_proc_hostdir_rm(const struct scsi_host_template *sht) { + struct scsi_proc_entry *e; + if (!sht->show_info) return; mutex_lock(&global_host_template_mutex); - if (!--sht->present && sht->proc_dir) { + e = __scsi_lookup_proc_entry(sht); + if (e && !--e->present) { remove_proc_entry(sht->proc_name, proc_scsi); - sht->proc_dir = NULL; + list_del(&e->entry); + kfree(e); } mutex_unlock(&global_host_template_mutex); } @@ -153,20 +217,29 @@ void scsi_proc_hostdir_rm(struct scsi_host_template *sht) */ void scsi_proc_host_add(struct Scsi_Host *shost) { - struct scsi_host_template *sht = shost->hostt; + const struct scsi_host_template *sht = shost->hostt; + struct scsi_proc_entry *e; struct proc_dir_entry *p; char name[10]; - if (!sht->proc_dir) + if (!sht->show_info) return; + e = scsi_lookup_proc_entry(sht); + if (!e) + goto err; + sprintf(name,"%d", shost->host_no); - p = proc_create_data(name, S_IRUGO | S_IWUSR, - sht->proc_dir, &proc_scsi_ops, shost); + p = proc_create_data(name, S_IRUGO | S_IWUSR, e->proc_dir, + &proc_scsi_ops, shost); if (!p) - printk(KERN_ERR "%s: Failed to register host %d in" - "%s\n", __func__, shost->host_no, - sht->proc_name); + goto err; + return; + +err: + shost_printk(KERN_ERR, shost, + "%s: Failed to register host (%s failed)\n", __func__, + e ? "proc_create_data()" : "scsi_proc_hostdir_add()"); } /** @@ -175,13 +248,19 @@ void scsi_proc_host_add(struct Scsi_Host *shost) */ void scsi_proc_host_rm(struct Scsi_Host *shost) { + const struct scsi_host_template *sht = shost->hostt; + struct scsi_proc_entry *e; char name[10]; - if (!shost->hostt->proc_dir) + if (!sht->show_info) + return; + + e = scsi_lookup_proc_entry(sht); + if (!e) return; sprintf(name,"%d", shost->host_no); - remove_proc_entry(name, shost->hostt->proc_dir); + remove_proc_entry(name, e->proc_dir); } /** * proc_print_scsidevice - return data about this host diff --git a/include/scsi/scsi_host.h b/include/scsi/scsi_host.h index 3854ffcb0b3e..e71436183c0d 100644 --- a/include/scsi/scsi_host.h +++ b/include/scsi/scsi_host.h @@ -357,12 +357,6 @@ struct scsi_host_template { */ const char *proc_name; - /* - * Used to store the procfs directory if a driver implements the - * show_info method. - */ - struct proc_dir_entry *proc_dir; - /* * This determines if we will use a non-interrupt driven * or an interrupt driven scheme. It is set to the maximum number @@ -423,12 +417,6 @@ struct scsi_host_template { */ short cmd_per_lun; - /* - * present contains counter indicating how many boards of this - * type were found when we did the scan. - */ - unsigned char present; - /* If use block layer to manage tags, this is tag allocation policy */ int tag_alloc_policy; -- cgit v1.2.3 From d460f624059266c2e7f0280bdd3ae806d4b75211 Mon Sep 17 00:00:00 2001 From: Bart Van Assche Date: Fri, 14 Oct 2022 17:24:15 -0700 Subject: scsi: core: Rework scsi_single_lun_run() Use __starget_for_each_device() instead of open-coding starget_for_each_device(). Run the queues asynchronously instead of synchronously. This commit removes code that calls scsi_device_put() from atomic context. Cc: Christoph Hellwig Cc: Ming Lei Cc: Hannes Reinecke Cc: John Garry Cc: Mike Christie Cc: Krzysztof Kozlowski Signed-off-by: Bart Van Assche Link: https://lore.kernel.org/r/20221015002418.30955-6-bvanassche@acm.org Signed-off-by: Martin K. Petersen --- drivers/scsi/scsi_lib.c | 32 +++++++++++++++----------------- 1 file changed, 15 insertions(+), 17 deletions(-) diff --git a/drivers/scsi/scsi_lib.c b/drivers/scsi/scsi_lib.c index 8b89fab7c420..fa96d3cfdfa3 100644 --- a/drivers/scsi/scsi_lib.c +++ b/drivers/scsi/scsi_lib.c @@ -307,6 +307,18 @@ static void scsi_kick_queue(struct request_queue *q) blk_mq_run_hw_queues(q, false); } +/* + * Kick the queue of SCSI device @sdev if @sdev != current_sdev. Called with + * interrupts disabled. + */ +static void scsi_kick_sdev_queue(struct scsi_device *sdev, void *data) +{ + struct scsi_device *current_sdev = data; + + if (sdev != current_sdev) + blk_mq_run_hw_queues(sdev->request_queue, true); +} + /* * Called for single_lun devices on IO completion. Clear starget_sdev_user, * and call blk_run_queue for all the scsi_devices on the target - @@ -317,7 +329,6 @@ static void scsi_kick_queue(struct request_queue *q) static void scsi_single_lun_run(struct scsi_device *current_sdev) { struct Scsi_Host *shost = current_sdev->host; - struct scsi_device *sdev, *tmp; struct scsi_target *starget = scsi_target(current_sdev); unsigned long flags; @@ -334,22 +345,9 @@ static void scsi_single_lun_run(struct scsi_device *current_sdev) scsi_kick_queue(current_sdev->request_queue); spin_lock_irqsave(shost->host_lock, flags); - if (starget->starget_sdev_user) - goto out; - list_for_each_entry_safe(sdev, tmp, &starget->devices, - same_target_siblings) { - if (sdev == current_sdev) - continue; - if (scsi_device_get(sdev)) - continue; - - spin_unlock_irqrestore(shost->host_lock, flags); - scsi_kick_queue(sdev->request_queue); - spin_lock_irqsave(shost->host_lock, flags); - - scsi_device_put(sdev); - } - out: + if (!starget->starget_sdev_user) + __starget_for_each_device(starget, current_sdev, + scsi_kick_sdev_queue); spin_unlock_irqrestore(shost->host_lock, flags); } -- cgit v1.2.3 From 6d1aa3b0589bdd17a46ed74fbd2c2d0fc59038ff Mon Sep 17 00:00:00 2001 From: Bart Van Assche Date: Fri, 14 Oct 2022 17:24:16 -0700 Subject: scsi: ufs: Simplify ufshcd_set_dev_pwr_mode() Simplify the code for incrementing the SCSI device reference count in ufshcd_set_dev_pwr_mode(). This commit removes one scsi_device_put() call that happens from atomic context. Reviewed-by: Adrian Hunter Cc: Avri Altman Signed-off-by: Bart Van Assche Link: https://lore.kernel.org/r/20221015002418.30955-7-bvanassche@acm.org Signed-off-by: Martin K. Petersen --- drivers/ufs/core/ufshcd.c | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) diff --git a/drivers/ufs/core/ufshcd.c b/drivers/ufs/core/ufshcd.c index 7256e6c43ca6..c8f0fe740005 100644 --- a/drivers/ufs/core/ufshcd.c +++ b/drivers/ufs/core/ufshcd.c @@ -8752,15 +8752,10 @@ static int ufshcd_set_dev_pwr_mode(struct ufs_hba *hba, spin_lock_irqsave(hba->host->host_lock, flags); sdp = hba->ufs_device_wlun; - if (sdp) { + if (sdp && scsi_device_online(sdp)) ret = scsi_device_get(sdp); - if (!ret && !scsi_device_online(sdp)) { - ret = -ENODEV; - scsi_device_put(sdp); - } - } else { + else ret = -ENODEV; - } spin_unlock_irqrestore(hba->host->host_lock, flags); if (ret) -- cgit v1.2.3 From 195fae206ef20a29b09f281b6db8ea30fafaa908 Mon Sep 17 00:00:00 2001 From: Bart Van Assche Date: Fri, 14 Oct 2022 17:24:17 -0700 Subject: scsi: core: Remove the put_device() call from scsi_device_get() scsi_device_get() may be called from atomic context, e.g. by shost_for_each_device(). A later commit will allow put_device() to sleep for SCSI devices. Hence remove the put_device() call from scsi_device_get(). According to Rusty Russell's "Module Refcount and Stuff mini-FAQ", calling module_put() from atomic context is allowed since considerable time. See also https://lkml.org/lkml/2002/11/18/330. Cc: Christoph Hellwig Cc: Ming Lei Cc: Hannes Reinecke Cc: Mike Christie Cc: Krzysztof Kozlowski Signed-off-by: Bart Van Assche Link: https://lore.kernel.org/r/20221015002418.30955-8-bvanassche@acm.org Signed-off-by: Martin K. Petersen --- drivers/scsi/scsi.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/drivers/scsi/scsi.c b/drivers/scsi/scsi.c index c59eac7a32f2..9feb0323bc44 100644 --- a/drivers/scsi/scsi.c +++ b/drivers/scsi/scsi.c @@ -563,14 +563,14 @@ int scsi_device_get(struct scsi_device *sdev) { if (sdev->sdev_state == SDEV_DEL || sdev->sdev_state == SDEV_CANCEL) goto fail; - if (!get_device(&sdev->sdev_gendev)) - goto fail; if (!try_module_get(sdev->host->hostt->module)) - goto fail_put_device; + goto fail; + if (!get_device(&sdev->sdev_gendev)) + goto fail_put_module; return 0; -fail_put_device: - put_device(&sdev->sdev_gendev); +fail_put_module: + module_put(sdev->host->hostt->module); fail: return -ENXIO; } -- cgit v1.2.3 From f93ed747e2c7e6bfbf309291879b33b0d0231a7d Mon Sep 17 00:00:00 2001 From: Bart Van Assche Date: Fri, 14 Oct 2022 17:24:18 -0700 Subject: scsi: core: Release SCSI devices synchronously All upstream scsi_device_put() calls happen from thread context. Hence simplify scsi_device_put() by always calling the release function synchronously. This commit prepares for constifying the SCSI host template by removing an assignment that clears the module pointer in the SCSI host template. scsi_device_dev_release_usercontext() was introduced in 2006 via commit 65110b216895 ("[SCSI] fix wrong context bugs in SCSI"). Cc: Christoph Hellwig Cc: Ming Lei Cc: Hannes Reinecke Cc: John Garry Cc: Mike Christie Cc: Krzysztof Kozlowski Signed-off-by: Bart Van Assche Link: https://lore.kernel.org/r/20221015002418.30955-9-bvanassche@acm.org Signed-off-by: Martin K. Petersen --- drivers/scsi/scsi.c | 2 ++ drivers/scsi/scsi_sysfs.c | 22 ++-------------------- include/scsi/scsi_device.h | 1 - 3 files changed, 4 insertions(+), 21 deletions(-) diff --git a/drivers/scsi/scsi.c b/drivers/scsi/scsi.c index 9feb0323bc44..1426b9b03612 100644 --- a/drivers/scsi/scsi.c +++ b/drivers/scsi/scsi.c @@ -588,6 +588,8 @@ void scsi_device_put(struct scsi_device *sdev) { struct module *mod = sdev->host->hostt->module; + might_sleep(); + put_device(&sdev->sdev_gendev); module_put(mod); } diff --git a/drivers/scsi/scsi_sysfs.c b/drivers/scsi/scsi_sysfs.c index c95177ca6ed2..f2a345cc0f8a 100644 --- a/drivers/scsi/scsi_sysfs.c +++ b/drivers/scsi/scsi_sysfs.c @@ -441,20 +441,15 @@ static void scsi_device_cls_release(struct device *class_dev) put_device(&sdev->sdev_gendev); } -static void scsi_device_dev_release_usercontext(struct work_struct *work) +static void scsi_device_dev_release(struct device *dev) { - struct scsi_device *sdev; + struct scsi_device *sdev = to_scsi_device(dev); struct device *parent; struct list_head *this, *tmp; struct scsi_vpd *vpd_pg80 = NULL, *vpd_pg83 = NULL; struct scsi_vpd *vpd_pg0 = NULL, *vpd_pg89 = NULL; struct scsi_vpd *vpd_pgb0 = NULL, *vpd_pgb1 = NULL, *vpd_pgb2 = NULL; unsigned long flags; - struct module *mod; - - sdev = container_of(work, struct scsi_device, ew.work); - - mod = sdev->host->hostt->module; scsi_dh_release_device(sdev); @@ -518,19 +513,6 @@ static void scsi_device_dev_release_usercontext(struct work_struct *work) if (parent) put_device(parent); - module_put(mod); -} - -static void scsi_device_dev_release(struct device *dev) -{ - struct scsi_device *sdp = to_scsi_device(dev); - - /* Set module pointer as NULL in case of module unloading */ - if (!try_module_get(sdp->host->hostt->module)) - sdp->host->hostt->module = NULL; - - execute_in_process_context(scsi_device_dev_release_usercontext, - &sdp->ew); } static struct class sdev_class = { diff --git a/include/scsi/scsi_device.h b/include/scsi/scsi_device.h index c36656d8ac6c..24bdbf7999ab 100644 --- a/include/scsi/scsi_device.h +++ b/include/scsi/scsi_device.h @@ -236,7 +236,6 @@ struct scsi_device { struct device sdev_gendev, sdev_dev; - struct execute_work ew; /* used to get process context on put */ struct work_struct requeue_work; struct scsi_device_handler *handler; -- cgit v1.2.3 From 773792e4e704ca1c47e3d9bc6ed5be2a00a22ad5 Mon Sep 17 00:00:00 2001 From: Jason Yan Date: Wed, 28 Sep 2022 15:01:23 +0800 Subject: scsi: libsas: Introduce SAS address comparison helpers SAS address comparison is widely used in libsas. However they are all opencoded and to avoid the line spill over 80 columns, are mostly split into multi-lines. Introduce some helpers to prepare for some refactoring. Signed-off-by: Jason Yan Link: https://lore.kernel.org/r/20220928070130.3657183-2-yanaijie@huawei.com Reviewed-by: Damien Le Moal Reviewed-by: John Garry Reviewed-by: Johannes Thumshirn Signed-off-by: Martin K. Petersen --- drivers/scsi/libsas/sas_internal.h | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/drivers/scsi/libsas/sas_internal.h b/drivers/scsi/libsas/sas_internal.h index b54bcf3c9a9d..6cf190ade35e 100644 --- a/drivers/scsi/libsas/sas_internal.h +++ b/drivers/scsi/libsas/sas_internal.h @@ -115,6 +115,23 @@ static inline void sas_smp_host_handler(struct bsg_job *job, } #endif +static inline bool sas_phy_match_dev_addr(struct domain_device *dev, + struct ex_phy *phy) +{ + return SAS_ADDR(dev->sas_addr) == SAS_ADDR(phy->attached_sas_addr); +} + +static inline bool sas_phy_match_port_addr(struct asd_sas_port *port, + struct ex_phy *phy) +{ + return SAS_ADDR(port->sas_addr) == SAS_ADDR(phy->attached_sas_addr); +} + +static inline bool sas_phy_addr_match(struct ex_phy *p1, struct ex_phy *p2) +{ + return SAS_ADDR(p1->attached_sas_addr) == SAS_ADDR(p2->attached_sas_addr); +} + static inline void sas_fail_probe(struct domain_device *dev, const char *func, int err) { pr_warn("%s: for %s device %016llx returned %d\n", -- cgit v1.2.3 From 2d08f329a4f2eace6b041d60132f441fc8e0b616 Mon Sep 17 00:00:00 2001 From: Jason Yan Date: Wed, 28 Sep 2022 15:01:24 +0800 Subject: scsi: libsas: Introduce sas_find_attached_phy_id() helper LLDDs are all implementing their own attached phy ID finding code. Factor it out to libsas. Signed-off-by: Jason Yan Link: https://lore.kernel.org/r/20220928070130.3657183-3-yanaijie@huawei.com Reviewed-by: Jack Wang Reviewed-by: Damien Le Moal Reviewed-by: John Garry Reviewed-by: Johannes Thumshirn Signed-off-by: Martin K. Petersen --- drivers/scsi/libsas/sas_expander.c | 16 ++++++++++++++++ include/scsi/libsas.h | 2 ++ 2 files changed, 18 insertions(+) diff --git a/drivers/scsi/libsas/sas_expander.c b/drivers/scsi/libsas/sas_expander.c index 5ce251830104..7ffb42946335 100644 --- a/drivers/scsi/libsas/sas_expander.c +++ b/drivers/scsi/libsas/sas_expander.c @@ -2107,6 +2107,22 @@ int sas_ex_revalidate_domain(struct domain_device *port_dev) return res; } +int sas_find_attached_phy_id(struct expander_device *ex_dev, + struct domain_device *dev) +{ + struct ex_phy *phy; + int phy_id; + + for (phy_id = 0; phy_id < ex_dev->num_phys; phy_id++) { + phy = &ex_dev->ex_phy[phy_id]; + if (sas_phy_match_dev_addr(dev, phy)) + return phy_id; + } + + return -ENODEV; +} +EXPORT_SYMBOL_GPL(sas_find_attached_phy_id); + void sas_smp_handler(struct bsg_job *job, struct Scsi_Host *shost, struct sas_rphy *rphy) { diff --git a/include/scsi/libsas.h b/include/scsi/libsas.h index f86b56bf7833..ec6c9ecd8d12 100644 --- a/include/scsi/libsas.h +++ b/include/scsi/libsas.h @@ -746,6 +746,8 @@ int sas_clear_task_set(struct domain_device *dev, u8 *lun); int sas_lu_reset(struct domain_device *dev, u8 *lun); int sas_query_task(struct sas_task *task, u16 tag); int sas_abort_task(struct sas_task *task, u16 tag); +int sas_find_attached_phy_id(struct expander_device *ex_dev, + struct domain_device *dev); void sas_notify_port_event(struct asd_sas_phy *phy, enum port_event event, gfp_t gfp_flags); -- cgit v1.2.3 From ec64858657a8c393e2ae956d37c23bf94aee8200 Mon Sep 17 00:00:00 2001 From: Jason Yan Date: Wed, 28 Sep 2022 15:01:25 +0800 Subject: scsi: pm8001: Use sas_find_attached_phy_id() instead of open coding it The attached phy id finding is open coded. Replace it with sas_find_attached_phy_id(). To keep things consistent, the return value of pm8001_dev_found_notify() is also changed to -ENODEV after calling sas_find_attathed_phy_id() failed. Signed-off-by: Jason Yan Link: https://lore.kernel.org/r/20220928070130.3657183-4-yanaijie@huawei.com Reviewed-by: Jack Wang Reviewed-by: Damien Le Moal Reviewed-by: Johannes Thumshirn Signed-off-by: Martin K. Petersen --- drivers/scsi/pm8001/pm8001_sas.c | 18 ++++++------------ 1 file changed, 6 insertions(+), 12 deletions(-) diff --git a/drivers/scsi/pm8001/pm8001_sas.c b/drivers/scsi/pm8001/pm8001_sas.c index 2d84ae95a1f9..51230b827149 100644 --- a/drivers/scsi/pm8001/pm8001_sas.c +++ b/drivers/scsi/pm8001/pm8001_sas.c @@ -645,22 +645,16 @@ static int pm8001_dev_found_notify(struct domain_device *dev) pm8001_device->dcompletion = &completion; if (parent_dev && dev_is_expander(parent_dev->dev_type)) { int phy_id; - struct ex_phy *phy; - for (phy_id = 0; phy_id < parent_dev->ex_dev.num_phys; - phy_id++) { - phy = &parent_dev->ex_dev.ex_phy[phy_id]; - if (SAS_ADDR(phy->attached_sas_addr) - == SAS_ADDR(dev->sas_addr)) { - pm8001_device->attached_phy = phy_id; - break; - } - } - if (phy_id == parent_dev->ex_dev.num_phys) { + + phy_id = sas_find_attached_phy_id(&parent_dev->ex_dev, dev); + if (phy_id < 0) { pm8001_dbg(pm8001_ha, FAIL, "Error: no attached dev:%016llx at ex:%016llx.\n", SAS_ADDR(dev->sas_addr), SAS_ADDR(parent_dev->sas_addr)); - res = -1; + res = phy_id; + } else { + pm8001_device->attached_phy = phy_id; } } else { if (dev->dev_type == SAS_SATA_DEV) { -- cgit v1.2.3 From 178c39d94ac2cf9524ff797d90dcdf96b110fb27 Mon Sep 17 00:00:00 2001 From: Jason Yan Date: Wed, 28 Sep 2022 15:01:26 +0800 Subject: scsi: mvsas: Use sas_find_attached_phy_id() instead of open coding it The attached phy finding is open coded. Replace it with sas_find_attached_phy_id(). To keep things consistent, the return value of mvs_dev_found_notify() is also changed to -ENODEV after calling sas_find_attathed_phy_id() failed. Signed-off-by: Jason Yan Link: https://lore.kernel.org/r/20220928070130.3657183-5-yanaijie@huawei.com Reviewed-by: Jack Wang Reviewed-by: Damien Le Moal Reviewed-by: Johannes Thumshirn Signed-off-by: Martin K. Petersen --- drivers/scsi/mvsas/mv_sas.c | 17 +++++------------ 1 file changed, 5 insertions(+), 12 deletions(-) diff --git a/drivers/scsi/mvsas/mv_sas.c b/drivers/scsi/mvsas/mv_sas.c index a6867dae0e7c..bf7d4995b257 100644 --- a/drivers/scsi/mvsas/mv_sas.c +++ b/drivers/scsi/mvsas/mv_sas.c @@ -1190,23 +1190,16 @@ static int mvs_dev_found_notify(struct domain_device *dev, int lock) mvi_device->sas_device = dev; if (parent_dev && dev_is_expander(parent_dev->dev_type)) { int phy_id; - u8 phy_num = parent_dev->ex_dev.num_phys; - struct ex_phy *phy; - for (phy_id = 0; phy_id < phy_num; phy_id++) { - phy = &parent_dev->ex_dev.ex_phy[phy_id]; - if (SAS_ADDR(phy->attached_sas_addr) == - SAS_ADDR(dev->sas_addr)) { - mvi_device->attached_phy = phy_id; - break; - } - } - if (phy_id == phy_num) { + phy_id = sas_find_attached_phy_id(&parent_dev->ex_dev, dev); + if (phy_id < 0) { mv_printk("Error: no attached dev:%016llx" "at ex:%016llx.\n", SAS_ADDR(dev->sas_addr), SAS_ADDR(parent_dev->sas_addr)); - res = -1; + res = phy_id; + } else { + mvi_device->attached_phy = phy_id; } } -- cgit v1.2.3 From f0ed7bd5d9137b8e736e44ce353620ec19ee6242 Mon Sep 17 00:00:00 2001 From: Jason Yan Date: Wed, 28 Sep 2022 15:01:27 +0800 Subject: scsi: hisi_sas: Use sas_find_attathed_phy_id() instead of open coding it The attached phy finding is open coded. Replace it with sas_find_attached_phy_id(). To keep things consistent, the return value of hisi_sas_dev_found() is also changed to -ENODEV after calling sas_find_attathed_phy_id() failed. Signed-off-by: Jason Yan Link: https://lore.kernel.org/r/20220928070130.3657183-6-yanaijie@huawei.com Reviewed-by: Jack Wang Reviewed-by: Damien Le Moal Reviewed-by: Johannes Thumshirn Acked-by: John Garry Signed-off-by: Martin K. Petersen --- drivers/scsi/hisi_sas/hisi_sas_main.c | 14 +++----------- 1 file changed, 3 insertions(+), 11 deletions(-) diff --git a/drivers/scsi/hisi_sas/hisi_sas_main.c b/drivers/scsi/hisi_sas/hisi_sas_main.c index 4c37ae9eb6b6..10813836a728 100644 --- a/drivers/scsi/hisi_sas/hisi_sas_main.c +++ b/drivers/scsi/hisi_sas/hisi_sas_main.c @@ -792,22 +792,14 @@ static int hisi_sas_dev_found(struct domain_device *device) if (parent_dev && dev_is_expander(parent_dev->dev_type)) { int phy_no; - u8 phy_num = parent_dev->ex_dev.num_phys; - struct ex_phy *phy; - for (phy_no = 0; phy_no < phy_num; phy_no++) { - phy = &parent_dev->ex_dev.ex_phy[phy_no]; - if (SAS_ADDR(phy->attached_sas_addr) == - SAS_ADDR(device->sas_addr)) - break; - } - - if (phy_no == phy_num) { + phy_no = sas_find_attached_phy_id(&parent_dev->ex_dev, device); + if (phy_no < 0) { dev_info(dev, "dev found: no attached " "dev:%016llx at ex:%016llx\n", SAS_ADDR(device->sas_addr), SAS_ADDR(parent_dev->sas_addr)); - rc = -EINVAL; + rc = phy_no; goto err_out; } } -- cgit v1.2.3 From ad74d1dadbe9fc5ff7f80796f7cac0f126a5ea74 Mon Sep 17 00:00:00 2001 From: Jason Yan Date: Wed, 28 Sep 2022 15:01:28 +0800 Subject: scsi: libsas: Use sas_phy_match_dev_addr() instead of open coding it The SAS address comparison of domain device and expander phy is open coded. Replace it with sas_phy_match_dev_addr(). Signed-off-by: Jason Yan Link: https://lore.kernel.org/r/20220928070130.3657183-7-yanaijie@huawei.com Reviewed-by: Damien Le Moal Reviewed-by: Johannes Thumshirn Signed-off-by: Martin K. Petersen --- drivers/scsi/libsas/sas_expander.c | 18 ++++++------------ 1 file changed, 6 insertions(+), 12 deletions(-) diff --git a/drivers/scsi/libsas/sas_expander.c b/drivers/scsi/libsas/sas_expander.c index 7ffb42946335..9d6330c55cbf 100644 --- a/drivers/scsi/libsas/sas_expander.c +++ b/drivers/scsi/libsas/sas_expander.c @@ -738,9 +738,7 @@ static void sas_ex_get_linkrate(struct domain_device *parent, phy->phy_state == PHY_NOT_PRESENT) continue; - if (SAS_ADDR(phy->attached_sas_addr) == - SAS_ADDR(child->sas_addr)) { - + if (sas_phy_match_dev_addr(child, phy)) { child->min_linkrate = min(parent->min_linkrate, phy->linkrate); child->max_linkrate = max(parent->max_linkrate, @@ -1012,8 +1010,7 @@ static int sas_ex_discover_dev(struct domain_device *dev, int phy_id) sas_add_parent_port(dev, phy_id); return 0; } - if (dev->parent && (SAS_ADDR(ex_phy->attached_sas_addr) == - SAS_ADDR(dev->parent->sas_addr))) { + if (dev->parent && sas_phy_match_dev_addr(dev->parent, ex_phy)) { sas_add_parent_port(dev, phy_id); if (ex_phy->routing_attr == TABLE_ROUTING) sas_configure_phy(dev, phy_id, dev->port->sas_addr, 1); @@ -1312,7 +1309,7 @@ static int sas_check_parent_topology(struct domain_device *child) parent_phy->phy_state == PHY_NOT_PRESENT) continue; - if (SAS_ADDR(parent_phy->attached_sas_addr) != SAS_ADDR(child->sas_addr)) + if (!sas_phy_match_dev_addr(child, parent_phy)) continue; child_phy = &child_ex->ex_phy[parent_phy->attached_phy_id]; @@ -1522,8 +1519,7 @@ static int sas_configure_parent(struct domain_device *parent, struct ex_phy *phy = &ex_parent->ex_phy[i]; if ((phy->routing_attr == TABLE_ROUTING) && - (SAS_ADDR(phy->attached_sas_addr) == - SAS_ADDR(child->sas_addr))) { + sas_phy_match_dev_addr(child, phy)) { res = sas_configure_phy(parent, i, sas_addr, include); if (res) return res; @@ -1858,8 +1854,7 @@ static void sas_unregister_devs_sas_addr(struct domain_device *parent, if (last) { list_for_each_entry_safe(child, n, &ex_dev->children, siblings) { - if (SAS_ADDR(child->sas_addr) == - SAS_ADDR(phy->attached_sas_addr)) { + if (sas_phy_match_dev_addr(child, phy)) { set_bit(SAS_DEV_GONE, &child->state); if (dev_is_expander(child->dev_type)) sas_unregister_ex_tree(parent->port, child); @@ -1941,8 +1936,7 @@ static int sas_discover_new(struct domain_device *dev, int phy_id) if (res) return res; list_for_each_entry(child, &dev->ex_dev.children, siblings) { - if (SAS_ADDR(child->sas_addr) == - SAS_ADDR(ex_phy->attached_sas_addr)) { + if (sas_phy_match_dev_addr(child, ex_phy)) { if (dev_is_expander(child->dev_type)) res = sas_discover_bfs_by_root(child); break; -- cgit v1.2.3 From bfa22905f3865469479f028770a352126ad0d2e8 Mon Sep 17 00:00:00 2001 From: Jason Yan Date: Wed, 28 Sep 2022 15:01:29 +0800 Subject: scsi: libsas: Use sas_phy_addr_match() instead of open coding it The SAS address comparison of expander phys is open coded. Replace it with sas_phy_addr_match(). Signed-off-by: Jason Yan Link: https://lore.kernel.org/r/20220928070130.3657183-8-yanaijie@huawei.com Reviewed-by: Damien Le Moal Reviewed-by: Johannes Thumshirn Signed-off-by: Martin K. Petersen --- drivers/scsi/libsas/sas_expander.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/drivers/scsi/libsas/sas_expander.c b/drivers/scsi/libsas/sas_expander.c index 9d6330c55cbf..caa0b2286733 100644 --- a/drivers/scsi/libsas/sas_expander.c +++ b/drivers/scsi/libsas/sas_expander.c @@ -2058,8 +2058,7 @@ static int sas_rediscover(struct domain_device *dev, const int phy_id) if (i == phy_id) continue; - if (SAS_ADDR(phy->attached_sas_addr) == - SAS_ADDR(changed_phy->attached_sas_addr)) { + if (sas_phy_addr_match(phy, changed_phy)) { last = false; break; } -- cgit v1.2.3 From 868a8824838f1f0d781e838fa36dbb2de6bc7fdd Mon Sep 17 00:00:00 2001 From: Jason Yan Date: Wed, 28 Sep 2022 15:01:30 +0800 Subject: scsi: libsas: Use sas_phy_match_port_addr() instead of open coding it The SAS address comparison of asd_sas_port and expander phy is open coded. Replace it with sas_phy_match_port_addr(). Signed-off-by: Jason Yan Link: https://lore.kernel.org/r/20220928070130.3657183-9-yanaijie@huawei.com Reviewed-by: Damien Le Moal Reviewed-by: Johannes Thumshirn Signed-off-by: Martin K. Petersen --- drivers/scsi/libsas/sas_expander.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/drivers/scsi/libsas/sas_expander.c b/drivers/scsi/libsas/sas_expander.c index caa0b2286733..2907ca5d0ed4 100644 --- a/drivers/scsi/libsas/sas_expander.c +++ b/drivers/scsi/libsas/sas_expander.c @@ -1005,8 +1005,7 @@ static int sas_ex_discover_dev(struct domain_device *dev, int phy_id) } /* Parent and domain coherency */ - if (!dev->parent && (SAS_ADDR(ex_phy->attached_sas_addr) == - SAS_ADDR(dev->port->sas_addr))) { + if (!dev->parent && sas_phy_match_port_addr(dev->port, ex_phy)) { sas_add_parent_port(dev, phy_id); return 0; } -- cgit v1.2.3 From 621a323c3a7e23b364deaddf769e731f2da6ff03 Mon Sep 17 00:00:00 2001 From: Jiapeng Chong Date: Tue, 18 Oct 2022 16:12:35 +0800 Subject: scsi: target: Remove the unused function transport_lba_64_ext() The function transport_lba_64_ext() is defined in the target_core_sbc.c file, but not called elsewhere, so remove this unused function. drivers/target/target_core_sbc.c:276:34: warning: unused function 'transport_lba_64_ext'. Link: https://bugzilla.openanolis.cn/show_bug.cgi?id=2427 Reported-by: Abaci Robot Signed-off-by: Jiapeng Chong Link: https://lore.kernel.org/r/20221018081235.124662-1-jiapeng.chong@linux.alibaba.com Signed-off-by: Martin K. Petersen --- drivers/target/target_core_sbc.c | 8 -------- 1 file changed, 8 deletions(-) diff --git a/drivers/target/target_core_sbc.c b/drivers/target/target_core_sbc.c index 1e3216de1e04..1cd41e3834bb 100644 --- a/drivers/target/target_core_sbc.c +++ b/drivers/target/target_core_sbc.c @@ -270,14 +270,6 @@ static inline unsigned long long transport_lba_64(unsigned char *cdb) return get_unaligned_be64(&cdb[2]); } -/* - * For VARIABLE_LENGTH_CDB w/ 32 byte extended CDBs - */ -static inline unsigned long long transport_lba_64_ext(unsigned char *cdb) -{ - return get_unaligned_be64(&cdb[12]); -} - static sense_reason_t sbc_setup_write_same(struct se_cmd *cmd, unsigned char flags, struct sbc_ops *ops) { -- cgit v1.2.3 From a9ee3f840646e2ec419c734e592ffe997195435e Mon Sep 17 00:00:00 2001 From: John Garry Date: Tue, 18 Oct 2022 19:15:57 +0800 Subject: scsi: libsas: Add sas_task_find_rq() blk-mq already provides a unique tag per request. Some libsas LLDDs - like hisi_sas - already use this tag as the unique per-I/O HW tag. Add a common function to provide the request associated with a sas_task for all libsas LLDDs. Signed-off-by: John Garry Link: https://lore.kernel.org/r/1666091763-11023-2-git-send-email-john.garry@huawei.com Reviewed-by: Jack Wang Reviewed-by: Jason Yan Reviewed-by: Hannes Reinecke Signed-off-by: Martin K. Petersen --- include/scsi/libsas.h | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/include/scsi/libsas.h b/include/scsi/libsas.h index ec6c9ecd8d12..1aee3d0ebbb2 100644 --- a/include/scsi/libsas.h +++ b/include/scsi/libsas.h @@ -644,6 +644,24 @@ static inline bool sas_is_internal_abort(struct sas_task *task) return task->task_proto == SAS_PROTOCOL_INTERNAL_ABORT; } +static inline struct request *sas_task_find_rq(struct sas_task *task) +{ + struct scsi_cmnd *scmd; + + if (task->task_proto & SAS_PROTOCOL_STP_ALL) { + struct ata_queued_cmd *qc = task->uldd_task; + + scmd = qc ? qc->scsicmd : NULL; + } else { + scmd = task->uldd_task; + } + + if (!scmd) + return NULL; + + return scsi_cmd_to_rq(scmd); +} + struct sas_domain_function_template { /* The class calls these to notify the LLDD of an event. */ void (*lldd_port_formed)(struct asd_sas_phy *); -- cgit v1.2.3 From 295fd2330a91f295522ad2b7fe2109833ae32e33 Mon Sep 17 00:00:00 2001 From: John Garry Date: Tue, 18 Oct 2022 19:15:58 +0800 Subject: scsi: hisi_sas: Use sas_task_find_rq() Use sas_task_find_rq() to lookup the request per task for its driver tag. Signed-off-by: John Garry Link: https://lore.kernel.org/r/1666091763-11023-3-git-send-email-john.garry@huawei.com Reviewed-by: Damien Le Moal Reviewed-by: Hannes Reinecke Signed-off-by: Martin K. Petersen --- drivers/scsi/hisi_sas/hisi_sas_main.c | 26 ++++++++------------------ 1 file changed, 8 insertions(+), 18 deletions(-) diff --git a/drivers/scsi/hisi_sas/hisi_sas_main.c b/drivers/scsi/hisi_sas/hisi_sas_main.c index 10813836a728..26e474b0f53f 100644 --- a/drivers/scsi/hisi_sas/hisi_sas_main.c +++ b/drivers/scsi/hisi_sas/hisi_sas_main.c @@ -177,13 +177,13 @@ static void hisi_sas_slot_index_set(struct hisi_hba *hisi_hba, int slot_idx) } static int hisi_sas_slot_index_alloc(struct hisi_hba *hisi_hba, - struct scsi_cmnd *scsi_cmnd) + struct request *rq) { int index; void *bitmap = hisi_hba->slot_index_tags; - if (scsi_cmnd) - return scsi_cmd_to_rq(scsi_cmnd)->tag; + if (rq) + return rq->tag; spin_lock(&hisi_hba->lock); index = find_next_zero_bit(bitmap, hisi_hba->slot_index_count, @@ -461,11 +461,11 @@ static int hisi_sas_queue_command(struct sas_task *task, gfp_t gfp_flags) struct asd_sas_port *sas_port = device->port; struct hisi_sas_device *sas_dev = device->lldd_dev; bool internal_abort = sas_is_internal_abort(task); - struct scsi_cmnd *scmd = NULL; struct hisi_sas_dq *dq = NULL; struct hisi_sas_port *port; struct hisi_hba *hisi_hba; struct hisi_sas_slot *slot; + struct request *rq = NULL; struct device *dev; int rc; @@ -520,22 +520,12 @@ static int hisi_sas_queue_command(struct sas_task *task, gfp_t gfp_flags) return -ECOMM; } - if (task->uldd_task) { - struct ata_queued_cmd *qc; - - if (dev_is_sata(device)) { - qc = task->uldd_task; - scmd = qc->scsicmd; - } else { - scmd = task->uldd_task; - } - } - - if (scmd) { + rq = sas_task_find_rq(task); + if (rq) { unsigned int dq_index; u32 blk_tag; - blk_tag = blk_mq_unique_tag(scsi_cmd_to_rq(scmd)); + blk_tag = blk_mq_unique_tag(rq); dq_index = blk_mq_unique_tag_to_hwq(blk_tag); dq = &hisi_hba->dq[dq_index]; } else { @@ -580,7 +570,7 @@ static int hisi_sas_queue_command(struct sas_task *task, gfp_t gfp_flags) if (!internal_abort && hisi_hba->hw->slot_index_alloc) rc = hisi_hba->hw->slot_index_alloc(hisi_hba, device); else - rc = hisi_sas_slot_index_alloc(hisi_hba, scmd); + rc = hisi_sas_slot_index_alloc(hisi_hba, rq); if (rc < 0) goto err_out_dif_dma_unmap; -- cgit v1.2.3 From f7d190a94e35a2784af8871e275b86e68ff8034a Mon Sep 17 00:00:00 2001 From: John Garry Date: Tue, 18 Oct 2022 19:15:59 +0800 Subject: scsi: hisi_sas: Put reserved tags in lower region of tagset To be consistent with blk-mq, put the reserved tags in the lower region of the tagset. Eventually we hope to get rid of all this reserved tag management. Signed-off-by: John Garry Link: https://lore.kernel.org/r/1666091763-11023-4-git-send-email-john.garry@huawei.com Reviewed-by: Hannes Reinecke Signed-off-by: Martin K. Petersen --- drivers/scsi/hisi_sas/hisi_sas_main.c | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/drivers/scsi/hisi_sas/hisi_sas_main.c b/drivers/scsi/hisi_sas/hisi_sas_main.c index 26e474b0f53f..54860d252466 100644 --- a/drivers/scsi/hisi_sas/hisi_sas_main.c +++ b/drivers/scsi/hisi_sas/hisi_sas_main.c @@ -183,16 +183,16 @@ static int hisi_sas_slot_index_alloc(struct hisi_hba *hisi_hba, void *bitmap = hisi_hba->slot_index_tags; if (rq) - return rq->tag; + return rq->tag + HISI_SAS_RESERVED_IPTT; spin_lock(&hisi_hba->lock); - index = find_next_zero_bit(bitmap, hisi_hba->slot_index_count, + index = find_next_zero_bit(bitmap, HISI_SAS_RESERVED_IPTT, hisi_hba->last_slot_index + 1); - if (index >= hisi_hba->slot_index_count) { + if (index >= HISI_SAS_RESERVED_IPTT) { index = find_next_zero_bit(bitmap, - hisi_hba->slot_index_count, - HISI_SAS_UNRESERVED_IPTT); - if (index >= hisi_hba->slot_index_count) { + HISI_SAS_RESERVED_IPTT, + 0); + if (index >= HISI_SAS_RESERVED_IPTT) { spin_unlock(&hisi_hba->lock); return -SAS_QUEUE_FULL; } @@ -2216,7 +2216,7 @@ int hisi_sas_alloc(struct hisi_hba *hisi_hba) if (!hisi_hba->sata_breakpoint) goto err_out; - hisi_hba->last_slot_index = HISI_SAS_UNRESERVED_IPTT; + hisi_hba->last_slot_index = 0; hisi_hba->wq = create_singlethread_workqueue(dev_name(dev)); if (!hisi_hba->wq) { -- cgit v1.2.3 From 1baa70d36403aa572453eee9fdd4f637455ecaaf Mon Sep 17 00:00:00 2001 From: Igor Pylypiv Date: Tue, 18 Oct 2022 19:16:00 +0800 Subject: scsi: pm8001: Remove pm8001_tag_init() In commit 5a141315ed7c ("scsi: pm80xx: Increase the number of outstanding I/O supported to 1024") the pm8001_ha->tags allocation was moved into pm8001_init_ccb_tag(). This changed the execution order of allocation. pm8001_tag_init() used to be called after the pm8001_ha->tags allocation and now it is called before the allocation. Before: pm8001_pci_probe() `--> pm8001_pci_alloc() `--> pm8001_alloc() `--> pm8001_ha->tags = kzalloc(...) `--> pm8001_tag_init(pm8001_ha); // OK: tags are allocated After: pm8001_pci_probe() `--> pm8001_pci_alloc() | `--> pm8001_alloc() | `--> pm8001_tag_init(pm8001_ha); // NOK: tags are not allocated | `--> pm8001_init_ccb_tag() `--> pm8001_ha->tags = kzalloc(...) // today it is bitmap_zalloc() Since pm8001_ha->tags_num is zero when pm8001_tag_init() is called it does nothing. Tags memory is allocated with bitmap_zalloc() so there is no need to manually clear each bit with pm8001_tag_free(). Reviewed-by: Changyuan Lyu Signed-off-by: Igor Pylypiv Signed-off-by: John Garry Link: https://lore.kernel.org/r/1666091763-11023-5-git-send-email-john.garry@huawei.com Reviewed-by: Damien Le Moal Reviewed-by: Jack Wang Reviewed-by: Hannes Reinecke Signed-off-by: Martin K. Petersen --- drivers/scsi/pm8001/pm8001_init.c | 2 -- drivers/scsi/pm8001/pm8001_sas.c | 7 ------- drivers/scsi/pm8001/pm8001_sas.h | 1 - 3 files changed, 10 deletions(-) diff --git a/drivers/scsi/pm8001/pm8001_init.c b/drivers/scsi/pm8001/pm8001_init.c index 2ff2fac1e403..040a8280f23b 100644 --- a/drivers/scsi/pm8001/pm8001_init.c +++ b/drivers/scsi/pm8001/pm8001_init.c @@ -436,8 +436,6 @@ static int pm8001_alloc(struct pm8001_hba_info *pm8001_ha, atomic_set(&pm8001_ha->devices[i].running_req, 0); } pm8001_ha->flags = PM8001F_INIT_TIME; - /* Initialize tags */ - pm8001_tag_init(pm8001_ha); return 0; err_out_nodev: diff --git a/drivers/scsi/pm8001/pm8001_sas.c b/drivers/scsi/pm8001/pm8001_sas.c index 51230b827149..c9fa3328f3fa 100644 --- a/drivers/scsi/pm8001/pm8001_sas.c +++ b/drivers/scsi/pm8001/pm8001_sas.c @@ -96,13 +96,6 @@ int pm8001_tag_alloc(struct pm8001_hba_info *pm8001_ha, u32 *tag_out) return 0; } -void pm8001_tag_init(struct pm8001_hba_info *pm8001_ha) -{ - int i; - for (i = 0; i < pm8001_ha->tags_num; ++i) - pm8001_tag_free(pm8001_ha, i); -} - /** * pm8001_mem_alloc - allocate memory for pm8001. * @pdev: pci device. diff --git a/drivers/scsi/pm8001/pm8001_sas.h b/drivers/scsi/pm8001/pm8001_sas.h index 16a753d5e8a7..ecb98bc5a8d0 100644 --- a/drivers/scsi/pm8001/pm8001_sas.h +++ b/drivers/scsi/pm8001/pm8001_sas.h @@ -632,7 +632,6 @@ extern struct workqueue_struct *pm8001_wq; /******************** function prototype *********************/ int pm8001_tag_alloc(struct pm8001_hba_info *pm8001_ha, u32 *tag_out); -void pm8001_tag_init(struct pm8001_hba_info *pm8001_ha); u32 pm8001_get_ncq_tag(struct sas_task *task, u32 *tag); void pm8001_ccb_task_free(struct pm8001_hba_info *pm8001_ha, struct pm8001_ccb_info *ccb); -- cgit v1.2.3 From 6472cfb418a0ba783a469deeb6586fb2f133c268 Mon Sep 17 00:00:00 2001 From: John Garry Date: Tue, 18 Oct 2022 19:16:01 +0800 Subject: scsi: pm8001: Use sas_task_find_rq() for tagging The request associated with a SCSI command coming from the block layer has a unique tag, so use that when possible for getting a CCB. Unfortunately we don't support reserved commands in the SCSI midlayer yet, so in the interim continue to manage those tags internally (along with tags for private commands). Signed-off-by: John Garry Link: https://lore.kernel.org/r/1666091763-11023-6-git-send-email-john.garry@huawei.com Reviewed-by: Jack Wang Reviewed-by: Damien Le Moal Reviewed-by: Hannes Reinecke Signed-off-by: Martin K. Petersen --- drivers/scsi/pm8001/pm8001_init.c | 12 ++++-------- drivers/scsi/pm8001/pm8001_sas.c | 13 +++++++++---- drivers/scsi/pm8001/pm8001_sas.h | 11 ++++++++--- drivers/scsi/pm8001/pm80xx_hwi.c | 19 +++---------------- 4 files changed, 24 insertions(+), 31 deletions(-) diff --git a/drivers/scsi/pm8001/pm8001_init.c b/drivers/scsi/pm8001/pm8001_init.c index 040a8280f23b..a1df61205b20 100644 --- a/drivers/scsi/pm8001/pm8001_init.c +++ b/drivers/scsi/pm8001/pm8001_init.c @@ -196,7 +196,7 @@ static void pm8001_free(struct pm8001_hba_info *pm8001_ha) } PM8001_CHIP_DISP->chip_iounmap(pm8001_ha); flush_workqueue(pm8001_wq); - bitmap_free(pm8001_ha->tags); + bitmap_free(pm8001_ha->rsvd_tags); kfree(pm8001_ha); } @@ -1208,18 +1208,15 @@ static int pm8001_init_ccb_tag(struct pm8001_hba_info *pm8001_ha) struct Scsi_Host *shost = pm8001_ha->shost; struct device *dev = pm8001_ha->dev; u32 max_out_io, ccb_count; - u32 can_queue; int i; max_out_io = pm8001_ha->main_cfg_tbl.pm80xx_tbl.max_out_io; ccb_count = min_t(int, PM8001_MAX_CCB, max_out_io); - /* Update to the scsi host*/ - can_queue = ccb_count - PM8001_RESERVE_SLOT; - shost->can_queue = can_queue; + shost->can_queue = ccb_count - PM8001_RESERVE_SLOT; - pm8001_ha->tags = bitmap_zalloc(ccb_count, GFP_KERNEL); - if (!pm8001_ha->tags) + pm8001_ha->rsvd_tags = bitmap_zalloc(PM8001_RESERVE_SLOT, GFP_KERNEL); + if (!pm8001_ha->rsvd_tags) goto err_out; /* Memory region for ccb_info*/ @@ -1244,7 +1241,6 @@ static int pm8001_init_ccb_tag(struct pm8001_hba_info *pm8001_ha) pm8001_ha->ccb_info[i].task = NULL; pm8001_ha->ccb_info[i].ccb_tag = PM8001_INVALID_TAG; pm8001_ha->ccb_info[i].device = NULL; - ++pm8001_ha->tags_num; } return 0; diff --git a/drivers/scsi/pm8001/pm8001_sas.c b/drivers/scsi/pm8001/pm8001_sas.c index c9fa3328f3fa..2359e827c9e6 100644 --- a/drivers/scsi/pm8001/pm8001_sas.c +++ b/drivers/scsi/pm8001/pm8001_sas.c @@ -65,9 +65,12 @@ static int pm8001_find_tag(struct sas_task *task, u32 *tag) */ void pm8001_tag_free(struct pm8001_hba_info *pm8001_ha, u32 tag) { - void *bitmap = pm8001_ha->tags; + void *bitmap = pm8001_ha->rsvd_tags; unsigned long flags; + if (tag >= PM8001_RESERVE_SLOT) + return; + spin_lock_irqsave(&pm8001_ha->bitmap_lock, flags); __clear_bit(tag, bitmap); spin_unlock_irqrestore(&pm8001_ha->bitmap_lock, flags); @@ -80,18 +83,20 @@ void pm8001_tag_free(struct pm8001_hba_info *pm8001_ha, u32 tag) */ int pm8001_tag_alloc(struct pm8001_hba_info *pm8001_ha, u32 *tag_out) { - void *bitmap = pm8001_ha->tags; + void *bitmap = pm8001_ha->rsvd_tags; unsigned long flags; unsigned int tag; spin_lock_irqsave(&pm8001_ha->bitmap_lock, flags); - tag = find_first_zero_bit(bitmap, pm8001_ha->tags_num); - if (tag >= pm8001_ha->tags_num) { + tag = find_first_zero_bit(bitmap, PM8001_RESERVE_SLOT); + if (tag >= PM8001_RESERVE_SLOT) { spin_unlock_irqrestore(&pm8001_ha->bitmap_lock, flags); return -SAS_QUEUE_FULL; } __set_bit(tag, bitmap); spin_unlock_irqrestore(&pm8001_ha->bitmap_lock, flags); + + /* reserved tags are in the lower region of the tagset */ *tag_out = tag; return 0; } diff --git a/drivers/scsi/pm8001/pm8001_sas.h b/drivers/scsi/pm8001/pm8001_sas.h index ecb98bc5a8d0..cf5f1b091959 100644 --- a/drivers/scsi/pm8001/pm8001_sas.h +++ b/drivers/scsi/pm8001/pm8001_sas.h @@ -510,8 +510,7 @@ struct pm8001_hba_info { u32 chip_id; const struct pm8001_chip_info *chip; struct completion *nvmd_completion; - int tags_num; - unsigned long *tags; + unsigned long *rsvd_tags; struct pm8001_phy phy[PM8001_MAX_PHYS]; struct pm8001_port port[PM8001_MAX_PHYS]; u32 id; @@ -736,9 +735,15 @@ pm8001_ccb_alloc(struct pm8001_hba_info *pm8001_ha, struct pm8001_device *dev, struct sas_task *task) { struct pm8001_ccb_info *ccb; + struct request *rq = NULL; u32 tag; - if (pm8001_tag_alloc(pm8001_ha, &tag)) { + if (task) + rq = sas_task_find_rq(task); + + if (rq) { + tag = rq->tag + PM8001_RESERVE_SLOT; + } else if (pm8001_tag_alloc(pm8001_ha, &tag)) { pm8001_dbg(pm8001_ha, FAIL, "Failed to allocate a tag\n"); return NULL; } diff --git a/drivers/scsi/pm8001/pm80xx_hwi.c b/drivers/scsi/pm8001/pm80xx_hwi.c index 4484c498bcb6..bc71db442dd9 100644 --- a/drivers/scsi/pm8001/pm80xx_hwi.c +++ b/drivers/scsi/pm8001/pm80xx_hwi.c @@ -4247,25 +4247,12 @@ static int check_enc_sat_cmd(struct sas_task *task) static u32 pm80xx_chip_get_q_index(struct sas_task *task) { - struct scsi_cmnd *scmd = NULL; - u32 blk_tag; + struct request *rq = sas_task_find_rq(task); - if (task->uldd_task) { - struct ata_queued_cmd *qc; - - if (dev_is_sata(task->dev)) { - qc = task->uldd_task; - scmd = qc->scsicmd; - } else { - scmd = task->uldd_task; - } - } - - if (!scmd) + if (!rq) return 0; - blk_tag = blk_mq_unique_tag(scsi_cmd_to_rq(scmd)); - return blk_mq_unique_tag_to_hwq(blk_tag); + return blk_mq_unique_tag_to_hwq(blk_mq_unique_tag(rq)); } /** -- cgit v1.2.3 From ffc9f9bf3f14876d019f67ef17d41138802529a8 Mon Sep 17 00:00:00 2001 From: John Garry Date: Tue, 18 Oct 2022 19:16:02 +0800 Subject: scsi: mvsas: Delete mvs_tag_init() All mvs_tag_init() does is zero the tag bitmap, but this is already done with the kzalloc() call to alloc the tags, so delete this unneeded function. Signed-off-by: John Garry Link: https://lore.kernel.org/r/1666091763-11023-7-git-send-email-john.garry@huawei.com Reviewed-by: Damien Le Moal Reviewed-by: Hannes Reinecke Signed-off-by: Martin K. Petersen --- drivers/scsi/mvsas/mv_init.c | 2 -- drivers/scsi/mvsas/mv_sas.c | 7 ------- drivers/scsi/mvsas/mv_sas.h | 1 - 3 files changed, 10 deletions(-) diff --git a/drivers/scsi/mvsas/mv_init.c b/drivers/scsi/mvsas/mv_init.c index 2fde496fff5f..c85fb812ad43 100644 --- a/drivers/scsi/mvsas/mv_init.c +++ b/drivers/scsi/mvsas/mv_init.c @@ -286,8 +286,6 @@ static int mvs_alloc(struct mvs_info *mvi, struct Scsi_Host *shost) } mvi->tags_num = slot_nr; - /* Initialize tags */ - mvs_tag_init(mvi); return 0; err_out: return 1; diff --git a/drivers/scsi/mvsas/mv_sas.c b/drivers/scsi/mvsas/mv_sas.c index bf7d4995b257..3aed5e3e0c8c 100644 --- a/drivers/scsi/mvsas/mv_sas.c +++ b/drivers/scsi/mvsas/mv_sas.c @@ -51,13 +51,6 @@ inline int mvs_tag_alloc(struct mvs_info *mvi, u32 *tag_out) return 0; } -void mvs_tag_init(struct mvs_info *mvi) -{ - int i; - for (i = 0; i < mvi->tags_num; ++i) - mvs_tag_clear(mvi, i); -} - static struct mvs_info *mvs_find_dev_mvi(struct domain_device *dev) { unsigned long i = 0, j = 0, hi = 0; diff --git a/drivers/scsi/mvsas/mv_sas.h b/drivers/scsi/mvsas/mv_sas.h index 509d8f32a04f..fe57665bdb50 100644 --- a/drivers/scsi/mvsas/mv_sas.h +++ b/drivers/scsi/mvsas/mv_sas.h @@ -428,7 +428,6 @@ void mvs_tag_clear(struct mvs_info *mvi, u32 tag); void mvs_tag_free(struct mvs_info *mvi, u32 tag); void mvs_tag_set(struct mvs_info *mvi, unsigned int tag); int mvs_tag_alloc(struct mvs_info *mvi, u32 *tag_out); -void mvs_tag_init(struct mvs_info *mvi); void mvs_iounmap(void __iomem *regs); int mvs_ioremap(struct mvs_info *mvi, int bar, int bar_ex); void mvs_phys_reset(struct mvs_info *mvi, u32 phy_mask, int hard); -- cgit v1.2.3 From 2acf97f199f9eba8321390325519e9b6bff60108 Mon Sep 17 00:00:00 2001 From: John Garry Date: Tue, 18 Oct 2022 19:16:03 +0800 Subject: scsi: mvsas: Use sas_task_find_rq() for tagging The request associated with a SCSI command coming from the block layer has a unique tag, so use that when possible for getting a slot. Unfortunately we don't support reserved commands in the SCSI midlayer yet. As such, SMP tasks - as an example - will not have a request associated, so in the interim continue to manage those tags for that type of sas_task internally. We reserve an arbitrary 4 tags for these internal tags. Indeed, we already decrement MVS_RSVD_SLOTS by 2 for the shost can_queue when flag MVF_FLAG_SOC is set. This change was made in commit 20b09c2992fe ("[SCSI] mvsas: add support for 94xx; layout change; bug fixes"), but what those 2 slots are used for is not obvious. Also make the tag management functions static, where possible. Signed-off-by: John Garry Link: https://lore.kernel.org/r/1666091763-11023-8-git-send-email-john.garry@huawei.com Signed-off-by: Martin K. Petersen --- drivers/scsi/mvsas/mv_defs.h | 1 + drivers/scsi/mvsas/mv_init.c | 9 +++++---- drivers/scsi/mvsas/mv_sas.c | 35 ++++++++++++++++++++++------------- drivers/scsi/mvsas/mv_sas.h | 7 +------ 4 files changed, 29 insertions(+), 23 deletions(-) diff --git a/drivers/scsi/mvsas/mv_defs.h b/drivers/scsi/mvsas/mv_defs.h index 7123a2efbf58..8ef174cd4d37 100644 --- a/drivers/scsi/mvsas/mv_defs.h +++ b/drivers/scsi/mvsas/mv_defs.h @@ -40,6 +40,7 @@ enum driver_configuration { MVS_ATA_CMD_SZ = 96, /* SATA command table buffer size */ MVS_OAF_SZ = 64, /* Open address frame buffer size */ MVS_QUEUE_SIZE = 64, /* Support Queue depth */ + MVS_RSVD_SLOTS = 4, MVS_SOC_CAN_QUEUE = MVS_SOC_SLOTS - 2, }; diff --git a/drivers/scsi/mvsas/mv_init.c b/drivers/scsi/mvsas/mv_init.c index c85fb812ad43..cfe84473a515 100644 --- a/drivers/scsi/mvsas/mv_init.c +++ b/drivers/scsi/mvsas/mv_init.c @@ -142,7 +142,7 @@ static void mvs_free(struct mvs_info *mvi) scsi_host_put(mvi->shost); list_for_each_entry(mwq, &mvi->wq_list, entry) cancel_delayed_work(&mwq->work_q); - kfree(mvi->tags); + kfree(mvi->rsvd_tags); kfree(mvi); } @@ -284,7 +284,6 @@ static int mvs_alloc(struct mvs_info *mvi, struct Scsi_Host *shost) printk(KERN_DEBUG "failed to create dma pool %s.\n", pool_name); goto err_out; } - mvi->tags_num = slot_nr; return 0; err_out: @@ -367,8 +366,8 @@ static struct mvs_info *mvs_pci_alloc(struct pci_dev *pdev, mvi->sas = sha; mvi->shost = shost; - mvi->tags = kzalloc(MVS_CHIP_SLOT_SZ>>3, GFP_KERNEL); - if (!mvi->tags) + mvi->rsvd_tags = bitmap_zalloc(MVS_RSVD_SLOTS, GFP_KERNEL); + if (!mvi->rsvd_tags) goto err_out; if (MVS_CHIP_DISP->chip_ioremap(mvi)) @@ -469,6 +468,8 @@ static void mvs_post_sas_ha_init(struct Scsi_Host *shost, else can_queue = MVS_CHIP_SLOT_SZ; + can_queue -= MVS_RSVD_SLOTS; + shost->sg_tablesize = min_t(u16, SG_ALL, MVS_MAX_SG); shost->can_queue = can_queue; mvi->shost->cmd_per_lun = MVS_QUEUE_SIZE; diff --git a/drivers/scsi/mvsas/mv_sas.c b/drivers/scsi/mvsas/mv_sas.c index 3aed5e3e0c8c..9978c424214c 100644 --- a/drivers/scsi/mvsas/mv_sas.c +++ b/drivers/scsi/mvsas/mv_sas.c @@ -20,31 +20,34 @@ static int mvs_find_tag(struct mvs_info *mvi, struct sas_task *task, u32 *tag) return 0; } -void mvs_tag_clear(struct mvs_info *mvi, u32 tag) +static void mvs_tag_clear(struct mvs_info *mvi, u32 tag) { - void *bitmap = mvi->tags; + void *bitmap = mvi->rsvd_tags; clear_bit(tag, bitmap); } -void mvs_tag_free(struct mvs_info *mvi, u32 tag) +static void mvs_tag_free(struct mvs_info *mvi, u32 tag) { + if (tag >= MVS_RSVD_SLOTS) + return; + mvs_tag_clear(mvi, tag); } -void mvs_tag_set(struct mvs_info *mvi, unsigned int tag) +static void mvs_tag_set(struct mvs_info *mvi, unsigned int tag) { - void *bitmap = mvi->tags; + void *bitmap = mvi->rsvd_tags; set_bit(tag, bitmap); } -inline int mvs_tag_alloc(struct mvs_info *mvi, u32 *tag_out) +static int mvs_tag_alloc(struct mvs_info *mvi, u32 *tag_out) { unsigned int index, tag; - void *bitmap = mvi->tags; + void *bitmap = mvi->rsvd_tags; - index = find_first_zero_bit(bitmap, mvi->tags_num); + index = find_first_zero_bit(bitmap, MVS_RSVD_SLOTS); tag = index; - if (tag >= mvi->tags_num) + if (tag >= MVS_RSVD_SLOTS) return -SAS_QUEUE_FULL; mvs_tag_set(mvi, tag); *tag_out = tag; @@ -696,6 +699,7 @@ static int mvs_task_prep(struct sas_task *task, struct mvs_info *mvi, int is_tmf struct mvs_task_exec_info tei; struct mvs_slot_info *slot; u32 tag = 0xdeadbeef, n_elem = 0; + struct request *rq; int rc = 0; if (!dev->port) { @@ -760,9 +764,14 @@ static int mvs_task_prep(struct sas_task *task, struct mvs_info *mvi, int is_tmf n_elem = task->num_scatter; } - rc = mvs_tag_alloc(mvi, &tag); - if (rc) - goto err_out; + rq = sas_task_find_rq(task); + if (rq) { + tag = rq->tag + MVS_RSVD_SLOTS; + } else { + rc = mvs_tag_alloc(mvi, &tag); + if (rc) + goto err_out; + } slot = &mvi->slot_info[tag]; @@ -857,7 +866,7 @@ int mvs_queue_command(struct sas_task *task, gfp_t gfp_flags) static void mvs_slot_free(struct mvs_info *mvi, u32 rx_desc) { u32 slot_idx = rx_desc & RXQ_SLOT_MASK; - mvs_tag_clear(mvi, slot_idx); + mvs_tag_free(mvi, slot_idx); } static void mvs_slot_task_free(struct mvs_info *mvi, struct sas_task *task, diff --git a/drivers/scsi/mvsas/mv_sas.h b/drivers/scsi/mvsas/mv_sas.h index fe57665bdb50..68df771e2975 100644 --- a/drivers/scsi/mvsas/mv_sas.h +++ b/drivers/scsi/mvsas/mv_sas.h @@ -370,8 +370,7 @@ struct mvs_info { u32 chip_id; const struct mvs_chip_info *chip; - int tags_num; - unsigned long *tags; + unsigned long *rsvd_tags; /* further per-slot information */ struct mvs_phy phy[MVS_MAX_PHYS]; struct mvs_port port[MVS_MAX_PHYS]; @@ -424,10 +423,6 @@ struct mvs_task_exec_info { /******************** function prototype *********************/ void mvs_get_sas_addr(void *buf, u32 buflen); -void mvs_tag_clear(struct mvs_info *mvi, u32 tag); -void mvs_tag_free(struct mvs_info *mvi, u32 tag); -void mvs_tag_set(struct mvs_info *mvi, unsigned int tag); -int mvs_tag_alloc(struct mvs_info *mvi, u32 *tag_out); void mvs_iounmap(void __iomem *regs); int mvs_ioremap(struct mvs_info *mvi, int bar, int bar_ex); void mvs_phys_reset(struct mvs_info *mvi, u32 phy_mask, int hard); -- cgit v1.2.3 From 5f62639dc2b668d8fa3bd3d4a92cf6e51b7574c6 Mon Sep 17 00:00:00 2001 From: Igor Pylypiv Date: Fri, 7 Oct 2022 16:07:51 -0700 Subject: scsi: pm80xx: Remove unused reset_in_progress flag logic The reset_in_progress flag was never set. Signed-off-by: Igor Pylypiv Link: https://lore.kernel.org/r/20221007230751.309363-1-ipylypiv@google.com Reviewed-by: Andrew Konecki Acked-by: Jack Wang Signed-off-by: Martin K. Petersen --- drivers/scsi/pm8001/pm8001_sas.h | 1 - drivers/scsi/pm8001/pm80xx_hwi.c | 4 ---- 2 files changed, 5 deletions(-) diff --git a/drivers/scsi/pm8001/pm8001_sas.h b/drivers/scsi/pm8001/pm8001_sas.h index cf5f1b091959..dc1f4d958e03 100644 --- a/drivers/scsi/pm8001/pm8001_sas.h +++ b/drivers/scsi/pm8001/pm8001_sas.h @@ -534,7 +534,6 @@ struct pm8001_hba_info { bool controller_fatal_error; const struct firmware *fw_image; struct isr_param irq_vector[PM8001_MAX_MSIX_VEC]; - u32 reset_in_progress; u32 non_fatal_count; u32 non_fatal_read_length; u32 max_q_num; diff --git a/drivers/scsi/pm8001/pm80xx_hwi.c b/drivers/scsi/pm8001/pm80xx_hwi.c index bc71db442dd9..9584cadc4201 100644 --- a/drivers/scsi/pm8001/pm80xx_hwi.c +++ b/drivers/scsi/pm8001/pm80xx_hwi.c @@ -3440,10 +3440,6 @@ static int mpi_hw_event(struct pm8001_hba_info *pm8001_ha, void *piomb) case HW_EVENT_PHY_DOWN: pm8001_dbg(pm8001_ha, MSG, "HW_EVENT_PHY_DOWN\n"); hw_event_phy_down(pm8001_ha, piomb); - if (pm8001_ha->reset_in_progress) { - pm8001_dbg(pm8001_ha, MSG, "Reset in progress\n"); - return 0; - } phy->phy_attached = 0; phy->phy_state = PHY_LINK_DISABLE; break; -- cgit v1.2.3 From e6f8a22ff4a14aeada44c8f78dfb7503f2ca318f Mon Sep 17 00:00:00 2001 From: Jiapeng Chong Date: Sun, 9 Oct 2022 14:02:49 +0800 Subject: scsi: qedf: Remove set but unused variable 'page' The variable page is not used in the function, so delete it. Link: https://bugzilla.openanolis.cn/show_bug.cgi?id=2348 Reported-by: Abaci Robot Signed-off-by: Jiapeng Chong Link: https://lore.kernel.org/r/20221009060249.40178-1-jiapeng.chong@linux.alibaba.com Signed-off-by: Martin K. Petersen --- drivers/scsi/qedf/qedf_main.c | 3 --- 1 file changed, 3 deletions(-) diff --git a/drivers/scsi/qedf/qedf_main.c b/drivers/scsi/qedf/qedf_main.c index e045c6e25090..35e16600fc63 100644 --- a/drivers/scsi/qedf/qedf_main.c +++ b/drivers/scsi/qedf/qedf_main.c @@ -2951,7 +2951,6 @@ static int qedf_alloc_bdq(struct qedf_ctx *qedf) int i; struct scsi_bd *pbl; u64 *list; - dma_addr_t page; /* Alloc dma memory for BDQ buffers */ for (i = 0; i < QEDF_BDQ_SIZE; i++) { @@ -3012,11 +3011,9 @@ static int qedf_alloc_bdq(struct qedf_ctx *qedf) qedf->bdq_pbl_list_num_entries = qedf->bdq_pbl_mem_size / QEDF_PAGE_SIZE; list = (u64 *)qedf->bdq_pbl_list; - page = qedf->bdq_pbl_list_dma; for (i = 0; i < qedf->bdq_pbl_list_num_entries; i++) { *list = qedf->bdq_pbl_dma; list++; - page += QEDF_PAGE_SIZE; } return 0; -- cgit v1.2.3 From 4fc66e7b16adf054e8dc7a5cd189085b8f545091 Mon Sep 17 00:00:00 2001 From: Justin Tee Date: Mon, 17 Oct 2022 09:43:19 -0700 Subject: scsi: lpfc: Set sli4_param's cmf option to zero when CMF is turned off Add missed clearing of phba->sli4_hba.pc_sli4_params.cmf when CMF is turned off. Signed-off-by: Justin Tee Link: https://lore.kernel.org/r/20221017164323.14536-1-justintee8345@gmail.com Signed-off-by: Martin K. Petersen --- drivers/scsi/lpfc/lpfc_sli.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/scsi/lpfc/lpfc_sli.c b/drivers/scsi/lpfc/lpfc_sli.c index 99d06dc7ddf6..768294b9bc0b 100644 --- a/drivers/scsi/lpfc/lpfc_sli.c +++ b/drivers/scsi/lpfc/lpfc_sli.c @@ -8354,6 +8354,7 @@ no_cmf: phba->cgn_i = NULL; /* Ensure CGN Mode is off */ phba->cmf_active_mode = LPFC_CFG_OFF; + sli4_params->cmf = 0; return 0; } } -- cgit v1.2.3 From c44e50f4a0ec00c2298f31f91bc2c3e9bbd81c7e Mon Sep 17 00:00:00 2001 From: Justin Tee Date: Mon, 17 Oct 2022 09:43:20 -0700 Subject: scsi: lpfc: Fix hard lockup when reading the rx_monitor from debugfs During I/O and simultaneous cat of /sys/kernel/debug/lpfc/fnX/rx_monitor, a hard lockup similar to the call trace below may occur. The spin_lock_bh in lpfc_rx_monitor_report is not protecting from timer interrupts as expected, so change the strength of the spin lock to _irq. Kernel panic - not syncing: Hard LOCKUP CPU: 3 PID: 110402 Comm: cat Kdump: loaded exception RIP: native_queued_spin_lock_slowpath+91 [IRQ stack] native_queued_spin_lock_slowpath at ffffffffb814e30b _raw_spin_lock at ffffffffb89a667a lpfc_rx_monitor_record at ffffffffc0a73a36 [lpfc] lpfc_cmf_timer at ffffffffc0abbc67 [lpfc] __hrtimer_run_queues at ffffffffb8184250 hrtimer_interrupt at ffffffffb8184ab0 smp_apic_timer_interrupt at ffffffffb8a026ba apic_timer_interrupt at ffffffffb8a01c4f [End of IRQ stack] apic_timer_interrupt at ffffffffb8a01c4f lpfc_rx_monitor_report at ffffffffc0a73c80 [lpfc] lpfc_rx_monitor_read at ffffffffc0addde1 [lpfc] full_proxy_read at ffffffffb83e7fc3 vfs_read at ffffffffb833fe71 ksys_read at ffffffffb83402af do_syscall_64 at ffffffffb800430b entry_SYSCALL_64_after_hwframe at ffffffffb8a000ad Signed-off-by: Justin Tee Link: https://lore.kernel.org/r/20221017164323.14536-2-justintee8345@gmail.com Signed-off-by: Martin K. Petersen --- drivers/scsi/lpfc/lpfc_sli.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/scsi/lpfc/lpfc_sli.c b/drivers/scsi/lpfc/lpfc_sli.c index 768294b9bc0b..86ba45ac91c8 100644 --- a/drivers/scsi/lpfc/lpfc_sli.c +++ b/drivers/scsi/lpfc/lpfc_sli.c @@ -8150,10 +8150,10 @@ u32 lpfc_rx_monitor_report(struct lpfc_hba *phba, "IO_cnt", "Info", "BWutil(ms)"); } - /* Needs to be _bh because record is called from timer interrupt + /* Needs to be _irq because record is called from timer interrupt * context */ - spin_lock_bh(ring_lock); + spin_lock_irq(ring_lock); while (*head_idx != *tail_idx) { entry = &ring[*head_idx]; @@ -8197,7 +8197,7 @@ u32 lpfc_rx_monitor_report(struct lpfc_hba *phba, if (cnt >= max_read_entries) break; } - spin_unlock_bh(ring_lock); + spin_unlock_irq(ring_lock); return cnt; } -- cgit v1.2.3 From eaf660e4282ba11239704b2b89ae94feae2010e0 Mon Sep 17 00:00:00 2001 From: Justin Tee Date: Mon, 17 Oct 2022 09:43:21 -0700 Subject: scsi: lpfc: Log when congestion management limits are in effect When bandwidth reduces from or recovers back to 100% due to congestion management, log the event. Signed-off-by: Justin Tee Link: https://lore.kernel.org/r/20221017164323.14536-3-justintee8345@gmail.com Signed-off-by: Martin K. Petersen --- drivers/scsi/lpfc/lpfc_sli.c | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/drivers/scsi/lpfc/lpfc_sli.c b/drivers/scsi/lpfc/lpfc_sli.c index 86ba45ac91c8..d25afc9dde14 100644 --- a/drivers/scsi/lpfc/lpfc_sli.c +++ b/drivers/scsi/lpfc/lpfc_sli.c @@ -1848,6 +1848,18 @@ lpfc_cmf_sync_cmpl(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb, phba->cmf_link_byte_count); bwpcent = div64_u64(bw * 100 + slop, phba->cmf_link_byte_count); + + if (phba->cmf_max_bytes_per_interval < bw && + bwpcent > 95) + lpfc_printf_log(phba, KERN_INFO, LOG_CGN_MGMT, + "6208 Congestion bandwidth " + "limits removed\n"); + else if ((phba->cmf_max_bytes_per_interval > bw) && + ((bwpcent + pcent) <= 100) && ((bwpcent + pcent) > 95)) + lpfc_printf_log(phba, KERN_INFO, LOG_CGN_MGMT, + "6209 Congestion bandwidth " + "limits in effect\n"); + if (asig) { lpfc_printf_log(phba, KERN_INFO, LOG_CGN_MGMT, "6237 BW Threshold %lld%% (%lld): " -- cgit v1.2.3 From 479b0917e4477f49df2e3be454aac3cfa5dec171 Mon Sep 17 00:00:00 2001 From: Justin Tee Date: Mon, 17 Oct 2022 09:43:22 -0700 Subject: scsi: lpfc: Create a sysfs entry called lpfc_xcvr_data for transceiver info The DUMP_MEMORY mailbox command is implemented for page A0 and A2 to retrieve transceiver information from firmware. The mailbox command output is then formatted to print raw data values for userspace to parse via sysfs. Signed-off-by: Justin Tee Link: https://lore.kernel.org/r/20221017164323.14536-4-justintee8345@gmail.com Signed-off-by: Martin K. Petersen --- drivers/scsi/lpfc/lpfc_attr.c | 118 ++++++++++++++++++++++++++++++++++++++ drivers/scsi/lpfc/lpfc_crtn.h | 3 + drivers/scsi/lpfc/lpfc_els.c | 128 ++++++++++++++++++++++++++++++++++++++++++ drivers/scsi/lpfc/lpfc_hw4.h | 5 +- 4 files changed, 252 insertions(+), 2 deletions(-) diff --git a/drivers/scsi/lpfc/lpfc_attr.c b/drivers/scsi/lpfc/lpfc_attr.c index ef1481326fd7..030ad1d59cbd 100644 --- a/drivers/scsi/lpfc/lpfc_attr.c +++ b/drivers/scsi/lpfc/lpfc_attr.c @@ -1877,6 +1877,122 @@ lpfc_set_trunking(struct lpfc_hba *phba, char *buff_out) return 0; } +static ssize_t +lpfc_xcvr_data_show(struct device *dev, struct device_attribute *attr, + char *buf) +{ + struct Scsi_Host *shost = class_to_shost(dev); + struct lpfc_vport *vport = (struct lpfc_vport *)shost->hostdata; + struct lpfc_hba *phba = vport->phba; + int rc; + int len = 0; + struct lpfc_rdp_context *rdp_context; + u16 temperature; + u16 rx_power; + u16 tx_bias; + u16 tx_power; + u16 vcc; + char chbuf[128]; + u16 wavelength = 0; + struct sff_trasnceiver_codes_byte7 *trasn_code_byte7; + + /* Get transceiver information */ + rdp_context = kmalloc(sizeof(*rdp_context), GFP_KERNEL); + + rc = lpfc_get_sfp_info_wait(phba, rdp_context); + if (rc) { + len = scnprintf(buf, PAGE_SIZE - len, "SFP info NA:\n"); + goto out_free_rdp; + } + + strncpy(chbuf, &rdp_context->page_a0[SSF_VENDOR_NAME], 16); + chbuf[16] = 0; + + len = scnprintf(buf, PAGE_SIZE - len, "VendorName:\t%s\n", chbuf); + len += scnprintf(buf + len, PAGE_SIZE - len, + "VendorOUI:\t%02x-%02x-%02x\n", + (uint8_t)rdp_context->page_a0[SSF_VENDOR_OUI], + (uint8_t)rdp_context->page_a0[SSF_VENDOR_OUI + 1], + (uint8_t)rdp_context->page_a0[SSF_VENDOR_OUI + 2]); + strncpy(chbuf, &rdp_context->page_a0[SSF_VENDOR_PN], 16); + chbuf[16] = 0; + len += scnprintf(buf + len, PAGE_SIZE - len, "VendorPN:\t%s\n", chbuf); + strncpy(chbuf, &rdp_context->page_a0[SSF_VENDOR_SN], 16); + chbuf[16] = 0; + len += scnprintf(buf + len, PAGE_SIZE - len, "VendorSN:\t%s\n", chbuf); + strncpy(chbuf, &rdp_context->page_a0[SSF_VENDOR_REV], 4); + chbuf[4] = 0; + len += scnprintf(buf + len, PAGE_SIZE - len, "VendorRev:\t%s\n", chbuf); + strncpy(chbuf, &rdp_context->page_a0[SSF_DATE_CODE], 8); + chbuf[8] = 0; + len += scnprintf(buf + len, PAGE_SIZE - len, "DateCode:\t%s\n", chbuf); + len += scnprintf(buf + len, PAGE_SIZE - len, "Identifier:\t%xh\n", + (uint8_t)rdp_context->page_a0[SSF_IDENTIFIER]); + len += scnprintf(buf + len, PAGE_SIZE - len, "ExtIdentifier:\t%xh\n", + (uint8_t)rdp_context->page_a0[SSF_EXT_IDENTIFIER]); + len += scnprintf(buf + len, PAGE_SIZE - len, "Connector:\t%xh\n", + (uint8_t)rdp_context->page_a0[SSF_CONNECTOR]); + wavelength = (rdp_context->page_a0[SSF_WAVELENGTH_B1] << 8) | + rdp_context->page_a0[SSF_WAVELENGTH_B0]; + + len += scnprintf(buf + len, PAGE_SIZE - len, "Wavelength:\t%d nm\n", + wavelength); + trasn_code_byte7 = (struct sff_trasnceiver_codes_byte7 *) + &rdp_context->page_a0[SSF_TRANSCEIVER_CODE_B7]; + + len += scnprintf(buf + len, PAGE_SIZE - len, "Speeds: \t"); + if (*(uint8_t *)trasn_code_byte7 == 0) { + len += scnprintf(buf + len, PAGE_SIZE - len, + "Unknown\n"); + } else { + if (trasn_code_byte7->fc_sp_100MB) + len += scnprintf(buf + len, PAGE_SIZE - len, + "1 "); + if (trasn_code_byte7->fc_sp_200mb) + len += scnprintf(buf + len, PAGE_SIZE - len, + "2 "); + if (trasn_code_byte7->fc_sp_400MB) + len += scnprintf(buf + len, PAGE_SIZE - len, + "4 "); + if (trasn_code_byte7->fc_sp_800MB) + len += scnprintf(buf + len, PAGE_SIZE - len, + "8 "); + if (trasn_code_byte7->fc_sp_1600MB) + len += scnprintf(buf + len, PAGE_SIZE - len, + "16 "); + if (trasn_code_byte7->fc_sp_3200MB) + len += scnprintf(buf + len, PAGE_SIZE - len, + "32 "); + if (trasn_code_byte7->speed_chk_ecc) + len += scnprintf(buf + len, PAGE_SIZE - len, + "64 "); + len += scnprintf(buf + len, PAGE_SIZE - len, "GB\n"); + } + temperature = (rdp_context->page_a2[SFF_TEMPERATURE_B1] << 8 | + rdp_context->page_a2[SFF_TEMPERATURE_B0]); + vcc = (rdp_context->page_a2[SFF_VCC_B1] << 8 | + rdp_context->page_a2[SFF_VCC_B0]); + tx_power = (rdp_context->page_a2[SFF_TXPOWER_B1] << 8 | + rdp_context->page_a2[SFF_TXPOWER_B0]); + tx_bias = (rdp_context->page_a2[SFF_TX_BIAS_CURRENT_B1] << 8 | + rdp_context->page_a2[SFF_TX_BIAS_CURRENT_B0]); + rx_power = (rdp_context->page_a2[SFF_RXPOWER_B1] << 8 | + rdp_context->page_a2[SFF_RXPOWER_B0]); + + len += scnprintf(buf + len, PAGE_SIZE - len, + "Temperature:\tx%04x C\n", temperature); + len += scnprintf(buf + len, PAGE_SIZE - len, "Vcc:\t\tx%04x V\n", vcc); + len += scnprintf(buf + len, PAGE_SIZE - len, + "TxBiasCurrent:\tx%04x mA\n", tx_bias); + len += scnprintf(buf + len, PAGE_SIZE - len, "TxPower:\tx%04x mW\n", + tx_power); + len += scnprintf(buf + len, PAGE_SIZE - len, "RxPower:\tx%04x mW\n", + rx_power); +out_free_rdp: + kfree(rdp_context); + return len; +} + /** * lpfc_board_mode_show - Return the state of the board * @dev: class device that is converted into a Scsi_host. @@ -2810,6 +2926,7 @@ static DEVICE_ATTR_RO(lpfc_drvr_version); static DEVICE_ATTR_RO(lpfc_enable_fip); static DEVICE_ATTR(board_mode, S_IRUGO | S_IWUSR, lpfc_board_mode_show, lpfc_board_mode_store); +static DEVICE_ATTR_RO(lpfc_xcvr_data); static DEVICE_ATTR(issue_reset, S_IWUSR, NULL, lpfc_issue_reset); static DEVICE_ATTR(max_vpi, S_IRUGO, lpfc_max_vpi_show, NULL); static DEVICE_ATTR(used_vpi, S_IRUGO, lpfc_used_vpi_show, NULL); @@ -5906,6 +6023,7 @@ static struct attribute *lpfc_hba_attrs[] = { &dev_attr_lpfc_fcp_wait_abts_rsp.attr, &dev_attr_nport_evt_cnt.attr, &dev_attr_board_mode.attr, + &dev_attr_lpfc_xcvr_data.attr, &dev_attr_max_vpi.attr, &dev_attr_used_vpi.attr, &dev_attr_max_rpi.attr, diff --git a/drivers/scsi/lpfc/lpfc_crtn.h b/drivers/scsi/lpfc/lpfc_crtn.h index d2d207791056..8928f016d09e 100644 --- a/drivers/scsi/lpfc/lpfc_crtn.h +++ b/drivers/scsi/lpfc/lpfc_crtn.h @@ -687,3 +687,6 @@ int lpfc_issue_els_qfpa(struct lpfc_vport *vport); void lpfc_sli_rpi_release(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp); + +int lpfc_get_sfp_info_wait(struct lpfc_hba *phba, + struct lpfc_rdp_context *rdp_context); diff --git a/drivers/scsi/lpfc/lpfc_els.c b/drivers/scsi/lpfc/lpfc_els.c index 863b2125fed6..2b03210264bb 100644 --- a/drivers/scsi/lpfc/lpfc_els.c +++ b/drivers/scsi/lpfc/lpfc_els.c @@ -7190,6 +7190,134 @@ rdp_fail: return 1; } +int lpfc_get_sfp_info_wait(struct lpfc_hba *phba, + struct lpfc_rdp_context *rdp_context) +{ + LPFC_MBOXQ_t *mbox = NULL; + int rc; + struct lpfc_dmabuf *mp; + struct lpfc_dmabuf *mpsave; + void *virt; + MAILBOX_t *mb; + + mbox = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL); + if (!mbox) { + lpfc_printf_log(phba, KERN_WARNING, LOG_MBOX | LOG_ELS, + "7205 failed to allocate mailbox memory"); + return 1; + } + + if (lpfc_sli4_dump_page_a0(phba, mbox)) + goto sfp_fail; + mp = mbox->ctx_buf; + mpsave = mp; + virt = mp->virt; + if (phba->sli_rev < LPFC_SLI_REV4) { + mb = &mbox->u.mb; + mb->un.varDmp.cv = 1; + mb->un.varDmp.co = 1; + mb->un.varWords[2] = 0; + mb->un.varWords[3] = DMP_SFF_PAGE_A0_SIZE / 4; + mb->un.varWords[4] = 0; + mb->un.varWords[5] = 0; + mb->un.varWords[6] = 0; + mb->un.varWords[7] = 0; + mb->un.varWords[8] = 0; + mb->un.varWords[9] = 0; + mb->un.varWords[10] = 0; + mbox->in_ext_byte_len = DMP_SFF_PAGE_A0_SIZE; + mbox->out_ext_byte_len = DMP_SFF_PAGE_A0_SIZE; + mbox->mbox_offset_word = 5; + mbox->ctx_buf = virt; + } else { + bf_set(lpfc_mbx_memory_dump_type3_length, + &mbox->u.mqe.un.mem_dump_type3, DMP_SFF_PAGE_A0_SIZE); + mbox->u.mqe.un.mem_dump_type3.addr_lo = putPaddrLow(mp->phys); + mbox->u.mqe.un.mem_dump_type3.addr_hi = putPaddrHigh(mp->phys); + } + mbox->vport = phba->pport; + mbox->ctx_ndlp = (struct lpfc_rdp_context *)rdp_context; + + rc = lpfc_sli_issue_mbox_wait(phba, mbox, 30); + if (rc == MBX_NOT_FINISHED) { + rc = 1; + goto error; + } + + if (phba->sli_rev == LPFC_SLI_REV4) + mp = (struct lpfc_dmabuf *)(mbox->ctx_buf); + else + mp = mpsave; + + if (bf_get(lpfc_mqe_status, &mbox->u.mqe)) { + rc = 1; + goto error; + } + + lpfc_sli_bemem_bcopy(mp->virt, &rdp_context->page_a0, + DMP_SFF_PAGE_A0_SIZE); + + memset(mbox, 0, sizeof(*mbox)); + memset(mp->virt, 0, DMP_SFF_PAGE_A2_SIZE); + INIT_LIST_HEAD(&mp->list); + + /* save address for completion */ + mbox->ctx_buf = mp; + mbox->vport = phba->pport; + + bf_set(lpfc_mqe_command, &mbox->u.mqe, MBX_DUMP_MEMORY); + bf_set(lpfc_mbx_memory_dump_type3_type, + &mbox->u.mqe.un.mem_dump_type3, DMP_LMSD); + bf_set(lpfc_mbx_memory_dump_type3_link, + &mbox->u.mqe.un.mem_dump_type3, phba->sli4_hba.physical_port); + bf_set(lpfc_mbx_memory_dump_type3_page_no, + &mbox->u.mqe.un.mem_dump_type3, DMP_PAGE_A2); + if (phba->sli_rev < LPFC_SLI_REV4) { + mb = &mbox->u.mb; + mb->un.varDmp.cv = 1; + mb->un.varDmp.co = 1; + mb->un.varWords[2] = 0; + mb->un.varWords[3] = DMP_SFF_PAGE_A2_SIZE / 4; + mb->un.varWords[4] = 0; + mb->un.varWords[5] = 0; + mb->un.varWords[6] = 0; + mb->un.varWords[7] = 0; + mb->un.varWords[8] = 0; + mb->un.varWords[9] = 0; + mb->un.varWords[10] = 0; + mbox->in_ext_byte_len = DMP_SFF_PAGE_A2_SIZE; + mbox->out_ext_byte_len = DMP_SFF_PAGE_A2_SIZE; + mbox->mbox_offset_word = 5; + mbox->ctx_buf = virt; + } else { + bf_set(lpfc_mbx_memory_dump_type3_length, + &mbox->u.mqe.un.mem_dump_type3, DMP_SFF_PAGE_A2_SIZE); + mbox->u.mqe.un.mem_dump_type3.addr_lo = putPaddrLow(mp->phys); + mbox->u.mqe.un.mem_dump_type3.addr_hi = putPaddrHigh(mp->phys); + } + + mbox->ctx_ndlp = (struct lpfc_rdp_context *)rdp_context; + rc = lpfc_sli_issue_mbox_wait(phba, mbox, 30); + if (bf_get(lpfc_mqe_status, &mbox->u.mqe)) { + rc = 1; + goto error; + } + rc = 0; + + lpfc_sli_bemem_bcopy(mp->virt, &rdp_context->page_a2, + DMP_SFF_PAGE_A2_SIZE); + +error: + mbox->ctx_buf = mpsave; + lpfc_mbox_rsrc_cleanup(phba, mbox, MBOX_THD_UNLOCKED); + + return rc; + +sfp_fail: + mempool_free(mbox, phba->mbox_mem_pool); + return 1; +} + /* * lpfc_els_rcv_rdp - Process an unsolicited RDP ELS. * @vport: pointer to a host virtual N_Port data structure. diff --git a/drivers/scsi/lpfc/lpfc_hw4.h b/drivers/scsi/lpfc/lpfc_hw4.h index 5288fc69908a..fb3504dbb899 100644 --- a/drivers/scsi/lpfc/lpfc_hw4.h +++ b/drivers/scsi/lpfc/lpfc_hw4.h @@ -3162,7 +3162,8 @@ struct lpfc_mbx_memory_dump_type3 { #define SFF_LENGTH_COPPER 18 #define SSF_LENGTH_50UM_OM3 19 #define SSF_VENDOR_NAME 20 -#define SSF_VENDOR_OUI 36 +#define SSF_TRANSCEIVER2 36 +#define SSF_VENDOR_OUI 37 #define SSF_VENDOR_PN 40 #define SSF_VENDOR_REV 56 #define SSF_WAVELENGTH_B1 60 @@ -3281,7 +3282,7 @@ struct sff_trasnceiver_codes_byte6 { struct sff_trasnceiver_codes_byte7 { uint8_t fc_sp_100MB:1; /* 100 MB/sec */ - uint8_t reserve:1; + uint8_t speed_chk_ecc:1; uint8_t fc_sp_200mb:1; /* 200 MB/sec */ uint8_t fc_sp_3200MB:1; /* 3200 MB/sec */ uint8_t fc_sp_400MB:1; /* 400 MB/sec */ -- cgit v1.2.3 From 24b3e45ca9c53185baec34488efcb75bbe162f7a Mon Sep 17 00:00:00 2001 From: Justin Tee Date: Mon, 17 Oct 2022 09:43:23 -0700 Subject: scsi: lpfc: Update lpfc version to 14.2.0.8 Update lpfc version to 14.2.0.8 Signed-off-by: Justin Tee Link: https://lore.kernel.org/r/20221017164323.14536-5-justintee8345@gmail.com Signed-off-by: Martin K. Petersen --- drivers/scsi/lpfc/lpfc_version.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/scsi/lpfc/lpfc_version.h b/drivers/scsi/lpfc/lpfc_version.h index 192d5630a44d..378eba7b09d9 100644 --- a/drivers/scsi/lpfc/lpfc_version.h +++ b/drivers/scsi/lpfc/lpfc_version.h @@ -20,7 +20,7 @@ * included with this package. * *******************************************************************/ -#define LPFC_DRIVER_VERSION "14.2.0.7" +#define LPFC_DRIVER_VERSION "14.2.0.8" #define LPFC_DRIVER_NAME "lpfc" /* Used for SLI 2/3 */ -- cgit v1.2.3 From 978b7922d3dca672b41bb4b8ce6c06ab77112741 Mon Sep 17 00:00:00 2001 From: Bart Van Assche Date: Tue, 18 Oct 2022 13:29:49 -0700 Subject: scsi: core: Fix a race between scsi_done() and scsi_timeout() If there is a race between scsi_done() and scsi_timeout() and if scsi_timeout() loses the race, scsi_timeout() should not reset the request timer. Hence change the return value for this case from BLK_EH_RESET_TIMER into BLK_EH_DONE. Although the block layer holds a reference on a request (req->ref) while calling a timeout handler, restarting the timer (blk_add_timer()) while a request is being completed is racy. Reviewed-by: Mike Christie Cc: Keith Busch Cc: Christoph Hellwig Cc: Ming Lei Cc: John Garry Cc: Hannes Reinecke Reported-by: Adrian Hunter Fixes: 15f73f5b3e59 ("blk-mq: move failure injection out of blk_mq_complete_request") Signed-off-by: Bart Van Assche Link: https://lore.kernel.org/r/20221018202958.1902564-2-bvanassche@acm.org Signed-off-by: Martin K. Petersen --- drivers/scsi/scsi_error.c | 14 +++----------- 1 file changed, 3 insertions(+), 11 deletions(-) diff --git a/drivers/scsi/scsi_error.c b/drivers/scsi/scsi_error.c index 6995c8979230..02520f912306 100644 --- a/drivers/scsi/scsi_error.c +++ b/drivers/scsi/scsi_error.c @@ -343,19 +343,11 @@ enum blk_eh_timer_return scsi_timeout(struct request *req) if (rtn == BLK_EH_DONE) { /* - * Set the command to complete first in order to prevent a real - * completion from releasing the command while error handling - * is using it. If the command was already completed, then the - * lower level driver beat the timeout handler, and it is safe - * to return without escalating error recovery. - * - * If timeout handling lost the race to a real completion, the - * block layer may ignore that due to a fake timeout injection, - * so return RESET_TIMER to allow error handling another shot - * at this command. + * If scsi_done() has already set SCMD_STATE_COMPLETE, do not + * modify *scmd. */ if (test_and_set_bit(SCMD_STATE_COMPLETE, &scmd->state)) - return BLK_EH_RESET_TIMER; + return BLK_EH_DONE; if (scsi_abort_command(scmd) != SUCCESS) { set_host_byte(scmd, DID_TIME_OUT); scsi_eh_scmd_add(scmd); -- cgit v1.2.3 From dee7121e8c0a3ce41af2b02d516f54eaec32abcd Mon Sep 17 00:00:00 2001 From: Bart Van Assche Date: Tue, 18 Oct 2022 13:29:50 -0700 Subject: scsi: core: Change the return type of .eh_timed_out() Commit 6600593cbd93 ("block: rename BLK_EH_NOT_HANDLED to BLK_EH_DONE") made it impossible for .eh_timed_out() implementations to call scsi_done() without causing a crash. Restore support for SCSI timeout handlers to call scsi_done() as follows: * Change all .eh_timed_out() handlers as follows: - Change the return type into enum scsi_timeout_action. - Change BLK_EH_RESET_TIMER into SCSI_EH_RESET_TIMER. - Change BLK_EH_DONE into SCSI_EH_NOT_HANDLED. * In scsi_timeout(), convert the SCSI_EH_* values into BLK_EH_* values. Reviewed-by: Lee Duncan Cc: Christoph Hellwig Cc: Ming Lei Cc: John Garry Cc: Mike Christie Cc: Hannes Reinecke Signed-off-by: Bart Van Assche Link: https://lore.kernel.org/r/20221018202958.1902564-3-bvanassche@acm.org Reviewed-by: Mike Christie Signed-off-by: Martin K. Petersen --- Documentation/scsi/scsi_eh.rst | 7 +++++-- drivers/message/fusion/mptsas.c | 8 ++++---- drivers/scsi/libiscsi.c | 26 ++++++++++++------------ drivers/scsi/megaraid/megaraid_sas_base.c | 7 +++---- drivers/scsi/mvumi.c | 4 ++-- drivers/scsi/qla4xxx/ql4_os.c | 8 ++++---- drivers/scsi/scsi_error.c | 33 ++++++++++++++++++------------- drivers/scsi/scsi_transport_fc.c | 7 +++---- drivers/scsi/scsi_transport_srp.c | 8 ++++---- drivers/scsi/storvsc_drv.c | 4 ++-- drivers/scsi/virtio_scsi.c | 4 ++-- include/scsi/libiscsi.h | 2 +- include/scsi/scsi_host.h | 14 ++++++++++++- include/scsi/scsi_transport_fc.h | 2 +- include/scsi/scsi_transport_srp.h | 2 +- 15 files changed, 77 insertions(+), 59 deletions(-) diff --git a/Documentation/scsi/scsi_eh.rst b/Documentation/scsi/scsi_eh.rst index bad624fab823..104d09e9af09 100644 --- a/Documentation/scsi/scsi_eh.rst +++ b/Documentation/scsi/scsi_eh.rst @@ -92,14 +92,17 @@ The timeout handler is scsi_timeout(). When a timeout occurs, this function 1. invokes optional hostt->eh_timed_out() callback. Return value can be one of - - BLK_EH_RESET_TIMER + - SCSI_EH_RESET_TIMER This indicates that more time is required to finish the command. Timer is restarted. - - BLK_EH_DONE + - SCSI_EH_NOT_HANDLED eh_timed_out() callback did not handle the command. Step #2 is taken. + - SCSI_EH_DONE + eh_timed_out() completed the command. + 2. scsi_abort_command() is invoked to schedule an asynchronous abort which may issue a retry scmd->allowed + 1 times. Asynchronous aborts are not invoked for commands for which the SCSI_EH_ABORT_SCHEDULED flag is set (this diff --git a/drivers/message/fusion/mptsas.c b/drivers/message/fusion/mptsas.c index 34901bcd1ce8..88fe4a860ae5 100644 --- a/drivers/message/fusion/mptsas.c +++ b/drivers/message/fusion/mptsas.c @@ -1952,12 +1952,12 @@ mptsas_qcmd(struct Scsi_Host *shost, struct scsi_cmnd *SCpnt) * @sc: scsi command that the midlayer is about to time out * **/ -static enum blk_eh_timer_return mptsas_eh_timed_out(struct scsi_cmnd *sc) +static enum scsi_timeout_action mptsas_eh_timed_out(struct scsi_cmnd *sc) { MPT_SCSI_HOST *hd; MPT_ADAPTER *ioc; VirtDevice *vdevice; - enum blk_eh_timer_return rc = BLK_EH_DONE; + enum scsi_timeout_action rc = SCSI_EH_NOT_HANDLED; hd = shost_priv(sc->device->host); if (hd == NULL) { @@ -1980,7 +1980,7 @@ static enum blk_eh_timer_return mptsas_eh_timed_out(struct scsi_cmnd *sc) dtmprintk(ioc, printk(MYIOC_s_WARN_FMT ": %s: ioc is in reset," "SML need to reset the timer (sc=%p)\n", ioc->name, __func__, sc)); - rc = BLK_EH_RESET_TIMER; + rc = SCSI_EH_RESET_TIMER; } vdevice = sc->device->hostdata; if (vdevice && vdevice->vtarget && (vdevice->vtarget->inDMD @@ -1988,7 +1988,7 @@ static enum blk_eh_timer_return mptsas_eh_timed_out(struct scsi_cmnd *sc) dtmprintk(ioc, printk(MYIOC_s_WARN_FMT ": %s: target removed " "or in device removal delay (sc=%p)\n", ioc->name, __func__, sc)); - rc = BLK_EH_RESET_TIMER; + rc = SCSI_EH_RESET_TIMER; goto done; } diff --git a/drivers/scsi/libiscsi.c b/drivers/scsi/libiscsi.c index d95f4bcdeb2e..ef2fc860257e 100644 --- a/drivers/scsi/libiscsi.c +++ b/drivers/scsi/libiscsi.c @@ -2071,9 +2071,9 @@ static int iscsi_has_ping_timed_out(struct iscsi_conn *conn) return 0; } -enum blk_eh_timer_return iscsi_eh_cmd_timed_out(struct scsi_cmnd *sc) +enum scsi_timeout_action iscsi_eh_cmd_timed_out(struct scsi_cmnd *sc) { - enum blk_eh_timer_return rc = BLK_EH_DONE; + enum scsi_timeout_action rc = SCSI_EH_NOT_HANDLED; struct iscsi_task *task = NULL, *running_task; struct iscsi_cls_session *cls_session; struct iscsi_session *session; @@ -2093,7 +2093,7 @@ enum blk_eh_timer_return iscsi_eh_cmd_timed_out(struct scsi_cmnd *sc) * Raced with completion. Blk layer has taken ownership * so let timeout code complete it now. */ - rc = BLK_EH_DONE; + rc = SCSI_EH_NOT_HANDLED; spin_unlock(&session->back_lock); goto done; } @@ -2102,7 +2102,7 @@ enum blk_eh_timer_return iscsi_eh_cmd_timed_out(struct scsi_cmnd *sc) * Racing with the completion path right now, so give it more * time so that path can complete it like normal. */ - rc = BLK_EH_RESET_TIMER; + rc = SCSI_EH_RESET_TIMER; task = NULL; spin_unlock(&session->back_lock); goto done; @@ -2120,21 +2120,21 @@ enum blk_eh_timer_return iscsi_eh_cmd_timed_out(struct scsi_cmnd *sc) if (unlikely(system_state != SYSTEM_RUNNING)) { sc->result = DID_NO_CONNECT << 16; ISCSI_DBG_EH(session, "sc on shutdown, handled\n"); - rc = BLK_EH_DONE; + rc = SCSI_EH_NOT_HANDLED; goto done; } /* * We are probably in the middle of iscsi recovery so let * that complete and handle the error. */ - rc = BLK_EH_RESET_TIMER; + rc = SCSI_EH_RESET_TIMER; goto done; } conn = session->leadconn; if (!conn) { /* In the middle of shuting down */ - rc = BLK_EH_RESET_TIMER; + rc = SCSI_EH_RESET_TIMER; goto done; } @@ -2151,7 +2151,7 @@ enum blk_eh_timer_return iscsi_eh_cmd_timed_out(struct scsi_cmnd *sc) "Last data xfer at %lu. Last timeout was at " "%lu\n.", task->last_xfer, task->last_timeout); task->have_checked_conn = false; - rc = BLK_EH_RESET_TIMER; + rc = SCSI_EH_RESET_TIMER; goto done; } @@ -2162,7 +2162,7 @@ enum blk_eh_timer_return iscsi_eh_cmd_timed_out(struct scsi_cmnd *sc) * and can let the iscsi eh handle it */ if (iscsi_has_ping_timed_out(conn)) { - rc = BLK_EH_RESET_TIMER; + rc = SCSI_EH_RESET_TIMER; goto done; } @@ -2200,7 +2200,7 @@ enum blk_eh_timer_return iscsi_eh_cmd_timed_out(struct scsi_cmnd *sc) task->last_xfer, running_task->last_xfer, task->last_timeout); spin_unlock(&session->back_lock); - rc = BLK_EH_RESET_TIMER; + rc = SCSI_EH_RESET_TIMER; goto done; } } @@ -2216,14 +2216,14 @@ enum blk_eh_timer_return iscsi_eh_cmd_timed_out(struct scsi_cmnd *sc) */ if (READ_ONCE(conn->ping_task)) { task->have_checked_conn = true; - rc = BLK_EH_RESET_TIMER; + rc = SCSI_EH_RESET_TIMER; goto done; } /* Make sure there is a transport check done */ iscsi_send_nopout(conn, NULL); task->have_checked_conn = true; - rc = BLK_EH_RESET_TIMER; + rc = SCSI_EH_RESET_TIMER; done: spin_unlock_bh(&session->frwd_lock); @@ -2232,7 +2232,7 @@ done: task->last_timeout = jiffies; iscsi_put_task(task); } - ISCSI_DBG_EH(session, "return %s\n", rc == BLK_EH_RESET_TIMER ? + ISCSI_DBG_EH(session, "return %s\n", rc == SCSI_EH_RESET_TIMER ? "timer reset" : "shutdown or nh"); return rc; } diff --git a/drivers/scsi/megaraid/megaraid_sas_base.c b/drivers/scsi/megaraid/megaraid_sas_base.c index 9be4ba61a076..6940043a91ae 100644 --- a/drivers/scsi/megaraid/megaraid_sas_base.c +++ b/drivers/scsi/megaraid/megaraid_sas_base.c @@ -2927,15 +2927,14 @@ static int megasas_generic_reset(struct scsi_cmnd *scmd) * Sets the FW busy flag and reduces the host->can_queue if the * cmd has not been completed within the timeout period. */ -static enum -blk_eh_timer_return megasas_reset_timer(struct scsi_cmnd *scmd) +static enum scsi_timeout_action megasas_reset_timer(struct scsi_cmnd *scmd) { struct megasas_instance *instance; unsigned long flags; if (time_after(jiffies, scmd->jiffies_at_alloc + (scmd_timeout * 2) * HZ)) { - return BLK_EH_DONE; + return SCSI_EH_NOT_HANDLED; } instance = (struct megasas_instance *)scmd->device->host->hostdata; @@ -2949,7 +2948,7 @@ blk_eh_timer_return megasas_reset_timer(struct scsi_cmnd *scmd) spin_unlock_irqrestore(instance->host->host_lock, flags); } - return BLK_EH_RESET_TIMER; + return SCSI_EH_RESET_TIMER; } /** diff --git a/drivers/scsi/mvumi.c b/drivers/scsi/mvumi.c index 05d3ce9b72db..b3dcb8918618 100644 --- a/drivers/scsi/mvumi.c +++ b/drivers/scsi/mvumi.c @@ -2109,7 +2109,7 @@ out_return_cmd: return 0; } -static enum blk_eh_timer_return mvumi_timed_out(struct scsi_cmnd *scmd) +static enum scsi_timeout_action mvumi_timed_out(struct scsi_cmnd *scmd) { struct mvumi_cmd *cmd = mvumi_priv(scmd)->cmd_priv; struct Scsi_Host *host = scmd->device->host; @@ -2137,7 +2137,7 @@ static enum blk_eh_timer_return mvumi_timed_out(struct scsi_cmnd *scmd) mvumi_return_cmd(mhba, cmd); spin_unlock_irqrestore(mhba->shost->host_lock, flags); - return BLK_EH_DONE; + return SCSI_EH_NOT_HANDLED; } static int diff --git a/drivers/scsi/qla4xxx/ql4_os.c b/drivers/scsi/qla4xxx/ql4_os.c index 9e849f6b0d0f..005502125b27 100644 --- a/drivers/scsi/qla4xxx/ql4_os.c +++ b/drivers/scsi/qla4xxx/ql4_os.c @@ -116,7 +116,7 @@ static int qla4xxx_iface_set_param(struct Scsi_Host *shost, void *data, static int qla4xxx_get_iface_param(struct iscsi_iface *iface, enum iscsi_param_type param_type, int param, char *buf); -static enum blk_eh_timer_return qla4xxx_eh_cmd_timed_out(struct scsi_cmnd *sc); +static enum scsi_timeout_action qla4xxx_eh_cmd_timed_out(struct scsi_cmnd *sc); static struct iscsi_endpoint *qla4xxx_ep_connect(struct Scsi_Host *shost, struct sockaddr *dst_addr, int non_blocking); @@ -1871,17 +1871,17 @@ exit_get_stats: return; } -static enum blk_eh_timer_return qla4xxx_eh_cmd_timed_out(struct scsi_cmnd *sc) +static enum scsi_timeout_action qla4xxx_eh_cmd_timed_out(struct scsi_cmnd *sc) { struct iscsi_cls_session *session; unsigned long flags; - enum blk_eh_timer_return ret = BLK_EH_DONE; + enum scsi_timeout_action ret = SCSI_EH_NOT_HANDLED; session = starget_to_session(scsi_target(sc->device)); spin_lock_irqsave(&session->lock, flags); if (session->state == ISCSI_SESSION_FAILED) - ret = BLK_EH_RESET_TIMER; + ret = SCSI_EH_RESET_TIMER; spin_unlock_irqrestore(&session->lock, flags); return ret; diff --git a/drivers/scsi/scsi_error.c b/drivers/scsi/scsi_error.c index 02520f912306..be2a70c5ac6d 100644 --- a/drivers/scsi/scsi_error.c +++ b/drivers/scsi/scsi_error.c @@ -328,7 +328,6 @@ void scsi_eh_scmd_add(struct scsi_cmnd *scmd) enum blk_eh_timer_return scsi_timeout(struct request *req) { struct scsi_cmnd *scmd = blk_mq_rq_to_pdu(req); - enum blk_eh_timer_return rtn = BLK_EH_DONE; struct Scsi_Host *host = scmd->device->host; trace_scsi_dispatch_cmd_timeout(scmd); @@ -338,23 +337,29 @@ enum blk_eh_timer_return scsi_timeout(struct request *req) if (host->eh_deadline != -1 && !host->last_reset) host->last_reset = jiffies; - if (host->hostt->eh_timed_out) - rtn = host->hostt->eh_timed_out(scmd); - - if (rtn == BLK_EH_DONE) { - /* - * If scsi_done() has already set SCMD_STATE_COMPLETE, do not - * modify *scmd. - */ - if (test_and_set_bit(SCMD_STATE_COMPLETE, &scmd->state)) + if (host->hostt->eh_timed_out) { + switch (host->hostt->eh_timed_out(scmd)) { + case SCSI_EH_DONE: return BLK_EH_DONE; - if (scsi_abort_command(scmd) != SUCCESS) { - set_host_byte(scmd, DID_TIME_OUT); - scsi_eh_scmd_add(scmd); + case SCSI_EH_RESET_TIMER: + return BLK_EH_RESET_TIMER; + case SCSI_EH_NOT_HANDLED: + break; } } - return rtn; + /* + * If scsi_done() has already set SCMD_STATE_COMPLETE, do not modify + * *scmd. + */ + if (test_and_set_bit(SCMD_STATE_COMPLETE, &scmd->state)) + return BLK_EH_DONE; + if (scsi_abort_command(scmd) != SUCCESS) { + set_host_byte(scmd, DID_TIME_OUT); + scsi_eh_scmd_add(scmd); + } + + return BLK_EH_DONE; } /** diff --git a/drivers/scsi/scsi_transport_fc.c b/drivers/scsi/scsi_transport_fc.c index 8934160c4a33..0965f8a7134f 100644 --- a/drivers/scsi/scsi_transport_fc.c +++ b/drivers/scsi/scsi_transport_fc.c @@ -2530,15 +2530,14 @@ static int fc_vport_match(struct attribute_container *cont, * Notes: * This routine assumes no locks are held on entry. */ -enum blk_eh_timer_return -fc_eh_timed_out(struct scsi_cmnd *scmd) +enum scsi_timeout_action fc_eh_timed_out(struct scsi_cmnd *scmd) { struct fc_rport *rport = starget_to_rport(scsi_target(scmd->device)); if (rport->port_state == FC_PORTSTATE_BLOCKED) - return BLK_EH_RESET_TIMER; + return SCSI_EH_RESET_TIMER; - return BLK_EH_DONE; + return SCSI_EH_NOT_HANDLED; } EXPORT_SYMBOL(fc_eh_timed_out); diff --git a/drivers/scsi/scsi_transport_srp.c b/drivers/scsi/scsi_transport_srp.c index 98a34ed10f1a..87d0fb8dc503 100644 --- a/drivers/scsi/scsi_transport_srp.c +++ b/drivers/scsi/scsi_transport_srp.c @@ -594,13 +594,13 @@ EXPORT_SYMBOL(srp_reconnect_rport); * @scmd: SCSI command. * * If a timeout occurs while an rport is in the blocked state, ask the SCSI - * EH to continue waiting (BLK_EH_RESET_TIMER). Otherwise let the SCSI core - * handle the timeout (BLK_EH_DONE). + * EH to continue waiting (SCSI_EH_RESET_TIMER). Otherwise let the SCSI core + * handle the timeout (SCSI_EH_NOT_HANDLED). * * Note: This function is called from soft-IRQ context and with the request * queue lock held. */ -enum blk_eh_timer_return srp_timed_out(struct scsi_cmnd *scmd) +enum scsi_timeout_action srp_timed_out(struct scsi_cmnd *scmd) { struct scsi_device *sdev = scmd->device; struct Scsi_Host *shost = sdev->host; @@ -611,7 +611,7 @@ enum blk_eh_timer_return srp_timed_out(struct scsi_cmnd *scmd) return rport && rport->fast_io_fail_tmo < 0 && rport->dev_loss_tmo < 0 && i->f->reset_timer_if_blocked && scsi_device_blocked(sdev) ? - BLK_EH_RESET_TIMER : BLK_EH_DONE; + SCSI_EH_RESET_TIMER : SCSI_EH_NOT_HANDLED; } EXPORT_SYMBOL(srp_timed_out); diff --git a/drivers/scsi/storvsc_drv.c b/drivers/scsi/storvsc_drv.c index bc46721aa01c..a84194d82347 100644 --- a/drivers/scsi/storvsc_drv.c +++ b/drivers/scsi/storvsc_drv.c @@ -1652,13 +1652,13 @@ static int storvsc_host_reset_handler(struct scsi_cmnd *scmnd) * be unbounded on Azure. Reset the timer unconditionally to give the host a * chance to perform EH. */ -static enum blk_eh_timer_return storvsc_eh_timed_out(struct scsi_cmnd *scmnd) +static enum scsi_timeout_action storvsc_eh_timed_out(struct scsi_cmnd *scmnd) { #if IS_ENABLED(CONFIG_SCSI_FC_ATTRS) if (scmnd->device->host->transportt == fc_transport_template) return fc_eh_timed_out(scmnd); #endif - return BLK_EH_RESET_TIMER; + return SCSI_EH_RESET_TIMER; } static bool storvsc_scsi_cmd_ok(struct scsi_cmnd *scmnd) diff --git a/drivers/scsi/virtio_scsi.c b/drivers/scsi/virtio_scsi.c index 2a79ab16134b..d07d24c06b54 100644 --- a/drivers/scsi/virtio_scsi.c +++ b/drivers/scsi/virtio_scsi.c @@ -731,9 +731,9 @@ static void virtscsi_commit_rqs(struct Scsi_Host *shost, u16 hwq) * latencies might be higher than on bare metal. Reset the timer * unconditionally to give the host a chance to perform EH. */ -static enum blk_eh_timer_return virtscsi_eh_timed_out(struct scsi_cmnd *scmnd) +static enum scsi_timeout_action virtscsi_eh_timed_out(struct scsi_cmnd *scmnd) { - return BLK_EH_RESET_TIMER; + return SCSI_EH_RESET_TIMER; } static struct scsi_host_template virtscsi_host_template = { diff --git a/include/scsi/libiscsi.h b/include/scsi/libiscsi.h index 654cc3918c94..695eebc6f2c8 100644 --- a/include/scsi/libiscsi.h +++ b/include/scsi/libiscsi.h @@ -393,7 +393,7 @@ extern int iscsi_eh_recover_target(struct scsi_cmnd *sc); extern int iscsi_eh_session_reset(struct scsi_cmnd *sc); extern int iscsi_eh_device_reset(struct scsi_cmnd *sc); extern int iscsi_queuecommand(struct Scsi_Host *host, struct scsi_cmnd *sc); -extern enum blk_eh_timer_return iscsi_eh_cmd_timed_out(struct scsi_cmnd *sc); +extern enum scsi_timeout_action iscsi_eh_cmd_timed_out(struct scsi_cmnd *sc); /* * iSCSI host helpers. diff --git a/include/scsi/scsi_host.h b/include/scsi/scsi_host.h index e71436183c0d..587cc767bb67 100644 --- a/include/scsi/scsi_host.h +++ b/include/scsi/scsi_host.h @@ -27,6 +27,18 @@ struct scsi_transport_template; #define MODE_INITIATOR 0x01 #define MODE_TARGET 0x02 +/** + * enum scsi_timeout_action - How to handle a command that timed out. + * @SCSI_EH_DONE: The command has already been completed. + * @SCSI_EH_RESET_TIMER: Reset the timer and continue waiting for completion. + * @SCSI_EH_NOT_HANDLED: The command has not yet finished. Abort the command. + */ +enum scsi_timeout_action { + SCSI_EH_DONE, + SCSI_EH_RESET_TIMER, + SCSI_EH_NOT_HANDLED, +}; + struct scsi_host_template { /* * Put fields referenced in IO submission path together in @@ -331,7 +343,7 @@ struct scsi_host_template { * * Status: OPTIONAL */ - enum blk_eh_timer_return (*eh_timed_out)(struct scsi_cmnd *); + enum scsi_timeout_action (*eh_timed_out)(struct scsi_cmnd *); /* * Optional routine that allows the transport to decide if a cmd * is retryable. Return true if the transport is in a state the diff --git a/include/scsi/scsi_transport_fc.h b/include/scsi/scsi_transport_fc.h index e80a7c542c88..3dcda19d3520 100644 --- a/include/scsi/scsi_transport_fc.h +++ b/include/scsi/scsi_transport_fc.h @@ -862,7 +862,7 @@ struct fc_vport *fc_vport_create(struct Scsi_Host *shost, int channel, int fc_vport_terminate(struct fc_vport *vport); int fc_block_rport(struct fc_rport *rport); int fc_block_scsi_eh(struct scsi_cmnd *cmnd); -enum blk_eh_timer_return fc_eh_timed_out(struct scsi_cmnd *scmd); +enum scsi_timeout_action fc_eh_timed_out(struct scsi_cmnd *scmd); bool fc_eh_should_retry_cmd(struct scsi_cmnd *scmd); static inline struct Scsi_Host *fc_bsg_to_shost(struct bsg_job *job) diff --git a/include/scsi/scsi_transport_srp.h b/include/scsi/scsi_transport_srp.h index d22df12584f9..dfc78aa112ad 100644 --- a/include/scsi/scsi_transport_srp.h +++ b/include/scsi/scsi_transport_srp.h @@ -118,7 +118,7 @@ extern int srp_reconnect_rport(struct srp_rport *rport); extern void srp_start_tl_fail_timers(struct srp_rport *rport); extern void srp_remove_host(struct Scsi_Host *); extern void srp_stop_rport_timers(struct srp_rport *rport); -enum blk_eh_timer_return srp_timed_out(struct scsi_cmnd *scmd); +enum scsi_timeout_action srp_timed_out(struct scsi_cmnd *scmd); /** * srp_chkready() - evaluate the transport layer state before I/O -- cgit v1.2.3 From 310bcaef6d7ed1626bba95dd9b5c5acd189c0e35 Mon Sep 17 00:00:00 2001 From: Bart Van Assche Date: Tue, 18 Oct 2022 13:29:51 -0700 Subject: scsi: core: Support failing requests while recovering The current behavior for SCSI commands submitted while error recovery is ongoing is to retry command submission after error recovery has finished. See also the scsi_host_in_recovery() check in scsi_host_queue_ready(). Add support for failing SCSI commands while host recovery is in progress. This functionality will be used to fix a deadlock in the UFS driver. Cc: Christoph Hellwig Cc: Ming Lei Cc: John Garry Cc: Mike Christie Cc: Hannes Reinecke Signed-off-by: Bart Van Assche Link: https://lore.kernel.org/r/20221018202958.1902564-4-bvanassche@acm.org Reviewed-by: Mike Christie Signed-off-by: Martin K. Petersen --- drivers/scsi/scsi_lib.c | 8 +++++--- include/scsi/scsi_cmnd.h | 3 ++- 2 files changed, 7 insertions(+), 4 deletions(-) diff --git a/drivers/scsi/scsi_lib.c b/drivers/scsi/scsi_lib.c index fa96d3cfdfa3..ec890865abae 100644 --- a/drivers/scsi/scsi_lib.c +++ b/drivers/scsi/scsi_lib.c @@ -1341,9 +1341,6 @@ static inline int scsi_host_queue_ready(struct request_queue *q, struct scsi_device *sdev, struct scsi_cmnd *cmd) { - if (scsi_host_in_recovery(shost)) - return 0; - if (atomic_read(&shost->host_blocked) > 0) { if (scsi_host_busy(shost) > 0) goto starved; @@ -1732,6 +1729,11 @@ static blk_status_t scsi_queue_rq(struct blk_mq_hw_ctx *hctx, ret = BLK_STS_RESOURCE; if (!scsi_target_queue_ready(shost, sdev)) goto out_put_budget; + if (unlikely(scsi_host_in_recovery(shost))) { + if (cmd->flags & SCMD_FAIL_IF_RECOVERING) + ret = BLK_STS_OFFLINE; + goto out_dec_target_busy; + } if (!scsi_host_queue_ready(q, shost, sdev, cmd)) goto out_dec_target_busy; diff --git a/include/scsi/scsi_cmnd.h b/include/scsi/scsi_cmnd.h index 7d3622db38ed..c2cb5f69635c 100644 --- a/include/scsi/scsi_cmnd.h +++ b/include/scsi/scsi_cmnd.h @@ -52,8 +52,9 @@ struct scsi_pointer { #define SCMD_TAGGED (1 << 0) #define SCMD_INITIALIZED (1 << 1) #define SCMD_LAST (1 << 2) +#define SCMD_FAIL_IF_RECOVERING (1 << 4) /* flags preserved across unprep / reprep */ -#define SCMD_PRESERVED_FLAGS (SCMD_INITIALIZED) +#define SCMD_PRESERVED_FLAGS (SCMD_INITIALIZED | SCMD_FAIL_IF_RECOVERING) /* for scmd->state */ #define SCMD_STATE_COMPLETE 0 -- cgit v1.2.3 From 1626c7bba1c42499d6753bd919803158e5792f08 Mon Sep 17 00:00:00 2001 From: Bart Van Assche Date: Tue, 18 Oct 2022 13:29:52 -0700 Subject: scsi: ufs: Remove an outdated comment Although the host lock had to be held by ufshcd_clk_scaling_start_busy() callers when that function was introduced, that is no longer the case today. Hence remove the comment that claims that callers of this function must hold the host lock. Reviewed-by: Bean Huo Reviewed-by: Adrian Hunter Signed-off-by: Bart Van Assche Link: https://lore.kernel.org/r/20221018202958.1902564-5-bvanassche@acm.org Signed-off-by: Martin K. Petersen --- drivers/ufs/core/ufshcd.c | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/ufs/core/ufshcd.c b/drivers/ufs/core/ufshcd.c index c8f0fe740005..bdee494381ca 100644 --- a/drivers/ufs/core/ufshcd.c +++ b/drivers/ufs/core/ufshcd.c @@ -2013,7 +2013,6 @@ static void ufshcd_exit_clk_gating(struct ufs_hba *hba) destroy_workqueue(hba->clk_gating.clk_gating_workq); } -/* Must be called with host lock acquired */ static void ufshcd_clk_scaling_start_busy(struct ufs_hba *hba) { bool queue_resume_work = false; -- cgit v1.2.3 From 836d322d73cb08486ecc50787695175a135e62ba Mon Sep 17 00:00:00 2001 From: Bart Van Assche Date: Tue, 18 Oct 2022 13:29:53 -0700 Subject: scsi: ufs: Use 'else' in ufshcd_set_dev_pwr_mode() Convert if (ret) { ... } if (!ret) { ... } into if (ret) { ... } else { ... }. Reviewed-by: Bean Huo Reviewed-by: Adrian Hunter Signed-off-by: Bart Van Assche Link: https://lore.kernel.org/r/20221018202958.1902564-6-bvanassche@acm.org Signed-off-by: Martin K. Petersen --- drivers/ufs/core/ufshcd.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/drivers/ufs/core/ufshcd.c b/drivers/ufs/core/ufshcd.c index bdee494381ca..db1997e99da2 100644 --- a/drivers/ufs/core/ufshcd.c +++ b/drivers/ufs/core/ufshcd.c @@ -8797,10 +8797,9 @@ static int ufshcd_set_dev_pwr_mode(struct ufs_hba *hba, scsi_print_sense_hdr(sdp, NULL, &sshdr); ret = -EIO; } - } - - if (!ret) + } else { hba->curr_dev_pwr_mode = pwr_mode; + } scsi_device_put(sdp); hba->host->eh_noresume = 0; -- cgit v1.2.3 From dcd5b7637c6d442d957f73780a03047413ed3a10 Mon Sep 17 00:00:00 2001 From: Bart Van Assche Date: Tue, 18 Oct 2022 13:29:54 -0700 Subject: scsi: ufs: Reduce the START STOP UNIT timeout Reduce the START STOP UNIT command timeout to one second since on Android devices a kernel panic is triggered if an attempt to suspend the system takes more than 20 seconds. One second should be enough for the START STOP UNIT command since this command completes in less than a millisecond for the UFS devices I have access to. Signed-off-by: Bart Van Assche Link: https://lore.kernel.org/r/20221018202958.1902564-7-bvanassche@acm.org Signed-off-by: Martin K. Petersen --- drivers/ufs/core/ufshcd.c | 9 +-------- 1 file changed, 1 insertion(+), 8 deletions(-) diff --git a/drivers/ufs/core/ufshcd.c b/drivers/ufs/core/ufshcd.c index db1997e99da2..f83a0045a129 100644 --- a/drivers/ufs/core/ufshcd.c +++ b/drivers/ufs/core/ufshcd.c @@ -8746,8 +8746,6 @@ static int ufshcd_set_dev_pwr_mode(struct ufs_hba *hba, struct scsi_device *sdp; unsigned long flags; int ret, retries; - unsigned long deadline; - int32_t remaining; spin_lock_irqsave(hba->host->host_lock, flags); sdp = hba->ufs_device_wlun; @@ -8775,14 +8773,9 @@ static int ufshcd_set_dev_pwr_mode(struct ufs_hba *hba, * callbacks hence set the RQF_PM flag so that it doesn't resume the * already suspended childs. */ - deadline = jiffies + 10 * HZ; for (retries = 3; retries > 0; --retries) { - ret = -ETIMEDOUT; - remaining = deadline - jiffies; - if (remaining <= 0) - break; ret = scsi_execute(sdp, cmd, DMA_NONE, NULL, 0, NULL, &sshdr, - remaining / HZ, 0, 0, RQF_PM, NULL); + HZ, 0, 0, RQF_PM, NULL); if (!scsi_status_is_check_condition(ret) || !scsi_sense_valid(&sshdr) || sshdr.sense_key != UNIT_ATTENTION) -- cgit v1.2.3 From 579a4e9dbd53978cad8df88dc612837cdd210ce0 Mon Sep 17 00:00:00 2001 From: Bart Van Assche Date: Tue, 18 Oct 2022 13:29:55 -0700 Subject: scsi: ufs: Try harder to change the power mode Instead of only retrying the START STOP UNIT command if a unit attention is reported, repeat it if any SCSI error is reported by the device or if the command timed out. Signed-off-by: Bart Van Assche Link: https://lore.kernel.org/r/20221018202958.1902564-8-bvanassche@acm.org Signed-off-by: Martin K. Petersen --- drivers/ufs/core/ufshcd.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/drivers/ufs/core/ufshcd.c b/drivers/ufs/core/ufshcd.c index f83a0045a129..84ca17d29898 100644 --- a/drivers/ufs/core/ufshcd.c +++ b/drivers/ufs/core/ufshcd.c @@ -8776,9 +8776,11 @@ static int ufshcd_set_dev_pwr_mode(struct ufs_hba *hba, for (retries = 3; retries > 0; --retries) { ret = scsi_execute(sdp, cmd, DMA_NONE, NULL, 0, NULL, &sshdr, HZ, 0, 0, RQF_PM, NULL); - if (!scsi_status_is_check_condition(ret) || - !scsi_sense_valid(&sshdr) || - sshdr.sense_key != UNIT_ATTENTION) + /* + * scsi_execute() only returns a negative value if the request + * queue is dying. + */ + if (ret <= 0) break; } if (ret) { -- cgit v1.2.3 From 1a547cbc6fdd07992f915a614a3f7ba3fccef8fb Mon Sep 17 00:00:00 2001 From: Bart Van Assche Date: Tue, 18 Oct 2022 13:29:56 -0700 Subject: scsi: ufs: Track system suspend / resume activity Add a new boolean variable that tracks whether the system is suspending, suspended or resuming. This information will be used in a later commit to fix a deadlock between the SCSI error handler and the suspend code. Reviewed-by: Adrian Hunter Signed-off-by: Bart Van Assche Link: https://lore.kernel.org/r/20221018202958.1902564-9-bvanassche@acm.org Signed-off-by: Martin K. Petersen --- drivers/ufs/core/ufshcd.c | 2 ++ include/ufs/ufshcd.h | 5 ++++- 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/drivers/ufs/core/ufshcd.c b/drivers/ufs/core/ufshcd.c index 84ca17d29898..2a32bcc93d2e 100644 --- a/drivers/ufs/core/ufshcd.c +++ b/drivers/ufs/core/ufshcd.c @@ -9247,6 +9247,7 @@ static int ufshcd_wl_suspend(struct device *dev) hba = shost_priv(sdev->host); down(&hba->host_sem); + hba->system_suspending = true; if (pm_runtime_suspended(dev)) goto out; @@ -9288,6 +9289,7 @@ out: hba->curr_dev_pwr_mode, hba->uic_link_state); if (!ret) hba->is_sys_suspended = false; + hba->system_suspending = false; up(&hba->host_sem); return ret; } diff --git a/include/ufs/ufshcd.h b/include/ufs/ufshcd.h index 9f28349ebcff..96538eb3a6c0 100644 --- a/include/ufs/ufshcd.h +++ b/include/ufs/ufshcd.h @@ -802,7 +802,9 @@ struct ufs_hba_monitor { * @caps: bitmask with information about UFS controller capabilities * @devfreq: frequency scaling information owned by the devfreq core * @clk_scaling: frequency scaling information owned by the UFS driver - * @is_sys_suspended: whether or not the entire system has been suspended + * @system_suspending: system suspend has been started and system resume has + * not yet finished. + * @is_sys_suspended: UFS device has been suspended because of system suspend * @urgent_bkops_lvl: keeps track of urgent bkops level for device * @is_urgent_bkops_lvl_checked: keeps track if the urgent bkops level for * device is known or not. @@ -943,6 +945,7 @@ struct ufs_hba { struct devfreq *devfreq; struct ufs_clk_scaling clk_scaling; + bool system_suspending; bool is_sys_suspended; enum bkops_status urgent_bkops_lvl; -- cgit v1.2.3 From 6a354a7e740ee779d8595bb3c555d415433f2b19 Mon Sep 17 00:00:00 2001 From: Bart Van Assche Date: Tue, 18 Oct 2022 13:29:57 -0700 Subject: scsi: ufs: Introduce the function ufshcd_execute_start_stop() Open-code scsi_execute() because a later patch will modify scmd->flags and because scsi_execute() does not support setting scmd->flags. No functionality is changed. Signed-off-by: Bart Van Assche Link: https://lore.kernel.org/r/20221018202958.1902564-10-bvanassche@acm.org Reviewed-by: Mike Christie Signed-off-by: Martin K. Petersen --- drivers/ufs/core/ufshcd.c | 39 ++++++++++++++++++++++++++++++++++----- 1 file changed, 34 insertions(+), 5 deletions(-) diff --git a/drivers/ufs/core/ufshcd.c b/drivers/ufs/core/ufshcd.c index 2a32bcc93d2e..c5ccc7ba583b 100644 --- a/drivers/ufs/core/ufshcd.c +++ b/drivers/ufs/core/ufshcd.c @@ -8729,6 +8729,39 @@ static void ufshcd_hba_exit(struct ufs_hba *hba) } } +static int ufshcd_execute_start_stop(struct scsi_device *sdev, + enum ufs_dev_pwr_mode pwr_mode, + struct scsi_sense_hdr *sshdr) +{ + unsigned char cdb[6] = { START_STOP, 0, 0, 0, pwr_mode << 4, 0 }; + struct request *req; + struct scsi_cmnd *scmd; + int ret; + + req = scsi_alloc_request(sdev->request_queue, REQ_OP_DRV_IN, + BLK_MQ_REQ_PM); + if (IS_ERR(req)) + return PTR_ERR(req); + + scmd = blk_mq_rq_to_pdu(req); + scmd->cmd_len = COMMAND_SIZE(cdb[0]); + memcpy(scmd->cmnd, cdb, scmd->cmd_len); + scmd->allowed = 0/*retries*/; + req->timeout = 1 * HZ; + req->rq_flags |= RQF_PM | RQF_QUIET; + + blk_execute_rq(req, /*at_head=*/true); + + if (sshdr) + scsi_normalize_sense(scmd->sense_buffer, scmd->sense_len, + sshdr); + ret = scmd->result; + + blk_mq_free_request(req); + + return ret; +} + /** * ufshcd_set_dev_pwr_mode - sends START STOP UNIT command to set device * power mode @@ -8741,7 +8774,6 @@ static void ufshcd_hba_exit(struct ufs_hba *hba) static int ufshcd_set_dev_pwr_mode(struct ufs_hba *hba, enum ufs_dev_pwr_mode pwr_mode) { - unsigned char cmd[6] = { START_STOP }; struct scsi_sense_hdr sshdr; struct scsi_device *sdp; unsigned long flags; @@ -8766,16 +8798,13 @@ static int ufshcd_set_dev_pwr_mode(struct ufs_hba *hba, */ hba->host->eh_noresume = 1; - cmd[4] = pwr_mode << 4; - /* * Current function would be generally called from the power management * callbacks hence set the RQF_PM flag so that it doesn't resume the * already suspended childs. */ for (retries = 3; retries > 0; --retries) { - ret = scsi_execute(sdp, cmd, DMA_NONE, NULL, 0, NULL, &sshdr, - HZ, 0, 0, RQF_PM, NULL); + ret = ufshcd_execute_start_stop(sdp, pwr_mode, &sshdr); /* * scsi_execute() only returns a negative value if the request * queue is dying. -- cgit v1.2.3 From 7029e2151a7c6a5c60b35996d026528e7d51aae3 Mon Sep 17 00:00:00 2001 From: Bart Van Assche Date: Tue, 18 Oct 2022 13:29:58 -0700 Subject: scsi: ufs: Fix a deadlock between PM and the SCSI error handler The following deadlock has been observed on multiple test setups: * ufshcd_wl_suspend() is waiting for blk_execute_rq(START STOP UNIT) to complete while ufshcd_wl_suspend() holds host_sem. * The SCSI error handler is activated, changes the host state to SHOST_RECOVERY, ufshcd_eh_host_reset_handler() and ufshcd_err_handler() are called and the latter function tries to obtain host_sem. This is a deadlock because blk_execute_rq() can't execute SCSI commands while the host is in the SHOST_RECOVERY state and because the error handler cannot make progress because host_sem is held by another thread. Fix this deadlock as follows: * Fail attempts to suspend the system while the SCSI error handler is in progress by setting the SCMD_FAIL_IF_RECOVERING flag for START STOP UNIT commands. * If the system is suspending and a START STOP UNIT command times out, handle the SCSI command timeout from inside the context of the SCSI timeout handler instead of activating the SCSI error handler. The runtime power management code is not affected by this deadlock since hba->host_sem is not touched by the runtime power management functions in the UFS driver. Reviewed-by: Adrian Hunter Signed-off-by: Bart Van Assche Link: https://lore.kernel.org/r/20221018202958.1902564-11-bvanassche@acm.org Signed-off-by: Martin K. Petersen --- drivers/ufs/core/ufshcd.c | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/drivers/ufs/core/ufshcd.c b/drivers/ufs/core/ufshcd.c index c5ccc7ba583b..b2203dd79e8c 100644 --- a/drivers/ufs/core/ufshcd.c +++ b/drivers/ufs/core/ufshcd.c @@ -8292,6 +8292,28 @@ out: } } +static enum scsi_timeout_action ufshcd_eh_timed_out(struct scsi_cmnd *scmd) +{ + struct ufs_hba *hba = shost_priv(scmd->device->host); + + if (!hba->system_suspending) { + /* Activate the error handler in the SCSI core. */ + return SCSI_EH_NOT_HANDLED; + } + + /* + * If we get here we know that no TMFs are outstanding and also that + * the only pending command is a START STOP UNIT command. Handle the + * timeout of that command directly to prevent a deadlock between + * ufshcd_set_dev_pwr_mode() and ufshcd_err_handler(). + */ + ufshcd_link_recovery(hba); + dev_info(hba->dev, "%s() finished; outstanding_tasks = %#lx.\n", + __func__, hba->outstanding_tasks); + + return hba->outstanding_reqs ? SCSI_EH_RESET_TIMER : SCSI_EH_DONE; +} + static const struct attribute_group *ufshcd_driver_groups[] = { &ufs_sysfs_unit_descriptor_group, &ufs_sysfs_lun_attributes_group, @@ -8326,6 +8348,7 @@ static struct scsi_host_template ufshcd_driver_template = { .eh_abort_handler = ufshcd_abort, .eh_device_reset_handler = ufshcd_eh_device_reset_handler, .eh_host_reset_handler = ufshcd_eh_host_reset_handler, + .eh_timed_out = ufshcd_eh_timed_out, .this_id = -1, .sg_tablesize = SG_ALL, .cmd_per_lun = UFSHCD_CMD_PER_LUN, @@ -8747,6 +8770,7 @@ static int ufshcd_execute_start_stop(struct scsi_device *sdev, scmd->cmd_len = COMMAND_SIZE(cdb[0]); memcpy(scmd->cmnd, cdb, scmd->cmd_len); scmd->allowed = 0/*retries*/; + scmd->flags |= SCMD_FAIL_IF_RECOVERING; req->timeout = 1 * HZ; req->rq_flags |= RQF_PM | RQF_QUIET; -- cgit v1.2.3 From b9b8782f8966a7f219ec2e2db3ffe5eeb23943ab Mon Sep 17 00:00:00 2001 From: Dmitry Bogdanov Date: Tue, 6 Sep 2022 13:34:16 +0300 Subject: scsi: target: core: Add support for RSOC command Add support for REPORT SUPPORTED OPERATION CODES command according to SPC4. Reviewed-by: Roman Bolshakov Signed-off-by: Dmitry Bogdanov Link: https://lore.kernel.org/r/20220906103421.22348-2-d.bogdanov@yadro.com Reviewed-by: Mike Christie Signed-off-by: Martin K. Petersen --- drivers/target/target_core_spc.c | 200 ++++++++++++++++++++++++++++++++++++++ include/scsi/scsi_proto.h | 7 ++ include/target/target_core_base.h | 12 +++ 3 files changed, 219 insertions(+) diff --git a/drivers/target/target_core_spc.c b/drivers/target/target_core_spc.c index 7cca3b15472b..afd5ea0344f3 100644 --- a/drivers/target/target_core_spc.c +++ b/drivers/target/target_core_spc.c @@ -1314,6 +1314,202 @@ spc_emulate_testunitready(struct se_cmd *cmd) return 0; } + +static struct target_opcode_descriptor *tcm_supported_opcodes[] = { +}; + +static int +spc_rsoc_encode_command_timeouts_descriptor(unsigned char *buf, u8 ctdp, + struct target_opcode_descriptor *descr) +{ + if (!ctdp) + return 0; + + put_unaligned_be16(0xa, buf); + buf[3] = descr->specific_timeout; + put_unaligned_be32(descr->nominal_timeout, &buf[4]); + put_unaligned_be32(descr->recommended_timeout, &buf[8]); + + return 12; +} + +static int +spc_rsoc_encode_command_descriptor(unsigned char *buf, u8 ctdp, + struct target_opcode_descriptor *descr) +{ + int td_size = 0; + + buf[0] = descr->opcode; + + put_unaligned_be16(descr->service_action, &buf[2]); + + buf[5] = (ctdp << 1) | descr->serv_action_valid; + put_unaligned_be16(descr->cdb_size, &buf[6]); + + td_size = spc_rsoc_encode_command_timeouts_descriptor(&buf[8], ctdp, + descr); + + return 8 + td_size; +} + +static int +spc_rsoc_encode_one_command_descriptor(unsigned char *buf, u8 ctdp, + struct target_opcode_descriptor *descr) +{ + int td_size = 0; + + if (!descr) { + buf[1] = (ctdp << 7) | SCSI_SUPPORT_NOT_SUPPORTED; + return 2; + } + + buf[1] = (ctdp << 7) | SCSI_SUPPORT_FULL; + put_unaligned_be16(descr->cdb_size, &buf[2]); + memcpy(&buf[4], descr->usage_bits, descr->cdb_size); + + td_size = spc_rsoc_encode_command_timeouts_descriptor( + &buf[4 + descr->cdb_size], ctdp, descr); + + return 4 + descr->cdb_size + td_size; +} + +static sense_reason_t +spc_rsoc_get_descr(struct se_cmd *cmd, struct target_opcode_descriptor **opcode) +{ + struct target_opcode_descriptor *descr; + struct se_session *sess = cmd->se_sess; + unsigned char *cdb = cmd->t_task_cdb; + u8 opts = cdb[2] & 0x3; + u8 requested_opcode; + u16 requested_sa; + int i; + + requested_opcode = cdb[3]; + requested_sa = ((u16)cdb[4]) << 8 | cdb[5]; + *opcode = NULL; + + if (opts > 3) { + pr_debug("TARGET_CORE[%s]: Invalid REPORT SUPPORTED OPERATION CODES" + " with unsupported REPORTING OPTIONS %#x for 0x%08llx from %s\n", + cmd->se_tfo->fabric_name, opts, + cmd->se_lun->unpacked_lun, + sess->se_node_acl->initiatorname); + return TCM_INVALID_CDB_FIELD; + } + + for (i = 0; i < ARRAY_SIZE(tcm_supported_opcodes); i++) { + descr = tcm_supported_opcodes[i]; + if (descr->opcode != requested_opcode) + continue; + + switch (opts) { + case 0x1: + /* + * If the REQUESTED OPERATION CODE field specifies an + * operation code for which the device server implements + * service actions, then the device server shall + * terminate the command with CHECK CONDITION status, + * with the sense key set to ILLEGAL REQUEST, and the + * additional sense code set to INVALID FIELD IN CDB + */ + if (descr->serv_action_valid) + return TCM_INVALID_CDB_FIELD; + *opcode = descr; + break; + case 0x2: + /* + * If the REQUESTED OPERATION CODE field specifies an + * operation code for which the device server does not + * implement service actions, then the device server + * shall terminate the command with CHECK CONDITION + * status, with the sense key set to ILLEGAL REQUEST, + * and the additional sense code set to INVALID FIELD IN CDB. + */ + if (descr->serv_action_valid && + descr->service_action == requested_sa) + *opcode = descr; + else if (!descr->serv_action_valid) + return TCM_INVALID_CDB_FIELD; + break; + case 0x3: + /* + * The command support data for the operation code and + * service action a specified in the REQUESTED OPERATION + * CODE field and REQUESTED SERVICE ACTION field shall + * be returned in the one_command parameter data format. + */ + if (descr->service_action == requested_sa) + *opcode = descr; + break; + } + } + return 0; +} + +static sense_reason_t +spc_emulate_report_supp_op_codes(struct se_cmd *cmd) +{ + int descr_num = ARRAY_SIZE(tcm_supported_opcodes); + struct target_opcode_descriptor *descr = NULL; + unsigned char *cdb = cmd->t_task_cdb; + u8 rctd = (cdb[2] >> 7) & 0x1; + unsigned char *buf = NULL; + int response_length = 0; + u8 opts = cdb[2] & 0x3; + unsigned char *rbuf; + sense_reason_t ret = 0; + int i; + + rbuf = transport_kmap_data_sg(cmd); + if (cmd->data_length && !rbuf) { + ret = TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE; + goto out; + } + + if (opts == 0) + response_length = 4 + (8 + rctd * 12) * descr_num; + else { + ret = spc_rsoc_get_descr(cmd, &descr); + if (ret) + goto out; + + if (descr) + response_length = 4 + descr->cdb_size + rctd * 12; + else + response_length = 2; + } + + buf = kzalloc(response_length, GFP_KERNEL); + if (!buf) { + ret = TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE; + goto out; + } + response_length = 0; + + if (opts == 0) { + response_length += 4; + + for (i = 0; i < ARRAY_SIZE(tcm_supported_opcodes); i++) { + descr = tcm_supported_opcodes[i]; + response_length += spc_rsoc_encode_command_descriptor( + &buf[response_length], rctd, descr); + } + put_unaligned_be32(response_length - 3, buf); + } else { + response_length = spc_rsoc_encode_one_command_descriptor( + &buf[response_length], rctd, descr); + } + + memcpy(rbuf, buf, min_t(u32, response_length, cmd->data_length)); +out: + kfree(buf); + transport_kunmap_data_sg(cmd); + + if (!ret) + target_complete_cmd_with_length(cmd, SAM_STAT_GOOD, response_length); + return ret; +} + sense_reason_t spc_parse_cdb(struct se_cmd *cmd, unsigned int *size) { @@ -1439,6 +1635,10 @@ spc_parse_cdb(struct se_cmd *cmd, unsigned int *size) cmd->execute_cmd = target_emulate_report_target_port_groups; } + if ((cdb[1] & 0x1f) == + MI_REPORT_SUPPORTED_OPERATION_CODES) + cmd->execute_cmd = + spc_emulate_report_supp_op_codes; *size = get_unaligned_be32(&cdb[6]); } else { /* diff --git a/include/scsi/scsi_proto.h b/include/scsi/scsi_proto.h index c03e35fc382c..651b5183451c 100644 --- a/include/scsi/scsi_proto.h +++ b/include/scsi/scsi_proto.h @@ -342,4 +342,11 @@ enum scsi_version_descriptor { SCSI_VERSION_DESCRIPTOR_SRP = 0x0940 }; +enum scsi_support_opcode { + SCSI_SUPPORT_NO_INFO = 0, + SCSI_SUPPORT_NOT_SUPPORTED = 1, + SCSI_SUPPORT_FULL = 3, + SCSI_SUPPORT_VENDOR = 5, +}; + #endif /* _SCSI_PROTO_H_ */ diff --git a/include/target/target_core_base.h b/include/target/target_core_base.h index 8c920456edd9..02a2d48d20b6 100644 --- a/include/target/target_core_base.h +++ b/include/target/target_core_base.h @@ -867,6 +867,18 @@ struct se_device { struct se_device_queue *queues; }; +struct target_opcode_descriptor { + u8 support:3; + u8 serv_action_valid:1; + u8 opcode; + u16 service_action; + u32 cdb_size; + u8 specific_timeout; + u16 nominal_timeout; + u16 recommended_timeout; + u8 usage_bits[]; +}; + struct se_hba { u16 hba_tpgt; u32 hba_id; -- cgit v1.2.3 From 0016e820716ff863a76e960cb91bd72373ac2e74 Mon Sep 17 00:00:00 2001 From: Dmitry Bogdanov Date: Tue, 6 Sep 2022 13:34:17 +0300 Subject: scsi: target: core: Add list of opcodes for RSOC Fill the strucures for supported opcodes and usage bits that are reported in REPORT SUPPORTED OPERATION CODES command response. Reviewed-by: Roman Bolshakov Signed-off-by: Dmitry Bogdanov Link: https://lore.kernel.org/r/20220906103421.22348-3-d.bogdanov@yadro.com Reviewed-by: Mike Christie Signed-off-by: Martin K. Petersen --- drivers/target/target_core_spc.c | 568 +++++++++++++++++++++++++++++++++++++++ include/scsi/scsi_proto.h | 3 + 2 files changed, 571 insertions(+) diff --git a/drivers/target/target_core_spc.c b/drivers/target/target_core_spc.c index afd5ea0344f3..31cd6f31f6b1 100644 --- a/drivers/target/target_core_spc.c +++ b/drivers/target/target_core_spc.c @@ -1314,8 +1314,576 @@ spc_emulate_testunitready(struct se_cmd *cmd) return 0; } +static struct target_opcode_descriptor tcm_opcode_read6 = { + .support = SCSI_SUPPORT_FULL, + .opcode = READ_6, + .cdb_size = 6, + .usage_bits = {READ_6, 0x1f, 0xff, 0xff, + 0xff, SCSI_CONTROL_MASK}, +}; + +static struct target_opcode_descriptor tcm_opcode_read10 = { + .support = SCSI_SUPPORT_FULL, + .opcode = READ_10, + .cdb_size = 10, + .usage_bits = {READ_10, 0xf8, 0xff, 0xff, + 0xff, 0xff, SCSI_GROUP_NUMBER_MASK, 0xff, + 0xff, SCSI_CONTROL_MASK}, +}; + +static struct target_opcode_descriptor tcm_opcode_read12 = { + .support = SCSI_SUPPORT_FULL, + .opcode = READ_12, + .cdb_size = 12, + .usage_bits = {READ_12, 0xf8, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, SCSI_GROUP_NUMBER_MASK, SCSI_CONTROL_MASK}, +}; + +static struct target_opcode_descriptor tcm_opcode_read16 = { + .support = SCSI_SUPPORT_FULL, + .opcode = READ_16, + .cdb_size = 16, + .usage_bits = {READ_16, 0xf8, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, SCSI_GROUP_NUMBER_MASK, SCSI_CONTROL_MASK}, +}; + +static struct target_opcode_descriptor tcm_opcode_write6 = { + .support = SCSI_SUPPORT_FULL, + .opcode = WRITE_6, + .cdb_size = 6, + .usage_bits = {WRITE_6, 0x1f, 0xff, 0xff, + 0xff, SCSI_CONTROL_MASK}, +}; + +static struct target_opcode_descriptor tcm_opcode_write10 = { + .support = SCSI_SUPPORT_FULL, + .opcode = WRITE_10, + .cdb_size = 10, + .usage_bits = {WRITE_10, 0xf8, 0xff, 0xff, + 0xff, 0xff, SCSI_GROUP_NUMBER_MASK, 0xff, + 0xff, SCSI_CONTROL_MASK}, +}; + +static struct target_opcode_descriptor tcm_opcode_write_verify10 = { + .support = SCSI_SUPPORT_FULL, + .opcode = WRITE_VERIFY, + .cdb_size = 10, + .usage_bits = {WRITE_VERIFY, 0xf0, 0xff, 0xff, + 0xff, 0xff, SCSI_GROUP_NUMBER_MASK, 0xff, + 0xff, SCSI_CONTROL_MASK}, +}; + +static struct target_opcode_descriptor tcm_opcode_write12 = { + .support = SCSI_SUPPORT_FULL, + .opcode = WRITE_12, + .cdb_size = 12, + .usage_bits = {WRITE_12, 0xf8, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, SCSI_GROUP_NUMBER_MASK, SCSI_CONTROL_MASK}, +}; + +static struct target_opcode_descriptor tcm_opcode_write16 = { + .support = SCSI_SUPPORT_FULL, + .opcode = WRITE_16, + .cdb_size = 16, + .usage_bits = {WRITE_16, 0xf8, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, SCSI_GROUP_NUMBER_MASK, SCSI_CONTROL_MASK}, +}; + +static struct target_opcode_descriptor tcm_opcode_write_verify16 = { + .support = SCSI_SUPPORT_FULL, + .opcode = WRITE_VERIFY_16, + .cdb_size = 16, + .usage_bits = {WRITE_VERIFY_16, 0xf0, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, SCSI_GROUP_NUMBER_MASK, SCSI_CONTROL_MASK}, +}; + +static struct target_opcode_descriptor tcm_opcode_write_same32 = { + .support = SCSI_SUPPORT_FULL, + .serv_action_valid = 1, + .opcode = VARIABLE_LENGTH_CMD, + .service_action = WRITE_SAME_32, + .cdb_size = 32, + .usage_bits = {VARIABLE_LENGTH_CMD, SCSI_CONTROL_MASK, 0x00, 0x00, + 0x00, 0x00, SCSI_GROUP_NUMBER_MASK, 0x18, + 0x00, WRITE_SAME_32, 0xe8, 0x00, + 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, + 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, + 0xff, 0xff, 0xff, 0xff}, +}; + +static struct target_opcode_descriptor tcm_opcode_compare_write = { + .support = SCSI_SUPPORT_FULL, + .opcode = COMPARE_AND_WRITE, + .cdb_size = 16, + .usage_bits = {COMPARE_AND_WRITE, 0x18, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0x00, 0x00, + 0x00, 0xff, SCSI_GROUP_NUMBER_MASK, SCSI_CONTROL_MASK}, +}; + +static struct target_opcode_descriptor tcm_opcode_read_capacity = { + .support = SCSI_SUPPORT_FULL, + .opcode = READ_CAPACITY, + .cdb_size = 10, + .usage_bits = {READ_CAPACITY, 0x00, 0xff, 0xff, + 0xff, 0xff, 0x00, 0x00, + 0x01, SCSI_CONTROL_MASK}, +}; + +static struct target_opcode_descriptor tcm_opcode_read_capacity16 = { + .support = SCSI_SUPPORT_FULL, + .serv_action_valid = 1, + .opcode = SERVICE_ACTION_IN_16, + .service_action = SAI_READ_CAPACITY_16, + .cdb_size = 16, + .usage_bits = {SERVICE_ACTION_IN_16, SAI_READ_CAPACITY_16, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0xff, 0xff, + 0xff, 0xff, 0x00, SCSI_CONTROL_MASK}, +}; + +static struct target_opcode_descriptor tcm_opcode_read_report_refferals = { + .support = SCSI_SUPPORT_FULL, + .serv_action_valid = 1, + .opcode = SERVICE_ACTION_IN_16, + .service_action = SAI_REPORT_REFERRALS, + .cdb_size = 16, + .usage_bits = {SERVICE_ACTION_IN_16, SAI_REPORT_REFERRALS, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0xff, 0xff, + 0xff, 0xff, 0x00, SCSI_CONTROL_MASK}, +}; + +static struct target_opcode_descriptor tcm_opcode_sync_cache = { + .support = SCSI_SUPPORT_FULL, + .opcode = SYNCHRONIZE_CACHE, + .cdb_size = 10, + .usage_bits = {SYNCHRONIZE_CACHE, 0x02, 0xff, 0xff, + 0xff, 0xff, SCSI_GROUP_NUMBER_MASK, 0xff, + 0xff, SCSI_CONTROL_MASK}, +}; + +static struct target_opcode_descriptor tcm_opcode_sync_cache16 = { + .support = SCSI_SUPPORT_FULL, + .opcode = SYNCHRONIZE_CACHE_16, + .cdb_size = 16, + .usage_bits = {SYNCHRONIZE_CACHE_16, 0x02, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, SCSI_GROUP_NUMBER_MASK, SCSI_CONTROL_MASK}, +}; + +static struct target_opcode_descriptor tcm_opcode_unmap = { + .support = SCSI_SUPPORT_FULL, + .opcode = UNMAP, + .cdb_size = 10, + .usage_bits = {UNMAP, 0x00, 0x00, 0x00, + 0x00, 0x00, SCSI_GROUP_NUMBER_MASK, 0xff, + 0xff, SCSI_CONTROL_MASK}, +}; + +static struct target_opcode_descriptor tcm_opcode_write_same = { + .support = SCSI_SUPPORT_FULL, + .opcode = WRITE_SAME, + .cdb_size = 10, + .usage_bits = {WRITE_SAME, 0xe8, 0xff, 0xff, + 0xff, 0xff, SCSI_GROUP_NUMBER_MASK, 0xff, + 0xff, SCSI_CONTROL_MASK}, +}; + +static struct target_opcode_descriptor tcm_opcode_write_same16 = { + .support = SCSI_SUPPORT_FULL, + .opcode = WRITE_SAME_16, + .cdb_size = 16, + .usage_bits = {WRITE_SAME_16, 0xe8, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, SCSI_GROUP_NUMBER_MASK, SCSI_CONTROL_MASK}, +}; + +static struct target_opcode_descriptor tcm_opcode_verify = { + .support = SCSI_SUPPORT_FULL, + .opcode = VERIFY, + .cdb_size = 10, + .usage_bits = {VERIFY, 0x00, 0xff, 0xff, + 0xff, 0xff, SCSI_GROUP_NUMBER_MASK, 0xff, + 0xff, SCSI_CONTROL_MASK}, +}; + +static struct target_opcode_descriptor tcm_opcode_verify16 = { + .support = SCSI_SUPPORT_FULL, + .opcode = VERIFY_16, + .cdb_size = 16, + .usage_bits = {VERIFY_16, 0x00, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, SCSI_GROUP_NUMBER_MASK, SCSI_CONTROL_MASK}, +}; + +static struct target_opcode_descriptor tcm_opcode_start_stop = { + .support = SCSI_SUPPORT_FULL, + .opcode = START_STOP, + .cdb_size = 6, + .usage_bits = {START_STOP, 0x01, 0x00, 0x00, + 0x01, SCSI_CONTROL_MASK}, +}; + +static struct target_opcode_descriptor tcm_opcode_mode_select = { + .support = SCSI_SUPPORT_FULL, + .opcode = MODE_SELECT, + .cdb_size = 6, + .usage_bits = {MODE_SELECT, 0x10, 0x00, 0x00, + 0xff, SCSI_CONTROL_MASK}, +}; + +static struct target_opcode_descriptor tcm_opcode_mode_select10 = { + .support = SCSI_SUPPORT_FULL, + .opcode = MODE_SELECT_10, + .cdb_size = 10, + .usage_bits = {MODE_SELECT_10, 0x10, 0x00, 0x00, + 0x00, 0x00, 0x00, 0xff, + 0xff, SCSI_CONTROL_MASK}, +}; + +static struct target_opcode_descriptor tcm_opcode_mode_sense = { + .support = SCSI_SUPPORT_FULL, + .opcode = MODE_SENSE, + .cdb_size = 6, + .usage_bits = {MODE_SENSE, 0x08, 0xff, 0xff, + 0xff, SCSI_CONTROL_MASK}, +}; + +static struct target_opcode_descriptor tcm_opcode_mode_sense10 = { + .support = SCSI_SUPPORT_FULL, + .opcode = MODE_SENSE_10, + .cdb_size = 10, + .usage_bits = {MODE_SENSE_10, 0x18, 0xff, 0xff, + 0x00, 0x00, 0x00, 0xff, + 0xff, SCSI_CONTROL_MASK}, +}; + +static struct target_opcode_descriptor tcm_opcode_pri_read_keys = { + .support = SCSI_SUPPORT_FULL, + .serv_action_valid = 1, + .opcode = PERSISTENT_RESERVE_IN, + .service_action = PRI_READ_KEYS, + .cdb_size = 10, + .usage_bits = {PERSISTENT_RESERVE_IN, PRI_READ_KEYS, 0x00, 0x00, + 0x00, 0x00, 0x00, 0xff, + 0xff, SCSI_CONTROL_MASK}, +}; + +static struct target_opcode_descriptor tcm_opcode_pri_read_resrv = { + .support = SCSI_SUPPORT_FULL, + .serv_action_valid = 1, + .opcode = PERSISTENT_RESERVE_IN, + .service_action = PRI_READ_RESERVATION, + .cdb_size = 10, + .usage_bits = {PERSISTENT_RESERVE_IN, PRI_READ_RESERVATION, 0x00, 0x00, + 0x00, 0x00, 0x00, 0xff, + 0xff, SCSI_CONTROL_MASK}, +}; + +static struct target_opcode_descriptor tcm_opcode_pri_read_caps = { + .support = SCSI_SUPPORT_FULL, + .serv_action_valid = 1, + .opcode = PERSISTENT_RESERVE_IN, + .service_action = PRI_REPORT_CAPABILITIES, + .cdb_size = 10, + .usage_bits = {PERSISTENT_RESERVE_IN, PRI_REPORT_CAPABILITIES, 0x00, 0x00, + 0x00, 0x00, 0x00, 0xff, + 0xff, SCSI_CONTROL_MASK}, +}; + +static struct target_opcode_descriptor tcm_opcode_pri_read_full_status = { + .support = SCSI_SUPPORT_FULL, + .serv_action_valid = 1, + .opcode = PERSISTENT_RESERVE_IN, + .service_action = PRI_READ_FULL_STATUS, + .cdb_size = 10, + .usage_bits = {PERSISTENT_RESERVE_IN, PRI_READ_FULL_STATUS, 0x00, 0x00, + 0x00, 0x00, 0x00, 0xff, + 0xff, SCSI_CONTROL_MASK}, +}; + +static struct target_opcode_descriptor tcm_opcode_pro_register = { + .support = SCSI_SUPPORT_FULL, + .serv_action_valid = 1, + .opcode = PERSISTENT_RESERVE_OUT, + .service_action = PRO_REGISTER, + .cdb_size = 10, + .usage_bits = {PERSISTENT_RESERVE_OUT, PRO_REGISTER, 0xff, 0x00, + 0x00, 0xff, 0xff, 0xff, + 0xff, SCSI_CONTROL_MASK}, +}; + +static struct target_opcode_descriptor tcm_opcode_pro_reserve = { + .support = SCSI_SUPPORT_FULL, + .serv_action_valid = 1, + .opcode = PERSISTENT_RESERVE_OUT, + .service_action = PRO_RESERVE, + .cdb_size = 10, + .usage_bits = {PERSISTENT_RESERVE_OUT, PRO_RESERVE, 0xff, 0x00, + 0x00, 0xff, 0xff, 0xff, + 0xff, SCSI_CONTROL_MASK}, +}; + +static struct target_opcode_descriptor tcm_opcode_pro_release = { + .support = SCSI_SUPPORT_FULL, + .serv_action_valid = 1, + .opcode = PERSISTENT_RESERVE_OUT, + .service_action = PRO_RELEASE, + .cdb_size = 10, + .usage_bits = {PERSISTENT_RESERVE_OUT, PRO_RELEASE, 0xff, 0x00, + 0x00, 0xff, 0xff, 0xff, + 0xff, SCSI_CONTROL_MASK}, +}; + +static struct target_opcode_descriptor tcm_opcode_pro_clear = { + .support = SCSI_SUPPORT_FULL, + .serv_action_valid = 1, + .opcode = PERSISTENT_RESERVE_OUT, + .service_action = PRO_CLEAR, + .cdb_size = 10, + .usage_bits = {PERSISTENT_RESERVE_OUT, PRO_CLEAR, 0xff, 0x00, + 0x00, 0xff, 0xff, 0xff, + 0xff, SCSI_CONTROL_MASK}, +}; + +static struct target_opcode_descriptor tcm_opcode_pro_preempt = { + .support = SCSI_SUPPORT_FULL, + .serv_action_valid = 1, + .opcode = PERSISTENT_RESERVE_OUT, + .service_action = PRO_PREEMPT, + .cdb_size = 10, + .usage_bits = {PERSISTENT_RESERVE_OUT, PRO_PREEMPT, 0xff, 0x00, + 0x00, 0xff, 0xff, 0xff, + 0xff, SCSI_CONTROL_MASK}, +}; + +static struct target_opcode_descriptor tcm_opcode_pro_preempt_abort = { + .support = SCSI_SUPPORT_FULL, + .serv_action_valid = 1, + .opcode = PERSISTENT_RESERVE_OUT, + .service_action = PRO_PREEMPT_AND_ABORT, + .cdb_size = 10, + .usage_bits = {PERSISTENT_RESERVE_OUT, PRO_PREEMPT_AND_ABORT, 0xff, 0x00, + 0x00, 0xff, 0xff, 0xff, + 0xff, SCSI_CONTROL_MASK}, +}; + +static struct target_opcode_descriptor tcm_opcode_pro_reg_ign_exist = { + .support = SCSI_SUPPORT_FULL, + .serv_action_valid = 1, + .opcode = PERSISTENT_RESERVE_OUT, + .service_action = PRO_REGISTER_AND_IGNORE_EXISTING_KEY, + .cdb_size = 10, + .usage_bits = { + PERSISTENT_RESERVE_OUT, PRO_REGISTER_AND_IGNORE_EXISTING_KEY, + 0xff, 0x00, + 0x00, 0xff, 0xff, 0xff, + 0xff, SCSI_CONTROL_MASK}, +}; + +static struct target_opcode_descriptor tcm_opcode_pro_register_move = { + .support = SCSI_SUPPORT_FULL, + .serv_action_valid = 1, + .opcode = PERSISTENT_RESERVE_OUT, + .service_action = PRO_REGISTER_AND_MOVE, + .cdb_size = 10, + .usage_bits = {PERSISTENT_RESERVE_OUT, PRO_REGISTER_AND_MOVE, 0xff, 0x00, + 0x00, 0xff, 0xff, 0xff, + 0xff, SCSI_CONTROL_MASK}, +}; + +static struct target_opcode_descriptor tcm_opcode_release = { + .support = SCSI_SUPPORT_FULL, + .opcode = RELEASE, + .cdb_size = 6, + .usage_bits = {RELEASE, 0x00, 0x00, 0x00, + 0x00, SCSI_CONTROL_MASK}, +}; + +static struct target_opcode_descriptor tcm_opcode_release10 = { + .support = SCSI_SUPPORT_FULL, + .opcode = RELEASE_10, + .cdb_size = 10, + .usage_bits = {RELEASE_10, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0xff, + 0xff, SCSI_CONTROL_MASK}, +}; + +static struct target_opcode_descriptor tcm_opcode_reserve = { + .support = SCSI_SUPPORT_FULL, + .opcode = RESERVE, + .cdb_size = 6, + .usage_bits = {RESERVE, 0x00, 0x00, 0x00, + 0x00, SCSI_CONTROL_MASK}, +}; + +static struct target_opcode_descriptor tcm_opcode_reserve10 = { + .support = SCSI_SUPPORT_FULL, + .opcode = RESERVE_10, + .cdb_size = 10, + .usage_bits = {RESERVE_10, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0xff, + 0xff, SCSI_CONTROL_MASK}, +}; + +static struct target_opcode_descriptor tcm_opcode_request_sense = { + .support = SCSI_SUPPORT_FULL, + .opcode = REQUEST_SENSE, + .cdb_size = 6, + .usage_bits = {REQUEST_SENSE, 0x00, 0x00, 0x00, + 0xff, SCSI_CONTROL_MASK}, +}; + +static struct target_opcode_descriptor tcm_opcode_inquiry = { + .support = SCSI_SUPPORT_FULL, + .opcode = INQUIRY, + .cdb_size = 6, + .usage_bits = {INQUIRY, 0x01, 0xff, 0xff, + 0xff, SCSI_CONTROL_MASK}, +}; + +static struct target_opcode_descriptor tcm_opcode_extended_copy_lid1 = { + .support = SCSI_SUPPORT_FULL, + .serv_action_valid = 1, + .opcode = EXTENDED_COPY, + .cdb_size = 16, + .usage_bits = {EXTENDED_COPY, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0xff, 0xff, + 0xff, 0xff, 0x00, SCSI_CONTROL_MASK}, +}; + +static struct target_opcode_descriptor tcm_opcode_rcv_copy_res_op_params = { + .support = SCSI_SUPPORT_FULL, + .serv_action_valid = 1, + .opcode = RECEIVE_COPY_RESULTS, + .service_action = RCR_SA_OPERATING_PARAMETERS, + .cdb_size = 16, + .usage_bits = {RECEIVE_COPY_RESULTS, RCR_SA_OPERATING_PARAMETERS, + 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0xff, 0xff, + 0xff, 0xff, 0x00, SCSI_CONTROL_MASK}, +}; + +static struct target_opcode_descriptor tcm_opcode_report_luns = { + .support = SCSI_SUPPORT_FULL, + .opcode = REPORT_LUNS, + .cdb_size = 12, + .usage_bits = {REPORT_LUNS, 0x00, 0xff, 0x00, + 0x00, 0x00, 0xff, 0xff, + 0xff, 0xff, 0x00, SCSI_CONTROL_MASK}, +}; + +static struct target_opcode_descriptor tcm_opcode_test_unit_ready = { + .support = SCSI_SUPPORT_FULL, + .opcode = TEST_UNIT_READY, + .cdb_size = 6, + .usage_bits = {TEST_UNIT_READY, 0x00, 0x00, 0x00, + 0x00, SCSI_CONTROL_MASK}, +}; + +static struct target_opcode_descriptor tcm_opcode_report_target_pgs = { + .support = SCSI_SUPPORT_FULL, + .serv_action_valid = 1, + .opcode = MAINTENANCE_IN, + .service_action = MI_REPORT_TARGET_PGS, + .cdb_size = 12, + .usage_bits = {MAINTENANCE_IN, 0xE0 | MI_REPORT_TARGET_PGS, 0x00, 0x00, + 0x00, 0x00, 0xff, 0xff, + 0xff, 0xff, 0x00, SCSI_CONTROL_MASK}, +}; + +static struct target_opcode_descriptor tcm_opcode_report_supp_opcodes = { + .support = SCSI_SUPPORT_FULL, + .serv_action_valid = 1, + .opcode = MAINTENANCE_IN, + .service_action = MI_REPORT_SUPPORTED_OPERATION_CODES, + .cdb_size = 12, + .usage_bits = {MAINTENANCE_IN, MI_REPORT_SUPPORTED_OPERATION_CODES, + 0x87, 0xff, + 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0x00, SCSI_CONTROL_MASK}, +}; + +static struct target_opcode_descriptor tcm_opcode_set_tpg = { + .support = SCSI_SUPPORT_FULL, + .serv_action_valid = 1, + .opcode = MAINTENANCE_OUT, + .service_action = MO_SET_TARGET_PGS, + .cdb_size = 12, + .usage_bits = {MAINTENANCE_OUT, MO_SET_TARGET_PGS, 0x00, 0x00, + 0x00, 0x00, 0xff, 0xff, + 0xff, 0xff, 0x00, SCSI_CONTROL_MASK}, +}; static struct target_opcode_descriptor *tcm_supported_opcodes[] = { + &tcm_opcode_read6, + &tcm_opcode_read10, + &tcm_opcode_read12, + &tcm_opcode_read16, + &tcm_opcode_write6, + &tcm_opcode_write10, + &tcm_opcode_write_verify10, + &tcm_opcode_write12, + &tcm_opcode_write16, + &tcm_opcode_write_verify16, + &tcm_opcode_write_same32, + &tcm_opcode_compare_write, + &tcm_opcode_read_capacity, + &tcm_opcode_read_capacity16, + &tcm_opcode_read_report_refferals, + &tcm_opcode_sync_cache, + &tcm_opcode_sync_cache16, + &tcm_opcode_unmap, + &tcm_opcode_write_same, + &tcm_opcode_write_same16, + &tcm_opcode_verify, + &tcm_opcode_verify16, + &tcm_opcode_start_stop, + &tcm_opcode_mode_select, + &tcm_opcode_mode_select10, + &tcm_opcode_mode_sense, + &tcm_opcode_mode_sense10, + &tcm_opcode_pri_read_keys, + &tcm_opcode_pri_read_resrv, + &tcm_opcode_pri_read_caps, + &tcm_opcode_pri_read_full_status, + &tcm_opcode_pro_register, + &tcm_opcode_pro_reserve, + &tcm_opcode_pro_release, + &tcm_opcode_pro_clear, + &tcm_opcode_pro_preempt, + &tcm_opcode_pro_preempt_abort, + &tcm_opcode_pro_reg_ign_exist, + &tcm_opcode_pro_register_move, + &tcm_opcode_release, + &tcm_opcode_release10, + &tcm_opcode_reserve, + &tcm_opcode_reserve10, + &tcm_opcode_request_sense, + &tcm_opcode_inquiry, + &tcm_opcode_extended_copy_lid1, + &tcm_opcode_rcv_copy_res_op_params, + &tcm_opcode_report_luns, + &tcm_opcode_test_unit_ready, + &tcm_opcode_report_target_pgs, + &tcm_opcode_report_supp_opcodes, + &tcm_opcode_set_tpg, }; static int diff --git a/include/scsi/scsi_proto.h b/include/scsi/scsi_proto.h index 651b5183451c..cb722225b3bc 100644 --- a/include/scsi/scsi_proto.h +++ b/include/scsi/scsi_proto.h @@ -349,4 +349,7 @@ enum scsi_support_opcode { SCSI_SUPPORT_VENDOR = 5, }; +#define SCSI_CONTROL_MASK 0 +#define SCSI_GROUP_NUMBER_MASK 0 + #endif /* _SCSI_PROTO_H_ */ -- cgit v1.2.3 From 553b08d9b3a78aa602f818c0c94705774f018df0 Mon Sep 17 00:00:00 2001 From: Dmitry Bogdanov Date: Tue, 6 Sep 2022 13:34:18 +0300 Subject: scsi: target: core: Dynamic opcode support in RSOC Report supported opcodes depending on a dynamic device configuration. Reviewed-by: Roman Bolshakov Signed-off-by: Dmitry Bogdanov Link: https://lore.kernel.org/r/20220906103421.22348-4-d.bogdanov@yadro.com Reviewed-by: Mike Christie Signed-off-by: Martin K. Petersen --- drivers/target/target_core_spc.c | 120 ++++++++++++++++++++++++++++++++++++-- include/target/target_core_base.h | 1 + 2 files changed, 116 insertions(+), 5 deletions(-) diff --git a/drivers/target/target_core_spc.c b/drivers/target/target_core_spc.c index 31cd6f31f6b1..e1cf9c352fd3 100644 --- a/drivers/target/target_core_spc.c +++ b/drivers/target/target_core_spc.c @@ -1405,6 +1405,15 @@ static struct target_opcode_descriptor tcm_opcode_write_verify16 = { 0xff, 0xff, SCSI_GROUP_NUMBER_MASK, SCSI_CONTROL_MASK}, }; +static bool tcm_is_ws_enabled(struct se_cmd *cmd) +{ + struct sbc_ops *ops = cmd->protocol_data; + struct se_device *dev = cmd->se_dev; + + return (dev->dev_attrib.emulate_tpws && !!ops->execute_unmap) || + !!ops->execute_write_same; +} + static struct target_opcode_descriptor tcm_opcode_write_same32 = { .support = SCSI_SUPPORT_FULL, .serv_action_valid = 1, @@ -1419,8 +1428,16 @@ static struct target_opcode_descriptor tcm_opcode_write_same32 = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff}, + .enabled = tcm_is_ws_enabled, }; +static bool tcm_is_caw_enabled(struct se_cmd *cmd) +{ + struct se_device *dev = cmd->se_dev; + + return dev->dev_attrib.emulate_caw; +} + static struct target_opcode_descriptor tcm_opcode_compare_write = { .support = SCSI_SUPPORT_FULL, .opcode = COMPARE_AND_WRITE, @@ -1429,6 +1446,7 @@ static struct target_opcode_descriptor tcm_opcode_compare_write = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0xff, SCSI_GROUP_NUMBER_MASK, SCSI_CONTROL_MASK}, + .enabled = tcm_is_caw_enabled, }; static struct target_opcode_descriptor tcm_opcode_read_capacity = { @@ -1452,6 +1470,20 @@ static struct target_opcode_descriptor tcm_opcode_read_capacity16 = { 0xff, 0xff, 0x00, SCSI_CONTROL_MASK}, }; +static bool tcm_is_rep_ref_enabled(struct se_cmd *cmd) +{ + struct se_device *dev = cmd->se_dev; + + spin_lock(&dev->t10_alua.lba_map_lock); + if (list_empty(&dev->t10_alua.lba_map_list)) { + spin_unlock(&dev->t10_alua.lba_map_lock); + return false; + } + spin_unlock(&dev->t10_alua.lba_map_lock); + return true; + +} + static struct target_opcode_descriptor tcm_opcode_read_report_refferals = { .support = SCSI_SUPPORT_FULL, .serv_action_valid = 1, @@ -1462,6 +1494,7 @@ static struct target_opcode_descriptor tcm_opcode_read_report_refferals = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0x00, SCSI_CONTROL_MASK}, + .enabled = tcm_is_rep_ref_enabled, }; static struct target_opcode_descriptor tcm_opcode_sync_cache = { @@ -1483,6 +1516,14 @@ static struct target_opcode_descriptor tcm_opcode_sync_cache16 = { 0xff, 0xff, SCSI_GROUP_NUMBER_MASK, SCSI_CONTROL_MASK}, }; +static bool tcm_is_unmap_enabled(struct se_cmd *cmd) +{ + struct sbc_ops *ops = cmd->protocol_data; + struct se_device *dev = cmd->se_dev; + + return ops->execute_unmap && dev->dev_attrib.emulate_tpu; +} + static struct target_opcode_descriptor tcm_opcode_unmap = { .support = SCSI_SUPPORT_FULL, .opcode = UNMAP, @@ -1490,6 +1531,7 @@ static struct target_opcode_descriptor tcm_opcode_unmap = { .usage_bits = {UNMAP, 0x00, 0x00, 0x00, 0x00, 0x00, SCSI_GROUP_NUMBER_MASK, 0xff, 0xff, SCSI_CONTROL_MASK}, + .enabled = tcm_is_unmap_enabled, }; static struct target_opcode_descriptor tcm_opcode_write_same = { @@ -1499,6 +1541,7 @@ static struct target_opcode_descriptor tcm_opcode_write_same = { .usage_bits = {WRITE_SAME, 0xe8, 0xff, 0xff, 0xff, 0xff, SCSI_GROUP_NUMBER_MASK, 0xff, 0xff, SCSI_CONTROL_MASK}, + .enabled = tcm_is_ws_enabled, }; static struct target_opcode_descriptor tcm_opcode_write_same16 = { @@ -1509,6 +1552,7 @@ static struct target_opcode_descriptor tcm_opcode_write_same16 = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, SCSI_GROUP_NUMBER_MASK, SCSI_CONTROL_MASK}, + .enabled = tcm_is_ws_enabled, }; static struct target_opcode_descriptor tcm_opcode_verify = { @@ -1594,6 +1638,13 @@ static struct target_opcode_descriptor tcm_opcode_pri_read_resrv = { 0xff, SCSI_CONTROL_MASK}, }; +static bool tcm_is_pr_enabled(struct se_cmd *cmd) +{ + struct se_device *dev = cmd->se_dev; + + return dev->dev_attrib.emulate_pr; +} + static struct target_opcode_descriptor tcm_opcode_pri_read_caps = { .support = SCSI_SUPPORT_FULL, .serv_action_valid = 1, @@ -1603,6 +1654,7 @@ static struct target_opcode_descriptor tcm_opcode_pri_read_caps = { .usage_bits = {PERSISTENT_RESERVE_IN, PRI_REPORT_CAPABILITIES, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, SCSI_CONTROL_MASK}, + .enabled = tcm_is_pr_enabled, }; static struct target_opcode_descriptor tcm_opcode_pri_read_full_status = { @@ -1614,6 +1666,7 @@ static struct target_opcode_descriptor tcm_opcode_pri_read_full_status = { .usage_bits = {PERSISTENT_RESERVE_IN, PRI_READ_FULL_STATUS, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, SCSI_CONTROL_MASK}, + .enabled = tcm_is_pr_enabled, }; static struct target_opcode_descriptor tcm_opcode_pro_register = { @@ -1625,6 +1678,7 @@ static struct target_opcode_descriptor tcm_opcode_pro_register = { .usage_bits = {PERSISTENT_RESERVE_OUT, PRO_REGISTER, 0xff, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, SCSI_CONTROL_MASK}, + .enabled = tcm_is_pr_enabled, }; static struct target_opcode_descriptor tcm_opcode_pro_reserve = { @@ -1636,6 +1690,7 @@ static struct target_opcode_descriptor tcm_opcode_pro_reserve = { .usage_bits = {PERSISTENT_RESERVE_OUT, PRO_RESERVE, 0xff, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, SCSI_CONTROL_MASK}, + .enabled = tcm_is_pr_enabled, }; static struct target_opcode_descriptor tcm_opcode_pro_release = { @@ -1647,6 +1702,7 @@ static struct target_opcode_descriptor tcm_opcode_pro_release = { .usage_bits = {PERSISTENT_RESERVE_OUT, PRO_RELEASE, 0xff, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, SCSI_CONTROL_MASK}, + .enabled = tcm_is_pr_enabled, }; static struct target_opcode_descriptor tcm_opcode_pro_clear = { @@ -1658,6 +1714,7 @@ static struct target_opcode_descriptor tcm_opcode_pro_clear = { .usage_bits = {PERSISTENT_RESERVE_OUT, PRO_CLEAR, 0xff, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, SCSI_CONTROL_MASK}, + .enabled = tcm_is_pr_enabled, }; static struct target_opcode_descriptor tcm_opcode_pro_preempt = { @@ -1669,6 +1726,7 @@ static struct target_opcode_descriptor tcm_opcode_pro_preempt = { .usage_bits = {PERSISTENT_RESERVE_OUT, PRO_PREEMPT, 0xff, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, SCSI_CONTROL_MASK}, + .enabled = tcm_is_pr_enabled, }; static struct target_opcode_descriptor tcm_opcode_pro_preempt_abort = { @@ -1680,6 +1738,7 @@ static struct target_opcode_descriptor tcm_opcode_pro_preempt_abort = { .usage_bits = {PERSISTENT_RESERVE_OUT, PRO_PREEMPT_AND_ABORT, 0xff, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, SCSI_CONTROL_MASK}, + .enabled = tcm_is_pr_enabled, }; static struct target_opcode_descriptor tcm_opcode_pro_reg_ign_exist = { @@ -1693,6 +1752,7 @@ static struct target_opcode_descriptor tcm_opcode_pro_reg_ign_exist = { 0xff, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, SCSI_CONTROL_MASK}, + .enabled = tcm_is_pr_enabled, }; static struct target_opcode_descriptor tcm_opcode_pro_register_move = { @@ -1704,14 +1764,23 @@ static struct target_opcode_descriptor tcm_opcode_pro_register_move = { .usage_bits = {PERSISTENT_RESERVE_OUT, PRO_REGISTER_AND_MOVE, 0xff, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, SCSI_CONTROL_MASK}, + .enabled = tcm_is_pr_enabled, }; +static bool tcm_is_scsi2_reservations_enabled(struct se_cmd *cmd) +{ + struct se_device *dev = cmd->se_dev; + + return dev->dev_attrib.emulate_pr; +} + static struct target_opcode_descriptor tcm_opcode_release = { .support = SCSI_SUPPORT_FULL, .opcode = RELEASE, .cdb_size = 6, .usage_bits = {RELEASE, 0x00, 0x00, 0x00, 0x00, SCSI_CONTROL_MASK}, + .enabled = tcm_is_scsi2_reservations_enabled, }; static struct target_opcode_descriptor tcm_opcode_release10 = { @@ -1721,6 +1790,7 @@ static struct target_opcode_descriptor tcm_opcode_release10 = { .usage_bits = {RELEASE_10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, SCSI_CONTROL_MASK}, + .enabled = tcm_is_scsi2_reservations_enabled, }; static struct target_opcode_descriptor tcm_opcode_reserve = { @@ -1729,6 +1799,7 @@ static struct target_opcode_descriptor tcm_opcode_reserve = { .cdb_size = 6, .usage_bits = {RESERVE, 0x00, 0x00, 0x00, 0x00, SCSI_CONTROL_MASK}, + .enabled = tcm_is_scsi2_reservations_enabled, }; static struct target_opcode_descriptor tcm_opcode_reserve10 = { @@ -1738,6 +1809,7 @@ static struct target_opcode_descriptor tcm_opcode_reserve10 = { .usage_bits = {RESERVE_10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, SCSI_CONTROL_MASK}, + .enabled = tcm_is_scsi2_reservations_enabled, }; static struct target_opcode_descriptor tcm_opcode_request_sense = { @@ -1756,6 +1828,13 @@ static struct target_opcode_descriptor tcm_opcode_inquiry = { 0xff, SCSI_CONTROL_MASK}, }; +static bool tcm_is_3pc_enabled(struct se_cmd *cmd) +{ + struct se_device *dev = cmd->se_dev; + + return dev->dev_attrib.emulate_3pc; +} + static struct target_opcode_descriptor tcm_opcode_extended_copy_lid1 = { .support = SCSI_SUPPORT_FULL, .serv_action_valid = 1, @@ -1765,6 +1844,7 @@ static struct target_opcode_descriptor tcm_opcode_extended_copy_lid1 = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0x00, SCSI_CONTROL_MASK}, + .enabled = tcm_is_3pc_enabled, }; static struct target_opcode_descriptor tcm_opcode_rcv_copy_res_op_params = { @@ -1778,6 +1858,7 @@ static struct target_opcode_descriptor tcm_opcode_rcv_copy_res_op_params = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0x00, SCSI_CONTROL_MASK}, + .enabled = tcm_is_3pc_enabled, }; static struct target_opcode_descriptor tcm_opcode_report_luns = { @@ -1820,6 +1901,26 @@ static struct target_opcode_descriptor tcm_opcode_report_supp_opcodes = { 0xff, 0xff, 0x00, SCSI_CONTROL_MASK}, }; +static bool tcm_is_set_tpg_enabled(struct se_cmd *cmd) +{ + struct t10_alua_tg_pt_gp *l_tg_pt_gp; + struct se_lun *l_lun = cmd->se_lun; + + rcu_read_lock(); + l_tg_pt_gp = rcu_dereference(l_lun->lun_tg_pt_gp); + if (!l_tg_pt_gp) { + rcu_read_unlock(); + return false; + } + if (!(l_tg_pt_gp->tg_pt_gp_alua_access_type & TPGS_EXPLICIT_ALUA)) { + rcu_read_unlock(); + return false; + } + rcu_read_unlock(); + + return true; +} + static struct target_opcode_descriptor tcm_opcode_set_tpg = { .support = SCSI_SUPPORT_FULL, .serv_action_valid = 1, @@ -1829,6 +1930,7 @@ static struct target_opcode_descriptor tcm_opcode_set_tpg = { .usage_bits = {MAINTENANCE_OUT, MO_SET_TARGET_PGS, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0x00, SCSI_CONTROL_MASK}, + .enabled = tcm_is_set_tpg_enabled, }; static struct target_opcode_descriptor *tcm_supported_opcodes[] = { @@ -1982,7 +2084,9 @@ spc_rsoc_get_descr(struct se_cmd *cmd, struct target_opcode_descriptor **opcode) */ if (descr->serv_action_valid) return TCM_INVALID_CDB_FIELD; - *opcode = descr; + + if (!descr->enabled || descr->enabled(cmd)) + *opcode = descr; break; case 0x2: /* @@ -1994,9 +2098,10 @@ spc_rsoc_get_descr(struct se_cmd *cmd, struct target_opcode_descriptor **opcode) * and the additional sense code set to INVALID FIELD IN CDB. */ if (descr->serv_action_valid && - descr->service_action == requested_sa) - *opcode = descr; - else if (!descr->serv_action_valid) + descr->service_action == requested_sa) { + if (!descr->enabled || descr->enabled(cmd)) + *opcode = descr; + } else if (!descr->serv_action_valid) return TCM_INVALID_CDB_FIELD; break; case 0x3: @@ -2007,10 +2112,12 @@ spc_rsoc_get_descr(struct se_cmd *cmd, struct target_opcode_descriptor **opcode) * be returned in the one_command parameter data format. */ if (descr->service_action == requested_sa) - *opcode = descr; + if (!descr->enabled || descr->enabled(cmd)) + *opcode = descr; break; } } + return 0; } @@ -2059,6 +2166,9 @@ spc_emulate_report_supp_op_codes(struct se_cmd *cmd) for (i = 0; i < ARRAY_SIZE(tcm_supported_opcodes); i++) { descr = tcm_supported_opcodes[i]; + if (descr->enabled && !descr->enabled(cmd)) + continue; + response_length += spc_rsoc_encode_command_descriptor( &buf[response_length], rctd, descr); } diff --git a/include/target/target_core_base.h b/include/target/target_core_base.h index 02a2d48d20b6..7542a8de8fb5 100644 --- a/include/target/target_core_base.h +++ b/include/target/target_core_base.h @@ -876,6 +876,7 @@ struct target_opcode_descriptor { u8 specific_timeout; u16 nominal_timeout; u16 recommended_timeout; + bool (*enabled)(struct se_cmd *cmd); u8 usage_bits[]; }; -- cgit v1.2.3 From bd217b8c3a1f705f2d92d30974412fbd5f43271a Mon Sep 17 00:00:00 2001 From: Dmitry Bogdanov Date: Tue, 6 Sep 2022 13:34:19 +0300 Subject: scsi: target: core: Add emulate_rsoc attribute Allow support for RSOC to be turned off via the emulate_rsoc attibute. This is just for testing purposes. Reviewed-by: Roman Bolshakov Signed-off-by: Dmitry Bogdanov Link: https://lore.kernel.org/r/20220906103421.22348-5-d.bogdanov@yadro.com Reviewed-by: Mike Christie Signed-off-by: Martin K. Petersen --- drivers/target/target_core_configfs.c | 20 ++++++++++++++++++++ drivers/target/target_core_device.c | 1 + drivers/target/target_core_spc.c | 12 ++++++++++++ include/target/target_core_base.h | 3 +++ 4 files changed, 36 insertions(+) diff --git a/drivers/target/target_core_configfs.c b/drivers/target/target_core_configfs.c index 416514c5c7ac..533524299ed6 100644 --- a/drivers/target/target_core_configfs.c +++ b/drivers/target/target_core_configfs.c @@ -547,6 +547,7 @@ DEF_CONFIGFS_ATTRIB_SHOW(unmap_granularity); DEF_CONFIGFS_ATTRIB_SHOW(unmap_granularity_alignment); DEF_CONFIGFS_ATTRIB_SHOW(unmap_zeroes_data); DEF_CONFIGFS_ATTRIB_SHOW(max_write_same_len); +DEF_CONFIGFS_ATTRIB_SHOW(emulate_rsoc); #define DEF_CONFIGFS_ATTRIB_STORE_U32(_name) \ static ssize_t _name##_store(struct config_item *item, const char *page,\ @@ -1186,6 +1187,23 @@ static ssize_t pgr_support_store(struct config_item *item, return count; } +static ssize_t emulate_rsoc_store(struct config_item *item, + const char *page, size_t count) +{ + struct se_dev_attrib *da = to_attrib(item); + bool flag; + int ret; + + ret = strtobool(page, &flag); + if (ret < 0) + return ret; + + da->emulate_rsoc = flag; + pr_debug("dev[%p]: SE Device REPORT_SUPPORTED_OPERATION_CODES_EMULATION flag: %d\n", + da->da_dev, flag); + return count; +} + CONFIGFS_ATTR(, emulate_model_alias); CONFIGFS_ATTR(, emulate_dpo); CONFIGFS_ATTR(, emulate_fua_write); @@ -1198,6 +1216,7 @@ CONFIGFS_ATTR(, emulate_tpws); CONFIGFS_ATTR(, emulate_caw); CONFIGFS_ATTR(, emulate_3pc); CONFIGFS_ATTR(, emulate_pr); +CONFIGFS_ATTR(, emulate_rsoc); CONFIGFS_ATTR(, pi_prot_type); CONFIGFS_ATTR_RO(, hw_pi_prot_type); CONFIGFS_ATTR(, pi_prot_format); @@ -1261,6 +1280,7 @@ struct configfs_attribute *sbc_attrib_attrs[] = { &attr_max_write_same_len, &attr_alua_support, &attr_pgr_support, + &attr_emulate_rsoc, NULL, }; EXPORT_SYMBOL(sbc_attrib_attrs); diff --git a/drivers/target/target_core_device.c b/drivers/target/target_core_device.c index b7f16ee8aa0e..e7d202b57405 100644 --- a/drivers/target/target_core_device.c +++ b/drivers/target/target_core_device.c @@ -785,6 +785,7 @@ struct se_device *target_alloc_device(struct se_hba *hba, const char *name) dev->dev_attrib.emulate_caw = DA_EMULATE_CAW; dev->dev_attrib.emulate_3pc = DA_EMULATE_3PC; dev->dev_attrib.emulate_pr = DA_EMULATE_PR; + dev->dev_attrib.emulate_rsoc = DA_EMULATE_RSOC; dev->dev_attrib.pi_prot_type = TARGET_DIF_TYPE0_PROT; dev->dev_attrib.enforce_pr_isids = DA_ENFORCE_PR_ISIDS; dev->dev_attrib.force_pr_aptpl = DA_FORCE_PR_APTPL; diff --git a/drivers/target/target_core_spc.c b/drivers/target/target_core_spc.c index e1cf9c352fd3..91f03312a5ea 100644 --- a/drivers/target/target_core_spc.c +++ b/drivers/target/target_core_spc.c @@ -1889,6 +1889,14 @@ static struct target_opcode_descriptor tcm_opcode_report_target_pgs = { 0xff, 0xff, 0x00, SCSI_CONTROL_MASK}, }; + +static bool spc_rsoc_enabled(struct se_cmd *cmd) +{ + struct se_device *dev = cmd->se_dev; + + return dev->dev_attrib.emulate_rsoc; +} + static struct target_opcode_descriptor tcm_opcode_report_supp_opcodes = { .support = SCSI_SUPPORT_FULL, .serv_action_valid = 1, @@ -1899,6 +1907,7 @@ static struct target_opcode_descriptor tcm_opcode_report_supp_opcodes = { 0x87, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, SCSI_CONTROL_MASK}, + .enabled = spc_rsoc_enabled, }; static bool tcm_is_set_tpg_enabled(struct se_cmd *cmd) @@ -2135,6 +2144,9 @@ spc_emulate_report_supp_op_codes(struct se_cmd *cmd) sense_reason_t ret = 0; int i; + if (!cmd->se_dev->dev_attrib.emulate_rsoc) + return TCM_UNSUPPORTED_SCSI_OPCODE; + rbuf = transport_kmap_data_sg(cmd); if (cmd->data_length && !rbuf) { ret = TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE; diff --git a/include/target/target_core_base.h b/include/target/target_core_base.h index 7542a8de8fb5..062ee8b6c433 100644 --- a/include/target/target_core_base.h +++ b/include/target/target_core_base.h @@ -91,6 +91,8 @@ #define DA_EMULATE_ALUA 0 /* Emulate SCSI2 RESERVE/RELEASE and Persistent Reservations by default */ #define DA_EMULATE_PR 1 +/* Emulation for REPORT SUPPORTED OPERATION CODES */ +#define DA_EMULATE_RSOC 1 /* Enforce SCSI Initiator Port TransportID with 'ISID' for PR */ #define DA_ENFORCE_PR_ISIDS 1 /* Force SPC-3 PR Activate Persistence across Target Power Loss */ @@ -690,6 +692,7 @@ struct se_dev_attrib { bool emulate_caw; bool emulate_3pc; bool emulate_pr; + bool emulate_rsoc; enum target_prot_type pi_prot_type; enum target_prot_type hw_pi_prot_type; bool pi_prot_verify; -- cgit v1.2.3 From b8908e5e1d1de66e6905fbec7cdfbbf8ac3ecf9a Mon Sep 17 00:00:00 2001 From: Dmitry Bogdanov Date: Tue, 6 Sep 2022 13:34:20 +0300 Subject: scsi: target: core: Check emulate_3pc for RECEIVE COPY RECEIVE COPY RESULTS is an opcode from 3rd party copy command set and shall be rejected if emulate_3pc attribute is off like EXTENDED COPY. Reviewed-by: Roman Bolshakov Signed-off-by: Dmitry Bogdanov Link: https://lore.kernel.org/r/20220906103421.22348-6-d.bogdanov@yadro.com Reviewed-by: Mike Christie Signed-off-by: Martin K. Petersen --- drivers/target/target_core_xcopy.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/drivers/target/target_core_xcopy.c b/drivers/target/target_core_xcopy.c index 8713cda0c2fb..edf522208285 100644 --- a/drivers/target/target_core_xcopy.c +++ b/drivers/target/target_core_xcopy.c @@ -1009,8 +1009,14 @@ sense_reason_t target_do_receive_copy_results(struct se_cmd *se_cmd) { unsigned char *cdb = &se_cmd->t_task_cdb[0]; int sa = (cdb[1] & 0x1f), list_id = cdb[2]; + struct se_device *dev = se_cmd->se_dev; sense_reason_t rc = TCM_NO_SENSE; + if (!dev->dev_attrib.emulate_3pc) { + pr_debug("Third-party copy operations explicitly disabled\n"); + return TCM_UNSUPPORTED_SCSI_OPCODE; + } + pr_debug("Entering target_do_receive_copy_results: SA: 0x%02x, List ID:" " 0x%02x, AL: %u\n", sa, list_id, se_cmd->data_length); -- cgit v1.2.3 From 415d82b4401150c32687e1b7cc68de621ad24663 Mon Sep 17 00:00:00 2001 From: Dmitry Bogdanov Date: Tue, 6 Sep 2022 13:34:21 +0300 Subject: scsi: target: core: Dynamically set DPO and FUA in usage_bits libiscsi tests check the support of DPO & FUA bits in usage bits of RSOC response. This patch adds support for dynamic usage bits for each opcode. Set support of DPO & FUA bits in usage_bits of RSOC response depending on support DPOFUA in the backstore device. Reviewed-by: Roman Bolshakov Reviewed-by: Konstantin Shelekhin Signed-off-by: Dmitry Bogdanov Link: https://lore.kernel.org/r/20220906103421.22348-7-d.bogdanov@yadro.com Reviewed-by: Mike Christie Signed-off-by: Martin K. Petersen --- drivers/target/target_core_spc.c | 34 ++++++++++++++++++++++++++++++++-- include/target/target_core_base.h | 2 ++ 2 files changed, 34 insertions(+), 2 deletions(-) diff --git a/drivers/target/target_core_spc.c b/drivers/target/target_core_spc.c index 91f03312a5ea..ffe02e195733 100644 --- a/drivers/target/target_core_spc.c +++ b/drivers/target/target_core_spc.c @@ -1314,6 +1314,22 @@ spc_emulate_testunitready(struct se_cmd *cmd) return 0; } +static void set_dpofua_usage_bits(u8 *usage_bits, struct se_device *dev) +{ + if (!target_check_fua(dev)) + usage_bits[1] &= ~0x18; + else + usage_bits[1] |= 0x18; +} + +static void set_dpofua_usage_bits32(u8 *usage_bits, struct se_device *dev) +{ + if (!target_check_fua(dev)) + usage_bits[10] &= ~0x18; + else + usage_bits[10] |= 0x18; +} + static struct target_opcode_descriptor tcm_opcode_read6 = { .support = SCSI_SUPPORT_FULL, .opcode = READ_6, @@ -1329,6 +1345,7 @@ static struct target_opcode_descriptor tcm_opcode_read10 = { .usage_bits = {READ_10, 0xf8, 0xff, 0xff, 0xff, 0xff, SCSI_GROUP_NUMBER_MASK, 0xff, 0xff, SCSI_CONTROL_MASK}, + .update_usage_bits = set_dpofua_usage_bits, }; static struct target_opcode_descriptor tcm_opcode_read12 = { @@ -1338,6 +1355,7 @@ static struct target_opcode_descriptor tcm_opcode_read12 = { .usage_bits = {READ_12, 0xf8, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, SCSI_GROUP_NUMBER_MASK, SCSI_CONTROL_MASK}, + .update_usage_bits = set_dpofua_usage_bits, }; static struct target_opcode_descriptor tcm_opcode_read16 = { @@ -1348,6 +1366,7 @@ static struct target_opcode_descriptor tcm_opcode_read16 = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, SCSI_GROUP_NUMBER_MASK, SCSI_CONTROL_MASK}, + .update_usage_bits = set_dpofua_usage_bits, }; static struct target_opcode_descriptor tcm_opcode_write6 = { @@ -1365,6 +1384,7 @@ static struct target_opcode_descriptor tcm_opcode_write10 = { .usage_bits = {WRITE_10, 0xf8, 0xff, 0xff, 0xff, 0xff, SCSI_GROUP_NUMBER_MASK, 0xff, 0xff, SCSI_CONTROL_MASK}, + .update_usage_bits = set_dpofua_usage_bits, }; static struct target_opcode_descriptor tcm_opcode_write_verify10 = { @@ -1374,6 +1394,7 @@ static struct target_opcode_descriptor tcm_opcode_write_verify10 = { .usage_bits = {WRITE_VERIFY, 0xf0, 0xff, 0xff, 0xff, 0xff, SCSI_GROUP_NUMBER_MASK, 0xff, 0xff, SCSI_CONTROL_MASK}, + .update_usage_bits = set_dpofua_usage_bits, }; static struct target_opcode_descriptor tcm_opcode_write12 = { @@ -1383,6 +1404,7 @@ static struct target_opcode_descriptor tcm_opcode_write12 = { .usage_bits = {WRITE_12, 0xf8, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, SCSI_GROUP_NUMBER_MASK, SCSI_CONTROL_MASK}, + .update_usage_bits = set_dpofua_usage_bits, }; static struct target_opcode_descriptor tcm_opcode_write16 = { @@ -1393,6 +1415,7 @@ static struct target_opcode_descriptor tcm_opcode_write16 = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, SCSI_GROUP_NUMBER_MASK, SCSI_CONTROL_MASK}, + .update_usage_bits = set_dpofua_usage_bits, }; static struct target_opcode_descriptor tcm_opcode_write_verify16 = { @@ -1403,6 +1426,7 @@ static struct target_opcode_descriptor tcm_opcode_write_verify16 = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, SCSI_GROUP_NUMBER_MASK, SCSI_CONTROL_MASK}, + .update_usage_bits = set_dpofua_usage_bits, }; static bool tcm_is_ws_enabled(struct se_cmd *cmd) @@ -1429,6 +1453,7 @@ static struct target_opcode_descriptor tcm_opcode_write_same32 = { 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff}, .enabled = tcm_is_ws_enabled, + .update_usage_bits = set_dpofua_usage_bits32, }; static bool tcm_is_caw_enabled(struct se_cmd *cmd) @@ -1447,6 +1472,7 @@ static struct target_opcode_descriptor tcm_opcode_compare_write = { 0xff, 0xff, 0x00, 0x00, 0x00, 0xff, SCSI_GROUP_NUMBER_MASK, SCSI_CONTROL_MASK}, .enabled = tcm_is_caw_enabled, + .update_usage_bits = set_dpofua_usage_bits, }; static struct target_opcode_descriptor tcm_opcode_read_capacity = { @@ -2033,7 +2059,8 @@ spc_rsoc_encode_command_descriptor(unsigned char *buf, u8 ctdp, static int spc_rsoc_encode_one_command_descriptor(unsigned char *buf, u8 ctdp, - struct target_opcode_descriptor *descr) + struct target_opcode_descriptor *descr, + struct se_device *dev) { int td_size = 0; @@ -2045,6 +2072,8 @@ spc_rsoc_encode_one_command_descriptor(unsigned char *buf, u8 ctdp, buf[1] = (ctdp << 7) | SCSI_SUPPORT_FULL; put_unaligned_be16(descr->cdb_size, &buf[2]); memcpy(&buf[4], descr->usage_bits, descr->cdb_size); + if (descr->update_usage_bits) + descr->update_usage_bits(&buf[4], dev); td_size = spc_rsoc_encode_command_timeouts_descriptor( &buf[4 + descr->cdb_size], ctdp, descr); @@ -2187,7 +2216,8 @@ spc_emulate_report_supp_op_codes(struct se_cmd *cmd) put_unaligned_be32(response_length - 3, buf); } else { response_length = spc_rsoc_encode_one_command_descriptor( - &buf[response_length], rctd, descr); + &buf[response_length], rctd, descr, + cmd->se_dev); } memcpy(rbuf, buf, min_t(u32, response_length, cmd->data_length)); diff --git a/include/target/target_core_base.h b/include/target/target_core_base.h index 062ee8b6c433..0c1e43980985 100644 --- a/include/target/target_core_base.h +++ b/include/target/target_core_base.h @@ -880,6 +880,8 @@ struct target_opcode_descriptor { u16 nominal_timeout; u16 recommended_timeout; bool (*enabled)(struct se_cmd *cmd); + void (*update_usage_bits)(u8 *usage_bits, + struct se_device *dev); u8 usage_bits[]; }; -- cgit v1.2.3 From a301d487d7bde62de43671a1642f8f5a2e2cceef Mon Sep 17 00:00:00 2001 From: Peter Wang Date: Mon, 24 Oct 2022 20:06:02 +0800 Subject: scsi: ufs: core: Print events for WLUN suspend and resume failures WLUN suspend and resume events are currently not handled by ufshcd_print_evt_hist(). Add the missing events. Signed-off-by: Peter Wang Link: https://lore.kernel.org/r/20221024120602.30019-1-peter.wang@mediatek.com Reviewed-by: Stanley Chu Reviewed-by: Asutosh Das Signed-off-by: Martin K. Petersen --- drivers/ufs/core/ufshcd.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/ufs/core/ufshcd.c b/drivers/ufs/core/ufshcd.c index b2203dd79e8c..008fc60392fc 100644 --- a/drivers/ufs/core/ufshcd.c +++ b/drivers/ufs/core/ufshcd.c @@ -486,6 +486,9 @@ static void ufshcd_print_evt_hist(struct ufs_hba *hba) ufshcd_print_evt(hba, UFS_EVT_RESUME_ERR, "resume_fail"); ufshcd_print_evt(hba, UFS_EVT_SUSPEND_ERR, "suspend_fail"); + ufshcd_print_evt(hba, UFS_EVT_WL_RES_ERR, "wlun resume_fail"); + ufshcd_print_evt(hba, UFS_EVT_WL_SUSP_ERR, + "wlun suspend_fail"); ufshcd_print_evt(hba, UFS_EVT_DEV_RESET, "dev_reset"); ufshcd_print_evt(hba, UFS_EVT_HOST_RESET, "host_reset"); ufshcd_print_evt(hba, UFS_EVT_ABORT, "task_abort"); -- cgit v1.2.3 From 25ad6f63e77eeafc3a9f17c92aadd66c56599fdc Mon Sep 17 00:00:00 2001 From: Colin Ian King Date: Mon, 24 Oct 2022 15:11:01 +0100 Subject: scsi: pcmcia: nsp_cs: Remove unused variable i Variable i is just being incremented and it's never used anywhere else. The variable and the increment are redundant so remove it. Signed-off-by: Colin Ian King Link: https://lore.kernel.org/r/20221024141101.2161167-1-colin.i.king@gmail.com Signed-off-by: Martin K. Petersen --- drivers/scsi/pcmcia/nsp_cs.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/drivers/scsi/pcmcia/nsp_cs.c b/drivers/scsi/pcmcia/nsp_cs.c index 48acab03a8a0..a5a1406a2bde 100644 --- a/drivers/scsi/pcmcia/nsp_cs.c +++ b/drivers/scsi/pcmcia/nsp_cs.c @@ -450,8 +450,6 @@ static int nsp_analyze_sdtr(struct scsi_cmnd *SCpnt) sync_data *sync = &(data->Sync[target]); struct nsp_sync_table *sync_table; unsigned int period, offset; - int i; - nsp_dbg(NSP_DEBUG_SYNC, "in"); @@ -466,7 +464,7 @@ static int nsp_analyze_sdtr(struct scsi_cmnd *SCpnt) sync_table = nsp_sync_table_40M; } - for ( i = 0; sync_table->max_period != 0; i++, sync_table++) { + for (; sync_table->max_period != 0; sync_table++) { if ( period >= sync_table->min_period && period <= sync_table->max_period ) { break; -- cgit v1.2.3 From b43678ea5bbd92388339ecae47ed44955474f53b Mon Sep 17 00:00:00 2001 From: Bean Huo Date: Wed, 26 Oct 2022 00:24:28 +0200 Subject: scsi: ufs: core: Revert "WB is only available on LUN #0 to #7" Ccommit d3d9c4570285 ("scsi: ufs: Fix memory corruption by ufshcd_read_desc_param()") has properly fixed stack overflow issue. As a result, commit a2fca52ee640 ("scsi: ufs: WB is only available on LUN #0 to #7") is no longer required. Revert it. Cc: Jaegeuk Kim Signed-off-by: Bean Huo Link: https://lore.kernel.org/r/20221025222430.277768-2-beanhuo@iokpp.de Reviewed-by: Arthur Simchaev Reviewed-by: Bart Van Assche Signed-off-by: Martin K. Petersen --- drivers/ufs/core/ufs-sysfs.c | 3 +-- drivers/ufs/core/ufshcd-priv.h | 6 +----- drivers/ufs/core/ufshcd.c | 2 +- 3 files changed, 3 insertions(+), 8 deletions(-) diff --git a/drivers/ufs/core/ufs-sysfs.c b/drivers/ufs/core/ufs-sysfs.c index 53aea56d1de1..eb6b278c4e79 100644 --- a/drivers/ufs/core/ufs-sysfs.c +++ b/drivers/ufs/core/ufs-sysfs.c @@ -1234,8 +1234,7 @@ static ssize_t _pname##_show(struct device *dev, \ struct scsi_device *sdev = to_scsi_device(dev); \ struct ufs_hba *hba = shost_priv(sdev->host); \ u8 lun = ufshcd_scsi_to_upiu_lun(sdev->lun); \ - if (!ufs_is_valid_unit_desc_lun(&hba->dev_info, lun, \ - _duname##_DESC_PARAM##_puname)) \ + if (!ufs_is_valid_unit_desc_lun(&hba->dev_info, lun)) \ return -EINVAL; \ return ufs_sysfs_read_desc_param(hba, QUERY_DESC_IDN_##_duname, \ lun, _duname##_DESC_PARAM##_puname, buf, _size); \ diff --git a/drivers/ufs/core/ufshcd-priv.h b/drivers/ufs/core/ufshcd-priv.h index f68ca33f6ac7..a9e8e1f5afe7 100644 --- a/drivers/ufs/core/ufshcd-priv.h +++ b/drivers/ufs/core/ufshcd-priv.h @@ -293,16 +293,12 @@ static inline int ufshcd_rpm_put(struct ufs_hba *hba) * @lun: LU number to check * @return: true if the lun has a matching unit descriptor, false otherwise */ -static inline bool ufs_is_valid_unit_desc_lun(struct ufs_dev_info *dev_info, - u8 lun, u8 param_offset) +static inline bool ufs_is_valid_unit_desc_lun(struct ufs_dev_info *dev_info, u8 lun) { if (!dev_info || !dev_info->max_lu_supported) { pr_err("Max General LU supported by UFS isn't initialized\n"); return false; } - /* WB is available only for the logical unit from 0 to 7 */ - if (param_offset == UNIT_DESC_PARAM_WB_BUF_ALLOC_UNITS) - return lun < UFS_UPIU_MAX_WB_LUN_ID; return lun == UFS_UPIU_RPMB_WLUN || (lun < dev_info->max_lu_supported); } diff --git a/drivers/ufs/core/ufshcd.c b/drivers/ufs/core/ufshcd.c index 008fc60392fc..94ae0fb25358 100644 --- a/drivers/ufs/core/ufshcd.c +++ b/drivers/ufs/core/ufshcd.c @@ -3608,7 +3608,7 @@ static inline int ufshcd_read_unit_desc_param(struct ufs_hba *hba, * Unit descriptors are only available for general purpose LUs (LUN id * from 0 to 7) and RPMB Well known LU. */ - if (!ufs_is_valid_unit_desc_lun(&hba->dev_info, lun, param_offset)) + if (!ufs_is_valid_unit_desc_lun(&hba->dev_info, lun)) return -EOPNOTSUPP; return ufshcd_read_desc_param(hba, QUERY_DESC_IDN_UNIT, lun, -- cgit v1.2.3 From dca899bc02231214e25cffd3014cc77018dae942 Mon Sep 17 00:00:00 2001 From: Bean Huo Date: Wed, 26 Oct 2022 00:24:29 +0200 Subject: scsi: ufs: core: Clean up ufshcd_slave_alloc() Combine ufshcd_get_lu_power_on_wp_status() and ufshcd_set_queue_depth() into one single ufshcd_lu_init(), so that we only need to read the LUN descriptor once. Signed-off-by: Bean Huo Link: https://lore.kernel.org/r/20221025222430.277768-3-beanhuo@iokpp.de Reviewed-by: Arthur Simchaev Reviewed-by: Bart Van Assche Signed-off-by: Martin K. Petersen --- drivers/ufs/core/ufshcd.c | 150 ++++++++++++++++------------------------------ 1 file changed, 53 insertions(+), 97 deletions(-) diff --git a/drivers/ufs/core/ufshcd.c b/drivers/ufs/core/ufshcd.c index 94ae0fb25358..ee73d7036133 100644 --- a/drivers/ufs/core/ufshcd.c +++ b/drivers/ufs/core/ufshcd.c @@ -4861,100 +4861,6 @@ static int ufshcd_verify_dev_init(struct ufs_hba *hba) return err; } -/** - * ufshcd_set_queue_depth - set lun queue depth - * @sdev: pointer to SCSI device - * - * Read bLUQueueDepth value and activate scsi tagged command - * queueing. For WLUN, queue depth is set to 1. For best-effort - * cases (bLUQueueDepth = 0) the queue depth is set to a maximum - * value that host can queue. - */ -static void ufshcd_set_queue_depth(struct scsi_device *sdev) -{ - int ret = 0; - u8 lun_qdepth; - struct ufs_hba *hba; - - hba = shost_priv(sdev->host); - - lun_qdepth = hba->nutrs; - ret = ufshcd_read_unit_desc_param(hba, - ufshcd_scsi_to_upiu_lun(sdev->lun), - UNIT_DESC_PARAM_LU_Q_DEPTH, - &lun_qdepth, - sizeof(lun_qdepth)); - - /* Some WLUN doesn't support unit descriptor */ - if (ret == -EOPNOTSUPP) - lun_qdepth = 1; - else if (!lun_qdepth) - /* eventually, we can figure out the real queue depth */ - lun_qdepth = hba->nutrs; - else - lun_qdepth = min_t(int, lun_qdepth, hba->nutrs); - - dev_dbg(hba->dev, "%s: activate tcq with queue depth %d\n", - __func__, lun_qdepth); - scsi_change_queue_depth(sdev, lun_qdepth); -} - -/* - * ufshcd_get_lu_wp - returns the "b_lu_write_protect" from UNIT DESCRIPTOR - * @hba: per-adapter instance - * @lun: UFS device lun id - * @b_lu_write_protect: pointer to buffer to hold the LU's write protect info - * - * Returns 0 in case of success and b_lu_write_protect status would be returned - * @b_lu_write_protect parameter. - * Returns -ENOTSUPP if reading b_lu_write_protect is not supported. - * Returns -EINVAL in case of invalid parameters passed to this function. - */ -static int ufshcd_get_lu_wp(struct ufs_hba *hba, - u8 lun, - u8 *b_lu_write_protect) -{ - int ret; - - if (!b_lu_write_protect) - ret = -EINVAL; - /* - * According to UFS device spec, RPMB LU can't be write - * protected so skip reading bLUWriteProtect parameter for - * it. For other W-LUs, UNIT DESCRIPTOR is not available. - */ - else if (lun >= hba->dev_info.max_lu_supported) - ret = -ENOTSUPP; - else - ret = ufshcd_read_unit_desc_param(hba, - lun, - UNIT_DESC_PARAM_LU_WR_PROTECT, - b_lu_write_protect, - sizeof(*b_lu_write_protect)); - return ret; -} - -/** - * ufshcd_get_lu_power_on_wp_status - get LU's power on write protect - * status - * @hba: per-adapter instance - * @sdev: pointer to SCSI device - * - */ -static inline void ufshcd_get_lu_power_on_wp_status(struct ufs_hba *hba, - const struct scsi_device *sdev) -{ - if (hba->dev_info.f_power_on_wp_en && - !hba->dev_info.is_lu_power_on_wp) { - u8 b_lu_write_protect; - - if (!ufshcd_get_lu_wp(hba, ufshcd_scsi_to_upiu_lun(sdev->lun), - &b_lu_write_protect) && - (b_lu_write_protect == UFS_LU_POWER_ON_WP)) - hba->dev_info.is_lu_power_on_wp = true; - } -} - /** * ufshcd_setup_links - associate link b/w device wlun and other luns * @sdev: pointer to SCSI device @@ -4992,6 +4898,58 @@ static void ufshcd_setup_links(struct ufs_hba *hba, struct scsi_device *sdev) } } +/** + * ufshcd_lu_init - Initialize the relevant parameters of the LU + * @hba: per-adapter instance + * @sdev: pointer to SCSI device + */ +static void ufshcd_lu_init(struct ufs_hba *hba, struct scsi_device *sdev) +{ + int len = hba->desc_size[QUERY_DESC_IDN_UNIT]; + u8 lun = ufshcd_scsi_to_upiu_lun(sdev->lun); + u8 lun_qdepth = hba->nutrs; + u8 *desc_buf; + int ret; + + desc_buf = kzalloc(len, GFP_KERNEL); + if (!desc_buf) + goto set_qdepth; + + ret = ufshcd_read_unit_desc_param(hba, lun, 0, desc_buf, len); + if (ret < 0) { + if (ret == -EOPNOTSUPP) + /* If LU doesn't support unit descriptor, its queue depth is set to 1 */ + lun_qdepth = 1; + kfree(desc_buf); + goto set_qdepth; + } + + if (desc_buf[UNIT_DESC_PARAM_LU_Q_DEPTH]) { + /* + * In per-LU queueing architecture, bLUQueueDepth will not be 0, then we will + * use the smaller between UFSHCI CAP.NUTRS and UFS LU bLUQueueDepth + */ + lun_qdepth = min_t(int, desc_buf[UNIT_DESC_PARAM_LU_Q_DEPTH], hba->nutrs); + } + /* + * According to UFS device specification, the write protection mode is only supported by + * normal LU, not supported by WLUN. + */ + if (hba->dev_info.f_power_on_wp_en && lun < hba->dev_info.max_lu_supported && + !hba->dev_info.is_lu_power_on_wp && + desc_buf[UNIT_DESC_PARAM_LU_WR_PROTECT] == UFS_LU_POWER_ON_WP) + hba->dev_info.is_lu_power_on_wp = true; + + kfree(desc_buf); +set_qdepth: + /* + * For WLUNs that don't support unit descriptor, queue depth is set to 1. For LUs whose + * bLUQueueDepth == 0, the queue depth is set to a maximum value that host can queue. + */ + dev_dbg(hba->dev, "Set LU %x queue depth %d\n", lun, lun_qdepth); + scsi_change_queue_depth(sdev, lun_qdepth); +} + /** * ufshcd_slave_alloc - handle initial SCSI device configurations * @sdev: pointer to SCSI device @@ -5019,9 +4977,7 @@ static int ufshcd_slave_alloc(struct scsi_device *sdev) /* WRITE_SAME command is not supported */ sdev->no_write_same = 1; - ufshcd_set_queue_depth(sdev); - - ufshcd_get_lu_power_on_wp_status(hba, sdev); + ufshcd_lu_init(hba, sdev); ufshcd_setup_links(hba, sdev); -- cgit v1.2.3 From 9d266e792b0fb4c25448dc240a808667e0932ef2 Mon Sep 17 00:00:00 2001 From: Bean Huo Date: Wed, 26 Oct 2022 00:24:30 +0200 Subject: scsi: ufs: core: Use is_visible to control UFS unit descriptor sysfs nodes UFS Boot and Device W-LUs do not have unit descriptors and RPMB does not support WB. Use is_visible() to control which nodes are visible and which are not. Signed-off-by: Bean Huo Link: https://lore.kernel.org/r/20221025222430.277768-4-beanhuo@iokpp.de Reviewed-by: Bart Van Assche Reviewed-by: Arthur Simchaev Signed-off-by: Martin K. Petersen --- drivers/ufs/core/ufs-sysfs.c | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/drivers/ufs/core/ufs-sysfs.c b/drivers/ufs/core/ufs-sysfs.c index eb6b278c4e79..883f0e44b54e 100644 --- a/drivers/ufs/core/ufs-sysfs.c +++ b/drivers/ufs/core/ufs-sysfs.c @@ -1285,9 +1285,27 @@ static struct attribute *ufs_sysfs_unit_descriptor[] = { NULL, }; +static umode_t ufs_unit_descriptor_is_visible(struct kobject *kobj, struct attribute *attr, int n) +{ + struct device *dev = container_of(kobj, struct device, kobj); + struct scsi_device *sdev = to_scsi_device(dev); + u8 lun = ufshcd_scsi_to_upiu_lun(sdev->lun); + umode_t mode = attr->mode; + + if (lun == UFS_UPIU_BOOT_WLUN || lun == UFS_UPIU_UFS_DEVICE_WLUN) + /* Boot and device WLUN have no unit descriptors */ + mode = 0; + if (lun == UFS_UPIU_RPMB_WLUN && attr == &dev_attr_wb_buf_alloc_units.attr) + mode = 0; + + return mode; +} + + const struct attribute_group ufs_sysfs_unit_descriptor_group = { .name = "unit_descriptor", .attrs = ufs_sysfs_unit_descriptor, + .is_visible = ufs_unit_descriptor_is_visible, }; static ssize_t dyn_cap_needed_attribute_show(struct device *dev, -- cgit v1.2.3 From 4481bdc677c1aa9b0138ee9234c8c2d14142b42e Mon Sep 17 00:00:00 2001 From: John Garry Date: Wed, 26 Oct 2022 18:56:04 +0800 Subject: scsi: pm8001: Drop !task check in pm8001_abort_task() In commit 0b639decf651 ("scsi: pm8001: Modify task abort handling for SATA task"), code was introduced to dereference "task" pointer in pm8001_abort_task(). However there was a pre-existing later check for "!task", which spooked the kernel test robot. Function pm8001_abort_task() should never be passed NULL for "task" pointer, so remove that check. Also remove the "unlikely" hint, as this is not fastpath code. Reported-by: kernel test robot Reported-by: Dan Carpenter Signed-off-by: John Garry Link: https://lore.kernel.org/r/1666781764-123090-1-git-send-email-john.garry@huawei.com Reviewed-by: Damien Le Moal Acked-by: Jack Wang Signed-off-by: Martin K. Petersen --- drivers/scsi/pm8001/pm8001_sas.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/scsi/pm8001/pm8001_sas.c b/drivers/scsi/pm8001/pm8001_sas.c index 2359e827c9e6..e5673c774f66 100644 --- a/drivers/scsi/pm8001/pm8001_sas.c +++ b/drivers/scsi/pm8001/pm8001_sas.c @@ -979,7 +979,7 @@ int pm8001_abort_task(struct sas_task *task) u32 phy_id, port_id; struct sas_task_slow slow_task; - if (unlikely(!task || !task->lldd_task || !task->dev)) + if (!task->lldd_task || !task->dev) return TMF_RESP_FUNC_FAILED; dev = task->dev; -- cgit v1.2.3 From e6629dcb00adeebcfeaee45b1c987a84eb3ce1ba Mon Sep 17 00:00:00 2001 From: John Garry Date: Wed, 26 Oct 2022 19:33:28 +0800 Subject: scsi: MAINTAINERS: Make Xiang Chen HiSilicon SAS controller driver maintainer I am soon leaving Huawei, so will no longer maintain this driver. However I will stay active in upstream Linux storage domain. Xiang Chen has worked on the driver for as long as I have and has good knowledge of the driver, so should do a good job. Signed-off-by: John Garry Link: https://lore.kernel.org/r/1666784008-125519-1-git-send-email-john.garry@huawei.com Signed-off-by: Martin K. Petersen --- MAINTAINERS | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/MAINTAINERS b/MAINTAINERS index cf0f18502372..174de5e8d4c8 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -9290,7 +9290,7 @@ F: Documentation/devicetree/bindings/infiniband/hisilicon-hns-roce.txt F: drivers/infiniband/hw/hns/ HISILICON SAS Controller -M: John Garry +M: Xiang Chen S: Supported W: http://www.hisilicon.com F: Documentation/devicetree/bindings/scsi/hisilicon-sas.txt -- cgit v1.2.3 From bc77fb9ce40c276cedf889dca2bc6d1b1edc2763 Mon Sep 17 00:00:00 2001 From: Keoseong Park Date: Fri, 28 Oct 2022 16:35:53 +0900 Subject: scsi: ufs: core: Refactor ufshcd_hba_enable() Use "if error return" style in ufshcd_hba_enable(). No functional change. Cc: Bart Van Assche Cc: Alim Akhtar Signed-off-by: Keoseong Park Link: https://lore.kernel.org/r/20221028073553epcms2p6dc4f8bdbebdc8f96f43fc4197b3edd0c@epcms2p6 Reviewed-by: Bart Van Assche Signed-off-by: Martin K. Petersen --- drivers/ufs/core/ufshcd.c | 18 +++++++++++------- 1 file changed, 11 insertions(+), 7 deletions(-) diff --git a/drivers/ufs/core/ufshcd.c b/drivers/ufs/core/ufshcd.c index ee73d7036133..0591d05c078a 100644 --- a/drivers/ufs/core/ufshcd.c +++ b/drivers/ufs/core/ufshcd.c @@ -4668,14 +4668,18 @@ int ufshcd_hba_enable(struct ufs_hba *hba) /* enable UIC related interrupts */ ufshcd_enable_intr(hba, UFSHCD_UIC_MASK); ret = ufshcd_dme_reset(hba); - if (!ret) { - ret = ufshcd_dme_enable(hba); - if (!ret) - ufshcd_vops_hce_enable_notify(hba, POST_CHANGE); - if (ret) - dev_err(hba->dev, - "Host controller enable failed with non-hce\n"); + if (ret) { + dev_err(hba->dev, "DME_RESET failed\n"); + return ret; } + + ret = ufshcd_dme_enable(hba); + if (ret) { + dev_err(hba->dev, "Enabling DME failed\n"); + return ret; + } + + ufshcd_vops_hce_enable_notify(hba, POST_CHANGE); } else { ret = ufshcd_hba_execute_hce(hba); } -- cgit v1.2.3 From e47c49219c1e20760cd66cef4411b35a3a86c0a2 Mon Sep 17 00:00:00 2001 From: Jilin Yuan Date: Fri, 28 Oct 2022 21:37:08 +0800 Subject: scsi: NCR5380: Fix repeated words in comment Delete the redundant word 'the'. Signed-off-by: Jilin Yuan Link: https://lore.kernel.org/r/20221028133708.60030-1-yuanjilin@cdjrlc.com Acked-by: Finn Thain Signed-off-by: Martin K. Petersen --- drivers/scsi/NCR5380.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/scsi/NCR5380.c b/drivers/scsi/NCR5380.c index dece7d9eb4d3..ca85bddb582b 100644 --- a/drivers/scsi/NCR5380.c +++ b/drivers/scsi/NCR5380.c @@ -858,7 +858,7 @@ static void NCR5380_dma_complete(struct Scsi_Host *instance) * latency, but a bus reset will reset chip logic. Checking for parity error * is unnecessary because that interrupt is never enabled. A Loss of BSY * condition will clear DMA Mode. We can tell when this occurs because the - * the Busy Monitor interrupt is enabled together with DMA Mode. + * Busy Monitor interrupt is enabled together with DMA Mode. */ static irqreturn_t __maybe_unused NCR5380_intr(int irq, void *dev_id) -- cgit v1.2.3 From c7cbaab2d464484008b4f8ed66b6bb0ee99745c2 Mon Sep 17 00:00:00 2001 From: Colin Ian King Date: Mon, 31 Oct 2022 15:45:38 +0000 Subject: scsi: message: fusion: Remove variable 'where' Variable 'where' is just being incremented and it's never used anywhere else. Remove it. Signed-off-by: Colin Ian King Link: https://lore.kernel.org/r/20221031154538.870223-1-colin.i.king@gmail.com Signed-off-by: Martin K. Petersen --- drivers/message/fusion/mptctl.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/drivers/message/fusion/mptctl.c b/drivers/message/fusion/mptctl.c index 52c7020c9d19..1decd09a08d8 100644 --- a/drivers/message/fusion/mptctl.c +++ b/drivers/message/fusion/mptctl.c @@ -2879,7 +2879,6 @@ static struct mpt_pci_driver mptctl_driver = { static int __init mptctl_init(void) { int err; - int where = 1; show_mptmod_ver(my_NAME, my_VERSION); @@ -2898,7 +2897,6 @@ static int __init mptctl_init(void) /* * Install our handler */ - ++where; mptctl_id = mpt_register(mptctl_reply, MPTCTL_DRIVER, "mptctl_reply"); if (!mptctl_id || mptctl_id >= MPT_MAX_PROTOCOL_DRIVERS) { -- cgit v1.2.3 From 81cb3eb68af5d0bee61ea45a72a0e6e3862b246f Mon Sep 17 00:00:00 2001 From: Colin Ian King Date: Mon, 31 Oct 2022 16:05:12 +0000 Subject: scsi: BusLogic: Remove variable 'adapter_count' Variable 'adapter_count' is just being incremented and it's never used anywhere else. Remove it. Signed-off-by: Colin Ian King Link: https://lore.kernel.org/r/20221031160512.872153-1-colin.i.king@gmail.com Acked-by: Khalid Aziz Signed-off-by: Martin K. Petersen --- drivers/scsi/BusLogic.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/drivers/scsi/BusLogic.c b/drivers/scsi/BusLogic.c index f2abffce2659..f7b7ffda1161 100644 --- a/drivers/scsi/BusLogic.c +++ b/drivers/scsi/BusLogic.c @@ -2198,7 +2198,7 @@ static int blogic_slaveconfig(struct scsi_device *dev) static int __init blogic_init(void) { - int adapter_count = 0, drvr_optindex = 0, probeindex; + int drvr_optindex = 0, probeindex; struct blogic_adapter *adapter; int ret = 0; @@ -2368,10 +2368,8 @@ static int __init blogic_init(void) list_del(&myadapter->host_list); scsi_host_put(host); ret = -ENODEV; - } else { + } else scsi_scan_host(host); - adapter_count++; - } } } else { /* -- cgit v1.2.3 From b817e6ffbad7a1a0a5ca5bb7d4020823c3f4d9d0 Mon Sep 17 00:00:00 2001 From: Bart Van Assche Date: Mon, 31 Oct 2022 11:34:21 -0700 Subject: scsi: ufs: core: Introduce ufshcd_abort_all() Move the code for aborting all SCSI commands and TMFs into a new function. This patch makes the ufshcd_err_handler() easier to read. Except for adding more logging, this patch does not change any functionality. Signed-off-by: Bart Van Assche Link: https://lore.kernel.org/r/20221031183433.2443554-1-bvanassche@acm.org Reviewed-by: Adrian Hunter Signed-off-by: Martin K. Petersen --- drivers/ufs/core/ufshcd.c | 62 ++++++++++++++++++++++++++--------------------- 1 file changed, 34 insertions(+), 28 deletions(-) diff --git a/drivers/ufs/core/ufshcd.c b/drivers/ufs/core/ufshcd.c index 0591d05c078a..768cb49d269c 100644 --- a/drivers/ufs/core/ufshcd.c +++ b/drivers/ufs/core/ufshcd.c @@ -6161,6 +6161,38 @@ static bool ufshcd_is_pwr_mode_restore_needed(struct ufs_hba *hba) return false; } +static bool ufshcd_abort_all(struct ufs_hba *hba) +{ + bool needs_reset = false; + int tag, ret; + + /* Clear pending transfer requests */ + for_each_set_bit(tag, &hba->outstanding_reqs, hba->nutrs) { + ret = ufshcd_try_to_abort_task(hba, tag); + dev_err(hba->dev, "Aborting tag %d / CDB %#02x %s\n", tag, + hba->lrb[tag].cmd ? hba->lrb[tag].cmd->cmnd[0] : -1, + ret ? "failed" : "succeeded"); + if (ret) { + needs_reset = true; + goto out; + } + } + + /* Clear pending task management requests */ + for_each_set_bit(tag, &hba->outstanding_tasks, hba->nutmrs) { + if (ufshcd_clear_tm_cmd(hba, tag)) { + needs_reset = true; + goto out; + } + } + +out: + /* Complete the requests that are cleared by s/w */ + ufshcd_complete_requests(hba); + + return needs_reset; +} + /** * ufshcd_err_handler - handle UFS errors that require s/w attention * @work: pointer to work structure @@ -6172,10 +6204,7 @@ static void ufshcd_err_handler(struct work_struct *work) unsigned long flags; bool needs_restore; bool needs_reset; - bool err_xfer; - bool err_tm; int pmc_err; - int tag; hba = container_of(work, struct ufs_hba, eh_work); @@ -6204,8 +6233,6 @@ static void ufshcd_err_handler(struct work_struct *work) again: needs_restore = false; needs_reset = false; - err_xfer = false; - err_tm = false; if (hba->ufshcd_state != UFSHCD_STATE_ERROR) hba->ufshcd_state = UFSHCD_STATE_RESET; @@ -6274,34 +6301,13 @@ again: hba->silence_err_logs = true; /* release lock as clear command might sleep */ spin_unlock_irqrestore(hba->host->host_lock, flags); - /* Clear pending transfer requests */ - for_each_set_bit(tag, &hba->outstanding_reqs, hba->nutrs) { - if (ufshcd_try_to_abort_task(hba, tag)) { - err_xfer = true; - goto lock_skip_pending_xfer_clear; - } - dev_err(hba->dev, "Aborted tag %d / CDB %#02x\n", tag, - hba->lrb[tag].cmd ? hba->lrb[tag].cmd->cmnd[0] : -1); - } - /* Clear pending task management requests */ - for_each_set_bit(tag, &hba->outstanding_tasks, hba->nutmrs) { - if (ufshcd_clear_tm_cmd(hba, tag)) { - err_tm = true; - goto lock_skip_pending_xfer_clear; - } - } - -lock_skip_pending_xfer_clear: - /* Complete the requests that are cleared by s/w */ - ufshcd_complete_requests(hba); + needs_reset = ufshcd_abort_all(hba); spin_lock_irqsave(hba->host->host_lock, flags); hba->silence_err_logs = false; - if (err_xfer || err_tm) { - needs_reset = true; + if (needs_reset) goto do_reset; - } /* * After all reqs and tasks are cleared from doorbell, -- cgit v1.2.3 From 3d75e766b58a7410d4e835c534e1b4664a8f62d0 Mon Sep 17 00:00:00 2001 From: Nathan Chancellor Date: Wed, 2 Nov 2022 09:19:06 -0700 Subject: scsi: elx: libefc: Fix second parameter type in state callbacks With clang's kernel control flow integrity (kCFI, CONFIG_CFI_CLANG), indirect call targets are validated against the expected function pointer prototype to make sure the call target is valid to help mitigate ROP attacks. If they are not identical, there is a failure at run time, which manifests as either a kernel panic or thread getting killed. A proposed warning in clang aims to catch these at compile time, which reveals: drivers/scsi/elx/libefc/efc_node.c:811:22: error: incompatible function pointer types assigning to 'void (*)(struct efc_sm_ctx *, u32, void *)' (aka 'void (*)(struct efc_sm_ctx *, unsigned int, void *)') from 'void (*)(struct efc_sm_ctx *, enum efc_sm_event, void *)' [-Werror,-Wincompatible-function-pointer-types-strict] ctx->current_state = state; ^ ~~~~~ drivers/scsi/elx/libefc/efc_node.c:878:21: error: incompatible function pointer types assigning to 'void (*)(struct efc_sm_ctx *, u32, void *)' (aka 'void (*)(struct efc_sm_ctx *, unsigned int, void *)') from 'void (*)(struct efc_sm_ctx *, enum efc_sm_event, void *)' [-Werror,-Wincompatible-function-pointer-types-strict] node->nodedb_state = state; ^ ~~~~~ drivers/scsi/elx/libefc/efc_node.c:905:6: error: incompatible function pointer types assigning to 'void (*)(struct efc_sm_ctx *, enum efc_sm_event, void *)' from 'void (*)(struct efc_sm_ctx *, u32, void *)' (aka 'void (*)(struct efc_sm_ctx *, unsigned int, void *)') [-Werror,-Wincompatible-function-pointer-types-strict] pf = node->nodedb_state; ^ ~~~~~~~~~~~~~~~~~~ drivers/scsi/elx/libefc/efc_device.c:455:22: error: incompatible function pointer types assigning to 'void (*)(struct efc_sm_ctx *, u32, void *)' (aka 'void (*)(struct efc_sm_ctx *, unsigned int, void *)') from 'void (struct efc_sm_ctx *, enum efc_sm_event, void *)' [-Werror,-Wincompatible-function-pointer-types-strict] node->nodedb_state = __efc_d_init; ^ ~~~~~~~~~~~~ drivers/scsi/elx/libefc/efc_sm.c:41:22: error: incompatible function pointer types assigning to 'void (*)(struct efc_sm_ctx *, u32, void *)' (aka 'void (*)(struct efc_sm_ctx *, unsigned int, void *)') from 'void (*)(struct efc_sm_ctx *, enum efc_sm_event, void *)' [-Werror,-Wincompatible-function-pointer-types-strict] ctx->current_state = state; ^ ~~~~~ The type of the second parameter in the prototypes of ->current_state() and ->nodedb_state() ('u32') does not match the implementations, which have a second parameter type of 'enum efc_sm_event'. Update the prototypes to have the correct second parameter type, clearing up all the warnings and CFI failures. Link: https://github.com/ClangBuiltLinux/linux/issues/1750 Reported-by: Sami Tolvanen Signed-off-by: Nathan Chancellor Link: https://lore.kernel.org/r/20221102161906.2781508-1-nathan@kernel.org Reviewed-by: Kees Cook Signed-off-by: Martin K. Petersen --- drivers/scsi/elx/libefc/efclib.h | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/drivers/scsi/elx/libefc/efclib.h b/drivers/scsi/elx/libefc/efclib.h index dde20891c2dd..57e338612812 100644 --- a/drivers/scsi/elx/libefc/efclib.h +++ b/drivers/scsi/elx/libefc/efclib.h @@ -58,10 +58,12 @@ enum efc_node_send_ls_acc { #define EFC_LINK_STATUS_UP 0 #define EFC_LINK_STATUS_DOWN 1 +enum efc_sm_event; + /* State machine context header */ struct efc_sm_ctx { void (*current_state)(struct efc_sm_ctx *ctx, - u32 evt, void *arg); + enum efc_sm_event evt, void *arg); const char *description; void *app; @@ -365,7 +367,7 @@ struct efc_node { int prev_evt; void (*nodedb_state)(struct efc_sm_ctx *ctx, - u32 evt, void *arg); + enum efc_sm_event evt, void *arg); struct timer_list gidpt_delay_timer; u64 time_last_gidpt_msec; -- cgit v1.2.3 From 3d6d7930928ace6b982258ebb81d585fe20e9f44 Mon Sep 17 00:00:00 2001 From: Keoseong Park Date: Thu, 3 Nov 2022 14:53:49 +0900 Subject: scsi: ufs: core: Remove check_upiu_size() from ufshcd.h Commit 68078d5cc1a5 ("[SCSI] ufs: Set fDeviceInit flag to initiate device initialization") added check_upiu_size(), but no caller. Cc: Dolev Raviv Link: https://lore.kernel.org/r/20221103055349epcms2p338f2550c2dd78d00231a83b24719a3d4@epcms2p3 Signed-off-by: Keoseong Park Reviewed-by: Avri Altman Signed-off-by: Martin K. Petersen --- include/ufs/ufshcd.h | 6 ------ 1 file changed, 6 deletions(-) diff --git a/include/ufs/ufshcd.h b/include/ufs/ufshcd.h index 96538eb3a6c0..5cf81dff60aa 100644 --- a/include/ufs/ufshcd.h +++ b/include/ufs/ufshcd.h @@ -1072,12 +1072,6 @@ void ufshcd_update_evt_hist(struct ufs_hba *hba, u32 id, u32 val); void ufshcd_hba_stop(struct ufs_hba *hba); void ufshcd_schedule_eh_work(struct ufs_hba *hba); -static inline void check_upiu_size(void) -{ - BUILD_BUG_ON(ALIGNED_UPIU_SIZE < - GENERAL_UPIU_REQUEST_SIZE + QUERY_DESC_MAX_SIZE); -} - /** * ufshcd_set_variant - set variant specific data to the hba * @hba: per adapter instance -- cgit v1.2.3 From 0b25e17e9018a0ea68a9f0b4787672e8c68fa8d5 Mon Sep 17 00:00:00 2001 From: Bart Van Assche Date: Mon, 31 Oct 2022 15:47:25 -0700 Subject: scsi: alua: Move a scsi_device_put() call out of alua_check_vpd() Fix the following smatch warning: drivers/scsi/device_handler/scsi_dh_alua.c:1013 alua_rtpg_queue() warn: sleeping in atomic context alua_check_vpd() <- disables preempt -> alua_rtpg_queue() -> scsi_device_put() Cc: Hannes Reinecke Cc: Dan Carpenter Reported-by: Dan Carpenter Signed-off-by: Bart Van Assche Link: https://lore.kernel.org/r/20221031224728.2607760-2-bvanassche@acm.org Reviewed-by: Hannes Reinecke Signed-off-by: Martin K. Petersen --- drivers/scsi/device_handler/scsi_dh_alua.c | 23 +++++++++++++++-------- 1 file changed, 15 insertions(+), 8 deletions(-) diff --git a/drivers/scsi/device_handler/scsi_dh_alua.c b/drivers/scsi/device_handler/scsi_dh_alua.c index 610a51538f03..f7bc81cc59ab 100644 --- a/drivers/scsi/device_handler/scsi_dh_alua.c +++ b/drivers/scsi/device_handler/scsi_dh_alua.c @@ -324,6 +324,7 @@ static int alua_check_vpd(struct scsi_device *sdev, struct alua_dh_data *h, struct alua_port_group *pg, *old_pg = NULL; bool pg_updated = false; unsigned long flags; + bool put_sdev; group_id = scsi_vpd_tpg_id(sdev, &rel_port); if (group_id < 0) { @@ -373,11 +374,14 @@ static int alua_check_vpd(struct scsi_device *sdev, struct alua_dh_data *h, list_add_rcu(&h->node, &pg->dh_list); spin_unlock_irqrestore(&pg->lock, flags); - alua_rtpg_queue(rcu_dereference_protected(h->pg, + put_sdev = alua_rtpg_queue(rcu_dereference_protected(h->pg, lockdep_is_held(&h->pg_lock)), sdev, NULL, true); spin_unlock(&h->pg_lock); + if (put_sdev) + scsi_device_put(sdev); + if (old_pg) kref_put(&old_pg->kref, release_port_group); @@ -968,9 +972,10 @@ static void alua_rtpg_work(struct work_struct *work) * RTPG already has been scheduled. * * Returns true if and only if alua_rtpg_work() will be called asynchronously. - * That function is responsible for calling @qdata->fn(). + * That function is responsible for calling @qdata->fn(). If this function + * returns true, the caller is responsible for invoking scsi_device_put(@sdev). */ -static bool alua_rtpg_queue(struct alua_port_group *pg, +static bool __must_check alua_rtpg_queue(struct alua_port_group *pg, struct scsi_device *sdev, struct alua_queue_data *qdata, bool force) { @@ -1009,8 +1014,6 @@ static bool alua_rtpg_queue(struct alua_port_group *pg, else kref_put(&pg->kref, release_port_group); } - if (sdev) - scsi_device_put(sdev); return true; } @@ -1117,10 +1120,12 @@ static int alua_activate(struct scsi_device *sdev, rcu_read_unlock(); mutex_unlock(&h->init_mutex); - if (alua_rtpg_queue(pg, sdev, qdata, true)) + if (alua_rtpg_queue(pg, sdev, qdata, true)) { + scsi_device_put(sdev); fn = NULL; - else + } else { err = SCSI_DH_DEV_OFFLINED; + } kref_put(&pg->kref, release_port_group); out: if (fn) @@ -1146,7 +1151,9 @@ static void alua_check(struct scsi_device *sdev, bool force) return; } rcu_read_unlock(); - alua_rtpg_queue(pg, sdev, NULL, force); + + if (alua_rtpg_queue(pg, sdev, NULL, force)) + scsi_device_put(sdev); kref_put(&pg->kref, release_port_group); } -- cgit v1.2.3 From 379e2554e3d10e87c0c0a728ef538f3c26d82a98 Mon Sep 17 00:00:00 2001 From: Bart Van Assche Date: Mon, 31 Oct 2022 15:47:26 -0700 Subject: scsi: alua: Move a scsi_device_put() call out of alua_rtpg_select_sdev() Move a scsi_device_put() call from alua_rtpg_select_sdev() to its callers. Fixes the following smatch complaint: drivers/scsi/device_handler/scsi_dh_alua.c:853 alua_rtpg_select_sdev() warn: sleeping in atomic context alua_rtpg_work() <- disables preempt -> alua_rtpg_select_sdev() -> scsi_device_put() Cc: Hannes Reinecke Cc: Dan Carpenter Reported-by: Dan Carpenter Signed-off-by: Bart Van Assche Link: https://lore.kernel.org/r/20221031224728.2607760-3-bvanassche@acm.org Signed-off-by: Martin K. Petersen --- drivers/scsi/device_handler/scsi_dh_alua.c | 38 +++++++++++++++++++----------- 1 file changed, 24 insertions(+), 14 deletions(-) diff --git a/drivers/scsi/device_handler/scsi_dh_alua.c b/drivers/scsi/device_handler/scsi_dh_alua.c index f7bc81cc59ab..693cd827e138 100644 --- a/drivers/scsi/device_handler/scsi_dh_alua.c +++ b/drivers/scsi/device_handler/scsi_dh_alua.c @@ -815,14 +815,19 @@ static unsigned alua_stpg(struct scsi_device *sdev, struct alua_port_group *pg) return SCSI_DH_RETRY; } -static bool alua_rtpg_select_sdev(struct alua_port_group *pg) +/* + * The caller must call scsi_device_put() on the returned pointer if it is not + * NULL. + */ +static struct scsi_device * __must_check +alua_rtpg_select_sdev(struct alua_port_group *pg) { struct alua_dh_data *h; - struct scsi_device *sdev = NULL; + struct scsi_device *sdev = NULL, *prev_sdev; lockdep_assert_held(&pg->lock); if (WARN_ON(!pg->rtpg_sdev)) - return false; + return NULL; /* * RCU protection isn't necessary for dh_list here @@ -849,22 +854,22 @@ static bool alua_rtpg_select_sdev(struct alua_port_group *pg) pr_warn("%s: no device found for rtpg\n", (pg->device_id_len ? (char *)pg->device_id_str : "(nameless PG)")); - return false; + return NULL; } sdev_printk(KERN_INFO, sdev, "rtpg retry on different device\n"); - scsi_device_put(pg->rtpg_sdev); + prev_sdev = pg->rtpg_sdev; pg->rtpg_sdev = sdev; - return true; + return prev_sdev; } static void alua_rtpg_work(struct work_struct *work) { struct alua_port_group *pg = container_of(work, struct alua_port_group, rtpg_work.work); - struct scsi_device *sdev; + struct scsi_device *sdev, *prev_sdev = NULL; LIST_HEAD(qdata_list); int err = SCSI_DH_OK; struct alua_queue_data *qdata, *tmp; @@ -905,7 +910,7 @@ static void alua_rtpg_work(struct work_struct *work) /* If RTPG failed on the current device, try using another */ if (err == SCSI_DH_RES_TEMP_UNAVAIL && - alua_rtpg_select_sdev(pg)) + (prev_sdev = alua_rtpg_select_sdev(pg))) err = SCSI_DH_IMM_RETRY; if (err == SCSI_DH_RETRY || err == SCSI_DH_IMM_RETRY || @@ -917,9 +922,7 @@ static void alua_rtpg_work(struct work_struct *work) pg->interval = ALUA_RTPG_RETRY_DELAY; pg->flags |= ALUA_PG_RUN_RTPG; spin_unlock_irqrestore(&pg->lock, flags); - queue_delayed_work(kaluad_wq, &pg->rtpg_work, - pg->interval * HZ); - return; + goto queue_rtpg; } if (err != SCSI_DH_OK) pg->flags &= ~ALUA_PG_RUN_STPG; @@ -934,9 +937,7 @@ static void alua_rtpg_work(struct work_struct *work) pg->interval = 0; pg->flags &= ~ALUA_PG_RUNNING; spin_unlock_irqrestore(&pg->lock, flags); - queue_delayed_work(kaluad_wq, &pg->rtpg_work, - pg->interval * HZ); - return; + goto queue_rtpg; } } @@ -950,6 +951,9 @@ static void alua_rtpg_work(struct work_struct *work) pg->rtpg_sdev = NULL; spin_unlock_irqrestore(&pg->lock, flags); + if (prev_sdev) + scsi_device_put(prev_sdev); + list_for_each_entry_safe(qdata, tmp, &qdata_list, entry) { list_del(&qdata->entry); if (qdata->callback_fn) @@ -961,6 +965,12 @@ static void alua_rtpg_work(struct work_struct *work) spin_unlock_irqrestore(&pg->lock, flags); scsi_device_put(sdev); kref_put(&pg->kref, release_port_group); + return; + +queue_rtpg: + if (prev_sdev) + scsi_device_put(prev_sdev); + queue_delayed_work(kaluad_wq, &pg->rtpg_work, pg->interval * HZ); } /** -- cgit v1.2.3 From 2e5a6c3baccd31476ed00c3fbc413b48ddd87993 Mon Sep 17 00:00:00 2001 From: Bart Van Assche Date: Mon, 31 Oct 2022 15:47:27 -0700 Subject: scsi: bfa: Convert bfad_reset_sdev_bflags() from a macro into a function Before modifying bfad_reset_sdev_bflags(), convert it from a macro into a function. Cc: Anil Gurumurthy Cc: Sudarsana Kalluru Signed-off-by: Bart Van Assche Link: https://lore.kernel.org/r/20221031224728.2607760-4-bvanassche@acm.org Signed-off-by: Martin K. Petersen --- drivers/scsi/bfa/bfad_bsg.c | 27 +++++++++++++++++++++++++++ drivers/scsi/bfa/bfad_im.h | 26 -------------------------- 2 files changed, 27 insertions(+), 26 deletions(-) diff --git a/drivers/scsi/bfa/bfad_bsg.c b/drivers/scsi/bfa/bfad_bsg.c index be8dfbe13e90..73754032e25c 100644 --- a/drivers/scsi/bfa/bfad_bsg.c +++ b/drivers/scsi/bfa/bfad_bsg.c @@ -2540,6 +2540,33 @@ out: return 0; } +/* + * Set the SCSI device sdev_bflags - sdev_bflags are used by the + * SCSI mid-layer to choose LUN Scanning mode REPORT_LUNS vs. Sequential Scan + * + * Internally iterates over all the ITNIM's part of the im_port & sets the + * sdev_bflags for the scsi_device associated with LUN #0. + */ +static void bfad_reset_sdev_bflags(struct bfad_im_port_s *im_port, + int lunmask_cfg) +{ + const u32 scan_flags = BLIST_NOREPORTLUN | BLIST_SPARSELUN; + struct bfad_itnim_s *itnim; + struct scsi_device *sdev; + + list_for_each_entry(itnim, &im_port->itnim_mapped_list, list_entry) { + sdev = scsi_device_lookup(im_port->shost, itnim->channel, + itnim->scsi_tgt_id, 0); + if (sdev) { + if (lunmask_cfg == BFA_TRUE) + sdev->sdev_bflags |= scan_flags; + else + sdev->sdev_bflags &= ~scan_flags; + scsi_device_put(sdev); + } + } +} + /* Function to reset the LUN SCAN mode */ static void bfad_iocmd_lunmask_reset_lunscan_mode(struct bfad_s *bfad, int lunmask_cfg) diff --git a/drivers/scsi/bfa/bfad_im.h b/drivers/scsi/bfa/bfad_im.h index c03b225ea1ba..4353feedf76a 100644 --- a/drivers/scsi/bfa/bfad_im.h +++ b/drivers/scsi/bfa/bfad_im.h @@ -198,30 +198,4 @@ irqreturn_t bfad_intx(int irq, void *dev_id); int bfad_im_bsg_request(struct bsg_job *job); int bfad_im_bsg_timeout(struct bsg_job *job); -/* - * Macro to set the SCSI device sdev_bflags - sdev_bflags are used by the - * SCSI mid-layer to choose LUN Scanning mode REPORT_LUNS vs. Sequential Scan - * - * Internally iterate's over all the ITNIM's part of the im_port & set's the - * sdev_bflags for the scsi_device associated with LUN #0. - */ -#define bfad_reset_sdev_bflags(__im_port, __lunmask_cfg) do { \ - struct scsi_device *__sdev = NULL; \ - struct bfad_itnim_s *__itnim = NULL; \ - u32 scan_flags = BLIST_NOREPORTLUN | BLIST_SPARSELUN; \ - list_for_each_entry(__itnim, &((__im_port)->itnim_mapped_list), \ - list_entry) { \ - __sdev = scsi_device_lookup((__im_port)->shost, \ - __itnim->channel, \ - __itnim->scsi_tgt_id, 0); \ - if (__sdev) { \ - if ((__lunmask_cfg) == BFA_TRUE) \ - __sdev->sdev_bflags |= scan_flags; \ - else \ - __sdev->sdev_bflags &= ~scan_flags; \ - scsi_device_put(__sdev); \ - } \ - } \ -} while (0) - #endif -- cgit v1.2.3 From 2e79cf37b15b1936f8630d9c5805d2c76bde213b Mon Sep 17 00:00:00 2001 From: Bart Van Assche Date: Mon, 31 Oct 2022 15:47:28 -0700 Subject: scsi: bfa: Rework bfad_reset_sdev_bflags() Since commit f93ed747e2c7 ("scsi: core: Release SCSI devices synchronously") it is no longer allowed to call scsi_device_put() from atomic context. Rework bfad_reset_sdev_bflags() such that scsi_device_put() is no longer called. This fixes the following smatch warning: drivers/scsi/bfa/bfad_bsg.c:2551 bfad_iocmd_lunmask_reset_lunscan_mode() warn: sleeping in atomic context bfad_iocmd_lunmask() <- disables preempt -> bfad_iocmd_lunmask_reset_lunscan_mode() -> scsi_device_put() Cc: Anil Gurumurthy Cc: Sudarsana Kalluru Cc: Dan Carpenter Reported-by: Dan Carpenter Signed-off-by: Bart Van Assche Link: https://lore.kernel.org/r/20221031224728.2607760-5-bvanassche@acm.org Signed-off-by: Martin K. Petersen --- drivers/scsi/bfa/bfad_bsg.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/drivers/scsi/bfa/bfad_bsg.c b/drivers/scsi/bfa/bfad_bsg.c index 73754032e25c..79d4f7ee5bcb 100644 --- a/drivers/scsi/bfa/bfad_bsg.c +++ b/drivers/scsi/bfa/bfad_bsg.c @@ -2553,18 +2553,20 @@ static void bfad_reset_sdev_bflags(struct bfad_im_port_s *im_port, const u32 scan_flags = BLIST_NOREPORTLUN | BLIST_SPARSELUN; struct bfad_itnim_s *itnim; struct scsi_device *sdev; + unsigned long flags; + spin_lock_irqsave(im_port->shost->host_lock, flags); list_for_each_entry(itnim, &im_port->itnim_mapped_list, list_entry) { - sdev = scsi_device_lookup(im_port->shost, itnim->channel, - itnim->scsi_tgt_id, 0); + sdev = __scsi_device_lookup(im_port->shost, itnim->channel, + itnim->scsi_tgt_id, 0); if (sdev) { if (lunmask_cfg == BFA_TRUE) sdev->sdev_bflags |= scan_flags; else sdev->sdev_bflags &= ~scan_flags; - scsi_device_put(sdev); } } + spin_unlock_irqrestore(im_port->shost->host_lock, flags); } /* Function to reset the LUN SCAN mode */ -- cgit v1.2.3 From 4fb2169d66b837a2986f569f5d5b81f79e6e4a4c Mon Sep 17 00:00:00 2001 From: Bart Van Assche Date: Mon, 31 Oct 2022 15:48:18 -0700 Subject: scsi: qla2xxx: Fix set-but-not-used variable warnings MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Fix the following two compiler warnings: drivers/scsi/qla2xxx/qla_init.c: In function ‘qla24xx_async_abort_cmd’: drivers/scsi/qla2xxx/qla_init.c:171:17: warning: variable ‘bail’ set but not used [-Wunused-but-set-variable] 171 | uint8_t bail; | ^~~~ drivers/scsi/qla2xxx/qla_init.c: In function ‘qla2x00_async_tm_cmd’: drivers/scsi/qla2xxx/qla_init.c:2023:17: warning: variable ‘bail’ set but not used [-Wunused-but-set-variable] 2023 | uint8_t bail; | ^~~~ Cc: Arun Easi Cc: Giridhar Malavali Fixes: feafb7b1714c ("[SCSI] qla2xxx: Fix vport delete issues") Signed-off-by: Bart Van Assche Link: https://lore.kernel.org/r/20221031224818.2607882-1-bvanassche@acm.org Signed-off-by: Martin K. Petersen --- drivers/scsi/qla2xxx/qla_def.h | 22 +++++++++++----------- drivers/scsi/qla2xxx/qla_init.c | 6 ++---- drivers/scsi/qla2xxx/qla_inline.h | 4 +--- drivers/scsi/qla2xxx/qla_os.c | 4 +--- 4 files changed, 15 insertions(+), 21 deletions(-) diff --git a/drivers/scsi/qla2xxx/qla_def.h b/drivers/scsi/qla2xxx/qla_def.h index 802eec6407d9..a26a373be9da 100644 --- a/drivers/scsi/qla2xxx/qla_def.h +++ b/drivers/scsi/qla2xxx/qla_def.h @@ -5136,17 +5136,17 @@ struct secure_flash_update_block_pk { (test_bit(ISP_ABORT_NEEDED, &ha->dpc_flags) || \ test_bit(LOOP_RESYNC_NEEDED, &ha->dpc_flags)) -#define QLA_VHA_MARK_BUSY(__vha, __bail) do { \ - atomic_inc(&__vha->vref_count); \ - mb(); \ - if (__vha->flags.delete_progress) { \ - atomic_dec(&__vha->vref_count); \ - wake_up(&__vha->vref_waitq); \ - __bail = 1; \ - } else { \ - __bail = 0; \ - } \ -} while (0) +static inline bool qla_vha_mark_busy(scsi_qla_host_t *vha) +{ + atomic_inc(&vha->vref_count); + mb(); + if (vha->flags.delete_progress) { + atomic_dec(&vha->vref_count); + wake_up(&vha->vref_waitq); + return true; + } + return false; +} #define QLA_VHA_MARK_NOT_BUSY(__vha) do { \ atomic_dec(&__vha->vref_count); \ diff --git a/drivers/scsi/qla2xxx/qla_init.c b/drivers/scsi/qla2xxx/qla_init.c index e12db95de688..631993504a76 100644 --- a/drivers/scsi/qla2xxx/qla_init.c +++ b/drivers/scsi/qla2xxx/qla_init.c @@ -168,7 +168,6 @@ int qla24xx_async_abort_cmd(srb_t *cmd_sp, bool wait) struct srb_iocb *abt_iocb; srb_t *sp; int rval = QLA_FUNCTION_FAILED; - uint8_t bail; /* ref: INIT for ABTS command */ sp = qla2xxx_get_qpair_sp(cmd_sp->vha, cmd_sp->qpair, cmd_sp->fcport, @@ -176,7 +175,7 @@ int qla24xx_async_abort_cmd(srb_t *cmd_sp, bool wait) if (!sp) return QLA_MEMORY_ALLOC_FAILED; - QLA_VHA_MARK_BUSY(vha, bail); + qla_vha_mark_busy(vha); abt_iocb = &sp->u.iocb_cmd; sp->type = SRB_ABT_CMD; sp->name = "abort"; @@ -2020,14 +2019,13 @@ qla2x00_async_tm_cmd(fc_port_t *fcport, uint32_t flags, uint32_t lun, struct srb_iocb *tm_iocb; srb_t *sp; int rval = QLA_FUNCTION_FAILED; - uint8_t bail; /* ref: INIT */ sp = qla2x00_get_sp(vha, fcport, GFP_KERNEL); if (!sp) goto done; - QLA_VHA_MARK_BUSY(vha, bail); + qla_vha_mark_busy(vha); sp->type = SRB_TM_CMD; sp->name = "tmf"; qla2x00_init_async_sp(sp, qla2x00_get_async_timeout(vha), diff --git a/drivers/scsi/qla2xxx/qla_inline.h b/drivers/scsi/qla2xxx/qla_inline.h index db17f7f410cd..5185dc5daf80 100644 --- a/drivers/scsi/qla2xxx/qla_inline.h +++ b/drivers/scsi/qla2xxx/qla_inline.h @@ -225,11 +225,9 @@ static inline srb_t * qla2x00_get_sp(scsi_qla_host_t *vha, fc_port_t *fcport, gfp_t flag) { srb_t *sp = NULL; - uint8_t bail; struct qla_qpair *qpair; - QLA_VHA_MARK_BUSY(vha, bail); - if (unlikely(bail)) + if (unlikely(qla_vha_mark_busy(vha))) return NULL; qpair = vha->hw->base_qpair; diff --git a/drivers/scsi/qla2xxx/qla_os.c b/drivers/scsi/qla2xxx/qla_os.c index 2c85f3cce726..96ba1398f20c 100644 --- a/drivers/scsi/qla2xxx/qla_os.c +++ b/drivers/scsi/qla2xxx/qla_os.c @@ -5069,13 +5069,11 @@ struct qla_work_evt * qla2x00_alloc_work(struct scsi_qla_host *vha, enum qla_work_type type) { struct qla_work_evt *e; - uint8_t bail; if (test_bit(UNLOADING, &vha->dpc_flags)) return NULL; - QLA_VHA_MARK_BUSY(vha, bail); - if (bail) + if (qla_vha_mark_busy(vha)) return NULL; e = kzalloc(sizeof(struct qla_work_evt), GFP_ATOMIC); -- cgit v1.2.3 From e137b81d30e7ef8ec27a77c3b2cbbad52845872a Mon Sep 17 00:00:00 2001 From: Colin Ian King Date: Tue, 1 Nov 2022 10:47:33 +0000 Subject: scsi: qla2xxx: Remove unused variable 'found_devs' Variable 'found_devs' is just being incremented and it's never used anywhere else. Remove it. Signed-off-by: Colin Ian King Link: https://lore.kernel.org/r/20221101104733.30363-1-colin.i.king@gmail.com Signed-off-by: Martin K. Petersen --- drivers/scsi/qla2xxx/qla_init.c | 4 ---- 1 file changed, 4 deletions(-) diff --git a/drivers/scsi/qla2xxx/qla_init.c b/drivers/scsi/qla2xxx/qla_init.c index 631993504a76..ce4c5d728407 100644 --- a/drivers/scsi/qla2xxx/qla_init.c +++ b/drivers/scsi/qla2xxx/qla_init.c @@ -5544,7 +5544,6 @@ static int qla2x00_configure_local_loop(scsi_qla_host_t *vha) { int rval, rval2; - int found_devs; int found; fc_port_t *fcport, *new_fcport; uint16_t index; @@ -5559,7 +5558,6 @@ qla2x00_configure_local_loop(scsi_qla_host_t *vha) if (N2N_TOPO(ha)) return qla2x00_configure_n2n_loop(vha); - found_devs = 0; new_fcport = NULL; entries = MAX_FIBRE_DEVICES_LOOP; @@ -5718,8 +5716,6 @@ qla2x00_configure_local_loop(scsi_qla_host_t *vha) /* Base iIDMA settings on HBA port speed. */ fcport->fp_speed = ha->link_data_rate; - - found_devs++; } list_for_each_entry(fcport, &vha->vp_fcports, list) { -- cgit v1.2.3 From 0aa46eba29553035d6af8384f19dfee2258d2a46 Mon Sep 17 00:00:00 2001 From: Colin Ian King Date: Tue, 1 Nov 2022 12:32:35 +0000 Subject: scsi: csiostor: Remove unused variable 'n' Variable 'n' is just being incremented and it's never used anywhere else. Remove it. Signed-off-by: Colin Ian King Link: https://lore.kernel.org/r/20221101123235.52152-1-colin.i.king@gmail.com Signed-off-by: Martin K. Petersen --- drivers/scsi/csiostor/csio_wr.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/drivers/scsi/csiostor/csio_wr.c b/drivers/scsi/csiostor/csio_wr.c index fe0355c964bc..a516df019c22 100644 --- a/drivers/scsi/csiostor/csio_wr.c +++ b/drivers/scsi/csiostor/csio_wr.c @@ -1051,7 +1051,6 @@ csio_wr_process_fl(struct csio_hw *hw, struct csio_q *q, struct csio_fl_dma_buf flb; struct csio_dma_buf *buf, *fbuf; uint32_t bufsz, len, lastlen = 0; - int n; struct csio_q *flq = hw->wrm.q_arr[q->un.iq.flq_idx]; CSIO_DB_ASSERT(flq != NULL); @@ -1071,7 +1070,7 @@ csio_wr_process_fl(struct csio_hw *hw, struct csio_q *q, flb.totlen = len; /* Consume all freelist buffers used for len bytes */ - for (n = 0, fbuf = flb.flbufs; ; n++, fbuf++) { + for (fbuf = flb.flbufs; ; fbuf++) { buf = &flq->un.fl.bufs[flq->cidx]; bufsz = csio_wr_fl_bufsz(sge, buf); -- cgit v1.2.3 From bc81131813aaf6fe764d1cc6b942a35a8c0c5c36 Mon Sep 17 00:00:00 2001 From: Colin Ian King Date: Tue, 1 Nov 2022 10:53:26 +0000 Subject: scsi: target: core: Remove unused variable 'unit_serial_len' Variable 'unit_serial_len' is just being assigned and it's never used anywhere else. Remove it. Signed-off-by: Colin Ian King Link: https://lore.kernel.org/r/20221101105326.31037-1-colin.i.king@gmail.com Signed-off-by: Martin K. Petersen --- drivers/target/target_core_spc.c | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/drivers/target/target_core_spc.c b/drivers/target/target_core_spc.c index ffe02e195733..621a460ba234 100644 --- a/drivers/target/target_core_spc.c +++ b/drivers/target/target_core_spc.c @@ -227,7 +227,7 @@ spc_emulate_evpd_83(struct se_cmd *cmd, unsigned char *buf) struct t10_alua_tg_pt_gp *tg_pt_gp; unsigned char *prod = &dev->t10_wwn.model[0]; u32 prod_len; - u32 unit_serial_len, off = 0; + u32 off = 0; u16 len = 0, id_len; off = 4; @@ -272,13 +272,9 @@ check_t10_vend_desc: prod_len += strlen(prod); prod_len++; /* For : */ - if (dev->dev_flags & DF_EMULATED_VPD_UNIT_SERIAL) { - unit_serial_len = strlen(&dev->t10_wwn.unit_serial[0]); - unit_serial_len++; /* For NULL Terminator */ - + if (dev->dev_flags & DF_EMULATED_VPD_UNIT_SERIAL) id_len += sprintf(&buf[off+12], "%s:%s", prod, &dev->t10_wwn.unit_serial[0]); - } buf[off] = 0x2; /* ASCII */ buf[off+1] = 0x1; /* T10 Vendor ID */ buf[off+2] = 0x0; -- cgit v1.2.3 From e56ca6bcd2136207868516f5a304fbb82cc0cb82 Mon Sep 17 00:00:00 2001 From: Christophe JAILLET Date: Tue, 1 Nov 2022 22:13:52 +0100 Subject: scsi: target: Use kstrtobool() instead of strtobool() strtobool() is the same as kstrtobool(). However, the latter is more used within the kernel. In order to remove strtobool() and slightly simplify kstrtox.h, switch to the other function name. While at it, include the corresponding header file () Signed-off-by: Christophe JAILLET Link: https://lore.kernel.org/r/fcddc0a53b4fc6e3c2e93592d3f61c5c63121855.1667336095.git.christophe.jaillet@wanadoo.fr Reviewed-by: Chaitanya Kulkarni Signed-off-by: Martin K. Petersen --- drivers/target/target_core_configfs.c | 29 ++++++++++++++-------------- drivers/target/target_core_fabric_configfs.c | 3 ++- 2 files changed, 17 insertions(+), 15 deletions(-) diff --git a/drivers/target/target_core_configfs.c b/drivers/target/target_core_configfs.c index 533524299ed6..b8a5c8d6cfde 100644 --- a/drivers/target/target_core_configfs.c +++ b/drivers/target/target_core_configfs.c @@ -12,6 +12,7 @@ * ****************************************************************************/ +#include #include #include #include @@ -578,7 +579,7 @@ static ssize_t _name##_store(struct config_item *item, const char *page, \ bool flag; \ int ret; \ \ - ret = strtobool(page, &flag); \ + ret = kstrtobool(page, &flag); \ if (ret < 0) \ return ret; \ da->_name = flag; \ @@ -638,7 +639,7 @@ static ssize_t emulate_model_alias_store(struct config_item *item, return -EINVAL; } - ret = strtobool(page, &flag); + ret = kstrtobool(page, &flag); if (ret < 0) return ret; @@ -660,7 +661,7 @@ static ssize_t emulate_write_cache_store(struct config_item *item, bool flag; int ret; - ret = strtobool(page, &flag); + ret = kstrtobool(page, &flag); if (ret < 0) return ret; @@ -712,7 +713,7 @@ static ssize_t emulate_tas_store(struct config_item *item, bool flag; int ret; - ret = strtobool(page, &flag); + ret = kstrtobool(page, &flag); if (ret < 0) return ret; @@ -737,7 +738,7 @@ static ssize_t emulate_tpu_store(struct config_item *item, bool flag; int ret; - ret = strtobool(page, &flag); + ret = kstrtobool(page, &flag); if (ret < 0) return ret; @@ -767,7 +768,7 @@ static ssize_t emulate_tpws_store(struct config_item *item, bool flag; int ret; - ret = strtobool(page, &flag); + ret = kstrtobool(page, &flag); if (ret < 0) return ret; @@ -866,7 +867,7 @@ static ssize_t pi_prot_format_store(struct config_item *item, bool flag; int ret; - ret = strtobool(page, &flag); + ret = kstrtobool(page, &flag); if (ret < 0) return ret; @@ -903,7 +904,7 @@ static ssize_t pi_prot_verify_store(struct config_item *item, bool flag; int ret; - ret = strtobool(page, &flag); + ret = kstrtobool(page, &flag); if (ret < 0) return ret; @@ -932,7 +933,7 @@ static ssize_t force_pr_aptpl_store(struct config_item *item, bool flag; int ret; - ret = strtobool(page, &flag); + ret = kstrtobool(page, &flag); if (ret < 0) return ret; if (da->da_dev->export_count) { @@ -954,7 +955,7 @@ static ssize_t emulate_rest_reord_store(struct config_item *item, bool flag; int ret; - ret = strtobool(page, &flag); + ret = kstrtobool(page, &flag); if (ret < 0) return ret; @@ -977,7 +978,7 @@ static ssize_t unmap_zeroes_data_store(struct config_item *item, bool flag; int ret; - ret = strtobool(page, &flag); + ret = kstrtobool(page, &flag); if (ret < 0) return ret; @@ -1126,7 +1127,7 @@ static ssize_t alua_support_store(struct config_item *item, bool flag, oldflag; int ret; - ret = strtobool(page, &flag); + ret = kstrtobool(page, &flag); if (ret < 0) return ret; @@ -1165,7 +1166,7 @@ static ssize_t pgr_support_store(struct config_item *item, bool flag, oldflag; int ret; - ret = strtobool(page, &flag); + ret = kstrtobool(page, &flag); if (ret < 0) return ret; @@ -1194,7 +1195,7 @@ static ssize_t emulate_rsoc_store(struct config_item *item, bool flag; int ret; - ret = strtobool(page, &flag); + ret = kstrtobool(page, &flag); if (ret < 0) return ret; diff --git a/drivers/target/target_core_fabric_configfs.c b/drivers/target/target_core_fabric_configfs.c index 95a88f6224cd..67b18a67317a 100644 --- a/drivers/target/target_core_fabric_configfs.c +++ b/drivers/target/target_core_fabric_configfs.c @@ -11,6 +11,7 @@ * ****************************************************************************/ +#include #include #include #include @@ -829,7 +830,7 @@ static ssize_t target_fabric_tpg_base_enable_store(struct config_item *item, int ret; bool op; - ret = strtobool(page, &op); + ret = kstrtobool(page, &op); if (ret) return ret; -- cgit v1.2.3 From 729c287e9f7481d630b69c73960e2ac990cd04fc Mon Sep 17 00:00:00 2001 From: Colin Ian King Date: Tue, 8 Nov 2022 10:36:20 -0800 Subject: scsi: lpfc: Remove redundant pointer 'lp' Pointer lp is being initialized and incremented but the result is never read. The pointer is redundant and can be removed. Once lp is removed, pcmd is not longer used. So remove pcmd as well Signed-off-by: Colin Ian King Signed-off-by: James Smart Link: https://lore.kernel.org/r/20221108183620.93978-1-jsmart2021@gmail.com Signed-off-by: Martin K. Petersen --- drivers/scsi/lpfc/lpfc_els.c | 5 ----- 1 file changed, 5 deletions(-) diff --git a/drivers/scsi/lpfc/lpfc_els.c b/drivers/scsi/lpfc/lpfc_els.c index 2b03210264bb..9326340d4226 100644 --- a/drivers/scsi/lpfc/lpfc_els.c +++ b/drivers/scsi/lpfc/lpfc_els.c @@ -9172,15 +9172,10 @@ static int lpfc_els_rcv_farpr(struct lpfc_vport *vport, struct lpfc_iocbq *cmdiocb, struct lpfc_nodelist *ndlp) { - struct lpfc_dmabuf *pcmd; - uint32_t *lp; uint32_t did; did = get_job_els_rsp64_did(vport->phba, cmdiocb); - pcmd = cmdiocb->cmd_dmabuf; - lp = (uint32_t *)pcmd->virt; - lp++; /* FARP-RSP received from DID */ lpfc_printf_vlog(vport, KERN_INFO, LOG_ELS, "0600 FARP-RSP received from DID x%x\n", did); -- cgit v1.2.3 From b27ac2faa2fc0b2677cf1cbd270af734a1f5fd95 Mon Sep 17 00:00:00 2001 From: Don Brace Date: Tue, 8 Nov 2022 13:21:38 -0600 Subject: scsi: smartpqi: Convert to host_tagset Add support for host_tagset. Also move the reserved command slots to the end of the pool to eliminate an addition operation for every SCSI request. This patch was originally authored by Hannes Reinecke here: Link: https://lore.kernel.org/linux-block/20191126131009.71726-8-hare@suse.de/ But we NAKed this patch because we wanted to fully test multipath failover operations. Suggested-by: Hannes Reinecke Reviewed-by: Scott Benesh Reviewed-by: Scott Teel Reviewed-by: Mahesh Rajashekhara Reviewed-by: Mike McGowen Reviewed-by: Kevin Barnett Signed-off-by: Don Brace Link: https://lore.kernel.org/r/166793529811.322537.3294617845448383948.stgit@brunhilda Signed-off-by: Martin K. Petersen --- drivers/scsi/smartpqi/smartpqi.h | 3 -- drivers/scsi/smartpqi/smartpqi_init.c | 68 ++++++++++++++++++++++------------- 2 files changed, 43 insertions(+), 28 deletions(-) diff --git a/drivers/scsi/smartpqi/smartpqi.h b/drivers/scsi/smartpqi/smartpqi.h index e550b12e525a..8cdf4d2476dd 100644 --- a/drivers/scsi/smartpqi/smartpqi.h +++ b/drivers/scsi/smartpqi/smartpqi.h @@ -1307,7 +1307,6 @@ struct pqi_ctrl_info { dma_addr_t error_buffer_dma_handle; size_t sg_chain_buffer_length; unsigned int num_queue_groups; - u16 max_hw_queue_index; u16 num_elements_per_iq; u16 num_elements_per_oq; u16 max_inbound_iu_length_per_firmware; @@ -1369,8 +1368,6 @@ struct pqi_ctrl_info { u64 sas_address; struct pqi_io_request *io_request_pool; - u16 next_io_request_slot; - struct pqi_event events[PQI_NUM_SUPPORTED_EVENTS]; struct work_struct event_work; diff --git a/drivers/scsi/smartpqi/smartpqi_init.c b/drivers/scsi/smartpqi/smartpqi_init.c index b971fbe3b3a1..651dca535b3b 100644 --- a/drivers/scsi/smartpqi/smartpqi_init.c +++ b/drivers/scsi/smartpqi/smartpqi_init.c @@ -678,23 +678,36 @@ static inline void pqi_reinit_io_request(struct pqi_io_request *io_request) io_request->raid_bypass = false; } -static struct pqi_io_request *pqi_alloc_io_request( - struct pqi_ctrl_info *ctrl_info) +static inline struct pqi_io_request *pqi_alloc_io_request(struct pqi_ctrl_info *ctrl_info, struct scsi_cmnd *scmd) { struct pqi_io_request *io_request; - u16 i = ctrl_info->next_io_request_slot; /* benignly racy */ + u16 i; - while (1) { + if (scmd) { /* SML I/O request */ + u32 blk_tag = blk_mq_unique_tag(scsi_cmd_to_rq(scmd)); + + i = blk_mq_unique_tag_to_tag(blk_tag); io_request = &ctrl_info->io_request_pool[i]; - if (atomic_inc_return(&io_request->refcount) == 1) - break; - atomic_dec(&io_request->refcount); - i = (i + 1) % ctrl_info->max_io_slots; + if (atomic_inc_return(&io_request->refcount) > 1) { + atomic_dec(&io_request->refcount); + return NULL; + } + } else { /* IOCTL or driver internal request */ + /* + * benignly racy - may have to wait for an open slot. + * command slot range is scsi_ml_can_queue - + * [scsi_ml_can_queue + (PQI_RESERVED_IO_SLOTS - 1)] + */ + i = 0; + while (1) { + io_request = &ctrl_info->io_request_pool[ctrl_info->scsi_ml_can_queue + i]; + if (atomic_inc_return(&io_request->refcount) == 1) + break; + atomic_dec(&io_request->refcount); + i = (i + 1) % PQI_RESERVED_IO_SLOTS; + } } - /* benignly racy */ - ctrl_info->next_io_request_slot = (i + 1) % ctrl_info->max_io_slots; - pqi_reinit_io_request(io_request); return io_request; @@ -4586,7 +4599,7 @@ static int pqi_submit_raid_request_synchronous(struct pqi_ctrl_info *ctrl_info, goto out; } - io_request = pqi_alloc_io_request(ctrl_info); + io_request = pqi_alloc_io_request(ctrl_info, NULL); put_unaligned_le16(io_request->index, &(((struct pqi_raid_path_request *)request)->request_id)); @@ -5233,7 +5246,6 @@ static void pqi_calculate_queue_resources(struct pqi_ctrl_info *ctrl_info) } ctrl_info->num_queue_groups = num_queue_groups; - ctrl_info->max_hw_queue_index = num_queue_groups - 1; /* * Make sure that the max. inbound IU length is an even multiple @@ -5567,7 +5579,9 @@ static inline int pqi_raid_submit_scsi_cmd(struct pqi_ctrl_info *ctrl_info, { struct pqi_io_request *io_request; - io_request = pqi_alloc_io_request(ctrl_info); + io_request = pqi_alloc_io_request(ctrl_info, scmd); + if (!io_request) + return SCSI_MLQUEUE_HOST_BUSY; return pqi_raid_submit_scsi_cmd_with_io_request(ctrl_info, io_request, device, scmd, queue_group); @@ -5671,7 +5685,9 @@ static int pqi_aio_submit_io(struct pqi_ctrl_info *ctrl_info, struct pqi_scsi_dev *device; device = scmd->device->hostdata; - io_request = pqi_alloc_io_request(ctrl_info); + io_request = pqi_alloc_io_request(ctrl_info, scmd); + if (!io_request) + return SCSI_MLQUEUE_HOST_BUSY; io_request->io_complete_callback = pqi_aio_io_complete; io_request->scmd = scmd; io_request->raid_bypass = raid_bypass; @@ -5743,7 +5759,10 @@ static int pqi_aio_submit_r1_write_io(struct pqi_ctrl_info *ctrl_info, struct pqi_io_request *io_request; struct pqi_aio_r1_path_request *r1_request; - io_request = pqi_alloc_io_request(ctrl_info); + io_request = pqi_alloc_io_request(ctrl_info, scmd); + if (!io_request) + return SCSI_MLQUEUE_HOST_BUSY; + io_request->io_complete_callback = pqi_aio_io_complete; io_request->scmd = scmd; io_request->raid_bypass = true; @@ -5801,7 +5820,9 @@ static int pqi_aio_submit_r56_write_io(struct pqi_ctrl_info *ctrl_info, struct pqi_io_request *io_request; struct pqi_aio_r56_path_request *r56_request; - io_request = pqi_alloc_io_request(ctrl_info); + io_request = pqi_alloc_io_request(ctrl_info, scmd); + if (!io_request) + return SCSI_MLQUEUE_HOST_BUSY; io_request->io_complete_callback = pqi_aio_io_complete; io_request->scmd = scmd; io_request->raid_bypass = true; @@ -5860,13 +5881,10 @@ static int pqi_aio_submit_r56_write_io(struct pqi_ctrl_info *ctrl_info, static inline u16 pqi_get_hw_queue(struct pqi_ctrl_info *ctrl_info, struct scsi_cmnd *scmd) { - u16 hw_queue; - - hw_queue = blk_mq_unique_tag_to_hwq(blk_mq_unique_tag(scsi_cmd_to_rq(scmd))); - if (hw_queue > ctrl_info->max_hw_queue_index) - hw_queue = 0; - - return hw_queue; + /* + * We are setting host_tagset = 1 during init. + */ + return blk_mq_unique_tag_to_hwq(blk_mq_unique_tag(scsi_cmd_to_rq(scmd))); } static inline bool pqi_is_bypass_eligible_request(struct scsi_cmnd *scmd) @@ -6268,7 +6286,7 @@ static int pqi_lun_reset(struct pqi_ctrl_info *ctrl_info, struct scsi_cmnd *scmd struct pqi_scsi_dev *device; device = scmd->device->hostdata; - io_request = pqi_alloc_io_request(ctrl_info); + io_request = pqi_alloc_io_request(ctrl_info, NULL); io_request->io_complete_callback = pqi_lun_reset_complete; io_request->context = &wait; -- cgit v1.2.3 From 0b93cf2a9097b1c3d75642ef878ba87f15f03043 Mon Sep 17 00:00:00 2001 From: Mike McGowen Date: Tue, 8 Nov 2022 13:21:43 -0600 Subject: scsi: smartpqi: Add new controller PCI IDs All PCI ID entries in Hex. Add PCI IDs for ByteDance controllers: VID / DID / SVID / SDID ---- ---- ---- ---- ByteHBA JGH43024-8 9005 / 028f / 1e93 / 1000 ByteHBA JGH43034-8 9005 / 028f / 1e93 / 1001 ByteHBA JGH44014-8 9005 / 028f / 1e93 / 1002 Add PCI IDs for new Inspur controllers: VID / DID / SVID / SDID ---- ---- ---- ---- INSPUR RT0800M7E 9005 / 028f / 1bd4 / 0086 INSPUR RT0800M7H 9005 / 028f / 1bd4 / 0087 INSPUR RT0804M7R 9005 / 028f / 1bd4 / 0088 INSPUR RT0808M7R 9005 / 028f / 1bd4 / 0089 Add PCI IDs for new FAB A controllers: VID / DID / SVID / SDID ---- ---- ---- ---- Adaptec SmartRAID 3254-16e /e 9005 / 028f / 9005 / 1475 Adaptec HBA 1200-16e 9005 / 028f / 9005 / 14c3 Adaptec HBA 1200-8e 9005 / 028f / 9005 / 14c4 Add H3C controller PCI IDs: VID / DID / SVID / SDID ---- ---- ---- ---- H3C H4508-Mf-8i 9005 / 028f / 193d / 110b Reviewed-by: Scott Benesh Reviewed-by: Scott Teel Signed-off-by: Mike McGowen Signed-off-by: Don Brace Link: https://lore.kernel.org/r/166793530327.322537.6056884426657539311.stgit@brunhilda Signed-off-by: Martin K. Petersen --- drivers/scsi/smartpqi/smartpqi_init.c | 44 +++++++++++++++++++++++++++++++++++ 1 file changed, 44 insertions(+) diff --git a/drivers/scsi/smartpqi/smartpqi_init.c b/drivers/scsi/smartpqi/smartpqi_init.c index 651dca535b3b..6cda12078130 100644 --- a/drivers/scsi/smartpqi/smartpqi_init.c +++ b/drivers/scsi/smartpqi/smartpqi_init.c @@ -9320,6 +9320,10 @@ static const struct pci_device_id pqi_pci_id_table[] = { PCI_DEVICE_SUB(PCI_VENDOR_ID_ADAPTEC2, 0x028f, 0x193d, 0x1109) }, + { + PCI_DEVICE_SUB(PCI_VENDOR_ID_ADAPTEC2, 0x028f, + 0x193d, 0x110b) + }, { PCI_DEVICE_SUB(PCI_VENDOR_ID_ADAPTEC2, 0x028f, 0x193d, 0x8460) @@ -9420,6 +9424,22 @@ static const struct pci_device_id pqi_pci_id_table[] = { PCI_DEVICE_SUB(PCI_VENDOR_ID_ADAPTEC2, 0x028f, 0x1bd4, 0x0072) }, + { + PCI_DEVICE_SUB(PCI_VENDOR_ID_ADAPTEC2, 0x028f, + 0x1bd4, 0x0086) + }, + { + PCI_DEVICE_SUB(PCI_VENDOR_ID_ADAPTEC2, 0x028f, + 0x1bd4, 0x0087) + }, + { + PCI_DEVICE_SUB(PCI_VENDOR_ID_ADAPTEC2, 0x028f, + 0x1bd4, 0x0088) + }, + { + PCI_DEVICE_SUB(PCI_VENDOR_ID_ADAPTEC2, 0x028f, + 0x1bd4, 0x0089) + }, { PCI_DEVICE_SUB(PCI_VENDOR_ID_ADAPTEC2, 0x028f, 0x19e5, 0xd227) @@ -9668,6 +9688,10 @@ static const struct pci_device_id pqi_pci_id_table[] = { PCI_DEVICE_SUB(PCI_VENDOR_ID_ADAPTEC2, 0x028f, PCI_VENDOR_ID_ADAPTEC2, 0x1474) }, + { + PCI_DEVICE_SUB(PCI_VENDOR_ID_ADAPTEC2, 0x028f, + PCI_VENDOR_ID_ADAPTEC2, 0x1475) + }, { PCI_DEVICE_SUB(PCI_VENDOR_ID_ADAPTEC2, 0x028f, PCI_VENDOR_ID_ADAPTEC2, 0x1480) @@ -9724,6 +9748,14 @@ static const struct pci_device_id pqi_pci_id_table[] = { PCI_DEVICE_SUB(PCI_VENDOR_ID_ADAPTEC2, 0x028f, PCI_VENDOR_ID_ADAPTEC2, 0x14c2) }, + { + PCI_DEVICE_SUB(PCI_VENDOR_ID_ADAPTEC2, 0x028f, + PCI_VENDOR_ID_ADAPTEC2, 0x14c3) + }, + { + PCI_DEVICE_SUB(PCI_VENDOR_ID_ADAPTEC2, 0x028f, + PCI_VENDOR_ID_ADAPTEC2, 0x14c4) + }, { PCI_DEVICE_SUB(PCI_VENDOR_ID_ADAPTEC2, 0x028f, PCI_VENDOR_ID_ADAPTEC2, 0x14d0) @@ -9960,6 +9992,18 @@ static const struct pci_device_id pqi_pci_id_table[] = { PCI_DEVICE_SUB(PCI_VENDOR_ID_ADAPTEC2, 0x028f, PCI_VENDOR_ID_LENOVO, 0x0623) }, + { + PCI_DEVICE_SUB(PCI_VENDOR_ID_ADAPTEC2, 0x028f, + 0x1e93, 0x1000) + }, + { + PCI_DEVICE_SUB(PCI_VENDOR_ID_ADAPTEC2, 0x028f, + 0x1e93, 0x1001) + }, + { + PCI_DEVICE_SUB(PCI_VENDOR_ID_ADAPTEC2, 0x028f, + 0x1e93, 0x1002) + }, { PCI_DEVICE_SUB(PCI_VENDOR_ID_ADAPTEC2, 0x028f, PCI_ANY_ID, PCI_ANY_ID) -- cgit v1.2.3 From 7c56850637ea820a89ce2f52fca66c5ae12d0f0a Mon Sep 17 00:00:00 2001 From: Kevin Barnett Date: Tue, 8 Nov 2022 13:21:48 -0600 Subject: scsi: smartpqi: Correct max LUN number Correct maximum LUN number for multi-actuator devices. When multi-actuator support was added to smartpqi, the maximum number of LUNs supported for multi-actuator devices was supposed to be changed from unlimited to 256, but the setting was inadvertently left at unlimited. Reviewed-by: Scott Benesh Reviewed-by: Scott Teel Signed-off-by: Kevin Barnett Signed-off-by: Don Brace Link: https://lore.kernel.org/r/166793530842.322537.816949081443241857.stgit@brunhilda Signed-off-by: Martin K. Petersen --- drivers/scsi/smartpqi/smartpqi_init.c | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/scsi/smartpqi/smartpqi_init.c b/drivers/scsi/smartpqi/smartpqi_init.c index 6cda12078130..33059355f9cd 100644 --- a/drivers/scsi/smartpqi/smartpqi_init.c +++ b/drivers/scsi/smartpqi/smartpqi_init.c @@ -7423,7 +7423,6 @@ static int pqi_register_scsi(struct pqi_ctrl_info *ctrl_info) shost->max_channel = PQI_MAX_BUS; shost->max_cmd_len = MAX_COMMAND_SIZE; shost->max_lun = PQI_MAX_LUNS_PER_DEVICE; - shost->max_lun = ~0; shost->max_id = ~0; shost->max_sectors = ctrl_info->max_sectors; shost->can_queue = ctrl_info->scsi_ml_can_queue; -- cgit v1.2.3 From cbe42ac15698a23b204a9b5c66eb0067b22cbd42 Mon Sep 17 00:00:00 2001 From: Kevin Barnett Date: Tue, 8 Nov 2022 13:21:53 -0600 Subject: scsi: smartpqi: Change sysfs raid_level attribute to N/A for controllers Change the sysfs raid_level attribute from "RAID-0" to N/A. Reviewed-by: Scott Benesh Reviewed-by: Scott Teel Reviewed-by: Mike McGowan Signed-off-by: Kevin Barnett Signed-off-by: Don Brace Link: https://lore.kernel.org/r/166793531357.322537.8639138137605612362.stgit@brunhilda Signed-off-by: Martin K. Petersen --- drivers/scsi/smartpqi/smartpqi_init.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/scsi/smartpqi/smartpqi_init.c b/drivers/scsi/smartpqi/smartpqi_init.c index 33059355f9cd..20fc6c8044ac 100644 --- a/drivers/scsi/smartpqi/smartpqi_init.c +++ b/drivers/scsi/smartpqi/smartpqi_init.c @@ -7255,7 +7255,7 @@ static ssize_t pqi_raid_level_show(struct device *dev, return -ENODEV; } - if (pqi_is_logical_device(device)) + if (pqi_is_logical_device(device) && device->devtype == TYPE_DISK) raid_level = pqi_raid_level_to_string(device->raid_level); else raid_level = "N/A"; -- cgit v1.2.3 From cc9befcbbb5ebce77726f938508700d913530035 Mon Sep 17 00:00:00 2001 From: Kumar Meiyappan Date: Tue, 8 Nov 2022 13:21:58 -0600 Subject: scsi: smartpqi: Correct device removal for multi-actuator devices Correct device count for multi-actuator drives which can cause kernel panics. Reviewed-by: Scott Benesh Reviewed-by: Scott Teel Reviewed-by: Mike Mcgowan Reviewed-by: Kevin Barnett Signed-off-by: Kumar Meiyappan Signed-off-by: Don Brace Link: https://lore.kernel.org/r/166793531872.322537.9003385780343419275.stgit@brunhilda Signed-off-by: Martin K. Petersen --- drivers/scsi/smartpqi/smartpqi.h | 2 +- drivers/scsi/smartpqi/smartpqi_init.c | 33 ++++++++++++++++++++++++--------- 2 files changed, 25 insertions(+), 10 deletions(-) diff --git a/drivers/scsi/smartpqi/smartpqi.h b/drivers/scsi/smartpqi/smartpqi.h index 8cdf4d2476dd..af27bb0f3133 100644 --- a/drivers/scsi/smartpqi/smartpqi.h +++ b/drivers/scsi/smartpqi/smartpqi.h @@ -1130,7 +1130,7 @@ struct pqi_scsi_dev { u8 phy_id; u8 ncq_prio_enable; u8 ncq_prio_support; - u8 multi_lun_device_lun_count; + u8 lun_count; bool raid_bypass_configured; /* RAID bypass configured */ bool raid_bypass_enabled; /* RAID bypass enabled */ u32 next_bypass_group[RAID_MAP_MAX_DATA_DISKS_PER_ROW]; diff --git a/drivers/scsi/smartpqi/smartpqi_init.c b/drivers/scsi/smartpqi/smartpqi_init.c index 20fc6c8044ac..e82f4de46ea7 100644 --- a/drivers/scsi/smartpqi/smartpqi_init.c +++ b/drivers/scsi/smartpqi/smartpqi_init.c @@ -1623,9 +1623,7 @@ static int pqi_get_physical_device_info(struct pqi_ctrl_info *ctrl_info, &id_phys->alternate_paths_phys_connector, sizeof(device->phys_connector)); device->bay = id_phys->phys_bay_in_box; - device->multi_lun_device_lun_count = id_phys->multi_lun_device_lun_count; - if (!device->multi_lun_device_lun_count) - device->multi_lun_device_lun_count = 1; + device->lun_count = id_phys->multi_lun_device_lun_count; if ((id_phys->even_more_flags & PQI_DEVICE_PHY_MAP_SUPPORTED) && id_phys->phy_count) device->phy_id = @@ -1759,7 +1757,7 @@ out: return offline; } -static int pqi_get_device_info(struct pqi_ctrl_info *ctrl_info, +static int pqi_get_device_info_phys_logical(struct pqi_ctrl_info *ctrl_info, struct pqi_scsi_dev *device, struct bmic_identify_physical_device *id_phys) { @@ -1776,6 +1774,20 @@ static int pqi_get_device_info(struct pqi_ctrl_info *ctrl_info, return rc; } +static int pqi_get_device_info(struct pqi_ctrl_info *ctrl_info, + struct pqi_scsi_dev *device, + struct bmic_identify_physical_device *id_phys) +{ + int rc; + + rc = pqi_get_device_info_phys_logical(ctrl_info, device, id_phys); + + if (rc == 0 && device->lun_count == 0) + device->lun_count = 1; + + return rc; +} + static void pqi_show_volume_status(struct pqi_ctrl_info *ctrl_info, struct pqi_scsi_dev *device) { @@ -1910,7 +1922,7 @@ static inline void pqi_remove_device(struct pqi_ctrl_info *ctrl_info, struct pqi int rc; int lun; - for (lun = 0; lun < device->multi_lun_device_lun_count; lun++) { + for (lun = 0; lun < device->lun_count; lun++) { rc = pqi_device_wait_for_pending_io(ctrl_info, device, lun, PQI_REMOVE_DEVICE_PENDING_IO_TIMEOUT_MSECS); if (rc) @@ -2089,6 +2101,7 @@ static void pqi_scsi_update_device(struct pqi_ctrl_info *ctrl_info, existing_device->sas_address = new_device->sas_address; existing_device->queue_depth = new_device->queue_depth; existing_device->device_offline = false; + existing_device->lun_count = new_device->lun_count; if (pqi_is_logical_device(existing_device)) { existing_device->is_external_raid_device = new_device->is_external_raid_device; @@ -2121,10 +2134,6 @@ static void pqi_scsi_update_device(struct pqi_ctrl_info *ctrl_info, existing_device->phy_connected_dev_type = new_device->phy_connected_dev_type; memcpy(existing_device->box, new_device->box, sizeof(existing_device->box)); memcpy(existing_device->phys_connector, new_device->phys_connector, sizeof(existing_device->phys_connector)); - - existing_device->multi_lun_device_lun_count = new_device->multi_lun_device_lun_count; - if (existing_device->multi_lun_device_lun_count == 0) - existing_device->multi_lun_device_lun_count = 1; } } @@ -6502,6 +6511,12 @@ static void pqi_slave_destroy(struct scsi_device *sdev) return; } + device->lun_count--; + if (device->lun_count > 0) { + mutex_unlock(&ctrl_info->scan_mutex); + return; + } + spin_lock_irqsave(&ctrl_info->scsi_device_list_lock, flags); list_del(&device->scsi_device_list_entry); spin_unlock_irqrestore(&ctrl_info->scsi_device_list_lock, flags); -- cgit v1.2.3 From 14063fb625c4541f48ff0dc7ae005b0d5a159c3f Mon Sep 17 00:00:00 2001 From: Gilbert Wu Date: Tue, 8 Nov 2022 13:22:03 -0600 Subject: scsi: smartpqi: Add controller cache flush during rmmod Add in a call to flush the controller cache during driver removal. Reviewed-by: Scott Benesh Reviewed-by: Mike Mcgowan Reviewed-by: Kevin Barnett Signed-off-by: Gilbert Wu Signed-off-by: Don Brace Link: https://lore.kernel.org/r/166793532388.322537.878022136408270892.stgit@brunhilda Signed-off-by: Martin K. Petersen --- drivers/scsi/smartpqi/smartpqi_init.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/drivers/scsi/smartpqi/smartpqi_init.c b/drivers/scsi/smartpqi/smartpqi_init.c index e82f4de46ea7..e9c924ac1bb2 100644 --- a/drivers/scsi/smartpqi/smartpqi_init.c +++ b/drivers/scsi/smartpqi/smartpqi_init.c @@ -9040,6 +9040,7 @@ static void pqi_pci_remove(struct pci_dev *pci_dev) { struct pqi_ctrl_info *ctrl_info; u16 vendor_id; + int rc; ctrl_info = pci_get_drvdata(pci_dev); if (!ctrl_info) @@ -9051,6 +9052,13 @@ static void pqi_pci_remove(struct pci_dev *pci_dev) else ctrl_info->ctrl_removal_state = PQI_CTRL_GRACEFUL_REMOVAL; + if (ctrl_info->ctrl_removal_state == PQI_CTRL_GRACEFUL_REMOVAL) { + rc = pqi_flush_cache(ctrl_info, RESTART); + if (rc) + dev_err(&pci_dev->dev, + "unable to flush controller cache during remove\n"); + } + pqi_remove_ctrl(ctrl_info); } -- cgit v1.2.3 From 921800a1deeaa832e4303e9335a31b4234c41ac1 Mon Sep 17 00:00:00 2001 From: Don Brace Date: Tue, 8 Nov 2022 13:22:09 -0600 Subject: scsi: smartpqi: Initialize feature section info Initialize features to 0 before processing. Reviewed-by: Scott Benesh Reviewed-by: Mike Mcgowan Reviewed-by: Kevin Barnett Signed-off-by: Don Brace Link: https://lore.kernel.org/r/166793532902.322537.2436075977808555348.stgit@brunhilda Signed-off-by: Martin K. Petersen --- drivers/scsi/smartpqi/smartpqi_init.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/scsi/smartpqi/smartpqi_init.c b/drivers/scsi/smartpqi/smartpqi_init.c index e9c924ac1bb2..fb4a33decde1 100644 --- a/drivers/scsi/smartpqi/smartpqi_init.c +++ b/drivers/scsi/smartpqi/smartpqi_init.c @@ -8004,7 +8004,7 @@ static int pqi_process_config_table(struct pqi_ctrl_info *ctrl_info) struct pqi_config_table *config_table; struct pqi_config_table_section_header *section; struct pqi_config_table_section_info section_info; - struct pqi_config_table_section_info feature_section_info; + struct pqi_config_table_section_info feature_section_info = {0}; table_length = ctrl_info->config_table_length; if (table_length == 0) -- cgit v1.2.3 From 2ae45329a956ff86ff8bec36463b6f49d2ca9bea Mon Sep 17 00:00:00 2001 From: Don Brace Date: Tue, 8 Nov 2022 13:22:14 -0600 Subject: scsi: smartpqi: Change version to 2.1.20-035 Reviewed-by: Scott Benesh Reviewed-by: Scott Teel Reviewed-by: Gerry Morong Reviewed-by: Kevin Barnett Signed-off-by: Don Brace Link: https://lore.kernel.org/r/166793533417.322537.3074216622272955440.stgit@brunhilda Signed-off-by: Martin K. Petersen --- drivers/scsi/smartpqi/smartpqi_init.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/scsi/smartpqi/smartpqi_init.c b/drivers/scsi/smartpqi/smartpqi_init.c index fb4a33decde1..d0446d4d4465 100644 --- a/drivers/scsi/smartpqi/smartpqi_init.c +++ b/drivers/scsi/smartpqi/smartpqi_init.c @@ -33,11 +33,11 @@ #define BUILD_TIMESTAMP #endif -#define DRIVER_VERSION "2.1.18-045" +#define DRIVER_VERSION "2.1.20-035" #define DRIVER_MAJOR 2 #define DRIVER_MINOR 1 -#define DRIVER_RELEASE 18 -#define DRIVER_REVISION 45 +#define DRIVER_RELEASE 20 +#define DRIVER_REVISION 35 #define DRIVER_NAME "Microchip SmartPQI Driver (v" \ DRIVER_VERSION BUILD_TIMESTAMP ")" -- cgit v1.2.3 From 216e179724c1d9f57a8ababf8bd7aaabef67f01b Mon Sep 17 00:00:00 2001 From: Harshit Mogalapalli Date: Fri, 11 Nov 2022 02:05:25 -0800 Subject: scsi: scsi_debug: Fix a warning in resp_write_scat() As 'lbdof_blen' is coming from user, if the size in kzalloc() is >= MAX_ORDER then we hit a warning. Call trace: sg_ioctl sg_ioctl_common scsi_ioctl sg_scsi_ioctl blk_execute_rq blk_mq_sched_insert_request blk_mq_run_hw_queue __blk_mq_delay_run_hw_queue __blk_mq_run_hw_queue blk_mq_sched_dispatch_requests __blk_mq_sched_dispatch_requests blk_mq_dispatch_rq_list scsi_queue_rq scsi_dispatch_cmd scsi_debug_queuecommand schedule_resp resp_write_scat If you try to allocate a memory larger than(>=) MAX_ORDER, then kmalloc() will definitely fail. It creates a stack trace and messes up dmesg. The user controls the size here so if they specify a too large size it will fail. Add __GFP_NOWARN in order to avoid too large allocation warning. This is detected by static analysis using smatch. Fixes: 481b5e5c7949 ("scsi: scsi_debug: add resp_write_scat function") Signed-off-by: Harshit Mogalapalli Link: https://lore.kernel.org/r/20221111100526.1790533-1-harshit.m.mogalapalli@oracle.com Acked-by: Douglas Gilbert Signed-off-by: Martin K. Petersen --- drivers/scsi/scsi_debug.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/scsi/scsi_debug.c b/drivers/scsi/scsi_debug.c index 697fc57bc711..273224d29ce9 100644 --- a/drivers/scsi/scsi_debug.c +++ b/drivers/scsi/scsi_debug.c @@ -3778,7 +3778,7 @@ static int resp_write_scat(struct scsi_cmnd *scp, mk_sense_buffer(scp, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB, 0); return illegal_condition_result; } - lrdp = kzalloc(lbdof_blen, GFP_ATOMIC); + lrdp = kzalloc(lbdof_blen, GFP_ATOMIC | __GFP_NOWARN); if (lrdp == NULL) return SCSI_MLQUEUE_HOST_BUSY; if (sdebug_verbose) -- cgit v1.2.3 From b29e91385ce2d3aae70906f80f517f9b93d97a7b Mon Sep 17 00:00:00 2001 From: Xiu Jianfeng Date: Fri, 11 Nov 2022 15:43:10 +0800 Subject: scsi: lpfc: Use memset_startat() helper Use memset_startat() helper to simplify the code, no functional changes in this patch. Signed-off-by: Xiu Jianfeng Link: https://lore.kernel.org/r/20221111074310.132125-1-xiujianfeng@huawei.com Reviewed-by: James Smart Signed-off-by: Martin K. Petersen --- drivers/scsi/lpfc/lpfc_sli.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/drivers/scsi/lpfc/lpfc_sli.c b/drivers/scsi/lpfc/lpfc_sli.c index d25afc9dde14..35c9404d5e49 100644 --- a/drivers/scsi/lpfc/lpfc_sli.c +++ b/drivers/scsi/lpfc/lpfc_sli.c @@ -1373,7 +1373,6 @@ static void __lpfc_sli_release_iocbq_s4(struct lpfc_hba *phba, struct lpfc_iocbq *iocbq) { struct lpfc_sglq *sglq; - size_t start_clean = offsetof(struct lpfc_iocbq, wqe); unsigned long iflag = 0; struct lpfc_sli_ring *pring; @@ -1430,7 +1429,7 @@ out: /* * Clean all volatile data fields, preserve iotag and node struct. */ - memset((char *)iocbq + start_clean, 0, sizeof(*iocbq) - start_clean); + memset_startat(iocbq, 0, wqe); iocbq->sli4_lxritag = NO_XRI; iocbq->sli4_xritag = NO_XRI; iocbq->cmd_flag &= ~(LPFC_IO_NVME | LPFC_IO_NVMET | LPFC_IO_CMF | @@ -1453,12 +1452,11 @@ out: static void __lpfc_sli_release_iocbq_s3(struct lpfc_hba *phba, struct lpfc_iocbq *iocbq) { - size_t start_clean = offsetof(struct lpfc_iocbq, iocb); /* * Clean all volatile data fields, preserve iotag and node struct. */ - memset((char*)iocbq + start_clean, 0, sizeof(*iocbq) - start_clean); + memset_startat(iocbq, 0, iocb); iocbq->sli4_xritag = NO_XRI; list_add_tail(&iocbq->list, &phba->lpfc_iocb_list); } -- cgit v1.2.3 From 0824050682aef5151ade16129b3a0498a07ca6c9 Mon Sep 17 00:00:00 2001 From: Colin Ian King Date: Fri, 11 Nov 2022 17:08:24 +0000 Subject: scsi: libfc: Remove redundant variable ev_qual Variable ev_qual is being assigned and modified but the end result is never used. The variable is redundant and can be removed. Signed-off-by: Colin Ian King Link: https://lore.kernel.org/r/20221111170824.558250-1-colin.i.king@gmail.com Signed-off-by: Martin K. Petersen --- drivers/scsi/libfc/fc_disc.c | 3 --- 1 file changed, 3 deletions(-) diff --git a/drivers/scsi/libfc/fc_disc.c b/drivers/scsi/libfc/fc_disc.c index 942fc60f7c21..0f32ded246d0 100644 --- a/drivers/scsi/libfc/fc_disc.c +++ b/drivers/scsi/libfc/fc_disc.c @@ -75,7 +75,6 @@ static void fc_disc_recv_rscn_req(struct fc_disc *disc, struct fc_frame *fp) struct fc_seq_els_data rjt_data; unsigned int len; int redisc = 0; - enum fc_els_rscn_ev_qual ev_qual; enum fc_els_rscn_addr_fmt fmt; LIST_HEAD(disc_ports); struct fc_disc_port *dp, *next; @@ -107,8 +106,6 @@ static void fc_disc_recv_rscn_req(struct fc_disc *disc, struct fc_frame *fp) goto reject; for (pp = (void *)(rp + 1); len > 0; len -= sizeof(*pp), pp++) { - ev_qual = pp->rscn_page_flags >> ELS_RSCN_EV_QUAL_BIT; - ev_qual &= ELS_RSCN_EV_QUAL_MASK; fmt = pp->rscn_page_flags >> ELS_RSCN_ADDR_FMT_BIT; fmt &= ELS_RSCN_ADDR_FMT_MASK; /* -- cgit v1.2.3 From c4c5fa35563a47957fa4f9c299ca1c6aadc27d50 Mon Sep 17 00:00:00 2001 From: "Gustavo A. R. Silva" Date: Tue, 15 Nov 2022 14:25:16 -0600 Subject: scsi: bfa: Replace one-element array with flexible-array member One-element arrays are deprecated, and we are replacing them with flexible array members instead. So, replace one-element array with flexible-array member in struct fdmi_attr_s. Important to mention is that doing a build before/after this patch results in no binary output differences. This helps with the ongoing efforts to tighten the FORTIFY_SOURCE routines on memcpy() and help us make progress towards globally enabling -fstrict-flex-arrays=3 [1]. Link: https://github.com/KSPP/linux/issues/209 Link: https://github.com/KSPP/linux/issues/79 Link: https://gcc.gnu.org/pipermail/gcc-patches/2022-October/602902.html [1] Signed-off-by: Gustavo A. R. Silva Link: https://lore.kernel.org/r/Y3P1rEEBq7HzJygq@work Reviewed-by: Kees Cook Signed-off-by: Martin K. Petersen --- drivers/scsi/bfa/bfa_fc.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/scsi/bfa/bfa_fc.h b/drivers/scsi/bfa/bfa_fc.h index 0314e4b9e1fb..a12d693065ce 100644 --- a/drivers/scsi/bfa/bfa_fc.h +++ b/drivers/scsi/bfa/bfa_fc.h @@ -1548,7 +1548,7 @@ enum fdmi_port_attribute_type { struct fdmi_attr_s { __be16 type; __be16 len; - u8 value[1]; + u8 value[]; }; /* -- cgit v1.2.3 From 2c1a0a7584f5084f3ec79f86c9a54ee4c55307c4 Mon Sep 17 00:00:00 2001 From: Justin Tee Date: Tue, 15 Nov 2022 17:19:16 -0800 Subject: scsi: lpfc: Fix WQ|CQ|EQ resource check Adapter configurations with limited EQ resources may fail to initialize. Firmware resources are queried in lpfc_sli4_read_config(). The driver parameters cfg_irq_chann and cfg_hdw_queue are adjusted from defaults if constrained by firmware resources. The minimum resource check includes a special allocation for queues such as ELS, MBOX, NVME LS. However the additional reservation was also incorrectly applied to EQ resources. Reordered WQ|CQ|EQ resource checks to apply the special allocation adjustment to WQ and CQ resources only. Signed-off-by: Justin Tee Link: https://lore.kernel.org/r/20221116011921.105995-2-justintee8345@gmail.com Signed-off-by: Martin K. Petersen --- drivers/scsi/lpfc/lpfc_init.c | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/drivers/scsi/lpfc/lpfc_init.c b/drivers/scsi/lpfc/lpfc_init.c index b49c39569386..a6e32ecd4151 100644 --- a/drivers/scsi/lpfc/lpfc_init.c +++ b/drivers/scsi/lpfc/lpfc_init.c @@ -10092,17 +10092,15 @@ lpfc_sli4_read_config(struct lpfc_hba *phba) qmin = phba->sli4_hba.max_cfg_param.max_wq; if (phba->sli4_hba.max_cfg_param.max_cq < qmin) qmin = phba->sli4_hba.max_cfg_param.max_cq; - if (phba->sli4_hba.max_cfg_param.max_eq < qmin) - qmin = phba->sli4_hba.max_cfg_param.max_eq; /* - * Whats left after this can go toward NVME / FCP. - * The minus 4 accounts for ELS, NVME LS, MBOX - * plus one extra. When configured for - * NVMET, FCP io channel WQs are not created. + * Reserve 4 (ELS, NVME LS, MBOX, plus one extra) and + * the remainder can be used for NVME / FCP. */ qmin -= 4; + if (phba->sli4_hba.max_cfg_param.max_eq < qmin) + qmin = phba->sli4_hba.max_cfg_param.max_eq; - /* Check to see if there is enough for NVME */ + /* Check to see if there is enough for default cfg */ if ((phba->cfg_irq_chann > qmin) || (phba->cfg_hdw_queue > qmin)) { lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, -- cgit v1.2.3 From ae696255d655bec673e5a5707f37ff6a098e89c2 Mon Sep 17 00:00:00 2001 From: Justin Tee Date: Tue, 15 Nov 2022 17:19:17 -0800 Subject: scsi: lpfc: Correct bandwidth logging during receipt of congestion sync WCQE The lpfc_cmf_timer adjusts phba->cmf_link_byte_count periodically and can artifically inflate bandwidth percent. During bandwidth calculation, correct for this by setting a cap of logging a maximum of 100%. Bandwidth calculation is only used for display under LOG_CGN_MGMT so there is no expectation of impacts on performance. Signed-off-by: Justin Tee Link: https://lore.kernel.org/r/20221116011921.105995-3-justintee8345@gmail.com Signed-off-by: Martin K. Petersen --- drivers/scsi/lpfc/lpfc_sli.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/drivers/scsi/lpfc/lpfc_sli.c b/drivers/scsi/lpfc/lpfc_sli.c index 35c9404d5e49..182aaae60386 100644 --- a/drivers/scsi/lpfc/lpfc_sli.c +++ b/drivers/scsi/lpfc/lpfc_sli.c @@ -1846,6 +1846,12 @@ lpfc_cmf_sync_cmpl(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb, phba->cmf_link_byte_count); bwpcent = div64_u64(bw * 100 + slop, phba->cmf_link_byte_count); + /* Because of bytes adjustment due to shorter timer in + * lpfc_cmf_timer() the cmf_link_byte_count can be shorter and + * may seem like BW is above 100%. + */ + if (bwpcent > 100) + bwpcent = 100; if (phba->cmf_max_bytes_per_interval < bw && bwpcent > 95) -- cgit v1.2.3 From d99af587d59ca39747b4328dad0b193655835c90 Mon Sep 17 00:00:00 2001 From: Justin Tee Date: Tue, 15 Nov 2022 17:19:18 -0800 Subject: scsi: lpfc: Fix MI capability display in cmf_info sysfs attribute The dynamic mi_ver value holds the currently configured MI setting. mi_ver was being displayed as part of the cmf_info sysfs attribute, when the output string meant to display MI capabilities instead. Add a mi_cap member in the lpfc_pc_sli4_params structure that will store MI capabilities during initialization so that cmf_info prints out capabilities instead of current configuration. Signed-off-by: Justin Tee Link: https://lore.kernel.org/r/20221116011921.105995-4-justintee8345@gmail.com Signed-off-by: Martin K. Petersen --- drivers/scsi/lpfc/lpfc_attr.c | 2 +- drivers/scsi/lpfc/lpfc_init.c | 3 +++ drivers/scsi/lpfc/lpfc_sli4.h | 1 + 3 files changed, 5 insertions(+), 1 deletion(-) diff --git a/drivers/scsi/lpfc/lpfc_attr.c b/drivers/scsi/lpfc/lpfc_attr.c index 030ad1d59cbd..77e1b2911cb4 100644 --- a/drivers/scsi/lpfc/lpfc_attr.c +++ b/drivers/scsi/lpfc/lpfc_attr.c @@ -134,7 +134,7 @@ lpfc_cmf_info_show(struct device *dev, struct device_attribute *attr, scnprintf(tmp, sizeof(tmp), "Congestion Mgmt Info: E2Eattr %d Ver %d " "CMF %d cnt %d\n", - phba->sli4_hba.pc_sli4_params.mi_ver, + phba->sli4_hba.pc_sli4_params.mi_cap, cp ? cp->cgn_info_version : 0, phba->sli4_hba.pc_sli4_params.cmf, phba->cmf_timer_cnt); diff --git a/drivers/scsi/lpfc/lpfc_init.c b/drivers/scsi/lpfc/lpfc_init.c index a6e32ecd4151..a119c06742b8 100644 --- a/drivers/scsi/lpfc/lpfc_init.c +++ b/drivers/scsi/lpfc/lpfc_init.c @@ -699,6 +699,8 @@ lpfc_sli4_refresh_params(struct lpfc_hba *phba) return rc; } mbx_sli4_parameters = &mqe->un.get_sli4_parameters.sli4_parameters; + phba->sli4_hba.pc_sli4_params.mi_cap = + bf_get(cfg_mi_ver, mbx_sli4_parameters); /* Are we forcing MI off via module parameter? */ if (phba->cfg_enable_mi) @@ -13839,6 +13841,7 @@ lpfc_get_sli4_parameters(struct lpfc_hba *phba, LPFC_MBOXQ_t *mboxq) mbx_sli4_parameters); phba->sli4_hba.extents_in_use = bf_get(cfg_ext, mbx_sli4_parameters); phba->sli4_hba.rpi_hdrs_in_use = bf_get(cfg_hdrr, mbx_sli4_parameters); + sli4_params->mi_cap = bf_get(cfg_mi_ver, mbx_sli4_parameters); /* Check for Extended Pre-Registered SGL support */ phba->cfg_xpsgl = bf_get(cfg_xpsgl, mbx_sli4_parameters); diff --git a/drivers/scsi/lpfc/lpfc_sli4.h b/drivers/scsi/lpfc/lpfc_sli4.h index cbb1aa1cf025..f927c2a25d54 100644 --- a/drivers/scsi/lpfc/lpfc_sli4.h +++ b/drivers/scsi/lpfc/lpfc_sli4.h @@ -556,6 +556,7 @@ struct lpfc_pc_sli4_params { #define LPFC_MIB3_SUPPORT 3 uint16_t mi_value; #define LPFC_DFLT_MIB_VAL 2 + uint8_t mi_cap; uint8_t mib_bde_cnt; uint8_t cmf; uint8_t cqv; -- cgit v1.2.3 From 97f256913c5d8a633efe4f11d4ed2d6a3ea42635 Mon Sep 17 00:00:00 2001 From: Justin Tee Date: Tue, 15 Nov 2022 17:19:19 -0800 Subject: scsi: lpfc: Fix crash involving race between FLOGI timeout and devloss handler When a FLOGI completes with a sequence timeout error, a freed kref ptr dereference crash can occur due to a timing race involving ndlp referencing in lpfc_dev_loss_tmo_callbk. Fix by ensuring the driver accounts for an outstanding FLOGI when dev_loss is active. Also, don't remove the HBA_FLOGI_OUTSTANDING flag when the FLOGI is retried to allow the driver to handle the reference counts correctly in lpfc_dev_loss_tmo_handler. Reported-by: Dietmar Hahn Tested-by: Dietmar Hahn Signed-off-by: Justin Tee Link: https://lore.kernel.org/r/20221116011921.105995-5-justintee8345@gmail.com Signed-off-by: Martin K. Petersen --- drivers/scsi/lpfc/lpfc_els.c | 36 +++++++++++++++++++++++++++++++----- drivers/scsi/lpfc/lpfc_hbadisc.c | 36 ++++++++++++++++++++++++++---------- 2 files changed, 57 insertions(+), 15 deletions(-) diff --git a/drivers/scsi/lpfc/lpfc_els.c b/drivers/scsi/lpfc/lpfc_els.c index 9326340d4226..919741bbe267 100644 --- a/drivers/scsi/lpfc/lpfc_els.c +++ b/drivers/scsi/lpfc/lpfc_els.c @@ -952,6 +952,7 @@ lpfc_cmpl_els_flogi(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb, uint16_t fcf_index; int rc; u32 ulp_status, ulp_word4, tmo; + bool flogi_in_retry = false; /* Check to see if link went down during discovery */ if (lpfc_els_chk_latt(vport)) { @@ -1022,8 +1023,23 @@ stop_rr_fcf_flogi: phba->hba_flag, phba->fcf.fcf_flag); /* Check for retry */ - if (lpfc_els_retry(phba, cmdiocb, rspiocb)) + if (lpfc_els_retry(phba, cmdiocb, rspiocb)) { + /* Address a timing race with dev_loss. If dev_loss + * is active on this FPort node, put the initial ref + * count back to stop premature node release actions. + */ + lpfc_check_nlp_post_devloss(vport, ndlp); + flogi_in_retry = true; goto out; + } + + /* The FLOGI will not be retried. If the FPort node is not + * registered with the SCSI transport, remove the initial + * reference to trigger node release. + */ + if (!(ndlp->nlp_flag & NLP_IN_DEV_LOSS) && + !(ndlp->fc4_xpt_flags & SCSI_XPT_REGD)) + lpfc_nlp_put(ndlp); lpfc_printf_vlog(vport, KERN_WARNING, LOG_TRACE_EVENT, "0150 FLOGI failure Status:x%x/x%x " @@ -1086,7 +1102,7 @@ stop_rr_fcf_flogi: spin_unlock_irq(shost->host_lock); /* - * The FLogI succeeded. Sync the data for the CPU before + * The FLOGI succeeded. Sync the data for the CPU before * accessing it. */ prsp = list_get_first(&pcmd->list, struct lpfc_dmabuf, list); @@ -1108,6 +1124,12 @@ stop_rr_fcf_flogi: vport->phba->pport->vmid_flag |= (LPFC_VMID_ISSUE_QFPA | LPFC_VMID_TYPE_PRIO); + /* + * Address a timing race with dev_loss. If dev_loss is active on + * this FPort node, put the initial ref count back to stop premature + * node release actions. + */ + lpfc_check_nlp_post_devloss(vport, ndlp); if (vport->port_state == LPFC_FLOGI) { /* * If Common Service Parameters indicate Nport @@ -1198,7 +1220,9 @@ flogifail: lpfc_issue_clear_la(phba, vport); } out: - phba->hba_flag &= ~HBA_FLOGI_OUTSTANDING; + if (!flogi_in_retry) + phba->hba_flag &= ~HBA_FLOGI_OUTSTANDING; + lpfc_els_free_iocb(phba, cmdiocb); lpfc_nlp_put(ndlp); } @@ -1365,15 +1389,17 @@ lpfc_issue_els_flogi(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, return 1; } + /* Avoid race with FLOGI completion and hba_flags. */ + phba->hba_flag |= (HBA_FLOGI_ISSUED | HBA_FLOGI_OUTSTANDING); + rc = lpfc_issue_fabric_iocb(phba, elsiocb); if (rc == IOCB_ERROR) { + phba->hba_flag &= ~(HBA_FLOGI_ISSUED | HBA_FLOGI_OUTSTANDING); lpfc_els_free_iocb(phba, elsiocb); lpfc_nlp_put(ndlp); return 1; } - phba->hba_flag |= (HBA_FLOGI_ISSUED | HBA_FLOGI_OUTSTANDING); - /* Clear external loopback plug detected flag */ phba->link_flag &= ~LS_EXTERNAL_LOOPBACK; diff --git a/drivers/scsi/lpfc/lpfc_hbadisc.c b/drivers/scsi/lpfc/lpfc_hbadisc.c index d38ebd7281b9..80375d73b732 100644 --- a/drivers/scsi/lpfc/lpfc_hbadisc.c +++ b/drivers/scsi/lpfc/lpfc_hbadisc.c @@ -426,10 +426,6 @@ lpfc_dev_loss_tmo_handler(struct lpfc_nodelist *ndlp) name = (uint8_t *)&ndlp->nlp_portname; phba = vport->phba; - spin_lock_irqsave(&ndlp->lock, iflags); - ndlp->nlp_flag &= ~NLP_IN_DEV_LOSS; - spin_unlock_irqrestore(&ndlp->lock, iflags); - if (phba->sli_rev == LPFC_SLI_REV4) fcf_inuse = lpfc_fcf_inuse(phba); @@ -451,22 +447,36 @@ lpfc_dev_loss_tmo_handler(struct lpfc_nodelist *ndlp) *name, *(name+1), *(name+2), *(name+3), *(name+4), *(name+5), *(name+6), *(name+7), ndlp->nlp_DID); + + spin_lock_irqsave(&ndlp->lock, iflags); + ndlp->nlp_flag &= ~NLP_IN_DEV_LOSS; + spin_unlock_irqrestore(&ndlp->lock, iflags); return fcf_inuse; } /* Fabric nodes are done. */ if (ndlp->nlp_type & NLP_FABRIC) { spin_lock_irqsave(&ndlp->lock, iflags); - /* In massive vport configuration settings, it's possible - * dev_loss_tmo fired during node recovery. So, check if - * fabric nodes are in discovery states outstanding. + + /* In massive vport configuration settings or when the FLOGI + * completes with a sequence timeout, it's possible + * dev_loss_tmo fired during node recovery. The driver has to + * account for this race to allow for recovery and keep + * the reference counting correct. */ switch (ndlp->nlp_DID) { case Fabric_DID: fc_vport = vport->fc_vport; - if (fc_vport && - fc_vport->vport_state == FC_VPORT_INITIALIZING) - recovering = true; + if (fc_vport) { + /* NPIV path. */ + if (fc_vport->vport_state == + FC_VPORT_INITIALIZING) + recovering = true; + } else { + /* Physical port path. */ + if (phba->hba_flag & HBA_FLOGI_OUTSTANDING) + recovering = true; + } break; case Fabric_Cntl_DID: if (ndlp->nlp_flag & NLP_REG_LOGIN_SEND) @@ -514,6 +524,9 @@ lpfc_dev_loss_tmo_handler(struct lpfc_nodelist *ndlp) return fcf_inuse; } + spin_lock_irqsave(&ndlp->lock, iflags); + ndlp->nlp_flag &= ~NLP_IN_DEV_LOSS; + spin_unlock_irqrestore(&ndlp->lock, iflags); lpfc_nlp_put(ndlp); return fcf_inuse; } @@ -552,6 +565,9 @@ lpfc_dev_loss_tmo_handler(struct lpfc_nodelist *ndlp) return fcf_inuse; } + spin_lock_irqsave(&ndlp->lock, iflags); + ndlp->nlp_flag &= ~NLP_IN_DEV_LOSS; + spin_unlock_irqrestore(&ndlp->lock, iflags); if (!(ndlp->fc4_xpt_flags & NVME_XPT_REGD)) lpfc_disc_state_machine(vport, ndlp, NULL, NLP_EVT_DEVICE_RM); -- cgit v1.2.3 From d57d98fef46fead01d954afa1b585405b617a4e4 Mon Sep 17 00:00:00 2001 From: Justin Tee Date: Tue, 15 Nov 2022 17:19:21 -0800 Subject: scsi: lpfc: Update lpfc version to 14.2.0.9 Update lpfc version to 14.2.0.9. Signed-off-by: Justin Tee Link: https://lore.kernel.org/r/20221116011921.105995-7-justintee8345@gmail.com Signed-off-by: Martin K. Petersen --- drivers/scsi/lpfc/lpfc_version.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/scsi/lpfc/lpfc_version.h b/drivers/scsi/lpfc/lpfc_version.h index 378eba7b09d9..41a1128f8651 100644 --- a/drivers/scsi/lpfc/lpfc_version.h +++ b/drivers/scsi/lpfc/lpfc_version.h @@ -20,7 +20,7 @@ * included with this package. * *******************************************************************/ -#define LPFC_DRIVER_VERSION "14.2.0.8" +#define LPFC_DRIVER_VERSION "14.2.0.9" #define LPFC_DRIVER_NAME "lpfc" /* Used for SLI 2/3 */ -- cgit v1.2.3 From cdd9344e00b4fe3a4683a0ee58826c7a5ce778e0 Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Sun, 13 Nov 2022 21:33:59 +0100 Subject: scsi: lpfc: Remove linux/msi.h include Nothing in this file needs anything from linux/msi.h Signed-off-by: Thomas Gleixner Link: https://lore.kernel.org/r/20221113202428.436270297@linutronix.de Cc: James Smart Cc: Dick Kennedy Cc: "James E.J. Bottomley" Cc: "Martin K. Petersen" Cc: linux-scsi@vger.kernel.org Reviewed-by: James Smart Signed-off-by: Martin K. Petersen --- drivers/scsi/lpfc/lpfc_init.c | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/scsi/lpfc/lpfc_init.c b/drivers/scsi/lpfc/lpfc_init.c index a119c06742b8..9d595d37d6ca 100644 --- a/drivers/scsi/lpfc/lpfc_init.c +++ b/drivers/scsi/lpfc/lpfc_init.c @@ -36,7 +36,6 @@ #include #include #include -#include #include #include #include -- cgit v1.2.3 From 7870d24817890bccee98db0718acececd6399d04 Mon Sep 17 00:00:00 2001 From: Anastasia Kovaleva Date: Mon, 14 Nov 2022 13:24:58 +0300 Subject: scsi: target: core: Send max transfer length in blocks A MAXIMUM TRANSFER LENGTH value indicates the maximum transfer length in logical blocks that the device server accepts for a single command. Fix function sending the length in sectors instead of blocks. This patch also removes the special casing for fileio in block_size_store since this logic in now unified in spc_emulate_evpd_b0() for all backends. Reviewed-by: Konstantin Shelekhin Reviewed-by: Dmitriy Bogdanov Signed-off-by: Anastasia Kovaleva Link: https://lore.kernel.org/r/20221114102500.88892-2-a.kovaleva@yadro.com Reviewed-by: Mike Christie Signed-off-by: Martin K. Petersen --- drivers/target/target_core_configfs.c | 2 -- drivers/target/target_core_file.c | 1 - drivers/target/target_core_spc.c | 6 +++++- include/target/target_core_base.h | 1 - 4 files changed, 5 insertions(+), 5 deletions(-) diff --git a/drivers/target/target_core_configfs.c b/drivers/target/target_core_configfs.c index b8a5c8d6cfde..611b0424e305 100644 --- a/drivers/target/target_core_configfs.c +++ b/drivers/target/target_core_configfs.c @@ -1102,8 +1102,6 @@ static ssize_t block_size_store(struct config_item *item, } da->block_size = val; - if (da->max_bytes_per_io) - da->hw_max_sectors = da->max_bytes_per_io / val; pr_debug("dev[%p]: SE Device block_size changed to %u\n", da->da_dev, val); diff --git a/drivers/target/target_core_file.c b/drivers/target/target_core_file.c index 28aa643be5d5..f9aed9fa8ced 100644 --- a/drivers/target/target_core_file.c +++ b/drivers/target/target_core_file.c @@ -193,7 +193,6 @@ static int fd_configure_device(struct se_device *dev) } dev->dev_attrib.hw_block_size = fd_dev->fd_block_size; - dev->dev_attrib.max_bytes_per_io = FD_MAX_BYTES; dev->dev_attrib.hw_max_sectors = FD_MAX_BYTES / fd_dev->fd_block_size; dev->dev_attrib.hw_queue_depth = FD_MAX_DEVICE_QUEUE_DEPTH; diff --git a/drivers/target/target_core_spc.c b/drivers/target/target_core_spc.c index 621a460ba234..fcc7b10a7ae3 100644 --- a/drivers/target/target_core_spc.c +++ b/drivers/target/target_core_spc.c @@ -515,6 +515,7 @@ spc_emulate_evpd_b0(struct se_cmd *cmd, unsigned char *buf) struct se_device *dev = cmd->se_dev; u32 mtl = 0; int have_tp = 0, opt, min; + u32 io_max_blocks; /* * Following spc3r22 section 6.5.3 Block Limits VPD page, when @@ -553,7 +554,10 @@ spc_emulate_evpd_b0(struct se_cmd *cmd, unsigned char *buf) mtl = (cmd->se_tfo->max_data_sg_nents * PAGE_SIZE) / dev->dev_attrib.block_size; } - put_unaligned_be32(min_not_zero(mtl, dev->dev_attrib.hw_max_sectors), &buf[8]); + io_max_blocks = mult_frac(dev->dev_attrib.hw_max_sectors, + dev->dev_attrib.hw_block_size, + dev->dev_attrib.block_size); + put_unaligned_be32(min_not_zero(mtl, io_max_blocks), &buf[8]); /* * Set OPTIMAL TRANSFER LENGTH diff --git a/include/target/target_core_base.h b/include/target/target_core_base.h index 0c1e43980985..12c9ba16217e 100644 --- a/include/target/target_core_base.h +++ b/include/target/target_core_base.h @@ -712,7 +712,6 @@ struct se_dev_attrib { u32 unmap_granularity; u32 unmap_granularity_alignment; u32 max_write_same_len; - u32 max_bytes_per_io; struct se_device *da_dev; struct config_group da_group; }; -- cgit v1.2.3 From 9375031ee40b66c8fd2fc24d5fbea47b69f53de6 Mon Sep 17 00:00:00 2001 From: Anastasia Kovaleva Date: Mon, 14 Nov 2022 13:24:59 +0300 Subject: scsi: target: core: Make hw_max_sectors store the sectors amount in blocks By default, hw_max_sectors stores its value in 512 blocks in iblock, despite the fact that the block size can be 4096 bytes. Change hw_max_sectors to store the number of sectors in hw_block_size blocks. Reviewed-by: Konstantin Shelekhin Reviewed-by: Dmitriy Bogdanov Signed-off-by: Anastasia Kovaleva Link: https://lore.kernel.org/r/20221114102500.88892-3-a.kovaleva@yadro.com Reviewed-by: Mike Christie Signed-off-by: Martin K. Petersen --- drivers/target/target_core_iblock.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/drivers/target/target_core_iblock.c b/drivers/target/target_core_iblock.c index 8351c974cee3..2a704926edb9 100644 --- a/drivers/target/target_core_iblock.c +++ b/drivers/target/target_core_iblock.c @@ -124,7 +124,9 @@ static int iblock_configure_device(struct se_device *dev) q = bdev_get_queue(bd); dev->dev_attrib.hw_block_size = bdev_logical_block_size(bd); - dev->dev_attrib.hw_max_sectors = queue_max_hw_sectors(q); + dev->dev_attrib.hw_max_sectors = mult_frac(queue_max_hw_sectors(q), + SECTOR_SIZE, + dev->dev_attrib.hw_block_size); dev->dev_attrib.hw_queue_depth = q->nr_requests; /* -- cgit v1.2.3 From 689d94ec208cfdf95101d99319cb4bdc5f55774d Mon Sep 17 00:00:00 2001 From: Anastasia Kovaleva Date: Mon, 14 Nov 2022 13:25:00 +0300 Subject: scsi: target: core: Change the way target_xcopy_do_work() sets restiction on max I/O To determine how many blocks sends in one command, the minimum value is selected from the hw_max_sectors of both devices. In target_xcopy_do_work, hw_max_sectors are used as blocks, not sectors; it also ignores the fact that sectors can be of different sizes, for example 512 and 4096 bytes. Because of this, a number of blocks can be transmitted that the device will not be able to accept. Change the selection of max transmission size into bytes. Reviewed-by: Konstantin Shelekhin Reviewed-by: Dmitriy Bogdanov Signed-off-by: Anastasia Kovaleva Link: https://lore.kernel.org/r/20221114102500.88892-4-a.kovaleva@yadro.com Reviewed-by: Mike Christie Signed-off-by: Martin K. Petersen --- drivers/target/target_core_xcopy.c | 97 +++++++++++++++++++++----------------- drivers/target/target_core_xcopy.h | 2 +- 2 files changed, 54 insertions(+), 45 deletions(-) diff --git a/drivers/target/target_core_xcopy.c b/drivers/target/target_core_xcopy.c index edf522208285..49eaee022ef1 100644 --- a/drivers/target/target_core_xcopy.c +++ b/drivers/target/target_core_xcopy.c @@ -582,11 +582,11 @@ static int target_xcopy_read_source( struct xcopy_op *xop, struct se_device *src_dev, sector_t src_lba, - u32 src_sectors) + u32 src_bytes) { struct xcopy_pt_cmd xpt_cmd; struct se_cmd *se_cmd = &xpt_cmd.se_cmd; - u32 length = (src_sectors * src_dev->dev_attrib.block_size); + u32 transfer_length_block = src_bytes / src_dev->dev_attrib.block_size; int rc; unsigned char cdb[16]; bool remote_port = (xop->op_origin == XCOL_DEST_RECV_OP); @@ -597,11 +597,11 @@ static int target_xcopy_read_source( memset(&cdb[0], 0, 16); cdb[0] = READ_16; put_unaligned_be64(src_lba, &cdb[2]); - put_unaligned_be32(src_sectors, &cdb[10]); - pr_debug("XCOPY: Built READ_16: LBA: %llu Sectors: %u Length: %u\n", - (unsigned long long)src_lba, src_sectors, length); + put_unaligned_be32(transfer_length_block, &cdb[10]); + pr_debug("XCOPY: Built READ_16: LBA: %llu Blocks: %u Length: %u\n", + (unsigned long long)src_lba, transfer_length_block, src_bytes); - __target_init_cmd(se_cmd, &xcopy_pt_tfo, &xcopy_pt_sess, length, + __target_init_cmd(se_cmd, &xcopy_pt_tfo, &xcopy_pt_sess, src_bytes, DMA_FROM_DEVICE, 0, &xpt_cmd.sense_buffer[0], 0); rc = target_xcopy_setup_pt_cmd(&xpt_cmd, xop, src_dev, &cdb[0], @@ -627,11 +627,11 @@ static int target_xcopy_write_destination( struct xcopy_op *xop, struct se_device *dst_dev, sector_t dst_lba, - u32 dst_sectors) + u32 dst_bytes) { struct xcopy_pt_cmd xpt_cmd; struct se_cmd *se_cmd = &xpt_cmd.se_cmd; - u32 length = (dst_sectors * dst_dev->dev_attrib.block_size); + u32 transfer_length_block = dst_bytes / dst_dev->dev_attrib.block_size; int rc; unsigned char cdb[16]; bool remote_port = (xop->op_origin == XCOL_SOURCE_RECV_OP); @@ -642,11 +642,11 @@ static int target_xcopy_write_destination( memset(&cdb[0], 0, 16); cdb[0] = WRITE_16; put_unaligned_be64(dst_lba, &cdb[2]); - put_unaligned_be32(dst_sectors, &cdb[10]); - pr_debug("XCOPY: Built WRITE_16: LBA: %llu Sectors: %u Length: %u\n", - (unsigned long long)dst_lba, dst_sectors, length); + put_unaligned_be32(transfer_length_block, &cdb[10]); + pr_debug("XCOPY: Built WRITE_16: LBA: %llu Blocks: %u Length: %u\n", + (unsigned long long)dst_lba, transfer_length_block, dst_bytes); - __target_init_cmd(se_cmd, &xcopy_pt_tfo, &xcopy_pt_sess, length, + __target_init_cmd(se_cmd, &xcopy_pt_tfo, &xcopy_pt_sess, dst_bytes, DMA_TO_DEVICE, 0, &xpt_cmd.sense_buffer[0], 0); rc = target_xcopy_setup_pt_cmd(&xpt_cmd, xop, dst_dev, &cdb[0], @@ -670,9 +670,10 @@ static void target_xcopy_do_work(struct work_struct *work) struct se_cmd *ec_cmd = xop->xop_se_cmd; struct se_device *src_dev, *dst_dev; sector_t src_lba, dst_lba, end_lba; - unsigned int max_sectors; + unsigned long long max_bytes, max_bytes_src, max_bytes_dst, max_blocks; int rc = 0; - unsigned short nolb, max_nolb, copied_nolb = 0; + unsigned short nolb; + unsigned int copied_bytes = 0; sense_reason_t sense_rc; sense_rc = target_parse_xcopy_cmd(xop); @@ -691,23 +692,31 @@ static void target_xcopy_do_work(struct work_struct *work) nolb = xop->nolb; end_lba = src_lba + nolb; /* - * Break up XCOPY I/O into hw_max_sectors sized I/O based on the - * smallest max_sectors between src_dev + dev_dev, or + * Break up XCOPY I/O into hw_max_sectors * hw_block_size sized + * I/O based on the smallest max_bytes between src_dev + dst_dev */ - max_sectors = min(src_dev->dev_attrib.hw_max_sectors, - dst_dev->dev_attrib.hw_max_sectors); - max_sectors = min_t(u32, max_sectors, XCOPY_MAX_SECTORS); + max_bytes_src = (unsigned long long) src_dev->dev_attrib.hw_max_sectors * + src_dev->dev_attrib.hw_block_size; + max_bytes_dst = (unsigned long long) dst_dev->dev_attrib.hw_max_sectors * + dst_dev->dev_attrib.hw_block_size; - max_nolb = min_t(u16, max_sectors, ((u16)(~0U))); + max_bytes = min_t(u64, max_bytes_src, max_bytes_dst); + max_bytes = min_t(u64, max_bytes, XCOPY_MAX_BYTES); - pr_debug("target_xcopy_do_work: nolb: %hu, max_nolb: %hu end_lba: %llu\n", - nolb, max_nolb, (unsigned long long)end_lba); - pr_debug("target_xcopy_do_work: Starting src_lba: %llu, dst_lba: %llu\n", + /* + * Using shift instead of the division because otherwise GCC + * generates __udivdi3 that is missing on i386 + */ + max_blocks = max_bytes >> ilog2(src_dev->dev_attrib.block_size); + + pr_debug("%s: nolb: %u, max_blocks: %llu end_lba: %llu\n", __func__, + nolb, max_blocks, (unsigned long long)end_lba); + pr_debug("%s: Starting src_lba: %llu, dst_lba: %llu\n", __func__, (unsigned long long)src_lba, (unsigned long long)dst_lba); - while (src_lba < end_lba) { - unsigned short cur_nolb = min(nolb, max_nolb); - u32 cur_bytes = cur_nolb * src_dev->dev_attrib.block_size; + while (nolb) { + u32 cur_bytes = min_t(u64, max_bytes, nolb * src_dev->dev_attrib.block_size); + unsigned short cur_nolb = cur_bytes / src_dev->dev_attrib.block_size; if (cur_bytes != xop->xop_data_bytes) { /* @@ -724,43 +733,43 @@ static void target_xcopy_do_work(struct work_struct *work) xop->xop_data_bytes = cur_bytes; } - pr_debug("target_xcopy_do_work: Calling read src_dev: %p src_lba: %llu," - " cur_nolb: %hu\n", src_dev, (unsigned long long)src_lba, cur_nolb); + pr_debug("%s: Calling read src_dev: %p src_lba: %llu, cur_nolb: %hu\n", + __func__, src_dev, (unsigned long long)src_lba, cur_nolb); - rc = target_xcopy_read_source(ec_cmd, xop, src_dev, src_lba, cur_nolb); + rc = target_xcopy_read_source(ec_cmd, xop, src_dev, src_lba, cur_bytes); if (rc < 0) goto out; - src_lba += cur_nolb; - pr_debug("target_xcopy_do_work: Incremented READ src_lba to %llu\n", + src_lba += cur_bytes / src_dev->dev_attrib.block_size; + pr_debug("%s: Incremented READ src_lba to %llu\n", __func__, (unsigned long long)src_lba); - pr_debug("target_xcopy_do_work: Calling write dst_dev: %p dst_lba: %llu," - " cur_nolb: %hu\n", dst_dev, (unsigned long long)dst_lba, cur_nolb); + pr_debug("%s: Calling write dst_dev: %p dst_lba: %llu, cur_nolb: %u\n", + __func__, dst_dev, (unsigned long long)dst_lba, cur_nolb); rc = target_xcopy_write_destination(ec_cmd, xop, dst_dev, - dst_lba, cur_nolb); + dst_lba, cur_bytes); if (rc < 0) goto out; - dst_lba += cur_nolb; - pr_debug("target_xcopy_do_work: Incremented WRITE dst_lba to %llu\n", + dst_lba += cur_bytes / dst_dev->dev_attrib.block_size; + pr_debug("%s: Incremented WRITE dst_lba to %llu\n", __func__, (unsigned long long)dst_lba); - copied_nolb += cur_nolb; - nolb -= cur_nolb; + copied_bytes += cur_bytes; + nolb -= cur_bytes / src_dev->dev_attrib.block_size; } xcopy_pt_undepend_remotedev(xop); target_free_sgl(xop->xop_data_sg, xop->xop_data_nents); kfree(xop); - pr_debug("target_xcopy_do_work: Final src_lba: %llu, dst_lba: %llu\n", + pr_debug("%s: Final src_lba: %llu, dst_lba: %llu\n", __func__, (unsigned long long)src_lba, (unsigned long long)dst_lba); - pr_debug("target_xcopy_do_work: Blocks copied: %hu, Bytes Copied: %u\n", - copied_nolb, copied_nolb * dst_dev->dev_attrib.block_size); + pr_debug("%s: Blocks copied: %u, Bytes Copied: %u\n", __func__, + copied_bytes / dst_dev->dev_attrib.block_size, copied_bytes); - pr_debug("target_xcopy_do_work: Setting X-COPY GOOD status -> sending response\n"); + pr_debug("%s: Setting X-COPY GOOD status -> sending response\n", __func__); target_complete_cmd(ec_cmd, SAM_STAT_GOOD); return; @@ -776,8 +785,8 @@ out: err_free: kfree(xop); - pr_warn_ratelimited("target_xcopy_do_work: rc: %d, sense: %u, XCOPY operation failed\n", - rc, sense_rc); + pr_warn_ratelimited("%s: rc: %d, sense: %u, XCOPY operation failed\n", + __func__, rc, sense_rc); target_complete_cmd_with_sense(ec_cmd, SAM_STAT_CHECK_CONDITION, sense_rc); } diff --git a/drivers/target/target_core_xcopy.h b/drivers/target/target_core_xcopy.h index e5f20005179a..0aad7dc65895 100644 --- a/drivers/target/target_core_xcopy.h +++ b/drivers/target/target_core_xcopy.h @@ -5,7 +5,7 @@ #define XCOPY_TARGET_DESC_LEN 32 #define XCOPY_SEGMENT_DESC_LEN 28 #define XCOPY_NAA_IEEE_REGEX_LEN 16 -#define XCOPY_MAX_SECTORS 4096 +#define XCOPY_MAX_BYTES 16777216 /* 16 MB */ /* * SPC4r37 6.4.6.1 -- cgit v1.2.3 From fec1b2fa62c162d03f5dcd7b03e3c89d3116d49f Mon Sep 17 00:00:00 2001 From: Maurizio Lombardi Date: Tue, 15 Nov 2022 13:56:38 +0100 Subject: scsi: target: iscsi: Fix a race condition between login_work and the login thread In case a malicious initiator sends some random data immediately after a login PDU; the iscsi_target_sk_data_ready() callback will schedule the login_work and, at the same time, the negotiation may end without clearing the LOGIN_FLAGS_INITIAL_PDU flag (because no additional PDU exchanges are required to complete the login). The login has been completed but the login_work function will find the LOGIN_FLAGS_INITIAL_PDU flag set and will never stop from rescheduling itself; at this point, if the initiator drops the connection, the iscsit_conn structure will be freed, login_work will dereference a released socket structure and the kernel crashes. BUG: kernel NULL pointer dereference, address: 0000000000000230 PF: supervisor write access in kernel mode PF: error_code(0x0002) - not-present page Workqueue: events iscsi_target_do_login_rx [iscsi_target_mod] RIP: 0010:_raw_read_lock_bh+0x15/0x30 Call trace: iscsi_target_do_login_rx+0x75/0x3f0 [iscsi_target_mod] process_one_work+0x1e8/0x3c0 Fix this bug by forcing login_work to stop after the login has been completed and the socket callbacks have been restored. Add a comment to clearify the return values of iscsi_target_do_login() Signed-off-by: Maurizio Lombardi Link: https://lore.kernel.org/r/20221115125638.102517-1-mlombard@redhat.com Reviewed-by: Mike Christie Signed-off-by: Martin K. Petersen --- drivers/target/iscsi/iscsi_target_nego.c | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/drivers/target/iscsi/iscsi_target_nego.c b/drivers/target/iscsi/iscsi_target_nego.c index f2919319ad38..ff49c8f3fe24 100644 --- a/drivers/target/iscsi/iscsi_target_nego.c +++ b/drivers/target/iscsi/iscsi_target_nego.c @@ -1018,6 +1018,13 @@ static int iscsi_target_handle_csg_one(struct iscsit_conn *conn, struct iscsi_lo return 0; } +/* + * RETURN VALUE: + * + * 1 = Login successful + * -1 = Login failed + * 0 = More PDU exchanges required + */ static int iscsi_target_do_login(struct iscsit_conn *conn, struct iscsi_login *login) { int pdu_count = 0; @@ -1363,12 +1370,13 @@ int iscsi_target_start_negotiation( ret = -1; if (ret < 0) { - cancel_delayed_work_sync(&conn->login_work); iscsi_target_restore_sock_callbacks(conn); iscsi_remove_failed_auth_entry(conn); } - if (ret != 0) + if (ret != 0) { + cancel_delayed_work_sync(&conn->login_work); iscsi_target_nego_release(conn); + } return ret; } -- cgit v1.2.3 From a72629b5cdbc43e28a4a19b0fce8d17c582c4db4 Mon Sep 17 00:00:00 2001 From: Maurizio Lombardi Date: Mon, 21 Nov 2022 10:27:03 +0100 Subject: scsi: target: core: Fix hard lockup when executing a compare-and-write command While handling an I/O completion for the compare portion of a COMPARE_AND_WRITE command, it may happen that the compare_and_write_callback function submits new bio structs while still in softirq context. Low level drivers like md raid5 do not expect their make_request call to be used in softirq context, they call into schedule() and create a deadlocked system. __schedule at ffffffff873a0807 schedule at ffffffff873a0cc5 raid5_get_active_stripe at ffffffffc0875744 [raid456] raid5_make_request at ffffffffc0875a50 [raid456] md_handle_request at ffffffff8713b9f9 md_make_request at ffffffff8713bacb generic_make_request at ffffffff86e6f14b submit_bio at ffffffff86e6f27c iblock_submit_bios at ffffffffc0b4e4dc [target_core_iblock] iblock_execute_rw at ffffffffc0b4f3ce [target_core_iblock] __target_execute_cmd at ffffffffc1090079 [target_core_mod] compare_and_write_callback at ffffffffc1093602 [target_core_mod] target_cmd_interrupted at ffffffffc108d1ec [target_core_mod] target_complete_cmd_with_sense at ffffffffc108d27c [target_core_mod] iblock_complete_cmd at ffffffffc0b4e23a [target_core_iblock] dm_io_dec_pending at ffffffffc00db29e [dm_mod] clone_endio at ffffffffc00dbf07 [dm_mod] raid5_align_endio at ffffffffc086d6c2 [raid456] blk_update_request at ffffffff86e6d950 scsi_end_request at ffffffff87063d48 scsi_io_completion at ffffffff87063ee8 blk_complete_reqs at ffffffff86e77b05 __softirqentry_text_start at ffffffff876000d7 This problem appears to be an issue between target_cmd_interrupted() and compare_and_write_callback(). target_cmd_interrupted() calls the se_cmd's transport_complete_callback function pointer if the se_cmd is being stopped or aborted, and CMD_T_ABORTED was set on the se_cmd. When calling compare_and_write_callback(), the success parameter was set to false. target_cmd_interrupted() seems to expect this means the callback will do cleanup that does not require a process context. But compare_and_write_callback() ignores the parameter if there was I/O done for the compare part of COMPARE_AND_WRITE. Since there was data, the function continued on, passed the compare, and issued a write while ignoring the value of the success parameter. The submit of a bio for the write portion of the COMPARE_AND_WRITE then causes schedule to be unsafely called from the softirq context. Fix the bug in compare_and_write_callback by jumping to the out label if success == "false", after checking if we have been called by transport_generic_request_failure(); The command is being aborted or stopped so there is no need to submit the write bio for the write part of the COMPARE_AND_WRITE command. Signed-off-by: Maurizio Lombardi Link: https://lore.kernel.org/r/20221121092703.316489-1-mlombard@redhat.com Reviewed-by: Mike Christie Signed-off-by: Martin K. Petersen --- drivers/target/target_core_sbc.c | 22 ++++++++++++++++------ 1 file changed, 16 insertions(+), 6 deletions(-) diff --git a/drivers/target/target_core_sbc.c b/drivers/target/target_core_sbc.c index 1cd41e3834bb..7536ca797606 100644 --- a/drivers/target/target_core_sbc.c +++ b/drivers/target/target_core_sbc.c @@ -446,12 +446,22 @@ static sense_reason_t compare_and_write_callback(struct se_cmd *cmd, bool succes sense_reason_t ret = TCM_NO_SENSE; int i; - /* - * Handle early failure in transport_generic_request_failure(), - * which will not have taken ->caw_sem yet.. - */ - if (!success && (!cmd->t_data_sg || !cmd->t_bidi_data_sg)) - return TCM_NO_SENSE; + if (!success) { + /* + * Handle early failure in transport_generic_request_failure(), + * which will not have taken ->caw_sem yet.. + */ + if (!cmd->t_data_sg || !cmd->t_bidi_data_sg) + return TCM_NO_SENSE; + + /* + * The command has been stopped or aborted so + * we don't have to perform the write operation. + */ + WARN_ON(!(cmd->transport_state & + (CMD_T_ABORTED | CMD_T_STOP))); + goto out; + } /* * Handle special case for zero-length COMPARE_AND_WRITE */ -- cgit v1.2.3 From 0c26a2d7c98039e913e63f9250fde738a3f88a60 Mon Sep 17 00:00:00 2001 From: Wenchao Hao Date: Tue, 22 Nov 2022 18:11:05 +0000 Subject: scsi: iscsi: Rename iscsi_set_param() to iscsi_if_set_param() There are two iscsi_set_param() functions defined in libiscsi.c and scsi_transport_iscsi.c respectively which is confusing. Rename the one in scsi_transport_iscsi.c to iscsi_if_set_param(). Signed-off-by: Wenchao Hao Link: https://lore.kernel.org/r/20221122181105.4123935-1-haowenchao@huawei.com Reviewed-by: Mike Christie Reviewed-by: Lee Duncan Signed-off-by: Martin K. Petersen --- drivers/scsi/scsi_transport_iscsi.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/scsi/scsi_transport_iscsi.c b/drivers/scsi/scsi_transport_iscsi.c index cd3db9684e52..c3fe5ecfee59 100644 --- a/drivers/scsi/scsi_transport_iscsi.c +++ b/drivers/scsi/scsi_transport_iscsi.c @@ -2988,7 +2988,7 @@ iscsi_if_destroy_conn(struct iscsi_transport *transport, struct iscsi_uevent *ev } static int -iscsi_set_param(struct iscsi_transport *transport, struct iscsi_uevent *ev) +iscsi_if_set_param(struct iscsi_transport *transport, struct iscsi_uevent *ev) { char *data = (char*)ev + sizeof(*ev); struct iscsi_cls_conn *conn; @@ -3941,7 +3941,7 @@ iscsi_if_recv_msg(struct sk_buff *skb, struct nlmsghdr *nlh, uint32_t *group) err = -EINVAL; break; case ISCSI_UEVENT_SET_PARAM: - err = iscsi_set_param(transport, ev); + err = iscsi_if_set_param(transport, ev); break; case ISCSI_UEVENT_CREATE_CONN: case ISCSI_UEVENT_DESTROY_CONN: -- cgit v1.2.3 From ec9780e48c77f469c339b53940ef0c5eacc8b9d2 Mon Sep 17 00:00:00 2001 From: Wenchao Hao Date: Wed, 23 Nov 2022 20:21:36 +0800 Subject: scsi: core: Increase scsi_device's iodone_cnt in scsi_timeout() If a SCSI command times out and is going to be aborted, we should increase the iodone_cnt of the related scsi_device. Otherwise the iodone_cnt would be smaller than iorequest_cnt. Increasing iodone_cnt in scsi_timeout() would not cause a double accounting issue. Brief analysis follows: - We add the iodone_cnt when BLK_EH_DONE is returned in scsi_timeout(). The related command's timeout event would not happen. - If the abort succeeds and the command is not retried, the command would be completed with scsi_finish_command() which would not increase iodone_cnt. - If the abort succeeds and the command is retried, it would be requeue. A scsi_dispatch_cmd() would be called and iorequest_cnt would be increased again. - If the abort fails, the error handler successfully recovers the device, and the command is not retried, the command would be completed with scsi_finish_command() which would not increase iodone_cnt. - If the abort fails, the error handler successfully recovers the device, and the command is retried, the iorequest_cnt would be increased again. Signed-off-by: Wenchao Hao Link: https://lore.kernel.org/r/20221123122137.150776-2-haowenchao@huawei.com Reviewed-by: Mike Christie Signed-off-by: Martin K. Petersen --- drivers/scsi/scsi_error.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/scsi/scsi_error.c b/drivers/scsi/scsi_error.c index be2a70c5ac6d..613d5aeb1e3c 100644 --- a/drivers/scsi/scsi_error.c +++ b/drivers/scsi/scsi_error.c @@ -354,6 +354,7 @@ enum blk_eh_timer_return scsi_timeout(struct request *req) */ if (test_and_set_bit(SCMD_STATE_COMPLETE, &scmd->state)) return BLK_EH_DONE; + atomic_inc(&scmd->device->iodone_cnt); if (scsi_abort_command(scmd) != SUCCESS) { set_host_byte(scmd, DID_TIME_OUT); scsi_eh_scmd_add(scmd); -- cgit v1.2.3 From cfee29ffb45b1c9798011b19d454637d1b0fe87d Mon Sep 17 00:00:00 2001 From: Wenchao Hao Date: Wed, 23 Nov 2022 20:21:37 +0800 Subject: scsi: core: Do not increase scsi_device's iorequest_cnt if dispatch failed If scsi_dispatch_cmd() failed, the SCSI command was not sent to the target. scsi_queue_rq() would return BLK_STS_RESOURCE if scsi_dispatch_cmd() failed, and the related request would be requeued. The timeout of this request would not fire, so noone would increase iodone_cnt. Signed-off-by: Wenchao Hao Link: https://lore.kernel.org/r/20221123122137.150776-3-haowenchao@huawei.com Reviewed-by: Mike Christie Signed-off-by: Martin K. Petersen --- drivers/scsi/scsi_lib.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/drivers/scsi/scsi_lib.c b/drivers/scsi/scsi_lib.c index ec890865abae..a29d87e57430 100644 --- a/drivers/scsi/scsi_lib.c +++ b/drivers/scsi/scsi_lib.c @@ -1464,8 +1464,6 @@ static int scsi_dispatch_cmd(struct scsi_cmnd *cmd) struct Scsi_Host *host = cmd->device->host; int rtn = 0; - atomic_inc(&cmd->device->iorequest_cnt); - /* check if the device is still usable */ if (unlikely(cmd->device->sdev_state == SDEV_DEL)) { /* in SDEV_DEL we error all commands. DID_NO_CONNECT @@ -1764,6 +1762,7 @@ static blk_status_t scsi_queue_rq(struct blk_mq_hw_ctx *hctx, goto out_dec_host_busy; } + atomic_inc(&cmd->device->iorequest_cnt); return BLK_STS_OK; out_dec_host_busy: -- cgit v1.2.3 From 9c9ff300e0de07475796495d86f449340d454a0c Mon Sep 17 00:00:00 2001 From: Yuan Can Date: Tue, 22 Nov 2022 01:57:51 +0000 Subject: scsi: hpsa: Fix possible memory leak in hpsa_init_one() The hpda_alloc_ctlr_info() allocates h and its field reply_map. However, in hpsa_init_one(), if alloc_percpu() failed, the hpsa_init_one() jumps to clean1 directly, which frees h and leaks the h->reply_map. Fix by calling hpda_free_ctlr_info() to release h->replay_map and h instead free h directly. Fixes: 8b834bff1b73 ("scsi: hpsa: fix selection of reply queue") Signed-off-by: Yuan Can Link: https://lore.kernel.org/r/20221122015751.87284-1-yuancan@huawei.com Reviewed-by: Ming Lei Signed-off-by: Martin K. Petersen --- drivers/scsi/hpsa.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/scsi/hpsa.c b/drivers/scsi/hpsa.c index f8e832b1bc46..e5cbc97a5ea4 100644 --- a/drivers/scsi/hpsa.c +++ b/drivers/scsi/hpsa.c @@ -8925,7 +8925,7 @@ clean1: /* wq/aer/h */ destroy_workqueue(h->monitor_ctlr_wq); h->monitor_ctlr_wq = NULL; } - kfree(h); + hpda_free_ctlr_info(h); return rc; } -- cgit v1.2.3 From 78316e9dfc24906dd474630928ed1d3c562b568e Mon Sep 17 00:00:00 2001 From: Yang Yingliang Date: Wed, 9 Nov 2022 11:24:03 +0800 Subject: scsi: mpt3sas: Fix possible resource leaks in mpt3sas_transport_port_add() In mpt3sas_transport_port_add(), if sas_rphy_add() returns error, sas_rphy_free() needs be called to free the resource allocated in sas_end_device_alloc(). Otherwise a kernel crash will happen: Unable to handle kernel NULL pointer dereference at virtual address 0000000000000108 CPU: 45 PID: 37020 Comm: bash Kdump: loaded Tainted: G W 6.1.0-rc1+ #189 pstate: 60000005 (nZCv daif -PAN -UAO -TCO -DIT -SSBS BTYPE=--) pc : device_del+0x54/0x3d0 lr : device_del+0x37c/0x3d0 Call trace: device_del+0x54/0x3d0 attribute_container_class_device_del+0x28/0x38 transport_remove_classdev+0x6c/0x80 attribute_container_device_trigger+0x108/0x110 transport_remove_device+0x28/0x38 sas_rphy_remove+0x50/0x78 [scsi_transport_sas] sas_port_delete+0x30/0x148 [scsi_transport_sas] do_sas_phy_delete+0x78/0x80 [scsi_transport_sas] device_for_each_child+0x68/0xb0 sas_remove_children+0x30/0x50 [scsi_transport_sas] sas_rphy_remove+0x38/0x78 [scsi_transport_sas] sas_port_delete+0x30/0x148 [scsi_transport_sas] do_sas_phy_delete+0x78/0x80 [scsi_transport_sas] device_for_each_child+0x68/0xb0 sas_remove_children+0x30/0x50 [scsi_transport_sas] sas_remove_host+0x20/0x38 [scsi_transport_sas] scsih_remove+0xd8/0x420 [mpt3sas] Because transport_add_device() is not called when sas_rphy_add() fails, the device is not added. When sas_rphy_remove() is subsequently called to remove the device in the remove() path, a NULL pointer dereference happens. Fixes: f92363d12359 ("[SCSI] mpt3sas: add new driver supporting 12GB SAS") Signed-off-by: Yang Yingliang Link: https://lore.kernel.org/r/20221109032403.1636422-1-yangyingliang@huawei.com Signed-off-by: Martin K. Petersen --- drivers/scsi/mpt3sas/mpt3sas_transport.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/scsi/mpt3sas/mpt3sas_transport.c b/drivers/scsi/mpt3sas/mpt3sas_transport.c index 0681daee6c14..e5ecd6ada6cd 100644 --- a/drivers/scsi/mpt3sas/mpt3sas_transport.c +++ b/drivers/scsi/mpt3sas/mpt3sas_transport.c @@ -829,6 +829,8 @@ mpt3sas_transport_port_add(struct MPT3SAS_ADAPTER *ioc, u16 handle, if ((sas_rphy_add(rphy))) { ioc_err(ioc, "failure at %s:%d/%s()!\n", __FILE__, __LINE__, __func__); + sas_rphy_free(rphy); + rphy = NULL; } if (mpt3sas_port->remote_identify.device_type == SAS_END_DEVICE) { -- cgit v1.2.3 From 4ef174a3ad9b5d73c1b6573e244ebba2b0d86eac Mon Sep 17 00:00:00 2001 From: Yang Yingliang Date: Thu, 10 Nov 2022 23:11:29 +0800 Subject: scsi: hpsa: Fix error handling in hpsa_add_sas_host() hpsa_sas_port_add_phy() does: ... sas_phy_add() -> may return error here sas_port_add_phy() ... Whereas hpsa_free_sas_phy() does: ... sas_port_delete_phy() sas_phy_delete() ... If hpsa_sas_port_add_phy() returns an error, hpsa_free_sas_phy() can not be called to free the memory because the port and the phy have not been added yet. Replace hpsa_free_sas_phy() with sas_phy_free() and kfree() to avoid kernel crash in this case. Fixes: d04e62b9d63a ("hpsa: add in sas transport class") Signed-off-by: Yang Yingliang Link: https://lore.kernel.org/r/20221110151129.394389-1-yangyingliang@huawei.com Signed-off-by: Martin K. Petersen --- drivers/scsi/hpsa.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/scsi/hpsa.c b/drivers/scsi/hpsa.c index e5cbc97a5ea4..6696967c5192 100644 --- a/drivers/scsi/hpsa.c +++ b/drivers/scsi/hpsa.c @@ -9786,7 +9786,8 @@ static int hpsa_add_sas_host(struct ctlr_info *h) return 0; free_sas_phy: - hpsa_free_sas_phy(hpsa_sas_phy); + sas_phy_free(hpsa_sas_phy->phy); + kfree(hpsa_sas_phy); free_sas_port: hpsa_free_sas_port(hpsa_sas_port); free_sas_node: -- cgit v1.2.3 From fda34a5d304d0b98cc967e8763b52221b66dc202 Mon Sep 17 00:00:00 2001 From: Yang Yingliang Date: Fri, 11 Nov 2022 12:30:12 +0800 Subject: scsi: hpsa: Fix possible memory leak in hpsa_add_sas_device() If hpsa_sas_port_add_rphy() returns an error, the 'rphy' allocated in sas_end_device_alloc() needs to be freed. Address this by calling sas_rphy_free() in the error path. Fixes: d04e62b9d63a ("hpsa: add in sas transport class") Signed-off-by: Yang Yingliang Link: https://lore.kernel.org/r/20221111043012.1074466-1-yangyingliang@huawei.com Signed-off-by: Martin K. Petersen --- drivers/scsi/hpsa.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/drivers/scsi/hpsa.c b/drivers/scsi/hpsa.c index 6696967c5192..4dbf51e2623a 100644 --- a/drivers/scsi/hpsa.c +++ b/drivers/scsi/hpsa.c @@ -9823,10 +9823,12 @@ static int hpsa_add_sas_device(struct hpsa_sas_node *hpsa_sas_node, rc = hpsa_sas_port_add_rphy(hpsa_sas_port, rphy); if (rc) - goto free_sas_port; + goto free_sas_rphy; return 0; +free_sas_rphy: + sas_rphy_free(rphy); free_sas_port: hpsa_free_sas_port(hpsa_sas_port); device->sas_port = NULL; -- cgit v1.2.3 From 859ed37c9c3f456510b97ecb0bf155cee2b9d3fc Mon Sep 17 00:00:00 2001 From: ChanWoo Lee Date: Fri, 11 Nov 2022 15:21:26 +0900 Subject: scsi: ufs: core: Separate function name and message Separate the function name and message to make it easier to check the log. Modify messages to fit the format of others. Signed-off-by: ChanWoo Lee Link: https://lore.kernel.org/r/20221111062126.7307-1-cw9316.lee@samsung.com Signed-off-by: Martin K. Petersen --- drivers/ufs/core/ufshcd.c | 6 +++--- drivers/ufs/core/ufshpb.c | 6 +++--- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/drivers/ufs/core/ufshcd.c b/drivers/ufs/core/ufshcd.c index 768cb49d269c..747183052114 100644 --- a/drivers/ufs/core/ufshcd.c +++ b/drivers/ufs/core/ufshcd.c @@ -4480,7 +4480,7 @@ static int ufshcd_complete_dev_init(struct ufs_hba *hba) QUERY_FLAG_IDN_FDEVICEINIT, 0, NULL); if (err) { dev_err(hba->dev, - "%s setting fDeviceInit flag failed with error %d\n", + "%s: setting fDeviceInit flag failed with error %d\n", __func__, err); goto out; } @@ -4497,11 +4497,11 @@ static int ufshcd_complete_dev_init(struct ufs_hba *hba) if (err) { dev_err(hba->dev, - "%s reading fDeviceInit flag failed with error %d\n", + "%s: reading fDeviceInit flag failed with error %d\n", __func__, err); } else if (flag_res) { dev_err(hba->dev, - "%s fDeviceInit was not cleared by the device\n", + "%s: fDeviceInit was not cleared by the device\n", __func__); err = -EBUSY; } diff --git a/drivers/ufs/core/ufshpb.c b/drivers/ufs/core/ufshpb.c index 3d69a81c5b17..fda3e7b494a6 100644 --- a/drivers/ufs/core/ufshpb.c +++ b/drivers/ufs/core/ufshpb.c @@ -2289,7 +2289,7 @@ static bool ufshpb_check_hpb_reset_query(struct ufs_hba *hba) /* wait for the device to complete HPB reset query */ for (try = 0; try < HPB_RESET_REQ_RETRIES; try++) { dev_dbg(hba->dev, - "%s start flag reset polling %d times\n", + "%s: start flag reset polling %d times\n", __func__, try); /* Poll fHpbReset flag to be cleared */ @@ -2298,7 +2298,7 @@ static bool ufshpb_check_hpb_reset_query(struct ufs_hba *hba) if (err) { dev_err(hba->dev, - "%s reading fHpbReset flag failed with error %d\n", + "%s: reading fHpbReset flag failed with error %d\n", __func__, err); return flag_res; } @@ -2310,7 +2310,7 @@ static bool ufshpb_check_hpb_reset_query(struct ufs_hba *hba) } if (flag_res) { dev_err(hba->dev, - "%s fHpbReset was not cleared by the device\n", + "%s: fHpbReset was not cleared by the device\n", __func__); } out: -- cgit v1.2.3 From 5277326d07fbf68aa7fc9e7bce6c381002e00fca Mon Sep 17 00:00:00 2001 From: ChanWoo Lee Date: Fri, 11 Nov 2022 15:22:09 +0900 Subject: scsi: ufs: core: Switch 'check_for_bkops' to bool Only checks true and false so it can be converted to bool. Signed-off-by: ChanWoo Lee Link: https://lore.kernel.org/r/20221111062209.7365-1-cw9316.lee@samsung.com Signed-off-by: Martin K. Petersen --- drivers/ufs/core/ufshcd.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/ufs/core/ufshcd.c b/drivers/ufs/core/ufshcd.c index 747183052114..0e8850869b21 100644 --- a/drivers/ufs/core/ufshcd.c +++ b/drivers/ufs/core/ufshcd.c @@ -8825,7 +8825,7 @@ static int ufshcd_set_dev_pwr_mode(struct ufs_hba *hba, static int ufshcd_link_state_transition(struct ufs_hba *hba, enum uic_link_state req_link_state, - int check_for_bkops) + bool check_for_bkops) { int ret = 0; @@ -8976,7 +8976,7 @@ static void ufshcd_hba_vreg_set_hpm(struct ufs_hba *hba) static int __ufshcd_wl_suspend(struct ufs_hba *hba, enum ufs_pm_op pm_op) { int ret = 0; - int check_for_bkops; + bool check_for_bkops; enum ufs_pm_level pm_lvl; enum ufs_dev_pwr_mode req_dev_pwr_mode; enum uic_link_state req_link_state; -- cgit v1.2.3 From 222d227f375b4cfa517a8f1f0f266ebe0263ad05 Mon Sep 17 00:00:00 2001 From: ChanWoo Lee Date: Fri, 11 Nov 2022 15:23:01 +0900 Subject: scsi: ufs: core: Fix unnecessary operation for early return Setting bitmap_len is not required when returning early. Defer until it is needed. Signed-off-by: ChanWoo Lee Link: https://lore.kernel.org/r/20221111062301.7423-1-cw9316.lee@samsung.com Signed-off-by: Martin K. Petersen --- drivers/ufs/core/ufshpb.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/drivers/ufs/core/ufshpb.c b/drivers/ufs/core/ufshpb.c index fda3e7b494a6..be3fb24b93d8 100644 --- a/drivers/ufs/core/ufshpb.c +++ b/drivers/ufs/core/ufshpb.c @@ -233,11 +233,6 @@ next_srgn: rgn = hpb->rgn_tbl + rgn_idx; srgn = rgn->srgn_tbl + srgn_idx; - if (likely(!srgn->is_last)) - bitmap_len = hpb->entries_per_srgn; - else - bitmap_len = hpb->last_srgn_entries; - if (!ufshpb_is_valid_srgn(rgn, srgn)) return true; @@ -253,6 +248,11 @@ next_srgn: return true; } + if (likely(!srgn->is_last)) + bitmap_len = hpb->entries_per_srgn; + else + bitmap_len = hpb->last_srgn_entries; + if ((srgn_offset + cnt) > bitmap_len) bit_len = bitmap_len - srgn_offset; else -- cgit v1.2.3 From bb0cd225dd37df1f4a22e36dad59ff33178ecdfc Mon Sep 17 00:00:00 2001 From: Chen Zhongjin Date: Fri, 11 Nov 2022 15:40:46 +0800 Subject: scsi: efct: Fix possible memleak in efct_device_init() In efct_device_init(), when efct_scsi_reg_fc_transport() fails, efct_scsi_tgt_driver_exit() is not called to release memory for efct_scsi_tgt_driver_init() and causes memleak: unreferenced object 0xffff8881020ce000 (size 2048): comm "modprobe", pid 465, jiffies 4294928222 (age 55.872s) backtrace: [<0000000021a1ef1b>] kmalloc_trace+0x27/0x110 [<000000004c3ed51c>] target_register_template+0x4fd/0x7b0 [target_core_mod] [<00000000f3393296>] efct_scsi_tgt_driver_init+0x18/0x50 [efct] [<00000000115de533>] 0xffffffffc0d90011 [<00000000d608f646>] do_one_initcall+0xd0/0x4e0 [<0000000067828cf1>] do_init_module+0x1cc/0x6a0 ... Fixes: 4df84e846624 ("scsi: elx: efct: Driver initialization routines") Signed-off-by: Chen Zhongjin Link: https://lore.kernel.org/r/20221111074046.57061-1-chenzhongjin@huawei.com Signed-off-by: Martin K. Petersen --- drivers/scsi/elx/efct/efct_driver.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/scsi/elx/efct/efct_driver.c b/drivers/scsi/elx/efct/efct_driver.c index b08fc8839808..49fd2cfed70c 100644 --- a/drivers/scsi/elx/efct/efct_driver.c +++ b/drivers/scsi/elx/efct/efct_driver.c @@ -42,6 +42,7 @@ efct_device_init(void) rc = efct_scsi_reg_fc_transport(); if (rc) { + efct_scsi_tgt_driver_exit(); pr_err("failed to register to FC host\n"); return rc; } -- cgit v1.2.3 From ed0f17b748b20271cb568c7ca0b23b120316a47d Mon Sep 17 00:00:00 2001 From: Harshit Mogalapalli Date: Fri, 11 Nov 2022 23:00:31 -0800 Subject: scsi: scsi_debug: Fix a warning in resp_verify() As 'vnum' is controlled by user, so if user tries to allocate memory larger than(>=) MAX_ORDER, then kcalloc() will fail, it creates a stack trace and messes up dmesg with a warning. Add __GFP_NOWARN in order to avoid too large allocation warning. This is detected by static analysis using smatch. Fixes: c3e2fe9222d4 ("scsi: scsi_debug: Implement VERIFY(10), add VERIFY(16)") Signed-off-by: Harshit Mogalapalli Link: https://lore.kernel.org/r/20221112070031.2121068-1-harshit.m.mogalapalli@oracle.com Signed-off-by: Martin K. Petersen --- drivers/scsi/scsi_debug.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/scsi/scsi_debug.c b/drivers/scsi/scsi_debug.c index 273224d29ce9..f556e36a2e0d 100644 --- a/drivers/scsi/scsi_debug.c +++ b/drivers/scsi/scsi_debug.c @@ -4429,7 +4429,7 @@ static int resp_verify(struct scsi_cmnd *scp, struct sdebug_dev_info *devip) if (ret) return ret; - arr = kcalloc(lb_size, vnum, GFP_ATOMIC); + arr = kcalloc(lb_size, vnum, GFP_ATOMIC | __GFP_NOWARN); if (!arr) { mk_sense_buffer(scp, ILLEGAL_REQUEST, INSUFF_RES_ASC, INSUFF_RES_ASCQ); -- cgit v1.2.3 From 07f2ca139d9a7a1ba71c4c03997c8de161db2346 Mon Sep 17 00:00:00 2001 From: Harshit Mogalapalli Date: Fri, 11 Nov 2022 23:06:12 -0800 Subject: scsi: scsi_debug: Fix a warning in resp_report_zones() As 'alloc_len' is user controlled data, if user tries to allocate memory larger than(>=) MAX_ORDER, then kcalloc() will fail, it creates a stack trace and messes up dmesg with a warning. Add __GFP_NOWARN in order to avoid too large allocation warning. This is detected by static analysis using smatch. Fixes: 7db0e0c8190a ("scsi: scsi_debug: Fix buffer size of REPORT ZONES command") Signed-off-by: Harshit Mogalapalli Link: https://lore.kernel.org/r/20221112070612.2121535-1-harshit.m.mogalapalli@oracle.com Signed-off-by: Martin K. Petersen --- drivers/scsi/scsi_debug.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/scsi/scsi_debug.c b/drivers/scsi/scsi_debug.c index f556e36a2e0d..19ad8e2aa07a 100644 --- a/drivers/scsi/scsi_debug.c +++ b/drivers/scsi/scsi_debug.c @@ -4497,7 +4497,7 @@ static int resp_report_zones(struct scsi_cmnd *scp, rep_max_zones = (alloc_len - 64) >> ilog2(RZONES_DESC_HD); - arr = kzalloc(alloc_len, GFP_ATOMIC); + arr = kzalloc(alloc_len, GFP_ATOMIC | __GFP_NOWARN); if (!arr) { mk_sense_buffer(scp, ILLEGAL_REQUEST, INSUFF_RES_ASC, INSUFF_RES_ASCQ); -- cgit v1.2.3 From 47b6a122c7b69a876c7ee2fc064a26b09627de9d Mon Sep 17 00:00:00 2001 From: Yang Yingliang Date: Sat, 12 Nov 2022 17:43:10 +0800 Subject: scsi: fcoe: Fix possible name leak when device_register() fails If device_register() returns an error, the name allocated by dev_set_name() needs to be freed. As the comment of device_register() says, one should use put_device() to give up the reference in the error path. Fix this by calling put_device(), then the name can be freed in kobject_cleanup(). The 'fcf' is freed in fcoe_fcf_device_release(), so the kfree() in the error path can be removed. The 'ctlr' is freed in fcoe_ctlr_device_release(), so don't use the error label, just return NULL after calling put_device(). Fixes: 9a74e884ee71 ("[SCSI] libfcoe: Add fcoe_sysfs") Signed-off-by: Yang Yingliang Link: https://lore.kernel.org/r/20221112094310.3633291-1-yangyingliang@huawei.com Signed-off-by: Martin K. Petersen --- drivers/scsi/fcoe/fcoe_sysfs.c | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-) diff --git a/drivers/scsi/fcoe/fcoe_sysfs.c b/drivers/scsi/fcoe/fcoe_sysfs.c index af658aa38fed..6260aa5ea6af 100644 --- a/drivers/scsi/fcoe/fcoe_sysfs.c +++ b/drivers/scsi/fcoe/fcoe_sysfs.c @@ -830,14 +830,15 @@ struct fcoe_ctlr_device *fcoe_ctlr_device_add(struct device *parent, dev_set_name(&ctlr->dev, "ctlr_%d", ctlr->id); error = device_register(&ctlr->dev); - if (error) - goto out_del_q2; + if (error) { + destroy_workqueue(ctlr->devloss_work_q); + destroy_workqueue(ctlr->work_q); + put_device(&ctlr->dev); + return NULL; + } return ctlr; -out_del_q2: - destroy_workqueue(ctlr->devloss_work_q); - ctlr->devloss_work_q = NULL; out_del_q: destroy_workqueue(ctlr->work_q); ctlr->work_q = NULL; @@ -1036,16 +1037,16 @@ struct fcoe_fcf_device *fcoe_fcf_device_add(struct fcoe_ctlr_device *ctlr, fcf->selected = new_fcf->selected; error = device_register(&fcf->dev); - if (error) - goto out_del; + if (error) { + put_device(&fcf->dev); + goto out; + } fcf->state = FCOE_FCF_STATE_CONNECTED; list_add_tail(&fcf->peers, &ctlr->fcfs); return fcf; -out_del: - kfree(fcf); out: return NULL; } -- cgit v1.2.3 From e6d773f93a49e0eda88a903a2a6542ca83380eb1 Mon Sep 17 00:00:00 2001 From: Yang Yingliang Date: Sat, 12 Nov 2022 21:10:10 +0800 Subject: scsi: scsi_debug: Fix possible name leak in sdebug_add_host_helper() Afer commit 1fa5ae857bb1 ("driver core: get rid of struct device's bus_id string array"), the name of device is allocated dynamically, it needs be freed when device_register() returns error. As comment of device_register() says, one should use put_device() to give up the reference in the error path. Fix this by calling put_device(), then the name can be freed in kobject_cleanup(), and sdbg_host is freed in sdebug_release_adapter(). When the device release is not set, it means the device is not initialized. We can not call put_device() in this case. Use kfree() to free memory. Fixes: 1fa5ae857bb1 ("driver core: get rid of struct device's bus_id string array") Signed-off-by: Yang Yingliang Link: https://lore.kernel.org/r/20221112131010.3757845-1-yangyingliang@huawei.com Signed-off-by: Martin K. Petersen --- drivers/scsi/scsi_debug.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/drivers/scsi/scsi_debug.c b/drivers/scsi/scsi_debug.c index 19ad8e2aa07a..de3d3b1edaf5 100644 --- a/drivers/scsi/scsi_debug.c +++ b/drivers/scsi/scsi_debug.c @@ -7329,7 +7329,10 @@ clean: kfree(sdbg_devinfo->zstate); kfree(sdbg_devinfo); } - kfree(sdbg_host); + if (sdbg_host->dev.release) + put_device(&sdbg_host->dev); + else + kfree(sdbg_host); pr_warn("%s: failed, errno=%d\n", __func__, -error); return error; } -- cgit v1.2.3 From e6f108bffc3708ddcff72324f7d40dfcd0204894 Mon Sep 17 00:00:00 2001 From: Shang XiaoJing Date: Sun, 13 Nov 2022 14:45:13 +0800 Subject: scsi: ipr: Fix WARNING in ipr_init() ipr_init() will not call unregister_reboot_notifier() when pci_register_driver() fails, which causes a WARNING. Call unregister_reboot_notifier() when pci_register_driver() fails. notifier callback ipr_halt [ipr] already registered WARNING: CPU: 3 PID: 299 at kernel/notifier.c:29 notifier_chain_register+0x16d/0x230 Modules linked in: ipr(+) xhci_pci_renesas xhci_hcd ehci_hcd usbcore led_class gpu_sched drm_buddy video wmi drm_ttm_helper ttm drm_display_helper drm_kms_helper drm drm_panel_orientation_quirks agpgart cfbft CPU: 3 PID: 299 Comm: modprobe Tainted: G W 6.1.0-rc1-00190-g39508d23b672-dirty #332 Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIOS rel-1.15.0-0-g2dd4b9b3f840-prebuilt.qemu.org 04/01/2014 RIP: 0010:notifier_chain_register+0x16d/0x230 Call Trace: __blocking_notifier_chain_register+0x73/0xb0 ipr_init+0x30/0x1000 [ipr] do_one_initcall+0xdb/0x480 do_init_module+0x1cf/0x680 load_module+0x6a50/0x70a0 __do_sys_finit_module+0x12f/0x1c0 do_syscall_64+0x3f/0x90 entry_SYSCALL_64_after_hwframe+0x63/0xcd Fixes: f72919ec2bbb ("[SCSI] ipr: implement shutdown changes and remove obsolete write cache parameter") Signed-off-by: Shang XiaoJing Link: https://lore.kernel.org/r/20221113064513.14028-1-shangxiaojing@huawei.com Signed-off-by: Martin K. Petersen --- drivers/scsi/ipr.c | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/drivers/scsi/ipr.c b/drivers/scsi/ipr.c index 9d01a3e3c26a..2022ffb45041 100644 --- a/drivers/scsi/ipr.c +++ b/drivers/scsi/ipr.c @@ -10872,11 +10872,19 @@ static struct notifier_block ipr_notifier = { **/ static int __init ipr_init(void) { + int rc; + ipr_info("IBM Power RAID SCSI Device Driver version: %s %s\n", IPR_DRIVER_VERSION, IPR_DRIVER_DATE); register_reboot_notifier(&ipr_notifier); - return pci_register_driver(&ipr_driver); + rc = pci_register_driver(&ipr_driver); + if (rc) { + unregister_reboot_notifier(&ipr_notifier); + return rc; + } + + return 0; } /** -- cgit v1.2.3 From 42c5907728867df91045f532a38682e0ec7a955b Mon Sep 17 00:00:00 2001 From: Shin'ichiro Kawasaki Date: Tue, 15 Nov 2022 09:29:05 +0900 Subject: scsi: sd: Use 16-byte SYNCHRONIZE CACHE on ZBC devices ZBC Zoned Block Commands specification mandates SYNCHRONIZE CACHE(16) for host-managed zoned block devices, but does not mandate SYNCHRONIZE CACHE(10). Call SYNCHRONIZE CACHE(16) in place of SYNCHRONIZE CACHE(10) to ensure that the command is always supported. For this purpose, add use_16_for_sync flag to struct scsi_device in same manner as use_16_for_rw flag. To be precise, ZBC does not mandate SYNCHRONIZE CACHE(16) for host-aware zoned block devices. However, modern devices should support 16-byte commands. Hence, call SYNCHRONIZE CACHE (16) on both types of ZBC devices, host-aware and host-managed. Of note is that READ(16) and WRITE(16) have same story and they are already called for both types of ZBC devices. Another note is that this patch depends on the fix commit ea045fd344cb ("ata: libata-scsi: fix SYNCHRONIZE CACHE (16) command failure"). Signed-off-by: Shin'ichiro Kawasaki Link: https://lore.kernel.org/r/20221115002905.1709006-1-shinichiro.kawasaki@wdc.com Reviewed-by: Damien Le Moal Signed-off-by: Martin K. Petersen --- drivers/scsi/sd.c | 16 ++++++++++++---- drivers/scsi/sd_zbc.c | 3 ++- include/scsi/scsi_device.h | 1 + 3 files changed, 15 insertions(+), 5 deletions(-) diff --git a/drivers/scsi/sd.c b/drivers/scsi/sd.c index eb76ba055021..faa2b55d1a21 100644 --- a/drivers/scsi/sd.c +++ b/drivers/scsi/sd.c @@ -1026,8 +1026,13 @@ static blk_status_t sd_setup_flush_cmnd(struct scsi_cmnd *cmd) /* flush requests don't perform I/O, zero the S/G table */ memset(&cmd->sdb, 0, sizeof(cmd->sdb)); - cmd->cmnd[0] = SYNCHRONIZE_CACHE; - cmd->cmd_len = 10; + if (cmd->device->use_16_for_sync) { + cmd->cmnd[0] = SYNCHRONIZE_CACHE_16; + cmd->cmd_len = 16; + } else { + cmd->cmnd[0] = SYNCHRONIZE_CACHE; + cmd->cmd_len = 10; + } cmd->transfersize = 0; cmd->allowed = sdkp->max_retries; @@ -1587,9 +1592,12 @@ static int sd_sync_cache(struct scsi_disk *sdkp, struct scsi_sense_hdr *sshdr) sshdr = &my_sshdr; for (retries = 3; retries > 0; --retries) { - unsigned char cmd[10] = { 0 }; + unsigned char cmd[16] = { 0 }; - cmd[0] = SYNCHRONIZE_CACHE; + if (sdp->use_16_for_sync) + cmd[0] = SYNCHRONIZE_CACHE_16; + else + cmd[0] = SYNCHRONIZE_CACHE; /* * Leave the rest of the command zero to indicate * flush everything. diff --git a/drivers/scsi/sd_zbc.c b/drivers/scsi/sd_zbc.c index bd15624c6322..b163bf936acc 100644 --- a/drivers/scsi/sd_zbc.c +++ b/drivers/scsi/sd_zbc.c @@ -921,9 +921,10 @@ int sd_zbc_read_zones(struct scsi_disk *sdkp, u8 buf[SD_BUF_SIZE]) return 0; } - /* READ16/WRITE16 is mandatory for ZBC disks */ + /* READ16/WRITE16/SYNC16 is mandatory for ZBC devices */ sdkp->device->use_16_for_rw = 1; sdkp->device->use_10_for_rw = 0; + sdkp->device->use_16_for_sync = 1; if (!blk_queue_is_zoned(q)) { /* diff --git a/include/scsi/scsi_device.h b/include/scsi/scsi_device.h index 24bdbf7999ab..3642b8e3928b 100644 --- a/include/scsi/scsi_device.h +++ b/include/scsi/scsi_device.h @@ -184,6 +184,7 @@ struct scsi_device { unsigned no_report_opcodes:1; /* no REPORT SUPPORTED OPERATION CODES */ unsigned no_write_same:1; /* no WRITE SAME command */ unsigned use_16_for_rw:1; /* Use read/write(16) over read/write(10) */ + unsigned use_16_for_sync:1; /* Use sync (16) over sync (10) */ unsigned skip_ms_page_8:1; /* do not use MODE SENSE page 0x08 */ unsigned skip_ms_page_3f:1; /* do not use MODE SENSE page 0x3f */ unsigned skip_vpd_pages:1; /* do not read VPD pages */ -- cgit v1.2.3 From 4155658cee394b22b24c6d64e49247bf26d95b92 Mon Sep 17 00:00:00 2001 From: Chen Zhongjin Date: Tue, 15 Nov 2022 17:24:42 +0800 Subject: scsi: fcoe: Fix transport not deattached when fcoe_if_init() fails fcoe_init() calls fcoe_transport_attach(&fcoe_sw_transport), but when fcoe_if_init() fails, &fcoe_sw_transport is not detached and leaves freed &fcoe_sw_transport on fcoe_transports list. This causes panic when reinserting module. BUG: unable to handle page fault for address: fffffbfff82e2213 RIP: 0010:fcoe_transport_attach+0xe1/0x230 [libfcoe] Call Trace: do_one_initcall+0xd0/0x4e0 load_module+0x5eee/0x7210 ... Fixes: 78a582463c1e ("[SCSI] fcoe: convert fcoe.ko to become an fcoe transport provider driver") Signed-off-by: Chen Zhongjin Link: https://lore.kernel.org/r/20221115092442.133088-1-chenzhongjin@huawei.com Signed-off-by: Martin K. Petersen --- drivers/scsi/fcoe/fcoe.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/scsi/fcoe/fcoe.c b/drivers/scsi/fcoe/fcoe.c index 6ec296321ffc..38774a272e62 100644 --- a/drivers/scsi/fcoe/fcoe.c +++ b/drivers/scsi/fcoe/fcoe.c @@ -2491,6 +2491,7 @@ static int __init fcoe_init(void) out_free: mutex_unlock(&fcoe_config_mutex); + fcoe_transport_detach(&fcoe_sw_transport); out_destroy: destroy_workqueue(fcoe_wq); return rc; -- cgit v1.2.3 From 3620e174d260adf88fa6511e8a20831cbddc4b66 Mon Sep 17 00:00:00 2001 From: Gleb Chesnokov Date: Tue, 15 Nov 2022 12:38:05 +0300 Subject: scsi: qla2xxx: Remove duplicate of vha->iocb_work initialization Commit 9b3e0f4d4147 ("scsi: qla2xxx: Move work element processing out of DPC thread") introduced the initialization of vha->iocb_work in qla2x00_create_host() function. This initialization is also called from qla2x00_probe_one() function, just after qla2x00_create_host(). Hence remove this duplicate call since it has already been called before. Signed-off-by: Gleb Chesnokov Link: https://lore.kernel.org/r/822b3823-f344-67d6-30f1-16e31cf68eed@scst.dev Signed-off-by: Martin K. Petersen --- drivers/scsi/qla2xxx/qla_os.c | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/scsi/qla2xxx/qla_os.c b/drivers/scsi/qla2xxx/qla_os.c index 96ba1398f20c..7fb28c207ee5 100644 --- a/drivers/scsi/qla2xxx/qla_os.c +++ b/drivers/scsi/qla2xxx/qla_os.c @@ -3284,7 +3284,6 @@ qla2x00_probe_one(struct pci_dev *pdev, const struct pci_device_id *id) host->max_cmd_len, host->max_channel, host->max_lun, host->transportt, sht->vendor_id); - INIT_WORK(&base_vha->iocb_work, qla2x00_iocb_work_fn); INIT_WORK(&ha->heartbeat_work, qla_heartbeat_work_fn); /* Set up the irqs */ -- cgit v1.2.3 From 95da5e58172cd3c58b82cb01e6cd157b6c5eabe9 Mon Sep 17 00:00:00 2001 From: Gleb Chesnokov Date: Tue, 15 Nov 2022 12:38:08 +0300 Subject: scsi: qla2xxx: Initialize vha->unknown_atio_[list, work] for NPIV hosts Initialization of vha->unknown_atio_list and vha->unknown_atio_work only happens for base_vha in qlt_probe_one_stage1(). But there is no initialization for NPIV hosts that are created in qla24xx_vport_create(). This causes a crash when trying to access these NPIV host fields. Fix this by adding initialization to qla_vport_create(). Signed-off-by: Gleb Chesnokov Link: https://lore.kernel.org/r/376c89a2-a9ac-bcf9-bf0f-dfe89a02fd4b@scst.dev Signed-off-by: Martin K. Petersen --- drivers/scsi/qla2xxx/qla_target.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/scsi/qla2xxx/qla_target.c b/drivers/scsi/qla2xxx/qla_target.c index bb754a950802..548f22705ddc 100644 --- a/drivers/scsi/qla2xxx/qla_target.c +++ b/drivers/scsi/qla2xxx/qla_target.c @@ -6741,6 +6741,9 @@ qlt_vport_create(struct scsi_qla_host *vha, struct qla_hw_data *ha) mutex_init(&vha->vha_tgt.tgt_mutex); mutex_init(&vha->vha_tgt.tgt_host_action_mutex); + INIT_LIST_HEAD(&vha->unknown_atio_list); + INIT_DELAYED_WORK(&vha->unknown_atio_work, qlt_unknown_atio_work_fn); + qlt_clear_mode(vha); /* -- cgit v1.2.3 From e118df492320176af94deec000ae034cc92be754 Mon Sep 17 00:00:00 2001 From: Gaosheng Cui Date: Thu, 17 Nov 2022 11:51:00 +0800 Subject: scsi: snic: Fix possible UAF in snic_tgt_create() Smatch reports a warning as follows: drivers/scsi/snic/snic_disc.c:307 snic_tgt_create() warn: '&tgt->list' not removed from list If device_add() fails in snic_tgt_create(), tgt will be freed, but tgt->list will not be removed from snic->disc.tgt_list, then list traversal may cause UAF. Remove from snic->disc.tgt_list before free(). Fixes: c8806b6c9e82 ("snic: driver for Cisco SCSI HBA") Signed-off-by: Gaosheng Cui Link: https://lore.kernel.org/r/20221117035100.2944812-1-cuigaosheng1@huawei.com Acked-by: Narsimhulu Musini Signed-off-by: Martin K. Petersen --- drivers/scsi/snic/snic_disc.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/scsi/snic/snic_disc.c b/drivers/scsi/snic/snic_disc.c index 9b2b5f8c23b9..8fbf3c1b1311 100644 --- a/drivers/scsi/snic/snic_disc.c +++ b/drivers/scsi/snic/snic_disc.c @@ -304,6 +304,9 @@ snic_tgt_create(struct snic *snic, struct snic_tgt_id *tgtid) ret); put_device(&snic->shost->shost_gendev); + spin_lock_irqsave(snic->shost->host_lock, flags); + list_del(&tgt->list); + spin_unlock_irqrestore(snic->shost->host_lock, flags); kfree(tgt); tgt = NULL; -- cgit v1.2.3 From a500c4cc06cd2830c692b571dd0a1c3585f23150 Mon Sep 17 00:00:00 2001 From: Bart Van Assche Date: Thu, 17 Nov 2022 10:36:25 -0800 Subject: scsi: device_handler: alua: Revert "Move a scsi_device_put() call out of alua_check_vpd()" There is a bug in commit 0b25e17e9018 ("scsi: alua: Move a scsi_device_put() call out of alua_check_vpd()"): that patch may cause alua_rtpg_queue() callers to call scsi_device_put() even if that function should not be called. Revert that commit to prepare for a different solution. Cc: Hannes Reinecke Cc: Martin Wilck Cc: Sachin Sant Cc: Benjamin Block Reported-by: Sachin Sant Reported-by: Benjamin Block Signed-off-by: Bart Van Assche Link: https://lore.kernel.org/r/20221117183626.2656196-2-bvanassche@acm.org Tested-by: Sachin Sant Signed-off-by: Martin K. Petersen --- drivers/scsi/device_handler/scsi_dh_alua.c | 23 ++++++++--------------- 1 file changed, 8 insertions(+), 15 deletions(-) diff --git a/drivers/scsi/device_handler/scsi_dh_alua.c b/drivers/scsi/device_handler/scsi_dh_alua.c index 693cd827e138..bd4ee294f5c7 100644 --- a/drivers/scsi/device_handler/scsi_dh_alua.c +++ b/drivers/scsi/device_handler/scsi_dh_alua.c @@ -324,7 +324,6 @@ static int alua_check_vpd(struct scsi_device *sdev, struct alua_dh_data *h, struct alua_port_group *pg, *old_pg = NULL; bool pg_updated = false; unsigned long flags; - bool put_sdev; group_id = scsi_vpd_tpg_id(sdev, &rel_port); if (group_id < 0) { @@ -374,14 +373,11 @@ static int alua_check_vpd(struct scsi_device *sdev, struct alua_dh_data *h, list_add_rcu(&h->node, &pg->dh_list); spin_unlock_irqrestore(&pg->lock, flags); - put_sdev = alua_rtpg_queue(rcu_dereference_protected(h->pg, + alua_rtpg_queue(rcu_dereference_protected(h->pg, lockdep_is_held(&h->pg_lock)), sdev, NULL, true); spin_unlock(&h->pg_lock); - if (put_sdev) - scsi_device_put(sdev); - if (old_pg) kref_put(&old_pg->kref, release_port_group); @@ -982,10 +978,9 @@ queue_rtpg: * RTPG already has been scheduled. * * Returns true if and only if alua_rtpg_work() will be called asynchronously. - * That function is responsible for calling @qdata->fn(). If this function - * returns true, the caller is responsible for invoking scsi_device_put(@sdev). + * That function is responsible for calling @qdata->fn(). */ -static bool __must_check alua_rtpg_queue(struct alua_port_group *pg, +static bool alua_rtpg_queue(struct alua_port_group *pg, struct scsi_device *sdev, struct alua_queue_data *qdata, bool force) { @@ -1024,6 +1019,8 @@ static bool __must_check alua_rtpg_queue(struct alua_port_group *pg, else kref_put(&pg->kref, release_port_group); } + if (sdev) + scsi_device_put(sdev); return true; } @@ -1130,12 +1127,10 @@ static int alua_activate(struct scsi_device *sdev, rcu_read_unlock(); mutex_unlock(&h->init_mutex); - if (alua_rtpg_queue(pg, sdev, qdata, true)) { - scsi_device_put(sdev); + if (alua_rtpg_queue(pg, sdev, qdata, true)) fn = NULL; - } else { + else err = SCSI_DH_DEV_OFFLINED; - } kref_put(&pg->kref, release_port_group); out: if (fn) @@ -1161,9 +1156,7 @@ static void alua_check(struct scsi_device *sdev, bool force) return; } rcu_read_unlock(); - - if (alua_rtpg_queue(pg, sdev, NULL, force)) - scsi_device_put(sdev); + alua_rtpg_queue(pg, sdev, NULL, force); kref_put(&pg->kref, release_port_group); } -- cgit v1.2.3 From 50759b881e1d6879e7cef15c74bdea2e937338c9 Mon Sep 17 00:00:00 2001 From: Bart Van Assche Date: Thu, 17 Nov 2022 10:36:26 -0800 Subject: scsi: device_handler: alua: Call scsi_device_put() from non-atomic context Since commit f93ed747e2c7 ("scsi: core: Release SCSI devices synchronously"), scsi_device_put() might sleep. Avoid calling it from alua_rtpg_queue() with the pg_lock held. The lock only pretects h->pg, anyway. To avoid the pg being freed under us, because of a race with another thread, take a temporary reference. In alua_rtpg_queue(), verify that the pg still belongs to the sdev being passed before actually queueing the RTPG. This patch fixes the following smatch warning: drivers/scsi/device_handler/scsi_dh_alua.c:1013 alua_rtpg_queue() warn: sleeping in atomic context alua_check_vpd() <- disables preempt -> alua_rtpg_queue() -> scsi_device_put() Cc: Martin Wilck Cc: Hannes Reinecke Cc: Sachin Sant Cc: Benjamin Block Suggested-by: Martin Wilck Reported-by: Dan Carpenter Signed-off-by: Bart Van Assche Link: https://lore.kernel.org/r/20221117183626.2656196-3-bvanassche@acm.org Tested-by: Sachin Sant Signed-off-by: Martin K. Petersen --- drivers/scsi/device_handler/scsi_dh_alua.c | 27 +++++++++++++++++++-------- 1 file changed, 19 insertions(+), 8 deletions(-) diff --git a/drivers/scsi/device_handler/scsi_dh_alua.c b/drivers/scsi/device_handler/scsi_dh_alua.c index bd4ee294f5c7..49cc18a87473 100644 --- a/drivers/scsi/device_handler/scsi_dh_alua.c +++ b/drivers/scsi/device_handler/scsi_dh_alua.c @@ -354,6 +354,8 @@ static int alua_check_vpd(struct scsi_device *sdev, struct alua_dh_data *h, "%s: port group %x rel port %x\n", ALUA_DH_NAME, group_id, rel_port); + kref_get(&pg->kref); + /* Check for existing port group references */ spin_lock(&h->pg_lock); old_pg = rcu_dereference_protected(h->pg, lockdep_is_held(&h->pg_lock)); @@ -373,11 +375,11 @@ static int alua_check_vpd(struct scsi_device *sdev, struct alua_dh_data *h, list_add_rcu(&h->node, &pg->dh_list); spin_unlock_irqrestore(&pg->lock, flags); - alua_rtpg_queue(rcu_dereference_protected(h->pg, - lockdep_is_held(&h->pg_lock)), - sdev, NULL, true); spin_unlock(&h->pg_lock); + alua_rtpg_queue(pg, sdev, NULL, true); + kref_put(&pg->kref, release_port_group); + if (old_pg) kref_put(&old_pg->kref, release_port_group); @@ -986,6 +988,9 @@ static bool alua_rtpg_queue(struct alua_port_group *pg, { int start_queue = 0; unsigned long flags; + + might_sleep(); + if (WARN_ON_ONCE(!pg) || scsi_device_get(sdev)) return false; @@ -996,11 +1001,17 @@ static bool alua_rtpg_queue(struct alua_port_group *pg, force = true; } if (pg->rtpg_sdev == NULL) { - pg->interval = 0; - pg->flags |= ALUA_PG_RUN_RTPG; - kref_get(&pg->kref); - pg->rtpg_sdev = sdev; - start_queue = 1; + struct alua_dh_data *h = sdev->handler_data; + + rcu_read_lock(); + if (h && rcu_dereference(h->pg) == pg) { + pg->interval = 0; + pg->flags |= ALUA_PG_RUN_RTPG; + kref_get(&pg->kref); + pg->rtpg_sdev = sdev; + start_queue = 1; + } + rcu_read_unlock(); } else if (!(pg->flags & ALUA_PG_RUN_RTPG) && force) { pg->flags |= ALUA_PG_RUN_RTPG; /* Do not queue if the worker is already running */ -- cgit v1.2.3 From 541555285339313e831f8e446c03a7994c604d65 Mon Sep 17 00:00:00 2001 From: ChanWoo Lee Date: Fri, 18 Nov 2022 13:41:36 +0900 Subject: scsi: ufs: ufs-mediatek: Remove unneeded code Remove unnecessary if/goto code. Signed-off-by: ChanWoo Lee Link: https://lore.kernel.org/r/20221118044136.921-1-cw9316.lee@samsung.com Reviewed-by: Stanley Chu Reviewed-by: AngeloGioacchino Del Regno Signed-off-by: Martin K. Petersen --- drivers/ufs/host/ufs-mediatek.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/drivers/ufs/host/ufs-mediatek.c b/drivers/ufs/host/ufs-mediatek.c index 7309f3f87eac..7d13878dff47 100644 --- a/drivers/ufs/host/ufs-mediatek.c +++ b/drivers/ufs/host/ufs-mediatek.c @@ -441,8 +441,6 @@ static int ufs_mtk_mphy_power_on(struct ufs_hba *hba, bool on) if (ufs_mtk_is_va09_supported(hba)) { ufs_mtk_va09_pwr_ctrl(res, 0); ret = regulator_disable(host->reg_va09); - if (ret < 0) - goto out; } } out: -- cgit v1.2.3 From 96a2dfa1df4b9df0cfa2e807153b4d254db2fa82 Mon Sep 17 00:00:00 2001 From: ChanWoo Lee Date: Fri, 18 Nov 2022 13:52:42 +0900 Subject: scsi: ufs: ufs-mediatek: Modify the return value Be consistent with the rest of driver wrt. functions returning bool. 91: return !!(host->caps & UFS_MTK_CAP_BOOST_CRYPT_ENGINE); 98: return !!(host->caps & UFS_MTK_CAP_VA09_PWR_CTRL); 105: return !!(host->caps & UFS_MTK_CAP_BROKEN_VCC); Signed-off-by: ChanWoo Lee Link: https://lore.kernel.org/r/20221118045242.2770-1-cw9316.lee@samsung.com Reviewed-by: Stanley Chu Reviewed-by: AngeloGioacchino Del Regno Signed-off-by: Martin K. Petersen --- drivers/ufs/host/ufs-mediatek.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/ufs/host/ufs-mediatek.c b/drivers/ufs/host/ufs-mediatek.c index 7d13878dff47..ef5816d82326 100644 --- a/drivers/ufs/host/ufs-mediatek.c +++ b/drivers/ufs/host/ufs-mediatek.c @@ -109,7 +109,7 @@ static bool ufs_mtk_is_pmc_via_fastauto(struct ufs_hba *hba) { struct ufs_mtk_host *host = ufshcd_get_variant(hba); - return (host->caps & UFS_MTK_CAP_PMC_VIA_FASTAUTO); + return !!(host->caps & UFS_MTK_CAP_PMC_VIA_FASTAUTO); } static void ufs_mtk_cfg_unipro_cg(struct ufs_hba *hba, bool enable) -- cgit v1.2.3 From 7e613be7c63d2b9041b38d51fc324b8ad67d31e3 Mon Sep 17 00:00:00 2001 From: Jie Zhan Date: Fri, 18 Nov 2022 16:37:10 +0800 Subject: scsi: Revert "scsi: hisi_sas: Drain bcast events in hisi_sas_rescan_topology()" This reverts commit 11ff0c98fca35df16c84d4eee52008faecaf10a6. Draining or flushing events in hisi_sas_rescan_topology() can hang the driver, typically with phy up or phy down events being processed, i.e. sas_porte_bytes_dmaed() or sas_phye_loss_of_signal(). Signed-off-by: Jie Zhan Link: https://lore.kernel.org/r/20221118083714.4034612-2-zhanjie9@hisilicon.com Signed-off-by: Martin K. Petersen --- drivers/scsi/hisi_sas/hisi_sas_main.c | 7 ------- 1 file changed, 7 deletions(-) diff --git a/drivers/scsi/hisi_sas/hisi_sas_main.c b/drivers/scsi/hisi_sas/hisi_sas_main.c index 54860d252466..4527ac266bb6 100644 --- a/drivers/scsi/hisi_sas/hisi_sas_main.c +++ b/drivers/scsi/hisi_sas/hisi_sas_main.c @@ -1323,7 +1323,6 @@ static void hisi_sas_refresh_port_id(struct hisi_hba *hisi_hba) static void hisi_sas_rescan_topology(struct hisi_hba *hisi_hba, u32 state) { - struct sas_ha_struct *sas_ha = &hisi_hba->sha; struct asd_sas_port *_sas_port = NULL; int phy_no; @@ -1352,12 +1351,6 @@ static void hisi_sas_rescan_topology(struct hisi_hba *hisi_hba, u32 state) hisi_sas_phy_down(hisi_hba, phy_no, 0, GFP_KERNEL); } } - /* - * Ensure any bcast events are processed prior to calling async nexus - * reset calls from hisi_sas_clear_nexus_ha() -> - * hisi_sas_async_I_T_nexus_reset() - */ - sas_drain_work(sas_ha); } static void hisi_sas_reset_init_all_devices(struct hisi_hba *hisi_hba) -- cgit v1.2.3 From 94a3555d1f0f51cf029a8668624e1cd40628880f Mon Sep 17 00:00:00 2001 From: Jie Zhan Date: Fri, 18 Nov 2022 16:37:11 +0800 Subject: scsi: Revert "scsi: hisi_sas: Don't send bcast events from HW during nexus HA reset" This reverts commit f5f2a2716055ad8c0c4ff83e51d667646c6c5d8a. This is now unnecessary to solve the SATA devices missing issue in hisi_sas_clear_nexus_ha(). Hence, we should not ignore bcast events during sas_eh_handle_sas_errors() in case of missing bcast events, unless a justified need is found and a mechanism to defer (but not ignore) bcast events in sas_eh_handle_sas_errors() is provided. Also, in hisi_sas_clear_nexus_ha(), there is nothing further to handle in "out: " other than return, so that part can be reverted. Signed-off-by: Jie Zhan Link: https://lore.kernel.org/r/20221118083714.4034612-3-zhanjie9@hisilicon.com Reviewed-by: John Garry Signed-off-by: Martin K. Petersen --- drivers/scsi/hisi_sas/hisi_sas_main.c | 16 ++++------------ 1 file changed, 4 insertions(+), 12 deletions(-) diff --git a/drivers/scsi/hisi_sas/hisi_sas_main.c b/drivers/scsi/hisi_sas/hisi_sas_main.c index 4527ac266bb6..62080d0fad6f 100644 --- a/drivers/scsi/hisi_sas/hisi_sas_main.c +++ b/drivers/scsi/hisi_sas/hisi_sas_main.c @@ -1812,14 +1812,12 @@ static int hisi_sas_clear_nexus_ha(struct sas_ha_struct *sas_ha) struct hisi_hba *hisi_hba = sas_ha->lldd_ha; HISI_SAS_DECLARE_RST_WORK_ON_STACK(r); ASYNC_DOMAIN_EXCLUSIVE(async); - int i, ret; + int i; queue_work(hisi_hba->wq, &r.work); wait_for_completion(r.completion); - if (!r.done) { - ret = TMF_RESP_FUNC_FAILED; - goto out; - } + if (!r.done) + return TMF_RESP_FUNC_FAILED; for (i = 0; i < HISI_SAS_MAX_DEVICES; i++) { struct hisi_sas_device *sas_dev = &hisi_hba->devices[i]; @@ -1836,9 +1834,7 @@ static int hisi_sas_clear_nexus_ha(struct sas_ha_struct *sas_ha) async_synchronize_full_domain(&async); hisi_sas_release_tasks(hisi_hba); - ret = TMF_RESP_FUNC_COMPLETE; -out: - return ret; + return TMF_RESP_FUNC_COMPLETE; } static int hisi_sas_query_task(struct sas_task *task) @@ -1986,14 +1982,10 @@ void hisi_sas_phy_bcast(struct hisi_sas_phy *phy) { struct asd_sas_phy *sas_phy = &phy->sas_phy; struct hisi_hba *hisi_hba = phy->hisi_hba; - struct sas_ha_struct *sha = &hisi_hba->sha; if (test_bit(HISI_SAS_RESETTING_BIT, &hisi_hba->flags)) return; - if (test_bit(SAS_HA_FROZEN, &sha->state)) - return; - sas_notify_port_event(sas_phy, PORTE_BROADCAST_RCVD, GFP_ATOMIC); } EXPORT_SYMBOL_GPL(hisi_sas_phy_bcast); -- cgit v1.2.3 From 9181ce3cb5d96f0ee28246a857ca651830fa3746 Mon Sep 17 00:00:00 2001 From: Jie Zhan Date: Fri, 18 Nov 2022 16:37:12 +0800 Subject: scsi: libsas: Add smp_ata_check_ready_type() Create function smp_ata_check_ready_type() for LLDDs to wait for SATA devices to come up after a link reset. Signed-off-by: Jie Zhan Link: https://lore.kernel.org/r/20221118083714.4034612-4-zhanjie9@hisilicon.com Signed-off-by: Martin K. Petersen --- drivers/scsi/libsas/sas_ata.c | 25 +++++++++++++++++++++++++ drivers/scsi/libsas/sas_expander.c | 4 ++-- drivers/scsi/libsas/sas_internal.h | 2 ++ include/scsi/sas_ata.h | 6 ++++++ 4 files changed, 35 insertions(+), 2 deletions(-) diff --git a/drivers/scsi/libsas/sas_ata.c b/drivers/scsi/libsas/sas_ata.c index 78e6046fb55a..4b65cd79150f 100644 --- a/drivers/scsi/libsas/sas_ata.c +++ b/drivers/scsi/libsas/sas_ata.c @@ -287,6 +287,31 @@ static int sas_ata_clear_pending(struct domain_device *dev, struct ex_phy *phy) return 1; } +int smp_ata_check_ready_type(struct ata_link *link) +{ + struct domain_device *dev = link->ap->private_data; + struct sas_phy *phy = sas_get_local_phy(dev); + struct domain_device *ex_dev = dev->parent; + enum sas_device_type type = SAS_PHY_UNUSED; + u8 sas_addr[SAS_ADDR_SIZE]; + int res; + + res = sas_get_phy_attached_dev(ex_dev, phy->number, sas_addr, &type); + sas_put_local_phy(phy); + if (res) + return res; + + switch (type) { + case SAS_SATA_PENDING: + return 0; + case SAS_END_DEVICE: + return 1; + default: + return -ENODEV; + } +} +EXPORT_SYMBOL_GPL(smp_ata_check_ready_type); + static int smp_ata_check_ready(struct ata_link *link) { int res; diff --git a/drivers/scsi/libsas/sas_expander.c b/drivers/scsi/libsas/sas_expander.c index 2907ca5d0ed4..a04cad620e93 100644 --- a/drivers/scsi/libsas/sas_expander.c +++ b/drivers/scsi/libsas/sas_expander.c @@ -1688,8 +1688,8 @@ static int sas_get_phy_change_count(struct domain_device *dev, return res; } -static int sas_get_phy_attached_dev(struct domain_device *dev, int phy_id, - u8 *sas_addr, enum sas_device_type *type) +int sas_get_phy_attached_dev(struct domain_device *dev, int phy_id, + u8 *sas_addr, enum sas_device_type *type) { int res; struct smp_disc_resp *disc_resp; diff --git a/drivers/scsi/libsas/sas_internal.h b/drivers/scsi/libsas/sas_internal.h index 6cf190ade35e..6f593fa69b58 100644 --- a/drivers/scsi/libsas/sas_internal.h +++ b/drivers/scsi/libsas/sas_internal.h @@ -88,6 +88,8 @@ struct domain_device *sas_ex_to_ata(struct domain_device *ex_dev, int phy_id); int sas_ex_phy_discover(struct domain_device *dev, int single); int sas_get_report_phy_sata(struct domain_device *dev, int phy_id, struct smp_rps_resp *rps_resp); +int sas_get_phy_attached_dev(struct domain_device *dev, int phy_id, + u8 *sas_addr, enum sas_device_type *type); int sas_try_ata_reset(struct asd_sas_phy *phy); void sas_hae_reset(struct work_struct *work); diff --git a/include/scsi/sas_ata.h b/include/scsi/sas_ata.h index e47f0aec0722..e7d466df8157 100644 --- a/include/scsi/sas_ata.h +++ b/include/scsi/sas_ata.h @@ -36,6 +36,7 @@ void sas_ata_device_link_abort(struct domain_device *dev, bool force_reset); int sas_execute_ata_cmd(struct domain_device *device, u8 *fis, int force_phy_id); int sas_ata_wait_after_reset(struct domain_device *dev, unsigned long deadline); +int smp_ata_check_ready_type(struct ata_link *link); #else @@ -104,6 +105,11 @@ static inline int sas_ata_wait_after_reset(struct domain_device *dev, { return -ETIMEDOUT; } + +static inline int smp_ata_check_ready_type(struct ata_link *link) +{ + return 0; +} #endif #endif /* _SAS_ATA_H_ */ -- cgit v1.2.3 From 3c2673a09cf1181318c07b7dbc1bc532ba3d33e3 Mon Sep 17 00:00:00 2001 From: Jie Zhan Date: Fri, 18 Nov 2022 16:37:13 +0800 Subject: scsi: hisi_sas: Fix SATA devices missing issue during I_T nexus reset SATA devices on an expander may be removed and not be found again when I_T nexus reset and revalidation are processed simultaneously. The issue comes from: - Revalidation can remove SATA devices in link reset, e.g. in hisi_sas_clear_nexus_ha(). - However, hisi_sas_debug_I_T_nexus_reset() polls the state of a SATA device on an expander after sending link_reset, where it calls: hisi_sas_debug_I_T_nexus_reset sas_ata_wait_after_reset ata_wait_after_reset ata_wait_ready smp_ata_check_ready sas_ex_phy_discover sas_ex_phy_discover_helper sas_set_ex_phy The ex_phy's change count is updated in sas_set_ex_phy(), so SATA devices after a link reset may not be found later through revalidation. A similar issue was reported in: commit 0f3fce5cc77e ("[SCSI] libsas: fix ata_eh clobbering ex_phys via smp_ata_check_ready") commit 87c8331fcf72 ("[SCSI] libsas: prevent domain rediscovery competing with ata error handling"). To address this issue, in hisi_sas_debug_I_T_nexus_reset(), we now call smp_ata_check_ready_type() that only polls the device type while not updating the ex_phy's data of libsas. Fixes: 71453bd9d1bf ("scsi: hisi_sas: Use sas_ata_wait_after_reset() in IT nexus reset") Signed-off-by: Jie Zhan Link: https://lore.kernel.org/r/20221118083714.4034612-5-zhanjie9@hisilicon.com Signed-off-by: Martin K. Petersen --- drivers/scsi/hisi_sas/hisi_sas_main.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/drivers/scsi/hisi_sas/hisi_sas_main.c b/drivers/scsi/hisi_sas/hisi_sas_main.c index 62080d0fad6f..41ba22f6c7f0 100644 --- a/drivers/scsi/hisi_sas/hisi_sas_main.c +++ b/drivers/scsi/hisi_sas/hisi_sas_main.c @@ -1694,13 +1694,15 @@ static int hisi_sas_debug_I_T_nexus_reset(struct domain_device *device) return rc; } + /* Remote phy */ if (rc) return rc; - /* Remote phy */ if (dev_is_sata(device)) { - rc = sas_ata_wait_after_reset(device, - HISI_SAS_WAIT_PHYUP_TIMEOUT); + struct ata_link *link = &device->sata_dev.ap->link; + + rc = ata_wait_after_reset(link, HISI_SAS_WAIT_PHYUP_TIMEOUT, + smp_ata_check_ready_type); } else { msleep(2000); } -- cgit v1.2.3 From 4d450cf2b00d34b53f52d93216dd23af57bdca73 Mon Sep 17 00:00:00 2001 From: Jie Zhan Date: Fri, 18 Nov 2022 16:37:14 +0800 Subject: scsi: libsas: Do not export sas_ata_wait_after_reset() sas_ata_wait_after_reset() does not need to be exported since it is no longer referenced outside libsas. Signed-off-by: Jie Zhan Link: https://lore.kernel.org/r/20221118083714.4034612-6-zhanjie9@hisilicon.com Reviewed-by: John Garry Signed-off-by: Martin K. Petersen --- drivers/scsi/libsas/sas_ata.c | 3 +-- include/scsi/sas_ata.h | 7 ------- 2 files changed, 1 insertion(+), 9 deletions(-) diff --git a/drivers/scsi/libsas/sas_ata.c b/drivers/scsi/libsas/sas_ata.c index 4b65cd79150f..f7439bf9cdc6 100644 --- a/drivers/scsi/libsas/sas_ata.c +++ b/drivers/scsi/libsas/sas_ata.c @@ -383,7 +383,7 @@ static int sas_ata_printk(const char *level, const struct domain_device *ddev, return r; } -int sas_ata_wait_after_reset(struct domain_device *dev, unsigned long deadline) +static int sas_ata_wait_after_reset(struct domain_device *dev, unsigned long deadline) { struct sata_device *sata_dev = &dev->sata_dev; int (*check_ready)(struct ata_link *link); @@ -405,7 +405,6 @@ int sas_ata_wait_after_reset(struct domain_device *dev, unsigned long deadline) return ret; } -EXPORT_SYMBOL_GPL(sas_ata_wait_after_reset); static int sas_ata_hard_reset(struct ata_link *link, unsigned int *class, unsigned long deadline) diff --git a/include/scsi/sas_ata.h b/include/scsi/sas_ata.h index e7d466df8157..9c927d46f136 100644 --- a/include/scsi/sas_ata.h +++ b/include/scsi/sas_ata.h @@ -35,7 +35,6 @@ void sas_ata_end_eh(struct ata_port *ap); void sas_ata_device_link_abort(struct domain_device *dev, bool force_reset); int sas_execute_ata_cmd(struct domain_device *device, u8 *fis, int force_phy_id); -int sas_ata_wait_after_reset(struct domain_device *dev, unsigned long deadline); int smp_ata_check_ready_type(struct ata_link *link); #else @@ -100,12 +99,6 @@ static inline int sas_execute_ata_cmd(struct domain_device *device, u8 *fis, return 0; } -static inline int sas_ata_wait_after_reset(struct domain_device *dev, - unsigned long deadline) -{ - return -ETIMEDOUT; -} - static inline int smp_ata_check_ready_type(struct ata_link *link) { return 0; -- cgit v1.2.3 From ee8c88cab4afbd5ee10a127d6cbecd6b200185a5 Mon Sep 17 00:00:00 2001 From: Bart Van Assche Date: Fri, 18 Nov 2022 15:37:03 -0800 Subject: scsi: ufs: core: Fix the polling implementation Fix the following issues in ufshcd_poll(): - If polling succeeds, return a positive value. - Do not complete polling requests from interrupt context because the block layer expects these requests to be completed from thread context. From block/bio.c: If REQ_ALLOC_CACHE is set, the final put of the bio MUST be done from process context, not hard/soft IRQ. Fixes: eaab9b573054 ("scsi: ufs: Implement polling support") Signed-off-by: Bart Van Assche Link: https://lore.kernel.org/r/20221118233717.441298-1-bvanassche@acm.org Reviewed-by: Adrian Hunter Signed-off-by: Martin K. Petersen --- drivers/ufs/core/ufshcd.c | 28 ++++++++++++++++++++++++++-- 1 file changed, 26 insertions(+), 2 deletions(-) diff --git a/drivers/ufs/core/ufshcd.c b/drivers/ufs/core/ufshcd.c index 0e8850869b21..2dbe24977822 100644 --- a/drivers/ufs/core/ufshcd.c +++ b/drivers/ufs/core/ufshcd.c @@ -5344,6 +5344,26 @@ static void __ufshcd_transfer_req_compl(struct ufs_hba *hba, } } +/* Any value that is not an existing queue number is fine for this constant. */ +enum { + UFSHCD_POLL_FROM_INTERRUPT_CONTEXT = -1 +}; + +static void ufshcd_clear_polled(struct ufs_hba *hba, + unsigned long *completed_reqs) +{ + int tag; + + for_each_set_bit(tag, completed_reqs, hba->nutrs) { + struct scsi_cmnd *cmd = hba->lrb[tag].cmd; + + if (!cmd) + continue; + if (scsi_cmd_to_rq(cmd)->cmd_flags & REQ_POLLED) + __clear_bit(tag, completed_reqs); + } +} + /* * Returns > 0 if one or more commands have been completed or 0 if no * requests have been completed. @@ -5360,13 +5380,17 @@ static int ufshcd_poll(struct Scsi_Host *shost, unsigned int queue_num) WARN_ONCE(completed_reqs & ~hba->outstanding_reqs, "completed: %#lx; outstanding: %#lx\n", completed_reqs, hba->outstanding_reqs); + if (queue_num == UFSHCD_POLL_FROM_INTERRUPT_CONTEXT) { + /* Do not complete polled requests from interrupt context. */ + ufshcd_clear_polled(hba, &completed_reqs); + } hba->outstanding_reqs &= ~completed_reqs; spin_unlock_irqrestore(&hba->outstanding_lock, flags); if (completed_reqs) __ufshcd_transfer_req_compl(hba, completed_reqs); - return completed_reqs; + return completed_reqs != 0; } /** @@ -5397,7 +5421,7 @@ static irqreturn_t ufshcd_transfer_req_compl(struct ufs_hba *hba) * Ignore the ufshcd_poll() return value and return IRQ_HANDLED since we * do not want polling to trigger spurious interrupt complaints. */ - ufshcd_poll(hba->host, 0); + ufshcd_poll(hba->host, UFSHCD_POLL_FROM_INTERRUPT_CONTEXT); return IRQ_HANDLED; } -- cgit v1.2.3 From d29c32efebf3f10b25e9f88ac75c962e7259412d Mon Sep 17 00:00:00 2001 From: ChanWoo Lee Date: Mon, 21 Nov 2022 09:33:38 +0900 Subject: scsi: ufs: ufs-mediatek: Remove unnecessary return code Modify to remove unnecessary 'return 0' code. Signed-off-by: ChanWoo Lee Link: https://lore.kernel.org/r/20221121003338.11034-1-cw9316.lee@samsung.com Reviewed-by: Bart Van Assche Signed-off-by: Martin K. Petersen --- drivers/ufs/host/ufs-mediatek.c | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) diff --git a/drivers/ufs/host/ufs-mediatek.c b/drivers/ufs/host/ufs-mediatek.c index ef5816d82326..21d9b047539f 100644 --- a/drivers/ufs/host/ufs-mediatek.c +++ b/drivers/ufs/host/ufs-mediatek.c @@ -1095,7 +1095,7 @@ static void ufs_mtk_setup_clk_gating(struct ufs_hba *hba) } } -static int ufs_mtk_post_link(struct ufs_hba *hba) +static void ufs_mtk_post_link(struct ufs_hba *hba) { /* enable unipro clock gating feature */ ufs_mtk_cfg_unipro_cg(hba, true); @@ -1106,8 +1106,6 @@ static int ufs_mtk_post_link(struct ufs_hba *hba) FIELD_PREP(UFSHCI_AHIBERN8_SCALE_MASK, 3); ufs_mtk_setup_clk_gating(hba); - - return 0; } static int ufs_mtk_link_startup_notify(struct ufs_hba *hba, @@ -1120,7 +1118,7 @@ static int ufs_mtk_link_startup_notify(struct ufs_hba *hba, ret = ufs_mtk_pre_link(hba); break; case POST_CHANGE: - ret = ufs_mtk_post_link(hba); + ufs_mtk_post_link(hba); break; default: ret = -EINVAL; @@ -1272,9 +1270,8 @@ static int ufs_mtk_suspend(struct ufs_hba *hba, enum ufs_pm_op pm_op, struct arm_smccc_res res; if (status == PRE_CHANGE) { - if (!ufshcd_is_auto_hibern8_supported(hba)) - return 0; - ufs_mtk_auto_hibern8_disable(hba); + if (ufshcd_is_auto_hibern8_supported(hba)) + ufs_mtk_auto_hibern8_disable(hba); return 0; } -- cgit v1.2.3 From 35bd6f9fd33b8beb043aea0db51b726ca6edfd87 Mon Sep 17 00:00:00 2001 From: John Garry Date: Mon, 21 Nov 2022 12:17:24 +0000 Subject: scsi: core: Use SCSI_SCAN_RESCAN in __scsi_add_device() Instead of using hardcoded '1' as the __scsi_add_device() -> scsi_probe_and_add_lun() rescan arg, use proper macro SCSI_SCAN_RESCAN. Signed-off-by: John Garry Link: https://lore.kernel.org/r/20221121121725.1910795-2-john.g.garry@oracle.com Reviewed-by: Damien Le Moal Reviewed-by: Jason Yan Signed-off-by: Martin K. Petersen --- drivers/scsi/scsi_scan.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/scsi/scsi_scan.c b/drivers/scsi/scsi_scan.c index 5d27f5196de6..6cc974b382c1 100644 --- a/drivers/scsi/scsi_scan.c +++ b/drivers/scsi/scsi_scan.c @@ -1580,7 +1580,8 @@ struct scsi_device *__scsi_add_device(struct Scsi_Host *shost, uint channel, scsi_complete_async_scans(); if (scsi_host_scan_allowed(shost) && scsi_autopm_get_host(shost) == 0) { - scsi_probe_and_add_lun(starget, lun, NULL, &sdev, 1, hostdata); + scsi_probe_and_add_lun(starget, lun, NULL, &sdev, + SCSI_SCAN_RESCAN, hostdata); scsi_autopm_put_host(shost); } mutex_unlock(&shost->scan_mutex); -- cgit v1.2.3 From 425b27a04dd8b2f5abaf8023166071b8342dc079 Mon Sep 17 00:00:00 2001 From: John Garry Date: Mon, 21 Nov 2022 12:17:25 +0000 Subject: scsi: core: Use SCSI_SCAN_INITIAL in do_scsi_scan_host() Instead of using hardcoded '0' as the do_scsi_scan_host() -> scsi_scan_host_selected() rescan arg, use proper macro SCSI_SCAN_INITIAL. Signed-off-by: John Garry Link: https://lore.kernel.org/r/20221121121725.1910795-3-john.g.garry@oracle.com Reviewed-by: Damien Le Moal Reviewed-by: Jason Yan Reviewed-by: Bart Van Assche Signed-off-by: Martin K. Petersen --- drivers/scsi/scsi_scan.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/scsi/scsi_scan.c b/drivers/scsi/scsi_scan.c index 6cc974b382c1..920b145f80b7 100644 --- a/drivers/scsi/scsi_scan.c +++ b/drivers/scsi/scsi_scan.c @@ -1920,7 +1920,7 @@ static void do_scsi_scan_host(struct Scsi_Host *shost) msleep(10); } else { scsi_scan_host_selected(shost, SCAN_WILD_CARD, SCAN_WILD_CARD, - SCAN_WILD_CARD, 0); + SCAN_WILD_CARD, SCSI_SCAN_INITIAL); } } -- cgit v1.2.3 From 76dc609556c699676776d53222d342276afd0442 Mon Sep 17 00:00:00 2001 From: Yu Zhe Date: Fri, 25 Nov 2022 10:07:03 +0800 Subject: scsi: megaraid_sas: Fix some spelling mistakes in comment Fix typos in comment. Reviewed-by: Randy Dunlap Signed-off-by: Yu Zhe Link: https://lore.kernel.org/r/20221125020703.22216-1-yuzhe@nfschina.com Signed-off-by: Martin K. Petersen --- drivers/scsi/megaraid/megaraid_sas_fusion.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/scsi/megaraid/megaraid_sas_fusion.c b/drivers/scsi/megaraid/megaraid_sas_fusion.c index 6650f8c8e9b0..fe70f8f11435 100644 --- a/drivers/scsi/megaraid/megaraid_sas_fusion.c +++ b/drivers/scsi/megaraid/megaraid_sas_fusion.c @@ -80,7 +80,7 @@ static void megasas_fusion_crash_dump(struct megasas_instance *instance); * @ocr_context: If called from OCR context this will * be set to 1, else 0 * - * This function initates a chip reset followed by a wait for controller to + * This function initiates a chip reset followed by a wait for controller to * transition to ready state. * During this, driver will block all access to PCI config space from userspace */ @@ -334,7 +334,7 @@ megasas_fire_cmd_fusion(struct megasas_instance *instance, * * This function is only for fusion controllers. * Update host can queue, if firmware downgrade max supported firmware commands. - * Firmware upgrade case will be skiped because underlying firmware has + * Firmware upgrade case will be skipped because underlying firmware has * more resource than exposed to the OS. * */ @@ -2588,7 +2588,7 @@ static void megasas_stream_detect(struct megasas_instance *instance, if ((io_info->ldStartBlock != current_sd->next_seq_lba) && ((!io_info->isRead) || (!is_read_ahead))) /* - * Once the API availible we need to change this. + * Once the API is available we need to change this. * At this point we are not allowing any gap */ continue; @@ -4650,7 +4650,7 @@ megasas_issue_tm(struct megasas_instance *instance, u16 device_handle, } /* - * megasas_fusion_smid_lookup : Look for fusion command correpspodning to SCSI + * megasas_fusion_smid_lookup : Look for fusion command corresponding to SCSI * @instance: per adapter struct * * Return Non Zero index, if SMID found in outstanding commands -- cgit v1.2.3 From 4e80eef45ad775a54fb06a66bf8267a154781ce5 Mon Sep 17 00:00:00 2001 From: "Kirill A. Shutemov" Date: Fri, 18 Nov 2022 02:23:04 +0300 Subject: scsi: sg: Fix get_user() in call sg_scsi_ioctl() get_user() expects the pointer to be pointer-to-simple-variable type, but sic->data is array of 'unsigned char'. It violates get_user() contracts. Explicitly take pointer to the first element of the array. It matches current behaviour. This is preparation for fixing sparse warnings caused by Linear Address Masking patchset. Signed-off-by: Kirill A. Shutemov Link: https://lore.kernel.org/r/20221117232304.1544-1-kirill.shutemov@linux.intel.com Cc: "James E.J. Bottomley" Cc: "Martin K. Petersen" Signed-off-by: Martin K. Petersen --- drivers/scsi/scsi_ioctl.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/scsi/scsi_ioctl.c b/drivers/scsi/scsi_ioctl.c index 2d20da55fb64..fdd47565a311 100644 --- a/drivers/scsi/scsi_ioctl.c +++ b/drivers/scsi/scsi_ioctl.c @@ -519,7 +519,7 @@ static int sg_scsi_ioctl(struct request_queue *q, fmode_t mode, return -EFAULT; if (in_len > PAGE_SIZE || out_len > PAGE_SIZE) return -EINVAL; - if (get_user(opcode, sic->data)) + if (get_user(opcode, &sic->data[0])) return -EFAULT; bytes = max(in_len, out_len); -- cgit v1.2.3