1c3b3a32fSmckusick /*
258c24e32Smckusick * Copyright (c) 1982, 1986 Regents of the University of California.
3d3d328d8Sbostic * All rights reserved.
4c3b3a32fSmckusick *
5defcbc46Sbostic * %sccs.include.redist.c%
6d3d328d8Sbostic *
7*dd262573Sbostic * @(#)if_dmc.c 7.10 (Berkeley) 12/16/90
8c3b3a32fSmckusick */
9bdd6c372Sroot
10bdd6c372Sroot #include "dmc.h"
11bdd6c372Sroot #if NDMC > 0
126b0400d7Skarels
13bdd6c372Sroot /*
14bdd6c372Sroot * DMC11 device driver, internet version
15bdd6c372Sroot *
166b0400d7Skarels * Bill Nesheim
17e8f34b3fStef * Cornell University
182c36073aSsam *
196b0400d7Skarels * Lou Salkind
206b0400d7Skarels * New York University
21bdd6c372Sroot */
226b0400d7Skarels
236b0400d7Skarels /* #define DEBUG /* for base table dump on fatal error */
246b0400d7Skarels
25*dd262573Sbostic #include "../include/pte.h"
26bdd6c372Sroot
27*dd262573Sbostic #include "sys/param.h"
28*dd262573Sbostic #include "sys/systm.h"
29*dd262573Sbostic #include "sys/mbuf.h"
30*dd262573Sbostic #include "sys/buf.h"
31*dd262573Sbostic #include "sys/ioctl.h" /* must precede tty.h */
32*dd262573Sbostic #include "sys/tty.h"
33*dd262573Sbostic #include "sys/protosw.h"
34*dd262573Sbostic #include "sys/socket.h"
35*dd262573Sbostic #include "sys/syslog.h"
36*dd262573Sbostic #include "sys/vmmac.h"
37*dd262573Sbostic #include "sys/errno.h"
38*dd262573Sbostic #include "sys/time.h"
39*dd262573Sbostic #include "sys/kernel.h"
4002ea2271Sroot
41*dd262573Sbostic #include "net/if.h"
42*dd262573Sbostic #include "net/netisr.h"
43*dd262573Sbostic #include "net/route.h"
4471555f1fSkarels
4571555f1fSkarels #ifdef INET
46*dd262573Sbostic #include "netinet/in.h"
47*dd262573Sbostic #include "netinet/in_systm.h"
48*dd262573Sbostic #include "netinet/in_var.h"
49*dd262573Sbostic #include "netinet/ip.h"
5071555f1fSkarels #endif
5102ea2271Sroot
52*dd262573Sbostic #include "../include/cpu.h"
53*dd262573Sbostic #include "../include/mtpr.h"
5491194558Sbloom #include "if_uba.h"
5591194558Sbloom #include "if_dmc.h"
56*dd262573Sbostic #include "../uba/ubareg.h"
57*dd262573Sbostic #include "../uba/ubavar.h"
58bdd6c372Sroot
596b0400d7Skarels
60d468a3c3Skarels /*
61d468a3c3Skarels * output timeout value, sec.; should depend on line speed.
62d468a3c3Skarels */
63d468a3c3Skarels int dmc_timeout = 20;
646b0400d7Skarels
65bdd6c372Sroot /*
66bdd6c372Sroot * Driver information for auto-configuration stuff.
67bdd6c372Sroot */
68b7ce7f86Ssam int dmcprobe(), dmcattach(), dmcinit(), dmcioctl();
69d468a3c3Skarels int dmcoutput(), dmcreset(), dmctimeout();
70bdd6c372Sroot struct uba_device *dmcinfo[NDMC];
71bdd6c372Sroot u_short dmcstd[] = { 0 };
72bdd6c372Sroot struct uba_driver dmcdriver =
73bdd6c372Sroot { dmcprobe, 0, dmcattach, 0, dmcstd, "dmc", dmcinfo };
74bdd6c372Sroot
75e8f34b3fStef #define NRCV 7
766b0400d7Skarels #define NXMT 3
7771555f1fSkarels #define NCMDS (NRCV+NXMT+4) /* size of command queue */
786b0400d7Skarels
796b0400d7Skarels #define printd if(dmcdebug)printf
806b0400d7Skarels int dmcdebug = 0;
81e8f34b3fStef
82e8f34b3fStef /* error reporting intervals */
83e8f34b3fStef #define DMC_RPNBFS 50
84e8f34b3fStef #define DMC_RPDSC 1
856b0400d7Skarels #define DMC_RPTMO 10
866b0400d7Skarels #define DMC_RPDCK 10
87e8f34b3fStef
88e8f34b3fStef struct dmc_command {
89e8f34b3fStef char qp_cmd; /* command */
90e8f34b3fStef short qp_ubaddr; /* buffer address */
91e8f34b3fStef short qp_cc; /* character count || XMEM */
92e8f34b3fStef struct dmc_command *qp_next; /* next command on queue */
93e8f34b3fStef };
94e8f34b3fStef
95e8f34b3fStef struct dmcbufs {
96e8f34b3fStef int ubinfo; /* from uballoc */
97e8f34b3fStef short cc; /* buffer size */
98e8f34b3fStef short flags; /* access control */
99e8f34b3fStef };
100e8f34b3fStef #define DBUF_OURS 0 /* buffer is available */
101e8f34b3fStef #define DBUF_DMCS 1 /* buffer claimed by somebody */
102e8f34b3fStef #define DBUF_XMIT 4 /* transmit buffer */
1036b0400d7Skarels #define DBUF_RCV 8 /* receive buffer */
104e8f34b3fStef
105e8f34b3fStef
106bdd6c372Sroot /*
107bdd6c372Sroot * DMC software status per interface.
108bdd6c372Sroot *
109bdd6c372Sroot * Each interface is referenced by a network interface structure,
110bdd6c372Sroot * sc_if, which the routing code uses to locate the interface.
111bdd6c372Sroot * This structure contains the output queue for the interface, its address, ...
112e8f34b3fStef * We also have, for each interface, a set of 7 UBA interface structures
113e8f34b3fStef * for each, which
114e8f34b3fStef * contain information about the UNIBUS resources held by the interface:
115bdd6c372Sroot * map registers, buffered data paths, etc. Information is cached in this
116bdd6c372Sroot * structure for use by the if_uba.c routines in running the interface
117bdd6c372Sroot * efficiently.
118bdd6c372Sroot */
119bdd6c372Sroot struct dmc_softc {
120e8f34b3fStef struct ifnet sc_if; /* network-visible interface */
1219e791473Skarels short sc_oused; /* output buffers currently in use */
1229e791473Skarels short sc_iused; /* input buffers given to DMC */
1239e791473Skarels short sc_flag; /* flags */
124bdd6c372Sroot int sc_ubinfo; /* UBA mapping info for base table */
125e8f34b3fStef int sc_errors[4]; /* non-fatal error counters */
126e8f34b3fStef #define sc_datck sc_errors[0]
127e8f34b3fStef #define sc_timeo sc_errors[1]
128e8f34b3fStef #define sc_nobuf sc_errors[2]
129e8f34b3fStef #define sc_disc sc_errors[3]
130d468a3c3Skarels struct dmcbufs sc_rbufs[NRCV]; /* receive buffer info */
131d468a3c3Skarels struct dmcbufs sc_xbufs[NXMT]; /* transmit buffer info */
132d468a3c3Skarels struct ifubinfo sc_ifuba; /* UNIBUS resources */
133d468a3c3Skarels struct ifrw sc_ifr[NRCV]; /* UNIBUS receive buffer maps */
134d468a3c3Skarels struct ifxmt sc_ifw[NXMT]; /* UNIBUS receive buffer maps */
135e8f34b3fStef /* command queue stuff */
1366b0400d7Skarels struct dmc_command sc_cmdbuf[NCMDS];
137e8f34b3fStef struct dmc_command *sc_qhead; /* head of command queue */
138e8f34b3fStef struct dmc_command *sc_qtail; /* tail of command queue */
139e8f34b3fStef struct dmc_command *sc_qactive; /* command in progress */
140e8f34b3fStef struct dmc_command *sc_qfreeh; /* head of list of free cmd buffers */
141e8f34b3fStef struct dmc_command *sc_qfreet; /* tail of list of free cmd buffers */
142e8f34b3fStef /* end command queue stuff */
143bdd6c372Sroot } dmc_softc[NDMC];
144bdd6c372Sroot
145bdd6c372Sroot /* flags */
146d468a3c3Skarels #define DMC_RUNNING 0x01 /* device initialized */
147f72a343aSkarels #define DMC_BMAPPED 0x02 /* base table mapped */
148f72a343aSkarels #define DMC_RESTART 0x04 /* software restart in progress */
149d468a3c3Skarels #define DMC_ONLINE 0x08 /* device running (had a RDYO) */
150bdd6c372Sroot
151bdd6c372Sroot struct dmc_base {
152bdd6c372Sroot short d_base[128]; /* DMC base table */
153bdd6c372Sroot } dmc_base[NDMC];
154bdd6c372Sroot
155e8f34b3fStef /* queue manipulation macros */
156e8f34b3fStef #define QUEUE_AT_HEAD(qp, head, tail) \
157e8f34b3fStef (qp)->qp_next = (head); \
158e8f34b3fStef (head) = (qp); \
159e8f34b3fStef if ((tail) == (struct dmc_command *) 0) \
160e8f34b3fStef (tail) = (head)
161e8f34b3fStef
162e8f34b3fStef #define QUEUE_AT_TAIL(qp, head, tail) \
163e8f34b3fStef if ((tail)) \
164e8f34b3fStef (tail)->qp_next = (qp); \
165e8f34b3fStef else \
166e8f34b3fStef (head) = (qp); \
167e8f34b3fStef (qp)->qp_next = (struct dmc_command *) 0; \
168e8f34b3fStef (tail) = (qp)
169e8f34b3fStef
170e8f34b3fStef #define DEQUEUE(head, tail) \
171e8f34b3fStef (head) = (head)->qp_next;\
172e8f34b3fStef if ((head) == (struct dmc_command *) 0)\
173e8f34b3fStef (tail) = (head)
174bdd6c372Sroot
dmcprobe(reg)175bdd6c372Sroot dmcprobe(reg)
176bdd6c372Sroot caddr_t reg;
177bdd6c372Sroot {
178bdd6c372Sroot register int br, cvec;
179bdd6c372Sroot register struct dmcdevice *addr = (struct dmcdevice *)reg;
180bdd6c372Sroot register int i;
181bdd6c372Sroot
182bdd6c372Sroot #ifdef lint
183bdd6c372Sroot br = 0; cvec = br; br = cvec;
184bdd6c372Sroot dmcrint(0); dmcxint(0);
185bdd6c372Sroot #endif
186bdd6c372Sroot addr->bsel1 = DMC_MCLR;
187bdd6c372Sroot for (i = 100000; i && (addr->bsel1 & DMC_RUN) == 0; i--)
188bdd6c372Sroot ;
1896b0400d7Skarels if ((addr->bsel1 & DMC_RUN) == 0) {
1906b0400d7Skarels printf("dmcprobe: can't start device\n" );
191bdd6c372Sroot return (0);
1926b0400d7Skarels }
193bdd6c372Sroot addr->bsel0 = DMC_RQI|DMC_IEI;
1946b0400d7Skarels /* let's be paranoid */
1956b0400d7Skarels addr->bsel0 |= DMC_RQI|DMC_IEI;
1966b0400d7Skarels DELAY(1000000);
197bdd6c372Sroot addr->bsel1 = DMC_MCLR;
198bdd6c372Sroot for (i = 100000; i && (addr->bsel1 & DMC_RUN) == 0; i--)
199bdd6c372Sroot ;
200bdd6c372Sroot return (1);
201bdd6c372Sroot }
202bdd6c372Sroot
203bdd6c372Sroot /*
204bdd6c372Sroot * Interface exists: make available by filling in network interface
205bdd6c372Sroot * record. System will initialize the interface when it is ready
206bdd6c372Sroot * to accept packets.
207bdd6c372Sroot */
dmcattach(ui)208bdd6c372Sroot dmcattach(ui)
209bdd6c372Sroot register struct uba_device *ui;
210bdd6c372Sroot {
211bdd6c372Sroot register struct dmc_softc *sc = &dmc_softc[ui->ui_unit];
212bdd6c372Sroot
213bdd6c372Sroot sc->sc_if.if_unit = ui->ui_unit;
214bdd6c372Sroot sc->sc_if.if_name = "dmc";
215bdd6c372Sroot sc->sc_if.if_mtu = DMCMTU;
216bdd6c372Sroot sc->sc_if.if_init = dmcinit;
217bdd6c372Sroot sc->sc_if.if_output = dmcoutput;
218b7ce7f86Ssam sc->sc_if.if_ioctl = dmcioctl;
219222ab732Sroot sc->sc_if.if_reset = dmcreset;
220d468a3c3Skarels sc->sc_if.if_watchdog = dmctimeout;
221e8f34b3fStef sc->sc_if.if_flags = IFF_POINTOPOINT;
22271555f1fSkarels sc->sc_ifuba.iff_flags = UBA_CANTWAIT;
223e8f34b3fStef
22471555f1fSkarels if_attach(&sc->sc_if);
225bdd6c372Sroot }
226bdd6c372Sroot
227bdd6c372Sroot /*
228bdd6c372Sroot * Reset of interface after UNIBUS reset.
229a08469b0Skarels * If interface is on specified UBA, reset its state.
230bdd6c372Sroot */
dmcreset(unit,uban)231bdd6c372Sroot dmcreset(unit, uban)
232bdd6c372Sroot int unit, uban;
233bdd6c372Sroot {
234bdd6c372Sroot register struct uba_device *ui;
235e8f34b3fStef register struct dmc_softc *sc = &dmc_softc[unit];
236bdd6c372Sroot
237bdd6c372Sroot if (unit >= NDMC || (ui = dmcinfo[unit]) == 0 || ui->ui_alive == 0 ||
238bdd6c372Sroot ui->ui_ubanum != uban)
239bdd6c372Sroot return;
240bdd6c372Sroot printf(" dmc%d", unit);
2416b0400d7Skarels sc->sc_flag = 0;
242a08469b0Skarels sc->sc_if.if_flags &= ~IFF_RUNNING;
243bdd6c372Sroot dmcinit(unit);
244bdd6c372Sroot }
245bdd6c372Sroot
246bdd6c372Sroot /*
247bdd6c372Sroot * Initialization of interface; reinitialize UNIBUS usage.
248bdd6c372Sroot */
dmcinit(unit)249bdd6c372Sroot dmcinit(unit)
250bdd6c372Sroot int unit;
251bdd6c372Sroot {
252bdd6c372Sroot register struct dmc_softc *sc = &dmc_softc[unit];
253bdd6c372Sroot register struct uba_device *ui = dmcinfo[unit];
254bdd6c372Sroot register struct dmcdevice *addr;
255b7ce7f86Ssam register struct ifnet *ifp = &sc->sc_if;
256e8f34b3fStef register struct ifrw *ifrw;
257e8f34b3fStef register struct ifxmt *ifxp;
258e8f34b3fStef register struct dmcbufs *rp;
2596b0400d7Skarels register struct dmc_command *qp;
260a08469b0Skarels struct ifaddr *ifa;
261bdd6c372Sroot int base;
2626b0400d7Skarels int s;
263bdd6c372Sroot
264e8f34b3fStef addr = (struct dmcdevice *)ui->ui_addr;
265e8f34b3fStef
266a08469b0Skarels /*
267a08469b0Skarels * Check to see that an address has been set
268a08469b0Skarels * (both local and destination for an address family).
269a08469b0Skarels */
270a08469b0Skarels for (ifa = ifp->if_addrlist; ifa; ifa = ifa->ifa_next)
271fbf380ddSkarels if (ifa->ifa_addr->sa_family && ifa->ifa_dstaddr->sa_family)
272a08469b0Skarels break;
273a08469b0Skarels if (ifa == (struct ifaddr *) 0)
274e8f34b3fStef return;
275e8f34b3fStef
276e8f34b3fStef if ((addr->bsel1&DMC_RUN) == 0) {
277e8f34b3fStef printf("dmcinit: DMC not running\n");
278a08469b0Skarels ifp->if_flags &= ~IFF_UP;
279e8f34b3fStef return;
280bdd6c372Sroot }
281e8f34b3fStef /* map base table */
282e8f34b3fStef if ((sc->sc_flag & DMC_BMAPPED) == 0) {
283e8f34b3fStef sc->sc_ubinfo = uballoc(ui->ui_ubanum,
284e8f34b3fStef (caddr_t)&dmc_base[unit], sizeof (struct dmc_base), 0);
285e8f34b3fStef sc->sc_flag |= DMC_BMAPPED;
286e8f34b3fStef }
287e8f34b3fStef /* initialize UNIBUS resources */
288e8f34b3fStef sc->sc_iused = sc->sc_oused = 0;
289a08469b0Skarels if ((ifp->if_flags & IFF_RUNNING) == 0) {
29071555f1fSkarels if (if_ubaminit(&sc->sc_ifuba, ui->ui_ubanum,
29171555f1fSkarels sizeof(struct dmc_header), (int)btoc(DMCMTU),
29271555f1fSkarels sc->sc_ifr, NRCV, sc->sc_ifw, NXMT) == 0) {
293a08469b0Skarels printf("dmc%d: can't allocate uba resources\n", unit);
294b7ce7f86Ssam ifp->if_flags &= ~IFF_UP;
295bdd6c372Sroot return;
296bdd6c372Sroot }
297a08469b0Skarels ifp->if_flags |= IFF_RUNNING;
298e8f34b3fStef }
299d468a3c3Skarels sc->sc_flag &= ~DMC_ONLINE;
300f72a343aSkarels sc->sc_flag |= DMC_RUNNING;
301d468a3c3Skarels /*
302d468a3c3Skarels * Limit packets enqueued until we see if we're on the air.
303d468a3c3Skarels */
304d468a3c3Skarels ifp->if_snd.ifq_maxlen = 3;
305e8f34b3fStef
306e8f34b3fStef /* initialize buffer pool */
3076b0400d7Skarels /* receives */
30871555f1fSkarels ifrw = &sc->sc_ifr[0];
309e8f34b3fStef for (rp = &sc->sc_rbufs[0]; rp < &sc->sc_rbufs[NRCV]; rp++) {
310e578e9bdSkarels rp->ubinfo = UBAI_ADDR(ifrw->ifrw_info);
3116b0400d7Skarels rp->cc = DMCMTU + sizeof (struct dmc_header);
312e8f34b3fStef rp->flags = DBUF_OURS|DBUF_RCV;
313e8f34b3fStef ifrw++;
314e8f34b3fStef }
315e8f34b3fStef /* transmits */
31671555f1fSkarels ifxp = &sc->sc_ifw[0];
317e8f34b3fStef for (rp = &sc->sc_xbufs[0]; rp < &sc->sc_xbufs[NXMT]; rp++) {
318e578e9bdSkarels rp->ubinfo = UBAI_ADDR(ifxp->ifw_info);
319e8f34b3fStef rp->cc = 0;
320e8f34b3fStef rp->flags = DBUF_OURS|DBUF_XMIT;
321e8f34b3fStef ifxp++;
322e8f34b3fStef }
3236b0400d7Skarels
3246b0400d7Skarels /* set up command queues */
3256b0400d7Skarels sc->sc_qfreeh = sc->sc_qfreet
3266b0400d7Skarels = sc->sc_qhead = sc->sc_qtail = sc->sc_qactive =
3276b0400d7Skarels (struct dmc_command *)0;
3286b0400d7Skarels /* set up free command buffer list */
3296b0400d7Skarels for (qp = &sc->sc_cmdbuf[0]; qp < &sc->sc_cmdbuf[NCMDS]; qp++) {
3306b0400d7Skarels QUEUE_AT_HEAD(qp, sc->sc_qfreeh, sc->sc_qfreet);
3316b0400d7Skarels }
3326b0400d7Skarels
333e8f34b3fStef /* base in */
334e578e9bdSkarels base = UBAI_ADDR(sc->sc_ubinfo);
335e578e9bdSkarels dmcload(sc, DMC_BASEI, (u_short)base, (base>>2) & DMC_XMEM);
336e8f34b3fStef /* specify half duplex operation, flags tell if primary */
337e8f34b3fStef /* or secondary station */
338e8f34b3fStef if (ui->ui_flags == 0)
339f72a343aSkarels /* use DDCMP mode in full duplex */
340e8f34b3fStef dmcload(sc, DMC_CNTLI, 0, 0);
341e8f34b3fStef else if (ui->ui_flags == 1)
342e8f34b3fStef /* use MAINTENENCE mode */
343e8f34b3fStef dmcload(sc, DMC_CNTLI, 0, DMC_MAINT );
344e8f34b3fStef else if (ui->ui_flags == 2)
345e8f34b3fStef /* use DDCMP half duplex as primary station */
346e8f34b3fStef dmcload(sc, DMC_CNTLI, 0, DMC_HDPLX);
347e8f34b3fStef else if (ui->ui_flags == 3)
348e8f34b3fStef /* use DDCMP half duplex as secondary station */
349e8f34b3fStef dmcload(sc, DMC_CNTLI, 0, DMC_HDPLX | DMC_SEC);
350e8f34b3fStef
3516b0400d7Skarels /* enable operation done interrupts */
3526b0400d7Skarels while ((addr->bsel2 & DMC_IEO) == 0)
3536b0400d7Skarels addr->bsel2 |= DMC_IEO;
3546b0400d7Skarels s = spl5();
355e8f34b3fStef /* queue first NRCV buffers for DMC to fill */
356e8f34b3fStef for (rp = &sc->sc_rbufs[0]; rp < &sc->sc_rbufs[NRCV]; rp++) {
357e8f34b3fStef rp->flags |= DBUF_DMCS;
358e8f34b3fStef dmcload(sc, DMC_READ, rp->ubinfo,
359e8f34b3fStef (((rp->ubinfo>>2)&DMC_XMEM) | rp->cc));
360e8f34b3fStef sc->sc_iused++;
361e8f34b3fStef }
3626b0400d7Skarels splx(s);
363b7ce7f86Ssam }
364bdd6c372Sroot
365bdd6c372Sroot /*
366bdd6c372Sroot * Start output on interface. Get another datagram
367bdd6c372Sroot * to send from the interface queue and map it to
368bdd6c372Sroot * the interface before starting output.
369e8f34b3fStef *
370e8f34b3fStef * Must be called at spl 5
371bdd6c372Sroot */
dmcstart(unit)372d468a3c3Skarels dmcstart(unit)
373d468a3c3Skarels int unit;
374bdd6c372Sroot {
375bdd6c372Sroot register struct dmc_softc *sc = &dmc_softc[unit];
376bdd6c372Sroot struct mbuf *m;
377e8f34b3fStef register struct dmcbufs *rp;
378e8f34b3fStef register int n;
379bdd6c372Sroot
380bdd6c372Sroot /*
381e8f34b3fStef * Dequeue up to NXMT requests and map them to the UNIBUS.
382e8f34b3fStef * If no more requests, or no dmc buffers available, just return.
383bdd6c372Sroot */
384e8f34b3fStef n = 0;
385e8f34b3fStef for (rp = &sc->sc_xbufs[0]; rp < &sc->sc_xbufs[NXMT]; rp++ ) {
386e8f34b3fStef /* find an available buffer */
387e8f34b3fStef if ((rp->flags & DBUF_DMCS) == 0) {
388bdd6c372Sroot IF_DEQUEUE(&sc->sc_if.if_snd, m);
389bdd6c372Sroot if (m == 0)
390bdd6c372Sroot return;
391e8f34b3fStef /* mark it dmcs */
392e8f34b3fStef rp->flags |= (DBUF_DMCS);
393bdd6c372Sroot /*
394e8f34b3fStef * Have request mapped to UNIBUS for transmission
395e8f34b3fStef * and start the output.
396bdd6c372Sroot */
39771555f1fSkarels rp->cc = if_ubaput(&sc->sc_ifuba, &sc->sc_ifw[n], m);
3986b0400d7Skarels rp->cc &= DMC_CCOUNT;
399d468a3c3Skarels if (++sc->sc_oused == 1)
400d468a3c3Skarels sc->sc_if.if_timer = dmc_timeout;
401e8f34b3fStef dmcload(sc, DMC_WRITE, rp->ubinfo,
402e8f34b3fStef rp->cc | ((rp->ubinfo>>2)&DMC_XMEM));
403e8f34b3fStef }
404e8f34b3fStef n++;
405e8f34b3fStef }
406bdd6c372Sroot }
407bdd6c372Sroot
408bdd6c372Sroot /*
409bdd6c372Sroot * Utility routine to load the DMC device registers.
410bdd6c372Sroot */
dmcload(sc,type,w0,w1)411bdd6c372Sroot dmcload(sc, type, w0, w1)
412bdd6c372Sroot register struct dmc_softc *sc;
413e578e9bdSkarels int type;
414e578e9bdSkarels u_short w0, w1;
415bdd6c372Sroot {
416bdd6c372Sroot register struct dmcdevice *addr;
417e8f34b3fStef register int unit, sps;
418e8f34b3fStef register struct dmc_command *qp;
419bdd6c372Sroot
4206b0400d7Skarels unit = sc - dmc_softc;
421bdd6c372Sroot addr = (struct dmcdevice *)dmcinfo[unit]->ui_addr;
422bdd6c372Sroot sps = spl5();
423e8f34b3fStef
424e8f34b3fStef /* grab a command buffer from the free list */
425e8f34b3fStef if ((qp = sc->sc_qfreeh) == (struct dmc_command *)0)
426e8f34b3fStef panic("dmc command queue overflow");
427e8f34b3fStef DEQUEUE(sc->sc_qfreeh, sc->sc_qfreet);
428e8f34b3fStef
429e8f34b3fStef /* fill in requested info */
430e8f34b3fStef qp->qp_cmd = (type | DMC_RQI);
431e8f34b3fStef qp->qp_ubaddr = w0;
432e8f34b3fStef qp->qp_cc = w1;
433e8f34b3fStef
434e8f34b3fStef if (sc->sc_qactive) { /* command in progress */
435e8f34b3fStef if (type == DMC_READ) {
436e8f34b3fStef QUEUE_AT_HEAD(qp, sc->sc_qhead, sc->sc_qtail);
437e8f34b3fStef } else {
438e8f34b3fStef QUEUE_AT_TAIL(qp, sc->sc_qhead, sc->sc_qtail);
439e8f34b3fStef }
440e8f34b3fStef } else { /* command port free */
441e8f34b3fStef sc->sc_qactive = qp;
442e8f34b3fStef addr->bsel0 = qp->qp_cmd;
443bdd6c372Sroot dmcrint(unit);
444e8f34b3fStef }
445bdd6c372Sroot splx(sps);
446bdd6c372Sroot }
447bdd6c372Sroot
448bdd6c372Sroot /*
449bdd6c372Sroot * DMC interface receiver interrupt.
450bdd6c372Sroot * Ready to accept another command,
451bdd6c372Sroot * pull one off the command queue.
452bdd6c372Sroot */
dmcrint(unit)453bdd6c372Sroot dmcrint(unit)
454bdd6c372Sroot int unit;
455bdd6c372Sroot {
456bdd6c372Sroot register struct dmc_softc *sc;
457bdd6c372Sroot register struct dmcdevice *addr;
458e8f34b3fStef register struct dmc_command *qp;
459bdd6c372Sroot register int n;
460bdd6c372Sroot
461bdd6c372Sroot addr = (struct dmcdevice *)dmcinfo[unit]->ui_addr;
462bdd6c372Sroot sc = &dmc_softc[unit];
463e8f34b3fStef if ((qp = sc->sc_qactive) == (struct dmc_command *) 0) {
4646b0400d7Skarels printf("dmc%d: dmcrint no command\n", unit);
465e8f34b3fStef return;
466e8f34b3fStef }
467bdd6c372Sroot while (addr->bsel0&DMC_RDYI) {
468e8f34b3fStef addr->sel4 = qp->qp_ubaddr;
469e8f34b3fStef addr->sel6 = qp->qp_cc;
470bdd6c372Sroot addr->bsel0 &= ~(DMC_IEI|DMC_RQI);
471e8f34b3fStef /* free command buffer */
472e8f34b3fStef QUEUE_AT_HEAD(qp, sc->sc_qfreeh, sc->sc_qfreet);
473e8f34b3fStef while (addr->bsel0 & DMC_RDYI) {
474e8f34b3fStef /*
475e8f34b3fStef * Can't check for RDYO here 'cause
476e8f34b3fStef * this routine isn't reentrant!
477e8f34b3fStef */
478e8f34b3fStef DELAY(5);
479e8f34b3fStef }
480e8f34b3fStef /* move on to next command */
481e8f34b3fStef if ((sc->sc_qactive = sc->sc_qhead) == (struct dmc_command *)0)
4826b0400d7Skarels break; /* all done */
483e8f34b3fStef /* more commands to do, start the next one */
484e8f34b3fStef qp = sc->sc_qactive;
485e8f34b3fStef DEQUEUE(sc->sc_qhead, sc->sc_qtail);
486e8f34b3fStef addr->bsel0 = qp->qp_cmd;
487bdd6c372Sroot n = RDYSCAN;
4886b0400d7Skarels while (n-- > 0)
4896b0400d7Skarels if ((addr->bsel0&DMC_RDYI) || (addr->bsel2&DMC_RDYO))
4906b0400d7Skarels break;
491bdd6c372Sroot }
492e8f34b3fStef if (sc->sc_qactive) {
493e8f34b3fStef addr->bsel0 |= DMC_IEI|DMC_RQI;
494e8f34b3fStef /* VMS does it twice !*$%@# */
495e8f34b3fStef addr->bsel0 |= DMC_IEI|DMC_RQI;
496e8f34b3fStef }
4976b0400d7Skarels
498bdd6c372Sroot }
499bdd6c372Sroot
500bdd6c372Sroot /*
501bdd6c372Sroot * DMC interface transmitter interrupt.
502e8f34b3fStef * A transfer may have completed, check for errors.
503bdd6c372Sroot * If it was a read, notify appropriate protocol.
504bdd6c372Sroot * If it was a write, pull the next one off the queue.
505bdd6c372Sroot */
dmcxint(unit)506bdd6c372Sroot dmcxint(unit)
507bdd6c372Sroot int unit;
508bdd6c372Sroot {
509bdd6c372Sroot register struct dmc_softc *sc;
5104ed66730Ssam register struct ifnet *ifp;
511bdd6c372Sroot struct uba_device *ui = dmcinfo[unit];
512bdd6c372Sroot struct dmcdevice *addr;
513bdd6c372Sroot struct mbuf *m;
5146b0400d7Skarels struct ifqueue *inq;
515f72a343aSkarels int arg, pkaddr, cmd, len, s;
516e8f34b3fStef register struct ifrw *ifrw;
517e8f34b3fStef register struct dmcbufs *rp;
5186b0400d7Skarels register struct ifxmt *ifxp;
5196b0400d7Skarels struct dmc_header *dh;
5206b0400d7Skarels int off, resid;
521bdd6c372Sroot
522bdd6c372Sroot addr = (struct dmcdevice *)ui->ui_addr;
523bdd6c372Sroot sc = &dmc_softc[unit];
5244ed66730Ssam ifp = &sc->sc_if;
525e8f34b3fStef
5266b0400d7Skarels while (addr->bsel2 & DMC_RDYO) {
5276b0400d7Skarels
528e8f34b3fStef cmd = addr->bsel2 & 0xff;
529e8f34b3fStef arg = addr->sel6 & 0xffff;
530e8f34b3fStef /* reconstruct UNIBUS address of buffer returned to us */
531e8f34b3fStef pkaddr = ((arg&DMC_XMEM)<<2) | (addr->sel4 & 0xffff);
532e8f34b3fStef /* release port */
533e8f34b3fStef addr->bsel2 &= ~DMC_RDYO;
534fe17efc2Ssam switch (cmd & 07) {
535bdd6c372Sroot
536bdd6c372Sroot case DMC_OUR:
537bdd6c372Sroot /*
538e8f34b3fStef * A read has completed.
539e8f34b3fStef * Pass packet to type specific
540bdd6c372Sroot * higher-level input routine.
541bdd6c372Sroot */
5424ed66730Ssam ifp->if_ipackets++;
543e8f34b3fStef /* find location in dmcuba struct */
54471555f1fSkarels ifrw= &sc->sc_ifr[0];
5456b0400d7Skarels for (rp = &sc->sc_rbufs[0]; rp < &sc->sc_rbufs[NRCV]; rp++) {
546e8f34b3fStef if(rp->ubinfo == pkaddr)
5476b0400d7Skarels break;
548e8f34b3fStef ifrw++;
549e8f34b3fStef }
5506b0400d7Skarels if (rp >= &sc->sc_rbufs[NRCV])
5516b0400d7Skarels panic("dmc rcv");
5526b0400d7Skarels if ((rp->flags & DBUF_DMCS) == 0)
5536b0400d7Skarels printf("dmc%d: done unalloc rbuf\n", unit);
5546b0400d7Skarels
5556b0400d7Skarels len = (arg & DMC_CCOUNT) - sizeof (struct dmc_header);
5566b0400d7Skarels if (len < 0 || len > DMCMTU) {
5576b0400d7Skarels ifp->if_ierrors++;
5586b0400d7Skarels printd("dmc%d: bad rcv pkt addr 0x%x len 0x%x\n",
5596b0400d7Skarels unit, pkaddr, len);
5606b0400d7Skarels goto setup;
5616b0400d7Skarels }
5626b0400d7Skarels /*
5636b0400d7Skarels * Deal with trailer protocol: if type is trailer
5646b0400d7Skarels * get true type from first 16-bit word past data.
5656b0400d7Skarels * Remember that type was trailer by setting off.
5666b0400d7Skarels */
5676b0400d7Skarels dh = (struct dmc_header *)ifrw->ifrw_addr;
5686b0400d7Skarels dh->dmc_type = ntohs((u_short)dh->dmc_type);
5696b0400d7Skarels #define dmcdataaddr(dh, off, type) ((type)(((caddr_t)((dh)+1)+(off))))
5706b0400d7Skarels if (dh->dmc_type >= DMC_TRAILER &&
5716b0400d7Skarels dh->dmc_type < DMC_TRAILER+DMC_NTRAILER) {
5726b0400d7Skarels off = (dh->dmc_type - DMC_TRAILER) * 512;
5736b0400d7Skarels if (off >= DMCMTU)
5746b0400d7Skarels goto setup; /* sanity */
5756b0400d7Skarels dh->dmc_type = ntohs(*dmcdataaddr(dh, off, u_short *));
5766b0400d7Skarels resid = ntohs(*(dmcdataaddr(dh, off+2, u_short *)));
5776b0400d7Skarels if (off + resid > len)
5786b0400d7Skarels goto setup; /* sanity */
5796b0400d7Skarels len = off + resid;
5806b0400d7Skarels } else
5816b0400d7Skarels off = 0;
5826b0400d7Skarels if (len == 0)
583e8f34b3fStef goto setup;
584e8f34b3fStef
5856b0400d7Skarels /*
5866b0400d7Skarels * Pull packet off interface. Off is nonzero if
5876b0400d7Skarels * packet has trailing header; dmc_get will then
5886b0400d7Skarels * force this header information to be at the front,
5896b0400d7Skarels * but we still have to drop the type and length
5906b0400d7Skarels * which are at the front of any trailer data.
5916b0400d7Skarels */
59271555f1fSkarels m = if_ubaget(&sc->sc_ifuba, ifrw, len, off, ifp);
5936b0400d7Skarels if (m == 0)
5946b0400d7Skarels goto setup;
5956b0400d7Skarels switch (dh->dmc_type) {
5966b0400d7Skarels
597bdd6c372Sroot #ifdef INET
5986b0400d7Skarels case DMC_IPTYPE:
59920bd5ff9Swnj schednetisr(NETISR_IP);
600bdd6c372Sroot inq = &ipintrq;
601bdd6c372Sroot break;
602bdd6c372Sroot #endif
603bdd6c372Sroot default:
6046b0400d7Skarels m_freem(m);
605bdd6c372Sroot goto setup;
606bdd6c372Sroot }
607e8f34b3fStef
608f72a343aSkarels s = splimp();
609fa57dce4Swnj if (IF_QFULL(inq)) {
610fa57dce4Swnj IF_DROP(inq);
611871045d0Ssam m_freem(m);
612fa57dce4Swnj } else
613bdd6c372Sroot IF_ENQUEUE(inq, m);
614f72a343aSkarels splx(s);
6156b0400d7Skarels
616bdd6c372Sroot setup:
6176b0400d7Skarels /* is this needed? */
618e578e9bdSkarels rp->ubinfo = UBAI_ADDR(ifrw->ifrw_info);
6196b0400d7Skarels
6206b0400d7Skarels dmcload(sc, DMC_READ, rp->ubinfo,
6216b0400d7Skarels ((rp->ubinfo >> 2) & DMC_XMEM) | rp->cc);
622e8f34b3fStef break;
623bdd6c372Sroot
624bdd6c372Sroot case DMC_OUX:
625bdd6c372Sroot /*
626bdd6c372Sroot * A write has completed, start another
627bdd6c372Sroot * transfer if there is more data to send.
628bdd6c372Sroot */
6294ed66730Ssam ifp->if_opackets++;
630e8f34b3fStef /* find associated dmcbuf structure */
63171555f1fSkarels ifxp = &sc->sc_ifw[0];
6326b0400d7Skarels for (rp = &sc->sc_xbufs[0]; rp < &sc->sc_xbufs[NXMT]; rp++) {
633e8f34b3fStef if(rp->ubinfo == pkaddr)
6346b0400d7Skarels break;
6356b0400d7Skarels ifxp++;
636bdd6c372Sroot }
6376b0400d7Skarels if (rp >= &sc->sc_xbufs[NXMT]) {
638e8f34b3fStef printf("dmc%d: bad packet address 0x%x\n",
639e8f34b3fStef unit, pkaddr);
640e8f34b3fStef break;
6416b0400d7Skarels }
642e8f34b3fStef if ((rp->flags & DBUF_DMCS) == 0)
6436b0400d7Skarels printf("dmc%d: unallocated packet 0x%x\n",
6446b0400d7Skarels unit, pkaddr);
645e8f34b3fStef /* mark buffer free */
64671555f1fSkarels if (ifxp->ifw_xtofree) {
64771555f1fSkarels (void)m_freem(ifxp->ifw_xtofree);
64871555f1fSkarels ifxp->ifw_xtofree = 0;
6496b0400d7Skarels }
6506b0400d7Skarels rp->flags &= ~DBUF_DMCS;
651d468a3c3Skarels if (--sc->sc_oused == 0)
652d468a3c3Skarels sc->sc_if.if_timer = 0;
653d468a3c3Skarels else
654d468a3c3Skarels sc->sc_if.if_timer = dmc_timeout;
655d468a3c3Skarels if ((sc->sc_flag & DMC_ONLINE) == 0) {
656d468a3c3Skarels extern int ifqmaxlen;
657d468a3c3Skarels
658d468a3c3Skarels /*
659d468a3c3Skarels * We're on the air.
660d468a3c3Skarels * Open the queue to the usual value.
661d468a3c3Skarels */
662d468a3c3Skarels sc->sc_flag |= DMC_ONLINE;
663d468a3c3Skarels ifp->if_snd.ifq_maxlen = ifqmaxlen;
664d468a3c3Skarels }
665e8f34b3fStef break;
666bdd6c372Sroot
667bdd6c372Sroot case DMC_CNTLO:
668bdd6c372Sroot arg &= DMC_CNTMASK;
669bdd6c372Sroot if (arg & DMC_FATAL) {
670d468a3c3Skarels if (arg != DMC_START)
671d468a3c3Skarels log(LOG_ERR,
672d468a3c3Skarels "dmc%d: fatal error, flags=%b\n",
673e8f34b3fStef unit, arg, CNTLO_BITS);
6746b0400d7Skarels dmcrestart(unit);
675e8f34b3fStef break;
6766b0400d7Skarels }
677bdd6c372Sroot /* ACCUMULATE STATISTICS */
678e8f34b3fStef switch(arg) {
679e8f34b3fStef case DMC_NOBUFS:
680e8f34b3fStef ifp->if_ierrors++;
6816b0400d7Skarels if ((sc->sc_nobuf++ % DMC_RPNBFS) == 0)
682e8f34b3fStef goto report;
6836b0400d7Skarels break;
684e8f34b3fStef case DMC_DISCONN:
6856b0400d7Skarels if ((sc->sc_disc++ % DMC_RPDSC) == 0)
686e8f34b3fStef goto report;
6876b0400d7Skarels break;
688e8f34b3fStef case DMC_TIMEOUT:
6896b0400d7Skarels if ((sc->sc_timeo++ % DMC_RPTMO) == 0)
690e8f34b3fStef goto report;
6916b0400d7Skarels break;
692e8f34b3fStef case DMC_DATACK:
693e8f34b3fStef ifp->if_oerrors++;
6946b0400d7Skarels if ((sc->sc_datck++ % DMC_RPDCK) == 0)
695e8f34b3fStef goto report;
6966b0400d7Skarels break;
697e8f34b3fStef default:
698e8f34b3fStef goto report;
699bdd6c372Sroot }
700e8f34b3fStef break;
701e8f34b3fStef report:
7026b0400d7Skarels printd("dmc%d: soft error, flags=%b\n", unit,
7036b0400d7Skarels arg, CNTLO_BITS);
7046b0400d7Skarels if ((sc->sc_flag & DMC_RESTART) == 0) {
7056b0400d7Skarels /*
7066b0400d7Skarels * kill off the dmc to get things
7076b0400d7Skarels * going again by generating a
7086b0400d7Skarels * procedure error
7096b0400d7Skarels */
7106b0400d7Skarels sc->sc_flag |= DMC_RESTART;
711e578e9bdSkarels arg = UBAI_ADDR(sc->sc_ubinfo);
7126b0400d7Skarels dmcload(sc, DMC_BASEI, arg, (arg>>2)&DMC_XMEM);
713e8f34b3fStef }
714e8f34b3fStef break;
715bdd6c372Sroot
716bdd6c372Sroot default:
717bdd6c372Sroot printf("dmc%d: bad control %o\n", unit, cmd);
7186b0400d7Skarels break;
719bdd6c372Sroot }
7206b0400d7Skarels }
7216b0400d7Skarels dmcstart(unit);
722e8f34b3fStef return;
723bdd6c372Sroot }
724bdd6c372Sroot
725bdd6c372Sroot /*
726bdd6c372Sroot * DMC output routine.
7276b0400d7Skarels * Encapsulate a packet of type family for the dmc.
7286b0400d7Skarels * Use trailer local net encapsulation if enough data in first
7296b0400d7Skarels * packet leaves a multiple of 512 bytes of data in remainder.
730bdd6c372Sroot */
dmcoutput(ifp,m0,dst)7316b0400d7Skarels dmcoutput(ifp, m0, dst)
732bdd6c372Sroot register struct ifnet *ifp;
7336b0400d7Skarels register struct mbuf *m0;
7348d171e64Ssam struct sockaddr *dst;
735bdd6c372Sroot {
7366b0400d7Skarels int type, error, s;
7376b0400d7Skarels register struct mbuf *m = m0;
7386b0400d7Skarels register struct dmc_header *dh;
7396b0400d7Skarels register int off;
740bdd6c372Sroot
741d468a3c3Skarels if ((ifp->if_flags & IFF_UP) == 0) {
742d468a3c3Skarels error = ENETDOWN;
743d468a3c3Skarels goto bad;
744d468a3c3Skarels }
745d468a3c3Skarels
7466b0400d7Skarels switch (dst->sa_family) {
7476b0400d7Skarels #ifdef INET
7486b0400d7Skarels case AF_INET:
749fbf380ddSkarels off = m->m_pkthdr.len - m->m_len;
7506b0400d7Skarels if ((ifp->if_flags & IFF_NOTRAILERS) == 0)
7516b0400d7Skarels if (off > 0 && (off & 0x1ff) == 0 &&
752fbf380ddSkarels (m->m_flags & M_EXT) == 0 &&
753fbf380ddSkarels m->m_data >= m->m_pktdat + 2 * sizeof (u_short)) {
7546b0400d7Skarels type = DMC_TRAILER + (off>>9);
755fbf380ddSkarels m->m_data -= 2 * sizeof (u_short);
7566b0400d7Skarels m->m_len += 2 * sizeof (u_short);
7576b0400d7Skarels *mtod(m, u_short *) = htons((u_short)DMC_IPTYPE);
7586b0400d7Skarels *(mtod(m, u_short *) + 1) = htons((u_short)m->m_len);
7596b0400d7Skarels goto gottrailertype;
760bdd6c372Sroot }
7616b0400d7Skarels type = DMC_IPTYPE;
7626b0400d7Skarels off = 0;
7636b0400d7Skarels goto gottype;
7646b0400d7Skarels #endif
7656b0400d7Skarels
7666b0400d7Skarels case AF_UNSPEC:
7676b0400d7Skarels dh = (struct dmc_header *)dst->sa_data;
7686b0400d7Skarels type = dh->dmc_type;
7696b0400d7Skarels goto gottype;
7706b0400d7Skarels
7716b0400d7Skarels default:
7726b0400d7Skarels printf("dmc%d: can't handle af%d\n", ifp->if_unit,
7736b0400d7Skarels dst->sa_family);
7746b0400d7Skarels error = EAFNOSUPPORT;
7756b0400d7Skarels goto bad;
7766b0400d7Skarels }
7776b0400d7Skarels
7786b0400d7Skarels gottrailertype:
7796b0400d7Skarels /*
7806b0400d7Skarels * Packet to be sent as a trailer; move first packet
7816b0400d7Skarels * (control information) to end of chain.
7826b0400d7Skarels */
7836b0400d7Skarels while (m->m_next)
7846b0400d7Skarels m = m->m_next;
7856b0400d7Skarels m->m_next = m0;
7866b0400d7Skarels m = m0->m_next;
7876b0400d7Skarels m0->m_next = 0;
7886b0400d7Skarels m0 = m;
7896b0400d7Skarels
7906b0400d7Skarels gottype:
7916b0400d7Skarels /*
7926b0400d7Skarels * Add local network header
7936b0400d7Skarels * (there is space for a uba on a vax to step on)
7946b0400d7Skarels */
795fbf380ddSkarels M_PREPEND(m, sizeof(struct dmc_header), M_DONTWAIT);
7966b0400d7Skarels if (m == 0) {
7976b0400d7Skarels error = ENOBUFS;
7986b0400d7Skarels goto bad;
7996b0400d7Skarels }
8006b0400d7Skarels dh = mtod(m, struct dmc_header *);
8016b0400d7Skarels dh->dmc_type = htons((u_short)type);
8026b0400d7Skarels
8036b0400d7Skarels /*
8046b0400d7Skarels * Queue message on interface, and start output if interface
8056b0400d7Skarels * not yet active.
8066b0400d7Skarels */
8076b0400d7Skarels s = splimp();
808fa57dce4Swnj if (IF_QFULL(&ifp->if_snd)) {
809fa57dce4Swnj IF_DROP(&ifp->if_snd);
8108d171e64Ssam m_freem(m);
811fa57dce4Swnj splx(s);
8121c805374Ssam return (ENOBUFS);
813fa57dce4Swnj }
814bdd6c372Sroot IF_ENQUEUE(&ifp->if_snd, m);
815bdd6c372Sroot dmcstart(ifp->if_unit);
816bdd6c372Sroot splx(s);
8171c805374Ssam return (0);
8186b0400d7Skarels
8196b0400d7Skarels bad:
8206b0400d7Skarels m_freem(m0);
8216b0400d7Skarels return (error);
822bdd6c372Sroot }
823b7ce7f86Ssam
8246b0400d7Skarels
825b7ce7f86Ssam /*
826b7ce7f86Ssam * Process an ioctl request.
827b7ce7f86Ssam */
82871555f1fSkarels /* ARGSUSED */
dmcioctl(ifp,cmd,data)829b7ce7f86Ssam dmcioctl(ifp, cmd, data)
830b7ce7f86Ssam register struct ifnet *ifp;
831b7ce7f86Ssam int cmd;
832b7ce7f86Ssam caddr_t data;
833b7ce7f86Ssam {
834b7ce7f86Ssam int s = splimp(), error = 0;
835f72a343aSkarels register struct dmc_softc *sc = &dmc_softc[ifp->if_unit];
836b7ce7f86Ssam
837b7ce7f86Ssam switch (cmd) {
838b7ce7f86Ssam
839b7ce7f86Ssam case SIOCSIFADDR:
840e8f34b3fStef ifp->if_flags |= IFF_UP;
841a08469b0Skarels if ((ifp->if_flags & IFF_RUNNING) == 0)
842a08469b0Skarels dmcinit(ifp->if_unit);
843b7ce7f86Ssam break;
844b7ce7f86Ssam
845b7ce7f86Ssam case SIOCSIFDSTADDR:
846a08469b0Skarels if ((ifp->if_flags & IFF_RUNNING) == 0)
847a08469b0Skarels dmcinit(ifp->if_unit);
848b7ce7f86Ssam break;
849b7ce7f86Ssam
850f72a343aSkarels case SIOCSIFFLAGS:
851f72a343aSkarels if ((ifp->if_flags & IFF_UP) == 0 &&
852d468a3c3Skarels sc->sc_flag & DMC_RUNNING)
853d468a3c3Skarels dmcdown(ifp->if_unit);
854d468a3c3Skarels else if (ifp->if_flags & IFF_UP &&
855f72a343aSkarels (sc->sc_flag & DMC_RUNNING) == 0)
856f72a343aSkarels dmcrestart(ifp->if_unit);
857f72a343aSkarels break;
858f72a343aSkarels
859b7ce7f86Ssam default:
860b7ce7f86Ssam error = EINVAL;
861b7ce7f86Ssam }
862b7ce7f86Ssam splx(s);
863b7ce7f86Ssam return (error);
864b7ce7f86Ssam }
865e8f34b3fStef
8666b0400d7Skarels /*
8676b0400d7Skarels * Restart after a fatal error.
8686b0400d7Skarels * Clear device and reinitialize.
8696b0400d7Skarels */
dmcrestart(unit)8706b0400d7Skarels dmcrestart(unit)
8716b0400d7Skarels int unit;
8726b0400d7Skarels {
8736b0400d7Skarels register struct dmc_softc *sc = &dmc_softc[unit];
8746b0400d7Skarels register struct dmcdevice *addr;
8756b0400d7Skarels register int i;
876d468a3c3Skarels int s;
8776b0400d7Skarels
8786b0400d7Skarels #ifdef DEBUG
8796b0400d7Skarels /* dump base table */
8806b0400d7Skarels printf("dmc%d base table:\n", unit);
8816b0400d7Skarels for (i = 0; i < sizeof (struct dmc_base); i++)
8826b0400d7Skarels printf("%o\n" ,dmc_base[unit].d_base[i]);
8836b0400d7Skarels #endif
884d468a3c3Skarels
885d468a3c3Skarels dmcdown(unit);
886d468a3c3Skarels
8876b0400d7Skarels /*
8886b0400d7Skarels * Let the DMR finish the MCLR. At 1 Mbit, it should do so
8896b0400d7Skarels * in about a max of 6.4 milliseconds with diagnostics enabled.
8906b0400d7Skarels */
891d468a3c3Skarels addr = (struct dmcdevice *)(dmcinfo[unit]->ui_addr);
8926b0400d7Skarels for (i = 100000; i && (addr->bsel1 & DMC_RUN) == 0; i--)
8936b0400d7Skarels ;
8946b0400d7Skarels /* Did the timer expire or did the DMR finish? */
8956b0400d7Skarels if ((addr->bsel1 & DMC_RUN) == 0) {
89679130c04Skarels log(LOG_ERR, "dmc%d: M820 Test Failed\n", unit);
8976b0400d7Skarels return;
8986b0400d7Skarels }
8996b0400d7Skarels
900d468a3c3Skarels /* restart DMC */
901d468a3c3Skarels dmcinit(unit);
902d468a3c3Skarels sc->sc_flag &= ~DMC_RESTART;
903d468a3c3Skarels s = spl5();
904d468a3c3Skarels dmcstart(unit);
905d468a3c3Skarels splx(s);
906d468a3c3Skarels sc->sc_if.if_collisions++; /* why not? */
907d468a3c3Skarels }
908d468a3c3Skarels
909d468a3c3Skarels /*
910d468a3c3Skarels * Reset a device and mark down.
911d468a3c3Skarels * Flush output queue and drop queue limit.
912d468a3c3Skarels */
dmcdown(unit)913d468a3c3Skarels dmcdown(unit)
914d468a3c3Skarels int unit;
915d468a3c3Skarels {
916d468a3c3Skarels register struct dmc_softc *sc = &dmc_softc[unit];
917d468a3c3Skarels register struct ifxmt *ifxp;
918d468a3c3Skarels
919d468a3c3Skarels ((struct dmcdevice *)(dmcinfo[unit]->ui_addr))->bsel1 = DMC_MCLR;
920d468a3c3Skarels sc->sc_flag &= ~(DMC_RUNNING | DMC_ONLINE);
921d468a3c3Skarels
92271555f1fSkarels for (ifxp = sc->sc_ifw; ifxp < &sc->sc_ifw[NXMT]; ifxp++) {
92371555f1fSkarels if (ifxp->ifw_xtofree) {
92471555f1fSkarels (void) m_freem(ifxp->ifw_xtofree);
92571555f1fSkarels ifxp->ifw_xtofree = 0;
9266b0400d7Skarels }
9276b0400d7Skarels }
928d468a3c3Skarels if_qflush(&sc->sc_if.if_snd);
9296b0400d7Skarels }
9306b0400d7Skarels
9316b0400d7Skarels /*
932d468a3c3Skarels * Watchdog timeout to see that transmitted packets don't
933d468a3c3Skarels * lose interrupts. The device has to be online (the first
934d468a3c3Skarels * transmission may block until the other side comes up).
9356b0400d7Skarels */
dmctimeout(unit)936d468a3c3Skarels dmctimeout(unit)
937d468a3c3Skarels int unit;
9386b0400d7Skarels {
9396b0400d7Skarels register struct dmc_softc *sc;
9406b0400d7Skarels struct dmcdevice *addr;
9416b0400d7Skarels
942d468a3c3Skarels sc = &dmc_softc[unit];
943d468a3c3Skarels if (sc->sc_flag & DMC_ONLINE) {
944d468a3c3Skarels addr = (struct dmcdevice *)(dmcinfo[unit]->ui_addr);
945d468a3c3Skarels log(LOG_ERR, "dmc%d: output timeout, bsel0=%b bsel2=%b\n",
946d468a3c3Skarels unit, addr->bsel0 & 0xff, DMC0BITS,
9476b0400d7Skarels addr->bsel2 & 0xff, DMC2BITS);
948d468a3c3Skarels dmcrestart(unit);
9496b0400d7Skarels }
9506b0400d7Skarels }
951014ee908Ssam #endif
952