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