tests/qtest: Add UFS Write Booster QTest
It adds 'wb-init' and 'wb-read-write' TCs into tests/qtest/ufs-test.c. 'wb-init' tests that the WB support is properly initialized with UFS device and 'wb-read-write' tests that WB can be enabled and WRITE I/O can be handled/buffered as a WB command. Signed-off-by: Jaemyung Lee <jaemyung.lee@samsung.com> Signed-off-by: Jeuk Kim <jeuk20.kim@samsung.com>
Jaemyung Lee committed
May 14, 2026 at 17:10 UTC
f50738e34f5bf8d907cfdb8195fedc780341b99a
1 file changed
+177
tests/qtest/ufs-test.c
+177
@@ -1182,6 +1182,175 @@ static void ufstest_query_desc_request(void *obj, void *data,
1182
ufs_exit(ufs, alloc);
1183
}
1184
1185
+static void ufstest_wb_init(void *obj, void *data, QGuestAllocator *alloc)
1186
+{
1187
+ QUfs *ufs = obj;
1188
+ enum UtpOcsCodes ocs;
1189
+ UtpUpiuRsp rsp_upiu;
1190
+ uint8_t *desc;
1191
+ uint32_t value;
1192
+
1193
+ ufs_init(ufs, alloc);
1194
+
1195
+ /* Read Device Descriptor */
1196
+ ocs = ufs_send_query(ufs, UFS_UPIU_QUERY_FUNC_STANDARD_READ_REQUEST,
1197
+ UFS_UPIU_QUERY_OPCODE_READ_DESC,
1198
+ UFS_QUERY_DESC_IDN_DEVICE, 0, 0, 0, &rsp_upiu);
1199
+ g_assert_cmpuint(ocs, ==, UFS_OCS_SUCCESS);
1200
+ g_assert_cmpuint(rsp_upiu.header.response, ==, UFS_COMMAND_RESULT_SUCCESS);
1201
+ g_assert_cmpuint(rsp_upiu.qr.opcode, ==, UFS_UPIU_QUERY_OPCODE_READ_DESC);
1202
+ g_assert_cmpuint(rsp_upiu.qr.idn, ==, UFS_QUERY_DESC_IDN_DEVICE);
1203
+ g_assert_cmpuint(rsp_upiu.qr.data[0], ==, sizeof(DeviceDescriptor));
1204
+ g_assert_cmpuint(rsp_upiu.qr.data[1], ==, UFS_QUERY_DESC_IDN_DEVICE);
1205
+
1206
+ /* Check Write Booster Supportability */
1207
+ desc = rsp_upiu.qr.data;
1208
+
1209
+ value = lduw_be_p(desc + UFS_DEVICE_DESC_PARAM_EXT_WB_SUP);
1210
+ g_assert_cmpuint(value, ==, WB_RESIZE | WB_FIFO | WB_PINNED);
1211
+
1212
+ value = ldl_be_p(desc + UFS_DEVICE_DESC_PARAM_EXT_UFS_FEATURE_SUP);
1213
+ g_assert_cmpuint(value & UFS_DEV_WB_SUPPORT, ==, UFS_DEV_WB_SUPPORT);
1214
+
1215
+ /* Read Geometry Descriptor */
1216
+ ocs = ufs_send_query(ufs, UFS_UPIU_QUERY_FUNC_STANDARD_READ_REQUEST,
1217
+ UFS_UPIU_QUERY_OPCODE_READ_DESC,
1218
+ UFS_QUERY_DESC_IDN_GEOMETRY, 0, 0, 0, &rsp_upiu);
1219
+ g_assert_cmpuint(ocs, ==, UFS_OCS_SUCCESS);
1220
+ g_assert_cmpuint(rsp_upiu.header.response, ==, UFS_COMMAND_RESULT_SUCCESS);
1221
+ g_assert_cmpuint(rsp_upiu.qr.data[0], ==, sizeof(GeometryDescriptor));
1222
+ g_assert_cmpuint(rsp_upiu.qr.data[1], ==, UFS_QUERY_DESC_IDN_GEOMETRY);
1223
+
1224
+ /* Check Write Booster Configuration */
1225
+ desc = rsp_upiu.qr.data;
1226
+
1227
+ value = ldl_be_p(desc + UFS_GEOMETRY_DESC_PARAM_WB_MAX_ALLOC_UNITS);
1228
+ g_assert_cmpuint(value, ==, 1024);
1229
+
1230
+ value = desc[UFS_GEOMETRY_DESC_PARAM_WB_MAX_WB_LUNS];
1231
+ g_assert_cmpuint(value, ==, 1);
1232
+
1233
+ value = desc[UFS_GEOMETRY_DESC_PARAM_WB_BUFF_CAP_ADJ];
1234
+ g_assert_cmpuint(value, ==, 3);
1235
+
1236
+ value = desc[UFS_GEOMETRY_DESC_PARAM_WB_SUP_RED_TYPE];
1237
+ g_assert_cmpuint(value, ==, 1);
1238
+
1239
+ value = desc[UFS_GEOMETRY_DESC_PARAM_WB_SUP_WB_TYPE];
1240
+ g_assert_cmpuint(value, ==, 1);
1241
+
1242
+ ufs_exit(ufs, alloc);
1243
+}
1244
+
1245
+static void ufstest_wb_read_write(void *obj, void *data, QGuestAllocator *alloc)
1246
+{
1247
+ QUfs *ufs = obj;
1248
+ uint8_t read_buf[4096] = { 0 };
1249
+ uint8_t write_buf[4096] = { 0 };
1250
+ const uint8_t read_capacity_cdb[UFS_CDB_SIZE] = {
1251
+ /* allocation length 4096 */
1252
+ SERVICE_ACTION_IN_16,
1253
+ SAI_READ_CAPACITY_16,
1254
+ 0x00,
1255
+ 0x00,
1256
+ 0x00,
1257
+ 0x00,
1258
+ 0x00,
1259
+ 0x00,
1260
+ 0x00,
1261
+ 0x00,
1262
+ 0x00,
1263
+ 0x00,
1264
+ 0x10,
1265
+ 0x00,
1266
+ 0x00,
1267
+ 0x00
1268
+ };
1269
+ const uint8_t request_sense_cdb[UFS_CDB_SIZE] = {
1270
+ REQUEST_SENSE,
1271
+ };
1272
+ const uint8_t write_cdb[UFS_CDB_SIZE] = {
1273
+ /* WRITE(10) to LBA 0, transfer length 1 */
1274
+ WRITE_10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00
1275
+ };
1276
+ uint32_t block_size;
1277
+ enum UtpOcsCodes ocs;
1278
+ UtpUpiuRsp rsp_upiu;
1279
+ const int test_lun = 1;
1280
+ uint64_t end_time;
1281
+
1282
+ ufs_init(ufs, alloc);
1283
+
1284
+ /* Clear Unit Attention */
1285
+ ocs = ufs_send_scsi_command(ufs, test_lun, request_sense_cdb, NULL, 0,
1286
+ read_buf, sizeof(read_buf), &rsp_upiu);
1287
+ g_assert_cmpuint(ocs, ==, UFS_OCS_SUCCESS);
1288
+ g_assert_cmpuint(rsp_upiu.header.scsi_status, ==, CHECK_CONDITION);
1289
+
1290
+ /* Read capacity */
1291
+ ocs = ufs_send_scsi_command(ufs, test_lun, read_capacity_cdb, NULL, 0,
1292
+ read_buf, sizeof(read_buf), &rsp_upiu);
1293
+ g_assert_cmpuint(ocs, ==, UFS_OCS_SUCCESS);
1294
+ g_assert_cmpuint(rsp_upiu.header.scsi_status, ==,
1295
+ UFS_COMMAND_RESULT_SUCCESS);
1296
+ block_size = ldl_be_p(&read_buf[8]);
1297
+ g_assert_cmpuint(block_size, ==, 4096);
1298
+
1299
+ /* Check available buffer size */
1300
+ ocs = ufs_send_query(ufs, UFS_UPIU_QUERY_FUNC_STANDARD_READ_REQUEST,
1301
+ UFS_UPIU_QUERY_OPCODE_READ_ATTR,
1302
+ UFS_QUERY_ATTR_IDN_AVAIL_WB_BUFF_SIZE, 0, 0, 0,
1303
+ &rsp_upiu);
1304
+ g_assert_cmpuint(ocs, ==, UFS_OCS_SUCCESS);
1305
+ g_assert_cmpuint(rsp_upiu.header.response, ==, UFS_COMMAND_RESULT_SUCCESS);
1306
+ g_assert_cmpuint(rsp_upiu.qr.opcode, ==, UFS_UPIU_QUERY_OPCODE_READ_ATTR);
1307
+ g_assert_cmpuint(rsp_upiu.qr.idn, ==,
1308
+ UFS_QUERY_ATTR_IDN_AVAIL_WB_BUFF_SIZE);
1309
+ g_assert_cmpuint(rsp_upiu.qr.value, ==, cpu_to_be32(0xA));
1310
+
1311
+ /* Enable WB */
1312
+ ocs = ufs_send_query(ufs, UFS_UPIU_QUERY_FUNC_STANDARD_WRITE_REQUEST,
1313
+ UFS_UPIU_QUERY_OPCODE_SET_FLAG,
1314
+ UFS_QUERY_FLAG_IDN_WB_EN, 0, 0, 0, &rsp_upiu);
1315
+ g_assert_cmpuint(ocs, ==, UFS_OCS_SUCCESS);
1316
+ g_assert_cmpuint(rsp_upiu.header.response, ==, UFS_COMMAND_RESULT_SUCCESS);
1317
+ g_assert_cmpuint(rsp_upiu.qr.value, ==, be32_to_cpu(1));
1318
+
1319
+ /* Write data */
1320
+ for (int i = 0; i < 256; i++) {
1321
+ memset(write_buf, 0xab, block_size);
1322
+ ocs = ufs_send_scsi_command(ufs, test_lun, write_cdb, write_buf,
1323
+ block_size, NULL, 0, &rsp_upiu);
1324
+ g_assert_cmpuint(ocs, ==, UFS_OCS_SUCCESS);
1325
+ g_assert_cmpuint(rsp_upiu.header.scsi_status, ==,
1326
+ UFS_COMMAND_RESULT_SUCCESS);
1327
+ }
1328
+
1329
+ end_time = g_get_monotonic_time() + TIMEOUT_SECONDS * G_TIME_SPAN_SECOND;
1330
+ do {
1331
+ qtest_clock_step(ufs->dev.bus->qts, 100);
1332
+
1333
+ /* Check available buffer size */
1334
+ ocs = ufs_send_query(ufs, UFS_UPIU_QUERY_FUNC_STANDARD_READ_REQUEST,
1335
+ UFS_UPIU_QUERY_OPCODE_READ_ATTR,
1336
+ UFS_QUERY_ATTR_IDN_AVAIL_WB_BUFF_SIZE, 0, 0, 0,
1337
+ &rsp_upiu);
1338
+ g_assert_cmpuint(ocs, ==, UFS_OCS_SUCCESS);
1339
+ g_assert_cmpuint(rsp_upiu.header.response, ==,
1340
+ UFS_COMMAND_RESULT_SUCCESS);
1341
+ g_assert_cmpuint(rsp_upiu.qr.opcode, ==,
1342
+ UFS_UPIU_QUERY_OPCODE_READ_ATTR);
1343
+ g_assert_cmpuint(rsp_upiu.qr.idn, ==,
1344
+ UFS_QUERY_ATTR_IDN_AVAIL_WB_BUFF_SIZE);
1345
+ } while (rsp_upiu.qr.value == cpu_to_be32(0xA) &&
1346
+ g_get_monotonic_time() < end_time);
1347
+
1348
+ /* Check available buffer size */
1349
+ g_assert_cmpuint(rsp_upiu.qr.value, ==, cpu_to_be32(0x9));
1350
+
1351
+ ufs_exit(ufs, alloc);
1352
+}
1353
+
1354
static void drive_destroy(void *path)
1355
{
1356
unlink(path);
@@ -1234,6 +1403,12 @@ static void ufs_register_nodes(void)
1403
.edge.extra_device_opts =
1404
"mcq=true,mcq-maxq=1" };
1405
1406
+ QOSGraphTestOptions wb_test_opts = { .before = ufs_blk_test_setup,
1407
+ .edge.extra_device_opts =
1408
+ "mcq=false,nutrs=32,nutmrs=8,"
1409
+ "wb-max-size=1024,"
1410
+ "wb-min-size=256" };
1411
+
1412
add_qpci_address(&edge_opts, &(QPCIAddress){ .devfn = QPCI_DEVFN(4, 0) });
1413
1414
qos_node_create_driver("ufs", ufs_create);
@@ -1262,6 +1437,8 @@ static void ufs_register_nodes(void)
1437
&io_test_opts);
1438
qos_add_test("query-desciptor", "ufs", ufstest_query_desc_request,
1439
&io_test_opts);
1440
+ qos_add_test("wb-init", "ufs", ufstest_wb_init, &wb_test_opts);
1441
+ qos_add_test("wb-read-write", "ufs", ufstest_wb_read_write, &wb_test_opts);
1442
}
1443
1444
libqos_init(ufs_register_nodes);