xref: /original-bsd/sys/i386/isa/if_we.c (revision f71c8376)
1 /*-
2  * Copyright (c) 1990 The Regents of the University of California.
3  * All rights reserved.
4  *
5  * This code is derived from software contributed to Berkeley by
6  * Tim L. Tucker
7  *
8  * %sccs.include.noredist.c%
9  *
10  *	@(#)if_we.c	5.5 (Berkeley) 01/08/91
11  */
12 
13 /*
14  * Modification history
15  *
16  * 8/28/89 - Initial version(if_wd.c), Tim L Tucker
17  */
18 
19 #include "we.h"
20 #if	NWE > 0
21 /*
22  * Western Digital 8003 ethernet/starlan adapter
23  *
24  * Supports the following interface cards:
25  * WD8003E, WD8003EBT, WD8003S, WD8003SBT, WD8013EBT
26  *
27  * The Western Digital card is one of many AT/MCA ethernet interfaces
28  * based on the National DS8390 Network Interface chip set.
29  */
30 #include "param.h"
31 #include "mbuf.h"
32 #include "socket.h"
33 #include "ioctl.h"
34 #include "errno.h"
35 #include "syslog.h"
36 
37 #include "../net/if.h"
38 #include "../net/netisr.h"
39 
40 #ifdef INET
41 #include "../netinet/in.h"
42 #include "../netinet/in_systm.h"
43 #include "../netinet/in_var.h"
44 #include "../netinet/ip.h"
45 #include "../netinet/if_ether.h"
46 #endif
47 
48 #ifdef NS
49 #include "../netns/ns.h"
50 #include "../netns/ns_if.h"
51 #endif
52 
53 #include "machine/isa/if_wereg.h"
54 #include "machine/isa/isa_device.h"
55 
56 /*
57  * This constant should really be 60 because the we adds 4 bytes of crc.
58  * However when set to 60 our packets are ignored by deuna's , 3coms are
59  * okay ??????????????????????????????????????????
60  */
61 #define ETHER_MIN_LEN 64
62 #define	ETHER_ADDR_LEN 6
63 #define ETHER_HDR_SIZE 14
64 
65 /*
66  * Ethernet software status per interface.
67  *
68  * Each interface is referenced by a network interface structure,
69  * qe_if, which the routing code uses to locate the interface.
70  * This structure contains the output queue for the interface, its address, ...
71  */
72 struct	we_softc {
73 	struct	arpcom we_ac;		/* Ethernet common part 	*/
74 #define	we_if	we_ac.ac_if		/* network-visible interface 	*/
75 #define	we_addr	we_ac.ac_enaddr		/* hardware Ethernet address 	*/
76 
77 	u_char	we_flags;		/* software state		*/
78 #define	WDF_RUNNING	0x01
79 #define WDF_TXBUSY	0x02
80 
81 	u_char	we_type;		/* interface type code		*/
82 	u_short	we_vector;		/* interrupt vector 		*/
83 	caddr_t	we_io_ctl_addr;		/* i/o bus address, control	*/
84 	caddr_t	we_io_nic_addr;		/* i/o bus address, DS8390	*/
85 
86 	caddr_t	we_vmem_addr;		/* card RAM virtual memory base */
87 	u_long	we_vmem_size;		/* card RAM bytes		*/
88 	caddr_t	we_vmem_ring;		/* receive ring RAM vaddress	*/
89 } we_softc[NWE];
90 
91 int	weprobe(), weattach(), weintr();
92 int	weinit(), weoutput(), weioctl(), wereset();
93 
94 struct	isa_driver wedriver = {
95 	weprobe, weattach, "we",
96 };
97 
98 /*
99  * Probe the WD8003 to see if it's there
100  */
101 weprobe(is)
102 	struct isa_device *is;
103 {
104 	register int i;
105 	register struct we_softc *sc = &we_softc[is->id_unit];
106 	union we_mem_sel wem;
107 	u_char sum;
108 
109 	/*
110 	 * Here we check the card ROM, if the checksum passes, and the
111 	 * type code and ethernet address check out, then we know we have
112 	 * a wd8003 card.
113 	 *
114 	 * Autoconfiguration: No warning message is printed on error.
115 	 */
116 	for (sum = 0, i = 0; i < 8; ++i)
117 	    sum += inb(is->id_iobase + WD_ROM_OFFSET + i);
118 	if (sum != WD_CHECKSUM)
119             return (0);
120 	sc->we_type = inb(is->id_iobase + WD_ROM_OFFSET + 6);
121 	if ((sc->we_type != WD_ETHER) && (sc->we_type != WD_STARLAN)
122 	&& (sc->we_type != WD_ETHER2))
123             return (0);
124 
125 	/*
126 	 * Setup card RAM area and i/o addresses
127 	 * Kernel Virtual to segment C0000-DFFFF?????
128 	 */
129 	sc->we_io_ctl_addr = is->id_iobase;
130 	sc->we_io_nic_addr = sc->we_io_ctl_addr + WD_NIC_OFFSET;
131 	sc->we_vector = is->id_irq;
132 	sc->we_vmem_addr = (caddr_t)is->id_maddr;
133 	sc->we_vmem_size = is->id_msize;
134 	sc->we_vmem_ring = sc->we_vmem_addr + (WD_PAGE_SIZE * WD_TXBUF_SIZE);
135 
136 	/*
137 	 * Save board ROM station address
138 	 */
139 	for (i = 0; i < ETHER_ADDR_LEN; ++i)
140 	    sc->we_addr[i] = inb(sc->we_io_ctl_addr + WD_ROM_OFFSET + i);
141 
142 	/*
143 	 * Mapin interface memory, setup memory select register
144 	 */
145 	/* wem.ms_addr = (u_long)sc->we_vmem_addr >> 13;  */
146 	wem.ms_addr = (u_long)(0xd0000)>> 13;
147 	wem.ms_enable = 1;
148 	wem.ms_reset = 0;
149 	outb(sc->we_io_ctl_addr, wem.ms_byte);
150 
151 	/*
152 	 * clear interface memory, then sum to make sure its valid
153 	 */
154 	for (i = 0; i < sc->we_vmem_size; ++i)
155 	    sc->we_vmem_addr[i] = 0x0;
156 	for (sum = 0, i = 0; i < sc->we_vmem_size; ++i)
157 	    sum += sc->we_vmem_addr[i];
158 	if (sum != 0x0) {
159             printf("we%d: wd8003 dual port RAM address error\n", is->id_unit);
160 	    return (0);
161 	}
162 
163 	return (WD_IO_PORTS);
164 }
165 
166 /*
167  * Interface exists: make available by filling in network interface
168  * record.  System will initialize the interface when it is ready
169  * to accept packets.
170  */
171 weattach(is)
172 	struct isa_device *is;
173 {
174 	register struct we_softc *sc = &we_softc[is->id_unit];
175 	register struct ifnet *ifp = &sc->we_if;
176 
177 	/*
178 	 * Initialize ifnet structure
179 	 */
180 	ifp->if_unit = is->id_unit;
181 	ifp->if_name = "we";
182 	ifp->if_mtu = ETHERMTU;
183 	ifp->if_flags = IFF_BROADCAST|IFF_NOTRAILERS;
184 	ifp->if_init = weinit;
185 	ifp->if_output = weoutput;
186 	ifp->if_ioctl = weioctl;
187 	ifp->if_reset = wereset;
188 	ifp->if_watchdog = 0;
189 	if_attach(ifp);
190 
191 	/*
192 	 * Banner...
193 	 */
194 	printf(" %s address %s",
195 		((sc->we_type != WD_STARLAN) ? "ethernet" : "starlan"),
196 		ether_sprintf(sc->we_addr));
197 }
198 
199 /*
200  * Reset of interface.
201  */
202 wereset(unit, uban)
203 	int unit, uban;
204 {
205 	if (unit >= NWE)
206 		return;
207 	printf("we%d: reset\n", unit);
208 	we_softc[unit].we_flags &= ~WDF_RUNNING;
209 	weinit(unit);
210 }
211 
212 /*
213  * Take interface offline.
214  */
215 westop(unit)
216 	int unit;
217 {
218 	register struct we_softc *sc = &we_softc[unit];
219 	union we_command wecmd;
220 	int s;
221 
222 	/*
223 	 * Shutdown DS8390
224 	 */
225 	s = splimp();
226 	wecmd.cs_byte = inb(sc->we_io_nic_addr + WD_P0_COMMAND);
227 	wecmd.cs_stp = 1;
228 	wecmd.cs_sta = 0;
229 	wecmd.cs_ps = 0;
230 	outb(sc->we_io_nic_addr + WD_P0_COMMAND, wecmd.cs_byte);
231 	(void) splx(s);
232 }
233 
234 /*
235  * Initialization of interface (really just DS8390).
236  */
237 weinit(unit)
238 	int unit;
239 {
240 	register struct we_softc *sc = &we_softc[unit];
241 	register struct ifnet *ifp = &sc->we_if;
242 	union we_command wecmd;
243 	int i, s;
244 
245 	/* address not known */
246 	if (ifp->if_addrlist == (struct ifaddr *)0)
247 		return;
248 
249 	/* already running */
250 	if (sc->we_flags & WDF_RUNNING)
251 		return;
252 
253 	/*
254 	 * Initialize DS8390 in order given in NSC NIC manual.
255 	 * this is stock code...please see the National manual for details.
256 	 */
257 	s = splhigh();
258 	wecmd.cs_byte = inb(sc->we_io_nic_addr + WD_P0_COMMAND);
259 	wecmd.cs_stp = 1;
260 	wecmd.cs_sta = 0;
261 	wecmd.cs_ps = 0;
262 	outb(sc->we_io_nic_addr + WD_P0_COMMAND, wecmd.cs_byte);
263 	outb(sc->we_io_nic_addr + WD_P0_DCR, WD_D_CONFIG);
264 	outb(sc->we_io_nic_addr + WD_P0_RBCR0, 0);
265 	outb(sc->we_io_nic_addr + WD_P0_RBCR1, 0);
266 	outb(sc->we_io_nic_addr + WD_P0_RCR, WD_R_MON);
267 	outb(sc->we_io_nic_addr + WD_P0_TCR, WD_T_CONFIG);
268 	outb(sc->we_io_nic_addr + WD_P0_TPSR, 0);
269 	outb(sc->we_io_nic_addr + WD_P0_PSTART, WD_TXBUF_SIZE);
270 	outb(sc->we_io_nic_addr + WD_P0_PSTOP,
271 		sc->we_vmem_size / WD_PAGE_SIZE);
272 	outb(sc->we_io_nic_addr + WD_P0_BNRY, WD_TXBUF_SIZE);
273 	outb(sc->we_io_nic_addr + WD_P0_ISR, 0xff);
274 	outb(sc->we_io_nic_addr + WD_P0_IMR, WD_I_CONFIG);
275 	wecmd.cs_ps = 1;
276 	outb(sc->we_io_nic_addr + WD_P0_COMMAND, wecmd.cs_byte);
277 	for (i = 0; i < ETHER_ADDR_LEN; ++i)
278 	    outb(sc->we_io_nic_addr + WD_P1_PAR0 + i, sc->we_addr[i]);
279 	for (i = 0; i < ETHER_ADDR_LEN; ++i)	/* == broadcast addr */
280 	    outb(sc->we_io_nic_addr + WD_P1_MAR0 + i, 0xff);
281 	outb(sc->we_io_nic_addr + WD_P1_CURR, WD_TXBUF_SIZE);
282 	wecmd.cs_ps = 0;
283 	wecmd.cs_stp = 0;
284 	wecmd.cs_sta = 1;
285 	wecmd.cs_rd = 0x4;
286 	outb(sc->we_io_nic_addr + WD_P1_COMMAND, wecmd.cs_byte);
287 	outb(sc->we_io_nic_addr + WD_P0_RCR, WD_R_CONFIG);
288 
289 	/*
290 	 * Take the interface out of reset, program the vector,
291 	 * enable interrupts, and tell the world we are up.
292 	 */
293 	ifp->if_flags |= IFF_UP | IFF_RUNNING;
294 	sc->we_flags |= WDF_RUNNING;
295 	sc->we_flags &= ~WDF_TXBUSY;
296 	(void) splx(s);
297 	westart(unit);
298 }
299 
300 /*
301  * Start output on interface.
302  */
303 westart(unit)
304 	int unit;
305 {
306 	register struct we_softc *sc = &we_softc[unit];
307 	struct mbuf *m0, *m;
308 	register caddr_t buffer;
309 	int len = 0, s;
310 	union we_command wecmd;
311 
312 	/*
313 	 * The DS8390 has only one transmit buffer, if it is busy we
314 	 * must wait until the transmit interrupt completes.
315 	 */
316 	s = splhigh();
317 	if (sc->we_flags & WDF_TXBUSY) {
318 		(void) splx(s);
319 		return;
320 	}
321 	IF_DEQUEUE(&sc->we_if.if_snd, m);
322 	if (m == 0) {
323 		(void) splx(s);
324 		return;
325 	}
326 	sc->we_flags |= WDF_TXBUSY;
327 	(void) splx(s);
328 
329 	/*
330 	 * Copy the mbuf chain into the transmit buffer
331 	 */
332 	buffer = sc->we_vmem_addr;
333 	for (m0 = m; m != 0; m = m->m_next) {
334 		bcopy(mtod(m, caddr_t), buffer, m->m_len);
335 		buffer += m->m_len;
336         	len += m->m_len;
337 	}
338 
339 	/*
340 	 * If this was a broadcast packet loop it
341 	 * back because the hardware can't hear its own
342 	 * transmits.
343 	 */
344 	if (bcmp((caddr_t)(mtod(m0, struct ether_header *)->ether_dhost),
345 	   (caddr_t)etherbroadcastaddr,
346 	   sizeof(etherbroadcastaddr)) == 0) {
347 		weread(sc, m0);
348 	} else {
349 		m_freem(m0);
350 	}
351 
352 	/*
353 	 * Init transmit length registers, and set transmit start flag.
354 	 */
355 	s = splhigh();
356 	len = MAX(len, ETHER_MIN_LEN);
357 	wecmd.cs_byte = inb(sc->we_io_nic_addr + WD_P0_COMMAND);
358 	wecmd.cs_ps = 0;
359 	outb(sc->we_io_nic_addr + WD_P0_COMMAND, wecmd.cs_byte);
360 	outb(sc->we_io_nic_addr + WD_P0_TBCR0, len & 0xff);
361 	outb(sc->we_io_nic_addr + WD_P0_TBCR1, len >> 8);
362 	wecmd.cs_txp = 1;
363 	outb(sc->we_io_nic_addr + WD_P0_COMMAND, wecmd.cs_byte);
364 	(void) splx(s);
365 }
366 
367 /*
368  * Ethernet interface interrupt processor
369  */
370 weintr(unit)
371 	int unit;
372 {
373 	register struct we_softc *sc = &we_softc[0];
374 	union we_command wecmd;
375 	union we_interrupt weisr;
376 	int s;
377 	unit =0;
378 
379 	/* disable onboard interrupts, then get interrupt status */
380 	s = splhigh();
381 	wecmd.cs_byte = inb(sc->we_io_nic_addr + WD_P0_COMMAND);
382 	wecmd.cs_ps = 0;
383 	outb(sc->we_io_nic_addr + WD_P0_COMMAND, wecmd.cs_byte);
384 	outb(sc->we_io_nic_addr + WD_P0_IMR, 0);
385 	weisr.is_byte = inb(sc->we_io_nic_addr + WD_P0_ISR);
386 	outb(sc->we_io_nic_addr + WD_P0_ISR, 0xff);
387 	(void) splx(s);
388 
389 	/* transmit error */
390 	if (weisr.is_txe) {
391 		/* need to read these registers to clear status */
392 		sc->we_if.if_collisions +=
393 		    inb(sc->we_io_nic_addr + WD_P0_TBCR0);
394 		++sc->we_if.if_oerrors;
395 	}
396 
397 	/* receiver error */
398 	if (weisr.is_rxe) {
399 		/* need to read these registers to clear status */
400 		(void) inb(sc->we_io_nic_addr + 0xD);
401 		(void) inb(sc->we_io_nic_addr + 0xE);
402 		(void) inb(sc->we_io_nic_addr + 0xF);
403 		++sc->we_if.if_ierrors;
404 	}
405 
406 	/* normal transmit complete */
407 	if (weisr.is_ptx)
408 		wetint (unit);
409 
410 	/* normal receive notification */
411 	if (weisr.is_prx)
412 		werint (unit);
413 
414 	/* try to start transmit */
415 	westart(unit);
416 
417 	/* re-enable onboard interrupts */
418 	wecmd.cs_byte = inb(sc->we_io_nic_addr + WD_P0_COMMAND);
419 	wecmd.cs_ps = 0;
420 	outb(sc->we_io_nic_addr + WD_P0_COMMAND, wecmd.cs_byte);
421 	outb(sc->we_io_nic_addr + WD_P0_IMR, WD_I_CONFIG);
422 }
423 
424 /*
425  * Ethernet interface transmit interrupt.
426  */
427 wetint(unit)
428 	int unit;
429 {
430 	register struct we_softc *sc = &we_softc[unit];
431 
432 	/*
433 	 * Do some statistics (assume page zero of NIC mapped in)
434 	 */
435 	sc->we_flags &= ~WDF_TXBUSY;
436 	sc->we_if.if_timer = 0;
437 	++sc->we_if.if_opackets;
438 	sc->we_if.if_collisions += inb(sc->we_io_nic_addr + WD_P0_TBCR0);
439 }
440 
441 /*
442  * Ethernet interface receiver interrupt.
443  */
444 werint(unit)
445 	int unit;
446 {
447 	register struct we_softc *sc = &we_softc[unit];
448 	register struct mbuf **m;
449 	int mlen, len, count;
450 	u_char bnry, curr;
451 	union we_command wecmd;
452 	struct we_ring *wer;
453 	struct mbuf *m0;
454 	caddr_t pkt, endp;
455 static Bdry;
456 
457 	/*
458 	 * Traverse the receive ring looking for packets to pass back.
459 	 * The search is complete when we find a descriptor not in use.
460 	 */
461 	wecmd.cs_byte = inb(sc->we_io_nic_addr + WD_P0_COMMAND);
462 	wecmd.cs_ps = 0;
463 	outb(sc->we_io_nic_addr + WD_P0_COMMAND, wecmd.cs_byte);
464 	bnry = inb(sc->we_io_nic_addr + WD_P0_BNRY);
465 	wecmd.cs_ps = 1;
466 	outb(sc->we_io_nic_addr + WD_P0_COMMAND, wecmd.cs_byte);
467 	curr = inb(sc->we_io_nic_addr + WD_P1_CURR);
468 if(Bdry && Bdry > bnry)
469 	bnry =Bdry;
470 	while (bnry != curr)
471 	{
472 		/* get pointer to this buffer header structure */
473 		wer = (struct we_ring *)(sc->we_vmem_addr + (bnry << 8));
474         	len = wer->we_count - 4;	/* count includes CRC */
475 		pkt = (caddr_t)(wer + 1) /*- 2*/;	/* 2 - word align pkt data */
476         	count = len /*+ 2*/;		/* copy two extra bytes */
477 		endp = (caddr_t)(sc->we_vmem_addr + sc->we_vmem_size);
478 		++sc->we_if.if_ipackets;
479 
480 		/* pull packet out of dual ported RAM */
481 		m = &m0; m0 = 0;
482 		while (count > 0)
483 		{
484 		    /* drop chain if can't get another buffer */
485 		    MGET(*m, M_DONTWAIT, MT_DATA);
486 		    if (*m == 0)
487 		    {
488 			m_freem(m0);
489 			goto outofbufs;
490 		    }
491 
492 		    /* fill mbuf and attach to packet list */
493 		    mlen = MIN(MLEN, count);
494 		    mlen = MIN(mlen, endp - pkt);
495 		    bcopy(pkt, mtod(*m, caddr_t), mlen);
496 		    (*m)->m_len = mlen;
497 		    m = &((*m)->m_next);
498 		    pkt += mlen;
499 		    count -= mlen;
500 
501 		    /* wrap memory pointer around circ buffer */
502 		    if (pkt == endp)
503 			pkt = (caddr_t)sc->we_vmem_ring;
504 		}
505 
506 		/* skip aligment bytes, send packet up to higher levels */
507 		if (m0 != 0)
508 		{
509 /*		    m0->m_off += 2*/;
510 		    weread(sc, m0);
511 		}
512 
513 outofbufs:
514 		/* advance on chip Boundry register */
515 		bnry = wer->we_next_packet;
516 		wecmd.cs_byte = inb(sc->we_io_nic_addr + WD_P0_COMMAND);
517 		wecmd.cs_ps = 0;
518 		outb(sc->we_io_nic_addr + WD_P0_COMMAND, wecmd.cs_byte);
519 
520 		/* watch out for NIC overflow, reset Boundry if invalid */
521 		if ((bnry - 1) < WD_TXBUF_SIZE) {
522 #ifdef notdef
523 		    wereset(unit, 0);
524 		    break;
525 #else
526 		    outb(sc->we_io_nic_addr + WD_P0_BNRY,
527 			(sc->we_vmem_size / WD_PAGE_SIZE) - 1);
528 #endif
529 		}
530 		outb(sc->we_io_nic_addr + WD_P0_BNRY, bnry-1);
531 
532 		/* refresh our copy of CURR */
533 		wecmd.cs_ps = 1;
534 		outb(sc->we_io_nic_addr + WD_P0_COMMAND, wecmd.cs_byte);
535 		curr = inb(sc->we_io_nic_addr + WD_P1_CURR);
536 	}
537 Bdry = bnry;
538 }
539 
540 /*
541  * Ethernet output routine.
542  * Encapsulate a packet of type family for the local net.
543  */
544 weoutput(ifp, m0, dst)
545 	struct ifnet *ifp;
546 	struct mbuf *m0;
547 	struct sockaddr *dst;
548 {
549 	int type, s, error;
550 	u_char edst[6];
551 	struct in_addr idst;
552 	register struct we_softc *sc = &we_softc[ifp->if_unit];
553 	register struct mbuf *m = m0;
554 	register struct ether_header *eh;
555 	int usetrailers;
556 
557 	if ((ifp->if_flags & (IFF_UP|IFF_RUNNING)) != (IFF_UP|IFF_RUNNING)) {
558 		error = ENETDOWN;
559 		goto bad;
560 	}
561 
562 	switch (dst->sa_family) {
563 
564 #ifdef INET
565 	case AF_INET:
566 		/* Note: we ignore usetrailers */
567 		idst = ((struct sockaddr_in *)dst)->sin_addr;
568 		if (!arpresolve(&sc->we_ac, m, &idst, edst, &usetrailers))
569 			return (0);	/* if not yet resolved */
570 		type = ETHERTYPE_IP;
571 		break;
572 #endif
573 #ifdef NS
574 	case AF_NS:
575 		type = ETHERTYPE_NS;
576  		bcopy((caddr_t)&(((struct sockaddr_ns *)dst)->sns_addr.x_host),
577 		    (caddr_t)edst, sizeof (edst));
578 		break;
579 #endif
580 
581 
582 	case AF_UNSPEC:
583 		eh = (struct ether_header *)dst->sa_data;
584  		bcopy((caddr_t)eh->ether_dhost, (caddr_t)edst, sizeof (edst));
585 		type = eh->ether_type;
586 		break;
587 
588 	default:
589 		printf("we%d: can't handle af%d\n", ifp->if_unit,
590 			dst->sa_family);
591 		error = EAFNOSUPPORT;
592 		goto bad;
593 	}
594 
595 	/*
596 	 * Add local net header.  If no space in first mbuf,
597 	 * allocate another.
598 	 */
599 	if (m->m_off > MMAXOFF || MMINOFF + ETHER_HDR_SIZE > m->m_off) {
600 		m = m_get(M_DONTWAIT, MT_HEADER);
601 		if (m == 0) {
602 			error = ENOBUFS;
603 			goto bad;
604 		}
605 		m->m_next = m0;
606 		m->m_off = MMINOFF;
607 		m->m_len = ETHER_HDR_SIZE;
608 	} else {
609 		m->m_off -= ETHER_HDR_SIZE;
610 		m->m_len += ETHER_HDR_SIZE;
611 	}
612 	eh = mtod(m, struct ether_header *);
613 	eh->ether_type = htons((u_short)type);
614  	bcopy((caddr_t)edst, (caddr_t)eh->ether_dhost, sizeof (edst));
615  	bcopy((caddr_t)sc->we_addr, (caddr_t)eh->ether_shost,
616 		sizeof (sc->we_addr));
617 
618 	/*
619 	 * Queue message on interface, and start output if interface
620 	 * not yet active.
621 	 */
622 	s = splimp();
623 	if (IF_QFULL(&ifp->if_snd)) {
624 		IF_DROP(&ifp->if_snd);
625 		(void) splx(s);
626 		m_freem(m);
627 		return (ENOBUFS);
628 	}
629 	IF_ENQUEUE(&ifp->if_snd, m);
630 	(void) splx(s);
631 	westart(ifp->if_unit);
632 	return (0);
633 
634 bad:
635 	m_freem(m0);
636 	return (error);
637 }
638 
639 /*
640  * Process an ioctl request.
641  */
642 weioctl(ifp, cmd, data)
643 	register struct ifnet *ifp;
644 	int cmd;
645 	caddr_t data;
646 {
647 	struct we_softc *sc = &we_softc[ifp->if_unit];
648 	struct ifaddr *ifa = (struct ifaddr *)data;
649 	int s = splimp(), error = 0;
650 
651 	switch (cmd) {
652 
653 	case SIOCSIFADDR:
654 		ifp->if_flags |= IFF_UP;
655 		weinit(ifp->if_unit);
656 		switch(ifa->ifa_addr.sa_family) {
657 #ifdef INET
658 		case AF_INET:
659 			((struct arpcom *)ifp)->ac_ipaddr =
660 				IA_SIN(ifa)->sin_addr;
661 			arpwhohas((struct arpcom *)ifp, &IA_SIN(ifa)->sin_addr);
662 			break;
663 #endif
664 #ifdef NS
665 		case AF_NS:
666 		    {
667 			register struct ns_addr *ina = &(IA_SNS(ifa)->sns_addr);
668 
669 			if (ns_nullhost(*ina))
670 				ina->x_host = *(union ns_host *)(sc->we_addr);
671 			else
672 				wesetaddr(ina->x_host.c_host, ifp->if_unit);
673 			break;
674 		    }
675 #endif
676 		}
677 		break;
678 
679 	case SIOCSIFFLAGS:
680 		if (((ifp->if_flags & IFF_UP) == 0) &&
681 		   (sc->we_flags & WDF_RUNNING)) {
682 			westop(ifp->if_unit);
683 		} else if (((ifp->if_flags & IFF_UP) == IFF_UP) &&
684 		   ((sc->we_flags & WDF_RUNNING) == 0))
685 			weinit(ifp->if_unit);
686 		break;
687 
688 	default:
689 		error = EINVAL;
690 
691 	}
692 	(void) splx(s);
693 	return (error);
694 }
695 
696 /*
697  * set ethernet address for unit
698  */
699 wesetaddr(physaddr, unit)
700 	u_char *physaddr;
701 	int unit;
702 {
703 	register struct we_softc *sc = &we_softc[unit];
704 	register int i;
705 
706 	/*
707 	 * Rewrite ethernet address, and then force restart of NIC
708 	 */
709 	for (i = 0; i < ETHER_ADDR_LEN; i++)
710 		sc->we_addr[i] = physaddr[i];
711 	sc->we_flags &= ~WDF_RUNNING;
712 	weinit(unit);
713 }
714 
715 /*
716  * Pass a packet to the higher levels.
717  * NO TRAILER PROTOCOL!
718  */
719 weread(sc, m)
720 	register struct we_softc *sc;
721     	struct mbuf *m;
722 {
723 	struct ether_header *eh;
724 	int scn, type, s;
725 	struct ifqueue *inq;
726 
727 	/*
728 	 * Get ethernet protocol type out of ether header
729 	 */
730 	eh = mtod(m, struct ether_header *);
731 	type = ntohs((u_short)eh->ether_type);
732 
733 	/*
734 	 * Drop ethernet header
735 	 */
736 	m->m_off += ETHER_HDR_SIZE;
737 	m->m_len -= ETHER_HDR_SIZE;
738 
739 	/*
740 	 * Insert ifp pointer at start of packet
741 	 */
742 	m->m_off -= sizeof (struct ifnet *);
743 	m->m_len += sizeof (struct ifnet *);
744 	*(mtod(m, struct ifnet **)) = &sc->we_if;
745 
746 	switch (type) {
747 
748 #ifdef INET
749 	case ETHERTYPE_IP:
750 		scn = NETISR_IP;
751 		inq = &ipintrq;
752 		break;
753 
754 	case ETHERTYPE_ARP:
755 		arpinput(&sc->we_ac, m);
756 		return;
757 #endif
758 #ifdef NS
759 	case ETHERTYPE_NS:
760 		scn = NETISR_NS;
761 		inq = &nsintrq;
762 		break;
763 
764 #endif
765 
766 	default:
767 		m_freem(m);
768 		return;
769 	}
770 
771 	s = splimp();
772 	if (IF_QFULL(inq)) {
773 		IF_DROP(inq);
774 		m_freem(m);
775 	} else
776 		IF_ENQUEUE(inq, m);
777 	schednetisr(scn);
778 	(void) splx(s);
779 }
780 
781 #endif
782