*BSD News Article 3361


Return to BSD News archive

Xref: sserve comp.unix.bsd:3405 alt.sources:3882
Newsgroups: comp.unix.bsd,alt.sources
Path: sserve!manuel!munnari.oz.au!mips!mips!darwin.sura.net!europa.asd.contel.com!uunet!emba-news.uvm.edu!trantor.emba.uvm.edu!wollman
From: wollman@trantor.emba.uvm.edu (Garrett Wollman)
Subject: [386BSD] Intel 82586 Ethernet Driver
Message-ID: <1992Aug11.174255.5756@uvm.edu>
Sender: news@uvm.edu
Organization: University of Vermont, EMBA Computer Facility
Date: Tue, 11 Aug 1992 17:42:55 GMT
Lines: 1624

Announcing a functional Ethernet driver for cards based on the Intel
i82586 and i82596 Ethernet controllers.  Currently, the driver
supports only the AT&T<boo, hiss> StarLAN-10/EN-100 series cards, but
porting the drivers to other Ethernet controllers is the matter of
writing three new functions and modifying the switch statements in
ieprobe() appropriately.

This driver supports multiple receive buffers and a single transmit
buffer, has has been tested to some degree.  Certain unusual
conditions have been left un-handled, as I'm not entirely sure how to
deal with them as yet.  If you find any bugs, please communicate them
(preferably with fixes) directly to me (wollman@emba.uvm.edu).

Here is a reasonable configuration for this adapter:

device ie0 at isa? port 0x360 net irq 3 iomem 0xd0000 iosiz ? vector
ieintr

You will need to add a line in files.i386:
i386/isa/if_ie.c        optional ie device-driver


The driver supports all statistics-gathering functions:

ie0   1500  <Link>                           778     0      969     0     0
ie0   1500  132.198.4   tsornin.emba.uv      778     0      969     0     0

and seems to operate reasonably quickly.  Again, if you can see how to
improve the speed, please send patches to me.

-GAWollman

------------------------------------
#! /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:  /sys/i386/isa/if_ie.c /sys/i386/isa/if_ieatt.h
#   /sys/i386/isa/ic/i82586.h
# Wrapped by wollman@tsornin on Tue Aug 11 13:03:30 1992
PATH=/bin:/usr/bin:/usr/ucb ; export PATH
if test -f '/sys/i386/isa/if_ie.c' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'/sys/i386/isa/if_ie.c'\"
else
echo shar: Extracting \"'/sys/i386/isa/if_ie.c'\" \(30006 characters\)
sed "s/^X//" >'/sys/i386/isa/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 NFRAMES associated
Xreceive buffer descriptors.  In addition, we keep one area for each
Xcommand we would ever want to execute, so that we can do so easily.
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
X#ifndef ETHERMINLEN
X#define ETHERMINLEN 60
X#endif
X
X/*
X * ETHERMTU plus room for the header plus some slop.  This also
X * makes sure that the next RBD (which comes immediately after
X * the previous RBD's buffer) is properly aligned.
X */
X#define IE_BUF_LEN 1532
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);
X
Xstruct mbuf *ieget(char *buf, int length, int offset, struct ifnet *ifp);
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 4		/* number of frames to allow for receive */
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 valid;
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[NFRAMES];
X  volatile int rcv_free[NFRAMES];
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
Xstatic struct ie_config_cmd defconfig = {
X  { 0, IE_CMD_CONFIG | IE_CMD_LAST, 0xffff },
X  0x0c, 8, 0x2e00, 0x6000, 0xf200, 0, 0x40
X};
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  int s;
X
X  s = splimp();
X
X  ie_softc[unit].port = dvp->id_iobase;
X  ie_softc[unit].iomembot = dvp->id_maddr;
X  ie_softc[unit].iomem = 0;
X  ie_softc[unit].valid = 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
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  splx(s);
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 = 0;		/* XXX */
X  if_attach(ifp);
X}
X
X/*
X * What to do upon receipt of an interrupt.
X *
X * We would like to receive interrupts upon various events (errors,
X * transmit complete, etc.), but since we don't have the manual, we
X * don't know how to do so.
X */
Xint ieintr(unit)
X     int unit;
X{
X  struct ie_softc *ie = &ie_softc[unit];
X  u_short status;
X  int i;
X  int s = splimp();
X
X  if(!ie->valid) {
X    printf("ie%d: extra interrupt\n", unit);
X    ie_ack(ie->scb, IE_ST_WHENCE, unit, ie->ie_chan_attn);
X
X    return 0;
X  }
X
X  status = ie->scb->ie_status;
X
X  if(status & IE_ST_RECV) {
X    ie_ack(ie->scb, IE_ST_RECV, unit, ie->ie_chan_attn);
X    ierint(unit, ie);
X  }
X
X  if(status & IE_ST_ALLDONE) {
X    ie_ack(ie->scb, IE_ST_ALLDONE, unit, ie->ie_chan_attn);
X  }
X
X  if(status & IE_ST_DONE) {
X    ie_ack(ie->scb, IE_ST_DONE, unit, ie->ie_chan_attn);
X    ietint(unit, ie);
X  }
X
X  if(status & IE_ST_RNR) {
X    ie_ack(ie->scb, IE_ST_RNR, unit, ie->ie_chan_attn);
X    iernr(unit, ie);
X  }
X
X  splx(s);
X  return 0;
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
X  for(i = 0; i < NFRAMES; i++) {
X    status = ie->rframes[i]->ie_fd_status;
X
X    if((status & IE_FD_COMPLETE) && (status & IE_FD_OK)) {
X      if(ie->ns_if.if_ipackets++ % 1024) {
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 = ie->scb->ie_err_align =
X	  ie->scb->ie_err_resource = ie->scb->ie_err_overrun = 0;
X      }
X      ie_readframe(unit, ie, i);
X    }
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  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  ie->ns_if.if_flags &= ~IFF_OACTIVE;
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 do nothing, which may eventually cause ``random Ethernet hangs''
X * later on.
X */
Xstatic int iernr(unit, ie)
X     int unit;
X     struct ie_softc *ie;
X{
X  printf("ie%d: iernr\n", unit);
X  return 0;
X}
X
X/*
X * Read frame NUM from unit UNIT (pre-cached as IE).
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  char *buf = Align((char *)(ie->rbuffs[num]) 
X		    + sizeof(struct ie_recv_buf_desc));
X  int len = ie->rbuffs[num]->ie_rbd_actual & 0x4fff;
X
X  struct ether_header *eh;
X  struct mbuf *m;
X  struct ifqueue *inq;
X  int offset;			/* for trailers */
X
X  /*
X   * Deal with trailers.  This is a pain.  Copied from if_is.c.
X   */
X  eh = (struct ether_header *)buf;
X  eh->ether_type = ntohs(eh->ether_type);
X  len-= sizeof(struct ether_header) - 4;
X
X  if(eh->ether_type >= ETHERTYPE_TRAIL &&
X     eh->ether_type < ETHERTYPE_TRAIL + ETHERTYPE_NTRAILER) {
X    int residue;
X
X    offset = (eh->ether_type - ETHERTYPE_TRAIL) * 512;
X    if(offset >= ETHERMTU) return; /* sanity check #1 */
X
X    /*
X     * Extract the new Ethertype from the trailer mess.
X     */
X    eh->ether_type =
X      *(u_short *)((char *)(&eh[1]) + offset);
X    eh->ether_type = ntohs(eh->ether_type);
X
X    /*
X     * Find out how much was left after the trailer.
X     */
X    residue =
X      *(u_short *)((char *)(&eh[1]) + offset + 2);
X    len = offset + ntohs(residue);
X  } else {
X    offset = 0;
X  }
X
X  if(!len)
X    return;
X
X  m = ieget(buf, len, offset, &ie->ns_if);
X  if(!m)
X    return;
X
X  /*
X   * Now let the card know that we are done with this packet.
X   */
X  ie->rbuffs[num]->ie_rbd_length = IE_BUF_LEN;
X  ie->rbuffs[num]->ie_rbd_actual = 0;
X  ie->rframes[num]->ie_fd_status = 0;
X
X  /*
X   * Finally pass this packet up to higher layers.
X   */
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 */
Xstruct mbuf *ieget(buf, length, offset, ifp)
X     char *buf;
X     int length;
X     int offset;
X     struct ifnet *ifp;
X{
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}
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  } 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    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    return 0;
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 */
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  if(unit >= NIE)
X    return -1;
X
X  printf("ie%d: reset\n", unit);
X
X  check_ie_present(unit, ie_softc[unit].iomembot, ie_softc[unit].iosize);
X  ieinit(unit);
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  int stat;
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  /*
X   * Send an ACK.
X   */
X  stat = ie_softc[unit].scb->ie_status;
X  ie_softc[unit].scb->ie_command = stat & 0xf000;
X  (*ie_softc[unit].ie_chan_attn)(unit);
X
X  splx(s);
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
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 received frame descriptors for quality reception.
X   */
X  {
X    volatile struct ie_recv_frame_desc *rfd = (void *)ptr;
X    int i;
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[i]->ie_fd_last |= IE_FD_LAST;
X  }
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  {
X    volatile struct ie_recv_buf_desc *rbd = (void *)ptr;
X    int i;
X
X    /* Set them up */
X    for(i = 0; i < NFRAMES; 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_BUF_LEN;
X      rbd->ie_rbd_buffer = MK_24(MEM, ptr);
X      ptr += IE_BUF_LEN;
X      rbd = (void *)ptr;
X    }
X
X    /* Now link them together */
X    for(i = 0; i < NFRAMES; i++) {
X      ie->rbuffs[i]->ie_rbd_next = MK_16(MEM, ie->rbuffs[(i + 1) % NFRAMES]);
X    }
X
X    /* Tag EOF on the last one */
X    ie->rbuffs[NFRAMES - 1]->ie_rbd_length |= IE_RBD_LAST;
X  }
X
X  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
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  ie->valid = 1;
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      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#endif
X
END_OF_FILE
if test 30006 -ne `wc -c <'/sys/i386/isa/if_ie.c'`; then
    echo shar: \"'/sys/i386/isa/if_ie.c'\" unpacked with wrong size!
fi
# end of '/sys/i386/isa/if_ie.c'
fi
if test -f '/sys/i386/isa/if_ieatt.h' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'/sys/i386/isa/if_ieatt.h'\"
else
echo shar: Extracting \"'/sys/i386/isa/if_ieatt.h'\" \(824 characters\)
sed "s/^X//" >'/sys/i386/isa/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 <'/sys/i386/isa/if_ieatt.h'`; then
    echo shar: \"'/sys/i386/isa/if_ieatt.h'\" unpacked with wrong size!
fi
# end of '/sys/i386/isa/if_ieatt.h'
fi
if test -f '/sys/i386/isa/ic/i82586.h' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'/sys/i386/isa/ic/i82586.h'\"
else
echo shar: Extracting \"'/sys/i386/isa/ic/i82586.h'\" \(11205 characters\)
sed "s/^X//" >'/sys/i386/isa/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 AUTHORS 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 <'/sys/i386/isa/ic/i82586.h'`; then
    echo shar: \"'/sys/i386/isa/ic/i82586.h'\" unpacked with wrong size!
fi
# end of '/sys/i386/isa/ic/i82586.h'
fi
echo shar: End of shell archive.
exit 0
-- 
   Garrett A. Wollman  = wollman@emba.uvm.edu = UVM is welcome to my opinions
                       =    uvm-gen!wollman   =
   That's what being alive is all about.  No deity, no higher goal
   exists, than to bring joy to another person.    - Elf Sternberg