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