Blame view

hw/esp.c 18.6 KB
bellard authored
1
/*
2
 * QEMU ESP/NCR53C9x emulation
3
 *
4
 * Copyright (c) 2005-2006 Fabrice Bellard
5
 *
bellard authored
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 * THE SOFTWARE.
 */
24
Paul Brook authored
25
#include "sysbus.h"
pbrook authored
26
#include "scsi-disk.h"
27
#include "scsi.h"
bellard authored
28
29

/* debug ESP card */
bellard authored
30
//#define DEBUG_ESP
bellard authored
31
32
/*
33
34
 * On Sparc32, this is the ESP (NCR53C90) part of chip STP2000 (Master I/O),
 * also produced as NCR89C100. See
35
36
37
38
39
 * http://www.ibiblio.org/pub/historic-linux/early-ports/Sparc/NCR/NCR89C100.txt
 * and
 * http://www.ibiblio.org/pub/historic-linux/early-ports/Sparc/NCR/NCR53C9X.txt
 */
bellard authored
40
#ifdef DEBUG_ESP
41
42
#define DPRINTF(fmt, ...)                                       \
    do { printf("ESP: " fmt , ## __VA_ARGS__); } while (0)
bellard authored
43
#else
44
#define DPRINTF(fmt, ...) do {} while (0)
bellard authored
45
46
#endif
47
48
#define ESP_ERROR(fmt, ...)                                             \
    do { printf("ESP ERROR: %s: " fmt, __func__ , ## __VA_ARGS__); } while (0)
49
50
#define ESP_REGS 16
51
#define TI_BUFSZ 16
52
53
typedef struct ESPState ESPState;
bellard authored
54
55
struct ESPState {
Paul Brook authored
56
    SysBusDevice busdev;
57
    uint32_t it_shift;
58
    qemu_irq irq;
59
60
    uint8_t rregs[ESP_REGS];
    uint8_t wregs[ESP_REGS];
61
    int32_t ti_size;
62
63
    uint32_t ti_rptr, ti_wptr;
    uint8_t ti_buf[TI_BUFSZ];
blueswir1 authored
64
65
    uint32_t sense;
    uint32_t dma;
66
    SCSIDevice *scsi_dev[ESP_MAX_DEVS];
67
    SCSIDevice *current_dev;
pbrook authored
68
    uint8_t cmdbuf[TI_BUFSZ];
blueswir1 authored
69
70
    uint32_t cmdlen;
    uint32_t do_cmd;
71
pbrook authored
72
    /* The amount of data left in the current DMA transfer.  */
73
    uint32_t dma_left;
pbrook authored
74
75
76
    /* The size of the current DMA transfer.  Zero if no transfer is in
       progress.  */
    uint32_t dma_counter;
pbrook authored
77
    uint8_t *async_buf;
78
    uint32_t async_len;
79
80
81

    espdma_memory_read_write dma_memory_read;
    espdma_memory_read_write dma_memory_write;
82
    void *dma_opaque;
83
};
bellard authored
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
#define ESP_TCLO   0x0
#define ESP_TCMID  0x1
#define ESP_FIFO   0x2
#define ESP_CMD    0x3
#define ESP_RSTAT  0x4
#define ESP_WBUSID 0x4
#define ESP_RINTR  0x5
#define ESP_WSEL   0x5
#define ESP_RSEQ   0x6
#define ESP_WSYNTP 0x6
#define ESP_RFLAGS 0x7
#define ESP_WSYNO  0x7
#define ESP_CFG1   0x8
#define ESP_RRES1  0x9
#define ESP_WCCF   0x9
#define ESP_RRES2  0xa
#define ESP_WTEST  0xa
#define ESP_CFG2   0xb
#define ESP_CFG3   0xc
#define ESP_RES3   0xd
#define ESP_TCHI   0xe
#define ESP_RES4   0xf

#define CMD_DMA 0x80
#define CMD_CMD 0x7f

#define CMD_NOP      0x00
#define CMD_FLUSH    0x01
#define CMD_RESET    0x02
#define CMD_BUSRESET 0x03
#define CMD_TI       0x10
#define CMD_ICCS     0x11
#define CMD_MSGACC   0x12
#define CMD_SATN     0x1a
#define CMD_SELATN   0x42
#define CMD_SELATNS  0x43
#define CMD_ENSEL    0x44
bellard authored
123
124
125
126
#define STAT_DO 0x00
#define STAT_DI 0x01
#define STAT_CD 0x02
#define STAT_ST 0x03
127
128
#define STAT_MO 0x06
#define STAT_MI 0x07
129
#define STAT_PIO_MASK 0x06
bellard authored
130
131

#define STAT_TC 0x10
132
133
#define STAT_PE 0x20
#define STAT_GE 0x40
134
#define STAT_INT 0x80
bellard authored
135
136
137
#define BUSID_DID 0x07
bellard authored
138
139
140
#define INTR_FC 0x08
#define INTR_BS 0x10
#define INTR_DC 0x20
bellard authored
141
#define INTR_RST 0x80
bellard authored
142
143
144
145

#define SEQ_0 0x0
#define SEQ_CD 0x4
146
147
148
149
#define CFG1_RESREPT 0x40

#define TCHI_FAS100A 0x4
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
static void esp_raise_irq(ESPState *s)
{
    if (!(s->rregs[ESP_RSTAT] & STAT_INT)) {
        s->rregs[ESP_RSTAT] |= STAT_INT;
        qemu_irq_raise(s->irq);
    }
}

static void esp_lower_irq(ESPState *s)
{
    if (s->rregs[ESP_RSTAT] & STAT_INT) {
        s->rregs[ESP_RSTAT] &= ~STAT_INT;
        qemu_irq_lower(s->irq);
    }
}
blueswir1 authored
166
static uint32_t get_cmd(ESPState *s, uint8_t *buf)
bellard authored
167
{
pbrook authored
168
    uint32_t dmalen;
bellard authored
169
170
    int target;
171
    target = s->wregs[ESP_WBUSID] & BUSID_DID;
172
    if (s->dma) {
173
        dmalen = s->rregs[ESP_TCLO] | (s->rregs[ESP_TCMID] << 8);
174
        s->dma_memory_read(s->dma_opaque, buf, dmalen);
175
    } else {
176
177
        dmalen = s->ti_size;
        memcpy(buf, s->ti_buf, dmalen);
blueswir1 authored
178
        buf[0] = 0;
179
    }
180
    DPRINTF("get_cmd: len %d target %d\n", dmalen, target);
181
bellard authored
182
    s->ti_size = 0;
183
184
    s->ti_rptr = 0;
    s->ti_wptr = 0;
bellard authored
185
pbrook authored
186
187
    if (s->current_dev) {
        /* Started a new command before the old one finished.  Cancel it.  */
ths authored
188
        s->current_dev->cancel_io(s->current_dev, 0);
pbrook authored
189
190
191
        s->async_len = 0;
    }
192
    if (target >= ESP_MAX_DEVS || !s->scsi_dev[target]) {
193
        // No such drive
194
        s->rregs[ESP_RSTAT] = 0;
195
196
        s->rregs[ESP_RINTR] = INTR_DC;
        s->rregs[ESP_RSEQ] = SEQ_0;
197
        esp_raise_irq(s);
blueswir1 authored
198
        return 0;
bellard authored
199
    }
200
    s->current_dev = s->scsi_dev[target];
pbrook authored
201
202
203
204
205
206
207
208
209
210
    return dmalen;
}

static void do_cmd(ESPState *s, uint8_t *buf)
{
    int32_t datalen;
    int lun;

    DPRINTF("do_cmd: busid 0x%x\n", buf[0]);
    lun = buf[0] & 7;
ths authored
211
    datalen = s->current_dev->send_command(s->current_dev, 0, &buf[1], lun);
212
213
    s->ti_size = datalen;
    if (datalen != 0) {
214
        s->rregs[ESP_RSTAT] = STAT_TC;
pbrook authored
215
        s->dma_left = 0;
pbrook authored
216
        s->dma_counter = 0;
217
        if (datalen > 0) {
218
            s->rregs[ESP_RSTAT] |= STAT_DI;
ths authored
219
            s->current_dev->read_data(s->current_dev, 0);
220
        } else {
221
            s->rregs[ESP_RSTAT] |= STAT_DO;
ths authored
222
            s->current_dev->write_data(s->current_dev, 0);
223
        }
bellard authored
224
    }
225
226
    s->rregs[ESP_RINTR] = INTR_BS | INTR_FC;
    s->rregs[ESP_RSEQ] = SEQ_CD;
227
    esp_raise_irq(s);
bellard authored
228
229
}
pbrook authored
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
static void handle_satn(ESPState *s)
{
    uint8_t buf[32];
    int len;

    len = get_cmd(s, buf);
    if (len)
        do_cmd(s, buf);
}

static void handle_satn_stop(ESPState *s)
{
    s->cmdlen = get_cmd(s, s->cmdbuf);
    if (s->cmdlen) {
        DPRINTF("Set ATN & Stop: cmdlen %d\n", s->cmdlen);
        s->do_cmd = 1;
246
        s->rregs[ESP_RSTAT] = STAT_TC | STAT_CD;
247
248
        s->rregs[ESP_RINTR] = INTR_BS | INTR_FC;
        s->rregs[ESP_RSEQ] = SEQ_CD;
249
        esp_raise_irq(s);
pbrook authored
250
251
252
    }
}
pbrook authored
253
static void write_response(ESPState *s)
bellard authored
254
{
pbrook authored
255
256
257
    DPRINTF("Transfer status (sense=%d)\n", s->sense);
    s->ti_buf[0] = s->sense;
    s->ti_buf[1] = 0;
258
    if (s->dma) {
259
        s->dma_memory_write(s->dma_opaque, s->ti_buf, 2);
260
        s->rregs[ESP_RSTAT] = STAT_TC | STAT_ST;
261
262
        s->rregs[ESP_RINTR] = INTR_BS | INTR_FC;
        s->rregs[ESP_RSEQ] = SEQ_CD;
263
    } else {
blueswir1 authored
264
265
266
        s->ti_size = 2;
        s->ti_rptr = 0;
        s->ti_wptr = 0;
267
        s->rregs[ESP_RFLAGS] = 2;
268
    }
269
    esp_raise_irq(s);
bellard authored
270
}
271
pbrook authored
272
273
static void esp_dma_done(ESPState *s)
{
274
    s->rregs[ESP_RSTAT] |= STAT_TC;
275
276
277
278
279
    s->rregs[ESP_RINTR] = INTR_BS;
    s->rregs[ESP_RSEQ] = 0;
    s->rregs[ESP_RFLAGS] = 0;
    s->rregs[ESP_TCLO] = 0;
    s->rregs[ESP_TCMID] = 0;
280
    esp_raise_irq(s);
pbrook authored
281
282
}
283
284
static void esp_do_dma(ESPState *s)
{
285
    uint32_t len;
286
    int to_device;
pbrook authored
287
288
    to_device = (s->ti_size < 0);
pbrook authored
289
    len = s->dma_left;
290
291
    if (s->do_cmd) {
        DPRINTF("command len %d + %d\n", s->cmdlen, len);
292
        s->dma_memory_read(s->dma_opaque, &s->cmdbuf[s->cmdlen], len);
293
294
295
296
297
        s->ti_size = 0;
        s->cmdlen = 0;
        s->do_cmd = 0;
        do_cmd(s, s->cmdbuf);
        return;
pbrook authored
298
299
300
301
302
303
304
305
306
    }
    if (s->async_len == 0) {
        /* Defer until data is available.  */
        return;
    }
    if (len > s->async_len) {
        len = s->async_len;
    }
    if (to_device) {
307
        s->dma_memory_read(s->dma_opaque, s->async_buf, len);
308
    } else {
309
        s->dma_memory_write(s->dma_opaque, s->async_buf, len);
pbrook authored
310
311
312
313
    }
    s->dma_left -= len;
    s->async_buf += len;
    s->async_len -= len;
pbrook authored
314
315
316
317
    if (to_device)
        s->ti_size += len;
    else
        s->ti_size -= len;
pbrook authored
318
    if (s->async_len == 0) {
319
        if (to_device) {
320
            // ti_size is negative
ths authored
321
            s->current_dev->write_data(s->current_dev, 0);
322
        } else {
ths authored
323
            s->current_dev->read_data(s->current_dev, 0);
pbrook authored
324
            /* If there is still data to be read from the device then
325
               complete the DMA operation immediately.  Otherwise defer
pbrook authored
326
327
328
329
               until the scsi layer has completed.  */
            if (s->dma_left == 0 && s->ti_size > 0) {
                esp_dma_done(s);
            }
330
        }
pbrook authored
331
332
    } else {
        /* Partially filled a scsi buffer. Complete immediately.  */
pbrook authored
333
334
        esp_dma_done(s);
    }
335
336
}
pbrook authored
337
338
static void esp_command_complete(void *opaque, int reason, uint32_t tag,
                                 uint32_t arg)
339
340
341
{
    ESPState *s = (ESPState *)opaque;
342
343
344
345
346
    if (reason == SCSI_REASON_DONE) {
        DPRINTF("SCSI Command complete\n");
        if (s->ti_size != 0)
            DPRINTF("SCSI command completed unexpectedly\n");
        s->ti_size = 0;
pbrook authored
347
348
349
        s->dma_left = 0;
        s->async_len = 0;
        if (arg)
350
            DPRINTF("Command failed\n");
pbrook authored
351
        s->sense = arg;
352
        s->rregs[ESP_RSTAT] = STAT_ST;
pbrook authored
353
354
        esp_dma_done(s);
        s->current_dev = NULL;
355
356
    } else {
        DPRINTF("transfer %d/%d\n", s->dma_left, s->ti_size);
pbrook authored
357
        s->async_len = arg;
ths authored
358
        s->async_buf = s->current_dev->get_buf(s->current_dev, 0);
pbrook authored
359
        if (s->dma_left) {
pbrook authored
360
            esp_do_dma(s);
pbrook authored
361
362
363
364
365
        } else if (s->dma_counter != 0 && s->ti_size <= 0) {
            /* If this was the last part of a DMA transfer then the
               completion interrupt is deferred to here.  */
            esp_dma_done(s);
        }
366
    }
367
368
}
bellard authored
369
370
static void handle_ti(ESPState *s)
{
371
    uint32_t dmalen, minlen;
bellard authored
372
373
    dmalen = s->rregs[ESP_TCLO] | (s->rregs[ESP_TCMID] << 8);
pbrook authored
374
375
376
    if (dmalen==0) {
      dmalen=0x10000;
    }
pbrook authored
377
    s->dma_counter = dmalen;
pbrook authored
378
pbrook authored
379
380
    if (s->do_cmd)
        minlen = (dmalen < 32) ? dmalen : 32;
381
382
    else if (s->ti_size < 0)
        minlen = (dmalen < -s->ti_size) ? dmalen : -s->ti_size;
pbrook authored
383
384
    else
        minlen = (dmalen < s->ti_size) ? dmalen : s->ti_size;
pbrook authored
385
    DPRINTF("Transfer Information len %d\n", minlen);
386
    if (s->dma) {
387
        s->dma_left = minlen;
388
        s->rregs[ESP_RSTAT] &= ~STAT_TC;
389
        esp_do_dma(s);
pbrook authored
390
391
392
393
394
395
396
397
    } else if (s->do_cmd) {
        DPRINTF("command len %d\n", s->cmdlen);
        s->ti_size = 0;
        s->cmdlen = 0;
        s->do_cmd = 0;
        do_cmd(s, s->cmdbuf);
        return;
    }
bellard authored
398
399
}
400
static void esp_reset(void *opaque)
bellard authored
401
402
{
    ESPState *s = opaque;
403
404
405
    memset(s->rregs, 0, ESP_REGS);
    memset(s->wregs, 0, ESP_REGS);
406
    s->rregs[ESP_TCHI] = TCHI_FAS100A; // Indicate fas100a
407
408
409
410
    s->ti_size = 0;
    s->ti_rptr = 0;
    s->ti_wptr = 0;
    s->dma = 0;
pbrook authored
411
    s->do_cmd = 0;
412
413

    s->rregs[ESP_CFG1] = 7;
bellard authored
414
415
}
416
417
418
419
420
421
static void parent_esp_reset(void *opaque, int irq, int level)
{
    if (level)
        esp_reset(opaque);
}
bellard authored
422
423
424
425
426
static uint32_t esp_mem_readb(void *opaque, target_phys_addr_t addr)
{
    ESPState *s = opaque;
    uint32_t saddr;
blueswir1 authored
427
    saddr = addr >> s->it_shift;
bellard authored
428
    DPRINTF("read reg[%d]: 0x%2.2x\n", saddr, s->rregs[saddr]);
bellard authored
429
    switch (saddr) {
430
    case ESP_FIFO:
blueswir1 authored
431
432
        if (s->ti_size > 0) {
            s->ti_size--;
433
            if ((s->rregs[ESP_RSTAT] & STAT_PIO_MASK) == 0) {
434
435
                /* Data out.  */
                ESP_ERROR("PIO data read not implemented\n");
436
                s->rregs[ESP_FIFO] = 0;
437
            } else {
438
                s->rregs[ESP_FIFO] = s->ti_buf[s->ti_rptr++];
439
            }
440
            esp_raise_irq(s);
blueswir1 authored
441
442
        }
        if (s->ti_size == 0) {
443
444
445
            s->ti_rptr = 0;
            s->ti_wptr = 0;
        }
blueswir1 authored
446
        break;
447
    case ESP_RINTR:
448
        // Clear interrupt/error status bits
449
450
        s->rregs[ESP_RSTAT] &= ~(STAT_GE | STAT_PE);
        esp_lower_irq(s);
bellard authored
451
        break;
bellard authored
452
    default:
blueswir1 authored
453
        break;
bellard authored
454
    }
bellard authored
455
    return s->rregs[saddr];
bellard authored
456
457
458
459
460
461
462
}

static void esp_mem_writeb(void *opaque, target_phys_addr_t addr, uint32_t val)
{
    ESPState *s = opaque;
    uint32_t saddr;
blueswir1 authored
463
    saddr = addr >> s->it_shift;
464
465
    DPRINTF("write reg[%d]: 0x%2.2x -> 0x%2.2x\n", saddr, s->wregs[saddr],
            val);
bellard authored
466
    switch (saddr) {
467
468
469
    case ESP_TCLO:
    case ESP_TCMID:
        s->rregs[ESP_RSTAT] &= ~STAT_TC;
470
        break;
471
    case ESP_FIFO:
pbrook authored
472
473
        if (s->do_cmd) {
            s->cmdbuf[s->cmdlen++] = val & 0xff;
474
475
        } else if (s->ti_size == TI_BUFSZ - 1) {
            ESP_ERROR("fifo overrun\n");
476
477
478
479
        } else {
            s->ti_size++;
            s->ti_buf[s->ti_wptr++] = val & 0xff;
        }
blueswir1 authored
480
        break;
481
    case ESP_CMD:
482
        s->rregs[saddr] = val;
483
        if (val & CMD_DMA) {
blueswir1 authored
484
            s->dma = 1;
pbrook authored
485
            /* Reload DMA counter.  */
486
487
            s->rregs[ESP_TCLO] = s->wregs[ESP_TCLO];
            s->rregs[ESP_TCMID] = s->wregs[ESP_TCMID];
blueswir1 authored
488
489
490
        } else {
            s->dma = 0;
        }
491
492
        switch(val & CMD_CMD) {
        case CMD_NOP:
blueswir1 authored
493
494
            DPRINTF("NOP (%2.2x)\n", val);
            break;
495
        case CMD_FLUSH:
blueswir1 authored
496
            DPRINTF("Flush FIFO (%2.2x)\n", val);
bellard authored
497
            //s->ti_size = 0;
498
499
            s->rregs[ESP_RINTR] = INTR_FC;
            s->rregs[ESP_RSEQ] = 0;
500
            s->rregs[ESP_RFLAGS] = 0;
blueswir1 authored
501
            break;
502
        case CMD_RESET:
blueswir1 authored
503
504
505
            DPRINTF("Chip reset (%2.2x)\n", val);
            esp_reset(s);
            break;
506
        case CMD_BUSRESET:
blueswir1 authored
507
            DPRINTF("Bus reset (%2.2x)\n", val);
508
509
            s->rregs[ESP_RINTR] = INTR_RST;
            if (!(s->wregs[ESP_CFG1] & CFG1_RESREPT)) {
510
                esp_raise_irq(s);
bellard authored
511
            }
blueswir1 authored
512
            break;
513
        case CMD_TI:
blueswir1 authored
514
515
            handle_ti(s);
            break;
516
        case CMD_ICCS:
blueswir1 authored
517
518
            DPRINTF("Initiator Command Complete Sequence (%2.2x)\n", val);
            write_response(s);
519
520
            s->rregs[ESP_RINTR] = INTR_FC;
            s->rregs[ESP_RSTAT] |= STAT_MI;
blueswir1 authored
521
            break;
522
        case CMD_MSGACC:
blueswir1 authored
523
524
            DPRINTF("Message Accepted (%2.2x)\n", val);
            write_response(s);
525
526
            s->rregs[ESP_RINTR] = INTR_DC;
            s->rregs[ESP_RSEQ] = 0;
blueswir1 authored
527
            break;
528
        case CMD_SATN:
blueswir1 authored
529
530
            DPRINTF("Set ATN (%2.2x)\n", val);
            break;
531
        case CMD_SELATN:
blueswir1 authored
532
533
534
            DPRINTF("Set ATN (%2.2x)\n", val);
            handle_satn(s);
            break;
535
        case CMD_SELATNS:
blueswir1 authored
536
537
538
            DPRINTF("Set ATN & stop (%2.2x)\n", val);
            handle_satn_stop(s);
            break;
539
        case CMD_ENSEL:
540
            DPRINTF("Enable selection (%2.2x)\n", val);
541
            s->rregs[ESP_RINTR] = 0;
542
            break;
blueswir1 authored
543
        default:
544
            ESP_ERROR("Unhandled ESP command (%2.2x)\n", val);
blueswir1 authored
545
546
547
            break;
        }
        break;
548
    case ESP_WBUSID ... ESP_WSYNO:
blueswir1 authored
549
        break;
550
    case ESP_CFG1:
551
552
        s->rregs[saddr] = val;
        break;
553
    case ESP_WCCF ... ESP_WTEST:
554
        break;
555
    case ESP_CFG2 ... ESP_RES4:
556
557
        s->rregs[saddr] = val;
        break;
bellard authored
558
    default:
559
560
        ESP_ERROR("invalid write of 0x%02x at [0x%x]\n", val, saddr);
        return;
bellard authored
561
    }
bellard authored
562
    s->wregs[saddr] = val;
bellard authored
563
564
565
566
}

static CPUReadMemoryFunc *esp_mem_read[3] = {
    esp_mem_readb,
567
568
    NULL,
    NULL,
bellard authored
569
570
571
572
};

static CPUWriteMemoryFunc *esp_mem_write[3] = {
    esp_mem_writeb,
573
    NULL,
574
    esp_mem_writeb,
bellard authored
575
576
577
578
579
};

static void esp_save(QEMUFile *f, void *opaque)
{
    ESPState *s = opaque;
bellard authored
580
581
582
    qemu_put_buffer(f, s->rregs, ESP_REGS);
    qemu_put_buffer(f, s->wregs, ESP_REGS);
583
    qemu_put_sbe32s(f, &s->ti_size);
584
585
586
    qemu_put_be32s(f, &s->ti_rptr);
    qemu_put_be32s(f, &s->ti_wptr);
    qemu_put_buffer(f, s->ti_buf, TI_BUFSZ);
587
    qemu_put_be32s(f, &s->sense);
588
    qemu_put_be32s(f, &s->dma);
589
590
591
592
593
    qemu_put_buffer(f, s->cmdbuf, TI_BUFSZ);
    qemu_put_be32s(f, &s->cmdlen);
    qemu_put_be32s(f, &s->do_cmd);
    qemu_put_be32s(f, &s->dma_left);
    // There should be no transfers in progress, so dma_counter is not saved
bellard authored
594
595
596
597
598
}

static int esp_load(QEMUFile *f, void *opaque, int version_id)
{
    ESPState *s = opaque;
599
600
601
    if (version_id != 3)
        return -EINVAL; // Cannot emulate 2
bellard authored
602
603
604
    qemu_get_buffer(f, s->rregs, ESP_REGS);
    qemu_get_buffer(f, s->wregs, ESP_REGS);
605
    qemu_get_sbe32s(f, &s->ti_size);
606
607
608
    qemu_get_be32s(f, &s->ti_rptr);
    qemu_get_be32s(f, &s->ti_wptr);
    qemu_get_buffer(f, s->ti_buf, TI_BUFSZ);
609
    qemu_get_be32s(f, &s->sense);
610
    qemu_get_be32s(f, &s->dma);
611
612
613
614
    qemu_get_buffer(f, s->cmdbuf, TI_BUFSZ);
    qemu_get_be32s(f, &s->cmdlen);
    qemu_get_be32s(f, &s->do_cmd);
    qemu_get_be32s(f, &s->dma_left);
bellard authored
615
bellard authored
616
617
618
    return 0;
}
Paul Brook authored
619
static void esp_scsi_attach(DeviceState *host, BlockDriverState *bd, int id)
620
{
Paul Brook authored
621
    ESPState *s = FROM_SYSBUS(ESPState, sysbus_from_qdev(host));
622
623
624

    if (id < 0) {
        for (id = 0; id < ESP_MAX_DEVS; id++) {
625
626
            if (id == (s->rregs[ESP_CFG1] & 0x7))
                continue;
627
628
629
630
631
632
633
634
635
636
            if (s->scsi_dev[id] == NULL)
                break;
        }
    }
    if (id >= ESP_MAX_DEVS) {
        DPRINTF("Bad Device ID %d\n", id);
        return;
    }
    if (s->scsi_dev[id]) {
        DPRINTF("Destroying device %d\n", id);
ths authored
637
        s->scsi_dev[id]->destroy(s->scsi_dev[id]);
638
639
640
    }
    DPRINTF("Attaching block device %d\n", id);
    /* Command queueing is not implemented.  */
641
642
643
    s->scsi_dev[id] = scsi_generic_init(bd, 0, esp_command_complete, s);
    if (s->scsi_dev[id] == NULL)
        s->scsi_dev[id] = scsi_disk_init(bd, 0, esp_command_complete, s);
644
645
}
Paul Brook authored
646
647
648
649
void esp_init(target_phys_addr_t espaddr, int it_shift,
              espdma_memory_read_write dma_memory_read,
              espdma_memory_read_write dma_memory_write,
              void *dma_opaque, qemu_irq irq, qemu_irq *reset)
bellard authored
650
{
Paul Brook authored
651
652
    DeviceState *dev;
    SysBusDevice *s;
653
    ESPState *esp;
Paul Brook authored
654
655

    dev = qdev_create(NULL, "esp");
656
657
658
659
660
    esp = DO_UPCAST(ESPState, busdev.qdev, dev);
    esp->dma_memory_read = dma_memory_read;
    esp->dma_memory_write = dma_memory_write;
    esp->dma_opaque = dma_opaque;
    esp->it_shift = it_shift;
Paul Brook authored
661
662
663
664
665
    qdev_init(dev);
    s = sysbus_from_qdev(dev);
    sysbus_connect_irq(s, 0, irq);
    sysbus_mmio_map(s, 0, espaddr);
}
bellard authored
666
Paul Brook authored
667
668
669
670
static void esp_init1(SysBusDevice *dev)
{
    ESPState *s = FROM_SYSBUS(ESPState, dev);
    int esp_io_memory;
bellard authored
671
Paul Brook authored
672
673
    sysbus_init_irq(dev, &s->irq);
    assert(s->it_shift != -1);
bellard authored
674
675
    esp_io_memory = cpu_register_io_memory(esp_mem_read, esp_mem_write, s);
Paul Brook authored
676
    sysbus_init_mmio(dev, ESP_REGS << s->it_shift, esp_io_memory);
bellard authored
677
678
679

    esp_reset(s);
Paul Brook authored
680
    register_savevm("esp", -1, 3, esp_save, esp_load, s);
681
    qemu_register_reset(esp_reset, s);
bellard authored
682
683
    qdev_init_gpio_in(&dev->qdev, parent_esp_reset, 1);
684
Paul Brook authored
685
    scsi_bus_new(&dev->qdev, esp_scsi_attach);
686
}
Paul Brook authored
687
688
689
690
691
692
693

static void esp_register_devices(void)
{
    sysbus_register_dev("esp", sizeof(ESPState), esp_init1);
}

device_init(esp_register_devices)