xref: /netbsd/sys/dev/isa/if_el.c (revision bf9ec67e)
1 /*	$NetBSD: if_el.c,v 1.66 2002/01/07 21:47:07 thorpej Exp $	*/
2 
3 /*
4  * Copyright (c) 1994, Matthew E. Kimmel.  Permission is hereby granted
5  * to use, copy, modify and distribute this software provided that both
6  * the copyright notice and this permission notice appear in all copies
7  * of the software, derivative works or modified versions, and any
8  * portions thereof.
9  */
10 
11 /*
12  * 3COM Etherlink 3C501 device driver
13  */
14 
15 /*
16  * Bugs/possible improvements:
17  *	- Does not currently support DMA
18  *	- Does not currently support multicasts
19  */
20 
21 #include <sys/cdefs.h>
22 __KERNEL_RCSID(0, "$NetBSD: if_el.c,v 1.66 2002/01/07 21:47:07 thorpej Exp $");
23 
24 #include "opt_inet.h"
25 #include "opt_ns.h"
26 #include "bpfilter.h"
27 #include "rnd.h"
28 
29 #include <sys/param.h>
30 #include <sys/systm.h>
31 #include <sys/errno.h>
32 #include <sys/ioctl.h>
33 #include <sys/mbuf.h>
34 #include <sys/socket.h>
35 #include <sys/syslog.h>
36 #include <sys/device.h>
37 #if NRND > 0
38 #include <sys/rnd.h>
39 #endif
40 
41 #include <net/if.h>
42 #include <net/if_dl.h>
43 #include <net/if_types.h>
44 
45 #include <net/if_ether.h>
46 
47 #ifdef INET
48 #include <netinet/in.h>
49 #include <netinet/in_systm.h>
50 #include <netinet/in_var.h>
51 #include <netinet/ip.h>
52 #include <netinet/if_inarp.h>
53 #endif
54 
55 #ifdef NS
56 #include <netns/ns.h>
57 #include <netns/ns_if.h>
58 #endif
59 
60 #if NBPFILTER > 0
61 #include <net/bpf.h>
62 #include <net/bpfdesc.h>
63 #endif
64 
65 #include <machine/cpu.h>
66 #include <machine/intr.h>
67 #include <machine/bus.h>
68 
69 #include <dev/isa/isavar.h>
70 #include <dev/isa/if_elreg.h>
71 
72 /* for debugging convenience */
73 #ifdef EL_DEBUG
74 #define DPRINTF(x) printf x
75 #else
76 #define DPRINTF(x)
77 #endif
78 
79 /*
80  * per-line info and status
81  */
82 struct el_softc {
83 	struct device sc_dev;
84 	void *sc_ih;
85 
86 	struct ethercom sc_ethercom;	/* ethernet common */
87 	bus_space_tag_t sc_iot;		/* bus space identifier */
88 	bus_space_handle_t sc_ioh;	/* i/o handle */
89 
90 #if NRND > 0
91 	rndsource_element_t rnd_source;
92 #endif
93 };
94 
95 /*
96  * prototypes
97  */
98 int elintr __P((void *));
99 void elinit __P((struct el_softc *));
100 int elioctl __P((struct ifnet *, u_long, caddr_t));
101 void elstart __P((struct ifnet *));
102 void elwatchdog __P((struct ifnet *));
103 void elreset __P((struct el_softc *));
104 void elstop __P((struct el_softc *));
105 static int el_xmit __P((struct el_softc *));
106 void elread __P((struct el_softc *, int));
107 struct mbuf *elget __P((struct el_softc *sc, int));
108 static inline void el_hardreset __P((struct el_softc *));
109 
110 int elprobe __P((struct device *, struct cfdata *, void *));
111 void elattach __P((struct device *, struct device *, void *));
112 
113 struct cfattach el_ca = {
114 	sizeof(struct el_softc), elprobe, elattach
115 };
116 
117 /*
118  * Probe routine.
119  *
120  * See if the card is there and at the right place.
121  * (XXX - cgd -- needs help)
122  */
123 int
124 elprobe(parent, match, aux)
125 	struct device *parent;
126 	struct cfdata *match;
127 	void *aux;
128 {
129 	struct isa_attach_args *ia = aux;
130 	bus_space_tag_t iot = ia->ia_iot;
131 	bus_space_handle_t ioh;
132 	int iobase;
133 	u_int8_t station_addr[ETHER_ADDR_LEN];
134 	u_int8_t i;
135 	int rval;
136 
137 	rval = 0;
138 
139 	if (ia->ia_nio < 1)
140 		return (0);
141 	if (ia->ia_nirq < 1)
142 		return (0);
143 
144 	if (ISA_DIRECT_CONFIG(ia))
145 		return (0);
146 
147 	iobase = ia->ia_io[0].ir_addr;
148 
149 	if (ia->ia_io[0].ir_addr == ISACF_PORT_DEFAULT)
150 		return (0);
151 	if (ia->ia_irq[0].ir_irq == ISACF_IRQ_DEFAULT)
152 		return (0);
153 
154 	/* First check the base. */
155 	if (iobase < 0x200 || iobase > 0x3f0)
156 		return 0;
157 
158 	/* Map i/o space. */
159 	if (bus_space_map(iot, iobase, 16, 0, &ioh))
160 		return 0;
161 
162 	/*
163 	 * Now attempt to grab the station address from the PROM and see if it
164 	 * contains the 3com vendor code.
165 	 */
166 	DPRINTF(("Probing 3c501 at 0x%x...\n", iobase));
167 
168 	/* Reset the board. */
169 	DPRINTF(("Resetting board...\n"));
170 	bus_space_write_1(iot, ioh, EL_AC, EL_AC_RESET);
171 	delay(5);
172 	bus_space_write_1(iot, ioh, EL_AC, 0);
173 
174 	/* Now read the address. */
175 	DPRINTF(("Reading station address...\n"));
176 	for (i = 0; i < ETHER_ADDR_LEN; i++) {
177 		bus_space_write_1(iot, ioh, EL_GPBL, i);
178 		station_addr[i] = bus_space_read_1(iot, ioh, EL_EAW);
179 	}
180 	DPRINTF(("Address is %s\n", ether_sprintf(station_addr)));
181 
182 	/*
183 	 * If the vendor code is ok, return a 1.  We'll assume that whoever
184 	 * configured this system is right about the IRQ.
185 	 */
186 	if (station_addr[0] != 0x02 || station_addr[1] != 0x60 ||
187 	    station_addr[2] != 0x8c) {
188 		DPRINTF(("Bad vendor code.\n"));
189 		goto out;
190 	}
191 	DPRINTF(("Vendor code ok.\n"));
192 
193 	ia->ia_nio = 1;
194 	ia->ia_io[0].ir_size = 16;
195 
196 	ia->ia_nirq = 1;
197 
198 	ia->ia_niomem = 0;
199 	ia->ia_ndrq = 0;
200 
201 	rval = 1;
202 
203  out:
204 	bus_space_unmap(iot, ioh, 16);
205 	return rval;
206 }
207 
208 /*
209  * Attach the interface to the kernel data structures.  By the time this is
210  * called, we know that the card exists at the given I/O address.  We still
211  * assume that the IRQ given is correct.
212  */
213 void
214 elattach(parent, self, aux)
215 	struct device *parent, *self;
216 	void *aux;
217 {
218 	struct el_softc *sc = (void *)self;
219 	struct isa_attach_args *ia = aux;
220 	bus_space_tag_t iot = ia->ia_iot;
221 	bus_space_handle_t ioh;
222 	struct ifnet *ifp = &sc->sc_ethercom.ec_if;
223 	u_int8_t myaddr[ETHER_ADDR_LEN];
224 	u_int8_t i;
225 
226 	printf("\n");
227 
228 	DPRINTF(("Attaching %s...\n", sc->sc_dev.dv_xname));
229 
230 	/* Map i/o space. */
231 	if (bus_space_map(iot, ia->ia_io[0].ir_addr, 16, 0, &ioh)) {
232 		printf("%s: can't map i/o space\n", self->dv_xname);
233 		return;
234 	}
235 
236 	sc->sc_iot = iot;
237 	sc->sc_ioh = ioh;
238 
239 	/* Reset the board. */
240 	bus_space_write_1(iot, ioh, EL_AC, EL_AC_RESET);
241 	delay(5);
242 	bus_space_write_1(iot, ioh, EL_AC, 0);
243 
244 	/* Now read the address. */
245 	for (i = 0; i < ETHER_ADDR_LEN; i++) {
246 		bus_space_write_1(iot, ioh, EL_GPBL, i);
247 		myaddr[i] = bus_space_read_1(iot, ioh, EL_EAW);
248 	}
249 
250 	/* Stop the board. */
251 	elstop(sc);
252 
253 	/* Initialize ifnet structure. */
254 	strcpy(ifp->if_xname, sc->sc_dev.dv_xname);
255 	ifp->if_softc = sc;
256 	ifp->if_start = elstart;
257 	ifp->if_ioctl = elioctl;
258 	ifp->if_watchdog = elwatchdog;
259 	ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_NOTRAILERS;
260 	IFQ_SET_READY(&ifp->if_snd);
261 
262 	/* Now we can attach the interface. */
263 	DPRINTF(("Attaching interface...\n"));
264 	if_attach(ifp);
265 	ether_ifattach(ifp, myaddr);
266 
267 	/* Print out some information for the user. */
268 	printf("%s: address %s\n", self->dv_xname, ether_sprintf(myaddr));
269 
270 	sc->sc_ih = isa_intr_establish(ia->ia_ic, ia->ia_irq[0].ir_irq,
271 	    IST_EDGE, IPL_NET, elintr, sc);
272 
273 #if NRND > 0
274 	DPRINTF(("Attaching to random...\n"));
275 	rnd_attach_source(&sc->rnd_source, sc->sc_dev.dv_xname,
276 			  RND_TYPE_NET, 0);
277 #endif
278 
279 	DPRINTF(("elattach() finished.\n"));
280 }
281 
282 /*
283  * Reset interface.
284  */
285 void
286 elreset(sc)
287 	struct el_softc *sc;
288 {
289 	int s;
290 
291 	DPRINTF(("elreset()\n"));
292 	s = splnet();
293 	elstop(sc);
294 	elinit(sc);
295 	splx(s);
296 }
297 
298 /*
299  * Stop interface.
300  */
301 void
302 elstop(sc)
303 	struct el_softc *sc;
304 {
305 
306 	bus_space_write_1(sc->sc_iot, sc->sc_ioh, EL_AC, 0);
307 }
308 
309 /*
310  * Do a hardware reset of the board, and upload the ethernet address again in
311  * case the board forgets.
312  */
313 static inline void
314 el_hardreset(sc)
315 	struct el_softc *sc;
316 {
317 	bus_space_tag_t iot = sc->sc_iot;
318 	bus_space_handle_t ioh = sc->sc_ioh;
319 	int i;
320 
321 	bus_space_write_1(iot, ioh, EL_AC, EL_AC_RESET);
322 	delay(5);
323 	bus_space_write_1(iot, ioh, EL_AC, 0);
324 
325 	for (i = 0; i < ETHER_ADDR_LEN; i++)
326 		bus_space_write_1(iot, ioh, i,
327 		    LLADDR(sc->sc_ethercom.ec_if.if_sadl)[i]);
328 }
329 
330 /*
331  * Initialize interface.
332  */
333 void
334 elinit(sc)
335 	struct el_softc *sc;
336 {
337 	struct ifnet *ifp = &sc->sc_ethercom.ec_if;
338 	bus_space_tag_t iot = sc->sc_iot;
339 	bus_space_handle_t ioh = sc->sc_ioh;
340 
341 	/* First, reset the board. */
342 	el_hardreset(sc);
343 
344 	/* Configure rx. */
345 	DPRINTF(("Configuring rx...\n"));
346 	if (ifp->if_flags & IFF_PROMISC)
347 		bus_space_write_1(iot, ioh, EL_RXC,
348 		    EL_RXC_AGF | EL_RXC_DSHORT | EL_RXC_DDRIB |
349 		    EL_RXC_DOFLOW | EL_RXC_PROMISC);
350 	else
351 		bus_space_write_1(iot, ioh, EL_RXC,
352 		    EL_RXC_AGF | EL_RXC_DSHORT | EL_RXC_DDRIB |
353 		    EL_RXC_DOFLOW | EL_RXC_ABROAD);
354 	bus_space_write_1(iot, ioh, EL_RBC, 0);
355 
356 	/* Configure TX. */
357 	DPRINTF(("Configuring tx...\n"));
358 	bus_space_write_1(iot, ioh, EL_TXC, 0);
359 
360 	/* Start reception. */
361 	DPRINTF(("Starting reception...\n"));
362 	bus_space_write_1(iot, ioh, EL_AC, EL_AC_IRQE | EL_AC_RX);
363 
364 	/* Set flags appropriately. */
365 	ifp->if_flags |= IFF_RUNNING;
366 	ifp->if_flags &= ~IFF_OACTIVE;
367 
368 	/* And start output. */
369 	elstart(ifp);
370 }
371 
372 /*
373  * Start output on interface.  Get datagrams from the queue and output them,
374  * giving the receiver a chance between datagrams.  Call only from splnet or
375  * interrupt level!
376  */
377 void
378 elstart(ifp)
379 	struct ifnet *ifp;
380 {
381 	struct el_softc *sc = ifp->if_softc;
382 	bus_space_tag_t iot = sc->sc_iot;
383 	bus_space_handle_t ioh = sc->sc_ioh;
384 	struct mbuf *m, *m0;
385 	int s, i, off, retries;
386 
387 	DPRINTF(("elstart()...\n"));
388 	s = splnet();
389 
390 	/* Don't do anything if output is active. */
391 	if ((ifp->if_flags & IFF_OACTIVE) != 0) {
392 		splx(s);
393 		return;
394 	}
395 
396 	ifp->if_flags |= IFF_OACTIVE;
397 
398 	/*
399 	 * The main loop.  They warned me against endless loops, but would I
400 	 * listen?  NOOO....
401 	 */
402 	for (;;) {
403 		/* Dequeue the next datagram. */
404 		IFQ_DEQUEUE(&ifp->if_snd, m0);
405 
406 		/* If there's nothing to send, return. */
407 		if (m0 == 0)
408 			break;
409 
410 #if NBPFILTER > 0
411 		/* Give the packet to the bpf, if any. */
412 		if (ifp->if_bpf)
413 			bpf_mtap(ifp->if_bpf, m0);
414 #endif
415 
416 		/* Disable the receiver. */
417 		bus_space_write_1(iot, ioh, EL_AC, EL_AC_HOST);
418 		bus_space_write_1(iot, ioh, EL_RBC, 0);
419 
420 		/* Transfer datagram to board. */
421 		DPRINTF(("el: xfr pkt length=%d...\n", m0->m_pkthdr.len));
422 		off = EL_BUFSIZ - max(m0->m_pkthdr.len,
423 		    ETHER_MIN_LEN - ETHER_CRC_LEN);
424 #ifdef DIAGNOSTIC
425 		if ((off & 0xffff) != off)
426 			printf("%s: bogus off 0x%x\n",
427 			    sc->sc_dev.dv_xname, off);
428 #endif
429 		bus_space_write_1(iot, ioh, EL_GPBL, off & 0xff);
430 		bus_space_write_1(iot, ioh, EL_GPBH, (off >> 8) & 0xff);
431 
432 		/* Copy the datagram to the buffer. */
433 		for (m = m0; m != 0; m = m->m_next)
434 			bus_space_write_multi_1(iot, ioh, EL_BUF,
435 			    mtod(m, u_int8_t *), m->m_len);
436 
437 		m_freem(m0);
438 
439 		/* Now transmit the datagram. */
440 		retries = 0;
441 		for (;;) {
442 			bus_space_write_1(iot, ioh, EL_GPBL, off & 0xff);
443 			bus_space_write_1(iot, ioh, EL_GPBH, (off >> 8) & 0xff);
444 			if (el_xmit(sc)) {
445 				ifp->if_oerrors++;
446 				break;
447 			}
448 			/* Check out status. */
449 			i = bus_space_read_1(iot, ioh, EL_TXS);
450 			DPRINTF(("tx status=0x%x\n", i));
451 			if ((i & EL_TXS_READY) == 0) {
452 				DPRINTF(("el: err txs=%x\n", i));
453 				if (i & (EL_TXS_COLL | EL_TXS_COLL16)) {
454 					ifp->if_collisions++;
455 					if ((i & EL_TXC_DCOLL16) == 0 &&
456 					    retries < 15) {
457 						retries++;
458 						bus_space_write_1(iot, ioh,
459 						    EL_AC, EL_AC_HOST);
460 					}
461 				} else {
462 					ifp->if_oerrors++;
463 					break;
464 				}
465 			} else {
466 				ifp->if_opackets++;
467 				break;
468 			}
469 		}
470 
471 		/*
472 		 * Now give the card a chance to receive.
473 		 * Gotta love 3c501s...
474 		 */
475 		(void)bus_space_read_1(iot, ioh, EL_AS);
476 		bus_space_write_1(iot, ioh, EL_AC, EL_AC_IRQE | EL_AC_RX);
477 		splx(s);
478 		/* Interrupt here. */
479 		s = splnet();
480 	}
481 
482 	(void)bus_space_read_1(iot, ioh, EL_AS);
483 	bus_space_write_1(iot, ioh, EL_AC, EL_AC_IRQE | EL_AC_RX);
484 	ifp->if_flags &= ~IFF_OACTIVE;
485 	splx(s);
486 }
487 
488 /*
489  * This function actually attempts to transmit a datagram downloaded to the
490  * board.  Call at splnet or interrupt, after downloading data!  Returns 0 on
491  * success, non-0 on failure.
492  */
493 static int
494 el_xmit(sc)
495 	struct el_softc *sc;
496 {
497 	bus_space_tag_t iot = sc->sc_iot;
498 	bus_space_handle_t ioh = sc->sc_ioh;
499 	int i;
500 
501 	/*
502 	 * XXX
503 	 * This busy-waits for the tx completion.  Can we get an interrupt
504 	 * instead?
505 	 */
506 
507 	DPRINTF(("el: xmit..."));
508 	bus_space_write_1(iot, ioh, EL_AC, EL_AC_TXFRX);
509 	i = 20000;
510 	while ((bus_space_read_1(iot, ioh, EL_AS) & EL_AS_TXBUSY) && (i > 0))
511 		i--;
512 	if (i == 0) {
513 		DPRINTF(("tx not ready\n"));
514 		return -1;
515 	}
516 	DPRINTF(("%d cycles.\n", 20000 - i));
517 	return 0;
518 }
519 
520 /*
521  * Controller interrupt.
522  */
523 int
524 elintr(arg)
525 	void *arg;
526 {
527 	struct el_softc *sc = arg;
528 	bus_space_tag_t iot = sc->sc_iot;
529 	bus_space_handle_t ioh = sc->sc_ioh;
530 	u_int8_t rxstat;
531 	int len;
532 
533 	DPRINTF(("elintr: "));
534 
535 	/* Check board status. */
536 	if ((bus_space_read_1(iot, ioh, EL_AS) & EL_AS_RXBUSY) != 0) {
537 		(void)bus_space_read_1(iot, ioh, EL_RXC);
538 		bus_space_write_1(iot, ioh, EL_AC, EL_AC_IRQE | EL_AC_RX);
539 		return 0;
540 	}
541 
542 	for (;;) {
543 		rxstat = bus_space_read_1(iot, ioh, EL_RXS);
544 		if (rxstat & EL_RXS_STALE)
545 			break;
546 
547 		/* If there's an overflow, reinit the board. */
548 		if ((rxstat & EL_RXS_NOFLOW) == 0) {
549 			DPRINTF(("overflow.\n"));
550 			el_hardreset(sc);
551 			/* Put board back into receive mode. */
552 			if (sc->sc_ethercom.ec_if.if_flags & IFF_PROMISC)
553 				bus_space_write_1(iot, ioh, EL_RXC,
554 				    EL_RXC_AGF | EL_RXC_DSHORT | EL_RXC_DDRIB |
555 				    EL_RXC_DOFLOW | EL_RXC_PROMISC);
556 			else
557 				bus_space_write_1(iot, ioh, EL_RXC,
558 				    EL_RXC_AGF | EL_RXC_DSHORT | EL_RXC_DDRIB |
559 				    EL_RXC_DOFLOW | EL_RXC_ABROAD);
560 			(void)bus_space_read_1(iot, ioh, EL_AS);
561 			bus_space_write_1(iot, ioh, EL_RBC, 0);
562 			break;
563 		}
564 
565 		/* Incoming packet. */
566 		len = bus_space_read_1(iot, ioh, EL_RBL);
567 		len |= bus_space_read_1(iot, ioh, EL_RBH) << 8;
568 		DPRINTF(("receive len=%d rxstat=%x ", len, rxstat));
569 		bus_space_write_1(iot, ioh, EL_AC, EL_AC_HOST);
570 
571 		/* Pass data up to upper levels. */
572 		elread(sc, len);
573 
574 		/* Is there another packet? */
575 		if ((bus_space_read_1(iot, ioh, EL_AS) & EL_AS_RXBUSY) != 0)
576 			break;
577 
578 #if NRND > 0
579 		rnd_add_uint32(&sc->rnd_source, rxstat);
580 #endif
581 
582 		DPRINTF(("<rescan> "));
583 	}
584 
585 	(void)bus_space_read_1(iot, ioh, EL_RXC);
586 	bus_space_write_1(iot, ioh, EL_AC, EL_AC_IRQE | EL_AC_RX);
587 	return 1;
588 }
589 
590 /*
591  * Pass a packet to the higher levels.
592  */
593 void
594 elread(sc, len)
595 	struct el_softc *sc;
596 	int len;
597 {
598 	struct ifnet *ifp = &sc->sc_ethercom.ec_if;
599 	struct mbuf *m;
600 
601 	if (len <= sizeof(struct ether_header) ||
602 	    len > ETHER_MAX_LEN) {
603 		printf("%s: invalid packet size %d; dropping\n",
604 		    sc->sc_dev.dv_xname, len);
605 		ifp->if_ierrors++;
606 		return;
607 	}
608 
609 	/* Pull packet off interface. */
610 	m = elget(sc, len);
611 	if (m == 0) {
612 		ifp->if_ierrors++;
613 		return;
614 	}
615 
616 	ifp->if_ipackets++;
617 
618 #if NBPFILTER > 0
619 	/*
620 	 * Check if there's a BPF listener on this interface.
621 	 * If so, hand off the raw packet to BPF.
622 	 */
623 	if (ifp->if_bpf)
624 		bpf_mtap(ifp->if_bpf, m);
625 #endif
626 
627 	(*ifp->if_input)(ifp, m);
628 }
629 
630 /*
631  * Pull read data off a interface.  Len is length of data, with local net
632  * header stripped.  We copy the data into mbufs.  When full cluster sized
633  * units are present we copy into clusters.
634  */
635 struct mbuf *
636 elget(sc, totlen)
637 	struct el_softc *sc;
638 	int totlen;
639 {
640 	struct ifnet *ifp = &sc->sc_ethercom.ec_if;
641 	bus_space_tag_t iot = sc->sc_iot;
642 	bus_space_handle_t ioh = sc->sc_ioh;
643 	struct mbuf *m, *m0, *newm;
644 	int len;
645 
646 	MGETHDR(m0, M_DONTWAIT, MT_DATA);
647 	if (m0 == 0)
648 		return (0);
649 	m0->m_pkthdr.rcvif = ifp;
650 	m0->m_pkthdr.len = totlen;
651 	len = MHLEN;
652 	m = m0;
653 
654 	bus_space_write_1(iot, ioh, EL_GPBL, 0);
655 	bus_space_write_1(iot, ioh, EL_GPBH, 0);
656 
657 	while (totlen > 0) {
658 		if (totlen >= MINCLSIZE) {
659 			MCLGET(m, M_DONTWAIT);
660 			if ((m->m_flags & M_EXT) == 0)
661 				goto bad;
662 			len = MCLBYTES;
663 		}
664 
665 		m->m_len = len = min(totlen, len);
666 		bus_space_read_multi_1(iot, ioh, EL_BUF, mtod(m, u_int8_t *), len);
667 
668 		totlen -= len;
669 		if (totlen > 0) {
670 			MGET(newm, M_DONTWAIT, MT_DATA);
671 			if (newm == 0)
672 				goto bad;
673 			len = MLEN;
674 			m = m->m_next = newm;
675 		}
676 	}
677 
678 	bus_space_write_1(iot, ioh, EL_RBC, 0);
679 	bus_space_write_1(iot, ioh, EL_AC, EL_AC_RX);
680 
681 	return (m0);
682 
683 bad:
684 	m_freem(m0);
685 	return (0);
686 }
687 
688 /*
689  * Process an ioctl request. This code needs some work - it looks pretty ugly.
690  */
691 int
692 elioctl(ifp, cmd, data)
693 	struct ifnet *ifp;
694 	u_long cmd;
695 	caddr_t data;
696 {
697 	struct el_softc *sc = ifp->if_softc;
698 	struct ifaddr *ifa = (struct ifaddr *)data;
699 	int s, error = 0;
700 
701 	s = splnet();
702 
703 	switch (cmd) {
704 
705 	case SIOCSIFADDR:
706 		ifp->if_flags |= IFF_UP;
707 
708 		switch (ifa->ifa_addr->sa_family) {
709 #ifdef INET
710 		case AF_INET:
711 			elinit(sc);
712 			arp_ifinit(ifp, ifa);
713 			break;
714 #endif
715 #ifdef NS
716 		/* XXX - This code is probably wrong. */
717 		case AF_NS:
718 		    {
719 			struct ns_addr *ina = &IA_SNS(ifa)->sns_addr;
720 
721 			if (ns_nullhost(*ina))
722 				ina->x_host =
723 				    *(union ns_host *)LLADDR(ifp->if_sadl);
724 			else
725 				memcpy(LLADDR(ifp->if_sadl), ina->x_host.c_host,
726 				    ETHER_ADDR_LEN);
727 			/* Set new address. */
728 			elinit(sc);
729 			break;
730 		    }
731 #endif
732 		default:
733 			elinit(sc);
734 			break;
735 		}
736 		break;
737 
738 	case SIOCSIFFLAGS:
739 		if ((ifp->if_flags & IFF_UP) == 0 &&
740 		    (ifp->if_flags & IFF_RUNNING) != 0) {
741 			/*
742 			 * If interface is marked down and it is running, then
743 			 * stop it.
744 			 */
745 			elstop(sc);
746 			ifp->if_flags &= ~IFF_RUNNING;
747 		} else if ((ifp->if_flags & IFF_UP) != 0 &&
748 		    	   (ifp->if_flags & IFF_RUNNING) == 0) {
749 			/*
750 			 * If interface is marked up and it is stopped, then
751 			 * start it.
752 			 */
753 			elinit(sc);
754 		} else {
755 			/*
756 			 * Some other important flag might have changed, so
757 			 * reset.
758 			 */
759 			elreset(sc);
760 		}
761 		break;
762 
763 	default:
764 		error = EINVAL;
765 		break;
766 	}
767 
768 	splx(s);
769 	return error;
770 }
771 
772 /*
773  * Device timeout routine.
774  */
775 void
776 elwatchdog(ifp)
777 	struct ifnet *ifp;
778 {
779 	struct el_softc *sc = ifp->if_softc;
780 
781 	log(LOG_ERR, "%s: device timeout\n", sc->sc_dev.dv_xname);
782 	sc->sc_ethercom.ec_if.if_oerrors++;
783 
784 	elreset(sc);
785 }
786