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