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