Commit aa53f580 authored by Can Guo's avatar Can Guo Committed by Martin K. Petersen
Browse files

scsi: ufs: Minor adjustments to error handling

In error handling prepare stage, after SCSI requests are blocked, do a
down/up_write(clk_scaling_lock) to clean up the queuecommand() path.
Meanwhile, stop eeh_work in case it disturbs error recovery. Moreover,
reset ufshcd_state at the entrance of ufshcd_probe_hba(), since it may be
called multiple times during error recovery.

Link: https://lore.kernel.org/r/1614145010-36079-2-git-send-email-cang@codeaurora.org


Reviewed-by: default avatarAvri Altman <avri.altman@wdc.com>
Signed-off-by: default avatarCan Guo <cang@codeaurora.org>
Signed-off-by: default avatarMartin K. Petersen <martin.petersen@oracle.com>
parent dbdbb81b
Loading
Loading
Loading
Loading
+12 −6
Original line number Diff line number Diff line
@@ -4987,6 +4987,7 @@ ufshcd_transfer_rsp_status(struct ufs_hba *hba, struct ufshcd_lrb *lrbp)
			 * UFS device needs urgent BKOPs.
			 */
			if (!hba->pm_op_in_progress &&
			    !ufshcd_eh_in_progress(hba) &&
			    ufshcd_is_exception_event(lrbp->ucd_rsp_ptr) &&
			    schedule_work(&hba->eeh_work)) {
				/*
@@ -5784,13 +5785,20 @@ static void ufshcd_err_handling_prepare(struct ufs_hba *hba)
			ufshcd_suspend_clkscaling(hba);
		ufshcd_clk_scaling_allow(hba, false);
	}
	ufshcd_scsi_block_requests(hba);
	/* Drain ufshcd_queuecommand() */
	down_write(&hba->clk_scaling_lock);
	up_write(&hba->clk_scaling_lock);
	cancel_work_sync(&hba->eeh_work);
}

static void ufshcd_err_handling_unprepare(struct ufs_hba *hba)
{
	ufshcd_scsi_unblock_requests(hba);
	ufshcd_release(hba);
	if (ufshcd_is_clkscaling_supported(hba))
		ufshcd_clk_scaling_suspend(hba, false);
	ufshcd_clear_ua_wluns(hba);
	pm_runtime_put(hba->dev);
}

@@ -5882,7 +5890,7 @@ static void ufshcd_err_handler(struct work_struct *work)
	spin_unlock_irqrestore(hba->host->host_lock, flags);
	ufshcd_err_handling_prepare(hba);
	spin_lock_irqsave(hba->host->host_lock, flags);
	ufshcd_scsi_block_requests(hba);
	if (hba->ufshcd_state != UFSHCD_STATE_ERROR)
		hba->ufshcd_state = UFSHCD_STATE_RESET;

	/* Complete requests that have door-bell cleared by h/w */
@@ -6042,12 +6050,8 @@ static void ufshcd_err_handler(struct work_struct *work)
	}
	ufshcd_clear_eh_in_progress(hba);
	spin_unlock_irqrestore(hba->host->host_lock, flags);
	ufshcd_scsi_unblock_requests(hba);
	ufshcd_err_handling_unprepare(hba);
	up(&hba->host_sem);

	if (!err && needs_reset)
		ufshcd_clear_ua_wluns(hba);
}

/**
@@ -7858,6 +7862,8 @@ static int ufshcd_probe_hba(struct ufs_hba *hba, bool async)
	unsigned long flags;
	ktime_t start = ktime_get();

	hba->ufshcd_state = UFSHCD_STATE_RESET;

	ret = ufshcd_link_startup(hba);
	if (ret)
		goto out;