OpenCores
URL https://opencores.org/ocsvn/openrisc_me/openrisc_me/trunk

Subversion Repositories openrisc_me

[/] [openrisc/] [trunk/] [rtos/] [rtems/] [c/] [src/] [lib/] [libbsp/] [i386/] [i386ex/] [network/] [network.c] - Rev 389

Go to most recent revision | Compare with Previous | Blame | View Log

/* uti596.c: An 82596 ethernet driver for rtems-bsd.
 *
 *  $Id: network.c,v 1.2 2001-09-27 11:59:46 chris Exp $
 */
 
void dump_scb(void);
void printk_time(void);
 
#ifdef DBG_VERSION
#define BREAKPOINT()  asm("   int $3"); 
#else
#define BREAKPOINT()
#endif
 
#define KERNEL
 
 
/*
 
  EII: Oct 16 : Version 0.0
 
*/
 
#define DMA_MODE_CASCADE 0xC0   /* pass thru DREQ->HRQ, DACK<-HLDA only */
#define DMA_MASK_REG     0x0A
#define DMA_MODE_REG     0x0B
#define DMA_ENABLE       0x0
#define DMA_DISABLE      0x4   
 
struct i596_rfd *pISR_Rfd;  
 
void show_buffers (void);
void show_queues(void);
 
void outbyte(char);
void dumpQ(void);
 
#define UTI_596_ASSERT( condition, str ) { if (!( condition ) ) printk(str); }
int count_rx = 0;
 
/* static char *version = "uti596.c:v0.0 11/13/97\n"; */
 
#include <bsp.h>
#include <stdio.h>
#include <stdlib.h>
#include <rtems/error.h>
#include <rtems/rtems_bsdnet.h>
 
#include <sys/param.h>
#include <sys/mbuf.h>
#include <sys/socket.h>
#include <sys/sockio.h>
 
#include <net/if.h>
 
#include <netinet/in.h>
#include <netinet/if_ether.h>
 
#include "uti596.h"
#include "netexterns.h"
 
#include <asm.h>
 
 
/* #include "../misc/utils.h" */
 
static struct uti596_softc uti596_softc;
 
 
static    int scbStatus;
static    rtems_status_code sc;
static    struct i596_cmd *pIsrCmd;
static    struct i596_rfd *pIsrRfd;
 
/*
 * Initial 596 configuration
 */
char uti596initSetup[] = {
	0x0E,	/* length, prefetch off ( no RBD's ) */
	0xC8,	/* fifo to 8, monitor off */
	0x40,	/* don't save bad frames ( was save= 80, use intel's 40 )*/
	0x2E,	/* No source address insertion, 8 byte preamble */
	0x00,	/* priority and backoff defaults */
	0x60,	/* interframe spacing */
	0x00,	/* slot time LSB */
	0xf2,	/* slot time and retries */
	0x0C,	/* */
	0x08,	/* collision detect */
	0x40,	/* minimum frame length */
	0xfb,	/* tried C8 same as byte 1 in bits 6-7, else ignored*/
	0x00,
	0x3f	/*  no multi IA */ };
/*
 *  Externally defined symbols
 */
#define RX_BUF_COUNT     15
#define TX_BUF_COUNT     4
#define TX_BD_PER_BUF    4
 
#define INTERRUPT_EVENT         RTEMS_EVENT_1
#define START_TRANSMIT_EVENT	RTEMS_EVENT_2
#define NIC_RESET_EVENT	        RTEMS_EVENT_3
 
#define RBUF_SIZE	1520
 
 
/*
 * Local Routines
 */
 
/* These are extern, and non-inline  for testing purposes */
 
void        uti596addCmd                  (struct i596_cmd *pCmd);
void        uti596_initMem                (struct uti596_softc *); 
void        uti596_init                   (void * );
int         uti596initRxBufs              (int num);
int         uti596_initRFA                (int num);
int         uti596initRxBufs              (int num);
static int  uti596_ioctl                  (struct ifnet *, int, caddr_t);
rtems_isr   uti596DynamicInterruptHandler (rtems_vector_number);
 
void        uti596_txDaemon               (void *);
void        uti596_rxDaemon               (void *);
void        uti596_resetDaemon            (void *);
 
void        uti596_stop                   (struct uti596_softc *);
static void uti596_start                  (struct ifnet *);
 
void        uti596reset            (void);
 
void         uti596_stats      (struct uti596_softc *);
 
void uti596_initialize_hardware(struct uti596_softc *);
void uti596_reset_hardware(struct uti596_softc *);
 
void uti596clearListStatus(struct i596_rfd *);
void uti596addPolledCmd(struct i596_cmd *);
 
void uti596supplyFD(struct i596_rfd *);
 
struct i596_rfd * uti596dequeue( struct i596_rfd ** );
void uti596append( struct i596_rfd ** , struct i596_rfd * ); 
 
#ifdef DEBUG_INIT
static void         print_eth              (unsigned char *);
static void         print_hdr              (unsigned char *);
static void         print_pkt              (unsigned char *);
#endif
 
void send_packet(struct ifnet *, struct mbuf *);
 
#define UTI_596_IRQ 5
#define UTI_596_ETH_MIN_SIZE 60
 
/* Waits for the command word to clear.  The command word is cleared AFTER the interrupt is
 * generated. This allows the CPU to issue the next command
 */
#define  UTI_WAIT_COMMAND_ACCEPTED(duration,function)\
{   int waitcount = duration; \
    while (  uti596_softc.scb.command ) \
      if (--waitcount == 0) \
	{ \
	  printk("%s: i82596 timed out with status %x, cmd %x.\n", function, \
                  uti596_softc.scb.status,  uti596_softc.scb.command); \
	  break; \
    	} \
}
/*************************************************************************/
 
void 
uti596_request_reset(void){
   uti596_softc.nic_reset = 0;
   sc = rtems_event_send(uti596_softc.resetDaemonTid, NIC_RESET_EVENT);
   if ( sc != RTEMS_SUCCESSFUL )
     rtems_panic ("Can't notify resetDaemon: %s\n", rtems_status_text (sc));
}
 
 
 
static void uti596_maskOn(const rtems_irq_connect_data* irq)
{
  /*
   * code should be moved from initialize_hardware
   * to this location ?
   */
  (void) BSP_irq_enable_at_i8259s (irq->name);
}
 
static void uti596_maskOff(const rtems_irq_connect_data* irq)
{
  /*
   * code should be moved from initialize_hardware
   * to this location ?
   */
  (void) BSP_irq_disable_at_i8259s (irq->name);
}
 
static int uti596_isOn(const rtems_irq_connect_data* irq)
{
  return BSP_irq_enabled_at_i8259s (irq->name);
}
 
 
/***********************************************************************
 *  Function:   uti596initRFA(int num) ( New )
 *
 *  Description:
 *              attempts to allocate and initialize ( chain together )
 *              the requested number of FD's
 *
 *  Algorithm:
 *
 ***********************************************************************/
 
 
int uti596_initRFA(int num)
{
    struct i596_rfd *pRfd;
    int i = 0;
 
 
#ifdef DBG_596
    printf ("%s: uti596_initRFA %d.\n", num);
#endif
 
    /* 
     * Initialize the first rfd in the rfa
     */
    pRfd = (struct i596_rfd *) calloc (1,sizeof (struct i596_rfd));
    if ( !pRfd ) {
      printf("Can't allocate all buffers: only %d allocated\n", i);
      return 0;
    }
    else {
      uti596_softc.countRFD = 1;
      uti596_softc.pBeginRFA = uti596_softc.pEndRFA = pRfd;
    printf ( "First Rfd allocated is: %p\n", 
	     uti596_softc.pBeginRFA);
    }
 
    for (i = 1; i < num; i++) {
      pRfd = (struct i596_rfd *) calloc (1,sizeof (struct i596_rfd) );
      if ( pRfd != NULL ) {
	uti596_softc.countRFD++;
	uti596_softc.pEndRFA -> next = pRfd; /* link it in   */	  
	uti596_softc.pEndRFA         = pRfd; /* move the end */
#ifdef DBG_596_RFA
	printf("Allocated RFD @ %p\n", pRfd);
#endif
      }
      else {	
	printf("Can't allocate all buffers: only %d allocated\n", i);
	break;
      }
    } /* end for */
 
    uti596_softc.pEndRFA -> next = I596_NULL;
    UTI_596_ASSERT(uti596_softc.countRFD == RX_BUF_COUNT,"INIT:WRONG RFD COUNT\n" ); 
 
#ifdef DBG_596_RFA
    printf ( "Head of RFA is buffer %p\nEnd of RFA is buffer %p \n", 
	     uti596_softc.pBeginRFA, 
	     uti596_softc.pEndRFA );
#endif
    /* initialize the Rfd's */
    for ( pRfd = uti596_softc.pBeginRFA;
	  pRfd != I596_NULL;
	  pRfd = pRfd -> next ) {
 
      pRfd->cmd = 0x0000;
      pRfd->stat = 0x0000;
      pRfd->pRbd =  I596_NULL;
      pRfd->count = 0;  /* number of bytes in buffer: usually less than size */
      pRfd->size = 1532;      /* was 1532;  buffer size ( All RBD ) */
      if ( pRfd -> data == NULL )
	printf("Can't allocate the RFD data buffer\n");
    }
 
    /* mark the last FD */ 
    uti596_softc.pEndRFA -> cmd = CMD_EOL; /* moved jan 13 from before the init stuff */
 
#ifdef DBG_596_RFA
    printf ( "Head of RFA is buffer @ %p \n", uti596_softc.pBeginRFA );
#endif
 
 
    uti596_softc.pSavedRfdQueue = 
      uti596_softc.pEndSavedQueue = I596_NULL;   /* initially empty */
 
    uti596_softc.savedCount = 0;
 
    uti596_softc.nop.cmd.command = CmdNOp; /* initialize the nop command */
 
    return (i); /* the number of allocated buffers */
 
}
/***********************************************************************
 *  Function:   uti596supplyFD
 *
 *  Description: returns a buffer to the receive frame pool.
 *               call this with Inetrrupts disabled!
 *
 *  Algorithm:
 *
 ***********************************************************************/
void uti596supplyFD(struct i596_rfd * pRfd )
{
 struct i596_rfd *pLastRfd;
 
 
 UTI_596_ASSERT(pRfd != I596_NULL, "Supplying NULL RFD!\n");
 pRfd -> cmd  = CMD_EOL;
 pRfd -> pRbd = I596_NULL;
 pRfd -> next = I596_NULL;
 pRfd -> stat = 0x0000;      /* clear STAT_C and STAT_B bits */
 
 /* 
  * Check if the list is empty:
  */
 if ( uti596_softc.pBeginRFA == I596_NULL ) {  
   /* Init a list w/ one entry */
   uti596_softc.pBeginRFA = uti596_softc.pEndRFA = pRfd;
   UTI_596_ASSERT(uti596_softc.countRFD == 0, "Null begin, but non-zero count\n");
   if ( uti596_softc.pLastUnkRFD != I596_NULL )
     printf("LastUnkRFD is NOT NULL!!\n");
   uti596_softc.countRFD = 1;
   return;
 }
 /*
  * Check if the last RFD is used/read by the 596.
  */
 pLastRfd = uti596_softc.pEndRFA;
 
 if (    pLastRfd != I596_NULL && 
      ! (pLastRfd -> stat & ( STAT_C | STAT_B ) )) { /* C = complete, B = busy (prefetched) */
 
   /* 
    * Not yet too late to add it 
    */
   pLastRfd -> next = pRfd;
   pLastRfd -> cmd &= ~CMD_EOL;  /* RESET_EL : reset EL bit to 0  */
   uti596_softc.countRFD++;  /* Lets assume we add it successfully 
			        If not, the RFD may be used, and may decrement countRFD < 0 !!*/
   /*
    * Check if the last RFD was used while appending.
    */
   if ( pLastRfd -> stat & ( STAT_C | STAT_B ) ) { /* completed or was prefetched */
     /* 
      * Either the EL bit of the last rfd has been read by the 82596,
      * and it will stop after reception,( true when RESET_EL not reached ) or
      * the EL bit was NOT read by the 82596 and it will use the linked
      * RFD for the next reception. ( true is RESET_EL was reached )
      * So, it is unknown whether or not the linked rfd will be used.
      * Therefore, the end of list CANNOT be updated.
      */
     UTI_596_ASSERT ( uti596_softc.pLastUnkRFD == I596_NULL, "Too many Unk RFD's\n" );
     uti596_softc.pLastUnkRFD = pRfd;              
     return;
   }
   else {
     /*
      * The RFD being added was not touched by the 82596
      */
     if (uti596_softc.pLastUnkRFD != I596_NULL ) {
 
       uti596append(&uti596_softc.pSavedRfdQueue, pRfd); /* Only here! saved Q */
       uti596_softc.pEndSavedQueue = pRfd;
       uti596_softc.savedCount++;
       uti596_softc.countRFD--;
 
     }
     else {
       uti596_softc.pEndRFA = pRfd;           /* the RFA has been extended */
       if ( ( uti596_softc.scb.status & SCB_STAT_RNR || 
	      uti596_softc.scb.status & RU_NO_RESOURCES ) &&
	    uti596_softc.countRFD > 1 ) {   /* was == 2 */
	 uti596_softc.pBeginRFA -> cmd &= ~CMD_EOL;  /* Ensure that beginRFA is not EOL */
 
	 UTI_596_ASSERT(uti596_softc.pEndRFA -> next == I596_NULL, "supply: List buggered\n");
	 UTI_596_ASSERT(uti596_softc.pEndRFA -> cmd & CMD_EOL, "supply: No EOL at end.\n");
	 UTI_596_ASSERT(uti596_softc.scb.command == 0, "Supply: scb command must be zero\n");
#ifdef DBG_START
	 printf("Supply FD: starting receiver");
#endif
	 /* start the receiver */
	 UTI_596_ASSERT(uti596_softc.pBeginRFA != I596_NULL, "rx start w/ NULL begin! \n");
	 uti596_softc.scb.pRfd = uti596_softc.pBeginRFA;
	 uti596_softc.scb.command = RX_START | SCB_STAT_RNR;  /* Don't ack RNR! The receiver should be stopped in this case */
	 UTI_596_ASSERT( !(uti596_softc.scb.status & SCB_STAT_FR),"FRAME RECEIVED INT COMING!\n");
	 outport_byte(CHAN_ATTN, 0); 
       }
     }
     return;
 
   }
 } 
 else {
   /* 
    * too late , pLastRfd in use ( or NULL ), 
    * in either case, EL bit has been read, and RNR condition will occur 
    */
   uti596append( &uti596_softc.pSavedRfdQueue, pRfd); /* save it for RNR */
 
   uti596_softc.pEndSavedQueue = pRfd;                /* reset end of saved queue */  
   uti596_softc.savedCount++;
 
 
   return;
 }
}
 
static void
uti596_start (struct ifnet *ifp)
{
	struct uti596_softc *sc = ifp->if_softc;
 
	rtems_event_send (sc->txDaemonTid, START_TRANSMIT_EVENT);
	ifp->if_flags |= IFF_OACTIVE;
}
 
void
uti596_initialize_hardware(struct uti596_softc *sc)
{
  int boguscnt = 1000;
  rtems_status_code status_code;
 
  printf("uti596_initialize_hardware\n");
 
  /* reset the board  */
  outport_word( PORT_ADDR, 0 );
  outport_word( PORT_ADDR, 0 );
 
  uti596_softc.pScp = (struct i596_scp *) calloc(1,sizeof(struct i596_scp) + 0xf);
#ifdef DBG_INIT
  printf("initialize_hardware:Scp address initially %p\n", sc->pScp);
#endif
  sc->pScp = (struct i596_scp *)
    ((((int)uti596_softc.pScp) + 0xf) & 0xfffffff0);
 
#ifdef DBG_INIT
  printf("initialize_hardware:change scp address to : %p\n",sc->pScp);
#endif
 
  /* change the scp address */
#ifdef DBG_INIT
  printf("Change the SCP address\n");
#endif
 
  /*
   * Set the DMA mode to enable the 82596 to become a bus-master
   */
  outport_byte(DMA_MASK_REG,DMA_DISABLE);      /* disable_dma */
  outport_byte(DMA_MODE_REG,DMA_MODE_CASCADE); /* set dma mode */
  outport_byte(DMA_MASK_REG,DMA_ENABLE);       /* enable dma */
 
  /* reset the board  */
  outport_word( PORT_ADDR, 0 );
  outport_word( PORT_ADDR, 0 );
 
  outport_word(PORT_ADDR, ((((int)sc->pScp) &  0xffff) | 2 ));
  outport_word(PORT_ADDR, (( (int)sc->pScp) >> 16 ) & 0xffff );
 
  /* This is linear mode, LOCK function is disabled  */
 
  sc->pScp->sysbus = 0x00540000;
  sc->pScp->iscp   = &sc->iscp;
  sc->iscp.scb     = &sc->scb;
  sc->iscp.stat    = 0x0001;
 
  sc->pCmdHead     = sc->scb.pCmd = I596_NULL;
 
#ifdef DBG_596
  printf("Starting i82596.\n");
#endif
 
  /* Pass the scb address to the 596 */
  outport_word(CHAN_ATTN,0);
 
  while (sc->iscp.stat)
    if (--boguscnt == 0)
      {
	printf("initialize_hardware: timed out with status %4.4lx\n", 
	       sc->iscp.stat );
	break;
      }
 
  /* clear the command word */
  sc->scb.command = 0;
 
  /*
   * Set up interrupts ( NEW irq style )
   */
  sc->irqInfo.name = UTI_596_IRQ;
  sc->irqInfo.hdl  = ( void * ) uti596DynamicInterruptHandler;
  sc->irqInfo.on   = uti596_maskOn;
  sc->irqInfo.off  = uti596_maskOff;
  sc->irqInfo.isOn = uti596_isOn;
 
  status_code = BSP_install_rtems_irq_handler (&sc->irqInfo);
  if (!status_code)
    rtems_panic ("Can't attach uti596 interrupt handler for irq %d\n",
		  sc->irqInfo.name);
 
  /* Initialize the 82596 memory ( Transmit buffers ) */
  uti596_initMem(sc);
 
#ifdef DBG_INIT
  printf("After attach, status of board = 0x%x\n", sc->scb.status );
#endif
  outport_word(0x380, 0xf); /* reset the LED's */
}
 

void
uti596_reset_hardware(struct uti596_softc *sc)
{
  int boguscnt = 1000;
  rtems_status_code status_code;
  struct i596_cmd *pCmd;
 
 
  printf("uti596_reset_hardware\n");
  pCmd = sc->pCmdHead;  /* This is a tx command for sure (99.99999%)  */
 
  /* reset the board  */
  outport_word( PORT_ADDR, 0 );
  outport_word( PORT_ADDR, 0 );
 
  if ( sc->pScp == NULL ) {
    printf("Calloc scp\n");
    uti596_softc.pScp = (struct i596_scp *) calloc(1,sizeof(struct i596_scp) + 0xf);
  }
 
#ifdef DBG_RESET
  printf("reset_hardware:Scp address %p\n", sc->pScp);
#endif
  sc->pScp = (struct i596_scp *)
    ((((int)uti596_softc.pScp) + 0xf) & 0xfffffff0);
 
#ifdef DBG_RESET
  printf("reset_hardware:change scp address to : %p\n",sc->pScp);
#endif
 
 
  /* change the scp address */
#ifdef DBG_RESET
  printf("Change the SCP address\n");
#endif
 
  /*
   * Set the DMA mode to enable the 82596 to become a bus-master
   */
  outport_byte(DMA_MASK_REG,DMA_DISABLE);      /* disable_dma */
  outport_byte(DMA_MODE_REG,DMA_MODE_CASCADE); /* set dma mode */
  outport_byte(DMA_MASK_REG,DMA_ENABLE);       /* enable dma */
 
  /* reset the board  */
  outport_word( PORT_ADDR, 0 );
  outport_word( PORT_ADDR, 0 );
 
  /*  outport_word(PORT_ADDR, ((((int)uti596_softc.pScp) &  0xffff) | 2 ));
  outport_word(PORT_ADDR, (( (int)uti596_softc.pScp) >> 16 ) & 0xffff ); */
 
  outport_word(PORT_ADDR, ((((int)sc->pScp) &  0xffff) | 2 ));
  outport_word(PORT_ADDR, (( (int)sc->pScp) >> 16 ) & 0xffff );
 
  /* This is linear mode, LOCK function is disabled  */
 
  sc->pScp->sysbus = 0x00540000;
  sc->pScp->iscp   = &sc->iscp;
  sc->iscp.scb     = &sc->scb;
  sc->iscp.stat    = 0x0001;
 
  sc->pCmdHead     = sc->scb.pCmd = I596_NULL;
  /*
   * Wake the transmitter if needed. 
   */
  if ( uti596_softc.txDaemonTid && pCmd != I596_NULL ){  
    printf("****RESET: wakes transmitter!\n");
    status_code = rtems_event_send (uti596_softc.txDaemonTid, 
			   INTERRUPT_EVENT);
 
    if ( status_code != RTEMS_SUCCESSFUL )
      printk("****ERROR:Could NOT send event to tid 0x%x : %s\n",
	     uti596_softc.txDaemonTid, rtems_status_text (status_code) );
  }
 
#ifdef DBG_596
  printf("reset_hardware: starting i82596.\n");
#endif
 
  /* Pass the scb address to the 596 */
  outport_word(CHAN_ATTN,0);
 
  while (sc->iscp.stat)
    if (--boguscnt == 0)
      {
	printf("reset_hardware: timed out with status %4.4lx\n", 
	       sc->iscp.stat );
	break;
      }
 
  /* clear the command word */
  sc->scb.command = 0;
 
#ifdef DBG_RESET
  printf("After reset_hardware, status of board = 0x%x\n", sc->scb.status );
#endif
 
  outport_word(0x380, 0xf); /* reset the LED's */
}
 

/***********************************************************************
 *  Function:   uti596_initMem
 *
 *  Description:
 *             creates the necessary descriptors for the
 *             uti596 board, hooks the interrupt, and starts the board.
 *             Assumes that interrupts are hooked.
 *
 *  Algorithm:
 *
 ***********************************************************************/
 
 
 void
uti596_initMem(struct uti596_softc * sc)
{
    int i,count;
    struct i596_tbd *pTbd;
 
    sc->resetDone = 0; /* ??? */
 
    /*
     * Set up receive frame area (RFA) 
     */
    i = uti596_initRFA( sc->rxBdCount );
    if ( i < sc->rxBdCount  ) 
      printf("init_rfd: only able to allocate %d receive frame descriptors\n", i);
 
    sc->scb.pRfd =  sc->pBeginRFA; 
 
#ifdef DBG_INIT
    printf(" IRQ %d.\n", sc->irqInfo.name);
#endif    
 
    /*
     * Diagnose the health of the board
     */
    uti596Diagnose(1);
 
    /*
     * set up the i596 config command
     */
#ifdef DBG_INIT
    printf("Configuring\n");
#endif
 
    sc->set_conf.cmd.command = CmdConfigure;
    memcpy (sc->set_conf.data, uti596initSetup, 14);
    uti596addPolledCmd( (struct i596_cmd *) &sc->set_conf);
 
    /****
    * POLL
    ****/
 
    count = 2000;
    while( !( sc->set_conf.cmd.status & STAT_C ) && --count )
      printf(".");
 
    if ( count )
      printf("Configure OK, count = %d\n",count);
    else
      printf("***Configure failed\n");
 
    /*******/
 
    /* 
     * Create the IA setup command
     */
 
#ifdef DBG_INIT
    printf("Setting Address\n");
#endif
    sc->set_add.cmd.command = CmdSASetup;
    for ( i=0; i<6; i++)
      sc->set_add.data[i]=sc->arpcom.ac_enaddr[i];
 
    sc->cmdOk = 0;
    uti596addPolledCmd((struct i596_cmd *)&sc->set_add);
        /*******/
 
    count = 2000;
    while( !(sc->set_add.cmd.status & STAT_C ) && --count)
      printf(".");
 
    if ( count )
      printf ("Set Address OK, count= %d\n",count);
    else
      printf("Set Address Failed\n");
    /*******/
 
#ifdef DBG_INIT
    printf( "After initialization, status and command: 0x%x, 0x%x\n", 
	    sc->scb.status, sc->scb.status);
 
#endif
 
    /* initialize transmit buffer descriptors*/
    sc->pLastUnkRFD = I596_NULL;
    sc->pTxCmd         = (struct tx_cmd *) calloc (1,sizeof (struct tx_cmd) );
    sc->pTbd           = (struct i596_tbd *) calloc (1,sizeof (struct i596_tbd) );
    sc->pTxCmd -> pTbd = sc->pTbd;
    sc->pTxCmd->cmd.command  = CMD_FLEX|CmdTx;
    sc->pTxCmd->pad          = 0;
    sc->pTxCmd->size         = 0; /* all bytes are in list of TBD's */                         
 
    pTbd = sc->pTbd;
 
    for ( i=0; i<sc->txBdCount; i++)
      pTbd = pTbd -> next = (struct i596_tbd *) calloc (1,sizeof (struct i596_tbd) );
 
    pTbd -> next = I596_NULL;
 
    memset ( &sc->zeroes, 0, 64);   
 
#ifdef DBG_596
    printf( "After receiver start, status and command: 0x%x, 0x%x\n", 
	    sc->scb.status, sc->scb.status);
#endif
    printf("uti596_initMem allows ISR's\n");
    sc->resetDone = 1; /* now need ISR  */
 
}
 
 

/***********************************************************************
 *  Function:   uti596dump
 *
 *  Description: Dump 596 registers
 *
 *  Algorithm: 
 ***********************************************************************/
/* static */ int
uti596dump(char * pDumpArea)
{
  struct i596_dump dumpCmd;
  int boguscnt = 25000000; /* over a second! */
 
 
#ifdef DBG_596  
printf("uti596dump:\n");
#endif
 
  dumpCmd.cmd.command = CmdDump;
  dumpCmd.cmd.next    = I596_NULL;
  dumpCmd.pData       = pDumpArea;
  uti596_softc.cmdOk = 0;
  uti596addCmd        ( (struct i596_cmd *)&dumpCmd);
  while (1)
    if ( --boguscnt == 0){
      printf("Dump command was not processed within spin loop delay\n");
      return 0;
    }
    else {
      if ( uti596_softc.cmdOk )
	return 1; /* successful completion */
    }
 
 
}

/***********************************************************************
 *  Function:   uti596_rxDaemon
 *
 *  Description: Receiver task
 *
 *  Algorithm: Extract the packet from an RFD, and place into an 
 *             mbuf chain.  Place the mbuf chain in the network task
 *             queue. Assumes that the frame check sequence is removed
 *             by the 82596.
 *
 ***********************************************************************/
 
/* static */ void
uti596_rxDaemon(void *arg)
{
  struct uti596_softc *sc = (struct uti596_softc *)arg;
  struct ifnet *ifp = &sc->arpcom.ac_if;
  struct mbuf *m;
 
  struct i596_rfd *pRfd;
  ISR_Level level;
  int tid;
  rtems_event_set events;
  struct ether_header *eh;
 
  int frames = 0;
 
#ifdef DBG_596
  printf ("uti596_rxDaemon\n");
  printf("&scb = %p, pRfd = %p\n", &sc->scb,sc->scb.pRfd);
#endif    
 
  rtems_task_ident (0, 0, &tid);
 
#ifdef DBG_596
  printf("RX tid = 0x%x\n", tid);
#endif    
 
    for(;;) {
      /*
       * Wait for packet.
       */
#ifdef DBG_596
      printf("Receiver sleeps\n");
#endif
 
      rtems_bsdnet_event_receive (INTERRUPT_EVENT,
				  RTEMS_WAIT|RTEMS_EVENT_ANY,
				  RTEMS_NO_TIMEOUT,
				  &events);
 
#ifdef DBG_596
      printf("Receiver wakes\n");
#endif
      /* 
       * While received frames are available. Note that the frame may be
       * a fragment, so it is NOT a complete packet.
       */
      pRfd = uti596dequeue( &sc->pInboundFrameQueue);
      while ( pRfd && 
	      pRfd != I596_NULL &&
	      pRfd -> stat & STAT_C )
	{
 
#ifdef DEBUG_INIT
	  printf("\nReceived packet:\n");
	  print_eth( pRfd->data);
#endif
	  if ( pRfd->stat & STAT_OK){
	    /*	 a good frame. Allocate an mbuf to take it from the queue */
 
	    int pkt_len = pRfd->count & 0x3fff; /* the actual # of bytes received */
 
#ifdef DBG_596
	    printf("Good frame, @%p, data @%p length %d\n", pRfd, pRfd -> data , pkt_len);
#endif
	    frames++;
 
 
            /* 
	     * Allocate an mbuf to give to the stack
             * The format of the data portion of the RFD is:
             * <ethernet header, payload>.  
	     * The FRAME CHECK SEQUENCE / CRC is stripped by the uti596. 
             * This is to be optimized later.... should not have to memcopy!
	     */
	    MGETHDR(m, M_WAIT, MT_DATA);
	    MCLGET(m, M_WAIT);
 
	    m->m_pkthdr.rcvif = ifp;
	    /* move everything into an mbuf */
	    memcpy(m->m_data, 
		   pRfd->data, 
		   pkt_len);
 
	    m->m_len = m->m_pkthdr.len = pkt_len - sizeof(struct ether_header) - 4;
 
	    /* move the header to an mbuf */
	    eh = mtod (m, struct ether_header *);
	    m->m_data += sizeof(struct ether_header);
 
#ifdef DBG_596
	      printf("m->m_ext: %p pRfd -> data: %p\n",
		     m->m_ext,  pRfd -> data);
#endif
#ifdef DEBUG_INIT_2
	    printf("mbuf contains:\n");
	    print_eth( (char *) (((int)m->m_data)-sizeof(struct ether_header)));
	    for ( i = 0; i<20; i++)
	      printf(".");
 
#endif
#ifdef DBG_VERSION
	  BREAKPOINT();
#endif
	    ether_input (ifp, eh, m);
 
          } /* end if STAT_OK */
 
	  else {
	    /* 
	     * A bad frame is present: Note that this could be the last RFD!
	     */
#ifdef DBG_596
	    printf("Bad frame\n");
#endif
	    /* 
	     * FIX ME: use the statistics from the SCB
	     */
	    sc->stats.rx_errors++;
	    if ((sc->scb.pRfd->stat) & 0x0001) 
	      sc->stats.collisions++;
	    if ((sc->scb.pRfd->stat) & 0x0080) 
	      sc->stats.rx_length_errors++;
	    if ((sc->scb.pRfd->stat) & 0x0100) 
	      sc->stats.rx_over_errors++;
	    if ((sc->scb.pRfd->stat) & 0x0200) 
	      sc->stats.rx_fifo_errors++;
	    if ((sc->scb.pRfd->stat) & 0x0400) 
	      sc->stats.rx_frame_errors++;
	    if ((sc->scb.pRfd->stat) & 0x0800) 
	      sc->stats.rx_crc_errors++;
	    if ((sc->scb.pRfd->stat) & 0x1000) 
	      sc->stats.rx_length_errors++;
	  }
 
	  UTI_596_ASSERT(pRfd != I596_NULL, "Supplying NULL RFD\n");
 
#ifdef DBG_SUPPLY_FD 
	  printf("Supply FD Starting\n");
#endif
	  _ISR_Disable(level);
	  uti596supplyFD ( pRfd );   /* Return RFD to RFA. CAN WE REALLY?*/
	  _ISR_Enable(level);
#ifdef DBG_SUPPLY_FD 
	  printf("Supply FD Complete\n");
#endif
#ifdef DBG_VERSION
	  BREAKPOINT();
#endif
 
	  pRfd = uti596dequeue( &sc->pInboundFrameQueue); /* grab next frame */
 
	} /* end while */
    } /* end for(;;)*/
 
#ifdef DBG_596
    printf ("frames %d\n", frames);
#endif
 
}
 
 /***********************************************************************
  *  Function:   uti596clearListStatus
  *
  *  Description:
  *             Clear the stat fields for all rfd's
  *  Algorithm: 
  *
  ***********************************************************************/
 
void
uti596clearListStatus(struct i596_rfd *pRfd)
{
 
  while ( pRfd != I596_NULL ) {
    pRfd -> stat = 0;           /* clear the status field */
    pRfd = pRfd-> next; 
  }
}
 
void uti596reset(void)
 {
   int i,count;
   struct uti596_softc *sc = &uti596_softc;
   /*   struct i596_rfd * pRfd; */
 
#ifdef DBG_RESET
     printf ("reset: begins\n");
#endif
 
  sc->resetDone = 0;
  sc->irqInfo.off(&sc->irqInfo);
 
  UTI_WAIT_COMMAND_ACCEPTED(10000, "reset: wait for previous command complete");  
 
  /* abort ALL of the current work */
    /* FEB 17 REMOVED 
    >>>>>
    sc->scb.command = CUC_ABORT | RX_ABORT;
    outport_word(CHAN_ATTN,0);
    UTI_WAIT_COMMAND_ACCEPTED(4000, "reset: abort requested");
    <<<<< 
    */
 
  uti596_reset_hardware(&uti596_softc); /* reset the ethernet hardware. must re-config */
 
#ifdef DBG_RESET
  uti596Diagnose(1);
#endif
 
  sc->set_conf.cmd.command = CmdConfigure;
  memcpy (sc->set_conf.data, uti596initSetup, 14);
  uti596addPolledCmd( (struct i596_cmd *) &sc->set_conf);
 
  /****
   * POLL
   ****/
 
  count = 2000;
  while( !( sc->set_conf.cmd.status & STAT_C ) && --count )
    printf(".");
 
  if ( count )
    printf("Configure OK, count = %d\n",count);
  else
    printf("***reset: Configure failed\n");
 
  /* 
   * Create the IA setup command
   */
 
#ifdef DBG_RESET
  printf("reset: Setting Address\n");
#endif
  sc->set_add.cmd.command = CmdSASetup;
  for ( i=0; i<6; i++)
    sc->set_add.data[i]=sc->arpcom.ac_enaddr[i];
 
  sc->cmdOk = 0;
  uti596addPolledCmd((struct i596_cmd *)&sc->set_add);
 
  count = 2000;
  while( !(sc->set_add.cmd.status & STAT_C ) && --count)
    printf(".");
 
  if ( count )
    printf ("Reset Set Address OK, count= %d\n",count);
  else
    printf("Reset Set Address Failed\n");
  /*******/
 
  sc->pCmdHead = sc->pCmdTail = sc->scb.pCmd = I596_NULL; /* Feb 17. clear these out */
 
#ifdef DBG_RESET
  printf( "After reset, status and command: 0x%x, 0x%x\n", 
	  sc->scb.status, sc->scb.status);
 
#endif
 
 
  /* restore the RFA */
 
  /*dumpQ();*/
 
  if ( sc->pLastUnkRFD != I596_NULL ) {
    sc-> pEndRFA =  sc->pLastUnkRFD; /* The end position can be updated */
    sc-> pLastUnkRFD = I596_NULL;           
  }
 
  sc->pEndRFA->next = sc->pSavedRfdQueue;
  if ( sc->pSavedRfdQueue != I596_NULL ) {
    sc->pEndRFA = sc->pEndSavedQueue;
    sc->pSavedRfdQueue = sc->pEndSavedQueue = I596_NULL;
    sc -> countRFD = sc->rxBdCount ;
  }
 
  /*   if ( sc->pInboundFrameQueue != I596_NULL ){
    do {
      pRfd = sc->pInboundFrameQueue->next;
      sc->pEndRFA -> next = sc->pInboundFrameQueue;
      sc->pInboundFrameQueue = pRfd;
     } while( pRfd != I596_NULL ) ;
 
  }
  */
 
  sc->scb.pRfd =  sc->pBeginRFA; /* readdress the head of the RFA in the SCB */
 
  uti596clearListStatus(sc->pBeginRFA );
 
  /*  dumpQ();*/
 
  printf("Reset:Starting NIC\n");
  sc->scb.command = RX_START;
  sc->started = 1;               /* we assume that the start works */
  sc->resetDone = 1;             /* moved here from after channel attn. */
  outport_word(CHAN_ATTN,0 ); 
  UTI_WAIT_COMMAND_ACCEPTED(4000, "reset");
  printf("Reset:Start complete \n");
  UTI_596_ASSERT(sc->pCmdHead == I596_NULL, "Reset: CMD not cleared\n");
  sc->irqInfo.on(&sc->irqInfo);  /* moved back here. Tried it before RX command issued. */
 
  /* uti596addCmd(&uti506_softc.nop); */ /* just for fun */
 
#ifdef DBG_RESET
  printf("reset: complete\n");
#endif
 }
 
 /***********************************************************************
  *  Function:   uti596addCmd
  *
  *  Description:
  *             This routine adds a command onto the end of the
  *             command chain
  *
  *  Algorithm:
  *            Add the command to the end of and existing chain,
  *            or start the chain and issue a CUC_START
  *
  *
  ***********************************************************************/
 
 /* static */ void uti596addCmd(struct i596_cmd *pCmd)
 {
     ISR_Level level;
 
 #ifdef DBG_596
     printf("Adding command 0x%x\n", pCmd -> command );
 #endif
 
#ifdef DEBUG_ADD
 
     switch ( pCmd -> command & 0x7 ){ /* check bottom 7 bits */
     case CmdConfigure:
       printf("ADD: Configure Command 0x%x\n", pCmd->command);
       break;
     case CmdSASetup:
       printf("ADD: Set Address Command 0x%x\n", pCmd->command);
       break;
     case CmdMulticastList:
       printf("ADD: Multi-cast list 0x%x\n", pCmd->command);
       break;
     case CmdNOp:
        printf("ADD: NO op 0x%x\n", pCmd->command);
	break;
     case CmdTDR:
        printf("ADD: TDR 0x%x\n", pCmd->command);
        break;
     case CmdDump:
       printf("ADD: Dump 0x%x\n", pCmd->command);
       break;
     case CmdDiagnose:
       printf("ADD: Diagnose 0x%x\n", pCmd->command);
       break;
     case CmdTx:
       break;
     default:
       printf("****Unknown Command encountered 0x%x\n", pCmd->command);
       break;
     } /* end switch */
 
#endif
 
 
 
     pCmd->status = 0;
     pCmd->command |= (CMD_EOL | CMD_INTR ); /* all commands last in list & return an interrupt */
 
     pCmd->next = I596_NULL;
 
     _ISR_Disable(level);
     if (uti596_softc.pCmdHead == I596_NULL)
       {
	 uti596_softc.pCmdHead =      
	   uti596_softc.pCmdTail =
	   uti596_softc.scb.pCmd = pCmd;
#ifdef DBG_596
	 printf("First Cmd\n");
#endif
	 UTI_WAIT_COMMAND_ACCEPTED(10000,"add command"); /* wait for acceptance of previous command */
	 /* CHANGED TO |= Mar. 27 4:20 pm, was just =. changed back jun 18 1998. The wait assures command = 0 */
	 uti596_softc.scb.command = CUC_START;
	 outport_word (CHAN_ATTN,0);
     _ISR_Enable(level);
       }
     else 
       {
#ifdef DBG_596
	 printf("Chained Cmd\n");
#endif
	 uti596_softc.pCmdTail->next = pCmd; 
	 uti596_softc.pCmdTail = pCmd;           /* added Jan 30 */
     _ISR_Enable(level);
       }
 
 
#ifdef DBG_596
	 printf("Scb status & command 0x%x 0x%x\n", 
		uti596_softc.scb.status,
		uti596_softc.scb.command );
#endif
 
 }
 
 /***********************************************************************
  *  Function:   uti596addPolledCmd
  *
  *  Description:
  *             This routine issues a single command then polls for it's
  *             completion.  TO BE CALLED FROM ISR ONLY
  *
  *  Algorithm:
  *            Give the command to the driver. ( CUC_START is ALWAYS required )
  *            Poll for completion. 
  *
  ***********************************************************************/
 
void uti596addPolledCmd(struct i596_cmd *pCmd)
 {
 
 #ifdef DBG_596
     printf("Adding command 0x%x\n", pCmd -> command );
 #endif
 
#ifdef DBG_POLLED_CMD
 
     switch ( pCmd -> command & 0x7 ){ /* check bottom 7 bits */
     case CmdConfigure:
       printf("PolledCMD: Configure Command 0x%x\n", pCmd->command);
       break;
     case CmdSASetup:
       printf("PolledCMD: Set CMDress Command 0x%x\n", pCmd->command);
       break;
     case CmdMulticastList:
       printf("PolledCMD: Multi-cast list 0x%x\n", pCmd->command);
       break;
     case CmdNOp:
        printf("PolledCMD: NO op 0x%x\n", pCmd->command);
	break;
     case CmdTDR:
        printf("PolledCMD: TDR 0x%x\n", pCmd->command);
        break;
     case CmdDump:
       printf("PolledCMD: Dump 0x%x\n", pCmd->command);
       break;
     case CmdDiagnose:
       printf("PolledCMD: Diagnose 0x%x\n", pCmd->command);
       break;
     case CmdTx:
       break;
     default:
       printf("PolledCMD: ****Unknown Command encountered 0x%x\n", pCmd->command);
       break;
     } /* end switch */
 
#endif
 
     pCmd->status = 0;
     pCmd->command |=  CMD_EOL ; /* only command in list*/
 
     pCmd->next = I596_NULL;
 
     UTI_WAIT_COMMAND_ACCEPTED(10000,"Add Polled command: wait prev");
 
     uti596_softc.pCmdHead = uti596_softc.pCmdTail = uti596_softc.scb.pCmd = pCmd;
     uti596_softc.scb.command = CUC_START;
     outport_word (CHAN_ATTN,0);
 
     UTI_WAIT_COMMAND_ACCEPTED(10000,"Add Polled command: start"); 
     uti596_softc.pCmdHead = uti596_softc.pCmdTail = uti596_softc.scb.pCmd = I596_NULL;
 
#ifdef DBG_POLLED_CMD
     printf("Scb status & command 0x%x 0x%x\n", 
	    uti596_softc.scb.status,
	    uti596_softc.scb.command );
#endif
 
 }
/*
 * Driver transmit daemon
 */
void
uti596_txDaemon (void *arg)
{
	struct uti596_softc *sc = (struct uti596_softc *)arg;
	struct ifnet *ifp = &sc->arpcom.ac_if;
	struct mbuf *m;
	rtems_event_set events;
 
	for (;;) {
	  /*
	   * Wait for packet from stack
	   */
	  rtems_bsdnet_event_receive (START_TRANSMIT_EVENT, 
				      RTEMS_EVENT_ANY | RTEMS_WAIT, 
				      RTEMS_NO_TIMEOUT, &events);
 
	  /*
	   * Send packets till queue is empty.
	   * Ensure that irq is on before sending.
	   */
	  for (;;) { 
	      /* Feb 17: No need to make sure a reset is in progress,
	       *         Since reset daemon runs at same priority as this thread
	       */
	      /*
	       * Get the next mbuf chain to transmit.
	       */
	      IF_DEQUEUE(&ifp->if_snd, m);
	      if (!m)
		break;
 
	      send_packet (ifp, m); /* blocks */
	  } /* end for */
	  ifp->if_flags &= ~IFF_OACTIVE; /* no more to send, mark output inactive  */
	}
}
 
 
/*
 * NIC reset daemon.
 */
void
uti596_resetDaemon (void *arg)
{
        struct uti596_softc *sc = (struct uti596_softc *)arg;
	rtems_event_set events;
	rtems_time_of_day tm_struct;
 
	/* struct ifnet *ifp = &sc->arpcom.ac_if; */
 
	for (;;) {
	  /*
	   * Wait for reset event from ISR
	   */
	  rtems_bsdnet_event_receive (NIC_RESET_EVENT, 
				      RTEMS_EVENT_ANY | RTEMS_WAIT, 
				      RTEMS_NO_TIMEOUT, &events);
 
	  rtems_clock_get(RTEMS_CLOCK_GET_TOD, &tm_struct);
	  printf("reset daemon: Resetting NIC @ %d:%d:%d \n",
		 tm_struct.hour, tm_struct.minute, tm_struct.second);
 
	  sc->stats.nic_reset_count++;
	  /*
	   * Reinitialize the network card
	   */
	  rtems_bsdnet_semaphore_obtain ();
	  uti596reset();
	  rtems_bsdnet_semaphore_release ();
	}
}
 
 
 /***********************************************************************
  *  Function:   send_packet
  *
  *  Description: Send a raw ethernet packet
  *              
  *  Algorithm:
  *             increment some stats counters,
  *             create the transmit command,
  *             add the command to the CBL,
  *             wait for event
  *
  ***********************************************************************/
 
void send_packet(struct ifnet *ifp, struct mbuf *m)
{
  struct i596_tbd *pPrev = I596_NULL,
    *pRemainingTbdList,
    *pTbd;
  struct mbuf *n, *input_m = m;
 
  struct uti596_softc *sc = ifp->if_softc; /* is this available from ifp ?*/
 
  struct mbuf *l = NULL; 
  unsigned int length = 0;
  rtems_status_code status;
  int bd_count = 0;
  rtems_event_set events;
 
  /* 
   * For all mbufs in the chain, 
   *  fill a transmit buffer descriptor
   */
  pTbd = sc->pTxCmd->pTbd;
 
  do {              
    if (m->m_len) {
      /*
       * Fill in the buffer descriptor
       */
      length    += m->m_len;
      pTbd->data = mtod (m, void *);
      pTbd->size = m->m_len;
      pPrev      = pTbd;
      pTbd       = pTbd -> next;
      l          = m;
      m          = m->m_next;
    }
    else {
      /*
       * Just toss empty mbufs
       */
      MFREE (m, n);
      m = n;
      if (l != NULL)
	l->m_next = m;
    }
  } while( m != NULL && ++bd_count < 16 );
 
 
  /* This should never happen */
  if ( bd_count == 16 ) {
    printf("TX ERROR:Too many mbufs in the packet!!!\n");
    printf("Must coalesce!\n");
  }
 
 
  if ( length < UTI_596_ETH_MIN_SIZE ) {
    pTbd->data = sc->zeroes;       /* add padding to pTbd */
    pTbd->size = UTI_596_ETH_MIN_SIZE - length; /* zeroes have no effect on the CRC */
  }
  else
    pTbd = pPrev; /* Don't use pTbd in the send routine */
 
  /*  Disconnect the packet from the list of Tbd's  */
  pRemainingTbdList = pTbd->next;
  pTbd->next  = I596_NULL;     
  pTbd->size |= UTI_596_END_OF_FRAME;    
 
#ifdef DBG_RAW
  printf("RAW:Add cmd and sleep\n");
#endif
 
  sc->rawsndcnt++;     
 
#ifdef DBG_RAW
  printf ("sending packet\n");
#endif
 
  /* Sending Zero length packet: shouldn't happen */
  if (pTbd->size <= 0) return ;
 
 
#ifdef DEBUG_INIT_2
  printf("\nTransmitter adds packet\n");
  print_hdr    ( sc->pTxCmd->pTbd->data ); /* print the first part */
  print_pkt    ( sc->pTxCmd->pTbd->next->data ); /* print the first part */
  /*  print_echo(sc->pTxCmd->pTbd->data); */
#endif
#ifdef DBG_VERSION
	  BREAKPOINT();
#endif
 
 
  /* add the command to the output command queue */
  uti596addCmd ( (struct i596_cmd *) sc->pTxCmd );
 
  /* sleep until the command has been processed or Timeout encountered. */
  status= rtems_bsdnet_event_receive (INTERRUPT_EVENT,
				      RTEMS_WAIT|RTEMS_EVENT_ANY,
				      RTEMS_NO_TIMEOUT,
				      &events);
 
  if ( status != RTEMS_SUCCESSFUL ) {
    printf("Could not sleep %s\n", rtems_status_text(status)); 
  }
 
#ifdef DBG_RAW
  printf("RAW: wake\n");
#endif
 
  sc->txInterrupts++;
 
#ifdef DEBUG_INIT
  printf("\nTransmitter issued packet\n");
  print_hdr    ( sc->pTxCmd->pTbd -> data ); /* print the first part */
  print_pkt    ( sc->pTxCmd->pTbd ->next-> data ); /* print the first part */
#endif
 
  if ( sc->pTxCmd -> cmd.status & STAT_OK )
    sc->stats.tx_packets++;
  else
    {
#ifdef DBG_RAW
      printf("******Driver Error 0x%x\n", sc->pTxCmd -> cmd.status );
#endif
      sc->stats.tx_errors++;
      if ( sc->pTxCmd->cmd.status  & 0x0020 ) 
	sc->stats.tx_retries_exceeded++;
      if (!(sc->pTxCmd->cmd.status & 0x0040)) 
	sc->stats.tx_heartbeat_errors++;
      if ( sc->pTxCmd->cmd.status  & 0x0400 ) 
	sc->stats.tx_carrier_errors++;
      if ( sc->pTxCmd->cmd.status  & 0x0800 ) 
	sc->stats.collisions++;
      if ( sc->pTxCmd->cmd.status  & 0x1000 ) 
	sc->stats.tx_aborted_errors++;
    } /* end if stat_ok */	 
 
  /* 
   * Restore the transmited buffer descriptor chain.
   */
  pTbd -> next = pRemainingTbdList;
 
  /*
   * Free the mbufs used by the sender.
   */
  m = input_m;
  while ( m != NULL ) {
    MFREE(m,n);
    m = n;
  }
 
 
}

 /***********************************************************************
  *  Function:   print_eth
  *
  *  Description:
  *              Print the contents of an ethernet packet header
  *              CANNOT BE CALLED FROM ISR
  *
  *  Algorithm:
  *            Print Destination, Src, and type of packet
  *
  ***********************************************************************/
 
 /* static */ void print_eth(unsigned char *add)
 {
     int i;
     short int length;
 
     printf("Packet Location %p\n", add);
 
     printf ("Dest  ");
 
     for (i = 0; i < 6; i++)
	 printf(" %2.2X", add[i]);
 
     printf ("\n");
 
     printf ("Source");
 
     for (i = 6; i < 12; i++)
	 printf(" %2.2X", add[i]);
 
     printf ("\n");
 
     printf ("frame type %2.2X%2.2X\n", add[12], add[13]);
 
     if ( add[12] == 0x08 && add[13] == 0x06 )
       { /* an ARP */
	 printf("Hardware type : %2.2X%2.2X\n", add[14],add[15]);
	 printf("Protocol type : %2.2X%2.2X\n", add[16],add[17]);
	 printf("Hardware size : %2.2X\n", add[18]);
	 printf("Protocol size : %2.2X\n", add[19]);
	 printf("op            : %2.2X%2.2X\n", add[20],add[21]);
 
	 printf("Sender Enet addr: ");
 
	 for ( i=0; i< 5 ; i++)
	   printf( "%x:", add[22 + i]);
 
	 printf("%x\n", add[27]);
 
	 printf("Sender IP addr: ");
	 for ( i=0; i< 3 ; i++)
	   printf( "%u.", add[28 + i]);
 
	 printf("%u\n", add[31]);
 
	 printf("Target Enet addr: ");
	 for ( i=0; i< 5 ; i++)
	   printf( "%x:", add[32 + i]);
	 printf("%x\n", add[37]);
 
	 printf("Target IP addr: ");
 
	 for ( i=0; i< 3 ; i++)
	   printf( "%u.", add[38 + i]);
	 printf("%u\n", add[41]);
 
	}
 
     if ( add[12] == 0x08 && add[13] == 0x00 )
       { /* an IP packet */
	 printf("*********************IP HEADER******************\n");
	 printf("IP version/IPhdr length: %2.2X TOS: %2.2X\n", add[14] , add[15]);
	 printf("IP total length: %2.2X %2.2X, decimal %d\n", add[16], add[17], length = (add[16]<<8 | add[17] )); 
	 printf("IP identification: %2.2X %2.2X, 3-bit flags and offset %2.2X %2.2X\n",
		add[18],add[19], add[20], add[21]);
	 printf("IP TTL: %2.2X, protocol: %2.2X, checksum: %2.2X %2.2X \n",
		add[22],add[23],add[24],add[25]);
	 printf("IP packet type: %2.2X code %2.2X\n", add[34],add[35]);
 
	 printf("Source IP address: ");
	 for ( i=0; i< 3 ; i++)
	   printf( "%u.", add[26 + i]);
 
	 printf("%u\n", add[29]);
 
	 printf("Destination IP address: ");
	 for ( i=0; i< 3 ; i++)
	   printf( "%u.", add[30 + i]);
	 printf("%u\n", add[33]);
 
	 /* printf("********************IP Packet Data*******************\n");
	 	 length -=20;
	 for ( i=0; i < length ; i++)
	   printf("0x%2.2x ", add[34+i]);
	 printf("\n");
 
	 printf("ICMP checksum: %2.2x %2.2x\n", add[36], add[37]);
	 printf("ICMP identifier: %2.2x %2.2x\n", add[38], add[39]);
	 printf("ICMP sequence nbr: %2.2x %2.2x\n", add[40], add[41]);
	 */
	}
 
 
 }
#ifdef DEBUG_INIT
 
 /***********************************************************************
  *  Function:   print_eth
  *
  *  Description:
  *              Print the contents of an ethernet packet header
  *              CANNOT BE CALLED FROM ISR
  *
  *  Algorithm:
  *            Print Destination, Src, and type of packet
  *
  ***********************************************************************/
 
 /* static */ void print_hdr(unsigned char *add)
 {
     int i;
     short int length;
 
     printf("Header Location %p\n", add);
 
     printf ("Dest  ");
 
     for (i = 0; i < 6; i++)
	 printf(" %2.2X", add[i]);
 
     printf ("\n");
 
     printf ("Source");
 
     for (i = 6; i < 12; i++)
	 printf(" %2.2X", add[i]);
 
     printf ("\n");
 
     printf ("frame type %2.2X%2.2X\n", add[12], add[13]);
 
 
 }
 /***********************************************************************
  *  Function:   print_pkt
  *
  *  Description:
  *              Print the contents of an ethernet packet header
  *              CANNOT BE CALLED FROM ISR
  *
  *  Algorithm:
  *            Print Destination, Src, and type of packet
  *
  ***********************************************************************/
 
 /* static */ void print_pkt(unsigned char *add)
 {
     int i;
     short int length;
 
     printf("Data Location %p\n", add);
 
     if ( add[0] == 0x08 && add[1] == 0x06 )
       { /* an ARP */
	 printf("Hardware type : %2.2X%2.2X\n", add[14],add[15]);
	 printf("Protocol type : %2.2X%2.2X\n", add[16],add[17]);
	 printf("Hardware size : %2.2X\n", add[18]);
	 printf("Protocol size : %2.2X\n", add[19]);
	 printf("op            : %2.2X%2.2X\n", add[20],add[21]);
 
	 printf("Sender Enet addr: ");
 
	 for ( i=0; i< 5 ; i++)
	   printf( "%x:", add[22 + i]);
 
	 printf("%x\n", add[27]);
 
	 printf("Sender IP addr: ");
	 for ( i=0; i< 3 ; i++)
	   printf( "%u.", add[28 + i]);
 
	 printf("%u\n", add[31]);
 
	 printf("Target Enet addr: ");
	 for ( i=0; i< 5 ; i++)
	   printf( "%x:", add[32 + i]);
	 printf("%x\n", add[37]);
 
	 printf("Target IP addr: ");
 
	 for ( i=0; i< 3 ; i++)
	   printf( "%u.", add[38 + i]);
	 printf("%u\n", add[41]);
 
	}
 
     if ( add[0] == 0x08 && add[1] == 0x00 )
       { /* an IP packet */
	 printf("*********************IP HEADER******************\n");
	 printf("IP version/IPhdr length: %2.2X TOS: %2.2X\n", add[14] , add[15]);
	 printf("IP total length: %2.2X %2.2X, decimal %d\n", add[16], add[17], length = (add[16]<<8 | add[17] )); 
	 printf("IP identification: %2.2X %2.2X, 3-bit flags and offset %2.2X %2.2X\n",
		add[18],add[19], add[20], add[21]);
	 printf("IP TTL: %2.2X, protocol: %2.2X, checksum: %2.2X %2.2X \n",
		add[22],add[23],add[24],add[25]);
	 printf("IP packet type: %2.2X code %2.2X\n", add[34],add[35]);
 
	 printf("Source IP address: ");
	 for ( i=0; i< 3 ; i++)
	   printf( "%u.", add[26 + i]);
 
	 printf("%u\n", add[29]);
 
	 printf("Destination IP address: ");
	 for ( i=0; i< 3 ; i++)
	   printf( "%u.", add[30 + i]);
	 printf("%u\n", add[33]);
 
	 printf("********************IP Packet Data*******************\n");
	 length -=20;
	 for ( i=0; i < length ; i++)
	   printf("0x%2.2x ", add[34+i]);
	 printf("\n");
 
	 printf("ICMP checksum: %2.2x %2.2x\n", add[36], add[37]);
	 printf("ICMP identifier: %2.2x %2.2x\n", add[38], add[39]);
	 printf("ICMP sequence nbr: %2.2x %2.2x\n", add[40], add[41]);
	}
 
 
 }
 /***********************************************************************
  *  Function:   print_echo
  *
  *  Description:
  *              Print the contents of an ethernet packet header
  *              CANNOT BE CALLED FROM ISR
  *
  *  Algorithm:
  *            Prints only echo packets
  *
  ***********************************************************************/
 
 /* static */ void print_echo(unsigned char *add)
 {
     int i;
     short int length;
 
     if ( add[12] == 0x08 && add[13] == 0x00 ){ /* an IP packet */
 
       printf("Packet Location %p\n", add);
 
       printf ("Dest  ");
 
       for (i = 0; i < 6; i++)
	 printf(" %2.2X", add[i]);
 
       printf ("\n");
 
       printf ("Source");
 
       for (i = 6; i < 12; i++)
	 printf(" %2.2X", add[i]);
 
       printf ("\n");
 
       printf ("frame type %2.2X%2.2X\n", add[12], add[13]);
 
       printf("*********************IP HEADER******************\n");
       printf("IP version/IPhdr length: %2.2X TOS: %2.2X\n", add[14] , add[15]);
       printf("IP total length: %2.2X %2.2X, decimal %d\n", add[16], add[17], length = (add[16]<<8 | add[17] )); 
       printf("IP identification: %2.2X %2.2X, 3-bit flags and offset %2.2X %2.2X\n",
	      add[18],add[19], add[20], add[21]);
       printf("IP TTL: %2.2X, protocol: %2.2X, checksum: %2.2X %2.2X \n",
	      add[22],add[23],add[24],add[25]);
       printf("IP packet type: %2.2X code %2.2X\n", add[34],add[35]);
 
       printf("Source IP address: ");
       for ( i=0; i< 3 ; i++)
	 printf( "%u.", add[26 + i]);
 
       printf("%u\n", add[29]);
 
       printf("Destination IP address: ");
       for ( i=0; i< 3 ; i++)
	 printf( "%u.", add[30 + i]);
       printf("%u\n", add[33]);
 
       printf("********************IP Packet Data*******************\n");
       length -=20;
       for ( i=0; i < length ; i++)
	 printf("0x%2.2x ", add[34+i]);
       printf("\n");
 
       printf("ICMP checksum: %2.2x %2.2x\n", add[36], add[37]);
       printf("ICMP identifier: %2.2x %2.2x\n", add[38], add[39]);
       printf("ICMP sequence nbr: %2.2x %2.2x\n", add[40], add[41]);
     }   
 }
#endif
 
 /***********************************************************************
  *  Function:   uti596_attach
  *
  *  Description:
  *              User requested attach of driver to hardware
  *
  *  Algorithm:
  *
  *              Check that the board is present
  *              parse and store the command line parameters
  *                 argv[0]: interface label, e.g., "uti596"
  *                 argv[1]: maximum transmission unit, bytes, e.g., "1500"
  *                 argv[2]: IP address (optional)
  *              initialize required rx and tx buffers
  *              hook interrupt
  *              issue start command and some diagnostics
  *              return       
  *
  ***********************************************************************/
 
 
int uti596_attach(struct rtems_bsdnet_ifconfig * pConfig )
{
  struct uti596_softc *sc = &uti596_softc;          /* soft config */
  struct ifnet * ifp = &sc->arpcom.ac_if;
  int i = 0;
 
#ifdef DBG_ATTACH
  printf("attach");
#endif
 
 
  sc->started = 0; /* The NIC is not started yet */
  sc->ioAddr = IO_ADDR;
 
  /* Indicate to ULCS that this is initialized */  
  ifp->if_softc = sc;  
  sc -> pScp = NULL;
 
  /* Assign the name */
  ifp->if_name = "uti";
 
  /* Assign the unit number */
  ifp->if_unit = 1;
 
  /* Assign mtu */
  if ( pConfig -> mtu )
    ifp->if_mtu = pConfig -> mtu;
  else
    ifp->if_mtu = ETHERMTU;
 
  /* Assign and possibly override the hw address */
 
  if ( !pConfig->hardware_address) { /* Read the ethernet address from the board */
    for (i = 0; i < 8; i++)
      inport_byte(NIC_ADDR+i,sc->arpcom.ac_enaddr[i] );
  }
  else {
    /* hwaddr override */ 
    memcpy (sc->arpcom.ac_enaddr, pConfig->hardware_address, ETHER_ADDR_LEN);
  }
 
  /* Test for valid hwaddr */
  if(memcmp(sc->arpcom.ac_enaddr,"\xAA\x55\x01",3)!= 0)/* b0 of byte 0 != 0 => multicast */
    return ENODEV;
 
  /* Assign requested receive buffer descriptor count */
  if (pConfig->rbuf_count)
    sc->rxBdCount = pConfig->rbuf_count;
  else
    sc->rxBdCount = RX_BUF_COUNT;
 
  /* Assign requested tx buffer descriptor count */
  if (pConfig->xbuf_count)
    sc->txBdCount = pConfig->xbuf_count;
  else
    sc->txBdCount = TX_BUF_COUNT * TX_BD_PER_BUF;
 
  /* ignore_broadcast is an unused feature... accept broadcast */
  /* sc->acceptBroadcast = !pConfig->ignore_broadcast; */
 
  ifp->if_snd.ifq_maxlen = ifqmaxlen;
  ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX;
 
  /* to init_hardware */
  sc->started = 1;
  sc->pInboundFrameQueue = I596_NULL;
 
 
  ifp->if_ioctl = uti596_ioctl;
  ifp->if_init  = uti596_init;
  ifp->if_start    = uti596_start;
  ifp->if_output   = ether_output;
 
  sc->scb.command = 0;
 
  /*
   * Attach the interface
   */
  if_attach (ifp);
  ether_ifattach (ifp);
  return 1;
 
 }
 
 
 /***********************************************************************
  *  Function:   uti596DynamicInterruptHandler
  *
  *  Description:
  *             This is the interrupt handler for the uti596 board
  *
  *  Algorithm:
  *
  ***********************************************************************/
 
 /* static */ rtems_isr uti596DynamicInterruptHandler(rtems_vector_number irq)
 {
#ifdef DEBUG_ISR
 printk("I");
#endif
 
 UTI_WAIT_COMMAND_ACCEPTED(20000, "****ERROR:on ISR entry");
 
 if ( !(i8259s_cache & 0x20 )) {
   printk("****Error: network ISR running, no IRR!\n");
   printk("****Error: i8259s_cache = 0x%x\n",i8259s_cache );
   printk_time();
 }
 
 scbStatus = uti596_softc.scb.status & 0xf000;
 
 if ( scbStatus ){
   /* acknowledge interrupts */
   /*   printk("***INFO: ACK %x\n", scbStatus);*/
   uti596_softc.scb.command = scbStatus;
   outport_word(CHAN_ATTN, 0);
 
   if( uti596_softc.resetDone ) { 
     /* stack is attached */
     UTI_WAIT_COMMAND_ACCEPTED(20000, "****ERROR:ACK");
   }
   else {
     /*     printk("***INFO: ACK'd w/o processing. status = %x\n", scbStatus); */
     return;
   }
 }
 else {
   printk("\n***ERROR: Spurious interrupt. Resetting...\n");
   uti596_softc.nic_reset = 1;
 }
 
 if ( (scbStatus & SCB_STAT_CX) && !(scbStatus & SCB_STAT_CNA) ){
   printk_time();
   printk("\n*****ERROR: Command Complete, and CNA available: 0x%x\nResetting...", scbStatus);
   uti596_softc.nic_reset = 1;
   return;
 }
 
 if ( !(scbStatus & SCB_STAT_CX) && (scbStatus & SCB_STAT_CNA) ) {
   printk_time();
   printk("\n*****ERROR: CNA, NO CX:0x%x\nResetting...",scbStatus);
   uti596_softc.nic_reset = 1;
   return;
 }
 
 if ( scbStatus & SCB_CUS_SUSPENDED ) {
   printk_time();
   printk("\n*****ERROR: Command unit suspended!:0x%x\nResetting...",scbStatus);
   uti596_softc.nic_reset = 1;
   return;
 }
 
 if ( scbStatus & RU_SUSPENDED  ) {
   printk_time();
   printk("\n*****ERROR: Receive unit suspended!:0x%x\nResetting...",scbStatus);
   uti596_softc.nic_reset = 1;
   return;
 }
 
 if ( scbStatus & SCB_STAT_RNR ) {
   printk_time();
   printk("\n*****WARNING: RNR %x\n",scbStatus);
   printk("*****INFO: RFD cmd: %x status:%x\n",
	  uti596_softc.pBeginRFA -> cmd,
	  uti596_softc.pBeginRFA -> stat);
 }
 
 /* 
  * Receive Unit Control
  */
 if ( scbStatus & SCB_STAT_FR ) { /* a frame has been received */
   uti596_softc.rxInterrupts++;
 
#ifdef DBG_FR
   printk("\nISR:FR\n");
#endif
   if ( uti596_softc.pBeginRFA == I596_NULL ||  !( uti596_softc.pBeginRFA -> stat & STAT_C)){
     dump_scb();
     uti596_softc.nic_reset = 1;
   }
   else
     while ( uti596_softc.pBeginRFA != I596_NULL && 
	     ( uti596_softc.pBeginRFA -> stat & STAT_C)) {
 
#ifdef DBG_ISR
       printk("ISR:pBeginRFA != NULL\n");
#endif
       count_rx ++;
       if ( count_rx > 1)
	 printk("****WARNING: Received 2 frames on 1 interrupt \n");
 
       /* 
	* Give Received Frame to the ULCS 
	*/	
       uti596_softc.countRFD--;
 
       if ( uti596_softc.countRFD < 0 )
	 printk("Count < 0 !!!: count == %d, beginRFA = %p\n",
		uti596_softc.countRFD, uti596_softc.pBeginRFA);
 
       uti596_softc.stats.rx_packets++;
       pIsrRfd = uti596_softc.pBeginRFA -> next; /* the append destroys the link */
       uti596append( &uti596_softc.pInboundFrameQueue , uti596_softc.pBeginRFA );
 
       /*
	* if we have just received the a frame int he last unknown RFD,
	* then it is certain that the RFA is empty.
	*/
       if ( uti596_softc.pLastUnkRFD == uti596_softc.pBeginRFA ) {
	 UTI_596_ASSERT(uti596_softc.pLastUnkRFD != I596_NULL,"****ERROR:LastUnk is NULL, begin ptr @ end!\n");
	 uti596_softc.pEndRFA = uti596_softc.pLastUnkRFD = I596_NULL;
       }
 
#ifdef DBG_ISR
       printk("Wake %#x\n",uti596_softc.rxDaemonTid);
#endif
       sc = rtems_event_send(uti596_softc.rxDaemonTid, INTERRUPT_EVENT);
       if ( sc != RTEMS_SUCCESSFUL )
	 rtems_panic ("Can't notify rxDaemon: %s\n", 
		      rtems_status_text (sc)); 
#ifdef DBG_RAW_ISR
       else
	 printk("Rx Wake: %#x\n",uti596_softc.rxDaemonTid);
#endif
 
       uti596_softc.pBeginRFA = pIsrRfd;
     } /* end while */
 
   if ( uti596_softc.pBeginRFA == I596_NULL ){ /* adjust the pEndRFA to reflect an empty list */
     if ( uti596_softc.pLastUnkRFD == I596_NULL && uti596_softc.countRFD != 0 )
       printk("Last Unk is NULL, BeginRFA is null, and count == %d\n",uti596_softc.countRFD);
 
     uti596_softc.pEndRFA = I596_NULL;
     if ( uti596_softc.countRFD != 0 ) {
       printk("****ERROR:Count is %d, but begin ptr is NULL\n",uti596_softc.countRFD );
     }
   }
 
 } /* end scb_stat_fr */
 
 /*
  * Check For Command Complete
  */
 if (  scbStatus & SCB_STAT_CX ){
#ifdef DBG_ISR
   printk("ISR:CU\n");
#endif   
 
   pIsrCmd = uti596_softc.pCmdHead;
 
   /* 
    * For ALL completed commands
    */
   if ( pIsrCmd !=  I596_NULL && pIsrCmd->status & STAT_C  ){
 
#ifdef DBG_RAW_ISR
       printk("ISR:pIsrCmd != NULL\n");
#endif
 
     /* 
      * Adjust the command block list 
      */
     uti596_softc.pCmdHead = pIsrCmd -> next;
 
     /*
      * If there are MORE commands to process, 
      * the serialization in the raw routine has failed.
      * ( Perhaps AddCmd is bad? )
      */
     UTI_596_ASSERT(uti596_softc.pCmdHead == I596_NULL,
		    "****ERROR: command serialization failed\n");
     /*
      * What if the command did not complete OK?
      */
     switch ( pIsrCmd->command & 0x7)
       {
       case CmdConfigure:
 
	 /*	 printk("****INFO:Configure OK\n"); */
	 uti596_softc.cmdOk = 1;
	 break;
 
       case CmdDump:
 
#ifdef DBG_ISR
	   printk("dump!\n");
#endif
	 uti596_softc.cmdOk = 1;
	 break;
 
       case CmdDiagnose:
 
#ifdef DBG_ISR
	   printk("diagnose!\n");
#endif
	 uti596_softc.cmdOk = 1;
	 break;
 
       case CmdSASetup:
 
	 /*	 printk("****INFO:Set address interrupt\n");	 */
	 if ( pIsrCmd -> status & STAT_OK )
	   uti596_softc.cmdOk = 1;
	 else
	   printk("****ERROR:SET ADD FAILED\n");
	 break;
 
       case CmdTx:
	 {
	   UTI_596_ASSERT(uti596_softc.txDaemonTid, "****ERROR:Null txDaemonTid\n");
#ifdef DBG_ISR
	   printk("wake TX:0x%x\n",uti596_softc.txDaemonTid);
#endif
	   if ( uti596_softc.txDaemonTid ){  /* Ensure that the transmitter is present */
	     sc = rtems_event_send (uti596_softc.txDaemonTid, 
				    INTERRUPT_EVENT);
 
	   if ( sc != RTEMS_SUCCESSFUL )
	     printk("****ERROR:Could NOT send event to tid 0x%x : %s\n",
		    uti596_softc.txDaemonTid, rtems_status_text (sc) );
#ifdef DBG_RAW_ISR
	   else
	     printk("****INFO:Tx wake: %#x\n",uti596_softc.txDaemonTid);
#endif	   
	   }
	 } /* End case Cmd_Tx */
	 break;
 
       case CmdMulticastList:
 
	 printk("***ERROR:Multicast?!\n");
	 pIsrCmd->next = I596_NULL;
	 break;
 
       case CmdTDR:
	 {
	   unsigned long status = *( (unsigned long *)pIsrCmd)+1;
	   printk("****ERROR:TDR?!\n");
 
	   if (status & STAT_C)
	     {
	       /*
		* mark the TDR command successful
		*/
	       uti596_softc.cmdOk = 1;
	     }
	   else
	     {
	       if (status & 0x4000)
		 printk("****WARNING:Transceiver problem.\n");
	       if (status & 0x2000)
		 printk("****WARNING:Termination problem.\n");
	       if (status & 0x1000)
		 printk("****WARNING:Short circuit.\n");
 
	       /*	       printk("****INFO:Time %ld.\n", status & 0x07ff); */
	     }
	 }
	 break;
 
       default: 
	 /* 
	  * This should never be reached 
	  */
	 printk("CX but NO known command\n");
       } /* end switch */
     pIsrCmd = uti596_softc.pCmdHead; /* next command */ 
     if ( pIsrCmd != I596_NULL )
       printk("****WARNING: more commands in list, but no start to NIC\n");
   } /* end if pIsrCmd != NULL && pIsrCmd->stat & STAT_C  */
   else {
     if ( pIsrCmd != I596_NULL ) { /* The command MAY be NULL from a RESET */
 
       /* Reset the ethernet card, and wake the transmitter (if necessary) */
       printk_time();
       printk("****INFO: Request board reset ( tx )\n");
       uti596_softc.nic_reset = 1;
       if ( uti596_softc.txDaemonTid){  /* Ensure that a transmitter is present */
	 sc = rtems_event_send (uti596_softc.txDaemonTid, 
				INTERRUPT_EVENT);
 
	 if ( sc != RTEMS_SUCCESSFUL )
	   printk("****ERROR:Could NOT send event to tid 0x%x : %s\n",uti596_softc.txDaemonTid, rtems_status_text (sc) );
#ifdef DBG_RAW_ISR
	 else
	   printk("****INFO:Tx wake: %#x\n",uti596_softc.txDaemonTid);
#endif	   
       }
     }
   } 
 }  /* end if command complete */   
 
 
 /* if the receiver has stopped, 
  * check if this is a No Resources scenario, 
  * Try to add more RFD's ( no RBDs are used )
  */
 if ( uti596_softc.started ) {
   if ( scbStatus & SCB_STAT_RNR ){
#ifdef DBG_ISR
     printk("INFO:RNR: status %#x \n", uti596_softc.scb.status );
#endif
     /*
      * THE RECEIVER IS OFF!
      */
     if ( uti596_softc.pLastUnkRFD != I596_NULL  ){ /* We have an unknown RFD, it is not inbound*/ 
       if ( uti596_softc.pLastUnkRFD -> stat & (STAT_C | STAT_B )) /* in use */
	 uti596_softc.pEndRFA = uti596_softc.pLastUnkRFD;      /* update end */
       else {      
	 /* 
	  *  It is NOT in use, and since RNR, we know EL bit of pEndRFA was read!
	  *  So, unlink it from the RFA and move it to the saved queue.
	  *  But pBegin can equal LastUnk!
	  */
 
	   if ( uti596_softc.pEndRFA != I596_NULL ){      /* check added feb24. */
#ifdef DEBUG_RFA
	     if (uti596_softc.pEndRFA -> next != uti596_softc.pLastUnkRFD){
	       printk("***ERROR:UNK: %p not end->next: %p, end: %p\n",
		      uti596_softc.pLastUnkRFD,uti596_softc.pEndRFA -> next,uti596_softc.pEndRFA);
	       printk("***INFO:countRFD now %d\n",	 uti596_softc.countRFD);
	       printk("\n\n");
 
	     }
#endif
	     uti596_softc.pEndRFA -> next = I596_NULL;   /* added feb 16 */
	   }
	 uti596append( &uti596_softc.pSavedRfdQueue, uti596_softc.pLastUnkRFD );
	 uti596_softc.savedCount++;
	 uti596_softc.pEndSavedQueue = uti596_softc.pLastUnkRFD;
	 uti596_softc.countRFD--;                    /* It was not in the RFA */
	 /* 
	  * The Begin pointer CAN advance this far. We must resynch the CPU side
	  * with the chip.
	  */
	 if ( uti596_softc.pBeginRFA == uti596_softc.pLastUnkRFD ) {
#ifdef DEBUG_RFA
	   if ( uti596_softc.countRFD != 0 ) {
	     printk("****INFO:About to set begin to NULL, with count == %d\n", uti596_softc.countRFD );
	     printk("\n\n");
	   }
#endif
	   uti596_softc.pBeginRFA = I596_NULL;
	   UTI_596_ASSERT(uti596_softc.countRFD == 0,"****ERROR:Count must be zero here!\n");
	 }
       }
 
       uti596_softc.pLastUnkRFD = I596_NULL;
 
     } /* end if exists UnkRFD */
 
     /* 
      * Append the saved queue to  the RFA.  
      * Any further RFD's being supplied will be added to
      * this new list.
      */
     if ( uti596_softc.pSavedRfdQueue != I596_NULL ) { /* entries to add */
       if ( uti596_softc.pBeginRFA == I596_NULL ) {    /* add at beginning to list */
#ifdef DEBUG_RFA
	 if(uti596_softc.countRFD != 0) {
	   printk("****ERROR:Begin pointer is NULL, but count == %d\n",uti596_softc.countRFD);
	 }
#endif
	 uti596_softc.pBeginRFA      = uti596_softc.pSavedRfdQueue; 
	 uti596_softc.pEndRFA        = uti596_softc.pEndSavedQueue;
	 uti596_softc.pSavedRfdQueue = uti596_softc.pEndSavedQueue = I596_NULL;  /* Reset the End */
       }
       else {  
#ifdef DEBUG_RFA
	 if ( uti596_softc.countRFD <= 0) {
	   printk("****ERROR:Begin pointer is not NULL, but count == %d\n",uti596_softc.countRFD);
	 }
#endif
	 UTI_596_ASSERT( uti596_softc.pEndRFA != I596_NULL, "****WARNING: END RFA IS NULL\n");
	 UTI_596_ASSERT( uti596_softc.pEndRFA->next == I596_NULL, "****ERROR:END RFA -> next must be NULL\n");
 
	 uti596_softc.pEndRFA->next   = uti596_softc.pSavedRfdQueue; 
	 uti596_softc.pEndRFA->cmd   &= ~CMD_EOL;      /* clear the end of list */ 
	 uti596_softc.pEndRFA         = uti596_softc.pEndSavedQueue;
	 uti596_softc.pSavedRfdQueue  = uti596_softc.pEndSavedQueue = I596_NULL; /* Reset the End */
#ifdef DEBUG_ISR
	 printk("count: %d, saved: %d \n", uti596_softc.countRFD , uti596_softc.savedCount);
#endif
 
       }
       /*       printk("Isr: countRFD = %d\n",uti596_softc.countRFD); */
       uti596_softc.countRFD += uti596_softc.savedCount;
       /* printk("Isr: after countRFD = %d\n",uti596_softc.countRFD); */
       uti596_softc.savedCount = 0;
     }
 
 
#ifdef DBG_596_RFD
     printk("The list starts here %p\n",uti596_softc.pBeginRFA );
#endif
 
     if ( uti596_softc.countRFD > 1) {
       /****REMOVED FEB 18.
	 &&            
	  !( uti596_softc.pBeginRFA -> stat & (STAT_C | STAT_B ))) { 
       *****/
       printk_time();
       printk("****INFO: pBeginRFA -> stat = 0x%x\n",uti596_softc.pBeginRFA -> stat);
       printk("****INFO: pBeginRFA -> cmd = 0x%x\n",uti596_softc.pBeginRFA -> cmd);
       uti596_softc.pBeginRFA -> stat = 0;
       UTI_596_ASSERT(uti596_softc.scb.command == 0, "****ERROR:scb command must be zero\n");
       uti596_softc.scb.pRfd = uti596_softc.pBeginRFA;
       /* start RX here  */
       printk("****INFO: ISR Starting receiver\n"); 
       uti596_softc.scb.command = RX_START; /* should this also be CU start? */
       outport_word(CHAN_ATTN, 0);
    }
     /*****REMOVED FEB 18.
       else {
       printk("****WARNING: Receiver NOT Started -- countRFD = %d\n", uti596_softc.countRFD);
       printk("82596 cmd: 0x%x, status: 0x%x RFA len: %d\n",
	      uti596_softc.scb.command, 
	      uti596_softc.scb.status,
	      uti596_softc.countRFD);
 
       printk("\nRFA: \n");
       for ( pISR_Rfd = uti596_softc.pBeginRFA;
	     pISR_Rfd != I596_NULL;
	     pISR_Rfd = pISR_Rfd->next) 
	 printk("Frame @ %x, status: %x, cmd: %x\n",
		pISR_Rfd, pISR_Rfd->stat, pISR_Rfd->cmd);
 
       printk("\nInbound: \n");
       for ( pISR_Rfd = uti596_softc.pInboundFrameQueue;
	     pISR_Rfd != I596_NULL;
	     pISR_Rfd = pISR_Rfd->next) 
	 printk("Frame @ %x, status: %x, cmd: %x\n",
		pISR_Rfd, pISR_Rfd->stat, pISR_Rfd->cmd);
 
 
       printk("\nSaved: \n");
       for ( pISR_Rfd = uti596_softc.pSavedRfdQueue;
	     pISR_Rfd != I596_NULL;
	     pISR_Rfd = pISR_Rfd->next) 
	 printk("Frame @ %x, status: %x, cmd: %x\n",
		pISR_Rfd, pISR_Rfd->stat, pISR_Rfd->cmd);
       printk("\nUnknown: %p\n",uti596_softc.pLastUnkRFD);
     }
     *****/
   } /* end stat_rnr */	 
 
 } /* end if receiver started */
 /* UTI_596_ASSERT(uti596_softc.scb.status == scbStatus, "****WARNING:scbStatus change!\n"); */
 
#ifdef DBG_ISR
   printk("X\n");
#endif
 count_rx=0;
 
 /*
  * Do this last, to ensure that the reset is called at the right time.
  */
 if ( uti596_softc.nic_reset ){
   uti596_softc.nic_reset = 0;
   sc = rtems_event_send(uti596_softc.resetDaemonTid, NIC_RESET_EVENT);
   if ( sc != RTEMS_SUCCESSFUL )
     rtems_panic ("Can't notify resetDaemon: %s\n", rtems_status_text (sc));
 }
 
 return;
 }
 
 
/***********************************************************************
 *  Function:   void uti596dequeue
 *
 *  Description:
 *              removes an RFD from the received frame queue,
 *
 *  Algorithm:
 *
 ***********************************************************************/
 
struct i596_rfd * uti596dequeue( struct i596_rfd ** ppQ )
 {
   ISR_Level level;
 
   struct i596_rfd * pRfd;
   _ISR_Disable(level);
 
   /* invalid address, or empty queue or emptied queue */
   if( ppQ == NULL || *ppQ == NULL || *ppQ == I596_NULL) {
     _ISR_Enable(level);
     return I596_NULL;
   }
 
     pRfd = *ppQ;            /* The dequeued buffer           */
     *ppQ = pRfd->next;      /* advance the queue pointer     */
     pRfd->next = I596_NULL; /* unlink the rfd being returned */
 
 
   _ISR_Enable(level);
   return pRfd;
}	
 
/***********************************************************************
 *  Function:   void uti596append
 *
 *  Description:
 *              adds an RFD to the end of the received frame queue,
 *              for processing by the rxproc.
 *              Also removes this RFD from the RFA 
 *
 *  Algorithm:
 *
 ***********************************************************************/
 
void uti596append( struct i596_rfd ** ppQ , struct i596_rfd * pRfd ) 
{
 
  struct i596_rfd *p;
 
  if ( pRfd != NULL && pRfd != I596_NULL) {
    pRfd -> next = I596_NULL;
    pRfd -> cmd |= CMD_EOL;    /* set EL bit */
 
    if ( *ppQ == NULL || *ppQ == I596_NULL ) {
      /* Empty or emptied */
      *ppQ = pRfd;
    }
    else
      {
	for ( p=*ppQ; p -> next != I596_NULL; p=p->next)
	  ;
 
	p->cmd &= ~CMD_EOL; /* Clear EL bit at end */
	p->next = pRfd;
      }
  }
  else
    printf("Illegal attempt to append: %p\n", pRfd);
}
 

/***********************************************************************
 *  Function:   uti596stop
 *
 *  Description:
 *             stop the driver
 *
 *  Algorithm:
 *             mark driver as not started,
 *             mark transmitter as busy
 *             abort any transmissions/receptions
 *             clean-up all buffers ( RFD's et. al. )
 *             
 *             
 * 
 *
 ***********************************************************************/
 
 
/* static */ 
void uti596_stop(struct uti596_softc *sc)
{
    sc->started  = 0;
 
#ifdef DBG_596
	printf("%s: Shutting down ethercard, status was %4.4x.\n",
	       uti596_softc.pIface->name, uti596_softc.scb.status);
#endif
 
    printf("Stopping interface\n");
    sc->scb.command = CUC_ABORT|RX_ABORT;
    outport_word( CHAN_ATTN, 0 );
 
}
 
 
static int
uti596_ioctl (struct ifnet *ifp, int command, caddr_t data)
{
	struct uti596_softc *sc = ifp->if_softc;
	int error = 0;
 
	switch (command) {
	case SIOCGIFADDR:
	case SIOCSIFADDR:
	        printk("SIOCSIFADDR\n");
		ether_ioctl (ifp, command, data);
		break;
 
	case SIOCSIFFLAGS:
	        printk("SIOCSIFFLAGS\n");
		switch (ifp->if_flags & (IFF_UP | IFF_RUNNING)) {
		case IFF_RUNNING:
	        printk("IFF_RUNNING\n");
			uti596_stop (sc);
			break;
 
		case IFF_UP:
	        printk("IFF_UP\n");
			uti596_init (sc);
			break;
 
		case IFF_UP | IFF_RUNNING:
	        printk("IFF_UP and RUNNING\n");
			uti596_stop (sc);
			uti596_init (sc);
			break;
 
		default:
	        printk("default\n");
 
			break;
		}
		break;
 
	case SIO_RTEMS_SHOW_STATS:
	        printk("show stats\n");
		uti596_stats (sc);
		break;
 
	/*
	 * FIXME: All sorts of multicast commands need to be added here!
	 */
	default:
	        printk("default: EINVAL\n");
		error = EINVAL;
		break;
	}
	return error;
}
 

/***********************************************************************
 *  Function:   uti596_stats
 *
 *  Description:
 *             print out the collected data
 *
 *  Algorithm:
 *            use printf
 *
 ***********************************************************************/
 
 
void 
uti596_stats(struct uti596_softc *sc)
      {
        printf(" CPU Reports:\n");
	printf ("Tx raw send count:%-8lu",  sc->rawsndcnt);
	printf ("Rx Interrupts:%-8lu",  sc->rxInterrupts);
	printf ("Tx Interrupts:%-8lu\n",  sc->txInterrupts);
	printf ("Rx Packets:%-8u",  sc->stats.rx_packets);
	printf ("Tx Attempts:%-u\n",  sc->stats.tx_packets);
 
	printf ("Rx Dropped:%-8u",     sc->stats.rx_dropped);
	printf ("Rx IP Packets:%-8u",  sc->stats.rx_packets);
	printf ("Tx Errors:%-8u\n",      sc->stats.tx_errors);
	printf ("Tx aborted:%-8u",     sc->stats.tx_aborted_errors);
	printf ("Tx Dropped:%-8u\n",     sc->stats.tx_dropped);
	printf ("Tx IP packets:%-8u",  sc->stats.tx_packets);
 
	printf ("Collisions Detected:%-8u\n",  sc->stats.collisions);
	printf ("Tx Heartbeat Errors:%-8u",  sc->stats.tx_heartbeat_errors);
	printf ("Tx Carrier Errors:%-8u\n",    sc->stats.tx_carrier_errors);
	printf ("Tx Aborted Errors:%-8u",    sc->stats.tx_aborted_errors);
	printf ("Rx Length Errors:%-8u\n",     sc->stats.rx_length_errors);
	printf ("Rx Overrun Errors:%-8u",    sc->stats.rx_over_errors);
	printf ("Rx Fifo Errors:%-8u\n",       sc->stats.rx_fifo_errors);
	printf ("Rx Framing Errors:%-8u",    sc->stats.rx_frame_errors);
	printf ("Rx crc errors:%-8u\n",        sc->stats.rx_crc_errors);
 
	printf ("TX WAITS: %-8lu\n", sc->txRawWait);
 
	printf ("NIC resets: %-8u\n", sc->stats.nic_reset_count);
 
	printf("NIC reports\n");
 
	dump_scb();
      }
 
void dumpQ(void) {
 
  struct i596_rfd *pRfd;
 
	   printf("savedQ:\n");
	   for( pRfd = uti596_softc.pSavedRfdQueue;
		pRfd != I596_NULL;
		pRfd = pRfd -> next) 
	     printf("pRfd: %p, stat: 0x%x cmd: 0x%x\n",pRfd,pRfd -> stat,pRfd -> cmd);
	   printf("Inbound:\n");
	   for( pRfd = uti596_softc.pInboundFrameQueue;
		pRfd != I596_NULL;
		pRfd = pRfd -> next) 
	     printf("pRfd: %p, stat: 0x%x cmd: 0x%x\n",pRfd,pRfd -> stat,pRfd -> cmd);
	    printf("Last Unk: %p\n", uti596_softc.pLastUnkRFD );
 
	   printf("RFA:\n");
	   for( pRfd = uti596_softc.pBeginRFA;
		pRfd != I596_NULL;
		pRfd = pRfd -> next) 
	     printf("pRfd: %p, stat: 0x%x cmd: 0x%x\n",pRfd,pRfd -> stat,pRfd -> cmd);
}
 
void uti596Diagnose(int verbose){
  struct i596_cmd diagnose;
  int count=10000;
 
  diagnose.command = CmdDiagnose;
  diagnose.status = 0;
  uti596addPolledCmd(&diagnose);
  while( !( diagnose.status & STAT_C ) && count ) {
    if(verbose)
      printf(".");
    count --;
  }
  if(verbose)
    printf("Status diagnostic: 0x%2.2x\n", diagnose.status);
 
}
void show_buffers (void) 
{
    struct i596_rfd *pRfd;
 
      printf("82596 cmd: 0x%x, status: 0x%x RFA len: %d\n",
	     uti596_softc.scb.command, 
	     uti596_softc.scb.status,
	     uti596_softc.countRFD);
 
      printf("\nRFA: \n");
      for ( pRfd = uti596_softc.pBeginRFA;
	    pRfd != I596_NULL;
	    pRfd = pRfd->next) 
	printf("Frame @ %p, status: %2.2x, cmd: %2.2x\n",
	       pRfd, pRfd->stat, pRfd->cmd);
 
      printf("\nInbound: \n");
      for ( pRfd = uti596_softc.pInboundFrameQueue;
	    pRfd != I596_NULL;
	    pRfd = pRfd->next) 
	printf("Frame @ %p, status: %2.2x, cmd: %2.2x\n",
	       pRfd, pRfd->stat, pRfd->cmd);
 
 
      printf("\nSaved: \n");
      for ( pRfd = uti596_softc.pSavedRfdQueue;
	    pRfd != I596_NULL;
	    pRfd = pRfd->next) 
	printf("Frame @ %p, status: %2.2x, cmd: %2.2x\n",
	       pRfd, pRfd->stat, pRfd->cmd);
    printf("\nUnknown: %p\n",uti596_softc.pLastUnkRFD);
 
}
void show_queues(void)
{
    struct i596_rfd *pRfd;
 
 
      printf("CMD: 0x%x, Status: 0x%x\n", 
	     uti596_softc.scb.command,
	     uti596_softc.scb.status);
      printf("saved Q\n");
 
      for ( pRfd = uti596_softc.pSavedRfdQueue;
	    pRfd != I596_NULL &&
	      pRfd != NULL;
	    pRfd = pRfd->next)
	printf("0x%p\n", pRfd);
 
      printf("End saved Q 0x%p\n", uti596_softc.pEndSavedQueue);
 
      printf("\nRFA:\n");
      for ( pRfd = uti596_softc.pBeginRFA;
	    pRfd != I596_NULL &&
	      pRfd != NULL;
	    pRfd = pRfd->next)
	printf("0x%p\n", pRfd);
 
      printf("uti596_softc.pEndRFA: %p\n",uti596_softc.pEndRFA);
}
 
 
void uti596_init(void * arg){
 
  struct uti596_softc  *sc = arg;
  struct ifnet *ifp = &sc->arpcom.ac_if;
  rtems_status_code status_code;
 
 
  if (sc->txDaemonTid == 0) {
 
    uti596_initialize_hardware(sc);
 
    /*
     * Start driver tasks
     */
 
    sc->txDaemonTid = rtems_bsdnet_newproc ("UTtx", 2*4096, uti596_txDaemon, sc);
    sc->rxDaemonTid = rtems_bsdnet_newproc ("UTrx", 2*4096, uti596_rxDaemon, sc);
    sc->resetDaemonTid = rtems_bsdnet_newproc ("UTrt", 2*4096, 
					       uti596_resetDaemon, sc);
 
 
#ifdef DBG_INIT
    printf("After attach, status of board = 0x%x\n", sc->scb.status );
#endif
    outport_word(0x380, 0xf); /* reset the LED's */
 
  }
 
  /* 
   * Enable receiver
   */
  UTI_WAIT_COMMAND_ACCEPTED(4000, "init:Before RX_START"); 
  sc->scb.pRfd = sc -> pBeginRFA;
  sc->scb.command = RX_START;
  outport_word(CHAN_ATTN,0 ); 
  UTI_WAIT_COMMAND_ACCEPTED(4000, "init:RX_START"); 
  /*
   * Tell the world that we're running.
   */
  ifp->if_flags |= IFF_RUNNING;
 
}
void dump_scb(void){
  printk("status 0x%x\n",uti596_softc.scb.status);
  printk("command 0x%x\n",uti596_softc.scb.command);
  printk("cmd 0x%x\n",(int)uti596_softc.scb.pCmd);
  printk("rfd 0x%x\n",(int)uti596_softc.scb.pRfd);  
  printk("crc_err 0x%x\n",uti596_softc.scb.crc_err);
  printk("align_err 0x%x\n",uti596_softc.scb.align_err);
  printk("resource_err 0x%x\n",uti596_softc.scb.resource_err );
  printk("over_err 0x%x\n",uti596_softc.scb.over_err);
  printk("rcvdt_err 0x%x\n",uti596_softc.scb.rcvdt_err);
  printk("short_err 0x%x\n",uti596_softc.scb.short_err);
  printk("t_on 0x%x\n",uti596_softc.scb.t_on);
  printk("t_off 0x%x\n",uti596_softc.scb.t_off);
}
 
void printk_time(void){
    rtems_time_of_day tm_struct;
 
    rtems_clock_get(RTEMS_CLOCK_GET_TOD, &tm_struct);
    printk("Current time: %d:%d:%d \n", tm_struct.hour, tm_struct.minute, tm_struct.second);  
}
 

Go to most recent revision | Compare with Previous | Blame | View Log

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.