Annotation of 43BSD/sys/vaxif/if_pcl.c, revision 1.1.1.1

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

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.