1631c8726SJeuk Kim /* 2631c8726SJeuk Kim * QTest testcase for UFS 3631c8726SJeuk Kim * 4631c8726SJeuk Kim * Copyright (c) 2023 Samsung Electronics Co., Ltd. All rights reserved. 5631c8726SJeuk Kim * 6631c8726SJeuk Kim * SPDX-License-Identifier: GPL-2.0-or-later 7631c8726SJeuk Kim */ 8631c8726SJeuk Kim 9631c8726SJeuk Kim #include "qemu/osdep.h" 10631c8726SJeuk Kim #include "qemu/module.h" 11631c8726SJeuk Kim #include "libqtest.h" 12631c8726SJeuk Kim #include "libqos/qgraph.h" 13631c8726SJeuk Kim #include "libqos/pci.h" 14631c8726SJeuk Kim #include "scsi/constants.h" 158b4d80bbSPhilippe Mathieu-Daudé #include "block/ufs.h" 16*5cb3566aSJeuk Kim #include "qemu/bitmap.h" 17631c8726SJeuk Kim 18631c8726SJeuk Kim /* Test images sizes in Bytes */ 19631c8726SJeuk Kim #define TEST_IMAGE_SIZE (64 * 1024 * 1024) 20631c8726SJeuk Kim /* Timeout for various operations, in seconds. */ 21631c8726SJeuk Kim #define TIMEOUT_SECONDS 10 22631c8726SJeuk Kim /* Maximum PRD entry count */ 23631c8726SJeuk Kim #define MAX_PRD_ENTRY_COUNT 10 24631c8726SJeuk Kim #define PRD_ENTRY_DATA_SIZE 4096 25631c8726SJeuk Kim /* Constants to build upiu */ 26631c8726SJeuk Kim #define UTP_COMMAND_DESCRIPTOR_SIZE 4096 27631c8726SJeuk Kim #define UTP_RESPONSE_UPIU_OFFSET 1024 28631c8726SJeuk Kim #define UTP_PRDT_UPIU_OFFSET 2048 29*5cb3566aSJeuk Kim #define UTRD_TEST_SLOT 0 30*5cb3566aSJeuk Kim #define UFS_MAX_CMD_DESC 32 31631c8726SJeuk Kim 32631c8726SJeuk Kim typedef struct QUfs QUfs; 33631c8726SJeuk Kim 34631c8726SJeuk Kim struct QUfs { 35631c8726SJeuk Kim QOSGraphObject obj; 36631c8726SJeuk Kim QPCIDevice dev; 37631c8726SJeuk Kim QPCIBar bar; 38631c8726SJeuk Kim 39631c8726SJeuk Kim uint64_t utrlba; 40*5cb3566aSJeuk Kim DECLARE_BITMAP(cmd_desc_bitmap, UFS_MAX_CMD_DESC); 41631c8726SJeuk Kim uint64_t cmd_desc_addr; 42631c8726SJeuk Kim uint64_t data_buffer_addr; 43631c8726SJeuk Kim 44631c8726SJeuk Kim bool enabled; 45631c8726SJeuk Kim }; 46631c8726SJeuk Kim 47631c8726SJeuk Kim static inline uint32_t ufs_rreg(QUfs *ufs, size_t offset) 48631c8726SJeuk Kim { 49631c8726SJeuk Kim return qpci_io_readl(&ufs->dev, ufs->bar, offset); 50631c8726SJeuk Kim } 51631c8726SJeuk Kim 52631c8726SJeuk Kim static inline void ufs_wreg(QUfs *ufs, size_t offset, uint32_t value) 53631c8726SJeuk Kim { 54631c8726SJeuk Kim qpci_io_writel(&ufs->dev, ufs->bar, offset, value); 55631c8726SJeuk Kim } 56631c8726SJeuk Kim 57*5cb3566aSJeuk Kim static int alloc_cmd_desc_slot(QUfs *ufs) 58*5cb3566aSJeuk Kim { 59*5cb3566aSJeuk Kim int slot = find_first_zero_bit(ufs->cmd_desc_bitmap, UFS_MAX_CMD_DESC); 60*5cb3566aSJeuk Kim if (slot == UFS_MAX_CMD_DESC) { 61*5cb3566aSJeuk Kim g_assert_not_reached(); 62*5cb3566aSJeuk Kim } 63*5cb3566aSJeuk Kim set_bit(slot, ufs->cmd_desc_bitmap); 64*5cb3566aSJeuk Kim return slot; 65*5cb3566aSJeuk Kim } 66*5cb3566aSJeuk Kim 67*5cb3566aSJeuk Kim static void release_cmd_desc_slot(QUfs *ufs, int slot) 68*5cb3566aSJeuk Kim { 69*5cb3566aSJeuk Kim if (!test_bit(slot, ufs->cmd_desc_bitmap)) { 70*5cb3566aSJeuk Kim g_assert_not_reached(); 71*5cb3566aSJeuk Kim } 72*5cb3566aSJeuk Kim clear_bit(slot, ufs->cmd_desc_bitmap); 73*5cb3566aSJeuk Kim } 74*5cb3566aSJeuk Kim 75631c8726SJeuk Kim static void ufs_wait_for_irq(QUfs *ufs) 76631c8726SJeuk Kim { 77631c8726SJeuk Kim uint64_t end_time; 78631c8726SJeuk Kim uint32_t is; 79631c8726SJeuk Kim /* Wait for device to reset as the linux driver does. */ 80631c8726SJeuk Kim end_time = g_get_monotonic_time() + TIMEOUT_SECONDS * G_TIME_SPAN_SECOND; 81631c8726SJeuk Kim do { 82631c8726SJeuk Kim qtest_clock_step(ufs->dev.bus->qts, 100); 83631c8726SJeuk Kim is = ufs_rreg(ufs, A_IS); 84631c8726SJeuk Kim } while (is == 0 && g_get_monotonic_time() < end_time); 85631c8726SJeuk Kim } 86631c8726SJeuk Kim 87*5cb3566aSJeuk Kim static UtpTransferReqDesc ufs_build_req_utrd(uint64_t command_desc_base_addr, 88631c8726SJeuk Kim uint32_t data_direction, 89631c8726SJeuk Kim uint16_t prd_table_length) 90631c8726SJeuk Kim { 91631c8726SJeuk Kim UtpTransferReqDesc req = { 0 }; 92631c8726SJeuk Kim 93631c8726SJeuk Kim req.header.dword_0 = 94631c8726SJeuk Kim cpu_to_le32(1 << 28 | data_direction | UFS_UTP_REQ_DESC_INT_CMD); 95631c8726SJeuk Kim req.header.dword_2 = cpu_to_le32(UFS_OCS_INVALID_COMMAND_STATUS); 96631c8726SJeuk Kim 97631c8726SJeuk Kim req.command_desc_base_addr_hi = cpu_to_le32(command_desc_base_addr >> 32); 98631c8726SJeuk Kim req.command_desc_base_addr_lo = 99631c8726SJeuk Kim cpu_to_le32(command_desc_base_addr & 0xffffffff); 100631c8726SJeuk Kim req.response_upiu_offset = 101631c8726SJeuk Kim cpu_to_le16(UTP_RESPONSE_UPIU_OFFSET / sizeof(uint32_t)); 102631c8726SJeuk Kim req.response_upiu_length = cpu_to_le16(sizeof(UtpUpiuRsp)); 103631c8726SJeuk Kim req.prd_table_offset = cpu_to_le16(UTP_PRDT_UPIU_OFFSET / sizeof(uint32_t)); 104631c8726SJeuk Kim req.prd_table_length = cpu_to_le16(prd_table_length); 105631c8726SJeuk Kim return req; 106631c8726SJeuk Kim } 107631c8726SJeuk Kim 108*5cb3566aSJeuk Kim static enum UtpOcsCodes 109*5cb3566aSJeuk Kim ufs_send_transfer_request_sync(QUfs *ufs, uint8_t lun, 110*5cb3566aSJeuk Kim const UtpTransferReqDesc *utrd) 111631c8726SJeuk Kim { 112*5cb3566aSJeuk Kim UtpTransferReqDesc utrd_result; 113*5cb3566aSJeuk Kim /* 114*5cb3566aSJeuk Kim * Currently, the transfer request is sent synchronously, so UTRD_TEST_SLOT 115*5cb3566aSJeuk Kim * is fixed to 0. If asynchronous testing is added in the future, this value 116*5cb3566aSJeuk Kim * should be adjusted dynamically. 117*5cb3566aSJeuk Kim */ 118*5cb3566aSJeuk Kim uint64_t utrd_addr = 119*5cb3566aSJeuk Kim ufs->utrlba + UTRD_TEST_SLOT * sizeof(UtpTransferReqDesc); 120*5cb3566aSJeuk Kim qtest_memwrite(ufs->dev.bus->qts, utrd_addr, utrd, sizeof(*utrd)); 121631c8726SJeuk Kim 122631c8726SJeuk Kim /* Ring Doorbell */ 123631c8726SJeuk Kim ufs_wreg(ufs, A_UTRLDBR, 1); 124631c8726SJeuk Kim ufs_wait_for_irq(ufs); 125631c8726SJeuk Kim g_assert_true(FIELD_EX32(ufs_rreg(ufs, A_IS), IS, UTRCS)); 126631c8726SJeuk Kim ufs_wreg(ufs, A_IS, FIELD_DP32(0, IS, UTRCS, 1)); 127631c8726SJeuk Kim 128*5cb3566aSJeuk Kim qtest_memread(ufs->dev.bus->qts, utrd_addr, &utrd_result, 129*5cb3566aSJeuk Kim sizeof(utrd_result)); 130*5cb3566aSJeuk Kim 131*5cb3566aSJeuk Kim return le32_to_cpu(utrd_result.header.dword_2) & 0xf; 132631c8726SJeuk Kim } 133631c8726SJeuk Kim 134*5cb3566aSJeuk Kim static enum UtpOcsCodes ufs_send_nop_out(QUfs *ufs, UtpUpiuRsp *rsp_out) 135631c8726SJeuk Kim { 136*5cb3566aSJeuk Kim int cmd_desc_slot = alloc_cmd_desc_slot(ufs); 137631c8726SJeuk Kim uint64_t req_upiu_addr = 138*5cb3566aSJeuk Kim ufs->cmd_desc_addr + cmd_desc_slot * UTP_COMMAND_DESCRIPTOR_SIZE; 139631c8726SJeuk Kim uint64_t rsp_upiu_addr = req_upiu_addr + UTP_RESPONSE_UPIU_OFFSET; 140*5cb3566aSJeuk Kim 141*5cb3566aSJeuk Kim /* Build up request upiu */ 142*5cb3566aSJeuk Kim UtpUpiuReq req_upiu = { 0 }; 143*5cb3566aSJeuk Kim req_upiu.header.trans_type = UFS_UPIU_TRANSACTION_NOP_OUT; 144*5cb3566aSJeuk Kim req_upiu.header.task_tag = cmd_desc_slot; 145*5cb3566aSJeuk Kim qtest_memwrite(ufs->dev.bus->qts, req_upiu_addr, &req_upiu, 146*5cb3566aSJeuk Kim sizeof(req_upiu)); 147*5cb3566aSJeuk Kim 148*5cb3566aSJeuk Kim /* Build up utp transfer request descriptor */ 149*5cb3566aSJeuk Kim UtpTransferReqDesc utrd = 150*5cb3566aSJeuk Kim ufs_build_req_utrd(req_upiu_addr, UFS_UTP_NO_DATA_TRANSFER, 0); 151*5cb3566aSJeuk Kim 152*5cb3566aSJeuk Kim /* Send Transfer Request */ 153*5cb3566aSJeuk Kim enum UtpOcsCodes ret = ufs_send_transfer_request_sync(ufs, 0, &utrd); 154*5cb3566aSJeuk Kim 155*5cb3566aSJeuk Kim qtest_memread(ufs->dev.bus->qts, rsp_upiu_addr, rsp_out, sizeof(*rsp_out)); 156*5cb3566aSJeuk Kim release_cmd_desc_slot(ufs, cmd_desc_slot); 157*5cb3566aSJeuk Kim return ret; 158*5cb3566aSJeuk Kim } 159*5cb3566aSJeuk Kim 160*5cb3566aSJeuk Kim static enum UtpOcsCodes ufs_send_query(QUfs *ufs, uint8_t query_function, 161*5cb3566aSJeuk Kim uint8_t query_opcode, uint8_t idn, 162*5cb3566aSJeuk Kim uint8_t index, uint8_t selector, 163*5cb3566aSJeuk Kim uint32_t attr_value, UtpUpiuRsp *rsp_out) 164*5cb3566aSJeuk Kim { 165*5cb3566aSJeuk Kim int cmd_desc_slot = alloc_cmd_desc_slot(ufs); 166*5cb3566aSJeuk Kim uint64_t req_upiu_addr = 167*5cb3566aSJeuk Kim ufs->cmd_desc_addr + cmd_desc_slot * UTP_COMMAND_DESCRIPTOR_SIZE; 168*5cb3566aSJeuk Kim uint64_t rsp_upiu_addr = req_upiu_addr + UTP_RESPONSE_UPIU_OFFSET; 169631c8726SJeuk Kim 170631c8726SJeuk Kim /* Build up request upiu */ 171631c8726SJeuk Kim UtpUpiuReq req_upiu = { 0 }; 172631c8726SJeuk Kim req_upiu.header.trans_type = UFS_UPIU_TRANSACTION_QUERY_REQ; 173631c8726SJeuk Kim req_upiu.header.query_func = query_function; 174*5cb3566aSJeuk Kim req_upiu.header.task_tag = cmd_desc_slot; 175631c8726SJeuk Kim /* 1767c85332aSYoochan Jeong * QEMU UFS does not currently support Write descriptor, 177631c8726SJeuk Kim * so the value of data_segment_length is always 0. 178631c8726SJeuk Kim */ 179631c8726SJeuk Kim req_upiu.header.data_segment_length = 0; 180631c8726SJeuk Kim req_upiu.qr.opcode = query_opcode; 181631c8726SJeuk Kim req_upiu.qr.idn = idn; 182631c8726SJeuk Kim req_upiu.qr.index = index; 1837c85332aSYoochan Jeong req_upiu.qr.selector = selector; 1844572daccSKeoseong Park req_upiu.qr.value = cpu_to_be32(attr_value); 1857c85332aSYoochan Jeong req_upiu.qr.length = UFS_QUERY_DESC_MAX_SIZE; 186631c8726SJeuk Kim qtest_memwrite(ufs->dev.bus->qts, req_upiu_addr, &req_upiu, 187631c8726SJeuk Kim sizeof(req_upiu)); 188631c8726SJeuk Kim 189*5cb3566aSJeuk Kim /* Build up utp transfer request descriptor */ 190*5cb3566aSJeuk Kim UtpTransferReqDesc utrd = 191*5cb3566aSJeuk Kim ufs_build_req_utrd(req_upiu_addr, UFS_UTP_NO_DATA_TRANSFER, 0); 192631c8726SJeuk Kim 193*5cb3566aSJeuk Kim /* Send Transfer Request */ 194*5cb3566aSJeuk Kim enum UtpOcsCodes ret = ufs_send_transfer_request_sync(ufs, 0, &utrd); 195*5cb3566aSJeuk Kim 196631c8726SJeuk Kim qtest_memread(ufs->dev.bus->qts, rsp_upiu_addr, rsp_out, sizeof(*rsp_out)); 197*5cb3566aSJeuk Kim release_cmd_desc_slot(ufs, cmd_desc_slot); 198*5cb3566aSJeuk Kim return ret; 199631c8726SJeuk Kim } 200631c8726SJeuk Kim 201*5cb3566aSJeuk Kim static enum UtpOcsCodes 202*5cb3566aSJeuk Kim ufs_send_scsi_command(QUfs *ufs, uint8_t lun, const uint8_t *cdb, 203*5cb3566aSJeuk Kim const uint8_t *data_in, size_t data_in_len, 204*5cb3566aSJeuk Kim uint8_t *data_out, size_t data_out_len, 205631c8726SJeuk Kim UtpUpiuRsp *rsp_out) 206631c8726SJeuk Kim 207631c8726SJeuk Kim { 208631c8726SJeuk Kim /* Build up PRDT */ 209631c8726SJeuk Kim UfshcdSgEntry entries[MAX_PRD_ENTRY_COUNT] = { 210631c8726SJeuk Kim 0, 211631c8726SJeuk Kim }; 212631c8726SJeuk Kim uint8_t flags; 213631c8726SJeuk Kim uint16_t prd_table_length, i; 214631c8726SJeuk Kim uint32_t data_direction, data_len; 215*5cb3566aSJeuk Kim int cmd_desc_slot = alloc_cmd_desc_slot(ufs); 216631c8726SJeuk Kim uint64_t req_upiu_addr = 217*5cb3566aSJeuk Kim ufs->cmd_desc_addr + cmd_desc_slot * UTP_COMMAND_DESCRIPTOR_SIZE; 218631c8726SJeuk Kim uint64_t prdt_addr = req_upiu_addr + UTP_PRDT_UPIU_OFFSET; 219631c8726SJeuk Kim 220631c8726SJeuk Kim g_assert_true(data_in_len < MAX_PRD_ENTRY_COUNT * PRD_ENTRY_DATA_SIZE); 221631c8726SJeuk Kim g_assert_true(data_out_len < MAX_PRD_ENTRY_COUNT * PRD_ENTRY_DATA_SIZE); 222631c8726SJeuk Kim if (data_in_len > 0) { 223631c8726SJeuk Kim g_assert_nonnull(data_in); 224631c8726SJeuk Kim data_direction = UFS_UTP_HOST_TO_DEVICE; 225631c8726SJeuk Kim data_len = data_in_len; 226631c8726SJeuk Kim flags = UFS_UPIU_CMD_FLAGS_WRITE; 227631c8726SJeuk Kim } else if (data_out_len > 0) { 228631c8726SJeuk Kim g_assert_nonnull(data_out); 229631c8726SJeuk Kim data_direction = UFS_UTP_DEVICE_TO_HOST; 230631c8726SJeuk Kim data_len = data_out_len; 231631c8726SJeuk Kim flags = UFS_UPIU_CMD_FLAGS_READ; 232631c8726SJeuk Kim } else { 233631c8726SJeuk Kim data_direction = UFS_UTP_NO_DATA_TRANSFER; 234631c8726SJeuk Kim data_len = 0; 235631c8726SJeuk Kim flags = UFS_UPIU_CMD_FLAGS_NONE; 236631c8726SJeuk Kim } 237631c8726SJeuk Kim prd_table_length = DIV_ROUND_UP(data_len, PRD_ENTRY_DATA_SIZE); 238631c8726SJeuk Kim 239631c8726SJeuk Kim qtest_memset(ufs->dev.bus->qts, ufs->data_buffer_addr, 0, 240631c8726SJeuk Kim MAX_PRD_ENTRY_COUNT * PRD_ENTRY_DATA_SIZE); 241631c8726SJeuk Kim if (data_in_len) { 242631c8726SJeuk Kim qtest_memwrite(ufs->dev.bus->qts, ufs->data_buffer_addr, data_in, 243631c8726SJeuk Kim data_in_len); 244631c8726SJeuk Kim } 245631c8726SJeuk Kim 246631c8726SJeuk Kim for (i = 0; i < prd_table_length; i++) { 247631c8726SJeuk Kim entries[i].addr = 248631c8726SJeuk Kim cpu_to_le64(ufs->data_buffer_addr + i * sizeof(UfshcdSgEntry)); 249631c8726SJeuk Kim if (i + 1 != prd_table_length) { 250631c8726SJeuk Kim entries[i].size = cpu_to_le32(PRD_ENTRY_DATA_SIZE - 1); 251631c8726SJeuk Kim } else { 252631c8726SJeuk Kim entries[i].size = cpu_to_le32( 253631c8726SJeuk Kim data_len - (PRD_ENTRY_DATA_SIZE * (prd_table_length - 1)) - 1); 254631c8726SJeuk Kim } 255631c8726SJeuk Kim } 256631c8726SJeuk Kim qtest_memwrite(ufs->dev.bus->qts, prdt_addr, entries, 257631c8726SJeuk Kim prd_table_length * sizeof(UfshcdSgEntry)); 258631c8726SJeuk Kim 259631c8726SJeuk Kim uint64_t rsp_upiu_addr = req_upiu_addr + UTP_RESPONSE_UPIU_OFFSET; 260631c8726SJeuk Kim 261631c8726SJeuk Kim /* Build up request upiu */ 262631c8726SJeuk Kim UtpUpiuReq req_upiu = { 0 }; 263631c8726SJeuk Kim req_upiu.header.trans_type = UFS_UPIU_TRANSACTION_COMMAND; 264631c8726SJeuk Kim req_upiu.header.flags = flags; 265631c8726SJeuk Kim req_upiu.header.lun = lun; 266*5cb3566aSJeuk Kim req_upiu.header.task_tag = cmd_desc_slot; 267631c8726SJeuk Kim req_upiu.sc.exp_data_transfer_len = cpu_to_be32(data_len); 268631c8726SJeuk Kim memcpy(req_upiu.sc.cdb, cdb, UFS_CDB_SIZE); 269631c8726SJeuk Kim qtest_memwrite(ufs->dev.bus->qts, req_upiu_addr, &req_upiu, 270631c8726SJeuk Kim sizeof(req_upiu)); 271631c8726SJeuk Kim 272*5cb3566aSJeuk Kim /* Build up utp transfer request descriptor */ 273*5cb3566aSJeuk Kim UtpTransferReqDesc utrd = 274*5cb3566aSJeuk Kim ufs_build_req_utrd(req_upiu_addr, data_direction, prd_table_length); 275631c8726SJeuk Kim 276*5cb3566aSJeuk Kim /* Send Transfer Request */ 277*5cb3566aSJeuk Kim enum UtpOcsCodes ret = ufs_send_transfer_request_sync(ufs, lun, &utrd); 278*5cb3566aSJeuk Kim 279631c8726SJeuk Kim qtest_memread(ufs->dev.bus->qts, rsp_upiu_addr, rsp_out, sizeof(*rsp_out)); 280631c8726SJeuk Kim if (data_out_len) { 281631c8726SJeuk Kim qtest_memread(ufs->dev.bus->qts, ufs->data_buffer_addr, data_out, 282631c8726SJeuk Kim data_out_len); 283631c8726SJeuk Kim } 284*5cb3566aSJeuk Kim release_cmd_desc_slot(ufs, cmd_desc_slot); 285*5cb3566aSJeuk Kim return ret; 286631c8726SJeuk Kim } 287631c8726SJeuk Kim 288631c8726SJeuk Kim /** 289631c8726SJeuk Kim * Initialize Ufs host controller and logical unit. 290631c8726SJeuk Kim * After running this function, you can make a transfer request to the UFS. 291631c8726SJeuk Kim */ 292631c8726SJeuk Kim static void ufs_init(QUfs *ufs, QGuestAllocator *alloc) 293631c8726SJeuk Kim { 294631c8726SJeuk Kim uint64_t end_time; 295e041d3d2SJeuk Kim uint32_t nutrs; 296631c8726SJeuk Kim uint32_t hcs, is, ucmdarg2, cap; 297631c8726SJeuk Kim uint32_t hce = 0, ie = 0; 298*5cb3566aSJeuk Kim enum UtpOcsCodes ocs; 299631c8726SJeuk Kim UtpUpiuRsp rsp_upiu; 300631c8726SJeuk Kim 301631c8726SJeuk Kim ufs->bar = qpci_iomap(&ufs->dev, 0, NULL); 302631c8726SJeuk Kim qpci_device_enable(&ufs->dev); 303631c8726SJeuk Kim 304631c8726SJeuk Kim /* Start host controller initialization */ 305631c8726SJeuk Kim hce = FIELD_DP32(hce, HCE, HCE, 1); 306631c8726SJeuk Kim ufs_wreg(ufs, A_HCE, hce); 307631c8726SJeuk Kim 308631c8726SJeuk Kim /* Wait for device to reset */ 309631c8726SJeuk Kim end_time = g_get_monotonic_time() + TIMEOUT_SECONDS * G_TIME_SPAN_SECOND; 310631c8726SJeuk Kim do { 311631c8726SJeuk Kim qtest_clock_step(ufs->dev.bus->qts, 100); 312631c8726SJeuk Kim hce = FIELD_EX32(ufs_rreg(ufs, A_HCE), HCE, HCE); 313631c8726SJeuk Kim } while (hce == 0 && g_get_monotonic_time() < end_time); 314631c8726SJeuk Kim g_assert_cmpuint(hce, ==, 1); 315631c8726SJeuk Kim 316631c8726SJeuk Kim /* Enable interrupt */ 317631c8726SJeuk Kim ie = FIELD_DP32(ie, IE, UCCE, 1); 318631c8726SJeuk Kim ie = FIELD_DP32(ie, IE, UHESE, 1); 319631c8726SJeuk Kim ie = FIELD_DP32(ie, IE, UHXSE, 1); 320631c8726SJeuk Kim ie = FIELD_DP32(ie, IE, UPMSE, 1); 321631c8726SJeuk Kim ufs_wreg(ufs, A_IE, ie); 322631c8726SJeuk Kim 323631c8726SJeuk Kim /* Send DME_LINK_STARTUP uic command */ 324631c8726SJeuk Kim hcs = ufs_rreg(ufs, A_HCS); 325631c8726SJeuk Kim g_assert_true(FIELD_EX32(hcs, HCS, UCRDY)); 326631c8726SJeuk Kim 327631c8726SJeuk Kim ufs_wreg(ufs, A_UCMDARG1, 0); 328631c8726SJeuk Kim ufs_wreg(ufs, A_UCMDARG2, 0); 329631c8726SJeuk Kim ufs_wreg(ufs, A_UCMDARG3, 0); 330631c8726SJeuk Kim ufs_wreg(ufs, A_UICCMD, UFS_UIC_CMD_DME_LINK_STARTUP); 331631c8726SJeuk Kim 332631c8726SJeuk Kim is = ufs_rreg(ufs, A_IS); 333631c8726SJeuk Kim g_assert_true(FIELD_EX32(is, IS, UCCS)); 334631c8726SJeuk Kim ufs_wreg(ufs, A_IS, FIELD_DP32(0, IS, UCCS, 1)); 335631c8726SJeuk Kim 336631c8726SJeuk Kim ucmdarg2 = ufs_rreg(ufs, A_UCMDARG2); 337631c8726SJeuk Kim g_assert_cmpuint(ucmdarg2, ==, 0); 338631c8726SJeuk Kim is = ufs_rreg(ufs, A_IS); 339631c8726SJeuk Kim g_assert_cmpuint(is, ==, 0); 340631c8726SJeuk Kim hcs = ufs_rreg(ufs, A_HCS); 341631c8726SJeuk Kim g_assert_true(FIELD_EX32(hcs, HCS, DP)); 342631c8726SJeuk Kim g_assert_true(FIELD_EX32(hcs, HCS, UTRLRDY)); 343631c8726SJeuk Kim g_assert_true(FIELD_EX32(hcs, HCS, UCRDY)); 344631c8726SJeuk Kim 345631c8726SJeuk Kim /* Enable all interrupt functions */ 346631c8726SJeuk Kim ie = FIELD_DP32(ie, IE, UTRCE, 1); 347631c8726SJeuk Kim ie = FIELD_DP32(ie, IE, UEE, 1); 348631c8726SJeuk Kim ie = FIELD_DP32(ie, IE, UPMSE, 1); 349631c8726SJeuk Kim ie = FIELD_DP32(ie, IE, UHXSE, 1); 350631c8726SJeuk Kim ie = FIELD_DP32(ie, IE, UHESE, 1); 351631c8726SJeuk Kim ie = FIELD_DP32(ie, IE, UTMRCE, 1); 352631c8726SJeuk Kim ie = FIELD_DP32(ie, IE, UCCE, 1); 353631c8726SJeuk Kim ie = FIELD_DP32(ie, IE, DFEE, 1); 354631c8726SJeuk Kim ie = FIELD_DP32(ie, IE, HCFEE, 1); 355631c8726SJeuk Kim ie = FIELD_DP32(ie, IE, SBFEE, 1); 356631c8726SJeuk Kim ie = FIELD_DP32(ie, IE, CEFEE, 1); 357631c8726SJeuk Kim ufs_wreg(ufs, A_IE, ie); 358631c8726SJeuk Kim ufs_wreg(ufs, A_UTRIACR, 0); 359631c8726SJeuk Kim 360*5cb3566aSJeuk Kim /* Enable transfer request */ 361631c8726SJeuk Kim cap = ufs_rreg(ufs, A_CAP); 362631c8726SJeuk Kim nutrs = FIELD_EX32(cap, CAP, NUTRS) + 1; 363631c8726SJeuk Kim ufs->cmd_desc_addr = 364*5cb3566aSJeuk Kim guest_alloc(alloc, UFS_MAX_CMD_DESC * UTP_COMMAND_DESCRIPTOR_SIZE); 365631c8726SJeuk Kim ufs->data_buffer_addr = 366631c8726SJeuk Kim guest_alloc(alloc, MAX_PRD_ENTRY_COUNT * PRD_ENTRY_DATA_SIZE); 367631c8726SJeuk Kim ufs->utrlba = guest_alloc(alloc, nutrs * sizeof(UtpTransferReqDesc)); 368631c8726SJeuk Kim 369631c8726SJeuk Kim ufs_wreg(ufs, A_UTRLBA, ufs->utrlba & 0xffffffff); 370631c8726SJeuk Kim ufs_wreg(ufs, A_UTRLBAU, ufs->utrlba >> 32); 371631c8726SJeuk Kim ufs_wreg(ufs, A_UTRLRSR, 1); 372631c8726SJeuk Kim 373631c8726SJeuk Kim /* Send nop out to test transfer request */ 374*5cb3566aSJeuk Kim ocs = ufs_send_nop_out(ufs, &rsp_upiu); 375*5cb3566aSJeuk Kim g_assert_cmpuint(ocs, ==, UFS_OCS_SUCCESS); 376631c8726SJeuk Kim 377631c8726SJeuk Kim /* Set fDeviceInit flag via query request */ 378*5cb3566aSJeuk Kim ocs = ufs_send_query(ufs, UFS_UPIU_QUERY_FUNC_STANDARD_WRITE_REQUEST, 379631c8726SJeuk Kim UFS_UPIU_QUERY_OPCODE_SET_FLAG, 380*5cb3566aSJeuk Kim UFS_QUERY_FLAG_IDN_FDEVICEINIT, 0, 0, 0, &rsp_upiu); 381*5cb3566aSJeuk Kim g_assert_cmpuint(ocs, ==, UFS_OCS_SUCCESS); 382*5cb3566aSJeuk Kim g_assert_cmpuint(rsp_upiu.header.response, ==, UFS_COMMAND_RESULT_SUCCESS); 383631c8726SJeuk Kim 384631c8726SJeuk Kim /* Wait for device to reset */ 385631c8726SJeuk Kim end_time = g_get_monotonic_time() + TIMEOUT_SECONDS * G_TIME_SPAN_SECOND; 386631c8726SJeuk Kim do { 387631c8726SJeuk Kim qtest_clock_step(ufs->dev.bus->qts, 100); 388*5cb3566aSJeuk Kim ocs = 389*5cb3566aSJeuk Kim ufs_send_query(ufs, UFS_UPIU_QUERY_FUNC_STANDARD_READ_REQUEST, 390631c8726SJeuk Kim UFS_UPIU_QUERY_OPCODE_READ_FLAG, 391*5cb3566aSJeuk Kim UFS_QUERY_FLAG_IDN_FDEVICEINIT, 0, 0, 0, &rsp_upiu); 392*5cb3566aSJeuk Kim g_assert_cmpuint(ocs, ==, UFS_OCS_SUCCESS); 393*5cb3566aSJeuk Kim g_assert_cmpuint(rsp_upiu.header.response, ==, 394*5cb3566aSJeuk Kim UFS_COMMAND_RESULT_SUCCESS); 395631c8726SJeuk Kim } while (be32_to_cpu(rsp_upiu.qr.value) != 0 && 396631c8726SJeuk Kim g_get_monotonic_time() < end_time); 397631c8726SJeuk Kim g_assert_cmpuint(be32_to_cpu(rsp_upiu.qr.value), ==, 0); 398631c8726SJeuk Kim 399631c8726SJeuk Kim ufs->enabled = true; 400631c8726SJeuk Kim } 401631c8726SJeuk Kim 402631c8726SJeuk Kim static void ufs_exit(QUfs *ufs, QGuestAllocator *alloc) 403631c8726SJeuk Kim { 404631c8726SJeuk Kim if (ufs->enabled) { 405631c8726SJeuk Kim guest_free(alloc, ufs->utrlba); 406631c8726SJeuk Kim guest_free(alloc, ufs->cmd_desc_addr); 407631c8726SJeuk Kim guest_free(alloc, ufs->data_buffer_addr); 408631c8726SJeuk Kim } 409631c8726SJeuk Kim 410631c8726SJeuk Kim qpci_iounmap(&ufs->dev, ufs->bar); 411631c8726SJeuk Kim } 412631c8726SJeuk Kim 413631c8726SJeuk Kim static void *ufs_get_driver(void *obj, const char *interface) 414631c8726SJeuk Kim { 415631c8726SJeuk Kim QUfs *ufs = obj; 416631c8726SJeuk Kim 417631c8726SJeuk Kim if (!g_strcmp0(interface, "pci-device")) { 418631c8726SJeuk Kim return &ufs->dev; 419631c8726SJeuk Kim } 420631c8726SJeuk Kim 421631c8726SJeuk Kim fprintf(stderr, "%s not present in ufs\n", interface); 422631c8726SJeuk Kim g_assert_not_reached(); 423631c8726SJeuk Kim } 424631c8726SJeuk Kim 425631c8726SJeuk Kim static void *ufs_create(void *pci_bus, QGuestAllocator *alloc, void *addr) 426631c8726SJeuk Kim { 427631c8726SJeuk Kim QUfs *ufs = g_new0(QUfs, 1); 428631c8726SJeuk Kim QPCIBus *bus = pci_bus; 429631c8726SJeuk Kim 430631c8726SJeuk Kim qpci_device_init(&ufs->dev, bus, addr); 431631c8726SJeuk Kim ufs->obj.get_driver = ufs_get_driver; 432631c8726SJeuk Kim 433631c8726SJeuk Kim return &ufs->obj; 434631c8726SJeuk Kim } 435631c8726SJeuk Kim 436631c8726SJeuk Kim static void ufstest_reg_read(void *obj, void *data, QGuestAllocator *alloc) 437631c8726SJeuk Kim { 438631c8726SJeuk Kim QUfs *ufs = obj; 439631c8726SJeuk Kim uint32_t cap; 440631c8726SJeuk Kim 441631c8726SJeuk Kim ufs->bar = qpci_iomap(&ufs->dev, 0, NULL); 442631c8726SJeuk Kim qpci_device_enable(&ufs->dev); 443631c8726SJeuk Kim 444631c8726SJeuk Kim cap = ufs_rreg(ufs, A_CAP); 445631c8726SJeuk Kim g_assert_cmpuint(FIELD_EX32(cap, CAP, NUTRS), ==, 31); 446631c8726SJeuk Kim g_assert_cmpuint(FIELD_EX32(cap, CAP, NUTMRS), ==, 7); 447631c8726SJeuk Kim g_assert_cmpuint(FIELD_EX32(cap, CAP, 64AS), ==, 1); 448631c8726SJeuk Kim 449631c8726SJeuk Kim qpci_iounmap(&ufs->dev, ufs->bar); 450631c8726SJeuk Kim } 451631c8726SJeuk Kim 452631c8726SJeuk Kim static void ufstest_init(void *obj, void *data, QGuestAllocator *alloc) 453631c8726SJeuk Kim { 454631c8726SJeuk Kim QUfs *ufs = obj; 455631c8726SJeuk Kim 456631c8726SJeuk Kim uint8_t buf[4096] = { 0 }; 457631c8726SJeuk Kim const uint8_t report_luns_cdb[UFS_CDB_SIZE] = { 458631c8726SJeuk Kim /* allocation length 4096 */ 459631c8726SJeuk Kim REPORT_LUNS, 0x00, 0x00, 0x00, 0x00, 0x00, 460631c8726SJeuk Kim 0x00, 0x00, 0x10, 0x00, 0x00, 0x00 461631c8726SJeuk Kim }; 462631c8726SJeuk Kim const uint8_t test_unit_ready_cdb[UFS_CDB_SIZE] = { 463631c8726SJeuk Kim TEST_UNIT_READY, 464631c8726SJeuk Kim }; 465096434feSJeuk Kim const uint8_t request_sense_cdb[UFS_CDB_SIZE] = { 466096434feSJeuk Kim REQUEST_SENSE, 467096434feSJeuk Kim }; 468*5cb3566aSJeuk Kim enum UtpOcsCodes ocs; 469631c8726SJeuk Kim UtpUpiuRsp rsp_upiu; 470631c8726SJeuk Kim 471631c8726SJeuk Kim ufs_init(ufs, alloc); 472631c8726SJeuk Kim 473631c8726SJeuk Kim /* Check REPORT_LUNS */ 474*5cb3566aSJeuk Kim ocs = ufs_send_scsi_command(ufs, 0, report_luns_cdb, NULL, 0, buf, 475*5cb3566aSJeuk Kim sizeof(buf), &rsp_upiu); 476*5cb3566aSJeuk Kim g_assert_cmpuint(ocs, ==, UFS_OCS_SUCCESS); 477631c8726SJeuk Kim g_assert_cmpuint(rsp_upiu.header.scsi_status, ==, GOOD); 478631c8726SJeuk Kim /* LUN LIST LENGTH should be 8, in big endian */ 479631c8726SJeuk Kim g_assert_cmpuint(buf[3], ==, 8); 480631c8726SJeuk Kim /* There is one logical unit whose lun is 0 */ 481631c8726SJeuk Kim g_assert_cmpuint(buf[9], ==, 0); 482631c8726SJeuk Kim 483096434feSJeuk Kim /* Clear Unit Attention */ 484*5cb3566aSJeuk Kim ocs = ufs_send_scsi_command(ufs, 0, request_sense_cdb, NULL, 0, buf, 485*5cb3566aSJeuk Kim sizeof(buf), &rsp_upiu); 486*5cb3566aSJeuk Kim g_assert_cmpuint(ocs, ==, UFS_OCS_SUCCESS); 487096434feSJeuk Kim g_assert_cmpuint(rsp_upiu.header.scsi_status, ==, CHECK_CONDITION); 488096434feSJeuk Kim 489631c8726SJeuk Kim /* Check TEST_UNIT_READY */ 490*5cb3566aSJeuk Kim ocs = ufs_send_scsi_command(ufs, 0, test_unit_ready_cdb, NULL, 0, NULL, 0, 491*5cb3566aSJeuk Kim &rsp_upiu); 492*5cb3566aSJeuk Kim g_assert_cmpuint(ocs, ==, UFS_OCS_SUCCESS); 493631c8726SJeuk Kim g_assert_cmpuint(rsp_upiu.header.scsi_status, ==, GOOD); 494631c8726SJeuk Kim 495631c8726SJeuk Kim ufs_exit(ufs, alloc); 496631c8726SJeuk Kim } 497631c8726SJeuk Kim 498631c8726SJeuk Kim static void ufstest_read_write(void *obj, void *data, QGuestAllocator *alloc) 499631c8726SJeuk Kim { 500631c8726SJeuk Kim QUfs *ufs = obj; 501631c8726SJeuk Kim uint8_t read_buf[4096] = { 0 }; 502631c8726SJeuk Kim uint8_t write_buf[4096] = { 0 }; 503631c8726SJeuk Kim const uint8_t read_capacity_cdb[UFS_CDB_SIZE] = { 504631c8726SJeuk Kim /* allocation length 4096 */ 505631c8726SJeuk Kim SERVICE_ACTION_IN_16, 506631c8726SJeuk Kim SAI_READ_CAPACITY_16, 507631c8726SJeuk Kim 0x00, 508631c8726SJeuk Kim 0x00, 509631c8726SJeuk Kim 0x00, 510631c8726SJeuk Kim 0x00, 511631c8726SJeuk Kim 0x00, 512631c8726SJeuk Kim 0x00, 513631c8726SJeuk Kim 0x00, 514631c8726SJeuk Kim 0x00, 515631c8726SJeuk Kim 0x00, 516631c8726SJeuk Kim 0x00, 517631c8726SJeuk Kim 0x10, 518631c8726SJeuk Kim 0x00, 519631c8726SJeuk Kim 0x00, 520631c8726SJeuk Kim 0x00 521631c8726SJeuk Kim }; 522096434feSJeuk Kim const uint8_t request_sense_cdb[UFS_CDB_SIZE] = { 523096434feSJeuk Kim REQUEST_SENSE, 524096434feSJeuk Kim }; 525631c8726SJeuk Kim const uint8_t read_cdb[UFS_CDB_SIZE] = { 526631c8726SJeuk Kim /* READ(10) to LBA 0, transfer length 1 */ 527631c8726SJeuk Kim READ_10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00 528631c8726SJeuk Kim }; 529631c8726SJeuk Kim const uint8_t write_cdb[UFS_CDB_SIZE] = { 530631c8726SJeuk Kim /* WRITE(10) to LBA 0, transfer length 1 */ 531631c8726SJeuk Kim WRITE_10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00 532631c8726SJeuk Kim }; 533631c8726SJeuk Kim uint32_t block_size; 534*5cb3566aSJeuk Kim enum UtpOcsCodes ocs; 535631c8726SJeuk Kim UtpUpiuRsp rsp_upiu; 536096434feSJeuk Kim const int test_lun = 1; 537631c8726SJeuk Kim 538631c8726SJeuk Kim ufs_init(ufs, alloc); 539631c8726SJeuk Kim 540096434feSJeuk Kim /* Clear Unit Attention */ 541*5cb3566aSJeuk Kim ocs = ufs_send_scsi_command(ufs, test_lun, request_sense_cdb, NULL, 0, 542*5cb3566aSJeuk Kim read_buf, sizeof(read_buf), &rsp_upiu); 543*5cb3566aSJeuk Kim g_assert_cmpuint(ocs, ==, UFS_OCS_SUCCESS); 544096434feSJeuk Kim g_assert_cmpuint(rsp_upiu.header.scsi_status, ==, CHECK_CONDITION); 545096434feSJeuk Kim 546631c8726SJeuk Kim /* Read capacity */ 547*5cb3566aSJeuk Kim ocs = ufs_send_scsi_command(ufs, test_lun, read_capacity_cdb, NULL, 0, 548*5cb3566aSJeuk Kim read_buf, sizeof(read_buf), &rsp_upiu); 549*5cb3566aSJeuk Kim g_assert_cmpuint(ocs, ==, UFS_OCS_SUCCESS); 550631c8726SJeuk Kim g_assert_cmpuint(rsp_upiu.header.scsi_status, ==, 551096434feSJeuk Kim UFS_COMMAND_RESULT_SUCCESS); 552631c8726SJeuk Kim block_size = ldl_be_p(&read_buf[8]); 553631c8726SJeuk Kim g_assert_cmpuint(block_size, ==, 4096); 554631c8726SJeuk Kim 555631c8726SJeuk Kim /* Write data */ 55697970daeSJeuk Kim memset(write_buf, 0xab, block_size); 557*5cb3566aSJeuk Kim ocs = ufs_send_scsi_command(ufs, test_lun, write_cdb, write_buf, block_size, 558*5cb3566aSJeuk Kim NULL, 0, &rsp_upiu); 559*5cb3566aSJeuk Kim g_assert_cmpuint(ocs, ==, UFS_OCS_SUCCESS); 560631c8726SJeuk Kim g_assert_cmpuint(rsp_upiu.header.scsi_status, ==, 561096434feSJeuk Kim UFS_COMMAND_RESULT_SUCCESS); 562631c8726SJeuk Kim 563631c8726SJeuk Kim /* Read data and verify */ 564*5cb3566aSJeuk Kim ocs = ufs_send_scsi_command(ufs, test_lun, read_cdb, NULL, 0, read_buf, 565*5cb3566aSJeuk Kim block_size, &rsp_upiu); 566*5cb3566aSJeuk Kim g_assert_cmpuint(ocs, ==, UFS_OCS_SUCCESS); 567631c8726SJeuk Kim g_assert_cmpuint(rsp_upiu.header.scsi_status, ==, 568096434feSJeuk Kim UFS_COMMAND_RESULT_SUCCESS); 569631c8726SJeuk Kim g_assert_cmpint(memcmp(read_buf, write_buf, block_size), ==, 0); 570631c8726SJeuk Kim 571631c8726SJeuk Kim ufs_exit(ufs, alloc); 572631c8726SJeuk Kim } 573631c8726SJeuk Kim 5744aac3029SYoochan Jeong static void ufstest_query_flag_request(void *obj, void *data, 5754aac3029SYoochan Jeong QGuestAllocator *alloc) 5764aac3029SYoochan Jeong { 5774aac3029SYoochan Jeong QUfs *ufs = obj; 5784aac3029SYoochan Jeong 579*5cb3566aSJeuk Kim enum UtpOcsCodes ocs; 5804aac3029SYoochan Jeong UtpUpiuRsp rsp_upiu; 5814aac3029SYoochan Jeong ufs_init(ufs, alloc); 5824aac3029SYoochan Jeong 5834aac3029SYoochan Jeong /* Read read-only flag */ 584*5cb3566aSJeuk Kim ocs = ufs_send_query(ufs, UFS_UPIU_QUERY_FUNC_STANDARD_READ_REQUEST, 5854aac3029SYoochan Jeong UFS_UPIU_QUERY_OPCODE_READ_FLAG, 586*5cb3566aSJeuk Kim UFS_QUERY_FLAG_IDN_FDEVICEINIT, 0, 0, 0, &rsp_upiu); 587*5cb3566aSJeuk Kim g_assert_cmpuint(ocs, ==, UFS_OCS_SUCCESS); 5884aac3029SYoochan Jeong g_assert_cmpuint(rsp_upiu.header.response, ==, UFS_COMMAND_RESULT_SUCCESS); 5894aac3029SYoochan Jeong g_assert_cmpuint(rsp_upiu.qr.opcode, ==, UFS_UPIU_QUERY_OPCODE_READ_FLAG); 5904aac3029SYoochan Jeong g_assert_cmpuint(rsp_upiu.qr.idn, ==, UFS_QUERY_FLAG_IDN_FDEVICEINIT); 5914aac3029SYoochan Jeong g_assert_cmpuint(rsp_upiu.qr.value, ==, be32_to_cpu(0)); 5924aac3029SYoochan Jeong 5934aac3029SYoochan Jeong /* Flag Set, Clear, Toggle Test with fDeviceLifeSpanModeEn */ 594*5cb3566aSJeuk Kim ocs = ufs_send_query(ufs, UFS_UPIU_QUERY_FUNC_STANDARD_READ_REQUEST, 5954aac3029SYoochan Jeong UFS_UPIU_QUERY_OPCODE_READ_FLAG, 596*5cb3566aSJeuk Kim UFS_QUERY_FLAG_IDN_LIFE_SPAN_MODE_ENABLE, 0, 0, 0, 5974aac3029SYoochan Jeong &rsp_upiu); 598*5cb3566aSJeuk Kim g_assert_cmpuint(ocs, ==, UFS_OCS_SUCCESS); 5994aac3029SYoochan Jeong g_assert_cmpuint(rsp_upiu.header.response, ==, UFS_COMMAND_RESULT_SUCCESS); 6004aac3029SYoochan Jeong g_assert_cmpuint(rsp_upiu.qr.value, ==, be32_to_cpu(0)); 6014aac3029SYoochan Jeong 602*5cb3566aSJeuk Kim ocs = ufs_send_query(ufs, UFS_UPIU_QUERY_FUNC_STANDARD_WRITE_REQUEST, 6034aac3029SYoochan Jeong UFS_UPIU_QUERY_OPCODE_SET_FLAG, 604*5cb3566aSJeuk Kim UFS_QUERY_FLAG_IDN_LIFE_SPAN_MODE_ENABLE, 0, 0, 0, 6054aac3029SYoochan Jeong &rsp_upiu); 606*5cb3566aSJeuk Kim g_assert_cmpuint(ocs, ==, UFS_OCS_SUCCESS); 6074aac3029SYoochan Jeong g_assert_cmpuint(rsp_upiu.header.response, ==, UFS_COMMAND_RESULT_SUCCESS); 6084aac3029SYoochan Jeong g_assert_cmpuint(rsp_upiu.qr.value, ==, be32_to_cpu(1)); 6094aac3029SYoochan Jeong 610*5cb3566aSJeuk Kim ocs = ufs_send_query(ufs, UFS_UPIU_QUERY_FUNC_STANDARD_WRITE_REQUEST, 6114aac3029SYoochan Jeong UFS_UPIU_QUERY_OPCODE_CLEAR_FLAG, 612*5cb3566aSJeuk Kim UFS_QUERY_FLAG_IDN_LIFE_SPAN_MODE_ENABLE, 0, 0, 0, 6134aac3029SYoochan Jeong &rsp_upiu); 614*5cb3566aSJeuk Kim g_assert_cmpuint(ocs, ==, UFS_OCS_SUCCESS); 6154aac3029SYoochan Jeong g_assert_cmpuint(rsp_upiu.header.response, ==, UFS_COMMAND_RESULT_SUCCESS); 6164aac3029SYoochan Jeong g_assert_cmpuint(rsp_upiu.qr.value, ==, be32_to_cpu(0)); 6174aac3029SYoochan Jeong 618*5cb3566aSJeuk Kim ocs = ufs_send_query(ufs, UFS_UPIU_QUERY_FUNC_STANDARD_WRITE_REQUEST, 6194aac3029SYoochan Jeong UFS_UPIU_QUERY_OPCODE_TOGGLE_FLAG, 620*5cb3566aSJeuk Kim UFS_QUERY_FLAG_IDN_LIFE_SPAN_MODE_ENABLE, 0, 0, 0, 6214aac3029SYoochan Jeong &rsp_upiu); 622*5cb3566aSJeuk Kim g_assert_cmpuint(ocs, ==, UFS_OCS_SUCCESS); 6234aac3029SYoochan Jeong g_assert_cmpuint(rsp_upiu.header.response, ==, UFS_COMMAND_RESULT_SUCCESS); 6244aac3029SYoochan Jeong g_assert_cmpuint(rsp_upiu.qr.value, ==, be32_to_cpu(1)); 6254aac3029SYoochan Jeong 626*5cb3566aSJeuk Kim ocs = ufs_send_query(ufs, UFS_UPIU_QUERY_FUNC_STANDARD_WRITE_REQUEST, 6274aac3029SYoochan Jeong UFS_UPIU_QUERY_OPCODE_TOGGLE_FLAG, 628*5cb3566aSJeuk Kim UFS_QUERY_FLAG_IDN_LIFE_SPAN_MODE_ENABLE, 0, 0, 0, 6294aac3029SYoochan Jeong &rsp_upiu); 630*5cb3566aSJeuk Kim g_assert_cmpuint(ocs, ==, UFS_OCS_SUCCESS); 6314aac3029SYoochan Jeong g_assert_cmpuint(rsp_upiu.header.response, ==, UFS_COMMAND_RESULT_SUCCESS); 6324aac3029SYoochan Jeong g_assert_cmpuint(rsp_upiu.qr.value, ==, be32_to_cpu(0)); 6334aac3029SYoochan Jeong 6344aac3029SYoochan Jeong /* Read Write-only Flag (Intended Failure) */ 635*5cb3566aSJeuk Kim ocs = ufs_send_query(ufs, UFS_UPIU_QUERY_FUNC_STANDARD_READ_REQUEST, 6364aac3029SYoochan Jeong UFS_UPIU_QUERY_OPCODE_READ_FLAG, 637*5cb3566aSJeuk Kim UFS_QUERY_FLAG_IDN_PURGE_ENABLE, 0, 0, 0, &rsp_upiu); 638*5cb3566aSJeuk Kim g_assert_cmpuint(ocs, ==, UFS_OCS_INVALID_CMD_TABLE_ATTR); 6394aac3029SYoochan Jeong g_assert_cmpuint(rsp_upiu.header.response, ==, 6404aac3029SYoochan Jeong UFS_QUERY_RESULT_NOT_READABLE); 6414aac3029SYoochan Jeong 6424aac3029SYoochan Jeong /* Write Read-Only Flag (Intended Failure) */ 643*5cb3566aSJeuk Kim ocs = ufs_send_query(ufs, UFS_UPIU_QUERY_FUNC_STANDARD_WRITE_REQUEST, 644*5cb3566aSJeuk Kim UFS_UPIU_QUERY_OPCODE_SET_FLAG, 645*5cb3566aSJeuk Kim UFS_QUERY_FLAG_IDN_BUSY_RTC, 0, 0, 0, &rsp_upiu); 646*5cb3566aSJeuk Kim g_assert_cmpuint(ocs, ==, UFS_OCS_INVALID_CMD_TABLE_ATTR); 6474aac3029SYoochan Jeong g_assert_cmpuint(rsp_upiu.header.response, ==, 6484aac3029SYoochan Jeong UFS_QUERY_RESULT_NOT_WRITEABLE); 6494aac3029SYoochan Jeong 6504aac3029SYoochan Jeong ufs_exit(ufs, alloc); 6514aac3029SYoochan Jeong } 6524aac3029SYoochan Jeong 65349ccea4bSYoochan Jeong static void ufstest_query_attr_request(void *obj, void *data, 65449ccea4bSYoochan Jeong QGuestAllocator *alloc) 65549ccea4bSYoochan Jeong { 65649ccea4bSYoochan Jeong QUfs *ufs = obj; 65749ccea4bSYoochan Jeong 658*5cb3566aSJeuk Kim enum UtpOcsCodes ocs; 65949ccea4bSYoochan Jeong UtpUpiuRsp rsp_upiu; 66049ccea4bSYoochan Jeong ufs_init(ufs, alloc); 66149ccea4bSYoochan Jeong 66249ccea4bSYoochan Jeong /* Read Readable Attributes*/ 663*5cb3566aSJeuk Kim ocs = ufs_send_query(ufs, UFS_UPIU_QUERY_FUNC_STANDARD_READ_REQUEST, 66449ccea4bSYoochan Jeong UFS_UPIU_QUERY_OPCODE_READ_ATTR, 665*5cb3566aSJeuk Kim UFS_QUERY_ATTR_IDN_BOOT_LU_EN, 0, 0, 0, &rsp_upiu); 666*5cb3566aSJeuk Kim g_assert_cmpuint(ocs, ==, UFS_OCS_SUCCESS); 66749ccea4bSYoochan Jeong g_assert_cmpuint(rsp_upiu.header.response, ==, UFS_COMMAND_RESULT_SUCCESS); 66849ccea4bSYoochan Jeong g_assert_cmpuint(rsp_upiu.qr.opcode, ==, UFS_UPIU_QUERY_OPCODE_READ_ATTR); 66949ccea4bSYoochan Jeong g_assert_cmpuint(rsp_upiu.qr.idn, ==, UFS_QUERY_ATTR_IDN_BOOT_LU_EN); 67049ccea4bSYoochan Jeong g_assert_cmpuint(rsp_upiu.qr.value, ==, cpu_to_be32(0x00)); 67149ccea4bSYoochan Jeong 672*5cb3566aSJeuk Kim ocs = ufs_send_query(ufs, UFS_UPIU_QUERY_FUNC_STANDARD_READ_REQUEST, 67349ccea4bSYoochan Jeong UFS_UPIU_QUERY_OPCODE_READ_ATTR, 674*5cb3566aSJeuk Kim UFS_QUERY_ATTR_IDN_BKOPS_STATUS, 0, 0, 0, &rsp_upiu); 675*5cb3566aSJeuk Kim g_assert_cmpuint(ocs, ==, UFS_OCS_SUCCESS); 67649ccea4bSYoochan Jeong g_assert_cmpuint(rsp_upiu.header.response, ==, UFS_COMMAND_RESULT_SUCCESS); 67749ccea4bSYoochan Jeong g_assert_cmpuint(rsp_upiu.qr.value, ==, cpu_to_be32(0x00)); 67849ccea4bSYoochan Jeong 67949ccea4bSYoochan Jeong /* Write Writable Attributes & Read Again */ 680*5cb3566aSJeuk Kim ocs = ufs_send_query(ufs, UFS_UPIU_QUERY_FUNC_STANDARD_WRITE_REQUEST, 68149ccea4bSYoochan Jeong UFS_UPIU_QUERY_OPCODE_WRITE_ATTR, 682*5cb3566aSJeuk Kim UFS_QUERY_ATTR_IDN_ACTIVE_ICC_LVL, 0, 0, 0x03, 68349ccea4bSYoochan Jeong &rsp_upiu); 684*5cb3566aSJeuk Kim g_assert_cmpuint(ocs, ==, UFS_OCS_SUCCESS); 68549ccea4bSYoochan Jeong g_assert_cmpuint(rsp_upiu.header.response, ==, UFS_COMMAND_RESULT_SUCCESS); 68649ccea4bSYoochan Jeong g_assert_cmpuint(rsp_upiu.qr.value, ==, cpu_to_be32(0x03)); 68749ccea4bSYoochan Jeong 688*5cb3566aSJeuk Kim ocs = ufs_send_query(ufs, UFS_UPIU_QUERY_FUNC_STANDARD_WRITE_REQUEST, 68949ccea4bSYoochan Jeong UFS_UPIU_QUERY_OPCODE_WRITE_ATTR, 690*5cb3566aSJeuk Kim UFS_QUERY_ATTR_IDN_EE_CONTROL, 0, 0, 0x07, &rsp_upiu); 691*5cb3566aSJeuk Kim g_assert_cmpuint(ocs, ==, UFS_OCS_SUCCESS); 69249ccea4bSYoochan Jeong g_assert_cmpuint(rsp_upiu.header.response, ==, UFS_COMMAND_RESULT_SUCCESS); 69349ccea4bSYoochan Jeong g_assert_cmpuint(rsp_upiu.qr.value, ==, cpu_to_be32(0x07)); 69449ccea4bSYoochan Jeong 695*5cb3566aSJeuk Kim ocs = ufs_send_query(ufs, UFS_UPIU_QUERY_FUNC_STANDARD_READ_REQUEST, 69649ccea4bSYoochan Jeong UFS_UPIU_QUERY_OPCODE_READ_ATTR, 697*5cb3566aSJeuk Kim UFS_QUERY_ATTR_IDN_ACTIVE_ICC_LVL, 0, 0, 0, &rsp_upiu); 698*5cb3566aSJeuk Kim g_assert_cmpuint(ocs, ==, UFS_OCS_SUCCESS); 69949ccea4bSYoochan Jeong g_assert_cmpuint(rsp_upiu.header.response, ==, UFS_COMMAND_RESULT_SUCCESS); 70049ccea4bSYoochan Jeong g_assert_cmpuint(rsp_upiu.qr.value, ==, cpu_to_be32(0x03)); 70149ccea4bSYoochan Jeong 702*5cb3566aSJeuk Kim ocs = ufs_send_query(ufs, UFS_UPIU_QUERY_FUNC_STANDARD_READ_REQUEST, 70349ccea4bSYoochan Jeong UFS_UPIU_QUERY_OPCODE_READ_ATTR, 704*5cb3566aSJeuk Kim UFS_QUERY_ATTR_IDN_EE_CONTROL, 0, 0, 0, &rsp_upiu); 705*5cb3566aSJeuk Kim g_assert_cmpuint(ocs, ==, UFS_OCS_SUCCESS); 70649ccea4bSYoochan Jeong g_assert_cmpuint(rsp_upiu.header.response, ==, UFS_COMMAND_RESULT_SUCCESS); 70749ccea4bSYoochan Jeong g_assert_cmpuint(rsp_upiu.qr.value, ==, cpu_to_be32(0x07)); 70849ccea4bSYoochan Jeong 70949ccea4bSYoochan Jeong /* Write Invalid Value (Intended Error) */ 710*5cb3566aSJeuk Kim ocs = ufs_send_query(ufs, UFS_UPIU_QUERY_FUNC_STANDARD_WRITE_REQUEST, 71149ccea4bSYoochan Jeong UFS_UPIU_QUERY_OPCODE_WRITE_ATTR, 712*5cb3566aSJeuk Kim UFS_QUERY_ATTR_IDN_ACTIVE_ICC_LVL, 0, 0, 0x10, 71349ccea4bSYoochan Jeong &rsp_upiu); 714*5cb3566aSJeuk Kim g_assert_cmpuint(ocs, ==, UFS_OCS_INVALID_CMD_TABLE_ATTR); 71549ccea4bSYoochan Jeong g_assert_cmpuint(rsp_upiu.header.response, ==, 71649ccea4bSYoochan Jeong UFS_QUERY_RESULT_INVALID_VALUE); 71749ccea4bSYoochan Jeong 718*5cb3566aSJeuk Kim ocs = ufs_send_query(ufs, UFS_UPIU_QUERY_FUNC_STANDARD_READ_REQUEST, 71949ccea4bSYoochan Jeong UFS_UPIU_QUERY_OPCODE_READ_ATTR, 720*5cb3566aSJeuk Kim UFS_QUERY_ATTR_IDN_ACTIVE_ICC_LVL, 0, 0, 0, &rsp_upiu); 721*5cb3566aSJeuk Kim g_assert_cmpuint(ocs, ==, UFS_OCS_SUCCESS); 72249ccea4bSYoochan Jeong g_assert_cmpuint(rsp_upiu.header.response, ==, UFS_COMMAND_RESULT_SUCCESS); 72349ccea4bSYoochan Jeong g_assert_cmpuint(rsp_upiu.qr.value, ==, cpu_to_be32(0x03)); 72449ccea4bSYoochan Jeong 72549ccea4bSYoochan Jeong /* Read Write-Only Attribute (Intended Error) */ 726*5cb3566aSJeuk Kim ocs = ufs_send_query(ufs, UFS_UPIU_QUERY_FUNC_STANDARD_READ_REQUEST, 72749ccea4bSYoochan Jeong UFS_UPIU_QUERY_OPCODE_READ_ATTR, 728*5cb3566aSJeuk Kim UFS_QUERY_ATTR_IDN_SECONDS_PASSED, 0, 0, 0, &rsp_upiu); 729*5cb3566aSJeuk Kim g_assert_cmpuint(ocs, ==, UFS_OCS_INVALID_CMD_TABLE_ATTR); 73049ccea4bSYoochan Jeong g_assert_cmpuint(rsp_upiu.header.response, ==, 73149ccea4bSYoochan Jeong UFS_QUERY_RESULT_NOT_READABLE); 73249ccea4bSYoochan Jeong 73349ccea4bSYoochan Jeong /* Write Read-Only Attribute (Intended Error) */ 734*5cb3566aSJeuk Kim ocs = ufs_send_query(ufs, UFS_UPIU_QUERY_FUNC_STANDARD_WRITE_REQUEST, 73549ccea4bSYoochan Jeong UFS_UPIU_QUERY_OPCODE_WRITE_ATTR, 736*5cb3566aSJeuk Kim UFS_QUERY_ATTR_IDN_POWER_MODE, 0, 0, 0x01, &rsp_upiu); 737*5cb3566aSJeuk Kim g_assert_cmpuint(ocs, ==, UFS_OCS_INVALID_CMD_TABLE_ATTR); 73849ccea4bSYoochan Jeong g_assert_cmpuint(rsp_upiu.header.response, ==, 73949ccea4bSYoochan Jeong UFS_QUERY_RESULT_NOT_WRITEABLE); 74049ccea4bSYoochan Jeong 741*5cb3566aSJeuk Kim ocs = ufs_send_query(ufs, UFS_UPIU_QUERY_FUNC_STANDARD_READ_REQUEST, 74249ccea4bSYoochan Jeong UFS_UPIU_QUERY_OPCODE_READ_ATTR, 743*5cb3566aSJeuk Kim UFS_QUERY_ATTR_IDN_POWER_MODE, 0, 0, 0, &rsp_upiu); 744*5cb3566aSJeuk Kim g_assert_cmpuint(ocs, ==, UFS_OCS_SUCCESS); 74549ccea4bSYoochan Jeong g_assert_cmpuint(rsp_upiu.header.response, ==, UFS_COMMAND_RESULT_SUCCESS); 74649ccea4bSYoochan Jeong g_assert_cmpuint(rsp_upiu.qr.value, ==, cpu_to_be32(0x00)); 74749ccea4bSYoochan Jeong 74849ccea4bSYoochan Jeong /* Reset Written Attributes */ 749*5cb3566aSJeuk Kim ocs = ufs_send_query(ufs, UFS_UPIU_QUERY_FUNC_STANDARD_WRITE_REQUEST, 75049ccea4bSYoochan Jeong UFS_UPIU_QUERY_OPCODE_WRITE_ATTR, 751*5cb3566aSJeuk Kim UFS_QUERY_ATTR_IDN_ACTIVE_ICC_LVL, 0, 0, 0, &rsp_upiu); 752*5cb3566aSJeuk Kim g_assert_cmpuint(ocs, ==, UFS_OCS_SUCCESS); 75349ccea4bSYoochan Jeong g_assert_cmpuint(rsp_upiu.header.response, ==, UFS_COMMAND_RESULT_SUCCESS); 75449ccea4bSYoochan Jeong g_assert_cmpuint(rsp_upiu.qr.value, ==, cpu_to_be32(0x00)); 75549ccea4bSYoochan Jeong 756*5cb3566aSJeuk Kim ocs = ufs_send_query(ufs, UFS_UPIU_QUERY_FUNC_STANDARD_WRITE_REQUEST, 75749ccea4bSYoochan Jeong UFS_UPIU_QUERY_OPCODE_WRITE_ATTR, 758*5cb3566aSJeuk Kim UFS_QUERY_ATTR_IDN_EE_CONTROL, 0, 0, 0, &rsp_upiu); 759*5cb3566aSJeuk Kim g_assert_cmpuint(ocs, ==, UFS_OCS_SUCCESS); 76049ccea4bSYoochan Jeong g_assert_cmpuint(rsp_upiu.header.response, ==, UFS_COMMAND_RESULT_SUCCESS); 76149ccea4bSYoochan Jeong g_assert_cmpuint(rsp_upiu.qr.value, ==, cpu_to_be32(0x00)); 76249ccea4bSYoochan Jeong 763*5cb3566aSJeuk Kim ocs = ufs_send_query(ufs, UFS_UPIU_QUERY_FUNC_STANDARD_READ_REQUEST, 76449ccea4bSYoochan Jeong UFS_UPIU_QUERY_OPCODE_READ_ATTR, 765*5cb3566aSJeuk Kim UFS_QUERY_ATTR_IDN_ACTIVE_ICC_LVL, 0, 0, 0, &rsp_upiu); 766*5cb3566aSJeuk Kim g_assert_cmpuint(ocs, ==, UFS_OCS_SUCCESS); 76749ccea4bSYoochan Jeong g_assert_cmpuint(rsp_upiu.header.response, ==, UFS_COMMAND_RESULT_SUCCESS); 76849ccea4bSYoochan Jeong g_assert_cmpuint(rsp_upiu.qr.value, ==, cpu_to_be32(0x00)); 76949ccea4bSYoochan Jeong 770*5cb3566aSJeuk Kim ocs = ufs_send_query(ufs, UFS_UPIU_QUERY_FUNC_STANDARD_READ_REQUEST, 77149ccea4bSYoochan Jeong UFS_UPIU_QUERY_OPCODE_READ_ATTR, 772*5cb3566aSJeuk Kim UFS_QUERY_ATTR_IDN_EE_CONTROL, 0, 0, 0, &rsp_upiu); 773*5cb3566aSJeuk Kim g_assert_cmpuint(ocs, ==, UFS_OCS_SUCCESS); 77449ccea4bSYoochan Jeong g_assert_cmpuint(rsp_upiu.header.response, ==, UFS_COMMAND_RESULT_SUCCESS); 77549ccea4bSYoochan Jeong g_assert_cmpuint(rsp_upiu.qr.value, ==, cpu_to_be32(0x00)); 77649ccea4bSYoochan Jeong 77749ccea4bSYoochan Jeong ufs_exit(ufs, alloc); 77849ccea4bSYoochan Jeong } 77949ccea4bSYoochan Jeong 7809fe8e2c6SYoochan Jeong static void ufstest_query_desc_request(void *obj, void *data, 7819fe8e2c6SYoochan Jeong QGuestAllocator *alloc) 7829fe8e2c6SYoochan Jeong { 7839fe8e2c6SYoochan Jeong QUfs *ufs = obj; 7849fe8e2c6SYoochan Jeong 785*5cb3566aSJeuk Kim enum UtpOcsCodes ocs; 7869fe8e2c6SYoochan Jeong UtpUpiuRsp rsp_upiu; 7879fe8e2c6SYoochan Jeong ufs_init(ufs, alloc); 7889fe8e2c6SYoochan Jeong 7899fe8e2c6SYoochan Jeong /* Write Descriptor is not supported yet */ 7909fe8e2c6SYoochan Jeong 7919fe8e2c6SYoochan Jeong /* Read Device Descriptor */ 792*5cb3566aSJeuk Kim ocs = ufs_send_query(ufs, UFS_UPIU_QUERY_FUNC_STANDARD_READ_REQUEST, 793*5cb3566aSJeuk Kim UFS_UPIU_QUERY_OPCODE_READ_DESC, 794*5cb3566aSJeuk Kim UFS_QUERY_DESC_IDN_DEVICE, 0, 0, 0, &rsp_upiu); 795*5cb3566aSJeuk Kim g_assert_cmpuint(ocs, ==, UFS_OCS_SUCCESS); 7969fe8e2c6SYoochan Jeong g_assert_cmpuint(rsp_upiu.header.response, ==, UFS_COMMAND_RESULT_SUCCESS); 7979fe8e2c6SYoochan Jeong g_assert_cmpuint(rsp_upiu.qr.opcode, ==, UFS_UPIU_QUERY_OPCODE_READ_DESC); 7989fe8e2c6SYoochan Jeong g_assert_cmpuint(rsp_upiu.qr.idn, ==, UFS_QUERY_DESC_IDN_DEVICE); 7999fe8e2c6SYoochan Jeong g_assert_cmpuint(rsp_upiu.qr.data[0], ==, sizeof(DeviceDescriptor)); 8009fe8e2c6SYoochan Jeong g_assert_cmpuint(rsp_upiu.qr.data[1], ==, UFS_QUERY_DESC_IDN_DEVICE); 8019fe8e2c6SYoochan Jeong 8029fe8e2c6SYoochan Jeong /* Read Configuration Descriptor is not supported yet*/ 8039fe8e2c6SYoochan Jeong 8049fe8e2c6SYoochan Jeong /* Read Unit Descriptor */ 805*5cb3566aSJeuk Kim ocs = ufs_send_query(ufs, UFS_UPIU_QUERY_FUNC_STANDARD_READ_REQUEST, 806*5cb3566aSJeuk Kim UFS_UPIU_QUERY_OPCODE_READ_DESC, 807*5cb3566aSJeuk Kim UFS_QUERY_DESC_IDN_UNIT, 0, 0, 0, &rsp_upiu); 808*5cb3566aSJeuk Kim g_assert_cmpuint(ocs, ==, UFS_OCS_SUCCESS); 8099fe8e2c6SYoochan Jeong g_assert_cmpuint(rsp_upiu.header.response, ==, UFS_COMMAND_RESULT_SUCCESS); 8109fe8e2c6SYoochan Jeong g_assert_cmpuint(rsp_upiu.qr.data[0], ==, sizeof(UnitDescriptor)); 8119fe8e2c6SYoochan Jeong g_assert_cmpuint(rsp_upiu.qr.data[1], ==, UFS_QUERY_DESC_IDN_UNIT); 8129fe8e2c6SYoochan Jeong g_assert_cmpuint(rsp_upiu.qr.data[2], ==, 0); 8139fe8e2c6SYoochan Jeong 814*5cb3566aSJeuk Kim ocs = ufs_send_query(ufs, UFS_UPIU_QUERY_FUNC_STANDARD_READ_REQUEST, 815*5cb3566aSJeuk Kim UFS_UPIU_QUERY_OPCODE_READ_DESC, 816*5cb3566aSJeuk Kim UFS_QUERY_DESC_IDN_UNIT, 1, 0, 0, &rsp_upiu); 817*5cb3566aSJeuk Kim g_assert_cmpuint(ocs, ==, UFS_OCS_SUCCESS); 8189fe8e2c6SYoochan Jeong g_assert_cmpuint(rsp_upiu.header.response, ==, UFS_COMMAND_RESULT_SUCCESS); 8199fe8e2c6SYoochan Jeong g_assert_cmpuint(rsp_upiu.qr.data[0], ==, sizeof(UnitDescriptor)); 8209fe8e2c6SYoochan Jeong g_assert_cmpuint(rsp_upiu.qr.data[1], ==, UFS_QUERY_DESC_IDN_UNIT); 8219fe8e2c6SYoochan Jeong g_assert_cmpuint(rsp_upiu.qr.data[2], ==, 1); 8229fe8e2c6SYoochan Jeong 823*5cb3566aSJeuk Kim ocs = 824*5cb3566aSJeuk Kim ufs_send_query(ufs, UFS_UPIU_QUERY_FUNC_STANDARD_READ_REQUEST, 8259fe8e2c6SYoochan Jeong UFS_UPIU_QUERY_OPCODE_READ_DESC, UFS_QUERY_DESC_IDN_UNIT, 826*5cb3566aSJeuk Kim UFS_UPIU_RPMB_WLUN, 0, 0, &rsp_upiu); 827*5cb3566aSJeuk Kim g_assert_cmpuint(ocs, ==, UFS_OCS_SUCCESS); 8289fe8e2c6SYoochan Jeong g_assert_cmpuint(rsp_upiu.header.response, ==, UFS_COMMAND_RESULT_SUCCESS); 8299fe8e2c6SYoochan Jeong g_assert_cmpuint(rsp_upiu.qr.data[0], ==, sizeof(RpmbUnitDescriptor)); 8309fe8e2c6SYoochan Jeong g_assert_cmpuint(rsp_upiu.qr.data[1], ==, UFS_QUERY_DESC_IDN_UNIT); 8319fe8e2c6SYoochan Jeong g_assert_cmpuint(rsp_upiu.qr.data[2], ==, UFS_UPIU_RPMB_WLUN); 8329fe8e2c6SYoochan Jeong 8339fe8e2c6SYoochan Jeong /* Read Interconnect Descriptor */ 834*5cb3566aSJeuk Kim ocs = ufs_send_query(ufs, UFS_UPIU_QUERY_FUNC_STANDARD_READ_REQUEST, 8359fe8e2c6SYoochan Jeong UFS_UPIU_QUERY_OPCODE_READ_DESC, 836*5cb3566aSJeuk Kim UFS_QUERY_DESC_IDN_INTERCONNECT, 0, 0, 0, &rsp_upiu); 837*5cb3566aSJeuk Kim g_assert_cmpuint(ocs, ==, UFS_OCS_SUCCESS); 8389fe8e2c6SYoochan Jeong g_assert_cmpuint(rsp_upiu.header.response, ==, UFS_COMMAND_RESULT_SUCCESS); 8399fe8e2c6SYoochan Jeong g_assert_cmpuint(rsp_upiu.qr.data[0], ==, sizeof(InterconnectDescriptor)); 8409fe8e2c6SYoochan Jeong g_assert_cmpuint(rsp_upiu.qr.data[1], ==, UFS_QUERY_DESC_IDN_INTERCONNECT); 8419fe8e2c6SYoochan Jeong 8429fe8e2c6SYoochan Jeong /* Read String Descriptor */ 843*5cb3566aSJeuk Kim ocs = ufs_send_query(ufs, UFS_UPIU_QUERY_FUNC_STANDARD_READ_REQUEST, 844*5cb3566aSJeuk Kim UFS_UPIU_QUERY_OPCODE_READ_DESC, 845*5cb3566aSJeuk Kim UFS_QUERY_DESC_IDN_STRING, 0, 0, 0, &rsp_upiu); 846*5cb3566aSJeuk Kim g_assert_cmpuint(ocs, ==, UFS_OCS_SUCCESS); 8479fe8e2c6SYoochan Jeong g_assert_cmpuint(rsp_upiu.header.response, ==, UFS_COMMAND_RESULT_SUCCESS); 8489fe8e2c6SYoochan Jeong g_assert_cmpuint(rsp_upiu.qr.data[0], ==, 0x12); 8499fe8e2c6SYoochan Jeong g_assert_cmpuint(rsp_upiu.qr.data[1], ==, UFS_QUERY_DESC_IDN_STRING); 8509fe8e2c6SYoochan Jeong 851*5cb3566aSJeuk Kim ocs = ufs_send_query(ufs, UFS_UPIU_QUERY_FUNC_STANDARD_READ_REQUEST, 852*5cb3566aSJeuk Kim UFS_UPIU_QUERY_OPCODE_READ_DESC, 853*5cb3566aSJeuk Kim UFS_QUERY_DESC_IDN_STRING, 1, 0, 0, &rsp_upiu); 854*5cb3566aSJeuk Kim g_assert_cmpuint(ocs, ==, UFS_OCS_SUCCESS); 8559fe8e2c6SYoochan Jeong g_assert_cmpuint(rsp_upiu.header.response, ==, UFS_COMMAND_RESULT_SUCCESS); 8569fe8e2c6SYoochan Jeong g_assert_cmpuint(rsp_upiu.qr.data[0], ==, 0x22); 8579fe8e2c6SYoochan Jeong g_assert_cmpuint(rsp_upiu.qr.data[1], ==, UFS_QUERY_DESC_IDN_STRING); 8589fe8e2c6SYoochan Jeong 859*5cb3566aSJeuk Kim ocs = ufs_send_query(ufs, UFS_UPIU_QUERY_FUNC_STANDARD_READ_REQUEST, 860*5cb3566aSJeuk Kim UFS_UPIU_QUERY_OPCODE_READ_DESC, 861*5cb3566aSJeuk Kim UFS_QUERY_DESC_IDN_STRING, 4, 0, 0, &rsp_upiu); 862*5cb3566aSJeuk Kim g_assert_cmpuint(ocs, ==, UFS_OCS_SUCCESS); 8639fe8e2c6SYoochan Jeong g_assert_cmpuint(rsp_upiu.header.response, ==, UFS_COMMAND_RESULT_SUCCESS); 8649fe8e2c6SYoochan Jeong g_assert_cmpuint(rsp_upiu.qr.data[0], ==, 0x0a); 8659fe8e2c6SYoochan Jeong g_assert_cmpuint(rsp_upiu.qr.data[1], ==, UFS_QUERY_DESC_IDN_STRING); 8669fe8e2c6SYoochan Jeong 8679fe8e2c6SYoochan Jeong /* Read Geometry Descriptor */ 868*5cb3566aSJeuk Kim ocs = ufs_send_query(ufs, UFS_UPIU_QUERY_FUNC_STANDARD_READ_REQUEST, 869*5cb3566aSJeuk Kim UFS_UPIU_QUERY_OPCODE_READ_DESC, 870*5cb3566aSJeuk Kim UFS_QUERY_DESC_IDN_GEOMETRY, 0, 0, 0, &rsp_upiu); 871*5cb3566aSJeuk Kim g_assert_cmpuint(ocs, ==, UFS_OCS_SUCCESS); 8729fe8e2c6SYoochan Jeong g_assert_cmpuint(rsp_upiu.header.response, ==, UFS_COMMAND_RESULT_SUCCESS); 8739fe8e2c6SYoochan Jeong g_assert_cmpuint(rsp_upiu.qr.data[0], ==, sizeof(GeometryDescriptor)); 8749fe8e2c6SYoochan Jeong g_assert_cmpuint(rsp_upiu.qr.data[1], ==, UFS_QUERY_DESC_IDN_GEOMETRY); 8759fe8e2c6SYoochan Jeong 8769fe8e2c6SYoochan Jeong /* Read Power Descriptor */ 877*5cb3566aSJeuk Kim ocs = ufs_send_query(ufs, UFS_UPIU_QUERY_FUNC_STANDARD_READ_REQUEST, 878*5cb3566aSJeuk Kim UFS_UPIU_QUERY_OPCODE_READ_DESC, 879*5cb3566aSJeuk Kim UFS_QUERY_DESC_IDN_POWER, 0, 0, 0, &rsp_upiu); 880*5cb3566aSJeuk Kim g_assert_cmpuint(ocs, ==, UFS_OCS_SUCCESS); 8819fe8e2c6SYoochan Jeong g_assert_cmpuint(rsp_upiu.header.response, ==, UFS_COMMAND_RESULT_SUCCESS); 8829fe8e2c6SYoochan Jeong g_assert_cmpuint(rsp_upiu.qr.data[0], ==, 8839fe8e2c6SYoochan Jeong sizeof(PowerParametersDescriptor)); 8849fe8e2c6SYoochan Jeong g_assert_cmpuint(rsp_upiu.qr.data[1], ==, UFS_QUERY_DESC_IDN_POWER); 8859fe8e2c6SYoochan Jeong 8869fe8e2c6SYoochan Jeong /* Read Health Descriptor */ 887*5cb3566aSJeuk Kim ocs = ufs_send_query(ufs, UFS_UPIU_QUERY_FUNC_STANDARD_READ_REQUEST, 888*5cb3566aSJeuk Kim UFS_UPIU_QUERY_OPCODE_READ_DESC, 889*5cb3566aSJeuk Kim UFS_QUERY_DESC_IDN_HEALTH, 0, 0, 0, &rsp_upiu); 890*5cb3566aSJeuk Kim g_assert_cmpuint(ocs, ==, UFS_OCS_SUCCESS); 8919fe8e2c6SYoochan Jeong g_assert_cmpuint(rsp_upiu.header.response, ==, UFS_COMMAND_RESULT_SUCCESS); 8929fe8e2c6SYoochan Jeong g_assert_cmpuint(rsp_upiu.qr.data[0], ==, sizeof(DeviceHealthDescriptor)); 8939fe8e2c6SYoochan Jeong g_assert_cmpuint(rsp_upiu.qr.data[1], ==, UFS_QUERY_DESC_IDN_HEALTH); 8949fe8e2c6SYoochan Jeong 8959fe8e2c6SYoochan Jeong /* Invalid Index (Intended Failure) */ 896*5cb3566aSJeuk Kim ocs = ufs_send_query(ufs, UFS_UPIU_QUERY_FUNC_STANDARD_READ_REQUEST, 897*5cb3566aSJeuk Kim UFS_UPIU_QUERY_OPCODE_READ_DESC, 898*5cb3566aSJeuk Kim UFS_QUERY_DESC_IDN_UNIT, 4, 0, 0, &rsp_upiu); 899*5cb3566aSJeuk Kim g_assert_cmpuint(ocs, ==, UFS_OCS_INVALID_CMD_TABLE_ATTR); 9009fe8e2c6SYoochan Jeong g_assert_cmpuint(rsp_upiu.header.response, ==, 9019fe8e2c6SYoochan Jeong UFS_QUERY_RESULT_INVALID_INDEX); 9029fe8e2c6SYoochan Jeong 903*5cb3566aSJeuk Kim ocs = ufs_send_query(ufs, UFS_UPIU_QUERY_FUNC_STANDARD_READ_REQUEST, 904*5cb3566aSJeuk Kim UFS_UPIU_QUERY_OPCODE_READ_DESC, 905*5cb3566aSJeuk Kim UFS_QUERY_DESC_IDN_STRING, 5, 0, 0, &rsp_upiu); 906*5cb3566aSJeuk Kim g_assert_cmpuint(ocs, ==, UFS_OCS_INVALID_CMD_TABLE_ATTR); 9079fe8e2c6SYoochan Jeong g_assert_cmpuint(rsp_upiu.header.response, ==, 9089fe8e2c6SYoochan Jeong UFS_QUERY_RESULT_INVALID_INDEX); 9099fe8e2c6SYoochan Jeong 9109fe8e2c6SYoochan Jeong /* Invalid Selector (Intended Failure) */ 911*5cb3566aSJeuk Kim ocs = ufs_send_query(ufs, UFS_UPIU_QUERY_FUNC_STANDARD_READ_REQUEST, 912*5cb3566aSJeuk Kim UFS_UPIU_QUERY_OPCODE_READ_DESC, 913*5cb3566aSJeuk Kim UFS_QUERY_DESC_IDN_DEVICE, 0, 1, 0, &rsp_upiu); 914*5cb3566aSJeuk Kim g_assert_cmpuint(ocs, ==, UFS_OCS_INVALID_CMD_TABLE_ATTR); 9159fe8e2c6SYoochan Jeong g_assert_cmpuint(rsp_upiu.header.response, ==, 9169fe8e2c6SYoochan Jeong UFS_QUERY_RESULT_INVALID_SELECTOR); 9179fe8e2c6SYoochan Jeong 918*5cb3566aSJeuk Kim ocs = ufs_send_query(ufs, UFS_UPIU_QUERY_FUNC_STANDARD_READ_REQUEST, 919*5cb3566aSJeuk Kim UFS_UPIU_QUERY_OPCODE_READ_DESC, 920*5cb3566aSJeuk Kim UFS_QUERY_DESC_IDN_STRING, 0, 1, 0, &rsp_upiu); 921*5cb3566aSJeuk Kim g_assert_cmpuint(ocs, ==, UFS_OCS_INVALID_CMD_TABLE_ATTR); 9229fe8e2c6SYoochan Jeong g_assert_cmpuint(rsp_upiu.header.response, ==, 9239fe8e2c6SYoochan Jeong UFS_QUERY_RESULT_INVALID_SELECTOR); 9249fe8e2c6SYoochan Jeong 9259fe8e2c6SYoochan Jeong ufs_exit(ufs, alloc); 9269fe8e2c6SYoochan Jeong } 9279fe8e2c6SYoochan Jeong 928631c8726SJeuk Kim static void drive_destroy(void *path) 929631c8726SJeuk Kim { 930631c8726SJeuk Kim unlink(path); 931631c8726SJeuk Kim g_free(path); 932631c8726SJeuk Kim qos_invalidate_command_line(); 933631c8726SJeuk Kim } 934631c8726SJeuk Kim 935631c8726SJeuk Kim static char *drive_create(void) 936631c8726SJeuk Kim { 937631c8726SJeuk Kim int fd, ret; 938631c8726SJeuk Kim char *t_path; 939631c8726SJeuk Kim 940631c8726SJeuk Kim /* Create a temporary raw image */ 941631c8726SJeuk Kim fd = g_file_open_tmp("qtest-ufs.XXXXXX", &t_path, NULL); 942631c8726SJeuk Kim g_assert_cmpint(fd, >=, 0); 943631c8726SJeuk Kim ret = ftruncate(fd, TEST_IMAGE_SIZE); 944631c8726SJeuk Kim g_assert_cmpint(ret, ==, 0); 945631c8726SJeuk Kim close(fd); 946631c8726SJeuk Kim 947631c8726SJeuk Kim g_test_queue_destroy(drive_destroy, t_path); 948631c8726SJeuk Kim return t_path; 949631c8726SJeuk Kim } 950631c8726SJeuk Kim 951631c8726SJeuk Kim static void *ufs_blk_test_setup(GString *cmd_line, void *arg) 952631c8726SJeuk Kim { 953631c8726SJeuk Kim char *tmp_path = drive_create(); 954631c8726SJeuk Kim 955631c8726SJeuk Kim g_string_append_printf(cmd_line, 956631c8726SJeuk Kim " -blockdev file,filename=%s,node-name=drv1 " 957631c8726SJeuk Kim "-device ufs-lu,bus=ufs0,drive=drv1,lun=1 ", 958631c8726SJeuk Kim tmp_path); 959631c8726SJeuk Kim 960631c8726SJeuk Kim return arg; 961631c8726SJeuk Kim } 962631c8726SJeuk Kim 963631c8726SJeuk Kim static void ufs_register_nodes(void) 964631c8726SJeuk Kim { 965631c8726SJeuk Kim const char *arch; 966631c8726SJeuk Kim QOSGraphEdgeOptions edge_opts = { 967631c8726SJeuk Kim .before_cmd_line = "-blockdev null-co,node-name=drv0,read-zeroes=on", 968631c8726SJeuk Kim .after_cmd_line = "-device ufs-lu,bus=ufs0,drive=drv0,lun=0", 969631c8726SJeuk Kim .extra_device_opts = "addr=04.0,id=ufs0,nutrs=32,nutmrs=8" 970631c8726SJeuk Kim }; 971631c8726SJeuk Kim 972631c8726SJeuk Kim QOSGraphTestOptions io_test_opts = { 973631c8726SJeuk Kim .before = ufs_blk_test_setup, 974631c8726SJeuk Kim }; 975631c8726SJeuk Kim 976631c8726SJeuk Kim add_qpci_address(&edge_opts, &(QPCIAddress){ .devfn = QPCI_DEVFN(4, 0) }); 977631c8726SJeuk Kim 978631c8726SJeuk Kim qos_node_create_driver("ufs", ufs_create); 979631c8726SJeuk Kim qos_node_consumes("ufs", "pci-bus", &edge_opts); 980631c8726SJeuk Kim qos_node_produces("ufs", "pci-device"); 981631c8726SJeuk Kim 982631c8726SJeuk Kim qos_add_test("reg-read", "ufs", ufstest_reg_read, NULL); 983631c8726SJeuk Kim 984631c8726SJeuk Kim /* 985631c8726SJeuk Kim * Check architecture 986631c8726SJeuk Kim * TODO: Enable ufs io tests for ppc64 987631c8726SJeuk Kim */ 988631c8726SJeuk Kim arch = qtest_get_arch(); 989631c8726SJeuk Kim if (!strcmp(arch, "ppc64")) { 990631c8726SJeuk Kim g_test_message("Skipping ufs io tests for ppc64"); 991631c8726SJeuk Kim return; 992631c8726SJeuk Kim } 993631c8726SJeuk Kim qos_add_test("init", "ufs", ufstest_init, NULL); 994631c8726SJeuk Kim qos_add_test("read-write", "ufs", ufstest_read_write, &io_test_opts); 9954aac3029SYoochan Jeong qos_add_test("flag read-write", "ufs", 9964aac3029SYoochan Jeong ufstest_query_flag_request, &io_test_opts); 99749ccea4bSYoochan Jeong qos_add_test("attr read-write", "ufs", 99849ccea4bSYoochan Jeong ufstest_query_attr_request, &io_test_opts); 9999fe8e2c6SYoochan Jeong qos_add_test("desc read-write", "ufs", 10009fe8e2c6SYoochan Jeong ufstest_query_desc_request, &io_test_opts); 1001631c8726SJeuk Kim } 1002631c8726SJeuk Kim 1003631c8726SJeuk Kim libqos_init(ufs_register_nodes); 1004