@@ -387,6 +387,15 @@ static void handle_satn_stop(ESPState *s)
}
}
+static void handle_pad(ESPState *s)
+{
+ if (s->dma) {
+ esp_do_dma(s);
+ } else {
+ esp_do_nodma(s);
+ }
+}
+
static void write_response(ESPState *s)
{
trace_esp_write_response(s->status);
@@ -518,20 +527,38 @@ static void esp_do_dma(ESPState *s)
len = s->async_len;
}
- if (s->dma_memory_read) {
- s->dma_memory_read(s->dma_opaque, s->async_buf, len);
- esp_set_tc(s, esp_get_tc(s) - len);
- } else {
- /* Copy FIFO data to device */
- len = MIN(s->async_len, ESP_FIFO_SZ);
- len = MIN(len, fifo8_num_used(&s->fifo));
- len = esp_fifo_pop_buf(&s->fifo, s->async_buf, len);
- esp_raise_drq(s);
- }
+ switch (s->rregs[ESP_CMD]) {
+ case CMD_TI | CMD_DMA:
+ if (s->dma_memory_read) {
+ s->dma_memory_read(s->dma_opaque, s->async_buf, len);
+ esp_set_tc(s, esp_get_tc(s) - len);
+ } else {
+ /* Copy FIFO data to device */
+ len = MIN(s->async_len, ESP_FIFO_SZ);
+ len = MIN(len, fifo8_num_used(&s->fifo));
+ len = esp_fifo_pop_buf(&s->fifo, s->async_buf, len);
+ esp_raise_drq(s);
+ }
- s->async_buf += len;
- s->async_len -= len;
- s->ti_size += len;
+ s->async_buf += len;
+ s->async_len -= len;
+ s->ti_size += len;
+ break;
+
+ case CMD_PAD | CMD_DMA:
+ /* Copy TC zero bytes into the incoming stream */
+ if (!s->dma_memory_read) {
+ len = MIN(s->async_len, ESP_FIFO_SZ);
+ len = MIN(len, fifo8_num_free(&s->fifo));
+ }
+
+ memset(s->async_buf, 0, len);
+
+ s->async_buf += len;
+ s->async_len -= len;
+ s->ti_size += len;
+ break;
+ }
if (s->async_len == 0 && fifo8_num_used(&s->fifo) < 2) {
/* Defer until the scsi layer has completed */
@@ -554,19 +581,35 @@ static void esp_do_dma(ESPState *s)
len = s->async_len;
}
- if (s->dma_memory_write) {
- s->dma_memory_write(s->dma_opaque, s->async_buf, len);
- } else {
- /* Copy device data to FIFO */
- len = MIN(len, fifo8_num_free(&s->fifo));
- fifo8_push_all(&s->fifo, s->async_buf, len);
- esp_raise_drq(s);
- }
+ switch (s->rregs[ESP_CMD]) {
+ case CMD_TI | CMD_DMA:
+ if (s->dma_memory_write) {
+ s->dma_memory_write(s->dma_opaque, s->async_buf, len);
+ } else {
+ /* Copy device data to FIFO */
+ len = MIN(len, fifo8_num_free(&s->fifo));
+ fifo8_push_all(&s->fifo, s->async_buf, len);
+ esp_raise_drq(s);
+ }
+
+ s->async_buf += len;
+ s->async_len -= len;
+ s->ti_size -= len;
+ esp_set_tc(s, esp_get_tc(s) - len);
+ break;
+
+ case CMD_PAD | CMD_DMA:
+ /* Drop TC bytes from the incoming stream */
+ if (!s->dma_memory_write) {
+ len = MIN(len, fifo8_num_free(&s->fifo));
+ }
- s->async_buf += len;
- s->async_len -= len;
- s->ti_size -= len;
- esp_set_tc(s, esp_get_tc(s) - len);
+ s->async_buf += len;
+ s->async_len -= len;
+ s->ti_size -= len;
+ esp_set_tc(s, esp_get_tc(s) - len);
+ break;
+ }
if (s->async_len == 0 && s->ti_size == 0 && esp_get_tc(s)) {
/* If the guest underflows TC then terminate SCSI request */
@@ -1087,9 +1130,7 @@ static void esp_run_cmd(ESPState *s)
break;
case CMD_PAD:
trace_esp_mem_writeb_cmd_pad(cmd);
- s->rregs[ESP_RSTAT] = STAT_TC;
- s->rregs[ESP_RINTR] |= INTR_FC;
- s->rregs[ESP_RSEQ] = 0;
+ handle_pad(s);
break;
case CMD_SATN:
trace_esp_mem_writeb_cmd_satn(cmd);