|
|
1.1 ! root 1: /* ! 2: * Copyright (c) 1982, 1986, 1988 Regents of the University of California. ! 3: * All rights reserved. ! 4: * ! 5: * Redistribution and use in source and binary forms, with or without ! 6: * modification, are permitted provided that the following conditions ! 7: * are met: ! 8: * 1. Redistributions of source code must retain the above copyright ! 9: * notice, this list of conditions and the following disclaimer. ! 10: * 2. Redistributions in binary form must reproduce the above copyright ! 11: * notice, this list of conditions and the following disclaimer in the ! 12: * documentation and/or other materials provided with the distribution. ! 13: * 3. All advertising materials mentioning features or use of this software ! 14: * must display the following acknowledgement: ! 15: * This product includes software developed by the University of ! 16: * California, Berkeley and its contributors. ! 17: * 4. Neither the name of the University nor the names of its contributors ! 18: * may be used to endorse or promote products derived from this software ! 19: * without specific prior written permission. ! 20: * ! 21: * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND ! 22: * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE ! 23: * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ! 24: * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE ! 25: * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL ! 26: * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS ! 27: * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) ! 28: * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT ! 29: * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY ! 30: * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF ! 31: * SUCH DAMAGE. ! 32: * ! 33: * @(#)if_acc.c 7.8 (Berkeley) 12/16/90 ! 34: */ ! 35: ! 36: #include "acc.h" ! 37: #if NACC > 0 ! 38: ! 39: /* ! 40: * ACC LH/DH ARPAnet IMP interface driver. ! 41: */ ! 42: #include "machine/pte.h" ! 43: ! 44: #include "sys/param.h" ! 45: #include "sys/systm.h" ! 46: #include "sys/mbuf.h" ! 47: #include "sys/buf.h" ! 48: #include "sys/protosw.h" ! 49: #include "sys/socket.h" ! 50: #include "sys/vmmac.h" ! 51: ! 52: #include "net/if.h" ! 53: #include "netimp/if_imp.h" ! 54: ! 55: #include "../include/cpu.h" ! 56: #include "../include/mtpr.h" ! 57: #include "if_accreg.h" ! 58: #include "if_uba.h" ! 59: #include "../uba/ubareg.h" ! 60: #include "../uba/ubavar.h" ! 61: ! 62: int accprobe(), accattach(), accrint(), accxint(); ! 63: struct uba_device *accinfo[NACC]; ! 64: u_short accstd[] = { 0 }; ! 65: struct uba_driver accdriver = ! 66: { accprobe, 0, accattach, 0, accstd, "acc", accinfo }; ! 67: ! 68: int accinit(), accoutput(), accdown(), accreset(); ! 69: ! 70: /* ! 71: * "Lower half" of IMP interface driver. ! 72: * ! 73: * Each IMP interface is handled by a common module which handles ! 74: * the IMP-host protocol and a hardware driver which manages the ! 75: * hardware specific details of talking with the IMP. ! 76: * ! 77: * The hardware portion of the IMP driver handles DMA and related ! 78: * management of UNIBUS resources. The IMP protocol module interprets ! 79: * contents of these messages and "controls" the actions of the ! 80: * hardware module during IMP resets, but not, for instance, during ! 81: * UNIBUS resets. ! 82: * ! 83: * The two modules are coupled at "attach time", and ever after, ! 84: * through the imp interface structure. Higher level protocols, ! 85: * e.g. IP, interact with the IMP driver, rather than the ACC. ! 86: */ ! 87: struct acc_softc { ! 88: struct imp_softc *acc_imp; /* data structure shared with IMP */ ! 89: struct ifuba acc_ifuba; /* UNIBUS resources */ ! 90: struct mbuf *acc_iq; /* input reassembly queue */ ! 91: short acc_olen; /* size of last message sent */ ! 92: char acc_flush; /* flush remainder of message */ ! 93: } acc_softc[NACC]; ! 94: ! 95: /* ! 96: * Reset the IMP and cause a transmitter interrupt by ! 97: * performing a null DMA. ! 98: */ ! 99: accprobe(reg) ! 100: caddr_t reg; ! 101: { ! 102: register int br, cvec; /* r11, r10 value-result */ ! 103: register struct accdevice *addr = (struct accdevice *)reg; ! 104: ! 105: #ifdef lint ! 106: br = 0; cvec = br; br = cvec; ! 107: accrint(0); accxint(0); ! 108: #endif ! 109: addr->icsr = ACC_RESET; DELAY(5000); ! 110: addr->ocsr = ACC_RESET; DELAY(5000); ! 111: addr->ocsr = OUT_BBACK; DELAY(5000); ! 112: addr->owc = 0; ! 113: addr->ocsr = ACC_IE | ACC_GO; DELAY(5000); ! 114: addr->ocsr = 0; ! 115: if (cvec && cvec != 0x200) /* transmit -> receive */ ! 116: cvec -= 4; ! 117: return (1); ! 118: } ! 119: ! 120: /* ! 121: * Call the IMP module to allow it to set up its internal ! 122: * state, then tie the two modules together by setting up ! 123: * the back pointers to common data structures. ! 124: */ ! 125: accattach(ui) ! 126: register struct uba_device *ui; ! 127: { ! 128: register struct acc_softc *sc = &acc_softc[ui->ui_unit]; ! 129: register struct impcb *ip; ! 130: ! 131: if ((sc->acc_imp = impattach(ui->ui_driver->ud_dname, ui->ui_unit, ! 132: accreset)) == 0) ! 133: return; ! 134: ip = &sc->acc_imp->imp_cb; ! 135: ip->ic_init = accinit; ! 136: ip->ic_output = accoutput; ! 137: ip->ic_down = accdown; ! 138: sc->acc_ifuba.ifu_flags = UBA_CANTWAIT; ! 139: #ifdef notdef ! 140: sc->acc_ifuba.ifu_flags |= UBA_NEEDBDP; ! 141: #endif ! 142: } ! 143: ! 144: /* ! 145: * Reset interface after UNIBUS reset. ! 146: * If interface is on specified uba, reset its state. ! 147: */ ! 148: accreset(unit, uban) ! 149: int unit, uban; ! 150: { ! 151: register struct uba_device *ui; ! 152: struct acc_softc *sc; ! 153: ! 154: if (unit >= NACC || (ui = accinfo[unit]) == 0 || ui->ui_alive == 0 || ! 155: ui->ui_ubanum != uban) ! 156: return; ! 157: printf(" acc%d", unit); ! 158: sc = &acc_softc[unit]; ! 159: sc->acc_imp->imp_if.if_flags &= ~IFF_RUNNING; ! 160: accoflush(unit); ! 161: /* must go through IMP to allow it to set state */ ! 162: (*sc->acc_imp->imp_if.if_init)(sc->acc_imp->imp_if.if_unit); ! 163: } ! 164: ! 165: /* ! 166: * Initialize interface: clear recorded pending operations, ! 167: * and retrieve, and initialize UNIBUS resources. Note ! 168: * return value is used by IMP init routine to mark IMP ! 169: * unavailable for outgoing traffic. ! 170: */ ! 171: accinit(unit) ! 172: int unit; ! 173: { ! 174: register struct acc_softc *sc; ! 175: register struct uba_device *ui; ! 176: register struct accdevice *addr; ! 177: int info; ! 178: ! 179: if (unit >= NACC || (ui = accinfo[unit]) == 0 || ui->ui_alive == 0) { ! 180: printf("acc%d: not alive\n", unit); ! 181: return (0); ! 182: } ! 183: sc = &acc_softc[unit]; ! 184: /* ! 185: * Header length is 0 since we have to passs ! 186: * the IMP leader up to the protocol interpretation ! 187: * routines. If we had the header length as ! 188: * sizeof(struct imp_leader), then the if_ routines ! 189: * would asssume we handle it on input and output. ! 190: */ ! 191: if ((sc->acc_imp->imp_if.if_flags & IFF_RUNNING) == 0 && ! 192: if_ubainit(&sc->acc_ifuba, ui->ui_ubanum, 0, ! 193: (int)btoc(IMP_RCVBUF)) == 0) { ! 194: printf("acc%d: can't initialize\n", unit); ! 195: sc->acc_imp->imp_if.if_flags &= ~(IFF_UP | IFF_RUNNING); ! 196: return (0); ! 197: } ! 198: sc->acc_imp->imp_if.if_flags |= IFF_RUNNING; ! 199: addr = (struct accdevice *)ui->ui_addr; ! 200: ! 201: /* ! 202: * Reset the imp interface; ! 203: * the delays are pure guesswork. ! 204: */ ! 205: addr->ocsr = ACC_RESET; DELAY(5000); ! 206: addr->ocsr = OUT_BBACK; DELAY(5000); /* reset host master ready */ ! 207: addr->ocsr = 0; ! 208: if (accinputreset(addr, unit) == 0) { ! 209: ui->ui_alive = 0; ! 210: return (0); ! 211: } ! 212: ! 213: /* ! 214: * Put up a read. We can't restart any outstanding writes ! 215: * until we're back in synch with the IMP (i.e. we've flushed ! 216: * the NOOPs it throws at us). ! 217: * Note: IMP_RCVBUF includes the leader. ! 218: */ ! 219: info = sc->acc_ifuba.ifu_r.ifrw_info; ! 220: addr->iba = (u_short)info; ! 221: addr->iwc = -((IMP_RCVBUF) >> 1); ! 222: #ifdef LOOPBACK ! 223: addr->ocsr |= OUT_BBACK; ! 224: #endif ! 225: addr->icsr = ! 226: IN_MRDY | ACC_IE | IN_WEN | ((info & 0x30000) >> 12) | ACC_GO; ! 227: return (1); ! 228: } ! 229: ! 230: accinputreset(addr, unit) ! 231: register struct accdevice *addr; ! 232: register int unit; ! 233: { ! 234: register int i; ! 235: ! 236: addr->icsr = ACC_RESET; DELAY(5000); ! 237: addr->icsr = IN_MRDY | IN_WEN; /* close the relay */ ! 238: DELAY(10000); ! 239: /* YECH!!! */ ! 240: for (i = 0; i < 500; i++) { ! 241: if ((addr->icsr & IN_HRDY) || ! 242: (addr->icsr & (IN_RMR | IN_IMPBSY)) == 0) ! 243: return (1); ! 244: addr->icsr = IN_MRDY | IN_WEN; DELAY(10000); ! 245: /* keep turning IN_RMR off */ ! 246: } ! 247: printf("acc%d: imp doesn't respond, icsr=%b\n", unit, ! 248: addr->icsr, ACC_INBITS); ! 249: return (0); ! 250: } ! 251: ! 252: /* ! 253: * Drop the host ready line to mark host down. ! 254: */ ! 255: accdown(unit) ! 256: int unit; ! 257: { ! 258: register struct accdevice *addr; ! 259: ! 260: addr = (struct accdevice *)(accinfo[unit]->ui_addr); ! 261: addr->ocsr = ACC_RESET; ! 262: DELAY(5000); ! 263: addr->ocsr = OUT_BBACK; /* reset host master ready */ ! 264: accoflush(unit); ! 265: return (1); ! 266: } ! 267: ! 268: accoflush(unit) ! 269: int unit; ! 270: { ! 271: register struct acc_softc *sc = &acc_softc[unit]; ! 272: ! 273: sc->acc_imp->imp_cb.ic_oactive = 0; ! 274: if (sc->acc_ifuba.ifu_xtofree) { ! 275: m_freem(sc->acc_ifuba.ifu_xtofree); ! 276: sc->acc_ifuba.ifu_xtofree = 0; ! 277: } ! 278: } ! 279: ! 280: /* ! 281: * Start output on an interface. ! 282: */ ! 283: accoutput(unit, m) ! 284: int unit; ! 285: struct mbuf *m; ! 286: { ! 287: int info; ! 288: register struct acc_softc *sc = &acc_softc[unit]; ! 289: register struct accdevice *addr; ! 290: u_short cmd; ! 291: ! 292: sc->acc_olen = if_wubaput(&sc->acc_ifuba, m); ! 293: /* ! 294: * Have request mapped to UNIBUS for ! 295: * transmission; start the output. ! 296: */ ! 297: if (sc->acc_ifuba.ifu_flags & UBA_NEEDBDP) ! 298: UBAPURGE(sc->acc_ifuba.ifu_uba, sc->acc_ifuba.ifu_w.ifrw_bdp); ! 299: addr = (struct accdevice *)accinfo[unit]->ui_addr; ! 300: info = sc->acc_ifuba.ifu_w.ifrw_info; ! 301: addr->oba = (u_short)info; ! 302: addr->owc = -((sc->acc_olen + 1) >> 1); ! 303: cmd = ACC_IE | OUT_ENLB | ((info & 0x30000) >> 12) | ACC_GO; ! 304: #ifdef LOOPBACK ! 305: cmd |= OUT_BBACK; ! 306: #endif ! 307: addr->ocsr = cmd; ! 308: sc->acc_imp->imp_cb.ic_oactive = 1; ! 309: } ! 310: ! 311: /* ! 312: * Output interrupt handler. ! 313: */ ! 314: accxint(unit) ! 315: int unit; ! 316: { ! 317: register struct acc_softc *sc = &acc_softc[unit]; ! 318: register struct accdevice *addr; ! 319: ! 320: addr = (struct accdevice *)accinfo[unit]->ui_addr; ! 321: if (sc->acc_imp->imp_cb.ic_oactive == 0) { ! 322: printf("acc%d: stray xmit interrupt, csr=%b\n", unit, ! 323: addr->ocsr, ACC_OUTBITS); ! 324: return; ! 325: } ! 326: sc->acc_imp->imp_if.if_opackets++; ! 327: sc->acc_imp->imp_cb.ic_oactive = 0; ! 328: if (addr->ocsr & ACC_ERR) { ! 329: printf("acc%d: output error, ocsr=%b, icsr=%b\n", unit, ! 330: addr->ocsr, ACC_OUTBITS, addr->icsr, ACC_INBITS); ! 331: sc->acc_imp->imp_if.if_oerrors++; ! 332: } ! 333: if (sc->acc_ifuba.ifu_xtofree) { ! 334: m_freem(sc->acc_ifuba.ifu_xtofree); ! 335: sc->acc_ifuba.ifu_xtofree = 0; ! 336: } ! 337: impstart(sc->acc_imp); ! 338: } ! 339: ! 340: /* ! 341: * Input interrupt handler ! 342: */ ! 343: accrint(unit) ! 344: int unit; ! 345: { ! 346: register struct acc_softc *sc = &acc_softc[unit]; ! 347: register struct accdevice *addr; ! 348: struct mbuf *m; ! 349: int len, info; ! 350: ! 351: addr = (struct accdevice *)accinfo[unit]->ui_addr; ! 352: sc->acc_imp->imp_if.if_ipackets++; ! 353: ! 354: /* ! 355: * Purge BDP; flush message if error indicated. ! 356: */ ! 357: if (sc->acc_ifuba.ifu_flags & UBA_NEEDBDP) ! 358: UBAPURGE(sc->acc_ifuba.ifu_uba, sc->acc_ifuba.ifu_r.ifrw_bdp); ! 359: if (addr->icsr & ACC_ERR) { ! 360: printf("acc%d: input error, csr=%b\n", unit, ! 361: addr->icsr, ACC_INBITS); ! 362: sc->acc_imp->imp_if.if_ierrors++; ! 363: sc->acc_flush = 1; ! 364: } ! 365: ! 366: if (sc->acc_flush) { ! 367: if (addr->icsr & IN_EOM) ! 368: sc->acc_flush = 0; ! 369: goto setup; ! 370: } ! 371: len = IMP_RCVBUF + (addr->iwc << 1); ! 372: if (len < 0 || len > IMP_RCVBUF) { ! 373: printf("acc%d: bad length=%d\n", unit, len); ! 374: sc->acc_imp->imp_if.if_ierrors++; ! 375: goto setup; ! 376: } ! 377: ! 378: /* ! 379: * The offset parameter is always 0 since using ! 380: * trailers on the ARPAnet is insane. ! 381: */ ! 382: m = if_rubaget(&sc->acc_ifuba, len, 0, &sc->acc_imp->imp_if); ! 383: if (m == 0) ! 384: goto setup; ! 385: if ((addr->icsr & IN_EOM) == 0) { ! 386: if (sc->acc_iq) ! 387: m_cat(sc->acc_iq, m); ! 388: else ! 389: sc->acc_iq = m; ! 390: goto setup; ! 391: } ! 392: if (sc->acc_iq) { ! 393: m_cat(sc->acc_iq, m); ! 394: m = sc->acc_iq; ! 395: sc->acc_iq = 0; ! 396: } ! 397: impinput(unit, m); ! 398: ! 399: setup: ! 400: /* ! 401: * Setup for next message. ! 402: */ ! 403: info = sc->acc_ifuba.ifu_r.ifrw_info; ! 404: addr->iba = (u_short)info; ! 405: addr->iwc = -((IMP_RCVBUF)>> 1); ! 406: addr->icsr = ! 407: IN_MRDY | ACC_IE | IN_WEN | ((info & 0x30000) >> 12) | ACC_GO; ! 408: } ! 409: #endif
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.