Annotation of 43BSDReno/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.
                      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

unix.superglobalmegacorp.com

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