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_sri.c 1.1 (2.10BSD Berkeley) 12/1/86 7: */ 8: 9: #include "sri.h" 10: #if NSRI > 0 11: 12: /* 13: * SRI dr11c ARPAnet IMP interface driver. 14: */ 15: 16: #include "param.h" 17: #include "systm.h" 18: #include "mbuf.h" 19: #include "buf.h" 20: #include "domain.h" 21: #include "protosw.h" 22: #include "socket.h" 23: #include "pdpuba/ubavar.h" 24: #include "netinet/in.h" 25: #include "netinet/in_systm.h" 26: #include "net/if.h" 27: #include "pdpif/if_sri.h" 28: #include "netimp/if_imp.h" 29: #include "pdpif/if_uba.h" 30: 31: int sriprobe(), sriattach(), srirint(), srixint(); 32: struct uba_device *sriinfo[NSRI]; 33: u_short sristd[] = { 0 }; 34: struct uba_driver sridriver = 35: { sriprobe, 0, sriattach, 0, sristd, "sri", sriinfo }; 36: #define SRIUNIT(x) minor(x) 37: 38: #define IFRADDR sc->sri_ifuba.ifu_r.ifrw_info 39: #define IFWADDR sc->sri_ifuba.ifu_w.ifrw_info 40: 41: int sriinit(), sristart(), srireset(); 42: 43: /* 44: * "Lower half" of IMP interface driver. 45: * 46: * Each IMP interface is handled by a common module which handles 47: * the IMP-host protocol and a hardware driver which manages the 48: * hardware specific details of talking with the IMP. 49: * 50: * The hardware portion of the IMP driver handles DMA and related 51: * management of UNIBUS resources. The IMP protocol module interprets 52: * contents of these messages and "controls" the actions of the 53: * hardware module during IMP resets, but not, for instance, during 54: * UNIBUS resets. 55: * 56: * The two modules are coupled at "attach time", and ever after, 57: * through the imp interface structure. Higher level protocols, 58: * e.g. IP, interact with the IMP driver, rather than the SRI. 59: */ 60: struct sri_softc { 61: /* pdma registers, shared with assembly helper */ 62: struct sridevice *sri_addr; /* hardware address */ 63: char *sri_iba; /* in byte addr */ 64: short sri_ibc; /* in byte count */ 65: short sri_iclick; /* in click addr */ 66: short sri_ibf; /* in buf (last byte, plus flags) */ 67: short sri_ibusy; /* in dma busy flag */ 68: char *sri_oba; /* out byte addr */ 69: short sri_obc; /* out byte count */ 70: short sri_oclick; /* out click addr */ 71: short sri_oend; /* out end flags */ 72: /* end pdma */ 73: struct ifnet *sri_if; /* pointer to IMP's ifnet struct */ 74: struct impcb *sri_ic; /* data structure shared with IMP */ 75: struct ifuba sri_ifuba; /* UNIBUS resources */ 76: struct mbuf *sri_iq; /* input reassembly queue */ 77: short sri_olen; /* size of last message sent */ 78: char sri_flush; /* flush remainder of message */ 79: } sri_softc[NSRI]; 80: 81: /* 82: * Reset the IMP and cause a transmitter interrupt. 83: */ 84: sriprobe(reg) 85: caddr_t reg; 86: { 87: #if !pdp11 88: register int br, cvec; /* r11, r10 value-result */ 89: register struct sridevice *addr = (struct sridevice *)reg; 90: int i; 91: 92: #ifdef lint 93: br = 0; cvec = br; br = cvec; 94: srirint(0); srixint(0); 95: #endif 96: addr->csr = 0; 97: addr->obf = OUT_HRDY; 98: DELAY(100000L); 99: addr->csr = SRI_OINT|SRI_OENB; 100: addr->obf = OUT_LAST; 101: DELAY(100000L); 102: addr->csr = 0; 103: addr->obf = OUT_HNRDY; 104: if(cvec && cvec != 0x200) 105: return(1); 106: addr->csr = SRI_IINT|SRI_IENB; 107: i = addr->ibf; 108: DELAY(100000L); 109: addr->csr = 0; 110: if(cvec && cvec != 0x200) 111: cvec -= 4; /* report as xmit intr */ 112: return(1); 113: #endif 114: } 115: 116: /* 117: * Call the IMP module to allow it to set up its internal 118: * state, then tie the two modules together by setting up 119: * the back pointers to common data structures. 120: */ 121: sriattach(ui) 122: struct uba_device *ui; 123: { 124: register struct sri_softc *sc = &sri_softc[ui->ui_unit]; 125: register struct impcb *ip; 126: struct ifimpcb { 127: struct ifnet ifimp_if; 128: struct impcb ifimp_impcb; 129: } *ifimp; 130: 131: if ((ifimp = (struct ifimpcb *)impattach(ui, srireset)) == 0) 132: panic("sriattach"); 133: sc->sri_if = &ifimp->ifimp_if; 134: ip = &ifimp->ifimp_impcb; 135: sc->sri_ic = ip; 136: ip->ic_init = sriinit; 137: ip->ic_start = sristart; 138: sc->sri_if->if_reset = srireset; 139: sc->sri_addr = (struct sridevice *) ui->ui_addr; 140: } 141: 142: /* 143: * Reset interface after UNIBUS reset. 144: * If interface is on specified uba, reset its state. 145: */ 146: srireset(unit, uban) 147: int unit, uban; 148: { 149: register struct uba_device *ui; 150: struct sri_softc *sc; 151: 152: if (unit >= NSRI || (ui = sriinfo[unit]) == 0 || ui->ui_alive == 0 || 153: ui->ui_ubanum != uban) 154: return; 155: printf(" sri%d", unit); 156: sc = &sri_softc[unit]; 157: /* must go through IMP to allow it to set state */ 158: (*sc->sri_if->if_init)(unit); 159: } 160: 161: /* 162: * Initialize interface: clear recorded pending operations, 163: * and retrieve, and initialize UNIBUS resources. Note 164: * return value is used by IMP init routine to mark IMP 165: * unavailable for outgoing traffic. 166: */ 167: sriinit(unit) 168: int unit; 169: { 170: register struct sri_softc *sc; 171: register struct uba_device *ui; 172: register struct sridevice *addr; 173: int x, info; 174: 175: if (unit >= NSRI || (ui = sriinfo[unit]) == 0 || ui->ui_alive == 0) { 176: printf("sri%d: not alive\n", unit); 177: return (0); 178: } 179: sc = &sri_softc[unit]; 180: /* 181: * Header length is 0 since we have to passs 182: * the IMP leader up to the protocol interpretation 183: * routines. If we had the header length as 184: * sizeof(struct imp_leader), then the if_ routines 185: * would asssume we handle it on input and output. 186: */ 187: 188: if (if_ubainit(&sc->sri_ifuba, ui->ui_ubanum, 0, 189: (int)btoc(IMPMTU)) == 0) { 190: printf("sri%d: can't initialize\n", unit); 191: goto down; 192: } 193: addr = (struct sridevice *)ui->ui_addr; 194: #if pdp11 195: sc->sri_iclick = (sc->sri_ifuba.ifu_r.ifrw_click); 196: sc->sri_oclick = (sc->sri_ifuba.ifu_w.ifrw_click); 197: #endif 198: 199: /* 200: * Reset the imp interface; 201: * the delays are pure guesswork. 202: */ 203: addr->csr = 0; DELAY(5000L); 204: addr->obf = OUT_HRDY; /* close the relay */ 205: DELAY(10000L); 206: addr->obf = 0; 207: /* YECH!!! */ 208: x = 5; /* was 500 before rdy line code!!! */ 209: while (x-- > 0) { 210: if ((addr->ibf & IN_INRDY) == 0 ) 211: break; 212: DELAY(10000L); 213: } 214: if (x <= 0) { 215: /* printf("sri%d: imp doesn't respond, ibf=%b\n", unit, 216: addr->ibf, SRI_INBITS); 217: */ 218: return(0); /* goto down;*/ 219: } 220: 221: /* 222: * Put up a read. We can't restart any outstanding writes 223: * until we're back in synch with the IMP (i.e. we've flushed 224: * the NOOPs it throws at us). 225: * Note: IMPMTU includes the leader. 226: */ 227: x = splimp(); 228: sc->sri_iba = (char *)IFRADDR; 229: sc->sri_ibc = IMPMTU; 230: sc->sri_ibusy = -1; /* skip leading zeros */ 231: addr->csr |= (SRI_IINT|SRI_IENB); 232: splx(x); 233: return (1); 234: down: 235: ui->ui_alive = 0; 236: return (0); 237: } 238: 239: /* 240: * Start output on an interface. 241: */ 242: sristart(dev) 243: dev_t dev; 244: { 245: int unit = SRIUNIT(dev), info; 246: register struct sri_softc *sc = &sri_softc[unit]; 247: register struct sridevice *addr; 248: struct mbuf *m; 249: u_short cmd; 250: 251: if (sc->sri_ic->ic_oactive) 252: goto restart; 253: 254: /* 255: * Not already active, deqeue a request and 256: * map it onto the UNIBUS. If no more 257: * requeusts, just return. 258: */ 259: IF_DEQUEUE(&sc->sri_if->if_snd, m); 260: if (m == 0) { 261: sc->sri_ic->ic_oactive = 0; 262: return; 263: } 264: sc->sri_olen = ((if_wubaput(&sc->sri_ifuba, m) + 1 ) & ~1); 265: 266: restart: 267: addr = (struct sridevice *)sriinfo[unit]->ui_addr; 268: sc->sri_oba = (char *)IFWADDR; 269: sc->sri_obc = sc->sri_olen; 270: sc->sri_oend = OUT_LAST; 271: sc->sri_obc--; 272: addr->csr |= (SRI_OENB|SRI_OINT); 273: addr->obf = (*sc->sri_oba++ & 0377); 274: sc->sri_ic->ic_oactive = 1; 275: } 276: 277: /* 278: * Output interrupt handler. 279: */ 280: srixint(unit) 281: { 282: register struct sri_softc *sc = &sri_softc[unit]; 283: register struct sridevice *addr = sc->sri_addr; 284: int burst,delay; 285: register int x; 286: 287: burst = 0; 288: while(sc->sri_obc > 0) { 289: x = (*sc->sri_oba++ & 0377); 290: if(--sc->sri_obc <= 0) x |= sc->sri_oend; 291: addr->obf = x; 292: if(++burst > 16) goto out; 293: for(delay=0 ;; delay++) { 294: if(delay > 12) goto out; 295: if(addr->csr&SRI_OREQ) break; 296: } 297: } 298: 299: addr->csr &= ~SRI_OINT; 300: if (sc->sri_ic->ic_oactive == 0) { 301: printf("sri%d: stray xmit interrupt\n", unit); 302: goto out; 303: } 304: sridump("out",IFWADDR,sc->sri_olen); 305: sc->sri_if->if_opackets++; 306: sc->sri_ic->ic_oactive = 0; 307: if (sc->sri_obc != 0) { /* only happens if IMP ready drop */ 308: printf("sri%d: output error, csr=%b\n", unit, 309: addr->csr, SRI_BITS); 310: sc->sri_if->if_oerrors++; 311: } 312: if (sc->sri_ifuba.ifu_xtofree) { 313: m_freem(sc->sri_ifuba.ifu_xtofree); 314: sc->sri_ifuba.ifu_xtofree = 0; 315: } 316: if (sc->sri_if->if_snd.ifq_head) 317: sristart(unit); 318: out: 319: return; 320: } 321: 322: /* 323: * Input interrupt handler 324: */ 325: srirint(unit) 326: { 327: register struct sri_softc *sc = &sri_softc[unit]; 328: struct mbuf *m; 329: int len, info; 330: register struct sridevice *addr = sc->sri_addr; 331: int burst,delay; 332: register int x; 333: 334: burst = 0; 335: for(;;) { 336: addr->csr &= ~SRI_IENB; /* prevents next read from starting */ 337: sc->sri_ibf = x = addr->ibf; 338: if(x & IN_CHECK) break; /* LAST or error */ 339: if(sc->sri_ibc <= 0) break; /* spurrious int */ 340: x &= 0377; 341: if(sc->sri_ibusy < 0) { /* flushing leading zeros */ 342: if(x == 0) goto next; 343: sc->sri_ibusy = 1; 344: } 345: *sc->sri_iba++ = x; 346: if(--sc->sri_ibc <= 0) break; /* count exhausted */ 347: next: 348: addr->csr |= SRI_IENB; /* start next read */ 349: if(++burst > 16) goto out; 350: for(delay=0 ;; delay++) { 351: if(delay > 12) goto out; 352: if(addr->csr&SRI_IREQ) break; 353: } 354: } 355: 356: x = sc->sri_ibf; 357: /* grab the last byte if EOM */ 358: if((x & IN_LAST) && !(x & IN_INRDY) && sc->sri_ibc > 0) { 359: *sc->sri_iba++ = (x & 0377); 360: sc->sri_ibc--; 361: } 362: addr->csr &= ~SRI_IINT; 363: sc->sri_if->if_ipackets++; 364: if ((x & IN_INRDY)) { 365: printf("sri%d: input error, ibf=%b\n", unit, 366: x, SRI_INBITS); 367: sc->sri_if->if_ierrors++; 368: sc->sri_flush = 1; 369: if(sc->sri_obc > 0) { /* if output active */ 370: sc->sri_obc = -1; /* flush it */ 371: srixint(unit); 372: } 373: /* tell "other half" of module that ready line just dropped */ 374: /* Kludge, I know, but the alternative is to create an mbuf */ 375: impinput(unit, (struct mbuf *) 0); /* ready line dropped */ 376: goto out; /* leave interrupts un-enabled */ /* FIX THIS!!!! */ 377: } 378: 379: if (sc->sri_flush) { 380: if (x & IN_LAST) 381: sc->sri_flush = 0; 382: goto setup; 383: } 384: len = IMPMTU - sc->sri_ibc; 385: if (len < 10 || len > IMPMTU) { 386: printf("sri%d: bad length=%d\n", len); 387: sc->sri_if->if_ierrors++; 388: goto setup; 389: } 390: sridump("in ",IFRADDR,len); 391: 392: /* 393: * The next to last parameter is always 0 since using 394: * trailers on the ARPAnet is insane. 395: */ 396: m = if_rubaget(&sc->sri_ifuba, len, 0, &sc->sri_if); 397: if (m == 0) 398: goto setup; 399: if ((x & IN_LAST) == 0) { 400: if (sc->sri_iq) 401: m_cat(sc->sri_iq, m); 402: else 403: sc->sri_iq = m; 404: goto setup; 405: } 406: if (sc->sri_iq) { 407: m_cat(sc->sri_iq, m); 408: m = sc->sri_iq; 409: sc->sri_iq = 0; 410: } 411: impinput(unit, m); 412: 413: setup: 414: /* 415: * Setup for next message. 416: */ 417: sc->sri_iba = (char *)IFRADDR; 418: sc->sri_ibc = IMPMTU; 419: sc->sri_ibusy = -1; /* skip leading zeros */ 420: addr->csr |= (SRI_IINT|SRI_IENB); 421: out: 422: return; 423: } 424: 425: sridump(str,aba,abc) 426: char *str,*aba; 427: { 428: int col,i; 429: 430: if(str[0] != 07) 431: if(!sridebug()) return; 432: printf("%s ",str); 433: col = 0; 434: for(; abc ; abc--) { 435: i = *aba++ & 0377; 436: printf("%o ",i); 437: if(++col > 31) { 438: col = 0; 439: printf("\n "); 440: } 441: } 442: printf("\n"); 443: } 444: 445: #if vax 446: 447: sridebug() 448: { 449: return( (mfpr(RXCS) & RXCS_DONE) == 0 && 450: (mfpr(RXDB) & 0177) == 07); 451: } 452: 453: #endif 454: #if pdp11 455: 456: sridebug() 457: { 458: return( (*(char *)0177560 & 0200) == 0 && 459: (*(char *)0177562 & 0177) == 07); 460: } 461: 462: #endif 463: #endif NSRI