xref: /csrg-svn/sys/vax/if/if_vv.c (revision 38986)
123305Smckusick /*
236085Skarels  * Copyright (c) 1982, 1986, 1988 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*38986Skarels  *	@(#)if_vv.c	7.5 (Berkeley) 09/04/89
1823305Smckusick  */
197024Ssam 
209799Ssam #include "vv.h"
2125275Sbloom #if NVV > 0
2211192Ssam 
237024Ssam /*
2435805Skarels  * 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
2735805Skarels  * to "v2", but this won't work right in config. Thus the name is "vv".
2811192Ssam  *
2935805Skarels  * 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  *
3435805Skarels  * This driver is also compatible with the Q-bus ProNET 10 megabit and
3535805Skarels  * 80 megabit token ring interfaces (models p1100 and p1180), but
3635805Skarels  * only on a MicroVAX-II or MicroVAX-III.  No attempt is made to
3735805Skarels  * support the MicroVAX-I.
3835805Skarels  *
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.
4635805Skarels  * If you need interoperability with anything else (like the p4200),
4735805Skarels  * 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  */
6017117Sbloom #include "param.h"
6117117Sbloom #include "systm.h"
6217117Sbloom #include "mbuf.h"
6317117Sbloom #include "buf.h"
64*38986Skarels #include "time.h"
65*38986Skarels #include "kernel.h"
6617117Sbloom #include "protosw.h"
6717117Sbloom #include "socket.h"
68*38986Skarels #include "syslog.h"
6917117Sbloom #include "vmmac.h"
7017117Sbloom #include "errno.h"
7117117Sbloom #include "ioctl.h"
728465Sroot 
738465Sroot #include "../net/if.h"
7411209Ssam #include "../net/netisr.h"
758465Sroot #include "../net/route.h"
7624793Skarels 
7724793Skarels #ifdef	INET
788421Swnj #include "../netinet/in.h"
798421Swnj #include "../netinet/in_systm.h"
8021779Skarels #include "../netinet/in_var.h"
818421Swnj #include "../netinet/ip.h"
8224793Skarels #endif
838465Sroot 
84*38986Skarels #include "../vax/pte.h"
8515794Sleres #include "../vax/cpu.h"
8611209Ssam #include "../vax/mtpr.h"
8717117Sbloom #include "if_vv.h"
8817117Sbloom #include "if_uba.h"
898465Sroot #include "../vaxuba/ubareg.h"
908465Sroot #include "../vaxuba/ubavar.h"
917024Ssam 
927024Ssam /*
9320997Skarels  *    maximum transmission unit definition --
9435805Skarels  *        you can set VVMTU at anything from 576 to 2036.
9520997Skarels  *        1536 is a popular "large" value, because it is a multiple
9620997Skarels  *	  of 512, which the trailer scheme likes.
9735805Skarels  *        The absolute maximum size is 2036, which is enforced.
9820997Skarels  */
9920997Skarels 
10035805Skarels #define VVMTU (2036)
10120997Skarels 
10235805Skarels #define VVMRU (VVMTU + (2 * sizeof(u_short)))
10320997Skarels #define VVBUFSIZE (VVMRU + sizeof(struct vv_header))
10435805Skarels #if VVMTU>2036
10520997Skarels #undef VVMTU
10620997Skarels #undef VVMRU
10720997Skarels #undef VVBUFSIZE
10820997Skarels #define VVBUFSIZE (2046)
10920997Skarels #define VVMRU (VVBUFSIZE - sizeof (struct vv_header))
11035805Skarels #define VVMTU (VVMRU - (2 * sizeof(u_short)))
1117024Ssam #endif
1127024Ssam 
11320997Skarels /*
11420997Skarels  *   debugging and tracing stuff
11520997Skarels  */
11616581Skarels int	vv_tracehdr = 0;	/* 1 => trace headers (slowly!!) */
1177640Ssam 
11820997Skarels #define vvtracehdr  if (vv_tracehdr) vvprt_hdr
119*38986Skarels #define vvlog    if (vs->vs_if.if_flags & IFF_DEBUG) log
12011192Ssam 
12120997Skarels /*
12220997Skarels  * externals, types, etc.
12320997Skarels  */
12416581Skarels int	vvprobe(), vvattach(), vvreset(), vvinit();
12516581Skarels int	vvidentify(), vvstart(), vvxint(), vvwatchdog();
12626394Skarels int	vvrint(), vvoutput(), vvioctl();
1277024Ssam struct	uba_device *vvinfo[NVV];
1287024Ssam u_short vvstd[] = { 0 };
1297024Ssam struct	uba_driver vvdriver =
1307024Ssam 	{ vvprobe, 0, vvattach, 0, vvstd, "vv", vvinfo };
1317024Ssam #define	VVUNIT(x)	minor(x)
1327024Ssam 
13320997Skarels #define LOOPBACK		/* use loopback for packets meant for us */
13420997Skarels #ifdef	LOOPBACK
13520997Skarels extern struct ifnet loif;
13620997Skarels #endif
13720997Skarels 
138*38986Skarels extern wakeup();
139*38986Skarels 
1407024Ssam /*
1417024Ssam  * Software status of each interface.
1427024Ssam  *
1437024Ssam  * Each interface is referenced by a network interface structure,
1447024Ssam  * vs_if, which the routing code uses to locate the interface.
1457024Ssam  * This structure contains the output queue for the interface, its address, ...
1467024Ssam  * We also have, for each interface, a UBA interface structure, which
1477024Ssam  * contains information about the UNIBUS resources held by the interface:
1487024Ssam  * map registers, buffered data paths, etc.  Information is cached in this
1497024Ssam  * structure for use by the if_uba.c routines in running the interface
1507024Ssam  * efficiently.
1517024Ssam  */
1527024Ssam struct	vv_softc {
1537024Ssam 	struct	ifnet vs_if;		/* network-visible interface */
1547024Ssam 	struct	ifuba vs_ifuba;		/* UNIBUS resources */
15526298Skarels 	u_short	vs_host;		/* this interface address */
15611192Ssam 	short	vs_oactive;		/* is output active */
15726903Sjas 	short	vs_is80;		/* is 80 megabit version */
1587024Ssam 	short	vs_olen;		/* length of last output */
15915794Sleres 	u_short	vs_lastx;		/* address of last packet sent */
16015794Sleres 	u_short	vs_lastr;		/* address of last packet received */
16111192Ssam 	short	vs_tries;		/* transmit current retry count */
1627024Ssam 	short	vs_init;		/* number of ring inits */
16320997Skarels 	short	vs_refused;		/* number of packets refused */
16415794Sleres 	short	vs_timeouts;		/* number of transmit timeouts */
16520997Skarels 	short	vs_otimeout;		/* number of output timeouts */
16620997Skarels 	short	vs_ibadf;		/* number of input bad formats */
16720997Skarels 	short	vs_parity;		/* number of parity errors on 10 meg, */
16820997Skarels 					/* link data errors on 80 meg */
16936085Skarels 	short	vs_ipl;			/* interrupt priority on Q-bus */
170*38986Skarels 	short	vs_flags;		/* board state: */
171*38986Skarels #define	VS_RUNNING	0x01		/* board has been initialized */
172*38986Skarels #define	VS_INIT		0x02		/* board being initialized */
1737024Ssam } vv_softc[NVV];
1747024Ssam 
175*38986Skarels #define	NOHOST	0xff			/* illegal host number */
17626311Skarels 
17720997Skarels /*
17820997Skarels  * probe the interface to see that the registers exist, and then
17920997Skarels  * cause an interrupt to find its vector
18020997Skarels  */
18136085Skarels vvprobe(reg, ui)
1827024Ssam 	caddr_t reg;
18336085Skarels 	struct uba_device *ui;
1847024Ssam {
1857024Ssam 	register int br, cvec;
18616581Skarels 	register struct vvreg *addr;
1877024Ssam 
1887024Ssam #ifdef lint
18915764Sleres 	br = 0; cvec = br; br = cvec;
1907024Ssam #endif
19116581Skarels 	addr = (struct vvreg *)reg;
19220997Skarels 
1937024Ssam 	/* reset interface, enable, and wait till dust settles */
19436085Skarels #ifdef QBA
19536085Skarels 	(void) spl6();
19636085Skarels #endif
1977024Ssam 	addr->vvicsr = VV_RST;
1987024Ssam 	addr->vvocsr = VV_RST;
19915764Sleres 	DELAY(100000);
20020997Skarels 
2017024Ssam 	/* generate interrupt by doing 1 word DMA from 0 in uba space!! */
2027024Ssam 	addr->vvoba = 0;		/* low 16 bits */
2037024Ssam 	addr->vvoea = 0;		/* extended bits */
2047024Ssam 	addr->vvowc = -1;		/* for 1 word */
20520997Skarels 	addr->vvocsr = VV_IEN | VV_DEN;	/* start the DMA, with interrupt */
2067024Ssam 	DELAY(100000);
20736085Skarels #ifdef QBA
20836085Skarels 	vv_softc[ui->ui_unit].vs_ipl = br = qbgetpri();
20936085Skarels #endif
21020997Skarels 	addr->vvocsr = VV_RST;		/* clear out the CSR */
2117024Ssam 	if (cvec && cvec != 0x200)
21215764Sleres 		cvec -= 4;		/* backup so vector => receive */
21336085Skarels 	return (sizeof(struct vvreg));
2147024Ssam }
2157024Ssam 
2167024Ssam /*
2177024Ssam  * Interface exists: make available by filling in network interface
2187024Ssam  * record.  System will initialize the interface when it is ready
2197024Ssam  * to accept packets.
2207024Ssam  */
2217024Ssam vvattach(ui)
2227024Ssam 	struct uba_device *ui;
2237024Ssam {
22415764Sleres 	register struct vv_softc *vs;
2257024Ssam 
22615764Sleres 	vs = &vv_softc[ui->ui_unit];
2277024Ssam 	vs->vs_if.if_unit = ui->ui_unit;
2287024Ssam 	vs->vs_if.if_name = "vv";
2297024Ssam 	vs->vs_if.if_mtu = VVMTU;
23021779Skarels 	vs->vs_if.if_flags = IFF_BROADCAST;
2317024Ssam 	vs->vs_if.if_init = vvinit;
23213057Ssam 	vs->vs_if.if_ioctl = vvioctl;
2337024Ssam 	vs->vs_if.if_output = vvoutput;
23411209Ssam 	vs->vs_if.if_reset = vvreset;
23515794Sleres 	vs->vs_if.if_timer = 0;
23615794Sleres 	vs->vs_if.if_watchdog = vvwatchdog;
23726201Skarels 	vs->vs_ifuba.ifu_flags = UBA_CANTWAIT | UBA_NEEDBDP;
23826903Sjas 
23926903Sjas 	/* use flag to determine if this is proNET-80 */
24026903Sjas 	vs->vs_is80 = (short)(ui->ui_flags & 01);
241*38986Skarels 	vs->vs_host = NOHOST;
24226903Sjas 
24312354Smo #if defined(VAX750)
24412354Smo 	/* don't chew up 750 bdp's */
24512354Smo 	if (cpu == VAX_750 && ui->ui_unit > 0)
24612354Smo 		vs->vs_ifuba.ifu_flags &= ~UBA_NEEDBDP;
24712354Smo #endif
2487024Ssam 	if_attach(&vs->vs_if);
2497024Ssam }
2507024Ssam 
2517024Ssam /*
2527024Ssam  * Reset of interface after UNIBUS reset.
2537024Ssam  * If interface is on specified uba, reset its state.
2547024Ssam  */
2557024Ssam vvreset(unit, uban)
2567024Ssam 	int unit, uban;
2577024Ssam {
2587024Ssam 	register struct uba_device *ui;
2597024Ssam 
2607024Ssam 	if (unit >= NVV || (ui = vvinfo[unit]) == 0 || ui->ui_alive == 0 ||
2617024Ssam 	    ui->ui_ubanum != uban)
2627024Ssam 		return;
2637024Ssam 	printf(" vv%d", unit);
264*38986Skarels 	vv_softc[unit].vs_if.if_flags &= ~IFF_RUNNING;
265*38986Skarels 	vv_softc[unit].vs_flags &= ~VS_RUNNING;
266*38986Skarels 	vvinit(unit, 0);
2677024Ssam }
2687024Ssam 
2697024Ssam /*
2707024Ssam  * Initialization of interface; clear recorded pending
2717024Ssam  * operations, and reinitialize UNIBUS usage.
2727024Ssam  */
273*38986Skarels vvinit(unit, cansleep)
274*38986Skarels 	int unit, cansleep;
2757024Ssam {
27615764Sleres 	register struct vv_softc *vs;
27715764Sleres 	register struct uba_device *ui;
2787024Ssam 	register struct vvreg *addr;
27935805Skarels 	register int ubaaddr, s;
2807024Ssam 
28115764Sleres 	vs = &vv_softc[unit];
28215764Sleres 	ui = vvinfo[unit];
28320997Skarels 
28421779Skarels 	if (vs->vs_if.if_addrlist == (struct ifaddr *)0)
28513057Ssam 		return;
28620997Skarels 
287*38986Skarels 	/*
288*38986Skarels 	 * Prevent multiple instances of vvinit
289*38986Skarels 	 * from trying simultaneously.
290*38986Skarels 	 */
291*38986Skarels 	while (vs->vs_flags & VS_INIT) {
292*38986Skarels 		if (cansleep)
293*38986Skarels 			sleep((caddr_t)vs);
294*38986Skarels 		else
295*38986Skarels 			return;
296*38986Skarels 	}
297*38986Skarels 	if (vs->vs_flags & VS_RUNNING)
298*38986Skarels 		return;
299*38986Skarels 	vs->vs_flags = VS_INIT;
300*38986Skarels 
3017640Ssam 	addr = (struct vvreg *)ui->ui_addr;
30236085Skarels 	if ((vs->vs_if.if_flags & IFF_RUNNING) == 0 &&
30336085Skarels 	    if_ubainit(&vs->vs_ifuba, ui->ui_ubanum,
30436085Skarels 	      sizeof (struct vv_header), (int)btoc(VVMRU)) == 0) {
30515794Sleres 		printf("vv%d: can't initialize, if_ubainit() failed\n", unit);
3067640Ssam 		vs->vs_if.if_flags &= ~IFF_UP;
307*38986Skarels 		vs->vs_flags = 0;
3087024Ssam 		return;
3097024Ssam 	}
31036085Skarels 	vs->vs_if.if_flags |= IFF_RUNNING;
31120997Skarels 
3127024Ssam 	/*
31315764Sleres 	 * Now that the uba is set up, figure out our address and
31415764Sleres 	 * update complete our host address.
3157640Ssam 	 */
316*38986Skarels 	if (cansleep)
317*38986Skarels 		vs->vs_host = vvidentify(unit);
318*38986Skarels 	if (vs->vs_host == NOHOST) {
31915794Sleres 		vs->vs_if.if_flags &= ~IFF_UP;
320*38986Skarels 		vs->vs_flags = 0;
32115794Sleres 		return;
32215794Sleres 	}
323*38986Skarels 	vvlog(LOG_DEBUG, "vv%d: host %u\n", unit, vs->vs_host);
32420997Skarels 
3257640Ssam 	/*
32620997Skarels 	 * Reset the interface, and stay in the ring
3277640Ssam 	 */
32820997Skarels 	addr->vvocsr = VV_RST;			/* take over output */
32920997Skarels 	addr->vvocsr = VV_CPB;			/* clear packet buffer */
33020997Skarels 	addr->vvicsr = VV_RST | VV_HEN;		/* take over input, */
33120997Skarels 						/* keep relay closed */
332*38986Skarels 	if (cansleep) {
333*38986Skarels 		timeout(wakeup, (caddr_t)vs, hz/2);
334*38986Skarels 		sleep((caddr_t)vs, PZERO);	/* let contacts settle */
335*38986Skarels 	} else
336*38986Skarels 		DELAY(500000);			/* let contacts settle */
33720997Skarels 
33820997Skarels 	vs->vs_init = 0;			/* clear counters, etc. */
33920997Skarels 	vs->vs_refused = 0;
34015794Sleres 	vs->vs_timeouts = 0;
34120997Skarels 	vs->vs_otimeout = 0;
34220997Skarels 	vs->vs_ibadf = 0;
34320997Skarels 	vs->vs_parity = 0;
34415794Sleres 	vs->vs_lastx = 256;			/* an invalid address */
34515794Sleres 	vs->vs_lastr = 256;			/* an invalid address */
34620997Skarels 
3477640Ssam 	/*
3487640Ssam 	 * Hang a receive and start any
3497640Ssam 	 * pending writes by faking a transmit complete.
3507640Ssam 	 */
3517640Ssam 	s = splimp();
35235805Skarels 	ubaaddr = UBAI_ADDR(vs->vs_ifuba.ifu_r.ifrw_info);
35335805Skarels 	addr->vviba = (u_short)ubaaddr;
35435805Skarels 	addr->vviea = (u_short)(ubaaddr >> 16);
35520997Skarels 	addr->vviwc = -(VVBUFSIZE) >> 1;
35620997Skarels 	addr->vvicsr = VV_IEN | VV_HEN | VV_DEN | VV_ENB;
3577640Ssam 	vs->vs_oactive = 1;
35836085Skarels 	vs->vs_if.if_flags |= IFF_UP;
359*38986Skarels 	vs->vs_flags = VS_RUNNING;		/* clear VS_INIT */
360*38986Skarels 	wakeup((caddr_t)vs);
3617640Ssam 	vvxint(unit);
3627640Ssam 	splx(s);
3637640Ssam }
3647640Ssam 
3657640Ssam /*
36620997Skarels  * Do a moderately thorough self-test in all three modes. Mostly
36720997Skarels  * to keeps defective nodes off the ring, rather than to be especially
36820997Skarels  * thorough. The key issue is to detect any cable breaks before joining
36920997Skarels  * the ring. Return our node address on success, return -1 on failure.
37020997Skarels  *
3717640Ssam  */
37220997Skarels 
37320997Skarels /* the three self-test modes */
37420997Skarels static u_short vv_modes[] = {
37520997Skarels 	VV_STE|VV_LPB,			/* digital loopback */
37620997Skarels 	VV_STE,				/* analog loopback */
37720997Skarels 	VV_HEN				/* network mode */
37820997Skarels };
37920997Skarels 
38011209Ssam vvidentify(unit)
38113057Ssam 	int unit;
38211209Ssam {
38315764Sleres 	register struct vv_softc *vs;
38415764Sleres 	register struct uba_device *ui;
3857640Ssam 	register struct vvreg *addr;
38616581Skarels 	register struct mbuf *m;
38716581Skarels 	register struct vv_header *v;
38835805Skarels 	register int ubaaddr;
38920997Skarels 	register int i, successes, failures, waitcount;
39026311Skarels 	u_short shost = NOHOST;
3917640Ssam 
39220997Skarels 	vs = &vv_softc[unit];
39320997Skarels 	ui = vvinfo[unit];
39420997Skarels 	addr = (struct vvreg *)ui->ui_addr;
39520997Skarels 
3967640Ssam 	/*
3977024Ssam 	 * Build a multicast message to identify our address
39820997Skarels 	 * We need do this only once, since nobody else is about to use
39920997Skarels 	 * the intermediate transmit buffer (ifu_w.ifrw_addr) that
40020997Skarels 	 * if_ubainit() aquired for us.
4017024Ssam 	 */
40211209Ssam 	m = m_get(M_DONTWAIT, MT_HEADER);
40315794Sleres 	if (m == NULL) {
40415794Sleres 		printf("vv%d: can't initialize, m_get() failed\n", unit);
405*38986Skarels 		return (NOHOST);
40615794Sleres 	}
40711192Ssam 	m->m_next = 0;
4087024Ssam 	m->m_off = MMINOFF;
4097024Ssam 	m->m_len = sizeof(struct vv_header);
4107024Ssam 	v = mtod(m, struct vv_header *);
41111192Ssam 	v->vh_dhost = VV_BROADCAST;	/* multicast destination address */
4127024Ssam 	v->vh_shost = 0;		/* will be overwritten with ours */
4137024Ssam 	v->vh_version = RING_VERSION;
41420997Skarels 	v->vh_type = RING_DIAGNOSTICS;
4157024Ssam 	v->vh_info = 0;
41620997Skarels 	/* map xmit message into uba, copying to intermediate buffer */
41720997Skarels 	vs->vs_olen = if_wubaput(&vs->vs_ifuba, m);
41820997Skarels 
4197024Ssam 	/*
42020997Skarels 	 * For each of the modes (digital, analog, network), go through
42120997Skarels 	 * a self-test that requires me to send VVIDENTSUCC good packets
42220997Skarels 	 * in VVIDENTRETRY attempts. Use broadcast destination to find out
42320997Skarels 	 * who I am, then use this as my address to check my address match
42420997Skarels 	 * logic. Only data checked is the vh_type field.
4257024Ssam 	 */
4267640Ssam 
42720997Skarels 	for (i = 0; i < 3; i++) {
42820997Skarels 		successes = 0;	/* clear successes for this mode */
42920997Skarels 		failures = 0;	/* and clear failures, too */
4307640Ssam 
43120997Skarels 		/* take over device, and leave ring */
43220997Skarels 		addr->vvicsr = VV_RST;
43320997Skarels 		addr->vvocsr = VV_RST;
43420997Skarels 		addr->vvicsr = vv_modes[i];	/* test mode */
43520997Skarels 
43620997Skarels 		/*
43720997Skarels 		 * let the flag and token timers pop so that the init ring bit
43820997Skarels 		 * will be allowed to work, by waiting about 1 second
43920997Skarels 		 */
440*38986Skarels 		timeout(wakeup, (caddr_t)vs, hz);
441*38986Skarels 		sleep((caddr_t)vs, PZERO);
44220997Skarels 
44320997Skarels 		/*
44420997Skarels 		 * retry loop
44520997Skarels  		 */
44620997Skarels 		while ((successes < VVIDENTSUCC) && (failures < VVIDENTRETRY))
44720997Skarels 		{
44820997Skarels 			/* start a receive */
44935805Skarels 			ubaaddr = UBAI_ADDR(vs->vs_ifuba.ifu_r.ifrw_info);
45020997Skarels 			addr->vvicsr = VV_RST | vv_modes[i]; /* abort last */
45135805Skarels 			addr->vviba = (u_short) ubaaddr;
45235805Skarels 			addr->vviea = (u_short) (ubaaddr >> 16);
45320997Skarels 			addr->vviwc = -(VVBUFSIZE) >> 1;
45420997Skarels 			addr->vvicsr = vv_modes[i] | VV_DEN | VV_ENB;
45520997Skarels 
456*38986Skarels #ifdef notdef
45720997Skarels 			/* purge stale data from BDP */
45820997Skarels 			if (vs->vs_ifuba.ifu_flags & UBA_NEEDBDP)
45920997Skarels 				UBAPURGE(vs->vs_ifuba.ifu_uba,
46020997Skarels 				    vs->vs_ifuba.ifu_w.ifrw_bdp);
461*38986Skarels #endif
46220997Skarels 
46320997Skarels 			/* do a transmit */
46435805Skarels 			ubaaddr = UBAI_ADDR(vs->vs_ifuba.ifu_w.ifrw_info);
46520997Skarels 			addr->vvocsr = VV_RST;	/* abort last try */
46635805Skarels 			addr->vvoba = (u_short) ubaaddr;
46735805Skarels 			addr->vvoea = (u_short) (ubaaddr >> 16);
46820997Skarels 			addr->vvowc = -((vs->vs_olen + 1) >> 1);
46920997Skarels 			addr->vvocsr = VV_CPB | VV_DEN | VV_INR | VV_ENB;
47020997Skarels 
47120997Skarels 			/* poll receive side for completion */
47220997Skarels 			DELAY(10000);		/* give it a chance */
47320997Skarels 			for (waitcount = 0; waitcount < 10; waitcount++) {
47420997Skarels 				if (addr->vvicsr & VV_RDY)
47520997Skarels 					goto gotit;
47620997Skarels 				DELAY(1000);
47720997Skarels 			}
47820997Skarels 			failures++;		/* no luck */
47911209Ssam 			continue;
48020997Skarels 
48120997Skarels gotit:			/* we got something--is it any good? */
48220997Skarels 			if ((addr->vvicsr & (VVRERR|VV_LDE)) ||
48321779Skarels 			    (addr->vvocsr & (VVXERR|VV_RFS))) {
48420997Skarels 				failures++;
48520997Skarels 				continue;
48620997Skarels 			}
48720997Skarels 
48820997Skarels 			/* Purge BDP before looking at received packet */
48920997Skarels 			if (vs->vs_ifuba.ifu_flags & UBA_NEEDBDP)
49020997Skarels 				UBAPURGE(vs->vs_ifuba.ifu_uba,
49120997Skarels 				    vs->vs_ifuba.ifu_r.ifrw_bdp);
492*38986Skarels #ifdef notdef
49324793Skarels 			m = if_rubaget(&vs->vs_ifuba, sizeof(struct vv_header),
49426394Skarels 				0, &vs->vs_if);
49520997Skarels 			if (m != NULL)
49620997Skarels 				m_freem(m);
497*38986Skarels #endif
49820997Skarels 
49920997Skarels 			v = (struct vv_header *)(vs->vs_ifuba.ifu_r.ifrw_addr);
50020997Skarels 
50120997Skarels 			/* check message type, catch our node address */
50220997Skarels 			if ((v->vh_type & 0xff) == RING_DIAGNOSTICS) {
50326311Skarels 				if (shost == NOHOST) {
50420997Skarels 					shost = v->vh_shost & 0xff;
50520997Skarels 					/* send to ourself now */
50620997Skarels 					((struct vv_header *)
50720997Skarels 					    (vs->vs_ifuba.ifu_r.ifrw_addr))
50820997Skarels 					    ->vh_dhost = shost;
50920997Skarels 				}
51020997Skarels 				successes++;
51126903Sjas 			} else {
51226903Sjas 				failures++;
51320997Skarels 			}
51426903Sjas 			v->vh_type = 0;  /* clear to check again */
51511192Ssam 		}
51620997Skarels 
51720997Skarels 		if (failures >= VVIDENTRETRY)
51820997Skarels 		{
51920997Skarels 			printf("vv%d: failed self-test after %d tries \
52020997Skarels in %s mode\n",
52120997Skarels 			    unit, VVIDENTRETRY, i == 0 ? "digital loopback" :
52220997Skarels 			    (i == 1 ? "analog loopback" : "network"));
52320997Skarels 			printf("vv%d: icsr = %b, ocsr = %b\n",
52420997Skarels 			    unit, 0xffff & addr->vvicsr, VV_IBITS,
52520997Skarels 			    0xffff & addr->vvocsr, VV_OBITS);
52620997Skarels 			addr->vvicsr = VV_RST;	/* kill the sick board */
52720997Skarels 			addr->vvocsr = VV_RST;
52826311Skarels 			shost = NOHOST;
52920997Skarels 			goto done;
53020997Skarels 		}
53111192Ssam 	}
53220997Skarels 
53320997Skarels done:
53420997Skarels 	/* deallocate mbuf used for send packet (won't be one, anyways) */
53515794Sleres 	if (vs->vs_ifuba.ifu_xtofree) {
5367024Ssam 		m_freem(vs->vs_ifuba.ifu_xtofree);
53715794Sleres 		vs->vs_ifuba.ifu_xtofree = 0;
53815794Sleres 	}
53920997Skarels 
54020997Skarels 	return(shost);
5417024Ssam }
5427024Ssam 
5437024Ssam /*
5447024Ssam  * Start or restart output on interface.
54511192Ssam  * If interface is active, this is a retransmit, so just
54611192Ssam  * restuff registers and go.
5477024Ssam  * If interface is not already active, get another datagram
5487024Ssam  * to send off of the interface queue, and map it to the interface
5497024Ssam  * before starting the output.
5507024Ssam  */
5517024Ssam vvstart(dev)
5527024Ssam 	dev_t dev;
5537024Ssam {
55416581Skarels 	register struct uba_device *ui;
55515764Sleres 	register struct vv_softc *vs;
5567024Ssam 	register struct vvreg *addr;
55716581Skarels 	register struct mbuf *m;
55835805Skarels 	register int unit, ubaaddr, dest, s;
5597024Ssam 
56016581Skarels 	unit = VVUNIT(dev);
56115764Sleres 	ui = vvinfo[unit];
56215764Sleres 	vs = &vv_softc[unit];
5637024Ssam 	if (vs->vs_oactive)
5647024Ssam 		goto restart;
5657024Ssam 	/*
5667024Ssam 	 * Not already active: dequeue another request
5677024Ssam 	 * and map it to the UNIBUS.  If no more requests,
5687024Ssam 	 * just return.
5697024Ssam 	 */
57015794Sleres 	s = splimp();
5717024Ssam 	IF_DEQUEUE(&vs->vs_if.if_snd, m);
57215794Sleres 	splx(s);
57311209Ssam 	if (m == NULL) {
5747024Ssam 		vs->vs_oactive = 0;
5757024Ssam 		return;
5767024Ssam 	}
5777024Ssam 	dest = mtod(m, struct vv_header *)->vh_dhost;
5787024Ssam 	vs->vs_olen = if_wubaput(&vs->vs_ifuba, m);
5797024Ssam 	vs->vs_lastx = dest;
5807024Ssam restart:
5817024Ssam 	/*
5827024Ssam 	 * Have request mapped to UNIBUS for transmission.
58315794Sleres 	 * Purge any stale data from this BDP, and start the output.
58415794Sleres 	 *
58515794Sleres 	 * Make sure this packet will fit in the interface.
5867024Ssam 	 */
58720997Skarels 	if (vs->vs_olen > VVBUFSIZE) {
58820997Skarels 		printf("vv%d vs_olen: %d > VVBUFSIZE\n", unit, vs->vs_olen);
58911192Ssam 		panic("vvdriver vs_olen botch");
59011192Ssam 	}
59120997Skarels 
59220997Skarels 	vs->vs_if.if_timer = VVTIMEOUT;
59320997Skarels 	vs->vs_oactive = 1;
59420997Skarels 
59520997Skarels 	/* ship it */
59636085Skarels #ifdef notdef
5977024Ssam 	if (vs->vs_ifuba.ifu_flags & UBA_NEEDBDP)
5987024Ssam 		UBAPURGE(vs->vs_ifuba.ifu_uba, vs->vs_ifuba.ifu_w.ifrw_bdp);
59936085Skarels #endif
6007024Ssam 	addr = (struct vvreg *)ui->ui_addr;
60135805Skarels 	ubaaddr = UBAI_ADDR(vs->vs_ifuba.ifu_w.ifrw_info);
60235805Skarels 	addr->vvoba = (u_short) ubaaddr;
60335805Skarels 	addr->vvoea = (u_short) (ubaaddr >> 16);
6047024Ssam 	addr->vvowc = -((vs->vs_olen + 1) >> 1);
60520997Skarels 	addr->vvowc = -((vs->vs_olen + 1) >> 1); /* extra byte is garbage */
60620997Skarels 	if (addr->vvocsr & VV_NOK)
60720997Skarels 		vs->vs_init++;			/* count ring inits */
6087024Ssam 	addr->vvocsr = VV_IEN | VV_CPB | VV_DEN | VV_INR | VV_ENB;
6097024Ssam }
6107024Ssam 
6117024Ssam /*
61220997Skarels  * proNET transmit interrupt
6137024Ssam  * Start another output if more data to send.
6147024Ssam  */
6157024Ssam vvxint(unit)
6167024Ssam 	int unit;
6177024Ssam {
61815764Sleres 	register struct uba_device *ui;
61915764Sleres 	register struct vv_softc *vs;
6207024Ssam 	register struct vvreg *addr;
6217024Ssam 	register int oc;
6227024Ssam 
623*38986Skarels 	ui = vvinfo[unit];
624*38986Skarels 	vs = &vv_softc[unit];
62536085Skarels #ifdef QBA
626*38986Skarels 	splx(vs->vs_ipl);
62736085Skarels #endif
62815794Sleres 	vs->vs_if.if_timer = 0;
6297024Ssam 	addr = (struct vvreg *)ui->ui_addr;
6307024Ssam 	oc = 0xffff & (addr->vvocsr);
6317024Ssam 	if (vs->vs_oactive == 0) {
632*38986Skarels 		vvlog(LOG_DEBUG, "vv%d: stray interrupt vvocsr = %b\n", unit,
63315764Sleres 		    oc, VV_OBITS);
6347024Ssam 		return;
6357024Ssam 	}
63620997Skarels 
63720997Skarels 	/*
63820997Skarels 	 * we retransmit on soft error
63920997Skarels 	 * TODO: sort retransmits to end of queue if possible!
64020997Skarels 	 */
64120997Skarels 	if (oc & (VV_OPT | VV_RFS)) {
64211192Ssam 		if (vs->vs_tries++ < VVRETRY) {
6437024Ssam 			if (oc & VV_OPT)
64420997Skarels 				vs->vs_otimeout++;
64520997Skarels 			if (oc & VV_RFS) {
64620997Skarels 				vs->vs_if.if_collisions++;
64720997Skarels 				vs->vs_refused++;
64820997Skarels 			}
64911192Ssam 			vvstart(unit);		/* restart this message */
6507024Ssam 			return;
6517024Ssam 		}
6527024Ssam 	}
6537024Ssam 	vs->vs_if.if_opackets++;
6547024Ssam 	vs->vs_oactive = 0;
6557024Ssam 	vs->vs_tries = 0;
65620997Skarels 
6577024Ssam 	if (oc & VVXERR) {
6587024Ssam 		vs->vs_if.if_oerrors++;
659*38986Skarels 		vvlog(LOG_ERR, "vv%d: error vvocsr = %b\n",
660*38986Skarels 		    unit, 0xffff & oc, VV_OBITS);
6617024Ssam 	}
6627024Ssam 	if (vs->vs_ifuba.ifu_xtofree) {
6637024Ssam 		m_freem(vs->vs_ifuba.ifu_xtofree);
6647024Ssam 		vs->vs_ifuba.ifu_xtofree = 0;
6657024Ssam 	}
6667024Ssam 	vvstart(unit);
6677024Ssam }
6687024Ssam 
6697024Ssam /*
67015794Sleres  * Transmit watchdog timer routine.
67115794Sleres  * This routine gets called when we lose a transmit interrupt.
67215794Sleres  * The best we can do is try to restart output.
67315794Sleres  */
67415794Sleres vvwatchdog(unit)
67515794Sleres 	int unit;
67615794Sleres {
67715794Sleres 	register struct vv_softc *vs;
67815794Sleres 
67915794Sleres 	vs = &vv_softc[unit];
680*38986Skarels 	log(LOG_ERR, "vv%d: lost transmit interrupt\n", unit);
68115794Sleres 	vs->vs_timeouts++;
68215794Sleres 	vvstart(unit);
68315794Sleres }
68415794Sleres 
68515794Sleres /*
68620997Skarels  * proNET interface receiver interrupt.
6877024Ssam  * If input error just drop packet.
68815764Sleres  * Otherwise purge input buffered data path and examine
6897024Ssam  * packet to determine type.  If can't determine length
69015764Sleres  * from type, then have to drop packet.  Otherwise decapsulate
6917024Ssam  * packet based on type and pass to type specific higher-level
6927024Ssam  * input routine.
6937024Ssam  */
6947024Ssam vvrint(unit)
6957024Ssam 	int unit;
6967024Ssam {
69715764Sleres 	register struct vv_softc *vs;
69816581Skarels 	register struct vvreg *addr;
6997024Ssam 	register struct vv_header *vv;
7007024Ssam 	register struct ifqueue *inq;
70116581Skarels 	register struct mbuf *m;
70235805Skarels 	int ubaaddr, len, off, s;
7037640Ssam 	short resid;
7047024Ssam 
705*38986Skarels 	vs = &vv_softc[unit];
70636085Skarels #ifdef QBA
707*38986Skarels 	splx(vs->vs_ipl);
70836085Skarels #endif
70916581Skarels 	vs->vs_if.if_ipackets++;
71015764Sleres 	addr = (struct vvreg *)vvinfo[unit]->ui_addr;
71120997Skarels 
7127024Ssam 	/*
71326903Sjas 	 * Purge BDP
7147024Ssam 	 */
7157024Ssam 	if (vs->vs_ifuba.ifu_flags & UBA_NEEDBDP)
7167024Ssam 		UBAPURGE(vs->vs_ifuba.ifu_uba, vs->vs_ifuba.ifu_r.ifrw_bdp);
71720997Skarels 
71820997Skarels 	/*
71920997Skarels 	 * receive errors?
72020997Skarels 	 */
7217024Ssam 	if (addr->vvicsr & VVRERR) {
722*38986Skarels 		vvlog(LOG_INFO, "vv%d: receive error, vvicsr = %b\n", unit,
72320997Skarels 		    0xffff&(addr->vvicsr), VV_IBITS);
72420997Skarels 		if (addr->vvicsr & VV_BDF)
72520997Skarels 			vs->vs_ibadf++;
7267640Ssam 		goto dropit;
7277024Ssam 	}
7287640Ssam 
7297024Ssam 	/*
73020997Skarels 	 * parity errors?
73120997Skarels 	 */
73220997Skarels 	if (addr->vvicsr & VV_LDE) {
73320997Skarels 		/* we don't have to clear it because the receive command */
73420997Skarels 		/* writes 0 to parity bit */
73520997Skarels 		vs->vs_parity++;
73626903Sjas 
73720997Skarels 		/*
73820997Skarels 		 * only on 10 megabit proNET is VV_LDE an end-to-end parity
73920997Skarels 		 * bit. On 80 megabit, it returns to the intended use of
74020997Skarels 		 * node-to-node parity. End-to-end parity errors on 80 megabit
74120997Skarels 		 * give VV_BDF.
74220997Skarels 		 */
74326903Sjas 		if (vs->vs_is80 == 0)
74426903Sjas 		    goto dropit;
74520997Skarels 	}
74620997Skarels 
74720997Skarels 	/*
74820997Skarels 	 * Get packet length from residual word count
7497640Ssam 	 *
7507640Ssam 	 * Compute header offset if trailer protocol
7517640Ssam 	 *
7527640Ssam 	 * Pull packet off interface.  Off is nonzero if packet
7537640Ssam 	 * has trailing header; if_rubaget will then force this header
7547640Ssam 	 * information to be at the front.  The vh_info field
7557640Ssam 	 * carries the offset to the trailer data in trailer
7567640Ssam 	 * format packets.
7577024Ssam 	 */
7587640Ssam 	vv = (struct vv_header *)(vs->vs_ifuba.ifu_r.ifrw_addr);
75911192Ssam 	vvtracehdr("vi", vv);
76020997Skarels 	resid = addr->vviwc & 01777;	/* only low 10 bits valid */
7617640Ssam 	if (resid)
76220997Skarels 		resid |= 0176000;	/* high 6 bits are undefined */
76320997Skarels 	len = ((VVBUFSIZE >> 1) + resid) << 1;
7647640Ssam 	len -= sizeof(struct vv_header);
76520997Skarels 
76620997Skarels 	if ((addr->vvicsr & VV_DPR) || len > VVMRU || len <= 0) {
767*38986Skarels 		vvlog(LOG_DEBUG, "vv%d: len too long or short, \
76820997Skarels len = %d, vvicsr = %b\n",
76915794Sleres 			    unit, len, 0xffff&(addr->vvicsr), VV_IBITS);
7707640Ssam 		goto dropit;
77115794Sleres 	}
77220997Skarels 
77320997Skarels 	/* check the protocol header version */
77420997Skarels 	if (vv->vh_version != RING_VERSION) {
775*38986Skarels 		vvlog(LOG_DEBUG, "vv%d: bad protocol header version %d\n",
77620997Skarels 		    unit, vv->vh_version & 0xff);
77720997Skarels 		goto dropit;
77820997Skarels 	}
77920997Skarels 
7807640Ssam #define	vvdataaddr(vv, off, type)	((type)(((caddr_t)((vv)+1)+(off))))
78126950Sjas 	if (vv->vh_type == RING_TRAILER ) {
78228954Skarels 		off = ntohs((u_short)vv->vh_info);
78315794Sleres 		if (off > VVMTU) {
784*38986Skarels 			vvlog(LOG_DEBUG,
785*38986Skarels 			    "vv%d: off > VVMTU, off = %d, vvicsr = %b\n",
786*38986Skarels 			    unit, off, 0xffff&(addr->vvicsr), VV_IBITS);
7877640Ssam 			goto dropit;
78815794Sleres 		}
78926903Sjas 		vv->vh_type = ntohs(*vvdataaddr(vv, off, u_short *));
79026950Sjas 		resid = ntohs(*(vvdataaddr(vv, off+sizeof(u_short), u_short *)));
79115794Sleres 		if (off + resid > len) {
792*38986Skarels 			vvlog(LOG_DEBUG, "vv%d: trailer packet too short\n",
793*38986Skarels 			    unit);
794*38986Skarels 			vvlog(LOG_DEBUG,
795*38986Skarels 			    "vv%d: off = %d, resid = %d, vvicsr = %b\n",
796*38986Skarels 			    unit, off, resid, 0xffff&(addr->vvicsr), VV_IBITS);
7977640Ssam 			goto dropit;
79815794Sleres 		}
7997640Ssam 		len = off + resid;
80011209Ssam 	} else
8017640Ssam 		off = 0;
80220997Skarels 
80315794Sleres 	if (len == 0) {
804*38986Skarels 		vvlog(LOG_DEBUG, "vv%d: len is zero, vvicsr = %b\n", unit,
80515794Sleres 			    0xffff&(addr->vvicsr), VV_IBITS);
8067640Ssam 		goto dropit;
80715794Sleres 	}
80820997Skarels 
80924793Skarels 	m = if_rubaget(&vs->vs_ifuba, len, off, &vs->vs_if);
81015794Sleres 	if (m == NULL) {
811*38986Skarels 		vvlog(LOG_DEBUG, "vv%d: if_rubaget() failed, vvicsr = %b\n",
812*38986Skarels 		    unit, 0xffff&(addr->vvicsr), VV_IBITS);
8137640Ssam 		goto dropit;
81415794Sleres 	}
8157640Ssam 	if (off) {
81624793Skarels 		struct ifnet *ifp;
81724793Skarels 
81824793Skarels 		ifp = *(mtod(m, struct ifnet **));
81924793Skarels 		m->m_off += 2 * sizeof (u_short);
82024793Skarels 		m->m_len -= 2 * sizeof (u_short);
82124793Skarels 		*(mtod(m, struct ifnet **)) = ifp;
8227640Ssam 	}
82311192Ssam 
82415794Sleres 	/* Keep track of source address of this packet */
82515794Sleres 	vs->vs_lastr = vv->vh_shost;
82620997Skarels 
82711192Ssam 	/*
82815764Sleres 	 * Demultiplex on packet type
82911192Ssam 	 */
8307024Ssam 	switch (vv->vh_type) {
83111192Ssam 
8327024Ssam #ifdef INET
8337024Ssam 	case RING_IP:
8347024Ssam 		schednetisr(NETISR_IP);
8357024Ssam 		inq = &ipintrq;
8367024Ssam 		break;
8377024Ssam #endif
8387024Ssam 	default:
839*38986Skarels 		vvlog(LOG_DEBUG, "vv%d: unknown pkt type 0x%x\n",
840*38986Skarels 		    unit, vv->vh_type);
8417640Ssam 		m_freem(m);
8427024Ssam 		goto setup;
8437024Ssam 	}
84415794Sleres 	s = splimp();
8457640Ssam 	if (IF_QFULL(inq)) {
8467640Ssam 		IF_DROP(inq);
8477640Ssam 		m_freem(m);
84811209Ssam 	} else
8497640Ssam 		IF_ENQUEUE(inq, m);
85015764Sleres 
85115794Sleres 	splx(s);
8527024Ssam 	/*
85315764Sleres 	 * Reset for the next packet.
8547024Ssam 	 */
85515764Sleres setup:
85635805Skarels 	ubaaddr = UBAI_ADDR(vs->vs_ifuba.ifu_r.ifrw_info);
85735805Skarels 	addr->vviba = (u_short) ubaaddr;
85835805Skarels 	addr->vviea = (u_short) (ubaaddr >> 16);
85920997Skarels 	addr->vviwc = -(VVBUFSIZE) >> 1;
86020997Skarels 	addr->vvicsr = VV_HEN | VV_IEN | VV_DEN | VV_ENB;
86115764Sleres 	return;
86211192Ssam 
86311192Ssam 	/*
86411209Ssam 	 * Drop packet on floor -- count them!!
86511192Ssam 	 */
8667640Ssam dropit:
8677640Ssam 	vs->vs_if.if_ierrors++;
8687640Ssam 	goto setup;
8697024Ssam }
8707024Ssam 
8717024Ssam /*
87220997Skarels  * proNET output routine.
8737024Ssam  * Encapsulate a packet of type family for the local net.
8747024Ssam  * Use trailer local net encapsulation if enough data in first
8757024Ssam  * packet leaves a multiple of 512 bytes of data in remainder.
8767024Ssam  */
8777024Ssam vvoutput(ifp, m0, dst)
8787024Ssam 	struct ifnet *ifp;
8797024Ssam 	struct mbuf *m0;
8807024Ssam 	struct sockaddr *dst;
8817024Ssam {
88216581Skarels 	register struct mbuf *m;
8837024Ssam 	register struct vv_header *vv;
8847640Ssam 	register int off;
88516581Skarels 	register int unit;
88616581Skarels 	register struct vvreg *addr;
88716581Skarels 	register struct vv_softc *vs;
88816581Skarels 	register int s;
88916581Skarels 	int type, dest, error;
8907024Ssam 
89116581Skarels 	m = m0;
89216581Skarels 	unit = ifp->if_unit;
893*38986Skarels 	if ((ifp->if_flags & IFF_UP) == 0)
894*38986Skarels 		return (ENETDOWN);
89516581Skarels 	addr = (struct vvreg *)vvinfo[unit]->ui_addr;
89616581Skarels 	vs = &vv_softc[unit];
89720997Skarels 
89816581Skarels 	/*
89920997Skarels 	 * Check to see if the input side has wedged due the UBA
90020997Skarels 	 * vectoring through 0.
90116581Skarels 	 *
90216581Skarels 	 * We are lower than device ipl when we enter this routine,
90316581Skarels 	 * so if the interface is ready with an input packet then
90416581Skarels 	 * an input interrupt must have slipped through the cracks.
90516581Skarels 	 *
90616581Skarels 	 * Avoid the race with an input interrupt by watching to see
90716581Skarels 	 * if any packets come in.
90816581Skarels 	 */
90916581Skarels 	s = vs->vs_if.if_ipackets;
91016581Skarels 	if (addr->vvicsr & VV_RDY && s == vs->vs_if.if_ipackets) {
911*38986Skarels 		log(LOG_ERR, "vv%d: lost a receive interrupt, icsr = %b\n",
91216581Skarels 			    unit, 0xffff&(addr->vvicsr), VV_IBITS);
91316581Skarels 		s = splimp();
91416581Skarels 		vvrint(unit);
91516581Skarels 		splx(s);
91616581Skarels 	}
91716581Skarels 
9187024Ssam 	switch (dst->sa_family) {
91911192Ssam 
9207024Ssam #ifdef INET
92115764Sleres 	case AF_INET:
92221779Skarels 		if (in_broadcast(((struct sockaddr_in *)dst)->sin_addr))
92321779Skarels 			dest = VV_BROADCAST;
92421779Skarels 		else
92521779Skarels 			dest = in_lnaof(((struct sockaddr_in *)dst)->sin_addr);
92620997Skarels #ifdef LOOPBACK
92721779Skarels 		if (dest == vs->vs_host && (loif.if_flags & IFF_UP))
92821779Skarels 			return (looutput(&loif, m0, dst));
92920997Skarels #endif LOOPBACK
93021779Skarels 		if (dest >= 0x100) {
9317640Ssam 			error = EPERM;
9327640Ssam 			goto bad;
9337640Ssam 		}
9347640Ssam 		off = ntohs((u_short)mtod(m, struct ip *)->ip_len) - m->m_len;
93520997Skarels 		/*
93620997Skarels 		 * Trailerize, if the configuration allows it.
93720997Skarels 		 * TODO: Need per host negotiation.
93820997Skarels 		 */
93913090Ssam 		if ((ifp->if_flags & IFF_NOTRAILERS) == 0)
94013090Ssam 		if (off > 0 && (off & 0x1ff) == 0 &&
9417640Ssam 		    m->m_off >= MMINOFF + 2 * sizeof (u_short)) {
94226950Sjas 			type = RING_TRAILER;
9437640Ssam 			m->m_off -= 2 * sizeof (u_short);
9447640Ssam 			m->m_len += 2 * sizeof (u_short);
94528954Skarels 			*mtod(m, u_short *) = htons((short)RING_IP);
94628954Skarels 			*(mtod(m, u_short *) + 1) = htons((u_short)m->m_len);
9477640Ssam 			goto gottrailertype;
9487640Ssam 		}
9497024Ssam 		type = RING_IP;
9507024Ssam 		off = 0;
9517024Ssam 		goto gottype;
9527024Ssam #endif
9537024Ssam 	default:
95416581Skarels 		printf("vv%d: can't handle af%d\n", unit, dst->sa_family);
9557640Ssam 		error = EAFNOSUPPORT;
9567640Ssam 		goto bad;
9577024Ssam 	}
9587024Ssam 
9597024Ssam gottrailertype:
9607024Ssam 	/*
9617024Ssam 	 * Packet to be sent as trailer: move first packet
9627024Ssam 	 * (control information) to end of chain.
9637024Ssam 	 */
9647024Ssam 	while (m->m_next)
9657024Ssam 		m = m->m_next;
9667024Ssam 	m->m_next = m0;
9677024Ssam 	m = m0->m_next;
9687024Ssam 	m0->m_next = 0;
9697024Ssam 	m0 = m;
9707024Ssam gottype:
9717024Ssam 	/*
9727024Ssam 	 * Add local net header.  If no space in first mbuf,
9737024Ssam 	 * allocate another.
9747024Ssam 	 */
9757024Ssam 	if (m->m_off > MMAXOFF ||
9767024Ssam 	    MMINOFF + sizeof (struct vv_header) > m->m_off) {
97711209Ssam 		m = m_get(M_DONTWAIT, MT_HEADER);
97811209Ssam 		if (m == NULL) {
9797640Ssam 			error = ENOBUFS;
9807640Ssam 			goto bad;
9817024Ssam 		}
9827024Ssam 		m->m_next = m0;
9837024Ssam 		m->m_off = MMINOFF;
9847024Ssam 		m->m_len = sizeof (struct vv_header);
9857024Ssam 	} else {
9867024Ssam 		m->m_off -= sizeof (struct vv_header);
9877024Ssam 		m->m_len += sizeof (struct vv_header);
9887024Ssam 	}
9897024Ssam 	vv = mtod(m, struct vv_header *);
99021779Skarels 	vv->vh_shost = vs->vs_host;
99121779Skarels 	vv->vh_dhost = dest;
9927024Ssam 	vv->vh_version = RING_VERSION;
9937024Ssam 	vv->vh_type = type;
99428954Skarels 	vv->vh_info = htons((u_short)off);
99511192Ssam 	vvtracehdr("vo", vv);
9967024Ssam 
9977024Ssam 	/*
9987024Ssam 	 * Queue message on interface, and start output if interface
9997024Ssam 	 * not yet active.
10007024Ssam 	 */
10017024Ssam 	s = splimp();
10027640Ssam 	if (IF_QFULL(&ifp->if_snd)) {
10037640Ssam 		IF_DROP(&ifp->if_snd);
10047640Ssam 		error = ENOBUFS;
10057640Ssam 		goto qfull;
10067640Ssam 	}
10077024Ssam 	IF_ENQUEUE(&ifp->if_snd, m);
100816581Skarels 	if (vs->vs_oactive == 0)
100916581Skarels 		vvstart(unit);
10107024Ssam 	splx(s);
10117640Ssam 	return (0);
10127640Ssam qfull:
10137640Ssam 	m0 = m;
10147640Ssam 	splx(s);
10157640Ssam bad:
10167640Ssam 	m_freem(m0);
10177640Ssam 	return(error);
10187024Ssam }
10197024Ssam 
10207024Ssam /*
102113057Ssam  * Process an ioctl request.
102213057Ssam  */
102313057Ssam vvioctl(ifp, cmd, data)
102413057Ssam 	register struct ifnet *ifp;
102513057Ssam 	int cmd;
102613057Ssam 	caddr_t data;
102713057Ssam {
1028*38986Skarels 	register struct vv_softc *vs = &vv_softc[ifp->if_unit];
102921779Skarels 	struct ifaddr *ifa = (struct ifaddr *) data;
1030*38986Skarels 	struct vvreg *addr = (struct vvreg *)(vvinfo[ifp->if_unit]);
103121779Skarels 	int s = splimp(), error = 0;
103213057Ssam 
103313057Ssam 	switch (cmd) {
103413057Ssam 
103513057Ssam 	case SIOCSIFADDR:
1036*38986Skarels 		if ((vs->vs_flags & VS_RUNNING) == 0)
1037*38986Skarels 			vvinit(ifp->if_unit, 1);
103826903Sjas 		/*
103926903Sjas 		 * Did self-test succeed?
104026903Sjas 		 */
104126903Sjas 		if ((ifp->if_flags & IFF_UP) == 0)
104226903Sjas 			error = ENETDOWN;
104336085Skarels 		else {
104436085Skarels 			/*
104536085Skarels 			 * Attempt to check agreement of protocol address
104636085Skarels 			 * and board address.
104736085Skarels 			 */
104836085Skarels 			switch (ifa->ifa_addr.sa_family) {
104936085Skarels 			case AF_INET:
105036085Skarels 				if ((in_lnaof(IA_SIN(ifa)->sin_addr) & 0xff) !=
1051*38986Skarels 				    vs->vs_host)
105236085Skarels 					error = EADDRNOTAVAIL;
105336085Skarels 				break;
105436085Skarels 			}
105521779Skarels 		}
105613057Ssam 		break;
105713057Ssam 
1058*38986Skarels 	case SIOCSIFFLAGS:
1059*38986Skarels 		if ((ifp->if_flags & IFF_UP) == 0 &&
1060*38986Skarels 		    vs->vs_flags & VS_RUNNING) {
1061*38986Skarels 			addr->vvicsr = VV_RST;
1062*38986Skarels 			addr->vvocsr = VV_RST;
1063*38986Skarels 			vs->vs_flags &= ~VS_RUNNING;
1064*38986Skarels 		} else if (ifp->if_flags & IFF_UP &&
1065*38986Skarels 		    (vs->vs_flags & VS_RUNNING) == 0)
1066*38986Skarels 			vvinit(ifp->if_unit, 1);
1067*38986Skarels 		break;
1068*38986Skarels 
106913057Ssam 	default:
107013057Ssam 		error = EINVAL;
1071*38986Skarels 		break;
107213057Ssam 	}
107313057Ssam 	splx(s);
107421779Skarels 	return (error);
107513057Ssam }
107625190Skarels 
107725190Skarels /*
107825190Skarels  * vvprt_hdr(s, v) print the local net header in "v"
107925190Skarels  *	with title is "s"
108025190Skarels  */
108125190Skarels vvprt_hdr(s, v)
108225190Skarels 	char *s;
108325190Skarels 	register struct vv_header *v;
108425190Skarels {
108525190Skarels 	printf("%s: dsvti: 0x%x 0x%x 0x%x 0x%x 0x%x\n",
108625190Skarels 		s,
108725190Skarels 		0xff & (int)(v->vh_dhost), 0xff & (int)(v->vh_shost),
108825190Skarels 		0xff & (int)(v->vh_version), 0xff & (int)(v->vh_type),
108925190Skarels 		0xffff & (int)(v->vh_info));
109025190Skarels }
109126903Sjas #endif NVV
1092