aboutsummaryrefslogtreecommitdiff
path: root/hw/scsi/esp.c
diff options
context:
space:
mode:
authorMark Cave-Ayland <mark.cave-ayland@ilande.co.uk>2024-01-12 12:54:16 +0000
committerMark Cave-Ayland <mark.cave-ayland@ilande.co.uk>2024-02-13 19:37:28 +0000
commita6cad7cd39f57b334f7cf1138a9e657455bb09ef (patch)
tree5060d24f931f4a5733ed9f1d808075ac6958c1fb /hw/scsi/esp.c
parent5a8573391e4a7936dc8276e484ae6208eea99a4b (diff)
esp.c: implement DMA Transfer Pad command for DATA phases
The Transfer Pad command is used to either drop incoming FIFO data during the DATA IN phase or generate a series of zero bytes in the FIFO during the DATA OUT phase. Implement the DMA Transfer Pad command for the DATA phases which is used by the NeXTCube firmware in the DATA IN phase to ignore part of the incoming SCSI data as it is copied into memory. Signed-off-by: Mark Cave-Ayland <mark.cave-ayland@ilande.co.uk> Tested-by: Helge Deller <deller@gmx.de> Tested-by: Thomas Huth <thuth@redhat.com> Message-Id: <20240112125420.514425-85-mark.cave-ayland@ilande.co.uk> Signed-off-by: Mark Cave-Ayland <mark.cave-ayland@ilande.co.uk>
Diffstat (limited to 'hw/scsi/esp.c')
-rw-r--r--hw/scsi/esp.c97
1 files changed, 69 insertions, 28 deletions
diff --git a/hw/scsi/esp.c b/hw/scsi/esp.c
index 73379a3c65..5583b3eb56 100644
--- a/hw/scsi/esp.c
+++ b/hw/scsi/esp.c
@@ -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);