Commit 6787f5fae0fb9e3923b8c316780645c3e1d81df2
1 parent
b8174937
SPARC SCSI fixes.
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2158 c046a42c-6fe2-441c-8c8c-71466251a162
Showing
1 changed file
with
31 additions
and
8 deletions
hw/esp.c
| @@ -61,7 +61,11 @@ struct ESPState { | @@ -61,7 +61,11 @@ struct ESPState { | ||
| 61 | int cmdlen; | 61 | int cmdlen; |
| 62 | int do_cmd; | 62 | int do_cmd; |
| 63 | 63 | ||
| 64 | + /* The amount of data left in the current DMA transfer. */ | ||
| 64 | uint32_t dma_left; | 65 | uint32_t dma_left; |
| 66 | + /* The size of the current DMA transfer. Zero if no transfer is in | ||
| 67 | + progress. */ | ||
| 68 | + uint32_t dma_counter; | ||
| 65 | uint8_t *async_buf; | 69 | uint8_t *async_buf; |
| 66 | uint32_t async_len; | 70 | uint32_t async_len; |
| 67 | void *dma_opaque; | 71 | void *dma_opaque; |
| @@ -92,7 +96,7 @@ static int get_cmd(ESPState *s, uint8_t *buf) | @@ -92,7 +96,7 @@ static int get_cmd(ESPState *s, uint8_t *buf) | ||
| 92 | uint32_t dmalen; | 96 | uint32_t dmalen; |
| 93 | int target; | 97 | int target; |
| 94 | 98 | ||
| 95 | - dmalen = s->wregs[0] | (s->wregs[1] << 8); | 99 | + dmalen = s->rregs[0] | (s->rregs[1] << 8); |
| 96 | target = s->wregs[4] & 7; | 100 | target = s->wregs[4] & 7; |
| 97 | DPRINTF("get_cmd: len %d target %d\n", dmalen, target); | 101 | DPRINTF("get_cmd: len %d target %d\n", dmalen, target); |
| 98 | if (s->dma) { | 102 | if (s->dma) { |
| @@ -137,6 +141,7 @@ static void do_cmd(ESPState *s, uint8_t *buf) | @@ -137,6 +141,7 @@ static void do_cmd(ESPState *s, uint8_t *buf) | ||
| 137 | if (datalen != 0) { | 141 | if (datalen != 0) { |
| 138 | s->rregs[4] = STAT_IN | STAT_TC; | 142 | s->rregs[4] = STAT_IN | STAT_TC; |
| 139 | s->dma_left = 0; | 143 | s->dma_left = 0; |
| 144 | + s->dma_counter = 0; | ||
| 140 | if (datalen > 0) { | 145 | if (datalen > 0) { |
| 141 | s->rregs[4] |= STAT_DI; | 146 | s->rregs[4] |= STAT_DI; |
| 142 | scsi_read_data(s->current_dev, 0); | 147 | scsi_read_data(s->current_dev, 0); |
| @@ -198,6 +203,8 @@ static void esp_dma_done(ESPState *s) | @@ -198,6 +203,8 @@ static void esp_dma_done(ESPState *s) | ||
| 198 | s->rregs[5] = INTR_BS; | 203 | s->rregs[5] = INTR_BS; |
| 199 | s->rregs[6] = 0; | 204 | s->rregs[6] = 0; |
| 200 | s->rregs[7] = 0; | 205 | s->rregs[7] = 0; |
| 206 | + s->rregs[0] = 0; | ||
| 207 | + s->rregs[1] = 0; | ||
| 201 | espdma_raise_irq(s->dma_opaque); | 208 | espdma_raise_irq(s->dma_opaque); |
| 202 | } | 209 | } |
| 203 | 210 | ||
| @@ -232,17 +239,25 @@ static void esp_do_dma(ESPState *s) | @@ -232,17 +239,25 @@ static void esp_do_dma(ESPState *s) | ||
| 232 | s->dma_left -= len; | 239 | s->dma_left -= len; |
| 233 | s->async_buf += len; | 240 | s->async_buf += len; |
| 234 | s->async_len -= len; | 241 | s->async_len -= len; |
| 242 | + if (to_device) | ||
| 243 | + s->ti_size += len; | ||
| 244 | + else | ||
| 245 | + s->ti_size -= len; | ||
| 235 | if (s->async_len == 0) { | 246 | if (s->async_len == 0) { |
| 236 | if (to_device) { | 247 | if (to_device) { |
| 237 | // ti_size is negative | 248 | // ti_size is negative |
| 238 | - s->ti_size += len; | ||
| 239 | scsi_write_data(s->current_dev, 0); | 249 | scsi_write_data(s->current_dev, 0); |
| 240 | } else { | 250 | } else { |
| 241 | - s->ti_size -= len; | ||
| 242 | scsi_read_data(s->current_dev, 0); | 251 | scsi_read_data(s->current_dev, 0); |
| 252 | + /* If there is still data to be read from the device then | ||
| 253 | + complete the DMA operation immeriately. Otherwise defer | ||
| 254 | + until the scsi layer has completed. */ | ||
| 255 | + if (s->dma_left == 0 && s->ti_size > 0) { | ||
| 256 | + esp_dma_done(s); | ||
| 257 | + } | ||
| 243 | } | 258 | } |
| 244 | - } | ||
| 245 | - if (s->dma_left == 0) { | 259 | + } else { |
| 260 | + /* Partially filled a scsi buffer. Complete immediately. */ | ||
| 246 | esp_dma_done(s); | 261 | esp_dma_done(s); |
| 247 | } | 262 | } |
| 248 | } | 263 | } |
| @@ -269,8 +284,13 @@ static void esp_command_complete(void *opaque, int reason, uint32_t tag, | @@ -269,8 +284,13 @@ static void esp_command_complete(void *opaque, int reason, uint32_t tag, | ||
| 269 | DPRINTF("transfer %d/%d\n", s->dma_left, s->ti_size); | 284 | DPRINTF("transfer %d/%d\n", s->dma_left, s->ti_size); |
| 270 | s->async_len = arg; | 285 | s->async_len = arg; |
| 271 | s->async_buf = scsi_get_buf(s->current_dev, 0); | 286 | s->async_buf = scsi_get_buf(s->current_dev, 0); |
| 272 | - if (s->dma_left) | 287 | + if (s->dma_left) { |
| 273 | esp_do_dma(s); | 288 | esp_do_dma(s); |
| 289 | + } else if (s->dma_counter != 0 && s->ti_size <= 0) { | ||
| 290 | + /* If this was the last part of a DMA transfer then the | ||
| 291 | + completion interrupt is deferred to here. */ | ||
| 292 | + esp_dma_done(s); | ||
| 293 | + } | ||
| 274 | } | 294 | } |
| 275 | } | 295 | } |
| 276 | 296 | ||
| @@ -278,10 +298,11 @@ static void handle_ti(ESPState *s) | @@ -278,10 +298,11 @@ static void handle_ti(ESPState *s) | ||
| 278 | { | 298 | { |
| 279 | uint32_t dmalen, minlen; | 299 | uint32_t dmalen, minlen; |
| 280 | 300 | ||
| 281 | - dmalen = s->wregs[0] | (s->wregs[1] << 8); | 301 | + dmalen = s->rregs[0] | (s->rregs[1] << 8); |
| 282 | if (dmalen==0) { | 302 | if (dmalen==0) { |
| 283 | dmalen=0x10000; | 303 | dmalen=0x10000; |
| 284 | } | 304 | } |
| 305 | + s->dma_counter = dmalen; | ||
| 285 | 306 | ||
| 286 | if (s->do_cmd) | 307 | if (s->do_cmd) |
| 287 | minlen = (dmalen < 32) ? dmalen : 32; | 308 | minlen = (dmalen < 32) ? dmalen : 32; |
| @@ -366,7 +387,6 @@ static void esp_mem_writeb(void *opaque, target_phys_addr_t addr, uint32_t val) | @@ -366,7 +387,6 @@ static void esp_mem_writeb(void *opaque, target_phys_addr_t addr, uint32_t val) | ||
| 366 | switch (saddr) { | 387 | switch (saddr) { |
| 367 | case 0: | 388 | case 0: |
| 368 | case 1: | 389 | case 1: |
| 369 | - s->rregs[saddr] = val; | ||
| 370 | s->rregs[4] &= ~STAT_TC; | 390 | s->rregs[4] &= ~STAT_TC; |
| 371 | break; | 391 | break; |
| 372 | case 2: | 392 | case 2: |
| @@ -388,6 +408,9 @@ static void esp_mem_writeb(void *opaque, target_phys_addr_t addr, uint32_t val) | @@ -388,6 +408,9 @@ static void esp_mem_writeb(void *opaque, target_phys_addr_t addr, uint32_t val) | ||
| 388 | // Command | 408 | // Command |
| 389 | if (val & 0x80) { | 409 | if (val & 0x80) { |
| 390 | s->dma = 1; | 410 | s->dma = 1; |
| 411 | + /* Reload DMA counter. */ | ||
| 412 | + s->rregs[0] = s->wregs[0]; | ||
| 413 | + s->rregs[1] = s->wregs[1]; | ||
| 391 | } else { | 414 | } else { |
| 392 | s->dma = 0; | 415 | s->dma = 0; |
| 393 | } | 416 | } |