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