X-Git-Url: https://repo.jachan.dev/qemu.git/blobdiff_plain/6ed5546fa7bf12c5b87ef76bafb86e1d77ed6e85..e822e81e350825dd94f41ee2538ff1432b812eb9:/tests/ahci-test.c diff --git a/tests/ahci-test.c b/tests/ahci-test.c index 57dc44cf3b..cb84edc8fb 100644 --- a/tests/ahci-test.c +++ b/tests/ahci-test.c @@ -78,25 +78,23 @@ static void string_bswap16(uint16_t *s, size_t bytes) /** * Verify that the transfer did not corrupt our state at all. */ -static void verify_state(AHCIQState *ahci) +static void verify_state(AHCIQState *ahci, uint64_t hba_old) { int i, j; uint32_t ahci_fingerprint; uint64_t hba_base; - uint64_t hba_stored; AHCICommandHeader cmd; ahci_fingerprint = qpci_config_readl(ahci->dev, PCI_VENDOR_ID); g_assert_cmphex(ahci_fingerprint, ==, ahci->fingerprint); /* If we haven't initialized, this is as much as can be validated. */ - if (!ahci->hba_base) { + if (!ahci->enabled) { return; } hba_base = (uint64_t)qpci_config_readl(ahci->dev, PCI_BASE_ADDRESS_5); - hba_stored = (uint64_t)(uintptr_t)ahci->hba_base; - g_assert_cmphex(hba_base, ==, hba_stored); + g_assert_cmphex(hba_base, ==, hba_old); g_assert_cmphex(ahci_rreg(ahci, AHCI_CAP), ==, ahci->cap); g_assert_cmphex(ahci_rreg(ahci, AHCI_CAP2), ==, ahci->cap2); @@ -119,12 +117,15 @@ static void ahci_migrate(AHCIQState *from, AHCIQState *to, const char *uri) QOSState *tmp = to->parent; QPCIDevice *dev = to->dev; char *uri_local = NULL; + uint64_t hba_old; if (uri == NULL) { uri_local = g_strdup_printf("%s%s", "unix:", mig_socket); uri = uri_local; } + hba_old = (uint64_t)qpci_config_readl(from->dev, PCI_BASE_ADDRESS_5); + /* context will be 'to' after completion. */ migrate(from->parent, to->parent, uri); @@ -141,7 +142,7 @@ static void ahci_migrate(AHCIQState *from, AHCIQState *to, const char *uri) from->parent = tmp; from->dev = dev; - verify_state(to); + verify_state(to, hba_old); g_free(uri_local); } @@ -154,7 +155,7 @@ static AHCIQState *ahci_vboot(const char *cli, va_list ap) { AHCIQState *s; - s = g_malloc0(sizeof(AHCIQState)); + s = g_new0(AHCIQState, 1); s->parent = qtest_pc_vboot(cli, ap); alloc_set_flags(s->parent->alloc, ALLOC_LEAK_ASSERT); @@ -1063,11 +1064,34 @@ static void test_dma_fragmented(void) g_free(tx); } +/* + * Write sector 1 with random data to make AHCI storage dirty + * Needed for flush tests so that flushes actually go though the block layer + */ +static void make_dirty(AHCIQState* ahci, uint8_t port) +{ + uint64_t ptr; + unsigned bufsize = 512; + + ptr = ahci_alloc(ahci, bufsize); + g_assert(ptr); + + ahci_guest_io(ahci, port, CMD_WRITE_DMA, ptr, bufsize, 1); + ahci_free(ahci, ptr); +} + static void test_flush(void) { AHCIQState *ahci; + uint8_t port; ahci = ahci_boot_and_enable(NULL); + + port = ahci_port_select(ahci); + ahci_port_clear(ahci, port); + + make_dirty(ahci, port); + ahci_test_flush(ahci); ahci_shutdown(ahci); } @@ -1087,10 +1111,13 @@ static void test_flush_retry(void) debug_path, tmp_path, imgfmt); - /* Issue Flush Command and wait for error */ port = ahci_port_select(ahci); ahci_port_clear(ahci, port); + /* Issue write so that flush actually goes to disk */ + make_dirty(ahci, port); + + /* Issue Flush Command and wait for error */ cmd = ahci_guest_io_halt(ahci, port, CMD_FLUSH_CACHE, 0, 0, 0); ahci_guest_io_resume(ahci, cmd); @@ -1105,9 +1132,9 @@ static void test_migrate_sanity(void) AHCIQState *src, *dst; char *uri = g_strdup_printf("unix:%s", mig_socket); - src = ahci_boot("-m 1024 -M q35 " + src = ahci_boot("-m 384 -M q35 " "-drive if=ide,file=%s,format=%s ", tmp_path, imgfmt); - dst = ahci_boot("-m 1024 -M q35 " + dst = ahci_boot("-m 384 -M q35 " "-drive if=ide,file=%s,format=%s " "-incoming %s", tmp_path, imgfmt, uri); @@ -1130,10 +1157,10 @@ static void ahci_migrate_simple(uint8_t cmd_read, uint8_t cmd_write) unsigned char *rx = g_malloc0(bufsize); char *uri = g_strdup_printf("unix:%s", mig_socket); - src = ahci_boot_and_enable("-m 1024 -M q35 " + src = ahci_boot_and_enable("-m 384 -M q35 " "-drive if=ide,format=%s,file=%s ", imgfmt, tmp_path); - dst = ahci_boot("-m 1024 -M q35 " + dst = ahci_boot("-m 384 -M q35 " "-drive if=ide,format=%s,file=%s " "-incoming %s", imgfmt, tmp_path, uri); @@ -1343,9 +1370,13 @@ static void test_flush_migrate(void) set_context(src->parent); - /* Issue Flush Command */ px = ahci_port_select(src); ahci_port_clear(src, px); + + /* Dirty device so that flush reaches disk */ + make_dirty(src, px); + + /* Issue Flush Command */ cmd = ahci_command_create(CMD_FLUSH_CACHE); ahci_command_commit(src, cmd, px); ahci_command_issue_async(src, cmd); @@ -1442,8 +1473,13 @@ static int ahci_cb_cmp_buff(AHCIQState *ahci, AHCICommand *cmd, const AHCIOpts *opts) { unsigned char *tx = opts->opaque; - unsigned char *rx = g_malloc0(opts->size); + unsigned char *rx; + if (!opts->size) { + return 0; + } + + rx = g_malloc0(opts->size); bufread(opts->buffer, rx, opts->size); g_assert_cmphex(memcmp(tx, rx, opts->size), ==, 0); g_free(rx); @@ -1451,7 +1487,8 @@ static int ahci_cb_cmp_buff(AHCIQState *ahci, AHCICommand *cmd, return 0; } -static void ahci_test_cdrom(int nsectors, bool dma) +static void ahci_test_cdrom(int nsectors, bool dma, uint8_t cmd, + bool override_bcl, uint16_t bcl) { AHCIQState *ahci; unsigned char *tx; @@ -1462,10 +1499,13 @@ static void ahci_test_cdrom(int nsectors, bool dma) .atapi = true, .atapi_dma = dma, .post_cb = ahci_cb_cmp_buff, + .set_bcl = override_bcl, + .bcl = bcl, }; + uint64_t iso_size = ATAPI_SECTOR_SIZE * (nsectors + 1); /* Prepare ISO and fill 'tx' buffer */ - fd = prepare_iso(1024 * 1024, &tx, &iso); + fd = prepare_iso(iso_size, &tx, &iso); opts.opaque = tx; /* Standard startup wonkery, but use ide-cd and our special iso file */ @@ -1474,7 +1514,7 @@ static void ahci_test_cdrom(int nsectors, bool dma) "-device ide-cd,drive=drive0 ", iso); /* Build & Send AHCI command */ - ahci_exec(ahci, ahci_port_select(ahci), CMD_ATAPI_READ_10, &opts); + ahci_exec(ahci, ahci_port_select(ahci), cmd, &opts); /* Cleanup */ g_free(tx); @@ -1482,24 +1522,133 @@ static void ahci_test_cdrom(int nsectors, bool dma) remove_iso(fd, iso); } +static void ahci_test_cdrom_read10(int nsectors, bool dma) +{ + ahci_test_cdrom(nsectors, dma, CMD_ATAPI_READ_10, false, 0); +} + static void test_cdrom_dma(void) { - ahci_test_cdrom(1, true); + ahci_test_cdrom_read10(1, true); } static void test_cdrom_dma_multi(void) { - ahci_test_cdrom(3, true); + ahci_test_cdrom_read10(3, true); } static void test_cdrom_pio(void) { - ahci_test_cdrom(1, false); + ahci_test_cdrom_read10(1, false); } static void test_cdrom_pio_multi(void) { - ahci_test_cdrom(3, false); + ahci_test_cdrom_read10(3, false); +} + +/* Regression test: Test that a READ_CD command with a BCL of 0 but a size of 0 + * completes as a NOP instead of erroring out. */ +static void test_atapi_bcl(void) +{ + ahci_test_cdrom(0, false, CMD_ATAPI_READ_CD, true, 0); +} + + +static void atapi_wait_tray(bool open) +{ + QDict *rsp = qmp_eventwait_ref("DEVICE_TRAY_MOVED"); + QDict *data = qdict_get_qdict(rsp, "data"); + if (open) { + g_assert(qdict_get_bool(data, "tray-open")); + } else { + g_assert(!qdict_get_bool(data, "tray-open")); + } + QDECREF(rsp); +} + +static void test_atapi_tray(void) +{ + AHCIQState *ahci; + unsigned char *tx; + char *iso; + int fd; + uint8_t port, sense, asc; + uint64_t iso_size = ATAPI_SECTOR_SIZE; + QDict *rsp; + + fd = prepare_iso(iso_size, &tx, &iso); + ahci = ahci_boot_and_enable("-drive if=none,id=drive0,file=%s,format=raw " + "-M q35 " + "-device ide-cd,drive=drive0 ", iso); + port = ahci_port_select(ahci); + + ahci_atapi_eject(ahci, port); + atapi_wait_tray(true); + + ahci_atapi_load(ahci, port); + atapi_wait_tray(false); + + /* Remove media */ + qmp_async("{'execute': 'blockdev-open-tray', " + "'arguments': {'device': 'drive0'}}"); + atapi_wait_tray(true); + rsp = qmp_receive(); + QDECREF(rsp); + + qmp_discard_response("{'execute': 'x-blockdev-remove-medium', " + "'arguments': {'device': 'drive0'}}"); + + /* Test the tray without a medium */ + ahci_atapi_load(ahci, port); + atapi_wait_tray(false); + + ahci_atapi_eject(ahci, port); + atapi_wait_tray(true); + + /* Re-insert media */ + qmp_discard_response("{'execute': 'blockdev-add', " + "'arguments': {'node-name': 'node0', " + "'driver': 'raw', " + "'file': { 'driver': 'file', " + "'filename': %s }}}", iso); + qmp_discard_response("{'execute': 'x-blockdev-insert-medium'," + "'arguments': { 'device': 'drive0', " + "'node-name': 'node0' }}"); + + /* Again, the event shows up first */ + qmp_async("{'execute': 'blockdev-close-tray', " + "'arguments': {'device': 'drive0'}}"); + atapi_wait_tray(false); + rsp = qmp_receive(); + QDECREF(rsp); + + /* Now, to convince ATAPI we understand the media has changed... */ + ahci_atapi_test_ready(ahci, port, false, SENSE_NOT_READY); + ahci_atapi_get_sense(ahci, port, &sense, &asc); + g_assert_cmpuint(sense, ==, SENSE_NOT_READY); + g_assert_cmpuint(asc, ==, ASC_MEDIUM_NOT_PRESENT); + + ahci_atapi_test_ready(ahci, port, false, SENSE_UNIT_ATTENTION); + ahci_atapi_get_sense(ahci, port, &sense, &asc); + g_assert_cmpuint(sense, ==, SENSE_UNIT_ATTENTION); + g_assert_cmpuint(asc, ==, ASC_MEDIUM_MAY_HAVE_CHANGED); + + ahci_atapi_test_ready(ahci, port, true, SENSE_NO_SENSE); + ahci_atapi_get_sense(ahci, port, &sense, &asc); + g_assert_cmpuint(sense, ==, SENSE_NO_SENSE); + + /* Final tray test. */ + ahci_atapi_eject(ahci, port); + atapi_wait_tray(true); + + ahci_atapi_load(ahci, port); + atapi_wait_tray(false); + + /* Cleanup */ + g_free(tx); + ahci_shutdown(ahci); + remove_iso(fd, iso); } /******************************************************************************/ @@ -1657,7 +1806,7 @@ static void create_ahci_io_test(enum IOMode type, enum AddrMode addr, char *name; AHCIIOTestOptions *opts; - opts = g_malloc(sizeof(AHCIIOTestOptions)); + opts = g_new(AHCIIOTestOptions, 1); opts->length = len; opts->address_type = addr; opts->io_type = type; @@ -1791,6 +1940,9 @@ int main(int argc, char **argv) qtest_add_func("/ahci/cdrom/pio/single", test_cdrom_pio); qtest_add_func("/ahci/cdrom/pio/multi", test_cdrom_pio_multi); + qtest_add_func("/ahci/cdrom/pio/bcl", test_atapi_bcl); + qtest_add_func("/ahci/cdrom/eject", test_atapi_tray); + ret = g_test_run(); /* Cleanup */