xref: /netbsd-src/sys/arch/acorn32/podulebus/if_ie.c (revision 9fbd88883c38d0c0fbfcbe66d76fe6b0fab3f9de)
1 /* $NetBSD: if_ie.c,v 1.4 2002/01/16 05:56:54 thorpej Exp $ */
2 
3 /*
4  * Copyright (c) 1995 Melvin Tang-Richardson.
5  * All rights reserved.
6  *
7  * This driver is a major hash up of src/sys/dev/isa/if_ie.c and
8  * src/sys/arch/acorn32/podulebus/kgdb_ie.c  Please refer to copyright
9  * notices from them too.
10  *
11  * Redistribution and use in source and binary forms, with or without
12  * modification, are permitted provided that the following conditions
13  * are met:
14  * 1. Redistributions of source code must retain the above copyright
15  *    notice, this list of conditions and the following disclaimer.
16  * 2. Redistributions in binary form must reproduce the above copyright
17  *    notice, this list of conditions and the following disclaimer in the
18  *    documentation and/or other materials provided with the distribution.
19  * 3. All advertising materials mentioning features or use of this software
20  *    must display the following acknowledgement:
21  *	This product includes software developed by RiscBSD.
22  * 4. The name of the company nor the name of the author may be used to
23  *    endorse or promote products derived from this software without specific
24  *    prior written permission.
25  *
26  * THIS SOFTWARE IS PROVIDED BY RISCBSD ``AS IS'' AND ANY EXPRESS OR IMPLIED
27  * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
28  * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
29  * IN NO EVENT SHALL RISCBSD OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
30  * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
31  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
32  * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
33  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
34  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
35  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
36  * SUCH DAMAGE.
37  *
38  * RiscBSD kernel project
39  *
40  * if_ie.c
41  *
42  * Ether 1 podule driver
43  *
44  * Created      : 26/06/95
45  */
46 
47 /*
48  *	This driver is at it's last beta release.  It should not cause
49  *	any problems (Touch wood)
50  *
51  * 	If it passes field tests again.  This will constitute the realse
52  *	version.
53  */
54 
55 #define IGNORE_ETHER1_IDROM_CHECKSUM
56 
57 /* Standard podule includes */
58 
59 #include "opt_inet.h"
60 #include "opt_ns.h"
61 
62 #include <sys/param.h>
63 #include <sys/systm.h>
64 #include <sys/kernel.h>
65 #include <sys/conf.h>
66 #include <sys/malloc.h>
67 #include <sys/device.h>
68 #include <machine/io.h>
69 #include <machine/intr.h>
70 #include <arm/arm32/katelib.h>
71 #include <acorn32/podulebus/podulebus.h>
72 #include <dev/podulebus/podules.h>
73 
74 /* Include for interface to the net and ethernet subsystems */
75 
76 #include <sys/socket.h>
77 #include <sys/syslog.h>
78 #include <sys/ioctl.h>
79 #include <sys/mbuf.h>
80 
81 #include <net/if.h>
82 #include <net/if_types.h>
83 #include <net/if_dl.h>
84 #include <net/if_ether.h>
85 
86 #ifdef INET
87 #include <netinet/in.h>
88 #include <netinet/in_systm.h>
89 #include <netinet/in_var.h>
90 #include <netinet/ip.h>
91 #include <netinet/if_inarp.h>
92 #endif
93 
94 #ifdef NS
95 #include <netns/ns.h>
96 #include <netns/ns_if.h>
97 #endif
98 
99 /* Import our data structres */
100 
101 #include "if_iereg.h"
102 
103 /* BPF support */
104 
105 #include "bpfilter.h"
106 #if NBPFILTER > 0
107 #include <net/bpf.h>
108 #include <net/bpfdesc.h>
109 #endif
110 
111 /* Some useful defines and macros */
112 
113 #define PODULE_IRQ_PENDING (1)
114 #define NFRAMES	(16)		/* number of frame to allow for receive */
115 #define NRXBUF	(48)		/* number of receive buffers to allocate */
116 #define IE_RXBUF_SIZE (256) 	/* receive buf size */
117 #define NTXBUF  (2)		/* number of transmit buffers to allocate */
118 #define IE_TXBUF_SIZE (1522) 	/* size of tx buffer */
119 
120 #define PWriteShort(a,b)	WriteWord(a,(b)<<16|(b))
121 
122 #define	xoffsetof(type, member)	(offsetof(type, member) << 1)
123 
124 /* Some data structres local to this file */
125 
126 struct ie_softc {
127 	struct device	sc_dev;
128 	int 		sc_podule_number;
129 	podule_t	*sc_podule;
130 	irqhandler_t 	sc_ih;
131 	int		sc_flags;
132 #define IE_BROKEN	1
133 	int		sc_iobase;
134 	int		sc_fastbase;
135 	int		sc_rom;
136 	int		sc_ram;
137 	int		sc_control;
138 	struct ethercom	sc_ethercom;
139 	int		promisc;
140 	int		sc_irqmode;
141 
142 	u_long	rframes[NFRAMES];
143 	u_long	rbuffs[NRXBUF];
144 	u_long	cbuffs[NRXBUF];
145 	int 	rfhead, rftail, rbhead, rbtail;
146 
147 	u_long 	xmit_cmds[NTXBUF];
148 	u_long 	xmit_buffs[NTXBUF];
149 	u_long 	xmit_cbuffs[NTXBUF];
150 	int	xmit_count;
151 	int	xmit_free;
152 	int	xchead;
153 	int 	xctail;
154 };
155 
156 /* Function and data prototypes */
157 
158 static void host2ie  __P(( struct ie_softc *sc, void *src, u_long dest, int size ));
159 static void ie2host  __P(( struct ie_softc *sc, u_long src, void *dest, int size ));
160 static void iezero   __P(( struct ie_softc *sc, u_long p, int size ));
161 void        iereset  __P(( struct ie_softc *sc ));
162 void        iewatchdog __P(( struct ifnet *ifp ));
163 int         ieioctl  __P(( struct ifnet *ifp, u_long cmd, caddr_t data ));
164 void        iestart  __P(( struct ifnet *ifp ));
165 int 	    iestop   __P(( struct ie_softc *sc ));
166 int         ieinit   __P(( struct ie_softc *sc ));
167 int 	    ieintr   __P(( void *arg ));
168 void 	    ietint   __P(( struct ie_softc *sc ));
169 
170 /* A whopper of a function */
171 static int command_and_wait __P(( struct ie_softc *sc, u_short cmd,
172 			      struct ie_sys_ctl_block *pscb,
173 			      void *pcmd, int ocmd, int scmd, int mask ));
174 
175 int ieprobe __P((struct device *, struct cfdata *, void *));
176 void ieattach __P((struct device *, struct device *, void *));
177 
178 /*
179  * Our cfattach structure for the autoconfig system to chew on
180  */
181 
182 struct cfattach ie_ca = {
183 	sizeof(struct ie_softc), ieprobe, ieattach
184 };
185 
186 /* Let's go! */
187 
188 /*
189  * Clear all pending interrupts from the i82586 chip
190  */
191 
192 static __inline void
193 ie_cli(sc)
194 	struct ie_softc *sc;
195 {
196 	WriteByte(sc->sc_fastbase + (IE_CONTROL<<2), IE_CONT_CLI);
197 }
198 
199 /*
200  * Cool down the i82586, like its namesake, it gets very hot
201  */
202 
203 static __inline void
204 ie_cooldown(temperature)
205 	int temperature;
206 {
207 }
208 
209 /*
210  * Wake the i82586 chip up and get it to do something
211  */
212 
213 static __inline void
214 ieattn(sc)
215 	struct ie_softc *sc;
216 {
217 	WriteByte ( sc->sc_control + (IE_CONTROL<<2), IE_CONT_ATTN );
218 }
219 
220 /*
221  * Set the podule page register to bring a given address into view
222  */
223 
224 static __inline void
225 setpage(sc, off)
226 	struct ie_softc *sc;
227 	u_long off;
228 {
229 	WriteByte ( sc->sc_control + (IE_PAGE<<2), IE_COFF2PAGE(off) );
230 }
231 
232 /*
233  * Ack the i82586
234  */
235 
236 static void
237 ie_ack(sc, mask)
238 	struct ie_softc *sc;
239 	u_short mask;
240 {
241 	u_short stat;
242 	int i;
243 	setpage(sc, IE_IBASE + IE_SCB_OFF );
244 
245 	stat = ReadShort ( sc->sc_ram + IE_COFF2POFF(IE_IBASE+IE_SCB_OFF) +
246 		(xoffsetof(struct ie_sys_ctl_block, ie_status)) );
247 
248 	PWriteShort ( sc->sc_ram + IE_COFF2POFF(IE_IBASE+IE_SCB_OFF) +
249 		(xoffsetof(struct ie_sys_ctl_block, ie_command)),
250 		stat & mask );
251 
252 	ieattn(sc);
253 
254 	for ( i=4000; --i>=0; ) {
255 		if ( !ReadShort(sc->sc_ram + IE_COFF2POFF(IE_IBASE+IE_SCB_OFF) +
256 		    (xoffsetof(struct ie_sys_ctl_block, ie_command))) )
257 			break;
258 		delay(100);
259 	}
260 
261 	if ( i<=0 )
262 		printf ( "ie: command timed out\n" );
263 	ie_cli(sc);
264 }
265 
266 /*
267  * This routine does the checksumming for the idrom
268  */
269 
270 #ifndef IGNORE_ETHER1_IDROM_CHECKSUM
271 static u_long
272 crc32(p, l)
273 	u_char *p;
274 	int l;
275 {
276 	u_long crc=-1;
277 	int i, b;
278 	while ( --l >= 0 ) {
279 		b = *p++;
280 		for ( i=8; --i >= 0; b>>=1 )
281 			if ((b&1)^(crc>>31))
282 				crc=(crc<<1)^0x4c11db7;
283 			else
284 				crc<<=1;
285 	}
286 	return crc;
287 }
288 #endif
289 
290 /*
291  * Probe for the ether1 card.  return 1 on success 0 on failure
292  */
293 
294 int
295 ieprobe(struct device *parent, struct cfdata *cf, void *aux)
296 {
297 	struct podule_attach_args *pa = (void *)aux;
298 
299 /* Look for a network slot interface */
300 
301 	if (matchpodule(pa, MANUFACTURER_ACORN, PODULE_ACORN_ETHER1, -1) == 0)
302 		return(0);
303 
304 	return(1);
305 }
306 
307 /*
308  * Attach our driver to the interfaces it uses
309  */
310 
311 void ieattach ( struct device *parent, struct device *self, void *aux )
312 {
313 	struct ie_softc *sc = (void *)self;
314 	struct podule_attach_args *pa = (void *)aux;
315 	struct ifnet *ifp = &sc->sc_ethercom.ec_if;
316 	int i;
317 	char idrom[32];
318 	u_int8_t hwaddr[ETHER_ADDR_LEN];
319 
320 	/* Check a few things about the attach args */
321 
322 	if (pa->pa_podule_number == -1)
323 		panic("Podule has disappeared !");
324 
325 	sc->sc_podule_number = pa->pa_podule_number;
326 	sc->sc_podule = pa->pa_podule;
327 	podules[sc->sc_podule_number].attached = 1;
328 
329 	/*
330 	 * MESS MESS MESS
331 	 *
332 	 * This needs a serious clean up. Alot of this code was in the probe function
333 	 * but required the softc structure. As a temporary measure until I rewrite it
334 	 * I have just bolted in the probe code here.
335 	 */
336 
337 	/* Index some podule areas */
338 	sc->sc_iobase   = sc->sc_podule->sync_base;	/* OBSOLETE */
339 	sc->sc_fastbase = sc->sc_podule->fast_base;	/* OBSOLETE */
340 	sc->sc_rom      = sc->sc_podule->sync_base;
341 	sc->sc_control  = sc->sc_podule->fast_base;
342 	sc->sc_ram      = sc->sc_podule->fast_base + IE_MEMOFF;
343 
344 	/* Set the page mask to something know and neutral */
345 	setpage(sc, IE_SCB_OFF);
346 
347 	/* Fetch the first part of the idrom */
348 	for ( i=0; i<16; i++ )
349 		idrom[i] = ReadByte ( sc->sc_rom + (i<<2) );
350 
351 	/* Verify the podulebus probe incase RiscOS lied */
352         if ( ReadByte ( sc->sc_rom + (3<<2) ) != 0x03 ) {
353 		printf(": Ether1 ROM probablly broken.  ECID corrupt\n");
354 		sc->sc_flags |= IE_BROKEN;
355 		return;
356 	}
357 
358 	/* Reset the 82586 */
359 	WriteByte ( sc->sc_fastbase + (IE_CONTROL<<2), IE_CONT_RESET );
360  	delay(1000);
361 	WriteByte ( sc->sc_fastbase + (IE_CONTROL<<2), 0 );
362 	delay(10000);
363 
364 	/* Clear pending interrupts */
365 	ie_cli (sc);
366 
367 	/* Setup SCP */
368 	{
369 		struct ie_sys_conf_ptr scp;
370 		bzero (&scp, sizeof(scp) );
371 		scp.ie_iscp_ptr = (caddr_t)IE_ISCP_ADDR;
372 		host2ie(sc, &scp, IE_SCP_ADDR, sizeof (scp) );
373 	}
374 
375 	/* Setup ISCP */
376 	{
377 		struct ie_int_sys_conf_ptr iscp;
378 		bzero ( &iscp, sizeof(iscp) );
379 		iscp.ie_busy = 1;
380 		iscp.ie_base = (caddr_t)IE_IBASE;
381 		iscp.ie_scb_offset = IE_SCB_OFF;
382 		host2ie(sc, &iscp, IE_ISCP_ADDR, sizeof(iscp) );
383 	}
384 
385 	/* Initialise the control block */
386 	iezero ( sc, IE_IBASE + IE_SCB_OFF, sizeof(struct ie_sys_ctl_block) );
387 	ieattn(sc);
388 
389 	/* Wait for not busy */
390 	setpage ( sc, IE_ISCP_ADDR );
391 	for ( i=10000; --i>=0; ) {
392 		if ( !ReadShort( sc->sc_ram + IE_COFF2POFF(IE_ISCP_ADDR) +
393 		    ( xoffsetof(struct ie_int_sys_conf_ptr, ie_busy)) ) )
394 			break;
395 		delay (10);
396 	}
397 
398 	/* If the busy didn't go low, the i82586 is broken or too slow */
399         if ( i<=0 ) {
400 		printf ( ": ether1 chipset didn't respond\n" );
401 		sc->sc_flags |= IE_BROKEN;
402 		return;
403 	}
404 
405 	/* Ensure that the podule sends interrupts */
406         for ( i=1000; --i>=0 ; ) {
407 		if ( ReadByte(sc->sc_rom + 0) & PODULE_IRQ_PENDING )
408 			break;
409 		delay (10);
410 	}
411 
412 	/* If we didn't see the interrupt then the IRQ line is broken */
413 	if ( i<=0 ) {
414 		printf ( ": interrupt from chipset didn't reach host\n" );
415 		sc->sc_flags |= IE_BROKEN;
416 		return;
417 	}
418 
419 	/* Ack our little test operation */
420 	ie_ack(sc,IE_ST_WHENCE);
421         ie_cli (sc);
422 
423 	/* Get second part of idrom */
424 	for ( i=16; i<32; i++ )
425 		idrom[i] = ReadByte ( sc->sc_rom + (i<<2) );
426 
427 	/* This checksum always fails.  For some reason the first 16 */
428 	/* bytes are duplicated in the second 16 bytes, the checksum */
429 	/* should be at location 28 it is clearly not		     */
430 
431 	/* It is possible that this ether1 card is buggered	     */
432 
433 #ifndef IGNORE_ETHER1_IDROM_CHECKSUM
434 	if ( crc32(idrom,28) != *(u_long *)(idrom+28) )
435 	{
436 	    printf ( "ie: ether1 idrom failed checksum %08x!=%08x\n",
437 					crc32(idrom,28), *(u_long *)(idrom+28));
438             for ( i=0; i<32; i+=8 ) {
439 	        printf ( "IDROM: %02x %02x %02x %02x %02x %02x %02x %02x\n",
440 		    idrom[0+i], idrom[1+i], idrom[2+i], idrom[3+i],
441 		    idrom[4+i], idrom[5+i], idrom[6+i], idrom[7+i] );
442 	    }
443 	    printf ( "ie: I'll ignore this fact for now!\n" );
444 	}
445 #endif
446 
447 	/* Get our ethernet address.  Do explicit copy */
448 	for ( i=0; i<ETHER_ADDR_LEN; i++ )
449 	    hwaddr[i] = idrom[9+i];
450 
451 	/* Fill in my application form to attach to the inet system */
452 
453 	bcopy(sc->sc_dev.dv_xname, ifp->if_xname, IFNAMSIZ);
454 	ifp->if_softc = sc;
455 	ifp->if_start = iestart;
456 	ifp->if_ioctl = ieioctl;
457 	ifp->if_watchdog = iewatchdog;
458 	ifp->if_flags = IFF_BROADCAST | IFF_NOTRAILERS;
459 
460 	/* Signed, dated then sent */
461         if_attach (ifp);
462 	ether_ifattach(ifp, hwaddr);
463 
464 	/* "Hmm," said nuts, "what if the attach fails" */
465 
466 	/* Write some pretty things on the annoucement line */
467 	printf ( ": %s using %dk card ram",
468 	    ether_sprintf(hwaddr),
469 	    ((NRXBUF*IE_RXBUF_SIZE)+(NTXBUF*IE_TXBUF_SIZE))/1024 );
470 
471 	sc->sc_ih.ih_func = ieintr;
472 	sc->sc_ih.ih_arg = sc;
473 	sc->sc_ih.ih_level = IPL_NET;
474 	sc->sc_ih.ih_name = "net: ie";
475 	sc->sc_ih.ih_maskaddr = sc->sc_podule->irq_addr;
476 	sc->sc_ih.ih_maskbits = sc->sc_podule->irq_mask;
477 
478 	if (irq_claim(sc->sc_podule->interrupt, &sc->sc_ih)) {
479 		sc->sc_irqmode = 0;
480 		printf(" POLLED");
481 		panic("%s: Cannot install IRQ handler\n", sc->sc_dev.dv_xname);
482 	} else {
483 		sc->sc_irqmode = 1;
484 		printf(" IRQ");
485 	}
486 
487 	printf("\n");
488 }
489 
490 
491 /*
492  * Oh no!! Where's my shorts!!! I'm sure I put them on this morning
493  */
494 
495 void
496 PWriteShorts(src, dest, cnt)
497 	char *src;
498 	char *dest;
499 	int cnt;
500 {
501 	for (cnt /= 2; --cnt >= 0; ) {
502 		PWriteShort(dest, *(u_short *)src);
503 		src+=2;
504 		dest+=4;
505 	}
506 }
507 
508 void
509 ReadShorts(src, dest, cnt)
510 	char *src;
511 	char *dest;
512 	int cnt;
513 {
514 	for (cnt /= 2; --cnt >= 0; ) {
515 		*(u_short *)dest = ReadShort(src);
516 		src+=4;
517 		dest+=2;
518 	}
519 }
520 
521 /*
522  * A bcopy or memcpy to adapter ram.  It handles the page register for you
523  * so you dont have to worry about the ram windowing
524  */
525 
526 static void
527 host2ie(sc, src, dest, size)
528 	struct ie_softc *sc;
529 	void *src;
530 	u_long dest;
531 	int size;
532 {
533 	int cnt;
534 	char *sptr = src;
535 
536 #ifdef DIAGNOSTIC
537 	if (size & 1)
538 		panic("host2ie");
539 #endif
540 
541 	while (size > 0) {
542 		cnt = IE_PAGESIZE - dest % IE_PAGESIZE;
543 		if (cnt > size)
544 			cnt = size;
545 		setpage(sc, dest);
546 		PWriteShorts(sptr, (char *)sc->sc_ram + IE_COFF2POFF(dest), cnt);
547 		sptr+=cnt;
548 		dest+=cnt;
549 		size-=cnt;
550 	}
551 }
552 
553 static void
554 ie2host(sc, src, dest, size)
555 	struct ie_softc *sc;
556 	u_long src;
557 	void *dest;
558 	int size;
559 {
560 	int cnt;
561 	char *dptr = dest;
562 
563 #ifdef DIAGNOSTIC
564 	if (size & 1)
565 		panic ( "ie2host" );
566 #endif
567 
568 	while (size > 0) {
569 		cnt = IE_PAGESIZE - src % IE_PAGESIZE;
570 		if (cnt > size)
571 			cnt = size;
572 		setpage(sc, src);
573 		ReadShorts((char *)sc->sc_ram + IE_COFF2POFF(src), dptr, cnt);
574 		src+=cnt;
575 		dptr+=cnt;
576 		size-=cnt;
577 	}
578 }
579 
580 /*
581  * Like a bzero or memset 0 for adapter memory.  It handles the page
582  * register so you dont have to worry about it
583  */
584 
585 static void
586 iezero(sc, p, size)
587 	struct ie_softc *sc;
588 	u_long p;
589 	int size;
590 {
591 	int cnt;
592 
593 	while (size > 0) {
594 		cnt = IE_PAGESIZE - p % IE_PAGESIZE;
595 		if (cnt > size)
596 			cnt=size;
597 		setpage(sc, p);
598 		bzero((char *)sc->sc_ram + IE_COFF2POFF(p), 2*cnt);
599 		p += cnt;
600 		size -= cnt;
601 	}
602 }
603 
604 /*
605  * I/O Control interface to the kernel, entry point here
606  */
607 
608 int
609 ieioctl(ifp, cmd, data)
610 	struct ifnet *ifp;
611 	u_long cmd;
612 	caddr_t data;
613 {
614     struct ie_softc *sc = ifp->if_softc;
615     struct ifaddr *ifa = (struct ifaddr *)data;
616 /*    struct ifreq *ifr = (struct ifreq *)data;*/
617     int s;
618     int error=0;
619 
620     s=splnet();
621 
622     switch ( cmd )
623     {
624 	case SIOCSIFADDR:
625 	    ifp->if_flags |= IFF_UP;
626 	    switch ( ifa->ifa_addr->sa_family ) {
627 #ifdef INET
628 		case AF_INET:
629 		    ieinit(sc);
630 		    arp_ifinit(ifp, ifa );
631 		    break;
632 #endif
633 		default:
634 		    ieinit(sc);
635 		    break;
636 	    }
637 	    break;
638 
639 #define IZSET(a,b) ((a->if_flags&b)!=0)
640 #define IZCLR(a,b) ((a->if_flags&b)==0)
641 #define DOSET(a,b) (a->if_flags|=b)
642 #define DOCLR(a,b) (a->if_flags&=~b)
643 
644 	case SIOCSIFFLAGS:
645 	    sc->promisc = ifp->if_flags & ( IFF_PROMISC | IFF_ALLMULTI );
646 
647 	    if ( IZCLR(ifp,IFF_UP) && IZSET(ifp,IFF_RUNNING) )
648 	    {
649 		/* Interface was marked down and its running so stop it */
650 		iestop(sc);
651 		DOCLR(ifp,IFF_RUNNING);
652 	    }
653 	    else if ( IZSET(ifp,IFF_UP) && IZCLR(ifp,IFF_RUNNING) )
654 	    {
655 		/* Just marked up and we're not running so start it */
656 		ieinit(sc);
657 	    }
658 	    else
659 	    {
660 		/* else reset to invoke changes in other registers */
661 		iestop(sc);
662 		ieinit(sc);
663             }
664 
665 	default:
666 	    error = EINVAL;
667     }
668     (void)splx(s);
669     return error;
670 }
671 
672 /*
673  * Reset the card.  Completely.
674  */
675 
676 void
677 iereset(sc)
678 	struct ie_softc *sc;
679 {
680 	struct ie_sys_ctl_block scb;
681 	int s = splnet();
682 
683 	iestop(sc);
684 
685 	ie2host(sc, IE_IBASE + IE_SCB_OFF, &scb, sizeof scb);
686 
687 	if (command_and_wait(sc, IE_RU_ABORT|IE_CU_ABORT, 0, 0, 0, 0, 0))
688 	        printf("ie0: abort commands timed out\n");
689 
690 	if (command_and_wait(sc, IE_RU_DISABLE|IE_CU_STOP, 0, 0, 0, 0, 0))
691 	        printf("ie0: abort commands timed out\n");
692 
693 	ieinit(sc);
694 
695 	(void)splx(s);
696 }
697 
698 /*
699  * Watchdog entry point.  This is the entry for the kernel to call us
700  */
701 
702 void
703 iewatchdog(ifp)
704 	struct ifnet *ifp;
705 {
706 	struct ie_softc *sc = ifp->if_softc;
707 
708 	log(LOG_ERR, "%s: device timeout\n", sc->sc_dev.dv_xname);
709 	++ifp->if_oerrors;
710 	iereset(sc);
711 }
712 
713 /*
714  * Start the time-domain-refloctometer running
715  */
716 
717 static void
718 run_tdr(sc)
719 struct ie_softc *sc;
720 {
721     struct ie_sys_ctl_block scb;
722     u_long ptr = IE_IBASE + IE_SCB_OFF + sizeof scb;
723     struct ie_tdr_cmd cmd;
724     int result;
725 
726     bzero ( &scb, sizeof(scb) );
727     bzero ( &cmd, sizeof(cmd) );
728 
729     cmd.com.ie_cmd_status = 0;
730     cmd.com.ie_cmd_cmd = IE_CMD_TDR | IE_CMD_LAST;
731     cmd.com.ie_cmd_link = 0xffff;
732     cmd.ie_tdr_time = 0;
733 
734     scb.ie_command_list = (u_short)ptr;
735 
736     result=0;
737     if ( command_and_wait(sc, IE_CU_START, &scb, &cmd, ptr, sizeof cmd,
738 	IE_STAT_COMPL) )
739     {
740 	    result = 0x10000;
741     }
742     else if ( !(cmd.com.ie_cmd_status & IE_STAT_OK) )
743     {
744 	result = 0x10000;
745     }
746 
747     if ( result==0 )
748 	result = cmd.ie_tdr_time;
749 
750     ie_ack ( sc, IE_ST_WHENCE );
751 
752     if (result & IE_TDR_SUCCESS )
753 	return;
754 
755     /* Very messy.  I'll tidy it later */
756 
757     if ( result & 0x10000 )
758     {
759 	printf ( "ie: TDR command failed\n" );
760     }
761     else if ( result & IE_TDR_XCVR )
762     {
763 	printf ( "ie: tranceiver problem. Is it plugged in?\n" );
764     }
765     else if ( result & IE_TDR_OPEN )
766     {
767 	if ((result & IE_TDR_TIME)>0)
768 	    printf ( "ie: TDR detected an open %d clocks away.\n",
769 			result & IE_TDR_TIME );
770     }
771     else if ( result & IE_TDR_SHORT )
772     {
773 	if ((result & IE_TDR_TIME)>0)
774 	    printf ( "ie: TDR detected a short %d clock away.\n",
775 			result & IE_TDR_TIME );
776     }
777     else
778     {
779 	printf ( "ie: TDR returned unknown status %x\n", result );
780     }
781 }
782 
783 u_long
784 setup_rfa(sc, ptr)
785 	struct ie_softc *sc;
786 	u_long ptr;
787 {
788     int i;
789     {
790 	/* Receive frame descriptors */
791         struct ie_recv_frame_desc rfd;
792 	bzero( &rfd, sizeof rfd );
793 	for ( i=0; i<NFRAMES; i++ )
794 	{
795 	    sc->rframes[i] = ptr;
796 	    rfd.ie_fd_next = ptr + sizeof rfd;
797 	    host2ie(sc, (char *)&rfd, ptr, sizeof rfd);
798 	    ptr += sizeof rfd;
799 	}
800 	rfd.ie_fd_next = sc->rframes[0];
801 	rfd.ie_fd_last |= IE_FD_LAST;
802 	host2ie(sc, (char *)&rfd, sc->rframes[NFRAMES-1], sizeof rfd );
803 
804 	ie2host(sc, sc->rframes[0], (char *)&rfd, sizeof rfd );
805 	rfd.ie_fd_buf_desc = (u_short) ptr;
806 	host2ie(sc, (char *)&rfd, sc->rframes[0], sizeof rfd );
807     }
808 
809     {
810 	/* Receive frame descriptors */
811 	struct ie_recv_buf_desc rbd;
812 	bzero(&rbd, sizeof rbd);
813 	for ( i=0; i<NRXBUF; i++ )
814 	{
815 	    sc->rbuffs[i] = ptr;
816 	    rbd.ie_rbd_length = IE_RXBUF_SIZE;
817 	    rbd.ie_rbd_buffer = (caddr_t)(ptr + sizeof rbd);
818 	    rbd.ie_rbd_next = (u_short)(ptr + sizeof rbd + IE_RXBUF_SIZE);
819 	    host2ie(sc, &rbd, ptr, sizeof rbd);
820 	    ptr+=sizeof rbd;
821 
822 	    sc->cbuffs[i] = ptr;
823 	    ptr+=IE_RXBUF_SIZE;
824 	}
825 	rbd.ie_rbd_next = sc->rbuffs[0];
826 	rbd.ie_rbd_length |= IE_RBD_LAST;
827 	host2ie(sc, &rbd, sc->rbuffs[NRXBUF-1], sizeof rbd);
828     }
829 
830     sc->rfhead = 0;
831     sc->rftail = NFRAMES-1;
832     sc->rbhead = 0;
833     sc->rbtail = NRXBUF-1;
834 
835     {
836 	struct ie_sys_ctl_block scb;
837 	bzero ( &scb, sizeof scb );
838 	scb.ie_recv_list = (u_short)sc->rframes[0];
839 	host2ie(sc, (char *)&scb, (IE_IBASE + IE_SCB_OFF), sizeof scb );
840     }
841     return ptr;
842 }
843 
844 static void
845 start_receiver(sc)
846 	struct ie_softc *sc;
847 {
848     struct ie_sys_ctl_block scb;
849     ie2host ( sc, IE_IBASE + IE_SCB_OFF, &scb, sizeof scb );
850     scb.ie_recv_list = (u_short)sc->rframes[0];
851     command_and_wait(sc, IE_RU_START, &scb, 0, 0, 0, 0);
852     ie_ack(sc, IE_ST_WHENCE );
853 }
854 
855 /*
856  * Take our configuration and update all the other data structures that
857  * require information from the driver.
858  *
859  * CALL AT SPLIMP OR HIGHER
860  */
861 
862 int
863 ieinit(sc)
864 	struct ie_softc *sc;
865 {
866     struct ifnet *ifp;
867     struct ie_sys_ctl_block scb;
868     struct ie_config_cmd cmd;
869     struct ie_iasetup_cmd iasetup_cmd;
870     u_long ptr = IE_IBASE + IE_SCB_OFF + sizeof scb;
871     int n;
872 
873     ifp = &sc->sc_ethercom.ec_if;
874 
875     bzero ( &scb, sizeof(scb) );
876 
877     /* Send the configure command */
878 
879     cmd.com.ie_cmd_status = 0;
880     cmd.com.ie_cmd_cmd = IE_CMD_CONFIG | IE_CMD_LAST;
881     cmd.com.ie_cmd_link = 0xffff;
882 
883     cmd.ie_config_count = 0x0c;
884     cmd.ie_fifo = 8;
885     cmd.ie_save_bad = 0x40;
886     cmd.ie_addr_len = 0x2e;
887     cmd.ie_priority = 0;
888     cmd.ie_ifs = 0x60;
889     cmd.ie_slot_low = 0;
890     cmd.ie_slot_high = 0xf2;
891     cmd.ie_promisc = 0;		/* Hey nuts, look at this! */
892     cmd.ie_crs_cdt = 0;
893     cmd.ie_min_len = 64;
894     cmd.ie_junk = 0xff;
895 
896     scb.ie_command_list = (u_short)ptr;
897 
898     if ( command_and_wait(sc, IE_CU_START, &scb, &cmd, ptr, sizeof cmd,
899 	IE_STAT_COMPL) )
900     {
901 	printf ( "%s: command failed: timeout\n", sc->sc_dev.dv_xname );
902 	return 0;
903     }
904 
905     if ( !(cmd.com.ie_cmd_status & IE_STAT_OK) )
906     {
907 	printf ( "%s: command failed: !IE_STAT_OK\n", sc->sc_dev.dv_xname );
908 	return 0;
909     }
910 
911     /* Individual address setup command */
912 
913     iasetup_cmd.com.ie_cmd_status = 0;
914     iasetup_cmd.com.ie_cmd_cmd = IE_CMD_IASETUP | IE_CMD_LAST;
915     iasetup_cmd.com.ie_cmd_link = 0xffff;
916 
917     bcopy ( LLADDR(ifp->if_sadl), (caddr_t) &iasetup_cmd.ie_address,
918 	 	sizeof (iasetup_cmd.ie_address) );
919 
920     if ( command_and_wait(sc, IE_CU_START, &scb, &iasetup_cmd, ptr, sizeof cmd,
921 	IE_STAT_COMPL) )
922     {
923 	printf ( "%s: iasetup failed : timeout\n", sc->sc_dev.dv_xname );
924 	return 0;
925     }
926 
927     if ( !(cmd.com.ie_cmd_status & IE_STAT_OK) )
928     {
929 	printf ( "%s: iasetup failed : !IE_STAT_OK\n", sc->sc_dev.dv_xname );
930 	return 0;
931     }
932 
933     ie_ack ( sc, IE_ST_WHENCE );
934 
935     /* Run the time-domain refloctometer */
936     run_tdr ( sc );
937 
938     ie_ack ( sc, IE_ST_WHENCE );
939 
940     /* meminit */
941     ptr = setup_rfa(sc, ptr);
942 
943     ifp->if_flags |= IFF_RUNNING;
944     ifp->if_flags &= ~IFF_OACTIVE;
945 
946     /* Setup transmit buffers */
947 
948     for ( n=0; n<NTXBUF; n++ ) {
949 	sc->xmit_cmds[n] = ptr;
950 	iezero(sc, ptr, sizeof(struct ie_xmit_cmd) );
951 	ptr += sizeof(struct ie_xmit_cmd);
952 
953 	sc->xmit_buffs[n] = ptr;
954 	iezero(sc, ptr, sizeof(struct ie_xmit_buf));
955 	ptr += sizeof(struct ie_xmit_buf);
956     }
957 
958     for ( n=0; n<NTXBUF; n++ ) {
959 	sc->xmit_cbuffs[n] = ptr;
960 	ptr += IE_TXBUF_SIZE;
961     }
962 
963     sc->xmit_free = NTXBUF;
964     sc->xchead = sc->xctail = 0;
965 
966     {
967 	struct ie_xmit_cmd xmcmd;
968 	bzero ( &xmcmd, sizeof xmcmd );
969 	xmcmd.ie_xmit_status = IE_STAT_COMPL;
970 	host2ie(sc, &xmcmd, sc->xmit_cmds[0], sizeof xmcmd);
971     }
972 
973     start_receiver (sc);
974 
975     return 0;
976 }
977 
978 int
979 iestop(sc)
980 	struct ie_softc *sc;
981 {
982     struct ie_sys_ctl_block scb;
983     int s = splnet();
984 
985     ie2host ( sc, IE_IBASE + IE_SCB_OFF, &scb, sizeof scb );
986 
987     if ( command_and_wait(sc, IE_RU_DISABLE, &scb, 0, 0, 0, 0) )
988         printf ( "ie0: abort commands timed out\n" );
989 
990     (void)splx(s);
991     return(0);
992 }
993 
994 /*
995  * Send a command to the card and awaits it's completion.
996  * Timeout if it's taking too long
997  */
998 
999 /*CAW*/
1000 
1001 static int
1002 command_and_wait(sc, cmd, pscb, pcmd, ocmd, scmd, mask)
1003 	struct ie_softc *sc;
1004 	u_short cmd;
1005 	struct ie_sys_ctl_block *pscb;
1006 	void *pcmd;
1007 	int ocmd, scmd, mask;
1008 {
1009     int i=0;
1010 
1011     /* Copy the command to the card */
1012 
1013     if ( pcmd )
1014 	host2ie(sc, pcmd, ocmd, scmd); /* transfer the command to the card */
1015 
1016     /* Copy the scb to the card */
1017 
1018     if ( pscb ) {
1019 	pscb->ie_command = cmd;
1020 	host2ie(sc, pscb, IE_IBASE + IE_SCB_OFF, sizeof *pscb);
1021     }
1022     else
1023     {
1024 	setpage ( sc, IE_IBASE + IE_SCB_OFF );
1025 	PWriteShort ( sc->sc_ram + IE_COFF2POFF(IE_IBASE+IE_SCB_OFF) +
1026 		(xoffsetof(struct ie_sys_ctl_block, ie_command)), cmd );
1027     }
1028 
1029     /* Prod the card to act on the newly loaded command */
1030     ieattn(sc);
1031 
1032     /* Wait for the command to complete */
1033     if ( IE_ACTION_COMMAND(cmd) && pcmd )
1034     {
1035 	setpage(sc,ocmd);
1036 	for ( i=4000; --i>=0; ) {
1037 	    if ( ReadShort(sc->sc_ram + IE_COFF2POFF(ocmd) +
1038 		(xoffsetof(struct ie_config_cmd, ie_config_status))) & mask)
1039 		break;
1040 	    delay(100);
1041 	}
1042     }
1043     else
1044     {
1045 	for ( i=4000; --i>=0; ) {
1046 	    if ( !ReadShort(sc->sc_ram + IE_COFF2POFF(IE_IBASE+IE_SCB_OFF) +
1047 		(xoffsetof(struct ie_sys_ctl_block, ie_command))) )
1048 		break;
1049 	    delay(100);
1050 	}
1051     }
1052 
1053     /* Update the host structures to reflect the state on the card */
1054     if ( pscb )
1055 	ie2host(sc, IE_IBASE + IE_SCB_OFF, pscb, sizeof *pscb );
1056     if ( pcmd )
1057 	ie2host(sc, ocmd, pcmd, scmd);
1058 
1059     return i < 0;
1060 }
1061 
1062 #define READ_MEMBER(sc,type,member,ptr,dest)			\
1063 	setpage(sc, ptr);					\
1064 	dest = ReadShort(sc->sc_ram + IE_COFF2POFF(ptr) +	\
1065 	       (xoffsetof(type, member)) );
1066 
1067 #define WRITE_MEMBER(sc,type,member,ptr,dest)			\
1068 	setpage(sc, ptr);					\
1069 	PWriteShort(sc->sc_ram + IE_COFF2POFF(ptr) +	\
1070 	       (xoffsetof(type, member)), dest );
1071 
1072 static __inline int
1073 ie_buflen(sc, head)
1074 	struct ie_softc *sc;
1075 	int head;
1076 {
1077 	int actual;
1078 
1079 	READ_MEMBER(sc,struct ie_recv_buf_desc, ie_rbd_actual,
1080 	    sc->rbuffs[head], actual );
1081 
1082 	return(actual & (IE_RXBUF_SIZE | (IE_RXBUF_SIZE-1))) ;
1083 }
1084 
1085 static __inline int
1086 ie_packet_len(sc)
1087 	struct ie_softc *sc;
1088 {
1089     int i;
1090     int actual;
1091     int head = sc->rbhead;
1092     int acc=0;
1093 
1094     do {
1095 	READ_MEMBER(sc,struct ie_recv_buf_desc, ie_rbd_actual,
1096 			sc->rbuffs[sc->rbhead], actual );
1097 	if (!(actual&IE_RBD_USED))
1098 	{
1099 	    return (-1);
1100 	}
1101 
1102 	READ_MEMBER(sc,struct ie_recv_buf_desc, ie_rbd_actual,
1103 			sc->rbuffs[head], i );
1104         i = i & IE_RBD_LAST;
1105 
1106 	acc += ie_buflen(sc, head);
1107 	head = (head+1) % NRXBUF;
1108     } while (!i);
1109 
1110     return acc;
1111 }
1112 
1113 struct mbuf *
1114 ieget(struct ie_softc *sc, int *to_bpf )
1115 {
1116     struct mbuf *top, **mp, *m;
1117     int head;
1118     int resid, totlen, thisrboff, thismboff;
1119     int len;
1120     struct ether_header eh;
1121 
1122     totlen = ie_packet_len(sc);
1123 
1124     if ( totlen > ETHER_MAX_LEN )
1125     {
1126 	printf ( "ie: Gosh that packet was s-o-o-o big.\n" );
1127 	return 0;
1128     }
1129 
1130     if ( totlen<=0 )
1131 	return 0;
1132 
1133     head = sc->rbhead;
1134 
1135     /* Read the ethernet header */
1136     ie2host ( sc, sc->cbuffs[head], (caddr_t)&eh, sizeof eh );
1137 
1138     /* Check if the packet is for us */
1139 
1140     resid = totlen;
1141 
1142     MGETHDR ( m, M_DONTWAIT, MT_DATA );
1143     if ( m==0 )
1144 	return 0;
1145 
1146     m->m_pkthdr.rcvif = &sc->sc_ethercom.ec_if;
1147     m->m_pkthdr.len = totlen;
1148     len = MHLEN;
1149     top = 0;
1150     mp = &top;
1151 
1152     /*
1153      * This loop goes through and allocates mbufs for all the data we will
1154      * be copying in.  It does not actually do the copying yet.
1155      */
1156     while (totlen > 0) {
1157 	if (top) {
1158 	    MGET(m, M_DONTWAIT, MT_DATA);
1159 	    if (m == 0) {
1160 		m_freem(top);
1161 		return 0;
1162 	    }
1163 	    len = MLEN;
1164 	}
1165 	if (totlen >= MINCLSIZE) {
1166 	    MCLGET(m, M_DONTWAIT);
1167 	    if (m->m_flags & M_EXT)
1168 		len = MCLBYTES;
1169 	}
1170 
1171 	if (mp == &top) {
1172 		caddr_t newdata = (caddr_t)
1173 		    ALIGN(m->m_data + sizeof(struct ether_header)) -
1174 		    sizeof(struct ether_header);
1175 		len -= newdata - m->m_data;
1176 		m->m_data = newdata;
1177 	}
1178 
1179         m->m_len = len = min(totlen, len);
1180 
1181         totlen -= len;
1182         *mp = m;
1183         mp = &m->m_next;
1184     }
1185 
1186     m = top;
1187     thismboff = 0;
1188 
1189     /*
1190      * Copy the Ethernet header into the mbuf chain.
1191      */
1192     memcpy(mtod(m, caddr_t), &eh, sizeof(struct ether_header));
1193     thismboff = sizeof(struct ether_header);
1194     thisrboff = sizeof(struct ether_header);
1195     resid -= sizeof(struct ether_header);
1196 
1197     /*
1198      * Now we take the mbuf chain (hopefully only one mbuf most of the
1199      * time) and stuff the data into it.  There are no possible failures at
1200      * or after this point.
1201      */
1202     while (resid > 0) {
1203 	int thisrblen = ie_buflen(sc, head) - thisrboff,
1204 	    thismblen = m->m_len - thismboff;
1205 	len = min(thisrblen, thismblen);
1206 
1207 /*      bcopy((caddr_t)(sc->cbuffs[head] + thisrboff),
1208 	    mtod(m, caddr_t) + thismboff, (u_int)len);	 */
1209 
1210 
1211 	if ( len&1 )
1212 	{
1213  	    ie2host(sc, sc->cbuffs[head]+thisrboff,
1214 		mtod(m, caddr_t) + thismboff, (u_int)len+1);
1215   	}
1216 	else
1217 	{
1218  	    ie2host(sc, sc->cbuffs[head]+thisrboff,
1219 		mtod(m, caddr_t) + thismboff, (u_int)len);
1220 	}
1221 
1222 	resid -= len;
1223 
1224 	if (len == thismblen) {
1225 		m = m->m_next;
1226 		thismboff = 0;
1227 	} else
1228 		thismboff += len;
1229 
1230 	if (len == thisrblen) {
1231 		head = (head + 1) % NRXBUF;
1232 		thisrboff = 0;
1233 	} else
1234 		thisrboff += len;
1235     }
1236 
1237 
1238     return top;
1239 }
1240 
1241 void
1242 ie_drop_packet_buffer(sc)
1243 	struct ie_softc *sc;
1244 {
1245     int i, actual, last;
1246 
1247     do {
1248 	READ_MEMBER(sc,struct ie_recv_buf_desc, ie_rbd_actual,
1249 			sc->rbuffs[sc->rbhead], actual );
1250 	if (!(actual&IE_RBD_USED))
1251 	{
1252 	    iereset(sc);
1253 	    return;
1254 	}
1255 
1256 	i = actual & IE_RBD_LAST;
1257 
1258         READ_MEMBER(sc,struct ie_recv_buf_desc,ie_rbd_length,
1259 			sc->rbuffs[sc->rbhead], last );
1260         last |= IE_RBD_LAST;
1261         WRITE_MEMBER(sc,struct ie_recv_buf_desc,ie_rbd_length,
1262 			sc->rbuffs[sc->rbhead], last );
1263 
1264         WRITE_MEMBER(sc,struct ie_recv_buf_desc,ie_rbd_actual,
1265 			sc->rbuffs[sc->rbhead], 0 );
1266 
1267 	sc->rbhead = ( sc->rbhead + 1 ) % NRXBUF;
1268 
1269         READ_MEMBER(sc,struct ie_recv_buf_desc,ie_rbd_length,
1270 			sc->rbuffs[sc->rbtail], last );
1271         last &= ~IE_RBD_LAST;
1272         WRITE_MEMBER(sc,struct ie_recv_buf_desc,ie_rbd_length,
1273 			sc->rbuffs[sc->rbtail], last );
1274 
1275 	sc->rbtail = ( sc->rbtail + 1 ) % NRXBUF;
1276     } while (!i);
1277 }
1278 
1279 void
1280 ie_read_frame(sc, num)
1281 	struct ie_softc *sc;
1282 	int num;
1283 {
1284     int status;
1285     struct ie_recv_frame_desc rfd;
1286     struct mbuf *m=0;
1287     struct ifnet *ifp;
1288     int last;
1289 
1290     ifp = &sc->sc_ethercom.ec_if;
1291 
1292     ie2host(sc, sc->rframes[num], &rfd, sizeof rfd );
1293     status = rfd.ie_fd_status;
1294 
1295     /* Advance the RFD list, since we're done with this descriptor */
1296 
1297     WRITE_MEMBER(sc,struct ie_recv_frame_desc,ie_fd_status,
1298 			sc->rframes[num], 0 );
1299 
1300     READ_MEMBER(sc,struct ie_recv_frame_desc,ie_fd_last,
1301 			sc->rframes[num], last );
1302     last |= IE_FD_LAST;
1303     WRITE_MEMBER(sc,struct ie_recv_frame_desc,ie_fd_last,
1304 			sc->rframes[num], last );
1305 
1306     READ_MEMBER(sc,struct ie_recv_frame_desc,ie_fd_last,
1307 			sc->rframes[sc->rftail], last );
1308     last &= ~IE_FD_LAST;
1309     WRITE_MEMBER(sc,struct ie_recv_frame_desc,ie_fd_last,
1310 			sc->rframes[sc->rftail], last );
1311 
1312     sc->rftail = ( sc->rftail + 1 ) % NFRAMES;
1313     sc->rfhead = ( sc->rfhead + 1 ) % NFRAMES;
1314 
1315     if ( status & IE_FD_OK ) {
1316 	m = ieget(sc, 0);
1317 	ie_drop_packet_buffer(sc);
1318     }
1319 
1320     if ( m==0 ) {
1321 	ifp->if_ierrors++;
1322 	return;
1323     }
1324 
1325     ifp->if_ipackets++;
1326 
1327 #if NBPFILTER > 0
1328     if ( ifp->if_bpf ) {
1329 	bpf_mtap(ifp->if_bpf, m );
1330     };
1331 #endif
1332 
1333     (*ifp->if_input)(ifp, m);
1334 }
1335 
1336 void
1337 ierint(sc)
1338 	struct ie_softc *sc;
1339 {
1340     int i;
1341     int times_thru = 1024;
1342     struct ie_sys_ctl_block scb;
1343     int status;
1344     int safety_catch = 0;
1345 
1346     i = sc->rfhead;
1347     for (;;) {
1348 
1349 	if ( (safety_catch++)>100 )
1350 	{
1351 	    printf ( "ie: ierint safety catch tripped\n" );
1352 	    iereset(sc);
1353 	    return;
1354 	}
1355 
1356 	READ_MEMBER(sc,struct ie_recv_frame_desc,ie_fd_status,
1357 				sc->rframes[i],status);
1358 
1359 	if ((status&IE_FD_COMPLETE)&&(status&IE_FD_OK)) {
1360 	    if ( !--times_thru ) {
1361 		printf ( "IERINT: Uh oh. Nuts, look at this bit!!!\n" );
1362     		ie2host ( sc, IE_IBASE + IE_SCB_OFF, &scb, sizeof scb );
1363 		sc->sc_ethercom.ec_if.if_ierrors += scb.ie_err_crc +
1364 						  scb.ie_err_align +
1365 						  scb.ie_err_resource +
1366 						  scb.ie_err_overrun;
1367 		scb.ie_err_crc      = scb.ie_err_align   = 0;
1368 		scb.ie_err_resource = scb.ie_err_overrun = 0;
1369 	        host2ie(sc, &scb, IE_SCP_ADDR, sizeof (scb) );
1370 	    }
1371 	    ie_read_frame(sc, i);
1372 	} else {
1373     	    ie2host ( sc, IE_IBASE + IE_SCB_OFF, &scb, sizeof scb );
1374 
1375 	    if ( ((status&IE_FD_RNR)!=0) && ((scb.ie_status&IE_RU_READY)==0) )
1376 	    {
1377 		WRITE_MEMBER(sc,struct ie_recv_frame_desc, ie_fd_buf_desc,
1378 				sc->rframes[0], sc->rbuffs[0] );
1379 
1380 		scb.ie_recv_list = sc->rframes[0];
1381 	        host2ie(sc, (char *)&scb, IE_IBASE + IE_SCB_OFF, sizeof (scb) );
1382     		command_and_wait(sc, IE_RU_START, &scb, 0, 0, 0, 0);
1383 	    }
1384 	    break;
1385 	}
1386 	i = (i + 1) % NFRAMES;
1387     }
1388 }
1389 
1390 static int in_intr = 0;
1391 
1392 int
1393 ieintr(arg)
1394 	void *arg;
1395 {
1396     struct ie_softc *sc = arg;
1397     u_short status;
1398     int safety_catch = 0;
1399     static int safety_net = 0;
1400 
1401     if (in_intr == 1)
1402 	panic ( "ie: INTERRUPT REENTERED\n" );
1403 
1404     /* Clear the interrrupt */
1405     ie_cli (sc);
1406 
1407     setpage(sc, IE_IBASE + IE_SCB_OFF );
1408     status = ReadShort ( sc->sc_ram + IE_COFF2POFF(IE_IBASE+IE_SCB_OFF) +
1409 		(xoffsetof(struct ie_sys_ctl_block, ie_status)) );
1410 
1411     status = status & IE_ST_WHENCE;
1412 
1413     if (status == 0) {
1414 	in_intr = 0;
1415 	return(0);
1416     }
1417 
1418 loop:
1419 
1420     ie_ack(sc, status);
1421 
1422     if (status & (IE_ST_FR | IE_ST_RNR))
1423 	ierint(sc);
1424 
1425     if (status & IE_ST_CX)
1426 	ietint(sc);
1427 
1428     if (status & IE_ST_RNR) {
1429 	printf ( "ie: receiver not ready\n" );
1430 	sc->sc_ethercom.ec_if.if_ierrors++;
1431 	iereset(sc);
1432     }
1433 
1434     setpage(sc, IE_IBASE + IE_SCB_OFF );
1435     status = ReadShort ( sc->sc_ram + IE_COFF2POFF(IE_IBASE+IE_SCB_OFF) +
1436 		(xoffsetof(struct ie_sys_ctl_block, ie_status)) );
1437     status = status & IE_ST_WHENCE;
1438 
1439     ie_cli(sc);
1440 
1441     if (status == 0) {
1442 	in_intr = 0;
1443 	return(0);
1444     }
1445 
1446     /* This is prehaps a little over cautious */
1447     if ( safety_catch++ > 10 )
1448     {
1449 	printf ( "ie: Interrupt couldn't be cleared\n" );
1450 	delay ( 1000 );
1451 	ie_cli(sc);
1452 	if ( safety_net++ > 50 )
1453 	{
1454 /*	    printf ( "ie: safety net catches driver, shutting down\n" );
1455 	    disable_irq ( IRQ_PODULE );*/
1456 	}
1457 	in_intr = 0;
1458 	return(0);
1459     }
1460 
1461     goto loop;
1462 }
1463 
1464 void
1465 iexmit(sc)
1466 	struct ie_softc *sc;
1467 {
1468 /*    int actual;*/
1469     struct ie_sys_ctl_block scb;
1470 
1471     struct ie_xmit_cmd xc;
1472     struct ie_xmit_buf xb;
1473 
1474     ie2host(sc, sc->xmit_buffs[sc->xctail], (char *)&xb, sizeof xb );
1475     xb.ie_xmit_flags |= IE_XMIT_LAST;
1476     xb.ie_xmit_next = 0xffff;
1477     xb.ie_xmit_buf = (caddr_t)sc->xmit_cbuffs[sc->xctail];
1478     host2ie(sc, &xb, sc->xmit_buffs[sc->xctail], sizeof xb );
1479 
1480     bzero ( &xc, sizeof xc );
1481     xc.com.ie_cmd_link = 0xffff;
1482     xc.com.ie_cmd_cmd = IE_CMD_XMIT | IE_CMD_INTR | IE_CMD_LAST;
1483     xc.ie_xmit_status = 0x0000;
1484     xc.ie_xmit_desc = sc->xmit_buffs[sc->xctail];
1485     host2ie(sc, (char *)&xc, sc->xmit_cmds[sc->xctail], sizeof xc );
1486 
1487     ie2host ( sc, IE_IBASE + IE_SCB_OFF, &scb, sizeof scb );
1488     scb.ie_command_list = sc->xmit_cmds[sc->xctail];
1489     host2ie(sc, (char *)&scb, (IE_IBASE + IE_SCB_OFF), sizeof scb );
1490 
1491     command_and_wait(sc, IE_CU_START, &scb, &xc, sc->xmit_cmds[sc->xctail]
1492 			, sizeof xc, IE_STAT_COMPL);
1493 
1494     sc->sc_ethercom.ec_if.if_timer = 5;
1495 }
1496 /*
1497  * Start sending all the queued buffers.
1498  */
1499 
1500 void
1501 iestart(ifp)
1502 	struct ifnet *ifp;
1503 {
1504 	struct ie_softc *sc = ifp->if_softc;
1505 	struct mbuf *m0, *m;
1506 	u_char *buffer;
1507 	u_short len;
1508 	char txbuf[IE_TXBUF_SIZE];
1509 	int safety_catch = 0;
1510 
1511 	if ((ifp->if_flags & IFF_OACTIVE) != 0)
1512 		return;
1513 
1514 	for (;;) {
1515 		if ( (safety_catch++)>100 )
1516 		{
1517 		    printf ( "ie: iestart safety catch tripped\n" );
1518 		    iereset(sc);
1519 		    return;
1520 		}
1521 		if (sc->xmit_free == 0) {
1522 			ifp->if_flags |= IFF_OACTIVE;
1523 			break;
1524 		}
1525 
1526 		IF_DEQUEUE(&ifp->if_snd, m);
1527 		if (!m)
1528 			break;
1529 
1530 		/* TODO: Write directly to the card */
1531 		len = 0;
1532 		/* buffer = sc->xmit_cbuffs[sc->xchead]; */
1533 		buffer = txbuf;
1534 
1535 		for (m0 = m; m && (len + m->m_len) < IE_TXBUF_SIZE;
1536 		     m = m->m_next) {
1537 			bcopy(mtod(m, caddr_t), buffer, m->m_len);
1538 			buffer += m->m_len;
1539 			len += m->m_len;
1540 		}
1541 
1542 #if NBPFILTER > 0
1543 		if ( ifp->if_bpf )
1544 		    bpf_mtap(ifp->if_bpf, m0);
1545 #endif
1546 
1547 		m_freem(m0);
1548 		len = max(len, ETHER_MIN_LEN);
1549 
1550 		/* When we write directly to the card we dont need this */
1551     		if (len&1)
1552    		    host2ie(sc, txbuf, sc->xmit_cbuffs[sc->xchead], len+1 );
1553 		else
1554    		    host2ie(sc, txbuf, sc->xmit_cbuffs[sc->xchead], len );
1555 
1556 		/* sc->xmit_buffs[sc->xchead]->ie_xmit_flags = len; */
1557 
1558 		WRITE_MEMBER(sc,struct ie_xmit_buf, ie_xmit_flags,
1559 				sc->xmit_buffs[sc->xchead], len)
1560 
1561 		/* Start the first packet transmitting. */
1562 		if (sc->xmit_free == NTXBUF)
1563 			iexmit(sc);
1564 
1565 		sc->xchead = (sc->xchead + 1) % NTXBUF;
1566 		sc->xmit_free--;
1567 	}
1568 }
1569 
1570 void
1571 ietint(sc)
1572 	struct ie_softc *sc;
1573 {
1574     struct ifnet *ifp = &sc->sc_ethercom.ec_if;
1575 
1576     int status;
1577 
1578     ifp->if_timer=0;
1579     ifp->if_flags &= ~IFF_OACTIVE;
1580 
1581     READ_MEMBER(sc,struct ie_xmit_cmd, ie_xmit_status,
1582 	sc->xmit_cmds[sc->xctail], status );
1583 
1584     if (!(status&IE_STAT_COMPL) || (status & IE_STAT_BUSY) )
1585 	printf ( "ietint: command still busy!\n" );
1586 
1587     if ( status & IE_STAT_OK ) {
1588 	ifp->if_opackets++;
1589 	ifp->if_collisions += status & IE_XS_MAXCOLL;
1590     } else {
1591 	ifp->if_oerrors++;
1592 	if ( status & IE_STAT_ABORT )
1593 	    printf ( "ie: send aborted\n" );
1594 	if ( status & IE_XS_LATECOLL )
1595 	    printf ( "ie: late collision\n" );
1596 	if ( status & IE_XS_NOCARRIER )
1597 	    printf ( "ie: no carrier\n" );
1598 	if ( status & IE_XS_LOSTCTS )
1599 	    printf ( "ie: lost CTS\n" );
1600 	if ( status & IE_XS_UNDERRUN )
1601 	    printf ( "ie: DMA underrun\n" );
1602 	if ( status & IE_XS_EXCMAX )
1603 	    printf ( "ie: too many collisions\n" );
1604 	ifp->if_collisions+=16;
1605     }
1606     /* Done with the buffer */
1607     sc->xmit_free++;
1608     sc->xctail = (sc->xctail + 1 ) % NTXBUF;
1609 
1610     /* Start the next packet transmitting, if any */
1611     if ( sc->xmit_free<NTXBUF )
1612 	iexmit(sc);
1613 
1614     iestart(ifp);
1615 }
1616 
1617 /* End of if_ie.c */
1618