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,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 }