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