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
18a54596a9SJeuk 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
32a54596a9SJeuk Kim /* Constants for MCQ */
33a54596a9SJeuk Kim #define TEST_QID 0
34a54596a9SJeuk Kim #define QUEUE_SIZE 32
35a54596a9SJeuk 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;
49a54596a9SJeuk Kim bool support_mcq;
50a54596a9SJeuk Kim
51a54596a9SJeuk Kim /* for legacy doorbell mode */
52a54596a9SJeuk Kim uint64_t utrlba;
53a54596a9SJeuk Kim
54a54596a9SJeuk Kim /* for mcq mode */
55a54596a9SJeuk Kim uint32_t maxq;
56a54596a9SJeuk Kim uint64_t sqlba[UFS_MCQ_MAX_QNUM];
57a54596a9SJeuk Kim uint64_t cqlba[UFS_MCQ_MAX_QNUM];
58a54596a9SJeuk Kim uint64_t sqdao[UFS_MCQ_MAX_QNUM];
59a54596a9SJeuk Kim uint64_t cqdao[UFS_MCQ_MAX_QNUM];
60631c8726SJeuk Kim };
61631c8726SJeuk Kim
ufs_rreg(QUfs * ufs,size_t offset)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
ufs_wreg(QUfs * ufs,size_t offset,uint32_t value)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
alloc_cmd_desc_slot(QUfs * ufs)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
release_cmd_desc_slot(QUfs * ufs,int slot)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
ufs_wait_for_irq(QUfs * ufs)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
ufs_build_req_utrd(uint64_t command_desc_base_addr,uint32_t data_direction,uint16_t prd_table_length)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
__ufs_send_transfer_request_doorbell(QUfs * ufs,uint8_t lun,const UtpTransferReqDesc * utrd)124a54596a9SJeuk 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);
129a54596a9SJeuk Kim UtpTransferReqDesc utrd_result;
130a54596a9SJeuk Kim
1315cb3566aSJeuk Kim qtest_memwrite(ufs->dev.bus->qts, utrd_addr, utrd, sizeof(*utrd));
132631c8726SJeuk Kim
133a54596a9SJeuk 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
139a54596a9SJeuk 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
145a54596a9SJeuk Kim static enum UtpOcsCodes
__ufs_send_transfer_request_mcq(QUfs * ufs,uint8_t lun,const UtpTransferReqDesc * utrd)146a54596a9SJeuk Kim __ufs_send_transfer_request_mcq(QUfs *ufs, uint8_t lun,
147a54596a9SJeuk Kim const UtpTransferReqDesc *utrd)
148a54596a9SJeuk Kim {
149a54596a9SJeuk Kim uint32_t sqtp = ufs_rreg(ufs, ufs->sqdao[TEST_QID] + 0x4);
150a54596a9SJeuk Kim uint64_t utrd_addr = ufs->sqlba[TEST_QID] + sqtp;
151a54596a9SJeuk Kim uint32_t cqhp;
152a54596a9SJeuk Kim uint64_t cqentry_addr;
153a54596a9SJeuk Kim UfsCqEntry cqentry;
154a54596a9SJeuk Kim
155a54596a9SJeuk Kim qtest_memwrite(ufs->dev.bus->qts, utrd_addr, utrd, sizeof(*utrd));
156a54596a9SJeuk Kim
157a54596a9SJeuk Kim /* Insert a new entry into the submission queue */
158a54596a9SJeuk Kim sqtp = ufs_rreg(ufs, ufs->sqdao[TEST_QID] + 0x4);
159a54596a9SJeuk Kim sqtp = (sqtp + sizeof(UfsSqEntry)) % (QUEUE_SIZE * sizeof(UfsSqEntry));
160a54596a9SJeuk Kim ufs_wreg(ufs, ufs->sqdao[TEST_QID] + 0x4, sqtp);
161a54596a9SJeuk Kim ufs_wait_for_irq(ufs);
162a54596a9SJeuk Kim g_assert_true(FIELD_EX32(ufs_rreg(ufs, A_IS), IS, CQES));
163a54596a9SJeuk Kim ufs_wreg(ufs, A_IS, FIELD_DP32(0, IS, CQES, 1));
164a54596a9SJeuk Kim
165a54596a9SJeuk Kim /* Handle the completed command from the completion queue */
166a54596a9SJeuk Kim cqhp = ufs_rreg(ufs, ufs->cqdao[TEST_QID]);
167a54596a9SJeuk Kim cqentry_addr = ufs->cqlba[TEST_QID] + cqhp;
168a54596a9SJeuk Kim qtest_memread(ufs->dev.bus->qts, cqentry_addr, &cqentry, sizeof(cqentry));
169a54596a9SJeuk Kim ufs_wreg(ufs, ufs->cqdao[TEST_QID], cqhp);
170a54596a9SJeuk Kim
171a54596a9SJeuk Kim return cqentry.status;
172a54596a9SJeuk Kim }
173a54596a9SJeuk Kim
174a54596a9SJeuk Kim static enum UtpOcsCodes
ufs_send_transfer_request_sync(QUfs * ufs,uint8_t lun,const UtpTransferReqDesc * utrd)175a54596a9SJeuk Kim ufs_send_transfer_request_sync(QUfs *ufs, uint8_t lun,
176a54596a9SJeuk Kim const UtpTransferReqDesc *utrd)
177a54596a9SJeuk Kim {
178a54596a9SJeuk Kim if (ufs->support_mcq) {
179a54596a9SJeuk Kim return __ufs_send_transfer_request_mcq(ufs, lun, utrd);
180a54596a9SJeuk Kim }
181a54596a9SJeuk Kim
182a54596a9SJeuk Kim return __ufs_send_transfer_request_doorbell(ufs, lun, utrd);
183a54596a9SJeuk Kim }
184a54596a9SJeuk Kim
ufs_send_nop_out(QUfs * ufs,UtpUpiuRsp * rsp_out)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
ufs_send_query(QUfs * ufs,uint8_t query_function,uint8_t query_opcode,uint8_t idn,uint8_t index,uint8_t selector,uint32_t attr_value,UtpUpiuRsp * rsp_out)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
ufs_send_scsi_command(QUfs * ufs,uint8_t lun,const uint8_t * cdb,const uint8_t * data_in,size_t data_in_len,uint8_t * data_out,size_t data_out_len,UtpUpiuRsp * rsp_out)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 */
ufs_init(QUfs * ufs,QGuestAllocator * alloc)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
396a54596a9SJeuk Kim /* Check MCQ support */
397a54596a9SJeuk Kim cap = ufs_rreg(ufs, A_CAP);
398a54596a9SJeuk Kim ufs->support_mcq = FIELD_EX32(cap, CAP, MCQS);
399a54596a9SJeuk 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);
412a54596a9SJeuk Kim if (ufs->support_mcq) {
413a54596a9SJeuk Kim ie = FIELD_DP32(ie, IE, CQEE, 1);
414a54596a9SJeuk 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);
423a54596a9SJeuk Kim
424a54596a9SJeuk Kim if (ufs->support_mcq) {
425a54596a9SJeuk Kim uint32_t mcqcap, qid, qcfgptr, mcq_reg_offset;
426a54596a9SJeuk Kim uint32_t cqattr = 0, sqattr = 0;
427a54596a9SJeuk Kim
428a54596a9SJeuk Kim mcqcap = ufs_rreg(ufs, A_MCQCAP);
429a54596a9SJeuk Kim qcfgptr = FIELD_EX32(mcqcap, MCQCAP, QCFGPTR);
430a54596a9SJeuk Kim ufs->maxq = FIELD_EX32(mcqcap, MCQCAP, MAXQ) + 1;
431a54596a9SJeuk Kim for (qid = 0; qid < ufs->maxq; ++qid) {
432a54596a9SJeuk Kim ufs->sqlba[qid] =
433a54596a9SJeuk Kim guest_alloc(alloc, QUEUE_SIZE * sizeof(UtpTransferReqDesc));
434a54596a9SJeuk Kim ufs->cqlba[qid] =
435a54596a9SJeuk Kim guest_alloc(alloc, QUEUE_SIZE * sizeof(UtpTransferReqDesc));
436a54596a9SJeuk Kim mcq_reg_offset = qcfgptr * 0x200 + qid * 0x40;
437a54596a9SJeuk Kim
438a54596a9SJeuk Kim ufs_wreg(ufs, mcq_reg_offset + A_SQLBA,
439a54596a9SJeuk Kim ufs->sqlba[qid] & 0xffffffff);
440a54596a9SJeuk Kim ufs_wreg(ufs, mcq_reg_offset + A_SQUBA, ufs->sqlba[qid] >> 32);
441a54596a9SJeuk Kim ufs_wreg(ufs, mcq_reg_offset + A_CQLBA,
442a54596a9SJeuk Kim ufs->cqlba[qid] & 0xffffffff);
443a54596a9SJeuk Kim ufs_wreg(ufs, mcq_reg_offset + A_CQUBA, ufs->cqlba[qid] >> 32);
444a54596a9SJeuk Kim
445a54596a9SJeuk Kim /* Enable Completion Queue */
446a54596a9SJeuk Kim cqattr = FIELD_DP32(cqattr, CQATTR, CQEN, 1);
447a54596a9SJeuk Kim cqattr = FIELD_DP32(cqattr, CQATTR, SIZE,
448a54596a9SJeuk Kim QUEUE_SIZE * sizeof(UtpTransferReqDesc) /
449a54596a9SJeuk Kim DWORD_BYTE);
450a54596a9SJeuk Kim ufs_wreg(ufs, mcq_reg_offset + A_CQATTR, cqattr);
451a54596a9SJeuk Kim
452a54596a9SJeuk Kim /* Enable Submission Queue */
453a54596a9SJeuk Kim sqattr = FIELD_DP32(sqattr, SQATTR, SQEN, 1);
454a54596a9SJeuk Kim sqattr = FIELD_DP32(sqattr, SQATTR, SIZE,
455a54596a9SJeuk Kim QUEUE_SIZE * sizeof(UtpTransferReqDesc) /
456a54596a9SJeuk Kim DWORD_BYTE);
457a54596a9SJeuk Kim sqattr = FIELD_DP32(sqattr, SQATTR, CQID, qid);
458a54596a9SJeuk Kim ufs_wreg(ufs, mcq_reg_offset + A_SQATTR, sqattr);
459a54596a9SJeuk Kim
460a54596a9SJeuk Kim /* Cache head & tail pointer */
461a54596a9SJeuk Kim ufs->sqdao[qid] = ufs_rreg(ufs, mcq_reg_offset + A_SQDAO);
462a54596a9SJeuk Kim ufs->cqdao[qid] = ufs_rreg(ufs, mcq_reg_offset + A_CQDAO);
463a54596a9SJeuk Kim }
464a54596a9SJeuk Kim } else {
465a54596a9SJeuk 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);
471a54596a9SJeuk 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
ufs_exit(QUfs * ufs,QGuestAllocator * alloc)502631c8726SJeuk Kim static void ufs_exit(QUfs *ufs, QGuestAllocator *alloc)
503631c8726SJeuk Kim {
504631c8726SJeuk Kim if (ufs->enabled) {
505a54596a9SJeuk Kim if (ufs->support_mcq) {
506a54596a9SJeuk Kim for (uint32_t qid = 0; qid < ufs->maxq; ++qid) {
507a54596a9SJeuk Kim guest_free(alloc, ufs->sqlba[qid]);
508a54596a9SJeuk Kim guest_free(alloc, ufs->cqlba[qid]);
509a54596a9SJeuk Kim }
510a54596a9SJeuk Kim } else {
511631c8726SJeuk Kim guest_free(alloc, ufs->utrlba);
512a54596a9SJeuk Kim }
513a54596a9SJeuk 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
ufs_get_driver(void * obj,const char * interface)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
ufs_create(void * pci_bus,QGuestAllocator * alloc,void * addr)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
ufstest_reg_read(void * obj,void * data,QGuestAllocator * alloc)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
ufstest_init(void * obj,void * data,QGuestAllocator * alloc)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
ufstest_read_write(void * obj,void * data,QGuestAllocator * alloc)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
ufstest_query_flag_request(void * obj,void * data,QGuestAllocator * alloc)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
ufstest_query_attr_request(void * obj,void * data,QGuestAllocator * alloc)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
787*5f6cb3caSKeoseong Park ocs = ufs_send_query(ufs, UFS_UPIU_QUERY_FUNC_STANDARD_READ_REQUEST,
788*5f6cb3caSKeoseong Park UFS_UPIU_QUERY_OPCODE_READ_ATTR,
789*5f6cb3caSKeoseong Park UFS_QUERY_ATTR_IDN_CASE_ROUGH_TEMP, 0, 0, 0,
790*5f6cb3caSKeoseong Park &rsp_upiu);
791*5f6cb3caSKeoseong Park g_assert_cmpuint(ocs, ==, UFS_OCS_SUCCESS);
792*5f6cb3caSKeoseong Park g_assert_cmpuint(rsp_upiu.header.response, ==, UFS_COMMAND_RESULT_SUCCESS);
793*5f6cb3caSKeoseong Park g_assert_cmpuint(rsp_upiu.qr.value, ==, cpu_to_be32(0x00));
794*5f6cb3caSKeoseong Park
795*5f6cb3caSKeoseong Park ocs = ufs_send_query(ufs, UFS_UPIU_QUERY_FUNC_STANDARD_READ_REQUEST,
796*5f6cb3caSKeoseong Park UFS_UPIU_QUERY_OPCODE_READ_ATTR,
797*5f6cb3caSKeoseong Park UFS_QUERY_ATTR_IDN_HIGH_TEMP_BOUND, 0, 0, 0,
798*5f6cb3caSKeoseong Park &rsp_upiu);
799*5f6cb3caSKeoseong Park g_assert_cmpuint(ocs, ==, UFS_OCS_SUCCESS);
800*5f6cb3caSKeoseong Park g_assert_cmpuint(rsp_upiu.header.response, ==, UFS_COMMAND_RESULT_SUCCESS);
801*5f6cb3caSKeoseong Park g_assert_cmpuint(rsp_upiu.qr.value, ==, cpu_to_be32(160));
802*5f6cb3caSKeoseong Park
803*5f6cb3caSKeoseong Park ocs = ufs_send_query(ufs, UFS_UPIU_QUERY_FUNC_STANDARD_READ_REQUEST,
804*5f6cb3caSKeoseong Park UFS_UPIU_QUERY_OPCODE_READ_ATTR,
805*5f6cb3caSKeoseong Park UFS_QUERY_ATTR_IDN_LOW_TEMP_BOUND, 0, 0, 0,
806*5f6cb3caSKeoseong Park &rsp_upiu);
807*5f6cb3caSKeoseong Park g_assert_cmpuint(ocs, ==, UFS_OCS_SUCCESS);
808*5f6cb3caSKeoseong Park g_assert_cmpuint(rsp_upiu.header.response, ==, UFS_COMMAND_RESULT_SUCCESS);
809*5f6cb3caSKeoseong Park g_assert_cmpuint(rsp_upiu.qr.value, ==, cpu_to_be32(60));
810*5f6cb3caSKeoseong Park
81149ccea4bSYoochan Jeong /* Write Writable Attributes & Read Again */
8125cb3566aSJeuk Kim ocs = ufs_send_query(ufs, UFS_UPIU_QUERY_FUNC_STANDARD_WRITE_REQUEST,
81349ccea4bSYoochan Jeong UFS_UPIU_QUERY_OPCODE_WRITE_ATTR,
8145cb3566aSJeuk Kim UFS_QUERY_ATTR_IDN_ACTIVE_ICC_LVL, 0, 0, 0x03,
81549ccea4bSYoochan Jeong &rsp_upiu);
8165cb3566aSJeuk Kim g_assert_cmpuint(ocs, ==, UFS_OCS_SUCCESS);
81749ccea4bSYoochan Jeong g_assert_cmpuint(rsp_upiu.header.response, ==, UFS_COMMAND_RESULT_SUCCESS);
81849ccea4bSYoochan Jeong g_assert_cmpuint(rsp_upiu.qr.value, ==, cpu_to_be32(0x03));
81949ccea4bSYoochan Jeong
8205cb3566aSJeuk Kim ocs = ufs_send_query(ufs, UFS_UPIU_QUERY_FUNC_STANDARD_WRITE_REQUEST,
82149ccea4bSYoochan Jeong UFS_UPIU_QUERY_OPCODE_WRITE_ATTR,
8225cb3566aSJeuk Kim UFS_QUERY_ATTR_IDN_EE_CONTROL, 0, 0, 0x07, &rsp_upiu);
8235cb3566aSJeuk Kim g_assert_cmpuint(ocs, ==, UFS_OCS_SUCCESS);
82449ccea4bSYoochan Jeong g_assert_cmpuint(rsp_upiu.header.response, ==, UFS_COMMAND_RESULT_SUCCESS);
82549ccea4bSYoochan Jeong g_assert_cmpuint(rsp_upiu.qr.value, ==, cpu_to_be32(0x07));
82649ccea4bSYoochan Jeong
8275cb3566aSJeuk Kim ocs = ufs_send_query(ufs, UFS_UPIU_QUERY_FUNC_STANDARD_READ_REQUEST,
82849ccea4bSYoochan Jeong UFS_UPIU_QUERY_OPCODE_READ_ATTR,
8295cb3566aSJeuk Kim UFS_QUERY_ATTR_IDN_ACTIVE_ICC_LVL, 0, 0, 0, &rsp_upiu);
8305cb3566aSJeuk Kim g_assert_cmpuint(ocs, ==, UFS_OCS_SUCCESS);
83149ccea4bSYoochan Jeong g_assert_cmpuint(rsp_upiu.header.response, ==, UFS_COMMAND_RESULT_SUCCESS);
83249ccea4bSYoochan Jeong g_assert_cmpuint(rsp_upiu.qr.value, ==, cpu_to_be32(0x03));
83349ccea4bSYoochan Jeong
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_EE_CONTROL, 0, 0, 0, &rsp_upiu);
8375cb3566aSJeuk Kim g_assert_cmpuint(ocs, ==, UFS_OCS_SUCCESS);
83849ccea4bSYoochan Jeong g_assert_cmpuint(rsp_upiu.header.response, ==, UFS_COMMAND_RESULT_SUCCESS);
83949ccea4bSYoochan Jeong g_assert_cmpuint(rsp_upiu.qr.value, ==, cpu_to_be32(0x07));
84049ccea4bSYoochan Jeong
84149ccea4bSYoochan Jeong /* Write Invalid Value (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_ACTIVE_ICC_LVL, 0, 0, 0x10,
84549ccea4bSYoochan Jeong &rsp_upiu);
8465cb3566aSJeuk Kim g_assert_cmpuint(ocs, ==, UFS_OCS_INVALID_CMD_TABLE_ATTR);
84749ccea4bSYoochan Jeong g_assert_cmpuint(rsp_upiu.header.response, ==,
84849ccea4bSYoochan Jeong UFS_QUERY_RESULT_INVALID_VALUE);
84949ccea4bSYoochan Jeong
8505cb3566aSJeuk Kim ocs = ufs_send_query(ufs, UFS_UPIU_QUERY_FUNC_STANDARD_READ_REQUEST,
85149ccea4bSYoochan Jeong UFS_UPIU_QUERY_OPCODE_READ_ATTR,
8525cb3566aSJeuk Kim UFS_QUERY_ATTR_IDN_ACTIVE_ICC_LVL, 0, 0, 0, &rsp_upiu);
8535cb3566aSJeuk Kim g_assert_cmpuint(ocs, ==, UFS_OCS_SUCCESS);
85449ccea4bSYoochan Jeong g_assert_cmpuint(rsp_upiu.header.response, ==, UFS_COMMAND_RESULT_SUCCESS);
85549ccea4bSYoochan Jeong g_assert_cmpuint(rsp_upiu.qr.value, ==, cpu_to_be32(0x03));
85649ccea4bSYoochan Jeong
85749ccea4bSYoochan Jeong /* Read Write-Only Attribute (Intended Error) */
8585cb3566aSJeuk Kim ocs = ufs_send_query(ufs, UFS_UPIU_QUERY_FUNC_STANDARD_READ_REQUEST,
85949ccea4bSYoochan Jeong UFS_UPIU_QUERY_OPCODE_READ_ATTR,
8605cb3566aSJeuk Kim UFS_QUERY_ATTR_IDN_SECONDS_PASSED, 0, 0, 0, &rsp_upiu);
8615cb3566aSJeuk Kim g_assert_cmpuint(ocs, ==, UFS_OCS_INVALID_CMD_TABLE_ATTR);
86249ccea4bSYoochan Jeong g_assert_cmpuint(rsp_upiu.header.response, ==,
86349ccea4bSYoochan Jeong UFS_QUERY_RESULT_NOT_READABLE);
86449ccea4bSYoochan Jeong
86549ccea4bSYoochan Jeong /* Write Read-Only Attribute (Intended Error) */
8665cb3566aSJeuk Kim ocs = ufs_send_query(ufs, UFS_UPIU_QUERY_FUNC_STANDARD_WRITE_REQUEST,
86749ccea4bSYoochan Jeong UFS_UPIU_QUERY_OPCODE_WRITE_ATTR,
8685cb3566aSJeuk Kim UFS_QUERY_ATTR_IDN_POWER_MODE, 0, 0, 0x01, &rsp_upiu);
8695cb3566aSJeuk Kim g_assert_cmpuint(ocs, ==, UFS_OCS_INVALID_CMD_TABLE_ATTR);
87049ccea4bSYoochan Jeong g_assert_cmpuint(rsp_upiu.header.response, ==,
87149ccea4bSYoochan Jeong UFS_QUERY_RESULT_NOT_WRITEABLE);
87249ccea4bSYoochan Jeong
8735cb3566aSJeuk Kim ocs = ufs_send_query(ufs, UFS_UPIU_QUERY_FUNC_STANDARD_READ_REQUEST,
87449ccea4bSYoochan Jeong UFS_UPIU_QUERY_OPCODE_READ_ATTR,
8755cb3566aSJeuk Kim UFS_QUERY_ATTR_IDN_POWER_MODE, 0, 0, 0, &rsp_upiu);
8765cb3566aSJeuk Kim g_assert_cmpuint(ocs, ==, UFS_OCS_SUCCESS);
87749ccea4bSYoochan Jeong g_assert_cmpuint(rsp_upiu.header.response, ==, UFS_COMMAND_RESULT_SUCCESS);
87849ccea4bSYoochan Jeong g_assert_cmpuint(rsp_upiu.qr.value, ==, cpu_to_be32(0x00));
87949ccea4bSYoochan Jeong
88049ccea4bSYoochan Jeong /* Reset Written Attributes */
8815cb3566aSJeuk Kim ocs = ufs_send_query(ufs, UFS_UPIU_QUERY_FUNC_STANDARD_WRITE_REQUEST,
88249ccea4bSYoochan Jeong UFS_UPIU_QUERY_OPCODE_WRITE_ATTR,
8835cb3566aSJeuk Kim UFS_QUERY_ATTR_IDN_ACTIVE_ICC_LVL, 0, 0, 0, &rsp_upiu);
8845cb3566aSJeuk Kim g_assert_cmpuint(ocs, ==, UFS_OCS_SUCCESS);
88549ccea4bSYoochan Jeong g_assert_cmpuint(rsp_upiu.header.response, ==, UFS_COMMAND_RESULT_SUCCESS);
88649ccea4bSYoochan Jeong g_assert_cmpuint(rsp_upiu.qr.value, ==, cpu_to_be32(0x00));
88749ccea4bSYoochan Jeong
8885cb3566aSJeuk Kim ocs = ufs_send_query(ufs, UFS_UPIU_QUERY_FUNC_STANDARD_WRITE_REQUEST,
88949ccea4bSYoochan Jeong UFS_UPIU_QUERY_OPCODE_WRITE_ATTR,
8905cb3566aSJeuk Kim UFS_QUERY_ATTR_IDN_EE_CONTROL, 0, 0, 0, &rsp_upiu);
8915cb3566aSJeuk Kim g_assert_cmpuint(ocs, ==, UFS_OCS_SUCCESS);
89249ccea4bSYoochan Jeong g_assert_cmpuint(rsp_upiu.header.response, ==, UFS_COMMAND_RESULT_SUCCESS);
89349ccea4bSYoochan Jeong g_assert_cmpuint(rsp_upiu.qr.value, ==, cpu_to_be32(0x00));
89449ccea4bSYoochan Jeong
8955cb3566aSJeuk Kim ocs = ufs_send_query(ufs, UFS_UPIU_QUERY_FUNC_STANDARD_READ_REQUEST,
89649ccea4bSYoochan Jeong UFS_UPIU_QUERY_OPCODE_READ_ATTR,
8975cb3566aSJeuk Kim UFS_QUERY_ATTR_IDN_ACTIVE_ICC_LVL, 0, 0, 0, &rsp_upiu);
8985cb3566aSJeuk Kim g_assert_cmpuint(ocs, ==, UFS_OCS_SUCCESS);
89949ccea4bSYoochan Jeong g_assert_cmpuint(rsp_upiu.header.response, ==, UFS_COMMAND_RESULT_SUCCESS);
90049ccea4bSYoochan Jeong g_assert_cmpuint(rsp_upiu.qr.value, ==, cpu_to_be32(0x00));
90149ccea4bSYoochan Jeong
9025cb3566aSJeuk Kim ocs = ufs_send_query(ufs, UFS_UPIU_QUERY_FUNC_STANDARD_READ_REQUEST,
90349ccea4bSYoochan Jeong UFS_UPIU_QUERY_OPCODE_READ_ATTR,
9045cb3566aSJeuk Kim UFS_QUERY_ATTR_IDN_EE_CONTROL, 0, 0, 0, &rsp_upiu);
9055cb3566aSJeuk Kim g_assert_cmpuint(ocs, ==, UFS_OCS_SUCCESS);
90649ccea4bSYoochan Jeong g_assert_cmpuint(rsp_upiu.header.response, ==, UFS_COMMAND_RESULT_SUCCESS);
90749ccea4bSYoochan Jeong g_assert_cmpuint(rsp_upiu.qr.value, ==, cpu_to_be32(0x00));
90849ccea4bSYoochan Jeong
90949ccea4bSYoochan Jeong ufs_exit(ufs, alloc);
91049ccea4bSYoochan Jeong }
91149ccea4bSYoochan Jeong
ufstest_query_desc_request(void * obj,void * data,QGuestAllocator * alloc)9129fe8e2c6SYoochan Jeong static void ufstest_query_desc_request(void *obj, void *data,
9139fe8e2c6SYoochan Jeong QGuestAllocator *alloc)
9149fe8e2c6SYoochan Jeong {
9159fe8e2c6SYoochan Jeong QUfs *ufs = obj;
9169fe8e2c6SYoochan Jeong
9175cb3566aSJeuk Kim enum UtpOcsCodes ocs;
9189fe8e2c6SYoochan Jeong UtpUpiuRsp rsp_upiu;
9199fe8e2c6SYoochan Jeong ufs_init(ufs, alloc);
9209fe8e2c6SYoochan Jeong
9219fe8e2c6SYoochan Jeong /* Write Descriptor is not supported yet */
9229fe8e2c6SYoochan Jeong
9239fe8e2c6SYoochan Jeong /* Read Device Descriptor */
9245cb3566aSJeuk Kim ocs = ufs_send_query(ufs, UFS_UPIU_QUERY_FUNC_STANDARD_READ_REQUEST,
9255cb3566aSJeuk Kim UFS_UPIU_QUERY_OPCODE_READ_DESC,
9265cb3566aSJeuk Kim UFS_QUERY_DESC_IDN_DEVICE, 0, 0, 0, &rsp_upiu);
9275cb3566aSJeuk Kim g_assert_cmpuint(ocs, ==, UFS_OCS_SUCCESS);
9289fe8e2c6SYoochan Jeong g_assert_cmpuint(rsp_upiu.header.response, ==, UFS_COMMAND_RESULT_SUCCESS);
9299fe8e2c6SYoochan Jeong g_assert_cmpuint(rsp_upiu.qr.opcode, ==, UFS_UPIU_QUERY_OPCODE_READ_DESC);
9309fe8e2c6SYoochan Jeong g_assert_cmpuint(rsp_upiu.qr.idn, ==, UFS_QUERY_DESC_IDN_DEVICE);
9319fe8e2c6SYoochan Jeong g_assert_cmpuint(rsp_upiu.qr.data[0], ==, sizeof(DeviceDescriptor));
9329fe8e2c6SYoochan Jeong g_assert_cmpuint(rsp_upiu.qr.data[1], ==, UFS_QUERY_DESC_IDN_DEVICE);
9339fe8e2c6SYoochan Jeong
9349fe8e2c6SYoochan Jeong /* Read Configuration Descriptor is not supported yet*/
9359fe8e2c6SYoochan Jeong
9369fe8e2c6SYoochan Jeong /* Read Unit Descriptor */
9375cb3566aSJeuk Kim ocs = ufs_send_query(ufs, UFS_UPIU_QUERY_FUNC_STANDARD_READ_REQUEST,
9385cb3566aSJeuk Kim UFS_UPIU_QUERY_OPCODE_READ_DESC,
9395cb3566aSJeuk Kim UFS_QUERY_DESC_IDN_UNIT, 0, 0, 0, &rsp_upiu);
9405cb3566aSJeuk Kim g_assert_cmpuint(ocs, ==, UFS_OCS_SUCCESS);
9419fe8e2c6SYoochan Jeong g_assert_cmpuint(rsp_upiu.header.response, ==, UFS_COMMAND_RESULT_SUCCESS);
9429fe8e2c6SYoochan Jeong g_assert_cmpuint(rsp_upiu.qr.data[0], ==, sizeof(UnitDescriptor));
9439fe8e2c6SYoochan Jeong g_assert_cmpuint(rsp_upiu.qr.data[1], ==, UFS_QUERY_DESC_IDN_UNIT);
9449fe8e2c6SYoochan Jeong g_assert_cmpuint(rsp_upiu.qr.data[2], ==, 0);
9459fe8e2c6SYoochan Jeong
9465cb3566aSJeuk Kim ocs = ufs_send_query(ufs, UFS_UPIU_QUERY_FUNC_STANDARD_READ_REQUEST,
9475cb3566aSJeuk Kim UFS_UPIU_QUERY_OPCODE_READ_DESC,
9485cb3566aSJeuk Kim UFS_QUERY_DESC_IDN_UNIT, 1, 0, 0, &rsp_upiu);
9495cb3566aSJeuk Kim g_assert_cmpuint(ocs, ==, UFS_OCS_SUCCESS);
9509fe8e2c6SYoochan Jeong g_assert_cmpuint(rsp_upiu.header.response, ==, UFS_COMMAND_RESULT_SUCCESS);
9519fe8e2c6SYoochan Jeong g_assert_cmpuint(rsp_upiu.qr.data[0], ==, sizeof(UnitDescriptor));
9529fe8e2c6SYoochan Jeong g_assert_cmpuint(rsp_upiu.qr.data[1], ==, UFS_QUERY_DESC_IDN_UNIT);
9539fe8e2c6SYoochan Jeong g_assert_cmpuint(rsp_upiu.qr.data[2], ==, 1);
9549fe8e2c6SYoochan Jeong
9555cb3566aSJeuk Kim ocs =
9565cb3566aSJeuk Kim ufs_send_query(ufs, UFS_UPIU_QUERY_FUNC_STANDARD_READ_REQUEST,
9579fe8e2c6SYoochan Jeong UFS_UPIU_QUERY_OPCODE_READ_DESC, UFS_QUERY_DESC_IDN_UNIT,
9585cb3566aSJeuk Kim UFS_UPIU_RPMB_WLUN, 0, 0, &rsp_upiu);
9595cb3566aSJeuk Kim g_assert_cmpuint(ocs, ==, UFS_OCS_SUCCESS);
9609fe8e2c6SYoochan Jeong g_assert_cmpuint(rsp_upiu.header.response, ==, UFS_COMMAND_RESULT_SUCCESS);
9619fe8e2c6SYoochan Jeong g_assert_cmpuint(rsp_upiu.qr.data[0], ==, sizeof(RpmbUnitDescriptor));
9629fe8e2c6SYoochan Jeong g_assert_cmpuint(rsp_upiu.qr.data[1], ==, UFS_QUERY_DESC_IDN_UNIT);
9639fe8e2c6SYoochan Jeong g_assert_cmpuint(rsp_upiu.qr.data[2], ==, UFS_UPIU_RPMB_WLUN);
9649fe8e2c6SYoochan Jeong
9659fe8e2c6SYoochan Jeong /* Read Interconnect Descriptor */
9665cb3566aSJeuk Kim ocs = ufs_send_query(ufs, UFS_UPIU_QUERY_FUNC_STANDARD_READ_REQUEST,
9679fe8e2c6SYoochan Jeong UFS_UPIU_QUERY_OPCODE_READ_DESC,
9685cb3566aSJeuk Kim UFS_QUERY_DESC_IDN_INTERCONNECT, 0, 0, 0, &rsp_upiu);
9695cb3566aSJeuk Kim g_assert_cmpuint(ocs, ==, UFS_OCS_SUCCESS);
9709fe8e2c6SYoochan Jeong g_assert_cmpuint(rsp_upiu.header.response, ==, UFS_COMMAND_RESULT_SUCCESS);
9719fe8e2c6SYoochan Jeong g_assert_cmpuint(rsp_upiu.qr.data[0], ==, sizeof(InterconnectDescriptor));
9729fe8e2c6SYoochan Jeong g_assert_cmpuint(rsp_upiu.qr.data[1], ==, UFS_QUERY_DESC_IDN_INTERCONNECT);
9739fe8e2c6SYoochan Jeong
9749fe8e2c6SYoochan Jeong /* Read String Descriptor */
9755cb3566aSJeuk Kim ocs = ufs_send_query(ufs, UFS_UPIU_QUERY_FUNC_STANDARD_READ_REQUEST,
9765cb3566aSJeuk Kim UFS_UPIU_QUERY_OPCODE_READ_DESC,
9775cb3566aSJeuk Kim UFS_QUERY_DESC_IDN_STRING, 0, 0, 0, &rsp_upiu);
9785cb3566aSJeuk Kim g_assert_cmpuint(ocs, ==, UFS_OCS_SUCCESS);
9799fe8e2c6SYoochan Jeong g_assert_cmpuint(rsp_upiu.header.response, ==, UFS_COMMAND_RESULT_SUCCESS);
9809fe8e2c6SYoochan Jeong g_assert_cmpuint(rsp_upiu.qr.data[0], ==, 0x12);
9819fe8e2c6SYoochan Jeong g_assert_cmpuint(rsp_upiu.qr.data[1], ==, UFS_QUERY_DESC_IDN_STRING);
9829fe8e2c6SYoochan Jeong
9835cb3566aSJeuk Kim ocs = ufs_send_query(ufs, UFS_UPIU_QUERY_FUNC_STANDARD_READ_REQUEST,
9845cb3566aSJeuk Kim UFS_UPIU_QUERY_OPCODE_READ_DESC,
9855cb3566aSJeuk Kim UFS_QUERY_DESC_IDN_STRING, 1, 0, 0, &rsp_upiu);
9865cb3566aSJeuk Kim g_assert_cmpuint(ocs, ==, UFS_OCS_SUCCESS);
9879fe8e2c6SYoochan Jeong g_assert_cmpuint(rsp_upiu.header.response, ==, UFS_COMMAND_RESULT_SUCCESS);
9889fe8e2c6SYoochan Jeong g_assert_cmpuint(rsp_upiu.qr.data[0], ==, 0x22);
9899fe8e2c6SYoochan Jeong g_assert_cmpuint(rsp_upiu.qr.data[1], ==, UFS_QUERY_DESC_IDN_STRING);
9909fe8e2c6SYoochan Jeong
9915cb3566aSJeuk Kim ocs = ufs_send_query(ufs, UFS_UPIU_QUERY_FUNC_STANDARD_READ_REQUEST,
9925cb3566aSJeuk Kim UFS_UPIU_QUERY_OPCODE_READ_DESC,
9935cb3566aSJeuk Kim UFS_QUERY_DESC_IDN_STRING, 4, 0, 0, &rsp_upiu);
9945cb3566aSJeuk Kim g_assert_cmpuint(ocs, ==, UFS_OCS_SUCCESS);
9959fe8e2c6SYoochan Jeong g_assert_cmpuint(rsp_upiu.header.response, ==, UFS_COMMAND_RESULT_SUCCESS);
9969fe8e2c6SYoochan Jeong g_assert_cmpuint(rsp_upiu.qr.data[0], ==, 0x0a);
9979fe8e2c6SYoochan Jeong g_assert_cmpuint(rsp_upiu.qr.data[1], ==, UFS_QUERY_DESC_IDN_STRING);
9989fe8e2c6SYoochan Jeong
9999fe8e2c6SYoochan Jeong /* Read Geometry Descriptor */
10005cb3566aSJeuk Kim ocs = ufs_send_query(ufs, UFS_UPIU_QUERY_FUNC_STANDARD_READ_REQUEST,
10015cb3566aSJeuk Kim UFS_UPIU_QUERY_OPCODE_READ_DESC,
10025cb3566aSJeuk Kim UFS_QUERY_DESC_IDN_GEOMETRY, 0, 0, 0, &rsp_upiu);
10035cb3566aSJeuk Kim g_assert_cmpuint(ocs, ==, UFS_OCS_SUCCESS);
10049fe8e2c6SYoochan Jeong g_assert_cmpuint(rsp_upiu.header.response, ==, UFS_COMMAND_RESULT_SUCCESS);
10059fe8e2c6SYoochan Jeong g_assert_cmpuint(rsp_upiu.qr.data[0], ==, sizeof(GeometryDescriptor));
10069fe8e2c6SYoochan Jeong g_assert_cmpuint(rsp_upiu.qr.data[1], ==, UFS_QUERY_DESC_IDN_GEOMETRY);
10079fe8e2c6SYoochan Jeong
10089fe8e2c6SYoochan Jeong /* Read Power Descriptor */
10095cb3566aSJeuk Kim ocs = ufs_send_query(ufs, UFS_UPIU_QUERY_FUNC_STANDARD_READ_REQUEST,
10105cb3566aSJeuk Kim UFS_UPIU_QUERY_OPCODE_READ_DESC,
10115cb3566aSJeuk Kim UFS_QUERY_DESC_IDN_POWER, 0, 0, 0, &rsp_upiu);
10125cb3566aSJeuk Kim g_assert_cmpuint(ocs, ==, UFS_OCS_SUCCESS);
10139fe8e2c6SYoochan Jeong g_assert_cmpuint(rsp_upiu.header.response, ==, UFS_COMMAND_RESULT_SUCCESS);
10149fe8e2c6SYoochan Jeong g_assert_cmpuint(rsp_upiu.qr.data[0], ==,
10159fe8e2c6SYoochan Jeong sizeof(PowerParametersDescriptor));
10169fe8e2c6SYoochan Jeong g_assert_cmpuint(rsp_upiu.qr.data[1], ==, UFS_QUERY_DESC_IDN_POWER);
10179fe8e2c6SYoochan Jeong
10189fe8e2c6SYoochan Jeong /* Read Health Descriptor */
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_HEALTH, 0, 0, 0, &rsp_upiu);
10225cb3566aSJeuk Kim g_assert_cmpuint(ocs, ==, UFS_OCS_SUCCESS);
10239fe8e2c6SYoochan Jeong g_assert_cmpuint(rsp_upiu.header.response, ==, UFS_COMMAND_RESULT_SUCCESS);
10249fe8e2c6SYoochan Jeong g_assert_cmpuint(rsp_upiu.qr.data[0], ==, sizeof(DeviceHealthDescriptor));
10259fe8e2c6SYoochan Jeong g_assert_cmpuint(rsp_upiu.qr.data[1], ==, UFS_QUERY_DESC_IDN_HEALTH);
10269fe8e2c6SYoochan Jeong
10279fe8e2c6SYoochan Jeong /* Invalid Index (Intended Failure) */
10285cb3566aSJeuk Kim ocs = ufs_send_query(ufs, UFS_UPIU_QUERY_FUNC_STANDARD_READ_REQUEST,
10295cb3566aSJeuk Kim UFS_UPIU_QUERY_OPCODE_READ_DESC,
10305cb3566aSJeuk Kim UFS_QUERY_DESC_IDN_UNIT, 4, 0, 0, &rsp_upiu);
10315cb3566aSJeuk Kim g_assert_cmpuint(ocs, ==, UFS_OCS_INVALID_CMD_TABLE_ATTR);
10329fe8e2c6SYoochan Jeong g_assert_cmpuint(rsp_upiu.header.response, ==,
10339fe8e2c6SYoochan Jeong UFS_QUERY_RESULT_INVALID_INDEX);
10349fe8e2c6SYoochan Jeong
10355cb3566aSJeuk Kim ocs = ufs_send_query(ufs, UFS_UPIU_QUERY_FUNC_STANDARD_READ_REQUEST,
10365cb3566aSJeuk Kim UFS_UPIU_QUERY_OPCODE_READ_DESC,
10375cb3566aSJeuk Kim UFS_QUERY_DESC_IDN_STRING, 5, 0, 0, &rsp_upiu);
10385cb3566aSJeuk Kim g_assert_cmpuint(ocs, ==, UFS_OCS_INVALID_CMD_TABLE_ATTR);
10399fe8e2c6SYoochan Jeong g_assert_cmpuint(rsp_upiu.header.response, ==,
10409fe8e2c6SYoochan Jeong UFS_QUERY_RESULT_INVALID_INDEX);
10419fe8e2c6SYoochan Jeong
10429fe8e2c6SYoochan Jeong /* Invalid Selector (Intended Failure) */
10435cb3566aSJeuk Kim ocs = ufs_send_query(ufs, UFS_UPIU_QUERY_FUNC_STANDARD_READ_REQUEST,
10445cb3566aSJeuk Kim UFS_UPIU_QUERY_OPCODE_READ_DESC,
10455cb3566aSJeuk Kim UFS_QUERY_DESC_IDN_DEVICE, 0, 1, 0, &rsp_upiu);
10465cb3566aSJeuk Kim g_assert_cmpuint(ocs, ==, UFS_OCS_INVALID_CMD_TABLE_ATTR);
10479fe8e2c6SYoochan Jeong g_assert_cmpuint(rsp_upiu.header.response, ==,
10489fe8e2c6SYoochan Jeong UFS_QUERY_RESULT_INVALID_SELECTOR);
10499fe8e2c6SYoochan Jeong
10505cb3566aSJeuk Kim ocs = ufs_send_query(ufs, UFS_UPIU_QUERY_FUNC_STANDARD_READ_REQUEST,
10515cb3566aSJeuk Kim UFS_UPIU_QUERY_OPCODE_READ_DESC,
10525cb3566aSJeuk Kim UFS_QUERY_DESC_IDN_STRING, 0, 1, 0, &rsp_upiu);
10535cb3566aSJeuk Kim g_assert_cmpuint(ocs, ==, UFS_OCS_INVALID_CMD_TABLE_ATTR);
10549fe8e2c6SYoochan Jeong g_assert_cmpuint(rsp_upiu.header.response, ==,
10559fe8e2c6SYoochan Jeong UFS_QUERY_RESULT_INVALID_SELECTOR);
10569fe8e2c6SYoochan Jeong
10579fe8e2c6SYoochan Jeong ufs_exit(ufs, alloc);
10589fe8e2c6SYoochan Jeong }
10599fe8e2c6SYoochan Jeong
drive_destroy(void * path)1060631c8726SJeuk Kim static void drive_destroy(void *path)
1061631c8726SJeuk Kim {
1062631c8726SJeuk Kim unlink(path);
1063631c8726SJeuk Kim g_free(path);
1064631c8726SJeuk Kim qos_invalidate_command_line();
1065631c8726SJeuk Kim }
1066631c8726SJeuk Kim
drive_create(void)1067631c8726SJeuk Kim static char *drive_create(void)
1068631c8726SJeuk Kim {
1069631c8726SJeuk Kim int fd, ret;
1070631c8726SJeuk Kim char *t_path;
1071631c8726SJeuk Kim
1072631c8726SJeuk Kim /* Create a temporary raw image */
1073631c8726SJeuk Kim fd = g_file_open_tmp("qtest-ufs.XXXXXX", &t_path, NULL);
1074631c8726SJeuk Kim g_assert_cmpint(fd, >=, 0);
1075631c8726SJeuk Kim ret = ftruncate(fd, TEST_IMAGE_SIZE);
1076631c8726SJeuk Kim g_assert_cmpint(ret, ==, 0);
1077631c8726SJeuk Kim close(fd);
1078631c8726SJeuk Kim
1079631c8726SJeuk Kim g_test_queue_destroy(drive_destroy, t_path);
1080631c8726SJeuk Kim return t_path;
1081631c8726SJeuk Kim }
1082631c8726SJeuk Kim
ufs_blk_test_setup(GString * cmd_line,void * arg)1083631c8726SJeuk Kim static void *ufs_blk_test_setup(GString *cmd_line, void *arg)
1084631c8726SJeuk Kim {
1085631c8726SJeuk Kim char *tmp_path = drive_create();
1086631c8726SJeuk Kim
1087631c8726SJeuk Kim g_string_append_printf(cmd_line,
1088631c8726SJeuk Kim " -blockdev file,filename=%s,node-name=drv1 "
1089631c8726SJeuk Kim "-device ufs-lu,bus=ufs0,drive=drv1,lun=1 ",
1090631c8726SJeuk Kim tmp_path);
1091631c8726SJeuk Kim
1092631c8726SJeuk Kim return arg;
1093631c8726SJeuk Kim }
1094631c8726SJeuk Kim
ufs_register_nodes(void)1095631c8726SJeuk Kim static void ufs_register_nodes(void)
1096631c8726SJeuk Kim {
1097631c8726SJeuk Kim const char *arch;
1098631c8726SJeuk Kim QOSGraphEdgeOptions edge_opts = {
1099631c8726SJeuk Kim .before_cmd_line = "-blockdev null-co,node-name=drv0,read-zeroes=on",
1100631c8726SJeuk Kim .after_cmd_line = "-device ufs-lu,bus=ufs0,drive=drv0,lun=0",
1101a54596a9SJeuk Kim .extra_device_opts = "addr=04.0,id=ufs0"
1102631c8726SJeuk Kim };
1103631c8726SJeuk Kim
1104a54596a9SJeuk Kim QOSGraphTestOptions io_test_opts = { .before = ufs_blk_test_setup,
1105a54596a9SJeuk Kim .edge.extra_device_opts =
1106a54596a9SJeuk Kim "mcq=false,nutrs=32,nutmrs=8" };
1107a54596a9SJeuk Kim
1108a54596a9SJeuk Kim QOSGraphTestOptions mcq_test_opts = { .before = ufs_blk_test_setup,
1109a54596a9SJeuk Kim .edge.extra_device_opts =
1110a54596a9SJeuk Kim "mcq=true,mcq-maxq=1" };
1111631c8726SJeuk Kim
1112631c8726SJeuk Kim add_qpci_address(&edge_opts, &(QPCIAddress){ .devfn = QPCI_DEVFN(4, 0) });
1113631c8726SJeuk Kim
1114631c8726SJeuk Kim qos_node_create_driver("ufs", ufs_create);
1115631c8726SJeuk Kim qos_node_consumes("ufs", "pci-bus", &edge_opts);
1116631c8726SJeuk Kim qos_node_produces("ufs", "pci-device");
1117631c8726SJeuk Kim
1118631c8726SJeuk Kim qos_add_test("reg-read", "ufs", ufstest_reg_read, NULL);
1119631c8726SJeuk Kim
1120631c8726SJeuk Kim /*
1121631c8726SJeuk Kim * Check architecture
1122631c8726SJeuk Kim * TODO: Enable ufs io tests for ppc64
1123631c8726SJeuk Kim */
1124631c8726SJeuk Kim arch = qtest_get_arch();
1125631c8726SJeuk Kim if (!strcmp(arch, "ppc64")) {
1126631c8726SJeuk Kim g_test_message("Skipping ufs io tests for ppc64");
1127631c8726SJeuk Kim return;
1128631c8726SJeuk Kim }
1129631c8726SJeuk Kim qos_add_test("init", "ufs", ufstest_init, NULL);
1130a54596a9SJeuk Kim qos_add_test("legacy-read-write", "ufs", ufstest_read_write, &io_test_opts);
1131a54596a9SJeuk Kim qos_add_test("mcq-read-write", "ufs", ufstest_read_write, &mcq_test_opts);
1132a54596a9SJeuk Kim qos_add_test("query-flag", "ufs", ufstest_query_flag_request,
1133a54596a9SJeuk Kim &io_test_opts);
1134a54596a9SJeuk Kim qos_add_test("query-attribute", "ufs", ufstest_query_attr_request,
1135a54596a9SJeuk Kim &io_test_opts);
1136a54596a9SJeuk Kim qos_add_test("query-desciptor", "ufs", ufstest_query_desc_request,
1137a54596a9SJeuk Kim &io_test_opts);
1138631c8726SJeuk Kim }
1139631c8726SJeuk Kim
1140631c8726SJeuk Kim libqos_init(ufs_register_nodes);
1141