ESP DMA fix.
[qemu] / hw / esp.c
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"
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 #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
37
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;
48
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
66     uint32_t dma_left;
67     uint8_t async_buf[TARGET_PAGE_SIZE];
68     uint32_t async_ptr;
69     uint32_t async_len;
70 };
71
72 #define STAT_DO 0x00
73 #define STAT_DI 0x01
74 #define STAT_CD 0x02
75 #define STAT_ST 0x03
76 #define STAT_MI 0x06
77 #define STAT_MO 0x07
78
79 #define STAT_TC 0x10
80 #define STAT_PE 0x20
81 #define STAT_GE 0x40
82 #define STAT_IN 0x80
83
84 #define INTR_FC 0x08
85 #define INTR_BS 0x10
86 #define INTR_DC 0x20
87 #define INTR_RST 0x80
88
89 #define SEQ_0 0x0
90 #define SEQ_CD 0x4
91
92 static int get_cmd(ESPState *s, uint8_t *buf)
93 {
94     uint32_t dmaptr, dmalen;
95     int target;
96
97     dmalen = s->wregs[0] | (s->wregs[1] << 8);
98     target = s->wregs[4] & 7;
99     DPRINTF("get_cmd: len %d target %d\n", dmalen, target);
100     if (s->dma) {
101         dmaptr = iommu_translate(s->espdmaregs[1]);
102         DPRINTF("DMA Direction: %c, addr 0x%8.8x\n",
103                 s->espdmaregs[0] & DMA_WRITE_MEM ? 'w': 'r', dmaptr);
104         cpu_physical_memory_read(dmaptr, buf, dmalen);
105     } else {
106         buf[0] = 0;
107         memcpy(&buf[1], s->ti_buf, dmalen);
108         dmalen++;
109     }
110
111     s->ti_size = 0;
112     s->ti_rptr = 0;
113     s->ti_wptr = 0;
114
115     if (target >= 4 || !s->scsi_dev[target]) {
116         // No such drive
117         s->rregs[4] = STAT_IN;
118         s->rregs[5] = INTR_DC;
119         s->rregs[6] = SEQ_0;
120         s->espdmaregs[0] |= DMA_INTR;
121         pic_set_irq(s->irq, 1);
122         return 0;
123     }
124     s->current_dev = s->scsi_dev[target];
125     return dmalen;
126 }
127
128 static void do_cmd(ESPState *s, uint8_t *buf)
129 {
130     int32_t datalen;
131     int lun;
132
133     DPRINTF("do_cmd: busid 0x%x\n", buf[0]);
134     lun = buf[0] & 7;
135     datalen = scsi_send_command(s->current_dev, 0, &buf[1], lun);
136     if (datalen == 0) {
137         s->ti_size = 0;
138     } else {
139         s->rregs[4] = STAT_IN | STAT_TC;
140         if (datalen > 0) {
141             s->rregs[4] |= STAT_DI;
142             s->ti_size = datalen;
143         } else {
144             s->rregs[4] |= STAT_DO;
145             s->ti_size = -datalen;
146         }
147     }
148     s->rregs[5] = INTR_BS | INTR_FC;
149     s->rregs[6] = SEQ_CD;
150     s->espdmaregs[0] |= DMA_INTR;
151     pic_set_irq(s->irq, 1);
152 }
153
154 static void handle_satn(ESPState *s)
155 {
156     uint8_t buf[32];
157     int len;
158
159     len = get_cmd(s, buf);
160     if (len)
161         do_cmd(s, buf);
162 }
163
164 static void handle_satn_stop(ESPState *s)
165 {
166     s->cmdlen = get_cmd(s, s->cmdbuf);
167     if (s->cmdlen) {
168         DPRINTF("Set ATN & Stop: cmdlen %d\n", s->cmdlen);
169         s->do_cmd = 1;
170         s->espdmaregs[1] += s->cmdlen;
171         s->rregs[4] = STAT_IN | STAT_TC | STAT_CD;
172         s->rregs[5] = INTR_BS | INTR_FC;
173         s->rregs[6] = SEQ_CD;
174         s->espdmaregs[0] |= DMA_INTR;
175         pic_set_irq(s->irq, 1);
176     }
177 }
178
179 static void write_response(ESPState *s)
180 {
181     uint32_t dmaptr;
182
183     DPRINTF("Transfer status (sense=%d)\n", s->sense);
184     s->ti_buf[0] = s->sense;
185     s->ti_buf[1] = 0;
186     if (s->dma) {
187         dmaptr = iommu_translate(s->espdmaregs[1]);
188         DPRINTF("DMA Direction: %c\n",
189                 s->espdmaregs[0] & DMA_WRITE_MEM ? 'w': 'r');
190         cpu_physical_memory_write(dmaptr, s->ti_buf, 2);
191         s->rregs[4] = STAT_IN | STAT_TC | STAT_ST;
192         s->rregs[5] = INTR_BS | INTR_FC;
193         s->rregs[6] = SEQ_CD;
194     } else {
195         s->ti_size = 2;
196         s->ti_rptr = 0;
197         s->ti_wptr = 0;
198         s->rregs[7] = 2;
199     }
200     s->espdmaregs[0] |= DMA_INTR;
201     pic_set_irq(s->irq, 1);
202
203 }
204
205 static void esp_do_dma(ESPState *s)
206 {
207     uint32_t dmaptr, minlen, len, from, to;
208     int to_device;
209     to_device = (s->espdmaregs[0] & DMA_WRITE_MEM) == 0;
210     from = s->espdmaregs[1];
211     minlen = s->dma_left;
212     to = from + minlen;
213     dmaptr = iommu_translate(s->espdmaregs[1]);
214     if ((from & TARGET_PAGE_MASK) != (to & TARGET_PAGE_MASK)) {
215        len = TARGET_PAGE_SIZE - (from & ~TARGET_PAGE_MASK);
216     } else {
217        len = to - from;
218     }
219     DPRINTF("DMA address p %08x v %08x len %08x, from %08x, to %08x\n", dmaptr, s->espdmaregs[1], len, from, to);
220     if (s->do_cmd) {
221         s->espdmaregs[1] += len;
222         s->ti_size -= len;
223         DPRINTF("command len %d + %d\n", s->cmdlen, len);
224         cpu_physical_memory_read(dmaptr, &s->cmdbuf[s->cmdlen], len);
225         s->ti_size = 0;
226         s->cmdlen = 0;
227         s->do_cmd = 0;
228         do_cmd(s, s->cmdbuf);
229         return;
230     } else {
231         s->async_len = len;
232         s->dma_left -= len;
233         if (to_device) {
234             s->async_ptr = -1;
235             cpu_physical_memory_read(dmaptr, s->async_buf, len);
236             scsi_write_data(s->current_dev, s->async_buf, len);
237         } else {
238             s->async_ptr = dmaptr;
239             scsi_read_data(s->current_dev, s->async_buf, len);
240         }
241     }
242 }
243
244 static void esp_command_complete(void *opaque, uint32_t reason, int sense)
245 {
246     ESPState *s = (ESPState *)opaque;
247
248     s->ti_size -= s->async_len;
249     s->espdmaregs[1] += s->async_len;
250     if (s->async_ptr != (uint32_t)-1) {
251         cpu_physical_memory_write(s->async_ptr, s->async_buf, s->async_len);
252     }
253     if (reason == SCSI_REASON_DONE) {
254         DPRINTF("SCSI Command complete\n");
255         if (s->ti_size != 0)
256             DPRINTF("SCSI command completed unexpectedly\n");
257         s->ti_size = 0;
258         if (sense)
259             DPRINTF("Command failed\n");
260         s->sense = sense;
261     } else {
262         DPRINTF("transfer %d/%d\n", s->dma_left, s->ti_size);
263     }
264     if (s->dma_left) {
265         esp_do_dma(s);
266     } else {
267         if (s->ti_size) {
268             s->rregs[4] |= STAT_IN | STAT_TC;
269         } else {
270             s->rregs[4] = STAT_IN | STAT_TC | STAT_ST;
271         }
272         s->rregs[5] = INTR_BS;
273         s->rregs[6] = 0;
274         s->rregs[7] = 0;
275         s->espdmaregs[0] |= DMA_INTR;
276         pic_set_irq(s->irq, 1);
277     }
278 }
279
280 static void handle_ti(ESPState *s)
281 {
282     uint32_t dmalen, minlen;
283
284     dmalen = s->wregs[0] | (s->wregs[1] << 8);
285     if (dmalen==0) {
286       dmalen=0x10000;
287     }
288
289     if (s->do_cmd)
290         minlen = (dmalen < 32) ? dmalen : 32;
291     else
292         minlen = (dmalen < s->ti_size) ? dmalen : s->ti_size;
293     DPRINTF("Transfer Information len %d\n", minlen);
294     if (s->dma) {
295         s->dma_left = minlen;
296         s->rregs[4] &= ~STAT_TC;
297         esp_do_dma(s);
298     } else if (s->do_cmd) {
299         DPRINTF("command len %d\n", s->cmdlen);
300         s->ti_size = 0;
301         s->cmdlen = 0;
302         s->do_cmd = 0;
303         do_cmd(s, s->cmdbuf);
304         return;
305     }
306 }
307
308 static void esp_reset(void *opaque)
309 {
310     ESPState *s = opaque;
311     memset(s->rregs, 0, ESP_MAXREG);
312     memset(s->wregs, 0, ESP_MAXREG);
313     s->rregs[0x0e] = 0x4; // Indicate fas100a
314     memset(s->espdmaregs, 0, ESPDMA_REGS * 4);
315     s->ti_size = 0;
316     s->ti_rptr = 0;
317     s->ti_wptr = 0;
318     s->dma = 0;
319     s->do_cmd = 0;
320 }
321
322 static uint32_t esp_mem_readb(void *opaque, target_phys_addr_t addr)
323 {
324     ESPState *s = opaque;
325     uint32_t saddr;
326
327     saddr = (addr & ESP_MAXREG) >> 2;
328     DPRINTF("read reg[%d]: 0x%2.2x\n", saddr, s->rregs[saddr]);
329     switch (saddr) {
330     case 2:
331         // FIFO
332         if (s->ti_size > 0) {
333             s->ti_size--;
334             if ((s->rregs[4] & 6) == 0) {
335                 /* Data in/out.  */
336                 scsi_read_data(s->current_dev, &s->rregs[2], 0);
337             } else {
338                 s->rregs[2] = s->ti_buf[s->ti_rptr++];
339             }
340             pic_set_irq(s->irq, 1);
341         }
342         if (s->ti_size == 0) {
343             s->ti_rptr = 0;
344             s->ti_wptr = 0;
345         }
346         break;
347     case 5:
348         // interrupt
349         // Clear interrupt/error status bits
350         s->rregs[4] &= ~(STAT_IN | STAT_GE | STAT_PE);
351         pic_set_irq(s->irq, 0);
352         s->espdmaregs[0] &= ~DMA_INTR;
353         break;
354     default:
355         break;
356     }
357     return s->rregs[saddr];
358 }
359
360 static void esp_mem_writeb(void *opaque, target_phys_addr_t addr, uint32_t val)
361 {
362     ESPState *s = opaque;
363     uint32_t saddr;
364
365     saddr = (addr & ESP_MAXREG) >> 2;
366     DPRINTF("write reg[%d]: 0x%2.2x -> 0x%2.2x\n", saddr, s->wregs[saddr], val);
367     switch (saddr) {
368     case 0:
369     case 1:
370         s->rregs[saddr] = val;
371         s->rregs[4] &= ~STAT_TC;
372         break;
373     case 2:
374         // FIFO
375         if (s->do_cmd) {
376             s->cmdbuf[s->cmdlen++] = val & 0xff;
377         } else if ((s->rregs[4] & 6) == 0) {
378             uint8_t buf;
379             buf = val & 0xff;
380             s->ti_size--;
381             scsi_write_data(s->current_dev, &buf, 0);
382         } else {
383             s->ti_size++;
384             s->ti_buf[s->ti_wptr++] = val & 0xff;
385         }
386         break;
387     case 3:
388         s->rregs[saddr] = val;
389         // Command
390         if (val & 0x80) {
391             s->dma = 1;
392         } else {
393             s->dma = 0;
394         }
395         switch(val & 0x7f) {
396         case 0:
397             DPRINTF("NOP (%2.2x)\n", val);
398             break;
399         case 1:
400             DPRINTF("Flush FIFO (%2.2x)\n", val);
401             //s->ti_size = 0;
402             s->rregs[5] = INTR_FC;
403             s->rregs[6] = 0;
404             break;
405         case 2:
406             DPRINTF("Chip reset (%2.2x)\n", val);
407             esp_reset(s);
408             break;
409         case 3:
410             DPRINTF("Bus reset (%2.2x)\n", val);
411             s->rregs[5] = INTR_RST;
412             if (!(s->wregs[8] & 0x40)) {
413                 s->espdmaregs[0] |= DMA_INTR;
414                 pic_set_irq(s->irq, 1);
415             }
416             break;
417         case 0x10:
418             handle_ti(s);
419             break;
420         case 0x11:
421             DPRINTF("Initiator Command Complete Sequence (%2.2x)\n", val);
422             write_response(s);
423             break;
424         case 0x12:
425             DPRINTF("Message Accepted (%2.2x)\n", val);
426             write_response(s);
427             s->rregs[5] = INTR_DC;
428             s->rregs[6] = 0;
429             break;
430         case 0x1a:
431             DPRINTF("Set ATN (%2.2x)\n", val);
432             break;
433         case 0x42:
434             DPRINTF("Set ATN (%2.2x)\n", val);
435             handle_satn(s);
436             break;
437         case 0x43:
438             DPRINTF("Set ATN & stop (%2.2x)\n", val);
439             handle_satn_stop(s);
440             break;
441         default:
442             DPRINTF("Unhandled ESP command (%2.2x)\n", val);
443             break;
444         }
445         break;
446     case 4 ... 7:
447         break;
448     case 8:
449         s->rregs[saddr] = val;
450         break;
451     case 9 ... 10:
452         break;
453     case 11:
454         s->rregs[saddr] = val & 0x15;
455         break;
456     case 12 ... 15:
457         s->rregs[saddr] = val;
458         break;
459     default:
460         break;
461     }
462     s->wregs[saddr] = val;
463 }
464
465 static CPUReadMemoryFunc *esp_mem_read[3] = {
466     esp_mem_readb,
467     esp_mem_readb,
468     esp_mem_readb,
469 };
470
471 static CPUWriteMemoryFunc *esp_mem_write[3] = {
472     esp_mem_writeb,
473     esp_mem_writeb,
474     esp_mem_writeb,
475 };
476
477 static uint32_t espdma_mem_readl(void *opaque, target_phys_addr_t addr)
478 {
479     ESPState *s = opaque;
480     uint32_t saddr;
481
482     saddr = (addr & ESPDMA_MAXADDR) >> 2;
483     DPRINTF("read dmareg[%d]: 0x%8.8x\n", saddr, s->espdmaregs[saddr]);
484
485     return s->espdmaregs[saddr];
486 }
487
488 static void espdma_mem_writel(void *opaque, target_phys_addr_t addr, uint32_t val)
489 {
490     ESPState *s = opaque;
491     uint32_t saddr;
492
493     saddr = (addr & ESPDMA_MAXADDR) >> 2;
494     DPRINTF("write dmareg[%d]: 0x%8.8x -> 0x%8.8x\n", saddr, s->espdmaregs[saddr], val);
495     switch (saddr) {
496     case 0:
497         if (!(val & DMA_INTREN))
498             pic_set_irq(s->irq, 0);
499         if (val & 0x80) {
500             esp_reset(s);
501         } else if (val & 0x40) {
502             val &= ~0x40;
503         } else if (val == 0)
504             val = 0x40;
505         val &= 0x0fffffff;
506         val |= DMA_VER;
507         break;
508     case 1:
509         s->espdmaregs[0] |= DMA_LOADED;
510         break;
511     default:
512         break;
513     }
514     s->espdmaregs[saddr] = val;
515 }
516
517 static CPUReadMemoryFunc *espdma_mem_read[3] = {
518     espdma_mem_readl,
519     espdma_mem_readl,
520     espdma_mem_readl,
521 };
522
523 static CPUWriteMemoryFunc *espdma_mem_write[3] = {
524     espdma_mem_writel,
525     espdma_mem_writel,
526     espdma_mem_writel,
527 };
528
529 static void esp_save(QEMUFile *f, void *opaque)
530 {
531     ESPState *s = opaque;
532     unsigned int i;
533
534     qemu_put_buffer(f, s->rregs, ESP_MAXREG);
535     qemu_put_buffer(f, s->wregs, ESP_MAXREG);
536     qemu_put_be32s(f, &s->irq);
537     for (i = 0; i < ESPDMA_REGS; i++)
538         qemu_put_be32s(f, &s->espdmaregs[i]);
539     qemu_put_be32s(f, &s->ti_size);
540     qemu_put_be32s(f, &s->ti_rptr);
541     qemu_put_be32s(f, &s->ti_wptr);
542     qemu_put_buffer(f, s->ti_buf, TI_BUFSZ);
543     qemu_put_be32s(f, &s->dma);
544 }
545
546 static int esp_load(QEMUFile *f, void *opaque, int version_id)
547 {
548     ESPState *s = opaque;
549     unsigned int i;
550     
551     if (version_id != 1)
552         return -EINVAL;
553
554     qemu_get_buffer(f, s->rregs, ESP_MAXREG);
555     qemu_get_buffer(f, s->wregs, ESP_MAXREG);
556     qemu_get_be32s(f, &s->irq);
557     for (i = 0; i < ESPDMA_REGS; i++)
558         qemu_get_be32s(f, &s->espdmaregs[i]);
559     qemu_get_be32s(f, &s->ti_size);
560     qemu_get_be32s(f, &s->ti_rptr);
561     qemu_get_be32s(f, &s->ti_wptr);
562     qemu_get_buffer(f, s->ti_buf, TI_BUFSZ);
563     qemu_get_be32s(f, &s->dma);
564
565     return 0;
566 }
567
568 void esp_init(BlockDriverState **bd, int irq, uint32_t espaddr, uint32_t espdaddr)
569 {
570     ESPState *s;
571     int esp_io_memory, espdma_io_memory;
572     int i;
573
574     s = qemu_mallocz(sizeof(ESPState));
575     if (!s)
576         return;
577
578     s->bd = bd;
579     s->irq = irq;
580
581     esp_io_memory = cpu_register_io_memory(0, esp_mem_read, esp_mem_write, s);
582     cpu_register_physical_memory(espaddr, ESP_MAXREG*4, esp_io_memory);
583
584     espdma_io_memory = cpu_register_io_memory(0, espdma_mem_read, espdma_mem_write, s);
585     cpu_register_physical_memory(espdaddr, 16, espdma_io_memory);
586
587     esp_reset(s);
588
589     register_savevm("esp", espaddr, 1, esp_save, esp_load, s);
590     qemu_register_reset(esp_reset, s);
591     for (i = 0; i < MAX_DISKS; i++) {
592         if (bs_table[i]) {
593             s->scsi_dev[i] =
594                 scsi_disk_init(bs_table[i], esp_command_complete, s);
595         }
596     }
597 }
598