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