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
9 #include "qemu/osdep.h"
10 #include "qemu/module.h"
11 #include "qemu/units.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
;
39 uint64_t cmd_desc_addr
;
40 uint64_t data_buffer_addr
;
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
)
59 /* Wait for device to reset as the linux driver does. */
60 end_time
= g_get_monotonic_time() + TIMEOUT_SECONDS
* G_TIME_SPAN_SECOND
;
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
,
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
;
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
);
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
,
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
,
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
,
163 UtpTransferReqDesc
*utrd_out
,
168 UfshcdSgEntry entries
[MAX_PRD_ENTRY_COUNT
] = {
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
;
191 data_direction
= UFS_UTP_NO_DATA_TRANSFER
;
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
);
200 qtest_memwrite(ufs
->dev
.bus
->qts
, ufs
->data_buffer_addr
, data_in
,
204 for (i
= 0; i
< prd_table_length
; i
++) {
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);
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
,
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
));
244 qtest_memread(ufs
->dev
.bus
->qts
, ufs
->data_buffer_addr
, data_out
,
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
)
256 uint32_t nutrs
, nutmrs
;
257 uint32_t hcs
, is
, ucmdarg2
, cap
;
258 uint32_t hce
= 0, ie
= 0;
259 UtpTransferReqDesc utrd
;
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
;
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;
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
;
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);
364 static void ufs_exit(QUfs
*ufs
, QGuestAllocator
*alloc
)
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
)
380 if (!g_strcmp0(interface
, "pci-device")) {
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
;
399 static void ufstest_reg_read(void *obj
, void *data
, QGuestAllocator
*alloc
)
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
)
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
] = {
428 UtpTransferReqDesc utrd
;
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
),
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,
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
)
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
,
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
485 UtpTransferReqDesc utrd
;
488 ufs_init(ufs
, alloc
);
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);
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,
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
,
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
)
522 qos_invalidate_command_line();
525 static char *drive_create(void)
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);
537 g_test_queue_destroy(drive_destroy
, 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 ",
553 static void ufs_register_nodes(void)
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
);
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");
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
);