summaryrefslogtreecommitdiff
path: root/hw/esp.c
diff options
context:
space:
mode:
authorpbrook <pbrook@c046a42c-6fe2-441c-8c8c-71466251a162>2006-06-03 14:19:19 +0000
committerpbrook <pbrook@c046a42c-6fe2-441c-8c8c-71466251a162>2006-06-03 14:19:19 +0000
commit9f149aa9c1a04117d03de16bb0f8d2dad8c4f8c1 (patch)
tree22ad2ff74ae238a0e94ca4569a639b24f683528a /hw/esp.c
parent7d8406be69ce936839300159fcf2a0c4863f7f08 (diff)
downloadqemu-9f149aa9c1a04117d03de16bb0f8d2dad8c4f8c1.tar.gz
SATN fixes (Blue Swirl).
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1947 c046a42c-6fe2-441c-8c8c-71466251a162
Diffstat (limited to 'hw/esp.c')
-rw-r--r--hw/esp.c93
1 files changed, 75 insertions, 18 deletions
diff --git a/hw/esp.c b/hw/esp.c
index 908767943d..cdd062f789 100644
--- a/hw/esp.c
+++ b/hw/esp.c
@@ -59,6 +59,9 @@ struct ESPState {
int dma;
SCSIDevice *scsi_dev[MAX_DISKS];
SCSIDevice *current_dev;
+ uint8_t cmdbuf[TI_BUFSZ];
+ int cmdlen;
+ int do_cmd;
};
#define STAT_DO 0x00
@@ -79,17 +82,14 @@ struct ESPState {
#define SEQ_0 0x0
#define SEQ_CD 0x4
-static void handle_satn(ESPState *s)
+static int get_cmd(ESPState *s, uint8_t *buf)
{
- uint8_t buf[32];
uint32_t dmaptr, dmalen;
int target;
- int32_t datalen;
- int lun;
dmalen = s->wregs[0] | (s->wregs[1] << 8);
target = s->wregs[4] & 7;
- DPRINTF("Select with ATN len %d target %d\n", dmalen, target);
+ 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",
@@ -100,8 +100,6 @@ static void handle_satn(ESPState *s)
memcpy(&buf[1], s->ti_buf, dmalen);
dmalen++;
}
- DPRINTF("busid 0x%x\n", buf[0]);
- lun = buf[0] & 7;
s->ti_size = 0;
s->ti_rptr = 0;
@@ -114,9 +112,19 @@ static void handle_satn(ESPState *s)
s->rregs[6] = SEQ_0;
s->espdmaregs[0] |= DMA_INTR;
pic_set_irq(s->irq, 1);
- return;
+ return 0;
}
s->current_dev = s->scsi_dev[target];
+ 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;
datalen = scsi_send_command(s->current_dev, 0, &buf[1], lun);
if (datalen == 0) {
s->ti_size = 0;
@@ -136,6 +144,31 @@ static void handle_satn(ESPState *s)
pic_set_irq(s->irq, 1);
}
+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;
+ s->espdmaregs[1] += s->cmdlen;
+ s->rregs[4] = STAT_IN | STAT_TC | STAT_CD;
+ s->rregs[5] = INTR_BS | INTR_FC;
+ s->rregs[6] = SEQ_CD;
+ s->espdmaregs[0] |= DMA_INTR;
+ pic_set_irq(s->irq, 1);
+ }
+}
+
static void write_response(ESPState *s)
{
uint32_t dmaptr;
@@ -188,7 +221,10 @@ static void handle_ti(ESPState *s)
dmalen=0x10000;
}
- minlen = (dmalen < s->ti_size) ? dmalen : s->ti_size;
+ if (s->do_cmd)
+ minlen = (dmalen < 32) ? dmalen : 32;
+ else
+ minlen = (dmalen < s->ti_size) ? dmalen : s->ti_size;
DPRINTF("Transfer Information len %d\n", minlen);
if (s->dma) {
dmaptr = iommu_translate(s->espdmaregs[1]);
@@ -207,14 +243,24 @@ static void handle_ti(ESPState *s)
}
DPRINTF("DMA address p %08x v %08x len %08x, from %08x, to %08x\n", dmaptr, s->espdmaregs[1] + i, len, from, to);
s->ti_size -= len;
- if (to_device) {
- cpu_physical_memory_read(dmaptr, buf, len);
- scsi_write_data(s->current_dev, buf, len);
+ if (s->do_cmd) {
+ DPRINTF("command len %d + %d\n", s->cmdlen, len);
+ cpu_physical_memory_read(dmaptr, &s->cmdbuf[s->cmdlen], len);
+ s->ti_size = 0;
+ s->cmdlen = 0;
+ s->do_cmd = 0;
+ do_cmd(s, s->cmdbuf);
+ return;
} else {
- scsi_read_data(s->current_dev, buf, len);
- cpu_physical_memory_write(dmaptr, buf, len);
+ if (to_device) {
+ cpu_physical_memory_read(dmaptr, buf, len);
+ scsi_write_data(s->current_dev, buf, len);
+ } else {
+ scsi_read_data(s->current_dev, buf, len);
+ cpu_physical_memory_write(dmaptr, buf, len);
+ }
}
- }
+ }
if (s->ti_size) {
s->rregs[4] = STAT_IN | STAT_TC | (to_device ? STAT_DO : STAT_DI);
}
@@ -222,7 +268,14 @@ static void handle_ti(ESPState *s)
s->rregs[6] = 0;
s->rregs[7] = 0;
s->espdmaregs[0] |= DMA_INTR;
- }
+ } 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;
+ }
pic_set_irq(s->irq, 1);
}
@@ -237,6 +290,7 @@ static void esp_reset(void *opaque)
s->ti_rptr = 0;
s->ti_wptr = 0;
s->dma = 0;
+ s->do_cmd = 0;
}
static uint32_t esp_mem_readb(void *opaque, target_phys_addr_t addr)
@@ -291,7 +345,9 @@ static void esp_mem_writeb(void *opaque, target_phys_addr_t addr, uint32_t val)
break;
case 2:
// FIFO
- if ((s->rregs[4] & 6) == 0) {
+ if (s->do_cmd) {
+ s->cmdbuf[s->cmdlen++] = val & 0xff;
+ } else if ((s->rregs[4] & 6) == 0) {
uint8_t buf;
buf = val & 0xff;
s->ti_size--;
@@ -348,11 +404,12 @@ static void esp_mem_writeb(void *opaque, target_phys_addr_t addr, uint32_t val)
DPRINTF("Set ATN (%2.2x)\n", val);
break;
case 0x42:
+ DPRINTF("Set ATN (%2.2x)\n", val);
handle_satn(s);
break;
case 0x43:
DPRINTF("Set ATN & stop (%2.2x)\n", val);
- handle_satn(s);
+ handle_satn_stop(s);
break;
default:
DPRINTF("Unhandled ESP command (%2.2x)\n", val);