xref: /csrg-svn/sys/vax/if/if_vv.c (revision 11192)
1*11192Ssam /*	if_vv.c	4.13	83/02/20	*/
27024Ssam 
39799Ssam #include "vv.h"
4*11192Ssam 
57024Ssam /*
67024Ssam  * Proteon 10 Meg Ring Driver.
77024Ssam  * This device is called "vv" because its "real name",
87024Ssam  * V2LNI won't work if shortened to the obvious "v2".
97024Ssam  * Hence the subterfuge.
10*11192Ssam  *
11*11192Ssam  * MUST BE UPDATE FOR 4.1C
127024Ssam  */
13*11192Ssam #include "../h/pte.h"
149799Ssam 
157024Ssam #include "../h/param.h"
167024Ssam #include "../h/systm.h"
177024Ssam #include "../h/mbuf.h"
187024Ssam #include "../h/buf.h"
197024Ssam #include "../h/protosw.h"
207024Ssam #include "../h/socket.h"
21*11192Ssam #include "../h/cpu.h"
22*11192Ssam #include "../h/mtpr.h"
237024Ssam #include "../h/vmmac.h"
24*11192Ssam #include "../h/errno.h"
258465Sroot 
268465Sroot #include "../net/if.h"
278465Sroot #include "../net/route.h"
28*11192Ssam 
298421Swnj #include "../netinet/in.h"
308421Swnj #include "../netinet/in_systm.h"
318421Swnj #include "../netinet/ip.h"
328421Swnj #include "../netinet/ip_var.h"
338465Sroot 
348421Swnj #include "../vaxif/if_vv.h"
358421Swnj #include "../vaxif/if_uba.h"
36*11192Ssam 
378465Sroot #include "../vaxuba/ubareg.h"
388465Sroot #include "../vaxuba/ubavar.h"
397024Ssam 
407024Ssam /*
417024Ssam  * N.B. - if WIRECENTER is defined wrong, it can well break
427024Ssam  * the hardware!!
437024Ssam  */
447640Ssam 
457024Ssam #define	WIRECENTER
467024Ssam 
477024Ssam #ifdef WIRECENTER
487024Ssam #define	VV_CONF	VV_HEN		/* drive wire center relay */
497024Ssam #else
507024Ssam #define	VV_CONF	VV_STE		/* allow operation without wire center */
517024Ssam #endif
527024Ssam 
537024Ssam #define	VVMTU	(1024+512)
547640Ssam #define VVMRU	(1024+512+16)	/* space for trailer */
557024Ssam 
56*11192Ssam int vv_dotrailer = 0,		/* 1 => do trailer protocol */
57*11192Ssam     vv_tracehdr = 0,		/* 1 => trace headers (slowly!!) */
58*11192Ssam     vv_tracetimeout = 1;	/* 1 => trace input error-rate limiting */
59*11192Ssam     vv_logreaderrors = 0;	/* 1 => log all read errors */
607640Ssam 
61*11192Ssam #define vvtracehdr	if (vv_tracehdr) vvprt_hdr
62*11192Ssam #define	vvtrprintf	if (vv_tracetimeout) printf
63*11192Ssam 
64*11192Ssam int vv_ticking = 0;		/* error flywheel is running */
65*11192Ssam 
66*11192Ssam #define VV_FLYWHEEL		3	/* interval in HZ - 50 msec.
67*11192Ssam 					   N.B. all times below are
68*11192Ssam 					   in units of flywheel ticks */
69*11192Ssam #define	VV_ERRORTHRESHOLD	100	/* errors/flywheel-interval */
70*11192Ssam #define	VV_MODE1ATTEMPTS	10	/* number mode 1 retries */
71*11192Ssam #define	VV_MODE1DELAY		2	/* period interface is PAUSEd - 100ms */
72*11192Ssam #define VV_MODE2DELAY		4	/* base interval host relay is off - 200ms */
73*11192Ssam #define	VV_MAXDELAY		6400	/* max interval host relay is off - 2 minutes */
74*11192Ssam 
757024Ssam int	vvprobe(), vvattach(), vvrint(), vvxint();
767024Ssam struct	uba_device *vvinfo[NVV];
777024Ssam u_short vvstd[] = { 0 };
787024Ssam struct	uba_driver vvdriver =
797024Ssam 	{ vvprobe, 0, vvattach, 0, vvstd, "vv", vvinfo };
807024Ssam #define	VVUNIT(x)	minor(x)
817024Ssam int	vvinit(),vvoutput(),vvreset();
827024Ssam 
837024Ssam /*
847024Ssam  * Software status of each interface.
857024Ssam  *
867024Ssam  * Each interface is referenced by a network interface structure,
877024Ssam  * vs_if, which the routing code uses to locate the interface.
887024Ssam  * This structure contains the output queue for the interface, its address, ...
897024Ssam  * We also have, for each interface, a UBA interface structure, which
907024Ssam  * contains information about the UNIBUS resources held by the interface:
917024Ssam  * map registers, buffered data paths, etc.  Information is cached in this
927024Ssam  * structure for use by the if_uba.c routines in running the interface
937024Ssam  * efficiently.
947024Ssam  */
957024Ssam struct	vv_softc {
967024Ssam 	struct	ifnet vs_if;		/* network-visible interface */
977024Ssam 	struct	ifuba vs_ifuba;		/* UNIBUS resources */
98*11192Ssam 	short	vs_oactive;		/* is output active */
99*11192Ssam 	short	vs_iactive;		/* is input active */
1007024Ssam 	short	vs_olen;		/* length of last output */
1017024Ssam 	u_short	vs_lastx;		/* last destination address */
102*11192Ssam 	short	vs_tries;		/* transmit current retry count */
1037024Ssam 	short	vs_init;		/* number of ring inits */
1047024Ssam 	short	vs_nottaken;		/* number of packets refused */
105*11192Ssam 	/* input error rate limiting state */
106*11192Ssam 	short	vs_major;		/* recovery major state */
107*11192Ssam 	short	vs_minor;		/* recovery minor state */
108*11192Ssam 	short	vs_retry;		/* recovery retry count */
109*11192Ssam 	short	vs_delayclock;		/* recovery delay clock */
110*11192Ssam 	short	vs_delayrange;		/* increasing delay interval */
111*11192Ssam 	short	vs_dropped;		/* number of packes tossed in last dt */
1127024Ssam } vv_softc[NVV];
1137024Ssam 
114*11192Ssam /*
115*11192Ssam  * states of vs_iactive
116*11192Ssam  */
117*11192Ssam 
118*11192Ssam #define	ACTIVE	1		/* interface should post new receives */
119*11192Ssam #define	PAUSE	0		/* interface should NOT post new receives */
120*11192Ssam #define	OPEN	-1		/* PAUSE and open host relay */
121*11192Ssam 
122*11192Ssam /*
123*11192Ssam  * recovery major states
124*11192Ssam  */
125*11192Ssam 
126*11192Ssam #define	MODE0	0		/* everything is wonderful */
127*11192Ssam #define	MODE1	1		/* hopefully whatever will go away */
128*11192Ssam #define	MODE2	2		/* drastic measures - open host relay
129*11192Ssam 				   for increasing intervals */
130*11192Ssam 
1317024Ssam vvprobe(reg)
1327024Ssam 	caddr_t reg;
1337024Ssam {
1347024Ssam 	register int br, cvec;
1357024Ssam 	register struct vvreg *addr = (struct vvreg *)reg;
1367024Ssam 
1377024Ssam #ifdef lint
1387024Ssam 	br = 0; cvec = br; br = cvec;
1397024Ssam #endif
1407024Ssam 	/* reset interface, enable, and wait till dust settles */
1417024Ssam 	addr->vvicsr = VV_RST;
1427024Ssam 	addr->vvocsr = VV_RST;
1437024Ssam 	DELAY(100000);
1447024Ssam 	/* generate interrupt by doing 1 word DMA from 0 in uba space!! */
1457024Ssam 	addr->vvocsr = VV_IEN;		/* enable interrupt */
1467024Ssam 	addr->vvoba = 0;		/* low 16 bits */
1477024Ssam 	addr->vvoea = 0;		/* extended bits */
1487024Ssam 	addr->vvowc = -1;		/* for 1 word */
1497024Ssam 	addr->vvocsr |= VV_DEN;		/* start the DMA */
1507024Ssam 	DELAY(100000);
1517024Ssam 	addr->vvocsr = 0;
1527024Ssam 	if (cvec && cvec != 0x200)
1537024Ssam 		cvec -= 4;		/* backup so vector => recieve */
1547024Ssam 	return(1);
1557024Ssam }
1567024Ssam 
1577024Ssam /*
1587024Ssam  * Interface exists: make available by filling in network interface
1597024Ssam  * record.  System will initialize the interface when it is ready
1607024Ssam  * to accept packets.
1617024Ssam  */
1627024Ssam vvattach(ui)
1637024Ssam 	struct uba_device *ui;
1647024Ssam {
1657024Ssam 	register struct vv_softc *vs = &vv_softc[ui->ui_unit];
1667024Ssam 	register struct sockaddr_in *sin;
1677024Ssam 
1687024Ssam 	vs->vs_if.if_unit = ui->ui_unit;
1697024Ssam 	vs->vs_if.if_name = "vv";
1707024Ssam 	vs->vs_if.if_mtu = VVMTU;
1717024Ssam 	vs->vs_if.if_net = ui->ui_flags;
1727024Ssam 	vs->vs_if.if_host[0] = 0;	/* this will be reset in vvinit() */
1737024Ssam 
1747024Ssam 	sin = (struct sockaddr_in *)&vs->vs_if.if_addr;
1757024Ssam 	sin->sin_family = AF_INET;
1767024Ssam 	sin->sin_addr = if_makeaddr(vs->vs_if.if_net, vs->vs_if.if_host[0]);
1777024Ssam 
1787024Ssam 	sin = (struct sockaddr_in *)&vs->vs_if.if_broadaddr;
1797024Ssam 	sin->sin_family = AF_INET;
1807024Ssam 	sin->sin_addr = if_makeaddr(vs->vs_if.if_net, VV_BROADCAST);
1817024Ssam 	vs->vs_if.if_flags = IFF_BROADCAST;
1827024Ssam 
1837024Ssam 	vs->vs_if.if_init = vvinit;
1847024Ssam 	vs->vs_if.if_output = vvoutput;
185*11192Ssam 	vs->vs_if.if_ubareset = vvreset;
1867640Ssam 	vs->vs_ifuba.ifu_flags = UBA_CANTWAIT | UBA_NEEDBDP | UBA_NEED16;
1877024Ssam 	if_attach(&vs->vs_if);
1887024Ssam }
1897024Ssam 
1907024Ssam /*
1917024Ssam  * Reset of interface after UNIBUS reset.
1927024Ssam  * If interface is on specified uba, reset its state.
1937024Ssam  */
1947024Ssam vvreset(unit, uban)
1957024Ssam 	int unit, uban;
1967024Ssam {
1977024Ssam 	register struct uba_device *ui;
1987024Ssam 
1997024Ssam 	if (unit >= NVV || (ui = vvinfo[unit]) == 0 || ui->ui_alive == 0 ||
2007024Ssam 	    ui->ui_ubanum != uban)
2017024Ssam 		return;
2027024Ssam 	printf(" vv%d", unit);
2037024Ssam 	vvinit(unit);
2047024Ssam }
2057024Ssam 
2067024Ssam /*
2077024Ssam  * Initialization of interface; clear recorded pending
2087024Ssam  * operations, and reinitialize UNIBUS usage.
2097024Ssam  */
2107024Ssam vvinit(unit)
2117024Ssam 	int unit;
2127024Ssam {
2137024Ssam 	register struct vv_softc *vs = &vv_softc[unit];
2147024Ssam 	register struct uba_device *ui = vvinfo[unit];
2157024Ssam 	register struct vvreg *addr;
2167024Ssam 	struct sockaddr_in *sin;
2177640Ssam 	int ubainfo, s;
218*11192Ssam 	int vvtimeout();
2197024Ssam 
2207640Ssam 	addr = (struct vvreg *)ui->ui_addr;
2217024Ssam 	if (if_ubainit(&vs->vs_ifuba, ui->ui_ubanum,
2227024Ssam 	    sizeof (struct vv_header), (int)btoc(VVMTU)) == 0) {
2237024Ssam 		printf("vv%d: can't initialize\n", unit);
2247640Ssam 		vs->vs_if.if_flags &= ~IFF_UP;
2257024Ssam 		return;
2267024Ssam 	}
2277024Ssam 
228*11192Ssam 	if (vv_ticking++ == 0) timeout(vvtimeout, (caddr_t) 0, VV_FLYWHEEL);
229*11192Ssam 
2307024Ssam 	/*
2317640Ssam 	 * discover our host address and post it
2327640Ssam 	 */
2337640Ssam 
2347640Ssam 	vs->vs_if.if_host[0] = vvidentify(unit);
2357640Ssam 	printf("vv%d: host %d\n", unit, vs->vs_if.if_host[0]);
2367640Ssam 	sin = (struct sockaddr_in *)&vs->vs_if.if_addr;
2377640Ssam 	sin->sin_family = AF_INET;
2387640Ssam 	sin->sin_addr =
2397640Ssam 	    if_makeaddr(vs->vs_if.if_net, vs->vs_if.if_host[0]);
2407640Ssam 
2417640Ssam 	/*
2427640Ssam 	 * Reset the interface, and join the ring
2437640Ssam 	 */
2447640Ssam 	addr->vvocsr = VV_RST | VV_CPB;		/* clear packet buffer */
2457640Ssam 	addr->vvicsr = VV_RST | VV_CONF;	/* close logical relay */
2467640Ssam 	sleep((caddr_t)&lbolt, PZERO);		/* let contacts settle */
2477640Ssam 	vs->vs_init = 0;
248*11192Ssam 	vs->vs_dropped = 0;
2497640Ssam 	vs->vs_nottaken = 0;
2507640Ssam 
2517640Ssam 	/*
2527640Ssam 	 * Hang a receive and start any
2537640Ssam 	 * pending writes by faking a transmit complete.
2547640Ssam 	 */
2557640Ssam 	s = splimp();
2567640Ssam 	ubainfo = vs->vs_ifuba.ifu_r.ifrw_info;
2577640Ssam 	addr->vviba = (u_short) ubainfo;
2587640Ssam 	addr->vviea = (u_short) (ubainfo >> 16);
2597640Ssam 	addr->vviwc = -(sizeof (struct vv_header) + VVMTU) >> 1;
2607640Ssam 	addr->vvicsr = VV_IEN | VV_CONF | VV_DEN | VV_ENB;
261*11192Ssam 	vs->vs_iactive = ACTIVE;
2627640Ssam 	vs->vs_oactive = 1;
2637640Ssam 	vs->vs_if.if_flags |= IFF_UP;
2647640Ssam 	vvxint(unit);
2657640Ssam 	splx(s);
2667640Ssam 	if_rtinit(&vs->vs_if, RTF_UP);
2677640Ssam }
2687640Ssam 
2697640Ssam /*
2707640Ssam  * vvidentify() - return our host address
2717640Ssam  */
272*11192Ssam 
273*11192Ssam vvidentify(unit) {
274*11192Ssam 
2757640Ssam 	register struct vv_softc *vs = &vv_softc[unit];
2767640Ssam 	register struct uba_device *ui = vvinfo[unit];
2777640Ssam 	register struct vvreg *addr;
2787640Ssam 	struct mbuf *m;
2797640Ssam 	struct vv_header *v;
2807640Ssam 	int ubainfo, retrying, attempts, waitcount, s;
2817640Ssam 
2827640Ssam 	/*
2837024Ssam 	 * Build a multicast message to identify our address
2847024Ssam 	 */
285*11192Ssam 
2867640Ssam 	addr = (struct vvreg *)ui->ui_addr;
287*11192Ssam 
2887024Ssam 	attempts = 0;		/* total attempts, including bad msg type */
2897024Ssam 	retrying = 0;		/* first time through */
290*11192Ssam 	m = m_get(M_DONTWAIT);
291*11192Ssam 	if (m == 0)
292*11192Ssam 		panic("vvinit: can't get mbuf");
293*11192Ssam 	m->m_next = 0;
2947024Ssam 	m->m_off = MMINOFF;
2957024Ssam 	m->m_len = sizeof(struct vv_header);
2967024Ssam 
2977024Ssam 	v = mtod(m, struct vv_header *);
298*11192Ssam 	v->vh_dhost = VV_BROADCAST;	/* multicast destination address */
2997024Ssam 	v->vh_shost = 0;		/* will be overwritten with ours */
3007024Ssam 	v->vh_version = RING_VERSION;
3017024Ssam 	v->vh_type = RING_WHOAMI;
3027024Ssam 	v->vh_info = 0;
303*11192Ssam 
304*11192Ssam 	/* map xmit message into uba */
305*11192Ssam 
3067640Ssam 	vs->vs_olen =  if_wubaput(&vs->vs_ifuba, m);
3077640Ssam 	if (vs->vs_ifuba.ifu_flags & UBA_NEEDBDP)
3087640Ssam 		UBAPURGE(vs->vs_ifuba.ifu_uba, vs->vs_ifuba.ifu_w.ifrw_bdp);
3097024Ssam 
3107024Ssam 	/*
3117024Ssam 	 * Reset interface, establish Digital Loopback Mode, and
3127024Ssam 	 * send the multicast (to myself) with Input Copy enabled.
3137024Ssam 	 */
3147024Ssam retry:
3157024Ssam 	ubainfo = vs->vs_ifuba.ifu_r.ifrw_info;
3167024Ssam 	addr->vvicsr = VV_RST;
3177024Ssam 	addr->vviba = (u_short) ubainfo;
3187024Ssam 	addr->vviea = (u_short) (ubainfo >> 16);
3197024Ssam 	addr->vviwc = -(sizeof (struct vv_header) + VVMTU) >> 1;
3207024Ssam 	addr->vvicsr = VV_STE | VV_DEN | VV_ENB | VV_LPB;
3217640Ssam 
3227640Ssam 	/* let flag timers fire so ring will initialize */
323*11192Ssam 
3247640Ssam 	sleep((caddr_t) &lbolt, PZERO);
3257640Ssam 	sleep((caddr_t) &lbolt, PZERO);
3267640Ssam 
3277024Ssam 	addr->vvocsr = VV_RST | VV_CPB;	/* clear packet buffer */
3287024Ssam 	ubainfo = vs->vs_ifuba.ifu_w.ifrw_info;
3297024Ssam 	addr->vvoba = (u_short) ubainfo;
3307024Ssam 	addr->vvoea = (u_short) (ubainfo >> 16);
3317024Ssam 	addr->vvowc = -((vs->vs_olen + 1) >> 1);
3327024Ssam 	addr->vvocsr = VV_CPB | VV_DEN | VV_INR | VV_ENB;
3337024Ssam 
3347024Ssam 	/*
3357024Ssam 	 * Wait for receive side to finish.
336*11192Ssam 	 * Extract source address (which will our own),
3377024Ssam 	 * and post to interface structure.
3387024Ssam 	 */
3397024Ssam 	DELAY(1000);
340*11192Ssam 	for (waitcount = 0; (addr->vvicsr & VV_RDY) == 0; waitcount++) {
3419876Ssam 		if (waitcount < 10) {
3427024Ssam 			DELAY(1000);
343*11192Ssam 		}
344*11192Ssam 		else {
345*11192Ssam 			if (attempts++ < 10){
3467024Ssam 				goto retry;
347*11192Ssam 			}
3487024Ssam 			else {
3497024Ssam 				printf("vv%d: can't initialize\n", unit);
3507024Ssam 				printf("vvinit loopwait: icsr = %b\n",
3517024Ssam 					0xffff&(addr->vvicsr),VV_IBITS);
3527640Ssam 				vs->vs_if.if_flags &= ~IFF_UP;
353*11192Ssam 				return;
3547024Ssam 			}
3557024Ssam 		}
356*11192Ssam 	}
357*11192Ssam 
3587024Ssam 	if (vs->vs_ifuba.ifu_flags & UBA_NEEDBDP)
3597024Ssam 		UBAPURGE(vs->vs_ifuba.ifu_uba, vs->vs_ifuba.ifu_w.ifrw_bdp);
3607024Ssam 	if (vs->vs_ifuba.ifu_xtofree)
3617024Ssam 		m_freem(vs->vs_ifuba.ifu_xtofree);
3627024Ssam 	if (vs->vs_ifuba.ifu_flags & UBA_NEEDBDP)
3637024Ssam 		UBAPURGE(vs->vs_ifuba.ifu_uba, vs->vs_ifuba.ifu_r.ifrw_bdp);
3647024Ssam 	m = if_rubaget(&vs->vs_ifuba, sizeof(struct vv_header), 0);
3657024Ssam 	if (m)
3667024Ssam 		m_freem(m);
3677024Ssam 	/*
3687024Ssam 	 * check message type before we believe the source host address
3697024Ssam 	 */
3707024Ssam 	v = (struct vv_header *)(vs->vs_ifuba.ifu_r.ifrw_addr);
371*11192Ssam 	if (v->vh_type == RING_WHOAMI)
372*11192Ssam 		return(v->vh_shost);
373*11192Ssam 	else
3747640Ssam 		goto retry;
3757024Ssam }
3767024Ssam 
3777024Ssam /*
378*11192Ssam  * vvtimeout() - called by timer flywheel to monitor input packet
379*11192Ssam  * discard rate.  Interfaces getting too many errors are shut
380*11192Ssam  * down for a while.  If the condition persists, the interface
381*11192Ssam  * is marked down.
382*11192Ssam  */
383*11192Ssam 
384*11192Ssam vvtimeout(junk)
385*11192Ssam int junk;
386*11192Ssam {
387*11192Ssam 	register struct vv_softc *vs;
388*11192Ssam 	register int i;
389*11192Ssam 	register struct vvreg *addr;
390*11192Ssam 	int ubainfo;
391*11192Ssam 
392*11192Ssam 	timeout(vvtimeout, (caddr_t) 0, VV_FLYWHEEL);
393*11192Ssam 
394*11192Ssam 	for (i=0; i<NVV; i++) {
395*11192Ssam 		vs = &vv_softc[i];
396*11192Ssam 		addr = (struct vvreg *)vvinfo[i]->ui_addr;
397*11192Ssam 		if (vs->vs_if.if_flags & IFF_UP == 0) continue;
398*11192Ssam 		switch (vs->vs_major) {
399*11192Ssam 
400*11192Ssam 		/*
401*11192Ssam 		 * MODE0: generally OK, just check error rate
402*11192Ssam 		 */
403*11192Ssam 
404*11192Ssam 		case MODE0:
405*11192Ssam 			if (vs->vs_dropped < VV_ERRORTHRESHOLD) {
406*11192Ssam 				vs->vs_dropped = 0;
407*11192Ssam 				continue;
408*11192Ssam 			}
409*11192Ssam 			else {
410*11192Ssam 				/* suspend reads for a while */
411*11192Ssam 				vvtrprintf("vv%d going MODE1 in vvtimeout\n",i);
412*11192Ssam 				vs->vs_major = MODE1;
413*11192Ssam 				vs->vs_iactive = PAUSE;	/* no new reads */
414*11192Ssam 				vs->vs_retry = VV_MODE1ATTEMPTS;
415*11192Ssam 				vs->vs_delayclock = VV_MODE1DELAY;
416*11192Ssam 				vs->vs_minor = 0;
417*11192Ssam 				continue;
418*11192Ssam 			}
419*11192Ssam 
420*11192Ssam 		/*
421*11192Ssam 		 * MODE1: excessive error rate observed
422*11192Ssam 		 * Scheme: try simply suspending reads for a
423*11192Ssam 		 * short while a small number of times
424*11192Ssam 		 */
425*11192Ssam 
426*11192Ssam 		case MODE1:
427*11192Ssam 			if (vs->vs_delayclock > 0) {
428*11192Ssam 				vs->vs_delayclock--;
429*11192Ssam 				continue;
430*11192Ssam 			}
431*11192Ssam 			switch (vs->vs_minor) {
432*11192Ssam 			case 0:				/* reenable reads */
433*11192Ssam 				vvtrprintf("vv%d M1m0\n",i);
434*11192Ssam 				vs->vs_dropped = 0;
435*11192Ssam 				vs->vs_iactive = ACTIVE;
436*11192Ssam 				vs->vs_minor = 1;	/* next state */
437*11192Ssam 				ubainfo = vs->vs_ifuba.ifu_r.ifrw_info;
438*11192Ssam 				addr->vviba = (u_short) ubainfo;
439*11192Ssam 				addr->vviea = (u_short) (ubainfo >> 16);
440*11192Ssam 				addr->vviwc = -(sizeof (struct vv_header) + VVMTU) >> 1;
441*11192Ssam 				addr->vvicsr = VV_RST | VV_CONF;
442*11192Ssam 				addr->vvicsr |= VV_IEN | VV_DEN | VV_ENB;
443*11192Ssam 				continue;
444*11192Ssam 			case 1:				/* see if it worked */
445*11192Ssam 				vvtrprintf("vv%d M1m1\n",i);
446*11192Ssam 				if (vs->vs_dropped < VV_ERRORTHRESHOLD) {
447*11192Ssam 					vs->vs_dropped = 0;
448*11192Ssam 					vs->vs_major = MODE0;	/* yeah!! */
449*11192Ssam 					continue;
450*11192Ssam 				}
451*11192Ssam 				else {
452*11192Ssam 					if (vs->vs_retry -- > 0) {
453*11192Ssam 						vs->vs_dropped = 0;
454*11192Ssam 						vs->vs_iactive = PAUSE;
455*11192Ssam 						vs->vs_delayclock = VV_MODE1DELAY;
456*11192Ssam 						vs->vs_minor = 0; /* recheck */
457*11192Ssam 						continue;
458*11192Ssam 					}
459*11192Ssam 					else {
460*11192Ssam 						vs->vs_major = MODE2;
461*11192Ssam 						vs->vs_minor = 0;
462*11192Ssam 						vs->vs_dropped = 0;
463*11192Ssam 						vs->vs_iactive = OPEN;
464*11192Ssam 						vs->vs_delayrange = VV_MODE2DELAY;
465*11192Ssam 						vs->vs_delayclock = VV_MODE2DELAY;
466*11192Ssam 					}
467*11192Ssam 				}
468*11192Ssam 			}
469*11192Ssam 
470*11192Ssam 		/*
471*11192Ssam 		 * MODE2: simply ignoring traffic didn't relieve condition
472*11192Ssam 		 * Scheme: open host relay for intervals linearly
473*11192Ssam 		 * increasing up to some maximum of a several minutes.
474*11192Ssam 		 * This allows broken networks to return to operation
475*11192Ssam 		 * without rebooting.
476*11192Ssam 		 */
477*11192Ssam 
478*11192Ssam 		case MODE2:
479*11192Ssam 			if (vs->vs_delayclock > 0) {
480*11192Ssam 				vs->vs_delayclock--;
481*11192Ssam 				continue;
482*11192Ssam 			}
483*11192Ssam 			switch (vs->vs_minor) {
484*11192Ssam 			case 0:		/* close relay and reenable reads */
485*11192Ssam 				vvtrprintf("vv%d M2m0\n",i);
486*11192Ssam 				vs->vs_dropped = 0;
487*11192Ssam 				vs->vs_iactive = ACTIVE;
488*11192Ssam 				vs->vs_minor = 1;	/* next state */
489*11192Ssam 				ubainfo = vs->vs_ifuba.ifu_r.ifrw_info;
490*11192Ssam 				addr->vviba = (u_short) ubainfo;
491*11192Ssam 				addr->vviea = (u_short) (ubainfo >> 16);
492*11192Ssam 				addr->vviwc = -(sizeof (struct vv_header) + VVMTU) >> 1;
493*11192Ssam 				addr->vvicsr = VV_RST | VV_CONF;
494*11192Ssam 				addr->vvicsr |= VV_IEN | VV_DEN | VV_ENB;
495*11192Ssam 				continue;
496*11192Ssam 			case 1:				/* see if it worked */
497*11192Ssam 				vvtrprintf("vv%d M2m1\n",i);
498*11192Ssam 				if (vs->vs_dropped < VV_ERRORTHRESHOLD) {
499*11192Ssam 					vs->vs_dropped = 0;
500*11192Ssam 					vs->vs_major = MODE0;	/* yeah!! */
501*11192Ssam 					continue;
502*11192Ssam 				}
503*11192Ssam 				else {
504*11192Ssam 					vvtrprintf("vv%d M2m1 ++ delay\n",i);
505*11192Ssam 					vs->vs_dropped = 0;
506*11192Ssam 					vs->vs_iactive = OPEN;
507*11192Ssam 					vs->vs_minor = 0;
508*11192Ssam 					if (vs->vs_delayrange < VV_MAXDELAY)
509*11192Ssam 						vs->vs_delayrange += (vs->vs_delayrange/2);
510*11192Ssam 					vs->vs_delayclock = vs->vs_delayrange;
511*11192Ssam 					continue;
512*11192Ssam 				}
513*11192Ssam 			}
514*11192Ssam 
515*11192Ssam 
516*11192Ssam 		default:
517*11192Ssam 			printf("vv%d: major state screwed\n", i);
518*11192Ssam 			vs->vs_if.if_flags &= ~IFF_UP;
519*11192Ssam 		}
520*11192Ssam 	}
521*11192Ssam }
522*11192Ssam 
523*11192Ssam /*
5247024Ssam  * Start or restart output on interface.
525*11192Ssam  * If interface is active, this is a retransmit, so just
526*11192Ssam  * restuff registers and go.
5277024Ssam  * If interface is not already active, get another datagram
5287024Ssam  * to send off of the interface queue, and map it to the interface
5297024Ssam  * before starting the output.
5307024Ssam  */
5317024Ssam vvstart(dev)
5327024Ssam 	dev_t dev;
5337024Ssam {
5347024Ssam         int unit = VVUNIT(dev);
5357024Ssam 	struct uba_device *ui = vvinfo[unit];
5367024Ssam 	register struct vv_softc *vs = &vv_softc[unit];
5377024Ssam 	register struct vvreg *addr;
5387024Ssam 	struct mbuf *m;
539*11192Ssam 	int ubainfo;
540*11192Ssam 	int dest;
5417024Ssam 
5427024Ssam 	if (vs->vs_oactive)
5437024Ssam 		goto restart;
544*11192Ssam 
5457024Ssam 	/*
5467024Ssam 	 * Not already active: dequeue another request
5477024Ssam 	 * and map it to the UNIBUS.  If no more requests,
5487024Ssam 	 * just return.
5497024Ssam 	 */
5507024Ssam 	IF_DEQUEUE(&vs->vs_if.if_snd, m);
5517024Ssam 	if (m == 0) {
5527024Ssam 		vs->vs_oactive = 0;
5537024Ssam 		return;
5547024Ssam 	}
5557024Ssam 	dest = mtod(m, struct vv_header *)->vh_dhost;
5567024Ssam 	vs->vs_olen = if_wubaput(&vs->vs_ifuba, m);
5577024Ssam 	vs->vs_lastx = dest;
5587024Ssam 
5597024Ssam restart:
560*11192Ssam 
5617024Ssam 	/*
5627024Ssam 	 * Have request mapped to UNIBUS for transmission.
5637024Ssam 	 * Purge any stale data from this BDP, and start the otput.
5647024Ssam 	 */
565*11192Ssam 
566*11192Ssam 	if (vs->vs_olen > VVMTU) {
567*11192Ssam 		printf("vv%d vs_olen: %d > VVMTU\n", unit, vs->vs_olen);
568*11192Ssam 		panic("vvdriver vs_olen botch");
569*11192Ssam 	}
5707024Ssam 	if (vs->vs_ifuba.ifu_flags & UBA_NEEDBDP)
5717024Ssam 		UBAPURGE(vs->vs_ifuba.ifu_uba, vs->vs_ifuba.ifu_w.ifrw_bdp);
5727024Ssam 	addr = (struct vvreg *)ui->ui_addr;
5737024Ssam 	ubainfo = vs->vs_ifuba.ifu_w.ifrw_info;
5747024Ssam 	addr->vvoba = (u_short) ubainfo;
5757024Ssam 	addr->vvoea = (u_short) (ubainfo >> 16);
5767024Ssam 	addr->vvowc = -((vs->vs_olen + 1) >> 1);
5777024Ssam 	addr->vvocsr = VV_IEN | VV_CPB | VV_DEN | VV_INR | VV_ENB;
5787024Ssam 	vs->vs_oactive = 1;
5797024Ssam }
5807024Ssam 
5817024Ssam /*
5827024Ssam  * VVLNI transmit interrupt
5837024Ssam  * Start another output if more data to send.
5847024Ssam  */
5857024Ssam vvxint(unit)
5867024Ssam 	int unit;
5877024Ssam {
5887024Ssam 	register struct uba_device *ui = vvinfo[unit];
5897024Ssam 	register struct vv_softc *vs = &vv_softc[unit];
5907024Ssam 	register struct vvreg *addr;
5917024Ssam 	register int oc;
5927024Ssam 
5937024Ssam 	addr = (struct vvreg *)ui->ui_addr;
5947024Ssam 	oc = 0xffff & (addr->vvocsr);
5957024Ssam 	if (vs->vs_oactive == 0) {
596*11192Ssam 		printf("vv%d: stray interrupt vvocsr = %b\n", unit,
5977024Ssam 			oc, VV_OBITS);
5987024Ssam 		return;
5997024Ssam 	}
6007024Ssam 	if (oc &  (VV_OPT | VV_RFS)) {
6017640Ssam 		vs->vs_if.if_collisions++;
602*11192Ssam 		if (vs->vs_tries++ < VVRETRY) {
6037024Ssam 			if (oc & VV_OPT)
6047024Ssam 				vs->vs_init++;
6057024Ssam 			if (oc & VV_RFS)
6067024Ssam 				vs->vs_nottaken++;
607*11192Ssam 			vvstart(unit);		/* restart this message */
6087024Ssam 			return;
6097024Ssam 		}
6107024Ssam 		if (oc & VV_OPT)
6117024Ssam 			printf("vv%d: output timeout\n");
6127024Ssam 	}
6137024Ssam 	vs->vs_if.if_opackets++;
6147024Ssam 	vs->vs_oactive = 0;
6157024Ssam 	vs->vs_tries = 0;
6167024Ssam 	if (oc & VVXERR) {
6177024Ssam 		vs->vs_if.if_oerrors++;
618*11192Ssam 		printf("vv%d: error vvocsr = %b\n", unit, 0xffff & oc,
6197024Ssam 			VV_OBITS);
6207024Ssam 	}
6217024Ssam 	if (vs->vs_ifuba.ifu_xtofree) {
6227024Ssam 		m_freem(vs->vs_ifuba.ifu_xtofree);
6237024Ssam 		vs->vs_ifuba.ifu_xtofree = 0;
6247024Ssam 	}
6257024Ssam 	if (vs->vs_if.if_snd.ifq_head == 0) {
626*11192Ssam 		vs->vs_lastx = 256;		/* an invalid address */
6277024Ssam 		return;
6287024Ssam 	}
6297024Ssam 	vvstart(unit);
6307024Ssam }
6317024Ssam 
6327024Ssam /*
6337024Ssam  * V2lni interface receiver interrupt.
6347024Ssam  * If input error just drop packet.
6357024Ssam  * Otherwise purge input buffered data path and examine
6367024Ssam  * packet to determine type.  If can't determine length
6377024Ssam  * from type, then have to drop packet.  Othewise decapsulate
6387024Ssam  * packet based on type and pass to type specific higher-level
6397024Ssam  * input routine.
6407024Ssam  */
6417024Ssam vvrint(unit)
6427024Ssam 	int unit;
6437024Ssam {
6447024Ssam 	register struct vv_softc *vs = &vv_softc[unit];
6457024Ssam 	struct vvreg *addr = (struct vvreg *)vvinfo[unit]->ui_addr;
6467024Ssam 	register struct vv_header *vv;
6477024Ssam 	register struct ifqueue *inq;
6487024Ssam     	struct mbuf *m;
6497024Ssam 	int ubainfo, len, off;
6507640Ssam 	short resid;
6517024Ssam 
6527024Ssam 	vs->vs_if.if_ipackets++;
653*11192Ssam 
6547024Ssam 	/*
6557024Ssam 	 * Purge BDP; drop if input error indicated.
6567024Ssam 	 */
657*11192Ssam 
6587024Ssam 	if (vs->vs_ifuba.ifu_flags & UBA_NEEDBDP)
6597024Ssam 		UBAPURGE(vs->vs_ifuba.ifu_uba, vs->vs_ifuba.ifu_r.ifrw_bdp);
6607024Ssam 	if (addr->vvicsr & VVRERR) {
661*11192Ssam 		if (vv_logreaderrors)
662*11192Ssam 			printf("vv%d: error vvicsr = %b\n", unit,
663*11192Ssam 				0xffff&(addr->vvicsr), VV_IBITS);
6647640Ssam 		goto dropit;
6657024Ssam 	}
6667640Ssam 
6677024Ssam 	/*
6687640Ssam 	 * Get packet length from word count residue
6697640Ssam 	 *
6707640Ssam 	 * Compute header offset if trailer protocol
6717640Ssam 	 *
6727640Ssam 	 * Pull packet off interface.  Off is nonzero if packet
6737640Ssam 	 * has trailing header; if_rubaget will then force this header
6747640Ssam 	 * information to be at the front.  The vh_info field
6757640Ssam 	 * carries the offset to the trailer data in trailer
6767640Ssam 	 * format packets.
6777024Ssam 	 */
678*11192Ssam 
6797640Ssam 	vv = (struct vv_header *)(vs->vs_ifuba.ifu_r.ifrw_addr);
680*11192Ssam 
681*11192Ssam 	vvtracehdr("vi", vv);
682*11192Ssam 
6837640Ssam 	resid = addr->vviwc;
6847640Ssam 	if (resid)
6857640Ssam 		resid |= 0176000;		/* ugly!!!! */
6867640Ssam 	len = (((sizeof (struct vv_header) + VVMRU) >> 1) + resid) << 1;
6877640Ssam 	len -= sizeof(struct vv_header);
688*11192Ssam 	if (len > VVMRU || len <= 0)
6897640Ssam 		goto dropit;
690*11192Ssam 
6917640Ssam #define	vvdataaddr(vv, off, type)	((type)(((caddr_t)((vv)+1)+(off))))
692*11192Ssam 
6937640Ssam 	if (vv_dotrailer && vv->vh_type >= RING_IPTrailer &&
6947640Ssam 	     vv->vh_type < RING_IPTrailer+RING_IPNTrailer){
6957640Ssam 		off = (vv->vh_type - RING_IPTrailer) * 512;
6967640Ssam 		if (off > VVMTU)
6977640Ssam 			goto dropit;
6987640Ssam 		vv->vh_type = *vvdataaddr(vv, off, u_short *);
6997640Ssam 		resid = *(vvdataaddr(vv, off+2, u_short *));
7007640Ssam 		if (off + resid > len)
7017640Ssam 			goto dropit;
7027640Ssam 		len = off + resid;
703*11192Ssam 	} else {
7047640Ssam 		off = 0;
705*11192Ssam 	}
7067640Ssam 	if (len == 0)
7077640Ssam 		goto dropit;
708*11192Ssam 
7097640Ssam 	m = if_rubaget(&vs->vs_ifuba, len, off);
7107640Ssam 	if (m == 0)
7117640Ssam 		goto dropit;
712*11192Ssam 
7137640Ssam 	if (off) {
7147640Ssam 		m->m_off += 2 * sizeof(u_short);
7157640Ssam 		m->m_len -= 2 * sizeof(u_short);
7167640Ssam 	}
717*11192Ssam 
718*11192Ssam 	/*
719*11192Ssam 	 * Demultiplex on packet type
720*11192Ssam 	 */
721*11192Ssam 
7227024Ssam 	switch (vv->vh_type) {
723*11192Ssam 
7247024Ssam #ifdef INET
7257024Ssam 	case RING_IP:
7267024Ssam 		schednetisr(NETISR_IP);
7277024Ssam 		inq = &ipintrq;
7287024Ssam 		break;
7297024Ssam #endif
7307024Ssam 	default:
7317024Ssam 		printf("vv%d: unknown pkt type 0x%x\n", unit, vv->vh_type);
7327640Ssam 		m_freem(m);
7337024Ssam 		goto setup;
7347024Ssam 	}
7357640Ssam 	if (IF_QFULL(inq)) {
7367640Ssam 		IF_DROP(inq);
7377640Ssam 		m_freem(m);
738*11192Ssam 	} else {
7397640Ssam 		IF_ENQUEUE(inq, m);
740*11192Ssam 	}
7417024Ssam 
7427024Ssam setup:
7437024Ssam 	/*
744*11192Ssam 	 * Check the error rate and start recovery if needed
745*11192Ssam 	 * this has to go here since the timer flywheel runs at
746*11192Ssam 	 * a lower ipl and never gets a chance to change the mode
7477024Ssam 	 */
748*11192Ssam 	if (vs->vs_major == MODE0 && vs->vs_dropped > VV_ERRORTHRESHOLD) {
7497024Ssam 
750*11192Ssam 		vvtrprintf("vv%d going MODE1 in vvrint\n",unit);
751*11192Ssam 		vs->vs_major = MODE1;
752*11192Ssam 		vs->vs_iactive = PAUSE;		/* no new reads */
753*11192Ssam 		vs->vs_retry = VV_MODE1ATTEMPTS;
754*11192Ssam 		vs->vs_delayclock = VV_MODE1DELAY;
755*11192Ssam 		vs->vs_minor = 0;
756*11192Ssam 		vs->vs_dropped = 0;
757*11192Ssam 	}
758*11192Ssam 
759*11192Ssam 	switch (vs->vs_iactive) {
760*11192Ssam 
761*11192Ssam 	case ACTIVE:
762*11192Ssam 
763*11192Ssam 		 /* Restart the read for next packet */
764*11192Ssam 
765*11192Ssam 		ubainfo = vs->vs_ifuba.ifu_r.ifrw_info;
766*11192Ssam 		addr->vviba = (u_short) ubainfo;
767*11192Ssam 		addr->vviea = (u_short) (ubainfo >> 16);
768*11192Ssam 		addr->vviwc = -(sizeof (struct vv_header) + VVMTU) >> 1;
769*11192Ssam 		addr->vvicsr = VV_RST | VV_CONF;
770*11192Ssam 		addr->vvicsr |= VV_IEN | VV_DEN | VV_ENB;
771*11192Ssam 		return;
772*11192Ssam 
773*11192Ssam 	case PAUSE:
774*11192Ssam 
775*11192Ssam 		/* requested to not start any new reads */
776*11192Ssam 		vs->vs_dropped = 0;
777*11192Ssam 		return;
778*11192Ssam 
779*11192Ssam 	case OPEN:
780*11192Ssam 
781*11192Ssam 		/* request to open host relay */
782*11192Ssam 		vs->vs_dropped = 0;
783*11192Ssam 		addr->vvicsr = 0;
784*11192Ssam 		return;
785*11192Ssam 
786*11192Ssam 	default:
787*11192Ssam 		printf("vv%d: vs_iactive = %d\n", unit, vs->vs_iactive);
788*11192Ssam 		return;
789*11192Ssam 	}
790*11192Ssam 
791*11192Ssam 	/*
792*11192Ssam 	 * drop packet on floor -- count them!!
793*11192Ssam 	 */
794*11192Ssam 
7957640Ssam dropit:
7967640Ssam 	vs->vs_if.if_ierrors++;
797*11192Ssam 	vs->vs_dropped++;
7987640Ssam 	/*
7997640Ssam 	printf("vv%d: error vvicsr = %b\n", unit,
8007640Ssam 		0xffff&(addr->vvicsr), VV_IBITS);
8017640Ssam 	*/
8027640Ssam 	goto setup;
803*11192Ssam 
8047024Ssam }
8057024Ssam 
8067024Ssam /*
8077024Ssam  * V2lni output routine.
8087024Ssam  * Encapsulate a packet of type family for the local net.
8097024Ssam  * Use trailer local net encapsulation if enough data in first
8107024Ssam  * packet leaves a multiple of 512 bytes of data in remainder.
8117024Ssam  */
8127024Ssam vvoutput(ifp, m0, dst)
8137024Ssam 	struct ifnet *ifp;
8147024Ssam 	struct mbuf *m0;
8157024Ssam 	struct sockaddr *dst;
8167024Ssam {
8177024Ssam 	register struct mbuf *m = m0;
8187024Ssam 	register struct vv_header *vv;
8197640Ssam 	register int off;
8207640Ssam 	int type, dest, s, error;
8217024Ssam 
8227024Ssam 	switch (dst->sa_family) {
823*11192Ssam 
8247024Ssam #ifdef INET
8257024Ssam 	case AF_INET: {
8267640Ssam 		dest = ((struct sockaddr_in *)dst)->sin_addr.s_addr;
827*11192Ssam 
828*11192Ssam 		/* check address range */
829*11192Ssam 
830*11192Ssam 		if ((dest = in_lnaof(*((struct in_addr *)&dest))) >= 0x100) {
8317640Ssam 			error = EPERM;
8327640Ssam 			goto bad;
8337640Ssam 		}
8347640Ssam 		off = ntohs((u_short)mtod(m, struct ip *)->ip_len) - m->m_len;
8357640Ssam 		if (vv_dotrailer && off > 0 && (off & 0x1ff) == 0 &&
8367640Ssam 		    m->m_off >= MMINOFF + 2 * sizeof (u_short)) {
8377640Ssam 			type = RING_IPTrailer + (off>>9);
8387640Ssam 			m->m_off -= 2 * sizeof (u_short);
8397640Ssam 			m->m_len += 2 * sizeof (u_short);
8407640Ssam 			*mtod(m, u_short *) = RING_IP;
8417640Ssam 			*(mtod(m, u_short *) + 1) = m->m_len;
8427640Ssam 			goto gottrailertype;
8437640Ssam 		}
8447024Ssam 		type = RING_IP;
8457024Ssam 		off = 0;
8467024Ssam 		goto gottype;
8477024Ssam 		}
8487024Ssam #endif
8497024Ssam 	default:
8507024Ssam 		printf("vv%d: can't handle af%d\n", ifp->if_unit,
8517024Ssam 			dst->sa_family);
8527640Ssam 		error = EAFNOSUPPORT;
8537640Ssam 		goto bad;
8547024Ssam 	}
8557024Ssam 
8567024Ssam gottrailertype:
8577024Ssam 	/*
8587024Ssam 	 * Packet to be sent as trailer: move first packet
8597024Ssam 	 * (control information) to end of chain.
8607024Ssam 	 */
8617024Ssam 	while (m->m_next)
8627024Ssam 		m = m->m_next;
8637024Ssam 	m->m_next = m0;
8647024Ssam 	m = m0->m_next;
8657024Ssam 	m0->m_next = 0;
8667024Ssam 	m0 = m;
8677024Ssam 
8687024Ssam gottype:
8697024Ssam 	/*
8707024Ssam 	 * Add local net header.  If no space in first mbuf,
8717024Ssam 	 * allocate another.
8727024Ssam 	 */
8737024Ssam 	if (m->m_off > MMAXOFF ||
8747024Ssam 	    MMINOFF + sizeof (struct vv_header) > m->m_off) {
875*11192Ssam 		m = m_get(M_DONTWAIT);
8767024Ssam 		if (m == 0) {
8777640Ssam 			error = ENOBUFS;
8787640Ssam 			goto bad;
8797024Ssam 		}
8807024Ssam 		m->m_next = m0;
8817024Ssam 		m->m_off = MMINOFF;
8827024Ssam 		m->m_len = sizeof (struct vv_header);
8837024Ssam 	} else {
8847024Ssam 		m->m_off -= sizeof (struct vv_header);
8857024Ssam 		m->m_len += sizeof (struct vv_header);
8867024Ssam 	}
8877024Ssam 	vv = mtod(m, struct vv_header *);
8887024Ssam 	vv->vh_shost = ifp->if_host[0];
8897024Ssam 	vv->vh_dhost = dest;
8907024Ssam 	vv->vh_version = RING_VERSION;
8917024Ssam 	vv->vh_type = type;
8927640Ssam 	vv->vh_info = off;
893*11192Ssam 	vvtracehdr("vo", vv);
8947024Ssam 
8957024Ssam 	/*
8967024Ssam 	 * Queue message on interface, and start output if interface
8977024Ssam 	 * not yet active.
8987024Ssam 	 */
8997024Ssam 	s = splimp();
9007640Ssam 	if (IF_QFULL(&ifp->if_snd)) {
9017640Ssam 		IF_DROP(&ifp->if_snd);
9027640Ssam 		error = ENOBUFS;
9037640Ssam 		goto qfull;
9047640Ssam 	}
9057024Ssam 	IF_ENQUEUE(&ifp->if_snd, m);
9067024Ssam 	if (vv_softc[ifp->if_unit].vs_oactive == 0)
9077024Ssam 		vvstart(ifp->if_unit);
9087024Ssam 	splx(s);
9097640Ssam 	return (0);
9107640Ssam 
9117640Ssam qfull:
9127640Ssam 	m0 = m;
9137640Ssam 	splx(s);
9147640Ssam bad:
9157640Ssam 	m_freem(m0);
9167640Ssam 	return(error);
9177024Ssam }
9187024Ssam 
9197024Ssam /*
9207024Ssam  * vvprt_hdr(s, v) print the local net header in "v"
9217024Ssam  * 	with title is "s"
9227024Ssam  */
9237024Ssam vvprt_hdr(s, v)
9247024Ssam 	char *s;
9257024Ssam 	register struct vv_header *v;
9267024Ssam {
9277024Ssam 	printf("%s: dsvti: 0x%x 0x%x 0x%x 0x%x 0x%x\n",
9287024Ssam 		s,
9297024Ssam 		0xff & (int)(v->vh_dhost), 0xff & (int)(v->vh_shost),
9307024Ssam 		0xff & (int)(v->vh_version), 0xff & (int)(v->vh_type),
9317024Ssam 		0xffff & (int)(v->vh_info));
9327024Ssam }
9337024Ssam 
9347024Ssam /*
9357024Ssam  * print "l" hex bytes starting at "s"
9367024Ssam  */
9377024Ssam vvprt_hex(s, l)
9387024Ssam 	char *s;
9397024Ssam 	int l;
9407024Ssam {
9417024Ssam 	register int i;
9427024Ssam 	register int z;
9437024Ssam 
9447024Ssam 	for (i=0 ; i < l; i++) {
9457024Ssam 		z = 0xff & (int)(*(s + i));
9467024Ssam 		printf("%c%c ",
9477024Ssam 		"0123456789abcdef"[(z >> 4) & 0x0f],
9487024Ssam 		"0123456789abcdef"[z & 0x0f]
9497024Ssam 		);
9507024Ssam 	}
9517024Ssam }
952