hw/scsi/lsi53c895a: stop script on phase mismatch
Netbsd isn't happy with qemu lsi53c895a emulation: cd0(esiop0:0:2:0): command with tag id 0 reset esiop0: autoconfiguration error: phase mismatch without command esiop0: autoconfiguration error: unhandled scsi interrupt, sist=0x80 sstat1=0x0 DSA=0x23a64b1 DSP=0x50 This is because lsi_bad_phase() triggers a phase mismatch, which stops SCRIPT processing. However, after returning to lsi_command_complete(), SCRIPT is restarted with lsi_resume_script(). Fix this by adding a return value to lsi_bad_phase(), and only resume script processing when lsi_bad_phase() didn't trigger a host interrupt. Signed-off-by: Sven Schnelle <svens@stackframe.org> Tested-by: Helge Deller <deller@gmx.de> Message-ID: <20240302214453.2071388-1-svens@stackframe.org> Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
This commit is contained in:
parent
5d402bd9ae
commit
a9198b3132
@ -573,8 +573,9 @@ static inline void lsi_set_phase(LSIState *s, int phase)
|
||||
s->sstat1 = (s->sstat1 & ~PHASE_MASK) | phase;
|
||||
}
|
||||
|
||||
static void lsi_bad_phase(LSIState *s, int out, int new_phase)
|
||||
static int lsi_bad_phase(LSIState *s, int out, int new_phase)
|
||||
{
|
||||
int ret = 0;
|
||||
/* Trigger a phase mismatch. */
|
||||
if (s->ccntl0 & LSI_CCNTL0_ENPMJ) {
|
||||
if ((s->ccntl0 & LSI_CCNTL0_PMJCTL)) {
|
||||
@ -587,8 +588,10 @@ static void lsi_bad_phase(LSIState *s, int out, int new_phase)
|
||||
trace_lsi_bad_phase_interrupt();
|
||||
lsi_script_scsi_interrupt(s, LSI_SIST0_MA, 0);
|
||||
lsi_stop_script(s);
|
||||
ret = 1;
|
||||
}
|
||||
lsi_set_phase(s, new_phase);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
@ -792,7 +795,7 @@ static int lsi_queue_req(LSIState *s, SCSIRequest *req, uint32_t len)
|
||||
static void lsi_command_complete(SCSIRequest *req, size_t resid)
|
||||
{
|
||||
LSIState *s = LSI53C895A(req->bus->qbus.parent);
|
||||
int out;
|
||||
int out, stop = 0;
|
||||
|
||||
out = (s->sstat1 & PHASE_MASK) == PHASE_DO;
|
||||
trace_lsi_command_complete(req->status);
|
||||
@ -800,7 +803,10 @@ static void lsi_command_complete(SCSIRequest *req, size_t resid)
|
||||
s->command_complete = 2;
|
||||
if (s->waiting && s->dbc != 0) {
|
||||
/* Raise phase mismatch for short transfers. */
|
||||
lsi_bad_phase(s, out, PHASE_ST);
|
||||
stop = lsi_bad_phase(s, out, PHASE_ST);
|
||||
if (stop) {
|
||||
s->waiting = 0;
|
||||
}
|
||||
} else {
|
||||
lsi_set_phase(s, PHASE_ST);
|
||||
}
|
||||
@ -810,7 +816,9 @@ static void lsi_command_complete(SCSIRequest *req, size_t resid)
|
||||
lsi_request_free(s, s->current);
|
||||
scsi_req_unref(req);
|
||||
}
|
||||
lsi_resume_script(s);
|
||||
if (!stop) {
|
||||
lsi_resume_script(s);
|
||||
}
|
||||
}
|
||||
|
||||
/* Callback to indicate that the SCSI layer has completed a transfer. */
|
||||
|
Loading…
Reference in New Issue
Block a user