131908Skarels /* 234727Smckusick * Copyright (c) 1988 Regents of the University of California. 334727Smckusick * All rights reserved. 434727Smckusick * 544558Sbostic * %sccs.include.redist.c% 634727Smckusick * 7*45291Ssklower * @(#)if_dmv.c 7.11 (Berkeley) 10/02/90 834868Sbostic */ 934868Sbostic 1034868Sbostic /* 1131908Skarels * DMV-11 Driver 1231908Skarels * 1331908Skarels * Qbus Sync DDCMP interface - DMV operated in full duplex, point to point mode 1431908Skarels * 1534727Smckusick * Written by Bob Kridle of Mt Xinu 1634727Smckusick * starting from if_dmc.c version 6.12 dated 4/23/86 1731908Skarels */ 1831908Skarels 1931908Skarels #include "dmv.h" 2031908Skarels #if NDMV > 0 2131908Skarels 2231908Skarels #include "param.h" 2331908Skarels #include "systm.h" 2431908Skarels #include "mbuf.h" 2531908Skarels #include "buf.h" 2631908Skarels #include "ioctl.h" /* must precede tty.h */ 2731908Skarels #include "tty.h" 2831908Skarels #include "protosw.h" 2931908Skarels #include "socket.h" 3031908Skarels #include "syslog.h" 3131908Skarels #include "vmmac.h" 3231908Skarels #include "errno.h" 3334529Skarels #include "time.h" 3434529Skarels #include "kernel.h" 3531908Skarels 3631908Skarels #include "../net/if.h" 3731908Skarels #include "../net/netisr.h" 3831908Skarels #include "../net/route.h" 3931908Skarels 4031908Skarels #ifdef INET 4131908Skarels #include "../netinet/in.h" 4231908Skarels #include "../netinet/in_systm.h" 4331908Skarels #include "../netinet/in_var.h" 4431908Skarels #include "../netinet/ip.h" 4531908Skarels #endif 4631908Skarels 4731908Skarels #include "../vax/cpu.h" 4831908Skarels #include "../vax/mtpr.h" 4934529Skarels #include "../vax/pte.h" 5034529Skarels #include "../vaxuba/ubareg.h" 5134529Skarels #include "../vaxuba/ubavar.h" 5231908Skarels #include "if_uba.h" 5331908Skarels #include "if_dmv.h" 5431908Skarels 5531908Skarels int dmv_timeout = 8; /* timeout value */ 5631908Skarels 5731908Skarels /* 5831908Skarels * Driver information for auto-configuration stuff. 5931908Skarels */ 6031908Skarels int dmvprobe(), dmvattach(), dmvinit(), dmvioctl(); 6134529Skarels int dmvoutput(), dmvreset(), dmvtimeout(); 6231908Skarels struct uba_device *dmvinfo[NDMV]; 6331908Skarels u_short dmvstd[] = { 0 }; 6431908Skarels struct uba_driver dmvdriver = 6531908Skarels { dmvprobe, 0, dmvattach, 0, dmvstd, "dmv", dmvinfo }; 6631908Skarels 6731908Skarels /* 6831908Skarels * Don't really know how many buffers/commands can be queued to a DMV-11. 6931908Skarels * Manual doesn't say... Perhaps we can look at a DEC driver some day. 7034529Skarels * These numbers ame from DMC/DMR driver. 7131908Skarels */ 7231908Skarels #define NRCV 5 7331908Skarels #define NXMT 3 7431908Skarels #define NCMDS (NRCV+NXMT+4) /* size of command queue */ 7531908Skarels 7634529Skarels #ifdef DEBUG 7734529Skarels #define printd(f) if (sc->sc_if.if_flags & IFF_DEBUG) \ 7834529Skarels printf("DMVDEBUG: dmv%d: ", unit), printf(f) 7934529Skarels #else 8034529Skarels #define printd(f) /* nil */ 8134529Skarels #endif 8231908Skarels 8331908Skarels /* error reporting intervals */ 8431908Skarels 8531908Skarels #define DMV_RPRTE 1 8631908Skarels #define DMV_RPTTE 1 8731908Skarels #define DMV_RPSTE 1 8831908Skarels #define DMV_RPNXM 1 8931908Skarels #define DMV_RPMODD 1 9031908Skarels #define DMV_RPQOVF 1 9131908Skarels #define DMV_RPCXRL 1 9231908Skarels 9331909Skarels /* number of errors to accept before trying a reset */ 9431909Skarels #define DMV_RPUNKNOWN 10 9531909Skarels 9631908Skarels struct dmv_command { 9731908Skarels u_char qp_mask; /* Which registers to set up */ 9831908Skarels #define QP_TRIB 0x01 9931908Skarels #define QP_SEL4 0x02 10031908Skarels #define QP_SEL6 0x04 10131908Skarels #define QP_SEL10 0x08 10231908Skarels u_char qp_cmd; 10331908Skarels u_char qp_tributary; 10431908Skarels u_short qp_sel4; 10531908Skarels u_short qp_sel6; 10631908Skarels u_short qp_sel10; 10731908Skarels struct dmv_command *qp_next; /* next command on queue */ 10831908Skarels }; 10931908Skarels 11031908Skarels #define qp_lowbufaddr qp_ 11131908Skarels 11231908Skarels struct dmvbufs { 11331908Skarels int ubinfo; /* from uballoc */ 11431908Skarels short cc; /* buffer size */ 11531908Skarels short flags; /* access control */ 11631908Skarels }; 11731908Skarels 11831908Skarels #define DBUF_OURS 0 /* buffer is available */ 11931908Skarels #define DBUF_DMVS 1 /* buffer claimed by somebody */ 12031908Skarels #define DBUF_XMIT 4 /* transmit buffer */ 12131908Skarels #define DBUF_RCV 8 /* receive buffer */ 12231908Skarels 12331908Skarels 12431908Skarels /* 12531908Skarels * DMV software status per interface. 12631908Skarels * 12731908Skarels * Each interface is referenced by a network interface structure, 12831908Skarels * sc_if, which the routing code uses to locate the interface. 12931908Skarels * This structure contains the output queue for the interface, its address, ... 13031908Skarels * We also have, for each interface, a set of 7 UBA interface structures 13131908Skarels * for each, which 13231908Skarels * contain information about the UNIBUS resources held by the interface: 13331908Skarels * map registers, buffered data paths, etc. Information is cached in this 13431908Skarels * structure for use by the if_uba.c routines in running the interface 13531908Skarels * efficiently. 13631908Skarels */ 13731908Skarels struct dmv_softc { 13831908Skarels struct ifnet sc_if; /* network-visible interface */ 13931908Skarels short sc_oused; /* output buffers currently in use */ 14031908Skarels short sc_iused; /* input buffers given to DMV */ 14131908Skarels short sc_flag; /* flags */ 14236032Skarels short sc_ipl; /* interrupt priority */ 14331908Skarels int sc_ubinfo; /* UBA mapping info for base table */ 14431908Skarels int sc_errors[8]; /* error counters */ 14531908Skarels #define sc_rte sc_errors[0] /* receive threshhold error */ 14631908Skarels #define sc_xte sc_errors[1] /* xmit threshhold error */ 14731908Skarels #define sc_ste sc_errors[2] /* select threshhold error */ 14831908Skarels #define sc_nxm sc_errors[3] /* non-existant memory */ 14931908Skarels #define sc_modd sc_errors[4] /* modem disconnect */ 15031908Skarels #define sc_qovf sc_errors[5] /* command/response queue overflow */ 15131908Skarels #define sc_cxrl sc_errors[6] /* carrier loss */ 15231908Skarels #define sc_unknown sc_errors[7] /* other errors - look in DMV manual */ 15334529Skarels struct dmvbufs sc_rbufs[NRCV]; /* receive buffer info */ 15434529Skarels struct dmvbufs sc_xbufs[NXMT]; /* transmit buffer info */ 15534529Skarels struct ifubinfo sc_ifuba; /* UNIBUS resources */ 15634529Skarels struct ifrw sc_ifr[NRCV]; /* UNIBUS receive buffer maps */ 15734529Skarels struct ifxmt sc_ifw[NXMT]; /* UNIBUS receive buffer maps */ 15831908Skarels /* command queue stuff */ 15931908Skarels struct dmv_command sc_cmdbuf[NCMDS]; 16031908Skarels struct dmv_command *sc_qhead; /* head of command queue */ 16131908Skarels struct dmv_command *sc_qtail; /* tail of command queue */ 16231908Skarels struct dmv_command *sc_qactive; /* command in progress */ 16331908Skarels struct dmv_command *sc_qfreeh; /* head of list of free cmd buffers */ 16431908Skarels struct dmv_command *sc_qfreet; /* tail of list of free cmd buffers */ 16531908Skarels /* end command queue stuff */ 16631908Skarels } dmv_softc[NDMV]; 16731908Skarels 16831908Skarels /* flags */ 16934529Skarels #define DMV_RESTART 0x01 /* software restart in progress */ 17034529Skarels #define DMV_ONLINE 0x02 /* device managed to transmit */ 17134529Skarels #define DMV_RUNNING 0x04 /* device initialized */ 17231908Skarels 17331908Skarels 17431908Skarels /* queue manipulation macros */ 17531908Skarels #define QUEUE_AT_HEAD(qp, head, tail) \ 17631908Skarels (qp)->qp_next = (head); \ 17731908Skarels (head) = (qp); \ 17831908Skarels if ((tail) == (struct dmv_command *) 0) \ 17931908Skarels (tail) = (head) 18031908Skarels 18131908Skarels #define QUEUE_AT_TAIL(qp, head, tail) \ 18231908Skarels if ((tail)) \ 18331908Skarels (tail)->qp_next = (qp); \ 18431908Skarels else \ 18531908Skarels (head) = (qp); \ 18631908Skarels (qp)->qp_next = (struct dmv_command *) 0; \ 18731908Skarels (tail) = (qp) 18831908Skarels 18931908Skarels #define DEQUEUE(head, tail) \ 19031908Skarels (head) = (head)->qp_next;\ 19131908Skarels if ((head) == (struct dmv_command *) 0)\ 19231908Skarels (tail) = (head) 19331908Skarels 19436032Skarels dmvprobe(reg, ui) 19531908Skarels caddr_t reg; 19636032Skarels struct uba_device *ui; 19731908Skarels { 19831908Skarels register int br, cvec; 19931908Skarels register struct dmvdevice *addr = (struct dmvdevice *)reg; 20031908Skarels register int i; 20131908Skarels 20231908Skarels #ifdef lint 20331908Skarels br = 0; cvec = br; br = cvec; 20431908Skarels dmvrint(0); dmvxint(0); 20531908Skarels #endif 20631908Skarels addr->bsel1 = DMV_MCLR; 20731908Skarels for (i = 100000; i && (addr->bsel1 & DMV_RUN) == 0; i--) 20831908Skarels ; 20931908Skarels if ((addr->bsel1 & DMV_RUN) == 0) { 21031908Skarels printf("dmvprobe: can't start device\n" ); 21131908Skarels return (0); 21231908Skarels } 21331908Skarels if ((addr->bsel4 != 033) || (addr->bsel6 != 0305)) 21431908Skarels { 21531908Skarels printf("dmvprobe: device init failed, bsel4=%o, bsel6=%o\n", 21631908Skarels addr->bsel4, addr->bsel6); 21731908Skarels return (0); 21831908Skarels } 21936032Skarels (void) spl6(); 22031908Skarels addr->bsel0 = DMV_RQI|DMV_IEI|DMV_IEO; 22131908Skarels DELAY(1000000); 22238984Skarels dmv_softc[ui->ui_unit].sc_ipl = br = qbgetpri(); 22331908Skarels addr->bsel1 = DMV_MCLR; 22431908Skarels for (i = 100000; i && (addr->bsel1 & DMV_RUN) == 0; i--) 22531908Skarels ; 22636032Skarels return (sizeof(struct dmvdevice)); 22731908Skarels } 22831908Skarels 22931908Skarels /* 23031908Skarels * Interface exists: make available by filling in network interface 23131908Skarels * record. System will initialize the interface when it is ready 23231908Skarels * to accept packets. 23331908Skarels */ 23431908Skarels dmvattach(ui) 23531908Skarels register struct uba_device *ui; 23631908Skarels { 23731908Skarels register struct dmv_softc *sc = &dmv_softc[ui->ui_unit]; 23831908Skarels 23931908Skarels sc->sc_if.if_unit = ui->ui_unit; 24031908Skarels sc->sc_if.if_name = "dmv"; 24131908Skarels sc->sc_if.if_mtu = DMVMTU; 24231908Skarels sc->sc_if.if_init = dmvinit; 24331908Skarels sc->sc_if.if_output = dmvoutput; 24431908Skarels sc->sc_if.if_ioctl = dmvioctl; 24531908Skarels sc->sc_if.if_reset = dmvreset; 24634529Skarels sc->sc_if.if_watchdog = dmvtimeout; 24731908Skarels sc->sc_if.if_flags = IFF_POINTOPOINT; 24831908Skarels sc->sc_ifuba.iff_flags = UBA_CANTWAIT; 24931908Skarels 25031908Skarels if_attach(&sc->sc_if); 25131908Skarels } 25231908Skarels 25331908Skarels /* 25431908Skarels * Reset of interface after UNIBUS reset. 25531908Skarels * If interface is on specified UBA, reset its state. 25631908Skarels */ 25731908Skarels dmvreset(unit, uban) 25831908Skarels int unit, uban; 25931908Skarels { 26031908Skarels register struct uba_device *ui; 26131908Skarels register struct dmv_softc *sc = &dmv_softc[unit]; 26231908Skarels 26331908Skarels if (unit >= NDMV || (ui = dmvinfo[unit]) == 0 || ui->ui_alive == 0 || 26431908Skarels ui->ui_ubanum != uban) 26531908Skarels return; 26631908Skarels printf(" dmv%d", unit); 26731908Skarels sc->sc_flag = 0; 26831908Skarels sc->sc_if.if_flags &= ~IFF_RUNNING; 26931908Skarels dmvinit(unit); 27031908Skarels } 27131908Skarels 27231908Skarels /* 27331908Skarels * Initialization of interface; reinitialize UNIBUS usage. 27431908Skarels */ 27531908Skarels dmvinit(unit) 27631908Skarels int unit; 27731908Skarels { 27831908Skarels register struct dmv_softc *sc = &dmv_softc[unit]; 27931908Skarels register struct uba_device *ui = dmvinfo[unit]; 28031908Skarels register struct dmvdevice *addr; 28131908Skarels register struct ifnet *ifp = &sc->sc_if; 28231908Skarels register struct ifrw *ifrw; 28331908Skarels register struct ifxmt *ifxp; 28431908Skarels register struct dmvbufs *rp; 28531908Skarels register struct dmv_command *qp; 28631908Skarels struct ifaddr *ifa; 28731908Skarels int base; 28831908Skarels int s; 28931908Skarels 29031908Skarels addr = (struct dmvdevice *)ui->ui_addr; 29131908Skarels 29231908Skarels /* 29331908Skarels * Check to see that an address has been set 29431908Skarels * (both local and destination for an address family). 29531908Skarels */ 29631908Skarels for (ifa = ifp->if_addrlist; ifa; ifa = ifa->ifa_next) 297*45291Ssklower if (ifa->ifa_addr->sa_family && 298*45291Ssklower ifa->ifa_addr->sa_family != AF_LINK && 299*45291Ssklower ifa->ifa_dstaddr && ifa->ifa_dstaddr->sa_family) 30031908Skarels break; 30131908Skarels if (ifa == (struct ifaddr *) 0) 30231908Skarels return; 30331908Skarels 30431908Skarels if ((addr->bsel1&DMV_RUN) == 0) { 30531908Skarels log(LOG_CRIT, "dmvinit: dmv%d not running\n", unit); 30631908Skarels ifp->if_flags &= ~IFF_UP; 30731908Skarels return; 30831908Skarels } 30934529Skarels printd(("dmvinit\n")); 31031908Skarels /* initialize UNIBUS resources */ 31131908Skarels sc->sc_iused = sc->sc_oused = 0; 31231908Skarels if ((ifp->if_flags & IFF_RUNNING) == 0) { 31331908Skarels if (if_ubaminit( 31431908Skarels &sc->sc_ifuba, 31531908Skarels ui->ui_ubanum, 31631908Skarels sizeof(struct dmv_header), 31731908Skarels (int)btoc(DMVMTU), 31831908Skarels sc->sc_ifr, 31931908Skarels NRCV, 32031908Skarels sc->sc_ifw, 32131908Skarels NXMT 32231908Skarels ) == 0) { 32331908Skarels log(LOG_CRIT, "dmvinit: dmv%d can't allocate uba resources\n", unit); 32431908Skarels ifp->if_flags &= ~IFF_UP; 32531908Skarels return; 32631908Skarels } 32731908Skarels ifp->if_flags |= IFF_RUNNING; 32831908Skarels } 32934529Skarels /* 33034529Skarels * Limit packets enqueued until we see if we're on the air. 33134529Skarels */ 33234529Skarels ifp->if_snd.ifq_maxlen = 3; 33331908Skarels 33434529Skarels 33531908Skarels /* initialize buffer pool */ 33631908Skarels /* receives */ 33731908Skarels ifrw = &sc->sc_ifr[0]; 33831908Skarels for (rp = &sc->sc_rbufs[0]; rp < &sc->sc_rbufs[NRCV]; rp++) { 33936032Skarels rp->ubinfo = UBAI_ADDR(ifrw->ifrw_info); 34031908Skarels rp->cc = DMVMTU + sizeof (struct dmv_header); 34131908Skarels rp->flags = DBUF_OURS|DBUF_RCV; 34231908Skarels ifrw++; 34331908Skarels } 34431908Skarels /* transmits */ 34531908Skarels ifxp = &sc->sc_ifw[0]; 34631908Skarels for (rp = &sc->sc_xbufs[0]; rp < &sc->sc_xbufs[NXMT]; rp++) { 34736032Skarels rp->ubinfo = UBAI_ADDR(ifxp->ifw_info); 34831908Skarels rp->cc = 0; 34931908Skarels rp->flags = DBUF_OURS|DBUF_XMIT; 35031908Skarels ifxp++; 35131908Skarels } 35231908Skarels 35331908Skarels /* set up command queues */ 35431908Skarels sc->sc_qfreeh = sc->sc_qfreet 35531908Skarels = sc->sc_qhead = sc->sc_qtail = sc->sc_qactive = 35631908Skarels (struct dmv_command *)0; 35731908Skarels /* set up free command buffer list */ 35831908Skarels for (qp = &sc->sc_cmdbuf[0]; qp < &sc->sc_cmdbuf[NCMDS]; qp++) { 35931908Skarels QUEUE_AT_HEAD(qp, sc->sc_qfreeh, sc->sc_qfreet); 36031908Skarels } 36131908Skarels if(sc->sc_flag & DMV_RUNNING) 36231908Skarels dmvload( sc, DMV_CNTRLI, (QP_TRIB|QP_SEL6), 1, 0, DMV_REQHS,0); 36331908Skarels else 36431908Skarels dmvload( sc, DMV_CNTRLI, (QP_TRIB|QP_SEL6), 1, 0, DMV_ESTTRIB,0); 36531908Skarels dmvload( sc, DMV_CNTRLI, (QP_TRIB|QP_SEL6), 1, 0, DMV_REQSUS,0); 36631908Skarels sc->sc_flag |= (DMV_RESTART|DMV_RUNNING); 36734529Skarels sc->sc_flag &= ~DMV_ONLINE; 36831908Skarels addr->bsel0 |= DMV_IEO; 36931908Skarels } 37031908Skarels 37131908Skarels /* 37231908Skarels * Start output on interface. Get another datagram 37331908Skarels * to send from the interface queue and map it to 37431908Skarels * the interface before starting output. 37531908Skarels * 37631908Skarels * Must be called at spl 5 37731908Skarels */ 37831908Skarels dmvstart(dev) 37931908Skarels dev_t dev; 38031908Skarels { 38131908Skarels int unit = minor(dev); 38231908Skarels register struct dmv_softc *sc = &dmv_softc[unit]; 38331908Skarels struct mbuf *m; 38431908Skarels register struct dmvbufs *rp; 38531908Skarels register int n; 38631908Skarels 38731908Skarels /* 38831908Skarels * Dequeue up to NXMT requests and map them to the UNIBUS. 38931908Skarels * If no more requests, or no dmv buffers available, just return. 39031908Skarels */ 39134529Skarels printd(("dmvstart\n")); 39231908Skarels n = 0; 39331908Skarels for (rp = &sc->sc_xbufs[0]; rp < &sc->sc_xbufs[NXMT]; rp++ ) { 39431908Skarels /* find an available buffer */ 39531908Skarels if ((rp->flags & DBUF_DMVS) == 0) { 39631908Skarels IF_DEQUEUE(&sc->sc_if.if_snd, m); 39731908Skarels if (m == 0) 39831908Skarels return; 39931908Skarels /* mark it dmvs */ 40031908Skarels rp->flags |= (DBUF_DMVS); 40131908Skarels /* 40231908Skarels * Have request mapped to UNIBUS for transmission 40331908Skarels * and start the output. 40431908Skarels */ 40531908Skarels rp->cc = if_ubaput(&sc->sc_ifuba, &sc->sc_ifw[n], m); 40634529Skarels if (++sc->sc_oused == 1) 40734529Skarels sc->sc_if.if_timer = dmv_timeout; 40831908Skarels dmvload( 40931908Skarels sc, 41031908Skarels DMV_BACCX, 41131908Skarels QP_TRIB|QP_SEL4|QP_SEL6|QP_SEL10, 41231908Skarels 1, 41331908Skarels rp->ubinfo, 41431908Skarels (rp->ubinfo>>16)&0x3f, 41531908Skarels rp->cc 41631908Skarels ); 41731908Skarels } 41831908Skarels n++; 41931908Skarels } 42031908Skarels } 42131908Skarels 42231908Skarels /* 42331908Skarels * Utility routine to load the DMV device registers. 42431908Skarels */ 42531908Skarels dmvload(sc, cmd, mask, tributary, sel4, sel6, sel10) 42631908Skarels register struct dmv_softc *sc; 42731908Skarels u_char cmd, tributary, mask; 42831908Skarels u_short sel4, sel6, sel10; 42931908Skarels { 43031908Skarels register struct dmvdevice *addr; 43131908Skarels register int unit, sps; 43231908Skarels register struct dmv_command *qp; 43331908Skarels 43431908Skarels unit = sc - dmv_softc; 43534529Skarels printd(("dmvload: cmd=%x mask=%x trib=%x sel4=%x sel6=%x sel10=%x\n", 43631908Skarels (unsigned) cmd, 43731908Skarels (unsigned) mask, 43831908Skarels (unsigned) tributary, 43931908Skarels (unsigned) sel4, 44031908Skarels (unsigned) sel6, 44131908Skarels (unsigned) sel10 44234529Skarels )); 44331908Skarels addr = (struct dmvdevice *)dmvinfo[unit]->ui_addr; 44431908Skarels sps = spl5(); 44531908Skarels 44631908Skarels /* grab a command buffer from the free list */ 44731908Skarels if ((qp = sc->sc_qfreeh) == (struct dmv_command *)0) 44831908Skarels panic("dmv command queue overflow"); 44931908Skarels DEQUEUE(sc->sc_qfreeh, sc->sc_qfreet); 45031908Skarels 45131908Skarels /* fill in requested info */ 45231908Skarels qp->qp_cmd = cmd; 45331908Skarels qp->qp_mask = mask; 45431908Skarels qp->qp_tributary = tributary; 45531908Skarels qp->qp_sel4 = sel4; 45631908Skarels qp->qp_sel6 = sel6; 45731908Skarels qp->qp_sel10 = sel10; 45831908Skarels 45931908Skarels if (sc->sc_qactive) { /* command in progress */ 46031908Skarels if (cmd == DMV_BACCR) { /* supply read buffers first */ 46131908Skarels QUEUE_AT_HEAD(qp, sc->sc_qhead, sc->sc_qtail); 46231908Skarels } else { 46331908Skarels QUEUE_AT_TAIL(qp, sc->sc_qhead, sc->sc_qtail); 46431908Skarels } 46531908Skarels } else { /* command port free */ 46631908Skarels sc->sc_qactive = qp; 46731908Skarels addr->bsel0 = (DMV_RQI|DMV_IEI|DMV_IEO); 46831908Skarels } 46931908Skarels splx(sps); 47031908Skarels } 47131908Skarels /* 47231908Skarels * DMV interface input interrupt. 47331908Skarels * Ready to accept another command, 47431908Skarels * pull one off the command queue. 47531908Skarels */ 47631908Skarels dmvrint(unit) 47731908Skarels int unit; 47831908Skarels { 47931908Skarels register struct dmv_softc *sc; 48031908Skarels register struct dmvdevice *addr; 48131908Skarels register struct dmv_command *qp; 48231908Skarels register int n; 48331908Skarels 48431908Skarels addr = (struct dmvdevice *)dmvinfo[unit]->ui_addr; 48531908Skarels sc = &dmv_softc[unit]; 48636032Skarels splx(sc->sc_ipl); 48734529Skarels printd(("dmvrint\n")); 48831908Skarels if ((qp = sc->sc_qactive) == (struct dmv_command *) 0) { 48931908Skarels log(LOG_WARNING, "dmvrint: dmv%d no command\n", unit); 49031908Skarels return; 49131908Skarels } 49231908Skarels while (addr->bsel2&DMV_RDI) { 49331908Skarels if(qp->qp_mask&QP_SEL4) 49431908Skarels addr->wsel4 = qp->qp_sel4; 49531908Skarels if(qp->qp_mask&QP_SEL6) 49631908Skarels addr->wsel6 = qp->qp_sel6; 49731908Skarels if(qp->qp_mask&QP_SEL10) { 49831908Skarels addr->wsel10 = qp->qp_sel10; 49931908Skarels qp->qp_cmd |= DMV_22BIT; 50031908Skarels } 50131908Skarels if(qp->qp_mask&QP_TRIB) 50231908Skarels addr->wsel2 = qp->qp_cmd|(qp->qp_tributary << 8); 50331908Skarels else 50431908Skarels addr->bsel2 = qp->qp_cmd; 50531908Skarels QUEUE_AT_HEAD(qp, sc->sc_qfreeh, sc->sc_qfreet); 50631908Skarels if ((sc->sc_qactive = sc->sc_qhead) == (struct dmv_command *)0) 50731908Skarels break; 50831908Skarels qp = sc->sc_qactive; 50931908Skarels DEQUEUE(sc->sc_qhead, sc->sc_qtail); 51031908Skarels if (addr->bsel2&DMV_RDO) 51131908Skarels break; 51231908Skarels } 51331908Skarels if (!sc->sc_qactive) { 51431908Skarels if(addr->bsel2&DMV_RDI) { 51531908Skarels /* clear RQI prior to last command per DMV manual */ 51631908Skarels addr->bsel0 &= ~DMV_RQI; 51731908Skarels addr->wsel6 = DMV_NOP; 51831908Skarels addr->bsel2 = DMV_CNTRLI; 51931908Skarels } 52031908Skarels addr->bsel0 = DMV_IEO; 52131908Skarels } 52231908Skarels else /* RDO set or DMV still holding CSR */ 52331908Skarels addr->bsel0 = (DMV_RQI|DMV_IEI|DMV_IEO); 52431908Skarels 52531908Skarels } 52631908Skarels 52731908Skarels /* 52831908Skarels * DMV interface output interrupt. 52931908Skarels * A transfer may have completed, check for errors. 53031908Skarels * If it was a read, notify appropriate protocol. 53131908Skarels * If it was a write, pull the next one off the queue. 53231908Skarels */ 53331908Skarels dmvxint(unit) 53431908Skarels int unit; 53531908Skarels { 53631908Skarels register struct dmv_softc *sc; 53731908Skarels register struct ifnet *ifp; 53831908Skarels struct uba_device *ui = dmvinfo[unit]; 53931908Skarels struct dmvdevice *addr; 54031908Skarels struct mbuf *m; 54131908Skarels struct ifqueue *inq; 54231908Skarels int sel2, sel3, sel4, sel6, sel10, pkaddr, len, s; 54331908Skarels register struct ifrw *ifrw; 54431908Skarels register struct dmvbufs *rp; 54531908Skarels register struct ifxmt *ifxp; 54631908Skarels struct dmv_header *dh; 54734529Skarels int off, resid; 54831908Skarels 54931908Skarels addr = (struct dmvdevice *)ui->ui_addr; 55031908Skarels sc = &dmv_softc[unit]; 55136032Skarels splx(sc->sc_ipl); 55231908Skarels ifp = &sc->sc_if; 55331908Skarels 55431908Skarels while (addr->bsel2 & DMV_RDO) { 55531908Skarels 55631908Skarels sel2 = addr->bsel2; 55731908Skarels sel3 = addr->bsel3; 55831908Skarels sel4 = addr->wsel4; /* release port */ 55931908Skarels sel6 = addr->wsel6; 56031908Skarels if(sel2 & DMV_22BIT) 56131908Skarels sel10 = addr->wsel10; 56231908Skarels addr->bsel2 &= ~DMV_RDO; 56331908Skarels pkaddr = sel4 | ((sel6 & 0x3f) << 16); 56434529Skarels printd(("dmvxint: sel2=%x sel4=%x sel6=%x sel10=%x pkaddr=%x\n", 56531908Skarels (unsigned) sel2, 56631908Skarels (unsigned) sel4, 56731908Skarels (unsigned) sel6, 56831908Skarels (unsigned) sel10, 56931908Skarels (unsigned) pkaddr 57034529Skarels )); 57131908Skarels if((sc->sc_flag & DMV_RUNNING)==0) { 57231908Skarels log(LOG_WARNING, "dmvxint: dmv%d xint while down\n", unit); 57331908Skarels return; 57431908Skarels } 57531908Skarels switch (sel2 & 07) { 57631908Skarels case DMV_BDRUS: 57731908Skarels /* 57831908Skarels * A read has completed. 57931908Skarels * Pass packet to type specific 58031908Skarels * higher-level input routine. 58131908Skarels */ 58231908Skarels ifp->if_ipackets++; 58331908Skarels /* find location in dmvuba struct */ 58431908Skarels ifrw= &sc->sc_ifr[0]; 58531908Skarels for (rp = &sc->sc_rbufs[0]; rp < &sc->sc_rbufs[NRCV]; rp++) { 58631908Skarels if(rp->ubinfo == pkaddr) 58731908Skarels break; 58831908Skarels ifrw++; 58931908Skarels } 59031908Skarels if (rp >= &sc->sc_rbufs[NRCV]) 59131908Skarels panic("dmv rcv"); 59231908Skarels if ((rp->flags & DBUF_DMVS) == 0) 59331908Skarels log(LOG_WARNING, "dmvxint: dmv%d done unalloc rbuf\n", unit); 59431908Skarels 59531908Skarels len = (sel10&0x3fff) - sizeof (struct dmv_header); 59631908Skarels if (len < 0 || len > DMVMTU) { 59731908Skarels ifp->if_ierrors++; 59831908Skarels log(LOG_ERR, "dmvxint: dmv%d bad rcv pkt addr 0x%x len 0x%x\n", 59931908Skarels unit, pkaddr, len); 60031908Skarels goto setup; 60131908Skarels } 60231908Skarels /* 60331908Skarels * Deal with trailer protocol: if type is trailer 60431908Skarels * get true type from first 16-bit word past data. 60531908Skarels * Remember that type was trailer by setting off. 60631908Skarels */ 60731908Skarels dh = (struct dmv_header *)ifrw->ifrw_addr; 60831908Skarels dh->dmv_type = ntohs((u_short)dh->dmv_type); 60931908Skarels #define dmvdataaddr(dh, off, type) ((type)(((caddr_t)((dh)+1)+(off)))) 61031908Skarels if (dh->dmv_type >= DMV_TRAILER && 61131908Skarels dh->dmv_type < DMV_TRAILER+DMV_NTRAILER) { 61231908Skarels off = (dh->dmv_type - DMV_TRAILER) * 512; 61331908Skarels if (off >= DMVMTU) 61431908Skarels goto setup; /* sanity */ 61531908Skarels dh->dmv_type = ntohs(*dmvdataaddr(dh, off, u_short *)); 61631908Skarels resid = ntohs(*(dmvdataaddr(dh, off+2, u_short *))); 61731908Skarels if (off + resid > len) 61831908Skarels goto setup; /* sanity */ 61931908Skarels len = off + resid; 62031908Skarels } else 62131908Skarels off = 0; 62231908Skarels if (len == 0) 62331908Skarels goto setup; 62431908Skarels 62531908Skarels /* 62631908Skarels * Pull packet off interface. Off is nonzero if 62731908Skarels * packet has trailing header; dmv_get will then 62831908Skarels * force this header information to be at the front, 62931908Skarels * but we still have to drop the type and length 63031908Skarels * which are at the front of any trailer data. 63131908Skarels */ 63231908Skarels m = if_ubaget(&sc->sc_ifuba, ifrw, len, off, ifp); 63331908Skarels if (m == 0) 63431908Skarels goto setup; 63531908Skarels switch (dh->dmv_type) { 63631908Skarels #ifdef INET 63731908Skarels case DMV_IPTYPE: 63831908Skarels schednetisr(NETISR_IP); 63931908Skarels inq = &ipintrq; 64031908Skarels break; 64131908Skarels #endif 64231908Skarels default: 64331908Skarels m_freem(m); 64431908Skarels goto setup; 64531908Skarels } 64631908Skarels 64731908Skarels s = splimp(); 64831908Skarels if (IF_QFULL(inq)) { 64931908Skarels IF_DROP(inq); 65031908Skarels m_freem(m); 65131908Skarels } else 65231908Skarels IF_ENQUEUE(inq, m); 65331908Skarels splx(s); 65431908Skarels setup: 65531908Skarels /* is this needed? */ 65636032Skarels rp->ubinfo = UBAI_ADDR(ifrw->ifrw_info); 65731908Skarels dmvload( 65831908Skarels sc, 65931908Skarels DMV_BACCR, 66031908Skarels QP_SEL4|QP_SEL6|QP_SEL10, 66131908Skarels 0, 66236032Skarels (u_short) rp->ubinfo, 66331908Skarels (rp->ubinfo>>16)&0x3f, 66431908Skarels rp->cc 66531908Skarels ); 66631908Skarels break; 66731908Skarels case DMV_BDXSA: 66831908Skarels /* 66931908Skarels * A write has completed, start another 67031908Skarels * transfer if there is more data to send. 67131908Skarels */ 67231908Skarels ifp->if_opackets++; 67331908Skarels /* find associated dmvbuf structure */ 67431908Skarels ifxp = &sc->sc_ifw[0]; 67531908Skarels for (rp = &sc->sc_xbufs[0]; rp < &sc->sc_xbufs[NXMT]; rp++) { 67631908Skarels if(rp->ubinfo == pkaddr) 67731908Skarels break; 67831908Skarels ifxp++; 67931908Skarels } 68031908Skarels if (rp >= &sc->sc_xbufs[NXMT]) { 68131908Skarels log(LOG_ERR, "dmv%d: bad packet address 0x%x\n", 68231908Skarels unit, pkaddr); 68331908Skarels break; 68431908Skarels } 68531908Skarels if ((rp->flags & DBUF_DMVS) == 0) 68631908Skarels log(LOG_ERR, "dmvxint: dmv%d unallocated packet 0x%x\n", 68731908Skarels unit, pkaddr); 68831908Skarels /* mark buffer free */ 68931908Skarels if (ifxp->ifw_xtofree) { 69031908Skarels (void)m_freem(ifxp->ifw_xtofree); 69131908Skarels ifxp->ifw_xtofree = 0; 69231908Skarels } 69331908Skarels rp->flags &= ~DBUF_DMVS; 69434529Skarels if (--sc->sc_oused == 0) 69534529Skarels sc->sc_if.if_timer = 0; 69634529Skarels else 69734529Skarels sc->sc_if.if_timer = dmv_timeout; 69834529Skarels if ((sc->sc_flag & DMV_ONLINE) == 0) { 69934529Skarels extern int ifqmaxlen; 70034529Skarels 70134529Skarels /* 70234529Skarels * We're on the air. 70334529Skarels * Open the queue to the usual value. 70434529Skarels */ 70534529Skarels sc->sc_flag |= DMV_ONLINE; 70634529Skarels ifp->if_snd.ifq_maxlen = ifqmaxlen; 70734529Skarels } 70831908Skarels break; 70931908Skarels 71031908Skarels case DMV_CNTRLO: 71131908Skarels /* ACCUMULATE STATISTICS */ 71231908Skarels switch(sel6&DMV_EEC) { 71331908Skarels case DMV_ORUN: 71431908Skarels if(sc->sc_flag & DMV_RESTART) { 71531908Skarels load_rec_bufs(sc); 71631908Skarels sc->sc_flag &= ~DMV_RESTART; 71731908Skarels log(LOG_INFO, 71834529Skarels "dmv%d: far end on-line\n", unit); 71931908Skarels } else { 72031908Skarels log(LOG_WARNING, 72134529Skarels "dmv%d: far end restart\n", unit); 72234529Skarels goto restart; 72331908Skarels } 72431908Skarels break; 72531908Skarels case DMV_RTE: 72631908Skarels ifp->if_ierrors++; 72731909Skarels if ((sc->sc_rte++ % DMV_RPRTE) == 0) 72831909Skarels log(LOG_WARNING, 72934529Skarels "dmv%d: receive threshold error\n", 73031909Skarels unit); 73131908Skarels break; 73231908Skarels case DMV_TTE: 73331908Skarels ifp->if_oerrors++; 73431909Skarels if ((sc->sc_xte++ % DMV_RPTTE) == 0) 73531909Skarels log(LOG_WARNING, 73634529Skarels "dmv%d: transmit threshold error\n", 73731909Skarels unit); 73831908Skarels break; 73931908Skarels case DMV_STE: 74031909Skarels if ((sc->sc_ste++ % DMV_RPSTE) == 0) 74131909Skarels log(LOG_WARNING, 74234529Skarels "dmv%d: select threshold error\n", 74331909Skarels unit); 74431908Skarels break; 74531908Skarels case DMV_NXM: 74631909Skarels if ((sc->sc_nxm++ % DMV_RPNXM) == 0) 74731909Skarels log(LOG_WARNING, 74834529Skarels "dmv%d: nonexistent memory error\n", 74931909Skarels unit); 75031908Skarels break; 75131908Skarels case DMV_MODD: 75234529Skarels if ((sc->sc_modd++ % DMV_RPMODD) == 0) { 75331909Skarels log(LOG_WARNING, 75434529Skarels "dmv%d: modem disconnected error\n", 75531909Skarels unit); 75634529Skarels goto restart; 75734529Skarels } 75831908Skarels break; 75931908Skarels case DMV_CXRL: 76031909Skarels if ((sc->sc_cxrl++ % DMV_RPCXRL) == 0) 76131909Skarels log(LOG_WARNING, 76234529Skarels "dmv%d: carrier loss error\n", 76331909Skarels unit); 76431908Skarels break; 76531908Skarels case DMV_QOVF: 76631908Skarels log(LOG_WARNING, 76734529Skarels "dmv%d: response queue overflow\n", 76834529Skarels unit); 76931908Skarels sc->sc_qovf++; 77034529Skarels goto restart; 77131908Skarels 77231908Skarels default: 77331908Skarels log(LOG_WARNING, 77434529Skarels "dmv%d: unknown error %o\n", 77534529Skarels unit, sel6&DMV_EEC); 77631908Skarels if ((sc->sc_unknown++ % DMV_RPUNKNOWN) == 0) 77734529Skarels goto restart; 77831908Skarels break; 77931908Skarels } 78031908Skarels break; 78131908Skarels 78231908Skarels case DMV_BDRUNUS: 78331908Skarels case DMV_BDXSN: 78431908Skarels case DMV_BDXNS: 78531908Skarels log(LOG_INFO, 78634529Skarels "dmv%d: buffer disp for halted trib %o\n", 78731908Skarels unit, sel2&0x7 78831908Skarels ); 78931908Skarels break; 79031908Skarels 79131908Skarels case DMV_MDEFO: 79231908Skarels if((sel6&0x1f) == 020) { 79331908Skarels log(LOG_INFO, 79434529Skarels "dmv%d: buffer return complete sel3=%x\n", 79531908Skarels unit, sel3); 79631908Skarels } else { 79731908Skarels log(LOG_INFO, 79834529Skarels "dmv%d: info resp sel3=%x sel4=%x sel6=%x\n", 79931908Skarels unit, sel3, sel4, sel6 80031908Skarels ); 80131908Skarels } 80231908Skarels break; 80331908Skarels 80431908Skarels default: 80534529Skarels log(LOG_WARNING, "dmv%d: bad control %o\n", 80631908Skarels unit, sel2&0x7 80731908Skarels ); 80831908Skarels break; 80931908Skarels } 81031908Skarels } 81131908Skarels dmvstart(unit); 81231908Skarels return; 81334529Skarels restart: 81431908Skarels dmvrestart(unit); 81531908Skarels } 81634529Skarels 81731908Skarels load_rec_bufs(sc) 81831908Skarels register struct dmv_softc *sc; 81931908Skarels { 82031908Skarels register struct dmvbufs *rp; 82131908Skarels 82231908Skarels /* queue first NRCV buffers for DMV to fill */ 82331908Skarels for (rp = &sc->sc_rbufs[0]; rp < &sc->sc_rbufs[NRCV]; rp++) { 82431908Skarels rp->flags |= DBUF_DMVS; 82531908Skarels dmvload( 82631908Skarels sc, 82731908Skarels DMV_BACCR, 82831908Skarels QP_TRIB|QP_SEL4|QP_SEL6|QP_SEL10, 82931908Skarels 1, 83031908Skarels rp->ubinfo, 83131908Skarels (rp->ubinfo>>16)&0x3f, 83231908Skarels rp->cc 83331908Skarels ); 83431908Skarels sc->sc_iused++; 83531908Skarels } 83631908Skarels } 83731908Skarels 83831908Skarels /* 83931908Skarels * DMV output routine. 84031908Skarels * Encapsulate a packet of type family for the dmv. 84131908Skarels * Use trailer local net encapsulation if enough data in first 84231908Skarels * packet leaves a multiple of 512 bytes of data in remainder. 84331908Skarels */ 84431908Skarels dmvoutput(ifp, m0, dst) 84531908Skarels register struct ifnet *ifp; 84631908Skarels register struct mbuf *m0; 84731908Skarels struct sockaddr *dst; 84831908Skarels { 84931908Skarels int type, error, s; 85031908Skarels register struct mbuf *m = m0; 85131908Skarels register struct dmv_header *dh; 85231908Skarels register int off; 85331908Skarels 85434529Skarels if ((ifp->if_flags & IFF_UP) == 0) { 85534529Skarels error = ENETDOWN; 85634529Skarels goto bad; 85734529Skarels } 85834529Skarels 85931908Skarels switch (dst->sa_family) { 86031908Skarels #ifdef INET 86131908Skarels case AF_INET: 86240843Ssklower off = m->m_pkthdr.len - m->m_len; 86331908Skarels if ((ifp->if_flags & IFF_NOTRAILERS) == 0) 86431908Skarels if (off > 0 && (off & 0x1ff) == 0 && 86540843Ssklower (m->m_flags & M_EXT) == 0 && 86640843Ssklower m->m_data >= m->m_pktdat + 2 * sizeof (u_short)) { 86731908Skarels type = DMV_TRAILER + (off>>9); 86840843Ssklower m->m_data -= 2 * sizeof (u_short); 86931908Skarels m->m_len += 2 * sizeof (u_short); 87031908Skarels *mtod(m, u_short *) = htons((u_short)DMV_IPTYPE); 87131908Skarels *(mtod(m, u_short *) + 1) = htons((u_short)m->m_len); 87231908Skarels goto gottrailertype; 87331908Skarels } 87431908Skarels type = DMV_IPTYPE; 87531908Skarels off = 0; 87631908Skarels goto gottype; 87731908Skarels #endif 87831908Skarels 87931908Skarels case AF_UNSPEC: 88031908Skarels dh = (struct dmv_header *)dst->sa_data; 88131908Skarels type = dh->dmv_type; 88231908Skarels goto gottype; 88331908Skarels 88431908Skarels default: 88534529Skarels log(LOG_ERR, "dmvoutput, dmv%d can't handle af%d\n", 88634529Skarels ifp->if_unit, dst->sa_family); 88731908Skarels error = EAFNOSUPPORT; 88831908Skarels goto bad; 88931908Skarels } 89031908Skarels 89131908Skarels gottrailertype: 89231908Skarels /* 89331908Skarels * Packet to be sent as a trailer; move first packet 89431908Skarels * (control information) to end of chain. 89531908Skarels */ 89631908Skarels while (m->m_next) 89731908Skarels m = m->m_next; 89831908Skarels m->m_next = m0; 89931908Skarels m = m0->m_next; 90031908Skarels m0->m_next = 0; 90131908Skarels m0 = m; 90231908Skarels 90331908Skarels gottype: 90431908Skarels /* 90531908Skarels * Add local network header 90631908Skarels * (there is space for a uba on a vax to step on) 90731908Skarels */ 90840843Ssklower M_PREPEND(m, sizeof(struct dmv_header), M_DONTWAIT); 90940843Ssklower if (m == 0) { 91040843Ssklower error = ENOBUFS; 91140843Ssklower goto bad; 91231908Skarels } 91331908Skarels dh = mtod(m, struct dmv_header *); 91431908Skarels dh->dmv_type = htons((u_short)type); 91531908Skarels 91631908Skarels /* 91731908Skarels * Queue message on interface, and start output if interface 91831908Skarels * not yet active. 91931908Skarels */ 92031908Skarels s = splimp(); 92131908Skarels if (IF_QFULL(&ifp->if_snd)) { 92231908Skarels IF_DROP(&ifp->if_snd); 92331908Skarels m_freem(m); 92431908Skarels splx(s); 92531908Skarels return (ENOBUFS); 92631908Skarels } 92731908Skarels IF_ENQUEUE(&ifp->if_snd, m); 92831908Skarels dmvstart(ifp->if_unit); 92931908Skarels splx(s); 93031908Skarels return (0); 93131908Skarels 93231908Skarels bad: 93331908Skarels m_freem(m0); 93431908Skarels return (error); 93531908Skarels } 93631908Skarels 93731908Skarels 93831908Skarels /* 93931908Skarels * Process an ioctl request. 94031908Skarels */ 94131908Skarels /* ARGSUSED */ 94231908Skarels dmvioctl(ifp, cmd, data) 94331908Skarels register struct ifnet *ifp; 94431908Skarels int cmd; 94531908Skarels caddr_t data; 94631908Skarels { 94731908Skarels int s = splimp(), error = 0; 94831908Skarels struct mbuf *m; 94931908Skarels register struct dmv_softc *sc = &dmv_softc[ifp->if_unit]; 95031908Skarels 95131908Skarels switch (cmd) { 95231908Skarels 95331908Skarels case SIOCSIFADDR: 95431908Skarels ifp->if_flags |= IFF_UP; 95531908Skarels if ((ifp->if_flags & IFF_RUNNING) == 0) 95631908Skarels dmvinit(ifp->if_unit); 95731908Skarels break; 95831908Skarels 95931908Skarels case SIOCSIFDSTADDR: 96031908Skarels if ((ifp->if_flags & IFF_RUNNING) == 0) 96131908Skarels dmvinit(ifp->if_unit); 96231908Skarels break; 96331908Skarels 96431908Skarels case SIOCSIFFLAGS: 96531908Skarels if ((ifp->if_flags & IFF_UP) == 0 && 96634529Skarels sc->sc_flag & DMV_RUNNING) 96734529Skarels dmvdown(ifp->if_unit); 96834529Skarels else if (ifp->if_flags & IFF_UP && 96931908Skarels (sc->sc_flag & DMV_RUNNING) == 0) 97031908Skarels dmvrestart(ifp->if_unit); 97131908Skarels break; 97231908Skarels 97331908Skarels default: 97431908Skarels error = EINVAL; 97531908Skarels } 97631908Skarels splx(s); 97731908Skarels return (error); 97831908Skarels } 97931908Skarels 98031908Skarels /* 98131908Skarels * Restart after a fatal error. 98231908Skarels * Clear device and reinitialize. 98331908Skarels */ 98431908Skarels dmvrestart(unit) 98531908Skarels int unit; 98631908Skarels { 98731908Skarels register struct dmvdevice *addr; 98831908Skarels register int i; 98934529Skarels 99034529Skarels dmvdown(unit); 99134529Skarels 99234529Skarels addr = (struct dmvdevice *)(dmvinfo[unit]->ui_addr); 99331908Skarels /* 99434529Skarels * Let the DMV finish the MCLR. 99531908Skarels */ 99631908Skarels for (i = 100000; i && (addr->bsel1 & DMV_RUN) == 0; i--) 99731908Skarels ; 99831908Skarels if ((addr->bsel1 & DMV_RUN) == 0) { 99931908Skarels log(LOG_ERR, "dmvrestart: can't start device\n" ); 100031908Skarels return (0); 100131908Skarels } 100231908Skarels if ((addr->bsel4 != 033) || (addr->bsel6 != 0305)) 100331908Skarels { 100434529Skarels log(LOG_ERR, "dmv%d: device init failed, bsel4=%o, bsel6=%o\n", 100534529Skarels unit, addr->bsel4, addr->bsel6); 100631908Skarels return (0); 100731908Skarels } 100834529Skarels 100934529Skarels /* restart DMV */ 101034529Skarels dmvinit(unit); 101134529Skarels dmv_softc[unit].sc_if.if_collisions++; /* why not? */ 101234529Skarels } 101334529Skarels 101434529Skarels /* 101534529Skarels * Reset a device and mark down. 101634529Skarels * Flush output queue and drop queue limit. 101734529Skarels */ 101834529Skarels dmvdown(unit) 101934529Skarels int unit; 102034529Skarels { 102134529Skarels struct dmv_softc *sc = &dmv_softc[unit]; 102234529Skarels register struct ifxmt *ifxp; 102334529Skarels 102434529Skarels ((struct dmvdevice *)(dmvinfo[unit]->ui_addr))->bsel1 = DMV_MCLR; 102534529Skarels sc->sc_flag &= ~(DMV_RUNNING | DMV_ONLINE); 102634529Skarels 102731908Skarels for (ifxp = sc->sc_ifw; ifxp < &sc->sc_ifw[NXMT]; ifxp++) { 102831908Skarels if (ifxp->ifw_xtofree) { 102931908Skarels (void) m_freem(ifxp->ifw_xtofree); 103031908Skarels ifxp->ifw_xtofree = 0; 103131908Skarels } 103231908Skarels } 103334529Skarels sc->sc_oused = 0; 103434529Skarels if_qflush(&sc->sc_if.if_snd); 103534529Skarels 103634529Skarels /* 103734529Skarels * Limit packets enqueued until we're back on the air. 103834529Skarels */ 103934529Skarels sc->sc_if.if_snd.ifq_maxlen = 3; 104031908Skarels } 104131908Skarels 104231908Skarels /* 104334529Skarels * Watchdog timeout to see that transmitted packets don't 104434529Skarels * lose interrupts. The device has to be online. 104531908Skarels */ 104634529Skarels dmvtimeout(unit) 104734529Skarels int unit; 104831908Skarels { 104931908Skarels register struct dmv_softc *sc; 105031908Skarels struct dmvdevice *addr; 105131908Skarels 105234529Skarels sc = &dmv_softc[unit]; 105334529Skarels if (sc->sc_flag & DMV_ONLINE) { 105434529Skarels addr = (struct dmvdevice *)(dmvinfo[unit]->ui_addr); 105534529Skarels log(LOG_ERR, "dmv%d: output timeout, bsel0=%b bsel2=%b\n", 105634529Skarels unit, addr->bsel0 & 0xff, DMV0BITS, 105734529Skarels addr->bsel2 & 0xff, DMV2BITS); 105834529Skarels dmvrestart(unit); 105931908Skarels } 106031908Skarels } 106131908Skarels #endif 1062