Commit f18fac1e authored by Bart Van Assche's avatar Bart Van Assche Committed by Martin K. Petersen
Browse files

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: default avatarAvri Altman <avri.altman@sandisk.com>
Signed-off-by: default avatarBart Van Assche <bvanassche@acm.org>
Link: https://patch.msgid.link/20251031204029.2883185-17-bvanassche@acm.org


Signed-off-by: default avatarMartin K. Petersen <martin.petersen@oracle.com>
parent 63a5b959
Loading
Loading
Loading
Loading
+38 −46
Original line number Diff line number Diff line
@@ -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)
	if (err) {
	} else if (resp != UPIU_TASK_MANAGEMENT_FUNC_COMPL) {
		err = resp;
		goto out;
	}

	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;
	}

	} else {
		/* 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);
		}
		blk_mq_tagset_busy_iter(&hba->host->tag_set,
					ufshcd_clear_lu_cmds,
					&cmd->device->lun);
	}
	__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) {