|
|
1.1 ! root 1: /* if_vv.c 6.1 83/07/29 */ ! 2: ! 3: #include "vv.h" ! 4: ! 5: /* ! 6: * Proteon 10 Meg Ring Driver. ! 7: * This device is called "vv" because its "real name", ! 8: * V2LNI won't work if shortened to the obvious "v2". ! 9: * Hence the subterfuge. ! 10: * ! 11: */ ! 12: #include "../machine/pte.h" ! 13: ! 14: #include "../h/param.h" ! 15: #include "../h/systm.h" ! 16: #include "../h/mbuf.h" ! 17: #include "../h/buf.h" ! 18: #include "../h/protosw.h" ! 19: #include "../h/socket.h" ! 20: #include "../h/vmmac.h" ! 21: #include "../h/errno.h" ! 22: #include "../h/time.h" ! 23: #include "../h/kernel.h" ! 24: #include "../h/ioctl.h" ! 25: ! 26: #include "../net/if.h" ! 27: #include "../net/netisr.h" ! 28: #include "../net/route.h" ! 29: ! 30: #include "../netinet/in.h" ! 31: #include "../netinet/in_systm.h" ! 32: #include "../netinet/ip.h" ! 33: #include "../netinet/ip_var.h" ! 34: ! 35: #include "../vax/mtpr.h" ! 36: #include "../vax/cpu.h" ! 37: ! 38: #include "../vaxuba/ubareg.h" ! 39: #include "../vaxuba/ubavar.h" ! 40: ! 41: #include "../vaxif/if_vv.h" ! 42: #include "../vaxif/if_uba.h" ! 43: ! 44: /* ! 45: * N.B. - if WIRECENTER is defined wrong, it can well break ! 46: * the hardware!! ! 47: */ ! 48: #define WIRECENTER ! 49: ! 50: #ifdef WIRECENTER ! 51: #define VV_CONF VV_HEN /* drive wire center relay */ ! 52: #else ! 53: #define VV_CONF VV_STE /* allow operation without wire center */ ! 54: #endif ! 55: ! 56: #define VVMTU (1024+512) ! 57: #define VVMRU (1024+512+16) /* space for trailer */ ! 58: ! 59: int vv_tracehdr = 0, /* 1 => trace headers (slowly!!) */ ! 60: vv_tracetimeout = 1; /* 1 => trace input error-rate limiting */ ! 61: vv_logreaderrors = 0; /* 1 => log all read errors */ ! 62: ! 63: #define vvtracehdr if (vv_tracehdr) vvprt_hdr ! 64: #define vvtrprintf if (vv_tracetimeout) printf ! 65: ! 66: int vv_ticking = 0; /* error flywheel is running */ ! 67: ! 68: /* ! 69: * Interval in HZ - 50 msec. ! 70: * N.B. all times below are in units of flywheel ticks ! 71: */ ! 72: #define VV_FLYWHEEL 3 ! 73: #define VV_ERRORTHRESHOLD 100 /* errors/flywheel-interval */ ! 74: #define VV_MODE1ATTEMPTS 10 /* number mode 1 retries */ ! 75: #define VV_MODE1DELAY 2 /* period interface is PAUSEd - 100ms */ ! 76: #define VV_MODE2DELAY 4 /* base interval host relay is off - 200ms */ ! 77: #define VV_MAXDELAY 6400 /* max interval host relay is off - 2 minutes */ ! 78: ! 79: int vvprobe(), vvattach(), vvrint(), vvxint(); ! 80: struct uba_device *vvinfo[NVV]; ! 81: u_short vvstd[] = { 0 }; ! 82: struct uba_driver vvdriver = ! 83: { vvprobe, 0, vvattach, 0, vvstd, "vv", vvinfo }; ! 84: #define VVUNIT(x) minor(x) ! 85: int vvinit(),vvioctl(),vvoutput(),vvreset(); ! 86: ! 87: /* ! 88: * Software status of each interface. ! 89: * ! 90: * Each interface is referenced by a network interface structure, ! 91: * vs_if, which the routing code uses to locate the interface. ! 92: * This structure contains the output queue for the interface, its address, ... ! 93: * We also have, for each interface, a UBA interface structure, which ! 94: * contains information about the UNIBUS resources held by the interface: ! 95: * map registers, buffered data paths, etc. Information is cached in this ! 96: * structure for use by the if_uba.c routines in running the interface ! 97: * efficiently. ! 98: */ ! 99: struct vv_softc { ! 100: struct ifnet vs_if; /* network-visible interface */ ! 101: struct ifuba vs_ifuba; /* UNIBUS resources */ ! 102: short vs_oactive; /* is output active */ ! 103: short vs_iactive; /* is input active */ ! 104: short vs_olen; /* length of last output */ ! 105: u_short vs_lastx; /* last destination address */ ! 106: short vs_tries; /* transmit current retry count */ ! 107: short vs_init; /* number of ring inits */ ! 108: short vs_nottaken; /* number of packets refused */ ! 109: /* input error rate limiting state */ ! 110: short vs_major; /* recovery major state */ ! 111: short vs_minor; /* recovery minor state */ ! 112: short vs_retry; /* recovery retry count */ ! 113: short vs_delayclock; /* recovery delay clock */ ! 114: short vs_delayrange; /* increasing delay interval */ ! 115: short vs_dropped; /* number of packes tossed in last dt */ ! 116: } vv_softc[NVV]; ! 117: ! 118: /* ! 119: * States of vs_iactive. ! 120: */ ! 121: #define ACTIVE 1 /* interface should post new receives */ ! 122: #define PAUSE 0 /* interface should NOT post new receives */ ! 123: #define OPEN -1 /* PAUSE and open host relay */ ! 124: ! 125: /* ! 126: * Recovery major states. ! 127: */ ! 128: #define MODE0 0 /* everything is wonderful */ ! 129: #define MODE1 1 /* hopefully whatever will go away */ ! 130: #define MODE2 2 /* drastic measures - open host relay for increasing intervals */ ! 131: ! 132: vvprobe(reg) ! 133: caddr_t reg; ! 134: { ! 135: register int br, cvec; ! 136: register struct vvreg *addr = (struct vvreg *)reg; ! 137: ! 138: #ifdef lint ! 139: br = 0; cvec = br; br = cvec; vvrint(0); ! 140: #endif ! 141: /* reset interface, enable, and wait till dust settles */ ! 142: addr->vvicsr = VV_RST; ! 143: addr->vvocsr = VV_RST; ! 144: DELAY(10000); ! 145: /* generate interrupt by doing 1 word DMA from 0 in uba space!! */ ! 146: addr->vvocsr = VV_IEN; /* enable interrupt */ ! 147: addr->vvoba = 0; /* low 16 bits */ ! 148: addr->vvoea = 0; /* extended bits */ ! 149: addr->vvowc = -1; /* for 1 word */ ! 150: addr->vvocsr |= VV_DEN; /* start the DMA */ ! 151: DELAY(100000); ! 152: addr->vvocsr = 0; ! 153: if (cvec && cvec != 0x200) ! 154: cvec -= 4; /* backup so vector => recieve */ ! 155: return(1); ! 156: } ! 157: ! 158: /* ! 159: * Interface exists: make available by filling in network interface ! 160: * record. System will initialize the interface when it is ready ! 161: * to accept packets. ! 162: */ ! 163: vvattach(ui) ! 164: struct uba_device *ui; ! 165: { ! 166: register struct vv_softc *vs = &vv_softc[ui->ui_unit]; ! 167: ! 168: vs->vs_if.if_unit = ui->ui_unit; ! 169: vs->vs_if.if_name = "vv"; ! 170: vs->vs_if.if_mtu = VVMTU; ! 171: vs->vs_if.if_init = vvinit; ! 172: vs->vs_if.if_ioctl = vvioctl; ! 173: vs->vs_if.if_output = vvoutput; ! 174: vs->vs_if.if_reset = vvreset; ! 175: vs->vs_ifuba.ifu_flags = UBA_CANTWAIT | UBA_NEEDBDP | UBA_NEED16; ! 176: #if defined(VAX750) ! 177: /* don't chew up 750 bdp's */ ! 178: if (cpu == VAX_750 && ui->ui_unit > 0) ! 179: vs->vs_ifuba.ifu_flags &= ~UBA_NEEDBDP; ! 180: #endif ! 181: if_attach(&vs->vs_if); ! 182: } ! 183: ! 184: /* ! 185: * Reset of interface after UNIBUS reset. ! 186: * If interface is on specified uba, reset its state. ! 187: */ ! 188: vvreset(unit, uban) ! 189: int unit, uban; ! 190: { ! 191: register struct uba_device *ui; ! 192: ! 193: if (unit >= NVV || (ui = vvinfo[unit]) == 0 || ui->ui_alive == 0 || ! 194: ui->ui_ubanum != uban) ! 195: return; ! 196: printf(" vv%d", unit); ! 197: vvinit(unit); ! 198: } ! 199: ! 200: /* ! 201: * Initialization of interface; clear recorded pending ! 202: * operations, and reinitialize UNIBUS usage. ! 203: */ ! 204: vvinit(unit) ! 205: int unit; ! 206: { ! 207: register struct vv_softc *vs = &vv_softc[unit]; ! 208: register struct uba_device *ui = vvinfo[unit]; ! 209: register struct vvreg *addr; ! 210: struct sockaddr_in *sin; ! 211: int ubainfo, s; ! 212: int vvtimeout(); ! 213: ! 214: if (vs->vs_if.if_net == 0) ! 215: return; ! 216: addr = (struct vvreg *)ui->ui_addr; ! 217: if (if_ubainit(&vs->vs_ifuba, ui->ui_ubanum, ! 218: sizeof (struct vv_header), (int)btoc(VVMTU)) == 0) { ! 219: printf("vv%d: can't initialize\n", unit); ! 220: vs->vs_if.if_flags &= ~IFF_UP; ! 221: return; ! 222: } ! 223: if (vv_ticking++ == 0) ! 224: timeout(vvtimeout, (caddr_t) 0, VV_FLYWHEEL); ! 225: /* ! 226: * Discover our host address and post it ! 227: */ ! 228: vs->vs_if.if_host[0] = vvidentify(unit); ! 229: printf("vv%d: host %d\n", unit, vs->vs_if.if_host[0]); ! 230: sin = (struct sockaddr_in *)&vs->vs_if.if_addr; ! 231: sin->sin_family = AF_INET; ! 232: sin->sin_addr = if_makeaddr(vs->vs_if.if_net, vs->vs_if.if_host[0]); ! 233: sin = (struct sockaddr_in *)&vs->vs_if.if_broadaddr; ! 234: sin->sin_family = AF_INET; ! 235: sin->sin_addr = if_makeaddr(vs->vs_if.if_net, VV_BROADCAST); ! 236: ! 237: /* ! 238: * Reset the interface, and join the ring ! 239: */ ! 240: addr->vvocsr = VV_RST | VV_CPB; /* clear packet buffer */ ! 241: addr->vvicsr = VV_RST | VV_CONF; /* close logical relay */ ! 242: DELAY(500000); /* let contacts settle */ ! 243: vs->vs_init = 0; ! 244: vs->vs_dropped = 0; ! 245: vs->vs_nottaken = 0; ! 246: ! 247: /* ! 248: * Hang a receive and start any ! 249: * pending writes by faking a transmit complete. ! 250: */ ! 251: s = splimp(); ! 252: ubainfo = vs->vs_ifuba.ifu_r.ifrw_info; ! 253: addr->vviba = (u_short)ubainfo; ! 254: addr->vviea = (u_short)(ubainfo >> 16); ! 255: addr->vviwc = -(sizeof (struct vv_header) + VVMTU) >> 1; ! 256: addr->vvicsr = VV_IEN | VV_CONF | VV_DEN | VV_ENB; ! 257: vs->vs_iactive = ACTIVE; ! 258: vs->vs_oactive = 1; ! 259: vs->vs_if.if_flags |= IFF_UP | IFF_RUNNING; ! 260: vvxint(unit); ! 261: splx(s); ! 262: if_rtinit(&vs->vs_if, RTF_UP); ! 263: } ! 264: ! 265: /* ! 266: * vvidentify() - return our host address ! 267: */ ! 268: vvidentify(unit) ! 269: int unit; ! 270: { ! 271: register struct vv_softc *vs = &vv_softc[unit]; ! 272: register struct uba_device *ui = vvinfo[unit]; ! 273: register struct vvreg *addr; ! 274: struct mbuf *m; ! 275: struct vv_header *v; ! 276: int ubainfo, attempts, waitcount; ! 277: ! 278: /* ! 279: * Build a multicast message to identify our address ! 280: */ ! 281: addr = (struct vvreg *)ui->ui_addr; ! 282: attempts = 0; /* total attempts, including bad msg type */ ! 283: m = m_get(M_DONTWAIT, MT_HEADER); ! 284: if (m == NULL) ! 285: return (0); ! 286: m->m_next = 0; ! 287: m->m_off = MMINOFF; ! 288: m->m_len = sizeof(struct vv_header); ! 289: v = mtod(m, struct vv_header *); ! 290: v->vh_dhost = VV_BROADCAST; /* multicast destination address */ ! 291: v->vh_shost = 0; /* will be overwritten with ours */ ! 292: v->vh_version = RING_VERSION; ! 293: v->vh_type = RING_WHOAMI; ! 294: v->vh_info = 0; ! 295: /* map xmit message into uba */ ! 296: vs->vs_olen = if_wubaput(&vs->vs_ifuba, m); ! 297: if (vs->vs_ifuba.ifu_flags & UBA_NEEDBDP) ! 298: UBAPURGE(vs->vs_ifuba.ifu_uba, vs->vs_ifuba.ifu_w.ifrw_bdp); ! 299: /* ! 300: * Reset interface, establish Digital Loopback Mode, and ! 301: * send the multicast (to myself) with Input Copy enabled. ! 302: */ ! 303: retry: ! 304: ubainfo = vs->vs_ifuba.ifu_r.ifrw_info; ! 305: addr->vvicsr = VV_RST; ! 306: addr->vviba = (u_short) ubainfo; ! 307: addr->vviea = (u_short) (ubainfo >> 16); ! 308: addr->vviwc = -(sizeof (struct vv_header) + VVMTU) >> 1; ! 309: addr->vvicsr = VV_STE | VV_DEN | VV_ENB | VV_LPB; ! 310: ! 311: /* let flag timers fire so ring will initialize */ ! 312: DELAY(2000000); ! 313: ! 314: addr->vvocsr = VV_RST | VV_CPB; /* clear packet buffer */ ! 315: ubainfo = vs->vs_ifuba.ifu_w.ifrw_info; ! 316: addr->vvoba = (u_short) ubainfo; ! 317: addr->vvoea = (u_short) (ubainfo >> 16); ! 318: addr->vvowc = -((vs->vs_olen + 1) >> 1); ! 319: addr->vvocsr = VV_CPB | VV_DEN | VV_INR | VV_ENB; ! 320: /* ! 321: * Wait for receive side to finish. ! 322: * Extract source address (which will our own), ! 323: * and post to interface structure. ! 324: */ ! 325: DELAY(1000); ! 326: for (waitcount = 0; (addr->vvicsr & VV_RDY) == 0; waitcount++) { ! 327: if (waitcount < 10) { ! 328: DELAY(1000); ! 329: continue; ! 330: } ! 331: if (attempts++ >= 10) { ! 332: printf("vv%d: can't initialize\n", unit); ! 333: printf("vvinit loopwait: icsr = %b\n", ! 334: 0xffff&(addr->vvicsr), VV_IBITS); ! 335: vs->vs_if.if_flags &= ~IFF_UP; ! 336: return (0); ! 337: } ! 338: goto retry; ! 339: } ! 340: if (vs->vs_ifuba.ifu_flags & UBA_NEEDBDP) ! 341: UBAPURGE(vs->vs_ifuba.ifu_uba, vs->vs_ifuba.ifu_w.ifrw_bdp); ! 342: if (vs->vs_ifuba.ifu_xtofree) ! 343: m_freem(vs->vs_ifuba.ifu_xtofree); ! 344: if (vs->vs_ifuba.ifu_flags & UBA_NEEDBDP) ! 345: UBAPURGE(vs->vs_ifuba.ifu_uba, vs->vs_ifuba.ifu_r.ifrw_bdp); ! 346: m = if_rubaget(&vs->vs_ifuba, sizeof(struct vv_header), 0); ! 347: if (m != NULL) ! 348: m_freem(m); ! 349: /* ! 350: * Check message type before we believe the source host address ! 351: */ ! 352: v = (struct vv_header *)(vs->vs_ifuba.ifu_r.ifrw_addr); ! 353: if (v->vh_type != RING_WHOAMI) ! 354: goto retry; ! 355: return(v->vh_shost); ! 356: } ! 357: ! 358: /* ! 359: * vvtimeout() - called by timer flywheel to monitor input packet ! 360: * discard rate. Interfaces getting too many errors are shut ! 361: * down for a while. If the condition persists, the interface ! 362: * is marked down. ! 363: */ ! 364: /*ARGSUSED*/ ! 365: vvtimeout(junk) ! 366: int junk; ! 367: { ! 368: register struct vv_softc *vs; ! 369: register int i; ! 370: register struct vvreg *addr; ! 371: int ubainfo; ! 372: ! 373: timeout(vvtimeout, (caddr_t) 0, VV_FLYWHEEL); ! 374: for (i = 0; i < NVV; i++) { ! 375: vs = &vv_softc[i]; ! 376: addr = (struct vvreg *)vvinfo[i]->ui_addr; ! 377: if ((vs->vs_if.if_flags & IFF_UP) == 0) ! 378: continue; ! 379: switch (vs->vs_major) { ! 380: ! 381: /* ! 382: * MODE0: generally OK, just check error rate ! 383: */ ! 384: case MODE0: ! 385: if (vs->vs_dropped < VV_ERRORTHRESHOLD) { ! 386: vs->vs_dropped = 0; ! 387: continue; ! 388: } ! 389: /* suspend reads for a while */ ! 390: vvtrprintf("vv%d going MODE1 in vvtimeout\n",i); ! 391: vs->vs_major = MODE1; ! 392: vs->vs_iactive = PAUSE; /* no new reads */ ! 393: vs->vs_retry = VV_MODE1ATTEMPTS; ! 394: vs->vs_delayclock = VV_MODE1DELAY; ! 395: vs->vs_minor = 0; ! 396: continue; ! 397: ! 398: /* ! 399: * MODE1: excessive error rate observed ! 400: * Scheme: try simply suspending reads for a ! 401: * short while a small number of times ! 402: */ ! 403: case MODE1: ! 404: if (vs->vs_delayclock > 0) { ! 405: vs->vs_delayclock--; ! 406: continue; ! 407: } ! 408: switch (vs->vs_minor) { ! 409: ! 410: case 0: /* reenable reads */ ! 411: vvtrprintf("vv%d M1m0\n",i); ! 412: vs->vs_dropped = 0; ! 413: vs->vs_iactive = ACTIVE; ! 414: vs->vs_minor = 1; /* next state */ ! 415: ubainfo = vs->vs_ifuba.ifu_r.ifrw_info; ! 416: addr->vviba = (u_short) ubainfo; ! 417: addr->vviea = (u_short) (ubainfo >> 16); ! 418: addr->vviwc = ! 419: -(sizeof (struct vv_header) + VVMTU) >> 1; ! 420: addr->vvicsr = VV_RST | VV_CONF; ! 421: addr->vvicsr |= VV_IEN | VV_DEN | VV_ENB; ! 422: continue; ! 423: ! 424: case 1: /* see if it worked */ ! 425: vvtrprintf("vv%d M1m1\n",i); ! 426: if (vs->vs_dropped < VV_ERRORTHRESHOLD) { ! 427: vs->vs_dropped = 0; ! 428: vs->vs_major = MODE0; /* yeah!! */ ! 429: continue; ! 430: } ! 431: if (vs->vs_retry -- > 0) { ! 432: vs->vs_dropped = 0; ! 433: vs->vs_iactive = PAUSE; ! 434: vs->vs_delayclock = VV_MODE1DELAY; ! 435: vs->vs_minor = 0; /* recheck */ ! 436: continue; ! 437: } ! 438: vs->vs_major = MODE2; ! 439: vs->vs_minor = 0; ! 440: vs->vs_dropped = 0; ! 441: vs->vs_iactive = OPEN; ! 442: vs->vs_delayrange = VV_MODE2DELAY; ! 443: vs->vs_delayclock = VV_MODE2DELAY; ! 444: /* fall thru ... */ ! 445: } ! 446: ! 447: /* ! 448: * MODE2: simply ignoring traffic didn't relieve condition ! 449: * Scheme: open host relay for intervals linearly ! 450: * increasing up to some maximum of a several minutes. ! 451: * This allows broken networks to return to operation ! 452: * without rebooting. ! 453: */ ! 454: case MODE2: ! 455: if (vs->vs_delayclock > 0) { ! 456: vs->vs_delayclock--; ! 457: continue; ! 458: } ! 459: switch (vs->vs_minor) { ! 460: ! 461: case 0: /* close relay and reenable reads */ ! 462: vvtrprintf("vv%d M2m0\n",i); ! 463: vs->vs_dropped = 0; ! 464: vs->vs_iactive = ACTIVE; ! 465: vs->vs_minor = 1; /* next state */ ! 466: ubainfo = vs->vs_ifuba.ifu_r.ifrw_info; ! 467: addr->vviba = (u_short) ubainfo; ! 468: addr->vviea = (u_short) (ubainfo >> 16); ! 469: addr->vviwc = ! 470: -(sizeof (struct vv_header) + VVMTU) >> 1; ! 471: addr->vvicsr = VV_RST | VV_CONF; ! 472: addr->vvicsr |= VV_IEN | VV_DEN | VV_ENB; ! 473: continue; ! 474: ! 475: case 1: /* see if it worked */ ! 476: vvtrprintf("vv%d M2m1\n",i); ! 477: if (vs->vs_dropped < VV_ERRORTHRESHOLD) { ! 478: vs->vs_dropped = 0; ! 479: vs->vs_major = MODE0; /* yeah!! */ ! 480: continue; ! 481: } ! 482: vvtrprintf("vv%d M2m1 ++ delay\n",i); ! 483: vs->vs_dropped = 0; ! 484: vs->vs_iactive = OPEN; ! 485: vs->vs_minor = 0; ! 486: if (vs->vs_delayrange < VV_MAXDELAY) ! 487: vs->vs_delayrange += ! 488: (vs->vs_delayrange/2); ! 489: vs->vs_delayclock = vs->vs_delayrange; ! 490: continue; ! 491: } ! 492: ! 493: default: ! 494: printf("vv%d: major state screwed\n", i); ! 495: vs->vs_if.if_flags &= ~IFF_UP; ! 496: } ! 497: } ! 498: } ! 499: ! 500: /* ! 501: * Start or restart output on interface. ! 502: * If interface is active, this is a retransmit, so just ! 503: * restuff registers and go. ! 504: * If interface is not already active, get another datagram ! 505: * to send off of the interface queue, and map it to the interface ! 506: * before starting the output. ! 507: */ ! 508: vvstart(dev) ! 509: dev_t dev; ! 510: { ! 511: int unit = VVUNIT(dev); ! 512: struct uba_device *ui = vvinfo[unit]; ! 513: register struct vv_softc *vs = &vv_softc[unit]; ! 514: register struct vvreg *addr; ! 515: struct mbuf *m; ! 516: int ubainfo; ! 517: int dest; ! 518: ! 519: if (vs->vs_oactive) ! 520: goto restart; ! 521: /* ! 522: * Not already active: dequeue another request ! 523: * and map it to the UNIBUS. If no more requests, ! 524: * just return. ! 525: */ ! 526: IF_DEQUEUE(&vs->vs_if.if_snd, m); ! 527: if (m == NULL) { ! 528: vs->vs_oactive = 0; ! 529: return; ! 530: } ! 531: dest = mtod(m, struct vv_header *)->vh_dhost; ! 532: vs->vs_olen = if_wubaput(&vs->vs_ifuba, m); ! 533: vs->vs_lastx = dest; ! 534: restart: ! 535: /* ! 536: * Have request mapped to UNIBUS for transmission. ! 537: * Purge any stale data from this BDP, and start the otput. ! 538: */ ! 539: if (vs->vs_olen > VVMTU + sizeof (struct vv_header)) { ! 540: printf("vv%d vs_olen: %d > VVMTU\n", unit, vs->vs_olen); ! 541: panic("vvdriver vs_olen botch"); ! 542: } ! 543: if (vs->vs_ifuba.ifu_flags & UBA_NEEDBDP) ! 544: UBAPURGE(vs->vs_ifuba.ifu_uba, vs->vs_ifuba.ifu_w.ifrw_bdp); ! 545: addr = (struct vvreg *)ui->ui_addr; ! 546: ubainfo = vs->vs_ifuba.ifu_w.ifrw_info; ! 547: addr->vvoba = (u_short) ubainfo; ! 548: addr->vvoea = (u_short) (ubainfo >> 16); ! 549: addr->vvowc = -((vs->vs_olen + 1) >> 1); ! 550: addr->vvocsr = VV_IEN | VV_CPB | VV_DEN | VV_INR | VV_ENB; ! 551: vs->vs_oactive = 1; ! 552: } ! 553: ! 554: /* ! 555: * VVLNI transmit interrupt ! 556: * Start another output if more data to send. ! 557: */ ! 558: vvxint(unit) ! 559: int unit; ! 560: { ! 561: register struct uba_device *ui = vvinfo[unit]; ! 562: register struct vv_softc *vs = &vv_softc[unit]; ! 563: register struct vvreg *addr; ! 564: register int oc; ! 565: ! 566: addr = (struct vvreg *)ui->ui_addr; ! 567: oc = 0xffff & (addr->vvocsr); ! 568: if (vs->vs_oactive == 0) { ! 569: printf("vv%d: stray interrupt vvocsr = %b\n", unit, ! 570: oc, VV_OBITS); ! 571: return; ! 572: } ! 573: if (oc & (VV_OPT | VV_RFS)) { ! 574: vs->vs_if.if_collisions++; ! 575: if (vs->vs_tries++ < VVRETRY) { ! 576: if (oc & VV_OPT) ! 577: vs->vs_init++; ! 578: if (oc & VV_RFS) ! 579: vs->vs_nottaken++; ! 580: vvstart(unit); /* restart this message */ ! 581: return; ! 582: } ! 583: if (oc & VV_OPT) ! 584: printf("vv%d: output timeout\n"); ! 585: } ! 586: vs->vs_if.if_opackets++; ! 587: vs->vs_oactive = 0; ! 588: vs->vs_tries = 0; ! 589: if (oc & VVXERR) { ! 590: vs->vs_if.if_oerrors++; ! 591: printf("vv%d: error vvocsr = %b\n", unit, 0xffff & oc, ! 592: VV_OBITS); ! 593: } ! 594: if (vs->vs_ifuba.ifu_xtofree) { ! 595: m_freem(vs->vs_ifuba.ifu_xtofree); ! 596: vs->vs_ifuba.ifu_xtofree = 0; ! 597: } ! 598: if (vs->vs_if.if_snd.ifq_head == 0) { ! 599: vs->vs_lastx = 256; /* an invalid address */ ! 600: return; ! 601: } ! 602: vvstart(unit); ! 603: } ! 604: ! 605: /* ! 606: * V2lni interface receiver interrupt. ! 607: * If input error just drop packet. ! 608: * Otherwise purge input buffered data path and examine ! 609: * packet to determine type. If can't determine length ! 610: * from type, then have to drop packet. Othewise decapsulate ! 611: * packet based on type and pass to type specific higher-level ! 612: * input routine. ! 613: */ ! 614: vvrint(unit) ! 615: int unit; ! 616: { ! 617: register struct vv_softc *vs = &vv_softc[unit]; ! 618: struct vvreg *addr = (struct vvreg *)vvinfo[unit]->ui_addr; ! 619: register struct vv_header *vv; ! 620: register struct ifqueue *inq; ! 621: struct mbuf *m; ! 622: int ubainfo, len, off; ! 623: short resid; ! 624: ! 625: vs->vs_if.if_ipackets++; ! 626: /* ! 627: * Purge BDP; drop if input error indicated. ! 628: */ ! 629: if (vs->vs_ifuba.ifu_flags & UBA_NEEDBDP) ! 630: UBAPURGE(vs->vs_ifuba.ifu_uba, vs->vs_ifuba.ifu_r.ifrw_bdp); ! 631: if (addr->vvicsr & VVRERR) { ! 632: if (vv_logreaderrors) ! 633: printf("vv%d: error vvicsr = %b\n", unit, ! 634: 0xffff&(addr->vvicsr), VV_IBITS); ! 635: goto dropit; ! 636: } ! 637: ! 638: /* ! 639: * Get packet length from word count residue ! 640: * ! 641: * Compute header offset if trailer protocol ! 642: * ! 643: * Pull packet off interface. Off is nonzero if packet ! 644: * has trailing header; if_rubaget will then force this header ! 645: * information to be at the front. The vh_info field ! 646: * carries the offset to the trailer data in trailer ! 647: * format packets. ! 648: */ ! 649: vv = (struct vv_header *)(vs->vs_ifuba.ifu_r.ifrw_addr); ! 650: vvtracehdr("vi", vv); ! 651: resid = addr->vviwc; ! 652: if (resid) ! 653: resid |= 0176000; /* ugly!!!! */ ! 654: len = (((sizeof (struct vv_header) + VVMRU) >> 1) + resid) << 1; ! 655: len -= sizeof(struct vv_header); ! 656: if (len > VVMRU || len <= 0) ! 657: goto dropit; ! 658: #define vvdataaddr(vv, off, type) ((type)(((caddr_t)((vv)+1)+(off)))) ! 659: if (vv->vh_type >= RING_IPTrailer && ! 660: vv->vh_type < RING_IPTrailer+RING_IPNTrailer) { ! 661: off = (vv->vh_type - RING_IPTrailer) * 512; ! 662: if (off > VVMTU) ! 663: goto dropit; ! 664: vv->vh_type = *vvdataaddr(vv, off, u_short *); ! 665: resid = *(vvdataaddr(vv, off+2, u_short *)); ! 666: if (off + resid > len) ! 667: goto dropit; ! 668: len = off + resid; ! 669: } else ! 670: off = 0; ! 671: if (len == 0) ! 672: goto dropit; ! 673: m = if_rubaget(&vs->vs_ifuba, len, off); ! 674: if (m == NULL) ! 675: goto dropit; ! 676: if (off) { ! 677: m->m_off += 2 * sizeof(u_short); ! 678: m->m_len -= 2 * sizeof(u_short); ! 679: } ! 680: ! 681: /* ! 682: * Demultiplex on packet type ! 683: */ ! 684: switch (vv->vh_type) { ! 685: ! 686: #ifdef INET ! 687: case RING_IP: ! 688: schednetisr(NETISR_IP); ! 689: inq = &ipintrq; ! 690: break; ! 691: #endif ! 692: default: ! 693: printf("vv%d: unknown pkt type 0x%x\n", unit, vv->vh_type); ! 694: m_freem(m); ! 695: goto setup; ! 696: } ! 697: if (IF_QFULL(inq)) { ! 698: IF_DROP(inq); ! 699: m_freem(m); ! 700: } else ! 701: IF_ENQUEUE(inq, m); ! 702: setup: ! 703: /* ! 704: * Check the error rate and start recovery if needed ! 705: * this has to go here since the timer flywheel runs at ! 706: * a lower ipl and never gets a chance to change the mode ! 707: */ ! 708: if (vs->vs_major == MODE0 && vs->vs_dropped > VV_ERRORTHRESHOLD) { ! 709: vvtrprintf("vv%d going MODE1 in vvrint\n",unit); ! 710: vs->vs_major = MODE1; ! 711: vs->vs_iactive = PAUSE; /* no new reads */ ! 712: vs->vs_retry = VV_MODE1ATTEMPTS; ! 713: vs->vs_delayclock = VV_MODE1DELAY; ! 714: vs->vs_minor = 0; ! 715: vs->vs_dropped = 0; ! 716: } ! 717: switch (vs->vs_iactive) { ! 718: ! 719: case ACTIVE: /* Restart the read for next packet */ ! 720: ubainfo = vs->vs_ifuba.ifu_r.ifrw_info; ! 721: addr->vviba = (u_short) ubainfo; ! 722: addr->vviea = (u_short) (ubainfo >> 16); ! 723: addr->vviwc = -(sizeof (struct vv_header) + VVMTU) >> 1; ! 724: addr->vvicsr = VV_RST | VV_CONF; ! 725: addr->vvicsr |= VV_IEN | VV_DEN | VV_ENB; ! 726: return; ! 727: ! 728: case PAUSE: /* requested to not start any new reads */ ! 729: vs->vs_dropped = 0; ! 730: return; ! 731: ! 732: case OPEN: /* request to open host relay */ ! 733: vs->vs_dropped = 0; ! 734: addr->vvicsr = 0; ! 735: return; ! 736: ! 737: default: ! 738: printf("vv%d: vs_iactive = %d\n", unit, vs->vs_iactive); ! 739: return; ! 740: } ! 741: /* ! 742: * Drop packet on floor -- count them!! ! 743: */ ! 744: dropit: ! 745: vs->vs_if.if_ierrors++; ! 746: vs->vs_dropped++; ! 747: /* ! 748: printf("vv%d: error vvicsr = %b\n", unit, ! 749: 0xffff&(addr->vvicsr), VV_IBITS); ! 750: */ ! 751: goto setup; ! 752: } ! 753: ! 754: /* ! 755: * V2lni output routine. ! 756: * Encapsulate a packet of type family for the local net. ! 757: * Use trailer local net encapsulation if enough data in first ! 758: * packet leaves a multiple of 512 bytes of data in remainder. ! 759: */ ! 760: vvoutput(ifp, m0, dst) ! 761: struct ifnet *ifp; ! 762: struct mbuf *m0; ! 763: struct sockaddr *dst; ! 764: { ! 765: register struct mbuf *m = m0; ! 766: register struct vv_header *vv; ! 767: register int off; ! 768: int type, dest, s, error; ! 769: ! 770: switch (dst->sa_family) { ! 771: ! 772: #ifdef INET ! 773: case AF_INET: { ! 774: dest = ((struct sockaddr_in *)dst)->sin_addr.s_addr; ! 775: if ((dest = in_lnaof(*((struct in_addr *)&dest))) >= 0x100) { ! 776: error = EPERM; ! 777: goto bad; ! 778: } ! 779: off = ntohs((u_short)mtod(m, struct ip *)->ip_len) - m->m_len; ! 780: if ((ifp->if_flags & IFF_NOTRAILERS) == 0) ! 781: if (off > 0 && (off & 0x1ff) == 0 && ! 782: m->m_off >= MMINOFF + 2 * sizeof (u_short)) { ! 783: type = RING_IPTrailer + (off>>9); ! 784: m->m_off -= 2 * sizeof (u_short); ! 785: m->m_len += 2 * sizeof (u_short); ! 786: *mtod(m, u_short *) = RING_IP; ! 787: *(mtod(m, u_short *) + 1) = m->m_len; ! 788: goto gottrailertype; ! 789: } ! 790: type = RING_IP; ! 791: off = 0; ! 792: goto gottype; ! 793: } ! 794: #endif ! 795: default: ! 796: printf("vv%d: can't handle af%d\n", ifp->if_unit, ! 797: dst->sa_family); ! 798: error = EAFNOSUPPORT; ! 799: goto bad; ! 800: } ! 801: ! 802: gottrailertype: ! 803: /* ! 804: * Packet to be sent as trailer: move first packet ! 805: * (control information) to end of chain. ! 806: */ ! 807: while (m->m_next) ! 808: m = m->m_next; ! 809: m->m_next = m0; ! 810: m = m0->m_next; ! 811: m0->m_next = 0; ! 812: m0 = m; ! 813: gottype: ! 814: /* ! 815: * Add local net header. If no space in first mbuf, ! 816: * allocate another. ! 817: */ ! 818: if (m->m_off > MMAXOFF || ! 819: MMINOFF + sizeof (struct vv_header) > m->m_off) { ! 820: m = m_get(M_DONTWAIT, MT_HEADER); ! 821: if (m == NULL) { ! 822: error = ENOBUFS; ! 823: goto bad; ! 824: } ! 825: m->m_next = m0; ! 826: m->m_off = MMINOFF; ! 827: m->m_len = sizeof (struct vv_header); ! 828: } else { ! 829: m->m_off -= sizeof (struct vv_header); ! 830: m->m_len += sizeof (struct vv_header); ! 831: } ! 832: vv = mtod(m, struct vv_header *); ! 833: vv->vh_shost = ifp->if_host[0]; ! 834: vv->vh_dhost = dest; ! 835: vv->vh_version = RING_VERSION; ! 836: vv->vh_type = type; ! 837: vv->vh_info = off; ! 838: vvtracehdr("vo", vv); ! 839: ! 840: /* ! 841: * Queue message on interface, and start output if interface ! 842: * not yet active. ! 843: */ ! 844: s = splimp(); ! 845: if (IF_QFULL(&ifp->if_snd)) { ! 846: IF_DROP(&ifp->if_snd); ! 847: error = ENOBUFS; ! 848: goto qfull; ! 849: } ! 850: IF_ENQUEUE(&ifp->if_snd, m); ! 851: if (vv_softc[ifp->if_unit].vs_oactive == 0) ! 852: vvstart(ifp->if_unit); ! 853: splx(s); ! 854: return (0); ! 855: qfull: ! 856: m0 = m; ! 857: splx(s); ! 858: bad: ! 859: m_freem(m0); ! 860: return(error); ! 861: } ! 862: ! 863: /* ! 864: * Process an ioctl request. ! 865: */ ! 866: vvioctl(ifp, cmd, data) ! 867: register struct ifnet *ifp; ! 868: int cmd; ! 869: caddr_t data; ! 870: { ! 871: struct ifreq *ifr = (struct ifreq *)data; ! 872: int s = splimp(), error = 0; ! 873: ! 874: switch (cmd) { ! 875: ! 876: case SIOCSIFADDR: ! 877: /* too difficult to change addr while running */ ! 878: if ((ifp->if_flags & IFF_RUNNING) == 0) { ! 879: struct sockaddr_in *sin = ! 880: (struct sockaddr_in *)&ifr->ifr_addr; ! 881: ifp->if_net = in_netof(sin->sin_addr); ! 882: vvinit(ifp->if_unit); ! 883: } else ! 884: error = EINVAL; ! 885: break; ! 886: ! 887: default: ! 888: error = EINVAL; ! 889: } ! 890: splx(s); ! 891: return (error); ! 892: } ! 893: ! 894: /* ! 895: * vvprt_hdr(s, v) print the local net header in "v" ! 896: * with title is "s" ! 897: */ ! 898: vvprt_hdr(s, v) ! 899: char *s; ! 900: register struct vv_header *v; ! 901: { ! 902: printf("%s: dsvti: 0x%x 0x%x 0x%x 0x%x 0x%x\n", ! 903: s, ! 904: 0xff & (int)(v->vh_dhost), 0xff & (int)(v->vh_shost), ! 905: 0xff & (int)(v->vh_version), 0xff & (int)(v->vh_type), ! 906: 0xffff & (int)(v->vh_info)); ! 907: } ! 908: ! 909: #ifdef notdef ! 910: /* ! 911: * print "l" hex bytes starting at "s" ! 912: */ ! 913: vvprt_hex(s, l) ! 914: char *s; ! 915: int l; ! 916: { ! 917: register int i; ! 918: register int z; ! 919: ! 920: for (i=0 ; i < l; i++) { ! 921: z = 0xff & (int)(*(s + i)); ! 922: printf("%c%c ", ! 923: "0123456789abcdef"[(z >> 4) & 0x0f], ! 924: "0123456789abcdef"[z & 0x0f] ! 925: ); ! 926: } ! 927: } ! 928: #endif
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.