Skip to content

Commit

Permalink
esp.c: handle TC underflow for DMA SCSI requests
Browse files Browse the repository at this point in the history
Detect the case where the guest underflows TC by requesting a DMA transfer which
is larger than the available data. If this case is detected, immediately
complete the SCSI request and handle any remaining FIFO accesses in the STATUS
phase by raising INTR_BS once the FIFO is below the threshold.

Note that handling the premature SCSI bus phase change in the case of TC
underflow fixes booting EMILE on m68k once again.

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-73-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 d68212c commit 02a3ce5
Showing 1 changed file with 24 additions and 1 deletion.
25 changes: 24 additions & 1 deletion hw/scsi/esp.c
Original file line number Diff line number Diff line change
Expand Up @@ -579,6 +579,12 @@ static void esp_do_dma(ESPState *s)
s->async_len -= len;
s->ti_size -= len;

if (s->async_len == 0 && s->ti_size == 0 && esp_get_tc(s)) {
/* If the guest underflows TC then terminate SCSI request */
scsi_req_continue(s->current_req);
return;
}

if (s->async_len == 0 && fifo8_num_used(&s->fifo) < 2) {
/* Defer until the scsi layer has completed */
scsi_req_continue(s->current_req);
Expand All @@ -596,6 +602,12 @@ static void esp_do_dma(ESPState *s)
esp_set_tc(s, esp_get_tc(s) - len);
esp_raise_drq(s);

if (s->async_len == 0 && s->ti_size == 0 && esp_get_tc(s)) {
/* If the guest underflows TC then terminate SCSI request */
scsi_req_continue(s->current_req);
return;
}

if (s->async_len == 0 && fifo8_num_used(&s->fifo) < 2) {
/* Defer until the scsi layer has completed */
scsi_req_continue(s->current_req);
Expand Down Expand Up @@ -630,6 +642,15 @@ static void esp_do_dma(ESPState *s)
}
}
break;

default:
/* Consume remaining data if the guest underflows TC */
if (fifo8_num_used(&s->fifo) < 2) {
s->rregs[ESP_RINTR] |= INTR_BS;
esp_raise_irq(s);
esp_lower_drq(s);
}
break;
}
break;

Expand Down Expand Up @@ -884,7 +905,9 @@ void esp_command_complete(SCSIRequest *req, size_t resid)
esp_set_phase(s, STAT_ST);
s->rregs[ESP_RINTR] |= INTR_BS;
esp_raise_irq(s);
esp_lower_drq(s);

/* Ensure DRQ is set correctly for TC underflow or normal completion */
esp_dma_ti_check(s);

if (s->current_req) {
scsi_req_unref(s->current_req);
Expand Down

0 comments on commit 02a3ce5

Please sign in to comment.