From: dridiha <[email protected]> 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 <[email protected]> --- hw/ufs/lu.c | 41 +++++++++++++++++++++++++++++++---------- include/block/ufs.h | 3 +++ 2 files changed, 34 insertions(+), 10 deletions(-) diff --git a/hw/ufs/lu.c b/hw/ufs/lu.c index bdb1650851..4d77c2da2f 100644 --- a/hw/ufs/lu.c +++ b/hw/ufs/lu.c @@ -211,33 +211,54 @@ 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, + UFS_WLUN_MSB); + ufs_append_lun(outbuf, outbuf_len, &len, u->dev_wlu.lun, UFS_WLUN_MSB); + ufs_append_lun(outbuf, outbuf_len, &len, u->boot_wlu.lun, UFS_WLUN_MSB); + ufs_append_lun(outbuf, outbuf_len, &len, u->rpmb_wlu.lun, 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
