Handle "scsi bus mode change" interrupts on 895 and higther.
Thanks to Hal Murray for reporting the problem and testing the fix.
This commit is contained in:
parent
5f61ae5a02
commit
221a99f782
|
@ -1,4 +1,4 @@
|
|||
/* $NetBSD: siop.c,v 1.19 2000/06/07 14:40:20 tsutsui Exp $ */
|
||||
/* $NetBSD: siop.c,v 1.20 2000/06/12 20:13:41 bouyer Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 2000 Manuel Bouyer.
|
||||
|
@ -388,8 +388,6 @@ siop_intr(v)
|
|||
}
|
||||
}
|
||||
if (cbdp == NULL) {
|
||||
printf("%s: current DSA invalid\n",
|
||||
sc->sc_dev.dv_xname);
|
||||
siop_cmd = NULL;
|
||||
}
|
||||
if (istat & ISTAT_DIP) {
|
||||
|
@ -433,6 +431,9 @@ siop_intr(v)
|
|||
printf("last msg_in=0x%x status=0x%x\n",
|
||||
siop_cmd->siop_table->msg_in[0],
|
||||
le32toh(siop_cmd->siop_table->status));
|
||||
else
|
||||
printf("%s: current DSA invalid\n",
|
||||
sc->sc_dev.dv_xname);
|
||||
need_reset = 1;
|
||||
}
|
||||
}
|
||||
|
@ -564,6 +565,26 @@ siop_intr(v)
|
|||
"command\n", sc->sc_dev.dv_xname);
|
||||
goto reset;
|
||||
}
|
||||
if (sist1 & SIST1_SBMC) {
|
||||
/* SCSI bus mode change */
|
||||
if (siop_modechange(sc) == 0 || need_reset == 1)
|
||||
goto reset;
|
||||
if ((istat & ISTAT_DIP) && (dstat & DSTAT_SIR)) {
|
||||
/*
|
||||
* we have a script interrupt, it will
|
||||
* restart the script.
|
||||
*/
|
||||
goto scintr;
|
||||
}
|
||||
/*
|
||||
* else we have to restart it ourselve, at the
|
||||
* interrupted instruction.
|
||||
*/
|
||||
bus_space_write_4(sc->sc_rt, sc->sc_rh, SIOP_DSP,
|
||||
bus_space_read_4(sc->sc_rt, sc->sc_rh,
|
||||
SIOP_DSP) - 8);
|
||||
return 1;
|
||||
}
|
||||
/* Else it's an unhandled exeption (for now). */
|
||||
printf("%s: unhandled scsi interrupt, sist0=0x%x sist1=0x%x "
|
||||
"sstat1=0x%x DSA=0x%x DSP=0x%x\n", sc->sc_dev.dv_xname,
|
||||
|
@ -592,7 +613,7 @@ reset:
|
|||
return 1;
|
||||
}
|
||||
|
||||
|
||||
scintr:
|
||||
if ((istat & ISTAT_DIP) && (dstat & DSTAT_SIR)) { /* script interrupt */
|
||||
irqcode = bus_space_read_4(sc->sc_rt, sc->sc_rh,
|
||||
SIOP_DSPS);
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
/* $NetBSD: siop_common.c,v 1.2 2000/05/15 15:16:59 bouyer Exp $ */
|
||||
/* $NetBSD: siop_common.c,v 1.3 2000/06/12 20:13:41 bouyer Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 2000 Manuel Bouyer.
|
||||
|
@ -478,3 +478,57 @@ siop_clearfifo(sc)
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
int
|
||||
siop_modechange(sc)
|
||||
struct siop_softc *sc;
|
||||
{
|
||||
int retry;
|
||||
int sist0, sist1, stest2, stest4;
|
||||
for (retry = 0; retry < 5; retry++) {
|
||||
/*
|
||||
* datasheet says to wait 100ms and re-read SIST1,
|
||||
* to check that DIFFSENSE is srable.
|
||||
* We may delay() 5 times for 100ms at interrupt time;
|
||||
* hopefully this will not happen often.
|
||||
*/
|
||||
delay(100000);
|
||||
sist0 = bus_space_read_1(sc->sc_rt, sc->sc_rh, SIOP_SIST0);
|
||||
sist1 = bus_space_read_1(sc->sc_rt, sc->sc_rh, SIOP_SIST1);
|
||||
if (sist1 & SIEN1_SBMC)
|
||||
continue; /* we got an irq again */
|
||||
stest4 = bus_space_read_1(sc->sc_rt, sc->sc_rh, SIOP_STEST4) &
|
||||
STEST4_MODE_MASK;
|
||||
stest2 = bus_space_read_1(sc->sc_rt, sc->sc_rh, SIOP_STEST2);
|
||||
switch(stest4) {
|
||||
case STEST4_MODE_DIF:
|
||||
printf("%s: switching to differential mode\n",
|
||||
sc->sc_dev.dv_xname);
|
||||
bus_space_write_1(sc->sc_rt, sc->sc_rh, SIOP_STEST2,
|
||||
stest2 | STEST2_DIF);
|
||||
break;
|
||||
case STEST4_MODE_SE:
|
||||
printf("%s: switching to single-ended mode\n",
|
||||
sc->sc_dev.dv_xname);
|
||||
bus_space_write_1(sc->sc_rt, sc->sc_rh, SIOP_STEST2,
|
||||
stest2 & ~STEST2_DIF);
|
||||
break;
|
||||
case STEST4_MODE_LVD:
|
||||
printf("%s: switching to LVD mode\n",
|
||||
sc->sc_dev.dv_xname);
|
||||
bus_space_write_1(sc->sc_rt, sc->sc_rh, SIOP_STEST2,
|
||||
stest2 & ~STEST2_DIF);
|
||||
break;
|
||||
default:
|
||||
printf("%s: invalid SCSI mode 0x%x\n",
|
||||
sc->sc_dev.dv_xname, stest4);
|
||||
return 0;
|
||||
}
|
||||
bus_space_write_1(sc->sc_rt, sc->sc_rh, SIOP_STEST0,
|
||||
stest4 >> 2);
|
||||
return 1;
|
||||
}
|
||||
printf("%s: timeout waiting for DIFFSENSE to stabilise\n",
|
||||
sc->sc_dev.dv_xname);
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
/* $NetBSD: siopreg.h,v 1.5 2000/05/15 07:48:25 bouyer Exp $ */
|
||||
/* $NetBSD: siopreg.h,v 1.6 2000/06/12 20:13:41 bouyer Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 2000 Manuel Bouyer.
|
||||
|
@ -276,6 +276,7 @@ static const struct scf_period scf_period[] __attribute__((__unused__)) = {
|
|||
#define SIEN0_PAR 0x01
|
||||
|
||||
#define SIOP_SIEN1 0x41 /* SCSI interrupt enable 1, R/W */
|
||||
#define SIEN1_SBMC 0x10 /* 895 only */
|
||||
#define SIEN1_STO 0x04
|
||||
#define SIEN1_GEN 0x02
|
||||
#define SIEN1_HTH 0x01
|
||||
|
@ -291,6 +292,7 @@ static const struct scf_period scf_period[] __attribute__((__unused__)) = {
|
|||
#define SIST0_PAR 0x01
|
||||
|
||||
#define SIOP_SIST1 0x43 /* SCSI interrut status 1, RO */
|
||||
#define SIST1_SBMC 0x10 /* 895 only */
|
||||
#define SIST1_STO 0x04
|
||||
#define SIST1_GEN 0x02
|
||||
#define SIST1_HTH 0x01
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
/* $NetBSD: siopvar_common.h,v 1.2 2000/05/23 17:08:07 bouyer Exp $ */
|
||||
/* $NetBSD: siopvar_common.h,v 1.3 2000/06/12 20:13:41 bouyer Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 2000 Manuel Bouyer.
|
||||
|
@ -126,6 +126,7 @@ struct siop_target {
|
|||
#define TARF_WIDE 0x01 /* target is wide */
|
||||
|
||||
void siop_common_reset __P((struct siop_softc *));
|
||||
int siop_modechange __P((struct siop_softc *));
|
||||
|
||||
int siop_wdtr_neg __P((struct siop_cmd *siop_cmd));
|
||||
int siop_sdtr_neg __P((struct siop_cmd *siop_cmd));
|
||||
|
|
Loading…
Reference in New Issue