@samitouri / QOSamiQemu / commits / 2fa24e9755

ide-test: Test reset during TRIM

This is a regression test for the bug fixed in the previous commits, a deadlock between the drain issued by an IDE reset and the TRIM state machine. Signed-off-by: Kevin Wolf <kwolf@redhat.com> Message-ID: <20260421161132.99878-8-kwolf@redhat.com> Signed-off-by: Kevin Wolf <kwolf@redhat.com>

Kevin Wolf committed Apr 21, 2026 at 18:11 UTC 2fa24e9755994f76f08ea2452215eb50f26f4c21
1 file changed +87 -8
tests/qtest/ide-test.c
+87 -8
@@ -41,8 +41,11 @@
41 #define IDE_PCI_FUNC 1
42
43 #define IDE_BASE 0x1f0
44 +#define IDE_BASE2 0x3f6
45 #define IDE_PRIMARY_IRQ 14
46
47 +#define IDE_CTRL_RESET 0x04
48 +
49 #define ATAPI_BLOCK_SIZE 2048
50
51 /* How many bytes to receive via ATAPI PIO at one time.
@@ -99,6 +102,7 @@ enum {
102
103 CMDF_ABORT = 0x100,
104 CMDF_NO_BM = 0x200,
105 + CMDF_NO_WAIT = 0x400,
106 };
107
108 enum {
@@ -228,21 +232,21 @@ static uint8_t wait_dma_completion(QTestState *qts, QPCIDevice *dev,
232 return status;
233 }
234
231 -static int send_dma_request(QTestState *qts, int cmd, uint64_t sector,
232 - int nb_sectors, PrdtEntry *prdt, int prdt_entries,
233 - void(*post_exec)(QPCIDevice *dev, QPCIBar ide_bar,
234 - uint64_t sector, int nb_sectors))
235 +static int send_dma_request_dev(QTestState *qts, QPCIDevice *dev,
236 + QPCIBar bmdma_bar, QPCIBar ide_bar, int cmd,
237 + uint64_t sector, int nb_sectors,
238 + PrdtEntry *prdt, int prdt_entries,
239 + void(*post_exec)(QPCIDevice *dev,
240 + QPCIBar ide_bar,
241 + uint64_t sector,
242 + int nb_sectors))
243 {
236 - QPCIDevice *dev;
237 - QPCIBar bmdma_bar, ide_bar;
244 uintptr_t guest_prdt;
245 size_t len;
246 bool from_dev;
247 uint8_t status;
248 int flags;
249
244 - dev = get_pci_device(qts, &bmdma_bar, &ide_bar);
245 -
250 flags = cmd & ~0xff;
251 cmd &= 0xff;
252
@@ -308,8 +312,28 @@ static int send_dma_request(QTestState *qts, int cmd, uint64_t sector,
312 qpci_io_writeb(dev, bmdma_bar, bmreg_cmd, 0);
313 }
314
315 + if (flags & CMDF_NO_WAIT) {
316 + return 0;
317 + }
318 +
319 status = wait_dma_completion(qts, dev, bmdma_bar, ide_bar);
320
321 + return status;
322 +}
323 +
324 +static int send_dma_request(QTestState *qts, int cmd, uint64_t sector,
325 + int nb_sectors, PrdtEntry *prdt, int prdt_entries,
326 + void(*post_exec)(QPCIDevice *dev, QPCIBar ide_bar,
327 + uint64_t sector, int nb_sectors))
328 +{
329 + QPCIDevice *dev;
330 + QPCIBar bmdma_bar, ide_bar;
331 + uint8_t status;
332 +
333 + dev = get_pci_device(qts, &bmdma_bar, &ide_bar);
334 + status = send_dma_request_dev(qts, dev, bmdma_bar, ide_bar,
335 + cmd, sector, nb_sectors, prdt, prdt_entries,
336 + post_exec);
337 free_pci_device(dev);
338
339 return status;
@@ -457,6 +481,60 @@ static void test_bmdma_trim(void)
481 test_bmdma_teardown(qts);
482 }
483
484 +static void test_bmdma_trim_reset(void)
485 +{
486 + QTestState *qts;
487 + QPCIDevice *dev;
488 + QPCIBar bmdma_bar, ide_bar, ide_bar2;
489 + uint8_t status;
490 + const uint64_t trim_range[] = {
491 + trim_range_le(0, 2),
492 + trim_range_le(6, 8),
493 + };
494 + size_t len = 512;
495 + uint8_t *buf;
496 + uintptr_t guest_buf;
497 + PrdtEntry prdt[1];
498 +
499 + qts = ide_test_start(
500 + "-blockdev file,filename=%s,node-name=img "
501 + "-blockdev blkdebug,image=img,node-name=dbg,discard=unmap,"
502 + "inject-error.0.event=none,inject-error.0.iotype=discard,"
503 + "inject-error.0.errno=0,inject-error.0.delay-ns=1000000 "
504 + "-device ide-hd,drive=dbg,bus=ide.0",
505 + tmp_path[0]);
506 + qtest_irq_intercept_in(qts, "ioapic");
507 +
508 + guest_buf = guest_alloc(&guest_malloc, len);
509 + prdt[0].addr = cpu_to_le32(guest_buf),
510 + prdt[0].size = cpu_to_le32(len | PRDT_EOT),
511 +
512 + dev = get_pci_device(qts, &bmdma_bar, &ide_bar);
513 + ide_bar2 = qpci_legacy_iomap(dev, IDE_BASE2);
514 +
515 + buf = g_malloc(len);
516 +
517 + /* TRIM request with two segments */
518 + *((uint64_t *)buf) = trim_range[0];
519 + *((uint64_t *)buf + 1) = trim_range[1];
520 +
521 + qtest_memwrite(qts, guest_buf, buf, 2 * sizeof(uint64_t));
522 +
523 + send_dma_request_dev(qts, dev, bmdma_bar, ide_bar, CMD_DSM | CMDF_NO_WAIT, 0, 1, prdt,
524 + ARRAY_SIZE(prdt), NULL);
525 +
526 + /* Reset the device while the first segment is in flight */
527 + qpci_io_writeb(dev, ide_bar2, 0, IDE_CTRL_RESET);
528 +
529 + status = wait_dma_completion(qts, dev, bmdma_bar, ide_bar);
530 + g_assert_cmphex(status, ==, BM_STS_INTR);
531 + assert_bit_clear(qpci_io_readb(dev, ide_bar, reg_status), DF | ERR);
532 +
533 + free_pci_device(dev);
534 + g_free(buf);
535 + test_bmdma_teardown(qts);
536 +}
537 +
538 /*
539 * This test is developed according to the Programming Interface for
540 * Bus Master IDE Controller (Revision 1.0 5/16/94)
@@ -1138,6 +1216,7 @@ int main(int argc, char **argv)
1216
1217 qtest_add_func("/ide/bmdma/simple_rw", test_bmdma_simple_rw);
1218 qtest_add_func("/ide/bmdma/trim", test_bmdma_trim);
1219 + qtest_add_func("/ide/bmdma/trim_reset", test_bmdma_trim_reset);
1220 qtest_add_func("/ide/bmdma/various_prdts", test_bmdma_various_prdts);
1221 qtest_add_func("/ide/bmdma/no_busmaster", test_bmdma_no_busmaster);
1222