debuggers.hg

view tools/ioemu/hw/esp.c @ 10995:08a11694b109

[qemu] Update ioemu to qemu 0.8.2.

Signed-off-by: Christian Limpach <Christian.Limpach@xensource.com>
author chris@kneesaa.uk.xensource.com
date Mon Aug 07 18:25:30 2006 +0100 (2006-08-07)
parents b450f21472a0
children 00618037d37d
line source
1 /*
2 * QEMU ESP emulation
3 *
4 * Copyright (c) 2005-2006 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"
26 /* debug ESP card */
27 //#define DEBUG_ESP
29 #ifdef DEBUG_ESP
30 #define DPRINTF(fmt, args...) \
31 do { printf("ESP: " fmt , ##args); } while (0)
32 #define pic_set_irq(irq, level) \
33 do { printf("ESP: set_irq(%d): %d\n", (irq), (level)); pic_set_irq((irq),(level));} while (0)
34 #else
35 #define DPRINTF(fmt, args...)
36 #endif
38 #define ESPDMA_REGS 4
39 #define ESPDMA_MAXADDR (ESPDMA_REGS * 4 - 1)
40 #define ESP_MAXREG 0x3f
41 #define TI_BUFSZ 32
42 #define DMA_VER 0xa0000000
43 #define DMA_INTR 1
44 #define DMA_INTREN 0x10
45 #define DMA_WRITE_MEM 0x100
46 #define DMA_LOADED 0x04000000
47 typedef struct ESPState ESPState;
49 struct ESPState {
50 BlockDriverState **bd;
51 uint8_t rregs[ESP_MAXREG];
52 uint8_t wregs[ESP_MAXREG];
53 int irq;
54 uint32_t espdmaregs[ESPDMA_REGS];
55 uint32_t ti_size;
56 uint32_t ti_rptr, ti_wptr;
57 uint8_t ti_buf[TI_BUFSZ];
58 int sense;
59 int dma;
60 SCSIDevice *scsi_dev[MAX_DISKS];
61 SCSIDevice *current_dev;
62 uint8_t cmdbuf[TI_BUFSZ];
63 int cmdlen;
64 int do_cmd;
65 };
67 #define STAT_DO 0x00
68 #define STAT_DI 0x01
69 #define STAT_CD 0x02
70 #define STAT_ST 0x03
71 #define STAT_MI 0x06
72 #define STAT_MO 0x07
74 #define STAT_TC 0x10
75 #define STAT_IN 0x80
77 #define INTR_FC 0x08
78 #define INTR_BS 0x10
79 #define INTR_DC 0x20
80 #define INTR_RST 0x80
82 #define SEQ_0 0x0
83 #define SEQ_CD 0x4
85 static int get_cmd(ESPState *s, uint8_t *buf)
86 {
87 uint32_t dmaptr, dmalen;
88 int target;
90 dmalen = s->wregs[0] | (s->wregs[1] << 8);
91 target = s->wregs[4] & 7;
92 DPRINTF("get_cmd: len %d target %d\n", dmalen, target);
93 if (s->dma) {
94 dmaptr = iommu_translate(s->espdmaregs[1]);
95 DPRINTF("DMA Direction: %c, addr 0x%8.8x\n",
96 s->espdmaregs[0] & DMA_WRITE_MEM ? 'w': 'r', dmaptr);
97 cpu_physical_memory_read(dmaptr, buf, dmalen);
98 } else {
99 buf[0] = 0;
100 memcpy(&buf[1], s->ti_buf, dmalen);
101 dmalen++;
102 }
104 s->ti_size = 0;
105 s->ti_rptr = 0;
106 s->ti_wptr = 0;
108 if (target >= 4 || !s->scsi_dev[target]) {
109 // No such drive
110 s->rregs[4] = STAT_IN;
111 s->rregs[5] = INTR_DC;
112 s->rregs[6] = SEQ_0;
113 s->espdmaregs[0] |= DMA_INTR;
114 pic_set_irq(s->irq, 1);
115 return 0;
116 }
117 s->current_dev = s->scsi_dev[target];
118 return dmalen;
119 }
121 static void do_cmd(ESPState *s, uint8_t *buf)
122 {
123 int32_t datalen;
124 int lun;
126 DPRINTF("do_cmd: busid 0x%x\n", buf[0]);
127 lun = buf[0] & 7;
128 datalen = scsi_send_command(s->current_dev, 0, &buf[1], lun);
129 if (datalen == 0) {
130 s->ti_size = 0;
131 } else {
132 s->rregs[4] = STAT_IN | STAT_TC;
133 if (datalen > 0) {
134 s->rregs[4] |= STAT_DI;
135 s->ti_size = datalen;
136 } else {
137 s->rregs[4] |= STAT_DO;
138 s->ti_size = -datalen;
139 }
140 }
141 s->rregs[5] = INTR_BS | INTR_FC;
142 s->rregs[6] = SEQ_CD;
143 s->espdmaregs[0] |= DMA_INTR;
144 pic_set_irq(s->irq, 1);
145 }
147 static void handle_satn(ESPState *s)
148 {
149 uint8_t buf[32];
150 int len;
152 len = get_cmd(s, buf);
153 if (len)
154 do_cmd(s, buf);
155 }
157 static void handle_satn_stop(ESPState *s)
158 {
159 s->cmdlen = get_cmd(s, s->cmdbuf);
160 if (s->cmdlen) {
161 DPRINTF("Set ATN & Stop: cmdlen %d\n", s->cmdlen);
162 s->do_cmd = 1;
163 s->espdmaregs[1] += s->cmdlen;
164 s->rregs[4] = STAT_IN | STAT_TC | STAT_CD;
165 s->rregs[5] = INTR_BS | INTR_FC;
166 s->rregs[6] = SEQ_CD;
167 s->espdmaregs[0] |= DMA_INTR;
168 pic_set_irq(s->irq, 1);
169 }
170 }
172 static void write_response(ESPState *s)
173 {
174 uint32_t dmaptr;
176 DPRINTF("Transfer status (sense=%d)\n", s->sense);
177 s->ti_buf[0] = s->sense;
178 s->ti_buf[1] = 0;
179 if (s->dma) {
180 dmaptr = iommu_translate(s->espdmaregs[1]);
181 DPRINTF("DMA Direction: %c\n",
182 s->espdmaregs[0] & DMA_WRITE_MEM ? 'w': 'r');
183 cpu_physical_memory_write(dmaptr, s->ti_buf, 2);
184 s->rregs[4] = STAT_IN | STAT_TC | STAT_ST;
185 s->rregs[5] = INTR_BS | INTR_FC;
186 s->rregs[6] = SEQ_CD;
187 } else {
188 s->ti_size = 2;
189 s->ti_rptr = 0;
190 s->ti_wptr = 0;
191 s->rregs[7] = 2;
192 }
193 s->espdmaregs[0] |= DMA_INTR;
194 pic_set_irq(s->irq, 1);
196 }
198 static void esp_command_complete(void *opaque, uint32_t tag, int sense)
199 {
200 ESPState *s = (ESPState *)opaque;
202 DPRINTF("SCSI Command complete\n");
203 if (s->ti_size != 0)
204 DPRINTF("SCSI command completed unexpectedly\n");
205 s->ti_size = 0;
206 if (sense)
207 DPRINTF("Command failed\n");
208 s->sense = sense;
209 s->rregs[4] = STAT_IN | STAT_TC | STAT_ST;
210 }
212 static void handle_ti(ESPState *s)
213 {
214 uint32_t dmaptr, dmalen, minlen, len, from, to;
215 unsigned int i;
216 int to_device;
217 uint8_t buf[TARGET_PAGE_SIZE];
219 dmalen = s->wregs[0] | (s->wregs[1] << 8);
220 if (dmalen==0) {
221 dmalen=0x10000;
222 }
224 if (s->do_cmd)
225 minlen = (dmalen < 32) ? dmalen : 32;
226 else
227 minlen = (dmalen < s->ti_size) ? dmalen : s->ti_size;
228 DPRINTF("Transfer Information len %d\n", minlen);
229 if (s->dma) {
230 dmaptr = iommu_translate(s->espdmaregs[1]);
231 /* Check if the transfer writes to to reads from the device. */
232 to_device = (s->espdmaregs[0] & DMA_WRITE_MEM) == 0;
233 DPRINTF("DMA Direction: %c, addr 0x%8.8x %08x\n",
234 to_device ? 'r': 'w', dmaptr, s->ti_size);
235 from = s->espdmaregs[1];
236 to = from + minlen;
237 for (i = 0; i < minlen; i += len, from += len) {
238 dmaptr = iommu_translate(s->espdmaregs[1] + i);
239 if ((from & TARGET_PAGE_MASK) != (to & TARGET_PAGE_MASK)) {
240 len = TARGET_PAGE_SIZE - (from & ~TARGET_PAGE_MASK);
241 } else {
242 len = to - from;
243 }
244 DPRINTF("DMA address p %08x v %08x len %08x, from %08x, to %08x\n", dmaptr, s->espdmaregs[1] + i, len, from, to);
245 s->ti_size -= len;
246 if (s->do_cmd) {
247 DPRINTF("command len %d + %d\n", s->cmdlen, len);
248 cpu_physical_memory_read(dmaptr, &s->cmdbuf[s->cmdlen], len);
249 s->ti_size = 0;
250 s->cmdlen = 0;
251 s->do_cmd = 0;
252 do_cmd(s, s->cmdbuf);
253 return;
254 } else {
255 if (to_device) {
256 cpu_physical_memory_read(dmaptr, buf, len);
257 scsi_write_data(s->current_dev, buf, len);
258 } else {
259 scsi_read_data(s->current_dev, buf, len);
260 cpu_physical_memory_write(dmaptr, buf, len);
261 }
262 }
263 }
264 if (s->ti_size) {
265 s->rregs[4] = STAT_IN | STAT_TC | (to_device ? STAT_DO : STAT_DI);
266 }
267 s->rregs[5] = INTR_BS;
268 s->rregs[6] = 0;
269 s->rregs[7] = 0;
270 s->espdmaregs[0] |= DMA_INTR;
271 } else if (s->do_cmd) {
272 DPRINTF("command len %d\n", s->cmdlen);
273 s->ti_size = 0;
274 s->cmdlen = 0;
275 s->do_cmd = 0;
276 do_cmd(s, s->cmdbuf);
277 return;
278 }
279 pic_set_irq(s->irq, 1);
280 }
282 static void esp_reset(void *opaque)
283 {
284 ESPState *s = opaque;
285 memset(s->rregs, 0, ESP_MAXREG);
286 memset(s->wregs, 0, ESP_MAXREG);
287 s->rregs[0x0e] = 0x4; // Indicate fas100a
288 memset(s->espdmaregs, 0, ESPDMA_REGS * 4);
289 s->ti_size = 0;
290 s->ti_rptr = 0;
291 s->ti_wptr = 0;
292 s->dma = 0;
293 s->do_cmd = 0;
294 }
296 static uint32_t esp_mem_readb(void *opaque, target_phys_addr_t addr)
297 {
298 ESPState *s = opaque;
299 uint32_t saddr;
301 saddr = (addr & ESP_MAXREG) >> 2;
302 DPRINTF("read reg[%d]: 0x%2.2x\n", saddr, s->rregs[saddr]);
303 switch (saddr) {
304 case 2:
305 // FIFO
306 if (s->ti_size > 0) {
307 s->ti_size--;
308 if ((s->rregs[4] & 6) == 0) {
309 /* Data in/out. */
310 scsi_read_data(s->current_dev, &s->rregs[2], 0);
311 } else {
312 s->rregs[2] = s->ti_buf[s->ti_rptr++];
313 }
314 pic_set_irq(s->irq, 1);
315 }
316 if (s->ti_size == 0) {
317 s->ti_rptr = 0;
318 s->ti_wptr = 0;
319 }
320 break;
321 case 5:
322 // interrupt
323 // Clear status bits except TC
324 s->rregs[4] &= STAT_TC;
325 pic_set_irq(s->irq, 0);
326 s->espdmaregs[0] &= ~DMA_INTR;
327 break;
328 default:
329 break;
330 }
331 return s->rregs[saddr];
332 }
334 static void esp_mem_writeb(void *opaque, target_phys_addr_t addr, uint32_t val)
335 {
336 ESPState *s = opaque;
337 uint32_t saddr;
339 saddr = (addr & ESP_MAXREG) >> 2;
340 DPRINTF("write reg[%d]: 0x%2.2x -> 0x%2.2x\n", saddr, s->wregs[saddr], val);
341 switch (saddr) {
342 case 0:
343 case 1:
344 s->rregs[saddr] = val;
345 break;
346 case 2:
347 // FIFO
348 if (s->do_cmd) {
349 s->cmdbuf[s->cmdlen++] = val & 0xff;
350 } else if ((s->rregs[4] & 6) == 0) {
351 uint8_t buf;
352 buf = val & 0xff;
353 s->ti_size--;
354 scsi_write_data(s->current_dev, &buf, 0);
355 } else {
356 s->ti_size++;
357 s->ti_buf[s->ti_wptr++] = val & 0xff;
358 }
359 break;
360 case 3:
361 s->rregs[saddr] = val;
362 // Command
363 if (val & 0x80) {
364 s->dma = 1;
365 } else {
366 s->dma = 0;
367 }
368 switch(val & 0x7f) {
369 case 0:
370 DPRINTF("NOP (%2.2x)\n", val);
371 break;
372 case 1:
373 DPRINTF("Flush FIFO (%2.2x)\n", val);
374 //s->ti_size = 0;
375 s->rregs[5] = INTR_FC;
376 s->rregs[6] = 0;
377 break;
378 case 2:
379 DPRINTF("Chip reset (%2.2x)\n", val);
380 esp_reset(s);
381 break;
382 case 3:
383 DPRINTF("Bus reset (%2.2x)\n", val);
384 s->rregs[5] = INTR_RST;
385 if (!(s->wregs[8] & 0x40)) {
386 s->espdmaregs[0] |= DMA_INTR;
387 pic_set_irq(s->irq, 1);
388 }
389 break;
390 case 0x10:
391 handle_ti(s);
392 break;
393 case 0x11:
394 DPRINTF("Initiator Command Complete Sequence (%2.2x)\n", val);
395 write_response(s);
396 break;
397 case 0x12:
398 DPRINTF("Message Accepted (%2.2x)\n", val);
399 write_response(s);
400 s->rregs[5] = INTR_DC;
401 s->rregs[6] = 0;
402 break;
403 case 0x1a:
404 DPRINTF("Set ATN (%2.2x)\n", val);
405 break;
406 case 0x42:
407 DPRINTF("Set ATN (%2.2x)\n", val);
408 handle_satn(s);
409 break;
410 case 0x43:
411 DPRINTF("Set ATN & stop (%2.2x)\n", val);
412 handle_satn_stop(s);
413 break;
414 default:
415 DPRINTF("Unhandled ESP command (%2.2x)\n", val);
416 break;
417 }
418 break;
419 case 4 ... 7:
420 break;
421 case 8:
422 s->rregs[saddr] = val;
423 break;
424 case 9 ... 10:
425 break;
426 case 11:
427 s->rregs[saddr] = val & 0x15;
428 break;
429 case 12 ... 15:
430 s->rregs[saddr] = val;
431 break;
432 default:
433 break;
434 }
435 s->wregs[saddr] = val;
436 }
438 static CPUReadMemoryFunc *esp_mem_read[3] = {
439 esp_mem_readb,
440 esp_mem_readb,
441 esp_mem_readb,
442 };
444 static CPUWriteMemoryFunc *esp_mem_write[3] = {
445 esp_mem_writeb,
446 esp_mem_writeb,
447 esp_mem_writeb,
448 };
450 static uint32_t espdma_mem_readl(void *opaque, target_phys_addr_t addr)
451 {
452 ESPState *s = opaque;
453 uint32_t saddr;
455 saddr = (addr & ESPDMA_MAXADDR) >> 2;
456 DPRINTF("read dmareg[%d]: 0x%8.8x\n", saddr, s->espdmaregs[saddr]);
458 return s->espdmaregs[saddr];
459 }
461 static void espdma_mem_writel(void *opaque, target_phys_addr_t addr, uint32_t val)
462 {
463 ESPState *s = opaque;
464 uint32_t saddr;
466 saddr = (addr & ESPDMA_MAXADDR) >> 2;
467 DPRINTF("write dmareg[%d]: 0x%8.8x -> 0x%8.8x\n", saddr, s->espdmaregs[saddr], val);
468 switch (saddr) {
469 case 0:
470 if (!(val & DMA_INTREN))
471 pic_set_irq(s->irq, 0);
472 if (val & 0x80) {
473 esp_reset(s);
474 } else if (val & 0x40) {
475 val &= ~0x40;
476 } else if (val == 0)
477 val = 0x40;
478 val &= 0x0fffffff;
479 val |= DMA_VER;
480 break;
481 case 1:
482 s->espdmaregs[0] |= DMA_LOADED;
483 break;
484 default:
485 break;
486 }
487 s->espdmaregs[saddr] = val;
488 }
490 static CPUReadMemoryFunc *espdma_mem_read[3] = {
491 espdma_mem_readl,
492 espdma_mem_readl,
493 espdma_mem_readl,
494 };
496 static CPUWriteMemoryFunc *espdma_mem_write[3] = {
497 espdma_mem_writel,
498 espdma_mem_writel,
499 espdma_mem_writel,
500 };
502 static void esp_save(QEMUFile *f, void *opaque)
503 {
504 ESPState *s = opaque;
505 unsigned int i;
507 qemu_put_buffer(f, s->rregs, ESP_MAXREG);
508 qemu_put_buffer(f, s->wregs, ESP_MAXREG);
509 qemu_put_be32s(f, &s->irq);
510 for (i = 0; i < ESPDMA_REGS; i++)
511 qemu_put_be32s(f, &s->espdmaregs[i]);
512 qemu_put_be32s(f, &s->ti_size);
513 qemu_put_be32s(f, &s->ti_rptr);
514 qemu_put_be32s(f, &s->ti_wptr);
515 qemu_put_buffer(f, s->ti_buf, TI_BUFSZ);
516 qemu_put_be32s(f, &s->dma);
517 }
519 static int esp_load(QEMUFile *f, void *opaque, int version_id)
520 {
521 ESPState *s = opaque;
522 unsigned int i;
524 if (version_id != 1)
525 return -EINVAL;
527 qemu_get_buffer(f, s->rregs, ESP_MAXREG);
528 qemu_get_buffer(f, s->wregs, ESP_MAXREG);
529 qemu_get_be32s(f, &s->irq);
530 for (i = 0; i < ESPDMA_REGS; i++)
531 qemu_get_be32s(f, &s->espdmaregs[i]);
532 qemu_get_be32s(f, &s->ti_size);
533 qemu_get_be32s(f, &s->ti_rptr);
534 qemu_get_be32s(f, &s->ti_wptr);
535 qemu_get_buffer(f, s->ti_buf, TI_BUFSZ);
536 qemu_get_be32s(f, &s->dma);
538 return 0;
539 }
541 void esp_init(BlockDriverState **bd, int irq, uint32_t espaddr, uint32_t espdaddr)
542 {
543 ESPState *s;
544 int esp_io_memory, espdma_io_memory;
545 int i;
547 s = qemu_mallocz(sizeof(ESPState));
548 if (!s)
549 return;
551 s->bd = bd;
552 s->irq = irq;
554 esp_io_memory = cpu_register_io_memory(0, esp_mem_read, esp_mem_write, s);
555 cpu_register_physical_memory(espaddr, ESP_MAXREG*4, esp_io_memory);
557 espdma_io_memory = cpu_register_io_memory(0, espdma_mem_read, espdma_mem_write, s);
558 cpu_register_physical_memory(espdaddr, 16, espdma_io_memory);
560 esp_reset(s);
562 register_savevm("esp", espaddr, 1, esp_save, esp_load, s);
563 qemu_register_reset(esp_reset, s);
564 for (i = 0; i < MAX_DISKS; i++) {
565 if (bs_table[i]) {
566 s->scsi_dev[i] =
567 scsi_disk_init(bs_table[i], esp_command_complete, s);
568 }
569 }
570 }