aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMark Cave-Ayland <mark.cave-ayland@ilande.co.uk>2024-01-12 12:54:04 +0000
committerMark Cave-Ayland <mark.cave-ayland@ilande.co.uk>2024-02-13 19:37:28 +0000
commit02a3ce56a7573d4c7b173b570abda9f239666dc0 (patch)
tree3a791ad29a668d5324493428918fb252759de49a
parentd68212cdb1b60011e23e94fda3f4c2b88f601816 (diff)
downloadqemu-02a3ce56a7573d4c7b173b570abda9f239666dc0.zip
qemu-02a3ce56a7573d4c7b173b570abda9f239666dc0.tar.gz
qemu-02a3ce56a7573d4c7b173b570abda9f239666dc0.tar.bz2
esp.c: handle TC underflow for DMA SCSI requests
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>
-rw-r--r--hw/scsi/esp.c25
1 files changed, 24 insertions, 1 deletions
diff --git a/hw/scsi/esp.c b/hw/scsi/esp.c
index 8ea100e..a3e18bb 100644
--- a/hw/scsi/esp.c
+++ b/hw/scsi/esp.c
@@ -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);
@@ -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);
@@ -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;
@@ -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);