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