SATN fixes (Blue Swirl).
[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
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
73
74 #define STAT_TC 0x10
75 #define STAT_IN 0x80
76
77 #define INTR_FC 0x08
78 #define INTR_BS 0x10
79 #define INTR_DC 0x20
80 #define INTR_RST 0x80
81
82 #define SEQ_0 0x0
83 #define SEQ_CD 0x4
84
85 static int get_cmd(ESPState *s, uint8_t *buf)
86 {
87     uint32_t dmaptr, dmalen;
88     int target;
89
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     }
103
104     s->ti_size = 0;
105     s->ti_rptr = 0;
106     s->ti_wptr = 0;
107
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 }
120
121 static void do_cmd(ESPState *s, uint8_t *buf)
122 {
123     int32_t datalen;
124     int lun;
125
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 }
146
147 static void handle_satn(ESPState *s)
148 {
149     uint8_t buf[32];
150     int len;
151
152     len = get_cmd(s, buf);
153     if (len)
154         do_cmd(s, buf);
155 }
156
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 }
171
172 static void write_response(ESPState *s)
173 {
174     uint32_t dmaptr;
175
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);
195
196 }
197
198 static void esp_command_complete(void *opaque, uint32_t tag, int sense)
199 {
200     ESPState *s = (ESPState *)opaque;
201
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 }
211
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];
218
219     dmalen = s->wregs[0] | (s->wregs[1] << 8);
220     if (dmalen==0) {
221       dmalen=0x10000;
222     }
223
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 }
281
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 }
295
296 static uint32_t esp_mem_readb(void *opaque, target_phys_addr_t addr)
297 {
298     ESPState *s = opaque;
299     uint32_t saddr;
300
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 }
333
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;
338
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 }
437
438 static CPUReadMemoryFunc *esp_mem_read[3] = {
439     esp_mem_readb,
440     esp_mem_readb,
441     esp_mem_readb,
442 };
443
444 static CPUWriteMemoryFunc *esp_mem_write[3] = {
445     esp_mem_writeb,
446     esp_mem_writeb,
447     esp_mem_writeb,
448 };
449
450 static uint32_t espdma_mem_readl(void *opaque, target_phys_addr_t addr)
451 {
452     ESPState *s = opaque;
453     uint32_t saddr;
454
455     saddr = (addr & ESPDMA_MAXADDR) >> 2;
456     DPRINTF("read dmareg[%d]: 0x%8.8x\n", saddr, s->espdmaregs[saddr]);
457
458     return s->espdmaregs[saddr];
459 }
460
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;
465
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 }
489
490 static CPUReadMemoryFunc *espdma_mem_read[3] = {
491     espdma_mem_readl,
492     espdma_mem_readl,
493     espdma_mem_readl,
494 };
495
496 static CPUWriteMemoryFunc *espdma_mem_write[3] = {
497     espdma_mem_writel,
498     espdma_mem_writel,
499     espdma_mem_writel,
500 };
501
502 static void esp_save(QEMUFile *f, void *opaque)
503 {
504     ESPState *s = opaque;
505     unsigned int i;
506
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 }
518
519 static int esp_load(QEMUFile *f, void *opaque, int version_id)
520 {
521     ESPState *s = opaque;
522     unsigned int i;
523     
524     if (version_id != 1)
525         return -EINVAL;
526
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);
537
538     return 0;
539 }
540
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;
546
547     s = qemu_mallocz(sizeof(ESPState));
548     if (!s)
549         return;
550
551     s->bd = bd;
552     s->irq = irq;
553
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);
556
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);
559
560     esp_reset(s);
561
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 }
571