Commit 92d01b9ee2 for qemu.org
commit 92d01b9ee2bc95771e8b9348b111a10083ff64e2
Author: Stanley Jhu <stanleyjhu@google.com>
Date: Mon Oct 5 19:03:15 2026 +0800
hw/ufs: Skip nullified MCQ submission queue entries with OCS_ABORTED
Per JEDEC UFSHCI (JESD223G Section 6.1.1 and Section 4.4.6 Step 2B),
host software in MCQ mode may stop a Submission Queue and nullify an
unfetched SQE by setting its UTRD Command Type (DW0 bits 31:28) to
0xF. When the Submission Queue is resumed, the host controller shall
skip execution of the nullified transfer request and post a Completion
Queue Entry (CQE) to the Completion Queue with OCS = ABORTED (0x06).
In ufs_mcq_process_sq(), check for UFS_UTP_CMD_TYPE_NULL (0xF), read
the Request UPIU header on a best-effort basis via
ufs_dma_read_req_upiu() to populate cqe.task_tag and cqe.lun for
UFSHCI 4.1+ completion decoding, and unconditionally post a CQE with
UFS_OCS_ABORTED without executing the command or writing a Response
UPIU for the nullified entry.
Signed-off-by: Stanley Jhu <stanleyjhu@google.com>
Reviewed-by: Jeuk Kim <jeuk20.kim@samsung.com>
Signed-off-by: Jeuk Kim <jeuk20.kim@samsung.com>
diff --git a/hw/ufs/ufs.c b/hw/ufs/ufs.c
index 4c505e0bff..f008af7467 100644
--- a/hw/ufs/ufs.c
+++ b/hw/ufs/ufs.c
@@ -36,6 +36,7 @@
static void ufs_exec_req(UfsRequest *req);
static void ufs_clear_req(UfsRequest *req);
+static void ufs_mcq_process_cq(void *opaque);
static inline uint64_t ufs_mcq_reg_addr(UfsHc *u, int qid)
{
@@ -474,6 +475,17 @@ static void ufs_mcq_process_sq(void *opaque)
ufs_mcq_init_req(sq->u, req, sq);
memcpy(&req->utrd, &sqe, sizeof(req->utrd));
+ if ((le32_to_cpu(sqe.header.dword_0) >> 28) == UFS_UTP_CMD_TYPE_NULL) {
+ ufs_dma_read_req_upiu(req);
+ req->utrd.header.dword_2 = cpu_to_le32(
+ (le32_to_cpu(req->utrd.header.dword_2) & ~UFS_MASK_OCS) |
+ UFS_OCS_ABORTED);
+ req->state = UFS_REQUEST_COMPLETE;
+ QTAILQ_INSERT_TAIL(&sq->cq->req_list, req, entry);
+ ufs_mcq_process_cq(sq->cq);
+ continue;
+ }
+
req->state = UFS_REQUEST_RUNNING;
ufs_exec_req(req);
}
@@ -493,7 +505,10 @@ static void ufs_mcq_process_cq(void *opaque)
break;
}
- ufs_dma_write_rsp_upiu(req);
+ if ((le32_to_cpu(req->utrd.header.dword_0) >> 28) !=
+ UFS_UTP_CMD_TYPE_NULL) {
+ ufs_dma_write_rsp_upiu(req);
+ }
/* UTRD/CQE are LE; round-trip through host to keep BE correct. */
uint64_t ucdba =
diff --git a/include/block/ufs.h b/include/block/ufs.h
index b0515325f9..4a614fbe52 100644
--- a/include/block/ufs.h
+++ b/include/block/ufs.h
@@ -665,6 +665,7 @@ enum {
UFS_UTP_CMD_TYPE_SCSI = 0x0,
UFS_UTP_CMD_TYPE_UFS = 0x1,
UFS_UTP_CMD_TYPE_DEV_MANAGE = 0x2,
+ UFS_UTP_CMD_TYPE_NULL = 0xf,
};
/* To accommodate UFS2.0 required Command type */