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