if_eg.c revision 1.21 1 /* $NetBSD: if_eg.c,v 1.21 1995/12/24 02:31:24 mycroft Exp $ */
2
3 /*
4 * Copyright (c) 1993 Dean Huxley <dean (at) fsa.ca>
5 * All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
15 * 3. All advertising materials mentioning features or use of this software
16 * must display the following acknowledgement:
17 * This product includes software developed by Dean Huxley.
18 * 4. The name of Dean Huxley may not be used to endorse or promote products
19 * derived from this software without specific prior written permission.
20 *
21 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
22 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
23 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
24 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
25 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
26 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
27 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
28 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
29 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
30 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31 */
32
33 /* To do:
34 * - multicast
35 * - promiscuous
36 */
37 #include "bpfilter.h"
38
39 #include <sys/types.h>
40 #include <sys/param.h>
41 #include <sys/mbuf.h>
42 #include <sys/socket.h>
43 #include <sys/ioctl.h>
44 #include <sys/errno.h>
45 #include <sys/syslog.h>
46 #include <sys/select.h>
47 #include <sys/device.h>
48
49 #include <net/if.h>
50 #include <net/netisr.h>
51 #include <net/if_dl.h>
52 #include <net/if_types.h>
53 #include <net/netisr.h>
54
55 #ifdef INET
56 #include <netinet/in.h>
57 #include <netinet/in_systm.h>
58 #include <netinet/in_var.h>
59 #include <netinet/ip.h>
60 #include <netinet/if_ether.h>
61 #endif
62
63 #ifdef NS
64 #include <netns/ns.h>
65 #include <netns/ns_if.h>
66 #endif
67
68 #if NBPFILTER > 0
69 #include <net/bpf.h>
70 #include <net/bpfdesc.h>
71 #endif
72
73 #include <machine/cpu.h>
74 #include <machine/pio.h>
75
76 #include <dev/isa/isavar.h>
77 #include <dev/isa/if_egreg.h>
78 #include <dev/isa/elink.h>
79
80 /* for debugging convenience */
81 #ifdef EGDEBUG
82 #define dprintf(x) printf x
83 #else
84 #define dprintf(x)
85 #endif
86
87 #define ETHER_MIN_LEN 64
88 #define ETHER_MAX_LEN 1518
89 #define ETHER_ADDR_LEN 6
90
91 #define EG_INLEN 10
92 #define EG_BUFLEN 0x0670
93
94 /*
95 * Ethernet software status per interface.
96 */
97 struct eg_softc {
98 struct device sc_dev;
99 void *sc_ih;
100 struct arpcom sc_arpcom; /* Ethernet common part */
101 int eg_cmd; /* Command register R/W */
102 int eg_ctl; /* Control register R/W (EG_CTL_*) */
103 int eg_stat; /* Status register R/O (EG_STAT_*) */
104 int eg_data; /* Data register R/W (16 bits) */
105 u_char eg_rom_major; /* Cards ROM version (major number) */
106 u_char eg_rom_minor; /* Cards ROM version (minor number) */
107 short eg_ram; /* Amount of RAM on the card */
108 u_char eg_pcb[64]; /* Primary Command Block buffer */
109 u_char eg_incount; /* Number of buffers currently used */
110 u_char *eg_inbuf; /* Incoming packet buffer */
111 u_char *eg_outbuf; /* Outgoing packet buffer */
112 };
113
114 int egprobe __P((struct device *, void *, void *));
115 void egattach __P((struct device *, struct device *, void *));
116
117 struct cfdriver egcd = {
118 NULL, "eg", egprobe, egattach, DV_IFNET, sizeof(struct eg_softc)
119 };
120
121 int egintr __P((void *));
122 void eginit __P((struct eg_softc *));
123 int egioctl __P((struct ifnet *, u_long, caddr_t));
124 void egrecv __P((struct eg_softc *));
125 void egstart __P((struct ifnet *));
126 void egwatchdog __P((int));
127 void egreset __P((struct eg_softc *));
128 void egread __P((struct eg_softc *, caddr_t, int));
129 struct mbuf *egget __P((struct eg_softc *, caddr_t, int));
130 void egstop __P((struct eg_softc *));
131
132 /*
133 * Support stuff
134 */
135
136 static inline void
137 egprintpcb(sc)
138 struct eg_softc *sc;
139 {
140 int i;
141
142 for (i = 0; i < sc->eg_pcb[1] + 2; i++)
143 dprintf(("pcb[%2d] = %x\n", i, sc->eg_pcb[i]));
144 }
145
146
147 static inline void
148 egprintstat(b)
149 u_char b;
150 {
151 dprintf(("%s %s %s %s %s %s %s\n",
152 (b & EG_STAT_HCRE)?"HCRE":"",
153 (b & EG_STAT_ACRF)?"ACRF":"",
154 (b & EG_STAT_DIR )?"DIR ":"",
155 (b & EG_STAT_DONE)?"DONE":"",
156 (b & EG_STAT_ASF3)?"ASF3":"",
157 (b & EG_STAT_ASF2)?"ASF2":"",
158 (b & EG_STAT_ASF1)?"ASF1":""));
159 }
160
161 static int
162 egoutPCB(sc, b)
163 struct eg_softc *sc;
164 u_char b;
165 {
166 int i;
167
168 for (i=0; i < 4000; i++) {
169 if (inb(sc->eg_stat) & EG_STAT_HCRE) {
170 outb(sc->eg_cmd, b);
171 return 0;
172 }
173 delay(10);
174 }
175 dprintf(("egoutPCB failed\n"));
176 return 1;
177 }
178
179 static int
180 egreadPCBstat(sc, statb)
181 struct eg_softc *sc;
182 u_char statb;
183 {
184 int i;
185
186 for (i=0; i < 5000; i++) {
187 if ((inb(sc->eg_stat) & EG_PCB_STAT) != EG_PCB_NULL)
188 break;
189 delay(10);
190 }
191 if ((inb(sc->eg_stat) & EG_PCB_STAT) == statb)
192 return 0;
193 return 1;
194 }
195
196 static int
197 egreadPCBready(sc)
198 struct eg_softc *sc;
199 {
200 int i;
201
202 for (i=0; i < 10000; i++) {
203 if (inb(sc->eg_stat) & EG_STAT_ACRF)
204 return 0;
205 delay(5);
206 }
207 dprintf(("PCB read not ready\n"));
208 return 1;
209 }
210
211 static int
212 egwritePCB(sc)
213 struct eg_softc *sc;
214 {
215 int i;
216 u_char len;
217
218 outb(sc->eg_ctl, (inb(sc->eg_ctl) & ~EG_PCB_STAT) | EG_PCB_NULL);
219
220 len = sc->eg_pcb[1] + 2;
221 for (i = 0; i < len; i++)
222 egoutPCB(sc, sc->eg_pcb[i]);
223
224 for (i=0; i < 4000; i++) {
225 if (inb(sc->eg_stat) & EG_STAT_HCRE)
226 break;
227 delay(10);
228 }
229
230 outb(sc->eg_ctl, (inb(sc->eg_ctl) & ~EG_PCB_STAT) | EG_PCB_DONE);
231
232 egoutPCB(sc, len);
233
234 if (egreadPCBstat(sc, EG_PCB_ACCEPT))
235 return 1;
236 return 0;
237 }
238
239 static int
240 egreadPCB(sc)
241 struct eg_softc *sc;
242 {
243 int i;
244 u_char b;
245
246 outb(sc->eg_ctl, (inb(sc->eg_ctl) & ~EG_PCB_STAT) | EG_PCB_NULL);
247
248 bzero(sc->eg_pcb, sizeof(sc->eg_pcb));
249
250 if (egreadPCBready(sc))
251 return 1;
252
253 sc->eg_pcb[0] = inb(sc->eg_cmd);
254
255 if (egreadPCBready(sc))
256 return 1;
257
258 sc->eg_pcb[1] = inb(sc->eg_cmd);
259
260 if (sc->eg_pcb[1] > 62) {
261 dprintf(("len %d too large\n", sc->eg_pcb[1]));
262 return 1;
263 }
264
265 for (i = 0; i < sc->eg_pcb[1]; i++) {
266 if (egreadPCBready(sc))
267 return 1;
268 sc->eg_pcb[2+i] = inb(sc->eg_cmd);
269 }
270 if (egreadPCBready(sc))
271 return 1;
272 if (egreadPCBstat(sc, EG_PCB_DONE))
273 return 1;
274 if ((b = inb(sc->eg_cmd)) != sc->eg_pcb[1] + 2) {
275 dprintf(("%d != %d\n", b, sc->eg_pcb[1] + 2));
276 return 1;
277 }
278
279 outb(sc->eg_ctl, (inb(sc->eg_ctl) & ~EG_PCB_STAT) | EG_PCB_ACCEPT);
280
281 return 0;
282 }
283
284 /*
285 * Real stuff
286 */
287
288 int
289 egprobe(parent, match, aux)
290 struct device *parent;
291 void *match, *aux;
292 {
293 struct eg_softc *sc = match;
294 struct isa_attach_args *ia = aux;
295 int i;
296
297 if (ia->ia_iobase & ~0x07f0 != 0) {
298 dprintf(("Weird iobase %x\n", ia->ia_iobase));
299 return 0;
300 }
301
302 sc->eg_cmd = ia->ia_iobase + EG_COMMAND;
303 sc->eg_ctl = ia->ia_iobase + EG_CONTROL;
304 sc->eg_stat = ia->ia_iobase + EG_STATUS;
305 sc->eg_data = ia->ia_iobase + EG_DATA;
306
307 /* hard reset card */
308 outb(sc->eg_ctl, EG_CTL_RESET);
309 outb(sc->eg_ctl, 0);
310 for (i = 0; i < 5000; i++) {
311 delay(1000);
312 if ((inb(sc->eg_stat) & EG_PCB_STAT) == EG_PCB_NULL)
313 break;
314 }
315 if ((inb(sc->eg_stat) & EG_PCB_STAT) != EG_PCB_NULL) {
316 dprintf(("eg: Reset failed\n"));
317 return 0;
318 }
319 sc->eg_pcb[0] = EG_CMD_GETINFO; /* Get Adapter Info */
320 sc->eg_pcb[1] = 0;
321 if (egwritePCB(sc) != 0)
322 return 0;
323
324 if (egreadPCB(sc) != 0) {
325 egprintpcb(sc);
326 return 0;
327 }
328
329 if (sc->eg_pcb[0] != EG_RSP_GETINFO || /* Get Adapter Info Response */
330 sc->eg_pcb[1] != 0x0a) {
331 egprintpcb(sc);
332 return 0;
333 }
334 sc->eg_rom_major = sc->eg_pcb[3];
335 sc->eg_rom_minor = sc->eg_pcb[2];
336 sc->eg_ram = sc->eg_pcb[6] | (sc->eg_pcb[7] << 8);
337
338 ia->ia_iosize = 0x08;
339 ia->ia_msize = 0;
340 return 1;
341 }
342
343 void
344 egattach(parent, self, aux)
345 struct device *parent, *self;
346 void *aux;
347 {
348 struct eg_softc *sc = (void *)self;
349 struct isa_attach_args *ia = aux;
350 struct ifnet *ifp = &sc->sc_arpcom.ac_if;
351 int i;
352
353 egstop(sc);
354
355 sc->eg_pcb[0] = EG_CMD_GETEADDR; /* Get Station address */
356 sc->eg_pcb[1] = 0;
357 if (egwritePCB(sc) != 0) {
358 dprintf(("write error\n"));
359 return;
360 }
361 if (egreadPCB(sc) != 0) {
362 dprintf(("read error\n"));
363 egprintpcb(sc);
364 return;
365 }
366
367 /* check Get station address response */
368 if (sc->eg_pcb[0] != EG_RSP_GETEADDR || sc->eg_pcb[1] != 0x06) {
369 dprintf(("parse error\n"));
370 egprintpcb(sc);
371 return;
372 }
373 bcopy(&sc->eg_pcb[2], sc->sc_arpcom.ac_enaddr, ETHER_ADDR_LEN);
374
375 printf(": ROM v%d.%02d %dk address %s\n",
376 sc->eg_rom_major, sc->eg_rom_minor, sc->eg_ram,
377 ether_sprintf(sc->sc_arpcom.ac_enaddr));
378
379 sc->eg_pcb[0] = EG_CMD_SETEADDR; /* Set station address */
380 if (egwritePCB(sc) != 0) {
381 dprintf(("write error2\n"));
382 return;
383 }
384 if (egreadPCB(sc) != 0) {
385 dprintf(("read error2\n"));
386 egprintpcb(sc);
387 return;
388 }
389 if (sc->eg_pcb[0] != EG_RSP_SETEADDR || sc->eg_pcb[1] != 0x02 ||
390 sc->eg_pcb[2] != 0 || sc->eg_pcb[3] != 0) {
391 dprintf(("parse error2\n"));
392 egprintpcb(sc);
393 return;
394 }
395
396 /* Initialize ifnet structure. */
397 ifp->if_unit = sc->sc_dev.dv_unit;
398 ifp->if_name = egcd.cd_name;
399 ifp->if_start = egstart;
400 ifp->if_ioctl = egioctl;
401 ifp->if_watchdog = egwatchdog;
402 ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_NOTRAILERS;
403
404 /* Now we can attach the interface. */
405 if_attach(ifp);
406 ether_ifattach(ifp);
407
408 #if NBPFILTER > 0
409 bpfattach(&ifp->if_bpf, ifp, DLT_EN10MB, sizeof(struct ether_header));
410 #endif
411
412 sc->sc_ih = isa_intr_establish(ia->ia_irq, IST_EDGE, IPL_NET, egintr,
413 sc);
414 }
415
416 void
417 eginit(sc)
418 register struct eg_softc *sc;
419 {
420 register struct ifnet *ifp = &sc->sc_arpcom.ac_if;
421
422 /* soft reset the board */
423 outb(sc->eg_ctl, EG_CTL_FLSH);
424 delay(100);
425 outb(sc->eg_ctl, EG_CTL_ATTN);
426 delay(100);
427 outb(sc->eg_ctl, 0);
428 delay(200);
429
430 sc->eg_pcb[0] = EG_CMD_CONFIG82586; /* Configure 82586 */
431 sc->eg_pcb[1] = 2;
432 sc->eg_pcb[2] = 3; /* receive broadcast & multicast */
433 sc->eg_pcb[3] = 0;
434 if (egwritePCB(sc) != 0)
435 dprintf(("write error3\n"));
436
437 if (egreadPCB(sc) != 0) {
438 dprintf(("read error\n"));
439 egprintpcb(sc);
440 } else if (sc->eg_pcb[2] != 0 || sc->eg_pcb[3] != 0)
441 printf("%s: configure card command failed\n",
442 sc->sc_dev.dv_xname);
443
444 if (sc->eg_inbuf == 0)
445 sc->eg_inbuf = malloc(EG_BUFLEN, M_TEMP, M_NOWAIT);
446 sc->eg_incount = 0;
447
448 if (sc->eg_outbuf == 0)
449 sc->eg_outbuf = malloc(EG_BUFLEN, M_TEMP, M_NOWAIT);
450
451 outb(sc->eg_ctl, EG_CTL_CMDE);
452
453 sc->eg_incount = 0;
454 egrecv(sc);
455
456 /* Interface is now `running', with no output active. */
457 ifp->if_flags |= IFF_RUNNING;
458 ifp->if_flags &= ~IFF_OACTIVE;
459
460 /* Attempt to start output, if any. */
461 egstart(ifp);
462 }
463
464 void
465 egrecv(sc)
466 struct eg_softc *sc;
467 {
468
469 while (sc->eg_incount < EG_INLEN) {
470 sc->eg_pcb[0] = EG_CMD_RECVPACKET;
471 sc->eg_pcb[1] = 0x08;
472 sc->eg_pcb[2] = 0; /* address not used.. we send zero */
473 sc->eg_pcb[3] = 0;
474 sc->eg_pcb[4] = 0;
475 sc->eg_pcb[5] = 0;
476 sc->eg_pcb[6] = EG_BUFLEN; /* our buffer size */
477 sc->eg_pcb[7] = EG_BUFLEN >> 8;
478 sc->eg_pcb[8] = 0; /* timeout, 0 == none */
479 sc->eg_pcb[9] = 0;
480 if (egwritePCB(sc) != 0)
481 break;
482 sc->eg_incount++;
483 }
484 }
485
486 void
487 egstart(ifp)
488 struct ifnet *ifp;
489 {
490 register struct eg_softc *sc = egcd.cd_devs[ifp->if_unit];
491 struct mbuf *m0, *m;
492 caddr_t buffer;
493 int len;
494 u_short *ptr;
495
496 /* Don't transmit if interface is busy or not running */
497 if ((ifp->if_flags & (IFF_RUNNING|IFF_OACTIVE)) != IFF_RUNNING)
498 return;
499
500 loop:
501 /* Dequeue the next datagram. */
502 IF_DEQUEUE(&ifp->if_snd, m0);
503 if (m0 == 0)
504 return;
505
506 ifp->if_flags |= IFF_OACTIVE;
507
508 /* We need to use m->m_pkthdr.len, so require the header */
509 if ((m0->m_flags & M_PKTHDR) == 0)
510 panic("egstart: no header mbuf");
511 len = max(m0->m_pkthdr.len, ETHER_MIN_LEN);
512
513 #if NBPFILTER > 0
514 if (ifp->if_bpf)
515 bpf_mtap(ifp->if_bpf, m0);
516 #endif
517
518 sc->eg_pcb[0] = EG_CMD_SENDPACKET;
519 sc->eg_pcb[1] = 0x06;
520 sc->eg_pcb[2] = 0; /* address not used, we send zero */
521 sc->eg_pcb[3] = 0;
522 sc->eg_pcb[4] = 0;
523 sc->eg_pcb[5] = 0;
524 sc->eg_pcb[6] = len; /* length of packet */
525 sc->eg_pcb[7] = len >> 8;
526 if (egwritePCB(sc) != 0) {
527 dprintf(("egwritePCB in egstart failed\n"));
528 ifp->if_oerrors++;
529 ifp->if_flags &= ~IFF_OACTIVE;
530 goto loop;
531 }
532
533 buffer = sc->eg_outbuf;
534 for (m = m0; m != 0; m = m->m_next) {
535 bcopy(mtod(m, caddr_t), buffer, m->m_len);
536 buffer += m->m_len;
537 }
538
539 /* set direction bit: host -> adapter */
540 outb(sc->eg_ctl, inb(sc->eg_ctl) & ~EG_CTL_DIR);
541
542 for (ptr = (u_short *) sc->eg_outbuf; len > 0; len -= 2) {
543 outw(sc->eg_data, *ptr++);
544 while (!(inb(sc->eg_stat) & EG_STAT_HRDY))
545 ; /* XXX need timeout here */
546 }
547
548 m_freem(m0);
549 }
550
551 int
552 egintr(arg)
553 void *arg;
554 {
555 register struct eg_softc *sc = arg;
556 int i, len;
557 u_short *ptr;
558
559 while (inb(sc->eg_stat) & EG_STAT_ACRF) {
560 egreadPCB(sc);
561 switch (sc->eg_pcb[0]) {
562 case EG_RSP_RECVPACKET:
563 len = sc->eg_pcb[6] | (sc->eg_pcb[7] << 8);
564
565 /* Set direction bit : Adapter -> host */
566 outb(sc->eg_ctl, inb(sc->eg_ctl) | EG_CTL_DIR);
567
568 for (ptr = (u_short *) sc->eg_inbuf; len > 0; len -= 2) {
569 while (!(inb(sc->eg_stat) & EG_STAT_HRDY))
570 ;
571 *ptr++ = inw(sc->eg_data);
572 }
573
574 len = sc->eg_pcb[8] | (sc->eg_pcb[9] << 8);
575 egread(sc, sc->eg_inbuf, len);
576
577 sc->eg_incount--;
578 egrecv(sc);
579 break;
580
581 case EG_RSP_SENDPACKET:
582 if (sc->eg_pcb[6] || sc->eg_pcb[7]) {
583 dprintf(("packet dropped\n"));
584 sc->sc_arpcom.ac_if.if_oerrors++;
585 } else
586 sc->sc_arpcom.ac_if.if_opackets++;
587 sc->sc_arpcom.ac_if.if_collisions += sc->eg_pcb[8] & 0xf;
588 sc->sc_arpcom.ac_if.if_flags &= ~IFF_OACTIVE;
589 egstart(&sc->sc_arpcom.ac_if);
590 break;
591
592 case EG_RSP_GETSTATS:
593 dprintf(("Card Statistics\n"));
594 bcopy(&sc->eg_pcb[2], &i, sizeof(i));
595 dprintf(("Receive Packets %d\n", i));
596 bcopy(&sc->eg_pcb[6], &i, sizeof(i));
597 dprintf(("Transmit Packets %d\n", i));
598 dprintf(("CRC errors %d\n", *(short*) &sc->eg_pcb[10]));
599 dprintf(("alignment errors %d\n", *(short*) &sc->eg_pcb[12]));
600 dprintf(("no resources errors %d\n", *(short*) &sc->eg_pcb[14]));
601 dprintf(("overrun errors %d\n", *(short*) &sc->eg_pcb[16]));
602 break;
603
604 default:
605 dprintf(("egintr: Unknown response %x??\n",
606 sc->eg_pcb[0]));
607 egprintpcb(sc);
608 break;
609 }
610 }
611
612 return 0;
613 }
614
615 /*
616 * Pass a packet up to the higher levels.
617 */
618 void
619 egread(sc, buf, len)
620 struct eg_softc *sc;
621 caddr_t buf;
622 int len;
623 {
624 struct ifnet *ifp = &sc->sc_arpcom.ac_if;
625 struct mbuf *m;
626 struct ether_header *eh;
627
628 if (len <= sizeof(struct ether_header) ||
629 len > ETHER_MAX_LEN) {
630 printf("%s: invalid packet size %d; dropping\n",
631 sc->sc_dev.dv_xname, len);
632 ifp->if_ierrors++;
633 return;
634 }
635
636 /* Pull packet off interface. */
637 m = egget(sc, buf, len);
638 if (m == 0) {
639 ifp->if_ierrors++;
640 return;
641 }
642
643 ifp->if_ipackets++;
644
645 /* We assume the header fit entirely in one mbuf. */
646 eh = mtod(m, struct ether_header *);
647
648 #if NBPFILTER > 0
649 /*
650 * Check if there's a BPF listener on this interface.
651 * If so, hand off the raw packet to BPF.
652 */
653 if (ifp->if_bpf) {
654 bpf_mtap(ifp->if_bpf, m);
655
656 /*
657 * Note that the interface cannot be in promiscuous mode if
658 * there are no BPF listeners. And if we are in promiscuous
659 * mode, we have to check if this packet is really ours.
660 */
661 if ((ifp->if_flags & IFF_PROMISC) &&
662 (eh->ether_dhost[0] & 1) == 0 && /* !mcast and !bcast */
663 bcmp(eh->ether_dhost, sc->sc_arpcom.ac_enaddr,
664 sizeof(eh->ether_dhost)) != 0) {
665 m_freem(m);
666 return;
667 }
668 }
669 #endif
670
671 /* We assume the header fit entirely in one mbuf. */
672 m_adj(m, sizeof(struct ether_header));
673 ether_input(ifp, eh, m);
674 }
675
676 /*
677 * convert buf into mbufs
678 */
679 struct mbuf *
680 egget(sc, buf, totlen)
681 struct eg_softc *sc;
682 caddr_t buf;
683 int totlen;
684 {
685 struct ifnet *ifp = &sc->sc_arpcom.ac_if;
686 struct mbuf *top, **mp, *m;
687 int len;
688
689 MGETHDR(m, M_DONTWAIT, MT_DATA);
690 if (m == 0)
691 return 0;
692 m->m_pkthdr.rcvif = ifp;
693 m->m_pkthdr.len = totlen;
694 len = MHLEN;
695 top = 0;
696 mp = ⊤
697
698 while (totlen > 0) {
699 if (top) {
700 MGET(m, M_DONTWAIT, MT_DATA);
701 if (m == 0) {
702 m_freem(top);
703 return 0;
704 }
705 len = MLEN;
706 }
707 if (totlen >= MINCLSIZE) {
708 MCLGET(m, M_DONTWAIT);
709 if (m->m_flags & M_EXT)
710 len = MCLBYTES;
711 }
712 m->m_len = len = min(totlen, len);
713 bcopy((caddr_t)buf, mtod(m, caddr_t), len);
714 buf += len;
715 totlen -= len;
716 *mp = m;
717 mp = &m->m_next;
718 }
719
720 return top;
721 }
722
723 int
724 egioctl(ifp, cmd, data)
725 register struct ifnet *ifp;
726 u_long cmd;
727 caddr_t data;
728 {
729 struct eg_softc *sc = egcd.cd_devs[ifp->if_unit];
730 struct ifaddr *ifa = (struct ifaddr *)data;
731 struct ifreq *ifr = (struct ifreq *)data;
732 int s, error = 0;
733
734 s = splnet();
735
736 switch (cmd) {
737
738 case SIOCSIFADDR:
739 ifp->if_flags |= IFF_UP;
740
741 switch (ifa->ifa_addr->sa_family) {
742 #ifdef INET
743 case AF_INET:
744 eginit(sc);
745 arp_ifinit(&sc->sc_arpcom, ifa);
746 break;
747 #endif
748 #ifdef NS
749 case AF_NS:
750 {
751 register struct ns_addr *ina = &IA_SNS(ifa)->sns_addr;
752
753 if (ns_nullhost(*ina))
754 ina->x_host =
755 *(union ns_host *)(sc->sc_arpcom.ac_enaddr);
756 else
757 bcopy(ina->x_host.c_host,
758 sc->sc_arpcom.ac_enaddr,
759 sizeof(sc->sc_arpcom.ac_enaddr));
760 /* Set new address. */
761 eginit(sc);
762 break;
763 }
764 #endif
765 default:
766 eginit(sc);
767 break;
768 }
769 break;
770
771 case SIOCSIFFLAGS:
772 if ((ifp->if_flags & IFF_UP) == 0 &&
773 (ifp->if_flags & IFF_RUNNING) != 0) {
774 /*
775 * If interface is marked down and it is running, then
776 * stop it.
777 */
778 egstop(sc);
779 ifp->if_flags &= ~IFF_RUNNING;
780 } else if ((ifp->if_flags & IFF_UP) != 0 &&
781 (ifp->if_flags & IFF_RUNNING) == 0) {
782 /*
783 * If interface is marked up and it is stopped, then
784 * start it.
785 */
786 eginit(sc);
787 } else {
788 sc->eg_pcb[0] = EG_CMD_GETSTATS;
789 sc->eg_pcb[1] = 0;
790 if (egwritePCB(sc) != 0)
791 dprintf(("write error\n"));
792 /*
793 * XXX deal with flags changes:
794 * IFF_MULTICAST, IFF_PROMISC,
795 * IFF_LINK0, IFF_LINK1,
796 */
797 }
798 break;
799
800 default:
801 error = EINVAL;
802 break;
803 }
804
805 splx(s);
806 return error;
807 }
808
809 void
810 egreset(sc)
811 struct eg_softc *sc;
812 {
813 int s;
814
815 dprintf(("egreset()\n"));
816 s = splnet();
817 egstop(sc);
818 eginit(sc);
819 splx(s);
820 }
821
822 void
823 egwatchdog(unit)
824 int unit;
825 {
826 struct eg_softc *sc = egcd.cd_devs[unit];
827
828 log(LOG_ERR, "%s: device timeout\n", sc->sc_dev.dv_xname);
829 sc->sc_arpcom.ac_if.if_oerrors++;
830
831 egreset(sc);
832 }
833
834 void
835 egstop(sc)
836 register struct eg_softc *sc;
837 {
838
839 outb(sc->eg_ctl, 0);
840 }
841