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