xref: /csrg-svn/sys/i386/isa/if_we.c (revision 49596)
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.redist.c%
9  *
10  *	@(#)if_we.c	7.1 (Berkeley) 05/09/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 "i386/isa/if_wereg.h"
54 #include "i386/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 	short	we_io_ctl_addr;		/* i/o bus address, control	*/
84 	short	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 	caddr_t	we_vmem_end;		/* receive ring RAM end	*/
90 } we_softc[NWE];
91 
92 int	weprobe(), weattach(), weintr(), westart();
93 int	weinit(), ether_output(), weioctl(), wereset(), wewatchdog();
94 
95 struct	isa_driver wedriver = {
96 	weprobe, weattach, "we",
97 };
98 
99 /*
100  * Probe the WD8003 to see if it's there
101  */
102 weprobe(is)
103 	struct isa_device *is;
104 {
105 	register int i;
106 	register struct we_softc *sc = &we_softc[is->id_unit];
107 	union we_mem_sel wem;
108 	u_char sum;
109 
110 	/*
111 	 * Here we check the card ROM, if the checksum passes, and the
112 	 * type code and ethernet address check out, then we know we have
113 	 * a wd8003 card.
114 	 *
115 	 * Autoconfiguration: No warning message is printed on error.
116 	 */
117 	for (sum = 0, i = 0; i < 8; ++i)
118 	    sum += inb(is->id_iobase + WD_ROM_OFFSET + i);
119 	if (sum != WD_CHECKSUM)
120             return (0);
121 	sc->we_type = inb(is->id_iobase + WD_ROM_OFFSET + 6);
122 	if ((sc->we_type != WD_ETHER) && (sc->we_type != WD_STARLAN)
123 	&& (sc->we_type != WD_ETHER2))
124             return (0);
125 
126 	/*
127 	 * Setup card RAM area and i/o addresses
128 	 * Kernel Virtual to segment C0000-DFFFF?????
129 	 */
130 	sc->we_io_ctl_addr = is->id_iobase;
131 	sc->we_io_nic_addr = sc->we_io_ctl_addr + WD_NIC_OFFSET;
132 	sc->we_vector = is->id_irq;
133 	sc->we_vmem_addr = (caddr_t)is->id_maddr;
134 	sc->we_vmem_size = is->id_msize;
135 	sc->we_vmem_ring = sc->we_vmem_addr + (WD_PAGE_SIZE * WD_TXBUF_SIZE);
136 	sc->we_vmem_end = sc->we_vmem_addr + is->id_msize;
137 
138 	/*
139 	 * Save board ROM station address
140 	 */
141 	for (i = 0; i < ETHER_ADDR_LEN; ++i)
142 	    sc->we_addr[i] = inb(sc->we_io_ctl_addr + WD_ROM_OFFSET + i);
143 
144 	/*
145 	 * Mapin interface memory, setup memory select register
146 	 */
147 	/* wem.ms_addr = (u_long)sc->we_vmem_addr >> 13; */
148 	wem.ms_addr = (u_long)(0xd0000)>> 13;
149 	wem.ms_enable = 1;
150 	wem.ms_reset = 0;
151 	outb(sc->we_io_ctl_addr, wem.ms_byte);
152 
153 	/*
154 	 * clear interface memory, then sum to make sure its valid
155 	 */
156 	for (i = 0; i < sc->we_vmem_size; ++i)
157 	    sc->we_vmem_addr[i] = 0x0;
158 	for (sum = 0, i = 0; i < sc->we_vmem_size; ++i)
159 	    sum += sc->we_vmem_addr[i];
160 	if (sum != 0x0) {
161             printf("we%d: wd8003 dual port RAM address error\n", is->id_unit);
162 	    return (0);
163 	}
164 
165 	return (WD_IO_PORTS);
166 }
167 
168 /*
169  * Interface exists: make available by filling in network interface
170  * record.  System will initialize the interface when it is ready
171  * to accept packets.
172  */
173 weattach(is)
174 	struct isa_device *is;
175 {
176 	register struct we_softc *sc = &we_softc[is->id_unit];
177 	register struct ifnet *ifp = &sc->we_if;
178 	union we_command wecmd;
179 
180 	wecmd.cs_byte = inb(sc->we_io_nic_addr + WD_P0_COMMAND);
181 	wecmd.cs_stp = 1;
182 	wecmd.cs_sta = 0;
183 	wecmd.cs_ps = 0;
184 	outb(sc->we_io_nic_addr + WD_P0_COMMAND, wecmd.cs_byte);
185 	/*
186 	 * Initialize ifnet structure
187 	 */
188 	ifp->if_unit = is->id_unit;
189 	ifp->if_name = "we" ;
190 	ifp->if_mtu = ETHERMTU;
191 	ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_NOTRAILERS ;
192 	ifp->if_init = weinit;
193 	ifp->if_output = ether_output;
194 	ifp->if_start = westart;
195 	ifp->if_ioctl = weioctl;
196 	ifp->if_reset = wereset;
197 	ifp->if_watchdog = wewatchdog;
198 	if_attach(ifp);
199 
200 	/*
201 	 * Banner...
202 	 */
203 	printf(" %s address %s",
204 		((sc->we_type != WD_STARLAN) ? "ethernet" : "starlan"),
205 		ether_sprintf(sc->we_addr));
206 }
207 
208 /*
209  * Reset of interface.
210  */
211 wereset(unit, uban)
212 	int unit, uban;
213 {
214 	if (unit >= NWE)
215 		return;
216 	printf("we%d: reset\n", unit);
217 /*	we_softc[unit].we_flags &= ~WDF_RUNNING; */
218 	weinit(unit);
219 }
220 
221 /*
222  * Take interface offline.
223  */
224 westop(unit)
225 	int unit;
226 {
227 	register struct we_softc *sc = &we_softc[unit];
228 	union we_command wecmd;
229 	int s;
230 
231 	/*
232 	 * Shutdown DS8390
233 	 */
234 	s = splimp();
235 	wecmd.cs_byte = inb(sc->we_io_nic_addr + WD_P0_COMMAND);
236 	wecmd.cs_stp = 1;
237 	wecmd.cs_sta = 0;
238 	wecmd.cs_ps = 0;
239 	outb(sc->we_io_nic_addr + WD_P0_COMMAND, wecmd.cs_byte);
240 	(void) splx(s);
241 }
242 
243 wewatchdog(unit) {
244 
245 	log(LOG_WARNING,"we%d: soft reset\n", unit);
246 printf("we: reset!\n");
247 	westop(unit);
248 DELAY(100000);
249 	weinit(unit);
250 }
251 
252 static Bdry;
253 /*
254  * Initialization of interface (really just DS8390).
255  */
256 weinit(unit)
257 	int unit;
258 {
259 	register struct we_softc *sc = &we_softc[unit];
260 	register struct ifnet *ifp = &sc->we_if;
261 	union we_command wecmd;
262 	int i, s;
263 
264 	/* address not known */
265 	if (ifp->if_addrlist == (struct ifaddr *)0)
266 		return;
267 
268 	/* already running */
269 /*	if (sc->we_flags & WDF_RUNNING)*/
270 	/*if (ifp->if_flags & IFF_RUNNING) return; */
271 
272 	/*
273 	 * Initialize DS8390 in order given in NSC NIC manual.
274 	 * this is stock code...please see the National manual for details.
275 	 */
276 	s = splhigh();
277 Bdry = 0;
278 	wecmd.cs_byte = inb(sc->we_io_nic_addr + WD_P0_COMMAND);
279 	wecmd.cs_stp = 1;
280 	wecmd.cs_sta = 0;
281 	wecmd.cs_ps = 0;
282 	outb(sc->we_io_nic_addr + WD_P0_COMMAND, wecmd.cs_byte);
283 	outb(sc->we_io_nic_addr + WD_P0_DCR, WD_D_CONFIG);
284 	outb(sc->we_io_nic_addr + WD_P0_RBCR0, 0);
285 	outb(sc->we_io_nic_addr + WD_P0_RBCR1, 0);
286 	outb(sc->we_io_nic_addr + WD_P0_RCR, WD_R_MON);
287 	outb(sc->we_io_nic_addr + WD_P0_TCR, WD_T_CONFIG);
288 	outb(sc->we_io_nic_addr + WD_P0_TPSR, 0);
289 	outb(sc->we_io_nic_addr + WD_P0_PSTART, WD_TXBUF_SIZE);
290 	outb(sc->we_io_nic_addr + WD_P0_PSTOP,
291 		sc->we_vmem_size / WD_PAGE_SIZE);
292 	outb(sc->we_io_nic_addr + WD_P0_BNRY, WD_TXBUF_SIZE);
293 	outb(sc->we_io_nic_addr + WD_P0_ISR, 0xff);
294 	outb(sc->we_io_nic_addr + WD_P0_IMR, WD_I_CONFIG);
295 	wecmd.cs_ps = 1;
296 	outb(sc->we_io_nic_addr + WD_P0_COMMAND, wecmd.cs_byte);
297 	for (i = 0; i < ETHER_ADDR_LEN; ++i)
298 	    outb(sc->we_io_nic_addr + WD_P1_PAR0 + i, sc->we_addr[i]);
299 	for (i = 0; i < ETHER_ADDR_LEN; ++i)	/* == broadcast addr */
300 	    outb(sc->we_io_nic_addr + WD_P1_MAR0 + i, 0xff);
301 	outb(sc->we_io_nic_addr + WD_P1_CURR, WD_TXBUF_SIZE);
302 	wecmd.cs_ps = 0;
303 	wecmd.cs_stp = 0;
304 	wecmd.cs_sta = 1;
305 	wecmd.cs_rd = 0x4;
306 	outb(sc->we_io_nic_addr + WD_P1_COMMAND, wecmd.cs_byte);
307 	outb(sc->we_io_nic_addr + WD_P0_RCR, WD_R_CONFIG);
308 
309 	/*
310 	 * Take the interface out of reset, program the vector,
311 	 * enable interrupts, and tell the world we are up.
312 	 */
313 	ifp->if_flags |= IFF_RUNNING;
314 	sc->we_flags &= ~WDF_TXBUSY;
315 	(void) splx(s);
316 	westart(ifp);
317 }
318 
319 /*
320  * Start output on interface.
321  */
322 westart(ifp)
323 	struct ifnet *ifp;
324 {
325 	register struct we_softc *sc = &we_softc[ifp->if_unit];
326 	struct mbuf *m0, *m;
327 	register caddr_t buffer;
328 	int len, s;
329 	union we_command wecmd;
330 
331 	/*
332 	 * The DS8390 has only one transmit buffer, if it is busy we
333 	 * must wait until the transmit interrupt completes.
334 	 */
335 	s = splhigh();
336 	if (sc->we_flags & WDF_TXBUSY) {
337 		(void) splx(s);
338 		return;
339 	}
340 	IF_DEQUEUE(&sc->we_if.if_snd, m);
341 	if (m == 0) {
342 		(void) splx(s);
343 		return;
344 	}
345 	sc->we_flags |= WDF_TXBUSY;
346 	(void) splx(s);
347 
348 	/*
349 	 * Copy the mbuf chain into the transmit buffer
350 	 */
351 	buffer = sc->we_vmem_addr;
352 	len = 0;
353 /*printf("\nT   "); */
354 	for (m0 = m; m != 0; m = m->m_next) {
355 /*int j;*/
356 		bcopy(mtod(m, caddr_t), buffer, m->m_len);
357 /*for(j=0; j < m->m_len;j++) {
358 
359 	puthex(buffer[j]);
360 	if (j == sizeof(struct ether_header)-1)
361 		printf("|");
362 }*/
363 		buffer += m->m_len;
364         	len += m->m_len;
365 	}
366 /*printf("|%d ", len);*/
367 
368 	m_freem(m0);
369 
370 	/*
371 	 * Init transmit length registers, and set transmit start flag.
372 	 */
373 	s = splhigh();
374 	len = MAX(len, ETHER_MIN_LEN);
375 /*printf("L %d ", len);
376 	if (len < 70) len=70;*/
377 	wecmd.cs_byte = inb(sc->we_io_nic_addr + WD_P0_COMMAND);
378 	wecmd.cs_ps = 0;
379 	outb(sc->we_io_nic_addr + WD_P0_COMMAND, wecmd.cs_byte);
380 	outb(sc->we_io_nic_addr + WD_P0_TBCR0, len & 0xff);
381 	outb(sc->we_io_nic_addr + WD_P0_TBCR1, len >> 8);
382 	wecmd.cs_txp = 1;
383 	outb(sc->we_io_nic_addr + WD_P0_COMMAND, wecmd.cs_byte);
384 	(void) splx(s);
385 }
386 
387 /*
388  * Ethernet interface interrupt processor
389  */
390 weintr(unit)
391 	int unit;
392 {
393 	register struct we_softc *sc = &we_softc[unit];
394 	union we_command wecmd;
395 	union we_interrupt weisr;
396 
397 	unit =0;
398 
399 	/* disable onboard interrupts, then get interrupt status */
400 	wecmd.cs_byte = inb(sc->we_io_nic_addr + WD_P0_COMMAND);
401 	wecmd.cs_ps = 0;
402 	outb(sc->we_io_nic_addr + WD_P0_COMMAND, wecmd.cs_byte);
403 	/*outb(sc->we_io_nic_addr + WD_P0_IMR, 0);*/
404 	weisr.is_byte = inb(sc->we_io_nic_addr + WD_P0_ISR);
405 loop:
406 	outb(sc->we_io_nic_addr + WD_P0_ISR, weisr.is_byte);
407 
408 	/* transmit error */
409 	if (weisr.is_txe) {
410 		/* need to read these registers to clear status */
411 		sc->we_if.if_collisions +=
412 		    inb(sc->we_io_nic_addr + WD_P0_TBCR0);
413 		++sc->we_if.if_oerrors;
414 	}
415 
416 	/* receiver error */
417 	if (weisr.is_rxe) {
418 		/* need to read these registers to clear status */
419 		(void) inb(sc->we_io_nic_addr + 0xD);
420 		(void) inb(sc->we_io_nic_addr + 0xE);
421 		(void) inb(sc->we_io_nic_addr + 0xF);
422 		++sc->we_if.if_ierrors;
423 	}
424 
425 	/* normal transmit complete */
426 	if (weisr.is_ptx || weisr.is_txe)
427 		wetint (unit);
428 
429 	/* normal receive notification */
430 	if (weisr.is_prx || weisr.is_rxe)
431 		werint (unit);
432 
433 	/* try to start transmit */
434 	westart(&sc->we_if);
435 
436 	/* re-enable onboard interrupts */
437 	wecmd.cs_byte = inb(sc->we_io_nic_addr + WD_P0_COMMAND);
438 	wecmd.cs_ps = 0;
439 	outb(sc->we_io_nic_addr + WD_P0_COMMAND, wecmd.cs_byte);
440 	outb(sc->we_io_nic_addr + WD_P0_IMR, 0xff/*WD_I_CONFIG*/);
441 	weisr.is_byte = inb(sc->we_io_nic_addr + WD_P0_ISR);
442 	if (weisr.is_byte) goto loop;
443 }
444 
445 /*
446  * Ethernet interface transmit interrupt.
447  */
448 wetint(unit)
449 	int unit;
450 {
451 	register struct we_softc *sc = &we_softc[unit];
452 
453 	/*
454 	 * Do some statistics (assume page zero of NIC mapped in)
455 	 */
456 	sc->we_flags &= ~WDF_TXBUSY;
457 	sc->we_if.if_timer = 0;
458 	++sc->we_if.if_opackets;
459 	sc->we_if.if_collisions += inb(sc->we_io_nic_addr + WD_P0_TBCR0);
460 }
461 
462 /*
463  * Ethernet interface receiver interrupt.
464  */
465 werint(unit)
466 	int unit;
467 {
468 	register struct we_softc *sc = &we_softc[unit];
469 	u_char bnry, curr;
470 	long len;
471 	union we_command wecmd;
472 	struct we_ring *wer;
473 
474 	/*
475 	 * Traverse the receive ring looking for packets to pass back.
476 	 * The search is complete when we find a descriptor not in use.
477 	 */
478 	wecmd.cs_byte = inb(sc->we_io_nic_addr + WD_P0_COMMAND);
479 	wecmd.cs_ps = 0;
480 	outb(sc->we_io_nic_addr + WD_P0_COMMAND, wecmd.cs_byte);
481 	bnry = inb(sc->we_io_nic_addr + WD_P0_BNRY);
482 	wecmd.cs_ps = 1;
483 	outb(sc->we_io_nic_addr + WD_P0_COMMAND, wecmd.cs_byte);
484 	curr = inb(sc->we_io_nic_addr + WD_P1_CURR);
485 if(Bdry)
486 	bnry =Bdry;
487 
488 /*printf("B %d c %d ", bnry, curr);*/
489 	while (bnry != curr)
490 	{
491 		/* get pointer to this buffer header structure */
492 		wer = (struct we_ring *)(sc->we_vmem_addr + (bnry << 8));
493 
494 		/* count includes CRC */
495 		len = wer->we_count - 4;
496 		if (len > 30 && len <= ETHERMTU+100
497 			/*&& (*(char *)wer  == 1 || *(char *) wer == 0x21)*/)
498 			weread(sc, (caddr_t)(wer + 1), len);
499 		else printf("reject %d", len);
500 
501 outofbufs:
502 		wecmd.cs_byte = inb(sc->we_io_nic_addr + WD_P0_COMMAND);
503 		wecmd.cs_ps = 0;
504 		outb(sc->we_io_nic_addr + WD_P0_COMMAND, wecmd.cs_byte);
505 
506 		/* advance on chip Boundry register */
507 		if((caddr_t) wer + WD_PAGE_SIZE - 1 > sc->we_vmem_end) {
508 			bnry = WD_TXBUF_SIZE;
509 			outb(sc->we_io_nic_addr + WD_P0_BNRY,
510 					sc->we_vmem_size / WD_PAGE_SIZE-1);
511 
512 		} else {
513 			if (len > 30 && len <= ETHERMTU+100)
514 				bnry = wer->we_next_packet;
515 			else bnry = curr;
516 
517 			/* watch out for NIC overflow, reset Boundry if invalid */
518 			if ((bnry - 1) < WD_TXBUF_SIZE) {
519 		    		outb(sc->we_io_nic_addr + WD_P0_BNRY,
520 					(sc->we_vmem_size / WD_PAGE_SIZE) - 1);
521 				bnry = WD_TXBUF_SIZE;
522 			} else
523 				outb(sc->we_io_nic_addr + WD_P0_BNRY, bnry-1);
524 		}
525 
526 		/* refresh our copy of CURR */
527 		wecmd.cs_ps = 1;
528 		outb(sc->we_io_nic_addr + WD_P0_COMMAND, wecmd.cs_byte);
529 		curr = inb(sc->we_io_nic_addr + WD_P1_CURR);
530 /*printf("b %d c %d ", bnry, curr); */
531 	}
532 Bdry = bnry;
533 }
534 
535 #ifdef shit
536 /*
537  * Process an ioctl request.
538  */
539 weioctl(ifp, cmd, data)
540 	register struct ifnet *ifp;
541 	int cmd;
542 	caddr_t data;
543 {
544 	struct we_softc *sc = &we_softc[ifp->if_unit];
545 	struct ifaddr *ifa = (struct ifaddr *)data;
546 	int s = splimp(), error = 0;
547 
548 	switch (cmd) {
549 
550 	case SIOCSIFADDR:
551 		ifp->if_flags |= IFF_UP;
552 		weinit(ifp->if_unit);
553 		switch(ifa->ifa_addr->sa_family) {
554 #ifdef INET
555 		case AF_INET:
556 			((struct arpcom *)ifp)->ac_ipaddr =
557 				IA_SIN(ifa)->sin_addr;
558 			arpwhohas((struct arpcom *)ifp, &IA_SIN(ifa)->sin_addr);
559 			break;
560 #endif
561 #ifdef NS
562 		case AF_NS:
563 		    {
564 			register struct ns_addr *ina = &(IA_SNS(ifa)->sns_addr);
565 
566 			if (ns_nullhost(*ina))
567 				ina->x_host = *(union ns_host *)(sc->we_addr);
568 			else
569 				wesetaddr(ina->x_host.c_host, ifp->if_unit);
570 			break;
571 		    }
572 #endif
573 		}
574 		break;
575 
576 	case SIOCSIFFLAGS:
577 		if (((ifp->if_flags & IFF_UP) == 0) &&
578 		   (sc->we_flags & WDF_RUNNING)) {
579 			westop(ifp->if_unit);
580 		} else if (((ifp->if_flags & IFF_UP) == IFF_UP) &&
581 		   ((sc->we_flags & WDF_RUNNING) == 0))
582 			weinit(ifp->if_unit);
583 		break;
584 
585 	default:
586 		error = EINVAL;
587 
588 	}
589 	(void) splx(s);
590 	return (error);
591 }
592 #endif
593 
594 /*
595  * Process an ioctl request.
596  */
597 weioctl(ifp, cmd, data)
598 	register struct ifnet *ifp;
599 	int cmd;
600 	caddr_t data;
601 {
602 	register struct ifaddr *ifa = (struct ifaddr *)data;
603 	struct we_softc *sc = &we_softc[ifp->if_unit];
604 	struct ifreq *ifr = (struct ifreq *)data;
605 	int s = splimp(), error = 0;
606 
607 
608 	switch (cmd) {
609 
610 	case SIOCSIFADDR:
611 		ifp->if_flags |= IFF_UP;
612 
613 		switch (ifa->ifa_addr->sa_family) {
614 #ifdef INET
615 		case AF_INET:
616 			weinit(ifp->if_unit);	/* before arpwhohas */
617 			((struct arpcom *)ifp)->ac_ipaddr =
618 				IA_SIN(ifa)->sin_addr;
619 			arpwhohas((struct arpcom *)ifp, &IA_SIN(ifa)->sin_addr);
620 			break;
621 #endif
622 #ifdef NS
623 		case AF_NS:
624 		    {
625 			register struct ns_addr *ina = &(IA_SNS(ifa)->sns_addr);
626 
627 			if (ns_nullhost(*ina))
628 				ina->x_host = *(union ns_host *)(sc->ns_addr);
629 			else {
630 				/*
631 				 * The manual says we can't change the address
632 				 * while the receiver is armed,
633 				 * so reset everything
634 				 */
635 				ifp->if_flags &= ~IFF_RUNNING;
636 				bcopy((caddr_t)ina->x_host.c_host,
637 				    (caddr_t)sc->ns_addr, sizeof(sc->ns_addr));
638 			}
639 			weinit(ifp->if_unit); /* does ne_setaddr() */
640 			break;
641 		    }
642 #endif
643 		default:
644 			weinit(ifp->if_unit);
645 			break;
646 		}
647 		break;
648 
649 	case SIOCSIFFLAGS:
650 		if ((ifp->if_flags & IFF_UP) == 0 &&
651 		    ifp->if_flags & IFF_RUNNING) {
652 			ifp->if_flags &= ~IFF_RUNNING;
653 			westop(ifp->if_unit);
654 		} else if (ifp->if_flags & IFF_UP &&
655 		    (ifp->if_flags & IFF_RUNNING) == 0)
656 			weinit(ifp->if_unit);
657 		break;
658 
659 #ifdef notdef
660 	case SIOCGHWADDR:
661 		bcopy((caddr_t)sc->sc_addr, (caddr_t) &ifr->ifr_data,
662 			sizeof(sc->sc_addr));
663 		break;
664 #endif
665 
666 	default:
667 		error = EINVAL;
668 	}
669 	splx(s);
670 	return (error);
671 }
672 /*
673  * set ethernet address for unit
674  */
675 wesetaddr(physaddr, unit)
676 	u_char *physaddr;
677 	int unit;
678 {
679 	register struct we_softc *sc = &we_softc[unit];
680 	register int i;
681 
682 	/*
683 	 * Rewrite ethernet address, and then force restart of NIC
684 	 */
685 	for (i = 0; i < ETHER_ADDR_LEN; i++)
686 		sc->we_addr[i] = physaddr[i];
687 	sc->we_flags &= ~WDF_RUNNING;
688 	weinit(unit);
689 }
690 
691 #define	wedataaddr(sc, eh, off, type) \
692 	((type) ((caddr_t)((eh)+1)+(off) >= (sc)->we_vmem_end) ? \
693 		(((caddr_t)((eh)+1)+(off))) - (sc)->we_vmem_end \
694 		+ (sc)->we_vmem_ring: \
695 		((caddr_t)((eh)+1)+(off)))
696 /*
697  * Pass a packet to the higher levels.
698  * We deal with the trailer protocol here.
699  */
700 weread(sc, buf, len)
701 	register struct we_softc *sc;
702 	char *buf;
703 	int len;
704 {
705 	register struct ether_header *eh;
706     	struct mbuf *m, *weget();
707 	int off, resid;
708 
709 	/*
710 	 * Deal with trailer protocol: if type is trailer type
711 	 * get true type from first 16-bit word past data.
712 	 * Remember that type was trailer by setting off.
713 	 */
714 	eh = (struct ether_header *)buf;
715 	eh->ether_type = ntohs((u_short)eh->ether_type);
716 	if (eh->ether_type >= ETHERTYPE_TRAIL &&
717 	    eh->ether_type < ETHERTYPE_TRAIL+ETHERTYPE_NTRAILER) {
718 		off = (eh->ether_type - ETHERTYPE_TRAIL) * 512;
719 		if (off >= ETHERMTU) return;		/* sanity */
720 		eh->ether_type = ntohs(*wedataaddr(sc, eh, off, u_short *));
721 		resid = ntohs(*(wedataaddr(sc, eh, off+2, u_short *)));
722 		if (off + resid > len) return;		/* sanity */
723 		len = off + resid;
724 	} else	off = 0;
725 
726 	len -= sizeof(struct ether_header);
727 	if (len <= 0) return;
728 
729 	/*
730 	 * Pull packet off interface.  Off is nonzero if packet
731 	 * has trailing header; neget will then force this header
732 	 * information to be at the front, but we still have to drop
733 	 * the type and length which are at the front of any trailer data.
734 	 */
735 	m = weget(buf, len, off, &sc->we_if, sc);
736 	if (m == 0) return;
737 	ether_input(&sc->we_if, eh, m);
738 }
739 
740 /*
741  * Supporting routines
742  */
743 
744 /*
745  * Pull read data off a interface.
746  * Len is length of data, with local net header stripped.
747  * Off is non-zero if a trailer protocol was used, and
748  * gives the offset of the trailer information.
749  * We copy the trailer information and then all the normal
750  * data into mbufs.  When full cluster sized units are present
751  * we copy into clusters.
752  */
753 struct mbuf *
754 weget(buf, totlen, off0, ifp, sc)
755 	caddr_t buf;
756 	int totlen, off0;
757 	struct ifnet *ifp;
758 	struct we_softc *sc;
759 {
760 	struct mbuf *top, **mp, *m, *p;
761 	int off = off0, len;
762 	register caddr_t cp = buf;
763 	char *epkt;
764 int tc =totlen;
765 
766 /*
767 printf("\nR");
768 { int j;
769 for(j=0; j < sizeof(struct ether_header);j++) puthex(buf[j]);
770 printf("|");
771 }*/
772 	buf += sizeof(struct ether_header);
773 	cp = buf;
774 	epkt = cp + totlen;
775 
776 	if (off) {
777 		cp += off + 2 * sizeof(u_short);
778 		totlen -= 2 * sizeof(u_short);
779 	}
780 
781 	MGETHDR(m, M_DONTWAIT, MT_DATA);
782 	if (m == 0)
783 		return (0);
784 	m->m_pkthdr.rcvif = ifp;
785 	m->m_pkthdr.len = totlen;
786 	m->m_len = MHLEN;
787 
788 	top = 0;
789 	mp = &top;
790 	while (totlen > 0) {
791 		if (top) {
792 			MGET(m, M_DONTWAIT, MT_DATA);
793 			if (m == 0) {
794 				m_freem(top);
795 				return (0);
796 			}
797 			m->m_len = MLEN;
798 		}
799 		len = min(totlen, epkt - cp);
800 #ifdef nope
801 		/* only do up to end of buffer */
802 		if (epkt > sc->we_vmem_end)
803 			len = min(len, sc->we_vmem_end - cp);
804 #endif
805 		if (len >= MINCLSIZE) {
806 			MCLGET(m, M_DONTWAIT);
807 			if (m->m_flags & M_EXT)
808 				m->m_len = len = min(len, MCLBYTES);
809 			else
810 				len = m->m_len;
811 		} else {
812 			/*
813 			 * Place initial small packet/header at end of mbuf.
814 			 */
815 			if (len < m->m_len) {
816 				if (top == 0 && len + max_linkhdr <= m->m_len)
817 					m->m_data += max_linkhdr;
818 				m->m_len = len;
819 			} else
820 				len = m->m_len;
821 		}
822 
823 		totlen -= len;
824 		/* only do up to end of buffer */
825 		if (cp+len > sc->we_vmem_end) {
826 			unsigned toend = sc->we_vmem_end - cp;
827 
828 			bcopy(cp, mtod(m, caddr_t), toend);
829 			cp = sc->we_vmem_ring;
830 			bcopy(cp, mtod(m, caddr_t)+toend, len - toend);
831 			cp += len - toend;
832 			epkt = cp + totlen;
833 		} else {
834 			bcopy(cp, mtod(m, caddr_t), (unsigned)len);
835 			cp += len;
836 		}
837 /*{ int j;
838 for(j=0; j < m->m_len;j++) puthex(mtod(m, char *)[j]);
839 printf("|");
840 }*/
841 		*mp = m;
842 		mp = &m->m_next;
843 		if (cp == epkt) {
844 			cp = buf;
845 			epkt = cp + tc;
846 		}
847 	}
848 /*printf("%d ",tc); */
849 	return (top);
850 }
851 
852 puthex(c){
853 	printf("%x",(c>>4)&0xf);
854 	printf("%x",c&0xf);
855 }
856 #endif
857