Skip to content

Commit 2a8fa60

Browse files
Subhash JadavaniChristoph Hellwig
authored andcommitted
ufs: manually add well known logical units
UFS device specification requires the UFS devices to support 4 well known logical units: "REPORT_LUNS" (address: 01h) "UFS Device" (address: 50h) "RPMB" (address: 44h) "BOOT" (address: 30h) UFS device's power management needs to be controlled by "POWER CONDITION" field of SSU (START STOP UNIT) command. But this "power condition" field will take effect only when its sent to "UFS device" well known logical unit hence we require the scsi_device instance to represent this logical unit in order for the UFS host driver to send the SSU command for power management. We also require the scsi_device instance for "RPMB" (Replay Protected Memory Block) LU so user space process can control this LU. User space may also want to have access to BOOT LU. This patch adds the scsi device instances for each of all well known LUs (except "REPORT LUNS" LU). Signed-off-by: Subhash Jadavani <[email protected]> Signed-off-by: Dolev Raviv <[email protected]> Signed-off-by: Christoph Hellwig <[email protected]>
1 parent 3a4bf06 commit 2a8fa60

File tree

2 files changed

+110
-0
lines changed

2 files changed

+110
-0
lines changed

drivers/scsi/ufs/ufshcd.c

Lines changed: 103 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -901,6 +901,17 @@ static int ufshcd_compose_upiu(struct ufs_hba *hba, struct ufshcd_lrb *lrbp)
901901
return ret;
902902
}
903903

904+
/**
905+
* ufshcd_upiu_wlun_to_scsi_wlun - maps UPIU W-LUN id to SCSI W-LUN ID
906+
* @scsi_lun: UPIU W-LUN id
907+
*
908+
* Returns SCSI W-LUN id
909+
*/
910+
static inline u16 ufshcd_upiu_wlun_to_scsi_wlun(u8 upiu_wlun_id)
911+
{
912+
return (upiu_wlun_id & ~UFS_UPIU_WLUN_ID) | SCSI_W_LUN_BASE;
913+
}
914+
904915
/**
905916
* ufshcd_queuecommand - main entry point for SCSI requests
906917
* @cmd: command from SCSI Midlayer
@@ -3383,6 +3394,93 @@ static void ufshcd_init_icc_levels(struct ufs_hba *hba)
33833394

33843395
}
33853396

3397+
/**
3398+
* ufshcd_scsi_add_wlus - Adds required W-LUs
3399+
* @hba: per-adapter instance
3400+
*
3401+
* UFS device specification requires the UFS devices to support 4 well known
3402+
* logical units:
3403+
* "REPORT_LUNS" (address: 01h)
3404+
* "UFS Device" (address: 50h)
3405+
* "RPMB" (address: 44h)
3406+
* "BOOT" (address: 30h)
3407+
* UFS device's power management needs to be controlled by "POWER CONDITION"
3408+
* field of SSU (START STOP UNIT) command. But this "power condition" field
3409+
* will take effect only when its sent to "UFS device" well known logical unit
3410+
* hence we require the scsi_device instance to represent this logical unit in
3411+
* order for the UFS host driver to send the SSU command for power management.
3412+
3413+
* We also require the scsi_device instance for "RPMB" (Replay Protected Memory
3414+
* Block) LU so user space process can control this LU. User space may also
3415+
* want to have access to BOOT LU.
3416+
3417+
* This function adds scsi device instances for each of all well known LUs
3418+
* (except "REPORT LUNS" LU).
3419+
*
3420+
* Returns zero on success (all required W-LUs are added successfully),
3421+
* non-zero error value on failure (if failed to add any of the required W-LU).
3422+
*/
3423+
static int ufshcd_scsi_add_wlus(struct ufs_hba *hba)
3424+
{
3425+
int ret = 0;
3426+
3427+
hba->sdev_ufs_device = __scsi_add_device(hba->host, 0, 0,
3428+
ufshcd_upiu_wlun_to_scsi_wlun(UFS_UPIU_UFS_DEVICE_WLUN), NULL);
3429+
if (IS_ERR(hba->sdev_ufs_device)) {
3430+
ret = PTR_ERR(hba->sdev_ufs_device);
3431+
hba->sdev_ufs_device = NULL;
3432+
goto out;
3433+
}
3434+
3435+
hba->sdev_boot = __scsi_add_device(hba->host, 0, 0,
3436+
ufshcd_upiu_wlun_to_scsi_wlun(UFS_UPIU_BOOT_WLUN), NULL);
3437+
if (IS_ERR(hba->sdev_boot)) {
3438+
ret = PTR_ERR(hba->sdev_boot);
3439+
hba->sdev_boot = NULL;
3440+
goto remove_sdev_ufs_device;
3441+
}
3442+
3443+
hba->sdev_rpmb = __scsi_add_device(hba->host, 0, 0,
3444+
ufshcd_upiu_wlun_to_scsi_wlun(UFS_UPIU_RPMB_WLUN), NULL);
3445+
if (IS_ERR(hba->sdev_rpmb)) {
3446+
ret = PTR_ERR(hba->sdev_rpmb);
3447+
hba->sdev_rpmb = NULL;
3448+
goto remove_sdev_boot;
3449+
}
3450+
goto out;
3451+
3452+
remove_sdev_boot:
3453+
scsi_remove_device(hba->sdev_boot);
3454+
remove_sdev_ufs_device:
3455+
scsi_remove_device(hba->sdev_ufs_device);
3456+
out:
3457+
return ret;
3458+
}
3459+
3460+
/**
3461+
* ufshcd_scsi_remove_wlus - Removes the W-LUs which were added by
3462+
* ufshcd_scsi_add_wlus()
3463+
* @hba: per-adapter instance
3464+
*
3465+
*/
3466+
static void ufshcd_scsi_remove_wlus(struct ufs_hba *hba)
3467+
{
3468+
if (hba->sdev_ufs_device) {
3469+
scsi_remove_device(hba->sdev_ufs_device);
3470+
hba->sdev_ufs_device = NULL;
3471+
}
3472+
3473+
if (hba->sdev_boot) {
3474+
scsi_remove_device(hba->sdev_boot);
3475+
hba->sdev_boot = NULL;
3476+
}
3477+
3478+
if (hba->sdev_rpmb) {
3479+
scsi_remove_device(hba->sdev_rpmb);
3480+
hba->sdev_rpmb = NULL;
3481+
}
3482+
}
3483+
33863484
/**
33873485
* ufshcd_probe_hba - probe hba to detect device and initialize
33883486
* @hba: per-adapter instance
@@ -3415,6 +3513,10 @@ static int ufshcd_probe_hba(struct ufs_hba *hba)
34153513
if (!hba->is_init_prefetch)
34163514
ufshcd_init_icc_levels(hba);
34173515

3516+
/* Add required well known logical units to scsi mid layer */
3517+
if (ufshcd_scsi_add_wlus(hba))
3518+
goto out;
3519+
34183520
scsi_scan_host(hba->host);
34193521
pm_runtime_put_sync(hba->dev);
34203522
}
@@ -3901,6 +4003,7 @@ EXPORT_SYMBOL(ufshcd_runtime_idle);
39014003
void ufshcd_remove(struct ufs_hba *hba)
39024004
{
39034005
scsi_remove_host(hba->host);
4006+
ufshcd_scsi_remove_wlus(hba);
39044007
/* disable interrupts */
39054008
ufshcd_disable_intr(hba, hba->intr_mask);
39064009
ufshcd_hba_stop(hba);

drivers/scsi/ufs/ufshcd.h

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -266,6 +266,13 @@ struct ufs_hba {
266266

267267
struct Scsi_Host *host;
268268
struct device *dev;
269+
/*
270+
* This field is to keep a reference to "scsi_device" corresponding to
271+
* "UFS device" W-LU.
272+
*/
273+
struct scsi_device *sdev_ufs_device;
274+
struct scsi_device *sdev_rpmb;
275+
struct scsi_device *sdev_boot;
269276

270277
struct ufshcd_lrb *lrb;
271278
unsigned long lrb_in_use;

0 commit comments

Comments
 (0)