hw/ufs/lu.c | 44 ++++++++++++++++++++++++++++++++++---------- include/block/ufs.h | 3 +++ 2 files changed, 37 insertions(+), 10 deletions(-)
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
> 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>
© 2016 - 2026 Red Hat, Inc.