FROMLIST: scsi: ufs: fix livelock of ufshcd_clear_ua_wluns

When gate_work/ungate_work gets an error during hibern8_enter or exit,
 ufshcd_err_handler()
   ufshcd_scsi_block_requests()
   ufshcd_reset_and_restore()
     ufshcd_clear_ua_wluns() -> stuck
   ufshcd_scsi_unblock_requests()

In order to avoid it, ufshcd_clear_ua_wluns() can be called per recovery flows
such as suspend/resume, link_recovery, and error_handler.

Bug: 175391270
Link: https://lore.kernel.org/linux-scsi/20201218033131.2624065-1-jaegeuk@kernel.org/T/#u
Fixes: fc6762d925 ("FROMLIST: scsi: ufs: Clear UAC for RPMB after ufshcd resets")
Signed-off-by: Jaegeuk Kim <jaegeuk@kernel.org>
Signed-off-by: Jaegeuk Kim <jaegeuk@google.com>
Change-Id: Ia53b70ce24c191985de3f8678c854e2df626de11
This commit is contained in:
Jaegeuk Kim
2020-12-17 19:18:08 -08:00
committed by Alistair Delva
parent de594973f8
commit b56c9e4cdf

View File

@@ -3973,6 +3973,8 @@ int ufshcd_link_recovery(struct ufs_hba *hba)
if (ret)
dev_err(hba->dev, "%s: link recovery failed, err %d",
__func__, ret);
else
ufshcd_clear_ua_wluns(hba);
return ret;
}
@@ -5969,6 +5971,9 @@ skip_err_handling:
ufshcd_scsi_unblock_requests(hba);
ufshcd_err_handling_unprepare(hba);
up(&hba->eh_sem);
if (!err && needs_reset)
ufshcd_clear_ua_wluns(hba);
}
/**
@@ -6906,14 +6911,11 @@ static int ufshcd_host_reset_and_restore(struct ufs_hba *hba)
ufshcd_set_clk_freq(hba, true);
err = ufshcd_hba_enable(hba);
if (err)
goto out;
/* Establish the link again and restore the device */
err = ufshcd_probe_hba(hba, false);
if (!err)
ufshcd_clear_ua_wluns(hba);
out:
err = ufshcd_probe_hba(hba, false);
if (err)
dev_err(hba->dev, "%s: Host init failed %d\n", __func__, err);
ufshcd_update_reg_hist(&hba->ufs_stats.host_reset, (u32)err);
@@ -8734,6 +8736,7 @@ enable_gating:
ufshcd_resume_clkscaling(hba);
hba->clk_gating.is_suspended = false;
hba->dev_info.b_rpm_dev_flush_capable = false;
ufshcd_clear_ua_wluns(hba);
ufshcd_release(hba);
out:
if (hba->dev_info.b_rpm_dev_flush_capable) {
@@ -8839,6 +8842,8 @@ static int ufshcd_resume(struct ufs_hba *hba, enum ufs_pm_op pm_op)
cancel_delayed_work(&hba->rpm_dev_flush_recheck_work);
}
ufshcd_clear_ua_wluns(hba);
/* Schedule clock gating in case of no access to UFS device yet */
ufshcd_release(hba);