Annotation of 42BSD/sys/vaxif/if_vv.c, revision 1.1

1.1     ! root        1: /*     if_vv.c 6.1     83/07/29        */
        !             2: 
        !             3: #include "vv.h"
        !             4: 
        !             5: /*
        !             6:  * Proteon 10 Meg Ring Driver.
        !             7:  * This device is called "vv" because its "real name",
        !             8:  * V2LNI won't work if shortened to the obvious "v2".
        !             9:  * Hence the subterfuge.
        !            10:  *
        !            11:  */
        !            12: #include "../machine/pte.h"
        !            13: 
        !            14: #include "../h/param.h"
        !            15: #include "../h/systm.h"
        !            16: #include "../h/mbuf.h"
        !            17: #include "../h/buf.h"
        !            18: #include "../h/protosw.h"
        !            19: #include "../h/socket.h"
        !            20: #include "../h/vmmac.h"
        !            21: #include "../h/errno.h"
        !            22: #include "../h/time.h"
        !            23: #include "../h/kernel.h"
        !            24: #include "../h/ioctl.h"
        !            25: 
        !            26: #include "../net/if.h"
        !            27: #include "../net/netisr.h"
        !            28: #include "../net/route.h"
        !            29: 
        !            30: #include "../netinet/in.h"
        !            31: #include "../netinet/in_systm.h"
        !            32: #include "../netinet/ip.h"
        !            33: #include "../netinet/ip_var.h"
        !            34: 
        !            35: #include "../vax/mtpr.h"
        !            36: #include "../vax/cpu.h"
        !            37: 
        !            38: #include "../vaxuba/ubareg.h"
        !            39: #include "../vaxuba/ubavar.h"
        !            40: 
        !            41: #include "../vaxif/if_vv.h"
        !            42: #include "../vaxif/if_uba.h"
        !            43: 
        !            44: /*
        !            45:  * N.B. - if WIRECENTER is defined wrong, it can well break
        !            46:  * the hardware!!
        !            47:  */
        !            48: #define        WIRECENTER
        !            49: 
        !            50: #ifdef WIRECENTER
        !            51: #define        VV_CONF VV_HEN          /* drive wire center relay */
        !            52: #else
        !            53: #define        VV_CONF VV_STE          /* allow operation without wire center */
        !            54: #endif
        !            55: 
        !            56: #define        VVMTU   (1024+512)
        !            57: #define VVMRU  (1024+512+16)   /* space for trailer */
        !            58: 
        !            59: int vv_tracehdr = 0,           /* 1 => trace headers (slowly!!) */
        !            60:     vv_tracetimeout = 1;       /* 1 => trace input error-rate limiting */
        !            61:     vv_logreaderrors = 0;      /* 1 => log all read errors */
        !            62: 
        !            63: #define vvtracehdr     if (vv_tracehdr) vvprt_hdr
        !            64: #define        vvtrprintf      if (vv_tracetimeout) printf
        !            65: 
        !            66: int vv_ticking = 0;            /* error flywheel is running */
        !            67: 
        !            68: /*
        !            69:  * Interval in HZ - 50 msec.
        !            70:  * N.B. all times below are in units of flywheel ticks
        !            71:  */
        !            72: #define VV_FLYWHEEL            3
        !            73: #define        VV_ERRORTHRESHOLD       100     /* errors/flywheel-interval */
        !            74: #define        VV_MODE1ATTEMPTS        10      /* number mode 1 retries */
        !            75: #define        VV_MODE1DELAY           2       /* period interface is PAUSEd - 100ms */
        !            76: #define VV_MODE2DELAY          4       /* base interval host relay is off - 200ms */
        !            77: #define        VV_MAXDELAY             6400    /* max interval host relay is off - 2 minutes */
        !            78: 
        !            79: int    vvprobe(), vvattach(), vvrint(), vvxint();
        !            80: struct uba_device *vvinfo[NVV];
        !            81: u_short vvstd[] = { 0 };
        !            82: struct uba_driver vvdriver =
        !            83:        { vvprobe, 0, vvattach, 0, vvstd, "vv", vvinfo };
        !            84: #define        VVUNIT(x)       minor(x)
        !            85: int    vvinit(),vvioctl(),vvoutput(),vvreset();
        !            86: 
        !            87: /*
        !            88:  * Software status of each interface.
        !            89:  *
        !            90:  * Each interface is referenced by a network interface structure,
        !            91:  * vs_if, which the routing code uses to locate the interface.
        !            92:  * This structure contains the output queue for the interface, its address, ...
        !            93:  * We also have, for each interface, a UBA interface structure, which
        !            94:  * contains information about the UNIBUS resources held by the interface:
        !            95:  * map registers, buffered data paths, etc.  Information is cached in this
        !            96:  * structure for use by the if_uba.c routines in running the interface
        !            97:  * efficiently.
        !            98:  */
        !            99: struct vv_softc {
        !           100:        struct  ifnet vs_if;            /* network-visible interface */
        !           101:        struct  ifuba vs_ifuba;         /* UNIBUS resources */
        !           102:        short   vs_oactive;             /* is output active */
        !           103:        short   vs_iactive;             /* is input active */
        !           104:        short   vs_olen;                /* length of last output */
        !           105:        u_short vs_lastx;               /* last destination address */
        !           106:        short   vs_tries;               /* transmit current retry count */
        !           107:        short   vs_init;                /* number of ring inits */
        !           108:        short   vs_nottaken;            /* number of packets refused */
        !           109:        /* input error rate limiting state */
        !           110:        short   vs_major;               /* recovery major state */
        !           111:        short   vs_minor;               /* recovery minor state */
        !           112:        short   vs_retry;               /* recovery retry count */
        !           113:        short   vs_delayclock;          /* recovery delay clock */
        !           114:        short   vs_delayrange;          /* increasing delay interval */
        !           115:        short   vs_dropped;             /* number of packes tossed in last dt */
        !           116: } vv_softc[NVV];
        !           117: 
        !           118: /*
        !           119:  * States of vs_iactive.
        !           120:  */
        !           121: #define        ACTIVE  1               /* interface should post new receives */
        !           122: #define        PAUSE   0               /* interface should NOT post new receives */
        !           123: #define        OPEN    -1              /* PAUSE and open host relay */
        !           124: 
        !           125: /*
        !           126:  * Recovery major states.
        !           127:  */
        !           128: #define        MODE0   0               /* everything is wonderful */
        !           129: #define        MODE1   1               /* hopefully whatever will go away */
        !           130: #define        MODE2   2               /* drastic measures - open host relay for increasing intervals */
        !           131: 
        !           132: vvprobe(reg)
        !           133:        caddr_t reg;
        !           134: {
        !           135:        register int br, cvec;
        !           136:        register struct vvreg *addr = (struct vvreg *)reg;
        !           137: 
        !           138: #ifdef lint
        !           139:        br = 0; cvec = br; br = cvec; vvrint(0);
        !           140: #endif
        !           141:        /* reset interface, enable, and wait till dust settles */
        !           142:        addr->vvicsr = VV_RST;
        !           143:        addr->vvocsr = VV_RST;
        !           144:        DELAY(10000);
        !           145:        /* generate interrupt by doing 1 word DMA from 0 in uba space!! */
        !           146:        addr->vvocsr = VV_IEN;          /* enable interrupt */
        !           147:        addr->vvoba = 0;                /* low 16 bits */
        !           148:        addr->vvoea = 0;                /* extended bits */
        !           149:        addr->vvowc = -1;               /* for 1 word */
        !           150:        addr->vvocsr |= VV_DEN;         /* start the DMA */
        !           151:        DELAY(100000);
        !           152:        addr->vvocsr = 0;
        !           153:        if (cvec && cvec != 0x200)
        !           154:                cvec -= 4;              /* backup so vector => recieve */
        !           155:        return(1);
        !           156: }
        !           157: 
        !           158: /*
        !           159:  * Interface exists: make available by filling in network interface
        !           160:  * record.  System will initialize the interface when it is ready
        !           161:  * to accept packets.
        !           162:  */
        !           163: vvattach(ui)
        !           164:        struct uba_device *ui;
        !           165: {
        !           166:        register struct vv_softc *vs = &vv_softc[ui->ui_unit];
        !           167: 
        !           168:        vs->vs_if.if_unit = ui->ui_unit;
        !           169:        vs->vs_if.if_name = "vv";
        !           170:        vs->vs_if.if_mtu = VVMTU;
        !           171:        vs->vs_if.if_init = vvinit;
        !           172:        vs->vs_if.if_ioctl = vvioctl;
        !           173:        vs->vs_if.if_output = vvoutput;
        !           174:        vs->vs_if.if_reset = vvreset;
        !           175:        vs->vs_ifuba.ifu_flags = UBA_CANTWAIT | UBA_NEEDBDP | UBA_NEED16;
        !           176: #if defined(VAX750)
        !           177:        /* don't chew up 750 bdp's */
        !           178:        if (cpu == VAX_750 && ui->ui_unit > 0)
        !           179:                vs->vs_ifuba.ifu_flags &= ~UBA_NEEDBDP;
        !           180: #endif
        !           181:        if_attach(&vs->vs_if);
        !           182: }
        !           183: 
        !           184: /*
        !           185:  * Reset of interface after UNIBUS reset.
        !           186:  * If interface is on specified uba, reset its state.
        !           187:  */
        !           188: vvreset(unit, uban)
        !           189:        int unit, uban;
        !           190: {
        !           191:        register struct uba_device *ui;
        !           192: 
        !           193:        if (unit >= NVV || (ui = vvinfo[unit]) == 0 || ui->ui_alive == 0 ||
        !           194:            ui->ui_ubanum != uban)
        !           195:                return;
        !           196:        printf(" vv%d", unit);
        !           197:        vvinit(unit);
        !           198: }
        !           199: 
        !           200: /*
        !           201:  * Initialization of interface; clear recorded pending
        !           202:  * operations, and reinitialize UNIBUS usage.
        !           203:  */
        !           204: vvinit(unit)
        !           205:        int unit;
        !           206: {
        !           207:        register struct vv_softc *vs = &vv_softc[unit];
        !           208:        register struct uba_device *ui = vvinfo[unit];
        !           209:        register struct vvreg *addr;
        !           210:        struct sockaddr_in *sin;
        !           211:        int ubainfo, s;
        !           212:        int vvtimeout();
        !           213: 
        !           214:        if (vs->vs_if.if_net == 0)
        !           215:                return;
        !           216:        addr = (struct vvreg *)ui->ui_addr;
        !           217:        if (if_ubainit(&vs->vs_ifuba, ui->ui_ubanum,
        !           218:            sizeof (struct vv_header), (int)btoc(VVMTU)) == 0) { 
        !           219:                printf("vv%d: can't initialize\n", unit);
        !           220:                vs->vs_if.if_flags &= ~IFF_UP;
        !           221:                return;
        !           222:        }
        !           223:        if (vv_ticking++ == 0)
        !           224:                timeout(vvtimeout, (caddr_t) 0, VV_FLYWHEEL);
        !           225:        /*
        !           226:         * Discover our host address and post it
        !           227:         */
        !           228:        vs->vs_if.if_host[0] = vvidentify(unit);
        !           229:        printf("vv%d: host %d\n", unit, vs->vs_if.if_host[0]);
        !           230:        sin = (struct sockaddr_in *)&vs->vs_if.if_addr;
        !           231:        sin->sin_family = AF_INET;
        !           232:        sin->sin_addr = if_makeaddr(vs->vs_if.if_net, vs->vs_if.if_host[0]);
        !           233:        sin = (struct sockaddr_in *)&vs->vs_if.if_broadaddr;
        !           234:        sin->sin_family = AF_INET;
        !           235:        sin->sin_addr = if_makeaddr(vs->vs_if.if_net, VV_BROADCAST);
        !           236: 
        !           237:        /*
        !           238:         * Reset the interface, and join the ring
        !           239:         */
        !           240:        addr->vvocsr = VV_RST | VV_CPB;         /* clear packet buffer */
        !           241:        addr->vvicsr = VV_RST | VV_CONF;        /* close logical relay */
        !           242:        DELAY(500000);                          /* let contacts settle */
        !           243:        vs->vs_init = 0;
        !           244:        vs->vs_dropped = 0;
        !           245:        vs->vs_nottaken = 0;
        !           246: 
        !           247:        /*
        !           248:         * Hang a receive and start any
        !           249:         * pending writes by faking a transmit complete.
        !           250:         */
        !           251:        s = splimp();
        !           252:        ubainfo = vs->vs_ifuba.ifu_r.ifrw_info;
        !           253:        addr->vviba = (u_short)ubainfo;
        !           254:        addr->vviea = (u_short)(ubainfo >> 16);
        !           255:        addr->vviwc = -(sizeof (struct vv_header) + VVMTU) >> 1;
        !           256:        addr->vvicsr = VV_IEN | VV_CONF | VV_DEN | VV_ENB;
        !           257:        vs->vs_iactive = ACTIVE;
        !           258:        vs->vs_oactive = 1;
        !           259:        vs->vs_if.if_flags |= IFF_UP | IFF_RUNNING;
        !           260:        vvxint(unit);
        !           261:        splx(s);
        !           262:        if_rtinit(&vs->vs_if, RTF_UP);
        !           263: }
        !           264: 
        !           265: /*
        !           266:  * vvidentify() - return our host address
        !           267:  */
        !           268: vvidentify(unit)
        !           269:        int unit;
        !           270: {
        !           271:        register struct vv_softc *vs = &vv_softc[unit];
        !           272:        register struct uba_device *ui = vvinfo[unit];
        !           273:        register struct vvreg *addr;
        !           274:        struct mbuf *m;
        !           275:        struct vv_header *v;
        !           276:        int ubainfo, attempts, waitcount;
        !           277: 
        !           278:        /*
        !           279:         * Build a multicast message to identify our address
        !           280:         */
        !           281:        addr = (struct vvreg *)ui->ui_addr;
        !           282:        attempts = 0;           /* total attempts, including bad msg type */
        !           283:        m = m_get(M_DONTWAIT, MT_HEADER);
        !           284:        if (m == NULL)
        !           285:                return (0);
        !           286:        m->m_next = 0;
        !           287:        m->m_off = MMINOFF;
        !           288:        m->m_len = sizeof(struct vv_header);
        !           289:        v = mtod(m, struct vv_header *);
        !           290:        v->vh_dhost = VV_BROADCAST;     /* multicast destination address */
        !           291:        v->vh_shost = 0;                /* will be overwritten with ours */
        !           292:        v->vh_version = RING_VERSION;
        !           293:        v->vh_type = RING_WHOAMI;
        !           294:        v->vh_info = 0;
        !           295:        /* map xmit message into uba */
        !           296:        vs->vs_olen =  if_wubaput(&vs->vs_ifuba, m);
        !           297:        if (vs->vs_ifuba.ifu_flags & UBA_NEEDBDP)
        !           298:                UBAPURGE(vs->vs_ifuba.ifu_uba, vs->vs_ifuba.ifu_w.ifrw_bdp);
        !           299:        /*
        !           300:         * Reset interface, establish Digital Loopback Mode, and
        !           301:         * send the multicast (to myself) with Input Copy enabled.
        !           302:         */
        !           303: retry:
        !           304:        ubainfo = vs->vs_ifuba.ifu_r.ifrw_info;
        !           305:        addr->vvicsr = VV_RST;
        !           306:        addr->vviba = (u_short) ubainfo;
        !           307:        addr->vviea = (u_short) (ubainfo >> 16);
        !           308:        addr->vviwc = -(sizeof (struct vv_header) + VVMTU) >> 1;
        !           309:        addr->vvicsr = VV_STE | VV_DEN | VV_ENB | VV_LPB;
        !           310: 
        !           311:        /* let flag timers fire so ring will initialize */
        !           312:        DELAY(2000000);
        !           313: 
        !           314:        addr->vvocsr = VV_RST | VV_CPB; /* clear packet buffer */
        !           315:        ubainfo = vs->vs_ifuba.ifu_w.ifrw_info;
        !           316:        addr->vvoba = (u_short) ubainfo;
        !           317:        addr->vvoea = (u_short) (ubainfo >> 16);
        !           318:        addr->vvowc = -((vs->vs_olen + 1) >> 1);
        !           319:        addr->vvocsr = VV_CPB | VV_DEN | VV_INR | VV_ENB;
        !           320:        /*
        !           321:         * Wait for receive side to finish.
        !           322:         * Extract source address (which will our own),
        !           323:         * and post to interface structure.
        !           324:         */
        !           325:        DELAY(1000);
        !           326:        for (waitcount = 0; (addr->vvicsr & VV_RDY) == 0; waitcount++) {
        !           327:                if (waitcount < 10) {
        !           328:                        DELAY(1000);
        !           329:                        continue;
        !           330:                }
        !           331:                if (attempts++ >= 10) {
        !           332:                        printf("vv%d: can't initialize\n", unit);
        !           333:                        printf("vvinit loopwait: icsr = %b\n",
        !           334:                                0xffff&(addr->vvicsr), VV_IBITS);
        !           335:                        vs->vs_if.if_flags &= ~IFF_UP;
        !           336:                        return (0);
        !           337:                }
        !           338:                goto retry;
        !           339:        }
        !           340:        if (vs->vs_ifuba.ifu_flags & UBA_NEEDBDP)
        !           341:                UBAPURGE(vs->vs_ifuba.ifu_uba, vs->vs_ifuba.ifu_w.ifrw_bdp);
        !           342:        if (vs->vs_ifuba.ifu_xtofree)
        !           343:                m_freem(vs->vs_ifuba.ifu_xtofree);
        !           344:        if (vs->vs_ifuba.ifu_flags & UBA_NEEDBDP)
        !           345:                UBAPURGE(vs->vs_ifuba.ifu_uba, vs->vs_ifuba.ifu_r.ifrw_bdp);
        !           346:        m = if_rubaget(&vs->vs_ifuba, sizeof(struct vv_header), 0);
        !           347:        if (m != NULL)
        !           348:                m_freem(m);
        !           349:        /*
        !           350:         * Check message type before we believe the source host address
        !           351:         */
        !           352:        v = (struct vv_header *)(vs->vs_ifuba.ifu_r.ifrw_addr);
        !           353:        if (v->vh_type != RING_WHOAMI)
        !           354:                goto retry;
        !           355:        return(v->vh_shost);
        !           356: }
        !           357: 
        !           358: /*
        !           359:  * vvtimeout() - called by timer flywheel to monitor input packet
        !           360:  * discard rate.  Interfaces getting too many errors are shut
        !           361:  * down for a while.  If the condition persists, the interface
        !           362:  * is marked down.
        !           363:  */
        !           364: /*ARGSUSED*/
        !           365: vvtimeout(junk)
        !           366:        int junk;
        !           367: {
        !           368:        register struct vv_softc *vs;
        !           369:        register int i;
        !           370:        register struct vvreg *addr;
        !           371:        int ubainfo;
        !           372: 
        !           373:        timeout(vvtimeout, (caddr_t) 0, VV_FLYWHEEL);
        !           374:        for (i = 0; i < NVV; i++) {
        !           375:                vs = &vv_softc[i];
        !           376:                addr = (struct vvreg *)vvinfo[i]->ui_addr;
        !           377:                if ((vs->vs_if.if_flags & IFF_UP) == 0)
        !           378:                        continue;
        !           379:                switch (vs->vs_major) {
        !           380: 
        !           381:                /*
        !           382:                 * MODE0: generally OK, just check error rate 
        !           383:                 */
        !           384:                case MODE0:
        !           385:                        if (vs->vs_dropped < VV_ERRORTHRESHOLD) {
        !           386:                                vs->vs_dropped = 0;
        !           387:                                continue;
        !           388:                        }
        !           389:                        /* suspend reads for a while */
        !           390:                        vvtrprintf("vv%d going MODE1 in vvtimeout\n",i);
        !           391:                        vs->vs_major = MODE1;
        !           392:                        vs->vs_iactive = PAUSE; /* no new reads */
        !           393:                        vs->vs_retry = VV_MODE1ATTEMPTS;
        !           394:                        vs->vs_delayclock = VV_MODE1DELAY;
        !           395:                        vs->vs_minor = 0;
        !           396:                        continue;
        !           397: 
        !           398:                /*
        !           399:                 * MODE1: excessive error rate observed
        !           400:                 * Scheme: try simply suspending reads for a
        !           401:                 * short while a small number of times
        !           402:                 */
        !           403:                case MODE1:
        !           404:                        if (vs->vs_delayclock > 0) {
        !           405:                                vs->vs_delayclock--;
        !           406:                                continue;
        !           407:                        }
        !           408:                        switch (vs->vs_minor) {
        !           409: 
        !           410:                        case 0:                         /* reenable reads */
        !           411:                                vvtrprintf("vv%d M1m0\n",i);
        !           412:                                vs->vs_dropped = 0;
        !           413:                                vs->vs_iactive = ACTIVE;
        !           414:                                vs->vs_minor = 1;       /* next state */
        !           415:                                ubainfo = vs->vs_ifuba.ifu_r.ifrw_info;
        !           416:                                addr->vviba = (u_short) ubainfo;
        !           417:                                addr->vviea = (u_short) (ubainfo >> 16);
        !           418:                                addr->vviwc =
        !           419:                                  -(sizeof (struct vv_header) + VVMTU) >> 1;
        !           420:                                addr->vvicsr = VV_RST | VV_CONF;
        !           421:                                addr->vvicsr |= VV_IEN | VV_DEN | VV_ENB;
        !           422:                                continue;
        !           423: 
        !           424:                        case 1:                         /* see if it worked */
        !           425:                                vvtrprintf("vv%d M1m1\n",i);
        !           426:                                if (vs->vs_dropped < VV_ERRORTHRESHOLD) {
        !           427:                                        vs->vs_dropped = 0;
        !           428:                                        vs->vs_major = MODE0;   /* yeah!! */
        !           429:                                        continue;
        !           430:                                }
        !           431:                                if (vs->vs_retry -- > 0) {
        !           432:                                        vs->vs_dropped = 0;
        !           433:                                        vs->vs_iactive = PAUSE;
        !           434:                                        vs->vs_delayclock = VV_MODE1DELAY;
        !           435:                                        vs->vs_minor = 0; /* recheck */
        !           436:                                        continue;
        !           437:                                }
        !           438:                                vs->vs_major = MODE2;
        !           439:                                vs->vs_minor = 0;
        !           440:                                vs->vs_dropped = 0;
        !           441:                                vs->vs_iactive = OPEN;
        !           442:                                vs->vs_delayrange = VV_MODE2DELAY;
        !           443:                                vs->vs_delayclock = VV_MODE2DELAY;
        !           444:                                /* fall thru ... */
        !           445:                        }
        !           446: 
        !           447:                /*
        !           448:                 * MODE2: simply ignoring traffic didn't relieve condition
        !           449:                 * Scheme: open host relay for intervals linearly
        !           450:                 * increasing up to some maximum of a several minutes.
        !           451:                 * This allows broken networks to return to operation
        !           452:                 * without rebooting.
        !           453:                 */
        !           454:                case MODE2:
        !           455:                        if (vs->vs_delayclock > 0) {
        !           456:                                vs->vs_delayclock--;
        !           457:                                continue;
        !           458:                        }
        !           459:                        switch (vs->vs_minor) {
        !           460: 
        !           461:                        case 0:         /* close relay and reenable reads */
        !           462:                                vvtrprintf("vv%d M2m0\n",i);
        !           463:                                vs->vs_dropped = 0;
        !           464:                                vs->vs_iactive = ACTIVE;
        !           465:                                vs->vs_minor = 1;       /* next state */
        !           466:                                ubainfo = vs->vs_ifuba.ifu_r.ifrw_info;
        !           467:                                addr->vviba = (u_short) ubainfo;
        !           468:                                addr->vviea = (u_short) (ubainfo >> 16);
        !           469:                                addr->vviwc =
        !           470:                                  -(sizeof (struct vv_header) + VVMTU) >> 1;
        !           471:                                addr->vvicsr = VV_RST | VV_CONF;
        !           472:                                addr->vvicsr |= VV_IEN | VV_DEN | VV_ENB;
        !           473:                                continue;
        !           474: 
        !           475:                        case 1:                         /* see if it worked */
        !           476:                                vvtrprintf("vv%d M2m1\n",i);
        !           477:                                if (vs->vs_dropped < VV_ERRORTHRESHOLD) {
        !           478:                                        vs->vs_dropped = 0;
        !           479:                                        vs->vs_major = MODE0;   /* yeah!! */
        !           480:                                        continue;
        !           481:                                }
        !           482:                                vvtrprintf("vv%d M2m1 ++ delay\n",i);
        !           483:                                vs->vs_dropped = 0;
        !           484:                                vs->vs_iactive = OPEN;
        !           485:                                vs->vs_minor = 0;
        !           486:                                if (vs->vs_delayrange < VV_MAXDELAY)
        !           487:                                        vs->vs_delayrange +=
        !           488:                                          (vs->vs_delayrange/2);
        !           489:                                vs->vs_delayclock = vs->vs_delayrange;
        !           490:                                continue;
        !           491:                        }
        !           492: 
        !           493:                default:
        !           494:                        printf("vv%d: major state screwed\n", i);
        !           495:                        vs->vs_if.if_flags &= ~IFF_UP;
        !           496:                }
        !           497:        }
        !           498: }
        !           499: 
        !           500: /*
        !           501:  * Start or restart output on interface.
        !           502:  * If interface is active, this is a retransmit, so just
        !           503:  * restuff registers and go.
        !           504:  * If interface is not already active, get another datagram
        !           505:  * to send off of the interface queue, and map it to the interface
        !           506:  * before starting the output.
        !           507:  */
        !           508: vvstart(dev)
        !           509:        dev_t dev;
        !           510: {
        !           511:         int unit = VVUNIT(dev);
        !           512:        struct uba_device *ui = vvinfo[unit];
        !           513:        register struct vv_softc *vs = &vv_softc[unit];
        !           514:        register struct vvreg *addr;
        !           515:        struct mbuf *m;
        !           516:        int ubainfo;
        !           517:        int dest;
        !           518: 
        !           519:        if (vs->vs_oactive)
        !           520:                goto restart;
        !           521:        /*
        !           522:         * Not already active: dequeue another request
        !           523:         * and map it to the UNIBUS.  If no more requests,
        !           524:         * just return.
        !           525:         */
        !           526:        IF_DEQUEUE(&vs->vs_if.if_snd, m);
        !           527:        if (m == NULL) {
        !           528:                vs->vs_oactive = 0;
        !           529:                return;
        !           530:        }
        !           531:        dest = mtod(m, struct vv_header *)->vh_dhost;
        !           532:        vs->vs_olen = if_wubaput(&vs->vs_ifuba, m);
        !           533:        vs->vs_lastx = dest;
        !           534: restart:
        !           535:        /*
        !           536:         * Have request mapped to UNIBUS for transmission.
        !           537:         * Purge any stale data from this BDP, and start the otput.
        !           538:         */
        !           539:        if (vs->vs_olen > VVMTU + sizeof (struct vv_header)) {
        !           540:                printf("vv%d vs_olen: %d > VVMTU\n", unit, vs->vs_olen);
        !           541:                panic("vvdriver vs_olen botch");
        !           542:        }
        !           543:        if (vs->vs_ifuba.ifu_flags & UBA_NEEDBDP)
        !           544:                UBAPURGE(vs->vs_ifuba.ifu_uba, vs->vs_ifuba.ifu_w.ifrw_bdp);
        !           545:        addr = (struct vvreg *)ui->ui_addr;
        !           546:        ubainfo = vs->vs_ifuba.ifu_w.ifrw_info;
        !           547:        addr->vvoba = (u_short) ubainfo;
        !           548:        addr->vvoea = (u_short) (ubainfo >> 16);
        !           549:        addr->vvowc = -((vs->vs_olen + 1) >> 1);
        !           550:        addr->vvocsr = VV_IEN | VV_CPB | VV_DEN | VV_INR | VV_ENB;
        !           551:        vs->vs_oactive = 1;
        !           552: }
        !           553: 
        !           554: /*
        !           555:  * VVLNI transmit interrupt
        !           556:  * Start another output if more data to send.
        !           557:  */
        !           558: vvxint(unit)
        !           559:        int unit;
        !           560: {
        !           561:        register struct uba_device *ui = vvinfo[unit];
        !           562:        register struct vv_softc *vs = &vv_softc[unit];
        !           563:        register struct vvreg *addr;
        !           564:        register int oc;
        !           565: 
        !           566:        addr = (struct vvreg *)ui->ui_addr;
        !           567:        oc = 0xffff & (addr->vvocsr);
        !           568:        if (vs->vs_oactive == 0) {
        !           569:                printf("vv%d: stray interrupt vvocsr = %b\n", unit,
        !           570:                        oc, VV_OBITS);
        !           571:                return;
        !           572:        }
        !           573:        if (oc &  (VV_OPT | VV_RFS)) {
        !           574:                vs->vs_if.if_collisions++;
        !           575:                if (vs->vs_tries++ < VVRETRY) {
        !           576:                        if (oc & VV_OPT)
        !           577:                                vs->vs_init++;
        !           578:                        if (oc & VV_RFS)
        !           579:                                vs->vs_nottaken++;
        !           580:                        vvstart(unit);          /* restart this message */
        !           581:                        return;
        !           582:                }
        !           583:                if (oc & VV_OPT)
        !           584:                        printf("vv%d: output timeout\n");
        !           585:        }
        !           586:        vs->vs_if.if_opackets++;
        !           587:        vs->vs_oactive = 0;
        !           588:        vs->vs_tries = 0;
        !           589:        if (oc & VVXERR) {
        !           590:                vs->vs_if.if_oerrors++;
        !           591:                printf("vv%d: error vvocsr = %b\n", unit, 0xffff & oc,
        !           592:                        VV_OBITS);
        !           593:        }
        !           594:        if (vs->vs_ifuba.ifu_xtofree) {
        !           595:                m_freem(vs->vs_ifuba.ifu_xtofree);
        !           596:                vs->vs_ifuba.ifu_xtofree = 0;
        !           597:        }
        !           598:        if (vs->vs_if.if_snd.ifq_head == 0) {
        !           599:                vs->vs_lastx = 256;             /* an invalid address */
        !           600:                return;
        !           601:        }
        !           602:        vvstart(unit);
        !           603: }
        !           604: 
        !           605: /*
        !           606:  * V2lni interface receiver interrupt.
        !           607:  * If input error just drop packet.
        !           608:  * Otherwise purge input buffered data path and examine 
        !           609:  * packet to determine type.  If can't determine length
        !           610:  * from type, then have to drop packet.  Othewise decapsulate
        !           611:  * packet based on type and pass to type specific higher-level
        !           612:  * input routine.
        !           613:  */
        !           614: vvrint(unit)
        !           615:        int unit;
        !           616: {
        !           617:        register struct vv_softc *vs = &vv_softc[unit];
        !           618:        struct vvreg *addr = (struct vvreg *)vvinfo[unit]->ui_addr;
        !           619:        register struct vv_header *vv;
        !           620:        register struct ifqueue *inq;
        !           621:        struct mbuf *m;
        !           622:        int ubainfo, len, off;
        !           623:        short resid;
        !           624: 
        !           625:        vs->vs_if.if_ipackets++;
        !           626:        /*
        !           627:         * Purge BDP; drop if input error indicated.
        !           628:         */
        !           629:        if (vs->vs_ifuba.ifu_flags & UBA_NEEDBDP)
        !           630:                UBAPURGE(vs->vs_ifuba.ifu_uba, vs->vs_ifuba.ifu_r.ifrw_bdp);
        !           631:        if (addr->vvicsr & VVRERR) {
        !           632:                if (vv_logreaderrors)
        !           633:                        printf("vv%d: error vvicsr = %b\n", unit,
        !           634:                                0xffff&(addr->vvicsr), VV_IBITS);
        !           635:                goto dropit;
        !           636:        }
        !           637: 
        !           638:        /*
        !           639:         * Get packet length from word count residue
        !           640:         *
        !           641:         * Compute header offset if trailer protocol
        !           642:         *
        !           643:         * Pull packet off interface.  Off is nonzero if packet
        !           644:         * has trailing header; if_rubaget will then force this header
        !           645:         * information to be at the front.  The vh_info field
        !           646:         * carries the offset to the trailer data in trailer
        !           647:         * format packets.
        !           648:         */
        !           649:        vv = (struct vv_header *)(vs->vs_ifuba.ifu_r.ifrw_addr);
        !           650:        vvtracehdr("vi", vv);
        !           651:        resid = addr->vviwc;
        !           652:        if (resid)
        !           653:                resid |= 0176000;               /* ugly!!!! */
        !           654:        len = (((sizeof (struct vv_header) + VVMRU) >> 1) + resid) << 1;
        !           655:        len -= sizeof(struct vv_header);
        !           656:        if (len > VVMRU || len <= 0)
        !           657:                goto dropit;
        !           658: #define        vvdataaddr(vv, off, type)       ((type)(((caddr_t)((vv)+1)+(off))))
        !           659:        if (vv->vh_type >= RING_IPTrailer &&
        !           660:             vv->vh_type < RING_IPTrailer+RING_IPNTrailer) {
        !           661:                off = (vv->vh_type - RING_IPTrailer) * 512;
        !           662:                if (off > VVMTU)
        !           663:                        goto dropit;
        !           664:                vv->vh_type = *vvdataaddr(vv, off, u_short *);
        !           665:                resid = *(vvdataaddr(vv, off+2, u_short *));
        !           666:                if (off + resid > len)
        !           667:                        goto dropit;
        !           668:                len = off + resid;
        !           669:        } else
        !           670:                off = 0;
        !           671:        if (len == 0)
        !           672:                goto dropit;
        !           673:        m = if_rubaget(&vs->vs_ifuba, len, off);
        !           674:        if (m == NULL)
        !           675:                goto dropit;
        !           676:        if (off) {
        !           677:                m->m_off += 2 * sizeof(u_short);
        !           678:                m->m_len -= 2 * sizeof(u_short);
        !           679:        }
        !           680: 
        !           681:        /*
        !           682:         * Demultiplex on packet type 
        !           683:         */
        !           684:        switch (vv->vh_type) {
        !           685: 
        !           686: #ifdef INET
        !           687:        case RING_IP:
        !           688:                schednetisr(NETISR_IP);
        !           689:                inq = &ipintrq;
        !           690:                break;
        !           691: #endif
        !           692:        default:
        !           693:                printf("vv%d: unknown pkt type 0x%x\n", unit, vv->vh_type);
        !           694:                m_freem(m);
        !           695:                goto setup;
        !           696:        }
        !           697:        if (IF_QFULL(inq)) {
        !           698:                IF_DROP(inq);
        !           699:                m_freem(m);
        !           700:        } else
        !           701:                IF_ENQUEUE(inq, m);
        !           702: setup:
        !           703:        /*
        !           704:         * Check the error rate and start recovery if needed
        !           705:         * this has to go here since the timer flywheel runs at
        !           706:         * a lower ipl and never gets a chance to change the mode
        !           707:         */
        !           708:        if (vs->vs_major == MODE0 && vs->vs_dropped > VV_ERRORTHRESHOLD) {
        !           709:                vvtrprintf("vv%d going MODE1 in vvrint\n",unit);
        !           710:                vs->vs_major = MODE1;
        !           711:                vs->vs_iactive = PAUSE;         /* no new reads */
        !           712:                vs->vs_retry = VV_MODE1ATTEMPTS;
        !           713:                vs->vs_delayclock = VV_MODE1DELAY;
        !           714:                vs->vs_minor = 0;
        !           715:                vs->vs_dropped = 0;
        !           716:        }
        !           717:        switch (vs->vs_iactive) {
        !           718: 
        !           719:        case ACTIVE:            /* Restart the read for next packet */
        !           720:                ubainfo = vs->vs_ifuba.ifu_r.ifrw_info;
        !           721:                addr->vviba = (u_short) ubainfo;
        !           722:                addr->vviea = (u_short) (ubainfo >> 16);
        !           723:                addr->vviwc = -(sizeof (struct vv_header) + VVMTU) >> 1;
        !           724:                addr->vvicsr = VV_RST | VV_CONF;
        !           725:                addr->vvicsr |= VV_IEN | VV_DEN | VV_ENB;
        !           726:                return;
        !           727: 
        !           728:        case PAUSE:             /* requested to not start any new reads */
        !           729:                vs->vs_dropped = 0;
        !           730:                return;
        !           731: 
        !           732:        case OPEN:              /* request to open host relay */
        !           733:                vs->vs_dropped = 0;
        !           734:                addr->vvicsr = 0;
        !           735:                return;
        !           736: 
        !           737:        default:
        !           738:                printf("vv%d: vs_iactive = %d\n", unit, vs->vs_iactive);
        !           739:                return;
        !           740:        }
        !           741:        /*
        !           742:         * Drop packet on floor -- count them!!
        !           743:         */
        !           744: dropit:
        !           745:        vs->vs_if.if_ierrors++;
        !           746:        vs->vs_dropped++;
        !           747:        /*
        !           748:        printf("vv%d: error vvicsr = %b\n", unit,
        !           749:                0xffff&(addr->vvicsr), VV_IBITS);
        !           750:        */
        !           751:        goto setup;
        !           752: }
        !           753: 
        !           754: /*
        !           755:  * V2lni output routine.
        !           756:  * Encapsulate a packet of type family for the local net.
        !           757:  * Use trailer local net encapsulation if enough data in first
        !           758:  * packet leaves a multiple of 512 bytes of data in remainder.
        !           759:  */
        !           760: vvoutput(ifp, m0, dst)
        !           761:        struct ifnet *ifp;
        !           762:        struct mbuf *m0;
        !           763:        struct sockaddr *dst;
        !           764: {
        !           765:        register struct mbuf *m = m0;
        !           766:        register struct vv_header *vv;
        !           767:        register int off;
        !           768:        int type, dest, s, error;
        !           769: 
        !           770:        switch (dst->sa_family) {
        !           771: 
        !           772: #ifdef INET
        !           773:        case AF_INET: {
        !           774:                dest = ((struct sockaddr_in *)dst)->sin_addr.s_addr;
        !           775:                if ((dest = in_lnaof(*((struct in_addr *)&dest))) >= 0x100) {
        !           776:                        error = EPERM;
        !           777:                        goto bad;
        !           778:                }
        !           779:                off = ntohs((u_short)mtod(m, struct ip *)->ip_len) - m->m_len;
        !           780:                if ((ifp->if_flags & IFF_NOTRAILERS) == 0)
        !           781:                if (off > 0 && (off & 0x1ff) == 0 &&
        !           782:                    m->m_off >= MMINOFF + 2 * sizeof (u_short)) {
        !           783:                        type = RING_IPTrailer + (off>>9);
        !           784:                        m->m_off -= 2 * sizeof (u_short);
        !           785:                        m->m_len += 2 * sizeof (u_short);
        !           786:                        *mtod(m, u_short *) = RING_IP;
        !           787:                        *(mtod(m, u_short *) + 1) = m->m_len;
        !           788:                        goto gottrailertype;
        !           789:                }
        !           790:                type = RING_IP;
        !           791:                off = 0;
        !           792:                goto gottype;
        !           793:                }
        !           794: #endif
        !           795:        default:
        !           796:                printf("vv%d: can't handle af%d\n", ifp->if_unit,
        !           797:                        dst->sa_family);
        !           798:                error = EAFNOSUPPORT;
        !           799:                goto bad;
        !           800:        }
        !           801: 
        !           802: gottrailertype:
        !           803:        /*
        !           804:         * Packet to be sent as trailer: move first packet
        !           805:         * (control information) to end of chain.
        !           806:         */
        !           807:        while (m->m_next)
        !           808:                m = m->m_next;
        !           809:        m->m_next = m0;
        !           810:        m = m0->m_next;
        !           811:        m0->m_next = 0;
        !           812:        m0 = m;
        !           813: gottype:
        !           814:        /*
        !           815:         * Add local net header.  If no space in first mbuf,
        !           816:         * allocate another.
        !           817:         */
        !           818:        if (m->m_off > MMAXOFF ||
        !           819:            MMINOFF + sizeof (struct vv_header) > m->m_off) {
        !           820:                m = m_get(M_DONTWAIT, MT_HEADER);
        !           821:                if (m == NULL) {
        !           822:                        error = ENOBUFS;
        !           823:                        goto bad;
        !           824:                }
        !           825:                m->m_next = m0;
        !           826:                m->m_off = MMINOFF;
        !           827:                m->m_len = sizeof (struct vv_header);
        !           828:        } else {
        !           829:                m->m_off -= sizeof (struct vv_header);
        !           830:                m->m_len += sizeof (struct vv_header);
        !           831:        }
        !           832:        vv = mtod(m, struct vv_header *);
        !           833:        vv->vh_shost = ifp->if_host[0];
        !           834:        vv->vh_dhost = dest;
        !           835:        vv->vh_version = RING_VERSION;
        !           836:        vv->vh_type = type;
        !           837:        vv->vh_info = off;
        !           838:        vvtracehdr("vo", vv);
        !           839: 
        !           840:        /*
        !           841:         * Queue message on interface, and start output if interface
        !           842:         * not yet active.
        !           843:         */
        !           844:        s = splimp();
        !           845:        if (IF_QFULL(&ifp->if_snd)) {
        !           846:                IF_DROP(&ifp->if_snd);
        !           847:                error = ENOBUFS;
        !           848:                goto qfull;
        !           849:        }
        !           850:        IF_ENQUEUE(&ifp->if_snd, m);
        !           851:        if (vv_softc[ifp->if_unit].vs_oactive == 0)
        !           852:                vvstart(ifp->if_unit);
        !           853:        splx(s);
        !           854:        return (0);
        !           855: qfull:
        !           856:        m0 = m;
        !           857:        splx(s);
        !           858: bad:
        !           859:        m_freem(m0);
        !           860:        return(error);
        !           861: }
        !           862: 
        !           863: /*
        !           864:  * Process an ioctl request.
        !           865:  */
        !           866: vvioctl(ifp, cmd, data)
        !           867:        register struct ifnet *ifp;
        !           868:        int cmd;
        !           869:        caddr_t data;
        !           870: {
        !           871:        struct ifreq *ifr = (struct ifreq *)data;
        !           872:        int s = splimp(), error = 0;
        !           873: 
        !           874:        switch (cmd) {
        !           875: 
        !           876:        case SIOCSIFADDR:
        !           877:                /* too difficult to change addr while running */
        !           878:                if ((ifp->if_flags & IFF_RUNNING) == 0) {
        !           879:                        struct sockaddr_in *sin =
        !           880:                            (struct sockaddr_in *)&ifr->ifr_addr;
        !           881:                        ifp->if_net = in_netof(sin->sin_addr);
        !           882:                        vvinit(ifp->if_unit);
        !           883:                } else
        !           884:                        error = EINVAL;
        !           885:                break;
        !           886: 
        !           887:        default:
        !           888:                error = EINVAL;
        !           889:        }
        !           890:        splx(s);
        !           891:        return (error);
        !           892: }
        !           893: 
        !           894: /*
        !           895:  * vvprt_hdr(s, v) print the local net header in "v"
        !           896:  *     with title is "s"
        !           897:  */
        !           898: vvprt_hdr(s, v)
        !           899:        char *s;
        !           900:        register struct vv_header *v;
        !           901: {
        !           902:        printf("%s: dsvti: 0x%x 0x%x 0x%x 0x%x 0x%x\n",
        !           903:                s,
        !           904:                0xff & (int)(v->vh_dhost), 0xff & (int)(v->vh_shost),
        !           905:                0xff & (int)(v->vh_version), 0xff & (int)(v->vh_type),
        !           906:                0xffff & (int)(v->vh_info));
        !           907: }
        !           908: 
        !           909: #ifdef notdef
        !           910: /*
        !           911:  * print "l" hex bytes starting at "s"
        !           912:  */
        !           913: vvprt_hex(s, l) 
        !           914:        char *s;
        !           915:        int l;
        !           916: {
        !           917:        register int i;
        !           918:        register int z;
        !           919: 
        !           920:        for (i=0 ; i < l; i++) {
        !           921:                z = 0xff & (int)(*(s + i));
        !           922:                printf("%c%c ",
        !           923:                "0123456789abcdef"[(z >> 4) & 0x0f],
        !           924:                "0123456789abcdef"[z & 0x0f]
        !           925:                );
        !           926:        }
        !           927: }
        !           928: #endif

unix.superglobalmegacorp.com

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