Skip to content

Commit

Permalink
scsi: ufs: Clear UAC for FFU and RPMB LUNs
Browse files Browse the repository at this point in the history
[ Upstream commit 4f3e900 ]

In order to conduct FFU or RPMB operations, UFS needs to clear UNIT
ATTENTION condition. Clear it explicitly so that we get no failures during
initialization.

Link: https://lore.kernel.org/r/20201117165839.1643377-4-jaegeuk@kernel.org
Signed-off-by: Jaegeuk Kim <jaegeuk@google.com>
Signed-off-by: Martin K. Petersen <martin.petersen@oracle.com>
Signed-off-by: Sasha Levin <sashal@kernel.org>
  • Loading branch information
Jaegeuk Kim authored and gregkh committed Jan 12, 2021
1 parent 43dee88 commit e538343
Show file tree
Hide file tree
Showing 2 changed files with 65 additions and 6 deletions.
70 changes: 64 additions & 6 deletions drivers/scsi/ufs/ufshcd.c
Expand Up @@ -7093,7 +7093,6 @@ static inline void ufshcd_blk_pm_runtime_init(struct scsi_device *sdev)
static int ufshcd_scsi_add_wlus(struct ufs_hba *hba)
{
int ret = 0;
struct scsi_device *sdev_rpmb;
struct scsi_device *sdev_boot;

hba->sdev_ufs_device = __scsi_add_device(hba->host, 0, 0,
Expand All @@ -7106,14 +7105,14 @@ static int ufshcd_scsi_add_wlus(struct ufs_hba *hba)
ufshcd_blk_pm_runtime_init(hba->sdev_ufs_device);
scsi_device_put(hba->sdev_ufs_device);

sdev_rpmb = __scsi_add_device(hba->host, 0, 0,
hba->sdev_rpmb = __scsi_add_device(hba->host, 0, 0,
ufshcd_upiu_wlun_to_scsi_wlun(UFS_UPIU_RPMB_WLUN), NULL);
if (IS_ERR(sdev_rpmb)) {
ret = PTR_ERR(sdev_rpmb);
if (IS_ERR(hba->sdev_rpmb)) {
ret = PTR_ERR(hba->sdev_rpmb);
goto remove_sdev_ufs_device;
}
ufshcd_blk_pm_runtime_init(sdev_rpmb);
scsi_device_put(sdev_rpmb);
ufshcd_blk_pm_runtime_init(hba->sdev_rpmb);
scsi_device_put(hba->sdev_rpmb);

sdev_boot = __scsi_add_device(hba->host, 0, 0,
ufshcd_upiu_wlun_to_scsi_wlun(UFS_UPIU_BOOT_WLUN), NULL);
Expand Down Expand Up @@ -7637,6 +7636,63 @@ static int ufshcd_add_lus(struct ufs_hba *hba)
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_ON(1);
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
Expand Down Expand Up @@ -7756,6 +7812,8 @@ static void ufshcd_async_scan(void *data, async_cookie_t cookie)
pm_runtime_put_sync(hba->dev);
ufshcd_exit_clk_scaling(hba);
ufshcd_hba_exit(hba);
} else {
ufshcd_clear_ua_wluns(hba);
}
}

Expand Down
1 change: 1 addition & 0 deletions drivers/scsi/ufs/ufshcd.h
Expand Up @@ -683,6 +683,7 @@ struct ufs_hba {
* "UFS device" W-LU.
*/
struct scsi_device *sdev_ufs_device;
struct scsi_device *sdev_rpmb;

enum ufs_dev_pwr_mode curr_dev_pwr_mode;
enum uic_link_state uic_link_state;
Expand Down

0 comments on commit e538343

Please sign in to comment.