added my responsibility for the `cpm' port
[unix-history] / sys / i386 / isa / if_ie.c
CommitLineData
9f4e6350
RG
1/*-
2 * Copyright (c) 1992, 1993, University of Vermont and State
3 * Agricultural College.
4 * Copyright (c) 1992, 1993, Garrett A. Wollman.
5 *
6 * Portions:
7 * Copyright (c) 1990, 1991, William F. Jolitz
8 * Copyright (c) 1990, The Regents of the University of California
9 *
10 * All rights reserved.
11 *
12 * Redistribution and use in source and binary forms, with or without
13 * modification, are permitted provided that the following conditions
14 * are met:
15 * 1. Redistributions of source code must retain the above copyright
16 * notice, this list of conditions and the following disclaimer.
17 * 2. Redistributions in binary form must reproduce the above copyright
18 * notice, this list of conditions and the following disclaimer in the
19 * documentation and/or other materials provided with the distribution.
20 * 3. All advertising materials mentioning features or use of this software
21 * must display the following acknowledgement:
22 * This product includes software developed by the University of
23 * Vermont and State Agricultural College and Garrett A. Wollman,
24 * by William F. Jolitz, by the University of California,
25 * Berkeley, by Larwence Berkeley Laboratory, and its contributors.
26 * 4. Neither the names of the Universities nor the names of the authors
27 * may be used to endorse or promote products derived from this software
28 * without specific prior written permission.
29 *
30 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
31 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
32 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
33 * ARE DISCLAIMED. IN NO EVENT SHALL THE UNIVERSITY OR AUTHORS BE LIABLE
34 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
35 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
36 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
37 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
38 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
39 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
40 * SUCH DAMAGE.
41 *
a942b037 42 * $Id: if_ie.c,v 1.2 1993/11/25 01:31:36 wollman Exp $
9f4e6350
RG
43 */
44
45/*
46 * Intel 82586 Ethernet chip
47 * Register, bit, and structure definitions.
48 *
49 * Written by GAW with reference to the Clarkson Packet Driver code for this
50 * chip written by Russ Nelson and others.
51 *
52 * BPF support code stolen directly from hpdev/if_le.c, supplied with
53 * tcpdump.
54 */
55
56/*
57 * The i82586 is a very versatile chip, found in many implementations.
58 * Programming this chip is mostly the same, but certain details differ
59 * from card to card. This driver is written so that different cards
60 * can be automatically detected at run-time. Currently, only the
61 * AT&T EN100/StarLAN 10 series are supported.
62 */
63
64/*
65Mode of operation:
66
67We run the 82586 in a standard Ethernet mode. We keep NFRAMES received
68frame descriptors around for the receiver to use, and NBUFFS associated
69receive buffer descriptors, both in a circular list. Whenever a frame is
70received, we rotate both lists as necessary. (The 586 treats both lists
71as a simple queue.) We also keep a transmit command around so that packets
72can be sent off quickly.
73
74We configure the adapter in AL-LOC = 1 mode, which means that the
75Ethernet/802.3 MAC header is placed at the beginning of the receive buffer
76rather than being split off into various fields in the RFD. This also
77means that we must include this header in the transmit buffer as well.
78
79By convention, all transmit commands, and only transmit commands, shall
80have the I (IE_CMD_INTR) bit set in the command. This way, when an
81interrupt arrives at ieintr(), it is immediately possible to tell
82what precisely caused it. ANY OTHER command-sending routines should
83run at splimp(), and should post an acknowledgement to every interrupt
84they generate.
85
86The 82586 has a 24-bit address space internally, and the adaptor's
87memory is located at the top of this region. However, the value we are
88given in configuration is normally the *bottom* of the adaptor RAM. So,
89we must go through a few gyrations to come up with a kernel virtual address
90which represents the actual beginning of the 586 address space. First,
91we autosize the RAM by running through several possible sizes and trying
92to initialize the adapter under the assumption that the selected size
93is correct. Then, knowing the correct RAM size, we set up our pointers
94in ie_softc[unit]. `iomem' represents the computed base of the 586
95address space. `iomembot' represents the actual configured base
96of adapter RAM. Finally, `iosize' represents the calculated size
97of 586 RAM. Then, when laying out commands, we use the interval
98[iomembot, iomembot + iosize); to make 24-pointers, we subtract
99iomem, and to make 16-pointers, we subtract iomem and and with 0xffff.
100
101*/
102
103#include "ie.h"
104#if NIE > 0
105
106#include "param.h"
107#include "systm.h"
108#include "mbuf.h"
9f4e6350
RG
109#include "protosw.h"
110#include "socket.h"
111#include "ioctl.h"
112#include "errno.h"
113#include "syslog.h"
114
115#include "net/if.h"
116#include "net/if_types.h"
117#include "net/if_dl.h"
9f4e6350
RG
118#include "net/route.h"
119
120#include "bpfilter.h"
121
122#ifdef INET
123#include "netinet/in.h"
124#include "netinet/in_systm.h"
125#include "netinet/in_var.h"
126#include "netinet/ip.h"
127#include "netinet/if_ether.h"
128#endif
129
130#ifdef NS
131#include "netns/ns.h"
132#include "netns/ns_if.h"
133#endif
134
135#include "i386/isa/isa.h"
9f4e6350
RG
136#include "i386/isa/isa_device.h"
137#include "i386/isa/ic/i82586.h"
138#include "i386/isa/if_iereg.h"
139#include "i386/isa/icu.h"
140
141#include "vm/vm.h"
142
143#if NBPFILTER > 0
144#include "net/bpf.h"
145#include "net/bpfdesc.h"
146#endif
147
148#if (NBPFILTER > 0) || defined(MULTICAST)
149#define FILTER
150static struct mbuf *last_not_for_us;
151#endif
152
153#ifdef DEBUG
154#define IED_RINT 1
155#define IED_TINT 2
156#define IED_RNR 4
157#define IED_CNA 8
158#define IED_READFRAME 16
159int ie_debug = IED_RNR;
160#endif
161
162#ifndef ETHERMINLEN
163#define ETHERMINLEN 60
164#endif
165
166#define IE_BUF_LEN 1512 /* length of transmit buffer */
167
168/* Forward declaration */
169struct ie_softc;
170
4c45483e
GW
171static int ieprobe(struct isa_device *dvp);
172static int ieattach(struct isa_device *dvp);
173static void ieinit(int unit);
174static int ieioctl(struct ifnet *ifp, int command, caddr_t data);
175static void iestart(struct ifnet *ifp);
9f4e6350
RG
176static void sl_reset_586(int unit);
177static void sl_chan_attn(int unit);
4c45483e 178static void iereset(int unit, int dummy);
9f4e6350
RG
179static void ie_readframe(int unit, struct ie_softc *ie, int bufno);
180static void ie_drop_packet_buffer(int unit, struct ie_softc *ie);
181static void sl_read_ether(int unit, unsigned char addr[6]);
182static void find_ie_mem_size(int unit);
183static int command_and_wait(int unit, int command, void volatile *pcmd, int);
184static int ierint(int unit, struct ie_softc *ie);
185static int ietint(int unit, struct ie_softc *ie);
186static int iernr(int unit, struct ie_softc *ie);
187static void start_receiver(int unit);
188static int ieget(int, struct ie_softc *, struct mbuf **,
189 struct ether_header *, int *);
190static caddr_t setup_rfa(caddr_t ptr, struct ie_softc *ie);
191static int mc_setup(int, caddr_t, volatile struct ie_sys_ctl_block *);
192#ifdef MULTICAST
193static void ie_mc_reset(int unit);
194#endif
195
196#ifdef DEBUG
197void print_rbd(volatile struct ie_recv_buf_desc *rbd);
198
199int in_ierint = 0;
200int in_ietint = 0;
201#endif
202
203/*
204 * This tells the autoconf code how to set us up.
205 */
206struct isa_driver iedriver = {
207 ieprobe, ieattach, "ie",
208};
209
210enum ie_hardware {
211 IE_STARLAN10,
212 IE_EN100,
213 IE_SLFIBER,
214 IE_UNKNOWN
215};
216
217const char *ie_hardware_names[] = {
218 "StarLAN 10",
219 "EN100",
220 "StarLAN Fiber",
221 "Unknown"
222};
223
224/*
225sizeof(iscp) == 1+1+2+4 == 8
226sizeof(scb) == 2+2+2+2+2+2+2+2 == 16
227NFRAMES * sizeof(rfd) == NFRAMES*(2+2+2+2+6+6+2+2) == NFRAMES*24 == 384
228sizeof(xmit_cmd) == 2+2+2+2+6+2 == 18
229sizeof(transmit buffer) == 1512
230sizeof(transmit buffer desc) == 8
231-----
2321946
233
234NBUFFS * sizeof(rbd) == NBUFFS*(2+2+4+2+2) == NBUFFS*12
235NBUFFS * IE_RBUF_SIZE == NBUFFS*256
236
237NBUFFS should be (16384 - 1946) / (256 + 12) == 14438 / 268 == 53
238
239With NBUFFS == 48, this leaves us 1574 bytes for another command or
240more buffers. Another transmit command would be 18+8+1512 == 1538
241---just barely fits!
242
243Obviously all these would have to be reduced for smaller memory sizes.
244With a larger memory, it would be possible to roughly double the number of
245both transmit and receive buffers.
246*/
247
248#define NFRAMES 16 /* number of frames to allow for receive */
249#define NBUFFS 48 /* number of buffers to allocate */
250#define IE_RBUF_SIZE 256 /* size of each buffer, MUST BE POWER OF TWO */
251
252/*
253 * Ethernet status, per interface.
254 */
255struct ie_softc {
256 struct arpcom arpcom;
257 void (*ie_reset_586)(int);
258 void (*ie_chan_attn)(int);
259 enum ie_hardware hard_type;
260 int hard_vers;
261
262 u_short port;
263 caddr_t iomem;
264 caddr_t iomembot;
265 unsigned iosize;
266
267 int want_mcsetup;
268 int promisc;
269 volatile struct ie_int_sys_conf_ptr *iscp;
270 volatile struct ie_sys_ctl_block *scb;
271 volatile struct ie_recv_frame_desc *rframes[NFRAMES];
272 volatile struct ie_recv_buf_desc *rbuffs[NBUFFS];
273 volatile char *cbuffs[NBUFFS];
274 int rfhead, rftail, rbhead, rbtail;
275
276 volatile struct ie_xmit_cmd *xmit_cmds[2];
277 volatile struct ie_xmit_buf *xmit_buffs[2];
278 int xmit_count;
279 u_char *xmit_cbuffs[2];
280
281 struct ie_en_addr mcast_addrs[MAXMCAST + 1];
282 int mcast_count;
283
284#if NBPFILTER > 0
285 caddr_t ie_bpf;
286#endif
287
288} ie_softc[NIE];
289
290#define MK_24(base, ptr) ((caddr_t)((u_long)ptr - (u_long)base))
291#define MK_16(base, ptr) ((u_short)(u_long)MK_24(base, ptr))
292
293#define PORT ie_softc[unit].port
294#define MEM ie_softc[unit].iomem
295
296
297int ieprobe(dvp)
298 struct isa_device *dvp;
299{
300 int unit = dvp->id_unit;
301 u_char c;
302
303 ie_softc[unit].port = dvp->id_iobase;
304 ie_softc[unit].iomembot = dvp->id_maddr;
305 ie_softc[unit].iomem = 0;
306
307 c = inb(PORT + IEATT_REVISION);
308 switch(SL_BOARD(c)) {
309 case SL10_BOARD:
310 ie_softc[unit].hard_type = IE_STARLAN10;
311 ie_softc[unit].ie_reset_586 = sl_reset_586;
312 ie_softc[unit].ie_chan_attn = sl_chan_attn;
313 break;
314 case EN100_BOARD:
315 ie_softc[unit].hard_type = IE_EN100;
316 ie_softc[unit].ie_reset_586 = sl_reset_586;
317 ie_softc[unit].ie_chan_attn = sl_chan_attn;
318 break;
319 case SLFIBER_BOARD:
320 ie_softc[unit].hard_type = IE_SLFIBER;
321 ie_softc[unit].ie_reset_586 = sl_reset_586;
322 ie_softc[unit].ie_chan_attn = sl_chan_attn;
323 break;
324
325 /*
326 * Anything else is not recognized or cannot be used.
327 */
328 default:
329 return 0;
330 }
331
332 ie_softc[unit].hard_vers = SL_REV(c);
333
334 /*
335 * Divine memory size on-board the card. Ususally 16k.
336 */
337 find_ie_mem_size(unit);
338
339 if(!ie_softc[unit].iosize) {
340 return 0;
341 }
342
343 dvp->id_msize = ie_softc[unit].iosize;
344
345 switch(ie_softc[unit].hard_type) {
346 case IE_EN100:
347 case IE_STARLAN10:
348 case IE_SLFIBER:
349 sl_read_ether(unit, ie_softc[unit].arpcom.ac_enaddr);
350 break;
351
352 default:
353 printf("ie%d: unknown AT&T board type code %d\n", unit,
354 ie_softc[unit].hard_type);
355 return 0;
356 }
357
358 return 1;
359}
360
361/*
362 * Taken almost exactly from Bill's if_is.c, then modified beyond recognition.
363 */
364int
365ieattach(dvp)
366 struct isa_device *dvp;
367{
368 int unit = dvp->id_unit;
369 struct ie_softc *ie = &ie_softc[unit];
370 struct ifnet *ifp = &ie->arpcom.ac_if;
371
372 ifp->if_unit = unit;
373 ifp->if_name = iedriver.name;
374 ifp->if_mtu = ETHERMTU;
375 printf("<%s R%d> ethernet address %s",
376 ie_hardware_names[ie_softc[unit].hard_type],
377 ie_softc[unit].hard_vers + 1,
378 ether_sprintf(ie->arpcom.ac_enaddr));
379
380 ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_NOTRAILERS;
381#ifdef MULTICAST
382 ifp->if_flags |= IFF_MULTICAST;
383#endif /* MULTICAST */
384
385 ifp->if_init = ieinit;
386 ifp->if_output = ether_output;
387 ifp->if_start = iestart;
388 ifp->if_ioctl = ieioctl;
389 ifp->if_reset = iereset;
390 ifp->if_type = IFT_ETHER;
391 ifp->if_addrlen = 6;
392 ifp->if_hdrlen = 14;
393
394#if NBPFILTER > 0
395 printf("\n");
396 bpfattach(&ie_softc[unit].ie_bpf, ifp, DLT_EN10MB,
397 sizeof(struct ether_header));
398#endif
399
400 if_attach(ifp);
401 {
402 struct ifaddr *ifa = ifp->if_addrlist;
403 struct sockaddr_dl *sdl;
404 while(ifa && ifa->ifa_addr && ifa->ifa_addr->sa_family != AF_LINK)
405 ifa = ifa->ifa_next;
406
4c45483e 407 if(!ifa || !ifa->ifa_addr) return 1;
9f4e6350
RG
408
409 /* Provide our ether address to the higher layers */
410 sdl = (struct sockaddr_dl *)ifa->ifa_addr;
411 sdl->sdl_type = IFT_ETHER;
412 sdl->sdl_alen = 6;
413 sdl->sdl_slen = 0;
414 bcopy(ie->arpcom.ac_enaddr, LLADDR(sdl), 6);
4c45483e 415 return 1;
9f4e6350
RG
416 }
417}
418
419/*
420 * What to do upon receipt of an interrupt.
421 */
422int ieintr(unit)
423 int unit;
424{
425 register struct ie_softc *ie = &ie_softc[unit];
426 register u_short status;
427
428 status = ie->scb->ie_status;
429
430loop:
431 if(status & (IE_ST_RECV | IE_ST_RNR)) {
432#ifdef DEBUG
433 in_ierint++;
434 if(ie_debug & IED_RINT)
435 printf("ie%d: rint\n", unit);
436#endif
437 ierint(unit, ie);
438#ifdef DEBUG
439 in_ierint--;
440#endif
441 }
442
443 if(status & IE_ST_DONE) {
444#ifdef DEBUG
445 in_ietint++;
446 if(ie_debug & IED_TINT)
447 printf("ie%d: tint\n", unit);
448#endif
449 ietint(unit, ie);
450#ifdef DEBUG
451 in_ietint--;
452#endif
453 }
454
455 if(status & IE_ST_RNR) {
456#ifdef DEBUG
457 if(ie_debug & IED_RNR)
458 printf("ie%d: rnr\n", unit);
459#endif
460 iernr(unit, ie);
461 }
462
463#ifdef DEBUG
464 if((status & IE_ST_ALLDONE)
465 && (ie_debug & IED_CNA))
466 printf("ie%d: cna\n", unit);
467#endif
468
469 /* Don't ack interrupts which we didn't receive */
470 ie_ack(ie->scb, IE_ST_WHENCE & status, unit, ie->ie_chan_attn);
471
472 if((status = ie->scb->ie_status) & IE_ST_WHENCE)
473 goto loop;
474
475 return unit;
476}
477
478/*
479 * Process a received-frame interrupt.
480 */
481static int ierint(unit, ie)
482 int unit;
483 struct ie_softc *ie;
484{
485 int i, status;
486 static int timesthru = 1024;
487
488 i = ie->rfhead;
489 while(1) {
490 status = ie->rframes[i]->ie_fd_status;
491
492 if((status & IE_FD_COMPLETE) && (status & IE_FD_OK)) {
493 ie->arpcom.ac_if.if_ipackets++;
494 if(!--timesthru) {
495 ie->arpcom.ac_if.if_ierrors += ie->scb->ie_err_crc + ie->scb->ie_err_align +
496 ie->scb->ie_err_resource + ie->scb->ie_err_overrun;
497 ie->scb->ie_err_crc = 0;
498 ie->scb->ie_err_align = 0;
499 ie->scb->ie_err_resource = 0;
500 ie->scb->ie_err_overrun = 0;
501 timesthru = 1024;
502 }
503 ie_readframe(unit, ie, i);
504 } else {
505 if(status & IE_FD_RNR) {
506 if(!(ie->scb->ie_status & IE_RU_READY)) {
507 ie->rframes[0]->ie_fd_next = MK_16(MEM, ie->rbuffs[0]);
508 ie->scb->ie_recv_list = MK_16(MEM, ie->rframes[0]);
509 command_and_wait(unit, IE_RU_START, 0, 0);
510 }
511 }
512 break;
513 }
514 i = (i + 1) % NFRAMES;
515 }
516 return 0;
517}
518
519/*
520 * Process a command-complete interrupt. These are only generated by
521 * the transmission of frames. This routine is deceptively simple, since
522 * most of the real work is done by iestart().
523 */
524static int ietint(unit, ie)
525 int unit;
526 struct ie_softc *ie;
527{
528 int status;
529 int i;
530
531 ie->arpcom.ac_if.if_timer = 0;
532 ie->arpcom.ac_if.if_flags &= ~IFF_OACTIVE;
533
534 for(i = 0; i < ie->xmit_count; i++) {
535 status = ie->xmit_cmds[i]->ie_xmit_status;
536
537 if(status & IE_XS_LATECOLL) {
538 printf("ie%d: late collision\n", unit);
539 ie->arpcom.ac_if.if_collisions++;
540 ie->arpcom.ac_if.if_oerrors++;
541 } else if(status & IE_XS_NOCARRIER) {
542 printf("ie%d: no carrier\n", unit);
543 ie->arpcom.ac_if.if_oerrors++;
544 } else if(status & IE_XS_LOSTCTS) {
545 printf("ie%d: lost CTS\n", unit);
546 ie->arpcom.ac_if.if_oerrors++;
547 } else if(status & IE_XS_UNDERRUN) {
548 printf("ie%d: DMA underrun\n", unit);
549 ie->arpcom.ac_if.if_oerrors++;
550 } else if(status & IE_XS_EXCMAX) {
551 printf("ie%d: too many collisions\n", unit);
552 ie->arpcom.ac_if.if_collisions += 16;
553 ie->arpcom.ac_if.if_oerrors++;
554 } else {
555 ie->arpcom.ac_if.if_opackets++;
556 ie->arpcom.ac_if.if_collisions += status & IE_XS_MAXCOLL;
557 }
558 }
559 ie->xmit_count = 0;
560
561 /*
562 * If multicast addresses were added or deleted while we were transmitting,
563 * ie_mc_reset() set the want_mcsetup flag indicating that we should do it.
564 */
565 if(ie->want_mcsetup) {
566 mc_setup(unit, (caddr_t)ie->xmit_cbuffs[0], ie->scb);
567 ie->want_mcsetup = 0;
568 }
569
570 /* Wish I knew why this seems to be necessary... */
571 ie->xmit_cmds[0]->ie_xmit_status |= IE_STAT_COMPL;
572
573 iestart(&ie->arpcom.ac_if);
574 return 0; /* shouldn't be necessary */
575}
576
577/*
578 * Process a receiver-not-ready interrupt. I believe that we get these
579 * when there aren't enough buffers to go around. For now (FIXME), we
580 * just restart the receiver, and hope everything's ok.
581 */
582static int iernr(unit, ie)
583 int unit;
584 struct ie_softc *ie;
585{
586#ifdef doesnt_work
587 setup_rfa((caddr_t)ie->rframes[0], ie);
588
589 ie->scb->ie_recv_list = MK_16(MEM, ie_softc[unit].rframes[0]);
590 command_and_wait(unit, IE_RU_START, 0, 0);
591#else
592 /* This doesn't work either, but it doesn't hang either. */
593 command_and_wait(unit, IE_RU_DISABLE, 0, 0); /* just in case */
594 setup_rfa((caddr_t)ie->rframes[0], ie); /* ignore cast-qual */
595
596 ie->scb->ie_recv_list = MK_16(MEM, ie_softc[unit].rframes[0]);
597 command_and_wait(unit, IE_RU_START, 0, 0); /* was ENABLE */
598
599#endif
600 ie_ack(ie->scb, IE_ST_WHENCE, unit, ie->ie_chan_attn);
601
602 ie->arpcom.ac_if.if_ierrors++;
603 return 0;
604}
605
606#ifdef FILTER
607/*
608 * Compare two Ether/802 addresses for equality, inlined and
609 * unrolled for speed. I'd love to have an inline assembler
610 * version of this...
611 */
612static inline int ether_equal(u_char *one, u_char *two) {
613 if(one[0] != two[0]) return 0;
614 if(one[1] != two[1]) return 0;
615 if(one[2] != two[2]) return 0;
616 if(one[3] != two[3]) return 0;
617 if(one[4] != two[4]) return 0;
618 if(one[5] != two[5]) return 0;
619 return 1;
620}
621
622/*
623 * Check for a valid address. to_bpf is filled in with one of the following:
624 * 0 -> BPF doesn't get this packet
625 * 1 -> BPF does get this packet
626 * 2 -> BPF does get this packet, but we don't
627 * Return value is true if the packet is for us, and false otherwise.
628 *
629 * This routine is a mess, but it's also critical that it be as fast
630 * as possible. It could be made cleaner if we can assume that the
631 * only client which will fiddle with IFF_PROMISC is BPF. This is
632 * probably a good assumption, but we do not make it here. (Yet.)
633 */
634static inline int check_eh(struct ie_softc *ie,
635 struct ether_header *eh,
636 int *to_bpf) {
637 int i;
638
639 switch(ie->promisc) {
640 case IFF_ALLMULTI:
641 /*
642 * Receiving all multicasts, but no unicasts except those destined for us.
643 */
644#if NBPFILTER > 0
645 *to_bpf = (ie->ie_bpf != 0); /* BPF gets this packet if anybody cares */
646#endif
647 if(eh->ether_dhost[0] & 1) {
648 return 1;
649 }
650 if(ether_equal(eh->ether_dhost, ie->arpcom.ac_enaddr)) return 1;
651 return 0;
652
653 case IFF_PROMISC:
654 /*
655 * Receiving all packets. These need to be passed on to BPF.
656 */
657#if NBPFILTER > 0
658 *to_bpf = (ie->ie_bpf != 0);
659#endif
660 /* If for us, accept and hand up to BPF */
661 if(ether_equal(eh->ether_dhost, ie->arpcom.ac_enaddr)) return 1;
662
663#if NBPFILTER > 0
664 if(*to_bpf) *to_bpf = 2; /* we don't need to see it */
665#endif
666
667#ifdef MULTICAST
668 /*
669 * Not a multicast, so BPF wants to see it but we don't.
670 */
671 if(!(eh->ether_dhost[0] & 1)) return 1;
672
673 /*
674 * If it's one of our multicast groups, accept it and pass it
675 * up.
676 */
677 for(i = 0; i < ie->mcast_count; i++) {
678 if(ether_equal(eh->ether_dhost, (u_char *)&ie->mcast_addrs[i])) {
679#if NBPFILTER > 0
680 if(*to_bpf) *to_bpf = 1;
681#endif
682 return 1;
683 }
684 }
685#endif /* MULTICAST */
686 return 1;
687
688 case IFF_ALLMULTI | IFF_PROMISC:
689 /*
690 * Acting as a multicast router, and BPF running at the same time.
691 * Whew! (Hope this is a fast machine...)
692 */
693#if NBPFILTER > 0
694 *to_bpf = (ie->ie_bpf != 0);
695#endif
696 /* We want to see multicasts. */
697 if(eh->ether_dhost[0] & 1) return 1;
698
699 /* We want to see our own packets */
700 if(ether_equal(eh->ether_dhost, ie->arpcom.ac_enaddr)) return 1;
701
702 /* Anything else goes to BPF but nothing else. */
703#if NBPFILTER > 0
704 if(*to_bpf) *to_bpf = 2;
705#endif
706 return 1;
707
708 default:
709 /*
710 * Only accept unicast packets destined for us, or multicasts
711 * for groups that we belong to. For now, we assume that the
712 * '586 will only return packets that we asked it for. This
713 * isn't strictly true (it uses hashing for the multicast filter),
714 * but it will do in this case, and we want to get out of here
715 * as quickly as possible.
716 */
717#if NBPFILTER > 0
718 *to_bpf = (ie->ie_bpf != 0);
719#endif
720 return 1;
721 }
722 return 0;
723}
724#endif /* FILTER */
725
726/*
727 * We want to isolate the bits that have meaning... This assumes that
728 * IE_RBUF_SIZE is an even power of two. If somehow the act_len exceeds
729 * the size of the buffer, then we are screwed anyway.
730 */
731static inline int ie_buflen(struct ie_softc *ie, int head) {
732 return (ie->rbuffs[head]->ie_rbd_actual
733 & (IE_RBUF_SIZE | (IE_RBUF_SIZE - 1)));
734}
735
736static inline int ie_packet_len(int unit, struct ie_softc *ie) {
737 int i;
738 int head = ie->rbhead;
739 int acc = 0;
740
741 do {
742 if(!(ie->rbuffs[ie->rbhead]->ie_rbd_actual & IE_RBD_USED)) {
743#ifdef DEBUG
744 print_rbd(ie->rbuffs[ie->rbhead]);
745#endif
746 log(LOG_ERR, "ie%d: receive descriptors out of sync at %d\n",
747 unit, ie->rbhead);
748 iereset(unit, 0);
749 return -1;
750 }
751
752 i = ie->rbuffs[head]->ie_rbd_actual & IE_RBD_LAST;
753
754 acc += ie_buflen(ie, head);
755 head = (head + 1) % NBUFFS;
756 } while(!i);
757
758 return acc;
759}
760
761/*
762 * Read data off the interface, and turn it into an mbuf chain.
763 *
764 * This code is DRAMATICALLY different from the previous version; this
765 * version tries to allocate the entire mbuf chain up front, given the
766 * length of the data available. This enables us to allocate mbuf
767 * clusters in many situations where before we would have had a long
768 * chain of partially-full mbufs. This should help to speed up the
769 * operation considerably. (Provided that it works, of course.)
770 */
771static inline int ieget(unit, ie, mp, ehp, to_bpf)
772 int unit;
773 struct ie_softc *ie;
774 struct mbuf **mp;
775 struct ether_header *ehp;
776 int *to_bpf;
777{
778 struct mbuf *m, *top, **mymp;
779 int i;
780 int offset;
781 int totlen, resid;
782 int thismboff;
783 int head;
784
785 totlen = ie_packet_len(unit, ie);
786 if(totlen <= 0) return -1;
787
788 i = ie->rbhead;
789
790 /*
791 * Snarf the Ethernet header.
792 */
793 bcopy((caddr_t)ie->cbuffs[i], (caddr_t)ehp, sizeof *ehp);
794 /* ignore cast-qual warning here */
795
796 /*
797 * As quickly as possible, check if this packet is for us.
798 * If not, don't waste a single cycle copying the rest of the
799 * packet in.
800 * This is only a consideration when FILTER is defined; i.e., when
801 * we are either running BPF or doing multicasting.
802 */
803#ifdef FILTER
804 if(!check_eh(ie, ehp, to_bpf)) {
805 ie_drop_packet_buffer(unit, ie);
806 ie->arpcom.ac_if.if_ierrors--; /* just this case, it's not an error */
807 return -1;
808 }
809#endif
810 totlen -= (offset = sizeof *ehp);
811
812 MGETHDR(*mp, M_DONTWAIT, MT_DATA);
813 if(!*mp) {
814 ie_drop_packet_buffer(unit, ie);
815 return -1;
816 }
817
818 m = *mp;
819 m->m_pkthdr.rcvif = &ie->arpcom.ac_if;
820 m->m_len = MHLEN;
821 resid = m->m_pkthdr.len = totlen;
822 top = 0;
823 mymp = &top;
824
825 /*
826 * This loop goes through and allocates mbufs for all the data we will
827 * be copying in. It does not actually do the copying yet.
828 */
829 do { /* while(resid > 0) */
830 /*
831 * Try to allocate an mbuf to hold the data that we have. If we
832 * already allocated one, just get another one and stick it on the
833 * end (eventually). If we don't already have one, try to allocate
834 * an mbuf cluster big enough to hold the whole packet, if we think it's
835 * reasonable, or a single mbuf which may or may not be big enough.
836 * Got that?
837 */
838 if(top) {
839 MGET(m, M_DONTWAIT, MT_DATA);
840 if(!m) {
841 m_freem(top);
842 ie_drop_packet_buffer(unit, ie);
843 return -1;
844 }
845 m->m_len = MLEN;
846 }
847
848 if(resid >= MINCLSIZE) {
849 MCLGET(m, M_DONTWAIT);
850 if(m->m_flags & M_EXT)
851 m->m_len = min(resid, MCLBYTES);
852 } else {
853 if(resid < m->m_len) {
854 if(!top && resid + max_linkhdr <= m->m_len)
855 m->m_data += max_linkhdr;
856 m->m_len = resid;
857 }
858 }
859 resid -= m->m_len;
860 *mymp = m;
861 mymp = &m->m_next;
862 } while(resid > 0);
863
864 resid = totlen;
865 m = top;
866 thismboff = 0;
867 head = ie->rbhead;
868
869 /*
870 * Now we take the mbuf chain (hopefully only one mbuf most of the
871 * time) and stuff the data into it. There are no possible failures
872 * at or after this point.
873 */
874 while(resid > 0) { /* while there's stuff left */
875 int thislen = ie_buflen(ie, head) - offset;
876
877 /*
878 * If too much data for the current mbuf, then fill the current one
879 * up, go to the next one, and try again.
880 */
881 if(thislen > m->m_len - thismboff) {
882 int newlen = m->m_len - thismboff;
883 bcopy((caddr_t)(ie->cbuffs[head] + offset),
884 mtod(m, caddr_t) + thismboff, (unsigned)newlen);
885 /* ignore cast-qual warning */
886 m = m->m_next;
887 thismboff = 0; /* new mbuf, so no offset */
888 offset += newlen; /* we are now this far into the packet */
889 resid -= newlen; /* so there is this much left to get */
890 continue;
891 }
892
893 /*
894 * If there is more than enough space in the mbuf to hold the
895 * contents of this buffer, copy everything in, advance pointers,
896 * and so on.
897 */
898 if(thislen < m->m_len - thismboff) {
899 bcopy((caddr_t)(ie->cbuffs[head] + offset), /* ignore warning */
900 mtod(m, caddr_t) + thismboff, (unsigned)thislen);
901 thismboff += thislen; /* we are this far into the mbuf */
902 resid -= thislen; /* and this much is left */
903 goto nextbuf;
904 }
905
906 /*
907 * Otherwise, there is exactly enough space to put this buffer's
908 * contents into the current mbuf. Do the combination of the above
909 * actions.
910 */
911 bcopy((caddr_t)(ie->cbuffs[head] + offset), /* ignore warning */
912 mtod(m, caddr_t) + thismboff, (unsigned)thislen);
913 m = m->m_next;
914 thismboff = 0; /* new mbuf, start at the beginning */
915 resid -= thislen; /* and we are this far through */
916
917 /*
918 * Advance all the pointers. We can get here from either of the
919 * last two cases, but never the first.
920 */
921nextbuf:
922 offset = 0;
923 ie->rbuffs[head]->ie_rbd_actual = 0;
924 ie->rbuffs[head]->ie_rbd_length |= IE_RBD_LAST;
925 ie->rbhead = head = (head + 1) % NBUFFS;
926 ie->rbuffs[ie->rbtail]->ie_rbd_length &= ~IE_RBD_LAST;
927 ie->rbtail = (ie->rbtail + 1) % NBUFFS;
928 }
929
930 /*
931 * Unless something changed strangely while we were doing the copy,
932 * we have now copied everything in from the shared memory.
933 * This means that we are done.
934 */
935 return 0;
936}
937
938/*
939 * Read frame NUM from unit UNIT (pre-cached as IE).
940 *
941 * This routine reads the RFD at NUM, and copies in the buffers from
942 * the list of RBD, then rotates the RBD and RFD lists so that the receiver
943 * doesn't start complaining. Trailers are DROPPED---there's no point
944 * in wasting time on confusing code to deal with them. Hopefully,
945 * this machine will never ARP for trailers anyway.
946 */
947static void ie_readframe(unit, ie, num)
948 int unit;
949 struct ie_softc *ie;
950 int num; /* frame number to read */
951{
952 struct ie_recv_frame_desc rfd;
953 struct mbuf *m = 0;
954 struct ether_header eh;
955#if NBPFILTER > 0
956 int bpf_gets_it = 0;
957#endif
958
959 bcopy((caddr_t)(ie->rframes[num]), &rfd, sizeof(struct ie_recv_frame_desc));
960
961 /* Immediately advance the RFD list, since we we have copied ours now. */
962 ie->rframes[num]->ie_fd_status = 0;
963 ie->rframes[num]->ie_fd_last |= IE_FD_LAST;
964 ie->rframes[ie->rftail]->ie_fd_last &= ~IE_FD_LAST;
965 ie->rftail = (ie->rftail + 1) % NFRAMES;
966 ie->rfhead = (ie->rfhead + 1) % NFRAMES;
967
968 if(rfd.ie_fd_status & IE_FD_OK) {
969 if(
970#if NBPFILTER > 0
971 ieget(unit, ie, &m, &eh, &bpf_gets_it)
972#else
973 ieget(unit, ie, &m, &eh, (int *)0)
974#endif
975 ) {
976 ie->arpcom.ac_if.if_ierrors++; /* this counts as an error */
977 return;
978 }
979 }
980
981#ifdef DEBUG
982 if(ie_debug & IED_READFRAME) {
983 printf("ie%d: frame from ether %s type %x\n", unit,
984 ether_sprintf(eh.ether_shost), (unsigned)eh.ether_type);
985 }
986 if(ntohs(eh.ether_type) > ETHERTYPE_TRAIL
987 && ntohs(eh.ether_type) < (ETHERTYPE_TRAIL + ETHERTYPE_NTRAILER))
988 printf("received trailer!\n");
989#endif
990
991 if(!m) return;
992
993#ifdef FILTER
994 if(last_not_for_us) {
995 m_freem(last_not_for_us);
996 last_not_for_us = 0;
997 }
998
999#if NBPFILTER > 0
1000 /*
1001 * Check for a BPF filter; if so, hand it up.
1002 * Note that we have to stick an extra mbuf up front, because
1003 * bpf_mtap expects to have the ether header at the front.
1004 * It doesn't matter that this results in an ill-formatted mbuf chain,
1005 * since BPF just looks at the data. (It doesn't try to free the mbuf,
1006 * tho' it will make a copy for tcpdump.)
1007 */
1008 if(bpf_gets_it) {
1009 struct mbuf m0;
1010 m0.m_len = sizeof eh;
1011 m0.m_data = (caddr_t)&eh;
1012 m0.m_next = m;
1013
1014 /* Pass it up */
1015 bpf_mtap(ie->ie_bpf, &m0);
1016 }
1017 /*
1018 * A signal passed up from the filtering code indicating that the
1019 * packet is intended for BPF but not for the protocol machinery.
1020 * We can save a few cycles by not handing it off to them.
1021 */
1022 if(bpf_gets_it == 2) {
1023 last_not_for_us = m;
1024 return;
1025 }
1026#endif /* NBPFILTER > 0 */
1027 /*
1028 * In here there used to be code to check destination addresses upon
1029 * receipt of a packet. We have deleted that code, and replaced it
1030 * with code to check the address much earlier in the cycle, before
1031 * copying the data in; this saves us valuable cycles when operating
1032 * as a multicast router or when using BPF.
1033 */
1034#endif /* FILTER */
1035
1036 eh.ether_type = ntohs(eh.ether_type);
1037
1038 /*
1039 * Finally pass this packet up to higher layers.
1040 */
1041 ether_input(&ie->arpcom.ac_if, &eh, m);
1042}
1043
1044static void ie_drop_packet_buffer(int unit, struct ie_softc *ie) {
1045 int i;
1046
1047 do {
1048 /*
1049 * This means we are somehow out of sync. So, we reset the
1050 * adapter.
1051 */
1052 if(!(ie->rbuffs[ie->rbhead]->ie_rbd_actual & IE_RBD_USED)) {
1053#ifdef DEBUG
1054 print_rbd(ie->rbuffs[ie->rbhead]);
1055#endif
1056 log(LOG_ERR, "ie%d: receive descriptors out of sync at %d\n",
1057 unit, ie->rbhead);
1058 iereset(unit, 0);
1059 return;
1060 }
1061
1062 i = ie->rbuffs[ie->rbhead]->ie_rbd_actual & IE_RBD_LAST;
1063
1064 ie->rbuffs[ie->rbhead]->ie_rbd_length |= IE_RBD_LAST;
1065 ie->rbuffs[ie->rbhead]->ie_rbd_actual = 0;
1066 ie->rbhead = (ie->rbhead + 1) % NBUFFS;
1067 ie->rbuffs[ie->rbtail]->ie_rbd_length &= ~IE_RBD_LAST;
1068 ie->rbtail = (ie->rbtail + 1) % NBUFFS;
1069 } while(!i);
1070}
1071
1072
1073/*
1074 * Start transmission on an interface.
1075 */
4c45483e
GW
1076static void
1077iestart(ifp)
1078 struct ifnet *ifp;
9f4e6350
RG
1079{
1080 struct ie_softc *ie = &ie_softc[ifp->if_unit];
1081 struct mbuf *m0, *m;
1082 unsigned char *buffer;
1083 u_short len;
1084 /* This is not really volatile, in this routine, but it makes gcc happy. */
1085 volatile u_short *bptr = &ie->scb->ie_command_list;
1086
1087 if(!(ifp->if_flags & IFF_RUNNING))
4c45483e 1088 return;
9f4e6350 1089 if(ifp->if_flags & IFF_OACTIVE)
4c45483e 1090 return;
9f4e6350
RG
1091
1092 do {
1093 IF_DEQUEUE(&ie->arpcom.ac_if.if_snd, m);
1094 if(!m)
1095 break;
1096
1097 buffer = ie->xmit_cbuffs[ie->xmit_count];
1098 len = 0;
1099
1100 for(m0 = m; m && len < IE_BUF_LEN; m = m->m_next) {
1101 bcopy(mtod(m, caddr_t), buffer, m->m_len);
1102 buffer += m->m_len;
1103 len += m->m_len;
1104 }
1105
1106 m_freem(m0);
1107 len = MAX(len, ETHERMINLEN);
1108
1109#if NBPFILTER > 0
1110 /*
1111 * See if bpf is listening on this interface, let it see the packet
1112 * before we commit it to the wire.
1113 */
1114 if(ie->ie_bpf)
1115 bpf_tap(ie->ie_bpf, ie->xmit_cbuffs[ie->xmit_count], len);
1116#endif
1117
1118 ie->xmit_buffs[ie->xmit_count]->ie_xmit_flags = IE_XMIT_LAST | len;
1119 ie->xmit_buffs[ie->xmit_count]->ie_xmit_next = 0xffff;
1120 ie->xmit_buffs[ie->xmit_count]->ie_xmit_buf =
1121 MK_24(ie->iomem, ie->xmit_cbuffs[ie->xmit_count]);
1122
1123 ie->xmit_cmds[ie->xmit_count]->com.ie_cmd_cmd = IE_CMD_XMIT;
1124 ie->xmit_cmds[ie->xmit_count]->ie_xmit_status = 0;
1125 ie->xmit_cmds[ie->xmit_count]->ie_xmit_desc =
1126 MK_16(ie->iomem, ie->xmit_buffs[ie->xmit_count]);
1127
1128 *bptr = MK_16(ie->iomem, ie->xmit_cmds[ie->xmit_count]);
1129 bptr = &ie->xmit_cmds[ie->xmit_count]->com.ie_cmd_link;
1130 ie->xmit_count++;
1131 } while(ie->xmit_count < 2);
1132
1133 /*
1134 * If we queued up anything for transmission, send it.
1135 */
1136 if(ie->xmit_count) {
1137 ie->xmit_cmds[ie->xmit_count - 1]->com.ie_cmd_cmd |=
1138 IE_CMD_LAST | IE_CMD_INTR;
1139
1140 /*
1141 * By passing the command pointer as a null, we tell
1142 * command_and_wait() to pretend that this isn't an action
1143 * command. I wish I understood what was happening here.
1144 */
1145 command_and_wait(ifp->if_unit, IE_CU_START, 0, 0);
1146 ifp->if_flags |= IFF_OACTIVE;
1147 }
1148
4c45483e 1149 return;
9f4e6350
RG
1150}
1151
1152/*
1153 * Check to see if there's an 82586 out there.
1154 */
1155int check_ie_present(unit, where, size)
1156 int unit;
1157 caddr_t where;
1158 unsigned size;
1159{
1160 volatile struct ie_sys_conf_ptr *scp;
1161 volatile struct ie_int_sys_conf_ptr *iscp;
1162 volatile struct ie_sys_ctl_block *scb;
1163 u_long realbase;
1164 int s;
1165
1166 s = splimp();
1167
1168 realbase = (u_long)where + size - (1 << 24);
1169
1170 scp = (volatile struct ie_sys_conf_ptr *)(realbase + IE_SCP_ADDR);
1171 bzero((char *)scp, sizeof *scp); /* ignore cast-qual */
1172
1173 /*
1174 * First we put the ISCP at the bottom of memory; this tests to make
1175 * sure that our idea of the size of memory is the same as the controller's.
1176 * This is NOT where the ISCP will be in normal operation.
1177 */
1178 iscp = (volatile struct ie_int_sys_conf_ptr *)where;
1179 bzero((char *)iscp, sizeof *iscp); /* ignore cast-qual */
1180
1181 scb = (volatile struct ie_sys_ctl_block *)where;
1182 bzero((char *)scb, sizeof *scb); /* ignore cast-qual */
1183
1184 scp->ie_bus_use = 0; /* 16-bit */
1185 scp->ie_iscp_ptr = (caddr_t)((volatile caddr_t)iscp - /* ignore cast-qual */
1186 (volatile caddr_t)realbase);
1187
1188 iscp->ie_busy = 1;
1189 iscp->ie_scb_offset = MK_16(realbase, scb) + 256;
1190
1191 (*ie_softc[unit].ie_reset_586)(unit);
1192 (*ie_softc[unit].ie_chan_attn)(unit);
1193
1194 DELAY(100); /* wait a while... */
1195
1196 if(iscp->ie_busy) {
1197 splx(s);
1198 return 0;
1199 }
1200
1201 /*
1202 * Now relocate the ISCP to its real home, and reset the controller
1203 * again.
1204 */
1205 iscp = (void *)Align((caddr_t)(realbase + IE_SCP_ADDR -
1206 sizeof(struct ie_int_sys_conf_ptr)));
1207 bzero((char *)iscp, sizeof *iscp); /* ignore cast-qual */
1208
1209 scp->ie_iscp_ptr = (caddr_t)((caddr_t)iscp - (caddr_t)realbase);
1210 /* ignore cast-qual */
1211
1212 iscp->ie_busy = 1;
1213 iscp->ie_scb_offset = MK_16(realbase, scb);
1214
1215 (*ie_softc[unit].ie_reset_586)(unit);
1216 (*ie_softc[unit].ie_chan_attn)(unit);
1217
1218 DELAY(100);
1219
1220 if(iscp->ie_busy) {
1221 splx(s);
1222 return 0;
1223 }
1224
1225 ie_softc[unit].iosize = size;
1226 ie_softc[unit].iomem = (caddr_t)realbase;
1227
1228 ie_softc[unit].iscp = iscp;
1229 ie_softc[unit].scb = scb;
1230
1231 /*
1232 * Acknowledge any interrupts we may have caused...
1233 */
1234 ie_ack(scb, IE_ST_WHENCE, unit, ie_softc[unit].ie_chan_attn);
1235 splx(s);
1236
1237 return 1;
1238}
1239
1240/*
1241 * Divine the memory size of ie board UNIT.
1242 * Better hope there's nothing important hiding just below the ie card...
1243 */
1244static void find_ie_mem_size(unit)
1245 int unit;
1246{
1247 unsigned size;
1248
1249 ie_softc[unit].iosize = 0;
1250
1251 for(size = 65536; size >= 16384; size -= 16384) {
1252 if(check_ie_present(unit, ie_softc[unit].iomembot, size)) {
1253 return;
1254 }
1255 }
1256
1257 return;
1258}
1259
1260void sl_reset_586(unit)
1261 int unit;
1262{
1263 outb(PORT + IEATT_RESET, 0);
1264}
1265
1266void sl_chan_attn(unit)
1267 int unit;
1268{
1269 outb(PORT + IEATT_ATTN, 0);
1270}
1271
1272void sl_read_ether(unit, addr)
1273 int unit;
1274 unsigned char addr[6];
1275{
1276 int i;
1277
1278 for(i = 0; i < 6; i++)
1279 addr[i] = inb(PORT + i);
1280}
1281
1282
4c45483e
GW
1283static void
1284iereset(unit, dummy)
1285 int unit, dummy;
9f4e6350
RG
1286{
1287 int s = splimp();
1288
1289 if(unit >= NIE) {
1290 splx(s);
4c45483e 1291 return;
9f4e6350
RG
1292 }
1293
1294 printf("ie%d: reset\n", unit);
1295 ie_softc[unit].arpcom.ac_if.if_flags &= ~IFF_UP;
1296 ieioctl(&ie_softc[unit].arpcom.ac_if, SIOCSIFFLAGS, 0);
1297
1298 /*
1299 * Stop i82586 dead in its tracks.
1300 */
1301 if(command_and_wait(unit, IE_RU_ABORT | IE_CU_ABORT, 0, 0))
1302 printf("ie%d: abort commands timed out\n", unit);
1303
1304 if(command_and_wait(unit, IE_RU_DISABLE | IE_CU_STOP, 0, 0))
1305 printf("ie%d: disable commands timed out\n", unit);
1306
1307#ifdef notdef
1308 if(!check_ie_present(unit, ie_softc[unit].iomembot, ie_softc[unit].iosize))
1309 panic("ie disappeared!\n");
1310#endif
1311
1312 ie_softc[unit].arpcom.ac_if.if_flags |= IFF_UP;
1313 ieioctl(&ie_softc[unit].arpcom.ac_if, SIOCSIFFLAGS, 0);
1314
1315 splx(s);
4c45483e 1316 return;
9f4e6350
RG
1317}
1318
1319/*
1320 * This is called if we time out.
1321 */
4c45483e
GW
1322static void
1323chan_attn_timeout(rock, arg2)
1324 caddr_t rock;
1325 int arg2;
9f4e6350
RG
1326{
1327 *(int *)rock = 1;
9f4e6350
RG
1328}
1329
1330/*
1331 * Send a command to the controller and wait for it to either
1332 * complete or be accepted, depending on the command. If the
1333 * command pointer is null, then pretend that the command is
1334 * not an action command. If the command pointer is not null,
1335 * and the command is an action command, wait for
1336 * ((volatile struct ie_cmd_common *)pcmd)->ie_cmd_status & MASK
1337 * to become true.
1338 */
1339static int command_and_wait(unit, cmd, pcmd, mask)
1340 int unit;
1341 int cmd;
1342 volatile void *pcmd;
1343 int mask;
1344{
1345 volatile struct ie_cmd_common *cc = pcmd;
1346 volatile int timedout = 0;
1347 extern int hz;
1348
1349 ie_softc[unit].scb->ie_command = (u_short)cmd;
1350
1351 if(IE_ACTION_COMMAND(cmd) && pcmd) {
1352 (*ie_softc[unit].ie_chan_attn)(unit);
1353
1354 /*
1355 * According to the packet driver, the minimum timeout should be
1356 * .369 seconds, which we round up to .37.
1357 */
1358 timeout(chan_attn_timeout, (caddr_t)&timedout, 37 * hz / 100);
1359 /* ignore cast-qual */
1360
1361 /*
1362 * Now spin-lock waiting for status. This is not a very nice
1363 * thing to do, but I haven't figured out how, or indeed if, we
1364 * can put the process waiting for action to sleep. (We may
1365 * be getting called through some other timeout running in the
1366 * kernel.)
1367 */
1368 while(1) {
1369 if((cc->ie_cmd_status & mask) || timedout)
1370 break;
1371 }
1372
1373 untimeout(chan_attn_timeout, (caddr_t)&timedout);
1374 /* ignore cast-qual */
1375
1376 return timedout;
1377 } else {
1378
1379 /*
1380 * Otherwise, just wait for the command to be accepted.
1381 */
1382 (*ie_softc[unit].ie_chan_attn)(unit);
1383
1384 while(ie_softc[unit].scb->ie_command)
1385 ; /* spin lock */
1386
1387 return 0;
1388 }
1389}
1390
1391/*
1392 * Run the time-domain reflectometer...
1393 */
1394static void run_tdr(unit, cmd)
1395 int unit;
1396 struct ie_tdr_cmd *cmd;
1397{
1398 int result;
1399
1400 cmd->com.ie_cmd_status = 0;
1401 cmd->com.ie_cmd_cmd = IE_CMD_TDR | IE_CMD_LAST;
1402 cmd->com.ie_cmd_link = 0xffff;
1403 cmd->ie_tdr_time = 0;
1404
1405 ie_softc[unit].scb->ie_command_list = MK_16(MEM, cmd);
1406 cmd->ie_tdr_time = 0;
1407
1408 if(command_and_wait(unit, IE_CU_START, cmd, IE_STAT_COMPL))
1409 result = 0x2000;
1410 else
1411 result = cmd->ie_tdr_time;
1412
1413 ie_ack(ie_softc[unit].scb, IE_ST_WHENCE, unit,
1414 ie_softc[unit].ie_chan_attn);
1415
1416 if(result & IE_TDR_SUCCESS)
1417 return;
1418
1419 if(result & IE_TDR_XCVR) {
1420 printf("ie%d: transceiver problem\n", unit);
1421 } else if(result & IE_TDR_OPEN) {
1422 printf("ie%d: TDR detected an open %d clocks away\n", unit,
1423 result & IE_TDR_TIME);
1424 } else if(result & IE_TDR_SHORT) {
1425 printf("ie%d: TDR detected a short %d clocks away\n", unit,
1426 result & IE_TDR_TIME);
1427 } else {
1428 printf("ie%d: TDR returned unknown status %x\n", result);
1429 }
1430}
1431
1432static void start_receiver(unit)
1433 int unit;
1434{
1435 int s = splimp();
1436
1437 ie_softc[unit].scb->ie_recv_list = MK_16(MEM, ie_softc[unit].rframes[0]);
1438 command_and_wait(unit, IE_RU_START, 0, 0);
1439
1440 ie_ack(ie_softc[unit].scb, IE_ST_WHENCE, unit, ie_softc[unit].ie_chan_attn);
1441
1442 splx(s);
1443}
1444
1445/*
1446 * Here is a helper routine for iernr() and ieinit(). This sets up
1447 * the RFA.
1448 */
1449static caddr_t setup_rfa(caddr_t ptr, struct ie_softc *ie) {
1450 volatile struct ie_recv_frame_desc *rfd = (void *)ptr;
1451 volatile struct ie_recv_buf_desc *rbd;
1452 int i;
1453 int unit = ie - &ie_softc[0];
1454
1455 /* First lay them out */
1456 for(i = 0; i < NFRAMES; i++) {
1457 ie->rframes[i] = rfd;
1458 bzero((char *)rfd, sizeof *rfd); /* ignore cast-qual */
1459 rfd++;
1460 }
1461
1462 ptr = (caddr_t)Align((caddr_t)rfd); /* ignore cast-qual */
1463
1464 /* Now link them together */
1465 for(i = 0; i < NFRAMES; i++) {
1466 ie->rframes[i]->ie_fd_next =
1467 MK_16(MEM, ie->rframes[(i + 1) % NFRAMES]);
1468 }
1469
1470 /* Finally, set the EOL bit on the last one. */
1471 ie->rframes[NFRAMES - 1]->ie_fd_last |= IE_FD_LAST;
1472
1473 /*
1474 * Now lay out some buffers for the incoming frames. Note that
1475 * we set aside a bit of slop in each buffer, to make sure that
1476 * we have enough space to hold a single frame in every buffer.
1477 */
1478 rbd = (void *)ptr;
1479
1480 for(i = 0; i < NBUFFS; i++) {
1481 ie->rbuffs[i] = rbd;
1482 bzero((char *)rbd, sizeof *rbd); /* ignore cast-qual */
1483 ptr = (caddr_t)Align(ptr + sizeof *rbd);
1484 rbd->ie_rbd_length = IE_RBUF_SIZE;
1485 rbd->ie_rbd_buffer = MK_24(MEM, ptr);
1486 ie->cbuffs[i] = (void *)ptr;
1487 ptr += IE_RBUF_SIZE;
1488 rbd = (void *)ptr;
1489 }
1490
1491 /* Now link them together */
1492 for(i = 0; i < NBUFFS; i++) {
1493 ie->rbuffs[i]->ie_rbd_next = MK_16(MEM, ie->rbuffs[(i + 1) % NBUFFS]);
1494 }
1495
1496 /* Tag EOF on the last one */
1497 ie->rbuffs[NBUFFS - 1]->ie_rbd_length |= IE_RBD_LAST;
1498
1499 /* We use the head and tail pointers on receive to keep track of
1500 * the order in which RFDs and RBDs are used. */
1501 ie->rfhead = 0;
1502 ie->rftail = NFRAMES - 1;
1503 ie->rbhead = 0;
1504 ie->rbtail = NBUFFS - 1;
1505
1506 ie->scb->ie_recv_list = MK_16(MEM, ie->rframes[0]);
1507 ie->rframes[0]->ie_fd_buf_desc = MK_16(MEM, ie->rbuffs[0]);
1508
1509 ptr = Align(ptr);
1510 return ptr;
1511}
1512
1513/*
1514 * Run the multicast setup command.
1515 * Call at splimp().
1516 */
1517static int mc_setup(int unit, caddr_t ptr,
1518 volatile struct ie_sys_ctl_block *scb) {
1519 struct ie_softc *ie = &ie_softc[unit];
1520 volatile struct ie_mcast_cmd *cmd = (void *)ptr;
1521
1522 cmd->com.ie_cmd_status = 0;
1523 cmd->com.ie_cmd_cmd = IE_CMD_MCAST | IE_CMD_LAST;
1524 cmd->com.ie_cmd_link = 0xffff;
1525
1526 /* ignore cast-qual */
1527 bcopy((caddr_t)ie->mcast_addrs, (caddr_t)cmd->ie_mcast_addrs,
1528 ie->mcast_count * sizeof *ie->mcast_addrs);
1529
1530 cmd->ie_mcast_bytes = ie->mcast_count * 6; /* grrr... */
1531
1532 scb->ie_command_list = MK_16(MEM, cmd);
1533 if(command_and_wait(unit, IE_CU_START, cmd, IE_STAT_COMPL)
1534 || !(cmd->com.ie_cmd_status & IE_STAT_OK)) {
1535 printf("ie%d: multicast address setup command failed\n", unit);
1536 return 0;
1537 }
1538 return 1;
1539}
1540
1541/*
1542 * This routine takes the environment generated by check_ie_present()
1543 * and adds to it all the other structures we need to operate the adapter.
1544 * This includes executing the CONFIGURE, IA-SETUP, and MC-SETUP commands,
1545 * starting the receiver unit, and clearing interrupts.
1546 *
1547 * THIS ROUTINE MUST BE CALLED AT splimp() OR HIGHER.
1548 */
4c45483e
GW
1549static void
1550ieinit(unit)
9f4e6350
RG
1551 int unit;
1552{
1553 struct ie_softc *ie = &ie_softc[unit];
1554 volatile struct ie_sys_ctl_block *scb = ie->scb;
1555 caddr_t ptr;
1556
1557 ptr = (caddr_t)Align((caddr_t)scb + sizeof *scb); /* ignore cast-qual */
1558
1559 /*
1560 * Send the configure command first.
1561 */
1562 {
1563 volatile struct ie_config_cmd *cmd = (void *)ptr;
1564
1565 ie_setup_config(cmd, ie->promisc, ie->hard_type == IE_STARLAN10);
1566 cmd->com.ie_cmd_status = 0;
1567 cmd->com.ie_cmd_cmd = IE_CMD_CONFIG | IE_CMD_LAST;
1568 cmd->com.ie_cmd_link = 0xffff;
1569
1570 scb->ie_command_list = MK_16(MEM, cmd);
1571
1572 if(command_and_wait(unit, IE_CU_START, cmd, IE_STAT_COMPL)
1573 || !(cmd->com.ie_cmd_status & IE_STAT_OK)) {
1574 printf("ie%d: configure command failed\n", unit);
4c45483e 1575 return;
9f4e6350
RG
1576 }
1577 }
1578 /*
1579 * Now send the Individual Address Setup command.
1580 */
1581 {
1582 volatile struct ie_iasetup_cmd *cmd = (void *)ptr;
1583
1584 cmd->com.ie_cmd_status = 0;
1585 cmd->com.ie_cmd_cmd = IE_CMD_IASETUP | IE_CMD_LAST;
1586 cmd->com.ie_cmd_link = 0xffff;
1587
1588 bcopy((char *)ie_softc[unit].arpcom.ac_enaddr, (char *)&cmd->ie_address,
1589 sizeof cmd->ie_address); /* ignore cast-qual */
1590
1591 scb->ie_command_list = MK_16(MEM, cmd);
1592 if(command_and_wait(unit, IE_CU_START, cmd, IE_STAT_COMPL)
1593 || !(cmd->com.ie_cmd_status & IE_STAT_OK)) {
1594 printf("ie%d: individual address setup command failed\n", unit);
4c45483e 1595 return;
9f4e6350
RG
1596 }
1597 }
1598
1599 /*
1600 * Now run the time-domain reflectometer.
1601 */
1602 run_tdr(unit, (void *)ptr);
1603
1604 /*
1605 * Acknowledge any interrupts we have generated thus far.
1606 */
1607 ie_ack(ie->scb, IE_ST_WHENCE, unit, ie->ie_chan_attn);
1608
1609 /*
1610 * Set up the RFA.
1611 */
1612 ptr = setup_rfa(ptr, ie);
1613
1614 /*
1615 * Finally, the transmit command and buffer are the last little bit of work.
1616 */
1617 ie->xmit_cmds[0] = (void *)ptr;
1618 ptr += sizeof *ie->xmit_cmds[0];
1619 ptr = Align(ptr);
1620 ie->xmit_buffs[0] = (void *)ptr;
1621 ptr += sizeof *ie->xmit_buffs[0];
1622 ptr = Align(ptr);
1623
1624 /* Second transmit command */
1625 ie->xmit_cmds[1] = (void *)ptr;
1626 ptr += sizeof *ie->xmit_cmds[1];
1627 ptr = Align(ptr);
1628 ie->xmit_buffs[1] = (void *)ptr;
1629 ptr += sizeof *ie->xmit_buffs[1];
1630 ptr = Align(ptr);
1631
1632 /* Both transmit buffers */
1633 ie->xmit_cbuffs[0] = (void *)ptr;
1634 ptr += IE_BUF_LEN;
1635 ptr = Align(ptr);
1636 ie->xmit_cbuffs[1] = (void *)ptr;
1637
1638 bzero((caddr_t)ie->xmit_cmds[0], sizeof *ie->xmit_cmds[0]); /* ignore */
1639 bzero((caddr_t)ie->xmit_buffs[0], sizeof *ie->xmit_buffs[0]); /* cast-qual */
1640 bzero((caddr_t)ie->xmit_cmds[1], sizeof *ie->xmit_cmds[0]); /* warnings */
1641 bzero((caddr_t)ie->xmit_buffs[1], sizeof *ie->xmit_buffs[0]); /* here */
1642
1643 /*
1644 * This must be coordinated with iestart() and ietint().
1645 */
1646 ie->xmit_cmds[0]->ie_xmit_status = IE_STAT_COMPL;
1647
1648 ie->arpcom.ac_if.if_flags |= IFF_RUNNING; /* tell higher levels that we are here */
1649 start_receiver(unit);
4c45483e 1650 return;
9f4e6350
RG
1651}
1652
1653static void ie_stop(unit)
1654 int unit;
1655{
1656 command_and_wait(unit, IE_RU_DISABLE, 0, 0);
1657}
1658
4c45483e
GW
1659static int
1660ieioctl(ifp, command, data)
1661 struct ifnet *ifp;
1662 int command;
1663 caddr_t data;
9f4e6350
RG
1664{
1665 struct ifaddr *ifa = (struct ifaddr *)data;
1666 struct ie_softc *ie = &ie_softc[ifp->if_unit];
1667 int s, error = 0;
1668
1669 s = splimp();
1670
1671 switch(command) {
1672 case SIOCSIFADDR:
1673 ifp->if_flags |= IFF_UP;
1674
1675 switch(ifa->ifa_addr->sa_family) {
1676#ifdef INET
1677 case AF_INET:
1678 ieinit(ifp->if_unit);
1679 ((struct arpcom *)ifp)->ac_ipaddr =
1680 IA_SIN(ifa)->sin_addr;
1681 arpwhohas((struct arpcom *)ifp, &IA_SIN(ifa)->sin_addr);
1682 break;
1683#endif /* INET */
1684
1685#ifdef NS
1686 /* This magic copied from if_is.c; I don't use XNS, so I have no
1687 * way of telling if this actually works or not.
1688 */
1689 case AF_NS:
1690 {
1691 struct ns_addr *ina = &(IA_SNS(ifa)->sns_addr);
1692
1693 if(ns_nullhost(*ina)) {
1694 ina->x_host = *(union ns_host *)(ie->arpcom.ac_enaddr);
1695 } else {
1696 ifp->if_flags &= ~IFF_RUNNING;
1697 bcopy((caddr_t)ina->x_host.c_host,
1698 (caddr_t)ie->arpcom.ac_enaddr,
1699 sizeof ie->arpcom.ac_enaddr);
1700 }
1701
1702 ieinit(ifp->if_unit);
1703 }
1704 break;
1705#endif /* NS */
1706
1707 default:
1708 ieinit(ifp->if_unit);
1709 break;
1710 }
1711 break;
1712
1713 case SIOCSIFFLAGS:
1714 /*
1715 * Note that this device doesn't have an "all multicast" mode, so we
1716 * must turn on promiscuous mode and do the filtering manually.
1717 */
1718 if((ifp->if_flags & IFF_UP) == 0 &&
1719 (ifp->if_flags & IFF_RUNNING)) {
1720 ifp->if_flags &= ~IFF_RUNNING;
1721 ie_stop(ifp->if_unit);
1722 } else if((ifp->if_flags & IFF_UP) &&
1723 (ifp->if_flags & IFF_RUNNING) == 0) {
1724 ie_softc[ifp->if_unit].promisc =
1725 ifp->if_flags & (IFF_PROMISC | IFF_ALLMULTI);
1726 ieinit(ifp->if_unit);
1727 } else if(ie_softc[ifp->if_unit].promisc ^
1728 (ifp->if_flags & (IFF_PROMISC | IFF_ALLMULTI))) {
1729 ie_softc[ifp->if_unit].promisc =
1730 ifp->if_flags & (IFF_PROMISC | IFF_ALLMULTI);
1731 ieinit(ifp->if_unit);
1732 }
1733 break;
1734
1735#ifdef MULTICAST
1736 case SIOCADDMULTI:
1737 case SIOCDELMULTI:
1738 /*
1739 * Update multicast listeners
1740 */
1741 error = ((command == SIOCADDMULTI)
1742 ? ether_addmulti((struct ifreq *)data, &ie->arpcom)
1743 : ether_delmulti((struct ifreq *)data, &ie->arpcom));
1744
1745 if(error == ENETRESET) {
1746 /* reset multicast filtering */
1747 ie_mc_reset(ifp->if_unit);
1748 error = 0;
1749 }
1750 break;
1751#endif /* MULTICAST */
1752
1753 default:
1754 error = EINVAL;
1755 }
1756
1757 splx(s);
1758 return error;
1759}
1760
1761#ifdef MULTICAST
1762static void ie_mc_reset(int unit) {
1763 struct ie_softc *ie = &ie_softc[unit];
1764 struct ether_multi *enm;
1765 struct ether_multistep step;
1766
1767 /*
1768 * Step through the list of addresses.
1769 */
1770 ie->mcast_count = 0;
1771 ETHER_FIRST_MULTI(step, &ie->arpcom, enm);
1772 while(enm) {
1773 if(ie->mcast_count >= MAXMCAST
1774 || bcmp(enm->enm_addrlo, enm->enm_addrhi, 6) != 0) {
1775 ie->arpcom.ac_if.if_flags |= IFF_ALLMULTI;
1776 ieioctl(&ie->arpcom.ac_if, SIOCSIFFLAGS, (void *)0);
1777 goto setflag;
1778 }
1779
1780 bcopy(enm->enm_addrlo, &(ie->mcast_addrs[ie->mcast_count]), 6);
1781 ie->mcast_count++;
1782 ETHER_NEXT_MULTI(step, enm);
1783 }
1784
1785setflag:
1786 ie->want_mcsetup = 1;
1787}
1788
1789#endif
1790
1791#ifdef DEBUG
1792void print_rbd(volatile struct ie_recv_buf_desc *rbd) {
1793 printf("RBD at %08lx:\n"
1794 "actual %04x, next %04x, buffer %08x\n"
1795 "length %04x, mbz %04x\n",
1796 (unsigned long)rbd,
1797 rbd->ie_rbd_actual, rbd->ie_rbd_next, rbd->ie_rbd_buffer,
1798 rbd->ie_rbd_length, rbd->mbz);
1799}
1800#endif /* DEBUG */
1801#endif /* NIE > 0 */
1802