xref: /csrg-svn/sys/vax/if/if_vv.c (revision 12351)
1 /*	if_vv.c	4.17	83/05/10	*/
2 
3 #include "vv.h"
4 
5 /*
6  * Proteon 10 Meg Ring Driver.
7  * This device is called "vv" because its "real name",
8  * V2LNI won't work if shortened to the obvious "v2".
9  * Hence the subterfuge.
10  *
11  */
12 #include "../machine/pte.h"
13 
14 #include "../h/param.h"
15 #include "../h/systm.h"
16 #include "../h/mbuf.h"
17 #include "../h/buf.h"
18 #include "../h/protosw.h"
19 #include "../h/socket.h"
20 #include "../h/vmmac.h"
21 #include "../h/errno.h"
22 #include "../h/time.h"
23 #include "../h/kernel.h"
24 
25 #include "../net/if.h"
26 #include "../net/netisr.h"
27 #include "../net/route.h"
28 
29 #include "../netinet/in.h"
30 #include "../netinet/in_systm.h"
31 #include "../netinet/ip.h"
32 #include "../netinet/ip_var.h"
33 
34 #include "../vax/mtpr.h"
35 #include "../vax/cpu.h"
36 
37 #include "../vaxuba/ubareg.h"
38 #include "../vaxuba/ubavar.h"
39 
40 #include "../vaxif/if_vv.h"
41 #include "../vaxif/if_uba.h"
42 
43 /*
44  * N.B. - if WIRECENTER is defined wrong, it can well break
45  * the hardware!!
46  */
47 #define	WIRECENTER
48 
49 #ifdef WIRECENTER
50 #define	VV_CONF	VV_HEN		/* drive wire center relay */
51 #else
52 #define	VV_CONF	VV_STE		/* allow operation without wire center */
53 #endif
54 
55 #define	VVMTU	(1024+512)
56 #define VVMRU	(1024+512+16)	/* space for trailer */
57 
58 int vv_dotrailer = 0,		/* 1 => do trailer protocol */
59     vv_tracehdr = 0,		/* 1 => trace headers (slowly!!) */
60     vv_tracetimeout = 1;	/* 1 => trace input error-rate limiting */
61     vv_logreaderrors = 0;	/* 1 => log all read errors */
62 
63 #define vvtracehdr	if (vv_tracehdr) vvprt_hdr
64 #define	vvtrprintf	if (vv_tracetimeout) printf
65 
66 int vv_ticking = 0;		/* error flywheel is running */
67 
68 /*
69  * Interval in HZ - 50 msec.
70  * N.B. all times below are in units of flywheel ticks
71  */
72 #define VV_FLYWHEEL		3
73 #define	VV_ERRORTHRESHOLD	100	/* errors/flywheel-interval */
74 #define	VV_MODE1ATTEMPTS	10	/* number mode 1 retries */
75 #define	VV_MODE1DELAY		2	/* period interface is PAUSEd - 100ms */
76 #define VV_MODE2DELAY		4	/* base interval host relay is off - 200ms */
77 #define	VV_MAXDELAY		6400	/* max interval host relay is off - 2 minutes */
78 
79 int	vvprobe(), vvattach(), vvrint(), vvxint();
80 struct	uba_device *vvinfo[NVV];
81 u_short vvstd[] = { 0 };
82 struct	uba_driver vvdriver =
83 	{ vvprobe, 0, vvattach, 0, vvstd, "vv", vvinfo };
84 #define	VVUNIT(x)	minor(x)
85 int	vvinit(),vvoutput(),vvreset();
86 
87 /*
88  * Software status of each interface.
89  *
90  * Each interface is referenced by a network interface structure,
91  * vs_if, which the routing code uses to locate the interface.
92  * This structure contains the output queue for the interface, its address, ...
93  * We also have, for each interface, a UBA interface structure, which
94  * contains information about the UNIBUS resources held by the interface:
95  * map registers, buffered data paths, etc.  Information is cached in this
96  * structure for use by the if_uba.c routines in running the interface
97  * efficiently.
98  */
99 struct	vv_softc {
100 	struct	ifnet vs_if;		/* network-visible interface */
101 	struct	ifuba vs_ifuba;		/* UNIBUS resources */
102 	short	vs_oactive;		/* is output active */
103 	short	vs_iactive;		/* is input active */
104 	short	vs_olen;		/* length of last output */
105 	u_short	vs_lastx;		/* last destination address */
106 	short	vs_tries;		/* transmit current retry count */
107 	short	vs_init;		/* number of ring inits */
108 	short	vs_nottaken;		/* number of packets refused */
109 	/* input error rate limiting state */
110 	short	vs_major;		/* recovery major state */
111 	short	vs_minor;		/* recovery minor state */
112 	short	vs_retry;		/* recovery retry count */
113 	short	vs_delayclock;		/* recovery delay clock */
114 	short	vs_delayrange;		/* increasing delay interval */
115 	short	vs_dropped;		/* number of packes tossed in last dt */
116 } vv_softc[NVV];
117 
118 /*
119  * States of vs_iactive.
120  */
121 #define	ACTIVE	1		/* interface should post new receives */
122 #define	PAUSE	0		/* interface should NOT post new receives */
123 #define	OPEN	-1		/* PAUSE and open host relay */
124 
125 /*
126  * Recovery major states.
127  */
128 #define	MODE0	0		/* everything is wonderful */
129 #define	MODE1	1		/* hopefully whatever will go away */
130 #define	MODE2	2		/* drastic measures - open host relay for increasing intervals */
131 
132 vvprobe(reg)
133 	caddr_t reg;
134 {
135 	register int br, cvec;
136 	register struct vvreg *addr = (struct vvreg *)reg;
137 
138 #ifdef lint
139 	br = 0; cvec = br; br = cvec;
140 #endif
141 	/* reset interface, enable, and wait till dust settles */
142 	addr->vvicsr = VV_RST;
143 	addr->vvocsr = VV_RST;
144 	DELAY(10000);
145 	/* generate interrupt by doing 1 word DMA from 0 in uba space!! */
146 	addr->vvocsr = VV_IEN;		/* enable interrupt */
147 	addr->vvoba = 0;		/* low 16 bits */
148 	addr->vvoea = 0;		/* extended bits */
149 	addr->vvowc = -1;		/* for 1 word */
150 	addr->vvocsr |= VV_DEN;		/* start the DMA */
151 	DELAY(100000);
152 	addr->vvocsr = 0;
153 	if (cvec && cvec != 0x200)
154 		cvec -= 4;		/* backup so vector => recieve */
155 	return(1);
156 }
157 
158 /*
159  * Interface exists: make available by filling in network interface
160  * record.  System will initialize the interface when it is ready
161  * to accept packets.
162  */
163 vvattach(ui)
164 	struct uba_device *ui;
165 {
166 	register struct vv_softc *vs = &vv_softc[ui->ui_unit];
167 	register struct sockaddr_in *sin;
168 
169 	vs->vs_if.if_unit = ui->ui_unit;
170 	vs->vs_if.if_name = "vv";
171 	vs->vs_if.if_mtu = VVMTU;
172 	vs->vs_if.if_net = ui->ui_flags;
173 	vs->vs_if.if_host[0] = 0;	/* this will be reset in vvinit() */
174 	sin = (struct sockaddr_in *)&vs->vs_if.if_addr;
175 	sin->sin_family = AF_INET;
176 	sin->sin_addr = if_makeaddr(vs->vs_if.if_net, vs->vs_if.if_host[0]);
177 	sin = (struct sockaddr_in *)&vs->vs_if.if_broadaddr;
178 	sin->sin_family = AF_INET;
179 	sin->sin_addr = if_makeaddr(vs->vs_if.if_net, VV_BROADCAST);
180 	vs->vs_if.if_flags = IFF_BROADCAST;
181 	vs->vs_if.if_init = vvinit;
182 	vs->vs_if.if_output = vvoutput;
183 	vs->vs_if.if_reset = vvreset;
184 	vs->vs_ifuba.ifu_flags = UBA_CANTWAIT | UBA_NEEDBDP | UBA_NEED16;
185 	if_attach(&vs->vs_if);
186 }
187 
188 /*
189  * Reset of interface after UNIBUS reset.
190  * If interface is on specified uba, reset its state.
191  */
192 vvreset(unit, uban)
193 	int unit, uban;
194 {
195 	register struct uba_device *ui;
196 
197 	if (unit >= NVV || (ui = vvinfo[unit]) == 0 || ui->ui_alive == 0 ||
198 	    ui->ui_ubanum != uban)
199 		return;
200 	printf(" vv%d", unit);
201 	vvinit(unit);
202 }
203 
204 /*
205  * Initialization of interface; clear recorded pending
206  * operations, and reinitialize UNIBUS usage.
207  */
208 vvinit(unit)
209 	int unit;
210 {
211 	register struct vv_softc *vs = &vv_softc[unit];
212 	register struct uba_device *ui = vvinfo[unit];
213 	register struct vvreg *addr;
214 	struct sockaddr_in *sin;
215 	int ubainfo, s;
216 	int vvtimeout();
217 
218 	addr = (struct vvreg *)ui->ui_addr;
219 	if (if_ubainit(&vs->vs_ifuba, ui->ui_ubanum,
220 	    sizeof (struct vv_header), (int)btoc(VVMTU)) == 0) {
221 		printf("vv%d: can't initialize\n", unit);
222 		vs->vs_if.if_flags &= ~IFF_UP;
223 		return;
224 	}
225 	if (vv_ticking++ == 0)
226 		timeout(vvtimeout, (caddr_t) 0, VV_FLYWHEEL);
227 	/*
228 	 * Discover our host address and post it
229 	 */
230 	vs->vs_if.if_host[0] = vvidentify(unit);
231 	printf("vv%d: host %d\n", unit, vs->vs_if.if_host[0]);
232 	sin = (struct sockaddr_in *)&vs->vs_if.if_addr;
233 	sin->sin_family = AF_INET;
234 	sin->sin_addr = if_makeaddr(vs->vs_if.if_net, vs->vs_if.if_host[0]);
235 
236 	/*
237 	 * Reset the interface, and join the ring
238 	 */
239 	addr->vvocsr = VV_RST | VV_CPB;		/* clear packet buffer */
240 	addr->vvicsr = VV_RST | VV_CONF;	/* close logical relay */
241 	DELAY(500000);				/* let contacts settle */
242 	vs->vs_init = 0;
243 	vs->vs_dropped = 0;
244 	vs->vs_nottaken = 0;
245 
246 	/*
247 	 * Hang a receive and start any
248 	 * pending writes by faking a transmit complete.
249 	 */
250 	s = splimp();
251 	ubainfo = vs->vs_ifuba.ifu_r.ifrw_info;
252 	addr->vviba = (u_short) ubainfo;
253 	addr->vviea = (u_short) (ubainfo >> 16);
254 	addr->vviwc = -(sizeof (struct vv_header) + VVMTU) >> 1;
255 	addr->vvicsr = VV_IEN | VV_CONF | VV_DEN | VV_ENB;
256 	vs->vs_iactive = ACTIVE;
257 	vs->vs_oactive = 1;
258 	vs->vs_if.if_flags |= IFF_UP;
259 	vvxint(unit);
260 	splx(s);
261 	if_rtinit(&vs->vs_if, RTF_UP);
262 }
263 
264 /*
265  * vvidentify() - return our host address
266  */
267 vvidentify(unit)
268 {
269 	register struct vv_softc *vs = &vv_softc[unit];
270 	register struct uba_device *ui = vvinfo[unit];
271 	register struct vvreg *addr;
272 	struct mbuf *m;
273 	struct vv_header *v;
274 	int ubainfo, retrying, attempts, waitcount, s;
275 
276 	/*
277 	 * Build a multicast message to identify our address
278 	 */
279 	addr = (struct vvreg *)ui->ui_addr;
280 	attempts = 0;		/* total attempts, including bad msg type */
281 	retrying = 0;		/* first time through */
282 	m = m_get(M_DONTWAIT, MT_HEADER);
283 	if (m == 0)
284 		panic("vvinit: can't get mbuf");
285 	m->m_next = 0;
286 	m->m_off = MMINOFF;
287 	m->m_len = sizeof(struct vv_header);
288 	v = mtod(m, struct vv_header *);
289 	v->vh_dhost = VV_BROADCAST;	/* multicast destination address */
290 	v->vh_shost = 0;		/* will be overwritten with ours */
291 	v->vh_version = RING_VERSION;
292 	v->vh_type = RING_WHOAMI;
293 	v->vh_info = 0;
294 	/* map xmit message into uba */
295 	vs->vs_olen =  if_wubaput(&vs->vs_ifuba, m);
296 	if (vs->vs_ifuba.ifu_flags & UBA_NEEDBDP)
297 		UBAPURGE(vs->vs_ifuba.ifu_uba, vs->vs_ifuba.ifu_w.ifrw_bdp);
298 	/*
299 	 * Reset interface, establish Digital Loopback Mode, and
300 	 * send the multicast (to myself) with Input Copy enabled.
301 	 */
302 retry:
303 	ubainfo = vs->vs_ifuba.ifu_r.ifrw_info;
304 	addr->vvicsr = VV_RST;
305 	addr->vviba = (u_short) ubainfo;
306 	addr->vviea = (u_short) (ubainfo >> 16);
307 	addr->vviwc = -(sizeof (struct vv_header) + VVMTU) >> 1;
308 	addr->vvicsr = VV_STE | VV_DEN | VV_ENB | VV_LPB;
309 
310 	/* let flag timers fire so ring will initialize */
311 	DELAY(2000000);
312 
313 	addr->vvocsr = VV_RST | VV_CPB;	/* clear packet buffer */
314 	ubainfo = vs->vs_ifuba.ifu_w.ifrw_info;
315 	addr->vvoba = (u_short) ubainfo;
316 	addr->vvoea = (u_short) (ubainfo >> 16);
317 	addr->vvowc = -((vs->vs_olen + 1) >> 1);
318 	addr->vvocsr = VV_CPB | VV_DEN | VV_INR | VV_ENB;
319 	/*
320 	 * Wait for receive side to finish.
321 	 * Extract source address (which will our own),
322 	 * and post to interface structure.
323 	 */
324 	DELAY(1000);
325 	for (waitcount = 0; (addr->vvicsr & VV_RDY) == 0; waitcount++) {
326 		if (waitcount < 10) {
327 			DELAY(1000);
328 			continue;
329 		}
330 		if (attempts++ >= 10) {
331 			printf("vv%d: can't initialize\n", unit);
332 			printf("vvinit loopwait: icsr = %b\n",
333 				0xffff&(addr->vvicsr), VV_IBITS);
334 			vs->vs_if.if_flags &= ~IFF_UP;
335 			return;
336 		}
337 		goto retry;
338 	}
339 	if (vs->vs_ifuba.ifu_flags & UBA_NEEDBDP)
340 		UBAPURGE(vs->vs_ifuba.ifu_uba, vs->vs_ifuba.ifu_w.ifrw_bdp);
341 	if (vs->vs_ifuba.ifu_xtofree)
342 		m_freem(vs->vs_ifuba.ifu_xtofree);
343 	if (vs->vs_ifuba.ifu_flags & UBA_NEEDBDP)
344 		UBAPURGE(vs->vs_ifuba.ifu_uba, vs->vs_ifuba.ifu_r.ifrw_bdp);
345 	m = if_rubaget(&vs->vs_ifuba, sizeof(struct vv_header), 0);
346 	if (m != NULL)
347 		m_freem(m);
348 	/*
349 	 * Check message type before we believe the source host address
350 	 */
351 	v = (struct vv_header *)(vs->vs_ifuba.ifu_r.ifrw_addr);
352 	if (v->vh_type != RING_WHOAMI)
353 		goto retry;
354 	return(v->vh_shost);
355 }
356 
357 /*
358  * vvtimeout() - called by timer flywheel to monitor input packet
359  * discard rate.  Interfaces getting too many errors are shut
360  * down for a while.  If the condition persists, the interface
361  * is marked down.
362  */
363 vvtimeout(junk)
364 	int junk;
365 {
366 	register struct vv_softc *vs;
367 	register int i;
368 	register struct vvreg *addr;
369 	int ubainfo;
370 
371 	timeout(vvtimeout, (caddr_t) 0, VV_FLYWHEEL);
372 	for (i = 0; i < NVV; i++) {
373 		vs = &vv_softc[i];
374 		addr = (struct vvreg *)vvinfo[i]->ui_addr;
375 		if (vs->vs_if.if_flags & IFF_UP == 0) continue;
376 		switch (vs->vs_major) {
377 
378 		/*
379 		 * MODE0: generally OK, just check error rate
380 		 */
381 		case MODE0:
382 			if (vs->vs_dropped < VV_ERRORTHRESHOLD) {
383 				vs->vs_dropped = 0;
384 				continue;
385 			}
386 			/* suspend reads for a while */
387 			vvtrprintf("vv%d going MODE1 in vvtimeout\n",i);
388 			vs->vs_major = MODE1;
389 			vs->vs_iactive = PAUSE;	/* no new reads */
390 			vs->vs_retry = VV_MODE1ATTEMPTS;
391 			vs->vs_delayclock = VV_MODE1DELAY;
392 			vs->vs_minor = 0;
393 			continue;
394 
395 		/*
396 		 * MODE1: excessive error rate observed
397 		 * Scheme: try simply suspending reads for a
398 		 * short while a small number of times
399 		 */
400 		case MODE1:
401 			if (vs->vs_delayclock > 0) {
402 				vs->vs_delayclock--;
403 				continue;
404 			}
405 			switch (vs->vs_minor) {
406 
407 			case 0:				/* reenable reads */
408 				vvtrprintf("vv%d M1m0\n",i);
409 				vs->vs_dropped = 0;
410 				vs->vs_iactive = ACTIVE;
411 				vs->vs_minor = 1;	/* next state */
412 				ubainfo = vs->vs_ifuba.ifu_r.ifrw_info;
413 				addr->vviba = (u_short) ubainfo;
414 				addr->vviea = (u_short) (ubainfo >> 16);
415 				addr->vviwc =
416 				  -(sizeof (struct vv_header) + VVMTU) >> 1;
417 				addr->vvicsr = VV_RST | VV_CONF;
418 				addr->vvicsr |= VV_IEN | VV_DEN | VV_ENB;
419 				continue;
420 
421 			case 1:				/* see if it worked */
422 				vvtrprintf("vv%d M1m1\n",i);
423 				if (vs->vs_dropped < VV_ERRORTHRESHOLD) {
424 					vs->vs_dropped = 0;
425 					vs->vs_major = MODE0;	/* yeah!! */
426 					continue;
427 				}
428 				if (vs->vs_retry -- > 0) {
429 					vs->vs_dropped = 0;
430 					vs->vs_iactive = PAUSE;
431 					vs->vs_delayclock = VV_MODE1DELAY;
432 					vs->vs_minor = 0; /* recheck */
433 					continue;
434 				}
435 				vs->vs_major = MODE2;
436 				vs->vs_minor = 0;
437 				vs->vs_dropped = 0;
438 				vs->vs_iactive = OPEN;
439 				vs->vs_delayrange = VV_MODE2DELAY;
440 				vs->vs_delayclock = VV_MODE2DELAY;
441 				/* fall thru ... */
442 			}
443 
444 		/*
445 		 * MODE2: simply ignoring traffic didn't relieve condition
446 		 * Scheme: open host relay for intervals linearly
447 		 * increasing up to some maximum of a several minutes.
448 		 * This allows broken networks to return to operation
449 		 * without rebooting.
450 		 */
451 		case MODE2:
452 			if (vs->vs_delayclock > 0) {
453 				vs->vs_delayclock--;
454 				continue;
455 			}
456 			switch (vs->vs_minor) {
457 
458 			case 0:		/* close relay and reenable reads */
459 				vvtrprintf("vv%d M2m0\n",i);
460 				vs->vs_dropped = 0;
461 				vs->vs_iactive = ACTIVE;
462 				vs->vs_minor = 1;	/* next state */
463 				ubainfo = vs->vs_ifuba.ifu_r.ifrw_info;
464 				addr->vviba = (u_short) ubainfo;
465 				addr->vviea = (u_short) (ubainfo >> 16);
466 				addr->vviwc =
467 				  -(sizeof (struct vv_header) + VVMTU) >> 1;
468 				addr->vvicsr = VV_RST | VV_CONF;
469 				addr->vvicsr |= VV_IEN | VV_DEN | VV_ENB;
470 				continue;
471 
472 			case 1:				/* see if it worked */
473 				vvtrprintf("vv%d M2m1\n",i);
474 				if (vs->vs_dropped < VV_ERRORTHRESHOLD) {
475 					vs->vs_dropped = 0;
476 					vs->vs_major = MODE0;	/* yeah!! */
477 					continue;
478 				}
479 				vvtrprintf("vv%d M2m1 ++ delay\n",i);
480 				vs->vs_dropped = 0;
481 				vs->vs_iactive = OPEN;
482 				vs->vs_minor = 0;
483 				if (vs->vs_delayrange < VV_MAXDELAY)
484 					vs->vs_delayrange +=
485 					  (vs->vs_delayrange/2);
486 				vs->vs_delayclock = vs->vs_delayrange;
487 				continue;
488 			}
489 
490 		default:
491 			printf("vv%d: major state screwed\n", i);
492 			vs->vs_if.if_flags &= ~IFF_UP;
493 		}
494 	}
495 }
496 
497 /*
498  * Start or restart output on interface.
499  * If interface is active, this is a retransmit, so just
500  * restuff registers and go.
501  * If interface is not already active, get another datagram
502  * to send off of the interface queue, and map it to the interface
503  * before starting the output.
504  */
505 vvstart(dev)
506 	dev_t dev;
507 {
508         int unit = VVUNIT(dev);
509 	struct uba_device *ui = vvinfo[unit];
510 	register struct vv_softc *vs = &vv_softc[unit];
511 	register struct vvreg *addr;
512 	struct mbuf *m;
513 	int ubainfo;
514 	int dest;
515 
516 	if (vs->vs_oactive)
517 		goto restart;
518 	/*
519 	 * Not already active: dequeue another request
520 	 * and map it to the UNIBUS.  If no more requests,
521 	 * just return.
522 	 */
523 	IF_DEQUEUE(&vs->vs_if.if_snd, m);
524 	if (m == NULL) {
525 		vs->vs_oactive = 0;
526 		return;
527 	}
528 	dest = mtod(m, struct vv_header *)->vh_dhost;
529 	vs->vs_olen = if_wubaput(&vs->vs_ifuba, m);
530 	vs->vs_lastx = dest;
531 restart:
532 	/*
533 	 * Have request mapped to UNIBUS for transmission.
534 	 * Purge any stale data from this BDP, and start the otput.
535 	 */
536 	if (vs->vs_olen > VVMTU + sizeof (struct vvheader)) {
537 		printf("vv%d vs_olen: %d > VVMTU\n", unit, vs->vs_olen);
538 		panic("vvdriver vs_olen botch");
539 	}
540 	if (vs->vs_ifuba.ifu_flags & UBA_NEEDBDP)
541 		UBAPURGE(vs->vs_ifuba.ifu_uba, vs->vs_ifuba.ifu_w.ifrw_bdp);
542 	addr = (struct vvreg *)ui->ui_addr;
543 	ubainfo = vs->vs_ifuba.ifu_w.ifrw_info;
544 	addr->vvoba = (u_short) ubainfo;
545 	addr->vvoea = (u_short) (ubainfo >> 16);
546 	addr->vvowc = -((vs->vs_olen + 1) >> 1);
547 	addr->vvocsr = VV_IEN | VV_CPB | VV_DEN | VV_INR | VV_ENB;
548 	vs->vs_oactive = 1;
549 }
550 
551 /*
552  * VVLNI transmit interrupt
553  * Start another output if more data to send.
554  */
555 vvxint(unit)
556 	int unit;
557 {
558 	register struct uba_device *ui = vvinfo[unit];
559 	register struct vv_softc *vs = &vv_softc[unit];
560 	register struct vvreg *addr;
561 	register int oc;
562 
563 	addr = (struct vvreg *)ui->ui_addr;
564 	oc = 0xffff & (addr->vvocsr);
565 	if (vs->vs_oactive == 0) {
566 		printf("vv%d: stray interrupt vvocsr = %b\n", unit,
567 			oc, VV_OBITS);
568 		return;
569 	}
570 	if (oc &  (VV_OPT | VV_RFS)) {
571 		vs->vs_if.if_collisions++;
572 		if (vs->vs_tries++ < VVRETRY) {
573 			if (oc & VV_OPT)
574 				vs->vs_init++;
575 			if (oc & VV_RFS)
576 				vs->vs_nottaken++;
577 			vvstart(unit);		/* restart this message */
578 			return;
579 		}
580 		if (oc & VV_OPT)
581 			printf("vv%d: output timeout\n");
582 	}
583 	vs->vs_if.if_opackets++;
584 	vs->vs_oactive = 0;
585 	vs->vs_tries = 0;
586 	if (oc & VVXERR) {
587 		vs->vs_if.if_oerrors++;
588 		printf("vv%d: error vvocsr = %b\n", unit, 0xffff & oc,
589 			VV_OBITS);
590 	}
591 	if (vs->vs_ifuba.ifu_xtofree) {
592 		m_freem(vs->vs_ifuba.ifu_xtofree);
593 		vs->vs_ifuba.ifu_xtofree = 0;
594 	}
595 	if (vs->vs_if.if_snd.ifq_head == 0) {
596 		vs->vs_lastx = 256;		/* an invalid address */
597 		return;
598 	}
599 	vvstart(unit);
600 }
601 
602 /*
603  * V2lni interface receiver interrupt.
604  * If input error just drop packet.
605  * Otherwise purge input buffered data path and examine
606  * packet to determine type.  If can't determine length
607  * from type, then have to drop packet.  Othewise decapsulate
608  * packet based on type and pass to type specific higher-level
609  * input routine.
610  */
611 vvrint(unit)
612 	int unit;
613 {
614 	register struct vv_softc *vs = &vv_softc[unit];
615 	struct vvreg *addr = (struct vvreg *)vvinfo[unit]->ui_addr;
616 	register struct vv_header *vv;
617 	register struct ifqueue *inq;
618     	struct mbuf *m;
619 	int ubainfo, len, off;
620 	short resid;
621 
622 	vs->vs_if.if_ipackets++;
623 	/*
624 	 * Purge BDP; drop if input error indicated.
625 	 */
626 	if (vs->vs_ifuba.ifu_flags & UBA_NEEDBDP)
627 		UBAPURGE(vs->vs_ifuba.ifu_uba, vs->vs_ifuba.ifu_r.ifrw_bdp);
628 	if (addr->vvicsr & VVRERR) {
629 		if (vv_logreaderrors)
630 			printf("vv%d: error vvicsr = %b\n", unit,
631 				0xffff&(addr->vvicsr), VV_IBITS);
632 		goto dropit;
633 	}
634 
635 	/*
636 	 * Get packet length from word count residue
637 	 *
638 	 * Compute header offset if trailer protocol
639 	 *
640 	 * Pull packet off interface.  Off is nonzero if packet
641 	 * has trailing header; if_rubaget will then force this header
642 	 * information to be at the front.  The vh_info field
643 	 * carries the offset to the trailer data in trailer
644 	 * format packets.
645 	 */
646 	vv = (struct vv_header *)(vs->vs_ifuba.ifu_r.ifrw_addr);
647 	vvtracehdr("vi", vv);
648 	resid = addr->vviwc;
649 	if (resid)
650 		resid |= 0176000;		/* ugly!!!! */
651 	len = (((sizeof (struct vv_header) + VVMRU) >> 1) + resid) << 1;
652 	len -= sizeof(struct vv_header);
653 	if (len > VVMRU || len <= 0)
654 		goto dropit;
655 #define	vvdataaddr(vv, off, type)	((type)(((caddr_t)((vv)+1)+(off))))
656 	if (vv_dotrailer && vv->vh_type >= RING_IPTrailer &&
657 	     vv->vh_type < RING_IPTrailer+RING_IPNTrailer){
658 		off = (vv->vh_type - RING_IPTrailer) * 512;
659 		if (off > VVMTU)
660 			goto dropit;
661 		vv->vh_type = *vvdataaddr(vv, off, u_short *);
662 		resid = *(vvdataaddr(vv, off+2, u_short *));
663 		if (off + resid > len)
664 			goto dropit;
665 		len = off + resid;
666 	} else
667 		off = 0;
668 	if (len == 0)
669 		goto dropit;
670 	m = if_rubaget(&vs->vs_ifuba, len, off);
671 	if (m == NULL)
672 		goto dropit;
673 	if (off) {
674 		m->m_off += 2 * sizeof(u_short);
675 		m->m_len -= 2 * sizeof(u_short);
676 	}
677 
678 	/*
679 	 * Demultiplex on packet type
680 	 */
681 	switch (vv->vh_type) {
682 
683 #ifdef INET
684 	case RING_IP:
685 		schednetisr(NETISR_IP);
686 		inq = &ipintrq;
687 		break;
688 #endif
689 	default:
690 		printf("vv%d: unknown pkt type 0x%x\n", unit, vv->vh_type);
691 		m_freem(m);
692 		goto setup;
693 	}
694 	if (IF_QFULL(inq)) {
695 		IF_DROP(inq);
696 		m_freem(m);
697 	} else
698 		IF_ENQUEUE(inq, m);
699 setup:
700 	/*
701 	 * Check the error rate and start recovery if needed
702 	 * this has to go here since the timer flywheel runs at
703 	 * a lower ipl and never gets a chance to change the mode
704 	 */
705 	if (vs->vs_major == MODE0 && vs->vs_dropped > VV_ERRORTHRESHOLD) {
706 		vvtrprintf("vv%d going MODE1 in vvrint\n",unit);
707 		vs->vs_major = MODE1;
708 		vs->vs_iactive = PAUSE;		/* no new reads */
709 		vs->vs_retry = VV_MODE1ATTEMPTS;
710 		vs->vs_delayclock = VV_MODE1DELAY;
711 		vs->vs_minor = 0;
712 		vs->vs_dropped = 0;
713 	}
714 	switch (vs->vs_iactive) {
715 
716 	case ACTIVE:		/* Restart the read for next packet */
717 		ubainfo = vs->vs_ifuba.ifu_r.ifrw_info;
718 		addr->vviba = (u_short) ubainfo;
719 		addr->vviea = (u_short) (ubainfo >> 16);
720 		addr->vviwc = -(sizeof (struct vv_header) + VVMTU) >> 1;
721 		addr->vvicsr = VV_RST | VV_CONF;
722 		addr->vvicsr |= VV_IEN | VV_DEN | VV_ENB;
723 		return;
724 
725 	case PAUSE:		/* requested to not start any new reads */
726 		vs->vs_dropped = 0;
727 		return;
728 
729 	case OPEN:		/* request to open host relay */
730 		vs->vs_dropped = 0;
731 		addr->vvicsr = 0;
732 		return;
733 
734 	default:
735 		printf("vv%d: vs_iactive = %d\n", unit, vs->vs_iactive);
736 		return;
737 	}
738 	/*
739 	 * Drop packet on floor -- count them!!
740 	 */
741 dropit:
742 	vs->vs_if.if_ierrors++;
743 	vs->vs_dropped++;
744 	/*
745 	printf("vv%d: error vvicsr = %b\n", unit,
746 		0xffff&(addr->vvicsr), VV_IBITS);
747 	*/
748 	goto setup;
749 }
750 
751 /*
752  * V2lni output routine.
753  * Encapsulate a packet of type family for the local net.
754  * Use trailer local net encapsulation if enough data in first
755  * packet leaves a multiple of 512 bytes of data in remainder.
756  */
757 vvoutput(ifp, m0, dst)
758 	struct ifnet *ifp;
759 	struct mbuf *m0;
760 	struct sockaddr *dst;
761 {
762 	register struct mbuf *m = m0;
763 	register struct vv_header *vv;
764 	register int off;
765 	int type, dest, s, error;
766 
767 	switch (dst->sa_family) {
768 
769 #ifdef INET
770 	case AF_INET: {
771 		dest = ((struct sockaddr_in *)dst)->sin_addr.s_addr;
772 		if ((dest = in_lnaof(*((struct in_addr *)&dest))) >= 0x100) {
773 			error = EPERM;
774 			goto bad;
775 		}
776 		off = ntohs((u_short)mtod(m, struct ip *)->ip_len) - m->m_len;
777 		if (vv_dotrailer && off > 0 && (off & 0x1ff) == 0 &&
778 		    m->m_off >= MMINOFF + 2 * sizeof (u_short)) {
779 			type = RING_IPTrailer + (off>>9);
780 			m->m_off -= 2 * sizeof (u_short);
781 			m->m_len += 2 * sizeof (u_short);
782 			*mtod(m, u_short *) = RING_IP;
783 			*(mtod(m, u_short *) + 1) = m->m_len;
784 			goto gottrailertype;
785 		}
786 		type = RING_IP;
787 		off = 0;
788 		goto gottype;
789 		}
790 #endif
791 	default:
792 		printf("vv%d: can't handle af%d\n", ifp->if_unit,
793 			dst->sa_family);
794 		error = EAFNOSUPPORT;
795 		goto bad;
796 	}
797 
798 gottrailertype:
799 	/*
800 	 * Packet to be sent as trailer: move first packet
801 	 * (control information) to end of chain.
802 	 */
803 	while (m->m_next)
804 		m = m->m_next;
805 	m->m_next = m0;
806 	m = m0->m_next;
807 	m0->m_next = 0;
808 	m0 = m;
809 gottype:
810 	/*
811 	 * Add local net header.  If no space in first mbuf,
812 	 * allocate another.
813 	 */
814 	if (m->m_off > MMAXOFF ||
815 	    MMINOFF + sizeof (struct vv_header) > m->m_off) {
816 		m = m_get(M_DONTWAIT, MT_HEADER);
817 		if (m == NULL) {
818 			error = ENOBUFS;
819 			goto bad;
820 		}
821 		m->m_next = m0;
822 		m->m_off = MMINOFF;
823 		m->m_len = sizeof (struct vv_header);
824 	} else {
825 		m->m_off -= sizeof (struct vv_header);
826 		m->m_len += sizeof (struct vv_header);
827 	}
828 	vv = mtod(m, struct vv_header *);
829 	vv->vh_shost = ifp->if_host[0];
830 	vv->vh_dhost = dest;
831 	vv->vh_version = RING_VERSION;
832 	vv->vh_type = type;
833 	vv->vh_info = off;
834 	vvtracehdr("vo", vv);
835 
836 	/*
837 	 * Queue message on interface, and start output if interface
838 	 * not yet active.
839 	 */
840 	s = splimp();
841 	if (IF_QFULL(&ifp->if_snd)) {
842 		IF_DROP(&ifp->if_snd);
843 		error = ENOBUFS;
844 		goto qfull;
845 	}
846 	IF_ENQUEUE(&ifp->if_snd, m);
847 	if (vv_softc[ifp->if_unit].vs_oactive == 0)
848 		vvstart(ifp->if_unit);
849 	splx(s);
850 	return (0);
851 qfull:
852 	m0 = m;
853 	splx(s);
854 bad:
855 	m_freem(m0);
856 	return(error);
857 }
858 
859 /*
860  * vvprt_hdr(s, v) print the local net header in "v"
861  * 	with title is "s"
862  */
863 vvprt_hdr(s, v)
864 	char *s;
865 	register struct vv_header *v;
866 {
867 	printf("%s: dsvti: 0x%x 0x%x 0x%x 0x%x 0x%x\n",
868 		s,
869 		0xff & (int)(v->vh_dhost), 0xff & (int)(v->vh_shost),
870 		0xff & (int)(v->vh_version), 0xff & (int)(v->vh_type),
871 		0xffff & (int)(v->vh_info));
872 }
873 
874 /*
875  * print "l" hex bytes starting at "s"
876  */
877 vvprt_hex(s, l)
878 	char *s;
879 	int l;
880 {
881 	register int i;
882 	register int z;
883 
884 	for (i=0 ; i < l; i++) {
885 		z = 0xff & (int)(*(s + i));
886 		printf("%c%c ",
887 		"0123456789abcdef"[(z >> 4) & 0x0f],
888 		"0123456789abcdef"[z & 0x0f]
889 		);
890 	}
891 }
892