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 | 61 | int cmdlen; |
62 | 62 | int do_cmd; |
63 | 63 | |
64 | + /* The amount of data left in the current DMA transfer. */ | |
64 | 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 | 69 | uint8_t *async_buf; |
66 | 70 | uint32_t async_len; |
67 | 71 | void *dma_opaque; |
... | ... | @@ -92,7 +96,7 @@ static int get_cmd(ESPState *s, uint8_t *buf) |
92 | 96 | uint32_t dmalen; |
93 | 97 | int target; |
94 | 98 | |
95 | - dmalen = s->wregs[0] | (s->wregs[1] << 8); | |
99 | + dmalen = s->rregs[0] | (s->rregs[1] << 8); | |
96 | 100 | target = s->wregs[4] & 7; |
97 | 101 | DPRINTF("get_cmd: len %d target %d\n", dmalen, target); |
98 | 102 | if (s->dma) { |
... | ... | @@ -137,6 +141,7 @@ static void do_cmd(ESPState *s, uint8_t *buf) |
137 | 141 | if (datalen != 0) { |
138 | 142 | s->rregs[4] = STAT_IN | STAT_TC; |
139 | 143 | s->dma_left = 0; |
144 | + s->dma_counter = 0; | |
140 | 145 | if (datalen > 0) { |
141 | 146 | s->rregs[4] |= STAT_DI; |
142 | 147 | scsi_read_data(s->current_dev, 0); |
... | ... | @@ -198,6 +203,8 @@ static void esp_dma_done(ESPState *s) |
198 | 203 | s->rregs[5] = INTR_BS; |
199 | 204 | s->rregs[6] = 0; |
200 | 205 | s->rregs[7] = 0; |
206 | + s->rregs[0] = 0; | |
207 | + s->rregs[1] = 0; | |
201 | 208 | espdma_raise_irq(s->dma_opaque); |
202 | 209 | } |
203 | 210 | |
... | ... | @@ -232,17 +239,25 @@ static void esp_do_dma(ESPState *s) |
232 | 239 | s->dma_left -= len; |
233 | 240 | s->async_buf += len; |
234 | 241 | s->async_len -= len; |
242 | + if (to_device) | |
243 | + s->ti_size += len; | |
244 | + else | |
245 | + s->ti_size -= len; | |
235 | 246 | if (s->async_len == 0) { |
236 | 247 | if (to_device) { |
237 | 248 | // ti_size is negative |
238 | - s->ti_size += len; | |
239 | 249 | scsi_write_data(s->current_dev, 0); |
240 | 250 | } else { |
241 | - s->ti_size -= len; | |
242 | 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 | 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 | 284 | DPRINTF("transfer %d/%d\n", s->dma_left, s->ti_size); |
270 | 285 | s->async_len = arg; |
271 | 286 | s->async_buf = scsi_get_buf(s->current_dev, 0); |
272 | - if (s->dma_left) | |
287 | + if (s->dma_left) { | |
273 | 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 | 298 | { |
279 | 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 | 302 | if (dmalen==0) { |
283 | 303 | dmalen=0x10000; |
284 | 304 | } |
305 | + s->dma_counter = dmalen; | |
285 | 306 | |
286 | 307 | if (s->do_cmd) |
287 | 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 | 387 | switch (saddr) { |
367 | 388 | case 0: |
368 | 389 | case 1: |
369 | - s->rregs[saddr] = val; | |
370 | 390 | s->rregs[4] &= ~STAT_TC; |
371 | 391 | break; |
372 | 392 | case 2: |
... | ... | @@ -388,6 +408,9 @@ static void esp_mem_writeb(void *opaque, target_phys_addr_t addr, uint32_t val) |
388 | 408 | // Command |
389 | 409 | if (val & 0x80) { |
390 | 410 | s->dma = 1; |
411 | + /* Reload DMA counter. */ | |
412 | + s->rregs[0] = s->wregs[0]; | |
413 | + s->rregs[1] = s->wregs[1]; | |
391 | 414 | } else { |
392 | 415 | s->dma = 0; |
393 | 416 | } | ... | ... |