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