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