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>
---
hw/scsi/esp.c | 35 ++++++++++++++++++-----------------
1 file changed, 18 insertions(+), 17 deletions(-)
diff --git a/hw/scsi/esp.c b/hw/scsi/esp.c
index b6cf1b43db..d71465718c 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);
}
/*
--
2.39.2