Re: Questions about probing WLUNs for UFS power management
- In reply to: Jaeyoon Choi : "Questions about probing WLUNs for UFS power management"
- Go to: [ bottom of page ] [ top of archives ] [ this month ]
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