]> Git Repo - qemu.git/blobdiff - hw/ide.c
windows cdrom cache flush (Stefano Stabellini)
[qemu.git] / hw / ide.c
index 329d053e14c5bf80c2d3abdcdb1488af4807f3de..8a1957831d08a9ecc5602ee4053fe1e4db8a887b 100644 (file)
--- a/hw/ide.c
+++ b/hw/ide.c
@@ -1,5 +1,5 @@
 /*
- * QEMU IDE disk and CD-ROM Emulator
+ * QEMU IDE disk and CD/DVD-ROM Emulator
  *
  * Copyright (c) 2003 Fabrice Bellard
  * Copyright (c) 2006 Openedhand Ltd.
  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
  * THE SOFTWARE.
  */
-#include "vl.h"
+#include "hw.h"
+#include "pc.h"
+#include "pci.h"
+#include "scsi-disk.h"
+#include "pcmcia.h"
+#include "block.h"
+#include "qemu-timer.h"
+#include "sysemu.h"
+#include "ppc_mac.h"
 
 /* debug IDE devices */
 //#define DEBUG_IDE
 /* set to 1 set disable mult support */
 #define MAX_MULT_SECTORS 16
 
+#define IDE_DMA_BUF_SECTORS 256
+
+#if (IDE_DMA_BUF_SECTORS < MAX_MULT_SECTORS)
+#error "IDE_DMA_BUF_SECTORS must be bigger or equal to MAX_MULT_SECTORS"
+#endif
+
 /* ATAPI defines */
 
 #define ATAPI_PACKET_SIZE 12
  * of MODE_SENSE_POWER_PAGE */
 #define GPMODE_CDROM_PAGE              0x0d
 
+/*
+ * Based on values from <linux/cdrom.h> but extending CD_MINS
+ * to the maximum common size allowed by the Orange's Book ATIP
+ *
+ * 90 and 99 min CDs are also available but using them as the
+ * upper limit reduces the effectiveness of the heuristic to
+ * detect DVDs burned to less than 25% of their maximum capacity
+ */
+
+/* Some generally useful CD-ROM information */
+#define CD_MINS                       80 /* max. minutes per CD */
+#define CD_SECS                       60 /* seconds per minute */
+#define CD_FRAMES                     75 /* frames per second */
+#define CD_FRAMESIZE                2048 /* bytes per frame, "cooked" mode */
+#define CD_MAX_BYTES       (CD_MINS * CD_SECS * CD_FRAMES * CD_FRAMESIZE)
+#define CD_MAX_SECTORS     (CD_MAX_BYTES / 512)
+
+/*
+ * The MMC values are not IDE specific and might need to be moved
+ * to a common header if they are also needed for the SCSI emulation
+ */
+
+/* Profile list from MMC-6 revision 1 table 91 */
+#define MMC_PROFILE_NONE                0x0000
+#define MMC_PROFILE_CD_ROM              0x0008
+#define MMC_PROFILE_CD_R                0x0009
+#define MMC_PROFILE_CD_RW               0x000A
+#define MMC_PROFILE_DVD_ROM             0x0010
+#define MMC_PROFILE_DVD_R_SR            0x0011
+#define MMC_PROFILE_DVD_RAM             0x0012
+#define MMC_PROFILE_DVD_RW_RO           0x0013
+#define MMC_PROFILE_DVD_RW_SR           0x0014
+#define MMC_PROFILE_DVD_R_DL_SR         0x0015
+#define MMC_PROFILE_DVD_R_DL_JR         0x0016
+#define MMC_PROFILE_DVD_RW_DL           0x0017
+#define MMC_PROFILE_DVD_DDR             0x0018
+#define MMC_PROFILE_DVD_PLUS_RW         0x001A
+#define MMC_PROFILE_DVD_PLUS_R          0x001B
+#define MMC_PROFILE_DVD_PLUS_RW_DL      0x002A
+#define MMC_PROFILE_DVD_PLUS_R_DL       0x002B
+#define MMC_PROFILE_BD_ROM              0x0040
+#define MMC_PROFILE_BD_R_SRM            0x0041
+#define MMC_PROFILE_BD_R_RRM            0x0042
+#define MMC_PROFILE_BD_RE               0x0043
+#define MMC_PROFILE_HDDVD_ROM           0x0050
+#define MMC_PROFILE_HDDVD_R             0x0051
+#define MMC_PROFILE_HDDVD_RAM           0x0052
+#define MMC_PROFILE_HDDVD_RW            0x0053
+#define MMC_PROFILE_HDDVD_R_DL          0x0058
+#define MMC_PROFILE_HDDVD_RW_DL         0x005A
+#define MMC_PROFILE_INVALID             0xFFFF
+
 #define ATAPI_INT_REASON_CD             0x01 /* 0 = data transfer */
 #define ATAPI_INT_REASON_IO             0x02 /* 1 = transfer to the host */
 #define ATAPI_INT_REASON_REL            0x04
 #define ASC_ILLEGAL_OPCODE                   0x20
 #define ASC_LOGICAL_BLOCK_OOR                0x21
 #define ASC_INV_FIELD_IN_CMD_PACKET          0x24
+#define ASC_MEDIUM_MAY_HAVE_CHANGED          0x28
+#define ASC_INCOMPATIBLE_FORMAT              0x30
 #define ASC_MEDIUM_NOT_PRESENT               0x3a
 #define ASC_SAVING_PARAMETERS_NOT_SUPPORTED  0x39
 
@@ -357,8 +425,8 @@ typedef struct IDEState {
     EndTransferFunc *end_transfer_func;
     uint8_t *data_ptr;
     uint8_t *data_end;
-    uint8_t io_buffer[MAX_MULT_SECTORS*512 + 4];
-    QEMUTimer *sector_write_timer; /* only used for win2k instal hack */
+    uint8_t *io_buffer;
+    QEMUTimer *sector_write_timer; /* only used for win2k install hack */
     uint32_t irq_count; /* counts IRQs when using win2k install hack */
     /* CF-ATA extended error */
     uint8_t ext_error;
@@ -368,6 +436,22 @@ typedef struct IDEState {
     int media_changed;
 } IDEState;
 
+/* XXX: DVDs that could fit on a CD will be reported as a CD */
+static inline int media_present(IDEState *s)
+{
+    return (s->nb_sectors > 0);
+}
+
+static inline int media_is_dvd(IDEState *s)
+{
+    return (media_present(s) && s->nb_sectors > CD_MAX_SECTORS);
+}
+
+static inline int media_is_cd(IDEState *s)
+{
+    return (media_present(s) && s->nb_sectors <= CD_MAX_SECTORS);
+}
+
 #define BM_STATUS_DMAING 0x01
 #define BM_STATUS_ERROR  0x02
 #define BM_STATUS_INT    0x04
@@ -422,8 +506,7 @@ static void padstr(char *str, const char *src, int len)
             v = *src++;
         else
             v = ' ';
-        *(char *)((long)str ^ 1) = v;
-        str++;
+        str[i^1] = v;
     }
 }
 
@@ -463,12 +546,12 @@ static void ide_identify(IDEState *s)
     put_le16(p + 5, 512); /* XXX: retired, remove ? */
     put_le16(p + 6, s->sectors);
     snprintf(buf, sizeof(buf), "QM%05d", s->drive_serial);
-    padstr((uint8_t *)(p + 10), buf, 20); /* serial number */
+    padstr((char *)(p + 10), buf, 20); /* serial number */
     put_le16(p + 20, 3); /* XXX: retired, remove ? */
     put_le16(p + 21, 512); /* cache size in sectors */
     put_le16(p + 22, 4); /* ecc bytes */
-    padstr((uint8_t *)(p + 23), QEMU_VERSION, 8); /* firmware version */
-    padstr((uint8_t *)(p + 27), "QEMU HARDDISK", 40); /* model */
+    padstr((char *)(p + 23), QEMU_VERSION, 8); /* firmware version */
+    padstr((char *)(p + 27), "QEMU HARDDISK", 40); /* model */
 #if MAX_MULT_SECTORS > 1
     put_le16(p + 47, 0x8000 | MAX_MULT_SECTORS);
 #endif
@@ -487,6 +570,7 @@ static void ide_identify(IDEState *s)
         put_le16(p + 59, 0x100 | s->mult_sectors);
     put_le16(p + 60, s->nb_sectors);
     put_le16(p + 61, s->nb_sectors >> 16);
+    put_le16(p + 62, 0x07); /* single word dma0-2 supported */
     put_le16(p + 63, 0x07); /* mdma0-2 supported */
     put_le16(p + 65, 120);
     put_le16(p + 66, 120);
@@ -528,16 +612,17 @@ static void ide_atapi_identify(IDEState *s)
     /* Removable CDROM, 50us response, 12 byte packets */
     put_le16(p + 0, (2 << 14) | (5 << 8) | (1 << 7) | (2 << 5) | (0 << 0));
     snprintf(buf, sizeof(buf), "QM%05d", s->drive_serial);
-    padstr((uint8_t *)(p + 10), buf, 20); /* serial number */
+    padstr((char *)(p + 10), buf, 20); /* serial number */
     put_le16(p + 20, 3); /* buffer type */
     put_le16(p + 21, 512); /* cache size in sectors */
     put_le16(p + 22, 4); /* ecc bytes */
-    padstr((uint8_t *)(p + 23), QEMU_VERSION, 8); /* firmware version */
-    padstr((uint8_t *)(p + 27), "QEMU CD-ROM", 40); /* model */
+    padstr((char *)(p + 23), QEMU_VERSION, 8); /* firmware version */
+    padstr((char *)(p + 27), "QEMU DVD-ROM", 40); /* model */
     put_le16(p + 48, 1); /* dword I/O (XXX: should not be set on CDROM) */
 #ifdef USE_DMA_CDROM
     put_le16(p + 49, 1 << 9 | 1 << 8); /* DMA and LBA supported */
     put_le16(p + 53, 7); /* words 64-70, 54-58, 88 valid */
+    put_le16(p + 62, 7);  /* single word dma0-2 supported */
     put_le16(p + 63, 7);  /* mdma0-2 supported */
     put_le16(p + 64, 0x3f); /* PIO modes supported */
 #else
@@ -583,10 +668,10 @@ static void ide_cfata_identify(IDEState *s)
     put_le16(p + 7, s->nb_sectors >> 16);      /* Sectors per card */
     put_le16(p + 8, s->nb_sectors);            /* Sectors per card */
     snprintf(buf, sizeof(buf), "QM%05d", s->drive_serial);
-    padstr((uint8_t *)(p + 10), buf, 20);      /* Serial number in ASCII */
+    padstr((char *)(p + 10), buf, 20); /* Serial number in ASCII */
     put_le16(p + 22, 0x0004);                  /* ECC bytes */
-    padstr((uint8_t *) (p + 23), QEMU_VERSION, 8);     /* Firmware Revision */
-    padstr((uint8_t *) (p + 27), "QEMU MICRODRIVE", 40);/* Model number */
+    padstr((char *) (p + 23), QEMU_VERSION, 8);        /* Firmware Revision */
+    padstr((char *) (p + 27), "QEMU MICRODRIVE", 40);/* Model number */
 #if MAX_MULT_SECTORS > 1
     put_le16(p + 47, 0x8000 | MAX_MULT_SECTORS);
 #else
@@ -654,6 +739,14 @@ static inline void ide_abort_command(IDEState *s)
     s->error = ABRT_ERR;
 }
 
+static inline void ide_dma_submit_check(IDEState *s,
+          BlockDriverCompletionFunc *dma_cb, BMDMAState *bm)
+{
+    if (bm->aiocb)
+       return;
+    dma_cb(bm, -1);
+}
+
 static inline void ide_set_irq(IDEState *s)
 {
     BMDMAState *bm = s->bmdma;
@@ -733,6 +826,11 @@ static void ide_set_sector(IDEState *s, int64_t sector_num)
     }
 }
 
+static void ide_rw_error(IDEState *s) {
+    ide_abort_command(s);
+    ide_set_irq(s);
+}
+
 static void ide_sector_read(IDEState *s)
 {
     int64_t sector_num;
@@ -747,11 +845,15 @@ static void ide_sector_read(IDEState *s)
         ide_transfer_stop(s);
     } else {
 #if defined(DEBUG_IDE)
-        printf("read sector=%Ld\n", sector_num);
+        printf("read sector=%" PRId64 "\n", sector_num);
 #endif
         if (n > s->req_nb_sectors)
             n = s->req_nb_sectors;
         ret = bdrv_read(s->bs, sector_num, s->io_buffer, n);
+        if (ret != 0) {
+            ide_rw_error(s);
+            return;
+        }
         ide_transfer_start(s, s->io_buffer, 512 * n, ide_sector_read);
         ide_set_irq(s);
         ide_set_sector(s, sector_num + n);
@@ -759,6 +861,14 @@ static void ide_sector_read(IDEState *s)
     }
 }
 
+static void ide_dma_error(IDEState *s)
+{
+    ide_transfer_stop(s);
+    s->error = ABRT_ERR;
+    s->status = READY_STAT | ERR_STAT;
+    ide_set_irq(s);
+}
+
 /* return 0 if buffer completed */
 static int dma_buf_rw(BMDMAState *bm, int is_write)
 {
@@ -807,7 +917,6 @@ static int dma_buf_rw(BMDMAState *bm, int is_write)
     return 1;
 }
 
-/* XXX: handle errors */
 static void ide_read_dma_cb(void *opaque, int ret)
 {
     BMDMAState *bm = opaque;
@@ -815,6 +924,11 @@ static void ide_read_dma_cb(void *opaque, int ret)
     int n;
     int64_t sector_num;
 
+    if (ret < 0) {
+       ide_dma_error(s);
+       return;
+    }
+
     n = s->io_buffer_size >> 9;
     sector_num = ide_get_sector(s);
     if (n > 0) {
@@ -840,8 +954,8 @@ static void ide_read_dma_cb(void *opaque, int ret)
 
     /* launch next transfer */
     n = s->nsector;
-    if (n > MAX_MULT_SECTORS)
-        n = MAX_MULT_SECTORS;
+    if (n > IDE_DMA_BUF_SECTORS)
+        n = IDE_DMA_BUF_SECTORS;
     s->io_buffer_index = 0;
     s->io_buffer_size = n * 512;
 #ifdef DEBUG_AIO
@@ -849,6 +963,7 @@ static void ide_read_dma_cb(void *opaque, int ret)
 #endif
     bm->aiocb = bdrv_aio_read(s->bs, sector_num, s->io_buffer, n,
                               ide_read_dma_cb, bm);
+    ide_dma_submit_check(s, ide_read_dma_cb, bm);
 }
 
 static void ide_sector_read_dma(IDEState *s)
@@ -865,53 +980,25 @@ static void ide_sector_write_timer_cb(void *opaque)
     ide_set_irq(s);
 }
 
-static void ide_sector_write_aio_cb(void *opaque, int ret)
-{
-    BMDMAState *bm = opaque;
-    IDEState *s = bm->ide_if;
-
-#ifdef TARGET_I386
-    if (win2k_install_hack && ((++s->irq_count % 16) == 0)) {
-       /* It seems there is a bug in the Windows 2000 installer HDD
-          IDE driver which fills the disk with empty logs when the
-          IDE write IRQ comes too early. This hack tries to correct
-          that at the expense of slower write performances. Use this
-          option _only_ to install Windows 2000. You must disable it
-          for normal use. */
-       qemu_mod_timer(s->sector_write_timer,
-                      qemu_get_clock(vm_clock) + (ticks_per_sec / 1000));
-    } else
-#endif
-    {
-       ide_set_irq(s);
-    }
-    bm->aiocb = NULL;
-}
-
 static void ide_sector_write(IDEState *s)
 {
-    BMDMAState *bm;
     int64_t sector_num;
-    int n, n1;
-
-    s->io_buffer_index = 0;
-    s->io_buffer_size = 0;
-    bm = s->bmdma;
-    if(bm == NULL) {
-       bm = qemu_mallocz(sizeof(BMDMAState));
-       s->bmdma = bm;
-    }
-    bm->ide_if = s;
-    bm->dma_cb = ide_sector_write_aio_cb;
+    int ret, n, n1;
 
     s->status = READY_STAT | SEEK_STAT;
     sector_num = ide_get_sector(s);
 #if defined(DEBUG_IDE)
-    printf("write sector=%Ld\n", sector_num);
+    printf("write sector=%" PRId64 "\n", sector_num);
 #endif
     n = s->nsector;
     if (n > s->req_nb_sectors)
         n = s->req_nb_sectors;
+    ret = bdrv_write(s->bs, sector_num, s->io_buffer, n);
+    if (ret != 0) {
+       ide_rw_error(s);
+       return;
+    }
+
     s->nsector -= n;
     if (s->nsector == 0) {
         /* no more sectors to write */
@@ -924,11 +1011,23 @@ static void ide_sector_write(IDEState *s)
     }
     ide_set_sector(s, sector_num + n);
 
-    bm->aiocb = bdrv_aio_write(s->bs, sector_num, s->io_buffer, n,
-                              ide_sector_write_aio_cb, bm);
+#ifdef TARGET_I386
+    if (win2k_install_hack && ((++s->irq_count % 16) == 0)) {
+        /* It seems there is a bug in the Windows 2000 installer HDD
+           IDE driver which fills the disk with empty logs when the
+           IDE write IRQ comes too early. This hack tries to correct
+           that at the expense of slower write performances. Use this
+           option _only_ to install Windows 2000. You must disable it
+           for normal use. */
+        qemu_mod_timer(s->sector_write_timer, 
+                       qemu_get_clock(vm_clock) + (ticks_per_sec / 1000));
+    } else 
+#endif
+    {
+        ide_set_irq(s);
+    }
 }
 
-/* XXX: handle errors */
 static void ide_write_dma_cb(void *opaque, int ret)
 {
     BMDMAState *bm = opaque;
@@ -936,6 +1035,11 @@ static void ide_write_dma_cb(void *opaque, int ret)
     int n;
     int64_t sector_num;
 
+    if (ret < 0) {
+       ide_dma_error(s);
+       return;
+    }
+
     n = s->io_buffer_size >> 9;
     sector_num = ide_get_sector(s);
     if (n > 0) {
@@ -959,8 +1063,8 @@ static void ide_write_dma_cb(void *opaque, int ret)
 
     /* launch next transfer */
     n = s->nsector;
-    if (n > MAX_MULT_SECTORS)
-        n = MAX_MULT_SECTORS;
+    if (n > IDE_DMA_BUF_SECTORS)
+        n = IDE_DMA_BUF_SECTORS;
     s->io_buffer_index = 0;
     s->io_buffer_size = n * 512;
 
@@ -971,6 +1075,7 @@ static void ide_write_dma_cb(void *opaque, int ret)
 #endif
     bm->aiocb = bdrv_aio_write(s->bs, sector_num, s->io_buffer, n,
                                ide_write_dma_cb, bm);
+    ide_dma_submit_check(s, ide_write_dma_cb, bm);
 }
 
 static void ide_sector_write_dma(IDEState *s)
@@ -984,7 +1089,7 @@ static void ide_sector_write_dma(IDEState *s)
 static void ide_atapi_cmd_ok(IDEState *s)
 {
     s->error = 0;
-    s->status = READY_STAT;
+    s->status = READY_STAT | SEEK_STAT;
     s->nsector = (s->nsector & ~7) | ATAPI_INT_REASON_IO | ATAPI_INT_REASON_CD;
     ide_set_irq(s);
 }
@@ -1002,6 +1107,17 @@ static void ide_atapi_cmd_error(IDEState *s, int sense_key, int asc)
     ide_set_irq(s);
 }
 
+static void ide_atapi_cmd_check_status(IDEState *s)
+{
+#ifdef DEBUG_IDE_ATAPI
+    printf("atapi_cmd_check_status\n");
+#endif
+    s->error = MC_ERR | (SENSE_UNIT_ATTENTION << 4);
+    s->status = ERR_STAT;
+    s->nsector = 0;
+    ide_set_irq(s);
+}
+
 static inline void cpu_to_ube16(uint8_t *buf, int val)
 {
     buf[0] = val >> 8;
@@ -1098,7 +1214,7 @@ static void ide_atapi_cmd_reply_end(IDEState *s)
     if (s->packet_transfer_size <= 0) {
         /* end of transfer */
         ide_transfer_stop(s);
-        s->status = READY_STAT;
+        s->status = READY_STAT | SEEK_STAT;
         s->nsector = (s->nsector & ~7) | ATAPI_INT_REASON_IO | ATAPI_INT_REASON_CD;
         ide_set_irq(s);
 #ifdef DEBUG_IDE_ATAPI
@@ -1176,10 +1292,10 @@ static void ide_atapi_cmd_reply(IDEState *s, int size, int max_size)
     s->io_buffer_index = 0;
 
     if (s->atapi_dma) {
-       s->status = READY_STAT | DRQ_STAT;
+       s->status = READY_STAT | SEEK_STAT | DRQ_STAT;
        ide_dma_start(s, ide_atapi_cmd_read_dma_cb);
     } else {
-       s->status = READY_STAT;
+       s->status = READY_STAT | SEEK_STAT;
        ide_atapi_cmd_reply_end(s);
     }
 }
@@ -1194,7 +1310,7 @@ static void ide_atapi_cmd_read_pio(IDEState *s, int lba, int nb_sectors,
     s->io_buffer_index = sector_size;
     s->cd_sector_size = sector_size;
 
-    s->status = READY_STAT;
+    s->status = READY_STAT | SEEK_STAT;
     ide_atapi_cmd_reply_end(s);
 }
 
@@ -1235,7 +1351,7 @@ static void ide_atapi_cmd_read_dma_cb(void *opaque, int ret)
     }
 
     if (s->packet_transfer_size <= 0) {
-        s->status = READY_STAT;
+        s->status = READY_STAT | SEEK_STAT;
         s->nsector = (s->nsector & ~7) | ATAPI_INT_REASON_IO | ATAPI_INT_REASON_CD;
         ide_set_irq(s);
     eot:
@@ -1254,8 +1370,8 @@ static void ide_atapi_cmd_read_dma_cb(void *opaque, int ret)
         data_offset = 16;
     } else {
         n = s->packet_transfer_size >> 11;
-        if (n > (MAX_MULT_SECTORS / 4))
-            n = (MAX_MULT_SECTORS / 4);
+        if (n > (IDE_DMA_BUF_SECTORS / 4))
+            n = (IDE_DMA_BUF_SECTORS / 4);
         s->io_buffer_size = n * 2048;
         data_offset = 0;
     }
@@ -1285,7 +1401,7 @@ static void ide_atapi_cmd_read_dma(IDEState *s, int lba, int nb_sectors,
     s->cd_sector_size = sector_size;
 
     /* XXX: check if BUSY_STAT should be set */
-    s->status = READY_STAT | DRQ_STAT | BUSY_STAT;
+    s->status = READY_STAT | SEEK_STAT | DRQ_STAT | BUSY_STAT;
     ide_dma_start(s, ide_atapi_cmd_read_dma_cb);
 }
 
@@ -1303,6 +1419,109 @@ static void ide_atapi_cmd_read(IDEState *s, int lba, int nb_sectors,
     }
 }
 
+static inline uint8_t ide_atapi_set_profile(uint8_t *buf, uint8_t *index,
+                                            uint16_t profile)
+{
+    uint8_t *buf_profile = buf + 12; /* start of profiles */
+
+    buf_profile += ((*index) * 4); /* start of indexed profile */
+    cpu_to_ube16 (buf_profile, profile);
+    buf_profile[2] = ((buf_profile[0] == buf[6]) && (buf_profile[1] == buf[7]));
+
+    /* each profile adds 4 bytes to the response */
+    (*index)++;
+    buf[11] += 4; /* Additional Length */
+
+    return 4;
+}
+
+static int ide_dvd_read_structure(IDEState *s, int format,
+                                  const uint8_t *packet, uint8_t *buf)
+{
+    switch (format) {
+        case 0x0: /* Physical format information */
+            {
+                int layer = packet[6];
+                uint64_t total_sectors;
+
+                if (layer != 0)
+                    return -ASC_INV_FIELD_IN_CMD_PACKET;
+
+                bdrv_get_geometry(s->bs, &total_sectors);
+                total_sectors >>= 2;
+                if (total_sectors == 0)
+                    return -ASC_MEDIUM_NOT_PRESENT;
+
+                buf[4] = 1;   /* DVD-ROM, part version 1 */
+                buf[5] = 0xf; /* 120mm disc, minimum rate unspecified */
+                buf[6] = 1;   /* one layer, read-only (per MMC-2 spec) */
+                buf[7] = 0;   /* default densities */
+
+                /* FIXME: 0x30000 per spec? */
+                cpu_to_ube32(buf + 8, 0); /* start sector */
+                cpu_to_ube32(buf + 12, total_sectors - 1); /* end sector */
+                cpu_to_ube32(buf + 16, total_sectors - 1); /* l0 end sector */
+
+                /* Size of buffer, not including 2 byte size field */
+                cpu_to_be16wu((uint16_t *)buf, 2048 + 2);
+
+                /* 2k data + 4 byte header */
+                return (2048 + 4);
+            }
+
+        case 0x01: /* DVD copyright information */
+            buf[4] = 0; /* no copyright data */
+            buf[5] = 0; /* no region restrictions */
+
+            /* Size of buffer, not including 2 byte size field */
+            cpu_to_be16wu((uint16_t *)buf, 4 + 2);
+
+            /* 4 byte header + 4 byte data */
+            return (4 + 4);
+
+        case 0x03: /* BCA information - invalid field for no BCA info */
+            return -ASC_INV_FIELD_IN_CMD_PACKET;
+
+        case 0x04: /* DVD disc manufacturing information */
+            /* Size of buffer, not including 2 byte size field */
+            cpu_to_be16wu((uint16_t *)buf, 2048 + 2);
+
+            /* 2k data + 4 byte header */
+            return (2048 + 4);
+
+        case 0xff:
+            /*
+             * This lists all the command capabilities above.  Add new ones
+             * in order and update the length and buffer return values.
+             */
+
+            buf[4] = 0x00; /* Physical format */
+            buf[5] = 0x40; /* Not writable, is readable */
+            cpu_to_be16wu((uint16_t *)(buf + 6), 2048 + 4);
+
+            buf[8] = 0x01; /* Copyright info */
+            buf[9] = 0x40; /* Not writable, is readable */
+            cpu_to_be16wu((uint16_t *)(buf + 10), 4 + 4);
+
+            buf[12] = 0x03; /* BCA info */
+            buf[13] = 0x40; /* Not writable, is readable */
+            cpu_to_be16wu((uint16_t *)(buf + 14), 188 + 4);
+
+            buf[16] = 0x04; /* Manufacturing info */
+            buf[17] = 0x40; /* Not writable, is readable */
+            cpu_to_be16wu((uint16_t *)(buf + 18), 2048 + 4);
+
+            /* Size of buffer, not including 2 byte size field */
+            cpu_to_be16wu((uint16_t *)buf, 16 + 2);
+
+            /* data written + 4 byte header */
+            return (16 + 4);
+
+        default: /* TODO: formats beyond DVD-ROM requires */
+            return -ASC_INV_FIELD_IN_CMD_PACKET;
+    }
+}
+
 static void ide_atapi_cmd(IDEState *s)
 {
     const uint8_t *packet;
@@ -1321,6 +1540,14 @@ static void ide_atapi_cmd(IDEState *s)
         printf("\n");
     }
 #endif
+    /* If there's a UNIT_ATTENTION condition pending, only
+       REQUEST_SENSE and INQUIRY commands are allowed to complete. */
+    if (s->sense_key == SENSE_UNIT_ATTENTION &&
+       s->io_buffer[0] != GPCMD_REQUEST_SENSE &&
+       s->io_buffer[0] != GPCMD_INQUIRY) {
+       ide_atapi_cmd_check_status(s);
+       return;
+    }
     switch(s->io_buffer[0]) {
     case GPCMD_TEST_UNIT_READY:
         if (bdrv_is_inserted(s->bs)) {
@@ -1373,7 +1600,7 @@ static void ide_atapi_cmd(IDEState *s)
 
                     buf[8] = 0x2a;
                     buf[9] = 0x12;
-                    buf[10] = 0x08;
+                    buf[10] = 0x00;
                     buf[11] = 0x00;
 
                     buf[12] = 0x70;
@@ -1416,6 +1643,8 @@ static void ide_atapi_cmd(IDEState *s)
         buf[2] = s->sense_key;
         buf[7] = 10;
         buf[12] = s->asc;
+        if (s->sense_key == SENSE_UNIT_ATTENTION)
+            s->sense_key = SENSE_NONE;
         ide_atapi_cmd_reply(s, 18, max_len);
         break;
     case GPCMD_PREVENT_ALLOW_MEDIUM_REMOVAL:
@@ -1477,12 +1706,12 @@ static void ide_atapi_cmd(IDEState *s)
         break;
     case GPCMD_SEEK:
         {
-            int lba;
-            int64_t total_sectors;
+            unsigned int lba;
+            uint64_t total_sectors;
 
             bdrv_get_geometry(s->bs, &total_sectors);
             total_sectors >>= 2;
-            if (total_sectors <= 0) {
+            if (total_sectors == 0) {
                 ide_atapi_cmd_error(s, SENSE_NOT_READY,
                                     ASC_MEDIUM_NOT_PRESENT);
                 break;
@@ -1528,11 +1757,11 @@ static void ide_atapi_cmd(IDEState *s)
     case GPCMD_READ_TOC_PMA_ATIP:
         {
             int format, msf, start_track, len;
-            int64_t total_sectors;
+            uint64_t total_sectors;
 
             bdrv_get_geometry(s->bs, &total_sectors);
             total_sectors >>= 2;
-            if (total_sectors <= 0) {
+            if (total_sectors == 0) {
                 ide_atapi_cmd_error(s, SENSE_NOT_READY,
                                     ASC_MEDIUM_NOT_PRESENT);
                 break;
@@ -1572,11 +1801,11 @@ static void ide_atapi_cmd(IDEState *s)
         break;
     case GPCMD_READ_CDVD_CAPACITY:
         {
-            int64_t total_sectors;
+            uint64_t total_sectors;
 
             bdrv_get_geometry(s->bs, &total_sectors);
             total_sectors >>= 2;
-            if (total_sectors <= 0) {
+            if (total_sectors == 0) {
                 ide_atapi_cmd_error(s, SENSE_NOT_READY,
                                     ASC_MEDIUM_NOT_PRESENT);
                 break;
@@ -1590,37 +1819,48 @@ static void ide_atapi_cmd(IDEState *s)
     case GPCMD_READ_DVD_STRUCTURE:
         {
             int media = packet[1];
-            int layer = packet[6];
-            int format = packet[2];
-            int64_t total_sectors;
-
-            if (media != 0 || layer != 0)
-            {
-                ide_atapi_cmd_error(s, SENSE_ILLEGAL_REQUEST,
-                                    ASC_INV_FIELD_IN_CMD_PACKET);
-            }
+            int format = packet[7];
+            int ret;
 
-            switch (format) {
-                case 0:
-                    bdrv_get_geometry(s->bs, &total_sectors);
-                    total_sectors >>= 2;
-
-                    memset(buf, 0, 2052);
+            max_len = ube16_to_cpu(packet + 8);
 
-                    buf[4] = 1;   // DVD-ROM, part version 1
-                    buf[5] = 0xf; // 120mm disc, maximum rate unspecified
-                    buf[6] = 0;   // one layer, embossed data
-                    buf[7] = 0;
+            if (format < 0xff) {
+                if (media_is_cd(s)) {
+                    ide_atapi_cmd_error(s, SENSE_ILLEGAL_REQUEST,
+                                        ASC_INCOMPATIBLE_FORMAT);
+                    break;
+                } else if (!media_present(s)) {
+                    ide_atapi_cmd_error(s, SENSE_ILLEGAL_REQUEST,
+                                        ASC_INV_FIELD_IN_CMD_PACKET);
+                    break;
+                }
+            }
 
-                    cpu_to_ube32(buf + 8, 0);
-                    cpu_to_ube32(buf + 12, total_sectors - 1);
-                    cpu_to_ube32(buf + 16, total_sectors - 1);
+            memset(buf, 0, max_len > IDE_DMA_BUF_SECTORS * 512 + 4 ?
+                   IDE_DMA_BUF_SECTORS * 512 + 4 : max_len);
 
-                    cpu_to_be16wu((uint16_t *)buf, 2048 + 4);
+            switch (format) {
+                case 0x00 ... 0x7f:
+                case 0xff:
+                    if (media == 0) {
+                        ret = ide_dvd_read_structure(s, format, packet, buf);
 
-                    ide_atapi_cmd_reply(s, 2048 + 3, 2048 + 4);
-                    break;
+                        if (ret < 0)
+                            ide_atapi_cmd_error(s, SENSE_ILLEGAL_REQUEST, -ret);
+                        else
+                            ide_atapi_cmd_reply(s, ret, max_len);
 
+                        break;
+                    }
+                    /* TODO: BD support, fall through for now */
+
+                /* Generic disk structures */
+                case 0x80: /* TODO: AACS volume identifier */
+                case 0x81: /* TODO: AACS media serial number */
+                case 0x82: /* TODO: AACS media identifier */
+                case 0x83: /* TODO: AACS media key block */
+                case 0x90: /* TODO: List of recognized format layers */
+                case 0xc0: /* TODO: Write protection status */
                 default:
                     ide_atapi_cmd_error(s, SENSE_ILLEGAL_REQUEST,
                                         ASC_INV_FIELD_IN_CMD_PACKET);
@@ -1642,13 +1882,14 @@ static void ide_atapi_cmd(IDEState *s)
         buf[6] = 0; /* reserved */
         buf[7] = 0; /* reserved */
         padstr8(buf + 8, 8, "QEMU");
-        padstr8(buf + 16, 16, "QEMU CD-ROM");
+        padstr8(buf + 16, 16, "QEMU DVD-ROM");
         padstr8(buf + 32, 4, QEMU_VERSION);
         ide_atapi_cmd_reply(s, 36, max_len);
         break;
     case GPCMD_GET_CONFIGURATION:
         {
-            int64_t total_sectors;
+            uint32_t len;
+            uint8_t index = 0;
 
             /* only feature 0 is supported */
             if (packet[2] != 0 || packet[3] != 0) {
@@ -1656,17 +1897,37 @@ static void ide_atapi_cmd(IDEState *s)
                                     ASC_INV_FIELD_IN_CMD_PACKET);
                 break;
             }
-            memset(buf, 0, 32);
-            bdrv_get_geometry(s->bs, &total_sectors);
-            buf[3] = 16;
-            buf[7] = total_sectors <= 1433600 ? 0x08 : 0x10; /* current profile */
-            buf[10] = 0x10 | 0x1;
-            buf[11] = 0x08; /* size of profile list */
-            buf[13] = 0x10; /* DVD-ROM profile */
-            buf[14] = buf[7] == 0x10; /* (in)active */
-            buf[17] = 0x08; /* CD-ROM profile */
-            buf[18] = buf[7] == 0x08; /* (in)active */
-            ide_atapi_cmd_reply(s, 32, 32);
+
+            /* XXX: could result in alignment problems in some architectures */
+            max_len = ube16_to_cpu(packet + 7);
+
+            /*
+             * XXX: avoid overflow for io_buffer if max_len is bigger than
+             *      the size of that buffer (dimensioned to max number of
+             *      sectors to transfer at once)
+             *
+             *      Only a problem if the feature/profiles grow.
+             */
+            if (max_len > 512) /* XXX: assume 1 sector */
+                max_len = 512;
+
+            memset(buf, 0, max_len);
+            /* 
+             * the number of sectors from the media tells us which profile
+             * to use as current.  0 means there is no media
+             */
+            if (media_is_dvd(s))
+                cpu_to_ube16(buf + 6, MMC_PROFILE_DVD_ROM);
+            else if (media_is_cd(s))
+                cpu_to_ube16(buf + 6, MMC_PROFILE_CD_ROM);
+
+            buf[10] = 0x02 | 0x01; /* persistent and current */
+            len = 12; /* headers: 8 + 4 */
+            len += ide_atapi_set_profile(buf, &index, MMC_PROFILE_DVD_ROM);
+            len += ide_atapi_set_profile(buf, &index, MMC_PROFILE_CD_ROM);
+            cpu_to_ube32(buf, len - 4); /* data length */
+
+            ide_atapi_cmd_reply(s, len, max_len);
             break;
         }
     default:
@@ -1733,11 +1994,15 @@ static void ide_cfata_metadata_write(IDEState *s)
 static void cdrom_change_cb(void *opaque)
 {
     IDEState *s = opaque;
-    int64_t nb_sectors;
+    uint64_t nb_sectors;
 
-    /* XXX: send interrupt too */
     bdrv_get_geometry(s->bs, &nb_sectors);
     s->nb_sectors = nb_sectors;
+
+    s->sense_key = SENSE_UNIT_ATTENTION;
+    s->asc = ASC_MEDIUM_MAY_HAVE_CHANGED;
+
+    ide_set_irq(s);
 }
 
 static void ide_cmd_lba48_transform(IDEState *s, int lba48)
@@ -1782,6 +2047,11 @@ static void ide_ioport_write(void *opaque, uint32_t addr, uint32_t val)
 #endif
 
     addr &= 7;
+
+    /* ignore writes to command block while busy with previous command */
+    if (addr != 7 && (ide_if->cur_drive->status & (BUSY_STAT|DRQ_STAT)))
+        return;
+
     switch(addr) {
     case 0:
         break;
@@ -1841,6 +2111,10 @@ static void ide_ioport_write(void *opaque, uint32_t addr, uint32_t val)
         if (s != ide_if && !s->bs)
             break;
 
+        /* Only DEVICE RESET is allowed while BSY or/and DRQ are set */
+        if ((s->status & (BUSY_STAT|DRQ_STAT)) && val != WIN_DEVICE_RESET)
+            break;
+
         switch(val) {
         case WIN_IDENTIFY:
             if (s->bs && !s->is_cdrom) {
@@ -1868,14 +2142,14 @@ static void ide_ioport_write(void *opaque, uint32_t addr, uint32_t val)
             if (s->is_cf && s->nsector == 0) {
                 /* Disable Read and Write Multiple */
                 s->mult_sectors = 0;
-                s->status = READY_STAT;
+                s->status = READY_STAT | SEEK_STAT;
             } else if ((s->nsector & 0xff) != 0 &&
                 ((s->nsector & 0xff) > MAX_MULT_SECTORS ||
                  (s->nsector & (s->nsector - 1)) != 0)) {
                 ide_abort_command(s);
             } else {
                 s->mult_sectors = s->nsector & 0xff;
-                s->status = READY_STAT;
+                s->status = READY_STAT | SEEK_STAT;
             }
             ide_set_irq(s);
             break;
@@ -1885,7 +2159,7 @@ static void ide_ioport_write(void *opaque, uint32_t addr, uint32_t val)
         case WIN_VERIFY_ONCE:
             /* do sector number check ? */
            ide_cmd_lba48_transform(s, lba48);
-            s->status = READY_STAT;
+            s->status = READY_STAT | SEEK_STAT;
             ide_set_irq(s);
             break;
        case WIN_READ_EXT:
@@ -1960,13 +2234,13 @@ static void ide_ioport_write(void *opaque, uint32_t addr, uint32_t val)
         case WIN_READ_NATIVE_MAX:
            ide_cmd_lba48_transform(s, lba48);
             ide_set_sector(s, s->nb_sectors - 1);
-            s->status = READY_STAT;
+            s->status = READY_STAT | SEEK_STAT;
             ide_set_irq(s);
             break;
         case WIN_CHECKPOWERMODE1:
         case WIN_CHECKPOWERMODE2:
             s->nsector = 0xff; /* device active or idle */
-            s->status = READY_STAT;
+            s->status = READY_STAT | SEEK_STAT;
             ide_set_irq(s);
             break;
         case WIN_SETFEATURES:
@@ -1997,14 +2271,22 @@ static void ide_ioport_write(void *opaque, uint32_t addr, uint32_t val)
                switch (s->nsector >> 3) {
                    case 0x00: /* pio default */
                    case 0x01: /* pio mode */
+                       put_le16(s->identify_data + 62,0x07);
+                       put_le16(s->identify_data + 63,0x07);
+                       put_le16(s->identify_data + 88,0x3f);
+                       break;
+                    case 0x02: /* sigle word dma mode*/
+                       put_le16(s->identify_data + 62,0x07 | (1 << (val + 8)));
                        put_le16(s->identify_data + 63,0x07);
                        put_le16(s->identify_data + 88,0x3f);
                        break;
                    case 0x04: /* mdma mode */
+                       put_le16(s->identify_data + 62,0x07);
                        put_le16(s->identify_data + 63,0x07 | (1 << (val + 8)));
                        put_le16(s->identify_data + 88,0x3f);
                        break;
                    case 0x08: /* udma mode */
+                       put_le16(s->identify_data + 62,0x07);
                        put_le16(s->identify_data + 63,0x07);
                        put_le16(s->identify_data + 88,0x3f | (1 << (val + 8)));
                        break;
@@ -2023,7 +2305,7 @@ static void ide_ioport_write(void *opaque, uint32_t addr, uint32_t val)
         case WIN_FLUSH_CACHE_EXT:
             if (s->bs)
                 bdrv_flush(s->bs);
-           s->status = READY_STAT;
+           s->status = READY_STAT | SEEK_STAT;
             ide_set_irq(s);
             break;
         case WIN_STANDBY:
@@ -2052,8 +2334,16 @@ static void ide_ioport_write(void *opaque, uint32_t addr, uint32_t val)
             break;
         case WIN_DIAGNOSE:
             ide_set_signature(s);
-            s->status = 0x00; /* NOTE: READY is _not_ set */
-            s->error = 0x01;
+            if (s->is_cdrom)
+                s->status = 0; /* ATAPI spec (v6) section 9.10 defines packet
+                                * devices to return a clear status register
+                                * with READY_STAT *not* set. */
+            else
+                s->status = READY_STAT | SEEK_STAT;
+            s->error = 0x01; /* Device 0 passed, Device 1 passed or not
+                              * present. 
+                              */
+            ide_set_irq(s);
             break;
         case WIN_SRST:
             if (!s->is_cdrom)
@@ -2068,7 +2358,7 @@ static void ide_ioport_write(void *opaque, uint32_t addr, uint32_t val)
             /* overlapping commands not supported */
             if (s->feature & 0x02)
                 goto abort_cmd;
-            s->status = READY_STAT;
+            s->status = READY_STAT | SEEK_STAT;
             s->atapi_dma = s->feature & 1;
             s->nsector = 1;
             ide_transfer_start(s, s->io_buffer, ATAPI_PACKET_SIZE,
@@ -2079,7 +2369,7 @@ static void ide_ioport_write(void *opaque, uint32_t addr, uint32_t val)
             if (!s->is_cf)
                 goto abort_cmd;
             s->error = 0x09;    /* miscellaneous error */
-            s->status = READY_STAT;
+            s->status = READY_STAT | SEEK_STAT;
             ide_set_irq(s);
             break;
         case CFA_ERASE_SECTORS:
@@ -2091,14 +2381,14 @@ static void ide_ioport_write(void *opaque, uint32_t addr, uint32_t val)
             if (val == CFA_ERASE_SECTORS)
                 s->media_changed = 1;
             s->error = 0x00;
-            s->status = READY_STAT;
+            s->status = READY_STAT | SEEK_STAT;
             ide_set_irq(s);
             break;
         case CFA_TRANSLATE_SECTOR:
             if (!s->is_cf)
                 goto abort_cmd;
             s->error = 0x00;
-            s->status = READY_STAT;
+            s->status = READY_STAT | SEEK_STAT;
             memset(s->io_buffer, 0, 0x200);
             s->io_buffer[0x00] = s->hcyl;                      /* Cyl MSB */
             s->io_buffer[0x01] = s->lcyl;                      /* Cyl LSB */
@@ -2144,7 +2434,7 @@ static void ide_ioport_write(void *opaque, uint32_t addr, uint32_t val)
             default:
                 goto abort_cmd;
             }
-            s->status = READY_STAT;
+            s->status = READY_STAT | SEEK_STAT;
             ide_set_irq(s);
             break;
         default:
@@ -2290,6 +2580,10 @@ static void ide_data_writew(void *opaque, uint32_t addr, uint32_t val)
     IDEState *s = ((IDEState *)opaque)->cur_drive;
     uint8_t *p;
 
+    /* PIO data access allowed only when DRQ bit is set */
+    if (!(s->status & DRQ_STAT))
+        return;
+
     p = s->data_ptr;
     *(uint16_t *)p = le16_to_cpu(val);
     p += 2;
@@ -2303,6 +2597,11 @@ static uint32_t ide_data_readw(void *opaque, uint32_t addr)
     IDEState *s = ((IDEState *)opaque)->cur_drive;
     uint8_t *p;
     int ret;
+
+    /* PIO data access allowed only when DRQ bit is set */
+    if (!(s->status & DRQ_STAT))
+        return 0;
+
     p = s->data_ptr;
     ret = cpu_to_le16(*(uint16_t *)p);
     p += 2;
@@ -2317,6 +2616,10 @@ static void ide_data_writel(void *opaque, uint32_t addr, uint32_t val)
     IDEState *s = ((IDEState *)opaque)->cur_drive;
     uint8_t *p;
 
+    /* PIO data access allowed only when DRQ bit is set */
+    if (!(s->status & DRQ_STAT))
+        return;
+
     p = s->data_ptr;
     *(uint32_t *)p = le32_to_cpu(val);
     p += 4;
@@ -2331,6 +2634,10 @@ static uint32_t ide_data_readl(void *opaque, uint32_t addr)
     uint8_t *p;
     int ret;
 
+    /* PIO data access allowed only when DRQ bit is set */
+    if (!(s->status & DRQ_STAT))
+        return 0;
+
     p = s->data_ptr;
     ret = cpu_to_le32(*(uint32_t *)p);
     p += 4;
@@ -2358,7 +2665,7 @@ static void ide_reset(IDEState *s)
         s->mult_sectors = MAX_MULT_SECTORS;
     s->cur_drive = s;
     s->select = 0xa0;
-    s->status = READY_STAT;
+    s->status = READY_STAT | SEEK_STAT;
     ide_set_signature(s);
     /* init the transfer handler so that 0xffff is returned on data
        accesses */
@@ -2384,17 +2691,19 @@ struct partition {
 static int guess_disk_lchs(IDEState *s,
                            int *pcylinders, int *pheads, int *psectors)
 {
-    uint8_t buf[512];
+    uint8_t *buf = s->io_buffer;
     int ret, i, heads, sectors, cylinders;
     struct partition *p;
     uint32_t nr_sects;
 
     ret = bdrv_read(s->bs, 0, buf, 1);
-    if (ret < 0)
+    if (ret < 0) {
         return -1;
+    }
     /* test msdos magic */
-    if (buf[510] != 0x55 || buf[511] != 0xaa)
+    if (buf[510] != 0x55 || buf[511] != 0xaa) {
         return -1;
+    }
     for(i = 0; i < 4; i++) {
         p = ((struct partition *)(buf + 0x1be)) + i;
         nr_sects = le32_to_cpu(p->nr_sects);
@@ -2428,10 +2737,11 @@ static void ide_init2(IDEState *ide_state,
     IDEState *s;
     static int drive_serial = 1;
     int i, cylinders, heads, secs, translation, lba_detected = 0;
-    int64_t nb_sectors;
+    uint64_t nb_sectors;
 
     for(i = 0; i < 2; i++) {
         s = ide_state + i;
+        s->io_buffer = qemu_memalign(512, IDE_DMA_BUF_SECTORS*512 + 4);
         if (i == 0)
             s->bs = hd0;
         else
@@ -2520,8 +2830,8 @@ static void ide_init_ioport(IDEState *ide_state, int iobase, int iobase2)
 /* save per IDE drive data */
 static void ide_save(QEMUFile* f, IDEState *s)
 {
-    qemu_put_be32s(f, &s->mult_sectors);
-    qemu_put_be32s(f, &s->identify_set);
+    qemu_put_be32(f, s->mult_sectors);
+    qemu_put_be32(f, s->identify_set);
     if (s->identify_set) {
         qemu_put_buffer(f, (const uint8_t *)s->identify_data, 512);
     }
@@ -2548,8 +2858,8 @@ static void ide_save(QEMUFile* f, IDEState *s)
 /* load per IDE drive data */
 static void ide_load(QEMUFile* f, IDEState *s)
 {
-    qemu_get_be32s(f, &s->mult_sectors);
-    qemu_get_be32s(f, &s->identify_set);
+    s->mult_sectors=qemu_get_be32(f);
+    s->identify_set=qemu_get_be32(f);
     if (s->identify_set) {
         qemu_get_buffer(f, (uint8_t *)s->identify_data, 512);
     }
@@ -2633,6 +2943,23 @@ static void ide_dma_start(IDEState *s, BlockDriverCompletionFunc *dma_cb)
     }
 }
 
+static void ide_dma_cancel(BMDMAState *bm)
+{
+    if (bm->status & BM_STATUS_DMAING) {
+        bm->status &= ~BM_STATUS_DMAING;
+        /* cancel DMA request */
+        bm->ide_if = NULL;
+        bm->dma_cb = NULL;
+        if (bm->aiocb) {
+#ifdef DEBUG_AIO
+            printf("aio_cancel\n");
+#endif
+            bdrv_aio_cancel(bm->aiocb);
+            bm->aiocb = NULL;
+        }
+    }
+}
+
 static void bmdma_cmd_writeb(void *opaque, uint32_t addr, uint32_t val)
 {
     BMDMAState *bm = opaque;
@@ -2641,19 +2968,7 @@ static void bmdma_cmd_writeb(void *opaque, uint32_t addr, uint32_t val)
 #endif
     if (!(val & BM_CMD_START)) {
         /* XXX: do it better */
-        if (bm->status & BM_STATUS_DMAING) {
-            bm->status &= ~BM_STATUS_DMAING;
-            /* cancel DMA request */
-            bm->ide_if = NULL;
-            bm->dma_cb = NULL;
-            if (bm->aiocb) {
-#ifdef DEBUG_AIO
-                printf("aio_cancel\n");
-#endif
-                bdrv_aio_cancel(bm->aiocb);
-                bm->aiocb = NULL;
-            }
-        }
+        ide_dma_cancel(bm);
         bm->cmd = val & 0x09;
     } else {
         if (!(bm->status & BM_STATUS_DMAING)) {
@@ -2739,6 +3054,52 @@ static void bmdma_writeb(void *opaque, uint32_t addr, uint32_t val)
     }
 }
 
+static uint32_t bmdma_addr_readb(void *opaque, uint32_t addr)
+{
+    BMDMAState *bm = opaque;
+    uint32_t val;
+    val = (bm->addr >> ((addr & 3) * 8)) & 0xff;
+#ifdef DEBUG_IDE
+    printf("%s: 0x%08x\n", __func__, val);
+#endif
+    return val;
+}
+
+static void bmdma_addr_writeb(void *opaque, uint32_t addr, uint32_t val)
+{
+    BMDMAState *bm = opaque;
+    int shift = (addr & 3) * 8;
+#ifdef DEBUG_IDE
+    printf("%s: 0x%08x\n", __func__, val);
+#endif
+    bm->addr &= ~(0xFF << shift);
+    bm->addr |= ((val & 0xFF) << shift) & ~3;
+    bm->cur_addr = bm->addr;
+}
+
+static uint32_t bmdma_addr_readw(void *opaque, uint32_t addr)
+{
+    BMDMAState *bm = opaque;
+    uint32_t val;
+    val = (bm->addr >> ((addr & 3) * 8)) & 0xffff;
+#ifdef DEBUG_IDE
+    printf("%s: 0x%08x\n", __func__, val);
+#endif
+    return val;
+}
+
+static void bmdma_addr_writew(void *opaque, uint32_t addr, uint32_t val)
+{
+    BMDMAState *bm = opaque;
+    int shift = (addr & 3) * 8;
+#ifdef DEBUG_IDE
+    printf("%s: 0x%08x\n", __func__, val);
+#endif
+    bm->addr &= ~(0xFFFF << shift);
+    bm->addr |= ((val & 0xFFFF) << shift) & ~3;
+    bm->cur_addr = bm->addr;
+}
+
 static uint32_t bmdma_addr_readl(void *opaque, uint32_t addr)
 {
     BMDMAState *bm = opaque;
@@ -2777,6 +3138,10 @@ static void bmdma_map(PCIDevice *pci_dev, int region_num,
         register_ioport_write(addr + 1, 3, 1, bmdma_writeb, bm);
         register_ioport_read(addr, 4, 1, bmdma_readb, bm);
 
+        register_ioport_write(addr + 4, 4, 1, bmdma_addr_writeb, bm);
+        register_ioport_read(addr + 4, 4, 1, bmdma_addr_readb, bm);
+        register_ioport_write(addr + 4, 4, 2, bmdma_addr_writew, bm);
+        register_ioport_read(addr + 4, 4, 2, bmdma_addr_readw, bm);
         register_ioport_write(addr + 4, 4, 4, bmdma_addr_writel, bm);
         register_ioport_read(addr + 4, 4, 4, bmdma_addr_readl, bm);
         addr += 8;
@@ -2927,9 +3292,14 @@ static int pci_ide_load(QEMUFile* f, void *opaque, int version_id)
     return 0;
 }
 
-static void piix3_reset(PCIIDEState *d)
+static void piix3_reset(void *opaque)
 {
+    PCIIDEState *d = opaque;
     uint8_t *pci_conf = d->dev.config;
+    int i;
+
+    for (i = 0; i < 2; i++)
+        ide_dma_cancel(&d->bmdma[i]);
 
     pci_conf[0x04] = 0x00;
     pci_conf[0x05] = 0x00;
@@ -2963,6 +3333,7 @@ void pci_piix3_ide_init(PCIBus *bus, BlockDriverState **hd_table, int devfn,
     pci_conf[0x0b] = 0x01; // class_base = PCI_mass_storage
     pci_conf[0x0e] = 0x00; // header_type
 
+    qemu_register_reset(piix3_reset, d);
     piix3_reset(d);
 
     pci_register_io_region((PCIDevice *)d, 4, 0x10,
@@ -3001,6 +3372,7 @@ void pci_piix4_ide_init(PCIBus *bus, BlockDriverState **hd_table, int devfn,
     pci_conf[0x0b] = 0x01; // class_base = PCI_mass_storage
     pci_conf[0x0e] = 0x00; // header_type
 
+    qemu_register_reset(piix3_reset, d);
     piix3_reset(d);
 
     pci_register_io_region((PCIDevice *)d, 4, 0x10,
@@ -3450,8 +3822,6 @@ static int md_load(QEMUFile *f, void *opaque, int version_id)
     return 0;
 }
 
-static int md_iid = 0;
-
 static const uint8_t dscm1xxxx_cis[0x14a] = {
     [0x000] = CISTPL_DEVICE,   /* 5V Device Information */
     [0x002] = 0x03,            /* Tuple length = 4 bytes */
@@ -3678,7 +4048,7 @@ struct pcmcia_card_s *dscm1xxxx_init(BlockDriverState *bdrv)
     md->ide->mdata_size = METADATA_SIZE;
     md->ide->mdata_storage = (uint8_t *) qemu_mallocz(METADATA_SIZE);
 
-    register_savevm("microdrive", md_iid ++, 0, md_save, md_load, md);
+    register_savevm("microdrive", -1, 0, md_save, md_load, md);
 
     return &md->card;
 }
This page took 0.06417 seconds and 4 git commands to generate.