diff --git a/hw/fdc.c b/hw/fdc.c
index a0236b7..5e855fd 100644
--- a/hw/fdc.c
+++ b/hw/fdc.c
@@ -1301,12 +1301,42 @@ static int fdctrl_transfer_handler (void *opaque, int nchan,
     return len;
 }
 
+enum {
+    FD_DATA_IDLE,
+    FD_DATA_WORKING,
+    FD_DATA_FIN,
+};
+
+int data_status[MAX_FD];
+
+static void fdctrl_read_pio_cb(void *opaque, int ret)
+{
+    FDCtrl *fdctrl = opaque;
+    FDrive *cur_drv;
+
+    if (ret < 0) {
+        cur_drv = get_cur_drv(fdctrl);
+        FLOPPY_DPRINTF("error getting sector %d\n",
+                       fd_sector(cur_drv));
+        /* Sure, image size is too small... */
+        memset(fdctrl->fifo, 0, FD_SECTOR_LEN);
+        data_status[fdctrl->cur_drv] = FD_DATA_IDLE;
+        goto end;
+    }
+    data_status[fdctrl->cur_drv] = FD_DATA_FIN;
+
+end:
+    return;
+}
+
 /* Data register : 0x05 */
 static uint32_t fdctrl_read_data(FDCtrl *fdctrl)
 {
     FDrive *cur_drv;
     uint32_t retval = 0;
     int pos;
+    QEMUIOVector qiov;
+    struct iovec iov;
 
     cur_drv = get_cur_drv(fdctrl);
     fdctrl->dsr &= ~FD_DSR_PWRDOWN;
@@ -1318,17 +1348,30 @@ static uint32_t fdctrl_read_data(FDCtrl *fdctrl)
     if (fdctrl->msr & FD_MSR_NONDMA) {
         pos %= FD_SECTOR_LEN;
         if (pos == 0) {
-            if (fdctrl->data_pos != 0)
-                if (!fdctrl_seek_to_next_sect(fdctrl, cur_drv)) {
-                    FLOPPY_DPRINTF("error seeking to next sector %d\n",
-                                   fd_sector(cur_drv));
-                    return 0;
+            switch (data_status[fdctrl->cur_drv]) {
+            case FD_DATA_IDLE:
+                if (fdctrl->data_pos != 0) {
+                    if (!fdctrl_seek_to_next_sect(fdctrl, cur_drv)) {
+                        FLOPPY_DPRINTF("error seeking to next sector %d\n",
+                                         fd_sector(cur_drv));
+                        goto end;
+                    }
                 }
-            if (bdrv_read(cur_drv->bs, fd_sector(cur_drv), fdctrl->fifo, 1) < 0) {
-                FLOPPY_DPRINTF("error getting sector %d\n",
-                               fd_sector(cur_drv));
-                /* Sure, image size is too small... */
-                memset(fdctrl->fifo, 0, FD_SECTOR_LEN);
+                iov.iov_base = fdctrl->fifo;
+                iov.iov_len  = FD_SECTOR_LEN;
+                qemu_iovec_init_external(&qiov, &iov, 1);
+                bdrv_aio_readv(cur_drv->bs, fd_sector(cur_drv),
+                    &qiov, 1, fdctrl_read_pio_cb, fdctrl);
+                data_status[fdctrl->cur_drv] = FD_DATA_WORKING;
+                goto end;
+            case FD_DATA_WORKING:
+                goto end;
+            case FD_DATA_FIN:
+                data_status[fdctrl->cur_drv] = FD_DATA_IDLE;
+                break;
+            default:
+                data_status[fdctrl->cur_drv] = FD_DATA_IDLE;
+                goto end;
             }
         }
     }
@@ -1347,6 +1390,7 @@ static uint32_t fdctrl_read_data(FDCtrl *fdctrl)
     }
     FLOPPY_DPRINTF("data register: 0x%02x\n", retval);
 
+end:
     return retval;
 }
 
@@ -1759,10 +1803,38 @@ static const struct {
 /* Associate command to an index in the 'handlers' array */
 static uint8_t command_to_handler[256];
 
+static void fdctrl_write_pio_cb(void *opaque, int ret)
+{
+    FDCtrl *fdctrl = opaque;
+    FDrive *cur_drv;
+
+    cur_drv = get_cur_drv(fdctrl);
+    if (ret < 0) {
+        FLOPPY_ERROR("writing sector %d\n", fd_sector(cur_drv));
+        goto end;
+    }
+    if (!fdctrl_seek_to_next_sect(fdctrl, cur_drv)) {
+        FLOPPY_DPRINTF("error seeking to next sector %d\n",
+                       fd_sector(cur_drv));
+        goto end;
+    }
+    /* Switch from transfer mode to status mode
+     * then from status mode to command mode
+     */
+    if (fdctrl->data_pos == fdctrl->data_len) {
+        fdctrl_stop_transfer(fdctrl, FD_SR0_SEEK, 0x00, 0x00);
+    }
+
+end:
+    return;
+}
+
 static void fdctrl_write_data(FDCtrl *fdctrl, uint32_t value)
 {
     FDrive *cur_drv;
     int pos;
+    QEMUIOVector qiov;
+    struct iovec iov;
 
     /* Reset mode */
     if (!(fdctrl->dor & FD_DOR_nRESET)) {
@@ -1780,25 +1852,16 @@ static void fdctrl_write_data(FDCtrl *fdctrl, uint32_t value)
         pos = fdctrl->data_pos++;
         pos %= FD_SECTOR_LEN;
         fdctrl->fifo[pos] = value;
-        if (pos == FD_SECTOR_LEN - 1 ||
-            fdctrl->data_pos == fdctrl->data_len) {
+        if ((pos == FD_SECTOR_LEN - 1) ||
+            (fdctrl->data_pos == fdctrl->data_len)) {
             cur_drv = get_cur_drv(fdctrl);
-            if (bdrv_write(cur_drv->bs, fd_sector(cur_drv), fdctrl->fifo, 1) < 0) {
-                FLOPPY_ERROR("writing sector %d\n", fd_sector(cur_drv));
-                return;
-            }
-            if (!fdctrl_seek_to_next_sect(fdctrl, cur_drv)) {
-                FLOPPY_DPRINTF("error seeking to next sector %d\n",
-                               fd_sector(cur_drv));
-                return;
-            }
+            iov.iov_base = fdctrl->fifo;
+            iov.iov_len  = FD_SECTOR_LEN;
+            qemu_iovec_init_external(&qiov, &iov, 1);
+            bdrv_aio_writev(cur_drv->bs, fd_sector(cur_drv),
+                &qiov, 1, fdctrl_write_pio_cb, fdctrl);
+            return;
         }
-        /* Switch from transfer mode to status mode
-         * then from status mode to command mode
-         */
-        if (fdctrl->data_pos == fdctrl->data_len)
-            fdctrl_stop_transfer(fdctrl, FD_SR0_SEEK, 0x00, 0x00);
-        return;
     }
     if (fdctrl->data_pos == 0) {
         /* Command */
