|
|
1.1 ! root 1: /* if_dmc.c 6.1 83/07/29 */ ! 2: ! 3: #include "dmc.h" ! 4: #if NDMC > 0 ! 5: #define printd if(dmcdebug)printf ! 6: int dmcdebug = 0; ! 7: /* ! 8: * DMC11 device driver, internet version ! 9: * ! 10: * TODO ! 11: * allow more than one outstanding read or write. ! 12: * ! 13: * UNTESTED WITH 4.2 ! 14: */ ! 15: #include "../machine/pte.h" ! 16: ! 17: #include "../h/param.h" ! 18: #include "../h/systm.h" ! 19: #include "../h/mbuf.h" ! 20: #include "../h/buf.h" ! 21: #include "../h/ioctl.h" /* must precede tty.h */ ! 22: #include "../h/tty.h" ! 23: #include "../h/protosw.h" ! 24: #include "../h/socket.h" ! 25: #include "../h/vmmac.h" ! 26: #include "../h/errno.h" ! 27: ! 28: #include "../net/if.h" ! 29: #include "../net/netisr.h" ! 30: #include "../net/route.h" ! 31: #include "../netinet/in.h" ! 32: #include "../netinet/in_systm.h" ! 33: ! 34: #include "../vax/cpu.h" ! 35: #include "../vax/mtpr.h" ! 36: #include "../vaxif/if_uba.h" ! 37: #include "../vaxif/if_dmc.h" ! 38: #include "../vaxuba/ubareg.h" ! 39: #include "../vaxuba/ubavar.h" ! 40: ! 41: #ifndef DMC_USEMAINT ! 42: #define DMC_USEMAINT 1 /* use maintenance mode */ ! 43: #endif ! 44: ! 45: /* ! 46: * Driver information for auto-configuration stuff. ! 47: */ ! 48: int dmcprobe(), dmcattach(), dmcinit(), dmcioctl(); ! 49: int dmcoutput(), dmcreset(); ! 50: struct uba_device *dmcinfo[NDMC]; ! 51: u_short dmcstd[] = { 0 }; ! 52: struct uba_driver dmcdriver = ! 53: { dmcprobe, 0, dmcattach, 0, dmcstd, "dmc", dmcinfo }; ! 54: ! 55: /* ! 56: * DMC software status per interface. ! 57: * ! 58: * Each interface is referenced by a network interface structure, ! 59: * sc_if, which the routing code uses to locate the interface. ! 60: * This structure contains the output queue for the interface, its address, ... ! 61: * We also have, for each interface, a UBA interface structure, which ! 62: * contains information about the UNIBUS resources held by the interface: ! 63: * map registers, buffered data paths, etc. Information is cached in this ! 64: * structure for use by the if_uba.c routines in running the interface ! 65: * efficiently. ! 66: */ ! 67: struct dmc_softc { ! 68: struct ifnet sc_if; /* network-visible interface */ ! 69: struct ifuba sc_ifuba; /* UNIBUS resources */ ! 70: short sc_flag; /* flags */ ! 71: short sc_oactive; /* output active */ ! 72: int sc_ubinfo; /* UBA mapping info for base table */ ! 73: struct clist sc_que; /* command queue */ ! 74: } dmc_softc[NDMC]; ! 75: ! 76: /* flags */ ! 77: #define DMCRUN 01 ! 78: #define DMCBMAPPED 02 /* base table mapped */ ! 79: ! 80: struct dmc_base { ! 81: short d_base[128]; /* DMC base table */ ! 82: } dmc_base[NDMC]; ! 83: ! 84: #define loword(x) ((short *)&x)[0] ! 85: #define hiword(x) ((short *)&x)[1] ! 86: ! 87: dmcprobe(reg) ! 88: caddr_t reg; ! 89: { ! 90: register int br, cvec; ! 91: register struct dmcdevice *addr = (struct dmcdevice *)reg; ! 92: register int i; ! 93: ! 94: #ifdef lint ! 95: br = 0; cvec = br; br = cvec; ! 96: dmcrint(0); dmcxint(0); ! 97: #endif ! 98: addr->bsel1 = DMC_MCLR; ! 99: for (i = 100000; i && (addr->bsel1 & DMC_RUN) == 0; i--) ! 100: ; ! 101: if ((addr->bsel1 & DMC_RUN) == 0) ! 102: return (0); ! 103: addr->bsel1 &= ~DMC_MCLR; ! 104: addr->bsel0 = DMC_RQI|DMC_IEI; ! 105: DELAY(100000); ! 106: addr->bsel1 = DMC_MCLR; ! 107: for (i = 100000; i && (addr->bsel1 & DMC_RUN) == 0; i--) ! 108: ; ! 109: return (1); ! 110: } ! 111: ! 112: /* ! 113: * Interface exists: make available by filling in network interface ! 114: * record. System will initialize the interface when it is ready ! 115: * to accept packets. ! 116: */ ! 117: dmcattach(ui) ! 118: register struct uba_device *ui; ! 119: { ! 120: register struct dmc_softc *sc = &dmc_softc[ui->ui_unit]; ! 121: ! 122: sc->sc_if.if_unit = ui->ui_unit; ! 123: sc->sc_if.if_name = "dmc"; ! 124: sc->sc_if.if_mtu = DMCMTU; ! 125: sc->sc_if.if_init = dmcinit; ! 126: sc->sc_if.if_output = dmcoutput; ! 127: sc->sc_if.if_ioctl = dmcioctl; ! 128: sc->sc_if.if_reset = dmcreset; ! 129: /* DON'T KNOW IF THIS WILL WORK WITH A BDP AT HIGH SPEEDS */ ! 130: sc->sc_ifuba.ifu_flags = UBA_NEEDBDP | UBA_CANTWAIT; ! 131: if_attach(&sc->sc_if); ! 132: } ! 133: ! 134: /* ! 135: * Reset of interface after UNIBUS reset. ! 136: * If interface is on specified UBA, reset it's state. ! 137: */ ! 138: dmcreset(unit, uban) ! 139: int unit, uban; ! 140: { ! 141: register struct uba_device *ui; ! 142: ! 143: if (unit >= NDMC || (ui = dmcinfo[unit]) == 0 || ui->ui_alive == 0 || ! 144: ui->ui_ubanum != uban) ! 145: return; ! 146: printf(" dmc%d", unit); ! 147: dmcinit(unit); ! 148: } ! 149: ! 150: /* ! 151: * Initialization of interface; reinitialize UNIBUS usage. ! 152: */ ! 153: dmcinit(unit) ! 154: int unit; ! 155: { ! 156: register struct dmc_softc *sc = &dmc_softc[unit]; ! 157: register struct uba_device *ui = dmcinfo[unit]; ! 158: register struct dmcdevice *addr; ! 159: register struct ifnet *ifp = &sc->sc_if; ! 160: struct sockaddr_in *sin; ! 161: int base; ! 162: ! 163: printd("dmcinit\n"); ! 164: sin = (struct sockaddr_in *)&ifp->if_addr; ! 165: if (sin->sin_addr.s_addr == 0) ! 166: return; ! 167: if ((ifp->if_flags & IFF_RUNNING) == 0) { ! 168: if ((sc->sc_flag&DMCBMAPPED) == 0) { ! 169: sc->sc_ubinfo = uballoc(ui->ui_ubanum, ! 170: (caddr_t)&dmc_base[unit], ! 171: sizeof (struct dmc_base), 0); ! 172: sc->sc_flag |= DMCBMAPPED; ! 173: } ! 174: if (if_ubainit(&sc->sc_ifuba, ui->ui_ubanum, 0, ! 175: (int)btoc(DMCMTU)) == 0) { ! 176: printf("dmc%d: can't initialize\n", unit); ! 177: ifp->if_flags &= ~IFF_UP; ! 178: return; ! 179: } ! 180: addr = (struct dmcdevice *)ui->ui_addr; ! 181: addr->bsel2 |= DMC_IEO; ! 182: base = sc->sc_ubinfo & 0x3ffff; ! 183: printd(" base 0x%x\n", base); ! 184: dmcload(sc, DMC_BASEI, base, (base>>2)&DMC_XMEM); ! 185: dmcload(sc, DMC_CNTLI, 0, DMC_USEMAINT ? DMC_MAINT : 0); ! 186: base = sc->sc_ifuba.ifu_r.ifrw_info & 0x3ffff; ! 187: dmcload(sc, DMC_READ, base, ((base>>2)&DMC_XMEM)|DMCMTU); ! 188: printd(" first read queued, addr 0x%x\n", base); ! 189: ifp->if_flags |= IFF_UP|IFF_RUNNING; ! 190: } ! 191: /* set up routing table entry */ ! 192: if ((ifp->if_flags & IFF_ROUTE) == 0) { ! 193: rtinit((struct sockaddr *)sin, (struct sockaddr *)sin, ! 194: RTF_HOST|RTF_UP); ! 195: ifp->if_flags |= IFF_ROUTE; ! 196: } ! 197: } ! 198: ! 199: /* ! 200: * Start output on interface. Get another datagram ! 201: * to send from the interface queue and map it to ! 202: * the interface before starting output. ! 203: */ ! 204: dmcstart(dev) ! 205: dev_t dev; ! 206: { ! 207: int unit = minor(dev); ! 208: register struct dmc_softc *sc = &dmc_softc[unit]; ! 209: int addr, len; ! 210: struct mbuf *m; ! 211: ! 212: printd("dmcstart\n"); ! 213: /* ! 214: * Dequeue a request and map it to the UNIBUS. ! 215: * If no more requests, just return. ! 216: */ ! 217: IF_DEQUEUE(&sc->sc_if.if_snd, m); ! 218: if (m == 0) ! 219: return; ! 220: len = if_wubaput(&sc->sc_ifuba, m); ! 221: ! 222: /* ! 223: * Have request mapped to UNIBUS for transmission. ! 224: * Purge any stale data from this BDP and start the output. ! 225: */ ! 226: if (sc->sc_ifuba.ifu_flags & UBA_NEEDBDP) ! 227: UBAPURGE(sc->sc_ifuba.ifu_uba, sc->sc_ifuba.ifu_w.ifrw_bdp); ! 228: addr = sc->sc_ifuba.ifu_w.ifrw_info & 0x3ffff; ! 229: printd(" len %d, addr 0x%x, ", len, addr); ! 230: printd("mr 0x%x\n", sc->sc_ifuba.ifu_w.ifrw_mr[0]); ! 231: dmcload(sc, DMC_WRITE, addr, (len&DMC_CCOUNT)|((addr>>2)&DMC_XMEM)); ! 232: sc->sc_oactive = 1; ! 233: } ! 234: ! 235: /* ! 236: * Utility routine to load the DMC device registers. ! 237: */ ! 238: dmcload(sc, type, w0, w1) ! 239: register struct dmc_softc *sc; ! 240: int type, w0, w1; ! 241: { ! 242: register struct dmcdevice *addr; ! 243: register int unit, sps, n; ! 244: ! 245: printd("dmcload: 0x%x 0x%x 0x%x\n", type, w0, w1); ! 246: unit = sc - dmc_softc; ! 247: addr = (struct dmcdevice *)dmcinfo[unit]->ui_addr; ! 248: sps = spl5(); ! 249: if ((n = sc->sc_que.c_cc) == 0) ! 250: addr->bsel0 = type | DMC_RQI; ! 251: else ! 252: (void) putc(type | DMC_RQI, &sc->sc_que); ! 253: (void) putw(w0, &sc->sc_que); ! 254: (void) putw(w1, &sc->sc_que); ! 255: if (n == 0) ! 256: dmcrint(unit); ! 257: splx(sps); ! 258: } ! 259: ! 260: /* ! 261: * DMC interface receiver interrupt. ! 262: * Ready to accept another command, ! 263: * pull one off the command queue. ! 264: */ ! 265: dmcrint(unit) ! 266: int unit; ! 267: { ! 268: register struct dmc_softc *sc; ! 269: register struct dmcdevice *addr; ! 270: register int n; ! 271: ! 272: addr = (struct dmcdevice *)dmcinfo[unit]->ui_addr; ! 273: sc = &dmc_softc[unit]; ! 274: while (addr->bsel0&DMC_RDYI) { ! 275: addr->sel4 = getw(&sc->sc_que); ! 276: addr->sel6 = getw(&sc->sc_que); ! 277: addr->bsel0 &= ~(DMC_IEI|DMC_RQI); ! 278: while (addr->bsel0&DMC_RDYI) ! 279: ; ! 280: if (sc->sc_que.c_cc == 0) ! 281: goto out; ! 282: addr->bsel0 = getc(&sc->sc_que); ! 283: n = RDYSCAN; ! 284: while (n-- && (addr->bsel0&DMC_RDYI) == 0) ! 285: ; ! 286: } ! 287: if (sc->sc_que.c_cc) ! 288: addr->bsel0 |= DMC_IEI; ! 289: out: ! 290: dmcxint(unit); ! 291: } ! 292: ! 293: /* ! 294: * DMC interface transmitter interrupt. ! 295: * A transfer has completed, check for errors. ! 296: * If it was a read, notify appropriate protocol. ! 297: * If it was a write, pull the next one off the queue. ! 298: */ ! 299: dmcxint(unit) ! 300: int unit; ! 301: { ! 302: register struct dmc_softc *sc; ! 303: register struct ifnet *ifp; ! 304: struct uba_device *ui = dmcinfo[unit]; ! 305: struct dmcdevice *addr; ! 306: struct mbuf *m; ! 307: register struct ifqueue *inq; ! 308: int arg, cmd, len; ! 309: ! 310: addr = (struct dmcdevice *)ui->ui_addr; ! 311: cmd = addr->bsel2 & 0xff; ! 312: if ((cmd & DMC_RDYO) == 0) ! 313: return; ! 314: #ifdef notdef ! 315: arg2 = addr->sel4; ! 316: #endif ! 317: arg = addr->sel6; ! 318: addr->bsel2 &= ~DMC_RDYO; ! 319: sc = &dmc_softc[unit]; ! 320: ifp = &sc->sc_if; ! 321: printd("dmcxint\n"); ! 322: switch (cmd & 07) { ! 323: ! 324: case DMC_OUR: ! 325: /* ! 326: * A read has completed. Purge input buffered ! 327: * data path. Pass packet to type specific ! 328: * higher-level input routine. ! 329: */ ! 330: ifp->if_ipackets++; ! 331: if (sc->sc_ifuba.ifu_flags & UBA_NEEDBDP) ! 332: UBAPURGE(sc->sc_ifuba.ifu_uba, ! 333: sc->sc_ifuba.ifu_r.ifrw_bdp); ! 334: len = arg & DMC_CCOUNT; ! 335: printd(" read done, len %d\n", len); ! 336: switch (ifp->if_addr.sa_family) { ! 337: #ifdef INET ! 338: case AF_INET: ! 339: schednetisr(NETISR_IP); ! 340: inq = &ipintrq; ! 341: break; ! 342: #endif ! 343: ! 344: default: ! 345: printf("dmc%d: unknown address type %d\n", unit, ! 346: ifp->if_addr.sa_family); ! 347: goto setup; ! 348: } ! 349: m = if_rubaget(&sc->sc_ifuba, len, 0); ! 350: if (m == 0) ! 351: goto setup; ! 352: if (IF_QFULL(inq)) { ! 353: IF_DROP(inq); ! 354: m_freem(m); ! 355: } else ! 356: IF_ENQUEUE(inq, m); ! 357: ! 358: setup: ! 359: arg = sc->sc_ifuba.ifu_r.ifrw_info & 0x3ffff; ! 360: dmcload(sc, DMC_READ, arg, ((arg >> 2) & DMC_XMEM) | DMCMTU); ! 361: return; ! 362: ! 363: case DMC_OUX: ! 364: /* ! 365: * A write has completed, start another ! 366: * transfer if there is more data to send. ! 367: */ ! 368: if (sc->sc_oactive == 0) ! 369: return; /* SHOULD IT BE A FATAL ERROR? */ ! 370: printd(" write done\n"); ! 371: ifp->if_opackets++; ! 372: sc->sc_oactive = 0; ! 373: if (sc->sc_ifuba.ifu_xtofree) { ! 374: m_freem(sc->sc_ifuba.ifu_xtofree); ! 375: sc->sc_ifuba.ifu_xtofree = 0; ! 376: } ! 377: if (ifp->if_snd.ifq_head == 0) ! 378: return; ! 379: dmcstart(unit); ! 380: return; ! 381: ! 382: case DMC_CNTLO: ! 383: arg &= DMC_CNTMASK; ! 384: if (arg&DMC_FATAL) { ! 385: addr->bsel1 = DMC_MCLR; ! 386: sc->sc_flag &= ~DMCRUN; ! 387: /*** DO SOMETHING TO RESTART DEVICE ***/ ! 388: printf("DMC FATAL ERROR 0%o\n", arg); ! 389: } else { ! 390: /* ACCUMULATE STATISTICS */ ! 391: printf("DMC SOFT ERROR 0%o\n", arg); ! 392: } ! 393: return; ! 394: ! 395: default: ! 396: printf("dmc%d: bad control %o\n", unit, cmd); ! 397: } ! 398: } ! 399: ! 400: /* ! 401: * DMC output routine. ! 402: * Just send the data, header was supplied by ! 403: * upper level protocol routines. ! 404: */ ! 405: dmcoutput(ifp, m, dst) ! 406: register struct ifnet *ifp; ! 407: register struct mbuf *m; ! 408: struct sockaddr *dst; ! 409: { ! 410: int s; ! 411: ! 412: printd("dmcoutput\n"); ! 413: if (dst->sa_family != ifp->if_addr.sa_family) { ! 414: printf("dmc%d: af%d not supported\n", ifp->if_unit, ! 415: dst->sa_family); ! 416: m_freem(m); ! 417: return (EAFNOSUPPORT); ! 418: } ! 419: s = splimp(); ! 420: if (IF_QFULL(&ifp->if_snd)) { ! 421: IF_DROP(&ifp->if_snd); ! 422: m_freem(m); ! 423: splx(s); ! 424: return (ENOBUFS); ! 425: } ! 426: IF_ENQUEUE(&ifp->if_snd, m); ! 427: if (dmc_softc[ifp->if_unit].sc_oactive == 0) ! 428: dmcstart(ifp->if_unit); ! 429: splx(s); ! 430: return (0); ! 431: } ! 432: ! 433: /* ! 434: * Process an ioctl request. ! 435: */ ! 436: dmcioctl(ifp, cmd, data) ! 437: register struct ifnet *ifp; ! 438: int cmd; ! 439: caddr_t data; ! 440: { ! 441: struct ifreq *ifr = (struct ifreq *)data; ! 442: struct sockaddr_in *sin; ! 443: int s = splimp(), error = 0; ! 444: ! 445: switch (cmd) { ! 446: ! 447: case SIOCSIFADDR: ! 448: if (ifp->if_flags & IFF_RUNNING) ! 449: if_rtinit(ifp, -1); /* delete previous route */ ! 450: sin = (struct sockaddr_in *)&ifr->ifr_addr; ! 451: ifp->if_addr = *(struct sockaddr *)sin; ! 452: ifp->if_net = in_netof(sin->sin_addr); ! 453: ifp->if_host[0] = in_lnaof(sin->sin_addr); ! 454: dmcinit(ifp->if_unit); ! 455: break; ! 456: ! 457: case SIOCSIFDSTADDR: ! 458: ifp->if_dstaddr = ifr->ifr_dstaddr; ! 459: break; ! 460: ! 461: default: ! 462: error = EINVAL; ! 463: } ! 464: splx(s); ! 465: return (error); ! 466: } ! 467: #endif
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.