|
|
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.