xref: /csrg-svn/sys/vax/if/if_vv.c (revision 35805)
123305Smckusick /*
229372Smckusick  * Copyright (c) 1982, 1986 Regents of the University of California.
335328Sbostic  * All rights reserved.
423305Smckusick  *
535328Sbostic  * Redistribution and use in source and binary forms are permitted
635328Sbostic  * provided that the above copyright notice and this paragraph are
735328Sbostic  * duplicated in all such forms and that any documentation,
835328Sbostic  * advertising materials, and other materials related to such
935328Sbostic  * distribution and use acknowledge that the software was developed
1035328Sbostic  * by the University of California, Berkeley.  The name of the
1135328Sbostic  * University may not be used to endorse or promote products derived
1235328Sbostic  * from this software without specific prior written permission.
1335328Sbostic  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
1435328Sbostic  * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
1535328Sbostic  * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
1635328Sbostic  *
17*35805Skarels  *	@(#)if_vv.c	7.3 (Berkeley) 10/12/88
1823305Smckusick  */
197024Ssam 
209799Ssam #include "vv.h"
2125275Sbloom #if NVV > 0
2211192Ssam 
237024Ssam /*
24*35805Skarels  * Proteon ProNET-10 and ProNET-80 token ring driver.
2520997Skarels  * The name of this device driver derives from the old MIT
2620997Skarels  * name of V2LNI for the proNET hardware, would would abbreviate
27*35805Skarels  * to "v2", but this won't work right in config. Thus the name is "vv".
2811192Ssam  *
29*35805Skarels  * This driver is compatible with the Unibus ProNET 10 megabit and
3020997Skarels  * 80 megabit token ring interfaces (models p1000 and p1080).
3126903Sjas  * A unit may be marked as 80 megabit using "flags 1" in the
3226903Sjas  * config file.
3320997Skarels  *
34*35805Skarels  * This driver is also compatible with the Q-bus ProNET 10 megabit and
35*35805Skarels  * 80 megabit token ring interfaces (models p1100 and p1180), but
36*35805Skarels  * only on a MicroVAX-II or MicroVAX-III.  No attempt is made to
37*35805Skarels  * support the MicroVAX-I.
38*35805Skarels  *
3926950Sjas  * TRAILERS: This driver has a new implementation of trailers that
4026950Sjas  * is at least a tolerable neighbor on the ring. The offset is not
4126950Sjas  * stored in the protocol type, but instead only in the vh_info
4226950Sjas  * field. Also, the vh_info field, and the two shorts before the
4326950Sjas  * trailing header, are in network byte order, not VAX byte order.
4420997Skarels  *
4526950Sjas  * Of course, nothing but BSD UNIX supports trailers on ProNET.
46*35805Skarels  * If you need interoperability with anything else (like the p4200),
47*35805Skarels  * turn off trailers using the -trailers option to /etc/ifconfig!
4826950Sjas  *
4926903Sjas  * HARDWARE COMPATABILITY: This driver prefers that the HSBU (p1001)
5020997Skarels  * have a serial number >= 040, which is about March, 1982. Older
5126903Sjas  * HSBUs do not carry across 64kbyte boundaries. They can be supported
5226903Sjas  * by adding "| UBA_NEED16" to the vs_ifuba.ifu_flags initialization
5326903Sjas  * in vvattach().
5426903Sjas  *
5526903Sjas  * The old warning about use without Wire Centers applies only to CTL
5626903Sjas  * (p1002) cards with serial <= 057, which have not received ECO 176-743,
5726903Sjas  * which was implemented in March, 1982. Most such CTLs have received
5826903Sjas  * this ECO.
597024Ssam  */
6011209Ssam #include "../machine/pte.h"
619799Ssam 
6217117Sbloom #include "param.h"
6317117Sbloom #include "systm.h"
6417117Sbloom #include "mbuf.h"
6517117Sbloom #include "buf.h"
6617117Sbloom #include "protosw.h"
6717117Sbloom #include "socket.h"
6817117Sbloom #include "vmmac.h"
6917117Sbloom #include "errno.h"
7017117Sbloom #include "ioctl.h"
718465Sroot 
728465Sroot #include "../net/if.h"
7311209Ssam #include "../net/netisr.h"
748465Sroot #include "../net/route.h"
7524793Skarels 
7624793Skarels #ifdef	INET
778421Swnj #include "../netinet/in.h"
788421Swnj #include "../netinet/in_systm.h"
7921779Skarels #include "../netinet/in_var.h"
808421Swnj #include "../netinet/ip.h"
8124793Skarels #endif
828465Sroot 
8315794Sleres #include "../vax/cpu.h"
8411209Ssam #include "../vax/mtpr.h"
8517117Sbloom #include "if_vv.h"
8617117Sbloom #include "if_uba.h"
878465Sroot #include "../vaxuba/ubareg.h"
888465Sroot #include "../vaxuba/ubavar.h"
897024Ssam 
907024Ssam /*
9120997Skarels  *    maximum transmission unit definition --
92*35805Skarels  *        you can set VVMTU at anything from 576 to 2036.
9320997Skarels  *        1536 is a popular "large" value, because it is a multiple
9420997Skarels  *	  of 512, which the trailer scheme likes.
95*35805Skarels  *        The absolute maximum size is 2036, which is enforced.
9620997Skarels  */
9720997Skarels 
98*35805Skarels #define VVMTU (2036)
9920997Skarels 
100*35805Skarels #define VVMRU (VVMTU + (2 * sizeof(u_short)))
10120997Skarels #define VVBUFSIZE (VVMRU + sizeof(struct vv_header))
102*35805Skarels #if VVMTU>2036
10320997Skarels #undef VVMTU
10420997Skarels #undef VVMRU
10520997Skarels #undef VVBUFSIZE
10620997Skarels #define VVBUFSIZE (2046)
10720997Skarels #define VVMRU (VVBUFSIZE - sizeof (struct vv_header))
108*35805Skarels #define VVMTU (VVMRU - (2 * sizeof(u_short)))
1097024Ssam #endif
1107024Ssam 
11120997Skarels /*
11220997Skarels  *   debugging and tracing stuff
11320997Skarels  */
11416581Skarels int	vv_tracehdr = 0;	/* 1 => trace headers (slowly!!) */
1157640Ssam 
11620997Skarels #define vvtracehdr  if (vv_tracehdr) vvprt_hdr
11721779Skarels #define vvprintf    if (vs->vs_if.if_flags & IFF_DEBUG) printf
11811192Ssam 
11920997Skarels /*
12020997Skarels  * externals, types, etc.
12120997Skarels  */
12216581Skarels int	vvprobe(), vvattach(), vvreset(), vvinit();
12316581Skarels int	vvidentify(), vvstart(), vvxint(), vvwatchdog();
12426394Skarels int	vvrint(), vvoutput(), vvioctl();
1257024Ssam struct	uba_device *vvinfo[NVV];
1267024Ssam u_short vvstd[] = { 0 };
1277024Ssam struct	uba_driver vvdriver =
1287024Ssam 	{ vvprobe, 0, vvattach, 0, vvstd, "vv", vvinfo };
1297024Ssam #define	VVUNIT(x)	minor(x)
1307024Ssam 
13120997Skarels #define LOOPBACK		/* use loopback for packets meant for us */
13220997Skarels #ifdef	LOOPBACK
13320997Skarels extern struct ifnet loif;
13420997Skarels #endif
13520997Skarels 
1367024Ssam /*
1377024Ssam  * Software status of each interface.
1387024Ssam  *
1397024Ssam  * Each interface is referenced by a network interface structure,
1407024Ssam  * vs_if, which the routing code uses to locate the interface.
1417024Ssam  * This structure contains the output queue for the interface, its address, ...
1427024Ssam  * We also have, for each interface, a UBA interface structure, which
1437024Ssam  * contains information about the UNIBUS resources held by the interface:
1447024Ssam  * map registers, buffered data paths, etc.  Information is cached in this
1457024Ssam  * structure for use by the if_uba.c routines in running the interface
1467024Ssam  * efficiently.
1477024Ssam  */
1487024Ssam struct	vv_softc {
1497024Ssam 	struct	ifnet vs_if;		/* network-visible interface */
1507024Ssam 	struct	ifuba vs_ifuba;		/* UNIBUS resources */
15126298Skarels 	u_short	vs_host;		/* this interface address */
15211192Ssam 	short	vs_oactive;		/* is output active */
15326903Sjas 	short	vs_is80;		/* is 80 megabit version */
1547024Ssam 	short	vs_olen;		/* length of last output */
15515794Sleres 	u_short	vs_lastx;		/* address of last packet sent */
15615794Sleres 	u_short	vs_lastr;		/* address of last packet received */
15711192Ssam 	short	vs_tries;		/* transmit current retry count */
1587024Ssam 	short	vs_init;		/* number of ring inits */
15920997Skarels 	short	vs_refused;		/* number of packets refused */
16015794Sleres 	short	vs_timeouts;		/* number of transmit timeouts */
16120997Skarels 	short	vs_otimeout;		/* number of output timeouts */
16220997Skarels 	short	vs_ibadf;		/* number of input bad formats */
16320997Skarels 	short	vs_parity;		/* number of parity errors on 10 meg, */
16420997Skarels 					/* link data errors on 80 meg */
1657024Ssam } vv_softc[NVV];
1667024Ssam 
16726311Skarels #define	NOHOST	0xffff			/* illegal host number */
16826311Skarels 
16920997Skarels /*
17020997Skarels  * probe the interface to see that the registers exist, and then
17120997Skarels  * cause an interrupt to find its vector
17220997Skarels  */
1737024Ssam vvprobe(reg)
1747024Ssam 	caddr_t reg;
1757024Ssam {
1767024Ssam 	register int br, cvec;
17716581Skarels 	register struct vvreg *addr;
1787024Ssam 
1797024Ssam #ifdef lint
18015764Sleres 	br = 0; cvec = br; br = cvec;
1817024Ssam #endif
18216581Skarels 	addr = (struct vvreg *)reg;
18320997Skarels 
1847024Ssam 	/* reset interface, enable, and wait till dust settles */
1857024Ssam 	addr->vvicsr = VV_RST;
1867024Ssam 	addr->vvocsr = VV_RST;
18715764Sleres 	DELAY(100000);
18820997Skarels 
1897024Ssam 	/* generate interrupt by doing 1 word DMA from 0 in uba space!! */
1907024Ssam 	addr->vvoba = 0;		/* low 16 bits */
1917024Ssam 	addr->vvoea = 0;		/* extended bits */
1927024Ssam 	addr->vvowc = -1;		/* for 1 word */
19320997Skarels 	addr->vvocsr = VV_IEN | VV_DEN;	/* start the DMA, with interrupt */
1947024Ssam 	DELAY(100000);
19520997Skarels 	addr->vvocsr = VV_RST;		/* clear out the CSR */
1967024Ssam 	if (cvec && cvec != 0x200)
19715764Sleres 		cvec -= 4;		/* backup so vector => receive */
1987024Ssam 	return(1);
1997024Ssam }
2007024Ssam 
2017024Ssam /*
2027024Ssam  * Interface exists: make available by filling in network interface
2037024Ssam  * record.  System will initialize the interface when it is ready
2047024Ssam  * to accept packets.
2057024Ssam  */
2067024Ssam vvattach(ui)
2077024Ssam 	struct uba_device *ui;
2087024Ssam {
20915764Sleres 	register struct vv_softc *vs;
2107024Ssam 
21115764Sleres 	vs = &vv_softc[ui->ui_unit];
2127024Ssam 	vs->vs_if.if_unit = ui->ui_unit;
2137024Ssam 	vs->vs_if.if_name = "vv";
2147024Ssam 	vs->vs_if.if_mtu = VVMTU;
21521779Skarels 	vs->vs_if.if_flags = IFF_BROADCAST;
2167024Ssam 	vs->vs_if.if_init = vvinit;
21713057Ssam 	vs->vs_if.if_ioctl = vvioctl;
2187024Ssam 	vs->vs_if.if_output = vvoutput;
21911209Ssam 	vs->vs_if.if_reset = vvreset;
22015794Sleres 	vs->vs_if.if_timer = 0;
22115794Sleres 	vs->vs_if.if_watchdog = vvwatchdog;
22226201Skarels 	vs->vs_ifuba.ifu_flags = UBA_CANTWAIT | UBA_NEEDBDP;
22326903Sjas 
22426903Sjas 	/* use flag to determine if this is proNET-80 */
22526903Sjas 	vs->vs_is80 = (short)(ui->ui_flags & 01);
22626903Sjas 
22712354Smo #if defined(VAX750)
22812354Smo 	/* don't chew up 750 bdp's */
22912354Smo 	if (cpu == VAX_750 && ui->ui_unit > 0)
23012354Smo 		vs->vs_ifuba.ifu_flags &= ~UBA_NEEDBDP;
23112354Smo #endif
2327024Ssam 	if_attach(&vs->vs_if);
2337024Ssam }
2347024Ssam 
2357024Ssam /*
2367024Ssam  * Reset of interface after UNIBUS reset.
2377024Ssam  * If interface is on specified uba, reset its state.
2387024Ssam  */
2397024Ssam vvreset(unit, uban)
2407024Ssam 	int unit, uban;
2417024Ssam {
2427024Ssam 	register struct uba_device *ui;
2437024Ssam 
2447024Ssam 	if (unit >= NVV || (ui = vvinfo[unit]) == 0 || ui->ui_alive == 0 ||
2457024Ssam 	    ui->ui_ubanum != uban)
2467024Ssam 		return;
2477024Ssam 	printf(" vv%d", unit);
2487024Ssam 	vvinit(unit);
2497024Ssam }
2507024Ssam 
2517024Ssam /*
2527024Ssam  * Initialization of interface; clear recorded pending
2537024Ssam  * operations, and reinitialize UNIBUS usage.
2547024Ssam  */
2557024Ssam vvinit(unit)
2567024Ssam 	int unit;
2577024Ssam {
25815764Sleres 	register struct vv_softc *vs;
25915764Sleres 	register struct uba_device *ui;
2607024Ssam 	register struct vvreg *addr;
261*35805Skarels 	register int ubaaddr, s;
2627024Ssam 
26315764Sleres 	vs = &vv_softc[unit];
26415764Sleres 	ui = vvinfo[unit];
26520997Skarels 
26621779Skarels 	if (vs->vs_if.if_addrlist == (struct ifaddr *)0)
26713057Ssam 		return;
26820997Skarels 
2697640Ssam 	addr = (struct vvreg *)ui->ui_addr;
2707024Ssam 	if (if_ubainit(&vs->vs_ifuba, ui->ui_ubanum,
271*35805Skarels 	    sizeof (struct vv_header), (int)btoc(VVMRU)) == 0) {
27215794Sleres 		printf("vv%d: can't initialize, if_ubainit() failed\n", unit);
2737640Ssam 		vs->vs_if.if_flags &= ~IFF_UP;
2747024Ssam 		return;
2757024Ssam 	}
27620997Skarels 
2777024Ssam 	/*
27815764Sleres 	 * Now that the uba is set up, figure out our address and
27915764Sleres 	 * update complete our host address.
2807640Ssam 	 */
28126311Skarels 	if ((vs->vs_host = vvidentify(unit)) == NOHOST) {
28215794Sleres 		vs->vs_if.if_flags &= ~IFF_UP;
28315794Sleres 		return;
28415794Sleres 	}
28526903Sjas 	printf("vv%d: host %u\n", unit, vs->vs_host);
28620997Skarels 
2877640Ssam 	/*
28820997Skarels 	 * Reset the interface, and stay in the ring
2897640Ssam 	 */
29020997Skarels 	addr->vvocsr = VV_RST;			/* take over output */
29120997Skarels 	addr->vvocsr = VV_CPB;			/* clear packet buffer */
29220997Skarels 	addr->vvicsr = VV_RST | VV_HEN;		/* take over input, */
29320997Skarels 						/* keep relay closed */
29412351Smo 	DELAY(500000);				/* let contacts settle */
29520997Skarels 
29620997Skarels 	vs->vs_init = 0;			/* clear counters, etc. */
29720997Skarels 	vs->vs_refused = 0;
29815794Sleres 	vs->vs_timeouts = 0;
29920997Skarels 	vs->vs_otimeout = 0;
30020997Skarels 	vs->vs_ibadf = 0;
30120997Skarels 	vs->vs_parity = 0;
30215794Sleres 	vs->vs_lastx = 256;			/* an invalid address */
30315794Sleres 	vs->vs_lastr = 256;			/* an invalid address */
30420997Skarels 
3057640Ssam 	/*
3067640Ssam 	 * Hang a receive and start any
3077640Ssam 	 * pending writes by faking a transmit complete.
3087640Ssam 	 */
3097640Ssam 	s = splimp();
310*35805Skarels 	ubaaddr = UBAI_ADDR(vs->vs_ifuba.ifu_r.ifrw_info);
311*35805Skarels 	addr->vviba = (u_short)ubaaddr;
312*35805Skarels 	addr->vviea = (u_short)(ubaaddr >> 16);
31320997Skarels 	addr->vviwc = -(VVBUFSIZE) >> 1;
31420997Skarels 	addr->vvicsr = VV_IEN | VV_HEN | VV_DEN | VV_ENB;
3157640Ssam 	vs->vs_oactive = 1;
31621779Skarels 	vs->vs_if.if_flags |= IFF_RUNNING;
3177640Ssam 	vvxint(unit);
3187640Ssam 	splx(s);
3197640Ssam }
3207640Ssam 
3217640Ssam /*
32220997Skarels  * Do a moderately thorough self-test in all three modes. Mostly
32320997Skarels  * to keeps defective nodes off the ring, rather than to be especially
32420997Skarels  * thorough. The key issue is to detect any cable breaks before joining
32520997Skarels  * the ring. Return our node address on success, return -1 on failure.
32620997Skarels  *
3277640Ssam  */
32820997Skarels 
32920997Skarels /* the three self-test modes */
33020997Skarels static u_short vv_modes[] = {
33120997Skarels 	VV_STE|VV_LPB,			/* digital loopback */
33220997Skarels 	VV_STE,				/* analog loopback */
33320997Skarels 	VV_HEN				/* network mode */
33420997Skarels };
33520997Skarels 
33611209Ssam vvidentify(unit)
33713057Ssam 	int unit;
33811209Ssam {
33915764Sleres 	register struct vv_softc *vs;
34015764Sleres 	register struct uba_device *ui;
3417640Ssam 	register struct vvreg *addr;
34216581Skarels 	register struct mbuf *m;
34316581Skarels 	register struct vv_header *v;
344*35805Skarels 	register int ubaaddr;
34520997Skarels 	register int i, successes, failures, waitcount;
34626311Skarels 	u_short shost = NOHOST;
3477640Ssam 
34820997Skarels 	vs = &vv_softc[unit];
34920997Skarels 	ui = vvinfo[unit];
35020997Skarels 	addr = (struct vvreg *)ui->ui_addr;
35120997Skarels 
3527640Ssam 	/*
3537024Ssam 	 * Build a multicast message to identify our address
35420997Skarels 	 * We need do this only once, since nobody else is about to use
35520997Skarels 	 * the intermediate transmit buffer (ifu_w.ifrw_addr) that
35620997Skarels 	 * if_ubainit() aquired for us.
3577024Ssam 	 */
35811209Ssam 	m = m_get(M_DONTWAIT, MT_HEADER);
35915794Sleres 	if (m == NULL) {
36015794Sleres 		printf("vv%d: can't initialize, m_get() failed\n", unit);
36113057Ssam 		return (0);
36215794Sleres 	}
36311192Ssam 	m->m_next = 0;
3647024Ssam 	m->m_off = MMINOFF;
3657024Ssam 	m->m_len = sizeof(struct vv_header);
3667024Ssam 	v = mtod(m, struct vv_header *);
36711192Ssam 	v->vh_dhost = VV_BROADCAST;	/* multicast destination address */
3687024Ssam 	v->vh_shost = 0;		/* will be overwritten with ours */
3697024Ssam 	v->vh_version = RING_VERSION;
37020997Skarels 	v->vh_type = RING_DIAGNOSTICS;
3717024Ssam 	v->vh_info = 0;
37220997Skarels 	/* map xmit message into uba, copying to intermediate buffer */
37320997Skarels 	vs->vs_olen = if_wubaput(&vs->vs_ifuba, m);
37420997Skarels 
3757024Ssam 	/*
37620997Skarels 	 * For each of the modes (digital, analog, network), go through
37720997Skarels 	 * a self-test that requires me to send VVIDENTSUCC good packets
37820997Skarels 	 * in VVIDENTRETRY attempts. Use broadcast destination to find out
37920997Skarels 	 * who I am, then use this as my address to check my address match
38020997Skarels 	 * logic. Only data checked is the vh_type field.
3817024Ssam 	 */
3827640Ssam 
38320997Skarels 	for (i = 0; i < 3; i++) {
38420997Skarels 		successes = 0;	/* clear successes for this mode */
38520997Skarels 		failures = 0;	/* and clear failures, too */
3867640Ssam 
38720997Skarels 		/* take over device, and leave ring */
38820997Skarels 		addr->vvicsr = VV_RST;
38920997Skarels 		addr->vvocsr = VV_RST;
39020997Skarels 		addr->vvicsr = vv_modes[i];	/* test mode */
39120997Skarels 
39220997Skarels 		/*
39320997Skarels 		 * let the flag and token timers pop so that the init ring bit
39420997Skarels 		 * will be allowed to work, by waiting about 1 second
39520997Skarels 		 */
39620997Skarels 		DELAY(1000000L);
39720997Skarels 
39820997Skarels 		/*
39920997Skarels 		 * retry loop
40020997Skarels  		 */
40120997Skarels 		while ((successes < VVIDENTSUCC) && (failures < VVIDENTRETRY))
40220997Skarels 		{
40320997Skarels 			/* start a receive */
404*35805Skarels 			ubaaddr = UBAI_ADDR(vs->vs_ifuba.ifu_r.ifrw_info);
40520997Skarels 			addr->vvicsr = VV_RST | vv_modes[i]; /* abort last */
406*35805Skarels 			addr->vviba = (u_short) ubaaddr;
407*35805Skarels 			addr->vviea = (u_short) (ubaaddr >> 16);
40820997Skarels 			addr->vviwc = -(VVBUFSIZE) >> 1;
40920997Skarels 			addr->vvicsr = vv_modes[i] | VV_DEN | VV_ENB;
41020997Skarels 
41120997Skarels 			/* purge stale data from BDP */
41220997Skarels 			if (vs->vs_ifuba.ifu_flags & UBA_NEEDBDP)
41320997Skarels 				UBAPURGE(vs->vs_ifuba.ifu_uba,
41420997Skarels 				    vs->vs_ifuba.ifu_w.ifrw_bdp);
41520997Skarels 
41620997Skarels 			/* do a transmit */
417*35805Skarels 			ubaaddr = UBAI_ADDR(vs->vs_ifuba.ifu_w.ifrw_info);
41820997Skarels 			addr->vvocsr = VV_RST;	/* abort last try */
419*35805Skarels 			addr->vvoba = (u_short) ubaaddr;
420*35805Skarels 			addr->vvoea = (u_short) (ubaaddr >> 16);
42120997Skarels 			addr->vvowc = -((vs->vs_olen + 1) >> 1);
42220997Skarels 			addr->vvocsr = VV_CPB | VV_DEN | VV_INR | VV_ENB;
42320997Skarels 
42420997Skarels 			/* poll receive side for completion */
42520997Skarels 			DELAY(10000);		/* give it a chance */
42620997Skarels 			for (waitcount = 0; waitcount < 10; waitcount++) {
42720997Skarels 				if (addr->vvicsr & VV_RDY)
42820997Skarels 					goto gotit;
42920997Skarels 				DELAY(1000);
43020997Skarels 			}
43120997Skarels 			failures++;		/* no luck */
43211209Ssam 			continue;
43320997Skarels 
43420997Skarels gotit:			/* we got something--is it any good? */
43520997Skarels 			if ((addr->vvicsr & (VVRERR|VV_LDE)) ||
43621779Skarels 			    (addr->vvocsr & (VVXERR|VV_RFS))) {
43720997Skarels 				failures++;
43820997Skarels 				continue;
43920997Skarels 			}
44020997Skarels 
44120997Skarels 			/* Purge BDP before looking at received packet */
44220997Skarels 			if (vs->vs_ifuba.ifu_flags & UBA_NEEDBDP)
44320997Skarels 				UBAPURGE(vs->vs_ifuba.ifu_uba,
44420997Skarels 				    vs->vs_ifuba.ifu_r.ifrw_bdp);
44524793Skarels 			m = if_rubaget(&vs->vs_ifuba, sizeof(struct vv_header),
44626394Skarels 				0, &vs->vs_if);
44720997Skarels 			if (m != NULL)
44820997Skarels 				m_freem(m);
44920997Skarels 
45020997Skarels 			v = (struct vv_header *)(vs->vs_ifuba.ifu_r.ifrw_addr);
45120997Skarels 
45220997Skarels 			/* check message type, catch our node address */
45320997Skarels 			if ((v->vh_type & 0xff) == RING_DIAGNOSTICS) {
45426311Skarels 				if (shost == NOHOST) {
45520997Skarels 					shost = v->vh_shost & 0xff;
45620997Skarels 					/* send to ourself now */
45720997Skarels 					((struct vv_header *)
45820997Skarels 					    (vs->vs_ifuba.ifu_r.ifrw_addr))
45920997Skarels 					    ->vh_dhost = shost;
46020997Skarels 				}
46120997Skarels 				successes++;
46226903Sjas 			} else {
46326903Sjas 				failures++;
46420997Skarels 			}
46526903Sjas 			v->vh_type = 0;  /* clear to check again */
46611192Ssam 		}
46720997Skarels 
46820997Skarels 		if (failures >= VVIDENTRETRY)
46920997Skarels 		{
47020997Skarels 			printf("vv%d: failed self-test after %d tries \
47120997Skarels in %s mode\n",
47220997Skarels 			    unit, VVIDENTRETRY, i == 0 ? "digital loopback" :
47320997Skarels 			    (i == 1 ? "analog loopback" : "network"));
47420997Skarels 			printf("vv%d: icsr = %b, ocsr = %b\n",
47520997Skarels 			    unit, 0xffff & addr->vvicsr, VV_IBITS,
47620997Skarels 			    0xffff & addr->vvocsr, VV_OBITS);
47720997Skarels 			addr->vvicsr = VV_RST;	/* kill the sick board */
47820997Skarels 			addr->vvocsr = VV_RST;
47926311Skarels 			shost = NOHOST;
48020997Skarels 			goto done;
48120997Skarels 		}
48211192Ssam 	}
48320997Skarels 
48420997Skarels done:
48520997Skarels 	/* deallocate mbuf used for send packet (won't be one, anyways) */
48615794Sleres 	if (vs->vs_ifuba.ifu_xtofree) {
4877024Ssam 		m_freem(vs->vs_ifuba.ifu_xtofree);
48815794Sleres 		vs->vs_ifuba.ifu_xtofree = 0;
48915794Sleres 	}
49020997Skarels 
49120997Skarels 	return(shost);
4927024Ssam }
4937024Ssam 
4947024Ssam /*
4957024Ssam  * Start or restart output on interface.
49611192Ssam  * If interface is active, this is a retransmit, so just
49711192Ssam  * restuff registers and go.
4987024Ssam  * If interface is not already active, get another datagram
4997024Ssam  * to send off of the interface queue, and map it to the interface
5007024Ssam  * before starting the output.
5017024Ssam  */
5027024Ssam vvstart(dev)
5037024Ssam 	dev_t dev;
5047024Ssam {
50516581Skarels 	register struct uba_device *ui;
50615764Sleres 	register struct vv_softc *vs;
5077024Ssam 	register struct vvreg *addr;
50816581Skarels 	register struct mbuf *m;
509*35805Skarels 	register int unit, ubaaddr, dest, s;
5107024Ssam 
51116581Skarels 	unit = VVUNIT(dev);
51215764Sleres 	ui = vvinfo[unit];
51315764Sleres 	vs = &vv_softc[unit];
5147024Ssam 	if (vs->vs_oactive)
5157024Ssam 		goto restart;
5167024Ssam 	/*
5177024Ssam 	 * Not already active: dequeue another request
5187024Ssam 	 * and map it to the UNIBUS.  If no more requests,
5197024Ssam 	 * just return.
5207024Ssam 	 */
52115794Sleres 	s = splimp();
5227024Ssam 	IF_DEQUEUE(&vs->vs_if.if_snd, m);
52315794Sleres 	splx(s);
52411209Ssam 	if (m == NULL) {
5257024Ssam 		vs->vs_oactive = 0;
5267024Ssam 		return;
5277024Ssam 	}
5287024Ssam 	dest = mtod(m, struct vv_header *)->vh_dhost;
5297024Ssam 	vs->vs_olen = if_wubaput(&vs->vs_ifuba, m);
5307024Ssam 	vs->vs_lastx = dest;
5317024Ssam restart:
5327024Ssam 	/*
5337024Ssam 	 * Have request mapped to UNIBUS for transmission.
53415794Sleres 	 * Purge any stale data from this BDP, and start the output.
53515794Sleres 	 *
53615794Sleres 	 * Make sure this packet will fit in the interface.
5377024Ssam 	 */
53820997Skarels 	if (vs->vs_olen > VVBUFSIZE) {
53920997Skarels 		printf("vv%d vs_olen: %d > VVBUFSIZE\n", unit, vs->vs_olen);
54011192Ssam 		panic("vvdriver vs_olen botch");
54111192Ssam 	}
54220997Skarels 
54320997Skarels 	vs->vs_if.if_timer = VVTIMEOUT;
54420997Skarels 	vs->vs_oactive = 1;
54520997Skarels 
54620997Skarels 	/* ship it */
5477024Ssam 	if (vs->vs_ifuba.ifu_flags & UBA_NEEDBDP)
5487024Ssam 		UBAPURGE(vs->vs_ifuba.ifu_uba, vs->vs_ifuba.ifu_w.ifrw_bdp);
5497024Ssam 	addr = (struct vvreg *)ui->ui_addr;
550*35805Skarels 	ubaaddr = UBAI_ADDR(vs->vs_ifuba.ifu_w.ifrw_info);
551*35805Skarels 	addr->vvoba = (u_short) ubaaddr;
552*35805Skarels 	addr->vvoea = (u_short) (ubaaddr >> 16);
5537024Ssam 	addr->vvowc = -((vs->vs_olen + 1) >> 1);
55420997Skarels 	addr->vvowc = -((vs->vs_olen + 1) >> 1); /* extra byte is garbage */
55520997Skarels 	if (addr->vvocsr & VV_NOK)
55620997Skarels 		vs->vs_init++;			/* count ring inits */
5577024Ssam 	addr->vvocsr = VV_IEN | VV_CPB | VV_DEN | VV_INR | VV_ENB;
5587024Ssam }
5597024Ssam 
5607024Ssam /*
56120997Skarels  * proNET transmit interrupt
5627024Ssam  * Start another output if more data to send.
5637024Ssam  */
5647024Ssam vvxint(unit)
5657024Ssam 	int unit;
5667024Ssam {
56715764Sleres 	register struct uba_device *ui;
56815764Sleres 	register struct vv_softc *vs;
5697024Ssam 	register struct vvreg *addr;
5707024Ssam 	register int oc;
5717024Ssam 
57215764Sleres 	ui = vvinfo[unit];
57315764Sleres 	vs = &vv_softc[unit];
57415794Sleres 	vs->vs_if.if_timer = 0;
5757024Ssam 	addr = (struct vvreg *)ui->ui_addr;
5767024Ssam 	oc = 0xffff & (addr->vvocsr);
5777024Ssam 	if (vs->vs_oactive == 0) {
57820997Skarels 		vvprintf("vv%d: stray interrupt vvocsr = %b\n", unit,
57915764Sleres 		    oc, VV_OBITS);
5807024Ssam 		return;
5817024Ssam 	}
58220997Skarels 
58320997Skarels 	/*
58420997Skarels 	 * we retransmit on soft error
58520997Skarels 	 * TODO: sort retransmits to end of queue if possible!
58620997Skarels 	 */
58720997Skarels 	if (oc & (VV_OPT | VV_RFS)) {
58811192Ssam 		if (vs->vs_tries++ < VVRETRY) {
5897024Ssam 			if (oc & VV_OPT)
59020997Skarels 				vs->vs_otimeout++;
59120997Skarels 			if (oc & VV_RFS) {
59220997Skarels 				vs->vs_if.if_collisions++;
59320997Skarels 				vs->vs_refused++;
59420997Skarels 			}
59511192Ssam 			vvstart(unit);		/* restart this message */
5967024Ssam 			return;
5977024Ssam 		}
5987024Ssam 	}
5997024Ssam 	vs->vs_if.if_opackets++;
6007024Ssam 	vs->vs_oactive = 0;
6017024Ssam 	vs->vs_tries = 0;
60220997Skarels 
6037024Ssam 	if (oc & VVXERR) {
6047024Ssam 		vs->vs_if.if_oerrors++;
60520997Skarels 		vvprintf("vv%d: error vvocsr = %b\n", unit, 0xffff & oc,
60615764Sleres 		    VV_OBITS);
6077024Ssam 	}
6087024Ssam 	if (vs->vs_ifuba.ifu_xtofree) {
6097024Ssam 		m_freem(vs->vs_ifuba.ifu_xtofree);
6107024Ssam 		vs->vs_ifuba.ifu_xtofree = 0;
6117024Ssam 	}
6127024Ssam 	vvstart(unit);
6137024Ssam }
6147024Ssam 
6157024Ssam /*
61615794Sleres  * Transmit watchdog timer routine.
61715794Sleres  * This routine gets called when we lose a transmit interrupt.
61815794Sleres  * The best we can do is try to restart output.
61915794Sleres  */
62015794Sleres vvwatchdog(unit)
62115794Sleres 	int unit;
62215794Sleres {
62315794Sleres 	register struct vv_softc *vs;
62415794Sleres 	register int s;
62515794Sleres 
62615794Sleres 	vs = &vv_softc[unit];
62720997Skarels 	vvprintf("vv%d: lost a transmit interrupt.\n", unit);
62815794Sleres 	vs->vs_timeouts++;
62915794Sleres 	s = splimp();
63015794Sleres 	vvstart(unit);
63115794Sleres 	splx(s);
63215794Sleres }
63315794Sleres 
63415794Sleres /*
63520997Skarels  * proNET interface receiver interrupt.
6367024Ssam  * If input error just drop packet.
63715764Sleres  * Otherwise purge input buffered data path and examine
6387024Ssam  * packet to determine type.  If can't determine length
63915764Sleres  * from type, then have to drop packet.  Otherwise decapsulate
6407024Ssam  * packet based on type and pass to type specific higher-level
6417024Ssam  * input routine.
6427024Ssam  */
6437024Ssam vvrint(unit)
6447024Ssam 	int unit;
6457024Ssam {
64615764Sleres 	register struct vv_softc *vs;
64716581Skarels 	register struct vvreg *addr;
6487024Ssam 	register struct vv_header *vv;
6497024Ssam 	register struct ifqueue *inq;
65016581Skarels 	register struct mbuf *m;
651*35805Skarels 	int ubaaddr, len, off, s;
6527640Ssam 	short resid;
6537024Ssam 
65415764Sleres 	vs = &vv_softc[unit];
65516581Skarels 	vs->vs_if.if_ipackets++;
65615764Sleres 	addr = (struct vvreg *)vvinfo[unit]->ui_addr;
65720997Skarels 
6587024Ssam 	/*
65926903Sjas 	 * Purge BDP
6607024Ssam 	 */
6617024Ssam 	if (vs->vs_ifuba.ifu_flags & UBA_NEEDBDP)
6627024Ssam 		UBAPURGE(vs->vs_ifuba.ifu_uba, vs->vs_ifuba.ifu_r.ifrw_bdp);
66320997Skarels 
66420997Skarels 	/*
66520997Skarels 	 * receive errors?
66620997Skarels 	 */
6677024Ssam 	if (addr->vvicsr & VVRERR) {
66820997Skarels 		vvprintf("vv%d: receive error, vvicsr = %b\n", unit,
66920997Skarels 		    0xffff&(addr->vvicsr), VV_IBITS);
67020997Skarels 		if (addr->vvicsr & VV_BDF)
67120997Skarels 			vs->vs_ibadf++;
6727640Ssam 		goto dropit;
6737024Ssam 	}
6747640Ssam 
6757024Ssam 	/*
67620997Skarels 	 * parity errors?
67720997Skarels 	 */
67820997Skarels 	if (addr->vvicsr & VV_LDE) {
67920997Skarels 		/* we don't have to clear it because the receive command */
68020997Skarels 		/* writes 0 to parity bit */
68120997Skarels 		vs->vs_parity++;
68226903Sjas 
68320997Skarels 		/*
68420997Skarels 		 * only on 10 megabit proNET is VV_LDE an end-to-end parity
68520997Skarels 		 * bit. On 80 megabit, it returns to the intended use of
68620997Skarels 		 * node-to-node parity. End-to-end parity errors on 80 megabit
68720997Skarels 		 * give VV_BDF.
68820997Skarels 		 */
68926903Sjas 		if (vs->vs_is80 == 0)
69026903Sjas 		    goto dropit;
69120997Skarels 	}
69220997Skarels 
69320997Skarels 	/*
69420997Skarels 	 * Get packet length from residual word count
6957640Ssam 	 *
6967640Ssam 	 * Compute header offset if trailer protocol
6977640Ssam 	 *
6987640Ssam 	 * Pull packet off interface.  Off is nonzero if packet
6997640Ssam 	 * has trailing header; if_rubaget will then force this header
7007640Ssam 	 * information to be at the front.  The vh_info field
7017640Ssam 	 * carries the offset to the trailer data in trailer
7027640Ssam 	 * format packets.
7037024Ssam 	 */
7047640Ssam 	vv = (struct vv_header *)(vs->vs_ifuba.ifu_r.ifrw_addr);
70511192Ssam 	vvtracehdr("vi", vv);
70620997Skarels 	resid = addr->vviwc & 01777;	/* only low 10 bits valid */
7077640Ssam 	if (resid)
70820997Skarels 		resid |= 0176000;	/* high 6 bits are undefined */
70920997Skarels 	len = ((VVBUFSIZE >> 1) + resid) << 1;
7107640Ssam 	len -= sizeof(struct vv_header);
71120997Skarels 
71220997Skarels 	if ((addr->vvicsr & VV_DPR) || len > VVMRU || len <= 0) {
71320997Skarels 		vvprintf("vv%d: len too long or short, \
71420997Skarels len = %d, vvicsr = %b\n",
71515794Sleres 			    unit, len, 0xffff&(addr->vvicsr), VV_IBITS);
7167640Ssam 		goto dropit;
71715794Sleres 	}
71820997Skarels 
71920997Skarels 	/* check the protocol header version */
72020997Skarels 	if (vv->vh_version != RING_VERSION) {
72120997Skarels 		vvprintf("vv%d: bad protocol header version %d\n",
72220997Skarels 		    unit, vv->vh_version & 0xff);
72320997Skarels 		goto dropit;
72420997Skarels 	}
72520997Skarels 
7267640Ssam #define	vvdataaddr(vv, off, type)	((type)(((caddr_t)((vv)+1)+(off))))
72726950Sjas 	if (vv->vh_type == RING_TRAILER ) {
72828954Skarels 		off = ntohs((u_short)vv->vh_info);
72915794Sleres 		if (off > VVMTU) {
73020997Skarels 			vvprintf("vv%d: off > VVMTU, off = %d, vvicsr = %b\n",
73115794Sleres 				    unit, off, 0xffff&(addr->vvicsr), VV_IBITS);
7327640Ssam 			goto dropit;
73315794Sleres 		}
73426903Sjas 		vv->vh_type = ntohs(*vvdataaddr(vv, off, u_short *));
73526950Sjas 		resid = ntohs(*(vvdataaddr(vv, off+sizeof(u_short), u_short *)));
73615794Sleres 		if (off + resid > len) {
73720997Skarels 			vvprintf("vv%d: trailer packet too short\n", unit);
73820997Skarels 			vvprintf("vv%d: off = %d, resid = %d, vvicsr = %b\n",
73915794Sleres 				    unit, off, resid,
74015794Sleres 				    0xffff&(addr->vvicsr), VV_IBITS);
7417640Ssam 			goto dropit;
74215794Sleres 		}
7437640Ssam 		len = off + resid;
74411209Ssam 	} else
7457640Ssam 		off = 0;
74620997Skarels 
74715794Sleres 	if (len == 0) {
74820997Skarels 		vvprintf("vv%d: len is zero, vvicsr = %b\n", unit,
74915794Sleres 			    0xffff&(addr->vvicsr), VV_IBITS);
7507640Ssam 		goto dropit;
75115794Sleres 	}
75220997Skarels 
75324793Skarels 	m = if_rubaget(&vs->vs_ifuba, len, off, &vs->vs_if);
75415794Sleres 	if (m == NULL) {
75520997Skarels 		vvprintf("vv%d: if_rubaget() failed, vvicsr = %b\n", unit,
75615794Sleres 			    0xffff&(addr->vvicsr), VV_IBITS);
7577640Ssam 		goto dropit;
75815794Sleres 	}
7597640Ssam 	if (off) {
76024793Skarels 		struct ifnet *ifp;
76124793Skarels 
76224793Skarels 		ifp = *(mtod(m, struct ifnet **));
76324793Skarels 		m->m_off += 2 * sizeof (u_short);
76424793Skarels 		m->m_len -= 2 * sizeof (u_short);
76524793Skarels 		*(mtod(m, struct ifnet **)) = ifp;
7667640Ssam 	}
76711192Ssam 
76815794Sleres 	/* Keep track of source address of this packet */
76915794Sleres 	vs->vs_lastr = vv->vh_shost;
77020997Skarels 
77111192Ssam 	/*
77215764Sleres 	 * Demultiplex on packet type
77311192Ssam 	 */
7747024Ssam 	switch (vv->vh_type) {
77511192Ssam 
7767024Ssam #ifdef INET
7777024Ssam 	case RING_IP:
7787024Ssam 		schednetisr(NETISR_IP);
7797024Ssam 		inq = &ipintrq;
7807024Ssam 		break;
7817024Ssam #endif
7827024Ssam 	default:
78320997Skarels 		vvprintf("vv%d: unknown pkt type 0x%x\n", unit, vv->vh_type);
7847640Ssam 		m_freem(m);
7857024Ssam 		goto setup;
7867024Ssam 	}
78715794Sleres 	s = splimp();
7887640Ssam 	if (IF_QFULL(inq)) {
7897640Ssam 		IF_DROP(inq);
7907640Ssam 		m_freem(m);
79111209Ssam 	} else
7927640Ssam 		IF_ENQUEUE(inq, m);
79315764Sleres 
79415794Sleres 	splx(s);
7957024Ssam 	/*
79615764Sleres 	 * Reset for the next packet.
7977024Ssam 	 */
79815764Sleres setup:
799*35805Skarels 	ubaaddr = UBAI_ADDR(vs->vs_ifuba.ifu_r.ifrw_info);
800*35805Skarels 	addr->vviba = (u_short) ubaaddr;
801*35805Skarels 	addr->vviea = (u_short) (ubaaddr >> 16);
80220997Skarels 	addr->vviwc = -(VVBUFSIZE) >> 1;
80320997Skarels 	addr->vvicsr = VV_HEN | VV_IEN | VV_DEN | VV_ENB;
80415764Sleres 	return;
80511192Ssam 
80611192Ssam 	/*
80711209Ssam 	 * Drop packet on floor -- count them!!
80811192Ssam 	 */
8097640Ssam dropit:
8107640Ssam 	vs->vs_if.if_ierrors++;
8117640Ssam 	goto setup;
8127024Ssam }
8137024Ssam 
8147024Ssam /*
81520997Skarels  * proNET output routine.
8167024Ssam  * Encapsulate a packet of type family for the local net.
8177024Ssam  * Use trailer local net encapsulation if enough data in first
8187024Ssam  * packet leaves a multiple of 512 bytes of data in remainder.
8197024Ssam  */
8207024Ssam vvoutput(ifp, m0, dst)
8217024Ssam 	struct ifnet *ifp;
8227024Ssam 	struct mbuf *m0;
8237024Ssam 	struct sockaddr *dst;
8247024Ssam {
82516581Skarels 	register struct mbuf *m;
8267024Ssam 	register struct vv_header *vv;
8277640Ssam 	register int off;
82816581Skarels 	register int unit;
82916581Skarels 	register struct vvreg *addr;
83016581Skarels 	register struct vv_softc *vs;
83116581Skarels 	register int s;
83216581Skarels 	int type, dest, error;
8337024Ssam 
83416581Skarels 	m = m0;
83516581Skarels 	unit = ifp->if_unit;
83616581Skarels 	addr = (struct vvreg *)vvinfo[unit]->ui_addr;
83716581Skarels 	vs = &vv_softc[unit];
83820997Skarels 
83916581Skarels 	/*
84020997Skarels 	 * Check to see if the input side has wedged due the UBA
84120997Skarels 	 * vectoring through 0.
84216581Skarels 	 *
84316581Skarels 	 * We are lower than device ipl when we enter this routine,
84416581Skarels 	 * so if the interface is ready with an input packet then
84516581Skarels 	 * an input interrupt must have slipped through the cracks.
84616581Skarels 	 *
84716581Skarels 	 * Avoid the race with an input interrupt by watching to see
84816581Skarels 	 * if any packets come in.
84916581Skarels 	 */
85016581Skarels 	s = vs->vs_if.if_ipackets;
85116581Skarels 	if (addr->vvicsr & VV_RDY && s == vs->vs_if.if_ipackets) {
85220997Skarels 		vvprintf("vv%d: lost a receive interrupt, icsr = %b\n",
85316581Skarels 			    unit, 0xffff&(addr->vvicsr), VV_IBITS);
85416581Skarels 		s = splimp();
85516581Skarels 		vvrint(unit);
85616581Skarels 		splx(s);
85716581Skarels 	}
85816581Skarels 
8597024Ssam 	switch (dst->sa_family) {
86011192Ssam 
8617024Ssam #ifdef INET
86215764Sleres 	case AF_INET:
86321779Skarels 		if (in_broadcast(((struct sockaddr_in *)dst)->sin_addr))
86421779Skarels 			dest = VV_BROADCAST;
86521779Skarels 		else
86621779Skarels 			dest = in_lnaof(((struct sockaddr_in *)dst)->sin_addr);
86720997Skarels #ifdef LOOPBACK
86821779Skarels 		if (dest == vs->vs_host && (loif.if_flags & IFF_UP))
86921779Skarels 			return (looutput(&loif, m0, dst));
87020997Skarels #endif LOOPBACK
87121779Skarels 		if (dest >= 0x100) {
8727640Ssam 			error = EPERM;
8737640Ssam 			goto bad;
8747640Ssam 		}
8757640Ssam 		off = ntohs((u_short)mtod(m, struct ip *)->ip_len) - m->m_len;
87620997Skarels 		/*
87720997Skarels 		 * Trailerize, if the configuration allows it.
87820997Skarels 		 * TODO: Need per host negotiation.
87920997Skarels 		 */
88013090Ssam 		if ((ifp->if_flags & IFF_NOTRAILERS) == 0)
88113090Ssam 		if (off > 0 && (off & 0x1ff) == 0 &&
8827640Ssam 		    m->m_off >= MMINOFF + 2 * sizeof (u_short)) {
88326950Sjas 			type = RING_TRAILER;
8847640Ssam 			m->m_off -= 2 * sizeof (u_short);
8857640Ssam 			m->m_len += 2 * sizeof (u_short);
88628954Skarels 			*mtod(m, u_short *) = htons((short)RING_IP);
88728954Skarels 			*(mtod(m, u_short *) + 1) = htons((u_short)m->m_len);
8887640Ssam 			goto gottrailertype;
8897640Ssam 		}
8907024Ssam 		type = RING_IP;
8917024Ssam 		off = 0;
8927024Ssam 		goto gottype;
8937024Ssam #endif
8947024Ssam 	default:
89516581Skarels 		printf("vv%d: can't handle af%d\n", unit, dst->sa_family);
8967640Ssam 		error = EAFNOSUPPORT;
8977640Ssam 		goto bad;
8987024Ssam 	}
8997024Ssam 
9007024Ssam gottrailertype:
9017024Ssam 	/*
9027024Ssam 	 * Packet to be sent as trailer: move first packet
9037024Ssam 	 * (control information) to end of chain.
9047024Ssam 	 */
9057024Ssam 	while (m->m_next)
9067024Ssam 		m = m->m_next;
9077024Ssam 	m->m_next = m0;
9087024Ssam 	m = m0->m_next;
9097024Ssam 	m0->m_next = 0;
9107024Ssam 	m0 = m;
9117024Ssam gottype:
9127024Ssam 	/*
9137024Ssam 	 * Add local net header.  If no space in first mbuf,
9147024Ssam 	 * allocate another.
9157024Ssam 	 */
9167024Ssam 	if (m->m_off > MMAXOFF ||
9177024Ssam 	    MMINOFF + sizeof (struct vv_header) > m->m_off) {
91811209Ssam 		m = m_get(M_DONTWAIT, MT_HEADER);
91911209Ssam 		if (m == NULL) {
9207640Ssam 			error = ENOBUFS;
9217640Ssam 			goto bad;
9227024Ssam 		}
9237024Ssam 		m->m_next = m0;
9247024Ssam 		m->m_off = MMINOFF;
9257024Ssam 		m->m_len = sizeof (struct vv_header);
9267024Ssam 	} else {
9277024Ssam 		m->m_off -= sizeof (struct vv_header);
9287024Ssam 		m->m_len += sizeof (struct vv_header);
9297024Ssam 	}
9307024Ssam 	vv = mtod(m, struct vv_header *);
93121779Skarels 	vv->vh_shost = vs->vs_host;
93221779Skarels 	vv->vh_dhost = dest;
9337024Ssam 	vv->vh_version = RING_VERSION;
9347024Ssam 	vv->vh_type = type;
93528954Skarels 	vv->vh_info = htons((u_short)off);
93611192Ssam 	vvtracehdr("vo", vv);
9377024Ssam 
9387024Ssam 	/*
9397024Ssam 	 * Queue message on interface, and start output if interface
9407024Ssam 	 * not yet active.
9417024Ssam 	 */
9427024Ssam 	s = splimp();
9437640Ssam 	if (IF_QFULL(&ifp->if_snd)) {
9447640Ssam 		IF_DROP(&ifp->if_snd);
9457640Ssam 		error = ENOBUFS;
9467640Ssam 		goto qfull;
9477640Ssam 	}
9487024Ssam 	IF_ENQUEUE(&ifp->if_snd, m);
94916581Skarels 	if (vs->vs_oactive == 0)
95016581Skarels 		vvstart(unit);
9517024Ssam 	splx(s);
9527640Ssam 	return (0);
9537640Ssam qfull:
9547640Ssam 	m0 = m;
9557640Ssam 	splx(s);
9567640Ssam bad:
9577640Ssam 	m_freem(m0);
9587640Ssam 	return(error);
9597024Ssam }
9607024Ssam 
9617024Ssam /*
96213057Ssam  * Process an ioctl request.
96313057Ssam  */
96413057Ssam vvioctl(ifp, cmd, data)
96513057Ssam 	register struct ifnet *ifp;
96613057Ssam 	int cmd;
96713057Ssam 	caddr_t data;
96813057Ssam {
96921779Skarels 	struct ifaddr *ifa = (struct ifaddr *) data;
97021779Skarels 	int s = splimp(), error = 0;
97113057Ssam 
97213057Ssam 	switch (cmd) {
97313057Ssam 
97413057Ssam 	case SIOCSIFADDR:
97524793Skarels 		ifp->if_flags |= IFF_UP;
97621779Skarels 		if ((ifp->if_flags & IFF_RUNNING) == 0)
97713057Ssam 			vvinit(ifp->if_unit);
97826903Sjas 		/*
97926903Sjas 		 * Did self-test succeed?
98026903Sjas 		 */
98126903Sjas 		if ((ifp->if_flags & IFF_UP) == 0)
98226903Sjas 			error = ENETDOWN;
98321779Skarels                 /*
98421779Skarels                  * Attempt to check agreement of protocol address
98521779Skarels                  * and board address.
98621779Skarels                  */
98721779Skarels 		switch (ifa->ifa_addr.sa_family) {
98821779Skarels                 case AF_INET:
98921779Skarels 			if (in_lnaof(IA_SIN(ifa)->sin_addr) !=
99021779Skarels 			    vv_softc[ifp->if_unit].vs_host)
99125194Skarels 				error = EADDRNOTAVAIL;
99221779Skarels 			break;
99321779Skarels 		}
99413057Ssam 		break;
99513057Ssam 
99613057Ssam 	default:
99713057Ssam 		error = EINVAL;
99813057Ssam 	}
99913057Ssam 	splx(s);
100021779Skarels 	return (error);
100113057Ssam }
100225190Skarels 
100325190Skarels /*
100425190Skarels  * vvprt_hdr(s, v) print the local net header in "v"
100525190Skarels  *	with title is "s"
100625190Skarels  */
100725190Skarels vvprt_hdr(s, v)
100825190Skarels 	char *s;
100925190Skarels 	register struct vv_header *v;
101025190Skarels {
101125190Skarels 	printf("%s: dsvti: 0x%x 0x%x 0x%x 0x%x 0x%x\n",
101225190Skarels 		s,
101325190Skarels 		0xff & (int)(v->vh_dhost), 0xff & (int)(v->vh_shost),
101425190Skarels 		0xff & (int)(v->vh_version), 0xff & (int)(v->vh_type),
101525190Skarels 		0xffff & (int)(v->vh_info));
101625190Skarels }
101726903Sjas #endif NVV
1018