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