[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[PULL 09/45] esp: handle non-DMA transfers from the target one byte at a
From: |
Paolo Bonzini |
Subject: |
[PULL 09/45] esp: handle non-DMA transfers from the target one byte at a time |
Date: |
Thu, 17 Jun 2021 11:30:58 +0200 |
From: Mark Cave-Ayland <mark.cave-ayland@ilande.co.uk>
The initial implementation of non-DMA transfers was based upon analysis of
traces
from the MacOS toolbox ROM for handling unaligned reads but missed one key
aspect - during a non-DMA transfer from the target, the bus service interrupt
should be raised for every single byte received from the bus and not just at
either
the end of the transfer or when the FIFO is full.
Adjust the non-DMA code accordingly so that esp_do_nodma() is called for every
byte
received from the target. This also includes special handling for managing the
change
from DATA IN to STATUS phase as this needs to occur when the final byte is read
out
from the FIFO, and not at the end of the transfer of the last byte into the
FIFO.
Signed-off-by: Mark Cave-Ayland <mark.cave-ayland@ilande.co.uk>
Message-Id: <20210519100803.10293-3-mark.cave-ayland@ilande.co.uk>
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
---
hw/scsi/esp.c | 72 +++++++++++++++++++++++++++++++++++----------------
1 file changed, 50 insertions(+), 22 deletions(-)
diff --git a/hw/scsi/esp.c b/hw/scsi/esp.c
index 50757e9264..a0dab319f2 100644
--- a/hw/scsi/esp.c
+++ b/hw/scsi/esp.c
@@ -739,20 +739,17 @@ static void esp_do_nodma(ESPState *s)
s->async_len -= len;
s->ti_size += len;
} else {
- len = MIN(s->ti_size, s->async_len);
- len = MIN(len, fifo8_num_free(&s->fifo));
- fifo8_push_all(&s->fifo, s->async_buf, len);
- s->async_buf += len;
- s->async_len -= len;
- s->ti_size -= len;
+ if (fifo8_is_empty(&s->fifo)) {
+ fifo8_push(&s->fifo, s->async_buf[0]);
+ s->async_buf++;
+ s->async_len--;
+ s->ti_size--;
+ }
}
if (s->async_len == 0) {
scsi_req_continue(s->current_req);
-
- if (to_device || s->ti_size == 0) {
- return;
- }
+ return;
}
s->rregs[ESP_RINTR] |= INTR_BS;
@@ -762,20 +759,37 @@ static void esp_do_nodma(ESPState *s)
void esp_command_complete(SCSIRequest *req, size_t resid)
{
ESPState *s = req->hba_private;
+ int to_device = ((s->rregs[ESP_RSTAT] & 7) == STAT_DO);
trace_esp_command_complete();
- if (s->ti_size != 0) {
- trace_esp_command_complete_unexpected();
+
+ /*
+ * Non-DMA transfers from the target will leave the last byte in
+ * the FIFO so don't reset ti_size in this case
+ */
+ if (s->dma || to_device) {
+ if (s->ti_size != 0) {
+ trace_esp_command_complete_unexpected();
+ }
+ s->ti_size = 0;
}
- s->ti_size = 0;
+
s->async_len = 0;
if (req->status) {
trace_esp_command_complete_fail();
}
s->status = req->status;
- s->rregs[ESP_RSTAT] = STAT_ST;
- esp_dma_done(s);
- esp_lower_drq(s);
+
+ /*
+ * If the transfer is finished, switch to status phase. For non-DMA
+ * transfers from the target the last byte is still in the FIFO
+ */
+ if (s->ti_size == 0) {
+ s->rregs[ESP_RSTAT] = STAT_TC | STAT_ST;
+ esp_dma_done(s);
+ esp_lower_drq(s);
+ }
+
if (s->current_req) {
scsi_req_unref(s->current_req);
s->current_req = NULL;
@@ -894,6 +908,17 @@ uint64_t esp_reg_read(ESPState *s, uint32_t saddr)
qemu_log_mask(LOG_UNIMP, "esp: PIO data read not implemented\n");
s->rregs[ESP_FIFO] = 0;
} else {
+ if ((s->rregs[ESP_RSTAT] & 0x7) == STAT_DI) {
+ if (s->ti_size) {
+ esp_do_nodma(s);
+ } else {
+ /*
+ * The last byte of a non-DMA transfer has been read out
+ * of the FIFO so switch to status phase
+ */
+ s->rregs[ESP_RSTAT] = STAT_TC | STAT_ST;
+ }
+ }
s->rregs[ESP_FIFO] = esp_fifo_pop(&s->fifo);
}
val = s->rregs[ESP_FIFO];
@@ -952,15 +977,18 @@ void esp_reg_write(ESPState *s, uint32_t saddr, uint64_t
val)
case ESP_FIFO:
if (s->do_cmd) {
esp_fifo_push(&s->cmdfifo, val);
+
+ /*
+ * If any unexpected message out/command phase data is
+ * transferred using non-DMA, raise the interrupt
+ */
+ if (s->rregs[ESP_CMD] == CMD_TI) {
+ s->rregs[ESP_RINTR] |= INTR_BS;
+ esp_raise_irq(s);
+ }
} else {
esp_fifo_push(&s->fifo, val);
}
-
- /* Non-DMA transfers raise an interrupt after every byte */
- if (s->rregs[ESP_CMD] == CMD_TI) {
- s->rregs[ESP_RINTR] |= INTR_FC | INTR_BS;
- esp_raise_irq(s);
- }
break;
case ESP_CMD:
s->rregs[saddr] = val;
--
2.31.1
- [PULL 03/45] qemu-config: use qemu_opts_from_qdict, (continued)
- [PULL 03/45] qemu-config: use qemu_opts_from_qdict, Paolo Bonzini, 2021/06/17
- [PULL 08/45] esp: allow non-DMA callback in esp_transfer_data() initial transfer, Paolo Bonzini, 2021/06/17
- [PULL 05/45] runstate: Initialize Error * to NULL, Paolo Bonzini, 2021/06/17
- [PULL 06/45] esp: only assert INTR_DC interrupt flag if selection fails, Paolo Bonzini, 2021/06/17
- [PULL 07/45] esp: only set ESP_RSEQ at the start of the select sequence, Paolo Bonzini, 2021/06/17
- [PULL 11/45] esp: revert 75ef849696 "esp: correctly fill bus id with requested lun", Paolo Bonzini, 2021/06/17
- [PULL 14/45] esp: store lun coming from the MESSAGE OUT phase, Paolo Bonzini, 2021/06/17
- [PULL 15/45] softmmu/physmem: Mark shared anonymous memory RAM_SHARED, Paolo Bonzini, 2021/06/17
- [PULL 16/45] softmmu/physmem: Fix ram_block_discard_range() to handle shared anonymous memory, Paolo Bonzini, 2021/06/17
- [PULL 18/45] util/mmap-alloc: Factor out calculation of the pagesize for the guard page, Paolo Bonzini, 2021/06/17
- [PULL 09/45] esp: handle non-DMA transfers from the target one byte at a time,
Paolo Bonzini <=
- [PULL 10/45] esp: ensure PDMA write transfers are flushed from the FIFO to the target immediately, Paolo Bonzini, 2021/06/17
- [PULL 13/45] esp: fix migration version check in esp_is_version_5(), Paolo Bonzini, 2021/06/17
- [PULL 12/45] esp: correctly accumulate extended messages for PDMA, Paolo Bonzini, 2021/06/17
- [PULL 17/45] softmmu/physmem: Fix qemu_ram_remap() to handle shared anonymous memory, Paolo Bonzini, 2021/06/17
- [PULL 19/45] util/mmap-alloc: Factor out reserving of a memory region to mmap_reserve(), Paolo Bonzini, 2021/06/17
- [PULL 20/45] util/mmap-alloc: Factor out activating of memory to mmap_activate(), Paolo Bonzini, 2021/06/17
- [PULL 22/45] softmmu/memory: Pass ram_flags to memory_region_init_ram_shared_nomigrate(), Paolo Bonzini, 2021/06/17
- [PULL 26/45] util/mmap-alloc: Support RAM_NORESERVE via MAP_NORESERVE under Linux, Paolo Bonzini, 2021/06/17
- [PULL 23/45] softmmu/memory: Pass ram_flags to qemu_ram_alloc() and qemu_ram_alloc_internal(), Paolo Bonzini, 2021/06/17
- [PULL 29/45] qmp: Include "share" property of memory backends, Paolo Bonzini, 2021/06/17