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