xref: /original-bsd/sys/vax/if/if_vv.c (revision 9cf141d8)
1 /*
2  * Copyright (c) 1982, 1986 Regents of the University of California.
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms are permitted
6  * provided that the above copyright notice and this paragraph are
7  * duplicated in all such forms and that any documentation,
8  * advertising materials, and other materials related to such
9  * distribution and use acknowledge that the software was developed
10  * by the University of California, Berkeley.  The name of the
11  * University may not be used to endorse or promote products derived
12  * from this software without specific prior written permission.
13  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
14  * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
15  * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
16  *
17  *	@(#)if_vv.c	7.3 (Berkeley) 10/12/88
18  */
19 
20 #include "vv.h"
21 #if NVV > 0
22 
23 /*
24  * Proteon ProNET-10 and ProNET-80 token ring driver.
25  * The name of this device driver derives from the old MIT
26  * name of V2LNI for the proNET hardware, would would abbreviate
27  * to "v2", but this won't work right in config. Thus the name is "vv".
28  *
29  * This driver is compatible with the Unibus ProNET 10 megabit and
30  * 80 megabit token ring interfaces (models p1000 and p1080).
31  * A unit may be marked as 80 megabit using "flags 1" in the
32  * config file.
33  *
34  * This driver is also compatible with the Q-bus ProNET 10 megabit and
35  * 80 megabit token ring interfaces (models p1100 and p1180), but
36  * only on a MicroVAX-II or MicroVAX-III.  No attempt is made to
37  * support the MicroVAX-I.
38  *
39  * TRAILERS: This driver has a new implementation of trailers that
40  * is at least a tolerable neighbor on the ring. The offset is not
41  * stored in the protocol type, but instead only in the vh_info
42  * field. Also, the vh_info field, and the two shorts before the
43  * trailing header, are in network byte order, not VAX byte order.
44  *
45  * Of course, nothing but BSD UNIX supports trailers on ProNET.
46  * If you need interoperability with anything else (like the p4200),
47  * turn off trailers using the -trailers option to /etc/ifconfig!
48  *
49  * HARDWARE COMPATABILITY: This driver prefers that the HSBU (p1001)
50  * have a serial number >= 040, which is about March, 1982. Older
51  * HSBUs do not carry across 64kbyte boundaries. They can be supported
52  * by adding "| UBA_NEED16" to the vs_ifuba.ifu_flags initialization
53  * in vvattach().
54  *
55  * The old warning about use without Wire Centers applies only to CTL
56  * (p1002) cards with serial <= 057, which have not received ECO 176-743,
57  * which was implemented in March, 1982. Most such CTLs have received
58  * this ECO.
59  */
60 #include "../machine/pte.h"
61 
62 #include "param.h"
63 #include "systm.h"
64 #include "mbuf.h"
65 #include "buf.h"
66 #include "protosw.h"
67 #include "socket.h"
68 #include "vmmac.h"
69 #include "errno.h"
70 #include "ioctl.h"
71 
72 #include "../net/if.h"
73 #include "../net/netisr.h"
74 #include "../net/route.h"
75 
76 #ifdef	INET
77 #include "../netinet/in.h"
78 #include "../netinet/in_systm.h"
79 #include "../netinet/in_var.h"
80 #include "../netinet/ip.h"
81 #endif
82 
83 #include "../vax/cpu.h"
84 #include "../vax/mtpr.h"
85 #include "if_vv.h"
86 #include "if_uba.h"
87 #include "../vaxuba/ubareg.h"
88 #include "../vaxuba/ubavar.h"
89 
90 /*
91  *    maximum transmission unit definition --
92  *        you can set VVMTU at anything from 576 to 2036.
93  *        1536 is a popular "large" value, because it is a multiple
94  *	  of 512, which the trailer scheme likes.
95  *        The absolute maximum size is 2036, which is enforced.
96  */
97 
98 #define VVMTU (2036)
99 
100 #define VVMRU (VVMTU + (2 * sizeof(u_short)))
101 #define VVBUFSIZE (VVMRU + sizeof(struct vv_header))
102 #if VVMTU>2036
103 #undef VVMTU
104 #undef VVMRU
105 #undef VVBUFSIZE
106 #define VVBUFSIZE (2046)
107 #define VVMRU (VVBUFSIZE - sizeof (struct vv_header))
108 #define VVMTU (VVMRU - (2 * sizeof(u_short)))
109 #endif
110 
111 /*
112  *   debugging and tracing stuff
113  */
114 int	vv_tracehdr = 0;	/* 1 => trace headers (slowly!!) */
115 
116 #define vvtracehdr  if (vv_tracehdr) vvprt_hdr
117 #define vvprintf    if (vs->vs_if.if_flags & IFF_DEBUG) printf
118 
119 /*
120  * externals, types, etc.
121  */
122 int	vvprobe(), vvattach(), vvreset(), vvinit();
123 int	vvidentify(), vvstart(), vvxint(), vvwatchdog();
124 int	vvrint(), vvoutput(), vvioctl();
125 struct	uba_device *vvinfo[NVV];
126 u_short vvstd[] = { 0 };
127 struct	uba_driver vvdriver =
128 	{ vvprobe, 0, vvattach, 0, vvstd, "vv", vvinfo };
129 #define	VVUNIT(x)	minor(x)
130 
131 #define LOOPBACK		/* use loopback for packets meant for us */
132 #ifdef	LOOPBACK
133 extern struct ifnet loif;
134 #endif
135 
136 /*
137  * Software status of each interface.
138  *
139  * Each interface is referenced by a network interface structure,
140  * vs_if, which the routing code uses to locate the interface.
141  * This structure contains the output queue for the interface, its address, ...
142  * We also have, for each interface, a UBA interface structure, which
143  * contains information about the UNIBUS resources held by the interface:
144  * map registers, buffered data paths, etc.  Information is cached in this
145  * structure for use by the if_uba.c routines in running the interface
146  * efficiently.
147  */
148 struct	vv_softc {
149 	struct	ifnet vs_if;		/* network-visible interface */
150 	struct	ifuba vs_ifuba;		/* UNIBUS resources */
151 	u_short	vs_host;		/* this interface address */
152 	short	vs_oactive;		/* is output active */
153 	short	vs_is80;		/* is 80 megabit version */
154 	short	vs_olen;		/* length of last output */
155 	u_short	vs_lastx;		/* address of last packet sent */
156 	u_short	vs_lastr;		/* address of last packet received */
157 	short	vs_tries;		/* transmit current retry count */
158 	short	vs_init;		/* number of ring inits */
159 	short	vs_refused;		/* number of packets refused */
160 	short	vs_timeouts;		/* number of transmit timeouts */
161 	short	vs_otimeout;		/* number of output timeouts */
162 	short	vs_ibadf;		/* number of input bad formats */
163 	short	vs_parity;		/* number of parity errors on 10 meg, */
164 					/* link data errors on 80 meg */
165 } vv_softc[NVV];
166 
167 #define	NOHOST	0xffff			/* illegal host number */
168 
169 /*
170  * probe the interface to see that the registers exist, and then
171  * cause an interrupt to find its vector
172  */
173 vvprobe(reg)
174 	caddr_t reg;
175 {
176 	register int br, cvec;
177 	register struct vvreg *addr;
178 
179 #ifdef lint
180 	br = 0; cvec = br; br = cvec;
181 #endif
182 	addr = (struct vvreg *)reg;
183 
184 	/* reset interface, enable, and wait till dust settles */
185 	addr->vvicsr = VV_RST;
186 	addr->vvocsr = VV_RST;
187 	DELAY(100000);
188 
189 	/* generate interrupt by doing 1 word DMA from 0 in uba space!! */
190 	addr->vvoba = 0;		/* low 16 bits */
191 	addr->vvoea = 0;		/* extended bits */
192 	addr->vvowc = -1;		/* for 1 word */
193 	addr->vvocsr = VV_IEN | VV_DEN;	/* start the DMA, with interrupt */
194 	DELAY(100000);
195 	addr->vvocsr = VV_RST;		/* clear out the CSR */
196 	if (cvec && cvec != 0x200)
197 		cvec -= 4;		/* backup so vector => receive */
198 	return(1);
199 }
200 
201 /*
202  * Interface exists: make available by filling in network interface
203  * record.  System will initialize the interface when it is ready
204  * to accept packets.
205  */
206 vvattach(ui)
207 	struct uba_device *ui;
208 {
209 	register struct vv_softc *vs;
210 
211 	vs = &vv_softc[ui->ui_unit];
212 	vs->vs_if.if_unit = ui->ui_unit;
213 	vs->vs_if.if_name = "vv";
214 	vs->vs_if.if_mtu = VVMTU;
215 	vs->vs_if.if_flags = IFF_BROADCAST;
216 	vs->vs_if.if_init = vvinit;
217 	vs->vs_if.if_ioctl = vvioctl;
218 	vs->vs_if.if_output = vvoutput;
219 	vs->vs_if.if_reset = vvreset;
220 	vs->vs_if.if_timer = 0;
221 	vs->vs_if.if_watchdog = vvwatchdog;
222 	vs->vs_ifuba.ifu_flags = UBA_CANTWAIT | UBA_NEEDBDP;
223 
224 	/* use flag to determine if this is proNET-80 */
225 	vs->vs_is80 = (short)(ui->ui_flags & 01);
226 
227 #if defined(VAX750)
228 	/* don't chew up 750 bdp's */
229 	if (cpu == VAX_750 && ui->ui_unit > 0)
230 		vs->vs_ifuba.ifu_flags &= ~UBA_NEEDBDP;
231 #endif
232 	if_attach(&vs->vs_if);
233 }
234 
235 /*
236  * Reset of interface after UNIBUS reset.
237  * If interface is on specified uba, reset its state.
238  */
239 vvreset(unit, uban)
240 	int unit, uban;
241 {
242 	register struct uba_device *ui;
243 
244 	if (unit >= NVV || (ui = vvinfo[unit]) == 0 || ui->ui_alive == 0 ||
245 	    ui->ui_ubanum != uban)
246 		return;
247 	printf(" vv%d", unit);
248 	vvinit(unit);
249 }
250 
251 /*
252  * Initialization of interface; clear recorded pending
253  * operations, and reinitialize UNIBUS usage.
254  */
255 vvinit(unit)
256 	int unit;
257 {
258 	register struct vv_softc *vs;
259 	register struct uba_device *ui;
260 	register struct vvreg *addr;
261 	register int ubaaddr, s;
262 
263 	vs = &vv_softc[unit];
264 	ui = vvinfo[unit];
265 
266 	if (vs->vs_if.if_addrlist == (struct ifaddr *)0)
267 		return;
268 
269 	addr = (struct vvreg *)ui->ui_addr;
270 	if (if_ubainit(&vs->vs_ifuba, ui->ui_ubanum,
271 	    sizeof (struct vv_header), (int)btoc(VVMRU)) == 0) {
272 		printf("vv%d: can't initialize, if_ubainit() failed\n", unit);
273 		vs->vs_if.if_flags &= ~IFF_UP;
274 		return;
275 	}
276 
277 	/*
278 	 * Now that the uba is set up, figure out our address and
279 	 * update complete our host address.
280 	 */
281 	if ((vs->vs_host = vvidentify(unit)) == NOHOST) {
282 		vs->vs_if.if_flags &= ~IFF_UP;
283 		return;
284 	}
285 	printf("vv%d: host %u\n", unit, vs->vs_host);
286 
287 	/*
288 	 * Reset the interface, and stay in the ring
289 	 */
290 	addr->vvocsr = VV_RST;			/* take over output */
291 	addr->vvocsr = VV_CPB;			/* clear packet buffer */
292 	addr->vvicsr = VV_RST | VV_HEN;		/* take over input, */
293 						/* keep relay closed */
294 	DELAY(500000);				/* let contacts settle */
295 
296 	vs->vs_init = 0;			/* clear counters, etc. */
297 	vs->vs_refused = 0;
298 	vs->vs_timeouts = 0;
299 	vs->vs_otimeout = 0;
300 	vs->vs_ibadf = 0;
301 	vs->vs_parity = 0;
302 	vs->vs_lastx = 256;			/* an invalid address */
303 	vs->vs_lastr = 256;			/* an invalid address */
304 
305 	/*
306 	 * Hang a receive and start any
307 	 * pending writes by faking a transmit complete.
308 	 */
309 	s = splimp();
310 	ubaaddr = UBAI_ADDR(vs->vs_ifuba.ifu_r.ifrw_info);
311 	addr->vviba = (u_short)ubaaddr;
312 	addr->vviea = (u_short)(ubaaddr >> 16);
313 	addr->vviwc = -(VVBUFSIZE) >> 1;
314 	addr->vvicsr = VV_IEN | VV_HEN | VV_DEN | VV_ENB;
315 	vs->vs_oactive = 1;
316 	vs->vs_if.if_flags |= IFF_RUNNING;
317 	vvxint(unit);
318 	splx(s);
319 }
320 
321 /*
322  * Do a moderately thorough self-test in all three modes. Mostly
323  * to keeps defective nodes off the ring, rather than to be especially
324  * thorough. The key issue is to detect any cable breaks before joining
325  * the ring. Return our node address on success, return -1 on failure.
326  *
327  */
328 
329 /* the three self-test modes */
330 static u_short vv_modes[] = {
331 	VV_STE|VV_LPB,			/* digital loopback */
332 	VV_STE,				/* analog loopback */
333 	VV_HEN				/* network mode */
334 };
335 
336 vvidentify(unit)
337 	int unit;
338 {
339 	register struct vv_softc *vs;
340 	register struct uba_device *ui;
341 	register struct vvreg *addr;
342 	register struct mbuf *m;
343 	register struct vv_header *v;
344 	register int ubaaddr;
345 	register int i, successes, failures, waitcount;
346 	u_short shost = NOHOST;
347 
348 	vs = &vv_softc[unit];
349 	ui = vvinfo[unit];
350 	addr = (struct vvreg *)ui->ui_addr;
351 
352 	/*
353 	 * Build a multicast message to identify our address
354 	 * We need do this only once, since nobody else is about to use
355 	 * the intermediate transmit buffer (ifu_w.ifrw_addr) that
356 	 * if_ubainit() aquired for us.
357 	 */
358 	m = m_get(M_DONTWAIT, MT_HEADER);
359 	if (m == NULL) {
360 		printf("vv%d: can't initialize, m_get() failed\n", unit);
361 		return (0);
362 	}
363 	m->m_next = 0;
364 	m->m_off = MMINOFF;
365 	m->m_len = sizeof(struct vv_header);
366 	v = mtod(m, struct vv_header *);
367 	v->vh_dhost = VV_BROADCAST;	/* multicast destination address */
368 	v->vh_shost = 0;		/* will be overwritten with ours */
369 	v->vh_version = RING_VERSION;
370 	v->vh_type = RING_DIAGNOSTICS;
371 	v->vh_info = 0;
372 	/* map xmit message into uba, copying to intermediate buffer */
373 	vs->vs_olen = if_wubaput(&vs->vs_ifuba, m);
374 
375 	/*
376 	 * For each of the modes (digital, analog, network), go through
377 	 * a self-test that requires me to send VVIDENTSUCC good packets
378 	 * in VVIDENTRETRY attempts. Use broadcast destination to find out
379 	 * who I am, then use this as my address to check my address match
380 	 * logic. Only data checked is the vh_type field.
381 	 */
382 
383 	for (i = 0; i < 3; i++) {
384 		successes = 0;	/* clear successes for this mode */
385 		failures = 0;	/* and clear failures, too */
386 
387 		/* take over device, and leave ring */
388 		addr->vvicsr = VV_RST;
389 		addr->vvocsr = VV_RST;
390 		addr->vvicsr = vv_modes[i];	/* test mode */
391 
392 		/*
393 		 * let the flag and token timers pop so that the init ring bit
394 		 * will be allowed to work, by waiting about 1 second
395 		 */
396 		DELAY(1000000L);
397 
398 		/*
399 		 * retry loop
400  		 */
401 		while ((successes < VVIDENTSUCC) && (failures < VVIDENTRETRY))
402 		{
403 			/* start a receive */
404 			ubaaddr = UBAI_ADDR(vs->vs_ifuba.ifu_r.ifrw_info);
405 			addr->vvicsr = VV_RST | vv_modes[i]; /* abort last */
406 			addr->vviba = (u_short) ubaaddr;
407 			addr->vviea = (u_short) (ubaaddr >> 16);
408 			addr->vviwc = -(VVBUFSIZE) >> 1;
409 			addr->vvicsr = vv_modes[i] | VV_DEN | VV_ENB;
410 
411 			/* purge stale data from BDP */
412 			if (vs->vs_ifuba.ifu_flags & UBA_NEEDBDP)
413 				UBAPURGE(vs->vs_ifuba.ifu_uba,
414 				    vs->vs_ifuba.ifu_w.ifrw_bdp);
415 
416 			/* do a transmit */
417 			ubaaddr = UBAI_ADDR(vs->vs_ifuba.ifu_w.ifrw_info);
418 			addr->vvocsr = VV_RST;	/* abort last try */
419 			addr->vvoba = (u_short) ubaaddr;
420 			addr->vvoea = (u_short) (ubaaddr >> 16);
421 			addr->vvowc = -((vs->vs_olen + 1) >> 1);
422 			addr->vvocsr = VV_CPB | VV_DEN | VV_INR | VV_ENB;
423 
424 			/* poll receive side for completion */
425 			DELAY(10000);		/* give it a chance */
426 			for (waitcount = 0; waitcount < 10; waitcount++) {
427 				if (addr->vvicsr & VV_RDY)
428 					goto gotit;
429 				DELAY(1000);
430 			}
431 			failures++;		/* no luck */
432 			continue;
433 
434 gotit:			/* we got something--is it any good? */
435 			if ((addr->vvicsr & (VVRERR|VV_LDE)) ||
436 			    (addr->vvocsr & (VVXERR|VV_RFS))) {
437 				failures++;
438 				continue;
439 			}
440 
441 			/* Purge BDP before looking at received packet */
442 			if (vs->vs_ifuba.ifu_flags & UBA_NEEDBDP)
443 				UBAPURGE(vs->vs_ifuba.ifu_uba,
444 				    vs->vs_ifuba.ifu_r.ifrw_bdp);
445 			m = if_rubaget(&vs->vs_ifuba, sizeof(struct vv_header),
446 				0, &vs->vs_if);
447 			if (m != NULL)
448 				m_freem(m);
449 
450 			v = (struct vv_header *)(vs->vs_ifuba.ifu_r.ifrw_addr);
451 
452 			/* check message type, catch our node address */
453 			if ((v->vh_type & 0xff) == RING_DIAGNOSTICS) {
454 				if (shost == NOHOST) {
455 					shost = v->vh_shost & 0xff;
456 					/* send to ourself now */
457 					((struct vv_header *)
458 					    (vs->vs_ifuba.ifu_r.ifrw_addr))
459 					    ->vh_dhost = shost;
460 				}
461 				successes++;
462 			} else {
463 				failures++;
464 			}
465 			v->vh_type = 0;  /* clear to check again */
466 		}
467 
468 		if (failures >= VVIDENTRETRY)
469 		{
470 			printf("vv%d: failed self-test after %d tries \
471 in %s mode\n",
472 			    unit, VVIDENTRETRY, i == 0 ? "digital loopback" :
473 			    (i == 1 ? "analog loopback" : "network"));
474 			printf("vv%d: icsr = %b, ocsr = %b\n",
475 			    unit, 0xffff & addr->vvicsr, VV_IBITS,
476 			    0xffff & addr->vvocsr, VV_OBITS);
477 			addr->vvicsr = VV_RST;	/* kill the sick board */
478 			addr->vvocsr = VV_RST;
479 			shost = NOHOST;
480 			goto done;
481 		}
482 	}
483 
484 done:
485 	/* deallocate mbuf used for send packet (won't be one, anyways) */
486 	if (vs->vs_ifuba.ifu_xtofree) {
487 		m_freem(vs->vs_ifuba.ifu_xtofree);
488 		vs->vs_ifuba.ifu_xtofree = 0;
489 	}
490 
491 	return(shost);
492 }
493 
494 /*
495  * Start or restart output on interface.
496  * If interface is active, this is a retransmit, so just
497  * restuff registers and go.
498  * If interface is not already active, get another datagram
499  * to send off of the interface queue, and map it to the interface
500  * before starting the output.
501  */
502 vvstart(dev)
503 	dev_t dev;
504 {
505 	register struct uba_device *ui;
506 	register struct vv_softc *vs;
507 	register struct vvreg *addr;
508 	register struct mbuf *m;
509 	register int unit, ubaaddr, dest, s;
510 
511 	unit = VVUNIT(dev);
512 	ui = vvinfo[unit];
513 	vs = &vv_softc[unit];
514 	if (vs->vs_oactive)
515 		goto restart;
516 	/*
517 	 * Not already active: dequeue another request
518 	 * and map it to the UNIBUS.  If no more requests,
519 	 * just return.
520 	 */
521 	s = splimp();
522 	IF_DEQUEUE(&vs->vs_if.if_snd, m);
523 	splx(s);
524 	if (m == NULL) {
525 		vs->vs_oactive = 0;
526 		return;
527 	}
528 	dest = mtod(m, struct vv_header *)->vh_dhost;
529 	vs->vs_olen = if_wubaput(&vs->vs_ifuba, m);
530 	vs->vs_lastx = dest;
531 restart:
532 	/*
533 	 * Have request mapped to UNIBUS for transmission.
534 	 * Purge any stale data from this BDP, and start the output.
535 	 *
536 	 * Make sure this packet will fit in the interface.
537 	 */
538 	if (vs->vs_olen > VVBUFSIZE) {
539 		printf("vv%d vs_olen: %d > VVBUFSIZE\n", unit, vs->vs_olen);
540 		panic("vvdriver vs_olen botch");
541 	}
542 
543 	vs->vs_if.if_timer = VVTIMEOUT;
544 	vs->vs_oactive = 1;
545 
546 	/* ship it */
547 	if (vs->vs_ifuba.ifu_flags & UBA_NEEDBDP)
548 		UBAPURGE(vs->vs_ifuba.ifu_uba, vs->vs_ifuba.ifu_w.ifrw_bdp);
549 	addr = (struct vvreg *)ui->ui_addr;
550 	ubaaddr = UBAI_ADDR(vs->vs_ifuba.ifu_w.ifrw_info);
551 	addr->vvoba = (u_short) ubaaddr;
552 	addr->vvoea = (u_short) (ubaaddr >> 16);
553 	addr->vvowc = -((vs->vs_olen + 1) >> 1);
554 	addr->vvowc = -((vs->vs_olen + 1) >> 1); /* extra byte is garbage */
555 	if (addr->vvocsr & VV_NOK)
556 		vs->vs_init++;			/* count ring inits */
557 	addr->vvocsr = VV_IEN | VV_CPB | VV_DEN | VV_INR | VV_ENB;
558 }
559 
560 /*
561  * proNET transmit interrupt
562  * Start another output if more data to send.
563  */
564 vvxint(unit)
565 	int unit;
566 {
567 	register struct uba_device *ui;
568 	register struct vv_softc *vs;
569 	register struct vvreg *addr;
570 	register int oc;
571 
572 	ui = vvinfo[unit];
573 	vs = &vv_softc[unit];
574 	vs->vs_if.if_timer = 0;
575 	addr = (struct vvreg *)ui->ui_addr;
576 	oc = 0xffff & (addr->vvocsr);
577 	if (vs->vs_oactive == 0) {
578 		vvprintf("vv%d: stray interrupt vvocsr = %b\n", unit,
579 		    oc, VV_OBITS);
580 		return;
581 	}
582 
583 	/*
584 	 * we retransmit on soft error
585 	 * TODO: sort retransmits to end of queue if possible!
586 	 */
587 	if (oc & (VV_OPT | VV_RFS)) {
588 		if (vs->vs_tries++ < VVRETRY) {
589 			if (oc & VV_OPT)
590 				vs->vs_otimeout++;
591 			if (oc & VV_RFS) {
592 				vs->vs_if.if_collisions++;
593 				vs->vs_refused++;
594 			}
595 			vvstart(unit);		/* restart this message */
596 			return;
597 		}
598 	}
599 	vs->vs_if.if_opackets++;
600 	vs->vs_oactive = 0;
601 	vs->vs_tries = 0;
602 
603 	if (oc & VVXERR) {
604 		vs->vs_if.if_oerrors++;
605 		vvprintf("vv%d: error vvocsr = %b\n", unit, 0xffff & oc,
606 		    VV_OBITS);
607 	}
608 	if (vs->vs_ifuba.ifu_xtofree) {
609 		m_freem(vs->vs_ifuba.ifu_xtofree);
610 		vs->vs_ifuba.ifu_xtofree = 0;
611 	}
612 	vvstart(unit);
613 }
614 
615 /*
616  * Transmit watchdog timer routine.
617  * This routine gets called when we lose a transmit interrupt.
618  * The best we can do is try to restart output.
619  */
620 vvwatchdog(unit)
621 	int unit;
622 {
623 	register struct vv_softc *vs;
624 	register int s;
625 
626 	vs = &vv_softc[unit];
627 	vvprintf("vv%d: lost a transmit interrupt.\n", unit);
628 	vs->vs_timeouts++;
629 	s = splimp();
630 	vvstart(unit);
631 	splx(s);
632 }
633 
634 /*
635  * proNET interface receiver interrupt.
636  * If input error just drop packet.
637  * Otherwise purge input buffered data path and examine
638  * packet to determine type.  If can't determine length
639  * from type, then have to drop packet.  Otherwise decapsulate
640  * packet based on type and pass to type specific higher-level
641  * input routine.
642  */
643 vvrint(unit)
644 	int unit;
645 {
646 	register struct vv_softc *vs;
647 	register struct vvreg *addr;
648 	register struct vv_header *vv;
649 	register struct ifqueue *inq;
650 	register struct mbuf *m;
651 	int ubaaddr, len, off, s;
652 	short resid;
653 
654 	vs = &vv_softc[unit];
655 	vs->vs_if.if_ipackets++;
656 	addr = (struct vvreg *)vvinfo[unit]->ui_addr;
657 
658 	/*
659 	 * Purge BDP
660 	 */
661 	if (vs->vs_ifuba.ifu_flags & UBA_NEEDBDP)
662 		UBAPURGE(vs->vs_ifuba.ifu_uba, vs->vs_ifuba.ifu_r.ifrw_bdp);
663 
664 	/*
665 	 * receive errors?
666 	 */
667 	if (addr->vvicsr & VVRERR) {
668 		vvprintf("vv%d: receive error, vvicsr = %b\n", unit,
669 		    0xffff&(addr->vvicsr), VV_IBITS);
670 		if (addr->vvicsr & VV_BDF)
671 			vs->vs_ibadf++;
672 		goto dropit;
673 	}
674 
675 	/*
676 	 * parity errors?
677 	 */
678 	if (addr->vvicsr & VV_LDE) {
679 		/* we don't have to clear it because the receive command */
680 		/* writes 0 to parity bit */
681 		vs->vs_parity++;
682 
683 		/*
684 		 * only on 10 megabit proNET is VV_LDE an end-to-end parity
685 		 * bit. On 80 megabit, it returns to the intended use of
686 		 * node-to-node parity. End-to-end parity errors on 80 megabit
687 		 * give VV_BDF.
688 		 */
689 		if (vs->vs_is80 == 0)
690 		    goto dropit;
691 	}
692 
693 	/*
694 	 * Get packet length from residual word count
695 	 *
696 	 * Compute header offset if trailer protocol
697 	 *
698 	 * Pull packet off interface.  Off is nonzero if packet
699 	 * has trailing header; if_rubaget will then force this header
700 	 * information to be at the front.  The vh_info field
701 	 * carries the offset to the trailer data in trailer
702 	 * format packets.
703 	 */
704 	vv = (struct vv_header *)(vs->vs_ifuba.ifu_r.ifrw_addr);
705 	vvtracehdr("vi", vv);
706 	resid = addr->vviwc & 01777;	/* only low 10 bits valid */
707 	if (resid)
708 		resid |= 0176000;	/* high 6 bits are undefined */
709 	len = ((VVBUFSIZE >> 1) + resid) << 1;
710 	len -= sizeof(struct vv_header);
711 
712 	if ((addr->vvicsr & VV_DPR) || len > VVMRU || len <= 0) {
713 		vvprintf("vv%d: len too long or short, \
714 len = %d, vvicsr = %b\n",
715 			    unit, len, 0xffff&(addr->vvicsr), VV_IBITS);
716 		goto dropit;
717 	}
718 
719 	/* check the protocol header version */
720 	if (vv->vh_version != RING_VERSION) {
721 		vvprintf("vv%d: bad protocol header version %d\n",
722 		    unit, vv->vh_version & 0xff);
723 		goto dropit;
724 	}
725 
726 #define	vvdataaddr(vv, off, type)	((type)(((caddr_t)((vv)+1)+(off))))
727 	if (vv->vh_type == RING_TRAILER ) {
728 		off = ntohs((u_short)vv->vh_info);
729 		if (off > VVMTU) {
730 			vvprintf("vv%d: off > VVMTU, off = %d, vvicsr = %b\n",
731 				    unit, off, 0xffff&(addr->vvicsr), VV_IBITS);
732 			goto dropit;
733 		}
734 		vv->vh_type = ntohs(*vvdataaddr(vv, off, u_short *));
735 		resid = ntohs(*(vvdataaddr(vv, off+sizeof(u_short), u_short *)));
736 		if (off + resid > len) {
737 			vvprintf("vv%d: trailer packet too short\n", unit);
738 			vvprintf("vv%d: off = %d, resid = %d, vvicsr = %b\n",
739 				    unit, off, resid,
740 				    0xffff&(addr->vvicsr), VV_IBITS);
741 			goto dropit;
742 		}
743 		len = off + resid;
744 	} else
745 		off = 0;
746 
747 	if (len == 0) {
748 		vvprintf("vv%d: len is zero, vvicsr = %b\n", unit,
749 			    0xffff&(addr->vvicsr), VV_IBITS);
750 		goto dropit;
751 	}
752 
753 	m = if_rubaget(&vs->vs_ifuba, len, off, &vs->vs_if);
754 	if (m == NULL) {
755 		vvprintf("vv%d: if_rubaget() failed, vvicsr = %b\n", unit,
756 			    0xffff&(addr->vvicsr), VV_IBITS);
757 		goto dropit;
758 	}
759 	if (off) {
760 		struct ifnet *ifp;
761 
762 		ifp = *(mtod(m, struct ifnet **));
763 		m->m_off += 2 * sizeof (u_short);
764 		m->m_len -= 2 * sizeof (u_short);
765 		*(mtod(m, struct ifnet **)) = ifp;
766 	}
767 
768 	/* Keep track of source address of this packet */
769 	vs->vs_lastr = vv->vh_shost;
770 
771 	/*
772 	 * Demultiplex on packet type
773 	 */
774 	switch (vv->vh_type) {
775 
776 #ifdef INET
777 	case RING_IP:
778 		schednetisr(NETISR_IP);
779 		inq = &ipintrq;
780 		break;
781 #endif
782 	default:
783 		vvprintf("vv%d: unknown pkt type 0x%x\n", unit, vv->vh_type);
784 		m_freem(m);
785 		goto setup;
786 	}
787 	s = splimp();
788 	if (IF_QFULL(inq)) {
789 		IF_DROP(inq);
790 		m_freem(m);
791 	} else
792 		IF_ENQUEUE(inq, m);
793 
794 	splx(s);
795 	/*
796 	 * Reset for the next packet.
797 	 */
798 setup:
799 	ubaaddr = UBAI_ADDR(vs->vs_ifuba.ifu_r.ifrw_info);
800 	addr->vviba = (u_short) ubaaddr;
801 	addr->vviea = (u_short) (ubaaddr >> 16);
802 	addr->vviwc = -(VVBUFSIZE) >> 1;
803 	addr->vvicsr = VV_HEN | VV_IEN | VV_DEN | VV_ENB;
804 	return;
805 
806 	/*
807 	 * Drop packet on floor -- count them!!
808 	 */
809 dropit:
810 	vs->vs_if.if_ierrors++;
811 	goto setup;
812 }
813 
814 /*
815  * proNET output routine.
816  * Encapsulate a packet of type family for the local net.
817  * Use trailer local net encapsulation if enough data in first
818  * packet leaves a multiple of 512 bytes of data in remainder.
819  */
820 vvoutput(ifp, m0, dst)
821 	struct ifnet *ifp;
822 	struct mbuf *m0;
823 	struct sockaddr *dst;
824 {
825 	register struct mbuf *m;
826 	register struct vv_header *vv;
827 	register int off;
828 	register int unit;
829 	register struct vvreg *addr;
830 	register struct vv_softc *vs;
831 	register int s;
832 	int type, dest, error;
833 
834 	m = m0;
835 	unit = ifp->if_unit;
836 	addr = (struct vvreg *)vvinfo[unit]->ui_addr;
837 	vs = &vv_softc[unit];
838 
839 	/*
840 	 * Check to see if the input side has wedged due the UBA
841 	 * vectoring through 0.
842 	 *
843 	 * We are lower than device ipl when we enter this routine,
844 	 * so if the interface is ready with an input packet then
845 	 * an input interrupt must have slipped through the cracks.
846 	 *
847 	 * Avoid the race with an input interrupt by watching to see
848 	 * if any packets come in.
849 	 */
850 	s = vs->vs_if.if_ipackets;
851 	if (addr->vvicsr & VV_RDY && s == vs->vs_if.if_ipackets) {
852 		vvprintf("vv%d: lost a receive interrupt, icsr = %b\n",
853 			    unit, 0xffff&(addr->vvicsr), VV_IBITS);
854 		s = splimp();
855 		vvrint(unit);
856 		splx(s);
857 	}
858 
859 	switch (dst->sa_family) {
860 
861 #ifdef INET
862 	case AF_INET:
863 		if (in_broadcast(((struct sockaddr_in *)dst)->sin_addr))
864 			dest = VV_BROADCAST;
865 		else
866 			dest = in_lnaof(((struct sockaddr_in *)dst)->sin_addr);
867 #ifdef LOOPBACK
868 		if (dest == vs->vs_host && (loif.if_flags & IFF_UP))
869 			return (looutput(&loif, m0, dst));
870 #endif LOOPBACK
871 		if (dest >= 0x100) {
872 			error = EPERM;
873 			goto bad;
874 		}
875 		off = ntohs((u_short)mtod(m, struct ip *)->ip_len) - m->m_len;
876 		/*
877 		 * Trailerize, if the configuration allows it.
878 		 * TODO: Need per host negotiation.
879 		 */
880 		if ((ifp->if_flags & IFF_NOTRAILERS) == 0)
881 		if (off > 0 && (off & 0x1ff) == 0 &&
882 		    m->m_off >= MMINOFF + 2 * sizeof (u_short)) {
883 			type = RING_TRAILER;
884 			m->m_off -= 2 * sizeof (u_short);
885 			m->m_len += 2 * sizeof (u_short);
886 			*mtod(m, u_short *) = htons((short)RING_IP);
887 			*(mtod(m, u_short *) + 1) = htons((u_short)m->m_len);
888 			goto gottrailertype;
889 		}
890 		type = RING_IP;
891 		off = 0;
892 		goto gottype;
893 #endif
894 	default:
895 		printf("vv%d: can't handle af%d\n", unit, dst->sa_family);
896 		error = EAFNOSUPPORT;
897 		goto bad;
898 	}
899 
900 gottrailertype:
901 	/*
902 	 * Packet to be sent as trailer: move first packet
903 	 * (control information) to end of chain.
904 	 */
905 	while (m->m_next)
906 		m = m->m_next;
907 	m->m_next = m0;
908 	m = m0->m_next;
909 	m0->m_next = 0;
910 	m0 = m;
911 gottype:
912 	/*
913 	 * Add local net header.  If no space in first mbuf,
914 	 * allocate another.
915 	 */
916 	if (m->m_off > MMAXOFF ||
917 	    MMINOFF + sizeof (struct vv_header) > m->m_off) {
918 		m = m_get(M_DONTWAIT, MT_HEADER);
919 		if (m == NULL) {
920 			error = ENOBUFS;
921 			goto bad;
922 		}
923 		m->m_next = m0;
924 		m->m_off = MMINOFF;
925 		m->m_len = sizeof (struct vv_header);
926 	} else {
927 		m->m_off -= sizeof (struct vv_header);
928 		m->m_len += sizeof (struct vv_header);
929 	}
930 	vv = mtod(m, struct vv_header *);
931 	vv->vh_shost = vs->vs_host;
932 	vv->vh_dhost = dest;
933 	vv->vh_version = RING_VERSION;
934 	vv->vh_type = type;
935 	vv->vh_info = htons((u_short)off);
936 	vvtracehdr("vo", vv);
937 
938 	/*
939 	 * Queue message on interface, and start output if interface
940 	 * not yet active.
941 	 */
942 	s = splimp();
943 	if (IF_QFULL(&ifp->if_snd)) {
944 		IF_DROP(&ifp->if_snd);
945 		error = ENOBUFS;
946 		goto qfull;
947 	}
948 	IF_ENQUEUE(&ifp->if_snd, m);
949 	if (vs->vs_oactive == 0)
950 		vvstart(unit);
951 	splx(s);
952 	return (0);
953 qfull:
954 	m0 = m;
955 	splx(s);
956 bad:
957 	m_freem(m0);
958 	return(error);
959 }
960 
961 /*
962  * Process an ioctl request.
963  */
964 vvioctl(ifp, cmd, data)
965 	register struct ifnet *ifp;
966 	int cmd;
967 	caddr_t data;
968 {
969 	struct ifaddr *ifa = (struct ifaddr *) data;
970 	int s = splimp(), error = 0;
971 
972 	switch (cmd) {
973 
974 	case SIOCSIFADDR:
975 		ifp->if_flags |= IFF_UP;
976 		if ((ifp->if_flags & IFF_RUNNING) == 0)
977 			vvinit(ifp->if_unit);
978 		/*
979 		 * Did self-test succeed?
980 		 */
981 		if ((ifp->if_flags & IFF_UP) == 0)
982 			error = ENETDOWN;
983                 /*
984                  * Attempt to check agreement of protocol address
985                  * and board address.
986                  */
987 		switch (ifa->ifa_addr.sa_family) {
988                 case AF_INET:
989 			if (in_lnaof(IA_SIN(ifa)->sin_addr) !=
990 			    vv_softc[ifp->if_unit].vs_host)
991 				error = EADDRNOTAVAIL;
992 			break;
993 		}
994 		break;
995 
996 	default:
997 		error = EINVAL;
998 	}
999 	splx(s);
1000 	return (error);
1001 }
1002 
1003 /*
1004  * vvprt_hdr(s, v) print the local net header in "v"
1005  *	with title is "s"
1006  */
1007 vvprt_hdr(s, v)
1008 	char *s;
1009 	register struct vv_header *v;
1010 {
1011 	printf("%s: dsvti: 0x%x 0x%x 0x%x 0x%x 0x%x\n",
1012 		s,
1013 		0xff & (int)(v->vh_dhost), 0xff & (int)(v->vh_shost),
1014 		0xff & (int)(v->vh_version), 0xff & (int)(v->vh_type),
1015 		0xffff & (int)(v->vh_info));
1016 }
1017 #endif NVV
1018