|
|
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_pcl.c 7.1 (Berkeley) 6/5/86 ! 7: */ ! 8: ! 9: #include "pcl.h" ! 10: #if NPCL > 0 ! 11: /* ! 12: * DEC CSS PCL-11B Parallel Communications Interface ! 13: * ! 14: * Written by Mike Muuss and Jeff Schwab. ! 15: */ ! 16: #include "../machine/pte.h" ! 17: ! 18: #include "param.h" ! 19: #include "systm.h" ! 20: #include "mbuf.h" ! 21: #include "buf.h" ! 22: #include "protosw.h" ! 23: #include "socket.h" ! 24: #include "vmmac.h" ! 25: #include "ioctl.h" ! 26: #include "errno.h" ! 27: ! 28: #include "../net/if.h" ! 29: #include "../net/netisr.h" ! 30: #include "../net/route.h" ! 31: ! 32: #ifdef INET ! 33: #include "../netinet/in.h" ! 34: #include "../netinet/in_systm.h" ! 35: #include "../netinet/in_var.h" ! 36: #include "../netinet/ip.h" ! 37: #endif ! 38: ! 39: #include "../vax/cpu.h" ! 40: #include "../vax/mtpr.h" ! 41: #include "if_pclreg.h" ! 42: #include "if_uba.h" ! 43: #include "../vaxuba/ubareg.h" ! 44: #include "../vaxuba/ubavar.h" ! 45: ! 46: /* The MTU has been carefully selected to prevent fragmentation <-> ArpaNet */ ! 47: #define PCLMTU (1006) /* Max transmission unit (bytes) */ ! 48: #define PCLMAXTDM 7 /* Max unit number on TDM bus */ ! 49: ! 50: int pclprobe(), pclattach(), pclrint(), pclxint(); ! 51: int pclinit(), pclioctl(), pcloutput(), pclreset(); ! 52: ! 53: struct uba_device *pclinfo[NPCL]; ! 54: u_short pclstd[] = { 0 }; ! 55: #define PCLUNIT(x) minor(x) ! 56: struct uba_driver pcldriver = ! 57: { pclprobe, 0, pclattach, 0, pclstd, "pcl", pclinfo }; ! 58: ! 59: /* ! 60: * PCL software status per interface. ! 61: * ! 62: * Each interface is referenced by a network interface structure, ! 63: * sc_if, which the routing code uses to locate the interface. ! 64: * This structure contains the output queue for the interface, its address, ... ! 65: * We also have, for each interface, a UBA interface structure, which ! 66: * contains information about the UNIBUS resources held by the interface: ! 67: * map registers, buffered data paths, etc. Information is cached in this ! 68: * structure for use by the if_uba.c routines in running the interface ! 69: * efficiently. ! 70: */ ! 71: struct pcl_softc { ! 72: struct ifnet sc_if; /* network-visible interface */ ! 73: struct ifuba sc_ifuba; /* UNIBUS resources */ ! 74: short sc_oactive; /* is output active? */ ! 75: short sc_olen; /* length of last output */ ! 76: short sc_lastdest; /* previous destination */ ! 77: short sc_odest; /* current xmit destination */ ! 78: short sc_bdest; /* buffer's stated destination */ ! 79: short sc_pattern; /* identification pattern */ ! 80: } pcl_softc[NPCL]; ! 81: ! 82: /* ! 83: * Structure of "local header", which only goes between ! 84: * pcloutput and pclstart. ! 85: */ ! 86: struct pcl_header { ! 87: short pcl_dest; /* Destination PCL station */ ! 88: }; ! 89: ! 90: /* ! 91: * Do non-DMA output of 1 word to determine presence of interface, ! 92: * and to find the interupt vector. 1 word messages are a special ! 93: * case in the receiver routine, and will be discarded. ! 94: */ ! 95: pclprobe(reg) ! 96: caddr_t reg; ! 97: { ! 98: register int br, cvec; /* r11, r10 value-result */ ! 99: register struct pcldevice *addr = (struct pcldevice *)reg; ! 100: ! 101: #ifdef lint ! 102: br = 0; cvec = br; br = cvec; ! 103: pclrint(0); pclxint(0); ! 104: #endif ! 105: addr->pcl_rcr = PCL_RCINIT; ! 106: addr->pcl_tcr = PCL_TXINIT; ! 107: addr->pcl_tsba = 0xFFFE; ! 108: /* going for 01777776 */ ! 109: addr->pcl_tsbc = -4; /* really short */ ! 110: addr->pcl_tcr = ! 111: ((1 & 0xF) << 8) | PCL_TXNPR | PCL_SNDWD | PCL_STTXM | PCL_IE | 0x0030; ! 112: DELAY(100000); ! 113: addr->pcl_tcr = PCL_TXINIT; ! 114: return (sizeof (struct pcldevice)); ! 115: } ! 116: ! 117: /* ! 118: * Interface exists: make available by filling in network interface ! 119: * record. System will initialize the interface when it is ready ! 120: * to accept packets. ! 121: */ ! 122: pclattach(ui) ! 123: struct uba_device *ui; ! 124: { ! 125: register struct pcl_softc *sc = &pcl_softc[ui->ui_unit]; ! 126: ! 127: sc->sc_if.if_unit = ui->ui_unit; ! 128: sc->sc_if.if_name = "pcl"; ! 129: sc->sc_if.if_mtu = PCLMTU; ! 130: sc->sc_if.if_init = pclinit; ! 131: sc->sc_if.if_output = pcloutput; ! 132: sc->sc_if.if_ioctl = pclioctl; ! 133: sc->sc_if.if_reset = pclreset; ! 134: sc->sc_if.if_flags = IFF_BROADCAST; ! 135: sc->sc_ifuba.ifu_flags = UBA_NEEDBDP; ! 136: if_attach(&sc->sc_if); ! 137: } ! 138: ! 139: /* ! 140: * Reset of interface after UNIBUS reset. ! 141: * If interface is on specified uba, reset its state. ! 142: */ ! 143: pclreset(unit, uban) ! 144: int unit, uban; ! 145: { ! 146: register struct uba_device *ui; ! 147: ! 148: if (unit >= NPCL || (ui = pclinfo[unit]) == 0 || ui->ui_alive == 0 || ! 149: ui->ui_ubanum != uban) ! 150: return; ! 151: printf(" pcl%d", unit); ! 152: pclinit(unit); ! 153: } ! 154: ! 155: /* ! 156: * Initialization of interface; clear recorded pending ! 157: * operations, and reinitialize UNIBUS usage. ! 158: */ ! 159: pclinit(unit) ! 160: int unit; ! 161: { ! 162: register struct pcl_softc *sc = &pcl_softc[unit]; ! 163: register struct uba_device *ui = pclinfo[unit]; ! 164: register struct pcldevice *addr; ! 165: int s; ! 166: ! 167: if (sc->sc_if.if_addrlist == (struct ifaddr *)0) ! 168: return; ! 169: if (if_ubainit(&sc->sc_ifuba, ui->ui_ubanum, 0, ! 170: (int)btoc(PCLMTU)) == 0) { ! 171: printf("pcl%d: can't init\n", unit); ! 172: sc->sc_if.if_flags &= ~(IFF_UP | IFF_RUNNING); ! 173: return; ! 174: } ! 175: sc->sc_if.if_flags |= IFF_RUNNING; ! 176: addr = (struct pcldevice *)ui->ui_addr; ! 177: addr->pcl_rcr = PCL_RCINIT; ! 178: addr->pcl_tcr = PCL_TXINIT; ! 179: ! 180: /* ! 181: * Hang a receive and start any ! 182: * pending writes by faking a transmit complete. ! 183: */ ! 184: s = splimp(); ! 185: addr->pcl_rdba = (short) sc->sc_ifuba.ifu_r.ifrw_info; ! 186: addr->pcl_rdbc = -PCLMTU; ! 187: addr->pcl_rcr = (((int)(sc->sc_ifuba.ifu_r.ifrw_info>>12))&0x0030) | ! 188: PCL_RCNPR | PCL_RCVWD | PCL_RCVDAT | PCL_IE; ! 189: sc->sc_oactive = 0; ! 190: pclstart(unit); ! 191: splx(s); ! 192: } ! 193: ! 194: /* ! 195: * PCL output routine. ! 196: */ ! 197: pcloutput(ifp, m, dst) ! 198: struct ifnet *ifp; ! 199: struct mbuf *m; ! 200: struct sockaddr *dst; ! 201: { ! 202: int dest, s, error; ! 203: struct pcl_header *pclp; ! 204: struct mbuf *m2; ! 205: ! 206: switch (dst->sa_family) { ! 207: ! 208: #ifdef INET ! 209: case AF_INET: ! 210: if (in_broadcast(((struct sockaddr_in *)dst)->sin_addr)) ! 211: dest = 0; ! 212: else ! 213: dest = in_lnaof(((struct sockaddr_in *)dst)->sin_addr); ! 214: if (dest > PCLMAXTDM) { ! 215: error = EHOSTUNREACH; ! 216: goto bad; ! 217: } ! 218: break; ! 219: #endif ! 220: default: ! 221: printf("pcl%d: can't handle af%d\n", ifp->if_unit, ! 222: dst->sa_family); ! 223: error = EAFNOSUPPORT; ! 224: goto bad; ! 225: } ! 226: ! 227: /* ! 228: * Add pseudo local net header. ! 229: * Actually, it does not get transmitted, but merely stripped ! 230: * off and used by the START routine to route the packet. ! 231: * If no space in first mbuf, allocate another. ! 232: */ ! 233: if (m->m_off > MMAXOFF || ! 234: MMINOFF + sizeof (struct pcl_header) > m->m_off) { ! 235: m2 = m_get(M_DONTWAIT, MT_HEADER); ! 236: if (m2 == 0) { ! 237: error = ENOBUFS; ! 238: goto bad; ! 239: } ! 240: m2->m_next = m; ! 241: m2->m_off = MMINOFF; ! 242: m2->m_len = sizeof (struct pcl_header); ! 243: m = m2; ! 244: } else { ! 245: m->m_off -= sizeof (struct pcl_header); ! 246: m->m_len += sizeof (struct pcl_header); ! 247: } ! 248: pclp = mtod(m, struct pcl_header *); ! 249: pclp->pcl_dest = dest; ! 250: ! 251: /* ! 252: * Queue message on interface, and start output if interface ! 253: * not yet active. ! 254: */ ! 255: s = splimp(); ! 256: if (IF_QFULL(&ifp->if_snd)) { ! 257: IF_DROP(&ifp->if_snd); ! 258: error = ENOBUFS; ! 259: goto qfull; ! 260: } ! 261: IF_ENQUEUE(&ifp->if_snd, m); ! 262: if (pcl_softc[ifp->if_unit].sc_oactive == 0) ! 263: pclstart(ifp->if_unit); ! 264: splx(s); ! 265: return (0); ! 266: qfull: ! 267: splx(s); ! 268: bad: ! 269: m_freem(m); ! 270: return (error); ! 271: } ! 272: ! 273: /* ! 274: * Start or restart output on interface. ! 275: * If interface is already active, then this is a retransmit. ! 276: * If interface is not already active, get another datagram ! 277: * to send off of the interface queue, and map it to the interface ! 278: * before starting the output. ! 279: */ ! 280: pclstart(dev) ! 281: dev_t dev; ! 282: { ! 283: int unit = PCLUNIT(dev); ! 284: struct uba_device *ui = pclinfo[unit]; ! 285: register struct pcl_softc *sc = &pcl_softc[unit]; ! 286: register struct pcldevice *addr; ! 287: struct mbuf *m; ! 288: ! 289: if (sc->sc_oactive) ! 290: goto restart; ! 291: ! 292: /* ! 293: * Not already active: dequeue another request ! 294: * and map it to the UNIBUS. If no more requests, ! 295: * just return. ! 296: */ ! 297: IF_DEQUEUE(&sc->sc_if.if_snd, m); ! 298: if (m == 0) { ! 299: sc->sc_oactive = 0; ! 300: return; ! 301: } ! 302: ! 303: /* ! 304: * Pull destination node out of pseudo-local net header. ! 305: * remove it from outbound data. ! 306: * Note that if_wubaput calls m_bcopy, which is prepared for ! 307: * m_len to be 0 in the first mbuf in the chain. ! 308: */ ! 309: sc->sc_bdest = mtod(m, struct pcl_header *)->pcl_dest; ! 310: sc->sc_odest = sc->sc_bdest? sc->sc_bdest: 1; ! 311: m->m_off += sizeof (struct pcl_header); ! 312: m->m_len -= sizeof (struct pcl_header); ! 313: ! 314: /* Map out to the DMA area */ ! 315: sc->sc_olen = if_wubaput(&sc->sc_ifuba, m); ! 316: ! 317: restart: ! 318: /* ! 319: * Have request mapped to UNIBUS for transmission. ! 320: * Purge any stale data from this BDP, and start the output. ! 321: */ ! 322: if (sc->sc_ifuba.ifu_flags & UBA_NEEDBDP) ! 323: UBAPURGE(sc->sc_ifuba.ifu_uba, sc->sc_ifuba.ifu_w.ifrw_bdp); ! 324: addr = (struct pcldevice *)ui->ui_addr; ! 325: addr->pcl_tcr = PCL_TXINIT; ! 326: addr->pcl_tsba = (int)sc->sc_ifuba.ifu_w.ifrw_info; ! 327: addr->pcl_tsbc = -sc->sc_olen; ! 328: ! 329: /* ! 330: * RIB (retry if busy) is used on the second and subsequent packets ! 331: * to a single host, because TCP often wants to transmit multiple ! 332: * buffers in a row, ! 333: * and if they are all going to the same place, the second and ! 334: * subsequent ones may be lost due to receiver not ready again yet. ! 335: * This can cause serious problems, because the TCP will resend the ! 336: * whole window, which just repeats the problem. The result is that ! 337: * a perfectly good link appears not to work unless we take steps here. ! 338: */ ! 339: addr->pcl_tcr = (((int)(sc->sc_ifuba.ifu_w.ifrw_info>>12))&0x0030) | ! 340: ((sc->sc_odest & 0xF)<<8) | ! 341: PCL_TXNPR | PCL_SNDWD | PCL_STTXM | PCL_IE | ! 342: (sc->sc_odest == sc->sc_lastdest ? PCL_RIB : 0); ! 343: sc->sc_lastdest = sc->sc_odest; ! 344: sc->sc_oactive = 1; ! 345: } ! 346: ! 347: /* ! 348: * PCL transmitter interrupt. ! 349: * Start another output if more data to send. ! 350: */ ! 351: pclxint(unit) ! 352: int unit; ! 353: { ! 354: register struct uba_device *ui = pclinfo[unit]; ! 355: register struct pcl_softc *sc = &pcl_softc[unit]; ! 356: register struct pcldevice *addr = (struct pcldevice *)ui->ui_addr; ! 357: ! 358: if (sc->sc_oactive == 0) { ! 359: printf ("pcl%d: stray interrupt\n", unit); ! 360: return; ! 361: } ! 362: if (addr->pcl_tsr & PCL_ERR) { ! 363: sc->sc_lastdest = 0; /* don't bother with RIB */ ! 364: if (addr->pcl_tsr & PCL_MSTDWN) { ! 365: addr->pcl_tmmr = PCL_MASTER|PCL_AUTOADDR; ! 366: pclstart(unit); /* Retry */ ! 367: printf("pcl%d: master\n", unit ); ! 368: return; ! 369: } ! 370: #ifndef PCL_TESTING ! 371: if ((addr->pcl_tsr & (PCL_ERR|PCL_RESPB)) == (PCL_ERR|0)) { ! 372: ; /* Receiver Offline -- not exactly an error */ ! 373: } else { ! 374: #else ! 375: { ! 376: #endif ! 377: /* Log as an error */ ! 378: printf("pcl%d: send error, tcr=%b tsr=%b\n", ! 379: unit, addr->pcl_tcr, PCL_TCSRBITS, ! 380: addr->pcl_tsr, PCL_TERRBITS); ! 381: sc->sc_if.if_oerrors++; ! 382: } ! 383: } else ! 384: sc->sc_if.if_opackets++; ! 385: if (sc->sc_bdest == 0 && sc->sc_odest < PCLMAXTDM) { ! 386: sc->sc_odest++; /* do next host (broadcast) */ ! 387: } else { ! 388: sc->sc_oactive = 0; ! 389: if (sc->sc_ifuba.ifu_xtofree) { ! 390: m_freem(sc->sc_ifuba.ifu_xtofree); ! 391: sc->sc_ifuba.ifu_xtofree = 0; ! 392: } ! 393: } ! 394: pclstart(unit); ! 395: } ! 396: ! 397: /* ! 398: * PCL interface receiver interrupt. ! 399: * If input error just drop packet. ! 400: */ ! 401: pclrint(unit) ! 402: int unit; ! 403: { ! 404: register struct pcl_softc *sc = &pcl_softc[unit]; ! 405: struct pcldevice *addr = (struct pcldevice *)pclinfo[unit]->ui_addr; ! 406: struct mbuf *m; ! 407: int len; ! 408: register struct ifqueue *inq; ! 409: ! 410: sc->sc_if.if_ipackets++; ! 411: /* ! 412: * Purge BDP; drop if input error indicated. ! 413: */ ! 414: if (sc->sc_ifuba.ifu_flags & UBA_NEEDBDP) ! 415: UBAPURGE(sc->sc_ifuba.ifu_uba, sc->sc_ifuba.ifu_r.ifrw_bdp); ! 416: if (addr->pcl_rsr & PCL_ERR) { ! 417: printf("pcl%d: rcv error, rcr=%b rsr=%b\n", ! 418: unit, addr->pcl_rcr, PCL_RCSRBITS, ! 419: addr->pcl_rsr, PCL_RERRBITS); ! 420: sc->sc_if.if_ierrors++; ! 421: goto setup; ! 422: } ! 423: len = PCLMTU + addr->pcl_rdbc; ! 424: if (len <= 0 || len > PCLMTU) { ! 425: printf("pcl%d: bad len=%d.\n", unit, len); ! 426: sc->sc_if.if_ierrors++; ! 427: goto setup; ! 428: } ! 429: ! 430: /* Really short packets will be part of the startup sequence */ ! 431: if (len <= 4) { ! 432: /* Later, do comming-up processing here */ ! 433: goto setup; /* drop packet */ ! 434: } ! 435: ! 436: /* ! 437: * Pull packet off interface. ! 438: */ ! 439: m = if_rubaget(&sc->sc_ifuba, len, 0, &sc->sc_if); ! 440: if (m == 0) ! 441: goto setup; ! 442: ! 443: schednetisr(NETISR_IP); ! 444: inq = &ipintrq; ! 445: ! 446: if (IF_QFULL(inq)) { ! 447: IF_DROP(inq); ! 448: m_freem(m); ! 449: } else ! 450: IF_ENQUEUE(inq, m); ! 451: setup: ! 452: /* ! 453: * Reset for next packet. ! 454: */ ! 455: addr->pcl_rcr = PCL_RCINIT; ! 456: addr->pcl_rdba = (int)sc->sc_ifuba.ifu_r.ifrw_info; ! 457: addr->pcl_rdbc = -PCLMTU; ! 458: addr->pcl_rcr = (((int)(sc->sc_ifuba.ifu_w.ifrw_info>>12))&0x0030) | ! 459: PCL_RCNPR | PCL_RCVWD | PCL_RCVDAT | PCL_IE; ! 460: } ! 461: ! 462: /* ! 463: * Process an ioctl request. ! 464: */ ! 465: /* ARGSUSED */ ! 466: pclioctl(ifp, cmd, data) ! 467: register struct ifnet *ifp; ! 468: int cmd; ! 469: caddr_t data; ! 470: { ! 471: int s = splimp(), error = 0; ! 472: ! 473: switch (cmd) { ! 474: ! 475: case SIOCSIFADDR: ! 476: ifp->if_flags |= IFF_UP; ! 477: if ((ifp->if_flags & IFF_RUNNING) == 0) ! 478: pclinit(ifp->if_unit); ! 479: break; ! 480: ! 481: default: ! 482: error = EINVAL; ! 483: } ! 484: splx(s); ! 485: return (error); ! 486: } ! 487: #endif
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.