131908Skarels /*
234727Smckusick * Copyright (c) 1988 Regents of the University of California.
334727Smckusick * All rights reserved.
434727Smckusick *
544558Sbostic * %sccs.include.redist.c%
634727Smckusick *
7*45801Sbostic * @(#)if_dmv.c 7.12 (Berkeley) 12/16/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
22*45801Sbostic #include "sys/param.h"
23*45801Sbostic #include "sys/systm.h"
24*45801Sbostic #include "sys/mbuf.h"
25*45801Sbostic #include "sys/buf.h"
26*45801Sbostic #include "sys/ioctl.h" /* must precede tty.h */
27*45801Sbostic #include "sys/tty.h"
28*45801Sbostic #include "sys/protosw.h"
29*45801Sbostic #include "sys/socket.h"
30*45801Sbostic #include "sys/syslog.h"
31*45801Sbostic #include "sys/vmmac.h"
32*45801Sbostic #include "sys/errno.h"
33*45801Sbostic #include "sys/time.h"
34*45801Sbostic #include "sys/kernel.h"
3531908Skarels
36*45801Sbostic #include "net/if.h"
37*45801Sbostic #include "net/netisr.h"
38*45801Sbostic #include "net/route.h"
3931908Skarels
4031908Skarels #ifdef INET
41*45801Sbostic #include "netinet/in.h"
42*45801Sbostic #include "netinet/in_systm.h"
43*45801Sbostic #include "netinet/in_var.h"
44*45801Sbostic #include "netinet/ip.h"
4531908Skarels #endif
4631908Skarels
47*45801Sbostic #include "../include/cpu.h"
48*45801Sbostic #include "../include/mtpr.h"
49*45801Sbostic #include "../include/pte.h"
50*45801Sbostic #include "../uba/ubareg.h"
51*45801Sbostic #include "../uba/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
dmvprobe(reg,ui)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 */
dmvattach(ui)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 */
dmvreset(unit,uban)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 */
dmvinit(unit)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)
29745291Ssklower if (ifa->ifa_addr->sa_family &&
29845291Ssklower ifa->ifa_addr->sa_family != AF_LINK &&
29945291Ssklower 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 */
dmvstart(dev)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 */
dmvload(sc,cmd,mask,tributary,sel4,sel6,sel10)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 */
dmvrint(unit)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 */
dmvxint(unit)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
load_rec_bufs(sc)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 */
dmvoutput(ifp,m0,dst)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 */
dmvioctl(ifp,cmd,data)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 */
dmvrestart(unit)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 */
dmvdown(unit)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 */
dmvtimeout(unit)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