Commit 6787f5fae0fb9e3923b8c316780645c3e1d81df2

Authored by pbrook
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 }
... ...