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" 165cb3566aSJeuk Kim #include "qemu/bitmap.h" 17631c8726SJeuk Kim 18*a54596a9SJeuk Kim #define DWORD_BYTE 4 19631c8726SJeuk Kim /* Test images sizes in Bytes */ 20631c8726SJeuk Kim #define TEST_IMAGE_SIZE (64 * 1024 * 1024) 21631c8726SJeuk Kim /* Timeout for various operations, in seconds. */ 22631c8726SJeuk Kim #define TIMEOUT_SECONDS 10 23631c8726SJeuk Kim /* Maximum PRD entry count */ 24631c8726SJeuk Kim #define MAX_PRD_ENTRY_COUNT 10 25631c8726SJeuk Kim #define PRD_ENTRY_DATA_SIZE 4096 26631c8726SJeuk Kim /* Constants to build upiu */ 27631c8726SJeuk Kim #define UTP_COMMAND_DESCRIPTOR_SIZE 4096 28631c8726SJeuk Kim #define UTP_RESPONSE_UPIU_OFFSET 1024 29631c8726SJeuk Kim #define UTP_PRDT_UPIU_OFFSET 2048 305cb3566aSJeuk Kim #define UTRD_TEST_SLOT 0 315cb3566aSJeuk Kim #define UFS_MAX_CMD_DESC 32 32*a54596a9SJeuk Kim /* Constants for MCQ */ 33*a54596a9SJeuk Kim #define TEST_QID 0 34*a54596a9SJeuk Kim #define QUEUE_SIZE 32 35*a54596a9SJeuk Kim #define UFS_MCQ_MAX_QNUM 32 36631c8726SJeuk Kim 37631c8726SJeuk Kim typedef struct QUfs QUfs; 38631c8726SJeuk Kim 39631c8726SJeuk Kim struct QUfs { 40631c8726SJeuk Kim QOSGraphObject obj; 41631c8726SJeuk Kim QPCIDevice dev; 42631c8726SJeuk Kim QPCIBar bar; 43631c8726SJeuk Kim 445cb3566aSJeuk Kim DECLARE_BITMAP(cmd_desc_bitmap, UFS_MAX_CMD_DESC); 45631c8726SJeuk Kim uint64_t cmd_desc_addr; 46631c8726SJeuk Kim uint64_t data_buffer_addr; 47631c8726SJeuk Kim 48631c8726SJeuk Kim bool enabled; 49*a54596a9SJeuk Kim bool support_mcq; 50*a54596a9SJeuk Kim 51*a54596a9SJeuk Kim /* for legacy doorbell mode */ 52*a54596a9SJeuk Kim uint64_t utrlba; 53*a54596a9SJeuk Kim 54*a54596a9SJeuk Kim /* for mcq mode */ 55*a54596a9SJeuk Kim uint32_t maxq; 56*a54596a9SJeuk Kim uint64_t sqlba[UFS_MCQ_MAX_QNUM]; 57*a54596a9SJeuk Kim uint64_t cqlba[UFS_MCQ_MAX_QNUM]; 58*a54596a9SJeuk Kim uint64_t sqdao[UFS_MCQ_MAX_QNUM]; 59*a54596a9SJeuk Kim uint64_t cqdao[UFS_MCQ_MAX_QNUM]; 60631c8726SJeuk Kim }; 61631c8726SJeuk Kim 62631c8726SJeuk Kim static inline uint32_t ufs_rreg(QUfs *ufs, size_t offset) 63631c8726SJeuk Kim { 64631c8726SJeuk Kim return qpci_io_readl(&ufs->dev, ufs->bar, offset); 65631c8726SJeuk Kim } 66631c8726SJeuk Kim 67631c8726SJeuk Kim static inline void ufs_wreg(QUfs *ufs, size_t offset, uint32_t value) 68631c8726SJeuk Kim { 69631c8726SJeuk Kim qpci_io_writel(&ufs->dev, ufs->bar, offset, value); 70631c8726SJeuk Kim } 71631c8726SJeuk Kim 725cb3566aSJeuk Kim static int alloc_cmd_desc_slot(QUfs *ufs) 735cb3566aSJeuk Kim { 745cb3566aSJeuk Kim int slot = find_first_zero_bit(ufs->cmd_desc_bitmap, UFS_MAX_CMD_DESC); 755cb3566aSJeuk Kim if (slot == UFS_MAX_CMD_DESC) { 765cb3566aSJeuk Kim g_assert_not_reached(); 775cb3566aSJeuk Kim } 785cb3566aSJeuk Kim set_bit(slot, ufs->cmd_desc_bitmap); 795cb3566aSJeuk Kim return slot; 805cb3566aSJeuk Kim } 815cb3566aSJeuk Kim 825cb3566aSJeuk Kim static void release_cmd_desc_slot(QUfs *ufs, int slot) 835cb3566aSJeuk Kim { 845cb3566aSJeuk Kim if (!test_bit(slot, ufs->cmd_desc_bitmap)) { 855cb3566aSJeuk Kim g_assert_not_reached(); 865cb3566aSJeuk Kim } 875cb3566aSJeuk Kim clear_bit(slot, ufs->cmd_desc_bitmap); 885cb3566aSJeuk Kim } 895cb3566aSJeuk Kim 90631c8726SJeuk Kim static void ufs_wait_for_irq(QUfs *ufs) 91631c8726SJeuk Kim { 92631c8726SJeuk Kim uint64_t end_time; 93631c8726SJeuk Kim uint32_t is; 94631c8726SJeuk Kim /* Wait for device to reset as the linux driver does. */ 95631c8726SJeuk Kim end_time = g_get_monotonic_time() + TIMEOUT_SECONDS * G_TIME_SPAN_SECOND; 96631c8726SJeuk Kim do { 97631c8726SJeuk Kim qtest_clock_step(ufs->dev.bus->qts, 100); 98631c8726SJeuk Kim is = ufs_rreg(ufs, A_IS); 99631c8726SJeuk Kim } while (is == 0 && g_get_monotonic_time() < end_time); 100631c8726SJeuk Kim } 101631c8726SJeuk Kim 1025cb3566aSJeuk Kim static UtpTransferReqDesc ufs_build_req_utrd(uint64_t command_desc_base_addr, 103631c8726SJeuk Kim uint32_t data_direction, 104631c8726SJeuk Kim uint16_t prd_table_length) 105631c8726SJeuk Kim { 106631c8726SJeuk Kim UtpTransferReqDesc req = { 0 }; 107631c8726SJeuk Kim 108631c8726SJeuk Kim req.header.dword_0 = 109631c8726SJeuk Kim cpu_to_le32(1 << 28 | data_direction | UFS_UTP_REQ_DESC_INT_CMD); 110631c8726SJeuk Kim req.header.dword_2 = cpu_to_le32(UFS_OCS_INVALID_COMMAND_STATUS); 111631c8726SJeuk Kim 112631c8726SJeuk Kim req.command_desc_base_addr_hi = cpu_to_le32(command_desc_base_addr >> 32); 113631c8726SJeuk Kim req.command_desc_base_addr_lo = 114631c8726SJeuk Kim cpu_to_le32(command_desc_base_addr & 0xffffffff); 115631c8726SJeuk Kim req.response_upiu_offset = 116631c8726SJeuk Kim cpu_to_le16(UTP_RESPONSE_UPIU_OFFSET / sizeof(uint32_t)); 117631c8726SJeuk Kim req.response_upiu_length = cpu_to_le16(sizeof(UtpUpiuRsp)); 118631c8726SJeuk Kim req.prd_table_offset = cpu_to_le16(UTP_PRDT_UPIU_OFFSET / sizeof(uint32_t)); 119631c8726SJeuk Kim req.prd_table_length = cpu_to_le16(prd_table_length); 120631c8726SJeuk Kim return req; 121631c8726SJeuk Kim } 122631c8726SJeuk Kim 1235cb3566aSJeuk Kim static enum UtpOcsCodes 124*a54596a9SJeuk Kim __ufs_send_transfer_request_doorbell(QUfs *ufs, uint8_t lun, 1255cb3566aSJeuk Kim const UtpTransferReqDesc *utrd) 126631c8726SJeuk Kim { 1275cb3566aSJeuk Kim uint64_t utrd_addr = 1285cb3566aSJeuk Kim ufs->utrlba + UTRD_TEST_SLOT * sizeof(UtpTransferReqDesc); 129*a54596a9SJeuk Kim UtpTransferReqDesc utrd_result; 130*a54596a9SJeuk Kim 1315cb3566aSJeuk Kim qtest_memwrite(ufs->dev.bus->qts, utrd_addr, utrd, sizeof(*utrd)); 132631c8726SJeuk Kim 133*a54596a9SJeuk Kim /* Ring the doorbell */ 134631c8726SJeuk Kim ufs_wreg(ufs, A_UTRLDBR, 1); 135631c8726SJeuk Kim ufs_wait_for_irq(ufs); 136631c8726SJeuk Kim g_assert_true(FIELD_EX32(ufs_rreg(ufs, A_IS), IS, UTRCS)); 137631c8726SJeuk Kim ufs_wreg(ufs, A_IS, FIELD_DP32(0, IS, UTRCS, 1)); 138631c8726SJeuk Kim 139*a54596a9SJeuk Kim /* Handle completed command */ 1405cb3566aSJeuk Kim qtest_memread(ufs->dev.bus->qts, utrd_addr, &utrd_result, 1415cb3566aSJeuk Kim sizeof(utrd_result)); 1425cb3566aSJeuk Kim return le32_to_cpu(utrd_result.header.dword_2) & 0xf; 143631c8726SJeuk Kim } 144631c8726SJeuk Kim 145*a54596a9SJeuk Kim static enum UtpOcsCodes 146*a54596a9SJeuk Kim __ufs_send_transfer_request_mcq(QUfs *ufs, uint8_t lun, 147*a54596a9SJeuk Kim const UtpTransferReqDesc *utrd) 148*a54596a9SJeuk Kim { 149*a54596a9SJeuk Kim uint32_t sqtp = ufs_rreg(ufs, ufs->sqdao[TEST_QID] + 0x4); 150*a54596a9SJeuk Kim uint64_t utrd_addr = ufs->sqlba[TEST_QID] + sqtp; 151*a54596a9SJeuk Kim uint32_t cqhp; 152*a54596a9SJeuk Kim uint64_t cqentry_addr; 153*a54596a9SJeuk Kim UfsCqEntry cqentry; 154*a54596a9SJeuk Kim 155*a54596a9SJeuk Kim qtest_memwrite(ufs->dev.bus->qts, utrd_addr, utrd, sizeof(*utrd)); 156*a54596a9SJeuk Kim 157*a54596a9SJeuk Kim /* Insert a new entry into the submission queue */ 158*a54596a9SJeuk Kim sqtp = ufs_rreg(ufs, ufs->sqdao[TEST_QID] + 0x4); 159*a54596a9SJeuk Kim sqtp = (sqtp + sizeof(UfsSqEntry)) % (QUEUE_SIZE * sizeof(UfsSqEntry)); 160*a54596a9SJeuk Kim ufs_wreg(ufs, ufs->sqdao[TEST_QID] + 0x4, sqtp); 161*a54596a9SJeuk Kim ufs_wait_for_irq(ufs); 162*a54596a9SJeuk Kim g_assert_true(FIELD_EX32(ufs_rreg(ufs, A_IS), IS, CQES)); 163*a54596a9SJeuk Kim ufs_wreg(ufs, A_IS, FIELD_DP32(0, IS, CQES, 1)); 164*a54596a9SJeuk Kim 165*a54596a9SJeuk Kim /* Handle the completed command from the completion queue */ 166*a54596a9SJeuk Kim cqhp = ufs_rreg(ufs, ufs->cqdao[TEST_QID]); 167*a54596a9SJeuk Kim cqentry_addr = ufs->cqlba[TEST_QID] + cqhp; 168*a54596a9SJeuk Kim qtest_memread(ufs->dev.bus->qts, cqentry_addr, &cqentry, sizeof(cqentry)); 169*a54596a9SJeuk Kim ufs_wreg(ufs, ufs->cqdao[TEST_QID], cqhp); 170*a54596a9SJeuk Kim 171*a54596a9SJeuk Kim return cqentry.status; 172*a54596a9SJeuk Kim } 173*a54596a9SJeuk Kim 174*a54596a9SJeuk Kim static enum UtpOcsCodes 175*a54596a9SJeuk Kim ufs_send_transfer_request_sync(QUfs *ufs, uint8_t lun, 176*a54596a9SJeuk Kim const UtpTransferReqDesc *utrd) 177*a54596a9SJeuk Kim { 178*a54596a9SJeuk Kim if (ufs->support_mcq) { 179*a54596a9SJeuk Kim return __ufs_send_transfer_request_mcq(ufs, lun, utrd); 180*a54596a9SJeuk Kim } 181*a54596a9SJeuk Kim 182*a54596a9SJeuk Kim return __ufs_send_transfer_request_doorbell(ufs, lun, utrd); 183*a54596a9SJeuk Kim } 184*a54596a9SJeuk Kim 1855cb3566aSJeuk Kim static enum UtpOcsCodes ufs_send_nop_out(QUfs *ufs, UtpUpiuRsp *rsp_out) 186631c8726SJeuk Kim { 1875cb3566aSJeuk Kim int cmd_desc_slot = alloc_cmd_desc_slot(ufs); 188631c8726SJeuk Kim uint64_t req_upiu_addr = 1895cb3566aSJeuk Kim ufs->cmd_desc_addr + cmd_desc_slot * UTP_COMMAND_DESCRIPTOR_SIZE; 190631c8726SJeuk Kim uint64_t rsp_upiu_addr = req_upiu_addr + UTP_RESPONSE_UPIU_OFFSET; 1915cb3566aSJeuk Kim 1925cb3566aSJeuk Kim /* Build up request upiu */ 1935cb3566aSJeuk Kim UtpUpiuReq req_upiu = { 0 }; 1945cb3566aSJeuk Kim req_upiu.header.trans_type = UFS_UPIU_TRANSACTION_NOP_OUT; 1955cb3566aSJeuk Kim req_upiu.header.task_tag = cmd_desc_slot; 1965cb3566aSJeuk Kim qtest_memwrite(ufs->dev.bus->qts, req_upiu_addr, &req_upiu, 1975cb3566aSJeuk Kim sizeof(req_upiu)); 1985cb3566aSJeuk Kim 1995cb3566aSJeuk Kim /* Build up utp transfer request descriptor */ 2005cb3566aSJeuk Kim UtpTransferReqDesc utrd = 2015cb3566aSJeuk Kim ufs_build_req_utrd(req_upiu_addr, UFS_UTP_NO_DATA_TRANSFER, 0); 2025cb3566aSJeuk Kim 2035cb3566aSJeuk Kim /* Send Transfer Request */ 2045cb3566aSJeuk Kim enum UtpOcsCodes ret = ufs_send_transfer_request_sync(ufs, 0, &utrd); 2055cb3566aSJeuk Kim 2065cb3566aSJeuk Kim qtest_memread(ufs->dev.bus->qts, rsp_upiu_addr, rsp_out, sizeof(*rsp_out)); 2075cb3566aSJeuk Kim release_cmd_desc_slot(ufs, cmd_desc_slot); 2085cb3566aSJeuk Kim return ret; 2095cb3566aSJeuk Kim } 2105cb3566aSJeuk Kim 2115cb3566aSJeuk Kim static enum UtpOcsCodes ufs_send_query(QUfs *ufs, uint8_t query_function, 2125cb3566aSJeuk Kim uint8_t query_opcode, uint8_t idn, 2135cb3566aSJeuk Kim uint8_t index, uint8_t selector, 2145cb3566aSJeuk Kim uint32_t attr_value, UtpUpiuRsp *rsp_out) 2155cb3566aSJeuk Kim { 2165cb3566aSJeuk Kim int cmd_desc_slot = alloc_cmd_desc_slot(ufs); 2175cb3566aSJeuk Kim uint64_t req_upiu_addr = 2185cb3566aSJeuk Kim ufs->cmd_desc_addr + cmd_desc_slot * UTP_COMMAND_DESCRIPTOR_SIZE; 2195cb3566aSJeuk Kim uint64_t rsp_upiu_addr = req_upiu_addr + UTP_RESPONSE_UPIU_OFFSET; 220631c8726SJeuk Kim 221631c8726SJeuk Kim /* Build up request upiu */ 222631c8726SJeuk Kim UtpUpiuReq req_upiu = { 0 }; 223631c8726SJeuk Kim req_upiu.header.trans_type = UFS_UPIU_TRANSACTION_QUERY_REQ; 224631c8726SJeuk Kim req_upiu.header.query_func = query_function; 2255cb3566aSJeuk Kim req_upiu.header.task_tag = cmd_desc_slot; 226631c8726SJeuk Kim /* 2277c85332aSYoochan Jeong * QEMU UFS does not currently support Write descriptor, 228631c8726SJeuk Kim * so the value of data_segment_length is always 0. 229631c8726SJeuk Kim */ 230631c8726SJeuk Kim req_upiu.header.data_segment_length = 0; 231631c8726SJeuk Kim req_upiu.qr.opcode = query_opcode; 232631c8726SJeuk Kim req_upiu.qr.idn = idn; 233631c8726SJeuk Kim req_upiu.qr.index = index; 2347c85332aSYoochan Jeong req_upiu.qr.selector = selector; 2354572daccSKeoseong Park req_upiu.qr.value = cpu_to_be32(attr_value); 2367c85332aSYoochan Jeong req_upiu.qr.length = UFS_QUERY_DESC_MAX_SIZE; 237631c8726SJeuk Kim qtest_memwrite(ufs->dev.bus->qts, req_upiu_addr, &req_upiu, 238631c8726SJeuk Kim sizeof(req_upiu)); 239631c8726SJeuk Kim 2405cb3566aSJeuk Kim /* Build up utp transfer request descriptor */ 2415cb3566aSJeuk Kim UtpTransferReqDesc utrd = 2425cb3566aSJeuk Kim ufs_build_req_utrd(req_upiu_addr, UFS_UTP_NO_DATA_TRANSFER, 0); 243631c8726SJeuk Kim 2445cb3566aSJeuk Kim /* Send Transfer Request */ 2455cb3566aSJeuk Kim enum UtpOcsCodes ret = ufs_send_transfer_request_sync(ufs, 0, &utrd); 2465cb3566aSJeuk Kim 247631c8726SJeuk Kim qtest_memread(ufs->dev.bus->qts, rsp_upiu_addr, rsp_out, sizeof(*rsp_out)); 2485cb3566aSJeuk Kim release_cmd_desc_slot(ufs, cmd_desc_slot); 2495cb3566aSJeuk Kim return ret; 250631c8726SJeuk Kim } 251631c8726SJeuk Kim 2525cb3566aSJeuk Kim static enum UtpOcsCodes 2535cb3566aSJeuk Kim ufs_send_scsi_command(QUfs *ufs, uint8_t lun, const uint8_t *cdb, 2545cb3566aSJeuk Kim const uint8_t *data_in, size_t data_in_len, 2555cb3566aSJeuk Kim uint8_t *data_out, size_t data_out_len, 256631c8726SJeuk Kim UtpUpiuRsp *rsp_out) 257631c8726SJeuk Kim 258631c8726SJeuk Kim { 259631c8726SJeuk Kim /* Build up PRDT */ 260631c8726SJeuk Kim UfshcdSgEntry entries[MAX_PRD_ENTRY_COUNT] = { 261631c8726SJeuk Kim 0, 262631c8726SJeuk Kim }; 263631c8726SJeuk Kim uint8_t flags; 264631c8726SJeuk Kim uint16_t prd_table_length, i; 265631c8726SJeuk Kim uint32_t data_direction, data_len; 2665cb3566aSJeuk Kim int cmd_desc_slot = alloc_cmd_desc_slot(ufs); 267631c8726SJeuk Kim uint64_t req_upiu_addr = 2685cb3566aSJeuk Kim ufs->cmd_desc_addr + cmd_desc_slot * UTP_COMMAND_DESCRIPTOR_SIZE; 269631c8726SJeuk Kim uint64_t prdt_addr = req_upiu_addr + UTP_PRDT_UPIU_OFFSET; 270631c8726SJeuk Kim 271631c8726SJeuk Kim g_assert_true(data_in_len < MAX_PRD_ENTRY_COUNT * PRD_ENTRY_DATA_SIZE); 272631c8726SJeuk Kim g_assert_true(data_out_len < MAX_PRD_ENTRY_COUNT * PRD_ENTRY_DATA_SIZE); 273631c8726SJeuk Kim if (data_in_len > 0) { 274631c8726SJeuk Kim g_assert_nonnull(data_in); 275631c8726SJeuk Kim data_direction = UFS_UTP_HOST_TO_DEVICE; 276631c8726SJeuk Kim data_len = data_in_len; 277631c8726SJeuk Kim flags = UFS_UPIU_CMD_FLAGS_WRITE; 278631c8726SJeuk Kim } else if (data_out_len > 0) { 279631c8726SJeuk Kim g_assert_nonnull(data_out); 280631c8726SJeuk Kim data_direction = UFS_UTP_DEVICE_TO_HOST; 281631c8726SJeuk Kim data_len = data_out_len; 282631c8726SJeuk Kim flags = UFS_UPIU_CMD_FLAGS_READ; 283631c8726SJeuk Kim } else { 284631c8726SJeuk Kim data_direction = UFS_UTP_NO_DATA_TRANSFER; 285631c8726SJeuk Kim data_len = 0; 286631c8726SJeuk Kim flags = UFS_UPIU_CMD_FLAGS_NONE; 287631c8726SJeuk Kim } 288631c8726SJeuk Kim prd_table_length = DIV_ROUND_UP(data_len, PRD_ENTRY_DATA_SIZE); 289631c8726SJeuk Kim 290631c8726SJeuk Kim qtest_memset(ufs->dev.bus->qts, ufs->data_buffer_addr, 0, 291631c8726SJeuk Kim MAX_PRD_ENTRY_COUNT * PRD_ENTRY_DATA_SIZE); 292631c8726SJeuk Kim if (data_in_len) { 293631c8726SJeuk Kim qtest_memwrite(ufs->dev.bus->qts, ufs->data_buffer_addr, data_in, 294631c8726SJeuk Kim data_in_len); 295631c8726SJeuk Kim } 296631c8726SJeuk Kim 297631c8726SJeuk Kim for (i = 0; i < prd_table_length; i++) { 298631c8726SJeuk Kim entries[i].addr = 299631c8726SJeuk Kim cpu_to_le64(ufs->data_buffer_addr + i * sizeof(UfshcdSgEntry)); 300631c8726SJeuk Kim if (i + 1 != prd_table_length) { 301631c8726SJeuk Kim entries[i].size = cpu_to_le32(PRD_ENTRY_DATA_SIZE - 1); 302631c8726SJeuk Kim } else { 303631c8726SJeuk Kim entries[i].size = cpu_to_le32( 304631c8726SJeuk Kim data_len - (PRD_ENTRY_DATA_SIZE * (prd_table_length - 1)) - 1); 305631c8726SJeuk Kim } 306631c8726SJeuk Kim } 307631c8726SJeuk Kim qtest_memwrite(ufs->dev.bus->qts, prdt_addr, entries, 308631c8726SJeuk Kim prd_table_length * sizeof(UfshcdSgEntry)); 309631c8726SJeuk Kim 310631c8726SJeuk Kim uint64_t rsp_upiu_addr = req_upiu_addr + UTP_RESPONSE_UPIU_OFFSET; 311631c8726SJeuk Kim 312631c8726SJeuk Kim /* Build up request upiu */ 313631c8726SJeuk Kim UtpUpiuReq req_upiu = { 0 }; 314631c8726SJeuk Kim req_upiu.header.trans_type = UFS_UPIU_TRANSACTION_COMMAND; 315631c8726SJeuk Kim req_upiu.header.flags = flags; 316631c8726SJeuk Kim req_upiu.header.lun = lun; 3175cb3566aSJeuk Kim req_upiu.header.task_tag = cmd_desc_slot; 318631c8726SJeuk Kim req_upiu.sc.exp_data_transfer_len = cpu_to_be32(data_len); 319631c8726SJeuk Kim memcpy(req_upiu.sc.cdb, cdb, UFS_CDB_SIZE); 320631c8726SJeuk Kim qtest_memwrite(ufs->dev.bus->qts, req_upiu_addr, &req_upiu, 321631c8726SJeuk Kim sizeof(req_upiu)); 322631c8726SJeuk Kim 3235cb3566aSJeuk Kim /* Build up utp transfer request descriptor */ 3245cb3566aSJeuk Kim UtpTransferReqDesc utrd = 3255cb3566aSJeuk Kim ufs_build_req_utrd(req_upiu_addr, data_direction, prd_table_length); 326631c8726SJeuk Kim 3275cb3566aSJeuk Kim /* Send Transfer Request */ 3285cb3566aSJeuk Kim enum UtpOcsCodes ret = ufs_send_transfer_request_sync(ufs, lun, &utrd); 3295cb3566aSJeuk Kim 330631c8726SJeuk Kim qtest_memread(ufs->dev.bus->qts, rsp_upiu_addr, rsp_out, sizeof(*rsp_out)); 331631c8726SJeuk Kim if (data_out_len) { 332631c8726SJeuk Kim qtest_memread(ufs->dev.bus->qts, ufs->data_buffer_addr, data_out, 333631c8726SJeuk Kim data_out_len); 334631c8726SJeuk Kim } 3355cb3566aSJeuk Kim release_cmd_desc_slot(ufs, cmd_desc_slot); 3365cb3566aSJeuk Kim return ret; 337631c8726SJeuk Kim } 338631c8726SJeuk Kim 339631c8726SJeuk Kim /** 340631c8726SJeuk Kim * Initialize Ufs host controller and logical unit. 341631c8726SJeuk Kim * After running this function, you can make a transfer request to the UFS. 342631c8726SJeuk Kim */ 343631c8726SJeuk Kim static void ufs_init(QUfs *ufs, QGuestAllocator *alloc) 344631c8726SJeuk Kim { 345631c8726SJeuk Kim uint64_t end_time; 346e041d3d2SJeuk Kim uint32_t nutrs; 347631c8726SJeuk Kim uint32_t hcs, is, ucmdarg2, cap; 348631c8726SJeuk Kim uint32_t hce = 0, ie = 0; 3495cb3566aSJeuk Kim enum UtpOcsCodes ocs; 350631c8726SJeuk Kim UtpUpiuRsp rsp_upiu; 351631c8726SJeuk Kim 352631c8726SJeuk Kim ufs->bar = qpci_iomap(&ufs->dev, 0, NULL); 353631c8726SJeuk Kim qpci_device_enable(&ufs->dev); 354631c8726SJeuk Kim 355631c8726SJeuk Kim /* Start host controller initialization */ 356631c8726SJeuk Kim hce = FIELD_DP32(hce, HCE, HCE, 1); 357631c8726SJeuk Kim ufs_wreg(ufs, A_HCE, hce); 358631c8726SJeuk Kim 359631c8726SJeuk Kim /* Wait for device to reset */ 360631c8726SJeuk Kim end_time = g_get_monotonic_time() + TIMEOUT_SECONDS * G_TIME_SPAN_SECOND; 361631c8726SJeuk Kim do { 362631c8726SJeuk Kim qtest_clock_step(ufs->dev.bus->qts, 100); 363631c8726SJeuk Kim hce = FIELD_EX32(ufs_rreg(ufs, A_HCE), HCE, HCE); 364631c8726SJeuk Kim } while (hce == 0 && g_get_monotonic_time() < end_time); 365631c8726SJeuk Kim g_assert_cmpuint(hce, ==, 1); 366631c8726SJeuk Kim 367631c8726SJeuk Kim /* Enable interrupt */ 368631c8726SJeuk Kim ie = FIELD_DP32(ie, IE, UCCE, 1); 369631c8726SJeuk Kim ie = FIELD_DP32(ie, IE, UHESE, 1); 370631c8726SJeuk Kim ie = FIELD_DP32(ie, IE, UHXSE, 1); 371631c8726SJeuk Kim ie = FIELD_DP32(ie, IE, UPMSE, 1); 372631c8726SJeuk Kim ufs_wreg(ufs, A_IE, ie); 373631c8726SJeuk Kim 374631c8726SJeuk Kim /* Send DME_LINK_STARTUP uic command */ 375631c8726SJeuk Kim hcs = ufs_rreg(ufs, A_HCS); 376631c8726SJeuk Kim g_assert_true(FIELD_EX32(hcs, HCS, UCRDY)); 377631c8726SJeuk Kim 378631c8726SJeuk Kim ufs_wreg(ufs, A_UCMDARG1, 0); 379631c8726SJeuk Kim ufs_wreg(ufs, A_UCMDARG2, 0); 380631c8726SJeuk Kim ufs_wreg(ufs, A_UCMDARG3, 0); 381631c8726SJeuk Kim ufs_wreg(ufs, A_UICCMD, UFS_UIC_CMD_DME_LINK_STARTUP); 382631c8726SJeuk Kim 383631c8726SJeuk Kim is = ufs_rreg(ufs, A_IS); 384631c8726SJeuk Kim g_assert_true(FIELD_EX32(is, IS, UCCS)); 385631c8726SJeuk Kim ufs_wreg(ufs, A_IS, FIELD_DP32(0, IS, UCCS, 1)); 386631c8726SJeuk Kim 387631c8726SJeuk Kim ucmdarg2 = ufs_rreg(ufs, A_UCMDARG2); 388631c8726SJeuk Kim g_assert_cmpuint(ucmdarg2, ==, 0); 389631c8726SJeuk Kim is = ufs_rreg(ufs, A_IS); 390631c8726SJeuk Kim g_assert_cmpuint(is, ==, 0); 391631c8726SJeuk Kim hcs = ufs_rreg(ufs, A_HCS); 392631c8726SJeuk Kim g_assert_true(FIELD_EX32(hcs, HCS, DP)); 393631c8726SJeuk Kim g_assert_true(FIELD_EX32(hcs, HCS, UTRLRDY)); 394631c8726SJeuk Kim g_assert_true(FIELD_EX32(hcs, HCS, UCRDY)); 395631c8726SJeuk Kim 396*a54596a9SJeuk Kim /* Check MCQ support */ 397*a54596a9SJeuk Kim cap = ufs_rreg(ufs, A_CAP); 398*a54596a9SJeuk Kim ufs->support_mcq = FIELD_EX32(cap, CAP, MCQS); 399*a54596a9SJeuk Kim 400631c8726SJeuk Kim /* Enable all interrupt functions */ 401631c8726SJeuk Kim ie = FIELD_DP32(ie, IE, UTRCE, 1); 402631c8726SJeuk Kim ie = FIELD_DP32(ie, IE, UEE, 1); 403631c8726SJeuk Kim ie = FIELD_DP32(ie, IE, UPMSE, 1); 404631c8726SJeuk Kim ie = FIELD_DP32(ie, IE, UHXSE, 1); 405631c8726SJeuk Kim ie = FIELD_DP32(ie, IE, UHESE, 1); 406631c8726SJeuk Kim ie = FIELD_DP32(ie, IE, UTMRCE, 1); 407631c8726SJeuk Kim ie = FIELD_DP32(ie, IE, UCCE, 1); 408631c8726SJeuk Kim ie = FIELD_DP32(ie, IE, DFEE, 1); 409631c8726SJeuk Kim ie = FIELD_DP32(ie, IE, HCFEE, 1); 410631c8726SJeuk Kim ie = FIELD_DP32(ie, IE, SBFEE, 1); 411631c8726SJeuk Kim ie = FIELD_DP32(ie, IE, CEFEE, 1); 412*a54596a9SJeuk Kim if (ufs->support_mcq) { 413*a54596a9SJeuk Kim ie = FIELD_DP32(ie, IE, CQEE, 1); 414*a54596a9SJeuk Kim } 415631c8726SJeuk Kim ufs_wreg(ufs, A_IE, ie); 416631c8726SJeuk Kim ufs_wreg(ufs, A_UTRIACR, 0); 417631c8726SJeuk Kim 4185cb3566aSJeuk Kim /* Enable transfer request */ 419631c8726SJeuk Kim ufs->cmd_desc_addr = 4205cb3566aSJeuk Kim guest_alloc(alloc, UFS_MAX_CMD_DESC * UTP_COMMAND_DESCRIPTOR_SIZE); 421631c8726SJeuk Kim ufs->data_buffer_addr = 422631c8726SJeuk Kim guest_alloc(alloc, MAX_PRD_ENTRY_COUNT * PRD_ENTRY_DATA_SIZE); 423*a54596a9SJeuk Kim 424*a54596a9SJeuk Kim if (ufs->support_mcq) { 425*a54596a9SJeuk Kim uint32_t mcqcap, qid, qcfgptr, mcq_reg_offset; 426*a54596a9SJeuk Kim uint32_t cqattr = 0, sqattr = 0; 427*a54596a9SJeuk Kim 428*a54596a9SJeuk Kim mcqcap = ufs_rreg(ufs, A_MCQCAP); 429*a54596a9SJeuk Kim qcfgptr = FIELD_EX32(mcqcap, MCQCAP, QCFGPTR); 430*a54596a9SJeuk Kim ufs->maxq = FIELD_EX32(mcqcap, MCQCAP, MAXQ) + 1; 431*a54596a9SJeuk Kim for (qid = 0; qid < ufs->maxq; ++qid) { 432*a54596a9SJeuk Kim ufs->sqlba[qid] = 433*a54596a9SJeuk Kim guest_alloc(alloc, QUEUE_SIZE * sizeof(UtpTransferReqDesc)); 434*a54596a9SJeuk Kim ufs->cqlba[qid] = 435*a54596a9SJeuk Kim guest_alloc(alloc, QUEUE_SIZE * sizeof(UtpTransferReqDesc)); 436*a54596a9SJeuk Kim mcq_reg_offset = qcfgptr * 0x200 + qid * 0x40; 437*a54596a9SJeuk Kim 438*a54596a9SJeuk Kim ufs_wreg(ufs, mcq_reg_offset + A_SQLBA, 439*a54596a9SJeuk Kim ufs->sqlba[qid] & 0xffffffff); 440*a54596a9SJeuk Kim ufs_wreg(ufs, mcq_reg_offset + A_SQUBA, ufs->sqlba[qid] >> 32); 441*a54596a9SJeuk Kim ufs_wreg(ufs, mcq_reg_offset + A_CQLBA, 442*a54596a9SJeuk Kim ufs->cqlba[qid] & 0xffffffff); 443*a54596a9SJeuk Kim ufs_wreg(ufs, mcq_reg_offset + A_CQUBA, ufs->cqlba[qid] >> 32); 444*a54596a9SJeuk Kim 445*a54596a9SJeuk Kim /* Enable Completion Queue */ 446*a54596a9SJeuk Kim cqattr = FIELD_DP32(cqattr, CQATTR, CQEN, 1); 447*a54596a9SJeuk Kim cqattr = FIELD_DP32(cqattr, CQATTR, SIZE, 448*a54596a9SJeuk Kim QUEUE_SIZE * sizeof(UtpTransferReqDesc) / 449*a54596a9SJeuk Kim DWORD_BYTE); 450*a54596a9SJeuk Kim ufs_wreg(ufs, mcq_reg_offset + A_CQATTR, cqattr); 451*a54596a9SJeuk Kim 452*a54596a9SJeuk Kim /* Enable Submission Queue */ 453*a54596a9SJeuk Kim sqattr = FIELD_DP32(sqattr, SQATTR, SQEN, 1); 454*a54596a9SJeuk Kim sqattr = FIELD_DP32(sqattr, SQATTR, SIZE, 455*a54596a9SJeuk Kim QUEUE_SIZE * sizeof(UtpTransferReqDesc) / 456*a54596a9SJeuk Kim DWORD_BYTE); 457*a54596a9SJeuk Kim sqattr = FIELD_DP32(sqattr, SQATTR, CQID, qid); 458*a54596a9SJeuk Kim ufs_wreg(ufs, mcq_reg_offset + A_SQATTR, sqattr); 459*a54596a9SJeuk Kim 460*a54596a9SJeuk Kim /* Cache head & tail pointer */ 461*a54596a9SJeuk Kim ufs->sqdao[qid] = ufs_rreg(ufs, mcq_reg_offset + A_SQDAO); 462*a54596a9SJeuk Kim ufs->cqdao[qid] = ufs_rreg(ufs, mcq_reg_offset + A_CQDAO); 463*a54596a9SJeuk Kim } 464*a54596a9SJeuk Kim } else { 465*a54596a9SJeuk Kim nutrs = FIELD_EX32(cap, CAP, NUTRS) + 1; 466631c8726SJeuk Kim ufs->utrlba = guest_alloc(alloc, nutrs * sizeof(UtpTransferReqDesc)); 467631c8726SJeuk Kim 468631c8726SJeuk Kim ufs_wreg(ufs, A_UTRLBA, ufs->utrlba & 0xffffffff); 469631c8726SJeuk Kim ufs_wreg(ufs, A_UTRLBAU, ufs->utrlba >> 32); 470631c8726SJeuk Kim ufs_wreg(ufs, A_UTRLRSR, 1); 471*a54596a9SJeuk Kim } 472631c8726SJeuk Kim 473631c8726SJeuk Kim /* Send nop out to test transfer request */ 4745cb3566aSJeuk Kim ocs = ufs_send_nop_out(ufs, &rsp_upiu); 4755cb3566aSJeuk Kim g_assert_cmpuint(ocs, ==, UFS_OCS_SUCCESS); 476631c8726SJeuk Kim 477631c8726SJeuk Kim /* Set fDeviceInit flag via query request */ 4785cb3566aSJeuk Kim ocs = ufs_send_query(ufs, UFS_UPIU_QUERY_FUNC_STANDARD_WRITE_REQUEST, 479631c8726SJeuk Kim UFS_UPIU_QUERY_OPCODE_SET_FLAG, 4805cb3566aSJeuk Kim UFS_QUERY_FLAG_IDN_FDEVICEINIT, 0, 0, 0, &rsp_upiu); 4815cb3566aSJeuk Kim g_assert_cmpuint(ocs, ==, UFS_OCS_SUCCESS); 4825cb3566aSJeuk Kim g_assert_cmpuint(rsp_upiu.header.response, ==, UFS_COMMAND_RESULT_SUCCESS); 483631c8726SJeuk Kim 484631c8726SJeuk Kim /* Wait for device to reset */ 485631c8726SJeuk Kim end_time = g_get_monotonic_time() + TIMEOUT_SECONDS * G_TIME_SPAN_SECOND; 486631c8726SJeuk Kim do { 487631c8726SJeuk Kim qtest_clock_step(ufs->dev.bus->qts, 100); 4885cb3566aSJeuk Kim ocs = 4895cb3566aSJeuk Kim ufs_send_query(ufs, UFS_UPIU_QUERY_FUNC_STANDARD_READ_REQUEST, 490631c8726SJeuk Kim UFS_UPIU_QUERY_OPCODE_READ_FLAG, 4915cb3566aSJeuk Kim UFS_QUERY_FLAG_IDN_FDEVICEINIT, 0, 0, 0, &rsp_upiu); 4925cb3566aSJeuk Kim g_assert_cmpuint(ocs, ==, UFS_OCS_SUCCESS); 4935cb3566aSJeuk Kim g_assert_cmpuint(rsp_upiu.header.response, ==, 4945cb3566aSJeuk Kim UFS_COMMAND_RESULT_SUCCESS); 495631c8726SJeuk Kim } while (be32_to_cpu(rsp_upiu.qr.value) != 0 && 496631c8726SJeuk Kim g_get_monotonic_time() < end_time); 497631c8726SJeuk Kim g_assert_cmpuint(be32_to_cpu(rsp_upiu.qr.value), ==, 0); 498631c8726SJeuk Kim 499631c8726SJeuk Kim ufs->enabled = true; 500631c8726SJeuk Kim } 501631c8726SJeuk Kim 502631c8726SJeuk Kim static void ufs_exit(QUfs *ufs, QGuestAllocator *alloc) 503631c8726SJeuk Kim { 504631c8726SJeuk Kim if (ufs->enabled) { 505*a54596a9SJeuk Kim if (ufs->support_mcq) { 506*a54596a9SJeuk Kim for (uint32_t qid = 0; qid < ufs->maxq; ++qid) { 507*a54596a9SJeuk Kim guest_free(alloc, ufs->sqlba[qid]); 508*a54596a9SJeuk Kim guest_free(alloc, ufs->cqlba[qid]); 509*a54596a9SJeuk Kim } 510*a54596a9SJeuk Kim } else { 511631c8726SJeuk Kim guest_free(alloc, ufs->utrlba); 512*a54596a9SJeuk Kim } 513*a54596a9SJeuk Kim 514631c8726SJeuk Kim guest_free(alloc, ufs->cmd_desc_addr); 515631c8726SJeuk Kim guest_free(alloc, ufs->data_buffer_addr); 516631c8726SJeuk Kim } 517631c8726SJeuk Kim 518631c8726SJeuk Kim qpci_iounmap(&ufs->dev, ufs->bar); 519631c8726SJeuk Kim } 520631c8726SJeuk Kim 521631c8726SJeuk Kim static void *ufs_get_driver(void *obj, const char *interface) 522631c8726SJeuk Kim { 523631c8726SJeuk Kim QUfs *ufs = obj; 524631c8726SJeuk Kim 525631c8726SJeuk Kim if (!g_strcmp0(interface, "pci-device")) { 526631c8726SJeuk Kim return &ufs->dev; 527631c8726SJeuk Kim } 528631c8726SJeuk Kim 529631c8726SJeuk Kim fprintf(stderr, "%s not present in ufs\n", interface); 530631c8726SJeuk Kim g_assert_not_reached(); 531631c8726SJeuk Kim } 532631c8726SJeuk Kim 533631c8726SJeuk Kim static void *ufs_create(void *pci_bus, QGuestAllocator *alloc, void *addr) 534631c8726SJeuk Kim { 535631c8726SJeuk Kim QUfs *ufs = g_new0(QUfs, 1); 536631c8726SJeuk Kim QPCIBus *bus = pci_bus; 537631c8726SJeuk Kim 538631c8726SJeuk Kim qpci_device_init(&ufs->dev, bus, addr); 539631c8726SJeuk Kim ufs->obj.get_driver = ufs_get_driver; 540631c8726SJeuk Kim 541631c8726SJeuk Kim return &ufs->obj; 542631c8726SJeuk Kim } 543631c8726SJeuk Kim 544631c8726SJeuk Kim static void ufstest_reg_read(void *obj, void *data, QGuestAllocator *alloc) 545631c8726SJeuk Kim { 546631c8726SJeuk Kim QUfs *ufs = obj; 547631c8726SJeuk Kim uint32_t cap; 548631c8726SJeuk Kim 549631c8726SJeuk Kim ufs->bar = qpci_iomap(&ufs->dev, 0, NULL); 550631c8726SJeuk Kim qpci_device_enable(&ufs->dev); 551631c8726SJeuk Kim 552631c8726SJeuk Kim cap = ufs_rreg(ufs, A_CAP); 553631c8726SJeuk Kim g_assert_cmpuint(FIELD_EX32(cap, CAP, NUTRS), ==, 31); 554631c8726SJeuk Kim g_assert_cmpuint(FIELD_EX32(cap, CAP, NUTMRS), ==, 7); 555631c8726SJeuk Kim g_assert_cmpuint(FIELD_EX32(cap, CAP, 64AS), ==, 1); 556631c8726SJeuk Kim 557631c8726SJeuk Kim qpci_iounmap(&ufs->dev, ufs->bar); 558631c8726SJeuk Kim } 559631c8726SJeuk Kim 560631c8726SJeuk Kim static void ufstest_init(void *obj, void *data, QGuestAllocator *alloc) 561631c8726SJeuk Kim { 562631c8726SJeuk Kim QUfs *ufs = obj; 563631c8726SJeuk Kim 564631c8726SJeuk Kim uint8_t buf[4096] = { 0 }; 565631c8726SJeuk Kim const uint8_t report_luns_cdb[UFS_CDB_SIZE] = { 566631c8726SJeuk Kim /* allocation length 4096 */ 567631c8726SJeuk Kim REPORT_LUNS, 0x00, 0x00, 0x00, 0x00, 0x00, 568631c8726SJeuk Kim 0x00, 0x00, 0x10, 0x00, 0x00, 0x00 569631c8726SJeuk Kim }; 570631c8726SJeuk Kim const uint8_t test_unit_ready_cdb[UFS_CDB_SIZE] = { 571631c8726SJeuk Kim TEST_UNIT_READY, 572631c8726SJeuk Kim }; 573096434feSJeuk Kim const uint8_t request_sense_cdb[UFS_CDB_SIZE] = { 574096434feSJeuk Kim REQUEST_SENSE, 575096434feSJeuk Kim }; 5765cb3566aSJeuk Kim enum UtpOcsCodes ocs; 577631c8726SJeuk Kim UtpUpiuRsp rsp_upiu; 578631c8726SJeuk Kim 579631c8726SJeuk Kim ufs_init(ufs, alloc); 580631c8726SJeuk Kim 581631c8726SJeuk Kim /* Check REPORT_LUNS */ 5825cb3566aSJeuk Kim ocs = ufs_send_scsi_command(ufs, 0, report_luns_cdb, NULL, 0, buf, 5835cb3566aSJeuk Kim sizeof(buf), &rsp_upiu); 5845cb3566aSJeuk Kim g_assert_cmpuint(ocs, ==, UFS_OCS_SUCCESS); 585631c8726SJeuk Kim g_assert_cmpuint(rsp_upiu.header.scsi_status, ==, GOOD); 586631c8726SJeuk Kim /* LUN LIST LENGTH should be 8, in big endian */ 587631c8726SJeuk Kim g_assert_cmpuint(buf[3], ==, 8); 588631c8726SJeuk Kim /* There is one logical unit whose lun is 0 */ 589631c8726SJeuk Kim g_assert_cmpuint(buf[9], ==, 0); 590631c8726SJeuk Kim 591096434feSJeuk Kim /* Clear Unit Attention */ 5925cb3566aSJeuk Kim ocs = ufs_send_scsi_command(ufs, 0, request_sense_cdb, NULL, 0, buf, 5935cb3566aSJeuk Kim sizeof(buf), &rsp_upiu); 5945cb3566aSJeuk Kim g_assert_cmpuint(ocs, ==, UFS_OCS_SUCCESS); 595096434feSJeuk Kim g_assert_cmpuint(rsp_upiu.header.scsi_status, ==, CHECK_CONDITION); 596096434feSJeuk Kim 597631c8726SJeuk Kim /* Check TEST_UNIT_READY */ 5985cb3566aSJeuk Kim ocs = ufs_send_scsi_command(ufs, 0, test_unit_ready_cdb, NULL, 0, NULL, 0, 5995cb3566aSJeuk Kim &rsp_upiu); 6005cb3566aSJeuk Kim g_assert_cmpuint(ocs, ==, UFS_OCS_SUCCESS); 601631c8726SJeuk Kim g_assert_cmpuint(rsp_upiu.header.scsi_status, ==, GOOD); 602631c8726SJeuk Kim 603631c8726SJeuk Kim ufs_exit(ufs, alloc); 604631c8726SJeuk Kim } 605631c8726SJeuk Kim 606631c8726SJeuk Kim static void ufstest_read_write(void *obj, void *data, QGuestAllocator *alloc) 607631c8726SJeuk Kim { 608631c8726SJeuk Kim QUfs *ufs = obj; 609631c8726SJeuk Kim uint8_t read_buf[4096] = { 0 }; 610631c8726SJeuk Kim uint8_t write_buf[4096] = { 0 }; 611631c8726SJeuk Kim const uint8_t read_capacity_cdb[UFS_CDB_SIZE] = { 612631c8726SJeuk Kim /* allocation length 4096 */ 613631c8726SJeuk Kim SERVICE_ACTION_IN_16, 614631c8726SJeuk Kim SAI_READ_CAPACITY_16, 615631c8726SJeuk Kim 0x00, 616631c8726SJeuk Kim 0x00, 617631c8726SJeuk Kim 0x00, 618631c8726SJeuk Kim 0x00, 619631c8726SJeuk Kim 0x00, 620631c8726SJeuk Kim 0x00, 621631c8726SJeuk Kim 0x00, 622631c8726SJeuk Kim 0x00, 623631c8726SJeuk Kim 0x00, 624631c8726SJeuk Kim 0x00, 625631c8726SJeuk Kim 0x10, 626631c8726SJeuk Kim 0x00, 627631c8726SJeuk Kim 0x00, 628631c8726SJeuk Kim 0x00 629631c8726SJeuk Kim }; 630096434feSJeuk Kim const uint8_t request_sense_cdb[UFS_CDB_SIZE] = { 631096434feSJeuk Kim REQUEST_SENSE, 632096434feSJeuk Kim }; 633631c8726SJeuk Kim const uint8_t read_cdb[UFS_CDB_SIZE] = { 634631c8726SJeuk Kim /* READ(10) to LBA 0, transfer length 1 */ 635631c8726SJeuk Kim READ_10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00 636631c8726SJeuk Kim }; 637631c8726SJeuk Kim const uint8_t write_cdb[UFS_CDB_SIZE] = { 638631c8726SJeuk Kim /* WRITE(10) to LBA 0, transfer length 1 */ 639631c8726SJeuk Kim WRITE_10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00 640631c8726SJeuk Kim }; 641631c8726SJeuk Kim uint32_t block_size; 6425cb3566aSJeuk Kim enum UtpOcsCodes ocs; 643631c8726SJeuk Kim UtpUpiuRsp rsp_upiu; 644096434feSJeuk Kim const int test_lun = 1; 645631c8726SJeuk Kim 646631c8726SJeuk Kim ufs_init(ufs, alloc); 647631c8726SJeuk Kim 648096434feSJeuk Kim /* Clear Unit Attention */ 6495cb3566aSJeuk Kim ocs = ufs_send_scsi_command(ufs, test_lun, request_sense_cdb, NULL, 0, 6505cb3566aSJeuk Kim read_buf, sizeof(read_buf), &rsp_upiu); 6515cb3566aSJeuk Kim g_assert_cmpuint(ocs, ==, UFS_OCS_SUCCESS); 652096434feSJeuk Kim g_assert_cmpuint(rsp_upiu.header.scsi_status, ==, CHECK_CONDITION); 653096434feSJeuk Kim 654631c8726SJeuk Kim /* Read capacity */ 6555cb3566aSJeuk Kim ocs = ufs_send_scsi_command(ufs, test_lun, read_capacity_cdb, NULL, 0, 6565cb3566aSJeuk Kim read_buf, sizeof(read_buf), &rsp_upiu); 6575cb3566aSJeuk Kim g_assert_cmpuint(ocs, ==, UFS_OCS_SUCCESS); 658631c8726SJeuk Kim g_assert_cmpuint(rsp_upiu.header.scsi_status, ==, 659096434feSJeuk Kim UFS_COMMAND_RESULT_SUCCESS); 660631c8726SJeuk Kim block_size = ldl_be_p(&read_buf[8]); 661631c8726SJeuk Kim g_assert_cmpuint(block_size, ==, 4096); 662631c8726SJeuk Kim 663631c8726SJeuk Kim /* Write data */ 66497970daeSJeuk Kim memset(write_buf, 0xab, block_size); 6655cb3566aSJeuk Kim ocs = ufs_send_scsi_command(ufs, test_lun, write_cdb, write_buf, block_size, 6665cb3566aSJeuk Kim NULL, 0, &rsp_upiu); 6675cb3566aSJeuk Kim g_assert_cmpuint(ocs, ==, UFS_OCS_SUCCESS); 668631c8726SJeuk Kim g_assert_cmpuint(rsp_upiu.header.scsi_status, ==, 669096434feSJeuk Kim UFS_COMMAND_RESULT_SUCCESS); 670631c8726SJeuk Kim 671631c8726SJeuk Kim /* Read data and verify */ 6725cb3566aSJeuk Kim ocs = ufs_send_scsi_command(ufs, test_lun, read_cdb, NULL, 0, read_buf, 6735cb3566aSJeuk Kim block_size, &rsp_upiu); 6745cb3566aSJeuk Kim g_assert_cmpuint(ocs, ==, UFS_OCS_SUCCESS); 675631c8726SJeuk Kim g_assert_cmpuint(rsp_upiu.header.scsi_status, ==, 676096434feSJeuk Kim UFS_COMMAND_RESULT_SUCCESS); 677631c8726SJeuk Kim g_assert_cmpint(memcmp(read_buf, write_buf, block_size), ==, 0); 678631c8726SJeuk Kim 679631c8726SJeuk Kim ufs_exit(ufs, alloc); 680631c8726SJeuk Kim } 681631c8726SJeuk Kim 6824aac3029SYoochan Jeong static void ufstest_query_flag_request(void *obj, void *data, 6834aac3029SYoochan Jeong QGuestAllocator *alloc) 6844aac3029SYoochan Jeong { 6854aac3029SYoochan Jeong QUfs *ufs = obj; 6864aac3029SYoochan Jeong 6875cb3566aSJeuk Kim enum UtpOcsCodes ocs; 6884aac3029SYoochan Jeong UtpUpiuRsp rsp_upiu; 6894aac3029SYoochan Jeong ufs_init(ufs, alloc); 6904aac3029SYoochan Jeong 6914aac3029SYoochan Jeong /* Read read-only flag */ 6925cb3566aSJeuk Kim ocs = ufs_send_query(ufs, UFS_UPIU_QUERY_FUNC_STANDARD_READ_REQUEST, 6934aac3029SYoochan Jeong UFS_UPIU_QUERY_OPCODE_READ_FLAG, 6945cb3566aSJeuk Kim UFS_QUERY_FLAG_IDN_FDEVICEINIT, 0, 0, 0, &rsp_upiu); 6955cb3566aSJeuk Kim g_assert_cmpuint(ocs, ==, UFS_OCS_SUCCESS); 6964aac3029SYoochan Jeong g_assert_cmpuint(rsp_upiu.header.response, ==, UFS_COMMAND_RESULT_SUCCESS); 6974aac3029SYoochan Jeong g_assert_cmpuint(rsp_upiu.qr.opcode, ==, UFS_UPIU_QUERY_OPCODE_READ_FLAG); 6984aac3029SYoochan Jeong g_assert_cmpuint(rsp_upiu.qr.idn, ==, UFS_QUERY_FLAG_IDN_FDEVICEINIT); 6994aac3029SYoochan Jeong g_assert_cmpuint(rsp_upiu.qr.value, ==, be32_to_cpu(0)); 7004aac3029SYoochan Jeong 7014aac3029SYoochan Jeong /* Flag Set, Clear, Toggle Test with fDeviceLifeSpanModeEn */ 7025cb3566aSJeuk Kim ocs = ufs_send_query(ufs, UFS_UPIU_QUERY_FUNC_STANDARD_READ_REQUEST, 7034aac3029SYoochan Jeong UFS_UPIU_QUERY_OPCODE_READ_FLAG, 7045cb3566aSJeuk Kim UFS_QUERY_FLAG_IDN_LIFE_SPAN_MODE_ENABLE, 0, 0, 0, 7054aac3029SYoochan Jeong &rsp_upiu); 7065cb3566aSJeuk Kim g_assert_cmpuint(ocs, ==, UFS_OCS_SUCCESS); 7074aac3029SYoochan Jeong g_assert_cmpuint(rsp_upiu.header.response, ==, UFS_COMMAND_RESULT_SUCCESS); 7084aac3029SYoochan Jeong g_assert_cmpuint(rsp_upiu.qr.value, ==, be32_to_cpu(0)); 7094aac3029SYoochan Jeong 7105cb3566aSJeuk Kim ocs = ufs_send_query(ufs, UFS_UPIU_QUERY_FUNC_STANDARD_WRITE_REQUEST, 7114aac3029SYoochan Jeong UFS_UPIU_QUERY_OPCODE_SET_FLAG, 7125cb3566aSJeuk Kim UFS_QUERY_FLAG_IDN_LIFE_SPAN_MODE_ENABLE, 0, 0, 0, 7134aac3029SYoochan Jeong &rsp_upiu); 7145cb3566aSJeuk Kim g_assert_cmpuint(ocs, ==, UFS_OCS_SUCCESS); 7154aac3029SYoochan Jeong g_assert_cmpuint(rsp_upiu.header.response, ==, UFS_COMMAND_RESULT_SUCCESS); 7164aac3029SYoochan Jeong g_assert_cmpuint(rsp_upiu.qr.value, ==, be32_to_cpu(1)); 7174aac3029SYoochan Jeong 7185cb3566aSJeuk Kim ocs = ufs_send_query(ufs, UFS_UPIU_QUERY_FUNC_STANDARD_WRITE_REQUEST, 7194aac3029SYoochan Jeong UFS_UPIU_QUERY_OPCODE_CLEAR_FLAG, 7205cb3566aSJeuk Kim UFS_QUERY_FLAG_IDN_LIFE_SPAN_MODE_ENABLE, 0, 0, 0, 7214aac3029SYoochan Jeong &rsp_upiu); 7225cb3566aSJeuk Kim g_assert_cmpuint(ocs, ==, UFS_OCS_SUCCESS); 7234aac3029SYoochan Jeong g_assert_cmpuint(rsp_upiu.header.response, ==, UFS_COMMAND_RESULT_SUCCESS); 7244aac3029SYoochan Jeong g_assert_cmpuint(rsp_upiu.qr.value, ==, be32_to_cpu(0)); 7254aac3029SYoochan Jeong 7265cb3566aSJeuk Kim ocs = ufs_send_query(ufs, UFS_UPIU_QUERY_FUNC_STANDARD_WRITE_REQUEST, 7274aac3029SYoochan Jeong UFS_UPIU_QUERY_OPCODE_TOGGLE_FLAG, 7285cb3566aSJeuk Kim UFS_QUERY_FLAG_IDN_LIFE_SPAN_MODE_ENABLE, 0, 0, 0, 7294aac3029SYoochan Jeong &rsp_upiu); 7305cb3566aSJeuk Kim g_assert_cmpuint(ocs, ==, UFS_OCS_SUCCESS); 7314aac3029SYoochan Jeong g_assert_cmpuint(rsp_upiu.header.response, ==, UFS_COMMAND_RESULT_SUCCESS); 7324aac3029SYoochan Jeong g_assert_cmpuint(rsp_upiu.qr.value, ==, be32_to_cpu(1)); 7334aac3029SYoochan Jeong 7345cb3566aSJeuk Kim ocs = ufs_send_query(ufs, UFS_UPIU_QUERY_FUNC_STANDARD_WRITE_REQUEST, 7354aac3029SYoochan Jeong UFS_UPIU_QUERY_OPCODE_TOGGLE_FLAG, 7365cb3566aSJeuk Kim UFS_QUERY_FLAG_IDN_LIFE_SPAN_MODE_ENABLE, 0, 0, 0, 7374aac3029SYoochan Jeong &rsp_upiu); 7385cb3566aSJeuk Kim g_assert_cmpuint(ocs, ==, UFS_OCS_SUCCESS); 7394aac3029SYoochan Jeong g_assert_cmpuint(rsp_upiu.header.response, ==, UFS_COMMAND_RESULT_SUCCESS); 7404aac3029SYoochan Jeong g_assert_cmpuint(rsp_upiu.qr.value, ==, be32_to_cpu(0)); 7414aac3029SYoochan Jeong 7424aac3029SYoochan Jeong /* Read Write-only Flag (Intended Failure) */ 7435cb3566aSJeuk Kim ocs = ufs_send_query(ufs, UFS_UPIU_QUERY_FUNC_STANDARD_READ_REQUEST, 7444aac3029SYoochan Jeong UFS_UPIU_QUERY_OPCODE_READ_FLAG, 7455cb3566aSJeuk Kim UFS_QUERY_FLAG_IDN_PURGE_ENABLE, 0, 0, 0, &rsp_upiu); 7465cb3566aSJeuk Kim g_assert_cmpuint(ocs, ==, UFS_OCS_INVALID_CMD_TABLE_ATTR); 7474aac3029SYoochan Jeong g_assert_cmpuint(rsp_upiu.header.response, ==, 7484aac3029SYoochan Jeong UFS_QUERY_RESULT_NOT_READABLE); 7494aac3029SYoochan Jeong 7504aac3029SYoochan Jeong /* Write Read-Only Flag (Intended Failure) */ 7515cb3566aSJeuk Kim ocs = ufs_send_query(ufs, UFS_UPIU_QUERY_FUNC_STANDARD_WRITE_REQUEST, 7525cb3566aSJeuk Kim UFS_UPIU_QUERY_OPCODE_SET_FLAG, 7535cb3566aSJeuk Kim UFS_QUERY_FLAG_IDN_BUSY_RTC, 0, 0, 0, &rsp_upiu); 7545cb3566aSJeuk Kim g_assert_cmpuint(ocs, ==, UFS_OCS_INVALID_CMD_TABLE_ATTR); 7554aac3029SYoochan Jeong g_assert_cmpuint(rsp_upiu.header.response, ==, 7564aac3029SYoochan Jeong UFS_QUERY_RESULT_NOT_WRITEABLE); 7574aac3029SYoochan Jeong 7584aac3029SYoochan Jeong ufs_exit(ufs, alloc); 7594aac3029SYoochan Jeong } 7604aac3029SYoochan Jeong 76149ccea4bSYoochan Jeong static void ufstest_query_attr_request(void *obj, void *data, 76249ccea4bSYoochan Jeong QGuestAllocator *alloc) 76349ccea4bSYoochan Jeong { 76449ccea4bSYoochan Jeong QUfs *ufs = obj; 76549ccea4bSYoochan Jeong 7665cb3566aSJeuk Kim enum UtpOcsCodes ocs; 76749ccea4bSYoochan Jeong UtpUpiuRsp rsp_upiu; 76849ccea4bSYoochan Jeong ufs_init(ufs, alloc); 76949ccea4bSYoochan Jeong 77049ccea4bSYoochan Jeong /* Read Readable Attributes*/ 7715cb3566aSJeuk Kim ocs = ufs_send_query(ufs, UFS_UPIU_QUERY_FUNC_STANDARD_READ_REQUEST, 77249ccea4bSYoochan Jeong UFS_UPIU_QUERY_OPCODE_READ_ATTR, 7735cb3566aSJeuk Kim UFS_QUERY_ATTR_IDN_BOOT_LU_EN, 0, 0, 0, &rsp_upiu); 7745cb3566aSJeuk Kim g_assert_cmpuint(ocs, ==, UFS_OCS_SUCCESS); 77549ccea4bSYoochan Jeong g_assert_cmpuint(rsp_upiu.header.response, ==, UFS_COMMAND_RESULT_SUCCESS); 77649ccea4bSYoochan Jeong g_assert_cmpuint(rsp_upiu.qr.opcode, ==, UFS_UPIU_QUERY_OPCODE_READ_ATTR); 77749ccea4bSYoochan Jeong g_assert_cmpuint(rsp_upiu.qr.idn, ==, UFS_QUERY_ATTR_IDN_BOOT_LU_EN); 77849ccea4bSYoochan Jeong g_assert_cmpuint(rsp_upiu.qr.value, ==, cpu_to_be32(0x00)); 77949ccea4bSYoochan Jeong 7805cb3566aSJeuk Kim ocs = ufs_send_query(ufs, UFS_UPIU_QUERY_FUNC_STANDARD_READ_REQUEST, 78149ccea4bSYoochan Jeong UFS_UPIU_QUERY_OPCODE_READ_ATTR, 7825cb3566aSJeuk Kim UFS_QUERY_ATTR_IDN_BKOPS_STATUS, 0, 0, 0, &rsp_upiu); 7835cb3566aSJeuk Kim g_assert_cmpuint(ocs, ==, UFS_OCS_SUCCESS); 78449ccea4bSYoochan Jeong g_assert_cmpuint(rsp_upiu.header.response, ==, UFS_COMMAND_RESULT_SUCCESS); 78549ccea4bSYoochan Jeong g_assert_cmpuint(rsp_upiu.qr.value, ==, cpu_to_be32(0x00)); 78649ccea4bSYoochan Jeong 78749ccea4bSYoochan Jeong /* Write Writable Attributes & Read Again */ 7885cb3566aSJeuk Kim ocs = ufs_send_query(ufs, UFS_UPIU_QUERY_FUNC_STANDARD_WRITE_REQUEST, 78949ccea4bSYoochan Jeong UFS_UPIU_QUERY_OPCODE_WRITE_ATTR, 7905cb3566aSJeuk Kim UFS_QUERY_ATTR_IDN_ACTIVE_ICC_LVL, 0, 0, 0x03, 79149ccea4bSYoochan Jeong &rsp_upiu); 7925cb3566aSJeuk Kim g_assert_cmpuint(ocs, ==, UFS_OCS_SUCCESS); 79349ccea4bSYoochan Jeong g_assert_cmpuint(rsp_upiu.header.response, ==, UFS_COMMAND_RESULT_SUCCESS); 79449ccea4bSYoochan Jeong g_assert_cmpuint(rsp_upiu.qr.value, ==, cpu_to_be32(0x03)); 79549ccea4bSYoochan Jeong 7965cb3566aSJeuk Kim ocs = ufs_send_query(ufs, UFS_UPIU_QUERY_FUNC_STANDARD_WRITE_REQUEST, 79749ccea4bSYoochan Jeong UFS_UPIU_QUERY_OPCODE_WRITE_ATTR, 7985cb3566aSJeuk Kim UFS_QUERY_ATTR_IDN_EE_CONTROL, 0, 0, 0x07, &rsp_upiu); 7995cb3566aSJeuk Kim g_assert_cmpuint(ocs, ==, UFS_OCS_SUCCESS); 80049ccea4bSYoochan Jeong g_assert_cmpuint(rsp_upiu.header.response, ==, UFS_COMMAND_RESULT_SUCCESS); 80149ccea4bSYoochan Jeong g_assert_cmpuint(rsp_upiu.qr.value, ==, cpu_to_be32(0x07)); 80249ccea4bSYoochan Jeong 8035cb3566aSJeuk Kim ocs = ufs_send_query(ufs, UFS_UPIU_QUERY_FUNC_STANDARD_READ_REQUEST, 80449ccea4bSYoochan Jeong UFS_UPIU_QUERY_OPCODE_READ_ATTR, 8055cb3566aSJeuk Kim UFS_QUERY_ATTR_IDN_ACTIVE_ICC_LVL, 0, 0, 0, &rsp_upiu); 8065cb3566aSJeuk Kim g_assert_cmpuint(ocs, ==, UFS_OCS_SUCCESS); 80749ccea4bSYoochan Jeong g_assert_cmpuint(rsp_upiu.header.response, ==, UFS_COMMAND_RESULT_SUCCESS); 80849ccea4bSYoochan Jeong g_assert_cmpuint(rsp_upiu.qr.value, ==, cpu_to_be32(0x03)); 80949ccea4bSYoochan Jeong 8105cb3566aSJeuk Kim ocs = ufs_send_query(ufs, UFS_UPIU_QUERY_FUNC_STANDARD_READ_REQUEST, 81149ccea4bSYoochan Jeong UFS_UPIU_QUERY_OPCODE_READ_ATTR, 8125cb3566aSJeuk Kim UFS_QUERY_ATTR_IDN_EE_CONTROL, 0, 0, 0, &rsp_upiu); 8135cb3566aSJeuk Kim g_assert_cmpuint(ocs, ==, UFS_OCS_SUCCESS); 81449ccea4bSYoochan Jeong g_assert_cmpuint(rsp_upiu.header.response, ==, UFS_COMMAND_RESULT_SUCCESS); 81549ccea4bSYoochan Jeong g_assert_cmpuint(rsp_upiu.qr.value, ==, cpu_to_be32(0x07)); 81649ccea4bSYoochan Jeong 81749ccea4bSYoochan Jeong /* Write Invalid Value (Intended Error) */ 8185cb3566aSJeuk Kim ocs = ufs_send_query(ufs, UFS_UPIU_QUERY_FUNC_STANDARD_WRITE_REQUEST, 81949ccea4bSYoochan Jeong UFS_UPIU_QUERY_OPCODE_WRITE_ATTR, 8205cb3566aSJeuk Kim UFS_QUERY_ATTR_IDN_ACTIVE_ICC_LVL, 0, 0, 0x10, 82149ccea4bSYoochan Jeong &rsp_upiu); 8225cb3566aSJeuk Kim g_assert_cmpuint(ocs, ==, UFS_OCS_INVALID_CMD_TABLE_ATTR); 82349ccea4bSYoochan Jeong g_assert_cmpuint(rsp_upiu.header.response, ==, 82449ccea4bSYoochan Jeong UFS_QUERY_RESULT_INVALID_VALUE); 82549ccea4bSYoochan Jeong 8265cb3566aSJeuk Kim ocs = ufs_send_query(ufs, UFS_UPIU_QUERY_FUNC_STANDARD_READ_REQUEST, 82749ccea4bSYoochan Jeong UFS_UPIU_QUERY_OPCODE_READ_ATTR, 8285cb3566aSJeuk Kim UFS_QUERY_ATTR_IDN_ACTIVE_ICC_LVL, 0, 0, 0, &rsp_upiu); 8295cb3566aSJeuk Kim g_assert_cmpuint(ocs, ==, UFS_OCS_SUCCESS); 83049ccea4bSYoochan Jeong g_assert_cmpuint(rsp_upiu.header.response, ==, UFS_COMMAND_RESULT_SUCCESS); 83149ccea4bSYoochan Jeong g_assert_cmpuint(rsp_upiu.qr.value, ==, cpu_to_be32(0x03)); 83249ccea4bSYoochan Jeong 83349ccea4bSYoochan Jeong /* Read Write-Only Attribute (Intended Error) */ 8345cb3566aSJeuk Kim ocs = ufs_send_query(ufs, UFS_UPIU_QUERY_FUNC_STANDARD_READ_REQUEST, 83549ccea4bSYoochan Jeong UFS_UPIU_QUERY_OPCODE_READ_ATTR, 8365cb3566aSJeuk Kim UFS_QUERY_ATTR_IDN_SECONDS_PASSED, 0, 0, 0, &rsp_upiu); 8375cb3566aSJeuk Kim g_assert_cmpuint(ocs, ==, UFS_OCS_INVALID_CMD_TABLE_ATTR); 83849ccea4bSYoochan Jeong g_assert_cmpuint(rsp_upiu.header.response, ==, 83949ccea4bSYoochan Jeong UFS_QUERY_RESULT_NOT_READABLE); 84049ccea4bSYoochan Jeong 84149ccea4bSYoochan Jeong /* Write Read-Only Attribute (Intended Error) */ 8425cb3566aSJeuk Kim ocs = ufs_send_query(ufs, UFS_UPIU_QUERY_FUNC_STANDARD_WRITE_REQUEST, 84349ccea4bSYoochan Jeong UFS_UPIU_QUERY_OPCODE_WRITE_ATTR, 8445cb3566aSJeuk Kim UFS_QUERY_ATTR_IDN_POWER_MODE, 0, 0, 0x01, &rsp_upiu); 8455cb3566aSJeuk Kim g_assert_cmpuint(ocs, ==, UFS_OCS_INVALID_CMD_TABLE_ATTR); 84649ccea4bSYoochan Jeong g_assert_cmpuint(rsp_upiu.header.response, ==, 84749ccea4bSYoochan Jeong UFS_QUERY_RESULT_NOT_WRITEABLE); 84849ccea4bSYoochan Jeong 8495cb3566aSJeuk Kim ocs = ufs_send_query(ufs, UFS_UPIU_QUERY_FUNC_STANDARD_READ_REQUEST, 85049ccea4bSYoochan Jeong UFS_UPIU_QUERY_OPCODE_READ_ATTR, 8515cb3566aSJeuk Kim UFS_QUERY_ATTR_IDN_POWER_MODE, 0, 0, 0, &rsp_upiu); 8525cb3566aSJeuk Kim g_assert_cmpuint(ocs, ==, UFS_OCS_SUCCESS); 85349ccea4bSYoochan Jeong g_assert_cmpuint(rsp_upiu.header.response, ==, UFS_COMMAND_RESULT_SUCCESS); 85449ccea4bSYoochan Jeong g_assert_cmpuint(rsp_upiu.qr.value, ==, cpu_to_be32(0x00)); 85549ccea4bSYoochan Jeong 85649ccea4bSYoochan Jeong /* Reset Written Attributes */ 8575cb3566aSJeuk Kim ocs = ufs_send_query(ufs, UFS_UPIU_QUERY_FUNC_STANDARD_WRITE_REQUEST, 85849ccea4bSYoochan Jeong UFS_UPIU_QUERY_OPCODE_WRITE_ATTR, 8595cb3566aSJeuk Kim UFS_QUERY_ATTR_IDN_ACTIVE_ICC_LVL, 0, 0, 0, &rsp_upiu); 8605cb3566aSJeuk Kim g_assert_cmpuint(ocs, ==, UFS_OCS_SUCCESS); 86149ccea4bSYoochan Jeong g_assert_cmpuint(rsp_upiu.header.response, ==, UFS_COMMAND_RESULT_SUCCESS); 86249ccea4bSYoochan Jeong g_assert_cmpuint(rsp_upiu.qr.value, ==, cpu_to_be32(0x00)); 86349ccea4bSYoochan Jeong 8645cb3566aSJeuk Kim ocs = ufs_send_query(ufs, UFS_UPIU_QUERY_FUNC_STANDARD_WRITE_REQUEST, 86549ccea4bSYoochan Jeong UFS_UPIU_QUERY_OPCODE_WRITE_ATTR, 8665cb3566aSJeuk Kim UFS_QUERY_ATTR_IDN_EE_CONTROL, 0, 0, 0, &rsp_upiu); 8675cb3566aSJeuk Kim g_assert_cmpuint(ocs, ==, UFS_OCS_SUCCESS); 86849ccea4bSYoochan Jeong g_assert_cmpuint(rsp_upiu.header.response, ==, UFS_COMMAND_RESULT_SUCCESS); 86949ccea4bSYoochan Jeong g_assert_cmpuint(rsp_upiu.qr.value, ==, cpu_to_be32(0x00)); 87049ccea4bSYoochan Jeong 8715cb3566aSJeuk Kim ocs = ufs_send_query(ufs, UFS_UPIU_QUERY_FUNC_STANDARD_READ_REQUEST, 87249ccea4bSYoochan Jeong UFS_UPIU_QUERY_OPCODE_READ_ATTR, 8735cb3566aSJeuk Kim UFS_QUERY_ATTR_IDN_ACTIVE_ICC_LVL, 0, 0, 0, &rsp_upiu); 8745cb3566aSJeuk Kim g_assert_cmpuint(ocs, ==, UFS_OCS_SUCCESS); 87549ccea4bSYoochan Jeong g_assert_cmpuint(rsp_upiu.header.response, ==, UFS_COMMAND_RESULT_SUCCESS); 87649ccea4bSYoochan Jeong g_assert_cmpuint(rsp_upiu.qr.value, ==, cpu_to_be32(0x00)); 87749ccea4bSYoochan Jeong 8785cb3566aSJeuk Kim ocs = ufs_send_query(ufs, UFS_UPIU_QUERY_FUNC_STANDARD_READ_REQUEST, 87949ccea4bSYoochan Jeong UFS_UPIU_QUERY_OPCODE_READ_ATTR, 8805cb3566aSJeuk Kim UFS_QUERY_ATTR_IDN_EE_CONTROL, 0, 0, 0, &rsp_upiu); 8815cb3566aSJeuk Kim g_assert_cmpuint(ocs, ==, UFS_OCS_SUCCESS); 88249ccea4bSYoochan Jeong g_assert_cmpuint(rsp_upiu.header.response, ==, UFS_COMMAND_RESULT_SUCCESS); 88349ccea4bSYoochan Jeong g_assert_cmpuint(rsp_upiu.qr.value, ==, cpu_to_be32(0x00)); 88449ccea4bSYoochan Jeong 88549ccea4bSYoochan Jeong ufs_exit(ufs, alloc); 88649ccea4bSYoochan Jeong } 88749ccea4bSYoochan Jeong 8889fe8e2c6SYoochan Jeong static void ufstest_query_desc_request(void *obj, void *data, 8899fe8e2c6SYoochan Jeong QGuestAllocator *alloc) 8909fe8e2c6SYoochan Jeong { 8919fe8e2c6SYoochan Jeong QUfs *ufs = obj; 8929fe8e2c6SYoochan Jeong 8935cb3566aSJeuk Kim enum UtpOcsCodes ocs; 8949fe8e2c6SYoochan Jeong UtpUpiuRsp rsp_upiu; 8959fe8e2c6SYoochan Jeong ufs_init(ufs, alloc); 8969fe8e2c6SYoochan Jeong 8979fe8e2c6SYoochan Jeong /* Write Descriptor is not supported yet */ 8989fe8e2c6SYoochan Jeong 8999fe8e2c6SYoochan Jeong /* Read Device Descriptor */ 9005cb3566aSJeuk Kim ocs = ufs_send_query(ufs, UFS_UPIU_QUERY_FUNC_STANDARD_READ_REQUEST, 9015cb3566aSJeuk Kim UFS_UPIU_QUERY_OPCODE_READ_DESC, 9025cb3566aSJeuk Kim UFS_QUERY_DESC_IDN_DEVICE, 0, 0, 0, &rsp_upiu); 9035cb3566aSJeuk Kim g_assert_cmpuint(ocs, ==, UFS_OCS_SUCCESS); 9049fe8e2c6SYoochan Jeong g_assert_cmpuint(rsp_upiu.header.response, ==, UFS_COMMAND_RESULT_SUCCESS); 9059fe8e2c6SYoochan Jeong g_assert_cmpuint(rsp_upiu.qr.opcode, ==, UFS_UPIU_QUERY_OPCODE_READ_DESC); 9069fe8e2c6SYoochan Jeong g_assert_cmpuint(rsp_upiu.qr.idn, ==, UFS_QUERY_DESC_IDN_DEVICE); 9079fe8e2c6SYoochan Jeong g_assert_cmpuint(rsp_upiu.qr.data[0], ==, sizeof(DeviceDescriptor)); 9089fe8e2c6SYoochan Jeong g_assert_cmpuint(rsp_upiu.qr.data[1], ==, UFS_QUERY_DESC_IDN_DEVICE); 9099fe8e2c6SYoochan Jeong 9109fe8e2c6SYoochan Jeong /* Read Configuration Descriptor is not supported yet*/ 9119fe8e2c6SYoochan Jeong 9129fe8e2c6SYoochan Jeong /* Read Unit Descriptor */ 9135cb3566aSJeuk Kim ocs = ufs_send_query(ufs, UFS_UPIU_QUERY_FUNC_STANDARD_READ_REQUEST, 9145cb3566aSJeuk Kim UFS_UPIU_QUERY_OPCODE_READ_DESC, 9155cb3566aSJeuk Kim UFS_QUERY_DESC_IDN_UNIT, 0, 0, 0, &rsp_upiu); 9165cb3566aSJeuk Kim g_assert_cmpuint(ocs, ==, UFS_OCS_SUCCESS); 9179fe8e2c6SYoochan Jeong g_assert_cmpuint(rsp_upiu.header.response, ==, UFS_COMMAND_RESULT_SUCCESS); 9189fe8e2c6SYoochan Jeong g_assert_cmpuint(rsp_upiu.qr.data[0], ==, sizeof(UnitDescriptor)); 9199fe8e2c6SYoochan Jeong g_assert_cmpuint(rsp_upiu.qr.data[1], ==, UFS_QUERY_DESC_IDN_UNIT); 9209fe8e2c6SYoochan Jeong g_assert_cmpuint(rsp_upiu.qr.data[2], ==, 0); 9219fe8e2c6SYoochan Jeong 9225cb3566aSJeuk Kim ocs = ufs_send_query(ufs, UFS_UPIU_QUERY_FUNC_STANDARD_READ_REQUEST, 9235cb3566aSJeuk Kim UFS_UPIU_QUERY_OPCODE_READ_DESC, 9245cb3566aSJeuk Kim UFS_QUERY_DESC_IDN_UNIT, 1, 0, 0, &rsp_upiu); 9255cb3566aSJeuk Kim g_assert_cmpuint(ocs, ==, UFS_OCS_SUCCESS); 9269fe8e2c6SYoochan Jeong g_assert_cmpuint(rsp_upiu.header.response, ==, UFS_COMMAND_RESULT_SUCCESS); 9279fe8e2c6SYoochan Jeong g_assert_cmpuint(rsp_upiu.qr.data[0], ==, sizeof(UnitDescriptor)); 9289fe8e2c6SYoochan Jeong g_assert_cmpuint(rsp_upiu.qr.data[1], ==, UFS_QUERY_DESC_IDN_UNIT); 9299fe8e2c6SYoochan Jeong g_assert_cmpuint(rsp_upiu.qr.data[2], ==, 1); 9309fe8e2c6SYoochan Jeong 9315cb3566aSJeuk Kim ocs = 9325cb3566aSJeuk Kim ufs_send_query(ufs, UFS_UPIU_QUERY_FUNC_STANDARD_READ_REQUEST, 9339fe8e2c6SYoochan Jeong UFS_UPIU_QUERY_OPCODE_READ_DESC, UFS_QUERY_DESC_IDN_UNIT, 9345cb3566aSJeuk Kim UFS_UPIU_RPMB_WLUN, 0, 0, &rsp_upiu); 9355cb3566aSJeuk Kim g_assert_cmpuint(ocs, ==, UFS_OCS_SUCCESS); 9369fe8e2c6SYoochan Jeong g_assert_cmpuint(rsp_upiu.header.response, ==, UFS_COMMAND_RESULT_SUCCESS); 9379fe8e2c6SYoochan Jeong g_assert_cmpuint(rsp_upiu.qr.data[0], ==, sizeof(RpmbUnitDescriptor)); 9389fe8e2c6SYoochan Jeong g_assert_cmpuint(rsp_upiu.qr.data[1], ==, UFS_QUERY_DESC_IDN_UNIT); 9399fe8e2c6SYoochan Jeong g_assert_cmpuint(rsp_upiu.qr.data[2], ==, UFS_UPIU_RPMB_WLUN); 9409fe8e2c6SYoochan Jeong 9419fe8e2c6SYoochan Jeong /* Read Interconnect Descriptor */ 9425cb3566aSJeuk Kim ocs = ufs_send_query(ufs, UFS_UPIU_QUERY_FUNC_STANDARD_READ_REQUEST, 9439fe8e2c6SYoochan Jeong UFS_UPIU_QUERY_OPCODE_READ_DESC, 9445cb3566aSJeuk Kim UFS_QUERY_DESC_IDN_INTERCONNECT, 0, 0, 0, &rsp_upiu); 9455cb3566aSJeuk Kim g_assert_cmpuint(ocs, ==, UFS_OCS_SUCCESS); 9469fe8e2c6SYoochan Jeong g_assert_cmpuint(rsp_upiu.header.response, ==, UFS_COMMAND_RESULT_SUCCESS); 9479fe8e2c6SYoochan Jeong g_assert_cmpuint(rsp_upiu.qr.data[0], ==, sizeof(InterconnectDescriptor)); 9489fe8e2c6SYoochan Jeong g_assert_cmpuint(rsp_upiu.qr.data[1], ==, UFS_QUERY_DESC_IDN_INTERCONNECT); 9499fe8e2c6SYoochan Jeong 9509fe8e2c6SYoochan Jeong /* Read String Descriptor */ 9515cb3566aSJeuk Kim ocs = ufs_send_query(ufs, UFS_UPIU_QUERY_FUNC_STANDARD_READ_REQUEST, 9525cb3566aSJeuk Kim UFS_UPIU_QUERY_OPCODE_READ_DESC, 9535cb3566aSJeuk Kim UFS_QUERY_DESC_IDN_STRING, 0, 0, 0, &rsp_upiu); 9545cb3566aSJeuk Kim g_assert_cmpuint(ocs, ==, UFS_OCS_SUCCESS); 9559fe8e2c6SYoochan Jeong g_assert_cmpuint(rsp_upiu.header.response, ==, UFS_COMMAND_RESULT_SUCCESS); 9569fe8e2c6SYoochan Jeong g_assert_cmpuint(rsp_upiu.qr.data[0], ==, 0x12); 9579fe8e2c6SYoochan Jeong g_assert_cmpuint(rsp_upiu.qr.data[1], ==, UFS_QUERY_DESC_IDN_STRING); 9589fe8e2c6SYoochan Jeong 9595cb3566aSJeuk Kim ocs = ufs_send_query(ufs, UFS_UPIU_QUERY_FUNC_STANDARD_READ_REQUEST, 9605cb3566aSJeuk Kim UFS_UPIU_QUERY_OPCODE_READ_DESC, 9615cb3566aSJeuk Kim UFS_QUERY_DESC_IDN_STRING, 1, 0, 0, &rsp_upiu); 9625cb3566aSJeuk Kim g_assert_cmpuint(ocs, ==, UFS_OCS_SUCCESS); 9639fe8e2c6SYoochan Jeong g_assert_cmpuint(rsp_upiu.header.response, ==, UFS_COMMAND_RESULT_SUCCESS); 9649fe8e2c6SYoochan Jeong g_assert_cmpuint(rsp_upiu.qr.data[0], ==, 0x22); 9659fe8e2c6SYoochan Jeong g_assert_cmpuint(rsp_upiu.qr.data[1], ==, UFS_QUERY_DESC_IDN_STRING); 9669fe8e2c6SYoochan Jeong 9675cb3566aSJeuk Kim ocs = ufs_send_query(ufs, UFS_UPIU_QUERY_FUNC_STANDARD_READ_REQUEST, 9685cb3566aSJeuk Kim UFS_UPIU_QUERY_OPCODE_READ_DESC, 9695cb3566aSJeuk Kim UFS_QUERY_DESC_IDN_STRING, 4, 0, 0, &rsp_upiu); 9705cb3566aSJeuk Kim g_assert_cmpuint(ocs, ==, UFS_OCS_SUCCESS); 9719fe8e2c6SYoochan Jeong g_assert_cmpuint(rsp_upiu.header.response, ==, UFS_COMMAND_RESULT_SUCCESS); 9729fe8e2c6SYoochan Jeong g_assert_cmpuint(rsp_upiu.qr.data[0], ==, 0x0a); 9739fe8e2c6SYoochan Jeong g_assert_cmpuint(rsp_upiu.qr.data[1], ==, UFS_QUERY_DESC_IDN_STRING); 9749fe8e2c6SYoochan Jeong 9759fe8e2c6SYoochan Jeong /* Read Geometry Descriptor */ 9765cb3566aSJeuk Kim ocs = ufs_send_query(ufs, UFS_UPIU_QUERY_FUNC_STANDARD_READ_REQUEST, 9775cb3566aSJeuk Kim UFS_UPIU_QUERY_OPCODE_READ_DESC, 9785cb3566aSJeuk Kim UFS_QUERY_DESC_IDN_GEOMETRY, 0, 0, 0, &rsp_upiu); 9795cb3566aSJeuk Kim g_assert_cmpuint(ocs, ==, UFS_OCS_SUCCESS); 9809fe8e2c6SYoochan Jeong g_assert_cmpuint(rsp_upiu.header.response, ==, UFS_COMMAND_RESULT_SUCCESS); 9819fe8e2c6SYoochan Jeong g_assert_cmpuint(rsp_upiu.qr.data[0], ==, sizeof(GeometryDescriptor)); 9829fe8e2c6SYoochan Jeong g_assert_cmpuint(rsp_upiu.qr.data[1], ==, UFS_QUERY_DESC_IDN_GEOMETRY); 9839fe8e2c6SYoochan Jeong 9849fe8e2c6SYoochan Jeong /* Read Power Descriptor */ 9855cb3566aSJeuk Kim ocs = ufs_send_query(ufs, UFS_UPIU_QUERY_FUNC_STANDARD_READ_REQUEST, 9865cb3566aSJeuk Kim UFS_UPIU_QUERY_OPCODE_READ_DESC, 9875cb3566aSJeuk Kim UFS_QUERY_DESC_IDN_POWER, 0, 0, 0, &rsp_upiu); 9885cb3566aSJeuk Kim g_assert_cmpuint(ocs, ==, UFS_OCS_SUCCESS); 9899fe8e2c6SYoochan Jeong g_assert_cmpuint(rsp_upiu.header.response, ==, UFS_COMMAND_RESULT_SUCCESS); 9909fe8e2c6SYoochan Jeong g_assert_cmpuint(rsp_upiu.qr.data[0], ==, 9919fe8e2c6SYoochan Jeong sizeof(PowerParametersDescriptor)); 9929fe8e2c6SYoochan Jeong g_assert_cmpuint(rsp_upiu.qr.data[1], ==, UFS_QUERY_DESC_IDN_POWER); 9939fe8e2c6SYoochan Jeong 9949fe8e2c6SYoochan Jeong /* Read Health Descriptor */ 9955cb3566aSJeuk Kim ocs = ufs_send_query(ufs, UFS_UPIU_QUERY_FUNC_STANDARD_READ_REQUEST, 9965cb3566aSJeuk Kim UFS_UPIU_QUERY_OPCODE_READ_DESC, 9975cb3566aSJeuk Kim UFS_QUERY_DESC_IDN_HEALTH, 0, 0, 0, &rsp_upiu); 9985cb3566aSJeuk Kim g_assert_cmpuint(ocs, ==, UFS_OCS_SUCCESS); 9999fe8e2c6SYoochan Jeong g_assert_cmpuint(rsp_upiu.header.response, ==, UFS_COMMAND_RESULT_SUCCESS); 10009fe8e2c6SYoochan Jeong g_assert_cmpuint(rsp_upiu.qr.data[0], ==, sizeof(DeviceHealthDescriptor)); 10019fe8e2c6SYoochan Jeong g_assert_cmpuint(rsp_upiu.qr.data[1], ==, UFS_QUERY_DESC_IDN_HEALTH); 10029fe8e2c6SYoochan Jeong 10039fe8e2c6SYoochan Jeong /* Invalid Index (Intended Failure) */ 10045cb3566aSJeuk Kim ocs = ufs_send_query(ufs, UFS_UPIU_QUERY_FUNC_STANDARD_READ_REQUEST, 10055cb3566aSJeuk Kim UFS_UPIU_QUERY_OPCODE_READ_DESC, 10065cb3566aSJeuk Kim UFS_QUERY_DESC_IDN_UNIT, 4, 0, 0, &rsp_upiu); 10075cb3566aSJeuk Kim g_assert_cmpuint(ocs, ==, UFS_OCS_INVALID_CMD_TABLE_ATTR); 10089fe8e2c6SYoochan Jeong g_assert_cmpuint(rsp_upiu.header.response, ==, 10099fe8e2c6SYoochan Jeong UFS_QUERY_RESULT_INVALID_INDEX); 10109fe8e2c6SYoochan Jeong 10115cb3566aSJeuk Kim ocs = ufs_send_query(ufs, UFS_UPIU_QUERY_FUNC_STANDARD_READ_REQUEST, 10125cb3566aSJeuk Kim UFS_UPIU_QUERY_OPCODE_READ_DESC, 10135cb3566aSJeuk Kim UFS_QUERY_DESC_IDN_STRING, 5, 0, 0, &rsp_upiu); 10145cb3566aSJeuk Kim g_assert_cmpuint(ocs, ==, UFS_OCS_INVALID_CMD_TABLE_ATTR); 10159fe8e2c6SYoochan Jeong g_assert_cmpuint(rsp_upiu.header.response, ==, 10169fe8e2c6SYoochan Jeong UFS_QUERY_RESULT_INVALID_INDEX); 10179fe8e2c6SYoochan Jeong 10189fe8e2c6SYoochan Jeong /* Invalid Selector (Intended Failure) */ 10195cb3566aSJeuk Kim ocs = ufs_send_query(ufs, UFS_UPIU_QUERY_FUNC_STANDARD_READ_REQUEST, 10205cb3566aSJeuk Kim UFS_UPIU_QUERY_OPCODE_READ_DESC, 10215cb3566aSJeuk Kim UFS_QUERY_DESC_IDN_DEVICE, 0, 1, 0, &rsp_upiu); 10225cb3566aSJeuk Kim g_assert_cmpuint(ocs, ==, UFS_OCS_INVALID_CMD_TABLE_ATTR); 10239fe8e2c6SYoochan Jeong g_assert_cmpuint(rsp_upiu.header.response, ==, 10249fe8e2c6SYoochan Jeong UFS_QUERY_RESULT_INVALID_SELECTOR); 10259fe8e2c6SYoochan Jeong 10265cb3566aSJeuk Kim ocs = ufs_send_query(ufs, UFS_UPIU_QUERY_FUNC_STANDARD_READ_REQUEST, 10275cb3566aSJeuk Kim UFS_UPIU_QUERY_OPCODE_READ_DESC, 10285cb3566aSJeuk Kim UFS_QUERY_DESC_IDN_STRING, 0, 1, 0, &rsp_upiu); 10295cb3566aSJeuk Kim g_assert_cmpuint(ocs, ==, UFS_OCS_INVALID_CMD_TABLE_ATTR); 10309fe8e2c6SYoochan Jeong g_assert_cmpuint(rsp_upiu.header.response, ==, 10319fe8e2c6SYoochan Jeong UFS_QUERY_RESULT_INVALID_SELECTOR); 10329fe8e2c6SYoochan Jeong 10339fe8e2c6SYoochan Jeong ufs_exit(ufs, alloc); 10349fe8e2c6SYoochan Jeong } 10359fe8e2c6SYoochan Jeong 1036631c8726SJeuk Kim static void drive_destroy(void *path) 1037631c8726SJeuk Kim { 1038631c8726SJeuk Kim unlink(path); 1039631c8726SJeuk Kim g_free(path); 1040631c8726SJeuk Kim qos_invalidate_command_line(); 1041631c8726SJeuk Kim } 1042631c8726SJeuk Kim 1043631c8726SJeuk Kim static char *drive_create(void) 1044631c8726SJeuk Kim { 1045631c8726SJeuk Kim int fd, ret; 1046631c8726SJeuk Kim char *t_path; 1047631c8726SJeuk Kim 1048631c8726SJeuk Kim /* Create a temporary raw image */ 1049631c8726SJeuk Kim fd = g_file_open_tmp("qtest-ufs.XXXXXX", &t_path, NULL); 1050631c8726SJeuk Kim g_assert_cmpint(fd, >=, 0); 1051631c8726SJeuk Kim ret = ftruncate(fd, TEST_IMAGE_SIZE); 1052631c8726SJeuk Kim g_assert_cmpint(ret, ==, 0); 1053631c8726SJeuk Kim close(fd); 1054631c8726SJeuk Kim 1055631c8726SJeuk Kim g_test_queue_destroy(drive_destroy, t_path); 1056631c8726SJeuk Kim return t_path; 1057631c8726SJeuk Kim } 1058631c8726SJeuk Kim 1059631c8726SJeuk Kim static void *ufs_blk_test_setup(GString *cmd_line, void *arg) 1060631c8726SJeuk Kim { 1061631c8726SJeuk Kim char *tmp_path = drive_create(); 1062631c8726SJeuk Kim 1063631c8726SJeuk Kim g_string_append_printf(cmd_line, 1064631c8726SJeuk Kim " -blockdev file,filename=%s,node-name=drv1 " 1065631c8726SJeuk Kim "-device ufs-lu,bus=ufs0,drive=drv1,lun=1 ", 1066631c8726SJeuk Kim tmp_path); 1067631c8726SJeuk Kim 1068631c8726SJeuk Kim return arg; 1069631c8726SJeuk Kim } 1070631c8726SJeuk Kim 1071631c8726SJeuk Kim static void ufs_register_nodes(void) 1072631c8726SJeuk Kim { 1073631c8726SJeuk Kim const char *arch; 1074631c8726SJeuk Kim QOSGraphEdgeOptions edge_opts = { 1075631c8726SJeuk Kim .before_cmd_line = "-blockdev null-co,node-name=drv0,read-zeroes=on", 1076631c8726SJeuk Kim .after_cmd_line = "-device ufs-lu,bus=ufs0,drive=drv0,lun=0", 1077*a54596a9SJeuk Kim .extra_device_opts = "addr=04.0,id=ufs0" 1078631c8726SJeuk Kim }; 1079631c8726SJeuk Kim 1080*a54596a9SJeuk Kim QOSGraphTestOptions io_test_opts = { .before = ufs_blk_test_setup, 1081*a54596a9SJeuk Kim .edge.extra_device_opts = 1082*a54596a9SJeuk Kim "mcq=false,nutrs=32,nutmrs=8" }; 1083*a54596a9SJeuk Kim 1084*a54596a9SJeuk Kim QOSGraphTestOptions mcq_test_opts = { .before = ufs_blk_test_setup, 1085*a54596a9SJeuk Kim .edge.extra_device_opts = 1086*a54596a9SJeuk Kim "mcq=true,mcq-maxq=1" }; 1087631c8726SJeuk Kim 1088631c8726SJeuk Kim add_qpci_address(&edge_opts, &(QPCIAddress){ .devfn = QPCI_DEVFN(4, 0) }); 1089631c8726SJeuk Kim 1090631c8726SJeuk Kim qos_node_create_driver("ufs", ufs_create); 1091631c8726SJeuk Kim qos_node_consumes("ufs", "pci-bus", &edge_opts); 1092631c8726SJeuk Kim qos_node_produces("ufs", "pci-device"); 1093631c8726SJeuk Kim 1094631c8726SJeuk Kim qos_add_test("reg-read", "ufs", ufstest_reg_read, NULL); 1095631c8726SJeuk Kim 1096631c8726SJeuk Kim /* 1097631c8726SJeuk Kim * Check architecture 1098631c8726SJeuk Kim * TODO: Enable ufs io tests for ppc64 1099631c8726SJeuk Kim */ 1100631c8726SJeuk Kim arch = qtest_get_arch(); 1101631c8726SJeuk Kim if (!strcmp(arch, "ppc64")) { 1102631c8726SJeuk Kim g_test_message("Skipping ufs io tests for ppc64"); 1103631c8726SJeuk Kim return; 1104631c8726SJeuk Kim } 1105631c8726SJeuk Kim qos_add_test("init", "ufs", ufstest_init, NULL); 1106*a54596a9SJeuk Kim qos_add_test("legacy-read-write", "ufs", ufstest_read_write, &io_test_opts); 1107*a54596a9SJeuk Kim qos_add_test("mcq-read-write", "ufs", ufstest_read_write, &mcq_test_opts); 1108*a54596a9SJeuk Kim qos_add_test("query-flag", "ufs", ufstest_query_flag_request, 1109*a54596a9SJeuk Kim &io_test_opts); 1110*a54596a9SJeuk Kim qos_add_test("query-attribute", "ufs", ufstest_query_attr_request, 1111*a54596a9SJeuk Kim &io_test_opts); 1112*a54596a9SJeuk Kim qos_add_test("query-desciptor", "ufs", ufstest_query_desc_request, 1113*a54596a9SJeuk Kim &io_test_opts); 1114631c8726SJeuk Kim } 1115631c8726SJeuk Kim 1116631c8726SJeuk Kim libqos_init(ufs_register_nodes); 1117