SPARC SCSI fixes.
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2158 c046a42c-6fe2-441c-8c8c-71466251a162
This commit is contained in:
parent
b8174937ed
commit
6787f5fae0
39
hw/esp.c
39
hw/esp.c
|
@ -61,7 +61,11 @@ struct ESPState {
|
||||||
int cmdlen;
|
int cmdlen;
|
||||||
int do_cmd;
|
int do_cmd;
|
||||||
|
|
||||||
|
/* The amount of data left in the current DMA transfer. */
|
||||||
uint32_t dma_left;
|
uint32_t dma_left;
|
||||||
|
/* The size of the current DMA transfer. Zero if no transfer is in
|
||||||
|
progress. */
|
||||||
|
uint32_t dma_counter;
|
||||||
uint8_t *async_buf;
|
uint8_t *async_buf;
|
||||||
uint32_t async_len;
|
uint32_t async_len;
|
||||||
void *dma_opaque;
|
void *dma_opaque;
|
||||||
|
@ -92,7 +96,7 @@ static int get_cmd(ESPState *s, uint8_t *buf)
|
||||||
uint32_t dmalen;
|
uint32_t dmalen;
|
||||||
int target;
|
int target;
|
||||||
|
|
||||||
dmalen = s->wregs[0] | (s->wregs[1] << 8);
|
dmalen = s->rregs[0] | (s->rregs[1] << 8);
|
||||||
target = s->wregs[4] & 7;
|
target = s->wregs[4] & 7;
|
||||||
DPRINTF("get_cmd: len %d target %d\n", dmalen, target);
|
DPRINTF("get_cmd: len %d target %d\n", dmalen, target);
|
||||||
if (s->dma) {
|
if (s->dma) {
|
||||||
|
@ -137,6 +141,7 @@ static void do_cmd(ESPState *s, uint8_t *buf)
|
||||||
if (datalen != 0) {
|
if (datalen != 0) {
|
||||||
s->rregs[4] = STAT_IN | STAT_TC;
|
s->rregs[4] = STAT_IN | STAT_TC;
|
||||||
s->dma_left = 0;
|
s->dma_left = 0;
|
||||||
|
s->dma_counter = 0;
|
||||||
if (datalen > 0) {
|
if (datalen > 0) {
|
||||||
s->rregs[4] |= STAT_DI;
|
s->rregs[4] |= STAT_DI;
|
||||||
scsi_read_data(s->current_dev, 0);
|
scsi_read_data(s->current_dev, 0);
|
||||||
|
@ -198,6 +203,8 @@ static void esp_dma_done(ESPState *s)
|
||||||
s->rregs[5] = INTR_BS;
|
s->rregs[5] = INTR_BS;
|
||||||
s->rregs[6] = 0;
|
s->rregs[6] = 0;
|
||||||
s->rregs[7] = 0;
|
s->rregs[7] = 0;
|
||||||
|
s->rregs[0] = 0;
|
||||||
|
s->rregs[1] = 0;
|
||||||
espdma_raise_irq(s->dma_opaque);
|
espdma_raise_irq(s->dma_opaque);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -232,17 +239,25 @@ static void esp_do_dma(ESPState *s)
|
||||||
s->dma_left -= len;
|
s->dma_left -= len;
|
||||||
s->async_buf += len;
|
s->async_buf += len;
|
||||||
s->async_len -= len;
|
s->async_len -= len;
|
||||||
|
if (to_device)
|
||||||
|
s->ti_size += len;
|
||||||
|
else
|
||||||
|
s->ti_size -= len;
|
||||||
if (s->async_len == 0) {
|
if (s->async_len == 0) {
|
||||||
if (to_device) {
|
if (to_device) {
|
||||||
// ti_size is negative
|
// ti_size is negative
|
||||||
s->ti_size += len;
|
|
||||||
scsi_write_data(s->current_dev, 0);
|
scsi_write_data(s->current_dev, 0);
|
||||||
} else {
|
} else {
|
||||||
s->ti_size -= len;
|
|
||||||
scsi_read_data(s->current_dev, 0);
|
scsi_read_data(s->current_dev, 0);
|
||||||
|
/* 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);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
} else {
|
||||||
if (s->dma_left == 0) {
|
/* Partially filled a scsi buffer. Complete immediately. */
|
||||||
esp_dma_done(s);
|
esp_dma_done(s);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -269,8 +284,13 @@ static void esp_command_complete(void *opaque, int reason, uint32_t tag,
|
||||||
DPRINTF("transfer %d/%d\n", s->dma_left, s->ti_size);
|
DPRINTF("transfer %d/%d\n", s->dma_left, s->ti_size);
|
||||||
s->async_len = arg;
|
s->async_len = arg;
|
||||||
s->async_buf = scsi_get_buf(s->current_dev, 0);
|
s->async_buf = scsi_get_buf(s->current_dev, 0);
|
||||||
if (s->dma_left)
|
if (s->dma_left) {
|
||||||
esp_do_dma(s);
|
esp_do_dma(s);
|
||||||
|
} 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);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -278,10 +298,11 @@ static void handle_ti(ESPState *s)
|
||||||
{
|
{
|
||||||
uint32_t dmalen, minlen;
|
uint32_t dmalen, minlen;
|
||||||
|
|
||||||
dmalen = s->wregs[0] | (s->wregs[1] << 8);
|
dmalen = s->rregs[0] | (s->rregs[1] << 8);
|
||||||
if (dmalen==0) {
|
if (dmalen==0) {
|
||||||
dmalen=0x10000;
|
dmalen=0x10000;
|
||||||
}
|
}
|
||||||
|
s->dma_counter = dmalen;
|
||||||
|
|
||||||
if (s->do_cmd)
|
if (s->do_cmd)
|
||||||
minlen = (dmalen < 32) ? dmalen : 32;
|
minlen = (dmalen < 32) ? dmalen : 32;
|
||||||
|
@ -366,7 +387,6 @@ static void esp_mem_writeb(void *opaque, target_phys_addr_t addr, uint32_t val)
|
||||||
switch (saddr) {
|
switch (saddr) {
|
||||||
case 0:
|
case 0:
|
||||||
case 1:
|
case 1:
|
||||||
s->rregs[saddr] = val;
|
|
||||||
s->rregs[4] &= ~STAT_TC;
|
s->rregs[4] &= ~STAT_TC;
|
||||||
break;
|
break;
|
||||||
case 2:
|
case 2:
|
||||||
|
@ -388,6 +408,9 @@ static void esp_mem_writeb(void *opaque, target_phys_addr_t addr, uint32_t val)
|
||||||
// Command
|
// Command
|
||||||
if (val & 0x80) {
|
if (val & 0x80) {
|
||||||
s->dma = 1;
|
s->dma = 1;
|
||||||
|
/* Reload DMA counter. */
|
||||||
|
s->rregs[0] = s->wregs[0];
|
||||||
|
s->rregs[1] = s->wregs[1];
|
||||||
} else {
|
} else {
|
||||||
s->dma = 0;
|
s->dma = 0;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue