xref: /csrg-svn/sys/vax/if/if_vv.c (revision 7165)
1 /*	if_vv.c	4.3	82/06/13	*/
2 
3 /*
4  * Proteon 10 Meg Ring Driver.
5  * This device is called "vv" because its "real name",
6  * V2LNI won't work if shortened to the obvious "v2".
7  * Hence the subterfuge.
8  */
9 #include "../h/param.h"
10 #include "../h/systm.h"
11 #include "../h/mbuf.h"
12 #include "../h/pte.h"
13 #include "../h/buf.h"
14 #include "../h/protosw.h"
15 #include "../h/socket.h"
16 #include "../h/ubareg.h"
17 #include "../h/ubavar.h"
18 #include "../h/cpu.h"
19 #include "../h/mtpr.h"
20 #include "../h/vmmac.h"
21 #include "../net/in.h"
22 #include "../net/in_systm.h"
23 #include "../net/if.h"
24 #include "../net/if_vv.h"
25 #include "../net/if_uba.h"
26 #include "../net/ip.h"
27 #include "../net/ip_var.h"
28 #include "../net/route.h"
29 
30 #include "vv.h"
31 
32 /*
33  * N.B. - if WIRECENTER is defined wrong, it can well break
34  * the hardware!!
35  */
36 #undef AUTOIDENTIFY
37 #define	WIRECENTER
38 
39 #ifdef WIRECENTER
40 #define	VV_CONF	VV_HEN		/* drive wire center relay */
41 #else
42 #define	VV_CONF	VV_STE		/* allow operation without wire center */
43 #endif
44 
45 #define	VVMTU	(1024+512)
46 
47 int	vvprobe(), vvattach(), vvrint(), vvxint();
48 struct	uba_device *vvinfo[NVV];
49 u_short vvstd[] = { 0 };
50 struct	uba_driver vvdriver =
51 	{ vvprobe, 0, vvattach, 0, vvstd, "vv", vvinfo };
52 #define	VVUNIT(x)	minor(x)
53 int	vvinit(),vvoutput(),vvreset();
54 
55 /*
56  * Software status of each interface.
57  *
58  * Each interface is referenced by a network interface structure,
59  * vs_if, which the routing code uses to locate the interface.
60  * This structure contains the output queue for the interface, its address, ...
61  * We also have, for each interface, a UBA interface structure, which
62  * contains information about the UNIBUS resources held by the interface:
63  * map registers, buffered data paths, etc.  Information is cached in this
64  * structure for use by the if_uba.c routines in running the interface
65  * efficiently.
66  */
67 struct	vv_softc {
68 	struct	ifnet vs_if;		/* network-visible interface */
69 	struct	ifuba vs_ifuba;		/* UNIBUS resources */
70 	short	vs_oactive;		/* is output active? */
71 	short	vs_olen;		/* length of last output */
72 	u_short	vs_lastx;		/* last destination address */
73 	short	vs_tries;		/* current retry count */
74 	short	vs_init;		/* number of ring inits */
75 	short	vs_flush;		/* number of flushed packets */
76 	short	vs_nottaken;		/* number of packets refused */
77 } vv_softc[NVV];
78 
79 vvprobe(reg)
80 	caddr_t reg;
81 {
82 	register int br, cvec;
83 	register struct vvreg *addr = (struct vvreg *)reg;
84 
85 #ifdef lint
86 	br = 0; cvec = br; br = cvec;
87 #endif
88 	/* reset interface, enable, and wait till dust settles */
89 	addr->vvicsr = VV_RST;
90 	addr->vvocsr = VV_RST;
91 	DELAY(100000);
92 	/* generate interrupt by doing 1 word DMA from 0 in uba space!! */
93 	addr->vvocsr = VV_IEN;		/* enable interrupt */
94 	addr->vvoba = 0;		/* low 16 bits */
95 	addr->vvoea = 0;		/* extended bits */
96 	addr->vvowc = -1;		/* for 1 word */
97 	addr->vvocsr |= VV_DEN;		/* start the DMA */
98 	DELAY(100000);
99 	addr->vvocsr = 0;
100 	if (cvec && cvec != 0x200)
101 		cvec -= 4;		/* backup so vector => recieve */
102 	return(1);
103 }
104 
105 /*
106  * Interface exists: make available by filling in network interface
107  * record.  System will initialize the interface when it is ready
108  * to accept packets.
109  */
110 vvattach(ui)
111 	struct uba_device *ui;
112 {
113 	register struct vv_softc *vs = &vv_softc[ui->ui_unit];
114 	register struct sockaddr_in *sin;
115 COUNT(VVATTACH);
116 
117 	vs->vs_if.if_unit = ui->ui_unit;
118 	vs->vs_if.if_name = "vv";
119 	vs->vs_if.if_mtu = VVMTU;
120 	vs->vs_if.if_net = ui->ui_flags;
121 	vs->vs_if.if_host[0] = 0;	/* this will be reset in vvinit() */
122 
123 	sin = (struct sockaddr_in *)&vs->vs_if.if_addr;
124 	sin->sin_family = AF_INET;
125 	sin->sin_addr = if_makeaddr(vs->vs_if.if_net, vs->vs_if.if_host[0]);
126 
127 	sin = (struct sockaddr_in *)&vs->vs_if.if_broadaddr;
128 	sin->sin_family = AF_INET;
129 	sin->sin_addr = if_makeaddr(vs->vs_if.if_net, VV_BROADCAST);
130 	vs->vs_if.if_flags = IFF_BROADCAST;
131 
132 	vs->vs_if.if_init = vvinit;
133 	vs->vs_if.if_output = vvoutput;
134 	vs->vs_if.if_ubareset = vvreset;
135 	vs->vs_ifuba.ifu_flags = UBA_NEEDBDP | UBA_NEED16;
136 	if_attach(&vs->vs_if);
137 }
138 
139 /*
140  * Reset of interface after UNIBUS reset.
141  * If interface is on specified uba, reset its state.
142  */
143 vvreset(unit, uban)
144 	int unit, uban;
145 {
146 	register struct uba_device *ui;
147 COUNT(VVRESET);
148 
149 	if (unit >= NVV || (ui = vvinfo[unit]) == 0 || ui->ui_alive == 0 ||
150 	    ui->ui_ubanum != uban)
151 		return;
152 	printf(" vv%d", unit);
153 	vvinit(unit);
154 }
155 
156 /*
157  * Initialization of interface; clear recorded pending
158  * operations, and reinitialize UNIBUS usage.
159  */
160 vvinit(unit)
161 	int unit;
162 {
163 	register struct vv_softc *vs = &vv_softc[unit];
164 	register struct uba_device *ui = vvinfo[unit];
165 	register struct vvreg *addr;
166 	struct sockaddr_in *sin;
167 	struct mbuf *m;
168 	struct vv_header *v;
169 	int ubainfo, retrying, attempts, waitcount, s;
170 
171 	if (if_ubainit(&vs->vs_ifuba, ui->ui_ubanum,
172 	    sizeof (struct vv_header), (int)btoc(VVMTU)) == 0) {
173 		printf("vv%d: can't initialize\n", unit);
174 		return;
175 	}
176 	addr = (struct vvreg *)ui->ui_addr;
177 
178 #ifdef AUTOIDENTIFY
179 	/*
180 	 * Build a multicast message to identify our address
181 	 */
182 	attempts = 0;		/* total attempts, including bad msg type */
183 top:
184 	retrying = 0;		/* first time through */
185 	m = m_get(M_DONTWAIT);
186 	if (m == 0)
187 		panic("vvinit: can't get mbuf");
188 	m->m_next = 0;
189 	m->m_off = MMINOFF;
190 	m->m_len = sizeof(struct vv_header);
191 
192 	v = mtod(m, struct vv_header *);
193 	v->vh_dhost = 0;		/* multicast destination address */
194 	v->vh_shost = 0;		/* will be overwritten with ours */
195 	v->vh_version = RING_VERSION;
196 	v->vh_type = RING_WHOAMI;
197 	v->vh_info = 0;
198 
199 	/*
200 	 * Reset interface, establish Digital Loopback Mode, and
201 	 * send the multicast (to myself) with Input Copy enabled.
202 	 */
203 retry:
204 	ubainfo = vs->vs_ifuba.ifu_r.ifrw_info;
205 	addr->vvicsr = VV_RST;
206 	addr->vviba = (u_short) ubainfo;
207 	addr->vviea = (u_short) (ubainfo >> 16);
208 	addr->vviwc = -(sizeof (struct vv_header) + VVMTU) >> 1;
209 	addr->vvicsr = VV_STE | VV_DEN | VV_ENB | VV_LPB;
210 	/* map xmit message into uba if not already there */
211 	if (!retrying)
212 		vs->vs_olen =  if_wubaput(&vs->vs_ifuba, m);
213 	if (vs->vs_ifuba.ifu_flags & UBA_NEEDBDP)
214 		UBAPURGE(vs->vs_ifuba.ifu_uba, vs->vs_ifuba.ifu_w.ifrw_bdp);
215 	addr->vvocsr = VV_RST | VV_CPB;	/* clear packet buffer */
216 	ubainfo = vs->vs_ifuba.ifu_w.ifrw_info;
217 	addr->vvoba = (u_short) ubainfo;
218 	addr->vvoea = (u_short) (ubainfo >> 16);
219 	addr->vvowc = -((vs->vs_olen + 1) >> 1);
220 	addr->vvocsr = VV_CPB | VV_DEN | VV_INR | VV_ENB;
221 
222 	/*
223 	 * Wait for receive side to finish.
224 	 * Extract source address (which will our own),
225 	 * and post to interface structure.
226 	 */
227 	DELAY(1000);
228 	for (waitcount = 0; ((addr->vvicsr) & VV_RDY) == 0; waitcount++) {
229 		if (waitcount < 10)
230 			DELAY(1000);
231 		else {
232 			if (attempts++ < 10)s
233 				goto retry;
234 			else {
235 				printf("vv%d: can't initialize\n", unit);
236 				printf("vvinit loopwait: icsr = %b\n",
237 					0xffff&(addr->vvicsr),VV_IBITS);
238 				return;
239 			}
240 		}
241 	}
242 
243 	if (vs->vs_ifuba.ifu_flags & UBA_NEEDBDP)
244 		UBAPURGE(vs->vs_ifuba.ifu_uba, vs->vs_ifuba.ifu_w.ifrw_bdp);
245 	if (vs->vs_ifuba.ifu_xtofree)
246 		m_freem(vs->vs_ifuba.ifu_xtofree);
247 	if (vs->vs_ifuba.ifu_flags & UBA_NEEDBDP)
248 		UBAPURGE(vs->vs_ifuba.ifu_uba, vs->vs_ifuba.ifu_r.ifrw_bdp);
249 	m = if_rubaget(&vs->vs_ifuba, sizeof(struct vv_header), 0);
250 	if (m)
251 		m_freem(m);
252 	/*
253 	 * check message type before we believe the source host address
254 	 */
255 	v = (struct vv_header *)(vs->vs_ifuba.ifu_r.ifrw_addr);
256 	if (v->vh_type == RING_WHOAMI)
257 		vs->vs_if.if_host[0] = v->vh_shost;
258 	else
259 		goto top;
260 #else
261 	vs->vs_if.if_host[0] = 24;
262 #endif
263 
264 	printf("vv%d: host %d\n", unit, vs->vs_if.if_host[0]);
265 	sin = (struct sockaddr_in *)&vs->vs_if.if_addr;
266 	sin->sin_family = AF_INET;
267 	sin->sin_addr =
268 	    if_makeaddr(vs->vs_if.if_net, vs->vs_if.if_host[0]);
269 
270 	/*
271 	 * Reset the interface, and join the ring
272 	 */
273 	addr->vvocsr = VV_RST | VV_CPB;		/* clear packet buffer */
274 	addr->vvicsr = VV_RST | VV_CONF;	/* close logical relay */
275 	sleep((caddr_t)&lbolt, PZERO);		/* let contacts settle */
276 	vs->vs_init = 0;
277 	vs->vs_flush = 0;
278 	vs->vs_nottaken = 0;
279 
280 	/*
281 	 * Hang a receive and start any
282 	 * pending writes by faking a transmit complete.
283 	 */
284 	s = splimp();
285 	ubainfo = vs->vs_ifuba.ifu_r.ifrw_info;
286 	addr->vviba = (u_short) ubainfo;
287 	addr->vviea = (u_short) (ubainfo >> 16);
288 	addr->vviwc = -(sizeof (struct vv_header) + VVMTU) >> 1;
289 	addr->vvicsr = VV_IEN | VV_CONF | VV_DEN | VV_ENB;
290 	vs->vs_oactive = 1;
291 	vvxint(unit);
292 	splx(s);
293 	if_rtinit(&vs->vs_if, RTF_UP);
294 }
295 
296 /*
297  * Start or restart output on interface.
298  * If interface is not already active, get another datagram
299  * to send off of the interface queue, and map it to the interface
300  * before starting the output.
301  */
302 vvstart(dev)
303 	dev_t dev;
304 {
305         int unit = VVUNIT(dev);
306 	struct uba_device *ui = vvinfo[unit];
307 	register struct vv_softc *vs = &vv_softc[unit];
308 	register struct vvreg *addr;
309 	struct mbuf *m;
310 	int ubainfo;
311 	int dest;
312 COUNT(VVSTART);
313 
314 	if (vs->vs_oactive)
315 		goto restart;
316 
317 	/*
318 	 * Not already active: dequeue another request
319 	 * and map it to the UNIBUS.  If no more requests,
320 	 * just return.
321 	 */
322 	IF_DEQUEUE(&vs->vs_if.if_snd, m);
323 	if (m == 0) {
324 		vs->vs_oactive = 0;
325 		return;
326 	}
327 	dest = mtod(m, struct vv_header *)->vh_dhost;
328 	vs->vs_olen = if_wubaput(&vs->vs_ifuba, m);
329 	vs->vs_lastx = dest;
330 
331 restart:
332 	/*
333 	 * Have request mapped to UNIBUS for transmission.
334 	 * Purge any stale data from this BDP, and start the otput.
335 	 */
336 	if (vs->vs_ifuba.ifu_flags & UBA_NEEDBDP)
337 		UBAPURGE(vs->vs_ifuba.ifu_uba, vs->vs_ifuba.ifu_w.ifrw_bdp);
338 	addr = (struct vvreg *)ui->ui_addr;
339 	ubainfo = vs->vs_ifuba.ifu_w.ifrw_info;
340 	addr->vvoba = (u_short) ubainfo;
341 	addr->vvoea = (u_short) (ubainfo >> 16);
342 	addr->vvowc = -((vs->vs_olen + 1) >> 1);
343 	addr->vvocsr = VV_IEN | VV_CPB | VV_DEN | VV_INR | VV_ENB;
344 	vs->vs_oactive = 1;
345 }
346 
347 /*
348  * VVLNI transmit interrupt
349  * Start another output if more data to send.
350  */
351 vvxint(unit)
352 	int unit;
353 {
354 	register struct uba_device *ui = vvinfo[unit];
355 	register struct vv_softc *vs = &vv_softc[unit];
356 	register struct vvreg *addr;
357 	register int oc;
358 COUNT(ENXINT);
359 
360 	addr = (struct vvreg *)ui->ui_addr;
361 	oc = 0xffff & (addr->vvocsr);
362 	if (vs->vs_oactive == 0) {
363 		printf("vv%d: stray interrupt vvocsr = %b\n", unit,
364 			oc, VV_OBITS);
365 		return;
366 	}
367 	if (oc &  (VV_OPT | VV_RFS)) {
368 		if (++(vs->vs_tries) < VVRETRY) {
369 			if (oc & VV_OPT)
370 				vs->vs_init++;
371 			if (oc & VV_RFS)
372 				vs->vs_nottaken++;
373 			addr->vvocsr = VV_IEN | VV_ENB | VV_INR;
374 			return;
375 		}
376 		if (oc & VV_OPT)
377 			printf("vv%d: output timeout\n");
378 	}
379 	vs->vs_if.if_opackets++;
380 	vs->vs_oactive = 0;
381 	vs->vs_tries = 0;
382 	if (oc & VVXERR) {
383 		vs->vs_if.if_oerrors++;
384 		printf("vv%d: error vvocsr = %b\n", unit, 0xffff & oc,
385 			VV_OBITS);
386 	}
387 	if (vs->vs_ifuba.ifu_xtofree) {
388 		m_freem(vs->vs_ifuba.ifu_xtofree);
389 		vs->vs_ifuba.ifu_xtofree = 0;
390 	}
391 	if (vs->vs_if.if_snd.ifq_head == 0) {
392 		vs->vs_lastx = 0;
393 		return;
394 	}
395 	vvstart(unit);
396 }
397 
398 /*
399  * V2lni interface receiver interrupt.
400  * If input error just drop packet.
401  * Otherwise purge input buffered data path and examine
402  * packet to determine type.  If can't determine length
403  * from type, then have to drop packet.  Othewise decapsulate
404  * packet based on type and pass to type specific higher-level
405  * input routine.
406  */
407 vvrint(unit)
408 	int unit;
409 {
410 	register struct vv_softc *vs = &vv_softc[unit];
411 	struct vvreg *addr = (struct vvreg *)vvinfo[unit]->ui_addr;
412 	register struct vv_header *vv;
413 	register struct ifqueue *inq;
414     	struct mbuf *m;
415 	int ubainfo, len, off;
416 COUNT(VVRINT);
417 
418 	vs->vs_if.if_ipackets++;
419 	/*
420 	 * Purge BDP; drop if input error indicated.
421 	 */
422 	if (vs->vs_ifuba.ifu_flags & UBA_NEEDBDP)
423 		UBAPURGE(vs->vs_ifuba.ifu_uba, vs->vs_ifuba.ifu_r.ifrw_bdp);
424 	if (addr->vvicsr & VVRERR) {
425 		vs->vs_if.if_ierrors++;
426 		printf("vv%d: error vvicsr = %b\n", unit,
427 			0xffff&(addr->vvicsr), VV_IBITS);
428 		goto setup;
429 	}
430 	off = 0;
431 	len = 0;
432 	vv = (struct vv_header *)(vs->vs_ifuba.ifu_r.ifrw_addr);
433 	/*
434 	 * Demultiplex on packet type and deal with oddities of
435 	 * trailer protocol format
436 	 */
437 	switch (vv->vh_type) {
438 
439 #ifdef INET
440 	case RING_IP:
441 		len = htons((u_short)((struct ip *) vv)->ip_len);
442 		schednetisr(NETISR_IP);
443 		inq = &ipintrq;
444 		break;
445 #endif
446 	default:
447 		printf("vv%d: unknown pkt type 0x%x\n", unit, vv->vh_type);
448 		goto setup;
449 	}
450 	if (len == 0)
451 		goto setup;
452 	/*
453 	 * Pull packet off interface.  Off is nonzero if packet
454 	 * has trailing header; if_rubaget will then force this header
455 	 * information to be at the front, but we still have to drop
456 	 * the two-byte type which is at the front of any trailer data.
457 	 */
458 	m = if_rubaget(&vs->vs_ifuba, len, off);
459 	if (m == 0)
460 		goto setup;
461 	IF_ENQUEUE(inq, m);
462 
463 setup:
464 	/*
465 	 * Reset for next packet.
466 	 */
467 	ubainfo = vs->vs_ifuba.ifu_r.ifrw_info;
468 	addr->vviba = (u_short) ubainfo;
469 	addr->vviea = (u_short) (ubainfo >> 16);
470 	addr->vviwc = -(sizeof (struct vv_header) + VVMTU) >> 1;
471 	addr->vvicsr = VV_RST | VV_CONF;
472 	addr->vvicsr |= VV_IEN | VV_DEN | VV_ENB;
473 
474 }
475 
476 /*
477  * V2lni output routine.
478  * Encapsulate a packet of type family for the local net.
479  * Use trailer local net encapsulation if enough data in first
480  * packet leaves a multiple of 512 bytes of data in remainder.
481  */
482 vvoutput(ifp, m0, dst)
483 	struct ifnet *ifp;
484 	struct mbuf *m0;
485 	struct sockaddr *dst;
486 {
487 	register struct mbuf *m = m0;
488 	register struct vv_header *vv;
489 	int type, dest, s;
490 
491 	switch (dst->sa_family) {
492 
493 #ifdef INET
494 	case AF_INET: {
495 		register struct ip *ip = mtod(m0, struct ip *);
496 		int off;
497 
498 		dest = ip->ip_dst.s_addr >> 24;
499 		type = RING_IP;
500 		off = 0;
501 		goto gottype;
502 		}
503 #endif
504 	default:
505 		printf("vv%d: can't handle af%d\n", ifp->if_unit,
506 			dst->sa_family);
507 		m_freem(m0);
508 		return (0);
509 	}
510 
511 gottrailertype:
512 	/*
513 	 * Packet to be sent as trailer: move first packet
514 	 * (control information) to end of chain.
515 	 */
516 	while (m->m_next)
517 		m = m->m_next;
518 	m->m_next = m0;
519 	m = m0->m_next;
520 	m0->m_next = 0;
521 	m0 = m;
522 
523 gottype:
524 	/*
525 	 * Add local net header.  If no space in first mbuf,
526 	 * allocate another.
527 	 */
528 	if (m->m_off > MMAXOFF ||
529 	    MMINOFF + sizeof (struct vv_header) > m->m_off) {
530 		m = m_get(M_DONTWAIT);
531 		if (m == 0) {
532 			m_freem(m0);
533 			return (0);
534 		}
535 		m->m_next = m0;
536 		m->m_off = MMINOFF;
537 		m->m_len = sizeof (struct vv_header);
538 	} else {
539 		m->m_off -= sizeof (struct vv_header);
540 		m->m_len += sizeof (struct vv_header);
541 	}
542 	vv = mtod(m, struct vv_header *);
543 	vv->vh_shost = ifp->if_host[0];
544 	vv->vh_dhost = dest;
545 	vv->vh_version = RING_VERSION;
546 	vv->vh_type = type;
547 	vv->vh_info = m->m_len;
548 
549 	/*
550 	 * Queue message on interface, and start output if interface
551 	 * not yet active.
552 	 */
553 	s = splimp();
554 	IF_ENQUEUE(&ifp->if_snd, m);
555 	if (vv_softc[ifp->if_unit].vs_oactive == 0)
556 		vvstart(ifp->if_unit);
557 	splx(s);
558 	return (1);
559 }
560 
561 #ifdef notdef
562 /*
563  * vvprt_hdr(s, v) print the local net header in "v"
564  * 	with title is "s"
565  */
566 vvprt_hdr(s, v)
567 	char *s;
568 	register struct vv_header *v;
569 {
570 	printf("%s: dsvti: 0x%x 0x%x 0x%x 0x%x 0x%x\n",
571 		s,
572 		0xff & (int)(v->vh_dhost), 0xff & (int)(v->vh_shost),
573 		0xff & (int)(v->vh_version), 0xff & (int)(v->vh_type),
574 		0xffff & (int)(v->vh_info));
575 }
576 
577 /*
578  * print "l" hex bytes starting at "s"
579  */
580 vvprt_hex(s, l)
581 	char *s;
582 	int l;
583 {
584 	register int i;
585 	register int z;
586 
587 	for (i=0 ; i < l; i++) {
588 		z = 0xff & (int)(*(s + i));
589 		printf("%c%c ",
590 		"0123456789abcdef"[(z >> 4) & 0x0f],
591 		"0123456789abcdef"[z & 0x0f]
592 		);
593 	}
594 }
595 #endif
596