xref: /original-bsd/sys/i386/isa/if_ec.c (revision 3705696b)
1 /*
2  * Copyright (c) 1992, 1993
3  *	The Regents of the University of California.  All rights reserved.
4  *
5  * %sccs.include.redist.c%
6  *
7  *	@(#)if_ec.c	8.1 (Berkeley) 06/11/93
8  */
9 
10 
11 /* WARNING -- THIS DRIVER DOES NOT WORK YET -- It is merely a sketch */
12 
13 #include "ec.h"
14 #if NEC > 0
15 
16 /*
17  * Intel 82586/3com Etherlink II controller.
18  */
19 #include <sys/param.h>
20 #include <sys/systm.h>
21 #include <sys/mbuf.h>
22 #include <sys/buf.h>
23 #include <sys/protosw.h>
24 #include <sys/socket.h>
25 #include <sys/syslog.h>
26 #include <sys/ioctl.h>
27 #include <sys/errno.h>
28 
29 #include <net/if.h>
30 #include <net/netisr.h>
31 #include <net/route.h>
32 
33 #ifdef INET
34 #include <netinet/in.h>
35 #include <netinet/in_systm.h>
36 #include <netinet/in_var.h>
37 #include <netinet/ip.h>
38 #include <netinet/if_ether.h>
39 #endif
40 
41 #ifdef NS
42 #include <netns/ns.h>
43 #include <netns/ns_if.h>
44 #endif
45 
46 #ifdef ISO
47 extern	char all_es_snpa[], all_is_snpa[], all_l1is_snpa[], all_l2is_snpa[];
48 #endif
49 
50 #include <i386/isa/if_ecreg.h>
51 
52 #if NBPFILTER > 0
53 #include <net/bpf.h>
54 #include <net/bpfdesc.h>
55 #endif
56 
57 int	ecdebug = 1;		/* console error messages */
58 
59 int	ecintr(), ecinit(), ecioctl(), ecstart(), ether_output();
60 int	ecattach(), ecprobe(), ecreset(), ecwatchdog();
61 void	ec_idpattern(), ec_reset_all(), ec_getnmdata(), ecread();
62 
63 struct	mbuf *m_devget();
64 extern	struct ifnet loif;
65 struct	ec_82586params ec_82586defaults =
66     { 11, 0xc8, ECMINSIZE, 0x2e, 0, 0x60, 0, 2, 0, 0, 0x40};
67     /* 2e == no source insert */
68 
69 /*
70  * Ethernet software status per interface.
71  *
72  * Each interface is referenced by a network interface structure,
73  * sc_if, which the routing code uses to locate the interface.
74  * This structure contains the output queue for the interface, its address, ...
75  */
76 struct	ec_softc {
77 	struct	arpcom sc_ac;	/* common Ethernet structures */
78 #define	sc_if	sc_ac.ac_if	/* network-visible interface */
79 #define	sc_addr	sc_ac.ac_enaddr	/* hardware Ethernet address */
80 	caddr_t	sc_device;		/* e.g. isa_device */
81 	caddr_t	sc_bpf;			/* for packet filter */
82 	struct	ec_ports *sc_ports;	/* control ports for this unit */
83 	struct	ec_mem *sc_hmem;	/* Host addr for shared memory */
84 	struct	ec_mem *sc_dmem;	/* Device (chip) addr for shared mem */
85 	int	sc_msize;		/* How much memory is mapped? */
86 	int	sc_iflags;		/* copy of sc_if.if_flags for state */
87 	int	sc_rxnum;		/* Last receiver dx we looked at */
88 	int	sc_txnum;		/* Last tranmistter dx we stomped on */
89 	int	sc_txcnt;		/* Number of packets queued for tx*/
90 	int	sc_xint;
91 	/* errors */
92 	int	sc_txbusy;		/* we're confused */
93 	int	sc_uflo;		/* DMA Late */
94 	int	sc_runt;		/* too short */
95 	int	sc_txbad;
96 	int	sc_rxlen;
97 } ec_softc[NEC];
98 
99 #include <i386/isa/isa_device.h>
100 
101 struct	isa_driver ecdriver = {
102 	ecprobe, ecattach, "ec",
103 };
104 
105 
106 #define TIMO 10000 /* used in ec_uprim */
107 
108 ecprobe(id)
109 	register struct	isa_device *id;
110 {
111 	int	unit = id->id_unit, msize = id->id_msize;
112 	struct	ec_ports *reg = (struct ec_ports *)id->id_iobase;
113 	register struct	ec_softc *ec = ec_softc + unit;
114 	u_char	data[6];
115 
116 	ec_reset_all();
117 	bzero((caddr_t)data, sizeof(data));
118 	ec_getnmdata(reg, R_ECID, data);
119 	if (bcmp((caddr_t)data, "*3COM*", sizeof(data)) != 0) {
120 		if (ecdebug) {
121 			printf("ecprobe: ec%d not matched: %s\n",
122 				unit, ether_sprintf(data));
123 		}
124 		return 0;
125 	}
126 	ec_getnmdata(reg, R_ETHER, ec->sc_addr);
127 	ec_getnmdata(reg, R_REV, data);
128 	ec->sc_hmem	= (struct ec_mem *) (id->id_maddr);
129 	ec->sc_dmem	= (struct ec_mem *) (0x10000 - msize);
130 	ec->sc_msize	= msize;
131 	ec->sc_device	= (caddr_t) id;
132 	ec->sc_ports	= reg;
133 	printf("ec%d: hardware address %s, rev info %s\n",
134 		unit, ether_sprintf(ec->sc_addr), ether_sprintf(data));
135 	return 1;
136 }
137 
138 void
139 ec_idpattern()
140 {
141 	int i = 255, n;
142 	register caddr_t p = (caddr_t)0x100;
143 	for (n = 255;  n > 0; n--) {
144 		outb(p, i);
145 		if ((i <<= 1) & 0x100)
146 			i ^= 0xe7;
147 	}
148 }
149 
150 void
151 ec_reset_all()
152 {
153 	register caddr_t p = (caddr_t)0x100;
154 	outb(p, 0);
155 	ec_idpattern();
156 	outb(p, 0);
157 }
158 extern int cpuspeed;
159 #define ECWR(p, e, d)	outb(&(p->e), d)
160 #define ECRD(p, e)	inb(&(p->e))
161 #define SET_CA		ECWR(ec->sc_ports, port_ca, 0)
162 #define UNLATCH_INT	ECWR(ec->sc_ports, port_ic, 0);
163 
164 void
165 ec_getnmdata(p, which, data)
166 register struct ec_ports *p;
167 int which;
168 register u_char *data;
169 {
170 	register int i;
171 
172 	ECWR(p, creg, which);
173 	DELAY(2);
174 	for (i = 0; i < 6; i++) {
175 		DELAY(2);
176 		data[i] = ECRD(p, data[i]);
177 	}
178 }
179 
180 ecreset(unit)
181 	register int unit;
182 {
183 	register struct ec_softc *ec = &ec_softc[unit];
184 	struct ec_ports *p	 = ec->sc_ports;
185 	struct ec_mem	*hmem	 = ec->sc_hmem;
186 	int timo;
187 
188 	ECWR(p, creg, R_LPB);	DELAY(10);
189 	if ((ec->sc_if.if_flags & IFF_RUNNING) == 0)
190 		return 0;
191 	if (ecdebug)
192 		printf("ec%dreset\n", unit);
193 	ec_meminit(ec);
194 	ECWR(p, creg, R_NORST);	DELAY(10);
195 	hmem->iscp.busy = 1;
196 	ECWR(p, port_ca, 0);	DELAY(10);
197 	for (timo = TIMO; hmem->iscp.busy; )
198 		timo--;
199 	if (timo == 0) {
200 		printf("ec(%d)reset: iscp failed\n", unit);
201 		return 0;
202 	}
203 	hmem->scb.command = CU_START;
204 	ECWR(p, port_ca, 0);	DELAY(10);
205 	for (timo = TIMO; (hmem->scb.status & CU_STATE) == CUS_ACTIVE;)
206 		timo--;
207 	if (timo == 0 || (hmem->scb.status & CU_STATE) != CUS_IDLE) {
208 		printf("ec(%d)reset: setup failed\n", unit);
209 		return 0;
210 	}
211 	ECWR(p, port_ic, 0);	DELAY(10);
212 	ECWR(p, creg, R_NORST|R_IEN);
213 	hmem->scb.command = RU_START | (hmem->scb.status & 0xf000);
214 	ECWR(p, port_ca, 0);	DELAY(10);
215 	ec->sc_if.if_timer = 5;
216 	return 0;			/* Keep GCC Happy! */
217 }
218 
219 /*
220  * Interface exists: make available by filling in network interface
221  * record.  System will initialize the interface when it is ready
222  * to accept packets.
223  */
224 
225 ecattach(id)
226 	register struct isa_device *id;
227 {
228 	int	unit = id->id_unit;
229 	struct ec_softc *ec = &ec_softc[unit];
230 	struct ifnet *ifp = &ec->sc_if;
231 
232 	ifp->if_unit = unit;
233 	ifp->if_name = "ec";
234 	ifp->if_mtu = ETHERMTU;
235 	ifp->if_init = ecinit;
236 	ifp->if_init = ecreset;
237 	ifp->if_ioctl = ecioctl;
238 	ifp->if_watchdog = ecwatchdog;
239 	ifp->if_output = ether_output;
240 	ifp->if_start = ecstart;
241 	ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX;
242 #if NBPFILTER > 0
243 	bpfattach(&ec->sc_bpf, ifp, DLT_EN10MB, sizeof(struct ether_header));
244 #endif
245 	if_attach(ifp);
246 	return (1);
247 }
248 #define OFF(e) ((u_short)&(((struct ec_mem *)0)->e))
249 
250 ec_meminit(ec)
251 	register struct ec_softc *ec;
252 {
253 	register struct ec_mem *hmem = ec->sc_hmem;
254 	register int i;
255 	struct ec_rfd *rc = hmem->rcom;
256 	struct ec_transmit *tc = hmem->tcom;
257 	caddr_t cp;
258 
259 	bzero((caddr_t)hmem, ec->sc_msize);
260 	*(struct ec_mem **)
261 		(ec->sc_msize - 4 + (caddr_t)ec->sc_hmem) = ec->sc_dmem;
262 
263 	hmem->iscp.scb_off	= OFF(scb);
264 	hmem->iscp.scb_base	= (caddr_t)ec->sc_dmem;
265 
266 	hmem->scb.rfa_off	= OFF(rcom[0]);
267 	hmem->scb.cbl_off	= OFF(config);
268 
269 	hmem->config.com1	= COM1_CONFIGURE;
270 	bcopy((caddr_t)&ec_82586defaults, (caddr_t)&hmem->config.modes,
271 		sizeof(hmem->config.modes));
272 #if NBPFILTER > 0
273 	if (ec->sc_if.if_flags & IFF_PROMISC)
274 		hmem->config.modes.promisc |= M_PROMISC;
275 #endif
276 	hmem->config.next_off	= OFF(iasetup);
277 
278 	bcopy((caddr_t)ec->sc_addr, (caddr_t)hmem->iasetup.srcaddr, 6);
279 #ifndef ISO
280 	hmem->iasetup.com1	= COM1_IASETUP | COM1_S | COM1_EL;
281 #else
282 	hmem->iasetup.com1	= COM1_IASETUP;
283 	hmem->iasetup.next_off	= OFF(mcsetup);
284 
285 	hmem->mcsetup.com1	= COM1_MCSETUP | COM1_S | COM1_EL;
286 	hmem->mcsetup.count	= 24;
287 	cp = (caddr_t)hmem->txbuf[0];
288 	bcopy((caddr_t)all_es_snpa, cp, 6);	cp += 6;
289 	bcopy((caddr_t)all_is_snpa, cp, 6);	cp += 6;
290 	bcopy((caddr_t)all_l1is_snpa, cp, 6);	cp += 6;
291 	bcopy((caddr_t)all_l2is_snpa, cp, 6);	cp += 6;
292 #endif
293 	for (i = 0; i < NTXBUF; i++) {
294 		tc->tbd_off	= OFF(tcom[i].count);
295 		tc->buffer	= ec->sc_dmem->txbuf[i];
296 		(tc++)->com1	= COM1_TRANSMIT | COM1_S | COM1_EL | COM1_I;
297 	}
298 	for (i = 0; i < NRXBUF; i++) {
299 		rc->next_off	= OFF(rcom[i + 1]);
300 		rc->rbd_off	= OFF(rcom[i].count);
301 		rc->buffer	= ec->sc_dmem->rxbuf[i];
302 		(rc++)->size	= ECMTU | COM1_EL;
303 	}
304 	(--rc)->next_off = OFF(rcom[0]);
305 }
306 /*
307  * Initialization of interface
308  */
309 ecinit(unit)
310 	int unit;
311 {
312 	register struct ifnet *ifp = &ec_softc[unit].sc_if;
313 	register struct ifaddr *ifa;
314 	int s;
315 
316 	/* not yet, if address still unknown */
317 	for (ifa = ifp->if_addrlist;; ifa = ifa->ifa_next)
318 		if (ifa == 0)
319 			return 0;
320 		else if (ifa->ifa_addr && ifa->ifa_addr->sa_family != AF_LINK)
321 			break;
322 	if ((ifp->if_flags & IFF_RUNNING) == 0) {
323 		s = splimp();
324 		ifp->if_flags |= IFF_RUNNING;
325 		ecreset(unit);
326 	        (void) ecstart(ifp);
327 		splx(s);
328 	}
329 	return 0;
330 }
331 
332 /*
333  * Timeout: for now check for a transmit command taking more than 10 seconds.
334  */
335 ecwatchdog(unit)
336 	int unit;
337 {
338 	register struct ec_softc *ec = ec_softc + unit;
339 	if (ec->sc_iflags & IFF_OACTIVE) {
340 		ec->sc_if.if_flags &= ~IFF_RUNNING;
341 		ecinit(unit);
342 	} else if (ec->sc_txcnt > 0)
343 		ec->sc_iflags |= IFF_OACTIVE;
344 	ec->sc_if.if_timer = 5;
345 }
346 
347 
348 
349 ec_txstart(ec)
350 register struct ec_softc *ec;
351 {
352 	struct	ec_mem *hmem = ec->sc_hmem;
353 	int i;
354 
355 	if ((i = ec->sc_txnum - ec->sc_txcnt) < 0) i += NTXBUF;
356 	hmem->scb.cbl_off = OFF(tcom[i]);
357 	hmem->scb.command = CU_START;
358 	hmem->scb.status = 0;
359 	SET_CA;
360 }
361 /*
362  * Start output on interface.  Get another datagram to send
363  * off of the interface queue, and copy it to the interface
364  * before starting the output.
365  */
366 ecstart(ifp)
367 	struct ifnet *ifp;
368 {
369 	register struct ec_softc *ec = &ec_softc[ifp->if_unit];
370 	register struct ec_transmit *tmd;
371 	register struct mbuf *m;
372 	int len;
373 
374 again:
375 	if ((ec->sc_if.if_flags & IFF_RUNNING) == 0 || ec->sc_txcnt >= NTXBUF)
376 		return (0);
377 	tmd = ec->sc_hmem->tcom + ec->sc_txnum;
378 	if (tmd->com0 & (COM0_B | COM0_C))
379 		return (ec->sc_txbusy++, 0);
380 	IF_DEQUEUE(&ec->sc_if.if_snd, m);
381 	if (m == 0)
382 		return (0);
383 	len = ecput(ec->sc_hmem->txbuf[ec->sc_txnum], m);
384 #if NBPFILTER > 0
385 	/*
386 	 * If bpf is listening on this interface, let it
387 	 * see the packet before we commit it to the wire.
388 	 */
389 	if (ec->sc_bpf)
390                 bpf_tap(ec->sc_bpf, ec->sc_hmem->txbuf[ec->sc_txnum], len);
391 #endif
392 	tmd->com0 = 0;
393 	tmd->count = len | COM1_EL;
394 	if (ec->sc_txcnt == 0)
395 		ec_txstart(ec);
396 	if (++ec->sc_txnum >= NTXBUF)
397 		ec->sc_txnum = 0;
398 	if (++ec->sc_txcnt >= NTXBUF) {
399 		ec->sc_txcnt = NTXBUF;
400 		ec->sc_if.if_flags |= IFF_OACTIVE;
401 	}
402 	goto again;
403 }
404 int ECC_intr, ECC_rint, ECC_xint, ECC_unready;
405 
406 ecintr(unit)
407 	register int unit;
408 {
409 	struct ec_softc *ec = &ec_softc[unit];
410 	struct ec_mem *hmem = ec->sc_hmem;
411 	register int stat = hmem->scb.status;
412 
413 	hmem->scb.command = stat & 0xf000; /* Ack interrupt cause */
414 	SET_CA;
415 	if (stat & FR)
416 		ecrint(unit);
417 	if (stat & CX)
418 		ecxint(unit);
419 	ECC_intr++;
420 	if ((stat & RU_STATE) != RUS_READY)
421 		ECC_unready++;
422 	UNLATCH_INT;
423 }
424 
425 /*
426  * Ethernet interface transmitter interrupt.
427  * Start another output if more data to send.
428  */
429 ecxint(unit)
430 	register int unit;
431 {
432 	register struct ec_softc *ec = &ec_softc[unit];
433 	register struct ec_transmit *tmd;
434 	int i;
435 
436 	ECC_rint++;
437 	if (ec->sc_txcnt == 0) {
438 		ec->sc_xint++;	/* unexpected transmit interrupt */
439 		return;
440 	}
441 	ec->sc_iflags &= ~IFF_OACTIVE; /* clear deadman indication */
442 	if ((i = ec->sc_txnum - ec->sc_txcnt) < 0) i += NTXBUF;
443 	tmd = ec->sc_hmem->tcom + i;
444 	if (tmd->com0 & COM0_B)
445 		return;
446 	ec->sc_if.if_collisions += tmd->com0 & 0xf;
447 	if ((tmd->com0 & EXCOL) && (tmd->com0 & 0xf) == 0)
448 		ec->sc_if.if_collisions += 16;
449 	if ((tmd->com0 & COM0_OK) == 0) {
450 		ecxerror(unit);
451 		ec->sc_if.if_oerrors++;
452 		if (tmd->com0 & DMALATE) {
453 			ec->sc_uflo++;
454 			(void) ecreset(unit);
455 			return;
456 		}
457 	} else
458 		ec->sc_if.if_opackets++;
459 	tmd->com0 = 0;
460 	if (--ec->sc_txcnt > 0)
461 		ec_txstart(ec);
462 	if (ec->sc_txcnt < 0) {
463 		ec->sc_txbad++;
464 		ec->sc_txcnt = 0;
465 	}
466 	ec->sc_if.if_flags &= ~IFF_OACTIVE;
467 	(void) ecstart(&ec->sc_if);
468 }
469 
470 #define	ECNEXTRCOM \
471 	if (++bix == NRXBUF) bix = 0, rmd = ec->sc_hmem->rcom; else ++rmd
472 
473 /*
474  * Ethernet interface receiver interrupt.
475  * If input error just drop packet.
476  * Decapsulate packet based on type and pass to type specific
477  * higher-level input routine.
478  */
479 ecrint(unit)
480 	int unit;
481 {
482 	register struct ec_softc *ec = &ec_softc[unit];
483 	register int bix = ec->sc_rxnum;
484 	register struct ec_rfd *rmd = ec->sc_hmem->rcom + bix;
485 
486 	/*
487 	 * Out of sync with hardware, should never happen?
488 	 */
489 	ECC_xint++;
490 	if ((rmd->rfd0 & COM0_C) == 0 || (rmd->count & RBD_F) == 0) {
491 		ecrerror(unit, "out of sync, resetting");
492 		return ecreset(unit);
493 	}
494 	/*
495 	 * Process all buffers with valid data
496 	 */
497 	while ((rmd->rfd0 & COM0_C) && (rmd->count & RBD_F)) {
498 		if (rmd->rfd0 & (COM0_C|COM0_B|COM0_OK) != (COM0_C|COM0_OK)) {
499 			ec->sc_rxnum = bix;
500 			ecrerror(unit, "bad packet");
501 			ec->sc_if.if_ierrors++;
502 		}
503 		if ((rmd->count & (RBD_F|RBD_EOF)) != (RBD_F|RBD_EOF)) {
504 			ecrerror(unit, "chained buffer");
505 			ec->sc_rxlen++;
506 			ec->sc_if.if_ierrors++;
507 		} else
508 			ecread(ec, ec->sc_hmem->txbuf[bix], rmd->count & 0x2f);
509 		rmd->count = 0;
510 		rmd->rfd0 = 0;
511 		ECNEXTRCOM;
512 		ec->sc_rxnum = bix;
513 	}
514 }
515 
516 void
517 ecread(ec, buf, len)
518 	register struct ec_softc *ec;
519 	char *buf;
520 	int len;
521 {
522 	struct ether_header *et, eh;
523     	struct mbuf *m;
524 	int off, resid, unit = ec->sc_if.if_unit;
525 
526 	ec->sc_if.if_ipackets++;
527 	et = (struct ether_header *)buf;
528 	et->ether_type = ntohs((u_short)et->ether_type);
529 	bcopy((caddr_t)et, &eh, sizeof(eh));
530 	/* adjust input length to account for header */
531 	len = len - sizeof(struct ether_header);
532 
533 #define	ecdataaddr(et, off, type)	((type)(((caddr_t)((et)+1)+(off))))
534 	if (et->ether_type >= ETHERTYPE_TRAIL &&
535 	    et->ether_type < ETHERTYPE_TRAIL+ETHERTYPE_NTRAILER) {
536 		off = (et->ether_type - ETHERTYPE_TRAIL) * 512;
537 		if (off >= ETHERMTU)
538 			return;		/* sanity */
539 		et->ether_type = ntohs(*ecdataaddr(et, off, u_short *));
540 		resid = ntohs(*(ecdataaddr(et, off+2, u_short *)));
541 		if (off + resid > len)
542 			return;		/* sanity */
543 		len = off + resid;
544 	} else
545 		off = 0;
546 
547 	if (len <= 0) {
548 		if (ecdebug)
549 			log(LOG_WARNING,
550 			    "ec%d: ierror(runt packet): from %s: len=%d\n",
551 			    unit, ether_sprintf(et->ether_shost), len);
552 		ec->sc_runt++;
553 		ec->sc_if.if_ierrors++;
554 		return;
555 	}
556 #if NBPFILTER > 0
557 	/*
558 	 * Check if there's a bpf filter listening on this interface.
559 	 * If so, hand off the raw packet to bpf, which must deal with
560 	 * trailers in its own way.
561 	 */
562 	if (ec->sc_bpf)
563 		bpf_tap(ec->sc_bpf, buf, len + sizeof(struct ether_header));
564 #endif
565 #if defined(ISO) || NBPFILTER > 0
566 	/*
567 	 * Note that the interface cannot be in promiscuous mode if
568 	 * there are no bpf listeners.  If we are in promiscuous
569 	 * mode, we have to check if this packet is really ours.
570 	 * However, there may be appropriate multicate addresses involved
571 	 */
572 #define NOT_TO(p) (bcmp(et->ether_dhost, p, sizeof(et->ether_dhost)) != 0)
573 	if (et->ether_dhost[0] & 1) {
574 		if (NOT_TO(etherbroadcastaddr)
575 #ifdef ISO
576 		    && NOT_TO(all_es_snpa) && NOT_TO(all_is_snpa)
577 		    && NOT_TO(all_l1is_snpa) && NOT_TO(all_l2is_snpa)
578 #endif
579 		     ) return;
580 	} else if ((ec->sc_if.if_flags & IFF_PROMISC) && NOT_TO(ec->sc_addr))
581 		return;
582 #endif
583 	/*
584 	 * Pull packet off interface.  Off is nonzero if packet
585 	 * has trailing header; m_devget will then force this header
586 	 * information to be at the front, but we still have to drop
587 	 * the type and length which are at the front of any trailer data.
588 	 */
589 	m = m_devget((char *)(et + 1), len, off, &ec->sc_if, 0);
590 	if (m == 0)
591 		return;
592 	ether_input(&ec->sc_if, &eh, m);
593 }
594 
595 /*
596  * Routine to copy from mbuf chain to transmit
597  * buffer in board local memory.
598  */
599 ecput(ecbuf, m)
600 	register char *ecbuf;
601 	register struct mbuf *m;
602 {
603 	register struct mbuf *mp;
604 	register int len, tlen = 0;
605 
606 	for (mp = m; mp; mp = mp->m_next) {
607 		len = mp->m_len;
608 		if (len == 0)
609 			continue;
610 		tlen += len;
611 		bcopy(mtod(mp, char *), ecbuf, len);
612 		ecbuf += len;
613 	}
614 	m_freem(m);
615 	if (tlen < ECMINSIZE) {
616 		bzero(ecbuf, ECMINSIZE - tlen);
617 		tlen = ECMINSIZE;
618 	}
619 	return(tlen);
620 }
621 
622 /*
623  * Process an ioctl request.
624  */
625 ecioctl(ifp, cmd, data)
626 	register struct ifnet *ifp;
627 	int cmd;
628 	caddr_t data;
629 {
630 	register struct ifaddr *ifa = (struct ifaddr *)data;
631 	struct ec_softc *ec = &ec_softc[ifp->if_unit];
632 	int s = splimp(), error = 0;
633 
634 	switch (cmd) {
635 
636 	case SIOCSIFADDR:
637 		ifp->if_flags |= IFF_UP;
638 		switch (ifa->ifa_addr->sa_family) {
639 #ifdef INET
640 		case AF_INET:
641 			ecinit(ifp->if_unit);	/* before arpwhohas */
642 			((struct arpcom *)ifp)->ac_ipaddr =
643 				IA_SIN(ifa)->sin_addr;
644 			arpwhohas((struct arpcom *)ifp, &IA_SIN(ifa)->sin_addr);
645 			break;
646 #endif
647 #ifdef NS
648 		case AF_NS:
649 		    {
650 			register struct ns_addr *ina = &(IA_SNS(ifa)->sns_addr);
651 
652 			if (ns_nullhost(*ina))
653 				ina->x_host = *(union ns_host *)(ec->sc_addr);
654 			else {
655 				ifp->if_flags &= ~IFF_RUNNING;
656 				bcopy((caddr_t)ina->x_host.c_host,
657 				    (caddr_t)ec->sc_addr, sizeof(ec->sc_addr));
658 			}
659 			ecinit(ifp->if_unit);
660 			break;
661 		    }
662 #endif
663 		default:
664 			ecinit(ifp->if_unit);
665 			break;
666 		}
667 		break;
668 
669 	case SIOCSIFFLAGS:
670 		if ((ifp->if_flags & IFF_UP) == 0 &&
671 		    ifp->if_flags & IFF_RUNNING) {
672 			ifp->if_flags &= ~IFF_RUNNING;
673 			ecreset(ifp->if_unit);
674 		} else if (ifp->if_flags & IFF_UP &&
675 		    (ifp->if_flags & IFF_RUNNING) == 0)
676 			ecinit(ifp->if_unit);
677 		/*
678 		 * If the state of the promiscuous bit changes, the interface
679 		 * must be reset to effect the change.
680 		 */
681 		if (((ifp->if_flags ^ ec->sc_iflags) & IFF_PROMISC) &&
682 		    (ifp->if_flags & IFF_RUNNING)) {
683 			ec->sc_iflags = ifp->if_flags & ~IFF_OACTIVE;
684 			ecreset(ifp->if_unit);
685 			ecstart(ifp);
686 		}
687 		break;
688 
689 	default:
690 		error = EINVAL;
691 	}
692 	splx(s);
693 	return (error);
694 }
695 
696 ecrerror(unit, msg)
697 	int unit;
698 	char *msg;
699 {
700 	register struct ec_softc *ec = &ec_softc[unit];
701 	register struct ec_rfd *rmd;
702 	int len;
703 
704 	if (!ecdebug)
705 		return;
706 
707 	rmd = &ec->sc_hmem->rcom[ec->sc_rxnum];
708 	len = rmd->count;
709 	log(LOG_WARNING,
710 	    "ec%d: ierror(%s): from %s: buf=%d, len=%d, rmd1=%b\n",
711 	    unit, msg,
712 	    len > 11 ? ether_sprintf(&ec->sc_hmem->rxbuf[ec->sc_rxnum][6]) : "unknown",
713 	    ec->sc_rxnum, len,
714 	    rmd->rfd0, "\14\14LEN\13CRC\12ALGN\11NBUF\10DMAL\07SHRT");
715 }
716 
717 ecxerror(unit)
718 	int unit;
719 {
720 	register struct ec_softc *ec = &ec_softc[unit];
721 	register struct ec_transmit *tmd;
722 	int len;
723 
724 	if (!ecdebug)
725 		return;
726 
727 	tmd = &ec->sc_hmem->tcom[ec->sc_txnum];
728 	len = tmd->count;
729 	log(LOG_WARNING,
730 	    "ec%d: oerror: to %s: buf=%d, len=%d, com0=%b\n",
731 	    unit,
732 	    len > 5 ? ether_sprintf(ec->sc_hmem->txbuf[ec->sc_txnum]) : "unknown",
733 	    ec->sc_txnum, len,
734 	    tmd->com0,
735 	    "\14\14ABRT\13LCOLL\12NCAR\11NCTS\10DMAL\07TDEF\06HRBT\05XCOL");
736 }
737 #endif
738