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 are permitted 6: * provided that this notice is preserved and that due credit is given 7: * to the University of California at Berkeley. The name of the University 8: * may not be used to endorse or promote products derived from this 9: * software without specific prior written permission. This software 10: * is provided ``as is'' without express or implied warranty. 11: * 12: * %W% (Berkeley) %G% 13: */ 14: 15: #include "acc.h" 16: #if NACC > 0 17: 18: /* 19: * ACC LH/DH ARPAnet IMP interface driver. 20: */ 21: #include "../machine/pte.h" 22: 23: #include "param.h" 24: #include "systm.h" 25: #include "mbuf.h" 26: #include "buf.h" 27: #include "protosw.h" 28: #include "socket.h" 29: #include "vmmac.h" 30: 31: #include "../net/if.h" 32: #include "../netimp/if_imp.h" 33: 34: #include "../vax/cpu.h" 35: #include "../vax/mtpr.h" 36: #include "if_accreg.h" 37: #include "if_uba.h" 38: #include "../vaxuba/ubareg.h" 39: #include "../vaxuba/ubavar.h" 40: 41: int accprobe(), accattach(), accrint(), accxint(); 42: struct uba_device *accinfo[NACC]; 43: u_short accstd[] = { 0 }; 44: struct uba_driver accdriver = 45: { accprobe, 0, accattach, 0, accstd, "acc", accinfo }; 46: 47: int accinit(), accoutput(), accdown(), accreset(); 48: 49: /* 50: * "Lower half" of IMP interface driver. 51: * 52: * Each IMP interface is handled by a common module which handles 53: * the IMP-host protocol and a hardware driver which manages the 54: * hardware specific details of talking with the IMP. 55: * 56: * The hardware portion of the IMP driver handles DMA and related 57: * management of UNIBUS resources. The IMP protocol module interprets 58: * contents of these messages and "controls" the actions of the 59: * hardware module during IMP resets, but not, for instance, during 60: * UNIBUS resets. 61: * 62: * The two modules are coupled at "attach time", and ever after, 63: * through the imp interface structure. Higher level protocols, 64: * e.g. IP, interact with the IMP driver, rather than the ACC. 65: */ 66: struct acc_softc { 67: struct imp_softc *acc_imp; /* data structure shared with IMP */ 68: struct ifuba acc_ifuba; /* UNIBUS resources */ 69: struct mbuf *acc_iq; /* input reassembly queue */ 70: short acc_olen; /* size of last message sent */ 71: char acc_flush; /* flush remainder of message */ 72: } acc_softc[NACC]; 73: 74: /* 75: * Reset the IMP and cause a transmitter interrupt by 76: * performing a null DMA. 77: */ 78: accprobe(reg) 79: caddr_t reg; 80: { 81: register int br, cvec; /* r11, r10 value-result */ 82: register struct accdevice *addr = (struct accdevice *)reg; 83: 84: #ifdef lint 85: br = 0; cvec = br; br = cvec; 86: accrint(0); accxint(0); 87: #endif 88: addr->icsr = ACC_RESET; DELAY(5000); 89: addr->ocsr = ACC_RESET; DELAY(5000); 90: addr->ocsr = OUT_BBACK; DELAY(5000); 91: addr->owc = 0; 92: addr->ocsr = ACC_IE | ACC_GO; DELAY(5000); 93: addr->ocsr = 0; 94: if (cvec && cvec != 0x200) /* transmit -> receive */ 95: cvec -= 4; 96: return (1); 97: } 98: 99: /* 100: * Call the IMP module to allow it to set up its internal 101: * state, then tie the two modules together by setting up 102: * the back pointers to common data structures. 103: */ 104: accattach(ui) 105: register struct uba_device *ui; 106: { 107: register struct acc_softc *sc = &acc_softc[ui->ui_unit]; 108: register struct impcb *ip; 109: 110: if ((sc->acc_imp = impattach(ui->ui_driver->ud_dname, ui->ui_unit, 111: accreset)) == 0) 112: return; 113: ip = &sc->acc_imp->imp_cb; 114: ip->ic_init = accinit; 115: ip->ic_output = accoutput; 116: ip->ic_down = accdown; 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_imp->imp_if.if_flags &= ~IFF_RUNNING; 139: /* must go through IMP to allow it to set state */ 140: (*sc->acc_imp->imp_if.if_init)(sc->acc_imp->imp_if.if_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 ((sc->acc_imp->imp_if.if_flags & IFF_RUNNING) == 0 && 170: if_ubainit(&sc->acc_ifuba, ui->ui_ubanum, 0, 171: (int)btoc(IMP_RCVBUF)) == 0) { 172: printf("acc%d: can't initialize\n", unit); 173: sc->acc_imp->imp_if.if_flags &= ~(IFF_UP | IFF_RUNNING); 174: return (0); 175: } 176: sc->acc_imp->imp_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: IMP_RCVBUF includes the leader. 196: */ 197: info = sc->acc_ifuba.ifu_r.ifrw_info; 198: addr->iba = (u_short)info; 199: addr->iwc = -((IMP_RCVBUF) >> 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: * Drop the host ready line to mark host down. 232: */ 233: accdown(unit) 234: int unit; 235: { 236: register struct accdevice *addr; 237: 238: addr = (struct accdevice *)(accinfo[unit]->ui_addr); 239: addr->ocsr = ACC_RESET; 240: DELAY(5000); 241: addr->ocsr = OUT_BBACK; /* reset host master ready */ 242: return (1); 243: } 244: 245: /* 246: * Start output on an interface. 247: */ 248: accoutput(unit, m) 249: int unit; 250: struct mbuf *m; 251: { 252: int info; 253: register struct acc_softc *sc = &acc_softc[unit]; 254: register struct accdevice *addr; 255: u_short cmd; 256: 257: sc->acc_olen = if_wubaput(&sc->acc_ifuba, m); 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_imp->imp_cb.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_imp->imp_cb.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_imp->imp_if.if_opackets++; 292: sc->acc_imp->imp_cb.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_imp->imp_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: impstart(sc->acc_imp); 303: } 304: 305: /* 306: * Input interrupt handler 307: */ 308: accrint(unit) 309: int unit; 310: { 311: register struct acc_softc *sc = &acc_softc[unit]; 312: register struct accdevice *addr; 313: struct mbuf *m; 314: int len, info; 315: 316: addr = (struct accdevice *)accinfo[unit]->ui_addr; 317: sc->acc_imp->imp_if.if_ipackets++; 318: 319: /* 320: * Purge BDP; flush message if error indicated. 321: */ 322: if (sc->acc_ifuba.ifu_flags & UBA_NEEDBDP) 323: UBAPURGE(sc->acc_ifuba.ifu_uba, sc->acc_ifuba.ifu_r.ifrw_bdp); 324: if (addr->icsr & ACC_ERR) { 325: printf("acc%d: input error, csr=%b\n", unit, 326: addr->icsr, ACC_INBITS); 327: sc->acc_imp->imp_if.if_ierrors++; 328: sc->acc_flush = 1; 329: } 330: 331: if (sc->acc_flush) { 332: if (addr->icsr & IN_EOM) 333: sc->acc_flush = 0; 334: goto setup; 335: } 336: len = IMP_RCVBUF + (addr->iwc << 1); 337: if (len < 0 || len > IMP_RCVBUF) { 338: printf("acc%d: bad length=%d\n", unit, len); 339: sc->acc_imp->imp_if.if_ierrors++; 340: goto setup; 341: } 342: 343: /* 344: * The offset parameter is always 0 since using 345: * trailers on the ARPAnet is insane. 346: */ 347: m = if_rubaget(&sc->acc_ifuba, len, 0, &sc->acc_imp->imp_if); 348: if (m == 0) 349: goto setup; 350: if ((addr->icsr & IN_EOM) == 0) { 351: if (sc->acc_iq) 352: m_cat(sc->acc_iq, m); 353: else 354: sc->acc_iq = m; 355: goto setup; 356: } 357: if (sc->acc_iq) { 358: m_cat(sc->acc_iq, m); 359: m = sc->acc_iq; 360: sc->acc_iq = 0; 361: } 362: impinput(unit, m); 363: 364: setup: 365: /* 366: * Setup for next message. 367: */ 368: info = sc->acc_ifuba.ifu_r.ifrw_info; 369: addr->iba = (u_short)info; 370: addr->iwc = -((IMP_RCVBUF)>> 1); 371: addr->icsr = 372: IN_MRDY | ACC_IE | IN_WEN | ((info & 0x30000) >> 12) | ACC_GO; 373: } 374: #endif