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