Statistics
| Branch: | Revision:

root / hw / esp.c @ 4d611c9a

History | View | Annotate | Download (15 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
    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
    dmaptr = iommu_translate(s->espdmaregs[1]);
210
    to_device = (s->espdmaregs[0] & DMA_WRITE_MEM) == 0;
211
    from = s->espdmaregs[1];
212
    minlen = s->dma_left;
213
    to = from + minlen;
214
    dmaptr = iommu_translate(s->espdmaregs[1]);
215
    if ((from & TARGET_PAGE_MASK) != (to & TARGET_PAGE_MASK)) {
216
       len = TARGET_PAGE_SIZE - (from & ~TARGET_PAGE_MASK);
217
    } else {
218
       len = to - from;
219
    }
220
    DPRINTF("DMA address p %08x v %08x len %08x, from %08x, to %08x\n", dmaptr, s->espdmaregs[1], len, from, to);
221
    s->espdmaregs[1] += len;
222
    if (s->do_cmd) {
223
        s->ti_size -= len;
224
        DPRINTF("command len %d + %d\n", s->cmdlen, len);
225
        cpu_physical_memory_read(dmaptr, &s->cmdbuf[s->cmdlen], len);
226
        s->ti_size = 0;
227
        s->cmdlen = 0;
228
        s->do_cmd = 0;
229
        do_cmd(s, s->cmdbuf);
230
        return;
231
    } else {
232
        s->async_len = len;
233
        s->dma_left -= len;
234
        if (to_device) {
235
            s->async_ptr = -1;
236
            cpu_physical_memory_read(dmaptr, s->async_buf, len);
237
            scsi_write_data(s->current_dev, s->async_buf, len);
238
        } else {
239
            s->async_ptr = dmaptr;
240
            scsi_read_data(s->current_dev, s->async_buf, len);
241
        }
242
    }
243
}
244

    
245
static void esp_command_complete(void *opaque, uint32_t reason, int sense)
246
{
247
    ESPState *s = (ESPState *)opaque;
248

    
249
    s->ti_size -= s->async_len;
250
    s->espdmaregs[1] += s->async_len;
251
    if (s->async_ptr != (uint32_t)-1) {
252
        cpu_physical_memory_write(s->async_ptr, s->async_buf, s->async_len);
253
    }
254
    if (reason == SCSI_REASON_DONE) {
255
        DPRINTF("SCSI Command complete\n");
256
        if (s->ti_size != 0)
257
            DPRINTF("SCSI command completed unexpectedly\n");
258
        s->ti_size = 0;
259
        if (sense)
260
            DPRINTF("Command failed\n");
261
        s->sense = sense;
262
    } else {
263
        DPRINTF("transfer %d/%d\n", s->dma_left, s->ti_size);
264
    }
265
    if (s->dma_left) {
266
        esp_do_dma(s);
267
    } else {
268
        if (s->ti_size) {
269
            s->rregs[4] |= STAT_IN | STAT_TC;
270
        } else {
271
            s->rregs[4] = STAT_IN | STAT_TC | STAT_ST;
272
        }
273
        s->rregs[5] = INTR_BS;
274
        s->rregs[6] = 0;
275
        s->rregs[7] = 0;
276
        s->espdmaregs[0] |= DMA_INTR;
277
        pic_set_irq(s->irq, 1);
278
    }
279
}
280

    
281
static void handle_ti(ESPState *s)
282
{
283
    uint32_t dmalen, minlen;
284

    
285
    dmalen = s->wregs[0] | (s->wregs[1] << 8);
286
    if (dmalen==0) {
287
      dmalen=0x10000;
288
    }
289

    
290
    if (s->do_cmd)
291
        minlen = (dmalen < 32) ? dmalen : 32;
292
    else
293
        minlen = (dmalen < s->ti_size) ? dmalen : s->ti_size;
294
    DPRINTF("Transfer Information len %d\n", minlen);
295
    if (s->dma) {
296
        s->dma_left = minlen;
297
        s->rregs[4] &= ~STAT_TC;
298
        esp_do_dma(s);
299
    } else if (s->do_cmd) {
300
        DPRINTF("command len %d\n", s->cmdlen);
301
        s->ti_size = 0;
302
        s->cmdlen = 0;
303
        s->do_cmd = 0;
304
        do_cmd(s, s->cmdbuf);
305
        return;
306
    }
307
}
308

    
309
static void esp_reset(void *opaque)
310
{
311
    ESPState *s = opaque;
312
    memset(s->rregs, 0, ESP_MAXREG);
313
    memset(s->wregs, 0, ESP_MAXREG);
314
    s->rregs[0x0e] = 0x4; // Indicate fas100a
315
    memset(s->espdmaregs, 0, ESPDMA_REGS * 4);
316
    s->ti_size = 0;
317
    s->ti_rptr = 0;
318
    s->ti_wptr = 0;
319
    s->dma = 0;
320
    s->do_cmd = 0;
321
}
322

    
323
static uint32_t esp_mem_readb(void *opaque, target_phys_addr_t addr)
324
{
325
    ESPState *s = opaque;
326
    uint32_t saddr;
327

    
328
    saddr = (addr & ESP_MAXREG) >> 2;
329
    DPRINTF("read reg[%d]: 0x%2.2x\n", saddr, s->rregs[saddr]);
330
    switch (saddr) {
331
    case 2:
332
        // FIFO
333
        if (s->ti_size > 0) {
334
            s->ti_size--;
335
            if ((s->rregs[4] & 6) == 0) {
336
                /* Data in/out.  */
337
                scsi_read_data(s->current_dev, &s->rregs[2], 0);
338
            } else {
339
                s->rregs[2] = s->ti_buf[s->ti_rptr++];
340
            }
341
            pic_set_irq(s->irq, 1);
342
        }
343
        if (s->ti_size == 0) {
344
            s->ti_rptr = 0;
345
            s->ti_wptr = 0;
346
        }
347
        break;
348
    case 5:
349
        // interrupt
350
        // Clear interrupt/error status bits
351
        s->rregs[4] &= ~(STAT_IN | STAT_GE | STAT_PE);
352
        pic_set_irq(s->irq, 0);
353
        s->espdmaregs[0] &= ~DMA_INTR;
354
        break;
355
    default:
356
        break;
357
    }
358
    return s->rregs[saddr];
359
}
360

    
361
static void esp_mem_writeb(void *opaque, target_phys_addr_t addr, uint32_t val)
362
{
363
    ESPState *s = opaque;
364
    uint32_t saddr;
365

    
366
    saddr = (addr & ESP_MAXREG) >> 2;
367
    DPRINTF("write reg[%d]: 0x%2.2x -> 0x%2.2x\n", saddr, s->wregs[saddr], val);
368
    switch (saddr) {
369
    case 0:
370
    case 1:
371
        s->rregs[saddr] = val;
372
        s->rregs[4] &= ~STAT_TC;
373
        break;
374
    case 2:
375
        // FIFO
376
        if (s->do_cmd) {
377
            s->cmdbuf[s->cmdlen++] = val & 0xff;
378
        } else if ((s->rregs[4] & 6) == 0) {
379
            uint8_t buf;
380
            buf = val & 0xff;
381
            s->ti_size--;
382
            scsi_write_data(s->current_dev, &buf, 0);
383
        } else {
384
            s->ti_size++;
385
            s->ti_buf[s->ti_wptr++] = val & 0xff;
386
        }
387
        break;
388
    case 3:
389
        s->rregs[saddr] = val;
390
        // Command
391
        if (val & 0x80) {
392
            s->dma = 1;
393
        } else {
394
            s->dma = 0;
395
        }
396
        switch(val & 0x7f) {
397
        case 0:
398
            DPRINTF("NOP (%2.2x)\n", val);
399
            break;
400
        case 1:
401
            DPRINTF("Flush FIFO (%2.2x)\n", val);
402
            //s->ti_size = 0;
403
            s->rregs[5] = INTR_FC;
404
            s->rregs[6] = 0;
405
            break;
406
        case 2:
407
            DPRINTF("Chip reset (%2.2x)\n", val);
408
            esp_reset(s);
409
            break;
410
        case 3:
411
            DPRINTF("Bus reset (%2.2x)\n", val);
412
            s->rregs[5] = INTR_RST;
413
            if (!(s->wregs[8] & 0x40)) {
414
                s->espdmaregs[0] |= DMA_INTR;
415
                pic_set_irq(s->irq, 1);
416
            }
417
            break;
418
        case 0x10:
419
            handle_ti(s);
420
            break;
421
        case 0x11:
422
            DPRINTF("Initiator Command Complete Sequence (%2.2x)\n", val);
423
            write_response(s);
424
            break;
425
        case 0x12:
426
            DPRINTF("Message Accepted (%2.2x)\n", val);
427
            write_response(s);
428
            s->rregs[5] = INTR_DC;
429
            s->rregs[6] = 0;
430
            break;
431
        case 0x1a:
432
            DPRINTF("Set ATN (%2.2x)\n", val);
433
            break;
434
        case 0x42:
435
            DPRINTF("Set ATN (%2.2x)\n", val);
436
            handle_satn(s);
437
            break;
438
        case 0x43:
439
            DPRINTF("Set ATN & stop (%2.2x)\n", val);
440
            handle_satn_stop(s);
441
            break;
442
        default:
443
            DPRINTF("Unhandled ESP command (%2.2x)\n", val);
444
            break;
445
        }
446
        break;
447
    case 4 ... 7:
448
        break;
449
    case 8:
450
        s->rregs[saddr] = val;
451
        break;
452
    case 9 ... 10:
453
        break;
454
    case 11:
455
        s->rregs[saddr] = val & 0x15;
456
        break;
457
    case 12 ... 15:
458
        s->rregs[saddr] = val;
459
        break;
460
    default:
461
        break;
462
    }
463
    s->wregs[saddr] = val;
464
}
465

    
466
static CPUReadMemoryFunc *esp_mem_read[3] = {
467
    esp_mem_readb,
468
    esp_mem_readb,
469
    esp_mem_readb,
470
};
471

    
472
static CPUWriteMemoryFunc *esp_mem_write[3] = {
473
    esp_mem_writeb,
474
    esp_mem_writeb,
475
    esp_mem_writeb,
476
};
477

    
478
static uint32_t espdma_mem_readl(void *opaque, target_phys_addr_t addr)
479
{
480
    ESPState *s = opaque;
481
    uint32_t saddr;
482

    
483
    saddr = (addr & ESPDMA_MAXADDR) >> 2;
484
    DPRINTF("read dmareg[%d]: 0x%8.8x\n", saddr, s->espdmaregs[saddr]);
485

    
486
    return s->espdmaregs[saddr];
487
}
488

    
489
static void espdma_mem_writel(void *opaque, target_phys_addr_t addr, uint32_t val)
490
{
491
    ESPState *s = opaque;
492
    uint32_t saddr;
493

    
494
    saddr = (addr & ESPDMA_MAXADDR) >> 2;
495
    DPRINTF("write dmareg[%d]: 0x%8.8x -> 0x%8.8x\n", saddr, s->espdmaregs[saddr], val);
496
    switch (saddr) {
497
    case 0:
498
        if (!(val & DMA_INTREN))
499
            pic_set_irq(s->irq, 0);
500
        if (val & 0x80) {
501
            esp_reset(s);
502
        } else if (val & 0x40) {
503
            val &= ~0x40;
504
        } else if (val == 0)
505
            val = 0x40;
506
        val &= 0x0fffffff;
507
        val |= DMA_VER;
508
        break;
509
    case 1:
510
        s->espdmaregs[0] |= DMA_LOADED;
511
        break;
512
    default:
513
        break;
514
    }
515
    s->espdmaregs[saddr] = val;
516
}
517

    
518
static CPUReadMemoryFunc *espdma_mem_read[3] = {
519
    espdma_mem_readl,
520
    espdma_mem_readl,
521
    espdma_mem_readl,
522
};
523

    
524
static CPUWriteMemoryFunc *espdma_mem_write[3] = {
525
    espdma_mem_writel,
526
    espdma_mem_writel,
527
    espdma_mem_writel,
528
};
529

    
530
static void esp_save(QEMUFile *f, void *opaque)
531
{
532
    ESPState *s = opaque;
533
    unsigned int i;
534

    
535
    qemu_put_buffer(f, s->rregs, ESP_MAXREG);
536
    qemu_put_buffer(f, s->wregs, ESP_MAXREG);
537
    qemu_put_be32s(f, &s->irq);
538
    for (i = 0; i < ESPDMA_REGS; i++)
539
        qemu_put_be32s(f, &s->espdmaregs[i]);
540
    qemu_put_be32s(f, &s->ti_size);
541
    qemu_put_be32s(f, &s->ti_rptr);
542
    qemu_put_be32s(f, &s->ti_wptr);
543
    qemu_put_buffer(f, s->ti_buf, TI_BUFSZ);
544
    qemu_put_be32s(f, &s->dma);
545
}
546

    
547
static int esp_load(QEMUFile *f, void *opaque, int version_id)
548
{
549
    ESPState *s = opaque;
550
    unsigned int i;
551
    
552
    if (version_id != 1)
553
        return -EINVAL;
554

    
555
    qemu_get_buffer(f, s->rregs, ESP_MAXREG);
556
    qemu_get_buffer(f, s->wregs, ESP_MAXREG);
557
    qemu_get_be32s(f, &s->irq);
558
    for (i = 0; i < ESPDMA_REGS; i++)
559
        qemu_get_be32s(f, &s->espdmaregs[i]);
560
    qemu_get_be32s(f, &s->ti_size);
561
    qemu_get_be32s(f, &s->ti_rptr);
562
    qemu_get_be32s(f, &s->ti_wptr);
563
    qemu_get_buffer(f, s->ti_buf, TI_BUFSZ);
564
    qemu_get_be32s(f, &s->dma);
565

    
566
    return 0;
567
}
568

    
569
void esp_init(BlockDriverState **bd, int irq, uint32_t espaddr, uint32_t espdaddr)
570
{
571
    ESPState *s;
572
    int esp_io_memory, espdma_io_memory;
573
    int i;
574

    
575
    s = qemu_mallocz(sizeof(ESPState));
576
    if (!s)
577
        return;
578

    
579
    s->bd = bd;
580
    s->irq = irq;
581

    
582
    esp_io_memory = cpu_register_io_memory(0, esp_mem_read, esp_mem_write, s);
583
    cpu_register_physical_memory(espaddr, ESP_MAXREG*4, esp_io_memory);
584

    
585
    espdma_io_memory = cpu_register_io_memory(0, espdma_mem_read, espdma_mem_write, s);
586
    cpu_register_physical_memory(espdaddr, 16, espdma_io_memory);
587

    
588
    esp_reset(s);
589

    
590
    register_savevm("esp", espaddr, 1, esp_save, esp_load, s);
591
    qemu_register_reset(esp_reset, s);
592
    for (i = 0; i < MAX_DISKS; i++) {
593
        if (bs_table[i]) {
594
            s->scsi_dev[i] =
595
                scsi_disk_init(bs_table[i], esp_command_complete, s);
596
        }
597
    }
598
}
599