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