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

Defined functions

pclattach defined in line 122; used 2 times
pclinit defined in line 159; used 4 times
pclioctl defined in line 466; used 2 times
pcloutput defined in line 197; used 2 times
pclprobe defined in line 95; used 2 times
pclreset defined in line 143; used 2 times
pclrint defined in line 401; used 2 times
pclstart defined in line 280; used 4 times
pclxint defined in line 351; used 2 times

Defined variables

pcl_softc defined in line 80; used 6 times
pcldriver defined in line 56; never used
pclinfo defined in line 53; used 6 times
pclstd defined in line 54; used 1 times
  • in line 57

Defined struct's

pcl_header defined in line 86; used 18 times
pcl_softc defined in line 71; used 10 times

Defined macros

PCLMAXTDM defined in line 48; used 2 times
PCLMTU defined in line 47; used 6 times
PCLUNIT defined in line 55; used 1 times
Last modified: 1986-06-06
Generated: 2016-12-26
Generated by src2html V0.67
page hit count: 1708
Valid CSS Valid XHTML 1.0 Strict