root / hw / ide / core.c @ 95b5edcd
History | View | Annotate | Download (55.9 kB)
1 | 5391d806 | bellard | /*
|
---|---|---|---|
2 | 38cdea7c | balrog | * QEMU IDE disk and CD/DVD-ROM Emulator
|
3 | 5fafdf24 | ths | *
|
4 | 5391d806 | bellard | * Copyright (c) 2003 Fabrice Bellard
|
5 | 201a51fc | balrog | * Copyright (c) 2006 Openedhand Ltd.
|
6 | 5fafdf24 | ths | *
|
7 | 5391d806 | bellard | * Permission is hereby granted, free of charge, to any person obtaining a copy
|
8 | 5391d806 | bellard | * of this software and associated documentation files (the "Software"), to deal
|
9 | 5391d806 | bellard | * in the Software without restriction, including without limitation the rights
|
10 | 5391d806 | bellard | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
11 | 5391d806 | bellard | * copies of the Software, and to permit persons to whom the Software is
|
12 | 5391d806 | bellard | * furnished to do so, subject to the following conditions:
|
13 | 5391d806 | bellard | *
|
14 | 5391d806 | bellard | * The above copyright notice and this permission notice shall be included in
|
15 | 5391d806 | bellard | * all copies or substantial portions of the Software.
|
16 | 5391d806 | bellard | *
|
17 | 5391d806 | bellard | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
18 | 5391d806 | bellard | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
19 | 5391d806 | bellard | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
20 | 5391d806 | bellard | * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
21 | 5391d806 | bellard | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
22 | 5391d806 | bellard | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
23 | 5391d806 | bellard | * THE SOFTWARE.
|
24 | 5391d806 | bellard | */
|
25 | 59f2a787 | Gerd Hoffmann | #include <hw/hw.h> |
26 | 59f2a787 | Gerd Hoffmann | #include <hw/pc.h> |
27 | 59f2a787 | Gerd Hoffmann | #include <hw/pci.h> |
28 | c4d74df7 | Markus Armbruster | #include "qemu-error.h" |
29 | 87ecb68b | pbrook | #include "qemu-timer.h" |
30 | 87ecb68b | pbrook | #include "sysemu.h" |
31 | 1fb8648d | aliguori | #include "dma.h" |
32 | 2446333c | Blue Swirl | #include "blockdev.h" |
33 | 59f2a787 | Gerd Hoffmann | |
34 | 59f2a787 | Gerd Hoffmann | #include <hw/ide/internal.h> |
35 | e8b54394 | Brian Wheeler | |
36 | b93af93d | Brian Wheeler | /* These values were based on a Seagate ST3500418AS but have been modified
|
37 | b93af93d | Brian Wheeler | to make more sense in QEMU */
|
38 | b93af93d | Brian Wheeler | static const int smart_attributes[][12] = { |
39 | b93af93d | Brian Wheeler | /* id, flags, hflags, val, wrst, raw (6 bytes), threshold */
|
40 | b93af93d | Brian Wheeler | /* raw read error rate*/
|
41 | b93af93d | Brian Wheeler | { 0x01, 0x03, 0x00, 0x64, 0x64, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06}, |
42 | b93af93d | Brian Wheeler | /* spin up */
|
43 | b93af93d | Brian Wheeler | { 0x03, 0x03, 0x00, 0x64, 0x64, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, |
44 | b93af93d | Brian Wheeler | /* start stop count */
|
45 | b93af93d | Brian Wheeler | { 0x04, 0x02, 0x00, 0x64, 0x64, 0x64, 0x00, 0x00, 0x00, 0x00, 0x00, 0x14}, |
46 | b93af93d | Brian Wheeler | /* remapped sectors */
|
47 | b93af93d | Brian Wheeler | { 0x05, 0x03, 0x00, 0x64, 0x64, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x24}, |
48 | b93af93d | Brian Wheeler | /* power on hours */
|
49 | b93af93d | Brian Wheeler | { 0x09, 0x03, 0x00, 0x64, 0x64, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, |
50 | b93af93d | Brian Wheeler | /* power cycle count */
|
51 | b93af93d | Brian Wheeler | { 0x0c, 0x03, 0x00, 0x64, 0x64, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, |
52 | b93af93d | Brian Wheeler | /* airflow-temperature-celsius */
|
53 | b93af93d | Brian Wheeler | { 190, 0x03, 0x00, 0x45, 0x45, 0x1f, 0x00, 0x1f, 0x1f, 0x00, 0x00, 0x32}, |
54 | b93af93d | Brian Wheeler | /* end of list */
|
55 | b93af93d | Brian Wheeler | { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00} |
56 | e8b54394 | Brian Wheeler | }; |
57 | e8b54394 | Brian Wheeler | |
58 | ce4b6522 | Kevin Wolf | static int ide_handle_rw_error(IDEState *s, int error, int op); |
59 | 98087450 | bellard | |
60 | 5391d806 | bellard | static void padstr(char *str, const char *src, int len) |
61 | 5391d806 | bellard | { |
62 | 5391d806 | bellard | int i, v;
|
63 | 5391d806 | bellard | for(i = 0; i < len; i++) { |
64 | 5391d806 | bellard | if (*src)
|
65 | 5391d806 | bellard | v = *src++; |
66 | 5391d806 | bellard | else
|
67 | 5391d806 | bellard | v = ' ';
|
68 | 69b34976 | ths | str[i^1] = v;
|
69 | 5391d806 | bellard | } |
70 | 5391d806 | bellard | } |
71 | 5391d806 | bellard | |
72 | 67b915a5 | bellard | static void put_le16(uint16_t *p, unsigned int v) |
73 | 67b915a5 | bellard | { |
74 | 0c4ad8dc | bellard | *p = cpu_to_le16(v); |
75 | 67b915a5 | bellard | } |
76 | 67b915a5 | bellard | |
77 | 5391d806 | bellard | static void ide_identify(IDEState *s) |
78 | 5391d806 | bellard | { |
79 | 5391d806 | bellard | uint16_t *p; |
80 | 5391d806 | bellard | unsigned int oldsize; |
81 | 57dac7ef | Markus Armbruster | IDEDevice *dev; |
82 | 5391d806 | bellard | |
83 | 94458802 | bellard | if (s->identify_set) {
|
84 | 94458802 | bellard | memcpy(s->io_buffer, s->identify_data, sizeof(s->identify_data));
|
85 | 94458802 | bellard | return;
|
86 | 94458802 | bellard | } |
87 | 94458802 | bellard | |
88 | 5391d806 | bellard | memset(s->io_buffer, 0, 512); |
89 | 5391d806 | bellard | p = (uint16_t *)s->io_buffer; |
90 | 67b915a5 | bellard | put_le16(p + 0, 0x0040); |
91 | 5fafdf24 | ths | put_le16(p + 1, s->cylinders);
|
92 | 67b915a5 | bellard | put_le16(p + 3, s->heads);
|
93 | 67b915a5 | bellard | put_le16(p + 4, 512 * s->sectors); /* XXX: retired, remove ? */ |
94 | 67b915a5 | bellard | put_le16(p + 5, 512); /* XXX: retired, remove ? */ |
95 | 5fafdf24 | ths | put_le16(p + 6, s->sectors);
|
96 | fa879c64 | aliguori | padstr((char *)(p + 10), s->drive_serial_str, 20); /* serial number */ |
97 | 67b915a5 | bellard | put_le16(p + 20, 3); /* XXX: retired, remove ? */ |
98 | 67b915a5 | bellard | put_le16(p + 21, 512); /* cache size in sectors */ |
99 | 67b915a5 | bellard | put_le16(p + 22, 4); /* ecc bytes */ |
100 | 47c06340 | Gerd Hoffmann | padstr((char *)(p + 23), s->version, 8); /* firmware version */ |
101 | 60fe76f3 | ths | padstr((char *)(p + 27), "QEMU HARDDISK", 40); /* model */ |
102 | 3b46e624 | ths | #if MAX_MULT_SECTORS > 1 |
103 | 67b915a5 | bellard | put_le16(p + 47, 0x8000 | MAX_MULT_SECTORS); |
104 | 5391d806 | bellard | #endif
|
105 | 67b915a5 | bellard | put_le16(p + 48, 1); /* dword I/O */ |
106 | 94458802 | bellard | put_le16(p + 49, (1 << 11) | (1 << 9) | (1 << 8)); /* DMA and LBA supported */ |
107 | 67b915a5 | bellard | put_le16(p + 51, 0x200); /* PIO transfer cycle */ |
108 | 67b915a5 | bellard | put_le16(p + 52, 0x200); /* DMA transfer cycle */ |
109 | 94458802 | bellard | put_le16(p + 53, 1 | (1 << 1) | (1 << 2)); /* words 54-58,64-70,88 are valid */ |
110 | 67b915a5 | bellard | put_le16(p + 54, s->cylinders);
|
111 | 67b915a5 | bellard | put_le16(p + 55, s->heads);
|
112 | 67b915a5 | bellard | put_le16(p + 56, s->sectors);
|
113 | 5391d806 | bellard | oldsize = s->cylinders * s->heads * s->sectors; |
114 | 67b915a5 | bellard | put_le16(p + 57, oldsize);
|
115 | 67b915a5 | bellard | put_le16(p + 58, oldsize >> 16); |
116 | 5391d806 | bellard | if (s->mult_sectors)
|
117 | 67b915a5 | bellard | put_le16(p + 59, 0x100 | s->mult_sectors); |
118 | 67b915a5 | bellard | put_le16(p + 60, s->nb_sectors);
|
119 | 67b915a5 | bellard | put_le16(p + 61, s->nb_sectors >> 16); |
120 | d1b5c20d | ths | put_le16(p + 62, 0x07); /* single word dma0-2 supported */ |
121 | 94458802 | bellard | put_le16(p + 63, 0x07); /* mdma0-2 supported */ |
122 | 79d1d331 | Jonathan A. Kollasch | put_le16(p + 64, 0x03); /* pio3-4 supported */ |
123 | 94458802 | bellard | put_le16(p + 65, 120); |
124 | 94458802 | bellard | put_le16(p + 66, 120); |
125 | 94458802 | bellard | put_le16(p + 67, 120); |
126 | 94458802 | bellard | put_le16(p + 68, 120); |
127 | ccf0fd8b | Roland Elek | |
128 | ccf0fd8b | Roland Elek | if (s->ncq_queues) {
|
129 | ccf0fd8b | Roland Elek | put_le16(p + 75, s->ncq_queues - 1); |
130 | ccf0fd8b | Roland Elek | /* NCQ supported */
|
131 | ccf0fd8b | Roland Elek | put_le16(p + 76, (1 << 8)); |
132 | ccf0fd8b | Roland Elek | } |
133 | ccf0fd8b | Roland Elek | |
134 | 94458802 | bellard | put_le16(p + 80, 0xf0); /* ata3 -> ata6 supported */ |
135 | 94458802 | bellard | put_le16(p + 81, 0x16); /* conforms to ata5 */ |
136 | a58b8d54 | Christoph Hellwig | /* 14=NOP supported, 5=WCACHE supported, 0=SMART supported */
|
137 | a58b8d54 | Christoph Hellwig | put_le16(p + 82, (1 << 14) | (1 << 5) | 1); |
138 | c2ff060f | bellard | /* 13=flush_cache_ext,12=flush_cache,10=lba48 */
|
139 | c2ff060f | bellard | put_le16(p + 83, (1 << 14) | (1 << 13) | (1 <<12) | (1 << 10)); |
140 | e8b54394 | Brian Wheeler | /* 14=set to 1, 1=SMART self test, 0=SMART error logging */
|
141 | e8b54394 | Brian Wheeler | put_le16(p + 84, (1 << 14) | 0); |
142 | e900a7b7 | Christoph Hellwig | /* 14 = NOP supported, 5=WCACHE enabled, 0=SMART feature set enabled */
|
143 | e900a7b7 | Christoph Hellwig | if (bdrv_enable_write_cache(s->bs))
|
144 | e900a7b7 | Christoph Hellwig | put_le16(p + 85, (1 << 14) | (1 << 5) | 1); |
145 | e900a7b7 | Christoph Hellwig | else
|
146 | e900a7b7 | Christoph Hellwig | put_le16(p + 85, (1 << 14) | 1); |
147 | c2ff060f | bellard | /* 13=flush_cache_ext,12=flush_cache,10=lba48 */
|
148 | c2ff060f | bellard | put_le16(p + 86, (1 << 14) | (1 << 13) | (1 <<12) | (1 << 10)); |
149 | e8b54394 | Brian Wheeler | /* 14=set to 1, 1=smart self test, 0=smart error logging */
|
150 | e8b54394 | Brian Wheeler | put_le16(p + 87, (1 << 14) | 0); |
151 | 94458802 | bellard | put_le16(p + 88, 0x3f | (1 << 13)); /* udma5 set and supported */ |
152 | 94458802 | bellard | put_le16(p + 93, 1 | (1 << 14) | 0x2000); |
153 | c2ff060f | bellard | put_le16(p + 100, s->nb_sectors);
|
154 | c2ff060f | bellard | put_le16(p + 101, s->nb_sectors >> 16); |
155 | c2ff060f | bellard | put_le16(p + 102, s->nb_sectors >> 32); |
156 | c2ff060f | bellard | put_le16(p + 103, s->nb_sectors >> 48); |
157 | 57dac7ef | Markus Armbruster | dev = s->unit ? s->bus->slave : s->bus->master; |
158 | 57dac7ef | Markus Armbruster | if (dev && dev->conf.physical_block_size)
|
159 | 57dac7ef | Markus Armbruster | put_le16(p + 106, 0x6000 | get_physical_block_exp(&dev->conf)); |
160 | 94458802 | bellard | |
161 | 94458802 | bellard | memcpy(s->identify_data, p, sizeof(s->identify_data));
|
162 | 94458802 | bellard | s->identify_set = 1;
|
163 | 5391d806 | bellard | } |
164 | 5391d806 | bellard | |
165 | 5391d806 | bellard | static void ide_atapi_identify(IDEState *s) |
166 | 5391d806 | bellard | { |
167 | 5391d806 | bellard | uint16_t *p; |
168 | 5391d806 | bellard | |
169 | 94458802 | bellard | if (s->identify_set) {
|
170 | 94458802 | bellard | memcpy(s->io_buffer, s->identify_data, sizeof(s->identify_data));
|
171 | 94458802 | bellard | return;
|
172 | 94458802 | bellard | } |
173 | 94458802 | bellard | |
174 | 5391d806 | bellard | memset(s->io_buffer, 0, 512); |
175 | 5391d806 | bellard | p = (uint16_t *)s->io_buffer; |
176 | 5391d806 | bellard | /* Removable CDROM, 50us response, 12 byte packets */
|
177 | 67b915a5 | bellard | put_le16(p + 0, (2 << 14) | (5 << 8) | (1 << 7) | (2 << 5) | (0 << 0)); |
178 | fa879c64 | aliguori | padstr((char *)(p + 10), s->drive_serial_str, 20); /* serial number */ |
179 | 67b915a5 | bellard | put_le16(p + 20, 3); /* buffer type */ |
180 | 67b915a5 | bellard | put_le16(p + 21, 512); /* cache size in sectors */ |
181 | 67b915a5 | bellard | put_le16(p + 22, 4); /* ecc bytes */ |
182 | 47c06340 | Gerd Hoffmann | padstr((char *)(p + 23), s->version, 8); /* firmware version */ |
183 | 38cdea7c | balrog | padstr((char *)(p + 27), "QEMU DVD-ROM", 40); /* model */ |
184 | 67b915a5 | bellard | put_le16(p + 48, 1); /* dword I/O (XXX: should not be set on CDROM) */ |
185 | 8ccad811 | bellard | #ifdef USE_DMA_CDROM
|
186 | 8ccad811 | bellard | put_le16(p + 49, 1 << 9 | 1 << 8); /* DMA and LBA supported */ |
187 | 8ccad811 | bellard | put_le16(p + 53, 7); /* words 64-70, 54-58, 88 valid */ |
188 | d1b5c20d | ths | put_le16(p + 62, 7); /* single word dma0-2 supported */ |
189 | 8ccad811 | bellard | put_le16(p + 63, 7); /* mdma0-2 supported */ |
190 | 8ccad811 | bellard | #else
|
191 | 67b915a5 | bellard | put_le16(p + 49, 1 << 9); /* LBA supported, no DMA */ |
192 | 67b915a5 | bellard | put_le16(p + 53, 3); /* words 64-70, 54-58 valid */ |
193 | 67b915a5 | bellard | put_le16(p + 63, 0x103); /* DMA modes XXX: may be incorrect */ |
194 | 8ccad811 | bellard | #endif
|
195 | 79d1d331 | Jonathan A. Kollasch | put_le16(p + 64, 3); /* pio3-4 supported */ |
196 | 67b915a5 | bellard | put_le16(p + 65, 0xb4); /* minimum DMA multiword tx cycle time */ |
197 | 67b915a5 | bellard | put_le16(p + 66, 0xb4); /* recommended DMA multiword tx cycle time */ |
198 | 67b915a5 | bellard | put_le16(p + 67, 0x12c); /* minimum PIO cycle time without flow control */ |
199 | 67b915a5 | bellard | put_le16(p + 68, 0xb4); /* minimum PIO cycle time with IORDY flow control */ |
200 | 94458802 | bellard | |
201 | 67b915a5 | bellard | put_le16(p + 71, 30); /* in ns */ |
202 | 67b915a5 | bellard | put_le16(p + 72, 30); /* in ns */ |
203 | 5391d806 | bellard | |
204 | 1bdaa28d | Alexander Graf | if (s->ncq_queues) {
|
205 | 1bdaa28d | Alexander Graf | put_le16(p + 75, s->ncq_queues - 1); |
206 | 1bdaa28d | Alexander Graf | /* NCQ supported */
|
207 | 1bdaa28d | Alexander Graf | put_le16(p + 76, (1 << 8)); |
208 | 1bdaa28d | Alexander Graf | } |
209 | 1bdaa28d | Alexander Graf | |
210 | 67b915a5 | bellard | put_le16(p + 80, 0x1e); /* support up to ATA/ATAPI-4 */ |
211 | 8ccad811 | bellard | #ifdef USE_DMA_CDROM
|
212 | 8ccad811 | bellard | put_le16(p + 88, 0x3f | (1 << 13)); /* udma5 set and supported */ |
213 | 8ccad811 | bellard | #endif
|
214 | 94458802 | bellard | memcpy(s->identify_data, p, sizeof(s->identify_data));
|
215 | 94458802 | bellard | s->identify_set = 1;
|
216 | 5391d806 | bellard | } |
217 | 5391d806 | bellard | |
218 | 201a51fc | balrog | static void ide_cfata_identify(IDEState *s) |
219 | 201a51fc | balrog | { |
220 | 201a51fc | balrog | uint16_t *p; |
221 | 201a51fc | balrog | uint32_t cur_sec; |
222 | 201a51fc | balrog | |
223 | 201a51fc | balrog | p = (uint16_t *) s->identify_data; |
224 | 201a51fc | balrog | if (s->identify_set)
|
225 | 201a51fc | balrog | goto fill_buffer;
|
226 | 201a51fc | balrog | |
227 | 201a51fc | balrog | memset(p, 0, sizeof(s->identify_data)); |
228 | 201a51fc | balrog | |
229 | 201a51fc | balrog | cur_sec = s->cylinders * s->heads * s->sectors; |
230 | 201a51fc | balrog | |
231 | 201a51fc | balrog | put_le16(p + 0, 0x848a); /* CF Storage Card signature */ |
232 | 201a51fc | balrog | put_le16(p + 1, s->cylinders); /* Default cylinders */ |
233 | 201a51fc | balrog | put_le16(p + 3, s->heads); /* Default heads */ |
234 | 201a51fc | balrog | put_le16(p + 6, s->sectors); /* Default sectors per track */ |
235 | 201a51fc | balrog | put_le16(p + 7, s->nb_sectors >> 16); /* Sectors per card */ |
236 | 201a51fc | balrog | put_le16(p + 8, s->nb_sectors); /* Sectors per card */ |
237 | fa879c64 | aliguori | padstr((char *)(p + 10), s->drive_serial_str, 20); /* serial number */ |
238 | 201a51fc | balrog | put_le16(p + 22, 0x0004); /* ECC bytes */ |
239 | 47c06340 | Gerd Hoffmann | padstr((char *) (p + 23), s->version, 8); /* Firmware Revision */ |
240 | 60fe76f3 | ths | padstr((char *) (p + 27), "QEMU MICRODRIVE", 40);/* Model number */ |
241 | 201a51fc | balrog | #if MAX_MULT_SECTORS > 1 |
242 | 201a51fc | balrog | put_le16(p + 47, 0x8000 | MAX_MULT_SECTORS); |
243 | 201a51fc | balrog | #else
|
244 | 201a51fc | balrog | put_le16(p + 47, 0x0000); |
245 | 201a51fc | balrog | #endif
|
246 | 201a51fc | balrog | put_le16(p + 49, 0x0f00); /* Capabilities */ |
247 | 201a51fc | balrog | put_le16(p + 51, 0x0002); /* PIO cycle timing mode */ |
248 | 201a51fc | balrog | put_le16(p + 52, 0x0001); /* DMA cycle timing mode */ |
249 | 201a51fc | balrog | put_le16(p + 53, 0x0003); /* Translation params valid */ |
250 | 201a51fc | balrog | put_le16(p + 54, s->cylinders); /* Current cylinders */ |
251 | 201a51fc | balrog | put_le16(p + 55, s->heads); /* Current heads */ |
252 | 201a51fc | balrog | put_le16(p + 56, s->sectors); /* Current sectors */ |
253 | 201a51fc | balrog | put_le16(p + 57, cur_sec); /* Current capacity */ |
254 | 201a51fc | balrog | put_le16(p + 58, cur_sec >> 16); /* Current capacity */ |
255 | 201a51fc | balrog | if (s->mult_sectors) /* Multiple sector setting */ |
256 | 201a51fc | balrog | put_le16(p + 59, 0x100 | s->mult_sectors); |
257 | 201a51fc | balrog | put_le16(p + 60, s->nb_sectors); /* Total LBA sectors */ |
258 | 201a51fc | balrog | put_le16(p + 61, s->nb_sectors >> 16); /* Total LBA sectors */ |
259 | 201a51fc | balrog | put_le16(p + 63, 0x0203); /* Multiword DMA capability */ |
260 | 201a51fc | balrog | put_le16(p + 64, 0x0001); /* Flow Control PIO support */ |
261 | 201a51fc | balrog | put_le16(p + 65, 0x0096); /* Min. Multiword DMA cycle */ |
262 | 201a51fc | balrog | put_le16(p + 66, 0x0096); /* Rec. Multiword DMA cycle */ |
263 | 201a51fc | balrog | put_le16(p + 68, 0x00b4); /* Min. PIO cycle time */ |
264 | 201a51fc | balrog | put_le16(p + 82, 0x400c); /* Command Set supported */ |
265 | 201a51fc | balrog | put_le16(p + 83, 0x7068); /* Command Set supported */ |
266 | 201a51fc | balrog | put_le16(p + 84, 0x4000); /* Features supported */ |
267 | 201a51fc | balrog | put_le16(p + 85, 0x000c); /* Command Set enabled */ |
268 | 201a51fc | balrog | put_le16(p + 86, 0x7044); /* Command Set enabled */ |
269 | 201a51fc | balrog | put_le16(p + 87, 0x4000); /* Features enabled */ |
270 | 201a51fc | balrog | put_le16(p + 91, 0x4060); /* Current APM level */ |
271 | 201a51fc | balrog | put_le16(p + 129, 0x0002); /* Current features option */ |
272 | 201a51fc | balrog | put_le16(p + 130, 0x0005); /* Reassigned sectors */ |
273 | 201a51fc | balrog | put_le16(p + 131, 0x0001); /* Initial power mode */ |
274 | 201a51fc | balrog | put_le16(p + 132, 0x0000); /* User signature */ |
275 | 201a51fc | balrog | put_le16(p + 160, 0x8100); /* Power requirement */ |
276 | 201a51fc | balrog | put_le16(p + 161, 0x8001); /* CF command set */ |
277 | 201a51fc | balrog | |
278 | 201a51fc | balrog | s->identify_set = 1;
|
279 | 201a51fc | balrog | |
280 | 201a51fc | balrog | fill_buffer:
|
281 | 201a51fc | balrog | memcpy(s->io_buffer, p, sizeof(s->identify_data));
|
282 | 201a51fc | balrog | } |
283 | 201a51fc | balrog | |
284 | 5391d806 | bellard | static void ide_set_signature(IDEState *s) |
285 | 5391d806 | bellard | { |
286 | 5391d806 | bellard | s->select &= 0xf0; /* clear head */ |
287 | 5391d806 | bellard | /* put signature */
|
288 | 5391d806 | bellard | s->nsector = 1;
|
289 | 5391d806 | bellard | s->sector = 1;
|
290 | cd8722bb | Markus Armbruster | if (s->drive_kind == IDE_CD) {
|
291 | 5391d806 | bellard | s->lcyl = 0x14;
|
292 | 5391d806 | bellard | s->hcyl = 0xeb;
|
293 | 5391d806 | bellard | } else if (s->bs) { |
294 | 5391d806 | bellard | s->lcyl = 0;
|
295 | 5391d806 | bellard | s->hcyl = 0;
|
296 | 5391d806 | bellard | } else {
|
297 | 5391d806 | bellard | s->lcyl = 0xff;
|
298 | 5391d806 | bellard | s->hcyl = 0xff;
|
299 | 5391d806 | bellard | } |
300 | 5391d806 | bellard | } |
301 | 5391d806 | bellard | |
302 | 5391d806 | bellard | static inline void ide_abort_command(IDEState *s) |
303 | 5391d806 | bellard | { |
304 | 5391d806 | bellard | s->status = READY_STAT | ERR_STAT; |
305 | 5391d806 | bellard | s->error = ABRT_ERR; |
306 | 5391d806 | bellard | } |
307 | 5391d806 | bellard | |
308 | 5391d806 | bellard | /* prepare data transfer and tell what to do after */
|
309 | 33231e0e | Kevin Wolf | void ide_transfer_start(IDEState *s, uint8_t *buf, int size, |
310 | 33231e0e | Kevin Wolf | EndTransferFunc *end_transfer_func) |
311 | 5391d806 | bellard | { |
312 | 5391d806 | bellard | s->end_transfer_func = end_transfer_func; |
313 | 5391d806 | bellard | s->data_ptr = buf; |
314 | 5391d806 | bellard | s->data_end = buf + size; |
315 | 40a6238a | Alexander Graf | if (!(s->status & ERR_STAT)) {
|
316 | 7603d156 | ths | s->status |= DRQ_STAT; |
317 | 40a6238a | Alexander Graf | } |
318 | 40a6238a | Alexander Graf | s->bus->dma->ops->start_transfer(s->bus->dma); |
319 | 5391d806 | bellard | } |
320 | 5391d806 | bellard | |
321 | 33231e0e | Kevin Wolf | void ide_transfer_stop(IDEState *s)
|
322 | 5391d806 | bellard | { |
323 | 5391d806 | bellard | s->end_transfer_func = ide_transfer_stop; |
324 | 5391d806 | bellard | s->data_ptr = s->io_buffer; |
325 | 5391d806 | bellard | s->data_end = s->io_buffer; |
326 | 5391d806 | bellard | s->status &= ~DRQ_STAT; |
327 | 5391d806 | bellard | } |
328 | 5391d806 | bellard | |
329 | 356721ae | Gerd Hoffmann | int64_t ide_get_sector(IDEState *s) |
330 | 5391d806 | bellard | { |
331 | 5391d806 | bellard | int64_t sector_num; |
332 | 5391d806 | bellard | if (s->select & 0x40) { |
333 | 5391d806 | bellard | /* lba */
|
334 | c2ff060f | bellard | if (!s->lba48) {
|
335 | c2ff060f | bellard | sector_num = ((s->select & 0x0f) << 24) | (s->hcyl << 16) | |
336 | c2ff060f | bellard | (s->lcyl << 8) | s->sector;
|
337 | c2ff060f | bellard | } else {
|
338 | c2ff060f | bellard | sector_num = ((int64_t)s->hob_hcyl << 40) |
|
339 | c2ff060f | bellard | ((int64_t) s->hob_lcyl << 32) |
|
340 | c2ff060f | bellard | ((int64_t) s->hob_sector << 24) |
|
341 | c2ff060f | bellard | ((int64_t) s->hcyl << 16) |
|
342 | c2ff060f | bellard | ((int64_t) s->lcyl << 8) | s->sector;
|
343 | c2ff060f | bellard | } |
344 | 5391d806 | bellard | } else {
|
345 | 5391d806 | bellard | sector_num = ((s->hcyl << 8) | s->lcyl) * s->heads * s->sectors +
|
346 | c2ff060f | bellard | (s->select & 0x0f) * s->sectors + (s->sector - 1); |
347 | 5391d806 | bellard | } |
348 | 5391d806 | bellard | return sector_num;
|
349 | 5391d806 | bellard | } |
350 | 5391d806 | bellard | |
351 | 356721ae | Gerd Hoffmann | void ide_set_sector(IDEState *s, int64_t sector_num)
|
352 | 5391d806 | bellard | { |
353 | 5391d806 | bellard | unsigned int cyl, r; |
354 | 5391d806 | bellard | if (s->select & 0x40) { |
355 | c2ff060f | bellard | if (!s->lba48) {
|
356 | c2ff060f | bellard | s->select = (s->select & 0xf0) | (sector_num >> 24); |
357 | c2ff060f | bellard | s->hcyl = (sector_num >> 16);
|
358 | c2ff060f | bellard | s->lcyl = (sector_num >> 8);
|
359 | c2ff060f | bellard | s->sector = (sector_num); |
360 | c2ff060f | bellard | } else {
|
361 | c2ff060f | bellard | s->sector = sector_num; |
362 | c2ff060f | bellard | s->lcyl = sector_num >> 8;
|
363 | c2ff060f | bellard | s->hcyl = sector_num >> 16;
|
364 | c2ff060f | bellard | s->hob_sector = sector_num >> 24;
|
365 | c2ff060f | bellard | s->hob_lcyl = sector_num >> 32;
|
366 | c2ff060f | bellard | s->hob_hcyl = sector_num >> 40;
|
367 | c2ff060f | bellard | } |
368 | 5391d806 | bellard | } else {
|
369 | 5391d806 | bellard | cyl = sector_num / (s->heads * s->sectors); |
370 | 5391d806 | bellard | r = sector_num % (s->heads * s->sectors); |
371 | 5391d806 | bellard | s->hcyl = cyl >> 8;
|
372 | 5391d806 | bellard | s->lcyl = cyl; |
373 | 1b8eb456 | bellard | s->select = (s->select & 0xf0) | ((r / s->sectors) & 0x0f); |
374 | 5391d806 | bellard | s->sector = (r % s->sectors) + 1;
|
375 | 5391d806 | bellard | } |
376 | 5391d806 | bellard | } |
377 | 5391d806 | bellard | |
378 | e162cfb0 | balrog | static void ide_rw_error(IDEState *s) { |
379 | e162cfb0 | balrog | ide_abort_command(s); |
380 | 9cdd03a7 | Gerd Hoffmann | ide_set_irq(s->bus); |
381 | e162cfb0 | balrog | } |
382 | e162cfb0 | balrog | |
383 | 40a6238a | Alexander Graf | void ide_sector_read(IDEState *s)
|
384 | 5391d806 | bellard | { |
385 | 5391d806 | bellard | int64_t sector_num; |
386 | 5391d806 | bellard | int ret, n;
|
387 | 5391d806 | bellard | |
388 | 5391d806 | bellard | s->status = READY_STAT | SEEK_STAT; |
389 | a136e5a8 | bellard | s->error = 0; /* not needed by IDE spec, but needed by Windows */ |
390 | 5391d806 | bellard | sector_num = ide_get_sector(s); |
391 | 5391d806 | bellard | n = s->nsector; |
392 | 5391d806 | bellard | if (n == 0) { |
393 | 5391d806 | bellard | /* no more sector to read from disk */
|
394 | 5391d806 | bellard | ide_transfer_stop(s); |
395 | 5391d806 | bellard | } else {
|
396 | 5391d806 | bellard | #if defined(DEBUG_IDE)
|
397 | 18c5f8ea | balrog | printf("read sector=%" PRId64 "\n", sector_num); |
398 | 5391d806 | bellard | #endif
|
399 | 5391d806 | bellard | if (n > s->req_nb_sectors)
|
400 | 5391d806 | bellard | n = s->req_nb_sectors; |
401 | 5391d806 | bellard | ret = bdrv_read(s->bs, sector_num, s->io_buffer, n); |
402 | e162cfb0 | balrog | if (ret != 0) { |
403 | ce4b6522 | Kevin Wolf | if (ide_handle_rw_error(s, -ret,
|
404 | ce4b6522 | Kevin Wolf | BM_STATUS_PIO_RETRY | BM_STATUS_RETRY_READ)) |
405 | ce4b6522 | Kevin Wolf | { |
406 | ce4b6522 | Kevin Wolf | return;
|
407 | ce4b6522 | Kevin Wolf | } |
408 | e162cfb0 | balrog | } |
409 | 5391d806 | bellard | ide_transfer_start(s, s->io_buffer, 512 * n, ide_sector_read);
|
410 | 9cdd03a7 | Gerd Hoffmann | ide_set_irq(s->bus); |
411 | 5391d806 | bellard | ide_set_sector(s, sector_num + n); |
412 | 5391d806 | bellard | s->nsector -= n; |
413 | 5391d806 | bellard | } |
414 | 5391d806 | bellard | } |
415 | 5391d806 | bellard | |
416 | 7aea4412 | aliguori | static void dma_buf_commit(IDEState *s, int is_write) |
417 | 7aea4412 | aliguori | { |
418 | 1fb8648d | aliguori | qemu_sglist_destroy(&s->sg); |
419 | 7aea4412 | aliguori | } |
420 | 7aea4412 | aliguori | |
421 | 33231e0e | Kevin Wolf | void ide_set_inactive(IDEState *s)
|
422 | 8337606d | Kevin Wolf | { |
423 | 40a6238a | Alexander Graf | s->bus->dma->aiocb = NULL;
|
424 | 40a6238a | Alexander Graf | s->bus->dma->ops->set_inactive(s->bus->dma); |
425 | 8337606d | Kevin Wolf | } |
426 | 8337606d | Kevin Wolf | |
427 | 356721ae | Gerd Hoffmann | void ide_dma_error(IDEState *s)
|
428 | e162cfb0 | balrog | { |
429 | e162cfb0 | balrog | ide_transfer_stop(s); |
430 | e162cfb0 | balrog | s->error = ABRT_ERR; |
431 | e162cfb0 | balrog | s->status = READY_STAT | ERR_STAT; |
432 | 40a6238a | Alexander Graf | ide_set_inactive(s); |
433 | 40a6238a | Alexander Graf | s->bus->dma->ops->add_status(s->bus->dma, BM_STATUS_INT); |
434 | 9cdd03a7 | Gerd Hoffmann | ide_set_irq(s->bus); |
435 | e162cfb0 | balrog | } |
436 | e162cfb0 | balrog | |
437 | ce4b6522 | Kevin Wolf | static int ide_handle_rw_error(IDEState *s, int error, int op) |
438 | 428c5705 | aliguori | { |
439 | ce4b6522 | Kevin Wolf | int is_read = (op & BM_STATUS_RETRY_READ);
|
440 | abd7f68d | Markus Armbruster | BlockErrorAction action = bdrv_get_on_error(s->bs, is_read); |
441 | 428c5705 | aliguori | |
442 | 7ad7e3c3 | Luiz Capitulino | if (action == BLOCK_ERR_IGNORE) {
|
443 | 7ad7e3c3 | Luiz Capitulino | bdrv_mon_event(s->bs, BDRV_ACTION_IGNORE, is_read); |
444 | 428c5705 | aliguori | return 0; |
445 | 7ad7e3c3 | Luiz Capitulino | } |
446 | 428c5705 | aliguori | |
447 | 428c5705 | aliguori | if ((error == ENOSPC && action == BLOCK_ERR_STOP_ENOSPC)
|
448 | 428c5705 | aliguori | || action == BLOCK_ERR_STOP_ANY) { |
449 | 40a6238a | Alexander Graf | s->bus->dma->ops->set_unit(s->bus->dma, s->unit); |
450 | 40a6238a | Alexander Graf | s->bus->dma->ops->add_status(s->bus->dma, op); |
451 | 7ad7e3c3 | Luiz Capitulino | bdrv_mon_event(s->bs, BDRV_ACTION_STOP, is_read); |
452 | e07bbac5 | Jan Kiszka | vm_stop(VMSTOP_DISKFULL); |
453 | 428c5705 | aliguori | } else {
|
454 | ce4b6522 | Kevin Wolf | if (op & BM_STATUS_DMA_RETRY) {
|
455 | 7aea4412 | aliguori | dma_buf_commit(s, 0);
|
456 | 428c5705 | aliguori | ide_dma_error(s); |
457 | 7aea4412 | aliguori | } else {
|
458 | 428c5705 | aliguori | ide_rw_error(s); |
459 | 7aea4412 | aliguori | } |
460 | 7ad7e3c3 | Luiz Capitulino | bdrv_mon_event(s->bs, BDRV_ACTION_REPORT, is_read); |
461 | 428c5705 | aliguori | } |
462 | 428c5705 | aliguori | |
463 | 428c5705 | aliguori | return 1; |
464 | 428c5705 | aliguori | } |
465 | 428c5705 | aliguori | |
466 | cd369c46 | Christoph Hellwig | void ide_dma_cb(void *opaque, int ret) |
467 | 98087450 | bellard | { |
468 | 40a6238a | Alexander Graf | IDEState *s = opaque; |
469 | 8ccad811 | bellard | int n;
|
470 | 8ccad811 | bellard | int64_t sector_num; |
471 | 8ccad811 | bellard | |
472 | c641483f | Christoph Hellwig | handle_rw_error:
|
473 | e162cfb0 | balrog | if (ret < 0) { |
474 | cd369c46 | Christoph Hellwig | int op = BM_STATUS_DMA_RETRY;
|
475 | cd369c46 | Christoph Hellwig | |
476 | cd369c46 | Christoph Hellwig | if (s->is_read)
|
477 | cd369c46 | Christoph Hellwig | op |= BM_STATUS_RETRY_READ; |
478 | cd369c46 | Christoph Hellwig | if (ide_handle_rw_error(s, -ret, op)) {
|
479 | ce4b6522 | Kevin Wolf | return;
|
480 | ce4b6522 | Kevin Wolf | } |
481 | e162cfb0 | balrog | } |
482 | e162cfb0 | balrog | |
483 | 8ccad811 | bellard | n = s->io_buffer_size >> 9;
|
484 | 8ccad811 | bellard | sector_num = ide_get_sector(s); |
485 | 8ccad811 | bellard | if (n > 0) { |
486 | cd369c46 | Christoph Hellwig | dma_buf_commit(s, s->is_read); |
487 | 8ccad811 | bellard | sector_num += n; |
488 | 8ccad811 | bellard | ide_set_sector(s, sector_num); |
489 | 8ccad811 | bellard | s->nsector -= n; |
490 | 8ccad811 | bellard | } |
491 | 8ccad811 | bellard | |
492 | 8ccad811 | bellard | /* end of transfer ? */
|
493 | 8ccad811 | bellard | if (s->nsector == 0) { |
494 | 98087450 | bellard | s->status = READY_STAT | SEEK_STAT; |
495 | 9cdd03a7 | Gerd Hoffmann | ide_set_irq(s->bus); |
496 | cd369c46 | Christoph Hellwig | goto eot;
|
497 | 98087450 | bellard | } |
498 | 8ccad811 | bellard | |
499 | 8ccad811 | bellard | /* launch next transfer */
|
500 | 8ccad811 | bellard | n = s->nsector; |
501 | 596bb44d | Christoph Hellwig | s->io_buffer_index = 0;
|
502 | 8ccad811 | bellard | s->io_buffer_size = n * 512;
|
503 | cd369c46 | Christoph Hellwig | if (s->bus->dma->ops->prepare_buf(s->bus->dma, s->is_read) == 0) |
504 | 7aea4412 | aliguori | goto eot;
|
505 | cd369c46 | Christoph Hellwig | |
506 | 8ccad811 | bellard | #ifdef DEBUG_AIO
|
507 | cd369c46 | Christoph Hellwig | printf("ide_dma_cb: sector_num=%" PRId64 " n=%d, is_read=%d\n", |
508 | cd369c46 | Christoph Hellwig | sector_num, n, s->is_read); |
509 | 8ccad811 | bellard | #endif
|
510 | cd369c46 | Christoph Hellwig | |
511 | cd369c46 | Christoph Hellwig | if (s->is_read) {
|
512 | cd369c46 | Christoph Hellwig | s->bus->dma->aiocb = dma_bdrv_read(s->bs, &s->sg, sector_num, |
513 | cd369c46 | Christoph Hellwig | ide_dma_cb, s); |
514 | cd369c46 | Christoph Hellwig | } else {
|
515 | cd369c46 | Christoph Hellwig | s->bus->dma->aiocb = dma_bdrv_write(s->bs, &s->sg, sector_num, |
516 | cd369c46 | Christoph Hellwig | ide_dma_cb, s); |
517 | cd369c46 | Christoph Hellwig | } |
518 | c641483f | Christoph Hellwig | |
519 | c641483f | Christoph Hellwig | if (!s->bus->dma->aiocb) {
|
520 | c641483f | Christoph Hellwig | ret = -1;
|
521 | c641483f | Christoph Hellwig | goto handle_rw_error;
|
522 | c641483f | Christoph Hellwig | } |
523 | cd369c46 | Christoph Hellwig | return;
|
524 | cd369c46 | Christoph Hellwig | |
525 | cd369c46 | Christoph Hellwig | eot:
|
526 | cd369c46 | Christoph Hellwig | s->bus->dma->ops->add_status(s->bus->dma, BM_STATUS_INT); |
527 | cd369c46 | Christoph Hellwig | ide_set_inactive(s); |
528 | 98087450 | bellard | } |
529 | 98087450 | bellard | |
530 | cd369c46 | Christoph Hellwig | static void ide_sector_start_dma(IDEState *s, int is_read) |
531 | 98087450 | bellard | { |
532 | 8ccad811 | bellard | s->status = READY_STAT | SEEK_STAT | DRQ_STAT | BUSY_STAT; |
533 | 98087450 | bellard | s->io_buffer_index = 0;
|
534 | 98087450 | bellard | s->io_buffer_size = 0;
|
535 | cd369c46 | Christoph Hellwig | s->is_read = is_read; |
536 | cd369c46 | Christoph Hellwig | s->bus->dma->ops->start_dma(s->bus->dma, s, ide_dma_cb); |
537 | 98087450 | bellard | } |
538 | 98087450 | bellard | |
539 | a09db21f | bellard | static void ide_sector_write_timer_cb(void *opaque) |
540 | a09db21f | bellard | { |
541 | a09db21f | bellard | IDEState *s = opaque; |
542 | 9cdd03a7 | Gerd Hoffmann | ide_set_irq(s->bus); |
543 | a09db21f | bellard | } |
544 | a09db21f | bellard | |
545 | 40a6238a | Alexander Graf | void ide_sector_write(IDEState *s)
|
546 | 5391d806 | bellard | { |
547 | 5391d806 | bellard | int64_t sector_num; |
548 | 31c2a146 | ths | int ret, n, n1;
|
549 | 5391d806 | bellard | |
550 | 5391d806 | bellard | s->status = READY_STAT | SEEK_STAT; |
551 | 5391d806 | bellard | sector_num = ide_get_sector(s); |
552 | 5391d806 | bellard | #if defined(DEBUG_IDE)
|
553 | 18c5f8ea | balrog | printf("write sector=%" PRId64 "\n", sector_num); |
554 | 5391d806 | bellard | #endif
|
555 | 5391d806 | bellard | n = s->nsector; |
556 | 5391d806 | bellard | if (n > s->req_nb_sectors)
|
557 | 5391d806 | bellard | n = s->req_nb_sectors; |
558 | 31c2a146 | ths | ret = bdrv_write(s->bs, sector_num, s->io_buffer, n); |
559 | 428c5705 | aliguori | |
560 | e162cfb0 | balrog | if (ret != 0) { |
561 | ce4b6522 | Kevin Wolf | if (ide_handle_rw_error(s, -ret, BM_STATUS_PIO_RETRY))
|
562 | 428c5705 | aliguori | return;
|
563 | e162cfb0 | balrog | } |
564 | e162cfb0 | balrog | |
565 | 5391d806 | bellard | s->nsector -= n; |
566 | 5391d806 | bellard | if (s->nsector == 0) { |
567 | 292eef5a | ths | /* no more sectors to write */
|
568 | 5391d806 | bellard | ide_transfer_stop(s); |
569 | 5391d806 | bellard | } else {
|
570 | 5391d806 | bellard | n1 = s->nsector; |
571 | 5391d806 | bellard | if (n1 > s->req_nb_sectors)
|
572 | 5391d806 | bellard | n1 = s->req_nb_sectors; |
573 | 5391d806 | bellard | ide_transfer_start(s, s->io_buffer, 512 * n1, ide_sector_write);
|
574 | 5391d806 | bellard | } |
575 | 5391d806 | bellard | ide_set_sector(s, sector_num + n); |
576 | 3b46e624 | ths | |
577 | 31c2a146 | ths | if (win2k_install_hack && ((++s->irq_count % 16) == 0)) { |
578 | 31c2a146 | ths | /* It seems there is a bug in the Windows 2000 installer HDD
|
579 | 31c2a146 | ths | IDE driver which fills the disk with empty logs when the
|
580 | 31c2a146 | ths | IDE write IRQ comes too early. This hack tries to correct
|
581 | 31c2a146 | ths | that at the expense of slower write performances. Use this
|
582 | 31c2a146 | ths | option _only_ to install Windows 2000. You must disable it
|
583 | 31c2a146 | ths | for normal use. */
|
584 | f7736b91 | Blue Swirl | qemu_mod_timer(s->sector_write_timer, |
585 | 74475455 | Paolo Bonzini | qemu_get_clock_ns(vm_clock) + (get_ticks_per_sec() / 1000));
|
586 | f7736b91 | Blue Swirl | } else {
|
587 | 9cdd03a7 | Gerd Hoffmann | ide_set_irq(s->bus); |
588 | 31c2a146 | ths | } |
589 | 5391d806 | bellard | } |
590 | 5391d806 | bellard | |
591 | b0484ae4 | Christoph Hellwig | static void ide_flush_cb(void *opaque, int ret) |
592 | b0484ae4 | Christoph Hellwig | { |
593 | b0484ae4 | Christoph Hellwig | IDEState *s = opaque; |
594 | b0484ae4 | Christoph Hellwig | |
595 | e2bcadad | Kevin Wolf | if (ret < 0) { |
596 | e2bcadad | Kevin Wolf | /* XXX: What sector number to set here? */
|
597 | e2bcadad | Kevin Wolf | if (ide_handle_rw_error(s, -ret, BM_STATUS_RETRY_FLUSH)) {
|
598 | e2bcadad | Kevin Wolf | return;
|
599 | e2bcadad | Kevin Wolf | } |
600 | e2bcadad | Kevin Wolf | } |
601 | b0484ae4 | Christoph Hellwig | |
602 | b0484ae4 | Christoph Hellwig | s->status = READY_STAT | SEEK_STAT; |
603 | b0484ae4 | Christoph Hellwig | ide_set_irq(s->bus); |
604 | b0484ae4 | Christoph Hellwig | } |
605 | b0484ae4 | Christoph Hellwig | |
606 | 40a6238a | Alexander Graf | void ide_flush_cache(IDEState *s)
|
607 | 6bcb1a79 | Kevin Wolf | { |
608 | b2df7531 | Kevin Wolf | BlockDriverAIOCB *acb; |
609 | b2df7531 | Kevin Wolf | |
610 | b2df7531 | Kevin Wolf | if (s->bs == NULL) { |
611 | 6bcb1a79 | Kevin Wolf | ide_flush_cb(s, 0);
|
612 | b2df7531 | Kevin Wolf | return;
|
613 | b2df7531 | Kevin Wolf | } |
614 | b2df7531 | Kevin Wolf | |
615 | b2df7531 | Kevin Wolf | acb = bdrv_aio_flush(s->bs, ide_flush_cb, s); |
616 | b2df7531 | Kevin Wolf | if (acb == NULL) { |
617 | b2df7531 | Kevin Wolf | ide_flush_cb(s, -EIO); |
618 | 6bcb1a79 | Kevin Wolf | } |
619 | 6bcb1a79 | Kevin Wolf | } |
620 | 6bcb1a79 | Kevin Wolf | |
621 | 201a51fc | balrog | static void ide_cfata_metadata_inquiry(IDEState *s) |
622 | 201a51fc | balrog | { |
623 | 201a51fc | balrog | uint16_t *p; |
624 | 201a51fc | balrog | uint32_t spd; |
625 | 201a51fc | balrog | |
626 | 201a51fc | balrog | p = (uint16_t *) s->io_buffer; |
627 | 201a51fc | balrog | memset(p, 0, 0x200); |
628 | 201a51fc | balrog | spd = ((s->mdata_size - 1) >> 9) + 1; |
629 | 201a51fc | balrog | |
630 | 201a51fc | balrog | put_le16(p + 0, 0x0001); /* Data format revision */ |
631 | 201a51fc | balrog | put_le16(p + 1, 0x0000); /* Media property: silicon */ |
632 | 201a51fc | balrog | put_le16(p + 2, s->media_changed); /* Media status */ |
633 | 201a51fc | balrog | put_le16(p + 3, s->mdata_size & 0xffff); /* Capacity in bytes (low) */ |
634 | 201a51fc | balrog | put_le16(p + 4, s->mdata_size >> 16); /* Capacity in bytes (high) */ |
635 | 201a51fc | balrog | put_le16(p + 5, spd & 0xffff); /* Sectors per device (low) */ |
636 | 201a51fc | balrog | put_le16(p + 6, spd >> 16); /* Sectors per device (high) */ |
637 | 201a51fc | balrog | } |
638 | 201a51fc | balrog | |
639 | 201a51fc | balrog | static void ide_cfata_metadata_read(IDEState *s) |
640 | 201a51fc | balrog | { |
641 | 201a51fc | balrog | uint16_t *p; |
642 | 201a51fc | balrog | |
643 | 201a51fc | balrog | if (((s->hcyl << 16) | s->lcyl) << 9 > s->mdata_size + 2) { |
644 | 201a51fc | balrog | s->status = ERR_STAT; |
645 | 201a51fc | balrog | s->error = ABRT_ERR; |
646 | 201a51fc | balrog | return;
|
647 | 201a51fc | balrog | } |
648 | 201a51fc | balrog | |
649 | 201a51fc | balrog | p = (uint16_t *) s->io_buffer; |
650 | 201a51fc | balrog | memset(p, 0, 0x200); |
651 | 201a51fc | balrog | |
652 | 201a51fc | balrog | put_le16(p + 0, s->media_changed); /* Media status */ |
653 | 201a51fc | balrog | memcpy(p + 1, s->mdata_storage + (((s->hcyl << 16) | s->lcyl) << 9), |
654 | 201a51fc | balrog | MIN(MIN(s->mdata_size - (((s->hcyl << 16) | s->lcyl) << 9), |
655 | 201a51fc | balrog | s->nsector << 9), 0x200 - 2)); |
656 | 201a51fc | balrog | } |
657 | 201a51fc | balrog | |
658 | 201a51fc | balrog | static void ide_cfata_metadata_write(IDEState *s) |
659 | 201a51fc | balrog | { |
660 | 201a51fc | balrog | if (((s->hcyl << 16) | s->lcyl) << 9 > s->mdata_size + 2) { |
661 | 201a51fc | balrog | s->status = ERR_STAT; |
662 | 201a51fc | balrog | s->error = ABRT_ERR; |
663 | 201a51fc | balrog | return;
|
664 | 201a51fc | balrog | } |
665 | 201a51fc | balrog | |
666 | 201a51fc | balrog | s->media_changed = 0;
|
667 | 201a51fc | balrog | |
668 | 201a51fc | balrog | memcpy(s->mdata_storage + (((s->hcyl << 16) | s->lcyl) << 9), |
669 | 201a51fc | balrog | s->io_buffer + 2,
|
670 | 201a51fc | balrog | MIN(MIN(s->mdata_size - (((s->hcyl << 16) | s->lcyl) << 9), |
671 | 201a51fc | balrog | s->nsector << 9), 0x200 - 2)); |
672 | 201a51fc | balrog | } |
673 | 201a51fc | balrog | |
674 | bd491d6a | ths | /* called when the inserted state of the media has changed */
|
675 | db97ee6a | Christoph Hellwig | static void cdrom_change_cb(void *opaque, int reason) |
676 | bd491d6a | ths | { |
677 | bd491d6a | ths | IDEState *s = opaque; |
678 | 96b8f136 | ths | uint64_t nb_sectors; |
679 | bd491d6a | ths | |
680 | db97ee6a | Christoph Hellwig | if (!(reason & CHANGE_MEDIA)) {
|
681 | db97ee6a | Christoph Hellwig | return;
|
682 | db97ee6a | Christoph Hellwig | } |
683 | db97ee6a | Christoph Hellwig | |
684 | bd491d6a | ths | bdrv_get_geometry(s->bs, &nb_sectors); |
685 | bd491d6a | ths | s->nb_sectors = nb_sectors; |
686 | 9118e7f0 | aliguori | |
687 | 4b9b7092 | Amit Shah | /*
|
688 | 4b9b7092 | Amit Shah | * First indicate to the guest that a CD has been removed. That's
|
689 | 4b9b7092 | Amit Shah | * done on the next command the guest sends us.
|
690 | 4b9b7092 | Amit Shah | *
|
691 | 4b9b7092 | Amit Shah | * Then we set SENSE_UNIT_ATTENTION, by which the guest will
|
692 | 4b9b7092 | Amit Shah | * detect a new CD in the drive. See ide_atapi_cmd() for details.
|
693 | 4b9b7092 | Amit Shah | */
|
694 | 93c8cfd9 | Gleb Natapov | s->cdrom_changed = 1;
|
695 | 996faf1a | Amit Shah | s->events.new_media = true;
|
696 | 9cdd03a7 | Gerd Hoffmann | ide_set_irq(s->bus); |
697 | bd491d6a | ths | } |
698 | bd491d6a | ths | |
699 | c2ff060f | bellard | static void ide_cmd_lba48_transform(IDEState *s, int lba48) |
700 | c2ff060f | bellard | { |
701 | c2ff060f | bellard | s->lba48 = lba48; |
702 | c2ff060f | bellard | |
703 | c2ff060f | bellard | /* handle the 'magic' 0 nsector count conversion here. to avoid
|
704 | c2ff060f | bellard | * fiddling with the rest of the read logic, we just store the
|
705 | c2ff060f | bellard | * full sector count in ->nsector and ignore ->hob_nsector from now
|
706 | c2ff060f | bellard | */
|
707 | c2ff060f | bellard | if (!s->lba48) {
|
708 | c2ff060f | bellard | if (!s->nsector)
|
709 | c2ff060f | bellard | s->nsector = 256;
|
710 | c2ff060f | bellard | } else {
|
711 | c2ff060f | bellard | if (!s->nsector && !s->hob_nsector)
|
712 | c2ff060f | bellard | s->nsector = 65536;
|
713 | c2ff060f | bellard | else {
|
714 | c2ff060f | bellard | int lo = s->nsector;
|
715 | c2ff060f | bellard | int hi = s->hob_nsector;
|
716 | c2ff060f | bellard | |
717 | c2ff060f | bellard | s->nsector = (hi << 8) | lo;
|
718 | c2ff060f | bellard | } |
719 | c2ff060f | bellard | } |
720 | c2ff060f | bellard | } |
721 | c2ff060f | bellard | |
722 | bcbdc4d3 | Gerd Hoffmann | static void ide_clear_hob(IDEBus *bus) |
723 | c2ff060f | bellard | { |
724 | c2ff060f | bellard | /* any write clears HOB high bit of device control register */
|
725 | bcbdc4d3 | Gerd Hoffmann | bus->ifs[0].select &= ~(1 << 7); |
726 | bcbdc4d3 | Gerd Hoffmann | bus->ifs[1].select &= ~(1 << 7); |
727 | c2ff060f | bellard | } |
728 | c2ff060f | bellard | |
729 | 356721ae | Gerd Hoffmann | void ide_ioport_write(void *opaque, uint32_t addr, uint32_t val) |
730 | caed8802 | bellard | { |
731 | bcbdc4d3 | Gerd Hoffmann | IDEBus *bus = opaque; |
732 | 5391d806 | bellard | |
733 | 5391d806 | bellard | #ifdef DEBUG_IDE
|
734 | 5391d806 | bellard | printf("IDE: write addr=0x%x val=0x%02x\n", addr, val);
|
735 | 5391d806 | bellard | #endif
|
736 | c2ff060f | bellard | |
737 | 5391d806 | bellard | addr &= 7;
|
738 | fcdd25ab | aliguori | |
739 | fcdd25ab | aliguori | /* ignore writes to command block while busy with previous command */
|
740 | bcbdc4d3 | Gerd Hoffmann | if (addr != 7 && (idebus_active_if(bus)->status & (BUSY_STAT|DRQ_STAT))) |
741 | fcdd25ab | aliguori | return;
|
742 | fcdd25ab | aliguori | |
743 | 5391d806 | bellard | switch(addr) {
|
744 | 5391d806 | bellard | case 0: |
745 | 5391d806 | bellard | break;
|
746 | 5391d806 | bellard | case 1: |
747 | bcbdc4d3 | Gerd Hoffmann | ide_clear_hob(bus); |
748 | c45c3d00 | bellard | /* NOTE: data is written to the two drives */
|
749 | bcbdc4d3 | Gerd Hoffmann | bus->ifs[0].hob_feature = bus->ifs[0].feature; |
750 | bcbdc4d3 | Gerd Hoffmann | bus->ifs[1].hob_feature = bus->ifs[1].feature; |
751 | bcbdc4d3 | Gerd Hoffmann | bus->ifs[0].feature = val;
|
752 | bcbdc4d3 | Gerd Hoffmann | bus->ifs[1].feature = val;
|
753 | 5391d806 | bellard | break;
|
754 | 5391d806 | bellard | case 2: |
755 | bcbdc4d3 | Gerd Hoffmann | ide_clear_hob(bus); |
756 | bcbdc4d3 | Gerd Hoffmann | bus->ifs[0].hob_nsector = bus->ifs[0].nsector; |
757 | bcbdc4d3 | Gerd Hoffmann | bus->ifs[1].hob_nsector = bus->ifs[1].nsector; |
758 | bcbdc4d3 | Gerd Hoffmann | bus->ifs[0].nsector = val;
|
759 | bcbdc4d3 | Gerd Hoffmann | bus->ifs[1].nsector = val;
|
760 | 5391d806 | bellard | break;
|
761 | 5391d806 | bellard | case 3: |
762 | bcbdc4d3 | Gerd Hoffmann | ide_clear_hob(bus); |
763 | bcbdc4d3 | Gerd Hoffmann | bus->ifs[0].hob_sector = bus->ifs[0].sector; |
764 | bcbdc4d3 | Gerd Hoffmann | bus->ifs[1].hob_sector = bus->ifs[1].sector; |
765 | bcbdc4d3 | Gerd Hoffmann | bus->ifs[0].sector = val;
|
766 | bcbdc4d3 | Gerd Hoffmann | bus->ifs[1].sector = val;
|
767 | 5391d806 | bellard | break;
|
768 | 5391d806 | bellard | case 4: |
769 | bcbdc4d3 | Gerd Hoffmann | ide_clear_hob(bus); |
770 | bcbdc4d3 | Gerd Hoffmann | bus->ifs[0].hob_lcyl = bus->ifs[0].lcyl; |
771 | bcbdc4d3 | Gerd Hoffmann | bus->ifs[1].hob_lcyl = bus->ifs[1].lcyl; |
772 | bcbdc4d3 | Gerd Hoffmann | bus->ifs[0].lcyl = val;
|
773 | bcbdc4d3 | Gerd Hoffmann | bus->ifs[1].lcyl = val;
|
774 | 5391d806 | bellard | break;
|
775 | 5391d806 | bellard | case 5: |
776 | bcbdc4d3 | Gerd Hoffmann | ide_clear_hob(bus); |
777 | bcbdc4d3 | Gerd Hoffmann | bus->ifs[0].hob_hcyl = bus->ifs[0].hcyl; |
778 | bcbdc4d3 | Gerd Hoffmann | bus->ifs[1].hob_hcyl = bus->ifs[1].hcyl; |
779 | bcbdc4d3 | Gerd Hoffmann | bus->ifs[0].hcyl = val;
|
780 | bcbdc4d3 | Gerd Hoffmann | bus->ifs[1].hcyl = val;
|
781 | 5391d806 | bellard | break;
|
782 | 5391d806 | bellard | case 6: |
783 | c2ff060f | bellard | /* FIXME: HOB readback uses bit 7 */
|
784 | bcbdc4d3 | Gerd Hoffmann | bus->ifs[0].select = (val & ~0x10) | 0xa0; |
785 | bcbdc4d3 | Gerd Hoffmann | bus->ifs[1].select = (val | 0x10) | 0xa0; |
786 | 5391d806 | bellard | /* select drive */
|
787 | bcbdc4d3 | Gerd Hoffmann | bus->unit = (val >> 4) & 1; |
788 | 5391d806 | bellard | break;
|
789 | 5391d806 | bellard | default:
|
790 | 5391d806 | bellard | case 7: |
791 | 5391d806 | bellard | /* command */
|
792 | 7cff87ff | Alexander Graf | ide_exec_cmd(bus, val); |
793 | 7cff87ff | Alexander Graf | break;
|
794 | 7cff87ff | Alexander Graf | } |
795 | 7cff87ff | Alexander Graf | } |
796 | 7cff87ff | Alexander Graf | |
797 | 7cff87ff | Alexander Graf | |
798 | 7cff87ff | Alexander Graf | void ide_exec_cmd(IDEBus *bus, uint32_t val)
|
799 | 7cff87ff | Alexander Graf | { |
800 | 7cff87ff | Alexander Graf | IDEState *s; |
801 | 7cff87ff | Alexander Graf | int n;
|
802 | 7cff87ff | Alexander Graf | int lba48 = 0; |
803 | 7cff87ff | Alexander Graf | |
804 | 5391d806 | bellard | #if defined(DEBUG_IDE)
|
805 | 6ef2ba5e | Alexander Graf | printf("ide: CMD=%02x\n", val);
|
806 | 5391d806 | bellard | #endif
|
807 | 6ef2ba5e | Alexander Graf | s = idebus_active_if(bus); |
808 | 6ef2ba5e | Alexander Graf | /* ignore commands to non existant slave */
|
809 | 6ef2ba5e | Alexander Graf | if (s != bus->ifs && !s->bs)
|
810 | 6ef2ba5e | Alexander Graf | return;
|
811 | c2ff060f | bellard | |
812 | 6ef2ba5e | Alexander Graf | /* Only DEVICE RESET is allowed while BSY or/and DRQ are set */
|
813 | 6ef2ba5e | Alexander Graf | if ((s->status & (BUSY_STAT|DRQ_STAT)) && val != WIN_DEVICE_RESET)
|
814 | 6ef2ba5e | Alexander Graf | return;
|
815 | fcdd25ab | aliguori | |
816 | 6ef2ba5e | Alexander Graf | switch(val) {
|
817 | 6ef2ba5e | Alexander Graf | case WIN_IDENTIFY:
|
818 | 6ef2ba5e | Alexander Graf | if (s->bs && s->drive_kind != IDE_CD) {
|
819 | 6ef2ba5e | Alexander Graf | if (s->drive_kind != IDE_CFATA)
|
820 | 6ef2ba5e | Alexander Graf | ide_identify(s); |
821 | 6ef2ba5e | Alexander Graf | else
|
822 | 6ef2ba5e | Alexander Graf | ide_cfata_identify(s); |
823 | 769bec72 | bellard | s->status = READY_STAT | SEEK_STAT; |
824 | 6ef2ba5e | Alexander Graf | ide_transfer_start(s, s->io_buffer, 512, ide_transfer_stop);
|
825 | 6ef2ba5e | Alexander Graf | } else {
|
826 | 6ef2ba5e | Alexander Graf | if (s->drive_kind == IDE_CD) {
|
827 | 6ef2ba5e | Alexander Graf | ide_set_signature(s); |
828 | 5391d806 | bellard | } |
829 | 6ef2ba5e | Alexander Graf | ide_abort_command(s); |
830 | 6ef2ba5e | Alexander Graf | } |
831 | 6ef2ba5e | Alexander Graf | ide_set_irq(s->bus); |
832 | 6ef2ba5e | Alexander Graf | break;
|
833 | 6ef2ba5e | Alexander Graf | case WIN_SPECIFY:
|
834 | 6ef2ba5e | Alexander Graf | case WIN_RECAL:
|
835 | 6ef2ba5e | Alexander Graf | s->error = 0;
|
836 | 6ef2ba5e | Alexander Graf | s->status = READY_STAT | SEEK_STAT; |
837 | 6ef2ba5e | Alexander Graf | ide_set_irq(s->bus); |
838 | 6ef2ba5e | Alexander Graf | break;
|
839 | 6ef2ba5e | Alexander Graf | case WIN_SETMULT:
|
840 | 6ef2ba5e | Alexander Graf | if (s->drive_kind == IDE_CFATA && s->nsector == 0) { |
841 | 6ef2ba5e | Alexander Graf | /* Disable Read and Write Multiple */
|
842 | 6ef2ba5e | Alexander Graf | s->mult_sectors = 0;
|
843 | 41a2b959 | aliguori | s->status = READY_STAT | SEEK_STAT; |
844 | 6ef2ba5e | Alexander Graf | } else if ((s->nsector & 0xff) != 0 && |
845 | 6ef2ba5e | Alexander Graf | ((s->nsector & 0xff) > MAX_MULT_SECTORS ||
|
846 | 6ef2ba5e | Alexander Graf | (s->nsector & (s->nsector - 1)) != 0)) { |
847 | 6ef2ba5e | Alexander Graf | ide_abort_command(s); |
848 | 6ef2ba5e | Alexander Graf | } else {
|
849 | 6ef2ba5e | Alexander Graf | s->mult_sectors = s->nsector & 0xff;
|
850 | 6ef2ba5e | Alexander Graf | s->status = READY_STAT | SEEK_STAT; |
851 | 6ef2ba5e | Alexander Graf | } |
852 | 6ef2ba5e | Alexander Graf | ide_set_irq(s->bus); |
853 | 6ef2ba5e | Alexander Graf | break;
|
854 | 6ef2ba5e | Alexander Graf | case WIN_VERIFY_EXT:
|
855 | 6ef2ba5e | Alexander Graf | lba48 = 1;
|
856 | 6ef2ba5e | Alexander Graf | case WIN_VERIFY:
|
857 | 6ef2ba5e | Alexander Graf | case WIN_VERIFY_ONCE:
|
858 | 6ef2ba5e | Alexander Graf | /* do sector number check ? */
|
859 | 6ef2ba5e | Alexander Graf | ide_cmd_lba48_transform(s, lba48); |
860 | 6ef2ba5e | Alexander Graf | s->status = READY_STAT | SEEK_STAT; |
861 | 6ef2ba5e | Alexander Graf | ide_set_irq(s->bus); |
862 | 6ef2ba5e | Alexander Graf | break;
|
863 | c2ff060f | bellard | case WIN_READ_EXT:
|
864 | 6ef2ba5e | Alexander Graf | lba48 = 1;
|
865 | 6ef2ba5e | Alexander Graf | case WIN_READ:
|
866 | 6ef2ba5e | Alexander Graf | case WIN_READ_ONCE:
|
867 | 6ef2ba5e | Alexander Graf | if (!s->bs)
|
868 | 6ef2ba5e | Alexander Graf | goto abort_cmd;
|
869 | 6ef2ba5e | Alexander Graf | ide_cmd_lba48_transform(s, lba48); |
870 | 6ef2ba5e | Alexander Graf | s->req_nb_sectors = 1;
|
871 | 6ef2ba5e | Alexander Graf | ide_sector_read(s); |
872 | 6ef2ba5e | Alexander Graf | break;
|
873 | c2ff060f | bellard | case WIN_WRITE_EXT:
|
874 | 6ef2ba5e | Alexander Graf | lba48 = 1;
|
875 | 6ef2ba5e | Alexander Graf | case WIN_WRITE:
|
876 | 6ef2ba5e | Alexander Graf | case WIN_WRITE_ONCE:
|
877 | 6ef2ba5e | Alexander Graf | case CFA_WRITE_SECT_WO_ERASE:
|
878 | 6ef2ba5e | Alexander Graf | case WIN_WRITE_VERIFY:
|
879 | 6ef2ba5e | Alexander Graf | ide_cmd_lba48_transform(s, lba48); |
880 | 6ef2ba5e | Alexander Graf | s->error = 0;
|
881 | 6ef2ba5e | Alexander Graf | s->status = SEEK_STAT | READY_STAT; |
882 | 6ef2ba5e | Alexander Graf | s->req_nb_sectors = 1;
|
883 | 6ef2ba5e | Alexander Graf | ide_transfer_start(s, s->io_buffer, 512, ide_sector_write);
|
884 | 6ef2ba5e | Alexander Graf | s->media_changed = 1;
|
885 | 6ef2ba5e | Alexander Graf | break;
|
886 | c2ff060f | bellard | case WIN_MULTREAD_EXT:
|
887 | 6ef2ba5e | Alexander Graf | lba48 = 1;
|
888 | 6ef2ba5e | Alexander Graf | case WIN_MULTREAD:
|
889 | 6ef2ba5e | Alexander Graf | if (!s->mult_sectors)
|
890 | 6ef2ba5e | Alexander Graf | goto abort_cmd;
|
891 | 6ef2ba5e | Alexander Graf | ide_cmd_lba48_transform(s, lba48); |
892 | 6ef2ba5e | Alexander Graf | s->req_nb_sectors = s->mult_sectors; |
893 | 6ef2ba5e | Alexander Graf | ide_sector_read(s); |
894 | 6ef2ba5e | Alexander Graf | break;
|
895 | 6ef2ba5e | Alexander Graf | case WIN_MULTWRITE_EXT:
|
896 | 6ef2ba5e | Alexander Graf | lba48 = 1;
|
897 | 6ef2ba5e | Alexander Graf | case WIN_MULTWRITE:
|
898 | 6ef2ba5e | Alexander Graf | case CFA_WRITE_MULTI_WO_ERASE:
|
899 | 6ef2ba5e | Alexander Graf | if (!s->mult_sectors)
|
900 | 6ef2ba5e | Alexander Graf | goto abort_cmd;
|
901 | 6ef2ba5e | Alexander Graf | ide_cmd_lba48_transform(s, lba48); |
902 | 6ef2ba5e | Alexander Graf | s->error = 0;
|
903 | 6ef2ba5e | Alexander Graf | s->status = SEEK_STAT | READY_STAT; |
904 | 6ef2ba5e | Alexander Graf | s->req_nb_sectors = s->mult_sectors; |
905 | 6ef2ba5e | Alexander Graf | n = s->nsector; |
906 | 6ef2ba5e | Alexander Graf | if (n > s->req_nb_sectors)
|
907 | 6ef2ba5e | Alexander Graf | n = s->req_nb_sectors; |
908 | 6ef2ba5e | Alexander Graf | ide_transfer_start(s, s->io_buffer, 512 * n, ide_sector_write);
|
909 | 6ef2ba5e | Alexander Graf | s->media_changed = 1;
|
910 | 6ef2ba5e | Alexander Graf | break;
|
911 | c2ff060f | bellard | case WIN_READDMA_EXT:
|
912 | 6ef2ba5e | Alexander Graf | lba48 = 1;
|
913 | 6ef2ba5e | Alexander Graf | case WIN_READDMA:
|
914 | 6ef2ba5e | Alexander Graf | case WIN_READDMA_ONCE:
|
915 | 6ef2ba5e | Alexander Graf | if (!s->bs)
|
916 | 6ef2ba5e | Alexander Graf | goto abort_cmd;
|
917 | 6ef2ba5e | Alexander Graf | ide_cmd_lba48_transform(s, lba48); |
918 | cd369c46 | Christoph Hellwig | ide_sector_start_dma(s, 1);
|
919 | 6ef2ba5e | Alexander Graf | break;
|
920 | c2ff060f | bellard | case WIN_WRITEDMA_EXT:
|
921 | 6ef2ba5e | Alexander Graf | lba48 = 1;
|
922 | 6ef2ba5e | Alexander Graf | case WIN_WRITEDMA:
|
923 | 6ef2ba5e | Alexander Graf | case WIN_WRITEDMA_ONCE:
|
924 | 6ef2ba5e | Alexander Graf | if (!s->bs)
|
925 | 6ef2ba5e | Alexander Graf | goto abort_cmd;
|
926 | 6ef2ba5e | Alexander Graf | ide_cmd_lba48_transform(s, lba48); |
927 | cd369c46 | Christoph Hellwig | ide_sector_start_dma(s, 0);
|
928 | 6ef2ba5e | Alexander Graf | s->media_changed = 1;
|
929 | 6ef2ba5e | Alexander Graf | break;
|
930 | 6ef2ba5e | Alexander Graf | case WIN_READ_NATIVE_MAX_EXT:
|
931 | 6ef2ba5e | Alexander Graf | lba48 = 1;
|
932 | 6ef2ba5e | Alexander Graf | case WIN_READ_NATIVE_MAX:
|
933 | 6ef2ba5e | Alexander Graf | ide_cmd_lba48_transform(s, lba48); |
934 | 6ef2ba5e | Alexander Graf | ide_set_sector(s, s->nb_sectors - 1);
|
935 | 6ef2ba5e | Alexander Graf | s->status = READY_STAT | SEEK_STAT; |
936 | 6ef2ba5e | Alexander Graf | ide_set_irq(s->bus); |
937 | 6ef2ba5e | Alexander Graf | break;
|
938 | 6ef2ba5e | Alexander Graf | case WIN_CHECKPOWERMODE1:
|
939 | 6ef2ba5e | Alexander Graf | case WIN_CHECKPOWERMODE2:
|
940 | b93af93d | Brian Wheeler | s->error = 0;
|
941 | 6ef2ba5e | Alexander Graf | s->nsector = 0xff; /* device active or idle */ |
942 | 6ef2ba5e | Alexander Graf | s->status = READY_STAT | SEEK_STAT; |
943 | 6ef2ba5e | Alexander Graf | ide_set_irq(s->bus); |
944 | 6ef2ba5e | Alexander Graf | break;
|
945 | 6ef2ba5e | Alexander Graf | case WIN_SETFEATURES:
|
946 | 6ef2ba5e | Alexander Graf | if (!s->bs)
|
947 | 6ef2ba5e | Alexander Graf | goto abort_cmd;
|
948 | 6ef2ba5e | Alexander Graf | /* XXX: valid for CDROM ? */
|
949 | 6ef2ba5e | Alexander Graf | switch(s->feature) {
|
950 | 6ef2ba5e | Alexander Graf | case 0xcc: /* reverting to power-on defaults enable */ |
951 | 6ef2ba5e | Alexander Graf | case 0x66: /* reverting to power-on defaults disable */ |
952 | 6ef2ba5e | Alexander Graf | case 0x02: /* write cache enable */ |
953 | 6ef2ba5e | Alexander Graf | case 0x82: /* write cache disable */ |
954 | 6ef2ba5e | Alexander Graf | case 0xaa: /* read look-ahead enable */ |
955 | 6ef2ba5e | Alexander Graf | case 0x55: /* read look-ahead disable */ |
956 | 6ef2ba5e | Alexander Graf | case 0x05: /* set advanced power management mode */ |
957 | 6ef2ba5e | Alexander Graf | case 0x85: /* disable advanced power management mode */ |
958 | 6ef2ba5e | Alexander Graf | case 0x69: /* NOP */ |
959 | 6ef2ba5e | Alexander Graf | case 0x67: /* NOP */ |
960 | 6ef2ba5e | Alexander Graf | case 0x96: /* NOP */ |
961 | 6ef2ba5e | Alexander Graf | case 0x9a: /* NOP */ |
962 | 6ef2ba5e | Alexander Graf | case 0x42: /* enable Automatic Acoustic Mode */ |
963 | 6ef2ba5e | Alexander Graf | case 0xc2: /* disable Automatic Acoustic Mode */ |
964 | 41a2b959 | aliguori | s->status = READY_STAT | SEEK_STAT; |
965 | 9cdd03a7 | Gerd Hoffmann | ide_set_irq(s->bus); |
966 | a136e5a8 | bellard | break;
|
967 | 6ef2ba5e | Alexander Graf | case 0x03: { /* set transfer mode */ |
968 | 94458802 | bellard | uint8_t val = s->nsector & 0x07;
|
969 | 6ef2ba5e | Alexander Graf | uint16_t *identify_data = (uint16_t *)s->identify_data; |
970 | 94458802 | bellard | |
971 | 94458802 | bellard | switch (s->nsector >> 3) { |
972 | 6ef2ba5e | Alexander Graf | case 0x00: /* pio default */ |
973 | 6ef2ba5e | Alexander Graf | case 0x01: /* pio mode */ |
974 | 96c35ceb | Juan Quintela | put_le16(identify_data + 62,0x07); |
975 | 96c35ceb | Juan Quintela | put_le16(identify_data + 63,0x07); |
976 | 96c35ceb | Juan Quintela | put_le16(identify_data + 88,0x3f); |
977 | d1b5c20d | ths | break;
|
978 | 6ef2ba5e | Alexander Graf | case 0x02: /* sigle word dma mode*/ |
979 | 96c35ceb | Juan Quintela | put_le16(identify_data + 62,0x07 | (1 << (val + 8))); |
980 | 96c35ceb | Juan Quintela | put_le16(identify_data + 63,0x07); |
981 | 96c35ceb | Juan Quintela | put_le16(identify_data + 88,0x3f); |
982 | 94458802 | bellard | break;
|
983 | 6ef2ba5e | Alexander Graf | case 0x04: /* mdma mode */ |
984 | 96c35ceb | Juan Quintela | put_le16(identify_data + 62,0x07); |
985 | 96c35ceb | Juan Quintela | put_le16(identify_data + 63,0x07 | (1 << (val + 8))); |
986 | 96c35ceb | Juan Quintela | put_le16(identify_data + 88,0x3f); |
987 | 94458802 | bellard | break;
|
988 | 6ef2ba5e | Alexander Graf | case 0x08: /* udma mode */ |
989 | 96c35ceb | Juan Quintela | put_le16(identify_data + 62,0x07); |
990 | 96c35ceb | Juan Quintela | put_le16(identify_data + 63,0x07); |
991 | 96c35ceb | Juan Quintela | put_le16(identify_data + 88,0x3f | (1 << (val + 8))); |
992 | 94458802 | bellard | break;
|
993 | 6ef2ba5e | Alexander Graf | default:
|
994 | 94458802 | bellard | goto abort_cmd;
|
995 | 94458802 | bellard | } |
996 | 4fbfcd6d | aurel32 | s->status = READY_STAT | SEEK_STAT; |
997 | 9cdd03a7 | Gerd Hoffmann | ide_set_irq(s->bus); |
998 | 4fbfcd6d | aurel32 | break;
|
999 | 6ef2ba5e | Alexander Graf | } |
1000 | 6ef2ba5e | Alexander Graf | default:
|
1001 | 6ef2ba5e | Alexander Graf | goto abort_cmd;
|
1002 | 6ef2ba5e | Alexander Graf | } |
1003 | 6ef2ba5e | Alexander Graf | break;
|
1004 | 6ef2ba5e | Alexander Graf | case WIN_FLUSH_CACHE:
|
1005 | 6ef2ba5e | Alexander Graf | case WIN_FLUSH_CACHE_EXT:
|
1006 | 6ef2ba5e | Alexander Graf | ide_flush_cache(s); |
1007 | 6ef2ba5e | Alexander Graf | break;
|
1008 | 6ef2ba5e | Alexander Graf | case WIN_STANDBY:
|
1009 | 6ef2ba5e | Alexander Graf | case WIN_STANDBY2:
|
1010 | 6ef2ba5e | Alexander Graf | case WIN_STANDBYNOW1:
|
1011 | 6ef2ba5e | Alexander Graf | case WIN_STANDBYNOW2:
|
1012 | 6ef2ba5e | Alexander Graf | case WIN_IDLEIMMEDIATE:
|
1013 | 6ef2ba5e | Alexander Graf | case CFA_IDLEIMMEDIATE:
|
1014 | 6ef2ba5e | Alexander Graf | case WIN_SETIDLE1:
|
1015 | 6ef2ba5e | Alexander Graf | case WIN_SETIDLE2:
|
1016 | 6ef2ba5e | Alexander Graf | case WIN_SLEEPNOW1:
|
1017 | 6ef2ba5e | Alexander Graf | case WIN_SLEEPNOW2:
|
1018 | 6ef2ba5e | Alexander Graf | s->status = READY_STAT; |
1019 | 6ef2ba5e | Alexander Graf | ide_set_irq(s->bus); |
1020 | 6ef2ba5e | Alexander Graf | break;
|
1021 | 6ef2ba5e | Alexander Graf | case WIN_SEEK:
|
1022 | 6ef2ba5e | Alexander Graf | if(s->drive_kind == IDE_CD)
|
1023 | 6ef2ba5e | Alexander Graf | goto abort_cmd;
|
1024 | 6ef2ba5e | Alexander Graf | /* XXX: Check that seek is within bounds */
|
1025 | 6ef2ba5e | Alexander Graf | s->status = READY_STAT | SEEK_STAT; |
1026 | 6ef2ba5e | Alexander Graf | ide_set_irq(s->bus); |
1027 | 6ef2ba5e | Alexander Graf | break;
|
1028 | 6ef2ba5e | Alexander Graf | /* ATAPI commands */
|
1029 | 6ef2ba5e | Alexander Graf | case WIN_PIDENTIFY:
|
1030 | 6ef2ba5e | Alexander Graf | if (s->drive_kind == IDE_CD) {
|
1031 | 6ef2ba5e | Alexander Graf | ide_atapi_identify(s); |
1032 | 41a2b959 | aliguori | s->status = READY_STAT | SEEK_STAT; |
1033 | 6ef2ba5e | Alexander Graf | ide_transfer_start(s, s->io_buffer, 512, ide_transfer_stop);
|
1034 | 6ef2ba5e | Alexander Graf | } else {
|
1035 | 6ef2ba5e | Alexander Graf | ide_abort_command(s); |
1036 | 6ef2ba5e | Alexander Graf | } |
1037 | 6ef2ba5e | Alexander Graf | ide_set_irq(s->bus); |
1038 | 6ef2ba5e | Alexander Graf | break;
|
1039 | 6ef2ba5e | Alexander Graf | case WIN_DIAGNOSE:
|
1040 | 6ef2ba5e | Alexander Graf | ide_set_signature(s); |
1041 | 6ef2ba5e | Alexander Graf | if (s->drive_kind == IDE_CD)
|
1042 | 6ef2ba5e | Alexander Graf | s->status = 0; /* ATAPI spec (v6) section 9.10 defines packet |
1043 | 6ef2ba5e | Alexander Graf | * devices to return a clear status register
|
1044 | 6ef2ba5e | Alexander Graf | * with READY_STAT *not* set. */
|
1045 | 6ef2ba5e | Alexander Graf | else
|
1046 | 41a2b959 | aliguori | s->status = READY_STAT | SEEK_STAT; |
1047 | 6ef2ba5e | Alexander Graf | s->error = 0x01; /* Device 0 passed, Device 1 passed or not |
1048 | 6ef2ba5e | Alexander Graf | * present.
|
1049 | 6ef2ba5e | Alexander Graf | */
|
1050 | 6ef2ba5e | Alexander Graf | ide_set_irq(s->bus); |
1051 | 6ef2ba5e | Alexander Graf | break;
|
1052 | 6ef2ba5e | Alexander Graf | case WIN_SRST:
|
1053 | 6ef2ba5e | Alexander Graf | if (s->drive_kind != IDE_CD)
|
1054 | 6ef2ba5e | Alexander Graf | goto abort_cmd;
|
1055 | 6ef2ba5e | Alexander Graf | ide_set_signature(s); |
1056 | 6ef2ba5e | Alexander Graf | s->status = 0x00; /* NOTE: READY is _not_ set */ |
1057 | 6ef2ba5e | Alexander Graf | s->error = 0x01;
|
1058 | 6ef2ba5e | Alexander Graf | break;
|
1059 | 6ef2ba5e | Alexander Graf | case WIN_PACKETCMD:
|
1060 | 6ef2ba5e | Alexander Graf | if (s->drive_kind != IDE_CD)
|
1061 | 6ef2ba5e | Alexander Graf | goto abort_cmd;
|
1062 | 6ef2ba5e | Alexander Graf | /* overlapping commands not supported */
|
1063 | 6ef2ba5e | Alexander Graf | if (s->feature & 0x02) |
1064 | 6ef2ba5e | Alexander Graf | goto abort_cmd;
|
1065 | 6ef2ba5e | Alexander Graf | s->status = READY_STAT | SEEK_STAT; |
1066 | 6ef2ba5e | Alexander Graf | s->atapi_dma = s->feature & 1;
|
1067 | 6ef2ba5e | Alexander Graf | s->nsector = 1;
|
1068 | 6ef2ba5e | Alexander Graf | ide_transfer_start(s, s->io_buffer, ATAPI_PACKET_SIZE, |
1069 | 6ef2ba5e | Alexander Graf | ide_atapi_cmd); |
1070 | 6ef2ba5e | Alexander Graf | break;
|
1071 | 6ef2ba5e | Alexander Graf | /* CF-ATA commands */
|
1072 | 6ef2ba5e | Alexander Graf | case CFA_REQ_EXT_ERROR_CODE:
|
1073 | 6ef2ba5e | Alexander Graf | if (s->drive_kind != IDE_CFATA)
|
1074 | 6ef2ba5e | Alexander Graf | goto abort_cmd;
|
1075 | 6ef2ba5e | Alexander Graf | s->error = 0x09; /* miscellaneous error */ |
1076 | 6ef2ba5e | Alexander Graf | s->status = READY_STAT | SEEK_STAT; |
1077 | 6ef2ba5e | Alexander Graf | ide_set_irq(s->bus); |
1078 | 6ef2ba5e | Alexander Graf | break;
|
1079 | 6ef2ba5e | Alexander Graf | case CFA_ERASE_SECTORS:
|
1080 | 6ef2ba5e | Alexander Graf | case CFA_WEAR_LEVEL:
|
1081 | 6ef2ba5e | Alexander Graf | if (s->drive_kind != IDE_CFATA)
|
1082 | 6ef2ba5e | Alexander Graf | goto abort_cmd;
|
1083 | 6ef2ba5e | Alexander Graf | if (val == CFA_WEAR_LEVEL)
|
1084 | 6ef2ba5e | Alexander Graf | s->nsector = 0;
|
1085 | 6ef2ba5e | Alexander Graf | if (val == CFA_ERASE_SECTORS)
|
1086 | 6ef2ba5e | Alexander Graf | s->media_changed = 1;
|
1087 | 6ef2ba5e | Alexander Graf | s->error = 0x00;
|
1088 | 6ef2ba5e | Alexander Graf | s->status = READY_STAT | SEEK_STAT; |
1089 | 6ef2ba5e | Alexander Graf | ide_set_irq(s->bus); |
1090 | 6ef2ba5e | Alexander Graf | break;
|
1091 | 6ef2ba5e | Alexander Graf | case CFA_TRANSLATE_SECTOR:
|
1092 | 6ef2ba5e | Alexander Graf | if (s->drive_kind != IDE_CFATA)
|
1093 | 6ef2ba5e | Alexander Graf | goto abort_cmd;
|
1094 | 6ef2ba5e | Alexander Graf | s->error = 0x00;
|
1095 | 6ef2ba5e | Alexander Graf | s->status = READY_STAT | SEEK_STAT; |
1096 | 6ef2ba5e | Alexander Graf | memset(s->io_buffer, 0, 0x200); |
1097 | 6ef2ba5e | Alexander Graf | s->io_buffer[0x00] = s->hcyl; /* Cyl MSB */ |
1098 | 6ef2ba5e | Alexander Graf | s->io_buffer[0x01] = s->lcyl; /* Cyl LSB */ |
1099 | 6ef2ba5e | Alexander Graf | s->io_buffer[0x02] = s->select; /* Head */ |
1100 | 6ef2ba5e | Alexander Graf | s->io_buffer[0x03] = s->sector; /* Sector */ |
1101 | 6ef2ba5e | Alexander Graf | s->io_buffer[0x04] = ide_get_sector(s) >> 16; /* LBA MSB */ |
1102 | 6ef2ba5e | Alexander Graf | s->io_buffer[0x05] = ide_get_sector(s) >> 8; /* LBA */ |
1103 | 6ef2ba5e | Alexander Graf | s->io_buffer[0x06] = ide_get_sector(s) >> 0; /* LBA LSB */ |
1104 | 6ef2ba5e | Alexander Graf | s->io_buffer[0x13] = 0x00; /* Erase flag */ |
1105 | 6ef2ba5e | Alexander Graf | s->io_buffer[0x18] = 0x00; /* Hot count */ |
1106 | 6ef2ba5e | Alexander Graf | s->io_buffer[0x19] = 0x00; /* Hot count */ |
1107 | 6ef2ba5e | Alexander Graf | s->io_buffer[0x1a] = 0x01; /* Hot count */ |
1108 | 6ef2ba5e | Alexander Graf | ide_transfer_start(s, s->io_buffer, 0x200, ide_transfer_stop);
|
1109 | 6ef2ba5e | Alexander Graf | ide_set_irq(s->bus); |
1110 | 6ef2ba5e | Alexander Graf | break;
|
1111 | 6ef2ba5e | Alexander Graf | case CFA_ACCESS_METADATA_STORAGE:
|
1112 | 6ef2ba5e | Alexander Graf | if (s->drive_kind != IDE_CFATA)
|
1113 | 6ef2ba5e | Alexander Graf | goto abort_cmd;
|
1114 | 6ef2ba5e | Alexander Graf | switch (s->feature) {
|
1115 | 6ef2ba5e | Alexander Graf | case 0x02: /* Inquiry Metadata Storage */ |
1116 | 6ef2ba5e | Alexander Graf | ide_cfata_metadata_inquiry(s); |
1117 | 201a51fc | balrog | break;
|
1118 | 6ef2ba5e | Alexander Graf | case 0x03: /* Read Metadata Storage */ |
1119 | 6ef2ba5e | Alexander Graf | ide_cfata_metadata_read(s); |
1120 | 201a51fc | balrog | break;
|
1121 | 6ef2ba5e | Alexander Graf | case 0x04: /* Write Metadata Storage */ |
1122 | 6ef2ba5e | Alexander Graf | ide_cfata_metadata_write(s); |
1123 | 201a51fc | balrog | break;
|
1124 | 6ef2ba5e | Alexander Graf | default:
|
1125 | 6ef2ba5e | Alexander Graf | goto abort_cmd;
|
1126 | 6ef2ba5e | Alexander Graf | } |
1127 | 6ef2ba5e | Alexander Graf | ide_transfer_start(s, s->io_buffer, 0x200, ide_transfer_stop);
|
1128 | 6ef2ba5e | Alexander Graf | s->status = 0x00; /* NOTE: READY is _not_ set */ |
1129 | 6ef2ba5e | Alexander Graf | ide_set_irq(s->bus); |
1130 | 6ef2ba5e | Alexander Graf | break;
|
1131 | 6ef2ba5e | Alexander Graf | case IBM_SENSE_CONDITION:
|
1132 | 6ef2ba5e | Alexander Graf | if (s->drive_kind != IDE_CFATA)
|
1133 | 6ef2ba5e | Alexander Graf | goto abort_cmd;
|
1134 | 6ef2ba5e | Alexander Graf | switch (s->feature) {
|
1135 | 6ef2ba5e | Alexander Graf | case 0x01: /* sense temperature in device */ |
1136 | 6ef2ba5e | Alexander Graf | s->nsector = 0x50; /* +20 C */ |
1137 | 201a51fc | balrog | break;
|
1138 | 6ef2ba5e | Alexander Graf | default:
|
1139 | 6ef2ba5e | Alexander Graf | goto abort_cmd;
|
1140 | 6ef2ba5e | Alexander Graf | } |
1141 | 6ef2ba5e | Alexander Graf | s->status = READY_STAT | SEEK_STAT; |
1142 | 6ef2ba5e | Alexander Graf | ide_set_irq(s->bus); |
1143 | 6ef2ba5e | Alexander Graf | break;
|
1144 | e8b54394 | Brian Wheeler | |
1145 | e8b54394 | Brian Wheeler | case WIN_SMART:
|
1146 | 6ef2ba5e | Alexander Graf | if (s->drive_kind == IDE_CD)
|
1147 | e8b54394 | Brian Wheeler | goto abort_cmd;
|
1148 | 6ef2ba5e | Alexander Graf | if (s->hcyl != 0xc2 || s->lcyl != 0x4f) |
1149 | e8b54394 | Brian Wheeler | goto abort_cmd;
|
1150 | 6ef2ba5e | Alexander Graf | if (!s->smart_enabled && s->feature != SMART_ENABLE)
|
1151 | e8b54394 | Brian Wheeler | goto abort_cmd;
|
1152 | 6ef2ba5e | Alexander Graf | switch (s->feature) {
|
1153 | 6ef2ba5e | Alexander Graf | case SMART_DISABLE:
|
1154 | e8b54394 | Brian Wheeler | s->smart_enabled = 0;
|
1155 | e8b54394 | Brian Wheeler | s->status = READY_STAT | SEEK_STAT; |
1156 | 9cdd03a7 | Gerd Hoffmann | ide_set_irq(s->bus); |
1157 | e8b54394 | Brian Wheeler | break;
|
1158 | 6ef2ba5e | Alexander Graf | case SMART_ENABLE:
|
1159 | e8b54394 | Brian Wheeler | s->smart_enabled = 1;
|
1160 | e8b54394 | Brian Wheeler | s->status = READY_STAT | SEEK_STAT; |
1161 | 9cdd03a7 | Gerd Hoffmann | ide_set_irq(s->bus); |
1162 | e8b54394 | Brian Wheeler | break;
|
1163 | 6ef2ba5e | Alexander Graf | case SMART_ATTR_AUTOSAVE:
|
1164 | e8b54394 | Brian Wheeler | switch (s->sector) {
|
1165 | e8b54394 | Brian Wheeler | case 0x00: |
1166 | 6ef2ba5e | Alexander Graf | s->smart_autosave = 0;
|
1167 | 6ef2ba5e | Alexander Graf | break;
|
1168 | e8b54394 | Brian Wheeler | case 0xf1: |
1169 | 6ef2ba5e | Alexander Graf | s->smart_autosave = 1;
|
1170 | 6ef2ba5e | Alexander Graf | break;
|
1171 | e8b54394 | Brian Wheeler | default:
|
1172 | 6ef2ba5e | Alexander Graf | goto abort_cmd;
|
1173 | e8b54394 | Brian Wheeler | } |
1174 | e8b54394 | Brian Wheeler | s->status = READY_STAT | SEEK_STAT; |
1175 | 9cdd03a7 | Gerd Hoffmann | ide_set_irq(s->bus); |
1176 | e8b54394 | Brian Wheeler | break;
|
1177 | 6ef2ba5e | Alexander Graf | case SMART_STATUS:
|
1178 | e8b54394 | Brian Wheeler | if (!s->smart_errors) {
|
1179 | 6ef2ba5e | Alexander Graf | s->hcyl = 0xc2;
|
1180 | 6ef2ba5e | Alexander Graf | s->lcyl = 0x4f;
|
1181 | e8b54394 | Brian Wheeler | } else {
|
1182 | 6ef2ba5e | Alexander Graf | s->hcyl = 0x2c;
|
1183 | 6ef2ba5e | Alexander Graf | s->lcyl = 0xf4;
|
1184 | e8b54394 | Brian Wheeler | } |
1185 | e8b54394 | Brian Wheeler | s->status = READY_STAT | SEEK_STAT; |
1186 | 9cdd03a7 | Gerd Hoffmann | ide_set_irq(s->bus); |
1187 | e8b54394 | Brian Wheeler | break;
|
1188 | 6ef2ba5e | Alexander Graf | case SMART_READ_THRESH:
|
1189 | e8b54394 | Brian Wheeler | memset(s->io_buffer, 0, 0x200); |
1190 | e8b54394 | Brian Wheeler | s->io_buffer[0] = 0x01; /* smart struct version */ |
1191 | e8b54394 | Brian Wheeler | for (n=0; n<30; n++) { |
1192 | 6ef2ba5e | Alexander Graf | if (smart_attributes[n][0] == 0) |
1193 | e8b54394 | Brian Wheeler | break;
|
1194 | 6ef2ba5e | Alexander Graf | s->io_buffer[2+0+(n*12)] = smart_attributes[n][0]; |
1195 | b93af93d | Brian Wheeler | s->io_buffer[2+1+(n*12)] = smart_attributes[n][11]; |
1196 | e8b54394 | Brian Wheeler | } |
1197 | e8b54394 | Brian Wheeler | for (n=0; n<511; n++) /* checksum */ |
1198 | 6ef2ba5e | Alexander Graf | s->io_buffer[511] += s->io_buffer[n];
|
1199 | e8b54394 | Brian Wheeler | s->io_buffer[511] = 0x100 - s->io_buffer[511]; |
1200 | e8b54394 | Brian Wheeler | s->status = READY_STAT | SEEK_STAT; |
1201 | e8b54394 | Brian Wheeler | ide_transfer_start(s, s->io_buffer, 0x200, ide_transfer_stop);
|
1202 | 9cdd03a7 | Gerd Hoffmann | ide_set_irq(s->bus); |
1203 | e8b54394 | Brian Wheeler | break;
|
1204 | 6ef2ba5e | Alexander Graf | case SMART_READ_DATA:
|
1205 | e8b54394 | Brian Wheeler | memset(s->io_buffer, 0, 0x200); |
1206 | e8b54394 | Brian Wheeler | s->io_buffer[0] = 0x01; /* smart struct version */ |
1207 | e8b54394 | Brian Wheeler | for (n=0; n<30; n++) { |
1208 | b93af93d | Brian Wheeler | if (smart_attributes[n][0] == 0) { |
1209 | e8b54394 | Brian Wheeler | break;
|
1210 | b93af93d | Brian Wheeler | } |
1211 | b93af93d | Brian Wheeler | int i;
|
1212 | b93af93d | Brian Wheeler | for(i = 0; i < 11; i++) { |
1213 | b93af93d | Brian Wheeler | s->io_buffer[2+i+(n*12)] = smart_attributes[n][i]; |
1214 | b93af93d | Brian Wheeler | } |
1215 | e8b54394 | Brian Wheeler | } |
1216 | e8b54394 | Brian Wheeler | s->io_buffer[362] = 0x02 | (s->smart_autosave?0x80:0x00); |
1217 | e8b54394 | Brian Wheeler | if (s->smart_selftest_count == 0) { |
1218 | 6ef2ba5e | Alexander Graf | s->io_buffer[363] = 0; |
1219 | e8b54394 | Brian Wheeler | } else {
|
1220 | 6ef2ba5e | Alexander Graf | s->io_buffer[363] =
|
1221 | e8b54394 | Brian Wheeler | s->smart_selftest_data[3 +
|
1222 | 6ef2ba5e | Alexander Graf | (s->smart_selftest_count - 1) *
|
1223 | 6ef2ba5e | Alexander Graf | 24];
|
1224 | e8b54394 | Brian Wheeler | } |
1225 | e8b54394 | Brian Wheeler | s->io_buffer[364] = 0x20; |
1226 | e8b54394 | Brian Wheeler | s->io_buffer[365] = 0x01; |
1227 | e8b54394 | Brian Wheeler | /* offline data collection capacity: execute + self-test*/
|
1228 | e8b54394 | Brian Wheeler | s->io_buffer[367] = (1<<4 | 1<<3 | 1); |
1229 | e8b54394 | Brian Wheeler | s->io_buffer[368] = 0x03; /* smart capability (1) */ |
1230 | e8b54394 | Brian Wheeler | s->io_buffer[369] = 0x00; /* smart capability (2) */ |
1231 | e8b54394 | Brian Wheeler | s->io_buffer[370] = 0x01; /* error logging supported */ |
1232 | e8b54394 | Brian Wheeler | s->io_buffer[372] = 0x02; /* minutes for poll short test */ |
1233 | e8b54394 | Brian Wheeler | s->io_buffer[373] = 0x36; /* minutes for poll ext test */ |
1234 | e8b54394 | Brian Wheeler | s->io_buffer[374] = 0x01; /* minutes for poll conveyance */ |
1235 | e8b54394 | Brian Wheeler | |
1236 | e8b54394 | Brian Wheeler | for (n=0; n<511; n++) |
1237 | 6ef2ba5e | Alexander Graf | s->io_buffer[511] += s->io_buffer[n];
|
1238 | e8b54394 | Brian Wheeler | s->io_buffer[511] = 0x100 - s->io_buffer[511]; |
1239 | e8b54394 | Brian Wheeler | s->status = READY_STAT | SEEK_STAT; |
1240 | e8b54394 | Brian Wheeler | ide_transfer_start(s, s->io_buffer, 0x200, ide_transfer_stop);
|
1241 | 9cdd03a7 | Gerd Hoffmann | ide_set_irq(s->bus); |
1242 | e8b54394 | Brian Wheeler | break;
|
1243 | 6ef2ba5e | Alexander Graf | case SMART_READ_LOG:
|
1244 | e8b54394 | Brian Wheeler | switch (s->sector) {
|
1245 | e8b54394 | Brian Wheeler | case 0x01: /* summary smart error log */ |
1246 | 6ef2ba5e | Alexander Graf | memset(s->io_buffer, 0, 0x200); |
1247 | 6ef2ba5e | Alexander Graf | s->io_buffer[0] = 0x01; |
1248 | 6ef2ba5e | Alexander Graf | s->io_buffer[1] = 0x00; /* no error entries */ |
1249 | 6ef2ba5e | Alexander Graf | s->io_buffer[452] = s->smart_errors & 0xff; |
1250 | 6ef2ba5e | Alexander Graf | s->io_buffer[453] = (s->smart_errors & 0xff00) >> 8; |
1251 | e8b54394 | Brian Wheeler | |
1252 | 6ef2ba5e | Alexander Graf | for (n=0; n<511; n++) |
1253 | e8b54394 | Brian Wheeler | s->io_buffer[511] += s->io_buffer[n];
|
1254 | 6ef2ba5e | Alexander Graf | s->io_buffer[511] = 0x100 - s->io_buffer[511]; |
1255 | 6ef2ba5e | Alexander Graf | break;
|
1256 | e8b54394 | Brian Wheeler | case 0x06: /* smart self test log */ |
1257 | 6ef2ba5e | Alexander Graf | memset(s->io_buffer, 0, 0x200); |
1258 | 6ef2ba5e | Alexander Graf | s->io_buffer[0] = 0x01; |
1259 | 6ef2ba5e | Alexander Graf | if (s->smart_selftest_count == 0) { |
1260 | e8b54394 | Brian Wheeler | s->io_buffer[508] = 0; |
1261 | 6ef2ba5e | Alexander Graf | } else {
|
1262 | e8b54394 | Brian Wheeler | s->io_buffer[508] = s->smart_selftest_count;
|
1263 | e8b54394 | Brian Wheeler | for (n=2; n<506; n++) |
1264 | 6ef2ba5e | Alexander Graf | s->io_buffer[n] = s->smart_selftest_data[n]; |
1265 | 6ef2ba5e | Alexander Graf | } |
1266 | 6ef2ba5e | Alexander Graf | for (n=0; n<511; n++) |
1267 | e8b54394 | Brian Wheeler | s->io_buffer[511] += s->io_buffer[n];
|
1268 | 6ef2ba5e | Alexander Graf | s->io_buffer[511] = 0x100 - s->io_buffer[511]; |
1269 | 6ef2ba5e | Alexander Graf | break;
|
1270 | e8b54394 | Brian Wheeler | default:
|
1271 | 6ef2ba5e | Alexander Graf | goto abort_cmd;
|
1272 | e8b54394 | Brian Wheeler | } |
1273 | e8b54394 | Brian Wheeler | s->status = READY_STAT | SEEK_STAT; |
1274 | e8b54394 | Brian Wheeler | ide_transfer_start(s, s->io_buffer, 0x200, ide_transfer_stop);
|
1275 | 9cdd03a7 | Gerd Hoffmann | ide_set_irq(s->bus); |
1276 | e8b54394 | Brian Wheeler | break;
|
1277 | 6ef2ba5e | Alexander Graf | case SMART_EXECUTE_OFFLINE:
|
1278 | e8b54394 | Brian Wheeler | switch (s->sector) {
|
1279 | e8b54394 | Brian Wheeler | case 0: /* off-line routine */ |
1280 | e8b54394 | Brian Wheeler | case 1: /* short self test */ |
1281 | e8b54394 | Brian Wheeler | case 2: /* extended self test */ |
1282 | 6ef2ba5e | Alexander Graf | s->smart_selftest_count++; |
1283 | 6ef2ba5e | Alexander Graf | if(s->smart_selftest_count > 21) |
1284 | e8b54394 | Brian Wheeler | s->smart_selftest_count = 0;
|
1285 | 6ef2ba5e | Alexander Graf | n = 2 + (s->smart_selftest_count - 1) * 24; |
1286 | 6ef2ba5e | Alexander Graf | s->smart_selftest_data[n] = s->sector; |
1287 | 6ef2ba5e | Alexander Graf | s->smart_selftest_data[n+1] = 0x00; /* OK and finished */ |
1288 | 6ef2ba5e | Alexander Graf | s->smart_selftest_data[n+2] = 0x34; /* hour count lsb */ |
1289 | 6ef2ba5e | Alexander Graf | s->smart_selftest_data[n+3] = 0x12; /* hour count msb */ |
1290 | 6ef2ba5e | Alexander Graf | s->status = READY_STAT | SEEK_STAT; |
1291 | 6ef2ba5e | Alexander Graf | ide_set_irq(s->bus); |
1292 | 6ef2ba5e | Alexander Graf | break;
|
1293 | e8b54394 | Brian Wheeler | default:
|
1294 | 6ef2ba5e | Alexander Graf | goto abort_cmd;
|
1295 | e8b54394 | Brian Wheeler | } |
1296 | e8b54394 | Brian Wheeler | break;
|
1297 | 6ef2ba5e | Alexander Graf | default:
|
1298 | e8b54394 | Brian Wheeler | goto abort_cmd;
|
1299 | 6ef2ba5e | Alexander Graf | } |
1300 | 6ef2ba5e | Alexander Graf | break;
|
1301 | 6ef2ba5e | Alexander Graf | default:
|
1302 | 6ef2ba5e | Alexander Graf | abort_cmd:
|
1303 | 6ef2ba5e | Alexander Graf | ide_abort_command(s); |
1304 | 6ef2ba5e | Alexander Graf | ide_set_irq(s->bus); |
1305 | 6ef2ba5e | Alexander Graf | break;
|
1306 | 6ef2ba5e | Alexander Graf | } |
1307 | 5391d806 | bellard | } |
1308 | 5391d806 | bellard | |
1309 | 356721ae | Gerd Hoffmann | uint32_t ide_ioport_read(void *opaque, uint32_t addr1)
|
1310 | 5391d806 | bellard | { |
1311 | bcbdc4d3 | Gerd Hoffmann | IDEBus *bus = opaque; |
1312 | bcbdc4d3 | Gerd Hoffmann | IDEState *s = idebus_active_if(bus); |
1313 | 5391d806 | bellard | uint32_t addr; |
1314 | c2ff060f | bellard | int ret, hob;
|
1315 | 5391d806 | bellard | |
1316 | 5391d806 | bellard | addr = addr1 & 7;
|
1317 | c2ff060f | bellard | /* FIXME: HOB readback uses bit 7, but it's always set right now */
|
1318 | c2ff060f | bellard | //hob = s->select & (1 << 7);
|
1319 | c2ff060f | bellard | hob = 0;
|
1320 | 5391d806 | bellard | switch(addr) {
|
1321 | 5391d806 | bellard | case 0: |
1322 | 5391d806 | bellard | ret = 0xff;
|
1323 | 5391d806 | bellard | break;
|
1324 | 5391d806 | bellard | case 1: |
1325 | bcbdc4d3 | Gerd Hoffmann | if ((!bus->ifs[0].bs && !bus->ifs[1].bs) || |
1326 | bcbdc4d3 | Gerd Hoffmann | (s != bus->ifs && !s->bs)) |
1327 | c45c3d00 | bellard | ret = 0;
|
1328 | c2ff060f | bellard | else if (!hob) |
1329 | c45c3d00 | bellard | ret = s->error; |
1330 | c2ff060f | bellard | else
|
1331 | c2ff060f | bellard | ret = s->hob_feature; |
1332 | 5391d806 | bellard | break;
|
1333 | 5391d806 | bellard | case 2: |
1334 | bcbdc4d3 | Gerd Hoffmann | if (!bus->ifs[0].bs && !bus->ifs[1].bs) |
1335 | c45c3d00 | bellard | ret = 0;
|
1336 | c2ff060f | bellard | else if (!hob) |
1337 | c45c3d00 | bellard | ret = s->nsector & 0xff;
|
1338 | c2ff060f | bellard | else
|
1339 | c2ff060f | bellard | ret = s->hob_nsector; |
1340 | 5391d806 | bellard | break;
|
1341 | 5391d806 | bellard | case 3: |
1342 | bcbdc4d3 | Gerd Hoffmann | if (!bus->ifs[0].bs && !bus->ifs[1].bs) |
1343 | c45c3d00 | bellard | ret = 0;
|
1344 | c2ff060f | bellard | else if (!hob) |
1345 | c45c3d00 | bellard | ret = s->sector; |
1346 | c2ff060f | bellard | else
|
1347 | c2ff060f | bellard | ret = s->hob_sector; |
1348 | 5391d806 | bellard | break;
|
1349 | 5391d806 | bellard | case 4: |
1350 | bcbdc4d3 | Gerd Hoffmann | if (!bus->ifs[0].bs && !bus->ifs[1].bs) |
1351 | c45c3d00 | bellard | ret = 0;
|
1352 | c2ff060f | bellard | else if (!hob) |
1353 | c45c3d00 | bellard | ret = s->lcyl; |
1354 | c2ff060f | bellard | else
|
1355 | c2ff060f | bellard | ret = s->hob_lcyl; |
1356 | 5391d806 | bellard | break;
|
1357 | 5391d806 | bellard | case 5: |
1358 | bcbdc4d3 | Gerd Hoffmann | if (!bus->ifs[0].bs && !bus->ifs[1].bs) |
1359 | c45c3d00 | bellard | ret = 0;
|
1360 | c2ff060f | bellard | else if (!hob) |
1361 | c45c3d00 | bellard | ret = s->hcyl; |
1362 | c2ff060f | bellard | else
|
1363 | c2ff060f | bellard | ret = s->hob_hcyl; |
1364 | 5391d806 | bellard | break;
|
1365 | 5391d806 | bellard | case 6: |
1366 | bcbdc4d3 | Gerd Hoffmann | if (!bus->ifs[0].bs && !bus->ifs[1].bs) |
1367 | c45c3d00 | bellard | ret = 0;
|
1368 | c45c3d00 | bellard | else
|
1369 | 7ae98627 | bellard | ret = s->select; |
1370 | 5391d806 | bellard | break;
|
1371 | 5391d806 | bellard | default:
|
1372 | 5391d806 | bellard | case 7: |
1373 | bcbdc4d3 | Gerd Hoffmann | if ((!bus->ifs[0].bs && !bus->ifs[1].bs) || |
1374 | bcbdc4d3 | Gerd Hoffmann | (s != bus->ifs && !s->bs)) |
1375 | c45c3d00 | bellard | ret = 0;
|
1376 | c45c3d00 | bellard | else
|
1377 | c45c3d00 | bellard | ret = s->status; |
1378 | 9cdd03a7 | Gerd Hoffmann | qemu_irq_lower(bus->irq); |
1379 | 5391d806 | bellard | break;
|
1380 | 5391d806 | bellard | } |
1381 | 5391d806 | bellard | #ifdef DEBUG_IDE
|
1382 | 5391d806 | bellard | printf("ide: read addr=0x%x val=%02x\n", addr1, ret);
|
1383 | 5391d806 | bellard | #endif
|
1384 | 5391d806 | bellard | return ret;
|
1385 | 5391d806 | bellard | } |
1386 | 5391d806 | bellard | |
1387 | 356721ae | Gerd Hoffmann | uint32_t ide_status_read(void *opaque, uint32_t addr)
|
1388 | 5391d806 | bellard | { |
1389 | bcbdc4d3 | Gerd Hoffmann | IDEBus *bus = opaque; |
1390 | bcbdc4d3 | Gerd Hoffmann | IDEState *s = idebus_active_if(bus); |
1391 | 5391d806 | bellard | int ret;
|
1392 | 7ae98627 | bellard | |
1393 | bcbdc4d3 | Gerd Hoffmann | if ((!bus->ifs[0].bs && !bus->ifs[1].bs) || |
1394 | bcbdc4d3 | Gerd Hoffmann | (s != bus->ifs && !s->bs)) |
1395 | 7ae98627 | bellard | ret = 0;
|
1396 | 7ae98627 | bellard | else
|
1397 | 7ae98627 | bellard | ret = s->status; |
1398 | 5391d806 | bellard | #ifdef DEBUG_IDE
|
1399 | 5391d806 | bellard | printf("ide: read status addr=0x%x val=%02x\n", addr, ret);
|
1400 | 5391d806 | bellard | #endif
|
1401 | 5391d806 | bellard | return ret;
|
1402 | 5391d806 | bellard | } |
1403 | 5391d806 | bellard | |
1404 | 356721ae | Gerd Hoffmann | void ide_cmd_write(void *opaque, uint32_t addr, uint32_t val) |
1405 | 5391d806 | bellard | { |
1406 | bcbdc4d3 | Gerd Hoffmann | IDEBus *bus = opaque; |
1407 | 5391d806 | bellard | IDEState *s; |
1408 | 5391d806 | bellard | int i;
|
1409 | 5391d806 | bellard | |
1410 | 5391d806 | bellard | #ifdef DEBUG_IDE
|
1411 | 5391d806 | bellard | printf("ide: write control addr=0x%x val=%02x\n", addr, val);
|
1412 | 5391d806 | bellard | #endif
|
1413 | 5391d806 | bellard | /* common for both drives */
|
1414 | 9cdd03a7 | Gerd Hoffmann | if (!(bus->cmd & IDE_CMD_RESET) &&
|
1415 | 5391d806 | bellard | (val & IDE_CMD_RESET)) { |
1416 | 5391d806 | bellard | /* reset low to high */
|
1417 | 5391d806 | bellard | for(i = 0;i < 2; i++) { |
1418 | bcbdc4d3 | Gerd Hoffmann | s = &bus->ifs[i]; |
1419 | 5391d806 | bellard | s->status = BUSY_STAT | SEEK_STAT; |
1420 | 5391d806 | bellard | s->error = 0x01;
|
1421 | 5391d806 | bellard | } |
1422 | 9cdd03a7 | Gerd Hoffmann | } else if ((bus->cmd & IDE_CMD_RESET) && |
1423 | 5391d806 | bellard | !(val & IDE_CMD_RESET)) { |
1424 | 5391d806 | bellard | /* high to low */
|
1425 | 5391d806 | bellard | for(i = 0;i < 2; i++) { |
1426 | bcbdc4d3 | Gerd Hoffmann | s = &bus->ifs[i]; |
1427 | cd8722bb | Markus Armbruster | if (s->drive_kind == IDE_CD)
|
1428 | 6b136f9e | bellard | s->status = 0x00; /* NOTE: READY is _not_ set */ |
1429 | 6b136f9e | bellard | else
|
1430 | 56bf1d37 | bellard | s->status = READY_STAT | SEEK_STAT; |
1431 | 5391d806 | bellard | ide_set_signature(s); |
1432 | 5391d806 | bellard | } |
1433 | 5391d806 | bellard | } |
1434 | 5391d806 | bellard | |
1435 | 9cdd03a7 | Gerd Hoffmann | bus->cmd = val; |
1436 | 5391d806 | bellard | } |
1437 | 5391d806 | bellard | |
1438 | 356721ae | Gerd Hoffmann | void ide_data_writew(void *opaque, uint32_t addr, uint32_t val) |
1439 | 5391d806 | bellard | { |
1440 | bcbdc4d3 | Gerd Hoffmann | IDEBus *bus = opaque; |
1441 | bcbdc4d3 | Gerd Hoffmann | IDEState *s = idebus_active_if(bus); |
1442 | 5391d806 | bellard | uint8_t *p; |
1443 | 5391d806 | bellard | |
1444 | fcdd25ab | aliguori | /* PIO data access allowed only when DRQ bit is set */
|
1445 | fcdd25ab | aliguori | if (!(s->status & DRQ_STAT))
|
1446 | fcdd25ab | aliguori | return;
|
1447 | fcdd25ab | aliguori | |
1448 | 5391d806 | bellard | p = s->data_ptr; |
1449 | 0c4ad8dc | bellard | *(uint16_t *)p = le16_to_cpu(val); |
1450 | 5391d806 | bellard | p += 2;
|
1451 | 5391d806 | bellard | s->data_ptr = p; |
1452 | 5391d806 | bellard | if (p >= s->data_end)
|
1453 | 5391d806 | bellard | s->end_transfer_func(s); |
1454 | 5391d806 | bellard | } |
1455 | 5391d806 | bellard | |
1456 | 356721ae | Gerd Hoffmann | uint32_t ide_data_readw(void *opaque, uint32_t addr)
|
1457 | 5391d806 | bellard | { |
1458 | bcbdc4d3 | Gerd Hoffmann | IDEBus *bus = opaque; |
1459 | bcbdc4d3 | Gerd Hoffmann | IDEState *s = idebus_active_if(bus); |
1460 | 5391d806 | bellard | uint8_t *p; |
1461 | 5391d806 | bellard | int ret;
|
1462 | fcdd25ab | aliguori | |
1463 | fcdd25ab | aliguori | /* PIO data access allowed only when DRQ bit is set */
|
1464 | fcdd25ab | aliguori | if (!(s->status & DRQ_STAT))
|
1465 | fcdd25ab | aliguori | return 0; |
1466 | fcdd25ab | aliguori | |
1467 | 5391d806 | bellard | p = s->data_ptr; |
1468 | 0c4ad8dc | bellard | ret = cpu_to_le16(*(uint16_t *)p); |
1469 | 5391d806 | bellard | p += 2;
|
1470 | 5391d806 | bellard | s->data_ptr = p; |
1471 | 5391d806 | bellard | if (p >= s->data_end)
|
1472 | 5391d806 | bellard | s->end_transfer_func(s); |
1473 | 5391d806 | bellard | return ret;
|
1474 | 5391d806 | bellard | } |
1475 | 5391d806 | bellard | |
1476 | 356721ae | Gerd Hoffmann | void ide_data_writel(void *opaque, uint32_t addr, uint32_t val) |
1477 | 5391d806 | bellard | { |
1478 | bcbdc4d3 | Gerd Hoffmann | IDEBus *bus = opaque; |
1479 | bcbdc4d3 | Gerd Hoffmann | IDEState *s = idebus_active_if(bus); |
1480 | 5391d806 | bellard | uint8_t *p; |
1481 | 5391d806 | bellard | |
1482 | fcdd25ab | aliguori | /* PIO data access allowed only when DRQ bit is set */
|
1483 | fcdd25ab | aliguori | if (!(s->status & DRQ_STAT))
|
1484 | fcdd25ab | aliguori | return;
|
1485 | fcdd25ab | aliguori | |
1486 | 5391d806 | bellard | p = s->data_ptr; |
1487 | 0c4ad8dc | bellard | *(uint32_t *)p = le32_to_cpu(val); |
1488 | 5391d806 | bellard | p += 4;
|
1489 | 5391d806 | bellard | s->data_ptr = p; |
1490 | 5391d806 | bellard | if (p >= s->data_end)
|
1491 | 5391d806 | bellard | s->end_transfer_func(s); |
1492 | 5391d806 | bellard | } |
1493 | 5391d806 | bellard | |
1494 | 356721ae | Gerd Hoffmann | uint32_t ide_data_readl(void *opaque, uint32_t addr)
|
1495 | 5391d806 | bellard | { |
1496 | bcbdc4d3 | Gerd Hoffmann | IDEBus *bus = opaque; |
1497 | bcbdc4d3 | Gerd Hoffmann | IDEState *s = idebus_active_if(bus); |
1498 | 5391d806 | bellard | uint8_t *p; |
1499 | 5391d806 | bellard | int ret;
|
1500 | 3b46e624 | ths | |
1501 | fcdd25ab | aliguori | /* PIO data access allowed only when DRQ bit is set */
|
1502 | fcdd25ab | aliguori | if (!(s->status & DRQ_STAT))
|
1503 | fcdd25ab | aliguori | return 0; |
1504 | fcdd25ab | aliguori | |
1505 | 5391d806 | bellard | p = s->data_ptr; |
1506 | 0c4ad8dc | bellard | ret = cpu_to_le32(*(uint32_t *)p); |
1507 | 5391d806 | bellard | p += 4;
|
1508 | 5391d806 | bellard | s->data_ptr = p; |
1509 | 5391d806 | bellard | if (p >= s->data_end)
|
1510 | 5391d806 | bellard | s->end_transfer_func(s); |
1511 | 5391d806 | bellard | return ret;
|
1512 | 5391d806 | bellard | } |
1513 | 5391d806 | bellard | |
1514 | a7dfe172 | bellard | static void ide_dummy_transfer_stop(IDEState *s) |
1515 | a7dfe172 | bellard | { |
1516 | a7dfe172 | bellard | s->data_ptr = s->io_buffer; |
1517 | a7dfe172 | bellard | s->data_end = s->io_buffer; |
1518 | a7dfe172 | bellard | s->io_buffer[0] = 0xff; |
1519 | a7dfe172 | bellard | s->io_buffer[1] = 0xff; |
1520 | a7dfe172 | bellard | s->io_buffer[2] = 0xff; |
1521 | a7dfe172 | bellard | s->io_buffer[3] = 0xff; |
1522 | a7dfe172 | bellard | } |
1523 | a7dfe172 | bellard | |
1524 | 4a643563 | Blue Swirl | static void ide_reset(IDEState *s) |
1525 | 5391d806 | bellard | { |
1526 | 4a643563 | Blue Swirl | #ifdef DEBUG_IDE
|
1527 | 4a643563 | Blue Swirl | printf("ide: reset\n");
|
1528 | 4a643563 | Blue Swirl | #endif
|
1529 | cd8722bb | Markus Armbruster | if (s->drive_kind == IDE_CFATA)
|
1530 | 201a51fc | balrog | s->mult_sectors = 0;
|
1531 | 201a51fc | balrog | else
|
1532 | 201a51fc | balrog | s->mult_sectors = MAX_MULT_SECTORS; |
1533 | 4a643563 | Blue Swirl | /* ide regs */
|
1534 | 4a643563 | Blue Swirl | s->feature = 0;
|
1535 | 4a643563 | Blue Swirl | s->error = 0;
|
1536 | 4a643563 | Blue Swirl | s->nsector = 0;
|
1537 | 4a643563 | Blue Swirl | s->sector = 0;
|
1538 | 4a643563 | Blue Swirl | s->lcyl = 0;
|
1539 | 4a643563 | Blue Swirl | s->hcyl = 0;
|
1540 | 4a643563 | Blue Swirl | |
1541 | 4a643563 | Blue Swirl | /* lba48 */
|
1542 | 4a643563 | Blue Swirl | s->hob_feature = 0;
|
1543 | 4a643563 | Blue Swirl | s->hob_sector = 0;
|
1544 | 4a643563 | Blue Swirl | s->hob_nsector = 0;
|
1545 | 4a643563 | Blue Swirl | s->hob_lcyl = 0;
|
1546 | 4a643563 | Blue Swirl | s->hob_hcyl = 0;
|
1547 | 4a643563 | Blue Swirl | |
1548 | 5391d806 | bellard | s->select = 0xa0;
|
1549 | 41a2b959 | aliguori | s->status = READY_STAT | SEEK_STAT; |
1550 | 4a643563 | Blue Swirl | |
1551 | 4a643563 | Blue Swirl | s->lba48 = 0;
|
1552 | 4a643563 | Blue Swirl | |
1553 | 4a643563 | Blue Swirl | /* ATAPI specific */
|
1554 | 4a643563 | Blue Swirl | s->sense_key = 0;
|
1555 | 4a643563 | Blue Swirl | s->asc = 0;
|
1556 | 4a643563 | Blue Swirl | s->cdrom_changed = 0;
|
1557 | 4a643563 | Blue Swirl | s->packet_transfer_size = 0;
|
1558 | 4a643563 | Blue Swirl | s->elementary_transfer_size = 0;
|
1559 | 4a643563 | Blue Swirl | s->io_buffer_index = 0;
|
1560 | 4a643563 | Blue Swirl | s->cd_sector_size = 0;
|
1561 | 4a643563 | Blue Swirl | s->atapi_dma = 0;
|
1562 | 4a643563 | Blue Swirl | /* ATA DMA state */
|
1563 | 4a643563 | Blue Swirl | s->io_buffer_size = 0;
|
1564 | 4a643563 | Blue Swirl | s->req_nb_sectors = 0;
|
1565 | 4a643563 | Blue Swirl | |
1566 | 5391d806 | bellard | ide_set_signature(s); |
1567 | a7dfe172 | bellard | /* init the transfer handler so that 0xffff is returned on data
|
1568 | a7dfe172 | bellard | accesses */
|
1569 | a7dfe172 | bellard | s->end_transfer_func = ide_dummy_transfer_stop; |
1570 | a7dfe172 | bellard | ide_dummy_transfer_stop(s); |
1571 | 201a51fc | balrog | s->media_changed = 0;
|
1572 | 5391d806 | bellard | } |
1573 | 5391d806 | bellard | |
1574 | 4a643563 | Blue Swirl | void ide_bus_reset(IDEBus *bus)
|
1575 | 4a643563 | Blue Swirl | { |
1576 | 4a643563 | Blue Swirl | bus->unit = 0;
|
1577 | 4a643563 | Blue Swirl | bus->cmd = 0;
|
1578 | 4a643563 | Blue Swirl | ide_reset(&bus->ifs[0]);
|
1579 | 4a643563 | Blue Swirl | ide_reset(&bus->ifs[1]);
|
1580 | 4a643563 | Blue Swirl | ide_clear_hob(bus); |
1581 | 40a6238a | Alexander Graf | |
1582 | 40a6238a | Alexander Graf | /* pending async DMA */
|
1583 | 40a6238a | Alexander Graf | if (bus->dma->aiocb) {
|
1584 | 40a6238a | Alexander Graf | #ifdef DEBUG_AIO
|
1585 | 40a6238a | Alexander Graf | printf("aio_cancel\n");
|
1586 | 40a6238a | Alexander Graf | #endif
|
1587 | 40a6238a | Alexander Graf | bdrv_aio_cancel(bus->dma->aiocb); |
1588 | 40a6238a | Alexander Graf | bus->dma->aiocb = NULL;
|
1589 | 40a6238a | Alexander Graf | } |
1590 | 40a6238a | Alexander Graf | |
1591 | 40a6238a | Alexander Graf | /* reset dma provider too */
|
1592 | 40a6238a | Alexander Graf | bus->dma->ops->reset(bus->dma); |
1593 | 4a643563 | Blue Swirl | } |
1594 | 4a643563 | Blue Swirl | |
1595 | 1f56e32a | Markus Armbruster | int ide_init_drive(IDEState *s, BlockDriverState *bs, IDEDriveKind kind,
|
1596 | c4d74df7 | Markus Armbruster | const char *version, const char *serial) |
1597 | 88804180 | Gerd Hoffmann | { |
1598 | 88804180 | Gerd Hoffmann | int cylinders, heads, secs;
|
1599 | 88804180 | Gerd Hoffmann | uint64_t nb_sectors; |
1600 | 88804180 | Gerd Hoffmann | |
1601 | f8b6cc00 | Markus Armbruster | s->bs = bs; |
1602 | 1f56e32a | Markus Armbruster | s->drive_kind = kind; |
1603 | 1f56e32a | Markus Armbruster | |
1604 | f8b6cc00 | Markus Armbruster | bdrv_get_geometry(bs, &nb_sectors); |
1605 | f8b6cc00 | Markus Armbruster | bdrv_guess_geometry(bs, &cylinders, &heads, &secs); |
1606 | dce9e928 | Markus Armbruster | if (cylinders < 1 || cylinders > 16383) { |
1607 | dce9e928 | Markus Armbruster | error_report("cyls must be between 1 and 16383");
|
1608 | dce9e928 | Markus Armbruster | return -1; |
1609 | dce9e928 | Markus Armbruster | } |
1610 | dce9e928 | Markus Armbruster | if (heads < 1 || heads > 16) { |
1611 | dce9e928 | Markus Armbruster | error_report("heads must be between 1 and 16");
|
1612 | dce9e928 | Markus Armbruster | return -1; |
1613 | dce9e928 | Markus Armbruster | } |
1614 | dce9e928 | Markus Armbruster | if (secs < 1 || secs > 63) { |
1615 | dce9e928 | Markus Armbruster | error_report("secs must be between 1 and 63");
|
1616 | dce9e928 | Markus Armbruster | return -1; |
1617 | dce9e928 | Markus Armbruster | } |
1618 | 870111c8 | Markus Armbruster | s->cylinders = cylinders; |
1619 | 870111c8 | Markus Armbruster | s->heads = heads; |
1620 | 870111c8 | Markus Armbruster | s->sectors = secs; |
1621 | 870111c8 | Markus Armbruster | s->nb_sectors = nb_sectors; |
1622 | 870111c8 | Markus Armbruster | /* The SMART values should be preserved across power cycles
|
1623 | 870111c8 | Markus Armbruster | but they aren't. */
|
1624 | 870111c8 | Markus Armbruster | s->smart_enabled = 1;
|
1625 | 870111c8 | Markus Armbruster | s->smart_autosave = 1;
|
1626 | 870111c8 | Markus Armbruster | s->smart_errors = 0;
|
1627 | 870111c8 | Markus Armbruster | s->smart_selftest_count = 0;
|
1628 | 1f56e32a | Markus Armbruster | if (kind == IDE_CD) {
|
1629 | f8b6cc00 | Markus Armbruster | bdrv_set_change_cb(bs, cdrom_change_cb, s); |
1630 | 1b2adf28 | Christoph Hellwig | bs->buffer_alignment = 2048;
|
1631 | 7aa9c811 | Markus Armbruster | } else {
|
1632 | 98f28ad7 | Markus Armbruster | if (!bdrv_is_inserted(s->bs)) {
|
1633 | 98f28ad7 | Markus Armbruster | error_report("Device needs media, but drive is empty");
|
1634 | 98f28ad7 | Markus Armbruster | return -1; |
1635 | 98f28ad7 | Markus Armbruster | } |
1636 | 7aa9c811 | Markus Armbruster | if (bdrv_is_read_only(bs)) {
|
1637 | 7aa9c811 | Markus Armbruster | error_report("Can't use a read-only drive");
|
1638 | 7aa9c811 | Markus Armbruster | return -1; |
1639 | 7aa9c811 | Markus Armbruster | } |
1640 | 88804180 | Gerd Hoffmann | } |
1641 | f8b6cc00 | Markus Armbruster | if (serial) {
|
1642 | 6ced55a5 | Markus Armbruster | strncpy(s->drive_serial_str, serial, sizeof(s->drive_serial_str));
|
1643 | 6ced55a5 | Markus Armbruster | } else {
|
1644 | 88804180 | Gerd Hoffmann | snprintf(s->drive_serial_str, sizeof(s->drive_serial_str),
|
1645 | 88804180 | Gerd Hoffmann | "QM%05d", s->drive_serial);
|
1646 | 870111c8 | Markus Armbruster | } |
1647 | 47c06340 | Gerd Hoffmann | if (version) {
|
1648 | 47c06340 | Gerd Hoffmann | pstrcpy(s->version, sizeof(s->version), version);
|
1649 | 47c06340 | Gerd Hoffmann | } else {
|
1650 | 47c06340 | Gerd Hoffmann | pstrcpy(s->version, sizeof(s->version), QEMU_VERSION);
|
1651 | 47c06340 | Gerd Hoffmann | } |
1652 | 40a6238a | Alexander Graf | |
1653 | 88804180 | Gerd Hoffmann | ide_reset(s); |
1654 | cd8722bb | Markus Armbruster | bdrv_set_removable(bs, s->drive_kind == IDE_CD); |
1655 | c4d74df7 | Markus Armbruster | return 0; |
1656 | 88804180 | Gerd Hoffmann | } |
1657 | 88804180 | Gerd Hoffmann | |
1658 | 57234ee4 | Markus Armbruster | static void ide_init1(IDEBus *bus, int unit) |
1659 | d459da0e | Markus Armbruster | { |
1660 | d459da0e | Markus Armbruster | static int drive_serial = 1; |
1661 | d459da0e | Markus Armbruster | IDEState *s = &bus->ifs[unit]; |
1662 | d459da0e | Markus Armbruster | |
1663 | d459da0e | Markus Armbruster | s->bus = bus; |
1664 | d459da0e | Markus Armbruster | s->unit = unit; |
1665 | d459da0e | Markus Armbruster | s->drive_serial = drive_serial++; |
1666 | 1b2adf28 | Christoph Hellwig | /* we need at least 2k alignment for accessing CDROMs using O_DIRECT */
|
1667 | 1b2adf28 | Christoph Hellwig | s->io_buffer = qemu_memalign(2048, IDE_DMA_BUF_SECTORS*512 + 4); |
1668 | 50641c5c | Juan Quintela | s->io_buffer_total_len = IDE_DMA_BUF_SECTORS*512 + 4; |
1669 | d459da0e | Markus Armbruster | s->smart_selftest_data = qemu_blockalign(s->bs, 512);
|
1670 | 74475455 | Paolo Bonzini | s->sector_write_timer = qemu_new_timer_ns(vm_clock, |
1671 | d459da0e | Markus Armbruster | ide_sector_write_timer_cb, s); |
1672 | 57234ee4 | Markus Armbruster | } |
1673 | 57234ee4 | Markus Armbruster | |
1674 | 40a6238a | Alexander Graf | static void ide_nop_start(IDEDMA *dma, IDEState *s, |
1675 | 40a6238a | Alexander Graf | BlockDriverCompletionFunc *cb) |
1676 | 40a6238a | Alexander Graf | { |
1677 | 40a6238a | Alexander Graf | } |
1678 | 40a6238a | Alexander Graf | |
1679 | 40a6238a | Alexander Graf | static int ide_nop(IDEDMA *dma) |
1680 | 40a6238a | Alexander Graf | { |
1681 | 40a6238a | Alexander Graf | return 0; |
1682 | 40a6238a | Alexander Graf | } |
1683 | 40a6238a | Alexander Graf | |
1684 | 40a6238a | Alexander Graf | static int ide_nop_int(IDEDMA *dma, int x) |
1685 | 40a6238a | Alexander Graf | { |
1686 | 40a6238a | Alexander Graf | return 0; |
1687 | 40a6238a | Alexander Graf | } |
1688 | 40a6238a | Alexander Graf | |
1689 | 40a6238a | Alexander Graf | static void ide_nop_restart(void *opaque, int x, int y) |
1690 | 40a6238a | Alexander Graf | { |
1691 | 40a6238a | Alexander Graf | } |
1692 | 40a6238a | Alexander Graf | |
1693 | 40a6238a | Alexander Graf | static const IDEDMAOps ide_dma_nop_ops = { |
1694 | 40a6238a | Alexander Graf | .start_dma = ide_nop_start, |
1695 | 40a6238a | Alexander Graf | .start_transfer = ide_nop, |
1696 | 40a6238a | Alexander Graf | .prepare_buf = ide_nop_int, |
1697 | 40a6238a | Alexander Graf | .rw_buf = ide_nop_int, |
1698 | 40a6238a | Alexander Graf | .set_unit = ide_nop_int, |
1699 | 40a6238a | Alexander Graf | .add_status = ide_nop_int, |
1700 | 40a6238a | Alexander Graf | .set_inactive = ide_nop, |
1701 | 40a6238a | Alexander Graf | .restart_cb = ide_nop_restart, |
1702 | 40a6238a | Alexander Graf | .reset = ide_nop, |
1703 | 40a6238a | Alexander Graf | }; |
1704 | 40a6238a | Alexander Graf | |
1705 | 40a6238a | Alexander Graf | static IDEDMA ide_dma_nop = {
|
1706 | 40a6238a | Alexander Graf | .ops = &ide_dma_nop_ops, |
1707 | 40a6238a | Alexander Graf | .aiocb = NULL,
|
1708 | 40a6238a | Alexander Graf | }; |
1709 | 40a6238a | Alexander Graf | |
1710 | 57234ee4 | Markus Armbruster | void ide_init2(IDEBus *bus, qemu_irq irq)
|
1711 | 57234ee4 | Markus Armbruster | { |
1712 | 57234ee4 | Markus Armbruster | int i;
|
1713 | 57234ee4 | Markus Armbruster | |
1714 | 57234ee4 | Markus Armbruster | for(i = 0; i < 2; i++) { |
1715 | 57234ee4 | Markus Armbruster | ide_init1(bus, i); |
1716 | 57234ee4 | Markus Armbruster | ide_reset(&bus->ifs[i]); |
1717 | 870111c8 | Markus Armbruster | } |
1718 | 57234ee4 | Markus Armbruster | bus->irq = irq; |
1719 | 40a6238a | Alexander Graf | bus->dma = &ide_dma_nop; |
1720 | d459da0e | Markus Armbruster | } |
1721 | d459da0e | Markus Armbruster | |
1722 | 57234ee4 | Markus Armbruster | /* TODO convert users to qdev and remove */
|
1723 | 57234ee4 | Markus Armbruster | void ide_init2_with_non_qdev_drives(IDEBus *bus, DriveInfo *hd0,
|
1724 | 57234ee4 | Markus Armbruster | DriveInfo *hd1, qemu_irq irq) |
1725 | 5391d806 | bellard | { |
1726 | 88804180 | Gerd Hoffmann | int i;
|
1727 | 57234ee4 | Markus Armbruster | DriveInfo *dinfo; |
1728 | 5391d806 | bellard | |
1729 | caed8802 | bellard | for(i = 0; i < 2; i++) { |
1730 | 57234ee4 | Markus Armbruster | dinfo = i == 0 ? hd0 : hd1;
|
1731 | 57234ee4 | Markus Armbruster | ide_init1(bus, i); |
1732 | 57234ee4 | Markus Armbruster | if (dinfo) {
|
1733 | 1f56e32a | Markus Armbruster | if (ide_init_drive(&bus->ifs[i], dinfo->bdrv,
|
1734 | 95b5edcd | Markus Armbruster | dinfo->media_cd ? IDE_CD : IDE_HD, NULL,
|
1735 | c4d74df7 | Markus Armbruster | *dinfo->serial ? dinfo->serial : NULL) < 0) { |
1736 | c4d74df7 | Markus Armbruster | error_report("Can't set up IDE drive %s", dinfo->id);
|
1737 | c4d74df7 | Markus Armbruster | exit(1);
|
1738 | c4d74df7 | Markus Armbruster | } |
1739 | 57234ee4 | Markus Armbruster | } else {
|
1740 | 57234ee4 | Markus Armbruster | ide_reset(&bus->ifs[i]); |
1741 | 57234ee4 | Markus Armbruster | } |
1742 | 5391d806 | bellard | } |
1743 | 9cdd03a7 | Gerd Hoffmann | bus->irq = irq; |
1744 | 40a6238a | Alexander Graf | bus->dma = &ide_dma_nop; |
1745 | 69b91039 | bellard | } |
1746 | 69b91039 | bellard | |
1747 | 356721ae | Gerd Hoffmann | void ide_init_ioport(IDEBus *bus, int iobase, int iobase2) |
1748 | 69b91039 | bellard | { |
1749 | bcbdc4d3 | Gerd Hoffmann | register_ioport_write(iobase, 8, 1, ide_ioport_write, bus); |
1750 | bcbdc4d3 | Gerd Hoffmann | register_ioport_read(iobase, 8, 1, ide_ioport_read, bus); |
1751 | caed8802 | bellard | if (iobase2) {
|
1752 | bcbdc4d3 | Gerd Hoffmann | register_ioport_read(iobase2, 1, 1, ide_status_read, bus); |
1753 | bcbdc4d3 | Gerd Hoffmann | register_ioport_write(iobase2, 1, 1, ide_cmd_write, bus); |
1754 | 5391d806 | bellard | } |
1755 | 3b46e624 | ths | |
1756 | caed8802 | bellard | /* data ports */
|
1757 | bcbdc4d3 | Gerd Hoffmann | register_ioport_write(iobase, 2, 2, ide_data_writew, bus); |
1758 | bcbdc4d3 | Gerd Hoffmann | register_ioport_read(iobase, 2, 2, ide_data_readw, bus); |
1759 | bcbdc4d3 | Gerd Hoffmann | register_ioport_write(iobase, 4, 4, ide_data_writel, bus); |
1760 | bcbdc4d3 | Gerd Hoffmann | register_ioport_read(iobase, 4, 4, ide_data_readl, bus); |
1761 | 5391d806 | bellard | } |
1762 | 69b91039 | bellard | |
1763 | 37159f13 | Juan Quintela | static bool is_identify_set(void *opaque, int version_id) |
1764 | aa941b94 | balrog | { |
1765 | 37159f13 | Juan Quintela | IDEState *s = opaque; |
1766 | 37159f13 | Juan Quintela | |
1767 | 37159f13 | Juan Quintela | return s->identify_set != 0; |
1768 | 37159f13 | Juan Quintela | } |
1769 | 37159f13 | Juan Quintela | |
1770 | 50641c5c | Juan Quintela | static EndTransferFunc* transfer_end_table[] = {
|
1771 | 50641c5c | Juan Quintela | ide_sector_read, |
1772 | 50641c5c | Juan Quintela | ide_sector_write, |
1773 | 50641c5c | Juan Quintela | ide_transfer_stop, |
1774 | 50641c5c | Juan Quintela | ide_atapi_cmd_reply_end, |
1775 | 50641c5c | Juan Quintela | ide_atapi_cmd, |
1776 | 50641c5c | Juan Quintela | ide_dummy_transfer_stop, |
1777 | 50641c5c | Juan Quintela | }; |
1778 | 50641c5c | Juan Quintela | |
1779 | 50641c5c | Juan Quintela | static int transfer_end_table_idx(EndTransferFunc *fn) |
1780 | 50641c5c | Juan Quintela | { |
1781 | 50641c5c | Juan Quintela | int i;
|
1782 | 50641c5c | Juan Quintela | |
1783 | 50641c5c | Juan Quintela | for (i = 0; i < ARRAY_SIZE(transfer_end_table); i++) |
1784 | 50641c5c | Juan Quintela | if (transfer_end_table[i] == fn)
|
1785 | 50641c5c | Juan Quintela | return i;
|
1786 | 50641c5c | Juan Quintela | |
1787 | 50641c5c | Juan Quintela | return -1; |
1788 | 50641c5c | Juan Quintela | } |
1789 | 50641c5c | Juan Quintela | |
1790 | 37159f13 | Juan Quintela | static int ide_drive_post_load(void *opaque, int version_id) |
1791 | aa941b94 | balrog | { |
1792 | 37159f13 | Juan Quintela | IDEState *s = opaque; |
1793 | 37159f13 | Juan Quintela | |
1794 | 37159f13 | Juan Quintela | if (version_id < 3) { |
1795 | 93c8cfd9 | Gleb Natapov | if (s->sense_key == SENSE_UNIT_ATTENTION &&
|
1796 | 37159f13 | Juan Quintela | s->asc == ASC_MEDIUM_MAY_HAVE_CHANGED) { |
1797 | 93c8cfd9 | Gleb Natapov | s->cdrom_changed = 1;
|
1798 | 37159f13 | Juan Quintela | } |
1799 | 93c8cfd9 | Gleb Natapov | } |
1800 | 37159f13 | Juan Quintela | return 0; |
1801 | aa941b94 | balrog | } |
1802 | aa941b94 | balrog | |
1803 | 50641c5c | Juan Quintela | static int ide_drive_pio_post_load(void *opaque, int version_id) |
1804 | 50641c5c | Juan Quintela | { |
1805 | 50641c5c | Juan Quintela | IDEState *s = opaque; |
1806 | 50641c5c | Juan Quintela | |
1807 | 7bccf573 | Blue Swirl | if (s->end_transfer_fn_idx > ARRAY_SIZE(transfer_end_table)) {
|
1808 | 50641c5c | Juan Quintela | return -EINVAL;
|
1809 | 50641c5c | Juan Quintela | } |
1810 | 50641c5c | Juan Quintela | s->end_transfer_func = transfer_end_table[s->end_transfer_fn_idx]; |
1811 | 50641c5c | Juan Quintela | s->data_ptr = s->io_buffer + s->cur_io_buffer_offset; |
1812 | 50641c5c | Juan Quintela | s->data_end = s->data_ptr + s->cur_io_buffer_len; |
1813 | 50641c5c | Juan Quintela | |
1814 | 50641c5c | Juan Quintela | return 0; |
1815 | 50641c5c | Juan Quintela | } |
1816 | 50641c5c | Juan Quintela | |
1817 | 50641c5c | Juan Quintela | static void ide_drive_pio_pre_save(void *opaque) |
1818 | 50641c5c | Juan Quintela | { |
1819 | 50641c5c | Juan Quintela | IDEState *s = opaque; |
1820 | 50641c5c | Juan Quintela | int idx;
|
1821 | 50641c5c | Juan Quintela | |
1822 | 50641c5c | Juan Quintela | s->cur_io_buffer_offset = s->data_ptr - s->io_buffer; |
1823 | 50641c5c | Juan Quintela | s->cur_io_buffer_len = s->data_end - s->data_ptr; |
1824 | 50641c5c | Juan Quintela | |
1825 | 50641c5c | Juan Quintela | idx = transfer_end_table_idx(s->end_transfer_func); |
1826 | 50641c5c | Juan Quintela | if (idx == -1) { |
1827 | 50641c5c | Juan Quintela | fprintf(stderr, "%s: invalid end_transfer_func for DRQ_STAT\n",
|
1828 | 50641c5c | Juan Quintela | __func__); |
1829 | 50641c5c | Juan Quintela | s->end_transfer_fn_idx = 2;
|
1830 | 50641c5c | Juan Quintela | } else {
|
1831 | 50641c5c | Juan Quintela | s->end_transfer_fn_idx = idx; |
1832 | 50641c5c | Juan Quintela | } |
1833 | 50641c5c | Juan Quintela | } |
1834 | 50641c5c | Juan Quintela | |
1835 | 50641c5c | Juan Quintela | static bool ide_drive_pio_state_needed(void *opaque) |
1836 | 50641c5c | Juan Quintela | { |
1837 | 50641c5c | Juan Quintela | IDEState *s = opaque; |
1838 | 50641c5c | Juan Quintela | |
1839 | 50641c5c | Juan Quintela | return (s->status & DRQ_STAT) != 0; |
1840 | 50641c5c | Juan Quintela | } |
1841 | 50641c5c | Juan Quintela | |
1842 | 996faf1a | Amit Shah | static bool ide_atapi_gesn_needed(void *opaque) |
1843 | 996faf1a | Amit Shah | { |
1844 | 996faf1a | Amit Shah | IDEState *s = opaque; |
1845 | 996faf1a | Amit Shah | |
1846 | 996faf1a | Amit Shah | return s->events.new_media || s->events.eject_request;
|
1847 | 996faf1a | Amit Shah | } |
1848 | 996faf1a | Amit Shah | |
1849 | 996faf1a | Amit Shah | /* Fields for GET_EVENT_STATUS_NOTIFICATION ATAPI command */
|
1850 | 996faf1a | Amit Shah | const VMStateDescription vmstate_ide_atapi_gesn_state = {
|
1851 | 996faf1a | Amit Shah | .name ="ide_drive/atapi/gesn_state",
|
1852 | 996faf1a | Amit Shah | .version_id = 1,
|
1853 | 996faf1a | Amit Shah | .minimum_version_id = 1,
|
1854 | 996faf1a | Amit Shah | .minimum_version_id_old = 1,
|
1855 | 996faf1a | Amit Shah | .fields = (VMStateField []) { |
1856 | 996faf1a | Amit Shah | VMSTATE_BOOL(events.new_media, IDEState), |
1857 | 996faf1a | Amit Shah | VMSTATE_BOOL(events.eject_request, IDEState), |
1858 | 996faf1a | Amit Shah | } |
1859 | 996faf1a | Amit Shah | }; |
1860 | 996faf1a | Amit Shah | |
1861 | 50641c5c | Juan Quintela | const VMStateDescription vmstate_ide_drive_pio_state = {
|
1862 | 50641c5c | Juan Quintela | .name = "ide_drive/pio_state",
|
1863 | 50641c5c | Juan Quintela | .version_id = 1,
|
1864 | 50641c5c | Juan Quintela | .minimum_version_id = 1,
|
1865 | 50641c5c | Juan Quintela | .minimum_version_id_old = 1,
|
1866 | 50641c5c | Juan Quintela | .pre_save = ide_drive_pio_pre_save, |
1867 | 50641c5c | Juan Quintela | .post_load = ide_drive_pio_post_load, |
1868 | 50641c5c | Juan Quintela | .fields = (VMStateField []) { |
1869 | 50641c5c | Juan Quintela | VMSTATE_INT32(req_nb_sectors, IDEState), |
1870 | 50641c5c | Juan Quintela | VMSTATE_VARRAY_INT32(io_buffer, IDEState, io_buffer_total_len, 1,
|
1871 | 50641c5c | Juan Quintela | vmstate_info_uint8, uint8_t), |
1872 | 50641c5c | Juan Quintela | VMSTATE_INT32(cur_io_buffer_offset, IDEState), |
1873 | 50641c5c | Juan Quintela | VMSTATE_INT32(cur_io_buffer_len, IDEState), |
1874 | 50641c5c | Juan Quintela | VMSTATE_UINT8(end_transfer_fn_idx, IDEState), |
1875 | 50641c5c | Juan Quintela | VMSTATE_INT32(elementary_transfer_size, IDEState), |
1876 | 50641c5c | Juan Quintela | VMSTATE_INT32(packet_transfer_size, IDEState), |
1877 | 50641c5c | Juan Quintela | VMSTATE_END_OF_LIST() |
1878 | 50641c5c | Juan Quintela | } |
1879 | 50641c5c | Juan Quintela | }; |
1880 | 50641c5c | Juan Quintela | |
1881 | 37159f13 | Juan Quintela | const VMStateDescription vmstate_ide_drive = {
|
1882 | 37159f13 | Juan Quintela | .name = "ide_drive",
|
1883 | 3abb6260 | Juan Quintela | .version_id = 3,
|
1884 | 37159f13 | Juan Quintela | .minimum_version_id = 0,
|
1885 | 37159f13 | Juan Quintela | .minimum_version_id_old = 0,
|
1886 | 37159f13 | Juan Quintela | .post_load = ide_drive_post_load, |
1887 | 37159f13 | Juan Quintela | .fields = (VMStateField []) { |
1888 | 37159f13 | Juan Quintela | VMSTATE_INT32(mult_sectors, IDEState), |
1889 | 37159f13 | Juan Quintela | VMSTATE_INT32(identify_set, IDEState), |
1890 | 37159f13 | Juan Quintela | VMSTATE_BUFFER_TEST(identify_data, IDEState, is_identify_set), |
1891 | 37159f13 | Juan Quintela | VMSTATE_UINT8(feature, IDEState), |
1892 | 37159f13 | Juan Quintela | VMSTATE_UINT8(error, IDEState), |
1893 | 37159f13 | Juan Quintela | VMSTATE_UINT32(nsector, IDEState), |
1894 | 37159f13 | Juan Quintela | VMSTATE_UINT8(sector, IDEState), |
1895 | 37159f13 | Juan Quintela | VMSTATE_UINT8(lcyl, IDEState), |
1896 | 37159f13 | Juan Quintela | VMSTATE_UINT8(hcyl, IDEState), |
1897 | 37159f13 | Juan Quintela | VMSTATE_UINT8(hob_feature, IDEState), |
1898 | 37159f13 | Juan Quintela | VMSTATE_UINT8(hob_sector, IDEState), |
1899 | 37159f13 | Juan Quintela | VMSTATE_UINT8(hob_nsector, IDEState), |
1900 | 37159f13 | Juan Quintela | VMSTATE_UINT8(hob_lcyl, IDEState), |
1901 | 37159f13 | Juan Quintela | VMSTATE_UINT8(hob_hcyl, IDEState), |
1902 | 37159f13 | Juan Quintela | VMSTATE_UINT8(select, IDEState), |
1903 | 37159f13 | Juan Quintela | VMSTATE_UINT8(status, IDEState), |
1904 | 37159f13 | Juan Quintela | VMSTATE_UINT8(lba48, IDEState), |
1905 | 37159f13 | Juan Quintela | VMSTATE_UINT8(sense_key, IDEState), |
1906 | 37159f13 | Juan Quintela | VMSTATE_UINT8(asc, IDEState), |
1907 | 37159f13 | Juan Quintela | VMSTATE_UINT8_V(cdrom_changed, IDEState, 3),
|
1908 | 37159f13 | Juan Quintela | VMSTATE_END_OF_LIST() |
1909 | 50641c5c | Juan Quintela | }, |
1910 | 50641c5c | Juan Quintela | .subsections = (VMStateSubsection []) { |
1911 | 50641c5c | Juan Quintela | { |
1912 | 50641c5c | Juan Quintela | .vmsd = &vmstate_ide_drive_pio_state, |
1913 | 50641c5c | Juan Quintela | .needed = ide_drive_pio_state_needed, |
1914 | 50641c5c | Juan Quintela | }, { |
1915 | 996faf1a | Amit Shah | .vmsd = &vmstate_ide_atapi_gesn_state, |
1916 | 996faf1a | Amit Shah | .needed = ide_atapi_gesn_needed, |
1917 | 996faf1a | Amit Shah | }, { |
1918 | 50641c5c | Juan Quintela | /* empty */
|
1919 | 50641c5c | Juan Quintela | } |
1920 | 37159f13 | Juan Quintela | } |
1921 | 37159f13 | Juan Quintela | }; |
1922 | 37159f13 | Juan Quintela | |
1923 | 6521dc62 | Juan Quintela | const VMStateDescription vmstate_ide_bus = {
|
1924 | 6521dc62 | Juan Quintela | .name = "ide_bus",
|
1925 | 6521dc62 | Juan Quintela | .version_id = 1,
|
1926 | 6521dc62 | Juan Quintela | .minimum_version_id = 1,
|
1927 | 6521dc62 | Juan Quintela | .minimum_version_id_old = 1,
|
1928 | 6521dc62 | Juan Quintela | .fields = (VMStateField []) { |
1929 | 6521dc62 | Juan Quintela | VMSTATE_UINT8(cmd, IDEBus), |
1930 | 6521dc62 | Juan Quintela | VMSTATE_UINT8(unit, IDEBus), |
1931 | 6521dc62 | Juan Quintela | VMSTATE_END_OF_LIST() |
1932 | 6521dc62 | Juan Quintela | } |
1933 | 6521dc62 | Juan Quintela | }; |
1934 | 75717903 | Isaku Yamahata | |
1935 | 75717903 | Isaku Yamahata | void ide_drive_get(DriveInfo **hd, int max_bus) |
1936 | 75717903 | Isaku Yamahata | { |
1937 | 75717903 | Isaku Yamahata | int i;
|
1938 | 75717903 | Isaku Yamahata | |
1939 | 75717903 | Isaku Yamahata | if (drive_get_max_bus(IF_IDE) >= max_bus) {
|
1940 | 75717903 | Isaku Yamahata | fprintf(stderr, "qemu: too many IDE bus: %d\n", max_bus);
|
1941 | 75717903 | Isaku Yamahata | exit(1);
|
1942 | 75717903 | Isaku Yamahata | } |
1943 | 75717903 | Isaku Yamahata | |
1944 | 75717903 | Isaku Yamahata | for(i = 0; i < max_bus * MAX_IDE_DEVS; i++) { |
1945 | 75717903 | Isaku Yamahata | hd[i] = drive_get(IF_IDE, i / MAX_IDE_DEVS, i % MAX_IDE_DEVS); |
1946 | 75717903 | Isaku Yamahata | } |
1947 | 75717903 | Isaku Yamahata | } |