esp.c 17.2 KB
Newer Older
B
bellard 已提交
1
/*
2
 * QEMU ESP/NCR53C9x emulation
3
 *
P
pbrook 已提交
4
 * Copyright (c) 2005-2006 Fabrice Bellard
5
 *
B
bellard 已提交
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.
 */
P
pbrook 已提交
24 25 26 27 28 29
#include "hw.h"
#include "block.h"
#include "scsi-disk.h"
#include "sun4m.h"
/* FIXME: Only needed for MAX_DISKS, which is probably wrong.  */
#include "sysemu.h"
B
bellard 已提交
30 31

/* debug ESP card */
B
bellard 已提交
32
//#define DEBUG_ESP
B
bellard 已提交
33

34
/*
35 36
 * On Sparc32, this is the ESP (NCR53C90) part of chip STP2000 (Master I/O),
 * also produced as NCR89C100. See
37 38 39 40 41
 * 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
 */

B
bellard 已提交
42 43 44 45 46 47 48
#ifdef DEBUG_ESP
#define DPRINTF(fmt, args...) \
do { printf("ESP: " fmt , ##args); } while (0)
#else
#define DPRINTF(fmt, args...)
#endif

B
blueswir1 已提交
49 50 51
#define ESP_MASK 0x3f
#define ESP_REGS 16
#define ESP_SIZE (ESP_REGS * 4)
P
pbrook 已提交
52
#define TI_BUFSZ 32
T
ths 已提交
53 54
/* The HBA is ID 7, so for simplicitly limit to 7 devices.  */
#define ESP_MAX_DEVS      7
55

P
pbrook 已提交
56
typedef struct ESPState ESPState;
B
bellard 已提交
57

P
pbrook 已提交
58
struct ESPState {
59
    qemu_irq irq;
B
bellard 已提交
60
    BlockDriverState **bd;
B
blueswir1 已提交
61 62
    uint8_t rregs[ESP_REGS];
    uint8_t wregs[ESP_REGS];
63
    int32_t ti_size;
64 65
    uint32_t ti_rptr, ti_wptr;
    uint8_t ti_buf[TI_BUFSZ];
P
pbrook 已提交
66
    int sense;
67
    int dma;
P
pbrook 已提交
68 69
    SCSIDevice *scsi_dev[MAX_DISKS];
    SCSIDevice *current_dev;
P
pbrook 已提交
70 71 72
    uint8_t cmdbuf[TI_BUFSZ];
    int cmdlen;
    int do_cmd;
P
pbrook 已提交
73

P
pbrook 已提交
74
    /* The amount of data left in the current DMA transfer.  */
P
pbrook 已提交
75
    uint32_t dma_left;
P
pbrook 已提交
76 77 78
    /* The size of the current DMA transfer.  Zero if no transfer is in
       progress.  */
    uint32_t dma_counter;
P
pbrook 已提交
79
    uint8_t *async_buf;
P
pbrook 已提交
80
    uint32_t async_len;
81
    void *dma_opaque;
P
pbrook 已提交
82
};
B
bellard 已提交
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 119 120 121
#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

B
bellard 已提交
122 123 124 125 126 127
#define STAT_DO 0x00
#define STAT_DI 0x01
#define STAT_CD 0x02
#define STAT_ST 0x03
#define STAT_MI 0x06
#define STAT_MO 0x07
128
#define STAT_PIO_MASK 0x06
B
bellard 已提交
129 130

#define STAT_TC 0x10
P
pbrook 已提交
131 132
#define STAT_PE 0x20
#define STAT_GE 0x40
B
bellard 已提交
133 134 135 136 137
#define STAT_IN 0x80

#define INTR_FC 0x08
#define INTR_BS 0x10
#define INTR_DC 0x20
B
bellard 已提交
138
#define INTR_RST 0x80
B
bellard 已提交
139 140 141 142

#define SEQ_0 0x0
#define SEQ_CD 0x4

143 144 145 146 147 148
#define CFG1_RESREPT 0x40

#define CFG2_MASK 0x15

#define TCHI_FAS100A 0x4

P
pbrook 已提交
149
static int get_cmd(ESPState *s, uint8_t *buf)
B
bellard 已提交
150
{
P
pbrook 已提交
151
    uint32_t dmalen;
B
bellard 已提交
152 153
    int target;

154 155
    dmalen = s->rregs[ESP_TCLO] | (s->rregs[ESP_TCMID] << 8);
    target = s->wregs[ESP_WBUSID] & 7;
P
pbrook 已提交
156
    DPRINTF("get_cmd: len %d target %d\n", dmalen, target);
157
    if (s->dma) {
158
        espdma_memory_read(s->dma_opaque, buf, dmalen);
159
    } else {
B
blueswir1 已提交
160 161 162
        buf[0] = 0;
        memcpy(&buf[1], s->ti_buf, dmalen);
        dmalen++;
163
    }
P
pbrook 已提交
164

B
bellard 已提交
165
    s->ti_size = 0;
166 167
    s->ti_rptr = 0;
    s->ti_wptr = 0;
B
bellard 已提交
168

P
pbrook 已提交
169 170 171 172 173 174
    if (s->current_dev) {
        /* Started a new command before the old one finished.  Cancel it.  */
        scsi_cancel_io(s->current_dev, 0);
        s->async_len = 0;
    }

175
    if (target >= MAX_DISKS || !s->scsi_dev[target]) {
P
pbrook 已提交
176
        // No such drive
177 178 179
        s->rregs[ESP_RSTAT] = STAT_IN;
        s->rregs[ESP_RINTR] = INTR_DC;
        s->rregs[ESP_RSEQ] = SEQ_0;
B
blueswir1 已提交
180 181
        qemu_irq_raise(s->irq);
        return 0;
B
bellard 已提交
182
    }
P
pbrook 已提交
183
    s->current_dev = s->scsi_dev[target];
P
pbrook 已提交
184 185 186 187 188 189 190 191 192 193
    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;
P
pbrook 已提交
194
    datalen = scsi_send_command(s->current_dev, 0, &buf[1], lun);
195 196
    s->ti_size = datalen;
    if (datalen != 0) {
197
        s->rregs[ESP_RSTAT] = STAT_IN | STAT_TC;
P
pbrook 已提交
198
        s->dma_left = 0;
P
pbrook 已提交
199
        s->dma_counter = 0;
P
pbrook 已提交
200
        if (datalen > 0) {
201
            s->rregs[ESP_RSTAT] |= STAT_DI;
P
pbrook 已提交
202
            scsi_read_data(s->current_dev, 0);
P
pbrook 已提交
203
        } else {
204
            s->rregs[ESP_RSTAT] |= STAT_DO;
P
pbrook 已提交
205
            scsi_write_data(s->current_dev, 0);
B
bellard 已提交
206
        }
B
bellard 已提交
207
    }
208 209
    s->rregs[ESP_RINTR] = INTR_BS | INTR_FC;
    s->rregs[ESP_RSEQ] = SEQ_CD;
210
    qemu_irq_raise(s->irq);
B
bellard 已提交
211 212
}

P
pbrook 已提交
213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228
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;
229 230 231
        s->rregs[ESP_RSTAT] = STAT_IN | STAT_TC | STAT_CD;
        s->rregs[ESP_RINTR] = INTR_BS | INTR_FC;
        s->rregs[ESP_RSEQ] = SEQ_CD;
232
        qemu_irq_raise(s->irq);
P
pbrook 已提交
233 234 235
    }
}

P
pbrook 已提交
236
static void write_response(ESPState *s)
B
bellard 已提交
237
{
P
pbrook 已提交
238 239 240
    DPRINTF("Transfer status (sense=%d)\n", s->sense);
    s->ti_buf[0] = s->sense;
    s->ti_buf[1] = 0;
241
    if (s->dma) {
242
        espdma_memory_write(s->dma_opaque, s->ti_buf, 2);
243 244 245
        s->rregs[ESP_RSTAT] = STAT_IN | STAT_TC | STAT_ST;
        s->rregs[ESP_RINTR] = INTR_BS | INTR_FC;
        s->rregs[ESP_RSEQ] = SEQ_CD;
246
    } else {
B
blueswir1 已提交
247 248 249
        s->ti_size = 2;
        s->ti_rptr = 0;
        s->ti_wptr = 0;
250
        s->rregs[ESP_RFLAGS] = 2;
251
    }
252
    qemu_irq_raise(s->irq);
B
bellard 已提交
253
}
254

P
pbrook 已提交
255 256
static void esp_dma_done(ESPState *s)
{
257 258 259 260 261 262
    s->rregs[ESP_RSTAT] |= STAT_IN | STAT_TC;
    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;
263
    qemu_irq_raise(s->irq);
P
pbrook 已提交
264 265
}

P
pbrook 已提交
266 267
static void esp_do_dma(ESPState *s)
{
268
    uint32_t len;
P
pbrook 已提交
269
    int to_device;
P
pbrook 已提交
270

271
    to_device = (s->ti_size < 0);
P
pbrook 已提交
272
    len = s->dma_left;
P
pbrook 已提交
273 274
    if (s->do_cmd) {
        DPRINTF("command len %d + %d\n", s->cmdlen, len);
275
        espdma_memory_read(s->dma_opaque, &s->cmdbuf[s->cmdlen], len);
P
pbrook 已提交
276 277 278 279 280
        s->ti_size = 0;
        s->cmdlen = 0;
        s->do_cmd = 0;
        do_cmd(s, s->cmdbuf);
        return;
P
pbrook 已提交
281 282 283 284 285 286 287 288 289
    }
    if (s->async_len == 0) {
        /* Defer until data is available.  */
        return;
    }
    if (len > s->async_len) {
        len = s->async_len;
    }
    if (to_device) {
290
        espdma_memory_read(s->dma_opaque, s->async_buf, len);
P
pbrook 已提交
291
    } else {
292
        espdma_memory_write(s->dma_opaque, s->async_buf, len);
P
pbrook 已提交
293 294 295 296
    }
    s->dma_left -= len;
    s->async_buf += len;
    s->async_len -= len;
P
pbrook 已提交
297 298 299 300
    if (to_device)
        s->ti_size += len;
    else
        s->ti_size -= len;
P
pbrook 已提交
301
    if (s->async_len == 0) {
P
pbrook 已提交
302
        if (to_device) {
303
            // ti_size is negative
P
pbrook 已提交
304
            scsi_write_data(s->current_dev, 0);
P
pbrook 已提交
305
        } else {
P
pbrook 已提交
306
            scsi_read_data(s->current_dev, 0);
P
pbrook 已提交
307 308 309 310 311 312
            /* 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);
            }
P
pbrook 已提交
313
        }
P
pbrook 已提交
314 315
    } else {
        /* Partially filled a scsi buffer. Complete immediately.  */
P
pbrook 已提交
316 317
        esp_dma_done(s);
    }
P
pbrook 已提交
318 319
}

P
pbrook 已提交
320 321
static void esp_command_complete(void *opaque, int reason, uint32_t tag,
                                 uint32_t arg)
P
pbrook 已提交
322 323 324
{
    ESPState *s = (ESPState *)opaque;

P
pbrook 已提交
325 326 327 328 329
    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;
P
pbrook 已提交
330 331 332
        s->dma_left = 0;
        s->async_len = 0;
        if (arg)
P
pbrook 已提交
333
            DPRINTF("Command failed\n");
P
pbrook 已提交
334
        s->sense = arg;
335
        s->rregs[ESP_RSTAT] = STAT_ST;
P
pbrook 已提交
336 337
        esp_dma_done(s);
        s->current_dev = NULL;
P
pbrook 已提交
338 339
    } else {
        DPRINTF("transfer %d/%d\n", s->dma_left, s->ti_size);
P
pbrook 已提交
340 341
        s->async_len = arg;
        s->async_buf = scsi_get_buf(s->current_dev, 0);
P
pbrook 已提交
342
        if (s->dma_left) {
P
pbrook 已提交
343
            esp_do_dma(s);
P
pbrook 已提交
344 345 346 347 348
        } 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);
        }
P
pbrook 已提交
349
    }
P
pbrook 已提交
350 351
}

B
bellard 已提交
352 353
static void handle_ti(ESPState *s)
{
P
pbrook 已提交
354
    uint32_t dmalen, minlen;
B
bellard 已提交
355

356
    dmalen = s->rregs[ESP_TCLO] | (s->rregs[ESP_TCMID] << 8);
P
pbrook 已提交
357 358 359
    if (dmalen==0) {
      dmalen=0x10000;
    }
P
pbrook 已提交
360
    s->dma_counter = dmalen;
P
pbrook 已提交
361

P
pbrook 已提交
362 363
    if (s->do_cmd)
        minlen = (dmalen < 32) ? dmalen : 32;
364 365
    else if (s->ti_size < 0)
        minlen = (dmalen < -s->ti_size) ? dmalen : -s->ti_size;
P
pbrook 已提交
366 367
    else
        minlen = (dmalen < s->ti_size) ? dmalen : s->ti_size;
P
pbrook 已提交
368
    DPRINTF("Transfer Information len %d\n", minlen);
369
    if (s->dma) {
P
pbrook 已提交
370
        s->dma_left = minlen;
371
        s->rregs[ESP_RSTAT] &= ~STAT_TC;
P
pbrook 已提交
372
        esp_do_dma(s);
P
pbrook 已提交
373 374 375 376 377 378 379 380
    } 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;
    }
B
bellard 已提交
381 382
}

B
blueswir1 已提交
383
static void esp_reset(void *opaque)
B
bellard 已提交
384 385
{
    ESPState *s = opaque;
386

B
blueswir1 已提交
387 388
    memset(s->rregs, 0, ESP_REGS);
    memset(s->wregs, 0, ESP_REGS);
389
    s->rregs[ESP_TCHI] = TCHI_FAS100A; // Indicate fas100a
P
pbrook 已提交
390 391 392 393
    s->ti_size = 0;
    s->ti_rptr = 0;
    s->ti_wptr = 0;
    s->dma = 0;
P
pbrook 已提交
394
    s->do_cmd = 0;
B
bellard 已提交
395 396
}

397 398 399 400 401 402
static void parent_esp_reset(void *opaque, int irq, int level)
{
    if (level)
        esp_reset(opaque);
}

B
bellard 已提交
403 404 405 406 407
static uint32_t esp_mem_readb(void *opaque, target_phys_addr_t addr)
{
    ESPState *s = opaque;
    uint32_t saddr;

B
blueswir1 已提交
408
    saddr = (addr & ESP_MASK) >> 2;
B
bellard 已提交
409
    DPRINTF("read reg[%d]: 0x%2.2x\n", saddr, s->rregs[saddr]);
B
bellard 已提交
410
    switch (saddr) {
411
    case ESP_FIFO:
B
blueswir1 已提交
412 413
        if (s->ti_size > 0) {
            s->ti_size--;
414
            if ((s->rregs[ESP_RSTAT] & STAT_PIO_MASK) == 0) {
P
pbrook 已提交
415
                /* Data in/out.  */
P
pbrook 已提交
416
                fprintf(stderr, "esp: PIO data read not implemented\n");
417
                s->rregs[ESP_FIFO] = 0;
P
pbrook 已提交
418
            } else {
419
                s->rregs[ESP_FIFO] = s->ti_buf[s->ti_rptr++];
P
pbrook 已提交
420
            }
421
            qemu_irq_raise(s->irq);
B
blueswir1 已提交
422 423
        }
        if (s->ti_size == 0) {
424 425 426
            s->ti_rptr = 0;
            s->ti_wptr = 0;
        }
B
blueswir1 已提交
427
        break;
428
    case ESP_RINTR:
P
pbrook 已提交
429
        // Clear interrupt/error status bits
430
        s->rregs[ESP_RSTAT] &= ~(STAT_IN | STAT_GE | STAT_PE);
B
blueswir1 已提交
431
        qemu_irq_lower(s->irq);
B
bellard 已提交
432
        break;
B
bellard 已提交
433
    default:
B
blueswir1 已提交
434
        break;
B
bellard 已提交
435
    }
B
bellard 已提交
436
    return s->rregs[saddr];
B
bellard 已提交
437 438 439 440 441 442 443
}

static void esp_mem_writeb(void *opaque, target_phys_addr_t addr, uint32_t val)
{
    ESPState *s = opaque;
    uint32_t saddr;

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

static CPUReadMemoryFunc *esp_mem_read[3] = {
    esp_mem_readb,
    esp_mem_readb,
    esp_mem_readb,
};

static CPUWriteMemoryFunc *esp_mem_write[3] = {
    esp_mem_writeb,
    esp_mem_writeb,
    esp_mem_writeb,
};

static void esp_save(QEMUFile *f, void *opaque)
{
    ESPState *s = opaque;
B
bellard 已提交
562

B
blueswir1 已提交
563 564
    qemu_put_buffer(f, s->rregs, ESP_REGS);
    qemu_put_buffer(f, s->wregs, ESP_REGS);
565 566 567 568
    qemu_put_be32s(f, &s->ti_size);
    qemu_put_be32s(f, &s->ti_rptr);
    qemu_put_be32s(f, &s->ti_wptr);
    qemu_put_buffer(f, s->ti_buf, TI_BUFSZ);
B
blueswir1 已提交
569
    qemu_put_be32s(f, &s->sense);
570
    qemu_put_be32s(f, &s->dma);
B
blueswir1 已提交
571 572 573 574 575
    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
B
bellard 已提交
576 577 578 579 580
}

static int esp_load(QEMUFile *f, void *opaque, int version_id)
{
    ESPState *s = opaque;
581

B
blueswir1 已提交
582 583
    if (version_id != 3)
        return -EINVAL; // Cannot emulate 2
B
bellard 已提交
584

B
blueswir1 已提交
585 586
    qemu_get_buffer(f, s->rregs, ESP_REGS);
    qemu_get_buffer(f, s->wregs, ESP_REGS);
587 588 589 590
    qemu_get_be32s(f, &s->ti_size);
    qemu_get_be32s(f, &s->ti_rptr);
    qemu_get_be32s(f, &s->ti_wptr);
    qemu_get_buffer(f, s->ti_buf, TI_BUFSZ);
B
blueswir1 已提交
591
    qemu_get_be32s(f, &s->sense);
592
    qemu_get_be32s(f, &s->dma);
B
blueswir1 已提交
593 594 595 596
    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);
B
bellard 已提交
597

B
bellard 已提交
598 599 600
    return 0;
}

T
ths 已提交
601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623
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);
        scsi_disk_destroy(s->scsi_dev[id]);
    }
    DPRINTF("Attaching block device %d\n", id);
    /* Command queueing is not implemented.  */
    s->scsi_dev[id] = scsi_disk_init(bd, 0, esp_command_complete, s);
}

624
void *esp_init(BlockDriverState **bd, target_phys_addr_t espaddr,
625
               void *dma_opaque, qemu_irq irq, qemu_irq *reset)
B
bellard 已提交
626 627
{
    ESPState *s;
628
    int esp_io_memory;
B
bellard 已提交
629 630 631

    s = qemu_mallocz(sizeof(ESPState));
    if (!s)
632
        return NULL;
B
bellard 已提交
633 634

    s->bd = bd;
635
    s->irq = irq;
636
    s->dma_opaque = dma_opaque;
B
bellard 已提交
637 638

    esp_io_memory = cpu_register_io_memory(0, esp_mem_read, esp_mem_write, s);
B
blueswir1 已提交
639
    cpu_register_physical_memory(espaddr, ESP_SIZE, esp_io_memory);
B
bellard 已提交
640 641 642

    esp_reset(s);

B
blueswir1 已提交
643
    register_savevm("esp", espaddr, 3, esp_save, esp_load, s);
B
bellard 已提交
644 645
    qemu_register_reset(esp_reset, s);

646 647
    *reset = *qemu_allocate_irqs(parent_esp_reset, s, 1);

648 649
    return s;
}