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