Commit 397086dd55 for qemu.org
commit 397086dd554e75fca27ac7b9ff9b5c51818fdf62
Author: dridiha <dridiha98@gmail.com>
Date: Mon Oct 12 16:53:20 2026 +0200
hw/ufs: Add support for REPORT_LUNS SCSI command for Well Known LUNs
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>
Reviewed-by: Jeuk Kim <jeuk20.kim@samsung.com>
Signed-off-by: Jeuk Kim <jeuk20.kim@samsung.com>
diff --git a/hw/ufs/lu.c b/hw/ufs/lu.c
index 5905c49fac..ee4bb75361 100644
--- a/hw/ufs/lu.c
+++ b/hw/ufs/lu.c
@@ -218,33 +218,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 4a614fbe52..f4a3371bce 100644
--- a/include/block/ufs.h
+++ b/include/block/ufs.h
@@ -835,6 +835,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,