131908Skarels /* 234727Smckusick * Copyright (c) 1988 Regents of the University of California. 334727Smckusick * All rights reserved. 434727Smckusick * 534727Smckusick * Redistribution and use in source and binary forms are permitted 634868Sbostic * provided that the above copyright notice and this paragraph are 734868Sbostic * duplicated in all such forms and that any documentation, 834868Sbostic * advertising materials, and other materials related to such 934868Sbostic * distribution and use acknowledge that the software was developed 1034868Sbostic * by the University of California, Berkeley. The name of the 1134868Sbostic * University may not be used to endorse or promote products derived 1234868Sbostic * from this software without specific prior written permission. 1334868Sbostic * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR 1434868Sbostic * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED 1534868Sbostic * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. 1634727Smckusick * 17*36032Skarels * @(#)if_dmv.c 7.7 (Berkeley) 10/22/88 1834868Sbostic */ 1934868Sbostic 2034868Sbostic /* 2131908Skarels * DMV-11 Driver 2231908Skarels * 2331908Skarels * Qbus Sync DDCMP interface - DMV operated in full duplex, point to point mode 2431908Skarels * 2534727Smckusick * Written by Bob Kridle of Mt Xinu 2634727Smckusick * starting from if_dmc.c version 6.12 dated 4/23/86 2731908Skarels */ 2831908Skarels 2931908Skarels #include "dmv.h" 3031908Skarels #if NDMV > 0 3131908Skarels 3231908Skarels #include "param.h" 3331908Skarels #include "systm.h" 3431908Skarels #include "mbuf.h" 3531908Skarels #include "buf.h" 3631908Skarels #include "ioctl.h" /* must precede tty.h */ 3731908Skarels #include "tty.h" 3831908Skarels #include "protosw.h" 3931908Skarels #include "socket.h" 4031908Skarels #include "syslog.h" 4131908Skarels #include "vmmac.h" 4231908Skarels #include "errno.h" 4334529Skarels #include "time.h" 4434529Skarels #include "kernel.h" 4531908Skarels 4631908Skarels #include "../net/if.h" 4731908Skarels #include "../net/netisr.h" 4831908Skarels #include "../net/route.h" 4931908Skarels 5031908Skarels #ifdef INET 5131908Skarels #include "../netinet/in.h" 5231908Skarels #include "../netinet/in_systm.h" 5331908Skarels #include "../netinet/in_var.h" 5431908Skarels #include "../netinet/ip.h" 5531908Skarels #endif 5631908Skarels 5731908Skarels #include "../vax/cpu.h" 5831908Skarels #include "../vax/mtpr.h" 5934529Skarels #include "../vax/pte.h" 6034529Skarels #include "../vaxuba/ubareg.h" 6134529Skarels #include "../vaxuba/ubavar.h" 6231908Skarels #include "if_uba.h" 6331908Skarels #include "if_dmv.h" 6431908Skarels 6531908Skarels int dmv_timeout = 8; /* timeout value */ 6631908Skarels 6731908Skarels /* 6831908Skarels * Driver information for auto-configuration stuff. 6931908Skarels */ 7031908Skarels int dmvprobe(), dmvattach(), dmvinit(), dmvioctl(); 7134529Skarels int dmvoutput(), dmvreset(), dmvtimeout(); 7231908Skarels struct uba_device *dmvinfo[NDMV]; 7331908Skarels u_short dmvstd[] = { 0 }; 7431908Skarels struct uba_driver dmvdriver = 7531908Skarels { dmvprobe, 0, dmvattach, 0, dmvstd, "dmv", dmvinfo }; 7631908Skarels 7731908Skarels /* 7831908Skarels * Don't really know how many buffers/commands can be queued to a DMV-11. 7931908Skarels * Manual doesn't say... Perhaps we can look at a DEC driver some day. 8034529Skarels * These numbers ame from DMC/DMR driver. 8131908Skarels */ 8231908Skarels #define NRCV 5 8331908Skarels #define NXMT 3 8431908Skarels #define NCMDS (NRCV+NXMT+4) /* size of command queue */ 8531908Skarels 8634529Skarels #ifdef DEBUG 8734529Skarels #define printd(f) if (sc->sc_if.if_flags & IFF_DEBUG) \ 8834529Skarels printf("DMVDEBUG: dmv%d: ", unit), printf(f) 8934529Skarels #else 9034529Skarels #define printd(f) /* nil */ 9134529Skarels #endif 9231908Skarels 9331908Skarels /* error reporting intervals */ 9431908Skarels 9531908Skarels #define DMV_RPRTE 1 9631908Skarels #define DMV_RPTTE 1 9731908Skarels #define DMV_RPSTE 1 9831908Skarels #define DMV_RPNXM 1 9931908Skarels #define DMV_RPMODD 1 10031908Skarels #define DMV_RPQOVF 1 10131908Skarels #define DMV_RPCXRL 1 10231908Skarels 10331909Skarels /* number of errors to accept before trying a reset */ 10431909Skarels #define DMV_RPUNKNOWN 10 10531909Skarels 10631908Skarels struct dmv_command { 10731908Skarels u_char qp_mask; /* Which registers to set up */ 10831908Skarels #define QP_TRIB 0x01 10931908Skarels #define QP_SEL4 0x02 11031908Skarels #define QP_SEL6 0x04 11131908Skarels #define QP_SEL10 0x08 11231908Skarels u_char qp_cmd; 11331908Skarels u_char qp_tributary; 11431908Skarels u_short qp_sel4; 11531908Skarels u_short qp_sel6; 11631908Skarels u_short qp_sel10; 11731908Skarels struct dmv_command *qp_next; /* next command on queue */ 11831908Skarels }; 11931908Skarels 12031908Skarels #define qp_lowbufaddr qp_ 12131908Skarels 12231908Skarels struct dmvbufs { 12331908Skarels int ubinfo; /* from uballoc */ 12431908Skarels short cc; /* buffer size */ 12531908Skarels short flags; /* access control */ 12631908Skarels }; 12731908Skarels 12831908Skarels #define DBUF_OURS 0 /* buffer is available */ 12931908Skarels #define DBUF_DMVS 1 /* buffer claimed by somebody */ 13031908Skarels #define DBUF_XMIT 4 /* transmit buffer */ 13131908Skarels #define DBUF_RCV 8 /* receive buffer */ 13231908Skarels 13331908Skarels 13431908Skarels /* 13531908Skarels * DMV software status per interface. 13631908Skarels * 13731908Skarels * Each interface is referenced by a network interface structure, 13831908Skarels * sc_if, which the routing code uses to locate the interface. 13931908Skarels * This structure contains the output queue for the interface, its address, ... 14031908Skarels * We also have, for each interface, a set of 7 UBA interface structures 14131908Skarels * for each, which 14231908Skarels * contain information about the UNIBUS resources held by the interface: 14331908Skarels * map registers, buffered data paths, etc. Information is cached in this 14431908Skarels * structure for use by the if_uba.c routines in running the interface 14531908Skarels * efficiently. 14631908Skarels */ 14731908Skarels struct dmv_softc { 14831908Skarels struct ifnet sc_if; /* network-visible interface */ 14931908Skarels short sc_oused; /* output buffers currently in use */ 15031908Skarels short sc_iused; /* input buffers given to DMV */ 15131908Skarels short sc_flag; /* flags */ 152*36032Skarels short sc_ipl; /* interrupt priority */ 15331908Skarels int sc_ubinfo; /* UBA mapping info for base table */ 15431908Skarels int sc_errors[8]; /* error counters */ 15531908Skarels #define sc_rte sc_errors[0] /* receive threshhold error */ 15631908Skarels #define sc_xte sc_errors[1] /* xmit threshhold error */ 15731908Skarels #define sc_ste sc_errors[2] /* select threshhold error */ 15831908Skarels #define sc_nxm sc_errors[3] /* non-existant memory */ 15931908Skarels #define sc_modd sc_errors[4] /* modem disconnect */ 16031908Skarels #define sc_qovf sc_errors[5] /* command/response queue overflow */ 16131908Skarels #define sc_cxrl sc_errors[6] /* carrier loss */ 16231908Skarels #define sc_unknown sc_errors[7] /* other errors - look in DMV manual */ 16334529Skarels struct dmvbufs sc_rbufs[NRCV]; /* receive buffer info */ 16434529Skarels struct dmvbufs sc_xbufs[NXMT]; /* transmit buffer info */ 16534529Skarels struct ifubinfo sc_ifuba; /* UNIBUS resources */ 16634529Skarels struct ifrw sc_ifr[NRCV]; /* UNIBUS receive buffer maps */ 16734529Skarels struct ifxmt sc_ifw[NXMT]; /* UNIBUS receive buffer maps */ 16831908Skarels /* command queue stuff */ 16931908Skarels struct dmv_command sc_cmdbuf[NCMDS]; 17031908Skarels struct dmv_command *sc_qhead; /* head of command queue */ 17131908Skarels struct dmv_command *sc_qtail; /* tail of command queue */ 17231908Skarels struct dmv_command *sc_qactive; /* command in progress */ 17331908Skarels struct dmv_command *sc_qfreeh; /* head of list of free cmd buffers */ 17431908Skarels struct dmv_command *sc_qfreet; /* tail of list of free cmd buffers */ 17531908Skarels /* end command queue stuff */ 17631908Skarels } dmv_softc[NDMV]; 17731908Skarels 17831908Skarels /* flags */ 17934529Skarels #define DMV_RESTART 0x01 /* software restart in progress */ 18034529Skarels #define DMV_ONLINE 0x02 /* device managed to transmit */ 18134529Skarels #define DMV_RUNNING 0x04 /* device initialized */ 18231908Skarels 18331908Skarels 18431908Skarels /* queue manipulation macros */ 18531908Skarels #define QUEUE_AT_HEAD(qp, head, tail) \ 18631908Skarels (qp)->qp_next = (head); \ 18731908Skarels (head) = (qp); \ 18831908Skarels if ((tail) == (struct dmv_command *) 0) \ 18931908Skarels (tail) = (head) 19031908Skarels 19131908Skarels #define QUEUE_AT_TAIL(qp, head, tail) \ 19231908Skarels if ((tail)) \ 19331908Skarels (tail)->qp_next = (qp); \ 19431908Skarels else \ 19531908Skarels (head) = (qp); \ 19631908Skarels (qp)->qp_next = (struct dmv_command *) 0; \ 19731908Skarels (tail) = (qp) 19831908Skarels 19931908Skarels #define DEQUEUE(head, tail) \ 20031908Skarels (head) = (head)->qp_next;\ 20131908Skarels if ((head) == (struct dmv_command *) 0)\ 20231908Skarels (tail) = (head) 20331908Skarels 204*36032Skarels dmvprobe(reg, ui) 20531908Skarels caddr_t reg; 206*36032Skarels struct uba_device *ui; 20731908Skarels { 20831908Skarels register int br, cvec; 20931908Skarels register struct dmvdevice *addr = (struct dmvdevice *)reg; 21031908Skarels register int i; 21131908Skarels 21231908Skarels #ifdef lint 21331908Skarels br = 0; cvec = br; br = cvec; 21431908Skarels dmvrint(0); dmvxint(0); 21531908Skarels #endif 21631908Skarels addr->bsel1 = DMV_MCLR; 21731908Skarels for (i = 100000; i && (addr->bsel1 & DMV_RUN) == 0; i--) 21831908Skarels ; 21931908Skarels if ((addr->bsel1 & DMV_RUN) == 0) { 22031908Skarels printf("dmvprobe: can't start device\n" ); 22131908Skarels return (0); 22231908Skarels } 22331908Skarels if ((addr->bsel4 != 033) || (addr->bsel6 != 0305)) 22431908Skarels { 22531908Skarels printf("dmvprobe: device init failed, bsel4=%o, bsel6=%o\n", 22631908Skarels addr->bsel4, addr->bsel6); 22731908Skarels return (0); 22831908Skarels } 229*36032Skarels (void) spl6(); 23031908Skarels addr->bsel0 = DMV_RQI|DMV_IEI|DMV_IEO; 23131908Skarels DELAY(1000000); 23231908Skarels addr->bsel1 = DMV_MCLR; 23331908Skarels for (i = 100000; i && (addr->bsel1 & DMV_RUN) == 0; i--) 23431908Skarels ; 235*36032Skarels dmv_softc[ui->ui_unit].sc_ipl = br = qbgetpri(); 236*36032Skarels return (sizeof(struct dmvdevice)); 23731908Skarels } 23831908Skarels 23931908Skarels /* 24031908Skarels * Interface exists: make available by filling in network interface 24131908Skarels * record. System will initialize the interface when it is ready 24231908Skarels * to accept packets. 24331908Skarels */ 24431908Skarels dmvattach(ui) 24531908Skarels register struct uba_device *ui; 24631908Skarels { 24731908Skarels register struct dmv_softc *sc = &dmv_softc[ui->ui_unit]; 24831908Skarels 24931908Skarels sc->sc_if.if_unit = ui->ui_unit; 25031908Skarels sc->sc_if.if_name = "dmv"; 25131908Skarels sc->sc_if.if_mtu = DMVMTU; 25231908Skarels sc->sc_if.if_init = dmvinit; 25331908Skarels sc->sc_if.if_output = dmvoutput; 25431908Skarels sc->sc_if.if_ioctl = dmvioctl; 25531908Skarels sc->sc_if.if_reset = dmvreset; 25634529Skarels sc->sc_if.if_watchdog = dmvtimeout; 25731908Skarels sc->sc_if.if_flags = IFF_POINTOPOINT; 25831908Skarels sc->sc_ifuba.iff_flags = UBA_CANTWAIT; 25931908Skarels 26031908Skarels if_attach(&sc->sc_if); 26131908Skarels } 26231908Skarels 26331908Skarels /* 26431908Skarels * Reset of interface after UNIBUS reset. 26531908Skarels * If interface is on specified UBA, reset its state. 26631908Skarels */ 26731908Skarels dmvreset(unit, uban) 26831908Skarels int unit, uban; 26931908Skarels { 27031908Skarels register struct uba_device *ui; 27131908Skarels register struct dmv_softc *sc = &dmv_softc[unit]; 27231908Skarels 27331908Skarels if (unit >= NDMV || (ui = dmvinfo[unit]) == 0 || ui->ui_alive == 0 || 27431908Skarels ui->ui_ubanum != uban) 27531908Skarels return; 27631908Skarels printf(" dmv%d", unit); 27731908Skarels sc->sc_flag = 0; 27831908Skarels sc->sc_if.if_flags &= ~IFF_RUNNING; 27931908Skarels dmvinit(unit); 28031908Skarels } 28131908Skarels 28231908Skarels /* 28331908Skarels * Initialization of interface; reinitialize UNIBUS usage. 28431908Skarels */ 28531908Skarels dmvinit(unit) 28631908Skarels int unit; 28731908Skarels { 28831908Skarels register struct dmv_softc *sc = &dmv_softc[unit]; 28931908Skarels register struct uba_device *ui = dmvinfo[unit]; 29031908Skarels register struct dmvdevice *addr; 29131908Skarels register struct ifnet *ifp = &sc->sc_if; 29231908Skarels register struct ifrw *ifrw; 29331908Skarels register struct ifxmt *ifxp; 29431908Skarels register struct dmvbufs *rp; 29531908Skarels register struct dmv_command *qp; 29631908Skarels struct ifaddr *ifa; 29731908Skarels int base; 29831908Skarels int s; 29931908Skarels 30031908Skarels addr = (struct dmvdevice *)ui->ui_addr; 30131908Skarels 30231908Skarels /* 30331908Skarels * Check to see that an address has been set 30431908Skarels * (both local and destination for an address family). 30531908Skarels */ 30631908Skarels for (ifa = ifp->if_addrlist; ifa; ifa = ifa->ifa_next) 30731908Skarels if (ifa->ifa_addr.sa_family && ifa->ifa_dstaddr.sa_family) 30831908Skarels break; 30931908Skarels if (ifa == (struct ifaddr *) 0) 31031908Skarels return; 31131908Skarels 31231908Skarels if ((addr->bsel1&DMV_RUN) == 0) { 31331908Skarels log(LOG_CRIT, "dmvinit: dmv%d not running\n", unit); 31431908Skarels ifp->if_flags &= ~IFF_UP; 31531908Skarels return; 31631908Skarels } 31734529Skarels printd(("dmvinit\n")); 31831908Skarels /* initialize UNIBUS resources */ 31931908Skarels sc->sc_iused = sc->sc_oused = 0; 32031908Skarels if ((ifp->if_flags & IFF_RUNNING) == 0) { 32131908Skarels if (if_ubaminit( 32231908Skarels &sc->sc_ifuba, 32331908Skarels ui->ui_ubanum, 32431908Skarels sizeof(struct dmv_header), 32531908Skarels (int)btoc(DMVMTU), 32631908Skarels sc->sc_ifr, 32731908Skarels NRCV, 32831908Skarels sc->sc_ifw, 32931908Skarels NXMT 33031908Skarels ) == 0) { 33131908Skarels log(LOG_CRIT, "dmvinit: dmv%d can't allocate uba resources\n", unit); 33231908Skarels ifp->if_flags &= ~IFF_UP; 33331908Skarels return; 33431908Skarels } 33531908Skarels ifp->if_flags |= IFF_RUNNING; 33631908Skarels } 33734529Skarels /* 33834529Skarels * Limit packets enqueued until we see if we're on the air. 33934529Skarels */ 34034529Skarels ifp->if_snd.ifq_maxlen = 3; 34131908Skarels 34234529Skarels 34331908Skarels /* initialize buffer pool */ 34431908Skarels /* receives */ 34531908Skarels ifrw = &sc->sc_ifr[0]; 34631908Skarels for (rp = &sc->sc_rbufs[0]; rp < &sc->sc_rbufs[NRCV]; rp++) { 347*36032Skarels rp->ubinfo = UBAI_ADDR(ifrw->ifrw_info); 34831908Skarels rp->cc = DMVMTU + sizeof (struct dmv_header); 34931908Skarels rp->flags = DBUF_OURS|DBUF_RCV; 35031908Skarels ifrw++; 35131908Skarels } 35231908Skarels /* transmits */ 35331908Skarels ifxp = &sc->sc_ifw[0]; 35431908Skarels for (rp = &sc->sc_xbufs[0]; rp < &sc->sc_xbufs[NXMT]; rp++) { 355*36032Skarels rp->ubinfo = UBAI_ADDR(ifxp->ifw_info); 35631908Skarels rp->cc = 0; 35731908Skarels rp->flags = DBUF_OURS|DBUF_XMIT; 35831908Skarels ifxp++; 35931908Skarels } 36031908Skarels 36131908Skarels /* set up command queues */ 36231908Skarels sc->sc_qfreeh = sc->sc_qfreet 36331908Skarels = sc->sc_qhead = sc->sc_qtail = sc->sc_qactive = 36431908Skarels (struct dmv_command *)0; 36531908Skarels /* set up free command buffer list */ 36631908Skarels for (qp = &sc->sc_cmdbuf[0]; qp < &sc->sc_cmdbuf[NCMDS]; qp++) { 36731908Skarels QUEUE_AT_HEAD(qp, sc->sc_qfreeh, sc->sc_qfreet); 36831908Skarels } 36931908Skarels if(sc->sc_flag & DMV_RUNNING) 37031908Skarels dmvload( sc, DMV_CNTRLI, (QP_TRIB|QP_SEL6), 1, 0, DMV_REQHS,0); 37131908Skarels else 37231908Skarels dmvload( sc, DMV_CNTRLI, (QP_TRIB|QP_SEL6), 1, 0, DMV_ESTTRIB,0); 37331908Skarels dmvload( sc, DMV_CNTRLI, (QP_TRIB|QP_SEL6), 1, 0, DMV_REQSUS,0); 37431908Skarels sc->sc_flag |= (DMV_RESTART|DMV_RUNNING); 37534529Skarels sc->sc_flag &= ~DMV_ONLINE; 37631908Skarels addr->bsel0 |= DMV_IEO; 37731908Skarels } 37831908Skarels 37931908Skarels /* 38031908Skarels * Start output on interface. Get another datagram 38131908Skarels * to send from the interface queue and map it to 38231908Skarels * the interface before starting output. 38331908Skarels * 38431908Skarels * Must be called at spl 5 38531908Skarels */ 38631908Skarels dmvstart(dev) 38731908Skarels dev_t dev; 38831908Skarels { 38931908Skarels int unit = minor(dev); 39031908Skarels register struct dmv_softc *sc = &dmv_softc[unit]; 39131908Skarels struct mbuf *m; 39231908Skarels register struct dmvbufs *rp; 39331908Skarels register int n; 39431908Skarels 39531908Skarels /* 39631908Skarels * Dequeue up to NXMT requests and map them to the UNIBUS. 39731908Skarels * If no more requests, or no dmv buffers available, just return. 39831908Skarels */ 39934529Skarels printd(("dmvstart\n")); 40031908Skarels n = 0; 40131908Skarels for (rp = &sc->sc_xbufs[0]; rp < &sc->sc_xbufs[NXMT]; rp++ ) { 40231908Skarels /* find an available buffer */ 40331908Skarels if ((rp->flags & DBUF_DMVS) == 0) { 40431908Skarels IF_DEQUEUE(&sc->sc_if.if_snd, m); 40531908Skarels if (m == 0) 40631908Skarels return; 40731908Skarels /* mark it dmvs */ 40831908Skarels rp->flags |= (DBUF_DMVS); 40931908Skarels /* 41031908Skarels * Have request mapped to UNIBUS for transmission 41131908Skarels * and start the output. 41231908Skarels */ 41331908Skarels rp->cc = if_ubaput(&sc->sc_ifuba, &sc->sc_ifw[n], m); 41434529Skarels if (++sc->sc_oused == 1) 41534529Skarels sc->sc_if.if_timer = dmv_timeout; 41631908Skarels dmvload( 41731908Skarels sc, 41831908Skarels DMV_BACCX, 41931908Skarels QP_TRIB|QP_SEL4|QP_SEL6|QP_SEL10, 42031908Skarels 1, 42131908Skarels rp->ubinfo, 42231908Skarels (rp->ubinfo>>16)&0x3f, 42331908Skarels rp->cc 42431908Skarels ); 42531908Skarels } 42631908Skarels n++; 42731908Skarels } 42831908Skarels } 42931908Skarels 43031908Skarels /* 43131908Skarels * Utility routine to load the DMV device registers. 43231908Skarels */ 43331908Skarels dmvload(sc, cmd, mask, tributary, sel4, sel6, sel10) 43431908Skarels register struct dmv_softc *sc; 43531908Skarels u_char cmd, tributary, mask; 43631908Skarels u_short sel4, sel6, sel10; 43731908Skarels { 43831908Skarels register struct dmvdevice *addr; 43931908Skarels register int unit, sps; 44031908Skarels register struct dmv_command *qp; 44131908Skarels 44231908Skarels unit = sc - dmv_softc; 44334529Skarels printd(("dmvload: cmd=%x mask=%x trib=%x sel4=%x sel6=%x sel10=%x\n", 44431908Skarels (unsigned) cmd, 44531908Skarels (unsigned) mask, 44631908Skarels (unsigned) tributary, 44731908Skarels (unsigned) sel4, 44831908Skarels (unsigned) sel6, 44931908Skarels (unsigned) sel10 45034529Skarels )); 45131908Skarels addr = (struct dmvdevice *)dmvinfo[unit]->ui_addr; 45231908Skarels sps = spl5(); 45331908Skarels 45431908Skarels /* grab a command buffer from the free list */ 45531908Skarels if ((qp = sc->sc_qfreeh) == (struct dmv_command *)0) 45631908Skarels panic("dmv command queue overflow"); 45731908Skarels DEQUEUE(sc->sc_qfreeh, sc->sc_qfreet); 45831908Skarels 45931908Skarels /* fill in requested info */ 46031908Skarels qp->qp_cmd = cmd; 46131908Skarels qp->qp_mask = mask; 46231908Skarels qp->qp_tributary = tributary; 46331908Skarels qp->qp_sel4 = sel4; 46431908Skarels qp->qp_sel6 = sel6; 46531908Skarels qp->qp_sel10 = sel10; 46631908Skarels 46731908Skarels if (sc->sc_qactive) { /* command in progress */ 46831908Skarels if (cmd == DMV_BACCR) { /* supply read buffers first */ 46931908Skarels QUEUE_AT_HEAD(qp, sc->sc_qhead, sc->sc_qtail); 47031908Skarels } else { 47131908Skarels QUEUE_AT_TAIL(qp, sc->sc_qhead, sc->sc_qtail); 47231908Skarels } 47331908Skarels } else { /* command port free */ 47431908Skarels sc->sc_qactive = qp; 47531908Skarels addr->bsel0 = (DMV_RQI|DMV_IEI|DMV_IEO); 47631908Skarels } 47731908Skarels splx(sps); 47831908Skarels } 47931908Skarels /* 48031908Skarels * DMV interface input interrupt. 48131908Skarels * Ready to accept another command, 48231908Skarels * pull one off the command queue. 48331908Skarels */ 48431908Skarels dmvrint(unit) 48531908Skarels int unit; 48631908Skarels { 48731908Skarels register struct dmv_softc *sc; 48831908Skarels register struct dmvdevice *addr; 48931908Skarels register struct dmv_command *qp; 49031908Skarels register int n; 49131908Skarels 49231908Skarels addr = (struct dmvdevice *)dmvinfo[unit]->ui_addr; 49331908Skarels sc = &dmv_softc[unit]; 494*36032Skarels splx(sc->sc_ipl); 49534529Skarels printd(("dmvrint\n")); 49631908Skarels if ((qp = sc->sc_qactive) == (struct dmv_command *) 0) { 49731908Skarels log(LOG_WARNING, "dmvrint: dmv%d no command\n", unit); 49831908Skarels return; 49931908Skarels } 50031908Skarels while (addr->bsel2&DMV_RDI) { 50131908Skarels if(qp->qp_mask&QP_SEL4) 50231908Skarels addr->wsel4 = qp->qp_sel4; 50331908Skarels if(qp->qp_mask&QP_SEL6) 50431908Skarels addr->wsel6 = qp->qp_sel6; 50531908Skarels if(qp->qp_mask&QP_SEL10) { 50631908Skarels addr->wsel10 = qp->qp_sel10; 50731908Skarels qp->qp_cmd |= DMV_22BIT; 50831908Skarels } 50931908Skarels if(qp->qp_mask&QP_TRIB) 51031908Skarels addr->wsel2 = qp->qp_cmd|(qp->qp_tributary << 8); 51131908Skarels else 51231908Skarels addr->bsel2 = qp->qp_cmd; 51331908Skarels QUEUE_AT_HEAD(qp, sc->sc_qfreeh, sc->sc_qfreet); 51431908Skarels if ((sc->sc_qactive = sc->sc_qhead) == (struct dmv_command *)0) 51531908Skarels break; 51631908Skarels qp = sc->sc_qactive; 51731908Skarels DEQUEUE(sc->sc_qhead, sc->sc_qtail); 51831908Skarels if (addr->bsel2&DMV_RDO) 51931908Skarels break; 52031908Skarels } 52131908Skarels if (!sc->sc_qactive) { 52231908Skarels if(addr->bsel2&DMV_RDI) { 52331908Skarels /* clear RQI prior to last command per DMV manual */ 52431908Skarels addr->bsel0 &= ~DMV_RQI; 52531908Skarels addr->wsel6 = DMV_NOP; 52631908Skarels addr->bsel2 = DMV_CNTRLI; 52731908Skarels } 52831908Skarels addr->bsel0 = DMV_IEO; 52931908Skarels } 53031908Skarels else /* RDO set or DMV still holding CSR */ 53131908Skarels addr->bsel0 = (DMV_RQI|DMV_IEI|DMV_IEO); 53231908Skarels 53331908Skarels } 53431908Skarels 53531908Skarels /* 53631908Skarels * DMV interface output interrupt. 53731908Skarels * A transfer may have completed, check for errors. 53831908Skarels * If it was a read, notify appropriate protocol. 53931908Skarels * If it was a write, pull the next one off the queue. 54031908Skarels */ 54131908Skarels dmvxint(unit) 54231908Skarels int unit; 54331908Skarels { 54431908Skarels register struct dmv_softc *sc; 54531908Skarels register struct ifnet *ifp; 54631908Skarels struct uba_device *ui = dmvinfo[unit]; 54731908Skarels struct dmvdevice *addr; 54831908Skarels struct mbuf *m; 54931908Skarels struct ifqueue *inq; 55031908Skarels int sel2, sel3, sel4, sel6, sel10, pkaddr, len, s; 55131908Skarels register struct ifrw *ifrw; 55231908Skarels register struct dmvbufs *rp; 55331908Skarels register struct ifxmt *ifxp; 55431908Skarels struct dmv_header *dh; 55534529Skarels int off, resid; 55631908Skarels 55731908Skarels addr = (struct dmvdevice *)ui->ui_addr; 55831908Skarels sc = &dmv_softc[unit]; 559*36032Skarels splx(sc->sc_ipl); 56031908Skarels ifp = &sc->sc_if; 56131908Skarels 56231908Skarels while (addr->bsel2 & DMV_RDO) { 56331908Skarels 56431908Skarels sel2 = addr->bsel2; 56531908Skarels sel3 = addr->bsel3; 56631908Skarels sel4 = addr->wsel4; /* release port */ 56731908Skarels sel6 = addr->wsel6; 56831908Skarels if(sel2 & DMV_22BIT) 56931908Skarels sel10 = addr->wsel10; 57031908Skarels addr->bsel2 &= ~DMV_RDO; 57131908Skarels pkaddr = sel4 | ((sel6 & 0x3f) << 16); 57234529Skarels printd(("dmvxint: sel2=%x sel4=%x sel6=%x sel10=%x pkaddr=%x\n", 57331908Skarels (unsigned) sel2, 57431908Skarels (unsigned) sel4, 57531908Skarels (unsigned) sel6, 57631908Skarels (unsigned) sel10, 57731908Skarels (unsigned) pkaddr 57834529Skarels )); 57931908Skarels if((sc->sc_flag & DMV_RUNNING)==0) { 58031908Skarels log(LOG_WARNING, "dmvxint: dmv%d xint while down\n", unit); 58131908Skarels return; 58231908Skarels } 58331908Skarels switch (sel2 & 07) { 58431908Skarels case DMV_BDRUS: 58531908Skarels /* 58631908Skarels * A read has completed. 58731908Skarels * Pass packet to type specific 58831908Skarels * higher-level input routine. 58931908Skarels */ 59031908Skarels ifp->if_ipackets++; 59131908Skarels /* find location in dmvuba struct */ 59231908Skarels ifrw= &sc->sc_ifr[0]; 59331908Skarels for (rp = &sc->sc_rbufs[0]; rp < &sc->sc_rbufs[NRCV]; rp++) { 59431908Skarels if(rp->ubinfo == pkaddr) 59531908Skarels break; 59631908Skarels ifrw++; 59731908Skarels } 59831908Skarels if (rp >= &sc->sc_rbufs[NRCV]) 59931908Skarels panic("dmv rcv"); 60031908Skarels if ((rp->flags & DBUF_DMVS) == 0) 60131908Skarels log(LOG_WARNING, "dmvxint: dmv%d done unalloc rbuf\n", unit); 60231908Skarels 60331908Skarels len = (sel10&0x3fff) - sizeof (struct dmv_header); 60431908Skarels if (len < 0 || len > DMVMTU) { 60531908Skarels ifp->if_ierrors++; 60631908Skarels log(LOG_ERR, "dmvxint: dmv%d bad rcv pkt addr 0x%x len 0x%x\n", 60731908Skarels unit, pkaddr, len); 60831908Skarels goto setup; 60931908Skarels } 61031908Skarels /* 61131908Skarels * Deal with trailer protocol: if type is trailer 61231908Skarels * get true type from first 16-bit word past data. 61331908Skarels * Remember that type was trailer by setting off. 61431908Skarels */ 61531908Skarels dh = (struct dmv_header *)ifrw->ifrw_addr; 61631908Skarels dh->dmv_type = ntohs((u_short)dh->dmv_type); 61731908Skarels #define dmvdataaddr(dh, off, type) ((type)(((caddr_t)((dh)+1)+(off)))) 61831908Skarels if (dh->dmv_type >= DMV_TRAILER && 61931908Skarels dh->dmv_type < DMV_TRAILER+DMV_NTRAILER) { 62031908Skarels off = (dh->dmv_type - DMV_TRAILER) * 512; 62131908Skarels if (off >= DMVMTU) 62231908Skarels goto setup; /* sanity */ 62331908Skarels dh->dmv_type = ntohs(*dmvdataaddr(dh, off, u_short *)); 62431908Skarels resid = ntohs(*(dmvdataaddr(dh, off+2, u_short *))); 62531908Skarels if (off + resid > len) 62631908Skarels goto setup; /* sanity */ 62731908Skarels len = off + resid; 62831908Skarels } else 62931908Skarels off = 0; 63031908Skarels if (len == 0) 63131908Skarels goto setup; 63231908Skarels 63331908Skarels /* 63431908Skarels * Pull packet off interface. Off is nonzero if 63531908Skarels * packet has trailing header; dmv_get will then 63631908Skarels * force this header information to be at the front, 63731908Skarels * but we still have to drop the type and length 63831908Skarels * which are at the front of any trailer data. 63931908Skarels */ 64031908Skarels m = if_ubaget(&sc->sc_ifuba, ifrw, len, off, ifp); 64131908Skarels if (m == 0) 64231908Skarels goto setup; 643*36032Skarels if (off) { 644*36032Skarels ifp = *(mtod(m, struct ifnet **)); 645*36032Skarels m->m_off += 2 * sizeof (u_short); 646*36032Skarels m->m_len -= 2 * sizeof (u_short); 647*36032Skarels *(mtod(m, struct ifnet **)) = ifp; 648*36032Skarels } 64931908Skarels switch (dh->dmv_type) { 65031908Skarels #ifdef INET 65131908Skarels case DMV_IPTYPE: 65231908Skarels schednetisr(NETISR_IP); 65331908Skarels inq = &ipintrq; 65431908Skarels break; 65531908Skarels #endif 65631908Skarels default: 65731908Skarels m_freem(m); 65831908Skarels goto setup; 65931908Skarels } 66031908Skarels 66131908Skarels s = splimp(); 66231908Skarels if (IF_QFULL(inq)) { 66331908Skarels IF_DROP(inq); 66431908Skarels m_freem(m); 66531908Skarels } else 66631908Skarels IF_ENQUEUE(inq, m); 66731908Skarels splx(s); 66831908Skarels setup: 66931908Skarels /* is this needed? */ 670*36032Skarels rp->ubinfo = UBAI_ADDR(ifrw->ifrw_info); 67131908Skarels dmvload( 67231908Skarels sc, 67331908Skarels DMV_BACCR, 67431908Skarels QP_SEL4|QP_SEL6|QP_SEL10, 67531908Skarels 0, 676*36032Skarels (u_short) rp->ubinfo, 67731908Skarels (rp->ubinfo>>16)&0x3f, 67831908Skarels rp->cc 67931908Skarels ); 68031908Skarels break; 68131908Skarels case DMV_BDXSA: 68231908Skarels /* 68331908Skarels * A write has completed, start another 68431908Skarels * transfer if there is more data to send. 68531908Skarels */ 68631908Skarels ifp->if_opackets++; 68731908Skarels /* find associated dmvbuf structure */ 68831908Skarels ifxp = &sc->sc_ifw[0]; 68931908Skarels for (rp = &sc->sc_xbufs[0]; rp < &sc->sc_xbufs[NXMT]; rp++) { 69031908Skarels if(rp->ubinfo == pkaddr) 69131908Skarels break; 69231908Skarels ifxp++; 69331908Skarels } 69431908Skarels if (rp >= &sc->sc_xbufs[NXMT]) { 69531908Skarels log(LOG_ERR, "dmv%d: bad packet address 0x%x\n", 69631908Skarels unit, pkaddr); 69731908Skarels break; 69831908Skarels } 69931908Skarels if ((rp->flags & DBUF_DMVS) == 0) 70031908Skarels log(LOG_ERR, "dmvxint: dmv%d unallocated packet 0x%x\n", 70131908Skarels unit, pkaddr); 70231908Skarels /* mark buffer free */ 70331908Skarels if (ifxp->ifw_xtofree) { 70431908Skarels (void)m_freem(ifxp->ifw_xtofree); 70531908Skarels ifxp->ifw_xtofree = 0; 70631908Skarels } 70731908Skarels rp->flags &= ~DBUF_DMVS; 70834529Skarels if (--sc->sc_oused == 0) 70934529Skarels sc->sc_if.if_timer = 0; 71034529Skarels else 71134529Skarels sc->sc_if.if_timer = dmv_timeout; 71234529Skarels if ((sc->sc_flag & DMV_ONLINE) == 0) { 71334529Skarels extern int ifqmaxlen; 71434529Skarels 71534529Skarels /* 71634529Skarels * We're on the air. 71734529Skarels * Open the queue to the usual value. 71834529Skarels */ 71934529Skarels sc->sc_flag |= DMV_ONLINE; 72034529Skarels ifp->if_snd.ifq_maxlen = ifqmaxlen; 72134529Skarels } 72231908Skarels break; 72331908Skarels 72431908Skarels case DMV_CNTRLO: 72531908Skarels /* ACCUMULATE STATISTICS */ 72631908Skarels switch(sel6&DMV_EEC) { 72731908Skarels case DMV_ORUN: 72831908Skarels if(sc->sc_flag & DMV_RESTART) { 72931908Skarels load_rec_bufs(sc); 73031908Skarels sc->sc_flag &= ~DMV_RESTART; 73131908Skarels log(LOG_INFO, 73234529Skarels "dmv%d: far end on-line\n", unit); 73331908Skarels } else { 73431908Skarels log(LOG_WARNING, 73534529Skarels "dmv%d: far end restart\n", unit); 73634529Skarels goto restart; 73731908Skarels } 73831908Skarels break; 73931908Skarels case DMV_RTE: 74031908Skarels ifp->if_ierrors++; 74131909Skarels if ((sc->sc_rte++ % DMV_RPRTE) == 0) 74231909Skarels log(LOG_WARNING, 74334529Skarels "dmv%d: receive threshold error\n", 74431909Skarels unit); 74531908Skarels break; 74631908Skarels case DMV_TTE: 74731908Skarels ifp->if_oerrors++; 74831909Skarels if ((sc->sc_xte++ % DMV_RPTTE) == 0) 74931909Skarels log(LOG_WARNING, 75034529Skarels "dmv%d: transmit threshold error\n", 75131909Skarels unit); 75231908Skarels break; 75331908Skarels case DMV_STE: 75431909Skarels if ((sc->sc_ste++ % DMV_RPSTE) == 0) 75531909Skarels log(LOG_WARNING, 75634529Skarels "dmv%d: select threshold error\n", 75731909Skarels unit); 75831908Skarels break; 75931908Skarels case DMV_NXM: 76031909Skarels if ((sc->sc_nxm++ % DMV_RPNXM) == 0) 76131909Skarels log(LOG_WARNING, 76234529Skarels "dmv%d: nonexistent memory error\n", 76331909Skarels unit); 76431908Skarels break; 76531908Skarels case DMV_MODD: 76634529Skarels if ((sc->sc_modd++ % DMV_RPMODD) == 0) { 76731909Skarels log(LOG_WARNING, 76834529Skarels "dmv%d: modem disconnected error\n", 76931909Skarels unit); 77034529Skarels goto restart; 77134529Skarels } 77231908Skarels break; 77331908Skarels case DMV_CXRL: 77431909Skarels if ((sc->sc_cxrl++ % DMV_RPCXRL) == 0) 77531909Skarels log(LOG_WARNING, 77634529Skarels "dmv%d: carrier loss error\n", 77731909Skarels unit); 77831908Skarels break; 77931908Skarels case DMV_QOVF: 78031908Skarels log(LOG_WARNING, 78134529Skarels "dmv%d: response queue overflow\n", 78234529Skarels unit); 78331908Skarels sc->sc_qovf++; 78434529Skarels goto restart; 78531908Skarels 78631908Skarels default: 78731908Skarels log(LOG_WARNING, 78834529Skarels "dmv%d: unknown error %o\n", 78934529Skarels unit, sel6&DMV_EEC); 79031908Skarels if ((sc->sc_unknown++ % DMV_RPUNKNOWN) == 0) 79134529Skarels goto restart; 79231908Skarels break; 79331908Skarels } 79431908Skarels break; 79531908Skarels 79631908Skarels case DMV_BDRUNUS: 79731908Skarels case DMV_BDXSN: 79831908Skarels case DMV_BDXNS: 79931908Skarels log(LOG_INFO, 80034529Skarels "dmv%d: buffer disp for halted trib %o\n", 80131908Skarels unit, sel2&0x7 80231908Skarels ); 80331908Skarels break; 80431908Skarels 80531908Skarels case DMV_MDEFO: 80631908Skarels if((sel6&0x1f) == 020) { 80731908Skarels log(LOG_INFO, 80834529Skarels "dmv%d: buffer return complete sel3=%x\n", 80931908Skarels unit, sel3); 81031908Skarels } else { 81131908Skarels log(LOG_INFO, 81234529Skarels "dmv%d: info resp sel3=%x sel4=%x sel6=%x\n", 81331908Skarels unit, sel3, sel4, sel6 81431908Skarels ); 81531908Skarels } 81631908Skarels break; 81731908Skarels 81831908Skarels default: 81934529Skarels log(LOG_WARNING, "dmv%d: bad control %o\n", 82031908Skarels unit, sel2&0x7 82131908Skarels ); 82231908Skarels break; 82331908Skarels } 82431908Skarels } 82531908Skarels dmvstart(unit); 82631908Skarels return; 82734529Skarels restart: 82831908Skarels dmvrestart(unit); 82931908Skarels } 83034529Skarels 83131908Skarels load_rec_bufs(sc) 83231908Skarels register struct dmv_softc *sc; 83331908Skarels { 83431908Skarels register struct dmvbufs *rp; 83531908Skarels 83631908Skarels /* queue first NRCV buffers for DMV to fill */ 83731908Skarels for (rp = &sc->sc_rbufs[0]; rp < &sc->sc_rbufs[NRCV]; rp++) { 83831908Skarels rp->flags |= DBUF_DMVS; 83931908Skarels dmvload( 84031908Skarels sc, 84131908Skarels DMV_BACCR, 84231908Skarels QP_TRIB|QP_SEL4|QP_SEL6|QP_SEL10, 84331908Skarels 1, 84431908Skarels rp->ubinfo, 84531908Skarels (rp->ubinfo>>16)&0x3f, 84631908Skarels rp->cc 84731908Skarels ); 84831908Skarels sc->sc_iused++; 84931908Skarels } 85031908Skarels } 85131908Skarels 85231908Skarels /* 85331908Skarels * DMV output routine. 85431908Skarels * Encapsulate a packet of type family for the dmv. 85531908Skarels * Use trailer local net encapsulation if enough data in first 85631908Skarels * packet leaves a multiple of 512 bytes of data in remainder. 85731908Skarels */ 85831908Skarels dmvoutput(ifp, m0, dst) 85931908Skarels register struct ifnet *ifp; 86031908Skarels register struct mbuf *m0; 86131908Skarels struct sockaddr *dst; 86231908Skarels { 86331908Skarels int type, error, s; 86431908Skarels register struct mbuf *m = m0; 86531908Skarels register struct dmv_header *dh; 86631908Skarels register int off; 86731908Skarels 86834529Skarels if ((ifp->if_flags & IFF_UP) == 0) { 86934529Skarels error = ENETDOWN; 87034529Skarels goto bad; 87134529Skarels } 87234529Skarels 87331908Skarels switch (dst->sa_family) { 87431908Skarels #ifdef INET 87531908Skarels case AF_INET: 876*36032Skarels off = ntohs((u_short)mtod(m, struct ip *)->ip_len) - m->m_len; 87731908Skarels if ((ifp->if_flags & IFF_NOTRAILERS) == 0) 87831908Skarels if (off > 0 && (off & 0x1ff) == 0 && 879*36032Skarels m->m_off >= MMINOFF + 2 * sizeof (u_short)) { 88031908Skarels type = DMV_TRAILER + (off>>9); 881*36032Skarels m->m_off -= 2 * sizeof (u_short); 88231908Skarels m->m_len += 2 * sizeof (u_short); 88331908Skarels *mtod(m, u_short *) = htons((u_short)DMV_IPTYPE); 88431908Skarels *(mtod(m, u_short *) + 1) = htons((u_short)m->m_len); 88531908Skarels goto gottrailertype; 88631908Skarels } 88731908Skarels type = DMV_IPTYPE; 88831908Skarels off = 0; 88931908Skarels goto gottype; 89031908Skarels #endif 89131908Skarels 89231908Skarels case AF_UNSPEC: 89331908Skarels dh = (struct dmv_header *)dst->sa_data; 89431908Skarels type = dh->dmv_type; 89531908Skarels goto gottype; 89631908Skarels 89731908Skarels default: 89834529Skarels log(LOG_ERR, "dmvoutput, dmv%d can't handle af%d\n", 89934529Skarels ifp->if_unit, dst->sa_family); 90031908Skarels error = EAFNOSUPPORT; 90131908Skarels goto bad; 90231908Skarels } 90331908Skarels 90431908Skarels gottrailertype: 90531908Skarels /* 90631908Skarels * Packet to be sent as a trailer; move first packet 90731908Skarels * (control information) to end of chain. 90831908Skarels */ 90931908Skarels while (m->m_next) 91031908Skarels m = m->m_next; 91131908Skarels m->m_next = m0; 91231908Skarels m = m0->m_next; 91331908Skarels m0->m_next = 0; 91431908Skarels m0 = m; 91531908Skarels 91631908Skarels gottype: 91731908Skarels /* 91831908Skarels * Add local network header 91931908Skarels * (there is space for a uba on a vax to step on) 92031908Skarels */ 921*36032Skarels if (m->m_off > MMAXOFF || 922*36032Skarels MMINOFF + sizeof(struct dmv_header) > m->m_off) { 923*36032Skarels m = m_get(M_DONTWAIT, MT_HEADER); 924*36032Skarels if (m == 0) { 925*36032Skarels error = ENOBUFS; 926*36032Skarels goto bad; 927*36032Skarels } 928*36032Skarels m->m_next = m0; 929*36032Skarels m->m_off = MMINOFF; 930*36032Skarels m->m_len = sizeof (struct dmv_header); 931*36032Skarels } else { 932*36032Skarels m->m_off -= sizeof (struct dmv_header); 933*36032Skarels m->m_len += sizeof (struct dmv_header); 93431908Skarels } 93531908Skarels dh = mtod(m, struct dmv_header *); 93631908Skarels dh->dmv_type = htons((u_short)type); 93731908Skarels 93831908Skarels /* 93931908Skarels * Queue message on interface, and start output if interface 94031908Skarels * not yet active. 94131908Skarels */ 94231908Skarels s = splimp(); 94331908Skarels if (IF_QFULL(&ifp->if_snd)) { 94431908Skarels IF_DROP(&ifp->if_snd); 94531908Skarels m_freem(m); 94631908Skarels splx(s); 94731908Skarels return (ENOBUFS); 94831908Skarels } 94931908Skarels IF_ENQUEUE(&ifp->if_snd, m); 95031908Skarels dmvstart(ifp->if_unit); 95131908Skarels splx(s); 95231908Skarels return (0); 95331908Skarels 95431908Skarels bad: 95531908Skarels m_freem(m0); 95631908Skarels return (error); 95731908Skarels } 95831908Skarels 95931908Skarels 96031908Skarels /* 96131908Skarels * Process an ioctl request. 96231908Skarels */ 96331908Skarels /* ARGSUSED */ 96431908Skarels dmvioctl(ifp, cmd, data) 96531908Skarels register struct ifnet *ifp; 96631908Skarels int cmd; 96731908Skarels caddr_t data; 96831908Skarels { 96931908Skarels int s = splimp(), error = 0; 97031908Skarels struct mbuf *m; 97131908Skarels register struct dmv_softc *sc = &dmv_softc[ifp->if_unit]; 97231908Skarels 97331908Skarels switch (cmd) { 97431908Skarels 97531908Skarels case SIOCSIFADDR: 97631908Skarels ifp->if_flags |= IFF_UP; 97731908Skarels if ((ifp->if_flags & IFF_RUNNING) == 0) 97831908Skarels dmvinit(ifp->if_unit); 97931908Skarels break; 98031908Skarels 98131908Skarels case SIOCSIFDSTADDR: 98231908Skarels if ((ifp->if_flags & IFF_RUNNING) == 0) 98331908Skarels dmvinit(ifp->if_unit); 98431908Skarels break; 98531908Skarels 98631908Skarels case SIOCSIFFLAGS: 98731908Skarels if ((ifp->if_flags & IFF_UP) == 0 && 98834529Skarels sc->sc_flag & DMV_RUNNING) 98934529Skarels dmvdown(ifp->if_unit); 99034529Skarels else if (ifp->if_flags & IFF_UP && 99131908Skarels (sc->sc_flag & DMV_RUNNING) == 0) 99231908Skarels dmvrestart(ifp->if_unit); 99331908Skarels break; 99431908Skarels 99531908Skarels default: 99631908Skarels error = EINVAL; 99731908Skarels } 99831908Skarels splx(s); 99931908Skarels return (error); 100031908Skarels } 100131908Skarels 100231908Skarels /* 100331908Skarels * Restart after a fatal error. 100431908Skarels * Clear device and reinitialize. 100531908Skarels */ 100631908Skarels dmvrestart(unit) 100731908Skarels int unit; 100831908Skarels { 100931908Skarels register struct dmvdevice *addr; 101031908Skarels register int i; 101134529Skarels 101234529Skarels dmvdown(unit); 101334529Skarels 101434529Skarels addr = (struct dmvdevice *)(dmvinfo[unit]->ui_addr); 101531908Skarels /* 101634529Skarels * Let the DMV finish the MCLR. 101731908Skarels */ 101831908Skarels for (i = 100000; i && (addr->bsel1 & DMV_RUN) == 0; i--) 101931908Skarels ; 102031908Skarels if ((addr->bsel1 & DMV_RUN) == 0) { 102131908Skarels log(LOG_ERR, "dmvrestart: can't start device\n" ); 102231908Skarels return (0); 102331908Skarels } 102431908Skarels if ((addr->bsel4 != 033) || (addr->bsel6 != 0305)) 102531908Skarels { 102634529Skarels log(LOG_ERR, "dmv%d: device init failed, bsel4=%o, bsel6=%o\n", 102734529Skarels unit, addr->bsel4, addr->bsel6); 102831908Skarels return (0); 102931908Skarels } 103034529Skarels 103134529Skarels /* restart DMV */ 103234529Skarels dmvinit(unit); 103334529Skarels dmv_softc[unit].sc_if.if_collisions++; /* why not? */ 103434529Skarels } 103534529Skarels 103634529Skarels /* 103734529Skarels * Reset a device and mark down. 103834529Skarels * Flush output queue and drop queue limit. 103934529Skarels */ 104034529Skarels dmvdown(unit) 104134529Skarels int unit; 104234529Skarels { 104334529Skarels struct dmv_softc *sc = &dmv_softc[unit]; 104434529Skarels register struct ifxmt *ifxp; 104534529Skarels 104634529Skarels ((struct dmvdevice *)(dmvinfo[unit]->ui_addr))->bsel1 = DMV_MCLR; 104734529Skarels sc->sc_flag &= ~(DMV_RUNNING | DMV_ONLINE); 104834529Skarels 104931908Skarels for (ifxp = sc->sc_ifw; ifxp < &sc->sc_ifw[NXMT]; ifxp++) { 105031908Skarels if (ifxp->ifw_xtofree) { 105131908Skarels (void) m_freem(ifxp->ifw_xtofree); 105231908Skarels ifxp->ifw_xtofree = 0; 105331908Skarels } 105431908Skarels } 105534529Skarels sc->sc_oused = 0; 105634529Skarels if_qflush(&sc->sc_if.if_snd); 105734529Skarels 105834529Skarels /* 105934529Skarels * Limit packets enqueued until we're back on the air. 106034529Skarels */ 106134529Skarels sc->sc_if.if_snd.ifq_maxlen = 3; 106231908Skarels } 106331908Skarels 106431908Skarels /* 106534529Skarels * Watchdog timeout to see that transmitted packets don't 106634529Skarels * lose interrupts. The device has to be online. 106731908Skarels */ 106834529Skarels dmvtimeout(unit) 106934529Skarels int unit; 107031908Skarels { 107131908Skarels register struct dmv_softc *sc; 107231908Skarels struct dmvdevice *addr; 107331908Skarels 107434529Skarels sc = &dmv_softc[unit]; 107534529Skarels if (sc->sc_flag & DMV_ONLINE) { 107634529Skarels addr = (struct dmvdevice *)(dmvinfo[unit]->ui_addr); 107734529Skarels log(LOG_ERR, "dmv%d: output timeout, bsel0=%b bsel2=%b\n", 107834529Skarels unit, addr->bsel0 & 0xff, DMV0BITS, 107934529Skarels addr->bsel2 & 0xff, DMV2BITS); 108034529Skarels dmvrestart(unit); 108131908Skarels } 108231908Skarels } 108331908Skarels #endif 1084