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