Skip to content

Commit

Permalink
esp.c: implement DMA Transfer Pad command for DATA phases
Browse files Browse the repository at this point in the history
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>
  • Loading branch information
mcayland committed Feb 13, 2024
1 parent 5a85733 commit a6cad7c
Showing 1 changed file with 69 additions and 28 deletions.
97 changes: 69 additions & 28 deletions hw/scsi/esp.c
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down Expand Up @@ -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 */
Expand All @@ -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 */
Expand Down Expand Up @@ -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);
Expand Down

0 comments on commit a6cad7c

Please sign in to comment.