159f2a787SGerd Hoffmann /*
259f2a787SGerd Hoffmann * QEMU IDE disk and CD/DVD-ROM Emulator
359f2a787SGerd Hoffmann *
459f2a787SGerd Hoffmann * Copyright (c) 2003 Fabrice Bellard
559f2a787SGerd Hoffmann * Copyright (c) 2006 Openedhand Ltd.
659f2a787SGerd Hoffmann *
759f2a787SGerd Hoffmann * Permission is hereby granted, free of charge, to any person obtaining a copy
859f2a787SGerd Hoffmann * of this software and associated documentation files (the "Software"), to deal
959f2a787SGerd Hoffmann * in the Software without restriction, including without limitation the rights
1059f2a787SGerd Hoffmann * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
1159f2a787SGerd Hoffmann * copies of the Software, and to permit persons to whom the Software is
1259f2a787SGerd Hoffmann * furnished to do so, subject to the following conditions:
1359f2a787SGerd Hoffmann *
1459f2a787SGerd Hoffmann * The above copyright notice and this permission notice shall be included in
1559f2a787SGerd Hoffmann * all copies or substantial portions of the Software.
1659f2a787SGerd Hoffmann *
1759f2a787SGerd Hoffmann * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
1859f2a787SGerd Hoffmann * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
1959f2a787SGerd Hoffmann * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
2059f2a787SGerd Hoffmann * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
2159f2a787SGerd Hoffmann * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
2259f2a787SGerd Hoffmann * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
2359f2a787SGerd Hoffmann * THE SOFTWARE.
2459f2a787SGerd Hoffmann */
25e688df6bSMarkus Armbruster
2653239262SPeter Maydell #include "qemu/osdep.h"
27da9f1172SPhilippe Mathieu-Daudé #include "hw/irq.h"
28a9c94277SMarkus Armbruster #include "hw/isa/isa.h"
29d6454270SMarkus Armbruster #include "migration/vmstate.h"
301de7afc9SPaolo Bonzini #include "qemu/error-report.h"
31db725815SMarkus Armbruster #include "qemu/main-loop.h"
321de7afc9SPaolo Bonzini #include "qemu/timer.h"
3315e09912SPeter Maydell #include "qemu/hw-version.h"
345df022cfSPeter Maydell #include "qemu/memalign.h"
359c17d615SPaolo Bonzini #include "sysemu/sysemu.h"
3678631611SPhilippe Mathieu-Daudé #include "sysemu/blockdev.h"
379c17d615SPaolo Bonzini #include "sysemu/dma.h"
380d09e41aSPaolo Bonzini #include "hw/block/block.h"
394be74634SMarkus Armbruster #include "sysemu/block-backend.h"
40e688df6bSMarkus Armbruster #include "qapi/error.h"
41f348b6d1SVeronia Bahaa #include "qemu/cutils.h"
42b255df7eSPavel Dovgalyuk #include "sysemu/replay.h"
4354d31236SMarkus Armbruster #include "sysemu/runstate.h"
440316482eSPhilippe Mathieu-Daudé #include "ide-internal.h"
453eee2611SJohn Snow #include "trace.h"
4659f2a787SGerd Hoffmann
47b93af93dSBrian Wheeler /* These values were based on a Seagate ST3500418AS but have been modified
48b93af93dSBrian Wheeler to make more sense in QEMU */
49b93af93dSBrian Wheeler static const int smart_attributes[][12] = {
50b93af93dSBrian Wheeler /* id, flags, hflags, val, wrst, raw (6 bytes), threshold */
51b93af93dSBrian Wheeler /* raw read error rate*/
52b93af93dSBrian Wheeler { 0x01, 0x03, 0x00, 0x64, 0x64, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06},
53b93af93dSBrian Wheeler /* spin up */
54b93af93dSBrian Wheeler { 0x03, 0x03, 0x00, 0x64, 0x64, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
55b93af93dSBrian Wheeler /* start stop count */
56b93af93dSBrian Wheeler { 0x04, 0x02, 0x00, 0x64, 0x64, 0x64, 0x00, 0x00, 0x00, 0x00, 0x00, 0x14},
57b93af93dSBrian Wheeler /* remapped sectors */
58b93af93dSBrian Wheeler { 0x05, 0x03, 0x00, 0x64, 0x64, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x24},
59b93af93dSBrian Wheeler /* power on hours */
60b93af93dSBrian Wheeler { 0x09, 0x03, 0x00, 0x64, 0x64, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
61b93af93dSBrian Wheeler /* power cycle count */
62b93af93dSBrian Wheeler { 0x0c, 0x03, 0x00, 0x64, 0x64, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
63b93af93dSBrian Wheeler /* airflow-temperature-celsius */
64b93af93dSBrian Wheeler { 190, 0x03, 0x00, 0x45, 0x45, 0x1f, 0x00, 0x1f, 0x1f, 0x00, 0x00, 0x32},
6559f2a787SGerd Hoffmann };
6659f2a787SGerd Hoffmann
670e168d35SJohn Snow const char *IDE_DMA_CMD_lookup[IDE_DMA__COUNT] = {
680e168d35SJohn Snow [IDE_DMA_READ] = "DMA READ",
690e168d35SJohn Snow [IDE_DMA_WRITE] = "DMA WRITE",
700e168d35SJohn Snow [IDE_DMA_TRIM] = "DMA TRIM",
710e168d35SJohn Snow [IDE_DMA_ATAPI] = "DMA ATAPI"
720e168d35SJohn Snow };
730e168d35SJohn Snow
IDE_DMA_CMD_str(enum ide_dma_cmd enval)740e168d35SJohn Snow static const char *IDE_DMA_CMD_str(enum ide_dma_cmd enval)
750e168d35SJohn Snow {
76159a9df0SJohn Snow if ((unsigned)enval < IDE_DMA__COUNT) {
770e168d35SJohn Snow return IDE_DMA_CMD_lookup[enval];
780e168d35SJohn Snow }
790e168d35SJohn Snow return "DMA UNKNOWN CMD";
800e168d35SJohn Snow }
810e168d35SJohn Snow
8240c4ed3fSKevin Wolf static void ide_dummy_transfer_stop(IDEState *s);
8359f2a787SGerd Hoffmann
8475524884SMark Cave-Ayland const MemoryRegionPortio ide_portio_list[] = {
8575524884SMark Cave-Ayland { 0, 8, 1, .read = ide_ioport_read, .write = ide_ioport_write },
8675524884SMark Cave-Ayland { 0, 1, 2, .read = ide_data_readw, .write = ide_data_writew },
8775524884SMark Cave-Ayland { 0, 1, 4, .read = ide_data_readl, .write = ide_data_writel },
8875524884SMark Cave-Ayland PORTIO_END_OF_LIST(),
8975524884SMark Cave-Ayland };
9075524884SMark Cave-Ayland
9175524884SMark Cave-Ayland const MemoryRegionPortio ide_portio2_list[] = {
9275524884SMark Cave-Ayland { 0, 1, 1, .read = ide_status_read, .write = ide_ctrl_write },
9375524884SMark Cave-Ayland PORTIO_END_OF_LIST(),
9475524884SMark Cave-Ayland };
9575524884SMark Cave-Ayland
padstr(char * str,const char * src,int len)9659f2a787SGerd Hoffmann static void padstr(char *str, const char *src, int len)
9759f2a787SGerd Hoffmann {
9859f2a787SGerd Hoffmann int i, v;
9959f2a787SGerd Hoffmann for(i = 0; i < len; i++) {
10059f2a787SGerd Hoffmann if (*src)
10159f2a787SGerd Hoffmann v = *src++;
10259f2a787SGerd Hoffmann else
10359f2a787SGerd Hoffmann v = ' ';
10459f2a787SGerd Hoffmann str[i^1] = v;
10559f2a787SGerd Hoffmann }
10659f2a787SGerd Hoffmann }
10759f2a787SGerd Hoffmann
put_le16(uint16_t * p,unsigned int v)10859f2a787SGerd Hoffmann static void put_le16(uint16_t *p, unsigned int v)
10959f2a787SGerd Hoffmann {
11059f2a787SGerd Hoffmann *p = cpu_to_le16(v);
11159f2a787SGerd Hoffmann }
11259f2a787SGerd Hoffmann
ide_identify_size(IDEState * s)11301ce352eSJohn Snow static void ide_identify_size(IDEState *s)
11401ce352eSJohn Snow {
11501ce352eSJohn Snow uint16_t *p = (uint16_t *)s->identify_data;
11646e018e9SSamuel Thibault int64_t nb_sectors_lba28 = s->nb_sectors;
11746e018e9SSamuel Thibault if (nb_sectors_lba28 >= 1 << 28) {
11846e018e9SSamuel Thibault nb_sectors_lba28 = (1 << 28) - 1;
11946e018e9SSamuel Thibault }
12046e018e9SSamuel Thibault put_le16(p + 60, nb_sectors_lba28);
12146e018e9SSamuel Thibault put_le16(p + 61, nb_sectors_lba28 >> 16);
12201ce352eSJohn Snow put_le16(p + 100, s->nb_sectors);
12301ce352eSJohn Snow put_le16(p + 101, s->nb_sectors >> 16);
12401ce352eSJohn Snow put_le16(p + 102, s->nb_sectors >> 32);
12501ce352eSJohn Snow put_le16(p + 103, s->nb_sectors >> 48);
12601ce352eSJohn Snow }
12701ce352eSJohn Snow
ide_identify(IDEState * s)12859f2a787SGerd Hoffmann static void ide_identify(IDEState *s)
12959f2a787SGerd Hoffmann {
13059f2a787SGerd Hoffmann uint16_t *p;
13159f2a787SGerd Hoffmann unsigned int oldsize;
132d353fb72SChristoph Hellwig IDEDevice *dev = s->unit ? s->bus->slave : s->bus->master;
13359f2a787SGerd Hoffmann
1344bf6637dSJohn Snow p = (uint16_t *)s->identify_data;
13559f2a787SGerd Hoffmann if (s->identify_set) {
1364bf6637dSJohn Snow goto fill_buffer;
13759f2a787SGerd Hoffmann }
1384bf6637dSJohn Snow memset(p, 0, sizeof(s->identify_data));
13959f2a787SGerd Hoffmann
14059f2a787SGerd Hoffmann put_le16(p + 0, 0x0040);
14159f2a787SGerd Hoffmann put_le16(p + 1, s->cylinders);
14259f2a787SGerd Hoffmann put_le16(p + 3, s->heads);
14359f2a787SGerd Hoffmann put_le16(p + 4, 512 * s->sectors); /* XXX: retired, remove ? */
14459f2a787SGerd Hoffmann put_le16(p + 5, 512); /* XXX: retired, remove ? */
14559f2a787SGerd Hoffmann put_le16(p + 6, s->sectors);
14659f2a787SGerd Hoffmann padstr((char *)(p + 10), s->drive_serial_str, 20); /* serial number */
14759f2a787SGerd Hoffmann put_le16(p + 20, 3); /* XXX: retired, remove ? */
14859f2a787SGerd Hoffmann put_le16(p + 21, 512); /* cache size in sectors */
14959f2a787SGerd Hoffmann put_le16(p + 22, 4); /* ecc bytes */
15047c06340SGerd Hoffmann padstr((char *)(p + 23), s->version, 8); /* firmware version */
15127e0c9a1SFloris Bos padstr((char *)(p + 27), s->drive_model_str, 40); /* model */
15259f2a787SGerd Hoffmann #if MAX_MULT_SECTORS > 1
15359f2a787SGerd Hoffmann put_le16(p + 47, 0x8000 | MAX_MULT_SECTORS);
15459f2a787SGerd Hoffmann #endif
15559f2a787SGerd Hoffmann put_le16(p + 48, 1); /* dword I/O */
15659f2a787SGerd Hoffmann put_le16(p + 49, (1 << 11) | (1 << 9) | (1 << 8)); /* DMA and LBA supported */
15759f2a787SGerd Hoffmann put_le16(p + 51, 0x200); /* PIO transfer cycle */
15859f2a787SGerd Hoffmann put_le16(p + 52, 0x200); /* DMA transfer cycle */
15959f2a787SGerd Hoffmann put_le16(p + 53, 1 | (1 << 1) | (1 << 2)); /* words 54-58,64-70,88 are valid */
16059f2a787SGerd Hoffmann put_le16(p + 54, s->cylinders);
16159f2a787SGerd Hoffmann put_le16(p + 55, s->heads);
16259f2a787SGerd Hoffmann put_le16(p + 56, s->sectors);
16359f2a787SGerd Hoffmann oldsize = s->cylinders * s->heads * s->sectors;
16459f2a787SGerd Hoffmann put_le16(p + 57, oldsize);
16559f2a787SGerd Hoffmann put_le16(p + 58, oldsize >> 16);
16659f2a787SGerd Hoffmann if (s->mult_sectors)
16759f2a787SGerd Hoffmann put_le16(p + 59, 0x100 | s->mult_sectors);
16801ce352eSJohn Snow /* *(p + 60) := nb_sectors -- see ide_identify_size */
16901ce352eSJohn Snow /* *(p + 61) := nb_sectors >> 16 -- see ide_identify_size */
17059f2a787SGerd Hoffmann put_le16(p + 62, 0x07); /* single word dma0-2 supported */
17159f2a787SGerd Hoffmann put_le16(p + 63, 0x07); /* mdma0-2 supported */
17279d1d331SJonathan A. Kollasch put_le16(p + 64, 0x03); /* pio3-4 supported */
17359f2a787SGerd Hoffmann put_le16(p + 65, 120);
17459f2a787SGerd Hoffmann put_le16(p + 66, 120);
17559f2a787SGerd Hoffmann put_le16(p + 67, 120);
17659f2a787SGerd Hoffmann put_le16(p + 68, 120);
177d353fb72SChristoph Hellwig if (dev && dev->conf.discard_granularity) {
178d353fb72SChristoph Hellwig put_le16(p + 69, (1 << 14)); /* determinate TRIM behavior */
179d353fb72SChristoph Hellwig }
180ccf0fd8bSRoland Elek
181ccf0fd8bSRoland Elek if (s->ncq_queues) {
182ccf0fd8bSRoland Elek put_le16(p + 75, s->ncq_queues - 1);
183ccf0fd8bSRoland Elek /* NCQ supported */
184ccf0fd8bSRoland Elek put_le16(p + 76, (1 << 8));
185ccf0fd8bSRoland Elek }
186ccf0fd8bSRoland Elek
18759f2a787SGerd Hoffmann put_le16(p + 80, 0xf0); /* ata3 -> ata6 supported */
18859f2a787SGerd Hoffmann put_le16(p + 81, 0x16); /* conforms to ata5 */
189a58b8d54SChristoph Hellwig /* 14=NOP supported, 5=WCACHE supported, 0=SMART supported */
190a58b8d54SChristoph Hellwig put_le16(p + 82, (1 << 14) | (1 << 5) | 1);
19159f2a787SGerd Hoffmann /* 13=flush_cache_ext,12=flush_cache,10=lba48 */
19259f2a787SGerd Hoffmann put_le16(p + 83, (1 << 14) | (1 << 13) | (1 <<12) | (1 << 10));
19395ebda85SFloris Bos /* 14=set to 1, 8=has WWN, 1=SMART self test, 0=SMART error logging */
19495ebda85SFloris Bos if (s->wwn) {
19595ebda85SFloris Bos put_le16(p + 84, (1 << 14) | (1 << 8) | 0);
19695ebda85SFloris Bos } else {
19759f2a787SGerd Hoffmann put_le16(p + 84, (1 << 14) | 0);
19895ebda85SFloris Bos }
199e900a7b7SChristoph Hellwig /* 14 = NOP supported, 5=WCACHE enabled, 0=SMART feature set enabled */
2004be74634SMarkus Armbruster if (blk_enable_write_cache(s->blk)) {
201e900a7b7SChristoph Hellwig put_le16(p + 85, (1 << 14) | (1 << 5) | 1);
2024be74634SMarkus Armbruster } else {
20359f2a787SGerd Hoffmann put_le16(p + 85, (1 << 14) | 1);
2044be74634SMarkus Armbruster }
20559f2a787SGerd Hoffmann /* 13=flush_cache_ext,12=flush_cache,10=lba48 */
2062844bdd9SKevin Wolf put_le16(p + 86, (1 << 13) | (1 <<12) | (1 << 10));
20795ebda85SFloris Bos /* 14=set to 1, 8=has WWN, 1=SMART self test, 0=SMART error logging */
20895ebda85SFloris Bos if (s->wwn) {
20995ebda85SFloris Bos put_le16(p + 87, (1 << 14) | (1 << 8) | 0);
21095ebda85SFloris Bos } else {
21159f2a787SGerd Hoffmann put_le16(p + 87, (1 << 14) | 0);
21295ebda85SFloris Bos }
21359f2a787SGerd Hoffmann put_le16(p + 88, 0x3f | (1 << 13)); /* udma5 set and supported */
21459f2a787SGerd Hoffmann put_le16(p + 93, 1 | (1 << 14) | 0x2000);
21501ce352eSJohn Snow /* *(p + 100) := nb_sectors -- see ide_identify_size */
21601ce352eSJohn Snow /* *(p + 101) := nb_sectors >> 16 -- see ide_identify_size */
21701ce352eSJohn Snow /* *(p + 102) := nb_sectors >> 32 -- see ide_identify_size */
21801ce352eSJohn Snow /* *(p + 103) := nb_sectors >> 48 -- see ide_identify_size */
219d353fb72SChristoph Hellwig
22057dac7efSMarkus Armbruster if (dev && dev->conf.physical_block_size)
22157dac7efSMarkus Armbruster put_le16(p + 106, 0x6000 | get_physical_block_exp(&dev->conf));
22295ebda85SFloris Bos if (s->wwn) {
22395ebda85SFloris Bos /* LE 16-bit words 111-108 contain 64-bit World Wide Name */
22495ebda85SFloris Bos put_le16(p + 108, s->wwn >> 48);
22595ebda85SFloris Bos put_le16(p + 109, s->wwn >> 32);
22695ebda85SFloris Bos put_le16(p + 110, s->wwn >> 16);
22795ebda85SFloris Bos put_le16(p + 111, s->wwn);
22895ebda85SFloris Bos }
229d353fb72SChristoph Hellwig if (dev && dev->conf.discard_granularity) {
230d353fb72SChristoph Hellwig put_le16(p + 169, 1); /* TRIM support */
231d353fb72SChristoph Hellwig }
23296f43c2bSDaniel P. Berrange if (dev) {
2333b19f450SDaniel P. Berrange put_le16(p + 217, dev->rotation_rate); /* Nominal media rotation rate */
23496f43c2bSDaniel P. Berrange }
23559f2a787SGerd Hoffmann
23601ce352eSJohn Snow ide_identify_size(s);
23759f2a787SGerd Hoffmann s->identify_set = 1;
2384bf6637dSJohn Snow
2394bf6637dSJohn Snow fill_buffer:
2404bf6637dSJohn Snow memcpy(s->io_buffer, p, sizeof(s->identify_data));
24159f2a787SGerd Hoffmann }
24259f2a787SGerd Hoffmann
ide_atapi_identify(IDEState * s)24359f2a787SGerd Hoffmann static void ide_atapi_identify(IDEState *s)
24459f2a787SGerd Hoffmann {
24559f2a787SGerd Hoffmann uint16_t *p;
24659f2a787SGerd Hoffmann
2474bf6637dSJohn Snow p = (uint16_t *)s->identify_data;
24859f2a787SGerd Hoffmann if (s->identify_set) {
2494bf6637dSJohn Snow goto fill_buffer;
25059f2a787SGerd Hoffmann }
2514bf6637dSJohn Snow memset(p, 0, sizeof(s->identify_data));
25259f2a787SGerd Hoffmann
25359f2a787SGerd Hoffmann /* Removable CDROM, 50us response, 12 byte packets */
25459f2a787SGerd Hoffmann put_le16(p + 0, (2 << 14) | (5 << 8) | (1 << 7) | (2 << 5) | (0 << 0));
25559f2a787SGerd Hoffmann padstr((char *)(p + 10), s->drive_serial_str, 20); /* serial number */
25659f2a787SGerd Hoffmann put_le16(p + 20, 3); /* buffer type */
25759f2a787SGerd Hoffmann put_le16(p + 21, 512); /* cache size in sectors */
25859f2a787SGerd Hoffmann put_le16(p + 22, 4); /* ecc bytes */
25947c06340SGerd Hoffmann padstr((char *)(p + 23), s->version, 8); /* firmware version */
26027e0c9a1SFloris Bos padstr((char *)(p + 27), s->drive_model_str, 40); /* model */
26159f2a787SGerd Hoffmann put_le16(p + 48, 1); /* dword I/O (XXX: should not be set on CDROM) */
26259f2a787SGerd Hoffmann #ifdef USE_DMA_CDROM
26359f2a787SGerd Hoffmann put_le16(p + 49, 1 << 9 | 1 << 8); /* DMA and LBA supported */
26459f2a787SGerd Hoffmann put_le16(p + 53, 7); /* words 64-70, 54-58, 88 valid */
26559f2a787SGerd Hoffmann put_le16(p + 62, 7); /* single word dma0-2 supported */
26659f2a787SGerd Hoffmann put_le16(p + 63, 7); /* mdma0-2 supported */
26759f2a787SGerd Hoffmann #else
26859f2a787SGerd Hoffmann put_le16(p + 49, 1 << 9); /* LBA supported, no DMA */
26959f2a787SGerd Hoffmann put_le16(p + 53, 3); /* words 64-70, 54-58 valid */
27059f2a787SGerd Hoffmann put_le16(p + 63, 0x103); /* DMA modes XXX: may be incorrect */
27159f2a787SGerd Hoffmann #endif
27279d1d331SJonathan A. Kollasch put_le16(p + 64, 3); /* pio3-4 supported */
27359f2a787SGerd Hoffmann put_le16(p + 65, 0xb4); /* minimum DMA multiword tx cycle time */
27459f2a787SGerd Hoffmann put_le16(p + 66, 0xb4); /* recommended DMA multiword tx cycle time */
27559f2a787SGerd Hoffmann put_le16(p + 67, 0x12c); /* minimum PIO cycle time without flow control */
27659f2a787SGerd Hoffmann put_le16(p + 68, 0xb4); /* minimum PIO cycle time with IORDY flow control */
27759f2a787SGerd Hoffmann
27859f2a787SGerd Hoffmann put_le16(p + 71, 30); /* in ns */
27959f2a787SGerd Hoffmann put_le16(p + 72, 30); /* in ns */
28059f2a787SGerd Hoffmann
2811bdaa28dSAlexander Graf if (s->ncq_queues) {
2821bdaa28dSAlexander Graf put_le16(p + 75, s->ncq_queues - 1);
2831bdaa28dSAlexander Graf /* NCQ supported */
2841bdaa28dSAlexander Graf put_le16(p + 76, (1 << 8));
2851bdaa28dSAlexander Graf }
2861bdaa28dSAlexander Graf
28759f2a787SGerd Hoffmann put_le16(p + 80, 0x1e); /* support up to ATA/ATAPI-4 */
288c5fe97e3SJohn Snow if (s->wwn) {
289c5fe97e3SJohn Snow put_le16(p + 84, (1 << 8)); /* supports WWN for words 108-111 */
290c5fe97e3SJohn Snow put_le16(p + 87, (1 << 8)); /* WWN enabled */
291c5fe97e3SJohn Snow }
292c5fe97e3SJohn Snow
29359f2a787SGerd Hoffmann #ifdef USE_DMA_CDROM
29459f2a787SGerd Hoffmann put_le16(p + 88, 0x3f | (1 << 13)); /* udma5 set and supported */
29559f2a787SGerd Hoffmann #endif
296c5fe97e3SJohn Snow
297c5fe97e3SJohn Snow if (s->wwn) {
298c5fe97e3SJohn Snow /* LE 16-bit words 111-108 contain 64-bit World Wide Name */
299c5fe97e3SJohn Snow put_le16(p + 108, s->wwn >> 48);
300c5fe97e3SJohn Snow put_le16(p + 109, s->wwn >> 32);
301c5fe97e3SJohn Snow put_le16(p + 110, s->wwn >> 16);
302c5fe97e3SJohn Snow put_le16(p + 111, s->wwn);
303c5fe97e3SJohn Snow }
304c5fe97e3SJohn Snow
30559f2a787SGerd Hoffmann s->identify_set = 1;
3064bf6637dSJohn Snow
3074bf6637dSJohn Snow fill_buffer:
3084bf6637dSJohn Snow memcpy(s->io_buffer, p, sizeof(s->identify_data));
30959f2a787SGerd Hoffmann }
31059f2a787SGerd Hoffmann
ide_cfata_identify_size(IDEState * s)31101ce352eSJohn Snow static void ide_cfata_identify_size(IDEState *s)
31201ce352eSJohn Snow {
31301ce352eSJohn Snow uint16_t *p = (uint16_t *)s->identify_data;
31401ce352eSJohn Snow put_le16(p + 7, s->nb_sectors >> 16); /* Sectors per card */
31501ce352eSJohn Snow put_le16(p + 8, s->nb_sectors); /* Sectors per card */
31601ce352eSJohn Snow put_le16(p + 60, s->nb_sectors); /* Total LBA sectors */
31701ce352eSJohn Snow put_le16(p + 61, s->nb_sectors >> 16); /* Total LBA sectors */
31801ce352eSJohn Snow }
31901ce352eSJohn Snow
ide_cfata_identify(IDEState * s)32059f2a787SGerd Hoffmann static void ide_cfata_identify(IDEState *s)
32159f2a787SGerd Hoffmann {
32259f2a787SGerd Hoffmann uint16_t *p;
32359f2a787SGerd Hoffmann uint32_t cur_sec;
32459f2a787SGerd Hoffmann
32559f2a787SGerd Hoffmann p = (uint16_t *)s->identify_data;
3264bf6637dSJohn Snow if (s->identify_set) {
32759f2a787SGerd Hoffmann goto fill_buffer;
3284bf6637dSJohn Snow }
32959f2a787SGerd Hoffmann memset(p, 0, sizeof(s->identify_data));
33059f2a787SGerd Hoffmann
33159f2a787SGerd Hoffmann cur_sec = s->cylinders * s->heads * s->sectors;
33259f2a787SGerd Hoffmann
33359f2a787SGerd Hoffmann put_le16(p + 0, 0x848a); /* CF Storage Card signature */
33459f2a787SGerd Hoffmann put_le16(p + 1, s->cylinders); /* Default cylinders */
33559f2a787SGerd Hoffmann put_le16(p + 3, s->heads); /* Default heads */
33659f2a787SGerd Hoffmann put_le16(p + 6, s->sectors); /* Default sectors per track */
33701ce352eSJohn Snow /* *(p + 7) := nb_sectors >> 16 -- see ide_cfata_identify_size */
33801ce352eSJohn Snow /* *(p + 8) := nb_sectors -- see ide_cfata_identify_size */
33959f2a787SGerd Hoffmann padstr((char *)(p + 10), s->drive_serial_str, 20); /* serial number */
34059f2a787SGerd Hoffmann put_le16(p + 22, 0x0004); /* ECC bytes */
34147c06340SGerd Hoffmann padstr((char *) (p + 23), s->version, 8); /* Firmware Revision */
34227e0c9a1SFloris Bos padstr((char *) (p + 27), s->drive_model_str, 40);/* Model number */
34359f2a787SGerd Hoffmann #if MAX_MULT_SECTORS > 1
34459f2a787SGerd Hoffmann put_le16(p + 47, 0x8000 | MAX_MULT_SECTORS);
34559f2a787SGerd Hoffmann #else
34659f2a787SGerd Hoffmann put_le16(p + 47, 0x0000);
34759f2a787SGerd Hoffmann #endif
34859f2a787SGerd Hoffmann put_le16(p + 49, 0x0f00); /* Capabilities */
34959f2a787SGerd Hoffmann put_le16(p + 51, 0x0002); /* PIO cycle timing mode */
35059f2a787SGerd Hoffmann put_le16(p + 52, 0x0001); /* DMA cycle timing mode */
35159f2a787SGerd Hoffmann put_le16(p + 53, 0x0003); /* Translation params valid */
35259f2a787SGerd Hoffmann put_le16(p + 54, s->cylinders); /* Current cylinders */
35359f2a787SGerd Hoffmann put_le16(p + 55, s->heads); /* Current heads */
35459f2a787SGerd Hoffmann put_le16(p + 56, s->sectors); /* Current sectors */
35559f2a787SGerd Hoffmann put_le16(p + 57, cur_sec); /* Current capacity */
35659f2a787SGerd Hoffmann put_le16(p + 58, cur_sec >> 16); /* Current capacity */
35759f2a787SGerd Hoffmann if (s->mult_sectors) /* Multiple sector setting */
35859f2a787SGerd Hoffmann put_le16(p + 59, 0x100 | s->mult_sectors);
35901ce352eSJohn Snow /* *(p + 60) := nb_sectors -- see ide_cfata_identify_size */
36001ce352eSJohn Snow /* *(p + 61) := nb_sectors >> 16 -- see ide_cfata_identify_size */
36159f2a787SGerd Hoffmann put_le16(p + 63, 0x0203); /* Multiword DMA capability */
36259f2a787SGerd Hoffmann put_le16(p + 64, 0x0001); /* Flow Control PIO support */
36359f2a787SGerd Hoffmann put_le16(p + 65, 0x0096); /* Min. Multiword DMA cycle */
36459f2a787SGerd Hoffmann put_le16(p + 66, 0x0096); /* Rec. Multiword DMA cycle */
36559f2a787SGerd Hoffmann put_le16(p + 68, 0x00b4); /* Min. PIO cycle time */
36659f2a787SGerd Hoffmann put_le16(p + 82, 0x400c); /* Command Set supported */
36759f2a787SGerd Hoffmann put_le16(p + 83, 0x7068); /* Command Set supported */
36859f2a787SGerd Hoffmann put_le16(p + 84, 0x4000); /* Features supported */
36959f2a787SGerd Hoffmann put_le16(p + 85, 0x000c); /* Command Set enabled */
37059f2a787SGerd Hoffmann put_le16(p + 86, 0x7044); /* Command Set enabled */
37159f2a787SGerd Hoffmann put_le16(p + 87, 0x4000); /* Features enabled */
37259f2a787SGerd Hoffmann put_le16(p + 91, 0x4060); /* Current APM level */
37359f2a787SGerd Hoffmann put_le16(p + 129, 0x0002); /* Current features option */
37459f2a787SGerd Hoffmann put_le16(p + 130, 0x0005); /* Reassigned sectors */
37559f2a787SGerd Hoffmann put_le16(p + 131, 0x0001); /* Initial power mode */
37659f2a787SGerd Hoffmann put_le16(p + 132, 0x0000); /* User signature */
37759f2a787SGerd Hoffmann put_le16(p + 160, 0x8100); /* Power requirement */
37859f2a787SGerd Hoffmann put_le16(p + 161, 0x8001); /* CF command set */
37959f2a787SGerd Hoffmann
38001ce352eSJohn Snow ide_cfata_identify_size(s);
38159f2a787SGerd Hoffmann s->identify_set = 1;
38259f2a787SGerd Hoffmann
38359f2a787SGerd Hoffmann fill_buffer:
38459f2a787SGerd Hoffmann memcpy(s->io_buffer, p, sizeof(s->identify_data));
38559f2a787SGerd Hoffmann }
38659f2a787SGerd Hoffmann
ide_set_signature(IDEState * s)38759f2a787SGerd Hoffmann static void ide_set_signature(IDEState *s)
38859f2a787SGerd Hoffmann {
3890c7515e1SJohn Snow s->select &= ~(ATA_DEV_HS); /* clear head */
39059f2a787SGerd Hoffmann /* put signature */
39159f2a787SGerd Hoffmann s->nsector = 1;
39259f2a787SGerd Hoffmann s->sector = 1;
393cd8722bbSMarkus Armbruster if (s->drive_kind == IDE_CD) {
39459f2a787SGerd Hoffmann s->lcyl = 0x14;
39559f2a787SGerd Hoffmann s->hcyl = 0xeb;
3964be74634SMarkus Armbruster } else if (s->blk) {
39759f2a787SGerd Hoffmann s->lcyl = 0;
39859f2a787SGerd Hoffmann s->hcyl = 0;
39959f2a787SGerd Hoffmann } else {
40059f2a787SGerd Hoffmann s->lcyl = 0xff;
40159f2a787SGerd Hoffmann s->hcyl = 0xff;
40259f2a787SGerd Hoffmann }
40359f2a787SGerd Hoffmann }
40459f2a787SGerd Hoffmann
ide_sect_range_ok(IDEState * s,uint64_t sector,uint64_t nb_sectors)405d8b070feSAnton Nefedov static bool ide_sect_range_ok(IDEState *s,
406d8b070feSAnton Nefedov uint64_t sector, uint64_t nb_sectors)
407d8b070feSAnton Nefedov {
408d8b070feSAnton Nefedov uint64_t total_sectors;
409d8b070feSAnton Nefedov
410d8b070feSAnton Nefedov blk_get_geometry(s->blk, &total_sectors);
411d8b070feSAnton Nefedov if (sector > total_sectors || nb_sectors > total_sectors - sector) {
412d8b070feSAnton Nefedov return false;
413d8b070feSAnton Nefedov }
414d8b070feSAnton Nefedov return true;
415d8b070feSAnton Nefedov }
416d8b070feSAnton Nefedov
417d353fb72SChristoph Hellwig typedef struct TrimAIOCB {
4187c84b1b8SMarkus Armbruster BlockAIOCB common;
419ef0e64a9SAnton Nefedov IDEState *s;
420d353fb72SChristoph Hellwig QEMUBH *bh;
421d353fb72SChristoph Hellwig int ret;
422501378c3SPaolo Bonzini QEMUIOVector *qiov;
4237c84b1b8SMarkus Armbruster BlockAIOCB *aiocb;
424501378c3SPaolo Bonzini int i, j;
425d353fb72SChristoph Hellwig } TrimAIOCB;
426d353fb72SChristoph Hellwig
trim_aio_cancel(BlockAIOCB * acb)4277c84b1b8SMarkus Armbruster static void trim_aio_cancel(BlockAIOCB *acb)
428d353fb72SChristoph Hellwig {
429d353fb72SChristoph Hellwig TrimAIOCB *iocb = container_of(acb, TrimAIOCB, common);
430d353fb72SChristoph Hellwig
431e551c999SFam Zheng /* Exit the loop so ide_issue_trim_cb will not continue */
432501378c3SPaolo Bonzini iocb->j = iocb->qiov->niov - 1;
433501378c3SPaolo Bonzini iocb->i = (iocb->qiov->iov[iocb->j].iov_len / 8) - 1;
434501378c3SPaolo Bonzini
435e551c999SFam Zheng iocb->ret = -ECANCELED;
436501378c3SPaolo Bonzini
437501378c3SPaolo Bonzini if (iocb->aiocb) {
4384be74634SMarkus Armbruster blk_aio_cancel_async(iocb->aiocb);
439e551c999SFam Zheng iocb->aiocb = NULL;
440501378c3SPaolo Bonzini }
441d353fb72SChristoph Hellwig }
442d353fb72SChristoph Hellwig
443d7331bedSStefan Hajnoczi static const AIOCBInfo trim_aiocb_info = {
444d353fb72SChristoph Hellwig .aiocb_size = sizeof(TrimAIOCB),
445e551c999SFam Zheng .cancel_async = trim_aio_cancel,
446d353fb72SChristoph Hellwig };
447d353fb72SChristoph Hellwig
ide_trim_bh_cb(void * opaque)448d353fb72SChristoph Hellwig static void ide_trim_bh_cb(void *opaque)
449d353fb72SChristoph Hellwig {
450d353fb72SChristoph Hellwig TrimAIOCB *iocb = opaque;
4517e5cdb34SHanna Reitz BlockBackend *blk = iocb->s->blk;
452d353fb72SChristoph Hellwig
453d353fb72SChristoph Hellwig iocb->common.cb(iocb->common.opaque, iocb->ret);
454caeadbc8SAnton Nefedov
455d353fb72SChristoph Hellwig qemu_bh_delete(iocb->bh);
456d353fb72SChristoph Hellwig iocb->bh = NULL;
4578007429aSFam Zheng qemu_aio_unref(iocb);
4587e5cdb34SHanna Reitz
4597e5cdb34SHanna Reitz /* Paired with an increment in ide_issue_trim() */
4607e5cdb34SHanna Reitz blk_dec_in_flight(blk);
461d353fb72SChristoph Hellwig }
462d353fb72SChristoph Hellwig
ide_issue_trim_cb(void * opaque,int ret)463501378c3SPaolo Bonzini static void ide_issue_trim_cb(void *opaque, int ret)
464d353fb72SChristoph Hellwig {
465501378c3SPaolo Bonzini TrimAIOCB *iocb = opaque;
466ef0e64a9SAnton Nefedov IDEState *s = iocb->s;
467ef0e64a9SAnton Nefedov
46899f18035SAnton Nefedov if (iocb->i >= 0) {
46999f18035SAnton Nefedov if (ret >= 0) {
47099f18035SAnton Nefedov block_acct_done(blk_get_stats(s->blk), &s->acct);
47199f18035SAnton Nefedov } else {
47299f18035SAnton Nefedov block_acct_failed(blk_get_stats(s->blk), &s->acct);
47399f18035SAnton Nefedov }
47499f18035SAnton Nefedov }
47599f18035SAnton Nefedov
476501378c3SPaolo Bonzini if (ret >= 0) {
477501378c3SPaolo Bonzini while (iocb->j < iocb->qiov->niov) {
478501378c3SPaolo Bonzini int j = iocb->j;
479501378c3SPaolo Bonzini while (++iocb->i < iocb->qiov->iov[j].iov_len / 8) {
480501378c3SPaolo Bonzini int i = iocb->i;
481501378c3SPaolo Bonzini uint64_t *buffer = iocb->qiov->iov[j].iov_base;
482d353fb72SChristoph Hellwig
483d353fb72SChristoph Hellwig /* 6-byte LBA + 2-byte range per entry */
484d353fb72SChristoph Hellwig uint64_t entry = le64_to_cpu(buffer[i]);
485d353fb72SChristoph Hellwig uint64_t sector = entry & 0x0000ffffffffffffULL;
486d353fb72SChristoph Hellwig uint16_t count = entry >> 48;
487d353fb72SChristoph Hellwig
488d353fb72SChristoph Hellwig if (count == 0) {
48980bc2e8dSPaolo Bonzini continue;
490d353fb72SChristoph Hellwig }
491d353fb72SChristoph Hellwig
492947858b0SAnton Nefedov if (!ide_sect_range_ok(s, sector, count)) {
49399f18035SAnton Nefedov block_acct_invalid(blk_get_stats(s->blk), BLOCK_ACCT_UNMAP);
494caeadbc8SAnton Nefedov iocb->ret = -EINVAL;
495947858b0SAnton Nefedov goto done;
496947858b0SAnton Nefedov }
497947858b0SAnton Nefedov
49899f18035SAnton Nefedov block_acct_start(blk_get_stats(s->blk), &s->acct,
49999f18035SAnton Nefedov count << BDRV_SECTOR_BITS, BLOCK_ACCT_UNMAP);
50099f18035SAnton Nefedov
501501378c3SPaolo Bonzini /* Got an entry! Submit and exit. */
502ef0e64a9SAnton Nefedov iocb->aiocb = blk_aio_pdiscard(s->blk,
5031c6c4bb7SEric Blake sector << BDRV_SECTOR_BITS,
5041c6c4bb7SEric Blake count << BDRV_SECTOR_BITS,
505501378c3SPaolo Bonzini ide_issue_trim_cb, opaque);
506501378c3SPaolo Bonzini return;
507501378c3SPaolo Bonzini }
508501378c3SPaolo Bonzini
509501378c3SPaolo Bonzini iocb->j++;
510501378c3SPaolo Bonzini iocb->i = -1;
511501378c3SPaolo Bonzini }
512501378c3SPaolo Bonzini } else {
513d353fb72SChristoph Hellwig iocb->ret = ret;
514d353fb72SChristoph Hellwig }
515d353fb72SChristoph Hellwig
516947858b0SAnton Nefedov done:
517501378c3SPaolo Bonzini iocb->aiocb = NULL;
518501378c3SPaolo Bonzini if (iocb->bh) {
519b255df7eSPavel Dovgalyuk replay_bh_schedule_event(iocb->bh);
520501378c3SPaolo Bonzini }
521501378c3SPaolo Bonzini }
522d353fb72SChristoph Hellwig
ide_issue_trim(int64_t offset,QEMUIOVector * qiov,BlockCompletionFunc * cb,void * cb_opaque,void * opaque)5238a8e63ebSPaolo Bonzini BlockAIOCB *ide_issue_trim(
5248a8e63ebSPaolo Bonzini int64_t offset, QEMUIOVector *qiov,
5258a8e63ebSPaolo Bonzini BlockCompletionFunc *cb, void *cb_opaque, void *opaque)
526501378c3SPaolo Bonzini {
527ef0e64a9SAnton Nefedov IDEState *s = opaque;
528f63192b0SAlexander Bulekov IDEDevice *dev = s->unit ? s->bus->slave : s->bus->master;
529501378c3SPaolo Bonzini TrimAIOCB *iocb;
530501378c3SPaolo Bonzini
5317e5cdb34SHanna Reitz /* Paired with a decrement in ide_trim_bh_cb() */
5327e5cdb34SHanna Reitz blk_inc_in_flight(s->blk);
5337e5cdb34SHanna Reitz
534ef0e64a9SAnton Nefedov iocb = blk_aio_get(&trim_aiocb_info, s->blk, cb, cb_opaque);
535ef0e64a9SAnton Nefedov iocb->s = s;
536f63192b0SAlexander Bulekov iocb->bh = qemu_bh_new_guarded(ide_trim_bh_cb, iocb,
537f63192b0SAlexander Bulekov &DEVICE(dev)->mem_reentrancy_guard);
538501378c3SPaolo Bonzini iocb->ret = 0;
539501378c3SPaolo Bonzini iocb->qiov = qiov;
540501378c3SPaolo Bonzini iocb->i = -1;
541501378c3SPaolo Bonzini iocb->j = 0;
542501378c3SPaolo Bonzini ide_issue_trim_cb(iocb, 0);
543d353fb72SChristoph Hellwig return &iocb->common;
544d353fb72SChristoph Hellwig }
545d353fb72SChristoph Hellwig
ide_abort_command(IDEState * s)5469ef2e93fSJohn Snow void ide_abort_command(IDEState *s)
54759f2a787SGerd Hoffmann {
54859f2a787SGerd Hoffmann s->status = READY_STAT | ERR_STAT;
54959f2a787SGerd Hoffmann s->error = ABRT_ERR;
550c3461c62SNiklas Cassel ide_transfer_stop(s);
55159f2a787SGerd Hoffmann }
55259f2a787SGerd Hoffmann
ide_set_retry(IDEState * s)5530eeee07eSEvgeny Yakovlev static void ide_set_retry(IDEState *s)
5540eeee07eSEvgeny Yakovlev {
5550eeee07eSEvgeny Yakovlev s->bus->retry_unit = s->unit;
5560eeee07eSEvgeny Yakovlev s->bus->retry_sector_num = ide_get_sector(s);
5570eeee07eSEvgeny Yakovlev s->bus->retry_nsector = s->nsector;
5580eeee07eSEvgeny Yakovlev }
5590eeee07eSEvgeny Yakovlev
ide_clear_retry(IDEState * s)5600eeee07eSEvgeny Yakovlev static void ide_clear_retry(IDEState *s)
5610eeee07eSEvgeny Yakovlev {
5620eeee07eSEvgeny Yakovlev s->bus->retry_unit = -1;
5630eeee07eSEvgeny Yakovlev s->bus->retry_sector_num = 0;
5640eeee07eSEvgeny Yakovlev s->bus->retry_nsector = 0;
5650eeee07eSEvgeny Yakovlev }
5660eeee07eSEvgeny Yakovlev
56759f2a787SGerd Hoffmann /* prepare data transfer and tell what to do after */
ide_transfer_start_norecurse(IDEState * s,uint8_t * buf,int size,EndTransferFunc * end_transfer_func)568c173723fSPaolo Bonzini bool ide_transfer_start_norecurse(IDEState *s, uint8_t *buf, int size,
56959f2a787SGerd Hoffmann EndTransferFunc *end_transfer_func)
57059f2a787SGerd Hoffmann {
57159f2a787SGerd Hoffmann s->data_ptr = buf;
57259f2a787SGerd Hoffmann s->data_end = buf + size;
57335f78ab4SEvgeny Yakovlev ide_set_retry(s);
57440a6238aSAlexander Graf if (!(s->status & ERR_STAT)) {
57559f2a787SGerd Hoffmann s->status |= DRQ_STAT;
57659f2a787SGerd Hoffmann }
577bed9bcfaSPaolo Bonzini if (!s->bus->dma->ops->pio_transfer) {
578bed9bcfaSPaolo Bonzini s->end_transfer_func = end_transfer_func;
579c173723fSPaolo Bonzini return false;
58040a6238aSAlexander Graf }
581bed9bcfaSPaolo Bonzini s->bus->dma->ops->pio_transfer(s->bus->dma);
582c173723fSPaolo Bonzini return true;
583c173723fSPaolo Bonzini }
584c173723fSPaolo Bonzini
ide_transfer_start(IDEState * s,uint8_t * buf,int size,EndTransferFunc * end_transfer_func)585c173723fSPaolo Bonzini void ide_transfer_start(IDEState *s, uint8_t *buf, int size,
586c173723fSPaolo Bonzini EndTransferFunc *end_transfer_func)
587c173723fSPaolo Bonzini {
588c173723fSPaolo Bonzini if (ide_transfer_start_norecurse(s, buf, size, end_transfer_func)) {
589bed9bcfaSPaolo Bonzini end_transfer_func(s);
59044635123SPaolo Bonzini }
591c173723fSPaolo Bonzini }
59259f2a787SGerd Hoffmann
ide_cmd_done(IDEState * s)593c7e73adbSPaolo Bonzini static void ide_cmd_done(IDEState *s)
594c7e73adbSPaolo Bonzini {
595c7e73adbSPaolo Bonzini if (s->bus->dma->ops->cmd_done) {
596c7e73adbSPaolo Bonzini s->bus->dma->ops->cmd_done(s->bus->dma);
597c7e73adbSPaolo Bonzini }
598c7e73adbSPaolo Bonzini }
599c7e73adbSPaolo Bonzini
ide_transfer_halt(IDEState * s)600882941a5SPaolo Bonzini static void ide_transfer_halt(IDEState *s)
60159f2a787SGerd Hoffmann {
602882941a5SPaolo Bonzini s->end_transfer_func = ide_transfer_stop;
60359f2a787SGerd Hoffmann s->data_ptr = s->io_buffer;
60459f2a787SGerd Hoffmann s->data_end = s->io_buffer;
60559f2a787SGerd Hoffmann s->status &= ~DRQ_STAT;
606e3044e23SJohn Snow }
607e3044e23SJohn Snow
ide_transfer_stop(IDEState * s)608e3044e23SJohn Snow void ide_transfer_stop(IDEState *s)
609e3044e23SJohn Snow {
610882941a5SPaolo Bonzini ide_transfer_halt(s);
611ee4cd662SPaolo Bonzini ide_cmd_done(s);
612e3044e23SJohn Snow }
613e3044e23SJohn Snow
ide_get_sector(IDEState * s)61459f2a787SGerd Hoffmann int64_t ide_get_sector(IDEState *s)
61559f2a787SGerd Hoffmann {
61659f2a787SGerd Hoffmann int64_t sector_num;
6170c7515e1SJohn Snow if (s->select & (ATA_DEV_LBA)) {
61814ee9b53SJohn Snow if (s->lba48) {
61959f2a787SGerd Hoffmann sector_num = ((int64_t)s->hob_hcyl << 40) |
62059f2a787SGerd Hoffmann ((int64_t) s->hob_lcyl << 32) |
62159f2a787SGerd Hoffmann ((int64_t) s->hob_sector << 24) |
62259f2a787SGerd Hoffmann ((int64_t) s->hcyl << 16) |
62359f2a787SGerd Hoffmann ((int64_t) s->lcyl << 8) | s->sector;
62414ee9b53SJohn Snow } else {
62514ee9b53SJohn Snow /* LBA28 */
6260c7515e1SJohn Snow sector_num = ((s->select & (ATA_DEV_LBA_MSB)) << 24) |
6270c7515e1SJohn Snow (s->hcyl << 16) | (s->lcyl << 8) | s->sector;
62859f2a787SGerd Hoffmann }
62959f2a787SGerd Hoffmann } else {
63014ee9b53SJohn Snow /* CHS */
63159f2a787SGerd Hoffmann sector_num = ((s->hcyl << 8) | s->lcyl) * s->heads * s->sectors +
6320c7515e1SJohn Snow (s->select & (ATA_DEV_HS)) * s->sectors + (s->sector - 1);
63359f2a787SGerd Hoffmann }
63414ee9b53SJohn Snow
63559f2a787SGerd Hoffmann return sector_num;
63659f2a787SGerd Hoffmann }
63759f2a787SGerd Hoffmann
ide_set_sector(IDEState * s,int64_t sector_num)63859f2a787SGerd Hoffmann void ide_set_sector(IDEState *s, int64_t sector_num)
63959f2a787SGerd Hoffmann {
64059f2a787SGerd Hoffmann unsigned int cyl, r;
6410c7515e1SJohn Snow if (s->select & (ATA_DEV_LBA)) {
64214ee9b53SJohn Snow if (s->lba48) {
64359f2a787SGerd Hoffmann s->sector = sector_num;
64459f2a787SGerd Hoffmann s->lcyl = sector_num >> 8;
64559f2a787SGerd Hoffmann s->hcyl = sector_num >> 16;
64659f2a787SGerd Hoffmann s->hob_sector = sector_num >> 24;
64759f2a787SGerd Hoffmann s->hob_lcyl = sector_num >> 32;
64859f2a787SGerd Hoffmann s->hob_hcyl = sector_num >> 40;
64914ee9b53SJohn Snow } else {
65014ee9b53SJohn Snow /* LBA28 */
6510c7515e1SJohn Snow s->select = (s->select & ~(ATA_DEV_LBA_MSB)) |
6520c7515e1SJohn Snow ((sector_num >> 24) & (ATA_DEV_LBA_MSB));
65314ee9b53SJohn Snow s->hcyl = (sector_num >> 16);
65414ee9b53SJohn Snow s->lcyl = (sector_num >> 8);
65514ee9b53SJohn Snow s->sector = (sector_num);
65659f2a787SGerd Hoffmann }
65759f2a787SGerd Hoffmann } else {
65814ee9b53SJohn Snow /* CHS */
65959f2a787SGerd Hoffmann cyl = sector_num / (s->heads * s->sectors);
66059f2a787SGerd Hoffmann r = sector_num % (s->heads * s->sectors);
66159f2a787SGerd Hoffmann s->hcyl = cyl >> 8;
66259f2a787SGerd Hoffmann s->lcyl = cyl;
6630c7515e1SJohn Snow s->select = (s->select & ~(ATA_DEV_HS)) |
6640c7515e1SJohn Snow ((r / s->sectors) & (ATA_DEV_HS));
66559f2a787SGerd Hoffmann s->sector = (r % s->sectors) + 1;
66659f2a787SGerd Hoffmann }
66759f2a787SGerd Hoffmann }
66859f2a787SGerd Hoffmann
ide_rw_error(IDEState * s)66959f2a787SGerd Hoffmann static void ide_rw_error(IDEState *s) {
67059f2a787SGerd Hoffmann ide_abort_command(s);
6710cfe719dSPhilippe Mathieu-Daudé ide_bus_set_irq(s->bus);
67259f2a787SGerd Hoffmann }
67359f2a787SGerd Hoffmann
ide_buffered_readv_cb(void * opaque,int ret)6741d8c11d6SPeter Lieven static void ide_buffered_readv_cb(void *opaque, int ret)
6751d8c11d6SPeter Lieven {
6761d8c11d6SPeter Lieven IDEBufferedRequest *req = opaque;
6771d8c11d6SPeter Lieven if (!req->orphaned) {
6781d8c11d6SPeter Lieven if (!ret) {
6795bbe9325SVladimir Sementsov-Ogievskiy assert(req->qiov.size == req->original_qiov->size);
6805bbe9325SVladimir Sementsov-Ogievskiy qemu_iovec_from_buf(req->original_qiov, 0,
6815bbe9325SVladimir Sementsov-Ogievskiy req->qiov.local_iov.iov_base,
6821d8c11d6SPeter Lieven req->original_qiov->size);
6831d8c11d6SPeter Lieven }
6841d8c11d6SPeter Lieven req->original_cb(req->original_opaque, ret);
6851d8c11d6SPeter Lieven }
6861d8c11d6SPeter Lieven QLIST_REMOVE(req, list);
6875bbe9325SVladimir Sementsov-Ogievskiy qemu_vfree(qemu_iovec_buf(&req->qiov));
6881d8c11d6SPeter Lieven g_free(req);
6891d8c11d6SPeter Lieven }
6901d8c11d6SPeter Lieven
6911d8c11d6SPeter Lieven #define MAX_BUFFERED_REQS 16
6921d8c11d6SPeter Lieven
ide_buffered_readv(IDEState * s,int64_t sector_num,QEMUIOVector * iov,int nb_sectors,BlockCompletionFunc * cb,void * opaque)6931d8c11d6SPeter Lieven BlockAIOCB *ide_buffered_readv(IDEState *s, int64_t sector_num,
6941d8c11d6SPeter Lieven QEMUIOVector *iov, int nb_sectors,
6951d8c11d6SPeter Lieven BlockCompletionFunc *cb, void *opaque)
6961d8c11d6SPeter Lieven {
6971d8c11d6SPeter Lieven BlockAIOCB *aioreq;
6981d8c11d6SPeter Lieven IDEBufferedRequest *req;
6991d8c11d6SPeter Lieven int c = 0;
7001d8c11d6SPeter Lieven
7011d8c11d6SPeter Lieven QLIST_FOREACH(req, &s->buffered_requests, list) {
7021d8c11d6SPeter Lieven c++;
7031d8c11d6SPeter Lieven }
7041d8c11d6SPeter Lieven if (c > MAX_BUFFERED_REQS) {
7051d8c11d6SPeter Lieven return blk_abort_aio_request(s->blk, cb, opaque, -EIO);
7061d8c11d6SPeter Lieven }
7071d8c11d6SPeter Lieven
7081d8c11d6SPeter Lieven req = g_new0(IDEBufferedRequest, 1);
7091d8c11d6SPeter Lieven req->original_qiov = iov;
7101d8c11d6SPeter Lieven req->original_cb = cb;
7111d8c11d6SPeter Lieven req->original_opaque = opaque;
7125bbe9325SVladimir Sementsov-Ogievskiy qemu_iovec_init_buf(&req->qiov, blk_blockalign(s->blk, iov->size),
7135bbe9325SVladimir Sementsov-Ogievskiy iov->size);
7141d8c11d6SPeter Lieven
715d4f510ebSEric Blake aioreq = blk_aio_preadv(s->blk, sector_num << BDRV_SECTOR_BITS,
716d4f510ebSEric Blake &req->qiov, 0, ide_buffered_readv_cb, req);
7171d8c11d6SPeter Lieven
7181d8c11d6SPeter Lieven QLIST_INSERT_HEAD(&s->buffered_requests, req, list);
7191d8c11d6SPeter Lieven return aioreq;
7201d8c11d6SPeter Lieven }
7211d8c11d6SPeter Lieven
72286698a12SJohn Snow /**
72386698a12SJohn Snow * Cancel all pending DMA requests.
72486698a12SJohn Snow * Any buffered DMA requests are instantly canceled,
72586698a12SJohn Snow * but any pending unbuffered DMA requests must be waited on.
72686698a12SJohn Snow */
ide_cancel_dma_sync(IDEState * s)72786698a12SJohn Snow void ide_cancel_dma_sync(IDEState *s)
72886698a12SJohn Snow {
72986698a12SJohn Snow IDEBufferedRequest *req;
73086698a12SJohn Snow
73186698a12SJohn Snow /* First invoke the callbacks of all buffered requests
73286698a12SJohn Snow * and flag those requests as orphaned. Ideally there
73386698a12SJohn Snow * are no unbuffered (Scatter Gather DMA Requests or
73486698a12SJohn Snow * write requests) pending and we can avoid to drain. */
73586698a12SJohn Snow QLIST_FOREACH(req, &s->buffered_requests, list) {
73686698a12SJohn Snow if (!req->orphaned) {
7373eee2611SJohn Snow trace_ide_cancel_dma_sync_buffered(req->original_cb, req);
73886698a12SJohn Snow req->original_cb(req->original_opaque, -ECANCELED);
73986698a12SJohn Snow }
74086698a12SJohn Snow req->orphaned = true;
74186698a12SJohn Snow }
74286698a12SJohn Snow
74386698a12SJohn Snow /*
74486698a12SJohn Snow * We can't cancel Scatter Gather DMA in the middle of the
74586698a12SJohn Snow * operation or a partial (not full) DMA transfer would reach
74668b57b0dSPhilippe Mathieu-Daudé * the storage so we wait for completion instead (we behave
74786698a12SJohn Snow * like if the DMA was completed by the time the guest trying
74886698a12SJohn Snow * to cancel dma with bmdma_cmd_writeb with BM_CMD_START not
74986698a12SJohn Snow * set).
75086698a12SJohn Snow *
75186698a12SJohn Snow * In the future we'll be able to safely cancel the I/O if the
75286698a12SJohn Snow * whole DMA operation will be submitted to disk with a single
75386698a12SJohn Snow * aio operation with preadv/pwritev.
75486698a12SJohn Snow */
75586698a12SJohn Snow if (s->bus->dma->aiocb) {
7563eee2611SJohn Snow trace_ide_cancel_dma_sync_remaining();
75751f7b5b8SJohn Snow blk_drain(s->blk);
75886698a12SJohn Snow assert(s->bus->dma->aiocb == NULL);
75986698a12SJohn Snow }
76086698a12SJohn Snow }
76186698a12SJohn Snow
7624e2b8b4aSPaolo Bonzini static void ide_sector_read(IDEState *s);
7634e2b8b4aSPaolo Bonzini
ide_sector_read_cb(void * opaque,int ret)764bef0fd59SStefan Hajnoczi static void ide_sector_read_cb(void *opaque, int ret)
765bef0fd59SStefan Hajnoczi {
766bef0fd59SStefan Hajnoczi IDEState *s = opaque;
767bef0fd59SStefan Hajnoczi int n;
768bef0fd59SStefan Hajnoczi
769bef0fd59SStefan Hajnoczi s->pio_aiocb = NULL;
770bef0fd59SStefan Hajnoczi s->status &= ~BUSY_STAT;
771bef0fd59SStefan Hajnoczi
772bef0fd59SStefan Hajnoczi if (ret != 0) {
773fd648f10SPaolo Bonzini if (ide_handle_rw_error(s, -ret, IDE_RETRY_PIO |
774fd648f10SPaolo Bonzini IDE_RETRY_READ)) {
775bef0fd59SStefan Hajnoczi return;
776bef0fd59SStefan Hajnoczi }
777bef0fd59SStefan Hajnoczi }
778bef0fd59SStefan Hajnoczi
779ecca3b39SAlberto Garcia block_acct_done(blk_get_stats(s->blk), &s->acct);
780ecca3b39SAlberto Garcia
781bef0fd59SStefan Hajnoczi n = s->nsector;
782bef0fd59SStefan Hajnoczi if (n > s->req_nb_sectors) {
783bef0fd59SStefan Hajnoczi n = s->req_nb_sectors;
784bef0fd59SStefan Hajnoczi }
785bef0fd59SStefan Hajnoczi
786bef0fd59SStefan Hajnoczi ide_set_sector(s, ide_get_sector(s) + n);
787bef0fd59SStefan Hajnoczi s->nsector -= n;
788dd0bf7baSJohn Snow /* Allow the guest to read the io_buffer */
789dd0bf7baSJohn Snow ide_transfer_start(s, s->io_buffer, n * BDRV_SECTOR_SIZE, ide_sector_read);
7900cfe719dSPhilippe Mathieu-Daudé ide_bus_set_irq(s->bus);
791bef0fd59SStefan Hajnoczi }
792bef0fd59SStefan Hajnoczi
ide_sector_read(IDEState * s)7934e2b8b4aSPaolo Bonzini static void ide_sector_read(IDEState *s)
79459f2a787SGerd Hoffmann {
79559f2a787SGerd Hoffmann int64_t sector_num;
796bef0fd59SStefan Hajnoczi int n;
79759f2a787SGerd Hoffmann
79859f2a787SGerd Hoffmann s->status = READY_STAT | SEEK_STAT;
79959f2a787SGerd Hoffmann s->error = 0; /* not needed by IDE spec, but needed by Windows */
80059f2a787SGerd Hoffmann sector_num = ide_get_sector(s);
80159f2a787SGerd Hoffmann n = s->nsector;
802a597e79cSChristoph Hellwig
803bef0fd59SStefan Hajnoczi if (n == 0) {
804bef0fd59SStefan Hajnoczi ide_transfer_stop(s);
80559f2a787SGerd Hoffmann return;
80659f2a787SGerd Hoffmann }
807bef0fd59SStefan Hajnoczi
808bef0fd59SStefan Hajnoczi s->status |= BUSY_STAT;
809bef0fd59SStefan Hajnoczi
810bef0fd59SStefan Hajnoczi if (n > s->req_nb_sectors) {
811bef0fd59SStefan Hajnoczi n = s->req_nb_sectors;
812ce4b6522SKevin Wolf }
813bef0fd59SStefan Hajnoczi
8143eee2611SJohn Snow trace_ide_sector_read(sector_num, n);
815bef0fd59SStefan Hajnoczi
81658ac3211SMarkus Armbruster if (!ide_sect_range_ok(s, sector_num, n)) {
81758ac3211SMarkus Armbruster ide_rw_error(s);
818ecca3b39SAlberto Garcia block_acct_invalid(blk_get_stats(s->blk), BLOCK_ACCT_READ);
81958ac3211SMarkus Armbruster return;
82058ac3211SMarkus Armbruster }
82158ac3211SMarkus Armbruster
822e5863d49SVladimir Sementsov-Ogievskiy qemu_iovec_init_buf(&s->qiov, s->io_buffer, n * BDRV_SECTOR_SIZE);
823bef0fd59SStefan Hajnoczi
8244be74634SMarkus Armbruster block_acct_start(blk_get_stats(s->blk), &s->acct,
8255366d0c8SBenoît Canet n * BDRV_SECTOR_SIZE, BLOCK_ACCT_READ);
826d66a8fa8SPeter Lieven s->pio_aiocb = ide_buffered_readv(s, sector_num, &s->qiov, n,
827bef0fd59SStefan Hajnoczi ide_sector_read_cb, s);
82859f2a787SGerd Hoffmann }
82959f2a787SGerd Hoffmann
dma_buf_commit(IDEState * s,uint32_t tx_bytes)830aaeda4a3SJohn Snow void dma_buf_commit(IDEState *s, uint32_t tx_bytes)
83159f2a787SGerd Hoffmann {
832659142ecSJohn Snow if (s->bus->dma->ops->commit_buf) {
833659142ecSJohn Snow s->bus->dma->ops->commit_buf(s->bus->dma, tx_bytes);
834659142ecSJohn Snow }
835aaeda4a3SJohn Snow s->io_buffer_offset += tx_bytes;
83659f2a787SGerd Hoffmann qemu_sglist_destroy(&s->sg);
83759f2a787SGerd Hoffmann }
83859f2a787SGerd Hoffmann
ide_set_inactive(IDEState * s,bool more)8390e7ce54cSPaolo Bonzini void ide_set_inactive(IDEState *s, bool more)
8408337606dSKevin Wolf {
84140a6238aSAlexander Graf s->bus->dma->aiocb = NULL;
8420eeee07eSEvgeny Yakovlev ide_clear_retry(s);
843829b933bSPaolo Bonzini if (s->bus->dma->ops->set_inactive) {
8440e7ce54cSPaolo Bonzini s->bus->dma->ops->set_inactive(s->bus->dma, more);
845829b933bSPaolo Bonzini }
846c7e73adbSPaolo Bonzini ide_cmd_done(s);
8478337606dSKevin Wolf }
8488337606dSKevin Wolf
ide_dma_error(IDEState * s)84959f2a787SGerd Hoffmann void ide_dma_error(IDEState *s)
85059f2a787SGerd Hoffmann {
851659142ecSJohn Snow dma_buf_commit(s, 0);
85208ee9e33SPaolo Bonzini ide_abort_command(s);
8530e7ce54cSPaolo Bonzini ide_set_inactive(s, false);
8540cfe719dSPhilippe Mathieu-Daudé ide_bus_set_irq(s->bus);
85559f2a787SGerd Hoffmann }
85659f2a787SGerd Hoffmann
ide_handle_rw_error(IDEState * s,int error,int op)857502356eeSPavel Butsykin int ide_handle_rw_error(IDEState *s, int error, int op)
85859f2a787SGerd Hoffmann {
859fd648f10SPaolo Bonzini bool is_read = (op & IDE_RETRY_READ) != 0;
8604be74634SMarkus Armbruster BlockErrorAction action = blk_get_error_action(s->blk, is_read, error);
86159f2a787SGerd Hoffmann
862a589569fSWenchao Xia if (action == BLOCK_ERROR_ACTION_STOP) {
863a96cb236SPaolo Bonzini assert(s->bus->retry_unit == s->unit);
864def93791SKevin Wolf s->bus->error_status = op;
865a589569fSWenchao Xia } else if (action == BLOCK_ERROR_ACTION_REPORT) {
866ecca3b39SAlberto Garcia block_acct_failed(blk_get_stats(s->blk), &s->acct);
867502356eeSPavel Butsykin if (IS_IDE_RETRY_DMA(op)) {
86859f2a787SGerd Hoffmann ide_dma_error(s);
869502356eeSPavel Butsykin } else if (IS_IDE_RETRY_ATAPI(op)) {
870502356eeSPavel Butsykin ide_atapi_io_error(s, -error);
87159f2a787SGerd Hoffmann } else {
87259f2a787SGerd Hoffmann ide_rw_error(s);
87359f2a787SGerd Hoffmann }
87459f2a787SGerd Hoffmann }
8754be74634SMarkus Armbruster blk_error_action(s->blk, action, is_read, error);
876a589569fSWenchao Xia return action != BLOCK_ERROR_ACTION_IGNORE;
87759f2a787SGerd Hoffmann }
87859f2a787SGerd Hoffmann
ide_dma_cb(void * opaque,int ret)8794e2b8b4aSPaolo Bonzini static void ide_dma_cb(void *opaque, int ret)
88059f2a787SGerd Hoffmann {
88140a6238aSAlexander Graf IDEState *s = opaque;
88259f2a787SGerd Hoffmann int n;
88359f2a787SGerd Hoffmann int64_t sector_num;
884cbe0ed62SPaolo Bonzini uint64_t offset;
885038268e2SKevin Wolf bool stay_active = false;
886ed78352aSAlexander Popov int32_t prep_size = 0;
88759f2a787SGerd Hoffmann
888caeadbc8SAnton Nefedov if (ret == -EINVAL) {
889caeadbc8SAnton Nefedov ide_dma_error(s);
890caeadbc8SAnton Nefedov return;
891caeadbc8SAnton Nefedov }
892caeadbc8SAnton Nefedov
89359f2a787SGerd Hoffmann if (ret < 0) {
894218fd37cSPavel Butsykin if (ide_handle_rw_error(s, -ret, ide_dma_cmd_to_retry(s->dma_cmd))) {
89587ac25fdSJohn Snow s->bus->dma->aiocb = NULL;
8965839df7bSMarc-André Lureau dma_buf_commit(s, 0);
89759f2a787SGerd Hoffmann return;
89859f2a787SGerd Hoffmann }
899ce4b6522SKevin Wolf }
90059f2a787SGerd Hoffmann
901ed78352aSAlexander Popov if (s->io_buffer_size > s->nsector * 512) {
902ed78352aSAlexander Popov /*
903ed78352aSAlexander Popov * The PRDs were longer than needed for this request.
904ed78352aSAlexander Popov * The Active bit must remain set after the request completes.
905ed78352aSAlexander Popov */
906038268e2SKevin Wolf n = s->nsector;
907038268e2SKevin Wolf stay_active = true;
908ed78352aSAlexander Popov } else {
909ed78352aSAlexander Popov n = s->io_buffer_size >> 9;
910038268e2SKevin Wolf }
911038268e2SKevin Wolf
91259f2a787SGerd Hoffmann sector_num = ide_get_sector(s);
91359f2a787SGerd Hoffmann if (n > 0) {
914a718978eSJohn Snow assert(n * 512 == s->sg.size);
915a718978eSJohn Snow dma_buf_commit(s, s->sg.size);
91659f2a787SGerd Hoffmann sector_num += n;
91759f2a787SGerd Hoffmann ide_set_sector(s, sector_num);
91859f2a787SGerd Hoffmann s->nsector -= n;
91959f2a787SGerd Hoffmann }
92059f2a787SGerd Hoffmann
92159f2a787SGerd Hoffmann /* end of transfer ? */
92259f2a787SGerd Hoffmann if (s->nsector == 0) {
92359f2a787SGerd Hoffmann s->status = READY_STAT | SEEK_STAT;
9240cfe719dSPhilippe Mathieu-Daudé ide_bus_set_irq(s->bus);
925cd369c46SChristoph Hellwig goto eot;
92659f2a787SGerd Hoffmann }
92759f2a787SGerd Hoffmann
92859f2a787SGerd Hoffmann /* launch next transfer */
92959f2a787SGerd Hoffmann n = s->nsector;
93059f2a787SGerd Hoffmann s->io_buffer_index = 0;
93159f2a787SGerd Hoffmann s->io_buffer_size = n * 512;
932ed78352aSAlexander Popov prep_size = s->bus->dma->ops->prepare_buf(s->bus->dma, s->io_buffer_size);
933ed78352aSAlexander Popov /* prepare_buf() must succeed and respect the limit */
934ed78352aSAlexander Popov assert(prep_size >= 0 && prep_size <= n * 512);
935ed78352aSAlexander Popov
936ed78352aSAlexander Popov /*
937ed78352aSAlexander Popov * Now prep_size stores the number of bytes in the sglist, and
938ed78352aSAlexander Popov * s->io_buffer_size stores the number of bytes described by the PRDs.
939ed78352aSAlexander Popov */
940ed78352aSAlexander Popov
941ed78352aSAlexander Popov if (prep_size < n * 512) {
942ed78352aSAlexander Popov /*
943ed78352aSAlexander Popov * The PRDs are too short for this request. Error condition!
944ed78352aSAlexander Popov * Reset the Active bit and don't raise the interrupt.
945ed78352aSAlexander Popov */
94672bcca73SKevin Wolf s->status = READY_STAT | SEEK_STAT;
9473251bdcfSJohn Snow dma_buf_commit(s, 0);
94859f2a787SGerd Hoffmann goto eot;
94969c38b8fSKevin Wolf }
950cd369c46SChristoph Hellwig
9510e168d35SJohn Snow trace_ide_dma_cb(s, sector_num, n, IDE_DMA_CMD_str(s->dma_cmd));
952cd369c46SChristoph Hellwig
953d66168edSMichael Tokarev if ((s->dma_cmd == IDE_DMA_READ || s->dma_cmd == IDE_DMA_WRITE) &&
954d66168edSMichael Tokarev !ide_sect_range_ok(s, sector_num, n)) {
95558ac3211SMarkus Armbruster ide_dma_error(s);
956ecca3b39SAlberto Garcia block_acct_invalid(blk_get_stats(s->blk), s->acct.type);
95758ac3211SMarkus Armbruster return;
95858ac3211SMarkus Armbruster }
95958ac3211SMarkus Armbruster
960cbe0ed62SPaolo Bonzini offset = sector_num << BDRV_SECTOR_BITS;
9614e1e0051SChristoph Hellwig switch (s->dma_cmd) {
9624e1e0051SChristoph Hellwig case IDE_DMA_READ:
963cbe0ed62SPaolo Bonzini s->bus->dma->aiocb = dma_blk_read(s->blk, &s->sg, offset,
96499868af3SMark Cave-Ayland BDRV_SECTOR_SIZE, ide_dma_cb, s);
9654e1e0051SChristoph Hellwig break;
9664e1e0051SChristoph Hellwig case IDE_DMA_WRITE:
967cbe0ed62SPaolo Bonzini s->bus->dma->aiocb = dma_blk_write(s->blk, &s->sg, offset,
96899868af3SMark Cave-Ayland BDRV_SECTOR_SIZE, ide_dma_cb, s);
9694e1e0051SChristoph Hellwig break;
970d353fb72SChristoph Hellwig case IDE_DMA_TRIM:
9718a8e63ebSPaolo Bonzini s->bus->dma->aiocb = dma_blk_io(blk_get_aio_context(s->blk),
97299868af3SMark Cave-Ayland &s->sg, offset, BDRV_SECTOR_SIZE,
973ef0e64a9SAnton Nefedov ide_issue_trim, s, ide_dma_cb, s,
97443cf8ae6SDavid Gibson DMA_DIRECTION_TO_DEVICE);
975d353fb72SChristoph Hellwig break;
976502356eeSPavel Butsykin default:
977502356eeSPavel Butsykin abort();
978cd369c46SChristoph Hellwig }
979cd369c46SChristoph Hellwig return;
980cd369c46SChristoph Hellwig
981cd369c46SChristoph Hellwig eot:
982a597e79cSChristoph Hellwig if (s->dma_cmd == IDE_DMA_READ || s->dma_cmd == IDE_DMA_WRITE) {
9834be74634SMarkus Armbruster block_acct_done(blk_get_stats(s->blk), &s->acct);
984a597e79cSChristoph Hellwig }
9850e7ce54cSPaolo Bonzini ide_set_inactive(s, stay_active);
98659f2a787SGerd Hoffmann }
98759f2a787SGerd Hoffmann
ide_sector_start_dma(IDEState * s,enum ide_dma_cmd dma_cmd)9884e1e0051SChristoph Hellwig static void ide_sector_start_dma(IDEState *s, enum ide_dma_cmd dma_cmd)
98959f2a787SGerd Hoffmann {
9909da82227SJohn Snow s->status = READY_STAT | SEEK_STAT | DRQ_STAT;
99159f2a787SGerd Hoffmann s->io_buffer_size = 0;
9924e1e0051SChristoph Hellwig s->dma_cmd = dma_cmd;
993a597e79cSChristoph Hellwig
994a597e79cSChristoph Hellwig switch (dma_cmd) {
995a597e79cSChristoph Hellwig case IDE_DMA_READ:
9964be74634SMarkus Armbruster block_acct_start(blk_get_stats(s->blk), &s->acct,
9975366d0c8SBenoît Canet s->nsector * BDRV_SECTOR_SIZE, BLOCK_ACCT_READ);
998a597e79cSChristoph Hellwig break;
999a597e79cSChristoph Hellwig case IDE_DMA_WRITE:
10004be74634SMarkus Armbruster block_acct_start(blk_get_stats(s->blk), &s->acct,
10015366d0c8SBenoît Canet s->nsector * BDRV_SECTOR_SIZE, BLOCK_ACCT_WRITE);
1002a597e79cSChristoph Hellwig break;
1003a597e79cSChristoph Hellwig default:
1004a597e79cSChristoph Hellwig break;
1005a597e79cSChristoph Hellwig }
1006a597e79cSChristoph Hellwig
10074855b576SPaolo Bonzini ide_start_dma(s, ide_dma_cb);
10084855b576SPaolo Bonzini }
10094855b576SPaolo Bonzini
ide_start_dma(IDEState * s,BlockCompletionFunc * cb)1010097310b5SMarkus Armbruster void ide_start_dma(IDEState *s, BlockCompletionFunc *cb)
10114855b576SPaolo Bonzini {
1012c71c06d4SPaolo Bonzini s->io_buffer_index = 0;
10130eeee07eSEvgeny Yakovlev ide_set_retry(s);
10144855b576SPaolo Bonzini if (s->bus->dma->ops->start_dma) {
10154855b576SPaolo Bonzini s->bus->dma->ops->start_dma(s->bus->dma, s, cb);
10164855b576SPaolo Bonzini }
101759f2a787SGerd Hoffmann }
101859f2a787SGerd Hoffmann
10194e2b8b4aSPaolo Bonzini static void ide_sector_write(IDEState *s);
10204e2b8b4aSPaolo Bonzini
ide_sector_write_timer_cb(void * opaque)102159f2a787SGerd Hoffmann static void ide_sector_write_timer_cb(void *opaque)
102259f2a787SGerd Hoffmann {
102359f2a787SGerd Hoffmann IDEState *s = opaque;
10240cfe719dSPhilippe Mathieu-Daudé ide_bus_set_irq(s->bus);
102559f2a787SGerd Hoffmann }
102659f2a787SGerd Hoffmann
ide_sector_write_cb(void * opaque,int ret)1027e82dabd8SStefan Hajnoczi static void ide_sector_write_cb(void *opaque, int ret)
102859f2a787SGerd Hoffmann {
1029e82dabd8SStefan Hajnoczi IDEState *s = opaque;
1030e82dabd8SStefan Hajnoczi int n;
103159f2a787SGerd Hoffmann
1032e82dabd8SStefan Hajnoczi s->pio_aiocb = NULL;
1033e82dabd8SStefan Hajnoczi s->status &= ~BUSY_STAT;
1034e82dabd8SStefan Hajnoczi
103559f2a787SGerd Hoffmann if (ret != 0) {
1036fd648f10SPaolo Bonzini if (ide_handle_rw_error(s, -ret, IDE_RETRY_PIO)) {
103759f2a787SGerd Hoffmann return;
103859f2a787SGerd Hoffmann }
1039e82dabd8SStefan Hajnoczi }
104059f2a787SGerd Hoffmann
1041ecca3b39SAlberto Garcia block_acct_done(blk_get_stats(s->blk), &s->acct);
1042ecca3b39SAlberto Garcia
1043e82dabd8SStefan Hajnoczi n = s->nsector;
1044e82dabd8SStefan Hajnoczi if (n > s->req_nb_sectors) {
1045e82dabd8SStefan Hajnoczi n = s->req_nb_sectors;
1046e82dabd8SStefan Hajnoczi }
104759f2a787SGerd Hoffmann s->nsector -= n;
104836334fafSJohn Snow
10496aff22c0SJohn Snow ide_set_sector(s, ide_get_sector(s) + n);
105059f2a787SGerd Hoffmann if (s->nsector == 0) {
105159f2a787SGerd Hoffmann /* no more sectors to write */
105259f2a787SGerd Hoffmann ide_transfer_stop(s);
105359f2a787SGerd Hoffmann } else {
1054e82dabd8SStefan Hajnoczi int n1 = s->nsector;
1055e82dabd8SStefan Hajnoczi if (n1 > s->req_nb_sectors) {
105659f2a787SGerd Hoffmann n1 = s->req_nb_sectors;
105759f2a787SGerd Hoffmann }
1058e82dabd8SStefan Hajnoczi ide_transfer_start(s, s->io_buffer, n1 * BDRV_SECTOR_SIZE,
1059e82dabd8SStefan Hajnoczi ide_sector_write);
1060e82dabd8SStefan Hajnoczi }
106159f2a787SGerd Hoffmann
1062d13f4035SPaolo Bonzini if (s->win2k_install_hack && ((++s->irq_count % 16) == 0)) {
106359f2a787SGerd Hoffmann /* It seems there is a bug in the Windows 2000 installer HDD
106459f2a787SGerd Hoffmann IDE driver which fills the disk with empty logs when the
106559f2a787SGerd Hoffmann IDE write IRQ comes too early. This hack tries to correct
106659f2a787SGerd Hoffmann that at the expense of slower write performances. Use this
106759f2a787SGerd Hoffmann option _only_ to install Windows 2000. You must disable it
106859f2a787SGerd Hoffmann for normal use. */
106973bcb24dSRutuja Shah timer_mod(s->sector_write_timer, qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) +
107073bcb24dSRutuja Shah (NANOSECONDS_PER_SECOND / 1000));
1071f7736b91SBlue Swirl } else {
10720cfe719dSPhilippe Mathieu-Daudé ide_bus_set_irq(s->bus);
107359f2a787SGerd Hoffmann }
107459f2a787SGerd Hoffmann }
107559f2a787SGerd Hoffmann
ide_sector_write(IDEState * s)10764e2b8b4aSPaolo Bonzini static void ide_sector_write(IDEState *s)
1077e82dabd8SStefan Hajnoczi {
1078e82dabd8SStefan Hajnoczi int64_t sector_num;
1079e82dabd8SStefan Hajnoczi int n;
1080e82dabd8SStefan Hajnoczi
1081e82dabd8SStefan Hajnoczi s->status = READY_STAT | SEEK_STAT | BUSY_STAT;
1082e82dabd8SStefan Hajnoczi sector_num = ide_get_sector(s);
10833eee2611SJohn Snow
1084e82dabd8SStefan Hajnoczi n = s->nsector;
1085e82dabd8SStefan Hajnoczi if (n > s->req_nb_sectors) {
1086e82dabd8SStefan Hajnoczi n = s->req_nb_sectors;
1087e82dabd8SStefan Hajnoczi }
1088e82dabd8SStefan Hajnoczi
10893eee2611SJohn Snow trace_ide_sector_write(sector_num, n);
10903eee2611SJohn Snow
109158ac3211SMarkus Armbruster if (!ide_sect_range_ok(s, sector_num, n)) {
109258ac3211SMarkus Armbruster ide_rw_error(s);
1093ecca3b39SAlberto Garcia block_acct_invalid(blk_get_stats(s->blk), BLOCK_ACCT_WRITE);
109458ac3211SMarkus Armbruster return;
109558ac3211SMarkus Armbruster }
109658ac3211SMarkus Armbruster
1097e5863d49SVladimir Sementsov-Ogievskiy qemu_iovec_init_buf(&s->qiov, s->io_buffer, n * BDRV_SECTOR_SIZE);
1098e82dabd8SStefan Hajnoczi
10994be74634SMarkus Armbruster block_acct_start(blk_get_stats(s->blk), &s->acct,
1100c618f331SAlberto Garcia n * BDRV_SECTOR_SIZE, BLOCK_ACCT_WRITE);
1101d4f510ebSEric Blake s->pio_aiocb = blk_aio_pwritev(s->blk, sector_num << BDRV_SECTOR_BITS,
1102d4f510ebSEric Blake &s->qiov, 0, ide_sector_write_cb, s);
1103e82dabd8SStefan Hajnoczi }
1104e82dabd8SStefan Hajnoczi
ide_flush_cb(void * opaque,int ret)1105b0484ae4SChristoph Hellwig static void ide_flush_cb(void *opaque, int ret)
1106b0484ae4SChristoph Hellwig {
1107b0484ae4SChristoph Hellwig IDEState *s = opaque;
1108b0484ae4SChristoph Hellwig
110969f72a22SPaolo Bonzini s->pio_aiocb = NULL;
111069f72a22SPaolo Bonzini
1111e2bcadadSKevin Wolf if (ret < 0) {
1112e2bcadadSKevin Wolf /* XXX: What sector number to set here? */
1113fd648f10SPaolo Bonzini if (ide_handle_rw_error(s, -ret, IDE_RETRY_FLUSH)) {
1114e2bcadadSKevin Wolf return;
1115e2bcadadSKevin Wolf }
1116e2bcadadSKevin Wolf }
1117b0484ae4SChristoph Hellwig
11184be74634SMarkus Armbruster if (s->blk) {
11194be74634SMarkus Armbruster block_acct_done(blk_get_stats(s->blk), &s->acct);
1120f7f3ff1dSKevin Wolf }
1121b0484ae4SChristoph Hellwig s->status = READY_STAT | SEEK_STAT;
1122c7e73adbSPaolo Bonzini ide_cmd_done(s);
11230cfe719dSPhilippe Mathieu-Daudé ide_bus_set_irq(s->bus);
1124b0484ae4SChristoph Hellwig }
1125b0484ae4SChristoph Hellwig
ide_flush_cache(IDEState * s)11264e2b8b4aSPaolo Bonzini static void ide_flush_cache(IDEState *s)
11276bcb1a79SKevin Wolf {
11284be74634SMarkus Armbruster if (s->blk == NULL) {
11296bcb1a79SKevin Wolf ide_flush_cb(s, 0);
1130b2df7531SKevin Wolf return;
1131b2df7531SKevin Wolf }
1132b2df7531SKevin Wolf
1133f68ec837SAndreas Färber s->status |= BUSY_STAT;
113435f78ab4SEvgeny Yakovlev ide_set_retry(s);
11354be74634SMarkus Armbruster block_acct_start(blk_get_stats(s->blk), &s->acct, 0, BLOCK_ACCT_FLUSH);
11364be74634SMarkus Armbruster s->pio_aiocb = blk_aio_flush(s->blk, ide_flush_cb, s);
11376bcb1a79SKevin Wolf }
11386bcb1a79SKevin Wolf
ide_cfata_metadata_inquiry(IDEState * s)113959f2a787SGerd Hoffmann static void ide_cfata_metadata_inquiry(IDEState *s)
114059f2a787SGerd Hoffmann {
114159f2a787SGerd Hoffmann uint16_t *p;
114259f2a787SGerd Hoffmann uint32_t spd;
114359f2a787SGerd Hoffmann
114459f2a787SGerd Hoffmann p = (uint16_t *) s->io_buffer;
114559f2a787SGerd Hoffmann memset(p, 0, 0x200);
114659f2a787SGerd Hoffmann spd = ((s->mdata_size - 1) >> 9) + 1;
114759f2a787SGerd Hoffmann
114859f2a787SGerd Hoffmann put_le16(p + 0, 0x0001); /* Data format revision */
114959f2a787SGerd Hoffmann put_le16(p + 1, 0x0000); /* Media property: silicon */
115059f2a787SGerd Hoffmann put_le16(p + 2, s->media_changed); /* Media status */
115159f2a787SGerd Hoffmann put_le16(p + 3, s->mdata_size & 0xffff); /* Capacity in bytes (low) */
115259f2a787SGerd Hoffmann put_le16(p + 4, s->mdata_size >> 16); /* Capacity in bytes (high) */
115359f2a787SGerd Hoffmann put_le16(p + 5, spd & 0xffff); /* Sectors per device (low) */
115459f2a787SGerd Hoffmann put_le16(p + 6, spd >> 16); /* Sectors per device (high) */
115559f2a787SGerd Hoffmann }
115659f2a787SGerd Hoffmann
ide_cfata_metadata_read(IDEState * s)115759f2a787SGerd Hoffmann static void ide_cfata_metadata_read(IDEState *s)
115859f2a787SGerd Hoffmann {
115959f2a787SGerd Hoffmann uint16_t *p;
116059f2a787SGerd Hoffmann
116159f2a787SGerd Hoffmann if (((s->hcyl << 16) | s->lcyl) << 9 > s->mdata_size + 2) {
116259f2a787SGerd Hoffmann s->status = ERR_STAT;
116359f2a787SGerd Hoffmann s->error = ABRT_ERR;
116459f2a787SGerd Hoffmann return;
116559f2a787SGerd Hoffmann }
116659f2a787SGerd Hoffmann
116759f2a787SGerd Hoffmann p = (uint16_t *) s->io_buffer;
116859f2a787SGerd Hoffmann memset(p, 0, 0x200);
116959f2a787SGerd Hoffmann
117059f2a787SGerd Hoffmann put_le16(p + 0, s->media_changed); /* Media status */
117159f2a787SGerd Hoffmann memcpy(p + 1, s->mdata_storage + (((s->hcyl << 16) | s->lcyl) << 9),
117259f2a787SGerd Hoffmann MIN(MIN(s->mdata_size - (((s->hcyl << 16) | s->lcyl) << 9),
117359f2a787SGerd Hoffmann s->nsector << 9), 0x200 - 2));
117459f2a787SGerd Hoffmann }
117559f2a787SGerd Hoffmann
ide_cfata_metadata_write(IDEState * s)117659f2a787SGerd Hoffmann static void ide_cfata_metadata_write(IDEState *s)
117759f2a787SGerd Hoffmann {
117859f2a787SGerd Hoffmann if (((s->hcyl << 16) | s->lcyl) << 9 > s->mdata_size + 2) {
117959f2a787SGerd Hoffmann s->status = ERR_STAT;
118059f2a787SGerd Hoffmann s->error = ABRT_ERR;
118159f2a787SGerd Hoffmann return;
118259f2a787SGerd Hoffmann }
118359f2a787SGerd Hoffmann
118459f2a787SGerd Hoffmann s->media_changed = 0;
118559f2a787SGerd Hoffmann
118659f2a787SGerd Hoffmann memcpy(s->mdata_storage + (((s->hcyl << 16) | s->lcyl) << 9),
118759f2a787SGerd Hoffmann s->io_buffer + 2,
118859f2a787SGerd Hoffmann MIN(MIN(s->mdata_size - (((s->hcyl << 16) | s->lcyl) << 9),
118959f2a787SGerd Hoffmann s->nsector << 9), 0x200 - 2));
119059f2a787SGerd Hoffmann }
119159f2a787SGerd Hoffmann
119259f2a787SGerd Hoffmann /* called when the inserted state of the media has changed */
ide_cd_change_cb(void * opaque,bool load,Error ** errp)119339829a01SKevin Wolf static void ide_cd_change_cb(void *opaque, bool load, Error **errp)
119459f2a787SGerd Hoffmann {
119559f2a787SGerd Hoffmann IDEState *s = opaque;
119659f2a787SGerd Hoffmann uint64_t nb_sectors;
119759f2a787SGerd Hoffmann
119825ad22bcSMarkus Armbruster s->tray_open = !load;
11994be74634SMarkus Armbruster blk_get_geometry(s->blk, &nb_sectors);
120059f2a787SGerd Hoffmann s->nb_sectors = nb_sectors;
120159f2a787SGerd Hoffmann
12024b9b7092SAmit Shah /*
12034b9b7092SAmit Shah * First indicate to the guest that a CD has been removed. That's
12044b9b7092SAmit Shah * done on the next command the guest sends us.
12054b9b7092SAmit Shah *
120667cc61e4SPaolo Bonzini * Then we set UNIT_ATTENTION, by which the guest will
12074b9b7092SAmit Shah * detect a new CD in the drive. See ide_atapi_cmd() for details.
12084b9b7092SAmit Shah */
120959f2a787SGerd Hoffmann s->cdrom_changed = 1;
1210996faf1aSAmit Shah s->events.new_media = true;
12112df0a3a3SPaolo Bonzini s->events.eject_request = false;
12120cfe719dSPhilippe Mathieu-Daudé ide_bus_set_irq(s->bus);
12132df0a3a3SPaolo Bonzini }
12142df0a3a3SPaolo Bonzini
ide_cd_eject_request_cb(void * opaque,bool force)12152df0a3a3SPaolo Bonzini static void ide_cd_eject_request_cb(void *opaque, bool force)
12162df0a3a3SPaolo Bonzini {
12172df0a3a3SPaolo Bonzini IDEState *s = opaque;
12182df0a3a3SPaolo Bonzini
12192df0a3a3SPaolo Bonzini s->events.eject_request = true;
12202df0a3a3SPaolo Bonzini if (force) {
12212df0a3a3SPaolo Bonzini s->tray_locked = false;
12222df0a3a3SPaolo Bonzini }
12230cfe719dSPhilippe Mathieu-Daudé ide_bus_set_irq(s->bus);
122459f2a787SGerd Hoffmann }
122559f2a787SGerd Hoffmann
ide_cmd_lba48_transform(IDEState * s,int lba48)122659f2a787SGerd Hoffmann static void ide_cmd_lba48_transform(IDEState *s, int lba48)
122759f2a787SGerd Hoffmann {
122859f2a787SGerd Hoffmann s->lba48 = lba48;
122959f2a787SGerd Hoffmann
123059f2a787SGerd Hoffmann /* handle the 'magic' 0 nsector count conversion here. to avoid
123159f2a787SGerd Hoffmann * fiddling with the rest of the read logic, we just store the
123259f2a787SGerd Hoffmann * full sector count in ->nsector and ignore ->hob_nsector from now
123359f2a787SGerd Hoffmann */
123459f2a787SGerd Hoffmann if (!s->lba48) {
123559f2a787SGerd Hoffmann if (!s->nsector)
123659f2a787SGerd Hoffmann s->nsector = 256;
123759f2a787SGerd Hoffmann } else {
123859f2a787SGerd Hoffmann if (!s->nsector && !s->hob_nsector)
123959f2a787SGerd Hoffmann s->nsector = 65536;
124059f2a787SGerd Hoffmann else {
124159f2a787SGerd Hoffmann int lo = s->nsector;
124259f2a787SGerd Hoffmann int hi = s->hob_nsector;
124359f2a787SGerd Hoffmann
124459f2a787SGerd Hoffmann s->nsector = (hi << 8) | lo;
124559f2a787SGerd Hoffmann }
124659f2a787SGerd Hoffmann }
124759f2a787SGerd Hoffmann }
124859f2a787SGerd Hoffmann
ide_clear_hob(IDEBus * bus)124959f2a787SGerd Hoffmann static void ide_clear_hob(IDEBus *bus)
125059f2a787SGerd Hoffmann {
125159f2a787SGerd Hoffmann /* any write clears HOB high bit of device control register */
1252be8c9423SJohn Snow bus->cmd &= ~(IDE_CTRL_HOB);
125359f2a787SGerd Hoffmann }
125459f2a787SGerd Hoffmann
1255335ca2f2SJohn Snow /* IOport [W]rite [R]egisters */
1256335ca2f2SJohn Snow enum ATA_IOPORT_WR {
1257335ca2f2SJohn Snow ATA_IOPORT_WR_DATA = 0,
1258335ca2f2SJohn Snow ATA_IOPORT_WR_FEATURES = 1,
1259335ca2f2SJohn Snow ATA_IOPORT_WR_SECTOR_COUNT = 2,
1260335ca2f2SJohn Snow ATA_IOPORT_WR_SECTOR_NUMBER = 3,
1261335ca2f2SJohn Snow ATA_IOPORT_WR_CYLINDER_LOW = 4,
1262335ca2f2SJohn Snow ATA_IOPORT_WR_CYLINDER_HIGH = 5,
1263335ca2f2SJohn Snow ATA_IOPORT_WR_DEVICE_HEAD = 6,
1264335ca2f2SJohn Snow ATA_IOPORT_WR_COMMAND = 7,
1265335ca2f2SJohn Snow ATA_IOPORT_WR_NUM_REGISTERS,
1266335ca2f2SJohn Snow };
1267335ca2f2SJohn Snow
1268335ca2f2SJohn Snow const char *ATA_IOPORT_WR_lookup[ATA_IOPORT_WR_NUM_REGISTERS] = {
1269335ca2f2SJohn Snow [ATA_IOPORT_WR_DATA] = "Data",
1270335ca2f2SJohn Snow [ATA_IOPORT_WR_FEATURES] = "Features",
1271335ca2f2SJohn Snow [ATA_IOPORT_WR_SECTOR_COUNT] = "Sector Count",
1272335ca2f2SJohn Snow [ATA_IOPORT_WR_SECTOR_NUMBER] = "Sector Number",
1273335ca2f2SJohn Snow [ATA_IOPORT_WR_CYLINDER_LOW] = "Cylinder Low",
1274335ca2f2SJohn Snow [ATA_IOPORT_WR_CYLINDER_HIGH] = "Cylinder High",
1275335ca2f2SJohn Snow [ATA_IOPORT_WR_DEVICE_HEAD] = "Device/Head",
1276335ca2f2SJohn Snow [ATA_IOPORT_WR_COMMAND] = "Command"
1277335ca2f2SJohn Snow };
1278335ca2f2SJohn Snow
ide_ioport_write(void * opaque,uint32_t addr,uint32_t val)127959f2a787SGerd Hoffmann void ide_ioport_write(void *opaque, uint32_t addr, uint32_t val)
128059f2a787SGerd Hoffmann {
128159f2a787SGerd Hoffmann IDEBus *bus = opaque;
12822c50207fSPhilippe Mathieu-Daudé IDEState *s = ide_bus_active_if(bus);
12833eee2611SJohn Snow int reg_num = addr & 7;
128459f2a787SGerd Hoffmann
1285335ca2f2SJohn Snow trace_ide_ioport_write(addr, ATA_IOPORT_WR_lookup[reg_num], val, bus, s);
128659f2a787SGerd Hoffmann
128759f2a787SGerd Hoffmann /* ignore writes to command block while busy with previous command */
12883eee2611SJohn Snow if (reg_num != 7 && (s->status & (BUSY_STAT|DRQ_STAT))) {
128959f2a787SGerd Hoffmann return;
12903eee2611SJohn Snow }
129159f2a787SGerd Hoffmann
1292be8c9423SJohn Snow /* NOTE: Device0 and Device1 both receive incoming register writes.
1293be8c9423SJohn Snow * (They're on the same bus! They have to!) */
1294be8c9423SJohn Snow
12953eee2611SJohn Snow switch (reg_num) {
129659f2a787SGerd Hoffmann case 0:
129759f2a787SGerd Hoffmann break;
1298335ca2f2SJohn Snow case ATA_IOPORT_WR_FEATURES:
129959f2a787SGerd Hoffmann ide_clear_hob(bus);
130059f2a787SGerd Hoffmann bus->ifs[0].hob_feature = bus->ifs[0].feature;
130159f2a787SGerd Hoffmann bus->ifs[1].hob_feature = bus->ifs[1].feature;
130259f2a787SGerd Hoffmann bus->ifs[0].feature = val;
130359f2a787SGerd Hoffmann bus->ifs[1].feature = val;
130459f2a787SGerd Hoffmann break;
1305335ca2f2SJohn Snow case ATA_IOPORT_WR_SECTOR_COUNT:
130659f2a787SGerd Hoffmann ide_clear_hob(bus);
130759f2a787SGerd Hoffmann bus->ifs[0].hob_nsector = bus->ifs[0].nsector;
130859f2a787SGerd Hoffmann bus->ifs[1].hob_nsector = bus->ifs[1].nsector;
130959f2a787SGerd Hoffmann bus->ifs[0].nsector = val;
131059f2a787SGerd Hoffmann bus->ifs[1].nsector = val;
131159f2a787SGerd Hoffmann break;
1312335ca2f2SJohn Snow case ATA_IOPORT_WR_SECTOR_NUMBER:
131359f2a787SGerd Hoffmann ide_clear_hob(bus);
131459f2a787SGerd Hoffmann bus->ifs[0].hob_sector = bus->ifs[0].sector;
131559f2a787SGerd Hoffmann bus->ifs[1].hob_sector = bus->ifs[1].sector;
131659f2a787SGerd Hoffmann bus->ifs[0].sector = val;
131759f2a787SGerd Hoffmann bus->ifs[1].sector = val;
131859f2a787SGerd Hoffmann break;
1319335ca2f2SJohn Snow case ATA_IOPORT_WR_CYLINDER_LOW:
132059f2a787SGerd Hoffmann ide_clear_hob(bus);
132159f2a787SGerd Hoffmann bus->ifs[0].hob_lcyl = bus->ifs[0].lcyl;
132259f2a787SGerd Hoffmann bus->ifs[1].hob_lcyl = bus->ifs[1].lcyl;
132359f2a787SGerd Hoffmann bus->ifs[0].lcyl = val;
132459f2a787SGerd Hoffmann bus->ifs[1].lcyl = val;
132559f2a787SGerd Hoffmann break;
1326335ca2f2SJohn Snow case ATA_IOPORT_WR_CYLINDER_HIGH:
132759f2a787SGerd Hoffmann ide_clear_hob(bus);
132859f2a787SGerd Hoffmann bus->ifs[0].hob_hcyl = bus->ifs[0].hcyl;
132959f2a787SGerd Hoffmann bus->ifs[1].hob_hcyl = bus->ifs[1].hcyl;
133059f2a787SGerd Hoffmann bus->ifs[0].hcyl = val;
133159f2a787SGerd Hoffmann bus->ifs[1].hcyl = val;
133259f2a787SGerd Hoffmann break;
1333335ca2f2SJohn Snow case ATA_IOPORT_WR_DEVICE_HEAD:
1334be8c9423SJohn Snow ide_clear_hob(bus);
13350c7515e1SJohn Snow bus->ifs[0].select = val | (ATA_DEV_ALWAYS_ON);
13360c7515e1SJohn Snow bus->ifs[1].select = val | (ATA_DEV_ALWAYS_ON);
133759f2a787SGerd Hoffmann /* select drive */
13380c7515e1SJohn Snow bus->unit = (val & (ATA_DEV_SELECT)) ? 1 : 0;
133959f2a787SGerd Hoffmann break;
134059f2a787SGerd Hoffmann default:
1341335ca2f2SJohn Snow case ATA_IOPORT_WR_COMMAND:
1342be8c9423SJohn Snow ide_clear_hob(bus);
13436f52e69fSJohn Snow qemu_irq_lower(bus->irq);
1344783f4474SPhilippe Mathieu-Daudé ide_bus_exec_cmd(bus, val);
13457cff87ffSAlexander Graf break;
13467cff87ffSAlexander Graf }
13477cff87ffSAlexander Graf }
13487cff87ffSAlexander Graf
ide_reset(IDEState * s)13494590355bSJohn Snow static void ide_reset(IDEState *s)
13504590355bSJohn Snow {
13513eee2611SJohn Snow trace_ide_reset(s);
13524590355bSJohn Snow
13534590355bSJohn Snow if (s->pio_aiocb) {
13544590355bSJohn Snow blk_aio_cancel(s->pio_aiocb);
13554590355bSJohn Snow s->pio_aiocb = NULL;
13564590355bSJohn Snow }
13574590355bSJohn Snow
1358176e4961SLev Kujawski if (s->reset_reverts) {
1359176e4961SLev Kujawski s->reset_reverts = false;
1360176e4961SLev Kujawski s->heads = s->drive_heads;
1361176e4961SLev Kujawski s->sectors = s->drive_sectors;
1362176e4961SLev Kujawski }
13634590355bSJohn Snow if (s->drive_kind == IDE_CFATA)
13644590355bSJohn Snow s->mult_sectors = 0;
13654590355bSJohn Snow else
13664590355bSJohn Snow s->mult_sectors = MAX_MULT_SECTORS;
13674590355bSJohn Snow /* ide regs */
13684590355bSJohn Snow s->feature = 0;
13694590355bSJohn Snow s->error = 0;
13704590355bSJohn Snow s->nsector = 0;
13714590355bSJohn Snow s->sector = 0;
13724590355bSJohn Snow s->lcyl = 0;
13734590355bSJohn Snow s->hcyl = 0;
13744590355bSJohn Snow
13754590355bSJohn Snow /* lba48 */
13764590355bSJohn Snow s->hob_feature = 0;
13774590355bSJohn Snow s->hob_sector = 0;
13784590355bSJohn Snow s->hob_nsector = 0;
13794590355bSJohn Snow s->hob_lcyl = 0;
13804590355bSJohn Snow s->hob_hcyl = 0;
13814590355bSJohn Snow
13820c7515e1SJohn Snow s->select = (ATA_DEV_ALWAYS_ON);
13834590355bSJohn Snow s->status = READY_STAT | SEEK_STAT;
13844590355bSJohn Snow
13854590355bSJohn Snow s->lba48 = 0;
13864590355bSJohn Snow
13874590355bSJohn Snow /* ATAPI specific */
13884590355bSJohn Snow s->sense_key = 0;
13894590355bSJohn Snow s->asc = 0;
13904590355bSJohn Snow s->cdrom_changed = 0;
13914590355bSJohn Snow s->packet_transfer_size = 0;
13924590355bSJohn Snow s->elementary_transfer_size = 0;
13934590355bSJohn Snow s->io_buffer_index = 0;
13944590355bSJohn Snow s->cd_sector_size = 0;
13954590355bSJohn Snow s->atapi_dma = 0;
13964590355bSJohn Snow s->tray_locked = 0;
13974590355bSJohn Snow s->tray_open = 0;
13984590355bSJohn Snow /* ATA DMA state */
13994590355bSJohn Snow s->io_buffer_size = 0;
14004590355bSJohn Snow s->req_nb_sectors = 0;
14014590355bSJohn Snow
14024590355bSJohn Snow ide_set_signature(s);
14034590355bSJohn Snow /* init the transfer handler so that 0xffff is returned on data
14044590355bSJohn Snow accesses */
14054590355bSJohn Snow s->end_transfer_func = ide_dummy_transfer_stop;
14064590355bSJohn Snow ide_dummy_transfer_stop(s);
14074590355bSJohn Snow s->media_changed = 0;
14084590355bSJohn Snow }
14094590355bSJohn Snow
cmd_nop(IDEState * s,uint8_t cmd)1410b300337eSKevin Wolf static bool cmd_nop(IDEState *s, uint8_t cmd)
1411b300337eSKevin Wolf {
1412b300337eSKevin Wolf return true;
1413b300337eSKevin Wolf }
1414b300337eSKevin Wolf
cmd_device_reset(IDEState * s,uint8_t cmd)1415f34ae00dSJohn Snow static bool cmd_device_reset(IDEState *s, uint8_t cmd)
1416f34ae00dSJohn Snow {
1417f34ae00dSJohn Snow /* Halt PIO (in the DRQ phase), then DMA */
1418882941a5SPaolo Bonzini ide_transfer_halt(s);
1419f34ae00dSJohn Snow ide_cancel_dma_sync(s);
1420f34ae00dSJohn Snow
1421f34ae00dSJohn Snow /* Reset any PIO commands, reset signature, etc */
1422f34ae00dSJohn Snow ide_reset(s);
1423f34ae00dSJohn Snow
1424f34ae00dSJohn Snow /* RESET: ATA8-ACS3 7.10.4 "Normal Outputs";
1425f34ae00dSJohn Snow * ATA8-ACS3 Table 184 "Device Signatures for Normal Output" */
1426f34ae00dSJohn Snow s->status = 0x00;
1427f34ae00dSJohn Snow
1428f34ae00dSJohn Snow /* Do not overwrite status register */
1429f34ae00dSJohn Snow return false;
1430f34ae00dSJohn Snow }
1431f34ae00dSJohn Snow
cmd_data_set_management(IDEState * s,uint8_t cmd)14324286434cSKevin Wolf static bool cmd_data_set_management(IDEState *s, uint8_t cmd)
14334286434cSKevin Wolf {
14344286434cSKevin Wolf switch (s->feature) {
14354286434cSKevin Wolf case DSM_TRIM:
14364be74634SMarkus Armbruster if (s->blk) {
14374286434cSKevin Wolf ide_sector_start_dma(s, IDE_DMA_TRIM);
14384286434cSKevin Wolf return false;
14394286434cSKevin Wolf }
14404286434cSKevin Wolf break;
14414286434cSKevin Wolf }
14424286434cSKevin Wolf
14434286434cSKevin Wolf ide_abort_command(s);
14444286434cSKevin Wolf return true;
14454286434cSKevin Wolf }
14464286434cSKevin Wolf
cmd_identify(IDEState * s,uint8_t cmd)14471c66869aSKevin Wolf static bool cmd_identify(IDEState *s, uint8_t cmd)
14481c66869aSKevin Wolf {
14494be74634SMarkus Armbruster if (s->blk && s->drive_kind != IDE_CD) {
14501c66869aSKevin Wolf if (s->drive_kind != IDE_CFATA) {
14511c66869aSKevin Wolf ide_identify(s);
14521c66869aSKevin Wolf } else {
14531c66869aSKevin Wolf ide_cfata_identify(s);
14541c66869aSKevin Wolf }
14551c66869aSKevin Wolf s->status = READY_STAT | SEEK_STAT;
14561c66869aSKevin Wolf ide_transfer_start(s, s->io_buffer, 512, ide_transfer_stop);
14570cfe719dSPhilippe Mathieu-Daudé ide_bus_set_irq(s->bus);
14581c66869aSKevin Wolf return false;
14591c66869aSKevin Wolf } else {
14601c66869aSKevin Wolf if (s->drive_kind == IDE_CD) {
14611c66869aSKevin Wolf ide_set_signature(s);
14621c66869aSKevin Wolf }
14631c66869aSKevin Wolf ide_abort_command(s);
14641c66869aSKevin Wolf }
14651c66869aSKevin Wolf
14661c66869aSKevin Wolf return true;
14671c66869aSKevin Wolf }
14681c66869aSKevin Wolf
cmd_verify(IDEState * s,uint8_t cmd)1469413860cfSKevin Wolf static bool cmd_verify(IDEState *s, uint8_t cmd)
1470413860cfSKevin Wolf {
1471413860cfSKevin Wolf bool lba48 = (cmd == WIN_VERIFY_EXT);
1472413860cfSKevin Wolf
1473413860cfSKevin Wolf /* do sector number check ? */
1474413860cfSKevin Wolf ide_cmd_lba48_transform(s, lba48);
1475413860cfSKevin Wolf
1476413860cfSKevin Wolf return true;
1477413860cfSKevin Wolf }
1478413860cfSKevin Wolf
cmd_set_multiple_mode(IDEState * s,uint8_t cmd)1479adf3a2c4SKevin Wolf static bool cmd_set_multiple_mode(IDEState *s, uint8_t cmd)
1480adf3a2c4SKevin Wolf {
1481adf3a2c4SKevin Wolf if (s->drive_kind == IDE_CFATA && s->nsector == 0) {
1482adf3a2c4SKevin Wolf /* Disable Read and Write Multiple */
1483adf3a2c4SKevin Wolf s->mult_sectors = 0;
1484adf3a2c4SKevin Wolf } else if ((s->nsector & 0xff) != 0 &&
1485adf3a2c4SKevin Wolf ((s->nsector & 0xff) > MAX_MULT_SECTORS ||
1486adf3a2c4SKevin Wolf (s->nsector & (s->nsector - 1)) != 0)) {
1487adf3a2c4SKevin Wolf ide_abort_command(s);
1488adf3a2c4SKevin Wolf } else {
1489adf3a2c4SKevin Wolf s->mult_sectors = s->nsector & 0xff;
1490adf3a2c4SKevin Wolf }
1491adf3a2c4SKevin Wolf
1492adf3a2c4SKevin Wolf return true;
1493adf3a2c4SKevin Wolf }
1494adf3a2c4SKevin Wolf
cmd_read_multiple(IDEState * s,uint8_t cmd)1495adf3a2c4SKevin Wolf static bool cmd_read_multiple(IDEState *s, uint8_t cmd)
1496adf3a2c4SKevin Wolf {
1497adf3a2c4SKevin Wolf bool lba48 = (cmd == WIN_MULTREAD_EXT);
1498adf3a2c4SKevin Wolf
14994be74634SMarkus Armbruster if (!s->blk || !s->mult_sectors) {
1500adf3a2c4SKevin Wolf ide_abort_command(s);
1501adf3a2c4SKevin Wolf return true;
1502adf3a2c4SKevin Wolf }
1503adf3a2c4SKevin Wolf
1504adf3a2c4SKevin Wolf ide_cmd_lba48_transform(s, lba48);
1505adf3a2c4SKevin Wolf s->req_nb_sectors = s->mult_sectors;
1506adf3a2c4SKevin Wolf ide_sector_read(s);
1507adf3a2c4SKevin Wolf return false;
1508adf3a2c4SKevin Wolf }
1509adf3a2c4SKevin Wolf
cmd_write_multiple(IDEState * s,uint8_t cmd)1510adf3a2c4SKevin Wolf static bool cmd_write_multiple(IDEState *s, uint8_t cmd)
1511adf3a2c4SKevin Wolf {
1512adf3a2c4SKevin Wolf bool lba48 = (cmd == WIN_MULTWRITE_EXT);
1513adf3a2c4SKevin Wolf int n;
1514adf3a2c4SKevin Wolf
15154be74634SMarkus Armbruster if (!s->blk || !s->mult_sectors) {
1516adf3a2c4SKevin Wolf ide_abort_command(s);
1517adf3a2c4SKevin Wolf return true;
1518adf3a2c4SKevin Wolf }
1519adf3a2c4SKevin Wolf
1520adf3a2c4SKevin Wolf ide_cmd_lba48_transform(s, lba48);
1521adf3a2c4SKevin Wolf
1522adf3a2c4SKevin Wolf s->req_nb_sectors = s->mult_sectors;
1523adf3a2c4SKevin Wolf n = MIN(s->nsector, s->req_nb_sectors);
1524adf3a2c4SKevin Wolf
1525adf3a2c4SKevin Wolf s->status = SEEK_STAT | READY_STAT;
1526adf3a2c4SKevin Wolf ide_transfer_start(s, s->io_buffer, 512 * n, ide_sector_write);
1527adf3a2c4SKevin Wolf
1528adf3a2c4SKevin Wolf s->media_changed = 1;
1529adf3a2c4SKevin Wolf
1530adf3a2c4SKevin Wolf return false;
1531adf3a2c4SKevin Wolf }
1532adf3a2c4SKevin Wolf
cmd_read_pio(IDEState * s,uint8_t cmd)15330e6498edSKevin Wolf static bool cmd_read_pio(IDEState *s, uint8_t cmd)
15340e6498edSKevin Wolf {
15350e6498edSKevin Wolf bool lba48 = (cmd == WIN_READ_EXT);
15360e6498edSKevin Wolf
15370e6498edSKevin Wolf if (s->drive_kind == IDE_CD) {
15380e6498edSKevin Wolf ide_set_signature(s); /* odd, but ATA4 8.27.5.2 requires it */
15390e6498edSKevin Wolf ide_abort_command(s);
15400e6498edSKevin Wolf return true;
15410e6498edSKevin Wolf }
15420e6498edSKevin Wolf
15434be74634SMarkus Armbruster if (!s->blk) {
15440e6498edSKevin Wolf ide_abort_command(s);
15450e6498edSKevin Wolf return true;
15460e6498edSKevin Wolf }
15470e6498edSKevin Wolf
15480e6498edSKevin Wolf ide_cmd_lba48_transform(s, lba48);
15490e6498edSKevin Wolf s->req_nb_sectors = 1;
15500e6498edSKevin Wolf ide_sector_read(s);
15510e6498edSKevin Wolf
15520e6498edSKevin Wolf return false;
15530e6498edSKevin Wolf }
15540e6498edSKevin Wolf
cmd_write_pio(IDEState * s,uint8_t cmd)15550e6498edSKevin Wolf static bool cmd_write_pio(IDEState *s, uint8_t cmd)
15560e6498edSKevin Wolf {
15570e6498edSKevin Wolf bool lba48 = (cmd == WIN_WRITE_EXT);
15580e6498edSKevin Wolf
15594be74634SMarkus Armbruster if (!s->blk) {
15600e6498edSKevin Wolf ide_abort_command(s);
15610e6498edSKevin Wolf return true;
15620e6498edSKevin Wolf }
15630e6498edSKevin Wolf
15640e6498edSKevin Wolf ide_cmd_lba48_transform(s, lba48);
15650e6498edSKevin Wolf
15660e6498edSKevin Wolf s->req_nb_sectors = 1;
15670e6498edSKevin Wolf s->status = SEEK_STAT | READY_STAT;
15680e6498edSKevin Wolf ide_transfer_start(s, s->io_buffer, 512, ide_sector_write);
15690e6498edSKevin Wolf
15700e6498edSKevin Wolf s->media_changed = 1;
15710e6498edSKevin Wolf
15720e6498edSKevin Wolf return false;
15730e6498edSKevin Wolf }
15740e6498edSKevin Wolf
cmd_read_dma(IDEState * s,uint8_t cmd)157592a6a6f6SKevin Wolf static bool cmd_read_dma(IDEState *s, uint8_t cmd)
157692a6a6f6SKevin Wolf {
157792a6a6f6SKevin Wolf bool lba48 = (cmd == WIN_READDMA_EXT);
157892a6a6f6SKevin Wolf
15794be74634SMarkus Armbruster if (!s->blk) {
158092a6a6f6SKevin Wolf ide_abort_command(s);
158192a6a6f6SKevin Wolf return true;
158292a6a6f6SKevin Wolf }
158392a6a6f6SKevin Wolf
158492a6a6f6SKevin Wolf ide_cmd_lba48_transform(s, lba48);
158592a6a6f6SKevin Wolf ide_sector_start_dma(s, IDE_DMA_READ);
158692a6a6f6SKevin Wolf
158792a6a6f6SKevin Wolf return false;
158892a6a6f6SKevin Wolf }
158992a6a6f6SKevin Wolf
cmd_write_dma(IDEState * s,uint8_t cmd)159092a6a6f6SKevin Wolf static bool cmd_write_dma(IDEState *s, uint8_t cmd)
159192a6a6f6SKevin Wolf {
159292a6a6f6SKevin Wolf bool lba48 = (cmd == WIN_WRITEDMA_EXT);
159392a6a6f6SKevin Wolf
15944be74634SMarkus Armbruster if (!s->blk) {
159592a6a6f6SKevin Wolf ide_abort_command(s);
159692a6a6f6SKevin Wolf return true;
159792a6a6f6SKevin Wolf }
159892a6a6f6SKevin Wolf
159992a6a6f6SKevin Wolf ide_cmd_lba48_transform(s, lba48);
160092a6a6f6SKevin Wolf ide_sector_start_dma(s, IDE_DMA_WRITE);
160192a6a6f6SKevin Wolf
160292a6a6f6SKevin Wolf s->media_changed = 1;
160392a6a6f6SKevin Wolf
160492a6a6f6SKevin Wolf return false;
160592a6a6f6SKevin Wolf }
160692a6a6f6SKevin Wolf
cmd_flush_cache(IDEState * s,uint8_t cmd)16079afce429SKevin Wolf static bool cmd_flush_cache(IDEState *s, uint8_t cmd)
16089afce429SKevin Wolf {
16099afce429SKevin Wolf ide_flush_cache(s);
16109afce429SKevin Wolf return false;
16119afce429SKevin Wolf }
16129afce429SKevin Wolf
cmd_seek(IDEState * s,uint8_t cmd)161361fdda37SKevin Wolf static bool cmd_seek(IDEState *s, uint8_t cmd)
161461fdda37SKevin Wolf {
161561fdda37SKevin Wolf /* XXX: Check that seek is within bounds */
161661fdda37SKevin Wolf return true;
161761fdda37SKevin Wolf }
161861fdda37SKevin Wolf
cmd_read_native_max(IDEState * s,uint8_t cmd)161963a82e6aSKevin Wolf static bool cmd_read_native_max(IDEState *s, uint8_t cmd)
162063a82e6aSKevin Wolf {
162163a82e6aSKevin Wolf bool lba48 = (cmd == WIN_READ_NATIVE_MAX_EXT);
162263a82e6aSKevin Wolf
162363a82e6aSKevin Wolf /* Refuse if no sectors are addressable (e.g. medium not inserted) */
162463a82e6aSKevin Wolf if (s->nb_sectors == 0) {
162563a82e6aSKevin Wolf ide_abort_command(s);
1626*8682ff69SLev Kujawski } else {
1627*8682ff69SLev Kujawski /*
1628*8682ff69SLev Kujawski * Save the active drive parameters, which may have been
1629*8682ff69SLev Kujawski * limited from their native counterparts by, e.g., INITIALIZE
1630*8682ff69SLev Kujawski * DEVICE PARAMETERS or SET MAX ADDRESS.
1631*8682ff69SLev Kujawski */
1632*8682ff69SLev Kujawski const int aheads = s->heads;
1633*8682ff69SLev Kujawski const int asectors = s->sectors;
1634*8682ff69SLev Kujawski
1635*8682ff69SLev Kujawski s->heads = s->drive_heads;
1636*8682ff69SLev Kujawski s->sectors = s->drive_sectors;
163763a82e6aSKevin Wolf
163863a82e6aSKevin Wolf ide_cmd_lba48_transform(s, lba48);
163963a82e6aSKevin Wolf ide_set_sector(s, s->nb_sectors - 1);
164063a82e6aSKevin Wolf
1641*8682ff69SLev Kujawski s->heads = aheads;
1642*8682ff69SLev Kujawski s->sectors = asectors;
1643*8682ff69SLev Kujawski }
1644*8682ff69SLev Kujawski
164563a82e6aSKevin Wolf return true;
164663a82e6aSKevin Wolf }
164763a82e6aSKevin Wolf
cmd_check_power_mode(IDEState * s,uint8_t cmd)1648785f6320SKevin Wolf static bool cmd_check_power_mode(IDEState *s, uint8_t cmd)
1649785f6320SKevin Wolf {
1650785f6320SKevin Wolf s->nsector = 0xff; /* device active or idle */
1651785f6320SKevin Wolf return true;
1652785f6320SKevin Wolf }
1653785f6320SKevin Wolf
1654176e4961SLev Kujawski /* INITIALIZE DEVICE PARAMETERS */
cmd_specify(IDEState * s,uint8_t cmd)1655176e4961SLev Kujawski static bool cmd_specify(IDEState *s, uint8_t cmd)
1656176e4961SLev Kujawski {
1657176e4961SLev Kujawski if (s->blk && s->drive_kind != IDE_CD) {
1658176e4961SLev Kujawski s->heads = (s->select & (ATA_DEV_HS)) + 1;
1659176e4961SLev Kujawski s->sectors = s->nsector;
16600cfe719dSPhilippe Mathieu-Daudé ide_bus_set_irq(s->bus);
1661176e4961SLev Kujawski } else {
1662176e4961SLev Kujawski ide_abort_command(s);
1663176e4961SLev Kujawski }
1664176e4961SLev Kujawski
1665176e4961SLev Kujawski return true;
1666176e4961SLev Kujawski }
1667176e4961SLev Kujawski
cmd_set_features(IDEState * s,uint8_t cmd)1668ee03398cSKevin Wolf static bool cmd_set_features(IDEState *s, uint8_t cmd)
1669ee03398cSKevin Wolf {
1670ee03398cSKevin Wolf uint16_t *identify_data;
1671ee03398cSKevin Wolf
16724be74634SMarkus Armbruster if (!s->blk) {
1673ee03398cSKevin Wolf ide_abort_command(s);
1674ee03398cSKevin Wolf return true;
1675ee03398cSKevin Wolf }
1676ee03398cSKevin Wolf
1677ee03398cSKevin Wolf /* XXX: valid for CDROM ? */
1678ee03398cSKevin Wolf switch (s->feature) {
16791ea17d22SLubomir Rintel case 0x01: /* 8-bit I/O enable (CompactFlash) */
16801ea17d22SLubomir Rintel case 0x81: /* 8-bit I/O disable (CompactFlash) */
16811ea17d22SLubomir Rintel if (s->drive_kind != IDE_CFATA) {
16821ea17d22SLubomir Rintel goto abort_cmd;
16831ea17d22SLubomir Rintel }
16841ea17d22SLubomir Rintel s->io8 = !(s->feature & 0x80);
16851ea17d22SLubomir Rintel return true;
1686ee03398cSKevin Wolf case 0x02: /* write cache enable */
16874be74634SMarkus Armbruster blk_set_enable_write_cache(s->blk, true);
1688ee03398cSKevin Wolf identify_data = (uint16_t *)s->identify_data;
1689ee03398cSKevin Wolf put_le16(identify_data + 85, (1 << 14) | (1 << 5) | 1);
1690ee03398cSKevin Wolf return true;
1691ee03398cSKevin Wolf case 0x82: /* write cache disable */
16924be74634SMarkus Armbruster blk_set_enable_write_cache(s->blk, false);
1693ee03398cSKevin Wolf identify_data = (uint16_t *)s->identify_data;
1694ee03398cSKevin Wolf put_le16(identify_data + 85, (1 << 14) | 1);
1695ee03398cSKevin Wolf ide_flush_cache(s);
1696ee03398cSKevin Wolf return false;
1697ee03398cSKevin Wolf case 0xcc: /* reverting to power-on defaults enable */
1698176e4961SLev Kujawski s->reset_reverts = true;
1699176e4961SLev Kujawski return true;
1700ee03398cSKevin Wolf case 0x66: /* reverting to power-on defaults disable */
1701176e4961SLev Kujawski s->reset_reverts = false;
1702176e4961SLev Kujawski return true;
1703ee03398cSKevin Wolf case 0xaa: /* read look-ahead enable */
1704ee03398cSKevin Wolf case 0x55: /* read look-ahead disable */
1705ee03398cSKevin Wolf case 0x05: /* set advanced power management mode */
1706ee03398cSKevin Wolf case 0x85: /* disable advanced power management mode */
1707ee03398cSKevin Wolf case 0x69: /* NOP */
1708ee03398cSKevin Wolf case 0x67: /* NOP */
1709ee03398cSKevin Wolf case 0x96: /* NOP */
1710ee03398cSKevin Wolf case 0x9a: /* NOP */
1711ee03398cSKevin Wolf case 0x42: /* enable Automatic Acoustic Mode */
1712ee03398cSKevin Wolf case 0xc2: /* disable Automatic Acoustic Mode */
1713ee03398cSKevin Wolf return true;
1714ee03398cSKevin Wolf case 0x03: /* set transfer mode */
1715ee03398cSKevin Wolf {
1716ee03398cSKevin Wolf uint8_t val = s->nsector & 0x07;
1717ee03398cSKevin Wolf identify_data = (uint16_t *)s->identify_data;
1718ee03398cSKevin Wolf
1719ee03398cSKevin Wolf switch (s->nsector >> 3) {
1720ee03398cSKevin Wolf case 0x00: /* pio default */
1721ee03398cSKevin Wolf case 0x01: /* pio mode */
1722ee03398cSKevin Wolf put_le16(identify_data + 62, 0x07);
1723ee03398cSKevin Wolf put_le16(identify_data + 63, 0x07);
1724ee03398cSKevin Wolf put_le16(identify_data + 88, 0x3f);
1725ee03398cSKevin Wolf break;
1726a980b95cSMichael Tokarev case 0x02: /* single word dma mode */
1727ee03398cSKevin Wolf put_le16(identify_data + 62, 0x07 | (1 << (val + 8)));
1728ee03398cSKevin Wolf put_le16(identify_data + 63, 0x07);
1729ee03398cSKevin Wolf put_le16(identify_data + 88, 0x3f);
1730ee03398cSKevin Wolf break;
1731ee03398cSKevin Wolf case 0x04: /* mdma mode */
1732ee03398cSKevin Wolf put_le16(identify_data + 62, 0x07);
1733ee03398cSKevin Wolf put_le16(identify_data + 63, 0x07 | (1 << (val + 8)));
1734ee03398cSKevin Wolf put_le16(identify_data + 88, 0x3f);
1735ee03398cSKevin Wolf break;
1736ee03398cSKevin Wolf case 0x08: /* udma mode */
1737ee03398cSKevin Wolf put_le16(identify_data + 62, 0x07);
1738ee03398cSKevin Wolf put_le16(identify_data + 63, 0x07);
1739ee03398cSKevin Wolf put_le16(identify_data + 88, 0x3f | (1 << (val + 8)));
1740ee03398cSKevin Wolf break;
1741ee03398cSKevin Wolf default:
1742ee03398cSKevin Wolf goto abort_cmd;
1743ee03398cSKevin Wolf }
1744ee03398cSKevin Wolf return true;
1745ee03398cSKevin Wolf }
1746ee03398cSKevin Wolf }
1747ee03398cSKevin Wolf
1748ee03398cSKevin Wolf abort_cmd:
1749ee03398cSKevin Wolf ide_abort_command(s);
1750ee03398cSKevin Wolf return true;
1751ee03398cSKevin Wolf }
1752ee03398cSKevin Wolf
1753ee425c78SKevin Wolf
1754ee425c78SKevin Wolf /*** ATAPI commands ***/
1755ee425c78SKevin Wolf
cmd_identify_packet(IDEState * s,uint8_t cmd)1756ee425c78SKevin Wolf static bool cmd_identify_packet(IDEState *s, uint8_t cmd)
1757ee425c78SKevin Wolf {
1758ee425c78SKevin Wolf ide_atapi_identify(s);
1759ee425c78SKevin Wolf s->status = READY_STAT | SEEK_STAT;
1760ee425c78SKevin Wolf ide_transfer_start(s, s->io_buffer, 512, ide_transfer_stop);
17610cfe719dSPhilippe Mathieu-Daudé ide_bus_set_irq(s->bus);
1762ee425c78SKevin Wolf return false;
1763ee425c78SKevin Wolf }
1764ee425c78SKevin Wolf
17653195c9e6SLev Kujawski /* EXECUTE DEVICE DIAGNOSTIC */
cmd_exec_dev_diagnostic(IDEState * s,uint8_t cmd)1766ee425c78SKevin Wolf static bool cmd_exec_dev_diagnostic(IDEState *s, uint8_t cmd)
1767ee425c78SKevin Wolf {
17683195c9e6SLev Kujawski /*
17693195c9e6SLev Kujawski * Clear the device register per the ATA (v6) specification,
17703195c9e6SLev Kujawski * because ide_set_signature does not clear LBA or drive bits.
17713195c9e6SLev Kujawski */
17723195c9e6SLev Kujawski s->select = (ATA_DEV_ALWAYS_ON);
1773ee425c78SKevin Wolf ide_set_signature(s);
1774ee425c78SKevin Wolf
1775ee425c78SKevin Wolf if (s->drive_kind == IDE_CD) {
1776ee425c78SKevin Wolf s->status = 0; /* ATAPI spec (v6) section 9.10 defines packet
1777ee425c78SKevin Wolf * devices to return a clear status register
1778ee425c78SKevin Wolf * with READY_STAT *not* set. */
1779850484a2SDavid du Colombier s->error = 0x01;
1780ee425c78SKevin Wolf } else {
1781ee425c78SKevin Wolf s->status = READY_STAT | SEEK_STAT;
1782ee425c78SKevin Wolf /* The bits of the error register are not as usual for this command!
1783ee425c78SKevin Wolf * They are part of the regular output (this is why ERR_STAT isn't set)
1784ee425c78SKevin Wolf * Device 0 passed, Device 1 passed or not present. */
1785ee425c78SKevin Wolf s->error = 0x01;
17860cfe719dSPhilippe Mathieu-Daudé ide_bus_set_irq(s->bus);
1787ee425c78SKevin Wolf }
1788ee425c78SKevin Wolf
1789ee425c78SKevin Wolf return false;
1790ee425c78SKevin Wolf }
1791ee425c78SKevin Wolf
cmd_packet(IDEState * s,uint8_t cmd)1792ee425c78SKevin Wolf static bool cmd_packet(IDEState *s, uint8_t cmd)
1793ee425c78SKevin Wolf {
1794ee425c78SKevin Wolf /* overlapping commands not supported */
1795ee425c78SKevin Wolf if (s->feature & 0x02) {
1796ee425c78SKevin Wolf ide_abort_command(s);
1797ee425c78SKevin Wolf return true;
1798ee425c78SKevin Wolf }
1799ee425c78SKevin Wolf
1800ee425c78SKevin Wolf s->status = READY_STAT | SEEK_STAT;
1801ee425c78SKevin Wolf s->atapi_dma = s->feature & 1;
1802502356eeSPavel Butsykin if (s->atapi_dma) {
1803502356eeSPavel Butsykin s->dma_cmd = IDE_DMA_ATAPI;
1804502356eeSPavel Butsykin }
1805ee425c78SKevin Wolf s->nsector = 1;
1806ee425c78SKevin Wolf ide_transfer_start(s, s->io_buffer, ATAPI_PACKET_SIZE,
1807ee425c78SKevin Wolf ide_atapi_cmd);
1808ee425c78SKevin Wolf return false;
1809ee425c78SKevin Wolf }
1810ee425c78SKevin Wolf
18116b1dd744SKevin Wolf
18126b1dd744SKevin Wolf /*** CF-ATA commands ***/
18136b1dd744SKevin Wolf
cmd_cfa_req_ext_error_code(IDEState * s,uint8_t cmd)18146b1dd744SKevin Wolf static bool cmd_cfa_req_ext_error_code(IDEState *s, uint8_t cmd)
18156b1dd744SKevin Wolf {
18166b1dd744SKevin Wolf s->error = 0x09; /* miscellaneous error */
18176b1dd744SKevin Wolf s->status = READY_STAT | SEEK_STAT;
18180cfe719dSPhilippe Mathieu-Daudé ide_bus_set_irq(s->bus);
18196b1dd744SKevin Wolf
18206b1dd744SKevin Wolf return false;
18216b1dd744SKevin Wolf }
18226b1dd744SKevin Wolf
cmd_cfa_erase_sectors(IDEState * s,uint8_t cmd)18236b1dd744SKevin Wolf static bool cmd_cfa_erase_sectors(IDEState *s, uint8_t cmd)
18246b1dd744SKevin Wolf {
18256b1dd744SKevin Wolf /* WIN_SECURITY_FREEZE_LOCK has the same ID as CFA_WEAR_LEVEL and is
18266b1dd744SKevin Wolf * required for Windows 8 to work with AHCI */
18276b1dd744SKevin Wolf
18286b1dd744SKevin Wolf if (cmd == CFA_WEAR_LEVEL) {
18296b1dd744SKevin Wolf s->nsector = 0;
18306b1dd744SKevin Wolf }
18316b1dd744SKevin Wolf
18326b1dd744SKevin Wolf if (cmd == CFA_ERASE_SECTORS) {
18336b1dd744SKevin Wolf s->media_changed = 1;
18346b1dd744SKevin Wolf }
18356b1dd744SKevin Wolf
18366b1dd744SKevin Wolf return true;
18376b1dd744SKevin Wolf }
18386b1dd744SKevin Wolf
cmd_cfa_translate_sector(IDEState * s,uint8_t cmd)18396b1dd744SKevin Wolf static bool cmd_cfa_translate_sector(IDEState *s, uint8_t cmd)
18406b1dd744SKevin Wolf {
18416b1dd744SKevin Wolf s->status = READY_STAT | SEEK_STAT;
18426b1dd744SKevin Wolf
18436b1dd744SKevin Wolf memset(s->io_buffer, 0, 0x200);
18446b1dd744SKevin Wolf s->io_buffer[0x00] = s->hcyl; /* Cyl MSB */
18456b1dd744SKevin Wolf s->io_buffer[0x01] = s->lcyl; /* Cyl LSB */
18466b1dd744SKevin Wolf s->io_buffer[0x02] = s->select; /* Head */
18476b1dd744SKevin Wolf s->io_buffer[0x03] = s->sector; /* Sector */
18486b1dd744SKevin Wolf s->io_buffer[0x04] = ide_get_sector(s) >> 16; /* LBA MSB */
18496b1dd744SKevin Wolf s->io_buffer[0x05] = ide_get_sector(s) >> 8; /* LBA */
18506b1dd744SKevin Wolf s->io_buffer[0x06] = ide_get_sector(s) >> 0; /* LBA LSB */
18516b1dd744SKevin Wolf s->io_buffer[0x13] = 0x00; /* Erase flag */
18526b1dd744SKevin Wolf s->io_buffer[0x18] = 0x00; /* Hot count */
18536b1dd744SKevin Wolf s->io_buffer[0x19] = 0x00; /* Hot count */
18546b1dd744SKevin Wolf s->io_buffer[0x1a] = 0x01; /* Hot count */
18556b1dd744SKevin Wolf
18566b1dd744SKevin Wolf ide_transfer_start(s, s->io_buffer, 0x200, ide_transfer_stop);
18570cfe719dSPhilippe Mathieu-Daudé ide_bus_set_irq(s->bus);
18586b1dd744SKevin Wolf
18596b1dd744SKevin Wolf return false;
18606b1dd744SKevin Wolf }
18616b1dd744SKevin Wolf
cmd_cfa_access_metadata_storage(IDEState * s,uint8_t cmd)18626b1dd744SKevin Wolf static bool cmd_cfa_access_metadata_storage(IDEState *s, uint8_t cmd)
18636b1dd744SKevin Wolf {
18646b1dd744SKevin Wolf switch (s->feature) {
18656b1dd744SKevin Wolf case 0x02: /* Inquiry Metadata Storage */
18666b1dd744SKevin Wolf ide_cfata_metadata_inquiry(s);
18676b1dd744SKevin Wolf break;
18686b1dd744SKevin Wolf case 0x03: /* Read Metadata Storage */
18696b1dd744SKevin Wolf ide_cfata_metadata_read(s);
18706b1dd744SKevin Wolf break;
18716b1dd744SKevin Wolf case 0x04: /* Write Metadata Storage */
18726b1dd744SKevin Wolf ide_cfata_metadata_write(s);
18736b1dd744SKevin Wolf break;
18746b1dd744SKevin Wolf default:
18756b1dd744SKevin Wolf ide_abort_command(s);
18766b1dd744SKevin Wolf return true;
18776b1dd744SKevin Wolf }
18786b1dd744SKevin Wolf
18796b1dd744SKevin Wolf ide_transfer_start(s, s->io_buffer, 0x200, ide_transfer_stop);
18806b1dd744SKevin Wolf s->status = 0x00; /* NOTE: READY is _not_ set */
18810cfe719dSPhilippe Mathieu-Daudé ide_bus_set_irq(s->bus);
18826b1dd744SKevin Wolf
18836b1dd744SKevin Wolf return false;
18846b1dd744SKevin Wolf }
18856b1dd744SKevin Wolf
cmd_ibm_sense_condition(IDEState * s,uint8_t cmd)18866b1dd744SKevin Wolf static bool cmd_ibm_sense_condition(IDEState *s, uint8_t cmd)
18876b1dd744SKevin Wolf {
18886b1dd744SKevin Wolf switch (s->feature) {
18896b1dd744SKevin Wolf case 0x01: /* sense temperature in device */
18906b1dd744SKevin Wolf s->nsector = 0x50; /* +20 C */
18916b1dd744SKevin Wolf break;
18926b1dd744SKevin Wolf default:
18936b1dd744SKevin Wolf ide_abort_command(s);
18946b1dd744SKevin Wolf return true;
18956b1dd744SKevin Wolf }
18966b1dd744SKevin Wolf
18976b1dd744SKevin Wolf return true;
18986b1dd744SKevin Wolf }
18996b1dd744SKevin Wolf
1900ff352677SKevin Wolf
1901ff352677SKevin Wolf /*** SMART commands ***/
1902ff352677SKevin Wolf
cmd_smart(IDEState * s,uint8_t cmd)1903ff352677SKevin Wolf static bool cmd_smart(IDEState *s, uint8_t cmd)
1904ff352677SKevin Wolf {
1905ff352677SKevin Wolf int n;
1906ff352677SKevin Wolf
1907ff352677SKevin Wolf if (s->hcyl != 0xc2 || s->lcyl != 0x4f) {
1908ff352677SKevin Wolf goto abort_cmd;
1909ff352677SKevin Wolf }
1910ff352677SKevin Wolf
1911ff352677SKevin Wolf if (!s->smart_enabled && s->feature != SMART_ENABLE) {
1912ff352677SKevin Wolf goto abort_cmd;
1913ff352677SKevin Wolf }
1914ff352677SKevin Wolf
1915ff352677SKevin Wolf switch (s->feature) {
1916ff352677SKevin Wolf case SMART_DISABLE:
1917ff352677SKevin Wolf s->smart_enabled = 0;
1918ff352677SKevin Wolf return true;
1919ff352677SKevin Wolf
1920ff352677SKevin Wolf case SMART_ENABLE:
1921ff352677SKevin Wolf s->smart_enabled = 1;
1922ff352677SKevin Wolf return true;
1923ff352677SKevin Wolf
1924ff352677SKevin Wolf case SMART_ATTR_AUTOSAVE:
1925ff352677SKevin Wolf switch (s->sector) {
1926ff352677SKevin Wolf case 0x00:
1927ff352677SKevin Wolf s->smart_autosave = 0;
1928ff352677SKevin Wolf break;
1929ff352677SKevin Wolf case 0xf1:
1930ff352677SKevin Wolf s->smart_autosave = 1;
1931ff352677SKevin Wolf break;
1932ff352677SKevin Wolf default:
1933ff352677SKevin Wolf goto abort_cmd;
1934ff352677SKevin Wolf }
1935ff352677SKevin Wolf return true;
1936ff352677SKevin Wolf
1937ff352677SKevin Wolf case SMART_STATUS:
1938ff352677SKevin Wolf if (!s->smart_errors) {
1939ff352677SKevin Wolf s->hcyl = 0xc2;
1940ff352677SKevin Wolf s->lcyl = 0x4f;
1941ff352677SKevin Wolf } else {
1942ff352677SKevin Wolf s->hcyl = 0x2c;
1943ff352677SKevin Wolf s->lcyl = 0xf4;
1944ff352677SKevin Wolf }
1945ff352677SKevin Wolf return true;
1946ff352677SKevin Wolf
1947ff352677SKevin Wolf case SMART_READ_THRESH:
1948ff352677SKevin Wolf memset(s->io_buffer, 0, 0x200);
1949ff352677SKevin Wolf s->io_buffer[0] = 0x01; /* smart struct version */
1950ff352677SKevin Wolf
1951ff352677SKevin Wolf for (n = 0; n < ARRAY_SIZE(smart_attributes); n++) {
1952ff352677SKevin Wolf s->io_buffer[2 + 0 + (n * 12)] = smart_attributes[n][0];
1953ff352677SKevin Wolf s->io_buffer[2 + 1 + (n * 12)] = smart_attributes[n][11];
1954ff352677SKevin Wolf }
1955ff352677SKevin Wolf
1956ff352677SKevin Wolf /* checksum */
1957ff352677SKevin Wolf for (n = 0; n < 511; n++) {
1958ff352677SKevin Wolf s->io_buffer[511] += s->io_buffer[n];
1959ff352677SKevin Wolf }
1960ff352677SKevin Wolf s->io_buffer[511] = 0x100 - s->io_buffer[511];
1961ff352677SKevin Wolf
1962ff352677SKevin Wolf s->status = READY_STAT | SEEK_STAT;
1963ff352677SKevin Wolf ide_transfer_start(s, s->io_buffer, 0x200, ide_transfer_stop);
19640cfe719dSPhilippe Mathieu-Daudé ide_bus_set_irq(s->bus);
1965ff352677SKevin Wolf return false;
1966ff352677SKevin Wolf
1967ff352677SKevin Wolf case SMART_READ_DATA:
1968ff352677SKevin Wolf memset(s->io_buffer, 0, 0x200);
1969ff352677SKevin Wolf s->io_buffer[0] = 0x01; /* smart struct version */
1970ff352677SKevin Wolf
1971ff352677SKevin Wolf for (n = 0; n < ARRAY_SIZE(smart_attributes); n++) {
1972ff352677SKevin Wolf int i;
1973ff352677SKevin Wolf for (i = 0; i < 11; i++) {
1974ff352677SKevin Wolf s->io_buffer[2 + i + (n * 12)] = smart_attributes[n][i];
1975ff352677SKevin Wolf }
1976ff352677SKevin Wolf }
1977ff352677SKevin Wolf
1978ff352677SKevin Wolf s->io_buffer[362] = 0x02 | (s->smart_autosave ? 0x80 : 0x00);
1979ff352677SKevin Wolf if (s->smart_selftest_count == 0) {
1980ff352677SKevin Wolf s->io_buffer[363] = 0;
1981ff352677SKevin Wolf } else {
1982ff352677SKevin Wolf s->io_buffer[363] =
1983ff352677SKevin Wolf s->smart_selftest_data[3 +
1984ff352677SKevin Wolf (s->smart_selftest_count - 1) *
1985ff352677SKevin Wolf 24];
1986ff352677SKevin Wolf }
1987ff352677SKevin Wolf s->io_buffer[364] = 0x20;
1988ff352677SKevin Wolf s->io_buffer[365] = 0x01;
1989ff352677SKevin Wolf /* offline data collection capacity: execute + self-test*/
1990ff352677SKevin Wolf s->io_buffer[367] = (1 << 4 | 1 << 3 | 1);
1991ff352677SKevin Wolf s->io_buffer[368] = 0x03; /* smart capability (1) */
1992ff352677SKevin Wolf s->io_buffer[369] = 0x00; /* smart capability (2) */
1993ff352677SKevin Wolf s->io_buffer[370] = 0x01; /* error logging supported */
1994ff352677SKevin Wolf s->io_buffer[372] = 0x02; /* minutes for poll short test */
1995ff352677SKevin Wolf s->io_buffer[373] = 0x36; /* minutes for poll ext test */
1996ff352677SKevin Wolf s->io_buffer[374] = 0x01; /* minutes for poll conveyance */
1997ff352677SKevin Wolf
1998ff352677SKevin Wolf for (n = 0; n < 511; n++) {
1999ff352677SKevin Wolf s->io_buffer[511] += s->io_buffer[n];
2000ff352677SKevin Wolf }
2001ff352677SKevin Wolf s->io_buffer[511] = 0x100 - s->io_buffer[511];
2002ff352677SKevin Wolf
2003ff352677SKevin Wolf s->status = READY_STAT | SEEK_STAT;
2004ff352677SKevin Wolf ide_transfer_start(s, s->io_buffer, 0x200, ide_transfer_stop);
20050cfe719dSPhilippe Mathieu-Daudé ide_bus_set_irq(s->bus);
2006ff352677SKevin Wolf return false;
2007ff352677SKevin Wolf
2008ff352677SKevin Wolf case SMART_READ_LOG:
2009ff352677SKevin Wolf switch (s->sector) {
2010ff352677SKevin Wolf case 0x01: /* summary smart error log */
2011ff352677SKevin Wolf memset(s->io_buffer, 0, 0x200);
2012ff352677SKevin Wolf s->io_buffer[0] = 0x01;
2013ff352677SKevin Wolf s->io_buffer[1] = 0x00; /* no error entries */
2014ff352677SKevin Wolf s->io_buffer[452] = s->smart_errors & 0xff;
2015ff352677SKevin Wolf s->io_buffer[453] = (s->smart_errors & 0xff00) >> 8;
2016ff352677SKevin Wolf
2017ff352677SKevin Wolf for (n = 0; n < 511; n++) {
2018ff352677SKevin Wolf s->io_buffer[511] += s->io_buffer[n];
2019ff352677SKevin Wolf }
2020ff352677SKevin Wolf s->io_buffer[511] = 0x100 - s->io_buffer[511];
2021ff352677SKevin Wolf break;
2022ff352677SKevin Wolf case 0x06: /* smart self test log */
2023ff352677SKevin Wolf memset(s->io_buffer, 0, 0x200);
2024ff352677SKevin Wolf s->io_buffer[0] = 0x01;
2025ff352677SKevin Wolf if (s->smart_selftest_count == 0) {
2026ff352677SKevin Wolf s->io_buffer[508] = 0;
2027ff352677SKevin Wolf } else {
2028ff352677SKevin Wolf s->io_buffer[508] = s->smart_selftest_count;
2029ff352677SKevin Wolf for (n = 2; n < 506; n++) {
2030ff352677SKevin Wolf s->io_buffer[n] = s->smart_selftest_data[n];
2031ff352677SKevin Wolf }
2032ff352677SKevin Wolf }
2033ff352677SKevin Wolf
2034ff352677SKevin Wolf for (n = 0; n < 511; n++) {
2035ff352677SKevin Wolf s->io_buffer[511] += s->io_buffer[n];
2036ff352677SKevin Wolf }
2037ff352677SKevin Wolf s->io_buffer[511] = 0x100 - s->io_buffer[511];
2038ff352677SKevin Wolf break;
2039ff352677SKevin Wolf default:
2040ff352677SKevin Wolf goto abort_cmd;
2041ff352677SKevin Wolf }
2042ff352677SKevin Wolf s->status = READY_STAT | SEEK_STAT;
2043ff352677SKevin Wolf ide_transfer_start(s, s->io_buffer, 0x200, ide_transfer_stop);
20440cfe719dSPhilippe Mathieu-Daudé ide_bus_set_irq(s->bus);
2045ff352677SKevin Wolf return false;
2046ff352677SKevin Wolf
2047ff352677SKevin Wolf case SMART_EXECUTE_OFFLINE:
2048ff352677SKevin Wolf switch (s->sector) {
2049ff352677SKevin Wolf case 0: /* off-line routine */
2050ff352677SKevin Wolf case 1: /* short self test */
2051ff352677SKevin Wolf case 2: /* extended self test */
2052ff352677SKevin Wolf s->smart_selftest_count++;
2053ff352677SKevin Wolf if (s->smart_selftest_count > 21) {
2054940973aeSBenoît Canet s->smart_selftest_count = 1;
2055ff352677SKevin Wolf }
2056ff352677SKevin Wolf n = 2 + (s->smart_selftest_count - 1) * 24;
2057ff352677SKevin Wolf s->smart_selftest_data[n] = s->sector;
2058ff352677SKevin Wolf s->smart_selftest_data[n + 1] = 0x00; /* OK and finished */
2059ff352677SKevin Wolf s->smart_selftest_data[n + 2] = 0x34; /* hour count lsb */
2060ff352677SKevin Wolf s->smart_selftest_data[n + 3] = 0x12; /* hour count msb */
2061ff352677SKevin Wolf break;
2062ff352677SKevin Wolf default:
2063ff352677SKevin Wolf goto abort_cmd;
2064ff352677SKevin Wolf }
2065ff352677SKevin Wolf return true;
2066ff352677SKevin Wolf }
2067ff352677SKevin Wolf
2068ff352677SKevin Wolf abort_cmd:
2069ff352677SKevin Wolf ide_abort_command(s);
2070ff352677SKevin Wolf return true;
2071ff352677SKevin Wolf }
2072ff352677SKevin Wolf
2073844505b1SMarkus Armbruster #define HD_OK (1u << IDE_HD)
2074844505b1SMarkus Armbruster #define CD_OK (1u << IDE_CD)
2075844505b1SMarkus Armbruster #define CFA_OK (1u << IDE_CFATA)
2076844505b1SMarkus Armbruster #define HD_CFA_OK (HD_OK | CFA_OK)
2077844505b1SMarkus Armbruster #define ALL_OK (HD_OK | CD_OK | CFA_OK)
2078844505b1SMarkus Armbruster
2079a0436e92SKevin Wolf /* Set the Disk Seek Completed status bit during completion */
2080a0436e92SKevin Wolf #define SET_DSC (1u << 8)
2081a0436e92SKevin Wolf
2082844505b1SMarkus Armbruster /* See ACS-2 T13/2015-D Table B.2 Command codes */
2083a0436e92SKevin Wolf static const struct {
2084a0436e92SKevin Wolf /* Returns true if the completion code should be run */
2085a0436e92SKevin Wolf bool (*handler)(IDEState *s, uint8_t cmd);
2086a0436e92SKevin Wolf int flags;
2087a0436e92SKevin Wolf } ide_cmd_table[0x100] = {
2088844505b1SMarkus Armbruster /* NOP not implemented, mandatory for CD */
20896b1dd744SKevin Wolf [CFA_REQ_EXT_ERROR_CODE] = { cmd_cfa_req_ext_error_code, CFA_OK },
2090d9033e1dSJohn Snow [WIN_DSM] = { cmd_data_set_management, HD_CFA_OK },
2091ee425c78SKevin Wolf [WIN_DEVICE_RESET] = { cmd_device_reset, CD_OK },
2092b300337eSKevin Wolf [WIN_RECAL] = { cmd_nop, HD_CFA_OK | SET_DSC},
20930e6498edSKevin Wolf [WIN_READ] = { cmd_read_pio, ALL_OK },
2094d9033e1dSJohn Snow [WIN_READ_ONCE] = { cmd_read_pio, HD_CFA_OK },
20950e6498edSKevin Wolf [WIN_READ_EXT] = { cmd_read_pio, HD_CFA_OK },
209692a6a6f6SKevin Wolf [WIN_READDMA_EXT] = { cmd_read_dma, HD_CFA_OK },
209763a82e6aSKevin Wolf [WIN_READ_NATIVE_MAX_EXT] = { cmd_read_native_max, HD_CFA_OK | SET_DSC },
2098adf3a2c4SKevin Wolf [WIN_MULTREAD_EXT] = { cmd_read_multiple, HD_CFA_OK },
20990e6498edSKevin Wolf [WIN_WRITE] = { cmd_write_pio, HD_CFA_OK },
21000e6498edSKevin Wolf [WIN_WRITE_ONCE] = { cmd_write_pio, HD_CFA_OK },
21010e6498edSKevin Wolf [WIN_WRITE_EXT] = { cmd_write_pio, HD_CFA_OK },
210292a6a6f6SKevin Wolf [WIN_WRITEDMA_EXT] = { cmd_write_dma, HD_CFA_OK },
21030e6498edSKevin Wolf [CFA_WRITE_SECT_WO_ERASE] = { cmd_write_pio, CFA_OK },
2104adf3a2c4SKevin Wolf [WIN_MULTWRITE_EXT] = { cmd_write_multiple, HD_CFA_OK },
21050e6498edSKevin Wolf [WIN_WRITE_VERIFY] = { cmd_write_pio, HD_CFA_OK },
2106413860cfSKevin Wolf [WIN_VERIFY] = { cmd_verify, HD_CFA_OK | SET_DSC },
2107413860cfSKevin Wolf [WIN_VERIFY_ONCE] = { cmd_verify, HD_CFA_OK | SET_DSC },
2108413860cfSKevin Wolf [WIN_VERIFY_EXT] = { cmd_verify, HD_CFA_OK | SET_DSC },
210961fdda37SKevin Wolf [WIN_SEEK] = { cmd_seek, HD_CFA_OK | SET_DSC },
21106b1dd744SKevin Wolf [CFA_TRANSLATE_SECTOR] = { cmd_cfa_translate_sector, CFA_OK },
2111ee425c78SKevin Wolf [WIN_DIAGNOSE] = { cmd_exec_dev_diagnostic, ALL_OK },
2112176e4961SLev Kujawski [WIN_SPECIFY] = { cmd_specify, HD_CFA_OK | SET_DSC },
2113d9033e1dSJohn Snow [WIN_STANDBYNOW2] = { cmd_nop, HD_CFA_OK },
2114d9033e1dSJohn Snow [WIN_IDLEIMMEDIATE2] = { cmd_nop, HD_CFA_OK },
2115d9033e1dSJohn Snow [WIN_STANDBY2] = { cmd_nop, HD_CFA_OK },
2116d9033e1dSJohn Snow [WIN_SETIDLE2] = { cmd_nop, HD_CFA_OK },
2117d9033e1dSJohn Snow [WIN_CHECKPOWERMODE2] = { cmd_check_power_mode, HD_CFA_OK | SET_DSC },
2118d9033e1dSJohn Snow [WIN_SLEEPNOW2] = { cmd_nop, HD_CFA_OK },
2119ee425c78SKevin Wolf [WIN_PACKETCMD] = { cmd_packet, CD_OK },
2120ee425c78SKevin Wolf [WIN_PIDENTIFY] = { cmd_identify_packet, CD_OK },
2121ff352677SKevin Wolf [WIN_SMART] = { cmd_smart, HD_CFA_OK | SET_DSC },
21226b1dd744SKevin Wolf [CFA_ACCESS_METADATA_STORAGE] = { cmd_cfa_access_metadata_storage, CFA_OK },
21236b1dd744SKevin Wolf [CFA_ERASE_SECTORS] = { cmd_cfa_erase_sectors, CFA_OK | SET_DSC },
2124adf3a2c4SKevin Wolf [WIN_MULTREAD] = { cmd_read_multiple, HD_CFA_OK },
2125adf3a2c4SKevin Wolf [WIN_MULTWRITE] = { cmd_write_multiple, HD_CFA_OK },
2126adf3a2c4SKevin Wolf [WIN_SETMULT] = { cmd_set_multiple_mode, HD_CFA_OK | SET_DSC },
212792a6a6f6SKevin Wolf [WIN_READDMA] = { cmd_read_dma, HD_CFA_OK },
212892a6a6f6SKevin Wolf [WIN_READDMA_ONCE] = { cmd_read_dma, HD_CFA_OK },
212992a6a6f6SKevin Wolf [WIN_WRITEDMA] = { cmd_write_dma, HD_CFA_OK },
213092a6a6f6SKevin Wolf [WIN_WRITEDMA_ONCE] = { cmd_write_dma, HD_CFA_OK },
2131adf3a2c4SKevin Wolf [CFA_WRITE_MULTI_WO_ERASE] = { cmd_write_multiple, CFA_OK },
2132d9033e1dSJohn Snow [WIN_STANDBYNOW1] = { cmd_nop, HD_CFA_OK },
2133d9033e1dSJohn Snow [WIN_IDLEIMMEDIATE] = { cmd_nop, HD_CFA_OK },
2134d9033e1dSJohn Snow [WIN_STANDBY] = { cmd_nop, HD_CFA_OK },
2135d9033e1dSJohn Snow [WIN_SETIDLE1] = { cmd_nop, HD_CFA_OK },
2136d9033e1dSJohn Snow [WIN_CHECKPOWERMODE1] = { cmd_check_power_mode, HD_CFA_OK | SET_DSC },
2137d9033e1dSJohn Snow [WIN_SLEEPNOW1] = { cmd_nop, HD_CFA_OK },
21389afce429SKevin Wolf [WIN_FLUSH_CACHE] = { cmd_flush_cache, ALL_OK },
21399afce429SKevin Wolf [WIN_FLUSH_CACHE_EXT] = { cmd_flush_cache, HD_CFA_OK },
21401c66869aSKevin Wolf [WIN_IDENTIFY] = { cmd_identify, ALL_OK },
2141ee03398cSKevin Wolf [WIN_SETFEATURES] = { cmd_set_features, ALL_OK | SET_DSC },
21426b1dd744SKevin Wolf [IBM_SENSE_CONDITION] = { cmd_ibm_sense_condition, CFA_OK | SET_DSC },
21436b1dd744SKevin Wolf [CFA_WEAR_LEVEL] = { cmd_cfa_erase_sectors, HD_CFA_OK | SET_DSC },
2144d9033e1dSJohn Snow [WIN_READ_NATIVE_MAX] = { cmd_read_native_max, HD_CFA_OK | SET_DSC },
2145844505b1SMarkus Armbruster };
2146844505b1SMarkus Armbruster
ide_cmd_permitted(IDEState * s,uint32_t cmd)2147844505b1SMarkus Armbruster static bool ide_cmd_permitted(IDEState *s, uint32_t cmd)
2148844505b1SMarkus Armbruster {
2149844505b1SMarkus Armbruster return cmd < ARRAY_SIZE(ide_cmd_table)
2150a0436e92SKevin Wolf && (ide_cmd_table[cmd].flags & (1u << s->drive_kind));
2151844505b1SMarkus Armbruster }
21527cff87ffSAlexander Graf
ide_bus_exec_cmd(IDEBus * bus,uint32_t val)2153783f4474SPhilippe Mathieu-Daudé void ide_bus_exec_cmd(IDEBus *bus, uint32_t val)
21547cff87ffSAlexander Graf {
21557cff87ffSAlexander Graf IDEState *s;
2156dfe1ea8fSKevin Wolf bool complete;
21577cff87ffSAlexander Graf
21582c50207fSPhilippe Mathieu-Daudé s = ide_bus_active_if(bus);
2159783f4474SPhilippe Mathieu-Daudé trace_ide_bus_exec_cmd(bus, s, val);
21603eee2611SJohn Snow
216166a0a2cbSDong Xu Wang /* ignore commands to non existent slave */
21624be74634SMarkus Armbruster if (s != bus->ifs && !s->blk) {
21637cff87ffSAlexander Graf return;
21644be74634SMarkus Armbruster }
216559f2a787SGerd Hoffmann
2166266e7781SJohn Snow /* Only RESET is allowed while BSY and/or DRQ are set,
2167266e7781SJohn Snow * and only to ATAPI devices. */
2168266e7781SJohn Snow if (s->status & (BUSY_STAT|DRQ_STAT)) {
2169266e7781SJohn Snow if (val != WIN_DEVICE_RESET || s->drive_kind != IDE_CD) {
21707cff87ffSAlexander Graf return;
2171266e7781SJohn Snow }
2172266e7781SJohn Snow }
217359f2a787SGerd Hoffmann
2174844505b1SMarkus Armbruster if (!ide_cmd_permitted(s, val)) {
2175dfe1ea8fSKevin Wolf ide_abort_command(s);
21760cfe719dSPhilippe Mathieu-Daudé ide_bus_set_irq(s->bus);
2177dfe1ea8fSKevin Wolf return;
2178844505b1SMarkus Armbruster }
2179844505b1SMarkus Armbruster
2180a0436e92SKevin Wolf s->status = READY_STAT | BUSY_STAT;
2181a0436e92SKevin Wolf s->error = 0;
218236334fafSJohn Snow s->io_buffer_offset = 0;
2183a0436e92SKevin Wolf
2184a0436e92SKevin Wolf complete = ide_cmd_table[val].handler(s, val);
2185a0436e92SKevin Wolf if (complete) {
2186a0436e92SKevin Wolf s->status &= ~BUSY_STAT;
2187a0436e92SKevin Wolf assert(!!s->error == !!(s->status & ERR_STAT));
2188a0436e92SKevin Wolf
2189a0436e92SKevin Wolf if ((ide_cmd_table[val].flags & SET_DSC) && !s->error) {
2190a0436e92SKevin Wolf s->status |= SEEK_STAT;
2191a0436e92SKevin Wolf }
2192a0436e92SKevin Wolf
2193c7e73adbSPaolo Bonzini ide_cmd_done(s);
21940cfe719dSPhilippe Mathieu-Daudé ide_bus_set_irq(s->bus);
2195a0436e92SKevin Wolf }
219659f2a787SGerd Hoffmann }
219759f2a787SGerd Hoffmann
2198335ca2f2SJohn Snow /* IOport [R]ead [R]egisters */
2199335ca2f2SJohn Snow enum ATA_IOPORT_RR {
2200335ca2f2SJohn Snow ATA_IOPORT_RR_DATA = 0,
2201335ca2f2SJohn Snow ATA_IOPORT_RR_ERROR = 1,
2202335ca2f2SJohn Snow ATA_IOPORT_RR_SECTOR_COUNT = 2,
2203335ca2f2SJohn Snow ATA_IOPORT_RR_SECTOR_NUMBER = 3,
2204335ca2f2SJohn Snow ATA_IOPORT_RR_CYLINDER_LOW = 4,
2205335ca2f2SJohn Snow ATA_IOPORT_RR_CYLINDER_HIGH = 5,
2206335ca2f2SJohn Snow ATA_IOPORT_RR_DEVICE_HEAD = 6,
2207335ca2f2SJohn Snow ATA_IOPORT_RR_STATUS = 7,
2208335ca2f2SJohn Snow ATA_IOPORT_RR_NUM_REGISTERS,
2209335ca2f2SJohn Snow };
2210335ca2f2SJohn Snow
2211335ca2f2SJohn Snow const char *ATA_IOPORT_RR_lookup[ATA_IOPORT_RR_NUM_REGISTERS] = {
2212335ca2f2SJohn Snow [ATA_IOPORT_RR_DATA] = "Data",
2213335ca2f2SJohn Snow [ATA_IOPORT_RR_ERROR] = "Error",
2214335ca2f2SJohn Snow [ATA_IOPORT_RR_SECTOR_COUNT] = "Sector Count",
2215335ca2f2SJohn Snow [ATA_IOPORT_RR_SECTOR_NUMBER] = "Sector Number",
2216335ca2f2SJohn Snow [ATA_IOPORT_RR_CYLINDER_LOW] = "Cylinder Low",
2217335ca2f2SJohn Snow [ATA_IOPORT_RR_CYLINDER_HIGH] = "Cylinder High",
2218335ca2f2SJohn Snow [ATA_IOPORT_RR_DEVICE_HEAD] = "Device/Head",
2219335ca2f2SJohn Snow [ATA_IOPORT_RR_STATUS] = "Status"
2220335ca2f2SJohn Snow };
2221335ca2f2SJohn Snow
ide_ioport_read(void * opaque,uint32_t addr)22223eee2611SJohn Snow uint32_t ide_ioport_read(void *opaque, uint32_t addr)
222359f2a787SGerd Hoffmann {
222459f2a787SGerd Hoffmann IDEBus *bus = opaque;
22252c50207fSPhilippe Mathieu-Daudé IDEState *s = ide_bus_active_if(bus);
22263eee2611SJohn Snow uint32_t reg_num;
222759f2a787SGerd Hoffmann int ret, hob;
222859f2a787SGerd Hoffmann
22293eee2611SJohn Snow reg_num = addr & 7;
2230be8c9423SJohn Snow hob = bus->cmd & (IDE_CTRL_HOB);
22313eee2611SJohn Snow switch (reg_num) {
2232335ca2f2SJohn Snow case ATA_IOPORT_RR_DATA:
2233758c925eSLev Kujawski /*
2234758c925eSLev Kujawski * The pre-GRUB Solaris x86 bootloader relies upon inb
2235758c925eSLev Kujawski * consuming a word from the drive's sector buffer.
2236758c925eSLev Kujawski */
2237758c925eSLev Kujawski ret = ide_data_readw(bus, addr) & 0xff;
223859f2a787SGerd Hoffmann break;
2239335ca2f2SJohn Snow case ATA_IOPORT_RR_ERROR:
22404be74634SMarkus Armbruster if ((!bus->ifs[0].blk && !bus->ifs[1].blk) ||
22414be74634SMarkus Armbruster (s != bus->ifs && !s->blk)) {
224259f2a787SGerd Hoffmann ret = 0;
22434be74634SMarkus Armbruster } else if (!hob) {
224459f2a787SGerd Hoffmann ret = s->error;
22454be74634SMarkus Armbruster } else {
224659f2a787SGerd Hoffmann ret = s->hob_feature;
22474be74634SMarkus Armbruster }
224859f2a787SGerd Hoffmann break;
2249335ca2f2SJohn Snow case ATA_IOPORT_RR_SECTOR_COUNT:
22504be74634SMarkus Armbruster if (!bus->ifs[0].blk && !bus->ifs[1].blk) {
225159f2a787SGerd Hoffmann ret = 0;
22524be74634SMarkus Armbruster } else if (!hob) {
225359f2a787SGerd Hoffmann ret = s->nsector & 0xff;
22544be74634SMarkus Armbruster } else {
225559f2a787SGerd Hoffmann ret = s->hob_nsector;
22564be74634SMarkus Armbruster }
225759f2a787SGerd Hoffmann break;
2258335ca2f2SJohn Snow case ATA_IOPORT_RR_SECTOR_NUMBER:
22594be74634SMarkus Armbruster if (!bus->ifs[0].blk && !bus->ifs[1].blk) {
226059f2a787SGerd Hoffmann ret = 0;
22614be74634SMarkus Armbruster } else if (!hob) {
226259f2a787SGerd Hoffmann ret = s->sector;
22634be74634SMarkus Armbruster } else {
226459f2a787SGerd Hoffmann ret = s->hob_sector;
22654be74634SMarkus Armbruster }
226659f2a787SGerd Hoffmann break;
2267335ca2f2SJohn Snow case ATA_IOPORT_RR_CYLINDER_LOW:
22684be74634SMarkus Armbruster if (!bus->ifs[0].blk && !bus->ifs[1].blk) {
226959f2a787SGerd Hoffmann ret = 0;
22704be74634SMarkus Armbruster } else if (!hob) {
227159f2a787SGerd Hoffmann ret = s->lcyl;
22724be74634SMarkus Armbruster } else {
227359f2a787SGerd Hoffmann ret = s->hob_lcyl;
22744be74634SMarkus Armbruster }
227559f2a787SGerd Hoffmann break;
2276335ca2f2SJohn Snow case ATA_IOPORT_RR_CYLINDER_HIGH:
22774be74634SMarkus Armbruster if (!bus->ifs[0].blk && !bus->ifs[1].blk) {
227859f2a787SGerd Hoffmann ret = 0;
22794be74634SMarkus Armbruster } else if (!hob) {
228059f2a787SGerd Hoffmann ret = s->hcyl;
22814be74634SMarkus Armbruster } else {
228259f2a787SGerd Hoffmann ret = s->hob_hcyl;
22834be74634SMarkus Armbruster }
228459f2a787SGerd Hoffmann break;
2285335ca2f2SJohn Snow case ATA_IOPORT_RR_DEVICE_HEAD:
22864be74634SMarkus Armbruster if (!bus->ifs[0].blk && !bus->ifs[1].blk) {
228759f2a787SGerd Hoffmann ret = 0;
22884be74634SMarkus Armbruster } else {
228959f2a787SGerd Hoffmann ret = s->select;
22904be74634SMarkus Armbruster }
229159f2a787SGerd Hoffmann break;
229259f2a787SGerd Hoffmann default:
2293335ca2f2SJohn Snow case ATA_IOPORT_RR_STATUS:
22944be74634SMarkus Armbruster if ((!bus->ifs[0].blk && !bus->ifs[1].blk) ||
22954be74634SMarkus Armbruster (s != bus->ifs && !s->blk)) {
229659f2a787SGerd Hoffmann ret = 0;
22974be74634SMarkus Armbruster } else {
229859f2a787SGerd Hoffmann ret = s->status;
22994be74634SMarkus Armbruster }
23009cdd03a7SGerd Hoffmann qemu_irq_lower(bus->irq);
230159f2a787SGerd Hoffmann break;
230259f2a787SGerd Hoffmann }
23033eee2611SJohn Snow
2304335ca2f2SJohn Snow trace_ide_ioport_read(addr, ATA_IOPORT_RR_lookup[reg_num], ret, bus, s);
230559f2a787SGerd Hoffmann return ret;
230659f2a787SGerd Hoffmann }
230759f2a787SGerd Hoffmann
ide_status_read(void * opaque,uint32_t addr)230859f2a787SGerd Hoffmann uint32_t ide_status_read(void *opaque, uint32_t addr)
230959f2a787SGerd Hoffmann {
231059f2a787SGerd Hoffmann IDEBus *bus = opaque;
23112c50207fSPhilippe Mathieu-Daudé IDEState *s = ide_bus_active_if(bus);
231259f2a787SGerd Hoffmann int ret;
231359f2a787SGerd Hoffmann
23144be74634SMarkus Armbruster if ((!bus->ifs[0].blk && !bus->ifs[1].blk) ||
23154be74634SMarkus Armbruster (s != bus->ifs && !s->blk)) {
231659f2a787SGerd Hoffmann ret = 0;
23174be74634SMarkus Armbruster } else {
231859f2a787SGerd Hoffmann ret = s->status;
23194be74634SMarkus Armbruster }
23203eee2611SJohn Snow
23213eee2611SJohn Snow trace_ide_status_read(addr, ret, bus, s);
232259f2a787SGerd Hoffmann return ret;
232359f2a787SGerd Hoffmann }
232459f2a787SGerd Hoffmann
ide_perform_srst(IDEState * s)232555adb3c4SJohn Snow static void ide_perform_srst(IDEState *s)
232655adb3c4SJohn Snow {
232755adb3c4SJohn Snow s->status |= BUSY_STAT;
232855adb3c4SJohn Snow
232955adb3c4SJohn Snow /* Halt PIO (Via register state); PIO BH remains scheduled. */
233055adb3c4SJohn Snow ide_transfer_halt(s);
233155adb3c4SJohn Snow
233255adb3c4SJohn Snow /* Cancel DMA -- may drain block device and invoke callbacks */
233355adb3c4SJohn Snow ide_cancel_dma_sync(s);
233455adb3c4SJohn Snow
233555adb3c4SJohn Snow /* Cancel PIO callback, reset registers/signature, etc */
233655adb3c4SJohn Snow ide_reset(s);
233755adb3c4SJohn Snow
23384ac4e728SJohn Snow /* perform diagnostic */
23394ac4e728SJohn Snow cmd_exec_dev_diagnostic(s, WIN_DIAGNOSE);
234055adb3c4SJohn Snow }
234155adb3c4SJohn Snow
ide_bus_perform_srst(void * opaque)234255adb3c4SJohn Snow static void ide_bus_perform_srst(void *opaque)
234355adb3c4SJohn Snow {
234455adb3c4SJohn Snow IDEBus *bus = opaque;
234555adb3c4SJohn Snow IDEState *s;
234655adb3c4SJohn Snow int i;
234755adb3c4SJohn Snow
234855adb3c4SJohn Snow for (i = 0; i < 2; i++) {
234955adb3c4SJohn Snow s = &bus->ifs[i];
235055adb3c4SJohn Snow ide_perform_srst(s);
235155adb3c4SJohn Snow }
23521a9925e3SJohn Snow
23531a9925e3SJohn Snow bus->cmd &= ~IDE_CTRL_RESET;
235455adb3c4SJohn Snow }
235555adb3c4SJohn Snow
ide_ctrl_write(void * opaque,uint32_t addr,uint32_t val)235698d98912SJohn Snow void ide_ctrl_write(void *opaque, uint32_t addr, uint32_t val)
235759f2a787SGerd Hoffmann {
235859f2a787SGerd Hoffmann IDEBus *bus = opaque;
235959f2a787SGerd Hoffmann IDEState *s;
236059f2a787SGerd Hoffmann int i;
236159f2a787SGerd Hoffmann
236298d98912SJohn Snow trace_ide_ctrl_write(addr, val, bus);
23633eee2611SJohn Snow
236455adb3c4SJohn Snow /* Device0 and Device1 each have their own control register,
236555adb3c4SJohn Snow * but QEMU models it as just one register in the controller. */
2366b45bcd81SJohn Snow if (!(bus->cmd & IDE_CTRL_RESET) && (val & IDE_CTRL_RESET)) {
236759f2a787SGerd Hoffmann for (i = 0; i < 2; i++) {
236859f2a787SGerd Hoffmann s = &bus->ifs[i];
236955adb3c4SJohn Snow s->status |= BUSY_STAT;
237059f2a787SGerd Hoffmann }
2371de00b8b3SAlex Bennée replay_bh_schedule_oneshot_event(qemu_get_aio_context(),
237255adb3c4SJohn Snow ide_bus_perform_srst, bus);
237359f2a787SGerd Hoffmann }
237459f2a787SGerd Hoffmann
23759cdd03a7SGerd Hoffmann bus->cmd = val;
237659f2a787SGerd Hoffmann }
237759f2a787SGerd Hoffmann
237840c4ed3fSKevin Wolf /*
237940c4ed3fSKevin Wolf * Returns true if the running PIO transfer is a PIO out (i.e. data is
238040c4ed3fSKevin Wolf * transferred from the device to the guest), false if it's a PIO in
238140c4ed3fSKevin Wolf */
ide_is_pio_out(IDEState * s)238240c4ed3fSKevin Wolf static bool ide_is_pio_out(IDEState *s)
238340c4ed3fSKevin Wolf {
238440c4ed3fSKevin Wolf if (s->end_transfer_func == ide_sector_write ||
238540c4ed3fSKevin Wolf s->end_transfer_func == ide_atapi_cmd) {
238640c4ed3fSKevin Wolf return false;
238740c4ed3fSKevin Wolf } else if (s->end_transfer_func == ide_sector_read ||
238840c4ed3fSKevin Wolf s->end_transfer_func == ide_transfer_stop ||
238940c4ed3fSKevin Wolf s->end_transfer_func == ide_atapi_cmd_reply_end ||
239040c4ed3fSKevin Wolf s->end_transfer_func == ide_dummy_transfer_stop) {
239140c4ed3fSKevin Wolf return true;
239240c4ed3fSKevin Wolf }
239340c4ed3fSKevin Wolf
239440c4ed3fSKevin Wolf abort();
239540c4ed3fSKevin Wolf }
239640c4ed3fSKevin Wolf
ide_data_writew(void * opaque,uint32_t addr,uint32_t val)239759f2a787SGerd Hoffmann void ide_data_writew(void *opaque, uint32_t addr, uint32_t val)
239859f2a787SGerd Hoffmann {
239959f2a787SGerd Hoffmann IDEBus *bus = opaque;
24002c50207fSPhilippe Mathieu-Daudé IDEState *s = ide_bus_active_if(bus);
240159f2a787SGerd Hoffmann uint8_t *p;
240259f2a787SGerd Hoffmann
24031787efc3SJohn Snow trace_ide_data_writew(addr, val, bus, s);
24041787efc3SJohn Snow
240540c4ed3fSKevin Wolf /* PIO data access allowed only when DRQ bit is set. The result of a write
240640c4ed3fSKevin Wolf * during PIO out is indeterminate, just ignore it. */
240740c4ed3fSKevin Wolf if (!(s->status & DRQ_STAT) || ide_is_pio_out(s)) {
240859f2a787SGerd Hoffmann return;
240940c4ed3fSKevin Wolf }
241059f2a787SGerd Hoffmann
241159f2a787SGerd Hoffmann p = s->data_ptr;
24121ea17d22SLubomir Rintel if (s->io8) {
24131ea17d22SLubomir Rintel if (p + 1 > s->data_end) {
24141ea17d22SLubomir Rintel return;
24151ea17d22SLubomir Rintel }
24161ea17d22SLubomir Rintel
24171ea17d22SLubomir Rintel *p++ = val;
24181ea17d22SLubomir Rintel } else {
2419d2ff8585SKevin Wolf if (p + 2 > s->data_end) {
2420d2ff8585SKevin Wolf return;
2421d2ff8585SKevin Wolf }
2422d2ff8585SKevin Wolf
242359f2a787SGerd Hoffmann *(uint16_t *)p = le16_to_cpu(val);
242459f2a787SGerd Hoffmann p += 2;
24251ea17d22SLubomir Rintel }
242659f2a787SGerd Hoffmann s->data_ptr = p;
2427cb72cba8SKevin Wolf if (p >= s->data_end) {
2428cb72cba8SKevin Wolf s->status &= ~DRQ_STAT;
242959f2a787SGerd Hoffmann s->end_transfer_func(s);
243059f2a787SGerd Hoffmann }
2431cb72cba8SKevin Wolf }
243259f2a787SGerd Hoffmann
ide_data_readw(void * opaque,uint32_t addr)243359f2a787SGerd Hoffmann uint32_t ide_data_readw(void *opaque, uint32_t addr)
243459f2a787SGerd Hoffmann {
243559f2a787SGerd Hoffmann IDEBus *bus = opaque;
24362c50207fSPhilippe Mathieu-Daudé IDEState *s = ide_bus_active_if(bus);
243759f2a787SGerd Hoffmann uint8_t *p;
243859f2a787SGerd Hoffmann int ret;
243959f2a787SGerd Hoffmann
244040c4ed3fSKevin Wolf /* PIO data access allowed only when DRQ bit is set. The result of a read
244140c4ed3fSKevin Wolf * during PIO in is indeterminate, return 0 and don't move forward. */
244240c4ed3fSKevin Wolf if (!(s->status & DRQ_STAT) || !ide_is_pio_out(s)) {
244359f2a787SGerd Hoffmann return 0;
244440c4ed3fSKevin Wolf }
244559f2a787SGerd Hoffmann
244659f2a787SGerd Hoffmann p = s->data_ptr;
24471ea17d22SLubomir Rintel if (s->io8) {
24481ea17d22SLubomir Rintel if (p + 1 > s->data_end) {
24491ea17d22SLubomir Rintel return 0;
24501ea17d22SLubomir Rintel }
24511ea17d22SLubomir Rintel
24521ea17d22SLubomir Rintel ret = *p++;
24531ea17d22SLubomir Rintel } else {
2454d2ff8585SKevin Wolf if (p + 2 > s->data_end) {
2455d2ff8585SKevin Wolf return 0;
2456d2ff8585SKevin Wolf }
2457d2ff8585SKevin Wolf
245859f2a787SGerd Hoffmann ret = cpu_to_le16(*(uint16_t *)p);
245959f2a787SGerd Hoffmann p += 2;
24601ea17d22SLubomir Rintel }
246159f2a787SGerd Hoffmann s->data_ptr = p;
2462cb72cba8SKevin Wolf if (p >= s->data_end) {
2463cb72cba8SKevin Wolf s->status &= ~DRQ_STAT;
246459f2a787SGerd Hoffmann s->end_transfer_func(s);
2465cb72cba8SKevin Wolf }
24661787efc3SJohn Snow
24671787efc3SJohn Snow trace_ide_data_readw(addr, ret, bus, s);
246859f2a787SGerd Hoffmann return ret;
246959f2a787SGerd Hoffmann }
247059f2a787SGerd Hoffmann
ide_data_writel(void * opaque,uint32_t addr,uint32_t val)247159f2a787SGerd Hoffmann void ide_data_writel(void *opaque, uint32_t addr, uint32_t val)
247259f2a787SGerd Hoffmann {
247359f2a787SGerd Hoffmann IDEBus *bus = opaque;
24742c50207fSPhilippe Mathieu-Daudé IDEState *s = ide_bus_active_if(bus);
247559f2a787SGerd Hoffmann uint8_t *p;
247659f2a787SGerd Hoffmann
24771787efc3SJohn Snow trace_ide_data_writel(addr, val, bus, s);
24781787efc3SJohn Snow
247940c4ed3fSKevin Wolf /* PIO data access allowed only when DRQ bit is set. The result of a write
248040c4ed3fSKevin Wolf * during PIO out is indeterminate, just ignore it. */
248140c4ed3fSKevin Wolf if (!(s->status & DRQ_STAT) || ide_is_pio_out(s)) {
248259f2a787SGerd Hoffmann return;
248340c4ed3fSKevin Wolf }
248459f2a787SGerd Hoffmann
248559f2a787SGerd Hoffmann p = s->data_ptr;
2486d2ff8585SKevin Wolf if (p + 4 > s->data_end) {
2487d2ff8585SKevin Wolf return;
2488d2ff8585SKevin Wolf }
2489d2ff8585SKevin Wolf
249059f2a787SGerd Hoffmann *(uint32_t *)p = le32_to_cpu(val);
249159f2a787SGerd Hoffmann p += 4;
249259f2a787SGerd Hoffmann s->data_ptr = p;
2493cb72cba8SKevin Wolf if (p >= s->data_end) {
2494cb72cba8SKevin Wolf s->status &= ~DRQ_STAT;
249559f2a787SGerd Hoffmann s->end_transfer_func(s);
249659f2a787SGerd Hoffmann }
2497cb72cba8SKevin Wolf }
249859f2a787SGerd Hoffmann
ide_data_readl(void * opaque,uint32_t addr)249959f2a787SGerd Hoffmann uint32_t ide_data_readl(void *opaque, uint32_t addr)
250059f2a787SGerd Hoffmann {
250159f2a787SGerd Hoffmann IDEBus *bus = opaque;
25022c50207fSPhilippe Mathieu-Daudé IDEState *s = ide_bus_active_if(bus);
250359f2a787SGerd Hoffmann uint8_t *p;
250459f2a787SGerd Hoffmann int ret;
250559f2a787SGerd Hoffmann
250640c4ed3fSKevin Wolf /* PIO data access allowed only when DRQ bit is set. The result of a read
250740c4ed3fSKevin Wolf * during PIO in is indeterminate, return 0 and don't move forward. */
250840c4ed3fSKevin Wolf if (!(s->status & DRQ_STAT) || !ide_is_pio_out(s)) {
25091787efc3SJohn Snow ret = 0;
25101787efc3SJohn Snow goto out;
251140c4ed3fSKevin Wolf }
251259f2a787SGerd Hoffmann
251359f2a787SGerd Hoffmann p = s->data_ptr;
2514d2ff8585SKevin Wolf if (p + 4 > s->data_end) {
2515d2ff8585SKevin Wolf return 0;
2516d2ff8585SKevin Wolf }
2517d2ff8585SKevin Wolf
251859f2a787SGerd Hoffmann ret = cpu_to_le32(*(uint32_t *)p);
251959f2a787SGerd Hoffmann p += 4;
252059f2a787SGerd Hoffmann s->data_ptr = p;
2521cb72cba8SKevin Wolf if (p >= s->data_end) {
2522cb72cba8SKevin Wolf s->status &= ~DRQ_STAT;
252359f2a787SGerd Hoffmann s->end_transfer_func(s);
2524cb72cba8SKevin Wolf }
25251787efc3SJohn Snow
25261787efc3SJohn Snow out:
25271787efc3SJohn Snow trace_ide_data_readl(addr, ret, bus, s);
252859f2a787SGerd Hoffmann return ret;
252959f2a787SGerd Hoffmann }
253059f2a787SGerd Hoffmann
ide_dummy_transfer_stop(IDEState * s)253159f2a787SGerd Hoffmann static void ide_dummy_transfer_stop(IDEState *s)
253259f2a787SGerd Hoffmann {
253359f2a787SGerd Hoffmann s->data_ptr = s->io_buffer;
253459f2a787SGerd Hoffmann s->data_end = s->io_buffer;
253559f2a787SGerd Hoffmann s->io_buffer[0] = 0xff;
253659f2a787SGerd Hoffmann s->io_buffer[1] = 0xff;
253759f2a787SGerd Hoffmann s->io_buffer[2] = 0xff;
253859f2a787SGerd Hoffmann s->io_buffer[3] = 0xff;
253959f2a787SGerd Hoffmann }
254059f2a787SGerd Hoffmann
ide_bus_reset(IDEBus * bus)25414a643563SBlue Swirl void ide_bus_reset(IDEBus *bus)
25424a643563SBlue Swirl {
25437d751201SFiona Ebner /* pending async DMA - needs the IDEState before it is reset */
254440a6238aSAlexander Graf if (bus->dma->aiocb) {
25450e168d35SJohn Snow trace_ide_bus_reset_aio();
25464be74634SMarkus Armbruster blk_aio_cancel(bus->dma->aiocb);
254740a6238aSAlexander Graf bus->dma->aiocb = NULL;
254840a6238aSAlexander Graf }
254940a6238aSAlexander Graf
25507d751201SFiona Ebner bus->unit = 0;
25517d751201SFiona Ebner bus->cmd = 0;
25527d751201SFiona Ebner ide_reset(&bus->ifs[0]);
25537d751201SFiona Ebner ide_reset(&bus->ifs[1]);
25547d751201SFiona Ebner ide_clear_hob(bus);
25557d751201SFiona Ebner
255640a6238aSAlexander Graf /* reset dma provider too */
25571374bec0SPaolo Bonzini if (bus->dma->ops->reset) {
255840a6238aSAlexander Graf bus->dma->ops->reset(bus->dma);
25594a643563SBlue Swirl }
25601374bec0SPaolo Bonzini }
25614a643563SBlue Swirl
ide_cd_is_tray_open(void * opaque)2562e4def80bSMarkus Armbruster static bool ide_cd_is_tray_open(void *opaque)
2563e4def80bSMarkus Armbruster {
2564e4def80bSMarkus Armbruster return ((IDEState *)opaque)->tray_open;
2565e4def80bSMarkus Armbruster }
2566e4def80bSMarkus Armbruster
ide_cd_is_medium_locked(void * opaque)2567f107639aSMarkus Armbruster static bool ide_cd_is_medium_locked(void *opaque)
2568f107639aSMarkus Armbruster {
2569f107639aSMarkus Armbruster return ((IDEState *)opaque)->tray_locked;
2570f107639aSMarkus Armbruster }
2571f107639aSMarkus Armbruster
ide_resize_cb(void * opaque)257201ce352eSJohn Snow static void ide_resize_cb(void *opaque)
257301ce352eSJohn Snow {
257401ce352eSJohn Snow IDEState *s = opaque;
257501ce352eSJohn Snow uint64_t nb_sectors;
257601ce352eSJohn Snow
257701ce352eSJohn Snow if (!s->identify_set) {
257801ce352eSJohn Snow return;
257901ce352eSJohn Snow }
258001ce352eSJohn Snow
25814be74634SMarkus Armbruster blk_get_geometry(s->blk, &nb_sectors);
258201ce352eSJohn Snow s->nb_sectors = nb_sectors;
258301ce352eSJohn Snow
258401ce352eSJohn Snow /* Update the identify data buffer. */
258501ce352eSJohn Snow if (s->drive_kind == IDE_CFATA) {
258601ce352eSJohn Snow ide_cfata_identify_size(s);
258701ce352eSJohn Snow } else {
258801ce352eSJohn Snow /* IDE_CD uses a different set of callbacks entirely. */
258901ce352eSJohn Snow assert(s->drive_kind != IDE_CD);
259001ce352eSJohn Snow ide_identify_size(s);
259101ce352eSJohn Snow }
259201ce352eSJohn Snow }
259301ce352eSJohn Snow
25940e49de52SMarkus Armbruster static const BlockDevOps ide_cd_block_ops = {
2595145feb17SMarkus Armbruster .change_media_cb = ide_cd_change_cb,
25962df0a3a3SPaolo Bonzini .eject_request_cb = ide_cd_eject_request_cb,
2597e4def80bSMarkus Armbruster .is_tray_open = ide_cd_is_tray_open,
2598f107639aSMarkus Armbruster .is_medium_locked = ide_cd_is_medium_locked,
25990e49de52SMarkus Armbruster };
26000e49de52SMarkus Armbruster
260101ce352eSJohn Snow static const BlockDevOps ide_hd_block_ops = {
260201ce352eSJohn Snow .resize_cb = ide_resize_cb,
260301ce352eSJohn Snow };
260401ce352eSJohn Snow
ide_init_drive(IDEState * s,IDEDevice * dev,IDEDriveKind kind,Error ** errp)2605dcaff461SPaolo Bonzini int ide_init_drive(IDEState *s, IDEDevice *dev, IDEDriveKind kind, Error **errp)
260659f2a787SGerd Hoffmann {
260759f2a787SGerd Hoffmann uint64_t nb_sectors;
260859f2a787SGerd Hoffmann
2609dcaff461SPaolo Bonzini s->blk = dev->conf.blk;
26101f56e32aSMarkus Armbruster s->drive_kind = kind;
26111f56e32aSMarkus Armbruster
2612dcaff461SPaolo Bonzini blk_get_geometry(s->blk, &nb_sectors);
2613d13f4035SPaolo Bonzini s->win2k_install_hack = dev->win2k_install_hack;
2614dcaff461SPaolo Bonzini s->cylinders = dev->conf.cyls;
2615dcaff461SPaolo Bonzini s->heads = s->drive_heads = dev->conf.heads;
2616dcaff461SPaolo Bonzini s->sectors = s->drive_sectors = dev->conf.secs;
2617dcaff461SPaolo Bonzini s->chs_trans = dev->chs_trans;
261859f2a787SGerd Hoffmann s->nb_sectors = nb_sectors;
2619dcaff461SPaolo Bonzini s->wwn = dev->wwn;
262059f2a787SGerd Hoffmann /* The SMART values should be preserved across power cycles
262159f2a787SGerd Hoffmann but they aren't. */
262259f2a787SGerd Hoffmann s->smart_enabled = 1;
262359f2a787SGerd Hoffmann s->smart_autosave = 1;
262459f2a787SGerd Hoffmann s->smart_errors = 0;
262559f2a787SGerd Hoffmann s->smart_selftest_count = 0;
26261f56e32aSMarkus Armbruster if (kind == IDE_CD) {
2627dcaff461SPaolo Bonzini blk_set_dev_ops(s->blk, &ide_cd_block_ops, s);
26287aa9c811SMarkus Armbruster } else {
26294be74634SMarkus Armbruster if (!blk_is_inserted(s->blk)) {
2630794939e8SMao Zhongyi error_setg(errp, "Device needs media, but drive is empty");
263198f28ad7SMarkus Armbruster return -1;
263298f28ad7SMarkus Armbruster }
2633dcaff461SPaolo Bonzini if (!blk_is_writable(s->blk)) {
2634794939e8SMao Zhongyi error_setg(errp, "Can't use a read-only drive");
26357aa9c811SMarkus Armbruster return -1;
26367aa9c811SMarkus Armbruster }
2637dcaff461SPaolo Bonzini blk_set_dev_ops(s->blk, &ide_hd_block_ops, s);
263859f2a787SGerd Hoffmann }
2639dcaff461SPaolo Bonzini if (dev->serial) {
2640dcaff461SPaolo Bonzini pstrcpy(s->drive_serial_str, sizeof(s->drive_serial_str), dev->serial);
26416ced55a5SMarkus Armbruster } else {
264259f2a787SGerd Hoffmann snprintf(s->drive_serial_str, sizeof(s->drive_serial_str),
264359f2a787SGerd Hoffmann "QM%05d", s->drive_serial);
2644870111c8SMarkus Armbruster }
2645dcaff461SPaolo Bonzini if (dev->model) {
2646dcaff461SPaolo Bonzini pstrcpy(s->drive_model_str, sizeof(s->drive_model_str), dev->model);
264727e0c9a1SFloris Bos } else {
264827e0c9a1SFloris Bos switch (kind) {
264927e0c9a1SFloris Bos case IDE_CD:
265027e0c9a1SFloris Bos strcpy(s->drive_model_str, "QEMU DVD-ROM");
265127e0c9a1SFloris Bos break;
265227e0c9a1SFloris Bos case IDE_CFATA:
265327e0c9a1SFloris Bos strcpy(s->drive_model_str, "QEMU MICRODRIVE");
265427e0c9a1SFloris Bos break;
265527e0c9a1SFloris Bos default:
265627e0c9a1SFloris Bos strcpy(s->drive_model_str, "QEMU HARDDISK");
265727e0c9a1SFloris Bos break;
265827e0c9a1SFloris Bos }
265927e0c9a1SFloris Bos }
266027e0c9a1SFloris Bos
2661dcaff461SPaolo Bonzini if (dev->version) {
2662dcaff461SPaolo Bonzini pstrcpy(s->version, sizeof(s->version), dev->version);
266347c06340SGerd Hoffmann } else {
266435c2c8dcSEduardo Habkost pstrcpy(s->version, sizeof(s->version), qemu_hw_version());
266547c06340SGerd Hoffmann }
266640a6238aSAlexander Graf
266788804180SGerd Hoffmann ide_reset(s);
2668dcaff461SPaolo Bonzini blk_iostatus_enable(s->blk);
2669c4d74df7SMarkus Armbruster return 0;
267088804180SGerd Hoffmann }
267188804180SGerd Hoffmann
ide_init1(IDEBus * bus,int unit)267257234ee4SMarkus Armbruster static void ide_init1(IDEBus *bus, int unit)
267388804180SGerd Hoffmann {
267488804180SGerd Hoffmann static int drive_serial = 1;
2675d459da0eSMarkus Armbruster IDEState *s = &bus->ifs[unit];
267688804180SGerd Hoffmann
267788804180SGerd Hoffmann s->bus = bus;
2678d459da0eSMarkus Armbruster s->unit = unit;
267988804180SGerd Hoffmann s->drive_serial = drive_serial++;
26801b2adf28SChristoph Hellwig /* we need at least 2k alignment for accessing CDROMs using O_DIRECT */
268150641c5cSJuan Quintela s->io_buffer_total_len = IDE_DMA_BUF_SECTORS*512 + 4;
2682c925400bSKevin Wolf s->io_buffer = qemu_memalign(2048, s->io_buffer_total_len);
2683c925400bSKevin Wolf memset(s->io_buffer, 0, s->io_buffer_total_len);
2684c925400bSKevin Wolf
26854be74634SMarkus Armbruster s->smart_selftest_data = blk_blockalign(s->blk, 512);
2686c925400bSKevin Wolf memset(s->smart_selftest_data, 0, 512);
2687c925400bSKevin Wolf
2688bc72ad67SAlex Bligh s->sector_write_timer = timer_new_ns(QEMU_CLOCK_VIRTUAL,
268959f2a787SGerd Hoffmann ide_sector_write_timer_cb, s);
2690d459da0eSMarkus Armbruster }
2691d459da0eSMarkus Armbruster
ide_nop_int(const IDEDMA * dma,bool is_write)2692ae0cebd7SPhilippe Mathieu-Daudé static int ide_nop_int(const IDEDMA *dma, bool is_write)
269340a6238aSAlexander Graf {
269440a6238aSAlexander Graf return 0;
269540a6238aSAlexander Graf }
269640a6238aSAlexander Graf
ide_nop(const IDEDMA * dma)2697ae0cebd7SPhilippe Mathieu-Daudé static void ide_nop(const IDEDMA *dma)
26989898586dSPaolo Bonzini {
26999898586dSPaolo Bonzini }
27009898586dSPaolo Bonzini
ide_nop_int32(const IDEDMA * dma,int32_t l)2701ae0cebd7SPhilippe Mathieu-Daudé static int32_t ide_nop_int32(const IDEDMA *dma, int32_t l)
27023251bdcfSJohn Snow {
27033251bdcfSJohn Snow return 0;
27043251bdcfSJohn Snow }
27053251bdcfSJohn Snow
270640a6238aSAlexander Graf static const IDEDMAOps ide_dma_nop_ops = {
27073251bdcfSJohn Snow .prepare_buf = ide_nop_int32,
27089898586dSPaolo Bonzini .restart_dma = ide_nop,
270940a6238aSAlexander Graf .rw_buf = ide_nop_int,
271040a6238aSAlexander Graf };
271140a6238aSAlexander Graf
ide_restart_dma(IDEState * s,enum ide_dma_cmd dma_cmd)27129898586dSPaolo Bonzini static void ide_restart_dma(IDEState *s, enum ide_dma_cmd dma_cmd)
27139898586dSPaolo Bonzini {
2714a96cb236SPaolo Bonzini s->unit = s->bus->retry_unit;
2715dc5d0af4SPaolo Bonzini ide_set_sector(s, s->bus->retry_sector_num);
2716dc5d0af4SPaolo Bonzini s->nsector = s->bus->retry_nsector;
27179898586dSPaolo Bonzini s->bus->dma->ops->restart_dma(s->bus->dma);
27189898586dSPaolo Bonzini s->io_buffer_size = 0;
27199898586dSPaolo Bonzini s->dma_cmd = dma_cmd;
27209898586dSPaolo Bonzini ide_start_dma(s, ide_dma_cb);
27219898586dSPaolo Bonzini }
27229898586dSPaolo Bonzini
ide_restart_bh(void * opaque)27239898586dSPaolo Bonzini static void ide_restart_bh(void *opaque)
27249898586dSPaolo Bonzini {
27259898586dSPaolo Bonzini IDEBus *bus = opaque;
27269898586dSPaolo Bonzini IDEState *s;
27279898586dSPaolo Bonzini bool is_read;
27289898586dSPaolo Bonzini int error_status;
27299898586dSPaolo Bonzini
27309898586dSPaolo Bonzini qemu_bh_delete(bus->bh);
27319898586dSPaolo Bonzini bus->bh = NULL;
27329898586dSPaolo Bonzini
27339898586dSPaolo Bonzini error_status = bus->error_status;
27349898586dSPaolo Bonzini if (bus->error_status == 0) {
27359898586dSPaolo Bonzini return;
27369898586dSPaolo Bonzini }
27379898586dSPaolo Bonzini
27382c50207fSPhilippe Mathieu-Daudé s = ide_bus_active_if(bus);
27399898586dSPaolo Bonzini is_read = (bus->error_status & IDE_RETRY_READ) != 0;
27409898586dSPaolo Bonzini
27419898586dSPaolo Bonzini /* The error status must be cleared before resubmitting the request: The
27429898586dSPaolo Bonzini * request may fail again, and this case can only be distinguished if the
27439898586dSPaolo Bonzini * called function can set a new error status. */
27449898586dSPaolo Bonzini bus->error_status = 0;
27459898586dSPaolo Bonzini
27467c03a691SJohn Snow /* The HBA has generically asked to be kicked on retry */
27477c03a691SJohn Snow if (error_status & IDE_RETRY_HBA) {
27487c03a691SJohn Snow if (s->bus->dma->ops->restart) {
27497c03a691SJohn Snow s->bus->dma->ops->restart(s->bus->dma);
27507c03a691SJohn Snow }
2751502356eeSPavel Butsykin } else if (IS_IDE_RETRY_DMA(error_status)) {
27529898586dSPaolo Bonzini if (error_status & IDE_RETRY_TRIM) {
27539898586dSPaolo Bonzini ide_restart_dma(s, IDE_DMA_TRIM);
27549898586dSPaolo Bonzini } else {
27559898586dSPaolo Bonzini ide_restart_dma(s, is_read ? IDE_DMA_READ : IDE_DMA_WRITE);
27569898586dSPaolo Bonzini }
2757502356eeSPavel Butsykin } else if (IS_IDE_RETRY_PIO(error_status)) {
27589898586dSPaolo Bonzini if (is_read) {
27599898586dSPaolo Bonzini ide_sector_read(s);
27609898586dSPaolo Bonzini } else {
27619898586dSPaolo Bonzini ide_sector_write(s);
27629898586dSPaolo Bonzini }
27639898586dSPaolo Bonzini } else if (error_status & IDE_RETRY_FLUSH) {
27649898586dSPaolo Bonzini ide_flush_cache(s);
2765502356eeSPavel Butsykin } else if (IS_IDE_RETRY_ATAPI(error_status)) {
2766502356eeSPavel Butsykin assert(s->end_transfer_func == ide_atapi_cmd);
27679898586dSPaolo Bonzini ide_atapi_dma_restart(s);
2768502356eeSPavel Butsykin } else {
2769502356eeSPavel Butsykin abort();
27709898586dSPaolo Bonzini }
27719898586dSPaolo Bonzini }
27729898586dSPaolo Bonzini
ide_restart_cb(void * opaque,bool running,RunState state)2773538f0497SPhilippe Mathieu-Daudé static void ide_restart_cb(void *opaque, bool running, RunState state)
27749898586dSPaolo Bonzini {
27759898586dSPaolo Bonzini IDEBus *bus = opaque;
27769898586dSPaolo Bonzini
27779898586dSPaolo Bonzini if (!running)
27789898586dSPaolo Bonzini return;
27799898586dSPaolo Bonzini
27809898586dSPaolo Bonzini if (!bus->bh) {
27819898586dSPaolo Bonzini bus->bh = qemu_bh_new(ide_restart_bh, bus);
27829898586dSPaolo Bonzini qemu_bh_schedule(bus->bh);
27839898586dSPaolo Bonzini }
27849898586dSPaolo Bonzini }
27859898586dSPaolo Bonzini
ide_bus_register_restart_cb(IDEBus * bus)2786e29b1246SPhilippe Mathieu-Daudé void ide_bus_register_restart_cb(IDEBus *bus)
2787f878c916SPaolo Bonzini {
27889898586dSPaolo Bonzini if (bus->dma->ops->restart_dma) {
2789ca44141dSAshijeet Acharya bus->vmstate = qemu_add_vm_change_state_handler(ide_restart_cb, bus);
27909898586dSPaolo Bonzini }
2791f878c916SPaolo Bonzini }
2792f878c916SPaolo Bonzini
279340a6238aSAlexander Graf static IDEDMA ide_dma_nop = {
279440a6238aSAlexander Graf .ops = &ide_dma_nop_ops,
279540a6238aSAlexander Graf .aiocb = NULL,
279640a6238aSAlexander Graf };
279740a6238aSAlexander Graf
ide_bus_init_output_irq(IDEBus * bus,qemu_irq irq_out)2798c9519630SPhilippe Mathieu-Daudé void ide_bus_init_output_irq(IDEBus *bus, qemu_irq irq_out)
2799d459da0eSMarkus Armbruster {
2800d459da0eSMarkus Armbruster int i;
2801d459da0eSMarkus Armbruster
2802d459da0eSMarkus Armbruster for(i = 0; i < 2; i++) {
280357234ee4SMarkus Armbruster ide_init1(bus, i);
280457234ee4SMarkus Armbruster ide_reset(&bus->ifs[i]);
280557234ee4SMarkus Armbruster }
2806c9519630SPhilippe Mathieu-Daudé bus->irq = irq_out;
280740a6238aSAlexander Graf bus->dma = &ide_dma_nop;
280857234ee4SMarkus Armbruster }
280957234ee4SMarkus Armbruster
ide_bus_set_irq(IDEBus * bus)28100cfe719dSPhilippe Mathieu-Daudé void ide_bus_set_irq(IDEBus *bus)
2811da9f1172SPhilippe Mathieu-Daudé {
2812da9f1172SPhilippe Mathieu-Daudé if (!(bus->cmd & IDE_CTRL_DISABLE_IRQ)) {
2813da9f1172SPhilippe Mathieu-Daudé qemu_irq_raise(bus->irq);
2814da9f1172SPhilippe Mathieu-Daudé }
2815da9f1172SPhilippe Mathieu-Daudé }
2816da9f1172SPhilippe Mathieu-Daudé
ide_exit(IDEState * s)2817c9f08641SLi Qiang void ide_exit(IDEState *s)
2818c9f08641SLi Qiang {
2819c9f08641SLi Qiang timer_free(s->sector_write_timer);
2820c9f08641SLi Qiang qemu_vfree(s->smart_selftest_data);
2821c9f08641SLi Qiang qemu_vfree(s->io_buffer);
2822c9f08641SLi Qiang }
2823c9f08641SLi Qiang
is_identify_set(void * opaque,int version_id)282437159f13SJuan Quintela static bool is_identify_set(void *opaque, int version_id)
282559f2a787SGerd Hoffmann {
282637159f13SJuan Quintela IDEState *s = opaque;
282759f2a787SGerd Hoffmann
282837159f13SJuan Quintela return s->identify_set != 0;
282959f2a787SGerd Hoffmann }
283059f2a787SGerd Hoffmann
283150641c5cSJuan Quintela static EndTransferFunc* transfer_end_table[] = {
283250641c5cSJuan Quintela ide_sector_read,
283350641c5cSJuan Quintela ide_sector_write,
283450641c5cSJuan Quintela ide_transfer_stop,
283550641c5cSJuan Quintela ide_atapi_cmd_reply_end,
283650641c5cSJuan Quintela ide_atapi_cmd,
283750641c5cSJuan Quintela ide_dummy_transfer_stop,
283850641c5cSJuan Quintela };
283950641c5cSJuan Quintela
transfer_end_table_idx(EndTransferFunc * fn)284050641c5cSJuan Quintela static int transfer_end_table_idx(EndTransferFunc *fn)
284150641c5cSJuan Quintela {
284250641c5cSJuan Quintela int i;
284350641c5cSJuan Quintela
284450641c5cSJuan Quintela for (i = 0; i < ARRAY_SIZE(transfer_end_table); i++)
284550641c5cSJuan Quintela if (transfer_end_table[i] == fn)
284650641c5cSJuan Quintela return i;
284750641c5cSJuan Quintela
284850641c5cSJuan Quintela return -1;
284950641c5cSJuan Quintela }
285050641c5cSJuan Quintela
ide_drive_post_load(void * opaque,int version_id)285137159f13SJuan Quintela static int ide_drive_post_load(void *opaque, int version_id)
285259f2a787SGerd Hoffmann {
285337159f13SJuan Quintela IDEState *s = opaque;
285459f2a787SGerd Hoffmann
28556b896ab2SDon Slutz if (s->blk && s->identify_set) {
28564be74634SMarkus Armbruster blk_set_enable_write_cache(s->blk, !!(s->identify_data[85] & (1 << 5)));
28577cdd481cSPaolo Bonzini }
285837159f13SJuan Quintela return 0;
285937159f13SJuan Quintela }
286037159f13SJuan Quintela
ide_drive_pio_post_load(void * opaque,int version_id)286150641c5cSJuan Quintela static int ide_drive_pio_post_load(void *opaque, int version_id)
286250641c5cSJuan Quintela {
286350641c5cSJuan Quintela IDEState *s = opaque;
286450641c5cSJuan Quintela
2865fb60105dSKevin Wolf if (s->end_transfer_fn_idx >= ARRAY_SIZE(transfer_end_table)) {
286650641c5cSJuan Quintela return -EINVAL;
286750641c5cSJuan Quintela }
286850641c5cSJuan Quintela s->end_transfer_func = transfer_end_table[s->end_transfer_fn_idx];
286950641c5cSJuan Quintela s->data_ptr = s->io_buffer + s->cur_io_buffer_offset;
287050641c5cSJuan Quintela s->data_end = s->data_ptr + s->cur_io_buffer_len;
2871819fa276SDr. David Alan Gilbert s->atapi_dma = s->feature & 1; /* as per cmd_packet */
287250641c5cSJuan Quintela
287350641c5cSJuan Quintela return 0;
287450641c5cSJuan Quintela }
287550641c5cSJuan Quintela
ide_drive_pio_pre_save(void * opaque)287644b1ff31SDr. David Alan Gilbert static int ide_drive_pio_pre_save(void *opaque)
287750641c5cSJuan Quintela {
287850641c5cSJuan Quintela IDEState *s = opaque;
287950641c5cSJuan Quintela int idx;
288050641c5cSJuan Quintela
288150641c5cSJuan Quintela s->cur_io_buffer_offset = s->data_ptr - s->io_buffer;
288250641c5cSJuan Quintela s->cur_io_buffer_len = s->data_end - s->data_ptr;
288350641c5cSJuan Quintela
288450641c5cSJuan Quintela idx = transfer_end_table_idx(s->end_transfer_func);
288550641c5cSJuan Quintela if (idx == -1) {
288650641c5cSJuan Quintela fprintf(stderr, "%s: invalid end_transfer_func for DRQ_STAT\n",
288750641c5cSJuan Quintela __func__);
288850641c5cSJuan Quintela s->end_transfer_fn_idx = 2;
288950641c5cSJuan Quintela } else {
289050641c5cSJuan Quintela s->end_transfer_fn_idx = idx;
289150641c5cSJuan Quintela }
289244b1ff31SDr. David Alan Gilbert
289344b1ff31SDr. David Alan Gilbert return 0;
289450641c5cSJuan Quintela }
289550641c5cSJuan Quintela
ide_drive_pio_state_needed(void * opaque)289650641c5cSJuan Quintela static bool ide_drive_pio_state_needed(void *opaque)
289750641c5cSJuan Quintela {
289850641c5cSJuan Quintela IDEState *s = opaque;
289950641c5cSJuan Quintela
2900fdc650d7SKevin Wolf return ((s->status & DRQ_STAT) != 0)
2901fd648f10SPaolo Bonzini || (s->bus->error_status & IDE_RETRY_PIO);
290250641c5cSJuan Quintela }
290350641c5cSJuan Quintela
ide_tray_state_needed(void * opaque)2904db118fe7SMarkus Armbruster static bool ide_tray_state_needed(void *opaque)
2905db118fe7SMarkus Armbruster {
2906db118fe7SMarkus Armbruster IDEState *s = opaque;
2907db118fe7SMarkus Armbruster
2908db118fe7SMarkus Armbruster return s->tray_open || s->tray_locked;
2909db118fe7SMarkus Armbruster }
2910db118fe7SMarkus Armbruster
ide_atapi_gesn_needed(void * opaque)2911996faf1aSAmit Shah static bool ide_atapi_gesn_needed(void *opaque)
2912996faf1aSAmit Shah {
2913996faf1aSAmit Shah IDEState *s = opaque;
2914996faf1aSAmit Shah
2915996faf1aSAmit Shah return s->events.new_media || s->events.eject_request;
2916996faf1aSAmit Shah }
2917996faf1aSAmit Shah
ide_error_needed(void * opaque)2918def93791SKevin Wolf static bool ide_error_needed(void *opaque)
2919def93791SKevin Wolf {
2920def93791SKevin Wolf IDEBus *bus = opaque;
2921def93791SKevin Wolf
2922def93791SKevin Wolf return (bus->error_status != 0);
2923def93791SKevin Wolf }
2924def93791SKevin Wolf
2925996faf1aSAmit Shah /* Fields for GET_EVENT_STATUS_NOTIFICATION ATAPI command */
2926656fbeffSMarkus Armbruster static const VMStateDescription vmstate_ide_atapi_gesn_state = {
2927996faf1aSAmit Shah .name ="ide_drive/atapi/gesn_state",
2928996faf1aSAmit Shah .version_id = 1,
2929996faf1aSAmit Shah .minimum_version_id = 1,
29305cd8cadaSJuan Quintela .needed = ide_atapi_gesn_needed,
29318595c054SRichard Henderson .fields = (const VMStateField[]) {
2932996faf1aSAmit Shah VMSTATE_BOOL(events.new_media, IDEState),
2933996faf1aSAmit Shah VMSTATE_BOOL(events.eject_request, IDEState),
29340754f9ecSKevin Wolf VMSTATE_END_OF_LIST()
2935996faf1aSAmit Shah }
2936996faf1aSAmit Shah };
2937996faf1aSAmit Shah
2938db118fe7SMarkus Armbruster static const VMStateDescription vmstate_ide_tray_state = {
2939db118fe7SMarkus Armbruster .name = "ide_drive/tray_state",
2940db118fe7SMarkus Armbruster .version_id = 1,
2941db118fe7SMarkus Armbruster .minimum_version_id = 1,
29425cd8cadaSJuan Quintela .needed = ide_tray_state_needed,
29438595c054SRichard Henderson .fields = (const VMStateField[]) {
2944db118fe7SMarkus Armbruster VMSTATE_BOOL(tray_open, IDEState),
2945db118fe7SMarkus Armbruster VMSTATE_BOOL(tray_locked, IDEState),
2946db118fe7SMarkus Armbruster VMSTATE_END_OF_LIST()
2947db118fe7SMarkus Armbruster }
2948db118fe7SMarkus Armbruster };
2949db118fe7SMarkus Armbruster
2950656fbeffSMarkus Armbruster static const VMStateDescription vmstate_ide_drive_pio_state = {
295150641c5cSJuan Quintela .name = "ide_drive/pio_state",
295250641c5cSJuan Quintela .version_id = 1,
295350641c5cSJuan Quintela .minimum_version_id = 1,
295450641c5cSJuan Quintela .pre_save = ide_drive_pio_pre_save,
295550641c5cSJuan Quintela .post_load = ide_drive_pio_post_load,
29565cd8cadaSJuan Quintela .needed = ide_drive_pio_state_needed,
29578595c054SRichard Henderson .fields = (const VMStateField[]) {
295850641c5cSJuan Quintela VMSTATE_INT32(req_nb_sectors, IDEState),
295950641c5cSJuan Quintela VMSTATE_VARRAY_INT32(io_buffer, IDEState, io_buffer_total_len, 1,
296050641c5cSJuan Quintela vmstate_info_uint8, uint8_t),
296150641c5cSJuan Quintela VMSTATE_INT32(cur_io_buffer_offset, IDEState),
296250641c5cSJuan Quintela VMSTATE_INT32(cur_io_buffer_len, IDEState),
296350641c5cSJuan Quintela VMSTATE_UINT8(end_transfer_fn_idx, IDEState),
296450641c5cSJuan Quintela VMSTATE_INT32(elementary_transfer_size, IDEState),
296550641c5cSJuan Quintela VMSTATE_INT32(packet_transfer_size, IDEState),
296650641c5cSJuan Quintela VMSTATE_END_OF_LIST()
296750641c5cSJuan Quintela }
296850641c5cSJuan Quintela };
296950641c5cSJuan Quintela
297037159f13SJuan Quintela const VMStateDescription vmstate_ide_drive = {
297137159f13SJuan Quintela .name = "ide_drive",
29723abb6260SJuan Quintela .version_id = 3,
297337159f13SJuan Quintela .minimum_version_id = 0,
297437159f13SJuan Quintela .post_load = ide_drive_post_load,
29758595c054SRichard Henderson .fields = (const VMStateField[]) {
297637159f13SJuan Quintela VMSTATE_INT32(mult_sectors, IDEState),
297737159f13SJuan Quintela VMSTATE_INT32(identify_set, IDEState),
297837159f13SJuan Quintela VMSTATE_BUFFER_TEST(identify_data, IDEState, is_identify_set),
297937159f13SJuan Quintela VMSTATE_UINT8(feature, IDEState),
298037159f13SJuan Quintela VMSTATE_UINT8(error, IDEState),
298137159f13SJuan Quintela VMSTATE_UINT32(nsector, IDEState),
298237159f13SJuan Quintela VMSTATE_UINT8(sector, IDEState),
298337159f13SJuan Quintela VMSTATE_UINT8(lcyl, IDEState),
298437159f13SJuan Quintela VMSTATE_UINT8(hcyl, IDEState),
298537159f13SJuan Quintela VMSTATE_UINT8(hob_feature, IDEState),
298637159f13SJuan Quintela VMSTATE_UINT8(hob_sector, IDEState),
298737159f13SJuan Quintela VMSTATE_UINT8(hob_nsector, IDEState),
298837159f13SJuan Quintela VMSTATE_UINT8(hob_lcyl, IDEState),
298937159f13SJuan Quintela VMSTATE_UINT8(hob_hcyl, IDEState),
299037159f13SJuan Quintela VMSTATE_UINT8(select, IDEState),
299137159f13SJuan Quintela VMSTATE_UINT8(status, IDEState),
299237159f13SJuan Quintela VMSTATE_UINT8(lba48, IDEState),
299337159f13SJuan Quintela VMSTATE_UINT8(sense_key, IDEState),
299437159f13SJuan Quintela VMSTATE_UINT8(asc, IDEState),
299537159f13SJuan Quintela VMSTATE_UINT8_V(cdrom_changed, IDEState, 3),
299637159f13SJuan Quintela VMSTATE_END_OF_LIST()
299750641c5cSJuan Quintela },
29988595c054SRichard Henderson .subsections = (const VMStateDescription * const []) {
29995cd8cadaSJuan Quintela &vmstate_ide_drive_pio_state,
30005cd8cadaSJuan Quintela &vmstate_ide_tray_state,
30015cd8cadaSJuan Quintela &vmstate_ide_atapi_gesn_state,
30025cd8cadaSJuan Quintela NULL
300337159f13SJuan Quintela }
300437159f13SJuan Quintela };
300537159f13SJuan Quintela
3006656fbeffSMarkus Armbruster static const VMStateDescription vmstate_ide_error_status = {
3007def93791SKevin Wolf .name ="ide_bus/error",
3008d12b9ff2SPaolo Bonzini .version_id = 2,
3009def93791SKevin Wolf .minimum_version_id = 1,
30105cd8cadaSJuan Quintela .needed = ide_error_needed,
30118595c054SRichard Henderson .fields = (const VMStateField[]) {
3012def93791SKevin Wolf VMSTATE_INT32(error_status, IDEBus),
3013d12b9ff2SPaolo Bonzini VMSTATE_INT64_V(retry_sector_num, IDEBus, 2),
3014d12b9ff2SPaolo Bonzini VMSTATE_UINT32_V(retry_nsector, IDEBus, 2),
3015d12b9ff2SPaolo Bonzini VMSTATE_UINT8_V(retry_unit, IDEBus, 2),
3016def93791SKevin Wolf VMSTATE_END_OF_LIST()
3017def93791SKevin Wolf }
3018def93791SKevin Wolf };
3019def93791SKevin Wolf
30206521dc62SJuan Quintela const VMStateDescription vmstate_ide_bus = {
30216521dc62SJuan Quintela .name = "ide_bus",
30226521dc62SJuan Quintela .version_id = 1,
30236521dc62SJuan Quintela .minimum_version_id = 1,
30248595c054SRichard Henderson .fields = (const VMStateField[]) {
30256521dc62SJuan Quintela VMSTATE_UINT8(cmd, IDEBus),
30266521dc62SJuan Quintela VMSTATE_UINT8(unit, IDEBus),
30276521dc62SJuan Quintela VMSTATE_END_OF_LIST()
3028def93791SKevin Wolf },
30298595c054SRichard Henderson .subsections = (const VMStateDescription * const []) {
30305cd8cadaSJuan Quintela &vmstate_ide_error_status,
30315cd8cadaSJuan Quintela NULL
30326521dc62SJuan Quintela }
30336521dc62SJuan Quintela };
303475717903SIsaku Yamahata
ide_drive_get(DriveInfo ** hd,int n)3035d8f94e1bSJohn Snow void ide_drive_get(DriveInfo **hd, int n)
303675717903SIsaku Yamahata {
303775717903SIsaku Yamahata int i;
303875717903SIsaku Yamahata
3039d8f94e1bSJohn Snow for (i = 0; i < n; i++) {
3040d8f94e1bSJohn Snow hd[i] = drive_get_by_index(IF_IDE, i);
304175717903SIsaku Yamahata }
304275717903SIsaku Yamahata }
3043