diff options
author | pbrook <pbrook@c046a42c-6fe2-441c-8c8c-71466251a162> | 2006-08-29 04:52:16 +0000 |
---|---|---|
committer | pbrook <pbrook@c046a42c-6fe2-441c-8c8c-71466251a162> | 2006-08-29 04:52:16 +0000 |
commit | a917d384ac0d09cd68266a6f2ca5c94212c8f81e (patch) | |
tree | f54b8fb2880361c0bf09087c3e382fc562193516 /hw/esp.c | |
parent | 508d92d0573319d7dbd827f6216aec44c1421832 (diff) |
SCSI TCQ support.
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2139 c046a42c-6fe2-441c-8c8c-71466251a162
Diffstat (limited to 'hw/esp.c')
-rw-r--r-- | hw/esp.c | 125 |
1 files changed, 71 insertions, 54 deletions
@@ -64,8 +64,7 @@ struct ESPState { int do_cmd; uint32_t dma_left; - uint8_t async_buf[TARGET_PAGE_SIZE]; - uint32_t async_ptr; + uint8_t *async_buf; uint32_t async_len; }; @@ -91,17 +90,16 @@ struct ESPState { static int get_cmd(ESPState *s, uint8_t *buf) { - uint32_t dmaptr, dmalen; + uint32_t dmalen; int target; dmalen = s->wregs[0] | (s->wregs[1] << 8); target = s->wregs[4] & 7; DPRINTF("get_cmd: len %d target %d\n", dmalen, target); if (s->dma) { - dmaptr = iommu_translate(s->espdmaregs[1]); DPRINTF("DMA Direction: %c, addr 0x%8.8x\n", - s->espdmaregs[0] & DMA_WRITE_MEM ? 'w': 'r', dmaptr); - cpu_physical_memory_read(dmaptr, buf, dmalen); + s->espdmaregs[0] & DMA_WRITE_MEM ? 'w': 'r', s->espdmaregs[1]); + sparc_iommu_memory_read(s->espdmaregs[1], buf, dmalen); } else { buf[0] = 0; memcpy(&buf[1], s->ti_buf, dmalen); @@ -112,6 +110,12 @@ static int get_cmd(ESPState *s, uint8_t *buf) s->ti_rptr = 0; s->ti_wptr = 0; + 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; + } + if (target >= 4 || !s->scsi_dev[target]) { // No such drive s->rregs[4] = STAT_IN; @@ -137,12 +141,15 @@ static void do_cmd(ESPState *s, uint8_t *buf) s->ti_size = 0; } else { s->rregs[4] = STAT_IN | STAT_TC; + s->dma_left = 0; if (datalen > 0) { s->rregs[4] |= STAT_DI; s->ti_size = datalen; + scsi_read_data(s->current_dev, 0); } else { s->rregs[4] |= STAT_DO; s->ti_size = -datalen; + scsi_write_data(s->current_dev, 0); } } s->rregs[5] = INTR_BS | INTR_FC; @@ -178,16 +185,13 @@ static void handle_satn_stop(ESPState *s) static void write_response(ESPState *s) { - uint32_t dmaptr; - DPRINTF("Transfer status (sense=%d)\n", s->sense); s->ti_buf[0] = s->sense; s->ti_buf[1] = 0; if (s->dma) { - dmaptr = iommu_translate(s->espdmaregs[1]); DPRINTF("DMA Direction: %c\n", s->espdmaregs[0] & DMA_WRITE_MEM ? 'w': 'r'); - cpu_physical_memory_write(dmaptr, s->ti_buf, 2); + sparc_iommu_memory_write(s->espdmaregs[1], s->ti_buf, 2); s->rregs[4] = STAT_IN | STAT_TC | STAT_ST; s->rregs[5] = INTR_BS | INTR_FC; s->rregs[6] = SEQ_CD; @@ -202,78 +206,89 @@ static void write_response(ESPState *s) } +static void esp_dma_done(ESPState *s) +{ + s->rregs[4] |= STAT_IN | STAT_TC; + s->rregs[5] = INTR_BS; + s->rregs[6] = 0; + s->rregs[7] = 0; + s->espdmaregs[0] |= DMA_INTR; + pic_set_irq(s->irq, 1); +} + static void esp_do_dma(ESPState *s) { - uint32_t dmaptr, minlen, len, from, to; + uint32_t addr, len; int to_device; + to_device = (s->espdmaregs[0] & DMA_WRITE_MEM) == 0; - from = s->espdmaregs[1]; - minlen = s->dma_left; - to = from + minlen; - dmaptr = iommu_translate(s->espdmaregs[1]); - if ((from & TARGET_PAGE_MASK) != (to & TARGET_PAGE_MASK)) { - len = TARGET_PAGE_SIZE - (from & ~TARGET_PAGE_MASK); - } else { - len = to - from; - } - DPRINTF("DMA address p %08x v %08x len %08x, from %08x, to %08x\n", dmaptr, s->espdmaregs[1], len, from, to); + addr = s->espdmaregs[1]; + len = s->dma_left; + DPRINTF("DMA address %08x len %08x\n", addr, len); if (s->do_cmd) { s->espdmaregs[1] += len; s->ti_size -= len; DPRINTF("command len %d + %d\n", s->cmdlen, len); - cpu_physical_memory_read(dmaptr, &s->cmdbuf[s->cmdlen], len); + sparc_iommu_memory_read(addr, &s->cmdbuf[s->cmdlen], len); s->ti_size = 0; s->cmdlen = 0; s->do_cmd = 0; do_cmd(s, s->cmdbuf); return; + } + if (s->async_len == 0) { + /* Defer until data is available. */ + return; + } + if (len > s->async_len) { + len = s->async_len; + } + if (to_device) { + sparc_iommu_memory_read(addr, s->async_buf, len); } else { - s->async_len = len; - s->dma_left -= len; + sparc_iommu_memory_write(addr, s->async_buf, len); + } + s->ti_size -= len; + s->dma_left -= len; + s->async_buf += len; + s->async_len -= len; + s->espdmaregs[1] += len; + if (s->async_len == 0) { if (to_device) { - s->async_ptr = -1; - cpu_physical_memory_read(dmaptr, s->async_buf, len); - scsi_write_data(s->current_dev, s->async_buf, len); + scsi_write_data(s->current_dev, 0); } else { - s->async_ptr = dmaptr; - scsi_read_data(s->current_dev, s->async_buf, len); + scsi_read_data(s->current_dev, 0); } } + if (s->dma_left == 0) { + esp_dma_done(s); + } } -static void esp_command_complete(void *opaque, uint32_t reason, int sense) +static void esp_command_complete(void *opaque, int reason, uint32_t tag, + uint32_t arg) { ESPState *s = (ESPState *)opaque; - s->ti_size -= s->async_len; - s->espdmaregs[1] += s->async_len; - if (s->async_ptr != (uint32_t)-1) { - cpu_physical_memory_write(s->async_ptr, s->async_buf, s->async_len); - } 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; - if (sense) + s->dma_left = 0; + s->async_len = 0; + if (arg) DPRINTF("Command failed\n"); - s->sense = sense; + s->sense = arg; + s->rregs[4] = STAT_ST; + esp_dma_done(s); + s->current_dev = NULL; } else { DPRINTF("transfer %d/%d\n", s->dma_left, s->ti_size); - } - if (s->dma_left) { - esp_do_dma(s); - } else { - if (s->ti_size) { - s->rregs[4] |= STAT_IN | STAT_TC; - } else { - s->rregs[4] = STAT_IN | STAT_TC | STAT_ST; - } - s->rregs[5] = INTR_BS; - s->rregs[6] = 0; - s->rregs[7] = 0; - s->espdmaregs[0] |= DMA_INTR; - pic_set_irq(s->irq, 1); + s->async_len = arg; + s->async_buf = scsi_get_buf(s->current_dev, 0); + if (s->dma_left) + esp_do_dma(s); } } @@ -333,7 +348,8 @@ static uint32_t esp_mem_readb(void *opaque, target_phys_addr_t addr) s->ti_size--; if ((s->rregs[4] & 6) == 0) { /* Data in/out. */ - scsi_read_data(s->current_dev, &s->rregs[2], 0); + fprintf(stderr, "esp: PIO data read not implemented\n"); + s->rregs[2] = 0; } else { s->rregs[2] = s->ti_buf[s->ti_rptr++]; } @@ -378,7 +394,7 @@ static void esp_mem_writeb(void *opaque, target_phys_addr_t addr, uint32_t val) uint8_t buf; buf = val & 0xff; s->ti_size--; - scsi_write_data(s->current_dev, &buf, 0); + fprintf(stderr, "esp: PIO data write not implemented\n"); } else { s->ti_size++; s->ti_buf[s->ti_wptr++] = val & 0xff; @@ -590,8 +606,9 @@ void esp_init(BlockDriverState **bd, int irq, uint32_t espaddr, uint32_t espdadd qemu_register_reset(esp_reset, s); for (i = 0; i < MAX_DISKS; i++) { if (bs_table[i]) { + /* Command queueing is not implemented. */ s->scsi_dev[i] = - scsi_disk_init(bs_table[i], esp_command_complete, s); + scsi_disk_init(bs_table[i], 0, esp_command_complete, s); } } } |