summaryrefslogtreecommitdiff
path: root/hw/ide/core.c
diff options
context:
space:
mode:
Diffstat (limited to 'hw/ide/core.c')
-rw-r--r--hw/ide/core.c67
1 files changed, 60 insertions, 7 deletions
diff --git a/hw/ide/core.c b/hw/ide/core.c
index 1cc6945d8..da3baab1e 100644
--- a/hw/ide/core.c
+++ b/hw/ide/core.c
@@ -457,7 +457,7 @@ BlockAIOCB *ide_issue_trim(BlockBackend *blk,
return &iocb->common;
}
-static inline void ide_abort_command(IDEState *s)
+void ide_abort_command(IDEState *s)
{
ide_transfer_stop(s);
s->status = READY_STAT | ERR_STAT;
@@ -561,6 +561,53 @@ static bool ide_sect_range_ok(IDEState *s,
return true;
}
+static void ide_buffered_readv_cb(void *opaque, int ret)
+{
+ IDEBufferedRequest *req = opaque;
+ if (!req->orphaned) {
+ if (!ret) {
+ qemu_iovec_from_buf(req->original_qiov, 0, req->iov.iov_base,
+ req->original_qiov->size);
+ }
+ req->original_cb(req->original_opaque, ret);
+ }
+ QLIST_REMOVE(req, list);
+ qemu_vfree(req->iov.iov_base);
+ g_free(req);
+}
+
+#define MAX_BUFFERED_REQS 16
+
+BlockAIOCB *ide_buffered_readv(IDEState *s, int64_t sector_num,
+ QEMUIOVector *iov, int nb_sectors,
+ BlockCompletionFunc *cb, void *opaque)
+{
+ BlockAIOCB *aioreq;
+ IDEBufferedRequest *req;
+ int c = 0;
+
+ QLIST_FOREACH(req, &s->buffered_requests, list) {
+ c++;
+ }
+ if (c > MAX_BUFFERED_REQS) {
+ return blk_abort_aio_request(s->blk, cb, opaque, -EIO);
+ }
+
+ req = g_new0(IDEBufferedRequest, 1);
+ req->original_qiov = iov;
+ req->original_cb = cb;
+ req->original_opaque = opaque;
+ req->iov.iov_base = qemu_blockalign(blk_bs(s->blk), iov->size);
+ req->iov.iov_len = iov->size;
+ qemu_iovec_init_external(&req->qiov, &req->iov, 1);
+
+ aioreq = blk_aio_readv(s->blk, sector_num, &req->qiov, nb_sectors,
+ ide_buffered_readv_cb, req);
+
+ QLIST_INSERT_HEAD(&s->buffered_requests, req, list);
+ return aioreq;
+}
+
static void ide_sector_read(IDEState *s);
static void ide_sector_read_cb(void *opaque, int ret)
@@ -574,7 +621,6 @@ static void ide_sector_read_cb(void *opaque, int ret)
if (ret == -ECANCELED) {
return;
}
- block_acct_done(blk_get_stats(s->blk), &s->acct);
if (ret != 0) {
if (ide_handle_rw_error(s, -ret, IDE_RETRY_PIO |
IDE_RETRY_READ)) {
@@ -582,6 +628,8 @@ static void ide_sector_read_cb(void *opaque, int ret)
}
}
+ block_acct_done(blk_get_stats(s->blk), &s->acct);
+
n = s->nsector;
if (n > s->req_nb_sectors) {
n = s->req_nb_sectors;
@@ -621,6 +669,7 @@ static void ide_sector_read(IDEState *s)
if (!ide_sect_range_ok(s, sector_num, n)) {
ide_rw_error(s);
+ block_acct_invalid(blk_get_stats(s->blk), BLOCK_ACCT_READ);
return;
}
@@ -630,8 +679,8 @@ static void ide_sector_read(IDEState *s)
block_acct_start(blk_get_stats(s->blk), &s->acct,
n * BDRV_SECTOR_SIZE, BLOCK_ACCT_READ);
- s->pio_aiocb = blk_aio_readv(s->blk, sector_num, &s->qiov, n,
- ide_sector_read_cb, s);
+ s->pio_aiocb = ide_buffered_readv(s, sector_num, &s->qiov, n,
+ ide_sector_read_cb, s);
}
void dma_buf_commit(IDEState *s, uint32_t tx_bytes)
@@ -672,6 +721,7 @@ static int ide_handle_rw_error(IDEState *s, int error, int op)
assert(s->bus->retry_unit == s->unit);
s->bus->error_status = op;
} else if (action == BLOCK_ERROR_ACTION_REPORT) {
+ block_acct_failed(blk_get_stats(s->blk), &s->acct);
if (op & IDE_RETRY_DMA) {
ide_dma_error(s);
} else {
@@ -750,6 +800,7 @@ static 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)) {
ide_dma_error(s);
+ block_acct_invalid(blk_get_stats(s->blk), s->acct.type);
return;
}
@@ -826,7 +877,6 @@ static void ide_sector_write_cb(void *opaque, int ret)
if (ret == -ECANCELED) {
return;
}
- block_acct_done(blk_get_stats(s->blk), &s->acct);
s->pio_aiocb = NULL;
s->status &= ~BUSY_STAT;
@@ -837,6 +887,8 @@ static void ide_sector_write_cb(void *opaque, int ret)
}
}
+ block_acct_done(blk_get_stats(s->blk), &s->acct);
+
n = s->nsector;
if (n > s->req_nb_sectors) {
n = s->req_nb_sectors;
@@ -887,6 +939,7 @@ static void ide_sector_write(IDEState *s)
if (!ide_sect_range_ok(s, sector_num, n)) {
ide_rw_error(s);
+ block_acct_invalid(blk_get_stats(s->blk), BLOCK_ACCT_WRITE);
return;
}
@@ -895,7 +948,7 @@ static void ide_sector_write(IDEState *s)
qemu_iovec_init_external(&s->qiov, &s->iov, 1);
block_acct_start(blk_get_stats(s->blk), &s->acct,
- n * BDRV_SECTOR_SIZE, BLOCK_ACCT_READ);
+ n * BDRV_SECTOR_SIZE, BLOCK_ACCT_WRITE);
s->pio_aiocb = blk_aio_writev(s->blk, sector_num, &s->qiov, n,
ide_sector_write_cb, s);
}
@@ -2312,7 +2365,7 @@ int ide_init_drive(IDEState *s, BlockBackend *blk, IDEDriveKind kind,
if (version) {
pstrcpy(s->version, sizeof(s->version), version);
} else {
- pstrcpy(s->version, sizeof(s->version), qemu_get_version());
+ pstrcpy(s->version, sizeof(s->version), qemu_hw_version());
}
ide_reset(s);