Subject: port-i386/1433: There is no Intel EtherExpress 16 driver
To: None <netbsd-bugs@NetBSD.ORG>
From: Andrew Gillham <gillham@digitron.COM>
List: netbsd-bugs
Date: 09/05/1995 10:50:48
>Number:         1433
>Category:       port-i386
>Synopsis:       There is no Intel EtherExpress 16 driver
>Confidential:   no
>Severity:       non-critical
>Priority:       low
>Responsible:    gnats-admin (GNATS administrator)
>State:          open
>Class:          change-request
>Submitter-Id:   net
>Arrival-Date:   Mon Sep  4 22:35:03 1995
>Last-Modified:
>Originator:     Andrew Gillham
>Organization:
Just me.
============================ Real 32bit multi-tasking UN*X System
Andrew Gillham             | TCP/IP,NFS,PPP,4.4BSD-lite,multi-user
gillham@andrews.edu        | i386,sparc,alpha,mac68k,amiga,others
LAN/WAN/NW/UN*X specialist |   ---> http://www.NetBSD.org <---
        'Free the daemon in your computer, NetBSD'
>Release:        Sept 2, 1995
>Environment:
System: NetBSD badboy 1.0A NetBSD 1.0A (BADBOY) #2: Mon Sep 4 03:51:44 EDT 1995 root@badboy:/usr/src/sys/arch/i386/compile/BADBOY i386

Actual testing done on my brother's system at Intel. (I don't have an EE16)
Here is his dmesg:  (note 'ix0')

NetBSD 1.0A (INTEL) #4: Mon Sep  4 11:39:41 PDT 1995
    root@ggillhax:/usr/src/sys/arch/i386/compile/INTEL
CPU: i486DX (486-class CPU)
real mem  = 7995392
avail mem = 6254592
using 123 buffers containing 503808 bytes of memory
isa0 (root)
com0 at isa0 port 0x3f8-0x3ff irq 4: ns8250 or ns16450, no fifo
com1 at isa0 port 0x2f8-0x2ff irq 3: ns8250 or ns16450, no fifo
lpt0 at isa0 port 0x378-0x37f irq 7
aha0: 1542C/CF detected, unlocking mailbox
aha0 at isa0 port 0x330-0x333 irq 11 drq 7
scsibus0 at aha0
aha0 targ 0 lun 0: <MAXTOR, LXT-213S, 4.57> SCSI1 0/direct fixed
sd0 at scsibus0: 202MB, 1310 cyl, 7 head, 45 sec, 512 bytes/sec
wdc0 at isa0 port 0x1f0-0x1f7 irq 14
wd0 at wdc0 drive 0: 202MB, 683 cyl, 16 head, 38 sec, 512 bytes/sec <Maxtor 7213 AT>
wd0: using 16-sector 16-bit pio transfers, chs addressing
wd1 at wdc0 drive 1: 124MB, 936 cyl, 16 head, 17 sec, 512 bytes/sec <Maxtor 7120 AT>
wd1: using 16-sector 16-bit pio transfers, chs addressing
ix0 at isa0 port 0x300-0x30f iomem 0xd0000-0xd7fff irq 10
ix0: address 00:aa:00:53:9c:32
npx0 at isa0 port 0xf0-0xff: using exception 16
vt0 at isa0 port 0x60-0x6f irq 1: generic, 80 col, color, 8 scr, mf2-kbd, [R3.00]
fdc0 at isa0 port 0x3f0-0x3f7 irq 6 drq 2
fd0 at fdc0 drive 0: 1.44MB 80 cyl, 2 head, 18 sec
root device eisa not configured
root device pci not configured
biomask 4840 netmask 400 ttymask 1a
changing root device to sd0a

>Description:
	There is no Intel EtherExpress 16 driver, though it is mentioned
	in /sys/dev/isa/files.isa.  My brother needed one as the only NICs
	used at Intel, are Intel NICs. (imagine that)

>How-To-Repeat:
	Install an Intel EtherExpress 16
>Fix:
	Included is a port of the FreeBSD "ix" driver by Rod Grimes.
	I did nothing more than convert it to the new config format with
	cfdata, etc..  I do not claim to be a kernel hacker, so my changes
	might not be up to snuff.  But... the code does work.
	Really this driver should be integrated with if_ie.c, but that was
	definitely beyond me!
	
	Included is:
	
	files.isa.diff	- uncomment the if_ix.c driver
	if_ix.c		- add EE16 support
	if_ixreg.h	- needed for above

*** files.isa.orig	Mon Jul 24 08:29:04 1995
--- files.isa	Mon Sep  4 14:40:44 1995
***************
*** 148,155 ****
  
  # XXX ???
  # XXX NOT IN TREE?
! #device	ix at isa: ether, ifnet
! #file	dev/isa/if_ix.c			ix
  
  # AMD am7990 (Lance) -based boards
  # (BICC Isolan, NE2100, DEPCA)
--- 148,155 ----
  
  # XXX ???
  # XXX NOT IN TREE?
! device	ix at isa: ether, ifnet
! file	dev/isa/if_ix.c			ix
  
  # AMD am7990 (Lance) -based boards
  # (BICC Isolan, NE2100, DEPCA)

-----cut here-----

/*
 * Copyright (c) 1993, 1994, 1995
 *	Rodney W. Grimes, Milwaukie, Oregon  97222.  All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer as
 *    the first lines of this file unmodified.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 * 3. All advertising materials mentioning features or use of this software
 *    must display the following acknowledgement:
 *	This product includes software developed by Rodney W. Grimes.
 * 4. The name of the author may not be used to endorse or promote products
 *    derived from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY RODNEY W. GRIMES ``AS IS'' AND ANY EXPRESS OR
 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
 * IN NO EVENT SHALL RODNEY W. GRIMES BE LIABLE FOR ANY DIRECT, INDIRECT,
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 *
 *	$Id: if_ix.c,v 1.7 1995/05/30 08:02:15 rgrimes Exp $
 */

#include <sys/param.h>
#include <sys/systm.h>
#include <sys/mbuf.h>
#include <sys/socket.h>
#include <sys/ioctl.h>
#include <sys/errno.h>
#include <sys/syslog.h>
#include <sys/device.h> 

#include <net/if.h>
#include <net/if_types.h>
#include <net/if_dl.h>

#ifdef INET
#include <netinet/in.h>
#include <netinet/in_systm.h>
#include <netinet/in_var.h>
#include <netinet/ip.h>
#include <netinet/if_ether.h>
#endif /* INET */

#ifdef NS /*ZZZ no work done on this, this is just here to remind me*/
#include <netns/ns.h>
#include <netns/ns_if.h>
#endif /* NS */

#ifdef ISO /*ZZZ no work done on this, this is just here to remind me*/
#include <netiso/iso.h>
#include <netiso/iso_var.h>
extern char all_es_snpa[], all_is_snpa[], all_l1is_snpa[], all_l2is_snpa[];
#endif /* ISO */

/*ZZZ no work done on this, this is just here to remind me*/
#include "bpfilter.h"
#if NBPFILTER > 0
#include <net/bpf.h>
#include <net/bpfdesc.h>
#endif /* NBPFILTER > 0 */

#include <machine/cpu.h>
#include <machine/pio.h>  

#include <dev/isa/isareg.h>
#include <dev/isa/isavar.h>
#include <i386/isa/isa_machdep.h>
#include <dev/isa/if_ixreg.h>

#define	DEBUGNONE	0x0000
#define	DEBUGPROBE	0x0001
#define	DEBUGATTACH	(DEBUGPROBE << 1)
#define DEBUGINIT	(DEBUGATTACH << 1)
#define	DEBUGINIT_RFA	(DEBUGINIT << 1)
#define	DEBUGINIT_TFA	(DEBUGINIT_RFA << 1)
#define DEBUGINTR	(DEBUGINIT_TFA << 1)
#define	DEBUGINTR_FR	(DEBUGINTR << 1)
#define	DEBUGINTR_CX	(DEBUGINTR_FR << 1)
#define DEBUGSTART	(DEBUGINTR_CX << 1)
#define	DEBUGSTOP	(DEBUGSTART << 1)
#define	DEBUGRESET	(DEBUGSTOP << 1)
#define DEBUGDONE	(DEBUGRESET << 1)
#define	DEBUGIOCTL	(DEBUGDONE << 1)
#define	DEBUGACK	(DEBUGIOCTL << 1)
#define	DEBUGCA		(DEBUGACK << 1)
#define	DEBUGCB_WAIT	(DEBUGCA << 1)
#define DEBUGALL	0xFFFFFFFF


/* #define IXDEBUG	(DEBUGPROBE | DEBUGINIT | DEBUGSTOP | DEBUGCB_WAIT) */


#ifdef IXDEBUG
int	ixdebug=IXDEBUG;
#define	DEBUGBEGIN(flag) \
	{\
	if (ixdebug & flag)\
		{
#define	DEBUGEND \
		}\
	}
#define DEBUGDO(x)	x

#else /* IXDEBUG */

#define DEBUGBEGIN(flag)
#define DEBUGEND
#define	DEBUGDO(x)
#endif /* IXDEBUG */

/*
 * Enable the exteneded ixcounters by using #define IXCOUNTERS, note that
 * this requires a modification to the ifnet structure to add the counters
 * in.  Some day a standard extended ifnet structure will be done so that
 * additional statistics can be gathered for any board that supports these
 * counters.
 */
#ifdef IXCOUNTERS
#define IXCOUNTER(x)	x
#else /* IXCOUNTERS */
#define IXCOUNTER(x)
#endif /* IXCOUNTERS */

/*
 * Function Prototypes
 */
static inline void ixinterrupt_enable __P((struct ix_softc *));
static inline void ixinterrupt_disable __P((struct ix_softc *));
static inline void ixchannel_attention __P((struct ix_softc *));
u_short ixacknowledge __P((struct ix_softc *));
int ix_cb_wait(cb_t *, char *);
int ix_scb_wait(scb_t *, u_short, char *);
int ixprobe __P((struct device *, void *, void *));
void  ixattach __P((struct device *, struct device *, void *));
void ixinit __P((struct ix_softc *));
void ixinit_rfa __P((struct ix_softc *));
void ixinit_tfa __P((struct ix_softc *));
int ixintr __P((void *));
static inline void ixintr_cx __P((struct ix_softc *));
static inline void ixintr_cx_free __P((struct ix_softc *, cb_t *));
static inline void ixintr_fr __P((struct ix_softc *));
static inline void ixintr_fr_copy __P((struct ix_softc *, rfd_t *));
static inline void ixintr_fr_free __P((struct ix_softc *, rfd_t *));

void	ixstart			__P((struct ifnet *));
int	ixstop			__P((struct ifnet *));
int	ixioctl			__P((struct ifnet *, u_long, caddr_t));
void	ixreset			__P((struct ix_softc *));
void	ixwatchdog		__P((int));
u_short	ixeeprom_read		__P((struct ix_softc *, int));
void	ixeeprom_outbits	__P((struct ix_softc *, int, int));
int	ixeeprom_inbits		__P((struct ix_softc *));
void	ixeeprom_clock		__P((struct ix_softc *, int));
/*
RRR */

struct cfdriver ixcd = {
        NULL, "ix", ixprobe, ixattach, DV_IFNET, sizeof(struct ix_softc)
};


/*
 * Enable the interrupt signal on the board so that it may interrupt
 * the host.
 */
static inline void
ixinterrupt_enable(sc)
	struct ix_softc *sc;
{
	outb(sc->sc_iobase + sel_irq, sc->irq_encoded | IRQ_ENABLE);
}


/*
 * Disable the interrupt signal on the board so that it will not interrupt
 * the host.
 */
static inline void
ixinterrupt_disable(sc)
	struct ix_softc *sc;
{
	outb(sc->sc_iobase + sel_irq, sc->irq_encoded);
}

/*
 * Send a channel attention to the 82586 chip
 */
static inline void
ixchannel_attention(sc)
	struct ix_softc *sc;
{
	DEBUGBEGIN(DEBUGCA)
	DEBUGDO(printf("ca");)
	DEBUGEND
	outb(sc->sc_iobase + ca_ctrl, 0);
}

u_short
ixacknowledge(sc)
	struct ix_softc *sc;
{
	scb_t		*scb = (scb_t *)(sc->sc_maddr + SCB_ADDR);
	u_short		status;
	int		i;

	DEBUGBEGIN(DEBUGACK)
	DEBUGDO(printf("ack:");)
	DEBUGEND
	status = scb->status;
	scb->command = status & SCB_ACK_MASK;
	if ((status & SCB_ACK_MASK) != 0) {
		ixchannel_attention(sc);
		for (i = 1000000; scb->command && (i > 0); i--); /*ZZZ timeout*/
		if (i == 0) {
			printf(".TO=%x:", scb->command);
			printf("\nshutting down\n");
			ixinterrupt_disable(sc);
			sc->flags = IXF_NONE;
			status = 0;
		} else {
			DEBUGBEGIN(DEBUGACK)
			DEBUGDO(printf(".ok:");)
			DEBUGEND
		}
	 } else {
		/* nothing to acknowledge */
		DEBUGBEGIN(DEBUGACK)
		DEBUGDO(printf("NONE:");)
		DEBUGEND
	}
	DEBUGBEGIN(DEBUGACK)
	DEBUGDO(printf("%x ", status);)
	DEBUGEND
	return(status);
}

int
ix_cb_wait(cb_t *cb, char *message) {
	int		i;
	int		status;

	for (i=1000000; i>0; i--) {
		if (cb->status & CB_COMPLETE) break; /* Wait for done */
	}
	if (i == 0) {
		printf("%s timeout cb->status = %x\n", message, cb->status);
		status = 1;
	} else {
		DEBUGBEGIN(DEBUGCB_WAIT)
		DEBUGDO(printf("%s cb ok count = %d\n", message, i);)
		DEBUGEND
		status = 0;
	}
	return (status);
}

int
ix_scb_wait(scb_t *scb, u_short expect, char *message) {
	int		i;
	int		status;

	for (i=1000000; i>0; i--) {
		if (scb->status == expect) break; /* Wait for done */
	}
	if (i == 0) {
		printf("%s timeout scb->status = %x\n", message, scb->status);
		status = 1;
	} else {
		DEBUGBEGIN(DEBUGINIT)
		DEBUGDO(printf("%s scb ok count = %d\n", message, i);)
		DEBUGEND
		status = 0;
	}
	return (status);
}

int
ixprobe(parent, match, aux)
	struct device *parent;
	void *match, *aux;
{
        struct ix_softc *sc = match;
        struct isa_attach_args *ia = aux;
	int iobase = ia->ia_iobase;

	char	tempid, idstate;
	int	i;
	int	status = 0;
	u_short	boardid,
		checksum,
		connector,
		eaddrtemp,
		irq;
	/* ZZZ irq_translate should really be unsigned, but until
	 * isa_device.h and all uses are fixed we have to live with it */
/*      short irq_translate[] = {0, IRQ9, IRQ3, IRQ4, IRQ5, IRQ10, IRQ11, 0}; */

	short	irq_translate[] = {0, 0x09, 0x03, 0x04, 0x05, 0x0a, 0x0b, 0};

	DEBUGBEGIN(DEBUGPROBE)
	DEBUGDO(printf ("ixprobe:");)
	DEBUGEND

	/*
	 * Since Intel gives us such a nice way to ID this board lets
	 * see if we really have one at this I/O address
	 */
	idstate = inb(iobase + autoid) & 0x03;
	for (i=0, boardid=0; i < 4; i++) {
		tempid = inb(iobase + autoid);
		boardid |= ((tempid & 0xF0) >> 4) << ((tempid & 0x03) << 2);
		if ((tempid & 0x03) != (++idstate & 0x03)) {
			/* out of sequence, destroy boardid and bail out */
			boardid = 0;
			break;
		}
	}
	DEBUGBEGIN(DEBUGPROBE)
	DEBUGDO(printf("boardid = %x\n", boardid);)
	DEBUGEND
	if (boardid != BOARDID) {
		goto ixprobe_exit;
	}

	/*
	 * We now know that we have a board, so save the I/O base
	 * address in the softc and use the softc from here on out
	 */
	sc->sc_iobase = iobase;
	sc->sc_maddr = ISA_HOLE_VADDR(ia->ia_maddr);
	sc->sc_msize = ia->ia_msize;

	/*
	 * Reset the Bart ASIC by pulsing the reset bit and waiting
	 * the required 240 uSecounds.  Also place the 82586 in the reset
	 * mode so that we can access the EEPROM
	 */
	outb(sc->sc_iobase + ee_ctrl, GA_RESET);
	outb(sc->sc_iobase + ee_ctrl, 0);
	DELAY(240);
	outb(sc->sc_iobase + ee_ctrl, I586_RESET);

	/*
	 * Checksum the EEPROM, should be equal to BOARDID
	 */
	for (i=0, checksum=0; i<64; i++) {
		checksum += ixeeprom_read(sc, i);
	}
	DEBUGBEGIN(DEBUGPROBE)
	DEBUGDO(printf ("checksum = %x\n", checksum);)
	DEBUGEND
	if (checksum != BOARDID) {
		goto ixprobe_exit;
	}

	/*
	 * Do the I/O channel ready test
	 */
	{
	u_char		lock_bit;

	lock_bit = ixeeprom_read(sc, eeprom_lock_address);
	if (lock_bit & EEPROM_LOCKED) {
		DEBUGBEGIN(DEBUGPROBE)
		DEBUGDO(printf ("lockbit set, not doing io channel ready test\n");)
		DEBUGEND
	} else {
		u_char	bart_config,
			junk;

		bart_config = inb(sc->sc_iobase + config);
		bart_config |= BART_IOCHRDY_LATE | BART_IO_TEST_EN;
		outb(sc->sc_iobase + config, bart_config);
		junk = inb(sc->sc_iobase + 0x4000);	 /*XXX read junk */
		bart_config = inb(sc->sc_iobase + config);
		outb(sc->sc_iobase + config, bart_config & ~(BART_IO_TEST_EN));
		if (bart_config & BART_IO_RESULT) {
			printf ("iochannel ready test failed!!\n");
		} else {
			DEBUGBEGIN(DEBUGPROBE)
			DEBUGDO(printf ("iochannel ready test passed\n");)
			DEBUGEND
		}
	}
	}

	/*
	 * Size and test the memory on the board.  The size of the memory
	 * can be one of 16k, 32k, 48k or 64k.  It can be located in the
	 * address range 0xC0000 to 0xEFFFF on 16k boundaries.  Although
	 * the board can be configured for 0xEC0000 to 0xEEFFFF,
	 * or 0xFC0000 to 0xFFFFFF these ranges are not supported by 386bsd.
	 *
	 * If the size does not match the passed in memory allocation size
	 * issue a warning, but continue with the minimum of the two sizes.
	 */
	{
	u_short	memory_page;
	u_short	memory_adjust;
	u_short	memory_decode;
	u_short	memory_edecode;

	switch (ia->ia_msize) {
		case 65536:
		case 32768: /* XXX Only support 32k and 64k right now */
			{ break; }
		case 16384:
		case 49512:
		default: {
			printf("ixprobe mapped memory size out of range\n");
			goto ixprobe_exit;
		}
	}


	if ((kvtop(sc->sc_maddr) < 0xC0000) ||
	    (kvtop(sc->sc_maddr) + sc->sc_msize > 0xF0000)) {
		printf("ixprobe mapped memory address out of range\n");
		goto ixprobe_exit;
	}

	memory_page = (kvtop(sc->sc_maddr) & 0x3C000) >> 14;
	memory_adjust = MEMCTRL_FMCS16 | (memory_page & 0x3) << 2;
	memory_decode = ((1 << (sc->sc_msize / 16384)) - 1) << memory_page;
	memory_edecode = ((~memory_decode >> 4) & 0xF0) | (memory_decode >> 8);

	/* ZZZ This should be checked against eeprom location 6, low byte */
	outb(sc->sc_iobase + memdec, memory_decode & 0xFF);
	/* ZZZ This should be checked against eeprom location 1, low byte */
	outb(sc->sc_iobase + memctrl, memory_adjust);
	/* ZZZ Now if I could find this one I would have it made */
	outb(sc->sc_iobase + mempc, (~memory_decode & 0xFF));
	/* ZZZ I think this is location 6, high byte */
	outb(sc->sc_iobase + memectrl, memory_edecode); /*XXX disable Exxx */


	DEBUGBEGIN(DEBUGPROBE)
	DEBUGDO(printf("Physical address = %lx\n", kvtop(sc->sc_maddr));)
	DEBUGEND
	}

	/*
	 * first prime the stupid bart DRAM controller so that it
	 * works, then zero out all of memory.
	 */
	bzero(sc->sc_maddr, 32);
	bzero(sc->sc_maddr, sc->sc_msize);

	/*
	 * Get the type of connector used, either AUI, BNC or TPE.
	 */
	connector = ixeeprom_read(sc, eeprom_config1);
	if (connector & CONNECT_BNCTPE) {
		connector = ixeeprom_read(sc, eeprom_config2);
		if (connector & CONNECT_TPE) {
			sc->connector = TPE;
			DEBUGBEGIN(DEBUGPROBE)
			DEBUGDO(printf ("Using TPE connector\n");)
			DEBUGEND
		} else {
			sc->connector = BNC;
			DEBUGBEGIN(DEBUGPROBE)
			DEBUGDO(printf ("Using BNC connector\n");)
			DEBUGEND
		}
	} else {
		sc->connector = AUI;
		DEBUGBEGIN(DEBUGPROBE)
		DEBUGDO(printf ("Using AUI connector\n");)
		DEBUGEND
	}

	/*
	 * Get the encoded interrupt number from the EEPROM, check it
	 * against the passed in IRQ.  Issue a warning if they do not
	 * match.  Always use the passed in IRQ, not the one in the EEPROM.
	 */
	irq = ixeeprom_read(sc, eeprom_config1);
	irq = (irq & IRQ) >> IRQ_SHIFT;
	sc->irq_encoded = irq;
	irq = irq_translate[irq];
	if (irq != ia->ia_irq) {
		printf("Warning board is configured for IRQ %d\n", irq);
	}

	/*
	 * Get the slot width, either 8 bit or 16 bit.
	 */
	if (inb(sc->sc_iobase + config) & SLOT_WIDTH) {
		sc->width = WIDTH_16;
		DEBUGBEGIN(DEBUGPROBE)
		DEBUGDO(printf("Using 16-bit slot\n");)
		DEBUGEND
	} else {
		sc->width = WIDTH_8;
		DEBUGBEGIN(DEBUGPROBE)
		DEBUGDO(printf("Using 8-bit slot\n");)
		DEBUGEND
	}

	/*
	 * Get the hardware ethernet address from the EEPROM and
	 * save it in the softc for use by the 586 setup code.
	 */
	eaddrtemp = ixeeprom_read(sc, eeprom_enetaddr_high);
	sc->sc_arpcom.ac_enaddr[1] = eaddrtemp & 0xFF;
	sc->sc_arpcom.ac_enaddr[0] = eaddrtemp >> 8;
	eaddrtemp = ixeeprom_read(sc, eeprom_enetaddr_mid);
	sc->sc_arpcom.ac_enaddr[3] = eaddrtemp & 0xFF;
	sc->sc_arpcom.ac_enaddr[2] = eaddrtemp >> 8;
	eaddrtemp = ixeeprom_read(sc, eeprom_enetaddr_low);
	sc->sc_arpcom.ac_enaddr[5] = eaddrtemp & 0xFF;
	sc->sc_arpcom.ac_enaddr[4] = eaddrtemp >> 8;

	sc->flags = IXF_NONE;	/* make sure the flag word is NONE */
	ia->ia_iosize = IX_IO_PORTS;
	status = 1;

ixprobe_exit:
	DEBUGBEGIN(DEBUGPROBE)
	DEBUGDO(printf ("ixprobe exited\n");)
	DEBUGEND
	return(status);
}

void
ixattach(parent, self, aux)
	struct device *parent, *self;
	void *aux;
{
	struct ix_softc *sc = (void *)self;
	struct isa_attach_args *ia = aux;
	struct cfdata *cf = sc->sc_dev.dv_cfdata;
	struct ifnet *ifp = &sc->sc_arpcom.ac_if;

	struct ifaddr		*ifa;
	struct sockaddr_dl	*sdl;

	DEBUGBEGIN(DEBUGATTACH)
	DEBUGDO(printf("ixattach:");)
	DEBUGEND

	/*
	 * Fill in the interface parameters for if_attach
	 * Note:  We could save some code here by first using a
	 *        bzero(ifp, sizeof(ifp)); and then not doing all
	 *        the = 0;'s
	 *        Infact we should bzero this just to make sure
	 *        that something does not get missed.
	 */
	bzero(ifp, sizeof(ifp));
	ifp->if_name = ixcd.cd_name;
	ifp->if_unit = sc->sc_dev.dv_unit;;
	ifp->if_mtu = ETHERMTU;
	ifp->if_flags = IFF_NOTRAILERS | IFF_BROADCAST;
	/*
	 * This is commented out to save memory and cpu time
	 * ifp->if_timer = 0;
	 * ifp->if_metric = 0;
	 * ifp->if_addrlist = 0;
	 * ifp->if_snd.ifq_head = 0;
	 * ifp->if_snd.ifq_tail = 0;
	 * ifp->if_snd.ifq_len = 0;
	 * ifp->if_snd.ifq_maxlen = 0;
	 * ifp->if_snd.ifq_drops = 0;
	 * end of commented out block
	 */
	ifp->if_output = ether_output;
	ifp->if_start = ixstart;
	ifp->if_ioctl = ixioctl;
	ifp->if_watchdog = ixwatchdog;
	/*
	 * This is commented out to save memory and cpu time
	 * ifp->if_ipackets = 0;
	 * ifp->if_ierrors = 0;
	 * ifp->if_opackets = 0;
	 * ifp->if_oerrors = 0;
	 * ifp->if_collisions = 0;
	 * ifp->if_next = 0;
	 * end of commented out block
	 */
	ifp->if_type = IFT_ETHER;
	ifp->if_addrlen = ETHER_ADDRESS_LENGTH;
	ifp->if_hdrlen = ETHER_HEADER_LENGTH;
	/*
	 * This is commented out to save memory and cpu time
	 * ifp->if_index = 0;
	 * ifp->if_lastchange.tv_sec = 0;
	 * ifp->if_lastchange.tv_usec = 0;
	 * ifp->if_ibytes = 0;
	 * ifp->if_obytes = 0;
	 * ifp->if_imcasts = 0;
	 * ifp->if_omcasts = 0;
	 * ifp->if_iqdrops = 0;
	 * ifp->if_noproto = 0;
	 * ifp->if_baudrate = 0;
         * ifp->if_pcount = 0;
	 * end of commented out block
	 */
#ifdef IXCOUNTERS
	 /*
	  * ZZZ more counters added, but bzero gets them
	  */
#endif /* IXCOUNTERS */

	if_attach(ifp);
	printf("\nix%d: address %s\n", ifp->if_unit, ether_sprintf(sc->sc_arpcom.ac_enaddr));
	sc->sc_ih = isa_intr_establish(ia->ia_irq, ISA_IST_EDGE, ISA_IPL_NET,
		ixintr, sc);
}

void
ixinit(sc)
	struct ix_softc *sc;
{
	struct		ifnet *ifp = &sc->sc_arpcom.ac_if;
	scp_t		*scp = (scp_t *)(sc->sc_maddr + SCP_ADDR);
	iscp_t		*iscp = (iscp_t *)(sc->sc_maddr + ISCP_ADDR);
	scb_t		*scb = (scb_t *)(sc->sc_maddr + SCB_ADDR);
	cb_t		*cb;
	tbd_t		*tbd;
	int		i;
	u_char		bart_config;	/* bart config byte */
	int		status = 0;

	DEBUGBEGIN(DEBUGINIT)
	DEBUGDO(printf("ixinit:");)
	DEBUGEND

	/* Put bart into loopback until we are done intializing to
	 * make sure that packets don't hit the wire */
	bart_config = inb(sc->sc_iobase + config);
	bart_config |= BART_LOOPBACK;
	bart_config |= BART_MCS16_TEST;	/* inb does not get this bit! */
	outb(sc->sc_iobase + config, bart_config);
	bart_config = inb(sc->sc_iobase + config);

	scp->unused1 = 0;		/* Intel says to put zeros in it */
	scp->sysbus = sc->width;	/* ZZZ need to fix for 596 */
	scp->unused2 = 0;		/* Intel says to put zeros in it */
	scp->unused3 = 0;		/* Intel says to put zeros in it */
	scp->iscp = ISCP_ADDR;

	iscp->busy = ISCP_BUSY;
	iscp->scb_offset = SCB_ADDR;
	iscp->scb_base = TFA_START;

	scb->status = SCB_STAT_NULL;
	scb->command = SCB_RESET;
	scb->cbl_offset = TFA_START;
	scb->rfa_offset = RFA_START;
	scb->crc_errors = 0;
	scb->aln_errors = 0;
	scb->rsc_errors = 0;
	scb->ovr_errors = 0;

	ixinit_tfa(sc);
	ixinit_rfa(sc);
	cb = sc->cb_head;
	tbd = sc->tbd_head;

	/*
	 * remove the reset signal and start the 586 up, the 586 well read
         * the SCP, ISCP and the reset CB.  This should put it into a
	 * known state: RESET!
	 */
	outb(sc->sc_iobase + ee_ctrl, EENORMAL);
	ixchannel_attention(sc);

	for (i=100000; iscp->busy && (i>0); i--);	/* Wait for done */
	if (i == 0) {
		printf("iscp->busy time out\n");
		status = 1;
	} else {
		DEBUGBEGIN(DEBUGINIT)
		DEBUGDO(printf ("iscp->busy did not timeout = %d\n", i);)
		DEBUGEND
	}

	status |= ix_scb_wait(scb, (u_short)(SCB_STAT_CX | SCB_STAT_CNA),
	                      "Reset");
	ixacknowledge(sc);

/* XXX this belongs some place else, run diagnostics on the 586 */
	{
	cb_diagnose_t	*cb_diag = (cb_diagnose_t *)(cb);

	cb_diag->common.status = 0;
	cb_diag->common.command = CB_CMD_EL | CB_CMD_DIAGNOSE;
	scb->command = SCB_CUC_START;
	ixchannel_attention(sc);
	status |= ix_cb_wait((cb_t *)cb_diag, "Diagnose");
	status |= ix_scb_wait(scb, (u_short)SCB_STAT_CNA, "Diagnose");
	ixacknowledge(sc);
	}
/* XXX end this belongs some place else, run diagnostics on the 586 */

/* XXX this belongs some place else, run configure on the 586 */
	{
	cb_configure_t	*cb_conf = (cb_configure_t *)(cb);

	cb_conf->common.status = 0;
	cb_conf->common.command = CB_CMD_EL | CB_CMD_CONF;
	cb_conf->byte[0] = 12;		/* 12 byte configure block */
	cb_conf->byte[1] = 8;		/* fifo limit at 8 bytes */
	cb_conf->byte[2] = 0x40;	/* don't save bad frames,
					   srdy/ardy is srdy */
	cb_conf->byte[3] = 0x2E;	/* address length is 6 bytes,
					   address and length are in tb,
					   preamble length is 8 bytes,
					   internal loopback off,
					   external loopback off */
	cb_conf->byte[4] = 0;		/* linear priority is 0,
					   ACR (Exponential priorty) is 0,
					   exponential backoff is 802.3 */
	cb_conf->byte[5] = 96;		/* interframe spacing in TxC clocks */
	cb_conf->byte[6] = 0;		/* lower 8 bits of slot time */
	cb_conf->byte[7] = 0xf2;	/* upper slot time (512 bits),
					   15 transmision retries */
	cb_conf->byte[8] = 0;		/* promiscuous mode off,
					   broadcast enabled,
					   nrz encodeing,
					   cease transmission if ^CRS,
					   insert crc,
					   end of carrier mode bit stuffing,
					   no padding */
	cb_conf->byte[9] = 0;		/* carrier sense filter = 0 bits,
					   carrier sense source external,
					   collision detect filter = 0 bits,
					   collision detect source external */
	cb_conf->byte[10] = 60;		/* minimum number of bytes is a frame */
	cb_conf->byte[11] = 0;		/* unused */

	scb->command = SCB_CUC_START;
	ixchannel_attention(sc);
	status |= ix_cb_wait((cb_t *)cb_conf, "Configure");
	status |= ix_scb_wait(scb, (u_short)SCB_STAT_CNA, "Configure");
	ixacknowledge(sc);
	}
/* XXX end this belongs some place else, run configure on the 586 */

/* XXX this belongs some place else, run ias on the 586 */
	{
	cb_ias_t	*cb_ias = (cb_ias_t *)(cb);

	cb_ias->common.status = 0;
	cb_ias->common.command = CB_CMD_EL | CB_CMD_IAS;
	bcopy(sc->sc_arpcom.ac_enaddr, cb_ias->source, ETHER_ADDRESS_LENGTH);
	scb->command = SCB_CUC_START;
	ixchannel_attention(sc);
	status |= ix_cb_wait((cb_t *)cb_ias, "IAS");
	status |= ix_scb_wait(scb, (u_short)SCB_STAT_CNA, "IAS");
	ixacknowledge(sc);
	}
/* XXX end this belongs some place else, run ias on the 586 */

	if (status == 0) {
		/* Take bart out of loopback as we are done intializing */
		bart_config = inb(sc->sc_iobase + config);
		bart_config &= ~BART_LOOPBACK;
		bart_config |= BART_MCS16_TEST; /* inb does not get this bit! */
		outb(sc->sc_iobase + config, bart_config);

		/* The above code screwed with the tfa, reinit it! */
		ixinit_tfa(sc);
		scb->command = SCB_RUC_START;	/* start up the receive unit */
		ixchannel_attention(sc);
		sc->flags |= IXF_INITED;	/* we have been initialized */
		ifp->if_flags |= IFF_RUNNING;
		ifp->if_flags &= ~IFF_OACTIVE;
		ixinterrupt_enable(sc);		/* Let err fly!!! */
	}

	DEBUGBEGIN(DEBUGINIT)
	DEBUGDO(printf("ixinit exited\n");)
	DEBUGEND
	return;
}

/*
 * ixinit_rfa(int unit)
 *
 *	This routine initializes the Receive Frame Area for the 82586
 *
 * input	the unit number to build the RFA for
 * access	the softc for memory address
 * output	an initialized RFA, ready for packet receiption
 *		the following queue pointers in the softc structure are
 *		also initialize
 *		sc->rfd_head		sc->rfd_tail
 *		sc->rbd_head		sc->rbd_tail
 * defines	RFA_START	the starting offset of the RFA
 *		RFA_SIZE	size of the RFA area
 *		RB_SIZE		size of the receive buffer, this must
 *				be even and should be greater than the
 *				minumum packet size and less than the
 *				maximum packet size
 */

void
ixinit_rfa(sc)
	struct ix_softc *sc;
{
	rfd_t		*rfd;
	rbd_t		*rbd;
	caddr_t		rb;
	int		i,
			complete_frame_size,
			how_many_frames;

	DEBUGBEGIN(DEBUGINIT_RFA)
	DEBUGDO(printf("\nix%d: ixinit_rfa\n", sc->sc_dev.dv_unit);)
	DEBUGEND

	complete_frame_size = sizeof(rfd_t) + sizeof(rbd_t) + RB_SIZE;
	how_many_frames = RFA_SIZE / complete_frame_size;

	/* build the list of rfd's, rbd's and rb's */
	rfd = (rfd_t *)(sc->sc_maddr + RFA_START);
	rbd = (rbd_t *)(sc->sc_maddr +
	                RFA_START +
                        (how_many_frames * sizeof(rfd_t)));
	rb = sc->sc_maddr + RFA_START +
	     (how_many_frames * (sizeof(rfd_t) + sizeof(rbd_t)));
	sc->rfd_head = rfd;
	sc->rbd_head = rbd;
	for (i = 0; i < how_many_frames; i++, rfd++, rbd++, rb += RB_SIZE) {
		rfd->status = 0;
		rfd->command = 0;
		rfd->next = KVTOBOARD(rfd) + sizeof(rfd_t);
		rfd->rbd_offset = INTEL586NULL;
		/* ZZZ could bzero this, but just leave a note for now */
		/* ZZZ bzero(rfd->destination); */
		/* ZZZ bzero(rfd->source); */
		rfd->length = 0;

		rbd->act_count = 0;
		rbd->next = KVTOBOARD(rbd) + sizeof(rbd_t);
		rbd->buffer = KVTOBOARD(rb);
		rbd->size = RB_SIZE;

		/*
		 * handle the boundary conditions here.  for the zeroth
		 * rfd we must set the rbd_offset to point at the zeroth
		 * rbd.  for the last rfd and rbd we need to close the
		 * list into a ring and set the end of list bits.
		 */

		if (i == 0) {
			rfd->rbd_offset = KVTOBOARD(rbd);
		}
		if (i == how_many_frames - 1) {
			rfd->command = RFD_CMD_EL | RFD_CMD_SUSP;
			rfd->next = KVTOBOARD(sc->rfd_head);

			rbd->next = KVTOBOARD(sc->rbd_head);
			rbd->size = RBD_SIZE_EL | RB_SIZE;
		}

	}
	sc->rfd_tail = (--rfd);
	sc->rbd_tail = (--rbd);

#ifdef IXDEBUG
	DEBUGBEGIN(DEBUGINIT_RFA)
		rfd = (rfd_t *)(sc->sc_maddr + RFA_START);
		rbd = (rbd_t *)(sc->sc_maddr +
		               RFA_START +
		               (how_many_frames * sizeof(rfd_t)));
		rb = sc->sc_maddr + RFA_START +
		     (how_many_frames * (sizeof(rfd_t) + sizeof(rbd_t)));
		printf("  complete_frame_size = %d\n", complete_frame_size);
		printf("  how_many_frames = %d\n", how_many_frames);
		printf("  rfd_head = %lx\t\trfd_tail = %lx\n",
		       kvtop(sc->rfd_head), kvtop(sc->rfd_tail));
		printf("  rbd_head = %lx\t\trbd_tail = %lx\n",
		       kvtop(sc->rbd_head), kvtop(sc->rbd_tail));
		for (i = 0; i < how_many_frames; i++, rfd++, rbd++, rb += RB_SIZE) {
			printf("  %d:\trfd = %lx\t\trbd = %lx\t\trb = %lx\n",
			       i, kvtop(rfd), kvtop(rbd), kvtop(rb));
			printf("\trfd->command = %x\n", rfd->command);
			printf("\trfd->next = %x\trfd->rbd_offset = %x\n",
			          rfd->next,      rfd->rbd_offset);
			printf("\trbd->next = %x\trbd->size = %x",
			          rbd->next,      rbd->size);
			printf("\trbd->buffer = %lx\n\n",
			          rbd->buffer);
		}
	DEBUGEND
#endif /* IXDEBUG */

	/*
	 * ZZZ need to add sanity check to see if last rb runs into
	 * the stuff after it in memory, this should not be possible
	 * but if someone screws up with the defines it can happen
	 */
	DEBUGBEGIN(DEBUGINIT_RFA)
	DEBUGDO(printf ("  next rb would be at %lx\n", kvtop(rb));)
	DEBUGDO(printf("ix%d: ixinit_rfa exit\n", sc->sc_dev.dv_unit);)
	DEBUGEND
}

/*
 * ixinit_tfa(int unit)
 *
 *	This routine initializes the Transmit Frame Area for the 82586
 *
 * input	the unit number to build the TFA for
 * access	the softc for memory address
 * output	an initialized TFA, ready for packet transmission
 *		the following queue pointers in the softc structure are
 *		also initialize
 *		sc->cb_head		sc->cb_tail
 *		sc->tbd_head		sc->tbd_tail
 * defines	TB_COUNT	home many transmit buffers to create
 *		TB_SIZE		size of the tranmit buffer, this must
 *				be even and should be greater than the
 *				minumum packet size and less than the
 *				maximum packet size
 *		TFA_START	the starting offset of the TFA
 */

void
ixinit_tfa(sc)
	struct ix_softc *sc;
{
	cb_transmit_t	*cb;
	tbd_t		*tbd;
	caddr_t		tb;
	int		i;

	DEBUGBEGIN(DEBUGINIT_TFA)
	DEBUGDO(printf("\nix%d: ixinit_tfa\n", sc->sc_dev.dv_unit);)
	DEBUGEND

	/* build the list of cb's, tbd's and tb's */
	cb = (cb_transmit_t *)(sc->sc_maddr + TFA_START);
	tbd = (tbd_t *)(sc->sc_maddr +
	                TFA_START +
                        (TB_COUNT * sizeof(cb_transmit_t)));
	tb = sc->sc_maddr + TFA_START +
	     (TB_COUNT * (sizeof(cb_transmit_t) + sizeof(tbd_t)));
	sc->cb_head = (cb_t *)cb;
	sc->tbd_head = tbd;
	for (i = 0; i < TB_COUNT; i++, cb++, tbd++, tb += TB_SIZE) {
		cb->common.status = 0;
		cb->common.command = CB_CMD_NOP;
		cb->common.next = KVTOBOARD(cb) + sizeof(cb_transmit_t);
		cb->tbd_offset = KVTOBOARD(tbd);
		/* ZZZ could bzero this, but just leave a note for now */
		/* ZZZ bzero(cb->destination); */
		cb->length = 0;

		tbd->act_count = 0;
		tbd->act_count = TBD_STAT_EOF;
		tbd->next = KVTOBOARD(tbd) + sizeof(tbd_t);
		tbd->buffer = KVTOBOARD(tb);

		/*
		 * handle the boundary conditions here.
		 */

		if (i == TB_COUNT - 1) {
			cb->common.command = CB_CMD_EL | CB_CMD_NOP;
			cb->common.next = INTEL586NULL; /*RRR KVTOBOARD(sc->cb_head);*/
			tbd->next = INTEL586NULL; /*RRR KVTOBOARD(sc->tbd_head);*/
		}
	}
	sc->cb_tail = (cb_t *)(--cb);
	sc->tbd_tail = (--tbd);

#ifdef IXDEBUG
	DEBUGBEGIN(DEBUGINIT_TFA)
		cb = (cb_transmit_t *)(sc->sc_maddr + TFA_START);
		tbd = (tbd_t *)(sc->sc_maddr +
		               TFA_START +
		               (TB_COUNT * sizeof(cb_transmit_t)));
		tb = sc->sc_maddr + TFA_START +
		     (TB_COUNT * (sizeof(cb_transmit_t) + sizeof(tbd_t)));
		printf("  TB_COUNT = %d\n", TB_COUNT);
		printf("  cb_head = %lx\t\tcb_tail = %lx\n",
		       kvtop(sc->cb_head), kvtop(sc->cb_tail));
		printf("  tbd_head = %lx\t\ttbd_tail = %lx\n",
		       kvtop(sc->tbd_head), kvtop(sc->tbd_tail));
		for (i = 0; i < TB_COUNT; i++, cb++, tbd++, tb += TB_SIZE) {
			printf("  %d:\tcb = %lx\t\ttbd = %lx\t\ttb = %lx\n",
			       i, kvtop(cb), kvtop(tbd), kvtop(tb));
			printf("\tcb->common.command = %x\n", cb->common.command);
			printf("\tcb->common.next = %x\tcb->tbd_offset = %x\n",
			          cb->common.next,      cb->tbd_offset);
			printf("\ttbd->act_count = %x", tbd->act_count);
			printf("\ttbd->next = %x", tbd->next);
			printf("\ttbd->buffer = %lx\n\n",
			          tbd->buffer);
		}
	DEBUGEND
#endif /* IXDEBUG */

	/*
	 * ZZZ need to add sanity check to see if last tb runs into
	 * the stuff after it in memory, this should not be possible
	 * but if someone screws up with the defines it can happen
	 */
	DEBUGBEGIN(DEBUGINIT_TFA)
	DEBUGDO(printf ("  next tb would be at %lx\n", kvtop(tb));)
	DEBUGDO(printf("ix%d: ixinit_tfa exit\n", sc->sc_dev.dv_unit);)
	DEBUGEND
}


int
ixintr(arg)
	void *arg;
{
	struct ix_softc *sc = arg;
	struct	ifnet	*ifp = &sc->sc_arpcom.ac_if;
	scb_t		*scb = (scb_t *)(sc->sc_maddr + SCB_ADDR);
	int		check_queue;	/* flag to tell us to check the queue */
	u_short		status;

	DEBUGBEGIN(DEBUGINTR)
	DEBUGDO(printf("ixintr: ");)
	DEBUGEND

	if ((sc->flags & IXF_INITED) == 0) {
		printf ("\n ixintr without being inited!!\n"); /* ZZZ */
		ixinterrupt_disable(sc);
		goto ixintr_exit;
	}
	if (ifp->if_flags & IFF_RUNNING == 0) {
		printf("\n  ixintr when device not running!!\n"); /* ZZZ */
		ixinterrupt_disable(sc);
		goto ixintr_exit;
	}

	/* The sequence, disable ints, status=ack must be done
	 * as quick as possible to avoid missing things */
	ixinterrupt_disable(sc);
	status = ixacknowledge(sc);
	check_queue = 0;
	while ((status & SCB_STAT_MASK) != 0) {
		if (status & SCB_STAT_FR) {
			ixintr_fr(sc);
		}
		if (status & SCB_STAT_CX) {
			ixintr_cx(sc);
			check_queue++;
		}
		if (status & SCB_STAT_CNA) {
			DEBUGBEGIN(DEBUGINTR)
			DEBUGDO(printf("cna:");)
			DEBUGEND
		}
		if ((status & SCB_STAT_RNR) ||
		    ((status & SCB_RUS_MASK) == SCB_RUS_NRSC)) {
			DEBUGBEGIN(DEBUGINTR)
			printf("RNR:");		/* ZZZ this means trouble */
			DEBUGEND
			IXCOUNTER(ifp->if_rnr++;)
			ixinit_rfa(sc);
			scb->status = SCB_STAT_NULL;
			scb->command = SCB_RUC_START;
			scb->rfa_offset = RFA_START;
			ixchannel_attention(sc);
		}
		if (scb->status & SCB_STAT_MASK) {
			status = ixacknowledge(sc);
		} else {
			status = 0;
		}
	}

	ixinterrupt_enable(sc);
	if (check_queue && ifp->if_snd.ifq_head != 0) {
		ixstart(ifp);	/* we have stuff on the queue */
	}

ixintr_exit:
	DEBUGBEGIN(DEBUGINTR)
	DEBUGDO(printf(" ixintr exited\n");)
	DEBUGEND
	return(0 /* XXX Should be ??? */);
}

static inline void
ixintr_cx(sc)
	struct ix_softc *sc;
{
	struct ifnet	*ifp = &sc->sc_arpcom.ac_if;
	cb_t		*cb;

	DEBUGBEGIN(DEBUGINTR_CX)
	DEBUGDO(printf("cx:");)
	DEBUGEND
	cb = sc->cb_head;
	do {
		if (cb->status & CB_BUSY) {
			IXCOUNTER(ifp->if_busy++;)
			printf("ix.cx.busy");	/* This should never occur */
		}
		if (cb->status & CB_COMPLETE) {
			IXCOUNTER(ifp->if_complete++;)
			switch(cb->command & CB_CMD_MASK) {
				case CB_CMD_NOP: { break; }
				case CB_CMD_IAS: { break; }
				case CB_CMD_CONF: { break; }
				case CB_CMD_MCAS: { break; }
				case CB_CMD_TRANSMIT: {
					if (cb->status & CB_OK) {
						ifp->if_opackets++;
						IXCOUNTER(ifp->if_ok++;)
					} else {
						if (cb->status & CB_ABORT) {
							IXCOUNTER(ifp->if_abort++;)
							printf("ix.cx.abort");
						}
						if (cb->status & CB_LATECOLL) {
							IXCOUNTER(ifp->if_latecoll++;)
							printf("ix.cx.latecoll");
						}
						if (cb->status & CB_NOCS) {
							IXCOUNTER(ifp->if_nocs++;)
							printf("ix.cx.nocs");
						}
						if (cb->status & CB_NOCTS) {
							IXCOUNTER(ifp->if_nocts++;)
							printf("ix.cx.nocts");
						}
						if (cb->status & CB_DMAUNDER) {
							IXCOUNTER(ifp->if_dmaunder++;)
							printf("ix.cx.dmaunder");
						}
						if (cb->status & CB_DEFER) {
							IXCOUNTER(ifp->if_defer++;)
							printf("ix.cx.defer");
						}
						if (cb->status & CB_HEARTBEAT) {
							IXCOUNTER(ifp->if_heartbeat++;)
							printf("ix.cx.heartbeat");
						}
						if (cb->status & CB_EXCESSCOLL) {
							IXCOUNTER(ifp->if_excesscoll++;)
							printf("ix.cx.excesscoll");
						}
						ifp->if_oerrors++;
					}
					ifp->if_collisions += cb->status & CB_COLLISIONS;
					ifp->if_timer = 0;	/* clear watchdog timeout */
					break;
				}
				case CB_CMD_TDR: { break; }
				case CB_CMD_DUMP: { break; }
				case CB_CMD_DIAGNOSE: { break; }
				default: { break; }
			}
			ixintr_cx_free(sc, cb);
		} else {
		}
		if (cb->next == INTEL586NULL) {
			break;
		} else {
			cb = (cb_t *)BOARDTOKV(cb->next);
		}
	}
	while (1);
	/*
	 * clear the IFF_OACTIVE flag because the CU should now be
	 * idle, this only holds true as long as the last CB is the
	 * only one with the CB_CMD_INT bit set.  If the start routine
	 * violates this rule this code well have to change.
	 */
	ifp->if_flags &= ~IFF_OACTIVE;
	}

static inline void
ixintr_cx_free(sc, cb)
	struct ix_softc *sc;
	cb_t *cb;
{

	DEBUGBEGIN(DEBUGINTR_CX)
	DEBUGDO(printf("cb=%x:cb->status=%x:", KVTOBOARD(cb), cb->status);)
	DEBUGEND
/*1*/	cb->command = CB_CMD_EL | CB_CMD_NOP;
/*2*/	cb->status = 0;
}

static inline void
ixintr_fr(sc)
	struct ix_softc *sc;
{
	DEBUGBEGIN(DEBUGINTR_FR)
	DEBUGDO(printf("fr:");)
	DEBUGEND
	/* find each frame in the rfa and copy it up, then free it */
	while ((sc->rfd_head->status & (RFD_COMPLETE | RFD_BUSY)) == RFD_COMPLETE) {
		ixintr_fr_copy(sc, sc->rfd_head);
		ixintr_fr_free(sc, sc->rfd_head);
	}
}

static inline void
ixintr_fr_copy(sc, rfd)
	struct ix_softc *sc;
	rfd_t *rfd;
{
	struct		ifnet *ifp = &sc->sc_arpcom.ac_if;
	rbd_t		*rbd;
	caddr_t		rb;
	struct mbuf	*m0, *m;
	struct ether_header	*eh;
	int		length,
			bytesleft;

	rbd = (rbd_t *)(sc->sc_maddr + rfd->rbd_offset);
	rb = (caddr_t)(sc->sc_maddr + rbd->buffer);
	DEBUGBEGIN(DEBUGINTR_FR)
	DEBUGDO(int	i;)
	DEBUGDO(printf("rfd=%x:", KVTOBOARD(rfd));)
	DEBUGDO(printf("rfd->status=%x:", rfd->status);)
	DEBUGDO(printf("rbd->act_count=%x:", rbd->act_count);)
	DEBUGDO(printf("data=");)
	DEBUGDO(for (i = 0; i < 16; i ++) printf ("%02x", rb[i] & 0xFF);)
	DEBUGDO(printf(":");)
	DEBUGEND
	/* trickery here, eh points right at memory on
	 * the board.  eh is only used by ether_input,
	 * it is not passed to the upper layer */
	eh = (struct ether_header *)rb;

	/* here we go, lets build an mbuf chain up to hold all this */
	MGETHDR(m, M_DONTWAIT, MT_DATA);
	if (m == 0) {
		printf ("MGETHDR:"); /* ZZZ need to add drop counters */
		return;
	}
	m0 = m;
	length = rbd->act_count & RBD_STAT_SIZE;
	bytesleft = length - sizeof(struct ether_header);
	rb += sizeof(struct ether_header);
	m->m_pkthdr.rcvif = ifp;
	m->m_pkthdr.len = bytesleft;
	m->m_len = MHLEN;
	while (bytesleft > 0) {
		if (bytesleft > MINCLSIZE) {
			MCLGET(m, M_DONTWAIT);
			if (m->m_flags & M_EXT) {
				m->m_len = MCLBYTES;
			} else {
				printf ("MCLGET:");
				m_freem(m0); /* ZZZ need to add drop counters */
				return;
			}
		}
		m->m_len = min(m->m_len, bytesleft);
		bcopy(rb, mtod(m, caddr_t), m->m_len);
		rb += m->m_len;
		bytesleft -= m->m_len;
		if (bytesleft > 0) {
			MGET(m->m_next, M_DONTWAIT, MT_DATA);
			if (m->m_next == 0) {
				printf ("MGET");
				m_freem(m0); /* ZZZ need to add drop counters */
				return;
			}
			m = m->m_next;
			m->m_len = MLEN;
		}
	}

	ether_input(ifp, eh, m0);
	ifp->if_ipackets++;
	return;
}

static inline void
ixintr_fr_free(sc, rfd)
	struct ix_softc *sc;
	rfd_t *rfd;
{
	rbd_t		*rbd;

	rbd = (rbd_t *)(sc->sc_maddr + rfd->rbd_offset);

	/* XXX this still needs work, does not handle chained rbd's */
/*1*/	rbd->act_count = 0;
/*2*/	rbd->size = RBD_SIZE_EL | RB_SIZE;
/*3*/	sc->rbd_tail->size = RB_SIZE;
/*4*/	sc->rbd_tail = rbd;

	/* Free the rfd buy putting it back on the rfd queue */
/*1*/	rfd->command = RFD_CMD_EL | RFD_CMD_SUSP;
/*2*/	rfd->status = 0;
/*3*/	rfd->rbd_offset = INTEL586NULL;
/*4*/	sc->rfd_head = (rfd_t *)BOARDTOKV(rfd->next);
/*5*/	sc->rfd_tail->command &= ~(RFD_CMD_EL | RFD_CMD_SUSP);
/*6*/	sc->rfd_tail = rfd;
}

/* Psuedo code:
 * 	Do consistency check:
 *	  IFF_UP should be set.
 *	  IFF_RUNNING should be set.
 *	  IFF_OACTIVE should be clear.
 *	  ifp->snd.ifq_head should point to an MBUF
 *	  I82586 CU should be in the idle state.
 *	  All cb's should have CUC = NOP.
 *	The real work:
 *	  while there are packets to send & free cb's do:
 *		build a cb, tbd, and tb
 *		copy the MBUF chain to a tb
 *	  setup the scb for a start CU
 *	  start the CU
 *	  set IFF_OACTIVE
 *	  set ifp->if_timer for watchdog timeout
 *	Exit:
 */
void
ixstart(struct ifnet *ifp) {
	struct ix_softc	*sc = ixcd.cd_devs[ifp->if_unit];
	scb_t 		*scb = (scb_t *)BOARDTOKV(SCB_ADDR);
	cb_t		*cb = sc->cb_head;
	tbd_t		*tbd;
	caddr_t		tb;
	struct mbuf	*m, *m_temp;
	u_short		length;
	IXCOUNTER(int		queued;)

	DEBUGBEGIN(DEBUGSTART)
	DEBUGDO(printf("ixstart:");)
	DEBUGEND

	/* check that if is up and running */
	if ((ifp->if_flags & (IFF_UP | IFF_RUNNING)) != (IFF_UP | IFF_RUNNING)) {
		goto ixstart_exit;
	}

	/* check to see that we are not already active */
	if ((ifp->if_flags & IFF_OACTIVE) == IFF_OACTIVE) {
		goto ixstart_exit;
	}

	/* check that there are packets to send */
	if (ifp->if_snd.ifq_head == 0) {
		goto ixstart_exit;
	}

	/* check that the command unit is idle */
	if ((scb->status & SCB_CUS_MASK) != SCB_CUS_IDLE) {
		goto ixstart_exit;
	}

	/* check that all cb's on the list are free */
#ifdef THISDONTDONOTHING
	cb = sc->cb_head;
	IXCOUNTER(ifp->if_could_queue = 0;)
	do {
		/* XXX this does nothing right now! */
		DEBUGBEGIN(DEBUGSTART)
		DEBUGDO(printf("chk_cb=%x:", KVTOBOARD(cb));)
		DEBUGEND
		IXCOUNTER(ifp->if_could_queue++;)
		if (cb->next == INTEL586NULL) {
			break;
		} else {
			cb = (cb_t *)BOARDTOKV(cb->next);
		}
	}
	while (1);
#endif /* THISDONTDONOTHING */

	/* build as many cb's as we can */
	IXCOUNTER(queued = 0;)
	cb = sc->cb_head;
	do {
		cb->status = 0;
		cb->command = CB_CMD_TRANSMIT;
		tbd = (tbd_t *)BOARDTOKV(((cb_transmit_t *)cb)->tbd_offset);
		tb = (caddr_t)BOARDTOKV(tbd->buffer);
		DEBUGBEGIN(DEBUGSTART)
		DEBUGDO(printf("cb=%x:", KVTOBOARD(cb));)
		DEBUGDO(printf("tbd=%x:", KVTOBOARD(tbd));)
		DEBUGDO(printf("tb=%x:", KVTOBOARD(tb));)
		DEBUGEND

		IF_DEQUEUE(&ifp->if_snd, m);
		length = 0;
		for (m_temp = m; m_temp != 0; m_temp = m_temp->m_next) {
			bcopy(mtod(m_temp, caddr_t), tb, m_temp->m_len);
			tb += m_temp->m_len;
			length += m_temp->m_len;
		}
		m_freem(m);
		if (length < ETHER_MIN_LENGTH) length = ETHER_MIN_LENGTH;
#ifdef DIAGNOSTIC
		if (length > ETHER_MAX_LENGTH) {
			/* XXX
 			 * This should never ever happen, if it does
			 * we probable screwed up all sorts of board data
			 * in the above bcopy's and should probably shut
			 * down, but for now just issue a warning that
			 * something is real wrong
			 */
			printf("ix%d: ixstart: Packet length=%d > MTU=%d\n",
			        ifp->if_unit, length, ETHER_MAX_LENGTH);
		}
#endif /* DIAGNOSTIC */
		tbd->act_count = TBD_STAT_EOF | length;
		IXCOUNTER(queued++;)
		/* check to see if we have used the last cb */
		if (cb->next == INTEL586NULL) {
			IXCOUNTER(ifp->if_filled_queue++;)
			break;
		} else {
			cb = (cb_t *)BOARDTOKV(cb->next);
		}
	} while (ifp->if_snd.ifq_head != 0);
	IXCOUNTER(ifp->if_high_queue = max(ifp->if_high_queue, queued);)

	/* set the end of list and interrupt bits in the last cb */
	cb->command |= (CB_CMD_EL | CB_CMD_INT);

	/* build the scb */
	scb->status = SCB_STAT_NULL;
	scb->command = SCB_CUC_START;
	scb->cbl_offset = KVTOBOARD(sc->cb_head);/* This should not be needed */

	/* start the cu */
	ixchannel_attention(sc);

	/* mark the interface as having output active */
	ifp->if_flags |= IFF_OACTIVE;

	/*
	 * set the watchdog timer so that if the board fails to interrupt
	 * we will go clean up
	 */
	ifp->if_timer = 2;

ixstart_exit:
	DEBUGBEGIN(DEBUGSTART)
	DEBUGDO(printf("ixstart exited\n");)
	DEBUGEND
	return;
}

int
ixstop(struct ifnet *ifp) {
	struct ix_softc *sc = ixcd.cd_devs[ifp->if_unit];

	DEBUGBEGIN(DEBUGSTOP)
	DEBUGDO(printf("ixstop:");)
	DEBUGEND

	/* XXX Need to find out what spl we are at, and maybe add splx */

	ifp->if_flags &= ~IFF_RUNNING;
	ixinterrupt_disable(sc);

	/* force the 82586 reset pin high */
	outb(sc->sc_iobase + ee_ctrl, I586_RESET);

	DEBUGBEGIN(DEBUGSTOP)
	DEBUGDO(printf("ixstop exiting\n");)
	DEBUGEND
	return(0);
}

int
ixioctl(struct ifnet *ifp, u_long cmd, caddr_t data) {
	struct ix_softc *sc = ixcd.cd_devs[ifp->if_unit];
	int	status = 0;

	DEBUGBEGIN(DEBUGIOCTL)
	DEBUGDO(printf("ixioctl:");)
	DEBUGEND
	switch(cmd) {

	case SIOCSIFADDR: {
		struct ifaddr *ifa = (struct ifaddr *)data;

		if (ifp->if_flags & IFF_RUNNING) ixstop(ifp);
		ifp->if_flags |= IFF_UP;
		ixinit(sc);

		switch(ifa->ifa_addr->sa_family) {
#ifdef INET
			case AF_INET: {
				arp_ifinit((struct arpcom *)ifp, ifa);
				break;
			}
#endif /* INET */
#ifdef NS
			case AF_NS: {
				/*ZZZ*/printf("Address family NS not supported by ixioctl\n");
				break;
			}
#endif /* NS */
			default: {
				DEBUGBEGIN(DEBUGIOCTL)
				DEBUGDO(printf("Unknow Address Family in ixioctl\n");)
				DEBUGEND
				status = EINVAL;
				break;
			}
		}
		break;
	}

	case SIOCSIFFLAGS: {
		if (((ifp->if_flags & IFF_UP) == 0) &&
		     (ifp->if_flags & IFF_RUNNING)) {
			ixstop(ifp);
		}
		else if ((ifp->if_flags & IFF_UP) &&
		        ((ifp->if_flags & IFF_RUNNING) == 0)) {
			ixinit(sc);
		}
		break;
	}

	default: {
		DEBUGBEGIN(DEBUGIOCTL)
		DEBUGDO(printf("Unknown cmd in ixioctl\n");)
		DEBUGEND
		status = EINVAL;
		break;
	}
	}

	DEBUGBEGIN(DEBUGIOCTL)
	DEBUGDO(printf("ixioctl exit\n");)
	DEBUGEND
	return(status);
}

void
ixreset(sc)
	struct ix_softc *sc;
{
	struct	ifnet	*ifp = &sc->sc_arpcom.ac_if;
	int		s;

	s = splimp();
	DEBUGBEGIN(DEBUGRESET)
	DEBUGDO(printf("ixreset:");)
	DEBUGEND

	ixstop(ifp);
	ixinit(sc);

	DEBUGBEGIN(DEBUGRESET)
	DEBUGDO(printf("ixreset exit\n");)
	DEBUGEND
	(void) splx(s);
	return;
}

/*
 * The ixwatchdog routine gets called if the transmitter failed to interrupt
 * within ifp->if_timer XXXseconds.  The interrupt service routine must reset
 * ifp->if_timer to 0 after an transmitter interrupt occurs to stop the
 * watchdog from happening.
 */
void
ixwatchdog(unit)
	int unit;
{
	struct ix_softc *sc = ixcd.cd_devs[unit];

	log(LOG_ERR, "ix%d: device timeout\n", unit);
	sc->sc_arpcom.ac_if.if_oerrors++;

	ixreset(sc);
}

u_short
ixeeprom_read(sc, location)
	struct ix_softc *sc;
	int location;
{
	int	eeprom_control,
		data;
	int iobase = sc->sc_iobase;

	eeprom_control = inb(iobase + ee_ctrl);
	eeprom_control &= 0xB2; /* XXX fix 0xB2 */
	eeprom_control |= EECS;
	outb(iobase + ee_ctrl, eeprom_control);
	ixeeprom_outbits(sc, eeprom_read_op, eeprom_opsize1);
	ixeeprom_outbits(sc, location, eeprom_addr_size);
	data = ixeeprom_inbits(sc);
	eeprom_control = inb(iobase + ee_ctrl);
	eeprom_control &= ~(GA_RESET | EEDI | EECS);
	outb(iobase + ee_ctrl, eeprom_control);
	ixeeprom_clock(sc, 1);
	ixeeprom_clock(sc, 0);
	return(data);
}

void
ixeeprom_outbits(sc, data, count)
	struct ix_softc *sc;
	int data, count;
{
	int	eeprom_control,
		i;
	int	iobase = sc->sc_iobase;

	eeprom_control = inb(iobase + ee_ctrl);
	eeprom_control &= ~GA_RESET;
	for(i=count-1; i>=0; i--) {
		eeprom_control &= ~EEDI;
		if (data & (1 << i)) {
			eeprom_control |= EEDI;
		}
		outb(iobase + ee_ctrl, eeprom_control);
		DELAY(1); /* eeprom data must be setup for 0.4 uSec */
		ixeeprom_clock(sc, 1);
		ixeeprom_clock(sc, 0);
	}
	eeprom_control &= ~EEDI;
	outb(iobase + ee_ctrl, eeprom_control);
	DELAY(1); /* eeprom data must be held for 0.4 uSec */
}

int
ixeeprom_inbits(sc)
	struct ix_softc *sc;
{
	int	eeprom_control,
		data,
		i;
	int iobase = sc->sc_iobase;

	eeprom_control = inb(iobase + ee_ctrl);
	eeprom_control &= ~GA_RESET;
	for(data=0, i=0; i<16; i++) {
		data = data << 1;
		ixeeprom_clock(sc, 1);
		eeprom_control = inb(iobase + ee_ctrl);
		if (eeprom_control & EEDO) {
			data |= 1;
		}
		ixeeprom_clock(sc, 0);
	}
	return(data);
}

void
ixeeprom_clock(sc, state)
	struct ix_softc *sc;
	int state;
{
	int	eeprom_control;
	int	iobase = sc->sc_iobase;

	eeprom_control = inb(iobase + ee_ctrl);
	eeprom_control &= ~(GA_RESET | EESK);
	if (state) {
		eeprom_control = eeprom_control | EESK;
	}
	outb(iobase + ee_ctrl, eeprom_control);
	DELAY(9); /* EESK must be stable for 8.38 uSec */
}

-----cut here-----

/*
 * Copyright (c) 1993, 1994, 1995
 *	Rodney W. Grimes, Milwaukie, Oregon  97222.  All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer as
 *    the first lines of this file unmodified.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 * 3. All advertising materials mentioning features or use of this software
 *    must display the following acknowledgement:
 *	This product includes software developed by Rodney W. Grimes.
 * 4. The name of the author may not be used to endorse or promote products
 *    derived from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY RODNEY W. GRIMES ``AS IS'' AND ANY EXPRESS OR
 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
 * IN NO EVENT SHALL RODNEY W. GRIMES BE LIABLE FOR ANY DIRECT, INDIRECT,
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 *
 *	$Id: if_ixreg.h,v 1.6 1995/05/30 08:02:17 rgrimes Exp $
 */

/*
 * These really belong some place else, but I can't find them right
 * now.  I'll look again latter
 */
#define	ETHER_ADDRESS_LENGTH	6	/* Length of an ethernet address */
#define	ETHER_HEADER_LENGTH	14	/* Length of an ethernet header */
#define	ETHER_DATA_LENGTH	ETHERMTU
#define	ETHER_CRC_LENGTH	4
#define	ETHER_MIN_LENGTH	64	/* Minimum length of an ethernet packet */
#define ETHER_MAX_LENGTH	(ETHER_HEADER_LENGTH + \
				 ETHERMTU + \
				 ETHER_CRC_LENGTH)

#define	IX_IO_PORTS	16	/* Number of I/O ports used, note
				 * this is not true, due to shadow
				 * ports at 400X,800X and C00X
				 */

#define	dxreg		0x00	/* Data transfer register	Word R/W */
#define	wrptr		0x02	/* Write address pointer	Word R/W */
#define	rdptr		0x04	/* Read address pointer		Word R/W */
#define	ca_ctrl		0x06	/* Channel attention control	Byte R/W */
#define	sel_irq		0x07	/* IRQ select			Byte R/W */
#define	  IRQ_ENABLE	  0x08	/* Enable board interrupts */
#define	smb_ptr		0x08	/* Shadow memory bank pointer	Word R/W */
#define	memdec		0x0A	/* Memory address decode	Byte   W */
#define	memctrl		0x0B	/* Memory mapped control	Byte R/W */
#define	  MEMCTRL_UNUSED  0x83	/* Unused bits */
#define	  MEMCTRL_MEMMEG  0x60	/* Which megabyte of memory, 0, E or F */
#define	  MEMCTRL_FMCS16  0x10	/* MEMCS16- for F000 */
#define	  MEMCTRL_MEMADJ  0xC0	/* memory adjust value */
#define	mempc		0x0C	/* MEMCS16- page control	Byte R/W */
#define	config		0x0D	/* Configuration, test		Byte R/W */
#define	 BART_LINK	  0x01	/* link integrity active, TPE */
#define	 BART_LOOPBACK	  0x02	/* Loopback, 0=none, 1=loopback */
#define	 SLOT_WIDTH	  0x04	/* 0 = 8bit, 1 = 16bit */
#define	 BART_USEWIDTH	  0x08	/* use SLOT_WIDTH for bus size */
#define	 BART_IOCHRDY_LATE 0x10 /* iochrdy late control bit */
#define	 BART_IO_TEST_EN  0x20	/* enable iochrdy timing test */
#define	 BART_IO_RESULT	  0x40	/* result of the iochrdy test */
#define	 BART_MCS16_TEST  0x80	/* enable memcs16 select test */
#define	ee_ctrl		0x0E	/* EEPROM control, reset	Byte R/W */
#define	  EENORMAL	  0x00	/* normal state of ee_ctrl */
#define	  EESK		  0x01	/* EEPROM clock bit */
#define	  EECS		  0x02	/* EEPROM chip select */
#define	  EEDI		  0x04	/* EEPROM data in bit (write EEPROM) */
#define	  EEDO		  0x08	/* EEPROM data out bit (read EEPROM) */
#define	  EEUNUSED	  0x30	/* unused bits in ee_ctrl */
#define	  GA_RESET	  0x40	/* BART ASIC chip reset pin */
#define	  I586_RESET	  0x80  /* 82586 chip reset pin */
#define	memectrl	0x0F	/* Memory control, E000h seg	Byte   W */
#define	autoid		0x0F	/* Auto ID register		Byte R   */

#define	BOARDID		0xBABA	/* Intel PCED board ID for EtherExpress */

#define	eeprom_opsize1		0x03	/* Size of opcodes for r/w/e */
#define	eeprom_read_op		0x06	/* EEPROM read op code */
#define	eeprom_write_op		0x05	/* EEPROM write op code */
#define	eeprom_erase_op		0x07	/* EEPROM erase op code */
#define	eeprom_opsize2		0x05	/* Size of opcodes for we/wdr */
#define	eeprom_wenable_op	0x13	/* EEPROM write enable op code */
#define	eeprom_wdisable_op	0x10	/* EEPROM write disable op code */

#define	eeprom_addr_size	0x06	/* Size of EEPROM address */

/* These are the locations in the EEPROM */
#define	eeprom_config1		0x00	/* Configuration register 1 */
#define	  CONNECT_BNCTPE	0x1000	/* 0 = AUI, 1 = BNC/TPE */
#define	  IRQ			  0xE000	/* Encoded IRQ */
#define	  IRQ_SHIFT		  13		/* To shift IRQ to lower bits */
#define	eeprom_lock_address	0x01	/* contains the lock bit */
#define	  EEPROM_LOCKED		 0x01	/* means that it is locked */
#define	eeprom_enetaddr_low	0x02	/* Ethernet address, low word */
#define	eeprom_enetaddr_mid	0x03	/* Ethernet address, middle word */
#define	eeprom_enetaddr_high	0x04	/* Ethernet address, high word */
#define	eeprom_config2		0x05	/* Configureation register 2 */
#define	  CONNECT_TPE		  0x0001	/* 0 = BNC, 1 = TPE */

/* this converts a kernal virtual address to a board offset */
#define	KVTOBOARD(addr)	((int)addr - (int)sc->sc_maddr)
#define BOARDTOKV(addr) ((int)addr + (int)sc->sc_maddr)

/* XXX This belongs is ic/i825x6.h, but is here for editing for now */

#define	INTEL586NULL	0xFFFF		/* NULL pointer for 82586 */
#define	INTEL596NULL	0xFFFFFFFF	/* NULL pointer for 82596 */

/*
 * Layout of memory for the 825x6 chip:
 * Low:		Control Blocks
 *		Transmit Frame Descriptor(s)
 *		Transmit Frame Buffer(s)
 *		Receive Frame Descriptors
 *		Receive Frames
 *		SCB_ADDR	System Control Block
 *		ISCP_ADDR	Intermediate System Configuration Pointer
 * High:	SCP_ADDR	System Configuration Pointer
 */
#define	SCP_ADDR	(sc->sc_msize - sizeof(scp_t))
#define	ISCP_ADDR	(SCP_ADDR - sizeof(iscp_t))
#define	SCB_ADDR	(ISCP_ADDR - sizeof(scb_t))

#define	TB_COUNT	3	/* How many transfer buffers in the TFA */
#define TB_SIZE		(ETHER_MAX_LENGTH)	/* size of transmit buffer */
#define	TFA_START	0x0000	/* Start of the TFA */
#define	TFA_SIZE	(TB_COUNT * \
			(sizeof(cb_transmit_t) + sizeof(tbd_t) + TB_SIZE))

#define	RFA_START	(TFA_SIZE)
#define	RFA_SIZE	(SCP_ADDR - RFA_START)
#define	RB_SIZE		(ETHER_MAX_LENGTH)	/* size of receive buffer */

typedef struct /* System Configuration Pointer */
	{
	u_short	unused1;	/* should be zeros for 82596 compatibility */
	u_short	sysbus;		/* width of the 82586 data bus 0=16, 1=8 */
	u_short	unused2;	/* should be zeros for 82596 compatibility */
	u_short	unused3;	/* should be zeros for 82596 compatibility */
	u_long	iscp;		/* iscp address (24bit 586, 32bit 596) */
	}	scp_t;

typedef struct /* Intermediate System Configuration Pointer */
	{
	volatile
	u_short	busy;		/* Set to 1 by host before its first CA,
				   cleared by 82586 after reading */
#define	ISCP_BUSY	0x01	/* 82586 is busy reading the iscp */
	u_short	scb_offset;	/* Address of System Control Block */
	u_long	scb_base;	/* scb base address (24bit 586, 32bit 596) */
	}	iscp_t;

typedef struct /* System Control Block */
	{
	volatile
	u_short	status;		/* status bits */
#define	SCB_RUS_MASK	0x0070	/* receive unit status mask */
#define	SCB_RUS_IDLE	0x0000	/* receive unit status idle */
#define	SCB_RUS_SUSP	0x0010	/* receive unit status suspended */
#define	SCB_RUS_NRSC	0x0020	/* receive unit status no resources */
#define	SCB_RUS_READY	0x0040	/* receive unit status ready */
#define	SCB_CUS_MASK	0x0700	/* command unit status mask */
#define	SCB_CUS_IDLE	0x0000	/* command unit status idle */
#define	SCB_CUS_SUSP	0x0100	/* command unit status suspended */
#define	SCB_CUS_ACT	0x0200	/* command unit status active */
#define	SCB_STAT_MASK	0xF000	/* command unit status mask */
#define	SCB_STAT_RNR	0x1000	/* receive unit left the ready state */
#define	SCB_STAT_CNA	0x2000	/* command unit left the active state */
#define	SCB_STAT_FR	0x4000	/* the ru finished receiving a frame */
#define	SCB_STAT_CX	0x8000	/* the cu finished executing a command
				   with its I (interrupt) bit set */
#define	SCB_STAT_NULL	0x0000	/* used to clear the status work */
	u_short	command;	/* command bits */
#define	SCB_RUC_MASK	0x0070	/* receive unit command mask */
#define	SCB_RUC_NOP	0x0000	/* receive unit command nop */
#define	SCB_RUC_START	0x0010	/* receive unit command start */
#define	SCB_RUC_RESUME	0x0020	/* receive unit command resume */
#define	SCB_RUC_SUSP	0x0030	/* receive unit command suspend */
#define SCB_RUC_ABORT	0x0040	/* receive unit command abort */
#define SCB_RESET	0x0080	/* reset the chip, same as hardware reset */
#define	SCB_CUC_MASK	0x0700	/* command unit command mask */
#define	SCB_CUC_NOP	0x0000	/* command unit command nop */
#define	SCB_CUC_START	0x0100	/* start execution of the first command */
#define	SCB_CUC_RESUME	0x0200	/* resume execution of the next command */
#define	SCB_CUC_SUSP	0x0300	/* suspend execution after the current command */
#define	SCB_CUC_ABORT	0x0400	/* abort execution of the current command */
#define	SCB_ACK_MASK	0xF000	/* command unit acknowledge mask */
#define	SCB_ACK_RNR	0x1000	/* ack receive unit left the ready state */
#define	SCB_ACK_CNA	0x2000	/* ack command unit left the active state */
#define	SCB_ACK_FR	0x4000	/* ack the ru finished receiving a frame */
#define	SCB_ACK_CX	0x8000	/* ack the cu finished executing a command
				   with its I (interrupt) bit set */
	u_short	cbl_offset;	/* first command block on the cbl */
	u_short	rfa_offset;	/* receive frame area */
	volatile
	u_short	crc_errors;	/* frame was aligned, but bad crc */
	volatile
	u_short	aln_errors;	/* frame was not aligned, and had bad crc */
	volatile
	u_short	rsc_errors;	/* did not have resources to receive */
	volatile
	u_short	ovr_errors;	/* system bus was not availiable to receive */
	}	scb_t;

typedef struct /* command block - nop (also the common part of cb's */
	{
	volatile
	u_short	status;		/* status bits */
#define	CB_COLLISIONS	0x000F	/* the number of collisions that occured */
#define	CB_BIT4		0x0010	/* reserved by intel */
#define	CB_EXCESSCOLL	0x0020	/* the number of collisions > MAX allowed */
#define	CB_HEARTBEAT	0x0040	/* */
#define	CB_DEFER	0x0080	/* had to defer due to trafic */
#define	CB_DMAUNDER	0x0100	/* dma underrun */
#define	CB_NOCTS	0x0200	/* lost clear to send */
#define	CB_NOCS		0x0400	/* lost carrier sense */
#define	CB_LATECOLL	0x0800	/* late collision occured (82596 only) */
#define	CB_ABORT	0x1000	/* command was aborted by CUC abort command */
#define	CB_OK		0x2000	/* command executed without error */
#define	CB_BUSY		0x4000	/* command is being executed */
#define	CB_COMPLETE	0x8000	/* command completed */
	u_short	command;	/* command bits */
#define	CB_CMD_MASK	0x0007	/* command mask */
#define	CB_CMD_NOP	0x0000	/* nop command */
#define	CB_CMD_IAS	0x0001	/* individual address setup command */
#define	CB_CMD_CONF	0x0002	/* configure command */
#define	CB_CMD_MCAS	0x0003	/* multicast address setup command */
#define	CB_CMD_TRANSMIT	0x0004	/* transmit command */
#define	CB_CMD_TDR	0x0005	/* time domain reflectometry command */
#define	CB_CMD_DUMP	0x0006	/* dump command */
#define	CB_CMD_DIAGNOSE	0x0007	/* diagnose command */
#define	CB_CMD_INT	0x2000	/* interrupt when command completed */
#define	CB_CMD_SUSP	0x4000	/* suspend CU when command completed */
#define	CB_CMD_EL	0x8000	/* end of the command block list */
	u_short	next;		/* pointer to the next cb */
	}	cb_t;

typedef	struct /* command block - individual address setup command */
	{
	cb_t	common;		/* common part of all command blocks */
	u_char	source[ETHER_ADDRESS_LENGTH];
				/* ethernet hardware address */
	}	cb_ias_t;

typedef	struct /* command block - configure command */
	{
	cb_t	common;		/* common part of all command blocks */
	u_char	byte[12];	/* ZZZ this is ugly, but it works */
	}	cb_configure_t;

typedef	struct /* command block - multicast address setup command */
	{
	cb_t	common;		/* common part of all command blocks */
	}	cb_mcas_t;

typedef	struct /* command block - transmit command */
	{
	cb_t	common;		/* common part of all command blocks */
	u_short	tbd_offset;	/* transmit buffer descriptor offset */
	u_char	destination[ETHER_ADDRESS_LENGTH];
				/* ethernet destination address field */
	u_short	length;		/* ethernet length field */
	u_char	byte[16];	/* XXX stupid fill tell I fix the ixinit
				 * code for the special cb's */
	}	cb_transmit_t;

typedef	struct /* command block - tdr command */
	{
	cb_t	common;		/* common part of all command blocks */
	}	cb_tdr_t;

typedef	struct /* command block - dump command */
	{
	cb_t	common;		/* common part of all command blocks */
	}	cb_dump_t;

typedef	struct /* command block - diagnose command */
	{
	cb_t	common;		/* common part of all command blocks */
	}	cb_diagnose_t;

typedef struct /* Transmit Buffer Descriptor */
	{
	volatile
	u_short	act_count;	/* size of buffer actual count of valid bytes */
#define	TBD_STAT_EOF	0x8000	/* end of frame */
	u_short	next;		/* pointer to the next tbd */
	u_long	buffer;		/* transmit buffer address (24bit 586, 32bit 596) */
	}	tbd_t;

typedef	struct /* Receive Frame Descriptor */
	{
	volatile
	u_short	status;		/* status bits */
#define	RFD_BUSY	0x4000	/* frame is being received */
#define	RFD_COMPLETE	0x8000	/* this frame is complete */
	u_short	command;	/* command bits */
#define	RFD_CMD_SUSP	0x4000	/* suspend the ru after this rfd is used */
#define	RFD_CMD_EL	0x8000	/* end of the rfd list */
	u_short	next;		/* pointer to the next rfd */
	u_short	rbd_offset;	/* pointer to the first rbd for this frame */
	u_char	destination[6];	/* ethernet destination address */
	u_char	source[6];	/* ethernet source address */
	u_short	length;		/* ethernet length field */
	}	rfd_t;

typedef	struct /* Receive Buffer Descriptor */
	{
	volatile
	u_short	act_count;	/* Actual Count (size) and status bits */
#define	RBD_STAT_SIZE	0x3FFF	/* size mask */
#define	RBD_STAT_VALID	0x4000	/* act_count field is valid */
#define	RBD_STAT_EOF	0x8000	/* end of frame */
	u_short	next;		/* pointer to the next rbd */
	u_long	buffer;		/* receive buffer address */
	u_short	size;		/* size of buffer in bytes, must be even */
#define	RBD_SIZE_EL	0x8000	/* end of rbd list */
	}	rbd_t;

/*
 * Ethernet software status per interface.
 *
 * Each interface is referenced by a network interface structure,
 * arpcom.ac_if, which the routing code uses to locate the interface.
 * This structure contains the output queue for the interface, its address, ...
 */
struct ix_softc {
	struct	device sc_dev;
	void *sc_ih;

	struct arpcom sc_arpcom;	/* ethernet common */

	int sc_iobase;
	caddr_t sc_maddr;
	u_int sc_msize;

	int	flags;			/* Software state */
#define	IXF_NONE	0x00000000	/* Clear all flags */
#define	IXF_INITED	0x00000001	/* Device has been inited */
#define	IXF_BPFATTACHED	0x80000000	/* BPF has been attached */
	int	connector;		/* Type of connector used on board */
#define	AUI		0x00		/* Using AUI connector */
#define	BNC		0x01		/* Using BNC connector */
#define TPE		0x02		/* Using TPE connector */
	u_short	irq_encoded;		/* Encoded interrupt for use on bart */
	int	width;			/* Width of slot the board is in, these
					 * constants are defined to match what
					 * the 82586/596 wants in scp->sysbus */
#define	WIDTH_8		0x01		/* 8-bit slot */
#define WIDTH_16	0x00		/* 16-bit slot */
	cb_t	*cb_head;		/* head of cb list */
	cb_t	*cb_tail;		/* tail of cb list */
	tbd_t	*tbd_head;		/* head of the tbd list */
	tbd_t	*tbd_tail;		/* tail of the tbd list */
	rfd_t	*rfd_head;		/* head of the rfd list */
	rfd_t	*rfd_tail;		/* tail of the rfd list */
	rbd_t	*rbd_head;		/* head of the rbd list */
	rbd_t	*rbd_tail;		/* tail of the rbd list */
	};

-----cut here-----
That's it!
>Audit-Trail:
>Unformatted: