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

unix.superglobalmegacorp.com

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