[PATCH v2] hw/ufs: Add support for REPORT_LUNS SCSI command for Well Known LUNs

Hamza Dridi posted 1 patch 1 week, 3 days ago
hw/ufs/lu.c         | 44 ++++++++++++++++++++++++++++++++++----------
include/block/ufs.h |  3 +++
2 files changed, 37 insertions(+), 10 deletions(-)
[PATCH v2] hw/ufs: Add support for REPORT_LUNS SCSI command for Well Known LUNs
Posted by Hamza Dridi 1 week, 3 days ago
From: dridiha <dridiha98@gmail.com>

According to the UFS specification, the REPORT_LUNS SCSI command can query
Well Known LUNs by setting CDB[2] to 0x01 (select Well Known LUNs) or 0x02
(select all LUNs).

Currently, the UFS emulation layer lacks handling for these CDB[2] select
report values, causing command failures when guests attempt to report Well
Known LUNs.

This patch adds support for handling CDB[2] values 0x01 and 0x02 in the
REPORT_LUNS command, returning the appropriate Well Known LUN descriptors
in the SCSI response payload.

Signed-off-by: Hamza Dridi <dridiha98@gmail.com>
---
v1 -> v2:
- Cleard the UPIU WLUN-ID before writing the Wlun byte.

 hw/ufs/lu.c         | 44 ++++++++++++++++++++++++++++++++++----------
 include/block/ufs.h |  3 +++
 2 files changed, 37 insertions(+), 10 deletions(-)

diff --git a/hw/ufs/lu.c b/hw/ufs/lu.c
index bdb1650851..4f1f4f265f 100644
--- a/hw/ufs/lu.c
+++ b/hw/ufs/lu.c
@@ -211,33 +211,57 @@ static const struct SCSIBusInfo ufs_scsi_info = {
     .cancel = ufs_scsi_command_cancelled,
 };
 
+static bool ufs_append_lun(uint8_t *outbuf, uint32_t outbuf_len, int *len,
+                           uint8_t lun, uint8_t lun_msb)
+{
+    if (*len + 8 > outbuf_len) {
+        return false;
+    }
+
+    memset(outbuf + *len, 0, 8);
+    outbuf[*len] = lun_msb;
+    outbuf[*len + 1] = lun;
+    *len += 8;
+
+    return true;
+}
+
 static int ufs_emulate_report_luns(UfsRequest *req, uint8_t *outbuf,
                                    uint32_t outbuf_len)
 {
     UfsHc *u = req->hc;
     int len = 0;
 
-    /* TODO: Support for cases where SELECT REPORT is 1 and 2 */
-    if (req->req_upiu.sc.cdb[2] != 0) {
+    uint8_t report_lun_cmd = req->req_upiu.sc.cdb[2];
+
+    if (report_lun_cmd > 2) {
         return SCSI_COMMAND_FAIL;
     }
 
     if (outbuf_len < 8) {
         return SCSI_COMMAND_FAIL;
     }
+
     memset(outbuf, 0, 8);
     len += 8;
 
-    for (uint8_t lun = 0; lun < UFS_MAX_LUS; ++lun) {
-        if (u->lus[lun]) {
-            if (len + 8 > outbuf_len) {
+    if (report_lun_cmd == 2 || report_lun_cmd == 1) {
+        ufs_append_lun(outbuf, outbuf_len, &len, u->report_wlu.lun & 0x7F,
+                       UFS_WLUN_MSB);
+        ufs_append_lun(outbuf, outbuf_len, &len, u->dev_wlu.lun & 0x7F,
+                       UFS_WLUN_MSB);
+        ufs_append_lun(outbuf, outbuf_len, &len, u->boot_wlu.lun & 0x7F,
+                       UFS_WLUN_MSB);
+        ufs_append_lun(outbuf, outbuf_len, &len, u->rpmb_wlu.lun & 0x7F,
+                       UFS_WLUN_MSB);
+    }
+
+    if (report_lun_cmd == 0 || report_lun_cmd == 2) {
+        for (uint8_t lun = 0; lun < UFS_MAX_LUS; ++lun) {
+            if (u->lus[lun] &&
+                !ufs_append_lun(outbuf, outbuf_len, &len, lun, 0)) {
                 break;
             }
-
-            memset(outbuf + len, 0, 8);
-            outbuf[len] = 0;
-            outbuf[len + 1] = lun;
-            len += 8;
         }
     }
 
diff --git a/include/block/ufs.h b/include/block/ufs.h
index d19b3c65ef..9d5ec4c77f 100644
--- a/include/block/ufs.h
+++ b/include/block/ufs.h
@@ -818,6 +818,9 @@ typedef struct QEMU_PACKED UtpTaskReqDesc {
  */
 #define UFS_EHS_OFFSET_IN_RESPONSE 32
 
+/* Most significant byte in the Report Lun response for Well Known LU */
+#define UFS_WLUN_MSB 0xC1
+
 /* Well known logical unit id in LUN field of UPIU */
 enum {
     UFS_UPIU_REPORT_LUNS_WLUN = 0x81,
-- 
2.43.0
Re: [PATCH v2] hw/ufs: Add support for REPORT_LUNS SCSI command for Well Known LUNs
Posted by Jeuk Kim 1 week, 2 days ago
> According to the UFS specification, the REPORT_LUNS SCSI command can query
> Well Known LUNs by setting CDB[2] to 0x01 (select Well Known LUNs) or 0x02
> (select all LUNs).
> 
> Currently, the UFS emulation layer lacks handling for these CDB[2] select
> report values, causing command failures when guests attempt to report Well
> Known LUNs.
> 
> This patch adds support for handling CDB[2] values 0x01 and 0x02 in the
> REPORT_LUNS command, returning the appropriate Well Known LUN descriptors
> in the SCSI response payload.
> 
> Signed-off-by: Hamza Dridi <dridiha98@gmail.com>
> ---
> v1 -> v2:
> - Cleard the UPIU WLUN-ID before writing the Wlun byte.
> 
>  hw/ufs/lu.c         | 44 ++++++++++++++++++++++++++++++++++----------
>  include/block/ufs.h |  3 +++
>  2 files changed, 37 insertions(+), 10 deletions(-)
>
> diff --git a/hw/ufs/lu.c b/hw/ufs/lu.c
> index bdb1650851..4f1f4f265f 100644
> --- a/hw/ufs/lu.c
> +++ b/hw/ufs/lu.c
> @@ -211,33 +211,57 @@ static const struct SCSIBusInfo ufs_scsi_info = {
>      .cancel = ufs_scsi_command_cancelled,
>  };
>  
> +static bool ufs_append_lun(uint8_t *outbuf, uint32_t outbuf_len, int *len,
> +                           uint8_t lun, uint8_t lun_msb)
> +{
> +    if (*len + 8 > outbuf_len) {
> +        return false;
> +    }
> +
> +    memset(outbuf + *len, 0, 8);
> +    outbuf[*len] = lun_msb;
> +    outbuf[*len + 1] = lun;
> +    *len += 8;
> +
> +    return true;
> +}
> +
>  static int ufs_emulate_report_luns(UfsRequest *req, uint8_t *outbuf,
>                                     uint32_t outbuf_len)
>  {
>      UfsHc *u = req->hc;
>      int len = 0;
>  
> -    /* TODO: Support for cases where SELECT REPORT is 1 and 2 */
> -    if (req->req_upiu.sc.cdb[2] != 0) {
> +    uint8_t report_lun_cmd = req->req_upiu.sc.cdb[2];
> +
> +    if (report_lun_cmd > 2) {
>          return SCSI_COMMAND_FAIL;
>      }
>  
>      if (outbuf_len < 8) {
>          return SCSI_COMMAND_FAIL;
>      }
> +
>      memset(outbuf, 0, 8);
>      len += 8;
>  
> -    for (uint8_t lun = 0; lun < UFS_MAX_LUS; ++lun) {
> -        if (u->lus[lun]) {
> -            if (len + 8 > outbuf_len) {
> +    if (report_lun_cmd == 2 || report_lun_cmd == 1) {
> +        ufs_append_lun(outbuf, outbuf_len, &len, u->report_wlu.lun & 0x7F,
> +                       UFS_WLUN_MSB);
> +        ufs_append_lun(outbuf, outbuf_len, &len, u->dev_wlu.lun & 0x7F,
> +                       UFS_WLUN_MSB);
> +        ufs_append_lun(outbuf, outbuf_len, &len, u->boot_wlu.lun & 0x7F,
> +                       UFS_WLUN_MSB);
> +        ufs_append_lun(outbuf, outbuf_len, &len, u->rpmb_wlu.lun & 0x7F,
> +                       UFS_WLUN_MSB);
> +    }
> +
> +    if (report_lun_cmd == 0 || report_lun_cmd == 2) {
> +        for (uint8_t lun = 0; lun < UFS_MAX_LUS; ++lun) {
> +            if (u->lus[lun] &&
> +                !ufs_append_lun(outbuf, outbuf_len, &len, lun, 0)) {
>                  break;
>              }
> -
> -            memset(outbuf + len, 0, 8);
> -            outbuf[len] = 0;
> -            outbuf[len + 1] = lun;
> -            len += 8;
>          }
>      }
>  
> diff --git a/include/block/ufs.h b/include/block/ufs.h
> index d19b3c65ef..9d5ec4c77f 100644
> --- a/include/block/ufs.h
> +++ b/include/block/ufs.h
> @@ -818,6 +818,9 @@ typedef struct QEMU_PACKED UtpTaskReqDesc {
>   */
>  #define UFS_EHS_OFFSET_IN_RESPONSE 32
>  
> +/* Most significant byte in the Report Lun response for Well Known LU */
> +#define UFS_WLUN_MSB 0xC1
> +
>  /* Well known logical unit id in LUN field of UPIU */
>  enum {
>      UFS_UPIU_REPORT_LUNS_WLUN = 0x81,

Thank you for your contribution.

Reviewed-by: Jeuk Kim <jeuk20.kim@samsung.com>

-- 
Jeuk Kim <jeuk20.kim@samsung.com>