xref: /csrg-svn/sys/vax/if/if_vv.c (revision 21779)
1*21779Skarels /*	if_vv.c	6.8	85/06/03	*/
27024Ssam 
39799Ssam #include "vv.h"
411192Ssam 
57024Ssam /*
620997Skarels  * Proteon proNET-10 and proNET-80 token ring driver.
720997Skarels  * The name of this device driver derives from the old MIT
820997Skarels  * name of V2LNI for the proNET hardware, would would abbreviate
920997Skarels  * to "v2", but this won't work right. Thus the name is "vv".
1011192Ssam  *
1120997Skarels  * This driver is compatible with the proNET 10 meagbit and
1220997Skarels  * 80 megabit token ring interfaces (models p1000 and p1080).
1320997Skarels  *
1420997Skarels  * TRAILERS: You must turn off trailers via ifconfig if you want to share
1520997Skarels  * a ring with software using the following protocol types:
1620997Skarels  *  3: Address Resolution Protocol
1720997Skarels  *  4: HDLC (old Proteon drivers)
1820997Skarels  *  5: VAX Debugging Protocol (never used)
1920997Skarels  * This is because the protocol type values chosen for trailers
2020997Skarels  * conflict with these protocols. It's too late to change either now.
2120997Skarels  *
2220997Skarels  * HARDWARE COMPATABILITY: This driver requires that the HSBU (p1001)
2320997Skarels  * have a serial number >= 040, which is about March, 1982. Older
2420997Skarels  * HSBUs do not carry across 64kbyte boundaries. The old warning
2520997Skarels  * about use without Wire Centers applies only to CTL (p1002) cards with
2620997Skarels  * serial <= 057, which have not received ECO 176-743, which was
2720997Skarels  * implemented in March, 1982. Most such CTLs have received this ECO,
2820997Skarels  * but they are only compatible with the old HSBUs (<=039) anyways.
297024Ssam  */
3011209Ssam #include "../machine/pte.h"
319799Ssam 
3217117Sbloom #include "param.h"
3317117Sbloom #include "systm.h"
3417117Sbloom #include "mbuf.h"
3517117Sbloom #include "buf.h"
3617117Sbloom #include "protosw.h"
3717117Sbloom #include "socket.h"
3817117Sbloom #include "vmmac.h"
3917117Sbloom #include "errno.h"
4017117Sbloom #include "ioctl.h"
418465Sroot 
428465Sroot #include "../net/if.h"
4311209Ssam #include "../net/netisr.h"
448465Sroot #include "../net/route.h"
458421Swnj #include "../netinet/in.h"
468421Swnj #include "../netinet/in_systm.h"
47*21779Skarels #include "../netinet/in_var.h"
488421Swnj #include "../netinet/ip.h"
498421Swnj #include "../netinet/ip_var.h"
508465Sroot 
5115794Sleres #include "../vax/cpu.h"
5211209Ssam #include "../vax/mtpr.h"
5317117Sbloom #include "if_vv.h"
5417117Sbloom #include "if_uba.h"
558465Sroot #include "../vaxuba/ubareg.h"
568465Sroot #include "../vaxuba/ubavar.h"
577024Ssam 
587024Ssam /*
5920997Skarels  * 80 megabit configuration
6020997Skarels  * Uncomment the next line if you are using the 80 megabit system. The
6120997Skarels  * only change is the disposition of packets with parity/link_data_error
6220997Skarels  * indication.
637024Ssam  */
6420997Skarels /* #define PRONET80 */
657024Ssam 
6620997Skarels /*
6720997Skarels  *    maximum transmission unit definition --
6820997Skarels  *        you can set VVMTU at anything from 576 to 2024.
6920997Skarels  *        1536 is a popular "large" value, because it is a multiple
7020997Skarels  *	  of 512, which the trailer scheme likes.
7120997Skarels  *        The absolute maximum size is 2024, which is enforced.
7220997Skarels  */
7320997Skarels 
7420997Skarels #define VVMTU (1024)
7520997Skarels 
7620997Skarels #define VVMRU (VVMTU + 16)
7720997Skarels #define VVBUFSIZE (VVMRU + sizeof(struct vv_header))
7820997Skarels #if VVMTU>2024
7920997Skarels #undef VVMTU
8020997Skarels #undef VVMRU
8120997Skarels #undef VVBUFSIZE
8220997Skarels #define VVBUFSIZE (2046)
8320997Skarels #define VVMRU (VVBUFSIZE - sizeof (struct vv_header))
8420997Skarels #define VVMTU (VVMRU - 16)
857024Ssam #endif
867024Ssam 
8720997Skarels /*
8820997Skarels  *   debugging and tracing stuff
8920997Skarels  */
9016581Skarels int	vv_tracehdr = 0;	/* 1 => trace headers (slowly!!) */
917640Ssam 
9220997Skarels #define vvtracehdr  if (vv_tracehdr) vvprt_hdr
93*21779Skarels #define vvprintf    if (vs->vs_if.if_flags & IFF_DEBUG) printf
9411192Ssam 
9520997Skarels /*
9620997Skarels  * externals, types, etc.
9720997Skarels  */
9816581Skarels int	vvprobe(), vvattach(), vvreset(), vvinit();
9916581Skarels int	vvidentify(), vvstart(), vvxint(), vvwatchdog();
10016581Skarels int	vvrint(), vvoutput(), vvioctl(), vvsetaddr();
1017024Ssam struct	uba_device *vvinfo[NVV];
1027024Ssam u_short vvstd[] = { 0 };
1037024Ssam struct	uba_driver vvdriver =
1047024Ssam 	{ vvprobe, 0, vvattach, 0, vvstd, "vv", vvinfo };
1057024Ssam #define	VVUNIT(x)	minor(x)
1067024Ssam 
10720997Skarels #define LOOPBACK		/* use loopback for packets meant for us */
10820997Skarels #ifdef	LOOPBACK
10920997Skarels extern struct ifnet loif;
11020997Skarels #endif
11120997Skarels 
1127024Ssam /*
1137024Ssam  * Software status of each interface.
1147024Ssam  *
1157024Ssam  * Each interface is referenced by a network interface structure,
1167024Ssam  * vs_if, which the routing code uses to locate the interface.
1177024Ssam  * This structure contains the output queue for the interface, its address, ...
1187024Ssam  * We also have, for each interface, a UBA interface structure, which
1197024Ssam  * contains information about the UNIBUS resources held by the interface:
1207024Ssam  * map registers, buffered data paths, etc.  Information is cached in this
1217024Ssam  * structure for use by the if_uba.c routines in running the interface
1227024Ssam  * efficiently.
1237024Ssam  */
1247024Ssam struct	vv_softc {
1257024Ssam 	struct	ifnet vs_if;		/* network-visible interface */
1267024Ssam 	struct	ifuba vs_ifuba;		/* UNIBUS resources */
127*21779Skarels 	int	vs_host;
12811192Ssam 	short	vs_oactive;		/* is output active */
1297024Ssam 	short	vs_olen;		/* length of last output */
13015794Sleres 	u_short	vs_lastx;		/* address of last packet sent */
13115794Sleres 	u_short	vs_lastr;		/* address of last packet received */
13211192Ssam 	short	vs_tries;		/* transmit current retry count */
1337024Ssam 	short	vs_init;		/* number of ring inits */
13420997Skarels 	short	vs_refused;		/* number of packets refused */
13515794Sleres 	short	vs_timeouts;		/* number of transmit timeouts */
13620997Skarels 	short	vs_otimeout;		/* number of output timeouts */
13720997Skarels 	short	vs_ibadf;		/* number of input bad formats */
13820997Skarels 	short	vs_parity;		/* number of parity errors on 10 meg, */
13920997Skarels 					/* link data errors on 80 meg */
1407024Ssam } vv_softc[NVV];
1417024Ssam 
14220997Skarels /*
14320997Skarels  * probe the interface to see that the registers exist, and then
14420997Skarels  * cause an interrupt to find its vector
14520997Skarels  */
1467024Ssam vvprobe(reg)
1477024Ssam 	caddr_t reg;
1487024Ssam {
1497024Ssam 	register int br, cvec;
15016581Skarels 	register struct vvreg *addr;
1517024Ssam 
1527024Ssam #ifdef lint
15315764Sleres 	br = 0; cvec = br; br = cvec;
1547024Ssam #endif
15516581Skarels 	addr = (struct vvreg *)reg;
15620997Skarels 
1577024Ssam 	/* reset interface, enable, and wait till dust settles */
1587024Ssam 	addr->vvicsr = VV_RST;
1597024Ssam 	addr->vvocsr = VV_RST;
16015764Sleres 	DELAY(100000);
16120997Skarels 
1627024Ssam 	/* generate interrupt by doing 1 word DMA from 0 in uba space!! */
1637024Ssam 	addr->vvoba = 0;		/* low 16 bits */
1647024Ssam 	addr->vvoea = 0;		/* extended bits */
1657024Ssam 	addr->vvowc = -1;		/* for 1 word */
16620997Skarels 	addr->vvocsr = VV_IEN | VV_DEN;	/* start the DMA, with interrupt */
1677024Ssam 	DELAY(100000);
16820997Skarels 	addr->vvocsr = VV_RST;		/* clear out the CSR */
1697024Ssam 	if (cvec && cvec != 0x200)
17015764Sleres 		cvec -= 4;		/* backup so vector => receive */
1717024Ssam 	return(1);
1727024Ssam }
1737024Ssam 
1747024Ssam /*
1757024Ssam  * Interface exists: make available by filling in network interface
1767024Ssam  * record.  System will initialize the interface when it is ready
1777024Ssam  * to accept packets.
1787024Ssam  */
1797024Ssam vvattach(ui)
1807024Ssam 	struct uba_device *ui;
1817024Ssam {
18215764Sleres 	register struct vv_softc *vs;
1837024Ssam 
18415764Sleres 	vs = &vv_softc[ui->ui_unit];
1857024Ssam 	vs->vs_if.if_unit = ui->ui_unit;
1867024Ssam 	vs->vs_if.if_name = "vv";
1877024Ssam 	vs->vs_if.if_mtu = VVMTU;
188*21779Skarels 	vs->vs_if.if_flags = IFF_BROADCAST;
1897024Ssam 	vs->vs_if.if_init = vvinit;
19013057Ssam 	vs->vs_if.if_ioctl = vvioctl;
1917024Ssam 	vs->vs_if.if_output = vvoutput;
19211209Ssam 	vs->vs_if.if_reset = vvreset;
19315794Sleres 	vs->vs_if.if_timer = 0;
19415794Sleres 	vs->vs_if.if_watchdog = vvwatchdog;
1957640Ssam 	vs->vs_ifuba.ifu_flags = UBA_CANTWAIT | UBA_NEEDBDP | UBA_NEED16;
19612354Smo #if defined(VAX750)
19712354Smo 	/* don't chew up 750 bdp's */
19812354Smo 	if (cpu == VAX_750 && ui->ui_unit > 0)
19912354Smo 		vs->vs_ifuba.ifu_flags &= ~UBA_NEEDBDP;
20012354Smo #endif
2017024Ssam 	if_attach(&vs->vs_if);
2027024Ssam }
2037024Ssam 
2047024Ssam /*
2057024Ssam  * Reset of interface after UNIBUS reset.
2067024Ssam  * If interface is on specified uba, reset its state.
2077024Ssam  */
2087024Ssam vvreset(unit, uban)
2097024Ssam 	int unit, uban;
2107024Ssam {
2117024Ssam 	register struct uba_device *ui;
2127024Ssam 
2137024Ssam 	if (unit >= NVV || (ui = vvinfo[unit]) == 0 || ui->ui_alive == 0 ||
2147024Ssam 	    ui->ui_ubanum != uban)
2157024Ssam 		return;
2167024Ssam 	printf(" vv%d", unit);
2177024Ssam 	vvinit(unit);
2187024Ssam }
2197024Ssam 
2207024Ssam /*
2217024Ssam  * Initialization of interface; clear recorded pending
2227024Ssam  * operations, and reinitialize UNIBUS usage.
2237024Ssam  */
2247024Ssam vvinit(unit)
2257024Ssam 	int unit;
2267024Ssam {
22715764Sleres 	register struct vv_softc *vs;
22815764Sleres 	register struct uba_device *ui;
2297024Ssam 	register struct vvreg *addr;
23016581Skarels 	register int ubainfo, s;
2317024Ssam 
23215764Sleres 	vs = &vv_softc[unit];
23315764Sleres 	ui = vvinfo[unit];
23420997Skarels 
235*21779Skarels 	if (vs->vs_if.if_addrlist == (struct ifaddr *)0)
23613057Ssam 		return;
23720997Skarels 
2387640Ssam 	addr = (struct vvreg *)ui->ui_addr;
2397024Ssam 	if (if_ubainit(&vs->vs_ifuba, ui->ui_ubanum,
24015764Sleres 	    sizeof (struct vv_header), (int)btoc(VVMTU)) == 0) {
24115794Sleres 		printf("vv%d: can't initialize, if_ubainit() failed\n", unit);
2427640Ssam 		vs->vs_if.if_flags &= ~IFF_UP;
2437024Ssam 		return;
2447024Ssam 	}
24520997Skarels 
2467024Ssam 	/*
24715764Sleres 	 * Now that the uba is set up, figure out our address and
24815764Sleres 	 * update complete our host address.
2497640Ssam 	 */
250*21779Skarels 	if ((vs->vs_host = vvidentify(unit)) == -1) {
25115794Sleres 		vs->vs_if.if_flags &= ~IFF_UP;
25215794Sleres 		return;
25315794Sleres 	}
254*21779Skarels 	printf("vv%d: host %d\n", unit, vs->vs_host);
25520997Skarels 
2567640Ssam 	/*
25720997Skarels 	 * Reset the interface, and stay in the ring
2587640Ssam 	 */
25920997Skarels 	addr->vvocsr = VV_RST;			/* take over output */
26020997Skarels 	addr->vvocsr = VV_CPB;			/* clear packet buffer */
26120997Skarels 	addr->vvicsr = VV_RST | VV_HEN;		/* take over input, */
26220997Skarels 						/* keep relay closed */
26312351Smo 	DELAY(500000);				/* let contacts settle */
26420997Skarels 
26520997Skarels 	vs->vs_init = 0;			/* clear counters, etc. */
26620997Skarels 	vs->vs_refused = 0;
26715794Sleres 	vs->vs_timeouts = 0;
26820997Skarels 	vs->vs_otimeout = 0;
26920997Skarels 	vs->vs_ibadf = 0;
27020997Skarels 	vs->vs_parity = 0;
27115794Sleres 	vs->vs_lastx = 256;			/* an invalid address */
27215794Sleres 	vs->vs_lastr = 256;			/* an invalid address */
27320997Skarels 
2747640Ssam 	/*
2757640Ssam 	 * Hang a receive and start any
2767640Ssam 	 * pending writes by faking a transmit complete.
2777640Ssam 	 */
2787640Ssam 	s = splimp();
2797640Ssam 	ubainfo = vs->vs_ifuba.ifu_r.ifrw_info;
28013057Ssam 	addr->vviba = (u_short)ubainfo;
28113057Ssam 	addr->vviea = (u_short)(ubainfo >> 16);
28220997Skarels 	addr->vviwc = -(VVBUFSIZE) >> 1;
28320997Skarels 	addr->vvicsr = VV_IEN | VV_HEN | VV_DEN | VV_ENB;
2847640Ssam 	vs->vs_oactive = 1;
285*21779Skarels 	vs->vs_if.if_flags |= IFF_RUNNING;
2867640Ssam 	vvxint(unit);
2877640Ssam 	splx(s);
2887640Ssam }
2897640Ssam 
2907640Ssam /*
29120997Skarels  * Do a moderately thorough self-test in all three modes. Mostly
29220997Skarels  * to keeps defective nodes off the ring, rather than to be especially
29320997Skarels  * thorough. The key issue is to detect any cable breaks before joining
29420997Skarels  * the ring. Return our node address on success, return -1 on failure.
29520997Skarels  *
2967640Ssam  */
29720997Skarels 
29820997Skarels /* the three self-test modes */
29920997Skarels static u_short vv_modes[] = {
30020997Skarels 	VV_STE|VV_LPB,			/* digital loopback */
30120997Skarels 	VV_STE,				/* analog loopback */
30220997Skarels 	VV_HEN				/* network mode */
30320997Skarels };
30420997Skarels 
30511209Ssam vvidentify(unit)
30613057Ssam 	int unit;
30711209Ssam {
30815764Sleres 	register struct vv_softc *vs;
30915764Sleres 	register struct uba_device *ui;
3107640Ssam 	register struct vvreg *addr;
31116581Skarels 	register struct mbuf *m;
31216581Skarels 	register struct vv_header *v;
31320997Skarels 	register int ubainfo;
31420997Skarels 	register int i, successes, failures, waitcount;
31520997Skarels 	u_short shost = -1;
3167640Ssam 
31720997Skarels 	vs = &vv_softc[unit];
31820997Skarels 	ui = vvinfo[unit];
31920997Skarels 	addr = (struct vvreg *)ui->ui_addr;
32020997Skarels 
3217640Ssam 	/*
3227024Ssam 	 * Build a multicast message to identify our address
32320997Skarels 	 * We need do this only once, since nobody else is about to use
32420997Skarels 	 * the intermediate transmit buffer (ifu_w.ifrw_addr) that
32520997Skarels 	 * if_ubainit() aquired for us.
3267024Ssam 	 */
32711209Ssam 	m = m_get(M_DONTWAIT, MT_HEADER);
32815794Sleres 	if (m == NULL) {
32915794Sleres 		printf("vv%d: can't initialize, m_get() failed\n", unit);
33013057Ssam 		return (0);
33115794Sleres 	}
33211192Ssam 	m->m_next = 0;
3337024Ssam 	m->m_off = MMINOFF;
3347024Ssam 	m->m_len = sizeof(struct vv_header);
3357024Ssam 	v = mtod(m, struct vv_header *);
33611192Ssam 	v->vh_dhost = VV_BROADCAST;	/* multicast destination address */
3377024Ssam 	v->vh_shost = 0;		/* will be overwritten with ours */
3387024Ssam 	v->vh_version = RING_VERSION;
33920997Skarels 	v->vh_type = RING_DIAGNOSTICS;
3407024Ssam 	v->vh_info = 0;
34120997Skarels 	/* map xmit message into uba, copying to intermediate buffer */
34220997Skarels 	vs->vs_olen = if_wubaput(&vs->vs_ifuba, m);
34320997Skarels 
3447024Ssam 	/*
34520997Skarels 	 * For each of the modes (digital, analog, network), go through
34620997Skarels 	 * a self-test that requires me to send VVIDENTSUCC good packets
34720997Skarels 	 * in VVIDENTRETRY attempts. Use broadcast destination to find out
34820997Skarels 	 * who I am, then use this as my address to check my address match
34920997Skarels 	 * logic. Only data checked is the vh_type field.
3507024Ssam 	 */
3517640Ssam 
35220997Skarels 	for (i = 0; i < 3; i++) {
35320997Skarels 		successes = 0;	/* clear successes for this mode */
35420997Skarels 		failures = 0;	/* and clear failures, too */
3557640Ssam 
35620997Skarels 		/* take over device, and leave ring */
35720997Skarels 		addr->vvicsr = VV_RST;
35820997Skarels 		addr->vvocsr = VV_RST;
35920997Skarels 		addr->vvicsr = vv_modes[i];	/* test mode */
36020997Skarels 
36120997Skarels 		/*
36220997Skarels 		 * let the flag and token timers pop so that the init ring bit
36320997Skarels 		 * will be allowed to work, by waiting about 1 second
36420997Skarels 		 */
36520997Skarels 		DELAY(1000000L);
36620997Skarels 
36720997Skarels 		/*
36820997Skarels 		 * retry loop
36920997Skarels  		 */
37020997Skarels 		while ((successes < VVIDENTSUCC) && (failures < VVIDENTRETRY))
37120997Skarels 		{
37220997Skarels 			/* start a receive */
37320997Skarels 			ubainfo = vs->vs_ifuba.ifu_r.ifrw_info;
37420997Skarels 			addr->vvicsr = VV_RST | vv_modes[i]; /* abort last */
37520997Skarels 			addr->vviba = (u_short) ubainfo;
37620997Skarels 			addr->vviea = (u_short) (ubainfo >> 16);
37720997Skarels 			addr->vviwc = -(VVBUFSIZE) >> 1;
37820997Skarels 			addr->vvicsr = vv_modes[i] | VV_DEN | VV_ENB;
37920997Skarels 
38020997Skarels 			/* purge stale data from BDP */
38120997Skarels 			if (vs->vs_ifuba.ifu_flags & UBA_NEEDBDP)
38220997Skarels 				UBAPURGE(vs->vs_ifuba.ifu_uba,
38320997Skarels 				    vs->vs_ifuba.ifu_w.ifrw_bdp);
38420997Skarels 
38520997Skarels 			/* do a transmit */
38620997Skarels 			ubainfo = vs->vs_ifuba.ifu_w.ifrw_info;
38720997Skarels 			addr->vvocsr = VV_RST;	/* abort last try */
38820997Skarels 			addr->vvoba = (u_short) ubainfo;
38920997Skarels 			addr->vvoea = (u_short) (ubainfo >> 16);
39020997Skarels 			addr->vvowc = -((vs->vs_olen + 1) >> 1);
39120997Skarels 			addr->vvocsr = VV_CPB | VV_DEN | VV_INR | VV_ENB;
39220997Skarels 
39320997Skarels 			/* poll receive side for completion */
39420997Skarels 			DELAY(10000);		/* give it a chance */
39520997Skarels 			for (waitcount = 0; waitcount < 10; waitcount++) {
39620997Skarels 				if (addr->vvicsr & VV_RDY)
39720997Skarels 					goto gotit;
39820997Skarels 				DELAY(1000);
39920997Skarels 			}
40020997Skarels 			failures++;		/* no luck */
40111209Ssam 			continue;
40220997Skarels 
40320997Skarels gotit:			/* we got something--is it any good? */
40420997Skarels 			if ((addr->vvicsr & (VVRERR|VV_LDE)) ||
405*21779Skarels 			    (addr->vvocsr & (VVXERR|VV_RFS))) {
40620997Skarels 				failures++;
40720997Skarels 				continue;
40820997Skarels 			}
40920997Skarels 
41020997Skarels 			/* Purge BDP before looking at received packet */
41120997Skarels 			if (vs->vs_ifuba.ifu_flags & UBA_NEEDBDP)
41220997Skarels 				UBAPURGE(vs->vs_ifuba.ifu_uba,
41320997Skarels 				    vs->vs_ifuba.ifu_r.ifrw_bdp);
41420997Skarels 			m = if_rubaget(&vs->vs_ifuba,
41520997Skarels 			    sizeof(struct vv_header), 0);
41620997Skarels 			if (m != NULL)
41720997Skarels 				m_freem(m);
41820997Skarels 
41920997Skarels 			v = (struct vv_header *)(vs->vs_ifuba.ifu_r.ifrw_addr);
42020997Skarels 
42120997Skarels 			/* check message type, catch our node address */
42220997Skarels 			if ((v->vh_type & 0xff) == RING_DIAGNOSTICS) {
42320997Skarels 				if (shost == -1) {
42420997Skarels 					shost = v->vh_shost & 0xff;
42520997Skarels 					/* send to ourself now */
42620997Skarels 					((struct vv_header *)
42720997Skarels 					    (vs->vs_ifuba.ifu_r.ifrw_addr))
42820997Skarels 					    ->vh_dhost = shost;
42920997Skarels 				}
43020997Skarels 				successes++;
43120997Skarels 				v->vh_type = 0;  /* clear to check again */
43220997Skarels 			}
43311192Ssam 		}
43420997Skarels 
43520997Skarels 		if (failures >= VVIDENTRETRY)
43620997Skarels 		{
43720997Skarels 			printf("vv%d: failed self-test after %d tries \
43820997Skarels in %s mode\n",
43920997Skarels 			    unit, VVIDENTRETRY, i == 0 ? "digital loopback" :
44020997Skarels 			    (i == 1 ? "analog loopback" : "network"));
44120997Skarels 			printf("vv%d: icsr = %b, ocsr = %b\n",
44220997Skarels 			    unit, 0xffff & addr->vvicsr, VV_IBITS,
44320997Skarels 			    0xffff & addr->vvocsr, VV_OBITS);
44420997Skarels 			addr->vvicsr = VV_RST;	/* kill the sick board */
44520997Skarels 			addr->vvocsr = VV_RST;
44620997Skarels 			shost = -1;
44720997Skarels 			goto done;
44820997Skarels 		}
44911192Ssam 	}
45020997Skarels 
45120997Skarels done:
45220997Skarels 	/* deallocate mbuf used for send packet (won't be one, anyways) */
45315794Sleres 	if (vs->vs_ifuba.ifu_xtofree) {
4547024Ssam 		m_freem(vs->vs_ifuba.ifu_xtofree);
45515794Sleres 		vs->vs_ifuba.ifu_xtofree = 0;
45615794Sleres 	}
45720997Skarels 
45820997Skarels 	return(shost);
4597024Ssam }
4607024Ssam 
4617024Ssam /*
4627024Ssam  * Start or restart output on interface.
46311192Ssam  * If interface is active, this is a retransmit, so just
46411192Ssam  * restuff registers and go.
4657024Ssam  * If interface is not already active, get another datagram
4667024Ssam  * to send off of the interface queue, and map it to the interface
4677024Ssam  * before starting the output.
4687024Ssam  */
4697024Ssam vvstart(dev)
4707024Ssam 	dev_t dev;
4717024Ssam {
47216581Skarels 	register struct uba_device *ui;
47315764Sleres 	register struct vv_softc *vs;
4747024Ssam 	register struct vvreg *addr;
47516581Skarels 	register struct mbuf *m;
47616581Skarels 	register int unit, ubainfo, dest, s;
4777024Ssam 
47816581Skarels 	unit = VVUNIT(dev);
47915764Sleres 	ui = vvinfo[unit];
48015764Sleres 	vs = &vv_softc[unit];
4817024Ssam 	if (vs->vs_oactive)
4827024Ssam 		goto restart;
4837024Ssam 	/*
4847024Ssam 	 * Not already active: dequeue another request
4857024Ssam 	 * and map it to the UNIBUS.  If no more requests,
4867024Ssam 	 * just return.
4877024Ssam 	 */
48815794Sleres 	s = splimp();
4897024Ssam 	IF_DEQUEUE(&vs->vs_if.if_snd, m);
49015794Sleres 	splx(s);
49111209Ssam 	if (m == NULL) {
4927024Ssam 		vs->vs_oactive = 0;
4937024Ssam 		return;
4947024Ssam 	}
4957024Ssam 	dest = mtod(m, struct vv_header *)->vh_dhost;
4967024Ssam 	vs->vs_olen = if_wubaput(&vs->vs_ifuba, m);
4977024Ssam 	vs->vs_lastx = dest;
4987024Ssam restart:
4997024Ssam 	/*
5007024Ssam 	 * Have request mapped to UNIBUS for transmission.
50115794Sleres 	 * Purge any stale data from this BDP, and start the output.
50215794Sleres 	 *
50315794Sleres 	 * Make sure this packet will fit in the interface.
5047024Ssam 	 */
50520997Skarels 	if (vs->vs_olen > VVBUFSIZE) {
50620997Skarels 		printf("vv%d vs_olen: %d > VVBUFSIZE\n", unit, vs->vs_olen);
50711192Ssam 		panic("vvdriver vs_olen botch");
50811192Ssam 	}
50920997Skarels 
51020997Skarels 	vs->vs_if.if_timer = VVTIMEOUT;
51120997Skarels 	vs->vs_oactive = 1;
51220997Skarels 
51320997Skarels 	/* ship it */
5147024Ssam 	if (vs->vs_ifuba.ifu_flags & UBA_NEEDBDP)
5157024Ssam 		UBAPURGE(vs->vs_ifuba.ifu_uba, vs->vs_ifuba.ifu_w.ifrw_bdp);
5167024Ssam 	addr = (struct vvreg *)ui->ui_addr;
5177024Ssam 	ubainfo = vs->vs_ifuba.ifu_w.ifrw_info;
5187024Ssam 	addr->vvoba = (u_short) ubainfo;
5197024Ssam 	addr->vvoea = (u_short) (ubainfo >> 16);
5207024Ssam 	addr->vvowc = -((vs->vs_olen + 1) >> 1);
52120997Skarels 	addr->vvowc = -((vs->vs_olen + 1) >> 1); /* extra byte is garbage */
52220997Skarels 	if (addr->vvocsr & VV_NOK)
52320997Skarels 		vs->vs_init++;			/* count ring inits */
5247024Ssam 	addr->vvocsr = VV_IEN | VV_CPB | VV_DEN | VV_INR | VV_ENB;
52515794Sleres 	vs->vs_if.if_timer = VVTIMEOUT;
5267024Ssam 	vs->vs_oactive = 1;
5277024Ssam }
5287024Ssam 
5297024Ssam /*
53020997Skarels  * proNET transmit interrupt
5317024Ssam  * Start another output if more data to send.
5327024Ssam  */
5337024Ssam vvxint(unit)
5347024Ssam 	int unit;
5357024Ssam {
53615764Sleres 	register struct uba_device *ui;
53715764Sleres 	register struct vv_softc *vs;
5387024Ssam 	register struct vvreg *addr;
5397024Ssam 	register int oc;
5407024Ssam 
54115764Sleres 	ui = vvinfo[unit];
54215764Sleres 	vs = &vv_softc[unit];
54315794Sleres 	vs->vs_if.if_timer = 0;
5447024Ssam 	addr = (struct vvreg *)ui->ui_addr;
5457024Ssam 	oc = 0xffff & (addr->vvocsr);
5467024Ssam 	if (vs->vs_oactive == 0) {
54720997Skarels 		vvprintf("vv%d: stray interrupt vvocsr = %b\n", unit,
54815764Sleres 		    oc, VV_OBITS);
5497024Ssam 		return;
5507024Ssam 	}
55120997Skarels 
55220997Skarels 	/*
55320997Skarels 	 * we retransmit on soft error
55420997Skarels 	 * TODO: sort retransmits to end of queue if possible!
55520997Skarels 	 */
55620997Skarels 	if (oc & (VV_OPT | VV_RFS)) {
55711192Ssam 		if (vs->vs_tries++ < VVRETRY) {
5587024Ssam 			if (oc & VV_OPT)
55920997Skarels 				vs->vs_otimeout++;
56020997Skarels 			if (oc & VV_RFS) {
56120997Skarels 				vs->vs_if.if_collisions++;
56220997Skarels 				vs->vs_refused++;
56320997Skarels 			}
56411192Ssam 			vvstart(unit);		/* restart this message */
5657024Ssam 			return;
5667024Ssam 		}
5677024Ssam 	}
5687024Ssam 	vs->vs_if.if_opackets++;
5697024Ssam 	vs->vs_oactive = 0;
5707024Ssam 	vs->vs_tries = 0;
57120997Skarels 
5727024Ssam 	if (oc & VVXERR) {
5737024Ssam 		vs->vs_if.if_oerrors++;
57420997Skarels 		vvprintf("vv%d: error vvocsr = %b\n", unit, 0xffff & oc,
57515764Sleres 		    VV_OBITS);
5767024Ssam 	}
5777024Ssam 	if (vs->vs_ifuba.ifu_xtofree) {
5787024Ssam 		m_freem(vs->vs_ifuba.ifu_xtofree);
5797024Ssam 		vs->vs_ifuba.ifu_xtofree = 0;
5807024Ssam 	}
5817024Ssam 	vvstart(unit);
5827024Ssam }
5837024Ssam 
5847024Ssam /*
58515794Sleres  * Transmit watchdog timer routine.
58615794Sleres  * This routine gets called when we lose a transmit interrupt.
58715794Sleres  * The best we can do is try to restart output.
58815794Sleres  */
58915794Sleres vvwatchdog(unit)
59015794Sleres 	int unit;
59115794Sleres {
59215794Sleres 	register struct vv_softc *vs;
59315794Sleres 	register int s;
59415794Sleres 
59515794Sleres 	vs = &vv_softc[unit];
59620997Skarels 	vvprintf("vv%d: lost a transmit interrupt.\n", unit);
59715794Sleres 	vs->vs_timeouts++;
59815794Sleres 	s = splimp();
59915794Sleres 	vvstart(unit);
60015794Sleres 	splx(s);
60115794Sleres }
60215794Sleres 
60315794Sleres /*
60420997Skarels  * proNET interface receiver interrupt.
6057024Ssam  * If input error just drop packet.
60615764Sleres  * Otherwise purge input buffered data path and examine
6077024Ssam  * packet to determine type.  If can't determine length
60815764Sleres  * from type, then have to drop packet.  Otherwise decapsulate
6097024Ssam  * packet based on type and pass to type specific higher-level
6107024Ssam  * input routine.
6117024Ssam  */
6127024Ssam vvrint(unit)
6137024Ssam 	int unit;
6147024Ssam {
61515764Sleres 	register struct vv_softc *vs;
61616581Skarels 	register struct vvreg *addr;
6177024Ssam 	register struct vv_header *vv;
6187024Ssam 	register struct ifqueue *inq;
61916581Skarels 	register struct mbuf *m;
62015794Sleres 	int ubainfo, len, off, s;
6217640Ssam 	short resid;
6227024Ssam 
62315764Sleres 	vs = &vv_softc[unit];
62416581Skarels 	vs->vs_if.if_ipackets++;
62515764Sleres 	addr = (struct vvreg *)vvinfo[unit]->ui_addr;
62620997Skarels 
6277024Ssam 	/*
6287024Ssam 	 * Purge BDP; drop if input error indicated.
6297024Ssam 	 */
6307024Ssam 	if (vs->vs_ifuba.ifu_flags & UBA_NEEDBDP)
6317024Ssam 		UBAPURGE(vs->vs_ifuba.ifu_uba, vs->vs_ifuba.ifu_r.ifrw_bdp);
63220997Skarels 
63320997Skarels 	/*
63420997Skarels 	 * receive errors?
63520997Skarels 	 */
6367024Ssam 	if (addr->vvicsr & VVRERR) {
63720997Skarels 		vvprintf("vv%d: receive error, vvicsr = %b\n", unit,
63820997Skarels 		    0xffff&(addr->vvicsr), VV_IBITS);
63920997Skarels 		if (addr->vvicsr & VV_BDF)
64020997Skarels 			vs->vs_ibadf++;
6417640Ssam 		goto dropit;
6427024Ssam 	}
6437640Ssam 
6447024Ssam 	/*
64520997Skarels 	 * parity errors?
64620997Skarels 	 */
64720997Skarels 	if (addr->vvicsr & VV_LDE) {
64820997Skarels 		/* we don't have to clear it because the receive command */
64920997Skarels 		/* writes 0 to parity bit */
65020997Skarels 		vs->vs_parity++;
65120997Skarels #ifndef PRONET80
65220997Skarels 		/*
65320997Skarels 		 * only on 10 megabit proNET is VV_LDE an end-to-end parity
65420997Skarels 		 * bit. On 80 megabit, it returns to the intended use of
65520997Skarels 		 * node-to-node parity. End-to-end parity errors on 80 megabit
65620997Skarels 		 * give VV_BDF.
65720997Skarels 		 */
65820997Skarels 		goto dropit;
65920997Skarels #endif
66020997Skarels 	}
66120997Skarels 
66220997Skarels 	/*
66320997Skarels 	 * Get packet length from residual word count
6647640Ssam 	 *
6657640Ssam 	 * Compute header offset if trailer protocol
6667640Ssam 	 *
6677640Ssam 	 * Pull packet off interface.  Off is nonzero if packet
6687640Ssam 	 * has trailing header; if_rubaget will then force this header
6697640Ssam 	 * information to be at the front.  The vh_info field
6707640Ssam 	 * carries the offset to the trailer data in trailer
6717640Ssam 	 * format packets.
6727024Ssam 	 */
6737640Ssam 	vv = (struct vv_header *)(vs->vs_ifuba.ifu_r.ifrw_addr);
67411192Ssam 	vvtracehdr("vi", vv);
67520997Skarels 	resid = addr->vviwc & 01777;	/* only low 10 bits valid */
6767640Ssam 	if (resid)
67720997Skarels 		resid |= 0176000;	/* high 6 bits are undefined */
67820997Skarels 	len = ((VVBUFSIZE >> 1) + resid) << 1;
6797640Ssam 	len -= sizeof(struct vv_header);
68020997Skarels 
68120997Skarels 	if ((addr->vvicsr & VV_DPR) || len > VVMRU || len <= 0) {
68220997Skarels 		vvprintf("vv%d: len too long or short, \
68320997Skarels len = %d, vvicsr = %b\n",
68415794Sleres 			    unit, len, 0xffff&(addr->vvicsr), VV_IBITS);
6857640Ssam 		goto dropit;
68615794Sleres 	}
68720997Skarels 
68820997Skarels 	/* check the protocol header version */
68920997Skarels 	if (vv->vh_version != RING_VERSION) {
69020997Skarels 		vvprintf("vv%d: bad protocol header version %d\n",
69120997Skarels 		    unit, vv->vh_version & 0xff);
69220997Skarels 		goto dropit;
69320997Skarels 	}
69420997Skarels 
6957640Ssam #define	vvdataaddr(vv, off, type)	((type)(((caddr_t)((vv)+1)+(off))))
69613057Ssam 	if (vv->vh_type >= RING_IPTrailer &&
69713057Ssam 	     vv->vh_type < RING_IPTrailer+RING_IPNTrailer) {
6987640Ssam 		off = (vv->vh_type - RING_IPTrailer) * 512;
69915794Sleres 		if (off > VVMTU) {
70020997Skarels 			vvprintf("vv%d: off > VVMTU, off = %d, vvicsr = %b\n",
70115794Sleres 				    unit, off, 0xffff&(addr->vvicsr), VV_IBITS);
7027640Ssam 			goto dropit;
70315794Sleres 		}
7047640Ssam 		vv->vh_type = *vvdataaddr(vv, off, u_short *);
7057640Ssam 		resid = *(vvdataaddr(vv, off+2, u_short *));
70615794Sleres 		if (off + resid > len) {
70720997Skarels 			vvprintf("vv%d: trailer packet too short\n", unit);
70820997Skarels 			vvprintf("vv%d: off = %d, resid = %d, vvicsr = %b\n",
70915794Sleres 				    unit, off, resid,
71015794Sleres 				    0xffff&(addr->vvicsr), VV_IBITS);
7117640Ssam 			goto dropit;
71215794Sleres 		}
7137640Ssam 		len = off + resid;
71411209Ssam 	} else
7157640Ssam 		off = 0;
71620997Skarels 
71715794Sleres 	if (len == 0) {
71820997Skarels 		vvprintf("vv%d: len is zero, vvicsr = %b\n", unit,
71915794Sleres 			    0xffff&(addr->vvicsr), VV_IBITS);
7207640Ssam 		goto dropit;
72115794Sleres 	}
72220997Skarels 
7237640Ssam 	m = if_rubaget(&vs->vs_ifuba, len, off);
72415794Sleres 	if (m == NULL) {
72520997Skarels 		vvprintf("vv%d: if_rubaget() failed, vvicsr = %b\n", unit,
72615794Sleres 			    0xffff&(addr->vvicsr), VV_IBITS);
7277640Ssam 		goto dropit;
72815794Sleres 	}
7297640Ssam 	if (off) {
7307640Ssam 		m->m_off += 2 * sizeof(u_short);
7317640Ssam 		m->m_len -= 2 * sizeof(u_short);
7327640Ssam 	}
73311192Ssam 
73415794Sleres 	/* Keep track of source address of this packet */
73515794Sleres 	vs->vs_lastr = vv->vh_shost;
73620997Skarels 
73711192Ssam 	/*
73815764Sleres 	 * Demultiplex on packet type
73911192Ssam 	 */
7407024Ssam 	switch (vv->vh_type) {
74111192Ssam 
7427024Ssam #ifdef INET
7437024Ssam 	case RING_IP:
7447024Ssam 		schednetisr(NETISR_IP);
7457024Ssam 		inq = &ipintrq;
7467024Ssam 		break;
7477024Ssam #endif
7487024Ssam 	default:
74920997Skarels 		vvprintf("vv%d: unknown pkt type 0x%x\n", unit, vv->vh_type);
7507640Ssam 		m_freem(m);
7517024Ssam 		goto setup;
7527024Ssam 	}
75315794Sleres 	s = splimp();
7547640Ssam 	if (IF_QFULL(inq)) {
7557640Ssam 		IF_DROP(inq);
7567640Ssam 		m_freem(m);
75711209Ssam 	} else
7587640Ssam 		IF_ENQUEUE(inq, m);
75915764Sleres 
76015794Sleres 	splx(s);
7617024Ssam 	/*
76215764Sleres 	 * Reset for the next packet.
7637024Ssam 	 */
76415764Sleres setup:
76515764Sleres 	ubainfo = vs->vs_ifuba.ifu_r.ifrw_info;
76615764Sleres 	addr->vviba = (u_short) ubainfo;
76715764Sleres 	addr->vviea = (u_short) (ubainfo >> 16);
76820997Skarels 	addr->vviwc = -(VVBUFSIZE) >> 1;
76920997Skarels 	addr->vvicsr = VV_HEN | VV_IEN | VV_DEN | VV_ENB;
77015764Sleres 	return;
77111192Ssam 
77211192Ssam 	/*
77311209Ssam 	 * Drop packet on floor -- count them!!
77411192Ssam 	 */
7757640Ssam dropit:
7767640Ssam 	vs->vs_if.if_ierrors++;
7777640Ssam 	goto setup;
7787024Ssam }
7797024Ssam 
7807024Ssam /*
78120997Skarels  * proNET output routine.
7827024Ssam  * Encapsulate a packet of type family for the local net.
7837024Ssam  * Use trailer local net encapsulation if enough data in first
7847024Ssam  * packet leaves a multiple of 512 bytes of data in remainder.
7857024Ssam  */
7867024Ssam vvoutput(ifp, m0, dst)
7877024Ssam 	struct ifnet *ifp;
7887024Ssam 	struct mbuf *m0;
7897024Ssam 	struct sockaddr *dst;
7907024Ssam {
79116581Skarels 	register struct mbuf *m;
7927024Ssam 	register struct vv_header *vv;
7937640Ssam 	register int off;
79416581Skarels 	register int unit;
79516581Skarels 	register struct vvreg *addr;
79616581Skarels 	register struct vv_softc *vs;
79716581Skarels 	register int s;
79816581Skarels 	int type, dest, error;
7997024Ssam 
80016581Skarels 	m = m0;
80116581Skarels 	unit = ifp->if_unit;
80216581Skarels 	addr = (struct vvreg *)vvinfo[unit]->ui_addr;
80316581Skarels 	vs = &vv_softc[unit];
80420997Skarels 
80516581Skarels 	/*
80620997Skarels 	 * Check to see if the input side has wedged due the UBA
80720997Skarels 	 * vectoring through 0.
80816581Skarels 	 *
80916581Skarels 	 * We are lower than device ipl when we enter this routine,
81016581Skarels 	 * so if the interface is ready with an input packet then
81116581Skarels 	 * an input interrupt must have slipped through the cracks.
81216581Skarels 	 *
81316581Skarels 	 * Avoid the race with an input interrupt by watching to see
81416581Skarels 	 * if any packets come in.
81516581Skarels 	 */
81616581Skarels 	s = vs->vs_if.if_ipackets;
81716581Skarels 	if (addr->vvicsr & VV_RDY && s == vs->vs_if.if_ipackets) {
81820997Skarels 		vvprintf("vv%d: lost a receive interrupt, icsr = %b\n",
81916581Skarels 			    unit, 0xffff&(addr->vvicsr), VV_IBITS);
82016581Skarels 		s = splimp();
82116581Skarels 		vvrint(unit);
82216581Skarels 		splx(s);
82316581Skarels 	}
82416581Skarels 
8257024Ssam 	switch (dst->sa_family) {
82611192Ssam 
8277024Ssam #ifdef INET
82815764Sleres 	case AF_INET:
829*21779Skarels 		if (in_broadcast(((struct sockaddr_in *)dst)->sin_addr))
830*21779Skarels 			dest = VV_BROADCAST;
831*21779Skarels 		else
832*21779Skarels 			dest = in_lnaof(((struct sockaddr_in *)dst)->sin_addr);
83320997Skarels #ifdef LOOPBACK
834*21779Skarels 		if (dest == vs->vs_host && (loif.if_flags & IFF_UP))
835*21779Skarels 			return (looutput(&loif, m0, dst));
83620997Skarels #endif LOOPBACK
837*21779Skarels 		if (dest >= 0x100) {
8387640Ssam 			error = EPERM;
8397640Ssam 			goto bad;
8407640Ssam 		}
8417640Ssam 		off = ntohs((u_short)mtod(m, struct ip *)->ip_len) - m->m_len;
84220997Skarels 		/*
84320997Skarels 		 * Trailerize, if the configuration allows it.
84420997Skarels 		 * TODO: Need per host negotiation.
84520997Skarels 		 */
84613090Ssam 		if ((ifp->if_flags & IFF_NOTRAILERS) == 0)
84713090Ssam 		if (off > 0 && (off & 0x1ff) == 0 &&
8487640Ssam 		    m->m_off >= MMINOFF + 2 * sizeof (u_short)) {
8497640Ssam 			type = RING_IPTrailer + (off>>9);
8507640Ssam 			m->m_off -= 2 * sizeof (u_short);
8517640Ssam 			m->m_len += 2 * sizeof (u_short);
8527640Ssam 			*mtod(m, u_short *) = RING_IP;
8537640Ssam 			*(mtod(m, u_short *) + 1) = m->m_len;
8547640Ssam 			goto gottrailertype;
8557640Ssam 		}
8567024Ssam 		type = RING_IP;
8577024Ssam 		off = 0;
8587024Ssam 		goto gottype;
8597024Ssam #endif
8607024Ssam 	default:
86116581Skarels 		printf("vv%d: can't handle af%d\n", unit, dst->sa_family);
8627640Ssam 		error = EAFNOSUPPORT;
8637640Ssam 		goto bad;
8647024Ssam 	}
8657024Ssam 
8667024Ssam gottrailertype:
8677024Ssam 	/*
8687024Ssam 	 * Packet to be sent as trailer: move first packet
8697024Ssam 	 * (control information) to end of chain.
8707024Ssam 	 */
8717024Ssam 	while (m->m_next)
8727024Ssam 		m = m->m_next;
8737024Ssam 	m->m_next = m0;
8747024Ssam 	m = m0->m_next;
8757024Ssam 	m0->m_next = 0;
8767024Ssam 	m0 = m;
8777024Ssam gottype:
8787024Ssam 	/*
8797024Ssam 	 * Add local net header.  If no space in first mbuf,
8807024Ssam 	 * allocate another.
8817024Ssam 	 */
8827024Ssam 	if (m->m_off > MMAXOFF ||
8837024Ssam 	    MMINOFF + sizeof (struct vv_header) > m->m_off) {
88411209Ssam 		m = m_get(M_DONTWAIT, MT_HEADER);
88511209Ssam 		if (m == NULL) {
8867640Ssam 			error = ENOBUFS;
8877640Ssam 			goto bad;
8887024Ssam 		}
8897024Ssam 		m->m_next = m0;
8907024Ssam 		m->m_off = MMINOFF;
8917024Ssam 		m->m_len = sizeof (struct vv_header);
8927024Ssam 	} else {
8937024Ssam 		m->m_off -= sizeof (struct vv_header);
8947024Ssam 		m->m_len += sizeof (struct vv_header);
8957024Ssam 	}
8967024Ssam 	vv = mtod(m, struct vv_header *);
897*21779Skarels 	vv->vh_shost = vs->vs_host;
898*21779Skarels 	vv->vh_dhost = dest;
8997024Ssam 	vv->vh_version = RING_VERSION;
9007024Ssam 	vv->vh_type = type;
9017640Ssam 	vv->vh_info = off;
90211192Ssam 	vvtracehdr("vo", vv);
9037024Ssam 
9047024Ssam 	/*
9057024Ssam 	 * Queue message on interface, and start output if interface
9067024Ssam 	 * not yet active.
9077024Ssam 	 */
9087024Ssam 	s = splimp();
9097640Ssam 	if (IF_QFULL(&ifp->if_snd)) {
9107640Ssam 		IF_DROP(&ifp->if_snd);
9117640Ssam 		error = ENOBUFS;
9127640Ssam 		goto qfull;
9137640Ssam 	}
9147024Ssam 	IF_ENQUEUE(&ifp->if_snd, m);
91516581Skarels 	if (vs->vs_oactive == 0)
91616581Skarels 		vvstart(unit);
9177024Ssam 	splx(s);
9187640Ssam 	return (0);
9197640Ssam qfull:
9207640Ssam 	m0 = m;
9217640Ssam 	splx(s);
9227640Ssam bad:
9237640Ssam 	m_freem(m0);
9247640Ssam 	return(error);
9257024Ssam }
9267024Ssam 
9277024Ssam /*
92813057Ssam  * Process an ioctl request.
92913057Ssam  */
93013057Ssam vvioctl(ifp, cmd, data)
93113057Ssam 	register struct ifnet *ifp;
93213057Ssam 	int cmd;
93313057Ssam 	caddr_t data;
93413057Ssam {
935*21779Skarels 	struct ifaddr *ifa = (struct ifaddr *) data;
936*21779Skarels 	int s = splimp(), error = 0;
93713057Ssam 
93813057Ssam 	switch (cmd) {
93913057Ssam 
94013057Ssam 	case SIOCSIFADDR:
941*21779Skarels 		if ((ifp->if_flags & IFF_RUNNING) == 0)
94213057Ssam 			vvinit(ifp->if_unit);
943*21779Skarels                 /*
944*21779Skarels                  * Attempt to check agreement of protocol address
945*21779Skarels                  * and board address.
946*21779Skarels                  */
947*21779Skarels 		switch (ifa->ifa_addr.sa_family) {
948*21779Skarels                 case AF_INET:
949*21779Skarels 			if (in_lnaof(IA_SIN(ifa)->sin_addr) !=
950*21779Skarels 			    vv_softc[ifp->if_unit].vs_host)
951*21779Skarels 				return (EADDRNOTAVAIL);
952*21779Skarels 			break;
953*21779Skarels 		}
954*21779Skarels 		ifp->if_flags |= IFF_UP;
95513057Ssam 		break;
95613057Ssam 
95713057Ssam 	default:
95813057Ssam 		error = EINVAL;
95913057Ssam 	}
96013057Ssam 	splx(s);
961*21779Skarels 	return (error);
96213057Ssam }
963