1625
ahci_test_cdrom_read10(3, false);
1626
}
1627
1628
+/*
1629
+ * Regression test: a buffered ATAPI read completing after a command
1630
+ * engine restart must not dereference the cleared cur_cmd. Cover both
1631
+ * PIO and DMA; the DMA variant is the reliable guard.
1632
+ */
1633
+static void test_atapi_engine_restart_in_flight(bool dma)
1634
+{
1635
+ AHCIQState *ahci;
1636
+ AHCICommand *cmd;
1637
+ unsigned char *tx;
1638
+ char *iso;
1639
+ int fd;
1640
+ uint8_t port;
1641
+ uint64_t buffer;
1642
+ uint64_t iso_size = (uint64_t)ATAPI_SECTOR_SIZE * 2;
1643
+
1644
+ fd = prepare_iso(iso_size, &tx, &iso);
1645
+
1646
+ ahci = ahci_boot_and_enable("-drive if=none,id=drive0,"
1647
+ "file=blkdebug::%s,format=raw,readonly=on "
1648
+ "-M q35 "
1649
+ "-device ide-cd,drive=drive0 ", iso);
1650
+ port = ahci_port_select(ahci);
1651
+
1652
+ buffer = ahci_alloc(ahci, ATAPI_SECTOR_SIZE);
1653
+ qtest_memset(ahci->parent->qts, buffer, 0x00, ATAPI_SECTOR_SIZE);
1654
+
1655
+ /* Suspend the next backend read so the ATAPI read stays in flight. */
1656
+ g_free(qtest_hmp(ahci->parent->qts,
1657
+ "qemu-io drive0 \"break read_aio rd\""));
1658
+
1659
+ cmd = ahci_atapi_command_create(CMD_ATAPI_READ_10, ATAPI_SECTOR_SIZE,
1660
+ dma);
1661
+ ahci_command_adjust(cmd, 0, buffer, ATAPI_SECTOR_SIZE, 0);
1662
+ ahci_command_commit(ahci, cmd, port);
1663
+ ahci_command_issue_async(ahci, cmd);
1664
+
1665
+ /* Stop and restart the command engine to re-map the command list. */
1666
+ ahci_px_clr(ahci, port, AHCI_PX_CMD, AHCI_PX_CMD_ST);
1667
+ ahci_px_set(ahci, port, AHCI_PX_CMD, AHCI_PX_CMD_ST);
1668
+
1669
+ g_free(qtest_hmp(ahci->parent->qts, "qemu-io drive0 \"resume rd\""));
1670
+
1671
+ /* Round-trip through the device to confirm qemu is still alive. */
1672
+ ahci_px_rreg(ahci, port, AHCI_PX_TFD);
1673
+
1674
+ ahci_command_free(cmd);
1675
+ ahci_free(ahci, buffer);
1676
+ g_free(tx);
1677
+ ahci_shutdown(ahci);
1678
+ remove_iso(fd, iso);
1679
+}
1680
+
1681
+static void test_atapi_engine_restart_pio(void)
1682
+{
1683
+ test_atapi_engine_restart_in_flight(false);
1684
+}
1685
+
1686
+static void test_atapi_engine_restart_dma(void)
1687
+{
1688
+ test_atapi_engine_restart_in_flight(true);
1689
+}
1690
+
1691
/* Regression test: Test that a READ_CD command with a BCL of 0 but a size of 0
1692
* completes as a NOP instead of erroring out. */
1693
static void test_atapi_bcl(void)
2105
2106
qtest_add_func("/ahci/cdrom/pio/bcl", test_atapi_bcl);
2107
qtest_add_func("/ahci/cdrom/eject", test_atapi_tray);
2108
+ qtest_add_func("/ahci/cdrom/engine_restart/pio",
2109
+ test_atapi_engine_restart_pio);
2110
+ qtest_add_func("/ahci/cdrom/engine_restart/dma",
2111
+ test_atapi_engine_restart_dma);
2112
2113
ret = g_test_run();
2114