The boot W-LU carries the medium of whichever boot logical unit bBootLunEn
selects, and describes none of its own, so the SCSI scan cannot size it.
Resolve the attribute against each unit descriptor's bBootLunID to say
which unit that is.

Signed-off-by: Alexey Charkov <[email protected]>
---
 drivers/ufs/ufs-uclass.c | 44 ++++++++++++++++++++++++++++++++++++++++++++
 drivers/ufs/ufs.h        | 28 ++++++++++++++++++++++++++++
 2 files changed, 72 insertions(+)

diff --git a/drivers/ufs/ufs-uclass.c b/drivers/ufs/ufs-uclass.c
index acaecfa1e341..da0d6f01146a 100644
--- a/drivers/ufs/ufs-uclass.c
+++ b/drivers/ufs/ufs-uclass.c
@@ -2293,6 +2293,49 @@ int ufshcd_probe(struct udevice *ufs_dev, struct 
ufs_hba_ops *hba_ops)
        return 0;
 }
 
+/**
+ * ufs_scsi_wlun_alias - find the logical unit the boot W-LU presents
+ *
+ * The boot W-LU stands in for whichever of the two boot logical units
+ * bBootLunEn selects, and reports no medium of its own. Report that unit so
+ * that its geometry can be borrowed.
+ */
+static int ufs_scsi_wlun_alias(struct udevice *scsi_dev, int lun)
+{
+       struct ufs_hba *hba = dev_get_uclass_priv(scsi_dev->parent);
+       u32 boot_lun_en;
+       u8 boot_lun_id;
+       int err, i;
+
+       if (lun != UFS_UPIU_BOOT_WLUN)
+               return -ENOENT;
+
+       err = ufshcd_query_attr_retry(hba, UPIU_QUERY_OPCODE_READ_ATTR,
+                                     QUERY_ATTR_IDN_BOOT_LU_EN, 0, 0,
+                                     &boot_lun_en);
+       if (err)
+               return err;
+
+       /* Booting is turned off, so the boot W-LU stands in for nothing */
+       if (boot_lun_en == UFS_BOOT_LUN_DISABLED)
+               return -ENOENT;
+
+       for (i = 0; i < UFS_MAX_LUNS; i++) {
+               err = ufshcd_read_desc_param(hba, QUERY_DESC_IDN_UNIT, i,
+                                            UNIT_DESC_PARAM_BOOT_LUN_ID,
+                                            &boot_lun_id, 1);
+               if (err)
+                       continue;
+
+               if (boot_lun_id == boot_lun_en)
+                       return i;
+       }
+
+       dev_err(hba->dev, "No logical unit carries boot LU %u\n", boot_lun_en);
+
+       return -ENOENT;
+}
+
 #if IS_ENABLED(CONFIG_BOUNCE_BUFFER)
 static int ufs_scsi_buffer_aligned(struct udevice *scsi_dev, struct 
bounce_buffer *state)
 {
@@ -2315,6 +2358,7 @@ static int ufs_scsi_buffer_aligned(struct udevice 
*scsi_dev, struct bounce_buffe
 
 static struct scsi_ops ufs_ops = {
        .exec           = ufs_scsi_exec,
+       .wlun_alias     = ufs_scsi_wlun_alias,
 #if IS_ENABLED(CONFIG_BOUNCE_BUFFER)
        .buffer_aligned = ufs_scsi_buffer_aligned,
 #endif /* CONFIG_BOUNCE_BUFFER */
diff --git a/drivers/ufs/ufs.h b/drivers/ufs/ufs.h
index 0f6c93fbce71..7c3c26e009b1 100644
--- a/drivers/ufs/ufs.h
+++ b/drivers/ufs/ufs.h
@@ -396,6 +396,34 @@ enum device_desc_param {
        DEVICE_DESC_PARAM_PRDCT_REV             = 0x2A,
 };
 
+/* Unit descriptor parameters offsets in bytes */
+enum unit_desc_param {
+       UNIT_DESC_PARAM_LEN                     = 0x0,
+       UNIT_DESC_PARAM_TYPE                    = 0x1,
+       UNIT_DESC_PARAM_UNIT_INDEX              = 0x2,
+       UNIT_DESC_PARAM_LU_ENABLE               = 0x3,
+       UNIT_DESC_PARAM_BOOT_LUN_ID             = 0x4,
+       UNIT_DESC_PARAM_LU_WR_PROTECT           = 0x5,
+       UNIT_DESC_PARAM_LU_Q_DEPTH              = 0x6,
+       UNIT_DESC_PARAM_PSA_SENSITIVE           = 0x7,
+       UNIT_DESC_PARAM_MEM_TYPE                = 0x8,
+       UNIT_DESC_PARAM_DATA_RELIABILITY        = 0x9,
+       UNIT_DESC_PARAM_LOGICAL_BLK_SIZE        = 0xA,
+       UNIT_DESC_PARAM_LOGICAL_BLK_COUNT       = 0xB,
+       UNIT_DESC_PARAM_ERASE_BLK_SIZE          = 0x13,
+       UNIT_DESC_PARAM_PROVISIONING_TYPE       = 0x17,
+       UNIT_DESC_PARAM_PHY_MEM_RSRC_CNT        = 0x18,
+       UNIT_DESC_PARAM_CTX_CAPABILITIES        = 0x20,
+       UNIT_DESC_PARAM_LARGE_UNIT_SIZE_M1      = 0x22,
+};
+
+/* Value of bBootLunEn, and of bBootLunID in the unit descriptor */
+enum ufs_boot_lun_id {
+       UFS_BOOT_LUN_DISABLED                   = 0x0,
+       UFS_BOOT_LUN_A                          = 0x1,
+       UFS_BOOT_LUN_B                          = 0x2,
+};
+
 struct ufs_hba;
 
 enum {

-- 
2.54.0

Reply via email to