]> git.proxmox.com Git - mirror_qemu.git/blob - hw/esp.c
ESP PIO mode, 2k CDROM sector size (Blue Swirl)
[mirror_qemu.git] / hw / esp.c
1 /*
2 * QEMU ESP emulation
3 *
4 * Copyright (c) 2005 Fabrice Bellard
5 *
6 * Permission is hereby granted, free of charge, to any person obtaining a copy
7 * of this software and associated documentation files (the "Software"), to deal
8 * in the Software without restriction, including without limitation the rights
9 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 * copies of the Software, and to permit persons to whom the Software is
11 * furnished to do so, subject to the following conditions:
12 *
13 * The above copyright notice and this permission notice shall be included in
14 * all copies or substantial portions of the Software.
15 *
16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
19 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
22 * THE SOFTWARE.
23 */
24 #include "vl.h"
25
26 /* debug ESP card */
27 //#define DEBUG_ESP
28
29 #ifdef DEBUG_ESP
30 #define DPRINTF(fmt, args...) \
31 do { printf("ESP: " fmt , ##args); } while (0)
32 #else
33 #define DPRINTF(fmt, args...)
34 #endif
35
36 #define ESPDMA_REGS 4
37 #define ESPDMA_MAXADDR (ESPDMA_REGS * 4 - 1)
38 #define ESP_MAXREG 0x3f
39 #define TI_BUFSZ 65536
40 #define DMA_VER 0xa0000000
41 #define DMA_LOADED 0x04000000
42
43 typedef struct ESPState {
44 BlockDriverState **bd;
45 uint8_t rregs[ESP_MAXREG];
46 uint8_t wregs[ESP_MAXREG];
47 int irq;
48 uint32_t espdmaregs[ESPDMA_REGS];
49 uint32_t ti_size;
50 uint32_t ti_rptr, ti_wptr;
51 int ti_dir;
52 uint8_t ti_buf[TI_BUFSZ];
53 int dma;
54 } ESPState;
55
56 #define STAT_DO 0x00
57 #define STAT_DI 0x01
58 #define STAT_CD 0x02
59 #define STAT_ST 0x03
60 #define STAT_MI 0x06
61 #define STAT_MO 0x07
62
63 #define STAT_TC 0x10
64 #define STAT_IN 0x80
65
66 #define INTR_FC 0x08
67 #define INTR_BS 0x10
68 #define INTR_DC 0x20
69
70 #define SEQ_0 0x0
71 #define SEQ_CD 0x4
72
73 static void handle_satn(ESPState *s)
74 {
75 uint8_t buf[32];
76 uint32_t dmaptr, dmalen;
77 unsigned int i;
78 int64_t nb_sectors;
79 int target;
80
81 dmalen = s->wregs[0] | (s->wregs[1] << 8);
82 target = s->wregs[4] & 7;
83 DPRINTF("Select with ATN len %d target %d\n", dmalen, target);
84 if (s->dma) {
85 dmaptr = iommu_translate(s->espdmaregs[1]);
86 DPRINTF("DMA Direction: %c, addr 0x%8.8x\n", s->espdmaregs[0] & 0x100? 'w': 'r', dmaptr);
87 cpu_physical_memory_read(dmaptr, buf, dmalen);
88 } else {
89 buf[0] = 0;
90 memcpy(&buf[1], s->ti_buf, dmalen);
91 dmalen++;
92 }
93 for (i = 0; i < dmalen; i++) {
94 DPRINTF("Command %2.2x\n", buf[i]);
95 }
96 s->ti_dir = 0;
97 s->ti_size = 0;
98 s->ti_rptr = 0;
99 s->ti_wptr = 0;
100
101 if (target > 4 || !s->bd[target]) { // No such drive
102 s->rregs[4] = STAT_IN;
103 s->rregs[5] = INTR_DC;
104 s->rregs[6] = SEQ_0;
105 s->espdmaregs[0] |= 1;
106 pic_set_irq(s->irq, 1);
107 return;
108 }
109 switch (buf[1]) {
110 case 0x0:
111 DPRINTF("Test Unit Ready (len %d)\n", buf[5]);
112 break;
113 case 0x12:
114 DPRINTF("Inquiry (len %d)\n", buf[5]);
115 memset(s->ti_buf, 0, 36);
116 if (bdrv_get_type_hint(s->bd[target]) == BDRV_TYPE_CDROM) {
117 s->ti_buf[0] = 5;
118 memcpy(&s->ti_buf[16], "QEMU CDROM ", 16);
119 } else {
120 s->ti_buf[0] = 0;
121 memcpy(&s->ti_buf[16], "QEMU HARDDISK ", 16);
122 }
123 memcpy(&s->ti_buf[8], "QEMU ", 8);
124 s->ti_buf[2] = 1;
125 s->ti_buf[3] = 2;
126 s->ti_dir = 1;
127 s->ti_size = 36;
128 break;
129 case 0x1a:
130 DPRINTF("Mode Sense(6) (page %d, len %d)\n", buf[3], buf[5]);
131 break;
132 case 0x25:
133 DPRINTF("Read Capacity (len %d)\n", buf[5]);
134 memset(s->ti_buf, 0, 8);
135 bdrv_get_geometry(s->bd[target], &nb_sectors);
136 s->ti_buf[0] = (nb_sectors >> 24) & 0xff;
137 s->ti_buf[1] = (nb_sectors >> 16) & 0xff;
138 s->ti_buf[2] = (nb_sectors >> 8) & 0xff;
139 s->ti_buf[3] = nb_sectors & 0xff;
140 s->ti_buf[4] = 0;
141 s->ti_buf[5] = 0;
142 if (bdrv_get_type_hint(s->bd[target]) == BDRV_TYPE_CDROM)
143 s->ti_buf[6] = 8; // sector size 2048
144 else
145 s->ti_buf[6] = 2; // sector size 512
146 s->ti_buf[7] = 0;
147 s->ti_dir = 1;
148 s->ti_size = 8;
149 break;
150 case 0x28:
151 {
152 int64_t offset, len;
153
154 if (bdrv_get_type_hint(s->bd[target]) == BDRV_TYPE_CDROM) {
155 offset = ((buf[3] << 24) | (buf[4] << 16) | (buf[5] << 8) | buf[6]) * 4;
156 len = ((buf[8] << 8) | buf[9]) * 4;
157 s->ti_size = len * 2048;
158 } else {
159 offset = (buf[3] << 24) | (buf[4] << 16) | (buf[5] << 8) | buf[6];
160 len = (buf[8] << 8) | buf[9];
161 s->ti_size = len * 512;
162 }
163 DPRINTF("Read (10) (offset %lld len %lld)\n", offset, len);
164 bdrv_read(s->bd[target], offset, s->ti_buf, len);
165 // XXX error handling
166 s->ti_dir = 1;
167 break;
168 }
169 case 0x2a:
170 {
171 int64_t offset, len;
172
173 if (bdrv_get_type_hint(s->bd[target]) == BDRV_TYPE_CDROM) {
174 offset = ((buf[3] << 24) | (buf[4] << 16) | (buf[5] << 8) | buf[6]) * 4;
175 len = ((buf[8] << 8) | buf[9]) * 4;
176 s->ti_size = len * 2048;
177 } else {
178 offset = (buf[3] << 24) | (buf[4] << 16) | (buf[5] << 8) | buf[6];
179 len = (buf[8] << 8) | buf[9];
180 s->ti_size = len * 512;
181 }
182 DPRINTF("Write (10) (offset %lld len %lld)\n", offset, len);
183 bdrv_write(s->bd[target], offset, s->ti_buf, len);
184 // XXX error handling
185 s->ti_dir = 0;
186 break;
187 }
188 default:
189 DPRINTF("Unknown SCSI command (%2.2x)\n", buf[1]);
190 break;
191 }
192 s->rregs[4] = STAT_IN | STAT_TC | STAT_DI;
193 s->rregs[5] = INTR_BS | INTR_FC;
194 s->rregs[6] = SEQ_CD;
195 s->espdmaregs[0] |= 1;
196 pic_set_irq(s->irq, 1);
197 }
198
199 static void dma_write(ESPState *s, const uint8_t *buf, uint32_t len)
200 {
201 uint32_t dmaptr, dmalen;
202
203 dmalen = s->wregs[0] | (s->wregs[1] << 8);
204 DPRINTF("Transfer status len %d\n", dmalen);
205 if (s->dma) {
206 dmaptr = iommu_translate(s->espdmaregs[1]);
207 DPRINTF("DMA Direction: %c\n", s->espdmaregs[0] & 0x100? 'w': 'r');
208 cpu_physical_memory_write(dmaptr, buf, len);
209 s->rregs[4] = STAT_IN | STAT_TC | STAT_ST;
210 s->rregs[5] = INTR_BS | INTR_FC;
211 s->rregs[6] = SEQ_CD;
212 s->espdmaregs[0] |= 1;
213 } else {
214 memcpy(s->ti_buf, buf, len);
215 s->ti_size = dmalen;
216 s->ti_rptr = 0;
217 s->ti_wptr = 0;
218 }
219 pic_set_irq(s->irq, 1);
220
221 }
222
223 static const uint8_t okbuf[] = {0, 0};
224
225 static void handle_ti(ESPState *s)
226 {
227 uint32_t dmaptr, dmalen;
228 unsigned int i;
229
230 dmalen = s->wregs[0] | (s->wregs[1] << 8);
231 DPRINTF("Transfer Information len %d\n", dmalen);
232 if (s->dma) {
233 dmaptr = iommu_translate(s->espdmaregs[1]);
234 DPRINTF("DMA Direction: %c, addr 0x%8.8x\n", s->espdmaregs[0] & 0x100? 'w': 'r', dmaptr);
235 for (i = 0; i < s->ti_size; i++) {
236 dmaptr = iommu_translate(s->espdmaregs[1] + i);
237 if (s->ti_dir)
238 cpu_physical_memory_write(dmaptr, &s->ti_buf[i], 1);
239 else
240 cpu_physical_memory_read(dmaptr, &s->ti_buf[i], 1);
241 }
242 s->rregs[4] = STAT_IN | STAT_TC | STAT_ST;
243 s->rregs[5] = INTR_BS;
244 s->rregs[6] = 0;
245 s->espdmaregs[0] |= 1;
246 } else {
247 s->ti_size = dmalen;
248 s->ti_rptr = 0;
249 s->ti_wptr = 0;
250 }
251 pic_set_irq(s->irq, 1);
252 }
253
254 static void esp_reset(void *opaque)
255 {
256 ESPState *s = opaque;
257 memset(s->rregs, 0, ESP_MAXREG);
258 s->rregs[0x0e] = 0x4; // Indicate fas100a
259 memset(s->espdmaregs, 0, ESPDMA_REGS * 4);
260 }
261
262 static uint32_t esp_mem_readb(void *opaque, target_phys_addr_t addr)
263 {
264 ESPState *s = opaque;
265 uint32_t saddr;
266
267 saddr = (addr & ESP_MAXREG) >> 2;
268 switch (saddr) {
269 case 2:
270 // FIFO
271 if (s->ti_size > 0) {
272 s->ti_size--;
273 s->rregs[saddr] = s->ti_buf[s->ti_rptr++];
274 pic_set_irq(s->irq, 1);
275 }
276 if (s->ti_size == 0) {
277 s->ti_rptr = 0;
278 s->ti_wptr = 0;
279 }
280 break;
281 default:
282 break;
283 }
284 DPRINTF("read reg[%d]: 0x%2.2x\n", saddr, s->rregs[saddr]);
285
286 return s->rregs[saddr];
287 }
288
289 static void esp_mem_writeb(void *opaque, target_phys_addr_t addr, uint32_t val)
290 {
291 ESPState *s = opaque;
292 uint32_t saddr;
293
294 saddr = (addr & ESP_MAXREG) >> 2;
295 DPRINTF("write reg[%d]: 0x%2.2x -> 0x%2.2x\n", saddr, s->wregs[saddr], val);
296 switch (saddr) {
297 case 0:
298 case 1:
299 s->rregs[saddr] = val;
300 break;
301 case 2:
302 // FIFO
303 s->ti_size++;
304 s->ti_buf[s->ti_wptr++] = val & 0xff;
305 break;
306 case 3:
307 s->rregs[saddr] = val;
308 // Command
309 if (val & 0x80) {
310 s->dma = 1;
311 } else {
312 s->dma = 0;
313 }
314 switch(val & 0x7f) {
315 case 0:
316 DPRINTF("NOP (%2.2x)\n", val);
317 break;
318 case 1:
319 DPRINTF("Flush FIFO (%2.2x)\n", val);
320 s->rregs[6] = 0;
321 s->rregs[5] = INTR_FC;
322 break;
323 case 2:
324 DPRINTF("Chip reset (%2.2x)\n", val);
325 esp_reset(s);
326 break;
327 case 3:
328 DPRINTF("Bus reset (%2.2x)\n", val);
329 break;
330 case 0x10:
331 handle_ti(s);
332 break;
333 case 0x11:
334 DPRINTF("Initiator Command Complete Sequence (%2.2x)\n", val);
335 dma_write(s, okbuf, 2);
336 break;
337 case 0x12:
338 DPRINTF("Message Accepted (%2.2x)\n", val);
339 dma_write(s, okbuf, 2);
340 s->rregs[5] = INTR_DC;
341 s->rregs[6] = 0;
342 break;
343 case 0x1a:
344 DPRINTF("Set ATN (%2.2x)\n", val);
345 break;
346 case 0x42:
347 handle_satn(s);
348 break;
349 case 0x43:
350 DPRINTF("Set ATN & stop (%2.2x)\n", val);
351 handle_satn(s);
352 break;
353 default:
354 DPRINTF("Unhandled ESP command (%2.2x)\n", val);
355 break;
356 }
357 break;
358 case 4 ... 7:
359 break;
360 case 8:
361 s->rregs[saddr] = val;
362 break;
363 case 9 ... 10:
364 break;
365 case 11 ... 15:
366 s->rregs[saddr] = val;
367 break;
368 default:
369 break;
370 }
371 s->wregs[saddr] = val;
372 }
373
374 static CPUReadMemoryFunc *esp_mem_read[3] = {
375 esp_mem_readb,
376 esp_mem_readb,
377 esp_mem_readb,
378 };
379
380 static CPUWriteMemoryFunc *esp_mem_write[3] = {
381 esp_mem_writeb,
382 esp_mem_writeb,
383 esp_mem_writeb,
384 };
385
386 static uint32_t espdma_mem_readl(void *opaque, target_phys_addr_t addr)
387 {
388 ESPState *s = opaque;
389 uint32_t saddr;
390
391 saddr = (addr & ESPDMA_MAXADDR) >> 2;
392 DPRINTF("read dmareg[%d]: 0x%8.8x\n", saddr, s->espdmaregs[saddr]);
393
394 return s->espdmaregs[saddr];
395 }
396
397 static void espdma_mem_writel(void *opaque, target_phys_addr_t addr, uint32_t val)
398 {
399 ESPState *s = opaque;
400 uint32_t saddr;
401
402 saddr = (addr & ESPDMA_MAXADDR) >> 2;
403 DPRINTF("write dmareg[%d]: 0x%8.8x -> 0x%8.8x\n", saddr, s->espdmaregs[saddr], val);
404 switch (saddr) {
405 case 0:
406 if (!(val & 0x10))
407 pic_set_irq(s->irq, 0);
408 if (val & 0x80) {
409 esp_reset(s);
410 } else if (val & 0x40) {
411 val &= ~0x40;
412 } else if (val == 0)
413 val = 0x40;
414 val &= 0x0fffffff;
415 val |= DMA_VER;
416 break;
417 case 1:
418 s->espdmaregs[0] = DMA_LOADED;
419 break;
420 default:
421 break;
422 }
423 s->espdmaregs[saddr] = val;
424 }
425
426 static CPUReadMemoryFunc *espdma_mem_read[3] = {
427 espdma_mem_readl,
428 espdma_mem_readl,
429 espdma_mem_readl,
430 };
431
432 static CPUWriteMemoryFunc *espdma_mem_write[3] = {
433 espdma_mem_writel,
434 espdma_mem_writel,
435 espdma_mem_writel,
436 };
437
438 static void esp_save(QEMUFile *f, void *opaque)
439 {
440 ESPState *s = opaque;
441 unsigned int i;
442
443 qemu_put_buffer(f, s->rregs, ESP_MAXREG);
444 qemu_put_buffer(f, s->wregs, ESP_MAXREG);
445 qemu_put_be32s(f, &s->irq);
446 for (i = 0; i < ESPDMA_REGS; i++)
447 qemu_put_be32s(f, &s->espdmaregs[i]);
448 qemu_put_be32s(f, &s->ti_size);
449 qemu_put_be32s(f, &s->ti_rptr);
450 qemu_put_be32s(f, &s->ti_wptr);
451 qemu_put_be32s(f, &s->ti_dir);
452 qemu_put_buffer(f, s->ti_buf, TI_BUFSZ);
453 qemu_put_be32s(f, &s->dma);
454 }
455
456 static int esp_load(QEMUFile *f, void *opaque, int version_id)
457 {
458 ESPState *s = opaque;
459 unsigned int i;
460
461 if (version_id != 1)
462 return -EINVAL;
463
464 qemu_get_buffer(f, s->rregs, ESP_MAXREG);
465 qemu_get_buffer(f, s->wregs, ESP_MAXREG);
466 qemu_get_be32s(f, &s->irq);
467 for (i = 0; i < ESPDMA_REGS; i++)
468 qemu_get_be32s(f, &s->espdmaregs[i]);
469 qemu_get_be32s(f, &s->ti_size);
470 qemu_get_be32s(f, &s->ti_rptr);
471 qemu_get_be32s(f, &s->ti_wptr);
472 qemu_get_be32s(f, &s->ti_dir);
473 qemu_get_buffer(f, s->ti_buf, TI_BUFSZ);
474 qemu_get_be32s(f, &s->dma);
475
476 return 0;
477 }
478
479 void esp_init(BlockDriverState **bd, int irq, uint32_t espaddr, uint32_t espdaddr)
480 {
481 ESPState *s;
482 int esp_io_memory, espdma_io_memory;
483
484 s = qemu_mallocz(sizeof(ESPState));
485 if (!s)
486 return;
487
488 s->bd = bd;
489 s->irq = irq;
490
491 esp_io_memory = cpu_register_io_memory(0, esp_mem_read, esp_mem_write, s);
492 cpu_register_physical_memory(espaddr, ESP_MAXREG*4, esp_io_memory);
493
494 espdma_io_memory = cpu_register_io_memory(0, espdma_mem_read, espdma_mem_write, s);
495 cpu_register_physical_memory(espdaddr, 16, espdma_io_memory);
496
497 esp_reset(s);
498
499 register_savevm("esp", espaddr, 1, esp_save, esp_load, s);
500 qemu_register_reset(esp_reset, s);
501 }
502