Annotation of 43BSDTahoe/sys/vaxif/if_dmc.c, revision 1.1.1.1

1.1       root        1: /*
                      2:  * Copyright (c) 1982, 1986 Regents of the University of California.
                      3:  * All rights reserved.  The Berkeley software License Agreement
                      4:  * specifies the terms and conditions for redistribution.
                      5:  *
                      6:  *     @(#)if_dmc.c    7.2 (Berkeley) 5/27/88
                      7:  */
                      8: 
                      9: #include "dmc.h"
                     10: #if NDMC > 0
                     11: 
                     12: /*
                     13:  * DMC11 device driver, internet version
                     14:  *
                     15:  *     Bill Nesheim
                     16:  *     Cornell University
                     17:  *
                     18:  *     Lou Salkind
                     19:  *     New York University
                     20:  */
                     21: 
                     22: /* #define DEBUG       /* for base table dump on fatal error */
                     23: 
                     24: #include "../machine/pte.h"
                     25: 
                     26: #include "param.h"
                     27: #include "systm.h"
                     28: #include "mbuf.h"
                     29: #include "buf.h"
                     30: #include "ioctl.h"             /* must precede tty.h */
                     31: #include "tty.h"
                     32: #include "protosw.h"
                     33: #include "socket.h"
                     34: #include "syslog.h"
                     35: #include "vmmac.h"
                     36: #include "errno.h"
                     37: 
                     38: #include "../net/if.h"
                     39: #include "../net/netisr.h"
                     40: #include "../net/route.h"
                     41: 
                     42: #ifdef INET
                     43: #include "../netinet/in.h"
                     44: #include "../netinet/in_systm.h"
                     45: #include "../netinet/in_var.h"
                     46: #include "../netinet/ip.h"
                     47: #endif
                     48: 
                     49: #include "../vax/cpu.h"
                     50: #include "../vax/mtpr.h"
                     51: #include "if_uba.h"
                     52: #include "if_dmc.h"
                     53: #include "../vaxuba/ubareg.h"
                     54: #include "../vaxuba/ubavar.h"
                     55: 
                     56: #include "../h/time.h"
                     57: #include "../h/kernel.h"
                     58: 
                     59: /*
                     60:  * output timeout value, sec.; should depend on line speed.
                     61:  */
                     62: int    dmc_timeout = 20;
                     63: 
                     64: /*
                     65:  * Driver information for auto-configuration stuff.
                     66:  */
                     67: int    dmcprobe(), dmcattach(), dmcinit(), dmcioctl();
                     68: int    dmcoutput(), dmcreset(), dmctimeout();
                     69: struct uba_device *dmcinfo[NDMC];
                     70: u_short        dmcstd[] = { 0 };
                     71: struct uba_driver dmcdriver =
                     72:        { dmcprobe, 0, dmcattach, 0, dmcstd, "dmc", dmcinfo };
                     73: 
                     74: #define NRCV 7
                     75: #define NXMT 3 
                     76: #define NCMDS  (NRCV+NXMT+4)   /* size of command queue */
                     77: 
                     78: #define printd if(dmcdebug)printf
                     79: int dmcdebug = 0;
                     80: 
                     81: /* error reporting intervals */
                     82: #define DMC_RPNBFS     50
                     83: #define DMC_RPDSC      1
                     84: #define DMC_RPTMO      10
                     85: #define DMC_RPDCK      10
                     86: 
                     87: struct  dmc_command {
                     88:        char    qp_cmd;         /* command */
                     89:        short   qp_ubaddr;      /* buffer address */
                     90:        short   qp_cc;          /* character count || XMEM */
                     91:        struct  dmc_command *qp_next;   /* next command on queue */
                     92: };
                     93: 
                     94: struct dmcbufs {
                     95:        int     ubinfo;         /* from uballoc */
                     96:        short   cc;             /* buffer size */
                     97:        short   flags;          /* access control */
                     98: };
                     99: #define        DBUF_OURS       0       /* buffer is available */
                    100: #define        DBUF_DMCS       1       /* buffer claimed by somebody */
                    101: #define        DBUF_XMIT       4       /* transmit buffer */
                    102: #define        DBUF_RCV        8       /* receive buffer */
                    103: 
                    104: 
                    105: /*
                    106:  * DMC software status per interface.
                    107:  *
                    108:  * Each interface is referenced by a network interface structure,
                    109:  * sc_if, which the routing code uses to locate the interface.
                    110:  * This structure contains the output queue for the interface, its address, ...
                    111:  * We also have, for each interface, a  set of 7 UBA interface structures
                    112:  * for each, which
                    113:  * contain information about the UNIBUS resources held by the interface:
                    114:  * map registers, buffered data paths, etc.  Information is cached in this
                    115:  * structure for use by the if_uba.c routines in running the interface
                    116:  * efficiently.
                    117:  */
                    118: struct dmc_softc {
                    119:        struct  ifnet sc_if;            /* network-visible interface */
                    120:        short   sc_oused;               /* output buffers currently in use */
                    121:        short   sc_iused;               /* input buffers given to DMC */
                    122:        short   sc_flag;                /* flags */
                    123:        int     sc_ubinfo;              /* UBA mapping info for base table */
                    124:        int     sc_errors[4];           /* non-fatal error counters */
                    125: #define sc_datck sc_errors[0]
                    126: #define sc_timeo sc_errors[1]
                    127: #define sc_nobuf sc_errors[2]
                    128: #define sc_disc  sc_errors[3]
                    129:        struct  dmcbufs sc_rbufs[NRCV]; /* receive buffer info */
                    130:        struct  dmcbufs sc_xbufs[NXMT]; /* transmit buffer info */
                    131:        struct  ifubinfo sc_ifuba;      /* UNIBUS resources */
                    132:        struct  ifrw sc_ifr[NRCV];      /* UNIBUS receive buffer maps */
                    133:        struct  ifxmt sc_ifw[NXMT];     /* UNIBUS receive buffer maps */
                    134:        /* command queue stuff */
                    135:        struct  dmc_command sc_cmdbuf[NCMDS];
                    136:        struct  dmc_command *sc_qhead;  /* head of command queue */
                    137:        struct  dmc_command *sc_qtail;  /* tail of command queue */
                    138:        struct  dmc_command *sc_qactive;        /* command in progress */
                    139:        struct  dmc_command *sc_qfreeh; /* head of list of free cmd buffers */
                    140:        struct  dmc_command *sc_qfreet; /* tail of list of free cmd buffers */
                    141:        /* end command queue stuff */
                    142: } dmc_softc[NDMC];
                    143: 
                    144: /* flags */
                    145: #define DMC_RUNNING    0x01            /* device initialized */
                    146: #define DMC_BMAPPED    0x02            /* base table mapped */
                    147: #define DMC_RESTART    0x04            /* software restart in progress */
                    148: #define DMC_ONLINE     0x08            /* device running (had a RDYO) */
                    149: 
                    150: struct dmc_base {
                    151:        short   d_base[128];            /* DMC base table */
                    152: } dmc_base[NDMC];
                    153: 
                    154: /* queue manipulation macros */
                    155: #define        QUEUE_AT_HEAD(qp, head, tail) \
                    156:        (qp)->qp_next = (head); \
                    157:        (head) = (qp); \
                    158:        if ((tail) == (struct dmc_command *) 0) \
                    159:                (tail) = (head) 
                    160: 
                    161: #define QUEUE_AT_TAIL(qp, head, tail) \
                    162:        if ((tail)) \
                    163:                (tail)->qp_next = (qp); \
                    164:        else \
                    165:                (head) = (qp); \
                    166:        (qp)->qp_next = (struct dmc_command *) 0; \
                    167:        (tail) = (qp)
                    168: 
                    169: #define DEQUEUE(head, tail) \
                    170:        (head) = (head)->qp_next;\
                    171:        if ((head) == (struct dmc_command *) 0)\
                    172:                (tail) = (head)
                    173: 
                    174: dmcprobe(reg)
                    175:        caddr_t reg;
                    176: {
                    177:        register int br, cvec;
                    178:        register struct dmcdevice *addr = (struct dmcdevice *)reg;
                    179:        register int i;
                    180: 
                    181: #ifdef lint
                    182:        br = 0; cvec = br; br = cvec;
                    183:        dmcrint(0); dmcxint(0);
                    184: #endif
                    185:        addr->bsel1 = DMC_MCLR;
                    186:        for (i = 100000; i && (addr->bsel1 & DMC_RUN) == 0; i--)
                    187:                ;
                    188:        if ((addr->bsel1 & DMC_RUN) == 0) {
                    189:                printf("dmcprobe: can't start device\n" );
                    190:                return (0);
                    191:        }
                    192:        addr->bsel0 = DMC_RQI|DMC_IEI;
                    193:        /* let's be paranoid */
                    194:        addr->bsel0 |= DMC_RQI|DMC_IEI;
                    195:        DELAY(1000000);
                    196:        addr->bsel1 = DMC_MCLR;
                    197:        for (i = 100000; i && (addr->bsel1 & DMC_RUN) == 0; i--)
                    198:                ;
                    199:        return (1);
                    200: }
                    201: 
                    202: /*
                    203:  * Interface exists: make available by filling in network interface
                    204:  * record.  System will initialize the interface when it is ready
                    205:  * to accept packets.
                    206:  */
                    207: dmcattach(ui)
                    208:        register struct uba_device *ui;
                    209: {
                    210:        register struct dmc_softc *sc = &dmc_softc[ui->ui_unit];
                    211: 
                    212:        sc->sc_if.if_unit = ui->ui_unit;
                    213:        sc->sc_if.if_name = "dmc";
                    214:        sc->sc_if.if_mtu = DMCMTU;
                    215:        sc->sc_if.if_init = dmcinit;
                    216:        sc->sc_if.if_output = dmcoutput;
                    217:        sc->sc_if.if_ioctl = dmcioctl;
                    218:        sc->sc_if.if_reset = dmcreset;
                    219:        sc->sc_if.if_watchdog = dmctimeout;
                    220:        sc->sc_if.if_flags = IFF_POINTOPOINT;
                    221:        sc->sc_ifuba.iff_flags = UBA_CANTWAIT;
                    222: 
                    223:        if_attach(&sc->sc_if);
                    224: }
                    225: 
                    226: /*
                    227:  * Reset of interface after UNIBUS reset.
                    228:  * If interface is on specified UBA, reset its state.
                    229:  */
                    230: dmcreset(unit, uban)
                    231:        int unit, uban;
                    232: {
                    233:        register struct uba_device *ui;
                    234:        register struct dmc_softc *sc = &dmc_softc[unit];
                    235: 
                    236:        if (unit >= NDMC || (ui = dmcinfo[unit]) == 0 || ui->ui_alive == 0 ||
                    237:            ui->ui_ubanum != uban)
                    238:                return;
                    239:        printf(" dmc%d", unit);
                    240:        sc->sc_flag = 0;
                    241:        sc->sc_if.if_flags &= ~IFF_RUNNING;
                    242:        dmcinit(unit);
                    243: }
                    244: 
                    245: /*
                    246:  * Initialization of interface; reinitialize UNIBUS usage.
                    247:  */
                    248: dmcinit(unit)
                    249:        int unit;
                    250: {
                    251:        register struct dmc_softc *sc = &dmc_softc[unit];
                    252:        register struct uba_device *ui = dmcinfo[unit];
                    253:        register struct dmcdevice *addr;
                    254:        register struct ifnet *ifp = &sc->sc_if;
                    255:        register struct ifrw *ifrw;
                    256:        register struct ifxmt *ifxp;
                    257:        register struct dmcbufs *rp;
                    258:        register struct dmc_command *qp;
                    259:        struct ifaddr *ifa;
                    260:        int base;
                    261:        int s;
                    262: 
                    263:        addr = (struct dmcdevice *)ui->ui_addr;
                    264: 
                    265:        /*
                    266:         * Check to see that an address has been set
                    267:         * (both local and destination for an address family).
                    268:         */
                    269:        for (ifa = ifp->if_addrlist; ifa; ifa = ifa->ifa_next)
                    270:                if (ifa->ifa_addr.sa_family && ifa->ifa_dstaddr.sa_family)
                    271:                        break;
                    272:        if (ifa == (struct ifaddr *) 0)
                    273:                return;
                    274: 
                    275:        if ((addr->bsel1&DMC_RUN) == 0) {
                    276:                printf("dmcinit: DMC not running\n");
                    277:                ifp->if_flags &= ~IFF_UP;
                    278:                return;
                    279:        }
                    280:        /* map base table */
                    281:        if ((sc->sc_flag & DMC_BMAPPED) == 0) {
                    282:                sc->sc_ubinfo = uballoc(ui->ui_ubanum,
                    283:                        (caddr_t)&dmc_base[unit], sizeof (struct dmc_base), 0);
                    284:                sc->sc_flag |= DMC_BMAPPED;
                    285:        }
                    286:        /* initialize UNIBUS resources */
                    287:        sc->sc_iused = sc->sc_oused = 0;
                    288:        if ((ifp->if_flags & IFF_RUNNING) == 0) {
                    289:                if (if_ubaminit(&sc->sc_ifuba, ui->ui_ubanum,
                    290:                    sizeof(struct dmc_header), (int)btoc(DMCMTU),
                    291:                    sc->sc_ifr, NRCV, sc->sc_ifw, NXMT) == 0) {
                    292:                        printf("dmc%d: can't allocate uba resources\n", unit);
                    293:                        ifp->if_flags &= ~IFF_UP;
                    294:                        return;
                    295:                }
                    296:                ifp->if_flags |= IFF_RUNNING;
                    297:        }
                    298:        sc->sc_flag &= ~DMC_ONLINE;
                    299:        sc->sc_flag |= DMC_RUNNING;
                    300:        /*
                    301:         * Limit packets enqueued until we see if we're on the air.
                    302:         */
                    303:        ifp->if_snd.ifq_maxlen = 3;
                    304: 
                    305:        /* initialize buffer pool */
                    306:        /* receives */
                    307:        ifrw = &sc->sc_ifr[0];
                    308:        for (rp = &sc->sc_rbufs[0]; rp < &sc->sc_rbufs[NRCV]; rp++) {
                    309:                rp->ubinfo = ifrw->ifrw_info & 0x3ffff;
                    310:                rp->cc = DMCMTU + sizeof (struct dmc_header);
                    311:                rp->flags = DBUF_OURS|DBUF_RCV;
                    312:                ifrw++; 
                    313:        }
                    314:        /* transmits */
                    315:        ifxp = &sc->sc_ifw[0];
                    316:        for (rp = &sc->sc_xbufs[0]; rp < &sc->sc_xbufs[NXMT]; rp++) {
                    317:                rp->ubinfo = ifxp->ifw_info & 0x3ffff;
                    318:                rp->cc = 0;
                    319:                rp->flags = DBUF_OURS|DBUF_XMIT;
                    320:                ifxp++; 
                    321:        }
                    322: 
                    323:        /* set up command queues */
                    324:        sc->sc_qfreeh = sc->sc_qfreet
                    325:                 = sc->sc_qhead = sc->sc_qtail = sc->sc_qactive =
                    326:                (struct dmc_command *)0;
                    327:        /* set up free command buffer list */
                    328:        for (qp = &sc->sc_cmdbuf[0]; qp < &sc->sc_cmdbuf[NCMDS]; qp++) {
                    329:                QUEUE_AT_HEAD(qp, sc->sc_qfreeh, sc->sc_qfreet);
                    330:        }
                    331: 
                    332:        /* base in */
                    333:        base = sc->sc_ubinfo & 0x3ffff;
                    334:        dmcload(sc, DMC_BASEI, base, (base>>2) & DMC_XMEM);
                    335:        /* specify half duplex operation, flags tell if primary */
                    336:        /* or secondary station */
                    337:        if (ui->ui_flags == 0)
                    338:                /* use DDCMP mode in full duplex */
                    339:                dmcload(sc, DMC_CNTLI, 0, 0);
                    340:        else if (ui->ui_flags == 1)
                    341:                /* use MAINTENENCE mode */
                    342:                dmcload(sc, DMC_CNTLI, 0, DMC_MAINT );
                    343:        else if (ui->ui_flags == 2)
                    344:                /* use DDCMP half duplex as primary station */
                    345:                dmcload(sc, DMC_CNTLI, 0, DMC_HDPLX);
                    346:        else if (ui->ui_flags == 3)
                    347:                /* use DDCMP half duplex as secondary station */
                    348:                dmcload(sc, DMC_CNTLI, 0, DMC_HDPLX | DMC_SEC);
                    349: 
                    350:        /* enable operation done interrupts */
                    351:        while ((addr->bsel2 & DMC_IEO) == 0)
                    352:                addr->bsel2 |= DMC_IEO;
                    353:        s = spl5();
                    354:        /* queue first NRCV buffers for DMC to fill */
                    355:        for (rp = &sc->sc_rbufs[0]; rp < &sc->sc_rbufs[NRCV]; rp++) {
                    356:                rp->flags |= DBUF_DMCS;
                    357:                dmcload(sc, DMC_READ, rp->ubinfo,
                    358:                        (((rp->ubinfo>>2)&DMC_XMEM) | rp->cc));
                    359:                sc->sc_iused++;
                    360:        }
                    361:        splx(s);
                    362: }
                    363: 
                    364: /*
                    365:  * Start output on interface.  Get another datagram
                    366:  * to send from the interface queue and map it to
                    367:  * the interface before starting output.
                    368:  *
                    369:  * Must be called at spl 5
                    370:  */
                    371: dmcstart(unit)
                    372:        int unit;
                    373: {
                    374:        register struct dmc_softc *sc = &dmc_softc[unit];
                    375:        struct mbuf *m;
                    376:        register struct dmcbufs *rp;
                    377:        register int n;
                    378: 
                    379:        /*
                    380:         * Dequeue up to NXMT requests and map them to the UNIBUS.
                    381:         * If no more requests, or no dmc buffers available, just return.
                    382:         */
                    383:        n = 0;
                    384:        for (rp = &sc->sc_xbufs[0]; rp < &sc->sc_xbufs[NXMT]; rp++ ) {
                    385:                /* find an available buffer */
                    386:                if ((rp->flags & DBUF_DMCS) == 0) {
                    387:                        IF_DEQUEUE(&sc->sc_if.if_snd, m);
                    388:                        if (m == 0)
                    389:                                return;
                    390:                        /* mark it dmcs */
                    391:                        rp->flags |= (DBUF_DMCS);
                    392:                        /*
                    393:                         * Have request mapped to UNIBUS for transmission
                    394:                         * and start the output.
                    395:                         */
                    396:                        rp->cc = if_ubaput(&sc->sc_ifuba, &sc->sc_ifw[n], m);
                    397:                        rp->cc &= DMC_CCOUNT;
                    398:                        if (++sc->sc_oused == 1)
                    399:                                sc->sc_if.if_timer = dmc_timeout;
                    400:                        dmcload(sc, DMC_WRITE, rp->ubinfo, 
                    401:                                rp->cc | ((rp->ubinfo>>2)&DMC_XMEM));
                    402:                }
                    403:                n++;
                    404:        }
                    405: }
                    406: 
                    407: /*
                    408:  * Utility routine to load the DMC device registers.
                    409:  */
                    410: dmcload(sc, type, w0, w1)
                    411:        register struct dmc_softc *sc;
                    412:        int type, w0, w1;
                    413: {
                    414:        register struct dmcdevice *addr;
                    415:        register int unit, sps;
                    416:        register struct dmc_command *qp;
                    417: 
                    418:        unit = sc - dmc_softc;
                    419:        addr = (struct dmcdevice *)dmcinfo[unit]->ui_addr;
                    420:        sps = spl5();
                    421: 
                    422:        /* grab a command buffer from the free list */
                    423:        if ((qp = sc->sc_qfreeh) == (struct dmc_command *)0)
                    424:                panic("dmc command queue overflow");
                    425:        DEQUEUE(sc->sc_qfreeh, sc->sc_qfreet);
                    426: 
                    427:        /* fill in requested info */
                    428:        qp->qp_cmd = (type | DMC_RQI);
                    429:        qp->qp_ubaddr = w0;
                    430:        qp->qp_cc = w1;
                    431:        
                    432:        if (sc->sc_qactive) {   /* command in progress */
                    433:                if (type == DMC_READ) {
                    434:                        QUEUE_AT_HEAD(qp, sc->sc_qhead, sc->sc_qtail);
                    435:                } else {
                    436:                        QUEUE_AT_TAIL(qp, sc->sc_qhead, sc->sc_qtail);
                    437:                }
                    438:        } else {        /* command port free */
                    439:                sc->sc_qactive = qp;
                    440:                addr->bsel0 = qp->qp_cmd;
                    441:                dmcrint(unit);
                    442:        }
                    443:        splx(sps);
                    444: }
                    445: 
                    446: /*
                    447:  * DMC interface receiver interrupt.
                    448:  * Ready to accept another command,
                    449:  * pull one off the command queue.
                    450:  */
                    451: dmcrint(unit)
                    452:        int unit;
                    453: {
                    454:        register struct dmc_softc *sc;
                    455:        register struct dmcdevice *addr;
                    456:        register struct dmc_command *qp;
                    457:        register int n;
                    458: 
                    459:        addr = (struct dmcdevice *)dmcinfo[unit]->ui_addr;
                    460:        sc = &dmc_softc[unit];
                    461:        if ((qp = sc->sc_qactive) == (struct dmc_command *) 0) {
                    462:                printf("dmc%d: dmcrint no command\n", unit);
                    463:                return;
                    464:        }
                    465:        while (addr->bsel0&DMC_RDYI) {
                    466:                addr->sel4 = qp->qp_ubaddr;
                    467:                addr->sel6 = qp->qp_cc;
                    468:                addr->bsel0 &= ~(DMC_IEI|DMC_RQI);
                    469:                /* free command buffer */
                    470:                QUEUE_AT_HEAD(qp, sc->sc_qfreeh, sc->sc_qfreet);
                    471:                while (addr->bsel0 & DMC_RDYI) {
                    472:                        /*
                    473:                         * Can't check for RDYO here 'cause
                    474:                         * this routine isn't reentrant!
                    475:                         */
                    476:                        DELAY(5);
                    477:                }
                    478:                /* move on to next command */
                    479:                if ((sc->sc_qactive = sc->sc_qhead) == (struct dmc_command *)0)
                    480:                        break;          /* all done */
                    481:                /* more commands to do, start the next one */
                    482:                qp = sc->sc_qactive;
                    483:                DEQUEUE(sc->sc_qhead, sc->sc_qtail);
                    484:                addr->bsel0 = qp->qp_cmd;
                    485:                n = RDYSCAN;
                    486:                while (n-- > 0)
                    487:                        if ((addr->bsel0&DMC_RDYI) || (addr->bsel2&DMC_RDYO))
                    488:                                break;
                    489:        }
                    490:        if (sc->sc_qactive) {
                    491:                addr->bsel0 |= DMC_IEI|DMC_RQI;
                    492:                /* VMS does it twice !*$%@# */
                    493:                addr->bsel0 |= DMC_IEI|DMC_RQI;
                    494:        }
                    495: 
                    496: }
                    497: 
                    498: /*
                    499:  * DMC interface transmitter interrupt.
                    500:  * A transfer may have completed, check for errors.
                    501:  * If it was a read, notify appropriate protocol.
                    502:  * If it was a write, pull the next one off the queue.
                    503:  */
                    504: dmcxint(unit)
                    505:        int unit;
                    506: {
                    507:        register struct dmc_softc *sc;
                    508:        register struct ifnet *ifp;
                    509:        struct uba_device *ui = dmcinfo[unit];
                    510:        struct dmcdevice *addr;
                    511:        struct mbuf *m;
                    512:        struct ifqueue *inq;
                    513:        int arg, pkaddr, cmd, len, s;
                    514:        register struct ifrw *ifrw;
                    515:        register struct dmcbufs *rp;
                    516:        register struct ifxmt *ifxp;
                    517:        struct dmc_header *dh;
                    518:        int off, resid;
                    519: 
                    520:        addr = (struct dmcdevice *)ui->ui_addr;
                    521:        sc = &dmc_softc[unit];
                    522:        ifp = &sc->sc_if;
                    523: 
                    524:        while (addr->bsel2 & DMC_RDYO) {
                    525: 
                    526:                cmd = addr->bsel2 & 0xff;
                    527:                arg = addr->sel6 & 0xffff;
                    528:                /* reconstruct UNIBUS address of buffer returned to us */
                    529:                pkaddr = ((arg&DMC_XMEM)<<2) | (addr->sel4 & 0xffff);
                    530:                /* release port */
                    531:                addr->bsel2 &= ~DMC_RDYO;
                    532:                switch (cmd & 07) {
                    533: 
                    534:                case DMC_OUR:
                    535:                        /*
                    536:                         * A read has completed.  
                    537:                         * Pass packet to type specific
                    538:                         * higher-level input routine.
                    539:                         */
                    540:                        ifp->if_ipackets++;
                    541:                        /* find location in dmcuba struct */
                    542:                        ifrw= &sc->sc_ifr[0];
                    543:                        for (rp = &sc->sc_rbufs[0]; rp < &sc->sc_rbufs[NRCV]; rp++) {
                    544:                                if(rp->ubinfo == pkaddr)
                    545:                                        break;
                    546:                                ifrw++;
                    547:                        }
                    548:                        if (rp >= &sc->sc_rbufs[NRCV])
                    549:                                panic("dmc rcv");
                    550:                        if ((rp->flags & DBUF_DMCS) == 0)
                    551:                                printf("dmc%d: done unalloc rbuf\n", unit);
                    552: 
                    553:                        len = (arg & DMC_CCOUNT) - sizeof (struct dmc_header);
                    554:                        if (len < 0 || len > DMCMTU) {
                    555:                                ifp->if_ierrors++;
                    556:                                printd("dmc%d: bad rcv pkt addr 0x%x len 0x%x\n",
                    557:                                    unit, pkaddr, len);
                    558:                                goto setup;
                    559:                        }
                    560:                        /*
                    561:                         * Deal with trailer protocol: if type is trailer
                    562:                         * get true type from first 16-bit word past data.
                    563:                         * Remember that type was trailer by setting off.
                    564:                         */
                    565:                        dh = (struct dmc_header *)ifrw->ifrw_addr;
                    566:                        dh->dmc_type = ntohs((u_short)dh->dmc_type);
                    567: #define dmcdataaddr(dh, off, type)     ((type)(((caddr_t)((dh)+1)+(off))))
                    568:                        if (dh->dmc_type >= DMC_TRAILER &&
                    569:                            dh->dmc_type < DMC_TRAILER+DMC_NTRAILER) {
                    570:                                off = (dh->dmc_type - DMC_TRAILER) * 512;
                    571:                                if (off >= DMCMTU)
                    572:                                        goto setup;             /* sanity */
                    573:                                dh->dmc_type = ntohs(*dmcdataaddr(dh, off, u_short *));
                    574:                                resid = ntohs(*(dmcdataaddr(dh, off+2, u_short *)));
                    575:                                if (off + resid > len)
                    576:                                        goto setup;             /* sanity */
                    577:                                len = off + resid;
                    578:                        } else
                    579:                                off = 0;
                    580:                        if (len == 0)
                    581:                                goto setup;
                    582: 
                    583:                        /*
                    584:                         * Pull packet off interface.  Off is nonzero if
                    585:                         * packet has trailing header; dmc_get will then
                    586:                         * force this header information to be at the front,
                    587:                         * but we still have to drop the type and length
                    588:                         * which are at the front of any trailer data.
                    589:                         */
                    590:                        m = if_ubaget(&sc->sc_ifuba, ifrw, len, off, ifp);
                    591:                        if (m == 0)
                    592:                                goto setup;
                    593:                        if (off) {
                    594:                                ifp = *(mtod(m, struct ifnet **));
                    595:                                m->m_off += 2 * sizeof (u_short);
                    596:                                m->m_len -= 2 * sizeof (u_short);
                    597:                                *(mtod(m, struct ifnet **)) = ifp;
                    598:                        }
                    599:                        switch (dh->dmc_type) {
                    600: 
                    601: #ifdef INET
                    602:                        case DMC_IPTYPE:
                    603:                                schednetisr(NETISR_IP);
                    604:                                inq = &ipintrq;
                    605:                                break;
                    606: #endif
                    607:                        default:
                    608:                                m_freem(m);
                    609:                                goto setup;
                    610:                        }
                    611: 
                    612:                        s = splimp();
                    613:                        if (IF_QFULL(inq)) {
                    614:                                IF_DROP(inq);
                    615:                                m_freem(m);
                    616:                        } else
                    617:                                IF_ENQUEUE(inq, m);
                    618:                        splx(s);
                    619: 
                    620:        setup:
                    621:                        /* is this needed? */
                    622:                        rp->ubinfo = ifrw->ifrw_info & 0x3ffff;
                    623: 
                    624:                        dmcload(sc, DMC_READ, rp->ubinfo, 
                    625:                            ((rp->ubinfo >> 2) & DMC_XMEM) | rp->cc);
                    626:                        break;
                    627: 
                    628:                case DMC_OUX:
                    629:                        /*
                    630:                         * A write has completed, start another
                    631:                         * transfer if there is more data to send.
                    632:                         */
                    633:                        ifp->if_opackets++;
                    634:                        /* find associated dmcbuf structure */
                    635:                        ifxp = &sc->sc_ifw[0];
                    636:                        for (rp = &sc->sc_xbufs[0]; rp < &sc->sc_xbufs[NXMT]; rp++) {
                    637:                                if(rp->ubinfo == pkaddr)
                    638:                                        break;
                    639:                                ifxp++;
                    640:                        }
                    641:                        if (rp >= &sc->sc_xbufs[NXMT]) {
                    642:                                printf("dmc%d: bad packet address 0x%x\n",
                    643:                                    unit, pkaddr);
                    644:                                break;
                    645:                        }
                    646:                        if ((rp->flags & DBUF_DMCS) == 0)
                    647:                                printf("dmc%d: unallocated packet 0x%x\n",
                    648:                                    unit, pkaddr);
                    649:                        /* mark buffer free */
                    650:                        if (ifxp->ifw_xtofree) {
                    651:                                (void)m_freem(ifxp->ifw_xtofree);
                    652:                                ifxp->ifw_xtofree = 0;
                    653:                        }
                    654:                        rp->flags &= ~DBUF_DMCS;
                    655:                        if (--sc->sc_oused == 0)
                    656:                                sc->sc_if.if_timer = 0;
                    657:                        else
                    658:                                sc->sc_if.if_timer = dmc_timeout;
                    659:                        if ((sc->sc_flag & DMC_ONLINE) == 0) {
                    660:                                extern int ifqmaxlen;
                    661: 
                    662:                                /*
                    663:                                 * We're on the air.
                    664:                                 * Open the queue to the usual value.
                    665:                                 */
                    666:                                sc->sc_flag |= DMC_ONLINE;
                    667:                                ifp->if_snd.ifq_maxlen = ifqmaxlen;
                    668:                        }
                    669:                        break;
                    670: 
                    671:                case DMC_CNTLO:
                    672:                        arg &= DMC_CNTMASK;
                    673:                        if (arg & DMC_FATAL) {
                    674:                                if (arg != DMC_START)
                    675:                                        log(LOG_ERR,
                    676:                                            "dmc%d: fatal error, flags=%b\n",
                    677:                                            unit, arg, CNTLO_BITS);
                    678:                                dmcrestart(unit);
                    679:                                break;
                    680:                        }
                    681:                        /* ACCUMULATE STATISTICS */
                    682:                        switch(arg) {
                    683:                        case DMC_NOBUFS:
                    684:                                ifp->if_ierrors++;
                    685:                                if ((sc->sc_nobuf++ % DMC_RPNBFS) == 0)
                    686:                                        goto report;
                    687:                                break;
                    688:                        case DMC_DISCONN:
                    689:                                if ((sc->sc_disc++ % DMC_RPDSC) == 0)
                    690:                                        goto report;
                    691:                                break;
                    692:                        case DMC_TIMEOUT:
                    693:                                if ((sc->sc_timeo++ % DMC_RPTMO) == 0)
                    694:                                        goto report;
                    695:                                break;
                    696:                        case DMC_DATACK:
                    697:                                ifp->if_oerrors++;
                    698:                                if ((sc->sc_datck++ % DMC_RPDCK) == 0)
                    699:                                        goto report;
                    700:                                break;
                    701:                        default:
                    702:                                goto report;
                    703:                        }
                    704:                        break;
                    705:                report:
                    706:                        printd("dmc%d: soft error, flags=%b\n", unit,
                    707:                            arg, CNTLO_BITS);
                    708:                        if ((sc->sc_flag & DMC_RESTART) == 0) {
                    709:                                /*
                    710:                                 * kill off the dmc to get things
                    711:                                 * going again by generating a
                    712:                                 * procedure error
                    713:                                 */
                    714:                                sc->sc_flag |= DMC_RESTART;
                    715:                                arg = sc->sc_ubinfo & 0x3ffff;
                    716:                                dmcload(sc, DMC_BASEI, arg, (arg>>2)&DMC_XMEM);
                    717:                        }
                    718:                        break;
                    719: 
                    720:                default:
                    721:                        printf("dmc%d: bad control %o\n", unit, cmd);
                    722:                        break;
                    723:                }
                    724:        }
                    725:        dmcstart(unit);
                    726:        return;
                    727: }
                    728: 
                    729: /*
                    730:  * DMC output routine.
                    731:  * Encapsulate a packet of type family for the dmc.
                    732:  * Use trailer local net encapsulation if enough data in first
                    733:  * packet leaves a multiple of 512 bytes of data in remainder.
                    734:  */
                    735: dmcoutput(ifp, m0, dst)
                    736:        register struct ifnet *ifp;
                    737:        register struct mbuf *m0;
                    738:        struct sockaddr *dst;
                    739: {
                    740:        int type, error, s;
                    741:        register struct mbuf *m = m0;
                    742:        register struct dmc_header *dh;
                    743:        register int off;
                    744: 
                    745:        if ((ifp->if_flags & IFF_UP) == 0) {
                    746:                error = ENETDOWN;
                    747:                goto bad;
                    748:        }
                    749: 
                    750:        switch (dst->sa_family) {
                    751: #ifdef INET
                    752:        case AF_INET:
                    753:                off = ntohs((u_short)mtod(m, struct ip *)->ip_len) - m->m_len;
                    754:                if ((ifp->if_flags & IFF_NOTRAILERS) == 0)
                    755:                if (off > 0 && (off & 0x1ff) == 0 &&
                    756:                    m->m_off >= MMINOFF + 2 * sizeof (u_short)) {
                    757:                        type = DMC_TRAILER + (off>>9);
                    758:                        m->m_off -= 2 * sizeof (u_short);
                    759:                        m->m_len += 2 * sizeof (u_short);
                    760:                        *mtod(m, u_short *) = htons((u_short)DMC_IPTYPE);
                    761:                        *(mtod(m, u_short *) + 1) = htons((u_short)m->m_len);
                    762:                        goto gottrailertype;
                    763:                }
                    764:                type = DMC_IPTYPE;
                    765:                off = 0;
                    766:                goto gottype;
                    767: #endif
                    768: 
                    769:        case AF_UNSPEC:
                    770:                dh = (struct dmc_header *)dst->sa_data;
                    771:                type = dh->dmc_type;
                    772:                goto gottype;
                    773: 
                    774:        default:
                    775:                printf("dmc%d: can't handle af%d\n", ifp->if_unit,
                    776:                        dst->sa_family);
                    777:                error = EAFNOSUPPORT;
                    778:                goto bad;
                    779:        }
                    780: 
                    781: gottrailertype:
                    782:        /*
                    783:         * Packet to be sent as a trailer; move first packet
                    784:         * (control information) to end of chain.
                    785:         */
                    786:        while (m->m_next)
                    787:                m = m->m_next;
                    788:        m->m_next = m0;
                    789:        m = m0->m_next;
                    790:        m0->m_next = 0;
                    791:        m0 = m;
                    792: 
                    793: gottype:
                    794:        /*
                    795:         * Add local network header
                    796:         * (there is space for a uba on a vax to step on)
                    797:         */
                    798:        if (m->m_off > MMAXOFF ||
                    799:            MMINOFF + sizeof(struct dmc_header) > m->m_off) {
                    800:                m = m_get(M_DONTWAIT, MT_HEADER);
                    801:                if (m == 0) {
                    802:                        error = ENOBUFS;
                    803:                        goto bad;
                    804:                }
                    805:                m->m_next = m0;
                    806:                m->m_off = MMINOFF;
                    807:                m->m_len = sizeof (struct dmc_header);
                    808:        } else {
                    809:                m->m_off -= sizeof (struct dmc_header);
                    810:                m->m_len += sizeof (struct dmc_header);
                    811:        }
                    812:        dh = mtod(m, struct dmc_header *);
                    813:        dh->dmc_type = htons((u_short)type);
                    814: 
                    815:        /*
                    816:         * Queue message on interface, and start output if interface
                    817:         * not yet active.
                    818:         */
                    819:        s = splimp();
                    820:        if (IF_QFULL(&ifp->if_snd)) {
                    821:                IF_DROP(&ifp->if_snd);
                    822:                m_freem(m);
                    823:                splx(s);
                    824:                return (ENOBUFS);
                    825:        }
                    826:        IF_ENQUEUE(&ifp->if_snd, m);
                    827:        dmcstart(ifp->if_unit);
                    828:        splx(s);
                    829:        return (0);
                    830: 
                    831: bad:
                    832:        m_freem(m0);
                    833:        return (error);
                    834: }
                    835: 
                    836: 
                    837: /*
                    838:  * Process an ioctl request.
                    839:  */
                    840: /* ARGSUSED */
                    841: dmcioctl(ifp, cmd, data)
                    842:        register struct ifnet *ifp;
                    843:        int cmd;
                    844:        caddr_t data;
                    845: {
                    846:        int s = splimp(), error = 0;
                    847:        register struct dmc_softc *sc = &dmc_softc[ifp->if_unit];
                    848: 
                    849:        switch (cmd) {
                    850: 
                    851:        case SIOCSIFADDR:
                    852:                ifp->if_flags |= IFF_UP;
                    853:                if ((ifp->if_flags & IFF_RUNNING) == 0)
                    854:                        dmcinit(ifp->if_unit); 
                    855:                break;
                    856: 
                    857:        case SIOCSIFDSTADDR:
                    858:                if ((ifp->if_flags & IFF_RUNNING) == 0)
                    859:                        dmcinit(ifp->if_unit); 
                    860:                break;
                    861:                
                    862:        case SIOCSIFFLAGS:
                    863:                if ((ifp->if_flags & IFF_UP) == 0 &&
                    864:                    sc->sc_flag & DMC_RUNNING)
                    865:                        dmcdown(ifp->if_unit);
                    866:                else if (ifp->if_flags & IFF_UP &&
                    867:                    (sc->sc_flag & DMC_RUNNING) == 0)
                    868:                        dmcrestart(ifp->if_unit);
                    869:                break;
                    870: 
                    871:        default:
                    872:                error = EINVAL;
                    873:        }
                    874:        splx(s);
                    875:        return (error);
                    876: }
                    877: 
                    878: /*
                    879:  * Restart after a fatal error.
                    880:  * Clear device and reinitialize.
                    881:  */
                    882: dmcrestart(unit)
                    883:        int unit;
                    884: {
                    885:        register struct dmc_softc *sc = &dmc_softc[unit];
                    886:        register struct dmcdevice *addr;
                    887:        register int i;
                    888:        int s;
                    889:        
                    890: #ifdef DEBUG
                    891:        /* dump base table */
                    892:        printf("dmc%d base table:\n", unit);
                    893:        for (i = 0; i < sizeof (struct dmc_base); i++)
                    894:                printf("%o\n" ,dmc_base[unit].d_base[i]);
                    895: #endif
                    896: 
                    897:        dmcdown(unit);
                    898: 
                    899:        /*
                    900:         * Let the DMR finish the MCLR.  At 1 Mbit, it should do so
                    901:         * in about a max of 6.4 milliseconds with diagnostics enabled.
                    902:         */
                    903:        addr = (struct dmcdevice *)(dmcinfo[unit]->ui_addr);
                    904:        for (i = 100000; i && (addr->bsel1 & DMC_RUN) == 0; i--)
                    905:                ;
                    906:        /* Did the timer expire or did the DMR finish? */
                    907:        if ((addr->bsel1 & DMC_RUN) == 0) {
                    908:                log(LOG_ERR, "dmc%d: M820 Test Failed\n", unit);
                    909:                return;
                    910:        }
                    911: 
                    912:        /* restart DMC */
                    913:        dmcinit(unit);
                    914:        sc->sc_flag &= ~DMC_RESTART;
                    915:        s = spl5();
                    916:        dmcstart(unit);
                    917:        splx(s);
                    918:        sc->sc_if.if_collisions++;      /* why not? */
                    919: }
                    920: 
                    921: /*
                    922:  * Reset a device and mark down.
                    923:  * Flush output queue and drop queue limit.
                    924:  */
                    925: dmcdown(unit)
                    926:        int unit;
                    927: {
                    928:        register struct dmc_softc *sc = &dmc_softc[unit];
                    929:        register struct ifxmt *ifxp;
                    930: 
                    931:        ((struct dmcdevice *)(dmcinfo[unit]->ui_addr))->bsel1 = DMC_MCLR;
                    932:        sc->sc_flag &= ~(DMC_RUNNING | DMC_ONLINE);
                    933: 
                    934:        for (ifxp = sc->sc_ifw; ifxp < &sc->sc_ifw[NXMT]; ifxp++) {
                    935:                if (ifxp->ifw_xtofree) {
                    936:                        (void) m_freem(ifxp->ifw_xtofree);
                    937:                        ifxp->ifw_xtofree = 0;
                    938:                }
                    939:        }
                    940:        if_qflush(&sc->sc_if.if_snd);
                    941: }
                    942: 
                    943: /*
                    944:  * Watchdog timeout to see that transmitted packets don't
                    945:  * lose interrupts.  The device has to be online (the first
                    946:  * transmission may block until the other side comes up).
                    947:  */
                    948: dmctimeout(unit)
                    949:        int unit;
                    950: {
                    951:        register struct dmc_softc *sc;
                    952:        struct dmcdevice *addr;
                    953: 
                    954:        sc = &dmc_softc[unit];
                    955:        if (sc->sc_flag & DMC_ONLINE) {
                    956:                addr = (struct dmcdevice *)(dmcinfo[unit]->ui_addr);
                    957:                log(LOG_ERR, "dmc%d: output timeout, bsel0=%b bsel2=%b\n",
                    958:                    unit, addr->bsel0 & 0xff, DMC0BITS,
                    959:                    addr->bsel2 & 0xff, DMC2BITS);
                    960:                dmcrestart(unit);
                    961:        }
                    962: }
                    963: #endif

unix.superglobalmegacorp.com

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