if_eihk.c
上传用户:luoyougen
上传日期:2008-05-12
资源大小:23136k
文件大小:61k
源码类别:

VxWorks

开发平台:

C/C++

  1. /* if_eihk.c - Intel 82596 Ethernet network interface driver for hkv3500 */
  2. /* Copyright 1989-1997 Wind River Systems, Inc. */
  3. #include "copyright_wrs.h"
  4. /*
  5. modification history
  6. --------------------
  7. 04e,15jul97,spm  added ARP request to SIOCSIFADDR ioctl handler
  8. 04f,30apr97,map  doc update.
  9. 04e,29apr97,map  Modified receive to use RBDs, and buf loaning [SPR# 3511]
  10. 04d,04mar97,dat  fixed watchdog to use netJobAdd, SPR 7771
  11. 04d,07apr97,spm  code cleanup, corrected statistics, and upgraded to BSD 4.4
  12. 04c,13aug96,dat  fixed wdog timer restart. SPR 6958
  13. 04b,12nov94,tmk  removed some IMPORTed function decs and included unixLib.h
  14. 04a,03nov93,caf  derived hkv3500-specific driver from version 03g of if_ei.c.
  15.  changed eiattach() to eihkattach(); changed MAX_RFDS_LOANED
  16.  from 8 to 0; added second parm to sys596Init(); connected
  17.  interrupt to sysSpareInt1() instead of eiInt(); made eiInt()
  18.  global.
  19. 03g,14oct93,wmd  Added initialization of pointer pDrvCtrl in eiWatchDog(),
  20.  SPR #2567.
  21. 03f,30sep93,wmd  Added changes to include timeout check of the receiver 
  22.  as done in the 5.0.6 release. Recreated eiInit() to allow
  23.  resetting the 596 if it locks up.
  24. 03e,11aug93,jmm  Changed ioctl.h and socket.h to sys/ioctl.h and sys/socket.h
  25. 03d,19feb93,jdi  documentation cleanup.
  26. 03c,15jan93,wmd  added setting of errno to S_ioslib_INVALID_ETHERNET_ADDRESS.
  27. 03b,11dec92,rfs  Removed dummy eiChipReset(), no longer needed for TP41.
  28. 03a,05oct92,rfs  Added documentation.
  29. 02z,02oct92,rfs  Made multiple attach calls per unit return OK, not ERROR.
  30. 02y,01oct92,rfs  Added 16 byte page alignment for SCP.
  31. 02x,28sep92,rfs  Modified the eiAction() routine to clear all events.  This
  32.                  makes the diagnostics pass, for some undocumented reason.
  33. 02w,09sep92,gae  documentation tweaks.
  34. 02v,11aug92,rfs  Slight change to memory carving.  Also fixed receive bug
  35.                  that was due to device manual incorrectly describing bit 7
  36.                  of config byte 10 and added error checks to RFDs.  Changed
  37.                  the device startup routine.
  38. 02u,26aug92,kdl  moved internal notes to file header (were just #ifdef'd out).
  39. 02t,19aug92,smb  changed systime.h to sys/times.h
  40. 02s,31jul92,dave Changed to new cacheLib.
  41. 02r,28jul92,rfs  Adapted to latest cache coherency model.
  42.                  Renamed driver control structure and moved it to bss.
  43.                  Combined the init() routine with the attach() routine and
  44.                  made attach() reject multiple invocations.  Rewrote the
  45.                  ioctl() routine to do the right stuff.  Reworked the action
  46.                  command routine and the primary command routine.  Other misc.
  47. 02q,16jul92,rfs  Moved driver specific items from header file to here,
  48.                  where they belong.
  49. 02p,16jul92,rfs  Moved internal comments to end of file, where they belong.
  50. 02o,03jul92,jwt  converted cacheClearEntry() calls to cacheClear() for 5.1.
  51. 02n,26jun92,rrr  make eiBusSnoop global again (needed by bsps)
  52. 02m,25jun92,rfs  backed out last mod; the manual is incorrect about the
  53.                  state of the bit that configures CRC inclusion
  54. 02l,25jun92,rfs  bug fix, changed a receive config parm that selects whether
  55.                  the CRC is included in the buffer
  56. 02k,23jun92,ajm  made eiChipReset global for tp41 BSP
  57. 02j,08jun92,ajm  modified so eiattach is only external function
  58.                  got rid of MEM_ROUND_UP macro now pulled in with vxWorks.h
  59.                  got rid of many ansi complaints
  60. 02i,26may92,rrr  the tree shuffle
  61.                  -changed includes to have absolute path from h/
  62. 02h,22feb92,wmd  added conditional compiles for 040, ansi fixes.
  63. 02g,07jan92,shl  made driver cache safe. added eiBusSnoop(). eliminated some
  64.                  ANSI warnings.
  65. 02f,12nov91,wmd  Added fix, courtesy of jrb-Intel, which added a watchdog to
  66.                  timeout any stalls due to hardware lockup and resets the
  67.                  82596.
  68. 02e,25oct91,rfs  Changed eiChipReset() to not depend on valid *es, and
  69.                  made it global for TP41 usage. Also eliminated ANSI
  70.                  warnings.
  71. 02d,04oct91,rrr  passed through the ansification filter
  72.                  -changed functions to ansi style
  73.                  -changed includes to have absolute path from h/
  74.                  -changed VOID to void
  75.                  -changed copyright notice
  76. 02c,15sep91,rfs  Bug fix. Eliminated lock condition when output queue full
  77.                  and out of TFDs. Added major comment to eiTxStartup. Also,
  78.                  major changes to eiChipReset() to make more robust. All
  79.                  instances of intLock()/intUnlock() changed to
  80.                  sys596IntDisable()/sys596IntEnable respectively. Statistic
  81.                  counters now being used, which required moderate changes to
  82.                  the transmit side design. More comments added.
  83. 02b,21aug91,rfs  changed method of obtaining Ethernet address.
  84. 02a,22jul91,jcf  completely rewritten to utilize simplified mode,
  85.             rfs  added big endian support, reworked buffer loaning.
  86. 01h,01may91,elh  fixed ethernet addressing problem, upgraded to 5.0,
  87.                  added buffer loanouts, fixed ifAddrSet bug by disabling
  88.                  interrupts in eiHardReset.
  89. 01g,28apr91,del  added #define of ETHER_HEADER_SIZE as workaround for
  90.                  gnu960 pading of struct ether_header.
  91. 01f,05jan91,gae  added global eiSCPSysConfig for board specific SCP parameters.
  92.                  moved CDELAY here from if_ei.h and renamed eichkcca.
  93. 01e,03jan91,gae  more cleanup and merged with Intel's fixes.
  94.                  Ethernet address (eiEnetAddr) is set in sysHwInit.
  95.                  cleaned up error printing & no carrier message always printed.
  96.                  changed printf's to printErr's (logMsg if at int level).
  97.                  made most routines local -- not available outside this module.
  98. 01d,31dec90,gae  removed 68K stuff.
  99. 01c,14dec90,elh  more cleanup.
  100. 01b,12dec90,elh  fixed buffer problems, cleaned up, added etherhooks.
  101. 01a,06feb90,djk  written
  102. */
  103. /*
  104. This module implements a hkv3500 specfic Intel 82596 Ethernet network
  105. interface driver.
  106. This driver is derived from the generic if_ei ethernet driver to support
  107. hkv3500 target board. The receive buffer scheme has been modified from a
  108. simplified memory structure to a flexible memory structure so that receive
  109. buffers can be word-aligned, and thus support buffer loaning on a MIPS CPU
  110. architecture.
  111. The driver requires several target-specific parameters, and some external
  112. support routines which are detailed below.
  113. This driver can run with the device configured in either big-endian or
  114. little-endian modes.  Error recovery code has been added to deal with some of
  115. the known errata in the A0 version of the device.  This driver supports up to
  116. four individual units per CPU.
  117. BOARD LAYOUT
  118. This device is on-board.  No jumpering diagram is necessary.
  119. EXTERNAL INTERFACE
  120. This driver provides the standard external interface with the following
  121. exceptions.  All initialization is performed within the attach routine;
  122. there is no separate initialization routine.  Therefore, in the global interface
  123. structure, the function pointer to the initialization routine is NULL.
  124. The only user-callable routine is eihkattach(), which publishes the `ei'
  125. interface and initializes the driver and device.
  126. TARGET-SPECIFIC PARAMETERS
  127. .iP "the <sysbus> value"
  128. This parameter is passed to the driver by eihkattach().
  129. The Intel 82596 requires this parameter during initialization.  This
  130. parameter tells the device about the system bus, hence the name "sysbus."
  131. To determine the correct value for a target, refer to the document
  132. .I "Intel 32-bit Local Area Network (LAN) Component User's Manual."
  133. .iP "interrupt vector"
  134. This parameter is passed to the driver by eihkattach().
  135. The Intel 82596 generates hardware interrupts for various events within
  136. the device; thus it contains an interrupt handler routine.
  137. This driver calls intConnect() to connect its interrupt handler to the 
  138. interrupt vector generated as a result of the 82596 interrupt.
  139. .iP "shared memory address"
  140. This parameter is passed to the driver by eihkattach().
  141. The Intel 82596 device is a DMA type device and typically shares
  142. access to some region of memory with the CPU.  This driver is designed
  143. for systems that directly share memory between the CPU and the 82596.
  144. This parameter can be used to specify an explicit memory region for use
  145. by the 82596.  This should be done on targets that restrict the 82596
  146. to a particular memory region.  The constant NONE can be used to indicate
  147. that there are no memory limitations, in which case, the driver 
  148. attempts to allocate the shared memory from the system space.
  149. .iP "number of Receive and Transmit Frame Descriptors"
  150. These parameters are passed to the driver by eihkattach().
  151. The Intel 82596 accesses frame descriptors in memory for each frame
  152. transmitted or received.  The number of frame descriptors 
  153. at run-time can be configured using these parameters.
  154. .iP "Ethernet address"
  155. This parameter is obtained by a call to an external support routine.
  156. During initialization, the driver needs to know the Ethernet address for
  157. the Intel 82596 device.  The driver calls the external support routine,
  158. sysEnetAddrGet(), to obtain the Ethernet address.  For a description of
  159. sysEnetAddrGet(), see "External Support Requirements" below.
  160. .LP
  161. EXTERNAL SUPPORT REQUIREMENTS
  162. This driver requires seven external support functions:
  163. .iP "STATUS sysEnetAddrGet (int unit, char *pCopy)" "" 9 -1
  164. This routine provides the six-byte Ethernet address
  165. used by <unit>.  It must copy the six-byte address
  166. to the space provided by <pCopy>.  This routine 
  167. returns OK, or ERROR if it fails.  The driver calls this 
  168. routine, once per unit, using eihkattach().
  169. .iP "STATUS sys596Init (int unit, SCB *pScb)"
  170. This routine performs any target-specific initialization
  171. required before the 82596 is initialized.  Typically, it is empty.  
  172. This routine must return OK, or ERROR if it fails.
  173. The driver calls this routine, once per unit, using eihkattach().
  174. .iP "void sys596Port (int unit, int cmd, UINT32 addr)"
  175. This routine provides access to the special port
  176. function of the 82596.  It delivers the command and
  177. address arguments to the port of the specified unit.
  178. The driver calls this routine primarily during
  179. initialization, but may also call it during error
  180. recovery procedures.
  181. .iP "void sys596ChanAtn (int unit)"
  182. This routine provides the channel attention signal to
  183. the 82596, for the specified <unit>.  The driver calls
  184. this routine frequently throughout all phases of
  185. operation.
  186. .iP "void sys596IntEnable (int unit), void sys596IntDisable (int unit)"
  187. These routines enable or disable the interrupt from
  188. the 82596 for the specified <unit>.  Typically, this
  189. involves interrupt controller hardware, either
  190. internal or external to the CPU.  Since the 82596
  191. itself has no mechanism for controlling its interrupt
  192. activity, these routines are vital to the correct
  193. operation of the driver.  The driver calls these
  194. routines throughout normal operation to protect
  195. certain critical sections of code from interrupt
  196. handler intervention.
  197. .iP "void sys596IntAck (int unit)"
  198. This routine must perform any required interrupt acknowledgment 
  199. or clearing.  Typically, this involves an operation to some interrupt
  200. control hardware.  Note that the INT signal from the 82596
  201. behaves in an "edge-triggered" mode; therefore, this routine 
  202. typically clears a latch within the control circuitry.
  203. The driver calls this routine from the interrupt handler.
  204. .LP
  205. SYSTEM RESOURCE USAGE
  206. When implemented, this driver requires the following system resources:
  207.     - one mutual exclusion semaphore
  208.     - one interrupt vector
  209.     - one watchdog timer.
  210.     - 8 bytes in the initialized data section (data)
  211.     - 912 bytes in the uninitialized data section (BSS)
  212. The above data and BSS requirements are for the MC68020 architecture 
  213. and may vary for other architectures.  Code size (text) varies greatly between
  214. architectures and is therefore not quoted here.
  215. The driver uses cacheDmaMalloc() to allocate memory to share with the 82596.  
  216. The fixed-size pieces in this area total 160 bytes.  The variable-size 
  217. pieces in this area are affected by the configuration parameters specified 
  218. in the eihkattach() call.  The size of one RFD (Receive Frame
  219. Descriptor) is 1536 bytes.  The size of one TFD (Transmit Frame Descriptor) 
  220. is 1534 bytes.  For more information about RFDs and TFDs, see the 
  221. .I "Intel 82596 User's Manual."
  222. The 82596 can be operated only if this shared memory region is non-cacheable
  223. or if the hardware implements bus snooping.  The driver cannot maintain
  224. cache coherency for the device because fields within the command
  225. structures are asynchronously modified by both the driver and the device,
  226. and these fields may share the same cache line.
  227. TUNING HINTS
  228. The only adjustable parameters are the number of TFDs and RFDs that will be
  229. created at run-time.  These parameters are given to the driver when eihkattach()
  230. is called.  There is one TFD and one RFD associated with each transmitted
  231. frame and each received frame respectively.  For memory-limited applications,
  232. decreasing the number of TFDs and RFDs may be desirable.  Increasing the number
  233. of TFDs will provide no performance benefit after a certain point.
  234. Increasing the number of RFDs will provide more buffering before packets are
  235. dropped.  This can be useful if there are tasks running at a higher priority
  236. than the net task.
  237. SEE ALSO: ifLib,
  238. .I "Intel 82596 User's Manual,"
  239. .I "Intel 32-bit Local Area Network (LAN) Component User's Manual"
  240. */
  241. #include "vxWorks.h"
  242. #include "wdLib.h"
  243. #include "iv.h"
  244. #include "vme.h"
  245. #include "net/mbuf.h"
  246. #include "net/protosw.h"
  247. #include "sys/socket.h"
  248. #include "sys/ioctl.h"
  249. #include "errno.h"
  250. #include "memLib.h"
  251. #include "intLib.h"
  252. #include "net/if.h"
  253. #include "net/unixLib.h"
  254. #include "net/route.h"
  255. #include "iosLib.h"
  256. #include "errnoLib.h"
  257. #include "cacheLib.h"
  258. #include "logLib.h"
  259. #include "netLib.h"
  260. #include "stdio.h"
  261. #include "stdlib.h"
  262. #include "sysLib.h"
  263. #ifdef  INET
  264. #include "netinet/in.h"
  265. #include "netinet/in_systm.h"
  266. #include "netinet/in_var.h"
  267. #include "netinet/ip.h"
  268. #include "netinet/if_ether.h"
  269. #endif  /* INET */
  270. #include "etherLib.h"
  271. #include "net/systm.h"
  272. #include "sys/times.h"
  273. #include "drv/netif/if_eihk.h"
  274. #include "net/if_subr.h"
  275. /***** LOCAL DEFINITIONS *****/
  276. #undef EI_DEBUG                             /* Compiles debug output */
  277. #define MAX_UNITS       4                   /* maximum units to support */
  278. #define DEF_NUM_TFDS    32                  /* default number of TFDs */
  279. #define DEF_NUM_RFDS    32                  /* default number of RFDs */
  280. #define MAX_RFDS_LOANED 8                   /* max RFDs that can be loaned */
  281. /* Typedefs for external structures that are not typedef'd in their .h files */
  282. typedef struct mbuf MBUF;
  283. typedef struct arpcom IDR;                  /* Interface Data Record wrapper */
  284. typedef struct ifnet IFNET;                 /* real Interface Data Record */
  285. typedef struct sockaddr SOCK;
  286. typedef struct ether_header ETH_HDR;
  287. /* The definition of our linked list management structure */
  288. typedef struct ei_list                       /* EI_LIST - 82596 queue head */
  289.     {
  290.     volatile EI_NODE *  head;       /* header of list */
  291.     volatile EI_NODE *  tail;       /* tail of list */
  292.     } EI_LIST;
  293. /* The definition of the driver control structure */
  294. typedef struct drv_ctrl
  295.     {
  296.     IDR                 idr;        /* interface data record */
  297.     BOOL                attached;   /* indicates attach() called */
  298.     char                *memBase;   /* 82596 memory pool base */
  299.     SCP                 *pScp;      /* SCP ptr */
  300.     ISCP                *pIscp;     /* ISCP ptr */
  301.     SCB                 *pScb;      /* SCB ptr */
  302.     CFD                 *pCfd;      /* synchronous command frame */
  303.     RFD                 *rfdPool;   /* RFD pool */
  304.     TFD                 *tfdPool;   /* TFD pool */
  305.     RFD                 *pFreeRfd;  /* first empty RFD in rxQueue */
  306.     volatile EI_LIST    rxQueue;    /* receive queue */
  307.     volatile EI_LIST    txQueue;    /* to be sent queue */
  308.     volatile EI_LIST    tfdQueue;   /* free transmit frame descriptors */
  309.     volatile EI_LIST    cblQueue;   /* actual chip transmit queue */
  310.     volatile EI_LIST    cleanQueue; /* queue of TFDs to cleanup */
  311.     volatile BOOL       rcvHandling;/* flag, indicates netTask active */
  312.     volatile BOOL       txCleaning; /* flag, indicates netTask active */
  313.     volatile BOOL       txIdle;     /* flag, indicates idle transmitter */
  314.     int                 nTFDs;      /* how many TFDs to create */
  315.     int                 nRFDs;      /* how many RFDs to create */
  316.     int                 nLoanRfds;  /* number of loanable RFDs left */
  317.     UINT8               sysbus;     /* SCP sysbus value */
  318.     int                 ivec;       /* interrupt vector */
  319.     CACHE_FUNCS         cacheFuncs; /* cache descriptor */
  320.     WDOG_ID             wid;        /* watchdog timer for transmit */
  321.     int                 wdInterval; /* ticks between eiWatchDog runs */
  322.     long recvLocks;  /* count for receive lockup failures */
  323.     long                transLocks; /* count for transmit lockup failures */
  324.     volatile char wdTxTimeout;/* watchdog runs with transmit hung */
  325.     volatile char wdRxTimeout;/* watchdog runs with receive hung */
  326.     } DRV_CTRL;
  327. #define DRV_CTRL_SIZ  sizeof(DRV_CTRL)
  328. #define EI_RX_TIMEOUT 3         /* # watchdog runs for receive timeout */
  329. #define EI_TX_TIMEOUT 2         /* # watchdog runs for transmit timeout */
  330. /***** GLOBALS *****/
  331. /* Function declarations not in any header files */
  332. IMPORT void   sysSpareInt1 (int arg); /* hkv3500 specific */
  333. IMPORT STATUS sysEnetAddrGet (int unit, char addr[]);
  334. IMPORT STATUS sys596Init (int unit, SCB *pScb);
  335. IMPORT STATUS sys596IntAck (int unit);
  336. IMPORT STATUS sys596IntEnable (int unit);
  337. IMPORT void   sys596IntDisable (int unit);
  338. IMPORT void   sys596Port (int unit, int cmd, UINT32 addr);
  339. IMPORT void   sys596ChanAtn (int unit);
  340. /***** LOCALS *****/
  341. /* The array of driver control structs */
  342. LOCAL DRV_CTRL drvCtrl [MAX_UNITS];
  343. /* forward function declarations */
  344. static STATUS eiInit (int unit);
  345. static void eiReset (int unit);
  346. static int eiIoctl (IDR *pIDR, int cmd, caddr_t data);
  347. #ifdef BSD43_DRIVER
  348. static int eiOutput (IDR *pIDR, MBUF *pMbuf, SOCK *pDestAddr);
  349. static void eiTxStartup (int unit);
  350. #else
  351. static void eiTxStartup (DRV_CTRL *pDrvCtrl);
  352. #endif
  353. void eiInt (DRV_CTRL *pDrvCtrl);
  354. static void eiTxCleanQ (DRV_CTRL *pDrvCtrl);
  355. static void eiHandleRecvInt (DRV_CTRL *pDrvCtrl);
  356. static STATUS eiReceive (DRV_CTRL *pDrvCtrl, RFD *pRfd);
  357. static void eiLoanFree (DRV_CTRL *pDrvCtrl, RFD *pRfd);
  358. static void eiDiag (int unit);
  359. static void eiConfig (int unit);
  360. static void eiIASetup (int unit);
  361. static void eiRxStartup (DRV_CTRL *pDrvCtrl);
  362. static void eiAction (int unit, UINT16 action);
  363. static STATUS eiCommand (DRV_CTRL *pDrvCtrl, UINT16 cmd);
  364. static void eiTxQPut (DRV_CTRL *pDrvCtrl, TFD *pTfd);
  365. static void eiTxQFlush (DRV_CTRL *pDrvCtrl);
  366. static void eiRxQPut (DRV_CTRL *pDrvCtrl, RFD *pRfd);
  367. static RFD *eiRxQGet (DRV_CTRL *pDrvCtrl);
  368. static BOOL eiRxQFull (DRV_CTRL *pDrvCtrl);
  369. static void eiQInit (EI_LIST *pHead);
  370. static EI_NODE *eiQGet (EI_LIST *pQueue);
  371. static void eiQPut (int unit, EI_LIST *pQueue, EI_NODE *pNode);
  372. static STATUS eiDeviceStart (int unit);
  373. static void eiWatchDog(int unit);
  374. /*******************************************************************************
  375. *
  376. * eihkattach - publish the `ei' network interface and initialize the driver and device
  377. *
  378. * This routine publishes the `ei' interface by filling in a network interface
  379. * record and adding this record to the system list.  This routine also
  380. * initializes the driver and the device to the operational state.
  381. *
  382. * The 82596 shares a region of memory with the driver.  The caller of this
  383. * routine can specify the address of this memory region, or can specify that
  384. * the driver must obtain this memory region from the system resources.
  385. *
  386. * The <sysbus> parameter accepts values as described in the Intel manual
  387. * for the 82596.  A default number of transmit/receive frames of 32 can be
  388. * selected by passing zero in the parameters <nTfds> and <nRfds>.
  389. * In other cases, the number of frames selected should be greater than two.
  390. *
  391. * The <memBase> parameter is used to inform the driver about the shared
  392. * memory region.  If this parameter is set to the constant "NONE," then this
  393. * routine will attempt to allocate the shared memory from the system.  Any
  394. * other value for this parameter is interpreted by this routine as the address
  395. * of the shared memory region to be used.
  396. *
  397. * If the caller provides the shared memory region, then the driver assumes
  398. * that this region does not require cache coherency operations, nor does it
  399. * require conversions between virtual and physical addresses.
  400. *
  401. * If the caller indicates that this routine must allocate the shared memory
  402. * region, then this routine will use cacheDmaMalloc() to obtain
  403. * some  non-cacheable memory.  The attributes of this memory will be checked,
  404. * and if the memory is not both read and write coherent, this routine will
  405. * abort and return ERROR.
  406. *
  407. * RETURNS: OK or ERROR.
  408. *
  409. * SEE ALSO: ifLib,
  410. * .I "Intel 82596 User's Manual"
  411. */
  412. STATUS eihkattach
  413.     (
  414.     int         unit,       /* unit number */
  415.     int         ivec,       /* interrupt vector number */
  416.     UINT8       sysbus,     /* sysbus field of SCP */
  417.     char *      memBase,    /* address of memory pool or NONE */
  418.     int         nTfds,      /* no. of transmit frames (0 = default) */
  419.     int         nRfds       /* no. of receive frames (0 = default) */
  420.     )
  421.     {
  422.     DRV_CTRL    *pDrvCtrl;
  423.     UINT        size;                           /* temporary size holder */
  424.     UINT        sizeScp;
  425.     UINT        sizeIscp;
  426.     UINT        sizeScb;
  427.     UINT        sizeCfd;
  428.     RFD *       pRfd;                   /* pointer to RFD's */
  429.     int         ix;
  430.     static char *errMsg1 = "neihkattach: could not obtain memoryn";
  431.     static char *errMsg2 = "neihkattach: shared memory not cache coherentn";
  432.     sizeScp  = MEM_ROUND_UP (sizeof (SCP));
  433.     sizeIscp = MEM_ROUND_UP (sizeof (ISCP));
  434.     sizeScb  = MEM_ROUND_UP (sizeof (SCB));
  435.     sizeCfd  = MEM_ROUND_UP (sizeof (CFD));
  436.     /* Sanity check the unit number */
  437.     if (unit < 0 || unit >= MAX_UNITS)
  438.         return (ERROR);
  439.     /* Ensure single invocation per system life */
  440.     pDrvCtrl = & drvCtrl [unit];
  441.     if (pDrvCtrl->attached)
  442.         return (OK);
  443.     /* Determine number of Tx and Rx descriptors to use */
  444.     pDrvCtrl->nTFDs = nTfds ? nTfds : DEF_NUM_TFDS;
  445.     pDrvCtrl->nRFDs = nRfds ? nRfds : DEF_NUM_RFDS;
  446.     /* Publish the interface record */
  447. #ifdef BSD43_DRIVER
  448.     ether_attach ( (IFNET *)&pDrvCtrl->idr, unit, "ei", (FUNCPTR)NULL,
  449.                    (FUNCPTR) eiIoctl, (FUNCPTR) eiOutput, (FUNCPTR) eiReset);
  450. #else
  451.     ether_attach ( 
  452.                  &pDrvCtrl->idr.ac_if, 
  453.                  unit, 
  454.                  "ei", 
  455.                  (FUNCPTR) NULL,
  456.                  (FUNCPTR) eiIoctl, 
  457.                  (FUNCPTR) ether_output, 
  458.                  (FUNCPTR) eiReset
  459.                  );
  460.     pDrvCtrl->idr.ac_if.if_start = (FUNCPTR)eiTxStartup;
  461. #endif
  462.     /* calculate the total size of 82596 memory pool */
  463.     size =
  464.             16 +                                /* allow for alignment */
  465.             sizeScp +
  466.             sizeIscp +
  467.             sizeScb +
  468.             sizeCfd +                           /* synch'ed command frame */
  469.             (sizeof (RFD) * pDrvCtrl->nRFDs) +  /* pool of receive frames */
  470.             (sizeof (TFD) * pDrvCtrl->nTFDs);   /* pool of transmit frames */
  471.     /* Establish the memory area that we will share with the device.  If
  472.      * the caller has provided an area, then we assume it is non-cacheable
  473.      * and will not require the use of the special cache routines.
  474.      * If the caller did not provide an area, then we must obtain it from
  475.      * the system, using the cache savvy allocation routine.
  476.      */
  477.     switch ((int) memBase)
  478.         {
  479.         case NONE :                            /* we must obtain it */
  480.             /* this driver can't handle incoherent caches */
  481.             if (!CACHE_DMA_IS_WRITE_COHERENT () ||
  482.                 !CACHE_DMA_IS_READ_COHERENT ())
  483.                 {
  484.                 printf (errMsg2);
  485.                 goto error;
  486.                 }
  487.             pDrvCtrl->memBase = cacheDmaMalloc (size);
  488.             if (pDrvCtrl->memBase == NULL)    /* no memory available */
  489.                 {
  490.                 printf (errMsg1);
  491.                 goto error;
  492.                 }
  493.             pDrvCtrl->cacheFuncs = cacheDmaFuncs;
  494.             break;
  495.         default :                               /* the user provided an area */
  496.             pDrvCtrl->memBase = memBase;        /* use the provided address */
  497.             pDrvCtrl->cacheFuncs = cacheNullFuncs;
  498.             break;
  499.         }
  500.     /* Save other passed-in parameters */
  501.     pDrvCtrl->sysbus = sysbus;                  /* remember sysbus value */
  502.     pDrvCtrl->ivec = ivec;                      /* interrupt vector */
  503.     /* Carve up the shared memory region into the specific sections */
  504.     bzero ((char *) pDrvCtrl->memBase, size);
  505.     pDrvCtrl->pScp  = (SCP *)                /* align to first 16 byte page */
  506.                       ( ((u_long) pDrvCtrl->memBase + 0xf) & ~0xf );
  507.     pDrvCtrl->pIscp = (ISCP *)((int)pDrvCtrl->pScp   + sizeScp);
  508.     pDrvCtrl->pScb  = (SCB *) ((int)pDrvCtrl->pIscp  + sizeIscp);
  509.     pDrvCtrl->pCfd  = (CFD *) ((int)pDrvCtrl->pScb   + sizeScb);
  510.     pDrvCtrl->rfdPool   = (RFD *) ((int)pDrvCtrl->pCfd   + sizeCfd);
  511.     pDrvCtrl->tfdPool = (TFD *)
  512.             ((int)pDrvCtrl->rfdPool+ (sizeof (RFD) * pDrvCtrl->nRFDs));
  513.     for (ix = 0, pRfd = pDrvCtrl->rfdPool; ix < DEF_NUM_RFDS; ix++, pRfd++)
  514.         {
  515.         pRfd->refCnt = 0;                    /* initialize ref cnt */
  516.         }
  517.     /* Init the watchdog that will patrol for device lockups */
  518.  
  519.     pDrvCtrl->transLocks = 0;
  520.     pDrvCtrl->recvLocks = 0;
  521.     pDrvCtrl->wid = wdCreate ();                      /* create watchdog */
  522.     if (pDrvCtrl->wid == NULL)                        /* no resource */
  523.         goto error;
  524.     pDrvCtrl->wdInterval = sysClkRateGet() >> 1;
  525.     /* get our enet addr */
  526.     if (sysEnetAddrGet (unit, (char *)pDrvCtrl->idr.ac_enaddr) == ERROR)
  527. {
  528. errnoSet (S_iosLib_INVALID_ETHERNET_ADDRESS);
  529.         goto error;
  530. }
  531.     /* initialize the unit */
  532.     if (eiInit (unit) == ERROR)
  533.         goto error;
  534.     /* Set our flag */
  535.     pDrvCtrl->attached = TRUE;
  536.     /* Set status flags in IDR */
  537.     pDrvCtrl->idr.ac_if.if_flags |= (IFF_UP | IFF_RUNNING | IFF_NOTRAILERS);
  538.     /* Successful return */
  539.     return (OK);
  540.     /***** Handle error cases *****/
  541.     error:
  542.         {
  543.         /* Release system memory */
  544.         if (((int) memBase == NONE) && ((int) pDrvCtrl->memBase != NULL))
  545.             cacheDmaFree (pDrvCtrl->memBase);
  546.         /* Release watchdog */
  547.         if (pDrvCtrl->wid != NULL)
  548.             wdDelete (pDrvCtrl->wid);
  549.         return (ERROR);
  550.         }
  551.     }
  552. /*******************************************************************************
  553. *
  554. * eiInit - Initialize the interface.
  555. *
  556. * Initialization of interface; clear recorded pending operations.
  557. * Called at boot time and by eiWatchDog() if a reset is required.
  558. *
  559. * RETURNS: OK or ERROR
  560. */
  561. static STATUS eiInit 
  562.     (
  563.     int unit /* unit number */
  564.     )
  565.     {
  566.     DRV_CTRL    *pDrvCtrl = & drvCtrl [unit];
  567.     pDrvCtrl->rcvHandling   = FALSE;  /* netTask not running our receive job */
  568.     pDrvCtrl->txCleaning    = FALSE;  /* netTask not running our clean job */
  569.     pDrvCtrl->txIdle        = TRUE;         /* transmitter idle */
  570.     eiQInit ((EI_LIST *)&pDrvCtrl->rxQueue);    /* to be received queue */
  571.     eiQInit ((EI_LIST *)&pDrvCtrl->txQueue);    /* to be sent queue */
  572.     eiQInit ((EI_LIST *)&pDrvCtrl->tfdQueue);   /* free tfds to add to send q */
  573.     eiQInit ((EI_LIST *)&pDrvCtrl->cblQueue);   /* actively sending queue */
  574.     eiQInit ((EI_LIST *)&pDrvCtrl->cleanQueue); /* queue of TFDs to clean */
  575.     pDrvCtrl->wdTxTimeout = 0;
  576.     pDrvCtrl->wdRxTimeout = 0;
  577.     { /***** Perform device initialization *****/
  578.     /* Block local variables */
  579.     int ix;
  580.     sys596IntDisable (unit);            /* disable device interrupts */
  581.     (void) sys596Init (unit, pDrvCtrl->pScb);  /* do board specific init */
  582.     /* Connect the interrupt handler */
  583.     /* Note: hkv3500 BSP demultiplexes interrupt in sysSpareInt1() */
  584.     if (intConnect ((VOIDFUNCPTR *)INUM_TO_IVEC (pDrvCtrl->ivec),
  585.     sysSpareInt1, (int)pDrvCtrl) == ERROR)
  586.         return (ERROR);
  587.     /* Start the device */
  588.     if ( eiDeviceStart (unit) == ERROR )
  589.         return (ERROR);
  590.     eiDiag (unit);                             /* run diagnostics */
  591.     eiConfig (unit);                           /* configure chip */
  592.     eiIASetup (unit);                          /* setup address */
  593.     for (ix = 0; ix < pDrvCtrl->nTFDs; ix ++)  /* tank up the free tfd queue */
  594.         {
  595.         eiQPut  (
  596.                 unit,
  597.                 (EI_LIST *) & pDrvCtrl->tfdQueue,
  598.                 (EI_NODE *) & pDrvCtrl->tfdPool [ix]
  599.                 );
  600.         }
  601.     pDrvCtrl->pFreeRfd  = NULL;                  /* first free RFD */
  602.     pDrvCtrl->nLoanRfds = MAX_RFDS_LOANED;       /* number of loanable RFD's */
  603.     for (ix = 0; ix < pDrvCtrl->nRFDs; ix ++)   /* tank up the receive queue */
  604. {
  605. if (pDrvCtrl->rfdPool[ix].refCnt == 0)
  606.         eiRxQPut (pDrvCtrl, & pDrvCtrl->rfdPool [ix]);
  607. }
  608.     sys596IntAck (unit);                     /* clear any pended dev ints */
  609.     sys596IntEnable (unit);                  /* enable interrupts at system */
  610.     } /* End block */
  611.     wdCancel(pDrvCtrl->wid);                  /* in case re-initializing */
  612.     wdStart(pDrvCtrl->wid, 
  613.     (int) pDrvCtrl->wdInterval, 
  614.     (FUNCPTR) eiWatchDog, 
  615.     pDrvCtrl->idr.ac_if.if_unit
  616.    );
  617.     return (OK);
  618.     }
  619. /*******************************************************************************
  620. *
  621. * eiReset - reset the ei interface
  622. *
  623. * Mark interface as inactive and reset the chip.
  624. */
  625. static void eiReset
  626.     (
  627.     int unit
  628.     )
  629.     {
  630.     DRV_CTRL *pDrvCtrl;
  631.     pDrvCtrl = & drvCtrl [unit];
  632.     pDrvCtrl->idr.ac_if.if_flags = 0;
  633.     sys596IntDisable (unit);                    /* disable ints from the dev */
  634.     sys596Port (unit, PORT_RESET, NULL);        /* reset the 596 chip */
  635.     }
  636. /*******************************************************************************
  637. *
  638. * eiIoctl - interface ioctl procedure
  639. *
  640. * Process an interface ioctl request.
  641. */
  642. static int eiIoctl
  643.     (
  644.     IDR     *pIDR,
  645.     int     cmd,
  646.     caddr_t data
  647.     )
  648.     {
  649.     int error;
  650. #ifdef EI_DEBUG
  651.     printf ("ei: ioctl: pIDR=%x cmd=%x data=%xn", pIDR, cmd, data);
  652. #endif /* EI_DEBUG */
  653.     error = 0;
  654.     switch (cmd)
  655.         {
  656.         case SIOCSIFADDR:
  657.             ((struct arpcom *)pIDR)->ac_ipaddr = IA_SIN (data)->sin_addr;
  658.             arpwhohas (pIDR, &IA_SIN (data)->sin_addr);
  659.             break;
  660.         case SIOCSIFFLAGS:
  661.             /* Flags are set outside this module. No additional work to do. */
  662.             break;
  663.         default:
  664.             error = EINVAL;
  665.         }
  666.     return (error);
  667.     }
  668. #ifdef BSD43_DRIVER
  669. /*******************************************************************************
  670. *
  671. * eiOutput - interface output routine.
  672. *
  673. * This is the entry point for packets arriving from protocols above.  This
  674. * routine merely calls our specific output routines that eventually lead
  675. * to a transmit to the network.
  676. *
  677. * RETURNS: 0 or appropriate errno
  678. */
  679. static int eiOutput
  680.     (
  681.     IDR *    pIDR,
  682.     MBUF *     pMbuf,
  683.     SOCK * pDestAddr
  684.     )
  685.     {
  686. #ifdef EI_DEBUG
  687.     printf ("ei: output: pIDR=%x pMbuf=%x pDestAddr=%xn",
  688.             pIDR, pMbuf, pDestAddr);
  689. #endif /* EI_DEBUG */
  690.     return (ether_output ((IFNET *)pIDR, pMbuf, pDestAddr,
  691.             (FUNCPTR) eiTxStartup, pIDR));
  692.     }
  693. #endif
  694. /*******************************************************************************
  695. *
  696. * eiTxStartup - start output on the chip
  697. *
  698. * Looks for any action on the queue, and begins output if there is anything
  699. * there.  This routine is called from several possible threads.  Each will be
  700. * described below.
  701. *
  702. * The first, and most common thread, is when a user task requests the
  703. * transmission of data.  Under BSD 4.3, this will cause eiOutput() to be 
  704. * called, which calls ether_output(), which will usually call this routine.
  705. * This routine will not be called if ether_output() finds that our interface 
  706. * output queue is full. In this case, the outgoing data will be thrown out.
  707. * BSD 4.4 uses a slightly different model in which the generic ether_output()
  708. * routine is called directly, followed by a call to this routine.
  709. *
  710. * The second, and most obscure thread, is when the reception of certain
  711. * packets causes an immediate (attempted) response.  For example, ICMP echo
  712. * packets (ping), and ICMP "no listener on that port" notifications.  All
  713. * functions in this driver that handle the reception side are executed in the
  714. * context of netTask().  Always.  So, in the case being discussed, netTask() 
  715. * will receive these certain packets, cause IP to be stimulated, and cause the
  716. * generation of a response to be sent.  We then find ourselves following the
  717. * thread explained in the second example, with the important distinction that
  718. * the context is that of netTask().
  719. *
  720. * The third thread occurs when this routine runs out of TFDs and returns.  If
  721. * this occurs when our output queue is not empty, this routine would typically
  722. * not get called again until new output was requested.  Even worse, if the
  723. * output queue was also full, this routine would never get called again and
  724. * we would have a lock state.  It DOES happen.  To guard against this, the
  725. * transmit clean-up handler detects the out-of-TFDs state and calls this
  726. * function.  The clean-up handler also runs from netTask.
  727. *
  728. * Note that this function is ALWAYS called between an splnet() and an splx().
  729. * This is true because netTask(), and ether_output() take care of
  730. * this when calling this function.  Therefore, no calls to these spl functions
  731. * are needed anywhere in this output thread.
  732. */
  733. #ifdef BSD43_DRIVER
  734. static void eiTxStartup
  735.     (
  736.     int unit
  737.     )
  738.     {
  739.     DRV_CTRL * pDrvCtrl = & drvCtrl [unit];
  740. #else
  741. static void eiTxStartup
  742.     (
  743.     DRV_CTRL *  pDrvCtrl  /* driver control structure */
  744.     )
  745.     {
  746. #endif
  747.     MBUF * pMbuf;
  748.     int length;
  749.     TFD * pTfd;
  750.     /*
  751.      * Loop until there are no more packets ready to send or we
  752.      * have insufficient resources left to send another one.
  753.      */
  754.     while (pDrvCtrl->idr.ac_if.if_snd.ifq_head)
  755.         {
  756.         /* get free tfd */
  757.         pTfd = (TFD *) eiQGet ((EI_LIST *)&pDrvCtrl->tfdQueue);
  758.         if (pTfd == NULL)
  759.             break;                              /* out of TFD's */
  760.         IF_DEQUEUE (&pDrvCtrl->idr.ac_if.if_snd, pMbuf);  /* dequeue a packet */
  761.         copy_from_mbufs ((ETH_HDR *)pTfd->enetHdr, pMbuf, length);
  762.         length = max (ETHERSMALL, length);
  763.         if ((etherOutputHookRtn != NULL) &&
  764.             (* etherOutputHookRtn) (&pDrvCtrl->idr, 
  765.                                     (ETH_HDR *)pTfd->enetHdr, length))
  766.             continue;
  767.         pTfd->count = length & ~0xc000;     /* fill in length */
  768.         eiTxQPut (pDrvCtrl, pTfd);
  769. #ifndef BSD43_DRIVER    /* BSD 4.4 ether_output() doesn't bump statistic. */
  770.         pDrvCtrl->idr.ac_if.if_opackets++;
  771. #endif
  772.         }
  773.     }
  774. /*******************************************************************************
  775. *
  776. * eiInt - entry point for handling interrupts from the 82596
  777. *
  778. * The interrupting events are acknowledged to the device, so that the device
  779. * will deassert its interrupt signal.  The amount of work done here is kept
  780. * to a minimum; the bulk of the work is defered to the netTask.  Several flags
  781. * are used here to synchronize with task level code and eliminate races.
  782. */
  783. void eiInt
  784.     (
  785.     DRV_CTRL *pDrvCtrl
  786.     )
  787.     {
  788.     UINT16  event;
  789.     SCB *pScb;
  790.     int unit;
  791.     pScb = pDrvCtrl->pScb;
  792.     unit = pDrvCtrl->idr.ac_if.if_unit;
  793.     event = pScb->scbStatus & (SCB_S_CX | SCB_S_FR | SCB_S_CNA | SCB_S_RNR);
  794. #ifdef EI_DEBUG
  795.     logMsg ("ei: interrupt: event=%xn", event, 0, 0, 0, 0, 0);
  796. #endif /* EI_DEBUG */
  797.     eiCommand (pDrvCtrl, event);                        /* ack the events */
  798.     sys596IntAck (unit);                                /* ack 596 interrupt */
  799.     /* Handle transmitter interrupt */
  800.     if (event & SCB_S_CNA)                              /* reclaim tx tfds */
  801.         {
  802.         pDrvCtrl->wdTxTimeout = 0;              /* reset timeout count */
  803.         if (pDrvCtrl->cleanQueue.head == NULL)      /* clean queue empty */
  804.             {
  805.             pDrvCtrl->cleanQueue.head = pDrvCtrl->cblQueue.head; /* new head */
  806.             pDrvCtrl->cleanQueue.tail = pDrvCtrl->cblQueue.tail; /* new tail */
  807.             }
  808.         else                                            /* concatenate queues */
  809.             {
  810.             pDrvCtrl->cleanQueue.tail->pNext =
  811.                         (EI_NODE*) pDrvCtrl->cblQueue.head;
  812.             pDrvCtrl->cleanQueue.tail = pDrvCtrl->cblQueue.tail;
  813.             }
  814.         if (!pDrvCtrl->txCleaning)                          /* not cleaning? */
  815.             {
  816.             pDrvCtrl->txCleaning = TRUE;                    /* set flag */
  817.             netJobAdd ((FUNCPTR) eiTxCleanQ, (int) pDrvCtrl, 0, 0, 0, 0);
  818.                             /* defer cleanup */
  819.             }
  820.         if (pDrvCtrl->txQueue.head != NULL)             /* anything to flush? */
  821.             eiTxQFlush (pDrvCtrl);                      /* flush the tx q */
  822.         else
  823.             pDrvCtrl->txIdle = TRUE;                    /* transmitter idle */
  824.         }
  825.     /* Handle receiver interrupt */
  826.     if (event & SCB_S_FR)
  827. {
  828. pDrvCtrl->wdRxTimeout = 0;                  /* reset timeout count */
  829. if (!(pDrvCtrl->rcvHandling))
  830.             {
  831.             pDrvCtrl->rcvHandling = TRUE;
  832.             (void) netJobAdd ((FUNCPTR) eiHandleRecvInt, (int) pDrvCtrl,0, 0, 0, 0);         /* netTask processes */
  833.     }
  834.         }
  835.     }
  836. /*******************************************************************************
  837. *
  838. * eiTxCleanQ - checks errors in completed TFDs and moves TFDs to free queue
  839. *
  840. * This routine is executed by netTask.  It "cleans" the TFDs on the clean-up
  841. * queue by checking each one for errors and then returning the TFD to the
  842. * "free TFD" queue.  The startup routine is sometimes called here to eliminate
  843. * the lock-out case where the driver input queue is full but there are no
  844. * TFDs available.
  845. */
  846. static void eiTxCleanQ
  847.     (
  848.     DRV_CTRL *pDrvCtrl
  849.     )
  850.     {
  851.     TFD *pTfd;
  852.     BOOL needTxStart;
  853.     int unit;
  854.     unit = pDrvCtrl->idr.ac_if.if_unit;
  855.     do
  856.         {
  857.         pDrvCtrl->txCleaning = TRUE;
  858.         if (pDrvCtrl->tfdQueue.head == NULL)              /* tfd queue empty */
  859.             needTxStart = TRUE;                           /* set flag */
  860.         else
  861.             needTxStart = FALSE;
  862.         /* process transmitted frames */
  863.         while (1)
  864.             {
  865.             /* Get TFD. No ints allowed while manipulating this queue. */
  866.             sys596IntDisable (unit);
  867.             pTfd = (TFD*) eiQGet ((EI_LIST *)&pDrvCtrl->cleanQueue);
  868.             sys596IntEnable (unit);
  869.             if (pTfd == NULL)
  870.                 break;
  871.             pDrvCtrl->idr.ac_if.if_collisions +=         /* add any colls */
  872.                 (pTfd->status & CFD_S_RETRY) ? 16 :  /* excessive colls */
  873.                 (pTfd->status & CFD_S_COLL_MASK);    /* some colls */
  874.             if (!(pTfd->status & CFD_S_OK))          /* packet not sent */
  875.                 {
  876.                 pDrvCtrl->idr.ac_if.if_oerrors++;        /* incr err count */
  877.                 pDrvCtrl->idr.ac_if.if_opackets--;       /* decr sent count */
  878.                 }
  879.             /* return to tfdQ */
  880.             eiQPut (unit,(EI_LIST *)&pDrvCtrl->tfdQueue, (EI_NODE*)pTfd);
  881.             }
  882.         if (needTxStart)                                  /* check flag */
  883. #ifdef BSD43_DRIVER
  884.             eiTxStartup (unit);
  885. #else
  886.             eiTxStartup (pDrvCtrl);
  887. #endif
  888.         pDrvCtrl->txCleaning = FALSE;
  889.         }
  890.     while (pDrvCtrl->cleanQueue.head != NULL);            /* check again */
  891.     }
  892. /*******************************************************************************
  893. *
  894. * eiHandleRecvInt - task level interrupt service for input packets
  895. *
  896. * This routine is called at task level indirectly by the interrupt
  897. * service routine to do any message received processing.
  898. */
  899. static void eiHandleRecvInt
  900.     (
  901.     DRV_CTRL *pDrvCtrl
  902.     )
  903.     {
  904.     RFD *pRfd;
  905.     do
  906.         {
  907.         pDrvCtrl->rcvHandling = TRUE;             /* interlock with eiInt() */
  908.         while ((pRfd = eiRxQGet (pDrvCtrl)) != NULL)
  909.             if (eiReceive (pDrvCtrl, pRfd) == OK)
  910.                 eiRxQPut (pDrvCtrl, pRfd);
  911.         pDrvCtrl->rcvHandling = FALSE;            /* interlock with eiInt() */
  912.         }
  913.     while (eiRxQFull (pDrvCtrl));              /* make sure rx q still empty */
  914.     }
  915. /*******************************************************************************
  916. *
  917. * eiReceive - pass a received frame to the next layer up
  918. *
  919. * Strips the Ethernet header and passes the packet to the appropriate
  920. * protocol.  The return value indicates if buffer loaning was used to hold
  921. * the data.  A return value of OK means that loaning was not done, and it
  922. * is therefore 'ok' to return the RFD to the Rx queue.  A return value of ERROR
  923. * means that buffer loaning was employed, and so the RFD is still in use and
  924. * should not be returned to the Rx queue.  In this latter case, the RFD will
  925. * eventually be returned by the protocol, via a call to our eiLoanFree().
  926. */
  927. static STATUS eiReceive
  928.     (
  929.     DRV_CTRL *pDrvCtrl,
  930.     RFD *pRfd
  931.     )
  932.     {
  933.     ETH_HDR *  pEh;
  934.     u_char      *pData;
  935.     int         len;
  936. #ifdef BSD43_DRIVER
  937.     UINT16      etherType;
  938. #endif
  939.     MBUF        *m = NULL;
  940.     BOOL        rfdLoaned = FALSE;
  941.     /* Check packet for errors.  This should be completely unnecessary,
  942.      * but since Intel does not seem capable of explaining the exact
  943.      * functioning of the 'save bad frames' config bit, we will look for
  944.      * errors.
  945.      */
  946.     if  (
  947.         ( pRfd->status & ( RFD_S_OK | RFD_S_COMPLETE ) ) !=
  948.         ( RFD_S_OK | RFD_S_COMPLETE )
  949.         )
  950.         {
  951.         ++pDrvCtrl->idr.ac_if.if_ierrors;            /* bump error counter */
  952.         eiRxQPut (pDrvCtrl, pRfd);                   /* free the RFD */
  953.         return (ERROR);
  954.         }
  955.     /* Bump input packet counter. */
  956.     ++pDrvCtrl->idr.ac_if.if_ipackets;
  957.     len = ((pRfd->actualCnt     & ~0xc000) +
  958.            (pRfd->rbd.actualCnt & ~0xc000));
  959.     pEh = (ETH_HDR *)pRfd->enetHdr;   /* ptr to ethernet header */
  960.     /* Service input hook */
  961.     if ( (etherInputHookRtn != NULL) )
  962.         {
  963.         /* pull enetHdr down 2 bytes to be contiguous with enetData */
  964.         bcopyBytes((char *)pEh, ((char*)pEh+2), EH_SIZE);
  965.         
  966.         if  ( (* etherInputHookRtn) (&pDrvCtrl->idr, ((char *)pEh+2), len) )
  967.             {
  968.             eiRxQPut (pDrvCtrl, pRfd);                  /* free the RFD */
  969.             return (OK);
  970.             }
  971.         }
  972.     len -= EH_SIZE;
  973.     pData = (u_char *) pRfd->enetData;
  974. #ifdef BSD43_DRIVER
  975.     etherType = ntohs (pEh->ether_type);
  976. #endif
  977.     /* we can loan out receive frames from 82596 receive queue if:
  978.      *
  979.      * 1) the threshold of loanable frames has not been exceeded
  980.      * 2) size of the input ethernet frame is large enough to be used with
  981.      *    clustering.
  982.      */
  983.     if ((pDrvCtrl->nLoanRfds > 0) && (USE_CLUSTER (len)) &&
  984.         ((m = build_cluster (pData, len, &pDrvCtrl->idr, MC_EI, &pRfd->refCnt,
  985.                  eiLoanFree, (int) pDrvCtrl, (int) pRfd, NULL)) != NULL))
  986.         {
  987.         pDrvCtrl->nLoanRfds --;             /* one less to loan */
  988.         rfdLoaned = TRUE;               /* we loaned a frame */
  989.         }
  990.     else
  991.         m = copy_to_mbufs (pData, len, 0, &pDrvCtrl->idr);
  992.     if (m != NULL)
  993. #ifdef BSD43_DRIVER
  994.         do_protocol_with_type (etherType, m, &pDrvCtrl->idr, len);
  995. #else
  996.         do_protocol (pEh, m, &pDrvCtrl->idr, len);
  997. #endif
  998.     else
  999.         pDrvCtrl->idr.ac_if.if_ierrors++;  /* bump error counter */
  1000.     return ((rfdLoaned) ? ERROR : OK);
  1001.     }
  1002. /*******************************************************************************
  1003. *
  1004. * eiLoanFree - return a loaned receive frame descriptor
  1005. *
  1006. * This routine is called by the protocol code when it has completed use of
  1007. * an RFD that we loaned to it.
  1008. */
  1009. static void eiLoanFree
  1010.     (
  1011.     DRV_CTRL *pDrvCtrl,
  1012.     RFD *pRfd
  1013.     )
  1014.     {
  1015.     eiRxQPut (pDrvCtrl, pRfd);
  1016.     pDrvCtrl->nLoanRfds ++;
  1017.     }
  1018. /*******************************************************************************
  1019. *
  1020. * eiDeviceStart - reset and start the device
  1021. *
  1022. * This routine assumes interrupts from the device have been disabled, and
  1023. * that the driver control structure has been initialized.
  1024. */
  1025. static STATUS eiDeviceStart
  1026.     (
  1027.     int unit                              /* physical unit number */
  1028.     )
  1029.     {
  1030.     void     *pTemp;
  1031.     DRV_CTRL *pDrvCtrl;
  1032.     SCP      *pScp;                       /* system config ptr */
  1033.     ISCP     *pIscp;                      /* intermediate system config ptr */
  1034.     SCB      *pScb;                       /* system control block ptr */
  1035.     /* Get pointers */
  1036.     pDrvCtrl = & drvCtrl [unit];
  1037.     pScp = pDrvCtrl->pScp;
  1038.     pIscp = pDrvCtrl->pIscp;
  1039.     pScb = pDrvCtrl->pScb;
  1040.     /* Issue the reset operation to the device */
  1041.     sys596Port (unit, PORT_RESET, NULL);
  1042.     /* Initialize the SCP */
  1043.     pScp->scpRsv1 =
  1044.     pScp->scpRsv2 =
  1045.     pScp->scpRsv3 = 0;
  1046.     pScp->scpSysbus = pDrvCtrl->sysbus;
  1047.     pTemp = CACHE_DRV_VIRT_TO_PHYS (&pDrvCtrl->cacheFuncs, pIscp);
  1048.     LINK_WR (&pScp->pIscp, pTemp);              /* point SCP to ISCP */
  1049.     /* Initialize the ISCP */
  1050.     pIscp->iscpBusy = 1;
  1051.     pIscp->iscpRsv1 = 0;
  1052.     pTemp = CACHE_DRV_VIRT_TO_PHYS (&pDrvCtrl->cacheFuncs, pScb);
  1053.     LINK_WR (&pIscp->pScb, pTemp);              /* point ISCP to SCB */
  1054.     /* Initialize the SCB */
  1055.     bzero ((char *)pScb, sizeof (SCB));
  1056.     /* Tell the device where the SCP is located */
  1057.     pTemp = CACHE_DRV_VIRT_TO_PHYS (&pDrvCtrl->cacheFuncs, pScp);
  1058.     sys596Port (unit, PORT_NEWSCP, (UINT32) pTemp);
  1059.     sys596ChanAtn (unit);
  1060.     /*
  1061.      * The device will now read our SCP and ISCP. It will clear the busy
  1062.      * flag in the ISCP.
  1063.      */
  1064.     taskDelay (50);
  1065.     if ( pIscp->iscpBusy == 1 )
  1066.         {
  1067.         printf ("nei: device did not initializen");
  1068.         return (ERROR);
  1069.         }
  1070.     return (OK);
  1071.     }
  1072. /*******************************************************************************
  1073. *
  1074. * eiDiag - format and issue a diagnostic command
  1075. */
  1076. static void eiDiag
  1077.     (
  1078.     int unit
  1079.     )
  1080.     {
  1081.     DRV_CTRL *pDrvCtrl;
  1082.     pDrvCtrl = & drvCtrl [unit];
  1083.     bzero ((char *)pDrvCtrl->pCfd, sizeof (CFD));       /* zero command frame */
  1084.     eiAction (unit, CFD_C_DIAG);                /* run diagnostics */
  1085.     if (!(pDrvCtrl->pCfd->cfdStatus & CFD_S_OK))
  1086.         printErr ("eiDiag: i82596 diagnostics failed.n");
  1087.     }
  1088. /*******************************************************************************
  1089. *
  1090. * eiConfig - format and issue a config command
  1091. */
  1092. static void eiConfig
  1093.     (
  1094.     int unit
  1095.     )
  1096.     {
  1097.     DRV_CTRL *pDrvCtrl;
  1098.     pDrvCtrl = & drvCtrl [unit];
  1099.     bzero ((char *)pDrvCtrl->pCfd, sizeof (CFD));       /* zero command frame */
  1100.     /* Recommeded i82596 User's Manual configuration values.  Note that
  1101.      * the original manual, #296443-001, was full of errors.  Errors in the
  1102.      * description of the config bytes that I am aware of are noted below.
  1103.      * It is possible there are further errors.  Intel has replaced the
  1104.      * manual with #296853-001, which does correct some errors, but not all.
  1105.      */
  1106.     pDrvCtrl->pCfd->cfdConfig.ccByte8  = 0x8e;
  1107.     pDrvCtrl->pCfd->cfdConfig.ccByte9  = 0xc8;
  1108.     /* The manual is wrong about bit 7 in byte 10.
  1109.      * A '0' allows reception of bad packets.
  1110.      * A '1' causes rejection of bad packets.
  1111.      */
  1112.     pDrvCtrl->pCfd->cfdConfig.ccByte10 = 0xc0;
  1113.     pDrvCtrl->pCfd->cfdConfig.ccByte11 = 0x2e;      /* loopback, NSAI */
  1114.     pDrvCtrl->pCfd->cfdConfig.ccByte12 = 0x00;
  1115.     pDrvCtrl->pCfd->cfdConfig.ccByte13 = 0x60;
  1116.     pDrvCtrl->pCfd->cfdConfig.ccByte14 = 0x00;
  1117.     pDrvCtrl->pCfd->cfdConfig.ccByte15 = 0xf2;
  1118.     pDrvCtrl->pCfd->cfdConfig.ccByte16 = 0x00;      /* promiscuous off */
  1119.     pDrvCtrl->pCfd->cfdConfig.ccByte17 = 0x00;
  1120.     pDrvCtrl->pCfd->cfdConfig.ccByte18 = 0x40;
  1121.     /* The manual is wrong about 2 bits in byte 19.
  1122.      * Bit 5, multicast, a '1' disables.
  1123.      * Bit 2, include CRC, a '1' disables.
  1124.      */
  1125.     pDrvCtrl->pCfd->cfdConfig.ccByte19 = 0xff;
  1126.     pDrvCtrl->pCfd->cfdConfig.ccByte20 = 0x00;
  1127.     pDrvCtrl->pCfd->cfdConfig.ccByte21 = 0x3f;
  1128.     eiAction (unit, CFD_C_CONFIG);          /* configure the chip */
  1129.     }
  1130. /*******************************************************************************
  1131. *
  1132. * eiIASetup - format and issue an interface address command
  1133. */
  1134. static void eiIASetup
  1135.     (
  1136.     int unit
  1137.     )
  1138.     {
  1139.     DRV_CTRL *pDrvCtrl;
  1140.     pDrvCtrl = & drvCtrl [unit];
  1141.     bzero ((char *)pDrvCtrl->pCfd, sizeof (CFD));       /* zero command frame */
  1142.     bcopy   (
  1143.             (char *)pDrvCtrl->idr.ac_enaddr,
  1144.             (char *)pDrvCtrl->pCfd->cfdIASetup.ciAddress,
  1145.             6
  1146.             );
  1147.     eiAction (unit, CFD_C_IASETUP);         /* setup the address */
  1148.     }
  1149. /*******************************************************************************
  1150. *
  1151. * eiRxStartup - start up the Receive Unit
  1152. *
  1153. * Starts up the Receive Unit.  Assumes that the receive structures are set up.
  1154. */
  1155. static void eiRxStartup
  1156.     (
  1157.     DRV_CTRL *pDrvCtrl
  1158.     )
  1159.     {
  1160.     SCB *pScb = pDrvCtrl->pScb;
  1161.     void * pTemp;
  1162.     if (pScb->scbStatus & SCB_S_RUREADY)        /* already running */
  1163.         return;
  1164.     pTemp = CACHE_DRV_VIRT_TO_PHYS (&pDrvCtrl->cacheFuncs, pDrvCtrl->pFreeRfd);
  1165.     LINK_WR (&pScb->pRF, pTemp);            /* point to free Rfd */
  1166.     sys596IntDisable (pDrvCtrl->idr.ac_if.if_unit);
  1167.     if ((pScb->scbStatus & SCB_S_RUMASK) != SCB_S_RUIDLE)
  1168.         eiCommand (pDrvCtrl, SCB_C_RUABORT);            /* abort if not idle */
  1169.     eiCommand (pDrvCtrl, SCB_C_RUSTART);              /* start receive unit */
  1170.     sys596IntEnable (pDrvCtrl->idr.ac_if.if_unit);
  1171.     }
  1172. /*******************************************************************************
  1173. *
  1174. * eiAction - execute the specified action with the CFD pointed to in pDrvCtrl
  1175. *
  1176. * Do the command contained in the CFD synchronously, so that we know
  1177. * it's complete upon return.  This routine assumes that interrupts from the
  1178. * device have been disabled.
  1179. */
  1180. static void eiAction
  1181.     (
  1182.     int    unit,
  1183.     UINT16 action
  1184.     )
  1185.     {
  1186.     void     *pTemp;
  1187.     CFD      *pCfd;
  1188.     SCB      *pScb;
  1189.     DRV_CTRL *pDrvCtrl;
  1190.     pDrvCtrl = & drvCtrl [unit];
  1191.     pCfd = pDrvCtrl->pCfd;
  1192.     pScb = pDrvCtrl->pScb;
  1193.     while (1)                   /* wait for idle command unit */
  1194.         {
  1195.         if ((pScb->scbStatus & SCB_S_CUMASK) == SCB_S_CUIDLE)
  1196.             break;
  1197.         }
  1198.     { /* Prepare and issue the command to the device */
  1199.     /* fill in CFD */
  1200.     pCfd->cfdStatus  = 0;                       /* clear status */
  1201.     pCfd->cfdCommand = CFD_C_EL | action;       /* fill in action */
  1202.     LINK_WR (&pCfd->link, NULL);                /* terminate link */
  1203.     /* and the SCB */
  1204.     pScb->scbCommand =
  1205.                         SCB_S_CX |              /* ack any events */
  1206.                         SCB_S_FR |
  1207.                         SCB_S_CNA |
  1208.                         SCB_S_RNR |
  1209.                         SCB_C_CUSTART;          /* start command unit */
  1210.     pTemp = CACHE_DRV_VIRT_TO_PHYS (&pDrvCtrl->cacheFuncs, pCfd);
  1211.     LINK_WR (&pScb->pCB, pTemp);                /* point chip at CFD */
  1212.     sys596ChanAtn (unit);               /* notify device of new command */
  1213.     }
  1214.     while (1)               /* wait for command acceptance and interrupt */
  1215.         {
  1216.         if ((pScb->scbCommand == 0) && (pScb->scbStatus & SCB_S_CNA))
  1217.             break;
  1218.         }
  1219.     /* Acknowledge the event to the device */
  1220.     pScb->scbCommand = (SCB_S_CX | SCB_S_CNA);
  1221.     sys596ChanAtn (unit);
  1222.     while (1)               /* wait for acknowledge acceptance */
  1223.         {
  1224.         if (pScb->scbCommand == 0)
  1225.             break;
  1226.         }
  1227.     }
  1228. /*******************************************************************************
  1229. *
  1230. * eiCommand - deliver a command to the 82596 via SCB
  1231. *
  1232. * This function causes the device to execute a command.  It should be called
  1233. * with interrupts from the device disabled.  An error status is returned if
  1234. * the command field does not return to zero, from a previous command, in a
  1235. * reasonable amount of time.
  1236. */
  1237. static STATUS eiCommand
  1238.     (
  1239.     DRV_CTRL *pDrvCtrl,
  1240.     UINT16    cmd
  1241.     )
  1242.     {
  1243.     int loopy;
  1244.     SCB * pScb;
  1245.     pScb = pDrvCtrl->pScb;
  1246.     for (loopy = 0x8000; loopy--;)
  1247.         {
  1248.         if (pScb->scbCommand == 0)                  /* wait for cmd zero */
  1249.             break;
  1250.         }
  1251.     if (loopy > 0)
  1252.         {
  1253.         pScb->scbCommand = cmd;                     /* fill in command */
  1254.         sys596ChanAtn (pDrvCtrl->idr.ac_if.if_unit);    /* channel attention */
  1255.         return (OK);
  1256.         }
  1257.     else
  1258.         {
  1259.         logMsg("ei driver: command field frozenn", 0, 0, 0, 0, 0, 0);
  1260.         return (ERROR);
  1261.         }
  1262.     }
  1263. /*******************************************************************************
  1264. *
  1265. * eiTxQPut - place a transmit frame on the transmit queue
  1266. *
  1267. * The TFD has been filled in with the network pertinent data.  This
  1268. * routine will enqueue the TFD for transmission and attempt to feed
  1269. * the queue to the device.
  1270. */
  1271. static void eiTxQPut
  1272.     (
  1273.     DRV_CTRL *pDrvCtrl,
  1274.     TFD *pTfd
  1275.     )
  1276.     {
  1277.     int unit;
  1278.     unit = pDrvCtrl->idr.ac_if.if_unit;
  1279.     pTfd->status    = 0;                    /* fill in TFD fields */
  1280.     pTfd->command   = CFD_C_XMIT;           /* EL set later */
  1281.     pTfd->count     |= TFD_CNT_EOF;         /* data kept in frame */
  1282.     pTfd->reserved  = 0;                    /* must be zero */
  1283.     LINK_WR (& pTfd->lBufDesc, NULL);                /* TBDs not used */
  1284.     sys596IntDisable (pDrvCtrl->idr.ac_if.if_unit);  /* disable dev ints */
  1285.     /* enqueue the TFD */
  1286.     eiQPut (unit,(EI_LIST *)&pDrvCtrl->txQueue, (EI_NODE*)pTfd);
  1287.     if (pDrvCtrl->txIdle)                             /* transmitter idle */
  1288.         eiTxQFlush (pDrvCtrl);                        /* flush txQueue */
  1289.     sys596IntEnable (pDrvCtrl->idr.ac_if.if_unit);  /* enable dev ints */
  1290.     }
  1291. /*******************************************************************************
  1292. *
  1293. * eiTxQFlush - make cmd unit of device start processing cmds
  1294. *
  1295. * This routine flushes the contents of the txQ to the cblQ and starts the
  1296. * device transmitting the cblQ.  Called only if transmit queue is not empty.
  1297. * Sometimes called from interrupt handler.
  1298. */
  1299. static void eiTxQFlush
  1300.     (
  1301.     DRV_CTRL *pDrvCtrl
  1302.     )
  1303.     {
  1304.     void * pTemp;
  1305.     extern int sysClkRateGet();     /* we call this */
  1306.     ((TFD*)pDrvCtrl->txQueue.tail)->command |= CFD_C_EL;  /* EL terminate q */
  1307.     pDrvCtrl->cblQueue.head = pDrvCtrl->txQueue.head;   /* remember cbl head */
  1308.     pDrvCtrl->cblQueue.tail = pDrvCtrl->txQueue.tail;   /* remember cbl tail */
  1309.     eiQInit ((EI_LIST *)&pDrvCtrl->txQueue);            /* tx queue now empty */
  1310.     pTemp = CACHE_DRV_VIRT_TO_PHYS (&pDrvCtrl->cacheFuncs,
  1311.                                     pDrvCtrl->cblQueue.head);
  1312.     LINK_WR (&pDrvCtrl->pScb->pCB, pTemp);          /* point CU to head */
  1313.     pDrvCtrl->txIdle = FALSE;                   /* transmitter busy */
  1314.     /* start command unit */
  1315.     eiCommand (pDrvCtrl, SCB_C_CUSTART);
  1316.     }
  1317. /*******************************************************************************
  1318. *
  1319. * eiRxQPut - return a RFD to the receive queue for use by the device
  1320. */
  1321. static void eiRxQPut
  1322.     (
  1323.     DRV_CTRL *pDrvCtrl,
  1324.     RFD *pRfd
  1325.     )
  1326.     {
  1327.     int unit;
  1328.     RFD *pTail;
  1329.     RBD *pRbd;
  1330.     void *pTemp;
  1331.     unit = pDrvCtrl->idr.ac_if.if_unit;
  1332.     pRbd = &pRfd->rbd;
  1333.     /* Initialize the RFD */
  1334.     pRfd->status = 0;
  1335.     pRfd->command = RFD_M_EL | RFD_M_FLEXMODE;
  1336.     pTemp = CACHE_DRV_VIRT_TO_PHYS (&pDrvCtrl->cacheFuncs, pRbd);
  1337.     LINK_WR (&pRfd->lBufDesc, pTemp);
  1338.     pRfd->actualCnt = 0;
  1339.     pRfd->bufSize = EH_SIZE;
  1340.     /* Initialize the RBD */
  1341.     pRbd->actualCnt = 0;
  1342.     pTemp = CACHE_DRV_VIRT_TO_PHYS (&pDrvCtrl->cacheFuncs, pRfd->enetData);
  1343.     LINK_WR (&pRbd->pData, pTemp);
  1344.     pRbd->size = RBD_EL | ETHERMTU;
  1345.     pTail = (RFD *) pDrvCtrl->rxQueue.tail;         /* remember tail */
  1346.     /* Put the RFD on the list */
  1347.     eiQPut (unit, (EI_LIST *) & pDrvCtrl->rxQueue, (EI_NODE *) pRfd);
  1348.     if (pTail != NULL)
  1349.         {
  1350.         pDrvCtrl->wdRxTimeout = 0;          /* reset timeout count */
  1351.         /* update RBD links */
  1352.         pTemp = CACHE_DRV_VIRT_TO_PHYS (&pDrvCtrl->cacheFuncs, pRbd);
  1353.         LINK_WR (&pTail->rbd.lNext, pTemp);
  1354.         pTail->rbd.size &= ~RBD_EL;
  1355.         pTail->command &= ~CFD_C_EL;        /* clear old tail EL */
  1356.         if (pTail->status & (CFD_S_COMPLETE | CFD_S_BUSY))
  1357.             {
  1358.             pDrvCtrl->pFreeRfd = pRfd;          /* link questionable */
  1359.             }
  1360.         else if (!(pDrvCtrl->pScb->scbStatus & SCB_S_RUREADY))
  1361.             /* receiver dormant */
  1362.             {
  1363.             eiRxStartup (pDrvCtrl);             /* start receive unit */
  1364.             }
  1365.         }
  1366.     else
  1367.         {
  1368.         pDrvCtrl->pFreeRfd = pRfd;              /* first free RFD */
  1369.         }
  1370.     }
  1371. /*******************************************************************************
  1372. *
  1373. * eiRxQGet - get a successfully received frame from the receive queue
  1374. *
  1375. * RETURNS: ptr to valid RFD, or NULL if none available
  1376. */
  1377. static RFD *eiRxQGet
  1378.     (
  1379.     DRV_CTRL *pDrvCtrl
  1380.     )
  1381.     {
  1382.     RFD *pRfd = NULL;
  1383.     if (eiRxQFull (pDrvCtrl))
  1384.         pRfd = (RFD *) eiQGet ((EI_LIST *)&pDrvCtrl->rxQueue);
  1385.     return (pRfd);
  1386.     }
  1387. /*******************************************************************************
  1388. *
  1389. * eiRxQFull - boolean function to determine fullness of receive queue
  1390. *
  1391. * RETURNS: TRUE if completely received frame is available, FALSE otherwise.
  1392. */
  1393. static BOOL eiRxQFull
  1394.     (
  1395.     DRV_CTRL *pDrvCtrl
  1396.     )
  1397.     {
  1398.     return ((pDrvCtrl->rxQueue.head != NULL) &&
  1399.         (((RFD*)pDrvCtrl->rxQueue.head)->status & CFD_S_COMPLETE));
  1400.     }
  1401. /*******************************************************************************
  1402. *
  1403. * eiQInit - initialize a singly linked node queue
  1404. */
  1405. static void eiQInit
  1406.     (
  1407.     EI_LIST *pQueue
  1408.     )
  1409.     {
  1410.     pQueue->head = pQueue->tail = NULL;         /* init head & tail */
  1411.     }
  1412. /*******************************************************************************
  1413. *
  1414. * eiQGet - get a node from the head of a node queue
  1415. *
  1416. * RETURNS: ptr to useable node, or NULL ptr if none available
  1417. */
  1418. static EI_NODE *eiQGet
  1419.     (
  1420.     EI_LIST *pQueue
  1421.     )
  1422.     {
  1423.     EI_NODE *pNode;
  1424.     if ((pNode = (EI_NODE *) pQueue->head) != NULL)     /* if list not empty */
  1425.         pQueue->head = pNode->pNext;                    /* advance ptr */
  1426.     return (pNode);
  1427.     }
  1428. /*******************************************************************************
  1429. *
  1430. * eiQPut - put a node on the tail of a node queue
  1431. */
  1432. static void eiQPut
  1433.     (
  1434.     int unit,
  1435.     EI_LIST *pQueue,
  1436.     EI_NODE *pNode
  1437.     )
  1438.     {
  1439.     void * pTemp;
  1440.     DRV_CTRL *pDrvCtrl;
  1441.     pDrvCtrl = & drvCtrl [unit];
  1442.     LINK_WR (&pNode->lNext, NULL);                    /* mark "end of list" */
  1443.     pNode->pNext = NULL;
  1444.     if (pQueue->head == NULL)                        /* if list empty */
  1445.         pQueue->tail = pQueue->head = pNode;         /* set both ptrs */
  1446.     else
  1447.         {
  1448.         pTemp = CACHE_DRV_VIRT_TO_PHYS (&pDrvCtrl->cacheFuncs, pNode);
  1449.         LINK_WR (&pQueue->tail->lNext, pTemp);       /* link node on tail */
  1450.         pQueue->tail->pNext = pNode;
  1451.         pQueue->tail = pNode;                        /* update tail ptr */
  1452.         }
  1453.     }
  1454. /*******************************************************************************
  1455. *
  1456. * eiWatchDog - if the watchdog timer fired off, we've hung during a transmit
  1457. *
  1458. * Check the scb command to verify and if so, reinit.
  1459. */
  1460. static void eiWatchDog
  1461.     (
  1462.     int unit        /* unit number */
  1463.     )
  1464.     {
  1465.     DRV_CTRL *pDrvCtrl = &drvCtrl [unit];
  1466.     SCB *pScb;
  1467.     int reset = FALSE;
  1468.     pScb = pDrvCtrl->pScb;
  1469.     /* Test for transmit timeout.
  1470.      *
  1471.      * Timeout occurs if the scb status indicates that CU (transmit) 
  1472.      * remains active for EI_TX_TIMEOUT iterations of eiWatchDog.
  1473.      * It might make sense to loop through the cfd's to look for
  1474.      * a complete bit as a sanity check, but given that transmit
  1475.      * was active, we will go ahead and do a reset.
  1476.      */
  1477.     if ((pDrvCtrl->txIdle == FALSE)
  1478.         && (pScb->scbStatus & SCB_S_CUACTIVE))
  1479.         {
  1480.         if (++(pDrvCtrl->wdTxTimeout) > EI_TX_TIMEOUT)
  1481.             {
  1482.             pDrvCtrl->transLocks++;   /* failure count */
  1483.             pDrvCtrl->idr.ac_if.if_oerrors++;             /* incr err count */
  1484.             pDrvCtrl->idr.ac_if.if_opackets--;            /* decr sent count */
  1485.             reset = TRUE;
  1486.             }
  1487.         }
  1488.     /* Test for receive timeout.
  1489.      *
  1490.      * Timeout occurs if the scb status indicates that RU (receive) 
  1491.      * remains out of resources for EI_RX_TIMEOUT iterations of eiWatchDog.
  1492.      */
  1493.     if (pScb->scbStatus & SCB_S_RUNORSRC)
  1494.         {
  1495.         if (++(pDrvCtrl->wdRxTimeout) > EI_RX_TIMEOUT)
  1496.             {
  1497.             pDrvCtrl->recvLocks++;   /* failure count */
  1498.             reset = TRUE;
  1499.             }
  1500.         }
  1501.     /* reinitialize the unit or restart the watchdog */
  1502.     if (reset)
  1503. netJobAdd ((FUNCPTR) eiInit, unit,0, 0, 0, 0);
  1504.     else
  1505.         wdStart (pDrvCtrl->wid, 
  1506. (int) pDrvCtrl->wdInterval, 
  1507. (FUNCPTR) eiWatchDog, 
  1508. unit);
  1509.     }
  1510. /******************************************************************************/
  1511. /* END OF FILE */