159f2a787SGerd Hoffmann /*
259f2a787SGerd Hoffmann * QEMU IDE disk and CD/DVD-ROM Emulator
359f2a787SGerd Hoffmann *
459f2a787SGerd Hoffmann * Copyright (c) 2003 Fabrice Bellard
559f2a787SGerd Hoffmann * Copyright (c) 2006 Openedhand Ltd.
659f2a787SGerd Hoffmann *
759f2a787SGerd Hoffmann * Permission is hereby granted, free of charge, to any person obtaining a copy
859f2a787SGerd Hoffmann * of this software and associated documentation files (the "Software"), to deal
959f2a787SGerd Hoffmann * in the Software without restriction, including without limitation the rights
1059f2a787SGerd Hoffmann * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
1159f2a787SGerd Hoffmann * copies of the Software, and to permit persons to whom the Software is
1259f2a787SGerd Hoffmann * furnished to do so, subject to the following conditions:
1359f2a787SGerd Hoffmann *
1459f2a787SGerd Hoffmann * The above copyright notice and this permission notice shall be included in
1559f2a787SGerd Hoffmann * all copies or substantial portions of the Software.
1659f2a787SGerd Hoffmann *
1759f2a787SGerd Hoffmann * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
1859f2a787SGerd Hoffmann * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
1959f2a787SGerd Hoffmann * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
2059f2a787SGerd Hoffmann * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
2159f2a787SGerd Hoffmann * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
2259f2a787SGerd Hoffmann * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
2359f2a787SGerd Hoffmann * THE SOFTWARE.
2459f2a787SGerd Hoffmann */
25e688df6bSMarkus Armbruster
2653239262SPeter Maydell #include "qemu/osdep.h"
27da9f1172SPhilippe Mathieu-Daudé #include "hw/irq.h"
28a9c94277SMarkus Armbruster #include "hw/isa/isa.h"
29d6454270SMarkus Armbruster #include "migration/vmstate.h"
301de7afc9SPaolo Bonzini #include "qemu/error-report.h"
31db725815SMarkus Armbruster #include "qemu/main-loop.h"
321de7afc9SPaolo Bonzini #include "qemu/timer.h"
3315e09912SPeter Maydell #include "qemu/hw-version.h"
345df022cfSPeter Maydell #include "qemu/memalign.h"
359c17d615SPaolo Bonzini #include "sysemu/sysemu.h"
3678631611SPhilippe Mathieu-Daudé #include "sysemu/blockdev.h"
379c17d615SPaolo Bonzini #include "sysemu/dma.h"
380d09e41aSPaolo Bonzini #include "hw/block/block.h"
394be74634SMarkus Armbruster #include "sysemu/block-backend.h"
40e688df6bSMarkus Armbruster #include "qapi/error.h"
41f348b6d1SVeronia Bahaa #include "qemu/cutils.h"
42b255df7eSPavel Dovgalyuk #include "sysemu/replay.h"
4354d31236SMarkus Armbruster #include "sysemu/runstate.h"
44a9c94277SMarkus Armbruster #include "hw/ide/internal.h"
453eee2611SJohn Snow #include "trace.h"
4659f2a787SGerd Hoffmann
47b93af93dSBrian Wheeler /* These values were based on a Seagate ST3500418AS but have been modified
48b93af93dSBrian Wheeler to make more sense in QEMU */
49b93af93dSBrian Wheeler static const int smart_attributes[][12] = {
50b93af93dSBrian Wheeler /* id, flags, hflags, val, wrst, raw (6 bytes), threshold */
51b93af93dSBrian Wheeler /* raw read error rate*/
52b93af93dSBrian Wheeler { 0x01, 0x03, 0x00, 0x64, 0x64, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06},
53b93af93dSBrian Wheeler /* spin up */
54b93af93dSBrian Wheeler { 0x03, 0x03, 0x00, 0x64, 0x64, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
55b93af93dSBrian Wheeler /* start stop count */
56b93af93dSBrian Wheeler { 0x04, 0x02, 0x00, 0x64, 0x64, 0x64, 0x00, 0x00, 0x00, 0x00, 0x00, 0x14},
57b93af93dSBrian Wheeler /* remapped sectors */
58b93af93dSBrian Wheeler { 0x05, 0x03, 0x00, 0x64, 0x64, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x24},
59b93af93dSBrian Wheeler /* power on hours */
60b93af93dSBrian Wheeler { 0x09, 0x03, 0x00, 0x64, 0x64, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
61b93af93dSBrian Wheeler /* power cycle count */
62b93af93dSBrian Wheeler { 0x0c, 0x03, 0x00, 0x64, 0x64, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
63b93af93dSBrian Wheeler /* airflow-temperature-celsius */
64b93af93dSBrian Wheeler { 190, 0x03, 0x00, 0x45, 0x45, 0x1f, 0x00, 0x1f, 0x1f, 0x00, 0x00, 0x32},
6559f2a787SGerd Hoffmann };
6659f2a787SGerd Hoffmann
670e168d35SJohn Snow const char *IDE_DMA_CMD_lookup[IDE_DMA__COUNT] = {
680e168d35SJohn Snow [IDE_DMA_READ] = "DMA READ",
690e168d35SJohn Snow [IDE_DMA_WRITE] = "DMA WRITE",
700e168d35SJohn Snow [IDE_DMA_TRIM] = "DMA TRIM",
710e168d35SJohn Snow [IDE_DMA_ATAPI] = "DMA ATAPI"
720e168d35SJohn Snow };
730e168d35SJohn Snow
IDE_DMA_CMD_str(enum ide_dma_cmd enval)740e168d35SJohn Snow static const char *IDE_DMA_CMD_str(enum ide_dma_cmd enval)
750e168d35SJohn Snow {
76159a9df0SJohn Snow if ((unsigned)enval < IDE_DMA__COUNT) {
770e168d35SJohn Snow return IDE_DMA_CMD_lookup[enval];
780e168d35SJohn Snow }
790e168d35SJohn Snow return "DMA UNKNOWN CMD";
800e168d35SJohn Snow }
810e168d35SJohn Snow
8240c4ed3fSKevin Wolf static void ide_dummy_transfer_stop(IDEState *s);
8359f2a787SGerd Hoffmann
84*75524884SMark Cave-Ayland const MemoryRegionPortio ide_portio_list[] = {
85*75524884SMark Cave-Ayland { 0, 8, 1, .read = ide_ioport_read, .write = ide_ioport_write },
86*75524884SMark Cave-Ayland { 0, 1, 2, .read = ide_data_readw, .write = ide_data_writew },
87*75524884SMark Cave-Ayland { 0, 1, 4, .read = ide_data_readl, .write = ide_data_writel },
88*75524884SMark Cave-Ayland PORTIO_END_OF_LIST(),
89*75524884SMark Cave-Ayland };
90*75524884SMark Cave-Ayland
91*75524884SMark Cave-Ayland const MemoryRegionPortio ide_portio2_list[] = {
92*75524884SMark Cave-Ayland { 0, 1, 1, .read = ide_status_read, .write = ide_ctrl_write },
93*75524884SMark Cave-Ayland PORTIO_END_OF_LIST(),
94*75524884SMark Cave-Ayland };
95*75524884SMark Cave-Ayland
padstr(char * str,const char * src,int len)9659f2a787SGerd Hoffmann static void padstr(char *str, const char *src, int len)
9759f2a787SGerd Hoffmann {
9859f2a787SGerd Hoffmann int i, v;
9959f2a787SGerd Hoffmann for(i = 0; i < len; i++) {
10059f2a787SGerd Hoffmann if (*src)
10159f2a787SGerd Hoffmann v = *src++;
10259f2a787SGerd Hoffmann else
10359f2a787SGerd Hoffmann v = ' ';
10459f2a787SGerd Hoffmann str[i^1] = v;
10559f2a787SGerd Hoffmann }
10659f2a787SGerd Hoffmann }
10759f2a787SGerd Hoffmann
put_le16(uint16_t * p,unsigned int v)10859f2a787SGerd Hoffmann static void put_le16(uint16_t *p, unsigned int v)
10959f2a787SGerd Hoffmann {
11059f2a787SGerd Hoffmann *p = cpu_to_le16(v);
11159f2a787SGerd Hoffmann }
11259f2a787SGerd Hoffmann
ide_identify_size(IDEState * s)11301ce352eSJohn Snow static void ide_identify_size(IDEState *s)
11401ce352eSJohn Snow {
11501ce352eSJohn Snow uint16_t *p = (uint16_t *)s->identify_data;
11646e018e9SSamuel Thibault int64_t nb_sectors_lba28 = s->nb_sectors;
11746e018e9SSamuel Thibault if (nb_sectors_lba28 >= 1 << 28) {
11846e018e9SSamuel Thibault nb_sectors_lba28 = (1 << 28) - 1;
11946e018e9SSamuel Thibault }
12046e018e9SSamuel Thibault put_le16(p + 60, nb_sectors_lba28);
12146e018e9SSamuel Thibault put_le16(p + 61, nb_sectors_lba28 >> 16);
12201ce352eSJohn Snow put_le16(p + 100, s->nb_sectors);
12301ce352eSJohn Snow put_le16(p + 101, s->nb_sectors >> 16);
12401ce352eSJohn Snow put_le16(p + 102, s->nb_sectors >> 32);
12501ce352eSJohn Snow put_le16(p + 103, s->nb_sectors >> 48);
12601ce352eSJohn Snow }
12701ce352eSJohn Snow
ide_identify(IDEState * s)12859f2a787SGerd Hoffmann static void ide_identify(IDEState *s)
12959f2a787SGerd Hoffmann {
13059f2a787SGerd Hoffmann uint16_t *p;
13159f2a787SGerd Hoffmann unsigned int oldsize;
132d353fb72SChristoph Hellwig IDEDevice *dev = s->unit ? s->bus->slave : s->bus->master;
13359f2a787SGerd Hoffmann
1344bf6637dSJohn Snow p = (uint16_t *)s->identify_data;
13559f2a787SGerd Hoffmann if (s->identify_set) {
1364bf6637dSJohn Snow goto fill_buffer;
13759f2a787SGerd Hoffmann }
1384bf6637dSJohn Snow memset(p, 0, sizeof(s->identify_data));
13959f2a787SGerd Hoffmann
14059f2a787SGerd Hoffmann put_le16(p + 0, 0x0040);
14159f2a787SGerd Hoffmann put_le16(p + 1, s->cylinders);
14259f2a787SGerd Hoffmann put_le16(p + 3, s->heads);
14359f2a787SGerd Hoffmann put_le16(p + 4, 512 * s->sectors); /* XXX: retired, remove ? */
14459f2a787SGerd Hoffmann put_le16(p + 5, 512); /* XXX: retired, remove ? */
14559f2a787SGerd Hoffmann put_le16(p + 6, s->sectors);
14659f2a787SGerd Hoffmann padstr((char *)(p + 10), s->drive_serial_str, 20); /* serial number */
14759f2a787SGerd Hoffmann put_le16(p + 20, 3); /* XXX: retired, remove ? */
14859f2a787SGerd Hoffmann put_le16(p + 21, 512); /* cache size in sectors */
14959f2a787SGerd Hoffmann put_le16(p + 22, 4); /* ecc bytes */
15047c06340SGerd Hoffmann padstr((char *)(p + 23), s->version, 8); /* firmware version */
15127e0c9a1SFloris Bos padstr((char *)(p + 27), s->drive_model_str, 40); /* model */
15259f2a787SGerd Hoffmann #if MAX_MULT_SECTORS > 1
15359f2a787SGerd Hoffmann put_le16(p + 47, 0x8000 | MAX_MULT_SECTORS);
15459f2a787SGerd Hoffmann #endif
15559f2a787SGerd Hoffmann put_le16(p + 48, 1); /* dword I/O */
15659f2a787SGerd Hoffmann put_le16(p + 49, (1 << 11) | (1 << 9) | (1 << 8)); /* DMA and LBA supported */
15759f2a787SGerd Hoffmann put_le16(p + 51, 0x200); /* PIO transfer cycle */
15859f2a787SGerd Hoffmann put_le16(p + 52, 0x200); /* DMA transfer cycle */
15959f2a787SGerd Hoffmann put_le16(p + 53, 1 | (1 << 1) | (1 << 2)); /* words 54-58,64-70,88 are valid */
16059f2a787SGerd Hoffmann put_le16(p + 54, s->cylinders);
16159f2a787SGerd Hoffmann put_le16(p + 55, s->heads);
16259f2a787SGerd Hoffmann put_le16(p + 56, s->sectors);
16359f2a787SGerd Hoffmann oldsize = s->cylinders * s->heads * s->sectors;
16459f2a787SGerd Hoffmann put_le16(p + 57, oldsize);
16559f2a787SGerd Hoffmann put_le16(p + 58, oldsize >> 16);
16659f2a787SGerd Hoffmann if (s->mult_sectors)
16759f2a787SGerd Hoffmann put_le16(p + 59, 0x100 | s->mult_sectors);
16801ce352eSJohn Snow /* *(p + 60) := nb_sectors -- see ide_identify_size */
16901ce352eSJohn Snow /* *(p + 61) := nb_sectors >> 16 -- see ide_identify_size */
17059f2a787SGerd Hoffmann put_le16(p + 62, 0x07); /* single word dma0-2 supported */
17159f2a787SGerd Hoffmann put_le16(p + 63, 0x07); /* mdma0-2 supported */
17279d1d331SJonathan A. Kollasch put_le16(p + 64, 0x03); /* pio3-4 supported */
17359f2a787SGerd Hoffmann put_le16(p + 65, 120);
17459f2a787SGerd Hoffmann put_le16(p + 66, 120);
17559f2a787SGerd Hoffmann put_le16(p + 67, 120);
17659f2a787SGerd Hoffmann put_le16(p + 68, 120);
177d353fb72SChristoph Hellwig if (dev && dev->conf.discard_granularity) {
178d353fb72SChristoph Hellwig put_le16(p + 69, (1 << 14)); /* determinate TRIM behavior */
179d353fb72SChristoph Hellwig }
180ccf0fd8bSRoland Elek
181ccf0fd8bSRoland Elek if (s->ncq_queues) {
182ccf0fd8bSRoland Elek put_le16(p + 75, s->ncq_queues - 1);
183ccf0fd8bSRoland Elek /* NCQ supported */
184ccf0fd8bSRoland Elek put_le16(p + 76, (1 << 8));
185ccf0fd8bSRoland Elek }
186ccf0fd8bSRoland Elek
18759f2a787SGerd Hoffmann put_le16(p + 80, 0xf0); /* ata3 -> ata6 supported */
18859f2a787SGerd Hoffmann put_le16(p + 81, 0x16); /* conforms to ata5 */
189a58b8d54SChristoph Hellwig /* 14=NOP supported, 5=WCACHE supported, 0=SMART supported */
190a58b8d54SChristoph Hellwig put_le16(p + 82, (1 << 14) | (1 << 5) | 1);
19159f2a787SGerd Hoffmann /* 13=flush_cache_ext,12=flush_cache,10=lba48 */
19259f2a787SGerd Hoffmann put_le16(p + 83, (1 << 14) | (1 << 13) | (1 <<12) | (1 << 10));
19395ebda85SFloris Bos /* 14=set to 1, 8=has WWN, 1=SMART self test, 0=SMART error logging */
19495ebda85SFloris Bos if (s->wwn) {
19595ebda85SFloris Bos put_le16(p + 84, (1 << 14) | (1 << 8) | 0);
19695ebda85SFloris Bos } else {
19759f2a787SGerd Hoffmann put_le16(p + 84, (1 << 14) | 0);
19895ebda85SFloris Bos }
199e900a7b7SChristoph Hellwig /* 14 = NOP supported, 5=WCACHE enabled, 0=SMART feature set enabled */
2004be74634SMarkus Armbruster if (blk_enable_write_cache(s->blk)) {
201e900a7b7SChristoph Hellwig put_le16(p + 85, (1 << 14) | (1 << 5) | 1);
2024be74634SMarkus Armbruster } else {
20359f2a787SGerd Hoffmann put_le16(p + 85, (1 << 14) | 1);
2044be74634SMarkus Armbruster }
20559f2a787SGerd Hoffmann /* 13=flush_cache_ext,12=flush_cache,10=lba48 */
2062844bdd9SKevin Wolf put_le16(p + 86, (1 << 13) | (1 <<12) | (1 << 10));
20795ebda85SFloris Bos /* 14=set to 1, 8=has WWN, 1=SMART self test, 0=SMART error logging */
20895ebda85SFloris Bos if (s->wwn) {
20995ebda85SFloris Bos put_le16(p + 87, (1 << 14) | (1 << 8) | 0);
21095ebda85SFloris Bos } else {
21159f2a787SGerd Hoffmann put_le16(p + 87, (1 << 14) | 0);
21295ebda85SFloris Bos }
21359f2a787SGerd Hoffmann put_le16(p + 88, 0x3f | (1 << 13)); /* udma5 set and supported */
21459f2a787SGerd Hoffmann put_le16(p + 93, 1 | (1 << 14) | 0x2000);
21501ce352eSJohn Snow /* *(p + 100) := nb_sectors -- see ide_identify_size */
21601ce352eSJohn Snow /* *(p + 101) := nb_sectors >> 16 -- see ide_identify_size */
21701ce352eSJohn Snow /* *(p + 102) := nb_sectors >> 32 -- see ide_identify_size */
21801ce352eSJohn Snow /* *(p + 103) := nb_sectors >> 48 -- see ide_identify_size */
219d353fb72SChristoph Hellwig
22057dac7efSMarkus Armbruster if (dev && dev->conf.physical_block_size)
22157dac7efSMarkus Armbruster put_le16(p + 106, 0x6000 | get_physical_block_exp(&dev->conf));
22295ebda85SFloris Bos if (s->wwn) {
22395ebda85SFloris Bos /* LE 16-bit words 111-108 contain 64-bit World Wide Name */
22495ebda85SFloris Bos put_le16(p + 108, s->wwn >> 48);
22595ebda85SFloris Bos put_le16(p + 109, s->wwn >> 32);
22695ebda85SFloris Bos put_le16(p + 110, s->wwn >> 16);
22795ebda85SFloris Bos put_le16(p + 111, s->wwn);
22895ebda85SFloris Bos }
229d353fb72SChristoph Hellwig if (dev && dev->conf.discard_granularity) {
230d353fb72SChristoph Hellwig put_le16(p + 169, 1); /* TRIM support */
231d353fb72SChristoph Hellwig }
23296f43c2bSDaniel P. Berrange if (dev) {
2333b19f450SDaniel P. Berrange put_le16(p + 217, dev->rotation_rate); /* Nominal media rotation rate */
23496f43c2bSDaniel P. Berrange }
23559f2a787SGerd Hoffmann
23601ce352eSJohn Snow ide_identify_size(s);
23759f2a787SGerd Hoffmann s->identify_set = 1;
2384bf6637dSJohn Snow
2394bf6637dSJohn Snow fill_buffer:
2404bf6637dSJohn Snow memcpy(s->io_buffer, p, sizeof(s->identify_data));
24159f2a787SGerd Hoffmann }
24259f2a787SGerd Hoffmann
ide_atapi_identify(IDEState * s)24359f2a787SGerd Hoffmann static void ide_atapi_identify(IDEState *s)
24459f2a787SGerd Hoffmann {
24559f2a787SGerd Hoffmann uint16_t *p;
24659f2a787SGerd Hoffmann
2474bf6637dSJohn Snow p = (uint16_t *)s->identify_data;
24859f2a787SGerd Hoffmann if (s->identify_set) {
2494bf6637dSJohn Snow goto fill_buffer;
25059f2a787SGerd Hoffmann }
2514bf6637dSJohn Snow memset(p, 0, sizeof(s->identify_data));
25259f2a787SGerd Hoffmann
25359f2a787SGerd Hoffmann /* Removable CDROM, 50us response, 12 byte packets */
25459f2a787SGerd Hoffmann put_le16(p + 0, (2 << 14) | (5 << 8) | (1 << 7) | (2 << 5) | (0 << 0));
25559f2a787SGerd Hoffmann padstr((char *)(p + 10), s->drive_serial_str, 20); /* serial number */
25659f2a787SGerd Hoffmann put_le16(p + 20, 3); /* buffer type */
25759f2a787SGerd Hoffmann put_le16(p + 21, 512); /* cache size in sectors */
25859f2a787SGerd Hoffmann put_le16(p + 22, 4); /* ecc bytes */
25947c06340SGerd Hoffmann padstr((char *)(p + 23), s->version, 8); /* firmware version */
26027e0c9a1SFloris Bos padstr((char *)(p + 27), s->drive_model_str, 40); /* model */
26159f2a787SGerd Hoffmann put_le16(p + 48, 1); /* dword I/O (XXX: should not be set on CDROM) */
26259f2a787SGerd Hoffmann #ifdef USE_DMA_CDROM
26359f2a787SGerd Hoffmann put_le16(p + 49, 1 << 9 | 1 << 8); /* DMA and LBA supported */
26459f2a787SGerd Hoffmann put_le16(p + 53, 7); /* words 64-70, 54-58, 88 valid */
26559f2a787SGerd Hoffmann put_le16(p + 62, 7); /* single word dma0-2 supported */
26659f2a787SGerd Hoffmann put_le16(p + 63, 7); /* mdma0-2 supported */
26759f2a787SGerd Hoffmann #else
26859f2a787SGerd Hoffmann put_le16(p + 49, 1 << 9); /* LBA supported, no DMA */
26959f2a787SGerd Hoffmann put_le16(p + 53, 3); /* words 64-70, 54-58 valid */
27059f2a787SGerd Hoffmann put_le16(p + 63, 0x103); /* DMA modes XXX: may be incorrect */
27159f2a787SGerd Hoffmann #endif
27279d1d331SJonathan A. Kollasch put_le16(p + 64, 3); /* pio3-4 supported */
27359f2a787SGerd Hoffmann put_le16(p + 65, 0xb4); /* minimum DMA multiword tx cycle time */
27459f2a787SGerd Hoffmann put_le16(p + 66, 0xb4); /* recommended DMA multiword tx cycle time */
27559f2a787SGerd Hoffmann put_le16(p + 67, 0x12c); /* minimum PIO cycle time without flow control */
27659f2a787SGerd Hoffmann put_le16(p + 68, 0xb4); /* minimum PIO cycle time with IORDY flow control */
27759f2a787SGerd Hoffmann
27859f2a787SGerd Hoffmann put_le16(p + 71, 30); /* in ns */
27959f2a787SGerd Hoffmann put_le16(p + 72, 30); /* in ns */
28059f2a787SGerd Hoffmann
2811bdaa28dSAlexander Graf if (s->ncq_queues) {
2821bdaa28dSAlexander Graf put_le16(p + 75, s->ncq_queues - 1);
2831bdaa28dSAlexander Graf /* NCQ supported */
2841bdaa28dSAlexander Graf put_le16(p + 76, (1 << 8));
2851bdaa28dSAlexander Graf }
2861bdaa28dSAlexander Graf
28759f2a787SGerd Hoffmann put_le16(p + 80, 0x1e); /* support up to ATA/ATAPI-4 */
288c5fe97e3SJohn Snow if (s->wwn) {
289c5fe97e3SJohn Snow put_le16(p + 84, (1 << 8)); /* supports WWN for words 108-111 */
290c5fe97e3SJohn Snow put_le16(p + 87, (1 << 8)); /* WWN enabled */
291c5fe97e3SJohn Snow }
292c5fe97e3SJohn Snow
29359f2a787SGerd Hoffmann #ifdef USE_DMA_CDROM
29459f2a787SGerd Hoffmann put_le16(p + 88, 0x3f | (1 << 13)); /* udma5 set and supported */
29559f2a787SGerd Hoffmann #endif
296c5fe97e3SJohn Snow
297c5fe97e3SJohn Snow if (s->wwn) {
298c5fe97e3SJohn Snow /* LE 16-bit words 111-108 contain 64-bit World Wide Name */
299c5fe97e3SJohn Snow put_le16(p + 108, s->wwn >> 48);
300c5fe97e3SJohn Snow put_le16(p + 109, s->wwn >> 32);
301c5fe97e3SJohn Snow put_le16(p + 110, s->wwn >> 16);
302c5fe97e3SJohn Snow put_le16(p + 111, s->wwn);
303c5fe97e3SJohn Snow }
304c5fe97e3SJohn Snow
30559f2a787SGerd Hoffmann s->identify_set = 1;
3064bf6637dSJohn Snow
3074bf6637dSJohn Snow fill_buffer:
3084bf6637dSJohn Snow memcpy(s->io_buffer, p, sizeof(s->identify_data));
30959f2a787SGerd Hoffmann }
31059f2a787SGerd Hoffmann
ide_cfata_identify_size(IDEState * s)31101ce352eSJohn Snow static void ide_cfata_identify_size(IDEState *s)
31201ce352eSJohn Snow {
31301ce352eSJohn Snow uint16_t *p = (uint16_t *)s->identify_data;
31401ce352eSJohn Snow put_le16(p + 7, s->nb_sectors >> 16); /* Sectors per card */
31501ce352eSJohn Snow put_le16(p + 8, s->nb_sectors); /* Sectors per card */
31601ce352eSJohn Snow put_le16(p + 60, s->nb_sectors); /* Total LBA sectors */
31701ce352eSJohn Snow put_le16(p + 61, s->nb_sectors >> 16); /* Total LBA sectors */
31801ce352eSJohn Snow }
31901ce352eSJohn Snow
ide_cfata_identify(IDEState * s)32059f2a787SGerd Hoffmann static void ide_cfata_identify(IDEState *s)
32159f2a787SGerd Hoffmann {
32259f2a787SGerd Hoffmann uint16_t *p;
32359f2a787SGerd Hoffmann uint32_t cur_sec;
32459f2a787SGerd Hoffmann
32559f2a787SGerd Hoffmann p = (uint16_t *)s->identify_data;
3264bf6637dSJohn Snow if (s->identify_set) {
32759f2a787SGerd Hoffmann goto fill_buffer;
3284bf6637dSJohn Snow }
32959f2a787SGerd Hoffmann memset(p, 0, sizeof(s->identify_data));
33059f2a787SGerd Hoffmann
33159f2a787SGerd Hoffmann cur_sec = s->cylinders * s->heads * s->sectors;
33259f2a787SGerd Hoffmann
33359f2a787SGerd Hoffmann put_le16(p + 0, 0x848a); /* CF Storage Card signature */
33459f2a787SGerd Hoffmann put_le16(p + 1, s->cylinders); /* Default cylinders */
33559f2a787SGerd Hoffmann put_le16(p + 3, s->heads); /* Default heads */
33659f2a787SGerd Hoffmann put_le16(p + 6, s->sectors); /* Default sectors per track */
33701ce352eSJohn Snow /* *(p + 7) := nb_sectors >> 16 -- see ide_cfata_identify_size */
33801ce352eSJohn Snow /* *(p + 8) := nb_sectors -- see ide_cfata_identify_size */
33959f2a787SGerd Hoffmann padstr((char *)(p + 10), s->drive_serial_str, 20); /* serial number */
34059f2a787SGerd Hoffmann put_le16(p + 22, 0x0004); /* ECC bytes */
34147c06340SGerd Hoffmann padstr((char *) (p + 23), s->version, 8); /* Firmware Revision */
34227e0c9a1SFloris Bos padstr((char *) (p + 27), s->drive_model_str, 40);/* Model number */
34359f2a787SGerd Hoffmann #if MAX_MULT_SECTORS > 1
34459f2a787SGerd Hoffmann put_le16(p + 47, 0x8000 | MAX_MULT_SECTORS);
34559f2a787SGerd Hoffmann #else
34659f2a787SGerd Hoffmann put_le16(p + 47, 0x0000);
34759f2a787SGerd Hoffmann #endif
34859f2a787SGerd Hoffmann put_le16(p + 49, 0x0f00); /* Capabilities */
34959f2a787SGerd Hoffmann put_le16(p + 51, 0x0002); /* PIO cycle timing mode */
35059f2a787SGerd Hoffmann put_le16(p + 52, 0x0001); /* DMA cycle timing mode */
35159f2a787SGerd Hoffmann put_le16(p + 53, 0x0003); /* Translation params valid */
35259f2a787SGerd Hoffmann put_le16(p + 54, s->cylinders); /* Current cylinders */
35359f2a787SGerd Hoffmann put_le16(p + 55, s->heads); /* Current heads */
35459f2a787SGerd Hoffmann put_le16(p + 56, s->sectors); /* Current sectors */
35559f2a787SGerd Hoffmann put_le16(p + 57, cur_sec); /* Current capacity */
35659f2a787SGerd Hoffmann put_le16(p + 58, cur_sec >> 16); /* Current capacity */
35759f2a787SGerd Hoffmann if (s->mult_sectors) /* Multiple sector setting */
35859f2a787SGerd Hoffmann put_le16(p + 59, 0x100 | s->mult_sectors);
35901ce352eSJohn Snow /* *(p + 60) := nb_sectors -- see ide_cfata_identify_size */
36001ce352eSJohn Snow /* *(p + 61) := nb_sectors >> 16 -- see ide_cfata_identify_size */
36159f2a787SGerd Hoffmann put_le16(p + 63, 0x0203); /* Multiword DMA capability */
36259f2a787SGerd Hoffmann put_le16(p + 64, 0x0001); /* Flow Control PIO support */
36359f2a787SGerd Hoffmann put_le16(p + 65, 0x0096); /* Min. Multiword DMA cycle */
36459f2a787SGerd Hoffmann put_le16(p + 66, 0x0096); /* Rec. Multiword DMA cycle */
36559f2a787SGerd Hoffmann put_le16(p + 68, 0x00b4); /* Min. PIO cycle time */
36659f2a787SGerd Hoffmann put_le16(p + 82, 0x400c); /* Command Set supported */
36759f2a787SGerd Hoffmann put_le16(p + 83, 0x7068); /* Command Set supported */
36859f2a787SGerd Hoffmann put_le16(p + 84, 0x4000); /* Features supported */
36959f2a787SGerd Hoffmann put_le16(p + 85, 0x000c); /* Command Set enabled */
37059f2a787SGerd Hoffmann put_le16(p + 86, 0x7044); /* Command Set enabled */
37159f2a787SGerd Hoffmann put_le16(p + 87, 0x4000); /* Features enabled */
37259f2a787SGerd Hoffmann put_le16(p + 91, 0x4060); /* Current APM level */
37359f2a787SGerd Hoffmann put_le16(p + 129, 0x0002); /* Current features option */
37459f2a787SGerd Hoffmann put_le16(p + 130, 0x0005); /* Reassigned sectors */
37559f2a787SGerd Hoffmann put_le16(p + 131, 0x0001); /* Initial power mode */
37659f2a787SGerd Hoffmann put_le16(p + 132, 0x0000); /* User signature */
37759f2a787SGerd Hoffmann put_le16(p + 160, 0x8100); /* Power requirement */
37859f2a787SGerd Hoffmann put_le16(p + 161, 0x8001); /* CF command set */
37959f2a787SGerd Hoffmann
38001ce352eSJohn Snow ide_cfata_identify_size(s);
38159f2a787SGerd Hoffmann s->identify_set = 1;
38259f2a787SGerd Hoffmann
38359f2a787SGerd Hoffmann fill_buffer:
38459f2a787SGerd Hoffmann memcpy(s->io_buffer, p, sizeof(s->identify_data));
38559f2a787SGerd Hoffmann }
38659f2a787SGerd Hoffmann
ide_set_signature(IDEState * s)38759f2a787SGerd Hoffmann static void ide_set_signature(IDEState *s)
38859f2a787SGerd Hoffmann {
3890c7515e1SJohn Snow s->select &= ~(ATA_DEV_HS); /* clear head */
39059f2a787SGerd Hoffmann /* put signature */
39159f2a787SGerd Hoffmann s->nsector = 1;
39259f2a787SGerd Hoffmann s->sector = 1;
393cd8722bbSMarkus Armbruster if (s->drive_kind == IDE_CD) {
39459f2a787SGerd Hoffmann s->lcyl = 0x14;
39559f2a787SGerd Hoffmann s->hcyl = 0xeb;
3964be74634SMarkus Armbruster } else if (s->blk) {
39759f2a787SGerd Hoffmann s->lcyl = 0;
39859f2a787SGerd Hoffmann s->hcyl = 0;
39959f2a787SGerd Hoffmann } else {
40059f2a787SGerd Hoffmann s->lcyl = 0xff;
40159f2a787SGerd Hoffmann s->hcyl = 0xff;
40259f2a787SGerd Hoffmann }
40359f2a787SGerd Hoffmann }
40459f2a787SGerd Hoffmann
ide_sect_range_ok(IDEState * s,uint64_t sector,uint64_t nb_sectors)405d8b070feSAnton Nefedov static bool ide_sect_range_ok(IDEState *s,
406d8b070feSAnton Nefedov uint64_t sector, uint64_t nb_sectors)
407d8b070feSAnton Nefedov {
408d8b070feSAnton Nefedov uint64_t total_sectors;
409d8b070feSAnton Nefedov
410d8b070feSAnton Nefedov blk_get_geometry(s->blk, &total_sectors);
411d8b070feSAnton Nefedov if (sector > total_sectors || nb_sectors > total_sectors - sector) {
412d8b070feSAnton Nefedov return false;
413d8b070feSAnton Nefedov }
414d8b070feSAnton Nefedov return true;
415d8b070feSAnton Nefedov }
416d8b070feSAnton Nefedov
417d353fb72SChristoph Hellwig typedef struct TrimAIOCB {
4187c84b1b8SMarkus Armbruster BlockAIOCB common;
419ef0e64a9SAnton Nefedov IDEState *s;
420d353fb72SChristoph Hellwig QEMUBH *bh;
421d353fb72SChristoph Hellwig int ret;
422501378c3SPaolo Bonzini QEMUIOVector *qiov;
4237c84b1b8SMarkus Armbruster BlockAIOCB *aiocb;
424501378c3SPaolo Bonzini int i, j;
425d353fb72SChristoph Hellwig } TrimAIOCB;
426d353fb72SChristoph Hellwig
trim_aio_cancel(BlockAIOCB * acb)4277c84b1b8SMarkus Armbruster static void trim_aio_cancel(BlockAIOCB *acb)
428d353fb72SChristoph Hellwig {
429d353fb72SChristoph Hellwig TrimAIOCB *iocb = container_of(acb, TrimAIOCB, common);
430d353fb72SChristoph Hellwig
431e551c999SFam Zheng /* Exit the loop so ide_issue_trim_cb will not continue */
432501378c3SPaolo Bonzini iocb->j = iocb->qiov->niov - 1;
433501378c3SPaolo Bonzini iocb->i = (iocb->qiov->iov[iocb->j].iov_len / 8) - 1;
434501378c3SPaolo Bonzini
435e551c999SFam Zheng iocb->ret = -ECANCELED;
436501378c3SPaolo Bonzini
437501378c3SPaolo Bonzini if (iocb->aiocb) {
4384be74634SMarkus Armbruster blk_aio_cancel_async(iocb->aiocb);
439e551c999SFam Zheng iocb->aiocb = NULL;
440501378c3SPaolo Bonzini }
441d353fb72SChristoph Hellwig }
442d353fb72SChristoph Hellwig
443d7331bedSStefan Hajnoczi static const AIOCBInfo trim_aiocb_info = {
444d353fb72SChristoph Hellwig .aiocb_size = sizeof(TrimAIOCB),
445e551c999SFam Zheng .cancel_async = trim_aio_cancel,
446d353fb72SChristoph Hellwig };
447d353fb72SChristoph Hellwig
ide_trim_bh_cb(void * opaque)448d353fb72SChristoph Hellwig static void ide_trim_bh_cb(void *opaque)
449d353fb72SChristoph Hellwig {
450d353fb72SChristoph Hellwig TrimAIOCB *iocb = opaque;
4517e5cdb34SHanna Reitz BlockBackend *blk = iocb->s->blk;
452d353fb72SChristoph Hellwig
453d353fb72SChristoph Hellwig iocb->common.cb(iocb->common.opaque, iocb->ret);
454caeadbc8SAnton Nefedov
455d353fb72SChristoph Hellwig qemu_bh_delete(iocb->bh);
456d353fb72SChristoph Hellwig iocb->bh = NULL;
4578007429aSFam Zheng qemu_aio_unref(iocb);
4587e5cdb34SHanna Reitz
4597e5cdb34SHanna Reitz /* Paired with an increment in ide_issue_trim() */
4607e5cdb34SHanna Reitz blk_dec_in_flight(blk);
461d353fb72SChristoph Hellwig }
462d353fb72SChristoph Hellwig
ide_issue_trim_cb(void * opaque,int ret)463501378c3SPaolo Bonzini static void ide_issue_trim_cb(void *opaque, int ret)
464d353fb72SChristoph Hellwig {
465501378c3SPaolo Bonzini TrimAIOCB *iocb = opaque;
466ef0e64a9SAnton Nefedov IDEState *s = iocb->s;
467ef0e64a9SAnton Nefedov
46899f18035SAnton Nefedov if (iocb->i >= 0) {
46999f18035SAnton Nefedov if (ret >= 0) {
47099f18035SAnton Nefedov block_acct_done(blk_get_stats(s->blk), &s->acct);
47199f18035SAnton Nefedov } else {
47299f18035SAnton Nefedov block_acct_failed(blk_get_stats(s->blk), &s->acct);
47399f18035SAnton Nefedov }
47499f18035SAnton Nefedov }
47599f18035SAnton Nefedov
476501378c3SPaolo Bonzini if (ret >= 0) {
477501378c3SPaolo Bonzini while (iocb->j < iocb->qiov->niov) {
478501378c3SPaolo Bonzini int j = iocb->j;
479501378c3SPaolo Bonzini while (++iocb->i < iocb->qiov->iov[j].iov_len / 8) {
480501378c3SPaolo Bonzini int i = iocb->i;
481501378c3SPaolo Bonzini uint64_t *buffer = iocb->qiov->iov[j].iov_base;
482d353fb72SChristoph Hellwig
483d353fb72SChristoph Hellwig /* 6-byte LBA + 2-byte range per entry */
484d353fb72SChristoph Hellwig uint64_t entry = le64_to_cpu(buffer[i]);
485d353fb72SChristoph Hellwig uint64_t sector = entry & 0x0000ffffffffffffULL;
486d353fb72SChristoph Hellwig uint16_t count = entry >> 48;
487d353fb72SChristoph Hellwig
488d353fb72SChristoph Hellwig if (count == 0) {
48980bc2e8dSPaolo Bonzini continue;
490d353fb72SChristoph Hellwig }
491d353fb72SChristoph Hellwig
492947858b0SAnton Nefedov if (!ide_sect_range_ok(s, sector, count)) {
49399f18035SAnton Nefedov block_acct_invalid(blk_get_stats(s->blk), BLOCK_ACCT_UNMAP);
494caeadbc8SAnton Nefedov iocb->ret = -EINVAL;
495947858b0SAnton Nefedov goto done;
496947858b0SAnton Nefedov }
497947858b0SAnton Nefedov
49899f18035SAnton Nefedov block_acct_start(blk_get_stats(s->blk), &s->acct,
49999f18035SAnton Nefedov count << BDRV_SECTOR_BITS, BLOCK_ACCT_UNMAP);
50099f18035SAnton Nefedov
501501378c3SPaolo Bonzini /* Got an entry! Submit and exit. */
502ef0e64a9SAnton Nefedov iocb->aiocb = blk_aio_pdiscard(s->blk,
5031c6c4bb7SEric Blake sector << BDRV_SECTOR_BITS,
5041c6c4bb7SEric Blake count << BDRV_SECTOR_BITS,
505501378c3SPaolo Bonzini ide_issue_trim_cb, opaque);
506501378c3SPaolo Bonzini return;
507501378c3SPaolo Bonzini }
508501378c3SPaolo Bonzini
509501378c3SPaolo Bonzini iocb->j++;
510501378c3SPaolo Bonzini iocb->i = -1;
511501378c3SPaolo Bonzini }
512501378c3SPaolo Bonzini } else {
513d353fb72SChristoph Hellwig iocb->ret = ret;
514d353fb72SChristoph Hellwig }
515d353fb72SChristoph Hellwig
516947858b0SAnton Nefedov done:
517501378c3SPaolo Bonzini iocb->aiocb = NULL;
518501378c3SPaolo Bonzini if (iocb->bh) {
519b255df7eSPavel Dovgalyuk replay_bh_schedule_event(iocb->bh);
520501378c3SPaolo Bonzini }
521501378c3SPaolo Bonzini }
522d353fb72SChristoph Hellwig
ide_issue_trim(int64_t offset,QEMUIOVector * qiov,BlockCompletionFunc * cb,void * cb_opaque,void * opaque)5238a8e63ebSPaolo Bonzini BlockAIOCB *ide_issue_trim(
5248a8e63ebSPaolo Bonzini int64_t offset, QEMUIOVector *qiov,
5258a8e63ebSPaolo Bonzini BlockCompletionFunc *cb, void *cb_opaque, void *opaque)
526501378c3SPaolo Bonzini {
527ef0e64a9SAnton Nefedov IDEState *s = opaque;
528f63192b0SAlexander Bulekov IDEDevice *dev = s->unit ? s->bus->slave : s->bus->master;
529501378c3SPaolo Bonzini TrimAIOCB *iocb;
530501378c3SPaolo Bonzini
5317e5cdb34SHanna Reitz /* Paired with a decrement in ide_trim_bh_cb() */
5327e5cdb34SHanna Reitz blk_inc_in_flight(s->blk);
5337e5cdb34SHanna Reitz
534ef0e64a9SAnton Nefedov iocb = blk_aio_get(&trim_aiocb_info, s->blk, cb, cb_opaque);
535ef0e64a9SAnton Nefedov iocb->s = s;
536f63192b0SAlexander Bulekov iocb->bh = qemu_bh_new_guarded(ide_trim_bh_cb, iocb,
537f63192b0SAlexander Bulekov &DEVICE(dev)->mem_reentrancy_guard);
538501378c3SPaolo Bonzini iocb->ret = 0;
539501378c3SPaolo Bonzini iocb->qiov = qiov;
540501378c3SPaolo Bonzini iocb->i = -1;
541501378c3SPaolo Bonzini iocb->j = 0;
542501378c3SPaolo Bonzini ide_issue_trim_cb(iocb, 0);
543d353fb72SChristoph Hellwig return &iocb->common;
544d353fb72SChristoph Hellwig }
545d353fb72SChristoph Hellwig
ide_abort_command(IDEState * s)5469ef2e93fSJohn Snow void ide_abort_command(IDEState *s)
54759f2a787SGerd Hoffmann {
54859f2a787SGerd Hoffmann s->status = READY_STAT | ERR_STAT;
54959f2a787SGerd Hoffmann s->error = ABRT_ERR;
550c3461c62SNiklas Cassel ide_transfer_stop(s);
55159f2a787SGerd Hoffmann }
55259f2a787SGerd Hoffmann
ide_set_retry(IDEState * s)5530eeee07eSEvgeny Yakovlev static void ide_set_retry(IDEState *s)
5540eeee07eSEvgeny Yakovlev {
5550eeee07eSEvgeny Yakovlev s->bus->retry_unit = s->unit;
5560eeee07eSEvgeny Yakovlev s->bus->retry_sector_num = ide_get_sector(s);
5570eeee07eSEvgeny Yakovlev s->bus->retry_nsector = s->nsector;
5580eeee07eSEvgeny Yakovlev }
5590eeee07eSEvgeny Yakovlev
ide_clear_retry(IDEState * s)5600eeee07eSEvgeny Yakovlev static void ide_clear_retry(IDEState *s)
5610eeee07eSEvgeny Yakovlev {
5620eeee07eSEvgeny Yakovlev s->bus->retry_unit = -1;
5630eeee07eSEvgeny Yakovlev s->bus->retry_sector_num = 0;
5640eeee07eSEvgeny Yakovlev s->bus->retry_nsector = 0;
5650eeee07eSEvgeny Yakovlev }
5660eeee07eSEvgeny Yakovlev
56759f2a787SGerd Hoffmann /* prepare data transfer and tell what to do after */
ide_transfer_start_norecurse(IDEState * s,uint8_t * buf,int size,EndTransferFunc * end_transfer_func)568c173723fSPaolo Bonzini bool ide_transfer_start_norecurse(IDEState *s, uint8_t *buf, int size,
56959f2a787SGerd Hoffmann EndTransferFunc *end_transfer_func)
57059f2a787SGerd Hoffmann {
57159f2a787SGerd Hoffmann s->data_ptr = buf;
57259f2a787SGerd Hoffmann s->data_end = buf + size;
57335f78ab4SEvgeny Yakovlev ide_set_retry(s);
57440a6238aSAlexander Graf if (!(s->status & ERR_STAT)) {
57559f2a787SGerd Hoffmann s->status |= DRQ_STAT;
57659f2a787SGerd Hoffmann }
577bed9bcfaSPaolo Bonzini if (!s->bus->dma->ops->pio_transfer) {
578bed9bcfaSPaolo Bonzini s->end_transfer_func = end_transfer_func;
579c173723fSPaolo Bonzini return false;
58040a6238aSAlexander Graf }
581bed9bcfaSPaolo Bonzini s->bus->dma->ops->pio_transfer(s->bus->dma);
582c173723fSPaolo Bonzini return true;
583c173723fSPaolo Bonzini }
584c173723fSPaolo Bonzini
ide_transfer_start(IDEState * s,uint8_t * buf,int size,EndTransferFunc * end_transfer_func)585c173723fSPaolo Bonzini void ide_transfer_start(IDEState *s, uint8_t *buf, int size,
586c173723fSPaolo Bonzini EndTransferFunc *end_transfer_func)
587c173723fSPaolo Bonzini {
588c173723fSPaolo Bonzini if (ide_transfer_start_norecurse(s, buf, size, end_transfer_func)) {
589bed9bcfaSPaolo Bonzini end_transfer_func(s);
59044635123SPaolo Bonzini }
591c173723fSPaolo Bonzini }
59259f2a787SGerd Hoffmann
ide_cmd_done(IDEState * s)593c7e73adbSPaolo Bonzini static void ide_cmd_done(IDEState *s)
594c7e73adbSPaolo Bonzini {
595c7e73adbSPaolo Bonzini if (s->bus->dma->ops->cmd_done) {
596c7e73adbSPaolo Bonzini s->bus->dma->ops->cmd_done(s->bus->dma);
597c7e73adbSPaolo Bonzini }
598c7e73adbSPaolo Bonzini }
599c7e73adbSPaolo Bonzini
ide_transfer_halt(IDEState * s)600882941a5SPaolo Bonzini static void ide_transfer_halt(IDEState *s)
60159f2a787SGerd Hoffmann {
602882941a5SPaolo Bonzini s->end_transfer_func = ide_transfer_stop;
60359f2a787SGerd Hoffmann s->data_ptr = s->io_buffer;
60459f2a787SGerd Hoffmann s->data_end = s->io_buffer;
60559f2a787SGerd Hoffmann s->status &= ~DRQ_STAT;
606e3044e23SJohn Snow }
607e3044e23SJohn Snow
ide_transfer_stop(IDEState * s)608e3044e23SJohn Snow void ide_transfer_stop(IDEState *s)
609e3044e23SJohn Snow {
610882941a5SPaolo Bonzini ide_transfer_halt(s);
611ee4cd662SPaolo Bonzini ide_cmd_done(s);
612e3044e23SJohn Snow }
613e3044e23SJohn Snow
ide_get_sector(IDEState * s)61459f2a787SGerd Hoffmann int64_t ide_get_sector(IDEState *s)
61559f2a787SGerd Hoffmann {
61659f2a787SGerd Hoffmann int64_t sector_num;
6170c7515e1SJohn Snow if (s->select & (ATA_DEV_LBA)) {
61814ee9b53SJohn Snow if (s->lba48) {
61959f2a787SGerd Hoffmann sector_num = ((int64_t)s->hob_hcyl << 40) |
62059f2a787SGerd Hoffmann ((int64_t) s->hob_lcyl << 32) |
62159f2a787SGerd Hoffmann ((int64_t) s->hob_sector << 24) |
62259f2a787SGerd Hoffmann ((int64_t) s->hcyl << 16) |
62359f2a787SGerd Hoffmann ((int64_t) s->lcyl << 8) | s->sector;
62414ee9b53SJohn Snow } else {
62514ee9b53SJohn Snow /* LBA28 */
6260c7515e1SJohn Snow sector_num = ((s->select & (ATA_DEV_LBA_MSB)) << 24) |
6270c7515e1SJohn Snow (s->hcyl << 16) | (s->lcyl << 8) | s->sector;
62859f2a787SGerd Hoffmann }
62959f2a787SGerd Hoffmann } else {
63014ee9b53SJohn Snow /* CHS */
63159f2a787SGerd Hoffmann sector_num = ((s->hcyl << 8) | s->lcyl) * s->heads * s->sectors +
6320c7515e1SJohn Snow (s->select & (ATA_DEV_HS)) * s->sectors + (s->sector - 1);
63359f2a787SGerd Hoffmann }
63414ee9b53SJohn Snow
63559f2a787SGerd Hoffmann return sector_num;
63659f2a787SGerd Hoffmann }
63759f2a787SGerd Hoffmann
ide_set_sector(IDEState * s,int64_t sector_num)63859f2a787SGerd Hoffmann void ide_set_sector(IDEState *s, int64_t sector_num)
63959f2a787SGerd Hoffmann {
64059f2a787SGerd Hoffmann unsigned int cyl, r;
6410c7515e1SJohn Snow if (s->select & (ATA_DEV_LBA)) {
64214ee9b53SJohn Snow if (s->lba48) {
64359f2a787SGerd Hoffmann s->sector = sector_num;
64459f2a787SGerd Hoffmann s->lcyl = sector_num >> 8;
64559f2a787SGerd Hoffmann s->hcyl = sector_num >> 16;
64659f2a787SGerd Hoffmann s->hob_sector = sector_num >> 24;
64759f2a787SGerd Hoffmann s->hob_lcyl = sector_num >> 32;
64859f2a787SGerd Hoffmann s->hob_hcyl = sector_num >> 40;
64914ee9b53SJohn Snow } else {
65014ee9b53SJohn Snow /* LBA28 */
6510c7515e1SJohn Snow s->select = (s->select & ~(ATA_DEV_LBA_MSB)) |
6520c7515e1SJohn Snow ((sector_num >> 24) & (ATA_DEV_LBA_MSB));
65314ee9b53SJohn Snow s->hcyl = (sector_num >> 16);
65414ee9b53SJohn Snow s->lcyl = (sector_num >> 8);
65514ee9b53SJohn Snow s->sector = (sector_num);
65659f2a787SGerd Hoffmann }
65759f2a787SGerd Hoffmann } else {
65814ee9b53SJohn Snow /* CHS */
65959f2a787SGerd Hoffmann cyl = sector_num / (s->heads * s->sectors);
66059f2a787SGerd Hoffmann r = sector_num % (s->heads * s->sectors);
66159f2a787SGerd Hoffmann s->hcyl = cyl >> 8;
66259f2a787SGerd Hoffmann s->lcyl = cyl;
6630c7515e1SJohn Snow s->select = (s->select & ~(ATA_DEV_HS)) |
6640c7515e1SJohn Snow ((r / s->sectors) & (ATA_DEV_HS));
66559f2a787SGerd Hoffmann s->sector = (r % s->sectors) + 1;
66659f2a787SGerd Hoffmann }
66759f2a787SGerd Hoffmann }
66859f2a787SGerd Hoffmann
ide_rw_error(IDEState * s)66959f2a787SGerd Hoffmann static void ide_rw_error(IDEState *s) {
67059f2a787SGerd Hoffmann ide_abort_command(s);
6710cfe719dSPhilippe Mathieu-Daudé ide_bus_set_irq(s->bus);
67259f2a787SGerd Hoffmann }
67359f2a787SGerd Hoffmann
ide_buffered_readv_cb(void * opaque,int ret)6741d8c11d6SPeter Lieven static void ide_buffered_readv_cb(void *opaque, int ret)
6751d8c11d6SPeter Lieven {
6761d8c11d6SPeter Lieven IDEBufferedRequest *req = opaque;
6771d8c11d6SPeter Lieven if (!req->orphaned) {
6781d8c11d6SPeter Lieven if (!ret) {
6795bbe9325SVladimir Sementsov-Ogievskiy assert(req->qiov.size == req->original_qiov->size);
6805bbe9325SVladimir Sementsov-Ogievskiy qemu_iovec_from_buf(req->original_qiov, 0,
6815bbe9325SVladimir Sementsov-Ogievskiy req->qiov.local_iov.iov_base,
6821d8c11d6SPeter Lieven req->original_qiov->size);
6831d8c11d6SPeter Lieven }
6841d8c11d6SPeter Lieven req->original_cb(req->original_opaque, ret);
6851d8c11d6SPeter Lieven }
6861d8c11d6SPeter Lieven QLIST_REMOVE(req, list);
6875bbe9325SVladimir Sementsov-Ogievskiy qemu_vfree(qemu_iovec_buf(&req->qiov));
6881d8c11d6SPeter Lieven g_free(req);
6891d8c11d6SPeter Lieven }
6901d8c11d6SPeter Lieven
6911d8c11d6SPeter Lieven #define MAX_BUFFERED_REQS 16
6921d8c11d6SPeter Lieven
ide_buffered_readv(IDEState * s,int64_t sector_num,QEMUIOVector * iov,int nb_sectors,BlockCompletionFunc * cb,void * opaque)6931d8c11d6SPeter Lieven BlockAIOCB *ide_buffered_readv(IDEState *s, int64_t sector_num,
6941d8c11d6SPeter Lieven QEMUIOVector *iov, int nb_sectors,
6951d8c11d6SPeter Lieven BlockCompletionFunc *cb, void *opaque)
6961d8c11d6SPeter Lieven {
6971d8c11d6SPeter Lieven BlockAIOCB *aioreq;
6981d8c11d6SPeter Lieven IDEBufferedRequest *req;
6991d8c11d6SPeter Lieven int c = 0;
7001d8c11d6SPeter Lieven
7011d8c11d6SPeter Lieven QLIST_FOREACH(req, &s->buffered_requests, list) {
7021d8c11d6SPeter Lieven c++;
7031d8c11d6SPeter Lieven }
7041d8c11d6SPeter Lieven if (c > MAX_BUFFERED_REQS) {
7051d8c11d6SPeter Lieven return blk_abort_aio_request(s->blk, cb, opaque, -EIO);
7061d8c11d6SPeter Lieven }
7071d8c11d6SPeter Lieven
7081d8c11d6SPeter Lieven req = g_new0(IDEBufferedRequest, 1);
7091d8c11d6SPeter Lieven req->original_qiov = iov;
7101d8c11d6SPeter Lieven req->original_cb = cb;
7111d8c11d6SPeter Lieven req->original_opaque = opaque;
7125bbe9325SVladimir Sementsov-Ogievskiy qemu_iovec_init_buf(&req->qiov, blk_blockalign(s->blk, iov->size),
7135bbe9325SVladimir Sementsov-Ogievskiy iov->size);
7141d8c11d6SPeter Lieven
715d4f510ebSEric Blake aioreq = blk_aio_preadv(s->blk, sector_num << BDRV_SECTOR_BITS,
716d4f510ebSEric Blake &req->qiov, 0, ide_buffered_readv_cb, req);
7171d8c11d6SPeter Lieven
7181d8c11d6SPeter Lieven QLIST_INSERT_HEAD(&s->buffered_requests, req, list);
7191d8c11d6SPeter Lieven return aioreq;
7201d8c11d6SPeter Lieven }
7211d8c11d6SPeter Lieven
72286698a12SJohn Snow /**
72386698a12SJohn Snow * Cancel all pending DMA requests.
72486698a12SJohn Snow * Any buffered DMA requests are instantly canceled,
72586698a12SJohn Snow * but any pending unbuffered DMA requests must be waited on.
72686698a12SJohn Snow */
ide_cancel_dma_sync(IDEState * s)72786698a12SJohn Snow void ide_cancel_dma_sync(IDEState *s)
72886698a12SJohn Snow {
72986698a12SJohn Snow IDEBufferedRequest *req;
73086698a12SJohn Snow
73186698a12SJohn Snow /* First invoke the callbacks of all buffered requests
73286698a12SJohn Snow * and flag those requests as orphaned. Ideally there
73386698a12SJohn Snow * are no unbuffered (Scatter Gather DMA Requests or
73486698a12SJohn Snow * write requests) pending and we can avoid to drain. */
73586698a12SJohn Snow QLIST_FOREACH(req, &s->buffered_requests, list) {
73686698a12SJohn Snow if (!req->orphaned) {
7373eee2611SJohn Snow trace_ide_cancel_dma_sync_buffered(req->original_cb, req);
73886698a12SJohn Snow req->original_cb(req->original_opaque, -ECANCELED);
73986698a12SJohn Snow }
74086698a12SJohn Snow req->orphaned = true;
74186698a12SJohn Snow }
74286698a12SJohn Snow
74386698a12SJohn Snow /*
74486698a12SJohn Snow * We can't cancel Scatter Gather DMA in the middle of the
74586698a12SJohn Snow * operation or a partial (not full) DMA transfer would reach
74668b57b0dSPhilippe Mathieu-Daudé * the storage so we wait for completion instead (we behave
74786698a12SJohn Snow * like if the DMA was completed by the time the guest trying
74886698a12SJohn Snow * to cancel dma with bmdma_cmd_writeb with BM_CMD_START not
74986698a12SJohn Snow * set).
75086698a12SJohn Snow *
75186698a12SJohn Snow * In the future we'll be able to safely cancel the I/O if the
75286698a12SJohn Snow * whole DMA operation will be submitted to disk with a single
75386698a12SJohn Snow * aio operation with preadv/pwritev.
75486698a12SJohn Snow */
75586698a12SJohn Snow if (s->bus->dma->aiocb) {
7563eee2611SJohn Snow trace_ide_cancel_dma_sync_remaining();
75751f7b5b8SJohn Snow blk_drain(s->blk);
75886698a12SJohn Snow assert(s->bus->dma->aiocb == NULL);
75986698a12SJohn Snow }
76086698a12SJohn Snow }
76186698a12SJohn Snow
7624e2b8b4aSPaolo Bonzini static void ide_sector_read(IDEState *s);
7634e2b8b4aSPaolo Bonzini
ide_sector_read_cb(void * opaque,int ret)764bef0fd59SStefan Hajnoczi static void ide_sector_read_cb(void *opaque, int ret)
765bef0fd59SStefan Hajnoczi {
766bef0fd59SStefan Hajnoczi IDEState *s = opaque;
767bef0fd59SStefan Hajnoczi int n;
768bef0fd59SStefan Hajnoczi
769bef0fd59SStefan Hajnoczi s->pio_aiocb = NULL;
770bef0fd59SStefan Hajnoczi s->status &= ~BUSY_STAT;
771bef0fd59SStefan Hajnoczi
772bef0fd59SStefan Hajnoczi if (ret != 0) {
773fd648f10SPaolo Bonzini if (ide_handle_rw_error(s, -ret, IDE_RETRY_PIO |
774fd648f10SPaolo Bonzini IDE_RETRY_READ)) {
775bef0fd59SStefan Hajnoczi return;
776bef0fd59SStefan Hajnoczi }
777bef0fd59SStefan Hajnoczi }
778bef0fd59SStefan Hajnoczi
779ecca3b39SAlberto Garcia block_acct_done(blk_get_stats(s->blk), &s->acct);
780ecca3b39SAlberto Garcia
781bef0fd59SStefan Hajnoczi n = s->nsector;
782bef0fd59SStefan Hajnoczi if (n > s->req_nb_sectors) {
783bef0fd59SStefan Hajnoczi n = s->req_nb_sectors;
784bef0fd59SStefan Hajnoczi }
785bef0fd59SStefan Hajnoczi
786bef0fd59SStefan Hajnoczi ide_set_sector(s, ide_get_sector(s) + n);
787bef0fd59SStefan Hajnoczi s->nsector -= n;
788dd0bf7baSJohn Snow /* Allow the guest to read the io_buffer */
789dd0bf7baSJohn Snow ide_transfer_start(s, s->io_buffer, n * BDRV_SECTOR_SIZE, ide_sector_read);
7900cfe719dSPhilippe Mathieu-Daudé ide_bus_set_irq(s->bus);
791bef0fd59SStefan Hajnoczi }
792bef0fd59SStefan Hajnoczi
ide_sector_read(IDEState * s)7934e2b8b4aSPaolo Bonzini static void ide_sector_read(IDEState *s)
79459f2a787SGerd Hoffmann {
79559f2a787SGerd Hoffmann int64_t sector_num;
796bef0fd59SStefan Hajnoczi int n;
79759f2a787SGerd Hoffmann
79859f2a787SGerd Hoffmann s->status = READY_STAT | SEEK_STAT;
79959f2a787SGerd Hoffmann s->error = 0; /* not needed by IDE spec, but needed by Windows */
80059f2a787SGerd Hoffmann sector_num = ide_get_sector(s);
80159f2a787SGerd Hoffmann n = s->nsector;
802a597e79cSChristoph Hellwig
803bef0fd59SStefan Hajnoczi if (n == 0) {
804bef0fd59SStefan Hajnoczi ide_transfer_stop(s);
80559f2a787SGerd Hoffmann return;
80659f2a787SGerd Hoffmann }
807bef0fd59SStefan Hajnoczi
808bef0fd59SStefan Hajnoczi s->status |= BUSY_STAT;
809bef0fd59SStefan Hajnoczi
810bef0fd59SStefan Hajnoczi if (n > s->req_nb_sectors) {
811bef0fd59SStefan Hajnoczi n = s->req_nb_sectors;
812ce4b6522SKevin Wolf }
813bef0fd59SStefan Hajnoczi
8143eee2611SJohn Snow trace_ide_sector_read(sector_num, n);
815bef0fd59SStefan Hajnoczi
81658ac3211SMarkus Armbruster if (!ide_sect_range_ok(s, sector_num, n)) {
81758ac3211SMarkus Armbruster ide_rw_error(s);
818ecca3b39SAlberto Garcia block_acct_invalid(blk_get_stats(s->blk), BLOCK_ACCT_READ);
81958ac3211SMarkus Armbruster return;
82058ac3211SMarkus Armbruster }
82158ac3211SMarkus Armbruster
822e5863d49SVladimir Sementsov-Ogievskiy qemu_iovec_init_buf(&s->qiov, s->io_buffer, n * BDRV_SECTOR_SIZE);
823bef0fd59SStefan Hajnoczi
8244be74634SMarkus Armbruster block_acct_start(blk_get_stats(s->blk), &s->acct,
8255366d0c8SBenoît Canet n * BDRV_SECTOR_SIZE, BLOCK_ACCT_READ);
826d66a8fa8SPeter Lieven s->pio_aiocb = ide_buffered_readv(s, sector_num, &s->qiov, n,
827bef0fd59SStefan Hajnoczi ide_sector_read_cb, s);
82859f2a787SGerd Hoffmann }
82959f2a787SGerd Hoffmann
dma_buf_commit(IDEState * s,uint32_t tx_bytes)830aaeda4a3SJohn Snow void dma_buf_commit(IDEState *s, uint32_t tx_bytes)
83159f2a787SGerd Hoffmann {
832659142ecSJohn Snow if (s->bus->dma->ops->commit_buf) {
833659142ecSJohn Snow s->bus->dma->ops->commit_buf(s->bus->dma, tx_bytes);
834659142ecSJohn Snow }
835aaeda4a3SJohn Snow s->io_buffer_offset += tx_bytes;
83659f2a787SGerd Hoffmann qemu_sglist_destroy(&s->sg);
83759f2a787SGerd Hoffmann }
83859f2a787SGerd Hoffmann
ide_set_inactive(IDEState * s,bool more)8390e7ce54cSPaolo Bonzini void ide_set_inactive(IDEState *s, bool more)
8408337606dSKevin Wolf {
84140a6238aSAlexander Graf s->bus->dma->aiocb = NULL;
8420eeee07eSEvgeny Yakovlev ide_clear_retry(s);
843829b933bSPaolo Bonzini if (s->bus->dma->ops->set_inactive) {
8440e7ce54cSPaolo Bonzini s->bus->dma->ops->set_inactive(s->bus->dma, more);
845829b933bSPaolo Bonzini }
846c7e73adbSPaolo Bonzini ide_cmd_done(s);
8478337606dSKevin Wolf }
8488337606dSKevin Wolf
ide_dma_error(IDEState * s)84959f2a787SGerd Hoffmann void ide_dma_error(IDEState *s)
85059f2a787SGerd Hoffmann {
851659142ecSJohn Snow dma_buf_commit(s, 0);
85208ee9e33SPaolo Bonzini ide_abort_command(s);
8530e7ce54cSPaolo Bonzini ide_set_inactive(s, false);
8540cfe719dSPhilippe Mathieu-Daudé ide_bus_set_irq(s->bus);
85559f2a787SGerd Hoffmann }
85659f2a787SGerd Hoffmann
ide_handle_rw_error(IDEState * s,int error,int op)857502356eeSPavel Butsykin int ide_handle_rw_error(IDEState *s, int error, int op)
85859f2a787SGerd Hoffmann {
859fd648f10SPaolo Bonzini bool is_read = (op & IDE_RETRY_READ) != 0;
8604be74634SMarkus Armbruster BlockErrorAction action = blk_get_error_action(s->blk, is_read, error);
86159f2a787SGerd Hoffmann
862a589569fSWenchao Xia if (action == BLOCK_ERROR_ACTION_STOP) {
863a96cb236SPaolo Bonzini assert(s->bus->retry_unit == s->unit);
864def93791SKevin Wolf s->bus->error_status = op;
865a589569fSWenchao Xia } else if (action == BLOCK_ERROR_ACTION_REPORT) {
866ecca3b39SAlberto Garcia block_acct_failed(blk_get_stats(s->blk), &s->acct);
867502356eeSPavel Butsykin if (IS_IDE_RETRY_DMA(op)) {
86859f2a787SGerd Hoffmann ide_dma_error(s);
869502356eeSPavel Butsykin } else if (IS_IDE_RETRY_ATAPI(op)) {
870502356eeSPavel Butsykin ide_atapi_io_error(s, -error);
87159f2a787SGerd Hoffmann } else {
87259f2a787SGerd Hoffmann ide_rw_error(s);
87359f2a787SGerd Hoffmann }
87459f2a787SGerd Hoffmann }
8754be74634SMarkus Armbruster blk_error_action(s->blk, action, is_read, error);
876a589569fSWenchao Xia return action != BLOCK_ERROR_ACTION_IGNORE;
87759f2a787SGerd Hoffmann }
87859f2a787SGerd Hoffmann
ide_dma_cb(void * opaque,int ret)8794e2b8b4aSPaolo Bonzini static void ide_dma_cb(void *opaque, int ret)
88059f2a787SGerd Hoffmann {
88140a6238aSAlexander Graf IDEState *s = opaque;
88259f2a787SGerd Hoffmann int n;
88359f2a787SGerd Hoffmann int64_t sector_num;
884cbe0ed62SPaolo Bonzini uint64_t offset;
885038268e2SKevin Wolf bool stay_active = false;
886ed78352aSAlexander Popov int32_t prep_size = 0;
88759f2a787SGerd Hoffmann
888caeadbc8SAnton Nefedov if (ret == -EINVAL) {
889caeadbc8SAnton Nefedov ide_dma_error(s);
890caeadbc8SAnton Nefedov return;
891caeadbc8SAnton Nefedov }
892caeadbc8SAnton Nefedov
89359f2a787SGerd Hoffmann if (ret < 0) {
894218fd37cSPavel Butsykin if (ide_handle_rw_error(s, -ret, ide_dma_cmd_to_retry(s->dma_cmd))) {
89587ac25fdSJohn Snow s->bus->dma->aiocb = NULL;
8965839df7bSMarc-André Lureau dma_buf_commit(s, 0);
89759f2a787SGerd Hoffmann return;
89859f2a787SGerd Hoffmann }
899ce4b6522SKevin Wolf }
90059f2a787SGerd Hoffmann
901ed78352aSAlexander Popov if (s->io_buffer_size > s->nsector * 512) {
902ed78352aSAlexander Popov /*
903ed78352aSAlexander Popov * The PRDs were longer than needed for this request.
904ed78352aSAlexander Popov * The Active bit must remain set after the request completes.
905ed78352aSAlexander Popov */
906038268e2SKevin Wolf n = s->nsector;
907038268e2SKevin Wolf stay_active = true;
908ed78352aSAlexander Popov } else {
909ed78352aSAlexander Popov n = s->io_buffer_size >> 9;
910038268e2SKevin Wolf }
911038268e2SKevin Wolf
91259f2a787SGerd Hoffmann sector_num = ide_get_sector(s);
91359f2a787SGerd Hoffmann if (n > 0) {
914a718978eSJohn Snow assert(n * 512 == s->sg.size);
915a718978eSJohn Snow dma_buf_commit(s, s->sg.size);
91659f2a787SGerd Hoffmann sector_num += n;
91759f2a787SGerd Hoffmann ide_set_sector(s, sector_num);
91859f2a787SGerd Hoffmann s->nsector -= n;
91959f2a787SGerd Hoffmann }
92059f2a787SGerd Hoffmann
92159f2a787SGerd Hoffmann /* end of transfer ? */
92259f2a787SGerd Hoffmann if (s->nsector == 0) {
92359f2a787SGerd Hoffmann s->status = READY_STAT | SEEK_STAT;
9240cfe719dSPhilippe Mathieu-Daudé ide_bus_set_irq(s->bus);
925cd369c46SChristoph Hellwig goto eot;
92659f2a787SGerd Hoffmann }
92759f2a787SGerd Hoffmann
92859f2a787SGerd Hoffmann /* launch next transfer */
92959f2a787SGerd Hoffmann n = s->nsector;
93059f2a787SGerd Hoffmann s->io_buffer_index = 0;
93159f2a787SGerd Hoffmann s->io_buffer_size = n * 512;
932ed78352aSAlexander Popov prep_size = s->bus->dma->ops->prepare_buf(s->bus->dma, s->io_buffer_size);
933ed78352aSAlexander Popov /* prepare_buf() must succeed and respect the limit */
934ed78352aSAlexander Popov assert(prep_size >= 0 && prep_size <= n * 512);
935ed78352aSAlexander Popov
936ed78352aSAlexander Popov /*
937ed78352aSAlexander Popov * Now prep_size stores the number of bytes in the sglist, and
938ed78352aSAlexander Popov * s->io_buffer_size stores the number of bytes described by the PRDs.
939ed78352aSAlexander Popov */
940ed78352aSAlexander Popov
941ed78352aSAlexander Popov if (prep_size < n * 512) {
942ed78352aSAlexander Popov /*
943ed78352aSAlexander Popov * The PRDs are too short for this request. Error condition!
944ed78352aSAlexander Popov * Reset the Active bit and don't raise the interrupt.
945ed78352aSAlexander Popov */
94672bcca73SKevin Wolf s->status = READY_STAT | SEEK_STAT;
9473251bdcfSJohn Snow dma_buf_commit(s, 0);
94859f2a787SGerd Hoffmann goto eot;
94969c38b8fSKevin Wolf }
950cd369c46SChristoph Hellwig
9510e168d35SJohn Snow trace_ide_dma_cb(s, sector_num, n, IDE_DMA_CMD_str(s->dma_cmd));
952cd369c46SChristoph Hellwig
953d66168edSMichael Tokarev if ((s->dma_cmd == IDE_DMA_READ || s->dma_cmd == IDE_DMA_WRITE) &&
954d66168edSMichael Tokarev !ide_sect_range_ok(s, sector_num, n)) {
95558ac3211SMarkus Armbruster ide_dma_error(s);
956ecca3b39SAlberto Garcia block_acct_invalid(blk_get_stats(s->blk), s->acct.type);
95758ac3211SMarkus Armbruster return;
95858ac3211SMarkus Armbruster }
95958ac3211SMarkus Armbruster
960cbe0ed62SPaolo Bonzini offset = sector_num << BDRV_SECTOR_BITS;
9614e1e0051SChristoph Hellwig switch (s->dma_cmd) {
9624e1e0051SChristoph Hellwig case IDE_DMA_READ:
963cbe0ed62SPaolo Bonzini s->bus->dma->aiocb = dma_blk_read(s->blk, &s->sg, offset,
96499868af3SMark Cave-Ayland BDRV_SECTOR_SIZE, ide_dma_cb, s);
9654e1e0051SChristoph Hellwig break;
9664e1e0051SChristoph Hellwig case IDE_DMA_WRITE:
967cbe0ed62SPaolo Bonzini s->bus->dma->aiocb = dma_blk_write(s->blk, &s->sg, offset,
96899868af3SMark Cave-Ayland BDRV_SECTOR_SIZE, ide_dma_cb, s);
9694e1e0051SChristoph Hellwig break;
970d353fb72SChristoph Hellwig case IDE_DMA_TRIM:
9718a8e63ebSPaolo Bonzini s->bus->dma->aiocb = dma_blk_io(blk_get_aio_context(s->blk),
97299868af3SMark Cave-Ayland &s->sg, offset, BDRV_SECTOR_SIZE,
973ef0e64a9SAnton Nefedov ide_issue_trim, s, ide_dma_cb, s,
97443cf8ae6SDavid Gibson DMA_DIRECTION_TO_DEVICE);
975d353fb72SChristoph Hellwig break;
976502356eeSPavel Butsykin default:
977502356eeSPavel Butsykin abort();
978cd369c46SChristoph Hellwig }
979cd369c46SChristoph Hellwig return;
980cd369c46SChristoph Hellwig
981cd369c46SChristoph Hellwig eot:
982a597e79cSChristoph Hellwig if (s->dma_cmd == IDE_DMA_READ || s->dma_cmd == IDE_DMA_WRITE) {
9834be74634SMarkus Armbruster block_acct_done(blk_get_stats(s->blk), &s->acct);
984a597e79cSChristoph Hellwig }
9850e7ce54cSPaolo Bonzini ide_set_inactive(s, stay_active);
98659f2a787SGerd Hoffmann }
98759f2a787SGerd Hoffmann
ide_sector_start_dma(IDEState * s,enum ide_dma_cmd dma_cmd)9884e1e0051SChristoph Hellwig static void ide_sector_start_dma(IDEState *s, enum ide_dma_cmd dma_cmd)
98959f2a787SGerd Hoffmann {
9909da82227SJohn Snow s->status = READY_STAT | SEEK_STAT | DRQ_STAT;
99159f2a787SGerd Hoffmann s->io_buffer_size = 0;
9924e1e0051SChristoph Hellwig s->dma_cmd = dma_cmd;
993a597e79cSChristoph Hellwig
994a597e79cSChristoph Hellwig switch (dma_cmd) {
995a597e79cSChristoph Hellwig case IDE_DMA_READ:
9964be74634SMarkus Armbruster block_acct_start(blk_get_stats(s->blk), &s->acct,
9975366d0c8SBenoît Canet s->nsector * BDRV_SECTOR_SIZE, BLOCK_ACCT_READ);
998a597e79cSChristoph Hellwig break;
999a597e79cSChristoph Hellwig case IDE_DMA_WRITE:
10004be74634SMarkus Armbruster block_acct_start(blk_get_stats(s->blk), &s->acct,
10015366d0c8SBenoît Canet s->nsector * BDRV_SECTOR_SIZE, BLOCK_ACCT_WRITE);
1002a597e79cSChristoph Hellwig break;
1003a597e79cSChristoph Hellwig default:
1004a597e79cSChristoph Hellwig break;
1005a597e79cSChristoph Hellwig }
1006a597e79cSChristoph Hellwig
10074855b576SPaolo Bonzini ide_start_dma(s, ide_dma_cb);
10084855b576SPaolo Bonzini }
10094855b576SPaolo Bonzini
ide_start_dma(IDEState * s,BlockCompletionFunc * cb)1010097310b5SMarkus Armbruster void ide_start_dma(IDEState *s, BlockCompletionFunc *cb)
10114855b576SPaolo Bonzini {
1012c71c06d4SPaolo Bonzini s->io_buffer_index = 0;
10130eeee07eSEvgeny Yakovlev ide_set_retry(s);
10144855b576SPaolo Bonzini if (s->bus->dma->ops->start_dma) {
10154855b576SPaolo Bonzini s->bus->dma->ops->start_dma(s->bus->dma, s, cb);
10164855b576SPaolo Bonzini }
101759f2a787SGerd Hoffmann }
101859f2a787SGerd Hoffmann
10194e2b8b4aSPaolo Bonzini static void ide_sector_write(IDEState *s);
10204e2b8b4aSPaolo Bonzini
ide_sector_write_timer_cb(void * opaque)102159f2a787SGerd Hoffmann static void ide_sector_write_timer_cb(void *opaque)
102259f2a787SGerd Hoffmann {
102359f2a787SGerd Hoffmann IDEState *s = opaque;
10240cfe719dSPhilippe Mathieu-Daudé ide_bus_set_irq(s->bus);
102559f2a787SGerd Hoffmann }
102659f2a787SGerd Hoffmann
ide_sector_write_cb(void * opaque,int ret)1027e82dabd8SStefan Hajnoczi static void ide_sector_write_cb(void *opaque, int ret)
102859f2a787SGerd Hoffmann {
1029e82dabd8SStefan Hajnoczi IDEState *s = opaque;
1030e82dabd8SStefan Hajnoczi int n;
103159f2a787SGerd Hoffmann
1032e82dabd8SStefan Hajnoczi s->pio_aiocb = NULL;
1033e82dabd8SStefan Hajnoczi s->status &= ~BUSY_STAT;
1034e82dabd8SStefan Hajnoczi
103559f2a787SGerd Hoffmann if (ret != 0) {
1036fd648f10SPaolo Bonzini if (ide_handle_rw_error(s, -ret, IDE_RETRY_PIO)) {
103759f2a787SGerd Hoffmann return;
103859f2a787SGerd Hoffmann }
1039e82dabd8SStefan Hajnoczi }
104059f2a787SGerd Hoffmann
1041ecca3b39SAlberto Garcia block_acct_done(blk_get_stats(s->blk), &s->acct);
1042ecca3b39SAlberto Garcia
1043e82dabd8SStefan Hajnoczi n = s->nsector;
1044e82dabd8SStefan Hajnoczi if (n > s->req_nb_sectors) {
1045e82dabd8SStefan Hajnoczi n = s->req_nb_sectors;
1046e82dabd8SStefan Hajnoczi }
104759f2a787SGerd Hoffmann s->nsector -= n;
104836334fafSJohn Snow
10496aff22c0SJohn Snow ide_set_sector(s, ide_get_sector(s) + n);
105059f2a787SGerd Hoffmann if (s->nsector == 0) {
105159f2a787SGerd Hoffmann /* no more sectors to write */
105259f2a787SGerd Hoffmann ide_transfer_stop(s);
105359f2a787SGerd Hoffmann } else {
1054e82dabd8SStefan Hajnoczi int n1 = s->nsector;
1055e82dabd8SStefan Hajnoczi if (n1 > s->req_nb_sectors) {
105659f2a787SGerd Hoffmann n1 = s->req_nb_sectors;
105759f2a787SGerd Hoffmann }
1058e82dabd8SStefan Hajnoczi ide_transfer_start(s, s->io_buffer, n1 * BDRV_SECTOR_SIZE,
1059e82dabd8SStefan Hajnoczi ide_sector_write);
1060e82dabd8SStefan Hajnoczi }
106159f2a787SGerd Hoffmann
106259f2a787SGerd Hoffmann if (win2k_install_hack && ((++s->irq_count % 16) == 0)) {
106359f2a787SGerd Hoffmann /* It seems there is a bug in the Windows 2000 installer HDD
106459f2a787SGerd Hoffmann IDE driver which fills the disk with empty logs when the
106559f2a787SGerd Hoffmann IDE write IRQ comes too early. This hack tries to correct
106659f2a787SGerd Hoffmann that at the expense of slower write performances. Use this
106759f2a787SGerd Hoffmann option _only_ to install Windows 2000. You must disable it
106859f2a787SGerd Hoffmann for normal use. */
106973bcb24dSRutuja Shah timer_mod(s->sector_write_timer, qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) +
107073bcb24dSRutuja Shah (NANOSECONDS_PER_SECOND / 1000));
1071f7736b91SBlue Swirl } else {
10720cfe719dSPhilippe Mathieu-Daudé ide_bus_set_irq(s->bus);
107359f2a787SGerd Hoffmann }
107459f2a787SGerd Hoffmann }
107559f2a787SGerd Hoffmann
ide_sector_write(IDEState * s)10764e2b8b4aSPaolo Bonzini static void ide_sector_write(IDEState *s)
1077e82dabd8SStefan Hajnoczi {
1078e82dabd8SStefan Hajnoczi int64_t sector_num;
1079e82dabd8SStefan Hajnoczi int n;
1080e82dabd8SStefan Hajnoczi
1081e82dabd8SStefan Hajnoczi s->status = READY_STAT | SEEK_STAT | BUSY_STAT;
1082e82dabd8SStefan Hajnoczi sector_num = ide_get_sector(s);
10833eee2611SJohn Snow
1084e82dabd8SStefan Hajnoczi n = s->nsector;
1085e82dabd8SStefan Hajnoczi if (n > s->req_nb_sectors) {
1086e82dabd8SStefan Hajnoczi n = s->req_nb_sectors;
1087e82dabd8SStefan Hajnoczi }
1088e82dabd8SStefan Hajnoczi
10893eee2611SJohn Snow trace_ide_sector_write(sector_num, n);
10903eee2611SJohn Snow
109158ac3211SMarkus Armbruster if (!ide_sect_range_ok(s, sector_num, n)) {
109258ac3211SMarkus Armbruster ide_rw_error(s);
1093ecca3b39SAlberto Garcia block_acct_invalid(blk_get_stats(s->blk), BLOCK_ACCT_WRITE);
109458ac3211SMarkus Armbruster return;
109558ac3211SMarkus Armbruster }
109658ac3211SMarkus Armbruster
1097e5863d49SVladimir Sementsov-Ogievskiy qemu_iovec_init_buf(&s->qiov, s->io_buffer, n * BDRV_SECTOR_SIZE);
1098e82dabd8SStefan Hajnoczi
10994be74634SMarkus Armbruster block_acct_start(blk_get_stats(s->blk), &s->acct,
1100c618f331SAlberto Garcia n * BDRV_SECTOR_SIZE, BLOCK_ACCT_WRITE);
1101d4f510ebSEric Blake s->pio_aiocb = blk_aio_pwritev(s->blk, sector_num << BDRV_SECTOR_BITS,
1102d4f510ebSEric Blake &s->qiov, 0, ide_sector_write_cb, s);
1103e82dabd8SStefan Hajnoczi }
1104e82dabd8SStefan Hajnoczi
ide_flush_cb(void * opaque,int ret)1105b0484ae4SChristoph Hellwig static void ide_flush_cb(void *opaque, int ret)
1106b0484ae4SChristoph Hellwig {
1107b0484ae4SChristoph Hellwig IDEState *s = opaque;
1108b0484ae4SChristoph Hellwig
110969f72a22SPaolo Bonzini s->pio_aiocb = NULL;
111069f72a22SPaolo Bonzini
1111e2bcadadSKevin Wolf if (ret < 0) {
1112e2bcadadSKevin Wolf /* XXX: What sector number to set here? */
1113fd648f10SPaolo Bonzini if (ide_handle_rw_error(s, -ret, IDE_RETRY_FLUSH)) {
1114e2bcadadSKevin Wolf return;
1115e2bcadadSKevin Wolf }
1116e2bcadadSKevin Wolf }
1117b0484ae4SChristoph Hellwig
11184be74634SMarkus Armbruster if (s->blk) {
11194be74634SMarkus Armbruster block_acct_done(blk_get_stats(s->blk), &s->acct);
1120f7f3ff1dSKevin Wolf }
1121b0484ae4SChristoph Hellwig s->status = READY_STAT | SEEK_STAT;
1122c7e73adbSPaolo Bonzini ide_cmd_done(s);
11230cfe719dSPhilippe Mathieu-Daudé ide_bus_set_irq(s->bus);
1124b0484ae4SChristoph Hellwig }
1125b0484ae4SChristoph Hellwig
ide_flush_cache(IDEState * s)11264e2b8b4aSPaolo Bonzini static void ide_flush_cache(IDEState *s)
11276bcb1a79SKevin Wolf {
11284be74634SMarkus Armbruster if (s->blk == NULL) {
11296bcb1a79SKevin Wolf ide_flush_cb(s, 0);
1130b2df7531SKevin Wolf return;
1131b2df7531SKevin Wolf }
1132b2df7531SKevin Wolf
1133f68ec837SAndreas Färber s->status |= BUSY_STAT;
113435f78ab4SEvgeny Yakovlev ide_set_retry(s);
11354be74634SMarkus Armbruster block_acct_start(blk_get_stats(s->blk), &s->acct, 0, BLOCK_ACCT_FLUSH);
11364be74634SMarkus Armbruster s->pio_aiocb = blk_aio_flush(s->blk, ide_flush_cb, s);
11376bcb1a79SKevin Wolf }
11386bcb1a79SKevin Wolf
ide_cfata_metadata_inquiry(IDEState * s)113959f2a787SGerd Hoffmann static void ide_cfata_metadata_inquiry(IDEState *s)
114059f2a787SGerd Hoffmann {
114159f2a787SGerd Hoffmann uint16_t *p;
114259f2a787SGerd Hoffmann uint32_t spd;
114359f2a787SGerd Hoffmann
114459f2a787SGerd Hoffmann p = (uint16_t *) s->io_buffer;
114559f2a787SGerd Hoffmann memset(p, 0, 0x200);
114659f2a787SGerd Hoffmann spd = ((s->mdata_size - 1) >> 9) + 1;
114759f2a787SGerd Hoffmann
114859f2a787SGerd Hoffmann put_le16(p + 0, 0x0001); /* Data format revision */
114959f2a787SGerd Hoffmann put_le16(p + 1, 0x0000); /* Media property: silicon */
115059f2a787SGerd Hoffmann put_le16(p + 2, s->media_changed); /* Media status */
115159f2a787SGerd Hoffmann put_le16(p + 3, s->mdata_size & 0xffff); /* Capacity in bytes (low) */
115259f2a787SGerd Hoffmann put_le16(p + 4, s->mdata_size >> 16); /* Capacity in bytes (high) */
115359f2a787SGerd Hoffmann put_le16(p + 5, spd & 0xffff); /* Sectors per device (low) */
115459f2a787SGerd Hoffmann put_le16(p + 6, spd >> 16); /* Sectors per device (high) */
115559f2a787SGerd Hoffmann }
115659f2a787SGerd Hoffmann
ide_cfata_metadata_read(IDEState * s)115759f2a787SGerd Hoffmann static void ide_cfata_metadata_read(IDEState *s)
115859f2a787SGerd Hoffmann {
115959f2a787SGerd Hoffmann uint16_t *p;
116059f2a787SGerd Hoffmann
116159f2a787SGerd Hoffmann if (((s->hcyl << 16) | s->lcyl) << 9 > s->mdata_size + 2) {
116259f2a787SGerd Hoffmann s->status = ERR_STAT;
116359f2a787SGerd Hoffmann s->error = ABRT_ERR;
116459f2a787SGerd Hoffmann return;
116559f2a787SGerd Hoffmann }
116659f2a787SGerd Hoffmann
116759f2a787SGerd Hoffmann p = (uint16_t *) s->io_buffer;
116859f2a787SGerd Hoffmann memset(p, 0, 0x200);
116959f2a787SGerd Hoffmann
117059f2a787SGerd Hoffmann put_le16(p + 0, s->media_changed); /* Media status */
117159f2a787SGerd Hoffmann memcpy(p + 1, s->mdata_storage + (((s->hcyl << 16) | s->lcyl) << 9),
117259f2a787SGerd Hoffmann MIN(MIN(s->mdata_size - (((s->hcyl << 16) | s->lcyl) << 9),
117359f2a787SGerd Hoffmann s->nsector << 9), 0x200 - 2));
117459f2a787SGerd Hoffmann }
117559f2a787SGerd Hoffmann
ide_cfata_metadata_write(IDEState * s)117659f2a787SGerd Hoffmann static void ide_cfata_metadata_write(IDEState *s)
117759f2a787SGerd Hoffmann {
117859f2a787SGerd Hoffmann if (((s->hcyl << 16) | s->lcyl) << 9 > s->mdata_size + 2) {
117959f2a787SGerd Hoffmann s->status = ERR_STAT;
118059f2a787SGerd Hoffmann s->error = ABRT_ERR;
118159f2a787SGerd Hoffmann return;
118259f2a787SGerd Hoffmann }
118359f2a787SGerd Hoffmann
118459f2a787SGerd Hoffmann s->media_changed = 0;
118559f2a787SGerd Hoffmann
118659f2a787SGerd Hoffmann memcpy(s->mdata_storage + (((s->hcyl << 16) | s->lcyl) << 9),
118759f2a787SGerd Hoffmann s->io_buffer + 2,
118859f2a787SGerd Hoffmann MIN(MIN(s->mdata_size - (((s->hcyl << 16) | s->lcyl) << 9),
118959f2a787SGerd Hoffmann s->nsector << 9), 0x200 - 2));
119059f2a787SGerd Hoffmann }
119159f2a787SGerd Hoffmann
119259f2a787SGerd Hoffmann /* called when the inserted state of the media has changed */
ide_cd_change_cb(void * opaque,bool load,Error ** errp)119339829a01SKevin Wolf static void ide_cd_change_cb(void *opaque, bool load, Error **errp)
119459f2a787SGerd Hoffmann {
119559f2a787SGerd Hoffmann IDEState *s = opaque;
119659f2a787SGerd Hoffmann uint64_t nb_sectors;
119759f2a787SGerd Hoffmann
119825ad22bcSMarkus Armbruster s->tray_open = !load;
11994be74634SMarkus Armbruster blk_get_geometry(s->blk, &nb_sectors);
120059f2a787SGerd Hoffmann s->nb_sectors = nb_sectors;
120159f2a787SGerd Hoffmann
12024b9b7092SAmit Shah /*
12034b9b7092SAmit Shah * First indicate to the guest that a CD has been removed. That's
12044b9b7092SAmit Shah * done on the next command the guest sends us.
12054b9b7092SAmit Shah *
120667cc61e4SPaolo Bonzini * Then we set UNIT_ATTENTION, by which the guest will
12074b9b7092SAmit Shah * detect a new CD in the drive. See ide_atapi_cmd() for details.
12084b9b7092SAmit Shah */
120959f2a787SGerd Hoffmann s->cdrom_changed = 1;
1210996faf1aSAmit Shah s->events.new_media = true;
12112df0a3a3SPaolo Bonzini s->events.eject_request = false;
12120cfe719dSPhilippe Mathieu-Daudé ide_bus_set_irq(s->bus);
12132df0a3a3SPaolo Bonzini }
12142df0a3a3SPaolo Bonzini
ide_cd_eject_request_cb(void * opaque,bool force)12152df0a3a3SPaolo Bonzini static void ide_cd_eject_request_cb(void *opaque, bool force)
12162df0a3a3SPaolo Bonzini {
12172df0a3a3SPaolo Bonzini IDEState *s = opaque;
12182df0a3a3SPaolo Bonzini
12192df0a3a3SPaolo Bonzini s->events.eject_request = true;
12202df0a3a3SPaolo Bonzini if (force) {
12212df0a3a3SPaolo Bonzini s->tray_locked = false;
12222df0a3a3SPaolo Bonzini }
12230cfe719dSPhilippe Mathieu-Daudé ide_bus_set_irq(s->bus);
122459f2a787SGerd Hoffmann }
122559f2a787SGerd Hoffmann
ide_cmd_lba48_transform(IDEState * s,int lba48)122659f2a787SGerd Hoffmann static void ide_cmd_lba48_transform(IDEState *s, int lba48)
122759f2a787SGerd Hoffmann {
122859f2a787SGerd Hoffmann s->lba48 = lba48;
122959f2a787SGerd Hoffmann
123059f2a787SGerd Hoffmann /* handle the 'magic' 0 nsector count conversion here. to avoid
123159f2a787SGerd Hoffmann * fiddling with the rest of the read logic, we just store the
123259f2a787SGerd Hoffmann * full sector count in ->nsector and ignore ->hob_nsector from now
123359f2a787SGerd Hoffmann */
123459f2a787SGerd Hoffmann if (!s->lba48) {
123559f2a787SGerd Hoffmann if (!s->nsector)
123659f2a787SGerd Hoffmann s->nsector = 256;
123759f2a787SGerd Hoffmann } else {
123859f2a787SGerd Hoffmann if (!s->nsector && !s->hob_nsector)
123959f2a787SGerd Hoffmann s->nsector = 65536;
124059f2a787SGerd Hoffmann else {
124159f2a787SGerd Hoffmann int lo = s->nsector;
124259f2a787SGerd Hoffmann int hi = s->hob_nsector;
124359f2a787SGerd Hoffmann
124459f2a787SGerd Hoffmann s->nsector = (hi << 8) | lo;
124559f2a787SGerd Hoffmann }
124659f2a787SGerd Hoffmann }
124759f2a787SGerd Hoffmann }
124859f2a787SGerd Hoffmann
ide_clear_hob(IDEBus * bus)124959f2a787SGerd Hoffmann static void ide_clear_hob(IDEBus *bus)
125059f2a787SGerd Hoffmann {
125159f2a787SGerd Hoffmann /* any write clears HOB high bit of device control register */
1252be8c9423SJohn Snow bus->cmd &= ~(IDE_CTRL_HOB);
125359f2a787SGerd Hoffmann }
125459f2a787SGerd Hoffmann
1255335ca2f2SJohn Snow /* IOport [W]rite [R]egisters */
1256335ca2f2SJohn Snow enum ATA_IOPORT_WR {
1257335ca2f2SJohn Snow ATA_IOPORT_WR_DATA = 0,
1258335ca2f2SJohn Snow ATA_IOPORT_WR_FEATURES = 1,
1259335ca2f2SJohn Snow ATA_IOPORT_WR_SECTOR_COUNT = 2,
1260335ca2f2SJohn Snow ATA_IOPORT_WR_SECTOR_NUMBER = 3,
1261335ca2f2SJohn Snow ATA_IOPORT_WR_CYLINDER_LOW = 4,
1262335ca2f2SJohn Snow ATA_IOPORT_WR_CYLINDER_HIGH = 5,
1263335ca2f2SJohn Snow ATA_IOPORT_WR_DEVICE_HEAD = 6,
1264335ca2f2SJohn Snow ATA_IOPORT_WR_COMMAND = 7,
1265335ca2f2SJohn Snow ATA_IOPORT_WR_NUM_REGISTERS,
1266335ca2f2SJohn Snow };
1267335ca2f2SJohn Snow
1268335ca2f2SJohn Snow const char *ATA_IOPORT_WR_lookup[ATA_IOPORT_WR_NUM_REGISTERS] = {
1269335ca2f2SJohn Snow [ATA_IOPORT_WR_DATA] = "Data",
1270335ca2f2SJohn Snow [ATA_IOPORT_WR_FEATURES] = "Features",
1271335ca2f2SJohn Snow [ATA_IOPORT_WR_SECTOR_COUNT] = "Sector Count",
1272335ca2f2SJohn Snow [ATA_IOPORT_WR_SECTOR_NUMBER] = "Sector Number",
1273335ca2f2SJohn Snow [ATA_IOPORT_WR_CYLINDER_LOW] = "Cylinder Low",
1274335ca2f2SJohn Snow [ATA_IOPORT_WR_CYLINDER_HIGH] = "Cylinder High",
1275335ca2f2SJohn Snow [ATA_IOPORT_WR_DEVICE_HEAD] = "Device/Head",
1276335ca2f2SJohn Snow [ATA_IOPORT_WR_COMMAND] = "Command"
1277335ca2f2SJohn Snow };
1278335ca2f2SJohn Snow
ide_ioport_write(void * opaque,uint32_t addr,uint32_t val)127959f2a787SGerd Hoffmann void ide_ioport_write(void *opaque, uint32_t addr, uint32_t val)
128059f2a787SGerd Hoffmann {
128159f2a787SGerd Hoffmann IDEBus *bus = opaque;
12822c50207fSPhilippe Mathieu-Daudé IDEState *s = ide_bus_active_if(bus);
12833eee2611SJohn Snow int reg_num = addr & 7;
128459f2a787SGerd Hoffmann
1285335ca2f2SJohn Snow trace_ide_ioport_write(addr, ATA_IOPORT_WR_lookup[reg_num], val, bus, s);
128659f2a787SGerd Hoffmann
128759f2a787SGerd Hoffmann /* ignore writes to command block while busy with previous command */
12883eee2611SJohn Snow if (reg_num != 7 && (s->status & (BUSY_STAT|DRQ_STAT))) {
128959f2a787SGerd Hoffmann return;
12903eee2611SJohn Snow }
129159f2a787SGerd Hoffmann
1292be8c9423SJohn Snow /* NOTE: Device0 and Device1 both receive incoming register writes.
1293be8c9423SJohn Snow * (They're on the same bus! They have to!) */
1294be8c9423SJohn Snow
12953eee2611SJohn Snow switch (reg_num) {
129659f2a787SGerd Hoffmann case 0:
129759f2a787SGerd Hoffmann break;
1298335ca2f2SJohn Snow case ATA_IOPORT_WR_FEATURES:
129959f2a787SGerd Hoffmann ide_clear_hob(bus);
130059f2a787SGerd Hoffmann bus->ifs[0].hob_feature = bus->ifs[0].feature;
130159f2a787SGerd Hoffmann bus->ifs[1].hob_feature = bus->ifs[1].feature;
130259f2a787SGerd Hoffmann bus->ifs[0].feature = val;
130359f2a787SGerd Hoffmann bus->ifs[1].feature = val;
130459f2a787SGerd Hoffmann break;
1305335ca2f2SJohn Snow case ATA_IOPORT_WR_SECTOR_COUNT:
130659f2a787SGerd Hoffmann ide_clear_hob(bus);
130759f2a787SGerd Hoffmann bus->ifs[0].hob_nsector = bus->ifs[0].nsector;
130859f2a787SGerd Hoffmann bus->ifs[1].hob_nsector = bus->ifs[1].nsector;
130959f2a787SGerd Hoffmann bus->ifs[0].nsector = val;
131059f2a787SGerd Hoffmann bus->ifs[1].nsector = val;
131159f2a787SGerd Hoffmann break;
1312335ca2f2SJohn Snow case ATA_IOPORT_WR_SECTOR_NUMBER:
131359f2a787SGerd Hoffmann ide_clear_hob(bus);
131459f2a787SGerd Hoffmann bus->ifs[0].hob_sector = bus->ifs[0].sector;
131559f2a787SGerd Hoffmann bus->ifs[1].hob_sector = bus->ifs[1].sector;
131659f2a787SGerd Hoffmann bus->ifs[0].sector = val;
131759f2a787SGerd Hoffmann bus->ifs[1].sector = val;
131859f2a787SGerd Hoffmann break;
1319335ca2f2SJohn Snow case ATA_IOPORT_WR_CYLINDER_LOW:
132059f2a787SGerd Hoffmann ide_clear_hob(bus);
132159f2a787SGerd Hoffmann bus->ifs[0].hob_lcyl = bus->ifs[0].lcyl;
132259f2a787SGerd Hoffmann bus->ifs[1].hob_lcyl = bus->ifs[1].lcyl;
132359f2a787SGerd Hoffmann bus->ifs[0].lcyl = val;
132459f2a787SGerd Hoffmann bus->ifs[1].lcyl = val;
132559f2a787SGerd Hoffmann break;
1326335ca2f2SJohn Snow case ATA_IOPORT_WR_CYLINDER_HIGH:
132759f2a787SGerd Hoffmann ide_clear_hob(bus);
132859f2a787SGerd Hoffmann bus->ifs[0].hob_hcyl = bus->ifs[0].hcyl;
132959f2a787SGerd Hoffmann bus->ifs[1].hob_hcyl = bus->ifs[1].hcyl;
133059f2a787SGerd Hoffmann bus->ifs[0].hcyl = val;
133159f2a787SGerd Hoffmann bus->ifs[1].hcyl = val;
133259f2a787SGerd Hoffmann break;
1333335ca2f2SJohn Snow case ATA_IOPORT_WR_DEVICE_HEAD:
1334be8c9423SJohn Snow ide_clear_hob(bus);
13350c7515e1SJohn Snow bus->ifs[0].select = val | (ATA_DEV_ALWAYS_ON);
13360c7515e1SJohn Snow bus->ifs[1].select = val | (ATA_DEV_ALWAYS_ON);
133759f2a787SGerd Hoffmann /* select drive */
13380c7515e1SJohn Snow bus->unit = (val & (ATA_DEV_SELECT)) ? 1 : 0;
133959f2a787SGerd Hoffmann break;
134059f2a787SGerd Hoffmann default:
1341335ca2f2SJohn Snow case ATA_IOPORT_WR_COMMAND:
1342be8c9423SJohn Snow ide_clear_hob(bus);
13436f52e69fSJohn Snow qemu_irq_lower(bus->irq);
1344783f4474SPhilippe Mathieu-Daudé ide_bus_exec_cmd(bus, val);
13457cff87ffSAlexander Graf break;
13467cff87ffSAlexander Graf }
13477cff87ffSAlexander Graf }
13487cff87ffSAlexander Graf
ide_reset(IDEState * s)13494590355bSJohn Snow static void ide_reset(IDEState *s)
13504590355bSJohn Snow {
13513eee2611SJohn Snow trace_ide_reset(s);
13524590355bSJohn Snow
13534590355bSJohn Snow if (s->pio_aiocb) {
13544590355bSJohn Snow blk_aio_cancel(s->pio_aiocb);
13554590355bSJohn Snow s->pio_aiocb = NULL;
13564590355bSJohn Snow }
13574590355bSJohn Snow
1358176e4961SLev Kujawski if (s->reset_reverts) {
1359176e4961SLev Kujawski s->reset_reverts = false;
1360176e4961SLev Kujawski s->heads = s->drive_heads;
1361176e4961SLev Kujawski s->sectors = s->drive_sectors;
1362176e4961SLev Kujawski }
13634590355bSJohn Snow if (s->drive_kind == IDE_CFATA)
13644590355bSJohn Snow s->mult_sectors = 0;
13654590355bSJohn Snow else
13664590355bSJohn Snow s->mult_sectors = MAX_MULT_SECTORS;
13674590355bSJohn Snow /* ide regs */
13684590355bSJohn Snow s->feature = 0;
13694590355bSJohn Snow s->error = 0;
13704590355bSJohn Snow s->nsector = 0;
13714590355bSJohn Snow s->sector = 0;
13724590355bSJohn Snow s->lcyl = 0;
13734590355bSJohn Snow s->hcyl = 0;
13744590355bSJohn Snow
13754590355bSJohn Snow /* lba48 */
13764590355bSJohn Snow s->hob_feature = 0;
13774590355bSJohn Snow s->hob_sector = 0;
13784590355bSJohn Snow s->hob_nsector = 0;
13794590355bSJohn Snow s->hob_lcyl = 0;
13804590355bSJohn Snow s->hob_hcyl = 0;
13814590355bSJohn Snow
13820c7515e1SJohn Snow s->select = (ATA_DEV_ALWAYS_ON);
13834590355bSJohn Snow s->status = READY_STAT | SEEK_STAT;
13844590355bSJohn Snow
13854590355bSJohn Snow s->lba48 = 0;
13864590355bSJohn Snow
13874590355bSJohn Snow /* ATAPI specific */
13884590355bSJohn Snow s->sense_key = 0;
13894590355bSJohn Snow s->asc = 0;
13904590355bSJohn Snow s->cdrom_changed = 0;
13914590355bSJohn Snow s->packet_transfer_size = 0;
13924590355bSJohn Snow s->elementary_transfer_size = 0;
13934590355bSJohn Snow s->io_buffer_index = 0;
13944590355bSJohn Snow s->cd_sector_size = 0;
13954590355bSJohn Snow s->atapi_dma = 0;
13964590355bSJohn Snow s->tray_locked = 0;
13974590355bSJohn Snow s->tray_open = 0;
13984590355bSJohn Snow /* ATA DMA state */
13994590355bSJohn Snow s->io_buffer_size = 0;
14004590355bSJohn Snow s->req_nb_sectors = 0;
14014590355bSJohn Snow
14024590355bSJohn Snow ide_set_signature(s);
14034590355bSJohn Snow /* init the transfer handler so that 0xffff is returned on data
14044590355bSJohn Snow accesses */
14054590355bSJohn Snow s->end_transfer_func = ide_dummy_transfer_stop;
14064590355bSJohn Snow ide_dummy_transfer_stop(s);
14074590355bSJohn Snow s->media_changed = 0;
14084590355bSJohn Snow }
14094590355bSJohn Snow
cmd_nop(IDEState * s,uint8_t cmd)1410b300337eSKevin Wolf static bool cmd_nop(IDEState *s, uint8_t cmd)
1411b300337eSKevin Wolf {
1412b300337eSKevin Wolf return true;
1413b300337eSKevin Wolf }
1414b300337eSKevin Wolf
cmd_device_reset(IDEState * s,uint8_t cmd)1415f34ae00dSJohn Snow static bool cmd_device_reset(IDEState *s, uint8_t cmd)
1416f34ae00dSJohn Snow {
1417f34ae00dSJohn Snow /* Halt PIO (in the DRQ phase), then DMA */
1418882941a5SPaolo Bonzini ide_transfer_halt(s);
1419f34ae00dSJohn Snow ide_cancel_dma_sync(s);
1420f34ae00dSJohn Snow
1421f34ae00dSJohn Snow /* Reset any PIO commands, reset signature, etc */
1422f34ae00dSJohn Snow ide_reset(s);
1423f34ae00dSJohn Snow
1424f34ae00dSJohn Snow /* RESET: ATA8-ACS3 7.10.4 "Normal Outputs";
1425f34ae00dSJohn Snow * ATA8-ACS3 Table 184 "Device Signatures for Normal Output" */
1426f34ae00dSJohn Snow s->status = 0x00;
1427f34ae00dSJohn Snow
1428f34ae00dSJohn Snow /* Do not overwrite status register */
1429f34ae00dSJohn Snow return false;
1430f34ae00dSJohn Snow }
1431f34ae00dSJohn Snow
cmd_data_set_management(IDEState * s,uint8_t cmd)14324286434cSKevin Wolf static bool cmd_data_set_management(IDEState *s, uint8_t cmd)
14334286434cSKevin Wolf {
14344286434cSKevin Wolf switch (s->feature) {
14354286434cSKevin Wolf case DSM_TRIM:
14364be74634SMarkus Armbruster if (s->blk) {
14374286434cSKevin Wolf ide_sector_start_dma(s, IDE_DMA_TRIM);
14384286434cSKevin Wolf return false;
14394286434cSKevin Wolf }
14404286434cSKevin Wolf break;
14414286434cSKevin Wolf }
14424286434cSKevin Wolf
14434286434cSKevin Wolf ide_abort_command(s);
14444286434cSKevin Wolf return true;
14454286434cSKevin Wolf }
14464286434cSKevin Wolf
cmd_identify(IDEState * s,uint8_t cmd)14471c66869aSKevin Wolf static bool cmd_identify(IDEState *s, uint8_t cmd)
14481c66869aSKevin Wolf {
14494be74634SMarkus Armbruster if (s->blk && s->drive_kind != IDE_CD) {
14501c66869aSKevin Wolf if (s->drive_kind != IDE_CFATA) {
14511c66869aSKevin Wolf ide_identify(s);
14521c66869aSKevin Wolf } else {
14531c66869aSKevin Wolf ide_cfata_identify(s);
14541c66869aSKevin Wolf }
14551c66869aSKevin Wolf s->status = READY_STAT | SEEK_STAT;
14561c66869aSKevin Wolf ide_transfer_start(s, s->io_buffer, 512, ide_transfer_stop);
14570cfe719dSPhilippe Mathieu-Daudé ide_bus_set_irq(s->bus);
14581c66869aSKevin Wolf return false;
14591c66869aSKevin Wolf } else {
14601c66869aSKevin Wolf if (s->drive_kind == IDE_CD) {
14611c66869aSKevin Wolf ide_set_signature(s);
14621c66869aSKevin Wolf }
14631c66869aSKevin Wolf ide_abort_command(s);
14641c66869aSKevin Wolf }
14651c66869aSKevin Wolf
14661c66869aSKevin Wolf return true;
14671c66869aSKevin Wolf }
14681c66869aSKevin Wolf
cmd_verify(IDEState * s,uint8_t cmd)1469413860cfSKevin Wolf static bool cmd_verify(IDEState *s, uint8_t cmd)
1470413860cfSKevin Wolf {
1471413860cfSKevin Wolf bool lba48 = (cmd == WIN_VERIFY_EXT);
1472413860cfSKevin Wolf
1473413860cfSKevin Wolf /* do sector number check ? */
1474413860cfSKevin Wolf ide_cmd_lba48_transform(s, lba48);
1475413860cfSKevin Wolf
1476413860cfSKevin Wolf return true;
1477413860cfSKevin Wolf }
1478413860cfSKevin Wolf
cmd_set_multiple_mode(IDEState * s,uint8_t cmd)1479adf3a2c4SKevin Wolf static bool cmd_set_multiple_mode(IDEState *s, uint8_t cmd)
1480adf3a2c4SKevin Wolf {
1481adf3a2c4SKevin Wolf if (s->drive_kind == IDE_CFATA && s->nsector == 0) {
1482adf3a2c4SKevin Wolf /* Disable Read and Write Multiple */
1483adf3a2c4SKevin Wolf s->mult_sectors = 0;
1484adf3a2c4SKevin Wolf } else if ((s->nsector & 0xff) != 0 &&
1485adf3a2c4SKevin Wolf ((s->nsector & 0xff) > MAX_MULT_SECTORS ||
1486adf3a2c4SKevin Wolf (s->nsector & (s->nsector - 1)) != 0)) {
1487adf3a2c4SKevin Wolf ide_abort_command(s);
1488adf3a2c4SKevin Wolf } else {
1489adf3a2c4SKevin Wolf s->mult_sectors = s->nsector & 0xff;
1490adf3a2c4SKevin Wolf }
1491adf3a2c4SKevin Wolf
1492adf3a2c4SKevin Wolf return true;
1493adf3a2c4SKevin Wolf }
1494adf3a2c4SKevin Wolf
cmd_read_multiple(IDEState * s,uint8_t cmd)1495adf3a2c4SKevin Wolf static bool cmd_read_multiple(IDEState *s, uint8_t cmd)
1496adf3a2c4SKevin Wolf {
1497adf3a2c4SKevin Wolf bool lba48 = (cmd == WIN_MULTREAD_EXT);
1498adf3a2c4SKevin Wolf
14994be74634SMarkus Armbruster if (!s->blk || !s->mult_sectors) {
1500adf3a2c4SKevin Wolf ide_abort_command(s);
1501adf3a2c4SKevin Wolf return true;
1502adf3a2c4SKevin Wolf }
1503adf3a2c4SKevin Wolf
1504adf3a2c4SKevin Wolf ide_cmd_lba48_transform(s, lba48);
1505adf3a2c4SKevin Wolf s->req_nb_sectors = s->mult_sectors;
1506adf3a2c4SKevin Wolf ide_sector_read(s);
1507adf3a2c4SKevin Wolf return false;
1508adf3a2c4SKevin Wolf }
1509adf3a2c4SKevin Wolf
cmd_write_multiple(IDEState * s,uint8_t cmd)1510adf3a2c4SKevin Wolf static bool cmd_write_multiple(IDEState *s, uint8_t cmd)
1511adf3a2c4SKevin Wolf {
1512adf3a2c4SKevin Wolf bool lba48 = (cmd == WIN_MULTWRITE_EXT);
1513adf3a2c4SKevin Wolf int n;
1514adf3a2c4SKevin Wolf
15154be74634SMarkus Armbruster if (!s->blk || !s->mult_sectors) {
1516adf3a2c4SKevin Wolf ide_abort_command(s);
1517adf3a2c4SKevin Wolf return true;
1518adf3a2c4SKevin Wolf }
1519adf3a2c4SKevin Wolf
1520adf3a2c4SKevin Wolf ide_cmd_lba48_transform(s, lba48);
1521adf3a2c4SKevin Wolf
1522adf3a2c4SKevin Wolf s->req_nb_sectors = s->mult_sectors;
1523adf3a2c4SKevin Wolf n = MIN(s->nsector, s->req_nb_sectors);
1524adf3a2c4SKevin Wolf
1525adf3a2c4SKevin Wolf s->status = SEEK_STAT | READY_STAT;
1526adf3a2c4SKevin Wolf ide_transfer_start(s, s->io_buffer, 512 * n, ide_sector_write);
1527adf3a2c4SKevin Wolf
1528adf3a2c4SKevin Wolf s->media_changed = 1;
1529adf3a2c4SKevin Wolf
1530adf3a2c4SKevin Wolf return false;
1531adf3a2c4SKevin Wolf }
1532adf3a2c4SKevin Wolf
cmd_read_pio(IDEState * s,uint8_t cmd)15330e6498edSKevin Wolf static bool cmd_read_pio(IDEState *s, uint8_t cmd)
15340e6498edSKevin Wolf {
15350e6498edSKevin Wolf bool lba48 = (cmd == WIN_READ_EXT);
15360e6498edSKevin Wolf
15370e6498edSKevin Wolf if (s->drive_kind == IDE_CD) {
15380e6498edSKevin Wolf ide_set_signature(s); /* odd, but ATA4 8.27.5.2 requires it */
15390e6498edSKevin Wolf ide_abort_command(s);
15400e6498edSKevin Wolf return true;
15410e6498edSKevin Wolf }
15420e6498edSKevin Wolf
15434be74634SMarkus Armbruster if (!s->blk) {
15440e6498edSKevin Wolf ide_abort_command(s);
15450e6498edSKevin Wolf return true;
15460e6498edSKevin Wolf }
15470e6498edSKevin Wolf
15480e6498edSKevin Wolf ide_cmd_lba48_transform(s, lba48);
15490e6498edSKevin Wolf s->req_nb_sectors = 1;
15500e6498edSKevin Wolf ide_sector_read(s);
15510e6498edSKevin Wolf
15520e6498edSKevin Wolf return false;
15530e6498edSKevin Wolf }
15540e6498edSKevin Wolf
cmd_write_pio(IDEState * s,uint8_t cmd)15550e6498edSKevin Wolf static bool cmd_write_pio(IDEState *s, uint8_t cmd)
15560e6498edSKevin Wolf {
15570e6498edSKevin Wolf bool lba48 = (cmd == WIN_WRITE_EXT);
15580e6498edSKevin Wolf
15594be74634SMarkus Armbruster if (!s->blk) {
15600e6498edSKevin Wolf ide_abort_command(s);
15610e6498edSKevin Wolf return true;
15620e6498edSKevin Wolf }
15630e6498edSKevin Wolf
15640e6498edSKevin Wolf ide_cmd_lba48_transform(s, lba48);
15650e6498edSKevin Wolf
15660e6498edSKevin Wolf s->req_nb_sectors = 1;
15670e6498edSKevin Wolf s->status = SEEK_STAT | READY_STAT;
15680e6498edSKevin Wolf ide_transfer_start(s, s->io_buffer, 512, ide_sector_write);
15690e6498edSKevin Wolf
15700e6498edSKevin Wolf s->media_changed = 1;
15710e6498edSKevin Wolf
15720e6498edSKevin Wolf return false;
15730e6498edSKevin Wolf }
15740e6498edSKevin Wolf
cmd_read_dma(IDEState * s,uint8_t cmd)157592a6a6f6SKevin Wolf static bool cmd_read_dma(IDEState *s, uint8_t cmd)
157692a6a6f6SKevin Wolf {
157792a6a6f6SKevin Wolf bool lba48 = (cmd == WIN_READDMA_EXT);
157892a6a6f6SKevin Wolf
15794be74634SMarkus Armbruster if (!s->blk) {
158092a6a6f6SKevin Wolf ide_abort_command(s);
158192a6a6f6SKevin Wolf return true;
158292a6a6f6SKevin Wolf }
158392a6a6f6SKevin Wolf
158492a6a6f6SKevin Wolf ide_cmd_lba48_transform(s, lba48);
158592a6a6f6SKevin Wolf ide_sector_start_dma(s, IDE_DMA_READ);
158692a6a6f6SKevin Wolf
158792a6a6f6SKevin Wolf return false;
158892a6a6f6SKevin Wolf }
158992a6a6f6SKevin Wolf
cmd_write_dma(IDEState * s,uint8_t cmd)159092a6a6f6SKevin Wolf static bool cmd_write_dma(IDEState *s, uint8_t cmd)
159192a6a6f6SKevin Wolf {
159292a6a6f6SKevin Wolf bool lba48 = (cmd == WIN_WRITEDMA_EXT);
159392a6a6f6SKevin Wolf
15944be74634SMarkus Armbruster if (!s->blk) {
159592a6a6f6SKevin Wolf ide_abort_command(s);
159692a6a6f6SKevin Wolf return true;
159792a6a6f6SKevin Wolf }
159892a6a6f6SKevin Wolf
159992a6a6f6SKevin Wolf ide_cmd_lba48_transform(s, lba48);
160092a6a6f6SKevin Wolf ide_sector_start_dma(s, IDE_DMA_WRITE);
160192a6a6f6SKevin Wolf
160292a6a6f6SKevin Wolf s->media_changed = 1;
160392a6a6f6SKevin Wolf
160492a6a6f6SKevin Wolf return false;
160592a6a6f6SKevin Wolf }
160692a6a6f6SKevin Wolf
cmd_flush_cache(IDEState * s,uint8_t cmd)16079afce429SKevin Wolf static bool cmd_flush_cache(IDEState *s, uint8_t cmd)
16089afce429SKevin Wolf {
16099afce429SKevin Wolf ide_flush_cache(s);
16109afce429SKevin Wolf return false;
16119afce429SKevin Wolf }
16129afce429SKevin Wolf
cmd_seek(IDEState * s,uint8_t cmd)161361fdda37SKevin Wolf static bool cmd_seek(IDEState *s, uint8_t cmd)
161461fdda37SKevin Wolf {
161561fdda37SKevin Wolf /* XXX: Check that seek is within bounds */
161661fdda37SKevin Wolf return true;
161761fdda37SKevin Wolf }
161861fdda37SKevin Wolf
cmd_read_native_max(IDEState * s,uint8_t cmd)161963a82e6aSKevin Wolf static bool cmd_read_native_max(IDEState *s, uint8_t cmd)
162063a82e6aSKevin Wolf {
162163a82e6aSKevin Wolf bool lba48 = (cmd == WIN_READ_NATIVE_MAX_EXT);
162263a82e6aSKevin Wolf
162363a82e6aSKevin Wolf /* Refuse if no sectors are addressable (e.g. medium not inserted) */
162463a82e6aSKevin Wolf if (s->nb_sectors == 0) {
162563a82e6aSKevin Wolf ide_abort_command(s);
162663a82e6aSKevin Wolf return true;
162763a82e6aSKevin Wolf }
162863a82e6aSKevin Wolf
162963a82e6aSKevin Wolf ide_cmd_lba48_transform(s, lba48);
163063a82e6aSKevin Wolf ide_set_sector(s, s->nb_sectors - 1);
163163a82e6aSKevin Wolf
163263a82e6aSKevin Wolf return true;
163363a82e6aSKevin Wolf }
163463a82e6aSKevin Wolf
cmd_check_power_mode(IDEState * s,uint8_t cmd)1635785f6320SKevin Wolf static bool cmd_check_power_mode(IDEState *s, uint8_t cmd)
1636785f6320SKevin Wolf {
1637785f6320SKevin Wolf s->nsector = 0xff; /* device active or idle */
1638785f6320SKevin Wolf return true;
1639785f6320SKevin Wolf }
1640785f6320SKevin Wolf
1641176e4961SLev Kujawski /* INITIALIZE DEVICE PARAMETERS */
cmd_specify(IDEState * s,uint8_t cmd)1642176e4961SLev Kujawski static bool cmd_specify(IDEState *s, uint8_t cmd)
1643176e4961SLev Kujawski {
1644176e4961SLev Kujawski if (s->blk && s->drive_kind != IDE_CD) {
1645176e4961SLev Kujawski s->heads = (s->select & (ATA_DEV_HS)) + 1;
1646176e4961SLev Kujawski s->sectors = s->nsector;
16470cfe719dSPhilippe Mathieu-Daudé ide_bus_set_irq(s->bus);
1648176e4961SLev Kujawski } else {
1649176e4961SLev Kujawski ide_abort_command(s);
1650176e4961SLev Kujawski }
1651176e4961SLev Kujawski
1652176e4961SLev Kujawski return true;
1653176e4961SLev Kujawski }
1654176e4961SLev Kujawski
cmd_set_features(IDEState * s,uint8_t cmd)1655ee03398cSKevin Wolf static bool cmd_set_features(IDEState *s, uint8_t cmd)
1656ee03398cSKevin Wolf {
1657ee03398cSKevin Wolf uint16_t *identify_data;
1658ee03398cSKevin Wolf
16594be74634SMarkus Armbruster if (!s->blk) {
1660ee03398cSKevin Wolf ide_abort_command(s);
1661ee03398cSKevin Wolf return true;
1662ee03398cSKevin Wolf }
1663ee03398cSKevin Wolf
1664ee03398cSKevin Wolf /* XXX: valid for CDROM ? */
1665ee03398cSKevin Wolf switch (s->feature) {
16661ea17d22SLubomir Rintel case 0x01: /* 8-bit I/O enable (CompactFlash) */
16671ea17d22SLubomir Rintel case 0x81: /* 8-bit I/O disable (CompactFlash) */
16681ea17d22SLubomir Rintel if (s->drive_kind != IDE_CFATA) {
16691ea17d22SLubomir Rintel goto abort_cmd;
16701ea17d22SLubomir Rintel }
16711ea17d22SLubomir Rintel s->io8 = !(s->feature & 0x80);
16721ea17d22SLubomir Rintel return true;
1673ee03398cSKevin Wolf case 0x02: /* write cache enable */
16744be74634SMarkus Armbruster blk_set_enable_write_cache(s->blk, true);
1675ee03398cSKevin Wolf identify_data = (uint16_t *)s->identify_data;
1676ee03398cSKevin Wolf put_le16(identify_data + 85, (1 << 14) | (1 << 5) | 1);
1677ee03398cSKevin Wolf return true;
1678ee03398cSKevin Wolf case 0x82: /* write cache disable */
16794be74634SMarkus Armbruster blk_set_enable_write_cache(s->blk, false);
1680ee03398cSKevin Wolf identify_data = (uint16_t *)s->identify_data;
1681ee03398cSKevin Wolf put_le16(identify_data + 85, (1 << 14) | 1);
1682ee03398cSKevin Wolf ide_flush_cache(s);
1683ee03398cSKevin Wolf return false;
1684ee03398cSKevin Wolf case 0xcc: /* reverting to power-on defaults enable */
1685176e4961SLev Kujawski s->reset_reverts = true;
1686176e4961SLev Kujawski return true;
1687ee03398cSKevin Wolf case 0x66: /* reverting to power-on defaults disable */
1688176e4961SLev Kujawski s->reset_reverts = false;
1689176e4961SLev Kujawski return true;
1690ee03398cSKevin Wolf case 0xaa: /* read look-ahead enable */
1691ee03398cSKevin Wolf case 0x55: /* read look-ahead disable */
1692ee03398cSKevin Wolf case 0x05: /* set advanced power management mode */
1693ee03398cSKevin Wolf case 0x85: /* disable advanced power management mode */
1694ee03398cSKevin Wolf case 0x69: /* NOP */
1695ee03398cSKevin Wolf case 0x67: /* NOP */
1696ee03398cSKevin Wolf case 0x96: /* NOP */
1697ee03398cSKevin Wolf case 0x9a: /* NOP */
1698ee03398cSKevin Wolf case 0x42: /* enable Automatic Acoustic Mode */
1699ee03398cSKevin Wolf case 0xc2: /* disable Automatic Acoustic Mode */
1700ee03398cSKevin Wolf return true;
1701ee03398cSKevin Wolf case 0x03: /* set transfer mode */
1702ee03398cSKevin Wolf {
1703ee03398cSKevin Wolf uint8_t val = s->nsector & 0x07;
1704ee03398cSKevin Wolf identify_data = (uint16_t *)s->identify_data;
1705ee03398cSKevin Wolf
1706ee03398cSKevin Wolf switch (s->nsector >> 3) {
1707ee03398cSKevin Wolf case 0x00: /* pio default */
1708ee03398cSKevin Wolf case 0x01: /* pio mode */
1709ee03398cSKevin Wolf put_le16(identify_data + 62, 0x07);
1710ee03398cSKevin Wolf put_le16(identify_data + 63, 0x07);
1711ee03398cSKevin Wolf put_le16(identify_data + 88, 0x3f);
1712ee03398cSKevin Wolf break;
1713a980b95cSMichael Tokarev case 0x02: /* single word dma mode */
1714ee03398cSKevin Wolf put_le16(identify_data + 62, 0x07 | (1 << (val + 8)));
1715ee03398cSKevin Wolf put_le16(identify_data + 63, 0x07);
1716ee03398cSKevin Wolf put_le16(identify_data + 88, 0x3f);
1717ee03398cSKevin Wolf break;
1718ee03398cSKevin Wolf case 0x04: /* mdma mode */
1719ee03398cSKevin Wolf put_le16(identify_data + 62, 0x07);
1720ee03398cSKevin Wolf put_le16(identify_data + 63, 0x07 | (1 << (val + 8)));
1721ee03398cSKevin Wolf put_le16(identify_data + 88, 0x3f);
1722ee03398cSKevin Wolf break;
1723ee03398cSKevin Wolf case 0x08: /* udma mode */
1724ee03398cSKevin Wolf put_le16(identify_data + 62, 0x07);
1725ee03398cSKevin Wolf put_le16(identify_data + 63, 0x07);
1726ee03398cSKevin Wolf put_le16(identify_data + 88, 0x3f | (1 << (val + 8)));
1727ee03398cSKevin Wolf break;
1728ee03398cSKevin Wolf default:
1729ee03398cSKevin Wolf goto abort_cmd;
1730ee03398cSKevin Wolf }
1731ee03398cSKevin Wolf return true;
1732ee03398cSKevin Wolf }
1733ee03398cSKevin Wolf }
1734ee03398cSKevin Wolf
1735ee03398cSKevin Wolf abort_cmd:
1736ee03398cSKevin Wolf ide_abort_command(s);
1737ee03398cSKevin Wolf return true;
1738ee03398cSKevin Wolf }
1739ee03398cSKevin Wolf
1740ee425c78SKevin Wolf
1741ee425c78SKevin Wolf /*** ATAPI commands ***/
1742ee425c78SKevin Wolf
cmd_identify_packet(IDEState * s,uint8_t cmd)1743ee425c78SKevin Wolf static bool cmd_identify_packet(IDEState *s, uint8_t cmd)
1744ee425c78SKevin Wolf {
1745ee425c78SKevin Wolf ide_atapi_identify(s);
1746ee425c78SKevin Wolf s->status = READY_STAT | SEEK_STAT;
1747ee425c78SKevin Wolf ide_transfer_start(s, s->io_buffer, 512, ide_transfer_stop);
17480cfe719dSPhilippe Mathieu-Daudé ide_bus_set_irq(s->bus);
1749ee425c78SKevin Wolf return false;
1750ee425c78SKevin Wolf }
1751ee425c78SKevin Wolf
17523195c9e6SLev Kujawski /* EXECUTE DEVICE DIAGNOSTIC */
cmd_exec_dev_diagnostic(IDEState * s,uint8_t cmd)1753ee425c78SKevin Wolf static bool cmd_exec_dev_diagnostic(IDEState *s, uint8_t cmd)
1754ee425c78SKevin Wolf {
17553195c9e6SLev Kujawski /*
17563195c9e6SLev Kujawski * Clear the device register per the ATA (v6) specification,
17573195c9e6SLev Kujawski * because ide_set_signature does not clear LBA or drive bits.
17583195c9e6SLev Kujawski */
17593195c9e6SLev Kujawski s->select = (ATA_DEV_ALWAYS_ON);
1760ee425c78SKevin Wolf ide_set_signature(s);
1761ee425c78SKevin Wolf
1762ee425c78SKevin Wolf if (s->drive_kind == IDE_CD) {
1763ee425c78SKevin Wolf s->status = 0; /* ATAPI spec (v6) section 9.10 defines packet
1764ee425c78SKevin Wolf * devices to return a clear status register
1765ee425c78SKevin Wolf * with READY_STAT *not* set. */
1766850484a2SDavid du Colombier s->error = 0x01;
1767ee425c78SKevin Wolf } else {
1768ee425c78SKevin Wolf s->status = READY_STAT | SEEK_STAT;
1769ee425c78SKevin Wolf /* The bits of the error register are not as usual for this command!
1770ee425c78SKevin Wolf * They are part of the regular output (this is why ERR_STAT isn't set)
1771ee425c78SKevin Wolf * Device 0 passed, Device 1 passed or not present. */
1772ee425c78SKevin Wolf s->error = 0x01;
17730cfe719dSPhilippe Mathieu-Daudé ide_bus_set_irq(s->bus);
1774ee425c78SKevin Wolf }
1775ee425c78SKevin Wolf
1776ee425c78SKevin Wolf return false;
1777ee425c78SKevin Wolf }
1778ee425c78SKevin Wolf
cmd_packet(IDEState * s,uint8_t cmd)1779ee425c78SKevin Wolf static bool cmd_packet(IDEState *s, uint8_t cmd)
1780ee425c78SKevin Wolf {
1781ee425c78SKevin Wolf /* overlapping commands not supported */
1782ee425c78SKevin Wolf if (s->feature & 0x02) {
1783ee425c78SKevin Wolf ide_abort_command(s);
1784ee425c78SKevin Wolf return true;
1785ee425c78SKevin Wolf }
1786ee425c78SKevin Wolf
1787ee425c78SKevin Wolf s->status = READY_STAT | SEEK_STAT;
1788ee425c78SKevin Wolf s->atapi_dma = s->feature & 1;
1789502356eeSPavel Butsykin if (s->atapi_dma) {
1790502356eeSPavel Butsykin s->dma_cmd = IDE_DMA_ATAPI;
1791502356eeSPavel Butsykin }
1792ee425c78SKevin Wolf s->nsector = 1;
1793ee425c78SKevin Wolf ide_transfer_start(s, s->io_buffer, ATAPI_PACKET_SIZE,
1794ee425c78SKevin Wolf ide_atapi_cmd);
1795ee425c78SKevin Wolf return false;
1796ee425c78SKevin Wolf }
1797ee425c78SKevin Wolf
17986b1dd744SKevin Wolf
17996b1dd744SKevin Wolf /*** CF-ATA commands ***/
18006b1dd744SKevin Wolf
cmd_cfa_req_ext_error_code(IDEState * s,uint8_t cmd)18016b1dd744SKevin Wolf static bool cmd_cfa_req_ext_error_code(IDEState *s, uint8_t cmd)
18026b1dd744SKevin Wolf {
18036b1dd744SKevin Wolf s->error = 0x09; /* miscellaneous error */
18046b1dd744SKevin Wolf s->status = READY_STAT | SEEK_STAT;
18050cfe719dSPhilippe Mathieu-Daudé ide_bus_set_irq(s->bus);
18066b1dd744SKevin Wolf
18076b1dd744SKevin Wolf return false;
18086b1dd744SKevin Wolf }
18096b1dd744SKevin Wolf
cmd_cfa_erase_sectors(IDEState * s,uint8_t cmd)18106b1dd744SKevin Wolf static bool cmd_cfa_erase_sectors(IDEState *s, uint8_t cmd)
18116b1dd744SKevin Wolf {
18126b1dd744SKevin Wolf /* WIN_SECURITY_FREEZE_LOCK has the same ID as CFA_WEAR_LEVEL and is
18136b1dd744SKevin Wolf * required for Windows 8 to work with AHCI */
18146b1dd744SKevin Wolf
18156b1dd744SKevin Wolf if (cmd == CFA_WEAR_LEVEL) {
18166b1dd744SKevin Wolf s->nsector = 0;
18176b1dd744SKevin Wolf }
18186b1dd744SKevin Wolf
18196b1dd744SKevin Wolf if (cmd == CFA_ERASE_SECTORS) {
18206b1dd744SKevin Wolf s->media_changed = 1;
18216b1dd744SKevin Wolf }
18226b1dd744SKevin Wolf
18236b1dd744SKevin Wolf return true;
18246b1dd744SKevin Wolf }
18256b1dd744SKevin Wolf
cmd_cfa_translate_sector(IDEState * s,uint8_t cmd)18266b1dd744SKevin Wolf static bool cmd_cfa_translate_sector(IDEState *s, uint8_t cmd)
18276b1dd744SKevin Wolf {
18286b1dd744SKevin Wolf s->status = READY_STAT | SEEK_STAT;
18296b1dd744SKevin Wolf
18306b1dd744SKevin Wolf memset(s->io_buffer, 0, 0x200);
18316b1dd744SKevin Wolf s->io_buffer[0x00] = s->hcyl; /* Cyl MSB */
18326b1dd744SKevin Wolf s->io_buffer[0x01] = s->lcyl; /* Cyl LSB */
18336b1dd744SKevin Wolf s->io_buffer[0x02] = s->select; /* Head */
18346b1dd744SKevin Wolf s->io_buffer[0x03] = s->sector; /* Sector */
18356b1dd744SKevin Wolf s->io_buffer[0x04] = ide_get_sector(s) >> 16; /* LBA MSB */
18366b1dd744SKevin Wolf s->io_buffer[0x05] = ide_get_sector(s) >> 8; /* LBA */
18376b1dd744SKevin Wolf s->io_buffer[0x06] = ide_get_sector(s) >> 0; /* LBA LSB */
18386b1dd744SKevin Wolf s->io_buffer[0x13] = 0x00; /* Erase flag */
18396b1dd744SKevin Wolf s->io_buffer[0x18] = 0x00; /* Hot count */
18406b1dd744SKevin Wolf s->io_buffer[0x19] = 0x00; /* Hot count */
18416b1dd744SKevin Wolf s->io_buffer[0x1a] = 0x01; /* Hot count */
18426b1dd744SKevin Wolf
18436b1dd744SKevin Wolf ide_transfer_start(s, s->io_buffer, 0x200, ide_transfer_stop);
18440cfe719dSPhilippe Mathieu-Daudé ide_bus_set_irq(s->bus);
18456b1dd744SKevin Wolf
18466b1dd744SKevin Wolf return false;
18476b1dd744SKevin Wolf }
18486b1dd744SKevin Wolf
cmd_cfa_access_metadata_storage(IDEState * s,uint8_t cmd)18496b1dd744SKevin Wolf static bool cmd_cfa_access_metadata_storage(IDEState *s, uint8_t cmd)
18506b1dd744SKevin Wolf {
18516b1dd744SKevin Wolf switch (s->feature) {
18526b1dd744SKevin Wolf case 0x02: /* Inquiry Metadata Storage */
18536b1dd744SKevin Wolf ide_cfata_metadata_inquiry(s);
18546b1dd744SKevin Wolf break;
18556b1dd744SKevin Wolf case 0x03: /* Read Metadata Storage */
18566b1dd744SKevin Wolf ide_cfata_metadata_read(s);
18576b1dd744SKevin Wolf break;
18586b1dd744SKevin Wolf case 0x04: /* Write Metadata Storage */
18596b1dd744SKevin Wolf ide_cfata_metadata_write(s);
18606b1dd744SKevin Wolf break;
18616b1dd744SKevin Wolf default:
18626b1dd744SKevin Wolf ide_abort_command(s);
18636b1dd744SKevin Wolf return true;
18646b1dd744SKevin Wolf }
18656b1dd744SKevin Wolf
18666b1dd744SKevin Wolf ide_transfer_start(s, s->io_buffer, 0x200, ide_transfer_stop);
18676b1dd744SKevin Wolf s->status = 0x00; /* NOTE: READY is _not_ set */
18680cfe719dSPhilippe Mathieu-Daudé ide_bus_set_irq(s->bus);
18696b1dd744SKevin Wolf
18706b1dd744SKevin Wolf return false;
18716b1dd744SKevin Wolf }
18726b1dd744SKevin Wolf
cmd_ibm_sense_condition(IDEState * s,uint8_t cmd)18736b1dd744SKevin Wolf static bool cmd_ibm_sense_condition(IDEState *s, uint8_t cmd)
18746b1dd744SKevin Wolf {
18756b1dd744SKevin Wolf switch (s->feature) {
18766b1dd744SKevin Wolf case 0x01: /* sense temperature in device */
18776b1dd744SKevin Wolf s->nsector = 0x50; /* +20 C */
18786b1dd744SKevin Wolf break;
18796b1dd744SKevin Wolf default:
18806b1dd744SKevin Wolf ide_abort_command(s);
18816b1dd744SKevin Wolf return true;
18826b1dd744SKevin Wolf }
18836b1dd744SKevin Wolf
18846b1dd744SKevin Wolf return true;
18856b1dd744SKevin Wolf }
18866b1dd744SKevin Wolf
1887ff352677SKevin Wolf
1888ff352677SKevin Wolf /*** SMART commands ***/
1889ff352677SKevin Wolf
cmd_smart(IDEState * s,uint8_t cmd)1890ff352677SKevin Wolf static bool cmd_smart(IDEState *s, uint8_t cmd)
1891ff352677SKevin Wolf {
1892ff352677SKevin Wolf int n;
1893ff352677SKevin Wolf
1894ff352677SKevin Wolf if (s->hcyl != 0xc2 || s->lcyl != 0x4f) {
1895ff352677SKevin Wolf goto abort_cmd;
1896ff352677SKevin Wolf }
1897ff352677SKevin Wolf
1898ff352677SKevin Wolf if (!s->smart_enabled && s->feature != SMART_ENABLE) {
1899ff352677SKevin Wolf goto abort_cmd;
1900ff352677SKevin Wolf }
1901ff352677SKevin Wolf
1902ff352677SKevin Wolf switch (s->feature) {
1903ff352677SKevin Wolf case SMART_DISABLE:
1904ff352677SKevin Wolf s->smart_enabled = 0;
1905ff352677SKevin Wolf return true;
1906ff352677SKevin Wolf
1907ff352677SKevin Wolf case SMART_ENABLE:
1908ff352677SKevin Wolf s->smart_enabled = 1;
1909ff352677SKevin Wolf return true;
1910ff352677SKevin Wolf
1911ff352677SKevin Wolf case SMART_ATTR_AUTOSAVE:
1912ff352677SKevin Wolf switch (s->sector) {
1913ff352677SKevin Wolf case 0x00:
1914ff352677SKevin Wolf s->smart_autosave = 0;
1915ff352677SKevin Wolf break;
1916ff352677SKevin Wolf case 0xf1:
1917ff352677SKevin Wolf s->smart_autosave = 1;
1918ff352677SKevin Wolf break;
1919ff352677SKevin Wolf default:
1920ff352677SKevin Wolf goto abort_cmd;
1921ff352677SKevin Wolf }
1922ff352677SKevin Wolf return true;
1923ff352677SKevin Wolf
1924ff352677SKevin Wolf case SMART_STATUS:
1925ff352677SKevin Wolf if (!s->smart_errors) {
1926ff352677SKevin Wolf s->hcyl = 0xc2;
1927ff352677SKevin Wolf s->lcyl = 0x4f;
1928ff352677SKevin Wolf } else {
1929ff352677SKevin Wolf s->hcyl = 0x2c;
1930ff352677SKevin Wolf s->lcyl = 0xf4;
1931ff352677SKevin Wolf }
1932ff352677SKevin Wolf return true;
1933ff352677SKevin Wolf
1934ff352677SKevin Wolf case SMART_READ_THRESH:
1935ff352677SKevin Wolf memset(s->io_buffer, 0, 0x200);
1936ff352677SKevin Wolf s->io_buffer[0] = 0x01; /* smart struct version */
1937ff352677SKevin Wolf
1938ff352677SKevin Wolf for (n = 0; n < ARRAY_SIZE(smart_attributes); n++) {
1939ff352677SKevin Wolf s->io_buffer[2 + 0 + (n * 12)] = smart_attributes[n][0];
1940ff352677SKevin Wolf s->io_buffer[2 + 1 + (n * 12)] = smart_attributes[n][11];
1941ff352677SKevin Wolf }
1942ff352677SKevin Wolf
1943ff352677SKevin Wolf /* checksum */
1944ff352677SKevin Wolf for (n = 0; n < 511; n++) {
1945ff352677SKevin Wolf s->io_buffer[511] += s->io_buffer[n];
1946ff352677SKevin Wolf }
1947ff352677SKevin Wolf s->io_buffer[511] = 0x100 - s->io_buffer[511];
1948ff352677SKevin Wolf
1949ff352677SKevin Wolf s->status = READY_STAT | SEEK_STAT;
1950ff352677SKevin Wolf ide_transfer_start(s, s->io_buffer, 0x200, ide_transfer_stop);
19510cfe719dSPhilippe Mathieu-Daudé ide_bus_set_irq(s->bus);
1952ff352677SKevin Wolf return false;
1953ff352677SKevin Wolf
1954ff352677SKevin Wolf case SMART_READ_DATA:
1955ff352677SKevin Wolf memset(s->io_buffer, 0, 0x200);
1956ff352677SKevin Wolf s->io_buffer[0] = 0x01; /* smart struct version */
1957ff352677SKevin Wolf
1958ff352677SKevin Wolf for (n = 0; n < ARRAY_SIZE(smart_attributes); n++) {
1959ff352677SKevin Wolf int i;
1960ff352677SKevin Wolf for (i = 0; i < 11; i++) {
1961ff352677SKevin Wolf s->io_buffer[2 + i + (n * 12)] = smart_attributes[n][i];
1962ff352677SKevin Wolf }
1963ff352677SKevin Wolf }
1964ff352677SKevin Wolf
1965ff352677SKevin Wolf s->io_buffer[362] = 0x02 | (s->smart_autosave ? 0x80 : 0x00);
1966ff352677SKevin Wolf if (s->smart_selftest_count == 0) {
1967ff352677SKevin Wolf s->io_buffer[363] = 0;
1968ff352677SKevin Wolf } else {
1969ff352677SKevin Wolf s->io_buffer[363] =
1970ff352677SKevin Wolf s->smart_selftest_data[3 +
1971ff352677SKevin Wolf (s->smart_selftest_count - 1) *
1972ff352677SKevin Wolf 24];
1973ff352677SKevin Wolf }
1974ff352677SKevin Wolf s->io_buffer[364] = 0x20;
1975ff352677SKevin Wolf s->io_buffer[365] = 0x01;
1976ff352677SKevin Wolf /* offline data collection capacity: execute + self-test*/
1977ff352677SKevin Wolf s->io_buffer[367] = (1 << 4 | 1 << 3 | 1);
1978ff352677SKevin Wolf s->io_buffer[368] = 0x03; /* smart capability (1) */
1979ff352677SKevin Wolf s->io_buffer[369] = 0x00; /* smart capability (2) */
1980ff352677SKevin Wolf s->io_buffer[370] = 0x01; /* error logging supported */
1981ff352677SKevin Wolf s->io_buffer[372] = 0x02; /* minutes for poll short test */
1982ff352677SKevin Wolf s->io_buffer[373] = 0x36; /* minutes for poll ext test */
1983ff352677SKevin Wolf s->io_buffer[374] = 0x01; /* minutes for poll conveyance */
1984ff352677SKevin Wolf
1985ff352677SKevin Wolf for (n = 0; n < 511; n++) {
1986ff352677SKevin Wolf s->io_buffer[511] += s->io_buffer[n];
1987ff352677SKevin Wolf }
1988ff352677SKevin Wolf s->io_buffer[511] = 0x100 - s->io_buffer[511];
1989ff352677SKevin Wolf
1990ff352677SKevin Wolf s->status = READY_STAT | SEEK_STAT;
1991ff352677SKevin Wolf ide_transfer_start(s, s->io_buffer, 0x200, ide_transfer_stop);
19920cfe719dSPhilippe Mathieu-Daudé ide_bus_set_irq(s->bus);
1993ff352677SKevin Wolf return false;
1994ff352677SKevin Wolf
1995ff352677SKevin Wolf case SMART_READ_LOG:
1996ff352677SKevin Wolf switch (s->sector) {
1997ff352677SKevin Wolf case 0x01: /* summary smart error log */
1998ff352677SKevin Wolf memset(s->io_buffer, 0, 0x200);
1999ff352677SKevin Wolf s->io_buffer[0] = 0x01;
2000ff352677SKevin Wolf s->io_buffer[1] = 0x00; /* no error entries */
2001ff352677SKevin Wolf s->io_buffer[452] = s->smart_errors & 0xff;
2002ff352677SKevin Wolf s->io_buffer[453] = (s->smart_errors & 0xff00) >> 8;
2003ff352677SKevin Wolf
2004ff352677SKevin Wolf for (n = 0; n < 511; n++) {
2005ff352677SKevin Wolf s->io_buffer[511] += s->io_buffer[n];
2006ff352677SKevin Wolf }
2007ff352677SKevin Wolf s->io_buffer[511] = 0x100 - s->io_buffer[511];
2008ff352677SKevin Wolf break;
2009ff352677SKevin Wolf case 0x06: /* smart self test log */
2010ff352677SKevin Wolf memset(s->io_buffer, 0, 0x200);
2011ff352677SKevin Wolf s->io_buffer[0] = 0x01;
2012ff352677SKevin Wolf if (s->smart_selftest_count == 0) {
2013ff352677SKevin Wolf s->io_buffer[508] = 0;
2014ff352677SKevin Wolf } else {
2015ff352677SKevin Wolf s->io_buffer[508] = s->smart_selftest_count;
2016ff352677SKevin Wolf for (n = 2; n < 506; n++) {
2017ff352677SKevin Wolf s->io_buffer[n] = s->smart_selftest_data[n];
2018ff352677SKevin Wolf }
2019ff352677SKevin Wolf }
2020ff352677SKevin Wolf
2021ff352677SKevin Wolf for (n = 0; n < 511; n++) {
2022ff352677SKevin Wolf s->io_buffer[511] += s->io_buffer[n];
2023ff352677SKevin Wolf }
2024ff352677SKevin Wolf s->io_buffer[511] = 0x100 - s->io_buffer[511];
2025ff352677SKevin Wolf break;
2026ff352677SKevin Wolf default:
2027ff352677SKevin Wolf goto abort_cmd;
2028ff352677SKevin Wolf }
2029ff352677SKevin Wolf s->status = READY_STAT | SEEK_STAT;
2030ff352677SKevin Wolf ide_transfer_start(s, s->io_buffer, 0x200, ide_transfer_stop);
20310cfe719dSPhilippe Mathieu-Daudé ide_bus_set_irq(s->bus);
2032ff352677SKevin Wolf return false;
2033ff352677SKevin Wolf
2034ff352677SKevin Wolf case SMART_EXECUTE_OFFLINE:
2035ff352677SKevin Wolf switch (s->sector) {
2036ff352677SKevin Wolf case 0: /* off-line routine */
2037ff352677SKevin Wolf case 1: /* short self test */
2038ff352677SKevin Wolf case 2: /* extended self test */
2039ff352677SKevin Wolf s->smart_selftest_count++;
2040ff352677SKevin Wolf if (s->smart_selftest_count > 21) {
2041940973aeSBenoît Canet s->smart_selftest_count = 1;
2042ff352677SKevin Wolf }
2043ff352677SKevin Wolf n = 2 + (s->smart_selftest_count - 1) * 24;
2044ff352677SKevin Wolf s->smart_selftest_data[n] = s->sector;
2045ff352677SKevin Wolf s->smart_selftest_data[n + 1] = 0x00; /* OK and finished */
2046ff352677SKevin Wolf s->smart_selftest_data[n + 2] = 0x34; /* hour count lsb */
2047ff352677SKevin Wolf s->smart_selftest_data[n + 3] = 0x12; /* hour count msb */
2048ff352677SKevin Wolf break;
2049ff352677SKevin Wolf default:
2050ff352677SKevin Wolf goto abort_cmd;
2051ff352677SKevin Wolf }
2052ff352677SKevin Wolf return true;
2053ff352677SKevin Wolf }
2054ff352677SKevin Wolf
2055ff352677SKevin Wolf abort_cmd:
2056ff352677SKevin Wolf ide_abort_command(s);
2057ff352677SKevin Wolf return true;
2058ff352677SKevin Wolf }
2059ff352677SKevin Wolf
2060844505b1SMarkus Armbruster #define HD_OK (1u << IDE_HD)
2061844505b1SMarkus Armbruster #define CD_OK (1u << IDE_CD)
2062844505b1SMarkus Armbruster #define CFA_OK (1u << IDE_CFATA)
2063844505b1SMarkus Armbruster #define HD_CFA_OK (HD_OK | CFA_OK)
2064844505b1SMarkus Armbruster #define ALL_OK (HD_OK | CD_OK | CFA_OK)
2065844505b1SMarkus Armbruster
2066a0436e92SKevin Wolf /* Set the Disk Seek Completed status bit during completion */
2067a0436e92SKevin Wolf #define SET_DSC (1u << 8)
2068a0436e92SKevin Wolf
2069844505b1SMarkus Armbruster /* See ACS-2 T13/2015-D Table B.2 Command codes */
2070a0436e92SKevin Wolf static const struct {
2071a0436e92SKevin Wolf /* Returns true if the completion code should be run */
2072a0436e92SKevin Wolf bool (*handler)(IDEState *s, uint8_t cmd);
2073a0436e92SKevin Wolf int flags;
2074a0436e92SKevin Wolf } ide_cmd_table[0x100] = {
2075844505b1SMarkus Armbruster /* NOP not implemented, mandatory for CD */
20766b1dd744SKevin Wolf [CFA_REQ_EXT_ERROR_CODE] = { cmd_cfa_req_ext_error_code, CFA_OK },
2077d9033e1dSJohn Snow [WIN_DSM] = { cmd_data_set_management, HD_CFA_OK },
2078ee425c78SKevin Wolf [WIN_DEVICE_RESET] = { cmd_device_reset, CD_OK },
2079b300337eSKevin Wolf [WIN_RECAL] = { cmd_nop, HD_CFA_OK | SET_DSC},
20800e6498edSKevin Wolf [WIN_READ] = { cmd_read_pio, ALL_OK },
2081d9033e1dSJohn Snow [WIN_READ_ONCE] = { cmd_read_pio, HD_CFA_OK },
20820e6498edSKevin Wolf [WIN_READ_EXT] = { cmd_read_pio, HD_CFA_OK },
208392a6a6f6SKevin Wolf [WIN_READDMA_EXT] = { cmd_read_dma, HD_CFA_OK },
208463a82e6aSKevin Wolf [WIN_READ_NATIVE_MAX_EXT] = { cmd_read_native_max, HD_CFA_OK | SET_DSC },
2085adf3a2c4SKevin Wolf [WIN_MULTREAD_EXT] = { cmd_read_multiple, HD_CFA_OK },
20860e6498edSKevin Wolf [WIN_WRITE] = { cmd_write_pio, HD_CFA_OK },
20870e6498edSKevin Wolf [WIN_WRITE_ONCE] = { cmd_write_pio, HD_CFA_OK },
20880e6498edSKevin Wolf [WIN_WRITE_EXT] = { cmd_write_pio, HD_CFA_OK },
208992a6a6f6SKevin Wolf [WIN_WRITEDMA_EXT] = { cmd_write_dma, HD_CFA_OK },
20900e6498edSKevin Wolf [CFA_WRITE_SECT_WO_ERASE] = { cmd_write_pio, CFA_OK },
2091adf3a2c4SKevin Wolf [WIN_MULTWRITE_EXT] = { cmd_write_multiple, HD_CFA_OK },
20920e6498edSKevin Wolf [WIN_WRITE_VERIFY] = { cmd_write_pio, HD_CFA_OK },
2093413860cfSKevin Wolf [WIN_VERIFY] = { cmd_verify, HD_CFA_OK | SET_DSC },
2094413860cfSKevin Wolf [WIN_VERIFY_ONCE] = { cmd_verify, HD_CFA_OK | SET_DSC },
2095413860cfSKevin Wolf [WIN_VERIFY_EXT] = { cmd_verify, HD_CFA_OK | SET_DSC },
209661fdda37SKevin Wolf [WIN_SEEK] = { cmd_seek, HD_CFA_OK | SET_DSC },
20976b1dd744SKevin Wolf [CFA_TRANSLATE_SECTOR] = { cmd_cfa_translate_sector, CFA_OK },
2098ee425c78SKevin Wolf [WIN_DIAGNOSE] = { cmd_exec_dev_diagnostic, ALL_OK },
2099176e4961SLev Kujawski [WIN_SPECIFY] = { cmd_specify, HD_CFA_OK | SET_DSC },
2100d9033e1dSJohn Snow [WIN_STANDBYNOW2] = { cmd_nop, HD_CFA_OK },
2101d9033e1dSJohn Snow [WIN_IDLEIMMEDIATE2] = { cmd_nop, HD_CFA_OK },
2102d9033e1dSJohn Snow [WIN_STANDBY2] = { cmd_nop, HD_CFA_OK },
2103d9033e1dSJohn Snow [WIN_SETIDLE2] = { cmd_nop, HD_CFA_OK },
2104d9033e1dSJohn Snow [WIN_CHECKPOWERMODE2] = { cmd_check_power_mode, HD_CFA_OK | SET_DSC },
2105d9033e1dSJohn Snow [WIN_SLEEPNOW2] = { cmd_nop, HD_CFA_OK },
2106ee425c78SKevin Wolf [WIN_PACKETCMD] = { cmd_packet, CD_OK },
2107ee425c78SKevin Wolf [WIN_PIDENTIFY] = { cmd_identify_packet, CD_OK },
2108ff352677SKevin Wolf [WIN_SMART] = { cmd_smart, HD_CFA_OK | SET_DSC },
21096b1dd744SKevin Wolf [CFA_ACCESS_METADATA_STORAGE] = { cmd_cfa_access_metadata_storage, CFA_OK },
21106b1dd744SKevin Wolf [CFA_ERASE_SECTORS] = { cmd_cfa_erase_sectors, CFA_OK | SET_DSC },
2111adf3a2c4SKevin Wolf [WIN_MULTREAD] = { cmd_read_multiple, HD_CFA_OK },
2112adf3a2c4SKevin Wolf [WIN_MULTWRITE] = { cmd_write_multiple, HD_CFA_OK },
2113adf3a2c4SKevin Wolf [WIN_SETMULT] = { cmd_set_multiple_mode, HD_CFA_OK | SET_DSC },
211492a6a6f6SKevin Wolf [WIN_READDMA] = { cmd_read_dma, HD_CFA_OK },
211592a6a6f6SKevin Wolf [WIN_READDMA_ONCE] = { cmd_read_dma, HD_CFA_OK },
211692a6a6f6SKevin Wolf [WIN_WRITEDMA] = { cmd_write_dma, HD_CFA_OK },
211792a6a6f6SKevin Wolf [WIN_WRITEDMA_ONCE] = { cmd_write_dma, HD_CFA_OK },
2118adf3a2c4SKevin Wolf [CFA_WRITE_MULTI_WO_ERASE] = { cmd_write_multiple, CFA_OK },
2119d9033e1dSJohn Snow [WIN_STANDBYNOW1] = { cmd_nop, HD_CFA_OK },
2120d9033e1dSJohn Snow [WIN_IDLEIMMEDIATE] = { cmd_nop, HD_CFA_OK },
2121d9033e1dSJohn Snow [WIN_STANDBY] = { cmd_nop, HD_CFA_OK },
2122d9033e1dSJohn Snow [WIN_SETIDLE1] = { cmd_nop, HD_CFA_OK },
2123d9033e1dSJohn Snow [WIN_CHECKPOWERMODE1] = { cmd_check_power_mode, HD_CFA_OK | SET_DSC },
2124d9033e1dSJohn Snow [WIN_SLEEPNOW1] = { cmd_nop, HD_CFA_OK },
21259afce429SKevin Wolf [WIN_FLUSH_CACHE] = { cmd_flush_cache, ALL_OK },
21269afce429SKevin Wolf [WIN_FLUSH_CACHE_EXT] = { cmd_flush_cache, HD_CFA_OK },
21271c66869aSKevin Wolf [WIN_IDENTIFY] = { cmd_identify, ALL_OK },
2128ee03398cSKevin Wolf [WIN_SETFEATURES] = { cmd_set_features, ALL_OK | SET_DSC },
21296b1dd744SKevin Wolf [IBM_SENSE_CONDITION] = { cmd_ibm_sense_condition, CFA_OK | SET_DSC },
21306b1dd744SKevin Wolf [CFA_WEAR_LEVEL] = { cmd_cfa_erase_sectors, HD_CFA_OK | SET_DSC },
2131d9033e1dSJohn Snow [WIN_READ_NATIVE_MAX] = { cmd_read_native_max, HD_CFA_OK | SET_DSC },
2132844505b1SMarkus Armbruster };
2133844505b1SMarkus Armbruster
ide_cmd_permitted(IDEState * s,uint32_t cmd)2134844505b1SMarkus Armbruster static bool ide_cmd_permitted(IDEState *s, uint32_t cmd)
2135844505b1SMarkus Armbruster {
2136844505b1SMarkus Armbruster return cmd < ARRAY_SIZE(ide_cmd_table)
2137a0436e92SKevin Wolf && (ide_cmd_table[cmd].flags & (1u << s->drive_kind));
2138844505b1SMarkus Armbruster }
21397cff87ffSAlexander Graf
ide_bus_exec_cmd(IDEBus * bus,uint32_t val)2140783f4474SPhilippe Mathieu-Daudé void ide_bus_exec_cmd(IDEBus *bus, uint32_t val)
21417cff87ffSAlexander Graf {
21427cff87ffSAlexander Graf IDEState *s;
2143dfe1ea8fSKevin Wolf bool complete;
21447cff87ffSAlexander Graf
21452c50207fSPhilippe Mathieu-Daudé s = ide_bus_active_if(bus);
2146783f4474SPhilippe Mathieu-Daudé trace_ide_bus_exec_cmd(bus, s, val);
21473eee2611SJohn Snow
214866a0a2cbSDong Xu Wang /* ignore commands to non existent slave */
21494be74634SMarkus Armbruster if (s != bus->ifs && !s->blk) {
21507cff87ffSAlexander Graf return;
21514be74634SMarkus Armbruster }
215259f2a787SGerd Hoffmann
2153266e7781SJohn Snow /* Only RESET is allowed while BSY and/or DRQ are set,
2154266e7781SJohn Snow * and only to ATAPI devices. */
2155266e7781SJohn Snow if (s->status & (BUSY_STAT|DRQ_STAT)) {
2156266e7781SJohn Snow if (val != WIN_DEVICE_RESET || s->drive_kind != IDE_CD) {
21577cff87ffSAlexander Graf return;
2158266e7781SJohn Snow }
2159266e7781SJohn Snow }
216059f2a787SGerd Hoffmann
2161844505b1SMarkus Armbruster if (!ide_cmd_permitted(s, val)) {
2162dfe1ea8fSKevin Wolf ide_abort_command(s);
21630cfe719dSPhilippe Mathieu-Daudé ide_bus_set_irq(s->bus);
2164dfe1ea8fSKevin Wolf return;
2165844505b1SMarkus Armbruster }
2166844505b1SMarkus Armbruster
2167a0436e92SKevin Wolf s->status = READY_STAT | BUSY_STAT;
2168a0436e92SKevin Wolf s->error = 0;
216936334fafSJohn Snow s->io_buffer_offset = 0;
2170a0436e92SKevin Wolf
2171a0436e92SKevin Wolf complete = ide_cmd_table[val].handler(s, val);
2172a0436e92SKevin Wolf if (complete) {
2173a0436e92SKevin Wolf s->status &= ~BUSY_STAT;
2174a0436e92SKevin Wolf assert(!!s->error == !!(s->status & ERR_STAT));
2175a0436e92SKevin Wolf
2176a0436e92SKevin Wolf if ((ide_cmd_table[val].flags & SET_DSC) && !s->error) {
2177a0436e92SKevin Wolf s->status |= SEEK_STAT;
2178a0436e92SKevin Wolf }
2179a0436e92SKevin Wolf
2180c7e73adbSPaolo Bonzini ide_cmd_done(s);
21810cfe719dSPhilippe Mathieu-Daudé ide_bus_set_irq(s->bus);
2182a0436e92SKevin Wolf }
218359f2a787SGerd Hoffmann }
218459f2a787SGerd Hoffmann
2185335ca2f2SJohn Snow /* IOport [R]ead [R]egisters */
2186335ca2f2SJohn Snow enum ATA_IOPORT_RR {
2187335ca2f2SJohn Snow ATA_IOPORT_RR_DATA = 0,
2188335ca2f2SJohn Snow ATA_IOPORT_RR_ERROR = 1,
2189335ca2f2SJohn Snow ATA_IOPORT_RR_SECTOR_COUNT = 2,
2190335ca2f2SJohn Snow ATA_IOPORT_RR_SECTOR_NUMBER = 3,
2191335ca2f2SJohn Snow ATA_IOPORT_RR_CYLINDER_LOW = 4,
2192335ca2f2SJohn Snow ATA_IOPORT_RR_CYLINDER_HIGH = 5,
2193335ca2f2SJohn Snow ATA_IOPORT_RR_DEVICE_HEAD = 6,
2194335ca2f2SJohn Snow ATA_IOPORT_RR_STATUS = 7,
2195335ca2f2SJohn Snow ATA_IOPORT_RR_NUM_REGISTERS,
2196335ca2f2SJohn Snow };
2197335ca2f2SJohn Snow
2198335ca2f2SJohn Snow const char *ATA_IOPORT_RR_lookup[ATA_IOPORT_RR_NUM_REGISTERS] = {
2199335ca2f2SJohn Snow [ATA_IOPORT_RR_DATA] = "Data",
2200335ca2f2SJohn Snow [ATA_IOPORT_RR_ERROR] = "Error",
2201335ca2f2SJohn Snow [ATA_IOPORT_RR_SECTOR_COUNT] = "Sector Count",
2202335ca2f2SJohn Snow [ATA_IOPORT_RR_SECTOR_NUMBER] = "Sector Number",
2203335ca2f2SJohn Snow [ATA_IOPORT_RR_CYLINDER_LOW] = "Cylinder Low",
2204335ca2f2SJohn Snow [ATA_IOPORT_RR_CYLINDER_HIGH] = "Cylinder High",
2205335ca2f2SJohn Snow [ATA_IOPORT_RR_DEVICE_HEAD] = "Device/Head",
2206335ca2f2SJohn Snow [ATA_IOPORT_RR_STATUS] = "Status"
2207335ca2f2SJohn Snow };
2208335ca2f2SJohn Snow
ide_ioport_read(void * opaque,uint32_t addr)22093eee2611SJohn Snow uint32_t ide_ioport_read(void *opaque, uint32_t addr)
221059f2a787SGerd Hoffmann {
221159f2a787SGerd Hoffmann IDEBus *bus = opaque;
22122c50207fSPhilippe Mathieu-Daudé IDEState *s = ide_bus_active_if(bus);
22133eee2611SJohn Snow uint32_t reg_num;
221459f2a787SGerd Hoffmann int ret, hob;
221559f2a787SGerd Hoffmann
22163eee2611SJohn Snow reg_num = addr & 7;
2217be8c9423SJohn Snow hob = bus->cmd & (IDE_CTRL_HOB);
22183eee2611SJohn Snow switch (reg_num) {
2219335ca2f2SJohn Snow case ATA_IOPORT_RR_DATA:
2220758c925eSLev Kujawski /*
2221758c925eSLev Kujawski * The pre-GRUB Solaris x86 bootloader relies upon inb
2222758c925eSLev Kujawski * consuming a word from the drive's sector buffer.
2223758c925eSLev Kujawski */
2224758c925eSLev Kujawski ret = ide_data_readw(bus, addr) & 0xff;
222559f2a787SGerd Hoffmann break;
2226335ca2f2SJohn Snow case ATA_IOPORT_RR_ERROR:
22274be74634SMarkus Armbruster if ((!bus->ifs[0].blk && !bus->ifs[1].blk) ||
22284be74634SMarkus Armbruster (s != bus->ifs && !s->blk)) {
222959f2a787SGerd Hoffmann ret = 0;
22304be74634SMarkus Armbruster } else if (!hob) {
223159f2a787SGerd Hoffmann ret = s->error;
22324be74634SMarkus Armbruster } else {
223359f2a787SGerd Hoffmann ret = s->hob_feature;
22344be74634SMarkus Armbruster }
223559f2a787SGerd Hoffmann break;
2236335ca2f2SJohn Snow case ATA_IOPORT_RR_SECTOR_COUNT:
22374be74634SMarkus Armbruster if (!bus->ifs[0].blk && !bus->ifs[1].blk) {
223859f2a787SGerd Hoffmann ret = 0;
22394be74634SMarkus Armbruster } else if (!hob) {
224059f2a787SGerd Hoffmann ret = s->nsector & 0xff;
22414be74634SMarkus Armbruster } else {
224259f2a787SGerd Hoffmann ret = s->hob_nsector;
22434be74634SMarkus Armbruster }
224459f2a787SGerd Hoffmann break;
2245335ca2f2SJohn Snow case ATA_IOPORT_RR_SECTOR_NUMBER:
22464be74634SMarkus Armbruster if (!bus->ifs[0].blk && !bus->ifs[1].blk) {
224759f2a787SGerd Hoffmann ret = 0;
22484be74634SMarkus Armbruster } else if (!hob) {
224959f2a787SGerd Hoffmann ret = s->sector;
22504be74634SMarkus Armbruster } else {
225159f2a787SGerd Hoffmann ret = s->hob_sector;
22524be74634SMarkus Armbruster }
225359f2a787SGerd Hoffmann break;
2254335ca2f2SJohn Snow case ATA_IOPORT_RR_CYLINDER_LOW:
22554be74634SMarkus Armbruster if (!bus->ifs[0].blk && !bus->ifs[1].blk) {
225659f2a787SGerd Hoffmann ret = 0;
22574be74634SMarkus Armbruster } else if (!hob) {
225859f2a787SGerd Hoffmann ret = s->lcyl;
22594be74634SMarkus Armbruster } else {
226059f2a787SGerd Hoffmann ret = s->hob_lcyl;
22614be74634SMarkus Armbruster }
226259f2a787SGerd Hoffmann break;
2263335ca2f2SJohn Snow case ATA_IOPORT_RR_CYLINDER_HIGH:
22644be74634SMarkus Armbruster if (!bus->ifs[0].blk && !bus->ifs[1].blk) {
226559f2a787SGerd Hoffmann ret = 0;
22664be74634SMarkus Armbruster } else if (!hob) {
226759f2a787SGerd Hoffmann ret = s->hcyl;
22684be74634SMarkus Armbruster } else {
226959f2a787SGerd Hoffmann ret = s->hob_hcyl;
22704be74634SMarkus Armbruster }
227159f2a787SGerd Hoffmann break;
2272335ca2f2SJohn Snow case ATA_IOPORT_RR_DEVICE_HEAD:
22734be74634SMarkus Armbruster if (!bus->ifs[0].blk && !bus->ifs[1].blk) {
227459f2a787SGerd Hoffmann ret = 0;
22754be74634SMarkus Armbruster } else {
227659f2a787SGerd Hoffmann ret = s->select;
22774be74634SMarkus Armbruster }
227859f2a787SGerd Hoffmann break;
227959f2a787SGerd Hoffmann default:
2280335ca2f2SJohn Snow case ATA_IOPORT_RR_STATUS:
22814be74634SMarkus Armbruster if ((!bus->ifs[0].blk && !bus->ifs[1].blk) ||
22824be74634SMarkus Armbruster (s != bus->ifs && !s->blk)) {
228359f2a787SGerd Hoffmann ret = 0;
22844be74634SMarkus Armbruster } else {
228559f2a787SGerd Hoffmann ret = s->status;
22864be74634SMarkus Armbruster }
22879cdd03a7SGerd Hoffmann qemu_irq_lower(bus->irq);
228859f2a787SGerd Hoffmann break;
228959f2a787SGerd Hoffmann }
22903eee2611SJohn Snow
2291335ca2f2SJohn Snow trace_ide_ioport_read(addr, ATA_IOPORT_RR_lookup[reg_num], ret, bus, s);
229259f2a787SGerd Hoffmann return ret;
229359f2a787SGerd Hoffmann }
229459f2a787SGerd Hoffmann
ide_status_read(void * opaque,uint32_t addr)229559f2a787SGerd Hoffmann uint32_t ide_status_read(void *opaque, uint32_t addr)
229659f2a787SGerd Hoffmann {
229759f2a787SGerd Hoffmann IDEBus *bus = opaque;
22982c50207fSPhilippe Mathieu-Daudé IDEState *s = ide_bus_active_if(bus);
229959f2a787SGerd Hoffmann int ret;
230059f2a787SGerd Hoffmann
23014be74634SMarkus Armbruster if ((!bus->ifs[0].blk && !bus->ifs[1].blk) ||
23024be74634SMarkus Armbruster (s != bus->ifs && !s->blk)) {
230359f2a787SGerd Hoffmann ret = 0;
23044be74634SMarkus Armbruster } else {
230559f2a787SGerd Hoffmann ret = s->status;
23064be74634SMarkus Armbruster }
23073eee2611SJohn Snow
23083eee2611SJohn Snow trace_ide_status_read(addr, ret, bus, s);
230959f2a787SGerd Hoffmann return ret;
231059f2a787SGerd Hoffmann }
231159f2a787SGerd Hoffmann
ide_perform_srst(IDEState * s)231255adb3c4SJohn Snow static void ide_perform_srst(IDEState *s)
231355adb3c4SJohn Snow {
231455adb3c4SJohn Snow s->status |= BUSY_STAT;
231555adb3c4SJohn Snow
231655adb3c4SJohn Snow /* Halt PIO (Via register state); PIO BH remains scheduled. */
231755adb3c4SJohn Snow ide_transfer_halt(s);
231855adb3c4SJohn Snow
231955adb3c4SJohn Snow /* Cancel DMA -- may drain block device and invoke callbacks */
232055adb3c4SJohn Snow ide_cancel_dma_sync(s);
232155adb3c4SJohn Snow
232255adb3c4SJohn Snow /* Cancel PIO callback, reset registers/signature, etc */
232355adb3c4SJohn Snow ide_reset(s);
232455adb3c4SJohn Snow
23254ac4e728SJohn Snow /* perform diagnostic */
23264ac4e728SJohn Snow cmd_exec_dev_diagnostic(s, WIN_DIAGNOSE);
232755adb3c4SJohn Snow }
232855adb3c4SJohn Snow
ide_bus_perform_srst(void * opaque)232955adb3c4SJohn Snow static void ide_bus_perform_srst(void *opaque)
233055adb3c4SJohn Snow {
233155adb3c4SJohn Snow IDEBus *bus = opaque;
233255adb3c4SJohn Snow IDEState *s;
233355adb3c4SJohn Snow int i;
233455adb3c4SJohn Snow
233555adb3c4SJohn Snow for (i = 0; i < 2; i++) {
233655adb3c4SJohn Snow s = &bus->ifs[i];
233755adb3c4SJohn Snow ide_perform_srst(s);
233855adb3c4SJohn Snow }
23391a9925e3SJohn Snow
23401a9925e3SJohn Snow bus->cmd &= ~IDE_CTRL_RESET;
234155adb3c4SJohn Snow }
234255adb3c4SJohn Snow
ide_ctrl_write(void * opaque,uint32_t addr,uint32_t val)234398d98912SJohn Snow void ide_ctrl_write(void *opaque, uint32_t addr, uint32_t val)
234459f2a787SGerd Hoffmann {
234559f2a787SGerd Hoffmann IDEBus *bus = opaque;
234659f2a787SGerd Hoffmann IDEState *s;
234759f2a787SGerd Hoffmann int i;
234859f2a787SGerd Hoffmann
234998d98912SJohn Snow trace_ide_ctrl_write(addr, val, bus);
23503eee2611SJohn Snow
235155adb3c4SJohn Snow /* Device0 and Device1 each have their own control register,
235255adb3c4SJohn Snow * but QEMU models it as just one register in the controller. */
2353b45bcd81SJohn Snow if (!(bus->cmd & IDE_CTRL_RESET) && (val & IDE_CTRL_RESET)) {
235459f2a787SGerd Hoffmann for (i = 0; i < 2; i++) {
235559f2a787SGerd Hoffmann s = &bus->ifs[i];
235655adb3c4SJohn Snow s->status |= BUSY_STAT;
235759f2a787SGerd Hoffmann }
2358de00b8b3SAlex Bennée replay_bh_schedule_oneshot_event(qemu_get_aio_context(),
235955adb3c4SJohn Snow ide_bus_perform_srst, bus);
236059f2a787SGerd Hoffmann }
236159f2a787SGerd Hoffmann
23629cdd03a7SGerd Hoffmann bus->cmd = val;
236359f2a787SGerd Hoffmann }
236459f2a787SGerd Hoffmann
236540c4ed3fSKevin Wolf /*
236640c4ed3fSKevin Wolf * Returns true if the running PIO transfer is a PIO out (i.e. data is
236740c4ed3fSKevin Wolf * transferred from the device to the guest), false if it's a PIO in
236840c4ed3fSKevin Wolf */
ide_is_pio_out(IDEState * s)236940c4ed3fSKevin Wolf static bool ide_is_pio_out(IDEState *s)
237040c4ed3fSKevin Wolf {
237140c4ed3fSKevin Wolf if (s->end_transfer_func == ide_sector_write ||
237240c4ed3fSKevin Wolf s->end_transfer_func == ide_atapi_cmd) {
237340c4ed3fSKevin Wolf return false;
237440c4ed3fSKevin Wolf } else if (s->end_transfer_func == ide_sector_read ||
237540c4ed3fSKevin Wolf s->end_transfer_func == ide_transfer_stop ||
237640c4ed3fSKevin Wolf s->end_transfer_func == ide_atapi_cmd_reply_end ||
237740c4ed3fSKevin Wolf s->end_transfer_func == ide_dummy_transfer_stop) {
237840c4ed3fSKevin Wolf return true;
237940c4ed3fSKevin Wolf }
238040c4ed3fSKevin Wolf
238140c4ed3fSKevin Wolf abort();
238240c4ed3fSKevin Wolf }
238340c4ed3fSKevin Wolf
ide_data_writew(void * opaque,uint32_t addr,uint32_t val)238459f2a787SGerd Hoffmann void ide_data_writew(void *opaque, uint32_t addr, uint32_t val)
238559f2a787SGerd Hoffmann {
238659f2a787SGerd Hoffmann IDEBus *bus = opaque;
23872c50207fSPhilippe Mathieu-Daudé IDEState *s = ide_bus_active_if(bus);
238859f2a787SGerd Hoffmann uint8_t *p;
238959f2a787SGerd Hoffmann
23901787efc3SJohn Snow trace_ide_data_writew(addr, val, bus, s);
23911787efc3SJohn Snow
239240c4ed3fSKevin Wolf /* PIO data access allowed only when DRQ bit is set. The result of a write
239340c4ed3fSKevin Wolf * during PIO out is indeterminate, just ignore it. */
239440c4ed3fSKevin Wolf if (!(s->status & DRQ_STAT) || ide_is_pio_out(s)) {
239559f2a787SGerd Hoffmann return;
239640c4ed3fSKevin Wolf }
239759f2a787SGerd Hoffmann
239859f2a787SGerd Hoffmann p = s->data_ptr;
23991ea17d22SLubomir Rintel if (s->io8) {
24001ea17d22SLubomir Rintel if (p + 1 > s->data_end) {
24011ea17d22SLubomir Rintel return;
24021ea17d22SLubomir Rintel }
24031ea17d22SLubomir Rintel
24041ea17d22SLubomir Rintel *p++ = val;
24051ea17d22SLubomir Rintel } else {
2406d2ff8585SKevin Wolf if (p + 2 > s->data_end) {
2407d2ff8585SKevin Wolf return;
2408d2ff8585SKevin Wolf }
2409d2ff8585SKevin Wolf
241059f2a787SGerd Hoffmann *(uint16_t *)p = le16_to_cpu(val);
241159f2a787SGerd Hoffmann p += 2;
24121ea17d22SLubomir Rintel }
241359f2a787SGerd Hoffmann s->data_ptr = p;
2414cb72cba8SKevin Wolf if (p >= s->data_end) {
2415cb72cba8SKevin Wolf s->status &= ~DRQ_STAT;
241659f2a787SGerd Hoffmann s->end_transfer_func(s);
241759f2a787SGerd Hoffmann }
2418cb72cba8SKevin Wolf }
241959f2a787SGerd Hoffmann
ide_data_readw(void * opaque,uint32_t addr)242059f2a787SGerd Hoffmann uint32_t ide_data_readw(void *opaque, uint32_t addr)
242159f2a787SGerd Hoffmann {
242259f2a787SGerd Hoffmann IDEBus *bus = opaque;
24232c50207fSPhilippe Mathieu-Daudé IDEState *s = ide_bus_active_if(bus);
242459f2a787SGerd Hoffmann uint8_t *p;
242559f2a787SGerd Hoffmann int ret;
242659f2a787SGerd Hoffmann
242740c4ed3fSKevin Wolf /* PIO data access allowed only when DRQ bit is set. The result of a read
242840c4ed3fSKevin Wolf * during PIO in is indeterminate, return 0 and don't move forward. */
242940c4ed3fSKevin Wolf if (!(s->status & DRQ_STAT) || !ide_is_pio_out(s)) {
243059f2a787SGerd Hoffmann return 0;
243140c4ed3fSKevin Wolf }
243259f2a787SGerd Hoffmann
243359f2a787SGerd Hoffmann p = s->data_ptr;
24341ea17d22SLubomir Rintel if (s->io8) {
24351ea17d22SLubomir Rintel if (p + 1 > s->data_end) {
24361ea17d22SLubomir Rintel return 0;
24371ea17d22SLubomir Rintel }
24381ea17d22SLubomir Rintel
24391ea17d22SLubomir Rintel ret = *p++;
24401ea17d22SLubomir Rintel } else {
2441d2ff8585SKevin Wolf if (p + 2 > s->data_end) {
2442d2ff8585SKevin Wolf return 0;
2443d2ff8585SKevin Wolf }
2444d2ff8585SKevin Wolf
244559f2a787SGerd Hoffmann ret = cpu_to_le16(*(uint16_t *)p);
244659f2a787SGerd Hoffmann p += 2;
24471ea17d22SLubomir Rintel }
244859f2a787SGerd Hoffmann s->data_ptr = p;
2449cb72cba8SKevin Wolf if (p >= s->data_end) {
2450cb72cba8SKevin Wolf s->status &= ~DRQ_STAT;
245159f2a787SGerd Hoffmann s->end_transfer_func(s);
2452cb72cba8SKevin Wolf }
24531787efc3SJohn Snow
24541787efc3SJohn Snow trace_ide_data_readw(addr, ret, bus, s);
245559f2a787SGerd Hoffmann return ret;
245659f2a787SGerd Hoffmann }
245759f2a787SGerd Hoffmann
ide_data_writel(void * opaque,uint32_t addr,uint32_t val)245859f2a787SGerd Hoffmann void ide_data_writel(void *opaque, uint32_t addr, uint32_t val)
245959f2a787SGerd Hoffmann {
246059f2a787SGerd Hoffmann IDEBus *bus = opaque;
24612c50207fSPhilippe Mathieu-Daudé IDEState *s = ide_bus_active_if(bus);
246259f2a787SGerd Hoffmann uint8_t *p;
246359f2a787SGerd Hoffmann
24641787efc3SJohn Snow trace_ide_data_writel(addr, val, bus, s);
24651787efc3SJohn Snow
246640c4ed3fSKevin Wolf /* PIO data access allowed only when DRQ bit is set. The result of a write
246740c4ed3fSKevin Wolf * during PIO out is indeterminate, just ignore it. */
246840c4ed3fSKevin Wolf if (!(s->status & DRQ_STAT) || ide_is_pio_out(s)) {
246959f2a787SGerd Hoffmann return;
247040c4ed3fSKevin Wolf }
247159f2a787SGerd Hoffmann
247259f2a787SGerd Hoffmann p = s->data_ptr;
2473d2ff8585SKevin Wolf if (p + 4 > s->data_end) {
2474d2ff8585SKevin Wolf return;
2475d2ff8585SKevin Wolf }
2476d2ff8585SKevin Wolf
247759f2a787SGerd Hoffmann *(uint32_t *)p = le32_to_cpu(val);
247859f2a787SGerd Hoffmann p += 4;
247959f2a787SGerd Hoffmann s->data_ptr = p;
2480cb72cba8SKevin Wolf if (p >= s->data_end) {
2481cb72cba8SKevin Wolf s->status &= ~DRQ_STAT;
248259f2a787SGerd Hoffmann s->end_transfer_func(s);
248359f2a787SGerd Hoffmann }
2484cb72cba8SKevin Wolf }
248559f2a787SGerd Hoffmann
ide_data_readl(void * opaque,uint32_t addr)248659f2a787SGerd Hoffmann uint32_t ide_data_readl(void *opaque, uint32_t addr)
248759f2a787SGerd Hoffmann {
248859f2a787SGerd Hoffmann IDEBus *bus = opaque;
24892c50207fSPhilippe Mathieu-Daudé IDEState *s = ide_bus_active_if(bus);
249059f2a787SGerd Hoffmann uint8_t *p;
249159f2a787SGerd Hoffmann int ret;
249259f2a787SGerd Hoffmann
249340c4ed3fSKevin Wolf /* PIO data access allowed only when DRQ bit is set. The result of a read
249440c4ed3fSKevin Wolf * during PIO in is indeterminate, return 0 and don't move forward. */
249540c4ed3fSKevin Wolf if (!(s->status & DRQ_STAT) || !ide_is_pio_out(s)) {
24961787efc3SJohn Snow ret = 0;
24971787efc3SJohn Snow goto out;
249840c4ed3fSKevin Wolf }
249959f2a787SGerd Hoffmann
250059f2a787SGerd Hoffmann p = s->data_ptr;
2501d2ff8585SKevin Wolf if (p + 4 > s->data_end) {
2502d2ff8585SKevin Wolf return 0;
2503d2ff8585SKevin Wolf }
2504d2ff8585SKevin Wolf
250559f2a787SGerd Hoffmann ret = cpu_to_le32(*(uint32_t *)p);
250659f2a787SGerd Hoffmann p += 4;
250759f2a787SGerd Hoffmann s->data_ptr = p;
2508cb72cba8SKevin Wolf if (p >= s->data_end) {
2509cb72cba8SKevin Wolf s->status &= ~DRQ_STAT;
251059f2a787SGerd Hoffmann s->end_transfer_func(s);
2511cb72cba8SKevin Wolf }
25121787efc3SJohn Snow
25131787efc3SJohn Snow out:
25141787efc3SJohn Snow trace_ide_data_readl(addr, ret, bus, s);
251559f2a787SGerd Hoffmann return ret;
251659f2a787SGerd Hoffmann }
251759f2a787SGerd Hoffmann
ide_dummy_transfer_stop(IDEState * s)251859f2a787SGerd Hoffmann static void ide_dummy_transfer_stop(IDEState *s)
251959f2a787SGerd Hoffmann {
252059f2a787SGerd Hoffmann s->data_ptr = s->io_buffer;
252159f2a787SGerd Hoffmann s->data_end = s->io_buffer;
252259f2a787SGerd Hoffmann s->io_buffer[0] = 0xff;
252359f2a787SGerd Hoffmann s->io_buffer[1] = 0xff;
252459f2a787SGerd Hoffmann s->io_buffer[2] = 0xff;
252559f2a787SGerd Hoffmann s->io_buffer[3] = 0xff;
252659f2a787SGerd Hoffmann }
252759f2a787SGerd Hoffmann
ide_bus_reset(IDEBus * bus)25284a643563SBlue Swirl void ide_bus_reset(IDEBus *bus)
25294a643563SBlue Swirl {
25307d751201SFiona Ebner /* pending async DMA - needs the IDEState before it is reset */
253140a6238aSAlexander Graf if (bus->dma->aiocb) {
25320e168d35SJohn Snow trace_ide_bus_reset_aio();
25334be74634SMarkus Armbruster blk_aio_cancel(bus->dma->aiocb);
253440a6238aSAlexander Graf bus->dma->aiocb = NULL;
253540a6238aSAlexander Graf }
253640a6238aSAlexander Graf
25377d751201SFiona Ebner bus->unit = 0;
25387d751201SFiona Ebner bus->cmd = 0;
25397d751201SFiona Ebner ide_reset(&bus->ifs[0]);
25407d751201SFiona Ebner ide_reset(&bus->ifs[1]);
25417d751201SFiona Ebner ide_clear_hob(bus);
25427d751201SFiona Ebner
254340a6238aSAlexander Graf /* reset dma provider too */
25441374bec0SPaolo Bonzini if (bus->dma->ops->reset) {
254540a6238aSAlexander Graf bus->dma->ops->reset(bus->dma);
25464a643563SBlue Swirl }
25471374bec0SPaolo Bonzini }
25484a643563SBlue Swirl
ide_cd_is_tray_open(void * opaque)2549e4def80bSMarkus Armbruster static bool ide_cd_is_tray_open(void *opaque)
2550e4def80bSMarkus Armbruster {
2551e4def80bSMarkus Armbruster return ((IDEState *)opaque)->tray_open;
2552e4def80bSMarkus Armbruster }
2553e4def80bSMarkus Armbruster
ide_cd_is_medium_locked(void * opaque)2554f107639aSMarkus Armbruster static bool ide_cd_is_medium_locked(void *opaque)
2555f107639aSMarkus Armbruster {
2556f107639aSMarkus Armbruster return ((IDEState *)opaque)->tray_locked;
2557f107639aSMarkus Armbruster }
2558f107639aSMarkus Armbruster
ide_resize_cb(void * opaque)255901ce352eSJohn Snow static void ide_resize_cb(void *opaque)
256001ce352eSJohn Snow {
256101ce352eSJohn Snow IDEState *s = opaque;
256201ce352eSJohn Snow uint64_t nb_sectors;
256301ce352eSJohn Snow
256401ce352eSJohn Snow if (!s->identify_set) {
256501ce352eSJohn Snow return;
256601ce352eSJohn Snow }
256701ce352eSJohn Snow
25684be74634SMarkus Armbruster blk_get_geometry(s->blk, &nb_sectors);
256901ce352eSJohn Snow s->nb_sectors = nb_sectors;
257001ce352eSJohn Snow
257101ce352eSJohn Snow /* Update the identify data buffer. */
257201ce352eSJohn Snow if (s->drive_kind == IDE_CFATA) {
257301ce352eSJohn Snow ide_cfata_identify_size(s);
257401ce352eSJohn Snow } else {
257501ce352eSJohn Snow /* IDE_CD uses a different set of callbacks entirely. */
257601ce352eSJohn Snow assert(s->drive_kind != IDE_CD);
257701ce352eSJohn Snow ide_identify_size(s);
257801ce352eSJohn Snow }
257901ce352eSJohn Snow }
258001ce352eSJohn Snow
25810e49de52SMarkus Armbruster static const BlockDevOps ide_cd_block_ops = {
2582145feb17SMarkus Armbruster .change_media_cb = ide_cd_change_cb,
25832df0a3a3SPaolo Bonzini .eject_request_cb = ide_cd_eject_request_cb,
2584e4def80bSMarkus Armbruster .is_tray_open = ide_cd_is_tray_open,
2585f107639aSMarkus Armbruster .is_medium_locked = ide_cd_is_medium_locked,
25860e49de52SMarkus Armbruster };
25870e49de52SMarkus Armbruster
258801ce352eSJohn Snow static const BlockDevOps ide_hd_block_ops = {
258901ce352eSJohn Snow .resize_cb = ide_resize_cb,
259001ce352eSJohn Snow };
259101ce352eSJohn Snow
ide_init_drive(IDEState * s,BlockBackend * blk,IDEDriveKind kind,const char * version,const char * serial,const char * model,uint64_t wwn,uint32_t cylinders,uint32_t heads,uint32_t secs,int chs_trans,Error ** errp)25924be74634SMarkus Armbruster int ide_init_drive(IDEState *s, BlockBackend *blk, IDEDriveKind kind,
259395ebda85SFloris Bos const char *version, const char *serial, const char *model,
2594ba801960SMarkus Armbruster uint64_t wwn,
2595ba801960SMarkus Armbruster uint32_t cylinders, uint32_t heads, uint32_t secs,
2596794939e8SMao Zhongyi int chs_trans, Error **errp)
259759f2a787SGerd Hoffmann {
259859f2a787SGerd Hoffmann uint64_t nb_sectors;
259959f2a787SGerd Hoffmann
26004be74634SMarkus Armbruster s->blk = blk;
26011f56e32aSMarkus Armbruster s->drive_kind = kind;
26021f56e32aSMarkus Armbruster
26034be74634SMarkus Armbruster blk_get_geometry(blk, &nb_sectors);
260459f2a787SGerd Hoffmann s->cylinders = cylinders;
2605176e4961SLev Kujawski s->heads = s->drive_heads = heads;
2606176e4961SLev Kujawski s->sectors = s->drive_sectors = secs;
2607ba801960SMarkus Armbruster s->chs_trans = chs_trans;
260859f2a787SGerd Hoffmann s->nb_sectors = nb_sectors;
260995ebda85SFloris Bos s->wwn = wwn;
261059f2a787SGerd Hoffmann /* The SMART values should be preserved across power cycles
261159f2a787SGerd Hoffmann but they aren't. */
261259f2a787SGerd Hoffmann s->smart_enabled = 1;
261359f2a787SGerd Hoffmann s->smart_autosave = 1;
261459f2a787SGerd Hoffmann s->smart_errors = 0;
261559f2a787SGerd Hoffmann s->smart_selftest_count = 0;
26161f56e32aSMarkus Armbruster if (kind == IDE_CD) {
26174be74634SMarkus Armbruster blk_set_dev_ops(blk, &ide_cd_block_ops, s);
26187aa9c811SMarkus Armbruster } else {
26194be74634SMarkus Armbruster if (!blk_is_inserted(s->blk)) {
2620794939e8SMao Zhongyi error_setg(errp, "Device needs media, but drive is empty");
262198f28ad7SMarkus Armbruster return -1;
262298f28ad7SMarkus Armbruster }
262386b1cf32SKevin Wolf if (!blk_is_writable(blk)) {
2624794939e8SMao Zhongyi error_setg(errp, "Can't use a read-only drive");
26257aa9c811SMarkus Armbruster return -1;
26267aa9c811SMarkus Armbruster }
26274be74634SMarkus Armbruster blk_set_dev_ops(blk, &ide_hd_block_ops, s);
262859f2a787SGerd Hoffmann }
2629f8b6cc00SMarkus Armbruster if (serial) {
2630aa2c91bdSFloris Bos pstrcpy(s->drive_serial_str, sizeof(s->drive_serial_str), serial);
26316ced55a5SMarkus Armbruster } else {
263259f2a787SGerd Hoffmann snprintf(s->drive_serial_str, sizeof(s->drive_serial_str),
263359f2a787SGerd Hoffmann "QM%05d", s->drive_serial);
2634870111c8SMarkus Armbruster }
263527e0c9a1SFloris Bos if (model) {
263627e0c9a1SFloris Bos pstrcpy(s->drive_model_str, sizeof(s->drive_model_str), model);
263727e0c9a1SFloris Bos } else {
263827e0c9a1SFloris Bos switch (kind) {
263927e0c9a1SFloris Bos case IDE_CD:
264027e0c9a1SFloris Bos strcpy(s->drive_model_str, "QEMU DVD-ROM");
264127e0c9a1SFloris Bos break;
264227e0c9a1SFloris Bos case IDE_CFATA:
264327e0c9a1SFloris Bos strcpy(s->drive_model_str, "QEMU MICRODRIVE");
264427e0c9a1SFloris Bos break;
264527e0c9a1SFloris Bos default:
264627e0c9a1SFloris Bos strcpy(s->drive_model_str, "QEMU HARDDISK");
264727e0c9a1SFloris Bos break;
264827e0c9a1SFloris Bos }
264927e0c9a1SFloris Bos }
265027e0c9a1SFloris Bos
265147c06340SGerd Hoffmann if (version) {
265247c06340SGerd Hoffmann pstrcpy(s->version, sizeof(s->version), version);
265347c06340SGerd Hoffmann } else {
265435c2c8dcSEduardo Habkost pstrcpy(s->version, sizeof(s->version), qemu_hw_version());
265547c06340SGerd Hoffmann }
265640a6238aSAlexander Graf
265788804180SGerd Hoffmann ide_reset(s);
26584be74634SMarkus Armbruster blk_iostatus_enable(blk);
2659c4d74df7SMarkus Armbruster return 0;
266088804180SGerd Hoffmann }
266188804180SGerd Hoffmann
ide_init1(IDEBus * bus,int unit)266257234ee4SMarkus Armbruster static void ide_init1(IDEBus *bus, int unit)
266388804180SGerd Hoffmann {
266488804180SGerd Hoffmann static int drive_serial = 1;
2665d459da0eSMarkus Armbruster IDEState *s = &bus->ifs[unit];
266688804180SGerd Hoffmann
266788804180SGerd Hoffmann s->bus = bus;
2668d459da0eSMarkus Armbruster s->unit = unit;
266988804180SGerd Hoffmann s->drive_serial = drive_serial++;
26701b2adf28SChristoph Hellwig /* we need at least 2k alignment for accessing CDROMs using O_DIRECT */
267150641c5cSJuan Quintela s->io_buffer_total_len = IDE_DMA_BUF_SECTORS*512 + 4;
2672c925400bSKevin Wolf s->io_buffer = qemu_memalign(2048, s->io_buffer_total_len);
2673c925400bSKevin Wolf memset(s->io_buffer, 0, s->io_buffer_total_len);
2674c925400bSKevin Wolf
26754be74634SMarkus Armbruster s->smart_selftest_data = blk_blockalign(s->blk, 512);
2676c925400bSKevin Wolf memset(s->smart_selftest_data, 0, 512);
2677c925400bSKevin Wolf
2678bc72ad67SAlex Bligh s->sector_write_timer = timer_new_ns(QEMU_CLOCK_VIRTUAL,
267959f2a787SGerd Hoffmann ide_sector_write_timer_cb, s);
2680d459da0eSMarkus Armbruster }
2681d459da0eSMarkus Armbruster
ide_nop_int(const IDEDMA * dma,bool is_write)2682ae0cebd7SPhilippe Mathieu-Daudé static int ide_nop_int(const IDEDMA *dma, bool is_write)
268340a6238aSAlexander Graf {
268440a6238aSAlexander Graf return 0;
268540a6238aSAlexander Graf }
268640a6238aSAlexander Graf
ide_nop(const IDEDMA * dma)2687ae0cebd7SPhilippe Mathieu-Daudé static void ide_nop(const IDEDMA *dma)
26889898586dSPaolo Bonzini {
26899898586dSPaolo Bonzini }
26909898586dSPaolo Bonzini
ide_nop_int32(const IDEDMA * dma,int32_t l)2691ae0cebd7SPhilippe Mathieu-Daudé static int32_t ide_nop_int32(const IDEDMA *dma, int32_t l)
26923251bdcfSJohn Snow {
26933251bdcfSJohn Snow return 0;
26943251bdcfSJohn Snow }
26953251bdcfSJohn Snow
269640a6238aSAlexander Graf static const IDEDMAOps ide_dma_nop_ops = {
26973251bdcfSJohn Snow .prepare_buf = ide_nop_int32,
26989898586dSPaolo Bonzini .restart_dma = ide_nop,
269940a6238aSAlexander Graf .rw_buf = ide_nop_int,
270040a6238aSAlexander Graf };
270140a6238aSAlexander Graf
ide_restart_dma(IDEState * s,enum ide_dma_cmd dma_cmd)27029898586dSPaolo Bonzini static void ide_restart_dma(IDEState *s, enum ide_dma_cmd dma_cmd)
27039898586dSPaolo Bonzini {
2704a96cb236SPaolo Bonzini s->unit = s->bus->retry_unit;
2705dc5d0af4SPaolo Bonzini ide_set_sector(s, s->bus->retry_sector_num);
2706dc5d0af4SPaolo Bonzini s->nsector = s->bus->retry_nsector;
27079898586dSPaolo Bonzini s->bus->dma->ops->restart_dma(s->bus->dma);
27089898586dSPaolo Bonzini s->io_buffer_size = 0;
27099898586dSPaolo Bonzini s->dma_cmd = dma_cmd;
27109898586dSPaolo Bonzini ide_start_dma(s, ide_dma_cb);
27119898586dSPaolo Bonzini }
27129898586dSPaolo Bonzini
ide_restart_bh(void * opaque)27139898586dSPaolo Bonzini static void ide_restart_bh(void *opaque)
27149898586dSPaolo Bonzini {
27159898586dSPaolo Bonzini IDEBus *bus = opaque;
27169898586dSPaolo Bonzini IDEState *s;
27179898586dSPaolo Bonzini bool is_read;
27189898586dSPaolo Bonzini int error_status;
27199898586dSPaolo Bonzini
27209898586dSPaolo Bonzini qemu_bh_delete(bus->bh);
27219898586dSPaolo Bonzini bus->bh = NULL;
27229898586dSPaolo Bonzini
27239898586dSPaolo Bonzini error_status = bus->error_status;
27249898586dSPaolo Bonzini if (bus->error_status == 0) {
27259898586dSPaolo Bonzini return;
27269898586dSPaolo Bonzini }
27279898586dSPaolo Bonzini
27282c50207fSPhilippe Mathieu-Daudé s = ide_bus_active_if(bus);
27299898586dSPaolo Bonzini is_read = (bus->error_status & IDE_RETRY_READ) != 0;
27309898586dSPaolo Bonzini
27319898586dSPaolo Bonzini /* The error status must be cleared before resubmitting the request: The
27329898586dSPaolo Bonzini * request may fail again, and this case can only be distinguished if the
27339898586dSPaolo Bonzini * called function can set a new error status. */
27349898586dSPaolo Bonzini bus->error_status = 0;
27359898586dSPaolo Bonzini
27367c03a691SJohn Snow /* The HBA has generically asked to be kicked on retry */
27377c03a691SJohn Snow if (error_status & IDE_RETRY_HBA) {
27387c03a691SJohn Snow if (s->bus->dma->ops->restart) {
27397c03a691SJohn Snow s->bus->dma->ops->restart(s->bus->dma);
27407c03a691SJohn Snow }
2741502356eeSPavel Butsykin } else if (IS_IDE_RETRY_DMA(error_status)) {
27429898586dSPaolo Bonzini if (error_status & IDE_RETRY_TRIM) {
27439898586dSPaolo Bonzini ide_restart_dma(s, IDE_DMA_TRIM);
27449898586dSPaolo Bonzini } else {
27459898586dSPaolo Bonzini ide_restart_dma(s, is_read ? IDE_DMA_READ : IDE_DMA_WRITE);
27469898586dSPaolo Bonzini }
2747502356eeSPavel Butsykin } else if (IS_IDE_RETRY_PIO(error_status)) {
27489898586dSPaolo Bonzini if (is_read) {
27499898586dSPaolo Bonzini ide_sector_read(s);
27509898586dSPaolo Bonzini } else {
27519898586dSPaolo Bonzini ide_sector_write(s);
27529898586dSPaolo Bonzini }
27539898586dSPaolo Bonzini } else if (error_status & IDE_RETRY_FLUSH) {
27549898586dSPaolo Bonzini ide_flush_cache(s);
2755502356eeSPavel Butsykin } else if (IS_IDE_RETRY_ATAPI(error_status)) {
2756502356eeSPavel Butsykin assert(s->end_transfer_func == ide_atapi_cmd);
27579898586dSPaolo Bonzini ide_atapi_dma_restart(s);
2758502356eeSPavel Butsykin } else {
2759502356eeSPavel Butsykin abort();
27609898586dSPaolo Bonzini }
27619898586dSPaolo Bonzini }
27629898586dSPaolo Bonzini
ide_restart_cb(void * opaque,bool running,RunState state)2763538f0497SPhilippe Mathieu-Daudé static void ide_restart_cb(void *opaque, bool running, RunState state)
27649898586dSPaolo Bonzini {
27659898586dSPaolo Bonzini IDEBus *bus = opaque;
27669898586dSPaolo Bonzini
27679898586dSPaolo Bonzini if (!running)
27689898586dSPaolo Bonzini return;
27699898586dSPaolo Bonzini
27709898586dSPaolo Bonzini if (!bus->bh) {
27719898586dSPaolo Bonzini bus->bh = qemu_bh_new(ide_restart_bh, bus);
27729898586dSPaolo Bonzini qemu_bh_schedule(bus->bh);
27739898586dSPaolo Bonzini }
27749898586dSPaolo Bonzini }
27759898586dSPaolo Bonzini
ide_bus_register_restart_cb(IDEBus * bus)2776e29b1246SPhilippe Mathieu-Daudé void ide_bus_register_restart_cb(IDEBus *bus)
2777f878c916SPaolo Bonzini {
27789898586dSPaolo Bonzini if (bus->dma->ops->restart_dma) {
2779ca44141dSAshijeet Acharya bus->vmstate = qemu_add_vm_change_state_handler(ide_restart_cb, bus);
27809898586dSPaolo Bonzini }
2781f878c916SPaolo Bonzini }
2782f878c916SPaolo Bonzini
278340a6238aSAlexander Graf static IDEDMA ide_dma_nop = {
278440a6238aSAlexander Graf .ops = &ide_dma_nop_ops,
278540a6238aSAlexander Graf .aiocb = NULL,
278640a6238aSAlexander Graf };
278740a6238aSAlexander Graf
ide_bus_init_output_irq(IDEBus * bus,qemu_irq irq_out)2788c9519630SPhilippe Mathieu-Daudé void ide_bus_init_output_irq(IDEBus *bus, qemu_irq irq_out)
2789d459da0eSMarkus Armbruster {
2790d459da0eSMarkus Armbruster int i;
2791d459da0eSMarkus Armbruster
2792d459da0eSMarkus Armbruster for(i = 0; i < 2; i++) {
279357234ee4SMarkus Armbruster ide_init1(bus, i);
279457234ee4SMarkus Armbruster ide_reset(&bus->ifs[i]);
279557234ee4SMarkus Armbruster }
2796c9519630SPhilippe Mathieu-Daudé bus->irq = irq_out;
279740a6238aSAlexander Graf bus->dma = &ide_dma_nop;
279857234ee4SMarkus Armbruster }
279957234ee4SMarkus Armbruster
ide_bus_set_irq(IDEBus * bus)28000cfe719dSPhilippe Mathieu-Daudé void ide_bus_set_irq(IDEBus *bus)
2801da9f1172SPhilippe Mathieu-Daudé {
2802da9f1172SPhilippe Mathieu-Daudé if (!(bus->cmd & IDE_CTRL_DISABLE_IRQ)) {
2803da9f1172SPhilippe Mathieu-Daudé qemu_irq_raise(bus->irq);
2804da9f1172SPhilippe Mathieu-Daudé }
2805da9f1172SPhilippe Mathieu-Daudé }
2806da9f1172SPhilippe Mathieu-Daudé
ide_exit(IDEState * s)2807c9f08641SLi Qiang void ide_exit(IDEState *s)
2808c9f08641SLi Qiang {
2809c9f08641SLi Qiang timer_free(s->sector_write_timer);
2810c9f08641SLi Qiang qemu_vfree(s->smart_selftest_data);
2811c9f08641SLi Qiang qemu_vfree(s->io_buffer);
2812c9f08641SLi Qiang }
2813c9f08641SLi Qiang
is_identify_set(void * opaque,int version_id)281437159f13SJuan Quintela static bool is_identify_set(void *opaque, int version_id)
281559f2a787SGerd Hoffmann {
281637159f13SJuan Quintela IDEState *s = opaque;
281759f2a787SGerd Hoffmann
281837159f13SJuan Quintela return s->identify_set != 0;
281959f2a787SGerd Hoffmann }
282059f2a787SGerd Hoffmann
282150641c5cSJuan Quintela static EndTransferFunc* transfer_end_table[] = {
282250641c5cSJuan Quintela ide_sector_read,
282350641c5cSJuan Quintela ide_sector_write,
282450641c5cSJuan Quintela ide_transfer_stop,
282550641c5cSJuan Quintela ide_atapi_cmd_reply_end,
282650641c5cSJuan Quintela ide_atapi_cmd,
282750641c5cSJuan Quintela ide_dummy_transfer_stop,
282850641c5cSJuan Quintela };
282950641c5cSJuan Quintela
transfer_end_table_idx(EndTransferFunc * fn)283050641c5cSJuan Quintela static int transfer_end_table_idx(EndTransferFunc *fn)
283150641c5cSJuan Quintela {
283250641c5cSJuan Quintela int i;
283350641c5cSJuan Quintela
283450641c5cSJuan Quintela for (i = 0; i < ARRAY_SIZE(transfer_end_table); i++)
283550641c5cSJuan Quintela if (transfer_end_table[i] == fn)
283650641c5cSJuan Quintela return i;
283750641c5cSJuan Quintela
283850641c5cSJuan Quintela return -1;
283950641c5cSJuan Quintela }
284050641c5cSJuan Quintela
ide_drive_post_load(void * opaque,int version_id)284137159f13SJuan Quintela static int ide_drive_post_load(void *opaque, int version_id)
284259f2a787SGerd Hoffmann {
284337159f13SJuan Quintela IDEState *s = opaque;
284459f2a787SGerd Hoffmann
28456b896ab2SDon Slutz if (s->blk && s->identify_set) {
28464be74634SMarkus Armbruster blk_set_enable_write_cache(s->blk, !!(s->identify_data[85] & (1 << 5)));
28477cdd481cSPaolo Bonzini }
284837159f13SJuan Quintela return 0;
284937159f13SJuan Quintela }
285037159f13SJuan Quintela
ide_drive_pio_post_load(void * opaque,int version_id)285150641c5cSJuan Quintela static int ide_drive_pio_post_load(void *opaque, int version_id)
285250641c5cSJuan Quintela {
285350641c5cSJuan Quintela IDEState *s = opaque;
285450641c5cSJuan Quintela
2855fb60105dSKevin Wolf if (s->end_transfer_fn_idx >= ARRAY_SIZE(transfer_end_table)) {
285650641c5cSJuan Quintela return -EINVAL;
285750641c5cSJuan Quintela }
285850641c5cSJuan Quintela s->end_transfer_func = transfer_end_table[s->end_transfer_fn_idx];
285950641c5cSJuan Quintela s->data_ptr = s->io_buffer + s->cur_io_buffer_offset;
286050641c5cSJuan Quintela s->data_end = s->data_ptr + s->cur_io_buffer_len;
2861819fa276SDr. David Alan Gilbert s->atapi_dma = s->feature & 1; /* as per cmd_packet */
286250641c5cSJuan Quintela
286350641c5cSJuan Quintela return 0;
286450641c5cSJuan Quintela }
286550641c5cSJuan Quintela
ide_drive_pio_pre_save(void * opaque)286644b1ff31SDr. David Alan Gilbert static int ide_drive_pio_pre_save(void *opaque)
286750641c5cSJuan Quintela {
286850641c5cSJuan Quintela IDEState *s = opaque;
286950641c5cSJuan Quintela int idx;
287050641c5cSJuan Quintela
287150641c5cSJuan Quintela s->cur_io_buffer_offset = s->data_ptr - s->io_buffer;
287250641c5cSJuan Quintela s->cur_io_buffer_len = s->data_end - s->data_ptr;
287350641c5cSJuan Quintela
287450641c5cSJuan Quintela idx = transfer_end_table_idx(s->end_transfer_func);
287550641c5cSJuan Quintela if (idx == -1) {
287650641c5cSJuan Quintela fprintf(stderr, "%s: invalid end_transfer_func for DRQ_STAT\n",
287750641c5cSJuan Quintela __func__);
287850641c5cSJuan Quintela s->end_transfer_fn_idx = 2;
287950641c5cSJuan Quintela } else {
288050641c5cSJuan Quintela s->end_transfer_fn_idx = idx;
288150641c5cSJuan Quintela }
288244b1ff31SDr. David Alan Gilbert
288344b1ff31SDr. David Alan Gilbert return 0;
288450641c5cSJuan Quintela }
288550641c5cSJuan Quintela
ide_drive_pio_state_needed(void * opaque)288650641c5cSJuan Quintela static bool ide_drive_pio_state_needed(void *opaque)
288750641c5cSJuan Quintela {
288850641c5cSJuan Quintela IDEState *s = opaque;
288950641c5cSJuan Quintela
2890fdc650d7SKevin Wolf return ((s->status & DRQ_STAT) != 0)
2891fd648f10SPaolo Bonzini || (s->bus->error_status & IDE_RETRY_PIO);
289250641c5cSJuan Quintela }
289350641c5cSJuan Quintela
ide_tray_state_needed(void * opaque)2894db118fe7SMarkus Armbruster static bool ide_tray_state_needed(void *opaque)
2895db118fe7SMarkus Armbruster {
2896db118fe7SMarkus Armbruster IDEState *s = opaque;
2897db118fe7SMarkus Armbruster
2898db118fe7SMarkus Armbruster return s->tray_open || s->tray_locked;
2899db118fe7SMarkus Armbruster }
2900db118fe7SMarkus Armbruster
ide_atapi_gesn_needed(void * opaque)2901996faf1aSAmit Shah static bool ide_atapi_gesn_needed(void *opaque)
2902996faf1aSAmit Shah {
2903996faf1aSAmit Shah IDEState *s = opaque;
2904996faf1aSAmit Shah
2905996faf1aSAmit Shah return s->events.new_media || s->events.eject_request;
2906996faf1aSAmit Shah }
2907996faf1aSAmit Shah
ide_error_needed(void * opaque)2908def93791SKevin Wolf static bool ide_error_needed(void *opaque)
2909def93791SKevin Wolf {
2910def93791SKevin Wolf IDEBus *bus = opaque;
2911def93791SKevin Wolf
2912def93791SKevin Wolf return (bus->error_status != 0);
2913def93791SKevin Wolf }
2914def93791SKevin Wolf
2915996faf1aSAmit Shah /* Fields for GET_EVENT_STATUS_NOTIFICATION ATAPI command */
2916656fbeffSMarkus Armbruster static const VMStateDescription vmstate_ide_atapi_gesn_state = {
2917996faf1aSAmit Shah .name ="ide_drive/atapi/gesn_state",
2918996faf1aSAmit Shah .version_id = 1,
2919996faf1aSAmit Shah .minimum_version_id = 1,
29205cd8cadaSJuan Quintela .needed = ide_atapi_gesn_needed,
2921996faf1aSAmit Shah .fields = (VMStateField[]) {
2922996faf1aSAmit Shah VMSTATE_BOOL(events.new_media, IDEState),
2923996faf1aSAmit Shah VMSTATE_BOOL(events.eject_request, IDEState),
29240754f9ecSKevin Wolf VMSTATE_END_OF_LIST()
2925996faf1aSAmit Shah }
2926996faf1aSAmit Shah };
2927996faf1aSAmit Shah
2928db118fe7SMarkus Armbruster static const VMStateDescription vmstate_ide_tray_state = {
2929db118fe7SMarkus Armbruster .name = "ide_drive/tray_state",
2930db118fe7SMarkus Armbruster .version_id = 1,
2931db118fe7SMarkus Armbruster .minimum_version_id = 1,
29325cd8cadaSJuan Quintela .needed = ide_tray_state_needed,
2933db118fe7SMarkus Armbruster .fields = (VMStateField[]) {
2934db118fe7SMarkus Armbruster VMSTATE_BOOL(tray_open, IDEState),
2935db118fe7SMarkus Armbruster VMSTATE_BOOL(tray_locked, IDEState),
2936db118fe7SMarkus Armbruster VMSTATE_END_OF_LIST()
2937db118fe7SMarkus Armbruster }
2938db118fe7SMarkus Armbruster };
2939db118fe7SMarkus Armbruster
2940656fbeffSMarkus Armbruster static const VMStateDescription vmstate_ide_drive_pio_state = {
294150641c5cSJuan Quintela .name = "ide_drive/pio_state",
294250641c5cSJuan Quintela .version_id = 1,
294350641c5cSJuan Quintela .minimum_version_id = 1,
294450641c5cSJuan Quintela .pre_save = ide_drive_pio_pre_save,
294550641c5cSJuan Quintela .post_load = ide_drive_pio_post_load,
29465cd8cadaSJuan Quintela .needed = ide_drive_pio_state_needed,
294750641c5cSJuan Quintela .fields = (VMStateField[]) {
294850641c5cSJuan Quintela VMSTATE_INT32(req_nb_sectors, IDEState),
294950641c5cSJuan Quintela VMSTATE_VARRAY_INT32(io_buffer, IDEState, io_buffer_total_len, 1,
295050641c5cSJuan Quintela vmstate_info_uint8, uint8_t),
295150641c5cSJuan Quintela VMSTATE_INT32(cur_io_buffer_offset, IDEState),
295250641c5cSJuan Quintela VMSTATE_INT32(cur_io_buffer_len, IDEState),
295350641c5cSJuan Quintela VMSTATE_UINT8(end_transfer_fn_idx, IDEState),
295450641c5cSJuan Quintela VMSTATE_INT32(elementary_transfer_size, IDEState),
295550641c5cSJuan Quintela VMSTATE_INT32(packet_transfer_size, IDEState),
295650641c5cSJuan Quintela VMSTATE_END_OF_LIST()
295750641c5cSJuan Quintela }
295850641c5cSJuan Quintela };
295950641c5cSJuan Quintela
296037159f13SJuan Quintela const VMStateDescription vmstate_ide_drive = {
296137159f13SJuan Quintela .name = "ide_drive",
29623abb6260SJuan Quintela .version_id = 3,
296337159f13SJuan Quintela .minimum_version_id = 0,
296437159f13SJuan Quintela .post_load = ide_drive_post_load,
296537159f13SJuan Quintela .fields = (VMStateField[]) {
296637159f13SJuan Quintela VMSTATE_INT32(mult_sectors, IDEState),
296737159f13SJuan Quintela VMSTATE_INT32(identify_set, IDEState),
296837159f13SJuan Quintela VMSTATE_BUFFER_TEST(identify_data, IDEState, is_identify_set),
296937159f13SJuan Quintela VMSTATE_UINT8(feature, IDEState),
297037159f13SJuan Quintela VMSTATE_UINT8(error, IDEState),
297137159f13SJuan Quintela VMSTATE_UINT32(nsector, IDEState),
297237159f13SJuan Quintela VMSTATE_UINT8(sector, IDEState),
297337159f13SJuan Quintela VMSTATE_UINT8(lcyl, IDEState),
297437159f13SJuan Quintela VMSTATE_UINT8(hcyl, IDEState),
297537159f13SJuan Quintela VMSTATE_UINT8(hob_feature, IDEState),
297637159f13SJuan Quintela VMSTATE_UINT8(hob_sector, IDEState),
297737159f13SJuan Quintela VMSTATE_UINT8(hob_nsector, IDEState),
297837159f13SJuan Quintela VMSTATE_UINT8(hob_lcyl, IDEState),
297937159f13SJuan Quintela VMSTATE_UINT8(hob_hcyl, IDEState),
298037159f13SJuan Quintela VMSTATE_UINT8(select, IDEState),
298137159f13SJuan Quintela VMSTATE_UINT8(status, IDEState),
298237159f13SJuan Quintela VMSTATE_UINT8(lba48, IDEState),
298337159f13SJuan Quintela VMSTATE_UINT8(sense_key, IDEState),
298437159f13SJuan Quintela VMSTATE_UINT8(asc, IDEState),
298537159f13SJuan Quintela VMSTATE_UINT8_V(cdrom_changed, IDEState, 3),
298637159f13SJuan Quintela VMSTATE_END_OF_LIST()
298750641c5cSJuan Quintela },
29885cd8cadaSJuan Quintela .subsections = (const VMStateDescription*[]) {
29895cd8cadaSJuan Quintela &vmstate_ide_drive_pio_state,
29905cd8cadaSJuan Quintela &vmstate_ide_tray_state,
29915cd8cadaSJuan Quintela &vmstate_ide_atapi_gesn_state,
29925cd8cadaSJuan Quintela NULL
299337159f13SJuan Quintela }
299437159f13SJuan Quintela };
299537159f13SJuan Quintela
2996656fbeffSMarkus Armbruster static const VMStateDescription vmstate_ide_error_status = {
2997def93791SKevin Wolf .name ="ide_bus/error",
2998d12b9ff2SPaolo Bonzini .version_id = 2,
2999def93791SKevin Wolf .minimum_version_id = 1,
30005cd8cadaSJuan Quintela .needed = ide_error_needed,
3001def93791SKevin Wolf .fields = (VMStateField[]) {
3002def93791SKevin Wolf VMSTATE_INT32(error_status, IDEBus),
3003d12b9ff2SPaolo Bonzini VMSTATE_INT64_V(retry_sector_num, IDEBus, 2),
3004d12b9ff2SPaolo Bonzini VMSTATE_UINT32_V(retry_nsector, IDEBus, 2),
3005d12b9ff2SPaolo Bonzini VMSTATE_UINT8_V(retry_unit, IDEBus, 2),
3006def93791SKevin Wolf VMSTATE_END_OF_LIST()
3007def93791SKevin Wolf }
3008def93791SKevin Wolf };
3009def93791SKevin Wolf
30106521dc62SJuan Quintela const VMStateDescription vmstate_ide_bus = {
30116521dc62SJuan Quintela .name = "ide_bus",
30126521dc62SJuan Quintela .version_id = 1,
30136521dc62SJuan Quintela .minimum_version_id = 1,
30146521dc62SJuan Quintela .fields = (VMStateField[]) {
30156521dc62SJuan Quintela VMSTATE_UINT8(cmd, IDEBus),
30166521dc62SJuan Quintela VMSTATE_UINT8(unit, IDEBus),
30176521dc62SJuan Quintela VMSTATE_END_OF_LIST()
3018def93791SKevin Wolf },
30195cd8cadaSJuan Quintela .subsections = (const VMStateDescription*[]) {
30205cd8cadaSJuan Quintela &vmstate_ide_error_status,
30215cd8cadaSJuan Quintela NULL
30226521dc62SJuan Quintela }
30236521dc62SJuan Quintela };
302475717903SIsaku Yamahata
ide_drive_get(DriveInfo ** hd,int n)3025d8f94e1bSJohn Snow void ide_drive_get(DriveInfo **hd, int n)
302675717903SIsaku Yamahata {
302775717903SIsaku Yamahata int i;
302875717903SIsaku Yamahata
3029d8f94e1bSJohn Snow for (i = 0; i < n; i++) {
3030d8f94e1bSJohn Snow hd[i] = drive_get_by_index(IF_IDE, i);
303175717903SIsaku Yamahata }
303275717903SIsaku Yamahata }
3033