*BSD News Article 4710


Return to BSD News archive

Xref: sserve alt.sources:4045 comp.unix.bsd:4758
Newsgroups: alt.sources,comp.unix.bsd
Path: sserve!manuel!munnari.oz.au!spool.mu.edu!uunet!emba-news.uvm.edu!trantor.emba.uvm.edu!wollman
From: wollman@trantor.emba.uvm.edu (Garrett Wollman)
Subject: [386BSD] Intel Ethernet driver, new release
Message-ID: <1992Sep8.224501.8592@uvm.edu>
Followup-To: comp.unix.bsd
Summary: This time, for sure!
Sender: news@uvm.edu
Organization: University of Vermont, EMBA Computer Facility
Date: Tue, 8 Sep 1992 22:45:01 GMT
Lines: 2039

Here is a new release of my `ie' driver for 386BSD release 0.1.  It
fixes many major bugs in the original version, and is much more
efficient.  If you were using the older version as a porting base for
something else, please throw it out now...  Please read the README
file before doing anything.

-GAWollman

---------------------------->snip snip<----------------------------
#! /bin/sh
# This is a shell archive.  Remove anything before this line, then unpack
# it by saving it into a file and typing "sh file".  To overwrite existing
# files, type "sh file -c".  You can also feed this as standard input via
# unshar, or by typing "sh <file", e.g..  If this archive is complete, you
# will see the following message at the end:
#		"End of shell archive."
# Contents:  README TSORNIN ic if_ie.c if_ieatt.h ic/i82586.h
# Wrapped by wollman@tsornin on Tue Sep  8 18:37:57 1992
PATH=/bin:/usr/bin:/usr/ucb ; export PATH
if test -f 'README' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'README'\"
else
echo shar: Extracting \"'README'\" \(7542 characters\)
sed "s/^X//" >'README' <<'END_OF_FILE'
XREADME
X  Second Release
X    Intel i82586 Ethernet controller driver
X
XCopyright 1992, Garrett A. Wollman
XCopyright 1992, University of Vermont and State Agricultural College.
XSee permission notice at end.
X
X
XINTRODUCTION
X
XThis package consists of a driver for the Intel high-performance
X8-/16-bit LAN controller, the i82586.  The mode in which it currently
Xoperates is known to be correct for a standard DIX version 2.0
XEthernet, but may not be correct for some other network systems, such
Xas StarLAN.  The only network hardware currently supported is the AT&T
XEN100 NAU, operating in Ethernet mode, but the software was designed
Xto allow support for other controllers to be easily integrated;
Xindeed, only three functions need to be written in order for other
Xstandard Ethernet cards based on this controller to work.  (The
XClarkson Packet Drivers should show you what needs to be done.)
X
XThe package as it stands does not support trailers.  I see no
Xparticularly good reason for it to do so, since no modern network
Xhardware emits such ugly packets.  There is rudimentary support for IP
Xmulticast, but could stand to be improved once multicast support is
Xactually added to the 386BSD kernel.  Eventually, I will try to
Xsupport Paul Tsuchiya's PIP in addition to IP, NS, and 802.2.
X
X
XINSTALLATION
X
XTo install this driver, you will first need to add the line
X
X   if_ie.c optional ie device-driver
X
Xto your /sys/i386/conf/files.i386 file.  Once this is done, you should
Xadd a configuration file entry similar to the one included in my
Xconfiguration file, TSORNIN.  Then re-run `config', `make depend', and
X`make'.  With luck, you will have a fully-functioning kernel with a
Xnetwork interface called `ie0'.  (You should be able to configure more
Xthan one, but I've never tried this myself.)
X
XYou can then add a `ifconfig ie0 inet my-address netmask my-netmask \
X broadcast my-broadcast' to your /etc/netstart, and away we go!
X
X
XPERFORMANCE
X
XWell, to be quite honest, performance was not one of my major goals.
XIndeed, I expect transmit to be quite a dog, since I only queue up a
Xsingle transmit command.  However, receive performance should be quite
Ximproved from the previous version (which died on large packets
Xanyway), as the new version takes note of the fact that most packets
Xare relatively small, and so uses a received frame area consisting of
X32 received frame descriptors (so a maximum of 32 frames can be
Xreceived while waiting for interrupt service) and 32 256-byte receive
Xbuffers.  The driver itself also takes pains to free up un-needed
Xreceiver resources as soon as possible, to reduce the number of
Xinterrupts which must be processed.  (The device interrupt routine
Xalso polls the 586 status register to keep immediate turnarounds down
Xto a minimum.)
X
XI tested the TCP performance of my machine, tsornin, against sal, an SGI
X4D/210S (which used to be a 220, 230, and 240).  First, to get a
Xbaseline, I tested the loopback interfaces:
X
XFor tsornin:
X------------------------------------
Xttcp-r: socket
Xttcp-r: accept from 127.0.0.1
Xttcp-r: buflen=8192, nbuf=2048, align=16384/0, port=5001  tcp
Xttcp-r: 16777216 bytes in 127.32 real seconds = 128.69 KB/sec +++
Xttcp-r: 4997 I/O calls, msec/call = 26.09, calls/sec = 39.25
Xttcp-r: 0.1user 38.1sys 2:07real 30% 0i+0d 0maxrss 0+0pf 156+4719csw
X------------------------------------
XFor sal:
X------------------------------------
Xttcp-r: socket
Xttcp-r: accept from 127.0.0.1
Xttcp-r: buflen=8192, nbuf=2048, align=16384/0, port=5001  tcp
Xttcp-r: 16777216 bytes in 14.68 real seconds = 1116.02 KB/sec +++
Xttcp-r: 2049 I/O calls, msec/call = 7.34, calls/sec = 139.57
Xttcp-r: 0.0user 2.3sys 0:14real 15% 220maxrss 0+0pf 14+966csw
X------------------------------------
X
XThe next test measures tsornin's receiver; this includes one cisco
Xrouter hop:
X------------------------------------
Xttcp-r: socket
Xttcp-r: accept from 132.198.3.22
Xttcp-r: buflen=8192, nbuf=2048, align=16384/0, port=5001  tcp
Xttcp-r: 16777216 bytes in 134.31 real seconds = 121.99 KB/sec +++
Xttcp-r: 16777216 bytes in 23.83 CPU seconds = 687.54 KB/cpu sec
Xttcp-r: 4123 I/O calls, msec/call = 33.36, calls/sec = 30.70
Xttcp-r: 0.1user 23.7sys 2:14real 17% 0i+0d 0maxrss 0+0pf 4116+166csw
Xttcp-r: buffer address 0xc000
X------------------------------------
X
XFinally, tsornin's transmitter (and, of course, also sal's receiver),
Xstill one hop:
X------------------------------------
Xttcp-r: socket
Xttcp-r: accept from 132.198.4.5
Xttcp-r: buflen=8192, nbuf=2048, align=16384/0, port=5001  tcp
Xttcp-r: 16777216 bytes in 101.18 real seconds = 161.93 KB/sec +++
Xttcp-r: 16340 I/O calls, msec/call = 6.34, calls/sec = 161.49
Xttcp-r: 0.1user 7.4sys 1:41real 7% 220maxrss 0+0pf 16334+32csw
X------------------------------------
X
X
XACKNOWLEDGEMENTS
X
XThis driver would not have been possible without the help of several
Xindividuals:
X
X- The authors of the Clarkson Packet Drivers
X- Terry from Novell
X- Somebody from Labtam whose name I've forgotten
X- Steve Ackerman for lending me a copy of his i82596 manual
X- Dr. Gary Barbour for not complaining about the amount of time I
X  spent making this work right.
X
XI would appreciate it if any new additions or extensions of this
Xdriver are communicated directly with me, rather than letting a
Xmish-mash of different versions float about.
X
X
XCONTACTING THE AUTHOR
X
XYou can contact me via electronic mail (preferred) as
X<Garrett.Wollman@UVM.EDU>.  You can send paper mail to me at 127 Saint
XPaul Street #218, Burlington, VT 05401.
X
X
XCOPYING
X
XHere are the conditions attached to this software:
X
XCopyright (c) 1992, University of Vermont and State Agricultural College.
XCopyright (c) 1992, Garrett A. Wollman.
X
XPortions:
XCopyright (c) 1990, 1991, William F. Jolitz
XCopyright (c) 1990, The Regents of the University of California
X
XAll rights reserved.
X
XRedistribution and use in source and binary forms, with or without
Xmodification, are permitted provided that the following conditions
Xare met:
X1. Redistributions of source code must retain the above copyright
X   notice, this list of conditions and the following disclaimer.
X2. Redistributions in binary form must reproduce the above copyright
X   notice, this list of conditions and the following disclaimer in the
X   documentation and/or other materials provided with the distribution.
X3. All advertising materials mentioning features or use of this software
X   must display the following acknowledgement:
X	This product includes software developed by the University of
X	Vermont and State Agricultural College and Garrett A. Wollman,
X	by William F. Jolitz, by the University of California,
X	Berkeley, and its contributors.
X4. Neither the names of the Universities nor the names of the authors
X   may be used to endorse or promote products derived from this software
X   without specific prior written permission.
X
XTHIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
XANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
XIMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
XARE DISCLAIMED.  IN NO EVENT SHALL THE UNIVERSITY OR AUTHORS BE LIABLE
XFOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
XDAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
XOR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
XHOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
XLIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
XOUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
XSUCH DAMAGE.
X
END_OF_FILE
if test 7542 -ne `wc -c <'README'`; then
    echo shar: \"'README'\" unpacked with wrong size!
fi
# end of 'README'
fi
if test -f 'TSORNIN' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'TSORNIN'\"
else
echo shar: Extracting \"'TSORNIN'\" \(1429 characters\)
sed "s/^X//" >'TSORNIN' <<'END_OF_FILE'
X#
X# TSORNIN - my machine
X#
Xmachine		"i386"
Xcpu		"i386"
Xident		TSORNIN
Xtimezone	5 dst
Xmaxusers	12
Xoptions		INET,MFS,NFS,DDB
Xoptions		"COMPAT_43"
Xoptions		"TCP_COMPAT_42"
X
Xconfig		"386bsd"	root on wd0 swap on wd0
X
Xcontroller	isa0
Xcontroller	wdc0	at isa? port "IO_WD1" bio irq 14 vector wdintr
Xdisk		wd0	at wdc0 drive 0
Xdisk		wd1	at wdc0 drive 1
X
Xcontroller	fdc0	at isa? port "IO_FD1" bio irq 6 drq 2 vector fdintr
Xdisk		fd0	at fdc0 drive 0
X# disk		fd1	at fd0 drive 1
X
X#controller	as0	at isa? port 0x330 bio irq 11 drq 5 vector asintr
X#disk		as0	at as0 drive 0
X#disk		as1	at as0 drive 1
X
Xdevice		pc0	at isa? port "IO_KBD" tty irq 1 vector pcrint
Xdevice		npx0	at isa? port "IO_NPX" irq 13 vector npxintr
Xdevice		com1	at isa? port "IO_COM1" tty irq 4 vector comintr
X#device		com2	at isa? port "IO_COM2" tty irq 3 vector comintr
X
X#device we0 at isa? port 0x280 net irq 2 iomem 0xd0000 iosiz 8192 vector weintr
X#device ne0 at isa? port 0x300 net irq 2 vector neintr
X#device ec0 at isa? port 0x250 net irq 2 iomem 0xd8000 iosiz 8192 vector ecintr
X#device is0 at isa? port 0x280 net irq 10 drq 7 vector isintr
Xdevice ie0 at isa? port 0x360 net irq 3 iomem 0xd0000 iosiz ? vector ieintr
X
X#device		wt0	at isa? port 0x300 bio irq 5 drq 1 vector wtintr
X
Xpseudo-device	loop
Xpseudo-device	ether
X#pseudo-device	sl	1
Xpseudo-device	log
Xpseudo-device	ddb
Xpseudo-device	pty	4
X
Xpseudo-device	swappager
Xpseudo-device	vnodepager
Xpseudo-device	devpager
END_OF_FILE
if test 1429 -ne `wc -c <'TSORNIN'`; then
    echo shar: \"'TSORNIN'\" unpacked with wrong size!
fi
# end of 'TSORNIN'
fi
if test ! -d 'ic' ; then
    echo shar: Creating directory \"'ic'\"
    mkdir 'ic'
fi
if test -f 'if_ie.c' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'if_ie.c'\"
else
echo shar: Extracting \"'if_ie.c'\" \(35027 characters\)
sed "s/^X//" >'if_ie.c' <<'END_OF_FILE'
X/*-
X * Copyright (c) 1992, University of Vermont and State Agricultural College.
X * Copyright (c) 1992, Garrett A. Wollman.
X *
X * Portions:
X * Copyright (c) 1990, 1991, William F. Jolitz
X * Copyright (c) 1990, The Regents of the University of California
X *
X * All rights reserved.
X *
X * Redistribution and use in source and binary forms, with or without
X * modification, are permitted provided that the following conditions
X * are met:
X * 1. Redistributions of source code must retain the above copyright
X *    notice, this list of conditions and the following disclaimer.
X * 2. Redistributions in binary form must reproduce the above copyright
X *    notice, this list of conditions and the following disclaimer in the
X *    documentation and/or other materials provided with the distribution.
X * 3. All advertising materials mentioning features or use of this software
X *    must display the following acknowledgement:
X *	This product includes software developed by the University of
X *	Vermont and State Agricultural College and Garrett A. Wollman,
X *	by William F. Jolitz, by the University of California,
X *	Berkeley, and its contributors.
X * 4. Neither the names of the Universities nor the names of the authors
X *    may be used to endorse or promote products derived from this software
X *    without specific prior written permission.
X *
X * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
X * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
X * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
X * ARE DISCLAIMED.  IN NO EVENT SHALL THE UNIVERSITY OR AUTHORS BE LIABLE
X * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
X * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
X * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
X * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
X * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
X * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
X * SUCH DAMAGE.
X *
X */
X
X/*
X * Intel 82586 Ethernet chip
X * Register, bit, and structure definitions.
X *
X * Written by GAW with reference to the Clarkson Packet Driver code for this
X * chip written by Russ Nelson and others.
X */
X
X/*
X * The i82586 is a very versatile chip, found in many implementations.
X * Programming this chip is mostly the same, but certain details differ
X * from card to card.  This driver is written so that different cards 
X * can be automatically detected at run-time.  Currently, only the
X * AT&T EN100/StarLAN 10 series are supported.
X */
X
X/*
XMode of operation:
X
XWe run the 82586 in a standard Ethernet mode.  We keep NFRAMES received
Xframe descriptors around for the receiver to use, and NBUFFS associated
Xreceive buffer descriptors, both in a circular list.  Whenever a frame is
Xreceived, we rotate both lists as necessary.  (The 586 treats both lists
Xas a simple queue.)  We also keep a transmit command around so that packets
Xcan be sent off quickly.
X
XWe configure the adapter in AL-LOC = 1 mode, which means that the
XEthernet/802.3 MAC header is placed at the beginning of the receive buffer
Xrather than being split off into various fields in the RFD.  This also
Xmeans that we must include this header in the transmit buffer as well.
X
XBy convention, all transmit commands, and only transmit commands, shall
Xhave the I (IE_CMD_INTR) bit set in the command.  This way, when an
Xinterrupt arrives at ieintr(), it is immediately possible to tell
Xwhat precisely caused it.  ANY OTHER command-sending routines should
Xrun at splimp(), and should post an acknowledgement to every interrupt
Xthey generate.
X
XThe 82586 has a 24-bit address space internally, and the adaptor's
Xmemory is located at the top of this region.  However, the value we are
Xgiven in configuration is normally the *bottom* of the adaptor RAM.  So,
Xwe must go through a few gyrations to come up with a kernel virtual address
Xwhich represents the actual beginning of the 586 address space.  First,
Xwe autosize the RAM by running through several possible sizes and trying
Xto initialize the adapter under the assumption that the selected size
Xis correct.  Then, knowing the correct RAM size, we set up our pointers
Xin ie_softc[unit].  `iomem' represents the computed base of the 586
Xaddress space.  `iomembot' represents the actual configured base
Xof adapter RAM.  Finally, `iosize' represents the calculated size
Xof 586 RAM.  Then, when laying out commands, we use the interval
X[iomembot, iomembot + iosize); to make 24-pointers, we subtract
Xiomem, and to make 16-pointers, we subtract iomem and and with 0xffff.
X
X*/
X
X#include "ie.h"
X#if NIE > 0
X
X#include "param.h"
X#include "systm.h"
X#include "mbuf.h"
X#include "buf.h"
X#include "protosw.h"
X#include "socket.h"
X#include "ioctl.h"
X#include "errno.h"
X#include "syslog.h"
X
X#include "net/if.h"
X#include "net/netisr.h"
X#include "net/route.h"
X
X#ifdef INET
X#include "netinet/in.h"
X#include "netinet/in_systm.h"
X#include "netinet/in_var.h"
X#include "netinet/ip.h"
X#include "netinet/if_ether.h"
X#endif
X
X#ifdef NS
X#include "netns/ns.h"
X#include "netns/ns_if.h"
X#endif
X
X#include "i386/isa/isa_device.h"
X#include "i386/isa/ic/i82586.h"
X#include "i386/isa/if_ieatt.h"
X#include "i386/isa/icu.h"
X
X#include "vm/vm.h"
X
X#ifdef DEBUG
X#define IED_RINT 1
X#define IED_TINT 2
X#define IED_RNR 4
X#define IED_CNA 8
X#define IED_READFRAME 16
Xint ie_debug = 0;
X#endif
X
X#ifndef ETHERMINLEN
X#define ETHERMINLEN 60
X#endif
X
X#define IE_BUF_LEN 1532		/* length of some buffer? */
X
X
X/* Forward declaration */
Xstruct ie_softc;
X
Xint ieprobe(struct isa_device *dvp);
Xint ieattach(struct isa_device *dvp);
Xint ieinit(int unit);
Xint ieioctl(struct ifnet *ifp, int command, void *data);
Xint iestart(struct ifnet *ifp);
Xstatic void sl_reset_586(int unit);
Xstatic void sl_chan_attn(int unit);
Xint iereset(int unit, int dummy);
Xstatic void ie_readframe(int unit, struct ie_softc *ie, int bufno);
Xstatic void sl_read_ether(int unit, unsigned char addr[6]);
Xstatic void find_ie_mem_size(int unit);
Xstatic int command_and_wait(int unit, int command, void volatile *pcmd, int);
Xstatic int ierint(int unit, struct ie_softc *ie);
Xstatic int ietint(int unit, struct ie_softc *ie);
Xstatic int iernr(int unit, struct ie_softc *ie);
Xstatic void start_receiver(int unit);
Xint ieget(int, struct ie_softc *, struct mbuf **,
X		   struct ether_header *);
Xstatic caddr_t setup_rfa(caddr_t ptr, struct ie_softc *ie);
X
X#ifdef DEBUG
Xvoid print_rbd(volatile struct ie_recv_buf_desc *rbd);
X
Xint in_ierint = 0;
Xint in_ietint = 0;
X#endif
X
X/*
X * This tells the autoconf code how to set us up.
X */
Xstruct isa_driver iedriver = {
X  ieprobe, ieattach, "ie",
X};
X
Xenum ie_hardware {
X  IE_STARLAN10,
X  IE_EN100,
X  IE_UNKNOWN
X};
X
Xconst char *ie_hardware_names[] = {
X  "StarLAN 10",
X  "EN100",
X  "Unknown"
X};
X
X#define NFRAMES 16		/* number of frames to allow for receive */
X#define NBUFFS 32		/* number of buffers to allocate */
X#define IE_RBUF_SIZE 256	/* size of each buffer, MUST BE POWER OF TWO */
X
X/*
X * Ethernet status, per interface.
X */
Xstruct ie_softc {
X  struct arpcom ns_ac;
X#define ns_if ns_ac.ac_if
X#define ns_addr ns_ac.ac_enaddr
X  void (*ie_reset_586)(int);
X  void (*ie_chan_attn)(int);
X  enum ie_hardware hard_type;
X  int hard_vers;
X
X  u_short port;
X  caddr_t iomem;
X  caddr_t iomembot;
X  unsigned iosize;
X  
X  int promisc;
X  volatile struct ie_int_sys_conf_ptr *iscp;
X  volatile struct ie_sys_ctl_block *scb;
X  volatile struct ie_recv_frame_desc *rframes[NFRAMES];
X  volatile struct ie_recv_buf_desc *rbuffs[NBUFFS];
X  volatile char *cbuffs[NBUFFS];
X  int rfhead, rftail, rbhead, rbtail;
X
X  volatile struct ie_xmit_cmd *xmit_cmd;
X  volatile struct ie_xmit_buf *xmit_buf;
X  u_char *xmit_cbuf;
X
X  /*
X   * The broadcast address is always put here in addition to the
X   * multicast addresses.
X   */
X  struct ie_en_addr mcast_addrs[MAXMCAST + 1];
X  int mcast_count;
X} ie_softc[NIE];
X
X#define MK_24(base, ptr) ((caddr_t)((caddr_t)ptr - base))
X#define MK_16(base, ptr) ((u_short)MK_24(base, ptr))
X
X#define PORT ie_softc[unit].port
X#define MEM ie_softc[unit].iomem
X
X
Xint ieprobe(dvp)
X     struct isa_device *dvp;
X{
X  int unit = dvp->id_unit;
X  u_char c, d;
X
X  ie_softc[unit].port = dvp->id_iobase;
X  ie_softc[unit].iomembot = dvp->id_maddr;
X  ie_softc[unit].iomem = 0;
X
X  c = inb(PORT + IEATT_REVISION);
X  switch(SL_BOARD(c)) {
X  case SL10_BOARD:
X    ie_softc[unit].hard_type = IE_STARLAN10;
X    ie_softc[unit].ie_reset_586 = sl_reset_586;
X    ie_softc[unit].ie_chan_attn = sl_chan_attn;
X    break;
X  case EN100_BOARD:
X    ie_softc[unit].hard_type = IE_EN100;
X    ie_softc[unit].ie_reset_586 = sl_reset_586;
X    ie_softc[unit].ie_chan_attn = sl_chan_attn;
X    break;
X
X    /*
X     * Anything else is not recognized or cannot be used.
X     */
X  default:
X    return 0;
X  }
X
X  ie_softc[unit].hard_vers = SL_REV(c);
X
X  /*
X   * Divine memory size on-board the card.  Ususally 16k.
X   */
X  find_ie_mem_size(unit);
X
X  if(!ie_softc[unit].iosize) {
X    return 0;
X  }
X
X  dvp->id_msize = ie_softc[unit].iosize;
X
X  switch(ie_softc[unit].hard_type) {
X  case IE_EN100:
X  case IE_STARLAN10:
X    sl_read_ether(unit, ie_softc[unit].ns_addr);
X    break;
X  /* more cases here... */
X  }
X
X  return 1;
X}
X
X/*
X * Taken almost exactly from Bill's if_is.c.
X */
Xint ieattach(dvp)
X     struct isa_device *dvp;
X{
X  int unit = dvp->id_unit;
X  struct ie_softc *ie = &ie_softc[unit];
X  struct ifnet *ifp = &ie->ns_if;
X
X  ifp->if_unit = unit;
X  ifp->if_name = iedriver.name;
X  ifp->if_mtu = ETHERMTU;
X  printf("<%s R%d> ethernet address %s", 
X	 ie_hardware_names[ie_softc[unit].hard_type],
X	 ie_softc[unit].hard_vers + 1,
X	 ether_sprintf(ie->ns_addr));
X
X  ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_NOTRAILERS;
X#ifdef IFF_MULTICAST
X  ifp->if_flags  |= IFF_MULTICAST;
X#endif
X
X  ifp->if_init = ieinit;
X  ifp->if_output = ether_output;
X  ifp->if_start = iestart;
X  ifp->if_ioctl = ieioctl;
X  ifp->if_reset = iereset;
X  ifp->if_watchdog = iereset; /* Yes, X3J11 members, this is indeed illegal. */
X  if_attach(ifp);
X}
X
X/*
X * What to do upon receipt of an interrupt.
X */
Xint ieintr(unit)
X     int unit;
X{
X  register struct ie_softc *ie = &ie_softc[unit];
X  register u_short status;
X
X  status = ie->scb->ie_status;
X
Xloop:
X  if(status & IE_ST_RECV) {
X#ifdef DEBUG
X    in_ierint++;
X    if(ie_debug & IED_RINT)
X      printf("ie%d: rint\n", unit);
X#endif
X    ierint(unit, ie);
X#ifdef DEBUG
X    in_ierint--;
X#endif
X  }
X
X  if(status & IE_ST_DONE) {
X#ifdef DEBUG
X    in_ietint++;
X    if(ie_debug & IED_TINT)
X      printf("ie%d: tint\n", unit);
X#endif
X    ietint(unit, ie);
X#ifdef DEBUG
X    in_ietint--;
X#endif
X  }
X
X  if(status & IE_ST_RNR) {
X#ifdef DEBUG
X    if(ie_debug & IED_RNR)
X      printf("ie%d: rnr\n", unit);
X#endif
X    iernr(unit, ie);
X  }
X
X#ifdef DEBUG
X  if((status & IE_ST_ALLDONE)
X     && (ie_debug & IED_CNA))
X    printf("ie%d: cna\n", unit);
X#endif
X
X  /* Don't ack interrupts which we didn't receive */
X  ie_ack(ie->scb, IE_ST_WHENCE & status, unit, ie->ie_chan_attn);
X
X  if((status = ie->scb->ie_status) & IE_ST_WHENCE)
X    goto loop;
X
X  return unit;
X}
X
X/*
X * Process a received-frame interrupt.
X */
Xstatic int ierint(unit, ie)
X     int unit;
X     struct ie_softc *ie;
X{
X  int i, status;
X  static int timesthru = 1024;
X
X  i = ie->rfhead;
X  while(1) {
X    status = ie->rframes[i]->ie_fd_status;
X
X    if((status & IE_FD_COMPLETE) && (status & IE_FD_OK)) {
X      ie->ns_if.if_ipackets++;
X      if(!--timesthru) {
X	ie->ns_if.if_ierrors += ie->scb->ie_err_crc + ie->scb->ie_err_align +
X	  ie->scb->ie_err_resource + ie->scb->ie_err_overrun;
X	ie->scb->ie_err_crc = 0;
X	ie->scb->ie_err_align = 0;
X	ie->scb->ie_err_resource = 0;
X	ie->scb->ie_err_overrun = 0;
X	timesthru = 1024;
X      }
X      ie_readframe(unit, ie, i);
X    } else {
X      break;
X    }
X    i = (i + 1) % NFRAMES;
X  }
X  return 0;
X}
X
X/*
X * Process a command-complete interrupt.  These are only generated by
X * the transmission of frames.  This routine is deceptively simple, since
X * most of the real work is done by iestart().
X */
Xstatic int ietint(unit, ie)
X     int unit;
X     struct ie_softc *ie;
X{
X  int status = ie->xmit_cmd->ie_xmit_status;
X
X  ie->ns_if.if_timer = 0;
X  ie->ns_if.if_flags &= ~IFF_OACTIVE;
X
X  if(status & IE_XS_LATECOLL) {
X    printf("ie%d: late collision\n", unit);
X    ie->ns_if.if_collisions++;
X    ie->ns_if.if_oerrors++;
X  } else if(status & IE_XS_NOCARRIER) {
X    printf("ie%d: no carrier\n", unit);
X    ie->ns_if.if_oerrors++;
X  } else if(status & IE_XS_LOSTCTS) {
X    printf("ie%d: lost CTS\n", unit);
X    ie->ns_if.if_oerrors++;
X  } else if(status & IE_XS_UNDERRUN) {
X    printf("ie%d: DMA underrun\n", unit);
X    ie->ns_if.if_oerrors++;
X  } else if(status & IE_XS_EXCMAX) {
X    printf("ie%d: too many collisions\n", unit);
X    ie->ns_if.if_collisions += 16;
X    ie->ns_if.if_oerrors++;
X  } else {
X    ie->ns_if.if_opackets++;
X    ie->ns_if.if_collisions += status & IE_XS_MAXCOLL;
X  }
X
X  /* Wish I knew why this seems to be necessary... */
X  ie->xmit_cmd->ie_xmit_status |= IE_STAT_COMPL;
X
X  iestart(&ie->ns_if);
X}
X
X/*
X * Process a receiver-not-ready interrupt.  I believe that we get these
X * when there aren't enough buffers to go around.  For now (FIXME), we
X * just restart the receiver, and hope everything's ok.
X */
Xstatic int iernr(unit, ie)
X     int unit;
X     struct ie_softc *ie;
X{
X  command_and_wait(unit, IE_RU_DISABLE, 0, 0); /* just in case */
X  setup_rfa((caddr_t)ie->rframes[0], ie);
X
X  ie_softc[unit].scb->ie_recv_list = MK_16(MEM, ie_softc[unit].rframes[0]);
X  command_and_wait(unit, IE_RU_ENABLE, 0, 0);
X
X  ie_ack(ie->scb, IE_ST_WHENCE, unit, ie->ie_chan_attn);
X
X  ie->ns_if.if_ierrors++;
X  return 0;
X}
X
X/*
X * Read frame NUM from unit UNIT (pre-cached as IE).
X *
X * This routine reads the RFD at NUM, and copies in the buffers from
X * the list of RBD, then rotates the RBD and RFD lists so that the receiver
X * doesn't start complaining.  Trailers are DROPPED---there's no point
X * in wasting time on confusing code to deal with them.  Hopefully,
X * this machine will never ARP for trailers anyway.
X */
Xstatic void ie_readframe(unit, ie, num)
X     int unit;
X     struct ie_softc *ie;
X     int num;			/* frame number to read */
X{
X  struct ie_recv_frame_desc rfd = *(ie->rframes[num]);
X  struct mbuf *m = 0;
X  struct ether_header eh;
X
X  /* Immediately advance the RFD list, since we we have copied ours now. */
X  ie->rframes[num]->ie_fd_status = 0;
X  ie->rframes[num]->ie_fd_last |= IE_FD_LAST;
X  ie->rframes[ie->rftail]->ie_fd_last &= ~IE_FD_LAST;
X  ie->rftail = (ie->rftail + 1) % NFRAMES;
X  ie->rfhead = (ie->rfhead + 1) % NFRAMES;
X
X  if(rfd.ie_fd_status & IE_FD_OK) {
X    if(ieget(unit, ie, &m, &eh))
X      return;
X  }
X
X  eh.ether_type = ntohs(eh.ether_type);
X
X#ifdef DEBUG
X  if(ie_debug & IED_READFRAME) {
X    printf("ie%d: frame from ether %s type %x\n", unit,
X	   ether_sprintf(eh.ether_shost), (unsigned)eh.ether_type);
X  }
X  if(eh.ether_type > ETHERTYPE_TRAIL
X     && eh.ether_type < (ETHERTYPE_TRAIL + ETHERTYPE_NTRAILER))
X    printf("received trailer!\n");
X#endif
X
X  /*
X   * Finally pass this packet up to higher layers.
X   */
X  if(m)
X    ether_input(&ie->ns_if, &eh, m);
X}  
X
X/*
X * Read data off the interface, and turn it into an mbuf chain.
X */
Xint ieget(unit, ie, mp, ehp)
X     int unit;
X     struct ie_softc *ie;
X     struct mbuf **mp;
X     struct ether_header *ehp;
X{
X  struct mbuf *m, *top, **mymp;
X  int i, j;
X  int offset;
X  int thislen, totlen = 0, len;
X  int ohead;
X
X  MGETHDR(*mp, M_DONTWAIT, MT_DATA);
X  if(!*mp) {
X    /* XXX - We need to deal with this situation gracefully by
X       dropping the packet -- but *without* a buffer leak in the RFA. */
X    panic("out of mbufs in ieget()");
X  }
X
X  m = *mp;
X  m->m_pkthdr.rcvif = (struct ifnet *)ie;
X  m->m_len = MHLEN;
X
X  top = 0;
X  mymp = &top;
X  
X  i = ohead = ie->rbhead;
X
X  do {
X    /*
X     * This means we are somehow out of sync.  So, we reset the
X     * adapter.
X     */
X    if(!(ie->rbuffs[i]->ie_rbd_actual & IE_RBD_USED)) {
X#ifdef DEBUG
X      print_rbd(ie->rbuffs[i]);
X#endif
X      log(LOG_ERR, "ie%d: receive descriptors out of sync at %d\n",
X	  unit, i);
X      m_freem(*mp);
X      iereset(unit, 0);
X      return -1;
X    }
X
X    offset = 0;
X    /*
X     * We want to isolate the bits that have meaning...  This assumes that
X     * IE_RBUF_SIZE is an even power of two.  If somehow the act_len exceeds
X     * the size of the buffer, then we are screwed anyway.
X     */
X    thislen = ie->rbuffs[i]->ie_rbd_actual
X      & (IE_RBUF_SIZE | (IE_RBUF_SIZE - 1));
X
X    /*
X     * If this is the first receive buffer, immediately copy
X     * the Ethernet header into ehp.
X     */
X    if(i == ohead) {
X      bcopy((caddr_t)ie->cbuffs[i], (caddr_t)ehp, sizeof *ehp);
X      thislen -= sizeof *ehp;
X      offset = sizeof *ehp;
X    }
X
X    len = thislen;
X
X    do {
X      if(top) {
X	MGET(m, M_DONTWAIT, MT_DATA);
X	if(!m) {
X	  m_freem(top);
X	  panic("out of mbuf in ieget()"); /* XXX FIXME PLEASE */
X	}
X	m->m_len = MLEN;
X      }
X
X      /*
X       * If this is big enough to merit an mbuf cluster, allocate one.
X       * Else, just use a regular mbuf.
X       */
X      if(len >= MINCLSIZE) {
X	MCLGET(m, M_DONTWAIT);
X	if(m->m_flags & M_EXT)
X	  m->m_len = len = min(len, MCLBYTES);
X	else
X	  len = m->m_len;
X      } else {
X	if(len < m->m_len) {
X	  if(!top && len + max_linkhdr <= m->m_len)
X	    m->m_data += max_linkhdr;
X	  m->m_len = len;
X	} else {
X	  len = m->m_len;
X	}
X      }
X      bcopy((caddr_t)(ie->cbuffs[i] + offset),
X	    mtod(m, caddr_t), (unsigned)len);
X      offset += len;
X      *mymp = m;		/* first time through, this sets top */
X      mymp = &m->m_next;
X      thislen -= len;
X      totlen += len;
X    } while(thislen > 0);
X
X    j = ie->rbuffs[i]->ie_rbd_actual;
X
X    ie->rbuffs[i]->ie_rbd_actual = 0;
X
X    ie->rbuffs[ie->rbhead]->ie_rbd_length |= IE_RBD_LAST;
X    ie->rbhead = (ie->rbhead + 1) % NBUFFS;
X    ie->rbuffs[ie->rbtail]->ie_rbd_length &= ~IE_RBD_LAST;
X    ie->rbtail = (ie->rbtail + 1) % NBUFFS;
X
X    i = (i + 1) % NBUFFS;
X  } while(!(j & IE_RBD_LAST));
X
X  (*mp)->m_pkthdr.len = totlen;
X
X  return 0;
X
X#if 0
X  struct mbuf *top, **mp, *m, *p;
X  int off = offset;
X  int len;
X  caddr_t cp = (caddr_t)buf;
X  char *epkt;
X
X  buf += sizeof(struct ether_header);
X  cp = (caddr_t)buf;
X  epkt = cp + length;
X
X  if(off) {
X    cp += off + 2 * sizeof(u_short);
X    length -= 2 * sizeof(u_short);
X  }
X
X  MGETHDR(m, M_DONTWAIT, MT_DATA);
X  if(!m)
X    return 0;
X
X  m->m_pkthdr.rcvif = ifp;
X  m->m_pkthdr.len = length;
X  m->m_len = MHLEN;
X
X  top = 0;
X  mp = &top;
X  while(length > 0) {
X    if(top) {
X      MGET(m, M_DONTWAIT, MT_DATA);
X      if(!m) {
X	m_freem(top);
X	return 0;
X      }
X      m->m_len = MLEN;
X    }
X
X    len = min(length, epkt - cp);
X
X    if(len >= MINCLSIZE) {
X      MCLGET(m, M_DONTWAIT);
X      if(m->m_flags & M_EXT)
X	m->m_len = len = min(len, MCLBYTES);
X      else
X	len = m->m_len;
X    } else {
X      if(len < m->m_len) {
X	if(!top && len + max_linkhdr <= m->m_len)
X	  m->m_data += max_linkhdr;
X	m->m_len = len;
X      } else {
X	len = m->m_len;
X      }
X    }
X
X    bcopy(cp, mtod(m, caddr_t), (unsigned)len);
X    cp += len;
X    *mp = m;
X    mp = &m->m_next;
X    length -= len;
X    if(cp == epkt)
X      cp = buf;
X  }
X  return top;
X#endif
X}
X
X/*
X * Start transmission on an interface.
X */
Xint iestart(ifp)
X     struct ifnet *ifp;
X{
X  struct ie_softc *ie = &ie_softc[ifp->if_unit];
X  struct mbuf *m0, *m;
X  unsigned char *buffer;
X  u_short len;
X  int i;
X
X  if(!(ifp->if_flags & IFF_RUNNING))
X    return 0;
X  if(ifp->if_flags & IFF_OACTIVE)
X    return 0;
X
X  do {
X    /*
X     * If last transmission didn't finish, forget it.
X     */
X    if(!(ie->xmit_cmd->ie_xmit_status & IE_STAT_COMPL)) {
X      printf("ie%d: output not active but complete not set\n", ifp->if_unit);
X      iereset(ifp->if_unit, 0);
X      return 0;
X    }
X
X    IF_DEQUEUE(&ie->ns_if.if_snd, m);
X    if(!m)
X      return;
X
X    buffer = ie->xmit_cbuf;
X    len = 0;
X
X    for(m0 = m; m && len < IE_BUF_LEN; m = m->m_next) {
X      bcopy(mtod(m, caddr_t), buffer, m->m_len);
X      buffer += m->m_len;
X      len += m->m_len;
X    }
X
X    m_freem(m0);
X    len = MAX(len, ETHERMINLEN);
X
X    ie->xmit_buf->ie_xmit_flags = IE_XMIT_LAST | len;
X    ie->xmit_buf->ie_xmit_next = 0xffff;
X    ie->xmit_buf->ie_xmit_buf = MK_24(ie->iomem, ie->xmit_cbuf);
X
X    ie->xmit_cmd->com.ie_cmd_cmd = IE_CMD_LAST | IE_CMD_XMIT | IE_CMD_INTR;
X    ie->xmit_cmd->ie_xmit_status = 0;
X    ie->xmit_cmd->ie_xmit_desc = MK_16(ie->iomem, ie->xmit_buf);
X
X    ie->scb->ie_command_list = MK_16(ie->iomem, ie->xmit_cmd);
X
X    /*
X     * By passing the command pointer as a null, we tell
X     * command_and_wait() to pretend that this isn't an action
X     * command.  I wish I understood what was happening here.
X     */
X    command_and_wait(ifp->if_unit, IE_CU_START, 0, 0);
X
X    ifp->if_flags |= IFF_OACTIVE;
X    ifp->if_timer = 10;		/* set watchdog to expire in ten seconds */
X  } while(0);			/* someday, we may have more than one... */
X
X  return 0;
X}
X
X/*
X * Check to see if there's an 82586 out there.
X */
Xint check_ie_present(unit, where, size)
X     int unit;
X     caddr_t where;
X     unsigned size;
X{
X  volatile struct ie_sys_conf_ptr *scp;
X  volatile struct ie_int_sys_conf_ptr *iscp;
X  volatile struct ie_sys_ctl_block *scb;
X  u_long realbase;
X  int s;
X
X  s = splimp();
X
X  realbase = (u_long)where + size - (1 << 24);
X
X  scp = (void *)(realbase + IE_SCP_ADDR);
X  bzero((char *)scp, sizeof *scp);
X  
X  /*
X   * First we put the ISCP at the bottom of memory; this tests to make
X   * sure that our idea of the size of memory is the same as the controller's.
X   * This is NOT where the ISCP will be in normal operation.
X   */
X  iscp = (void *)where;
X  bzero((char *)iscp, sizeof *iscp);
X
X  scb = (void *)where;
X  bzero((char *)scb, sizeof *scb);
X
X  scp->ie_bus_use = 0;		/* 16-bit */
X  scp->ie_iscp_ptr = (caddr_t)((caddr_t)iscp - (caddr_t)realbase);
X
X  iscp->ie_busy = 1;
X  iscp->ie_scb_offset = MK_16(realbase, scb) + 256;
X
X  (*ie_softc[unit].ie_reset_586)(unit);
X  (*ie_softc[unit].ie_chan_attn)(unit);
X
X  DELAY(100);			/* wait a while... */
X
X  if(iscp->ie_busy) {
X    splx(s);
X    return 0;
X  }
X
X  /*
X   * Now relocate the ISCP to its real home, and reset the controller
X   * again.
X   */
X  iscp = (void *)Align((caddr_t)(realbase + IE_SCP_ADDR - 
X				 sizeof(struct ie_int_sys_conf_ptr)));
X  bzero((char *)iscp, sizeof *iscp);
X
X  scp->ie_iscp_ptr = (caddr_t)((caddr_t)iscp - (caddr_t)realbase);
X
X  iscp->ie_busy = 1;
X  iscp->ie_scb_offset = MK_16(realbase, scb);
X
X  (*ie_softc[unit].ie_reset_586)(unit);
X  (*ie_softc[unit].ie_chan_attn)(unit);
X
X  DELAY(100);
X
X  if(iscp->ie_busy) {
X    splx(s);
X    return 0;
X  }
X
X  ie_softc[unit].iosize = size;
X  ie_softc[unit].iomem = (caddr_t)realbase;
X
X  ie_softc[unit].iscp = iscp;
X  ie_softc[unit].scb = scb;
X
X  /*
X   * Acknowledge any interrupts we may have caused...
X   */
X  ie_ack(scb, IE_ST_WHENCE, unit, ie_softc[unit].ie_chan_attn);
X  splx(s);
X
X  return 1;
X}
X
X/*
X * Divine the memory size of ie board UNIT.
X * Better hope there's nothing important hiding just below the ie card...
X */
Xstatic void find_ie_mem_size(unit)
X     int unit;
X{
X  unsigned size;
X
X  ie_softc[unit].iosize = 0;
X
X  for(size = 65536; size >= 16384; size -= 16384) {
X    if(check_ie_present(unit, ie_softc[unit].iomembot, size)) {
X      return;
X    }
X  }
X
X  return;
X}
X
Xvoid sl_reset_586(unit)
X     int unit;
X{
X  outb(PORT + IEATT_RESET, 0);
X}
X
Xvoid sl_chan_attn(unit)
X     int unit;
X{
X  outb(PORT + IEATT_ATTN, 0);
X}
X
Xvoid sl_read_ether(unit, addr)
X     int unit;
X     unsigned char addr[6];
X{
X  int i;
X
X  for(i = 0; i < 6; i++)
X    addr[i] = inb(PORT + i);
X}
X
X
Xint iereset(unit, dummy)
X     int unit, dummy;
X{
X  int s = splimp();
X
X  if(unit >= NIE) {
X    splx(s);
X    return -1;
X  }
X
X  printf("ie%d: reset\n", unit);
X
X  /*
X   * Stop i82586 dead in its tracks.
X   */
X  if(command_and_wait(unit, IE_RU_ABORT | IE_CU_ABORT, 0, 0))
X    printf("ie%d: abort commands timed out\n", unit);
X
X  if(command_and_wait(unit, IE_RU_DISABLE | IE_CU_STOP, 0, 0))
X    printf("ie%d: disable commands timed out\n", unit);
X
X  if(!check_ie_present(unit, ie_softc[unit].iomembot, ie_softc[unit].iosize))
X    panic("ie disappeared!\n");
X
X  ieinit(unit);
X  splx(s);
X  return 0;
X}
X
X/*
X * This is called if we time out.
X */
Xstatic int chan_attn_timeout(rock)
X     caddr_t rock;
X{
X  *(int *)rock = 1;
X}
X
X/*
X * Send a command to the controller and wait for it to either
X * complete or be accepted, depending on the command.  If the
X * command pointer is null, then pretend that the command is
X * not an action command.  If the command pointer is not null,
X * and the command is an action command, wait for
X * ((volatile struct ie_cmd_common *)pcmd)->ie_cmd_status & MASK
X * to become true.
X */
Xstatic int command_and_wait(unit, cmd, pcmd, mask)
X     int unit;
X     int cmd;
X     volatile void *pcmd;
X     int mask;
X{
X  volatile struct ie_cmd_common *cc = pcmd;
X  volatile int timedout = 0;
X  extern int hz;
X
X  ie_softc[unit].scb->ie_command = (u_short)cmd;
X  
X  if(IE_ACTION_COMMAND(cmd) && pcmd) {
X    (*ie_softc[unit].ie_chan_attn)(unit);
X
X    /*
X     * According to the packet driver, the minimum timeout should be
X     * .369 seconds, which we round up to .37.
X     */
X    timeout(chan_attn_timeout, (caddr_t)&timedout, 37 * hz / 100);
X
X    /*
X     * Now spin-lock waiting for status.  This is not a very nice
X     * thing to do, but I haven't figured out how, or indeed if, we
X     * can put the process waiting for action to sleep.  (We may
X     * be getting called through some other timeout running in the
X     * kernel.)
X     */
X    while(1) {
X      if((cc->ie_cmd_status & mask) || timedout)
X	break;
X    }
X
X    untimeout(chan_attn_timeout, (caddr_t)&timedout);
X
X    return timedout;
X  } else {
X    
X    /*
X     * Otherwise, just wait for the command to be accepted.
X     */
X    (*ie_softc[unit].ie_chan_attn)(unit);
X
X    while(ie_softc[unit].scb->ie_command)
X      ;				/* spin lock */
X
X    return 0;
X  }
X}
X
X/*
X * Run the time-domain reflectometer...
X */
Xstatic void run_tdr(unit, cmd)
X     int unit;
X     struct ie_tdr_cmd *cmd;
X{
X  int result;
X
X  cmd->com.ie_cmd_status = 0;
X  cmd->com.ie_cmd_cmd = IE_CMD_TDR | IE_CMD_LAST;
X  cmd->com.ie_cmd_link = 0xffff;
X  cmd->ie_tdr_time = 0;
X
X  ie_softc[unit].scb->ie_command_list = MK_16(MEM, cmd);
X  cmd->ie_tdr_time = 0;
X
X  if(command_and_wait(unit, IE_CU_START, cmd, IE_STAT_COMPL))
X    result = 0x2000;
X  else
X    result = cmd->ie_tdr_time;
X
X  ie_ack(ie_softc[unit].scb, IE_ST_WHENCE, unit, 
X	 ie_softc[unit].ie_chan_attn);
X
X  if(result & IE_TDR_SUCCESS)
X    return;
X
X  if(result & IE_TDR_XCVR) {
X    printf("ie%d: transceiver problem\n", unit);
X  } else if(result & IE_TDR_OPEN) {
X    printf("ie%d: TDR detected an open %d clocks away\n", unit, 
X	   result & IE_TDR_TIME);
X  } else if(result & IE_TDR_SHORT) {
X    printf("ie%d: TDR detected a short %d clocks away\n", unit,
X	   result & IE_TDR_TIME);
X  } else {
X    printf("ie%d: TDR returned unknown status %x\n", result);
X  }
X}
X
Xstatic void start_receiver(unit)
X     int unit;
X{
X  int s = splimp();
X
X  ie_softc[unit].scb->ie_recv_list = MK_16(MEM, ie_softc[unit].rframes[0]);
X  command_and_wait(unit, IE_RU_START, 0, 0);
X
X  ie_ack(ie_softc[unit].scb, IE_ST_WHENCE, unit, ie_softc[unit].ie_chan_attn);
X
X  splx(s);
X}
X
X/*
X * Here is a helper routine for iernr() and ieinit().  This sets up
X * the RFA.
X */
Xstatic caddr_t setup_rfa(caddr_t ptr, struct ie_softc *ie) {
X  volatile struct ie_recv_frame_desc *rfd = (void *)ptr;
X  volatile struct ie_recv_buf_desc *rbd;
X  int i;
X  int unit = ie - &ie_softc[0];
X
X  /* First lay them out */
X  for(i = 0; i < NFRAMES; i++) {
X    ie->rframes[i] = rfd;
X    bzero((char *)rfd, sizeof *rfd);
X    rfd++;
X  }
X
X  ptr = (caddr_t)Align((caddr_t)rfd);
X  
X  /* Now link them together */
X  for(i = 0; i < NFRAMES; i++) {
X    ie->rframes[i]->ie_fd_next =
X      MK_16(MEM, ie->rframes[(i + 1) % NFRAMES]);
X  }
X  
X  /* Finally, set the EOL bit on the last one. */
X  ie->rframes[NFRAMES - 1]->ie_fd_last |= IE_FD_LAST;
X
X  /*
X   * Now lay out some buffers for the incoming frames.  Note that
X   * we set aside a bit of slop in each buffer, to make sure that
X   * we have enough space to hold a single frame in every buffer.
X   */
X  rbd = (void *)ptr;
X
X  for(i = 0; i < NBUFFS; i++) {
X    ie->rbuffs[i] = rbd;
X    bzero((char *)rbd, sizeof *rbd);
X    ptr = (caddr_t)Align(ptr + sizeof *rbd);
X    rbd->ie_rbd_length = IE_RBUF_SIZE;
X    rbd->ie_rbd_buffer = MK_24(MEM, ptr);
X    ie->cbuffs[i] =  (void *)ptr;
X    ptr += IE_RBUF_SIZE;
X    rbd = (void *)ptr;
X  }
X  
X  /* Now link them together */
X  for(i = 0; i < NBUFFS; i++) {
X    ie->rbuffs[i]->ie_rbd_next = MK_16(MEM, ie->rbuffs[(i + 1) % NBUFFS]);
X  }
X  
X  /* Tag EOF on the last one */
X  ie->rbuffs[NBUFFS - 1]->ie_rbd_length |= IE_RBD_LAST;
X
X  /* We use the head and tail pointers on receive to keep track of
X   * the order in which RFDs and RBDs are used. */
X  ie->rfhead = 0;
X  ie->rftail = NFRAMES - 1;
X  ie->rbhead = 0;
X  ie->rbtail = NBUFFS - 1;
X
X  ie->scb->ie_recv_list = MK_16(MEM, ie->rframes[0]);
X  ie->rframes[0]->ie_fd_buf_desc = MK_16(MEM, ie->rbuffs[0]);
X
X  ptr = Align(ptr);
X  return ptr;
X}
X
X/*
X * This routine takes the environment generated by check_ie_present()
X * and adds to it all the other structures we need to operate the adapter.
X * This includes executing the CONFIGURE, IA-SETUP, and MC-SETUP commands,
X * starting the receiver unit, and clearing interrupts.
X *
X * THIS ROUTINE MUST BE CALLED AT splimp() OR HIGHER.
X */
Xint ieinit(unit)
X     int unit;
X{
X  struct ie_softc *ie = &ie_softc[unit];
X  volatile struct ie_sys_ctl_block *scb = ie->scb;
X  caddr_t ptr;
X  int s;
X
X  s = splimp();
X  if(~s & splhigh()) {
X    splx(s);
X    panic("ieinit not called at splimp() or higher");
X  }
X  splx(s);
X
X  ptr = (caddr_t)Align((caddr_t)scb + sizeof *scb);
X
X  /*
X   * Send the configure command first.
X   */
X  {
X    volatile struct ie_config_cmd *cmd = (void *)ptr;
X
X    ie_setup_config(cmd, ie->promisc);
X    cmd->com.ie_cmd_status = 0;
X    cmd->com.ie_cmd_cmd = IE_CMD_CONFIG | IE_CMD_LAST;
X    cmd->com.ie_cmd_link = 0xffff;
X
X    scb->ie_command_list = MK_16(MEM, cmd);
X
X    if(command_and_wait(unit, IE_CU_START, cmd, IE_STAT_COMPL)
X       || !(cmd->com.ie_cmd_status & IE_STAT_OK)) {
X      printf("ie%d: configure command failed\n", unit);
X      return 0;
X    }
X  }
X  /*
X   * Now send the Individual Address Setup command.
X   */
X  {
X    volatile struct ie_iasetup_cmd *cmd = (void *)ptr;
X
X    cmd->com.ie_cmd_status = 0;
X    cmd->com.ie_cmd_cmd = IE_CMD_IASETUP | IE_CMD_LAST;
X    cmd->com.ie_cmd_link = 0xffff;
X
X    bcopy((char *)ie_softc[unit].ns_addr, (char *)&cmd->ie_address,
X	  sizeof cmd->ie_address);
X
X    scb->ie_command_list = MK_16(MEM, cmd);
X    if(command_and_wait(unit, IE_CU_START, cmd, IE_STAT_COMPL)
X       || !(cmd->com.ie_cmd_status & IE_STAT_OK)) {
X      printf("ie%d: individual address setup command failed\n", unit);
X      return 0;
X    }
X  }
X
X  {
X    volatile struct ie_mcast_cmd *cmd = (void *)ptr;
X
X    cmd->com.ie_cmd_status = 0;
X    cmd->com.ie_cmd_cmd = IE_CMD_MCAST | IE_CMD_LAST;
X    cmd->com.ie_cmd_link = 0xffff;
X
X    /*
X     * Set up standard Ether broadcst address.
X     */
X    {
X      u_char *p = ie->mcast_addrs[0].data;
X      int i;
X      for(i = 0; i < 6; i++)
X	p[i] = 0xff;
X    }
X    ie->mcast_count = 1;
X
X    bcopy((caddr_t)ie->mcast_addrs, (caddr_t)cmd->ie_mcast_addrs,
X	  sizeof ie->mcast_addrs);
X    cmd->ie_mcast_number = ie->mcast_count;
X
X    scb->ie_command_list = MK_16(MEM, cmd);
X    if(command_and_wait(unit, IE_CU_START, cmd, IE_STAT_COMPL)
X       || !(cmd->com.ie_cmd_status & IE_STAT_OK)) {
X      printf("ie%d: multicast address setup command failed\n", unit);
X      return 0;
X    }
X  }
X
X  /*
X   * Now run the time-domain reflectometer.
X   */
X  run_tdr(unit, (void *)ptr);
X
X  /*
X   * Acknowledge any interrupts we have generated thus far.
X   */
X  ie_ack(ie->scb, IE_ST_WHENCE, unit, ie->ie_chan_attn);
X
X  /*
X   * Set up the RFA.
X   */
X  ptr = setup_rfa(ptr, ie);
X
X  /*
X   * Finally, the transmit command and buffer are the last little bit of work.
X   */
X  ie->xmit_cmd = (void *)ptr;
X  ptr += sizeof *ie->xmit_cmd;
X  ptr = Align(ptr);
X  ie->xmit_buf = (void *)ptr;
X  ptr += sizeof *ie->xmit_buf;
X  ptr = Align(ptr);
X  ie->xmit_cbuf = (void *)ptr;
X
X  bzero((caddr_t)ie->xmit_cmd, sizeof *ie->xmit_cmd);
X  bzero((caddr_t)ie->xmit_buf, sizeof *ie->xmit_buf);
X
X  /*
X   * This must be coordinated with iestart() and ietint().
X   */
X  ie->xmit_cmd->ie_xmit_status = IE_STAT_COMPL;
X
X  start_receiver(unit);
X  ie->ns_if.if_flags |= IFF_RUNNING; /* tell higher levels that we are here */
X}
X
Xstatic void ie_stop(unit)
X    int unit;
X{
X  command_and_wait(unit, IE_RU_DISABLE, 0, 0);
X}
X
Xint ieioctl(ifp, command, data)
X     struct ifnet *ifp;
X     int command;
X     void *data;
X{
X  struct ifaddr *ifa = (struct ifaddr *)data;
X  struct ie_softc *ie = &ie_softc[ifp->if_unit];
X  struct ifreq *ifr = (struct ifreq *)data;
X  int s, error = 0;
X
X  s = splimp();
X
X  switch(command) {
X  case SIOCSIFADDR:
X    ifp->if_flags |= IFF_UP;
X
X    switch(ifa->ifa_addr->sa_family) {
X#ifdef INET
X    case AF_INET:
X      ieinit(ifp->if_unit);
X      ((struct arpcom *)ifp)->ac_ipaddr =
X	IA_SIN(ifa)->sin_addr;
X      arpwhohas((struct arpcom *)ifp, &IA_SIN(ifa)->sin_addr);
X      break;
X#endif /* INET */
X
X#ifdef NS
X      /* This magic copied from if_is.c; I don't use XNS, so I have no
X       * way of telling if this actually works or not.
X       */
X    case AF_NS:
X      {
X	struct ns_addr *ina = &(IS_SNS(ifa)->sns_addr);
X
X	if(ns_nullhost(*ina)) {
X	  ina->x_host = *(union ns_host *)(ns->ns_addr);
X	} else {
X	  ifp->if_flags &= ~IFF_RUNNING;
X	  bcopy((caddr_t)ina->x_host.c_host,
X		(caddr_t)ns->ns_addr,
X		sizeof ns->ns_addr);
X	}
X
X	ieinit(ifp->if_unit);
X      }
X      break;
X#endif /* NS */
X
X    default:
X      ieinit(ifp->if_unit);
X      break;
X    }
X    break;
X
X  case SIOCSIFFLAGS:
X    if((ifp->if_flags & IFF_UP) == 0 &&
X       (ifp->if_flags & IFF_RUNNING)) {
X      ifp->if_flags &= ~IFF_RUNNING;
X      ie_stop(ifp->if_unit);
X    } else if((ifp->if_flags & IFF_UP) &&
X	      (ifp->if_flags & IFF_RUNNING) == 0) {
X      ie_softc[ifp->if_unit].promisc = 
X	!!(ifp->if_flags & (IFF_PROMISC|IFF_ALLMULTI));
X      ieinit(ifp->if_unit);
X    } else if(!ie_softc[ifp->if_unit].promisc &&
X	      (ifp->if_flags & (IFF_PROMISC | IFF_ALLMULTI))) {
X      ie_softc[ifp->if_unit].promisc = 1;
X      ieinit(ifp->if_unit);
X    } else if(ie_softc[ifp->if_unit].promisc &&
X	      !(ifp->if_flags & (IFF_PROMISC | IFF_ALLMULTI))) {
X      ie_softc[ifp->if_unit].promisc = 0;
X      ieinit(ifp->if_unit);
X    }
X    break;
X
X#ifdef useSIOCGHWADDR
X  case SIOCGHWADDR:
X    bcopy((caddr_t)ns->ns_addr, (caddr_t)&ifr->ifr_data, sizeof ns->ns_addr);
X    break;
X#endif /* useSIOCGHWADDR */
X
X  default:
X    error = EINVAL;
X  }
X
X  splx(s);
X  return error;
X}
X
X#ifdef DEBUG
Xvoid print_rbd(volatile struct ie_recv_buf_desc *rbd) {
X  printf("RBD at %08lx:\n"
X	 "actual %04x, next %04x, buffer %08x\n"
X	 "length %04x, mbz %04x\n",
X	 (unsigned long)rbd,
X	 rbd->ie_rbd_actual, rbd->ie_rbd_next, rbd->ie_rbd_buffer,
X	 rbd->ie_rbd_length, rbd->mbz);
X}
X#endif /* DEBUG */
X#endif /* NIE > 0 */
X
END_OF_FILE
if test 35027 -ne `wc -c <'if_ie.c'`; then
    echo shar: \"'if_ie.c'\" unpacked with wrong size!
fi
# end of 'if_ie.c'
fi
if test -f 'if_ieatt.h' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'if_ieatt.h'\"
else
echo shar: Extracting \"'if_ieatt.h'\" \(824 characters\)
sed "s/^X//" >'if_ieatt.h' <<'END_OF_FILE'
X/*
X * definitions for AT&T StarLAN 10 etc...
X */
X
X#define IEATT_RESET 	0	/* any write here resets the 586 */
X#define IEATT_ATTN 	1	/* any write here sends a Chan attn */
X#define IEATT_REVISION	6	/* read here to figure out this board */
X#define IEATT_ATTRIB	7	/* more information about this board */
X
X#define SL_BOARD(x) ((x) & 0x0f)
X#define SL_REV(x) ((x) >> 4)
X
X#define SL1_BOARD	0
X#define SL10_BOARD	1
X#define EN100_BOARD	2
X#define SLFIBER_BOARD	3
X
X#define SL_ATTR_WIDTH	0x04	/* bus width: clear -> 8-bit */
X#define SL_ATTR_SPEED	0x08	/* medium speed: clear -> 10 Mbps */
X#define SL_ATTR_CODING	0x10	/* encoding: clear -> Manchester */
X#define SL_ATTR_HBW	0x20	/* host bus width: clear -> 16-bit */
X#define SL_ATTR_TYPE	0x40	/* medium type: clear -> Ethernet */
X#define SL_ATTR_BOOTROM	0x80	/* set -> boot ROM present */
X
END_OF_FILE
if test 824 -ne `wc -c <'if_ieatt.h'`; then
    echo shar: \"'if_ieatt.h'\" unpacked with wrong size!
fi
# end of 'if_ieatt.h'
fi
if test -f 'ic/i82586.h' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'ic/i82586.h'\"
else
echo shar: Extracting \"'ic/i82586.h'\" \(11205 characters\)
sed "s/^X//" >'ic/i82586.h' <<'END_OF_FILE'
X/*-
X * Copyright (c) 1992, University of Vermont and State Agricultural College.
X * Copyright (c) 1992, Garrett A. Wollman.
X * All rights reserved.
X *
X * Redistribution and use in source and binary forms, with or without
X * modification, are permitted provided that the following conditions
X * are met:
X * 1. Redistributions of source code must retain the above copyright
X *    notice, this list of conditions and the following disclaimer.
X * 2. Redistributions in binary form must reproduce the above copyright
X *    notice, this list of conditions and the following disclaimer in the
X *    documentation and/or other materials provided with the distribution.
X * 3. All advertising materials mentioning features or use of this software
X *    must display the following acknowledgement:
X *	This product includes software developed by the University of
X *	Vermont and State Agricultural College and Garrett A. Wollman.
X * 4. Neither the name of the University nor the name of the author
X *    may be used to endorse or promote products derived from this software
X *    without specific prior written permission.
X *
X * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
X * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
X * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
X * ARE DISCLAIMED.  IN NO EVENT SHALL THE UNIVERSITY OR AUTHOR BE LIABLE
X * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
X * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
X * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
X * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
X * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
X * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
X * SUCH DAMAGE.
X *
X */
X
X/*
X * Intel 82586 Ethernet chip
X * Register, bit, and structure definitions.
X *
X * Written by GAW with reference to the Clarkson Packet Driver code for this
X * chip written by Russ Nelson and others.
X */
X
Xstruct ie_en_addr {
X  u_char data[6];
X};
X
X/*
X * This is the master configuration block.  It tells the hardware where all
X * the rest of the stuff is.
X */
Xstruct ie_sys_conf_ptr {
X  u_short mbz;			/* must be zero */
X  u_char ie_bus_use;		/* true if 8-bit only */
X  u_char mbz2[5];		/* must be zero */
X  caddr_t ie_iscp_ptr;		/* 24-bit physaddr of ISCP */
X};
X
X/*
X * Note that this is wired in hardware; the SCP is always located here, no
X * matter what.
X */
X#define IE_SCP_ADDR 0xfffff4
X
X/*
X * The tells the hardware where all the rest of the stuff is, too.
X * FIXME: some of these should be re-commented after we figure out their
X * REAL function.
X */
Xstruct ie_int_sys_conf_ptr {
X  u_char ie_busy;		/* zeroed after init */
X  u_char mbz;
X  u_short ie_scb_offset;	/* 16-bit physaddr of next struct */
X  caddr_t ie_base;		/* 24-bit physaddr for all 16-bit vars */
X};
X
X/*
X * This FINALLY tells the hardware what to do and where to put it.
X */
Xstruct ie_sys_ctl_block {
X  u_short ie_status;		/* status word */
X  u_short ie_command;		/* command word */
X  u_short ie_command_list;	/* 16-pointer to command block list */
X  u_short ie_recv_list;		/* 16-pointer to receive frame list */
X  u_short ie_err_crc;		/* CRC errors */
X  u_short ie_err_align;		/* Alignment errors */
X  u_short ie_err_resource;	/* Resource errors */
X  u_short ie_err_overrun;	/* Overrun errors */
X};
X
X/* Command values */
X#define IE_RU_COMMAND	0x0070	/* mask for RU command */
X#define IE_RU_NOP	0	/* for completeness */
X#define IE_RU_START	0x0010	/* start receive unit command */
X#define IE_RU_ENABLE	0x0020	/* enable receiver command */
X#define IE_RU_DISABLE	0x0030	/* disable receiver command */
X#define IE_RU_ABORT	0x0040	/* abort current receive operation */
X
X#define IE_CU_COMMAND	0x0700	/* mask for CU command */
X#define IE_CU_NOP	0	/* included for completeness */
X#define IE_CU_START	0x0100	/* do-command command */
X#define IE_CU_RESUME	0x0200	/* resume a suspended cmd list */
X#define IE_CU_STOP	0x0300	/* SUSPEND was already taken */
X#define IE_CU_ABORT	0x0400	/* abort current command */
X
X#define IE_ACK_COMMAND	0xf000	/* mask for ACK command */
X#define IE_ACK_CX	0x8000	/* ack IE_ST_DONE */
X#define IE_ACK_FR	0x4000	/* ack IE_ST_RECV */
X#define IE_ACK_CNA	0x2000	/* ack IE_ST_ALLDONE */
X#define IE_ACK_RNR	0x1000	/* ack IE_ST_RNR */
X
X#define IE_ACTION_COMMAND(x) (((x) & IE_CU_COMMAND) == IE_CU_START)
X				/* is this command an action command? */
X
X/* Status values */
X#define IE_ST_WHENCE	0xf000	/* mask for cause of interrupt */
X#define IE_ST_DONE	0x8000	/* command with I bit completed */
X#define IE_ST_RECV	0x4000	/* frame received */
X#define IE_ST_ALLDONE	0x2000	/* all commands completed */
X#define IE_ST_RNR	0x1000	/* receive not ready */
X
X#define IE_CU_STATUS	0x700	/* mask for command unit status */
X#define IE_CU_ACTIVE	0x200	/* command unit is active */
X#define IE_CU_SUSPEND	0x100	/* command unit is suspended */
X
X#define IE_RU_STATUS	0x70	/* mask for receiver unit status */
X#define IE_RU_SUSPEND	0x10	/* receiver is suspended */
X#define IE_RU_NOSPACE	0x20	/* receiver has no resources */
X#define IE_RU_READY	0x40	/* reveiver is ready */
X
X/*
X * This is filled in partially by the chip, partially by us.
X */
Xstruct ie_recv_frame_desc {
X  u_short ie_fd_status;		/* status for this frame */
X  u_short ie_fd_last;		/* end of frame list flag */
X  u_short ie_fd_next;		/* 16-pointer to next RFD */
X  u_short ie_fd_buf_desc;	/* 16-pointer to list of buffer desc's */
X  struct ie_en_addr dest;	/* destination ether */
X  struct ie_en_addr src;	/* source ether */
X  u_short ie_length;		/* 802 length/Ether type */
X  u_short mbz;			/* must be zero */
X};
X
X#define IE_FD_LAST	0x8000	/* last rfd in list */
X#define IE_FD_SUSP	0x4000	/* suspend RU after receipt */
X
X#define IE_FD_COMPLETE	0x8000	/* frame is complete */
X#define IE_FD_BUSY	0x4000	/* frame is busy */
X#define IE_FD_OK	0x2000	/* frame is bad */
X
X/*
X * linked list of buffers...
X */
Xstruct ie_recv_buf_desc {
X  u_short ie_rbd_actual;	/* status for this buffer */
X  u_short ie_rbd_next;		/* 16-pointer to next RBD */
X  caddr_t ie_rbd_buffer;	/* 24-pointer to buffer for this RBD */
X  u_short ie_rbd_length;	/* length of the buffer */
X  u_short mbz;			/* must be zero */
X};
X
X#define IE_RBD_LAST	0x8000	/* last buffer */
X#define IE_RBD_USED	0x4000	/* this buffer has data */
X/*
X * All commands share this in common.
X */
Xstruct ie_cmd_common {
X  u_short ie_cmd_status;	/* status of this command */
X  u_short ie_cmd_cmd;		/* command word */
X  u_short ie_cmd_link;		/* link to next command */
X};
X
X#define IE_STAT_COMPL	0x8000	/* command is completed */
X#define IE_STAT_BUSY	0x4000	/* command is running now */
X#define IE_STAT_OK	0x2000	/* command completed successfully */
X
X#define IE_CMD_NOP	0x0000	/* NOP */
X#define IE_CMD_IASETUP	0x0001	/* initial address setup */
X#define IE_CMD_CONFIG	0x0002	/* configure command */
X#define IE_CMD_MCAST	0x0003	/* multicast setup command */
X#define IE_CMD_XMIT	0x0004	/* transmit command */
X#define IE_CMD_TDR	0x0005	/* time-domain reflectometer command */
X#define IE_CMD_DUMP	0x0006	/* dump command */
X#define IE_CMD_DIAGNOSE	0x0007	/* diagnostics command */
X
X#define IE_CMD_LAST	0x8000	/* this is the last command in the list */
X#define IE_CMD_SUSPEND	0x4000	/* suspend CU after this command */
X#define IE_CMD_INTR	0x2000	/* post an interrupt after completion */
X
X/*
X * This is the command to transmit a frame.
X */
Xstruct ie_xmit_cmd {
X  struct ie_cmd_common com;	/* common part */
X#define ie_xmit_status com.ie_cmd_status
X
X  u_short ie_xmit_desc;		/* 16-pointer to buffer descriptor */
X  struct ie_en_addr ie_xmit_addr; /* destination address */
X
X  u_short ie_xmit_length;	/* 802.3 length/Ether type field */
X};
X
X#define IE_XS_MAXCOLL  	0x000f	/* number of collisions during transmit */
X#define IE_XS_EXCMAX	0x0020	/* exceeded maximum number of collisions */
X#define IE_XS_SQE	0x0040	/* SQE positive */
X#define IE_XS_DEFERRED	0x0080	/* transmission deferred */
X#define IE_XS_UNDERRUN	0x0100	/* DMA underrun */
X#define IE_XS_LOSTCTS	0x0200	/* Lost CTS */
X#define IE_XS_NOCARRIER	0x0400	/* No Carrier */
X#define IE_XS_LATECOLL	0x0800	/* Late collision */
X
X/*
X * This is a buffer descriptor for a frame to be transmitted.
X */
X
Xstruct ie_xmit_buf {
X  u_short ie_xmit_flags;	/* see below */
X  u_short ie_xmit_next;		/* 16-pointer to next desc. */
X  caddr_t ie_xmit_buf;		/* 24-pointer to the actual buffer */
X};
X
X#define IE_XMIT_LAST 0x8000	/* this TBD is the last one */
X/* The rest of the `flags' word is actually the length. */
X
X/*
X * Multicast setup command.
X */
X
X#define MAXMCAST 10
X
Xstruct ie_mcast_cmd {
X  struct ie_cmd_common com;	/* common part */
X#define ie_mcast_status com.ie_cmd_status
X
X  u_short ie_mcast_number;	/* number of multicast addresses */
X  struct ie_en_addr ie_mcast_addrs[MAXMCAST + 1];	/* space for them */
X};
X
X/*
X * Time Domain Reflectometer command.
X */
X
Xstruct ie_tdr_cmd {
X  struct ie_cmd_common com;	/* common part */
X#define ie_tdr_status com.ie_cmd_status
X
X  u_short ie_tdr_time;		/* error bits and time */
X};
X
X#define IE_TDR_SUCCESS	0x8000	/* TDR succeeded without error */
X#define IE_TDR_XCVR	0x4000	/* detected a transceiver problem */
X#define IE_TDR_OPEN	0x2000	/* detected an open */
X#define IE_TDR_SHORT	0x1000	/* TDR detected a short */
X#define IE_TDR_TIME	0x07ff	/* mask for reflection time */
X
X/*
X * Initial Address Setup command
X */
Xstruct ie_iasetup_cmd {
X  struct ie_cmd_common com;
X#define ie_iasetup_status com.ie_cmd_status
X
X  struct ie_en_addr ie_address;
X};
X
X/*
X * Configuration command
X */
Xstruct ie_config_cmd {
X  struct ie_cmd_common com;	/* common part */
X#define ie_config_status com.ie_cmd_status
X
X  u_char ie_config_count;	/* byte count (0x0c) */
X  u_char ie_fifo;		/* fifo (8) */
X  u_char ie_save_bad;		/* save bad frames (0x40) */
X  u_char ie_addr_len;		/* address length (0x2e) (AL-LOC == 1) */
X  u_char ie_priority;		/* priority and backoff (0x0) */
X  u_char ie_ifs;		/* inter-frame spacing (0x60) */
X  u_char ie_slot_low;		/* slot time, LSB (0x0) */
X  u_char ie_slot_high;		/* slot time, MSN, and retries (0xf2) */
X  u_char ie_promisc;		/* 1 if promiscuous, else 0 */
X  u_char ie_crs_cdt;		/* CSMA/CD parameters (0x0) */
X  u_char ie_min_len;		/* min frame length (0x40) */
X  u_char ie_junk;		/* stuff for 82596 (0xff) */
X};
X
X/*
X * Here are a few useful functions.  We could have done these as macros,
X * but since we have the inline facility, it makes sense to use that
X * instead.
X */
Xinline void ie_setup_config(volatile struct ie_config_cmd *cmd,
X				   int promiscuous) {
X  cmd->ie_config_count = 0x0c;
X  cmd->ie_fifo = 8;
X  cmd->ie_save_bad = 0x40;
X  cmd->ie_addr_len = 0x2e;
X  cmd->ie_priority = 0;
X  cmd->ie_ifs = 0x60;
X  cmd->ie_slot_low = 0;
X  cmd->ie_slot_high = 0xf2;
X  cmd->ie_promisc = !!promiscuous;
X  cmd->ie_crs_cdt = 0;
X  cmd->ie_min_len = 64;
X  cmd->ie_junk = 0xff;
X}
X
Xinline caddr_t Align(caddr_t ptr) {
X  unsigned long l = (unsigned long)ptr;
X  l = (l + 3) & ~3L;
X  return (caddr_t)l;
X}
X
Xinline void ie_ack(volatile struct ie_sys_ctl_block *scb,
X				  u_int mask, int unit,
X				  void (*ca)(int)) {
X  scb->ie_command = scb->ie_status & mask;
X  (*ca)(unit);
X}
X
END_OF_FILE
if test 11205 -ne `wc -c <'ic/i82586.h'`; then
    echo shar: \"'ic/i82586.h'\" unpacked with wrong size!
fi
# end of 'ic/i82586.h'
fi
echo shar: End of shell archive.
exit 0
-- 
Garrett A. Wollman   | Shashish is simple, it's discreet, it's brief. ... 
wollman@emba.uvm.edu | Shashish is the bonding of hearts in spite of distance.
uvm-gen!wollman      | It is a bond more powerful than absence.  We like people
UVM disagrees.       | who like Shashish.  - Claude McKenzie + Florent Vollant