Statistics
| Branch: | Revision:

root / hw / esp.c @ 9f149aa9

History | View | Annotate | Download (14.5 kB)

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