aboutsummaryrefslogtreecommitdiff
path: root/hw/scsi
diff options
context:
space:
mode:
authorMark Cave-Ayland <mark.cave-ayland@ilande.co.uk>2024-01-12 12:53:52 +0000
committerMark Cave-Ayland <mark.cave-ayland@ilande.co.uk>2024-02-13 19:37:28 +0000
commitc90b2792293d5ce3eb66b1db924894e94d807654 (patch)
tree301edaaa0012548471e519deb2d0128db327f3dc /hw/scsi
parenta4608fa0a5148dbb10f8ac473051ec326ffd71f7 (diff)
downloadqemu-c90b2792293d5ce3eb66b1db924894e94d807654.zip
qemu-c90b2792293d5ce3eb66b1db924894e94d807654.tar.gz
qemu-c90b2792293d5ce3eb66b1db924894e94d807654.tar.bz2
esp.c: use deferred interrupts for both DATA IN and DATA OUT phases
This brings DATA OUT transfers in line with DATA IN transfers by ensuring that the guest visible function complete interrupt is only set once the SCSI layer has returned. 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-61-mark.cave-ayland@ilande.co.uk> Signed-off-by: Mark Cave-Ayland <mark.cave-ayland@ilande.co.uk>
Diffstat (limited to 'hw/scsi')
-rw-r--r--hw/scsi/esp.c35
1 files changed, 18 insertions, 17 deletions
diff --git a/hw/scsi/esp.c b/hw/scsi/esp.c
index b6cf1b4..d714657 100644
--- a/hw/scsi/esp.c
+++ b/hw/scsi/esp.c
@@ -248,10 +248,8 @@ static int esp_select(ESPState *s)
/*
* Note that we deliberately don't raise the IRQ here: this will be done
- * either in do_command_phase() for DATA OUT transfers or by the deferred
- * IRQ mechanism in esp_transfer_data() for DATA IN transfers
+ * either in esp_transfer_data() or esp_command_complete()
*/
- s->rregs[ESP_RINTR] |= INTR_FC;
s->rregs[ESP_RSEQ] = SEQ_CD;
return 0;
}
@@ -321,20 +319,17 @@ static void do_command_phase(ESPState *s)
datalen = scsi_req_enqueue(s->current_req);
s->ti_size = datalen;
fifo8_reset(&s->cmdfifo);
+ s->data_ready = false;
if (datalen != 0) {
s->ti_cmd = 0;
+ /*
+ * Switch to DATA phase but wait until initial data xfer is
+ * complete before raising the command completion interrupt
+ */
if (datalen > 0) {
- /*
- * Switch to DATA IN phase but wait until initial data xfer is
- * complete before raising the command completion interrupt
- */
- s->data_ready = false;
esp_set_phase(s, STAT_DI);
} else {
esp_set_phase(s, STAT_DO);
- s->rregs[ESP_RINTR] |= INTR_BS | INTR_FC;
- esp_raise_irq(s);
- esp_lower_drq(s);
}
scsi_req_continue(s->current_req);
return;
@@ -832,9 +827,9 @@ void esp_command_complete(SCSIRequest *req, size_t resid)
case CMD_SELATN:
/*
* No data phase for sequencer command so raise deferred bus service
- * interrupt
+ * and function complete interrupt
*/
- s->rregs[ESP_RINTR] |= INTR_BS;
+ s->rregs[ESP_RINTR] |= INTR_BS | INTR_FC;
break;
}
@@ -854,14 +849,13 @@ void esp_command_complete(SCSIRequest *req, size_t resid)
void esp_transfer_data(SCSIRequest *req, uint32_t len)
{
ESPState *s = req->hba_private;
- int to_device = (esp_get_phase(s) == STAT_DO);
uint32_t dmalen = esp_get_tc(s);
trace_esp_transfer_data(dmalen, s->ti_size);
s->async_len = len;
s->async_buf = scsi_req_get_buf(req);
- if (!to_device && !s->data_ready) {
+ if (!s->data_ready) {
s->data_ready = true;
switch (s->rregs[ESP_CMD]) {
@@ -869,6 +863,13 @@ void esp_transfer_data(SCSIRequest *req, uint32_t len)
case CMD_SEL:
case CMD_SELATN | CMD_DMA:
case CMD_SELATN:
+ /*
+ * Initial incoming data xfer is complete for sequencer command
+ * so raise deferred bus service and function complete interrupt
+ */
+ s->rregs[ESP_RINTR] |= INTR_BS | INTR_FC;
+ break;
+
case CMD_SELATNS | CMD_DMA:
case CMD_SELATNS:
/*
@@ -876,7 +877,6 @@ void esp_transfer_data(SCSIRequest *req, uint32_t len)
* completion interrupt
*/
s->rregs[ESP_RINTR] |= INTR_BS;
- esp_raise_irq(s);
break;
case CMD_TI | CMD_DMA:
@@ -886,9 +886,10 @@ void esp_transfer_data(SCSIRequest *req, uint32_t len)
* DATA phase
*/
s->rregs[ESP_RINTR] |= INTR_BS;
- esp_raise_irq(s);
break;
}
+
+ esp_raise_irq(s);
}
/*