BSD 4_3_Reno release
[unix-history] / usr / src / sys / vaxif / if_dmc.c
CommitLineData
da7c5cc6 1/*
2eb4e665 2 * Copyright (c) 1982, 1986 Regents of the University of California.
5f9369d6 3 * All rights reserved.
da7c5cc6 4 *
1c15e888
C
5 * Redistribution is only permitted until one year after the first shipment
6 * of 4.4BSD by the Regents. Otherwise, redistribution and use in source and
7 * binary forms are permitted provided that: (1) source distributions retain
8 * this entire copyright notice and comment, and (2) distributions including
9 * binaries display the following acknowledgement: This product includes
10 * software developed by the University of California, Berkeley and its
11 * contributors'' in the documentation or other materials provided with the
12 * distribution and in all advertising materials mentioning features or use
13 * of this software. Neither the name of the University nor the names of
14 * its contributors may be used to endorse or promote products derived from
15 * this software without specific prior written permission.
16 * THIS SOFTWARE IS PROVIDED AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
17 * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
18 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
5f9369d6 19 *
1c15e888 20 * @(#)if_dmc.c 7.9 (Berkeley) 6/28/90
da7c5cc6 21 */
63665984
BJ
22
23#include "dmc.h"
24#if NDMC > 0
ba0b299a 25
63665984
BJ
26/*
27 * DMC11 device driver, internet version
28 *
ba0b299a 29 * Bill Nesheim
032f82b3 30 * Cornell University
c6020d6c 31 *
ba0b299a
MK
32 * Lou Salkind
33 * New York University
63665984 34 */
ba0b299a
MK
35
36/* #define DEBUG /* for base table dump on fatal error */
37
1c15e888 38#include "machine/pte.h"
63665984 39
a6e960e7
JB
40#include "param.h"
41#include "systm.h"
42#include "mbuf.h"
43#include "buf.h"
032f82b3 44#include "ioctl.h" /* must precede tty.h */
a6e960e7
JB
45#include "tty.h"
46#include "protosw.h"
47#include "socket.h"
1556e171 48#include "syslog.h"
a6e960e7
JB
49#include "vmmac.h"
50#include "errno.h"
1c15e888
C
51#include "time.h"
52#include "kernel.h"
a9687d27
BJ
53
54#include "../net/if.h"
4fce3bf9 55#include "../net/netisr.h"
a9687d27 56#include "../net/route.h"
822a4f2c 57
822a4f2c 58#ifdef INET
d2cc167c
BJ
59#include "../netinet/in.h"
60#include "../netinet/in_systm.h"
58bca61d 61#include "../netinet/in_var.h"
ba0b299a 62#include "../netinet/ip.h"
822a4f2c 63#endif
a9687d27
BJ
64
65#include "../vax/cpu.h"
66#include "../vax/mtpr.h"
a6e960e7
JB
67#include "if_uba.h"
68#include "if_dmc.h"
a9687d27
BJ
69#include "../vaxuba/ubareg.h"
70#include "../vaxuba/ubavar.h"
63665984 71
ba0b299a 72
bb08cf86
MK
73/*
74 * output timeout value, sec.; should depend on line speed.
75 */
76int dmc_timeout = 20;
ba0b299a 77
63665984
BJ
78/*
79 * Driver information for auto-configuration stuff.
80 */
17718098 81int dmcprobe(), dmcattach(), dmcinit(), dmcioctl();
bb08cf86 82int dmcoutput(), dmcreset(), dmctimeout();
63665984
BJ
83struct uba_device *dmcinfo[NDMC];
84u_short dmcstd[] = { 0 };
85struct uba_driver dmcdriver =
86 { dmcprobe, 0, dmcattach, 0, dmcstd, "dmc", dmcinfo };
87
032f82b3 88#define NRCV 7
ba0b299a 89#define NXMT 3
822a4f2c 90#define NCMDS (NRCV+NXMT+4) /* size of command queue */
ba0b299a
MK
91
92#define printd if(dmcdebug)printf
93int dmcdebug = 0;
032f82b3
TF
94
95/* error reporting intervals */
96#define DMC_RPNBFS 50
97#define DMC_RPDSC 1
ba0b299a
MK
98#define DMC_RPTMO 10
99#define DMC_RPDCK 10
032f82b3
TF
100
101struct dmc_command {
102 char qp_cmd; /* command */
103 short qp_ubaddr; /* buffer address */
104 short qp_cc; /* character count || XMEM */
105 struct dmc_command *qp_next; /* next command on queue */
106};
107
032f82b3
TF
108struct dmcbufs {
109 int ubinfo; /* from uballoc */
110 short cc; /* buffer size */
111 short flags; /* access control */
112};
113#define DBUF_OURS 0 /* buffer is available */
114#define DBUF_DMCS 1 /* buffer claimed by somebody */
115#define DBUF_XMIT 4 /* transmit buffer */
ba0b299a 116#define DBUF_RCV 8 /* receive buffer */
032f82b3 117
032f82b3 118
63665984
BJ
119/*
120 * DMC software status per interface.
121 *
122 * Each interface is referenced by a network interface structure,
123 * sc_if, which the routing code uses to locate the interface.
124 * This structure contains the output queue for the interface, its address, ...
032f82b3
TF
125 * We also have, for each interface, a set of 7 UBA interface structures
126 * for each, which
127 * contain information about the UNIBUS resources held by the interface:
63665984
BJ
128 * map registers, buffered data paths, etc. Information is cached in this
129 * structure for use by the if_uba.c routines in running the interface
130 * efficiently.
131 */
132struct dmc_softc {
032f82b3 133 struct ifnet sc_if; /* network-visible interface */
adfd8bff
MK
134 short sc_oused; /* output buffers currently in use */
135 short sc_iused; /* input buffers given to DMC */
136 short sc_flag; /* flags */
63665984 137 int sc_ubinfo; /* UBA mapping info for base table */
032f82b3
TF
138 int sc_errors[4]; /* non-fatal error counters */
139#define sc_datck sc_errors[0]
140#define sc_timeo sc_errors[1]
141#define sc_nobuf sc_errors[2]
142#define sc_disc sc_errors[3]
bb08cf86
MK
143 struct dmcbufs sc_rbufs[NRCV]; /* receive buffer info */
144 struct dmcbufs sc_xbufs[NXMT]; /* transmit buffer info */
145 struct ifubinfo sc_ifuba; /* UNIBUS resources */
146 struct ifrw sc_ifr[NRCV]; /* UNIBUS receive buffer maps */
147 struct ifxmt sc_ifw[NXMT]; /* UNIBUS receive buffer maps */
032f82b3 148 /* command queue stuff */
ba0b299a 149 struct dmc_command sc_cmdbuf[NCMDS];
032f82b3
TF
150 struct dmc_command *sc_qhead; /* head of command queue */
151 struct dmc_command *sc_qtail; /* tail of command queue */
152 struct dmc_command *sc_qactive; /* command in progress */
153 struct dmc_command *sc_qfreeh; /* head of list of free cmd buffers */
154 struct dmc_command *sc_qfreet; /* tail of list of free cmd buffers */
155 /* end command queue stuff */
63665984
BJ
156} dmc_softc[NDMC];
157
158/* flags */
bb08cf86 159#define DMC_RUNNING 0x01 /* device initialized */
56bfc7be
MK
160#define DMC_BMAPPED 0x02 /* base table mapped */
161#define DMC_RESTART 0x04 /* software restart in progress */
bb08cf86 162#define DMC_ONLINE 0x08 /* device running (had a RDYO) */
63665984 163
ba0b299a
MK
164struct dmc_base {
165 short d_base[128]; /* DMC base table */
63665984
BJ
166} dmc_base[NDMC];
167
032f82b3
TF
168/* queue manipulation macros */
169#define QUEUE_AT_HEAD(qp, head, tail) \
170 (qp)->qp_next = (head); \
171 (head) = (qp); \
172 if ((tail) == (struct dmc_command *) 0) \
173 (tail) = (head)
174
175#define QUEUE_AT_TAIL(qp, head, tail) \
176 if ((tail)) \
177 (tail)->qp_next = (qp); \
178 else \
179 (head) = (qp); \
180 (qp)->qp_next = (struct dmc_command *) 0; \
181 (tail) = (qp)
182
183#define DEQUEUE(head, tail) \
184 (head) = (head)->qp_next;\
185 if ((head) == (struct dmc_command *) 0)\
186 (tail) = (head)
63665984
BJ
187
188dmcprobe(reg)
189 caddr_t reg;
190{
191 register int br, cvec;
192 register struct dmcdevice *addr = (struct dmcdevice *)reg;
193 register int i;
194
195#ifdef lint
196 br = 0; cvec = br; br = cvec;
197 dmcrint(0); dmcxint(0);
198#endif
199 addr->bsel1 = DMC_MCLR;
200 for (i = 100000; i && (addr->bsel1 & DMC_RUN) == 0; i--)
201 ;
ba0b299a
MK
202 if ((addr->bsel1 & DMC_RUN) == 0) {
203 printf("dmcprobe: can't start device\n" );
ee787340 204 return (0);
ba0b299a 205 }
63665984 206 addr->bsel0 = DMC_RQI|DMC_IEI;
ba0b299a
MK
207 /* let's be paranoid */
208 addr->bsel0 |= DMC_RQI|DMC_IEI;
209 DELAY(1000000);
63665984
BJ
210 addr->bsel1 = DMC_MCLR;
211 for (i = 100000; i && (addr->bsel1 & DMC_RUN) == 0; i--)
212 ;
ee787340 213 return (1);
63665984
BJ
214}
215
216/*
217 * Interface exists: make available by filling in network interface
218 * record. System will initialize the interface when it is ready
219 * to accept packets.
220 */
221dmcattach(ui)
222 register struct uba_device *ui;
223{
224 register struct dmc_softc *sc = &dmc_softc[ui->ui_unit];
225
226 sc->sc_if.if_unit = ui->ui_unit;
227 sc->sc_if.if_name = "dmc";
228 sc->sc_if.if_mtu = DMCMTU;
63665984
BJ
229 sc->sc_if.if_init = dmcinit;
230 sc->sc_if.if_output = dmcoutput;
17718098 231 sc->sc_if.if_ioctl = dmcioctl;
51595ca2 232 sc->sc_if.if_reset = dmcreset;
bb08cf86 233 sc->sc_if.if_watchdog = dmctimeout;
032f82b3 234 sc->sc_if.if_flags = IFF_POINTOPOINT;
822a4f2c 235 sc->sc_ifuba.iff_flags = UBA_CANTWAIT;
032f82b3 236
822a4f2c 237 if_attach(&sc->sc_if);
63665984
BJ
238}
239
240/*
241 * Reset of interface after UNIBUS reset.
7f0e1e06 242 * If interface is on specified UBA, reset its state.
63665984
BJ
243 */
244dmcreset(unit, uban)
245 int unit, uban;
246{
247 register struct uba_device *ui;
032f82b3 248 register struct dmc_softc *sc = &dmc_softc[unit];
63665984
BJ
249
250 if (unit >= NDMC || (ui = dmcinfo[unit]) == 0 || ui->ui_alive == 0 ||
251 ui->ui_ubanum != uban)
252 return;
253 printf(" dmc%d", unit);
ba0b299a 254 sc->sc_flag = 0;
7f0e1e06 255 sc->sc_if.if_flags &= ~IFF_RUNNING;
63665984
BJ
256 dmcinit(unit);
257}
258
259/*
260 * Initialization of interface; reinitialize UNIBUS usage.
261 */
262dmcinit(unit)
263 int unit;
264{
265 register struct dmc_softc *sc = &dmc_softc[unit];
266 register struct uba_device *ui = dmcinfo[unit];
267 register struct dmcdevice *addr;
17718098 268 register struct ifnet *ifp = &sc->sc_if;
032f82b3
TF
269 register struct ifrw *ifrw;
270 register struct ifxmt *ifxp;
271 register struct dmcbufs *rp;
ba0b299a 272 register struct dmc_command *qp;
7f0e1e06 273 struct ifaddr *ifa;
63665984 274 int base;
ba0b299a 275 int s;
63665984 276
032f82b3
TF
277 addr = (struct dmcdevice *)ui->ui_addr;
278
7f0e1e06
MK
279 /*
280 * Check to see that an address has been set
281 * (both local and destination for an address family).
282 */
283 for (ifa = ifp->if_addrlist; ifa; ifa = ifa->ifa_next)
583ff5c5 284 if (ifa->ifa_addr->sa_family && ifa->ifa_dstaddr->sa_family)
7f0e1e06
MK
285 break;
286 if (ifa == (struct ifaddr *) 0)
032f82b3
TF
287 return;
288
289 if ((addr->bsel1&DMC_RUN) == 0) {
290 printf("dmcinit: DMC not running\n");
7f0e1e06 291 ifp->if_flags &= ~IFF_UP;
032f82b3
TF
292 return;
293 }
294 /* map base table */
ba0b299a 295 if ((sc->sc_flag & DMC_BMAPPED) == 0) {
032f82b3
TF
296 sc->sc_ubinfo = uballoc(ui->ui_ubanum,
297 (caddr_t)&dmc_base[unit], sizeof (struct dmc_base), 0);
298 sc->sc_flag |= DMC_BMAPPED;
299 }
300 /* initialize UNIBUS resources */
301 sc->sc_iused = sc->sc_oused = 0;
7f0e1e06 302 if ((ifp->if_flags & IFF_RUNNING) == 0) {
822a4f2c
MK
303 if (if_ubaminit(&sc->sc_ifuba, ui->ui_ubanum,
304 sizeof(struct dmc_header), (int)btoc(DMCMTU),
305 sc->sc_ifr, NRCV, sc->sc_ifw, NXMT) == 0) {
7f0e1e06 306 printf("dmc%d: can't allocate uba resources\n", unit);
17718098
SL
307 ifp->if_flags &= ~IFF_UP;
308 return;
309 }
7f0e1e06 310 ifp->if_flags |= IFF_RUNNING;
032f82b3 311 }
bb08cf86 312 sc->sc_flag &= ~DMC_ONLINE;
56bfc7be 313 sc->sc_flag |= DMC_RUNNING;
bb08cf86
MK
314 /*
315 * Limit packets enqueued until we see if we're on the air.
316 */
317 ifp->if_snd.ifq_maxlen = 3;
032f82b3
TF
318
319 /* initialize buffer pool */
ba0b299a 320 /* receives */
822a4f2c 321 ifrw = &sc->sc_ifr[0];
032f82b3 322 for (rp = &sc->sc_rbufs[0]; rp < &sc->sc_rbufs[NRCV]; rp++) {
3ba98c3a 323 rp->ubinfo = UBAI_ADDR(ifrw->ifrw_info);
ba0b299a 324 rp->cc = DMCMTU + sizeof (struct dmc_header);
032f82b3 325 rp->flags = DBUF_OURS|DBUF_RCV;
032f82b3 326 ifrw++;
63665984 327 }
032f82b3 328 /* transmits */
822a4f2c 329 ifxp = &sc->sc_ifw[0];
032f82b3 330 for (rp = &sc->sc_xbufs[0]; rp < &sc->sc_xbufs[NXMT]; rp++) {
3ba98c3a 331 rp->ubinfo = UBAI_ADDR(ifxp->ifw_info);
032f82b3
TF
332 rp->cc = 0;
333 rp->flags = DBUF_OURS|DBUF_XMIT;
032f82b3 334 ifxp++;
f6311fb6 335 }
ba0b299a
MK
336
337 /* set up command queues */
338 sc->sc_qfreeh = sc->sc_qfreet
339 = sc->sc_qhead = sc->sc_qtail = sc->sc_qactive =
340 (struct dmc_command *)0;
341 /* set up free command buffer list */
342 for (qp = &sc->sc_cmdbuf[0]; qp < &sc->sc_cmdbuf[NCMDS]; qp++) {
343 QUEUE_AT_HEAD(qp, sc->sc_qfreeh, sc->sc_qfreet);
344 }
345
032f82b3 346 /* base in */
3ba98c3a
MK
347 base = UBAI_ADDR(sc->sc_ubinfo);
348 dmcload(sc, DMC_BASEI, (u_short)base, (base>>2) & DMC_XMEM);
032f82b3
TF
349 /* specify half duplex operation, flags tell if primary */
350 /* or secondary station */
351 if (ui->ui_flags == 0)
56bfc7be 352 /* use DDCMP mode in full duplex */
ba0b299a 353 dmcload(sc, DMC_CNTLI, 0, 0);
032f82b3 354 else if (ui->ui_flags == 1)
ba0b299a
MK
355 /* use MAINTENENCE mode */
356 dmcload(sc, DMC_CNTLI, 0, DMC_MAINT );
032f82b3
TF
357 else if (ui->ui_flags == 2)
358 /* use DDCMP half duplex as primary station */
359 dmcload(sc, DMC_CNTLI, 0, DMC_HDPLX);
360 else if (ui->ui_flags == 3)
361 /* use DDCMP half duplex as secondary station */
362 dmcload(sc, DMC_CNTLI, 0, DMC_HDPLX | DMC_SEC);
ba0b299a
MK
363
364 /* enable operation done interrupts */
ba0b299a
MK
365 while ((addr->bsel2 & DMC_IEO) == 0)
366 addr->bsel2 |= DMC_IEO;
367 s = spl5();
032f82b3
TF
368 /* queue first NRCV buffers for DMC to fill */
369 for (rp = &sc->sc_rbufs[0]; rp < &sc->sc_rbufs[NRCV]; rp++) {
370 rp->flags |= DBUF_DMCS;
371 dmcload(sc, DMC_READ, rp->ubinfo,
ba0b299a 372 (((rp->ubinfo>>2)&DMC_XMEM) | rp->cc));
032f82b3
TF
373 sc->sc_iused++;
374 }
ba0b299a 375 splx(s);
63665984
BJ
376}
377
378/*
379 * Start output on interface. Get another datagram
380 * to send from the interface queue and map it to
381 * the interface before starting output.
032f82b3
TF
382 *
383 * Must be called at spl 5
63665984 384 */
bb08cf86
MK
385dmcstart(unit)
386 int unit;
63665984 387{
63665984 388 register struct dmc_softc *sc = &dmc_softc[unit];
63665984 389 struct mbuf *m;
032f82b3
TF
390 register struct dmcbufs *rp;
391 register int n;
63665984 392
63665984 393 /*
032f82b3
TF
394 * Dequeue up to NXMT requests and map them to the UNIBUS.
395 * If no more requests, or no dmc buffers available, just return.
63665984 396 */
032f82b3
TF
397 n = 0;
398 for (rp = &sc->sc_xbufs[0]; rp < &sc->sc_xbufs[NXMT]; rp++ ) {
399 /* find an available buffer */
ba0b299a 400 if ((rp->flags & DBUF_DMCS) == 0) {
032f82b3
TF
401 IF_DEQUEUE(&sc->sc_if.if_snd, m);
402 if (m == 0)
403 return;
032f82b3
TF
404 /* mark it dmcs */
405 rp->flags |= (DBUF_DMCS);
406 /*
407 * Have request mapped to UNIBUS for transmission
408 * and start the output.
409 */
822a4f2c 410 rp->cc = if_ubaput(&sc->sc_ifuba, &sc->sc_ifw[n], m);
ba0b299a 411 rp->cc &= DMC_CCOUNT;
bb08cf86
MK
412 if (++sc->sc_oused == 1)
413 sc->sc_if.if_timer = dmc_timeout;
032f82b3
TF
414 dmcload(sc, DMC_WRITE, rp->ubinfo,
415 rp->cc | ((rp->ubinfo>>2)&DMC_XMEM));
416 }
417 n++;
418 }
63665984
BJ
419}
420
421/*
422 * Utility routine to load the DMC device registers.
423 */
424dmcload(sc, type, w0, w1)
425 register struct dmc_softc *sc;
3ba98c3a
MK
426 int type;
427 u_short w0, w1;
63665984
BJ
428{
429 register struct dmcdevice *addr;
032f82b3
TF
430 register int unit, sps;
431 register struct dmc_command *qp;
63665984 432
ba0b299a 433 unit = sc - dmc_softc;
63665984
BJ
434 addr = (struct dmcdevice *)dmcinfo[unit]->ui_addr;
435 sps = spl5();
032f82b3
TF
436
437 /* grab a command buffer from the free list */
438 if ((qp = sc->sc_qfreeh) == (struct dmc_command *)0)
439 panic("dmc command queue overflow");
440 DEQUEUE(sc->sc_qfreeh, sc->sc_qfreet);
441
442 /* fill in requested info */
443 qp->qp_cmd = (type | DMC_RQI);
444 qp->qp_ubaddr = w0;
445 qp->qp_cc = w1;
446
447 if (sc->sc_qactive) { /* command in progress */
448 if (type == DMC_READ) {
449 QUEUE_AT_HEAD(qp, sc->sc_qhead, sc->sc_qtail);
450 } else {
451 QUEUE_AT_TAIL(qp, sc->sc_qhead, sc->sc_qtail);
452 }
453 } else { /* command port free */
454 sc->sc_qactive = qp;
455 addr->bsel0 = qp->qp_cmd;
63665984 456 dmcrint(unit);
032f82b3 457 }
63665984
BJ
458 splx(sps);
459}
460
461/*
462 * DMC interface receiver interrupt.
463 * Ready to accept another command,
464 * pull one off the command queue.
465 */
466dmcrint(unit)
467 int unit;
468{
469 register struct dmc_softc *sc;
470 register struct dmcdevice *addr;
032f82b3 471 register struct dmc_command *qp;
63665984 472 register int n;
63665984
BJ
473
474 addr = (struct dmcdevice *)dmcinfo[unit]->ui_addr;
475 sc = &dmc_softc[unit];
032f82b3 476 if ((qp = sc->sc_qactive) == (struct dmc_command *) 0) {
ba0b299a 477 printf("dmc%d: dmcrint no command\n", unit);
032f82b3
TF
478 return;
479 }
63665984 480 while (addr->bsel0&DMC_RDYI) {
032f82b3
TF
481 addr->sel4 = qp->qp_ubaddr;
482 addr->sel6 = qp->qp_cc;
63665984 483 addr->bsel0 &= ~(DMC_IEI|DMC_RQI);
032f82b3
TF
484 /* free command buffer */
485 QUEUE_AT_HEAD(qp, sc->sc_qfreeh, sc->sc_qfreet);
486 while (addr->bsel0 & DMC_RDYI) {
487 /*
488 * Can't check for RDYO here 'cause
489 * this routine isn't reentrant!
490 */
491 DELAY(5);
492 }
493 /* move on to next command */
ba0b299a
MK
494 if ((sc->sc_qactive = sc->sc_qhead) == (struct dmc_command *)0)
495 break; /* all done */
032f82b3
TF
496 /* more commands to do, start the next one */
497 qp = sc->sc_qactive;
498 DEQUEUE(sc->sc_qhead, sc->sc_qtail);
499 addr->bsel0 = qp->qp_cmd;
63665984 500 n = RDYSCAN;
ba0b299a
MK
501 while (n-- > 0)
502 if ((addr->bsel0&DMC_RDYI) || (addr->bsel2&DMC_RDYO))
503 break;
032f82b3
TF
504 }
505 if (sc->sc_qactive) {
506 addr->bsel0 |= DMC_IEI|DMC_RQI;
507 /* VMS does it twice !*$%@# */
508 addr->bsel0 |= DMC_IEI|DMC_RQI;
63665984 509 }
ba0b299a 510
63665984
BJ
511}
512
513/*
514 * DMC interface transmitter interrupt.
032f82b3 515 * A transfer may have completed, check for errors.
63665984
BJ
516 * If it was a read, notify appropriate protocol.
517 * If it was a write, pull the next one off the queue.
518 */
519dmcxint(unit)
520 int unit;
521{
522 register struct dmc_softc *sc;
abcd48c6 523 register struct ifnet *ifp;
63665984
BJ
524 struct uba_device *ui = dmcinfo[unit];
525 struct dmcdevice *addr;
526 struct mbuf *m;
ba0b299a 527 struct ifqueue *inq;
56bfc7be 528 int arg, pkaddr, cmd, len, s;
032f82b3
TF
529 register struct ifrw *ifrw;
530 register struct dmcbufs *rp;
ba0b299a
MK
531 register struct ifxmt *ifxp;
532 struct dmc_header *dh;
533 int off, resid;
63665984
BJ
534
535 addr = (struct dmcdevice *)ui->ui_addr;
63665984 536 sc = &dmc_softc[unit];
abcd48c6 537 ifp = &sc->sc_if;
032f82b3 538
ba0b299a
MK
539 while (addr->bsel2 & DMC_RDYO) {
540
541 cmd = addr->bsel2 & 0xff;
542 arg = addr->sel6 & 0xffff;
543 /* reconstruct UNIBUS address of buffer returned to us */
544 pkaddr = ((arg&DMC_XMEM)<<2) | (addr->sel4 & 0xffff);
545 /* release port */
546 addr->bsel2 &= ~DMC_RDYO;
547 switch (cmd & 07) {
548
549 case DMC_OUR:
550 /*
551 * A read has completed.
552 * Pass packet to type specific
553 * higher-level input routine.
554 */
555 ifp->if_ipackets++;
556 /* find location in dmcuba struct */
822a4f2c 557 ifrw= &sc->sc_ifr[0];
ba0b299a
MK
558 for (rp = &sc->sc_rbufs[0]; rp < &sc->sc_rbufs[NRCV]; rp++) {
559 if(rp->ubinfo == pkaddr)
560 break;
561 ifrw++;
562 }
563 if (rp >= &sc->sc_rbufs[NRCV])
564 panic("dmc rcv");
565 if ((rp->flags & DBUF_DMCS) == 0)
566 printf("dmc%d: done unalloc rbuf\n", unit);
567
568 len = (arg & DMC_CCOUNT) - sizeof (struct dmc_header);
569 if (len < 0 || len > DMCMTU) {
570 ifp->if_ierrors++;
571 printd("dmc%d: bad rcv pkt addr 0x%x len 0x%x\n",
572 unit, pkaddr, len);
573 goto setup;
574 }
575 /*
576 * Deal with trailer protocol: if type is trailer
577 * get true type from first 16-bit word past data.
578 * Remember that type was trailer by setting off.
579 */
580 dh = (struct dmc_header *)ifrw->ifrw_addr;
581 dh->dmc_type = ntohs((u_short)dh->dmc_type);
582#define dmcdataaddr(dh, off, type) ((type)(((caddr_t)((dh)+1)+(off))))
583 if (dh->dmc_type >= DMC_TRAILER &&
584 dh->dmc_type < DMC_TRAILER+DMC_NTRAILER) {
585 off = (dh->dmc_type - DMC_TRAILER) * 512;
586 if (off >= DMCMTU)
587 goto setup; /* sanity */
588 dh->dmc_type = ntohs(*dmcdataaddr(dh, off, u_short *));
589 resid = ntohs(*(dmcdataaddr(dh, off+2, u_short *)));
590 if (off + resid > len)
591 goto setup; /* sanity */
592 len = off + resid;
593 } else
594 off = 0;
595 if (len == 0)
596 goto setup;
597
598 /*
599 * Pull packet off interface. Off is nonzero if
600 * packet has trailing header; dmc_get will then
601 * force this header information to be at the front,
602 * but we still have to drop the type and length
603 * which are at the front of any trailer data.
604 */
822a4f2c 605 m = if_ubaget(&sc->sc_ifuba, ifrw, len, off, ifp);
ba0b299a
MK
606 if (m == 0)
607 goto setup;
ba0b299a 608 switch (dh->dmc_type) {
63665984 609
63665984 610#ifdef INET
ba0b299a
MK
611 case DMC_IPTYPE:
612 schednetisr(NETISR_IP);
613 inq = &ipintrq;
614 break;
63665984 615#endif
ba0b299a
MK
616 default:
617 m_freem(m);
618 goto setup;
619 }
63665984 620
56bfc7be 621 s = splimp();
ba0b299a
MK
622 if (IF_QFULL(inq)) {
623 IF_DROP(inq);
624 m_freem(m);
625 } else
626 IF_ENQUEUE(inq, m);
56bfc7be 627 splx(s);
032f82b3 628
ba0b299a
MK
629 setup:
630 /* is this needed? */
3ba98c3a 631 rp->ubinfo = UBAI_ADDR(ifrw->ifrw_info);
63665984 632
ba0b299a
MK
633 dmcload(sc, DMC_READ, rp->ubinfo,
634 ((rp->ubinfo >> 2) & DMC_XMEM) | rp->cc);
635 break;
63665984 636
ba0b299a
MK
637 case DMC_OUX:
638 /*
639 * A write has completed, start another
640 * transfer if there is more data to send.
641 */
642 ifp->if_opackets++;
643 /* find associated dmcbuf structure */
822a4f2c 644 ifxp = &sc->sc_ifw[0];
ba0b299a
MK
645 for (rp = &sc->sc_xbufs[0]; rp < &sc->sc_xbufs[NXMT]; rp++) {
646 if(rp->ubinfo == pkaddr)
647 break;
648 ifxp++;
649 }
650 if (rp >= &sc->sc_xbufs[NXMT]) {
651 printf("dmc%d: bad packet address 0x%x\n",
652 unit, pkaddr);
653 break;
654 }
655 if ((rp->flags & DBUF_DMCS) == 0)
656 printf("dmc%d: unallocated packet 0x%x\n",
657 unit, pkaddr);
658 /* mark buffer free */
822a4f2c
MK
659 if (ifxp->ifw_xtofree) {
660 (void)m_freem(ifxp->ifw_xtofree);
661 ifxp->ifw_xtofree = 0;
ba0b299a
MK
662 }
663 rp->flags &= ~DBUF_DMCS;
bb08cf86
MK
664 if (--sc->sc_oused == 0)
665 sc->sc_if.if_timer = 0;
666 else
667 sc->sc_if.if_timer = dmc_timeout;
668 if ((sc->sc_flag & DMC_ONLINE) == 0) {
669 extern int ifqmaxlen;
670
671 /*
672 * We're on the air.
673 * Open the queue to the usual value.
674 */
675 sc->sc_flag |= DMC_ONLINE;
676 ifp->if_snd.ifq_maxlen = ifqmaxlen;
677 }
032f82b3 678 break;
ba0b299a
MK
679
680 case DMC_CNTLO:
681 arg &= DMC_CNTMASK;
682 if (arg & DMC_FATAL) {
bb08cf86
MK
683 if (arg != DMC_START)
684 log(LOG_ERR,
685 "dmc%d: fatal error, flags=%b\n",
686 unit, arg, CNTLO_BITS);
ba0b299a
MK
687 dmcrestart(unit);
688 break;
689 }
690 /* ACCUMULATE STATISTICS */
032f82b3
TF
691 switch(arg) {
692 case DMC_NOBUFS:
ba0b299a
MK
693 ifp->if_ierrors++;
694 if ((sc->sc_nobuf++ % DMC_RPNBFS) == 0)
695 goto report;
696 break;
032f82b3 697 case DMC_DISCONN:
ba0b299a
MK
698 if ((sc->sc_disc++ % DMC_RPDSC) == 0)
699 goto report;
700 break;
032f82b3 701 case DMC_TIMEOUT:
ba0b299a
MK
702 if ((sc->sc_timeo++ % DMC_RPTMO) == 0)
703 goto report;
704 break;
032f82b3 705 case DMC_DATACK:
ba0b299a
MK
706 ifp->if_oerrors++;
707 if ((sc->sc_datck++ % DMC_RPDCK) == 0)
708 goto report;
709 break;
032f82b3
TF
710 default:
711 goto report;
712 }
713 break;
714 report:
ba0b299a
MK
715 printd("dmc%d: soft error, flags=%b\n", unit,
716 arg, CNTLO_BITS);
717 if ((sc->sc_flag & DMC_RESTART) == 0) {
718 /*
719 * kill off the dmc to get things
720 * going again by generating a
721 * procedure error
722 */
723 sc->sc_flag |= DMC_RESTART;
3ba98c3a 724 arg = UBAI_ADDR(sc->sc_ubinfo);
ba0b299a
MK
725 dmcload(sc, DMC_BASEI, arg, (arg>>2)&DMC_XMEM);
726 }
727 break;
63665984 728
ba0b299a
MK
729 default:
730 printf("dmc%d: bad control %o\n", unit, cmd);
731 break;
732 }
63665984 733 }
ba0b299a 734 dmcstart(unit);
032f82b3 735 return;
63665984
BJ
736}
737
738/*
739 * DMC output routine.
ba0b299a
MK
740 * Encapsulate a packet of type family for the dmc.
741 * Use trailer local net encapsulation if enough data in first
742 * packet leaves a multiple of 512 bytes of data in remainder.
63665984 743 */
ba0b299a 744dmcoutput(ifp, m0, dst)
63665984 745 register struct ifnet *ifp;
ba0b299a 746 register struct mbuf *m0;
ee787340 747 struct sockaddr *dst;
63665984 748{
ba0b299a
MK
749 int type, error, s;
750 register struct mbuf *m = m0;
751 register struct dmc_header *dh;
752 register int off;
753
bb08cf86
MK
754 if ((ifp->if_flags & IFF_UP) == 0) {
755 error = ENETDOWN;
756 goto bad;
757 }
758
ba0b299a
MK
759 switch (dst->sa_family) {
760#ifdef INET
761 case AF_INET:
583ff5c5 762 off = m->m_pkthdr.len - m->m_len;
ba0b299a
MK
763 if ((ifp->if_flags & IFF_NOTRAILERS) == 0)
764 if (off > 0 && (off & 0x1ff) == 0 &&
583ff5c5
MK
765 (m->m_flags & M_EXT) == 0 &&
766 m->m_data >= m->m_pktdat + 2 * sizeof (u_short)) {
ba0b299a 767 type = DMC_TRAILER + (off>>9);
583ff5c5 768 m->m_data -= 2 * sizeof (u_short);
ba0b299a
MK
769 m->m_len += 2 * sizeof (u_short);
770 *mtod(m, u_short *) = htons((u_short)DMC_IPTYPE);
771 *(mtod(m, u_short *) + 1) = htons((u_short)m->m_len);
772 goto gottrailertype;
773 }
774 type = DMC_IPTYPE;
775 off = 0;
776 goto gottype;
777#endif
63665984 778
ba0b299a
MK
779 case AF_UNSPEC:
780 dh = (struct dmc_header *)dst->sa_data;
781 type = dh->dmc_type;
782 goto gottype;
783
784 default:
785 printf("dmc%d: can't handle af%d\n", ifp->if_unit,
786 dst->sa_family);
787 error = EAFNOSUPPORT;
788 goto bad;
63665984 789 }
ba0b299a
MK
790
791gottrailertype:
792 /*
793 * Packet to be sent as a trailer; move first packet
794 * (control information) to end of chain.
795 */
796 while (m->m_next)
797 m = m->m_next;
798 m->m_next = m0;
799 m = m0->m_next;
800 m0->m_next = 0;
801 m0 = m;
802
803gottype:
804 /*
805 * Add local network header
806 * (there is space for a uba on a vax to step on)
807 */
583ff5c5
MK
808 M_PREPEND(m, sizeof(struct dmc_header), M_DONTWAIT);
809 if (m == 0) {
810 error = ENOBUFS;
811 goto bad;
ba0b299a
MK
812 }
813 dh = mtod(m, struct dmc_header *);
814 dh->dmc_type = htons((u_short)type);
815
816 /*
817 * Queue message on interface, and start output if interface
818 * not yet active.
819 */
820 s = splimp();
1e977657
BJ
821 if (IF_QFULL(&ifp->if_snd)) {
822 IF_DROP(&ifp->if_snd);
ee787340 823 m_freem(m);
1e977657 824 splx(s);
8a2f82db 825 return (ENOBUFS);
1e977657 826 }
63665984 827 IF_ENQUEUE(&ifp->if_snd, m);
032f82b3 828 dmcstart(ifp->if_unit);
63665984 829 splx(s);
8a2f82db 830 return (0);
ba0b299a
MK
831
832bad:
833 m_freem(m0);
834 return (error);
63665984 835}
17718098 836
ba0b299a 837
17718098
SL
838/*
839 * Process an ioctl request.
840 */
822a4f2c 841/* ARGSUSED */
17718098
SL
842dmcioctl(ifp, cmd, data)
843 register struct ifnet *ifp;
844 int cmd;
845 caddr_t data;
846{
17718098 847 int s = splimp(), error = 0;
56bfc7be 848 register struct dmc_softc *sc = &dmc_softc[ifp->if_unit];
17718098
SL
849
850 switch (cmd) {
851
852 case SIOCSIFADDR:
032f82b3 853 ifp->if_flags |= IFF_UP;
7f0e1e06
MK
854 if ((ifp->if_flags & IFF_RUNNING) == 0)
855 dmcinit(ifp->if_unit);
17718098
SL
856 break;
857
858 case SIOCSIFDSTADDR:
7f0e1e06
MK
859 if ((ifp->if_flags & IFF_RUNNING) == 0)
860 dmcinit(ifp->if_unit);
17718098 861 break;
032f82b3 862
56bfc7be
MK
863 case SIOCSIFFLAGS:
864 if ((ifp->if_flags & IFF_UP) == 0 &&
bb08cf86
MK
865 sc->sc_flag & DMC_RUNNING)
866 dmcdown(ifp->if_unit);
867 else if (ifp->if_flags & IFF_UP &&
56bfc7be
MK
868 (sc->sc_flag & DMC_RUNNING) == 0)
869 dmcrestart(ifp->if_unit);
870 break;
871
17718098
SL
872 default:
873 error = EINVAL;
874 }
875 splx(s);
876 return (error);
877}
032f82b3 878
ba0b299a
MK
879/*
880 * Restart after a fatal error.
881 * Clear device and reinitialize.
882 */
883dmcrestart(unit)
884 int unit;
885{
886 register struct dmc_softc *sc = &dmc_softc[unit];
ba0b299a 887 register struct dmcdevice *addr;
ba0b299a 888 register int i;
bb08cf86 889 int s;
ba0b299a 890
ba0b299a
MK
891#ifdef DEBUG
892 /* dump base table */
893 printf("dmc%d base table:\n", unit);
894 for (i = 0; i < sizeof (struct dmc_base); i++)
895 printf("%o\n" ,dmc_base[unit].d_base[i]);
896#endif
bb08cf86
MK
897
898 dmcdown(unit);
899
ba0b299a
MK
900 /*
901 * Let the DMR finish the MCLR. At 1 Mbit, it should do so
902 * in about a max of 6.4 milliseconds with diagnostics enabled.
903 */
bb08cf86 904 addr = (struct dmcdevice *)(dmcinfo[unit]->ui_addr);
ba0b299a
MK
905 for (i = 100000; i && (addr->bsel1 & DMC_RUN) == 0; i--)
906 ;
907 /* Did the timer expire or did the DMR finish? */
908 if ((addr->bsel1 & DMC_RUN) == 0) {
1556e171 909 log(LOG_ERR, "dmc%d: M820 Test Failed\n", unit);
ba0b299a
MK
910 return;
911 }
912
bb08cf86
MK
913 /* restart DMC */
914 dmcinit(unit);
915 sc->sc_flag &= ~DMC_RESTART;
916 s = spl5();
917 dmcstart(unit);
918 splx(s);
919 sc->sc_if.if_collisions++; /* why not? */
920}
921
922/*
923 * Reset a device and mark down.
924 * Flush output queue and drop queue limit.
925 */
926dmcdown(unit)
927 int unit;
928{
929 register struct dmc_softc *sc = &dmc_softc[unit];
930 register struct ifxmt *ifxp;
931
932 ((struct dmcdevice *)(dmcinfo[unit]->ui_addr))->bsel1 = DMC_MCLR;
933 sc->sc_flag &= ~(DMC_RUNNING | DMC_ONLINE);
934
822a4f2c
MK
935 for (ifxp = sc->sc_ifw; ifxp < &sc->sc_ifw[NXMT]; ifxp++) {
936 if (ifxp->ifw_xtofree) {
937 (void) m_freem(ifxp->ifw_xtofree);
938 ifxp->ifw_xtofree = 0;
ba0b299a
MK
939 }
940 }
bb08cf86 941 if_qflush(&sc->sc_if.if_snd);
ba0b299a
MK
942}
943
944/*
bb08cf86
MK
945 * Watchdog timeout to see that transmitted packets don't
946 * lose interrupts. The device has to be online (the first
947 * transmission may block until the other side comes up).
ba0b299a 948 */
bb08cf86
MK
949dmctimeout(unit)
950 int unit;
ba0b299a 951{
ba0b299a
MK
952 register struct dmc_softc *sc;
953 struct dmcdevice *addr;
ba0b299a 954
bb08cf86
MK
955 sc = &dmc_softc[unit];
956 if (sc->sc_flag & DMC_ONLINE) {
957 addr = (struct dmcdevice *)(dmcinfo[unit]->ui_addr);
958 log(LOG_ERR, "dmc%d: output timeout, bsel0=%b bsel2=%b\n",
959 unit, addr->bsel0 & 0xff, DMC0BITS,
960 addr->bsel2 & 0xff, DMC2BITS);
961 dmcrestart(unit);
ba0b299a 962 }
ba0b299a 963}
44eb2da3 964#endif