BACKPORT: FROMGIT: scsi: ufs: core: Stop clearing unit attentions
Commit aa53f580e67b ("scsi: ufs: Minor adjustments to error handling") introduced a ufshcd_clear_ua_wluns() call in ufshcd_err_handling_unprepare(). As explained in detail by Adrian Hunter, this can trigger a deadlock. Avoid that deadlock by removing the code that clears the unit attention. This is safe because the only software that relies on clearing unit attentions is the Android Trusty software and because support for handling unit attentions has been added in the Trusty software. See also https://lore.kernel.org/linux-scsi/20210930124224.114031-2-adrian.hunter@intel.com/ Note that, should apply "scsi: ufs: retry START_STOP on UNIT_ATTENTION" before this patch, since this patch gives UNIT ATTENTION to scsi_execute(START_STOP). Bug: 194712579 (cherry picked from commit edc0596cc04bf0ac3a69c66e994d3ff8b650ff71 git://git.kernel.org/pub/scm/linux/kernel/git/mkp/scsi.git for-next) Link: https://lore.kernel.org/r/20211001182015.1347587-3-jaegeuk@kernel.org Fixes: aa53f580e67b ("scsi: ufs: Minor adjustments to error handling") Cc: Adrian Hunter <adrian.hunter@intel.com> Signed-off-by: Bart Van Assche <bvanassche@google.com> Signed-off-by: Jaegeuk Kim <jaegeuk@kernel.org> Signed-off-by: Martin K. Petersen <martin.petersen@oracle.com> Change-Id: I73656b8b6773558dc7a552700d283c1ae6dc25f7
This commit is contained in:

committed by
Jaegeuk Kim

parent
2b411f1257
commit
d5aea3dbfb
@@ -226,7 +226,6 @@ static int ufshcd_reset_and_restore(struct ufs_hba *hba);
|
||||
static int ufshcd_eh_host_reset_handler(struct scsi_cmnd *cmd);
|
||||
static int ufshcd_clear_tm_cmd(struct ufs_hba *hba, int tag);
|
||||
static void ufshcd_hba_exit(struct ufs_hba *hba);
|
||||
static int ufshcd_clear_ua_wluns(struct ufs_hba *hba);
|
||||
static int ufshcd_probe_hba(struct ufs_hba *hba, bool async);
|
||||
static int ufshcd_setup_clocks(struct ufs_hba *hba, bool on);
|
||||
static inline void ufshcd_add_delay_before_dme_cmd(struct ufs_hba *hba);
|
||||
@@ -4087,8 +4086,6 @@ 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;
|
||||
}
|
||||
@@ -5950,7 +5947,6 @@ static void ufshcd_err_handling_unprepare(struct ufs_hba *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);
|
||||
}
|
||||
|
||||
@@ -7862,8 +7858,6 @@ static int ufshcd_add_lus(struct ufs_hba *hba)
|
||||
if (ret)
|
||||
goto out;
|
||||
|
||||
ufshcd_clear_ua_wluns(hba);
|
||||
|
||||
/* Initialize devfreq after UFS device is detected */
|
||||
if (ufshcd_is_clkscaling_supported(hba)) {
|
||||
memcpy(&hba->clk_scaling.saved_pwr_info.info,
|
||||
@@ -7889,63 +7883,6 @@ out:
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int
|
||||
ufshcd_send_request_sense(struct ufs_hba *hba, struct scsi_device *sdp);
|
||||
|
||||
static int ufshcd_clear_ua_wlun(struct ufs_hba *hba, u8 wlun)
|
||||
{
|
||||
struct scsi_device *sdp;
|
||||
unsigned long flags;
|
||||
int ret = 0;
|
||||
|
||||
spin_lock_irqsave(hba->host->host_lock, flags);
|
||||
if (wlun == UFS_UPIU_UFS_DEVICE_WLUN)
|
||||
sdp = hba->sdev_ufs_device;
|
||||
else if (wlun == UFS_UPIU_RPMB_WLUN)
|
||||
sdp = hba->sdev_rpmb;
|
||||
else
|
||||
BUG();
|
||||
if (sdp) {
|
||||
ret = scsi_device_get(sdp);
|
||||
if (!ret && !scsi_device_online(sdp)) {
|
||||
ret = -ENODEV;
|
||||
scsi_device_put(sdp);
|
||||
}
|
||||
} else {
|
||||
ret = -ENODEV;
|
||||
}
|
||||
spin_unlock_irqrestore(hba->host->host_lock, flags);
|
||||
if (ret)
|
||||
goto out_err;
|
||||
|
||||
ret = ufshcd_send_request_sense(hba, sdp);
|
||||
scsi_device_put(sdp);
|
||||
out_err:
|
||||
if (ret)
|
||||
dev_err(hba->dev, "%s: UAC clear LU=%x ret = %d\n",
|
||||
__func__, wlun, ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int ufshcd_clear_ua_wluns(struct ufs_hba *hba)
|
||||
{
|
||||
int ret = 0;
|
||||
|
||||
if (!hba->wlun_dev_clr_ua)
|
||||
goto out;
|
||||
|
||||
ret = ufshcd_clear_ua_wlun(hba, UFS_UPIU_UFS_DEVICE_WLUN);
|
||||
if (!ret)
|
||||
ret = ufshcd_clear_ua_wlun(hba, UFS_UPIU_RPMB_WLUN);
|
||||
if (!ret)
|
||||
hba->wlun_dev_clr_ua = false;
|
||||
out:
|
||||
if (ret)
|
||||
dev_err(hba->dev, "%s: Failed to clear UAC WLUNS ret = %d\n",
|
||||
__func__, ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* ufshcd_probe_hba - probe hba to detect device and initialize
|
||||
* @hba: per-adapter instance
|
||||
@@ -7999,7 +7936,6 @@ static int ufshcd_probe_hba(struct ufs_hba *hba, bool async)
|
||||
/* UFS device is also active now */
|
||||
ufshcd_set_ufs_dev_active(hba);
|
||||
ufshcd_force_reset_auto_bkops(hba);
|
||||
hba->wlun_dev_clr_ua = true;
|
||||
|
||||
/* Gear up to HS gear if supported */
|
||||
if (hba->max_pwr_info.is_valid) {
|
||||
@@ -8528,35 +8464,6 @@ static void ufshcd_hba_exit(struct ufs_hba *hba)
|
||||
}
|
||||
}
|
||||
|
||||
static int
|
||||
ufshcd_send_request_sense(struct ufs_hba *hba, struct scsi_device *sdp)
|
||||
{
|
||||
unsigned char cmd[6] = {REQUEST_SENSE,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
UFS_SENSE_SIZE,
|
||||
0};
|
||||
char *buffer;
|
||||
int ret;
|
||||
|
||||
buffer = kzalloc(UFS_SENSE_SIZE, GFP_KERNEL);
|
||||
if (!buffer) {
|
||||
ret = -ENOMEM;
|
||||
goto out;
|
||||
}
|
||||
|
||||
ret = scsi_execute(sdp, cmd, DMA_FROM_DEVICE, buffer,
|
||||
UFS_SENSE_SIZE, NULL, NULL,
|
||||
msecs_to_jiffies(1000), 3, 0, RQF_PM, NULL);
|
||||
if (ret)
|
||||
pr_err("%s: failed with err %d\n", __func__, ret);
|
||||
|
||||
kfree(buffer);
|
||||
out:
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* ufshcd_set_dev_pwr_mode - sends START STOP UNIT command to set device
|
||||
* power mode
|
||||
@@ -8598,7 +8505,6 @@ static int ufshcd_set_dev_pwr_mode(struct ufs_hba *hba,
|
||||
* handling context.
|
||||
*/
|
||||
hba->host->eh_noresume = 1;
|
||||
ufshcd_clear_ua_wluns(hba);
|
||||
|
||||
cmd[4] = pwr_mode << 4;
|
||||
|
||||
@@ -8927,7 +8833,6 @@ enable_gating:
|
||||
|
||||
hba->clk_gating.is_suspended = false;
|
||||
hba->dev_info.b_rpm_dev_flush_capable = false;
|
||||
ufshcd_clear_ua_wluns(hba);
|
||||
ufshcd_release(hba);
|
||||
ufshpb_resume(hba);
|
||||
out:
|
||||
@@ -9036,8 +8941,6 @@ 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);
|
||||
|
||||
|
Reference in New Issue
Block a user