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
