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