Round-trip UTRD fields through cpu_to_le/ le_to_cpu when building MCQ CQEs to
keep BE hosts correct. Also avoid double BE conversion of response
data_segment_length and document the LE round-trip.

Signed-off-by: Jeuk Kim <[email protected]>
---
 hw/ufs/lu.c         |  3 +--
 hw/ufs/ufs.c        | 27 ++++++++++++++++++---------
 include/block/ufs.h |  2 +-
 3 files changed, 20 insertions(+), 12 deletions(-)

diff --git a/hw/ufs/lu.c b/hw/ufs/lu.c
index 2d8ffd72c5..3f3c9589ce 100644
--- a/hw/ufs/lu.c
+++ b/hw/ufs/lu.c
@@ -53,8 +53,7 @@ static void ufs_build_scsi_response_upiu(UfsRequest *req, 
uint8_t *sense,
         response = UFS_COMMAND_RESULT_FAIL;
     }
 
-    data_segment_length =
-        cpu_to_be16(sense_len + sizeof(req->rsp_upiu.sr.sense_data_len));
+    data_segment_length = sense_len + sizeof(req->rsp_upiu.sr.sense_data_len);
     ufs_build_upiu_header(req, UFS_UPIU_TRANSACTION_RESPONSE, flags, response,
                           status, data_segment_length);
 }
diff --git a/hw/ufs/ufs.c b/hw/ufs/ufs.c
index cab42ae7b6..043c35e68f 100644
--- a/hw/ufs/ufs.c
+++ b/hw/ufs/ufs.c
@@ -448,15 +448,24 @@ static void ufs_mcq_process_cq(void *opaque)
     {
         ufs_dma_write_rsp_upiu(req);
 
-        req->cqe.utp_addr =
-            ((uint64_t)req->utrd.command_desc_base_addr_hi << 32ULL) |
-            req->utrd.command_desc_base_addr_lo;
-        req->cqe.utp_addr |= req->sq->sqid;
-        req->cqe.resp_len = req->utrd.response_upiu_length;
-        req->cqe.resp_off = req->utrd.response_upiu_offset;
-        req->cqe.prdt_len = req->utrd.prd_table_length;
-        req->cqe.prdt_off = req->utrd.prd_table_offset;
-        req->cqe.status = req->utrd.header.dword_2 & 0xf;
+        /* UTRD/CQE are LE; round-trip through host to keep BE correct. */
+        uint64_t ucdba =
+            ((uint64_t)le32_to_cpu(req->utrd.command_desc_base_addr_hi)
+             << 32ULL) |
+            le32_to_cpu(req->utrd.command_desc_base_addr_lo);
+        uint16_t resp_len = le16_to_cpu(req->utrd.response_upiu_length);
+        uint16_t resp_off = le16_to_cpu(req->utrd.response_upiu_offset);
+        uint16_t prdt_len = le16_to_cpu(req->utrd.prd_table_length);
+        uint16_t prdt_off = le16_to_cpu(req->utrd.prd_table_offset);
+        uint8_t status = le32_to_cpu(req->utrd.header.dword_2) & UFS_MASK_OCS;
+
+        ucdba |= req->sq->sqid;
+        req->cqe.utp_addr = cpu_to_le64(ucdba);
+        req->cqe.resp_len = cpu_to_le16(resp_len);
+        req->cqe.resp_off = cpu_to_le16(resp_off);
+        req->cqe.prdt_len = cpu_to_le16(prdt_len);
+        req->cqe.prdt_off = cpu_to_le16(prdt_off);
+        req->cqe.status = status;
         req->cqe.error = 0;
 
         ret = ufs_addr_write(u, cq->addr + tail, &req->cqe, sizeof(req->cqe));
diff --git a/include/block/ufs.h b/include/block/ufs.h
index ede4aff08e..04cb24324d 100644
--- a/include/block/ufs.h
+++ b/include/block/ufs.h
@@ -645,7 +645,7 @@ enum UtpOcsCodes {
 };
 
 enum {
-    UFS_MASK_OCS = 0x0F,
+    UFS_MASK_OCS = 0xFF,
 };
 
 /*
-- 
2.43.0


Reply via email to