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