1
0

scsi: ufs: core: Rework ufshcd_eh_device_reset_handler()

Merge the MCQ mode and legacy mode loops into a single loop. This patch
prepares for optimizing the hot path by removing the direct hba->lrb[]
accesses from ufshcd_eh_device_reset_handler().

Reviewed-by: Avri Altman <avri.altman@sandisk.com>
Signed-off-by: Bart Van Assche <bvanassche@acm.org>
Link: https://patch.msgid.link/20251031204029.2883185-17-bvanassche@acm.org
Signed-off-by: Martin K. Petersen <martin.petersen@oracle.com>
This commit is contained in:
Bart Van Assche
2025-10-31 13:39:24 -07:00
committed by Martin K. Petersen
parent 63a5b959c8
commit f18fac1e2b

View File

@@ -7566,6 +7566,36 @@ int ufshcd_advanced_rpmb_req_handler(struct ufs_hba *hba, struct utp_upiu_req *r
return err ? : result;
}
static bool ufshcd_clear_lu_cmds(struct request *req, void *priv)
{
struct scsi_cmnd *cmd = blk_mq_rq_to_pdu(req);
struct scsi_device *sdev = cmd->device;
struct Scsi_Host *shost = sdev->host;
struct ufs_hba *hba = shost_priv(shost);
const u64 lun = *(u64 *)priv;
const u32 tag = req->tag;
if (sdev->lun != lun)
return true;
if (ufshcd_clear_cmd(hba, tag) < 0) {
dev_err(hba->dev, "%s: failed to clear request %d\n", __func__,
tag);
return true;
}
if (hba->mcq_enabled) {
struct ufs_hw_queue *hwq = ufshcd_mcq_req_to_hwq(hba, req);
if (hwq)
ufshcd_mcq_poll_cqe_lock(hba, hwq);
return true;
}
ufshcd_compl_one_cqe(hba, tag, NULL);
return true;
}
/**
* ufshcd_eh_device_reset_handler() - Reset a single logical unit.
* @cmd: SCSI command pointer
@@ -7574,12 +7604,8 @@ int ufshcd_advanced_rpmb_req_handler(struct ufs_hba *hba, struct utp_upiu_req *r
*/
static int ufshcd_eh_device_reset_handler(struct scsi_cmnd *cmd)
{
unsigned long flags, pending_reqs = 0, not_cleared = 0;
struct Scsi_Host *host;
struct ufs_hba *hba;
struct ufs_hw_queue *hwq;
struct ufshcd_lrb *lrbp;
u32 pos, not_cleared_mask = 0;
int err;
u8 resp = 0xF, lun;
@@ -7588,50 +7614,16 @@ static int ufshcd_eh_device_reset_handler(struct scsi_cmnd *cmd)
lun = ufshcd_scsi_to_upiu_lun(cmd->device->lun);
err = ufshcd_issue_tm_cmd(hba, lun, 0, UFS_LOGICAL_RESET, &resp);
if (err || resp != UPIU_TASK_MANAGEMENT_FUNC_COMPL) {
if (!err)
err = resp;
goto out;
if (err) {
} else if (resp != UPIU_TASK_MANAGEMENT_FUNC_COMPL) {
err = resp;
} else {
/* clear the commands that were pending for corresponding LUN */
blk_mq_tagset_busy_iter(&hba->host->tag_set,
ufshcd_clear_lu_cmds,
&cmd->device->lun);
}
if (hba->mcq_enabled) {
for (pos = 0; pos < hba->nutrs; pos++) {
lrbp = &hba->lrb[pos];
if (ufshcd_cmd_inflight(lrbp->cmd) &&
lrbp->lun == lun) {
ufshcd_clear_cmd(hba, pos);
hwq = ufshcd_mcq_req_to_hwq(hba, scsi_cmd_to_rq(lrbp->cmd));
ufshcd_mcq_poll_cqe_lock(hba, hwq);
}
}
err = 0;
goto out;
}
/* clear the commands that were pending for corresponding LUN */
spin_lock_irqsave(&hba->outstanding_lock, flags);
for_each_set_bit(pos, &hba->outstanding_reqs, hba->nutrs)
if (hba->lrb[pos].lun == lun)
__set_bit(pos, &pending_reqs);
hba->outstanding_reqs &= ~pending_reqs;
spin_unlock_irqrestore(&hba->outstanding_lock, flags);
for_each_set_bit(pos, &pending_reqs, hba->nutrs) {
if (ufshcd_clear_cmd(hba, pos) < 0) {
spin_lock_irqsave(&hba->outstanding_lock, flags);
not_cleared = 1U << pos &
ufshcd_readl(hba, REG_UTP_TRANSFER_REQ_DOOR_BELL);
hba->outstanding_reqs |= not_cleared;
not_cleared_mask |= not_cleared;
spin_unlock_irqrestore(&hba->outstanding_lock, flags);
dev_err(hba->dev, "%s: failed to clear request %d\n",
__func__, pos);
}
}
__ufshcd_transfer_req_compl(hba, pending_reqs & ~not_cleared_mask);
out:
hba->req_abort_count = 0;
ufshcd_update_evt_hist(hba, UFS_EVT_DEV_RESET, (u32)err);
if (!err) {