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

unix.superglobalmegacorp.com

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