@samitouri / QOSamiQemu / commits / f50738e34f

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);