Annotation of Net2/arch/vax/if/if_dmv.c, revision 1.1.1.1

1.1       root        1: /*
                      2:  * Copyright (c) 1988 Regents of the University of California.
                      3:  * All rights reserved.
                      4:  *
                      5:  * Redistribution and use in source and binary forms, with or without
                      6:  * modification, are permitted provided that the following conditions
                      7:  * are met:
                      8:  * 1. Redistributions of source code must retain the above copyright
                      9:  *    notice, this list of conditions and the following disclaimer.
                     10:  * 2. Redistributions in binary form must reproduce the above copyright
                     11:  *    notice, this list of conditions and the following disclaimer in the
                     12:  *    documentation and/or other materials provided with the distribution.
                     13:  * 3. All advertising materials mentioning features or use of this software
                     14:  *    must display the following acknowledgement:
                     15:  *     This product includes software developed by the University of
                     16:  *     California, Berkeley and its contributors.
                     17:  * 4. Neither the name of the University nor the names of its contributors
                     18:  *    may be used to endorse or promote products derived from this software
                     19:  *    without specific prior written permission.
                     20:  *
                     21:  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
                     22:  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
                     23:  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
                     24:  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
                     25:  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
                     26:  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
                     27:  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
                     28:  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
                     29:  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
                     30:  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
                     31:  * SUCH DAMAGE.
                     32:  *
                     33:  *     @(#)if_dmv.c    7.12 (Berkeley) 12/16/90
                     34:  */
                     35: 
                     36: /*
                     37:  * DMV-11 Driver
                     38:  *
                     39:  * Qbus Sync DDCMP interface - DMV operated in full duplex, point to point mode
                     40:  *
                     41:  * Written by Bob Kridle of Mt Xinu
                     42:  * starting from if_dmc.c version 6.12 dated 4/23/86
                     43:  */
                     44: 
                     45: #include "dmv.h"
                     46: #if NDMV > 0
                     47: 
                     48: #include "sys/param.h"
                     49: #include "sys/systm.h"
                     50: #include "sys/mbuf.h"
                     51: #include "sys/buf.h"
                     52: #include "sys/ioctl.h"         /* must precede tty.h */
                     53: #include "sys/tty.h"
                     54: #include "sys/protosw.h"
                     55: #include "sys/socket.h"
                     56: #include "sys/syslog.h"
                     57: #include "sys/vmmac.h"
                     58: #include "sys/errno.h"
                     59: #include "sys/time.h"
                     60: #include "sys/kernel.h"
                     61: 
                     62: #include "net/if.h"
                     63: #include "net/netisr.h"
                     64: #include "net/route.h"
                     65: 
                     66: #ifdef INET
                     67: #include "netinet/in.h"
                     68: #include "netinet/in_systm.h"
                     69: #include "netinet/in_var.h"
                     70: #include "netinet/ip.h"
                     71: #endif
                     72: 
                     73: #include "../include/cpu.h"
                     74: #include "../include/mtpr.h"
                     75: #include "../include/pte.h"
                     76: #include "../uba/ubareg.h"
                     77: #include "../uba/ubavar.h"
                     78: #include "if_uba.h"
                     79: #include "if_dmv.h"
                     80: 
                     81: int    dmv_timeout = 8;                /* timeout value */
                     82: 
                     83: /*
                     84:  * Driver information for auto-configuration stuff.
                     85:  */
                     86: int    dmvprobe(), dmvattach(), dmvinit(), dmvioctl();
                     87: int    dmvoutput(), dmvreset(), dmvtimeout();
                     88: struct uba_device *dmvinfo[NDMV];
                     89: u_short        dmvstd[] = { 0 };
                     90: struct uba_driver dmvdriver =
                     91:        { dmvprobe, 0, dmvattach, 0, dmvstd, "dmv", dmvinfo };
                     92: 
                     93: /*
                     94:  * Don't really know how many buffers/commands can be queued to a DMV-11.
                     95:  * Manual doesn't say... Perhaps we can look at a DEC driver some day.
                     96:  * These numbers ame from DMC/DMR driver.
                     97:  */
                     98: #define NRCV 5
                     99: #define NXMT 3 
                    100: #define NCMDS  (NRCV+NXMT+4)   /* size of command queue */
                    101: 
                    102: #ifdef DEBUG
                    103: #define printd(f)   if (sc->sc_if.if_flags & IFF_DEBUG) \
                    104:        printf("DMVDEBUG: dmv%d: ", unit), printf(f)
                    105: #else
                    106: #define        printd(f)       /* nil */
                    107: #endif
                    108: 
                    109: /* error reporting intervals */
                    110: 
                    111: #define        DMV_RPRTE        1
                    112: #define        DMV_RPTTE        1
                    113: #define        DMV_RPSTE        1
                    114: #define DMV_RPNXM        1
                    115: #define DMV_RPMODD       1
                    116: #define DMV_RPQOVF      1
                    117: #define DMV_RPCXRL      1
                    118: 
                    119: /* number of errors to accept before trying a reset */
                    120: #define DMV_RPUNKNOWN   10
                    121: 
                    122: struct  dmv_command {
                    123:        u_char  qp_mask;        /* Which registers to set up */
                    124: #define        QP_TRIB         0x01
                    125: #define        QP_SEL4         0x02
                    126: #define        QP_SEL6         0x04
                    127: #define        QP_SEL10        0x08
                    128:        u_char  qp_cmd;
                    129:        u_char  qp_tributary;
                    130:        u_short qp_sel4;
                    131:        u_short qp_sel6;
                    132:        u_short qp_sel10;
                    133:        struct  dmv_command *qp_next;   /* next command on queue */
                    134: };
                    135: 
                    136: #define        qp_lowbufaddr   qp_
                    137: 
                    138: struct dmvbufs {
                    139:        int     ubinfo;         /* from uballoc */
                    140:        short   cc;             /* buffer size */
                    141:        short   flags;          /* access control */
                    142: };
                    143: 
                    144: #define        DBUF_OURS       0       /* buffer is available */
                    145: #define        DBUF_DMVS       1       /* buffer claimed by somebody */
                    146: #define        DBUF_XMIT       4       /* transmit buffer */
                    147: #define        DBUF_RCV        8       /* receive buffer */
                    148: 
                    149: 
                    150: /*
                    151:  * DMV software status per interface.
                    152:  *
                    153:  * Each interface is referenced by a network interface structure,
                    154:  * sc_if, which the routing code uses to locate the interface.
                    155:  * This structure contains the output queue for the interface, its address, ...
                    156:  * We also have, for each interface, a  set of 7 UBA interface structures
                    157:  * for each, which
                    158:  * contain information about the UNIBUS resources held by the interface:
                    159:  * map registers, buffered data paths, etc.  Information is cached in this
                    160:  * structure for use by the if_uba.c routines in running the interface
                    161:  * efficiently.
                    162:  */
                    163: struct dmv_softc {
                    164:        struct  ifnet sc_if;            /* network-visible interface */
                    165:        short   sc_oused;               /* output buffers currently in use */
                    166:        short   sc_iused;               /* input buffers given to DMV */
                    167:        short   sc_flag;                /* flags */
                    168:        short   sc_ipl;                 /* interrupt priority */
                    169:        int     sc_ubinfo;              /* UBA mapping info for base table */
                    170:        int     sc_errors[8];           /* error counters */
                    171: #define        sc_rte  sc_errors[0]            /* receive threshhold error */
                    172: #define        sc_xte  sc_errors[1]            /* xmit threshhold error */
                    173: #define        sc_ste  sc_errors[2]            /* select threshhold error */
                    174: #define        sc_nxm  sc_errors[3]            /* non-existant memory */
                    175: #define        sc_modd sc_errors[4]            /* modem disconnect */
                    176: #define        sc_qovf sc_errors[5]            /* command/response queue overflow */
                    177: #define        sc_cxrl sc_errors[6]            /* carrier loss */
                    178: #define sc_unknown sc_errors[7]                /* other errors - look in DMV manual */
                    179:        struct  dmvbufs sc_rbufs[NRCV]; /* receive buffer info */
                    180:        struct  dmvbufs sc_xbufs[NXMT]; /* transmit buffer info */
                    181:        struct  ifubinfo sc_ifuba;      /* UNIBUS resources */
                    182:        struct  ifrw sc_ifr[NRCV];      /* UNIBUS receive buffer maps */
                    183:        struct  ifxmt sc_ifw[NXMT];     /* UNIBUS receive buffer maps */
                    184:        /* command queue stuff */
                    185:        struct  dmv_command sc_cmdbuf[NCMDS];
                    186:        struct  dmv_command *sc_qhead;  /* head of command queue */
                    187:        struct  dmv_command *sc_qtail;  /* tail of command queue */
                    188:        struct  dmv_command *sc_qactive;        /* command in progress */
                    189:        struct  dmv_command *sc_qfreeh; /* head of list of free cmd buffers */
                    190:        struct  dmv_command *sc_qfreet; /* tail of list of free cmd buffers */
                    191:        /* end command queue stuff */
                    192: } dmv_softc[NDMV];
                    193: 
                    194: /* flags */
                    195: #define DMV_RESTART    0x01            /* software restart in progress */
                    196: #define DMV_ONLINE     0x02            /* device managed to transmit */
                    197: #define DMV_RUNNING    0x04            /* device initialized */
                    198: 
                    199: 
                    200: /* queue manipulation macros */
                    201: #define        QUEUE_AT_HEAD(qp, head, tail) \
                    202:        (qp)->qp_next = (head); \
                    203:        (head) = (qp); \
                    204:        if ((tail) == (struct dmv_command *) 0) \
                    205:                (tail) = (head) 
                    206: 
                    207: #define QUEUE_AT_TAIL(qp, head, tail) \
                    208:        if ((tail)) \
                    209:                (tail)->qp_next = (qp); \
                    210:        else \
                    211:                (head) = (qp); \
                    212:        (qp)->qp_next = (struct dmv_command *) 0; \
                    213:        (tail) = (qp)
                    214: 
                    215: #define DEQUEUE(head, tail) \
                    216:        (head) = (head)->qp_next;\
                    217:        if ((head) == (struct dmv_command *) 0)\
                    218:                (tail) = (head)
                    219: 
                    220: dmvprobe(reg, ui)
                    221:        caddr_t reg;
                    222:        struct uba_device *ui;
                    223: {
                    224:        register int br, cvec;
                    225:        register struct dmvdevice *addr = (struct dmvdevice *)reg;
                    226:        register int i;
                    227: 
                    228: #ifdef lint
                    229:        br = 0; cvec = br; br = cvec;
                    230:        dmvrint(0); dmvxint(0);
                    231: #endif
                    232:        addr->bsel1 = DMV_MCLR;
                    233:        for (i = 100000; i && (addr->bsel1 & DMV_RUN) == 0; i--)
                    234:                ;
                    235:        if ((addr->bsel1 & DMV_RUN) == 0) {
                    236:                printf("dmvprobe: can't start device\n" );
                    237:                return (0);
                    238:        }
                    239:        if ((addr->bsel4 != 033) || (addr->bsel6 != 0305))
                    240:        {
                    241:                printf("dmvprobe: device init failed, bsel4=%o, bsel6=%o\n",
                    242:                        addr->bsel4, addr->bsel6);
                    243:                return (0);
                    244:        }
                    245:        (void) spl6();
                    246:        addr->bsel0 = DMV_RQI|DMV_IEI|DMV_IEO;
                    247:        DELAY(1000000);
                    248:        dmv_softc[ui->ui_unit].sc_ipl = br = qbgetpri();
                    249:        addr->bsel1 = DMV_MCLR;
                    250:        for (i = 100000; i && (addr->bsel1 & DMV_RUN) == 0; i--)
                    251:                ;
                    252:        return (sizeof(struct dmvdevice));
                    253: }
                    254: 
                    255: /*
                    256:  * Interface exists: make available by filling in network interface
                    257:  * record.  System will initialize the interface when it is ready
                    258:  * to accept packets.
                    259:  */
                    260: dmvattach(ui)
                    261:        register struct uba_device *ui;
                    262: {
                    263:        register struct dmv_softc *sc = &dmv_softc[ui->ui_unit];
                    264: 
                    265:        sc->sc_if.if_unit = ui->ui_unit;
                    266:        sc->sc_if.if_name = "dmv";
                    267:        sc->sc_if.if_mtu = DMVMTU;
                    268:        sc->sc_if.if_init = dmvinit;
                    269:        sc->sc_if.if_output = dmvoutput;
                    270:        sc->sc_if.if_ioctl = dmvioctl;
                    271:        sc->sc_if.if_reset = dmvreset;
                    272:        sc->sc_if.if_watchdog = dmvtimeout;
                    273:        sc->sc_if.if_flags = IFF_POINTOPOINT;
                    274:        sc->sc_ifuba.iff_flags = UBA_CANTWAIT;
                    275: 
                    276:        if_attach(&sc->sc_if);
                    277: }
                    278: 
                    279: /*
                    280:  * Reset of interface after UNIBUS reset.
                    281:  * If interface is on specified UBA, reset its state.
                    282:  */
                    283: dmvreset(unit, uban)
                    284:        int unit, uban;
                    285: {
                    286:        register struct uba_device *ui;
                    287:        register struct dmv_softc *sc = &dmv_softc[unit];
                    288: 
                    289:        if (unit >= NDMV || (ui = dmvinfo[unit]) == 0 || ui->ui_alive == 0 ||
                    290:            ui->ui_ubanum != uban)
                    291:                return;
                    292:        printf(" dmv%d", unit);
                    293:        sc->sc_flag = 0;
                    294:        sc->sc_if.if_flags &= ~IFF_RUNNING;
                    295:        dmvinit(unit);
                    296: }
                    297: 
                    298: /*
                    299:  * Initialization of interface; reinitialize UNIBUS usage.
                    300:  */
                    301: dmvinit(unit)
                    302:        int unit;
                    303: {
                    304:        register struct dmv_softc *sc = &dmv_softc[unit];
                    305:        register struct uba_device *ui = dmvinfo[unit];
                    306:        register struct dmvdevice *addr;
                    307:        register struct ifnet *ifp = &sc->sc_if;
                    308:        register struct ifrw *ifrw;
                    309:        register struct ifxmt *ifxp;
                    310:        register struct dmvbufs *rp;
                    311:        register struct dmv_command *qp;
                    312:        struct ifaddr *ifa;
                    313:        int base;
                    314:        int s;
                    315: 
                    316:        addr = (struct dmvdevice *)ui->ui_addr;
                    317: 
                    318:        /*
                    319:         * Check to see that an address has been set
                    320:         * (both local and destination for an address family).
                    321:         */
                    322:        for (ifa = ifp->if_addrlist; ifa; ifa = ifa->ifa_next)
                    323:                if (ifa->ifa_addr->sa_family &&
                    324:                    ifa->ifa_addr->sa_family != AF_LINK &&
                    325:                    ifa->ifa_dstaddr && ifa->ifa_dstaddr->sa_family)
                    326:                        break;
                    327:        if (ifa == (struct ifaddr *) 0)
                    328:                return;
                    329: 
                    330:        if ((addr->bsel1&DMV_RUN) == 0) {
                    331:                log(LOG_CRIT, "dmvinit: dmv%d not running\n", unit);
                    332:                ifp->if_flags &= ~IFF_UP;
                    333:                return;
                    334:        }
                    335:        printd(("dmvinit\n"));
                    336:        /* initialize UNIBUS resources */
                    337:        sc->sc_iused = sc->sc_oused = 0;
                    338:        if ((ifp->if_flags & IFF_RUNNING) == 0) {
                    339:                if (if_ubaminit(
                    340:                        &sc->sc_ifuba,
                    341:                        ui->ui_ubanum,
                    342:                        sizeof(struct dmv_header),
                    343:                        (int)btoc(DMVMTU),
                    344:                        sc->sc_ifr,
                    345:                        NRCV,
                    346:                        sc->sc_ifw,
                    347:                        NXMT
                    348:                ) == 0) {
                    349:                        log(LOG_CRIT, "dmvinit: dmv%d can't allocate uba resources\n", unit);
                    350:                        ifp->if_flags &= ~IFF_UP;
                    351:                        return;
                    352:                }
                    353:                ifp->if_flags |= IFF_RUNNING;
                    354:        }
                    355:        /*
                    356:         * Limit packets enqueued until we see if we're on the air.
                    357:         */
                    358:        ifp->if_snd.ifq_maxlen = 3;
                    359: 
                    360: 
                    361:        /* initialize buffer pool */
                    362:        /* receives */
                    363:        ifrw = &sc->sc_ifr[0];
                    364:        for (rp = &sc->sc_rbufs[0]; rp < &sc->sc_rbufs[NRCV]; rp++) {
                    365:                rp->ubinfo = UBAI_ADDR(ifrw->ifrw_info);
                    366:                rp->cc = DMVMTU + sizeof (struct dmv_header);
                    367:                rp->flags = DBUF_OURS|DBUF_RCV;
                    368:                ifrw++; 
                    369:        }
                    370:        /* transmits */
                    371:        ifxp = &sc->sc_ifw[0];
                    372:        for (rp = &sc->sc_xbufs[0]; rp < &sc->sc_xbufs[NXMT]; rp++) {
                    373:                rp->ubinfo = UBAI_ADDR(ifxp->ifw_info);
                    374:                rp->cc = 0;
                    375:                rp->flags = DBUF_OURS|DBUF_XMIT;
                    376:                ifxp++; 
                    377:        }
                    378: 
                    379:        /* set up command queues */
                    380:        sc->sc_qfreeh = sc->sc_qfreet
                    381:                 = sc->sc_qhead = sc->sc_qtail = sc->sc_qactive =
                    382:                (struct dmv_command *)0;
                    383:        /* set up free command buffer list */
                    384:        for (qp = &sc->sc_cmdbuf[0]; qp < &sc->sc_cmdbuf[NCMDS]; qp++) {
                    385:                QUEUE_AT_HEAD(qp, sc->sc_qfreeh, sc->sc_qfreet);
                    386:        }
                    387:        if(sc->sc_flag & DMV_RUNNING)
                    388:                dmvload( sc, DMV_CNTRLI, (QP_TRIB|QP_SEL6), 1, 0, DMV_REQHS,0);
                    389:        else
                    390:                dmvload( sc, DMV_CNTRLI, (QP_TRIB|QP_SEL6), 1, 0, DMV_ESTTRIB,0);
                    391:        dmvload( sc, DMV_CNTRLI, (QP_TRIB|QP_SEL6), 1, 0, DMV_REQSUS,0);
                    392:        sc->sc_flag |= (DMV_RESTART|DMV_RUNNING);
                    393:        sc->sc_flag &= ~DMV_ONLINE;
                    394:        addr->bsel0 |= DMV_IEO;
                    395: }
                    396: 
                    397: /*
                    398:  * Start output on interface.  Get another datagram
                    399:  * to send from the interface queue and map it to
                    400:  * the interface before starting output.
                    401:  *
                    402:  * Must be called at spl 5
                    403:  */
                    404: dmvstart(dev)
                    405:        dev_t dev;
                    406: {
                    407:        int unit = minor(dev);
                    408:        register struct dmv_softc *sc = &dmv_softc[unit];
                    409:        struct mbuf *m;
                    410:        register struct dmvbufs *rp;
                    411:        register int n;
                    412: 
                    413:        /*
                    414:         * Dequeue up to NXMT requests and map them to the UNIBUS.
                    415:         * If no more requests, or no dmv buffers available, just return.
                    416:         */
                    417:        printd(("dmvstart\n"));
                    418:        n = 0;
                    419:        for (rp = &sc->sc_xbufs[0]; rp < &sc->sc_xbufs[NXMT]; rp++ ) {
                    420:                /* find an available buffer */
                    421:                if ((rp->flags & DBUF_DMVS) == 0) {
                    422:                        IF_DEQUEUE(&sc->sc_if.if_snd, m);
                    423:                        if (m == 0)
                    424:                                return;
                    425:                        /* mark it dmvs */
                    426:                        rp->flags |= (DBUF_DMVS);
                    427:                        /*
                    428:                         * Have request mapped to UNIBUS for transmission
                    429:                         * and start the output.
                    430:                         */
                    431:                        rp->cc = if_ubaput(&sc->sc_ifuba, &sc->sc_ifw[n], m);
                    432:                        if (++sc->sc_oused == 1)
                    433:                                sc->sc_if.if_timer = dmv_timeout;
                    434:                        dmvload(
                    435:                                sc,
                    436:                                DMV_BACCX,
                    437:                                QP_TRIB|QP_SEL4|QP_SEL6|QP_SEL10,
                    438:                                1,
                    439:                                rp->ubinfo,
                    440:                                (rp->ubinfo>>16)&0x3f,
                    441:                                rp->cc
                    442:                        );
                    443:                }
                    444:                n++;
                    445:        }
                    446: }
                    447: 
                    448: /*
                    449:  * Utility routine to load the DMV device registers.
                    450:  */
                    451: dmvload(sc, cmd, mask, tributary, sel4, sel6, sel10)
                    452:        register struct dmv_softc *sc;
                    453:        u_char cmd, tributary, mask;
                    454:        u_short sel4, sel6, sel10;
                    455: {
                    456:        register struct dmvdevice *addr;
                    457:        register int unit, sps;
                    458:        register struct dmv_command *qp;
                    459: 
                    460:        unit = sc - dmv_softc;
                    461:        printd(("dmvload: cmd=%x mask=%x trib=%x sel4=%x sel6=%x sel10=%x\n",
                    462:                (unsigned) cmd,
                    463:                (unsigned) mask,
                    464:                (unsigned) tributary,
                    465:                (unsigned) sel4,
                    466:                (unsigned) sel6,
                    467:                (unsigned) sel10
                    468:        ));
                    469:        addr = (struct dmvdevice *)dmvinfo[unit]->ui_addr;
                    470:        sps = spl5();
                    471: 
                    472:        /* grab a command buffer from the free list */
                    473:        if ((qp = sc->sc_qfreeh) == (struct dmv_command *)0)
                    474:                panic("dmv command queue overflow");
                    475:        DEQUEUE(sc->sc_qfreeh, sc->sc_qfreet);
                    476: 
                    477:        /* fill in requested info */
                    478:        qp->qp_cmd = cmd;
                    479:        qp->qp_mask = mask;
                    480:        qp->qp_tributary = tributary;
                    481:        qp->qp_sel4 = sel4;
                    482:        qp->qp_sel6 = sel6;
                    483:        qp->qp_sel10 = sel10;
                    484:        
                    485:        if (sc->sc_qactive) {   /* command in progress */
                    486:                if (cmd == DMV_BACCR) {  /* supply read buffers first */
                    487:                        QUEUE_AT_HEAD(qp, sc->sc_qhead, sc->sc_qtail);
                    488:                } else {
                    489:                        QUEUE_AT_TAIL(qp, sc->sc_qhead, sc->sc_qtail);
                    490:                }
                    491:        } else {        /* command port free */
                    492:                sc->sc_qactive = qp;
                    493:                addr->bsel0 = (DMV_RQI|DMV_IEI|DMV_IEO);
                    494:        }
                    495:        splx(sps);
                    496: }
                    497: /*
                    498:  * DMV interface input interrupt.
                    499:  * Ready to accept another command,
                    500:  * pull one off the command queue.
                    501:  */
                    502: dmvrint(unit)
                    503:        int unit;
                    504: {
                    505:        register struct dmv_softc *sc;
                    506:        register struct dmvdevice *addr;
                    507:        register struct dmv_command *qp;
                    508:        register int n;
                    509: 
                    510:        addr = (struct dmvdevice *)dmvinfo[unit]->ui_addr;
                    511:        sc = &dmv_softc[unit];
                    512:        splx(sc->sc_ipl);
                    513:        printd(("dmvrint\n"));
                    514:        if ((qp = sc->sc_qactive) == (struct dmv_command *) 0) {
                    515:                log(LOG_WARNING, "dmvrint: dmv%d no command\n", unit);
                    516:                return;
                    517:        }
                    518:        while (addr->bsel2&DMV_RDI) {
                    519:                if(qp->qp_mask&QP_SEL4)
                    520:                        addr->wsel4 = qp->qp_sel4;
                    521:                if(qp->qp_mask&QP_SEL6)
                    522:                        addr->wsel6 = qp->qp_sel6;
                    523:                if(qp->qp_mask&QP_SEL10) {
                    524:                        addr->wsel10 = qp->qp_sel10;
                    525:                        qp->qp_cmd |= DMV_22BIT;
                    526:                }
                    527:                if(qp->qp_mask&QP_TRIB)
                    528:                        addr->wsel2 = qp->qp_cmd|(qp->qp_tributary << 8);
                    529:                else
                    530:                        addr->bsel2 = qp->qp_cmd;
                    531:                QUEUE_AT_HEAD(qp, sc->sc_qfreeh, sc->sc_qfreet);
                    532:                if ((sc->sc_qactive = sc->sc_qhead) == (struct dmv_command *)0)
                    533:                        break;
                    534:                qp = sc->sc_qactive;
                    535:                DEQUEUE(sc->sc_qhead, sc->sc_qtail);
                    536:                if (addr->bsel2&DMV_RDO)
                    537:                                break;
                    538:        }
                    539:        if (!sc->sc_qactive) {
                    540:                if(addr->bsel2&DMV_RDI) {
                    541:                        /* clear RQI prior to last command per DMV manual */
                    542:                        addr->bsel0 &= ~DMV_RQI;
                    543:                        addr->wsel6 = DMV_NOP;
                    544:                        addr->bsel2 = DMV_CNTRLI;
                    545:                }
                    546:                addr->bsel0 = DMV_IEO;
                    547:        }
                    548:        else /* RDO set or DMV still holding CSR */
                    549:                addr->bsel0 = (DMV_RQI|DMV_IEI|DMV_IEO);
                    550: 
                    551: }
                    552: 
                    553: /*
                    554:  * DMV interface output interrupt.
                    555:  * A transfer may have completed, check for errors.
                    556:  * If it was a read, notify appropriate protocol.
                    557:  * If it was a write, pull the next one off the queue.
                    558:  */
                    559: dmvxint(unit)
                    560:        int unit;
                    561: {
                    562:        register struct dmv_softc *sc;
                    563:        register struct ifnet *ifp;
                    564:        struct uba_device *ui = dmvinfo[unit];
                    565:        struct dmvdevice *addr;
                    566:        struct mbuf *m;
                    567:        struct ifqueue *inq;
                    568:        int sel2, sel3, sel4, sel6, sel10, pkaddr, len, s;
                    569:        register struct ifrw *ifrw;
                    570:        register struct dmvbufs *rp;
                    571:        register struct ifxmt *ifxp;
                    572:        struct dmv_header *dh;
                    573:        int off, resid;
                    574: 
                    575:        addr = (struct dmvdevice *)ui->ui_addr;
                    576:        sc = &dmv_softc[unit];
                    577:        splx(sc->sc_ipl);
                    578:        ifp = &sc->sc_if;
                    579: 
                    580:        while (addr->bsel2 & DMV_RDO) {
                    581: 
                    582:                sel2 = addr->bsel2;
                    583:                sel3 = addr->bsel3;
                    584:                sel4 = addr->wsel4;             /* release port */
                    585:                sel6 = addr->wsel6;
                    586:                if(sel2 & DMV_22BIT)
                    587:                        sel10 = addr->wsel10;
                    588:                addr->bsel2 &= ~DMV_RDO;
                    589:                pkaddr =  sel4 | ((sel6 & 0x3f) << 16);
                    590:                printd(("dmvxint: sel2=%x sel4=%x sel6=%x sel10=%x pkaddr=%x\n",
                    591:                        (unsigned) sel2,
                    592:                        (unsigned) sel4,
                    593:                        (unsigned) sel6,
                    594:                        (unsigned) sel10,
                    595:                        (unsigned) pkaddr
                    596:                ));
                    597:                if((sc->sc_flag & DMV_RUNNING)==0) {
                    598:                                log(LOG_WARNING, "dmvxint: dmv%d xint while down\n", unit);
                    599:                                return;
                    600:                }
                    601:                switch (sel2 & 07) {
                    602:                case DMV_BDRUS:
                    603:                        /*
                    604:                         * A read has completed.  
                    605:                         * Pass packet to type specific
                    606:                         * higher-level input routine.
                    607:                         */
                    608:                        ifp->if_ipackets++;
                    609:                        /* find location in dmvuba struct */
                    610:                        ifrw= &sc->sc_ifr[0];
                    611:                        for (rp = &sc->sc_rbufs[0]; rp < &sc->sc_rbufs[NRCV]; rp++) {
                    612:                                if(rp->ubinfo == pkaddr)
                    613:                                        break;
                    614:                                ifrw++;
                    615:                        }
                    616:                        if (rp >= &sc->sc_rbufs[NRCV])
                    617:                                panic("dmv rcv");
                    618:                        if ((rp->flags & DBUF_DMVS) == 0)
                    619:                                log(LOG_WARNING, "dmvxint: dmv%d done unalloc rbuf\n", unit);
                    620: 
                    621:                        len = (sel10&0x3fff) - sizeof (struct dmv_header);
                    622:                        if (len < 0 || len > DMVMTU) {
                    623:                                ifp->if_ierrors++;
                    624:                                log(LOG_ERR, "dmvxint: dmv%d bad rcv pkt addr 0x%x len 0x%x\n",
                    625:                                    unit, pkaddr, len);
                    626:                                goto setup;
                    627:                        }
                    628:                        /*
                    629:                         * Deal with trailer protocol: if type is trailer
                    630:                         * get true type from first 16-bit word past data.
                    631:                         * Remember that type was trailer by setting off.
                    632:                         */
                    633:                        dh = (struct dmv_header *)ifrw->ifrw_addr;
                    634:                        dh->dmv_type = ntohs((u_short)dh->dmv_type);
                    635: #define dmvdataaddr(dh, off, type)     ((type)(((caddr_t)((dh)+1)+(off))))
                    636:                        if (dh->dmv_type >= DMV_TRAILER &&
                    637:                            dh->dmv_type < DMV_TRAILER+DMV_NTRAILER) {
                    638:                                off = (dh->dmv_type - DMV_TRAILER) * 512;
                    639:                                if (off >= DMVMTU)
                    640:                                        goto setup;             /* sanity */
                    641:                                dh->dmv_type = ntohs(*dmvdataaddr(dh, off, u_short *));
                    642:                                resid = ntohs(*(dmvdataaddr(dh, off+2, u_short *)));
                    643:                                if (off + resid > len)
                    644:                                        goto setup;             /* sanity */
                    645:                                len = off + resid;
                    646:                        } else
                    647:                                off = 0;
                    648:                        if (len == 0)
                    649:                                goto setup;
                    650: 
                    651:                        /*
                    652:                         * Pull packet off interface.  Off is nonzero if
                    653:                         * packet has trailing header; dmv_get will then
                    654:                         * force this header information to be at the front,
                    655:                         * but we still have to drop the type and length
                    656:                         * which are at the front of any trailer data.
                    657:                         */
                    658:                        m = if_ubaget(&sc->sc_ifuba, ifrw, len, off, ifp);
                    659:                        if (m == 0)
                    660:                                goto setup;
                    661:                        switch (dh->dmv_type) {
                    662: #ifdef INET
                    663:                        case DMV_IPTYPE:
                    664:                                schednetisr(NETISR_IP);
                    665:                                inq = &ipintrq;
                    666:                                break;
                    667: #endif
                    668:                        default:
                    669:                                m_freem(m);
                    670:                                goto setup;
                    671:                        }
                    672: 
                    673:                        s = splimp();
                    674:                        if (IF_QFULL(inq)) {
                    675:                                IF_DROP(inq);
                    676:                                m_freem(m);
                    677:                        } else
                    678:                                IF_ENQUEUE(inq, m);
                    679:                        splx(s);
                    680:        setup:
                    681:                        /* is this needed? */
                    682:                        rp->ubinfo = UBAI_ADDR(ifrw->ifrw_info);
                    683:                        dmvload(
                    684:                                sc,
                    685:                                DMV_BACCR,
                    686:                                QP_SEL4|QP_SEL6|QP_SEL10,
                    687:                                0,
                    688:                                (u_short) rp->ubinfo,
                    689:                                (rp->ubinfo>>16)&0x3f,
                    690:                                rp->cc
                    691:                        );
                    692:                        break;
                    693:                case DMV_BDXSA:
                    694:                        /*
                    695:                         * A write has completed, start another
                    696:                         * transfer if there is more data to send.
                    697:                         */
                    698:                        ifp->if_opackets++;
                    699:                        /* find associated dmvbuf structure */
                    700:                        ifxp = &sc->sc_ifw[0];
                    701:                        for (rp = &sc->sc_xbufs[0]; rp < &sc->sc_xbufs[NXMT]; rp++) {
                    702:                                if(rp->ubinfo == pkaddr)
                    703:                                        break;
                    704:                                ifxp++;
                    705:                        }
                    706:                        if (rp >= &sc->sc_xbufs[NXMT]) {
                    707:                                log(LOG_ERR, "dmv%d: bad packet address 0x%x\n",
                    708:                                    unit, pkaddr);
                    709:                                break;
                    710:                        }
                    711:                        if ((rp->flags & DBUF_DMVS) == 0)
                    712:                                log(LOG_ERR, "dmvxint: dmv%d unallocated packet 0x%x\n",
                    713:                                    unit, pkaddr);
                    714:                        /* mark buffer free */
                    715:                        if (ifxp->ifw_xtofree) {
                    716:                                (void)m_freem(ifxp->ifw_xtofree);
                    717:                                ifxp->ifw_xtofree = 0;
                    718:                        }
                    719:                        rp->flags &= ~DBUF_DMVS;
                    720:                        if (--sc->sc_oused == 0)
                    721:                                sc->sc_if.if_timer = 0;
                    722:                        else
                    723:                                sc->sc_if.if_timer = dmv_timeout;
                    724:                        if ((sc->sc_flag & DMV_ONLINE) == 0) {
                    725:                                extern int ifqmaxlen;
                    726: 
                    727:                                /*
                    728:                                 * We're on the air.
                    729:                                 * Open the queue to the usual value.
                    730:                                 */
                    731:                                sc->sc_flag |= DMV_ONLINE;
                    732:                                ifp->if_snd.ifq_maxlen = ifqmaxlen;
                    733:                        }
                    734:                        break;
                    735: 
                    736:                case DMV_CNTRLO:
                    737:                        /* ACCUMULATE STATISTICS */
                    738:                        switch(sel6&DMV_EEC) {
                    739:                        case DMV_ORUN:
                    740:                                if(sc->sc_flag & DMV_RESTART) {
                    741:                                        load_rec_bufs(sc);
                    742:                                        sc->sc_flag &= ~DMV_RESTART;
                    743:                                        log(LOG_INFO,
                    744:                                            "dmv%d: far end on-line\n", unit);
                    745:                                } else {
                    746:                                        log(LOG_WARNING,
                    747:                                            "dmv%d: far end restart\n", unit);
                    748:                                        goto restart;
                    749:                                }
                    750:                                break;
                    751:                        case DMV_RTE:
                    752:                                ifp->if_ierrors++;
                    753:                                if ((sc->sc_rte++ % DMV_RPRTE) == 0)
                    754:                                        log(LOG_WARNING,
                    755:                                    "dmv%d: receive threshold error\n",
                    756:                                            unit);
                    757:                                break;
                    758:                        case DMV_TTE:
                    759:                                ifp->if_oerrors++;
                    760:                                if ((sc->sc_xte++ % DMV_RPTTE) == 0)
                    761:                                        log(LOG_WARNING,
                    762:                                    "dmv%d: transmit threshold error\n",
                    763:                                            unit);
                    764:                                break;
                    765:                        case DMV_STE:
                    766:                                if ((sc->sc_ste++ % DMV_RPSTE) == 0)
                    767:                                        log(LOG_WARNING,
                    768:                                    "dmv%d: select threshold error\n",
                    769:                                            unit);
                    770:                                break;
                    771:                        case DMV_NXM:
                    772:                                if ((sc->sc_nxm++ % DMV_RPNXM) == 0)
                    773:                                        log(LOG_WARNING,
                    774:                                    "dmv%d: nonexistent memory error\n",
                    775:                                            unit);
                    776:                                break;
                    777:                        case DMV_MODD:
                    778:                                if ((sc->sc_modd++ % DMV_RPMODD) == 0) {
                    779:                                        log(LOG_WARNING,
                    780:                                    "dmv%d: modem disconnected error\n",
                    781:                                            unit);
                    782:                                        goto restart;
                    783:                                }
                    784:                                break;
                    785:                        case DMV_CXRL:
                    786:                                if ((sc->sc_cxrl++ % DMV_RPCXRL) == 0)
                    787:                                        log(LOG_WARNING,
                    788:                                    "dmv%d: carrier loss error\n",
                    789:                                            unit);
                    790:                                break;
                    791:                        case DMV_QOVF:
                    792:                                log(LOG_WARNING,
                    793:                                    "dmv%d: response queue overflow\n",
                    794:                                    unit);
                    795:                                sc->sc_qovf++;
                    796:                                goto restart;
                    797: 
                    798:                        default:
                    799:                                log(LOG_WARNING,
                    800:                                    "dmv%d: unknown error %o\n",
                    801:                                    unit, sel6&DMV_EEC);
                    802:                                if ((sc->sc_unknown++ % DMV_RPUNKNOWN) == 0)
                    803:                                        goto restart;
                    804:                                break;
                    805:                        }
                    806:                        break;
                    807: 
                    808:                case DMV_BDRUNUS:
                    809:                case DMV_BDXSN:
                    810:                case DMV_BDXNS:
                    811:                        log(LOG_INFO,
                    812:                           "dmv%d: buffer disp for halted trib %o\n",
                    813:                           unit, sel2&0x7
                    814:                        );
                    815:                        break;
                    816: 
                    817:                case DMV_MDEFO:
                    818:                        if((sel6&0x1f) == 020) {
                    819:                                log(LOG_INFO,
                    820:                                        "dmv%d: buffer return complete sel3=%x\n",
                    821:                                        unit, sel3);
                    822:                        } else {
                    823:                                log(LOG_INFO,
                    824:                                "dmv%d: info resp sel3=%x sel4=%x sel6=%x\n",
                    825:                                unit, sel3, sel4, sel6
                    826:                                );
                    827:                        }
                    828:                        break;
                    829:                        
                    830:                default:
                    831:                        log(LOG_WARNING, "dmv%d: bad control %o\n",
                    832:                           unit, sel2&0x7
                    833:                        );
                    834:                        break;
                    835:                }
                    836:        }
                    837:        dmvstart(unit);
                    838:        return;
                    839: restart:
                    840:        dmvrestart(unit);
                    841: }
                    842: 
                    843: load_rec_bufs(sc)
                    844: register struct dmv_softc *sc;
                    845: {
                    846:        register struct dmvbufs *rp;
                    847: 
                    848:        /* queue first NRCV buffers for DMV to fill */
                    849:        for (rp = &sc->sc_rbufs[0]; rp < &sc->sc_rbufs[NRCV]; rp++) {
                    850:                rp->flags |= DBUF_DMVS;
                    851:                dmvload(
                    852:                        sc,
                    853:                        DMV_BACCR,
                    854:                        QP_TRIB|QP_SEL4|QP_SEL6|QP_SEL10,
                    855:                        1,
                    856:                        rp->ubinfo,
                    857:                        (rp->ubinfo>>16)&0x3f,
                    858:                        rp->cc
                    859:                );
                    860:                sc->sc_iused++;
                    861:        }
                    862: }
                    863: 
                    864: /*
                    865:  * DMV output routine.
                    866:  * Encapsulate a packet of type family for the dmv.
                    867:  * Use trailer local net encapsulation if enough data in first
                    868:  * packet leaves a multiple of 512 bytes of data in remainder.
                    869:  */
                    870: dmvoutput(ifp, m0, dst)
                    871:        register struct ifnet *ifp;
                    872:        register struct mbuf *m0;
                    873:        struct sockaddr *dst;
                    874: {
                    875:        int type, error, s;
                    876:        register struct mbuf *m = m0;
                    877:        register struct dmv_header *dh;
                    878:        register int off;
                    879: 
                    880:        if ((ifp->if_flags & IFF_UP) == 0) {
                    881:                error = ENETDOWN;
                    882:                goto bad;
                    883:        }
                    884: 
                    885:        switch (dst->sa_family) {
                    886: #ifdef INET
                    887:        case AF_INET:
                    888:                off = m->m_pkthdr.len - m->m_len;
                    889:                if ((ifp->if_flags & IFF_NOTRAILERS) == 0)
                    890:                if (off > 0 && (off & 0x1ff) == 0 &&
                    891:                    (m->m_flags & M_EXT) == 0 &&
                    892:                    m->m_data >= m->m_pktdat + 2 * sizeof (u_short)) {
                    893:                        type = DMV_TRAILER + (off>>9);
                    894:                        m->m_data -= 2 * sizeof (u_short);
                    895:                        m->m_len += 2 * sizeof (u_short);
                    896:                        *mtod(m, u_short *) = htons((u_short)DMV_IPTYPE);
                    897:                        *(mtod(m, u_short *) + 1) = htons((u_short)m->m_len);
                    898:                        goto gottrailertype;
                    899:                }
                    900:                type = DMV_IPTYPE;
                    901:                off = 0;
                    902:                goto gottype;
                    903: #endif
                    904: 
                    905:        case AF_UNSPEC:
                    906:                dh = (struct dmv_header *)dst->sa_data;
                    907:                type = dh->dmv_type;
                    908:                goto gottype;
                    909: 
                    910:        default:
                    911:                log(LOG_ERR, "dmvoutput, dmv%d can't handle af%d\n",
                    912:                    ifp->if_unit, dst->sa_family);
                    913:                error = EAFNOSUPPORT;
                    914:                goto bad;
                    915:        }
                    916: 
                    917: gottrailertype:
                    918:        /*
                    919:         * Packet to be sent as a trailer; move first packet
                    920:         * (control information) to end of chain.
                    921:         */
                    922:        while (m->m_next)
                    923:                m = m->m_next;
                    924:        m->m_next = m0;
                    925:        m = m0->m_next;
                    926:        m0->m_next = 0;
                    927:        m0 = m;
                    928: 
                    929: gottype:
                    930:        /*
                    931:         * Add local network header
                    932:         * (there is space for a uba on a vax to step on)
                    933:         */
                    934:        M_PREPEND(m, sizeof(struct dmv_header), M_DONTWAIT);
                    935:        if (m == 0) {
                    936:                error = ENOBUFS;
                    937:                goto bad;
                    938:        }
                    939:        dh = mtod(m, struct dmv_header *);
                    940:        dh->dmv_type = htons((u_short)type);
                    941: 
                    942:        /*
                    943:         * Queue message on interface, and start output if interface
                    944:         * not yet active.
                    945:         */
                    946:        s = splimp();
                    947:        if (IF_QFULL(&ifp->if_snd)) {
                    948:                IF_DROP(&ifp->if_snd);
                    949:                m_freem(m);
                    950:                splx(s);
                    951:                return (ENOBUFS);
                    952:        }
                    953:        IF_ENQUEUE(&ifp->if_snd, m);
                    954:        dmvstart(ifp->if_unit);
                    955:        splx(s);
                    956:        return (0);
                    957: 
                    958: bad:
                    959:        m_freem(m0);
                    960:        return (error);
                    961: }
                    962: 
                    963: 
                    964: /*
                    965:  * Process an ioctl request.
                    966:  */
                    967: /* ARGSUSED */
                    968: dmvioctl(ifp, cmd, data)
                    969:        register struct ifnet *ifp;
                    970:        int cmd;
                    971:        caddr_t data;
                    972: {
                    973:        int s = splimp(), error = 0;
                    974:        struct mbuf *m;
                    975:        register struct dmv_softc *sc = &dmv_softc[ifp->if_unit];
                    976: 
                    977:        switch (cmd) {
                    978: 
                    979:        case SIOCSIFADDR:
                    980:                ifp->if_flags |= IFF_UP;
                    981:                if ((ifp->if_flags & IFF_RUNNING) == 0)
                    982:                        dmvinit(ifp->if_unit); 
                    983:                break;
                    984: 
                    985:        case SIOCSIFDSTADDR:
                    986:                if ((ifp->if_flags & IFF_RUNNING) == 0)
                    987:                        dmvinit(ifp->if_unit); 
                    988:                break;
                    989:                
                    990:        case SIOCSIFFLAGS:
                    991:                if ((ifp->if_flags & IFF_UP) == 0 &&
                    992:                    sc->sc_flag & DMV_RUNNING)
                    993:                        dmvdown(ifp->if_unit);
                    994:                else if (ifp->if_flags & IFF_UP &&
                    995:                    (sc->sc_flag & DMV_RUNNING) == 0)
                    996:                        dmvrestart(ifp->if_unit);
                    997:                break;
                    998: 
                    999:        default:
                   1000:                error = EINVAL;
                   1001:        }
                   1002:        splx(s);
                   1003:        return (error);
                   1004: }
                   1005: 
                   1006: /*
                   1007:  * Restart after a fatal error.
                   1008:  * Clear device and reinitialize.
                   1009:  */
                   1010: dmvrestart(unit)
                   1011:        int unit;
                   1012: {
                   1013:        register struct dmvdevice *addr;
                   1014:        register int i;
                   1015: 
                   1016:        dmvdown(unit);
                   1017: 
                   1018:        addr = (struct dmvdevice *)(dmvinfo[unit]->ui_addr);
                   1019:        /*
                   1020:         * Let the DMV finish the MCLR.
                   1021:         */
                   1022:        for (i = 100000; i && (addr->bsel1 & DMV_RUN) == 0; i--)
                   1023:                ;
                   1024:        if ((addr->bsel1 & DMV_RUN) == 0) {
                   1025:                log(LOG_ERR, "dmvrestart: can't start device\n" );
                   1026:                return (0);
                   1027:        }
                   1028:        if ((addr->bsel4 != 033) || (addr->bsel6 != 0305))
                   1029:        {
                   1030:                log(LOG_ERR, "dmv%d: device init failed, bsel4=%o, bsel6=%o\n",
                   1031:                        unit, addr->bsel4, addr->bsel6);
                   1032:                return (0);
                   1033:        }
                   1034: 
                   1035:        /* restart DMV */
                   1036:        dmvinit(unit);
                   1037:        dmv_softc[unit].sc_if.if_collisions++;  /* why not? */
                   1038: }
                   1039:        
                   1040: /*
                   1041:  * Reset a device and mark down.
                   1042:  * Flush output queue and drop queue limit.
                   1043:  */
                   1044: dmvdown(unit)
                   1045:        int unit;
                   1046: {
                   1047:        struct dmv_softc *sc = &dmv_softc[unit];
                   1048:        register struct ifxmt *ifxp;
                   1049: 
                   1050:        ((struct dmvdevice *)(dmvinfo[unit]->ui_addr))->bsel1 = DMV_MCLR;
                   1051:        sc->sc_flag &= ~(DMV_RUNNING | DMV_ONLINE);
                   1052: 
                   1053:        for (ifxp = sc->sc_ifw; ifxp < &sc->sc_ifw[NXMT]; ifxp++) {
                   1054:                if (ifxp->ifw_xtofree) {
                   1055:                        (void) m_freem(ifxp->ifw_xtofree);
                   1056:                        ifxp->ifw_xtofree = 0;
                   1057:                }
                   1058:        }
                   1059:        sc->sc_oused = 0;
                   1060:        if_qflush(&sc->sc_if.if_snd);
                   1061: 
                   1062:        /*
                   1063:         * Limit packets enqueued until we're back on the air.
                   1064:         */
                   1065:        sc->sc_if.if_snd.ifq_maxlen = 3;
                   1066: }
                   1067: 
                   1068: /*
                   1069:  * Watchdog timeout to see that transmitted packets don't
                   1070:  * lose interrupts.  The device has to be online.
                   1071:  */
                   1072: dmvtimeout(unit)
                   1073:        int unit;
                   1074: {
                   1075:        register struct dmv_softc *sc;
                   1076:        struct dmvdevice *addr;
                   1077: 
                   1078:        sc = &dmv_softc[unit];
                   1079:        if (sc->sc_flag & DMV_ONLINE) {
                   1080:                addr = (struct dmvdevice *)(dmvinfo[unit]->ui_addr);
                   1081:                log(LOG_ERR, "dmv%d: output timeout, bsel0=%b bsel2=%b\n",
                   1082:                    unit, addr->bsel0 & 0xff, DMV0BITS,
                   1083:                    addr->bsel2 & 0xff, DMV2BITS);
                   1084:                dmvrestart(unit);
                   1085:        }
                   1086: }
                   1087: #endif

unix.superglobalmegacorp.com

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