Annotation of qemu/hw/esp.c, revision 1.1.1.6

1.1       root        1: /*
1.1.1.5   root        2:  * QEMU ESP/NCR53C9x emulation
1.1.1.6 ! root        3:  *
1.1.1.3   root        4:  * Copyright (c) 2005-2006 Fabrice Bellard
1.1.1.6 ! root        5:  *
1.1       root        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:  */
1.1.1.6 ! root       24: #include "hw.h"
        !            25: #include "block.h"
        !            26: #include "scsi-disk.h"
        !            27: #include "sun4m.h"
        !            28: /* FIXME: Only needed for MAX_DISKS, which is probably wrong.  */
        !            29: #include "sysemu.h"
1.1       root       30: 
                     31: /* debug ESP card */
                     32: //#define DEBUG_ESP
                     33: 
1.1.1.5   root       34: /*
1.1.1.6 ! root       35:  * On Sparc32, this is the ESP (NCR53C90) part of chip STP2000 (Master I/O),
        !            36:  * also produced as NCR89C100. See
1.1.1.5   root       37:  * http://www.ibiblio.org/pub/historic-linux/early-ports/Sparc/NCR/NCR89C100.txt
                     38:  * and
                     39:  * http://www.ibiblio.org/pub/historic-linux/early-ports/Sparc/NCR/NCR53C9X.txt
                     40:  */
                     41: 
1.1       root       42: #ifdef DEBUG_ESP
                     43: #define DPRINTF(fmt, args...) \
                     44: do { printf("ESP: " fmt , ##args); } while (0)
                     45: #else
                     46: #define DPRINTF(fmt, args...)
                     47: #endif
                     48: 
1.1.1.6 ! root       49: #define ESP_MASK 0x3f
        !            50: #define ESP_REGS 16
        !            51: #define ESP_SIZE (ESP_REGS * 4)
1.1.1.4   root       52: #define TI_BUFSZ 32
1.1.1.5   root       53: 
1.1.1.3   root       54: typedef struct ESPState ESPState;
1.1       root       55: 
1.1.1.3   root       56: struct ESPState {
1.1.1.6 ! root       57:     qemu_irq irq;
        !            58:     uint8_t rregs[ESP_REGS];
        !            59:     uint8_t wregs[ESP_REGS];
1.1.1.5   root       60:     int32_t ti_size;
1.1.1.2   root       61:     uint32_t ti_rptr, ti_wptr;
                     62:     uint8_t ti_buf[TI_BUFSZ];
1.1.1.4   root       63:     int sense;
1.1.1.2   root       64:     int dma;
1.1.1.6 ! root       65:     SCSIDevice *scsi_dev[ESP_MAX_DEVS];
1.1.1.4   root       66:     SCSIDevice *current_dev;
                     67:     uint8_t cmdbuf[TI_BUFSZ];
                     68:     int cmdlen;
                     69:     int do_cmd;
1.1.1.5   root       70: 
                     71:     /* The amount of data left in the current DMA transfer.  */
                     72:     uint32_t dma_left;
                     73:     /* The size of the current DMA transfer.  Zero if no transfer is in
                     74:        progress.  */
                     75:     uint32_t dma_counter;
                     76:     uint8_t *async_buf;
                     77:     uint32_t async_len;
                     78:     void *dma_opaque;
1.1.1.3   root       79: };
1.1       root       80: 
1.1.1.6 ! root       81: #define ESP_TCLO   0x0
        !            82: #define ESP_TCMID  0x1
        !            83: #define ESP_FIFO   0x2
        !            84: #define ESP_CMD    0x3
        !            85: #define ESP_RSTAT  0x4
        !            86: #define ESP_WBUSID 0x4
        !            87: #define ESP_RINTR  0x5
        !            88: #define ESP_WSEL   0x5
        !            89: #define ESP_RSEQ   0x6
        !            90: #define ESP_WSYNTP 0x6
        !            91: #define ESP_RFLAGS 0x7
        !            92: #define ESP_WSYNO  0x7
        !            93: #define ESP_CFG1   0x8
        !            94: #define ESP_RRES1  0x9
        !            95: #define ESP_WCCF   0x9
        !            96: #define ESP_RRES2  0xa
        !            97: #define ESP_WTEST  0xa
        !            98: #define ESP_CFG2   0xb
        !            99: #define ESP_CFG3   0xc
        !           100: #define ESP_RES3   0xd
        !           101: #define ESP_TCHI   0xe
        !           102: #define ESP_RES4   0xf
        !           103: 
        !           104: #define CMD_DMA 0x80
        !           105: #define CMD_CMD 0x7f
        !           106: 
        !           107: #define CMD_NOP      0x00
        !           108: #define CMD_FLUSH    0x01
        !           109: #define CMD_RESET    0x02
        !           110: #define CMD_BUSRESET 0x03
        !           111: #define CMD_TI       0x10
        !           112: #define CMD_ICCS     0x11
        !           113: #define CMD_MSGACC   0x12
        !           114: #define CMD_SATN     0x1a
        !           115: #define CMD_SELATN   0x42
        !           116: #define CMD_SELATNS  0x43
        !           117: #define CMD_ENSEL    0x44
        !           118: 
1.1       root      119: #define STAT_DO 0x00
                    120: #define STAT_DI 0x01
                    121: #define STAT_CD 0x02
                    122: #define STAT_ST 0x03
                    123: #define STAT_MI 0x06
                    124: #define STAT_MO 0x07
1.1.1.6 ! root      125: #define STAT_PIO_MASK 0x06
1.1       root      126: 
                    127: #define STAT_TC 0x10
1.1.1.5   root      128: #define STAT_PE 0x20
                    129: #define STAT_GE 0x40
1.1       root      130: #define STAT_IN 0x80
                    131: 
                    132: #define INTR_FC 0x08
                    133: #define INTR_BS 0x10
                    134: #define INTR_DC 0x20
1.1.1.2   root      135: #define INTR_RST 0x80
1.1       root      136: 
                    137: #define SEQ_0 0x0
                    138: #define SEQ_CD 0x4
                    139: 
1.1.1.6 ! root      140: #define CFG1_RESREPT 0x40
        !           141: 
        !           142: #define CFG2_MASK 0x15
        !           143: 
        !           144: #define TCHI_FAS100A 0x4
        !           145: 
1.1.1.4   root      146: static int get_cmd(ESPState *s, uint8_t *buf)
1.1       root      147: {
1.1.1.5   root      148:     uint32_t dmalen;
1.1       root      149:     int target;
                    150: 
1.1.1.6 ! root      151:     dmalen = s->rregs[ESP_TCLO] | (s->rregs[ESP_TCMID] << 8);
        !           152:     target = s->wregs[ESP_WBUSID] & 7;
1.1.1.4   root      153:     DPRINTF("get_cmd: len %d target %d\n", dmalen, target);
1.1.1.2   root      154:     if (s->dma) {
1.1.1.5   root      155:         espdma_memory_read(s->dma_opaque, buf, dmalen);
1.1.1.2   root      156:     } else {
1.1.1.6 ! root      157:         buf[0] = 0;
        !           158:         memcpy(&buf[1], s->ti_buf, dmalen);
        !           159:         dmalen++;
1.1.1.2   root      160:     }
1.1.1.4   root      161: 
1.1       root      162:     s->ti_size = 0;
1.1.1.2   root      163:     s->ti_rptr = 0;
                    164:     s->ti_wptr = 0;
1.1       root      165: 
1.1.1.5   root      166:     if (s->current_dev) {
                    167:         /* Started a new command before the old one finished.  Cancel it.  */
1.1.1.6 ! root      168:         s->current_dev->cancel_io(s->current_dev, 0);
1.1.1.5   root      169:         s->async_len = 0;
                    170:     }
                    171: 
1.1.1.6 ! root      172:     if (target >= ESP_MAX_DEVS || !s->scsi_dev[target]) {
1.1.1.4   root      173:         // No such drive
1.1.1.6 ! root      174:         s->rregs[ESP_RSTAT] = STAT_IN;
        !           175:         s->rregs[ESP_RINTR] = INTR_DC;
        !           176:         s->rregs[ESP_RSEQ] = SEQ_0;
        !           177:         qemu_irq_raise(s->irq);
        !           178:         return 0;
1.1       root      179:     }
1.1.1.4   root      180:     s->current_dev = s->scsi_dev[target];
                    181:     return dmalen;
                    182: }
                    183: 
                    184: static void do_cmd(ESPState *s, uint8_t *buf)
                    185: {
                    186:     int32_t datalen;
                    187:     int lun;
                    188: 
                    189:     DPRINTF("do_cmd: busid 0x%x\n", buf[0]);
                    190:     lun = buf[0] & 7;
1.1.1.6 ! root      191:     datalen = s->current_dev->send_command(s->current_dev, 0, &buf[1], lun);
1.1.1.5   root      192:     s->ti_size = datalen;
                    193:     if (datalen != 0) {
1.1.1.6 ! root      194:         s->rregs[ESP_RSTAT] = STAT_IN | STAT_TC;
1.1.1.5   root      195:         s->dma_left = 0;
                    196:         s->dma_counter = 0;
1.1.1.4   root      197:         if (datalen > 0) {
1.1.1.6 ! root      198:             s->rregs[ESP_RSTAT] |= STAT_DI;
        !           199:             s->current_dev->read_data(s->current_dev, 0);
1.1.1.4   root      200:         } else {
1.1.1.6 ! root      201:             s->rregs[ESP_RSTAT] |= STAT_DO;
        !           202:             s->current_dev->write_data(s->current_dev, 0);
1.1.1.2   root      203:         }
1.1       root      204:     }
1.1.1.6 ! root      205:     s->rregs[ESP_RINTR] = INTR_BS | INTR_FC;
        !           206:     s->rregs[ESP_RSEQ] = SEQ_CD;
        !           207:     qemu_irq_raise(s->irq);
1.1       root      208: }
                    209: 
1.1.1.4   root      210: static void handle_satn(ESPState *s)
                    211: {
                    212:     uint8_t buf[32];
                    213:     int len;
                    214: 
                    215:     len = get_cmd(s, buf);
                    216:     if (len)
                    217:         do_cmd(s, buf);
                    218: }
                    219: 
                    220: static void handle_satn_stop(ESPState *s)
1.1       root      221: {
1.1.1.4   root      222:     s->cmdlen = get_cmd(s, s->cmdbuf);
                    223:     if (s->cmdlen) {
                    224:         DPRINTF("Set ATN & Stop: cmdlen %d\n", s->cmdlen);
                    225:         s->do_cmd = 1;
1.1.1.6 ! root      226:         s->rregs[ESP_RSTAT] = STAT_IN | STAT_TC | STAT_CD;
        !           227:         s->rregs[ESP_RINTR] = INTR_BS | INTR_FC;
        !           228:         s->rregs[ESP_RSEQ] = SEQ_CD;
        !           229:         qemu_irq_raise(s->irq);
1.1.1.4   root      230:     }
                    231: }
1.1       root      232: 
1.1.1.4   root      233: static void write_response(ESPState *s)
                    234: {
                    235:     DPRINTF("Transfer status (sense=%d)\n", s->sense);
                    236:     s->ti_buf[0] = s->sense;
                    237:     s->ti_buf[1] = 0;
1.1.1.2   root      238:     if (s->dma) {
1.1.1.5   root      239:         espdma_memory_write(s->dma_opaque, s->ti_buf, 2);
1.1.1.6 ! root      240:         s->rregs[ESP_RSTAT] = STAT_IN | STAT_TC | STAT_ST;
        !           241:         s->rregs[ESP_RINTR] = INTR_BS | INTR_FC;
        !           242:         s->rregs[ESP_RSEQ] = SEQ_CD;
1.1.1.2   root      243:     } else {
1.1.1.6 ! root      244:         s->ti_size = 2;
        !           245:         s->ti_rptr = 0;
        !           246:         s->ti_wptr = 0;
        !           247:         s->rregs[ESP_RFLAGS] = 2;
1.1.1.2   root      248:     }
1.1.1.6 ! root      249:     qemu_irq_raise(s->irq);
1.1.1.5   root      250: }
1.1       root      251: 
1.1.1.5   root      252: static void esp_dma_done(ESPState *s)
                    253: {
1.1.1.6 ! root      254:     s->rregs[ESP_RSTAT] |= STAT_IN | STAT_TC;
        !           255:     s->rregs[ESP_RINTR] = INTR_BS;
        !           256:     s->rregs[ESP_RSEQ] = 0;
        !           257:     s->rregs[ESP_RFLAGS] = 0;
        !           258:     s->rregs[ESP_TCLO] = 0;
        !           259:     s->rregs[ESP_TCMID] = 0;
        !           260:     qemu_irq_raise(s->irq);
1.1       root      261: }
1.1.1.2   root      262: 
1.1.1.5   root      263: static void esp_do_dma(ESPState *s)
                    264: {
                    265:     uint32_t len;
                    266:     int to_device;
                    267: 
                    268:     to_device = (s->ti_size < 0);
                    269:     len = s->dma_left;
                    270:     if (s->do_cmd) {
                    271:         DPRINTF("command len %d + %d\n", s->cmdlen, len);
                    272:         espdma_memory_read(s->dma_opaque, &s->cmdbuf[s->cmdlen], len);
                    273:         s->ti_size = 0;
                    274:         s->cmdlen = 0;
                    275:         s->do_cmd = 0;
                    276:         do_cmd(s, s->cmdbuf);
                    277:         return;
                    278:     }
                    279:     if (s->async_len == 0) {
                    280:         /* Defer until data is available.  */
                    281:         return;
                    282:     }
                    283:     if (len > s->async_len) {
                    284:         len = s->async_len;
                    285:     }
                    286:     if (to_device) {
                    287:         espdma_memory_read(s->dma_opaque, s->async_buf, len);
                    288:     } else {
                    289:         espdma_memory_write(s->dma_opaque, s->async_buf, len);
                    290:     }
                    291:     s->dma_left -= len;
                    292:     s->async_buf += len;
                    293:     s->async_len -= len;
                    294:     if (to_device)
                    295:         s->ti_size += len;
                    296:     else
                    297:         s->ti_size -= len;
                    298:     if (s->async_len == 0) {
                    299:         if (to_device) {
                    300:             // ti_size is negative
1.1.1.6 ! root      301:             s->current_dev->write_data(s->current_dev, 0);
1.1.1.5   root      302:         } else {
1.1.1.6 ! root      303:             s->current_dev->read_data(s->current_dev, 0);
1.1.1.5   root      304:             /* If there is still data to be read from the device then
                    305:                complete the DMA operation immeriately.  Otherwise defer
                    306:                until the scsi layer has completed.  */
                    307:             if (s->dma_left == 0 && s->ti_size > 0) {
                    308:                 esp_dma_done(s);
                    309:             }
                    310:         }
                    311:     } else {
                    312:         /* Partially filled a scsi buffer. Complete immediately.  */
                    313:         esp_dma_done(s);
                    314:     }
                    315: }
                    316: 
                    317: static void esp_command_complete(void *opaque, int reason, uint32_t tag,
                    318:                                  uint32_t arg)
1.1.1.4   root      319: {
                    320:     ESPState *s = (ESPState *)opaque;
                    321: 
1.1.1.5   root      322:     if (reason == SCSI_REASON_DONE) {
                    323:         DPRINTF("SCSI Command complete\n");
                    324:         if (s->ti_size != 0)
                    325:             DPRINTF("SCSI command completed unexpectedly\n");
                    326:         s->ti_size = 0;
                    327:         s->dma_left = 0;
                    328:         s->async_len = 0;
                    329:         if (arg)
                    330:             DPRINTF("Command failed\n");
                    331:         s->sense = arg;
1.1.1.6 ! root      332:         s->rregs[ESP_RSTAT] = STAT_ST;
1.1.1.5   root      333:         esp_dma_done(s);
                    334:         s->current_dev = NULL;
                    335:     } else {
                    336:         DPRINTF("transfer %d/%d\n", s->dma_left, s->ti_size);
                    337:         s->async_len = arg;
1.1.1.6 ! root      338:         s->async_buf = s->current_dev->get_buf(s->current_dev, 0);
1.1.1.5   root      339:         if (s->dma_left) {
                    340:             esp_do_dma(s);
                    341:         } else if (s->dma_counter != 0 && s->ti_size <= 0) {
                    342:             /* If this was the last part of a DMA transfer then the
                    343:                completion interrupt is deferred to here.  */
                    344:             esp_dma_done(s);
                    345:         }
                    346:     }
1.1.1.4   root      347: }
1.1       root      348: 
                    349: static void handle_ti(ESPState *s)
                    350: {
1.1.1.5   root      351:     uint32_t dmalen, minlen;
1.1       root      352: 
1.1.1.6 ! root      353:     dmalen = s->rregs[ESP_TCLO] | (s->rregs[ESP_TCMID] << 8);
1.1.1.4   root      354:     if (dmalen==0) {
                    355:       dmalen=0x10000;
                    356:     }
1.1.1.5   root      357:     s->dma_counter = dmalen;
1.1.1.4   root      358: 
                    359:     if (s->do_cmd)
                    360:         minlen = (dmalen < 32) ? dmalen : 32;
1.1.1.5   root      361:     else if (s->ti_size < 0)
                    362:         minlen = (dmalen < -s->ti_size) ? dmalen : -s->ti_size;
1.1.1.4   root      363:     else
                    364:         minlen = (dmalen < s->ti_size) ? dmalen : s->ti_size;
                    365:     DPRINTF("Transfer Information len %d\n", minlen);
1.1.1.2   root      366:     if (s->dma) {
1.1.1.5   root      367:         s->dma_left = minlen;
1.1.1.6 ! root      368:         s->rregs[ESP_RSTAT] &= ~STAT_TC;
1.1.1.5   root      369:         esp_do_dma(s);
1.1.1.4   root      370:     } else if (s->do_cmd) {
                    371:         DPRINTF("command len %d\n", s->cmdlen);
                    372:         s->ti_size = 0;
                    373:         s->cmdlen = 0;
                    374:         s->do_cmd = 0;
                    375:         do_cmd(s, s->cmdbuf);
                    376:         return;
                    377:     }
1.1       root      378: }
                    379: 
1.1.1.6 ! root      380: static void esp_reset(void *opaque)
1.1       root      381: {
                    382:     ESPState *s = opaque;
1.1.1.5   root      383: 
1.1.1.6 ! root      384:     memset(s->rregs, 0, ESP_REGS);
        !           385:     memset(s->wregs, 0, ESP_REGS);
        !           386:     s->rregs[ESP_TCHI] = TCHI_FAS100A; // Indicate fas100a
1.1.1.3   root      387:     s->ti_size = 0;
                    388:     s->ti_rptr = 0;
                    389:     s->ti_wptr = 0;
                    390:     s->dma = 0;
1.1.1.4   root      391:     s->do_cmd = 0;
1.1       root      392: }
                    393: 
1.1.1.6 ! root      394: static void parent_esp_reset(void *opaque, int irq, int level)
        !           395: {
        !           396:     if (level)
        !           397:         esp_reset(opaque);
        !           398: }
        !           399: 
1.1       root      400: static uint32_t esp_mem_readb(void *opaque, target_phys_addr_t addr)
                    401: {
                    402:     ESPState *s = opaque;
                    403:     uint32_t saddr;
                    404: 
1.1.1.6 ! root      405:     saddr = (addr & ESP_MASK) >> 2;
1.1.1.2   root      406:     DPRINTF("read reg[%d]: 0x%2.2x\n", saddr, s->rregs[saddr]);
1.1       root      407:     switch (saddr) {
1.1.1.6 ! root      408:     case ESP_FIFO:
        !           409:         if (s->ti_size > 0) {
        !           410:             s->ti_size--;
        !           411:             if ((s->rregs[ESP_RSTAT] & STAT_PIO_MASK) == 0) {
1.1.1.4   root      412:                 /* Data in/out.  */
1.1.1.5   root      413:                 fprintf(stderr, "esp: PIO data read not implemented\n");
1.1.1.6 ! root      414:                 s->rregs[ESP_FIFO] = 0;
1.1.1.4   root      415:             } else {
1.1.1.6 ! root      416:                 s->rregs[ESP_FIFO] = s->ti_buf[s->ti_rptr++];
1.1.1.4   root      417:             }
1.1.1.6 ! root      418:             qemu_irq_raise(s->irq);
        !           419:         }
        !           420:         if (s->ti_size == 0) {
1.1.1.2   root      421:             s->ti_rptr = 0;
                    422:             s->ti_wptr = 0;
                    423:         }
1.1.1.6 ! root      424:         break;
        !           425:     case ESP_RINTR:
1.1.1.5   root      426:         // Clear interrupt/error status bits
1.1.1.6 ! root      427:         s->rregs[ESP_RSTAT] &= ~(STAT_IN | STAT_GE | STAT_PE);
        !           428:         qemu_irq_lower(s->irq);
1.1.1.2   root      429:         break;
1.1       root      430:     default:
1.1.1.6 ! root      431:         break;
1.1       root      432:     }
                    433:     return s->rregs[saddr];
                    434: }
                    435: 
                    436: static void esp_mem_writeb(void *opaque, target_phys_addr_t addr, uint32_t val)
                    437: {
                    438:     ESPState *s = opaque;
                    439:     uint32_t saddr;
                    440: 
1.1.1.6 ! root      441:     saddr = (addr & ESP_MASK) >> 2;
        !           442:     DPRINTF("write reg[%d]: 0x%2.2x -> 0x%2.2x\n", saddr, s->wregs[saddr],
        !           443:             val);
1.1       root      444:     switch (saddr) {
1.1.1.6 ! root      445:     case ESP_TCLO:
        !           446:     case ESP_TCMID:
        !           447:         s->rregs[ESP_RSTAT] &= ~STAT_TC;
1.1.1.2   root      448:         break;
1.1.1.6 ! root      449:     case ESP_FIFO:
1.1.1.4   root      450:         if (s->do_cmd) {
                    451:             s->cmdbuf[s->cmdlen++] = val & 0xff;
1.1.1.6 ! root      452:         } else if ((s->rregs[ESP_RSTAT] & STAT_PIO_MASK) == 0) {
1.1.1.4   root      453:             uint8_t buf;
                    454:             buf = val & 0xff;
                    455:             s->ti_size--;
1.1.1.5   root      456:             fprintf(stderr, "esp: PIO data write not implemented\n");
1.1.1.4   root      457:         } else {
                    458:             s->ti_size++;
                    459:             s->ti_buf[s->ti_wptr++] = val & 0xff;
                    460:         }
1.1.1.6 ! root      461:         break;
        !           462:     case ESP_CMD:
1.1.1.2   root      463:         s->rregs[saddr] = val;
1.1.1.6 ! root      464:         if (val & CMD_DMA) {
        !           465:             s->dma = 1;
1.1.1.5   root      466:             /* Reload DMA counter.  */
1.1.1.6 ! root      467:             s->rregs[ESP_TCLO] = s->wregs[ESP_TCLO];
        !           468:             s->rregs[ESP_TCMID] = s->wregs[ESP_TCMID];
        !           469:         } else {
        !           470:             s->dma = 0;
        !           471:         }
        !           472:         switch(val & CMD_CMD) {
        !           473:         case CMD_NOP:
        !           474:             DPRINTF("NOP (%2.2x)\n", val);
        !           475:             break;
        !           476:         case CMD_FLUSH:
        !           477:             DPRINTF("Flush FIFO (%2.2x)\n", val);
1.1.1.2   root      478:             //s->ti_size = 0;
1.1.1.6 ! root      479:             s->rregs[ESP_RINTR] = INTR_FC;
        !           480:             s->rregs[ESP_RSEQ] = 0;
        !           481:             break;
        !           482:         case CMD_RESET:
        !           483:             DPRINTF("Chip reset (%2.2x)\n", val);
        !           484:             esp_reset(s);
        !           485:             break;
        !           486:         case CMD_BUSRESET:
        !           487:             DPRINTF("Bus reset (%2.2x)\n", val);
        !           488:             s->rregs[ESP_RINTR] = INTR_RST;
        !           489:             if (!(s->wregs[ESP_CFG1] & CFG1_RESREPT)) {
        !           490:                 qemu_irq_raise(s->irq);
1.1.1.2   root      491:             }
1.1.1.6 ! root      492:             break;
        !           493:         case CMD_TI:
        !           494:             handle_ti(s);
        !           495:             break;
        !           496:         case CMD_ICCS:
        !           497:             DPRINTF("Initiator Command Complete Sequence (%2.2x)\n", val);
        !           498:             write_response(s);
        !           499:             break;
        !           500:         case CMD_MSGACC:
        !           501:             DPRINTF("Message Accepted (%2.2x)\n", val);
        !           502:             write_response(s);
        !           503:             s->rregs[ESP_RINTR] = INTR_DC;
        !           504:             s->rregs[ESP_RSEQ] = 0;
        !           505:             break;
        !           506:         case CMD_SATN:
        !           507:             DPRINTF("Set ATN (%2.2x)\n", val);
        !           508:             break;
        !           509:         case CMD_SELATN:
        !           510:             DPRINTF("Set ATN (%2.2x)\n", val);
        !           511:             handle_satn(s);
        !           512:             break;
        !           513:         case CMD_SELATNS:
        !           514:             DPRINTF("Set ATN & stop (%2.2x)\n", val);
        !           515:             handle_satn_stop(s);
        !           516:             break;
        !           517:         case CMD_ENSEL:
        !           518:             DPRINTF("Enable selection (%2.2x)\n", val);
        !           519:             break;
        !           520:         default:
        !           521:             DPRINTF("Unhandled ESP command (%2.2x)\n", val);
        !           522:             break;
        !           523:         }
        !           524:         break;
        !           525:     case ESP_WBUSID ... ESP_WSYNO:
        !           526:         break;
        !           527:     case ESP_CFG1:
1.1.1.2   root      528:         s->rregs[saddr] = val;
                    529:         break;
1.1.1.6 ! root      530:     case ESP_WCCF ... ESP_WTEST:
1.1.1.2   root      531:         break;
1.1.1.6 ! root      532:     case ESP_CFG2:
        !           533:         s->rregs[saddr] = val & CFG2_MASK;
1.1.1.2   root      534:         break;
1.1.1.6 ! root      535:     case ESP_CFG3 ... ESP_RES4:
1.1.1.2   root      536:         s->rregs[saddr] = val;
                    537:         break;
1.1       root      538:     default:
1.1.1.6 ! root      539:         break;
1.1       root      540:     }
                    541:     s->wregs[saddr] = val;
                    542: }
                    543: 
                    544: static CPUReadMemoryFunc *esp_mem_read[3] = {
                    545:     esp_mem_readb,
1.1.1.6 ! root      546:     NULL,
        !           547:     NULL,
1.1       root      548: };
                    549: 
                    550: static CPUWriteMemoryFunc *esp_mem_write[3] = {
                    551:     esp_mem_writeb,
1.1.1.6 ! root      552:     NULL,
        !           553:     NULL,
1.1       root      554: };
                    555: 
                    556: static void esp_save(QEMUFile *f, void *opaque)
                    557: {
                    558:     ESPState *s = opaque;
                    559: 
1.1.1.6 ! root      560:     qemu_put_buffer(f, s->rregs, ESP_REGS);
        !           561:     qemu_put_buffer(f, s->wregs, ESP_REGS);
1.1.1.2   root      562:     qemu_put_be32s(f, &s->ti_size);
                    563:     qemu_put_be32s(f, &s->ti_rptr);
                    564:     qemu_put_be32s(f, &s->ti_wptr);
                    565:     qemu_put_buffer(f, s->ti_buf, TI_BUFSZ);
1.1.1.6 ! root      566:     qemu_put_be32s(f, &s->sense);
1.1.1.2   root      567:     qemu_put_be32s(f, &s->dma);
1.1.1.6 ! root      568:     qemu_put_buffer(f, s->cmdbuf, TI_BUFSZ);
        !           569:     qemu_put_be32s(f, &s->cmdlen);
        !           570:     qemu_put_be32s(f, &s->do_cmd);
        !           571:     qemu_put_be32s(f, &s->dma_left);
        !           572:     // There should be no transfers in progress, so dma_counter is not saved
1.1       root      573: }
                    574: 
                    575: static int esp_load(QEMUFile *f, void *opaque, int version_id)
                    576: {
                    577:     ESPState *s = opaque;
                    578: 
1.1.1.6 ! root      579:     if (version_id != 3)
        !           580:         return -EINVAL; // Cannot emulate 2
        !           581: 
        !           582:     qemu_get_buffer(f, s->rregs, ESP_REGS);
        !           583:     qemu_get_buffer(f, s->wregs, ESP_REGS);
1.1.1.2   root      584:     qemu_get_be32s(f, &s->ti_size);
                    585:     qemu_get_be32s(f, &s->ti_rptr);
                    586:     qemu_get_be32s(f, &s->ti_wptr);
                    587:     qemu_get_buffer(f, s->ti_buf, TI_BUFSZ);
1.1.1.6 ! root      588:     qemu_get_be32s(f, &s->sense);
1.1.1.2   root      589:     qemu_get_be32s(f, &s->dma);
1.1.1.6 ! root      590:     qemu_get_buffer(f, s->cmdbuf, TI_BUFSZ);
        !           591:     qemu_get_be32s(f, &s->cmdlen);
        !           592:     qemu_get_be32s(f, &s->do_cmd);
        !           593:     qemu_get_be32s(f, &s->dma_left);
1.1       root      594: 
                    595:     return 0;
                    596: }
                    597: 
1.1.1.5   root      598: void esp_scsi_attach(void *opaque, BlockDriverState *bd, int id)
                    599: {
                    600:     ESPState *s = (ESPState *)opaque;
                    601: 
                    602:     if (id < 0) {
                    603:         for (id = 0; id < ESP_MAX_DEVS; id++) {
                    604:             if (s->scsi_dev[id] == NULL)
                    605:                 break;
                    606:         }
                    607:     }
                    608:     if (id >= ESP_MAX_DEVS) {
                    609:         DPRINTF("Bad Device ID %d\n", id);
                    610:         return;
                    611:     }
                    612:     if (s->scsi_dev[id]) {
                    613:         DPRINTF("Destroying device %d\n", id);
1.1.1.6 ! root      614:         s->scsi_dev[id]->destroy(s->scsi_dev[id]);
1.1.1.5   root      615:     }
                    616:     DPRINTF("Attaching block device %d\n", id);
                    617:     /* Command queueing is not implemented.  */
1.1.1.6 ! root      618:     s->scsi_dev[id] = scsi_generic_init(bd, 0, esp_command_complete, s);
        !           619:     if (s->scsi_dev[id] == NULL)
        !           620:         s->scsi_dev[id] = scsi_disk_init(bd, 0, esp_command_complete, s);
1.1.1.5   root      621: }
                    622: 
1.1.1.6 ! root      623: void *esp_init(target_phys_addr_t espaddr,
        !           624:                void *dma_opaque, qemu_irq irq, qemu_irq *reset)
1.1       root      625: {
                    626:     ESPState *s;
1.1.1.5   root      627:     int esp_io_memory;
1.1       root      628: 
                    629:     s = qemu_mallocz(sizeof(ESPState));
                    630:     if (!s)
1.1.1.5   root      631:         return NULL;
1.1       root      632: 
1.1.1.6 ! root      633:     s->irq = irq;
1.1.1.5   root      634:     s->dma_opaque = dma_opaque;
1.1       root      635: 
                    636:     esp_io_memory = cpu_register_io_memory(0, esp_mem_read, esp_mem_write, s);
1.1.1.6 ! root      637:     cpu_register_physical_memory(espaddr, ESP_SIZE, esp_io_memory);
1.1       root      638: 
                    639:     esp_reset(s);
                    640: 
1.1.1.6 ! root      641:     register_savevm("esp", espaddr, 3, esp_save, esp_load, s);
1.1       root      642:     qemu_register_reset(esp_reset, s);
                    643: 
1.1.1.6 ! root      644:     *reset = *qemu_allocate_irqs(parent_esp_reset, s, 1);
        !           645: 
1.1.1.5   root      646:     return s;
                    647: }

unix.superglobalmegacorp.com