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