Commit | Line | Data |
---|---|---|
ecfa166d | 1 | /* |
2aba78b9 KM |
2 | * Copyright (c) 1988 Regents of the University of California. |
3 | * All rights reserved. | |
4 | * | |
5 | * Redistribution and use in source and binary forms are permitted | |
616d42db KB |
6 | * provided that the above copyright notice and this paragraph are |
7 | * duplicated in all such forms and that any documentation, | |
8 | * advertising materials, and other materials related to such | |
9 | * distribution and use acknowledge that the software was developed | |
10 | * by the University of California, Berkeley. The name of the | |
11 | * University may not be used to endorse or promote products derived | |
12 | * from this software without specific prior written permission. | |
13 | * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR | |
14 | * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED | |
15 | * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. | |
2aba78b9 | 16 | * |
3ba98c3a | 17 | * @(#)if_dmv.c 7.7 (Berkeley) %G% |
616d42db KB |
18 | */ |
19 | ||
20 | /* | |
ecfa166d MK |
21 | * DMV-11 Driver |
22 | * | |
23 | * Qbus Sync DDCMP interface - DMV operated in full duplex, point to point mode | |
24 | * | |
2aba78b9 KM |
25 | * Written by Bob Kridle of Mt Xinu |
26 | * starting from if_dmc.c version 6.12 dated 4/23/86 | |
ecfa166d MK |
27 | */ |
28 | ||
29 | #include "dmv.h" | |
30 | #if NDMV > 0 | |
31 | ||
ecfa166d MK |
32 | #include "param.h" |
33 | #include "systm.h" | |
34 | #include "mbuf.h" | |
35 | #include "buf.h" | |
36 | #include "ioctl.h" /* must precede tty.h */ | |
37 | #include "tty.h" | |
38 | #include "protosw.h" | |
39 | #include "socket.h" | |
40 | #include "syslog.h" | |
41 | #include "vmmac.h" | |
42 | #include "errno.h" | |
bb08cf86 MK |
43 | #include "time.h" |
44 | #include "kernel.h" | |
ecfa166d MK |
45 | |
46 | #include "../net/if.h" | |
47 | #include "../net/netisr.h" | |
48 | #include "../net/route.h" | |
49 | ||
50 | #ifdef INET | |
51 | #include "../netinet/in.h" | |
52 | #include "../netinet/in_systm.h" | |
53 | #include "../netinet/in_var.h" | |
54 | #include "../netinet/ip.h" | |
55 | #endif | |
56 | ||
57 | #include "../vax/cpu.h" | |
58 | #include "../vax/mtpr.h" | |
bb08cf86 | 59 | #include "../vax/pte.h" |
ecfa166d MK |
60 | #include "../vaxuba/ubareg.h" |
61 | #include "../vaxuba/ubavar.h" | |
bb08cf86 MK |
62 | #include "if_uba.h" |
63 | #include "if_dmv.h" | |
ecfa166d | 64 | |
ecfa166d | 65 | int dmv_timeout = 8; /* timeout value */ |
ecfa166d MK |
66 | |
67 | /* | |
68 | * Driver information for auto-configuration stuff. | |
69 | */ | |
70 | int dmvprobe(), dmvattach(), dmvinit(), dmvioctl(); | |
bb08cf86 | 71 | int dmvoutput(), dmvreset(), dmvtimeout(); |
ecfa166d MK |
72 | struct uba_device *dmvinfo[NDMV]; |
73 | u_short dmvstd[] = { 0 }; | |
74 | struct uba_driver dmvdriver = | |
75 | { dmvprobe, 0, dmvattach, 0, dmvstd, "dmv", dmvinfo }; | |
76 | ||
77 | /* | |
78 | * Don't really know how many buffers/commands can be queued to a DMV-11. | |
79 | * Manual doesn't say... Perhaps we can look at a DEC driver some day. | |
bb08cf86 | 80 | * These numbers ame from DMC/DMR driver. |
ecfa166d MK |
81 | */ |
82 | #define NRCV 5 | |
83 | #define NXMT 3 | |
84 | #define NCMDS (NRCV+NXMT+4) /* size of command queue */ | |
85 | ||
bb08cf86 MK |
86 | #ifdef DEBUG |
87 | #define printd(f) if (sc->sc_if.if_flags & IFF_DEBUG) \ | |
88 | printf("DMVDEBUG: dmv%d: ", unit), printf(f) | |
89 | #else | |
90 | #define printd(f) /* nil */ | |
91 | #endif | |
ecfa166d MK |
92 | |
93 | /* error reporting intervals */ | |
94 | ||
95 | #define DMV_RPRTE 1 | |
96 | #define DMV_RPTTE 1 | |
97 | #define DMV_RPSTE 1 | |
98 | #define DMV_RPNXM 1 | |
99 | #define DMV_RPMODD 1 | |
100 | #define DMV_RPQOVF 1 | |
101 | #define DMV_RPCXRL 1 | |
d9bcdfcc MK |
102 | |
103 | /* number of errors to accept before trying a reset */ | |
104 | #define DMV_RPUNKNOWN 10 | |
ecfa166d MK |
105 | |
106 | struct dmv_command { | |
107 | u_char qp_mask; /* Which registers to set up */ | |
108 | #define QP_TRIB 0x01 | |
109 | #define QP_SEL4 0x02 | |
110 | #define QP_SEL6 0x04 | |
111 | #define QP_SEL10 0x08 | |
112 | u_char qp_cmd; | |
113 | u_char qp_tributary; | |
114 | u_short qp_sel4; | |
115 | u_short qp_sel6; | |
116 | u_short qp_sel10; | |
117 | struct dmv_command *qp_next; /* next command on queue */ | |
118 | }; | |
119 | ||
120 | #define qp_lowbufaddr qp_ | |
121 | ||
122 | struct dmvbufs { | |
123 | int ubinfo; /* from uballoc */ | |
124 | short cc; /* buffer size */ | |
125 | short flags; /* access control */ | |
126 | }; | |
127 | ||
128 | #define DBUF_OURS 0 /* buffer is available */ | |
129 | #define DBUF_DMVS 1 /* buffer claimed by somebody */ | |
130 | #define DBUF_XMIT 4 /* transmit buffer */ | |
131 | #define DBUF_RCV 8 /* receive buffer */ | |
132 | ||
133 | ||
134 | /* | |
135 | * DMV software status per interface. | |
136 | * | |
137 | * Each interface is referenced by a network interface structure, | |
138 | * sc_if, which the routing code uses to locate the interface. | |
139 | * This structure contains the output queue for the interface, its address, ... | |
140 | * We also have, for each interface, a set of 7 UBA interface structures | |
141 | * for each, which | |
142 | * contain information about the UNIBUS resources held by the interface: | |
143 | * map registers, buffered data paths, etc. Information is cached in this | |
144 | * structure for use by the if_uba.c routines in running the interface | |
145 | * efficiently. | |
146 | */ | |
147 | struct dmv_softc { | |
148 | struct ifnet sc_if; /* network-visible interface */ | |
ecfa166d MK |
149 | short sc_oused; /* output buffers currently in use */ |
150 | short sc_iused; /* input buffers given to DMV */ | |
151 | short sc_flag; /* flags */ | |
3ba98c3a | 152 | short sc_ipl; /* interrupt priority */ |
ecfa166d MK |
153 | int sc_ubinfo; /* UBA mapping info for base table */ |
154 | int sc_errors[8]; /* error counters */ | |
155 | #define sc_rte sc_errors[0] /* receive threshhold error */ | |
156 | #define sc_xte sc_errors[1] /* xmit threshhold error */ | |
157 | #define sc_ste sc_errors[2] /* select threshhold error */ | |
158 | #define sc_nxm sc_errors[3] /* non-existant memory */ | |
159 | #define sc_modd sc_errors[4] /* modem disconnect */ | |
160 | #define sc_qovf sc_errors[5] /* command/response queue overflow */ | |
161 | #define sc_cxrl sc_errors[6] /* carrier loss */ | |
162 | #define sc_unknown sc_errors[7] /* other errors - look in DMV manual */ | |
bb08cf86 MK |
163 | struct dmvbufs sc_rbufs[NRCV]; /* receive buffer info */ |
164 | struct dmvbufs sc_xbufs[NXMT]; /* transmit buffer info */ | |
165 | struct ifubinfo sc_ifuba; /* UNIBUS resources */ | |
166 | struct ifrw sc_ifr[NRCV]; /* UNIBUS receive buffer maps */ | |
167 | struct ifxmt sc_ifw[NXMT]; /* UNIBUS receive buffer maps */ | |
ecfa166d MK |
168 | /* command queue stuff */ |
169 | struct dmv_command sc_cmdbuf[NCMDS]; | |
170 | struct dmv_command *sc_qhead; /* head of command queue */ | |
171 | struct dmv_command *sc_qtail; /* tail of command queue */ | |
172 | struct dmv_command *sc_qactive; /* command in progress */ | |
173 | struct dmv_command *sc_qfreeh; /* head of list of free cmd buffers */ | |
174 | struct dmv_command *sc_qfreet; /* tail of list of free cmd buffers */ | |
175 | /* end command queue stuff */ | |
176 | } dmv_softc[NDMV]; | |
177 | ||
178 | /* flags */ | |
bb08cf86 MK |
179 | #define DMV_RESTART 0x01 /* software restart in progress */ |
180 | #define DMV_ONLINE 0x02 /* device managed to transmit */ | |
181 | #define DMV_RUNNING 0x04 /* device initialized */ | |
ecfa166d MK |
182 | |
183 | ||
184 | /* queue manipulation macros */ | |
185 | #define QUEUE_AT_HEAD(qp, head, tail) \ | |
186 | (qp)->qp_next = (head); \ | |
187 | (head) = (qp); \ | |
188 | if ((tail) == (struct dmv_command *) 0) \ | |
189 | (tail) = (head) | |
190 | ||
191 | #define QUEUE_AT_TAIL(qp, head, tail) \ | |
192 | if ((tail)) \ | |
193 | (tail)->qp_next = (qp); \ | |
194 | else \ | |
195 | (head) = (qp); \ | |
196 | (qp)->qp_next = (struct dmv_command *) 0; \ | |
197 | (tail) = (qp) | |
198 | ||
199 | #define DEQUEUE(head, tail) \ | |
200 | (head) = (head)->qp_next;\ | |
201 | if ((head) == (struct dmv_command *) 0)\ | |
202 | (tail) = (head) | |
203 | ||
3ba98c3a | 204 | dmvprobe(reg, ui) |
ecfa166d | 205 | caddr_t reg; |
3ba98c3a | 206 | struct uba_device *ui; |
ecfa166d MK |
207 | { |
208 | register int br, cvec; | |
209 | register struct dmvdevice *addr = (struct dmvdevice *)reg; | |
210 | register int i; | |
211 | ||
212 | #ifdef lint | |
213 | br = 0; cvec = br; br = cvec; | |
214 | dmvrint(0); dmvxint(0); | |
215 | #endif | |
216 | addr->bsel1 = DMV_MCLR; | |
217 | for (i = 100000; i && (addr->bsel1 & DMV_RUN) == 0; i--) | |
218 | ; | |
219 | if ((addr->bsel1 & DMV_RUN) == 0) { | |
220 | printf("dmvprobe: can't start device\n" ); | |
221 | return (0); | |
222 | } | |
223 | if ((addr->bsel4 != 033) || (addr->bsel6 != 0305)) | |
224 | { | |
225 | printf("dmvprobe: device init failed, bsel4=%o, bsel6=%o\n", | |
226 | addr->bsel4, addr->bsel6); | |
227 | return (0); | |
228 | } | |
3ba98c3a | 229 | (void) spl6(); |
ecfa166d MK |
230 | addr->bsel0 = DMV_RQI|DMV_IEI|DMV_IEO; |
231 | DELAY(1000000); | |
232 | addr->bsel1 = DMV_MCLR; | |
233 | for (i = 100000; i && (addr->bsel1 & DMV_RUN) == 0; i--) | |
234 | ; | |
3ba98c3a MK |
235 | dmv_softc[ui->ui_unit].sc_ipl = br = qbgetpri(); |
236 | return (sizeof(struct dmvdevice)); | |
ecfa166d MK |
237 | } |
238 | ||
239 | /* | |
240 | * Interface exists: make available by filling in network interface | |
241 | * record. System will initialize the interface when it is ready | |
242 | * to accept packets. | |
243 | */ | |
244 | dmvattach(ui) | |
245 | register struct uba_device *ui; | |
246 | { | |
247 | register struct dmv_softc *sc = &dmv_softc[ui->ui_unit]; | |
248 | ||
249 | sc->sc_if.if_unit = ui->ui_unit; | |
250 | sc->sc_if.if_name = "dmv"; | |
251 | sc->sc_if.if_mtu = DMVMTU; | |
252 | sc->sc_if.if_init = dmvinit; | |
253 | sc->sc_if.if_output = dmvoutput; | |
254 | sc->sc_if.if_ioctl = dmvioctl; | |
255 | sc->sc_if.if_reset = dmvreset; | |
bb08cf86 | 256 | sc->sc_if.if_watchdog = dmvtimeout; |
ecfa166d MK |
257 | sc->sc_if.if_flags = IFF_POINTOPOINT; |
258 | sc->sc_ifuba.iff_flags = UBA_CANTWAIT; | |
259 | ||
ecfa166d MK |
260 | if_attach(&sc->sc_if); |
261 | } | |
262 | ||
263 | /* | |
264 | * Reset of interface after UNIBUS reset. | |
265 | * If interface is on specified UBA, reset its state. | |
266 | */ | |
267 | dmvreset(unit, uban) | |
268 | int unit, uban; | |
269 | { | |
270 | register struct uba_device *ui; | |
271 | register struct dmv_softc *sc = &dmv_softc[unit]; | |
272 | ||
273 | if (unit >= NDMV || (ui = dmvinfo[unit]) == 0 || ui->ui_alive == 0 || | |
274 | ui->ui_ubanum != uban) | |
275 | return; | |
276 | printf(" dmv%d", unit); | |
277 | sc->sc_flag = 0; | |
278 | sc->sc_if.if_flags &= ~IFF_RUNNING; | |
279 | dmvinit(unit); | |
280 | } | |
281 | ||
282 | /* | |
283 | * Initialization of interface; reinitialize UNIBUS usage. | |
284 | */ | |
285 | dmvinit(unit) | |
286 | int unit; | |
287 | { | |
288 | register struct dmv_softc *sc = &dmv_softc[unit]; | |
289 | register struct uba_device *ui = dmvinfo[unit]; | |
290 | register struct dmvdevice *addr; | |
291 | register struct ifnet *ifp = &sc->sc_if; | |
292 | register struct ifrw *ifrw; | |
293 | register struct ifxmt *ifxp; | |
294 | register struct dmvbufs *rp; | |
295 | register struct dmv_command *qp; | |
296 | struct ifaddr *ifa; | |
297 | int base; | |
298 | int s; | |
299 | ||
300 | addr = (struct dmvdevice *)ui->ui_addr; | |
301 | ||
302 | /* | |
303 | * Check to see that an address has been set | |
304 | * (both local and destination for an address family). | |
305 | */ | |
306 | for (ifa = ifp->if_addrlist; ifa; ifa = ifa->ifa_next) | |
307 | if (ifa->ifa_addr.sa_family && ifa->ifa_dstaddr.sa_family) | |
308 | break; | |
309 | if (ifa == (struct ifaddr *) 0) | |
310 | return; | |
311 | ||
312 | if ((addr->bsel1&DMV_RUN) == 0) { | |
313 | log(LOG_CRIT, "dmvinit: dmv%d not running\n", unit); | |
314 | ifp->if_flags &= ~IFF_UP; | |
315 | return; | |
316 | } | |
bb08cf86 | 317 | printd(("dmvinit\n")); |
ecfa166d MK |
318 | /* initialize UNIBUS resources */ |
319 | sc->sc_iused = sc->sc_oused = 0; | |
320 | if ((ifp->if_flags & IFF_RUNNING) == 0) { | |
321 | if (if_ubaminit( | |
322 | &sc->sc_ifuba, | |
323 | ui->ui_ubanum, | |
324 | sizeof(struct dmv_header), | |
325 | (int)btoc(DMVMTU), | |
326 | sc->sc_ifr, | |
327 | NRCV, | |
328 | sc->sc_ifw, | |
329 | NXMT | |
330 | ) == 0) { | |
331 | log(LOG_CRIT, "dmvinit: dmv%d can't allocate uba resources\n", unit); | |
332 | ifp->if_flags &= ~IFF_UP; | |
333 | return; | |
334 | } | |
335 | ifp->if_flags |= IFF_RUNNING; | |
336 | } | |
bb08cf86 MK |
337 | /* |
338 | * Limit packets enqueued until we see if we're on the air. | |
339 | */ | |
340 | ifp->if_snd.ifq_maxlen = 3; | |
341 | ||
ecfa166d MK |
342 | |
343 | /* initialize buffer pool */ | |
344 | /* receives */ | |
345 | ifrw = &sc->sc_ifr[0]; | |
346 | for (rp = &sc->sc_rbufs[0]; rp < &sc->sc_rbufs[NRCV]; rp++) { | |
3ba98c3a | 347 | rp->ubinfo = UBAI_ADDR(ifrw->ifrw_info); |
ecfa166d MK |
348 | rp->cc = DMVMTU + sizeof (struct dmv_header); |
349 | rp->flags = DBUF_OURS|DBUF_RCV; | |
350 | ifrw++; | |
351 | } | |
352 | /* transmits */ | |
353 | ifxp = &sc->sc_ifw[0]; | |
354 | for (rp = &sc->sc_xbufs[0]; rp < &sc->sc_xbufs[NXMT]; rp++) { | |
3ba98c3a | 355 | rp->ubinfo = UBAI_ADDR(ifxp->ifw_info); |
ecfa166d MK |
356 | rp->cc = 0; |
357 | rp->flags = DBUF_OURS|DBUF_XMIT; | |
358 | ifxp++; | |
359 | } | |
360 | ||
361 | /* set up command queues */ | |
362 | sc->sc_qfreeh = sc->sc_qfreet | |
363 | = sc->sc_qhead = sc->sc_qtail = sc->sc_qactive = | |
364 | (struct dmv_command *)0; | |
365 | /* set up free command buffer list */ | |
366 | for (qp = &sc->sc_cmdbuf[0]; qp < &sc->sc_cmdbuf[NCMDS]; qp++) { | |
367 | QUEUE_AT_HEAD(qp, sc->sc_qfreeh, sc->sc_qfreet); | |
368 | } | |
369 | if(sc->sc_flag & DMV_RUNNING) | |
370 | dmvload( sc, DMV_CNTRLI, (QP_TRIB|QP_SEL6), 1, 0, DMV_REQHS,0); | |
371 | else | |
372 | dmvload( sc, DMV_CNTRLI, (QP_TRIB|QP_SEL6), 1, 0, DMV_ESTTRIB,0); | |
373 | dmvload( sc, DMV_CNTRLI, (QP_TRIB|QP_SEL6), 1, 0, DMV_REQSUS,0); | |
374 | sc->sc_flag |= (DMV_RESTART|DMV_RUNNING); | |
bb08cf86 | 375 | sc->sc_flag &= ~DMV_ONLINE; |
ecfa166d MK |
376 | addr->bsel0 |= DMV_IEO; |
377 | } | |
378 | ||
379 | /* | |
380 | * Start output on interface. Get another datagram | |
381 | * to send from the interface queue and map it to | |
382 | * the interface before starting output. | |
383 | * | |
384 | * Must be called at spl 5 | |
385 | */ | |
386 | dmvstart(dev) | |
387 | dev_t dev; | |
388 | { | |
389 | int unit = minor(dev); | |
390 | register struct dmv_softc *sc = &dmv_softc[unit]; | |
391 | struct mbuf *m; | |
392 | register struct dmvbufs *rp; | |
393 | register int n; | |
394 | ||
395 | /* | |
396 | * Dequeue up to NXMT requests and map them to the UNIBUS. | |
397 | * If no more requests, or no dmv buffers available, just return. | |
398 | */ | |
bb08cf86 | 399 | printd(("dmvstart\n")); |
ecfa166d MK |
400 | n = 0; |
401 | for (rp = &sc->sc_xbufs[0]; rp < &sc->sc_xbufs[NXMT]; rp++ ) { | |
402 | /* find an available buffer */ | |
403 | if ((rp->flags & DBUF_DMVS) == 0) { | |
404 | IF_DEQUEUE(&sc->sc_if.if_snd, m); | |
405 | if (m == 0) | |
406 | return; | |
407 | /* mark it dmvs */ | |
408 | rp->flags |= (DBUF_DMVS); | |
409 | /* | |
410 | * Have request mapped to UNIBUS for transmission | |
411 | * and start the output. | |
412 | */ | |
413 | rp->cc = if_ubaput(&sc->sc_ifuba, &sc->sc_ifw[n], m); | |
bb08cf86 MK |
414 | if (++sc->sc_oused == 1) |
415 | sc->sc_if.if_timer = dmv_timeout; | |
ecfa166d MK |
416 | dmvload( |
417 | sc, | |
418 | DMV_BACCX, | |
419 | QP_TRIB|QP_SEL4|QP_SEL6|QP_SEL10, | |
420 | 1, | |
421 | rp->ubinfo, | |
422 | (rp->ubinfo>>16)&0x3f, | |
423 | rp->cc | |
424 | ); | |
425 | } | |
426 | n++; | |
427 | } | |
428 | } | |
429 | ||
430 | /* | |
431 | * Utility routine to load the DMV device registers. | |
432 | */ | |
433 | dmvload(sc, cmd, mask, tributary, sel4, sel6, sel10) | |
434 | register struct dmv_softc *sc; | |
435 | u_char cmd, tributary, mask; | |
436 | u_short sel4, sel6, sel10; | |
437 | { | |
438 | register struct dmvdevice *addr; | |
439 | register int unit, sps; | |
440 | register struct dmv_command *qp; | |
441 | ||
442 | unit = sc - dmv_softc; | |
bb08cf86 | 443 | printd(("dmvload: cmd=%x mask=%x trib=%x sel4=%x sel6=%x sel10=%x\n", |
ecfa166d MK |
444 | (unsigned) cmd, |
445 | (unsigned) mask, | |
446 | (unsigned) tributary, | |
447 | (unsigned) sel4, | |
448 | (unsigned) sel6, | |
449 | (unsigned) sel10 | |
bb08cf86 | 450 | )); |
ecfa166d MK |
451 | addr = (struct dmvdevice *)dmvinfo[unit]->ui_addr; |
452 | sps = spl5(); | |
453 | ||
454 | /* grab a command buffer from the free list */ | |
455 | if ((qp = sc->sc_qfreeh) == (struct dmv_command *)0) | |
456 | panic("dmv command queue overflow"); | |
457 | DEQUEUE(sc->sc_qfreeh, sc->sc_qfreet); | |
458 | ||
459 | /* fill in requested info */ | |
460 | qp->qp_cmd = cmd; | |
461 | qp->qp_mask = mask; | |
462 | qp->qp_tributary = tributary; | |
463 | qp->qp_sel4 = sel4; | |
464 | qp->qp_sel6 = sel6; | |
465 | qp->qp_sel10 = sel10; | |
466 | ||
467 | if (sc->sc_qactive) { /* command in progress */ | |
468 | if (cmd == DMV_BACCR) { /* supply read buffers first */ | |
469 | QUEUE_AT_HEAD(qp, sc->sc_qhead, sc->sc_qtail); | |
470 | } else { | |
471 | QUEUE_AT_TAIL(qp, sc->sc_qhead, sc->sc_qtail); | |
472 | } | |
473 | } else { /* command port free */ | |
474 | sc->sc_qactive = qp; | |
475 | addr->bsel0 = (DMV_RQI|DMV_IEI|DMV_IEO); | |
476 | } | |
477 | splx(sps); | |
478 | } | |
479 | /* | |
480 | * DMV interface input interrupt. | |
481 | * Ready to accept another command, | |
482 | * pull one off the command queue. | |
483 | */ | |
484 | dmvrint(unit) | |
485 | int unit; | |
486 | { | |
487 | register struct dmv_softc *sc; | |
488 | register struct dmvdevice *addr; | |
489 | register struct dmv_command *qp; | |
490 | register int n; | |
491 | ||
492 | addr = (struct dmvdevice *)dmvinfo[unit]->ui_addr; | |
493 | sc = &dmv_softc[unit]; | |
3ba98c3a | 494 | splx(sc->sc_ipl); |
bb08cf86 | 495 | printd(("dmvrint\n")); |
ecfa166d MK |
496 | if ((qp = sc->sc_qactive) == (struct dmv_command *) 0) { |
497 | log(LOG_WARNING, "dmvrint: dmv%d no command\n", unit); | |
498 | return; | |
499 | } | |
500 | while (addr->bsel2&DMV_RDI) { | |
501 | if(qp->qp_mask&QP_SEL4) | |
502 | addr->wsel4 = qp->qp_sel4; | |
503 | if(qp->qp_mask&QP_SEL6) | |
504 | addr->wsel6 = qp->qp_sel6; | |
505 | if(qp->qp_mask&QP_SEL10) { | |
506 | addr->wsel10 = qp->qp_sel10; | |
507 | qp->qp_cmd |= DMV_22BIT; | |
508 | } | |
509 | if(qp->qp_mask&QP_TRIB) | |
510 | addr->wsel2 = qp->qp_cmd|(qp->qp_tributary << 8); | |
511 | else | |
512 | addr->bsel2 = qp->qp_cmd; | |
513 | QUEUE_AT_HEAD(qp, sc->sc_qfreeh, sc->sc_qfreet); | |
514 | if ((sc->sc_qactive = sc->sc_qhead) == (struct dmv_command *)0) | |
515 | break; | |
516 | qp = sc->sc_qactive; | |
517 | DEQUEUE(sc->sc_qhead, sc->sc_qtail); | |
518 | if (addr->bsel2&DMV_RDO) | |
519 | break; | |
520 | } | |
521 | if (!sc->sc_qactive) { | |
522 | if(addr->bsel2&DMV_RDI) { | |
523 | /* clear RQI prior to last command per DMV manual */ | |
524 | addr->bsel0 &= ~DMV_RQI; | |
525 | addr->wsel6 = DMV_NOP; | |
526 | addr->bsel2 = DMV_CNTRLI; | |
527 | } | |
528 | addr->bsel0 = DMV_IEO; | |
529 | } | |
530 | else /* RDO set or DMV still holding CSR */ | |
531 | addr->bsel0 = (DMV_RQI|DMV_IEI|DMV_IEO); | |
532 | ||
533 | } | |
534 | ||
535 | /* | |
536 | * DMV interface output interrupt. | |
537 | * A transfer may have completed, check for errors. | |
538 | * If it was a read, notify appropriate protocol. | |
539 | * If it was a write, pull the next one off the queue. | |
540 | */ | |
541 | dmvxint(unit) | |
542 | int unit; | |
543 | { | |
544 | register struct dmv_softc *sc; | |
545 | register struct ifnet *ifp; | |
546 | struct uba_device *ui = dmvinfo[unit]; | |
547 | struct dmvdevice *addr; | |
548 | struct mbuf *m; | |
549 | struct ifqueue *inq; | |
550 | int sel2, sel3, sel4, sel6, sel10, pkaddr, len, s; | |
551 | register struct ifrw *ifrw; | |
552 | register struct dmvbufs *rp; | |
553 | register struct ifxmt *ifxp; | |
554 | struct dmv_header *dh; | |
bb08cf86 | 555 | int off, resid; |
ecfa166d MK |
556 | |
557 | addr = (struct dmvdevice *)ui->ui_addr; | |
558 | sc = &dmv_softc[unit]; | |
3ba98c3a | 559 | splx(sc->sc_ipl); |
ecfa166d MK |
560 | ifp = &sc->sc_if; |
561 | ||
562 | while (addr->bsel2 & DMV_RDO) { | |
563 | ||
564 | sel2 = addr->bsel2; | |
565 | sel3 = addr->bsel3; | |
566 | sel4 = addr->wsel4; /* release port */ | |
567 | sel6 = addr->wsel6; | |
568 | if(sel2 & DMV_22BIT) | |
569 | sel10 = addr->wsel10; | |
570 | addr->bsel2 &= ~DMV_RDO; | |
571 | pkaddr = sel4 | ((sel6 & 0x3f) << 16); | |
bb08cf86 | 572 | printd(("dmvxint: sel2=%x sel4=%x sel6=%x sel10=%x pkaddr=%x\n", |
ecfa166d MK |
573 | (unsigned) sel2, |
574 | (unsigned) sel4, | |
575 | (unsigned) sel6, | |
576 | (unsigned) sel10, | |
577 | (unsigned) pkaddr | |
bb08cf86 | 578 | )); |
ecfa166d MK |
579 | if((sc->sc_flag & DMV_RUNNING)==0) { |
580 | log(LOG_WARNING, "dmvxint: dmv%d xint while down\n", unit); | |
581 | return; | |
582 | } | |
583 | switch (sel2 & 07) { | |
584 | case DMV_BDRUS: | |
585 | /* | |
586 | * A read has completed. | |
587 | * Pass packet to type specific | |
588 | * higher-level input routine. | |
589 | */ | |
590 | ifp->if_ipackets++; | |
591 | /* find location in dmvuba struct */ | |
592 | ifrw= &sc->sc_ifr[0]; | |
593 | for (rp = &sc->sc_rbufs[0]; rp < &sc->sc_rbufs[NRCV]; rp++) { | |
594 | if(rp->ubinfo == pkaddr) | |
595 | break; | |
596 | ifrw++; | |
597 | } | |
598 | if (rp >= &sc->sc_rbufs[NRCV]) | |
599 | panic("dmv rcv"); | |
600 | if ((rp->flags & DBUF_DMVS) == 0) | |
601 | log(LOG_WARNING, "dmvxint: dmv%d done unalloc rbuf\n", unit); | |
602 | ||
603 | len = (sel10&0x3fff) - sizeof (struct dmv_header); | |
604 | if (len < 0 || len > DMVMTU) { | |
605 | ifp->if_ierrors++; | |
606 | log(LOG_ERR, "dmvxint: dmv%d bad rcv pkt addr 0x%x len 0x%x\n", | |
607 | unit, pkaddr, len); | |
608 | goto setup; | |
609 | } | |
610 | /* | |
611 | * Deal with trailer protocol: if type is trailer | |
612 | * get true type from first 16-bit word past data. | |
613 | * Remember that type was trailer by setting off. | |
614 | */ | |
615 | dh = (struct dmv_header *)ifrw->ifrw_addr; | |
616 | dh->dmv_type = ntohs((u_short)dh->dmv_type); | |
617 | #define dmvdataaddr(dh, off, type) ((type)(((caddr_t)((dh)+1)+(off)))) | |
618 | if (dh->dmv_type >= DMV_TRAILER && | |
619 | dh->dmv_type < DMV_TRAILER+DMV_NTRAILER) { | |
620 | off = (dh->dmv_type - DMV_TRAILER) * 512; | |
621 | if (off >= DMVMTU) | |
622 | goto setup; /* sanity */ | |
623 | dh->dmv_type = ntohs(*dmvdataaddr(dh, off, u_short *)); | |
624 | resid = ntohs(*(dmvdataaddr(dh, off+2, u_short *))); | |
625 | if (off + resid > len) | |
626 | goto setup; /* sanity */ | |
627 | len = off + resid; | |
628 | } else | |
629 | off = 0; | |
630 | if (len == 0) | |
631 | goto setup; | |
632 | ||
633 | /* | |
634 | * Pull packet off interface. Off is nonzero if | |
635 | * packet has trailing header; dmv_get will then | |
636 | * force this header information to be at the front, | |
637 | * but we still have to drop the type and length | |
638 | * which are at the front of any trailer data. | |
639 | */ | |
640 | m = if_ubaget(&sc->sc_ifuba, ifrw, len, off, ifp); | |
641 | if (m == 0) | |
642 | goto setup; | |
3ba98c3a MK |
643 | if (off) { |
644 | ifp = *(mtod(m, struct ifnet **)); | |
645 | m->m_off += 2 * sizeof (u_short); | |
646 | m->m_len -= 2 * sizeof (u_short); | |
647 | *(mtod(m, struct ifnet **)) = ifp; | |
648 | } | |
ecfa166d MK |
649 | switch (dh->dmv_type) { |
650 | #ifdef INET | |
651 | case DMV_IPTYPE: | |
652 | schednetisr(NETISR_IP); | |
653 | inq = &ipintrq; | |
654 | break; | |
655 | #endif | |
656 | default: | |
657 | m_freem(m); | |
658 | goto setup; | |
659 | } | |
660 | ||
661 | s = splimp(); | |
662 | if (IF_QFULL(inq)) { | |
663 | IF_DROP(inq); | |
664 | m_freem(m); | |
665 | } else | |
666 | IF_ENQUEUE(inq, m); | |
667 | splx(s); | |
668 | setup: | |
669 | /* is this needed? */ | |
3ba98c3a | 670 | rp->ubinfo = UBAI_ADDR(ifrw->ifrw_info); |
ecfa166d MK |
671 | dmvload( |
672 | sc, | |
673 | DMV_BACCR, | |
674 | QP_SEL4|QP_SEL6|QP_SEL10, | |
675 | 0, | |
3ba98c3a | 676 | (u_short) rp->ubinfo, |
ecfa166d MK |
677 | (rp->ubinfo>>16)&0x3f, |
678 | rp->cc | |
679 | ); | |
680 | break; | |
681 | case DMV_BDXSA: | |
682 | /* | |
683 | * A write has completed, start another | |
684 | * transfer if there is more data to send. | |
685 | */ | |
686 | ifp->if_opackets++; | |
687 | /* find associated dmvbuf structure */ | |
688 | ifxp = &sc->sc_ifw[0]; | |
689 | for (rp = &sc->sc_xbufs[0]; rp < &sc->sc_xbufs[NXMT]; rp++) { | |
690 | if(rp->ubinfo == pkaddr) | |
691 | break; | |
692 | ifxp++; | |
693 | } | |
694 | if (rp >= &sc->sc_xbufs[NXMT]) { | |
695 | log(LOG_ERR, "dmv%d: bad packet address 0x%x\n", | |
696 | unit, pkaddr); | |
697 | break; | |
698 | } | |
699 | if ((rp->flags & DBUF_DMVS) == 0) | |
700 | log(LOG_ERR, "dmvxint: dmv%d unallocated packet 0x%x\n", | |
701 | unit, pkaddr); | |
702 | /* mark buffer free */ | |
703 | if (ifxp->ifw_xtofree) { | |
704 | (void)m_freem(ifxp->ifw_xtofree); | |
705 | ifxp->ifw_xtofree = 0; | |
706 | } | |
707 | rp->flags &= ~DBUF_DMVS; | |
bb08cf86 MK |
708 | if (--sc->sc_oused == 0) |
709 | sc->sc_if.if_timer = 0; | |
710 | else | |
711 | sc->sc_if.if_timer = dmv_timeout; | |
712 | if ((sc->sc_flag & DMV_ONLINE) == 0) { | |
713 | extern int ifqmaxlen; | |
714 | ||
715 | /* | |
716 | * We're on the air. | |
717 | * Open the queue to the usual value. | |
718 | */ | |
719 | sc->sc_flag |= DMV_ONLINE; | |
720 | ifp->if_snd.ifq_maxlen = ifqmaxlen; | |
721 | } | |
ecfa166d MK |
722 | break; |
723 | ||
724 | case DMV_CNTRLO: | |
725 | /* ACCUMULATE STATISTICS */ | |
ecfa166d MK |
726 | switch(sel6&DMV_EEC) { |
727 | case DMV_ORUN: | |
728 | if(sc->sc_flag & DMV_RESTART) { | |
729 | load_rec_bufs(sc); | |
730 | sc->sc_flag &= ~DMV_RESTART; | |
731 | log(LOG_INFO, | |
bb08cf86 | 732 | "dmv%d: far end on-line\n", unit); |
ecfa166d MK |
733 | } else { |
734 | log(LOG_WARNING, | |
bb08cf86 MK |
735 | "dmv%d: far end restart\n", unit); |
736 | goto restart; | |
ecfa166d MK |
737 | } |
738 | break; | |
739 | case DMV_RTE: | |
740 | ifp->if_ierrors++; | |
ecfa166d | 741 | if ((sc->sc_rte++ % DMV_RPRTE) == 0) |
d9bcdfcc | 742 | log(LOG_WARNING, |
bb08cf86 | 743 | "dmv%d: receive threshold error\n", |
d9bcdfcc | 744 | unit); |
ecfa166d MK |
745 | break; |
746 | case DMV_TTE: | |
747 | ifp->if_oerrors++; | |
ecfa166d | 748 | if ((sc->sc_xte++ % DMV_RPTTE) == 0) |
d9bcdfcc | 749 | log(LOG_WARNING, |
bb08cf86 | 750 | "dmv%d: transmit threshold error\n", |
d9bcdfcc | 751 | unit); |
ecfa166d MK |
752 | break; |
753 | case DMV_STE: | |
ecfa166d | 754 | if ((sc->sc_ste++ % DMV_RPSTE) == 0) |
d9bcdfcc | 755 | log(LOG_WARNING, |
bb08cf86 | 756 | "dmv%d: select threshold error\n", |
d9bcdfcc | 757 | unit); |
ecfa166d MK |
758 | break; |
759 | case DMV_NXM: | |
d9bcdfcc MK |
760 | if ((sc->sc_nxm++ % DMV_RPNXM) == 0) |
761 | log(LOG_WARNING, | |
bb08cf86 | 762 | "dmv%d: nonexistent memory error\n", |
d9bcdfcc | 763 | unit); |
ecfa166d MK |
764 | break; |
765 | case DMV_MODD: | |
bb08cf86 | 766 | if ((sc->sc_modd++ % DMV_RPMODD) == 0) { |
d9bcdfcc | 767 | log(LOG_WARNING, |
bb08cf86 | 768 | "dmv%d: modem disconnected error\n", |
d9bcdfcc | 769 | unit); |
bb08cf86 MK |
770 | goto restart; |
771 | } | |
ecfa166d MK |
772 | break; |
773 | case DMV_CXRL: | |
ecfa166d | 774 | if ((sc->sc_cxrl++ % DMV_RPCXRL) == 0) |
d9bcdfcc | 775 | log(LOG_WARNING, |
bb08cf86 | 776 | "dmv%d: carrier loss error\n", |
d9bcdfcc | 777 | unit); |
ecfa166d MK |
778 | break; |
779 | case DMV_QOVF: | |
780 | log(LOG_WARNING, | |
bb08cf86 MK |
781 | "dmv%d: response queue overflow\n", |
782 | unit); | |
ecfa166d | 783 | sc->sc_qovf++; |
bb08cf86 | 784 | goto restart; |
ecfa166d MK |
785 | |
786 | default: | |
787 | log(LOG_WARNING, | |
bb08cf86 MK |
788 | "dmv%d: unknown error %o\n", |
789 | unit, sel6&DMV_EEC); | |
ecfa166d | 790 | if ((sc->sc_unknown++ % DMV_RPUNKNOWN) == 0) |
bb08cf86 | 791 | goto restart; |
ecfa166d MK |
792 | break; |
793 | } | |
794 | break; | |
795 | ||
796 | case DMV_BDRUNUS: | |
797 | case DMV_BDXSN: | |
798 | case DMV_BDXNS: | |
799 | log(LOG_INFO, | |
bb08cf86 | 800 | "dmv%d: buffer disp for halted trib %o\n", |
ecfa166d MK |
801 | unit, sel2&0x7 |
802 | ); | |
803 | break; | |
804 | ||
805 | case DMV_MDEFO: | |
806 | if((sel6&0x1f) == 020) { | |
807 | log(LOG_INFO, | |
bb08cf86 | 808 | "dmv%d: buffer return complete sel3=%x\n", |
ecfa166d MK |
809 | unit, sel3); |
810 | } else { | |
811 | log(LOG_INFO, | |
bb08cf86 | 812 | "dmv%d: info resp sel3=%x sel4=%x sel6=%x\n", |
ecfa166d MK |
813 | unit, sel3, sel4, sel6 |
814 | ); | |
815 | } | |
816 | break; | |
817 | ||
818 | default: | |
bb08cf86 | 819 | log(LOG_WARNING, "dmv%d: bad control %o\n", |
ecfa166d MK |
820 | unit, sel2&0x7 |
821 | ); | |
822 | break; | |
823 | } | |
824 | } | |
825 | dmvstart(unit); | |
826 | return; | |
bb08cf86 | 827 | restart: |
ecfa166d MK |
828 | dmvrestart(unit); |
829 | } | |
bb08cf86 | 830 | |
ecfa166d MK |
831 | load_rec_bufs(sc) |
832 | register struct dmv_softc *sc; | |
833 | { | |
834 | register struct dmvbufs *rp; | |
835 | ||
836 | /* queue first NRCV buffers for DMV to fill */ | |
837 | for (rp = &sc->sc_rbufs[0]; rp < &sc->sc_rbufs[NRCV]; rp++) { | |
838 | rp->flags |= DBUF_DMVS; | |
839 | dmvload( | |
840 | sc, | |
841 | DMV_BACCR, | |
842 | QP_TRIB|QP_SEL4|QP_SEL6|QP_SEL10, | |
843 | 1, | |
844 | rp->ubinfo, | |
845 | (rp->ubinfo>>16)&0x3f, | |
846 | rp->cc | |
847 | ); | |
848 | sc->sc_iused++; | |
849 | } | |
850 | } | |
851 | ||
852 | /* | |
853 | * DMV output routine. | |
854 | * Encapsulate a packet of type family for the dmv. | |
855 | * Use trailer local net encapsulation if enough data in first | |
856 | * packet leaves a multiple of 512 bytes of data in remainder. | |
857 | */ | |
858 | dmvoutput(ifp, m0, dst) | |
859 | register struct ifnet *ifp; | |
860 | register struct mbuf *m0; | |
861 | struct sockaddr *dst; | |
862 | { | |
863 | int type, error, s; | |
864 | register struct mbuf *m = m0; | |
865 | register struct dmv_header *dh; | |
866 | register int off; | |
867 | ||
bb08cf86 MK |
868 | if ((ifp->if_flags & IFF_UP) == 0) { |
869 | error = ENETDOWN; | |
870 | goto bad; | |
871 | } | |
872 | ||
ecfa166d MK |
873 | switch (dst->sa_family) { |
874 | #ifdef INET | |
875 | case AF_INET: | |
3ba98c3a | 876 | off = ntohs((u_short)mtod(m, struct ip *)->ip_len) - m->m_len; |
ecfa166d MK |
877 | if ((ifp->if_flags & IFF_NOTRAILERS) == 0) |
878 | if (off > 0 && (off & 0x1ff) == 0 && | |
3ba98c3a | 879 | m->m_off >= MMINOFF + 2 * sizeof (u_short)) { |
ecfa166d | 880 | type = DMV_TRAILER + (off>>9); |
3ba98c3a | 881 | m->m_off -= 2 * sizeof (u_short); |
ecfa166d MK |
882 | m->m_len += 2 * sizeof (u_short); |
883 | *mtod(m, u_short *) = htons((u_short)DMV_IPTYPE); | |
884 | *(mtod(m, u_short *) + 1) = htons((u_short)m->m_len); | |
885 | goto gottrailertype; | |
886 | } | |
887 | type = DMV_IPTYPE; | |
888 | off = 0; | |
889 | goto gottype; | |
890 | #endif | |
891 | ||
892 | case AF_UNSPEC: | |
893 | dh = (struct dmv_header *)dst->sa_data; | |
894 | type = dh->dmv_type; | |
895 | goto gottype; | |
896 | ||
897 | default: | |
bb08cf86 MK |
898 | log(LOG_ERR, "dmvoutput, dmv%d can't handle af%d\n", |
899 | ifp->if_unit, dst->sa_family); | |
ecfa166d MK |
900 | error = EAFNOSUPPORT; |
901 | goto bad; | |
902 | } | |
903 | ||
904 | gottrailertype: | |
905 | /* | |
906 | * Packet to be sent as a trailer; move first packet | |
907 | * (control information) to end of chain. | |
908 | */ | |
909 | while (m->m_next) | |
910 | m = m->m_next; | |
911 | m->m_next = m0; | |
912 | m = m0->m_next; | |
913 | m0->m_next = 0; | |
914 | m0 = m; | |
915 | ||
916 | gottype: | |
917 | /* | |
918 | * Add local network header | |
919 | * (there is space for a uba on a vax to step on) | |
920 | */ | |
3ba98c3a MK |
921 | if (m->m_off > MMAXOFF || |
922 | MMINOFF + sizeof(struct dmv_header) > m->m_off) { | |
923 | m = m_get(M_DONTWAIT, MT_HEADER); | |
924 | if (m == 0) { | |
925 | error = ENOBUFS; | |
926 | goto bad; | |
927 | } | |
928 | m->m_next = m0; | |
929 | m->m_off = MMINOFF; | |
930 | m->m_len = sizeof (struct dmv_header); | |
931 | } else { | |
932 | m->m_off -= sizeof (struct dmv_header); | |
933 | m->m_len += sizeof (struct dmv_header); | |
ecfa166d MK |
934 | } |
935 | dh = mtod(m, struct dmv_header *); | |
936 | dh->dmv_type = htons((u_short)type); | |
937 | ||
938 | /* | |
939 | * Queue message on interface, and start output if interface | |
940 | * not yet active. | |
941 | */ | |
942 | s = splimp(); | |
943 | if (IF_QFULL(&ifp->if_snd)) { | |
944 | IF_DROP(&ifp->if_snd); | |
945 | m_freem(m); | |
946 | splx(s); | |
947 | return (ENOBUFS); | |
948 | } | |
949 | IF_ENQUEUE(&ifp->if_snd, m); | |
950 | dmvstart(ifp->if_unit); | |
951 | splx(s); | |
952 | return (0); | |
953 | ||
954 | bad: | |
955 | m_freem(m0); | |
956 | return (error); | |
957 | } | |
958 | ||
959 | ||
960 | /* | |
961 | * Process an ioctl request. | |
962 | */ | |
963 | /* ARGSUSED */ | |
964 | dmvioctl(ifp, cmd, data) | |
965 | register struct ifnet *ifp; | |
966 | int cmd; | |
967 | caddr_t data; | |
968 | { | |
969 | int s = splimp(), error = 0; | |
970 | struct mbuf *m; | |
971 | register struct dmv_softc *sc = &dmv_softc[ifp->if_unit]; | |
972 | ||
973 | switch (cmd) { | |
974 | ||
975 | case SIOCSIFADDR: | |
976 | ifp->if_flags |= IFF_UP; | |
977 | if ((ifp->if_flags & IFF_RUNNING) == 0) | |
978 | dmvinit(ifp->if_unit); | |
979 | break; | |
980 | ||
981 | case SIOCSIFDSTADDR: | |
982 | if ((ifp->if_flags & IFF_RUNNING) == 0) | |
983 | dmvinit(ifp->if_unit); | |
984 | break; | |
985 | ||
986 | case SIOCSIFFLAGS: | |
987 | if ((ifp->if_flags & IFF_UP) == 0 && | |
bb08cf86 MK |
988 | sc->sc_flag & DMV_RUNNING) |
989 | dmvdown(ifp->if_unit); | |
990 | else if (ifp->if_flags & IFF_UP && | |
ecfa166d MK |
991 | (sc->sc_flag & DMV_RUNNING) == 0) |
992 | dmvrestart(ifp->if_unit); | |
993 | break; | |
994 | ||
995 | default: | |
996 | error = EINVAL; | |
997 | } | |
998 | splx(s); | |
999 | return (error); | |
1000 | } | |
1001 | ||
1002 | /* | |
1003 | * Restart after a fatal error. | |
1004 | * Clear device and reinitialize. | |
1005 | */ | |
1006 | dmvrestart(unit) | |
1007 | int unit; | |
1008 | { | |
ecfa166d | 1009 | register struct dmvdevice *addr; |
ecfa166d | 1010 | register int i; |
bb08cf86 MK |
1011 | |
1012 | dmvdown(unit); | |
1013 | ||
1014 | addr = (struct dmvdevice *)(dmvinfo[unit]->ui_addr); | |
ecfa166d | 1015 | /* |
bb08cf86 | 1016 | * Let the DMV finish the MCLR. |
ecfa166d | 1017 | */ |
ecfa166d MK |
1018 | for (i = 100000; i && (addr->bsel1 & DMV_RUN) == 0; i--) |
1019 | ; | |
1020 | if ((addr->bsel1 & DMV_RUN) == 0) { | |
1021 | log(LOG_ERR, "dmvrestart: can't start device\n" ); | |
1022 | return (0); | |
1023 | } | |
1024 | if ((addr->bsel4 != 033) || (addr->bsel6 != 0305)) | |
1025 | { | |
bb08cf86 MK |
1026 | log(LOG_ERR, "dmv%d: device init failed, bsel4=%o, bsel6=%o\n", |
1027 | unit, addr->bsel4, addr->bsel6); | |
ecfa166d MK |
1028 | return (0); |
1029 | } | |
bb08cf86 MK |
1030 | |
1031 | /* restart DMV */ | |
1032 | dmvinit(unit); | |
1033 | dmv_softc[unit].sc_if.if_collisions++; /* why not? */ | |
1034 | } | |
1035 | ||
1036 | /* | |
1037 | * Reset a device and mark down. | |
1038 | * Flush output queue and drop queue limit. | |
1039 | */ | |
1040 | dmvdown(unit) | |
1041 | int unit; | |
1042 | { | |
1043 | struct dmv_softc *sc = &dmv_softc[unit]; | |
1044 | register struct ifxmt *ifxp; | |
1045 | ||
1046 | ((struct dmvdevice *)(dmvinfo[unit]->ui_addr))->bsel1 = DMV_MCLR; | |
1047 | sc->sc_flag &= ~(DMV_RUNNING | DMV_ONLINE); | |
1048 | ||
ecfa166d MK |
1049 | for (ifxp = sc->sc_ifw; ifxp < &sc->sc_ifw[NXMT]; ifxp++) { |
1050 | if (ifxp->ifw_xtofree) { | |
1051 | (void) m_freem(ifxp->ifw_xtofree); | |
1052 | ifxp->ifw_xtofree = 0; | |
1053 | } | |
1054 | } | |
bb08cf86 MK |
1055 | sc->sc_oused = 0; |
1056 | if_qflush(&sc->sc_if.if_snd); | |
1057 | ||
1058 | /* | |
1059 | * Limit packets enqueued until we're back on the air. | |
1060 | */ | |
1061 | sc->sc_if.if_snd.ifq_maxlen = 3; | |
ecfa166d MK |
1062 | } |
1063 | ||
1064 | /* | |
bb08cf86 MK |
1065 | * Watchdog timeout to see that transmitted packets don't |
1066 | * lose interrupts. The device has to be online. | |
ecfa166d | 1067 | */ |
bb08cf86 MK |
1068 | dmvtimeout(unit) |
1069 | int unit; | |
ecfa166d | 1070 | { |
ecfa166d MK |
1071 | register struct dmv_softc *sc; |
1072 | struct dmvdevice *addr; | |
ecfa166d | 1073 | |
bb08cf86 MK |
1074 | sc = &dmv_softc[unit]; |
1075 | if (sc->sc_flag & DMV_ONLINE) { | |
1076 | addr = (struct dmvdevice *)(dmvinfo[unit]->ui_addr); | |
1077 | log(LOG_ERR, "dmv%d: output timeout, bsel0=%b bsel2=%b\n", | |
1078 | unit, addr->bsel0 & 0xff, DMV0BITS, | |
1079 | addr->bsel2 & 0xff, DMV2BITS); | |
1080 | dmvrestart(unit); | |
ecfa166d | 1081 | } |
ecfa166d MK |
1082 | } |
1083 | #endif |