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