131908Skarels /* 2*34529Skarels * @(#)if_dmv.c 7.3 (Berkeley) 05/27/88 331908Skarels * DMV-11 Driver 431908Skarels * 531908Skarels * Qbus Sync DDCMP interface - DMV operated in full duplex, point to point mode 631908Skarels * 731908Skarels * Derived from 4.3 release if_dmv.c rev. 6.12 dated 4/23/86 831908Skarels * (which wasn't the 4.3 release!) 931908Skarels * 1031908Skarels * Bob Kridle 1131908Skarels * mt Xinu 1231908Skarels */ 1331908Skarels 1431908Skarels #include "dmv.h" 1531908Skarels #if NDMV > 0 1631908Skarels 1731908Skarels #include "param.h" 1831908Skarels #include "systm.h" 1931908Skarels #include "mbuf.h" 2031908Skarels #include "buf.h" 2131908Skarels #include "ioctl.h" /* must precede tty.h */ 2231908Skarels #include "tty.h" 2331908Skarels #include "protosw.h" 2431908Skarels #include "socket.h" 2531908Skarels #include "syslog.h" 2631908Skarels #include "vmmac.h" 2731908Skarels #include "errno.h" 28*34529Skarels #include "time.h" 29*34529Skarels #include "kernel.h" 3031908Skarels 3131908Skarels #include "../net/if.h" 3231908Skarels #include "../net/netisr.h" 3331908Skarels #include "../net/route.h" 3431908Skarels 3531908Skarels #ifdef INET 3631908Skarels #include "../netinet/in.h" 3731908Skarels #include "../netinet/in_systm.h" 3831908Skarels #include "../netinet/in_var.h" 3931908Skarels #include "../netinet/ip.h" 4031908Skarels #endif 4131908Skarels 4231908Skarels #include "../vax/cpu.h" 4331908Skarels #include "../vax/mtpr.h" 44*34529Skarels #include "../vax/pte.h" 45*34529Skarels #include "../vaxuba/ubareg.h" 46*34529Skarels #include "../vaxuba/ubavar.h" 4731908Skarels #include "if_uba.h" 4831908Skarels #include "if_dmv.h" 4931908Skarels 5031908Skarels int dmv_timeout = 8; /* timeout value */ 5131908Skarels 5231908Skarels /* 5331908Skarels * Driver information for auto-configuration stuff. 5431908Skarels */ 5531908Skarels int dmvprobe(), dmvattach(), dmvinit(), dmvioctl(); 56*34529Skarels int dmvoutput(), dmvreset(), dmvtimeout(); 5731908Skarels struct uba_device *dmvinfo[NDMV]; 5831908Skarels u_short dmvstd[] = { 0 }; 5931908Skarels struct uba_driver dmvdriver = 6031908Skarels { dmvprobe, 0, dmvattach, 0, dmvstd, "dmv", dmvinfo }; 6131908Skarels 6231908Skarels /* 6331908Skarels * Don't really know how many buffers/commands can be queued to a DMV-11. 6431908Skarels * Manual doesn't say... Perhaps we can look at a DEC driver some day. 65*34529Skarels * These numbers ame from DMC/DMR driver. 6631908Skarels */ 6731908Skarels #define NRCV 5 6831908Skarels #define NXMT 3 6931908Skarels #define NCMDS (NRCV+NXMT+4) /* size of command queue */ 7031908Skarels 71*34529Skarels #ifdef DEBUG 72*34529Skarels #define printd(f) if (sc->sc_if.if_flags & IFF_DEBUG) \ 73*34529Skarels printf("DMVDEBUG: dmv%d: ", unit), printf(f) 74*34529Skarels #else 75*34529Skarels #define printd(f) /* nil */ 76*34529Skarels #endif 7731908Skarels 7831908Skarels /* error reporting intervals */ 7931908Skarels 8031908Skarels #define DMV_RPRTE 1 8131908Skarels #define DMV_RPTTE 1 8231908Skarels #define DMV_RPSTE 1 8331908Skarels #define DMV_RPNXM 1 8431908Skarels #define DMV_RPMODD 1 8531908Skarels #define DMV_RPQOVF 1 8631908Skarels #define DMV_RPCXRL 1 8731908Skarels 8831909Skarels /* number of errors to accept before trying a reset */ 8931909Skarels #define DMV_RPUNKNOWN 10 9031909Skarels 9131908Skarels struct dmv_command { 9231908Skarels u_char qp_mask; /* Which registers to set up */ 9331908Skarels #define QP_TRIB 0x01 9431908Skarels #define QP_SEL4 0x02 9531908Skarels #define QP_SEL6 0x04 9631908Skarels #define QP_SEL10 0x08 9731908Skarels u_char qp_cmd; 9831908Skarels u_char qp_tributary; 9931908Skarels u_short qp_sel4; 10031908Skarels u_short qp_sel6; 10131908Skarels u_short qp_sel10; 10231908Skarels struct dmv_command *qp_next; /* next command on queue */ 10331908Skarels }; 10431908Skarels 10531908Skarels #define qp_lowbufaddr qp_ 10631908Skarels 10731908Skarels struct dmvbufs { 10831908Skarels int ubinfo; /* from uballoc */ 10931908Skarels short cc; /* buffer size */ 11031908Skarels short flags; /* access control */ 11131908Skarels }; 11231908Skarels 11331908Skarels #define DBUF_OURS 0 /* buffer is available */ 11431908Skarels #define DBUF_DMVS 1 /* buffer claimed by somebody */ 11531908Skarels #define DBUF_XMIT 4 /* transmit buffer */ 11631908Skarels #define DBUF_RCV 8 /* receive buffer */ 11731908Skarels 11831908Skarels 11931908Skarels /* 12031908Skarels * DMV software status per interface. 12131908Skarels * 12231908Skarels * Each interface is referenced by a network interface structure, 12331908Skarels * sc_if, which the routing code uses to locate the interface. 12431908Skarels * This structure contains the output queue for the interface, its address, ... 12531908Skarels * We also have, for each interface, a set of 7 UBA interface structures 12631908Skarels * for each, which 12731908Skarels * contain information about the UNIBUS resources held by the interface: 12831908Skarels * map registers, buffered data paths, etc. Information is cached in this 12931908Skarels * structure for use by the if_uba.c routines in running the interface 13031908Skarels * efficiently. 13131908Skarels */ 13231908Skarels struct dmv_softc { 13331908Skarels struct ifnet sc_if; /* network-visible interface */ 13431908Skarels short sc_oused; /* output buffers currently in use */ 13531908Skarels short sc_iused; /* input buffers given to DMV */ 13631908Skarels short sc_flag; /* flags */ 13731908Skarels int sc_ubinfo; /* UBA mapping info for base table */ 13831908Skarels int sc_errors[8]; /* error counters */ 13931908Skarels #define sc_rte sc_errors[0] /* receive threshhold error */ 14031908Skarels #define sc_xte sc_errors[1] /* xmit threshhold error */ 14131908Skarels #define sc_ste sc_errors[2] /* select threshhold error */ 14231908Skarels #define sc_nxm sc_errors[3] /* non-existant memory */ 14331908Skarels #define sc_modd sc_errors[4] /* modem disconnect */ 14431908Skarels #define sc_qovf sc_errors[5] /* command/response queue overflow */ 14531908Skarels #define sc_cxrl sc_errors[6] /* carrier loss */ 14631908Skarels #define sc_unknown sc_errors[7] /* other errors - look in DMV manual */ 147*34529Skarels struct dmvbufs sc_rbufs[NRCV]; /* receive buffer info */ 148*34529Skarels struct dmvbufs sc_xbufs[NXMT]; /* transmit buffer info */ 149*34529Skarels struct ifubinfo sc_ifuba; /* UNIBUS resources */ 150*34529Skarels struct ifrw sc_ifr[NRCV]; /* UNIBUS receive buffer maps */ 151*34529Skarels struct ifxmt sc_ifw[NXMT]; /* UNIBUS receive buffer maps */ 15231908Skarels /* command queue stuff */ 15331908Skarels struct dmv_command sc_cmdbuf[NCMDS]; 15431908Skarels struct dmv_command *sc_qhead; /* head of command queue */ 15531908Skarels struct dmv_command *sc_qtail; /* tail of command queue */ 15631908Skarels struct dmv_command *sc_qactive; /* command in progress */ 15731908Skarels struct dmv_command *sc_qfreeh; /* head of list of free cmd buffers */ 15831908Skarels struct dmv_command *sc_qfreet; /* tail of list of free cmd buffers */ 15931908Skarels /* end command queue stuff */ 16031908Skarels } dmv_softc[NDMV]; 16131908Skarels 16231908Skarels /* flags */ 163*34529Skarels #define DMV_RESTART 0x01 /* software restart in progress */ 164*34529Skarels #define DMV_ONLINE 0x02 /* device managed to transmit */ 165*34529Skarels #define DMV_RUNNING 0x04 /* device initialized */ 16631908Skarels 16731908Skarels 16831908Skarels /* queue manipulation macros */ 16931908Skarels #define QUEUE_AT_HEAD(qp, head, tail) \ 17031908Skarels (qp)->qp_next = (head); \ 17131908Skarels (head) = (qp); \ 17231908Skarels if ((tail) == (struct dmv_command *) 0) \ 17331908Skarels (tail) = (head) 17431908Skarels 17531908Skarels #define QUEUE_AT_TAIL(qp, head, tail) \ 17631908Skarels if ((tail)) \ 17731908Skarels (tail)->qp_next = (qp); \ 17831908Skarels else \ 17931908Skarels (head) = (qp); \ 18031908Skarels (qp)->qp_next = (struct dmv_command *) 0; \ 18131908Skarels (tail) = (qp) 18231908Skarels 18331908Skarels #define DEQUEUE(head, tail) \ 18431908Skarels (head) = (head)->qp_next;\ 18531908Skarels if ((head) == (struct dmv_command *) 0)\ 18631908Skarels (tail) = (head) 18731908Skarels 18831908Skarels dmvprobe(reg) 18931908Skarels caddr_t reg; 19031908Skarels { 19131908Skarels register int br, cvec; 19231908Skarels register struct dmvdevice *addr = (struct dmvdevice *)reg; 19331908Skarels register int i; 19431908Skarels 19531908Skarels #ifdef lint 19631908Skarels br = 0; cvec = br; br = cvec; 19731908Skarels dmvrint(0); dmvxint(0); 19831908Skarels #endif 19931908Skarels addr->bsel1 = DMV_MCLR; 20031908Skarels for (i = 100000; i && (addr->bsel1 & DMV_RUN) == 0; i--) 20131908Skarels ; 20231908Skarels if ((addr->bsel1 & DMV_RUN) == 0) { 20331908Skarels printf("dmvprobe: can't start device\n" ); 20431908Skarels return (0); 20531908Skarels } 20631908Skarels if ((addr->bsel4 != 033) || (addr->bsel6 != 0305)) 20731908Skarels { 20831908Skarels printf("dmvprobe: device init failed, bsel4=%o, bsel6=%o\n", 20931908Skarels addr->bsel4, addr->bsel6); 21031908Skarels return (0); 21131908Skarels } 21231908Skarels addr->bsel0 = DMV_RQI|DMV_IEI|DMV_IEO; 21331908Skarels DELAY(1000000); 21431908Skarels addr->bsel1 = DMV_MCLR; 21531908Skarels for (i = 100000; i && (addr->bsel1 & DMV_RUN) == 0; i--) 21631908Skarels ; 217*34529Skarels br = 0x15; /* screwy interrupt structure */ 21831908Skarels return (1); 21931908Skarels } 22031908Skarels 22131908Skarels /* 22231908Skarels * Interface exists: make available by filling in network interface 22331908Skarels * record. System will initialize the interface when it is ready 22431908Skarels * to accept packets. 22531908Skarels */ 22631908Skarels dmvattach(ui) 22731908Skarels register struct uba_device *ui; 22831908Skarels { 22931908Skarels register struct dmv_softc *sc = &dmv_softc[ui->ui_unit]; 23031908Skarels 23131908Skarels sc->sc_if.if_unit = ui->ui_unit; 23231908Skarels sc->sc_if.if_name = "dmv"; 23331908Skarels sc->sc_if.if_mtu = DMVMTU; 23431908Skarels sc->sc_if.if_init = dmvinit; 23531908Skarels sc->sc_if.if_output = dmvoutput; 23631908Skarels sc->sc_if.if_ioctl = dmvioctl; 23731908Skarels sc->sc_if.if_reset = dmvreset; 238*34529Skarels sc->sc_if.if_watchdog = dmvtimeout; 23931908Skarels sc->sc_if.if_flags = IFF_POINTOPOINT; 24031908Skarels sc->sc_ifuba.iff_flags = UBA_CANTWAIT; 24131908Skarels 24231908Skarels if_attach(&sc->sc_if); 24331908Skarels } 24431908Skarels 24531908Skarels /* 24631908Skarels * Reset of interface after UNIBUS reset. 24731908Skarels * If interface is on specified UBA, reset its state. 24831908Skarels */ 24931908Skarels dmvreset(unit, uban) 25031908Skarels int unit, uban; 25131908Skarels { 25231908Skarels register struct uba_device *ui; 25331908Skarels register struct dmv_softc *sc = &dmv_softc[unit]; 25431908Skarels 25531908Skarels if (unit >= NDMV || (ui = dmvinfo[unit]) == 0 || ui->ui_alive == 0 || 25631908Skarels ui->ui_ubanum != uban) 25731908Skarels return; 25831908Skarels printf(" dmv%d", unit); 25931908Skarels sc->sc_flag = 0; 26031908Skarels sc->sc_if.if_flags &= ~IFF_RUNNING; 26131908Skarels dmvinit(unit); 26231908Skarels } 26331908Skarels 26431908Skarels /* 26531908Skarels * Initialization of interface; reinitialize UNIBUS usage. 26631908Skarels */ 26731908Skarels dmvinit(unit) 26831908Skarels int unit; 26931908Skarels { 27031908Skarels register struct dmv_softc *sc = &dmv_softc[unit]; 27131908Skarels register struct uba_device *ui = dmvinfo[unit]; 27231908Skarels register struct dmvdevice *addr; 27331908Skarels register struct ifnet *ifp = &sc->sc_if; 27431908Skarels register struct ifrw *ifrw; 27531908Skarels register struct ifxmt *ifxp; 27631908Skarels register struct dmvbufs *rp; 27731908Skarels register struct dmv_command *qp; 27831908Skarels struct ifaddr *ifa; 27931908Skarels int base; 28031908Skarels int s; 28131908Skarels 28231908Skarels addr = (struct dmvdevice *)ui->ui_addr; 28331908Skarels 28431908Skarels /* 28531908Skarels * Check to see that an address has been set 28631908Skarels * (both local and destination for an address family). 28731908Skarels */ 28831908Skarels for (ifa = ifp->if_addrlist; ifa; ifa = ifa->ifa_next) 28931908Skarels if (ifa->ifa_addr.sa_family && ifa->ifa_dstaddr.sa_family) 29031908Skarels break; 29131908Skarels if (ifa == (struct ifaddr *) 0) 29231908Skarels return; 29331908Skarels 29431908Skarels if ((addr->bsel1&DMV_RUN) == 0) { 29531908Skarels log(LOG_CRIT, "dmvinit: dmv%d not running\n", unit); 29631908Skarels ifp->if_flags &= ~IFF_UP; 29731908Skarels return; 29831908Skarels } 299*34529Skarels printd(("dmvinit\n")); 30031908Skarels /* initialize UNIBUS resources */ 30131908Skarels sc->sc_iused = sc->sc_oused = 0; 30231908Skarels if ((ifp->if_flags & IFF_RUNNING) == 0) { 30331908Skarels if (if_ubaminit( 30431908Skarels &sc->sc_ifuba, 30531908Skarels ui->ui_ubanum, 30631908Skarels sizeof(struct dmv_header), 30731908Skarels (int)btoc(DMVMTU), 30831908Skarels sc->sc_ifr, 30931908Skarels NRCV, 31031908Skarels sc->sc_ifw, 31131908Skarels NXMT 31231908Skarels ) == 0) { 31331908Skarels log(LOG_CRIT, "dmvinit: dmv%d can't allocate uba resources\n", unit); 31431908Skarels ifp->if_flags &= ~IFF_UP; 31531908Skarels return; 31631908Skarels } 31731908Skarels ifp->if_flags |= IFF_RUNNING; 31831908Skarels } 319*34529Skarels /* 320*34529Skarels * Limit packets enqueued until we see if we're on the air. 321*34529Skarels */ 322*34529Skarels ifp->if_snd.ifq_maxlen = 3; 32331908Skarels 324*34529Skarels 32531908Skarels /* initialize buffer pool */ 32631908Skarels /* receives */ 32731908Skarels ifrw = &sc->sc_ifr[0]; 32831908Skarels for (rp = &sc->sc_rbufs[0]; rp < &sc->sc_rbufs[NRCV]; rp++) { 32931908Skarels rp->ubinfo = ifrw->ifrw_info & 0x3ffff; 33031908Skarels rp->cc = DMVMTU + sizeof (struct dmv_header); 33131908Skarels rp->flags = DBUF_OURS|DBUF_RCV; 33231908Skarels ifrw++; 33331908Skarels } 33431908Skarels /* transmits */ 33531908Skarels ifxp = &sc->sc_ifw[0]; 33631908Skarels for (rp = &sc->sc_xbufs[0]; rp < &sc->sc_xbufs[NXMT]; rp++) { 33731908Skarels rp->ubinfo = ifxp->ifw_info & 0x3ffff; 33831908Skarels rp->cc = 0; 33931908Skarels rp->flags = DBUF_OURS|DBUF_XMIT; 34031908Skarels ifxp++; 34131908Skarels } 34231908Skarels 34331908Skarels /* set up command queues */ 34431908Skarels sc->sc_qfreeh = sc->sc_qfreet 34531908Skarels = sc->sc_qhead = sc->sc_qtail = sc->sc_qactive = 34631908Skarels (struct dmv_command *)0; 34731908Skarels /* set up free command buffer list */ 34831908Skarels for (qp = &sc->sc_cmdbuf[0]; qp < &sc->sc_cmdbuf[NCMDS]; qp++) { 34931908Skarels QUEUE_AT_HEAD(qp, sc->sc_qfreeh, sc->sc_qfreet); 35031908Skarels } 35131908Skarels if(sc->sc_flag & DMV_RUNNING) 35231908Skarels dmvload( sc, DMV_CNTRLI, (QP_TRIB|QP_SEL6), 1, 0, DMV_REQHS,0); 35331908Skarels else 35431908Skarels dmvload( sc, DMV_CNTRLI, (QP_TRIB|QP_SEL6), 1, 0, DMV_ESTTRIB,0); 35531908Skarels dmvload( sc, DMV_CNTRLI, (QP_TRIB|QP_SEL6), 1, 0, DMV_REQSUS,0); 35631908Skarels sc->sc_flag |= (DMV_RESTART|DMV_RUNNING); 357*34529Skarels sc->sc_flag &= ~DMV_ONLINE; 35831908Skarels addr->bsel0 |= DMV_IEO; 35931908Skarels } 36031908Skarels 36131908Skarels /* 36231908Skarels * Start output on interface. Get another datagram 36331908Skarels * to send from the interface queue and map it to 36431908Skarels * the interface before starting output. 36531908Skarels * 36631908Skarels * Must be called at spl 5 36731908Skarels */ 36831908Skarels dmvstart(dev) 36931908Skarels dev_t dev; 37031908Skarels { 37131908Skarels int unit = minor(dev); 37231908Skarels register struct dmv_softc *sc = &dmv_softc[unit]; 37331908Skarels struct mbuf *m; 37431908Skarels register struct dmvbufs *rp; 37531908Skarels register int n; 37631908Skarels 37731908Skarels /* 37831908Skarels * Dequeue up to NXMT requests and map them to the UNIBUS. 37931908Skarels * If no more requests, or no dmv buffers available, just return. 38031908Skarels */ 381*34529Skarels printd(("dmvstart\n")); 38231908Skarels n = 0; 38331908Skarels for (rp = &sc->sc_xbufs[0]; rp < &sc->sc_xbufs[NXMT]; rp++ ) { 38431908Skarels /* find an available buffer */ 38531908Skarels if ((rp->flags & DBUF_DMVS) == 0) { 38631908Skarels IF_DEQUEUE(&sc->sc_if.if_snd, m); 38731908Skarels if (m == 0) 38831908Skarels return; 38931908Skarels /* mark it dmvs */ 39031908Skarels rp->flags |= (DBUF_DMVS); 39131908Skarels /* 39231908Skarels * Have request mapped to UNIBUS for transmission 39331908Skarels * and start the output. 39431908Skarels */ 39531908Skarels rp->cc = if_ubaput(&sc->sc_ifuba, &sc->sc_ifw[n], m); 396*34529Skarels if (++sc->sc_oused == 1) 397*34529Skarels sc->sc_if.if_timer = dmv_timeout; 39831908Skarels dmvload( 39931908Skarels sc, 40031908Skarels DMV_BACCX, 40131908Skarels QP_TRIB|QP_SEL4|QP_SEL6|QP_SEL10, 40231908Skarels 1, 40331908Skarels rp->ubinfo, 40431908Skarels (rp->ubinfo>>16)&0x3f, 40531908Skarels rp->cc 40631908Skarels ); 40731908Skarels } 40831908Skarels n++; 40931908Skarels } 41031908Skarels } 41131908Skarels 41231908Skarels /* 41331908Skarels * Utility routine to load the DMV device registers. 41431908Skarels */ 41531908Skarels dmvload(sc, cmd, mask, tributary, sel4, sel6, sel10) 41631908Skarels register struct dmv_softc *sc; 41731908Skarels u_char cmd, tributary, mask; 41831908Skarels u_short sel4, sel6, sel10; 41931908Skarels { 42031908Skarels register struct dmvdevice *addr; 42131908Skarels register int unit, sps; 42231908Skarels register struct dmv_command *qp; 42331908Skarels 42431908Skarels unit = sc - dmv_softc; 425*34529Skarels printd(("dmvload: cmd=%x mask=%x trib=%x sel4=%x sel6=%x sel10=%x\n", 42631908Skarels (unsigned) cmd, 42731908Skarels (unsigned) mask, 42831908Skarels (unsigned) tributary, 42931908Skarels (unsigned) sel4, 43031908Skarels (unsigned) sel6, 43131908Skarels (unsigned) sel10 432*34529Skarels )); 43331908Skarels addr = (struct dmvdevice *)dmvinfo[unit]->ui_addr; 43431908Skarels sps = spl5(); 43531908Skarels 43631908Skarels /* grab a command buffer from the free list */ 43731908Skarels if ((qp = sc->sc_qfreeh) == (struct dmv_command *)0) 43831908Skarels panic("dmv command queue overflow"); 43931908Skarels DEQUEUE(sc->sc_qfreeh, sc->sc_qfreet); 44031908Skarels 44131908Skarels /* fill in requested info */ 44231908Skarels qp->qp_cmd = cmd; 44331908Skarels qp->qp_mask = mask; 44431908Skarels qp->qp_tributary = tributary; 44531908Skarels qp->qp_sel4 = sel4; 44631908Skarels qp->qp_sel6 = sel6; 44731908Skarels qp->qp_sel10 = sel10; 44831908Skarels 44931908Skarels if (sc->sc_qactive) { /* command in progress */ 45031908Skarels if (cmd == DMV_BACCR) { /* supply read buffers first */ 45131908Skarels QUEUE_AT_HEAD(qp, sc->sc_qhead, sc->sc_qtail); 45231908Skarels } else { 45331908Skarels QUEUE_AT_TAIL(qp, sc->sc_qhead, sc->sc_qtail); 45431908Skarels } 45531908Skarels } else { /* command port free */ 45631908Skarels sc->sc_qactive = qp; 45731908Skarels addr->bsel0 = (DMV_RQI|DMV_IEI|DMV_IEO); 45831908Skarels } 45931908Skarels splx(sps); 46031908Skarels } 46131908Skarels /* 46231908Skarels * DMV interface input interrupt. 46331908Skarels * Ready to accept another command, 46431908Skarels * pull one off the command queue. 46531908Skarels */ 46631908Skarels dmvrint(unit) 46731908Skarels int unit; 46831908Skarels { 46931908Skarels register struct dmv_softc *sc; 47031908Skarels register struct dmvdevice *addr; 47131908Skarels register struct dmv_command *qp; 47231908Skarels register int n; 47331908Skarels 47431908Skarels addr = (struct dmvdevice *)dmvinfo[unit]->ui_addr; 47531908Skarels sc = &dmv_softc[unit]; 476*34529Skarels printd(("dmvrint\n")); 47731908Skarels if ((qp = sc->sc_qactive) == (struct dmv_command *) 0) { 47831908Skarels log(LOG_WARNING, "dmvrint: dmv%d no command\n", unit); 47931908Skarels return; 48031908Skarels } 48131908Skarels while (addr->bsel2&DMV_RDI) { 48231908Skarels if(qp->qp_mask&QP_SEL4) 48331908Skarels addr->wsel4 = qp->qp_sel4; 48431908Skarels if(qp->qp_mask&QP_SEL6) 48531908Skarels addr->wsel6 = qp->qp_sel6; 48631908Skarels if(qp->qp_mask&QP_SEL10) { 48731908Skarels addr->wsel10 = qp->qp_sel10; 48831908Skarels qp->qp_cmd |= DMV_22BIT; 48931908Skarels } 49031908Skarels if(qp->qp_mask&QP_TRIB) 49131908Skarels addr->wsel2 = qp->qp_cmd|(qp->qp_tributary << 8); 49231908Skarels else 49331908Skarels addr->bsel2 = qp->qp_cmd; 49431908Skarels QUEUE_AT_HEAD(qp, sc->sc_qfreeh, sc->sc_qfreet); 49531908Skarels if ((sc->sc_qactive = sc->sc_qhead) == (struct dmv_command *)0) 49631908Skarels break; 49731908Skarels qp = sc->sc_qactive; 49831908Skarels DEQUEUE(sc->sc_qhead, sc->sc_qtail); 49931908Skarels if (addr->bsel2&DMV_RDO) 50031908Skarels break; 50131908Skarels } 50231908Skarels if (!sc->sc_qactive) { 50331908Skarels if(addr->bsel2&DMV_RDI) { 50431908Skarels /* clear RQI prior to last command per DMV manual */ 50531908Skarels addr->bsel0 &= ~DMV_RQI; 50631908Skarels addr->wsel6 = DMV_NOP; 50731908Skarels addr->bsel2 = DMV_CNTRLI; 50831908Skarels } 50931908Skarels addr->bsel0 = DMV_IEO; 51031908Skarels } 51131908Skarels else /* RDO set or DMV still holding CSR */ 51231908Skarels addr->bsel0 = (DMV_RQI|DMV_IEI|DMV_IEO); 51331908Skarels 51431908Skarels } 51531908Skarels 51631908Skarels /* 51731908Skarels * DMV interface output interrupt. 51831908Skarels * A transfer may have completed, check for errors. 51931908Skarels * If it was a read, notify appropriate protocol. 52031908Skarels * If it was a write, pull the next one off the queue. 52131908Skarels */ 52231908Skarels dmvxint(unit) 52331908Skarels int unit; 52431908Skarels { 52531908Skarels register struct dmv_softc *sc; 52631908Skarels register struct ifnet *ifp; 52731908Skarels struct uba_device *ui = dmvinfo[unit]; 52831908Skarels struct dmvdevice *addr; 52931908Skarels struct mbuf *m; 53031908Skarels struct ifqueue *inq; 53131908Skarels int sel2, sel3, sel4, sel6, sel10, pkaddr, len, s; 53231908Skarels register struct ifrw *ifrw; 53331908Skarels register struct dmvbufs *rp; 53431908Skarels register struct ifxmt *ifxp; 53531908Skarels struct dmv_header *dh; 536*34529Skarels int off, resid; 53731908Skarels 53831908Skarels addr = (struct dmvdevice *)ui->ui_addr; 53931908Skarels sc = &dmv_softc[unit]; 54031908Skarels ifp = &sc->sc_if; 54131908Skarels 54231908Skarels while (addr->bsel2 & DMV_RDO) { 54331908Skarels 54431908Skarels sel2 = addr->bsel2; 54531908Skarels sel3 = addr->bsel3; 54631908Skarels sel4 = addr->wsel4; /* release port */ 54731908Skarels sel6 = addr->wsel6; 54831908Skarels if(sel2 & DMV_22BIT) 54931908Skarels sel10 = addr->wsel10; 55031908Skarels addr->bsel2 &= ~DMV_RDO; 55131908Skarels pkaddr = sel4 | ((sel6 & 0x3f) << 16); 552*34529Skarels printd(("dmvxint: sel2=%x sel4=%x sel6=%x sel10=%x pkaddr=%x\n", 55331908Skarels (unsigned) sel2, 55431908Skarels (unsigned) sel4, 55531908Skarels (unsigned) sel6, 55631908Skarels (unsigned) sel10, 55731908Skarels (unsigned) pkaddr 558*34529Skarels )); 55931908Skarels if((sc->sc_flag & DMV_RUNNING)==0) { 56031908Skarels log(LOG_WARNING, "dmvxint: dmv%d xint while down\n", unit); 56131908Skarels return; 56231908Skarels } 56331908Skarels switch (sel2 & 07) { 56431908Skarels case DMV_BDRUS: 56531908Skarels /* 56631908Skarels * A read has completed. 56731908Skarels * Pass packet to type specific 56831908Skarels * higher-level input routine. 56931908Skarels */ 57031908Skarels ifp->if_ipackets++; 57131908Skarels /* find location in dmvuba struct */ 57231908Skarels ifrw= &sc->sc_ifr[0]; 57331908Skarels for (rp = &sc->sc_rbufs[0]; rp < &sc->sc_rbufs[NRCV]; rp++) { 57431908Skarels if(rp->ubinfo == pkaddr) 57531908Skarels break; 57631908Skarels ifrw++; 57731908Skarels } 57831908Skarels if (rp >= &sc->sc_rbufs[NRCV]) 57931908Skarels panic("dmv rcv"); 58031908Skarels if ((rp->flags & DBUF_DMVS) == 0) 58131908Skarels log(LOG_WARNING, "dmvxint: dmv%d done unalloc rbuf\n", unit); 58231908Skarels 58331908Skarels len = (sel10&0x3fff) - sizeof (struct dmv_header); 58431908Skarels if (len < 0 || len > DMVMTU) { 58531908Skarels ifp->if_ierrors++; 58631908Skarels log(LOG_ERR, "dmvxint: dmv%d bad rcv pkt addr 0x%x len 0x%x\n", 58731908Skarels unit, pkaddr, len); 58831908Skarels goto setup; 58931908Skarels } 59031908Skarels /* 59131908Skarels * Deal with trailer protocol: if type is trailer 59231908Skarels * get true type from first 16-bit word past data. 59331908Skarels * Remember that type was trailer by setting off. 59431908Skarels */ 59531908Skarels dh = (struct dmv_header *)ifrw->ifrw_addr; 59631908Skarels dh->dmv_type = ntohs((u_short)dh->dmv_type); 59731908Skarels #define dmvdataaddr(dh, off, type) ((type)(((caddr_t)((dh)+1)+(off)))) 59831908Skarels if (dh->dmv_type >= DMV_TRAILER && 59931908Skarels dh->dmv_type < DMV_TRAILER+DMV_NTRAILER) { 60031908Skarels off = (dh->dmv_type - DMV_TRAILER) * 512; 60131908Skarels if (off >= DMVMTU) 60231908Skarels goto setup; /* sanity */ 60331908Skarels dh->dmv_type = ntohs(*dmvdataaddr(dh, off, u_short *)); 60431908Skarels resid = ntohs(*(dmvdataaddr(dh, off+2, u_short *))); 60531908Skarels if (off + resid > len) 60631908Skarels goto setup; /* sanity */ 60731908Skarels len = off + resid; 60831908Skarels } else 60931908Skarels off = 0; 61031908Skarels if (len == 0) 61131908Skarels goto setup; 61231908Skarels 61331908Skarels /* 61431908Skarels * Pull packet off interface. Off is nonzero if 61531908Skarels * packet has trailing header; dmv_get will then 61631908Skarels * force this header information to be at the front, 61731908Skarels * but we still have to drop the type and length 61831908Skarels * which are at the front of any trailer data. 61931908Skarels */ 62031908Skarels m = if_ubaget(&sc->sc_ifuba, ifrw, len, off, ifp); 62131908Skarels if (m == 0) 62231908Skarels goto setup; 62331908Skarels if (off) { 62431908Skarels ifp = *(mtod(m, struct ifnet **)); 62531908Skarels m->m_off += 2 * sizeof (u_short); 62631908Skarels m->m_len -= 2 * sizeof (u_short); 62731908Skarels *(mtod(m, struct ifnet **)) = ifp; 62831908Skarels } 62931908Skarels switch (dh->dmv_type) { 63031908Skarels #ifdef INET 63131908Skarels case DMV_IPTYPE: 63231908Skarels schednetisr(NETISR_IP); 63331908Skarels inq = &ipintrq; 63431908Skarels break; 63531908Skarels #endif 63631908Skarels default: 63731908Skarels m_freem(m); 63831908Skarels goto setup; 63931908Skarels } 64031908Skarels 64131908Skarels s = splimp(); 64231908Skarels if (IF_QFULL(inq)) { 64331908Skarels IF_DROP(inq); 64431908Skarels m_freem(m); 64531908Skarels } else 64631908Skarels IF_ENQUEUE(inq, m); 64731908Skarels splx(s); 64831908Skarels setup: 64931908Skarels /* is this needed? */ 65031908Skarels rp->ubinfo = ifrw->ifrw_info & 0x3ffff; 65131908Skarels dmvload( 65231908Skarels sc, 65331908Skarels DMV_BACCR, 65431908Skarels QP_SEL4|QP_SEL6|QP_SEL10, 65531908Skarels 0, 65631908Skarels rp->ubinfo, 65731908Skarels (rp->ubinfo>>16)&0x3f, 65831908Skarels rp->cc 65931908Skarels ); 66031908Skarels break; 66131908Skarels case DMV_BDXSA: 66231908Skarels /* 66331908Skarels * A write has completed, start another 66431908Skarels * transfer if there is more data to send. 66531908Skarels */ 66631908Skarels ifp->if_opackets++; 66731908Skarels /* find associated dmvbuf structure */ 66831908Skarels ifxp = &sc->sc_ifw[0]; 66931908Skarels for (rp = &sc->sc_xbufs[0]; rp < &sc->sc_xbufs[NXMT]; rp++) { 67031908Skarels if(rp->ubinfo == pkaddr) 67131908Skarels break; 67231908Skarels ifxp++; 67331908Skarels } 67431908Skarels if (rp >= &sc->sc_xbufs[NXMT]) { 67531908Skarels log(LOG_ERR, "dmv%d: bad packet address 0x%x\n", 67631908Skarels unit, pkaddr); 67731908Skarels break; 67831908Skarels } 67931908Skarels if ((rp->flags & DBUF_DMVS) == 0) 68031908Skarels log(LOG_ERR, "dmvxint: dmv%d unallocated packet 0x%x\n", 68131908Skarels unit, pkaddr); 68231908Skarels /* mark buffer free */ 68331908Skarels if (ifxp->ifw_xtofree) { 68431908Skarels (void)m_freem(ifxp->ifw_xtofree); 68531908Skarels ifxp->ifw_xtofree = 0; 68631908Skarels } 68731908Skarels rp->flags &= ~DBUF_DMVS; 688*34529Skarels if (--sc->sc_oused == 0) 689*34529Skarels sc->sc_if.if_timer = 0; 690*34529Skarels else 691*34529Skarels sc->sc_if.if_timer = dmv_timeout; 692*34529Skarels if ((sc->sc_flag & DMV_ONLINE) == 0) { 693*34529Skarels extern int ifqmaxlen; 694*34529Skarels 695*34529Skarels /* 696*34529Skarels * We're on the air. 697*34529Skarels * Open the queue to the usual value. 698*34529Skarels */ 699*34529Skarels sc->sc_flag |= DMV_ONLINE; 700*34529Skarels ifp->if_snd.ifq_maxlen = ifqmaxlen; 701*34529Skarels } 70231908Skarels break; 70331908Skarels 70431908Skarels case DMV_CNTRLO: 70531908Skarels /* ACCUMULATE STATISTICS */ 70631908Skarels switch(sel6&DMV_EEC) { 70731908Skarels case DMV_ORUN: 70831908Skarels if(sc->sc_flag & DMV_RESTART) { 70931908Skarels load_rec_bufs(sc); 71031908Skarels sc->sc_flag &= ~DMV_RESTART; 71131908Skarels log(LOG_INFO, 712*34529Skarels "dmv%d: far end on-line\n", unit); 71331908Skarels } else { 71431908Skarels log(LOG_WARNING, 715*34529Skarels "dmv%d: far end restart\n", unit); 716*34529Skarels goto restart; 71731908Skarels } 71831908Skarels break; 71931908Skarels case DMV_RTE: 72031908Skarels ifp->if_ierrors++; 72131909Skarels if ((sc->sc_rte++ % DMV_RPRTE) == 0) 72231909Skarels log(LOG_WARNING, 723*34529Skarels "dmv%d: receive threshold error\n", 72431909Skarels unit); 72531908Skarels break; 72631908Skarels case DMV_TTE: 72731908Skarels ifp->if_oerrors++; 72831909Skarels if ((sc->sc_xte++ % DMV_RPTTE) == 0) 72931909Skarels log(LOG_WARNING, 730*34529Skarels "dmv%d: transmit threshold error\n", 73131909Skarels unit); 73231908Skarels break; 73331908Skarels case DMV_STE: 73431909Skarels if ((sc->sc_ste++ % DMV_RPSTE) == 0) 73531909Skarels log(LOG_WARNING, 736*34529Skarels "dmv%d: select threshold error\n", 73731909Skarels unit); 73831908Skarels break; 73931908Skarels case DMV_NXM: 74031909Skarels if ((sc->sc_nxm++ % DMV_RPNXM) == 0) 74131909Skarels log(LOG_WARNING, 742*34529Skarels "dmv%d: nonexistent memory error\n", 74331909Skarels unit); 74431908Skarels break; 74531908Skarels case DMV_MODD: 746*34529Skarels if ((sc->sc_modd++ % DMV_RPMODD) == 0) { 74731909Skarels log(LOG_WARNING, 748*34529Skarels "dmv%d: modem disconnected error\n", 74931909Skarels unit); 750*34529Skarels goto restart; 751*34529Skarels } 75231908Skarels break; 75331908Skarels case DMV_CXRL: 75431909Skarels if ((sc->sc_cxrl++ % DMV_RPCXRL) == 0) 75531909Skarels log(LOG_WARNING, 756*34529Skarels "dmv%d: carrier loss error\n", 75731909Skarels unit); 75831908Skarels break; 75931908Skarels case DMV_QOVF: 76031908Skarels log(LOG_WARNING, 761*34529Skarels "dmv%d: response queue overflow\n", 762*34529Skarels unit); 76331908Skarels sc->sc_qovf++; 764*34529Skarels goto restart; 76531908Skarels 76631908Skarels default: 76731908Skarels log(LOG_WARNING, 768*34529Skarels "dmv%d: unknown error %o\n", 769*34529Skarels unit, sel6&DMV_EEC); 77031908Skarels if ((sc->sc_unknown++ % DMV_RPUNKNOWN) == 0) 771*34529Skarels goto restart; 77231908Skarels break; 77331908Skarels } 77431908Skarels break; 77531908Skarels 77631908Skarels case DMV_BDRUNUS: 77731908Skarels case DMV_BDXSN: 77831908Skarels case DMV_BDXNS: 77931908Skarels log(LOG_INFO, 780*34529Skarels "dmv%d: buffer disp for halted trib %o\n", 78131908Skarels unit, sel2&0x7 78231908Skarels ); 78331908Skarels break; 78431908Skarels 78531908Skarels case DMV_MDEFO: 78631908Skarels if((sel6&0x1f) == 020) { 78731908Skarels log(LOG_INFO, 788*34529Skarels "dmv%d: buffer return complete sel3=%x\n", 78931908Skarels unit, sel3); 79031908Skarels } else { 79131908Skarels log(LOG_INFO, 792*34529Skarels "dmv%d: info resp sel3=%x sel4=%x sel6=%x\n", 79331908Skarels unit, sel3, sel4, sel6 79431908Skarels ); 79531908Skarels } 79631908Skarels break; 79731908Skarels 79831908Skarels default: 799*34529Skarels log(LOG_WARNING, "dmv%d: bad control %o\n", 80031908Skarels unit, sel2&0x7 80131908Skarels ); 80231908Skarels break; 80331908Skarels } 80431908Skarels } 80531908Skarels dmvstart(unit); 80631908Skarels return; 807*34529Skarels restart: 80831908Skarels dmvrestart(unit); 80931908Skarels } 810*34529Skarels 81131908Skarels load_rec_bufs(sc) 81231908Skarels register struct dmv_softc *sc; 81331908Skarels { 81431908Skarels register struct dmvbufs *rp; 81531908Skarels 81631908Skarels /* queue first NRCV buffers for DMV to fill */ 81731908Skarels for (rp = &sc->sc_rbufs[0]; rp < &sc->sc_rbufs[NRCV]; rp++) { 81831908Skarels rp->flags |= DBUF_DMVS; 81931908Skarels dmvload( 82031908Skarels sc, 82131908Skarels DMV_BACCR, 82231908Skarels QP_TRIB|QP_SEL4|QP_SEL6|QP_SEL10, 82331908Skarels 1, 82431908Skarels rp->ubinfo, 82531908Skarels (rp->ubinfo>>16)&0x3f, 82631908Skarels rp->cc 82731908Skarels ); 82831908Skarels sc->sc_iused++; 82931908Skarels } 83031908Skarels } 83131908Skarels 83231908Skarels /* 83331908Skarels * DMV output routine. 83431908Skarels * Encapsulate a packet of type family for the dmv. 83531908Skarels * Use trailer local net encapsulation if enough data in first 83631908Skarels * packet leaves a multiple of 512 bytes of data in remainder. 83731908Skarels */ 83831908Skarels dmvoutput(ifp, m0, dst) 83931908Skarels register struct ifnet *ifp; 84031908Skarels register struct mbuf *m0; 84131908Skarels struct sockaddr *dst; 84231908Skarels { 84331908Skarels int type, error, s; 84431908Skarels register struct mbuf *m = m0; 84531908Skarels register struct dmv_header *dh; 84631908Skarels register int off; 84731908Skarels 848*34529Skarels if ((ifp->if_flags & IFF_UP) == 0) { 849*34529Skarels error = ENETDOWN; 850*34529Skarels goto bad; 851*34529Skarels } 852*34529Skarels 85331908Skarels switch (dst->sa_family) { 85431908Skarels #ifdef INET 85531908Skarels case AF_INET: 85631908Skarels off = ntohs((u_short)mtod(m, struct ip *)->ip_len) - m->m_len; 85731908Skarels if ((ifp->if_flags & IFF_NOTRAILERS) == 0) 85831908Skarels if (off > 0 && (off & 0x1ff) == 0 && 85931908Skarels m->m_off >= MMINOFF + 2 * sizeof (u_short)) { 86031908Skarels type = DMV_TRAILER + (off>>9); 86131908Skarels m->m_off -= 2 * sizeof (u_short); 86231908Skarels m->m_len += 2 * sizeof (u_short); 86331908Skarels *mtod(m, u_short *) = htons((u_short)DMV_IPTYPE); 86431908Skarels *(mtod(m, u_short *) + 1) = htons((u_short)m->m_len); 86531908Skarels goto gottrailertype; 86631908Skarels } 86731908Skarels type = DMV_IPTYPE; 86831908Skarels off = 0; 86931908Skarels goto gottype; 87031908Skarels #endif 87131908Skarels 87231908Skarels case AF_UNSPEC: 87331908Skarels dh = (struct dmv_header *)dst->sa_data; 87431908Skarels type = dh->dmv_type; 87531908Skarels goto gottype; 87631908Skarels 87731908Skarels default: 878*34529Skarels log(LOG_ERR, "dmvoutput, dmv%d can't handle af%d\n", 879*34529Skarels ifp->if_unit, dst->sa_family); 88031908Skarels error = EAFNOSUPPORT; 88131908Skarels goto bad; 88231908Skarels } 88331908Skarels 88431908Skarels gottrailertype: 88531908Skarels /* 88631908Skarels * Packet to be sent as a trailer; move first packet 88731908Skarels * (control information) to end of chain. 88831908Skarels */ 88931908Skarels while (m->m_next) 89031908Skarels m = m->m_next; 89131908Skarels m->m_next = m0; 89231908Skarels m = m0->m_next; 89331908Skarels m0->m_next = 0; 89431908Skarels m0 = m; 89531908Skarels 89631908Skarels gottype: 89731908Skarels /* 89831908Skarels * Add local network header 89931908Skarels * (there is space for a uba on a vax to step on) 90031908Skarels */ 90131908Skarels if (m->m_off > MMAXOFF || 90231908Skarels MMINOFF + sizeof(struct dmv_header) > m->m_off) { 90331908Skarels m = m_get(M_DONTWAIT, MT_HEADER); 90431908Skarels if (m == 0) { 90531908Skarels error = ENOBUFS; 90631908Skarels goto bad; 90731908Skarels } 90831908Skarels m->m_next = m0; 90931908Skarels m->m_off = MMINOFF; 91031908Skarels m->m_len = sizeof (struct dmv_header); 91131908Skarels } else { 91231908Skarels m->m_off -= sizeof (struct dmv_header); 91331908Skarels m->m_len += sizeof (struct dmv_header); 91431908Skarels } 91531908Skarels dh = mtod(m, struct dmv_header *); 91631908Skarels dh->dmv_type = htons((u_short)type); 91731908Skarels 91831908Skarels /* 91931908Skarels * Queue message on interface, and start output if interface 92031908Skarels * not yet active. 92131908Skarels */ 92231908Skarels s = splimp(); 92331908Skarels if (IF_QFULL(&ifp->if_snd)) { 92431908Skarels IF_DROP(&ifp->if_snd); 92531908Skarels m_freem(m); 92631908Skarels splx(s); 92731908Skarels return (ENOBUFS); 92831908Skarels } 92931908Skarels IF_ENQUEUE(&ifp->if_snd, m); 93031908Skarels dmvstart(ifp->if_unit); 93131908Skarels splx(s); 93231908Skarels return (0); 93331908Skarels 93431908Skarels bad: 93531908Skarels m_freem(m0); 93631908Skarels return (error); 93731908Skarels } 93831908Skarels 93931908Skarels 94031908Skarels /* 94131908Skarels * Process an ioctl request. 94231908Skarels */ 94331908Skarels /* ARGSUSED */ 94431908Skarels dmvioctl(ifp, cmd, data) 94531908Skarels register struct ifnet *ifp; 94631908Skarels int cmd; 94731908Skarels caddr_t data; 94831908Skarels { 94931908Skarels int s = splimp(), error = 0; 95031908Skarels struct mbuf *m; 95131908Skarels register struct dmv_softc *sc = &dmv_softc[ifp->if_unit]; 95231908Skarels 95331908Skarels switch (cmd) { 95431908Skarels 95531908Skarels case SIOCSIFADDR: 95631908Skarels ifp->if_flags |= IFF_UP; 95731908Skarels if ((ifp->if_flags & IFF_RUNNING) == 0) 95831908Skarels dmvinit(ifp->if_unit); 95931908Skarels break; 96031908Skarels 96131908Skarels case SIOCSIFDSTADDR: 96231908Skarels if ((ifp->if_flags & IFF_RUNNING) == 0) 96331908Skarels dmvinit(ifp->if_unit); 96431908Skarels break; 96531908Skarels 96631908Skarels case SIOCSIFFLAGS: 96731908Skarels if ((ifp->if_flags & IFF_UP) == 0 && 968*34529Skarels sc->sc_flag & DMV_RUNNING) 969*34529Skarels dmvdown(ifp->if_unit); 970*34529Skarels else if (ifp->if_flags & IFF_UP && 97131908Skarels (sc->sc_flag & DMV_RUNNING) == 0) 97231908Skarels dmvrestart(ifp->if_unit); 97331908Skarels break; 97431908Skarels 97531908Skarels default: 97631908Skarels error = EINVAL; 97731908Skarels } 97831908Skarels splx(s); 97931908Skarels return (error); 98031908Skarels } 98131908Skarels 98231908Skarels /* 98331908Skarels * Restart after a fatal error. 98431908Skarels * Clear device and reinitialize. 98531908Skarels */ 98631908Skarels dmvrestart(unit) 98731908Skarels int unit; 98831908Skarels { 98931908Skarels register struct dmvdevice *addr; 99031908Skarels register int i; 991*34529Skarels 992*34529Skarels dmvdown(unit); 993*34529Skarels 994*34529Skarels addr = (struct dmvdevice *)(dmvinfo[unit]->ui_addr); 99531908Skarels /* 996*34529Skarels * Let the DMV finish the MCLR. 99731908Skarels */ 99831908Skarels for (i = 100000; i && (addr->bsel1 & DMV_RUN) == 0; i--) 99931908Skarels ; 100031908Skarels if ((addr->bsel1 & DMV_RUN) == 0) { 100131908Skarels log(LOG_ERR, "dmvrestart: can't start device\n" ); 100231908Skarels return (0); 100331908Skarels } 100431908Skarels if ((addr->bsel4 != 033) || (addr->bsel6 != 0305)) 100531908Skarels { 1006*34529Skarels log(LOG_ERR, "dmv%d: device init failed, bsel4=%o, bsel6=%o\n", 1007*34529Skarels unit, addr->bsel4, addr->bsel6); 100831908Skarels return (0); 100931908Skarels } 1010*34529Skarels 1011*34529Skarels /* restart DMV */ 1012*34529Skarels dmvinit(unit); 1013*34529Skarels dmv_softc[unit].sc_if.if_collisions++; /* why not? */ 1014*34529Skarels } 1015*34529Skarels 1016*34529Skarels /* 1017*34529Skarels * Reset a device and mark down. 1018*34529Skarels * Flush output queue and drop queue limit. 1019*34529Skarels */ 1020*34529Skarels dmvdown(unit) 1021*34529Skarels int unit; 1022*34529Skarels { 1023*34529Skarels struct dmv_softc *sc = &dmv_softc[unit]; 1024*34529Skarels register struct ifxmt *ifxp; 1025*34529Skarels 1026*34529Skarels ((struct dmvdevice *)(dmvinfo[unit]->ui_addr))->bsel1 = DMV_MCLR; 1027*34529Skarels sc->sc_flag &= ~(DMV_RUNNING | DMV_ONLINE); 1028*34529Skarels 102931908Skarels for (ifxp = sc->sc_ifw; ifxp < &sc->sc_ifw[NXMT]; ifxp++) { 103031908Skarels if (ifxp->ifw_xtofree) { 103131908Skarels (void) m_freem(ifxp->ifw_xtofree); 103231908Skarels ifxp->ifw_xtofree = 0; 103331908Skarels } 103431908Skarels } 1035*34529Skarels sc->sc_oused = 0; 1036*34529Skarels if_qflush(&sc->sc_if.if_snd); 1037*34529Skarels 1038*34529Skarels /* 1039*34529Skarels * Limit packets enqueued until we're back on the air. 1040*34529Skarels */ 1041*34529Skarels sc->sc_if.if_snd.ifq_maxlen = 3; 104231908Skarels } 104331908Skarels 104431908Skarels /* 1045*34529Skarels * Watchdog timeout to see that transmitted packets don't 1046*34529Skarels * lose interrupts. The device has to be online. 104731908Skarels */ 1048*34529Skarels dmvtimeout(unit) 1049*34529Skarels int unit; 105031908Skarels { 105131908Skarels register struct dmv_softc *sc; 105231908Skarels struct dmvdevice *addr; 105331908Skarels 1054*34529Skarels sc = &dmv_softc[unit]; 1055*34529Skarels if (sc->sc_flag & DMV_ONLINE) { 1056*34529Skarels addr = (struct dmvdevice *)(dmvinfo[unit]->ui_addr); 1057*34529Skarels log(LOG_ERR, "dmv%d: output timeout, bsel0=%b bsel2=%b\n", 1058*34529Skarels unit, addr->bsel0 & 0xff, DMV0BITS, 1059*34529Skarels addr->bsel2 & 0xff, DMV2BITS); 1060*34529Skarels dmvrestart(unit); 106131908Skarels } 106231908Skarels } 106331908Skarels #endif 1064