1 /*-
2 * Copyright (c) 1990, 1993
3 * The Regents of the University of California. 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 8.1 (Berkeley) 06/11/93
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 <sys/param.h>
31 #include <sys/mbuf.h>
32 #include <sys/socket.h>
33 #include <sys/ioctl.h>
34 #include <sys/errno.h>
35 #include <sys/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 */
wereset(unit,uban)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 */
westop(unit)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
wewatchdog(unit)243 wewatchdog(unit) {
244
245 log(LOG_WARNING,"we%d: soft reset\n", unit);
246 westop(unit);
247 weinit(unit);
248 }
249
250 static Bdry;
251 /*
252 * Initialization of interface (really just DS8390).
253 */
weinit(unit)254 weinit(unit)
255 int unit;
256 {
257 register struct we_softc *sc = &we_softc[unit];
258 register struct ifnet *ifp = &sc->we_if;
259 union we_command wecmd;
260 int i, s;
261
262 /* address not known */
263 if (ifp->if_addrlist == (struct ifaddr *)0)
264 return;
265
266 /* already running */
267 /*if (ifp->if_flags & IFF_RUNNING) return; */
268
269 /*
270 * Initialize DS8390 in order given in NSC NIC manual.
271 * this is stock code...please see the National manual for details.
272 */
273 s = splhigh();
274 Bdry = 0;
275 wecmd.cs_byte = inb(sc->we_io_nic_addr + WD_P0_COMMAND);
276 wecmd.cs_stp = 1;
277 wecmd.cs_sta = 0;
278 wecmd.cs_ps = 0;
279 outb(sc->we_io_nic_addr + WD_P0_COMMAND, wecmd.cs_byte);
280 outb(sc->we_io_nic_addr + WD_P0_DCR, WD_D_CONFIG);
281 outb(sc->we_io_nic_addr + WD_P0_RBCR0, 0);
282 outb(sc->we_io_nic_addr + WD_P0_RBCR1, 0);
283 outb(sc->we_io_nic_addr + WD_P0_RCR, WD_R_MON);
284 outb(sc->we_io_nic_addr + WD_P0_TCR, WD_T_CONFIG);
285 outb(sc->we_io_nic_addr + WD_P0_TPSR, 0);
286 outb(sc->we_io_nic_addr + WD_P0_PSTART, WD_TXBUF_SIZE);
287 outb(sc->we_io_nic_addr + WD_P0_PSTOP,
288 sc->we_vmem_size / WD_PAGE_SIZE);
289 outb(sc->we_io_nic_addr + WD_P0_BNRY, WD_TXBUF_SIZE);
290 outb(sc->we_io_nic_addr + WD_P0_ISR, 0xff);
291 outb(sc->we_io_nic_addr + WD_P0_IMR, WD_I_CONFIG);
292 wecmd.cs_ps = 1;
293 outb(sc->we_io_nic_addr + WD_P0_COMMAND, wecmd.cs_byte);
294 for (i = 0; i < ETHER_ADDR_LEN; ++i)
295 outb(sc->we_io_nic_addr + WD_P1_PAR0 + i, sc->we_addr[i]);
296 for (i = 0; i < ETHER_ADDR_LEN; ++i) /* == broadcast addr */
297 outb(sc->we_io_nic_addr + WD_P1_MAR0 + i, 0xff);
298 outb(sc->we_io_nic_addr + WD_P1_CURR, WD_TXBUF_SIZE);
299 wecmd.cs_ps = 0;
300 wecmd.cs_stp = 0;
301 wecmd.cs_sta = 1;
302 wecmd.cs_rd = 0x4;
303 outb(sc->we_io_nic_addr + WD_P1_COMMAND, wecmd.cs_byte);
304 outb(sc->we_io_nic_addr + WD_P0_RCR, WD_R_CONFIG);
305
306 /*
307 * Take the interface out of reset, program the vector,
308 * enable interrupts, and tell the world we are up.
309 */
310 ifp->if_flags |= IFF_RUNNING;
311 sc->we_flags &= ~WDF_TXBUSY;
312 (void) splx(s);
313 westart(ifp);
314 }
315
316 /*
317 * Start output on interface.
318 */
319 westart(ifp)
320 struct ifnet *ifp;
321 {
322 register struct we_softc *sc = &we_softc[ifp->if_unit];
323 struct mbuf *m0, *m;
324 register caddr_t buffer;
325 int len, s;
326 union we_command wecmd;
327
328 /*
329 * The DS8390 has only one transmit buffer, if it is busy we
330 * must wait until the transmit interrupt completes.
331 */
332 s = splhigh();
333 if (sc->we_flags & WDF_TXBUSY) {
334 (void) splx(s);
335 return;
336 }
337 IF_DEQUEUE(&sc->we_if.if_snd, m);
338 if (m == 0) {
339 (void) splx(s);
340 return;
341 }
342 sc->we_flags |= WDF_TXBUSY;
343 (void) splx(s);
344
345 /*
346 * Copy the mbuf chain into the transmit buffer
347 */
348 buffer = sc->we_vmem_addr;
349 len = 0;
350 for (m0 = m; m != 0; m = m->m_next) {
351 bcopy(mtod(m, caddr_t), buffer, m->m_len);
352 buffer += m->m_len;
353 len += m->m_len;
354 }
355
356 m_freem(m0);
357
358 /*
359 * Init transmit length registers, and set transmit start flag.
360 */
361 s = splhigh();
362 len = MAX(len, ETHER_MIN_LEN);
363 wecmd.cs_byte = inb(sc->we_io_nic_addr + WD_P0_COMMAND);
364 wecmd.cs_ps = 0;
365 outb(sc->we_io_nic_addr + WD_P0_COMMAND, wecmd.cs_byte);
366 outb(sc->we_io_nic_addr + WD_P0_TBCR0, len & 0xff);
367 outb(sc->we_io_nic_addr + WD_P0_TBCR1, len >> 8);
368 wecmd.cs_txp = 1;
369 outb(sc->we_io_nic_addr + WD_P0_COMMAND, wecmd.cs_byte);
370 (void) splx(s);
371 }
372
373 /*
374 * Ethernet interface interrupt processor
375 */
weintr(unit)376 weintr(unit)
377 int unit;
378 {
379 register struct we_softc *sc = &we_softc[unit];
380 union we_command wecmd;
381 union we_interrupt weisr;
382 int nloops = 10;
383
384 unit =0;
385
386 /* disable onboard interrupts, then get interrupt status */
387 wecmd.cs_byte = inb(sc->we_io_nic_addr + WD_P0_COMMAND);
388 wecmd.cs_ps = 0;
389 outb(sc->we_io_nic_addr + WD_P0_COMMAND, wecmd.cs_byte);
390 weisr.is_byte = inb(sc->we_io_nic_addr + WD_P0_ISR);
391 loop:
392 outb(sc->we_io_nic_addr + WD_P0_ISR, weisr.is_byte);
393
394 /* transmit error */
395 if (weisr.is_txe) {
396 /* need to read these registers to clear status */
397 sc->we_if.if_collisions +=
398 inb(sc->we_io_nic_addr + WD_P0_TBCR0);
399 ++sc->we_if.if_oerrors;
400 }
401
402 /* receiver error */
403 if (weisr.is_rxe) {
404 /* need to read these registers to clear status */
405 (void) inb(sc->we_io_nic_addr + 0xD);
406 (void) inb(sc->we_io_nic_addr + 0xE);
407 (void) inb(sc->we_io_nic_addr + 0xF);
408 ++sc->we_if.if_ierrors;
409 }
410
411 /* normal transmit complete */
412 if (weisr.is_ptx || weisr.is_txe)
413 wetint (unit);
414
415 /* normal receive notification */
416 if (weisr.is_prx || weisr.is_rxe)
417 werint (unit);
418
419 /* try to start transmit */
420 westart(&sc->we_if);
421
422 /* re-enable onboard interrupts */
423 wecmd.cs_byte = inb(sc->we_io_nic_addr + WD_P0_COMMAND);
424 wecmd.cs_ps = 0;
425 outb(sc->we_io_nic_addr + WD_P0_COMMAND, wecmd.cs_byte);
426 outb(sc->we_io_nic_addr + WD_P0_IMR, 0xff/*WD_I_CONFIG*/);
427 weisr.is_byte = inb(sc->we_io_nic_addr + WD_P0_ISR);
428 if (weisr.is_byte) {
429 /*
430 * I caught it looping forever here a couple of times,
431 * but I haven't had time to figure out why. Just
432 * returning seems to be safe, and it does not appear
433 * to interfere with future packets. - Pace 5/19/92
434 */
435 if (--nloops <= 0) {
436 printf ("we0: weintr is looping\n");
437 return;
438 }
439 goto loop;
440 }
441 }
442
443 /*
444 * Ethernet interface transmit interrupt.
445 */
wetint(unit)446 wetint(unit)
447 int unit;
448 {
449 register struct we_softc *sc = &we_softc[unit];
450
451 /*
452 * Do some statistics (assume page zero of NIC mapped in)
453 */
454 sc->we_flags &= ~WDF_TXBUSY;
455 sc->we_if.if_timer = 0;
456 ++sc->we_if.if_opackets;
457 sc->we_if.if_collisions += inb(sc->we_io_nic_addr + WD_P0_TBCR0);
458 }
459
460 /*
461 * Ethernet interface receiver interrupt.
462 */
werint(unit)463 werint(unit)
464 int unit;
465 {
466 register struct we_softc *sc = &we_softc[unit];
467 u_char bnry, curr;
468 long len;
469 union we_command wecmd;
470 struct we_ring *wer;
471
472 /*
473 * Traverse the receive ring looking for packets to pass back.
474 * The search is complete when we find a descriptor not in use.
475 */
476 wecmd.cs_byte = inb(sc->we_io_nic_addr + WD_P0_COMMAND);
477 wecmd.cs_ps = 0;
478 outb(sc->we_io_nic_addr + WD_P0_COMMAND, wecmd.cs_byte);
479 bnry = inb(sc->we_io_nic_addr + WD_P0_BNRY);
480 wecmd.cs_ps = 1;
481 outb(sc->we_io_nic_addr + WD_P0_COMMAND, wecmd.cs_byte);
482 curr = inb(sc->we_io_nic_addr + WD_P1_CURR);
483 if(Bdry)
484 bnry =Bdry;
485
486 while (bnry != curr)
487 {
488 /* get pointer to this buffer header structure */
489 wer = (struct we_ring *)(sc->we_vmem_addr + (bnry << 8));
490
491 /* count includes CRC */
492 len = wer->we_count - 4;
493 if (len > 30 && len <= ETHERMTU+100
494 /*&& (*(char *)wer == 1 || *(char *) wer == 0x21)*/)
495 weread(sc, (caddr_t)(wer + 1), len);
496 else printf("reject %d", len);
497
498 outofbufs:
499 wecmd.cs_byte = inb(sc->we_io_nic_addr + WD_P0_COMMAND);
500 wecmd.cs_ps = 0;
501 outb(sc->we_io_nic_addr + WD_P0_COMMAND, wecmd.cs_byte);
502
503 /* advance on chip Boundry register */
504 if((caddr_t) wer + WD_PAGE_SIZE - 1 > sc->we_vmem_end) {
505 bnry = WD_TXBUF_SIZE;
506 outb(sc->we_io_nic_addr + WD_P0_BNRY,
507 sc->we_vmem_size / WD_PAGE_SIZE-1);
508
509 } else {
510 if (len > 30 && len <= ETHERMTU+100)
511 bnry = wer->we_next_packet;
512 else bnry = curr;
513
514 /* watch out for NIC overflow, reset Boundry if invalid */
515 if ((bnry - 1) < WD_TXBUF_SIZE) {
516 outb(sc->we_io_nic_addr + WD_P0_BNRY,
517 (sc->we_vmem_size / WD_PAGE_SIZE) - 1);
518 bnry = WD_TXBUF_SIZE;
519 } else
520 outb(sc->we_io_nic_addr + WD_P0_BNRY, bnry-1);
521 }
522
523 /* refresh our copy of CURR */
524 wecmd.cs_ps = 1;
525 outb(sc->we_io_nic_addr + WD_P0_COMMAND, wecmd.cs_byte);
526 curr = inb(sc->we_io_nic_addr + WD_P1_CURR);
527 }
528 Bdry = bnry;
529 }
530
531 #ifdef shit
532 /*
533 * Process an ioctl request.
534 */
weioctl(ifp,cmd,data)535 weioctl(ifp, cmd, data)
536 register struct ifnet *ifp;
537 int cmd;
538 caddr_t data;
539 {
540 struct we_softc *sc = &we_softc[ifp->if_unit];
541 struct ifaddr *ifa = (struct ifaddr *)data;
542 int s = splimp(), error = 0;
543
544 switch (cmd) {
545
546 case SIOCSIFADDR:
547 ifp->if_flags |= IFF_UP;
548 weinit(ifp->if_unit);
549 switch(ifa->ifa_addr->sa_family) {
550 #ifdef INET
551 case AF_INET:
552 ((struct arpcom *)ifp)->ac_ipaddr =
553 IA_SIN(ifa)->sin_addr;
554 arpwhohas((struct arpcom *)ifp, &IA_SIN(ifa)->sin_addr);
555 break;
556 #endif
557 #ifdef NS
558 case AF_NS:
559 {
560 register struct ns_addr *ina = &(IA_SNS(ifa)->sns_addr);
561
562 if (ns_nullhost(*ina))
563 ina->x_host = *(union ns_host *)(sc->we_addr);
564 else
565 wesetaddr(ina->x_host.c_host, ifp->if_unit);
566 break;
567 }
568 #endif
569 }
570 break;
571
572 case SIOCSIFFLAGS:
573 if (((ifp->if_flags & IFF_UP) == 0) &&
574 (sc->we_flags & WDF_RUNNING)) {
575 westop(ifp->if_unit);
576 } else if (((ifp->if_flags & IFF_UP) == IFF_UP) &&
577 ((sc->we_flags & WDF_RUNNING) == 0))
578 weinit(ifp->if_unit);
579 break;
580
581 default:
582 error = EINVAL;
583
584 }
585 (void) splx(s);
586 return (error);
587 }
588 #endif
589
590 /*
591 * Process an ioctl request.
592 */
weioctl(ifp,cmd,data)593 weioctl(ifp, cmd, data)
594 register struct ifnet *ifp;
595 int cmd;
596 caddr_t data;
597 {
598 register struct ifaddr *ifa = (struct ifaddr *)data;
599 struct we_softc *sc = &we_softc[ifp->if_unit];
600 struct ifreq *ifr = (struct ifreq *)data;
601 int s = splimp(), error = 0;
602
603
604 switch (cmd) {
605
606 case SIOCSIFADDR:
607 ifp->if_flags |= IFF_UP;
608
609 switch (ifa->ifa_addr->sa_family) {
610 #ifdef INET
611 case AF_INET:
612 weinit(ifp->if_unit); /* before arpwhohas */
613 ((struct arpcom *)ifp)->ac_ipaddr =
614 IA_SIN(ifa)->sin_addr;
615 arpwhohas((struct arpcom *)ifp, &IA_SIN(ifa)->sin_addr);
616 break;
617 #endif
618 #ifdef NS
619 case AF_NS:
620 {
621 register struct ns_addr *ina = &(IA_SNS(ifa)->sns_addr);
622
623 if (ns_nullhost(*ina))
624 ina->x_host = *(union ns_host *)(sc->ns_addr);
625 else {
626 /*
627 * The manual says we can't change the address
628 * while the receiver is armed,
629 * so reset everything
630 */
631 ifp->if_flags &= ~IFF_RUNNING;
632 bcopy((caddr_t)ina->x_host.c_host,
633 (caddr_t)sc->ns_addr, sizeof(sc->ns_addr));
634 }
635 weinit(ifp->if_unit); /* does ne_setaddr() */
636 break;
637 }
638 #endif
639 default:
640 weinit(ifp->if_unit);
641 break;
642 }
643 break;
644
645 case SIOCSIFFLAGS:
646 if ((ifp->if_flags & IFF_UP) == 0 &&
647 ifp->if_flags & IFF_RUNNING) {
648 ifp->if_flags &= ~IFF_RUNNING;
649 westop(ifp->if_unit);
650 } else if (ifp->if_flags & IFF_UP &&
651 (ifp->if_flags & IFF_RUNNING) == 0)
652 weinit(ifp->if_unit);
653 break;
654
655 #ifdef notdef
656 case SIOCGHWADDR:
657 bcopy((caddr_t)sc->sc_addr, (caddr_t) &ifr->ifr_data,
658 sizeof(sc->sc_addr));
659 break;
660 #endif
661
662 default:
663 error = EINVAL;
664 }
665 splx(s);
666 return (error);
667 }
668 /*
669 * set ethernet address for unit
670 */
wesetaddr(physaddr,unit)671 wesetaddr(physaddr, unit)
672 u_char *physaddr;
673 int unit;
674 {
675 register struct we_softc *sc = &we_softc[unit];
676 register int i;
677
678 /*
679 * Rewrite ethernet address, and then force restart of NIC
680 */
681 for (i = 0; i < ETHER_ADDR_LEN; i++)
682 sc->we_addr[i] = physaddr[i];
683 sc->we_flags &= ~WDF_RUNNING;
684 weinit(unit);
685 }
686
687 #define wedataaddr(sc, eh, off, type) \
688 ((type) ((caddr_t)((eh)+1)+(off) >= (sc)->we_vmem_end) ? \
689 (((caddr_t)((eh)+1)+(off))) - (sc)->we_vmem_end \
690 + (sc)->we_vmem_ring: \
691 ((caddr_t)((eh)+1)+(off)))
692 /*
693 * Pass a packet to the higher levels.
694 * We deal with the trailer protocol here.
695 */
weread(sc,buf,len)696 weread(sc, buf, len)
697 register struct we_softc *sc;
698 char *buf;
699 int len;
700 {
701 register struct ether_header *eh;
702 struct mbuf *m, *weget();
703 int off, resid;
704
705 /*
706 * Deal with trailer protocol: if type is trailer type
707 * get true type from first 16-bit word past data.
708 * Remember that type was trailer by setting off.
709 */
710 eh = (struct ether_header *)buf;
711 eh->ether_type = ntohs((u_short)eh->ether_type);
712 if (eh->ether_type >= ETHERTYPE_TRAIL &&
713 eh->ether_type < ETHERTYPE_TRAIL+ETHERTYPE_NTRAILER) {
714 off = (eh->ether_type - ETHERTYPE_TRAIL) * 512;
715 if (off >= ETHERMTU) return; /* sanity */
716 eh->ether_type = ntohs(*wedataaddr(sc, eh, off, u_short *));
717 resid = ntohs(*(wedataaddr(sc, eh, off+2, u_short *)));
718 if (off + resid > len) return; /* sanity */
719 len = off + resid;
720 } else off = 0;
721
722 len -= sizeof(struct ether_header);
723 if (len <= 0) return;
724
725 /*
726 * Pull packet off interface. Off is nonzero if packet
727 * has trailing header; neget will then force this header
728 * information to be at the front, but we still have to drop
729 * the type and length which are at the front of any trailer data.
730 */
731 m = weget(buf, len, off, &sc->we_if, sc);
732 if (m == 0) return;
733 ether_input(&sc->we_if, eh, m);
734 }
735
736 /*
737 * Supporting routines
738 */
739
740 /*
741 * Pull read data off a interface.
742 * Len is length of data, with local net header stripped.
743 * Off is non-zero if a trailer protocol was used, and
744 * gives the offset of the trailer information.
745 * We copy the trailer information and then all the normal
746 * data into mbufs. When full cluster sized units are present
747 * we copy into clusters.
748 */
749 struct mbuf *
weget(buf,totlen,off0,ifp,sc)750 weget(buf, totlen, off0, ifp, sc)
751 caddr_t buf;
752 int totlen, off0;
753 struct ifnet *ifp;
754 struct we_softc *sc;
755 {
756 struct mbuf *top, **mp, *m, *p;
757 int off = off0, len;
758 register caddr_t cp = buf;
759 char *epkt;
760 int tc =totlen;
761
762 buf += sizeof(struct ether_header);
763 cp = buf;
764 epkt = cp + totlen;
765
766 if (off) {
767 cp += off + 2 * sizeof(u_short);
768 totlen -= 2 * sizeof(u_short);
769 }
770
771 MGETHDR(m, M_DONTWAIT, MT_DATA);
772 if (m == 0)
773 return (0);
774 m->m_pkthdr.rcvif = ifp;
775 m->m_pkthdr.len = totlen;
776 m->m_len = MHLEN;
777
778 top = 0;
779 mp = ⊤
780 while (totlen > 0) {
781 if (top) {
782 MGET(m, M_DONTWAIT, MT_DATA);
783 if (m == 0) {
784 m_freem(top);
785 return (0);
786 }
787 m->m_len = MLEN;
788 }
789 len = min(totlen, epkt - cp);
790 if (len >= MINCLSIZE) {
791 MCLGET(m, M_DONTWAIT);
792 if (m->m_flags & M_EXT)
793 m->m_len = len = min(len, MCLBYTES);
794 else
795 len = m->m_len;
796 } else {
797 /*
798 * Place initial small packet/header at end of mbuf.
799 */
800 if (len < m->m_len) {
801 if (top == 0 && len + max_linkhdr <= m->m_len)
802 m->m_data += max_linkhdr;
803 m->m_len = len;
804 } else
805 len = m->m_len;
806 }
807
808 totlen -= len;
809 /* only do up to end of buffer */
810 if (cp+len > sc->we_vmem_end) {
811 unsigned toend = sc->we_vmem_end - cp;
812
813 bcopy(cp, mtod(m, caddr_t), toend);
814 cp = sc->we_vmem_ring;
815 bcopy(cp, mtod(m, caddr_t)+toend, len - toend);
816 cp += len - toend;
817 epkt = cp + totlen;
818 } else {
819 bcopy(cp, mtod(m, caddr_t), (unsigned)len);
820 cp += len;
821 }
822 *mp = m;
823 mp = &m->m_next;
824 if (cp == epkt) {
825 cp = buf;
826 epkt = cp + tc;
827 }
828 }
829 return (top);
830 }
831 #endif
832