mirror of
https://github.com/mii443/qemu.git
synced 2025-08-30 19:09:35 +00:00
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:
committed by
Paolo Bonzini
parent
6ed0b8431c
commit
9ae56d2e46
@ -573,8 +573,9 @@ static inline void lsi_set_phase(LSIState *s, int phase)
|
|||||||
s->sstat1 = (s->sstat1 & ~PHASE_MASK) | 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. */
|
/* Trigger a phase mismatch. */
|
||||||
if (s->ccntl0 & LSI_CCNTL0_ENPMJ) {
|
if (s->ccntl0 & LSI_CCNTL0_ENPMJ) {
|
||||||
if ((s->ccntl0 & LSI_CCNTL0_PMJCTL)) {
|
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();
|
trace_lsi_bad_phase_interrupt();
|
||||||
lsi_script_scsi_interrupt(s, LSI_SIST0_MA, 0);
|
lsi_script_scsi_interrupt(s, LSI_SIST0_MA, 0);
|
||||||
lsi_stop_script(s);
|
lsi_stop_script(s);
|
||||||
|
ret = 1;
|
||||||
}
|
}
|
||||||
lsi_set_phase(s, new_phase);
|
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)
|
static void lsi_command_complete(SCSIRequest *req, size_t resid)
|
||||||
{
|
{
|
||||||
LSIState *s = LSI53C895A(req->bus->qbus.parent);
|
LSIState *s = LSI53C895A(req->bus->qbus.parent);
|
||||||
int out;
|
int out, stop = 0;
|
||||||
|
|
||||||
out = (s->sstat1 & PHASE_MASK) == PHASE_DO;
|
out = (s->sstat1 & PHASE_MASK) == PHASE_DO;
|
||||||
trace_lsi_command_complete(req->status);
|
trace_lsi_command_complete(req->status);
|
||||||
@ -800,7 +803,10 @@ static void lsi_command_complete(SCSIRequest *req, size_t resid)
|
|||||||
s->command_complete = 2;
|
s->command_complete = 2;
|
||||||
if (s->waiting && s->dbc != 0) {
|
if (s->waiting && s->dbc != 0) {
|
||||||
/* Raise phase mismatch for short transfers. */
|
/* 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 {
|
} else {
|
||||||
lsi_set_phase(s, PHASE_ST);
|
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);
|
lsi_request_free(s, s->current);
|
||||||
scsi_req_unref(req);
|
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. */
|
/* Callback to indicate that the SCSI layer has completed a transfer. */
|
||||||
|
Reference in New Issue
Block a user