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