diff options
Diffstat (limited to 'hw/ide/core.c')
| -rw-r--r-- | hw/ide/core.c | 17 |
1 files changed, 15 insertions, 2 deletions
diff --git a/hw/ide/core.c b/hw/ide/core.c index d683a8cc84..8da894f240 100644 --- a/hw/ide/core.c +++ b/hw/ide/core.c @@ -336,7 +336,7 @@ static void trim_aio_cancel(BlockDriverAIOCB *acb) qemu_aio_release(iocb); } -static AIOPool trim_aio_pool = { +static const AIOCBInfo trim_aiocb_info = { .aiocb_size = sizeof(TrimAIOCB), .cancel = trim_aio_cancel, }; @@ -360,7 +360,7 @@ BlockDriverAIOCB *ide_issue_trim(BlockDriverState *bs, TrimAIOCB *iocb; int i, j, ret; - iocb = qemu_aio_get(&trim_aio_pool, bs, cb, opaque); + iocb = qemu_aio_get(&trim_aiocb_info, bs, cb, opaque); iocb->bh = qemu_bh_new(ide_trim_bh_cb, iocb); iocb->ret = 0; @@ -579,6 +579,7 @@ void ide_dma_cb(void *opaque, int ret) IDEState *s = opaque; int n; int64_t sector_num; + bool stay_active = false; if (ret < 0) { int op = BM_STATUS_DMA_RETRY; @@ -594,6 +595,14 @@ void ide_dma_cb(void *opaque, int ret) } n = s->io_buffer_size >> 9; + if (n > s->nsector) { + /* The PRDs were longer than needed for this request. Shorten them so + * we don't get a negative remainder. The Active bit must remain set + * after the request completes. */ + n = s->nsector; + stay_active = true; + } + sector_num = ide_get_sector(s); if (n > 0) { dma_buf_commit(s); @@ -616,6 +625,7 @@ void ide_dma_cb(void *opaque, int ret) if (s->bus->dma->ops->prepare_buf(s->bus->dma, ide_cmd_is_read(s)) == 0) { /* The PRDs were too short. Reset the Active bit, but don't raise an * interrupt. */ + s->status = READY_STAT | SEEK_STAT; goto eot; } @@ -646,6 +656,9 @@ eot: bdrv_acct_done(s->bs, &s->acct); } ide_set_inactive(s); + if (stay_active) { + s->bus->dma->ops->add_status(s->bus->dma, BM_STATUS_DMAING); + } } static void ide_sector_start_dma(IDEState *s, enum ide_dma_cmd dma_cmd) |