From de2cc4078240f8b745a7caeed461b02f2577e2d2 Mon Sep 17 00:00:00 2001 From: Kyoungrul Kim Date: Fri, 2 Aug 2024 14:19:02 +0900 Subject: [PATCH 1/5] hw/ufs: add basic info of query response upiu Modify to fill the opcode, idn, index, selector information of all Query Response UPIU. because attr and flag operation of query response upiu need these information too. Signed-off-by: KyoungrulKim Reviewed-by: Minwoo Im Reviewed-by: Jeuk Kim Signed-off-by: Jeuk Kim --- hw/ufs/ufs.c | 13 +++++++++---- hw/ufs/ufs.h | 1 + 2 files changed, 10 insertions(+), 4 deletions(-) diff --git a/hw/ufs/ufs.c b/hw/ufs/ufs.c index 945a0ea127..ce2c96aeea 100644 --- a/hw/ufs/ufs.c +++ b/hw/ufs/ufs.c @@ -851,6 +851,14 @@ void ufs_build_upiu_header(UfsRequest *req, uint8_t trans_type, uint8_t flags, req->rsp_upiu.header.data_segment_length = cpu_to_be16(data_segment_length); } +void ufs_build_query_response(UfsRequest *req) +{ + req->rsp_upiu.qr.opcode = req->req_upiu.qr.opcode; + req->rsp_upiu.qr.idn = req->req_upiu.qr.idn; + req->rsp_upiu.qr.index = req->req_upiu.qr.index; + req->rsp_upiu.qr.selector = req->req_upiu.qr.selector; +} + static UfsReqResult ufs_exec_scsi_cmd(UfsRequest *req) { UfsHc *u = req->hc; @@ -1327,10 +1335,6 @@ static QueryRespCode ufs_read_desc(UfsRequest *req) if (length > req->rsp_upiu.qr.data[0]) { length = req->rsp_upiu.qr.data[0]; } - req->rsp_upiu.qr.opcode = req->req_upiu.qr.opcode; - req->rsp_upiu.qr.idn = req->req_upiu.qr.idn; - req->rsp_upiu.qr.index = req->req_upiu.qr.index; - req->rsp_upiu.qr.selector = req->req_upiu.qr.selector; req->rsp_upiu.qr.length = cpu_to_be16(length); return status; @@ -1411,6 +1415,7 @@ static UfsReqResult ufs_exec_query_cmd(UfsRequest *req) data_segment_length = be16_to_cpu(req->rsp_upiu.qr.length); ufs_build_upiu_header(req, UFS_UPIU_TRANSACTION_QUERY_RSP, 0, status, 0, data_segment_length); + ufs_build_query_response(req); if (status != UFS_QUERY_RESULT_SUCCESS) { return UFS_REQUEST_FAIL; diff --git a/hw/ufs/ufs.h b/hw/ufs/ufs.h index 6c9382cbc4..4bcc41f53a 100644 --- a/hw/ufs/ufs.h +++ b/hw/ufs/ufs.h @@ -228,6 +228,7 @@ static inline bool is_wlun(uint8_t lun) void ufs_build_upiu_header(UfsRequest *req, uint8_t trans_type, uint8_t flags, uint8_t response, uint8_t scsi_status, uint16_t data_segment_length); +void ufs_build_query_response(UfsRequest *req); void ufs_complete_req(UfsRequest *req, UfsReqResult req_result); void ufs_init_wlu(UfsLu *wlu, uint8_t wlun); #endif /* HW_UFS_UFS_H */ From 7c85332a2b3e8d58db209f29afca740d2f0cd6e7 Mon Sep 17 00:00:00 2001 From: Yoochan Jeong Date: Thu, 22 Aug 2024 17:09:50 +0900 Subject: [PATCH 2/5] hw/ufs: minor bug fixes related to ufs-test Minor bugs and errors related to ufs-test are resolved. Some permissions and code implementations that are not synchronized with the ufs spec are edited. Signed-off-by: Yoochan Jeong Reviewed-by: Jeuk Kim Signed-off-by: Jeuk Kim --- hw/ufs/ufs.c | 19 +++++++++++++------ include/block/ufs.h | 6 ++++++ tests/qtest/ufs-test.c | 11 ++++++++--- 3 files changed, 27 insertions(+), 9 deletions(-) diff --git a/hw/ufs/ufs.c b/hw/ufs/ufs.c index ce2c96aeea..79f786ed4e 100644 --- a/hw/ufs/ufs.c +++ b/hw/ufs/ufs.c @@ -1111,10 +1111,13 @@ static uint32_t ufs_read_attr_value(UfsHc *u, uint8_t idn) return 0; } -static void ufs_write_attr_value(UfsHc *u, uint8_t idn, uint32_t value) +static QueryRespCode ufs_write_attr_value(UfsHc *u, uint8_t idn, uint32_t value) { switch (idn) { case UFS_QUERY_ATTR_IDN_ACTIVE_ICC_LVL: + if (value > UFS_QUERY_ATTR_ACTIVE_ICC_MAXVALUE) { + return UFS_QUERY_RESULT_INVALID_VALUE; + } u->attributes.active_icc_level = value; break; case UFS_QUERY_ATTR_IDN_MAX_DATA_IN: @@ -1142,6 +1145,7 @@ static void ufs_write_attr_value(UfsHc *u, uint8_t idn, uint32_t value) u->attributes.psa_data_size = cpu_to_be32(value); break; } + return UFS_QUERY_RESULT_SUCCESS; } static QueryRespCode ufs_exec_query_attr(UfsRequest *req, int op) @@ -1158,13 +1162,13 @@ static QueryRespCode ufs_exec_query_attr(UfsRequest *req, int op) if (op == UFS_QUERY_ATTR_READ) { value = ufs_read_attr_value(u, idn); + ret = UFS_QUERY_RESULT_SUCCESS; } else { - value = be32_to_cpu(req->req_upiu.qr.value); - ufs_write_attr_value(u, idn, value); + value = req->req_upiu.qr.value; + ret = ufs_write_attr_value(u, idn, value); } - req->rsp_upiu.qr.value = cpu_to_be32(value); - return UFS_QUERY_RESULT_SUCCESS; + return ret; } static const RpmbUnitDescriptor rpmb_unit_desc = { @@ -1287,9 +1291,12 @@ static QueryRespCode ufs_read_desc(UfsRequest *req) UfsHc *u = req->hc; QueryRespCode status; uint8_t idn = req->req_upiu.qr.idn; + uint8_t selector = req->req_upiu.qr.selector; uint16_t length = be16_to_cpu(req->req_upiu.qr.length); InterconnectDescriptor desc; - + if (selector != 0) { + return UFS_QUERY_RESULT_INVALID_SELECTOR; + } switch (idn) { case UFS_QUERY_DESC_IDN_DEVICE: memcpy(&req->rsp_upiu.qr.data, &u->device_desc, sizeof(u->device_desc)); diff --git a/include/block/ufs.h b/include/block/ufs.h index 92da7a89b9..57f5ea3500 100644 --- a/include/block/ufs.h +++ b/include/block/ufs.h @@ -763,6 +763,12 @@ typedef struct QEMU_PACKED UtpTaskReqDesc { */ #define UFS_WB_EXCEED_LIFETIME 0x0B +/* + * The range of valid value of Active ICC attritbute + * is from 0x00 to 0x0F. + */ +#define UFS_QUERY_ATTR_ACTIVE_ICC_MAXVALUE 0x0F + /* * In UFS Spec, the Extra Header Segment (EHS) starts from byte 32 in UPIU * request/response packet diff --git a/tests/qtest/ufs-test.c b/tests/qtest/ufs-test.c index 82ec3f0671..9cc9e578ff 100644 --- a/tests/qtest/ufs-test.c +++ b/tests/qtest/ufs-test.c @@ -119,6 +119,7 @@ static void ufs_send_nop_out(QUfs *ufs, uint8_t slot, static void ufs_send_query(QUfs *ufs, uint8_t slot, uint8_t query_function, uint8_t query_opcode, uint8_t idn, uint8_t index, + uint8_t selector, uint32_t attr_value, UtpTransferReqDesc *utrd_out, UtpUpiuRsp *rsp_out) { /* Build up utp transfer request descriptor */ @@ -136,13 +137,16 @@ static void ufs_send_query(QUfs *ufs, uint8_t slot, uint8_t query_function, req_upiu.header.query_func = query_function; req_upiu.header.task_tag = slot; /* - * QEMU UFS does not currently support Write descriptor and Write attribute, + * QEMU UFS does not currently support Write descriptor, * so the value of data_segment_length is always 0. */ req_upiu.header.data_segment_length = 0; req_upiu.qr.opcode = query_opcode; req_upiu.qr.idn = idn; req_upiu.qr.index = index; + req_upiu.qr.selector = selector; + req_upiu.qr.value = attr_value; + req_upiu.qr.length = UFS_QUERY_DESC_MAX_SIZE; qtest_memwrite(ufs->dev.bus->qts, req_upiu_addr, &req_upiu, sizeof(req_upiu)); @@ -344,7 +348,7 @@ static void ufs_init(QUfs *ufs, QGuestAllocator *alloc) /* Set fDeviceInit flag via query request */ ufs_send_query(ufs, 0, UFS_UPIU_QUERY_FUNC_STANDARD_WRITE_REQUEST, UFS_UPIU_QUERY_OPCODE_SET_FLAG, - UFS_QUERY_FLAG_IDN_FDEVICEINIT, 0, &utrd, &rsp_upiu); + UFS_QUERY_FLAG_IDN_FDEVICEINIT, 0, 0, 0, &utrd, &rsp_upiu); g_assert_cmpuint(le32_to_cpu(utrd.header.dword_2), ==, UFS_OCS_SUCCESS); /* Wait for device to reset */ @@ -353,7 +357,8 @@ static void ufs_init(QUfs *ufs, QGuestAllocator *alloc) qtest_clock_step(ufs->dev.bus->qts, 100); ufs_send_query(ufs, 0, UFS_UPIU_QUERY_FUNC_STANDARD_READ_REQUEST, UFS_UPIU_QUERY_OPCODE_READ_FLAG, - UFS_QUERY_FLAG_IDN_FDEVICEINIT, 0, &utrd, &rsp_upiu); + UFS_QUERY_FLAG_IDN_FDEVICEINIT, 0, 0, 0, &utrd, + &rsp_upiu); } while (be32_to_cpu(rsp_upiu.qr.value) != 0 && g_get_monotonic_time() < end_time); g_assert_cmpuint(be32_to_cpu(rsp_upiu.qr.value), ==, 0); From 4aac30299b742f594f52016d4133487ad33459e7 Mon Sep 17 00:00:00 2001 From: Yoochan Jeong Date: Thu, 22 Aug 2024 17:10:36 +0900 Subject: [PATCH 3/5] hw/ufs: ufs flag read/write test implemented New test function "ufstest_flag_request" added, which can check one's virtual UFS device can properly read and write its flag data. It tests if reading, setting, clearing and toggling flags work properly. There are some testcases that are intended to make an error caused by permission issues. Signed-off-by: Yoochan Jeong Reviewed-by: Jeuk Kim Signed-off-by: Jeuk Kim --- tests/qtest/ufs-test.c | 83 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 83 insertions(+) diff --git a/tests/qtest/ufs-test.c b/tests/qtest/ufs-test.c index 9cc9e578ff..9f45a078e7 100644 --- a/tests/qtest/ufs-test.c +++ b/tests/qtest/ufs-test.c @@ -539,6 +539,87 @@ static void ufstest_read_write(void *obj, void *data, QGuestAllocator *alloc) ufs_exit(ufs, alloc); } +static void ufstest_query_flag_request(void *obj, void *data, + QGuestAllocator *alloc) +{ + QUfs *ufs = obj; + + UtpTransferReqDesc utrd; + UtpUpiuRsp rsp_upiu; + ufs_init(ufs, alloc); + + /* Read read-only flag */ + ufs_send_query(ufs, 0, UFS_UPIU_QUERY_FUNC_STANDARD_READ_REQUEST, + UFS_UPIU_QUERY_OPCODE_READ_FLAG, + UFS_QUERY_FLAG_IDN_FDEVICEINIT, 0, 0, 0, &utrd, &rsp_upiu); + g_assert_cmpuint(le32_to_cpu(utrd.header.dword_2), ==, UFS_OCS_SUCCESS); + g_assert_cmpuint(rsp_upiu.header.response, ==, UFS_COMMAND_RESULT_SUCCESS); + g_assert_cmpuint(rsp_upiu.qr.opcode, ==, UFS_UPIU_QUERY_OPCODE_READ_FLAG); + g_assert_cmpuint(rsp_upiu.qr.idn, ==, UFS_QUERY_FLAG_IDN_FDEVICEINIT); + g_assert_cmpuint(rsp_upiu.qr.value, ==, be32_to_cpu(0)); + + /* Flag Set, Clear, Toggle Test with fDeviceLifeSpanModeEn */ + ufs_send_query(ufs, 0, UFS_UPIU_QUERY_FUNC_STANDARD_READ_REQUEST, + UFS_UPIU_QUERY_OPCODE_READ_FLAG, + UFS_QUERY_FLAG_IDN_LIFE_SPAN_MODE_ENABLE, 0, 0, 0, &utrd, + &rsp_upiu); + g_assert_cmpuint(le32_to_cpu(utrd.header.dword_2), ==, UFS_OCS_SUCCESS); + g_assert_cmpuint(rsp_upiu.header.response, ==, UFS_COMMAND_RESULT_SUCCESS); + g_assert_cmpuint(rsp_upiu.qr.value, ==, be32_to_cpu(0)); + + ufs_send_query(ufs, 0, UFS_UPIU_QUERY_FUNC_STANDARD_WRITE_REQUEST, + UFS_UPIU_QUERY_OPCODE_SET_FLAG, + UFS_QUERY_FLAG_IDN_LIFE_SPAN_MODE_ENABLE, 0, 0, 0, &utrd, + &rsp_upiu); + g_assert_cmpuint(le32_to_cpu(utrd.header.dword_2), ==, UFS_OCS_SUCCESS); + g_assert_cmpuint(rsp_upiu.header.response, ==, UFS_COMMAND_RESULT_SUCCESS); + g_assert_cmpuint(rsp_upiu.qr.value, ==, be32_to_cpu(1)); + + ufs_send_query(ufs, 0, UFS_UPIU_QUERY_FUNC_STANDARD_WRITE_REQUEST, + UFS_UPIU_QUERY_OPCODE_CLEAR_FLAG, + UFS_QUERY_FLAG_IDN_LIFE_SPAN_MODE_ENABLE, 0, 0, 0, &utrd, + &rsp_upiu); + g_assert_cmpuint(le32_to_cpu(utrd.header.dword_2), ==, UFS_OCS_SUCCESS); + g_assert_cmpuint(rsp_upiu.header.response, ==, UFS_COMMAND_RESULT_SUCCESS); + g_assert_cmpuint(rsp_upiu.qr.value, ==, be32_to_cpu(0)); + + ufs_send_query(ufs, 0, UFS_UPIU_QUERY_FUNC_STANDARD_WRITE_REQUEST, + UFS_UPIU_QUERY_OPCODE_TOGGLE_FLAG, + UFS_QUERY_FLAG_IDN_LIFE_SPAN_MODE_ENABLE, 0, 0, 0, &utrd, + &rsp_upiu); + g_assert_cmpuint(le32_to_cpu(utrd.header.dword_2), ==, UFS_OCS_SUCCESS); + g_assert_cmpuint(rsp_upiu.header.response, ==, UFS_COMMAND_RESULT_SUCCESS); + g_assert_cmpuint(rsp_upiu.qr.value, ==, be32_to_cpu(1)); + + ufs_send_query(ufs, 0, UFS_UPIU_QUERY_FUNC_STANDARD_WRITE_REQUEST, + UFS_UPIU_QUERY_OPCODE_TOGGLE_FLAG, + UFS_QUERY_FLAG_IDN_LIFE_SPAN_MODE_ENABLE, 0, 0, 0, &utrd, + &rsp_upiu); + g_assert_cmpuint(le32_to_cpu(utrd.header.dword_2), ==, UFS_OCS_SUCCESS); + g_assert_cmpuint(rsp_upiu.header.response, ==, UFS_COMMAND_RESULT_SUCCESS); + g_assert_cmpuint(rsp_upiu.qr.value, ==, be32_to_cpu(0)); + + /* Read Write-only Flag (Intended Failure) */ + ufs_send_query(ufs, 0, UFS_UPIU_QUERY_FUNC_STANDARD_READ_REQUEST, + UFS_UPIU_QUERY_OPCODE_READ_FLAG, + UFS_QUERY_FLAG_IDN_PURGE_ENABLE, 0, 0, 0, &utrd, &rsp_upiu); + g_assert_cmpuint(le32_to_cpu(utrd.header.dword_2), ==, + UFS_OCS_INVALID_CMD_TABLE_ATTR); + g_assert_cmpuint(rsp_upiu.header.response, ==, + UFS_QUERY_RESULT_NOT_READABLE); + + /* Write Read-Only Flag (Intended Failure) */ + ufs_send_query(ufs, 0, UFS_UPIU_QUERY_FUNC_STANDARD_WRITE_REQUEST, + UFS_UPIU_QUERY_OPCODE_SET_FLAG, UFS_QUERY_FLAG_IDN_BUSY_RTC, + 0, 0, 0, &utrd, &rsp_upiu); + g_assert_cmpuint(le32_to_cpu(utrd.header.dword_2), ==, + UFS_OCS_INVALID_CMD_TABLE_ATTR); + g_assert_cmpuint(rsp_upiu.header.response, ==, + UFS_QUERY_RESULT_NOT_WRITEABLE); + + ufs_exit(ufs, alloc); +} + static void drive_destroy(void *path) { unlink(path); @@ -606,6 +687,8 @@ static void ufs_register_nodes(void) } qos_add_test("init", "ufs", ufstest_init, NULL); qos_add_test("read-write", "ufs", ufstest_read_write, &io_test_opts); + qos_add_test("flag read-write", "ufs", + ufstest_query_flag_request, &io_test_opts); } libqos_init(ufs_register_nodes); From 49ccea4be9400a29477ab20fe959629786b076fd Mon Sep 17 00:00:00 2001 From: Yoochan Jeong Date: Thu, 22 Aug 2024 17:11:51 +0900 Subject: [PATCH 4/5] hw/ufs: ufs attribute read/write test implemented New test function "ufstest_query_attr_request" added, which can check one's virtual UFS device can properly read and write its attribute data. It tests if reading and writing attributes work properly. There are some testcases that are intended to make an error caused by writing an invalid value, allocating an invalid selector and permission issues. Signed-off-by: Yoochan Jeong Reviewed-by: Jeuk Kim Signed-off-by: Jeuk Kim --- tests/qtest/ufs-test.c | 137 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 137 insertions(+) diff --git a/tests/qtest/ufs-test.c b/tests/qtest/ufs-test.c index 9f45a078e7..061371414a 100644 --- a/tests/qtest/ufs-test.c +++ b/tests/qtest/ufs-test.c @@ -620,6 +620,141 @@ static void ufstest_query_flag_request(void *obj, void *data, ufs_exit(ufs, alloc); } +static void ufstest_query_attr_request(void *obj, void *data, + QGuestAllocator *alloc) +{ + QUfs *ufs = obj; + + UtpTransferReqDesc utrd; + UtpUpiuRsp rsp_upiu; + ufs_init(ufs, alloc); + + /* Read Readable Attributes*/ + ufs_send_query(ufs, 0, UFS_UPIU_QUERY_FUNC_STANDARD_READ_REQUEST, + UFS_UPIU_QUERY_OPCODE_READ_ATTR, + UFS_QUERY_ATTR_IDN_BOOT_LU_EN, 0, 0, 0, &utrd, &rsp_upiu); + g_assert_cmpuint(le32_to_cpu(utrd.header.dword_2), ==, UFS_OCS_SUCCESS); + g_assert_cmpuint(rsp_upiu.header.response, ==, UFS_COMMAND_RESULT_SUCCESS); + g_assert_cmpuint(rsp_upiu.qr.opcode, ==, UFS_UPIU_QUERY_OPCODE_READ_ATTR); + g_assert_cmpuint(rsp_upiu.qr.idn, ==, UFS_QUERY_ATTR_IDN_BOOT_LU_EN); + g_assert_cmpuint(rsp_upiu.qr.value, ==, cpu_to_be32(0x00)); + + ufs_send_query(ufs, 0, UFS_UPIU_QUERY_FUNC_STANDARD_READ_REQUEST, + UFS_UPIU_QUERY_OPCODE_READ_ATTR, + UFS_QUERY_ATTR_IDN_BKOPS_STATUS, 0, 0, 0, &utrd, &rsp_upiu); + g_assert_cmpuint(le32_to_cpu(utrd.header.dword_2), ==, UFS_OCS_SUCCESS); + g_assert_cmpuint(rsp_upiu.header.response, ==, UFS_COMMAND_RESULT_SUCCESS); + g_assert_cmpuint(rsp_upiu.qr.value, ==, cpu_to_be32(0x00)); + + /* Write Writable Attributes & Read Again */ + ufs_send_query(ufs, 0, UFS_UPIU_QUERY_FUNC_STANDARD_WRITE_REQUEST, + UFS_UPIU_QUERY_OPCODE_WRITE_ATTR, + UFS_QUERY_ATTR_IDN_ACTIVE_ICC_LVL, 0, 0, 0x03, &utrd, + &rsp_upiu); + g_assert_cmpuint(le32_to_cpu(utrd.header.dword_2), ==, UFS_OCS_SUCCESS); + g_assert_cmpuint(rsp_upiu.header.response, ==, UFS_COMMAND_RESULT_SUCCESS); + g_assert_cmpuint(rsp_upiu.qr.value, ==, cpu_to_be32(0x03)); + + ufs_send_query(ufs, 0, UFS_UPIU_QUERY_FUNC_STANDARD_WRITE_REQUEST, + UFS_UPIU_QUERY_OPCODE_WRITE_ATTR, + UFS_QUERY_ATTR_IDN_EE_CONTROL, 0, 0, 0x07, &utrd, &rsp_upiu); + g_assert_cmpuint(le32_to_cpu(utrd.header.dword_2), ==, UFS_OCS_SUCCESS); + g_assert_cmpuint(rsp_upiu.header.response, ==, UFS_COMMAND_RESULT_SUCCESS); + g_assert_cmpuint(rsp_upiu.qr.value, ==, cpu_to_be32(0x07)); + + ufs_send_query(ufs, 0, UFS_UPIU_QUERY_FUNC_STANDARD_READ_REQUEST, + UFS_UPIU_QUERY_OPCODE_READ_ATTR, + UFS_QUERY_ATTR_IDN_ACTIVE_ICC_LVL, 0, 0, 0, &utrd, + &rsp_upiu); + g_assert_cmpuint(le32_to_cpu(utrd.header.dword_2), ==, UFS_OCS_SUCCESS); + g_assert_cmpuint(rsp_upiu.header.response, ==, UFS_COMMAND_RESULT_SUCCESS); + g_assert_cmpuint(rsp_upiu.qr.value, ==, cpu_to_be32(0x03)); + + ufs_send_query(ufs, 0, UFS_UPIU_QUERY_FUNC_STANDARD_READ_REQUEST, + UFS_UPIU_QUERY_OPCODE_READ_ATTR, + UFS_QUERY_ATTR_IDN_EE_CONTROL, 0, 0, 0, &utrd, &rsp_upiu); + g_assert_cmpuint(le32_to_cpu(utrd.header.dword_2), ==, UFS_OCS_SUCCESS); + g_assert_cmpuint(rsp_upiu.header.response, ==, UFS_COMMAND_RESULT_SUCCESS); + g_assert_cmpuint(rsp_upiu.qr.value, ==, cpu_to_be32(0x07)); + + /* Write Invalid Value (Intended Error) */ + ufs_send_query(ufs, 0, UFS_UPIU_QUERY_FUNC_STANDARD_WRITE_REQUEST, + UFS_UPIU_QUERY_OPCODE_WRITE_ATTR, + UFS_QUERY_ATTR_IDN_ACTIVE_ICC_LVL, 0, 0, 0x10, &utrd, + &rsp_upiu); + g_assert_cmpuint(le32_to_cpu(utrd.header.dword_2), ==, + UFS_OCS_INVALID_CMD_TABLE_ATTR); + g_assert_cmpuint(rsp_upiu.header.response, ==, + UFS_QUERY_RESULT_INVALID_VALUE); + + ufs_send_query(ufs, 0, UFS_UPIU_QUERY_FUNC_STANDARD_READ_REQUEST, + UFS_UPIU_QUERY_OPCODE_READ_ATTR, + UFS_QUERY_ATTR_IDN_ACTIVE_ICC_LVL, 0, 0, 0, &utrd, + &rsp_upiu); + g_assert_cmpuint(le32_to_cpu(utrd.header.dword_2), ==, UFS_OCS_SUCCESS); + g_assert_cmpuint(rsp_upiu.header.response, ==, UFS_COMMAND_RESULT_SUCCESS); + g_assert_cmpuint(rsp_upiu.qr.value, ==, cpu_to_be32(0x03)); + + /* Read Write-Only Attribute (Intended Error) */ + ufs_send_query(ufs, 0, UFS_UPIU_QUERY_FUNC_STANDARD_READ_REQUEST, + UFS_UPIU_QUERY_OPCODE_READ_ATTR, + UFS_QUERY_ATTR_IDN_SECONDS_PASSED, 0, 0, 0, &utrd, + &rsp_upiu); + g_assert_cmpuint(le32_to_cpu(utrd.header.dword_2), ==, + UFS_OCS_INVALID_CMD_TABLE_ATTR); + g_assert_cmpuint(rsp_upiu.header.response, ==, + UFS_QUERY_RESULT_NOT_READABLE); + + /* Write Read-Only Attribute (Intended Error) */ + ufs_send_query(ufs, 0, UFS_UPIU_QUERY_FUNC_STANDARD_WRITE_REQUEST, + UFS_UPIU_QUERY_OPCODE_WRITE_ATTR, + UFS_QUERY_ATTR_IDN_POWER_MODE, 0, 0, 0x01, &utrd, &rsp_upiu); + g_assert_cmpuint(le32_to_cpu(utrd.header.dword_2), ==, + UFS_OCS_INVALID_CMD_TABLE_ATTR); + g_assert_cmpuint(rsp_upiu.header.response, ==, + UFS_QUERY_RESULT_NOT_WRITEABLE); + + ufs_send_query(ufs, 0, UFS_UPIU_QUERY_FUNC_STANDARD_READ_REQUEST, + UFS_UPIU_QUERY_OPCODE_READ_ATTR, + UFS_QUERY_ATTR_IDN_POWER_MODE, 0, 0, 0, &utrd, &rsp_upiu); + g_assert_cmpuint(le32_to_cpu(utrd.header.dword_2), ==, UFS_OCS_SUCCESS); + g_assert_cmpuint(rsp_upiu.header.response, ==, UFS_COMMAND_RESULT_SUCCESS); + g_assert_cmpuint(rsp_upiu.qr.value, ==, cpu_to_be32(0x00)); + + /* Reset Written Attributes */ + ufs_send_query(ufs, 0, UFS_UPIU_QUERY_FUNC_STANDARD_WRITE_REQUEST, + UFS_UPIU_QUERY_OPCODE_WRITE_ATTR, + UFS_QUERY_ATTR_IDN_ACTIVE_ICC_LVL, 0, 0, 0, &utrd, + &rsp_upiu); + g_assert_cmpuint(le32_to_cpu(utrd.header.dword_2), ==, UFS_OCS_SUCCESS); + g_assert_cmpuint(rsp_upiu.header.response, ==, UFS_COMMAND_RESULT_SUCCESS); + g_assert_cmpuint(rsp_upiu.qr.value, ==, cpu_to_be32(0x00)); + + ufs_send_query(ufs, 0, UFS_UPIU_QUERY_FUNC_STANDARD_WRITE_REQUEST, + UFS_UPIU_QUERY_OPCODE_WRITE_ATTR, + UFS_QUERY_ATTR_IDN_EE_CONTROL, 0, 0, 0, &utrd, &rsp_upiu); + g_assert_cmpuint(le32_to_cpu(utrd.header.dword_2), ==, UFS_OCS_SUCCESS); + g_assert_cmpuint(rsp_upiu.header.response, ==, UFS_COMMAND_RESULT_SUCCESS); + g_assert_cmpuint(rsp_upiu.qr.value, ==, cpu_to_be32(0x00)); + + ufs_send_query(ufs, 0, UFS_UPIU_QUERY_FUNC_STANDARD_READ_REQUEST, + UFS_UPIU_QUERY_OPCODE_READ_ATTR, + UFS_QUERY_ATTR_IDN_ACTIVE_ICC_LVL, 0, 0, 0, &utrd, + &rsp_upiu); + g_assert_cmpuint(le32_to_cpu(utrd.header.dword_2), ==, UFS_OCS_SUCCESS); + g_assert_cmpuint(rsp_upiu.header.response, ==, UFS_COMMAND_RESULT_SUCCESS); + g_assert_cmpuint(rsp_upiu.qr.value, ==, cpu_to_be32(0x00)); + + ufs_send_query(ufs, 0, UFS_UPIU_QUERY_FUNC_STANDARD_READ_REQUEST, + UFS_UPIU_QUERY_OPCODE_READ_ATTR, + UFS_QUERY_ATTR_IDN_EE_CONTROL, 0, 0, 0, &utrd, &rsp_upiu); + g_assert_cmpuint(le32_to_cpu(utrd.header.dword_2), ==, UFS_OCS_SUCCESS); + g_assert_cmpuint(rsp_upiu.header.response, ==, UFS_COMMAND_RESULT_SUCCESS); + g_assert_cmpuint(rsp_upiu.qr.value, ==, cpu_to_be32(0x00)); + + ufs_exit(ufs, alloc); +} + static void drive_destroy(void *path) { unlink(path); @@ -689,6 +824,8 @@ static void ufs_register_nodes(void) qos_add_test("read-write", "ufs", ufstest_read_write, &io_test_opts); qos_add_test("flag read-write", "ufs", ufstest_query_flag_request, &io_test_opts); + qos_add_test("attr read-write", "ufs", + ufstest_query_attr_request, &io_test_opts); } libqos_init(ufs_register_nodes); From 9fe8e2c68ad99e503a11390b868a7dad846e7a0d Mon Sep 17 00:00:00 2001 From: Yoochan Jeong Date: Thu, 22 Aug 2024 17:12:50 +0900 Subject: [PATCH 5/5] hw/ufs: ufs descriptor read test implemented New test function "ufstest_query_desc_request" added, which can check one's virtual UFS device can properly read and its descriptor data. (Writing descriptors are not implemented yet.) The testcases attempt to read all kinds of descriptors at least once, except for configuration descriptors (which are not implemented yet.) There are some testcases that are intended to make an error caused by an invalid index value or an invalid selector value. Signed-off-by: Yoochan Jeong Reviewed-by: Jeuk Kim Signed-off-by: Jeuk Kim --- tests/qtest/ufs-test.c | 153 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 153 insertions(+) diff --git a/tests/qtest/ufs-test.c b/tests/qtest/ufs-test.c index 061371414a..60199abbee 100644 --- a/tests/qtest/ufs-test.c +++ b/tests/qtest/ufs-test.c @@ -755,6 +755,157 @@ static void ufstest_query_attr_request(void *obj, void *data, ufs_exit(ufs, alloc); } +static void ufstest_query_desc_request(void *obj, void *data, + QGuestAllocator *alloc) +{ + QUfs *ufs = obj; + + UtpTransferReqDesc utrd; + UtpUpiuRsp rsp_upiu; + ufs_init(ufs, alloc); + + /* Write Descriptor is not supported yet */ + + /* Read Device Descriptor */ + ufs_send_query(ufs, 0, UFS_UPIU_QUERY_FUNC_STANDARD_READ_REQUEST, + UFS_UPIU_QUERY_OPCODE_READ_DESC, UFS_QUERY_DESC_IDN_DEVICE, + 0, 0, 0, &utrd, &rsp_upiu); + g_assert_cmpuint(le32_to_cpu(utrd.header.dword_2), ==, UFS_OCS_SUCCESS); + g_assert_cmpuint(rsp_upiu.header.response, ==, UFS_COMMAND_RESULT_SUCCESS); + g_assert_cmpuint(rsp_upiu.qr.opcode, ==, UFS_UPIU_QUERY_OPCODE_READ_DESC); + g_assert_cmpuint(rsp_upiu.qr.idn, ==, UFS_QUERY_DESC_IDN_DEVICE); + g_assert_cmpuint(rsp_upiu.qr.data[0], ==, sizeof(DeviceDescriptor)); + g_assert_cmpuint(rsp_upiu.qr.data[1], ==, UFS_QUERY_DESC_IDN_DEVICE); + + /* Read Configuration Descriptor is not supported yet*/ + + /* Read Unit Descriptor */ + ufs_send_query(ufs, 0, UFS_UPIU_QUERY_FUNC_STANDARD_READ_REQUEST, + UFS_UPIU_QUERY_OPCODE_READ_DESC, UFS_QUERY_DESC_IDN_UNIT, 0, + 0, 0, &utrd, &rsp_upiu); + g_assert_cmpuint(le32_to_cpu(utrd.header.dword_2), ==, UFS_OCS_SUCCESS); + g_assert_cmpuint(rsp_upiu.header.response, ==, UFS_COMMAND_RESULT_SUCCESS); + g_assert_cmpuint(rsp_upiu.qr.data[0], ==, sizeof(UnitDescriptor)); + g_assert_cmpuint(rsp_upiu.qr.data[1], ==, UFS_QUERY_DESC_IDN_UNIT); + g_assert_cmpuint(rsp_upiu.qr.data[2], ==, 0); + + ufs_send_query(ufs, 0, UFS_UPIU_QUERY_FUNC_STANDARD_READ_REQUEST, + UFS_UPIU_QUERY_OPCODE_READ_DESC, UFS_QUERY_DESC_IDN_UNIT, 1, + 0, 0, &utrd, &rsp_upiu); + g_assert_cmpuint(le32_to_cpu(utrd.header.dword_2), ==, UFS_OCS_SUCCESS); + g_assert_cmpuint(rsp_upiu.header.response, ==, UFS_COMMAND_RESULT_SUCCESS); + g_assert_cmpuint(rsp_upiu.qr.data[0], ==, sizeof(UnitDescriptor)); + g_assert_cmpuint(rsp_upiu.qr.data[1], ==, UFS_QUERY_DESC_IDN_UNIT); + g_assert_cmpuint(rsp_upiu.qr.data[2], ==, 1); + + ufs_send_query(ufs, 0, UFS_UPIU_QUERY_FUNC_STANDARD_READ_REQUEST, + UFS_UPIU_QUERY_OPCODE_READ_DESC, UFS_QUERY_DESC_IDN_UNIT, + UFS_UPIU_RPMB_WLUN, 0, 0, &utrd, &rsp_upiu); + g_assert_cmpuint(le32_to_cpu(utrd.header.dword_2), ==, UFS_OCS_SUCCESS); + g_assert_cmpuint(rsp_upiu.header.response, ==, UFS_COMMAND_RESULT_SUCCESS); + g_assert_cmpuint(rsp_upiu.qr.data[0], ==, sizeof(RpmbUnitDescriptor)); + g_assert_cmpuint(rsp_upiu.qr.data[1], ==, UFS_QUERY_DESC_IDN_UNIT); + g_assert_cmpuint(rsp_upiu.qr.data[2], ==, UFS_UPIU_RPMB_WLUN); + + /* Read Interconnect Descriptor */ + ufs_send_query(ufs, 0, UFS_UPIU_QUERY_FUNC_STANDARD_READ_REQUEST, + UFS_UPIU_QUERY_OPCODE_READ_DESC, + UFS_QUERY_DESC_IDN_INTERCONNECT, 0, 0, 0, &utrd, &rsp_upiu); + g_assert_cmpuint(le32_to_cpu(utrd.header.dword_2), ==, UFS_OCS_SUCCESS); + g_assert_cmpuint(rsp_upiu.header.response, ==, UFS_COMMAND_RESULT_SUCCESS); + g_assert_cmpuint(rsp_upiu.qr.data[0], ==, sizeof(InterconnectDescriptor)); + g_assert_cmpuint(rsp_upiu.qr.data[1], ==, UFS_QUERY_DESC_IDN_INTERCONNECT); + + /* Read String Descriptor */ + ufs_send_query(ufs, 0, UFS_UPIU_QUERY_FUNC_STANDARD_READ_REQUEST, + UFS_UPIU_QUERY_OPCODE_READ_DESC, UFS_QUERY_DESC_IDN_STRING, + 0, 0, 0, &utrd, &rsp_upiu); + g_assert_cmpuint(le32_to_cpu(utrd.header.dword_2), ==, UFS_OCS_SUCCESS); + g_assert_cmpuint(rsp_upiu.header.response, ==, UFS_COMMAND_RESULT_SUCCESS); + g_assert_cmpuint(rsp_upiu.qr.data[0], ==, 0x12); + g_assert_cmpuint(rsp_upiu.qr.data[1], ==, UFS_QUERY_DESC_IDN_STRING); + + ufs_send_query(ufs, 0, UFS_UPIU_QUERY_FUNC_STANDARD_READ_REQUEST, + UFS_UPIU_QUERY_OPCODE_READ_DESC, UFS_QUERY_DESC_IDN_STRING, + 1, 0, 0, &utrd, &rsp_upiu); + g_assert_cmpuint(le32_to_cpu(utrd.header.dword_2), ==, UFS_OCS_SUCCESS); + g_assert_cmpuint(rsp_upiu.header.response, ==, UFS_COMMAND_RESULT_SUCCESS); + g_assert_cmpuint(rsp_upiu.qr.data[0], ==, 0x22); + g_assert_cmpuint(rsp_upiu.qr.data[1], ==, UFS_QUERY_DESC_IDN_STRING); + + ufs_send_query(ufs, 0, UFS_UPIU_QUERY_FUNC_STANDARD_READ_REQUEST, + UFS_UPIU_QUERY_OPCODE_READ_DESC, UFS_QUERY_DESC_IDN_STRING, + 4, 0, 0, &utrd, &rsp_upiu); + g_assert_cmpuint(le32_to_cpu(utrd.header.dword_2), ==, UFS_OCS_SUCCESS); + g_assert_cmpuint(rsp_upiu.header.response, ==, UFS_COMMAND_RESULT_SUCCESS); + g_assert_cmpuint(rsp_upiu.qr.data[0], ==, 0x0a); + g_assert_cmpuint(rsp_upiu.qr.data[1], ==, UFS_QUERY_DESC_IDN_STRING); + + /* Read Geometry Descriptor */ + ufs_send_query(ufs, 0, UFS_UPIU_QUERY_FUNC_STANDARD_READ_REQUEST, + UFS_UPIU_QUERY_OPCODE_READ_DESC, UFS_QUERY_DESC_IDN_GEOMETRY, + 0, 0, 0, &utrd, &rsp_upiu); + g_assert_cmpuint(le32_to_cpu(utrd.header.dword_2), ==, UFS_OCS_SUCCESS); + g_assert_cmpuint(rsp_upiu.header.response, ==, UFS_COMMAND_RESULT_SUCCESS); + g_assert_cmpuint(rsp_upiu.qr.data[0], ==, sizeof(GeometryDescriptor)); + g_assert_cmpuint(rsp_upiu.qr.data[1], ==, UFS_QUERY_DESC_IDN_GEOMETRY); + + /* Read Power Descriptor */ + ufs_send_query(ufs, 0, UFS_UPIU_QUERY_FUNC_STANDARD_READ_REQUEST, + UFS_UPIU_QUERY_OPCODE_READ_DESC, UFS_QUERY_DESC_IDN_POWER, 0, + 0, 0, &utrd, &rsp_upiu); + g_assert_cmpuint(le32_to_cpu(utrd.header.dword_2), ==, UFS_OCS_SUCCESS); + g_assert_cmpuint(rsp_upiu.header.response, ==, UFS_COMMAND_RESULT_SUCCESS); + g_assert_cmpuint(rsp_upiu.qr.data[0], ==, + sizeof(PowerParametersDescriptor)); + g_assert_cmpuint(rsp_upiu.qr.data[1], ==, UFS_QUERY_DESC_IDN_POWER); + + /* Read Health Descriptor */ + ufs_send_query(ufs, 0, UFS_UPIU_QUERY_FUNC_STANDARD_READ_REQUEST, + UFS_UPIU_QUERY_OPCODE_READ_DESC, UFS_QUERY_DESC_IDN_HEALTH, + 0, 0, 0, &utrd, &rsp_upiu); + g_assert_cmpuint(le32_to_cpu(utrd.header.dword_2), ==, UFS_OCS_SUCCESS); + g_assert_cmpuint(rsp_upiu.header.response, ==, UFS_COMMAND_RESULT_SUCCESS); + g_assert_cmpuint(rsp_upiu.qr.data[0], ==, sizeof(DeviceHealthDescriptor)); + g_assert_cmpuint(rsp_upiu.qr.data[1], ==, UFS_QUERY_DESC_IDN_HEALTH); + + /* Invalid Index (Intended Failure) */ + ufs_send_query(ufs, 0, UFS_UPIU_QUERY_FUNC_STANDARD_READ_REQUEST, + UFS_UPIU_QUERY_OPCODE_READ_DESC, UFS_QUERY_DESC_IDN_UNIT, 4, + 0, 0, &utrd, &rsp_upiu); + g_assert_cmpuint(le32_to_cpu(utrd.header.dword_2), ==, + UFS_OCS_INVALID_CMD_TABLE_ATTR); + g_assert_cmpuint(rsp_upiu.header.response, ==, + UFS_QUERY_RESULT_INVALID_INDEX); + + ufs_send_query(ufs, 0, UFS_UPIU_QUERY_FUNC_STANDARD_READ_REQUEST, + UFS_UPIU_QUERY_OPCODE_READ_DESC, UFS_QUERY_DESC_IDN_STRING, + 5, 0, 0, &utrd, &rsp_upiu); + g_assert_cmpuint(le32_to_cpu(utrd.header.dword_2), ==, + UFS_OCS_INVALID_CMD_TABLE_ATTR); + g_assert_cmpuint(rsp_upiu.header.response, ==, + UFS_QUERY_RESULT_INVALID_INDEX); + + /* Invalid Selector (Intended Failure) */ + ufs_send_query(ufs, 0, UFS_UPIU_QUERY_FUNC_STANDARD_READ_REQUEST, + UFS_UPIU_QUERY_OPCODE_READ_DESC, UFS_QUERY_DESC_IDN_DEVICE, + 0, 1, 0, &utrd, &rsp_upiu); + g_assert_cmpuint(le32_to_cpu(utrd.header.dword_2), ==, + UFS_OCS_INVALID_CMD_TABLE_ATTR); + g_assert_cmpuint(rsp_upiu.header.response, ==, + UFS_QUERY_RESULT_INVALID_SELECTOR); + + ufs_send_query(ufs, 0, UFS_UPIU_QUERY_FUNC_STANDARD_READ_REQUEST, + UFS_UPIU_QUERY_OPCODE_READ_DESC, UFS_QUERY_DESC_IDN_STRING, + 0, 1, 0, &utrd, &rsp_upiu); + g_assert_cmpuint(le32_to_cpu(utrd.header.dword_2), ==, + UFS_OCS_INVALID_CMD_TABLE_ATTR); + g_assert_cmpuint(rsp_upiu.header.response, ==, + UFS_QUERY_RESULT_INVALID_SELECTOR); + + ufs_exit(ufs, alloc); +} + static void drive_destroy(void *path) { unlink(path); @@ -826,6 +977,8 @@ static void ufs_register_nodes(void) ufstest_query_flag_request, &io_test_opts); qos_add_test("attr read-write", "ufs", ufstest_query_attr_request, &io_test_opts); + qos_add_test("desc read-write", "ufs", + ufstest_query_desc_request, &io_test_opts); } libqos_init(ufs_register_nodes);