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