From 6aff22c013ab6f5f711665e7031fd555086d4464 Mon Sep 17 00:00:00 2001 From: John Snow Date: Thu, 19 Mar 2015 20:24:13 -0400 Subject: ide: fix cmd_write_pio when nsectors > 1 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit We need to adjust the sector being written to prior to calling ide_transfer_start, otherwise we'll write to the same sector again. Signed-off-by: John Snow Reviewed-by: Stefan Hajnoczi Tested-by: Andreas Färber Message-id: 1426811056-2202-2-git-send-email-jsnow@redhat.com --- hw/ide/core.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hw/ide/core.c b/hw/ide/core.c index ef52f3516f..0e9da648ea 100644 --- a/hw/ide/core.c +++ b/hw/ide/core.c @@ -846,6 +846,7 @@ static void ide_sector_write_cb(void *opaque, int ret) s->nsector -= n; s->io_buffer_offset += 512 * n; + ide_set_sector(s, ide_get_sector(s) + n); if (s->nsector == 0) { /* no more sectors to write */ ide_transfer_stop(s); @@ -857,7 +858,6 @@ static void ide_sector_write_cb(void *opaque, int ret) ide_transfer_start(s, s->io_buffer, n1 * BDRV_SECTOR_SIZE, ide_sector_write); } - ide_set_sector(s, ide_get_sector(s) + n); if (win2k_install_hack && ((++s->irq_count % 16) == 0)) { /* It seems there is a bug in the Windows 2000 installer HDD -- cgit v1.2.3 From dd0bf7baab2201bd8f834be9eb87766662f50b19 Mon Sep 17 00:00:00 2001 From: John Snow Date: Thu, 19 Mar 2015 20:24:14 -0400 Subject: ide: fix cmd_read_pio when nsectors > 1 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Similar to the cmd_write_pio fix, update the nsector count and ide sector before we invoke ide_transfer_start. Signed-off-by: John Snow Reviewed-by: Stefan Hajnoczi Tested-by: Andreas Färber Message-id: 1426811056-2202-3-git-send-email-jsnow@redhat.com --- hw/ide/core.c | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/hw/ide/core.c b/hw/ide/core.c index 0e9da648ea..a895fd86f6 100644 --- a/hw/ide/core.c +++ b/hw/ide/core.c @@ -587,14 +587,12 @@ static void ide_sector_read_cb(void *opaque, int ret) n = s->req_nb_sectors; } - /* Allow the guest to read the io_buffer */ - ide_transfer_start(s, s->io_buffer, n * BDRV_SECTOR_SIZE, ide_sector_read); - - ide_set_irq(s->bus); - ide_set_sector(s, ide_get_sector(s) + n); s->nsector -= n; + /* Allow the guest to read the io_buffer */ + ide_transfer_start(s, s->io_buffer, n * BDRV_SECTOR_SIZE, ide_sector_read); s->io_buffer_offset += 512 * n; + ide_set_irq(s->bus); } static void ide_sector_read(IDEState *s) -- cgit v1.2.3 From ac38123609742ce3fbdf53774a797ac230cbf118 Mon Sep 17 00:00:00 2001 From: John Snow Date: Thu, 19 Mar 2015 20:24:15 -0400 Subject: ahci: Fix sglist offset manipulation for BE machines MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This does not bother DMA, because DMA generally transfers the entire SGList in one shot if it can. PIO, on the other hand, tries to transfer just one sector at a time, and will make multiple visits to the sglist to fetch memory addresses. Fix the memory address calculaton when we have an offset by moving the offset addition OUTSIDE of the le64_to_cpu calculation. Signed-off-by: John Snow Reviewed-by: Stefan Hajnoczi Tested-by: Andreas Färber Message-id: 1426811056-2202-4-git-send-email-jsnow@redhat.com --- hw/ide/ahci.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hw/ide/ahci.c b/hw/ide/ahci.c index e1ae36f7cd..7a223bede7 100644 --- a/hw/ide/ahci.c +++ b/hw/ide/ahci.c @@ -799,7 +799,7 @@ static int ahci_populate_sglist(AHCIDevice *ad, QEMUSGList *sglist, qemu_sglist_init(sglist, qbus->parent, (sglist_alloc_hint - off_idx), ad->hba->as); - qemu_sglist_add(sglist, le64_to_cpu(tbl[off_idx].addr + off_pos), + qemu_sglist_add(sglist, le64_to_cpu(tbl[off_idx].addr) + off_pos, prdt_tbl_entry_size(&tbl[off_idx]) - off_pos); for (i = off_idx + 1; i < sglist_alloc_hint; i++) { -- cgit v1.2.3 From 54fced034e4d32d8ba6d1e27ecb7e2e2fb2f45d4 Mon Sep 17 00:00:00 2001 From: John Snow Date: Thu, 19 Mar 2015 20:24:16 -0400 Subject: ahci-test: improve rw buffer patterns MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit My pattern was cyclical every 256 bytes, so it missed a fairly obvious failure case. Add some rand() pepper into the test pattern, and for large patterns that exceed 256 sectors, start writing an ID per-sector so that we never generate identical sector patterns. Signed-off-by: John Snow Reviewed-by: Stefan Hajnoczi Tested-by: Andreas Färber Message-id: 1426811056-2202-5-git-send-email-jsnow@redhat.com --- tests/ahci-test.c | 36 ++++++++++++++++++++++++++++-------- 1 file changed, 28 insertions(+), 8 deletions(-) diff --git a/tests/ahci-test.c b/tests/ahci-test.c index 169e83b6ba..ea62e249f5 100644 --- a/tests/ahci-test.c +++ b/tests/ahci-test.c @@ -68,6 +68,32 @@ static void string_bswap16(uint16_t *s, size_t bytes) } } +static void generate_pattern(void *buffer, size_t len, size_t cycle_len) +{ + int i, j; + unsigned char *tx = (unsigned char *)buffer; + unsigned char p; + size_t *sx; + + /* Write an indicative pattern that varies and is unique per-cycle */ + p = rand() % 256; + for (i = j = 0; i < len; i++, j++) { + tx[i] = p; + if (j % cycle_len == 0) { + p = rand() % 256; + } + } + + /* force uniqueness by writing an id per-cycle */ + for (i = 0; i < len / cycle_len; i++) { + j = i * cycle_len; + if (j + sizeof(*sx) <= len) { + sx = (size_t *)&tx[j]; + *sx = i; + } + } +} + /*** Test Setup & Teardown ***/ /** @@ -736,7 +762,6 @@ static void ahci_test_io_rw_simple(AHCIQState *ahci, unsigned bufsize, { uint64_t ptr; uint8_t port; - unsigned i; unsigned char *tx = g_malloc(bufsize); unsigned char *rx = g_malloc0(bufsize); @@ -752,9 +777,7 @@ static void ahci_test_io_rw_simple(AHCIQState *ahci, unsigned bufsize, g_assert(ptr); /* Write some indicative pattern to our buffer. */ - for (i = 0; i < bufsize; i++) { - tx[i] = (bufsize - i); - } + generate_pattern(tx, bufsize, AHCI_SECTOR_SIZE); memwrite(ptr, tx, bufsize); /* Write this buffer to disk, then read it back to the DMA buffer. */ @@ -865,7 +888,6 @@ static void test_dma_fragmented(void) size_t bufsize = 4096; unsigned char *tx = g_malloc(bufsize); unsigned char *rx = g_malloc0(bufsize); - unsigned i; uint64_t ptr; ahci = ahci_boot_and_enable(); @@ -873,9 +895,7 @@ static void test_dma_fragmented(void) ahci_port_clear(ahci, px); /* create pattern */ - for (i = 0; i < bufsize; i++) { - tx[i] = (bufsize - i); - } + generate_pattern(tx, bufsize, AHCI_SECTOR_SIZE); /* Create a DMA buffer in guest memory, and write our pattern to it. */ ptr = guest_alloc(ahci->parent->alloc, bufsize); -- cgit v1.2.3