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