From 9307a998cb9846a2557fdca286997430bee36a2a Mon Sep 17 00:00:00 2001 From: Peter Wang Date: Fri, 28 Jun 2024 15:00:29 +0800 Subject: [PATCH 1/3] scsi: ufs: core: Fix ufshcd_clear_cmd racing issue When ufshcd_clear_cmd is racing with the completion ISR, the completed tag of the request's mq_hctx pointer will be set to NULL by the ISR. And ufshcd_clear_cmd's call to ufshcd_mcq_req_to_hwq will get NULL pointer KE. Return success when the request is completed by ISR because sq does not need cleanup. The racing flow is: Thread A ufshcd_err_handler step 1 ufshcd_try_to_abort_task ufshcd_cmd_inflight(true) step 3 ufshcd_clear_cmd ... ufshcd_mcq_req_to_hwq blk_mq_unique_tag rq->mq_hctx->queue_num step 5 Thread B ufs_mtk_mcq_intr(cq complete ISR) step 2 scsi_done ... __blk_mq_free_request rq->mq_hctx = NULL; step 4 Below is KE back trace: ufshcd_try_to_abort_task: cmd pending in the device. tag = 6 Unable to handle kernel NULL pointer dereference at virtual address 0000000000000194 pc : [0xffffffd589679bf8] blk_mq_unique_tag+0x8/0x14 lr : [0xffffffd5862f95b4] ufshcd_mcq_sq_cleanup+0x6c/0x1cc [ufs_mediatek_mod_ise] Workqueue: ufs_eh_wq_0 ufshcd_err_handler [ufs_mediatek_mod_ise] Call trace: dump_backtrace+0xf8/0x148 show_stack+0x18/0x24 dump_stack_lvl+0x60/0x7c dump_stack+0x18/0x3c mrdump_common_die+0x24c/0x398 [mrdump] ipanic_die+0x20/0x34 [mrdump] notify_die+0x80/0xd8 die+0x94/0x2b8 __do_kernel_fault+0x264/0x298 do_page_fault+0xa4/0x4b8 do_translation_fault+0x38/0x54 do_mem_abort+0x58/0x118 el1_abort+0x3c/0x5c el1h_64_sync_handler+0x54/0x90 el1h_64_sync+0x68/0x6c blk_mq_unique_tag+0x8/0x14 ufshcd_clear_cmd+0x34/0x118 [ufs_mediatek_mod_ise] ufshcd_try_to_abort_task+0x2c8/0x5b4 [ufs_mediatek_mod_ise] ufshcd_err_handler+0xa7c/0xfa8 [ufs_mediatek_mod_ise] process_one_work+0x208/0x4fc worker_thread+0x228/0x438 kthread+0x104/0x1d4 ret_from_fork+0x10/0x20 Fixes: 8d7290348992 ("scsi: ufs: mcq: Add supporting functions for MCQ abort") Suggested-by: Bart Van Assche Signed-off-by: Peter Wang Link: https://lore.kernel.org/r/20240628070030.30929-2-peter.wang@mediatek.com Reviewed-by: Bart Van Assche Signed-off-by: Martin K. Petersen --- drivers/ufs/core/ufs-mcq.c | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/drivers/ufs/core/ufs-mcq.c b/drivers/ufs/core/ufs-mcq.c index 8944548c30fa..c532416aec22 100644 --- a/drivers/ufs/core/ufs-mcq.c +++ b/drivers/ufs/core/ufs-mcq.c @@ -105,16 +105,15 @@ EXPORT_SYMBOL_GPL(ufshcd_mcq_config_mac); * @hba: per adapter instance * @req: pointer to the request to be issued * - * Return: the hardware queue instance on which the request would - * be queued. + * Return: the hardware queue instance on which the request will be or has + * been queued. %NULL if the request has already been freed. */ struct ufs_hw_queue *ufshcd_mcq_req_to_hwq(struct ufs_hba *hba, struct request *req) { - u32 utag = blk_mq_unique_tag(req); - u32 hwq = blk_mq_unique_tag_to_hwq(utag); + struct blk_mq_hw_ctx *hctx = READ_ONCE(req->mq_hctx); - return &hba->uhq[hwq]; + return hctx ? &hba->uhq[hctx->queue_num] : NULL; } /** @@ -515,6 +514,8 @@ int ufshcd_mcq_sq_cleanup(struct ufs_hba *hba, int task_tag) if (!cmd) return -EINVAL; hwq = ufshcd_mcq_req_to_hwq(hba, scsi_cmd_to_rq(cmd)); + if (!hwq) + return 0; } else { hwq = hba->dev_cmd_queue; } From 74736103fb4123c71bf11fb7a6abe7c884c5269e Mon Sep 17 00:00:00 2001 From: Peter Wang Date: Fri, 28 Jun 2024 15:00:30 +0800 Subject: [PATCH 2/3] scsi: ufs: core: Fix ufshcd_abort_one racing issue When ufshcd_abort_one is racing with the completion ISR, the completed tag of the request's mq_hctx pointer will be set to NULL by ISR. Return success when request is completed by ISR because ufshcd_abort_one does not need to do anything. The racing flow is: Thread A ufshcd_err_handler step 1 ... ufshcd_abort_one ufshcd_try_to_abort_task ufshcd_cmd_inflight(true) step 3 ufshcd_mcq_req_to_hwq blk_mq_unique_tag rq->mq_hctx->queue_num step 5 Thread B ufs_mtk_mcq_intr(cq complete ISR) step 2 scsi_done ... __blk_mq_free_request rq->mq_hctx = NULL; step 4 Below is KE back trace. ufshcd_try_to_abort_task: cmd at tag 41 not pending in the device. ufshcd_try_to_abort_task: cmd at tag=41 is cleared. Aborting tag 41 / CDB 0x28 succeeded Unable to handle kernel NULL pointer dereference at virtual address 0000000000000194 pc : [0xffffffddd7a79bf8] blk_mq_unique_tag+0x8/0x14 lr : [0xffffffddd6155b84] ufshcd_mcq_req_to_hwq+0x1c/0x40 [ufs_mediatek_mod_ise] do_mem_abort+0x58/0x118 el1_abort+0x3c/0x5c el1h_64_sync_handler+0x54/0x90 el1h_64_sync+0x68/0x6c blk_mq_unique_tag+0x8/0x14 ufshcd_err_handler+0xae4/0xfa8 [ufs_mediatek_mod_ise] process_one_work+0x208/0x4fc worker_thread+0x228/0x438 kthread+0x104/0x1d4 ret_from_fork+0x10/0x20 Fixes: 93e6c0e19d5b ("scsi: ufs: core: Clear cmd if abort succeeds in MCQ mode") Suggested-by: Bart Van Assche Signed-off-by: Peter Wang Link: https://lore.kernel.org/r/20240628070030.30929-3-peter.wang@mediatek.com Reviewed-by: Bart Van Assche Signed-off-by: Martin K. Petersen --- drivers/ufs/core/ufshcd.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/ufs/core/ufshcd.c b/drivers/ufs/core/ufshcd.c index 1b65e6ae4137..46433ecf0c4d 100644 --- a/drivers/ufs/core/ufshcd.c +++ b/drivers/ufs/core/ufshcd.c @@ -6456,6 +6456,8 @@ static bool ufshcd_abort_one(struct request *rq, void *priv) /* Release cmd in MCQ mode if abort succeeds */ if (is_mcq_enabled(hba) && (*ret == 0)) { hwq = ufshcd_mcq_req_to_hwq(hba, scsi_cmd_to_rq(lrbp->cmd)); + if (!hwq) + return 0; spin_lock_irqsave(&hwq->cq_lock, flags); if (ufshcd_cmd_inflight(lrbp->cmd)) ufshcd_release_scsi_cmd(hba, lrbp); From 7a6bbc2829d4ab592c7e440a6f6f5deb3cd95db4 Mon Sep 17 00:00:00 2001 From: Damien Le Moal Date: Tue, 2 Jul 2024 06:53:26 +0900 Subject: [PATCH 3/3] scsi: sd: Do not repeat the starting disk message The SCSI disk message "Starting disk" to signal resuming of a suspended disk is printed in both sd_resume() and sd_resume_common() which results in this message being printed twice when resuming from e.g. autosuspend: $ echo 5000 > /sys/block/sda/device/power/autosuspend_delay_ms $ echo auto > /sys/block/sda/device/power/control [ 4962.438293] sd 0:0:0:0: [sda] Synchronizing SCSI cache [ 4962.501121] sd 0:0:0:0: [sda] Stopping disk $ echo on > /sys/block/sda/device/power/control [ 4972.805851] sd 0:0:0:0: [sda] Starting disk [ 4980.558806] sd 0:0:0:0: [sda] Starting disk Fix this double print by removing the call to sd_printk() from sd_resume() and moving the call to sd_printk() in sd_resume_common() earlier in the function, before the check using sd_do_start_stop(). Doing so, the message is printed once regardless if sd_resume_common() actually executes sd_start_stop_device() (i.e. SCSI device case) or not (libsas and libata managed ATA devices case). Fixes: 0c76106cb975 ("scsi: sd: Fix TCG OPAL unlock on system resume") Cc: stable@vger.kernel.org Signed-off-by: Damien Le Moal Link: https://lore.kernel.org/r/20240701215326.128067-1-dlemoal@kernel.org Reviewed-by: Bart Van Assche Reviewed-by: John Garry Signed-off-by: Martin K. Petersen --- drivers/scsi/sd.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/drivers/scsi/sd.c b/drivers/scsi/sd.c index fe82baa924f8..6203915945a4 100644 --- a/drivers/scsi/sd.c +++ b/drivers/scsi/sd.c @@ -4117,8 +4117,6 @@ static int sd_resume(struct device *dev) { struct scsi_disk *sdkp = dev_get_drvdata(dev); - sd_printk(KERN_NOTICE, sdkp, "Starting disk\n"); - if (opal_unlock_from_suspend(sdkp->opal_dev)) { sd_printk(KERN_NOTICE, sdkp, "OPAL unlock failed\n"); return -EIO; @@ -4135,12 +4133,13 @@ static int sd_resume_common(struct device *dev, bool runtime) if (!sdkp) /* E.g.: runtime resume at the start of sd_probe() */ return 0; + sd_printk(KERN_NOTICE, sdkp, "Starting disk\n"); + if (!sd_do_start_stop(sdkp->device, runtime)) { sdkp->suspended = false; return 0; } - sd_printk(KERN_NOTICE, sdkp, "Starting disk\n"); ret = sd_start_stop_device(sdkp, 1); if (!ret) { sd_resume(dev);