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 <[email protected]>
---
 hw/ufs/ufs.c        | 17 ++++++++++++++++-
 include/block/ufs.h |  1 +
 2 files changed, 17 insertions(+), 1 deletion(-)

diff --git a/hw/ufs/ufs.c b/hw/ufs/ufs.c
index 4c505e0bf..f008af746 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 b0515325f..4a614fbe5 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 */
-- 
2.56.0.rc1.315.gc6ed9934b7-goog


Reply via email to