tests/qtest: Introduce tests for UFS
[qemu/kevin.git] / tests / qtest / ufs-test.c
blobed3dbca15497a3823c2dcc223b1e0e604dc7ab30
1 /*
2 * QTest testcase for UFS
4 * Copyright (c) 2023 Samsung Electronics Co., Ltd. All rights reserved.
6 * SPDX-License-Identifier: GPL-2.0-or-later
7 */
9 #include "qemu/osdep.h"
10 #include "qemu/module.h"
11 #include "qemu/units.h"
12 #include "libqtest.h"
13 #include "libqos/qgraph.h"
14 #include "libqos/pci.h"
15 #include "scsi/constants.h"
16 #include "include/block/ufs.h"
18 /* Test images sizes in Bytes */
19 #define TEST_IMAGE_SIZE (64 * 1024 * 1024)
20 /* Timeout for various operations, in seconds. */
21 #define TIMEOUT_SECONDS 10
22 /* Maximum PRD entry count */
23 #define MAX_PRD_ENTRY_COUNT 10
24 #define PRD_ENTRY_DATA_SIZE 4096
25 /* Constants to build upiu */
26 #define UTP_COMMAND_DESCRIPTOR_SIZE 4096
27 #define UTP_RESPONSE_UPIU_OFFSET 1024
28 #define UTP_PRDT_UPIU_OFFSET 2048
30 typedef struct QUfs QUfs;
32 struct QUfs {
33 QOSGraphObject obj;
34 QPCIDevice dev;
35 QPCIBar bar;
37 uint64_t utrlba;
38 uint64_t utmrlba;
39 uint64_t cmd_desc_addr;
40 uint64_t data_buffer_addr;
42 bool enabled;
45 static inline uint32_t ufs_rreg(QUfs *ufs, size_t offset)
47 return qpci_io_readl(&ufs->dev, ufs->bar, offset);
50 static inline void ufs_wreg(QUfs *ufs, size_t offset, uint32_t value)
52 qpci_io_writel(&ufs->dev, ufs->bar, offset, value);
55 static void ufs_wait_for_irq(QUfs *ufs)
57 uint64_t end_time;
58 uint32_t is;
59 /* Wait for device to reset as the linux driver does. */
60 end_time = g_get_monotonic_time() + TIMEOUT_SECONDS * G_TIME_SPAN_SECOND;
61 do {
62 qtest_clock_step(ufs->dev.bus->qts, 100);
63 is = ufs_rreg(ufs, A_IS);
64 } while (is == 0 && g_get_monotonic_time() < end_time);
67 static UtpTransferReqDesc ufs_build_req_utrd(uint64_t cmd_desc_addr,
68 uint8_t slot,
69 uint32_t data_direction,
70 uint16_t prd_table_length)
72 UtpTransferReqDesc req = { 0 };
73 uint64_t command_desc_base_addr =
74 cmd_desc_addr + slot * UTP_COMMAND_DESCRIPTOR_SIZE;
76 req.header.dword_0 =
77 cpu_to_le32(1 << 28 | data_direction | UFS_UTP_REQ_DESC_INT_CMD);
78 req.header.dword_2 = cpu_to_le32(UFS_OCS_INVALID_COMMAND_STATUS);
80 req.command_desc_base_addr_hi = cpu_to_le32(command_desc_base_addr >> 32);
81 req.command_desc_base_addr_lo =
82 cpu_to_le32(command_desc_base_addr & 0xffffffff);
83 req.response_upiu_offset =
84 cpu_to_le16(UTP_RESPONSE_UPIU_OFFSET / sizeof(uint32_t));
85 req.response_upiu_length = cpu_to_le16(sizeof(UtpUpiuRsp));
86 req.prd_table_offset = cpu_to_le16(UTP_PRDT_UPIU_OFFSET / sizeof(uint32_t));
87 req.prd_table_length = cpu_to_le16(prd_table_length);
88 return req;
91 static void ufs_send_nop_out(QUfs *ufs, uint8_t slot,
92 UtpTransferReqDesc *utrd_out, UtpUpiuRsp *rsp_out)
94 /* Build up utp transfer request descriptor */
95 UtpTransferReqDesc utrd = ufs_build_req_utrd(ufs->cmd_desc_addr, slot,
96 UFS_UTP_NO_DATA_TRANSFER, 0);
97 uint64_t utrd_addr = ufs->utrlba + slot * sizeof(UtpTransferReqDesc);
98 uint64_t req_upiu_addr =
99 ufs->cmd_desc_addr + slot * UTP_COMMAND_DESCRIPTOR_SIZE;
100 uint64_t rsp_upiu_addr = req_upiu_addr + UTP_RESPONSE_UPIU_OFFSET;
101 qtest_memwrite(ufs->dev.bus->qts, utrd_addr, &utrd, sizeof(utrd));
103 /* Build up request upiu */
104 UtpUpiuReq req_upiu = { 0 };
105 req_upiu.header.trans_type = UFS_UPIU_TRANSACTION_NOP_OUT;
106 req_upiu.header.task_tag = slot;
107 qtest_memwrite(ufs->dev.bus->qts, req_upiu_addr, &req_upiu,
108 sizeof(req_upiu));
110 /* Ring Doorbell */
111 ufs_wreg(ufs, A_UTRLDBR, 1);
112 ufs_wait_for_irq(ufs);
113 g_assert_true(FIELD_EX32(ufs_rreg(ufs, A_IS), IS, UTRCS));
114 ufs_wreg(ufs, A_IS, FIELD_DP32(0, IS, UTRCS, 1));
116 qtest_memread(ufs->dev.bus->qts, utrd_addr, utrd_out, sizeof(*utrd_out));
117 qtest_memread(ufs->dev.bus->qts, rsp_upiu_addr, rsp_out, sizeof(*rsp_out));
120 static void ufs_send_query(QUfs *ufs, uint8_t slot, uint8_t query_function,
121 uint8_t query_opcode, uint8_t idn, uint8_t index,
122 UtpTransferReqDesc *utrd_out, UtpUpiuRsp *rsp_out)
124 /* Build up utp transfer request descriptor */
125 UtpTransferReqDesc utrd = ufs_build_req_utrd(ufs->cmd_desc_addr, slot,
126 UFS_UTP_NO_DATA_TRANSFER, 0);
127 uint64_t utrd_addr = ufs->utrlba + slot * sizeof(UtpTransferReqDesc);
128 uint64_t req_upiu_addr =
129 ufs->cmd_desc_addr + slot * UTP_COMMAND_DESCRIPTOR_SIZE;
130 uint64_t rsp_upiu_addr = req_upiu_addr + UTP_RESPONSE_UPIU_OFFSET;
131 qtest_memwrite(ufs->dev.bus->qts, utrd_addr, &utrd, sizeof(utrd));
133 /* Build up request upiu */
134 UtpUpiuReq req_upiu = { 0 };
135 req_upiu.header.trans_type = UFS_UPIU_TRANSACTION_QUERY_REQ;
136 req_upiu.header.query_func = query_function;
137 req_upiu.header.task_tag = slot;
139 * QEMU UFS does not currently support Write descriptor and Write attribute,
140 * so the value of data_segment_length is always 0.
142 req_upiu.header.data_segment_length = 0;
143 req_upiu.qr.opcode = query_opcode;
144 req_upiu.qr.idn = idn;
145 req_upiu.qr.index = index;
146 qtest_memwrite(ufs->dev.bus->qts, req_upiu_addr, &req_upiu,
147 sizeof(req_upiu));
149 /* Ring Doorbell */
150 ufs_wreg(ufs, A_UTRLDBR, 1);
151 ufs_wait_for_irq(ufs);
152 g_assert_true(FIELD_EX32(ufs_rreg(ufs, A_IS), IS, UTRCS));
153 ufs_wreg(ufs, A_IS, FIELD_DP32(0, IS, UTRCS, 1));
155 qtest_memread(ufs->dev.bus->qts, utrd_addr, utrd_out, sizeof(*utrd_out));
156 qtest_memread(ufs->dev.bus->qts, rsp_upiu_addr, rsp_out, sizeof(*rsp_out));
159 static void ufs_send_scsi_command(QUfs *ufs, uint8_t slot, uint8_t lun,
160 const uint8_t *cdb, const uint8_t *data_in,
161 size_t data_in_len, uint8_t *data_out,
162 size_t data_out_len,
163 UtpTransferReqDesc *utrd_out,
164 UtpUpiuRsp *rsp_out)
167 /* Build up PRDT */
168 UfshcdSgEntry entries[MAX_PRD_ENTRY_COUNT] = {
171 uint8_t flags;
172 uint16_t prd_table_length, i;
173 uint32_t data_direction, data_len;
174 uint64_t req_upiu_addr =
175 ufs->cmd_desc_addr + slot * UTP_COMMAND_DESCRIPTOR_SIZE;
176 uint64_t prdt_addr = req_upiu_addr + UTP_PRDT_UPIU_OFFSET;
178 g_assert_true(data_in_len < MAX_PRD_ENTRY_COUNT * PRD_ENTRY_DATA_SIZE);
179 g_assert_true(data_out_len < MAX_PRD_ENTRY_COUNT * PRD_ENTRY_DATA_SIZE);
180 if (data_in_len > 0) {
181 g_assert_nonnull(data_in);
182 data_direction = UFS_UTP_HOST_TO_DEVICE;
183 data_len = data_in_len;
184 flags = UFS_UPIU_CMD_FLAGS_WRITE;
185 } else if (data_out_len > 0) {
186 g_assert_nonnull(data_out);
187 data_direction = UFS_UTP_DEVICE_TO_HOST;
188 data_len = data_out_len;
189 flags = UFS_UPIU_CMD_FLAGS_READ;
190 } else {
191 data_direction = UFS_UTP_NO_DATA_TRANSFER;
192 data_len = 0;
193 flags = UFS_UPIU_CMD_FLAGS_NONE;
195 prd_table_length = DIV_ROUND_UP(data_len, PRD_ENTRY_DATA_SIZE);
197 qtest_memset(ufs->dev.bus->qts, ufs->data_buffer_addr, 0,
198 MAX_PRD_ENTRY_COUNT * PRD_ENTRY_DATA_SIZE);
199 if (data_in_len) {
200 qtest_memwrite(ufs->dev.bus->qts, ufs->data_buffer_addr, data_in,
201 data_in_len);
204 for (i = 0; i < prd_table_length; i++) {
205 entries[i].addr =
206 cpu_to_le64(ufs->data_buffer_addr + i * sizeof(UfshcdSgEntry));
207 if (i + 1 != prd_table_length) {
208 entries[i].size = cpu_to_le32(PRD_ENTRY_DATA_SIZE - 1);
209 } else {
210 entries[i].size = cpu_to_le32(
211 data_len - (PRD_ENTRY_DATA_SIZE * (prd_table_length - 1)) - 1);
214 qtest_memwrite(ufs->dev.bus->qts, prdt_addr, entries,
215 prd_table_length * sizeof(UfshcdSgEntry));
217 /* Build up utp transfer request descriptor */
218 UtpTransferReqDesc utrd = ufs_build_req_utrd(
219 ufs->cmd_desc_addr, slot, data_direction, prd_table_length);
220 uint64_t utrd_addr = ufs->utrlba + slot * sizeof(UtpTransferReqDesc);
221 uint64_t rsp_upiu_addr = req_upiu_addr + UTP_RESPONSE_UPIU_OFFSET;
222 qtest_memwrite(ufs->dev.bus->qts, utrd_addr, &utrd, sizeof(utrd));
224 /* Build up request upiu */
225 UtpUpiuReq req_upiu = { 0 };
226 req_upiu.header.trans_type = UFS_UPIU_TRANSACTION_COMMAND;
227 req_upiu.header.flags = flags;
228 req_upiu.header.lun = lun;
229 req_upiu.header.task_tag = slot;
230 req_upiu.sc.exp_data_transfer_len = cpu_to_be32(data_len);
231 memcpy(req_upiu.sc.cdb, cdb, UFS_CDB_SIZE);
232 qtest_memwrite(ufs->dev.bus->qts, req_upiu_addr, &req_upiu,
233 sizeof(req_upiu));
235 /* Ring Doorbell */
236 ufs_wreg(ufs, A_UTRLDBR, 1);
237 ufs_wait_for_irq(ufs);
238 g_assert_true(FIELD_EX32(ufs_rreg(ufs, A_IS), IS, UTRCS));
239 ufs_wreg(ufs, A_IS, FIELD_DP32(0, IS, UTRCS, 1));
241 qtest_memread(ufs->dev.bus->qts, utrd_addr, utrd_out, sizeof(*utrd_out));
242 qtest_memread(ufs->dev.bus->qts, rsp_upiu_addr, rsp_out, sizeof(*rsp_out));
243 if (data_out_len) {
244 qtest_memread(ufs->dev.bus->qts, ufs->data_buffer_addr, data_out,
245 data_out_len);
250 * Initialize Ufs host controller and logical unit.
251 * After running this function, you can make a transfer request to the UFS.
253 static void ufs_init(QUfs *ufs, QGuestAllocator *alloc)
255 uint64_t end_time;
256 uint32_t nutrs, nutmrs;
257 uint32_t hcs, is, ucmdarg2, cap;
258 uint32_t hce = 0, ie = 0;
259 UtpTransferReqDesc utrd;
260 UtpUpiuRsp rsp_upiu;
262 ufs->bar = qpci_iomap(&ufs->dev, 0, NULL);
263 qpci_device_enable(&ufs->dev);
265 /* Start host controller initialization */
266 hce = FIELD_DP32(hce, HCE, HCE, 1);
267 ufs_wreg(ufs, A_HCE, hce);
269 /* Wait for device to reset */
270 end_time = g_get_monotonic_time() + TIMEOUT_SECONDS * G_TIME_SPAN_SECOND;
271 do {
272 qtest_clock_step(ufs->dev.bus->qts, 100);
273 hce = FIELD_EX32(ufs_rreg(ufs, A_HCE), HCE, HCE);
274 } while (hce == 0 && g_get_monotonic_time() < end_time);
275 g_assert_cmpuint(hce, ==, 1);
277 /* Enable interrupt */
278 ie = FIELD_DP32(ie, IE, UCCE, 1);
279 ie = FIELD_DP32(ie, IE, UHESE, 1);
280 ie = FIELD_DP32(ie, IE, UHXSE, 1);
281 ie = FIELD_DP32(ie, IE, UPMSE, 1);
282 ufs_wreg(ufs, A_IE, ie);
284 /* Send DME_LINK_STARTUP uic command */
285 hcs = ufs_rreg(ufs, A_HCS);
286 g_assert_true(FIELD_EX32(hcs, HCS, UCRDY));
288 ufs_wreg(ufs, A_UCMDARG1, 0);
289 ufs_wreg(ufs, A_UCMDARG2, 0);
290 ufs_wreg(ufs, A_UCMDARG3, 0);
291 ufs_wreg(ufs, A_UICCMD, UFS_UIC_CMD_DME_LINK_STARTUP);
293 is = ufs_rreg(ufs, A_IS);
294 g_assert_true(FIELD_EX32(is, IS, UCCS));
295 ufs_wreg(ufs, A_IS, FIELD_DP32(0, IS, UCCS, 1));
297 ucmdarg2 = ufs_rreg(ufs, A_UCMDARG2);
298 g_assert_cmpuint(ucmdarg2, ==, 0);
299 is = ufs_rreg(ufs, A_IS);
300 g_assert_cmpuint(is, ==, 0);
301 hcs = ufs_rreg(ufs, A_HCS);
302 g_assert_true(FIELD_EX32(hcs, HCS, DP));
303 g_assert_true(FIELD_EX32(hcs, HCS, UTRLRDY));
304 g_assert_true(FIELD_EX32(hcs, HCS, UTMRLRDY));
305 g_assert_true(FIELD_EX32(hcs, HCS, UCRDY));
307 /* Enable all interrupt functions */
308 ie = FIELD_DP32(ie, IE, UTRCE, 1);
309 ie = FIELD_DP32(ie, IE, UEE, 1);
310 ie = FIELD_DP32(ie, IE, UPMSE, 1);
311 ie = FIELD_DP32(ie, IE, UHXSE, 1);
312 ie = FIELD_DP32(ie, IE, UHESE, 1);
313 ie = FIELD_DP32(ie, IE, UTMRCE, 1);
314 ie = FIELD_DP32(ie, IE, UCCE, 1);
315 ie = FIELD_DP32(ie, IE, DFEE, 1);
316 ie = FIELD_DP32(ie, IE, HCFEE, 1);
317 ie = FIELD_DP32(ie, IE, SBFEE, 1);
318 ie = FIELD_DP32(ie, IE, CEFEE, 1);
319 ufs_wreg(ufs, A_IE, ie);
320 ufs_wreg(ufs, A_UTRIACR, 0);
322 /* Enable tranfer request and task management request */
323 cap = ufs_rreg(ufs, A_CAP);
324 nutrs = FIELD_EX32(cap, CAP, NUTRS) + 1;
325 nutmrs = FIELD_EX32(cap, CAP, NUTMRS) + 1;
326 ufs->cmd_desc_addr =
327 guest_alloc(alloc, nutrs * UTP_COMMAND_DESCRIPTOR_SIZE);
328 ufs->data_buffer_addr =
329 guest_alloc(alloc, MAX_PRD_ENTRY_COUNT * PRD_ENTRY_DATA_SIZE);
330 ufs->utrlba = guest_alloc(alloc, nutrs * sizeof(UtpTransferReqDesc));
331 ufs->utmrlba = guest_alloc(alloc, nutmrs * sizeof(UtpTaskReqDesc));
333 ufs_wreg(ufs, A_UTRLBA, ufs->utrlba & 0xffffffff);
334 ufs_wreg(ufs, A_UTRLBAU, ufs->utrlba >> 32);
335 ufs_wreg(ufs, A_UTMRLBA, ufs->utmrlba & 0xffffffff);
336 ufs_wreg(ufs, A_UTMRLBAU, ufs->utmrlba >> 32);
337 ufs_wreg(ufs, A_UTRLRSR, 1);
338 ufs_wreg(ufs, A_UTMRLRSR, 1);
340 /* Send nop out to test transfer request */
341 ufs_send_nop_out(ufs, 0, &utrd, &rsp_upiu);
342 g_assert_cmpuint(le32_to_cpu(utrd.header.dword_2), ==, UFS_OCS_SUCCESS);
344 /* Set fDeviceInit flag via query request */
345 ufs_send_query(ufs, 0, UFS_UPIU_QUERY_FUNC_STANDARD_WRITE_REQUEST,
346 UFS_UPIU_QUERY_OPCODE_SET_FLAG,
347 UFS_QUERY_FLAG_IDN_FDEVICEINIT, 0, &utrd, &rsp_upiu);
348 g_assert_cmpuint(le32_to_cpu(utrd.header.dword_2), ==, UFS_OCS_SUCCESS);
350 /* Wait for device to reset */
351 end_time = g_get_monotonic_time() + TIMEOUT_SECONDS * G_TIME_SPAN_SECOND;
352 do {
353 qtest_clock_step(ufs->dev.bus->qts, 100);
354 ufs_send_query(ufs, 0, UFS_UPIU_QUERY_FUNC_STANDARD_READ_REQUEST,
355 UFS_UPIU_QUERY_OPCODE_READ_FLAG,
356 UFS_QUERY_FLAG_IDN_FDEVICEINIT, 0, &utrd, &rsp_upiu);
357 } while (be32_to_cpu(rsp_upiu.qr.value) != 0 &&
358 g_get_monotonic_time() < end_time);
359 g_assert_cmpuint(be32_to_cpu(rsp_upiu.qr.value), ==, 0);
361 ufs->enabled = true;
364 static void ufs_exit(QUfs *ufs, QGuestAllocator *alloc)
366 if (ufs->enabled) {
367 guest_free(alloc, ufs->utrlba);
368 guest_free(alloc, ufs->utmrlba);
369 guest_free(alloc, ufs->cmd_desc_addr);
370 guest_free(alloc, ufs->data_buffer_addr);
373 qpci_iounmap(&ufs->dev, ufs->bar);
376 static void *ufs_get_driver(void *obj, const char *interface)
378 QUfs *ufs = obj;
380 if (!g_strcmp0(interface, "pci-device")) {
381 return &ufs->dev;
384 fprintf(stderr, "%s not present in ufs\n", interface);
385 g_assert_not_reached();
388 static void *ufs_create(void *pci_bus, QGuestAllocator *alloc, void *addr)
390 QUfs *ufs = g_new0(QUfs, 1);
391 QPCIBus *bus = pci_bus;
393 qpci_device_init(&ufs->dev, bus, addr);
394 ufs->obj.get_driver = ufs_get_driver;
396 return &ufs->obj;
399 static void ufstest_reg_read(void *obj, void *data, QGuestAllocator *alloc)
401 QUfs *ufs = obj;
402 uint32_t cap;
404 ufs->bar = qpci_iomap(&ufs->dev, 0, NULL);
405 qpci_device_enable(&ufs->dev);
407 cap = ufs_rreg(ufs, A_CAP);
408 g_assert_cmpuint(FIELD_EX32(cap, CAP, NUTRS), ==, 31);
409 g_assert_cmpuint(FIELD_EX32(cap, CAP, NUTMRS), ==, 7);
410 g_assert_cmpuint(FIELD_EX32(cap, CAP, 64AS), ==, 1);
412 qpci_iounmap(&ufs->dev, ufs->bar);
415 static void ufstest_init(void *obj, void *data, QGuestAllocator *alloc)
417 QUfs *ufs = obj;
419 uint8_t buf[4096] = { 0 };
420 const uint8_t report_luns_cdb[UFS_CDB_SIZE] = {
421 /* allocation length 4096 */
422 REPORT_LUNS, 0x00, 0x00, 0x00, 0x00, 0x00,
423 0x00, 0x00, 0x10, 0x00, 0x00, 0x00
425 const uint8_t test_unit_ready_cdb[UFS_CDB_SIZE] = {
426 TEST_UNIT_READY,
428 UtpTransferReqDesc utrd;
429 UtpUpiuRsp rsp_upiu;
431 ufs_init(ufs, alloc);
433 /* Check REPORT_LUNS */
434 ufs_send_scsi_command(ufs, 0, 0, report_luns_cdb, NULL, 0, buf, sizeof(buf),
435 &utrd, &rsp_upiu);
436 g_assert_cmpuint(le32_to_cpu(utrd.header.dword_2), ==, UFS_OCS_SUCCESS);
437 g_assert_cmpuint(rsp_upiu.header.scsi_status, ==, GOOD);
438 /* LUN LIST LENGTH should be 8, in big endian */
439 g_assert_cmpuint(buf[3], ==, 8);
440 /* There is one logical unit whose lun is 0 */
441 g_assert_cmpuint(buf[9], ==, 0);
443 /* Check TEST_UNIT_READY */
444 ufs_send_scsi_command(ufs, 0, 0, test_unit_ready_cdb, NULL, 0, NULL, 0,
445 &utrd, &rsp_upiu);
446 g_assert_cmpuint(le32_to_cpu(utrd.header.dword_2), ==, UFS_OCS_SUCCESS);
447 g_assert_cmpuint(rsp_upiu.header.scsi_status, ==, GOOD);
449 ufs_exit(ufs, alloc);
452 static void ufstest_read_write(void *obj, void *data, QGuestAllocator *alloc)
454 QUfs *ufs = obj;
455 uint8_t read_buf[4096] = { 0 };
456 uint8_t write_buf[4096] = { 0 };
457 const uint8_t read_capacity_cdb[UFS_CDB_SIZE] = {
458 /* allocation length 4096 */
459 SERVICE_ACTION_IN_16,
460 SAI_READ_CAPACITY_16,
461 0x00,
462 0x00,
463 0x00,
464 0x00,
465 0x00,
466 0x00,
467 0x00,
468 0x00,
469 0x00,
470 0x00,
471 0x10,
472 0x00,
473 0x00,
474 0x00
476 const uint8_t read_cdb[UFS_CDB_SIZE] = {
477 /* READ(10) to LBA 0, transfer length 1 */
478 READ_10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00
480 const uint8_t write_cdb[UFS_CDB_SIZE] = {
481 /* WRITE(10) to LBA 0, transfer length 1 */
482 WRITE_10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00
484 uint32_t block_size;
485 UtpTransferReqDesc utrd;
486 UtpUpiuRsp rsp_upiu;
488 ufs_init(ufs, alloc);
490 /* Read capacity */
491 ufs_send_scsi_command(ufs, 0, 1, read_capacity_cdb, NULL, 0, read_buf,
492 sizeof(read_buf), &utrd, &rsp_upiu);
493 g_assert_cmpuint(le32_to_cpu(utrd.header.dword_2), ==, UFS_OCS_SUCCESS);
494 g_assert_cmpuint(rsp_upiu.header.scsi_status, ==,
495 UFS_COMMAND_RESULT_SUCESS);
496 block_size = ldl_be_p(&read_buf[8]);
497 g_assert_cmpuint(block_size, ==, 4096);
499 /* Write data */
500 memset(write_buf, rand() % 255 + 1, block_size);
501 ufs_send_scsi_command(ufs, 0, 1, write_cdb, write_buf, block_size, NULL, 0,
502 &utrd, &rsp_upiu);
503 g_assert_cmpuint(le32_to_cpu(utrd.header.dword_2), ==, UFS_OCS_SUCCESS);
504 g_assert_cmpuint(rsp_upiu.header.scsi_status, ==,
505 UFS_COMMAND_RESULT_SUCESS);
507 /* Read data and verify */
508 ufs_send_scsi_command(ufs, 0, 1, read_cdb, NULL, 0, read_buf, block_size,
509 &utrd, &rsp_upiu);
510 g_assert_cmpuint(le32_to_cpu(utrd.header.dword_2), ==, UFS_OCS_SUCCESS);
511 g_assert_cmpuint(rsp_upiu.header.scsi_status, ==,
512 UFS_COMMAND_RESULT_SUCESS);
513 g_assert_cmpint(memcmp(read_buf, write_buf, block_size), ==, 0);
515 ufs_exit(ufs, alloc);
518 static void drive_destroy(void *path)
520 unlink(path);
521 g_free(path);
522 qos_invalidate_command_line();
525 static char *drive_create(void)
527 int fd, ret;
528 char *t_path;
530 /* Create a temporary raw image */
531 fd = g_file_open_tmp("qtest-ufs.XXXXXX", &t_path, NULL);
532 g_assert_cmpint(fd, >=, 0);
533 ret = ftruncate(fd, TEST_IMAGE_SIZE);
534 g_assert_cmpint(ret, ==, 0);
535 close(fd);
537 g_test_queue_destroy(drive_destroy, t_path);
538 return t_path;
541 static void *ufs_blk_test_setup(GString *cmd_line, void *arg)
543 char *tmp_path = drive_create();
545 g_string_append_printf(cmd_line,
546 " -blockdev file,filename=%s,node-name=drv1 "
547 "-device ufs-lu,bus=ufs0,drive=drv1,lun=1 ",
548 tmp_path);
550 return arg;
553 static void ufs_register_nodes(void)
555 const char *arch;
556 QOSGraphEdgeOptions edge_opts = {
557 .before_cmd_line = "-blockdev null-co,node-name=drv0,read-zeroes=on",
558 .after_cmd_line = "-device ufs-lu,bus=ufs0,drive=drv0,lun=0",
559 .extra_device_opts = "addr=04.0,id=ufs0,nutrs=32,nutmrs=8"
562 QOSGraphTestOptions io_test_opts = {
563 .before = ufs_blk_test_setup,
566 add_qpci_address(&edge_opts, &(QPCIAddress){ .devfn = QPCI_DEVFN(4, 0) });
568 qos_node_create_driver("ufs", ufs_create);
569 qos_node_consumes("ufs", "pci-bus", &edge_opts);
570 qos_node_produces("ufs", "pci-device");
572 qos_add_test("reg-read", "ufs", ufstest_reg_read, NULL);
575 * Check architecture
576 * TODO: Enable ufs io tests for ppc64
578 arch = qtest_get_arch();
579 if (!strcmp(arch, "ppc64")) {
580 g_test_message("Skipping ufs io tests for ppc64");
581 return;
583 qos_add_test("init", "ufs", ufstest_init, NULL);
584 qos_add_test("read-write", "ufs", ufstest_read_write, &io_test_opts);
587 libqos_init(ufs_register_nodes);