Annotation of 42BSD/sys/vaxif/if_vv.c, revision 1.1.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.