Annotation of 43BSD/sys/vaxif/if_qe.c, revision 1.1

1.1     ! root        1: /*     @(#)if_qe.c     7.1 (Berkeley) 6/5/86 */
        !             2: 
        !             3: /* from  @(#)if_qe.c   1.15    (ULTRIX)        4/16/86 */
        !             4:  
        !             5:  
        !             6: /****************************************************************
        !             7:  *                                                             *
        !             8:  *        Licensed from Digital Equipment Corporation          *
        !             9:  *                       Copyright (c)                                 *
        !            10:  *               Digital Equipment Corporation                 *
        !            11:  *                   Maynard, Massachusetts                    *
        !            12:  *                         1985, 1986                          *
        !            13:  *                    All rights reserved.                     *
        !            14:  *                                                             *
        !            15:  *        The Information in this software is subject to change *
        !            16:  *   without notice and should not be construed as a commitment *
        !            17:  *   by  Digital  Equipment  Corporation.   Digital   makes  no *
        !            18:  *   representations about the suitability of this software for *
        !            19:  *   any purpose.  It is supplied "As Is" without expressed  or *
        !            20:  *   implied  warranty.                                        *
        !            21:  *                                                             *
        !            22:  *        If the Regents of the University of California or its *
        !            23:  *   licensees modify the software in a manner creating        *
        !            24:  *   derivative copyright rights, appropriate copyright        *
        !            25:  *   legends may be placed on the derivative work in addition   *
        !            26:  *   to that set forth above.                                  *
        !            27:  *                                                             *
        !            28:  ****************************************************************/
        !            29: /* ---------------------------------------------------------------------
        !            30:  * Modification History 
        !            31:  *
        !            32:  * 15-Apr-86  -- afd
        !            33:  *     Rename "unused_multi" to "qunused_multi" for extending Generic
        !            34:  *     kernel to MicroVAXen.
        !            35:  *
        !            36:  * 18-mar-86  -- jaw     br/cvec changed to NOT use registers.
        !            37:  *
        !            38:  * 12 March 86 -- Jeff Chase
        !            39:  *     Modified to handle the new MCLGET macro
        !            40:  *     Changed if_qe_data.c to use more receive buffers
        !            41:  *     Added a flag to poke with adb to log qe_restarts on console
        !            42:  *
        !            43:  * 19 Oct 85 -- rjl
        !            44:  *     Changed the watch dog timer from 30 seconds to 3.  VMS is using
        !            45:  *     less than 1 second in their's. Also turned the printf into an
        !            46:  *     mprintf.
        !            47:  *
        !            48:  *  09/16/85 -- Larry Cohen
        !            49:  *             Add 43bsd alpha tape changes for subnet routing         
        !            50:  *
        !            51:  *  1 Aug 85 -- rjl
        !            52:  *     Panic on a non-existent memory interrupt and the case where a packet
        !            53:  *     was chained.  The first should never happen because non-existant 
        !            54:  *     memory interrupts cause a bus reset. The second should never happen
        !            55:  *     because we hang 2k input buffers on the device.
        !            56:  *
        !            57:  *  1 Aug 85 -- rich
        !            58:  *      Fixed the broadcast loopback code to handle Clusters without
        !            59:  *      wedging the system.
        !            60:  *
        !            61:  *  27 Feb. 85 -- ejf
        !            62:  *     Return default hardware address on ioctl request.
        !            63:  *
        !            64:  *  12 Feb. 85 -- ejf
        !            65:  *     Added internal extended loopback capability.
        !            66:  *
        !            67:  *  27 Dec. 84 -- rjl
        !            68:  *     Fixed bug that caused every other transmit descriptor to be used
        !            69:  *     instead of every descriptor.
        !            70:  *
        !            71:  *  21 Dec. 84 -- rjl
        !            72:  *     Added watchdog timer to mask hardware bug that causes device lockup.
        !            73:  *
        !            74:  *  18 Dec. 84 -- rjl
        !            75:  *     Reworked driver to use q-bus mapping routines.  MicroVAX-I now does
        !            76:  *     copying instead of m-buf shuffleing.
        !            77:  *     A number of deficencies in the hardware/firmware were compensated
        !            78:  *     for. See comments in qestart and qerint.
        !            79:  *
        !            80:  *  14 Nov. 84 -- jf
        !            81:  *     Added usage counts for multicast addresses.
        !            82:  *     Updated general protocol support to allow access to the Ethernet
        !            83:  *     header.
        !            84:  *
        !            85:  *  04 Oct. 84 -- jf
        !            86:  *     Added support for new ioctls to add and delete multicast addresses
        !            87:  *     and set the physical address.
        !            88:  *     Add support for general protocols.
        !            89:  *
        !            90:  *  14 Aug. 84 -- rjl
        !            91:  *     Integrated Shannon changes. (allow arp above 1024 and ? )
        !            92:  *
        !            93:  *  13 Feb. 84 -- rjl
        !            94:  *
        !            95:  *     Initial version of driver. derived from IL driver.
        !            96:  * 
        !            97:  * ---------------------------------------------------------------------
        !            98:  */
        !            99:  
        !           100: #include "qe.h"
        !           101: #if    NQE > 0
        !           102: /*
        !           103:  * Digital Q-BUS to NI Adapter
        !           104:  */
        !           105: #include "../machine/pte.h"
        !           106: 
        !           107: #include "param.h"
        !           108: #include "systm.h"
        !           109: #include "mbuf.h"
        !           110: #include "buf.h"
        !           111: #include "protosw.h"
        !           112: #include "socket.h"
        !           113: #include "vmmac.h"
        !           114: #include "ioctl.h"
        !           115: #include "errno.h"
        !           116: #include "syslog.h"
        !           117: #include "time.h"
        !           118: #include "kernel.h"
        !           119: 
        !           120: #include "../net/if.h"
        !           121: #include "../net/netisr.h"
        !           122: #include "../net/route.h"
        !           123: 
        !           124: #ifdef INET
        !           125: #include "../netinet/in.h"
        !           126: #include "../netinet/in_systm.h"
        !           127: #include "../netinet/in_var.h"
        !           128: #include "../netinet/ip.h"
        !           129: #include "../netinet/if_ether.h"
        !           130: #endif
        !           131: 
        !           132: #ifdef NS
        !           133: #include "../netns/ns.h"
        !           134: #include "../netns/ns_if.h"
        !           135: #endif
        !           136: 
        !           137: #include "../vax/cpu.h"
        !           138: #include "../vax/mtpr.h"
        !           139: #include "if_qereg.h"
        !           140: #include "if_uba.h"
        !           141: #include "../vaxuba/ubareg.h"
        !           142: #include "../vaxuba/ubavar.h"
        !           143:  
        !           144: #define NRCV   25                      /* Receive descriptors          */
        !           145: #define NXMT   5                       /* Transmit descriptors         */
        !           146: #define NTOT   (NXMT + NRCV)
        !           147:  
        !           148: /*
        !           149:  * This constant should really be 60 because the qna adds 4 bytes of crc.
        !           150:  * However when set to 60 our packets are ignored by deuna's , 3coms are
        !           151:  * okay ??????????????????????????????????????????
        !           152:  */
        !           153: #define MINDATA 64
        !           154:  
        !           155: /*
        !           156:  * Ethernet software status per interface.
        !           157:  *
        !           158:  * Each interface is referenced by a network interface structure,
        !           159:  * is_if, which the routing code uses to locate the interface.
        !           160:  * This structure contains the output queue for the interface, its address, ...
        !           161:  */
        !           162: struct qe_softc {
        !           163:        struct  arpcom is_ac;           /* Ethernet common part         */
        !           164: #define        is_if   is_ac.ac_if             /* network-visible interface    */
        !           165: #define        is_addr is_ac.ac_enaddr         /* hardware Ethernet address    */
        !           166:        struct  ifubinfo qe_uba;        /* Q-bus resources              */
        !           167:        struct  ifrw qe_ifr[NRCV];      /*      for receive buffers;    */
        !           168:        struct  ifxmt qe_ifw[NXMT];     /*      for xmit buffers;       */
        !           169:        int     qe_flags;               /* software state               */
        !           170: #define        QEF_RUNNING     0x01
        !           171: #define        QEF_SETADDR     0x02
        !           172:        int     setupaddr;              /* mapping info for setup pkts  */
        !           173:        struct  qe_ring *rringaddr;     /* mapping info for rings       */
        !           174:        struct  qe_ring *tringaddr;     /*       ""                     */
        !           175:        struct  qe_ring rring[NRCV+1];  /* Receive ring descriptors     */
        !           176:        struct  qe_ring tring[NXMT+1];  /* Transmit ring descriptors    */
        !           177:        u_char  setup_pkt[16][8];       /* Setup packet                 */
        !           178:        int     rindex;                 /* Receive index                */
        !           179:        int     tindex;                 /* Transmit index               */
        !           180:        int     otindex;                /* Old transmit index           */
        !           181:        int     qe_intvec;              /* Interrupt vector             */
        !           182:        struct  qedevice *addr;         /* device addr                  */
        !           183:        int     setupqueued;            /* setup packet queued          */
        !           184:        int     nxmit;                  /* Transmits in progress        */
        !           185:        int     timeout;                /* watchdog                     */
        !           186:        int     qe_restarts;            /* timeouts                     */
        !           187: } qe_softc[NQE];
        !           188: 
        !           189: struct uba_device *qeinfo[NQE];
        !           190:  
        !           191: extern struct timeval time;
        !           192: extern timeout();
        !           193:  
        !           194: int    qeprobe(), qeattach(), qeintr(), qewatch();
        !           195: int    qeinit(),qeoutput(),qeioctl(),qereset(),qewatch();
        !           196:  
        !           197: u_short qestd[] = { 0 };
        !           198: struct uba_driver qedriver =
        !           199:        { qeprobe, 0, qeattach, 0, qestd, "qe", qeinfo };
        !           200:  
        !           201: #define QE_TIMEO       (15)
        !           202: #define        QEUNIT(x)       minor(x)
        !           203: static int mask = 0x3ffff;             /* address mask         */
        !           204: int qewatchrun = 0;                    /* watchdog running     */
        !           205: /*
        !           206:  * The deqna shouldn't receive more than ETHERMTU + sizeof(struct ether_header)
        !           207:  * but will actually take in up to 2048 bytes. To guard against the receiver
        !           208:  * chaining buffers (which we aren't prepared to handle) we allocate 2kb 
        !           209:  * size buffers.
        !           210:  */
        !           211: #define MAXPACKETSIZE 2048             /* Should really be ETHERMTU    */
        !           212: /*
        !           213:  * Probe the QNA to see if it's there
        !           214:  */
        !           215: qeprobe(reg)
        !           216:        caddr_t reg;
        !           217: {
        !           218:        register int br, cvec;          /* r11, r10 value-result */
        !           219:        register struct qedevice *addr = (struct qedevice *)reg;
        !           220:        register struct qe_ring *rp; 
        !           221:        register struct qe_ring *prp;   /* physical rp          */
        !           222:        register int i, j;
        !           223:        static int next=0;              /* softc index          */
        !           224:        register struct qe_softc *sc = &qe_softc[next++];
        !           225:  
        !           226: #ifdef lint
        !           227:        br = 0; cvec = br; br = cvec;
        !           228:        qeintr(0);
        !           229: #endif
        !           230:        /*
        !           231:         * Set the address mask for the particular cpu
        !           232:         */
        !           233:        mask = 0x3ffff;
        !           234:  
        !           235:        /*
        !           236:         * The QNA interrupts on i/o operations. To do an I/O operation 
        !           237:         * we have to setup the interface by transmitting a setup  packet.
        !           238:         */
        !           239:        addr->qe_csr = QE_RESET;
        !           240:        addr->qe_vector = (uba_hd[numuba].uh_lastiv -= 4);
        !           241:  
        !           242:        /*
        !           243:         * Map the communications area and the setup packet.
        !           244:         */
        !           245:        sc->setupaddr =
        !           246:                uballoc(0, (caddr_t)sc->setup_pkt, sizeof(sc->setup_pkt), 0);
        !           247:        sc->rringaddr = (struct qe_ring *) uballoc(0, (caddr_t)sc->rring,
        !           248:                sizeof(struct qe_ring) * (NTOT+2), 0);
        !           249:        prp = (struct qe_ring *)((int)sc->rringaddr & mask);
        !           250:  
        !           251:        /*
        !           252:         * The QNA will loop the setup packet back to the receive ring
        !           253:         * for verification, therefore we initialize the first 
        !           254:         * receive & transmit ring descriptors and link the setup packet
        !           255:         * to them.
        !           256:         */
        !           257:        qeinitdesc(sc->tring, (caddr_t)(sc->setupaddr & mask),
        !           258:            sizeof(sc->setup_pkt));
        !           259:        qeinitdesc(sc->rring, (caddr_t)(sc->setupaddr & mask),
        !           260:            sizeof(sc->setup_pkt));
        !           261:  
        !           262:        rp = (struct qe_ring *)sc->tring;
        !           263:        rp->qe_setup = 1;
        !           264:        rp->qe_eomsg = 1;
        !           265:        rp->qe_flag = rp->qe_status1 = QE_NOTYET;
        !           266:        rp->qe_valid = 1;
        !           267:  
        !           268:        rp = (struct qe_ring *)sc->rring;
        !           269:        rp->qe_flag = rp->qe_status1 = QE_NOTYET;
        !           270:        rp->qe_valid = 1;
        !           271:  
        !           272:        /*
        !           273:         * Get the addr off of the interface and place it into the setup
        !           274:         * packet. This code looks strange due to the fact that the address
        !           275:         * is placed in the setup packet in col. major order. 
        !           276:         */
        !           277:        for( i = 0 ; i < 6 ; i++ )
        !           278:                sc->setup_pkt[i][1] = addr->qe_sta_addr[i];
        !           279:  
        !           280:        qesetup( sc );
        !           281:        /*
        !           282:         * Start the interface and wait for the packet.
        !           283:         */
        !           284:        j = cvec;
        !           285:        addr->qe_csr = QE_INT_ENABLE | QE_XMIT_INT | QE_RCV_INT;
        !           286:        addr->qe_rcvlist_lo = (short)prp;
        !           287:        addr->qe_rcvlist_hi = (short)((int)prp >> 16);
        !           288:        prp += NRCV+1;
        !           289:        addr->qe_xmtlist_lo = (short)prp;
        !           290:        addr->qe_xmtlist_hi = (short)((int)prp >> 16);
        !           291:        DELAY(10000);
        !           292:        /*
        !           293:         * All done with the bus resources.
        !           294:         */
        !           295:        ubarelse(0, &sc->setupaddr);
        !           296:        ubarelse(0, (int *)&sc->rringaddr);
        !           297:        if( cvec == j ) 
        !           298:                return 0;               /* didn't interrupt     */
        !           299:  
        !           300:        return( sizeof(struct qedevice) );
        !           301: }
        !           302:  
        !           303: /*
        !           304:  * Interface exists: make available by filling in network interface
        !           305:  * record.  System will initialize the interface when it is ready
        !           306:  * to accept packets.
        !           307:  */
        !           308: qeattach(ui)
        !           309:        struct uba_device *ui;
        !           310: {
        !           311:        register struct qe_softc *sc = &qe_softc[ui->ui_unit];
        !           312:        register struct ifnet *ifp = &sc->is_if;
        !           313:        register struct qedevice *addr = (struct qedevice *)ui->ui_addr;
        !           314:        register int i;
        !           315:  
        !           316:        ifp->if_unit = ui->ui_unit;
        !           317:        ifp->if_name = "qe";
        !           318:        ifp->if_mtu = ETHERMTU;
        !           319:        ifp->if_flags = IFF_BROADCAST;
        !           320:  
        !           321:        /*
        !           322:         * Read the address from the prom and save it.
        !           323:         */
        !           324:        for( i=0 ; i<6 ; i++ )
        !           325:                sc->setup_pkt[i][1] = sc->is_addr[i] = addr->qe_sta_addr[i] & 0xff;  
        !           326:  
        !           327:        /*
        !           328:         * Save the vector for initialization at reset time.
        !           329:         */
        !           330:        sc->qe_intvec = addr->qe_vector;
        !           331:  
        !           332:        ifp->if_init = qeinit;
        !           333:        ifp->if_output = qeoutput;
        !           334:        ifp->if_ioctl = qeioctl;
        !           335:        ifp->if_reset = qereset;
        !           336:        sc->qe_uba.iff_flags = UBA_CANTWAIT;
        !           337:        if_attach(ifp);
        !           338: }
        !           339:  
        !           340: /*
        !           341:  * Reset of interface after UNIBUS reset.
        !           342:  * If interface is on specified uba, reset its state.
        !           343:  */
        !           344: qereset(unit, uban)
        !           345:        int unit, uban;
        !           346: {
        !           347:        register struct uba_device *ui;
        !           348:  
        !           349:        if (unit >= NQE || (ui = qeinfo[unit]) == 0 || ui->ui_alive == 0 ||
        !           350:                ui->ui_ubanum != uban)
        !           351:                return;
        !           352:        printf(" qe%d", unit);
        !           353:        qe_softc[unit].is_if.if_flags &= ~IFF_RUNNING;
        !           354:        qeinit(unit);
        !           355: }
        !           356:  
        !           357: /*
        !           358:  * Initialization of interface. 
        !           359:  */
        !           360: qeinit(unit)
        !           361:        int unit;
        !           362: {
        !           363:        register struct qe_softc *sc = &qe_softc[unit];
        !           364:        register struct uba_device *ui = qeinfo[unit];
        !           365:        register struct qedevice *addr = (struct qedevice *)ui->ui_addr;
        !           366:        register struct ifnet *ifp = &sc->is_if;
        !           367:        register i;
        !           368:        int s;
        !           369:  
        !           370:        /* address not known */
        !           371:        if (ifp->if_addrlist == (struct ifaddr *)0)
        !           372:                        return;
        !           373:        if (sc->qe_flags & QEF_RUNNING)
        !           374:                return;
        !           375:  
        !           376:        if ((ifp->if_flags & IFF_RUNNING) == 0) {
        !           377:                /*
        !           378:                 * map the communications area onto the device 
        !           379:                 */
        !           380:                sc->rringaddr = (struct qe_ring *)
        !           381:                    ((int) uballoc(0, (caddr_t)sc->rring,
        !           382:                    sizeof(struct qe_ring) * (NTOT+2), 0) & mask);
        !           383:                sc->tringaddr = sc->rringaddr + NRCV + 1;
        !           384:                sc->setupaddr = uballoc(0, (caddr_t)sc->setup_pkt,
        !           385:                    sizeof(sc->setup_pkt), 0) & mask;
        !           386:                /*
        !           387:                 * init buffers and maps
        !           388:                 */
        !           389:                if (if_ubaminit(&sc->qe_uba, ui->ui_ubanum,
        !           390:                    sizeof (struct ether_header), (int)btoc(MAXPACKETSIZE),
        !           391:                    sc->qe_ifr, NRCV, sc->qe_ifw, NXMT) == 0) {
        !           392:                        printf("qe%d: can't initialize\n", unit);
        !           393:                        sc->is_if.if_flags &= ~IFF_UP;
        !           394:                        return;
        !           395:                }
        !           396:        }
        !           397:        /*
        !           398:         * Init the buffer descriptors and indexes for each of the lists and
        !           399:         * loop them back to form a ring.
        !           400:         */
        !           401:        for (i = 0; i < NRCV; i++) {
        !           402:                qeinitdesc( &sc->rring[i],
        !           403:                    (caddr_t)(sc->qe_ifr[i].ifrw_info & mask), MAXPACKETSIZE);
        !           404:                sc->rring[i].qe_flag = sc->rring[i].qe_status1 = QE_NOTYET;
        !           405:                sc->rring[i].qe_valid = 1;
        !           406:        }
        !           407:        qeinitdesc(&sc->rring[i], (caddr_t)NULL, 0);
        !           408:  
        !           409:        sc->rring[i].qe_addr_lo = (short)sc->rringaddr;
        !           410:        sc->rring[i].qe_addr_hi = (short)((int)sc->rringaddr >> 16);
        !           411:        sc->rring[i].qe_chain = 1;
        !           412:        sc->rring[i].qe_flag = sc->rring[i].qe_status1 = QE_NOTYET;
        !           413:        sc->rring[i].qe_valid = 1;
        !           414:  
        !           415:        for( i = 0 ; i <= NXMT ; i++ )
        !           416:                qeinitdesc(&sc->tring[i], (caddr_t)NULL, 0);
        !           417:        i--;
        !           418:  
        !           419:        sc->tring[i].qe_addr_lo = (short)sc->tringaddr;
        !           420:        sc->tring[i].qe_addr_hi = (short)((int)sc->tringaddr >> 16);
        !           421:        sc->tring[i].qe_chain = 1;
        !           422:        sc->tring[i].qe_flag = sc->tring[i].qe_status1 = QE_NOTYET;
        !           423:        sc->tring[i].qe_valid = 1;
        !           424:  
        !           425:        sc->nxmit = sc->otindex = sc->tindex = sc->rindex = 0;
        !           426:  
        !           427:        /*
        !           428:         * Take the interface out of reset, program the vector, 
        !           429:         * enable interrupts, and tell the world we are up.
        !           430:         */
        !           431:        s = splimp();
        !           432:        addr->qe_vector = sc->qe_intvec;
        !           433:        sc->addr = addr;
        !           434:        addr->qe_csr = QE_RCV_ENABLE | QE_INT_ENABLE | QE_XMIT_INT |
        !           435:            QE_RCV_INT | QE_ILOOP;
        !           436:        addr->qe_rcvlist_lo = (short)sc->rringaddr;
        !           437:        addr->qe_rcvlist_hi = (short)((int)sc->rringaddr >> 16);
        !           438:        ifp->if_flags |= IFF_UP | IFF_RUNNING;
        !           439:        sc->qe_flags |= QEF_RUNNING;
        !           440:        qesetup( sc );
        !           441:        qestart( unit );
        !           442:        splx( s );
        !           443:  
        !           444: }
        !           445:  
        !           446: /*
        !           447:  * Start output on interface.
        !           448:  *
        !           449:  */
        !           450: qestart(dev)
        !           451:        dev_t dev;
        !           452: {
        !           453:        int unit = QEUNIT(dev);
        !           454:        struct uba_device *ui = qeinfo[unit];
        !           455:        register struct qe_softc *sc = &qe_softc[unit];
        !           456:        register struct qedevice *addr;
        !           457:        register struct qe_ring *rp;
        !           458:        register index;
        !           459:        struct mbuf *m;
        !           460:        int buf_addr, len, s;
        !           461:  
        !           462:         
        !           463:        s = splimp();
        !           464:        addr = (struct qedevice *)ui->ui_addr;
        !           465:        /*
        !           466:         * The deqna doesn't look at anything but the valid bit
        !           467:         * to determine if it should transmit this packet. If you have
        !           468:         * a ring and fill it the device will loop indefinately on the
        !           469:         * packet and continue to flood the net with packets until you
        !           470:         * break the ring. For this reason we never queue more than n-1
        !           471:         * packets in the transmit ring. 
        !           472:         *
        !           473:         * The microcoders should have obeyed their own defination of the
        !           474:         * flag and status words, but instead we have to compensate.
        !           475:         */
        !           476:        for( index = sc->tindex; 
        !           477:                sc->tring[index].qe_valid == 0 && sc->nxmit < (NXMT-1) ;
        !           478:                sc->tindex = index = ++index % NXMT){
        !           479:                rp = &sc->tring[index];
        !           480:                if( sc->setupqueued ) {
        !           481:                        buf_addr = sc->setupaddr;
        !           482:                        len = 128;
        !           483:                        rp->qe_setup = 1;
        !           484:                        sc->setupqueued = 0;
        !           485:                } else {
        !           486:                        IF_DEQUEUE(&sc->is_if.if_snd, m);
        !           487:                        if( m == 0 ){
        !           488:                                splx(s);
        !           489:                                return;
        !           490:                        }
        !           491:                        buf_addr = sc->qe_ifw[index].ifw_info;
        !           492:                        len = if_ubaput(&sc->qe_uba, &sc->qe_ifw[index], m);
        !           493:                }
        !           494:                /*
        !           495:                 *  Does buffer end on odd byte ? 
        !           496:                 */
        !           497:                if( len & 1 ) {
        !           498:                        len++;
        !           499:                        rp->qe_odd_end = 1;
        !           500:                }
        !           501:                if( len < MINDATA )
        !           502:                        len = MINDATA;
        !           503:                rp->qe_buf_len = -(len/2);
        !           504:                buf_addr &= mask;
        !           505:                rp->qe_flag = rp->qe_status1 = QE_NOTYET;
        !           506:                rp->qe_addr_lo = (short)buf_addr;
        !           507:                rp->qe_addr_hi = (short)(buf_addr >> 16);
        !           508:                rp->qe_eomsg = 1;
        !           509:                rp->qe_flag = rp->qe_status1 = QE_NOTYET;
        !           510:                rp->qe_valid = 1;
        !           511:                sc->nxmit++;
        !           512:                /*
        !           513:                 * If the watchdog time isn't running kick it.
        !           514:                 */
        !           515:                sc->timeout=1;
        !           516:                if (qewatchrun == 0) { 
        !           517:                        qewatchrun++; 
        !           518:                        timeout(qewatch, (caddr_t)0, QE_TIMEO);
        !           519:                }
        !           520:                        
        !           521:                /*
        !           522:                 * See if the xmit list is invalid.
        !           523:                 */
        !           524:                if( addr->qe_csr & QE_XL_INVALID ) {
        !           525:                        buf_addr = (int)(sc->tringaddr+index);
        !           526:                        addr->qe_xmtlist_lo = (short)buf_addr;
        !           527:                        addr->qe_xmtlist_hi = (short)(buf_addr >> 16);
        !           528:                }
        !           529:        }
        !           530:        splx( s );
        !           531: }
        !           532:  
        !           533: /*
        !           534:  * Ethernet interface interrupt processor
        !           535:  */
        !           536: qeintr(unit)
        !           537:        int unit;
        !           538: {
        !           539:        register struct qe_softc *sc = &qe_softc[unit];
        !           540:        struct qedevice *addr = (struct qedevice *)qeinfo[unit]->ui_addr;
        !           541:        int s, buf_addr, csr;
        !           542:  
        !           543:        s = splimp();
        !           544:        csr = addr->qe_csr;
        !           545:        addr->qe_csr = QE_RCV_ENABLE | QE_INT_ENABLE | QE_XMIT_INT | QE_RCV_INT | QE_ILOOP;
        !           546:        if( csr & QE_RCV_INT ) 
        !           547:                qerint( unit );
        !           548:        if( csr & QE_XMIT_INT )
        !           549:                qetint( unit );
        !           550:        if( csr & QE_NEX_MEM_INT )
        !           551:                panic("qe: Non existant memory interrupt");
        !           552:        
        !           553:        if( addr->qe_csr & QE_RL_INVALID && sc->rring[sc->rindex].qe_status1 == QE_NOTYET ) {
        !           554:                buf_addr = (int)&sc->rringaddr[sc->rindex];
        !           555:                addr->qe_rcvlist_lo = (short)buf_addr;
        !           556:                addr->qe_rcvlist_hi = (short)(buf_addr >> 16);
        !           557:        }
        !           558:        splx( s );
        !           559: }
        !           560:  
        !           561: /*
        !           562:  * Ethernet interface transmit interrupt.
        !           563:  */
        !           564:  
        !           565: qetint(unit)
        !           566:        int unit;
        !           567: {
        !           568:        register struct qe_softc *sc = &qe_softc[unit];
        !           569:        register struct qe_ring *rp;
        !           570:        register struct ifxmt *ifxp;
        !           571:        int status1, setupflag;
        !           572:        short len;
        !           573:  
        !           574:  
        !           575:        while( sc->otindex != sc->tindex && sc->tring[sc->otindex].qe_status1 != QE_NOTYET && sc->nxmit > 0 ) {
        !           576:                /*
        !           577:                 * Save the status words from the descriptor so that it can
        !           578:                 * be released.
        !           579:                 */
        !           580:                rp = &sc->tring[sc->otindex];
        !           581:                status1 = rp->qe_status1;
        !           582:                setupflag = rp->qe_setup;
        !           583:                len = (-rp->qe_buf_len) * 2;
        !           584:                if( rp->qe_odd_end )
        !           585:                        len++;
        !           586:                /*
        !           587:                 * Init the buffer descriptor
        !           588:                 */
        !           589:                bzero((caddr_t)rp, sizeof(struct qe_ring));
        !           590:                if( --sc->nxmit == 0 )
        !           591:                        sc->timeout = 0;
        !           592:                if( !setupflag ) {
        !           593:                        /*
        !           594:                         * Do some statistics.
        !           595:                         */
        !           596:                        sc->is_if.if_opackets++;
        !           597:                        sc->is_if.if_collisions += ( status1 & QE_CCNT ) >> 4;
        !           598:                        if (status1 & QE_ERROR)
        !           599:                                sc->is_if.if_oerrors++;
        !           600:                        /*
        !           601:                         * If this was a broadcast packet loop it
        !           602:                         * back because the hardware can't hear its own
        !           603:                         * transmits.
        !           604:                         */
        !           605:                        ifxp = &sc->qe_ifw[sc->otindex];
        !           606:                        if (bcmp((caddr_t)ifxp->ifw_addr,
        !           607:                            (caddr_t)etherbroadcastaddr,
        !           608:                            sizeof(etherbroadcastaddr)) == 0)
        !           609:                                qeread(sc, &ifxp->ifrw, len);
        !           610:                        if (ifxp->ifw_xtofree) {
        !           611:                                m_freem(ifxp->ifw_xtofree);
        !           612:                                ifxp->ifw_xtofree = 0;
        !           613:                        }
        !           614:                }
        !           615:                sc->otindex = ++sc->otindex % NXMT;
        !           616:        }
        !           617:        qestart( unit );
        !           618: }
        !           619:  
        !           620: /*
        !           621:  * Ethernet interface receiver interrupt.
        !           622:  * If can't determine length from type, then have to drop packet.  
        !           623:  * Othewise decapsulate packet based on type and pass to type specific 
        !           624:  * higher-level input routine.
        !           625:  */
        !           626: qerint(unit)
        !           627:        int unit;
        !           628: {
        !           629:        register struct qe_softc *sc = &qe_softc[unit];
        !           630:        register struct qe_ring *rp;
        !           631:        int len, status1, status2;
        !           632:        int bufaddr;
        !           633:  
        !           634:        /*
        !           635:         * Traverse the receive ring looking for packets to pass back.
        !           636:         * The search is complete when we find a descriptor not in use.
        !           637:         *
        !           638:         * As in the transmit case the deqna doesn't honor it's own protocols
        !           639:         * so there exists the possibility that the device can beat us around
        !           640:         * the ring. The proper way to guard against this is to insure that
        !           641:         * there is always at least one invalid descriptor. We chose instead
        !           642:         * to make the ring large enough to minimize the problem. With a ring
        !           643:         * size of 4 we haven't been able to see the problem. To be safe we
        !           644:         * doubled that to 8.
        !           645:         *
        !           646:         */
        !           647:        for( ; sc->rring[sc->rindex].qe_status1 != QE_NOTYET ; sc->rindex = ++sc->rindex % NRCV ){
        !           648:                rp = &sc->rring[sc->rindex];
        !           649:                status1 = rp->qe_status1;
        !           650:                status2 = rp->qe_status2;
        !           651:                bzero((caddr_t)rp, sizeof(struct qe_ring));
        !           652:                if( (status1 & QE_MASK) == QE_MASK )
        !           653:                        panic("qe: chained packet");
        !           654:                len = ((status1 & QE_RBL_HI) | (status2 & QE_RBL_LO)) + 60;
        !           655:                sc->is_if.if_ipackets++;
        !           656:  
        !           657:                if (status1 & QE_ERROR)
        !           658:                        sc->is_if.if_ierrors++;
        !           659:                else {
        !           660:                        /*
        !           661:                         * We don't process setup packets.
        !           662:                         */
        !           663:                        if( !(status1 & QE_ESETUP) )
        !           664:                                qeread(sc, &sc->qe_ifr[sc->rindex],
        !           665:                                        len - sizeof(struct ether_header));
        !           666:                }
        !           667:                /*
        !           668:                 * Return the buffer to the ring
        !           669:                 */
        !           670:                bufaddr = (int)sc->qe_ifr[sc->rindex].ifrw_info & mask;
        !           671:                rp->qe_buf_len = -((MAXPACKETSIZE)/2);
        !           672:                rp->qe_addr_lo = (short)bufaddr;
        !           673:                rp->qe_addr_hi = (short)((int)bufaddr >> 16);
        !           674:                rp->qe_flag = rp->qe_status1 = QE_NOTYET;
        !           675:                rp->qe_valid = 1;
        !           676:        }
        !           677: }
        !           678: /*
        !           679:  * Ethernet output routine.
        !           680:  * Encapsulate a packet of type family for the local net.
        !           681:  * Use trailer local net encapsulation if enough data in first
        !           682:  * packet leaves a multiple of 512 bytes of data in remainder.
        !           683:  */
        !           684: qeoutput(ifp, m0, dst)
        !           685:        struct ifnet *ifp;
        !           686:        struct mbuf *m0;
        !           687:        struct sockaddr *dst;
        !           688: {
        !           689:        int type, s, error;
        !           690:        u_char edst[6];
        !           691:        struct in_addr idst;
        !           692:        register struct qe_softc *is = &qe_softc[ifp->if_unit];
        !           693:        register struct mbuf *m = m0;
        !           694:        register struct ether_header *eh;
        !           695:        register int off;
        !           696:        int usetrailers;
        !           697:  
        !           698:        if ((ifp->if_flags & (IFF_UP|IFF_RUNNING)) != (IFF_UP|IFF_RUNNING)) {
        !           699:                error = ENETDOWN;
        !           700:                goto bad;
        !           701:        }
        !           702: 
        !           703:        switch (dst->sa_family) {
        !           704:  
        !           705: #ifdef INET
        !           706:        case AF_INET:
        !           707:                idst = ((struct sockaddr_in *)dst)->sin_addr;
        !           708:                if (!arpresolve(&is->is_ac, m, &idst, edst, &usetrailers))
        !           709:                        return (0);     /* if not yet resolved */
        !           710:                off = ntohs((u_short)mtod(m, struct ip *)->ip_len) - m->m_len;
        !           711:                if (usetrailers && off > 0 && (off & 0x1ff) == 0 &&
        !           712:                    m->m_off >= MMINOFF + 2 * sizeof (u_short)) {
        !           713:                        type = ETHERTYPE_TRAIL + (off>>9);
        !           714:                        m->m_off -= 2 * sizeof (u_short);
        !           715:                        m->m_len += 2 * sizeof (u_short);
        !           716:                        *mtod(m, u_short *) = htons((u_short)ETHERTYPE_IP);
        !           717:                        *(mtod(m, u_short *) + 1) = htons((u_short)m->m_len);
        !           718:                        goto gottrailertype;
        !           719:                }
        !           720:                type = ETHERTYPE_IP;
        !           721:                off = 0;
        !           722:                goto gottype;
        !           723: #endif
        !           724: #ifdef NS
        !           725:        case AF_NS:
        !           726:                type = ETHERTYPE_NS;
        !           727:                bcopy((caddr_t)&(((struct sockaddr_ns *)dst)->sns_addr.x_host),
        !           728:                    (caddr_t)edst, sizeof (edst));
        !           729:                off = 0;
        !           730:                goto gottype;
        !           731: #endif
        !           732: 
        !           733:  
        !           734:        case AF_UNSPEC:
        !           735:                eh = (struct ether_header *)dst->sa_data;
        !           736:                bcopy((caddr_t)eh->ether_dhost, (caddr_t)edst, sizeof (edst));
        !           737:                type = eh->ether_type;
        !           738:                goto gottype;
        !           739:  
        !           740:        default:
        !           741:                printf("qe%d: can't handle af%d\n", ifp->if_unit,
        !           742:                        dst->sa_family);
        !           743:                error = EAFNOSUPPORT;
        !           744:                goto bad;
        !           745:        }
        !           746:  
        !           747: gottrailertype:
        !           748:        /*
        !           749:         * Packet to be sent as trailer: move first packet
        !           750:         * (control information) to end of chain.
        !           751:         */
        !           752:        while (m->m_next)
        !           753:                m = m->m_next;
        !           754:        m->m_next = m0;
        !           755:        m = m0->m_next;
        !           756:        m0->m_next = 0;
        !           757:        m0 = m;
        !           758:  
        !           759: gottype:
        !           760:        /*
        !           761:         * Add local net header.  If no space in first mbuf,
        !           762:         * allocate another.
        !           763:         */
        !           764:        if (m->m_off > MMAXOFF ||
        !           765:            MMINOFF + sizeof (struct ether_header) > m->m_off) {
        !           766:                m = m_get(M_DONTWAIT, MT_HEADER);
        !           767:                if (m == 0) {
        !           768:                        error = ENOBUFS;
        !           769:                        goto bad;
        !           770:                }
        !           771:                m->m_next = m0;
        !           772:                m->m_off = MMINOFF;
        !           773:                m->m_len = sizeof (struct ether_header);
        !           774:        } else {
        !           775:                m->m_off -= sizeof (struct ether_header);
        !           776:                m->m_len += sizeof (struct ether_header);
        !           777:        }
        !           778:        eh = mtod(m, struct ether_header *);
        !           779:        eh->ether_type = htons((u_short)type);
        !           780:        bcopy((caddr_t)edst, (caddr_t)eh->ether_dhost, sizeof (edst));
        !           781:        bcopy((caddr_t)is->is_addr, (caddr_t)eh->ether_shost, sizeof (is->is_addr));
        !           782:  
        !           783:        /*
        !           784:         * Queue message on interface, and start output if interface
        !           785:         * not yet active.
        !           786:         */
        !           787:        s = splimp();
        !           788:        if (IF_QFULL(&ifp->if_snd)) {
        !           789:                IF_DROP(&ifp->if_snd);
        !           790:                splx(s);
        !           791:                m_freem(m);
        !           792:                return (ENOBUFS);
        !           793:        }
        !           794:        IF_ENQUEUE(&ifp->if_snd, m);
        !           795:        qestart(ifp->if_unit);
        !           796:        splx(s);
        !           797:        return (0);
        !           798:  
        !           799: bad:
        !           800:        m_freem(m0);
        !           801:        return (error);
        !           802: }
        !           803:  
        !           804:  
        !           805: /*
        !           806:  * Process an ioctl request.
        !           807:  */
        !           808: qeioctl(ifp, cmd, data)
        !           809:        register struct ifnet *ifp;
        !           810:        int cmd;
        !           811:        caddr_t data;
        !           812: {
        !           813:        struct qe_softc *sc = &qe_softc[ifp->if_unit];
        !           814:        struct ifaddr *ifa = (struct ifaddr *)data;
        !           815:        int s = splimp(), error = 0;
        !           816:  
        !           817:        switch (cmd) {
        !           818:  
        !           819:        case SIOCSIFADDR:
        !           820:                ifp->if_flags |= IFF_UP;
        !           821:                qeinit(ifp->if_unit);
        !           822:                switch(ifa->ifa_addr.sa_family) {
        !           823: #ifdef INET
        !           824:                case AF_INET:
        !           825:                        ((struct arpcom *)ifp)->ac_ipaddr =
        !           826:                                IA_SIN(ifa)->sin_addr;
        !           827:                        arpwhohas((struct arpcom *)ifp, &IA_SIN(ifa)->sin_addr);
        !           828:                        break;
        !           829: #endif
        !           830: #ifdef NS
        !           831:                case AF_NS:
        !           832:                    {
        !           833:                        register struct ns_addr *ina = &(IA_SNS(ifa)->sns_addr);
        !           834:                        
        !           835:                        if (ns_nullhost(*ina))
        !           836:                                ina->x_host = *(union ns_host *)(sc->is_addr);
        !           837:                        else
        !           838:                                qe_setaddr(ina->x_host.c_host, ifp->if_unit);
        !           839:                        break;
        !           840:                    }
        !           841: #endif
        !           842:                }
        !           843:                break;
        !           844: 
        !           845:        case SIOCSIFFLAGS:
        !           846:                if ((ifp->if_flags & IFF_UP) == 0 &&
        !           847:                    sc->qe_flags & QEF_RUNNING) {
        !           848:                        ((struct qedevice *)
        !           849:                           (qeinfo[ifp->if_unit]->ui_addr))->qe_csr = QE_RESET;
        !           850:                        sc->qe_flags &= ~QEF_RUNNING;
        !           851:                } else if (ifp->if_flags & IFF_UP &&
        !           852:                    (sc->qe_flags & QEF_RUNNING) == 0)
        !           853:                        qerestart(sc);
        !           854:                break;
        !           855: 
        !           856:        default:
        !           857:                error = EINVAL;
        !           858:  
        !           859:        }
        !           860:        splx(s);
        !           861:        return (error);
        !           862: }
        !           863:  
        !           864: /*
        !           865:  * set ethernet address for unit
        !           866:  */
        !           867: qe_setaddr(physaddr, unit)
        !           868:        u_char *physaddr;
        !           869:        int unit;
        !           870: {
        !           871:        register struct qe_softc *sc = &qe_softc[unit];
        !           872:        register int i;
        !           873: 
        !           874:        for (i = 0; i < 6; i++)
        !           875:                sc->setup_pkt[i][1] = sc->is_addr[i] = physaddr[i];
        !           876:        sc->qe_flags |= QEF_SETADDR;
        !           877:        if (sc->is_if.if_flags & IFF_RUNNING)
        !           878:                qesetup(sc);
        !           879:        qeinit(unit);
        !           880: }
        !           881:  
        !           882:  
        !           883: /*
        !           884:  * Initialize a ring descriptor with mbuf allocation side effects
        !           885:  */
        !           886: qeinitdesc(rp, addr, len)
        !           887:        register struct qe_ring *rp;
        !           888:        caddr_t addr;                   /* mapped address */
        !           889:        int len;
        !           890: {
        !           891:        /*
        !           892:         * clear the entire descriptor
        !           893:         */
        !           894:        bzero((caddr_t)rp, sizeof(struct qe_ring));
        !           895:  
        !           896:        if( len ) {
        !           897:                rp->qe_buf_len = -(len/2);
        !           898:                rp->qe_addr_lo = (short)addr;
        !           899:                rp->qe_addr_hi = (short)((int)addr >> 16);
        !           900:        }
        !           901: }
        !           902: /*
        !           903:  * Build a setup packet - the physical address will already be present
        !           904:  * in first column.
        !           905:  */
        !           906: qesetup( sc )
        !           907: struct qe_softc *sc;
        !           908: {
        !           909:        register i, j;
        !           910:  
        !           911:        /*
        !           912:         * Copy the target address to the rest of the entries in this row.
        !           913:         */
        !           914:         for ( j = 0; j < 6 ; j++ )
        !           915:                for ( i = 2 ; i < 8 ; i++ )
        !           916:                        sc->setup_pkt[j][i] = sc->setup_pkt[j][1];
        !           917:        /*
        !           918:         * Duplicate the first half.
        !           919:         */
        !           920:        bcopy((caddr_t)sc->setup_pkt[0], (caddr_t)sc->setup_pkt[8], 64);
        !           921:        /*
        !           922:         * Fill in the broadcast address.
        !           923:         */
        !           924:        for ( i = 0; i < 6 ; i++ )
        !           925:                sc->setup_pkt[i][2] = 0xff;
        !           926:        sc->setupqueued++;
        !           927: }
        !           928: 
        !           929: /*
        !           930:  * Pass a packet to the higher levels.
        !           931:  * We deal with the trailer protocol here.
        !           932:  */
        !           933: qeread(sc, ifrw, len)
        !           934:        register struct qe_softc *sc;
        !           935:        struct ifrw *ifrw;
        !           936:        int len;
        !           937: {
        !           938:        struct ether_header *eh;
        !           939:        struct mbuf *m;
        !           940:        int off, resid;
        !           941:        struct ifqueue *inq;
        !           942:  
        !           943:        /*
        !           944:         * Deal with trailer protocol: if type is INET trailer
        !           945:         * get true type from first 16-bit word past data.
        !           946:         * Remember that type was trailer by setting off.
        !           947:         */
        !           948:  
        !           949:        eh = (struct ether_header *)ifrw->ifrw_addr;
        !           950:        eh->ether_type = ntohs((u_short)eh->ether_type);
        !           951: #define        qedataaddr(eh, off, type)       ((type)(((caddr_t)((eh)+1)+(off))))
        !           952:        if (eh->ether_type >= ETHERTYPE_TRAIL &&
        !           953:            eh->ether_type < ETHERTYPE_TRAIL+ETHERTYPE_NTRAILER) {
        !           954:                off = (eh->ether_type - ETHERTYPE_TRAIL) * 512;
        !           955:                if (off >= ETHERMTU)
        !           956:                        return;         /* sanity */
        !           957:                eh->ether_type = ntohs(*qedataaddr(eh,off, u_short *));
        !           958:                resid = ntohs(*(qedataaddr(eh, off+2, u_short *)));
        !           959:                if (off + resid > len)
        !           960:                     return;            /* sanity */
        !           961:                len = off + resid;
        !           962:        } else
        !           963:                off = 0;
        !           964:        if (len == 0)
        !           965:                return;
        !           966:  
        !           967:        /*
        !           968:         * Pull packet off interface.  Off is nonzero if packet
        !           969:         * has trailing header; qeget will then force this header
        !           970:         * information to be at the front, but we still have to drop
        !           971:         * the type and length which are at the front of any trailer data.
        !           972:         */
        !           973:        m = if_ubaget(&sc->qe_uba, ifrw, len, off, &sc->is_if);
        !           974:  
        !           975:        if (m == 0)
        !           976:                return;
        !           977:  
        !           978:        if (off) {
        !           979:                struct ifnet *ifp;
        !           980: 
        !           981:                ifp = *(mtod(m, struct ifnet **));
        !           982:                m->m_off += 2 * sizeof (u_short);
        !           983:                m->m_len -= 2 * sizeof (u_short);
        !           984:                *(mtod(m, struct ifnet **)) = ifp;
        !           985:        }
        !           986:        switch (eh->ether_type) {
        !           987: 
        !           988: #ifdef INET
        !           989:        case ETHERTYPE_IP:
        !           990:                schednetisr(NETISR_IP);
        !           991:                inq = &ipintrq;
        !           992:                break;
        !           993: 
        !           994:        case ETHERTYPE_ARP:
        !           995:                arpinput(&sc->is_ac, m);
        !           996:                return;
        !           997: #endif
        !           998: #ifdef NS
        !           999:        case ETHERTYPE_NS:
        !          1000:                schednetisr(NETISR_NS);
        !          1001:                inq = &nsintrq;
        !          1002:                break;
        !          1003: 
        !          1004: #endif
        !          1005:  
        !          1006:        default:
        !          1007:                m_freem(m);
        !          1008:                return;
        !          1009:        }
        !          1010:  
        !          1011:        if (IF_QFULL(inq)) {
        !          1012:                IF_DROP(inq);
        !          1013:                m_freem(m);
        !          1014:                return;
        !          1015:        }
        !          1016:        IF_ENQUEUE(inq, m);
        !          1017: }
        !          1018: 
        !          1019: /*
        !          1020:  * Watchdog timer routine. There is a condition in the hardware that
        !          1021:  * causes the board to lock up under heavy load. This routine detects
        !          1022:  * the hang up and restarts the device.
        !          1023:  */
        !          1024: qewatch()
        !          1025: {
        !          1026:        register struct qe_softc *sc;
        !          1027:        register int i;
        !          1028:        int inprogress=0;
        !          1029:  
        !          1030:        for (i = 0; i < NQE; i++) {
        !          1031:                sc = &qe_softc[i];
        !          1032:                if (sc->timeout) 
        !          1033:                        if (++sc->timeout > 3 ) {
        !          1034:                                log(LOG_ERR,
        !          1035:                                     "qerestart: restarted qe%d %d\n",
        !          1036:                                     i, ++sc->qe_restarts);
        !          1037:                                qerestart(sc);
        !          1038:                        } else
        !          1039:                                inprogress++;
        !          1040:        }
        !          1041:        if (inprogress) {
        !          1042:                timeout(qewatch, (caddr_t)0, QE_TIMEO);
        !          1043:                qewatchrun++;
        !          1044:        } else
        !          1045:                qewatchrun=0;
        !          1046: }
        !          1047: /*
        !          1048:  * Restart for board lockup problem.
        !          1049:  */
        !          1050: qerestart(sc)
        !          1051:        register struct qe_softc *sc;
        !          1052: {
        !          1053:        register struct ifnet *ifp = &sc->is_if;
        !          1054:        register struct qedevice *addr = sc->addr;
        !          1055:        register struct qe_ring *rp;
        !          1056:        register i;
        !          1057:  
        !          1058:        addr->qe_csr = QE_RESET;
        !          1059:        sc->timeout = 0;
        !          1060:        qesetup( sc );
        !          1061:        for (i = 0, rp = sc->tring; i < NXMT; rp++, i++) {
        !          1062:                rp->qe_flag = rp->qe_status1 = QE_NOTYET;
        !          1063:                rp->qe_valid = 0;
        !          1064:        }
        !          1065:        sc->nxmit = sc->otindex = sc->tindex = sc->rindex = 0;
        !          1066:        addr->qe_csr = QE_RCV_ENABLE | QE_INT_ENABLE | QE_XMIT_INT |
        !          1067:            QE_RCV_INT | QE_ILOOP;
        !          1068:        addr->qe_rcvlist_lo = (short)sc->rringaddr;
        !          1069:        addr->qe_rcvlist_hi = (short)((int)sc->rringaddr >> 16);
        !          1070:        sc->qe_flags |= QEF_RUNNING;
        !          1071:        qestart(ifp->if_unit);
        !          1072: }
        !          1073: #endif

unix.superglobalmegacorp.com

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