diff options
author | Guenter Roeck | 2018-11-29 18:17:42 +0100 |
---|---|---|
committer | Paolo Bonzini | 2019-01-11 13:57:24 +0100 |
commit | ea84a44250f79566484692bb000e97776ac66047 (patch) | |
tree | 438608bd3b63f32142e711889f730de90b5ac9b9 /include/hw/scsi | |
parent | esp-pci: Fix status register write erase control (diff) | |
download | qemu-ea84a44250f79566484692bb000e97776ac66047.tar.gz qemu-ea84a44250f79566484692bb000e97776ac66047.tar.xz qemu-ea84a44250f79566484692bb000e97776ac66047.zip |
scsi: esp: Defer command completion until previous interrupts have been handled
The guest OS reads RSTAT, RSEQ, and RINTR, and expects those registers
to reflect a consistent state. However, it is possible that the registers
can change after RSTAT was read, but before RINTR is read, when
esp_command_complete() is called.
Guest OS qemu
-------- ----
[handle interrupt]
Read RSTAT
esp_command_complete()
RSTAT = STAT_ST
esp_dma_done()
RSTAT |= STAT_TC
RSEQ = 0
RINTR = INTR_BS
Read RSEQ
Read RINTR RINTR = 0
RSTAT &= ~STAT_TC
RSEQ = SEQ_CD
The guest OS would then try to handle INTR_BS combined with an old
value of RSTAT. This sometimes resulted in lost events, spurious
interrupts, guest OS confusion, and stalled SCSI operations.
A typical guest error log (observed with various versions of Linux)
looks as follows.
scsi host1: Spurious irq, sreg=13.
...
scsi host1: Aborting command [84531f10:2a]
scsi host1: Current command [f882eea8:35]
scsi host1: Queued command [84531f10:2a]
scsi host1: Active command [f882eea8:35]
scsi host1: Dumping command log
scsi host1: ent[15] CMD val[44] sreg[90] seqreg[00] sreg2[00] ireg[20] ss[00] event[0c]
scsi host1: ent[16] CMD val[01] sreg[90] seqreg[00] sreg2[00] ireg[20] ss[02] event[0c]
scsi host1: ent[17] CMD val[43] sreg[90] seqreg[00] sreg2[00] ireg[20] ss[02] event[0c]
scsi host1: ent[18] EVENT val[0d] sreg[92] seqreg[04] sreg2[00] ireg[18] ss[00] event[0c]
...
Defer handling command completion until previous interrupts have been
handled to fix the problem.
Signed-off-by: Guenter Roeck <linux@roeck-us.net>
Diffstat (limited to 'include/hw/scsi')
-rw-r--r-- | include/hw/scsi/esp.h | 2 |
1 files changed, 2 insertions, 0 deletions
diff --git a/include/hw/scsi/esp.h b/include/hw/scsi/esp.h index 682a0d2de0..adab63d1c9 100644 --- a/include/hw/scsi/esp.h +++ b/include/hw/scsi/esp.h @@ -23,6 +23,8 @@ struct ESPState { int32_t ti_size; uint32_t ti_rptr, ti_wptr; uint32_t status; + uint32_t deferred_status; + bool deferred_complete; uint32_t dma; uint8_t ti_buf[TI_BUFSZ]; SCSIBus bus; |