xref: /csrg-svn/sys/vax/if/if_vv.c (revision 20997)
1*20997Skarels /*	if_vv.c	6.7	85/05/22	*/
27024Ssam 
39799Ssam #include "vv.h"
411192Ssam 
57024Ssam /*
6*20997Skarels  * Proteon proNET-10 and proNET-80 token ring driver.
7*20997Skarels  * The name of this device driver derives from the old MIT
8*20997Skarels  * name of V2LNI for the proNET hardware, would would abbreviate
9*20997Skarels  * to "v2", but this won't work right. Thus the name is "vv".
1011192Ssam  *
11*20997Skarels  * This driver is compatible with the proNET 10 meagbit and
12*20997Skarels  * 80 megabit token ring interfaces (models p1000 and p1080).
13*20997Skarels  *
14*20997Skarels  * TRAILERS: You must turn off trailers via ifconfig if you want to share
15*20997Skarels  * a ring with software using the following protocol types:
16*20997Skarels  *  3: Address Resolution Protocol
17*20997Skarels  *  4: HDLC (old Proteon drivers)
18*20997Skarels  *  5: VAX Debugging Protocol (never used)
19*20997Skarels  * This is because the protocol type values chosen for trailers
20*20997Skarels  * conflict with these protocols. It's too late to change either now.
21*20997Skarels  *
22*20997Skarels  * HARDWARE COMPATABILITY: This driver requires that the HSBU (p1001)
23*20997Skarels  * have a serial number >= 040, which is about March, 1982. Older
24*20997Skarels  * HSBUs do not carry across 64kbyte boundaries. The old warning
25*20997Skarels  * about use without Wire Centers applies only to CTL (p1002) cards with
26*20997Skarels  * serial <= 057, which have not received ECO 176-743, which was
27*20997Skarels  * implemented in March, 1982. Most such CTLs have received this ECO,
28*20997Skarels  * 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"
478421Swnj #include "../netinet/ip.h"
488421Swnj #include "../netinet/ip_var.h"
498465Sroot 
5015794Sleres #include "../vax/cpu.h"
5111209Ssam #include "../vax/mtpr.h"
5217117Sbloom #include "if_vv.h"
5317117Sbloom #include "if_uba.h"
548465Sroot #include "../vaxuba/ubareg.h"
558465Sroot #include "../vaxuba/ubavar.h"
567024Ssam 
577024Ssam /*
58*20997Skarels  * 80 megabit configuration
59*20997Skarels  * Uncomment the next line if you are using the 80 megabit system. The
60*20997Skarels  * only change is the disposition of packets with parity/link_data_error
61*20997Skarels  * indication.
627024Ssam  */
63*20997Skarels /* #define PRONET80 */
647024Ssam 
65*20997Skarels /*
66*20997Skarels  *    maximum transmission unit definition --
67*20997Skarels  *        you can set VVMTU at anything from 576 to 2024.
68*20997Skarels  *        1536 is a popular "large" value, because it is a multiple
69*20997Skarels  *	  of 512, which the trailer scheme likes.
70*20997Skarels  *        The absolute maximum size is 2024, which is enforced.
71*20997Skarels  */
72*20997Skarels 
73*20997Skarels #define VVMTU (1024)
74*20997Skarels 
75*20997Skarels #define VVMRU (VVMTU + 16)
76*20997Skarels #define VVBUFSIZE (VVMRU + sizeof(struct vv_header))
77*20997Skarels #if VVMTU>2024
78*20997Skarels #undef VVMTU
79*20997Skarels #undef VVMRU
80*20997Skarels #undef VVBUFSIZE
81*20997Skarels #define VVBUFSIZE (2046)
82*20997Skarels #define VVMRU (VVBUFSIZE - sizeof (struct vv_header))
83*20997Skarels #define VVMTU (VVMRU - 16)
847024Ssam #endif
857024Ssam 
86*20997Skarels /*
87*20997Skarels  *   debugging and tracing stuff
88*20997Skarels  */
8916581Skarels int	vv_tracehdr = 0;	/* 1 => trace headers (slowly!!) */
90*20997Skarels #ifndef proteon
9116581Skarels int	vv_logreaderrors = 1;	/* 1 => log all read errors */
92*20997Skarels #else proteon
93*20997Skarels int	vv_logerrors = 0;	/* 1 => log all i/o errors */
94*20997Skarels #endif proteon
957640Ssam 
96*20997Skarels #define vvtracehdr  if (vv_tracehdr) vvprt_hdr
97*20997Skarels #define vvprintf    if (vv_logerrors && vs->vs_if.if_flags & IFF_DEBUG) printf
9811192Ssam 
99*20997Skarels /*
100*20997Skarels  * externals, types, etc.
101*20997Skarels  */
10216581Skarels int	vvprobe(), vvattach(), vvreset(), vvinit();
10316581Skarels int	vvidentify(), vvstart(), vvxint(), vvwatchdog();
10416581Skarels int	vvrint(), vvoutput(), vvioctl(), vvsetaddr();
1057024Ssam struct	uba_device *vvinfo[NVV];
1067024Ssam u_short vvstd[] = { 0 };
1077024Ssam struct	uba_driver vvdriver =
1087024Ssam 	{ vvprobe, 0, vvattach, 0, vvstd, "vv", vvinfo };
1097024Ssam #define	VVUNIT(x)	minor(x)
1107024Ssam 
111*20997Skarels #define LOOPBACK		/* use loopback for packets meant for us */
112*20997Skarels #ifdef	LOOPBACK
113*20997Skarels extern struct ifnet loif;
114*20997Skarels #endif
115*20997Skarels 
1167024Ssam /*
1177024Ssam  * Software status of each interface.
1187024Ssam  *
1197024Ssam  * Each interface is referenced by a network interface structure,
1207024Ssam  * vs_if, which the routing code uses to locate the interface.
1217024Ssam  * This structure contains the output queue for the interface, its address, ...
1227024Ssam  * We also have, for each interface, a UBA interface structure, which
1237024Ssam  * contains information about the UNIBUS resources held by the interface:
1247024Ssam  * map registers, buffered data paths, etc.  Information is cached in this
1257024Ssam  * structure for use by the if_uba.c routines in running the interface
1267024Ssam  * efficiently.
1277024Ssam  */
1287024Ssam struct	vv_softc {
1297024Ssam 	struct	ifnet vs_if;		/* network-visible interface */
1307024Ssam 	struct	ifuba vs_ifuba;		/* UNIBUS resources */
13111192Ssam 	short	vs_oactive;		/* is output active */
1327024Ssam 	short	vs_olen;		/* length of last output */
13315794Sleres 	u_short	vs_lastx;		/* address of last packet sent */
13415794Sleres 	u_short	vs_lastr;		/* address of last packet received */
13511192Ssam 	short	vs_tries;		/* transmit current retry count */
1367024Ssam 	short	vs_init;		/* number of ring inits */
137*20997Skarels 	short	vs_refused;		/* number of packets refused */
13815794Sleres 	short	vs_timeouts;		/* number of transmit timeouts */
139*20997Skarels 	short	vs_otimeout;		/* number of output timeouts */
140*20997Skarels 	short	vs_ibadf;		/* number of input bad formats */
141*20997Skarels 	short	vs_parity;		/* number of parity errors on 10 meg, */
142*20997Skarels 					/* link data errors on 80 meg */
1437024Ssam } vv_softc[NVV];
1447024Ssam 
145*20997Skarels /*
146*20997Skarels  * probe the interface to see that the registers exist, and then
147*20997Skarels  * cause an interrupt to find its vector
148*20997Skarels  */
1497024Ssam vvprobe(reg)
1507024Ssam 	caddr_t reg;
1517024Ssam {
1527024Ssam 	register int br, cvec;
15316581Skarels 	register struct vvreg *addr;
1547024Ssam 
1557024Ssam #ifdef lint
15615764Sleres 	br = 0; cvec = br; br = cvec;
1577024Ssam #endif
15816581Skarels 	addr = (struct vvreg *)reg;
159*20997Skarels 
1607024Ssam 	/* reset interface, enable, and wait till dust settles */
1617024Ssam 	addr->vvicsr = VV_RST;
1627024Ssam 	addr->vvocsr = VV_RST;
16315764Sleres 	DELAY(100000);
164*20997Skarels 
1657024Ssam 	/* generate interrupt by doing 1 word DMA from 0 in uba space!! */
1667024Ssam 	addr->vvoba = 0;		/* low 16 bits */
1677024Ssam 	addr->vvoea = 0;		/* extended bits */
1687024Ssam 	addr->vvowc = -1;		/* for 1 word */
169*20997Skarels 	addr->vvocsr = VV_IEN | VV_DEN;	/* start the DMA, with interrupt */
1707024Ssam 	DELAY(100000);
171*20997Skarels 	addr->vvocsr = VV_RST;		/* clear out the CSR */
1727024Ssam 	if (cvec && cvec != 0x200)
17315764Sleres 		cvec -= 4;		/* backup so vector => receive */
1747024Ssam 	return(1);
1757024Ssam }
1767024Ssam 
1777024Ssam /*
1787024Ssam  * Interface exists: make available by filling in network interface
1797024Ssam  * record.  System will initialize the interface when it is ready
1807024Ssam  * to accept packets.
1817024Ssam  */
1827024Ssam vvattach(ui)
1837024Ssam 	struct uba_device *ui;
1847024Ssam {
18515764Sleres 	register struct vv_softc *vs;
1867024Ssam 
18715764Sleres 	vs = &vv_softc[ui->ui_unit];
1887024Ssam 	vs->vs_if.if_unit = ui->ui_unit;
1897024Ssam 	vs->vs_if.if_name = "vv";
1907024Ssam 	vs->vs_if.if_mtu = VVMTU;
1917024Ssam 	vs->vs_if.if_init = vvinit;
19213057Ssam 	vs->vs_if.if_ioctl = vvioctl;
1937024Ssam 	vs->vs_if.if_output = vvoutput;
19411209Ssam 	vs->vs_if.if_reset = vvreset;
19515794Sleres 	vs->vs_if.if_timer = 0;
19615794Sleres 	vs->vs_if.if_watchdog = vvwatchdog;
1977640Ssam 	vs->vs_ifuba.ifu_flags = UBA_CANTWAIT | UBA_NEEDBDP | UBA_NEED16;
19812354Smo #if defined(VAX750)
19912354Smo 	/* don't chew up 750 bdp's */
20012354Smo 	if (cpu == VAX_750 && ui->ui_unit > 0)
20112354Smo 		vs->vs_ifuba.ifu_flags &= ~UBA_NEEDBDP;
20212354Smo #endif
2037024Ssam 	if_attach(&vs->vs_if);
2047024Ssam }
2057024Ssam 
2067024Ssam /*
2077024Ssam  * Reset of interface after UNIBUS reset.
2087024Ssam  * If interface is on specified uba, reset its state.
2097024Ssam  */
2107024Ssam vvreset(unit, uban)
2117024Ssam 	int unit, uban;
2127024Ssam {
2137024Ssam 	register struct uba_device *ui;
2147024Ssam 
2157024Ssam 	if (unit >= NVV || (ui = vvinfo[unit]) == 0 || ui->ui_alive == 0 ||
2167024Ssam 	    ui->ui_ubanum != uban)
2177024Ssam 		return;
2187024Ssam 	printf(" vv%d", unit);
2197024Ssam 	vvinit(unit);
2207024Ssam }
2217024Ssam 
2227024Ssam /*
2237024Ssam  * Initialization of interface; clear recorded pending
2247024Ssam  * operations, and reinitialize UNIBUS usage.
2257024Ssam  */
2267024Ssam vvinit(unit)
2277024Ssam 	int unit;
2287024Ssam {
22915764Sleres 	register struct vv_softc *vs;
23015764Sleres 	register struct uba_device *ui;
2317024Ssam 	register struct vvreg *addr;
23216581Skarels 	register struct sockaddr_in *sin;
23316581Skarels 	register int ubainfo, s;
2347024Ssam 
23515764Sleres 	vs = &vv_softc[unit];
23615764Sleres 	ui = vvinfo[unit];
23715764Sleres 	sin = (struct sockaddr_in *)&vs->vs_if.if_addr;
238*20997Skarels 
23915764Sleres 	/*
24015764Sleres 	 * If the network number is still zero, we've been
24115764Sleres 	 * called too soon.
24215764Sleres 	 */
24315764Sleres 	if (in_netof(sin->sin_addr) == 0)
24413057Ssam 		return;
245*20997Skarels 
2467640Ssam 	addr = (struct vvreg *)ui->ui_addr;
2477024Ssam 	if (if_ubainit(&vs->vs_ifuba, ui->ui_ubanum,
24815764Sleres 	    sizeof (struct vv_header), (int)btoc(VVMTU)) == 0) {
24915794Sleres 		printf("vv%d: can't initialize, if_ubainit() failed\n", unit);
2507640Ssam 		vs->vs_if.if_flags &= ~IFF_UP;
2517024Ssam 		return;
2527024Ssam 	}
253*20997Skarels 
2547024Ssam 	/*
25515764Sleres 	 * Now that the uba is set up, figure out our address and
25615764Sleres 	 * update complete our host address.
2577640Ssam 	 */
258*20997Skarels 	if ((vs->vs_if.if_host[0] = vvidentify(unit)) == -1) {
25915794Sleres 		vs->vs_if.if_flags &= ~IFF_UP;
26015794Sleres 		return;
26115794Sleres 	}
2627640Ssam 	printf("vv%d: host %d\n", unit, vs->vs_if.if_host[0]);
26311209Ssam 	sin->sin_addr = if_makeaddr(vs->vs_if.if_net, vs->vs_if.if_host[0]);
264*20997Skarels 
2657640Ssam 	/*
266*20997Skarels 	 * Reset the interface, and stay in the ring
2677640Ssam 	 */
268*20997Skarels 	addr->vvocsr = VV_RST;			/* take over output */
269*20997Skarels 	addr->vvocsr = VV_CPB;			/* clear packet buffer */
270*20997Skarels 	addr->vvicsr = VV_RST | VV_HEN;		/* take over input, */
271*20997Skarels 						/* keep relay closed */
27212351Smo 	DELAY(500000);				/* let contacts settle */
273*20997Skarels 
274*20997Skarels 	vs->vs_init = 0;			/* clear counters, etc. */
275*20997Skarels 	vs->vs_refused = 0;
27615794Sleres 	vs->vs_timeouts = 0;
277*20997Skarels 	vs->vs_otimeout = 0;
278*20997Skarels 	vs->vs_ibadf = 0;
279*20997Skarels 	vs->vs_parity = 0;
28015794Sleres 	vs->vs_lastx = 256;			/* an invalid address */
28115794Sleres 	vs->vs_lastr = 256;			/* an invalid address */
282*20997Skarels 
2837640Ssam 	/*
2847640Ssam 	 * Hang a receive and start any
2857640Ssam 	 * pending writes by faking a transmit complete.
2867640Ssam 	 */
2877640Ssam 	s = splimp();
2887640Ssam 	ubainfo = vs->vs_ifuba.ifu_r.ifrw_info;
28913057Ssam 	addr->vviba = (u_short)ubainfo;
29013057Ssam 	addr->vviea = (u_short)(ubainfo >> 16);
291*20997Skarels 	addr->vviwc = -(VVBUFSIZE) >> 1;
292*20997Skarels 	addr->vvicsr = VV_IEN | VV_HEN | VV_DEN | VV_ENB;
2937640Ssam 	vs->vs_oactive = 1;
29413057Ssam 	vs->vs_if.if_flags |= IFF_UP | IFF_RUNNING;
2957640Ssam 	vvxint(unit);
2967640Ssam 	splx(s);
2977640Ssam 	if_rtinit(&vs->vs_if, RTF_UP);
2987640Ssam }
2997640Ssam 
3007640Ssam /*
301*20997Skarels  * Do a moderately thorough self-test in all three modes. Mostly
302*20997Skarels  * to keeps defective nodes off the ring, rather than to be especially
303*20997Skarels  * thorough. The key issue is to detect any cable breaks before joining
304*20997Skarels  * the ring. Return our node address on success, return -1 on failure.
305*20997Skarels  *
3067640Ssam  */
307*20997Skarels 
308*20997Skarels /* the three self-test modes */
309*20997Skarels static u_short vv_modes[] = {
310*20997Skarels 	VV_STE|VV_LPB,			/* digital loopback */
311*20997Skarels 	VV_STE,				/* analog loopback */
312*20997Skarels 	VV_HEN				/* network mode */
313*20997Skarels };
314*20997Skarels 
31511209Ssam vvidentify(unit)
31613057Ssam 	int unit;
31711209Ssam {
31815764Sleres 	register struct vv_softc *vs;
31915764Sleres 	register struct uba_device *ui;
3207640Ssam 	register struct vvreg *addr;
32116581Skarels 	register struct mbuf *m;
32216581Skarels 	register struct vv_header *v;
323*20997Skarels 	register int ubainfo;
324*20997Skarels 	register int i, successes, failures, waitcount;
325*20997Skarels 	u_short shost = -1;
3267640Ssam 
327*20997Skarels 	vs = &vv_softc[unit];
328*20997Skarels 	ui = vvinfo[unit];
329*20997Skarels 	addr = (struct vvreg *)ui->ui_addr;
330*20997Skarels 
3317640Ssam 	/*
3327024Ssam 	 * Build a multicast message to identify our address
333*20997Skarels 	 * We need do this only once, since nobody else is about to use
334*20997Skarels 	 * the intermediate transmit buffer (ifu_w.ifrw_addr) that
335*20997Skarels 	 * if_ubainit() aquired for us.
3367024Ssam 	 */
33711209Ssam 	m = m_get(M_DONTWAIT, MT_HEADER);
33815794Sleres 	if (m == NULL) {
33915794Sleres 		printf("vv%d: can't initialize, m_get() failed\n", unit);
34013057Ssam 		return (0);
34115794Sleres 	}
34211192Ssam 	m->m_next = 0;
3437024Ssam 	m->m_off = MMINOFF;
3447024Ssam 	m->m_len = sizeof(struct vv_header);
3457024Ssam 	v = mtod(m, struct vv_header *);
34611192Ssam 	v->vh_dhost = VV_BROADCAST;	/* multicast destination address */
3477024Ssam 	v->vh_shost = 0;		/* will be overwritten with ours */
3487024Ssam 	v->vh_version = RING_VERSION;
349*20997Skarels 	v->vh_type = RING_DIAGNOSTICS;
3507024Ssam 	v->vh_info = 0;
351*20997Skarels 	/* map xmit message into uba, copying to intermediate buffer */
352*20997Skarels 	vs->vs_olen = if_wubaput(&vs->vs_ifuba, m);
353*20997Skarels 
3547024Ssam 	/*
355*20997Skarels 	 * For each of the modes (digital, analog, network), go through
356*20997Skarels 	 * a self-test that requires me to send VVIDENTSUCC good packets
357*20997Skarels 	 * in VVIDENTRETRY attempts. Use broadcast destination to find out
358*20997Skarels 	 * who I am, then use this as my address to check my address match
359*20997Skarels 	 * logic. Only data checked is the vh_type field.
3607024Ssam 	 */
3617640Ssam 
362*20997Skarels 	for (i = 0; i < 3; i++) {
363*20997Skarels 		successes = 0;	/* clear successes for this mode */
364*20997Skarels 		failures = 0;	/* and clear failures, too */
3657640Ssam 
366*20997Skarels 		/* take over device, and leave ring */
367*20997Skarels 		addr->vvicsr = VV_RST;
368*20997Skarels 		addr->vvocsr = VV_RST;
369*20997Skarels 		addr->vvicsr = vv_modes[i];	/* test mode */
370*20997Skarels 
371*20997Skarels 		/*
372*20997Skarels 		 * let the flag and token timers pop so that the init ring bit
373*20997Skarels 		 * will be allowed to work, by waiting about 1 second
374*20997Skarels 		 */
375*20997Skarels 		DELAY(1000000L);
376*20997Skarels 
377*20997Skarels 		/*
378*20997Skarels 		 * retry loop
379*20997Skarels  		 */
380*20997Skarels 		while ((successes < VVIDENTSUCC) && (failures < VVIDENTRETRY))
381*20997Skarels 		{
382*20997Skarels 			/* start a receive */
383*20997Skarels 			ubainfo = vs->vs_ifuba.ifu_r.ifrw_info;
384*20997Skarels 			addr->vvicsr = VV_RST | vv_modes[i]; /* abort last */
385*20997Skarels 			addr->vviba = (u_short) ubainfo;
386*20997Skarels 			addr->vviea = (u_short) (ubainfo >> 16);
387*20997Skarels 			addr->vviwc = -(VVBUFSIZE) >> 1;
388*20997Skarels 			addr->vvicsr = vv_modes[i] | VV_DEN | VV_ENB;
389*20997Skarels 
390*20997Skarels 			/* purge stale data from BDP */
391*20997Skarels 			if (vs->vs_ifuba.ifu_flags & UBA_NEEDBDP)
392*20997Skarels 				UBAPURGE(vs->vs_ifuba.ifu_uba,
393*20997Skarels 				    vs->vs_ifuba.ifu_w.ifrw_bdp);
394*20997Skarels 
395*20997Skarels 			/* do a transmit */
396*20997Skarels 			ubainfo = vs->vs_ifuba.ifu_w.ifrw_info;
397*20997Skarels 			addr->vvocsr = VV_RST;	/* abort last try */
398*20997Skarels 			addr->vvoba = (u_short) ubainfo;
399*20997Skarels 			addr->vvoea = (u_short) (ubainfo >> 16);
400*20997Skarels 			addr->vvowc = -((vs->vs_olen + 1) >> 1);
401*20997Skarels 			addr->vvocsr = VV_CPB | VV_DEN | VV_INR | VV_ENB;
402*20997Skarels 
403*20997Skarels 			/* poll receive side for completion */
404*20997Skarels 			DELAY(10000);		/* give it a chance */
405*20997Skarels 			for (waitcount = 0; waitcount < 10; waitcount++) {
406*20997Skarels 				if (addr->vvicsr & VV_RDY)
407*20997Skarels 					goto gotit;
408*20997Skarels 				DELAY(1000);
409*20997Skarels 			}
410*20997Skarels 			failures++;		/* no luck */
41111209Ssam 			continue;
412*20997Skarels 
413*20997Skarels gotit:			/* we got something--is it any good? */
414*20997Skarels 			if ((addr->vvicsr & (VVRERR|VV_LDE)) ||
415*20997Skarels 			    (ADDR->vvocsr & (VVXERR|VV_RFS))) {
416*20997Skarels 				failures++;
417*20997Skarels 				continue;
418*20997Skarels 			}
419*20997Skarels 
420*20997Skarels 			/* Purge BDP before looking at received packet */
421*20997Skarels 			if (vs->vs_ifuba.ifu_flags & UBA_NEEDBDP)
422*20997Skarels 				UBAPURGE(vs->vs_ifuba.ifu_uba,
423*20997Skarels 				    vs->vs_ifuba.ifu_r.ifrw_bdp);
424*20997Skarels 			m = if_rubaget(&vs->vs_ifuba,
425*20997Skarels 			    sizeof(struct vv_header), 0);
426*20997Skarels 			if (m != NULL)
427*20997Skarels 				m_freem(m);
428*20997Skarels 
429*20997Skarels 			v = (struct vv_header *)(vs->vs_ifuba.ifu_r.ifrw_addr);
430*20997Skarels 
431*20997Skarels 			/* check message type, catch our node address */
432*20997Skarels 			if ((v->vh_type & 0xff) == RING_DIAGNOSTICS) {
433*20997Skarels 				if (shost == -1) {
434*20997Skarels 					shost = v->vh_shost & 0xff;
435*20997Skarels 					/* send to ourself now */
436*20997Skarels 					((struct vv_header *)
437*20997Skarels 					    (vs->vs_ifuba.ifu_r.ifrw_addr))
438*20997Skarels 					    ->vh_dhost = shost;
439*20997Skarels 				}
440*20997Skarels 				successes++;
441*20997Skarels 				v->vh_type = 0;  /* clear to check again */
442*20997Skarels 			}
44311192Ssam 		}
444*20997Skarels 
445*20997Skarels 		if (failures >= VVIDENTRETRY)
446*20997Skarels 		{
447*20997Skarels 			printf("vv%d: failed self-test after %d tries \
448*20997Skarels in %s mode\n",
449*20997Skarels 			    unit, VVIDENTRETRY, i == 0 ? "digital loopback" :
450*20997Skarels 			    (i == 1 ? "analog loopback" : "network"));
451*20997Skarels 			printf("vv%d: icsr = %b, ocsr = %b\n",
452*20997Skarels 			    unit, 0xffff & addr->vvicsr, VV_IBITS,
453*20997Skarels 			    0xffff & addr->vvocsr, VV_OBITS);
454*20997Skarels 			addr->vvicsr = VV_RST;	/* kill the sick board */
455*20997Skarels 			addr->vvocsr = VV_RST;
456*20997Skarels 			shost = -1;
457*20997Skarels 			goto done;
458*20997Skarels 		}
45911192Ssam 	}
460*20997Skarels 
461*20997Skarels done:
462*20997Skarels 	/* deallocate mbuf used for send packet (won't be one, anyways) */
46315794Sleres 	if (vs->vs_ifuba.ifu_xtofree) {
4647024Ssam 		m_freem(vs->vs_ifuba.ifu_xtofree);
46515794Sleres 		vs->vs_ifuba.ifu_xtofree = 0;
46615794Sleres 	}
467*20997Skarels 
468*20997Skarels 	return(shost);
4697024Ssam }
4707024Ssam 
4717024Ssam /*
4727024Ssam  * Start or restart output on interface.
47311192Ssam  * If interface is active, this is a retransmit, so just
47411192Ssam  * restuff registers and go.
4757024Ssam  * If interface is not already active, get another datagram
4767024Ssam  * to send off of the interface queue, and map it to the interface
4777024Ssam  * before starting the output.
4787024Ssam  */
4797024Ssam vvstart(dev)
4807024Ssam 	dev_t dev;
4817024Ssam {
48216581Skarels 	register struct uba_device *ui;
48315764Sleres 	register struct vv_softc *vs;
4847024Ssam 	register struct vvreg *addr;
48516581Skarels 	register struct mbuf *m;
48616581Skarels 	register int unit, ubainfo, dest, s;
4877024Ssam 
48816581Skarels 	unit = VVUNIT(dev);
48915764Sleres 	ui = vvinfo[unit];
49015764Sleres 	vs = &vv_softc[unit];
4917024Ssam 	if (vs->vs_oactive)
4927024Ssam 		goto restart;
4937024Ssam 	/*
4947024Ssam 	 * Not already active: dequeue another request
4957024Ssam 	 * and map it to the UNIBUS.  If no more requests,
4967024Ssam 	 * just return.
4977024Ssam 	 */
49815794Sleres 	s = splimp();
4997024Ssam 	IF_DEQUEUE(&vs->vs_if.if_snd, m);
50015794Sleres 	splx(s);
50111209Ssam 	if (m == NULL) {
5027024Ssam 		vs->vs_oactive = 0;
5037024Ssam 		return;
5047024Ssam 	}
5057024Ssam 	dest = mtod(m, struct vv_header *)->vh_dhost;
5067024Ssam 	vs->vs_olen = if_wubaput(&vs->vs_ifuba, m);
5077024Ssam 	vs->vs_lastx = dest;
5087024Ssam restart:
5097024Ssam 	/*
5107024Ssam 	 * Have request mapped to UNIBUS for transmission.
51115794Sleres 	 * Purge any stale data from this BDP, and start the output.
51215794Sleres 	 *
51315794Sleres 	 * Make sure this packet will fit in the interface.
5147024Ssam 	 */
515*20997Skarels 	if (vs->vs_olen > VVBUFSIZE) {
516*20997Skarels 		printf("vv%d vs_olen: %d > VVBUFSIZE\n", unit, vs->vs_olen);
51711192Ssam 		panic("vvdriver vs_olen botch");
51811192Ssam 	}
519*20997Skarels 
520*20997Skarels 	vs->vs_if.if_timer = VVTIMEOUT;
521*20997Skarels 	vs->vs_oactive = 1;
522*20997Skarels 
523*20997Skarels 	/* ship it */
5247024Ssam 	if (vs->vs_ifuba.ifu_flags & UBA_NEEDBDP)
5257024Ssam 		UBAPURGE(vs->vs_ifuba.ifu_uba, vs->vs_ifuba.ifu_w.ifrw_bdp);
5267024Ssam 	addr = (struct vvreg *)ui->ui_addr;
5277024Ssam 	ubainfo = vs->vs_ifuba.ifu_w.ifrw_info;
5287024Ssam 	addr->vvoba = (u_short) ubainfo;
5297024Ssam 	addr->vvoea = (u_short) (ubainfo >> 16);
5307024Ssam 	addr->vvowc = -((vs->vs_olen + 1) >> 1);
531*20997Skarels 	addr->vvowc = -((vs->vs_olen + 1) >> 1); /* extra byte is garbage */
532*20997Skarels 	if (addr->vvocsr & VV_NOK)
533*20997Skarels 		vs->vs_init++;			/* count ring inits */
5347024Ssam 	addr->vvocsr = VV_IEN | VV_CPB | VV_DEN | VV_INR | VV_ENB;
53515794Sleres 	vs->vs_if.if_timer = VVTIMEOUT;
5367024Ssam 	vs->vs_oactive = 1;
5377024Ssam }
5387024Ssam 
5397024Ssam /*
540*20997Skarels  * proNET transmit interrupt
5417024Ssam  * Start another output if more data to send.
5427024Ssam  */
5437024Ssam vvxint(unit)
5447024Ssam 	int unit;
5457024Ssam {
54615764Sleres 	register struct uba_device *ui;
54715764Sleres 	register struct vv_softc *vs;
5487024Ssam 	register struct vvreg *addr;
5497024Ssam 	register int oc;
5507024Ssam 
55115764Sleres 	ui = vvinfo[unit];
55215764Sleres 	vs = &vv_softc[unit];
55315794Sleres 	vs->vs_if.if_timer = 0;
5547024Ssam 	addr = (struct vvreg *)ui->ui_addr;
5557024Ssam 	oc = 0xffff & (addr->vvocsr);
5567024Ssam 	if (vs->vs_oactive == 0) {
557*20997Skarels 		vvprintf("vv%d: stray interrupt vvocsr = %b\n", unit,
55815764Sleres 		    oc, VV_OBITS);
5597024Ssam 		return;
5607024Ssam 	}
561*20997Skarels 
562*20997Skarels 	/*
563*20997Skarels 	 * we retransmit on soft error
564*20997Skarels 	 * TODO: sort retransmits to end of queue if possible!
565*20997Skarels 	 */
566*20997Skarels 	if (oc & (VV_OPT | VV_RFS)) {
56711192Ssam 		if (vs->vs_tries++ < VVRETRY) {
5687024Ssam 			if (oc & VV_OPT)
569*20997Skarels 				vs->vs_otimeout++;
570*20997Skarels 			if (oc & VV_RFS) {
571*20997Skarels 				vs->vs_if.if_collisions++;
572*20997Skarels 				vs->vs_refused++;
573*20997Skarels 			}
57411192Ssam 			vvstart(unit);		/* restart this message */
5757024Ssam 			return;
5767024Ssam 		}
5777024Ssam 	}
5787024Ssam 	vs->vs_if.if_opackets++;
5797024Ssam 	vs->vs_oactive = 0;
5807024Ssam 	vs->vs_tries = 0;
581*20997Skarels 
5827024Ssam 	if (oc & VVXERR) {
5837024Ssam 		vs->vs_if.if_oerrors++;
58411192Ssam 		printf("vv%d: error vvocsr = %b\n", unit, 0xffff & oc,
585*20997Skarels 		vvprintf("vv%d: error vvocsr = %b\n", unit, 0xffff & oc,
58615764Sleres 		    VV_OBITS);
5877024Ssam 	}
5887024Ssam 	if (vs->vs_ifuba.ifu_xtofree) {
5897024Ssam 		m_freem(vs->vs_ifuba.ifu_xtofree);
5907024Ssam 		vs->vs_ifuba.ifu_xtofree = 0;
5917024Ssam 	}
5927024Ssam 	vvstart(unit);
5937024Ssam }
5947024Ssam 
5957024Ssam /*
59615794Sleres  * Transmit watchdog timer routine.
59715794Sleres  * This routine gets called when we lose a transmit interrupt.
59815794Sleres  * The best we can do is try to restart output.
59915794Sleres  */
60015794Sleres vvwatchdog(unit)
60115794Sleres 	int unit;
60215794Sleres {
60315794Sleres 	register struct vv_softc *vs;
60415794Sleres 	register int s;
60515794Sleres 
60615794Sleres 	vs = &vv_softc[unit];
607*20997Skarels 	vvprintf("vv%d: lost a transmit interrupt.\n", unit);
60815794Sleres 	vs->vs_timeouts++;
60915794Sleres 	s = splimp();
61015794Sleres 	vvstart(unit);
61115794Sleres 	splx(s);
61215794Sleres }
61315794Sleres 
61415794Sleres /*
615*20997Skarels  * proNET interface receiver interrupt.
6167024Ssam  * If input error just drop packet.
61715764Sleres  * Otherwise purge input buffered data path and examine
6187024Ssam  * packet to determine type.  If can't determine length
61915764Sleres  * from type, then have to drop packet.  Otherwise decapsulate
6207024Ssam  * packet based on type and pass to type specific higher-level
6217024Ssam  * input routine.
6227024Ssam  */
6237024Ssam vvrint(unit)
6247024Ssam 	int unit;
6257024Ssam {
62615764Sleres 	register struct vv_softc *vs;
62716581Skarels 	register struct vvreg *addr;
6287024Ssam 	register struct vv_header *vv;
6297024Ssam 	register struct ifqueue *inq;
63016581Skarels 	register struct mbuf *m;
63115794Sleres 	int ubainfo, len, off, s;
6327640Ssam 	short resid;
6337024Ssam 
63415764Sleres 	vs = &vv_softc[unit];
63516581Skarels 	vs->vs_if.if_ipackets++;
63615764Sleres 	addr = (struct vvreg *)vvinfo[unit]->ui_addr;
637*20997Skarels 
6387024Ssam 	/*
6397024Ssam 	 * Purge BDP; drop if input error indicated.
6407024Ssam 	 */
6417024Ssam 	if (vs->vs_ifuba.ifu_flags & UBA_NEEDBDP)
6427024Ssam 		UBAPURGE(vs->vs_ifuba.ifu_uba, vs->vs_ifuba.ifu_r.ifrw_bdp);
643*20997Skarels 
644*20997Skarels 	/*
645*20997Skarels 	 * receive errors?
646*20997Skarels 	 */
6477024Ssam 	if (addr->vvicsr & VVRERR) {
648*20997Skarels 		vvprintf("vv%d: receive error, vvicsr = %b\n", unit,
649*20997Skarels 		    0xffff&(addr->vvicsr), VV_IBITS);
650*20997Skarels 		if (addr->vvicsr & VV_BDF)
651*20997Skarels 			vs->vs_ibadf++;
6527640Ssam 		goto dropit;
6537024Ssam 	}
6547640Ssam 
6557024Ssam 	/*
656*20997Skarels 	 * parity errors?
657*20997Skarels 	 */
658*20997Skarels 	if (addr->vvicsr & VV_LDE) {
659*20997Skarels 		/* we don't have to clear it because the receive command */
660*20997Skarels 		/* writes 0 to parity bit */
661*20997Skarels 		vs->vs_parity++;
662*20997Skarels #ifndef PRONET80
663*20997Skarels 		/*
664*20997Skarels 		 * only on 10 megabit proNET is VV_LDE an end-to-end parity
665*20997Skarels 		 * bit. On 80 megabit, it returns to the intended use of
666*20997Skarels 		 * node-to-node parity. End-to-end parity errors on 80 megabit
667*20997Skarels 		 * give VV_BDF.
668*20997Skarels 		 */
669*20997Skarels 		goto dropit;
670*20997Skarels #endif
671*20997Skarels 	}
672*20997Skarels 
673*20997Skarels 	/*
674*20997Skarels 	 * Get packet length from residual word count
6757640Ssam 	 *
6767640Ssam 	 * Compute header offset if trailer protocol
6777640Ssam 	 *
6787640Ssam 	 * Pull packet off interface.  Off is nonzero if packet
6797640Ssam 	 * has trailing header; if_rubaget will then force this header
6807640Ssam 	 * information to be at the front.  The vh_info field
6817640Ssam 	 * carries the offset to the trailer data in trailer
6827640Ssam 	 * format packets.
6837024Ssam 	 */
6847640Ssam 	vv = (struct vv_header *)(vs->vs_ifuba.ifu_r.ifrw_addr);
68511192Ssam 	vvtracehdr("vi", vv);
686*20997Skarels 	resid = addr->vviwc & 01777;	/* only low 10 bits valid */
6877640Ssam 	if (resid)
688*20997Skarels 		resid |= 0176000;	/* high 6 bits are undefined */
689*20997Skarels 	len = ((VVBUFSIZE >> 1) + resid) << 1;
6907640Ssam 	len -= sizeof(struct vv_header);
691*20997Skarels 
692*20997Skarels 	if ((addr->vvicsr & VV_DPR) || len > VVMRU || len <= 0) {
693*20997Skarels 		vvprintf("vv%d: len too long or short, \
694*20997Skarels len = %d, vvicsr = %b\n",
69515794Sleres 			    unit, len, 0xffff&(addr->vvicsr), VV_IBITS);
6967640Ssam 		goto dropit;
69715794Sleres 	}
698*20997Skarels 
699*20997Skarels 	/* check the protocol header version */
700*20997Skarels 	if (vv->vh_version != RING_VERSION) {
701*20997Skarels 		vvprintf("vv%d: bad protocol header version %d\n",
702*20997Skarels 		    unit, vv->vh_version & 0xff);
703*20997Skarels 		goto dropit;
704*20997Skarels 	}
705*20997Skarels 
7067640Ssam #define	vvdataaddr(vv, off, type)	((type)(((caddr_t)((vv)+1)+(off))))
70713057Ssam 	if (vv->vh_type >= RING_IPTrailer &&
70813057Ssam 	     vv->vh_type < RING_IPTrailer+RING_IPNTrailer) {
7097640Ssam 		off = (vv->vh_type - RING_IPTrailer) * 512;
71015794Sleres 		if (off > VVMTU) {
711*20997Skarels 			vvprintf("vv%d: off > VVMTU, off = %d, vvicsr = %b\n",
71215794Sleres 				    unit, off, 0xffff&(addr->vvicsr), VV_IBITS);
7137640Ssam 			goto dropit;
71415794Sleres 		}
7157640Ssam 		vv->vh_type = *vvdataaddr(vv, off, u_short *);
7167640Ssam 		resid = *(vvdataaddr(vv, off+2, u_short *));
71715794Sleres 		if (off + resid > len) {
718*20997Skarels 			vvprintf("vv%d: trailer packet too short\n", unit);
719*20997Skarels 			vvprintf("vv%d: off = %d, resid = %d, vvicsr = %b\n",
72015794Sleres 				    unit, off, resid,
72115794Sleres 				    0xffff&(addr->vvicsr), VV_IBITS);
7227640Ssam 			goto dropit;
72315794Sleres 		}
7247640Ssam 		len = off + resid;
72511209Ssam 	} else
7267640Ssam 		off = 0;
727*20997Skarels 
72815794Sleres 	if (len == 0) {
729*20997Skarels 		vvprintf("vv%d: len is zero, vvicsr = %b\n", unit,
73015794Sleres 			    0xffff&(addr->vvicsr), VV_IBITS);
7317640Ssam 		goto dropit;
73215794Sleres 	}
733*20997Skarels 
7347640Ssam 	m = if_rubaget(&vs->vs_ifuba, len, off);
73515794Sleres 	if (m == NULL) {
736*20997Skarels 		vvprintf("vv%d: if_rubaget() failed, vvicsr = %b\n", unit,
73715794Sleres 			    0xffff&(addr->vvicsr), VV_IBITS);
7387640Ssam 		goto dropit;
73915794Sleres 	}
7407640Ssam 	if (off) {
7417640Ssam 		m->m_off += 2 * sizeof(u_short);
7427640Ssam 		m->m_len -= 2 * sizeof(u_short);
7437640Ssam 	}
74411192Ssam 
74515794Sleres 	/* Keep track of source address of this packet */
74615794Sleres 	vs->vs_lastr = vv->vh_shost;
747*20997Skarels 
74811192Ssam 	/*
74915764Sleres 	 * Demultiplex on packet type
75011192Ssam 	 */
7517024Ssam 	switch (vv->vh_type) {
75211192Ssam 
7537024Ssam #ifdef INET
7547024Ssam 	case RING_IP:
7557024Ssam 		schednetisr(NETISR_IP);
7567024Ssam 		inq = &ipintrq;
7577024Ssam 		break;
7587024Ssam #endif
7597024Ssam 	default:
760*20997Skarels 		vvprintf("vv%d: unknown pkt type 0x%x\n", unit, vv->vh_type);
7617640Ssam 		m_freem(m);
7627024Ssam 		goto setup;
7637024Ssam 	}
76415794Sleres 	s = splimp();
7657640Ssam 	if (IF_QFULL(inq)) {
7667640Ssam 		IF_DROP(inq);
7677640Ssam 		m_freem(m);
76811209Ssam 	} else
7697640Ssam 		IF_ENQUEUE(inq, m);
77015764Sleres 
77115794Sleres 	splx(s);
7727024Ssam 	/*
77315764Sleres 	 * Reset for the next packet.
7747024Ssam 	 */
77515764Sleres setup:
77615764Sleres 	ubainfo = vs->vs_ifuba.ifu_r.ifrw_info;
77715764Sleres 	addr->vviba = (u_short) ubainfo;
77815764Sleres 	addr->vviea = (u_short) (ubainfo >> 16);
779*20997Skarels 	addr->vviwc = -(VVBUFSIZE) >> 1;
780*20997Skarels 	addr->vvicsr = VV_HEN | VV_IEN | VV_DEN | VV_ENB;
78115764Sleres 	return;
78211192Ssam 
78311192Ssam 	/*
78411209Ssam 	 * Drop packet on floor -- count them!!
78511192Ssam 	 */
7867640Ssam dropit:
7877640Ssam 	vs->vs_if.if_ierrors++;
7887640Ssam 	goto setup;
7897024Ssam }
7907024Ssam 
7917024Ssam /*
792*20997Skarels  * proNET output routine.
7937024Ssam  * Encapsulate a packet of type family for the local net.
7947024Ssam  * Use trailer local net encapsulation if enough data in first
7957024Ssam  * packet leaves a multiple of 512 bytes of data in remainder.
7967024Ssam  */
7977024Ssam vvoutput(ifp, m0, dst)
7987024Ssam 	struct ifnet *ifp;
7997024Ssam 	struct mbuf *m0;
8007024Ssam 	struct sockaddr *dst;
8017024Ssam {
80216581Skarels 	register struct mbuf *m;
8037024Ssam 	register struct vv_header *vv;
8047640Ssam 	register int off;
80516581Skarels 	register int unit;
80616581Skarels 	register struct vvreg *addr;
80716581Skarels 	register struct vv_softc *vs;
80816581Skarels 	register int s;
80916581Skarels 	int type, dest, error;
8107024Ssam 
81116581Skarels 	m = m0;
81216581Skarels 	unit = ifp->if_unit;
81316581Skarels 	addr = (struct vvreg *)vvinfo[unit]->ui_addr;
81416581Skarels 	vs = &vv_softc[unit];
815*20997Skarels 
81616581Skarels 	/*
817*20997Skarels 	 * Check to see if the input side has wedged due the UBA
818*20997Skarels 	 * vectoring through 0.
81916581Skarels 	 *
82016581Skarels 	 * We are lower than device ipl when we enter this routine,
82116581Skarels 	 * so if the interface is ready with an input packet then
82216581Skarels 	 * an input interrupt must have slipped through the cracks.
82316581Skarels 	 *
82416581Skarels 	 * Avoid the race with an input interrupt by watching to see
82516581Skarels 	 * if any packets come in.
82616581Skarels 	 */
82716581Skarels 	s = vs->vs_if.if_ipackets;
82816581Skarels 	if (addr->vvicsr & VV_RDY && s == vs->vs_if.if_ipackets) {
829*20997Skarels 		vvprintf("vv%d: lost a receive interrupt, icsr = %b\n",
83016581Skarels 			    unit, 0xffff&(addr->vvicsr), VV_IBITS);
83116581Skarels 		s = splimp();
83216581Skarels 		vvrint(unit);
83316581Skarels 		splx(s);
83416581Skarels 	}
83516581Skarels 
8367024Ssam 	switch (dst->sa_family) {
83711192Ssam 
8387024Ssam #ifdef INET
83915764Sleres 	case AF_INET:
8407640Ssam 		dest = ((struct sockaddr_in *)dst)->sin_addr.s_addr;
841*20997Skarels #ifdef LOOPBACK
842*20997Skarels 		if ((dest == ((struct sockaddr_in *)&ifp->if_addr)->sin_addr.s_addr) &&
843*20997Skarels 		   ((loif.if_flags & IFF_UP) != 0))
844*20997Skarels 			return(looutput(&loif, m0, dst));
845*20997Skarels #endif LOOPBACK
84611192Ssam 		if ((dest = in_lnaof(*((struct in_addr *)&dest))) >= 0x100) {
8477640Ssam 			error = EPERM;
8487640Ssam 			goto bad;
8497640Ssam 		}
8507640Ssam 		off = ntohs((u_short)mtod(m, struct ip *)->ip_len) - m->m_len;
851*20997Skarels 		/*
852*20997Skarels 		 * Trailerize, if the configuration allows it.
853*20997Skarels 		 * TODO: Need per host negotiation.
854*20997Skarels 		 */
85513090Ssam 		if ((ifp->if_flags & IFF_NOTRAILERS) == 0)
85613090Ssam 		if (off > 0 && (off & 0x1ff) == 0 &&
8577640Ssam 		    m->m_off >= MMINOFF + 2 * sizeof (u_short)) {
8587640Ssam 			type = RING_IPTrailer + (off>>9);
8597640Ssam 			m->m_off -= 2 * sizeof (u_short);
8607640Ssam 			m->m_len += 2 * sizeof (u_short);
8617640Ssam 			*mtod(m, u_short *) = RING_IP;
8627640Ssam 			*(mtod(m, u_short *) + 1) = m->m_len;
8637640Ssam 			goto gottrailertype;
8647640Ssam 		}
8657024Ssam 		type = RING_IP;
8667024Ssam 		off = 0;
8677024Ssam 		goto gottype;
8687024Ssam #endif
8697024Ssam 	default:
87016581Skarels 		printf("vv%d: can't handle af%d\n", unit, dst->sa_family);
8717640Ssam 		error = EAFNOSUPPORT;
8727640Ssam 		goto bad;
8737024Ssam 	}
8747024Ssam 
8757024Ssam gottrailertype:
8767024Ssam 	/*
8777024Ssam 	 * Packet to be sent as trailer: move first packet
8787024Ssam 	 * (control information) to end of chain.
8797024Ssam 	 */
8807024Ssam 	while (m->m_next)
8817024Ssam 		m = m->m_next;
8827024Ssam 	m->m_next = m0;
8837024Ssam 	m = m0->m_next;
8847024Ssam 	m0->m_next = 0;
8857024Ssam 	m0 = m;
8867024Ssam gottype:
8877024Ssam 	/*
8887024Ssam 	 * Add local net header.  If no space in first mbuf,
8897024Ssam 	 * allocate another.
8907024Ssam 	 */
8917024Ssam 	if (m->m_off > MMAXOFF ||
8927024Ssam 	    MMINOFF + sizeof (struct vv_header) > m->m_off) {
89311209Ssam 		m = m_get(M_DONTWAIT, MT_HEADER);
89411209Ssam 		if (m == NULL) {
8957640Ssam 			error = ENOBUFS;
8967640Ssam 			goto bad;
8977024Ssam 		}
8987024Ssam 		m->m_next = m0;
8997024Ssam 		m->m_off = MMINOFF;
9007024Ssam 		m->m_len = sizeof (struct vv_header);
9017024Ssam 	} else {
9027024Ssam 		m->m_off -= sizeof (struct vv_header);
9037024Ssam 		m->m_len += sizeof (struct vv_header);
9047024Ssam 	}
9057024Ssam 	vv = mtod(m, struct vv_header *);
9067024Ssam 	vv->vh_shost = ifp->if_host[0];
90715764Sleres 	/* Map the destination address if it's a broadcast */
90815764Sleres 	if ((vv->vh_dhost = dest) == INADDR_ANY)
90915764Sleres 		vv->vh_dhost = VV_BROADCAST;
9107024Ssam 	vv->vh_version = RING_VERSION;
9117024Ssam 	vv->vh_type = type;
9127640Ssam 	vv->vh_info = off;
91311192Ssam 	vvtracehdr("vo", vv);
9147024Ssam 
9157024Ssam 	/*
9167024Ssam 	 * Queue message on interface, and start output if interface
9177024Ssam 	 * not yet active.
9187024Ssam 	 */
9197024Ssam 	s = splimp();
9207640Ssam 	if (IF_QFULL(&ifp->if_snd)) {
9217640Ssam 		IF_DROP(&ifp->if_snd);
9227640Ssam 		error = ENOBUFS;
9237640Ssam 		goto qfull;
9247640Ssam 	}
9257024Ssam 	IF_ENQUEUE(&ifp->if_snd, m);
92616581Skarels 	if (vs->vs_oactive == 0)
92716581Skarels 		vvstart(unit);
9287024Ssam 	splx(s);
9297640Ssam 	return (0);
9307640Ssam qfull:
9317640Ssam 	m0 = m;
9327640Ssam 	splx(s);
9337640Ssam bad:
9347640Ssam 	m_freem(m0);
9357640Ssam 	return(error);
9367024Ssam }
9377024Ssam 
9387024Ssam /*
93913057Ssam  * Process an ioctl request.
94013057Ssam  */
94113057Ssam vvioctl(ifp, cmd, data)
94213057Ssam 	register struct ifnet *ifp;
94313057Ssam 	int cmd;
94413057Ssam 	caddr_t data;
94513057Ssam {
94616581Skarels 	register struct ifreq *ifr;
94716581Skarels 	register int s;
94816581Skarels 	int error;
94913057Ssam 
95015764Sleres 	ifr = (struct ifreq *)data;
95115764Sleres 	error = 0;
95215764Sleres 	s = splimp();
95313057Ssam 	switch (cmd) {
95413057Ssam 
95513057Ssam 	case SIOCSIFADDR:
95616581Skarels 		if (ifp->if_flags & IFF_RUNNING)
95716581Skarels 			if_rtinit(ifp, -1);	/* delete previous route */
95816581Skarels 		vvsetaddr(ifp, (struct sockaddr_in *)&ifr->ifr_addr);
95916581Skarels 		if (ifp->if_flags & IFF_RUNNING)
96016581Skarels 			if_rtinit(ifp, RTF_UP);
96116581Skarels 		else
96213057Ssam 			vvinit(ifp->if_unit);
96313057Ssam 		break;
96413057Ssam 
96513057Ssam 	default:
96613057Ssam 		error = EINVAL;
96713057Ssam 	}
96813057Ssam 	splx(s);
96916581Skarels 	return(error);
97013057Ssam }
97113057Ssam 
97213057Ssam /*
97315764Sleres  * Set up the address for this interface. We use the network number
97415794Sleres  * from the passed address and an invalid host number; vvinit() will
97515794Sleres  * figure out the host number and insert it later.
97615764Sleres  */
97715764Sleres vvsetaddr(ifp, sin)
97815764Sleres 	register struct ifnet *ifp;
97915764Sleres 	register struct sockaddr_in *sin;
98015764Sleres {
98115764Sleres 	ifp->if_net = in_netof(sin->sin_addr);
98215764Sleres 	ifp->if_host[0] = 256;			/* an invalid host number */
98315764Sleres 	sin = (struct sockaddr_in *)&ifp->if_addr;
98415764Sleres 	sin->sin_family = AF_INET;
98515764Sleres 	sin->sin_addr = if_makeaddr(ifp->if_net, ifp->if_host[0]);
98615764Sleres 	sin = (struct sockaddr_in *)&ifp->if_broadaddr;
98715764Sleres 	sin->sin_family = AF_INET;
98815764Sleres 	sin->sin_addr = if_makeaddr(ifp->if_net, INADDR_ANY);
98915764Sleres 	ifp->if_flags |= IFF_BROADCAST;
99015764Sleres }
99115764Sleres 
99215764Sleres /*
9937024Ssam  * vvprt_hdr(s, v) print the local net header in "v"
99415764Sleres  *	with title is "s"
9957024Ssam  */
9967024Ssam vvprt_hdr(s, v)
9977024Ssam 	char *s;
9987024Ssam 	register struct vv_header *v;
9997024Ssam {
10007024Ssam 	printf("%s: dsvti: 0x%x 0x%x 0x%x 0x%x 0x%x\n",
10017024Ssam 		s,
10027024Ssam 		0xff & (int)(v->vh_dhost), 0xff & (int)(v->vh_shost),
10037024Ssam 		0xff & (int)(v->vh_version), 0xff & (int)(v->vh_type),
10047024Ssam 		0xffff & (int)(v->vh_info));
10057024Ssam }
1006