xref: /csrg-svn/sys/i386/isa/if_we.c (revision 45540)
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.2 (Berkeley) 11/08/90
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
26  *
27  * The Western Digital card is one of many AT/MCA ethernet interfaces
28  * based on the National N8390/NS32490 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/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, NS32490	*/
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 NS32490
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 NS32490).
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 NS32490 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 #define WD_I_CONFIG	0xff
275 	outb(sc->we_io_nic_addr + WD_P0_IMR, WD_I_CONFIG);
276 	wecmd.cs_ps = 1;
277 	outb(sc->we_io_nic_addr + WD_P0_COMMAND, wecmd.cs_byte);
278 	for (i = 0; i < ETHER_ADDR_LEN; ++i)
279 	    outb(sc->we_io_nic_addr + WD_P1_PAR0 + i, sc->we_addr[i]);
280 	for (i = 0; i < ETHER_ADDR_LEN; ++i)	/* == broadcast addr */
281 	    outb(sc->we_io_nic_addr + WD_P1_MAR0 + i, 0xff);
282 	outb(sc->we_io_nic_addr + WD_P1_CURR, WD_TXBUF_SIZE);
283 	wecmd.cs_ps = 0;
284 	wecmd.cs_stp = 0;
285 	wecmd.cs_sta = 1;
286 	wecmd.cs_rd = 0x4;
287 	outb(sc->we_io_nic_addr + WD_P1_COMMAND, wecmd.cs_byte);
288 	outb(sc->we_io_nic_addr + WD_P0_RCR, WD_R_CONFIG);
289 
290 	/*
291 	 * Take the interface out of reset, program the vector,
292 	 * enable interrupts, and tell the world we are up.
293 	 */
294 	ifp->if_flags |= IFF_UP | IFF_RUNNING;
295 	sc->we_flags |= WDF_RUNNING;
296 	sc->we_flags &= ~WDF_TXBUSY;
297 	(void) splx(s);
298 	westart(unit);
299 }
300 
301 /*
302  * Start output on interface.
303  */
304 westart(unit)
305 	int unit;
306 {
307 	register struct we_softc *sc = &we_softc[unit];
308 	struct mbuf *m0, *m;
309 	register caddr_t buffer;
310 	int len = 0, s;
311 	union we_command wecmd;
312 
313 	/*
314 	 * The NS32490 has only one transmit buffer, if it is busy we
315 	 * must wait until the transmit interrupt completes.
316 	 */
317 	s = splhigh();
318 	if (sc->we_flags & WDF_TXBUSY) {
319 		(void) splx(s);
320 		return;
321 	}
322 	IF_DEQUEUE(&sc->we_if.if_snd, m);
323 	if (m == 0) {
324 		(void) splx(s);
325 		return;
326 	}
327 	sc->we_flags |= WDF_TXBUSY;
328 	(void) splx(s);
329 
330 	/*
331 	 * Copy the mbuf chain into the transmit buffer
332 	 */
333 	buffer = sc->we_vmem_addr;
334 	for (m0 = m; m != 0; m = m->m_next) {
335 		bcopy(mtod(m, caddr_t), buffer, m->m_len);
336 		buffer += m->m_len;
337         	len += m->m_len;
338 	}
339 
340 	/*
341 	 * If this was a broadcast packet loop it
342 	 * back because the hardware can't hear its own
343 	 * transmits.
344 	 */
345 #ifdef notyet
346 	if (bcmp((caddr_t)(mtod(m0, struct ether_header *)->ether_dhost),
347 	   (caddr_t)etherbroadcastaddr,
348 	   sizeof(etherbroadcastaddr)) == 0) {
349 		weread(sc, m0);
350 	} else {
351 #endif
352 		m_freem(m0);
353 #ifdef notyet
354 	}
355 #endif
356 
357 	/*
358 	 * Init transmit length registers, and set transmit start flag.
359 	 */
360 	s = splhigh();
361 	len = MAX(len, ETHER_MIN_LEN);
362 	wecmd.cs_byte = inb(sc->we_io_nic_addr + WD_P0_COMMAND);
363 	wecmd.cs_ps = 0;
364 	outb(sc->we_io_nic_addr + WD_P0_COMMAND, wecmd.cs_byte);
365 	outb(sc->we_io_nic_addr + WD_P0_TBCR0, len & 0xff);
366 	outb(sc->we_io_nic_addr + WD_P0_TBCR1, len >> 8);
367 	wecmd.cs_txp = 1;
368 	outb(sc->we_io_nic_addr + WD_P0_COMMAND, wecmd.cs_byte);
369 	(void) splx(s);
370 }
371 
372 /*
373  * Ethernet interface interrupt processor
374  */
375 weintr(unit)
376 	int unit;
377 {
378 	register struct we_softc *sc = &we_softc[0];
379 	union we_command wecmd;
380 	union we_interrupt weisr;
381 	int s;
382 	unit =0;
383 
384 	/* disable onboard interrupts, then get interrupt status */
385 	s = splhigh();
386 	wecmd.cs_byte = inb(sc->we_io_nic_addr + WD_P0_COMMAND);
387 	wecmd.cs_ps = 0;
388 	outb(sc->we_io_nic_addr + WD_P0_COMMAND, wecmd.cs_byte);
389 	/* outb(sc->we_io_nic_addr + WD_P0_IMR, 0); */
390 	weisr.is_byte = inb(sc->we_io_nic_addr + WD_P0_ISR);
391 #ifdef notdef
392 printf("weintr %x ", inb(sc->we_io_nic_addr + WD_P0_ISR));
393 outb(sc->we_io_nic_addr+WD_P0_IMR,0xff);
394 #endif
395 	outb(sc->we_io_nic_addr + WD_P0_ISR, 0xff);
396 	(void) splx(s);
397 
398 	/* transmit error */
399 	if (weisr.is_txe) {
400 printf("txe\n");
401 		/* need to read these registers to clear status */
402 		sc->we_if.if_collisions +=
403 		    inb(sc->we_io_nic_addr + WD_P0_TBCR0);
404 		++sc->we_if.if_oerrors;
405 	}
406 
407 	/* receiver error */
408 	if (weisr.is_rxe) {
409 printf("rxe\n");
410 		/* need to read these registers to clear status */
411 		(void) inb(sc->we_io_nic_addr + 0xD);
412 		(void) inb(sc->we_io_nic_addr + 0xE);
413 		(void) inb(sc->we_io_nic_addr + 0xF);
414 		++sc->we_if.if_ierrors;
415 	}
416 
417 	/* normal transmit complete */
418 	if (weisr.is_ptx)
419 		wetint (unit);
420 
421 	/* normal receive notification */
422 	if (weisr.is_prx)
423 		werint (unit);
424 
425 	/* try to start transmit */
426 	westart(unit);
427 
428 	/* re-enable onboard interrupts */
429 	wecmd.cs_byte = inb(sc->we_io_nic_addr + WD_P0_COMMAND);
430 	wecmd.cs_ps = 0;
431 	outb(sc->we_io_nic_addr + WD_P0_COMMAND, wecmd.cs_byte);
432 	outb(sc->we_io_nic_addr + WD_P0_IMR, WD_I_CONFIG);
433 }
434 
435 /*
436  * Ethernet interface transmit interrupt.
437  */
438 wetint(unit)
439 	int unit;
440 {
441 	register struct we_softc *sc = &we_softc[unit];
442 
443 	/*
444 	 * Do some statistics (assume page zero of NIC mapped in)
445 	 */
446 	sc->we_flags &= ~WDF_TXBUSY;
447 	sc->we_if.if_timer = 0;
448 	++sc->we_if.if_opackets;
449 	sc->we_if.if_collisions += inb(sc->we_io_nic_addr + WD_P0_TBCR0);
450 }
451 
452 /*
453  * Ethernet interface receiver interrupt.
454  */
455 werint(unit)
456 	int unit;
457 {
458 	register struct we_softc *sc = &we_softc[unit];
459 	register struct mbuf **m;
460 	int mlen, len, count;
461 	u_char bnry, curr;
462 	union we_command wecmd;
463 	struct we_ring *wer;
464 	struct mbuf *m0;
465 	caddr_t pkt, endp;
466 static Bdry;
467 
468 	/*
469 	 * Traverse the receive ring looking for packets to pass back.
470 	 * The search is complete when we find a descriptor not in use.
471 	 */
472 	wecmd.cs_byte = inb(sc->we_io_nic_addr + WD_P0_COMMAND);
473 	wecmd.cs_ps = 0;
474 	outb(sc->we_io_nic_addr + WD_P0_COMMAND, wecmd.cs_byte);
475 	bnry = inb(sc->we_io_nic_addr + WD_P0_BNRY);
476 	wecmd.cs_ps = 1;
477 	outb(sc->we_io_nic_addr + WD_P0_COMMAND, wecmd.cs_byte);
478 	curr = inb(sc->we_io_nic_addr + WD_P1_CURR);
479 printf("Bd %x cur %x ", bnry, curr);
480 if(Bdry && Bdry > bnry){
481 	bnry =Bdry;
482 printf("bd %x! ", bnry);
483 }
484 	while (bnry != curr)
485 	{
486 		/* get pointer to this buffer header structure */
487 		wer = (struct we_ring *)(sc->we_vmem_addr + (bnry << 8));
488         	len = wer->we_count - 4;	/* count includes CRC */
489 printf("l %d", len);
490 		pkt = (caddr_t)(wer + 1) /*- 2*/;	/* 2 - word align pkt data */
491         	count = len /*+ 2*/;		/* copy two extra bytes */
492 		endp = (caddr_t)(sc->we_vmem_addr + sc->we_vmem_size);
493 		++sc->we_if.if_ipackets;
494 
495 		/* pull packet out of dual ported RAM */
496 		m = &m0; m0 = 0;
497 		while (count > 0)
498 		{
499 		    /* drop chain if can't get another buffer */
500 		    MGET(*m, M_DONTWAIT, MT_DATA);
501 		    if (*m == 0)
502 		    {
503 			m_freem(m0);
504 			goto outofbufs;
505 		    }
506 
507 		    /* fill mbuf and attach to packet list */
508 		    mlen = MIN(MLEN, count);
509 		    mlen = MIN(mlen, endp - pkt);
510 		    bcopy(pkt, mtod(*m, caddr_t), mlen);
511 		    (*m)->m_len = mlen;
512 		    m = &((*m)->m_next);
513 		    pkt += mlen;
514 		    count -= mlen;
515 
516 		    /* wrap memory pointer around circ buffer */
517 		    if (pkt == endp)
518 			pkt = (caddr_t)sc->we_vmem_ring;
519 		}
520 
521 		/* skip aligment bytes, send packet up to higher levels */
522 		if (m0 != 0)
523 		{
524 /*		    m0->m_off += 2*/;
525 		    weread(sc, m0);
526 		}
527 
528 outofbufs:
529 		/* advance on chip Boundry register */
530 printf("nx %x ", wer->we_next_packet);
531 		bnry = wer->we_next_packet;
532 		wecmd.cs_byte = inb(sc->we_io_nic_addr + WD_P0_COMMAND);
533 		wecmd.cs_ps = 0;
534 		outb(sc->we_io_nic_addr + WD_P0_COMMAND, wecmd.cs_byte);
535 
536 		/* watch out for NIC overflow, reset Boundry if invalid */
537 		if ((bnry - 1) < WD_TXBUF_SIZE) {
538 #ifdef notdef
539 		    wereset(unit, 0);
540 		    break;
541 #else
542 		    outb(sc->we_io_nic_addr + WD_P0_BNRY,
543 			(sc->we_vmem_size / WD_PAGE_SIZE) - 1);
544 #endif
545 		}
546 		outb(sc->we_io_nic_addr + WD_P0_BNRY, bnry-1);
547 
548 		/* refresh our copy of CURR */
549 		wecmd.cs_ps = 1;
550 		outb(sc->we_io_nic_addr + WD_P0_COMMAND, wecmd.cs_byte);
551 		curr = inb(sc->we_io_nic_addr + WD_P1_CURR);
552 printf("bd %x cur %x ", bnry-1, curr);
553 	}
554 printf("bD %x\n", bnry);
555 Bdry = bnry;
556 }
557 
558 /*
559  * Ethernet output routine.
560  * Encapsulate a packet of type family for the local net.
561  */
562 weoutput(ifp, m0, dst)
563 	struct ifnet *ifp;
564 	struct mbuf *m0;
565 	struct sockaddr *dst;
566 {
567 	int type, s, error;
568 	u_char edst[6];
569 	struct in_addr idst;
570 	register struct we_softc *sc = &we_softc[ifp->if_unit];
571 	register struct mbuf *m = m0;
572 	register struct ether_header *eh;
573 	int usetrailers;
574 
575 	if ((ifp->if_flags & (IFF_UP|IFF_RUNNING)) != (IFF_UP|IFF_RUNNING)) {
576 		error = ENETDOWN;
577 		goto bad;
578 	}
579 
580 	switch (dst->sa_family) {
581 
582 #ifdef INET
583 	case AF_INET:
584 		/* Note: we ignore usetrailers */
585 		idst = ((struct sockaddr_in *)dst)->sin_addr;
586 		if (!arpresolve(&sc->we_ac, m, &idst, edst, &usetrailers))
587 			return (0);	/* if not yet resolved */
588 		type = ETHERTYPE_IP;
589 		break;
590 #endif
591 #ifdef NS
592 	case AF_NS:
593 		type = ETHERTYPE_NS;
594  		bcopy((caddr_t)&(((struct sockaddr_ns *)dst)->sns_addr.x_host),
595 		    (caddr_t)edst, sizeof (edst));
596 		break;
597 #endif
598 
599 
600 	case AF_UNSPEC:
601 		eh = (struct ether_header *)dst->sa_data;
602  		bcopy((caddr_t)eh->ether_dhost, (caddr_t)edst, sizeof (edst));
603 		type = eh->ether_type;
604 		break;
605 
606 	default:
607 		printf("we%d: can't handle af%d\n", ifp->if_unit,
608 			dst->sa_family);
609 		error = EAFNOSUPPORT;
610 		goto bad;
611 	}
612 
613 	/*
614 	 * Add local net header.  If no space in first mbuf,
615 	 * allocate another.
616 	 */
617 	if (m->m_off > MMAXOFF || MMINOFF + ETHER_HDR_SIZE > m->m_off) {
618 		m = m_get(M_DONTWAIT, MT_HEADER);
619 		if (m == 0) {
620 			error = ENOBUFS;
621 			goto bad;
622 		}
623 		m->m_next = m0;
624 		m->m_off = MMINOFF;
625 		m->m_len = ETHER_HDR_SIZE;
626 	} else {
627 		m->m_off -= ETHER_HDR_SIZE;
628 		m->m_len += ETHER_HDR_SIZE;
629 	}
630 	eh = mtod(m, struct ether_header *);
631 	eh->ether_type = htons((u_short)type);
632  	bcopy((caddr_t)edst, (caddr_t)eh->ether_dhost, sizeof (edst));
633  	bcopy((caddr_t)sc->we_addr, (caddr_t)eh->ether_shost,
634 		sizeof (sc->we_addr));
635 
636 	/*
637 	 * Queue message on interface, and start output if interface
638 	 * not yet active.
639 	 */
640 	s = splimp();
641 	if (IF_QFULL(&ifp->if_snd)) {
642 		IF_DROP(&ifp->if_snd);
643 		(void) splx(s);
644 		m_freem(m);
645 		return (ENOBUFS);
646 	}
647 	IF_ENQUEUE(&ifp->if_snd, m);
648 	(void) splx(s);
649 	westart(ifp->if_unit);
650 	return (0);
651 
652 bad:
653 	m_freem(m0);
654 	return (error);
655 }
656 
657 /*
658  * Process an ioctl request.
659  */
660 weioctl(ifp, cmd, data)
661 	register struct ifnet *ifp;
662 	int cmd;
663 	caddr_t data;
664 {
665 	struct we_softc *sc = &we_softc[ifp->if_unit];
666 	struct ifaddr *ifa = (struct ifaddr *)data;
667 	int s = splimp(), error = 0;
668 
669 	switch (cmd) {
670 
671 	case SIOCSIFADDR:
672 		ifp->if_flags |= IFF_UP;
673 		weinit(ifp->if_unit);
674 		switch(ifa->ifa_addr.sa_family) {
675 #ifdef INET
676 		case AF_INET:
677 			((struct arpcom *)ifp)->ac_ipaddr =
678 				IA_SIN(ifa)->sin_addr;
679 			arpwhohas((struct arpcom *)ifp, &IA_SIN(ifa)->sin_addr);
680 			break;
681 #endif
682 #ifdef NS
683 		case AF_NS:
684 		    {
685 			register struct ns_addr *ina = &(IA_SNS(ifa)->sns_addr);
686 
687 			if (ns_nullhost(*ina))
688 				ina->x_host = *(union ns_host *)(sc->we_addr);
689 			else
690 				wesetaddr(ina->x_host.c_host, ifp->if_unit);
691 			break;
692 		    }
693 #endif
694 		}
695 		break;
696 
697 	case SIOCSIFFLAGS:
698 		if (((ifp->if_flags & IFF_UP) == 0) &&
699 		   (sc->we_flags & WDF_RUNNING)) {
700 			westop(ifp->if_unit);
701 		} else if (((ifp->if_flags & IFF_UP) == IFF_UP) &&
702 		   ((sc->we_flags & WDF_RUNNING) == 0))
703 			weinit(ifp->if_unit);
704 		break;
705 
706 	default:
707 		error = EINVAL;
708 
709 	}
710 	(void) splx(s);
711 	return (error);
712 }
713 
714 /*
715  * set ethernet address for unit
716  */
717 wesetaddr(physaddr, unit)
718 	u_char *physaddr;
719 	int unit;
720 {
721 	register struct we_softc *sc = &we_softc[unit];
722 	register int i;
723 
724 	/*
725 	 * Rewrite ethernet address, and then force restart of NIC
726 	 */
727 	for (i = 0; i < ETHER_ADDR_LEN; i++)
728 		sc->we_addr[i] = physaddr[i];
729 	sc->we_flags &= ~WDF_RUNNING;
730 	weinit(unit);
731 }
732 
733 /*
734  * Pass a packet to the higher levels.
735  * NO TRAILER PROTOCOL!
736  */
737 weread(sc, m)
738 	register struct we_softc *sc;
739     	struct mbuf *m;
740 {
741 	struct ether_header *eh;
742 	int scn, type, s;
743 	struct ifqueue *inq;
744 
745 	/*
746 	 * Get ethernet protocol type out of ether header
747 	 */
748 	eh = mtod(m, struct ether_header *);
749 	type = ntohs((u_short)eh->ether_type);
750 
751 	/*
752 	 * Drop ethernet header
753 	 */
754 	m->m_off += ETHER_HDR_SIZE;
755 	m->m_len -= ETHER_HDR_SIZE;
756 
757 	/*
758 	 * Insert ifp pointer at start of packet
759 	 */
760 	m->m_off -= sizeof (struct ifnet *);
761 	m->m_len += sizeof (struct ifnet *);
762 	*(mtod(m, struct ifnet **)) = &sc->we_if;
763 
764 printf("ty %x ", type);
765 	switch (type) {
766 
767 #ifdef INET
768 	case ETHERTYPE_IP:
769 printf("ip ");
770 		scn = NETISR_IP;
771 		inq = &ipintrq;
772 		break;
773 
774 	case ETHERTYPE_ARP:
775 printf("arp ");
776 		arpinput(&sc->we_ac, m);
777 		return;
778 #endif
779 #ifdef NS
780 	case ETHERTYPE_NS:
781 		scn = NETISR_NS;
782 		inq = &nsintrq;
783 		break;
784 
785 #endif
786 
787 	default:
788 		m_freem(m);
789 		return;
790 	}
791 
792 	s = splimp();
793 	if (IF_QFULL(inq)) {
794 		IF_DROP(inq);
795 		m_freem(m);
796 	} else
797 		IF_ENQUEUE(inq, m);
798 	schednetisr(scn);
799 	(void) splx(s);
800 }
801 
802 #endif
803