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