aboutsummaryrefslogtreecommitdiff
path: root/hw/ide/core.c
diff options
context:
space:
mode:
Diffstat (limited to 'hw/ide/core.c')
-rw-r--r--hw/ide/core.c137
1 files changed, 97 insertions, 40 deletions
diff --git a/hw/ide/core.c b/hw/ide/core.c
index 35723fd800..a5216a6aac 100644
--- a/hw/ide/core.c
+++ b/hw/ide/core.c
@@ -471,40 +471,68 @@ static void ide_rw_error(IDEState *s) {
ide_set_irq(s->bus);
}
+static void ide_sector_read_cb(void *opaque, int ret)
+{
+ IDEState *s = opaque;
+ int n;
+
+ s->pio_aiocb = NULL;
+ s->status &= ~BUSY_STAT;
+
+ bdrv_acct_done(s->bs, &s->acct);
+ if (ret != 0) {
+ if (ide_handle_rw_error(s, -ret, BM_STATUS_PIO_RETRY |
+ BM_STATUS_RETRY_READ)) {
+ return;
+ }
+ }
+
+ n = s->nsector;
+ if (n > s->req_nb_sectors) {
+ 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;
+}
+
void ide_sector_read(IDEState *s)
{
int64_t sector_num;
- int ret, n;
+ int n;
s->status = READY_STAT | SEEK_STAT;
s->error = 0; /* not needed by IDE spec, but needed by Windows */
sector_num = ide_get_sector(s);
n = s->nsector;
+
if (n == 0) {
- /* no more sector to read from disk */
ide_transfer_stop(s);
- } else {
+ return;
+ }
+
+ s->status |= BUSY_STAT;
+
+ if (n > s->req_nb_sectors) {
+ n = s->req_nb_sectors;
+ }
+
#if defined(DEBUG_IDE)
- printf("read sector=%" PRId64 "\n", sector_num);
+ printf("sector=%" PRId64 "\n", sector_num);
#endif
- if (n > s->req_nb_sectors)
- n = s->req_nb_sectors;
- bdrv_acct_start(s->bs, &s->acct, n * BDRV_SECTOR_SIZE, BDRV_ACCT_READ);
- ret = bdrv_read(s->bs, sector_num, s->io_buffer, n);
- bdrv_acct_done(s->bs, &s->acct);
- if (ret != 0) {
- if (ide_handle_rw_error(s, -ret,
- BM_STATUS_PIO_RETRY | BM_STATUS_RETRY_READ))
- {
- return;
- }
- }
- ide_transfer_start(s, s->io_buffer, 512 * n, ide_sector_read);
- ide_set_irq(s->bus);
- ide_set_sector(s, sector_num + n);
- s->nsector -= n;
- }
+ s->iov.iov_base = s->io_buffer;
+ s->iov.iov_len = n * BDRV_SECTOR_SIZE;
+ qemu_iovec_init_external(&s->qiov, &s->iov, 1);
+
+ bdrv_acct_start(s->bs, &s->acct, n * BDRV_SECTOR_SIZE, BDRV_ACCT_READ);
+ s->pio_aiocb = bdrv_aio_readv(s->bs, sector_num, &s->qiov, n,
+ ide_sector_read_cb, s);
}
static void dma_buf_commit(IDEState *s)
@@ -660,40 +688,39 @@ static void ide_sector_write_timer_cb(void *opaque)
ide_set_irq(s->bus);
}
-void ide_sector_write(IDEState *s)
+static void ide_sector_write_cb(void *opaque, int ret)
{
- int64_t sector_num;
- int ret, n, n1;
-
- s->status = READY_STAT | SEEK_STAT;
- sector_num = ide_get_sector(s);
-#if defined(DEBUG_IDE)
- printf("write sector=%" PRId64 "\n", sector_num);
-#endif
- n = s->nsector;
- if (n > s->req_nb_sectors)
- n = s->req_nb_sectors;
+ IDEState *s = opaque;
+ int n;
- bdrv_acct_start(s->bs, &s->acct, n * BDRV_SECTOR_SIZE, BDRV_ACCT_READ);
- ret = bdrv_write(s->bs, sector_num, s->io_buffer, n);
bdrv_acct_done(s->bs, &s->acct);
+ s->pio_aiocb = NULL;
+ s->status &= ~BUSY_STAT;
+
if (ret != 0) {
- if (ide_handle_rw_error(s, -ret, BM_STATUS_PIO_RETRY))
+ if (ide_handle_rw_error(s, -ret, BM_STATUS_PIO_RETRY)) {
return;
+ }
}
+ n = s->nsector;
+ if (n > s->req_nb_sectors) {
+ n = s->req_nb_sectors;
+ }
s->nsector -= n;
if (s->nsector == 0) {
/* no more sectors to write */
ide_transfer_stop(s);
} else {
- n1 = s->nsector;
- if (n1 > s->req_nb_sectors)
+ int n1 = s->nsector;
+ if (n1 > s->req_nb_sectors) {
n1 = s->req_nb_sectors;
- ide_transfer_start(s, s->io_buffer, 512 * n1, ide_sector_write);
+ }
+ ide_transfer_start(s, s->io_buffer, n1 * BDRV_SECTOR_SIZE,
+ ide_sector_write);
}
- ide_set_sector(s, sector_num + n);
+ 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
@@ -709,6 +736,30 @@ void ide_sector_write(IDEState *s)
}
}
+void ide_sector_write(IDEState *s)
+{
+ int64_t sector_num;
+ int n;
+
+ s->status = READY_STAT | SEEK_STAT | BUSY_STAT;
+ sector_num = ide_get_sector(s);
+#if defined(DEBUG_IDE)
+ printf("sector=%" PRId64 "\n", sector_num);
+#endif
+ n = s->nsector;
+ if (n > s->req_nb_sectors) {
+ n = s->req_nb_sectors;
+ }
+
+ s->iov.iov_base = s->io_buffer;
+ s->iov.iov_len = n * BDRV_SECTOR_SIZE;
+ qemu_iovec_init_external(&s->qiov, &s->iov, 1);
+
+ bdrv_acct_start(s->bs, &s->acct, n * BDRV_SECTOR_SIZE, BDRV_ACCT_READ);
+ s->pio_aiocb = bdrv_aio_writev(s->bs, sector_num, &s->qiov, n,
+ ide_sector_write_cb, s);
+}
+
static void ide_flush_cb(void *opaque, int ret)
{
IDEState *s = opaque;
@@ -1765,6 +1816,12 @@ static void ide_reset(IDEState *s)
#ifdef DEBUG_IDE
printf("ide: reset\n");
#endif
+
+ if (s->pio_aiocb) {
+ bdrv_aio_cancel(s->pio_aiocb);
+ s->pio_aiocb = NULL;
+ }
+
if (s->drive_kind == IDE_CFATA)
s->mult_sectors = 0;
else