From dc23ff50bb890c8c743d7f86ccfb7f300c03db82 Mon Sep 17 00:00:00 2001 From: Ian Jackson Date: Mon, 25 Feb 2008 18:13:54 +0000 Subject: [PATCH] ide.c make write cacheing controllable by guest The attached 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 . --- hw/ide.c | 25 ++++++++++++++++++++++++- 1 file changed, 24 insertions(+), 1 deletion(-) diff --git a/hw/ide.c b/hw/ide.c index 56a1cda92..6668cc9df 100644 --- a/hw/ide.c +++ b/hw/ide.c @@ -377,6 +377,7 @@ typedef struct IDEState { PCIDevice *pci_dev; struct BMDMAState *bmdma; int drive_serial; + int write_cache; /* ide regs */ uint8_t feature; uint8_t error; @@ -553,7 +554,8 @@ 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)); @@ -959,6 +961,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; @@ -1015,6 +1020,13 @@ static void ide_write_dma_cb(void *opaque, int ret) /* end of transfer ? */ if (s->nsector == 0) { + if (!s->write_cache) { + ret = bdrv_flush(s->bs); + if (ret != 0) { + ide_dma_error(s); + return; + } + } s->status = READY_STAT | SEEK_STAT; ide_set_irq(s); eot: @@ -2097,7 +2109,17 @@ static void ide_ioport_write(void *opaque, uint32_t addr, uint32_t val) case 0xcc: /* reverting to power-on defaults enable */ case 0x66: /* reverting to power-on defaults disable */ 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 0xaa: /* read look-ahead enable */ case 0x55: /* read look-ahead disable */ case 0x05: /* set advanced power management mode */ @@ -2623,6 +2645,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); } } -- 2.39.5