Skip to content

Commit

Permalink
esp.c: use deferred interrupts for both DATA IN and DATA OUT phases
Browse files Browse the repository at this point in the history
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>
  • Loading branch information
mcayland committed Feb 13, 2024
1 parent a4608fa commit c90b279
Showing 1 changed file with 18 additions and 17 deletions.
35 changes: 18 additions & 17 deletions hw/scsi/esp.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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;
}

Expand All @@ -854,29 +849,34 @@ 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]) {
case CMD_SEL | CMD_DMA:
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:
/*
* Initial incoming data xfer is complete so raise command
* completion interrupt
*/
s->rregs[ESP_RINTR] |= INTR_BS;
esp_raise_irq(s);
break;

case CMD_TI | CMD_DMA:
Expand All @@ -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);
}

/*
Expand Down

0 comments on commit c90b279

Please sign in to comment.