xref: /csrg-svn/sys/vax/if/if_vv.c (revision 7240)
1 /*	if_vv.c	4.5	82/06/20	*/
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 
116 	vs->vs_if.if_unit = ui->ui_unit;
117 	vs->vs_if.if_name = "vv";
118 	vs->vs_if.if_mtu = VVMTU;
119 	vs->vs_if.if_net = ui->ui_flags;
120 	vs->vs_if.if_host[0] = 0;	/* this will be reset in vvinit() */
121 
122 	sin = (struct sockaddr_in *)&vs->vs_if.if_addr;
123 	sin->sin_family = AF_INET;
124 	sin->sin_addr = if_makeaddr(vs->vs_if.if_net, vs->vs_if.if_host[0]);
125 
126 	sin = (struct sockaddr_in *)&vs->vs_if.if_broadaddr;
127 	sin->sin_family = AF_INET;
128 	sin->sin_addr = if_makeaddr(vs->vs_if.if_net, VV_BROADCAST);
129 	vs->vs_if.if_flags = IFF_BROADCAST;
130 
131 	vs->vs_if.if_init = vvinit;
132 	vs->vs_if.if_output = vvoutput;
133 	vs->vs_if.if_ubareset = vvreset;
134 	vs->vs_ifuba.ifu_flags = UBA_NEEDBDP | UBA_NEED16;
135 	if_attach(&vs->vs_if);
136 }
137 
138 /*
139  * Reset of interface after UNIBUS reset.
140  * If interface is on specified uba, reset its state.
141  */
142 vvreset(unit, uban)
143 	int unit, uban;
144 {
145 	register struct uba_device *ui;
146 
147 	if (unit >= NVV || (ui = vvinfo[unit]) == 0 || ui->ui_alive == 0 ||
148 	    ui->ui_ubanum != uban)
149 		return;
150 	printf(" vv%d", unit);
151 	vvinit(unit);
152 }
153 
154 /*
155  * Initialization of interface; clear recorded pending
156  * operations, and reinitialize UNIBUS usage.
157  */
158 vvinit(unit)
159 	int unit;
160 {
161 	register struct vv_softc *vs = &vv_softc[unit];
162 	register struct uba_device *ui = vvinfo[unit];
163 	register struct vvreg *addr;
164 	struct sockaddr_in *sin;
165 	struct mbuf *m;
166 	struct vv_header *v;
167 	int ubainfo, retrying, attempts, waitcount, s;
168 
169 	if (if_ubainit(&vs->vs_ifuba, ui->ui_ubanum,
170 	    sizeof (struct vv_header), (int)btoc(VVMTU)) == 0) {
171 		printf("vv%d: can't initialize\n", unit);
172 		vs->vs_ifuba.if_flags &= ~IFF_UP;
173 		return;
174 	}
175 	addr = (struct vvreg *)ui->ui_addr;
176 
177 #ifdef AUTOIDENTIFY
178 	/*
179 	 * Build a multicast message to identify our address
180 	 */
181 	attempts = 0;		/* total attempts, including bad msg type */
182 top:
183 	retrying = 0;		/* first time through */
184 	m = m_get(M_DONTWAIT);
185 	if (m == 0)
186 		panic("vvinit: can't get mbuf");
187 	m->m_next = 0;
188 	m->m_off = MMINOFF;
189 	m->m_len = sizeof(struct vv_header);
190 
191 	v = mtod(m, struct vv_header *);
192 	v->vh_dhost = 0;		/* multicast destination address */
193 	v->vh_shost = 0;		/* will be overwritten with ours */
194 	v->vh_version = RING_VERSION;
195 	v->vh_type = RING_WHOAMI;
196 	v->vh_info = 0;
197 
198 	/*
199 	 * Reset interface, establish Digital Loopback Mode, and
200 	 * send the multicast (to myself) with Input Copy enabled.
201 	 */
202 retry:
203 	ubainfo = vs->vs_ifuba.ifu_r.ifrw_info;
204 	addr->vvicsr = VV_RST;
205 	addr->vviba = (u_short) ubainfo;
206 	addr->vviea = (u_short) (ubainfo >> 16);
207 	addr->vviwc = -(sizeof (struct vv_header) + VVMTU) >> 1;
208 	addr->vvicsr = VV_STE | VV_DEN | VV_ENB | VV_LPB;
209 	/* map xmit message into uba if not already there */
210 	if (!retrying)
211 		vs->vs_olen =  if_wubaput(&vs->vs_ifuba, m);
212 	if (vs->vs_ifuba.ifu_flags & UBA_NEEDBDP)
213 		UBAPURGE(vs->vs_ifuba.ifu_uba, vs->vs_ifuba.ifu_w.ifrw_bdp);
214 	addr->vvocsr = VV_RST | VV_CPB;	/* clear packet buffer */
215 	ubainfo = vs->vs_ifuba.ifu_w.ifrw_info;
216 	addr->vvoba = (u_short) ubainfo;
217 	addr->vvoea = (u_short) (ubainfo >> 16);
218 	addr->vvowc = -((vs->vs_olen + 1) >> 1);
219 	addr->vvocsr = VV_CPB | VV_DEN | VV_INR | VV_ENB;
220 
221 	/*
222 	 * Wait for receive side to finish.
223 	 * Extract source address (which will our own),
224 	 * and post to interface structure.
225 	 */
226 	DELAY(1000);
227 	for (waitcount = 0; ((addr->vvicsr) & VV_RDY) == 0; waitcount++) {
228 		if (waitcount < 10)
229 			DELAY(1000);
230 		else {
231 			if (attempts++ < 10)s
232 				goto retry;
233 			else {
234 				printf("vv%d: can't initialize\n", unit);
235 				printf("vvinit loopwait: icsr = %b\n",
236 					0xffff&(addr->vvicsr),VV_IBITS);
237 				vs->vs_ifuba.if_flags &= ~IFF_UP;
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 	vs->vs_ifuba.if_flags |= IFF_UP;
292 	vvxint(unit);
293 	splx(s);
294 	if_rtinit(&vs->vs_if, RTF_UP);
295 }
296 
297 /*
298  * Start or restart output on interface.
299  * If interface is not already active, get another datagram
300  * to send off of the interface queue, and map it to the interface
301  * before starting the output.
302  */
303 vvstart(dev)
304 	dev_t dev;
305 {
306         int unit = VVUNIT(dev);
307 	struct uba_device *ui = vvinfo[unit];
308 	register struct vv_softc *vs = &vv_softc[unit];
309 	register struct vvreg *addr;
310 	struct mbuf *m;
311 	int ubainfo;
312 	int dest;
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 
359 	addr = (struct vvreg *)ui->ui_addr;
360 	oc = 0xffff & (addr->vvocsr);
361 	if (vs->vs_oactive == 0) {
362 		printf("vv%d: stray interrupt vvocsr = %b\n", unit,
363 			oc, VV_OBITS);
364 		return;
365 	}
366 	if (oc &  (VV_OPT | VV_RFS)) {
367 		if (++(vs->vs_tries) < VVRETRY) {
368 			if (oc & VV_OPT)
369 				vs->vs_init++;
370 			if (oc & VV_RFS)
371 				vs->vs_nottaken++;
372 			addr->vvocsr = VV_IEN | VV_ENB | VV_INR;
373 			return;
374 		}
375 		if (oc & VV_OPT)
376 			printf("vv%d: output timeout\n");
377 	}
378 	vs->vs_if.if_opackets++;
379 	vs->vs_oactive = 0;
380 	vs->vs_tries = 0;
381 	if (oc & VVXERR) {
382 		vs->vs_if.if_oerrors++;
383 		printf("vv%d: error vvocsr = %b\n", unit, 0xffff & oc,
384 			VV_OBITS);
385 	}
386 	if (vs->vs_ifuba.ifu_xtofree) {
387 		m_freem(vs->vs_ifuba.ifu_xtofree);
388 		vs->vs_ifuba.ifu_xtofree = 0;
389 	}
390 	if (vs->vs_if.if_snd.ifq_head == 0) {
391 		vs->vs_lastx = 0;
392 		return;
393 	}
394 	vvstart(unit);
395 }
396 
397 /*
398  * V2lni interface receiver interrupt.
399  * If input error just drop packet.
400  * Otherwise purge input buffered data path and examine
401  * packet to determine type.  If can't determine length
402  * from type, then have to drop packet.  Othewise decapsulate
403  * packet based on type and pass to type specific higher-level
404  * input routine.
405  */
406 vvrint(unit)
407 	int unit;
408 {
409 	register struct vv_softc *vs = &vv_softc[unit];
410 	struct vvreg *addr = (struct vvreg *)vvinfo[unit]->ui_addr;
411 	register struct vv_header *vv;
412 	register struct ifqueue *inq;
413     	struct mbuf *m;
414 	int ubainfo, len, off;
415 
416 	vs->vs_if.if_ipackets++;
417 	/*
418 	 * Purge BDP; drop if input error indicated.
419 	 */
420 	if (vs->vs_ifuba.ifu_flags & UBA_NEEDBDP)
421 		UBAPURGE(vs->vs_ifuba.ifu_uba, vs->vs_ifuba.ifu_r.ifrw_bdp);
422 	if (addr->vvicsr & VVRERR) {
423 		vs->vs_if.if_ierrors++;
424 		printf("vv%d: error vvicsr = %b\n", unit,
425 			0xffff&(addr->vvicsr), VV_IBITS);
426 		goto setup;
427 	}
428 	off = 0;
429 	len = 0;
430 	vv = (struct vv_header *)(vs->vs_ifuba.ifu_r.ifrw_addr);
431 	/*
432 	 * Demultiplex on packet type and deal with oddities of
433 	 * trailer protocol format
434 	 */
435 	switch (vv->vh_type) {
436 
437 #ifdef INET
438 	case RING_IP:
439 		len = htons((u_short)((struct ip *) vv)->ip_len);
440 		schednetisr(NETISR_IP);
441 		inq = &ipintrq;
442 		break;
443 #endif
444 	default:
445 		printf("vv%d: unknown pkt type 0x%x\n", unit, vv->vh_type);
446 		goto setup;
447 	}
448 	if (len == 0)
449 		goto setup;
450 	/*
451 	 * Pull packet off interface.  Off is nonzero if packet
452 	 * has trailing header; if_rubaget will then force this header
453 	 * information to be at the front, but we still have to drop
454 	 * the two-byte type which is at the front of any trailer data.
455 	 */
456 	m = if_rubaget(&vs->vs_ifuba, len, off);
457 	if (m == 0)
458 		goto setup;
459 	IF_ENQUEUE(inq, m);
460 
461 setup:
462 	/*
463 	 * Reset for next packet.
464 	 */
465 	ubainfo = vs->vs_ifuba.ifu_r.ifrw_info;
466 	addr->vviba = (u_short) ubainfo;
467 	addr->vviea = (u_short) (ubainfo >> 16);
468 	addr->vviwc = -(sizeof (struct vv_header) + VVMTU) >> 1;
469 	addr->vvicsr = VV_RST | VV_CONF;
470 	addr->vvicsr |= VV_IEN | VV_DEN | VV_ENB;
471 
472 }
473 
474 /*
475  * V2lni output routine.
476  * Encapsulate a packet of type family for the local net.
477  * Use trailer local net encapsulation if enough data in first
478  * packet leaves a multiple of 512 bytes of data in remainder.
479  */
480 vvoutput(ifp, m0, dst)
481 	struct ifnet *ifp;
482 	struct mbuf *m0;
483 	struct sockaddr *dst;
484 {
485 	register struct mbuf *m = m0;
486 	register struct vv_header *vv;
487 	int type, dest, s;
488 
489 	switch (dst->sa_family) {
490 
491 #ifdef INET
492 	case AF_INET: {
493 		register struct ip *ip = mtod(m0, struct ip *);
494 		int off;
495 
496 		dest = ip->ip_dst.s_addr >> 24;
497 		type = RING_IP;
498 		off = 0;
499 		goto gottype;
500 		}
501 #endif
502 	default:
503 		printf("vv%d: can't handle af%d\n", ifp->if_unit,
504 			dst->sa_family);
505 		m_freem(m0);
506 		return (0);
507 	}
508 
509 gottrailertype:
510 	/*
511 	 * Packet to be sent as trailer: move first packet
512 	 * (control information) to end of chain.
513 	 */
514 	while (m->m_next)
515 		m = m->m_next;
516 	m->m_next = m0;
517 	m = m0->m_next;
518 	m0->m_next = 0;
519 	m0 = m;
520 
521 gottype:
522 	/*
523 	 * Add local net header.  If no space in first mbuf,
524 	 * allocate another.
525 	 */
526 	if (m->m_off > MMAXOFF ||
527 	    MMINOFF + sizeof (struct vv_header) > m->m_off) {
528 		m = m_get(M_DONTWAIT);
529 		if (m == 0) {
530 			m_freem(m0);
531 			return (0);
532 		}
533 		m->m_next = m0;
534 		m->m_off = MMINOFF;
535 		m->m_len = sizeof (struct vv_header);
536 	} else {
537 		m->m_off -= sizeof (struct vv_header);
538 		m->m_len += sizeof (struct vv_header);
539 	}
540 	vv = mtod(m, struct vv_header *);
541 	vv->vh_shost = ifp->if_host[0];
542 	vv->vh_dhost = dest;
543 	vv->vh_version = RING_VERSION;
544 	vv->vh_type = type;
545 	vv->vh_info = m->m_len;
546 
547 	/*
548 	 * Queue message on interface, and start output if interface
549 	 * not yet active.
550 	 */
551 	s = splimp();
552 	IF_ENQUEUE(&ifp->if_snd, m);
553 	if (vv_softc[ifp->if_unit].vs_oactive == 0)
554 		vvstart(ifp->if_unit);
555 	splx(s);
556 	return (1);
557 }
558 
559 #ifdef notdef
560 /*
561  * vvprt_hdr(s, v) print the local net header in "v"
562  * 	with title is "s"
563  */
564 vvprt_hdr(s, v)
565 	char *s;
566 	register struct vv_header *v;
567 {
568 	printf("%s: dsvti: 0x%x 0x%x 0x%x 0x%x 0x%x\n",
569 		s,
570 		0xff & (int)(v->vh_dhost), 0xff & (int)(v->vh_shost),
571 		0xff & (int)(v->vh_version), 0xff & (int)(v->vh_type),
572 		0xffff & (int)(v->vh_info));
573 }
574 
575 /*
576  * print "l" hex bytes starting at "s"
577  */
578 vvprt_hex(s, l)
579 	char *s;
580 	int l;
581 {
582 	register int i;
583 	register int z;
584 
585 	for (i=0 ; i < l; i++) {
586 		z = 0xff & (int)(*(s + i));
587 		printf("%c%c ",
588 		"0123456789abcdef"[(z >> 4) & 0x0f],
589 		"0123456789abcdef"[z & 0x0f]
590 		);
591 	}
592 }
593 #endif
594