# 2.11BSD#431 - /usr/src/sys/vaxif/if_pcl.c

##### Functions

    pclattach         X
    pclinit           X
    pclioctl          X
    pcloutput         X
    pclprobe          X
    pclreset          X
    pclrint           X
    pclstart          X
    pclxint           X

##### Variables

    pcl_softc         X
    pcldriver         X
    pclinfo           X
    pclstd            X

##### Macros

    PCLMAXTDM         X
    PCLMTU            X
    PCLUNIT           X

##### struct's

    pcl_header        X
    pcl_softc         X

       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

- in line 50, 57

pclinit defined in line 159; used 4 times

- in line 51, 130, 152, 478

pclioctl defined in line 466; used 2 times

- in line 51, 132

pcloutput defined in line 197; used 2 times

- in line 51, 131

pclprobe defined in line 95; used 2 times

- in line 50, 57

pclreset defined in line 143; used 2 times

- in line 51, 133

pclrint defined in line 401; used 2 times

- in line 50, 103

pclstart defined in line 280; used 4 times

- in line 190, 263, 366, 394

pclxint defined in line 351; used 2 times

- in line 50, 103

#### Defined variables

pcl_softc defined in line 80; used 6 times

- in line 125, 162, 262, 285, 355, 404

pcldriver defined in line 56; never used
pclinfo defined in line 53; used 6 times

- in line 57, 148, 163, 284, 354, 405

pclstd defined in line 54; used 1 times

- in line 57

#### Defined struct's

pcl_header defined in line 86; used 18 times

- in line 203(2), 234(2), 242-248(8), 309-312(6)

pcl_softc defined in line 71; used 10 times

- in line 125(2), 162(2), 285(2), 355(2), 404(2)

#### Defined macros

PCLMAXTDM defined in line 48; used 2 times

- in line 214, 385

PCLMTU defined in line 47; used 6 times

- in line 129, 170, 186, 423-424(2), 457

PCLUNIT defined in line 55; used 1 times

- in line 283

Last modified: 1986-06-06 Generated: 2016-12-26 | Generated by src2html V0.67 page hit count: 286 |