[PATCH v7 1/2] scsi: ufs: core: skip ABORT TASK for device management commands
From: Kiwoong Kim
Date: Thu Nov 05 2026 - 23:14:16 EST
In MCQ mode, ufshcd_mcq_abort() falls through to ufshcd_try_to_abort_task()
for all timed-out commands. However, device management commands
(query, NOP) use reserved requests and are not SCSI I/O commands.
The ABORT TASK task management function is designed for SCSI I/O UPIUs
and is not applicable to device management UPIUs.
This is only reachable since device management commands were converted to
scsi_get_internal_cmd(); before that, a timed-out query was handled by
ufshcd_wait_for_dev_cmd() -> ufshcd_clear_cmd() and never reached
ufshcd_try_to_abort_task().
Fix this by checking ufshcd_is_scsi_cmd() in ufshcd_try_to_abort_task().
For a reserved (device management) command, skip the TM path and call
ufshcd_clear_cmd() directly. ufshcd_abort() now calls
ufshcd_try_to_abort_task() for every request,
so its separate reserved-request branch is removed.
Fixes: 08b12cda6c44 ("scsi: ufs: core: Switch to scsi_get_internal_cmd()")
Reported-by: Bart Van Assche <bvanassche@xxxxxxx>
Closes: https://lore.kernel.org/r/8446dc27-9518-4b0c-b9e9-116458210616@xxxxxxx
Signed-off-by: Kiwoong Kim <kwmad.kim@xxxxxxxxxxx>
Reviewed-by: Bean Huo <beanhuo@xxxxxxxxxx>
---
drivers/ufs/core/ufshcd.c | 23 ++++++++++++++---------
1 file changed, 14 insertions(+), 9 deletions(-)
diff --git a/drivers/ufs/core/ufshcd.c b/drivers/ufs/core/ufshcd.c
index bcc2512bf34b..b9aa0b692fa5 100644
--- a/drivers/ufs/core/ufshcd.c
+++ b/drivers/ufs/core/ufshcd.c
@@ -8025,11 +8025,15 @@ static void ufshcd_set_req_abort_skip(struct ufs_hba *hba, unsigned long bitmap)
* @hba: Pointer to adapter instance
* @tag: Tag of the task to be aborted
*
- * Abort the pending command in device by sending UFS_ABORT_TASK task management
- * command, and in host controller by clearing the door-bell register. There can
- * be race between controller sending the command to the device while abort is
- * issued. To avoid that, first issue UFS_QUERY_TASK to check if the command is
- * really issued and then try to abort it.
+ * Abort the pending SCSI command in device by sending UFS_ABORT_TASK task
+ * management command, and in host controller by clearing the door-bell
+ * register. There can be race between controller sending the command to the
+ * device while abort is issued. To avoid that, first issue UFS_QUERY_TASK to
+ * check if the command is really issued and then try to abort it.
+ *
+ * Device management commands are not SCSI commands, so no task management
+ * function is issued for them; only the command is cleared in the host
+ * controller.
*
* Return: zero on success, non-zero on failure.
*/
@@ -8046,6 +8050,9 @@ int ufshcd_try_to_abort_task(struct ufs_hba *hba, int tag)
lrbp = scsi_cmd_priv(cmd);
+ if (!ufshcd_is_scsi_cmd(cmd))
+ goto clear_cmd;
+
for (poll_cnt = 100; poll_cnt; poll_cnt--) {
err = ufshcd_issue_tm_cmd(hba, lrbp->lun, tag, UFS_QUERY_TASK,
&resp);
@@ -8091,6 +8098,7 @@ int ufshcd_try_to_abort_task(struct ufs_hba *hba, int tag)
return err;
}
+clear_cmd:
err = ufshcd_clear_cmd(hba, tag);
if (err)
dev_err(hba->dev, "%s: Failed clearing cmd at tag %d, err %d\n",
@@ -8194,10 +8202,7 @@ static int ufshcd_abort(struct scsi_cmnd *cmd)
goto release;
}
- if (blk_mq_is_reserved_rq(rq))
- err = ufshcd_clear_cmd(hba, tag);
- else
- err = ufshcd_try_to_abort_task(hba, tag);
+ err = ufshcd_try_to_abort_task(hba, tag);
if (err) {
dev_err(hba->dev, "%s: failed with err %d\n", __func__, err);
ufshcd_set_req_abort_skip(hba, hba->outstanding_reqs);
--
2.43.0