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 "qemu/units.h"
12631c8726SJeuk Kim #include "libqtest.h"
13631c8726SJeuk Kim #include "libqos/qgraph.h"
14631c8726SJeuk Kim #include "libqos/pci.h"
15631c8726SJeuk Kim #include "scsi/constants.h"
168b4d80bbSPhilippe Mathieu-Daudé #include "block/ufs.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
29631c8726SJeuk Kim
30631c8726SJeuk Kim typedef struct QUfs QUfs;
31631c8726SJeuk Kim
32631c8726SJeuk Kim struct QUfs {
33631c8726SJeuk Kim QOSGraphObject obj;
34631c8726SJeuk Kim QPCIDevice dev;
35631c8726SJeuk Kim QPCIBar bar;
36631c8726SJeuk Kim
37631c8726SJeuk Kim uint64_t utrlba;
38631c8726SJeuk Kim uint64_t utmrlba;
39631c8726SJeuk Kim uint64_t cmd_desc_addr;
40631c8726SJeuk Kim uint64_t data_buffer_addr;
41631c8726SJeuk Kim
42631c8726SJeuk Kim bool enabled;
43631c8726SJeuk Kim };
44631c8726SJeuk Kim
ufs_rreg(QUfs * ufs,size_t offset)45631c8726SJeuk Kim static inline uint32_t ufs_rreg(QUfs *ufs, size_t offset)
46631c8726SJeuk Kim {
47631c8726SJeuk Kim return qpci_io_readl(&ufs->dev, ufs->bar, offset);
48631c8726SJeuk Kim }
49631c8726SJeuk Kim
ufs_wreg(QUfs * ufs,size_t offset,uint32_t value)50631c8726SJeuk Kim static inline void ufs_wreg(QUfs *ufs, size_t offset, uint32_t value)
51631c8726SJeuk Kim {
52631c8726SJeuk Kim qpci_io_writel(&ufs->dev, ufs->bar, offset, value);
53631c8726SJeuk Kim }
54631c8726SJeuk Kim
ufs_wait_for_irq(QUfs * ufs)55631c8726SJeuk Kim static void ufs_wait_for_irq(QUfs *ufs)
56631c8726SJeuk Kim {
57631c8726SJeuk Kim uint64_t end_time;
58631c8726SJeuk Kim uint32_t is;
59631c8726SJeuk Kim /* Wait for device to reset as the linux driver does. */
60631c8726SJeuk Kim end_time = g_get_monotonic_time() + TIMEOUT_SECONDS * G_TIME_SPAN_SECOND;
61631c8726SJeuk Kim do {
62631c8726SJeuk Kim qtest_clock_step(ufs->dev.bus->qts, 100);
63631c8726SJeuk Kim is = ufs_rreg(ufs, A_IS);
64631c8726SJeuk Kim } while (is == 0 && g_get_monotonic_time() < end_time);
65631c8726SJeuk Kim }
66631c8726SJeuk Kim
ufs_build_req_utrd(uint64_t cmd_desc_addr,uint8_t slot,uint32_t data_direction,uint16_t prd_table_length)67631c8726SJeuk Kim static UtpTransferReqDesc ufs_build_req_utrd(uint64_t cmd_desc_addr,
68631c8726SJeuk Kim uint8_t slot,
69631c8726SJeuk Kim uint32_t data_direction,
70631c8726SJeuk Kim uint16_t prd_table_length)
71631c8726SJeuk Kim {
72631c8726SJeuk Kim UtpTransferReqDesc req = { 0 };
73631c8726SJeuk Kim uint64_t command_desc_base_addr =
74631c8726SJeuk Kim cmd_desc_addr + slot * UTP_COMMAND_DESCRIPTOR_SIZE;
75631c8726SJeuk Kim
76631c8726SJeuk Kim req.header.dword_0 =
77631c8726SJeuk Kim cpu_to_le32(1 << 28 | data_direction | UFS_UTP_REQ_DESC_INT_CMD);
78631c8726SJeuk Kim req.header.dword_2 = cpu_to_le32(UFS_OCS_INVALID_COMMAND_STATUS);
79631c8726SJeuk Kim
80631c8726SJeuk Kim req.command_desc_base_addr_hi = cpu_to_le32(command_desc_base_addr >> 32);
81631c8726SJeuk Kim req.command_desc_base_addr_lo =
82631c8726SJeuk Kim cpu_to_le32(command_desc_base_addr & 0xffffffff);
83631c8726SJeuk Kim req.response_upiu_offset =
84631c8726SJeuk Kim cpu_to_le16(UTP_RESPONSE_UPIU_OFFSET / sizeof(uint32_t));
85631c8726SJeuk Kim req.response_upiu_length = cpu_to_le16(sizeof(UtpUpiuRsp));
86631c8726SJeuk Kim req.prd_table_offset = cpu_to_le16(UTP_PRDT_UPIU_OFFSET / sizeof(uint32_t));
87631c8726SJeuk Kim req.prd_table_length = cpu_to_le16(prd_table_length);
88631c8726SJeuk Kim return req;
89631c8726SJeuk Kim }
90631c8726SJeuk Kim
ufs_send_nop_out(QUfs * ufs,uint8_t slot,UtpTransferReqDesc * utrd_out,UtpUpiuRsp * rsp_out)91631c8726SJeuk Kim static void ufs_send_nop_out(QUfs *ufs, uint8_t slot,
92631c8726SJeuk Kim UtpTransferReqDesc *utrd_out, UtpUpiuRsp *rsp_out)
93631c8726SJeuk Kim {
94631c8726SJeuk Kim /* Build up utp transfer request descriptor */
95631c8726SJeuk Kim UtpTransferReqDesc utrd = ufs_build_req_utrd(ufs->cmd_desc_addr, slot,
96631c8726SJeuk Kim UFS_UTP_NO_DATA_TRANSFER, 0);
97631c8726SJeuk Kim uint64_t utrd_addr = ufs->utrlba + slot * sizeof(UtpTransferReqDesc);
98631c8726SJeuk Kim uint64_t req_upiu_addr =
99631c8726SJeuk Kim ufs->cmd_desc_addr + slot * UTP_COMMAND_DESCRIPTOR_SIZE;
100631c8726SJeuk Kim uint64_t rsp_upiu_addr = req_upiu_addr + UTP_RESPONSE_UPIU_OFFSET;
101631c8726SJeuk Kim qtest_memwrite(ufs->dev.bus->qts, utrd_addr, &utrd, sizeof(utrd));
102631c8726SJeuk Kim
103631c8726SJeuk Kim /* Build up request upiu */
104631c8726SJeuk Kim UtpUpiuReq req_upiu = { 0 };
105631c8726SJeuk Kim req_upiu.header.trans_type = UFS_UPIU_TRANSACTION_NOP_OUT;
106631c8726SJeuk Kim req_upiu.header.task_tag = slot;
107631c8726SJeuk Kim qtest_memwrite(ufs->dev.bus->qts, req_upiu_addr, &req_upiu,
108631c8726SJeuk Kim sizeof(req_upiu));
109631c8726SJeuk Kim
110631c8726SJeuk Kim /* Ring Doorbell */
111631c8726SJeuk Kim ufs_wreg(ufs, A_UTRLDBR, 1);
112631c8726SJeuk Kim ufs_wait_for_irq(ufs);
113631c8726SJeuk Kim g_assert_true(FIELD_EX32(ufs_rreg(ufs, A_IS), IS, UTRCS));
114631c8726SJeuk Kim ufs_wreg(ufs, A_IS, FIELD_DP32(0, IS, UTRCS, 1));
115631c8726SJeuk Kim
116631c8726SJeuk Kim qtest_memread(ufs->dev.bus->qts, utrd_addr, utrd_out, sizeof(*utrd_out));
117631c8726SJeuk Kim qtest_memread(ufs->dev.bus->qts, rsp_upiu_addr, rsp_out, sizeof(*rsp_out));
118631c8726SJeuk Kim }
119631c8726SJeuk Kim
ufs_send_query(QUfs * ufs,uint8_t slot,uint8_t query_function,uint8_t query_opcode,uint8_t idn,uint8_t index,uint8_t selector,uint32_t attr_value,UtpTransferReqDesc * utrd_out,UtpUpiuRsp * rsp_out)120631c8726SJeuk Kim static void ufs_send_query(QUfs *ufs, uint8_t slot, uint8_t query_function,
121631c8726SJeuk Kim uint8_t query_opcode, uint8_t idn, uint8_t index,
1227c85332aSYoochan Jeong uint8_t selector, uint32_t attr_value,
123631c8726SJeuk Kim UtpTransferReqDesc *utrd_out, UtpUpiuRsp *rsp_out)
124631c8726SJeuk Kim {
125631c8726SJeuk Kim /* Build up utp transfer request descriptor */
126631c8726SJeuk Kim UtpTransferReqDesc utrd = ufs_build_req_utrd(ufs->cmd_desc_addr, slot,
127631c8726SJeuk Kim UFS_UTP_NO_DATA_TRANSFER, 0);
128631c8726SJeuk Kim uint64_t utrd_addr = ufs->utrlba + slot * sizeof(UtpTransferReqDesc);
129631c8726SJeuk Kim uint64_t req_upiu_addr =
130631c8726SJeuk Kim ufs->cmd_desc_addr + slot * UTP_COMMAND_DESCRIPTOR_SIZE;
131631c8726SJeuk Kim uint64_t rsp_upiu_addr = req_upiu_addr + UTP_RESPONSE_UPIU_OFFSET;
132631c8726SJeuk Kim qtest_memwrite(ufs->dev.bus->qts, utrd_addr, &utrd, sizeof(utrd));
133631c8726SJeuk Kim
134631c8726SJeuk Kim /* Build up request upiu */
135631c8726SJeuk Kim UtpUpiuReq req_upiu = { 0 };
136631c8726SJeuk Kim req_upiu.header.trans_type = UFS_UPIU_TRANSACTION_QUERY_REQ;
137631c8726SJeuk Kim req_upiu.header.query_func = query_function;
138631c8726SJeuk Kim req_upiu.header.task_tag = slot;
139631c8726SJeuk Kim /*
1407c85332aSYoochan Jeong * QEMU UFS does not currently support Write descriptor,
141631c8726SJeuk Kim * so the value of data_segment_length is always 0.
142631c8726SJeuk Kim */
143631c8726SJeuk Kim req_upiu.header.data_segment_length = 0;
144631c8726SJeuk Kim req_upiu.qr.opcode = query_opcode;
145631c8726SJeuk Kim req_upiu.qr.idn = idn;
146631c8726SJeuk Kim req_upiu.qr.index = index;
1477c85332aSYoochan Jeong req_upiu.qr.selector = selector;
148*48876bfcSKeoseong Park req_upiu.qr.value = cpu_to_be32(attr_value);
1497c85332aSYoochan Jeong req_upiu.qr.length = UFS_QUERY_DESC_MAX_SIZE;
150631c8726SJeuk Kim qtest_memwrite(ufs->dev.bus->qts, req_upiu_addr, &req_upiu,
151631c8726SJeuk Kim sizeof(req_upiu));
152631c8726SJeuk Kim
153631c8726SJeuk Kim /* Ring Doorbell */
154631c8726SJeuk Kim ufs_wreg(ufs, A_UTRLDBR, 1);
155631c8726SJeuk Kim ufs_wait_for_irq(ufs);
156631c8726SJeuk Kim g_assert_true(FIELD_EX32(ufs_rreg(ufs, A_IS), IS, UTRCS));
157631c8726SJeuk Kim ufs_wreg(ufs, A_IS, FIELD_DP32(0, IS, UTRCS, 1));
158631c8726SJeuk Kim
159631c8726SJeuk Kim qtest_memread(ufs->dev.bus->qts, utrd_addr, utrd_out, sizeof(*utrd_out));
160631c8726SJeuk Kim qtest_memread(ufs->dev.bus->qts, rsp_upiu_addr, rsp_out, sizeof(*rsp_out));
161631c8726SJeuk Kim }
162631c8726SJeuk Kim
ufs_send_scsi_command(QUfs * ufs,uint8_t slot,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,UtpTransferReqDesc * utrd_out,UtpUpiuRsp * rsp_out)163631c8726SJeuk Kim static void ufs_send_scsi_command(QUfs *ufs, uint8_t slot, uint8_t lun,
164631c8726SJeuk Kim const uint8_t *cdb, const uint8_t *data_in,
165631c8726SJeuk Kim size_t data_in_len, uint8_t *data_out,
166631c8726SJeuk Kim size_t data_out_len,
167631c8726SJeuk Kim UtpTransferReqDesc *utrd_out,
168631c8726SJeuk Kim UtpUpiuRsp *rsp_out)
169631c8726SJeuk Kim
170631c8726SJeuk Kim {
171631c8726SJeuk Kim /* Build up PRDT */
172631c8726SJeuk Kim UfshcdSgEntry entries[MAX_PRD_ENTRY_COUNT] = {
173631c8726SJeuk Kim 0,
174631c8726SJeuk Kim };
175631c8726SJeuk Kim uint8_t flags;
176631c8726SJeuk Kim uint16_t prd_table_length, i;
177631c8726SJeuk Kim uint32_t data_direction, data_len;
178631c8726SJeuk Kim uint64_t req_upiu_addr =
179631c8726SJeuk Kim ufs->cmd_desc_addr + slot * UTP_COMMAND_DESCRIPTOR_SIZE;
180631c8726SJeuk Kim uint64_t prdt_addr = req_upiu_addr + UTP_PRDT_UPIU_OFFSET;
181631c8726SJeuk Kim
182631c8726SJeuk Kim g_assert_true(data_in_len < MAX_PRD_ENTRY_COUNT * PRD_ENTRY_DATA_SIZE);
183631c8726SJeuk Kim g_assert_true(data_out_len < MAX_PRD_ENTRY_COUNT * PRD_ENTRY_DATA_SIZE);
184631c8726SJeuk Kim if (data_in_len > 0) {
185631c8726SJeuk Kim g_assert_nonnull(data_in);
186631c8726SJeuk Kim data_direction = UFS_UTP_HOST_TO_DEVICE;
187631c8726SJeuk Kim data_len = data_in_len;
188631c8726SJeuk Kim flags = UFS_UPIU_CMD_FLAGS_WRITE;
189631c8726SJeuk Kim } else if (data_out_len > 0) {
190631c8726SJeuk Kim g_assert_nonnull(data_out);
191631c8726SJeuk Kim data_direction = UFS_UTP_DEVICE_TO_HOST;
192631c8726SJeuk Kim data_len = data_out_len;
193631c8726SJeuk Kim flags = UFS_UPIU_CMD_FLAGS_READ;
194631c8726SJeuk Kim } else {
195631c8726SJeuk Kim data_direction = UFS_UTP_NO_DATA_TRANSFER;
196631c8726SJeuk Kim data_len = 0;
197631c8726SJeuk Kim flags = UFS_UPIU_CMD_FLAGS_NONE;
198631c8726SJeuk Kim }
199631c8726SJeuk Kim prd_table_length = DIV_ROUND_UP(data_len, PRD_ENTRY_DATA_SIZE);
200631c8726SJeuk Kim
201631c8726SJeuk Kim qtest_memset(ufs->dev.bus->qts, ufs->data_buffer_addr, 0,
202631c8726SJeuk Kim MAX_PRD_ENTRY_COUNT * PRD_ENTRY_DATA_SIZE);
203631c8726SJeuk Kim if (data_in_len) {
204631c8726SJeuk Kim qtest_memwrite(ufs->dev.bus->qts, ufs->data_buffer_addr, data_in,
205631c8726SJeuk Kim data_in_len);
206631c8726SJeuk Kim }
207631c8726SJeuk Kim
208631c8726SJeuk Kim for (i = 0; i < prd_table_length; i++) {
209631c8726SJeuk Kim entries[i].addr =
210631c8726SJeuk Kim cpu_to_le64(ufs->data_buffer_addr + i * sizeof(UfshcdSgEntry));
211631c8726SJeuk Kim if (i + 1 != prd_table_length) {
212631c8726SJeuk Kim entries[i].size = cpu_to_le32(PRD_ENTRY_DATA_SIZE - 1);
213631c8726SJeuk Kim } else {
214631c8726SJeuk Kim entries[i].size = cpu_to_le32(
215631c8726SJeuk Kim data_len - (PRD_ENTRY_DATA_SIZE * (prd_table_length - 1)) - 1);
216631c8726SJeuk Kim }
217631c8726SJeuk Kim }
218631c8726SJeuk Kim qtest_memwrite(ufs->dev.bus->qts, prdt_addr, entries,
219631c8726SJeuk Kim prd_table_length * sizeof(UfshcdSgEntry));
220631c8726SJeuk Kim
221631c8726SJeuk Kim /* Build up utp transfer request descriptor */
222631c8726SJeuk Kim UtpTransferReqDesc utrd = ufs_build_req_utrd(
223631c8726SJeuk Kim ufs->cmd_desc_addr, slot, data_direction, prd_table_length);
224631c8726SJeuk Kim uint64_t utrd_addr = ufs->utrlba + slot * sizeof(UtpTransferReqDesc);
225631c8726SJeuk Kim uint64_t rsp_upiu_addr = req_upiu_addr + UTP_RESPONSE_UPIU_OFFSET;
226631c8726SJeuk Kim qtest_memwrite(ufs->dev.bus->qts, utrd_addr, &utrd, sizeof(utrd));
227631c8726SJeuk Kim
228631c8726SJeuk Kim /* Build up request upiu */
229631c8726SJeuk Kim UtpUpiuReq req_upiu = { 0 };
230631c8726SJeuk Kim req_upiu.header.trans_type = UFS_UPIU_TRANSACTION_COMMAND;
231631c8726SJeuk Kim req_upiu.header.flags = flags;
232631c8726SJeuk Kim req_upiu.header.lun = lun;
233631c8726SJeuk Kim req_upiu.header.task_tag = slot;
234631c8726SJeuk Kim req_upiu.sc.exp_data_transfer_len = cpu_to_be32(data_len);
235631c8726SJeuk Kim memcpy(req_upiu.sc.cdb, cdb, UFS_CDB_SIZE);
236631c8726SJeuk Kim qtest_memwrite(ufs->dev.bus->qts, req_upiu_addr, &req_upiu,
237631c8726SJeuk Kim sizeof(req_upiu));
238631c8726SJeuk Kim
239631c8726SJeuk Kim /* Ring Doorbell */
240631c8726SJeuk Kim ufs_wreg(ufs, A_UTRLDBR, 1);
241631c8726SJeuk Kim ufs_wait_for_irq(ufs);
242631c8726SJeuk Kim g_assert_true(FIELD_EX32(ufs_rreg(ufs, A_IS), IS, UTRCS));
243631c8726SJeuk Kim ufs_wreg(ufs, A_IS, FIELD_DP32(0, IS, UTRCS, 1));
244631c8726SJeuk Kim
245631c8726SJeuk Kim qtest_memread(ufs->dev.bus->qts, utrd_addr, utrd_out, sizeof(*utrd_out));
246631c8726SJeuk Kim qtest_memread(ufs->dev.bus->qts, rsp_upiu_addr, rsp_out, sizeof(*rsp_out));
247631c8726SJeuk Kim if (data_out_len) {
248631c8726SJeuk Kim qtest_memread(ufs->dev.bus->qts, ufs->data_buffer_addr, data_out,
249631c8726SJeuk Kim data_out_len);
250631c8726SJeuk Kim }
251631c8726SJeuk Kim }
252631c8726SJeuk Kim
253631c8726SJeuk Kim /**
254631c8726SJeuk Kim * Initialize Ufs host controller and logical unit.
255631c8726SJeuk Kim * After running this function, you can make a transfer request to the UFS.
256631c8726SJeuk Kim */
ufs_init(QUfs * ufs,QGuestAllocator * alloc)257631c8726SJeuk Kim static void ufs_init(QUfs *ufs, QGuestAllocator *alloc)
258631c8726SJeuk Kim {
259631c8726SJeuk Kim uint64_t end_time;
260631c8726SJeuk Kim uint32_t nutrs, nutmrs;
261631c8726SJeuk Kim uint32_t hcs, is, ucmdarg2, cap;
262631c8726SJeuk Kim uint32_t hce = 0, ie = 0;
263631c8726SJeuk Kim UtpTransferReqDesc utrd;
264631c8726SJeuk Kim UtpUpiuRsp rsp_upiu;
265631c8726SJeuk Kim
266631c8726SJeuk Kim ufs->bar = qpci_iomap(&ufs->dev, 0, NULL);
267631c8726SJeuk Kim qpci_device_enable(&ufs->dev);
268631c8726SJeuk Kim
269631c8726SJeuk Kim /* Start host controller initialization */
270631c8726SJeuk Kim hce = FIELD_DP32(hce, HCE, HCE, 1);
271631c8726SJeuk Kim ufs_wreg(ufs, A_HCE, hce);
272631c8726SJeuk Kim
273631c8726SJeuk Kim /* Wait for device to reset */
274631c8726SJeuk Kim end_time = g_get_monotonic_time() + TIMEOUT_SECONDS * G_TIME_SPAN_SECOND;
275631c8726SJeuk Kim do {
276631c8726SJeuk Kim qtest_clock_step(ufs->dev.bus->qts, 100);
277631c8726SJeuk Kim hce = FIELD_EX32(ufs_rreg(ufs, A_HCE), HCE, HCE);
278631c8726SJeuk Kim } while (hce == 0 && g_get_monotonic_time() < end_time);
279631c8726SJeuk Kim g_assert_cmpuint(hce, ==, 1);
280631c8726SJeuk Kim
281631c8726SJeuk Kim /* Enable interrupt */
282631c8726SJeuk Kim ie = FIELD_DP32(ie, IE, UCCE, 1);
283631c8726SJeuk Kim ie = FIELD_DP32(ie, IE, UHESE, 1);
284631c8726SJeuk Kim ie = FIELD_DP32(ie, IE, UHXSE, 1);
285631c8726SJeuk Kim ie = FIELD_DP32(ie, IE, UPMSE, 1);
286631c8726SJeuk Kim ufs_wreg(ufs, A_IE, ie);
287631c8726SJeuk Kim
288631c8726SJeuk Kim /* Send DME_LINK_STARTUP uic command */
289631c8726SJeuk Kim hcs = ufs_rreg(ufs, A_HCS);
290631c8726SJeuk Kim g_assert_true(FIELD_EX32(hcs, HCS, UCRDY));
291631c8726SJeuk Kim
292631c8726SJeuk Kim ufs_wreg(ufs, A_UCMDARG1, 0);
293631c8726SJeuk Kim ufs_wreg(ufs, A_UCMDARG2, 0);
294631c8726SJeuk Kim ufs_wreg(ufs, A_UCMDARG3, 0);
295631c8726SJeuk Kim ufs_wreg(ufs, A_UICCMD, UFS_UIC_CMD_DME_LINK_STARTUP);
296631c8726SJeuk Kim
297631c8726SJeuk Kim is = ufs_rreg(ufs, A_IS);
298631c8726SJeuk Kim g_assert_true(FIELD_EX32(is, IS, UCCS));
299631c8726SJeuk Kim ufs_wreg(ufs, A_IS, FIELD_DP32(0, IS, UCCS, 1));
300631c8726SJeuk Kim
301631c8726SJeuk Kim ucmdarg2 = ufs_rreg(ufs, A_UCMDARG2);
302631c8726SJeuk Kim g_assert_cmpuint(ucmdarg2, ==, 0);
303631c8726SJeuk Kim is = ufs_rreg(ufs, A_IS);
304631c8726SJeuk Kim g_assert_cmpuint(is, ==, 0);
305631c8726SJeuk Kim hcs = ufs_rreg(ufs, A_HCS);
306631c8726SJeuk Kim g_assert_true(FIELD_EX32(hcs, HCS, DP));
307631c8726SJeuk Kim g_assert_true(FIELD_EX32(hcs, HCS, UTRLRDY));
308631c8726SJeuk Kim g_assert_true(FIELD_EX32(hcs, HCS, UTMRLRDY));
309631c8726SJeuk Kim g_assert_true(FIELD_EX32(hcs, HCS, UCRDY));
310631c8726SJeuk Kim
311631c8726SJeuk Kim /* Enable all interrupt functions */
312631c8726SJeuk Kim ie = FIELD_DP32(ie, IE, UTRCE, 1);
313631c8726SJeuk Kim ie = FIELD_DP32(ie, IE, UEE, 1);
314631c8726SJeuk Kim ie = FIELD_DP32(ie, IE, UPMSE, 1);
315631c8726SJeuk Kim ie = FIELD_DP32(ie, IE, UHXSE, 1);
316631c8726SJeuk Kim ie = FIELD_DP32(ie, IE, UHESE, 1);
317631c8726SJeuk Kim ie = FIELD_DP32(ie, IE, UTMRCE, 1);
318631c8726SJeuk Kim ie = FIELD_DP32(ie, IE, UCCE, 1);
319631c8726SJeuk Kim ie = FIELD_DP32(ie, IE, DFEE, 1);
320631c8726SJeuk Kim ie = FIELD_DP32(ie, IE, HCFEE, 1);
321631c8726SJeuk Kim ie = FIELD_DP32(ie, IE, SBFEE, 1);
322631c8726SJeuk Kim ie = FIELD_DP32(ie, IE, CEFEE, 1);
323631c8726SJeuk Kim ufs_wreg(ufs, A_IE, ie);
324631c8726SJeuk Kim ufs_wreg(ufs, A_UTRIACR, 0);
325631c8726SJeuk Kim
3264b3e4d2bSMichael Tokarev /* Enable transfer request and task management request */
327631c8726SJeuk Kim cap = ufs_rreg(ufs, A_CAP);
328631c8726SJeuk Kim nutrs = FIELD_EX32(cap, CAP, NUTRS) + 1;
329631c8726SJeuk Kim nutmrs = FIELD_EX32(cap, CAP, NUTMRS) + 1;
330631c8726SJeuk Kim ufs->cmd_desc_addr =
331631c8726SJeuk Kim guest_alloc(alloc, nutrs * UTP_COMMAND_DESCRIPTOR_SIZE);
332631c8726SJeuk Kim ufs->data_buffer_addr =
333631c8726SJeuk Kim guest_alloc(alloc, MAX_PRD_ENTRY_COUNT * PRD_ENTRY_DATA_SIZE);
334631c8726SJeuk Kim ufs->utrlba = guest_alloc(alloc, nutrs * sizeof(UtpTransferReqDesc));
335631c8726SJeuk Kim ufs->utmrlba = guest_alloc(alloc, nutmrs * sizeof(UtpTaskReqDesc));
336631c8726SJeuk Kim
337631c8726SJeuk Kim ufs_wreg(ufs, A_UTRLBA, ufs->utrlba & 0xffffffff);
338631c8726SJeuk Kim ufs_wreg(ufs, A_UTRLBAU, ufs->utrlba >> 32);
339631c8726SJeuk Kim ufs_wreg(ufs, A_UTMRLBA, ufs->utmrlba & 0xffffffff);
340631c8726SJeuk Kim ufs_wreg(ufs, A_UTMRLBAU, ufs->utmrlba >> 32);
341631c8726SJeuk Kim ufs_wreg(ufs, A_UTRLRSR, 1);
342631c8726SJeuk Kim ufs_wreg(ufs, A_UTMRLRSR, 1);
343631c8726SJeuk Kim
344631c8726SJeuk Kim /* Send nop out to test transfer request */
345631c8726SJeuk Kim ufs_send_nop_out(ufs, 0, &utrd, &rsp_upiu);
346631c8726SJeuk Kim g_assert_cmpuint(le32_to_cpu(utrd.header.dword_2), ==, UFS_OCS_SUCCESS);
347631c8726SJeuk Kim
348631c8726SJeuk Kim /* Set fDeviceInit flag via query request */
349631c8726SJeuk Kim ufs_send_query(ufs, 0, UFS_UPIU_QUERY_FUNC_STANDARD_WRITE_REQUEST,
350631c8726SJeuk Kim UFS_UPIU_QUERY_OPCODE_SET_FLAG,
3517c85332aSYoochan Jeong UFS_QUERY_FLAG_IDN_FDEVICEINIT, 0, 0, 0, &utrd, &rsp_upiu);
352631c8726SJeuk Kim g_assert_cmpuint(le32_to_cpu(utrd.header.dword_2), ==, UFS_OCS_SUCCESS);
353631c8726SJeuk Kim
354631c8726SJeuk Kim /* Wait for device to reset */
355631c8726SJeuk Kim end_time = g_get_monotonic_time() + TIMEOUT_SECONDS * G_TIME_SPAN_SECOND;
356631c8726SJeuk Kim do {
357631c8726SJeuk Kim qtest_clock_step(ufs->dev.bus->qts, 100);
358631c8726SJeuk Kim ufs_send_query(ufs, 0, UFS_UPIU_QUERY_FUNC_STANDARD_READ_REQUEST,
359631c8726SJeuk Kim UFS_UPIU_QUERY_OPCODE_READ_FLAG,
3607c85332aSYoochan Jeong UFS_QUERY_FLAG_IDN_FDEVICEINIT, 0, 0, 0, &utrd,
3617c85332aSYoochan Jeong &rsp_upiu);
362631c8726SJeuk Kim } while (be32_to_cpu(rsp_upiu.qr.value) != 0 &&
363631c8726SJeuk Kim g_get_monotonic_time() < end_time);
364631c8726SJeuk Kim g_assert_cmpuint(be32_to_cpu(rsp_upiu.qr.value), ==, 0);
365631c8726SJeuk Kim
366631c8726SJeuk Kim ufs->enabled = true;
367631c8726SJeuk Kim }
368631c8726SJeuk Kim
ufs_exit(QUfs * ufs,QGuestAllocator * alloc)369631c8726SJeuk Kim static void ufs_exit(QUfs *ufs, QGuestAllocator *alloc)
370631c8726SJeuk Kim {
371631c8726SJeuk Kim if (ufs->enabled) {
372631c8726SJeuk Kim guest_free(alloc, ufs->utrlba);
373631c8726SJeuk Kim guest_free(alloc, ufs->utmrlba);
374631c8726SJeuk Kim guest_free(alloc, ufs->cmd_desc_addr);
375631c8726SJeuk Kim guest_free(alloc, ufs->data_buffer_addr);
376631c8726SJeuk Kim }
377631c8726SJeuk Kim
378631c8726SJeuk Kim qpci_iounmap(&ufs->dev, ufs->bar);
379631c8726SJeuk Kim }
380631c8726SJeuk Kim
ufs_get_driver(void * obj,const char * interface)381631c8726SJeuk Kim static void *ufs_get_driver(void *obj, const char *interface)
382631c8726SJeuk Kim {
383631c8726SJeuk Kim QUfs *ufs = obj;
384631c8726SJeuk Kim
385631c8726SJeuk Kim if (!g_strcmp0(interface, "pci-device")) {
386631c8726SJeuk Kim return &ufs->dev;
387631c8726SJeuk Kim }
388631c8726SJeuk Kim
389631c8726SJeuk Kim fprintf(stderr, "%s not present in ufs\n", interface);
390631c8726SJeuk Kim g_assert_not_reached();
391631c8726SJeuk Kim }
392631c8726SJeuk Kim
ufs_create(void * pci_bus,QGuestAllocator * alloc,void * addr)393631c8726SJeuk Kim static void *ufs_create(void *pci_bus, QGuestAllocator *alloc, void *addr)
394631c8726SJeuk Kim {
395631c8726SJeuk Kim QUfs *ufs = g_new0(QUfs, 1);
396631c8726SJeuk Kim QPCIBus *bus = pci_bus;
397631c8726SJeuk Kim
398631c8726SJeuk Kim qpci_device_init(&ufs->dev, bus, addr);
399631c8726SJeuk Kim ufs->obj.get_driver = ufs_get_driver;
400631c8726SJeuk Kim
401631c8726SJeuk Kim return &ufs->obj;
402631c8726SJeuk Kim }
403631c8726SJeuk Kim
ufstest_reg_read(void * obj,void * data,QGuestAllocator * alloc)404631c8726SJeuk Kim static void ufstest_reg_read(void *obj, void *data, QGuestAllocator *alloc)
405631c8726SJeuk Kim {
406631c8726SJeuk Kim QUfs *ufs = obj;
407631c8726SJeuk Kim uint32_t cap;
408631c8726SJeuk Kim
409631c8726SJeuk Kim ufs->bar = qpci_iomap(&ufs->dev, 0, NULL);
410631c8726SJeuk Kim qpci_device_enable(&ufs->dev);
411631c8726SJeuk Kim
412631c8726SJeuk Kim cap = ufs_rreg(ufs, A_CAP);
413631c8726SJeuk Kim g_assert_cmpuint(FIELD_EX32(cap, CAP, NUTRS), ==, 31);
414631c8726SJeuk Kim g_assert_cmpuint(FIELD_EX32(cap, CAP, NUTMRS), ==, 7);
415631c8726SJeuk Kim g_assert_cmpuint(FIELD_EX32(cap, CAP, 64AS), ==, 1);
416631c8726SJeuk Kim
417631c8726SJeuk Kim qpci_iounmap(&ufs->dev, ufs->bar);
418631c8726SJeuk Kim }
419631c8726SJeuk Kim
ufstest_init(void * obj,void * data,QGuestAllocator * alloc)420631c8726SJeuk Kim static void ufstest_init(void *obj, void *data, QGuestAllocator *alloc)
421631c8726SJeuk Kim {
422631c8726SJeuk Kim QUfs *ufs = obj;
423631c8726SJeuk Kim
424631c8726SJeuk Kim uint8_t buf[4096] = { 0 };
425631c8726SJeuk Kim const uint8_t report_luns_cdb[UFS_CDB_SIZE] = {
426631c8726SJeuk Kim /* allocation length 4096 */
427631c8726SJeuk Kim REPORT_LUNS, 0x00, 0x00, 0x00, 0x00, 0x00,
428631c8726SJeuk Kim 0x00, 0x00, 0x10, 0x00, 0x00, 0x00
429631c8726SJeuk Kim };
430631c8726SJeuk Kim const uint8_t test_unit_ready_cdb[UFS_CDB_SIZE] = {
431631c8726SJeuk Kim TEST_UNIT_READY,
432631c8726SJeuk Kim };
433096434feSJeuk Kim const uint8_t request_sense_cdb[UFS_CDB_SIZE] = {
434096434feSJeuk Kim REQUEST_SENSE,
435096434feSJeuk Kim };
436631c8726SJeuk Kim UtpTransferReqDesc utrd;
437631c8726SJeuk Kim UtpUpiuRsp rsp_upiu;
438631c8726SJeuk Kim
439631c8726SJeuk Kim ufs_init(ufs, alloc);
440631c8726SJeuk Kim
441631c8726SJeuk Kim /* Check REPORT_LUNS */
442631c8726SJeuk Kim ufs_send_scsi_command(ufs, 0, 0, report_luns_cdb, NULL, 0, buf, sizeof(buf),
443631c8726SJeuk Kim &utrd, &rsp_upiu);
444631c8726SJeuk Kim g_assert_cmpuint(le32_to_cpu(utrd.header.dword_2), ==, UFS_OCS_SUCCESS);
445631c8726SJeuk Kim g_assert_cmpuint(rsp_upiu.header.scsi_status, ==, GOOD);
446631c8726SJeuk Kim /* LUN LIST LENGTH should be 8, in big endian */
447631c8726SJeuk Kim g_assert_cmpuint(buf[3], ==, 8);
448631c8726SJeuk Kim /* There is one logical unit whose lun is 0 */
449631c8726SJeuk Kim g_assert_cmpuint(buf[9], ==, 0);
450631c8726SJeuk Kim
451096434feSJeuk Kim /* Clear Unit Attention */
452096434feSJeuk Kim ufs_send_scsi_command(ufs, 0, 0, request_sense_cdb, NULL, 0, buf,
453096434feSJeuk Kim sizeof(buf), &utrd, &rsp_upiu);
454096434feSJeuk Kim g_assert_cmpuint(le32_to_cpu(utrd.header.dword_2), ==, UFS_OCS_SUCCESS);
455096434feSJeuk Kim g_assert_cmpuint(rsp_upiu.header.scsi_status, ==, CHECK_CONDITION);
456096434feSJeuk Kim
457631c8726SJeuk Kim /* Check TEST_UNIT_READY */
458631c8726SJeuk Kim ufs_send_scsi_command(ufs, 0, 0, test_unit_ready_cdb, NULL, 0, NULL, 0,
459631c8726SJeuk Kim &utrd, &rsp_upiu);
460631c8726SJeuk Kim g_assert_cmpuint(le32_to_cpu(utrd.header.dword_2), ==, UFS_OCS_SUCCESS);
461631c8726SJeuk Kim g_assert_cmpuint(rsp_upiu.header.scsi_status, ==, GOOD);
462631c8726SJeuk Kim
463631c8726SJeuk Kim ufs_exit(ufs, alloc);
464631c8726SJeuk Kim }
465631c8726SJeuk Kim
ufstest_read_write(void * obj,void * data,QGuestAllocator * alloc)466631c8726SJeuk Kim static void ufstest_read_write(void *obj, void *data, QGuestAllocator *alloc)
467631c8726SJeuk Kim {
468631c8726SJeuk Kim QUfs *ufs = obj;
469631c8726SJeuk Kim uint8_t read_buf[4096] = { 0 };
470631c8726SJeuk Kim uint8_t write_buf[4096] = { 0 };
471631c8726SJeuk Kim const uint8_t read_capacity_cdb[UFS_CDB_SIZE] = {
472631c8726SJeuk Kim /* allocation length 4096 */
473631c8726SJeuk Kim SERVICE_ACTION_IN_16,
474631c8726SJeuk Kim SAI_READ_CAPACITY_16,
475631c8726SJeuk Kim 0x00,
476631c8726SJeuk Kim 0x00,
477631c8726SJeuk Kim 0x00,
478631c8726SJeuk Kim 0x00,
479631c8726SJeuk Kim 0x00,
480631c8726SJeuk Kim 0x00,
481631c8726SJeuk Kim 0x00,
482631c8726SJeuk Kim 0x00,
483631c8726SJeuk Kim 0x00,
484631c8726SJeuk Kim 0x00,
485631c8726SJeuk Kim 0x10,
486631c8726SJeuk Kim 0x00,
487631c8726SJeuk Kim 0x00,
488631c8726SJeuk Kim 0x00
489631c8726SJeuk Kim };
490096434feSJeuk Kim const uint8_t request_sense_cdb[UFS_CDB_SIZE] = {
491096434feSJeuk Kim REQUEST_SENSE,
492096434feSJeuk Kim };
493631c8726SJeuk Kim const uint8_t read_cdb[UFS_CDB_SIZE] = {
494631c8726SJeuk Kim /* READ(10) to LBA 0, transfer length 1 */
495631c8726SJeuk Kim READ_10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00
496631c8726SJeuk Kim };
497631c8726SJeuk Kim const uint8_t write_cdb[UFS_CDB_SIZE] = {
498631c8726SJeuk Kim /* WRITE(10) to LBA 0, transfer length 1 */
499631c8726SJeuk Kim WRITE_10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00
500631c8726SJeuk Kim };
501631c8726SJeuk Kim uint32_t block_size;
502631c8726SJeuk Kim UtpTransferReqDesc utrd;
503631c8726SJeuk Kim UtpUpiuRsp rsp_upiu;
504096434feSJeuk Kim const int test_lun = 1;
505631c8726SJeuk Kim
506631c8726SJeuk Kim ufs_init(ufs, alloc);
507631c8726SJeuk Kim
508096434feSJeuk Kim /* Clear Unit Attention */
509096434feSJeuk Kim ufs_send_scsi_command(ufs, 0, test_lun, request_sense_cdb, NULL, 0,
510096434feSJeuk Kim read_buf, sizeof(read_buf), &utrd, &rsp_upiu);
511096434feSJeuk Kim g_assert_cmpuint(le32_to_cpu(utrd.header.dword_2), ==, UFS_OCS_SUCCESS);
512096434feSJeuk Kim g_assert_cmpuint(rsp_upiu.header.scsi_status, ==, CHECK_CONDITION);
513096434feSJeuk Kim
514631c8726SJeuk Kim /* Read capacity */
515096434feSJeuk Kim ufs_send_scsi_command(ufs, 0, test_lun, read_capacity_cdb, NULL, 0,
516096434feSJeuk Kim read_buf, sizeof(read_buf), &utrd, &rsp_upiu);
517631c8726SJeuk Kim g_assert_cmpuint(le32_to_cpu(utrd.header.dword_2), ==, UFS_OCS_SUCCESS);
518631c8726SJeuk Kim g_assert_cmpuint(rsp_upiu.header.scsi_status, ==,
519096434feSJeuk Kim UFS_COMMAND_RESULT_SUCCESS);
520631c8726SJeuk Kim block_size = ldl_be_p(&read_buf[8]);
521631c8726SJeuk Kim g_assert_cmpuint(block_size, ==, 4096);
522631c8726SJeuk Kim
523631c8726SJeuk Kim /* Write data */
52497970daeSJeuk Kim memset(write_buf, 0xab, block_size);
525096434feSJeuk Kim ufs_send_scsi_command(ufs, 0, test_lun, write_cdb, write_buf, block_size,
526096434feSJeuk Kim NULL, 0, &utrd, &rsp_upiu);
527631c8726SJeuk Kim g_assert_cmpuint(le32_to_cpu(utrd.header.dword_2), ==, UFS_OCS_SUCCESS);
528631c8726SJeuk Kim g_assert_cmpuint(rsp_upiu.header.scsi_status, ==,
529096434feSJeuk Kim UFS_COMMAND_RESULT_SUCCESS);
530631c8726SJeuk Kim
531631c8726SJeuk Kim /* Read data and verify */
532096434feSJeuk Kim ufs_send_scsi_command(ufs, 0, test_lun, read_cdb, NULL, 0, read_buf,
533096434feSJeuk Kim block_size, &utrd, &rsp_upiu);
534631c8726SJeuk Kim g_assert_cmpuint(le32_to_cpu(utrd.header.dword_2), ==, UFS_OCS_SUCCESS);
535631c8726SJeuk Kim g_assert_cmpuint(rsp_upiu.header.scsi_status, ==,
536096434feSJeuk Kim UFS_COMMAND_RESULT_SUCCESS);
537631c8726SJeuk Kim g_assert_cmpint(memcmp(read_buf, write_buf, block_size), ==, 0);
538631c8726SJeuk Kim
539631c8726SJeuk Kim ufs_exit(ufs, alloc);
540631c8726SJeuk Kim }
541631c8726SJeuk Kim
ufstest_query_flag_request(void * obj,void * data,QGuestAllocator * alloc)5424aac3029SYoochan Jeong static void ufstest_query_flag_request(void *obj, void *data,
5434aac3029SYoochan Jeong QGuestAllocator *alloc)
5444aac3029SYoochan Jeong {
5454aac3029SYoochan Jeong QUfs *ufs = obj;
5464aac3029SYoochan Jeong
5474aac3029SYoochan Jeong UtpTransferReqDesc utrd;
5484aac3029SYoochan Jeong UtpUpiuRsp rsp_upiu;
5494aac3029SYoochan Jeong ufs_init(ufs, alloc);
5504aac3029SYoochan Jeong
5514aac3029SYoochan Jeong /* Read read-only flag */
5524aac3029SYoochan Jeong ufs_send_query(ufs, 0, UFS_UPIU_QUERY_FUNC_STANDARD_READ_REQUEST,
5534aac3029SYoochan Jeong UFS_UPIU_QUERY_OPCODE_READ_FLAG,
5544aac3029SYoochan Jeong UFS_QUERY_FLAG_IDN_FDEVICEINIT, 0, 0, 0, &utrd, &rsp_upiu);
5554aac3029SYoochan Jeong g_assert_cmpuint(le32_to_cpu(utrd.header.dword_2), ==, UFS_OCS_SUCCESS);
5564aac3029SYoochan Jeong g_assert_cmpuint(rsp_upiu.header.response, ==, UFS_COMMAND_RESULT_SUCCESS);
5574aac3029SYoochan Jeong g_assert_cmpuint(rsp_upiu.qr.opcode, ==, UFS_UPIU_QUERY_OPCODE_READ_FLAG);
5584aac3029SYoochan Jeong g_assert_cmpuint(rsp_upiu.qr.idn, ==, UFS_QUERY_FLAG_IDN_FDEVICEINIT);
5594aac3029SYoochan Jeong g_assert_cmpuint(rsp_upiu.qr.value, ==, be32_to_cpu(0));
5604aac3029SYoochan Jeong
5614aac3029SYoochan Jeong /* Flag Set, Clear, Toggle Test with fDeviceLifeSpanModeEn */
5624aac3029SYoochan Jeong ufs_send_query(ufs, 0, UFS_UPIU_QUERY_FUNC_STANDARD_READ_REQUEST,
5634aac3029SYoochan Jeong UFS_UPIU_QUERY_OPCODE_READ_FLAG,
5644aac3029SYoochan Jeong UFS_QUERY_FLAG_IDN_LIFE_SPAN_MODE_ENABLE, 0, 0, 0, &utrd,
5654aac3029SYoochan Jeong &rsp_upiu);
5664aac3029SYoochan Jeong g_assert_cmpuint(le32_to_cpu(utrd.header.dword_2), ==, UFS_OCS_SUCCESS);
5674aac3029SYoochan Jeong g_assert_cmpuint(rsp_upiu.header.response, ==, UFS_COMMAND_RESULT_SUCCESS);
5684aac3029SYoochan Jeong g_assert_cmpuint(rsp_upiu.qr.value, ==, be32_to_cpu(0));
5694aac3029SYoochan Jeong
5704aac3029SYoochan Jeong ufs_send_query(ufs, 0, UFS_UPIU_QUERY_FUNC_STANDARD_WRITE_REQUEST,
5714aac3029SYoochan Jeong UFS_UPIU_QUERY_OPCODE_SET_FLAG,
5724aac3029SYoochan Jeong UFS_QUERY_FLAG_IDN_LIFE_SPAN_MODE_ENABLE, 0, 0, 0, &utrd,
5734aac3029SYoochan Jeong &rsp_upiu);
5744aac3029SYoochan Jeong g_assert_cmpuint(le32_to_cpu(utrd.header.dword_2), ==, UFS_OCS_SUCCESS);
5754aac3029SYoochan Jeong g_assert_cmpuint(rsp_upiu.header.response, ==, UFS_COMMAND_RESULT_SUCCESS);
5764aac3029SYoochan Jeong g_assert_cmpuint(rsp_upiu.qr.value, ==, be32_to_cpu(1));
5774aac3029SYoochan Jeong
5784aac3029SYoochan Jeong ufs_send_query(ufs, 0, UFS_UPIU_QUERY_FUNC_STANDARD_WRITE_REQUEST,
5794aac3029SYoochan Jeong UFS_UPIU_QUERY_OPCODE_CLEAR_FLAG,
5804aac3029SYoochan Jeong UFS_QUERY_FLAG_IDN_LIFE_SPAN_MODE_ENABLE, 0, 0, 0, &utrd,
5814aac3029SYoochan Jeong &rsp_upiu);
5824aac3029SYoochan Jeong g_assert_cmpuint(le32_to_cpu(utrd.header.dword_2), ==, UFS_OCS_SUCCESS);
5834aac3029SYoochan Jeong g_assert_cmpuint(rsp_upiu.header.response, ==, UFS_COMMAND_RESULT_SUCCESS);
5844aac3029SYoochan Jeong g_assert_cmpuint(rsp_upiu.qr.value, ==, be32_to_cpu(0));
5854aac3029SYoochan Jeong
5864aac3029SYoochan Jeong ufs_send_query(ufs, 0, UFS_UPIU_QUERY_FUNC_STANDARD_WRITE_REQUEST,
5874aac3029SYoochan Jeong UFS_UPIU_QUERY_OPCODE_TOGGLE_FLAG,
5884aac3029SYoochan Jeong UFS_QUERY_FLAG_IDN_LIFE_SPAN_MODE_ENABLE, 0, 0, 0, &utrd,
5894aac3029SYoochan Jeong &rsp_upiu);
5904aac3029SYoochan Jeong g_assert_cmpuint(le32_to_cpu(utrd.header.dword_2), ==, UFS_OCS_SUCCESS);
5914aac3029SYoochan Jeong g_assert_cmpuint(rsp_upiu.header.response, ==, UFS_COMMAND_RESULT_SUCCESS);
5924aac3029SYoochan Jeong g_assert_cmpuint(rsp_upiu.qr.value, ==, be32_to_cpu(1));
5934aac3029SYoochan Jeong
5944aac3029SYoochan Jeong ufs_send_query(ufs, 0, UFS_UPIU_QUERY_FUNC_STANDARD_WRITE_REQUEST,
5954aac3029SYoochan Jeong UFS_UPIU_QUERY_OPCODE_TOGGLE_FLAG,
5964aac3029SYoochan Jeong UFS_QUERY_FLAG_IDN_LIFE_SPAN_MODE_ENABLE, 0, 0, 0, &utrd,
5974aac3029SYoochan Jeong &rsp_upiu);
5984aac3029SYoochan Jeong g_assert_cmpuint(le32_to_cpu(utrd.header.dword_2), ==, 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
6024aac3029SYoochan Jeong /* Read Write-only Flag (Intended Failure) */
6034aac3029SYoochan Jeong ufs_send_query(ufs, 0, UFS_UPIU_QUERY_FUNC_STANDARD_READ_REQUEST,
6044aac3029SYoochan Jeong UFS_UPIU_QUERY_OPCODE_READ_FLAG,
6054aac3029SYoochan Jeong UFS_QUERY_FLAG_IDN_PURGE_ENABLE, 0, 0, 0, &utrd, &rsp_upiu);
6064aac3029SYoochan Jeong g_assert_cmpuint(le32_to_cpu(utrd.header.dword_2), ==,
6074aac3029SYoochan Jeong UFS_OCS_INVALID_CMD_TABLE_ATTR);
6084aac3029SYoochan Jeong g_assert_cmpuint(rsp_upiu.header.response, ==,
6094aac3029SYoochan Jeong UFS_QUERY_RESULT_NOT_READABLE);
6104aac3029SYoochan Jeong
6114aac3029SYoochan Jeong /* Write Read-Only Flag (Intended Failure) */
6124aac3029SYoochan Jeong ufs_send_query(ufs, 0, UFS_UPIU_QUERY_FUNC_STANDARD_WRITE_REQUEST,
6134aac3029SYoochan Jeong UFS_UPIU_QUERY_OPCODE_SET_FLAG, UFS_QUERY_FLAG_IDN_BUSY_RTC,
6144aac3029SYoochan Jeong 0, 0, 0, &utrd, &rsp_upiu);
6154aac3029SYoochan Jeong g_assert_cmpuint(le32_to_cpu(utrd.header.dword_2), ==,
6164aac3029SYoochan Jeong UFS_OCS_INVALID_CMD_TABLE_ATTR);
6174aac3029SYoochan Jeong g_assert_cmpuint(rsp_upiu.header.response, ==,
6184aac3029SYoochan Jeong UFS_QUERY_RESULT_NOT_WRITEABLE);
6194aac3029SYoochan Jeong
6204aac3029SYoochan Jeong ufs_exit(ufs, alloc);
6214aac3029SYoochan Jeong }
6224aac3029SYoochan Jeong
ufstest_query_attr_request(void * obj,void * data,QGuestAllocator * alloc)62349ccea4bSYoochan Jeong static void ufstest_query_attr_request(void *obj, void *data,
62449ccea4bSYoochan Jeong QGuestAllocator *alloc)
62549ccea4bSYoochan Jeong {
62649ccea4bSYoochan Jeong QUfs *ufs = obj;
62749ccea4bSYoochan Jeong
62849ccea4bSYoochan Jeong UtpTransferReqDesc utrd;
62949ccea4bSYoochan Jeong UtpUpiuRsp rsp_upiu;
63049ccea4bSYoochan Jeong ufs_init(ufs, alloc);
63149ccea4bSYoochan Jeong
63249ccea4bSYoochan Jeong /* Read Readable Attributes*/
63349ccea4bSYoochan Jeong ufs_send_query(ufs, 0, UFS_UPIU_QUERY_FUNC_STANDARD_READ_REQUEST,
63449ccea4bSYoochan Jeong UFS_UPIU_QUERY_OPCODE_READ_ATTR,
63549ccea4bSYoochan Jeong UFS_QUERY_ATTR_IDN_BOOT_LU_EN, 0, 0, 0, &utrd, &rsp_upiu);
63649ccea4bSYoochan Jeong g_assert_cmpuint(le32_to_cpu(utrd.header.dword_2), ==, UFS_OCS_SUCCESS);
63749ccea4bSYoochan Jeong g_assert_cmpuint(rsp_upiu.header.response, ==, UFS_COMMAND_RESULT_SUCCESS);
63849ccea4bSYoochan Jeong g_assert_cmpuint(rsp_upiu.qr.opcode, ==, UFS_UPIU_QUERY_OPCODE_READ_ATTR);
63949ccea4bSYoochan Jeong g_assert_cmpuint(rsp_upiu.qr.idn, ==, UFS_QUERY_ATTR_IDN_BOOT_LU_EN);
64049ccea4bSYoochan Jeong g_assert_cmpuint(rsp_upiu.qr.value, ==, cpu_to_be32(0x00));
64149ccea4bSYoochan Jeong
64249ccea4bSYoochan Jeong ufs_send_query(ufs, 0, UFS_UPIU_QUERY_FUNC_STANDARD_READ_REQUEST,
64349ccea4bSYoochan Jeong UFS_UPIU_QUERY_OPCODE_READ_ATTR,
64449ccea4bSYoochan Jeong UFS_QUERY_ATTR_IDN_BKOPS_STATUS, 0, 0, 0, &utrd, &rsp_upiu);
64549ccea4bSYoochan Jeong g_assert_cmpuint(le32_to_cpu(utrd.header.dword_2), ==, UFS_OCS_SUCCESS);
64649ccea4bSYoochan Jeong g_assert_cmpuint(rsp_upiu.header.response, ==, UFS_COMMAND_RESULT_SUCCESS);
64749ccea4bSYoochan Jeong g_assert_cmpuint(rsp_upiu.qr.value, ==, cpu_to_be32(0x00));
64849ccea4bSYoochan Jeong
64949ccea4bSYoochan Jeong /* Write Writable Attributes & Read Again */
65049ccea4bSYoochan Jeong ufs_send_query(ufs, 0, UFS_UPIU_QUERY_FUNC_STANDARD_WRITE_REQUEST,
65149ccea4bSYoochan Jeong UFS_UPIU_QUERY_OPCODE_WRITE_ATTR,
65249ccea4bSYoochan Jeong UFS_QUERY_ATTR_IDN_ACTIVE_ICC_LVL, 0, 0, 0x03, &utrd,
65349ccea4bSYoochan Jeong &rsp_upiu);
65449ccea4bSYoochan Jeong g_assert_cmpuint(le32_to_cpu(utrd.header.dword_2), ==, UFS_OCS_SUCCESS);
65549ccea4bSYoochan Jeong g_assert_cmpuint(rsp_upiu.header.response, ==, UFS_COMMAND_RESULT_SUCCESS);
65649ccea4bSYoochan Jeong g_assert_cmpuint(rsp_upiu.qr.value, ==, cpu_to_be32(0x03));
65749ccea4bSYoochan Jeong
65849ccea4bSYoochan Jeong ufs_send_query(ufs, 0, UFS_UPIU_QUERY_FUNC_STANDARD_WRITE_REQUEST,
65949ccea4bSYoochan Jeong UFS_UPIU_QUERY_OPCODE_WRITE_ATTR,
66049ccea4bSYoochan Jeong UFS_QUERY_ATTR_IDN_EE_CONTROL, 0, 0, 0x07, &utrd, &rsp_upiu);
66149ccea4bSYoochan Jeong g_assert_cmpuint(le32_to_cpu(utrd.header.dword_2), ==, UFS_OCS_SUCCESS);
66249ccea4bSYoochan Jeong g_assert_cmpuint(rsp_upiu.header.response, ==, UFS_COMMAND_RESULT_SUCCESS);
66349ccea4bSYoochan Jeong g_assert_cmpuint(rsp_upiu.qr.value, ==, cpu_to_be32(0x07));
66449ccea4bSYoochan Jeong
66549ccea4bSYoochan Jeong ufs_send_query(ufs, 0, UFS_UPIU_QUERY_FUNC_STANDARD_READ_REQUEST,
66649ccea4bSYoochan Jeong UFS_UPIU_QUERY_OPCODE_READ_ATTR,
66749ccea4bSYoochan Jeong UFS_QUERY_ATTR_IDN_ACTIVE_ICC_LVL, 0, 0, 0, &utrd,
66849ccea4bSYoochan Jeong &rsp_upiu);
66949ccea4bSYoochan Jeong g_assert_cmpuint(le32_to_cpu(utrd.header.dword_2), ==, UFS_OCS_SUCCESS);
67049ccea4bSYoochan Jeong g_assert_cmpuint(rsp_upiu.header.response, ==, UFS_COMMAND_RESULT_SUCCESS);
67149ccea4bSYoochan Jeong g_assert_cmpuint(rsp_upiu.qr.value, ==, cpu_to_be32(0x03));
67249ccea4bSYoochan Jeong
67349ccea4bSYoochan Jeong ufs_send_query(ufs, 0, UFS_UPIU_QUERY_FUNC_STANDARD_READ_REQUEST,
67449ccea4bSYoochan Jeong UFS_UPIU_QUERY_OPCODE_READ_ATTR,
67549ccea4bSYoochan Jeong UFS_QUERY_ATTR_IDN_EE_CONTROL, 0, 0, 0, &utrd, &rsp_upiu);
67649ccea4bSYoochan Jeong g_assert_cmpuint(le32_to_cpu(utrd.header.dword_2), ==, UFS_OCS_SUCCESS);
67749ccea4bSYoochan Jeong g_assert_cmpuint(rsp_upiu.header.response, ==, UFS_COMMAND_RESULT_SUCCESS);
67849ccea4bSYoochan Jeong g_assert_cmpuint(rsp_upiu.qr.value, ==, cpu_to_be32(0x07));
67949ccea4bSYoochan Jeong
68049ccea4bSYoochan Jeong /* Write Invalid Value (Intended Error) */
68149ccea4bSYoochan Jeong ufs_send_query(ufs, 0, UFS_UPIU_QUERY_FUNC_STANDARD_WRITE_REQUEST,
68249ccea4bSYoochan Jeong UFS_UPIU_QUERY_OPCODE_WRITE_ATTR,
68349ccea4bSYoochan Jeong UFS_QUERY_ATTR_IDN_ACTIVE_ICC_LVL, 0, 0, 0x10, &utrd,
68449ccea4bSYoochan Jeong &rsp_upiu);
68549ccea4bSYoochan Jeong g_assert_cmpuint(le32_to_cpu(utrd.header.dword_2), ==,
68649ccea4bSYoochan Jeong UFS_OCS_INVALID_CMD_TABLE_ATTR);
68749ccea4bSYoochan Jeong g_assert_cmpuint(rsp_upiu.header.response, ==,
68849ccea4bSYoochan Jeong UFS_QUERY_RESULT_INVALID_VALUE);
68949ccea4bSYoochan Jeong
69049ccea4bSYoochan Jeong ufs_send_query(ufs, 0, UFS_UPIU_QUERY_FUNC_STANDARD_READ_REQUEST,
69149ccea4bSYoochan Jeong UFS_UPIU_QUERY_OPCODE_READ_ATTR,
69249ccea4bSYoochan Jeong UFS_QUERY_ATTR_IDN_ACTIVE_ICC_LVL, 0, 0, 0, &utrd,
69349ccea4bSYoochan Jeong &rsp_upiu);
69449ccea4bSYoochan Jeong g_assert_cmpuint(le32_to_cpu(utrd.header.dword_2), ==, UFS_OCS_SUCCESS);
69549ccea4bSYoochan Jeong g_assert_cmpuint(rsp_upiu.header.response, ==, UFS_COMMAND_RESULT_SUCCESS);
69649ccea4bSYoochan Jeong g_assert_cmpuint(rsp_upiu.qr.value, ==, cpu_to_be32(0x03));
69749ccea4bSYoochan Jeong
69849ccea4bSYoochan Jeong /* Read Write-Only Attribute (Intended Error) */
69949ccea4bSYoochan Jeong ufs_send_query(ufs, 0, UFS_UPIU_QUERY_FUNC_STANDARD_READ_REQUEST,
70049ccea4bSYoochan Jeong UFS_UPIU_QUERY_OPCODE_READ_ATTR,
70149ccea4bSYoochan Jeong UFS_QUERY_ATTR_IDN_SECONDS_PASSED, 0, 0, 0, &utrd,
70249ccea4bSYoochan Jeong &rsp_upiu);
70349ccea4bSYoochan Jeong g_assert_cmpuint(le32_to_cpu(utrd.header.dword_2), ==,
70449ccea4bSYoochan Jeong UFS_OCS_INVALID_CMD_TABLE_ATTR);
70549ccea4bSYoochan Jeong g_assert_cmpuint(rsp_upiu.header.response, ==,
70649ccea4bSYoochan Jeong UFS_QUERY_RESULT_NOT_READABLE);
70749ccea4bSYoochan Jeong
70849ccea4bSYoochan Jeong /* Write Read-Only Attribute (Intended Error) */
70949ccea4bSYoochan Jeong ufs_send_query(ufs, 0, UFS_UPIU_QUERY_FUNC_STANDARD_WRITE_REQUEST,
71049ccea4bSYoochan Jeong UFS_UPIU_QUERY_OPCODE_WRITE_ATTR,
71149ccea4bSYoochan Jeong UFS_QUERY_ATTR_IDN_POWER_MODE, 0, 0, 0x01, &utrd, &rsp_upiu);
71249ccea4bSYoochan Jeong g_assert_cmpuint(le32_to_cpu(utrd.header.dword_2), ==,
71349ccea4bSYoochan Jeong UFS_OCS_INVALID_CMD_TABLE_ATTR);
71449ccea4bSYoochan Jeong g_assert_cmpuint(rsp_upiu.header.response, ==,
71549ccea4bSYoochan Jeong UFS_QUERY_RESULT_NOT_WRITEABLE);
71649ccea4bSYoochan Jeong
71749ccea4bSYoochan Jeong ufs_send_query(ufs, 0, UFS_UPIU_QUERY_FUNC_STANDARD_READ_REQUEST,
71849ccea4bSYoochan Jeong UFS_UPIU_QUERY_OPCODE_READ_ATTR,
71949ccea4bSYoochan Jeong UFS_QUERY_ATTR_IDN_POWER_MODE, 0, 0, 0, &utrd, &rsp_upiu);
72049ccea4bSYoochan Jeong g_assert_cmpuint(le32_to_cpu(utrd.header.dword_2), ==, UFS_OCS_SUCCESS);
72149ccea4bSYoochan Jeong g_assert_cmpuint(rsp_upiu.header.response, ==, UFS_COMMAND_RESULT_SUCCESS);
72249ccea4bSYoochan Jeong g_assert_cmpuint(rsp_upiu.qr.value, ==, cpu_to_be32(0x00));
72349ccea4bSYoochan Jeong
72449ccea4bSYoochan Jeong /* Reset Written Attributes */
72549ccea4bSYoochan Jeong ufs_send_query(ufs, 0, UFS_UPIU_QUERY_FUNC_STANDARD_WRITE_REQUEST,
72649ccea4bSYoochan Jeong UFS_UPIU_QUERY_OPCODE_WRITE_ATTR,
72749ccea4bSYoochan Jeong UFS_QUERY_ATTR_IDN_ACTIVE_ICC_LVL, 0, 0, 0, &utrd,
72849ccea4bSYoochan Jeong &rsp_upiu);
72949ccea4bSYoochan Jeong g_assert_cmpuint(le32_to_cpu(utrd.header.dword_2), ==, UFS_OCS_SUCCESS);
73049ccea4bSYoochan Jeong g_assert_cmpuint(rsp_upiu.header.response, ==, UFS_COMMAND_RESULT_SUCCESS);
73149ccea4bSYoochan Jeong g_assert_cmpuint(rsp_upiu.qr.value, ==, cpu_to_be32(0x00));
73249ccea4bSYoochan Jeong
73349ccea4bSYoochan Jeong ufs_send_query(ufs, 0, UFS_UPIU_QUERY_FUNC_STANDARD_WRITE_REQUEST,
73449ccea4bSYoochan Jeong UFS_UPIU_QUERY_OPCODE_WRITE_ATTR,
73549ccea4bSYoochan Jeong UFS_QUERY_ATTR_IDN_EE_CONTROL, 0, 0, 0, &utrd, &rsp_upiu);
73649ccea4bSYoochan Jeong g_assert_cmpuint(le32_to_cpu(utrd.header.dword_2), ==, UFS_OCS_SUCCESS);
73749ccea4bSYoochan Jeong g_assert_cmpuint(rsp_upiu.header.response, ==, UFS_COMMAND_RESULT_SUCCESS);
73849ccea4bSYoochan Jeong g_assert_cmpuint(rsp_upiu.qr.value, ==, cpu_to_be32(0x00));
73949ccea4bSYoochan Jeong
74049ccea4bSYoochan Jeong ufs_send_query(ufs, 0, UFS_UPIU_QUERY_FUNC_STANDARD_READ_REQUEST,
74149ccea4bSYoochan Jeong UFS_UPIU_QUERY_OPCODE_READ_ATTR,
74249ccea4bSYoochan Jeong UFS_QUERY_ATTR_IDN_ACTIVE_ICC_LVL, 0, 0, 0, &utrd,
74349ccea4bSYoochan Jeong &rsp_upiu);
74449ccea4bSYoochan Jeong g_assert_cmpuint(le32_to_cpu(utrd.header.dword_2), ==, 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 ufs_send_query(ufs, 0, UFS_UPIU_QUERY_FUNC_STANDARD_READ_REQUEST,
74949ccea4bSYoochan Jeong UFS_UPIU_QUERY_OPCODE_READ_ATTR,
75049ccea4bSYoochan Jeong UFS_QUERY_ATTR_IDN_EE_CONTROL, 0, 0, 0, &utrd, &rsp_upiu);
75149ccea4bSYoochan Jeong g_assert_cmpuint(le32_to_cpu(utrd.header.dword_2), ==, UFS_OCS_SUCCESS);
75249ccea4bSYoochan Jeong g_assert_cmpuint(rsp_upiu.header.response, ==, UFS_COMMAND_RESULT_SUCCESS);
75349ccea4bSYoochan Jeong g_assert_cmpuint(rsp_upiu.qr.value, ==, cpu_to_be32(0x00));
75449ccea4bSYoochan Jeong
75549ccea4bSYoochan Jeong ufs_exit(ufs, alloc);
75649ccea4bSYoochan Jeong }
75749ccea4bSYoochan Jeong
ufstest_query_desc_request(void * obj,void * data,QGuestAllocator * alloc)7589fe8e2c6SYoochan Jeong static void ufstest_query_desc_request(void *obj, void *data,
7599fe8e2c6SYoochan Jeong QGuestAllocator *alloc)
7609fe8e2c6SYoochan Jeong {
7619fe8e2c6SYoochan Jeong QUfs *ufs = obj;
7629fe8e2c6SYoochan Jeong
7639fe8e2c6SYoochan Jeong UtpTransferReqDesc utrd;
7649fe8e2c6SYoochan Jeong UtpUpiuRsp rsp_upiu;
7659fe8e2c6SYoochan Jeong ufs_init(ufs, alloc);
7669fe8e2c6SYoochan Jeong
7679fe8e2c6SYoochan Jeong /* Write Descriptor is not supported yet */
7689fe8e2c6SYoochan Jeong
7699fe8e2c6SYoochan Jeong /* Read Device Descriptor */
7709fe8e2c6SYoochan Jeong ufs_send_query(ufs, 0, UFS_UPIU_QUERY_FUNC_STANDARD_READ_REQUEST,
7719fe8e2c6SYoochan Jeong UFS_UPIU_QUERY_OPCODE_READ_DESC, UFS_QUERY_DESC_IDN_DEVICE,
7729fe8e2c6SYoochan Jeong 0, 0, 0, &utrd, &rsp_upiu);
7739fe8e2c6SYoochan Jeong g_assert_cmpuint(le32_to_cpu(utrd.header.dword_2), ==, UFS_OCS_SUCCESS);
7749fe8e2c6SYoochan Jeong g_assert_cmpuint(rsp_upiu.header.response, ==, UFS_COMMAND_RESULT_SUCCESS);
7759fe8e2c6SYoochan Jeong g_assert_cmpuint(rsp_upiu.qr.opcode, ==, UFS_UPIU_QUERY_OPCODE_READ_DESC);
7769fe8e2c6SYoochan Jeong g_assert_cmpuint(rsp_upiu.qr.idn, ==, UFS_QUERY_DESC_IDN_DEVICE);
7779fe8e2c6SYoochan Jeong g_assert_cmpuint(rsp_upiu.qr.data[0], ==, sizeof(DeviceDescriptor));
7789fe8e2c6SYoochan Jeong g_assert_cmpuint(rsp_upiu.qr.data[1], ==, UFS_QUERY_DESC_IDN_DEVICE);
7799fe8e2c6SYoochan Jeong
7809fe8e2c6SYoochan Jeong /* Read Configuration Descriptor is not supported yet*/
7819fe8e2c6SYoochan Jeong
7829fe8e2c6SYoochan Jeong /* Read Unit Descriptor */
7839fe8e2c6SYoochan Jeong ufs_send_query(ufs, 0, UFS_UPIU_QUERY_FUNC_STANDARD_READ_REQUEST,
7849fe8e2c6SYoochan Jeong UFS_UPIU_QUERY_OPCODE_READ_DESC, UFS_QUERY_DESC_IDN_UNIT, 0,
7859fe8e2c6SYoochan Jeong 0, 0, &utrd, &rsp_upiu);
7869fe8e2c6SYoochan Jeong g_assert_cmpuint(le32_to_cpu(utrd.header.dword_2), ==, UFS_OCS_SUCCESS);
7879fe8e2c6SYoochan Jeong g_assert_cmpuint(rsp_upiu.header.response, ==, UFS_COMMAND_RESULT_SUCCESS);
7889fe8e2c6SYoochan Jeong g_assert_cmpuint(rsp_upiu.qr.data[0], ==, sizeof(UnitDescriptor));
7899fe8e2c6SYoochan Jeong g_assert_cmpuint(rsp_upiu.qr.data[1], ==, UFS_QUERY_DESC_IDN_UNIT);
7909fe8e2c6SYoochan Jeong g_assert_cmpuint(rsp_upiu.qr.data[2], ==, 0);
7919fe8e2c6SYoochan Jeong
7929fe8e2c6SYoochan Jeong ufs_send_query(ufs, 0, UFS_UPIU_QUERY_FUNC_STANDARD_READ_REQUEST,
7939fe8e2c6SYoochan Jeong UFS_UPIU_QUERY_OPCODE_READ_DESC, UFS_QUERY_DESC_IDN_UNIT, 1,
7949fe8e2c6SYoochan Jeong 0, 0, &utrd, &rsp_upiu);
7959fe8e2c6SYoochan Jeong g_assert_cmpuint(le32_to_cpu(utrd.header.dword_2), ==, UFS_OCS_SUCCESS);
7969fe8e2c6SYoochan Jeong g_assert_cmpuint(rsp_upiu.header.response, ==, UFS_COMMAND_RESULT_SUCCESS);
7979fe8e2c6SYoochan Jeong g_assert_cmpuint(rsp_upiu.qr.data[0], ==, sizeof(UnitDescriptor));
7989fe8e2c6SYoochan Jeong g_assert_cmpuint(rsp_upiu.qr.data[1], ==, UFS_QUERY_DESC_IDN_UNIT);
7999fe8e2c6SYoochan Jeong g_assert_cmpuint(rsp_upiu.qr.data[2], ==, 1);
8009fe8e2c6SYoochan Jeong
8019fe8e2c6SYoochan Jeong ufs_send_query(ufs, 0, UFS_UPIU_QUERY_FUNC_STANDARD_READ_REQUEST,
8029fe8e2c6SYoochan Jeong UFS_UPIU_QUERY_OPCODE_READ_DESC, UFS_QUERY_DESC_IDN_UNIT,
8039fe8e2c6SYoochan Jeong UFS_UPIU_RPMB_WLUN, 0, 0, &utrd, &rsp_upiu);
8049fe8e2c6SYoochan Jeong g_assert_cmpuint(le32_to_cpu(utrd.header.dword_2), ==, UFS_OCS_SUCCESS);
8059fe8e2c6SYoochan Jeong g_assert_cmpuint(rsp_upiu.header.response, ==, UFS_COMMAND_RESULT_SUCCESS);
8069fe8e2c6SYoochan Jeong g_assert_cmpuint(rsp_upiu.qr.data[0], ==, sizeof(RpmbUnitDescriptor));
8079fe8e2c6SYoochan Jeong g_assert_cmpuint(rsp_upiu.qr.data[1], ==, UFS_QUERY_DESC_IDN_UNIT);
8089fe8e2c6SYoochan Jeong g_assert_cmpuint(rsp_upiu.qr.data[2], ==, UFS_UPIU_RPMB_WLUN);
8099fe8e2c6SYoochan Jeong
8109fe8e2c6SYoochan Jeong /* Read Interconnect Descriptor */
8119fe8e2c6SYoochan Jeong ufs_send_query(ufs, 0, UFS_UPIU_QUERY_FUNC_STANDARD_READ_REQUEST,
8129fe8e2c6SYoochan Jeong UFS_UPIU_QUERY_OPCODE_READ_DESC,
8139fe8e2c6SYoochan Jeong UFS_QUERY_DESC_IDN_INTERCONNECT, 0, 0, 0, &utrd, &rsp_upiu);
8149fe8e2c6SYoochan Jeong g_assert_cmpuint(le32_to_cpu(utrd.header.dword_2), ==, UFS_OCS_SUCCESS);
8159fe8e2c6SYoochan Jeong g_assert_cmpuint(rsp_upiu.header.response, ==, UFS_COMMAND_RESULT_SUCCESS);
8169fe8e2c6SYoochan Jeong g_assert_cmpuint(rsp_upiu.qr.data[0], ==, sizeof(InterconnectDescriptor));
8179fe8e2c6SYoochan Jeong g_assert_cmpuint(rsp_upiu.qr.data[1], ==, UFS_QUERY_DESC_IDN_INTERCONNECT);
8189fe8e2c6SYoochan Jeong
8199fe8e2c6SYoochan Jeong /* Read String Descriptor */
8209fe8e2c6SYoochan Jeong ufs_send_query(ufs, 0, UFS_UPIU_QUERY_FUNC_STANDARD_READ_REQUEST,
8219fe8e2c6SYoochan Jeong UFS_UPIU_QUERY_OPCODE_READ_DESC, UFS_QUERY_DESC_IDN_STRING,
8229fe8e2c6SYoochan Jeong 0, 0, 0, &utrd, &rsp_upiu);
8239fe8e2c6SYoochan Jeong g_assert_cmpuint(le32_to_cpu(utrd.header.dword_2), ==, UFS_OCS_SUCCESS);
8249fe8e2c6SYoochan Jeong g_assert_cmpuint(rsp_upiu.header.response, ==, UFS_COMMAND_RESULT_SUCCESS);
8259fe8e2c6SYoochan Jeong g_assert_cmpuint(rsp_upiu.qr.data[0], ==, 0x12);
8269fe8e2c6SYoochan Jeong g_assert_cmpuint(rsp_upiu.qr.data[1], ==, UFS_QUERY_DESC_IDN_STRING);
8279fe8e2c6SYoochan Jeong
8289fe8e2c6SYoochan Jeong ufs_send_query(ufs, 0, UFS_UPIU_QUERY_FUNC_STANDARD_READ_REQUEST,
8299fe8e2c6SYoochan Jeong UFS_UPIU_QUERY_OPCODE_READ_DESC, UFS_QUERY_DESC_IDN_STRING,
8309fe8e2c6SYoochan Jeong 1, 0, 0, &utrd, &rsp_upiu);
8319fe8e2c6SYoochan Jeong g_assert_cmpuint(le32_to_cpu(utrd.header.dword_2), ==, UFS_OCS_SUCCESS);
8329fe8e2c6SYoochan Jeong g_assert_cmpuint(rsp_upiu.header.response, ==, UFS_COMMAND_RESULT_SUCCESS);
8339fe8e2c6SYoochan Jeong g_assert_cmpuint(rsp_upiu.qr.data[0], ==, 0x22);
8349fe8e2c6SYoochan Jeong g_assert_cmpuint(rsp_upiu.qr.data[1], ==, UFS_QUERY_DESC_IDN_STRING);
8359fe8e2c6SYoochan Jeong
8369fe8e2c6SYoochan Jeong ufs_send_query(ufs, 0, UFS_UPIU_QUERY_FUNC_STANDARD_READ_REQUEST,
8379fe8e2c6SYoochan Jeong UFS_UPIU_QUERY_OPCODE_READ_DESC, UFS_QUERY_DESC_IDN_STRING,
8389fe8e2c6SYoochan Jeong 4, 0, 0, &utrd, &rsp_upiu);
8399fe8e2c6SYoochan Jeong g_assert_cmpuint(le32_to_cpu(utrd.header.dword_2), ==, UFS_OCS_SUCCESS);
8409fe8e2c6SYoochan Jeong g_assert_cmpuint(rsp_upiu.header.response, ==, UFS_COMMAND_RESULT_SUCCESS);
8419fe8e2c6SYoochan Jeong g_assert_cmpuint(rsp_upiu.qr.data[0], ==, 0x0a);
8429fe8e2c6SYoochan Jeong g_assert_cmpuint(rsp_upiu.qr.data[1], ==, UFS_QUERY_DESC_IDN_STRING);
8439fe8e2c6SYoochan Jeong
8449fe8e2c6SYoochan Jeong /* Read Geometry Descriptor */
8459fe8e2c6SYoochan Jeong ufs_send_query(ufs, 0, UFS_UPIU_QUERY_FUNC_STANDARD_READ_REQUEST,
8469fe8e2c6SYoochan Jeong UFS_UPIU_QUERY_OPCODE_READ_DESC, UFS_QUERY_DESC_IDN_GEOMETRY,
8479fe8e2c6SYoochan Jeong 0, 0, 0, &utrd, &rsp_upiu);
8489fe8e2c6SYoochan Jeong g_assert_cmpuint(le32_to_cpu(utrd.header.dword_2), ==, UFS_OCS_SUCCESS);
8499fe8e2c6SYoochan Jeong g_assert_cmpuint(rsp_upiu.header.response, ==, UFS_COMMAND_RESULT_SUCCESS);
8509fe8e2c6SYoochan Jeong g_assert_cmpuint(rsp_upiu.qr.data[0], ==, sizeof(GeometryDescriptor));
8519fe8e2c6SYoochan Jeong g_assert_cmpuint(rsp_upiu.qr.data[1], ==, UFS_QUERY_DESC_IDN_GEOMETRY);
8529fe8e2c6SYoochan Jeong
8539fe8e2c6SYoochan Jeong /* Read Power Descriptor */
8549fe8e2c6SYoochan Jeong ufs_send_query(ufs, 0, UFS_UPIU_QUERY_FUNC_STANDARD_READ_REQUEST,
8559fe8e2c6SYoochan Jeong UFS_UPIU_QUERY_OPCODE_READ_DESC, UFS_QUERY_DESC_IDN_POWER, 0,
8569fe8e2c6SYoochan Jeong 0, 0, &utrd, &rsp_upiu);
8579fe8e2c6SYoochan Jeong g_assert_cmpuint(le32_to_cpu(utrd.header.dword_2), ==, UFS_OCS_SUCCESS);
8589fe8e2c6SYoochan Jeong g_assert_cmpuint(rsp_upiu.header.response, ==, UFS_COMMAND_RESULT_SUCCESS);
8599fe8e2c6SYoochan Jeong g_assert_cmpuint(rsp_upiu.qr.data[0], ==,
8609fe8e2c6SYoochan Jeong sizeof(PowerParametersDescriptor));
8619fe8e2c6SYoochan Jeong g_assert_cmpuint(rsp_upiu.qr.data[1], ==, UFS_QUERY_DESC_IDN_POWER);
8629fe8e2c6SYoochan Jeong
8639fe8e2c6SYoochan Jeong /* Read Health Descriptor */
8649fe8e2c6SYoochan Jeong ufs_send_query(ufs, 0, UFS_UPIU_QUERY_FUNC_STANDARD_READ_REQUEST,
8659fe8e2c6SYoochan Jeong UFS_UPIU_QUERY_OPCODE_READ_DESC, UFS_QUERY_DESC_IDN_HEALTH,
8669fe8e2c6SYoochan Jeong 0, 0, 0, &utrd, &rsp_upiu);
8679fe8e2c6SYoochan Jeong g_assert_cmpuint(le32_to_cpu(utrd.header.dword_2), ==, UFS_OCS_SUCCESS);
8689fe8e2c6SYoochan Jeong g_assert_cmpuint(rsp_upiu.header.response, ==, UFS_COMMAND_RESULT_SUCCESS);
8699fe8e2c6SYoochan Jeong g_assert_cmpuint(rsp_upiu.qr.data[0], ==, sizeof(DeviceHealthDescriptor));
8709fe8e2c6SYoochan Jeong g_assert_cmpuint(rsp_upiu.qr.data[1], ==, UFS_QUERY_DESC_IDN_HEALTH);
8719fe8e2c6SYoochan Jeong
8729fe8e2c6SYoochan Jeong /* Invalid Index (Intended Failure) */
8739fe8e2c6SYoochan Jeong ufs_send_query(ufs, 0, UFS_UPIU_QUERY_FUNC_STANDARD_READ_REQUEST,
8749fe8e2c6SYoochan Jeong UFS_UPIU_QUERY_OPCODE_READ_DESC, UFS_QUERY_DESC_IDN_UNIT, 4,
8759fe8e2c6SYoochan Jeong 0, 0, &utrd, &rsp_upiu);
8769fe8e2c6SYoochan Jeong g_assert_cmpuint(le32_to_cpu(utrd.header.dword_2), ==,
8779fe8e2c6SYoochan Jeong UFS_OCS_INVALID_CMD_TABLE_ATTR);
8789fe8e2c6SYoochan Jeong g_assert_cmpuint(rsp_upiu.header.response, ==,
8799fe8e2c6SYoochan Jeong UFS_QUERY_RESULT_INVALID_INDEX);
8809fe8e2c6SYoochan Jeong
8819fe8e2c6SYoochan Jeong ufs_send_query(ufs, 0, UFS_UPIU_QUERY_FUNC_STANDARD_READ_REQUEST,
8829fe8e2c6SYoochan Jeong UFS_UPIU_QUERY_OPCODE_READ_DESC, UFS_QUERY_DESC_IDN_STRING,
8839fe8e2c6SYoochan Jeong 5, 0, 0, &utrd, &rsp_upiu);
8849fe8e2c6SYoochan Jeong g_assert_cmpuint(le32_to_cpu(utrd.header.dword_2), ==,
8859fe8e2c6SYoochan Jeong UFS_OCS_INVALID_CMD_TABLE_ATTR);
8869fe8e2c6SYoochan Jeong g_assert_cmpuint(rsp_upiu.header.response, ==,
8879fe8e2c6SYoochan Jeong UFS_QUERY_RESULT_INVALID_INDEX);
8889fe8e2c6SYoochan Jeong
8899fe8e2c6SYoochan Jeong /* Invalid Selector (Intended Failure) */
8909fe8e2c6SYoochan Jeong ufs_send_query(ufs, 0, UFS_UPIU_QUERY_FUNC_STANDARD_READ_REQUEST,
8919fe8e2c6SYoochan Jeong UFS_UPIU_QUERY_OPCODE_READ_DESC, UFS_QUERY_DESC_IDN_DEVICE,
8929fe8e2c6SYoochan Jeong 0, 1, 0, &utrd, &rsp_upiu);
8939fe8e2c6SYoochan Jeong g_assert_cmpuint(le32_to_cpu(utrd.header.dword_2), ==,
8949fe8e2c6SYoochan Jeong UFS_OCS_INVALID_CMD_TABLE_ATTR);
8959fe8e2c6SYoochan Jeong g_assert_cmpuint(rsp_upiu.header.response, ==,
8969fe8e2c6SYoochan Jeong UFS_QUERY_RESULT_INVALID_SELECTOR);
8979fe8e2c6SYoochan Jeong
8989fe8e2c6SYoochan Jeong ufs_send_query(ufs, 0, UFS_UPIU_QUERY_FUNC_STANDARD_READ_REQUEST,
8999fe8e2c6SYoochan Jeong UFS_UPIU_QUERY_OPCODE_READ_DESC, UFS_QUERY_DESC_IDN_STRING,
9009fe8e2c6SYoochan Jeong 0, 1, 0, &utrd, &rsp_upiu);
9019fe8e2c6SYoochan Jeong g_assert_cmpuint(le32_to_cpu(utrd.header.dword_2), ==,
9029fe8e2c6SYoochan Jeong UFS_OCS_INVALID_CMD_TABLE_ATTR);
9039fe8e2c6SYoochan Jeong g_assert_cmpuint(rsp_upiu.header.response, ==,
9049fe8e2c6SYoochan Jeong UFS_QUERY_RESULT_INVALID_SELECTOR);
9059fe8e2c6SYoochan Jeong
9069fe8e2c6SYoochan Jeong ufs_exit(ufs, alloc);
9079fe8e2c6SYoochan Jeong }
9089fe8e2c6SYoochan Jeong
drive_destroy(void * path)909631c8726SJeuk Kim static void drive_destroy(void *path)
910631c8726SJeuk Kim {
911631c8726SJeuk Kim unlink(path);
912631c8726SJeuk Kim g_free(path);
913631c8726SJeuk Kim qos_invalidate_command_line();
914631c8726SJeuk Kim }
915631c8726SJeuk Kim
drive_create(void)916631c8726SJeuk Kim static char *drive_create(void)
917631c8726SJeuk Kim {
918631c8726SJeuk Kim int fd, ret;
919631c8726SJeuk Kim char *t_path;
920631c8726SJeuk Kim
921631c8726SJeuk Kim /* Create a temporary raw image */
922631c8726SJeuk Kim fd = g_file_open_tmp("qtest-ufs.XXXXXX", &t_path, NULL);
923631c8726SJeuk Kim g_assert_cmpint(fd, >=, 0);
924631c8726SJeuk Kim ret = ftruncate(fd, TEST_IMAGE_SIZE);
925631c8726SJeuk Kim g_assert_cmpint(ret, ==, 0);
926631c8726SJeuk Kim close(fd);
927631c8726SJeuk Kim
928631c8726SJeuk Kim g_test_queue_destroy(drive_destroy, t_path);
929631c8726SJeuk Kim return t_path;
930631c8726SJeuk Kim }
931631c8726SJeuk Kim
ufs_blk_test_setup(GString * cmd_line,void * arg)932631c8726SJeuk Kim static void *ufs_blk_test_setup(GString *cmd_line, void *arg)
933631c8726SJeuk Kim {
934631c8726SJeuk Kim char *tmp_path = drive_create();
935631c8726SJeuk Kim
936631c8726SJeuk Kim g_string_append_printf(cmd_line,
937631c8726SJeuk Kim " -blockdev file,filename=%s,node-name=drv1 "
938631c8726SJeuk Kim "-device ufs-lu,bus=ufs0,drive=drv1,lun=1 ",
939631c8726SJeuk Kim tmp_path);
940631c8726SJeuk Kim
941631c8726SJeuk Kim return arg;
942631c8726SJeuk Kim }
943631c8726SJeuk Kim
ufs_register_nodes(void)944631c8726SJeuk Kim static void ufs_register_nodes(void)
945631c8726SJeuk Kim {
946631c8726SJeuk Kim const char *arch;
947631c8726SJeuk Kim QOSGraphEdgeOptions edge_opts = {
948631c8726SJeuk Kim .before_cmd_line = "-blockdev null-co,node-name=drv0,read-zeroes=on",
949631c8726SJeuk Kim .after_cmd_line = "-device ufs-lu,bus=ufs0,drive=drv0,lun=0",
950631c8726SJeuk Kim .extra_device_opts = "addr=04.0,id=ufs0,nutrs=32,nutmrs=8"
951631c8726SJeuk Kim };
952631c8726SJeuk Kim
953631c8726SJeuk Kim QOSGraphTestOptions io_test_opts = {
954631c8726SJeuk Kim .before = ufs_blk_test_setup,
955631c8726SJeuk Kim };
956631c8726SJeuk Kim
957631c8726SJeuk Kim add_qpci_address(&edge_opts, &(QPCIAddress){ .devfn = QPCI_DEVFN(4, 0) });
958631c8726SJeuk Kim
959631c8726SJeuk Kim qos_node_create_driver("ufs", ufs_create);
960631c8726SJeuk Kim qos_node_consumes("ufs", "pci-bus", &edge_opts);
961631c8726SJeuk Kim qos_node_produces("ufs", "pci-device");
962631c8726SJeuk Kim
963631c8726SJeuk Kim qos_add_test("reg-read", "ufs", ufstest_reg_read, NULL);
964631c8726SJeuk Kim
965631c8726SJeuk Kim /*
966631c8726SJeuk Kim * Check architecture
967631c8726SJeuk Kim * TODO: Enable ufs io tests for ppc64
968631c8726SJeuk Kim */
969631c8726SJeuk Kim arch = qtest_get_arch();
970631c8726SJeuk Kim if (!strcmp(arch, "ppc64")) {
971631c8726SJeuk Kim g_test_message("Skipping ufs io tests for ppc64");
972631c8726SJeuk Kim return;
973631c8726SJeuk Kim }
974631c8726SJeuk Kim qos_add_test("init", "ufs", ufstest_init, NULL);
975631c8726SJeuk Kim qos_add_test("read-write", "ufs", ufstest_read_write, &io_test_opts);
9764aac3029SYoochan Jeong qos_add_test("flag read-write", "ufs",
9774aac3029SYoochan Jeong ufstest_query_flag_request, &io_test_opts);
97849ccea4bSYoochan Jeong qos_add_test("attr read-write", "ufs",
97949ccea4bSYoochan Jeong ufstest_query_attr_request, &io_test_opts);
9809fe8e2c6SYoochan Jeong qos_add_test("desc read-write", "ufs",
9819fe8e2c6SYoochan Jeong ufstest_query_desc_request, &io_test_opts);
982631c8726SJeuk Kim }
983631c8726SJeuk Kim
984631c8726SJeuk Kim libqos_init(ufs_register_nodes);
985