Re: Questions about probing WLUNs for UFS power management

From: Jaeyoon Choi <jaeyoon_at_freebsd.org>
Date: Thu, 25 Sep 2025 02:30:49 UTC
If we go with option 1), we could add a PIM_WLUN flag to hba_misc,
similar to PIM_EXTLUN, so that only device drivers configured with
this flag would probe for WLUNs.

Jaeyoon

2025년 9월 24일 (수) 오전 11:32, Jaeyoon Choi <jaeyoon@freebsd.org>님이 작성:
>
> Hello freebsd-scsi,
>
> I’m trying to implement Well-known LUNs (WLUNs) for the UFS (Universal
> Flash Storage, ufshci(4)) driver, but the current SCSI XPT doesn't probe
> WLUNs, so I have a few questions.
>
> First, Well-known LUNs are defined in SCSI SAM-5. In UFS, 'REPORT LUNS',
> 'UFS Device', 'RPMB', and 'BOOT' LUNs are treated as WLUNs.
> (SAM-5 4.7.5.1 "Well-known logical unit addressing",
> UFS 2.1 spec 10.8.5 "10.8.5 Well Known Logical Unit Defined in UFS")
>
> Because a UFS device contains multiple LUNs, power management requires
> sending a START STOP UNIT(SSU) command to the 'UFS Device' WLUN. (If SSU
> is sent to a non-WLUN (normal) LUN, the device power mode is not changed
> and only that LUN becomes disabled.)
> (UFS 2.1 spec 7.4.2 "Power Management Command: START STOP UNIT")
>
> In FreeBSD, the SCSI XPT logic that parses LUNs checks the 'Simple logical
> unit addressing format' (SAM-5 Table 26) and the 8-byte 'Extended logical
> unit addressing format' (SAM-5 Table 35), but it does not check the
> 'Well-known logical unit extended addressing format' (SAM-5 Table 37).
> In the scsi_xpt.c code below, CAM_GET_LUN reads Extended LUNs and
> CAM_GET_SIMPLE_LUN reads Simple LUNs:
>
> ```
> sys/cam/scsi/scsi_xpt.c line:2114
> static void
> scsi_scan_bus(struct cam_periph *periph, union ccb *request_ccb)
> ...
>             while (scan_info->lunindex[target_id] < nluns) {
>                 if (scan_info->cpi->hba_misc & PIM_EXTLUNS) {
>                     CAM_GET_LUN(target->luns,
>                         scan_info->lunindex[target_id],
>                         lun_id);
>                     break;
>                 }
>
>                 if (CAM_CAN_GET_SIMPLE_LUN(target->luns,
>                     scan_info->lunindex[target_id])) {
>                     CAM_GET_SIMPLE_LUN(target->luns,
>                         scan_info->lunindex[target_id],
>                         lun_id);
>                     break;
>                 }
>
>                 scan_info->lunindex[target_id]++;
>             }
> ```
>
> Also, we can obtain the number of WLUNs via the REPORT LUNS SCSI command.
> To retrieve WLUNs, the SELECT REPORT field must be set to 0x01, but
> SCSI XPT currently uses 0x00 to obtain only normal LUNs.
> (UFS 2.1 spec 11.3.12.2 "Report LUNS Command Select Report Field Values")
>
> ```
> sys/cam/scsi/scsi_xpt.c line:827
> static void
> probestart(struct cam_periph *periph, union ccb *start_ccb)
> ...
>     case PROBE_REPORT_LUNS:
> ...
>         scsi_report_luns(csio, 5, probedone, MSG_SIMPLE_Q_TAG,
>             RPL_REPORT_DEFAULT, rp, periph->path->target->rpl_size,
>             SSD_FULL_SIZE, 60000);
> ```
> ```
> sys/cam/scsi/scsi_all.h line:3020
> struct scsi_report_luns
> {
>     uint8_t opcode;
>     uint8_t reserved1;
> #define RPL_REPORT_DEFAULT     0x00
> #define RPL_REPORT_WELLKNOWN   0x01
> ```
>
> Looking at the Linux code, Linux also does not check WLUNs at the SCSI
> layer. Therefore, the Linux UFS driver explicitly registers the WLUNs
> during initialization by calling __scsi_add_device()
>
> ```
> drivers/ufs/core/ufshcd.c line:8137
> /**
>  * ufshcd_scsi_add_wlus - Adds required W-LUs
>  * @hba: per-adapter instance
>  *
>  * 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 function adds scsi device instances for each of all well known LUs
>  * (except "REPORT LUNS" LU).
>  *
>  * Return: zero on success (all required W-LUs are added successfully),
>  * non-zero error value on failure (if failed to add any of the required W-LU).
>  */
> static int ufshcd_scsi_add_wlus(struct ufs_hba *hba)
> {
>     int ret = 0;
>     struct scsi_device *sdev_boot, *sdev_rpmb;
>
>     hba->ufs_device_wlun = __scsi_add_device(hba->host, 0, 0,
>         ufshcd_upiu_wlun_to_scsi_wlun(UFS_UPIU_UFS_DEVICE_WLUN), NULL);
>     if (IS_ERR(hba->ufs_device_wlun)) {
>         ret = PTR_ERR(hba->ufs_device_wlun);
>         hba->ufs_device_wlun = NULL;
>         goto out;
>     }
>     scsi_device_put(hba->ufs_device_wlun);
>
>     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);
>         goto remove_ufs_device_wlun;
>     }
>     ufshcd_blk_pm_runtime_init(sdev_rpmb);
>     scsi_device_put(sdev_rpmb);
>
>     sdev_boot = __scsi_add_device(hba->host, 0, 0,
>         ufshcd_upiu_wlun_to_scsi_wlun(UFS_UPIU_BOOT_WLUN), NULL);
>     if (IS_ERR(sdev_boot)) {
>         dev_err(hba->dev, "%s: BOOT WLUN not found\n", __func__);
>     } else {
>         ufshcd_blk_pm_runtime_init(sdev_boot);
>         scsi_device_put(sdev_boot);
>     }
>     goto out;
>
> remove_ufs_device_wlun:
>     scsi_remove_device(hba->ufs_device_wlun);
> out:
>     return ret;
> }
> ```
>
> ---------------------------------------------------------------------------
>
> My question is: which approach would be more appropriate for using WLUN
> devices in UFS driver on FreeBSD?
>
> (1) Add support in SCSI XPT to probe WLUNs and allocate devices for them.
> (2) Follow Linux: have the UFS driver explicitly probe/register WLUN
>     devices itself.
>
> If (2) is preferred, what is the recommended way for the UFSHCI driver to
> probe/register WLUNs in FreeBSD? (Is there an equivalent to Linux’s
> __scsi_add_device()?)
>
> Thanks,
> Jaeyoon