|
|
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.1 (Berkeley) 6/5/86 ! 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: int dmctimer; /* timer started? */ ! 60: int dmc_timeout = 8; /* timeout value */ ! 61: int dmcwatch(); ! 62: ! 63: /* ! 64: * Driver information for auto-configuration stuff. ! 65: */ ! 66: int dmcprobe(), dmcattach(), dmcinit(), dmcioctl(); ! 67: int dmcoutput(), dmcreset(); ! 68: struct uba_device *dmcinfo[NDMC]; ! 69: u_short dmcstd[] = { 0 }; ! 70: struct uba_driver dmcdriver = ! 71: { dmcprobe, 0, dmcattach, 0, dmcstd, "dmc", dmcinfo }; ! 72: ! 73: #define NRCV 7 ! 74: #define NXMT 3 ! 75: #define NCMDS (NRCV+NXMT+4) /* size of command queue */ ! 76: ! 77: #define printd if(dmcdebug)printf ! 78: int dmcdebug = 0; ! 79: ! 80: /* error reporting intervals */ ! 81: #define DMC_RPNBFS 50 ! 82: #define DMC_RPDSC 1 ! 83: #define DMC_RPTMO 10 ! 84: #define DMC_RPDCK 10 ! 85: ! 86: struct dmc_command { ! 87: char qp_cmd; /* command */ ! 88: short qp_ubaddr; /* buffer address */ ! 89: short qp_cc; /* character count || XMEM */ ! 90: struct dmc_command *qp_next; /* next command on queue */ ! 91: }; ! 92: ! 93: struct dmcbufs { ! 94: int ubinfo; /* from uballoc */ ! 95: short cc; /* buffer size */ ! 96: short flags; /* access control */ ! 97: }; ! 98: #define DBUF_OURS 0 /* buffer is available */ ! 99: #define DBUF_DMCS 1 /* buffer claimed by somebody */ ! 100: #define DBUF_XMIT 4 /* transmit buffer */ ! 101: #define DBUF_RCV 8 /* receive buffer */ ! 102: ! 103: ! 104: /* ! 105: * DMC software status per interface. ! 106: * ! 107: * Each interface is referenced by a network interface structure, ! 108: * sc_if, which the routing code uses to locate the interface. ! 109: * This structure contains the output queue for the interface, its address, ... ! 110: * We also have, for each interface, a set of 7 UBA interface structures ! 111: * for each, which ! 112: * contain information about the UNIBUS resources held by the interface: ! 113: * map registers, buffered data paths, etc. Information is cached in this ! 114: * structure for use by the if_uba.c routines in running the interface ! 115: * efficiently. ! 116: */ ! 117: struct dmc_softc { ! 118: struct ifnet sc_if; /* network-visible interface */ ! 119: struct dmcbufs sc_rbufs[NRCV]; /* receive buffer info */ ! 120: struct dmcbufs sc_xbufs[NXMT]; /* transmit buffer info */ ! 121: struct ifubinfo sc_ifuba; /* UNIBUS resources */ ! 122: struct ifrw sc_ifr[NRCV]; /* UNIBUS receive buffer maps */ ! 123: struct ifxmt sc_ifw[NXMT]; /* UNIBUS receive buffer maps */ ! 124: short sc_oused; /* output buffers currently in use */ ! 125: short sc_iused; /* input buffers given to DMC */ ! 126: short sc_flag; /* flags */ ! 127: int sc_nticks; /* seconds since last interrupt */ ! 128: int sc_ubinfo; /* UBA mapping info for base table */ ! 129: int sc_errors[4]; /* non-fatal error counters */ ! 130: #define sc_datck sc_errors[0] ! 131: #define sc_timeo sc_errors[1] ! 132: #define sc_nobuf sc_errors[2] ! 133: #define sc_disc sc_errors[3] ! 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_ALLOC 0x01 /* unibus resources allocated */ ! 146: #define DMC_BMAPPED 0x02 /* base table mapped */ ! 147: #define DMC_RESTART 0x04 /* software restart in progress */ ! 148: #define DMC_ACTIVE 0x08 /* device active */ ! 149: #define DMC_RUNNING 0x20 /* device initialized */ ! 150: ! 151: struct dmc_base { ! 152: short d_base[128]; /* DMC base table */ ! 153: } dmc_base[NDMC]; ! 154: ! 155: /* queue manipulation macros */ ! 156: #define QUEUE_AT_HEAD(qp, head, tail) \ ! 157: (qp)->qp_next = (head); \ ! 158: (head) = (qp); \ ! 159: if ((tail) == (struct dmc_command *) 0) \ ! 160: (tail) = (head) ! 161: ! 162: #define QUEUE_AT_TAIL(qp, head, tail) \ ! 163: if ((tail)) \ ! 164: (tail)->qp_next = (qp); \ ! 165: else \ ! 166: (head) = (qp); \ ! 167: (qp)->qp_next = (struct dmc_command *) 0; \ ! 168: (tail) = (qp) ! 169: ! 170: #define DEQUEUE(head, tail) \ ! 171: (head) = (head)->qp_next;\ ! 172: if ((head) == (struct dmc_command *) 0)\ ! 173: (tail) = (head) ! 174: ! 175: dmcprobe(reg) ! 176: caddr_t reg; ! 177: { ! 178: register int br, cvec; ! 179: register struct dmcdevice *addr = (struct dmcdevice *)reg; ! 180: register int i; ! 181: ! 182: #ifdef lint ! 183: br = 0; cvec = br; br = cvec; ! 184: dmcrint(0); dmcxint(0); ! 185: #endif ! 186: addr->bsel1 = DMC_MCLR; ! 187: for (i = 100000; i && (addr->bsel1 & DMC_RUN) == 0; i--) ! 188: ; ! 189: if ((addr->bsel1 & DMC_RUN) == 0) { ! 190: printf("dmcprobe: can't start device\n" ); ! 191: return (0); ! 192: } ! 193: addr->bsel0 = DMC_RQI|DMC_IEI; ! 194: /* let's be paranoid */ ! 195: addr->bsel0 |= DMC_RQI|DMC_IEI; ! 196: DELAY(1000000); ! 197: addr->bsel1 = DMC_MCLR; ! 198: for (i = 100000; i && (addr->bsel1 & DMC_RUN) == 0; i--) ! 199: ; ! 200: return (1); ! 201: } ! 202: ! 203: /* ! 204: * Interface exists: make available by filling in network interface ! 205: * record. System will initialize the interface when it is ready ! 206: * to accept packets. ! 207: */ ! 208: dmcattach(ui) ! 209: register struct uba_device *ui; ! 210: { ! 211: register struct dmc_softc *sc = &dmc_softc[ui->ui_unit]; ! 212: ! 213: sc->sc_if.if_unit = ui->ui_unit; ! 214: sc->sc_if.if_name = "dmc"; ! 215: sc->sc_if.if_mtu = DMCMTU; ! 216: sc->sc_if.if_init = dmcinit; ! 217: sc->sc_if.if_output = dmcoutput; ! 218: sc->sc_if.if_ioctl = dmcioctl; ! 219: sc->sc_if.if_reset = dmcreset; ! 220: sc->sc_if.if_flags = IFF_POINTOPOINT; ! 221: sc->sc_ifuba.iff_flags = UBA_CANTWAIT; ! 222: ! 223: if (dmctimer == 0) { ! 224: dmctimer = 1; ! 225: timeout(dmcwatch, (caddr_t) 0, hz); ! 226: } ! 227: if_attach(&sc->sc_if); ! 228: } ! 229: ! 230: /* ! 231: * Reset of interface after UNIBUS reset. ! 232: * If interface is on specified UBA, reset its state. ! 233: */ ! 234: dmcreset(unit, uban) ! 235: int unit, uban; ! 236: { ! 237: register struct uba_device *ui; ! 238: register struct dmc_softc *sc = &dmc_softc[unit]; ! 239: ! 240: if (unit >= NDMC || (ui = dmcinfo[unit]) == 0 || ui->ui_alive == 0 || ! 241: ui->ui_ubanum != uban) ! 242: return; ! 243: printf(" dmc%d", unit); ! 244: sc->sc_flag = 0; ! 245: sc->sc_if.if_flags &= ~IFF_RUNNING; ! 246: dmcinit(unit); ! 247: } ! 248: ! 249: /* ! 250: * Initialization of interface; reinitialize UNIBUS usage. ! 251: */ ! 252: dmcinit(unit) ! 253: int unit; ! 254: { ! 255: register struct dmc_softc *sc = &dmc_softc[unit]; ! 256: register struct uba_device *ui = dmcinfo[unit]; ! 257: register struct dmcdevice *addr; ! 258: register struct ifnet *ifp = &sc->sc_if; ! 259: register struct ifrw *ifrw; ! 260: register struct ifxmt *ifxp; ! 261: register struct dmcbufs *rp; ! 262: register struct dmc_command *qp; ! 263: struct ifaddr *ifa; ! 264: int base; ! 265: int s; ! 266: ! 267: addr = (struct dmcdevice *)ui->ui_addr; ! 268: ! 269: /* ! 270: * Check to see that an address has been set ! 271: * (both local and destination for an address family). ! 272: */ ! 273: for (ifa = ifp->if_addrlist; ifa; ifa = ifa->ifa_next) ! 274: if (ifa->ifa_addr.sa_family && ifa->ifa_dstaddr.sa_family) ! 275: break; ! 276: if (ifa == (struct ifaddr *) 0) ! 277: return; ! 278: ! 279: if ((addr->bsel1&DMC_RUN) == 0) { ! 280: printf("dmcinit: DMC not running\n"); ! 281: ifp->if_flags &= ~IFF_UP; ! 282: return; ! 283: } ! 284: /* map base table */ ! 285: if ((sc->sc_flag & DMC_BMAPPED) == 0) { ! 286: sc->sc_ubinfo = uballoc(ui->ui_ubanum, ! 287: (caddr_t)&dmc_base[unit], sizeof (struct dmc_base), 0); ! 288: sc->sc_flag |= DMC_BMAPPED; ! 289: } ! 290: /* initialize UNIBUS resources */ ! 291: sc->sc_iused = sc->sc_oused = 0; ! 292: if ((ifp->if_flags & IFF_RUNNING) == 0) { ! 293: if (if_ubaminit(&sc->sc_ifuba, ui->ui_ubanum, ! 294: sizeof(struct dmc_header), (int)btoc(DMCMTU), ! 295: sc->sc_ifr, NRCV, sc->sc_ifw, NXMT) == 0) { ! 296: printf("dmc%d: can't allocate uba resources\n", unit); ! 297: ifp->if_flags &= ~IFF_UP; ! 298: return; ! 299: } ! 300: ifp->if_flags |= IFF_RUNNING; ! 301: } ! 302: sc->sc_flag |= DMC_RUNNING; ! 303: ! 304: /* initialize buffer pool */ ! 305: /* receives */ ! 306: ifrw = &sc->sc_ifr[0]; ! 307: for (rp = &sc->sc_rbufs[0]; rp < &sc->sc_rbufs[NRCV]; rp++) { ! 308: rp->ubinfo = ifrw->ifrw_info & 0x3ffff; ! 309: rp->cc = DMCMTU + sizeof (struct dmc_header); ! 310: rp->flags = DBUF_OURS|DBUF_RCV; ! 311: ifrw++; ! 312: } ! 313: /* transmits */ ! 314: ifxp = &sc->sc_ifw[0]; ! 315: for (rp = &sc->sc_xbufs[0]; rp < &sc->sc_xbufs[NXMT]; rp++) { ! 316: rp->ubinfo = ifxp->ifw_info & 0x3ffff; ! 317: rp->cc = 0; ! 318: rp->flags = DBUF_OURS|DBUF_XMIT; ! 319: ifxp++; ! 320: } ! 321: ! 322: /* set up command queues */ ! 323: sc->sc_qfreeh = sc->sc_qfreet ! 324: = sc->sc_qhead = sc->sc_qtail = sc->sc_qactive = ! 325: (struct dmc_command *)0; ! 326: /* set up free command buffer list */ ! 327: for (qp = &sc->sc_cmdbuf[0]; qp < &sc->sc_cmdbuf[NCMDS]; qp++) { ! 328: QUEUE_AT_HEAD(qp, sc->sc_qfreeh, sc->sc_qfreet); ! 329: } ! 330: ! 331: /* base in */ ! 332: base = sc->sc_ubinfo & 0x3ffff; ! 333: dmcload(sc, DMC_BASEI, base, (base>>2) & DMC_XMEM); ! 334: /* specify half duplex operation, flags tell if primary */ ! 335: /* or secondary station */ ! 336: if (ui->ui_flags == 0) ! 337: /* use DDCMP mode in full duplex */ ! 338: dmcload(sc, DMC_CNTLI, 0, 0); ! 339: else if (ui->ui_flags == 1) ! 340: /* use MAINTENENCE mode */ ! 341: dmcload(sc, DMC_CNTLI, 0, DMC_MAINT ); ! 342: else if (ui->ui_flags == 2) ! 343: /* use DDCMP half duplex as primary station */ ! 344: dmcload(sc, DMC_CNTLI, 0, DMC_HDPLX); ! 345: else if (ui->ui_flags == 3) ! 346: /* use DDCMP half duplex as secondary station */ ! 347: dmcload(sc, DMC_CNTLI, 0, DMC_HDPLX | DMC_SEC); ! 348: ! 349: /* enable operation done interrupts */ ! 350: sc->sc_flag &= ~DMC_ACTIVE; ! 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(dev) ! 372: dev_t dev; ! 373: { ! 374: int unit = minor(dev); ! 375: register struct dmc_softc *sc = &dmc_softc[unit]; ! 376: struct mbuf *m; ! 377: register struct dmcbufs *rp; ! 378: register int n; ! 379: ! 380: /* ! 381: * Dequeue up to NXMT requests and map them to the UNIBUS. ! 382: * If no more requests, or no dmc buffers available, just return. ! 383: */ ! 384: n = 0; ! 385: for (rp = &sc->sc_xbufs[0]; rp < &sc->sc_xbufs[NXMT]; rp++ ) { ! 386: /* find an available buffer */ ! 387: if ((rp->flags & DBUF_DMCS) == 0) { ! 388: IF_DEQUEUE(&sc->sc_if.if_snd, m); ! 389: if (m == 0) ! 390: return; ! 391: /* mark it dmcs */ ! 392: rp->flags |= (DBUF_DMCS); ! 393: /* ! 394: * Have request mapped to UNIBUS for transmission ! 395: * and start the output. ! 396: */ ! 397: rp->cc = if_ubaput(&sc->sc_ifuba, &sc->sc_ifw[n], m); ! 398: rp->cc &= DMC_CCOUNT; ! 399: sc->sc_oused++; ! 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: sc->sc_oused--; ! 656: sc->sc_nticks = 0; ! 657: sc->sc_flag |= DMC_ACTIVE; ! 658: break; ! 659: ! 660: case DMC_CNTLO: ! 661: arg &= DMC_CNTMASK; ! 662: if (arg & DMC_FATAL) { ! 663: log(LOG_ERR, "dmc%d: fatal error, flags=%b\n", ! 664: unit, arg, CNTLO_BITS); ! 665: dmcrestart(unit); ! 666: break; ! 667: } ! 668: /* ACCUMULATE STATISTICS */ ! 669: switch(arg) { ! 670: case DMC_NOBUFS: ! 671: ifp->if_ierrors++; ! 672: if ((sc->sc_nobuf++ % DMC_RPNBFS) == 0) ! 673: goto report; ! 674: break; ! 675: case DMC_DISCONN: ! 676: if ((sc->sc_disc++ % DMC_RPDSC) == 0) ! 677: goto report; ! 678: break; ! 679: case DMC_TIMEOUT: ! 680: if ((sc->sc_timeo++ % DMC_RPTMO) == 0) ! 681: goto report; ! 682: break; ! 683: case DMC_DATACK: ! 684: ifp->if_oerrors++; ! 685: if ((sc->sc_datck++ % DMC_RPDCK) == 0) ! 686: goto report; ! 687: break; ! 688: default: ! 689: goto report; ! 690: } ! 691: break; ! 692: report: ! 693: printd("dmc%d: soft error, flags=%b\n", unit, ! 694: arg, CNTLO_BITS); ! 695: if ((sc->sc_flag & DMC_RESTART) == 0) { ! 696: /* ! 697: * kill off the dmc to get things ! 698: * going again by generating a ! 699: * procedure error ! 700: */ ! 701: sc->sc_flag |= DMC_RESTART; ! 702: arg = sc->sc_ubinfo & 0x3ffff; ! 703: dmcload(sc, DMC_BASEI, arg, (arg>>2)&DMC_XMEM); ! 704: } ! 705: break; ! 706: ! 707: default: ! 708: printf("dmc%d: bad control %o\n", unit, cmd); ! 709: break; ! 710: } ! 711: } ! 712: dmcstart(unit); ! 713: return; ! 714: } ! 715: ! 716: /* ! 717: * DMC output routine. ! 718: * Encapsulate a packet of type family for the dmc. ! 719: * Use trailer local net encapsulation if enough data in first ! 720: * packet leaves a multiple of 512 bytes of data in remainder. ! 721: */ ! 722: dmcoutput(ifp, m0, dst) ! 723: register struct ifnet *ifp; ! 724: register struct mbuf *m0; ! 725: struct sockaddr *dst; ! 726: { ! 727: int type, error, s; ! 728: register struct mbuf *m = m0; ! 729: register struct dmc_header *dh; ! 730: register int off; ! 731: ! 732: switch (dst->sa_family) { ! 733: #ifdef INET ! 734: case AF_INET: ! 735: off = ntohs((u_short)mtod(m, struct ip *)->ip_len) - m->m_len; ! 736: if ((ifp->if_flags & IFF_NOTRAILERS) == 0) ! 737: if (off > 0 && (off & 0x1ff) == 0 && ! 738: m->m_off >= MMINOFF + 2 * sizeof (u_short)) { ! 739: type = DMC_TRAILER + (off>>9); ! 740: m->m_off -= 2 * sizeof (u_short); ! 741: m->m_len += 2 * sizeof (u_short); ! 742: *mtod(m, u_short *) = htons((u_short)DMC_IPTYPE); ! 743: *(mtod(m, u_short *) + 1) = htons((u_short)m->m_len); ! 744: goto gottrailertype; ! 745: } ! 746: type = DMC_IPTYPE; ! 747: off = 0; ! 748: goto gottype; ! 749: #endif ! 750: ! 751: case AF_UNSPEC: ! 752: dh = (struct dmc_header *)dst->sa_data; ! 753: type = dh->dmc_type; ! 754: goto gottype; ! 755: ! 756: default: ! 757: printf("dmc%d: can't handle af%d\n", ifp->if_unit, ! 758: dst->sa_family); ! 759: error = EAFNOSUPPORT; ! 760: goto bad; ! 761: } ! 762: ! 763: gottrailertype: ! 764: /* ! 765: * Packet to be sent as a trailer; move first packet ! 766: * (control information) to end of chain. ! 767: */ ! 768: while (m->m_next) ! 769: m = m->m_next; ! 770: m->m_next = m0; ! 771: m = m0->m_next; ! 772: m0->m_next = 0; ! 773: m0 = m; ! 774: ! 775: gottype: ! 776: /* ! 777: * Add local network header ! 778: * (there is space for a uba on a vax to step on) ! 779: */ ! 780: if (m->m_off > MMAXOFF || ! 781: MMINOFF + sizeof(struct dmc_header) > m->m_off) { ! 782: m = m_get(M_DONTWAIT, MT_HEADER); ! 783: if (m == 0) { ! 784: error = ENOBUFS; ! 785: goto bad; ! 786: } ! 787: m->m_next = m0; ! 788: m->m_off = MMINOFF; ! 789: m->m_len = sizeof (struct dmc_header); ! 790: } else { ! 791: m->m_off -= sizeof (struct dmc_header); ! 792: m->m_len += sizeof (struct dmc_header); ! 793: } ! 794: dh = mtod(m, struct dmc_header *); ! 795: dh->dmc_type = htons((u_short)type); ! 796: ! 797: /* ! 798: * Queue message on interface, and start output if interface ! 799: * not yet active. ! 800: */ ! 801: s = splimp(); ! 802: if (IF_QFULL(&ifp->if_snd)) { ! 803: IF_DROP(&ifp->if_snd); ! 804: m_freem(m); ! 805: splx(s); ! 806: return (ENOBUFS); ! 807: } ! 808: IF_ENQUEUE(&ifp->if_snd, m); ! 809: dmcstart(ifp->if_unit); ! 810: splx(s); ! 811: return (0); ! 812: ! 813: bad: ! 814: m_freem(m0); ! 815: return (error); ! 816: } ! 817: ! 818: ! 819: /* ! 820: * Process an ioctl request. ! 821: */ ! 822: /* ARGSUSED */ ! 823: dmcioctl(ifp, cmd, data) ! 824: register struct ifnet *ifp; ! 825: int cmd; ! 826: caddr_t data; ! 827: { ! 828: int s = splimp(), error = 0; ! 829: register struct dmc_softc *sc = &dmc_softc[ifp->if_unit]; ! 830: ! 831: switch (cmd) { ! 832: ! 833: case SIOCSIFADDR: ! 834: ifp->if_flags |= IFF_UP; ! 835: if ((ifp->if_flags & IFF_RUNNING) == 0) ! 836: dmcinit(ifp->if_unit); ! 837: break; ! 838: ! 839: case SIOCSIFDSTADDR: ! 840: if ((ifp->if_flags & IFF_RUNNING) == 0) ! 841: dmcinit(ifp->if_unit); ! 842: break; ! 843: ! 844: case SIOCSIFFLAGS: ! 845: if ((ifp->if_flags & IFF_UP) == 0 && ! 846: sc->sc_flag & DMC_RUNNING) { ! 847: ((struct dmcdevice *) ! 848: (dmcinfo[ifp->if_unit]->ui_addr))->bsel1 = DMC_MCLR; ! 849: sc->sc_flag &= ~DMC_RUNNING; ! 850: } else if (ifp->if_flags & IFF_UP && ! 851: (sc->sc_flag & DMC_RUNNING) == 0) ! 852: dmcrestart(ifp->if_unit); ! 853: break; ! 854: ! 855: default: ! 856: error = EINVAL; ! 857: } ! 858: splx(s); ! 859: return (error); ! 860: } ! 861: ! 862: /* ! 863: * Restart after a fatal error. ! 864: * Clear device and reinitialize. ! 865: */ ! 866: dmcrestart(unit) ! 867: int unit; ! 868: { ! 869: register struct dmc_softc *sc = &dmc_softc[unit]; ! 870: register struct uba_device *ui = dmcinfo[unit]; ! 871: register struct dmcdevice *addr; ! 872: register struct ifxmt *ifxp; ! 873: register int i; ! 874: ! 875: addr = (struct dmcdevice *)ui->ui_addr; ! 876: #ifdef DEBUG ! 877: /* dump base table */ ! 878: printf("dmc%d base table:\n", unit); ! 879: for (i = 0; i < sizeof (struct dmc_base); i++) ! 880: printf("%o\n" ,dmc_base[unit].d_base[i]); ! 881: #endif ! 882: /* ! 883: * Let the DMR finish the MCLR. At 1 Mbit, it should do so ! 884: * in about a max of 6.4 milliseconds with diagnostics enabled. ! 885: */ ! 886: addr->bsel1 = DMC_MCLR; ! 887: for (i = 100000; i && (addr->bsel1 & DMC_RUN) == 0; i--) ! 888: ; ! 889: /* Did the timer expire or did the DMR finish? */ ! 890: if ((addr->bsel1 & DMC_RUN) == 0) { ! 891: log(LOG_ERR, "dmc%d: M820 Test Failed\n", unit); ! 892: return; ! 893: } ! 894: ! 895: for (ifxp = sc->sc_ifw; ifxp < &sc->sc_ifw[NXMT]; ifxp++) { ! 896: if (ifxp->ifw_xtofree) { ! 897: (void) m_freem(ifxp->ifw_xtofree); ! 898: ifxp->ifw_xtofree = 0; ! 899: } ! 900: } ! 901: ! 902: /* restart DMC */ ! 903: dmcinit(unit); ! 904: sc->sc_flag &= ~DMC_RESTART; ! 905: sc->sc_if.if_collisions++; /* why not? */ ! 906: } ! 907: ! 908: /* ! 909: * Check to see that transmitted packets don't ! 910: * lose interrupts. The device has to be active. ! 911: */ ! 912: dmcwatch() ! 913: { ! 914: register struct uba_device *ui; ! 915: register struct dmc_softc *sc; ! 916: struct dmcdevice *addr; ! 917: register int i; ! 918: ! 919: for (i = 0; i < NDMC; i++) { ! 920: sc = &dmc_softc[i]; ! 921: if ((sc->sc_flag & DMC_ACTIVE) == 0) ! 922: continue; ! 923: if ((ui = dmcinfo[i]) == 0 || ui->ui_alive == 0) ! 924: continue; ! 925: if (sc->sc_oused) { ! 926: sc->sc_nticks++; ! 927: if (sc->sc_nticks > dmc_timeout) { ! 928: sc->sc_nticks = 0; ! 929: addr = (struct dmcdevice *)ui->ui_addr; ! 930: log(LOG_ERR, "dmc%d hung: bsel0=%b bsel2=%b\n", ! 931: i, addr->bsel0 & 0xff, DMC0BITS, ! 932: addr->bsel2 & 0xff, DMC2BITS); ! 933: dmcrestart(i); ! 934: } ! 935: } ! 936: } ! 937: timeout(dmcwatch, (caddr_t) 0, hz); ! 938: } ! 939: #endif
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.