aboutsummaryrefslogtreecommitdiff
path: root/hw/ide/core.c
diff options
context:
space:
mode:
authorJohn Snow <jsnow@redhat.com>2014-10-01 18:55:47 -0400
committerStefan Hajnoczi <stefanha@redhat.com>2014-11-03 09:48:41 +0000
commit659142ecf71a0da240ab0ff7cf929ee25c32b9bc (patch)
tree2c3890a83310e734b490dc6dec985459e5b7c94b /hw/ide/core.c
parent7b8bad1b6abde7612940900dd1092dad873f1a11 (diff)
ahci: Update byte count after DMA completion
Currently, DMA read/write operations neglect to update the byte count after a successful transfer like ATAPI DMA read or PIO read/write operations do. We correct this oversight by adding another callback into the IDEDMAOps structure. The commit callback is called whenever we are cleaning up a scatter-gather list. AHCI can register this callback in order to update post- transfer information such as byte count updates. We use this callback in AHCI to consolidate where we delete the SGlist as generated from the PRDT, as well as update the byte count after the transfer is complete. The QEMUSGList structure has an init flag added to it in order to make qemu_sglist_destroy a nop if it is called when there is no sglist, which simplifies cleanup and error paths. This patch fixes several AHCI problems, notably Non-NCQ modes of operation for Windows 7 as well as Hibernate support for Windows 7. Signed-off-by: John Snow <jsnow@redhat.com> Reviewed-by: Paolo Bonzini <pbonzini@redhat.com> Tested-by: Michael S. Tsirkin <mst@redhat.com> Message-id: 1412204151-18117-3-git-send-email-jsnow@redhat.com Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
Diffstat (limited to 'hw/ide/core.c')
-rw-r--r--hw/ide/core.c11
1 files changed, 7 insertions, 4 deletions
diff --git a/hw/ide/core.c b/hw/ide/core.c
index 44e3d502d4..d316ccf961 100644
--- a/hw/ide/core.c
+++ b/hw/ide/core.c
@@ -634,8 +634,11 @@ void ide_sector_read(IDEState *s)
ide_sector_read_cb, s);
}
-static void dma_buf_commit(IDEState *s)
+static void dma_buf_commit(IDEState *s, uint32_t tx_bytes)
{
+ if (s->bus->dma->ops->commit_buf) {
+ s->bus->dma->ops->commit_buf(s->bus->dma, tx_bytes);
+ }
qemu_sglist_destroy(&s->sg);
}
@@ -650,6 +653,7 @@ void ide_set_inactive(IDEState *s, bool more)
void ide_dma_error(IDEState *s)
{
+ dma_buf_commit(s, 0);
ide_abort_command(s);
ide_set_inactive(s, false);
ide_set_irq(s->bus);
@@ -665,7 +669,6 @@ static int ide_handle_rw_error(IDEState *s, int error, int op)
s->bus->error_status = op;
} else if (action == BLOCK_ERROR_ACTION_REPORT) {
if (op & IDE_RETRY_DMA) {
- dma_buf_commit(s);
ide_dma_error(s);
} else {
ide_rw_error(s);
@@ -709,7 +712,8 @@ void ide_dma_cb(void *opaque, int ret)
sector_num = ide_get_sector(s);
if (n > 0) {
- dma_buf_commit(s);
+ assert(s->io_buffer_size == s->sg.size);
+ dma_buf_commit(s, s->io_buffer_size);
sector_num += n;
ide_set_sector(s, sector_num);
s->nsector -= n;
@@ -740,7 +744,6 @@ void ide_dma_cb(void *opaque, int ret)
if ((s->dma_cmd == IDE_DMA_READ || s->dma_cmd == IDE_DMA_WRITE) &&
!ide_sect_range_ok(s, sector_num, n)) {
- dma_buf_commit(s);
ide_dma_error(s);
return;
}