|
|
1.1 ! root 1: /* ! 2: * Copyright (c) 1982, 1986 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_dmc.c 7.10 (Berkeley) 12/16/90 ! 34: */ ! 35: ! 36: #include "dmc.h" ! 37: #if NDMC > 0 ! 38: ! 39: /* ! 40: * DMC11 device driver, internet version ! 41: * ! 42: * Bill Nesheim ! 43: * Cornell University ! 44: * ! 45: * Lou Salkind ! 46: * New York University ! 47: */ ! 48: ! 49: /* #define DEBUG /* for base table dump on fatal error */ ! 50: ! 51: #include "../include/pte.h" ! 52: ! 53: #include "sys/param.h" ! 54: #include "sys/systm.h" ! 55: #include "sys/mbuf.h" ! 56: #include "sys/buf.h" ! 57: #include "sys/ioctl.h" /* must precede tty.h */ ! 58: #include "sys/tty.h" ! 59: #include "sys/protosw.h" ! 60: #include "sys/socket.h" ! 61: #include "sys/syslog.h" ! 62: #include "sys/vmmac.h" ! 63: #include "sys/errno.h" ! 64: #include "sys/time.h" ! 65: #include "sys/kernel.h" ! 66: ! 67: #include "net/if.h" ! 68: #include "net/netisr.h" ! 69: #include "net/route.h" ! 70: ! 71: #ifdef INET ! 72: #include "netinet/in.h" ! 73: #include "netinet/in_systm.h" ! 74: #include "netinet/in_var.h" ! 75: #include "netinet/ip.h" ! 76: #endif ! 77: ! 78: #include "../include/cpu.h" ! 79: #include "../include/mtpr.h" ! 80: #include "if_uba.h" ! 81: #include "if_dmc.h" ! 82: #include "../uba/ubareg.h" ! 83: #include "../uba/ubavar.h" ! 84: ! 85: ! 86: /* ! 87: * output timeout value, sec.; should depend on line speed. ! 88: */ ! 89: int dmc_timeout = 20; ! 90: ! 91: /* ! 92: * Driver information for auto-configuration stuff. ! 93: */ ! 94: int dmcprobe(), dmcattach(), dmcinit(), dmcioctl(); ! 95: int dmcoutput(), dmcreset(), dmctimeout(); ! 96: struct uba_device *dmcinfo[NDMC]; ! 97: u_short dmcstd[] = { 0 }; ! 98: struct uba_driver dmcdriver = ! 99: { dmcprobe, 0, dmcattach, 0, dmcstd, "dmc", dmcinfo }; ! 100: ! 101: #define NRCV 7 ! 102: #define NXMT 3 ! 103: #define NCMDS (NRCV+NXMT+4) /* size of command queue */ ! 104: ! 105: #define printd if(dmcdebug)printf ! 106: int dmcdebug = 0; ! 107: ! 108: /* error reporting intervals */ ! 109: #define DMC_RPNBFS 50 ! 110: #define DMC_RPDSC 1 ! 111: #define DMC_RPTMO 10 ! 112: #define DMC_RPDCK 10 ! 113: ! 114: struct dmc_command { ! 115: char qp_cmd; /* command */ ! 116: short qp_ubaddr; /* buffer address */ ! 117: short qp_cc; /* character count || XMEM */ ! 118: struct dmc_command *qp_next; /* next command on queue */ ! 119: }; ! 120: ! 121: struct dmcbufs { ! 122: int ubinfo; /* from uballoc */ ! 123: short cc; /* buffer size */ ! 124: short flags; /* access control */ ! 125: }; ! 126: #define DBUF_OURS 0 /* buffer is available */ ! 127: #define DBUF_DMCS 1 /* buffer claimed by somebody */ ! 128: #define DBUF_XMIT 4 /* transmit buffer */ ! 129: #define DBUF_RCV 8 /* receive buffer */ ! 130: ! 131: ! 132: /* ! 133: * DMC software status per interface. ! 134: * ! 135: * Each interface is referenced by a network interface structure, ! 136: * sc_if, which the routing code uses to locate the interface. ! 137: * This structure contains the output queue for the interface, its address, ... ! 138: * We also have, for each interface, a set of 7 UBA interface structures ! 139: * for each, which ! 140: * contain information about the UNIBUS resources held by the interface: ! 141: * map registers, buffered data paths, etc. Information is cached in this ! 142: * structure for use by the if_uba.c routines in running the interface ! 143: * efficiently. ! 144: */ ! 145: struct dmc_softc { ! 146: struct ifnet sc_if; /* network-visible interface */ ! 147: short sc_oused; /* output buffers currently in use */ ! 148: short sc_iused; /* input buffers given to DMC */ ! 149: short sc_flag; /* flags */ ! 150: int sc_ubinfo; /* UBA mapping info for base table */ ! 151: int sc_errors[4]; /* non-fatal error counters */ ! 152: #define sc_datck sc_errors[0] ! 153: #define sc_timeo sc_errors[1] ! 154: #define sc_nobuf sc_errors[2] ! 155: #define sc_disc sc_errors[3] ! 156: struct dmcbufs sc_rbufs[NRCV]; /* receive buffer info */ ! 157: struct dmcbufs sc_xbufs[NXMT]; /* transmit buffer info */ ! 158: struct ifubinfo sc_ifuba; /* UNIBUS resources */ ! 159: struct ifrw sc_ifr[NRCV]; /* UNIBUS receive buffer maps */ ! 160: struct ifxmt sc_ifw[NXMT]; /* UNIBUS receive buffer maps */ ! 161: /* command queue stuff */ ! 162: struct dmc_command sc_cmdbuf[NCMDS]; ! 163: struct dmc_command *sc_qhead; /* head of command queue */ ! 164: struct dmc_command *sc_qtail; /* tail of command queue */ ! 165: struct dmc_command *sc_qactive; /* command in progress */ ! 166: struct dmc_command *sc_qfreeh; /* head of list of free cmd buffers */ ! 167: struct dmc_command *sc_qfreet; /* tail of list of free cmd buffers */ ! 168: /* end command queue stuff */ ! 169: } dmc_softc[NDMC]; ! 170: ! 171: /* flags */ ! 172: #define DMC_RUNNING 0x01 /* device initialized */ ! 173: #define DMC_BMAPPED 0x02 /* base table mapped */ ! 174: #define DMC_RESTART 0x04 /* software restart in progress */ ! 175: #define DMC_ONLINE 0x08 /* device running (had a RDYO) */ ! 176: ! 177: struct dmc_base { ! 178: short d_base[128]; /* DMC base table */ ! 179: } dmc_base[NDMC]; ! 180: ! 181: /* queue manipulation macros */ ! 182: #define QUEUE_AT_HEAD(qp, head, tail) \ ! 183: (qp)->qp_next = (head); \ ! 184: (head) = (qp); \ ! 185: if ((tail) == (struct dmc_command *) 0) \ ! 186: (tail) = (head) ! 187: ! 188: #define QUEUE_AT_TAIL(qp, head, tail) \ ! 189: if ((tail)) \ ! 190: (tail)->qp_next = (qp); \ ! 191: else \ ! 192: (head) = (qp); \ ! 193: (qp)->qp_next = (struct dmc_command *) 0; \ ! 194: (tail) = (qp) ! 195: ! 196: #define DEQUEUE(head, tail) \ ! 197: (head) = (head)->qp_next;\ ! 198: if ((head) == (struct dmc_command *) 0)\ ! 199: (tail) = (head) ! 200: ! 201: dmcprobe(reg) ! 202: caddr_t reg; ! 203: { ! 204: register int br, cvec; ! 205: register struct dmcdevice *addr = (struct dmcdevice *)reg; ! 206: register int i; ! 207: ! 208: #ifdef lint ! 209: br = 0; cvec = br; br = cvec; ! 210: dmcrint(0); dmcxint(0); ! 211: #endif ! 212: addr->bsel1 = DMC_MCLR; ! 213: for (i = 100000; i && (addr->bsel1 & DMC_RUN) == 0; i--) ! 214: ; ! 215: if ((addr->bsel1 & DMC_RUN) == 0) { ! 216: printf("dmcprobe: can't start device\n" ); ! 217: return (0); ! 218: } ! 219: addr->bsel0 = DMC_RQI|DMC_IEI; ! 220: /* let's be paranoid */ ! 221: addr->bsel0 |= DMC_RQI|DMC_IEI; ! 222: DELAY(1000000); ! 223: addr->bsel1 = DMC_MCLR; ! 224: for (i = 100000; i && (addr->bsel1 & DMC_RUN) == 0; i--) ! 225: ; ! 226: return (1); ! 227: } ! 228: ! 229: /* ! 230: * Interface exists: make available by filling in network interface ! 231: * record. System will initialize the interface when it is ready ! 232: * to accept packets. ! 233: */ ! 234: dmcattach(ui) ! 235: register struct uba_device *ui; ! 236: { ! 237: register struct dmc_softc *sc = &dmc_softc[ui->ui_unit]; ! 238: ! 239: sc->sc_if.if_unit = ui->ui_unit; ! 240: sc->sc_if.if_name = "dmc"; ! 241: sc->sc_if.if_mtu = DMCMTU; ! 242: sc->sc_if.if_init = dmcinit; ! 243: sc->sc_if.if_output = dmcoutput; ! 244: sc->sc_if.if_ioctl = dmcioctl; ! 245: sc->sc_if.if_reset = dmcreset; ! 246: sc->sc_if.if_watchdog = dmctimeout; ! 247: sc->sc_if.if_flags = IFF_POINTOPOINT; ! 248: sc->sc_ifuba.iff_flags = UBA_CANTWAIT; ! 249: ! 250: if_attach(&sc->sc_if); ! 251: } ! 252: ! 253: /* ! 254: * Reset of interface after UNIBUS reset. ! 255: * If interface is on specified UBA, reset its state. ! 256: */ ! 257: dmcreset(unit, uban) ! 258: int unit, uban; ! 259: { ! 260: register struct uba_device *ui; ! 261: register struct dmc_softc *sc = &dmc_softc[unit]; ! 262: ! 263: if (unit >= NDMC || (ui = dmcinfo[unit]) == 0 || ui->ui_alive == 0 || ! 264: ui->ui_ubanum != uban) ! 265: return; ! 266: printf(" dmc%d", unit); ! 267: sc->sc_flag = 0; ! 268: sc->sc_if.if_flags &= ~IFF_RUNNING; ! 269: dmcinit(unit); ! 270: } ! 271: ! 272: /* ! 273: * Initialization of interface; reinitialize UNIBUS usage. ! 274: */ ! 275: dmcinit(unit) ! 276: int unit; ! 277: { ! 278: register struct dmc_softc *sc = &dmc_softc[unit]; ! 279: register struct uba_device *ui = dmcinfo[unit]; ! 280: register struct dmcdevice *addr; ! 281: register struct ifnet *ifp = &sc->sc_if; ! 282: register struct ifrw *ifrw; ! 283: register struct ifxmt *ifxp; ! 284: register struct dmcbufs *rp; ! 285: register struct dmc_command *qp; ! 286: struct ifaddr *ifa; ! 287: int base; ! 288: int s; ! 289: ! 290: addr = (struct dmcdevice *)ui->ui_addr; ! 291: ! 292: /* ! 293: * Check to see that an address has been set ! 294: * (both local and destination for an address family). ! 295: */ ! 296: for (ifa = ifp->if_addrlist; ifa; ifa = ifa->ifa_next) ! 297: if (ifa->ifa_addr->sa_family && ifa->ifa_dstaddr->sa_family) ! 298: break; ! 299: if (ifa == (struct ifaddr *) 0) ! 300: return; ! 301: ! 302: if ((addr->bsel1&DMC_RUN) == 0) { ! 303: printf("dmcinit: DMC not running\n"); ! 304: ifp->if_flags &= ~IFF_UP; ! 305: return; ! 306: } ! 307: /* map base table */ ! 308: if ((sc->sc_flag & DMC_BMAPPED) == 0) { ! 309: sc->sc_ubinfo = uballoc(ui->ui_ubanum, ! 310: (caddr_t)&dmc_base[unit], sizeof (struct dmc_base), 0); ! 311: sc->sc_flag |= DMC_BMAPPED; ! 312: } ! 313: /* initialize UNIBUS resources */ ! 314: sc->sc_iused = sc->sc_oused = 0; ! 315: if ((ifp->if_flags & IFF_RUNNING) == 0) { ! 316: if (if_ubaminit(&sc->sc_ifuba, ui->ui_ubanum, ! 317: sizeof(struct dmc_header), (int)btoc(DMCMTU), ! 318: sc->sc_ifr, NRCV, sc->sc_ifw, NXMT) == 0) { ! 319: printf("dmc%d: can't allocate uba resources\n", unit); ! 320: ifp->if_flags &= ~IFF_UP; ! 321: return; ! 322: } ! 323: ifp->if_flags |= IFF_RUNNING; ! 324: } ! 325: sc->sc_flag &= ~DMC_ONLINE; ! 326: sc->sc_flag |= DMC_RUNNING; ! 327: /* ! 328: * Limit packets enqueued until we see if we're on the air. ! 329: */ ! 330: ifp->if_snd.ifq_maxlen = 3; ! 331: ! 332: /* initialize buffer pool */ ! 333: /* receives */ ! 334: ifrw = &sc->sc_ifr[0]; ! 335: for (rp = &sc->sc_rbufs[0]; rp < &sc->sc_rbufs[NRCV]; rp++) { ! 336: rp->ubinfo = UBAI_ADDR(ifrw->ifrw_info); ! 337: rp->cc = DMCMTU + sizeof (struct dmc_header); ! 338: rp->flags = DBUF_OURS|DBUF_RCV; ! 339: ifrw++; ! 340: } ! 341: /* transmits */ ! 342: ifxp = &sc->sc_ifw[0]; ! 343: for (rp = &sc->sc_xbufs[0]; rp < &sc->sc_xbufs[NXMT]; rp++) { ! 344: rp->ubinfo = UBAI_ADDR(ifxp->ifw_info); ! 345: rp->cc = 0; ! 346: rp->flags = DBUF_OURS|DBUF_XMIT; ! 347: ifxp++; ! 348: } ! 349: ! 350: /* set up command queues */ ! 351: sc->sc_qfreeh = sc->sc_qfreet ! 352: = sc->sc_qhead = sc->sc_qtail = sc->sc_qactive = ! 353: (struct dmc_command *)0; ! 354: /* set up free command buffer list */ ! 355: for (qp = &sc->sc_cmdbuf[0]; qp < &sc->sc_cmdbuf[NCMDS]; qp++) { ! 356: QUEUE_AT_HEAD(qp, sc->sc_qfreeh, sc->sc_qfreet); ! 357: } ! 358: ! 359: /* base in */ ! 360: base = UBAI_ADDR(sc->sc_ubinfo); ! 361: dmcload(sc, DMC_BASEI, (u_short)base, (base>>2) & DMC_XMEM); ! 362: /* specify half duplex operation, flags tell if primary */ ! 363: /* or secondary station */ ! 364: if (ui->ui_flags == 0) ! 365: /* use DDCMP mode in full duplex */ ! 366: dmcload(sc, DMC_CNTLI, 0, 0); ! 367: else if (ui->ui_flags == 1) ! 368: /* use MAINTENENCE mode */ ! 369: dmcload(sc, DMC_CNTLI, 0, DMC_MAINT ); ! 370: else if (ui->ui_flags == 2) ! 371: /* use DDCMP half duplex as primary station */ ! 372: dmcload(sc, DMC_CNTLI, 0, DMC_HDPLX); ! 373: else if (ui->ui_flags == 3) ! 374: /* use DDCMP half duplex as secondary station */ ! 375: dmcload(sc, DMC_CNTLI, 0, DMC_HDPLX | DMC_SEC); ! 376: ! 377: /* enable operation done interrupts */ ! 378: while ((addr->bsel2 & DMC_IEO) == 0) ! 379: addr->bsel2 |= DMC_IEO; ! 380: s = spl5(); ! 381: /* queue first NRCV buffers for DMC to fill */ ! 382: for (rp = &sc->sc_rbufs[0]; rp < &sc->sc_rbufs[NRCV]; rp++) { ! 383: rp->flags |= DBUF_DMCS; ! 384: dmcload(sc, DMC_READ, rp->ubinfo, ! 385: (((rp->ubinfo>>2)&DMC_XMEM) | rp->cc)); ! 386: sc->sc_iused++; ! 387: } ! 388: splx(s); ! 389: } ! 390: ! 391: /* ! 392: * Start output on interface. Get another datagram ! 393: * to send from the interface queue and map it to ! 394: * the interface before starting output. ! 395: * ! 396: * Must be called at spl 5 ! 397: */ ! 398: dmcstart(unit) ! 399: int unit; ! 400: { ! 401: register struct dmc_softc *sc = &dmc_softc[unit]; ! 402: struct mbuf *m; ! 403: register struct dmcbufs *rp; ! 404: register int n; ! 405: ! 406: /* ! 407: * Dequeue up to NXMT requests and map them to the UNIBUS. ! 408: * If no more requests, or no dmc buffers available, just return. ! 409: */ ! 410: n = 0; ! 411: for (rp = &sc->sc_xbufs[0]; rp < &sc->sc_xbufs[NXMT]; rp++ ) { ! 412: /* find an available buffer */ ! 413: if ((rp->flags & DBUF_DMCS) == 0) { ! 414: IF_DEQUEUE(&sc->sc_if.if_snd, m); ! 415: if (m == 0) ! 416: return; ! 417: /* mark it dmcs */ ! 418: rp->flags |= (DBUF_DMCS); ! 419: /* ! 420: * Have request mapped to UNIBUS for transmission ! 421: * and start the output. ! 422: */ ! 423: rp->cc = if_ubaput(&sc->sc_ifuba, &sc->sc_ifw[n], m); ! 424: rp->cc &= DMC_CCOUNT; ! 425: if (++sc->sc_oused == 1) ! 426: sc->sc_if.if_timer = dmc_timeout; ! 427: dmcload(sc, DMC_WRITE, rp->ubinfo, ! 428: rp->cc | ((rp->ubinfo>>2)&DMC_XMEM)); ! 429: } ! 430: n++; ! 431: } ! 432: } ! 433: ! 434: /* ! 435: * Utility routine to load the DMC device registers. ! 436: */ ! 437: dmcload(sc, type, w0, w1) ! 438: register struct dmc_softc *sc; ! 439: int type; ! 440: u_short w0, w1; ! 441: { ! 442: register struct dmcdevice *addr; ! 443: register int unit, sps; ! 444: register struct dmc_command *qp; ! 445: ! 446: unit = sc - dmc_softc; ! 447: addr = (struct dmcdevice *)dmcinfo[unit]->ui_addr; ! 448: sps = spl5(); ! 449: ! 450: /* grab a command buffer from the free list */ ! 451: if ((qp = sc->sc_qfreeh) == (struct dmc_command *)0) ! 452: panic("dmc command queue overflow"); ! 453: DEQUEUE(sc->sc_qfreeh, sc->sc_qfreet); ! 454: ! 455: /* fill in requested info */ ! 456: qp->qp_cmd = (type | DMC_RQI); ! 457: qp->qp_ubaddr = w0; ! 458: qp->qp_cc = w1; ! 459: ! 460: if (sc->sc_qactive) { /* command in progress */ ! 461: if (type == DMC_READ) { ! 462: QUEUE_AT_HEAD(qp, sc->sc_qhead, sc->sc_qtail); ! 463: } else { ! 464: QUEUE_AT_TAIL(qp, sc->sc_qhead, sc->sc_qtail); ! 465: } ! 466: } else { /* command port free */ ! 467: sc->sc_qactive = qp; ! 468: addr->bsel0 = qp->qp_cmd; ! 469: dmcrint(unit); ! 470: } ! 471: splx(sps); ! 472: } ! 473: ! 474: /* ! 475: * DMC interface receiver interrupt. ! 476: * Ready to accept another command, ! 477: * pull one off the command queue. ! 478: */ ! 479: dmcrint(unit) ! 480: int unit; ! 481: { ! 482: register struct dmc_softc *sc; ! 483: register struct dmcdevice *addr; ! 484: register struct dmc_command *qp; ! 485: register int n; ! 486: ! 487: addr = (struct dmcdevice *)dmcinfo[unit]->ui_addr; ! 488: sc = &dmc_softc[unit]; ! 489: if ((qp = sc->sc_qactive) == (struct dmc_command *) 0) { ! 490: printf("dmc%d: dmcrint no command\n", unit); ! 491: return; ! 492: } ! 493: while (addr->bsel0&DMC_RDYI) { ! 494: addr->sel4 = qp->qp_ubaddr; ! 495: addr->sel6 = qp->qp_cc; ! 496: addr->bsel0 &= ~(DMC_IEI|DMC_RQI); ! 497: /* free command buffer */ ! 498: QUEUE_AT_HEAD(qp, sc->sc_qfreeh, sc->sc_qfreet); ! 499: while (addr->bsel0 & DMC_RDYI) { ! 500: /* ! 501: * Can't check for RDYO here 'cause ! 502: * this routine isn't reentrant! ! 503: */ ! 504: DELAY(5); ! 505: } ! 506: /* move on to next command */ ! 507: if ((sc->sc_qactive = sc->sc_qhead) == (struct dmc_command *)0) ! 508: break; /* all done */ ! 509: /* more commands to do, start the next one */ ! 510: qp = sc->sc_qactive; ! 511: DEQUEUE(sc->sc_qhead, sc->sc_qtail); ! 512: addr->bsel0 = qp->qp_cmd; ! 513: n = RDYSCAN; ! 514: while (n-- > 0) ! 515: if ((addr->bsel0&DMC_RDYI) || (addr->bsel2&DMC_RDYO)) ! 516: break; ! 517: } ! 518: if (sc->sc_qactive) { ! 519: addr->bsel0 |= DMC_IEI|DMC_RQI; ! 520: /* VMS does it twice !*$%@# */ ! 521: addr->bsel0 |= DMC_IEI|DMC_RQI; ! 522: } ! 523: ! 524: } ! 525: ! 526: /* ! 527: * DMC interface transmitter interrupt. ! 528: * A transfer may have completed, check for errors. ! 529: * If it was a read, notify appropriate protocol. ! 530: * If it was a write, pull the next one off the queue. ! 531: */ ! 532: dmcxint(unit) ! 533: int unit; ! 534: { ! 535: register struct dmc_softc *sc; ! 536: register struct ifnet *ifp; ! 537: struct uba_device *ui = dmcinfo[unit]; ! 538: struct dmcdevice *addr; ! 539: struct mbuf *m; ! 540: struct ifqueue *inq; ! 541: int arg, pkaddr, cmd, len, s; ! 542: register struct ifrw *ifrw; ! 543: register struct dmcbufs *rp; ! 544: register struct ifxmt *ifxp; ! 545: struct dmc_header *dh; ! 546: int off, resid; ! 547: ! 548: addr = (struct dmcdevice *)ui->ui_addr; ! 549: sc = &dmc_softc[unit]; ! 550: ifp = &sc->sc_if; ! 551: ! 552: while (addr->bsel2 & DMC_RDYO) { ! 553: ! 554: cmd = addr->bsel2 & 0xff; ! 555: arg = addr->sel6 & 0xffff; ! 556: /* reconstruct UNIBUS address of buffer returned to us */ ! 557: pkaddr = ((arg&DMC_XMEM)<<2) | (addr->sel4 & 0xffff); ! 558: /* release port */ ! 559: addr->bsel2 &= ~DMC_RDYO; ! 560: switch (cmd & 07) { ! 561: ! 562: case DMC_OUR: ! 563: /* ! 564: * A read has completed. ! 565: * Pass packet to type specific ! 566: * higher-level input routine. ! 567: */ ! 568: ifp->if_ipackets++; ! 569: /* find location in dmcuba struct */ ! 570: ifrw= &sc->sc_ifr[0]; ! 571: for (rp = &sc->sc_rbufs[0]; rp < &sc->sc_rbufs[NRCV]; rp++) { ! 572: if(rp->ubinfo == pkaddr) ! 573: break; ! 574: ifrw++; ! 575: } ! 576: if (rp >= &sc->sc_rbufs[NRCV]) ! 577: panic("dmc rcv"); ! 578: if ((rp->flags & DBUF_DMCS) == 0) ! 579: printf("dmc%d: done unalloc rbuf\n", unit); ! 580: ! 581: len = (arg & DMC_CCOUNT) - sizeof (struct dmc_header); ! 582: if (len < 0 || len > DMCMTU) { ! 583: ifp->if_ierrors++; ! 584: printd("dmc%d: bad rcv pkt addr 0x%x len 0x%x\n", ! 585: unit, pkaddr, len); ! 586: goto setup; ! 587: } ! 588: /* ! 589: * Deal with trailer protocol: if type is trailer ! 590: * get true type from first 16-bit word past data. ! 591: * Remember that type was trailer by setting off. ! 592: */ ! 593: dh = (struct dmc_header *)ifrw->ifrw_addr; ! 594: dh->dmc_type = ntohs((u_short)dh->dmc_type); ! 595: #define dmcdataaddr(dh, off, type) ((type)(((caddr_t)((dh)+1)+(off)))) ! 596: if (dh->dmc_type >= DMC_TRAILER && ! 597: dh->dmc_type < DMC_TRAILER+DMC_NTRAILER) { ! 598: off = (dh->dmc_type - DMC_TRAILER) * 512; ! 599: if (off >= DMCMTU) ! 600: goto setup; /* sanity */ ! 601: dh->dmc_type = ntohs(*dmcdataaddr(dh, off, u_short *)); ! 602: resid = ntohs(*(dmcdataaddr(dh, off+2, u_short *))); ! 603: if (off + resid > len) ! 604: goto setup; /* sanity */ ! 605: len = off + resid; ! 606: } else ! 607: off = 0; ! 608: if (len == 0) ! 609: goto setup; ! 610: ! 611: /* ! 612: * Pull packet off interface. Off is nonzero if ! 613: * packet has trailing header; dmc_get will then ! 614: * force this header information to be at the front, ! 615: * but we still have to drop the type and length ! 616: * which are at the front of any trailer data. ! 617: */ ! 618: m = if_ubaget(&sc->sc_ifuba, ifrw, len, off, ifp); ! 619: if (m == 0) ! 620: goto setup; ! 621: switch (dh->dmc_type) { ! 622: ! 623: #ifdef INET ! 624: case DMC_IPTYPE: ! 625: schednetisr(NETISR_IP); ! 626: inq = &ipintrq; ! 627: break; ! 628: #endif ! 629: default: ! 630: m_freem(m); ! 631: goto setup; ! 632: } ! 633: ! 634: s = splimp(); ! 635: if (IF_QFULL(inq)) { ! 636: IF_DROP(inq); ! 637: m_freem(m); ! 638: } else ! 639: IF_ENQUEUE(inq, m); ! 640: splx(s); ! 641: ! 642: setup: ! 643: /* is this needed? */ ! 644: rp->ubinfo = UBAI_ADDR(ifrw->ifrw_info); ! 645: ! 646: dmcload(sc, DMC_READ, rp->ubinfo, ! 647: ((rp->ubinfo >> 2) & DMC_XMEM) | rp->cc); ! 648: break; ! 649: ! 650: case DMC_OUX: ! 651: /* ! 652: * A write has completed, start another ! 653: * transfer if there is more data to send. ! 654: */ ! 655: ifp->if_opackets++; ! 656: /* find associated dmcbuf structure */ ! 657: ifxp = &sc->sc_ifw[0]; ! 658: for (rp = &sc->sc_xbufs[0]; rp < &sc->sc_xbufs[NXMT]; rp++) { ! 659: if(rp->ubinfo == pkaddr) ! 660: break; ! 661: ifxp++; ! 662: } ! 663: if (rp >= &sc->sc_xbufs[NXMT]) { ! 664: printf("dmc%d: bad packet address 0x%x\n", ! 665: unit, pkaddr); ! 666: break; ! 667: } ! 668: if ((rp->flags & DBUF_DMCS) == 0) ! 669: printf("dmc%d: unallocated packet 0x%x\n", ! 670: unit, pkaddr); ! 671: /* mark buffer free */ ! 672: if (ifxp->ifw_xtofree) { ! 673: (void)m_freem(ifxp->ifw_xtofree); ! 674: ifxp->ifw_xtofree = 0; ! 675: } ! 676: rp->flags &= ~DBUF_DMCS; ! 677: if (--sc->sc_oused == 0) ! 678: sc->sc_if.if_timer = 0; ! 679: else ! 680: sc->sc_if.if_timer = dmc_timeout; ! 681: if ((sc->sc_flag & DMC_ONLINE) == 0) { ! 682: extern int ifqmaxlen; ! 683: ! 684: /* ! 685: * We're on the air. ! 686: * Open the queue to the usual value. ! 687: */ ! 688: sc->sc_flag |= DMC_ONLINE; ! 689: ifp->if_snd.ifq_maxlen = ifqmaxlen; ! 690: } ! 691: break; ! 692: ! 693: case DMC_CNTLO: ! 694: arg &= DMC_CNTMASK; ! 695: if (arg & DMC_FATAL) { ! 696: if (arg != DMC_START) ! 697: log(LOG_ERR, ! 698: "dmc%d: fatal error, flags=%b\n", ! 699: unit, arg, CNTLO_BITS); ! 700: dmcrestart(unit); ! 701: break; ! 702: } ! 703: /* ACCUMULATE STATISTICS */ ! 704: switch(arg) { ! 705: case DMC_NOBUFS: ! 706: ifp->if_ierrors++; ! 707: if ((sc->sc_nobuf++ % DMC_RPNBFS) == 0) ! 708: goto report; ! 709: break; ! 710: case DMC_DISCONN: ! 711: if ((sc->sc_disc++ % DMC_RPDSC) == 0) ! 712: goto report; ! 713: break; ! 714: case DMC_TIMEOUT: ! 715: if ((sc->sc_timeo++ % DMC_RPTMO) == 0) ! 716: goto report; ! 717: break; ! 718: case DMC_DATACK: ! 719: ifp->if_oerrors++; ! 720: if ((sc->sc_datck++ % DMC_RPDCK) == 0) ! 721: goto report; ! 722: break; ! 723: default: ! 724: goto report; ! 725: } ! 726: break; ! 727: report: ! 728: printd("dmc%d: soft error, flags=%b\n", unit, ! 729: arg, CNTLO_BITS); ! 730: if ((sc->sc_flag & DMC_RESTART) == 0) { ! 731: /* ! 732: * kill off the dmc to get things ! 733: * going again by generating a ! 734: * procedure error ! 735: */ ! 736: sc->sc_flag |= DMC_RESTART; ! 737: arg = UBAI_ADDR(sc->sc_ubinfo); ! 738: dmcload(sc, DMC_BASEI, arg, (arg>>2)&DMC_XMEM); ! 739: } ! 740: break; ! 741: ! 742: default: ! 743: printf("dmc%d: bad control %o\n", unit, cmd); ! 744: break; ! 745: } ! 746: } ! 747: dmcstart(unit); ! 748: return; ! 749: } ! 750: ! 751: /* ! 752: * DMC output routine. ! 753: * Encapsulate a packet of type family for the dmc. ! 754: * Use trailer local net encapsulation if enough data in first ! 755: * packet leaves a multiple of 512 bytes of data in remainder. ! 756: */ ! 757: dmcoutput(ifp, m0, dst) ! 758: register struct ifnet *ifp; ! 759: register struct mbuf *m0; ! 760: struct sockaddr *dst; ! 761: { ! 762: int type, error, s; ! 763: register struct mbuf *m = m0; ! 764: register struct dmc_header *dh; ! 765: register int off; ! 766: ! 767: if ((ifp->if_flags & IFF_UP) == 0) { ! 768: error = ENETDOWN; ! 769: goto bad; ! 770: } ! 771: ! 772: switch (dst->sa_family) { ! 773: #ifdef INET ! 774: case AF_INET: ! 775: off = m->m_pkthdr.len - m->m_len; ! 776: if ((ifp->if_flags & IFF_NOTRAILERS) == 0) ! 777: if (off > 0 && (off & 0x1ff) == 0 && ! 778: (m->m_flags & M_EXT) == 0 && ! 779: m->m_data >= m->m_pktdat + 2 * sizeof (u_short)) { ! 780: type = DMC_TRAILER + (off>>9); ! 781: m->m_data -= 2 * sizeof (u_short); ! 782: m->m_len += 2 * sizeof (u_short); ! 783: *mtod(m, u_short *) = htons((u_short)DMC_IPTYPE); ! 784: *(mtod(m, u_short *) + 1) = htons((u_short)m->m_len); ! 785: goto gottrailertype; ! 786: } ! 787: type = DMC_IPTYPE; ! 788: off = 0; ! 789: goto gottype; ! 790: #endif ! 791: ! 792: case AF_UNSPEC: ! 793: dh = (struct dmc_header *)dst->sa_data; ! 794: type = dh->dmc_type; ! 795: goto gottype; ! 796: ! 797: default: ! 798: printf("dmc%d: can't handle af%d\n", ifp->if_unit, ! 799: dst->sa_family); ! 800: error = EAFNOSUPPORT; ! 801: goto bad; ! 802: } ! 803: ! 804: gottrailertype: ! 805: /* ! 806: * Packet to be sent as a trailer; move first packet ! 807: * (control information) to end of chain. ! 808: */ ! 809: while (m->m_next) ! 810: m = m->m_next; ! 811: m->m_next = m0; ! 812: m = m0->m_next; ! 813: m0->m_next = 0; ! 814: m0 = m; ! 815: ! 816: gottype: ! 817: /* ! 818: * Add local network header ! 819: * (there is space for a uba on a vax to step on) ! 820: */ ! 821: M_PREPEND(m, sizeof(struct dmc_header), M_DONTWAIT); ! 822: if (m == 0) { ! 823: error = ENOBUFS; ! 824: goto bad; ! 825: } ! 826: dh = mtod(m, struct dmc_header *); ! 827: dh->dmc_type = htons((u_short)type); ! 828: ! 829: /* ! 830: * Queue message on interface, and start output if interface ! 831: * not yet active. ! 832: */ ! 833: s = splimp(); ! 834: if (IF_QFULL(&ifp->if_snd)) { ! 835: IF_DROP(&ifp->if_snd); ! 836: m_freem(m); ! 837: splx(s); ! 838: return (ENOBUFS); ! 839: } ! 840: IF_ENQUEUE(&ifp->if_snd, m); ! 841: dmcstart(ifp->if_unit); ! 842: splx(s); ! 843: return (0); ! 844: ! 845: bad: ! 846: m_freem(m0); ! 847: return (error); ! 848: } ! 849: ! 850: ! 851: /* ! 852: * Process an ioctl request. ! 853: */ ! 854: /* ARGSUSED */ ! 855: dmcioctl(ifp, cmd, data) ! 856: register struct ifnet *ifp; ! 857: int cmd; ! 858: caddr_t data; ! 859: { ! 860: int s = splimp(), error = 0; ! 861: register struct dmc_softc *sc = &dmc_softc[ifp->if_unit]; ! 862: ! 863: switch (cmd) { ! 864: ! 865: case SIOCSIFADDR: ! 866: ifp->if_flags |= IFF_UP; ! 867: if ((ifp->if_flags & IFF_RUNNING) == 0) ! 868: dmcinit(ifp->if_unit); ! 869: break; ! 870: ! 871: case SIOCSIFDSTADDR: ! 872: if ((ifp->if_flags & IFF_RUNNING) == 0) ! 873: dmcinit(ifp->if_unit); ! 874: break; ! 875: ! 876: case SIOCSIFFLAGS: ! 877: if ((ifp->if_flags & IFF_UP) == 0 && ! 878: sc->sc_flag & DMC_RUNNING) ! 879: dmcdown(ifp->if_unit); ! 880: else if (ifp->if_flags & IFF_UP && ! 881: (sc->sc_flag & DMC_RUNNING) == 0) ! 882: dmcrestart(ifp->if_unit); ! 883: break; ! 884: ! 885: default: ! 886: error = EINVAL; ! 887: } ! 888: splx(s); ! 889: return (error); ! 890: } ! 891: ! 892: /* ! 893: * Restart after a fatal error. ! 894: * Clear device and reinitialize. ! 895: */ ! 896: dmcrestart(unit) ! 897: int unit; ! 898: { ! 899: register struct dmc_softc *sc = &dmc_softc[unit]; ! 900: register struct dmcdevice *addr; ! 901: register int i; ! 902: int s; ! 903: ! 904: #ifdef DEBUG ! 905: /* dump base table */ ! 906: printf("dmc%d base table:\n", unit); ! 907: for (i = 0; i < sizeof (struct dmc_base); i++) ! 908: printf("%o\n" ,dmc_base[unit].d_base[i]); ! 909: #endif ! 910: ! 911: dmcdown(unit); ! 912: ! 913: /* ! 914: * Let the DMR finish the MCLR. At 1 Mbit, it should do so ! 915: * in about a max of 6.4 milliseconds with diagnostics enabled. ! 916: */ ! 917: addr = (struct dmcdevice *)(dmcinfo[unit]->ui_addr); ! 918: for (i = 100000; i && (addr->bsel1 & DMC_RUN) == 0; i--) ! 919: ; ! 920: /* Did the timer expire or did the DMR finish? */ ! 921: if ((addr->bsel1 & DMC_RUN) == 0) { ! 922: log(LOG_ERR, "dmc%d: M820 Test Failed\n", unit); ! 923: return; ! 924: } ! 925: ! 926: /* restart DMC */ ! 927: dmcinit(unit); ! 928: sc->sc_flag &= ~DMC_RESTART; ! 929: s = spl5(); ! 930: dmcstart(unit); ! 931: splx(s); ! 932: sc->sc_if.if_collisions++; /* why not? */ ! 933: } ! 934: ! 935: /* ! 936: * Reset a device and mark down. ! 937: * Flush output queue and drop queue limit. ! 938: */ ! 939: dmcdown(unit) ! 940: int unit; ! 941: { ! 942: register struct dmc_softc *sc = &dmc_softc[unit]; ! 943: register struct ifxmt *ifxp; ! 944: ! 945: ((struct dmcdevice *)(dmcinfo[unit]->ui_addr))->bsel1 = DMC_MCLR; ! 946: sc->sc_flag &= ~(DMC_RUNNING | DMC_ONLINE); ! 947: ! 948: for (ifxp = sc->sc_ifw; ifxp < &sc->sc_ifw[NXMT]; ifxp++) { ! 949: if (ifxp->ifw_xtofree) { ! 950: (void) m_freem(ifxp->ifw_xtofree); ! 951: ifxp->ifw_xtofree = 0; ! 952: } ! 953: } ! 954: if_qflush(&sc->sc_if.if_snd); ! 955: } ! 956: ! 957: /* ! 958: * Watchdog timeout to see that transmitted packets don't ! 959: * lose interrupts. The device has to be online (the first ! 960: * transmission may block until the other side comes up). ! 961: */ ! 962: dmctimeout(unit) ! 963: int unit; ! 964: { ! 965: register struct dmc_softc *sc; ! 966: struct dmcdevice *addr; ! 967: ! 968: sc = &dmc_softc[unit]; ! 969: if (sc->sc_flag & DMC_ONLINE) { ! 970: addr = (struct dmcdevice *)(dmcinfo[unit]->ui_addr); ! 971: log(LOG_ERR, "dmc%d: output timeout, bsel0=%b bsel2=%b\n", ! 972: unit, addr->bsel0 & 0xff, DMC0BITS, ! 973: addr->bsel2 & 0xff, DMC2BITS); ! 974: dmcrestart(unit); ! 975: } ! 976: } ! 977: #endif
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.