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