xref: /openbmc/qemu/hw/ide/core.c (revision 75524884)
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"
44a9c94277SMarkus Armbruster #include "hw/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 
84*75524884SMark Cave-Ayland const MemoryRegionPortio ide_portio_list[] = {
85*75524884SMark Cave-Ayland     { 0, 8, 1, .read = ide_ioport_read, .write = ide_ioport_write },
86*75524884SMark Cave-Ayland     { 0, 1, 2, .read = ide_data_readw, .write = ide_data_writew },
87*75524884SMark Cave-Ayland     { 0, 1, 4, .read = ide_data_readl, .write = ide_data_writel },
88*75524884SMark Cave-Ayland     PORTIO_END_OF_LIST(),
89*75524884SMark Cave-Ayland };
90*75524884SMark Cave-Ayland 
91*75524884SMark Cave-Ayland const MemoryRegionPortio ide_portio2_list[] = {
92*75524884SMark Cave-Ayland     { 0, 1, 1, .read = ide_status_read, .write = ide_ctrl_write },
93*75524884SMark Cave-Ayland     PORTIO_END_OF_LIST(),
94*75524884SMark Cave-Ayland };
95*75524884SMark 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 
106259f2a787SGerd Hoffmann     if (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);
162663a82e6aSKevin Wolf         return true;
162763a82e6aSKevin Wolf     }
162863a82e6aSKevin Wolf 
162963a82e6aSKevin Wolf     ide_cmd_lba48_transform(s, lba48);
163063a82e6aSKevin Wolf     ide_set_sector(s, s->nb_sectors - 1);
163163a82e6aSKevin Wolf 
163263a82e6aSKevin Wolf     return true;
163363a82e6aSKevin Wolf }
163463a82e6aSKevin Wolf 
cmd_check_power_mode(IDEState * s,uint8_t cmd)1635785f6320SKevin Wolf static bool cmd_check_power_mode(IDEState *s, uint8_t cmd)
1636785f6320SKevin Wolf {
1637785f6320SKevin Wolf     s->nsector = 0xff; /* device active or idle */
1638785f6320SKevin Wolf     return true;
1639785f6320SKevin Wolf }
1640785f6320SKevin Wolf 
1641176e4961SLev Kujawski /* INITIALIZE DEVICE PARAMETERS */
cmd_specify(IDEState * s,uint8_t cmd)1642176e4961SLev Kujawski static bool cmd_specify(IDEState *s, uint8_t cmd)
1643176e4961SLev Kujawski {
1644176e4961SLev Kujawski     if (s->blk && s->drive_kind != IDE_CD) {
1645176e4961SLev Kujawski         s->heads = (s->select & (ATA_DEV_HS)) + 1;
1646176e4961SLev Kujawski         s->sectors = s->nsector;
16470cfe719dSPhilippe Mathieu-Daudé         ide_bus_set_irq(s->bus);
1648176e4961SLev Kujawski     } else {
1649176e4961SLev Kujawski         ide_abort_command(s);
1650176e4961SLev Kujawski     }
1651176e4961SLev Kujawski 
1652176e4961SLev Kujawski     return true;
1653176e4961SLev Kujawski }
1654176e4961SLev Kujawski 
cmd_set_features(IDEState * s,uint8_t cmd)1655ee03398cSKevin Wolf static bool cmd_set_features(IDEState *s, uint8_t cmd)
1656ee03398cSKevin Wolf {
1657ee03398cSKevin Wolf     uint16_t *identify_data;
1658ee03398cSKevin Wolf 
16594be74634SMarkus Armbruster     if (!s->blk) {
1660ee03398cSKevin Wolf         ide_abort_command(s);
1661ee03398cSKevin Wolf         return true;
1662ee03398cSKevin Wolf     }
1663ee03398cSKevin Wolf 
1664ee03398cSKevin Wolf     /* XXX: valid for CDROM ? */
1665ee03398cSKevin Wolf     switch (s->feature) {
16661ea17d22SLubomir Rintel     case 0x01: /* 8-bit I/O enable (CompactFlash) */
16671ea17d22SLubomir Rintel     case 0x81: /* 8-bit I/O disable (CompactFlash) */
16681ea17d22SLubomir Rintel         if (s->drive_kind != IDE_CFATA) {
16691ea17d22SLubomir Rintel             goto abort_cmd;
16701ea17d22SLubomir Rintel         }
16711ea17d22SLubomir Rintel         s->io8 = !(s->feature & 0x80);
16721ea17d22SLubomir Rintel         return true;
1673ee03398cSKevin Wolf     case 0x02: /* write cache enable */
16744be74634SMarkus Armbruster         blk_set_enable_write_cache(s->blk, true);
1675ee03398cSKevin Wolf         identify_data = (uint16_t *)s->identify_data;
1676ee03398cSKevin Wolf         put_le16(identify_data + 85, (1 << 14) | (1 << 5) | 1);
1677ee03398cSKevin Wolf         return true;
1678ee03398cSKevin Wolf     case 0x82: /* write cache disable */
16794be74634SMarkus Armbruster         blk_set_enable_write_cache(s->blk, false);
1680ee03398cSKevin Wolf         identify_data = (uint16_t *)s->identify_data;
1681ee03398cSKevin Wolf         put_le16(identify_data + 85, (1 << 14) | 1);
1682ee03398cSKevin Wolf         ide_flush_cache(s);
1683ee03398cSKevin Wolf         return false;
1684ee03398cSKevin Wolf     case 0xcc: /* reverting to power-on defaults enable */
1685176e4961SLev Kujawski         s->reset_reverts = true;
1686176e4961SLev Kujawski         return true;
1687ee03398cSKevin Wolf     case 0x66: /* reverting to power-on defaults disable */
1688176e4961SLev Kujawski         s->reset_reverts = false;
1689176e4961SLev Kujawski         return true;
1690ee03398cSKevin Wolf     case 0xaa: /* read look-ahead enable */
1691ee03398cSKevin Wolf     case 0x55: /* read look-ahead disable */
1692ee03398cSKevin Wolf     case 0x05: /* set advanced power management mode */
1693ee03398cSKevin Wolf     case 0x85: /* disable advanced power management mode */
1694ee03398cSKevin Wolf     case 0x69: /* NOP */
1695ee03398cSKevin Wolf     case 0x67: /* NOP */
1696ee03398cSKevin Wolf     case 0x96: /* NOP */
1697ee03398cSKevin Wolf     case 0x9a: /* NOP */
1698ee03398cSKevin Wolf     case 0x42: /* enable Automatic Acoustic Mode */
1699ee03398cSKevin Wolf     case 0xc2: /* disable Automatic Acoustic Mode */
1700ee03398cSKevin Wolf         return true;
1701ee03398cSKevin Wolf     case 0x03: /* set transfer mode */
1702ee03398cSKevin Wolf         {
1703ee03398cSKevin Wolf             uint8_t val = s->nsector & 0x07;
1704ee03398cSKevin Wolf             identify_data = (uint16_t *)s->identify_data;
1705ee03398cSKevin Wolf 
1706ee03398cSKevin Wolf             switch (s->nsector >> 3) {
1707ee03398cSKevin Wolf             case 0x00: /* pio default */
1708ee03398cSKevin Wolf             case 0x01: /* pio mode */
1709ee03398cSKevin Wolf                 put_le16(identify_data + 62, 0x07);
1710ee03398cSKevin Wolf                 put_le16(identify_data + 63, 0x07);
1711ee03398cSKevin Wolf                 put_le16(identify_data + 88, 0x3f);
1712ee03398cSKevin Wolf                 break;
1713a980b95cSMichael Tokarev             case 0x02: /* single word dma mode */
1714ee03398cSKevin Wolf                 put_le16(identify_data + 62, 0x07 | (1 << (val + 8)));
1715ee03398cSKevin Wolf                 put_le16(identify_data + 63, 0x07);
1716ee03398cSKevin Wolf                 put_le16(identify_data + 88, 0x3f);
1717ee03398cSKevin Wolf                 break;
1718ee03398cSKevin Wolf             case 0x04: /* mdma mode */
1719ee03398cSKevin Wolf                 put_le16(identify_data + 62, 0x07);
1720ee03398cSKevin Wolf                 put_le16(identify_data + 63, 0x07 | (1 << (val + 8)));
1721ee03398cSKevin Wolf                 put_le16(identify_data + 88, 0x3f);
1722ee03398cSKevin Wolf                 break;
1723ee03398cSKevin Wolf             case 0x08: /* udma mode */
1724ee03398cSKevin Wolf                 put_le16(identify_data + 62, 0x07);
1725ee03398cSKevin Wolf                 put_le16(identify_data + 63, 0x07);
1726ee03398cSKevin Wolf                 put_le16(identify_data + 88, 0x3f | (1 << (val + 8)));
1727ee03398cSKevin Wolf                 break;
1728ee03398cSKevin Wolf             default:
1729ee03398cSKevin Wolf                 goto abort_cmd;
1730ee03398cSKevin Wolf             }
1731ee03398cSKevin Wolf             return true;
1732ee03398cSKevin Wolf         }
1733ee03398cSKevin Wolf     }
1734ee03398cSKevin Wolf 
1735ee03398cSKevin Wolf abort_cmd:
1736ee03398cSKevin Wolf     ide_abort_command(s);
1737ee03398cSKevin Wolf     return true;
1738ee03398cSKevin Wolf }
1739ee03398cSKevin Wolf 
1740ee425c78SKevin Wolf 
1741ee425c78SKevin Wolf /*** ATAPI commands ***/
1742ee425c78SKevin Wolf 
cmd_identify_packet(IDEState * s,uint8_t cmd)1743ee425c78SKevin Wolf static bool cmd_identify_packet(IDEState *s, uint8_t cmd)
1744ee425c78SKevin Wolf {
1745ee425c78SKevin Wolf     ide_atapi_identify(s);
1746ee425c78SKevin Wolf     s->status = READY_STAT | SEEK_STAT;
1747ee425c78SKevin Wolf     ide_transfer_start(s, s->io_buffer, 512, ide_transfer_stop);
17480cfe719dSPhilippe Mathieu-Daudé     ide_bus_set_irq(s->bus);
1749ee425c78SKevin Wolf     return false;
1750ee425c78SKevin Wolf }
1751ee425c78SKevin Wolf 
17523195c9e6SLev Kujawski /* EXECUTE DEVICE DIAGNOSTIC */
cmd_exec_dev_diagnostic(IDEState * s,uint8_t cmd)1753ee425c78SKevin Wolf static bool cmd_exec_dev_diagnostic(IDEState *s, uint8_t cmd)
1754ee425c78SKevin Wolf {
17553195c9e6SLev Kujawski     /*
17563195c9e6SLev Kujawski      * Clear the device register per the ATA (v6) specification,
17573195c9e6SLev Kujawski      * because ide_set_signature does not clear LBA or drive bits.
17583195c9e6SLev Kujawski      */
17593195c9e6SLev Kujawski     s->select = (ATA_DEV_ALWAYS_ON);
1760ee425c78SKevin Wolf     ide_set_signature(s);
1761ee425c78SKevin Wolf 
1762ee425c78SKevin Wolf     if (s->drive_kind == IDE_CD) {
1763ee425c78SKevin Wolf         s->status = 0; /* ATAPI spec (v6) section 9.10 defines packet
1764ee425c78SKevin Wolf                         * devices to return a clear status register
1765ee425c78SKevin Wolf                         * with READY_STAT *not* set. */
1766850484a2SDavid du Colombier         s->error = 0x01;
1767ee425c78SKevin Wolf     } else {
1768ee425c78SKevin Wolf         s->status = READY_STAT | SEEK_STAT;
1769ee425c78SKevin Wolf         /* The bits of the error register are not as usual for this command!
1770ee425c78SKevin Wolf          * They are part of the regular output (this is why ERR_STAT isn't set)
1771ee425c78SKevin Wolf          * Device 0 passed, Device 1 passed or not present. */
1772ee425c78SKevin Wolf         s->error = 0x01;
17730cfe719dSPhilippe Mathieu-Daudé         ide_bus_set_irq(s->bus);
1774ee425c78SKevin Wolf     }
1775ee425c78SKevin Wolf 
1776ee425c78SKevin Wolf     return false;
1777ee425c78SKevin Wolf }
1778ee425c78SKevin Wolf 
cmd_packet(IDEState * s,uint8_t cmd)1779ee425c78SKevin Wolf static bool cmd_packet(IDEState *s, uint8_t cmd)
1780ee425c78SKevin Wolf {
1781ee425c78SKevin Wolf     /* overlapping commands not supported */
1782ee425c78SKevin Wolf     if (s->feature & 0x02) {
1783ee425c78SKevin Wolf         ide_abort_command(s);
1784ee425c78SKevin Wolf         return true;
1785ee425c78SKevin Wolf     }
1786ee425c78SKevin Wolf 
1787ee425c78SKevin Wolf     s->status = READY_STAT | SEEK_STAT;
1788ee425c78SKevin Wolf     s->atapi_dma = s->feature & 1;
1789502356eeSPavel Butsykin     if (s->atapi_dma) {
1790502356eeSPavel Butsykin         s->dma_cmd = IDE_DMA_ATAPI;
1791502356eeSPavel Butsykin     }
1792ee425c78SKevin Wolf     s->nsector = 1;
1793ee425c78SKevin Wolf     ide_transfer_start(s, s->io_buffer, ATAPI_PACKET_SIZE,
1794ee425c78SKevin Wolf                        ide_atapi_cmd);
1795ee425c78SKevin Wolf     return false;
1796ee425c78SKevin Wolf }
1797ee425c78SKevin Wolf 
17986b1dd744SKevin Wolf 
17996b1dd744SKevin Wolf /*** CF-ATA commands ***/
18006b1dd744SKevin Wolf 
cmd_cfa_req_ext_error_code(IDEState * s,uint8_t cmd)18016b1dd744SKevin Wolf static bool cmd_cfa_req_ext_error_code(IDEState *s, uint8_t cmd)
18026b1dd744SKevin Wolf {
18036b1dd744SKevin Wolf     s->error = 0x09;    /* miscellaneous error */
18046b1dd744SKevin Wolf     s->status = READY_STAT | SEEK_STAT;
18050cfe719dSPhilippe Mathieu-Daudé     ide_bus_set_irq(s->bus);
18066b1dd744SKevin Wolf 
18076b1dd744SKevin Wolf     return false;
18086b1dd744SKevin Wolf }
18096b1dd744SKevin Wolf 
cmd_cfa_erase_sectors(IDEState * s,uint8_t cmd)18106b1dd744SKevin Wolf static bool cmd_cfa_erase_sectors(IDEState *s, uint8_t cmd)
18116b1dd744SKevin Wolf {
18126b1dd744SKevin Wolf     /* WIN_SECURITY_FREEZE_LOCK has the same ID as CFA_WEAR_LEVEL and is
18136b1dd744SKevin Wolf      * required for Windows 8 to work with AHCI */
18146b1dd744SKevin Wolf 
18156b1dd744SKevin Wolf     if (cmd == CFA_WEAR_LEVEL) {
18166b1dd744SKevin Wolf         s->nsector = 0;
18176b1dd744SKevin Wolf     }
18186b1dd744SKevin Wolf 
18196b1dd744SKevin Wolf     if (cmd == CFA_ERASE_SECTORS) {
18206b1dd744SKevin Wolf         s->media_changed = 1;
18216b1dd744SKevin Wolf     }
18226b1dd744SKevin Wolf 
18236b1dd744SKevin Wolf     return true;
18246b1dd744SKevin Wolf }
18256b1dd744SKevin Wolf 
cmd_cfa_translate_sector(IDEState * s,uint8_t cmd)18266b1dd744SKevin Wolf static bool cmd_cfa_translate_sector(IDEState *s, uint8_t cmd)
18276b1dd744SKevin Wolf {
18286b1dd744SKevin Wolf     s->status = READY_STAT | SEEK_STAT;
18296b1dd744SKevin Wolf 
18306b1dd744SKevin Wolf     memset(s->io_buffer, 0, 0x200);
18316b1dd744SKevin Wolf     s->io_buffer[0x00] = s->hcyl;                   /* Cyl MSB */
18326b1dd744SKevin Wolf     s->io_buffer[0x01] = s->lcyl;                   /* Cyl LSB */
18336b1dd744SKevin Wolf     s->io_buffer[0x02] = s->select;                 /* Head */
18346b1dd744SKevin Wolf     s->io_buffer[0x03] = s->sector;                 /* Sector */
18356b1dd744SKevin Wolf     s->io_buffer[0x04] = ide_get_sector(s) >> 16;   /* LBA MSB */
18366b1dd744SKevin Wolf     s->io_buffer[0x05] = ide_get_sector(s) >> 8;    /* LBA */
18376b1dd744SKevin Wolf     s->io_buffer[0x06] = ide_get_sector(s) >> 0;    /* LBA LSB */
18386b1dd744SKevin Wolf     s->io_buffer[0x13] = 0x00;                      /* Erase flag */
18396b1dd744SKevin Wolf     s->io_buffer[0x18] = 0x00;                      /* Hot count */
18406b1dd744SKevin Wolf     s->io_buffer[0x19] = 0x00;                      /* Hot count */
18416b1dd744SKevin Wolf     s->io_buffer[0x1a] = 0x01;                      /* Hot count */
18426b1dd744SKevin Wolf 
18436b1dd744SKevin Wolf     ide_transfer_start(s, s->io_buffer, 0x200, ide_transfer_stop);
18440cfe719dSPhilippe Mathieu-Daudé     ide_bus_set_irq(s->bus);
18456b1dd744SKevin Wolf 
18466b1dd744SKevin Wolf     return false;
18476b1dd744SKevin Wolf }
18486b1dd744SKevin Wolf 
cmd_cfa_access_metadata_storage(IDEState * s,uint8_t cmd)18496b1dd744SKevin Wolf static bool cmd_cfa_access_metadata_storage(IDEState *s, uint8_t cmd)
18506b1dd744SKevin Wolf {
18516b1dd744SKevin Wolf     switch (s->feature) {
18526b1dd744SKevin Wolf     case 0x02:  /* Inquiry Metadata Storage */
18536b1dd744SKevin Wolf         ide_cfata_metadata_inquiry(s);
18546b1dd744SKevin Wolf         break;
18556b1dd744SKevin Wolf     case 0x03:  /* Read Metadata Storage */
18566b1dd744SKevin Wolf         ide_cfata_metadata_read(s);
18576b1dd744SKevin Wolf         break;
18586b1dd744SKevin Wolf     case 0x04:  /* Write Metadata Storage */
18596b1dd744SKevin Wolf         ide_cfata_metadata_write(s);
18606b1dd744SKevin Wolf         break;
18616b1dd744SKevin Wolf     default:
18626b1dd744SKevin Wolf         ide_abort_command(s);
18636b1dd744SKevin Wolf         return true;
18646b1dd744SKevin Wolf     }
18656b1dd744SKevin Wolf 
18666b1dd744SKevin Wolf     ide_transfer_start(s, s->io_buffer, 0x200, ide_transfer_stop);
18676b1dd744SKevin Wolf     s->status = 0x00; /* NOTE: READY is _not_ set */
18680cfe719dSPhilippe Mathieu-Daudé     ide_bus_set_irq(s->bus);
18696b1dd744SKevin Wolf 
18706b1dd744SKevin Wolf     return false;
18716b1dd744SKevin Wolf }
18726b1dd744SKevin Wolf 
cmd_ibm_sense_condition(IDEState * s,uint8_t cmd)18736b1dd744SKevin Wolf static bool cmd_ibm_sense_condition(IDEState *s, uint8_t cmd)
18746b1dd744SKevin Wolf {
18756b1dd744SKevin Wolf     switch (s->feature) {
18766b1dd744SKevin Wolf     case 0x01:  /* sense temperature in device */
18776b1dd744SKevin Wolf         s->nsector = 0x50;      /* +20 C */
18786b1dd744SKevin Wolf         break;
18796b1dd744SKevin Wolf     default:
18806b1dd744SKevin Wolf         ide_abort_command(s);
18816b1dd744SKevin Wolf         return true;
18826b1dd744SKevin Wolf     }
18836b1dd744SKevin Wolf 
18846b1dd744SKevin Wolf     return true;
18856b1dd744SKevin Wolf }
18866b1dd744SKevin Wolf 
1887ff352677SKevin Wolf 
1888ff352677SKevin Wolf /*** SMART commands ***/
1889ff352677SKevin Wolf 
cmd_smart(IDEState * s,uint8_t cmd)1890ff352677SKevin Wolf static bool cmd_smart(IDEState *s, uint8_t cmd)
1891ff352677SKevin Wolf {
1892ff352677SKevin Wolf     int n;
1893ff352677SKevin Wolf 
1894ff352677SKevin Wolf     if (s->hcyl != 0xc2 || s->lcyl != 0x4f) {
1895ff352677SKevin Wolf         goto abort_cmd;
1896ff352677SKevin Wolf     }
1897ff352677SKevin Wolf 
1898ff352677SKevin Wolf     if (!s->smart_enabled && s->feature != SMART_ENABLE) {
1899ff352677SKevin Wolf         goto abort_cmd;
1900ff352677SKevin Wolf     }
1901ff352677SKevin Wolf 
1902ff352677SKevin Wolf     switch (s->feature) {
1903ff352677SKevin Wolf     case SMART_DISABLE:
1904ff352677SKevin Wolf         s->smart_enabled = 0;
1905ff352677SKevin Wolf         return true;
1906ff352677SKevin Wolf 
1907ff352677SKevin Wolf     case SMART_ENABLE:
1908ff352677SKevin Wolf         s->smart_enabled = 1;
1909ff352677SKevin Wolf         return true;
1910ff352677SKevin Wolf 
1911ff352677SKevin Wolf     case SMART_ATTR_AUTOSAVE:
1912ff352677SKevin Wolf         switch (s->sector) {
1913ff352677SKevin Wolf         case 0x00:
1914ff352677SKevin Wolf             s->smart_autosave = 0;
1915ff352677SKevin Wolf             break;
1916ff352677SKevin Wolf         case 0xf1:
1917ff352677SKevin Wolf             s->smart_autosave = 1;
1918ff352677SKevin Wolf             break;
1919ff352677SKevin Wolf         default:
1920ff352677SKevin Wolf             goto abort_cmd;
1921ff352677SKevin Wolf         }
1922ff352677SKevin Wolf         return true;
1923ff352677SKevin Wolf 
1924ff352677SKevin Wolf     case SMART_STATUS:
1925ff352677SKevin Wolf         if (!s->smart_errors) {
1926ff352677SKevin Wolf             s->hcyl = 0xc2;
1927ff352677SKevin Wolf             s->lcyl = 0x4f;
1928ff352677SKevin Wolf         } else {
1929ff352677SKevin Wolf             s->hcyl = 0x2c;
1930ff352677SKevin Wolf             s->lcyl = 0xf4;
1931ff352677SKevin Wolf         }
1932ff352677SKevin Wolf         return true;
1933ff352677SKevin Wolf 
1934ff352677SKevin Wolf     case SMART_READ_THRESH:
1935ff352677SKevin Wolf         memset(s->io_buffer, 0, 0x200);
1936ff352677SKevin Wolf         s->io_buffer[0] = 0x01; /* smart struct version */
1937ff352677SKevin Wolf 
1938ff352677SKevin Wolf         for (n = 0; n < ARRAY_SIZE(smart_attributes); n++) {
1939ff352677SKevin Wolf             s->io_buffer[2 + 0 + (n * 12)] = smart_attributes[n][0];
1940ff352677SKevin Wolf             s->io_buffer[2 + 1 + (n * 12)] = smart_attributes[n][11];
1941ff352677SKevin Wolf         }
1942ff352677SKevin Wolf 
1943ff352677SKevin Wolf         /* checksum */
1944ff352677SKevin Wolf         for (n = 0; n < 511; n++) {
1945ff352677SKevin Wolf             s->io_buffer[511] += s->io_buffer[n];
1946ff352677SKevin Wolf         }
1947ff352677SKevin Wolf         s->io_buffer[511] = 0x100 - s->io_buffer[511];
1948ff352677SKevin Wolf 
1949ff352677SKevin Wolf         s->status = READY_STAT | SEEK_STAT;
1950ff352677SKevin Wolf         ide_transfer_start(s, s->io_buffer, 0x200, ide_transfer_stop);
19510cfe719dSPhilippe Mathieu-Daudé         ide_bus_set_irq(s->bus);
1952ff352677SKevin Wolf         return false;
1953ff352677SKevin Wolf 
1954ff352677SKevin Wolf     case SMART_READ_DATA:
1955ff352677SKevin Wolf         memset(s->io_buffer, 0, 0x200);
1956ff352677SKevin Wolf         s->io_buffer[0] = 0x01; /* smart struct version */
1957ff352677SKevin Wolf 
1958ff352677SKevin Wolf         for (n = 0; n < ARRAY_SIZE(smart_attributes); n++) {
1959ff352677SKevin Wolf             int i;
1960ff352677SKevin Wolf             for (i = 0; i < 11; i++) {
1961ff352677SKevin Wolf                 s->io_buffer[2 + i + (n * 12)] = smart_attributes[n][i];
1962ff352677SKevin Wolf             }
1963ff352677SKevin Wolf         }
1964ff352677SKevin Wolf 
1965ff352677SKevin Wolf         s->io_buffer[362] = 0x02 | (s->smart_autosave ? 0x80 : 0x00);
1966ff352677SKevin Wolf         if (s->smart_selftest_count == 0) {
1967ff352677SKevin Wolf             s->io_buffer[363] = 0;
1968ff352677SKevin Wolf         } else {
1969ff352677SKevin Wolf             s->io_buffer[363] =
1970ff352677SKevin Wolf                 s->smart_selftest_data[3 +
1971ff352677SKevin Wolf                            (s->smart_selftest_count - 1) *
1972ff352677SKevin Wolf                            24];
1973ff352677SKevin Wolf         }
1974ff352677SKevin Wolf         s->io_buffer[364] = 0x20;
1975ff352677SKevin Wolf         s->io_buffer[365] = 0x01;
1976ff352677SKevin Wolf         /* offline data collection capacity: execute + self-test*/
1977ff352677SKevin Wolf         s->io_buffer[367] = (1 << 4 | 1 << 3 | 1);
1978ff352677SKevin Wolf         s->io_buffer[368] = 0x03; /* smart capability (1) */
1979ff352677SKevin Wolf         s->io_buffer[369] = 0x00; /* smart capability (2) */
1980ff352677SKevin Wolf         s->io_buffer[370] = 0x01; /* error logging supported */
1981ff352677SKevin Wolf         s->io_buffer[372] = 0x02; /* minutes for poll short test */
1982ff352677SKevin Wolf         s->io_buffer[373] = 0x36; /* minutes for poll ext test */
1983ff352677SKevin Wolf         s->io_buffer[374] = 0x01; /* minutes for poll conveyance */
1984ff352677SKevin Wolf 
1985ff352677SKevin Wolf         for (n = 0; n < 511; n++) {
1986ff352677SKevin Wolf             s->io_buffer[511] += s->io_buffer[n];
1987ff352677SKevin Wolf         }
1988ff352677SKevin Wolf         s->io_buffer[511] = 0x100 - s->io_buffer[511];
1989ff352677SKevin Wolf 
1990ff352677SKevin Wolf         s->status = READY_STAT | SEEK_STAT;
1991ff352677SKevin Wolf         ide_transfer_start(s, s->io_buffer, 0x200, ide_transfer_stop);
19920cfe719dSPhilippe Mathieu-Daudé         ide_bus_set_irq(s->bus);
1993ff352677SKevin Wolf         return false;
1994ff352677SKevin Wolf 
1995ff352677SKevin Wolf     case SMART_READ_LOG:
1996ff352677SKevin Wolf         switch (s->sector) {
1997ff352677SKevin Wolf         case 0x01: /* summary smart error log */
1998ff352677SKevin Wolf             memset(s->io_buffer, 0, 0x200);
1999ff352677SKevin Wolf             s->io_buffer[0] = 0x01;
2000ff352677SKevin Wolf             s->io_buffer[1] = 0x00; /* no error entries */
2001ff352677SKevin Wolf             s->io_buffer[452] = s->smart_errors & 0xff;
2002ff352677SKevin Wolf             s->io_buffer[453] = (s->smart_errors & 0xff00) >> 8;
2003ff352677SKevin Wolf 
2004ff352677SKevin Wolf             for (n = 0; n < 511; n++) {
2005ff352677SKevin Wolf                 s->io_buffer[511] += s->io_buffer[n];
2006ff352677SKevin Wolf             }
2007ff352677SKevin Wolf             s->io_buffer[511] = 0x100 - s->io_buffer[511];
2008ff352677SKevin Wolf             break;
2009ff352677SKevin Wolf         case 0x06: /* smart self test log */
2010ff352677SKevin Wolf             memset(s->io_buffer, 0, 0x200);
2011ff352677SKevin Wolf             s->io_buffer[0] = 0x01;
2012ff352677SKevin Wolf             if (s->smart_selftest_count == 0) {
2013ff352677SKevin Wolf                 s->io_buffer[508] = 0;
2014ff352677SKevin Wolf             } else {
2015ff352677SKevin Wolf                 s->io_buffer[508] = s->smart_selftest_count;
2016ff352677SKevin Wolf                 for (n = 2; n < 506; n++)  {
2017ff352677SKevin Wolf                     s->io_buffer[n] = s->smart_selftest_data[n];
2018ff352677SKevin Wolf                 }
2019ff352677SKevin Wolf             }
2020ff352677SKevin Wolf 
2021ff352677SKevin Wolf             for (n = 0; n < 511; n++) {
2022ff352677SKevin Wolf                 s->io_buffer[511] += s->io_buffer[n];
2023ff352677SKevin Wolf             }
2024ff352677SKevin Wolf             s->io_buffer[511] = 0x100 - s->io_buffer[511];
2025ff352677SKevin Wolf             break;
2026ff352677SKevin Wolf         default:
2027ff352677SKevin Wolf             goto abort_cmd;
2028ff352677SKevin Wolf         }
2029ff352677SKevin Wolf         s->status = READY_STAT | SEEK_STAT;
2030ff352677SKevin Wolf         ide_transfer_start(s, s->io_buffer, 0x200, ide_transfer_stop);
20310cfe719dSPhilippe Mathieu-Daudé         ide_bus_set_irq(s->bus);
2032ff352677SKevin Wolf         return false;
2033ff352677SKevin Wolf 
2034ff352677SKevin Wolf     case SMART_EXECUTE_OFFLINE:
2035ff352677SKevin Wolf         switch (s->sector) {
2036ff352677SKevin Wolf         case 0: /* off-line routine */
2037ff352677SKevin Wolf         case 1: /* short self test */
2038ff352677SKevin Wolf         case 2: /* extended self test */
2039ff352677SKevin Wolf             s->smart_selftest_count++;
2040ff352677SKevin Wolf             if (s->smart_selftest_count > 21) {
2041940973aeSBenoît Canet                 s->smart_selftest_count = 1;
2042ff352677SKevin Wolf             }
2043ff352677SKevin Wolf             n = 2 + (s->smart_selftest_count - 1) * 24;
2044ff352677SKevin Wolf             s->smart_selftest_data[n] = s->sector;
2045ff352677SKevin Wolf             s->smart_selftest_data[n + 1] = 0x00; /* OK and finished */
2046ff352677SKevin Wolf             s->smart_selftest_data[n + 2] = 0x34; /* hour count lsb */
2047ff352677SKevin Wolf             s->smart_selftest_data[n + 3] = 0x12; /* hour count msb */
2048ff352677SKevin Wolf             break;
2049ff352677SKevin Wolf         default:
2050ff352677SKevin Wolf             goto abort_cmd;
2051ff352677SKevin Wolf         }
2052ff352677SKevin Wolf         return true;
2053ff352677SKevin Wolf     }
2054ff352677SKevin Wolf 
2055ff352677SKevin Wolf abort_cmd:
2056ff352677SKevin Wolf     ide_abort_command(s);
2057ff352677SKevin Wolf     return true;
2058ff352677SKevin Wolf }
2059ff352677SKevin Wolf 
2060844505b1SMarkus Armbruster #define HD_OK (1u << IDE_HD)
2061844505b1SMarkus Armbruster #define CD_OK (1u << IDE_CD)
2062844505b1SMarkus Armbruster #define CFA_OK (1u << IDE_CFATA)
2063844505b1SMarkus Armbruster #define HD_CFA_OK (HD_OK | CFA_OK)
2064844505b1SMarkus Armbruster #define ALL_OK (HD_OK | CD_OK | CFA_OK)
2065844505b1SMarkus Armbruster 
2066a0436e92SKevin Wolf /* Set the Disk Seek Completed status bit during completion */
2067a0436e92SKevin Wolf #define SET_DSC (1u << 8)
2068a0436e92SKevin Wolf 
2069844505b1SMarkus Armbruster /* See ACS-2 T13/2015-D Table B.2 Command codes */
2070a0436e92SKevin Wolf static const struct {
2071a0436e92SKevin Wolf     /* Returns true if the completion code should be run */
2072a0436e92SKevin Wolf     bool (*handler)(IDEState *s, uint8_t cmd);
2073a0436e92SKevin Wolf     int flags;
2074a0436e92SKevin Wolf } ide_cmd_table[0x100] = {
2075844505b1SMarkus Armbruster     /* NOP not implemented, mandatory for CD */
20766b1dd744SKevin Wolf     [CFA_REQ_EXT_ERROR_CODE]      = { cmd_cfa_req_ext_error_code, CFA_OK },
2077d9033e1dSJohn Snow     [WIN_DSM]                     = { cmd_data_set_management, HD_CFA_OK },
2078ee425c78SKevin Wolf     [WIN_DEVICE_RESET]            = { cmd_device_reset, CD_OK },
2079b300337eSKevin Wolf     [WIN_RECAL]                   = { cmd_nop, HD_CFA_OK | SET_DSC},
20800e6498edSKevin Wolf     [WIN_READ]                    = { cmd_read_pio, ALL_OK },
2081d9033e1dSJohn Snow     [WIN_READ_ONCE]               = { cmd_read_pio, HD_CFA_OK },
20820e6498edSKevin Wolf     [WIN_READ_EXT]                = { cmd_read_pio, HD_CFA_OK },
208392a6a6f6SKevin Wolf     [WIN_READDMA_EXT]             = { cmd_read_dma, HD_CFA_OK },
208463a82e6aSKevin Wolf     [WIN_READ_NATIVE_MAX_EXT]     = { cmd_read_native_max, HD_CFA_OK | SET_DSC },
2085adf3a2c4SKevin Wolf     [WIN_MULTREAD_EXT]            = { cmd_read_multiple, HD_CFA_OK },
20860e6498edSKevin Wolf     [WIN_WRITE]                   = { cmd_write_pio, HD_CFA_OK },
20870e6498edSKevin Wolf     [WIN_WRITE_ONCE]              = { cmd_write_pio, HD_CFA_OK },
20880e6498edSKevin Wolf     [WIN_WRITE_EXT]               = { cmd_write_pio, HD_CFA_OK },
208992a6a6f6SKevin Wolf     [WIN_WRITEDMA_EXT]            = { cmd_write_dma, HD_CFA_OK },
20900e6498edSKevin Wolf     [CFA_WRITE_SECT_WO_ERASE]     = { cmd_write_pio, CFA_OK },
2091adf3a2c4SKevin Wolf     [WIN_MULTWRITE_EXT]           = { cmd_write_multiple, HD_CFA_OK },
20920e6498edSKevin Wolf     [WIN_WRITE_VERIFY]            = { cmd_write_pio, HD_CFA_OK },
2093413860cfSKevin Wolf     [WIN_VERIFY]                  = { cmd_verify, HD_CFA_OK | SET_DSC },
2094413860cfSKevin Wolf     [WIN_VERIFY_ONCE]             = { cmd_verify, HD_CFA_OK | SET_DSC },
2095413860cfSKevin Wolf     [WIN_VERIFY_EXT]              = { cmd_verify, HD_CFA_OK | SET_DSC },
209661fdda37SKevin Wolf     [WIN_SEEK]                    = { cmd_seek, HD_CFA_OK | SET_DSC },
20976b1dd744SKevin Wolf     [CFA_TRANSLATE_SECTOR]        = { cmd_cfa_translate_sector, CFA_OK },
2098ee425c78SKevin Wolf     [WIN_DIAGNOSE]                = { cmd_exec_dev_diagnostic, ALL_OK },
2099176e4961SLev Kujawski     [WIN_SPECIFY]                 = { cmd_specify, HD_CFA_OK | SET_DSC },
2100d9033e1dSJohn Snow     [WIN_STANDBYNOW2]             = { cmd_nop, HD_CFA_OK },
2101d9033e1dSJohn Snow     [WIN_IDLEIMMEDIATE2]          = { cmd_nop, HD_CFA_OK },
2102d9033e1dSJohn Snow     [WIN_STANDBY2]                = { cmd_nop, HD_CFA_OK },
2103d9033e1dSJohn Snow     [WIN_SETIDLE2]                = { cmd_nop, HD_CFA_OK },
2104d9033e1dSJohn Snow     [WIN_CHECKPOWERMODE2]         = { cmd_check_power_mode, HD_CFA_OK | SET_DSC },
2105d9033e1dSJohn Snow     [WIN_SLEEPNOW2]               = { cmd_nop, HD_CFA_OK },
2106ee425c78SKevin Wolf     [WIN_PACKETCMD]               = { cmd_packet, CD_OK },
2107ee425c78SKevin Wolf     [WIN_PIDENTIFY]               = { cmd_identify_packet, CD_OK },
2108ff352677SKevin Wolf     [WIN_SMART]                   = { cmd_smart, HD_CFA_OK | SET_DSC },
21096b1dd744SKevin Wolf     [CFA_ACCESS_METADATA_STORAGE] = { cmd_cfa_access_metadata_storage, CFA_OK },
21106b1dd744SKevin Wolf     [CFA_ERASE_SECTORS]           = { cmd_cfa_erase_sectors, CFA_OK | SET_DSC },
2111adf3a2c4SKevin Wolf     [WIN_MULTREAD]                = { cmd_read_multiple, HD_CFA_OK },
2112adf3a2c4SKevin Wolf     [WIN_MULTWRITE]               = { cmd_write_multiple, HD_CFA_OK },
2113adf3a2c4SKevin Wolf     [WIN_SETMULT]                 = { cmd_set_multiple_mode, HD_CFA_OK | SET_DSC },
211492a6a6f6SKevin Wolf     [WIN_READDMA]                 = { cmd_read_dma, HD_CFA_OK },
211592a6a6f6SKevin Wolf     [WIN_READDMA_ONCE]            = { cmd_read_dma, HD_CFA_OK },
211692a6a6f6SKevin Wolf     [WIN_WRITEDMA]                = { cmd_write_dma, HD_CFA_OK },
211792a6a6f6SKevin Wolf     [WIN_WRITEDMA_ONCE]           = { cmd_write_dma, HD_CFA_OK },
2118adf3a2c4SKevin Wolf     [CFA_WRITE_MULTI_WO_ERASE]    = { cmd_write_multiple, CFA_OK },
2119d9033e1dSJohn Snow     [WIN_STANDBYNOW1]             = { cmd_nop, HD_CFA_OK },
2120d9033e1dSJohn Snow     [WIN_IDLEIMMEDIATE]           = { cmd_nop, HD_CFA_OK },
2121d9033e1dSJohn Snow     [WIN_STANDBY]                 = { cmd_nop, HD_CFA_OK },
2122d9033e1dSJohn Snow     [WIN_SETIDLE1]                = { cmd_nop, HD_CFA_OK },
2123d9033e1dSJohn Snow     [WIN_CHECKPOWERMODE1]         = { cmd_check_power_mode, HD_CFA_OK | SET_DSC },
2124d9033e1dSJohn Snow     [WIN_SLEEPNOW1]               = { cmd_nop, HD_CFA_OK },
21259afce429SKevin Wolf     [WIN_FLUSH_CACHE]             = { cmd_flush_cache, ALL_OK },
21269afce429SKevin Wolf     [WIN_FLUSH_CACHE_EXT]         = { cmd_flush_cache, HD_CFA_OK },
21271c66869aSKevin Wolf     [WIN_IDENTIFY]                = { cmd_identify, ALL_OK },
2128ee03398cSKevin Wolf     [WIN_SETFEATURES]             = { cmd_set_features, ALL_OK | SET_DSC },
21296b1dd744SKevin Wolf     [IBM_SENSE_CONDITION]         = { cmd_ibm_sense_condition, CFA_OK | SET_DSC },
21306b1dd744SKevin Wolf     [CFA_WEAR_LEVEL]              = { cmd_cfa_erase_sectors, HD_CFA_OK | SET_DSC },
2131d9033e1dSJohn Snow     [WIN_READ_NATIVE_MAX]         = { cmd_read_native_max, HD_CFA_OK | SET_DSC },
2132844505b1SMarkus Armbruster };
2133844505b1SMarkus Armbruster 
ide_cmd_permitted(IDEState * s,uint32_t cmd)2134844505b1SMarkus Armbruster static bool ide_cmd_permitted(IDEState *s, uint32_t cmd)
2135844505b1SMarkus Armbruster {
2136844505b1SMarkus Armbruster     return cmd < ARRAY_SIZE(ide_cmd_table)
2137a0436e92SKevin Wolf         && (ide_cmd_table[cmd].flags & (1u << s->drive_kind));
2138844505b1SMarkus Armbruster }
21397cff87ffSAlexander Graf 
ide_bus_exec_cmd(IDEBus * bus,uint32_t val)2140783f4474SPhilippe Mathieu-Daudé void ide_bus_exec_cmd(IDEBus *bus, uint32_t val)
21417cff87ffSAlexander Graf {
21427cff87ffSAlexander Graf     IDEState *s;
2143dfe1ea8fSKevin Wolf     bool complete;
21447cff87ffSAlexander Graf 
21452c50207fSPhilippe Mathieu-Daudé     s = ide_bus_active_if(bus);
2146783f4474SPhilippe Mathieu-Daudé     trace_ide_bus_exec_cmd(bus, s, val);
21473eee2611SJohn Snow 
214866a0a2cbSDong Xu Wang     /* ignore commands to non existent slave */
21494be74634SMarkus Armbruster     if (s != bus->ifs && !s->blk) {
21507cff87ffSAlexander Graf         return;
21514be74634SMarkus Armbruster     }
215259f2a787SGerd Hoffmann 
2153266e7781SJohn Snow     /* Only RESET is allowed while BSY and/or DRQ are set,
2154266e7781SJohn Snow      * and only to ATAPI devices. */
2155266e7781SJohn Snow     if (s->status & (BUSY_STAT|DRQ_STAT)) {
2156266e7781SJohn Snow         if (val != WIN_DEVICE_RESET || s->drive_kind != IDE_CD) {
21577cff87ffSAlexander Graf             return;
2158266e7781SJohn Snow         }
2159266e7781SJohn Snow     }
216059f2a787SGerd Hoffmann 
2161844505b1SMarkus Armbruster     if (!ide_cmd_permitted(s, val)) {
2162dfe1ea8fSKevin Wolf         ide_abort_command(s);
21630cfe719dSPhilippe Mathieu-Daudé         ide_bus_set_irq(s->bus);
2164dfe1ea8fSKevin Wolf         return;
2165844505b1SMarkus Armbruster     }
2166844505b1SMarkus Armbruster 
2167a0436e92SKevin Wolf     s->status = READY_STAT | BUSY_STAT;
2168a0436e92SKevin Wolf     s->error = 0;
216936334fafSJohn Snow     s->io_buffer_offset = 0;
2170a0436e92SKevin Wolf 
2171a0436e92SKevin Wolf     complete = ide_cmd_table[val].handler(s, val);
2172a0436e92SKevin Wolf     if (complete) {
2173a0436e92SKevin Wolf         s->status &= ~BUSY_STAT;
2174a0436e92SKevin Wolf         assert(!!s->error == !!(s->status & ERR_STAT));
2175a0436e92SKevin Wolf 
2176a0436e92SKevin Wolf         if ((ide_cmd_table[val].flags & SET_DSC) && !s->error) {
2177a0436e92SKevin Wolf             s->status |= SEEK_STAT;
2178a0436e92SKevin Wolf         }
2179a0436e92SKevin Wolf 
2180c7e73adbSPaolo Bonzini         ide_cmd_done(s);
21810cfe719dSPhilippe Mathieu-Daudé         ide_bus_set_irq(s->bus);
2182a0436e92SKevin Wolf     }
218359f2a787SGerd Hoffmann }
218459f2a787SGerd Hoffmann 
2185335ca2f2SJohn Snow /* IOport [R]ead [R]egisters */
2186335ca2f2SJohn Snow enum ATA_IOPORT_RR {
2187335ca2f2SJohn Snow     ATA_IOPORT_RR_DATA = 0,
2188335ca2f2SJohn Snow     ATA_IOPORT_RR_ERROR = 1,
2189335ca2f2SJohn Snow     ATA_IOPORT_RR_SECTOR_COUNT = 2,
2190335ca2f2SJohn Snow     ATA_IOPORT_RR_SECTOR_NUMBER = 3,
2191335ca2f2SJohn Snow     ATA_IOPORT_RR_CYLINDER_LOW = 4,
2192335ca2f2SJohn Snow     ATA_IOPORT_RR_CYLINDER_HIGH = 5,
2193335ca2f2SJohn Snow     ATA_IOPORT_RR_DEVICE_HEAD = 6,
2194335ca2f2SJohn Snow     ATA_IOPORT_RR_STATUS = 7,
2195335ca2f2SJohn Snow     ATA_IOPORT_RR_NUM_REGISTERS,
2196335ca2f2SJohn Snow };
2197335ca2f2SJohn Snow 
2198335ca2f2SJohn Snow const char *ATA_IOPORT_RR_lookup[ATA_IOPORT_RR_NUM_REGISTERS] = {
2199335ca2f2SJohn Snow     [ATA_IOPORT_RR_DATA] = "Data",
2200335ca2f2SJohn Snow     [ATA_IOPORT_RR_ERROR] = "Error",
2201335ca2f2SJohn Snow     [ATA_IOPORT_RR_SECTOR_COUNT] = "Sector Count",
2202335ca2f2SJohn Snow     [ATA_IOPORT_RR_SECTOR_NUMBER] = "Sector Number",
2203335ca2f2SJohn Snow     [ATA_IOPORT_RR_CYLINDER_LOW] = "Cylinder Low",
2204335ca2f2SJohn Snow     [ATA_IOPORT_RR_CYLINDER_HIGH] = "Cylinder High",
2205335ca2f2SJohn Snow     [ATA_IOPORT_RR_DEVICE_HEAD] = "Device/Head",
2206335ca2f2SJohn Snow     [ATA_IOPORT_RR_STATUS] = "Status"
2207335ca2f2SJohn Snow };
2208335ca2f2SJohn Snow 
ide_ioport_read(void * opaque,uint32_t addr)22093eee2611SJohn Snow uint32_t ide_ioport_read(void *opaque, uint32_t addr)
221059f2a787SGerd Hoffmann {
221159f2a787SGerd Hoffmann     IDEBus *bus = opaque;
22122c50207fSPhilippe Mathieu-Daudé     IDEState *s = ide_bus_active_if(bus);
22133eee2611SJohn Snow     uint32_t reg_num;
221459f2a787SGerd Hoffmann     int ret, hob;
221559f2a787SGerd Hoffmann 
22163eee2611SJohn Snow     reg_num = addr & 7;
2217be8c9423SJohn Snow     hob = bus->cmd & (IDE_CTRL_HOB);
22183eee2611SJohn Snow     switch (reg_num) {
2219335ca2f2SJohn Snow     case ATA_IOPORT_RR_DATA:
2220758c925eSLev Kujawski         /*
2221758c925eSLev Kujawski          * The pre-GRUB Solaris x86 bootloader relies upon inb
2222758c925eSLev Kujawski          * consuming a word from the drive's sector buffer.
2223758c925eSLev Kujawski          */
2224758c925eSLev Kujawski         ret = ide_data_readw(bus, addr) & 0xff;
222559f2a787SGerd Hoffmann         break;
2226335ca2f2SJohn Snow     case ATA_IOPORT_RR_ERROR:
22274be74634SMarkus Armbruster         if ((!bus->ifs[0].blk && !bus->ifs[1].blk) ||
22284be74634SMarkus Armbruster             (s != bus->ifs && !s->blk)) {
222959f2a787SGerd Hoffmann             ret = 0;
22304be74634SMarkus Armbruster         } else if (!hob) {
223159f2a787SGerd Hoffmann             ret = s->error;
22324be74634SMarkus Armbruster         } else {
223359f2a787SGerd Hoffmann             ret = s->hob_feature;
22344be74634SMarkus Armbruster         }
223559f2a787SGerd Hoffmann         break;
2236335ca2f2SJohn Snow     case ATA_IOPORT_RR_SECTOR_COUNT:
22374be74634SMarkus Armbruster         if (!bus->ifs[0].blk && !bus->ifs[1].blk) {
223859f2a787SGerd Hoffmann             ret = 0;
22394be74634SMarkus Armbruster         } else if (!hob) {
224059f2a787SGerd Hoffmann             ret = s->nsector & 0xff;
22414be74634SMarkus Armbruster         } else {
224259f2a787SGerd Hoffmann             ret = s->hob_nsector;
22434be74634SMarkus Armbruster         }
224459f2a787SGerd Hoffmann         break;
2245335ca2f2SJohn Snow     case ATA_IOPORT_RR_SECTOR_NUMBER:
22464be74634SMarkus Armbruster         if (!bus->ifs[0].blk && !bus->ifs[1].blk) {
224759f2a787SGerd Hoffmann             ret = 0;
22484be74634SMarkus Armbruster         } else if (!hob) {
224959f2a787SGerd Hoffmann             ret = s->sector;
22504be74634SMarkus Armbruster         } else {
225159f2a787SGerd Hoffmann             ret = s->hob_sector;
22524be74634SMarkus Armbruster         }
225359f2a787SGerd Hoffmann         break;
2254335ca2f2SJohn Snow     case ATA_IOPORT_RR_CYLINDER_LOW:
22554be74634SMarkus Armbruster         if (!bus->ifs[0].blk && !bus->ifs[1].blk) {
225659f2a787SGerd Hoffmann             ret = 0;
22574be74634SMarkus Armbruster         } else if (!hob) {
225859f2a787SGerd Hoffmann             ret = s->lcyl;
22594be74634SMarkus Armbruster         } else {
226059f2a787SGerd Hoffmann             ret = s->hob_lcyl;
22614be74634SMarkus Armbruster         }
226259f2a787SGerd Hoffmann         break;
2263335ca2f2SJohn Snow     case ATA_IOPORT_RR_CYLINDER_HIGH:
22644be74634SMarkus Armbruster         if (!bus->ifs[0].blk && !bus->ifs[1].blk) {
226559f2a787SGerd Hoffmann             ret = 0;
22664be74634SMarkus Armbruster         } else if (!hob) {
226759f2a787SGerd Hoffmann             ret = s->hcyl;
22684be74634SMarkus Armbruster         } else {
226959f2a787SGerd Hoffmann             ret = s->hob_hcyl;
22704be74634SMarkus Armbruster         }
227159f2a787SGerd Hoffmann         break;
2272335ca2f2SJohn Snow     case ATA_IOPORT_RR_DEVICE_HEAD:
22734be74634SMarkus Armbruster         if (!bus->ifs[0].blk && !bus->ifs[1].blk) {
227459f2a787SGerd Hoffmann             ret = 0;
22754be74634SMarkus Armbruster         } else {
227659f2a787SGerd Hoffmann             ret = s->select;
22774be74634SMarkus Armbruster         }
227859f2a787SGerd Hoffmann         break;
227959f2a787SGerd Hoffmann     default:
2280335ca2f2SJohn Snow     case ATA_IOPORT_RR_STATUS:
22814be74634SMarkus Armbruster         if ((!bus->ifs[0].blk && !bus->ifs[1].blk) ||
22824be74634SMarkus Armbruster             (s != bus->ifs && !s->blk)) {
228359f2a787SGerd Hoffmann             ret = 0;
22844be74634SMarkus Armbruster         } else {
228559f2a787SGerd Hoffmann             ret = s->status;
22864be74634SMarkus Armbruster         }
22879cdd03a7SGerd Hoffmann         qemu_irq_lower(bus->irq);
228859f2a787SGerd Hoffmann         break;
228959f2a787SGerd Hoffmann     }
22903eee2611SJohn Snow 
2291335ca2f2SJohn Snow     trace_ide_ioport_read(addr, ATA_IOPORT_RR_lookup[reg_num], ret, bus, s);
229259f2a787SGerd Hoffmann     return ret;
229359f2a787SGerd Hoffmann }
229459f2a787SGerd Hoffmann 
ide_status_read(void * opaque,uint32_t addr)229559f2a787SGerd Hoffmann uint32_t ide_status_read(void *opaque, uint32_t addr)
229659f2a787SGerd Hoffmann {
229759f2a787SGerd Hoffmann     IDEBus *bus = opaque;
22982c50207fSPhilippe Mathieu-Daudé     IDEState *s = ide_bus_active_if(bus);
229959f2a787SGerd Hoffmann     int ret;
230059f2a787SGerd Hoffmann 
23014be74634SMarkus Armbruster     if ((!bus->ifs[0].blk && !bus->ifs[1].blk) ||
23024be74634SMarkus Armbruster         (s != bus->ifs && !s->blk)) {
230359f2a787SGerd Hoffmann         ret = 0;
23044be74634SMarkus Armbruster     } else {
230559f2a787SGerd Hoffmann         ret = s->status;
23064be74634SMarkus Armbruster     }
23073eee2611SJohn Snow 
23083eee2611SJohn Snow     trace_ide_status_read(addr, ret, bus, s);
230959f2a787SGerd Hoffmann     return ret;
231059f2a787SGerd Hoffmann }
231159f2a787SGerd Hoffmann 
ide_perform_srst(IDEState * s)231255adb3c4SJohn Snow static void ide_perform_srst(IDEState *s)
231355adb3c4SJohn Snow {
231455adb3c4SJohn Snow     s->status |= BUSY_STAT;
231555adb3c4SJohn Snow 
231655adb3c4SJohn Snow     /* Halt PIO (Via register state); PIO BH remains scheduled. */
231755adb3c4SJohn Snow     ide_transfer_halt(s);
231855adb3c4SJohn Snow 
231955adb3c4SJohn Snow     /* Cancel DMA -- may drain block device and invoke callbacks */
232055adb3c4SJohn Snow     ide_cancel_dma_sync(s);
232155adb3c4SJohn Snow 
232255adb3c4SJohn Snow     /* Cancel PIO callback, reset registers/signature, etc */
232355adb3c4SJohn Snow     ide_reset(s);
232455adb3c4SJohn Snow 
23254ac4e728SJohn Snow     /* perform diagnostic */
23264ac4e728SJohn Snow     cmd_exec_dev_diagnostic(s, WIN_DIAGNOSE);
232755adb3c4SJohn Snow }
232855adb3c4SJohn Snow 
ide_bus_perform_srst(void * opaque)232955adb3c4SJohn Snow static void ide_bus_perform_srst(void *opaque)
233055adb3c4SJohn Snow {
233155adb3c4SJohn Snow     IDEBus *bus = opaque;
233255adb3c4SJohn Snow     IDEState *s;
233355adb3c4SJohn Snow     int i;
233455adb3c4SJohn Snow 
233555adb3c4SJohn Snow     for (i = 0; i < 2; i++) {
233655adb3c4SJohn Snow         s = &bus->ifs[i];
233755adb3c4SJohn Snow         ide_perform_srst(s);
233855adb3c4SJohn Snow     }
23391a9925e3SJohn Snow 
23401a9925e3SJohn Snow     bus->cmd &= ~IDE_CTRL_RESET;
234155adb3c4SJohn Snow }
234255adb3c4SJohn Snow 
ide_ctrl_write(void * opaque,uint32_t addr,uint32_t val)234398d98912SJohn Snow void ide_ctrl_write(void *opaque, uint32_t addr, uint32_t val)
234459f2a787SGerd Hoffmann {
234559f2a787SGerd Hoffmann     IDEBus *bus = opaque;
234659f2a787SGerd Hoffmann     IDEState *s;
234759f2a787SGerd Hoffmann     int i;
234859f2a787SGerd Hoffmann 
234998d98912SJohn Snow     trace_ide_ctrl_write(addr, val, bus);
23503eee2611SJohn Snow 
235155adb3c4SJohn Snow     /* Device0 and Device1 each have their own control register,
235255adb3c4SJohn Snow      * but QEMU models it as just one register in the controller. */
2353b45bcd81SJohn Snow     if (!(bus->cmd & IDE_CTRL_RESET) && (val & IDE_CTRL_RESET)) {
235459f2a787SGerd Hoffmann         for (i = 0; i < 2; i++) {
235559f2a787SGerd Hoffmann             s = &bus->ifs[i];
235655adb3c4SJohn Snow             s->status |= BUSY_STAT;
235759f2a787SGerd Hoffmann         }
2358de00b8b3SAlex Bennée         replay_bh_schedule_oneshot_event(qemu_get_aio_context(),
235955adb3c4SJohn Snow                                          ide_bus_perform_srst, bus);
236059f2a787SGerd Hoffmann     }
236159f2a787SGerd Hoffmann 
23629cdd03a7SGerd Hoffmann     bus->cmd = val;
236359f2a787SGerd Hoffmann }
236459f2a787SGerd Hoffmann 
236540c4ed3fSKevin Wolf /*
236640c4ed3fSKevin Wolf  * Returns true if the running PIO transfer is a PIO out (i.e. data is
236740c4ed3fSKevin Wolf  * transferred from the device to the guest), false if it's a PIO in
236840c4ed3fSKevin Wolf  */
ide_is_pio_out(IDEState * s)236940c4ed3fSKevin Wolf static bool ide_is_pio_out(IDEState *s)
237040c4ed3fSKevin Wolf {
237140c4ed3fSKevin Wolf     if (s->end_transfer_func == ide_sector_write ||
237240c4ed3fSKevin Wolf         s->end_transfer_func == ide_atapi_cmd) {
237340c4ed3fSKevin Wolf         return false;
237440c4ed3fSKevin Wolf     } else if (s->end_transfer_func == ide_sector_read ||
237540c4ed3fSKevin Wolf                s->end_transfer_func == ide_transfer_stop ||
237640c4ed3fSKevin Wolf                s->end_transfer_func == ide_atapi_cmd_reply_end ||
237740c4ed3fSKevin Wolf                s->end_transfer_func == ide_dummy_transfer_stop) {
237840c4ed3fSKevin Wolf         return true;
237940c4ed3fSKevin Wolf     }
238040c4ed3fSKevin Wolf 
238140c4ed3fSKevin Wolf     abort();
238240c4ed3fSKevin Wolf }
238340c4ed3fSKevin Wolf 
ide_data_writew(void * opaque,uint32_t addr,uint32_t val)238459f2a787SGerd Hoffmann void ide_data_writew(void *opaque, uint32_t addr, uint32_t val)
238559f2a787SGerd Hoffmann {
238659f2a787SGerd Hoffmann     IDEBus *bus = opaque;
23872c50207fSPhilippe Mathieu-Daudé     IDEState *s = ide_bus_active_if(bus);
238859f2a787SGerd Hoffmann     uint8_t *p;
238959f2a787SGerd Hoffmann 
23901787efc3SJohn Snow     trace_ide_data_writew(addr, val, bus, s);
23911787efc3SJohn Snow 
239240c4ed3fSKevin Wolf     /* PIO data access allowed only when DRQ bit is set. The result of a write
239340c4ed3fSKevin Wolf      * during PIO out is indeterminate, just ignore it. */
239440c4ed3fSKevin Wolf     if (!(s->status & DRQ_STAT) || ide_is_pio_out(s)) {
239559f2a787SGerd Hoffmann         return;
239640c4ed3fSKevin Wolf     }
239759f2a787SGerd Hoffmann 
239859f2a787SGerd Hoffmann     p = s->data_ptr;
23991ea17d22SLubomir Rintel     if (s->io8) {
24001ea17d22SLubomir Rintel         if (p + 1 > s->data_end) {
24011ea17d22SLubomir Rintel             return;
24021ea17d22SLubomir Rintel         }
24031ea17d22SLubomir Rintel 
24041ea17d22SLubomir Rintel         *p++ = val;
24051ea17d22SLubomir Rintel     } else {
2406d2ff8585SKevin Wolf         if (p + 2 > s->data_end) {
2407d2ff8585SKevin Wolf             return;
2408d2ff8585SKevin Wolf         }
2409d2ff8585SKevin Wolf 
241059f2a787SGerd Hoffmann         *(uint16_t *)p = le16_to_cpu(val);
241159f2a787SGerd Hoffmann         p += 2;
24121ea17d22SLubomir Rintel     }
241359f2a787SGerd Hoffmann     s->data_ptr = p;
2414cb72cba8SKevin Wolf     if (p >= s->data_end) {
2415cb72cba8SKevin Wolf         s->status &= ~DRQ_STAT;
241659f2a787SGerd Hoffmann         s->end_transfer_func(s);
241759f2a787SGerd Hoffmann     }
2418cb72cba8SKevin Wolf }
241959f2a787SGerd Hoffmann 
ide_data_readw(void * opaque,uint32_t addr)242059f2a787SGerd Hoffmann uint32_t ide_data_readw(void *opaque, uint32_t addr)
242159f2a787SGerd Hoffmann {
242259f2a787SGerd Hoffmann     IDEBus *bus = opaque;
24232c50207fSPhilippe Mathieu-Daudé     IDEState *s = ide_bus_active_if(bus);
242459f2a787SGerd Hoffmann     uint8_t *p;
242559f2a787SGerd Hoffmann     int ret;
242659f2a787SGerd Hoffmann 
242740c4ed3fSKevin Wolf     /* PIO data access allowed only when DRQ bit is set. The result of a read
242840c4ed3fSKevin Wolf      * during PIO in is indeterminate, return 0 and don't move forward. */
242940c4ed3fSKevin Wolf     if (!(s->status & DRQ_STAT) || !ide_is_pio_out(s)) {
243059f2a787SGerd Hoffmann         return 0;
243140c4ed3fSKevin Wolf     }
243259f2a787SGerd Hoffmann 
243359f2a787SGerd Hoffmann     p = s->data_ptr;
24341ea17d22SLubomir Rintel     if (s->io8) {
24351ea17d22SLubomir Rintel         if (p + 1 > s->data_end) {
24361ea17d22SLubomir Rintel             return 0;
24371ea17d22SLubomir Rintel         }
24381ea17d22SLubomir Rintel 
24391ea17d22SLubomir Rintel         ret = *p++;
24401ea17d22SLubomir Rintel     } else {
2441d2ff8585SKevin Wolf         if (p + 2 > s->data_end) {
2442d2ff8585SKevin Wolf             return 0;
2443d2ff8585SKevin Wolf         }
2444d2ff8585SKevin Wolf 
244559f2a787SGerd Hoffmann         ret = cpu_to_le16(*(uint16_t *)p);
244659f2a787SGerd Hoffmann         p += 2;
24471ea17d22SLubomir Rintel     }
244859f2a787SGerd Hoffmann     s->data_ptr = p;
2449cb72cba8SKevin Wolf     if (p >= s->data_end) {
2450cb72cba8SKevin Wolf         s->status &= ~DRQ_STAT;
245159f2a787SGerd Hoffmann         s->end_transfer_func(s);
2452cb72cba8SKevin Wolf     }
24531787efc3SJohn Snow 
24541787efc3SJohn Snow     trace_ide_data_readw(addr, ret, bus, s);
245559f2a787SGerd Hoffmann     return ret;
245659f2a787SGerd Hoffmann }
245759f2a787SGerd Hoffmann 
ide_data_writel(void * opaque,uint32_t addr,uint32_t val)245859f2a787SGerd Hoffmann void ide_data_writel(void *opaque, uint32_t addr, uint32_t val)
245959f2a787SGerd Hoffmann {
246059f2a787SGerd Hoffmann     IDEBus *bus = opaque;
24612c50207fSPhilippe Mathieu-Daudé     IDEState *s = ide_bus_active_if(bus);
246259f2a787SGerd Hoffmann     uint8_t *p;
246359f2a787SGerd Hoffmann 
24641787efc3SJohn Snow     trace_ide_data_writel(addr, val, bus, s);
24651787efc3SJohn Snow 
246640c4ed3fSKevin Wolf     /* PIO data access allowed only when DRQ bit is set. The result of a write
246740c4ed3fSKevin Wolf      * during PIO out is indeterminate, just ignore it. */
246840c4ed3fSKevin Wolf     if (!(s->status & DRQ_STAT) || ide_is_pio_out(s)) {
246959f2a787SGerd Hoffmann         return;
247040c4ed3fSKevin Wolf     }
247159f2a787SGerd Hoffmann 
247259f2a787SGerd Hoffmann     p = s->data_ptr;
2473d2ff8585SKevin Wolf     if (p + 4 > s->data_end) {
2474d2ff8585SKevin Wolf         return;
2475d2ff8585SKevin Wolf     }
2476d2ff8585SKevin Wolf 
247759f2a787SGerd Hoffmann     *(uint32_t *)p = le32_to_cpu(val);
247859f2a787SGerd Hoffmann     p += 4;
247959f2a787SGerd Hoffmann     s->data_ptr = p;
2480cb72cba8SKevin Wolf     if (p >= s->data_end) {
2481cb72cba8SKevin Wolf         s->status &= ~DRQ_STAT;
248259f2a787SGerd Hoffmann         s->end_transfer_func(s);
248359f2a787SGerd Hoffmann     }
2484cb72cba8SKevin Wolf }
248559f2a787SGerd Hoffmann 
ide_data_readl(void * opaque,uint32_t addr)248659f2a787SGerd Hoffmann uint32_t ide_data_readl(void *opaque, uint32_t addr)
248759f2a787SGerd Hoffmann {
248859f2a787SGerd Hoffmann     IDEBus *bus = opaque;
24892c50207fSPhilippe Mathieu-Daudé     IDEState *s = ide_bus_active_if(bus);
249059f2a787SGerd Hoffmann     uint8_t *p;
249159f2a787SGerd Hoffmann     int ret;
249259f2a787SGerd Hoffmann 
249340c4ed3fSKevin Wolf     /* PIO data access allowed only when DRQ bit is set. The result of a read
249440c4ed3fSKevin Wolf      * during PIO in is indeterminate, return 0 and don't move forward. */
249540c4ed3fSKevin Wolf     if (!(s->status & DRQ_STAT) || !ide_is_pio_out(s)) {
24961787efc3SJohn Snow         ret = 0;
24971787efc3SJohn Snow         goto out;
249840c4ed3fSKevin Wolf     }
249959f2a787SGerd Hoffmann 
250059f2a787SGerd Hoffmann     p = s->data_ptr;
2501d2ff8585SKevin Wolf     if (p + 4 > s->data_end) {
2502d2ff8585SKevin Wolf         return 0;
2503d2ff8585SKevin Wolf     }
2504d2ff8585SKevin Wolf 
250559f2a787SGerd Hoffmann     ret = cpu_to_le32(*(uint32_t *)p);
250659f2a787SGerd Hoffmann     p += 4;
250759f2a787SGerd Hoffmann     s->data_ptr = p;
2508cb72cba8SKevin Wolf     if (p >= s->data_end) {
2509cb72cba8SKevin Wolf         s->status &= ~DRQ_STAT;
251059f2a787SGerd Hoffmann         s->end_transfer_func(s);
2511cb72cba8SKevin Wolf     }
25121787efc3SJohn Snow 
25131787efc3SJohn Snow out:
25141787efc3SJohn Snow     trace_ide_data_readl(addr, ret, bus, s);
251559f2a787SGerd Hoffmann     return ret;
251659f2a787SGerd Hoffmann }
251759f2a787SGerd Hoffmann 
ide_dummy_transfer_stop(IDEState * s)251859f2a787SGerd Hoffmann static void ide_dummy_transfer_stop(IDEState *s)
251959f2a787SGerd Hoffmann {
252059f2a787SGerd Hoffmann     s->data_ptr = s->io_buffer;
252159f2a787SGerd Hoffmann     s->data_end = s->io_buffer;
252259f2a787SGerd Hoffmann     s->io_buffer[0] = 0xff;
252359f2a787SGerd Hoffmann     s->io_buffer[1] = 0xff;
252459f2a787SGerd Hoffmann     s->io_buffer[2] = 0xff;
252559f2a787SGerd Hoffmann     s->io_buffer[3] = 0xff;
252659f2a787SGerd Hoffmann }
252759f2a787SGerd Hoffmann 
ide_bus_reset(IDEBus * bus)25284a643563SBlue Swirl void ide_bus_reset(IDEBus *bus)
25294a643563SBlue Swirl {
25307d751201SFiona Ebner     /* pending async DMA - needs the IDEState before it is reset */
253140a6238aSAlexander Graf     if (bus->dma->aiocb) {
25320e168d35SJohn Snow         trace_ide_bus_reset_aio();
25334be74634SMarkus Armbruster         blk_aio_cancel(bus->dma->aiocb);
253440a6238aSAlexander Graf         bus->dma->aiocb = NULL;
253540a6238aSAlexander Graf     }
253640a6238aSAlexander Graf 
25377d751201SFiona Ebner     bus->unit = 0;
25387d751201SFiona Ebner     bus->cmd = 0;
25397d751201SFiona Ebner     ide_reset(&bus->ifs[0]);
25407d751201SFiona Ebner     ide_reset(&bus->ifs[1]);
25417d751201SFiona Ebner     ide_clear_hob(bus);
25427d751201SFiona Ebner 
254340a6238aSAlexander Graf     /* reset dma provider too */
25441374bec0SPaolo Bonzini     if (bus->dma->ops->reset) {
254540a6238aSAlexander Graf         bus->dma->ops->reset(bus->dma);
25464a643563SBlue Swirl     }
25471374bec0SPaolo Bonzini }
25484a643563SBlue Swirl 
ide_cd_is_tray_open(void * opaque)2549e4def80bSMarkus Armbruster static bool ide_cd_is_tray_open(void *opaque)
2550e4def80bSMarkus Armbruster {
2551e4def80bSMarkus Armbruster     return ((IDEState *)opaque)->tray_open;
2552e4def80bSMarkus Armbruster }
2553e4def80bSMarkus Armbruster 
ide_cd_is_medium_locked(void * opaque)2554f107639aSMarkus Armbruster static bool ide_cd_is_medium_locked(void *opaque)
2555f107639aSMarkus Armbruster {
2556f107639aSMarkus Armbruster     return ((IDEState *)opaque)->tray_locked;
2557f107639aSMarkus Armbruster }
2558f107639aSMarkus Armbruster 
ide_resize_cb(void * opaque)255901ce352eSJohn Snow static void ide_resize_cb(void *opaque)
256001ce352eSJohn Snow {
256101ce352eSJohn Snow     IDEState *s = opaque;
256201ce352eSJohn Snow     uint64_t nb_sectors;
256301ce352eSJohn Snow 
256401ce352eSJohn Snow     if (!s->identify_set) {
256501ce352eSJohn Snow         return;
256601ce352eSJohn Snow     }
256701ce352eSJohn Snow 
25684be74634SMarkus Armbruster     blk_get_geometry(s->blk, &nb_sectors);
256901ce352eSJohn Snow     s->nb_sectors = nb_sectors;
257001ce352eSJohn Snow 
257101ce352eSJohn Snow     /* Update the identify data buffer. */
257201ce352eSJohn Snow     if (s->drive_kind == IDE_CFATA) {
257301ce352eSJohn Snow         ide_cfata_identify_size(s);
257401ce352eSJohn Snow     } else {
257501ce352eSJohn Snow         /* IDE_CD uses a different set of callbacks entirely. */
257601ce352eSJohn Snow         assert(s->drive_kind != IDE_CD);
257701ce352eSJohn Snow         ide_identify_size(s);
257801ce352eSJohn Snow     }
257901ce352eSJohn Snow }
258001ce352eSJohn Snow 
25810e49de52SMarkus Armbruster static const BlockDevOps ide_cd_block_ops = {
2582145feb17SMarkus Armbruster     .change_media_cb = ide_cd_change_cb,
25832df0a3a3SPaolo Bonzini     .eject_request_cb = ide_cd_eject_request_cb,
2584e4def80bSMarkus Armbruster     .is_tray_open = ide_cd_is_tray_open,
2585f107639aSMarkus Armbruster     .is_medium_locked = ide_cd_is_medium_locked,
25860e49de52SMarkus Armbruster };
25870e49de52SMarkus Armbruster 
258801ce352eSJohn Snow static const BlockDevOps ide_hd_block_ops = {
258901ce352eSJohn Snow     .resize_cb = ide_resize_cb,
259001ce352eSJohn Snow };
259101ce352eSJohn Snow 
ide_init_drive(IDEState * s,BlockBackend * blk,IDEDriveKind kind,const char * version,const char * serial,const char * model,uint64_t wwn,uint32_t cylinders,uint32_t heads,uint32_t secs,int chs_trans,Error ** errp)25924be74634SMarkus Armbruster int ide_init_drive(IDEState *s, BlockBackend *blk, IDEDriveKind kind,
259395ebda85SFloris Bos                    const char *version, const char *serial, const char *model,
2594ba801960SMarkus Armbruster                    uint64_t wwn,
2595ba801960SMarkus Armbruster                    uint32_t cylinders, uint32_t heads, uint32_t secs,
2596794939e8SMao Zhongyi                    int chs_trans, Error **errp)
259759f2a787SGerd Hoffmann {
259859f2a787SGerd Hoffmann     uint64_t nb_sectors;
259959f2a787SGerd Hoffmann 
26004be74634SMarkus Armbruster     s->blk = blk;
26011f56e32aSMarkus Armbruster     s->drive_kind = kind;
26021f56e32aSMarkus Armbruster 
26034be74634SMarkus Armbruster     blk_get_geometry(blk, &nb_sectors);
260459f2a787SGerd Hoffmann     s->cylinders = cylinders;
2605176e4961SLev Kujawski     s->heads = s->drive_heads = heads;
2606176e4961SLev Kujawski     s->sectors = s->drive_sectors = secs;
2607ba801960SMarkus Armbruster     s->chs_trans = chs_trans;
260859f2a787SGerd Hoffmann     s->nb_sectors = nb_sectors;
260995ebda85SFloris Bos     s->wwn = wwn;
261059f2a787SGerd Hoffmann     /* The SMART values should be preserved across power cycles
261159f2a787SGerd Hoffmann        but they aren't.  */
261259f2a787SGerd Hoffmann     s->smart_enabled = 1;
261359f2a787SGerd Hoffmann     s->smart_autosave = 1;
261459f2a787SGerd Hoffmann     s->smart_errors = 0;
261559f2a787SGerd Hoffmann     s->smart_selftest_count = 0;
26161f56e32aSMarkus Armbruster     if (kind == IDE_CD) {
26174be74634SMarkus Armbruster         blk_set_dev_ops(blk, &ide_cd_block_ops, s);
26187aa9c811SMarkus Armbruster     } else {
26194be74634SMarkus Armbruster         if (!blk_is_inserted(s->blk)) {
2620794939e8SMao Zhongyi             error_setg(errp, "Device needs media, but drive is empty");
262198f28ad7SMarkus Armbruster             return -1;
262298f28ad7SMarkus Armbruster         }
262386b1cf32SKevin Wolf         if (!blk_is_writable(blk)) {
2624794939e8SMao Zhongyi             error_setg(errp, "Can't use a read-only drive");
26257aa9c811SMarkus Armbruster             return -1;
26267aa9c811SMarkus Armbruster         }
26274be74634SMarkus Armbruster         blk_set_dev_ops(blk, &ide_hd_block_ops, s);
262859f2a787SGerd Hoffmann     }
2629f8b6cc00SMarkus Armbruster     if (serial) {
2630aa2c91bdSFloris Bos         pstrcpy(s->drive_serial_str, sizeof(s->drive_serial_str), serial);
26316ced55a5SMarkus Armbruster     } else {
263259f2a787SGerd Hoffmann         snprintf(s->drive_serial_str, sizeof(s->drive_serial_str),
263359f2a787SGerd Hoffmann                  "QM%05d", s->drive_serial);
2634870111c8SMarkus Armbruster     }
263527e0c9a1SFloris Bos     if (model) {
263627e0c9a1SFloris Bos         pstrcpy(s->drive_model_str, sizeof(s->drive_model_str), model);
263727e0c9a1SFloris Bos     } else {
263827e0c9a1SFloris Bos         switch (kind) {
263927e0c9a1SFloris Bos         case IDE_CD:
264027e0c9a1SFloris Bos             strcpy(s->drive_model_str, "QEMU DVD-ROM");
264127e0c9a1SFloris Bos             break;
264227e0c9a1SFloris Bos         case IDE_CFATA:
264327e0c9a1SFloris Bos             strcpy(s->drive_model_str, "QEMU MICRODRIVE");
264427e0c9a1SFloris Bos             break;
264527e0c9a1SFloris Bos         default:
264627e0c9a1SFloris Bos             strcpy(s->drive_model_str, "QEMU HARDDISK");
264727e0c9a1SFloris Bos             break;
264827e0c9a1SFloris Bos         }
264927e0c9a1SFloris Bos     }
265027e0c9a1SFloris Bos 
265147c06340SGerd Hoffmann     if (version) {
265247c06340SGerd Hoffmann         pstrcpy(s->version, sizeof(s->version), version);
265347c06340SGerd Hoffmann     } else {
265435c2c8dcSEduardo Habkost         pstrcpy(s->version, sizeof(s->version), qemu_hw_version());
265547c06340SGerd Hoffmann     }
265640a6238aSAlexander Graf 
265788804180SGerd Hoffmann     ide_reset(s);
26584be74634SMarkus Armbruster     blk_iostatus_enable(blk);
2659c4d74df7SMarkus Armbruster     return 0;
266088804180SGerd Hoffmann }
266188804180SGerd Hoffmann 
ide_init1(IDEBus * bus,int unit)266257234ee4SMarkus Armbruster static void ide_init1(IDEBus *bus, int unit)
266388804180SGerd Hoffmann {
266488804180SGerd Hoffmann     static int drive_serial = 1;
2665d459da0eSMarkus Armbruster     IDEState *s = &bus->ifs[unit];
266688804180SGerd Hoffmann 
266788804180SGerd Hoffmann     s->bus = bus;
2668d459da0eSMarkus Armbruster     s->unit = unit;
266988804180SGerd Hoffmann     s->drive_serial = drive_serial++;
26701b2adf28SChristoph Hellwig     /* we need at least 2k alignment for accessing CDROMs using O_DIRECT */
267150641c5cSJuan Quintela     s->io_buffer_total_len = IDE_DMA_BUF_SECTORS*512 + 4;
2672c925400bSKevin Wolf     s->io_buffer = qemu_memalign(2048, s->io_buffer_total_len);
2673c925400bSKevin Wolf     memset(s->io_buffer, 0, s->io_buffer_total_len);
2674c925400bSKevin Wolf 
26754be74634SMarkus Armbruster     s->smart_selftest_data = blk_blockalign(s->blk, 512);
2676c925400bSKevin Wolf     memset(s->smart_selftest_data, 0, 512);
2677c925400bSKevin Wolf 
2678bc72ad67SAlex Bligh     s->sector_write_timer = timer_new_ns(QEMU_CLOCK_VIRTUAL,
267959f2a787SGerd Hoffmann                                            ide_sector_write_timer_cb, s);
2680d459da0eSMarkus Armbruster }
2681d459da0eSMarkus Armbruster 
ide_nop_int(const IDEDMA * dma,bool is_write)2682ae0cebd7SPhilippe Mathieu-Daudé static int ide_nop_int(const IDEDMA *dma, bool is_write)
268340a6238aSAlexander Graf {
268440a6238aSAlexander Graf     return 0;
268540a6238aSAlexander Graf }
268640a6238aSAlexander Graf 
ide_nop(const IDEDMA * dma)2687ae0cebd7SPhilippe Mathieu-Daudé static void ide_nop(const IDEDMA *dma)
26889898586dSPaolo Bonzini {
26899898586dSPaolo Bonzini }
26909898586dSPaolo Bonzini 
ide_nop_int32(const IDEDMA * dma,int32_t l)2691ae0cebd7SPhilippe Mathieu-Daudé static int32_t ide_nop_int32(const IDEDMA *dma, int32_t l)
26923251bdcfSJohn Snow {
26933251bdcfSJohn Snow     return 0;
26943251bdcfSJohn Snow }
26953251bdcfSJohn Snow 
269640a6238aSAlexander Graf static const IDEDMAOps ide_dma_nop_ops = {
26973251bdcfSJohn Snow     .prepare_buf    = ide_nop_int32,
26989898586dSPaolo Bonzini     .restart_dma    = ide_nop,
269940a6238aSAlexander Graf     .rw_buf         = ide_nop_int,
270040a6238aSAlexander Graf };
270140a6238aSAlexander Graf 
ide_restart_dma(IDEState * s,enum ide_dma_cmd dma_cmd)27029898586dSPaolo Bonzini static void ide_restart_dma(IDEState *s, enum ide_dma_cmd dma_cmd)
27039898586dSPaolo Bonzini {
2704a96cb236SPaolo Bonzini     s->unit = s->bus->retry_unit;
2705dc5d0af4SPaolo Bonzini     ide_set_sector(s, s->bus->retry_sector_num);
2706dc5d0af4SPaolo Bonzini     s->nsector = s->bus->retry_nsector;
27079898586dSPaolo Bonzini     s->bus->dma->ops->restart_dma(s->bus->dma);
27089898586dSPaolo Bonzini     s->io_buffer_size = 0;
27099898586dSPaolo Bonzini     s->dma_cmd = dma_cmd;
27109898586dSPaolo Bonzini     ide_start_dma(s, ide_dma_cb);
27119898586dSPaolo Bonzini }
27129898586dSPaolo Bonzini 
ide_restart_bh(void * opaque)27139898586dSPaolo Bonzini static void ide_restart_bh(void *opaque)
27149898586dSPaolo Bonzini {
27159898586dSPaolo Bonzini     IDEBus *bus = opaque;
27169898586dSPaolo Bonzini     IDEState *s;
27179898586dSPaolo Bonzini     bool is_read;
27189898586dSPaolo Bonzini     int error_status;
27199898586dSPaolo Bonzini 
27209898586dSPaolo Bonzini     qemu_bh_delete(bus->bh);
27219898586dSPaolo Bonzini     bus->bh = NULL;
27229898586dSPaolo Bonzini 
27239898586dSPaolo Bonzini     error_status = bus->error_status;
27249898586dSPaolo Bonzini     if (bus->error_status == 0) {
27259898586dSPaolo Bonzini         return;
27269898586dSPaolo Bonzini     }
27279898586dSPaolo Bonzini 
27282c50207fSPhilippe Mathieu-Daudé     s = ide_bus_active_if(bus);
27299898586dSPaolo Bonzini     is_read = (bus->error_status & IDE_RETRY_READ) != 0;
27309898586dSPaolo Bonzini 
27319898586dSPaolo Bonzini     /* The error status must be cleared before resubmitting the request: The
27329898586dSPaolo Bonzini      * request may fail again, and this case can only be distinguished if the
27339898586dSPaolo Bonzini      * called function can set a new error status. */
27349898586dSPaolo Bonzini     bus->error_status = 0;
27359898586dSPaolo Bonzini 
27367c03a691SJohn Snow     /* The HBA has generically asked to be kicked on retry */
27377c03a691SJohn Snow     if (error_status & IDE_RETRY_HBA) {
27387c03a691SJohn Snow         if (s->bus->dma->ops->restart) {
27397c03a691SJohn Snow             s->bus->dma->ops->restart(s->bus->dma);
27407c03a691SJohn Snow         }
2741502356eeSPavel Butsykin     } else if (IS_IDE_RETRY_DMA(error_status)) {
27429898586dSPaolo Bonzini         if (error_status & IDE_RETRY_TRIM) {
27439898586dSPaolo Bonzini             ide_restart_dma(s, IDE_DMA_TRIM);
27449898586dSPaolo Bonzini         } else {
27459898586dSPaolo Bonzini             ide_restart_dma(s, is_read ? IDE_DMA_READ : IDE_DMA_WRITE);
27469898586dSPaolo Bonzini         }
2747502356eeSPavel Butsykin     } else if (IS_IDE_RETRY_PIO(error_status)) {
27489898586dSPaolo Bonzini         if (is_read) {
27499898586dSPaolo Bonzini             ide_sector_read(s);
27509898586dSPaolo Bonzini         } else {
27519898586dSPaolo Bonzini             ide_sector_write(s);
27529898586dSPaolo Bonzini         }
27539898586dSPaolo Bonzini     } else if (error_status & IDE_RETRY_FLUSH) {
27549898586dSPaolo Bonzini         ide_flush_cache(s);
2755502356eeSPavel Butsykin     } else if (IS_IDE_RETRY_ATAPI(error_status)) {
2756502356eeSPavel Butsykin         assert(s->end_transfer_func == ide_atapi_cmd);
27579898586dSPaolo Bonzini         ide_atapi_dma_restart(s);
2758502356eeSPavel Butsykin     } else {
2759502356eeSPavel Butsykin         abort();
27609898586dSPaolo Bonzini     }
27619898586dSPaolo Bonzini }
27629898586dSPaolo Bonzini 
ide_restart_cb(void * opaque,bool running,RunState state)2763538f0497SPhilippe Mathieu-Daudé static void ide_restart_cb(void *opaque, bool running, RunState state)
27649898586dSPaolo Bonzini {
27659898586dSPaolo Bonzini     IDEBus *bus = opaque;
27669898586dSPaolo Bonzini 
27679898586dSPaolo Bonzini     if (!running)
27689898586dSPaolo Bonzini         return;
27699898586dSPaolo Bonzini 
27709898586dSPaolo Bonzini     if (!bus->bh) {
27719898586dSPaolo Bonzini         bus->bh = qemu_bh_new(ide_restart_bh, bus);
27729898586dSPaolo Bonzini         qemu_bh_schedule(bus->bh);
27739898586dSPaolo Bonzini     }
27749898586dSPaolo Bonzini }
27759898586dSPaolo Bonzini 
ide_bus_register_restart_cb(IDEBus * bus)2776e29b1246SPhilippe Mathieu-Daudé void ide_bus_register_restart_cb(IDEBus *bus)
2777f878c916SPaolo Bonzini {
27789898586dSPaolo Bonzini     if (bus->dma->ops->restart_dma) {
2779ca44141dSAshijeet Acharya         bus->vmstate = qemu_add_vm_change_state_handler(ide_restart_cb, bus);
27809898586dSPaolo Bonzini     }
2781f878c916SPaolo Bonzini }
2782f878c916SPaolo Bonzini 
278340a6238aSAlexander Graf static IDEDMA ide_dma_nop = {
278440a6238aSAlexander Graf     .ops = &ide_dma_nop_ops,
278540a6238aSAlexander Graf     .aiocb = NULL,
278640a6238aSAlexander Graf };
278740a6238aSAlexander Graf 
ide_bus_init_output_irq(IDEBus * bus,qemu_irq irq_out)2788c9519630SPhilippe Mathieu-Daudé void ide_bus_init_output_irq(IDEBus *bus, qemu_irq irq_out)
2789d459da0eSMarkus Armbruster {
2790d459da0eSMarkus Armbruster     int i;
2791d459da0eSMarkus Armbruster 
2792d459da0eSMarkus Armbruster     for(i = 0; i < 2; i++) {
279357234ee4SMarkus Armbruster         ide_init1(bus, i);
279457234ee4SMarkus Armbruster         ide_reset(&bus->ifs[i]);
279557234ee4SMarkus Armbruster     }
2796c9519630SPhilippe Mathieu-Daudé     bus->irq = irq_out;
279740a6238aSAlexander Graf     bus->dma = &ide_dma_nop;
279857234ee4SMarkus Armbruster }
279957234ee4SMarkus Armbruster 
ide_bus_set_irq(IDEBus * bus)28000cfe719dSPhilippe Mathieu-Daudé void ide_bus_set_irq(IDEBus *bus)
2801da9f1172SPhilippe Mathieu-Daudé {
2802da9f1172SPhilippe Mathieu-Daudé     if (!(bus->cmd & IDE_CTRL_DISABLE_IRQ)) {
2803da9f1172SPhilippe Mathieu-Daudé         qemu_irq_raise(bus->irq);
2804da9f1172SPhilippe Mathieu-Daudé     }
2805da9f1172SPhilippe Mathieu-Daudé }
2806da9f1172SPhilippe Mathieu-Daudé 
ide_exit(IDEState * s)2807c9f08641SLi Qiang void ide_exit(IDEState *s)
2808c9f08641SLi Qiang {
2809c9f08641SLi Qiang     timer_free(s->sector_write_timer);
2810c9f08641SLi Qiang     qemu_vfree(s->smart_selftest_data);
2811c9f08641SLi Qiang     qemu_vfree(s->io_buffer);
2812c9f08641SLi Qiang }
2813c9f08641SLi Qiang 
is_identify_set(void * opaque,int version_id)281437159f13SJuan Quintela static bool is_identify_set(void *opaque, int version_id)
281559f2a787SGerd Hoffmann {
281637159f13SJuan Quintela     IDEState *s = opaque;
281759f2a787SGerd Hoffmann 
281837159f13SJuan Quintela     return s->identify_set != 0;
281959f2a787SGerd Hoffmann }
282059f2a787SGerd Hoffmann 
282150641c5cSJuan Quintela static EndTransferFunc* transfer_end_table[] = {
282250641c5cSJuan Quintela         ide_sector_read,
282350641c5cSJuan Quintela         ide_sector_write,
282450641c5cSJuan Quintela         ide_transfer_stop,
282550641c5cSJuan Quintela         ide_atapi_cmd_reply_end,
282650641c5cSJuan Quintela         ide_atapi_cmd,
282750641c5cSJuan Quintela         ide_dummy_transfer_stop,
282850641c5cSJuan Quintela };
282950641c5cSJuan Quintela 
transfer_end_table_idx(EndTransferFunc * fn)283050641c5cSJuan Quintela static int transfer_end_table_idx(EndTransferFunc *fn)
283150641c5cSJuan Quintela {
283250641c5cSJuan Quintela     int i;
283350641c5cSJuan Quintela 
283450641c5cSJuan Quintela     for (i = 0; i < ARRAY_SIZE(transfer_end_table); i++)
283550641c5cSJuan Quintela         if (transfer_end_table[i] == fn)
283650641c5cSJuan Quintela             return i;
283750641c5cSJuan Quintela 
283850641c5cSJuan Quintela     return -1;
283950641c5cSJuan Quintela }
284050641c5cSJuan Quintela 
ide_drive_post_load(void * opaque,int version_id)284137159f13SJuan Quintela static int ide_drive_post_load(void *opaque, int version_id)
284259f2a787SGerd Hoffmann {
284337159f13SJuan Quintela     IDEState *s = opaque;
284459f2a787SGerd Hoffmann 
28456b896ab2SDon Slutz     if (s->blk && s->identify_set) {
28464be74634SMarkus Armbruster         blk_set_enable_write_cache(s->blk, !!(s->identify_data[85] & (1 << 5)));
28477cdd481cSPaolo Bonzini     }
284837159f13SJuan Quintela     return 0;
284937159f13SJuan Quintela }
285037159f13SJuan Quintela 
ide_drive_pio_post_load(void * opaque,int version_id)285150641c5cSJuan Quintela static int ide_drive_pio_post_load(void *opaque, int version_id)
285250641c5cSJuan Quintela {
285350641c5cSJuan Quintela     IDEState *s = opaque;
285450641c5cSJuan Quintela 
2855fb60105dSKevin Wolf     if (s->end_transfer_fn_idx >= ARRAY_SIZE(transfer_end_table)) {
285650641c5cSJuan Quintela         return -EINVAL;
285750641c5cSJuan Quintela     }
285850641c5cSJuan Quintela     s->end_transfer_func = transfer_end_table[s->end_transfer_fn_idx];
285950641c5cSJuan Quintela     s->data_ptr = s->io_buffer + s->cur_io_buffer_offset;
286050641c5cSJuan Quintela     s->data_end = s->data_ptr + s->cur_io_buffer_len;
2861819fa276SDr. David Alan Gilbert     s->atapi_dma = s->feature & 1; /* as per cmd_packet */
286250641c5cSJuan Quintela 
286350641c5cSJuan Quintela     return 0;
286450641c5cSJuan Quintela }
286550641c5cSJuan Quintela 
ide_drive_pio_pre_save(void * opaque)286644b1ff31SDr. David Alan Gilbert static int ide_drive_pio_pre_save(void *opaque)
286750641c5cSJuan Quintela {
286850641c5cSJuan Quintela     IDEState *s = opaque;
286950641c5cSJuan Quintela     int idx;
287050641c5cSJuan Quintela 
287150641c5cSJuan Quintela     s->cur_io_buffer_offset = s->data_ptr - s->io_buffer;
287250641c5cSJuan Quintela     s->cur_io_buffer_len = s->data_end - s->data_ptr;
287350641c5cSJuan Quintela 
287450641c5cSJuan Quintela     idx = transfer_end_table_idx(s->end_transfer_func);
287550641c5cSJuan Quintela     if (idx == -1) {
287650641c5cSJuan Quintela         fprintf(stderr, "%s: invalid end_transfer_func for DRQ_STAT\n",
287750641c5cSJuan Quintela                         __func__);
287850641c5cSJuan Quintela         s->end_transfer_fn_idx = 2;
287950641c5cSJuan Quintela     } else {
288050641c5cSJuan Quintela         s->end_transfer_fn_idx = idx;
288150641c5cSJuan Quintela     }
288244b1ff31SDr. David Alan Gilbert 
288344b1ff31SDr. David Alan Gilbert     return 0;
288450641c5cSJuan Quintela }
288550641c5cSJuan Quintela 
ide_drive_pio_state_needed(void * opaque)288650641c5cSJuan Quintela static bool ide_drive_pio_state_needed(void *opaque)
288750641c5cSJuan Quintela {
288850641c5cSJuan Quintela     IDEState *s = opaque;
288950641c5cSJuan Quintela 
2890fdc650d7SKevin Wolf     return ((s->status & DRQ_STAT) != 0)
2891fd648f10SPaolo Bonzini         || (s->bus->error_status & IDE_RETRY_PIO);
289250641c5cSJuan Quintela }
289350641c5cSJuan Quintela 
ide_tray_state_needed(void * opaque)2894db118fe7SMarkus Armbruster static bool ide_tray_state_needed(void *opaque)
2895db118fe7SMarkus Armbruster {
2896db118fe7SMarkus Armbruster     IDEState *s = opaque;
2897db118fe7SMarkus Armbruster 
2898db118fe7SMarkus Armbruster     return s->tray_open || s->tray_locked;
2899db118fe7SMarkus Armbruster }
2900db118fe7SMarkus Armbruster 
ide_atapi_gesn_needed(void * opaque)2901996faf1aSAmit Shah static bool ide_atapi_gesn_needed(void *opaque)
2902996faf1aSAmit Shah {
2903996faf1aSAmit Shah     IDEState *s = opaque;
2904996faf1aSAmit Shah 
2905996faf1aSAmit Shah     return s->events.new_media || s->events.eject_request;
2906996faf1aSAmit Shah }
2907996faf1aSAmit Shah 
ide_error_needed(void * opaque)2908def93791SKevin Wolf static bool ide_error_needed(void *opaque)
2909def93791SKevin Wolf {
2910def93791SKevin Wolf     IDEBus *bus = opaque;
2911def93791SKevin Wolf 
2912def93791SKevin Wolf     return (bus->error_status != 0);
2913def93791SKevin Wolf }
2914def93791SKevin Wolf 
2915996faf1aSAmit Shah /* Fields for GET_EVENT_STATUS_NOTIFICATION ATAPI command */
2916656fbeffSMarkus Armbruster static const VMStateDescription vmstate_ide_atapi_gesn_state = {
2917996faf1aSAmit Shah     .name ="ide_drive/atapi/gesn_state",
2918996faf1aSAmit Shah     .version_id = 1,
2919996faf1aSAmit Shah     .minimum_version_id = 1,
29205cd8cadaSJuan Quintela     .needed = ide_atapi_gesn_needed,
2921996faf1aSAmit Shah     .fields = (VMStateField[]) {
2922996faf1aSAmit Shah         VMSTATE_BOOL(events.new_media, IDEState),
2923996faf1aSAmit Shah         VMSTATE_BOOL(events.eject_request, IDEState),
29240754f9ecSKevin Wolf         VMSTATE_END_OF_LIST()
2925996faf1aSAmit Shah     }
2926996faf1aSAmit Shah };
2927996faf1aSAmit Shah 
2928db118fe7SMarkus Armbruster static const VMStateDescription vmstate_ide_tray_state = {
2929db118fe7SMarkus Armbruster     .name = "ide_drive/tray_state",
2930db118fe7SMarkus Armbruster     .version_id = 1,
2931db118fe7SMarkus Armbruster     .minimum_version_id = 1,
29325cd8cadaSJuan Quintela     .needed = ide_tray_state_needed,
2933db118fe7SMarkus Armbruster     .fields = (VMStateField[]) {
2934db118fe7SMarkus Armbruster         VMSTATE_BOOL(tray_open, IDEState),
2935db118fe7SMarkus Armbruster         VMSTATE_BOOL(tray_locked, IDEState),
2936db118fe7SMarkus Armbruster         VMSTATE_END_OF_LIST()
2937db118fe7SMarkus Armbruster     }
2938db118fe7SMarkus Armbruster };
2939db118fe7SMarkus Armbruster 
2940656fbeffSMarkus Armbruster static const VMStateDescription vmstate_ide_drive_pio_state = {
294150641c5cSJuan Quintela     .name = "ide_drive/pio_state",
294250641c5cSJuan Quintela     .version_id = 1,
294350641c5cSJuan Quintela     .minimum_version_id = 1,
294450641c5cSJuan Quintela     .pre_save = ide_drive_pio_pre_save,
294550641c5cSJuan Quintela     .post_load = ide_drive_pio_post_load,
29465cd8cadaSJuan Quintela     .needed = ide_drive_pio_state_needed,
294750641c5cSJuan Quintela     .fields = (VMStateField[]) {
294850641c5cSJuan Quintela         VMSTATE_INT32(req_nb_sectors, IDEState),
294950641c5cSJuan Quintela         VMSTATE_VARRAY_INT32(io_buffer, IDEState, io_buffer_total_len, 1,
295050641c5cSJuan Quintela                              vmstate_info_uint8, uint8_t),
295150641c5cSJuan Quintela         VMSTATE_INT32(cur_io_buffer_offset, IDEState),
295250641c5cSJuan Quintela         VMSTATE_INT32(cur_io_buffer_len, IDEState),
295350641c5cSJuan Quintela         VMSTATE_UINT8(end_transfer_fn_idx, IDEState),
295450641c5cSJuan Quintela         VMSTATE_INT32(elementary_transfer_size, IDEState),
295550641c5cSJuan Quintela         VMSTATE_INT32(packet_transfer_size, IDEState),
295650641c5cSJuan Quintela         VMSTATE_END_OF_LIST()
295750641c5cSJuan Quintela     }
295850641c5cSJuan Quintela };
295950641c5cSJuan Quintela 
296037159f13SJuan Quintela const VMStateDescription vmstate_ide_drive = {
296137159f13SJuan Quintela     .name = "ide_drive",
29623abb6260SJuan Quintela     .version_id = 3,
296337159f13SJuan Quintela     .minimum_version_id = 0,
296437159f13SJuan Quintela     .post_load = ide_drive_post_load,
296537159f13SJuan Quintela     .fields = (VMStateField[]) {
296637159f13SJuan Quintela         VMSTATE_INT32(mult_sectors, IDEState),
296737159f13SJuan Quintela         VMSTATE_INT32(identify_set, IDEState),
296837159f13SJuan Quintela         VMSTATE_BUFFER_TEST(identify_data, IDEState, is_identify_set),
296937159f13SJuan Quintela         VMSTATE_UINT8(feature, IDEState),
297037159f13SJuan Quintela         VMSTATE_UINT8(error, IDEState),
297137159f13SJuan Quintela         VMSTATE_UINT32(nsector, IDEState),
297237159f13SJuan Quintela         VMSTATE_UINT8(sector, IDEState),
297337159f13SJuan Quintela         VMSTATE_UINT8(lcyl, IDEState),
297437159f13SJuan Quintela         VMSTATE_UINT8(hcyl, IDEState),
297537159f13SJuan Quintela         VMSTATE_UINT8(hob_feature, IDEState),
297637159f13SJuan Quintela         VMSTATE_UINT8(hob_sector, IDEState),
297737159f13SJuan Quintela         VMSTATE_UINT8(hob_nsector, IDEState),
297837159f13SJuan Quintela         VMSTATE_UINT8(hob_lcyl, IDEState),
297937159f13SJuan Quintela         VMSTATE_UINT8(hob_hcyl, IDEState),
298037159f13SJuan Quintela         VMSTATE_UINT8(select, IDEState),
298137159f13SJuan Quintela         VMSTATE_UINT8(status, IDEState),
298237159f13SJuan Quintela         VMSTATE_UINT8(lba48, IDEState),
298337159f13SJuan Quintela         VMSTATE_UINT8(sense_key, IDEState),
298437159f13SJuan Quintela         VMSTATE_UINT8(asc, IDEState),
298537159f13SJuan Quintela         VMSTATE_UINT8_V(cdrom_changed, IDEState, 3),
298637159f13SJuan Quintela         VMSTATE_END_OF_LIST()
298750641c5cSJuan Quintela     },
29885cd8cadaSJuan Quintela     .subsections = (const VMStateDescription*[]) {
29895cd8cadaSJuan Quintela         &vmstate_ide_drive_pio_state,
29905cd8cadaSJuan Quintela         &vmstate_ide_tray_state,
29915cd8cadaSJuan Quintela         &vmstate_ide_atapi_gesn_state,
29925cd8cadaSJuan Quintela         NULL
299337159f13SJuan Quintela     }
299437159f13SJuan Quintela };
299537159f13SJuan Quintela 
2996656fbeffSMarkus Armbruster static const VMStateDescription vmstate_ide_error_status = {
2997def93791SKevin Wolf     .name ="ide_bus/error",
2998d12b9ff2SPaolo Bonzini     .version_id = 2,
2999def93791SKevin Wolf     .minimum_version_id = 1,
30005cd8cadaSJuan Quintela     .needed = ide_error_needed,
3001def93791SKevin Wolf     .fields = (VMStateField[]) {
3002def93791SKevin Wolf         VMSTATE_INT32(error_status, IDEBus),
3003d12b9ff2SPaolo Bonzini         VMSTATE_INT64_V(retry_sector_num, IDEBus, 2),
3004d12b9ff2SPaolo Bonzini         VMSTATE_UINT32_V(retry_nsector, IDEBus, 2),
3005d12b9ff2SPaolo Bonzini         VMSTATE_UINT8_V(retry_unit, IDEBus, 2),
3006def93791SKevin Wolf         VMSTATE_END_OF_LIST()
3007def93791SKevin Wolf     }
3008def93791SKevin Wolf };
3009def93791SKevin Wolf 
30106521dc62SJuan Quintela const VMStateDescription vmstate_ide_bus = {
30116521dc62SJuan Quintela     .name = "ide_bus",
30126521dc62SJuan Quintela     .version_id = 1,
30136521dc62SJuan Quintela     .minimum_version_id = 1,
30146521dc62SJuan Quintela     .fields = (VMStateField[]) {
30156521dc62SJuan Quintela         VMSTATE_UINT8(cmd, IDEBus),
30166521dc62SJuan Quintela         VMSTATE_UINT8(unit, IDEBus),
30176521dc62SJuan Quintela         VMSTATE_END_OF_LIST()
3018def93791SKevin Wolf     },
30195cd8cadaSJuan Quintela     .subsections = (const VMStateDescription*[]) {
30205cd8cadaSJuan Quintela         &vmstate_ide_error_status,
30215cd8cadaSJuan Quintela         NULL
30226521dc62SJuan Quintela     }
30236521dc62SJuan Quintela };
302475717903SIsaku Yamahata 
ide_drive_get(DriveInfo ** hd,int n)3025d8f94e1bSJohn Snow void ide_drive_get(DriveInfo **hd, int n)
302675717903SIsaku Yamahata {
302775717903SIsaku Yamahata     int i;
302875717903SIsaku Yamahata 
3029d8f94e1bSJohn Snow     for (i = 0; i < n; i++) {
3030d8f94e1bSJohn Snow         hd[i] = drive_get_by_index(IF_IDE, i);
303175717903SIsaku Yamahata     }
303275717903SIsaku Yamahata }
3033