aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMark Cave-Ayland <mark.cave-ayland@ilande.co.uk>2021-03-04 22:10:48 +0000
committerMark Cave-Ayland <mark.cave-ayland@ilande.co.uk>2021-03-07 10:39:05 +0000
commit496913153a9d5d0b200c2ac30a541f9f294f55aa (patch)
treefc3ded64485eb3b21bf9835e2ef93b274ae821bb
parentc7bce09c0595b235ad367a12bae54cb04b33025b (diff)
downloadqemu-496913153a9d5d0b200c2ac30a541f9f294f55aa.zip
qemu-496913153a9d5d0b200c2ac30a541f9f294f55aa.tar.gz
qemu-496913153a9d5d0b200c2ac30a541f9f294f55aa.tar.bz2
esp: fix PDMA target selection
Currently the target selection for PDMA is done after the SCSI command has been delivered which is not correct. Perform target selection as part of the initial get_cmd() call when the command is submitted: if no target is present, don't raise DRQ. If the target is present then switch to the command phase since the MacOS toolbox ROM checks for this before attempting to submit the SCSI command. Signed-off-by: Mark Cave-Ayland <mark.cave-ayland@ilande.co.uk> Reviewed-by: Laurent Vivier <laurent@vivier.eu> Message-Id: <20210304221103.6369-28-mark.cave-ayland@ilande.co.uk>
-rw-r--r--hw/scsi/esp.c53
1 files changed, 34 insertions, 19 deletions
diff --git a/hw/scsi/esp.c b/hw/scsi/esp.c
index d8d7ede..10e63d1 100644
--- a/hw/scsi/esp.c
+++ b/hw/scsi/esp.c
@@ -243,6 +243,9 @@ static uint32_t get_cmd(ESPState *s)
s->dma_memory_read(s->dma_opaque, buf, dmalen);
} else {
set_pdma(s, TI);
+ if (esp_select(s) < 0) {
+ return -1;
+ }
esp_raise_drq(s);
return 0;
}
@@ -257,7 +260,7 @@ static uint32_t get_cmd(ESPState *s)
trace_esp_get_cmd(dmalen, target);
if (esp_select(s) < 0) {
- return 0;
+ return -1;
}
return dmalen;
}
@@ -299,9 +302,6 @@ static void do_cmd(ESPState *s)
static void satn_pdma_cb(ESPState *s)
{
- if (esp_select(s) < 0) {
- return;
- }
s->do_cmd = 0;
if (s->cmdlen) {
do_cmd(s);
@@ -310,24 +310,28 @@ static void satn_pdma_cb(ESPState *s)
static void handle_satn(ESPState *s)
{
+ int32_t cmdlen;
+
if (s->dma && !s->dma_enabled) {
s->dma_cb = handle_satn;
return;
}
s->pdma_cb = satn_pdma_cb;
- s->cmdlen = get_cmd(s);
- if (s->cmdlen) {
+ cmdlen = get_cmd(s);
+ if (cmdlen > 0) {
+ s->cmdlen = cmdlen;
do_cmd(s);
- } else {
+ } else if (cmdlen == 0) {
+ s->cmdlen = 0;
s->do_cmd = 1;
+ /* Target present, but no cmd yet - switch to command phase */
+ s->rregs[ESP_RSEQ] = SEQ_CD;
+ s->rregs[ESP_RSTAT] = STAT_CD;
}
}
static void s_without_satn_pdma_cb(ESPState *s)
{
- if (esp_select(s) < 0) {
- return;
- }
s->do_cmd = 0;
if (s->cmdlen) {
do_busid_cmd(s, s->cmdbuf, 0);
@@ -336,24 +340,28 @@ static void s_without_satn_pdma_cb(ESPState *s)
static void handle_s_without_atn(ESPState *s)
{
+ int32_t cmdlen;
+
if (s->dma && !s->dma_enabled) {
s->dma_cb = handle_s_without_atn;
return;
}
s->pdma_cb = s_without_satn_pdma_cb;
- s->cmdlen = get_cmd(s);
- if (s->cmdlen) {
+ cmdlen = get_cmd(s);
+ if (cmdlen > 0) {
+ s->cmdlen = cmdlen;
do_busid_cmd(s, s->cmdbuf, 0);
- } else {
+ } else if (cmdlen == 0) {
+ s->cmdlen = 0;
s->do_cmd = 1;
+ /* Target present, but no cmd yet - switch to command phase */
+ s->rregs[ESP_RSEQ] = SEQ_CD;
+ s->rregs[ESP_RSTAT] = STAT_CD;
}
}
static void satn_stop_pdma_cb(ESPState *s)
{
- if (esp_select(s) < 0) {
- return;
- }
s->do_cmd = 0;
if (s->cmdlen) {
trace_esp_handle_satn_stop(s->cmdlen);
@@ -367,21 +375,28 @@ static void satn_stop_pdma_cb(ESPState *s)
static void handle_satn_stop(ESPState *s)
{
+ int32_t cmdlen;
+
if (s->dma && !s->dma_enabled) {
s->dma_cb = handle_satn_stop;
return;
}
s->pdma_cb = satn_stop_pdma_cb;
- s->cmdlen = get_cmd(s);
- if (s->cmdlen) {
+ cmdlen = get_cmd(s);
+ if (cmdlen > 0) {
trace_esp_handle_satn_stop(s->cmdlen);
+ s->cmdlen = cmdlen;
s->do_cmd = 1;
s->rregs[ESP_RSTAT] = STAT_TC | STAT_CD;
s->rregs[ESP_RINTR] = INTR_BS | INTR_FC;
s->rregs[ESP_RSEQ] = SEQ_CD;
esp_raise_irq(s);
- } else {
+ } else if (cmdlen == 0) {
+ s->cmdlen = 0;
s->do_cmd = 1;
+ /* Target present, but no cmd yet - switch to command phase */
+ s->rregs[ESP_RSEQ] = SEQ_CD;
+ s->rregs[ESP_RSTAT] = STAT_CD;
}
}