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