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: