|
|
1.1 ! root 1: /* ! 2: * Copyright (c) 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_dmv.c 7.10 (Berkeley) 6/28/90 ! 21: */ ! 22: ! 23: /* ! 24: * DMV-11 Driver ! 25: * ! 26: * Qbus Sync DDCMP interface - DMV operated in full duplex, point to point mode ! 27: * ! 28: * Written by Bob Kridle of Mt Xinu ! 29: * starting from if_dmc.c version 6.12 dated 4/23/86 ! 30: */ ! 31: ! 32: #include "dmv.h" ! 33: #if NDMV > 0 ! 34: ! 35: #include "param.h" ! 36: #include "systm.h" ! 37: #include "mbuf.h" ! 38: #include "buf.h" ! 39: #include "ioctl.h" /* must precede tty.h */ ! 40: #include "tty.h" ! 41: #include "protosw.h" ! 42: #include "socket.h" ! 43: #include "syslog.h" ! 44: #include "vmmac.h" ! 45: #include "errno.h" ! 46: #include "time.h" ! 47: #include "kernel.h" ! 48: ! 49: #include "../net/if.h" ! 50: #include "../net/netisr.h" ! 51: #include "../net/route.h" ! 52: ! 53: #ifdef INET ! 54: #include "../netinet/in.h" ! 55: #include "../netinet/in_systm.h" ! 56: #include "../netinet/in_var.h" ! 57: #include "../netinet/ip.h" ! 58: #endif ! 59: ! 60: #include "../vax/cpu.h" ! 61: #include "../vax/mtpr.h" ! 62: #include "../vax/pte.h" ! 63: #include "../vaxuba/ubareg.h" ! 64: #include "../vaxuba/ubavar.h" ! 65: #include "if_uba.h" ! 66: #include "if_dmv.h" ! 67: ! 68: int dmv_timeout = 8; /* timeout value */ ! 69: ! 70: /* ! 71: * Driver information for auto-configuration stuff. ! 72: */ ! 73: int dmvprobe(), dmvattach(), dmvinit(), dmvioctl(); ! 74: int dmvoutput(), dmvreset(), dmvtimeout(); ! 75: struct uba_device *dmvinfo[NDMV]; ! 76: u_short dmvstd[] = { 0 }; ! 77: struct uba_driver dmvdriver = ! 78: { dmvprobe, 0, dmvattach, 0, dmvstd, "dmv", dmvinfo }; ! 79: ! 80: /* ! 81: * Don't really know how many buffers/commands can be queued to a DMV-11. ! 82: * Manual doesn't say... Perhaps we can look at a DEC driver some day. ! 83: * These numbers ame from DMC/DMR driver. ! 84: */ ! 85: #define NRCV 5 ! 86: #define NXMT 3 ! 87: #define NCMDS (NRCV+NXMT+4) /* size of command queue */ ! 88: ! 89: #ifdef DEBUG ! 90: #define printd(f) if (sc->sc_if.if_flags & IFF_DEBUG) \ ! 91: printf("DMVDEBUG: dmv%d: ", unit), printf(f) ! 92: #else ! 93: #define printd(f) /* nil */ ! 94: #endif ! 95: ! 96: /* error reporting intervals */ ! 97: ! 98: #define DMV_RPRTE 1 ! 99: #define DMV_RPTTE 1 ! 100: #define DMV_RPSTE 1 ! 101: #define DMV_RPNXM 1 ! 102: #define DMV_RPMODD 1 ! 103: #define DMV_RPQOVF 1 ! 104: #define DMV_RPCXRL 1 ! 105: ! 106: /* number of errors to accept before trying a reset */ ! 107: #define DMV_RPUNKNOWN 10 ! 108: ! 109: struct dmv_command { ! 110: u_char qp_mask; /* Which registers to set up */ ! 111: #define QP_TRIB 0x01 ! 112: #define QP_SEL4 0x02 ! 113: #define QP_SEL6 0x04 ! 114: #define QP_SEL10 0x08 ! 115: u_char qp_cmd; ! 116: u_char qp_tributary; ! 117: u_short qp_sel4; ! 118: u_short qp_sel6; ! 119: u_short qp_sel10; ! 120: struct dmv_command *qp_next; /* next command on queue */ ! 121: }; ! 122: ! 123: #define qp_lowbufaddr qp_ ! 124: ! 125: struct dmvbufs { ! 126: int ubinfo; /* from uballoc */ ! 127: short cc; /* buffer size */ ! 128: short flags; /* access control */ ! 129: }; ! 130: ! 131: #define DBUF_OURS 0 /* buffer is available */ ! 132: #define DBUF_DMVS 1 /* buffer claimed by somebody */ ! 133: #define DBUF_XMIT 4 /* transmit buffer */ ! 134: #define DBUF_RCV 8 /* receive buffer */ ! 135: ! 136: ! 137: /* ! 138: * DMV software status per interface. ! 139: * ! 140: * Each interface is referenced by a network interface structure, ! 141: * sc_if, which the routing code uses to locate the interface. ! 142: * This structure contains the output queue for the interface, its address, ... ! 143: * We also have, for each interface, a set of 7 UBA interface structures ! 144: * for each, which ! 145: * contain information about the UNIBUS resources held by the interface: ! 146: * map registers, buffered data paths, etc. Information is cached in this ! 147: * structure for use by the if_uba.c routines in running the interface ! 148: * efficiently. ! 149: */ ! 150: struct dmv_softc { ! 151: struct ifnet sc_if; /* network-visible interface */ ! 152: short sc_oused; /* output buffers currently in use */ ! 153: short sc_iused; /* input buffers given to DMV */ ! 154: short sc_flag; /* flags */ ! 155: short sc_ipl; /* interrupt priority */ ! 156: int sc_ubinfo; /* UBA mapping info for base table */ ! 157: int sc_errors[8]; /* error counters */ ! 158: #define sc_rte sc_errors[0] /* receive threshhold error */ ! 159: #define sc_xte sc_errors[1] /* xmit threshhold error */ ! 160: #define sc_ste sc_errors[2] /* select threshhold error */ ! 161: #define sc_nxm sc_errors[3] /* non-existant memory */ ! 162: #define sc_modd sc_errors[4] /* modem disconnect */ ! 163: #define sc_qovf sc_errors[5] /* command/response queue overflow */ ! 164: #define sc_cxrl sc_errors[6] /* carrier loss */ ! 165: #define sc_unknown sc_errors[7] /* other errors - look in DMV manual */ ! 166: struct dmvbufs sc_rbufs[NRCV]; /* receive buffer info */ ! 167: struct dmvbufs sc_xbufs[NXMT]; /* transmit buffer info */ ! 168: struct ifubinfo sc_ifuba; /* UNIBUS resources */ ! 169: struct ifrw sc_ifr[NRCV]; /* UNIBUS receive buffer maps */ ! 170: struct ifxmt sc_ifw[NXMT]; /* UNIBUS receive buffer maps */ ! 171: /* command queue stuff */ ! 172: struct dmv_command sc_cmdbuf[NCMDS]; ! 173: struct dmv_command *sc_qhead; /* head of command queue */ ! 174: struct dmv_command *sc_qtail; /* tail of command queue */ ! 175: struct dmv_command *sc_qactive; /* command in progress */ ! 176: struct dmv_command *sc_qfreeh; /* head of list of free cmd buffers */ ! 177: struct dmv_command *sc_qfreet; /* tail of list of free cmd buffers */ ! 178: /* end command queue stuff */ ! 179: } dmv_softc[NDMV]; ! 180: ! 181: /* flags */ ! 182: #define DMV_RESTART 0x01 /* software restart in progress */ ! 183: #define DMV_ONLINE 0x02 /* device managed to transmit */ ! 184: #define DMV_RUNNING 0x04 /* device initialized */ ! 185: ! 186: ! 187: /* queue manipulation macros */ ! 188: #define QUEUE_AT_HEAD(qp, head, tail) \ ! 189: (qp)->qp_next = (head); \ ! 190: (head) = (qp); \ ! 191: if ((tail) == (struct dmv_command *) 0) \ ! 192: (tail) = (head) ! 193: ! 194: #define QUEUE_AT_TAIL(qp, head, tail) \ ! 195: if ((tail)) \ ! 196: (tail)->qp_next = (qp); \ ! 197: else \ ! 198: (head) = (qp); \ ! 199: (qp)->qp_next = (struct dmv_command *) 0; \ ! 200: (tail) = (qp) ! 201: ! 202: #define DEQUEUE(head, tail) \ ! 203: (head) = (head)->qp_next;\ ! 204: if ((head) == (struct dmv_command *) 0)\ ! 205: (tail) = (head) ! 206: ! 207: dmvprobe(reg, ui) ! 208: caddr_t reg; ! 209: struct uba_device *ui; ! 210: { ! 211: register int br, cvec; ! 212: register struct dmvdevice *addr = (struct dmvdevice *)reg; ! 213: register int i; ! 214: ! 215: #ifdef lint ! 216: br = 0; cvec = br; br = cvec; ! 217: dmvrint(0); dmvxint(0); ! 218: #endif ! 219: addr->bsel1 = DMV_MCLR; ! 220: for (i = 100000; i && (addr->bsel1 & DMV_RUN) == 0; i--) ! 221: ; ! 222: if ((addr->bsel1 & DMV_RUN) == 0) { ! 223: printf("dmvprobe: can't start device\n" ); ! 224: return (0); ! 225: } ! 226: if ((addr->bsel4 != 033) || (addr->bsel6 != 0305)) ! 227: { ! 228: printf("dmvprobe: device init failed, bsel4=%o, bsel6=%o\n", ! 229: addr->bsel4, addr->bsel6); ! 230: return (0); ! 231: } ! 232: (void) spl6(); ! 233: addr->bsel0 = DMV_RQI|DMV_IEI|DMV_IEO; ! 234: DELAY(1000000); ! 235: dmv_softc[ui->ui_unit].sc_ipl = br = qbgetpri(); ! 236: addr->bsel1 = DMV_MCLR; ! 237: for (i = 100000; i && (addr->bsel1 & DMV_RUN) == 0; i--) ! 238: ; ! 239: return (sizeof(struct dmvdevice)); ! 240: } ! 241: ! 242: /* ! 243: * Interface exists: make available by filling in network interface ! 244: * record. System will initialize the interface when it is ready ! 245: * to accept packets. ! 246: */ ! 247: dmvattach(ui) ! 248: register struct uba_device *ui; ! 249: { ! 250: register struct dmv_softc *sc = &dmv_softc[ui->ui_unit]; ! 251: ! 252: sc->sc_if.if_unit = ui->ui_unit; ! 253: sc->sc_if.if_name = "dmv"; ! 254: sc->sc_if.if_mtu = DMVMTU; ! 255: sc->sc_if.if_init = dmvinit; ! 256: sc->sc_if.if_output = dmvoutput; ! 257: sc->sc_if.if_ioctl = dmvioctl; ! 258: sc->sc_if.if_reset = dmvreset; ! 259: sc->sc_if.if_watchdog = dmvtimeout; ! 260: sc->sc_if.if_flags = IFF_POINTOPOINT; ! 261: sc->sc_ifuba.iff_flags = UBA_CANTWAIT; ! 262: ! 263: if_attach(&sc->sc_if); ! 264: } ! 265: ! 266: /* ! 267: * Reset of interface after UNIBUS reset. ! 268: * If interface is on specified UBA, reset its state. ! 269: */ ! 270: dmvreset(unit, uban) ! 271: int unit, uban; ! 272: { ! 273: register struct uba_device *ui; ! 274: register struct dmv_softc *sc = &dmv_softc[unit]; ! 275: ! 276: if (unit >= NDMV || (ui = dmvinfo[unit]) == 0 || ui->ui_alive == 0 || ! 277: ui->ui_ubanum != uban) ! 278: return; ! 279: printf(" dmv%d", unit); ! 280: sc->sc_flag = 0; ! 281: sc->sc_if.if_flags &= ~IFF_RUNNING; ! 282: dmvinit(unit); ! 283: } ! 284: ! 285: /* ! 286: * Initialization of interface; reinitialize UNIBUS usage. ! 287: */ ! 288: dmvinit(unit) ! 289: int unit; ! 290: { ! 291: register struct dmv_softc *sc = &dmv_softc[unit]; ! 292: register struct uba_device *ui = dmvinfo[unit]; ! 293: register struct dmvdevice *addr; ! 294: register struct ifnet *ifp = &sc->sc_if; ! 295: register struct ifrw *ifrw; ! 296: register struct ifxmt *ifxp; ! 297: register struct dmvbufs *rp; ! 298: register struct dmv_command *qp; ! 299: struct ifaddr *ifa; ! 300: int base; ! 301: int s; ! 302: ! 303: addr = (struct dmvdevice *)ui->ui_addr; ! 304: ! 305: /* ! 306: * Check to see that an address has been set ! 307: * (both local and destination for an address family). ! 308: */ ! 309: for (ifa = ifp->if_addrlist; ifa; ifa = ifa->ifa_next) ! 310: if (ifa->ifa_addr->sa_family && ifa->ifa_dstaddr->sa_family) ! 311: break; ! 312: if (ifa == (struct ifaddr *) 0) ! 313: return; ! 314: ! 315: if ((addr->bsel1&DMV_RUN) == 0) { ! 316: log(LOG_CRIT, "dmvinit: dmv%d not running\n", unit); ! 317: ifp->if_flags &= ~IFF_UP; ! 318: return; ! 319: } ! 320: printd(("dmvinit\n")); ! 321: /* initialize UNIBUS resources */ ! 322: sc->sc_iused = sc->sc_oused = 0; ! 323: if ((ifp->if_flags & IFF_RUNNING) == 0) { ! 324: if (if_ubaminit( ! 325: &sc->sc_ifuba, ! 326: ui->ui_ubanum, ! 327: sizeof(struct dmv_header), ! 328: (int)btoc(DMVMTU), ! 329: sc->sc_ifr, ! 330: NRCV, ! 331: sc->sc_ifw, ! 332: NXMT ! 333: ) == 0) { ! 334: log(LOG_CRIT, "dmvinit: dmv%d can't allocate uba resources\n", unit); ! 335: ifp->if_flags &= ~IFF_UP; ! 336: return; ! 337: } ! 338: ifp->if_flags |= IFF_RUNNING; ! 339: } ! 340: /* ! 341: * Limit packets enqueued until we see if we're on the air. ! 342: */ ! 343: ifp->if_snd.ifq_maxlen = 3; ! 344: ! 345: ! 346: /* initialize buffer pool */ ! 347: /* receives */ ! 348: ifrw = &sc->sc_ifr[0]; ! 349: for (rp = &sc->sc_rbufs[0]; rp < &sc->sc_rbufs[NRCV]; rp++) { ! 350: rp->ubinfo = UBAI_ADDR(ifrw->ifrw_info); ! 351: rp->cc = DMVMTU + sizeof (struct dmv_header); ! 352: rp->flags = DBUF_OURS|DBUF_RCV; ! 353: ifrw++; ! 354: } ! 355: /* transmits */ ! 356: ifxp = &sc->sc_ifw[0]; ! 357: for (rp = &sc->sc_xbufs[0]; rp < &sc->sc_xbufs[NXMT]; rp++) { ! 358: rp->ubinfo = UBAI_ADDR(ifxp->ifw_info); ! 359: rp->cc = 0; ! 360: rp->flags = DBUF_OURS|DBUF_XMIT; ! 361: ifxp++; ! 362: } ! 363: ! 364: /* set up command queues */ ! 365: sc->sc_qfreeh = sc->sc_qfreet ! 366: = sc->sc_qhead = sc->sc_qtail = sc->sc_qactive = ! 367: (struct dmv_command *)0; ! 368: /* set up free command buffer list */ ! 369: for (qp = &sc->sc_cmdbuf[0]; qp < &sc->sc_cmdbuf[NCMDS]; qp++) { ! 370: QUEUE_AT_HEAD(qp, sc->sc_qfreeh, sc->sc_qfreet); ! 371: } ! 372: if(sc->sc_flag & DMV_RUNNING) ! 373: dmvload( sc, DMV_CNTRLI, (QP_TRIB|QP_SEL6), 1, 0, DMV_REQHS,0); ! 374: else ! 375: dmvload( sc, DMV_CNTRLI, (QP_TRIB|QP_SEL6), 1, 0, DMV_ESTTRIB,0); ! 376: dmvload( sc, DMV_CNTRLI, (QP_TRIB|QP_SEL6), 1, 0, DMV_REQSUS,0); ! 377: sc->sc_flag |= (DMV_RESTART|DMV_RUNNING); ! 378: sc->sc_flag &= ~DMV_ONLINE; ! 379: addr->bsel0 |= DMV_IEO; ! 380: } ! 381: ! 382: /* ! 383: * Start output on interface. Get another datagram ! 384: * to send from the interface queue and map it to ! 385: * the interface before starting output. ! 386: * ! 387: * Must be called at spl 5 ! 388: */ ! 389: dmvstart(dev) ! 390: dev_t dev; ! 391: { ! 392: int unit = minor(dev); ! 393: register struct dmv_softc *sc = &dmv_softc[unit]; ! 394: struct mbuf *m; ! 395: register struct dmvbufs *rp; ! 396: register int n; ! 397: ! 398: /* ! 399: * Dequeue up to NXMT requests and map them to the UNIBUS. ! 400: * If no more requests, or no dmv buffers available, just return. ! 401: */ ! 402: printd(("dmvstart\n")); ! 403: n = 0; ! 404: for (rp = &sc->sc_xbufs[0]; rp < &sc->sc_xbufs[NXMT]; rp++ ) { ! 405: /* find an available buffer */ ! 406: if ((rp->flags & DBUF_DMVS) == 0) { ! 407: IF_DEQUEUE(&sc->sc_if.if_snd, m); ! 408: if (m == 0) ! 409: return; ! 410: /* mark it dmvs */ ! 411: rp->flags |= (DBUF_DMVS); ! 412: /* ! 413: * Have request mapped to UNIBUS for transmission ! 414: * and start the output. ! 415: */ ! 416: rp->cc = if_ubaput(&sc->sc_ifuba, &sc->sc_ifw[n], m); ! 417: if (++sc->sc_oused == 1) ! 418: sc->sc_if.if_timer = dmv_timeout; ! 419: dmvload( ! 420: sc, ! 421: DMV_BACCX, ! 422: QP_TRIB|QP_SEL4|QP_SEL6|QP_SEL10, ! 423: 1, ! 424: rp->ubinfo, ! 425: (rp->ubinfo>>16)&0x3f, ! 426: rp->cc ! 427: ); ! 428: } ! 429: n++; ! 430: } ! 431: } ! 432: ! 433: /* ! 434: * Utility routine to load the DMV device registers. ! 435: */ ! 436: dmvload(sc, cmd, mask, tributary, sel4, sel6, sel10) ! 437: register struct dmv_softc *sc; ! 438: u_char cmd, tributary, mask; ! 439: u_short sel4, sel6, sel10; ! 440: { ! 441: register struct dmvdevice *addr; ! 442: register int unit, sps; ! 443: register struct dmv_command *qp; ! 444: ! 445: unit = sc - dmv_softc; ! 446: printd(("dmvload: cmd=%x mask=%x trib=%x sel4=%x sel6=%x sel10=%x\n", ! 447: (unsigned) cmd, ! 448: (unsigned) mask, ! 449: (unsigned) tributary, ! 450: (unsigned) sel4, ! 451: (unsigned) sel6, ! 452: (unsigned) sel10 ! 453: )); ! 454: addr = (struct dmvdevice *)dmvinfo[unit]->ui_addr; ! 455: sps = spl5(); ! 456: ! 457: /* grab a command buffer from the free list */ ! 458: if ((qp = sc->sc_qfreeh) == (struct dmv_command *)0) ! 459: panic("dmv command queue overflow"); ! 460: DEQUEUE(sc->sc_qfreeh, sc->sc_qfreet); ! 461: ! 462: /* fill in requested info */ ! 463: qp->qp_cmd = cmd; ! 464: qp->qp_mask = mask; ! 465: qp->qp_tributary = tributary; ! 466: qp->qp_sel4 = sel4; ! 467: qp->qp_sel6 = sel6; ! 468: qp->qp_sel10 = sel10; ! 469: ! 470: if (sc->sc_qactive) { /* command in progress */ ! 471: if (cmd == DMV_BACCR) { /* supply read buffers first */ ! 472: QUEUE_AT_HEAD(qp, sc->sc_qhead, sc->sc_qtail); ! 473: } else { ! 474: QUEUE_AT_TAIL(qp, sc->sc_qhead, sc->sc_qtail); ! 475: } ! 476: } else { /* command port free */ ! 477: sc->sc_qactive = qp; ! 478: addr->bsel0 = (DMV_RQI|DMV_IEI|DMV_IEO); ! 479: } ! 480: splx(sps); ! 481: } ! 482: /* ! 483: * DMV interface input interrupt. ! 484: * Ready to accept another command, ! 485: * pull one off the command queue. ! 486: */ ! 487: dmvrint(unit) ! 488: int unit; ! 489: { ! 490: register struct dmv_softc *sc; ! 491: register struct dmvdevice *addr; ! 492: register struct dmv_command *qp; ! 493: register int n; ! 494: ! 495: addr = (struct dmvdevice *)dmvinfo[unit]->ui_addr; ! 496: sc = &dmv_softc[unit]; ! 497: splx(sc->sc_ipl); ! 498: printd(("dmvrint\n")); ! 499: if ((qp = sc->sc_qactive) == (struct dmv_command *) 0) { ! 500: log(LOG_WARNING, "dmvrint: dmv%d no command\n", unit); ! 501: return; ! 502: } ! 503: while (addr->bsel2&DMV_RDI) { ! 504: if(qp->qp_mask&QP_SEL4) ! 505: addr->wsel4 = qp->qp_sel4; ! 506: if(qp->qp_mask&QP_SEL6) ! 507: addr->wsel6 = qp->qp_sel6; ! 508: if(qp->qp_mask&QP_SEL10) { ! 509: addr->wsel10 = qp->qp_sel10; ! 510: qp->qp_cmd |= DMV_22BIT; ! 511: } ! 512: if(qp->qp_mask&QP_TRIB) ! 513: addr->wsel2 = qp->qp_cmd|(qp->qp_tributary << 8); ! 514: else ! 515: addr->bsel2 = qp->qp_cmd; ! 516: QUEUE_AT_HEAD(qp, sc->sc_qfreeh, sc->sc_qfreet); ! 517: if ((sc->sc_qactive = sc->sc_qhead) == (struct dmv_command *)0) ! 518: break; ! 519: qp = sc->sc_qactive; ! 520: DEQUEUE(sc->sc_qhead, sc->sc_qtail); ! 521: if (addr->bsel2&DMV_RDO) ! 522: break; ! 523: } ! 524: if (!sc->sc_qactive) { ! 525: if(addr->bsel2&DMV_RDI) { ! 526: /* clear RQI prior to last command per DMV manual */ ! 527: addr->bsel0 &= ~DMV_RQI; ! 528: addr->wsel6 = DMV_NOP; ! 529: addr->bsel2 = DMV_CNTRLI; ! 530: } ! 531: addr->bsel0 = DMV_IEO; ! 532: } ! 533: else /* RDO set or DMV still holding CSR */ ! 534: addr->bsel0 = (DMV_RQI|DMV_IEI|DMV_IEO); ! 535: ! 536: } ! 537: ! 538: /* ! 539: * DMV interface output interrupt. ! 540: * A transfer may have completed, check for errors. ! 541: * If it was a read, notify appropriate protocol. ! 542: * If it was a write, pull the next one off the queue. ! 543: */ ! 544: dmvxint(unit) ! 545: int unit; ! 546: { ! 547: register struct dmv_softc *sc; ! 548: register struct ifnet *ifp; ! 549: struct uba_device *ui = dmvinfo[unit]; ! 550: struct dmvdevice *addr; ! 551: struct mbuf *m; ! 552: struct ifqueue *inq; ! 553: int sel2, sel3, sel4, sel6, sel10, pkaddr, len, s; ! 554: register struct ifrw *ifrw; ! 555: register struct dmvbufs *rp; ! 556: register struct ifxmt *ifxp; ! 557: struct dmv_header *dh; ! 558: int off, resid; ! 559: ! 560: addr = (struct dmvdevice *)ui->ui_addr; ! 561: sc = &dmv_softc[unit]; ! 562: splx(sc->sc_ipl); ! 563: ifp = &sc->sc_if; ! 564: ! 565: while (addr->bsel2 & DMV_RDO) { ! 566: ! 567: sel2 = addr->bsel2; ! 568: sel3 = addr->bsel3; ! 569: sel4 = addr->wsel4; /* release port */ ! 570: sel6 = addr->wsel6; ! 571: if(sel2 & DMV_22BIT) ! 572: sel10 = addr->wsel10; ! 573: addr->bsel2 &= ~DMV_RDO; ! 574: pkaddr = sel4 | ((sel6 & 0x3f) << 16); ! 575: printd(("dmvxint: sel2=%x sel4=%x sel6=%x sel10=%x pkaddr=%x\n", ! 576: (unsigned) sel2, ! 577: (unsigned) sel4, ! 578: (unsigned) sel6, ! 579: (unsigned) sel10, ! 580: (unsigned) pkaddr ! 581: )); ! 582: if((sc->sc_flag & DMV_RUNNING)==0) { ! 583: log(LOG_WARNING, "dmvxint: dmv%d xint while down\n", unit); ! 584: return; ! 585: } ! 586: switch (sel2 & 07) { ! 587: case DMV_BDRUS: ! 588: /* ! 589: * A read has completed. ! 590: * Pass packet to type specific ! 591: * higher-level input routine. ! 592: */ ! 593: ifp->if_ipackets++; ! 594: /* find location in dmvuba struct */ ! 595: ifrw= &sc->sc_ifr[0]; ! 596: for (rp = &sc->sc_rbufs[0]; rp < &sc->sc_rbufs[NRCV]; rp++) { ! 597: if(rp->ubinfo == pkaddr) ! 598: break; ! 599: ifrw++; ! 600: } ! 601: if (rp >= &sc->sc_rbufs[NRCV]) ! 602: panic("dmv rcv"); ! 603: if ((rp->flags & DBUF_DMVS) == 0) ! 604: log(LOG_WARNING, "dmvxint: dmv%d done unalloc rbuf\n", unit); ! 605: ! 606: len = (sel10&0x3fff) - sizeof (struct dmv_header); ! 607: if (len < 0 || len > DMVMTU) { ! 608: ifp->if_ierrors++; ! 609: log(LOG_ERR, "dmvxint: dmv%d bad rcv pkt addr 0x%x len 0x%x\n", ! 610: unit, pkaddr, len); ! 611: goto setup; ! 612: } ! 613: /* ! 614: * Deal with trailer protocol: if type is trailer ! 615: * get true type from first 16-bit word past data. ! 616: * Remember that type was trailer by setting off. ! 617: */ ! 618: dh = (struct dmv_header *)ifrw->ifrw_addr; ! 619: dh->dmv_type = ntohs((u_short)dh->dmv_type); ! 620: #define dmvdataaddr(dh, off, type) ((type)(((caddr_t)((dh)+1)+(off)))) ! 621: if (dh->dmv_type >= DMV_TRAILER && ! 622: dh->dmv_type < DMV_TRAILER+DMV_NTRAILER) { ! 623: off = (dh->dmv_type - DMV_TRAILER) * 512; ! 624: if (off >= DMVMTU) ! 625: goto setup; /* sanity */ ! 626: dh->dmv_type = ntohs(*dmvdataaddr(dh, off, u_short *)); ! 627: resid = ntohs(*(dmvdataaddr(dh, off+2, u_short *))); ! 628: if (off + resid > len) ! 629: goto setup; /* sanity */ ! 630: len = off + resid; ! 631: } else ! 632: off = 0; ! 633: if (len == 0) ! 634: goto setup; ! 635: ! 636: /* ! 637: * Pull packet off interface. Off is nonzero if ! 638: * packet has trailing header; dmv_get will then ! 639: * force this header information to be at the front, ! 640: * but we still have to drop the type and length ! 641: * which are at the front of any trailer data. ! 642: */ ! 643: m = if_ubaget(&sc->sc_ifuba, ifrw, len, off, ifp); ! 644: if (m == 0) ! 645: goto setup; ! 646: switch (dh->dmv_type) { ! 647: #ifdef INET ! 648: case DMV_IPTYPE: ! 649: schednetisr(NETISR_IP); ! 650: inq = &ipintrq; ! 651: break; ! 652: #endif ! 653: default: ! 654: m_freem(m); ! 655: goto setup; ! 656: } ! 657: ! 658: s = splimp(); ! 659: if (IF_QFULL(inq)) { ! 660: IF_DROP(inq); ! 661: m_freem(m); ! 662: } else ! 663: IF_ENQUEUE(inq, m); ! 664: splx(s); ! 665: setup: ! 666: /* is this needed? */ ! 667: rp->ubinfo = UBAI_ADDR(ifrw->ifrw_info); ! 668: dmvload( ! 669: sc, ! 670: DMV_BACCR, ! 671: QP_SEL4|QP_SEL6|QP_SEL10, ! 672: 0, ! 673: (u_short) rp->ubinfo, ! 674: (rp->ubinfo>>16)&0x3f, ! 675: rp->cc ! 676: ); ! 677: break; ! 678: case DMV_BDXSA: ! 679: /* ! 680: * A write has completed, start another ! 681: * transfer if there is more data to send. ! 682: */ ! 683: ifp->if_opackets++; ! 684: /* find associated dmvbuf structure */ ! 685: ifxp = &sc->sc_ifw[0]; ! 686: for (rp = &sc->sc_xbufs[0]; rp < &sc->sc_xbufs[NXMT]; rp++) { ! 687: if(rp->ubinfo == pkaddr) ! 688: break; ! 689: ifxp++; ! 690: } ! 691: if (rp >= &sc->sc_xbufs[NXMT]) { ! 692: log(LOG_ERR, "dmv%d: bad packet address 0x%x\n", ! 693: unit, pkaddr); ! 694: break; ! 695: } ! 696: if ((rp->flags & DBUF_DMVS) == 0) ! 697: log(LOG_ERR, "dmvxint: dmv%d unallocated packet 0x%x\n", ! 698: unit, pkaddr); ! 699: /* mark buffer free */ ! 700: if (ifxp->ifw_xtofree) { ! 701: (void)m_freem(ifxp->ifw_xtofree); ! 702: ifxp->ifw_xtofree = 0; ! 703: } ! 704: rp->flags &= ~DBUF_DMVS; ! 705: if (--sc->sc_oused == 0) ! 706: sc->sc_if.if_timer = 0; ! 707: else ! 708: sc->sc_if.if_timer = dmv_timeout; ! 709: if ((sc->sc_flag & DMV_ONLINE) == 0) { ! 710: extern int ifqmaxlen; ! 711: ! 712: /* ! 713: * We're on the air. ! 714: * Open the queue to the usual value. ! 715: */ ! 716: sc->sc_flag |= DMV_ONLINE; ! 717: ifp->if_snd.ifq_maxlen = ifqmaxlen; ! 718: } ! 719: break; ! 720: ! 721: case DMV_CNTRLO: ! 722: /* ACCUMULATE STATISTICS */ ! 723: switch(sel6&DMV_EEC) { ! 724: case DMV_ORUN: ! 725: if(sc->sc_flag & DMV_RESTART) { ! 726: load_rec_bufs(sc); ! 727: sc->sc_flag &= ~DMV_RESTART; ! 728: log(LOG_INFO, ! 729: "dmv%d: far end on-line\n", unit); ! 730: } else { ! 731: log(LOG_WARNING, ! 732: "dmv%d: far end restart\n", unit); ! 733: goto restart; ! 734: } ! 735: break; ! 736: case DMV_RTE: ! 737: ifp->if_ierrors++; ! 738: if ((sc->sc_rte++ % DMV_RPRTE) == 0) ! 739: log(LOG_WARNING, ! 740: "dmv%d: receive threshold error\n", ! 741: unit); ! 742: break; ! 743: case DMV_TTE: ! 744: ifp->if_oerrors++; ! 745: if ((sc->sc_xte++ % DMV_RPTTE) == 0) ! 746: log(LOG_WARNING, ! 747: "dmv%d: transmit threshold error\n", ! 748: unit); ! 749: break; ! 750: case DMV_STE: ! 751: if ((sc->sc_ste++ % DMV_RPSTE) == 0) ! 752: log(LOG_WARNING, ! 753: "dmv%d: select threshold error\n", ! 754: unit); ! 755: break; ! 756: case DMV_NXM: ! 757: if ((sc->sc_nxm++ % DMV_RPNXM) == 0) ! 758: log(LOG_WARNING, ! 759: "dmv%d: nonexistent memory error\n", ! 760: unit); ! 761: break; ! 762: case DMV_MODD: ! 763: if ((sc->sc_modd++ % DMV_RPMODD) == 0) { ! 764: log(LOG_WARNING, ! 765: "dmv%d: modem disconnected error\n", ! 766: unit); ! 767: goto restart; ! 768: } ! 769: break; ! 770: case DMV_CXRL: ! 771: if ((sc->sc_cxrl++ % DMV_RPCXRL) == 0) ! 772: log(LOG_WARNING, ! 773: "dmv%d: carrier loss error\n", ! 774: unit); ! 775: break; ! 776: case DMV_QOVF: ! 777: log(LOG_WARNING, ! 778: "dmv%d: response queue overflow\n", ! 779: unit); ! 780: sc->sc_qovf++; ! 781: goto restart; ! 782: ! 783: default: ! 784: log(LOG_WARNING, ! 785: "dmv%d: unknown error %o\n", ! 786: unit, sel6&DMV_EEC); ! 787: if ((sc->sc_unknown++ % DMV_RPUNKNOWN) == 0) ! 788: goto restart; ! 789: break; ! 790: } ! 791: break; ! 792: ! 793: case DMV_BDRUNUS: ! 794: case DMV_BDXSN: ! 795: case DMV_BDXNS: ! 796: log(LOG_INFO, ! 797: "dmv%d: buffer disp for halted trib %o\n", ! 798: unit, sel2&0x7 ! 799: ); ! 800: break; ! 801: ! 802: case DMV_MDEFO: ! 803: if((sel6&0x1f) == 020) { ! 804: log(LOG_INFO, ! 805: "dmv%d: buffer return complete sel3=%x\n", ! 806: unit, sel3); ! 807: } else { ! 808: log(LOG_INFO, ! 809: "dmv%d: info resp sel3=%x sel4=%x sel6=%x\n", ! 810: unit, sel3, sel4, sel6 ! 811: ); ! 812: } ! 813: break; ! 814: ! 815: default: ! 816: log(LOG_WARNING, "dmv%d: bad control %o\n", ! 817: unit, sel2&0x7 ! 818: ); ! 819: break; ! 820: } ! 821: } ! 822: dmvstart(unit); ! 823: return; ! 824: restart: ! 825: dmvrestart(unit); ! 826: } ! 827: ! 828: load_rec_bufs(sc) ! 829: register struct dmv_softc *sc; ! 830: { ! 831: register struct dmvbufs *rp; ! 832: ! 833: /* queue first NRCV buffers for DMV to fill */ ! 834: for (rp = &sc->sc_rbufs[0]; rp < &sc->sc_rbufs[NRCV]; rp++) { ! 835: rp->flags |= DBUF_DMVS; ! 836: dmvload( ! 837: sc, ! 838: DMV_BACCR, ! 839: QP_TRIB|QP_SEL4|QP_SEL6|QP_SEL10, ! 840: 1, ! 841: rp->ubinfo, ! 842: (rp->ubinfo>>16)&0x3f, ! 843: rp->cc ! 844: ); ! 845: sc->sc_iused++; ! 846: } ! 847: } ! 848: ! 849: /* ! 850: * DMV output routine. ! 851: * Encapsulate a packet of type family for the dmv. ! 852: * Use trailer local net encapsulation if enough data in first ! 853: * packet leaves a multiple of 512 bytes of data in remainder. ! 854: */ ! 855: dmvoutput(ifp, m0, dst) ! 856: register struct ifnet *ifp; ! 857: register struct mbuf *m0; ! 858: struct sockaddr *dst; ! 859: { ! 860: int type, error, s; ! 861: register struct mbuf *m = m0; ! 862: register struct dmv_header *dh; ! 863: register int off; ! 864: ! 865: if ((ifp->if_flags & IFF_UP) == 0) { ! 866: error = ENETDOWN; ! 867: goto bad; ! 868: } ! 869: ! 870: switch (dst->sa_family) { ! 871: #ifdef INET ! 872: case AF_INET: ! 873: off = m->m_pkthdr.len - m->m_len; ! 874: if ((ifp->if_flags & IFF_NOTRAILERS) == 0) ! 875: if (off > 0 && (off & 0x1ff) == 0 && ! 876: (m->m_flags & M_EXT) == 0 && ! 877: m->m_data >= m->m_pktdat + 2 * sizeof (u_short)) { ! 878: type = DMV_TRAILER + (off>>9); ! 879: m->m_data -= 2 * sizeof (u_short); ! 880: m->m_len += 2 * sizeof (u_short); ! 881: *mtod(m, u_short *) = htons((u_short)DMV_IPTYPE); ! 882: *(mtod(m, u_short *) + 1) = htons((u_short)m->m_len); ! 883: goto gottrailertype; ! 884: } ! 885: type = DMV_IPTYPE; ! 886: off = 0; ! 887: goto gottype; ! 888: #endif ! 889: ! 890: case AF_UNSPEC: ! 891: dh = (struct dmv_header *)dst->sa_data; ! 892: type = dh->dmv_type; ! 893: goto gottype; ! 894: ! 895: default: ! 896: log(LOG_ERR, "dmvoutput, dmv%d can't handle af%d\n", ! 897: ifp->if_unit, dst->sa_family); ! 898: error = EAFNOSUPPORT; ! 899: goto bad; ! 900: } ! 901: ! 902: gottrailertype: ! 903: /* ! 904: * Packet to be sent as a trailer; move first packet ! 905: * (control information) to end of chain. ! 906: */ ! 907: while (m->m_next) ! 908: m = m->m_next; ! 909: m->m_next = m0; ! 910: m = m0->m_next; ! 911: m0->m_next = 0; ! 912: m0 = m; ! 913: ! 914: gottype: ! 915: /* ! 916: * Add local network header ! 917: * (there is space for a uba on a vax to step on) ! 918: */ ! 919: M_PREPEND(m, sizeof(struct dmv_header), M_DONTWAIT); ! 920: if (m == 0) { ! 921: error = ENOBUFS; ! 922: goto bad; ! 923: } ! 924: dh = mtod(m, struct dmv_header *); ! 925: dh->dmv_type = htons((u_short)type); ! 926: ! 927: /* ! 928: * Queue message on interface, and start output if interface ! 929: * not yet active. ! 930: */ ! 931: s = splimp(); ! 932: if (IF_QFULL(&ifp->if_snd)) { ! 933: IF_DROP(&ifp->if_snd); ! 934: m_freem(m); ! 935: splx(s); ! 936: return (ENOBUFS); ! 937: } ! 938: IF_ENQUEUE(&ifp->if_snd, m); ! 939: dmvstart(ifp->if_unit); ! 940: splx(s); ! 941: return (0); ! 942: ! 943: bad: ! 944: m_freem(m0); ! 945: return (error); ! 946: } ! 947: ! 948: ! 949: /* ! 950: * Process an ioctl request. ! 951: */ ! 952: /* ARGSUSED */ ! 953: dmvioctl(ifp, cmd, data) ! 954: register struct ifnet *ifp; ! 955: int cmd; ! 956: caddr_t data; ! 957: { ! 958: int s = splimp(), error = 0; ! 959: struct mbuf *m; ! 960: register struct dmv_softc *sc = &dmv_softc[ifp->if_unit]; ! 961: ! 962: switch (cmd) { ! 963: ! 964: case SIOCSIFADDR: ! 965: ifp->if_flags |= IFF_UP; ! 966: if ((ifp->if_flags & IFF_RUNNING) == 0) ! 967: dmvinit(ifp->if_unit); ! 968: break; ! 969: ! 970: case SIOCSIFDSTADDR: ! 971: if ((ifp->if_flags & IFF_RUNNING) == 0) ! 972: dmvinit(ifp->if_unit); ! 973: break; ! 974: ! 975: case SIOCSIFFLAGS: ! 976: if ((ifp->if_flags & IFF_UP) == 0 && ! 977: sc->sc_flag & DMV_RUNNING) ! 978: dmvdown(ifp->if_unit); ! 979: else if (ifp->if_flags & IFF_UP && ! 980: (sc->sc_flag & DMV_RUNNING) == 0) ! 981: dmvrestart(ifp->if_unit); ! 982: break; ! 983: ! 984: default: ! 985: error = EINVAL; ! 986: } ! 987: splx(s); ! 988: return (error); ! 989: } ! 990: ! 991: /* ! 992: * Restart after a fatal error. ! 993: * Clear device and reinitialize. ! 994: */ ! 995: dmvrestart(unit) ! 996: int unit; ! 997: { ! 998: register struct dmvdevice *addr; ! 999: register int i; ! 1000: ! 1001: dmvdown(unit); ! 1002: ! 1003: addr = (struct dmvdevice *)(dmvinfo[unit]->ui_addr); ! 1004: /* ! 1005: * Let the DMV finish the MCLR. ! 1006: */ ! 1007: for (i = 100000; i && (addr->bsel1 & DMV_RUN) == 0; i--) ! 1008: ; ! 1009: if ((addr->bsel1 & DMV_RUN) == 0) { ! 1010: log(LOG_ERR, "dmvrestart: can't start device\n" ); ! 1011: return (0); ! 1012: } ! 1013: if ((addr->bsel4 != 033) || (addr->bsel6 != 0305)) ! 1014: { ! 1015: log(LOG_ERR, "dmv%d: device init failed, bsel4=%o, bsel6=%o\n", ! 1016: unit, addr->bsel4, addr->bsel6); ! 1017: return (0); ! 1018: } ! 1019: ! 1020: /* restart DMV */ ! 1021: dmvinit(unit); ! 1022: dmv_softc[unit].sc_if.if_collisions++; /* why not? */ ! 1023: } ! 1024: ! 1025: /* ! 1026: * Reset a device and mark down. ! 1027: * Flush output queue and drop queue limit. ! 1028: */ ! 1029: dmvdown(unit) ! 1030: int unit; ! 1031: { ! 1032: struct dmv_softc *sc = &dmv_softc[unit]; ! 1033: register struct ifxmt *ifxp; ! 1034: ! 1035: ((struct dmvdevice *)(dmvinfo[unit]->ui_addr))->bsel1 = DMV_MCLR; ! 1036: sc->sc_flag &= ~(DMV_RUNNING | DMV_ONLINE); ! 1037: ! 1038: for (ifxp = sc->sc_ifw; ifxp < &sc->sc_ifw[NXMT]; ifxp++) { ! 1039: if (ifxp->ifw_xtofree) { ! 1040: (void) m_freem(ifxp->ifw_xtofree); ! 1041: ifxp->ifw_xtofree = 0; ! 1042: } ! 1043: } ! 1044: sc->sc_oused = 0; ! 1045: if_qflush(&sc->sc_if.if_snd); ! 1046: ! 1047: /* ! 1048: * Limit packets enqueued until we're back on the air. ! 1049: */ ! 1050: sc->sc_if.if_snd.ifq_maxlen = 3; ! 1051: } ! 1052: ! 1053: /* ! 1054: * Watchdog timeout to see that transmitted packets don't ! 1055: * lose interrupts. The device has to be online. ! 1056: */ ! 1057: dmvtimeout(unit) ! 1058: int unit; ! 1059: { ! 1060: register struct dmv_softc *sc; ! 1061: struct dmvdevice *addr; ! 1062: ! 1063: sc = &dmv_softc[unit]; ! 1064: if (sc->sc_flag & DMV_ONLINE) { ! 1065: addr = (struct dmvdevice *)(dmvinfo[unit]->ui_addr); ! 1066: log(LOG_ERR, "dmv%d: output timeout, bsel0=%b bsel2=%b\n", ! 1067: unit, addr->bsel0 & 0xff, DMV0BITS, ! 1068: addr->bsel2 & 0xff, DMV2BITS); ! 1069: dmvrestart(unit); ! 1070: } ! 1071: } ! 1072: #endif
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.