qemu-devel
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[Qemu-devel] [PATCH 3/3] make write cacheing controllable by guest


From: Ian Jackson
Subject: [Qemu-devel] [PATCH 3/3] make write cacheing controllable by guest
Date: Tue, 2 Sep 2008 15:51:46 +0100

This patch implements the ATA write cache feature.  This enables a
guest to control, in the standard way, whether disk writes are
immediately committed to disk before the IDE command completes, or may
be buffered in the host.

In this patch, by default buffering is off, which provides better
reliability but may have a performance impact.  It would be
straightforward to change the default, or perhaps offer a command-line
option, if that would be preferred.

This patch is derived from one which was originally submitted to the
Xen tree by Rik van Riel <address@hidden> and includes code to save
the write_cache setting from Samuel Thibault.  Thanks also to Paul
Brook for pointing out a bug, fixed in Xen and in this change.

From: Rik van Riel <address@hidden>
Signed-off-by: Christian Limpach <address@hidden>
Signed-off-by: Samuel Thibault <address@hidden>
Signed-off-by: Ian Jackson <address@hidden>

Cherry picked from the following commits to qemu-xen-unstable:
 a9c94b06d240709c99966722cae655c5aa6771bf ide write_cache ... bdrv_aio_flush
 76a7df8cfdc7a8c2d89a181ab5196490f800f733 advertise write cache enabled ...
 f881e2f3b58647a6a132bd0d944358c89887b7a2 ide write_cache saving ... fixes
 9c2f4d468e1653f8f73a215ca2b375875c68748d Move WIN_SETFEATURES 0x02 and ...
 d1e5cc49395831cb9c23e00c37898cf943c1d4be make write cacheing controllable ...
with no conflicts.
Signed-off-by: Ian Jackson <address@hidden>
---
 hw/ide.c |   83 +++++++++++++++++++++++++++++++++++++++++++------------------
 1 files changed, 58 insertions(+), 25 deletions(-)

diff --git a/hw/ide.c b/hw/ide.c
index a3b9e6e..b5c9a11 100644
--- a/hw/ide.c
+++ b/hw/ide.c
@@ -384,6 +384,7 @@ typedef struct IDEState {
     PCIDevice *pci_dev;
     struct BMDMAState *bmdma;
     int drive_serial;
+    uint8_t write_cache;
     /* ide regs */
     uint8_t feature;
     uint8_t error;
@@ -577,11 +578,12 @@ static void ide_identify(IDEState *s)
     put_le16(p + 68, 120);
     put_le16(p + 80, 0xf0); /* ata3 -> ata6 supported */
     put_le16(p + 81, 0x16); /* conforms to ata5 */
-    put_le16(p + 82, (1 << 14));
+    /* 14=nop 5=write_cache */
+    put_le16(p + 82, (1 << 14) | (1 << 5));
     /* 13=flush_cache_ext,12=flush_cache,10=lba48 */
     put_le16(p + 83, (1 << 14) | (1 << 13) | (1 <<12) | (1 << 10));
     put_le16(p + 84, (1 << 14));
-    put_le16(p + 85, (1 << 14));
+    put_le16(p + 85, (1 << 14) | (s->write_cache << 5));
     /* 13=flush_cache_ext,12=flush_cache,10=lba48 */
     put_le16(p + 86, (1 << 14) | (1 << 13) | (1 <<12) | (1 << 10));
     put_le16(p + 87, (1 << 14));
@@ -916,6 +918,14 @@ static int dma_buf_rw(BMDMAState *bm, int is_write)
     return 1;
 }
 
+static void ide_dma_eot(BMDMAState *bm) {
+    bm->status &= ~BM_STATUS_DMAING;
+    bm->status |= BM_STATUS_INT;
+    bm->dma_cb = NULL;
+    bm->ide_if = NULL;
+    bm->aiocb = NULL;
+}
+
 static void ide_read_dma_cb(void *opaque, int ret)
 {
     BMDMAState *bm = opaque;
@@ -945,11 +955,7 @@ static void ide_read_dma_cb(void *opaque, int ret)
         s->status = READY_STAT | SEEK_STAT;
         ide_set_irq(s);
     eot:
-        bm->status &= ~BM_STATUS_DMAING;
-        bm->status |= BM_STATUS_INT;
-        bm->dma_cb = NULL;
-        bm->ide_if = NULL;
-        bm->aiocb = NULL;
+       ide_dma_eot(bm);
         return;
     }
 
@@ -995,6 +1001,9 @@ static void ide_sector_write(IDEState *s)
     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 && !s->write_cache) {
+       ret = bdrv_flush(s->bs);
+    }
     if (ret != 0) {
        ide_rw_error(s);
        return;
@@ -1029,6 +1038,20 @@ static void ide_sector_write(IDEState *s)
     }
 }
 
+static void ide_write_flush_cb(void *opaque, int ret) {
+    BMDMAState *bm = opaque;
+    IDEState *s = bm->ide_if;
+
+    if (ret != 0) {
+       ide_dma_error(s);
+       return;
+    }
+    s->status = READY_STAT | SEEK_STAT;
+    ide_set_irq(s);
+    ide_dma_eot(bm);
+    return;
+}
+
 static void ide_write_dma_cb(void *opaque, int ret)
 {
     BMDMAState *bm = opaque;
@@ -1053,14 +1076,14 @@ static void ide_write_dma_cb(void *opaque, int ret)
 
     /* end of transfer ? */
     if (s->nsector == 0) {
+       if (!s->write_cache) {
+           bdrv_aio_flush(s->bs, ide_write_flush_cb, bm);
+           return;
+       }
         s->status = READY_STAT | SEEK_STAT;
         ide_set_irq(s);
     eot:
-        bm->status &= ~BM_STATUS_DMAING;
-        bm->status |= BM_STATUS_INT;
-        bm->dma_cb = NULL;
-        bm->ide_if = NULL;
-        bm->aiocb = NULL;
+       ide_dma_eot(bm);
         return;
     }
 
@@ -1382,11 +1405,7 @@ static void ide_atapi_cmd_read_dma_cb(void *opaque, int 
ret)
         s->nsector = (s->nsector & ~7) | ATAPI_INT_REASON_IO | 
ATAPI_INT_REASON_CD;
         ide_set_irq(s);
     eot:
-        bm->status &= ~BM_STATUS_DMAING;
-        bm->status |= BM_STATUS_INT;
-        bm->dma_cb = NULL;
-        bm->ide_if = NULL;
-        bm->aiocb = NULL;
+       ide_dma_eot(bm);
         return;
     }
 
@@ -2266,8 +2285,6 @@ static void ide_ioport_write(void *opaque, uint32_t addr, 
uint32_t val)
             switch(s->feature) {
             case 0xcc: /* reverting to power-on defaults enable */
             case 0x66: /* reverting to power-on defaults disable */
-            case 0x02: /* write cache enable */
-            case 0x82: /* write cache disable */
             case 0xaa: /* read look-ahead enable */
             case 0x55: /* read look-ahead disable */
             case 0x05: /* set advanced power management mode */
@@ -2281,6 +2298,18 @@ static void ide_ioport_write(void *opaque, uint32_t 
addr, uint32_t val)
                 s->status = READY_STAT | SEEK_STAT;
                 ide_set_irq(s);
                 break;
+            case 0x02: /* write cache enable */
+                s->write_cache = 1;
+                s->status = READY_STAT | SEEK_STAT;
+                ide_set_irq(s);
+                break;
+            case 0x82: /* write cache disable */
+                s->write_cache = 0;
+                ret = bdrv_flush(s->bs);
+               if (ret != 0) goto abort_cmd;
+                s->status = READY_STAT | SEEK_STAT;
+                ide_set_irq(s);
+                break;
             case 0x03: { /* set transfer mode */
                uint8_t val = s->nsector & 0x07;
 
@@ -2814,6 +2843,7 @@ static void ide_init2(IDEState *ide_state,
         s->irq = irq;
         s->sector_write_timer = qemu_new_timer(vm_clock,
                                                ide_sector_write_timer_cb, s);
+       s->write_cache = 0;
         ide_reset(s);
     }
 }
@@ -2842,6 +2872,7 @@ static void ide_save(QEMUFile* f, IDEState *s)
     if (s->identify_set) {
         qemu_put_buffer(f, (const uint8_t *)s->identify_data, 512);
     }
+    qemu_put_8s(f, &s->write_cache);
     qemu_put_8s(f, &s->feature);
     qemu_put_8s(f, &s->error);
     qemu_put_be32s(f, &s->nsector);
@@ -2863,13 +2894,15 @@ static void ide_save(QEMUFile* f, IDEState *s)
 }
 
 /* load per IDE drive data */
-static void ide_load(QEMUFile* f, IDEState *s)
+static void ide_load(QEMUFile* f, IDEState *s, int version_id)
 {
     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);
     }
+    if (version_id >= 2)
+       qemu_get_8s(f, &s->write_cache);
     qemu_get_8s(f, &s->feature);
     qemu_get_8s(f, &s->error);
     qemu_get_be32s(f, &s->nsector);
@@ -3269,7 +3302,7 @@ static int pci_ide_load(QEMUFile* f, void *opaque, int 
version_id)
     PCIIDEState *d = opaque;
     int ret, i;
 
-    if (version_id != 1)
+    if (version_id != 1 && version_id != 2)
         return -EINVAL;
     ret = pci_device_load(&d->dev, f);
     if (ret < 0)
@@ -3294,7 +3327,7 @@ static int pci_ide_load(QEMUFile* f, void *opaque, int 
version_id)
 
     /* per IDE drive data */
     for(i = 0; i < 4; i++) {
-        ide_load(f, &d->ide_if[i]);
+        ide_load(f, &d->ide_if[i], version_id);
     }
     return 0;
 }
@@ -3351,7 +3384,7 @@ void pci_piix3_ide_init(PCIBus *bus, BlockDriverState 
**hd_table, int devfn,
     ide_init_ioport(&d->ide_if[0], 0x1f0, 0x3f6);
     ide_init_ioport(&d->ide_if[2], 0x170, 0x376);
 
-    register_savevm("ide", 0, 1, pci_ide_save, pci_ide_load, d);
+    register_savevm("ide", 0, 2, pci_ide_save, pci_ide_load, d);
 }
 
 /* hd_table must contain 4 block drivers */
@@ -3390,7 +3423,7 @@ void pci_piix4_ide_init(PCIBus *bus, BlockDriverState 
**hd_table, int devfn,
     ide_init_ioport(&d->ide_if[0], 0x1f0, 0x3f6);
     ide_init_ioport(&d->ide_if[2], 0x170, 0x376);
 
-    register_savevm("ide", 0, 1, pci_ide_save, pci_ide_load, d);
+    register_savevm("ide", 0, 2, pci_ide_save, pci_ide_load, d);
 }
 
 /***********************************************************/
@@ -3824,7 +3857,7 @@ static int md_load(QEMUFile *f, void *opaque, int 
version_id)
     s->ide->cur_drive = &s->ide[(drive1_selected != 0)];
 
     for (i = 0; i < 2; i ++)
-        ide_load(f, &s->ide[i]);
+        ide_load(f, &s->ide[i], version_id);
 
     return 0;
 }
-- 
1.4.4.4





reply via email to

[Prev in Thread] Current Thread [Next in Thread]