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