Subject: port-sparc/1422: Sun 4/110 has no SCSI driver.
To: None <gnats-bugs@gnats.netbsd.org>
From: Jason R. Thorpe <thorpej@SJ.Xenotropic.COM>
List: netbsd-bugs
Date: 08/30/1995 01:36:39
>Number: 1422
>Category: port-sparc
>Synopsis: Sun 4/110 has no SCSI driver.
>Confidential: no
>Severity: serious
>Priority: high
>Responsible: gnats-admin (GNATS administrator)
>State: open
>Class: change-request
>Submitter-Id: net
>Arrival-Date: Wed Aug 30 04:50:01 1995
>Last-Modified:
>Originator:
>Organization:
Just me and my collection of obsolete computer gear(s).
>Release: -current, Aug 27 1995
>Environment:
System: NetBSD bigsby 1.0A NetBSD 1.0A (BIGSBY) #51: Wed Aug 30 00:50:38 PDT 1995 thorpej@bigsby:/tmp_mnt/basalt/work/netbsd/src/sys/arch/sparc/compile/BIGSBY sparc
>Description:
This is really a combination of a sw-bug and a change-request.
In any case, there is no SCSI driver for the Sun 4/110. Considering
that the 4/110 `SCSI Weird' controller is just an NCR 5380 behind
different glue, there's no reason why there shouldn't be.
Additionally, the Sun 3 `si' driver has had a few changes made
to it lately, which are appropriate for inclusion in
<dev/ic/ncr5380.c>. Also, ncr5380.c still has some `si'-specific
goo in it. This is wrong for a machine-independant driver.
The `si' driver is missing the bootpath code recently added to
the SPARC port. I have already submitted a PR about this, and
to my knowledge, it is still open.
The `si' driver currently maps controller registers incorrectly.
This can cause panics on some systems.
>How-To-Repeat:
Try to use SCSI on a 4/110. You lose.
>Fix:
The following set of diffs implement a non-DMA `sw' driver
using the pre-existing non-DMA `si' driver. It's good to
have the `sw' code in place, since it should be a consideration
when adding DMA support to this driver in the future.
In addition to the diffs attached below, the the `si' entry in
.../sparc/conf/files.sparc needs to change into something like:
device si at vmes: scsi
device sw at obio: scsi
file arch/sparc/dev/si.c si sw needs-flag
The line configuring an `sw' in the kernel configuration
file should look like:
sw0 at obio0 addr 0x0a000000 leve 2 # 4/100
Attached below are diffs to:
sys/dev/ic/ncr5380.c
sys/dev/ic/ncr5380var.h
sys/arch/sparc/dev/si.c
sys/arch/sparc/dev/sireg.h
All diffs are against virgin NetBSD-current as of August 27, 1995.
Index: ncr5380.c
===================================================================
RCS file: /usr/og/devsrc/netbsd/src/sys/dev/ic/ncr5380.c,v
retrieving revision 1.1.1.1
retrieving revision 1.3
diff -c -r1.1.1.1 -r1.3
*** ncr5380.c 1995/08/03 07:13:37 1.1.1.1
--- ncr5380.c 1995/08/30 07:43:19 1.3
***************
*** 181,189 ****
ncr5380_show_scsi_cmd(xs);
#endif
! sense = ncr5380_generic( xs->sc_link->scsibus, xs->sc_link->target,
! xs->sc_link->lun, xs->cmd, xs->cmdlen,
! xs->data, xs->datalen );
switch (sense) {
case 0: /* success */
--- 181,189 ----
ncr5380_show_scsi_cmd(xs);
#endif
! sense = ncr5380_generic( xs->sc_link->adapter_softc,
! xs->sc_link->target, xs->sc_link->lun, xs->cmd,
! xs->cmdlen, xs->data, xs->datalen );
switch (sense) {
case 0: /* success */
***************
*** 198,204 ****
xs->sc_link->target);
#endif
delay(10); /* Phil's fix for slow devices. */
! ncr5380_group0(xs->sc_link->scsibus,
xs->sc_link->target,
xs->sc_link->lun,
0x3, 0x0,
--- 198,204 ----
xs->sc_link->target);
#endif
delay(10); /* Phil's fix for slow devices. */
! ncr5380_group0(xs->sc_link->adapter_softc,
xs->sc_link->target,
xs->sc_link->lun,
0x3, 0x0,
***************
*** 228,234 ****
int ret = SCSI_RET_RETRY;
int arb_retries, arb_wait;
int i;
- volatile u_char vuc;
/* for our purposes.. */
myid = 1 << myid;
--- 228,233 ----
***************
*** 241,246 ****
--- 240,246 ----
retry_arbitration:
regs->sci_mode = 0; /* get into a harmless state */
+ wait_for_bus_free:
if (--arb_retries <= 0) {
#ifdef DEBUG
if (ncr5380_debug) {
***************
*** 253,273 ****
icmd = regs->sci_icmd & ~(SCI_ICMD_DIFF|SCI_ICMD_TEST);
! /* Picked this constant for convenience. --thorpej */
! for (i = 0; i < ARBITRATION_RETRIES; ++i) {
! vuc = (regs->sci_bus_csr & (SCI_BUS_BSY|SCI_BUS_SEL));
! if (vuc == 0)
! break;
! delay(10);
! }
! if (vuc != 0) {
! /* No sir, I don't like it. Call for a reset. */
#ifdef DEBUG
! if (ncr5380_debug)
! printf("ncr5380_select_target: still BSY+SEL; resetting\n");
#endif
! ret = SCSI_RET_NEED_RESET;
! goto nosel;
}
regs->sci_odata = myid;
--- 253,269 ----
icmd = regs->sci_icmd & ~(SCI_ICMD_DIFF|SCI_ICMD_TEST);
! if (regs->sci_bus_csr & (SCI_BUS_BSY|SCI_BUS_SEL)) {
! /* Something is sitting on the SCSI bus... */
#ifdef DEBUG
! /* Only complain once (the last time through). */
! if (ncr5380_debug && (arb_retries <= 1)) {
! printf("si_select_target: still BSY+SEL\n");
! }
#endif
! /* Give it a little time, then try again. */
! delay(10);
! goto wait_for_bus_free;
}
regs->sci_odata = myid;
***************
*** 416,425 ****
icmd = regs->sci_icmd & ~(SCI_ICMD_DIFF|SCI_ICMD_TEST);
loop:
if (SCI_CUR_PHASE(regs->sci_bus_csr) != phase)
return cnt;
- WAIT_FOR_REQ(regs);
icmd |= SCI_ICMD_DATA;
regs->sci_icmd = icmd;
regs->sci_odata = *data++;
--- 412,422 ----
icmd = regs->sci_icmd & ~(SCI_ICMD_DIFF|SCI_ICMD_TEST);
loop:
+ /* SCSI bus phase not valid until REQ is true. */
+ WAIT_FOR_REQ(regs);
if (SCI_CUR_PHASE(regs->sci_bus_csr) != phase)
return cnt;
icmd |= SCI_ICMD_DATA;
regs->sci_icmd = icmd;
regs->sci_odata = *data++;
***************
*** 449,458 ****
icmd = regs->sci_icmd & ~(SCI_ICMD_DIFF|SCI_ICMD_TEST);
loop:
if (SCI_CUR_PHASE(regs->sci_bus_csr) != phase)
return cnt;
- WAIT_FOR_REQ(regs);
*data++ = regs->sci_data;
icmd |= SCI_ICMD_ACK;
regs->sci_icmd = icmd;
--- 446,456 ----
icmd = regs->sci_icmd & ~(SCI_ICMD_DIFF|SCI_ICMD_TEST);
loop:
+ /* SCSI bus phase not valid until REQ is true. */
+ WAIT_FOR_REQ(regs);
if (SCI_CUR_PHASE(regs->sci_bus_csr) != phase)
return cnt;
*data++ = regs->sci_data;
icmd |= SCI_ICMD_ACK;
regs->sci_icmd = icmd;
***************
*** 693,705 ****
static int
ncr5380_generic(adapter, id, lun, cmd, cmdlen, databuf, datalen)
! int adapter, id, lun;
struct scsi_generic *cmd;
int cmdlen;
void *databuf;
int datalen;
{
! register struct ncr5380_softc *sc = sicd.cd_devs[adapter];
int i, j, sent;
if (cmd->opcode == TEST_UNIT_READY) /* XXX */
--- 691,704 ----
static int
ncr5380_generic(adapter, id, lun, cmd, cmdlen, databuf, datalen)
! void *adapter;
! int id, lun;
struct scsi_generic *cmd;
int cmdlen;
void *databuf;
int datalen;
{
! register struct ncr5380_softc *sc = adapter;
int i, j, sent;
if (cmd->opcode == TEST_UNIT_READY) /* XXX */
***************
*** 713,723 ****
static int
ncr5380_group0(adapter, id, lun, opcode, addr, len, flags, databuf, datalen)
! int adapter, id, lun, opcode, addr, len, flags;
caddr_t databuf;
int datalen;
{
! register struct ncr5380_softc *sc = sicd.cd_devs[adapter];
unsigned char cmd[6];
int i, j, sent;
--- 712,723 ----
static int
ncr5380_group0(adapter, id, lun, opcode, addr, len, flags, databuf, datalen)
! void *adapter;
! int id, lun, opcode, addr, len, flags;
caddr_t databuf;
int datalen;
{
! register struct ncr5380_softc *sc = adapter;
unsigned char cmd[6];
int i, j, sent;
Index: ncr5380var.h
===================================================================
RCS file: /usr/og/devsrc/netbsd/src/sys/dev/ic/ncr5380var.h,v
retrieving revision 1.1.1.1
retrieving revision 1.2
diff -c -r1.1.1.1 -r1.2
*** ncr5380var.h 1995/08/03 07:13:38 1.1.1.1
--- ncr5380var.h 1995/08/30 06:51:19 1.2
***************
*** 109,117 ****
static int ncr5380_dorequest __P((struct ncr5380_softc *, int, int,
u_char *, int, char *, int, int *));
! static int ncr5380_generic __P((int, int, int, struct scsi_generic *,
int, void *, int));
! static int ncr5380_group0 __P((int, int, int, int, int, int,
int, caddr_t, int));
--- 109,117 ----
static int ncr5380_dorequest __P((struct ncr5380_softc *, int, int,
u_char *, int, char *, int, int *));
! static int ncr5380_generic __P((void *, int, int, struct scsi_generic *,
int, void *, int));
! static int ncr5380_group0 __P((void *, int, int, int, int, int,
int, caddr_t, int));
Index: si.c
===================================================================
RCS file: /usr/og/devsrc/netbsd/src/sys/arch/sparc/dev/si.c,v
retrieving revision 1.1.1.2
retrieving revision 1.4
diff -c -r1.1.1.2 -r1.4
*** si.c 1995/08/21 03:29:44 1.1.1.2
--- si.c 1995/08/30 06:54:53 1.4
***************
*** 96,101 ****
--- 96,112 ----
sizeof(struct ncr5380_softc), NULL, 0,
};
+ /*
+ * An `sw' is just an `si' behind a different DMA engine.
+ * This driver doesn't currently do DMA, so we can more or less
+ * handle it here. (It's really not much different than the
+ * Sun 3/50 SCSI controller, if I understand it right.)
+ */
+ struct cfdriver swcd = {
+ NULL, "sw", si_match, si_attach, DV_DULL,
+ sizeof(struct ncr5380_softc), NULL, 0,
+ };
+
static int
si_print(aux, name)
void *aux;
***************
*** 117,127 ****
if (strcmp(cf->cf_driver->cd_name, ra->ra_name))
return (0);
! /* AFAIK, Sun 4s can only have an `si' on the VME16 (?) */
! if (cputyp != CPU_SUN4 || ca->ca_bustype != BUS_VME16)
return (0);
! /* Default interrupt priority always splbio==2 */
if (ra->ra_intr[0].int_pri == -1)
ra->ra_intr[0].int_pri == 2;
--- 128,157 ----
if (strcmp(cf->cf_driver->cd_name, ra->ra_name))
return (0);
! /* Nothing but a Sun 4 is going to have these devices. */
! if (cputyp != CPU_SUN4)
return (0);
! /* Figure out the bus type and look for the appropriate adapter. */
! switch (ca->ca_bustype) {
! case BUS_VME16:
! /* AFAIK, the `si' can only exist on the vmes. */
! if (strcmp(ra->ra_name, "si") || cpumod == SUN4_100)
! return (0);
! break;
!
! case BUS_OBIO:
! /* AFAIK, an `sw' can only exist on the obio. */
! if (strcmp(ra->ra_name, "sw") || cpumod != SUN4_100)
! return (0);
! break;
!
! default:
! /* Don't know what we ended up with ... */
! return (0);
! }
!
! /* Default interrupt priority always splbio == 2 */
if (ra->ra_intr[0].int_pri == -1)
ra->ra_intr[0].int_pri == 2;
***************
*** 130,143 ****
return (0);
/*
! * We have to determine whether it is an `sc' (Sun2) or
! * `si' (Sun3) SCSI board. This can be determined using
! * the fact that the `sc' board occupies 4K bytes in VME
! * space but the `si' board occupies 2K bytes.
* Note that the `si' board should NOT respond to this.
*/
! if (probeget(ra->ra_vaddr + 0x801, 1) != -1)
! return(0);
return (1);
}
--- 160,174 ----
return (0);
/*
! * If we're looking for an `si', we have to determine whether
! * it is an `sc' (Sun2) or `si' (Sun3) SCSI board. This can be
! * determined using the fact that the `sc' board occupies 4K bytes
! * in VME space but the `si' board occupies 2K bytes.
* Note that the `si' board should NOT respond to this.
*/
! if (strcmp(cf->cf_driver->cd_name, "si") == 0)
! if (probeget(ra->ra_vaddr + 0x801, 1) != -1)
! return(0);
return (1);
}
***************
*** 148,176 ****
void *aux;
{
struct ncr5380_softc *ncr5380 = (struct ncr5380_softc *) self;
! volatile sci_regmap_t *regs;
struct confargs *ca = aux;
struct romaux *ra = &ca->ca_ra;
switch (ca->ca_bustype) {
case BUS_VME16:
! regs = (sci_regmap_t *)
! mapiodev(ra->ra_paddr, sizeof(sci_regmap_t),
! ca->ca_bustype);
! ncr5380->sc_ih.ih_fun = si_intr;
! ncr5380->sc_ih.ih_arg = ncr5380;
vmeintr_establish(ra->ra_intr[0].int_vec,
ra->ra_intr[0].int_pri, &ncr5380->sc_ih);
break;
default:
! printf("unknown\n");
! return;
}
ncr5380->sc_adapter_type = ca->ca_bustype;
- ncr5380->sc_adapter_iv_am =
- VME_SUPV_DATA_24 | (ra->ra_intr[0].int_vec & 0xFF);
ncr5380->sc_regs = regs;
/*
--- 179,221 ----
void *aux;
{
struct ncr5380_softc *ncr5380 = (struct ncr5380_softc *) self;
! volatile struct si_regs *regs;
struct confargs *ca = aux;
struct romaux *ra = &ca->ca_ra;
+ struct bootpath *bp;
+
+ /* Map the controller registers. */
+ regs = (struct si_regs *)mapiodev(ra->ra_paddr,
+ sizeof(struct si_regs), ca->ca_bustype);
+
+ /* Establish the interrupt. */
+ ncr5380->sc_ih.ih_fun = si_intr;
+ ncr5380->sc_ih.ih_arg = ncr5380;
switch (ca->ca_bustype) {
case BUS_VME16:
! /*
! * This will be an `si'.
! */
vmeintr_establish(ra->ra_intr[0].int_vec,
ra->ra_intr[0].int_pri, &ncr5380->sc_ih);
+ ncr5380->sc_adapter_iv_am =
+ VME_SUPV_DATA_24 | (ra->ra_intr[0].int_vec & 0xFF);
+ break;
+
+ case BUS_OBIO:
+ /*
+ * This will be an `sw'.
+ */
+ intr_establish(ra->ra_intr[0].int_pri, &ncr5380->sc_ih);
break;
default:
! printf("\n");
! panic("si_attach: unknown bus type 0x%x", ca->ca_bustype);
}
ncr5380->sc_adapter_type = ca->ca_bustype;
ncr5380->sc_regs = regs;
/*
***************
*** 188,194 ****
--- 233,253 ----
printf(" pri %d\n", ra->ra_intr[0].int_pri);
reset_adapter(ncr5380);
ncr5380_reset_scsibus(ncr5380);
+
+ /*
+ * If the boot path is "sw" or "si" at the moment and it's me, then
+ * walk out pointer to the sub-device, ready for the config
+ * below.
+ */
+ bp = ra->ra_bp;
+ if (bp != NULL && strcmp(bp->name, ra->ra_name) == 0 &&
+ bp->val[0] == -1 && bp->val[1] == ncr5380->sc_dev.dv_unit)
+ bootpath_store(1, bp + 1);
+
+ /* Configure sub-devices */
config_found(self, &(ncr5380->sc_link), si_print);
+
+ bootpath_store(1, NULL);
}
static void
***************
*** 210,227 ****
volatile struct si_regs *si = ncr5380->sc_regs;
int rv = 0;
! /* Interrupts not enabled? Can not be for us. */
! if ((si->si_csr & SI_CSR_INTR_EN) == 0)
! return rv;
!
! if (si->si_csr & SI_CSR_DMA_IP) {
! si_dma_intr(ncr5380);
! rv++;
! }
! if (si->si_csr & SI_CSR_SBC_IP) {
! ncr5380_sbc_intr(ncr5380);
! rv++;
}
return rv;
}
--- 269,306 ----
volatile struct si_regs *si = ncr5380->sc_regs;
int rv = 0;
! switch (ncr5380->sc_adapter_type) {
! case BUS_VME16:
! /* Interrupts not enabled? Can not be for us. */
! if ((si->si_csr & SI_CSR_INTR_EN) == 0)
! return rv;
!
! if (si->si_csr & SI_CSR_DMA_IP) {
! si_dma_intr(ncr5380);
! rv++;
! }
! if (si->si_csr & SI_CSR_SBC_IP) {
! ncr5380_sbc_intr(ncr5380);
! rv++;
! }
! break;
!
! case BUS_OBIO:
! /* Interrupts not enabled? Can not be for us. */
! if ((si->sw_csr & SI_CSR_INTR_EN) == 0)
! return rv;
!
! if (si->sw_csr & SI_CSR_DMA_IP) {
! si_dma_intr(ncr5380);
! rv++;
! }
! if (si->sw_csr & SI_CSR_SBC_IP) {
! ncr5380_sbc_intr(ncr5380);
! rv++;
! }
! break;
}
+
return rv;
}
***************
*** 237,253 ****
}
#endif
! /* The reset bits in the CSR are active low. */
! si->si_csr = 0;
! delay(20);
! si->si_csr = SI_CSR_FIFO_RES | SI_CSR_SCSI_RES;
! si->fifo_count = 0;
! if (sc->sc_adapter_type == BUS_VME16) {
si->dma_addrh = 0;
si->dma_addrl = 0;
si->dma_counth = 0;
si->dma_countl = 0;
si->iv_am = sc->sc_adapter_iv_am;
}
}
--- 316,342 ----
}
#endif
! switch(sc->sc_adapter_type) {
! case BUS_VME16:
! /* The reset bits in the CSR are active low. */
! si->si_csr = 0;
! delay(20);
! si->si_csr = SI_CSR_FIFO_RES | SI_CSR_SCSI_RES;
! si->fifo_count = 0;
si->dma_addrh = 0;
si->dma_addrl = 0;
si->dma_counth = 0;
si->dma_countl = 0;
si->iv_am = sc->sc_adapter_iv_am;
+ break;
+
+ case BUS_OBIO:
+ si->sw_csr = 0;
+ delay(20);
+ si->sw_csr = SI_CSR_FIFO_RES | SI_CSR_SCSI_RES;
+ si->dma_addr = 0;
+ si->dma_count = 0;
+ break;
}
}
Index: sireg.h
===================================================================
RCS file: /usr/og/devsrc/netbsd/src/sys/arch/sparc/dev/sireg.h,v
retrieving revision 1.1.1.1
retrieving revision 1.2
diff -c -r1.1.1.1 -r1.2
*** sireg.h 1995/08/03 07:11:45 1.1.1.1
--- sireg.h 1995/08/30 06:54:55 1.2
***************
*** 25,53 ****
struct si_regs {
sci_regmap_t sci; /* See ncr5380.h */
/* DMA controller registers */
! u_short dma_addrh; /* dma address (VME only) */
! u_short dma_addrl; /* (high word, low word) */
! u_short dma_counth; /* dma count (VME only) */
! u_short dma_countl; /* (high word, low word) */
! /* AMD 9516 regs (OBIO only) see am9516.h */
! u_short udc_data; /* Am9516, reg data (OBIO only) */
! u_short udc_addr; /* Am9516, reg addr (OBIO only) */
! /* These three registers are on both OBIO and VME versions. */
! u_short fifo_data; /* fifo data register */
! /* holds extra byte on odd */
! /* byte dma read */
! u_short fifo_count; /* fifo byte count */
! u_short si_csr; /* control/status register */
/* The rest of these are on the VME interface only: */
! u_short bprh; /* byte pack, high (VME only) */
! u_short bprl; /* byte pack, low (VME only) */
u_short iv_am; /* bits 0-7: intr vector */
! /* bits 8-13: addr modifier (VME only) */
/* bits 14-15: unused */
! u_short bcrh; /* high portion of bcr (VME only) */
};
/* possible values for the address modifier, sun3 vme version only */
--- 25,81 ----
struct si_regs {
sci_regmap_t sci; /* See ncr5380.h */
/* DMA controller registers */
! union {
! u_short _Dma_addrh; /* dma address (VME only) */
! u_short _Dma_addrl; /* (high word, low word) */
! u_int _Dma_addr; /* dma address (OBIO) */
! } _si_u1;
! #define dma_addrh _si_u1._Dma_addrh
! #define dma_addrl _si_u1._Dma_addrl
! #define dma_addr _si_u1._Dma_addr
! union {
! u_short _Dma_counth; /* dma count (VME only) */
! u_short _Dma_countl; /* (high word, low word) */
! u_int _Dma_count; /* dma count (OBIO) */
! } _si_u2;
! #define dma_counth _si_u2._Dma_counth
! #define dma_countl _si_u2._Dma_countl
! #define dma_count _si_u2._Dma_count
! union {
! u_short _Udc_data; /* Am9516 data reg (OBIO si) */
! u_short _Udc_addr; /* Am9516 addr reg (OBIO si) */
! u_int _Sw_bcr; /* non-existent sw bcr */
! } _si_u3;
! #define udc_data _si_u3._Udc_data
! #define udc_addr _si_u3._Udc_addr
! #define sw_bcr _si_u3._Sw_bcr
!
! union {
! u_short _Fifo_data; /* fifo data register */
! u_short _Fifo_count; /* fifo count register */
! u_int _Sw_csr; /* sw control/status */
! } _si_u4;
! #define fifo_data _si_u4._Fifo_data
! #define fifo_count _si_u4._Fifo_count
! #define sw_csr _si_u4._Sw_csr
!
! union {
! u_short _Si_csr; /* si control/status */
! u_short _Bprh; /* VME byte pack high */
! u_int _Bpr; /* sw byte pack */
! } _si_u5;
! #define si_csr _si_u5._Si_csr
! #define bprh _si_u5._Bprh
! #define bpr _si_u5._Bpr
/* The rest of these are on the VME interface only: */
! u_short bprl; /* VME byte pack low */
u_short iv_am; /* bits 0-7: intr vector */
! /* bits 8-13: addr modifier */
/* bits 14-15: unused */
! u_short bcrh; /* high portion of bcr */
};
/* possible values for the address modifier, sun3 vme version only */
>Audit-Trail:
>Unformatted: