OpenCores
URL https://opencores.org/ocsvn/openrisc_2011-10-31/openrisc_2011-10-31/trunk

Subversion Repositories openrisc_2011-10-31

[/] [openrisc/] [trunk/] [rtos/] [rtems/] [c/] [src/] [lib/] [libbsp/] [m68k/] [mvme167/] [network/] [network.c] - Rev 30

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

/*  network.c: An 82596 ethernet driver for rtems-bsd.
 *
 *  $Id: network.c,v 1.2 2001-09-27 12:00:20 chris Exp $
 */
 
#define KERNEL
 
/* 
 *  Selectively define to debug the network driver. If you define any of these
 *  you must run with polled console I/O.
 */
 
/* 
#define DBG_ADD_CMD
#define DBG_WAIT
#define DBG_SEND
#define DBG_MEM
#define DBG_SELFTEST_CMD
#define DBG_DUMP_CMD
#define DBG_RESET
#define DBG_ATTACH
#define DBG_START
#define DBG_INIT
#define DBG_STOP
#define DBG_RX
#define DBG_ISR
#define DBG_IOCTL
#define DBG_STAT
#define DBG_PACKETS
*/
 
/*
 * Default number of buffer descriptors and buffer sizes.
 */
#define RX_BUF_COUNT   15
#define TX_BUF_COUNT   4
#define TX_BD_PER_BUF  4
 
#define RBUF_SIZE  1520
 
#define UTI_596_ETH_MIN_SIZE  60
 
/*
 * RTEMS events
 */
#define INTERRUPT_EVENT         RTEMS_EVENT_1
#define START_TRANSMIT_EVENT    RTEMS_EVENT_2
#define NIC_RESET_EVENT         RTEMS_EVENT_3
 
 
#include <bsp.h>
#include <stdio.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"
 
/* If we are running interrupt driven I/O no debug output is printed */
#if CD2401_POLLED_IO == 1
   #define printk(arglist) printk arglist;
#else
   #define printk(arglist)
#endif
 
#define UTI_596_ASSERT( condition, str )  if (!( condition ) ) { printk((str)) }
 
/* Types of PORT commands */
#define UTI596_RESET_PORT_FUNCTION	  	0
#define UTI596_SELFTEST_PORT_FUNCTION 	1
#define UTI596_SCP_PORT_FUNCTION      	2
#define UTI596_DUMP_PORT_FUNCTION     	3
 
/* Types of waiting for commands */
#define UTI596_NO_WAIT  				0
#define UTI596_WAIT_FOR_CU_ACCEPT  		1
#define UTI596_WAIT_FOR_INITIALIZATION  2
#define UTI596_WAIT_FOR_STAT_C 			3
 
/* Device dependent data structure */
static uti596_softc_ uti596_softc;
 
/* Globals */
int count_rx = 0;
static int scbStatus;
static rtems_status_code sc;
static i596_cmd *pIsrCmd;
static i596_rfd *pIsrRfd;
 
/*
 * Initial 596 configuration
 */
char uti596initSetup[] = {
  0x0E,   /* Byte 0: length, prefetch off ( no RBD's ) */
  0xC8,   /* Byte 1: fifo to 8, monitor off */
  0x40,   /* Byte 2: don't save bad frames ( was save= 80, use intel's 40 )*/
  0x2E,   /* Byte 3: No source address insertion, 8 byte preamble */
  0x00,   /* Byte 4: priority and backoff defaults */
  0x60,   /* Byte 5: interframe spacing */
  0x00,   /* Byte 6: slot time LSB */
  0xf2,   /* Byte 7: slot time and retries */
  0x0C,   /* Byte 8: not promisc, enable bcast, tx no crs, crc inserted 32bit, 802.3 framing */
  0x08,   /* Byte 9: collision detect */
  0x40,   /* Byte 10: minimum frame length */
  0xfb,   /* Byte 11: tried C8 same as byte 1 in bits 6-7, else ignored*/
  0x00,   /* Byte 12: disable full duplex */
  0x3f    /* Byte 13: no multi IA, backoff enabled */
};
 
 
/* Local Routines */
 
static unsigned long word_swap ( unsigned long );
static void * malloc_16byte_aligned ( void **, void ** adjusted_pointer, size_t );
RTEMS_INLINE_ROUTINE void uti596_writePortFunction ( void *, unsigned long );
RTEMS_INLINE_ROUTINE void uti596_portReset( void );
static unsigned long uti596_portSelfTest( i596_selftest * );
static int uti596_portDump ( i596_dump_result * );
static int uti596_wait ( uti596_softc_ *, unsigned8 );
static int uti596_issueCA ( uti596_softc_ *, unsigned8 );
static void uti596_addCmd ( i596_cmd * );
static void uti596_addPolledCmd ( i596_cmd * );
static void uti596_CU_dump ( i596_dump_result * );
static void uti596_dump_scb ( void );
static int uti596_setScpAndScb ( uti596_softc_ * );
static int uti596_diagnose ( void );
static int uti596_configure ( uti596_softc_ * );
static int uti596_IAsetup ( uti596_softc_ * );
static int uti596_initTBD ( uti596_softc_ * );
static int uti596_initRFA ( int );
static void uti596_initMem ( uti596_softc_ * );
static void uti596_initialize ( uti596_softc_ * );
static void uti596_initialize_hardware ( uti596_softc_ * );
static void uti596_reset_hardware ( uti596_softc_ *);
static void uti596_reset ( void );
static void uti596_clearListStatus ( i596_rfd * );
static i596_rfd * uti596_dequeue ( i596_rfd ** );
static void uti596_append ( i596_rfd ** , i596_rfd * );
static void uti596_supplyFD ( i596_rfd * );
static void send_packet ( struct ifnet *, struct mbuf * );
 
 
/* Required RTEMS network driver functions and tasks (plus reset daemon) */
 
static void uti596_start ( struct ifnet * );
void uti596_init ( void * );
void uti596_stop ( uti596_softc_ * );
void uti596_txDaemon ( void * );
void uti596_rxDaemon ( void * );
void uti596_resetDaemon( void * );
rtems_isr uti596_DynamicInterruptHandler ( rtems_vector_number );
static int uti596_ioctl ( struct ifnet *, int, caddr_t );
void uti596_stats ( uti596_softc_ * );
 
#ifdef DBG_PACKETS
static void dumpQ( void );
static void show_buffers( void );
static void show_queues( void );
static void print_eth  ( unsigned char * );
static void print_hdr  ( unsigned char * );
static void print_pkt  ( unsigned char * );
static void print_echo ( unsigned char * );
#endif
 
 
 
/*
 *  word_swap
 *
 *  Return a 32 bit value, swapping the upper and lower words first.
 *
 *  Input parameters:
 *    val - 32 bit value to swap
 *
 *  Output parameters: NONE
 *
 *  Return value:
 *    Input value with upper and lower 16-bit words swapped
 */
static unsigned long word_swap(
  unsigned long val
)
{
  return (((val >> 16)&(0x0000ffff)) | ((val << 16)&(0xffff0000)));
}
 
 
/*
 *  malloc_16byte_aligned
 *
 *  Allocate a block of a least nbytes aligned on a 16-byte boundary.
 *  Clients are responsible to store both the real address and the adjusted
 *  address. The real address must be used to free the block.
 *
 *  Input parameters:
 *    real_pointer - pointer to a void * pointer in which to store the starting
 *                   address of the block. Required for free.
 *    adjusted_pointer - pointer to a void * pointer in which to store the
 *                       starting address of the block rounded up to the next
 *                       16 byte boundary.
 *    nbytes - number of bytes of storage requested
 *
 *  Output parameters:
 *    real_pointer - starting address of the block.
 *    adjusted_pointer - starting address of the block rounded up to the next
 *                       16 byte boundary.
 *
 *  Return value:
 *    starting address of the block rounded up to the next 16 byte boundary.
 *    NULL if no storage was allocated.
 */
static void * malloc_16byte_aligned(
  void ** real_pointer,
  void ** adjusted_pointer,
  size_t nbytes
)
{
  *real_pointer = malloc( nbytes + 0xF, 0, M_NOWAIT );
  *adjusted_pointer = (void *)(((unsigned long)*real_pointer + 0xF ) & 0xFFFFFFF0 );
  return *adjusted_pointer;
}
 
 
/*
 *  uti596_scp_alloc
 *
 *  Allocate a new scp, possibly freeing a previously allocated one.
 *
 *  Input parameters:
 *    sc - pointer to the global uti596_softc in which to store pointers
 *         to the newly allocated block.
 *
 *  Output parameters: NONE
 *
 *  Return value:
 *    Pointer to the newly allocated, 16-byte aligned scp.
 */
static i596_scp * uti596_scp_alloc(
  uti596_softc_ * sc
)
{
  if( sc->base_scp != NULL ) {
    #ifdef DBG_MEM
    printk(("uti596_scp_alloc: Already have an SCP at %p\n", sc->base_scp))
    #endif
    return sc->pScp;
  }
 
  /* allocate enough memory for the Scp block to be aligned on 16 byte boundary */
  malloc_16byte_aligned( (void *)&(sc->base_scp), (void *)&(sc->pScp), sizeof( i596_scp ) );
 
  #ifdef DBG_MEM
  printk(("uti596_scp_alloc: Scp base address is %p\n", sc->base_scp))
  printk(("uti596_scp_alloc: Scp aligned address is : %p\n",sc->pScp))
  #endif
 
  return sc->pScp;
}
 
 
/*
 *  uti596_writePortFunction
 *  
 *  Write the command into the PORT.
 *  
 *  Input parameters:
 *    addr - 16-byte aligned address to write into the PORT.
 *    cmd - 4-bit cmd to write into the PORT
 *
 *  Output parameters: NONE
 *
 *  Return value: NONE
 *    
 *  The Motorola manual swapped the high and low registers.
 */
RTEMS_INLINE_ROUTINE void uti596_writePortFunction(
  void * addr,
  unsigned long cmd
)
{
  i82596->port_lower = (unsigned short)(((unsigned long)addr & 0xFFF0) | cmd);
  i82596->port_upper = (unsigned short)(((unsigned long)addr >> 16 ) & 0xFFFF);
}
 
 
/*
 *  uti596_portReset
 * 
 *  Issue a port Reset to the uti596
 * 
 *  Input parameters: NONE
 *
 *  Output parameters: NONE
 *
 *  Return value: NONE
 */
RTEMS_INLINE_ROUTINE void uti596_portReset( void )
{
  uti596_writePortFunction( NULL, UTI596_RESET_PORT_FUNCTION );
}
 
 
/*
 *  uti596_portSelfTest
 *
 *  Perform a self-test. Wait for up to 1 second for the test to
 *  complete. Normally, the test should complete in a very short time,
 *  so busy waiting is not  an issue.
 *
 *  Input parameters:
 *    stp - pointer to a 16-byte aligned uti596_selftest structure.
 *
 *  Output parameters: NONE
 *
 *  Return value:
 *    32-bit result field if successful, -1 otherwise.
 */
static unsigned long uti596_portSelfTest(
  i596_selftest * stp
)
{
  rtems_interval ticks_per_second, start_ticks, end_ticks;
 
  stp->results = 0xFFFFFFFF;
  uti596_writePortFunction( stp, UTI596_SELFTEST_PORT_FUNCTION );
 
  rtems_clock_get(RTEMS_CLOCK_GET_TICKS_PER_SECOND, &ticks_per_second);
	rtems_clock_get(RTEMS_CLOCK_GET_TICKS_SINCE_BOOT, &start_ticks);
	end_ticks = start_ticks + ticks_per_second;	
 
  do {
    if( stp->results != 0xFFFFFFFF )
      break;
		else
			rtems_clock_get(RTEMS_CLOCK_GET_TICKS_SINCE_BOOT, &start_ticks);
	} while (start_ticks <= end_ticks);
 
  if (start_ticks > end_ticks ) {
    #ifdef DBG_SELFTEST_CMD
    printk(("uti596_selftest: Timed out\n" ))
		#endif
		return -1;
  }
  else {
    #ifdef DBG_SELFTEST_CMD
    printk(("uti596_selftest: Succeeded with signature = 0x%08x, result = 0x%08x\n",
      			 stp->signature,
             stp->results))
		#endif
		return stp->results;
	}
}
 
 
/*
 *  uti596_portDump
 *
 *  Perform a dump Wait for up to 1 second for the test to
 *  complete. Normally, the test should complete in a very short time,
 *  so busy waiting is not an issue.
 *
 *  Input parameters:
 *    dp - pointer to a 16-byte aligned uti596_dump structure.
 *
 *  Output parameters: NONE
 *
 *  Return value:
 *    16-bit dump_status field if successful, -1 otherwise.
 */
static int uti596_portDump(
  i596_dump_result * dp
)
{
  rtems_interval ticks_per_second, start_ticks, end_ticks;
 
  dp->dump_status = 0;
  uti596_writePortFunction( dp, UTI596_DUMP_PORT_FUNCTION );
 
  rtems_clock_get(RTEMS_CLOCK_GET_TICKS_PER_SECOND, &ticks_per_second);
	rtems_clock_get(RTEMS_CLOCK_GET_TICKS_SINCE_BOOT, &start_ticks);
	end_ticks = start_ticks + ticks_per_second;	
 
  do {
    if( dp->dump_status != 0xA006 )
      break;
		else
			rtems_clock_get(RTEMS_CLOCK_GET_TICKS_SINCE_BOOT, &start_ticks);
	} while (start_ticks <= end_ticks);
 
  if (start_ticks > end_ticks ) {
    #ifdef DBG_DUMP_CMD
    printk(("uti596_dump: Timed out with dump at 0x%08x\n", (unsigned long)dp ))
		#endif
		return -1;
  }
  else {
    #ifdef DBG_DUMP_CMD
    printk(("uti596_dump: Succeeded with dump at = 0x%08x\n", (unsigned long)dp ))
		#endif
		return dp->dump_status;
	}
}
 
 
/*
 *  uti596_wait
 *
 *  Wait for a certain condition.
 *  
 *  Input parameters:
 *    sc - pointer to the uti596_softc struct
 *    wait_type - UTI596_NO_WAIT
 *                UTI596_WAIT_FOR_CU_ACCEPT
 *                UTI596_WAIT_FOR_INITIALIZATION
 *                UTI596_WAIT_FOR_STAT_C
 *
 *  Output parameters: NONE
 *
 *  Return value:
 *    0 if successful, -1 otherwise.
 */
static int uti596_wait(
  uti596_softc_ *sc,
  unsigned8 waitType
)
{
  rtems_interval ticks_per_second, start_ticks, end_ticks;
 
  switch( waitType ) {
    case UTI596_NO_WAIT:
      return 0;
 
    case UTI596_WAIT_FOR_CU_ACCEPT:
      rtems_clock_get(RTEMS_CLOCK_GET_TICKS_PER_SECOND, &ticks_per_second);
		  rtems_clock_get(RTEMS_CLOCK_GET_TICKS_SINCE_BOOT, &start_ticks);
		  end_ticks = start_ticks + ticks_per_second;
 
		  do {
			  if (sc->scb.command == 0)
				  break;
			  else
				  rtems_clock_get(RTEMS_CLOCK_GET_TICKS_SINCE_BOOT, &start_ticks);
 
		  } while (start_ticks <= end_ticks);
 
		  if( (sc->scb.command != 0) || (start_ticks > end_ticks) ) {
			  printf("i82596 timed out with status %x, cmd %x.\n",
               sc->scb.status,  sc->scb.command);
        return -1;
      }
      else
        return 0;
 
    case UTI596_WAIT_FOR_INITIALIZATION:
      rtems_clock_get(RTEMS_CLOCK_GET_TICKS_PER_SECOND, &ticks_per_second);
		  rtems_clock_get(RTEMS_CLOCK_GET_TICKS_SINCE_BOOT, &start_ticks);
		  end_ticks = start_ticks + ticks_per_second;
 
		  do {
		    if( !sc->iscp.busy )
		      break;
				else
					rtems_clock_get(RTEMS_CLOCK_GET_TICKS_SINCE_BOOT, &start_ticks);
			} while (start_ticks <= end_ticks);
 
		  if (start_ticks > end_ticks ) {
		    #ifdef DBG_WAIT
		    printk(("uti596_setScpAndScb: Timed out\n"  ))
				#endif
				return -1;
		  }
		  else {
		    #ifdef DBG_WAIT
		    printk(("uti596_setScpAndScb: Succeeded\n" ))
				#endif
				return 0;
			}
 
	 case UTI596_WAIT_FOR_STAT_C:
	   rtems_clock_get(RTEMS_CLOCK_GET_TICKS_PER_SECOND, &ticks_per_second);
		 rtems_clock_get(RTEMS_CLOCK_GET_TICKS_SINCE_BOOT, &start_ticks);
		 end_ticks = start_ticks + ticks_per_second;
 
		 do {
		   if( *sc->pCurrent_command_status & STAT_C )
		      break;
			 else
					rtems_clock_get(RTEMS_CLOCK_GET_TICKS_SINCE_BOOT, &start_ticks);
			} while (start_ticks <= end_ticks);
 
		  if (start_ticks > end_ticks ) {
		    #ifdef DBG_WAIT
		    printk(("uti596_initMem: timed out - STAT_C not obtained\n"  ))
				#endif
				return -1;
		  }
		  else {
		    #ifdef DBG_WAIT
		    printk(("uti596_initMem: STAT_C obtained OK\n" ))
				#endif
				return 0;
			}
	 }
	 return -1;
}
 
 
/*
 *  uti596_issueCA
 *
 *  Issue a Channel Attention command. Possibly wait for the
 *  command to start or complete.
 *  
 *  Input parameters:
 *    sc - pointer to the uti596_softc
 *    wait_type - UTI596_NO_WAIT
 *                UTI596_WAIT_BEGIN
 *                UTI596_WAIT_COMPLETION
 *
 *  Output parameters: NONE
 *
 *  Return value:
 *    0 if successful, -1 otherwise.
 */
static int uti596_issueCA(
  uti596_softc_ *sc,
  unsigned8 waitType
)
{
  /* Issue Channel Attention */
  i82596->chan_attn = 0x00000000;
 
  return (uti596_wait ( sc, waitType ));
}
 
 
/*
 *  uti596_addCmd
 * 
 *  Add a uti596_cmd onto the end of the CBL command chain,
 *  	or to the start if the chain is empty.
 * 
 *  Input parameters:
 *  	pCmd - a pointer to the command to be added.
 *
 *  Output parameters: NONE 
 *
 *  Return value: NONE
 */
static void uti596_addCmd(
  i596_cmd *pCmd
)
{
  ISR_Level level;
 
	#ifdef DBG_ADD_CMD
  printk(("uti596_addCmd: Adding command 0x%x\n", pCmd -> command ))
	#endif
 
  /* Mark command as last in list, to return an interrupt */
  pCmd->command |= (CMD_EOL | CMD_INTR );
  pCmd->status = 0;
  pCmd->next = I596_NULL;
 
  _ISR_Disable(level);
 
  if (uti596_softc.pCmdHead == I596_NULL) {
    uti596_softc.pCmdHead = uti596_softc.pCmdTail = uti596_softc.scb.pCmd = pCmd;
    uti596_softc.scb.cmd_pointer = word_swap ((unsigned long)pCmd);
 
		uti596_wait ( &uti596_softc, UTI596_WAIT_FOR_CU_ACCEPT );
		uti596_softc.scb.command = CUC_START;
  	uti596_issueCA ( &uti596_softc, UTI596_NO_WAIT );
 
  	_ISR_Enable(level);
  }
  else {
    uti596_softc.pCmdTail->next = (i596_cmd *) word_swap ((unsigned long)pCmd);
    uti596_softc.pCmdTail = pCmd;
    _ISR_Enable(level);
	}
 
	#ifdef DBG_ADD_CMD
  printk(("uti596_addCmd: Scb status & command 0x%x 0x%x\n",
           uti596_softc.scb.status,
           uti596_softc.scb.command ))
	#endif
}
 
 
/*
 *  uti596_addPolledCmd
 * 
 *  Add a single uti596_cmd to the end of the command block list
 *  for processing, send a CU_START and wait for its acceptance
 * 
 *  Input parameters:
 *  	sc - a pointer to the uti596_softc struct
 *
 *  Output parameters: NONE
 *
 *  Return value: NONE
 */
void uti596_addPolledCmd(
  i596_cmd *pCmd
)
{
 
	#ifdef DBG_ADD_CMD
  printk(("uti596_addPolledCmd: Adding command 0x%x\n", pCmd -> command ))
	#endif
 
	pCmd->status = 0;
  pCmd->command |=  CMD_EOL ; /* only command in list*/
  pCmd->next = I596_NULL;
 
  uti596_wait ( &uti596_softc, UTI596_WAIT_FOR_CU_ACCEPT );
 
  uti596_softc.pCmdHead = uti596_softc.pCmdTail = uti596_softc.scb.pCmd = pCmd;
  uti596_softc.scb.cmd_pointer = word_swap((unsigned long)pCmd);
  uti596_softc.scb.command = CUC_START;
  uti596_issueCA ( &uti596_softc, UTI596_WAIT_FOR_CU_ACCEPT );
 
  uti596_softc.pCmdHead = uti596_softc.pCmdTail = uti596_softc.scb.pCmd = I596_NULL;
  uti596_softc.scb.cmd_pointer = (unsigned long) I596_NULL;
 
	#ifdef DBG_ADD_CMD
  printk(("uti596_addPolledCmd: Scb status & command 0x%x 0x%x\n",
           uti596_softc.scb.status,
           uti596_softc.scb.command ))
	#endif
}
 
 
/*
 *  uti596_CU_dump
 * 
 *  Dump the LANC 82596 registers
 *  	The outcome is the same as the portDump() but executed
 *  	via the CU instead of via a PORT access.
 * 
 *  Input parameters:
 *  	drp - a pointer to a i596_dump_result structure.
 *
 *  Output parameters: NONE
 *
 *  Return value: NONE
 */
static void uti596_CU_dump ( i596_dump_result * drp)
{
  i596_dump dumpCmd;
 
  dumpCmd.cmd.command = CmdDump;
  dumpCmd.cmd.next    = I596_NULL;
  dumpCmd.pData       = (char *) drp;
  uti596_softc.cmdOk  = 0;
  uti596_addCmd ( (i596_cmd *) &dumpCmd );
 
}
 
 
/*
 *  uti596_dump_scb
 * 
 *  Dump the system control block
 *  This function expands to nothing when using interrupt driven I/O
 * 
 *  Input parameters: NONE
 *
 *  Output parameters: NONE
 *
 *  Return value: NONE
 */
static void uti596_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))
}
 
 
/*
 *  uti596_setScpAndScb
 *
 *  Issue the first channel attention after reset and wait for the busy
 *  field to clear in the iscp.
 *
 *  Input parameters:
 *    sc - pointer to the global uti596_softc
 *
 *  Output parameters: NONE
 *
 *  Return value:
 *    0 if successful, -1 otherwise.
 */
static int uti596_setScpAndScb(
  uti596_softc_ * sc
)
{
  /* set the busy flag in the iscp */
  sc->iscp.busy = 1;
 
  /* the command block list (CBL) is empty */
  sc->scb.command = 0;
  sc->scb.cmd_pointer = (unsigned long) I596_NULL;	/* all 1's */
  sc->pCmdHead = sc->scb.pCmd = I596_NULL;			    /* all 1's */
 
  uti596_writePortFunction( sc->pScp, UTI596_SCP_PORT_FUNCTION );
 
  /* Issue CA: pass the scb address to the 596 */
  return ( uti596_issueCA ( sc, UTI596_WAIT_FOR_INITIALIZATION ) );
}
 
 
/*
 *  uti596_diagnose
 * 
 *  Send a diagnose command to the CU
 * 
 *  Input parameters: NONE
 *
 *  Output parameters: NONE
 *
 *  Return value:
 *  	0 if successful, -1 otherwise
 */
static int uti596_diagnose( void )
{
  i596_cmd diagnose;
 
  diagnose.command = CmdDiagnose;
  diagnose.status = 0;
  uti596_softc.pCurrent_command_status = &diagnose.status;
  uti596_addPolledCmd(&diagnose);
  return (uti596_wait ( &uti596_softc, UTI596_WAIT_FOR_STAT_C ));
 
	#ifdef DBG_INIT
  printk(("Status diagnostic: 0xa000 is a success ... 0x%2.2x\n", diagnose.status))
	#endif
}
 
 
/*
 *  uti596_configure
 * 
 *  Send the CU a configure command with the desired
 *  configuration structure
 * 
 *  Input parameters:
 *  	sc - a pointer to the uti596_softc struct
 *
 *  Output parameters: NONE
 *
 *  Return value:
 *  	0 if successful, -1 otherwise
 */
static int uti596_configure ( 
	uti596_softc_ * sc
)
{
  sc->set_conf.cmd.command = CmdConfigure;
  memcpy (sc->set_conf.data, uti596initSetup, 14);
  uti596_addPolledCmd( (i596_cmd *) &sc->set_conf);
 
  /* Poll for successful command completion */
  sc->pCurrent_command_status = &(sc->set_conf.cmd.status);
  return ( uti596_wait ( sc, UTI596_WAIT_FOR_STAT_C ) );
}
 
 
/*
 *  uti596_IAsetup
 * 
 *  Send the CU an Individual Address setup command with
 *  the ethernet hardware address
 * 
 *  Input parameters:
 *  	sc - a pointer to the uti596_softc struct
 *
 *  Output parameters: NONE
 *
 *  Return value:
 *  	0 if successful, -1 otherwise
 */
static int uti596_IAsetup (
	uti596_softc_ * sc
)
{
	int i;
 
  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;
  uti596_addPolledCmd((i596_cmd *)&sc->set_add);
 
  /* Poll for successful command completion */
  sc->pCurrent_command_status = &(sc->set_add.cmd.status);
  return ( uti596_wait ( sc, UTI596_WAIT_FOR_STAT_C ) );
}
 
 
/*
 *  uti596_initTBD
 * 
 *  Initialize transmit buffer descriptors
 *    dynamically allocate mem for the number of tbd's required
 * 
 *  Input parameters:
 *  	sc - a pointer to the uti596_softc struct
 *
 *  Output parameters: NONE
 *
 *  Return value:
 *  	0 if successful, -1 otherwise
 */
static int uti596_initTBD ( uti596_softc_ * sc )
{
	int i;
  i596_tbd *pTbd, *pPrev;
 
  /* Set up a transmit command with a tbd ready */
  sc->pLastUnkRFD = I596_NULL;
  sc->pTxCmd = (i596_tx *) calloc (1,sizeof (struct i596_tx) );
  sc->pTbd = (i596_tbd *) calloc (1,sizeof (struct i596_tbd) );
  if ((sc->pTxCmd == NULL) || (sc->pTbd == NULL)) {
  	return -1;
	}
  sc->pTxCmd->pTbd = (i596_tbd *) word_swap ((unsigned long) sc->pTbd);
  sc->pTxCmd->cmd.command = CMD_FLEX|CmdTx;
  sc->pTxCmd->pad = 0;
  sc->pTxCmd->count = 0; /* all bytes are in list of TBD's */
 
  pPrev = pTbd = sc->pTbd;
 
  /* Allocate a linked list of tbd's each with it's 'next' field written
   * with upper and lower words swapped (for big endian), and mark the end.
   */
  for ( i=0; i<sc->txBdCount; i++) {
    if ( (pTbd = (i596_tbd *) calloc (1,sizeof (struct i596_tbd) )) == NULL ) {
      return -1;
    }
    pPrev->next = (i596_tbd *) word_swap ((unsigned long) pTbd);
    pPrev = pTbd;
  }
  pTbd->next = I596_NULL;
  return 0;
}
 
 
/*
 *  uti596_initRFA
 * 
 *  Initialize the Receive Frame Area
 *    dynamically allocate mem for the number of rfd's required
 * 
 *  Input parameters:
 *  	sc - a pointer to the uti596_softc struct
 *
 *  Output parameters: NONE
 *
 *  Return value:
 *  	# of buffer descriptors successfully allocated
 */
static int uti596_initRFA( int num )
{
  i596_rfd *pRfd;
  int i = 0;
 
	#ifdef DBG_INIT
  printk(("uti596_initRFA: begins\n   Requested frame descriptors ... %d.\n", num))
	#endif
 
  /*
   * Create the first RFD in the RFA
   */
  pRfd = (i596_rfd *) calloc (1, sizeof (struct i596_rfd));
  if ( !pRfd ) {
    printk(("Can't allocate first buffer.\n"))
    return 0;
  }
  else {
    uti596_softc.countRFD = 1;
    uti596_softc.pBeginRFA = uti596_softc.pEndRFA = pRfd;
  }
 
  /* Create remaining RFDs */
  for (i = 1; i < num; i++) {
    pRfd = (i596_rfd *) calloc (1, sizeof (struct i596_rfd) );
    if ( pRfd != NULL ) {
      uti596_softc.countRFD++;                          /* update count */
      uti596_softc.pEndRFA->next = 
        (i596_rfd *) word_swap ((unsigned long) pRfd);  /* write the link */
      uti596_softc.pEndRFA = pRfd;   										/* move the end */
    }
    else {
      printk(("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_INIT
  printk (("uti596_initRFA: Head of RFA is buffer %p \n\
            uti596_initRFA: End of RFA is buffer %p \n",
            uti596_softc.pBeginRFA, uti596_softc.pEndRFA ))
	#endif
 
  /* Walk and initialize the RFD's */
  for ( pRfd = uti596_softc.pBeginRFA;
        pRfd != I596_NULL;
        pRfd = (i596_rfd *) word_swap ((unsigned long)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 ) */
  } /* end for */
 
  /* mark the last RFD as the last one in the RDL */
  uti596_softc.pEndRFA -> cmd = CMD_EOL;
  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 */
}
 
 
/*
 *  uti596_initMem
 * 
 *  Initialize the 82596 memory structures for Tx and Rx
 *    dynamically allocate mem for the number of tbd's required
 * 
 *  Input parameters:
 *  	sc - a pointer to the uti596_softc struct
 *
 *  Output parameters: NONE
 *
 *  Return value: NONE
 */
void uti596_initMem(
  uti596_softc_ * sc
)
{
  int i;
 
  #ifdef DBG_INIT
  printk(("uti596_initMem: begins\n"))
  #endif
 
  sc->resetDone = 0;
 
  /*
   * Set up receive frame area (RFA)
   */
  i = uti596_initRFA( sc->rxBdCount );
  if ( i < sc->rxBdCount ) {
    printk(("init_rfd: only able to allocate %d receive frame descriptors\n", i))
  }
 
  /*
   * Write the SCB with a pointer to the receive frame area
   * and keep a pointer for our use.
   */
  sc->scb.rfd_pointer = word_swap((unsigned long)sc->pBeginRFA);
  sc->scb.pRfd =  sc->pBeginRFA;
 
  /*
   * Diagnose the health of the board
   */
  uti596_diagnose();
 
  /*
   * Configure the 82596
   */
  uti596_configure( sc );
 
  /*
   * Set up the Individual (hardware) Address
   */
  uti596_IAsetup ( sc );
 
	/*
	 * Initialize the transmit buffer descriptors
	 */
  uti596_initTBD( sc );
 
  /* Padding used to fill short tx frames */
  memset ( &sc->zeroes, 0, 64);
 
  /* now need ISR  */
  sc->resetDone = 1;
}
 
/*
 *  uti596_initialize
 *
 *  Reset the 82596 and initialize it with a new SCP.
 *  
 *  Input parameters:
 *    sc - pointer to the uti596_softc
 *
 *  Output parameters: NONE
 *
 *  Return value: NONE
 */
void uti596_initialize(
  uti596_softc_ *sc
)
{
  /* Reset the device. Stops it from doing whatever it might be doing.  */
  uti596_portReset();
 
  /* Get a new System Configuration Pointer */
  uti596_scp_alloc( sc );
 
  /* write the SYSBUS: interrupt pin active high, LOCK disabled,
   * internal triggering, linear mode
   */
  sc->pScp->sysbus = 0x54;
 
  /* provide the iscp to the scp, keep a pointer for our use */
  sc->pScp->iscp_pointer = word_swap((unsigned long)&sc->iscp);
  sc->pScp->iscp = &sc->iscp;
 
  /* provide the scb to the iscp, keep a pointer for our use */
  sc->iscp.scb_pointer = word_swap((unsigned long)&sc->scb);
  sc->iscp.scb = &sc->scb;
 
  #ifdef DBG_INIT
  printk(("uti596_initialize: Starting i82596.\n"))
  #endif
 
  /* Set up the 82596 */
  uti596_setScpAndScb( sc );
 
  /* clear the scb command word */
  sc->scb.command = 0;
}
 
 
/*
 *  uti596_initialize_hardware
 *
 *  Reset the 82596 and initialize it with a new SCP. Enable bus snooping.
 *  Install the interrupt handlers.
 *  
 *  Input parameters:
 *    sc - pointer to the uti596_softc
 *
 *  Output parameters: NONE
 *
 *  Return value: NONE
 */
void uti596_initialize_hardware(
  uti596_softc_ *sc
)
{
  rtems_isr_entry dummy;
 
  printk(("uti596_initialize_hardware: begins\n"))
 
  /* Get the PCCChip2 to assert bus snooping signals on behalf of the i82596 */
  pccchip2->LANC_berr_ctl	= 0x40;
 
  uti596_initialize( sc );
 
  /*
   * Configure interrupt control in PCCchip2
   */
  pccchip2->LANC_error		= 0xff;		/* clear status register */
  pccchip2->LANC_int_ctl	= 0x5d;		/* lvl 5, enabled, edge-sensitive rising */
  pccchip2->LANC_berr_ctl	= 0x5d;		/* bus error: lvl 5, enabled, snoop control
  								 									 * will supply dirty data and leave dirty data
  								 									 * on read access and sink any data on write
  								 									 */
  /* 
   * Install the interrupt handler
   * calls rtems_interrupt_catch
   */  
  dummy = (rtems_isr_entry) set_vector( uti596_DynamicInterruptHandler, 0x57, 1 );
 
  /* Initialize the 82596 memory */
  uti596_initMem(sc);
 
  #ifdef DBG_INIT
  printk(("uti596_initialize_hardware: After attach, status of board = 0x%x\n", sc->scb.status ))
  #endif
}
 
 
/*
 *  uti596_reset_hardware
 *
 *  Reset the 82596 and initialize it with an SCP.
 *  
 *  Input parameters:
 *    sc - pointer to the uti596_softc
 *
 *  Output parameters: NONE
 *
 *  Return value: NONE
 */
void uti596_reset_hardware(
  uti596_softc_ *sc
)
{
  rtems_status_code status_code;
  i596_cmd *pCmd;
 
  pCmd = sc->pCmdHead;  /* This is a tx command for sure (99.99999%)  */
 
  /* the command block list (CBL) is empty */
  sc->scb.cmd_pointer = (unsigned long) I596_NULL;	/* all 1's */
  sc->pCmdHead = sc->scb.pCmd = I596_NULL;			    /* all 1's */
 
  #ifdef DBG_RESET
  printk(("uti596_reset_hardware\n"))
  #endif
  uti596_initialize( sc );
 
  /*
   * Wake the transmitter if needed.
   */
  if ( sc->txDaemonTid && pCmd != I596_NULL ) {
    printk(("****RESET: wakes transmitter!\n"))
    status_code = rtems_event_send (sc->txDaemonTid,
                           INTERRUPT_EVENT);
 
    if ( status_code != RTEMS_SUCCESSFUL ) {
      printk(("****ERROR:Could NOT send event to tid 0x%x : %s\n",
             sc->txDaemonTid, rtems_status_text (status_code) ))
    }
  }
 
  #ifdef DBG_RESET
  printk(("uti596_reset_hardware: After reset_hardware, status of board = 0x%x\n", sc->scb.status ))
  #endif
}
 
 
/*
 *  uti596_clearListStatus
 * 
 *  Clear the stat fields for all RFDs
 * 
 *  Input parameters:
 *  	pRfd - a pointer to the head of the RFA
 *
 *  Output parameters: NONE 
 *
 *  Return value: NONE
 */
void uti596_clearListStatus(
  i596_rfd *pRfd
)
{
  while ( pRfd != I596_NULL ) {
    pRfd -> stat = 0;
    pRfd = (i596_rfd *) word_swap((unsigned long)pRfd-> next);
  }
}
 
 
/*
 *  uti596_reset
 * 
 *  Reset the 82596 and reconfigure
 * 
 *  Input parameters: NONE
 *
 *  Output parameters: NONE 
 *
 *  Return value: NONE
 */
void uti596_reset( void )
{
  uti596_softc_ *sc = &uti596_softc;
 
	#ifdef DBG_RESET
  printk(("uti596_reset: begin\n"))
	#endif
 
	/* Wait for the CU to be available, then
	 * reset the ethernet hardware. Must re-config.
 	 */
  sc->resetDone = 0;
	uti596_wait ( sc, UTI596_WAIT_FOR_CU_ACCEPT );
  uti596_reset_hardware ( &uti596_softc ); 
 
	#ifdef DBG_RESET
  uti596_diagnose();
	#endif
 
  /*
   * Configure the 82596
   */
  uti596_configure( sc );
 
  /*
   * Set up the Individual (hardware) Address
   */
  uti596_IAsetup ( sc );
 
  sc->pCmdHead = sc->pCmdTail = sc->scb.pCmd = I596_NULL;
 
 
  /* restore the RFA */
 
  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 ;
  }
 
  /* Re-address the head of the RFA in the SCB */
  sc->scb.pRfd =  sc->pBeginRFA; 
  sc->scb.rfd_pointer = word_swap((unsigned long)sc->pBeginRFA);
 
	/* Clear the status of all RFDs */
  uti596_clearListStatus( sc->pBeginRFA );
 
  printk(("uti596_reset: Starting NIC\n"))
 
  /* Start the receiver */
  sc->scb.command = RX_START;
  sc->started = 1;               /* assume that the start is accepted */
  sc->resetDone = 1;
  uti596_issueCA ( sc, UTI596_WAIT_FOR_CU_ACCEPT );
 
  UTI_596_ASSERT(sc->pCmdHead == I596_NULL, "Reset: CMD not cleared\n")
 
	#ifdef DBG_RESET
  printk(("uti596_reset: completed\n"))
	#endif
}
 
 
/*
 *  uti596_dequeue
 * 
 *  Remove an RFD from the received fram queue
 * 
 *  Input parameters:
 *  	ppQ - a pointer to a i596_rfd pointer
 *
 *  Output parameters: NONE 
 *
 *  Return value:
 *  	pRfd - a pointer to the dequeued RFD
 */
i596_rfd * uti596_dequeue(
  i596_rfd ** ppQ
)
{
  ISR_Level level;
  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;
  }
 
	/* 
	 * Point to the dequeued buffer, then
	 * adjust the queue pointer and detach the buffer
	 */
  pRfd = *ppQ;      
  *ppQ = (i596_rfd *) word_swap ((unsigned long) pRfd->next);
  pRfd->next = I596_NULL;  /* unlink the rfd being returned */
 
  _ISR_Enable(level);
  return pRfd;
}
 
 
/*
 *  uti596_append
 * 
 *  Remove an RFD buffer from the RFA and tack it on to
 *  	the received frame queue for processing.
 * 
 *  Input parameters:
 *  	 ppQ - a pointer to the queue pointer
 *  	pRfd - a pointer to the buffer to be returned
 *
 *  Output parameters: NONE 
 *
 *  Return value: NONE
 */ 
 
void uti596_append(
  i596_rfd ** ppQ,
  i596_rfd * pRfd
)
{
 
  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 list */
      *ppQ = pRfd;
    }
    else {
      /* walk to the end of the list */
      for ( p=*ppQ;
            p->next != I596_NULL;
            p=(i596_rfd *) word_swap ((unsigned long)p->next) );
 
      /* append the rfd */
      p->cmd &= ~CMD_EOL;  /* Clear EL bit at end */
      p->next = (i596_rfd *) word_swap ((unsigned long)pRfd);
    }
  }
  else {
    printk(("Illegal attempt to append: %p\n", pRfd))
  }
}
 
 
/*
 *  uti596_supplyFD
 * 
 *  Return a buffer (RFD) to the receive frame area (RFA).
 *  Call with interrupts disabled.
 * 
 *  Input parameters:
 *  	pRfd - a pointer to the buffer to be returned
 *
 *  Output parameters: NONE 
 *
 *  Return value: NONE
 */
void uti596_supplyFD (
  i596_rfd * pRfd
)
{
 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 ) {
 
 	 /* Start a list with 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 ) {
     printk(("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;
 
 /* C = complete, B = busy (prefetched) */
 if ( pLastRfd != I596_NULL && ! (pLastRfd -> stat & ( STAT_C | STAT_B ) )) {
 
   /*
    * Not yet too late to add it
    */
   pLastRfd -> next = (i596_rfd *) word_swap ((unsigned long)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 when 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 ) {
 
       uti596_append(&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 ) {
 
         /* Ensure that beginRFA is not EOL */
         uti596_softc.pBeginRFA -> cmd &= ~CMD_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_MEM
         printk(("uti596_supplyFD: 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.rfd_pointer = word_swap ((unsigned long) uti596_softc.pBeginRFA);
 
         /* Don't ack RNR! The receiver should be stopped in this case */
         uti596_softc.scb.command = RX_START | SCB_STAT_RNR;
 
         UTI_596_ASSERT( !(uti596_softc.scb.status & SCB_STAT_FR),"FRAME RECEIVED INT COMING!\n")
 
         /* send CA signal */
         uti596_issueCA ( &uti596_softc, UTI596_NO_WAIT );
       }
     }
     return;
   }
 }
 else {
   /*
    * too late , pLastRfd in use ( or NULL ),
    * in either case, EL bit has been read, and RNR condition will occur
    */
   uti596_append( &uti596_softc.pSavedRfdQueue, pRfd); /* save it for RNR */
 
   uti596_softc.pEndSavedQueue = pRfd;  /* reset end of saved queue */
   uti596_softc.savedCount++;
 
   return;
 }
}
 
 
/*
 *  send_packet
 * 
 *  Send a raw ethernet packet, add a
 *  	transmit command to the CBL
 * 
 *  Input parameters:
 *  	ifp - a pointer to the ifnet structure
 *  	  m	-	a pointer to the mbuf being sent
 *
 *  Output parameters: NONE 
 *
 *  Return value: NONE
 */
void send_packet(
  struct ifnet *ifp, struct mbuf *m
)
{
  i596_tbd *pPrev = I596_NULL;
  i596_tbd *pRemainingTbdList;
  i596_tbd *pTbd;
  struct mbuf *n, *input_m = m;
  uti596_softc_ *sc = ifp->if_softc;
  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 for each
  */
  pTbd = (i596_tbd*) word_swap ((unsigned long)sc->pTxCmd->pTbd);
 
  do {
    if (m->m_len) {
      /*
       * Fill in the buffer descriptor
       */
      length    += m->m_len;
      pTbd->data = (char *) word_swap ((unsigned long) mtod (m, void *));
      pTbd->size = m->m_len;
      pPrev      = pTbd;
      pTbd       = (i596_tbd *) word_swap ((unsigned long) 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 ) {
    printk(("TX ERROR:Too many mbufs in the packet!!!\n"))
    printk(("Must coalesce!\n"))
  }
 
  if ( length < UTI_596_ETH_MIN_SIZE ) {
    pTbd->data = (char *) word_swap ((unsigned long) sc->zeroes); /* add padding to pTbd */
    pTbd->size = UTI_596_ETH_MIN_SIZE - length; /* zeroes have no effect on the CRC */
  }
  else   /* Don't use pTbd in the send routine */
    pTbd = pPrev;
 
  /*  Disconnect the packet from the list of Tbd's  */
  pRemainingTbdList = (i596_tbd *) word_swap ((unsigned long)pTbd->next);
  pTbd->next  = I596_NULL;
  pTbd->size |= UTI_596_END_OF_FRAME;
 
  sc->rawsndcnt++;
 
	#ifdef DBG_SEND
  printk(("send_packet: sending packet\n"))
	#endif
 
  /* Sending Zero length packet: shouldn't happen */
  if (pTbd->size <= 0) return;
 
	#ifdef DBG_PACKETS
  printk     (("\nsend_packet: Transmitter 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
 
  /* add the command to the output command queue */
  uti596_addCmd ( (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 ) {
    printk(("Could not sleep %s\n", rtems_status_text(status)))
  }
 
	#ifdef DBG_SEND
  printk(("send_packet: RAW - wake\n"))
	#endif
 
  sc->txInterrupts++;
 
  if ( sc->pTxCmd -> cmd.status & STAT_OK ) {
    sc->stats.tx_packets++;
  }
  else {
 
    printk(("*** send_packet: Driver Error 0x%x\n", sc->pTxCmd -> cmd.status ))
 
    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 transmitted buffer descriptor chain.
   */
  pTbd -> next = (i596_tbd *) word_swap ((unsigned long)pRemainingTbdList);
 
  /*
   * Free the mbufs used by the sender.
   */
  m = input_m;
  while ( m != NULL ) {
    MFREE(m,n);
    m = n;
  }
}
 
 
/***********************************************************************
 *  Function:   uti596_attach
 *
 *  Description:
 *              Configure the driver, and connect to the network stack
 *
 *  Algorithm:
 *
 *              Check parameters in the ifconfig structure, and
 *              set driver parameters accordingly.
 *              Initialize required rx and tx buffers.
 *              Link driver data structure onto device list.
 *              Return 1 on successful completion.
 *
 ***********************************************************************/
 
int uti596_attach(
  struct rtems_bsdnet_ifconfig * pConfig
)
{
  uti596_softc_ *sc = &uti596_softc;				/* device dependent data structure */
  struct ifnet * ifp = &sc->arpcom.ac_if;   /* ifnet structure */
 
        int unitNumber;
        char *unitName;
 
	#ifdef DBG_ATTACH
  printk(("uti596_attach: begins\n"))
	#endif
 
  /* The NIC is not started yet */
  sc->started = 0;
 
  /* Indicate to ULCS that this is initialized */
  ifp->if_softc = sc;
  sc->pScp = NULL;
 
        /* Parse driver name */
        if ((unitNumber = rtems_bsdnet_parse_driver_name (pConfig, &unitName)) < 0)
                return 0;
 
  ifp->if_name = unitName;
  ifp->if_unit = unitNumber;
 
  /* Assign mtu */
  if ( pConfig -> mtu )
    ifp->if_mtu = pConfig -> mtu;
  else
    ifp->if_mtu = ETHERMTU;
 
  /* Ethernet address can be specified in the ifconfig structure or
   * it can be read in from BBRAM at $FFFC1F2C (6 bytes)
   * mvme167 manual p. 1-47
   */
  if ( pConfig->hardware_address) {
    memcpy (sc->arpcom.ac_enaddr, pConfig->hardware_address, ETHER_ADDR_LEN);
  }
  else {
    memcpy (sc->arpcom.ac_enaddr, (char *)0xFFFC1F2C, ETHER_ADDR_LEN);
  }
 
  /* 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;
 
  /* Set up fields in the ifnet structure*/
  ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX;
  ifp->if_snd.ifq_maxlen = ifqmaxlen;
        ifp->if_init = uti596_init;
  ifp->if_ioctl = uti596_ioctl;
  ifp->if_start = uti596_start;
  ifp->if_output = ether_output;
 
  /* uti596_softc housekeeping */
  sc->started = 1;
  sc->pInboundFrameQueue = I596_NULL;
  sc->scb.command = 0;
 
  /*
   * Attach the interface
   */
  if_attach (ifp);
  ether_ifattach (ifp);
  return 1;
}
 
/***********************************************************************
 *  Function:  uti596_start
 *
 *  Description:
 *             start the driver
 *
 *  Algorithm:
 *             send an event to the tx task
 *             set the if_flags
 *
 ***********************************************************************/
static void uti596_start(
  struct ifnet *ifp
)
{
  uti596_softc_ *sc = ifp->if_softc;
 
	#ifdef DBG_START
  printk(("uti596_start: begins\n"))
	#endif
 
  rtems_event_send (sc->txDaemonTid, START_TRANSMIT_EVENT);
  ifp->if_flags |= IFF_OACTIVE;
}
 
/***********************************************************************
 *  Function:  uti596_init
 *
 *  Description:
 *             driver initialization
 *
 *  Algorithm:
 *             initialize the 82596
 *             start driver tx and rx tasks, and reset task
 *             send the RX_START command the the RU
 *             set if_flags
 *
 *
 ***********************************************************************/
void uti596_init(
  void * arg
)
{
  uti596_softc_ *sc = arg;
  struct ifnet *ifp = &sc->arpcom.ac_if;
 
  if (sc->txDaemonTid == 0) {
 
    /*
     * Initialize the 82596
     */
		#ifdef DBG_INIT
    printk(("uti596_init: begins\nuti596_init: initializing the 82596...\n"))
		#endif
    uti596_initialize_hardware(sc);
 
    /*
     * Start driver tasks
     */
		#ifdef DBG_INIT
    printk(("uti596_init: starting driver tasks...\n"))
		#endif
    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
    printk(("uti596_init: After attach, status of board = 0x%x\n", sc->scb.status ))
		#endif
  }
 
  /*
   * Enable receiver
   */
		#ifdef DBG_INIT
    printk(("uti596_init: enabling the reciever...\n" ))
		#endif
  sc->scb.command = RX_START;
  uti596_issueCA ( sc, UTI596_WAIT_FOR_CU_ACCEPT );
 
  /*
   * Tell the world that we're running.
   */
  ifp->if_flags |= IFF_RUNNING;
		#ifdef DBG_INIT
    printk(("uti596_init: completed.\n"))
		#endif  
}
 
/***********************************************************************
 *  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(
  uti596_softc_ *sc
)
{
        struct ifnet *ifp = &sc->arpcom.ac_if;
 
        ifp->if_flags &= ~IFF_RUNNING;
  sc->started = 0;
 
		#ifdef DBG_STOP
    printk(("uti596stop: %s: Shutting down ethercard, status was %4.4x.\n",
           uti596_softc.arpcom.ac_if.if_name, uti596_softc.scb.status))
		#endif
 
    printk(("Stopping interface\n"))
    sc->scb.command = CUC_ABORT | RX_ABORT;
    i82596->chan_attn = 0x00000000;
}
 
 
 
/***********************************************************************
 *  Function:   void uti596_txDaemon
 *
 *  Description: Transmit task
 *  
 *  Algorithm: Get mbufs to be transmitted, stuff into RFDs, send
 *  
 ***********************************************************************/
 
void uti596_txDaemon(
  void *arg
)
{
  uti596_softc_ *sc = (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 (;;) {
     /* Get the next mbuf chain to transmit. */
      IF_DEQUEUE(&ifp->if_snd, m);
      if (!m)
        break;
 
      send_packet (ifp, m); /* blocks */
    }
    ifp->if_flags &= ~IFF_OACTIVE; /* no more to send, mark output inactive  */
  }
}
 
/***********************************************************************
 *  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
)
{
  uti596_softc_ *sc = (uti596_softc_ *)arg;
  struct ifnet *ifp = &sc->arpcom.ac_if;
  struct mbuf *m;
 
  i596_rfd *pRfd;
  ISR_Level level;
  int tid;
  rtems_event_set events;
  struct ether_header *eh;
 
  int frames = 0;
 
	#ifdef DBG_RX
  printk(("uti596_rxDaemon: begin\n"))
  printk(("&scb = %p, pRfd = %p\n", &sc->scb,sc->scb.pRfd))
	#endif
 
  rtems_task_ident (0, 0, &tid);
 
  for(;;) {
    /*
     * Wait for packet.
     */
	#ifdef DBG_RX
     printk(("uti596_rxDaemon: Receiver sleeps\n"))
	#endif
 
     rtems_bsdnet_event_receive (INTERRUPT_EVENT,
                                 RTEMS_WAIT|RTEMS_EVENT_ANY,
                                 RTEMS_NO_TIMEOUT,
                                 &events);
 
		 #ifdef DBG_RX
     printk(("uti596_rxDaemon: 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 = uti596_dequeue( &sc->pInboundFrameQueue);
     while ( pRfd &&
             pRfd != I596_NULL &&
             pRfd -> stat & STAT_C )
     {
 
       if ( pRfd->stat & STAT_OK) {    				/* a good frame */
         int pkt_len = pRfd->count & 0x3fff;	/* the actual # of bytes received */
 
				 #ifdef DBG_RX
         printk(("uti596_rxDaemon: 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_PACKETS
				 {
				 	 int i;
         	 printk(("uti596_rxDaemon: mbuf contains:\n"))
         	 print_eth( (char *) (((int)m->m_data)-sizeof(struct ether_header)));
         	 for ( i = 0; i<20; i++) {
 		     	   printk(("."))
	       	 }
         }
				 #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_RX
         printk(("uti596_rxDaemon: 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")
 
       _ISR_Disable(level);
       uti596_supplyFD ( pRfd );   /* Return RFD to RFA. */
       _ISR_Enable(level);
 
       pRfd = uti596_dequeue( &sc->pInboundFrameQueue); /* grab next frame */
 
     } /* end while */
  } /* end for() */
 
	#ifdef DBG_RX
  printk (("uti596_rxDaemon: frames ... %d\n", frames))
	#endif
}
 
 
/***********************************************************************
 *  Function:   void uti596_resetDaemon
 *
 *  Description:
 ***********************************************************************/
void uti596_resetDaemon(
  void *arg
)
{
  uti596_softc_ *sc = (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);
    printk(("reset daemon: Resetting NIC @ %d:%d:%d \n",
           tm_struct.hour, tm_struct.minute, tm_struct.second))
 
    sc->stats.nic_reset_count++;
    /* Reinitialize the LANC */
    rtems_bsdnet_semaphore_obtain ();
    uti596_reset();
    rtems_bsdnet_semaphore_release ();
  }
}
 
 
/***********************************************************************
 *  Function:   uti596_DynamicInterruptHandler
 *
 *  Description:
 *             This is the interrupt handler for the uti596 board
 *
 ***********************************************************************/
 
/* static */ rtems_isr uti596_DynamicInterruptHandler(
  rtems_vector_number irq
)
{
	#ifdef DBG_ISR
  printk(("uti596_DynamicInterruptHandler: begins"))
	#endif
 
 uti596_wait (&uti596_softc, UTI596_WAIT_FOR_CU_ACCEPT);
 
 scbStatus = uti596_softc.scb.status & 0xf000;
 
 if ( scbStatus ) {
   /* acknowledge interrupts */
 
   /* Write to the ICLR bit in the PCCchip2 control registers to clear
    * the INT status bit. Clearing INT here *before* sending the CA signal
    * to the 82596 should ensure that interrupts won't be lost.
    */
    pccchip2->LANC_int_ctl |=0x08;
    pccchip2->LANC_berr_ctl |=0x08;
 
    /* printk(("***INFO: ACK %x\n", scbStatus))*/
 
    /* Send the CA signal to acknowledge interrupt */
    uti596_softc.scb.command = scbStatus;
    uti596_issueCA ( &uti596_softc, UTI596_NO_WAIT );
 
    if( uti596_softc.resetDone ) {
      /* stack is attached */
      uti596_wait ( &uti596_softc, UTI596_WAIT_FOR_CU_ACCEPT );
    }
    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(("\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(("\n*****ERROR: CNA, NO CX:0x%x\nResetting...",scbStatus))
    uti596_softc.nic_reset = 1;
    return;
  }
 
  if ( scbStatus & SCB_CUS_SUSPENDED ) {
    printk(("\n*****ERROR: Command unit suspended!:0x%x\nResetting...",scbStatus))
    uti596_softc.nic_reset = 1;
    return;
  }
 
  if ( scbStatus & RU_SUSPENDED  ) {
    printk(("\n*****ERROR: Receive unit suspended!:0x%x\nResetting...",scbStatus))
    uti596_softc.nic_reset = 1;
    return;
  }
 
  if ( scbStatus & SCB_STAT_RNR ) {
    printk(("\n*****WARNING: RNR %x\n",scbStatus))
    if (uti596_softc.pBeginRFA != I596_NULL) {
        printk(("*****INFO: RFD cmd: %x status:%x\n", uti596_softc.pBeginRFA->cmd,
                                        uti596_softc.pBeginRFA->stat))
    }
    else {
        printk(("*****WARNING: RNR condition with NULL BeginRFA\n"))
    }          
  }
 
 /*
  * Receive Unit Control
  *   a frame is received
  */
  if ( scbStatus & SCB_STAT_FR ) {
    uti596_softc.rxInterrupts++;
 
		#ifdef DBG_ISR
    printk(("uti596_DynamicInterruptHandler: Frame received\n"))
		#endif
    if ( uti596_softc.pBeginRFA == I596_NULL ||
       !( uti596_softc.pBeginRFA -> stat & STAT_C)) {
      uti596_dump_scb();
      uti596_softc.nic_reset = 1;
    }
    else {
      while ( uti596_softc.pBeginRFA != I596_NULL &&
           ( uti596_softc.pBeginRFA -> stat & STAT_C)) {
 
				#ifdef DBG_ISR
        printk(("uti596_DynamicInterruptHandler: 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(("ISR: Count < 0 !!! count == %d, beginRFA = %p\n",
                 uti596_softc.countRFD, uti596_softc.pBeginRFA))
                                }
        uti596_softc.stats.rx_packets++;
        /* the rfd next link is stored with upper and lower words swapped so read it that way */
        pIsrRfd = (i596_rfd *) word_swap ((unsigned long)uti596_softc.pBeginRFA->next);
        /* the append destroys the link */
        uti596_append( &uti596_softc.pInboundFrameQueue , uti596_softc.pBeginRFA );
 
       /*
        * if we have just received the a frame in the 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(("uti596_DynamicInterruptHandler: 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_ISR
        else {
          printk(("uti596_DynamicInterruptHandler: Rx Wake: %#x\n",uti596_softc.rxDaemonTid))
        }
				#endif
 
        uti596_softc.pBeginRFA = pIsrRfd;
      } /* end while */
    } /* end if */
 
    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 if ( scbStatus & SCB_STAT_FR ) */
 
 
 /*
  * Command Unit Control
  *   a command is completed
  */
  if ( scbStatus & SCB_STAT_CX ) {
		#ifdef DBG_ISR
    printk(("uti596_DynamicInterruptHandler: CU\n"))
		#endif
 
    pIsrCmd = uti596_softc.pCmdHead;
 
   /* For ALL completed commands */
   if ( pIsrCmd !=  I596_NULL && pIsrCmd->status & STAT_C  ) {
 
			 #ifdef DBG_ISR
       printk(("uti596_DynamicInterruptHandler: pIsrCmd != NULL\n"))
			 #endif
 
      /* Adjust the command block list */
      uti596_softc.pCmdHead = (i596_cmd *) word_swap ((unsigned long)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:
 
          uti596_softc.cmdOk = 1;
          break;
 
        case CmdDump:
					#ifdef DBG_ISR
          printk(("uti596_DynamicInterruptHandler: dump!\n"))
					#endif
          uti596_softc.cmdOk = 1;
          break;
 
        case CmdDiagnose:
					#ifdef DBG_ISR
          printk(("uti596_DynamicInterruptHandler: 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(("uti596_DynamicInterruptHandler: 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_ISR
            else {
              printk(("****INFO:Tx wake: %#x\n",uti596_softc.txDaemonTid))
            }
						#endif
          }
          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(("****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_ISR
          else {
            printk(("uti596_DynamicInterruptHandler: ****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(("uti596_DynamicInterruptHandler: 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 DBG_ISR
            if ((i596_rfd *)word_swap((unsigned long)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 */
          }
          uti596_append( &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 DBG_ISR
            if ( uti596_softc.countRFD != 0 ) {
              printk(("****INFO:About to set begin to NULL, with count == %d\n\n",
                     uti596_softc.countRFD ))
            }
						#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 DBG_ISR
          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 DBG_ISR
          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   = (i596_rfd *)word_swap((unsigned long)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 DBG_ISR
          printk(("uti596_DynamicInterruptHandler: 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_ISR
      printk(("uti596_DynamicInterruptHandler: The list starts here %p\n",uti596_softc.pBeginRFA ))
			#endif
 
      if ( uti596_softc.countRFD > 1) {
        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;
        uti596_softc.scb.rfd_pointer = word_swap((unsigned long)uti596_softc.pBeginRFA);
        /* start RX here  */
        printk(("****INFO: ISR Starting receiver\n"))
        uti596_softc.scb.command = RX_START; /* should this also be CU start? */
        i82596->chan_attn = 0x00000000;
      }
    } /* end stat_rnr */
  } /* end if receiver started */
 
	#ifdef DBG_ISR
  printk(("uti596_DynamicInterruptHandler: 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:  uti596_ioctl
 *
 *  Description:
 *             driver ioctl function
 *             handles SIOCGIFADDR, SIOCSIFADDR, SIOCSIFFLAGS
 *             
 ***********************************************************************/
 
static int uti596_ioctl(
  struct ifnet *ifp,
  int command, caddr_t data
)
{
  uti596_softc_ *sc = ifp->if_softc;
  int error = 0;
 
	#ifdef DBG_IOCTL
  printk(("uti596_ioctl: begins\n", sc->pScp))
	#endif
 
  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(
  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");
 
	#ifdef DBG_STAT
  uti596_dump_scb();
  #endif
}
 
 
 
 
/************************ PACKET DEBUG ROUTINES ************************/
 
#ifdef DBG_PACKETS
 
/*
 *  dumpQ
 *
 *  Dumps frame queues for debugging
 */
static void dumpQ( void )
{
  i596_rfd *pRfd;
 
  printk(("savedQ:\n"))
 
  for( pRfd = uti596_softc.pSavedRfdQueue;
       pRfd != I596_NULL;
       pRfd = pRfd -> next) {
      printk(("pRfd: %p, stat: 0x%x cmd: 0x%x\n",pRfd,pRfd -> stat,pRfd -> cmd))
  }
 
  printk(("Inbound:\n"))
 
  for( pRfd = uti596_softc.pInboundFrameQueue;
       pRfd != I596_NULL;
       pRfd = pRfd -> next) {
    printk(("pRfd: %p, stat: 0x%x cmd: 0x%x\n",pRfd,pRfd -> stat,pRfd -> cmd))
  }
 
  printk(("Last Unk: %p\n", uti596_softc.pLastUnkRFD ))
  printk(("RFA:\n"))
 
  for( pRfd = uti596_softc.pBeginRFA;
       pRfd != I596_NULL;
       pRfd = pRfd -> next) {
    printk(("pRfd: %p, stat: 0x%x cmd: 0x%x\n",pRfd,pRfd -> stat,pRfd -> cmd))
  }
}
 
 
/*
 *  show_buffers
 *  
 *  Print out the RFA and frame queues
 */
static void show_buffers (void)
{
  i596_rfd *pRfd;
 
  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 ( pRfd = uti596_softc.pBeginRFA;
        pRfd != I596_NULL;
        pRfd = pRfd->next) {
    printk(("Frame @ %p, status: %2.2x, cmd: %2.2x\n",
            pRfd, pRfd->stat, pRfd->cmd))
        }
  printk(("\nInbound: \n"))
 
  for ( pRfd = uti596_softc.pInboundFrameQueue;
        pRfd != I596_NULL;
        pRfd = pRfd->next) {
    printk(("Frame @ %p, status: %2.2x, cmd: %2.2x\n",
            pRfd, pRfd->stat, pRfd->cmd))
        }
 
  printk(("\nSaved: \n"))
 
  for ( pRfd = uti596_softc.pSavedRfdQueue;
        pRfd != I596_NULL;
        pRfd = pRfd->next) {
    printk(("Frame @ %p, status: %2.2x, cmd: %2.2x\n",
             pRfd, pRfd->stat, pRfd->cmd))
  }
 
  printk(("\nUnknown: %p\n",uti596_softc.pLastUnkRFD))
}
 
 
/*
 *  show_queues
 *
 *  Print out the saved frame queue and the RFA
 */
static void show_queues(void)
{
  i596_rfd *pRfd;
 
  printk(("CMD: 0x%x, Status: 0x%x\n",
         uti596_softc.scb.command,
         uti596_softc.scb.status))
  printk(("saved Q\n"))
 
  for ( pRfd = uti596_softc.pSavedRfdQueue;
        pRfd != I596_NULL &&
        pRfd != NULL;
        pRfd = pRfd->next) {
    printk(("0x%p\n", pRfd))
  }
 
  printk(("End saved Q 0x%p\n", uti596_softc.pEndSavedQueue))
 
  printk(("\nRFA:\n"))
 
  for ( pRfd = uti596_softc.pBeginRFA;
        pRfd != I596_NULL &&
        pRfd != NULL;
        pRfd = pRfd->next) {
    printk(("0x%p\n", pRfd))
  }
 
  printk(("uti596_softc.pEndRFA: %p\n",uti596_softc.pEndRFA))
}
 
 
/*
 *  print_eth
 *
 *  Print the contents of an ethernet packet
 *  CANNOT BE CALLED FROM ISR
 */
static void print_eth(
  unsigned char *add
)
{
  int i;
  short int length;
 
  printk (("Packet Location %p\n", add))
  printk (("Dest  "))
 
  for (i = 0; i < 6; i++) {
    printk ((" %2.2X", add[i]))
        }
  printk (("\n"))
  printk (("Source"))
 
  for (i = 6; i < 12; i++) {
        printk ((" %2.2X", add[i]))
  }
 
  printk (("\n"))
  printk (("frame type %2.2X%2.2X\n", add[12], add[13]))
 
  if ( add[12] == 0x08 && add[13] == 0x06 ) { 
    /* an ARP */
    printk (("Hardware type : %2.2X%2.2X\n", add[14],add[15]))
    printk (("Protocol type : %2.2X%2.2X\n", add[16],add[17]))
    printk (("Hardware size : %2.2X\n", add[18]))
    printk (("Protocol size : %2.2X\n", add[19]))
    printk (("op            : %2.2X%2.2X\n", add[20],add[21]))
    printk (("Sender Enet addr: "))
 
    for ( i=0; i< 5 ; i++) {
      printk (("%x:", add[22 + i]))
                }
    printk (("%x\n", add[27]))
    printk (("Sender IP addr: "))
 
    for ( i=0; i< 3 ; i++) {
      printk (("%u.", add[28 + i]))
                }
    printk (("%u\n", add[31]))
    printk (("Target Enet addr: "))
 
    for ( i=0; i< 5 ; i++) {
      printk (( "%x:", add[32 + i]))
                }
    printk (("%x\n", add[37]))
    printk (("Target IP addr: "))
 
    for ( i=0; i< 3 ; i++) {
      printk (( "%u.", add[38 + i]))
    }
    printk (("%u\n", add[41]))
  }
 
 
  if ( add[12] == 0x08 && add[13] == 0x00 ) {
  	/* an IP packet */
    printk (("*********************IP HEADER******************\n"))
    printk (("IP version/IPhdr length: %2.2X TOS: %2.2X\n", add[14] , add[15]))
    printk (("IP total length: %2.2X %2.2X, decimal %d\n", add[16], add[17], length = (add[16]<<8 | add[17] )))
    printk (("IP identification: %2.2X %2.2X, 3-bit flags and offset %2.2X %2.2X\n",
            add[18],add[19], add[20], add[21]))
    printk (("IP TTL: %2.2X, protocol: %2.2X, checksum: %2.2X %2.2X \n",
             add[22],add[23],add[24],add[25]))
    printk (("IP packet type: %2.2X code %2.2X\n", add[34],add[35]))
    printk (("Source IP address: "))
 
    for ( i=0; i< 3 ; i++) {
      printk (("%u.", add[26 + i]))
    }
    printk (("%u\n", add[29]))
    printk (("Destination IP address: "))
 
    for ( i=0; i< 3 ; i++) {
      printk (("%u.", add[30 + i]))
    }
    printk (("%u\n", add[33]))
  }
}
 
 
/*
 *  print_hdr
 *
 *  Print the contents of an ethernet packet header
 *  CANNOT BE CALLED FROM ISR
 */
static  void print_hdr(
  unsigned char *add
)
{
  int i;
 
  printk (("print_hdr: begins\n"))
  printk (("Header Location %p\n", add))
  printk (("Dest  "))
 
  for (i = 0; i < 6; i++) {
    printk ((" %2.2X", add[i]))
        }
  printk (("\nSource"))
 
  for (i = 6; i < 12; i++) {
    printk ((" %2.2X", add[i]))
        }
  printk (("\nframe type %2.2X%2.2X\n", add[12], add[13]))
  printk (("print_hdr: completed"))
}
 
 
/*
 *  Function:   print_pkt
 *
 *  Print the contents of an ethernet packet & data
 *  CANNOT BE CALLED FROM ISR
 */
static void print_pkt(
  unsigned char *add
)
{
  int i;
  short int length;
 
  printk (("print_pkt: begins"))
  printk (("Data Location %p\n", add))
 
  if ( add[0] == 0x08 && add[1] == 0x06 ) {
    /* an ARP */
    printk (("Hardware type : %2.2X%2.2X\n", add[14],add[15]))
    printk (("Protocol type : %2.2X%2.2X\n", add[16],add[17]))
    printk (("Hardware size : %2.2X\n", add[18]))
    printk (("Protocol size : %2.2X\n", add[19]))
    printk (("op            : %2.2X%2.2X\n", add[20],add[21]))
    printk (("Sender Enet addr: "))
 
    for ( i=0; i< 5 ; i++) {
      printk (( "%x:", add[22 + i]))
                }
    printk (("%x\n", add[27]))
    printk (("Sender IP addr: "))
 
    for ( i=0; i< 3 ; i++) {
      printk (("%u.", add[28 + i]))
                }
    printk (("%u\n", add[31]))
    printk (("Target Enet addr: "))
 
    for ( i=0; i< 5 ; i++) {
      printk (( "%x:", add[32 + i]))    
    }
    printk (("%x\n", add[37]))
    printk (("Target IP addr: "))
 
    for ( i=0; i< 3 ; i++) {
      printk (( "%u.", add[38 + i]))
    }
    printk (("%u\n", add[41]))
  }
 
  if ( add[0] == 0x08 && add[1] == 0x00 ) {
    /* an IP packet */
    printk (("*********************IP HEADER******************\n"))
    printk (("IP version/IPhdr length: %2.2X TOS: %2.2X\n", add[14] , add[15]))
    printk (("IP total length: %2.2X %2.2X, decimal %d\n", add[16], add[17], length = (add[16]<<8 | add[17] )))
    printk (("IP identification: %2.2X %2.2X, 3-bit flags and offset %2.2X %2.2X\n",
            add[18],add[19], add[20], add[21]))
    printk (("IP TTL: %2.2X, protocol: %2.2X, checksum: %2.2X %2.2X \n",
            add[22],add[23],add[24],add[25]))
    printk (("IP packet type: %2.2X code %2.2X\n", add[34],add[35]))
    printk (("Source IP address: "))
 
    for ( i=0; i< 3 ; i++) {
      printk(( "%u.", add[26 + i]))
                }
    printk(("%u\n", add[29]))
    printk(("Destination IP address: "))
 
    for ( i=0; i< 3 ; i++) {
      printk(( "%u.", add[30 + i]))
    }
    printk(("%u\n", add[33]))
    printk(("********************IP Packet Data*******************\n"))
    length -=20;
 
    for ( i=0; i < length ; i++) {
      printk(("0x%2.2x ", add[34+i]))
    }
    printk(("\n"))
    printk(("ICMP checksum: %2.2x %2.2x\n", add[36], add[37]))
    printk(("ICMP identifier: %2.2x %2.2x\n", add[38], add[39]))
    printk(("ICMP sequence nbr: %2.2x %2.2x\n", add[40], add[41]))
    printk(("print_pkt: completed"))
  }
}
 
 
/*
 *  print_echo
 *
 *  Print the contents of an echo packet
 *  CANNOT BE CALLED FROM ISR
 */
static void print_echo(
  unsigned char *add
)
{
  int i;
  short int length;
 
  printk (("print_echo: begins"))
 
  if ( add[12] == 0x08 && add[13] == 0x00 ) { 
    /* an IP packet */
    printk (("Packet Location %p\n", add))
    printk (("Dest  "))
 
    for (i = 0; i < 6; i++) {
      printk ((" %2.2X", add[i]))
                }
    printk (("\n"))
    printk (("Source"))
 
    for (i = 6; i < 12; i++) {
      printk ((" %2.2X", add[i]))
                }
    printk (("\n"))
    printk (("frame type %2.2X%2.2X\n", add[12], add[13]))
 
    printk (("*********************IP HEADER******************\n"))
    printk (("IP version/IPhdr length: %2.2X TOS: %2.2X\n", add[14] , add[15]))
    printk (("IP total length: %2.2X %2.2X, decimal %d\n", add[16], add[17], length = (add[16]<<8 | add[17] )))
    printk (("IP identification: %2.2X %2.2X, 3-bit flags and offset %2.2X %2.2X\n",
            add[18],add[19], add[20], add[21]))
    printk (("IP TTL: %2.2X, protocol: %2.2X, checksum: %2.2X %2.2X \n",
            add[22],add[23],add[24],add[25]))
    printk (("IP packet type: %2.2X code %2.2X\n", add[34],add[35]))
    printk (("Source IP address: "))
 
    for ( i=0; i< 3 ; i++) {
      printk (("%u.", add[26 + i]))
                }
    printk (("%u\n", add[29]))
    printk (("Destination IP address: "))
 
    for ( i=0; i< 3 ; i++) {
      printk (("%u.", add[30 + i]))
    }
    printk (("%u\n", add[33]))
    printk(("********************IP Packet Data*******************\n"))
    length -=20;
 
    for ( i=0; i < length ; i++) {
      printk(("0x%2.2x ", add[34+i]))
                }
    printk(("\n"))
    printk(("ICMP checksum: %2.2x %2.2x\n", add[36], add[37]))
    printk(("ICMP identifier: %2.2x %2.2x\n", add[38], add[39]))
    printk(("ICMP sequence nbr: %2.2x %2.2x\n", add[40], add[41]))
    printk(("print_echo: completed"))
  }
}
 
#endif

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.