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