Blame view

hw/esp.c 17.8 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
pbrook authored
25
26
#include "hw.h"
#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
41
42
43
#ifdef DEBUG_ESP
#define DPRINTF(fmt, args...) \
do { printf("ESP: " fmt , ##args); } while (0)
#else
blueswir1 authored
44
#define DPRINTF(fmt, args...) do {} while (0)
bellard authored
45
46
#endif
47
#define ESP_REGS 16
48
#define TI_BUFSZ 32
49
50
typedef struct ESPState ESPState;
bellard authored
51
52
struct ESPState {
53
    uint32_t it_shift;
54
    qemu_irq irq;
55
56
    uint8_t rregs[ESP_REGS];
    uint8_t wregs[ESP_REGS];
57
    int32_t ti_size;
58
59
    uint32_t ti_rptr, ti_wptr;
    uint8_t ti_buf[TI_BUFSZ];
blueswir1 authored
60
61
    uint32_t sense;
    uint32_t dma;
62
    SCSIDevice *scsi_dev[ESP_MAX_DEVS];
63
    SCSIDevice *current_dev;
pbrook authored
64
    uint8_t cmdbuf[TI_BUFSZ];
blueswir1 authored
65
66
    uint32_t cmdlen;
    uint32_t do_cmd;
67
pbrook authored
68
    /* The amount of data left in the current DMA transfer.  */
69
    uint32_t dma_left;
pbrook authored
70
71
72
    /* The size of the current DMA transfer.  Zero if no transfer is in
       progress.  */
    uint32_t dma_counter;
pbrook authored
73
    uint8_t *async_buf;
74
    uint32_t async_len;
75
76
77

    espdma_memory_read_write dma_memory_read;
    espdma_memory_read_write dma_memory_write;
78
    void *dma_opaque;
79
};
bellard authored
80
81
82
83
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
#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
119
120
121
122
123
124
#define STAT_DO 0x00
#define STAT_DI 0x01
#define STAT_CD 0x02
#define STAT_ST 0x03
#define STAT_MI 0x06
#define STAT_MO 0x07
125
#define STAT_PIO_MASK 0x06
bellard authored
126
127

#define STAT_TC 0x10
128
129
#define STAT_PE 0x20
#define STAT_GE 0x40
130
#define STAT_INT 0x80
bellard authored
131
132
133
134

#define INTR_FC 0x08
#define INTR_BS 0x10
#define INTR_DC 0x20
bellard authored
135
#define INTR_RST 0x80
bellard authored
136
137
138
139

#define SEQ_0 0x0
#define SEQ_CD 0x4
140
141
142
143
144
145
#define CFG1_RESREPT 0x40

#define CFG2_MASK 0x15

#define TCHI_FAS100A 0x4
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
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
162
static uint32_t get_cmd(ESPState *s, uint8_t *buf)
bellard authored
163
{
pbrook authored
164
    uint32_t dmalen;
bellard authored
165
166
    int target;
167
168
    dmalen = s->rregs[ESP_TCLO] | (s->rregs[ESP_TCMID] << 8);
    target = s->wregs[ESP_WBUSID] & 7;
pbrook authored
169
    DPRINTF("get_cmd: len %d target %d\n", dmalen, target);
170
    if (s->dma) {
171
        s->dma_memory_read(s->dma_opaque, buf, dmalen);
172
    } else {
blueswir1 authored
173
174
175
        buf[0] = 0;
        memcpy(&buf[1], s->ti_buf, dmalen);
        dmalen++;
176
    }
177
bellard authored
178
    s->ti_size = 0;
179
180
    s->ti_rptr = 0;
    s->ti_wptr = 0;
bellard authored
181
pbrook authored
182
183
    if (s->current_dev) {
        /* Started a new command before the old one finished.  Cancel it.  */
ths authored
184
        s->current_dev->cancel_io(s->current_dev, 0);
pbrook authored
185
186
187
        s->async_len = 0;
    }
188
    if (target >= ESP_MAX_DEVS || !s->scsi_dev[target]) {
189
        // No such drive
190
        s->rregs[ESP_RSTAT] = 0;
191
192
        s->rregs[ESP_RINTR] = INTR_DC;
        s->rregs[ESP_RSEQ] = SEQ_0;
193
        esp_raise_irq(s);
blueswir1 authored
194
        return 0;
bellard authored
195
    }
196
    s->current_dev = s->scsi_dev[target];
pbrook authored
197
198
199
200
201
202
203
204
205
206
    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
207
    datalen = s->current_dev->send_command(s->current_dev, 0, &buf[1], lun);
208
209
    s->ti_size = datalen;
    if (datalen != 0) {
210
        s->rregs[ESP_RSTAT] = STAT_TC;
pbrook authored
211
        s->dma_left = 0;
pbrook authored
212
        s->dma_counter = 0;
213
        if (datalen > 0) {
214
            s->rregs[ESP_RSTAT] |= STAT_DI;
ths authored
215
            s->current_dev->read_data(s->current_dev, 0);
216
        } else {
217
            s->rregs[ESP_RSTAT] |= STAT_DO;
ths authored
218
            s->current_dev->write_data(s->current_dev, 0);
219
        }
bellard authored
220
    }
221
222
    s->rregs[ESP_RINTR] = INTR_BS | INTR_FC;
    s->rregs[ESP_RSEQ] = SEQ_CD;
223
    esp_raise_irq(s);
bellard authored
224
225
}
pbrook authored
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
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;
242
        s->rregs[ESP_RSTAT] = STAT_TC | STAT_CD;
243
244
        s->rregs[ESP_RINTR] = INTR_BS | INTR_FC;
        s->rregs[ESP_RSEQ] = SEQ_CD;
245
        esp_raise_irq(s);
pbrook authored
246
247
248
    }
}
pbrook authored
249
static void write_response(ESPState *s)
bellard authored
250
{
pbrook authored
251
252
253
    DPRINTF("Transfer status (sense=%d)\n", s->sense);
    s->ti_buf[0] = s->sense;
    s->ti_buf[1] = 0;
254
    if (s->dma) {
255
        s->dma_memory_write(s->dma_opaque, s->ti_buf, 2);
256
        s->rregs[ESP_RSTAT] = STAT_TC | STAT_ST;
257
258
        s->rregs[ESP_RINTR] = INTR_BS | INTR_FC;
        s->rregs[ESP_RSEQ] = SEQ_CD;
259
    } else {
blueswir1 authored
260
261
262
        s->ti_size = 2;
        s->ti_rptr = 0;
        s->ti_wptr = 0;
263
        s->rregs[ESP_RFLAGS] = 2;
264
    }
265
    esp_raise_irq(s);
bellard authored
266
}
267
pbrook authored
268
269
static void esp_dma_done(ESPState *s)
{
270
    s->rregs[ESP_RSTAT] |= STAT_TC;
271
272
273
274
275
    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;
276
    esp_raise_irq(s);
pbrook authored
277
278
}
279
280
static void esp_do_dma(ESPState *s)
{
281
    uint32_t len;
282
    int to_device;
pbrook authored
283
284
    to_device = (s->ti_size < 0);
pbrook authored
285
    len = s->dma_left;
286
287
    if (s->do_cmd) {
        DPRINTF("command len %d + %d\n", s->cmdlen, len);
288
        s->dma_memory_read(s->dma_opaque, &s->cmdbuf[s->cmdlen], len);
289
290
291
292
293
        s->ti_size = 0;
        s->cmdlen = 0;
        s->do_cmd = 0;
        do_cmd(s, s->cmdbuf);
        return;
pbrook authored
294
295
296
297
298
299
300
301
302
    }
    if (s->async_len == 0) {
        /* Defer until data is available.  */
        return;
    }
    if (len > s->async_len) {
        len = s->async_len;
    }
    if (to_device) {
303
        s->dma_memory_read(s->dma_opaque, s->async_buf, len);
304
    } else {
305
        s->dma_memory_write(s->dma_opaque, s->async_buf, len);
pbrook authored
306
307
308
309
    }
    s->dma_left -= len;
    s->async_buf += len;
    s->async_len -= len;
pbrook authored
310
311
312
313
    if (to_device)
        s->ti_size += len;
    else
        s->ti_size -= len;
pbrook authored
314
    if (s->async_len == 0) {
315
        if (to_device) {
316
            // ti_size is negative
ths authored
317
            s->current_dev->write_data(s->current_dev, 0);
318
        } else {
ths authored
319
            s->current_dev->read_data(s->current_dev, 0);
pbrook authored
320
321
322
323
324
325
            /* If there is still data to be read from the device then
               complete the DMA operation immeriately.  Otherwise defer
               until the scsi layer has completed.  */
            if (s->dma_left == 0 && s->ti_size > 0) {
                esp_dma_done(s);
            }
326
        }
pbrook authored
327
328
    } else {
        /* Partially filled a scsi buffer. Complete immediately.  */
pbrook authored
329
330
        esp_dma_done(s);
    }
331
332
}
pbrook authored
333
334
static void esp_command_complete(void *opaque, int reason, uint32_t tag,
                                 uint32_t arg)
335
336
337
{
    ESPState *s = (ESPState *)opaque;
338
339
340
341
342
    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
343
344
345
        s->dma_left = 0;
        s->async_len = 0;
        if (arg)
346
            DPRINTF("Command failed\n");
pbrook authored
347
        s->sense = arg;
348
        s->rregs[ESP_RSTAT] = STAT_ST;
pbrook authored
349
350
        esp_dma_done(s);
        s->current_dev = NULL;
351
352
    } else {
        DPRINTF("transfer %d/%d\n", s->dma_left, s->ti_size);
pbrook authored
353
        s->async_len = arg;
ths authored
354
        s->async_buf = s->current_dev->get_buf(s->current_dev, 0);
pbrook authored
355
        if (s->dma_left) {
pbrook authored
356
            esp_do_dma(s);
pbrook authored
357
358
359
360
361
        } 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);
        }
362
    }
363
364
}
bellard authored
365
366
static void handle_ti(ESPState *s)
{
367
    uint32_t dmalen, minlen;
bellard authored
368
369
    dmalen = s->rregs[ESP_TCLO] | (s->rregs[ESP_TCMID] << 8);
pbrook authored
370
371
372
    if (dmalen==0) {
      dmalen=0x10000;
    }
pbrook authored
373
    s->dma_counter = dmalen;
pbrook authored
374
pbrook authored
375
376
    if (s->do_cmd)
        minlen = (dmalen < 32) ? dmalen : 32;
377
378
    else if (s->ti_size < 0)
        minlen = (dmalen < -s->ti_size) ? dmalen : -s->ti_size;
pbrook authored
379
380
    else
        minlen = (dmalen < s->ti_size) ? dmalen : s->ti_size;
pbrook authored
381
    DPRINTF("Transfer Information len %d\n", minlen);
382
    if (s->dma) {
383
        s->dma_left = minlen;
384
        s->rregs[ESP_RSTAT] &= ~STAT_TC;
385
        esp_do_dma(s);
pbrook authored
386
387
388
389
390
391
392
393
    } 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
394
395
}
396
static void esp_reset(void *opaque)
bellard authored
397
398
{
    ESPState *s = opaque;
399
400
401
    esp_lower_irq(s);
402
403
    memset(s->rregs, 0, ESP_REGS);
    memset(s->wregs, 0, ESP_REGS);
404
    s->rregs[ESP_TCHI] = TCHI_FAS100A; // Indicate fas100a
405
406
407
408
    s->ti_size = 0;
    s->ti_rptr = 0;
    s->ti_wptr = 0;
    s->dma = 0;
pbrook authored
409
    s->do_cmd = 0;
bellard authored
410
411
}
412
413
414
415
416
417
static void parent_esp_reset(void *opaque, int irq, int level)
{
    if (level)
        esp_reset(opaque);
}
bellard authored
418
419
420
421
422
static uint32_t esp_mem_readb(void *opaque, target_phys_addr_t addr)
{
    ESPState *s = opaque;
    uint32_t saddr;
423
    saddr = (addr >> s->it_shift) & (ESP_REGS - 1);
bellard authored
424
    DPRINTF("read reg[%d]: 0x%2.2x\n", saddr, s->rregs[saddr]);
bellard authored
425
    switch (saddr) {
426
    case ESP_FIFO:
blueswir1 authored
427
428
        if (s->ti_size > 0) {
            s->ti_size--;
429
            if ((s->rregs[ESP_RSTAT] & STAT_PIO_MASK) == 0) {
430
                /* Data in/out.  */
pbrook authored
431
                fprintf(stderr, "esp: PIO data read not implemented\n");
432
                s->rregs[ESP_FIFO] = 0;
433
            } else {
434
                s->rregs[ESP_FIFO] = s->ti_buf[s->ti_rptr++];
435
            }
436
            esp_raise_irq(s);
blueswir1 authored
437
438
        }
        if (s->ti_size == 0) {
439
440
441
            s->ti_rptr = 0;
            s->ti_wptr = 0;
        }
blueswir1 authored
442
        break;
443
    case ESP_RINTR:
444
        // Clear interrupt/error status bits
445
446
        s->rregs[ESP_RSTAT] &= ~(STAT_GE | STAT_PE);
        esp_lower_irq(s);
bellard authored
447
        break;
bellard authored
448
    default:
blueswir1 authored
449
        break;
bellard authored
450
    }
bellard authored
451
    return s->rregs[saddr];
bellard authored
452
453
454
455
456
457
458
}

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

static CPUReadMemoryFunc *esp_mem_read[3] = {
    esp_mem_readb,
564
565
    NULL,
    NULL,
bellard authored
566
567
568
569
};

static CPUWriteMemoryFunc *esp_mem_write[3] = {
    esp_mem_writeb,
570
571
    NULL,
    NULL,
bellard authored
572
573
574
575
576
};

static void esp_save(QEMUFile *f, void *opaque)
{
    ESPState *s = opaque;
bellard authored
577
578
579
    qemu_put_buffer(f, s->rregs, ESP_REGS);
    qemu_put_buffer(f, s->wregs, ESP_REGS);
blueswir1 authored
580
    qemu_put_be32s(f, (uint32_t *)&s->ti_size);
581
582
583
    qemu_put_be32s(f, &s->ti_rptr);
    qemu_put_be32s(f, &s->ti_wptr);
    qemu_put_buffer(f, s->ti_buf, TI_BUFSZ);
584
    qemu_put_be32s(f, &s->sense);
585
    qemu_put_be32s(f, &s->dma);
586
587
588
589
590
    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
591
592
593
594
595
}

static int esp_load(QEMUFile *f, void *opaque, int version_id)
{
    ESPState *s = opaque;
596
597
598
    if (version_id != 3)
        return -EINVAL; // Cannot emulate 2
bellard authored
599
600
601
    qemu_get_buffer(f, s->rregs, ESP_REGS);
    qemu_get_buffer(f, s->wregs, ESP_REGS);
blueswir1 authored
602
    qemu_get_be32s(f, (uint32_t *)&s->ti_size);
603
604
605
    qemu_get_be32s(f, &s->ti_rptr);
    qemu_get_be32s(f, &s->ti_wptr);
    qemu_get_buffer(f, s->ti_buf, TI_BUFSZ);
606
    qemu_get_be32s(f, &s->sense);
607
    qemu_get_be32s(f, &s->dma);
608
609
610
611
    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
612
bellard authored
613
614
615
    return 0;
}
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
void esp_scsi_attach(void *opaque, BlockDriverState *bd, int id)
{
    ESPState *s = (ESPState *)opaque;

    if (id < 0) {
        for (id = 0; id < ESP_MAX_DEVS; id++) {
            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
632
        s->scsi_dev[id]->destroy(s->scsi_dev[id]);
633
634
635
    }
    DPRINTF("Attaching block device %d\n", id);
    /* Command queueing is not implemented.  */
636
637
638
    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);
639
640
}
641
void *esp_init(target_phys_addr_t espaddr, int it_shift,
642
643
               espdma_memory_read_write dma_memory_read,
               espdma_memory_read_write dma_memory_write,
644
               void *dma_opaque, qemu_irq irq, qemu_irq *reset)
bellard authored
645
646
{
    ESPState *s;
647
    int esp_io_memory;
bellard authored
648
649
650

    s = qemu_mallocz(sizeof(ESPState));
    if (!s)
651
        return NULL;
bellard authored
652
653
    s->irq = irq;
654
    s->it_shift = it_shift;
655
656
    s->dma_memory_read = dma_memory_read;
    s->dma_memory_write = dma_memory_write;
657
    s->dma_opaque = dma_opaque;
bellard authored
658
659

    esp_io_memory = cpu_register_io_memory(0, esp_mem_read, esp_mem_write, s);
660
    cpu_register_physical_memory(espaddr, ESP_REGS << it_shift, esp_io_memory);
bellard authored
661
662
663

    esp_reset(s);
664
    register_savevm("esp", espaddr, 3, esp_save, esp_load, s);
bellard authored
665
666
    qemu_register_reset(esp_reset, s);
667
668
    *reset = *qemu_allocate_irqs(parent_esp_reset, s, 1);
669
670
    return s;
}