if_el.c revision 1.2 1 1.2 cgd /*
2 1.2 cgd * Copyright (c) 1994, Matthew E. Kimmel. Permission is hereby granted
3 1.1 hpeyerl * to use, copy, modify and distribute this software provided that both
4 1.1 hpeyerl * the copyright notice and this permission notice appear in all copies
5 1.1 hpeyerl * of the software, derivative works or modified versions, and any
6 1.1 hpeyerl * portions thereof.
7 1.1 hpeyerl */
8 1.2 cgd
9 1.2 cgd /*
10 1.2 cgd * 3COM Etherlink 3C501 device driver
11 1.2 cgd *
12 1.2 cgd * $Id: if_el.c,v 1.2 1994/03/01 04:12:25 cgd Exp $
13 1.1 hpeyerl */
14 1.2 cgd
15 1.2 cgd /*
16 1.2 cgd * Bugs/possible improvements:
17 1.1 hpeyerl * - Does not currently support DMA
18 1.1 hpeyerl * - Does not currently support multicasts
19 1.1 hpeyerl */
20 1.2 cgd
21 1.1 hpeyerl #include "el.h"
22 1.1 hpeyerl #if NEL > 0
23 1.1 hpeyerl #include "bpfilter.h"
24 1.1 hpeyerl
25 1.1 hpeyerl #include <sys/param.h>
26 1.1 hpeyerl #include <sys/errno.h>
27 1.1 hpeyerl #include <sys/ioctl.h>
28 1.1 hpeyerl #include <sys/mbuf.h>
29 1.1 hpeyerl #include <sys/socket.h>
30 1.1 hpeyerl #include <sys/syslog.h>
31 1.1 hpeyerl
32 1.1 hpeyerl #include <net/if.h>
33 1.1 hpeyerl #include <net/if_dl.h>
34 1.1 hpeyerl #include <net/if_types.h>
35 1.1 hpeyerl
36 1.1 hpeyerl #ifdef INET
37 1.1 hpeyerl #include <netinet/in.h>
38 1.1 hpeyerl #include <netinet/in_systm.h>
39 1.1 hpeyerl #include <netinet/in_var.h>
40 1.1 hpeyerl #include <netinet/ip.h>
41 1.1 hpeyerl #include <netinet/if_ether.h>
42 1.1 hpeyerl #endif
43 1.1 hpeyerl
44 1.1 hpeyerl #ifdef NS
45 1.1 hpeyerl #include <netns/ns.h>
46 1.1 hpeyerl #include <netns/ns_if.h>
47 1.1 hpeyerl #endif
48 1.1 hpeyerl
49 1.1 hpeyerl #if NBPFILTER > 0
50 1.1 hpeyerl #include <net/bpf.h>
51 1.1 hpeyerl #include <net/bpfdesc.h>
52 1.1 hpeyerl #endif
53 1.1 hpeyerl
54 1.1 hpeyerl #include <machine/pio.h>
55 1.1 hpeyerl
56 1.1 hpeyerl #include <i386/isa/isa.h>
57 1.1 hpeyerl #include <i386/isa/isa_device.h>
58 1.1 hpeyerl #include <i386/isa/icu.h>
59 1.1 hpeyerl #include <i386/isa/if_elreg.h>
60 1.1 hpeyerl
61 1.1 hpeyerl #define ETHER_MIN_LEN 64
62 1.1 hpeyerl #define ETHER_MAX_LEN 1518
63 1.1 hpeyerl
64 1.1 hpeyerl /* For debugging convenience */
65 1.1 hpeyerl #ifdef EL_DEBUG
66 1.1 hpeyerl #define dprintf(x) printf x
67 1.1 hpeyerl #else
68 1.1 hpeyerl #define dprintf(x)
69 1.1 hpeyerl #endif
70 1.1 hpeyerl
71 1.2 cgd /*
72 1.2 cgd * el_softc: per-line info and status
73 1.2 cgd */
74 1.1 hpeyerl struct el_softc {
75 1.2 cgd struct arpcom arpcom; /* Ethernet common */
76 1.2 cgd u_short el_base; /* Base I/O addr */
77 1.2 cgd caddr_t bpf; /* BPF magic cookie */
78 1.1 hpeyerl char el_pktbuf[EL_BUFSIZ]; /* Frame buffer */
79 1.1 hpeyerl } el_softc[NEL];
80 1.1 hpeyerl
81 1.2 cgd /*
82 1.2 cgd * Prototypes
83 1.2 cgd */
84 1.2 cgd int elintr __P((int));
85 1.1 hpeyerl static int el_attach __P((struct isa_device *));
86 1.1 hpeyerl static int el_init __P((int));
87 1.2 cgd static int el_ioctl __P((struct ifnet *, int, caddr_t));
88 1.1 hpeyerl static int el_probe __P((struct isa_device *));
89 1.1 hpeyerl static int el_start __P((struct ifnet *));
90 1.1 hpeyerl static int el_watchdog __P((int));
91 1.1 hpeyerl
92 1.2 cgd static void el_reset __P((int, int));
93 1.1 hpeyerl static void el_stop __P((int));
94 1.2 cgd static int el_xmit __P((struct el_softc *, int));
95 1.2 cgd static inline void elread __P((struct el_softc *, caddr_t, int));
96 1.2 cgd static struct mbuf *elget __P((caddr_t, int, int, struct ifnet *));
97 1.1 hpeyerl
98 1.1 hpeyerl /* isa_driver structure for autoconf */
99 1.1 hpeyerl struct isa_driver eldriver = {
100 1.1 hpeyerl el_probe, el_attach, "el"
101 1.1 hpeyerl };
102 1.1 hpeyerl
103 1.2 cgd /*
104 1.2 cgd * Probe routine.
105 1.2 cgd *
106 1.2 cgd * See if the card is there and at the right place.
107 1.2 cgd * (XXX - cgd -- needs help)
108 1.2 cgd */
109 1.1 hpeyerl static int
110 1.2 cgd el_probe(idev)
111 1.2 cgd struct isa_device *idev;
112 1.1 hpeyerl {
113 1.1 hpeyerl struct el_softc *sc;
114 1.1 hpeyerl u_short base; /* Just for convenience */
115 1.1 hpeyerl u_char station_addr[ETHER_ADDR_LEN];
116 1.1 hpeyerl int i;
117 1.1 hpeyerl
118 1.1 hpeyerl /* Grab some info for our structure */
119 1.1 hpeyerl sc = &el_softc[idev->id_unit];
120 1.1 hpeyerl sc->el_base = idev->id_iobase;
121 1.1 hpeyerl base = sc->el_base;
122 1.1 hpeyerl
123 1.1 hpeyerl /* First check the base */
124 1.2 cgd if ((base < 0x280) || (base > 0x3f0))
125 1.1 hpeyerl return(0);
126 1.1 hpeyerl
127 1.2 cgd /*
128 1.2 cgd * Now attempt to grab the station address from the PROM
129 1.1 hpeyerl * and see if it contains the 3com vendor code.
130 1.1 hpeyerl */
131 1.2 cgd dprintf(("Probing 3c501 at 0x%x...\n", base));
132 1.1 hpeyerl /* Reset the board */
133 1.1 hpeyerl dprintf(("Resetting board...\n"));
134 1.2 cgd outb(base+EL_AC, EL_AC_RESET);
135 1.1 hpeyerl DELAY(5);
136 1.2 cgd outb(base+EL_AC, 0);
137 1.1 hpeyerl dprintf(("Reading station address...\n"));
138 1.1 hpeyerl /* Now read the address */
139 1.1 hpeyerl for(i=0;i<ETHER_ADDR_LEN;i++) {
140 1.2 cgd outb(base+EL_GPBL, i);
141 1.1 hpeyerl station_addr[i] = inb(base+EL_EAW);
142 1.1 hpeyerl }
143 1.2 cgd dprintf(("Address is %s\n", ether_sprintf(station_addr)));
144 1.1 hpeyerl
145 1.2 cgd /*
146 1.2 cgd * If the vendor code is ok, return a 1. We'll assume that
147 1.1 hpeyerl * whoever configured this system is right about the IRQ.
148 1.1 hpeyerl */
149 1.2 cgd if ((station_addr[0] != 0x02) || (station_addr[1] != 0x60)
150 1.2 cgd || (station_addr[2] != 0x8c)) {
151 1.1 hpeyerl dprintf(("Bad vendor code.\n"));
152 1.1 hpeyerl return(0);
153 1.1 hpeyerl } else {
154 1.1 hpeyerl dprintf(("Vendor code ok.\n"));
155 1.1 hpeyerl /* Copy the station address into the arpcom structure */
156 1.2 cgd bcopy(station_addr, sc->arpcom.ac_enaddr, ETHER_ADDR_LEN);
157 1.2 cgd return(1); /* XXX - cgd? */
158 1.1 hpeyerl }
159 1.1 hpeyerl }
160 1.1 hpeyerl
161 1.2 cgd /*
162 1.2 cgd * Attach the interface to the kernel data structures. By the time
163 1.1 hpeyerl * this is called, we know that the card exists at the given I/O address.
164 1.1 hpeyerl * We still assume that the IRQ given is correct.
165 1.1 hpeyerl */
166 1.1 hpeyerl static int
167 1.2 cgd el_attach(idev)
168 1.2 cgd struct isa_device *idev;
169 1.1 hpeyerl {
170 1.1 hpeyerl struct el_softc *sc;
171 1.1 hpeyerl struct ifnet *ifp;
172 1.1 hpeyerl struct ifaddr *ifa;
173 1.1 hpeyerl struct sockaddr_dl *sdl;
174 1.1 hpeyerl u_short base;
175 1.1 hpeyerl int t;
176 1.1 hpeyerl
177 1.2 cgd dprintf(("Attaching el%d...\n", idev->id_unit));
178 1.1 hpeyerl
179 1.1 hpeyerl /* Get things pointing to the right places. */
180 1.1 hpeyerl sc = &el_softc[idev->id_unit];
181 1.1 hpeyerl ifp = &sc->arpcom.ac_if;
182 1.1 hpeyerl base = sc->el_base;
183 1.1 hpeyerl
184 1.1 hpeyerl /* Now reset the board */
185 1.1 hpeyerl dprintf(("Resetting board...\n"));
186 1.2 cgd outb(base+EL_AC, EL_AC_RESET);
187 1.1 hpeyerl DELAY(5);
188 1.2 cgd outb(base+EL_AC, 0);
189 1.1 hpeyerl
190 1.1 hpeyerl /* Initialize ifnet structure */
191 1.1 hpeyerl ifp->if_unit = idev->id_unit;
192 1.1 hpeyerl ifp->if_name = "el";
193 1.1 hpeyerl ifp->if_mtu = ETHERMTU;
194 1.1 hpeyerl ifp->if_output = ether_output;
195 1.1 hpeyerl ifp->if_start = el_start;
196 1.1 hpeyerl ifp->if_ioctl = el_ioctl;
197 1.1 hpeyerl ifp->if_watchdog = el_watchdog;
198 1.1 hpeyerl ifp->if_flags = (IFF_BROADCAST | IFF_SIMPLEX | IFF_NOTRAILERS);
199 1.1 hpeyerl
200 1.1 hpeyerl /* Now we can attach the interface */
201 1.1 hpeyerl dprintf(("Attaching interface...\n"));
202 1.1 hpeyerl if_attach(ifp);
203 1.1 hpeyerl
204 1.2 cgd /*
205 1.2 cgd * Put the station address in the ifa address list's AF_LINK
206 1.1 hpeyerl * entry, if any.
207 1.1 hpeyerl */
208 1.1 hpeyerl ifa = ifp->if_addrlist;
209 1.1 hpeyerl while ((ifa != NULL) && (ifa->ifa_addr != NULL) &&
210 1.2 cgd (ifa->ifa_addr->sa_family != AF_LINK))
211 1.1 hpeyerl ifa = ifa->ifa_next;
212 1.2 cgd if ((ifa != NULL) && (ifa->ifa_addr != NULL)) {
213 1.1 hpeyerl sdl = (struct sockaddr_dl *)ifa->ifa_addr;
214 1.1 hpeyerl sdl->sdl_type = IFT_ETHER;
215 1.1 hpeyerl sdl->sdl_alen = ETHER_ADDR_LEN;
216 1.1 hpeyerl sdl->sdl_slen = 0;
217 1.2 cgd bcopy(sc->arpcom.ac_enaddr, LLADDR(sdl), ETHER_ADDR_LEN);
218 1.1 hpeyerl }
219 1.1 hpeyerl
220 1.1 hpeyerl /* Print out some information for the user */
221 1.2 cgd printf("el%d: address %s\n", idev->id_unit,
222 1.2 cgd ether_sprintf(sc->arpcom.ac_enaddr));
223 1.1 hpeyerl
224 1.1 hpeyerl /* Finally, attach to bpf filter if it is present. */
225 1.1 hpeyerl #if NBPFILTER > 0
226 1.1 hpeyerl dprintf(("Attaching to BPF...\n"));
227 1.2 cgd bpfattach(&sc->bpf, ifp, DLT_EN10MB, sizeof(struct ether_header));
228 1.1 hpeyerl #endif
229 1.1 hpeyerl
230 1.1 hpeyerl dprintf(("el_attach() finished.\n"));
231 1.1 hpeyerl return(1);
232 1.1 hpeyerl }
233 1.1 hpeyerl
234 1.2 cgd /*
235 1.2 cgd * Reset interface.
236 1.2 cgd */
237 1.1 hpeyerl static void
238 1.2 cgd el_reset(unit, uban)
239 1.2 cgd int unit, uban;
240 1.1 hpeyerl {
241 1.1 hpeyerl int s;
242 1.1 hpeyerl
243 1.1 hpeyerl dprintf(("elreset()\n"));
244 1.1 hpeyerl s = splimp();
245 1.1 hpeyerl el_stop(unit);
246 1.1 hpeyerl el_init(unit);
247 1.1 hpeyerl splx(s);
248 1.1 hpeyerl }
249 1.1 hpeyerl
250 1.2 cgd /*
251 1.2 cgd * Stop interface.
252 1.2 cgd */
253 1.1 hpeyerl static void
254 1.2 cgd el_stop(unit)
255 1.2 cgd int unit;
256 1.1 hpeyerl {
257 1.1 hpeyerl struct el_softc *sc;
258 1.1 hpeyerl
259 1.1 hpeyerl sc = &el_softc[unit];
260 1.2 cgd outb(sc->el_base+EL_AC, 0);
261 1.1 hpeyerl }
262 1.1 hpeyerl
263 1.2 cgd /*
264 1.2 cgd * Initialize interface.
265 1.2 cgd */
266 1.1 hpeyerl static int
267 1.2 cgd el_init(unit)
268 1.2 cgd int unit;
269 1.1 hpeyerl {
270 1.1 hpeyerl struct el_softc *sc;
271 1.1 hpeyerl struct ifnet *ifp;
272 1.1 hpeyerl int s;
273 1.1 hpeyerl u_short base;
274 1.1 hpeyerl
275 1.1 hpeyerl /* Set up pointers */
276 1.1 hpeyerl sc = &el_softc[unit];
277 1.1 hpeyerl ifp = &sc->arpcom.ac_if;
278 1.1 hpeyerl base = sc->el_base;
279 1.1 hpeyerl
280 1.1 hpeyerl /* If address not known, do nothing. */
281 1.2 cgd if (ifp->if_addrlist == (struct ifaddr *)0)
282 1.1 hpeyerl return;
283 1.1 hpeyerl
284 1.1 hpeyerl s = splimp();
285 1.1 hpeyerl
286 1.1 hpeyerl /* First, reset the board. */
287 1.1 hpeyerl dprintf(("Resetting board...\n"));
288 1.2 cgd outb(base+EL_AC, EL_AC_RESET);
289 1.1 hpeyerl DELAY(5);
290 1.2 cgd outb(base+EL_AC, 0);
291 1.1 hpeyerl
292 1.1 hpeyerl /* Configure rx */
293 1.1 hpeyerl dprintf(("Configuring rx...\n"));
294 1.2 cgd if (ifp->if_flags & IFF_PROMISC)
295 1.2 cgd outb(base+EL_RXC, (EL_RXC_PROMISC|EL_RXC_AGF|EL_RXC_DSHORT|EL_RXC_DDRIB|EL_RXC_DOFLOW));
296 1.1 hpeyerl else
297 1.2 cgd outb(base+EL_RXC, (EL_RXC_ABROAD|EL_RXC_AGF|EL_RXC_DSHORT|EL_RXC_DDRIB|EL_RXC_DOFLOW));
298 1.2 cgd outb(base+EL_RBC, 0);
299 1.1 hpeyerl
300 1.1 hpeyerl /* Configure TX */
301 1.1 hpeyerl dprintf(("Configuring tx...\n"));
302 1.2 cgd outb(base+EL_TXC, 0);
303 1.1 hpeyerl
304 1.1 hpeyerl /* Start reception */
305 1.1 hpeyerl dprintf(("Starting reception...\n"));
306 1.2 cgd outb(base+EL_AC, (EL_AC_IRQE|EL_AC_RX));
307 1.1 hpeyerl
308 1.1 hpeyerl /* Set flags appropriately */
309 1.1 hpeyerl ifp->if_flags |= IFF_RUNNING;
310 1.1 hpeyerl ifp->if_flags &= ~IFF_OACTIVE;
311 1.1 hpeyerl
312 1.1 hpeyerl /* And start output. */
313 1.1 hpeyerl el_start(ifp);
314 1.1 hpeyerl
315 1.1 hpeyerl splx(s);
316 1.1 hpeyerl }
317 1.1 hpeyerl
318 1.2 cgd /*
319 1.2 cgd * Start output on interface. Get datagrams from the queue and output
320 1.1 hpeyerl * them, giving the receiver a chance between datagrams. Call only
321 1.1 hpeyerl * from splimp or interrupt level!
322 1.1 hpeyerl */
323 1.1 hpeyerl static int
324 1.2 cgd el_start(ifp)
325 1.2 cgd struct ifnet *ifp;
326 1.1 hpeyerl {
327 1.1 hpeyerl struct el_softc *sc;
328 1.1 hpeyerl u_short base;
329 1.1 hpeyerl struct mbuf *m, *m0;
330 1.1 hpeyerl int s, i, len, retries, done;
331 1.1 hpeyerl
332 1.1 hpeyerl /* Get things pointing in the right directions */
333 1.1 hpeyerl sc = &el_softc[ifp->if_unit];
334 1.1 hpeyerl base = sc->el_base;
335 1.1 hpeyerl
336 1.1 hpeyerl dprintf(("el_start()...\n"));
337 1.1 hpeyerl s = splimp();
338 1.1 hpeyerl
339 1.1 hpeyerl /* Don't do anything if output is active */
340 1.2 cgd if (sc->arpcom.ac_if.if_flags & IFF_OACTIVE)
341 1.1 hpeyerl return;
342 1.1 hpeyerl sc->arpcom.ac_if.if_flags |= IFF_OACTIVE;
343 1.1 hpeyerl
344 1.1 hpeyerl /* The main loop. They warned me against endless loops, but
345 1.1 hpeyerl * would I listen? NOOO....
346 1.1 hpeyerl */
347 1.1 hpeyerl while(1) {
348 1.1 hpeyerl /* Dequeue the next datagram */
349 1.2 cgd IF_DEQUEUE(&sc->arpcom.ac_if.if_snd, m0);
350 1.1 hpeyerl
351 1.1 hpeyerl /* If there's nothing to send, return. */
352 1.2 cgd if (m0 == NULL) {
353 1.1 hpeyerl sc->arpcom.ac_if.if_flags &= ~IFF_OACTIVE;
354 1.1 hpeyerl splx(s);
355 1.1 hpeyerl return;
356 1.1 hpeyerl }
357 1.1 hpeyerl
358 1.1 hpeyerl /* Disable the receiver */
359 1.2 cgd outb(base+EL_AC, EL_AC_HOST);
360 1.2 cgd outb(base+EL_RBC, 0);
361 1.1 hpeyerl
362 1.1 hpeyerl /* Copy the datagram to the buffer. */
363 1.1 hpeyerl len = 0;
364 1.1 hpeyerl for(m = m0; m != NULL; m = m->m_next) {
365 1.2 cgd if (m->m_len == 0)
366 1.1 hpeyerl continue;
367 1.2 cgd bcopy(mtod(m, caddr_t), sc->el_pktbuf+len, m->m_len);
368 1.1 hpeyerl len += m->m_len;
369 1.1 hpeyerl }
370 1.1 hpeyerl m_freem(m0);
371 1.1 hpeyerl
372 1.2 cgd len = MAX(len, ETHER_MIN_LEN);
373 1.1 hpeyerl
374 1.1 hpeyerl /* Give the packet to the bpf, if any */
375 1.1 hpeyerl #if NBPFILTER > 0
376 1.2 cgd if (sc->bpf)
377 1.2 cgd bpf_tap(sc->bpf, sc->el_pktbuf, len);
378 1.1 hpeyerl #endif
379 1.1 hpeyerl
380 1.1 hpeyerl /* Transfer datagram to board */
381 1.2 cgd dprintf(("el: xfr pkt length=%d...\n", len));
382 1.1 hpeyerl i = EL_BUFSIZ - len;
383 1.2 cgd outb(base+EL_GPBL, (i & 0xff));
384 1.2 cgd outb(base+EL_GPBH, ((i>>8)&0xff));
385 1.2 cgd outsb(base+EL_BUF, sc->el_pktbuf, len);
386 1.1 hpeyerl
387 1.1 hpeyerl /* Now transmit the datagram */
388 1.1 hpeyerl retries=0;
389 1.1 hpeyerl done=0;
390 1.1 hpeyerl while(!done) {
391 1.2 cgd if (el_xmit(sc, len)) { /* Something went wrong */
392 1.1 hpeyerl done = -1;
393 1.1 hpeyerl break;
394 1.1 hpeyerl }
395 1.1 hpeyerl /* Check out status */
396 1.1 hpeyerl i = inb(base+EL_TXS);
397 1.2 cgd dprintf(("tx status=0x%x\n", i));
398 1.2 cgd if (!(i & EL_TXS_READY)) {
399 1.2 cgd dprintf(("el: err txs=%x\n", i));
400 1.1 hpeyerl sc->arpcom.ac_if.if_oerrors++;
401 1.2 cgd if (i & (EL_TXS_COLL|EL_TXS_COLL16)) {
402 1.2 cgd if ((!(i & EL_TXC_DCOLL16)) &&
403 1.2 cgd retries < 15) {
404 1.1 hpeyerl retries++;
405 1.2 cgd outb(base+EL_AC, EL_AC_HOST);
406 1.1 hpeyerl }
407 1.2 cgd } else
408 1.1 hpeyerl done = 1;
409 1.2 cgd } else
410 1.1 hpeyerl done = 1;
411 1.1 hpeyerl }
412 1.2 cgd if (done == -1) /* Packet not transmitted */
413 1.1 hpeyerl continue;
414 1.1 hpeyerl
415 1.2 cgd /*
416 1.2 cgd * Now give the card a chance to receive.
417 1.1 hpeyerl * Gotta love 3c501s...
418 1.1 hpeyerl */
419 1.1 hpeyerl (void)inb(base+EL_AS);
420 1.2 cgd outb(base+EL_AC, (EL_AC_IRQE|EL_AC_RX));
421 1.1 hpeyerl splx(s);
422 1.1 hpeyerl /* Interrupt here */
423 1.1 hpeyerl s = splimp();
424 1.1 hpeyerl }
425 1.1 hpeyerl }
426 1.1 hpeyerl
427 1.2 cgd /*
428 1.2 cgd * This function actually attempts to transmit a datagram downloaded
429 1.1 hpeyerl * to the board. Call at splimp or interrupt, after downloading data!
430 1.1 hpeyerl * Returns 0 on success, non-0 on failure
431 1.1 hpeyerl */
432 1.1 hpeyerl static int
433 1.2 cgd el_xmit(sc, len)
434 1.2 cgd struct el_softc *sc;
435 1.2 cgd int len;
436 1.1 hpeyerl {
437 1.1 hpeyerl int gpl;
438 1.1 hpeyerl int i;
439 1.1 hpeyerl
440 1.1 hpeyerl gpl = EL_BUFSIZ - len;
441 1.1 hpeyerl dprintf(("el: xmit..."));
442 1.2 cgd outb((sc->el_base)+EL_GPBL, (gpl & 0xff));
443 1.2 cgd outb((sc->el_base)+EL_GPBH, ((gpl>>8)&0xff));
444 1.2 cgd outb((sc->el_base)+EL_AC, EL_AC_TXFRX);
445 1.1 hpeyerl i = 20000;
446 1.1 hpeyerl while((inb((sc->el_base)+EL_AS) & EL_AS_TXBUSY) && (i>0))
447 1.1 hpeyerl i--;
448 1.2 cgd if (i == 0) {
449 1.1 hpeyerl dprintf(("tx not ready\n"));
450 1.1 hpeyerl sc->arpcom.ac_if.if_oerrors++;
451 1.1 hpeyerl return(-1);
452 1.1 hpeyerl }
453 1.2 cgd dprintf(("%d cycles.\n", (20000-i)));
454 1.1 hpeyerl return(0);
455 1.1 hpeyerl }
456 1.1 hpeyerl
457 1.1 hpeyerl /* controller interrupt */
458 1.1 hpeyerl int
459 1.2 cgd elintr(unit)
460 1.2 cgd int unit;
461 1.1 hpeyerl {
462 1.1 hpeyerl register struct el_softc *sc;
463 1.1 hpeyerl register base;
464 1.1 hpeyerl int stat, rxstat, len, done;
465 1.1 hpeyerl
466 1.1 hpeyerl /* Get things pointing properly */
467 1.1 hpeyerl sc = &el_softc[unit];
468 1.1 hpeyerl base = sc->el_base;
469 1.1 hpeyerl
470 1.1 hpeyerl dprintf(("elintr: "));
471 1.1 hpeyerl
472 1.1 hpeyerl /* Check board status */
473 1.1 hpeyerl stat = inb(base+EL_AS);
474 1.2 cgd if (stat & EL_AS_RXBUSY) {
475 1.1 hpeyerl (void)inb(base+EL_RXC);
476 1.2 cgd outb(base+EL_AC, (EL_AC_IRQE|EL_AC_RX));
477 1.1 hpeyerl return;
478 1.1 hpeyerl }
479 1.1 hpeyerl
480 1.1 hpeyerl done = 0;
481 1.1 hpeyerl while(!done) {
482 1.1 hpeyerl rxstat = inb(base+EL_RXS);
483 1.2 cgd if (rxstat & EL_RXS_STALE) {
484 1.1 hpeyerl (void)inb(base+EL_RXC);
485 1.2 cgd outb(base+EL_AC, (EL_AC_IRQE|EL_AC_RX));
486 1.1 hpeyerl return;
487 1.1 hpeyerl }
488 1.1 hpeyerl
489 1.1 hpeyerl /* If there's an overflow, reinit the board. */
490 1.2 cgd if (!(rxstat & EL_RXS_NOFLOW)) {
491 1.1 hpeyerl dprintf(("overflow.\n"));
492 1.2 cgd outb(base+EL_AC, EL_AC_RESET);
493 1.1 hpeyerl DELAY(5);
494 1.2 cgd outb(base+EL_AC, 0);
495 1.1 hpeyerl /* Put board back into receive mode */
496 1.2 cgd if (sc->arpcom.ac_if.if_flags & IFF_PROMISC)
497 1.2 cgd outb(base+EL_RXC, (EL_RXC_PROMISC|EL_RXC_AGF|EL_RXC_DSHORT|EL_RXC_DDRIB|EL_RXC_DOFLOW));
498 1.1 hpeyerl else
499 1.2 cgd outb(base+EL_RXC, (EL_RXC_ABROAD|EL_RXC_AGF|EL_RXC_DSHORT|EL_RXC_DDRIB|EL_RXC_DOFLOW));
500 1.1 hpeyerl (void)inb(base+EL_AS);
501 1.2 cgd outb(base+EL_RBC, 0);
502 1.1 hpeyerl (void)inb(base+EL_RXC);
503 1.2 cgd outb(base+EL_AC, (EL_AC_IRQE|EL_AC_RX));
504 1.1 hpeyerl return;
505 1.1 hpeyerl }
506 1.1 hpeyerl
507 1.1 hpeyerl /* Incoming packet */
508 1.1 hpeyerl len = inb(base+EL_RBL);
509 1.1 hpeyerl len |= inb(base+EL_RBH) << 8;
510 1.2 cgd dprintf(("receive len=%d rxstat=%x ", len, rxstat));
511 1.2 cgd outb(base+EL_AC, EL_AC_HOST);
512 1.1 hpeyerl
513 1.2 cgd /*
514 1.2 cgd * If packet too short or too long, restore rx mode and return
515 1.1 hpeyerl */
516 1.2 cgd if ((len <= sizeof(struct ether_header)) ||
517 1.2 cgd (len > ETHER_MAX_LEN)) {
518 1.2 cgd if (sc->arpcom.ac_if.if_flags & IFF_PROMISC)
519 1.2 cgd outb(base+EL_RXC, (EL_RXC_PROMISC|EL_RXC_AGF|EL_RXC_DSHORT|EL_RXC_DDRIB|EL_RXC_DOFLOW));
520 1.1 hpeyerl else
521 1.2 cgd outb(base+EL_RXC, (EL_RXC_ABROAD|EL_RXC_AGF|EL_RXC_DSHORT|EL_RXC_DDRIB|EL_RXC_DOFLOW));
522 1.1 hpeyerl (void)inb(base+EL_AS);
523 1.2 cgd outb(base+EL_RBC, 0);
524 1.1 hpeyerl (void)inb(base+EL_RXC);
525 1.2 cgd outb(base+EL_AC, (EL_AC_IRQE|EL_AC_RX));
526 1.1 hpeyerl return;
527 1.1 hpeyerl }
528 1.1 hpeyerl
529 1.1 hpeyerl sc->arpcom.ac_if.if_ipackets++;
530 1.1 hpeyerl
531 1.1 hpeyerl /* Copy the data into our buffer */
532 1.2 cgd outb(base+EL_GPBL, 0);
533 1.2 cgd outb(base+EL_GPBH, 0);
534 1.2 cgd insb(base+EL_BUF, sc->el_pktbuf, len);
535 1.2 cgd outb(base+EL_RBC, 0);
536 1.2 cgd outb(base+EL_AC, EL_AC_RX);
537 1.2 cgd dprintf(("%s-->", ether_sprintf(sc->el_pktbuf+6)));
538 1.2 cgd dprintf(("%s\n", ether_sprintf(sc->el_pktbuf)));
539 1.1 hpeyerl
540 1.1 hpeyerl /* Pass data up to upper levels */
541 1.1 hpeyerl len -= sizeof(struct ether_header);
542 1.2 cgd elread(sc, (caddr_t)(sc->el_pktbuf), len);
543 1.1 hpeyerl
544 1.1 hpeyerl /* Is there another packet? */
545 1.1 hpeyerl stat = inb(base+EL_AS);
546 1.1 hpeyerl
547 1.1 hpeyerl /* If so, do it all again (i.e. don't set done to 1) */
548 1.2 cgd if (!(stat & EL_AS_RXBUSY))
549 1.1 hpeyerl dprintf(("<rescan> "));
550 1.1 hpeyerl else
551 1.1 hpeyerl done = 1;
552 1.1 hpeyerl }
553 1.1 hpeyerl
554 1.1 hpeyerl (void)inb(base+EL_RXC);
555 1.2 cgd outb(base+EL_AC, (EL_AC_IRQE|EL_AC_RX));
556 1.1 hpeyerl return;
557 1.1 hpeyerl }
558 1.1 hpeyerl
559 1.2 cgd /*
560 1.2 cgd * Pass a packet up to the higher levels. Deal with trailer protocol.
561 1.2 cgd */
562 1.1 hpeyerl static inline void
563 1.2 cgd elread(sc, buf, len)
564 1.2 cgd struct el_softc *sc;
565 1.2 cgd caddr_t buf;
566 1.2 cgd int len;
567 1.1 hpeyerl {
568 1.1 hpeyerl register struct ether_header *eh;
569 1.1 hpeyerl struct mbuf *m;
570 1.1 hpeyerl int off, resid;
571 1.2 cgd u_short et;
572 1.1 hpeyerl
573 1.2 cgd /*
574 1.2 cgd * Deal with trailer protocol: if type is trailer type
575 1.1 hpeyerl * get true type from first 16-bit word past data.
576 1.1 hpeyerl * Remember that type was trailer by setting off.
577 1.1 hpeyerl */
578 1.1 hpeyerl eh = (struct ether_header *)buf;
579 1.2 cgd et = ntohs(eh->ether_type);
580 1.2 cgd #define eldataaddr(eh, off, type) ((type)(((caddr_t)((eh)+1)+(off))))
581 1.2 cgd if (et >= ETHERTYPE_TRAIL && et < ETHERTYPE_TRAIL+ETHERTYPE_NTRAILER) {
582 1.2 cgd off = (et - ETHERTYPE_TRAIL) * 512;
583 1.2 cgd if (off >= ETHERMTU)
584 1.1 hpeyerl return;
585 1.2 cgd /* next few lines are rather icky. XXX - cgd */
586 1.2 cgd eh->ether_type = *eldataaddr(eh, off, u_short *);
587 1.2 cgd resid = ntohs(*(eldataaddr(eh, off+2, u_short *)));
588 1.2 cgd if ((off+resid) > len)
589 1.1 hpeyerl return;
590 1.1 hpeyerl len = off + resid;
591 1.2 cgd } else
592 1.1 hpeyerl off = 0;
593 1.1 hpeyerl
594 1.2 cgd if (len <= 0)
595 1.1 hpeyerl return;
596 1.1 hpeyerl
597 1.1 hpeyerl #if NBPFILTER > 0
598 1.1 hpeyerl /*
599 1.1 hpeyerl * Check if there's a bpf filter listening on this interface.
600 1.1 hpeyerl * If so, hand off the raw packet to bpf, which must deal with
601 1.1 hpeyerl * trailers in its own way.
602 1.2 cgd *
603 1.2 cgd * comparing to if_ed, this code does bpf on trailer
604 1.2 cgd * packets incorrectly -- the ether type's already
605 1.2 cgd * been copied over... XXX - cgd
606 1.1 hpeyerl */
607 1.2 cgd if (sc->bpf) {
608 1.2 cgd bpf_tap(sc->bpf, buf, (len+sizeof(struct ether_header));
609 1.1 hpeyerl
610 1.1 hpeyerl /*
611 1.1 hpeyerl * Note that the interface cannot be in promiscuous mode if
612 1.1 hpeyerl * there are no bpf listeners. And if el are in promiscuous
613 1.1 hpeyerl * mode, el have to check if this packet is really ours.
614 1.1 hpeyerl *
615 1.1 hpeyerl * This test does not support multicasts.
616 1.1 hpeyerl */
617 1.2 cgd if ((sc->arpcom.ac_if.if_flags & IFF_PROMISC)
618 1.2 cgd && bcmp(eh->ether_dhost, sc->arpcom.ac_enaddr,
619 1.1 hpeyerl sizeof(eh->ether_dhost)) != 0
620 1.2 cgd && bcmp(eh->ether_dhost, etherbroadcastaddr,
621 1.1 hpeyerl sizeof(eh->ether_dhost)) != 0)
622 1.1 hpeyerl return;
623 1.1 hpeyerl }
624 1.1 hpeyerl #endif
625 1.1 hpeyerl
626 1.1 hpeyerl /*
627 1.1 hpeyerl * Pull packet off interface. Off is nonzero if packet
628 1.1 hpeyerl * has trailing header; neget will then force this header
629 1.1 hpeyerl * information to be at the front, but we still have to drop
630 1.1 hpeyerl * the type and length which are at the front of any trailer data.
631 1.1 hpeyerl */
632 1.2 cgd m = elget(buf, len, off, &sc->arpcom.ac_if);
633 1.2 cgd if (m == 0)
634 1.1 hpeyerl return;
635 1.1 hpeyerl
636 1.2 cgd ether_input(&sc->arpcom.ac_if, eh, m);
637 1.1 hpeyerl }
638 1.1 hpeyerl
639 1.1 hpeyerl /*
640 1.1 hpeyerl * Pull read data off a interface.
641 1.1 hpeyerl * Len is length of data, with local net header stripped.
642 1.1 hpeyerl * Off is non-zero if a trailer protocol was used, and
643 1.1 hpeyerl * gives the offset of the trailer information.
644 1.1 hpeyerl * We copy the trailer information and then all the normal
645 1.1 hpeyerl * data into mbufs. When full cluster sized units are present
646 1.1 hpeyerl * we copy into clusters.
647 1.1 hpeyerl */
648 1.1 hpeyerl struct mbuf *
649 1.1 hpeyerl elget(buf, totlen, off0, ifp)
650 1.1 hpeyerl caddr_t buf;
651 1.1 hpeyerl int totlen, off0;
652 1.1 hpeyerl struct ifnet *ifp;
653 1.1 hpeyerl {
654 1.1 hpeyerl struct mbuf *top, **mp, *m, *p;
655 1.1 hpeyerl int off = off0, len;
656 1.1 hpeyerl register caddr_t cp = buf;
657 1.1 hpeyerl char *epkt;
658 1.1 hpeyerl
659 1.1 hpeyerl buf += sizeof(struct ether_header);
660 1.1 hpeyerl cp = buf;
661 1.1 hpeyerl epkt = cp + totlen;
662 1.1 hpeyerl
663 1.1 hpeyerl if (off) {
664 1.1 hpeyerl cp += off + 2 * sizeof(u_short);
665 1.1 hpeyerl totlen -= 2 * sizeof(u_short);
666 1.1 hpeyerl }
667 1.1 hpeyerl
668 1.1 hpeyerl MGETHDR(m, M_DONTWAIT, MT_DATA);
669 1.1 hpeyerl if (m == 0)
670 1.1 hpeyerl return (0);
671 1.1 hpeyerl m->m_pkthdr.rcvif = ifp;
672 1.1 hpeyerl m->m_pkthdr.len = totlen;
673 1.1 hpeyerl m->m_len = MHLEN;
674 1.1 hpeyerl top = 0;
675 1.1 hpeyerl mp = ⊤
676 1.1 hpeyerl while (totlen > 0) {
677 1.1 hpeyerl if (top) {
678 1.1 hpeyerl MGET(m, M_DONTWAIT, MT_DATA);
679 1.1 hpeyerl if (m == 0) {
680 1.1 hpeyerl m_freem(top);
681 1.1 hpeyerl return (0);
682 1.1 hpeyerl }
683 1.1 hpeyerl m->m_len = MLEN;
684 1.1 hpeyerl }
685 1.1 hpeyerl len = min(totlen, epkt - cp);
686 1.1 hpeyerl if (len >= MINCLSIZE) {
687 1.1 hpeyerl MCLGET(m, M_DONTWAIT);
688 1.1 hpeyerl if (m->m_flags & M_EXT)
689 1.1 hpeyerl m->m_len = len = min(len, MCLBYTES);
690 1.1 hpeyerl else
691 1.1 hpeyerl len = m->m_len;
692 1.1 hpeyerl } else {
693 1.1 hpeyerl /*
694 1.1 hpeyerl * Place initial small packet/header at end of mbuf.
695 1.1 hpeyerl */
696 1.1 hpeyerl if (len < m->m_len) {
697 1.1 hpeyerl if (top == 0 && len + max_linkhdr <= m->m_len)
698 1.1 hpeyerl m->m_data += max_linkhdr;
699 1.1 hpeyerl m->m_len = len;
700 1.1 hpeyerl } else
701 1.1 hpeyerl len = m->m_len;
702 1.1 hpeyerl }
703 1.1 hpeyerl bcopy(cp, mtod(m, caddr_t), (unsigned)len);
704 1.1 hpeyerl cp += len;
705 1.1 hpeyerl *mp = m;
706 1.1 hpeyerl mp = &m->m_next;
707 1.1 hpeyerl totlen -= len;
708 1.1 hpeyerl if (cp == epkt)
709 1.1 hpeyerl cp = buf;
710 1.1 hpeyerl }
711 1.1 hpeyerl return (top);
712 1.1 hpeyerl }
713 1.1 hpeyerl
714 1.1 hpeyerl /*
715 1.1 hpeyerl * Process an ioctl request. This code needs some work - it looks
716 1.2 cgd * pretty ugly. (XXX? - cgd)
717 1.1 hpeyerl */
718 1.1 hpeyerl static int
719 1.1 hpeyerl el_ioctl(ifp, command, data)
720 1.1 hpeyerl register struct ifnet *ifp;
721 1.1 hpeyerl int command;
722 1.1 hpeyerl caddr_t data;
723 1.1 hpeyerl {
724 1.1 hpeyerl register struct ifaddr *ifa = (struct ifaddr *)data;
725 1.1 hpeyerl struct el_softc *sc = &el_softc[ifp->if_unit];
726 1.1 hpeyerl struct ifreq *ifr = (struct ifreq *)data;
727 1.1 hpeyerl int s, error = 0;
728 1.1 hpeyerl
729 1.1 hpeyerl s = splimp();
730 1.1 hpeyerl
731 1.1 hpeyerl switch (command) {
732 1.1 hpeyerl
733 1.1 hpeyerl case SIOCSIFADDR:
734 1.1 hpeyerl ifp->if_flags |= IFF_UP;
735 1.1 hpeyerl
736 1.1 hpeyerl switch (ifa->ifa_addr->sa_family) {
737 1.1 hpeyerl #ifdef INET
738 1.1 hpeyerl case AF_INET:
739 1.1 hpeyerl el_init(ifp->if_unit); /* before arpwhohas */
740 1.1 hpeyerl /*
741 1.1 hpeyerl * See if another station has *our* IP address.
742 1.1 hpeyerl * i.e.: There is an address conflict! If a
743 1.1 hpeyerl * conflict exists, a message is sent to the
744 1.1 hpeyerl * console.
745 1.1 hpeyerl */
746 1.1 hpeyerl ((struct arpcom *)ifp)->ac_ipaddr = IA_SIN(ifa)->sin_addr;
747 1.1 hpeyerl arpwhohas((struct arpcom *)ifp, &IA_SIN(ifa)->sin_addr);
748 1.1 hpeyerl break;
749 1.1 hpeyerl #endif
750 1.1 hpeyerl #ifdef NS
751 1.1 hpeyerl /*
752 1.2 cgd * XXX - This code is probably wrong (XXX? - cgd)
753 1.1 hpeyerl */
754 1.1 hpeyerl case AF_NS:
755 1.2 cgd {
756 1.2 cgd register struct ns_addr *ina =
757 1.2 cgd &(IA_SNS(ifa)->sns_addr);
758 1.2 cgd
759 1.2 cgd if (ns_nullhost(*ina))
760 1.2 cgd ina->x_host = *(union ns_host *)
761 1.2 cgd (sc->arpcom.ac_enaddr);
762 1.2 cgd else {
763 1.2 cgd /*
764 1.2 cgd *
765 1.2 cgd */
766 1.2 cgd bcopy((caddr_t)ina->x_host.c_host,
767 1.2 cgd (caddr_t)sc->arpcom.ac_enaddr,
768 1.2 cgd sizeof(sc->arpcom.ac_enaddr));
769 1.2 cgd }
770 1.2 cgd /*
771 1.2 cgd * Set new address
772 1.1 hpeyerl */
773 1.2 cgd el_init(ifp->if_unit);
774 1.2 cgd break;
775 1.1 hpeyerl }
776 1.1 hpeyerl #endif
777 1.1 hpeyerl default:
778 1.1 hpeyerl el_init(ifp->if_unit);
779 1.1 hpeyerl break;
780 1.1 hpeyerl }
781 1.1 hpeyerl break;
782 1.1 hpeyerl
783 1.1 hpeyerl case SIOCGIFADDR:
784 1.1 hpeyerl {
785 1.1 hpeyerl struct sockaddr *sa;
786 1.1 hpeyerl sa = (struct sockaddr *)&ifr->ifr_data;
787 1.1 hpeyerl bcopy((caddr_t)sc->arpcom.ac_enaddr,
788 1.1 hpeyerl (caddr_t) sa->sa_data, ETHER_ADDR_LEN);
789 1.1 hpeyerl }
790 1.1 hpeyerl break;
791 1.1 hpeyerl
792 1.1 hpeyerl case SIOCSIFFLAGS:
793 1.1 hpeyerl /*
794 1.1 hpeyerl * If interface is marked down and it is running, then stop it
795 1.1 hpeyerl */
796 1.1 hpeyerl if (((ifp->if_flags & IFF_UP) == 0) &&
797 1.1 hpeyerl (ifp->if_flags & IFF_RUNNING)) {
798 1.1 hpeyerl el_stop(ifp->if_unit);
799 1.1 hpeyerl ifp->if_flags &= ~IFF_RUNNING;
800 1.1 hpeyerl } else {
801 1.1 hpeyerl /*
802 1.1 hpeyerl * If interface is marked up and it is stopped, then start it
803 1.1 hpeyerl */
804 1.1 hpeyerl if ((ifp->if_flags & IFF_UP) &&
805 1.1 hpeyerl ((ifp->if_flags & IFF_RUNNING) == 0))
806 1.1 hpeyerl el_init(ifp->if_unit);
807 1.1 hpeyerl }
808 1.1 hpeyerl
809 1.1 hpeyerl default:
810 1.1 hpeyerl error = EINVAL;
811 1.1 hpeyerl }
812 1.1 hpeyerl (void) splx(s);
813 1.1 hpeyerl return (error);
814 1.1 hpeyerl }
815 1.1 hpeyerl
816 1.1 hpeyerl /* Device timeout routine */
817 1.1 hpeyerl static int
818 1.2 cgd el_watchdog(unit)
819 1.2 cgd int unit;
820 1.1 hpeyerl {
821 1.1 hpeyerl struct el_softc *sc;
822 1.1 hpeyerl
823 1.1 hpeyerl sc = &el_softc[unit];
824 1.1 hpeyerl
825 1.2 cgd log(LOG_ERR,"el%d: device timeout\n", unit);
826 1.1 hpeyerl sc->arpcom.ac_if.if_oerrors++;
827 1.2 cgd el_reset(unit, 0);
828 1.1 hpeyerl }
829 1.1 hpeyerl #endif
830