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

VxWorks

开发平台:

C/C++

  1. /* ei82596End.c - END style Intel 82596 Ethernet network interface driver */
  2. /* Copyright 1989-2002 Wind River Systems, Inc. */
  3. #include "copyright_wrs.h"
  4. /*
  5. modification history
  6. --------------------
  7. 02c,14jan02,dat  Removing warnings from Diab compiler
  8. 02b,12sep01,tor  add interlock between ei82596DeviceRestart() and int (SPR 70154)
  9.  update pFreeRfd in ei82596RxQPut() (SPR 70148)
  10. 02a,11jun00,ham  removed reference to etherLib.
  11. 01z,27jan00,dat  fixed use of NULL
  12. 01y,30nov99,stv  freed mBlk chain before returning ERROR (SPR #28492).  
  13. 01x,11jan99,mem  added offset load parameter, changed pNext fields in RFD
  14.  and TFD to type EI_LINK. Added test for netClusterGet()
  15.  returning NULL. (SPR 24440)
  16. 01w,05nov98,dbt  fixed error handling in ei82596Recv() routine (SPR #22557).
  17. 01v,22sep98,dat  Lint cleanup.
  18. 01u,28aug98,n_s  Changed watchdog to call ei82596DeviceRestart via netJobAdd.
  19.  spr #22224
  20. 01t,17aug98,sut  removed SYS_INT_ENABLE and sys596IntAck, which was before
  21.                  SYS_INT_CONNECT [SPR 20284]
  22. 01s,08dec97,gnn  END code review fixes.
  23. 01r,19oct97,vin  moved swapping of loaned buffer before END_RCV_RTN_CALL
  24. 01q,17oct97,vin  removed extra free.
  25. 01p,09oct97,vin  delete unwanted frees in PollSend routine
  26. 01o,07oct97,vin  fixed multicasting, fixed mtu to ETHER_MTU
  27. 01m,25sep97,gnn  SENS beta feedback fixes
  28. 01l,24sep97,vin  added clBlk related calls
  29. 01k,01sep97,vin  fixed the restart logic
  30. 01j,22aug97,gnn  changes due to new buffering scheme
  31. 01i,12aug97,gnn  changes necessitated by MUX/END update.
  32. 01h,30may97,map  Doc updates.
  33. 01g,02may97,map  Fixed bug in multicast address set.
  34. 01f,30apr97,jag  Fixed man page errors.
  35. 01d,21apr97,map  fixed strtok_r() invocation; added intr (dis)enable macros
  36.                  added sys596Init.
  37. 01c,17apr97,gnn  fixed bug in Load/Start sequence.
  38. 01b,17mar97,map  updates for new buffering scheme, and code cleanups.
  39. 01a,13sep96,map  modified if_ei.c to END style.
  40. */
  41. /*
  42. This module implements an Intel 82596 Ethernet network interface driver.
  43. This driver is designed to be moderately generic.  It operates unmodified
  44. across the range of architectures and targets supported by VxWorks.  
  45. To achieve this, this driver requires some external support routines 
  46. as well as several target-specific parameters.  These parameters (and the 
  47. mechanisms used to communicate them to the driver) are detailed below.
  48. This driver can run with the device configured in either
  49. big-endian or little-endian modes.  Error recovery code has been added to
  50. deal with some of the known errata in the A0 version of the device.  This
  51. driver supports up to four individual units per CPU.
  52. BOARD LAYOUT
  53. This device is on-board.  No jumpering diagram is necessary.
  54. EXTERNAL INTERFACE
  55. The driver provides one standard external interface, ei82596EndLoad().
  56. As input, this routine takes a string of colon-separated parameters.
  57. The parameters should be specified in hexadecimal (optionally preceded by "0x" 
  58. or a minus sign "-").  The parameter string is parsed using strtok_r(), and 
  59. each parameter is converted from string to binary by a call to:
  60. .CS
  61.     strtoul(parameter, NULL, 16).
  62. .CE
  63. TARGET-SPECIFIC PARAMETERS
  64. The format of the parameter string is:
  65.     <unit>:<ivec>:<sysbus>:<memBase>:<nTfds>:<nRfds>:<offset>
  66. .IP <unit>
  67. A convenient holdover from the former model.  It is only used in the
  68. string name for the driver.
  69. .IP <ivec>
  70. This is the interrupt vector number of the hardware interrupt generated by
  71. this ethernet device.  The driver uses intConnect() to attach an interrupt
  72. handler to this interrupt.
  73. .IP <sysbus>
  74. This parameter tells the device about the system bus. 
  75. To determine the correct value for a target, see 
  76. .I "Intel 32-bit Local Area Network (LAN) Component User's Manual."
  77. .IP <memBase>
  78. This parameter specifies the base address of a DMA-able cache-free
  79. pre-allocated memory region for use as a memory pool for transmit/receive
  80. descriptors, buffers, and other device control structures.
  81. If there is no pre-allocated memory available for the driver, this parameter
  82. should be -1 (NONE). In which case, the driver calls cacheDmaAlloc() to
  83. allocate cache-safe memory.
  84. .IP <nTfds>
  85. This parameter specifies the number of transmit descriptor/buffers to be
  86. allocated. If this parameter is zero or -1 (NULL), a default of 32 is used.
  87. .IP <nRfds>
  88. This parameter specifies the number of receive descriptor/buffers to be
  89. allocated. If this parameter is zero or -1 (NULL), a default of 32 is used.
  90. .IP <offset>
  91. Specifies the memory alignment offset.
  92. .LP
  93. EXTERNAL SUPPORT REQUIREMENTS
  94. This driver requires seven external support functions:
  95. .IP sys596IntEnable()
  96. .CS
  97.     void sys596IntEnable (int unit)
  98. .CE
  99. This routine provides a target-specific interface to enable Ethernet device
  100. interrupts for a given device unit.
  101. .IP sys596IntDisable()
  102. .CS
  103.     void sys596IntDisable (int unit)
  104. .CE
  105. This routine provides a target-specific interface to disable Ethernet device
  106. interrupts for a given device unit.
  107. .IP sysEnetAddrGet()
  108. .CS
  109.     STATUS sysEnetAddrGet (int unit, char *enetAdrs)
  110. .CE
  111. This routine provides a target-specific interface to access a device Ethernet
  112. address. This routine should provide a six-byte Ethernet address in  
  113. the <enetAdrs> parameter and return OK or ERROR.
  114. .IP sys596Init()
  115. .CS
  116.     STATUS sys596Init (int unit)
  117. .CE
  118. This routine performs any target-specific initialization required before the
  119. 82596 is initialized.  Typically, it is empty.  This routine must return OK
  120. or ERROR.
  121. .IP sys596Port()
  122. .CS
  123.     void sys596Port (int unit, int cmd, UINT32 addr)
  124. .CE
  125. This routine provides access to the special port function of the 82596.  It
  126. delivers the command and address arguments to the port of the specified unit.
  127. The driver calls this routine primarily during initialization and, under 
  128. some conditions, during error recovery procedures.
  129. .IP sys596ChanAtn()
  130. .CS
  131.     void sys596ChanAtn (int unit)
  132. .CE
  133. This routine provides the channel attention signal to the 82596 for the
  134. specified <unit>.  The driver calls this routine frequently throughout all
  135. phases of operation.
  136. .IP sys596IntAck()
  137. .CS
  138. void sys596IntAck (int unit)
  139. .CE
  140. This routine must perform any required interrupt acknowledgment or clearing.
  141. Typically, this involves an operation to some interrupt control hardware.
  142. Note that the INT signal from the 82596 behaves in an "edge-triggered" mode.
  143. Therefore, this routine typically clears a latch within the control circuitry.
  144. The driver calls this routine from the interrupt handler.
  145. .LP
  146. SYSTEM RESOURCE USAGE
  147. The driver uses cacheDmaMalloc() to allocate memory to share with the 82596.
  148. The fixed-size pieces in this area total 160 bytes.  The variable-size pieces
  149. in this area are affected by the configuration parameters specified in the
  150. eiattach() call.  The size of one RFD (Receive Frame Descriptor) is 1536
  151. bytes.  The size of one TFD (Transmit Frame Descriptor) is 1534 bytes.  For
  152. more on RFDs and TFDs, see the
  153. .I "Intel 82596 User's Manual."
  154. The 82596 requires ether that this shared memory region is non-cacheable
  155. or that the hardware implements bus snooping.  The driver cannot maintain
  156. cache coherency for the device. This is because fields within the command
  157. structures are asynchronously modified by both the driver and the device,
  158. and these fields might share the same cache line.
  159. TUNING HINTS
  160. The only adjustable parameters are the number of TFDs and RFDs that are
  161. created at run-time.  These parameters are given to the driver when eiattach()
  162. is called.  There is one TFD and one RFD associated with each transmitted
  163. frame and each received frame respectively.  For memory-limited applications,
  164. decreasing the number of TFDs and RFDs might be a good idea.  Increasing the
  165. number of TFDs provides no performance benefit after a certain point.
  166. Increasing the number of RFDs provides more buffering before packets are
  167. dropped.  This can be useful if there are tasks running at a higher priority
  168. than the net task.
  169. SEE ALSO: ifLib,
  170. .I "Intel 82596 User's Manual,"
  171. .I "Intel 32-bit Local Area Network (LAN) Component User's Manual"
  172. */
  173. #include "vxWorks.h"
  174. #include "wdLib.h"
  175. #include "iv.h"
  176. #include "vme.h"
  177. #include "net/mbuf.h"
  178. #include "net/unixLib.h"
  179. #include "net/protosw.h"
  180. #include "sys/socket.h"
  181. #include "sys/ioctl.h"
  182. #include "errno.h"
  183. #include "memLib.h"
  184. #include "intLib.h"
  185. #include "net/route.h"
  186. #include "iosLib.h"
  187. #include "errnoLib.h"
  188. #include "cacheLib.h"
  189. #include "logLib.h"
  190. #include "netLib.h"
  191. #include "stdio.h"
  192. #include "stdlib.h"
  193. #include "sysLib.h"
  194. #include "net/systm.h"
  195. #include "sys/times.h"
  196. #include "net/if_subr.h"
  197. #include "drv/end/ei82596End.h"
  198. #undef ETHER_MAP_IP_MULTICAST
  199. #include "etherMultiLib.h"
  200. #include "end.h"
  201. #include "semLib.h"
  202. #define END_MACROS
  203. #include "endLib.h"
  204. #include "lstLib.h"
  205. /* stuff to change in endLib.h */
  206. #define END_OBJ_FREE(X) END_OBJECT_UNLOAD(X)
  207. /***** LOCAL DEFINITIONS *****/
  208. /* Driver debug control */
  209. #ifdef DRV_DEBUG
  210. #define DRV_DEBUG_OFF 0x0000
  211. #define DRV_DEBUG_RX 0x0001
  212. #define DRV_DEBUG_TX 0x0002
  213. #define DRV_DEBUG_POLL (DRV_DEBUG_POLL_RX | DRV_DEBUG_POLL_TX)
  214. #define DRV_DEBUG_POLL_RX 0x0004
  215. #define DRV_DEBUG_POLL_TX 0x0008
  216. #define DRV_DEBUG_LOAD 0x0010
  217. #define DRV_DEBUG_IOCTL 0x0020
  218. #define DRV_DEBUG_BUF 0x0040
  219. #define DRV_DEBUG_INT 0x0800
  220. #define DRV_DEBUG_POLL_REDIR 0x10000
  221. #define DRV_DEBUG_LOG_NVRAM 0x20000
  222. int eiDebug = 0xff;
  223. int nLoan=0;
  224. IMPORT int  nvLogMsg();
  225. #define DRV_LOG(FLG, X0, X1, X2, X3, X4, X5, X6)                        
  226.     {                                                                   
  227. if ((eiDebug & FLG) && (eiDebug & DRV_DEBUG_LOG_NVRAM))         
  228.       logMsg(X0, X1, X2, X3, X4, X5, X6);                     
  229. else if (eiDebug & FLG)                                         
  230.       logMsg(X0, X1, X2, X3, X4, X5, X6);                       
  231.     }
  232. #define DRV_PRINT(FLG,X)                                                
  233.     {                                                                   
  234. if (eiDebug & FLG) printf X;                                    
  235.     }
  236. #else /*DRV_DEBUG*/
  237. #define DRV_LOG(DBG_SW, X0, X1, X2, X3, X4, X5, X6)
  238. #define DRV_PRINT(DBG_SW,X)
  239. #endif /*DRV_DEBUG*/
  240. /* When a cluster is in a free cluster pool, the first four bytes are
  241.  * used as a link pointer to the next cluster in the free list.
  242.  */
  243. #define CLUSTER_POINTER_SIZE    sizeof(void *)
  244. #define EI_CLUSTER_SIZE         MEM_ROUND_UP((sizeof(RFD)+2))
  245. #define END_FLAGS_ISSET(pEnd, setBits)                                  
  246.             ((pEnd)->flags & (setBits))
  247. /* A shortcut for getting the hardware address from the MIB II stuff. */
  248. #define END_HADDR(pEnd)                                                 
  249. ((pEnd)->mib2Tbl.ifPhysAddress.phyAddress)
  250. #define END_HADDR_LEN(pEnd)                                             
  251. ((pEnd)->mib2Tbl.ifPhysAddress.addrLength)
  252. #define EI_SPEED 10000000             /* bits per sec */
  253. #define EADDR_LEN 6                    /* ethernet address length */
  254. #define DEF_NUM_TFDS    32                   /* default number of TFDs */
  255. #define DEF_NUM_RFDS    32                   /* default number of RFDs */
  256. #define EI_PKT_SIZE (ETHERMTU + SIZEOF_ETHERHEADER + EADDR_LEN)
  257. #define EI_DEV_NAME "ei"
  258. #define EI_DEV_NAME_LEN 3
  259. /* driver flags */
  260. #define EI_POLLING 0x01    /* polling mode */
  261. #define EI_PROMISC 0x02    /* promiscuous mode */
  262. #define EI_MCAST 0x04    /* multicast addressing mode */
  263. #define EI_MCAST_SOFT 0x08    /* software multicast */
  264. #define EI_MEMOWN 0x10    /* device mem allocated by driver */
  265. #define END_CTRL_SIZ sizeof(END_CTRL)
  266. #define EI_RX_TIMEOUT 3         /* # watchdog runs for receive timeout */
  267. #define EI_TX_TIMEOUT 2         /* # watchdog runs for transmit timeout */
  268. #define DRV_FLAGS_SET(setBits)                                          
  269. (pDrvCtrl->flags |= (setBits))
  270. #define DRV_FLAGS_CLR(clrBits)                                          
  271. (pDrvCtrl->flags &= ~(clrBits))
  272. #define DRV_FLAGS_GET()                                                 
  273.         (pDrvCtrl->flags)
  274.             
  275. #define DRV_FLAGS_ISSET(setBits)                                        
  276.         (pDrvCtrl->flags & (setBits))            
  277. /*
  278.  * Default macro definitions for BSP interface.
  279.  * These macros can be redefined in a wrapper file, to generate
  280.  * a new module with an optimized interface.
  281.  */
  282. #ifndef SYS_INT_CONNECT
  283. #define SYS_INT_CONNECT(pDrvCtrl,rtn,arg,pResult) 
  284.     { 
  285.     IMPORT STATUS sysIntConnect(); 
  286.     *pResult = intConnect ((VOIDFUNCPTR *)INUM_TO_IVEC (pDrvCtrl->ivec), 
  287.      rtn, (int)arg); 
  288.     }
  289. #endif /*SYS_INT_CONNECT*/
  290. #ifndef SYS_INT_DISCONNECT
  291. #define SYS_INT_DISCONNECT(pDrvCtrl,rtn,arg,pResult)                    
  292.     {                                                                   
  293.     *pResult = OK; /* HELP: need a real routine */                      
  294.     }
  295. #endif /*SYS_INT_DISCONNECT*/
  296. #ifndef SYS_INT_ENABLE
  297. #define SYS_INT_ENABLE(pDrvCtrl)                                        
  298.     {                                                                   
  299.     IMPORT STATUS sys596IntEnable(int);                                 
  300.                                                                         
  301.     (void) sys596IntEnable (pDrvCtrl->unit);                            
  302.     }
  303. #endif /*SYS_INT_ENABLE*/
  304. #ifndef SYS_INT_DISABLE
  305. #define SYS_INT_DISABLE(pDrvCtrl)                                       
  306.     {                                                                   
  307.     IMPORT void sys596IntDisable(int);                                  
  308.                                                                         
  309.     sys596IntDisable(pDrvCtrl->unit);                                   
  310.     }
  311. #endif /* SYS_INT_DISABLE */
  312. #ifndef DRV_NAME
  313. #define DRV_NAME "ei"
  314. #define DRV_NAME_LEN    3
  315. #endif /* DRV_NAME */
  316. #define NET_BUF_FREE(pNetBuf) 
  317. pNetBuf->freeRtn(pNetBuf->pSpare1, pNetBuf->pSpare2)
  318. /* The definition of our linked list management structure */
  319. typedef struct ei_list                       /* EI_LIST - 82596 queue head */
  320.     {
  321.     volatile EI_NODE *  head;       /* header of list */
  322.     volatile EI_NODE *  tail;       /* tail of list */
  323.     } EI_LIST;
  324. /* The definition of the driver control structure */
  325. typedef struct end_ctrl
  326.     {
  327.     END_OBJ endObj;              /* base class */
  328.     int unit;                /* unit number */
  329.     int                 ivec;                /* interrupt vector */
  330.     UINT8               sysbus;              /* SCP sysbus value */
  331.     char                *memBase;            /* 82596 memory pool base */
  332.     int                 nTFDs;               /* how many TFDs to create */
  333.     int                 nRFDs;               /* how many RFDs to create */
  334.     INT8 flags;               /* driver state */
  335.     CACHE_FUNCS         cacheFuncs;          /* cache descriptor */
  336.     SCP                 *pScp;               /* SCP ptr */
  337.     ISCP                *pIscp;              /* ISCP ptr */
  338.     SCB                 *pScb;               /* SCB ptr */
  339.     CFD                 *pCfd;               /* synchronous command frame */
  340.     RFD                 *rfdPool;            /* RFD pool */
  341.     TFD                 *tfdPool;            /* TFD pool */
  342.     TFD *pPollTfd;           /* TFD for polled transmits */
  343.     RFD                 *pFreeRfd;           /* first empty RFD in rxQueue */
  344.     volatile EI_LIST    rxQueue;             /* receive queue */
  345.     volatile EI_LIST    txQueue;             /* to be sent queue */
  346.     volatile EI_LIST    freeQueue;           /* free frame descriptors */
  347.     volatile EI_LIST    cblQueue;            /* actual chip transmit queue */
  348.     volatile EI_LIST    cleanQueue;          /* queue of TFDs to cleanup */
  349.     WDOG_ID             wid;                 /* watchdog timer for transmit */
  350.     int                 wdInterval;          /* watchdog interval in ticks */
  351.     long rxLockups;           /* receive lockup count */
  352.     long                txLockups;           /* transmit lockup count */
  353.     volatile char wdTxTimeout;         /* watchdog runs with tx lockup */
  354.     volatile char wdRxTimeout;         /* watchdog runs with rx lockup */
  355.     int resetCount;          /* number of chip resets */
  356.     BOOL txIdle;              /* no pending transmits */
  357.     BOOL txCleaning;          /* cleaning transmit queue */
  358.     BOOL rxHandling;          /* handling received packets */
  359.     BOOL txBlocked;      /* to implement flow control */
  360.     CL_POOL_ID          pClPoolId;
  361.     int offset;      /* memory offset */
  362.     } END_CTRL;
  363. /***** GLOBALS *****/
  364. #ifdef DRV_DEBUG
  365. END_CTRL  *pEndCtrl;
  366. #endif /*DRV_DEBUG*/
  367. /* Function declarations not in any header files */
  368. IMPORT STATUS sysEnetAddrGet (int unit, UCHAR addr[]);
  369. IMPORT void   sys596Init (int unit);
  370. IMPORT STATUS sys596IntAck (int unit);
  371. IMPORT STATUS sys596IntEnable (int unit);
  372. IMPORT void   sys596IntDisable (int unit);
  373. IMPORT void   sys596Port (int unit, int cmd, UINT32 addr);
  374. IMPORT void   sys596ChanAtn (int unit);
  375. /* forward function declarations */
  376. LOCAL STATUS ei82596InitParse (END_CTRL *pDrvCtrl, char *initString);
  377. LOCAL STATUS ei82596InitMem (END_CTRL *pDrvCtrl);
  378. LOCAL STATUS ei82596Diag (END_CTRL *pDrvCtrl);
  379. LOCAL void ei82596Config (END_CTRL *pDrvCtrl);
  380. LOCAL STATUS ei82596MCastConfig (END_CTRL *pDrvCtrl);
  381. LOCAL void ei82596IASetup (END_CTRL *pDrvCtrl);
  382. LOCAL void ei82596RxStartup (END_CTRL *pDrvCtrl);
  383. LOCAL void ei82596Action (END_CTRL *pDrvCtrl, UINT16 action);
  384. LOCAL STATUS ei82596Command (END_CTRL *pDrvCtrl, UINT16 cmd);
  385. LOCAL void ei82596TxQPut (END_CTRL *pDrvCtrl, TFD *pTfd);
  386. LOCAL void ei82596RxQPut (END_CTRL *pDrvCtrl, RFD *pRfd);
  387. LOCAL void ei82596TxQFlush (END_CTRL *pDrvCtrl);
  388. LOCAL RFD * ei82596RxQGet (END_CTRL *pDrvCtrl);
  389. LOCAL BOOL ei82596RxQFull (END_CTRL *pDrvCtrl);
  390. LOCAL void ei82596QInit (volatile EI_LIST *pHead);
  391. LOCAL EI_NODE * ei82596QGet (volatile EI_LIST *pQueue);
  392. LOCAL void ei82596QPut (END_CTRL *pDrvCtrl, EI_LIST *pQueue,
  393.                              EI_NODE *pNode);
  394. LOCAL void ei82596QCat (volatile EI_LIST *pQDest, volatile EI_LIST *pQSrc);
  395. LOCAL STATUS ei82596DeviceStart (END_CTRL *pDrvCtrl);
  396. LOCAL void ei82596WatchDog (END_CTRL *pDrvCtrl);
  397. LOCAL void ei82596Recv (END_CTRL *pDrvCtrl, RFD *pRfd);
  398. LOCAL void ei82596TxCleanQ (END_CTRL *pDrvCtrl);
  399. LOCAL void ei82596RxIntHandle (END_CTRL *pDrvCtrl);
  400. LOCAL void ei82596Int (END_CTRL *pDrvCtrl);
  401. LOCAL void ei82596DeviceRestart(END_CTRL *pDrvCtrl);
  402. /* END Specific interfaces. */
  403. END_OBJ * ei82596EndLoad (char *initString);
  404. LOCAL STATUS ei82596Unload (END_CTRL *pDrvCtrl);
  405. LOCAL STATUS ei82596Start(END_CTRL *pDrvCtrl);
  406. LOCAL STATUS ei82596Stop(END_CTRL *pDrvCtrl);
  407. LOCAL int ei82596Ioctl (END_CTRL *pDrvCtrl, int cmd, caddr_t data);
  408. LOCAL STATUS ei82596Send (END_CTRL *pDrvCtrl, M_BLK_ID pMblk);
  409. LOCAL STATUS ei82596MCastAdrsAdd (END_CTRL *pDrvCtrl, char* pAddress);
  410. LOCAL STATUS ei82596MCastAdrsDel (END_CTRL *pDrvCtrl, char* pAddress);
  411. LOCAL STATUS ei82596MCastAdrsGet (END_CTRL *pDrvCtrl, 
  412. MULTI_TABLE *pTable);
  413. LOCAL STATUS ei82596PollSend (END_CTRL *pDrvCtrl, M_BLK_ID pMblk);
  414. LOCAL STATUS ei82596PollReceive (END_CTRL *pDrvCtrl, M_BLK_ID pMblk);
  415. LOCAL STATUS ei82596PollStart (END_CTRL *pDrvCtrl);
  416. LOCAL STATUS ei82596PollStop (END_CTRL *pDrvCtrl);
  417. /* 
  418.  * Define the device function table.  This is static across all driver
  419.  * instances.
  420.  */
  421. LOCAL NET_FUNCS netFuncs = 
  422.   {
  423.   (FUNCPTR)ei82596Start, /* start func. */                 
  424.   (FUNCPTR)ei82596Stop, /* stop func. */
  425.   (FUNCPTR)ei82596Unload,       /* unload func. */                
  426.   (FUNCPTR)ei82596Ioctl, /* ioctl func. */                 
  427.   (FUNCPTR)ei82596Send, /* send func. */                  
  428.   (FUNCPTR)ei82596MCastAdrsAdd, /* multicast add func. */         
  429.   (FUNCPTR)ei82596MCastAdrsDel, /* multicast delete func. */      
  430.   (FUNCPTR)ei82596MCastAdrsGet, /* multicast get fun. */          
  431.   (FUNCPTR)ei82596PollSend, /* polling send func. */          
  432.   (FUNCPTR)ei82596PollReceive, /* polling receive func. */
  433.   endEtherAddressForm,   /* put address info into a NET_BUFFER. */
  434.   endEtherPacketDataGet, /* get pointer to data in NET_BUFFER. */
  435.   endEtherPacketAddrGet  /* Get packet addresses. */
  436.   };
  437. /* network buffers configuration */
  438. M_CL_CONFIG  eiMclBlkConfig = 
  439. {
  440.     0, 0, NULL, 0
  441. };
  442. CL_DESC  eiClDescTbl [] =
  443. {
  444.     /* 
  445.        clusterSize num memArea memSize
  446.        ----------- ---- ------- -------
  447.        */
  448.     {EI_CLUSTER_SIZE, 0, NULL, 0}
  449. }; 
  450. int eiClDescTblNumEnt = (NELEMENTS(eiClDescTbl));
  451. /*******************************************************************************
  452. *
  453. * ei82596EndLoad - initialize the driver and device
  454. *
  455. * This routine initializes both driver and device to an operational state
  456. * using the device-specific values specified by <initString>.
  457. * The <initString> parameter expects an ordered list of colon-separated 
  458. * values. 
  459. * The format of the <initString> is:
  460. *     <unit>:<ivec>:<sysbus>:<memBase>:<nTfds>:<nRfds>
  461. *
  462. * .IP <unit>
  463. * Specifies the unit number for this device.
  464. * .IP <ivec>
  465. * This is the interrupt vector number of the hardware interrupt generated by
  466. * this Ethernet device.  The driver uses intConnect() to attach an interrupt
  467. * handler for this interrupt.
  468. * .IP <sysbus> 
  469. * Passes in values as described in the Intel manual
  470. * for the 82596.  A default number of transmit/receive frames of 32 can be
  471. * selected by passing zero in the parameters <nTfds> and <nRfds>.
  472. * In other cases, the number of frames selected should be greater than two.
  473. * .IP <memBase> 
  474. * Informs the driver about the shared memory region.  The 82596 shares a 
  475. * region of memory with the driver.  The caller of this routine can specify 
  476. * the address of this memory region, or can specify that the driver must 
  477. * obtain this memory region from the system resources.  If this parameter 
  478. * is set to the constant "NONE", this routine tries to allocate the shared 
  479. * memory from the system.  Any other value for this parameter is interpreted 
  480. * by this routine as the address of the shared memory region to be used.
  481. *
  482. * If the caller provides the shared memory region, the driver assumes
  483. * that this region does not require cache-coherency operations, nor does 
  484. * it require conversions between virtual and physical addresses.
  485. * If the caller indicates that this routine must allocate the shared memory
  486. * region, this routine uses cacheDmaMalloc() to obtain some  non-cacheable 
  487. * memory.  The attributes of this memory are checked, and, if the memory is 
  488. * not both read- and write-coherent, this routine aborts.
  489. * .LP
  490. *
  491. * RETURNS: An END object pointer or NULL.
  492. *
  493. * SEE ALSO: ifLib,
  494. * .I "Intel 82596 User's Manual"
  495. */
  496. END_OBJ *ei82596EndLoad
  497.     (
  498.     char * initString      /* parameter string */
  499.     )
  500.     {
  501.     END_CTRL    *pDrvCtrl;
  502.     UCHAR eAdrs[EADDR_LEN];            /* ethernet address */
  503.     RFD *pRfd;
  504.     int ix;
  505.     if (initString == NULL)
  506.         return (NULL);
  507.     
  508.     if (initString[0] == 0)
  509.         {
  510.         bcopy((char *)DRV_NAME, initString, DRV_NAME_LEN);
  511.         return (0);
  512.         }
  513.     /* Allocate a control structure for this device */
  514.     pDrvCtrl  = calloc (sizeof(END_CTRL), 1);
  515.     if (pDrvCtrl == NULL)
  516.         return (NULL);
  517.     /* Parse InitString */
  518.     if (ei82596InitParse (pDrvCtrl, initString) == ERROR)
  519.         return (NULL);
  520. #ifdef DRV_DEBUG
  521.     pEndCtrl=pDrvCtrl;
  522. #endif /* DRV_DEBUG */
  523.     
  524.     /* endObj initializations */
  525.     if (END_OBJ_INIT (&pDrvCtrl->endObj, (DEV_OBJ*) pDrvCtrl, DRV_NAME,
  526.                       pDrvCtrl->unit, &netFuncs,
  527.                       "Intel 82596 Ethernet Enhanced Network Driver") == ERROR)
  528.         return (NULL);
  529.     
  530.     /* memory initialization */
  531.     if (ei82596InitMem (pDrvCtrl) == ERROR)
  532.         goto error;
  533.     /* Initialize a watchdog for device lockups */
  534.     pDrvCtrl->txLockups = 0;
  535.     pDrvCtrl->rxLockups = 0;
  536.     pDrvCtrl->wid = wdCreate ();                /* create watchdog */
  537.     if (pDrvCtrl->wid == NULL)                  /* no resource */
  538.         goto error;
  539.     pDrvCtrl->wdInterval = sysClkRateGet() >> 1;
  540.     /* Get our enet addr */
  541.     if (sysEnetAddrGet (pDrvCtrl->unit, eAdrs) == ERROR)
  542. {
  543. errnoSet (S_iosLib_INVALID_ETHERNET_ADDRESS);
  544.         goto error;
  545. }
  546.     /* Initialize MIB-II entries */
  547.     if (END_MIB_INIT (&pDrvCtrl->endObj, M2_ifType_ethernet_csmacd,
  548.                       eAdrs, 6,
  549.                       ETHERMTU, EI_SPEED) == ERROR)
  550.         goto error;
  551.     pDrvCtrl->txIdle = TRUE;
  552.     pDrvCtrl->rxHandling = FALSE;
  553.     pDrvCtrl->txCleaning = FALSE;
  554.     
  555.     ei82596QInit (&pDrvCtrl->rxQueue);   /* to be received queue */
  556.     ei82596QInit (&pDrvCtrl->txQueue);   /* to be sent queue */
  557.     ei82596QInit (&pDrvCtrl->freeQueue);  /* free tfds for the send q */
  558.     ei82596QInit (&pDrvCtrl->cblQueue);  /* actively sending queue */
  559.     ei82596QInit (&pDrvCtrl->cleanQueue);/* queue of TFDs to clean */
  560.     pDrvCtrl->wdTxTimeout = 0;
  561.     pDrvCtrl->wdRxTimeout = 0;
  562.     for (ix = 0; ix < pDrvCtrl->nTFDs; ix ++)  /* tank up the free tfd queue */
  563.         {
  564.         ei82596QPut  (pDrvCtrl,
  565.                       (EI_LIST *) & pDrvCtrl->freeQueue,
  566.                       (EI_NODE *) & pDrvCtrl->tfdPool [ix]);
  567.         }
  568.     for (ix = 0; ix < pDrvCtrl->nRFDs; ix ++)   /* tank up the receive queue */
  569.         {
  570.         static BOOL first = TRUE;
  571.         pRfd = (RFD *) netClusterGet (pDrvCtrl->endObj.pNetPool,
  572.                                       pDrvCtrl->pClPoolId);
  573. if (pRfd == NULL)
  574.             {
  575.             DRV_LOG (DRV_DEBUG_LOAD, "Could not get an RFD buffern",
  576.                      1, 2, 3, 4, 5, 6);
  577.     goto error;
  578.             }
  579. /* offset pRfd */
  580. pRfd = (RFD *) (((char *) pRfd) + pDrvCtrl->offset );
  581.         pRfd->status = 0;
  582.         pRfd->command = 0;
  583.         if (first)
  584.             {
  585.             pDrvCtrl->pFreeRfd = pRfd;
  586.             first = FALSE;
  587.             }
  588.             
  589.         pRfd->bufSize = ETHERMTU + EH_SIZE;     /* max packet size */
  590.         LINK_WR (& pRfd->lBufDesc, 0xffffffff); /* no RDB */
  591.         ei82596QPut (pDrvCtrl,
  592.                      (EI_LIST *) &pDrvCtrl->rxQueue,
  593.                      (EI_NODE *) pRfd);
  594.         }
  595.     pRfd = (RFD *) pDrvCtrl->rxQueue.tail;
  596.     pRfd->command = CFD_C_EL;                /* end of list */
  597.     /* Mark the device ready */
  598.     END_OBJ_READY (&pDrvCtrl->endObj,
  599.                    IFF_NOTRAILERS | IFF_MULTICAST | IFF_BROADCAST);
  600.     /* Successful return */
  601.     return (&pDrvCtrl->endObj);
  602.     /***** Handle error cases *****/
  603.     error:
  604. {
  605.         ei82596Unload (pDrvCtrl);
  606.         return (NULL);
  607.         }
  608.     }
  609. /*******************************************************************************
  610. *
  611. * ei82596Unload - unload a driver from the system
  612. *
  613. * This routine deallocates lists, and free allocated memory.
  614. *
  615. * RETURNS: OK, always.
  616. */
  617. LOCAL STATUS ei82596Unload
  618.     (
  619.     END_CTRL *pDrvCtrl
  620.     )
  621.     {
  622.     DRV_LOG (DRV_DEBUG_LOAD, "eiUnloadn", 0, 0, 0, 0, 0, 0);
  623.     /* deallocate lists */
  624.     END_OBJ_FREE (&pDrvCtrl->endObj);
  625.     /* Free the allocated watchdog */
  626.     if (pDrvCtrl->wid != NULL)
  627.         wdDelete (pDrvCtrl->wid);
  628.     /* deallocate allocated shared memory */
  629.     if (DRV_FLAGS_ISSET (EI_MEMOWN)  && pDrvCtrl->memBase)
  630.         cacheDmaFree (pDrvCtrl->memBase);
  631.     return (OK);
  632.     }
  633. /*******************************************************************************
  634. *
  635. * ei82596InitParse - parse parameter values from initString
  636. *
  637. * RETURNS: OK or ERROR.
  638. */
  639. LOCAL STATUS ei82596InitParse
  640.     (
  641.     END_CTRL *pDrvCtrl,
  642.     char  *initString
  643.     )
  644.     {
  645.     char * tok; /* an initString token */
  646.     char * holder=NULL; /* points to initString fragment beyond tok */
  647.     
  648.     tok = strtok_r(initString, ":", &holder);
  649.     if (tok == NULL)
  650.         return ERROR;
  651.     pDrvCtrl->unit = atoi(tok);
  652.     tok=strtok_r(NULL, ":", &holder);
  653.     if (tok == NULL)
  654.         return ERROR;
  655.     pDrvCtrl->ivec = strtoul (tok, NULL, 16);
  656.     
  657.     tok=strtok_r(NULL, ":", &holder);
  658.     if (tok == NULL)
  659.         return ERROR;
  660.     pDrvCtrl->sysbus = (UINT8) strtoul (tok, NULL, 16);
  661.     
  662.     tok=strtok_r(NULL, ":", &holder);
  663.     if (tok == NULL)
  664.         return ERROR;
  665.     pDrvCtrl->memBase = (char *) strtoul (tok, NULL, 16);
  666.     tok = strtok_r (NULL, ":", &holder);
  667.     if (tok == NULL)
  668.         return ERROR;
  669.     pDrvCtrl->nTFDs = atoi (tok);
  670.     if (!pDrvCtrl->nTFDs || pDrvCtrl->nTFDs == -1)
  671.         pDrvCtrl->nTFDs = DEF_NUM_TFDS;
  672.     tok = strtok_r (NULL, ":", &holder);
  673.     if (tok == NULL)
  674.         return ERROR;
  675.     pDrvCtrl->nRFDs = atoi (tok);
  676.     if (!pDrvCtrl->nRFDs || pDrvCtrl->nRFDs == -1)
  677.         pDrvCtrl->nRFDs = DEF_NUM_RFDS;
  678.     pDrvCtrl->offset = -1;
  679.     tok = strtok_r (NULL, ":", &holder);
  680.     if (tok != NULL)
  681. {
  682. pDrvCtrl->offset = atoi (tok);
  683. }
  684.     if (pDrvCtrl->offset == -1)
  685. pDrvCtrl->offset = 0;
  686.     DRV_LOG (DRV_DEBUG_LOAD,
  687.             "eiEndLoad: unit=%d ivec=0x%x sysbus=0x%x membase=0x%x "
  688.             "nTfds=%d nRfds=%dn",
  689.             pDrvCtrl->unit, pDrvCtrl->ivec, pDrvCtrl->sysbus,
  690.             (int)pDrvCtrl->memBase, pDrvCtrl->nTFDs, pDrvCtrl->nRFDs);
  691.     if (pDrvCtrl->offset)
  692. DRV_LOG (DRV_DEBUG_LOAD,
  693.  "eiEndLoad: unit=%d offset=%dn",
  694.  pDrvCtrl->unit, pDrvCtrl->offset, 0, 0, 0, 0);
  695.     return OK;
  696.     }
  697. /*******************************************************************************
  698. *
  699. * ei82596InitMem - initialize memory
  700. *
  701. * RETURNS: OK or ERROR
  702. */
  703. LOCAL STATUS ei82596InitMem
  704.     (
  705.     END_CTRL * pDrvCtrl
  706.     )
  707.     {
  708.     UINT size;
  709.     UINT        sizeScp;
  710.     UINT        sizeIscp;
  711.     UINT        sizeScb;
  712.     UINT        sizeCfd;
  713.     static char *errMsg1 = "nei82596EndLoad: could not obtain memoryn";
  714.     static char *errMsg2 = "nei82596EndLoad: shared memory not cache"
  715.                            "coherentn";
  716.     /* initialize the netPool */
  717.     if ((pDrvCtrl->endObj.pNetPool = malloc (sizeof(NET_POOL))) == NULL)
  718.         return (ERROR);
  719.     if (eiMclBlkConfig.mBlkNum == 0) /* pool of mblks */
  720.         eiMclBlkConfig.mBlkNum =  pDrvCtrl->nRFDs * 4;  
  721.     if (eiClDescTbl [0].clNum == 0)
  722.         {/* pool of receive frames */
  723.         eiClDescTbl[0].clNum =  pDrvCtrl->nRFDs * 2;
  724.         eiClDescTbl[0].clSize = EI_CLUSTER_SIZE;
  725.         }
  726.     if (eiMclBlkConfig.clBlkNum == 0) /* pool of cluster blks */
  727.         eiMclBlkConfig.clBlkNum =  eiClDescTbl[0].clNum; 
  728.     
  729.     /* Force word (4-byte) alignment */
  730.     sizeScp  = MEM_ROUND_UP (sizeof (SCP));
  731.     sizeIscp = MEM_ROUND_UP (sizeof (ISCP));
  732.     sizeScb  = MEM_ROUND_UP (sizeof (SCB));
  733.     sizeCfd  = MEM_ROUND_UP (sizeof (CFD));
  734.     /* calculate the total size of 82596 memory pool
  735.      * NOTE: When calling netPoolInit(), the library adds
  736.      * a link pointer to the size of every cluster.  It
  737.      * also adds a link pointer to the beginning of the
  738.      * cluster pool.  This is accounted for below with
  739.      * the CLUSTER_POINTER_SIZE macro.
  740.      */
  741.     size =
  742.             16 +                                /* allow for alignment */
  743.             sizeScp +
  744.             sizeIscp +
  745.             sizeScb +
  746.             sizeCfd +                           /* synch'ed command frame */
  747.             (((eiClDescTbl[0].clSize + CLUSTER_POINTER_SIZE) *
  748. eiClDescTbl[0].clNum) + CLUSTER_POINTER_SIZE) + 
  749.             (sizeof (TFD) * pDrvCtrl->nTFDs) +  /* pool of transmit frames */
  750.             (sizeof (TFD)); /* one TFD for polled TX */
  751.     /* Establish the memory area that we will share with the device.  If
  752.      * the caller has provided an area, then we assume it is non-cacheable
  753.      * and will not require the use of the special cache routines.
  754.      * If the caller did not provide an area, then we must obtain it from
  755.      * the system, using the cache savvy allocation routine.
  756.      */
  757.     switch ((int) pDrvCtrl->memBase)
  758.         {
  759.         case NONE :                             /* we must obtain it */
  760.             /* this driver can't handle incoherent caches */
  761.             if (!CACHE_DMA_IS_WRITE_COHERENT () ||
  762.                 !CACHE_DMA_IS_READ_COHERENT ())
  763.                 {
  764.                 printf (errMsg2);
  765.                 return (ERROR);
  766.                 }
  767.             pDrvCtrl->memBase = cacheDmaMalloc (size);
  768.             DRV_FLAGS_SET(EI_MEMOWN);
  769.             if (pDrvCtrl->memBase == NULL)      /* no memory available */
  770.                 {
  771.                 printf (errMsg1);
  772.                 return (ERROR);
  773.                 }
  774.             pDrvCtrl->cacheFuncs = cacheDmaFuncs;
  775.             break;
  776.         default :                               /* the user provided an area */
  777.             pDrvCtrl->cacheFuncs = cacheNullFuncs;
  778.             DRV_FLAGS_CLR (EI_MEMOWN);
  779.             break;
  780.         }
  781.     /* Carve up the shared memory region into the specific sections */
  782.     bzero ((char *) pDrvCtrl->memBase, size);
  783.     pDrvCtrl->pScp  = (SCP *)                 /* align to first 16 byte page */
  784.                       ( ((u_long) pDrvCtrl->memBase + 0xf) & ~0xf );
  785.     pDrvCtrl->pIscp = (ISCP *)((int)pDrvCtrl->pScp   + sizeScp);
  786.     pDrvCtrl->pScb  = (SCB *) ((int)pDrvCtrl->pIscp  + sizeIscp);
  787.     pDrvCtrl->pCfd  = (CFD *) ((int)pDrvCtrl->pScb   + sizeScb);
  788.     if (eiMclBlkConfig.memArea == NULL) /* do a default allocation */
  789.         {
  790.         /* memory size adjusted to hold the netPool pointer at the head */
  791.         eiMclBlkConfig.memSize = ((eiMclBlkConfig.mBlkNum *
  792.                                    (MSIZE + sizeof (long)))  +
  793.                                   (eiMclBlkConfig.clBlkNum *
  794.                                    (CL_BLK_SZ + sizeof(long))));
  795.         if ((eiMclBlkConfig.memArea = (char *) memalign
  796.               (sizeof(long), eiMclBlkConfig.memSize))
  797.             == NULL)
  798.             return (ERROR);
  799.         }
  800.     eiClDescTbl[0].memArea = (char *) ((int)pDrvCtrl->pCfd + sizeCfd);
  801.     eiClDescTbl[0].memSize = ((eiClDescTbl[0].clSize + 4) *
  802.                               eiClDescTbl[0].clNum);
  803.     if (netPoolInit (pDrvCtrl->endObj.pNetPool, &eiMclBlkConfig, &eiClDescTbl [0],
  804.                      eiClDescTblNumEnt, NULL) == ERROR)
  805.         return (ERROR);
  806.     if ((pDrvCtrl->pClPoolId = netClPoolIdGet (pDrvCtrl->endObj.pNetPool, sizeof (RFD), FALSE))
  807.         == NULL)
  808.         return (ERROR);
  809.     
  810.     pDrvCtrl->tfdPool = (TFD *) ((int)eiClDescTbl[0].memArea +
  811.                                  eiClDescTbl[0].memSize);
  812.     
  813.     pDrvCtrl->pPollTfd = (TFD *) ((int)pDrvCtrl->tfdPool +
  814.                                   (sizeof(TFD) * pDrvCtrl->nTFDs));
  815.     return (OK);
  816.     }
  817. /*******************************************************************************
  818. *
  819. * ei82596Start - start the device
  820. *
  821. * RETURNS: OK or ERROR
  822. */
  823. LOCAL STATUS ei82596Start
  824.     (
  825.     END_CTRL *pDrvCtrl
  826.     )
  827.     {
  828.     int ret_val;
  829.     
  830.     DRV_LOG (DRV_DEBUG_LOAD,
  831.                   "eiStart ... beginn", 0, 0, 0, 0, 0, 0);
  832.     SYS_INT_DISABLE (pDrvCtrl);
  833.     /* Start the device */
  834.     if (ei82596DeviceStart (pDrvCtrl) == ERROR)
  835.         return ERROR; /*goto error;*/
  836.     /* run diagnostics */
  837.     if (ei82596Diag (pDrvCtrl) == ERROR)
  838.         return ERROR; /*goto error;*/
  839.     if (END_FLAGS_ISSET (&pDrvCtrl->endObj, IFF_MULTICAST))
  840.         DRV_FLAGS_SET (EI_MCAST);
  841.     
  842.     ei82596Config (pDrvCtrl);               /* configure chip */
  843.     ei82596IASetup (pDrvCtrl);              /* setup address */
  844.     /* Connect the interrupt handler */
  845.     SYS_INT_CONNECT (pDrvCtrl, ei82596Int, (int)pDrvCtrl, &ret_val);
  846.     if (ret_val == ERROR)
  847.        return (ERROR);
  848.     /* enable interrupts */
  849.     sys596IntAck (pDrvCtrl->unit);
  850.     SYS_INT_ENABLE (pDrvCtrl);
  851.     /* start the watchdog */
  852.     wdCancel(pDrvCtrl->wid); 
  853.     wdStart(pDrvCtrl->wid, (int) pDrvCtrl->wdInterval, 
  854.     (FUNCPTR) ei82596WatchDog, (int) pDrvCtrl);
  855.     /* start the receiver */
  856.     ei82596RxStartup (pDrvCtrl);
  857.     
  858.     DRV_LOG (DRV_DEBUG_LOAD,
  859.                   "eiStart ... Donen", 0, 0, 0, 0, 0, 0);
  860.     /* mark the interface -- up */
  861.     END_FLAGS_SET (&pDrvCtrl->endObj, (IFF_UP | IFF_RUNNING));
  862.     return OK;
  863.     }
  864. /*******************************************************************************
  865. *
  866. * ei82596Stop - stop the device
  867. *
  868. * This routine cancels the watchdog, disables interrupts, and resets the device.
  869. *
  870. * RETURNS: OK or ERROR
  871. */
  872. LOCAL STATUS ei82596Stop
  873.     (
  874.     END_CTRL *pDrvCtrl
  875.     )
  876.     {
  877.     int ret_val;
  878.     
  879.     /* mark the interface -- down */
  880.     END_FLAGS_CLR (&pDrvCtrl->endObj, IFF_UP | IFF_RUNNING);
  881.     wdCancel(pDrvCtrl->wid); 
  882.     SYS_INT_DISABLE( pDrvCtrl );
  883.     sys596Port (pDrvCtrl->unit, PORT_RESET, 0);
  884.     SYS_INT_DISCONNECT (pDrvCtrl, ei82596Int, (int)pDrvCtrl, &ret_val);
  885.     return OK;
  886.     }
  887. /*******************************************************************************
  888. *
  889. * ei82596Ioctl - interface ioctl procedure
  890. *
  891. * Process an interface ioctl request.
  892. */
  893. LOCAL int ei82596Ioctl
  894.     (
  895.     END_CTRL * pDrvCtrl,
  896.     int cmd,
  897.     caddr_t data
  898.     )
  899.     {
  900.     int error=0;
  901.     long value;
  902.     int savedFlags;
  903.     END_OBJ * pEndObj=&pDrvCtrl->endObj;
  904.     
  905.     DRV_LOG (DRV_DEBUG_IOCTL,
  906.                   "eiIoctln", 0, 0, 0, 0, 0, 0);
  907.     switch ((UINT)cmd)
  908.         {
  909.         case EIOCSADDR:
  910.             if (data == NULL)
  911.                 error = EINVAL;
  912.             else
  913.                 {
  914.                 /* Copy and install the new address */
  915.                 bcopy ((char *)data, (char *)END_HADDR(pEndObj),
  916.                        END_HADDR_LEN(pEndObj));
  917.                 ei82596IASetup (pDrvCtrl);
  918.                 }
  919.             break;
  920.             
  921.         case EIOCGADDR:
  922.             if (data == NULL)
  923.                 error = EINVAL;
  924.             else
  925.                 bcopy ((char *)END_HADDR(pEndObj), (char *)data,
  926.                        END_HADDR_LEN(pEndObj));
  927. #ifdef DRV_DEBUG
  928.             {
  929.             char *cp = (char *)data;
  930.             DRV_LOG (DRV_DEBUG_IOCTL,
  931.                           "EIOCGADDR: %x:%x:%x:%x:%x:%xn",
  932.                           cp[0], cp[1], cp[2], cp[3], cp[4], cp[5]);
  933.             }
  934. #endif /*DRV_DEBUG*/
  935.             break;
  936.         case EIOCSFLAGS:
  937.             value = (long) data;
  938.             if (value < 0)
  939.                 {
  940.                 value = -value;
  941.                 value--;
  942.                 END_FLAGS_CLR (pEndObj, value);
  943.                 }
  944.             else
  945.                 END_FLAGS_SET (pEndObj, value);
  946.             /* handle IFF_PROMISC and IFF_ALLMULTI */
  947.             savedFlags = DRV_FLAGS_GET();
  948.             if (END_FLAGS_ISSET (pEndObj, IFF_PROMISC))
  949.                 DRV_FLAGS_SET (EI_PROMISC);
  950.             else
  951.                 DRV_FLAGS_CLR (EI_PROMISC);
  952.             if (END_FLAGS_GET(pEndObj) & (IFF_MULTICAST | IFF_ALLMULTI))
  953.                 DRV_FLAGS_SET (EI_MCAST);
  954.             else
  955.                 DRV_FLAGS_CLR (EI_MCAST);
  956.             if ((DRV_FLAGS_GET() != savedFlags) &&
  957.                 (END_FLAGS_GET(pEndObj) & IFF_UP))
  958.                 {
  959.                 END_FLAGS_CLR(pEndObj, IFF_UP | IFF_RUNNING); /* config down */
  960.                 ei82596Config (pDrvCtrl);
  961.                 }
  962.             break;
  963.         case EIOCGFLAGS:
  964.             DRV_LOG (DRV_DEBUG_IOCTL, "EIOCGFLAGS: 0x%x: 0x%xn",
  965.                     pEndObj->flags, *(long *)data, 0, 0, 0, 0);
  966.             if (data == NULL)
  967.                 error = EINVAL;
  968.             else
  969.                 *(long *)data = END_FLAGS_GET(pEndObj);
  970.             break;
  971.         case EIOCMULTIADD:
  972.             error = ei82596MCastAdrsAdd (pDrvCtrl, (char *)data);
  973.             break;
  974.         case EIOCMULTIDEL:
  975.             error = ei82596MCastAdrsDel (pDrvCtrl, (char *)data);
  976.             break;
  977.         case EIOCMULTIGET:
  978.             error = ei82596MCastAdrsGet (pDrvCtrl, (MULTI_TABLE *)data);
  979.             break;
  980.         case EIOCPOLLSTART:
  981.             ei82596PollStart (pDrvCtrl);
  982.             break;
  983.         case EIOCPOLLSTOP:
  984.             ei82596PollStop (pDrvCtrl);
  985.             break;
  986.         case EIOCGMIB2:
  987.             if (data == NULL)
  988.                 error=EINVAL;
  989.             else
  990.                 bcopy((char *)&pEndObj->mib2Tbl, (char *)data,
  991.                       sizeof(pEndObj->mib2Tbl));
  992.             break;
  993.         default:
  994.             error = EINVAL;
  995.         }
  996.     return (error);
  997.     }
  998. /*******************************************************************************
  999. *
  1000. * ei82596MCastAdrsAdd - add a multicast address for the device
  1001. *
  1002. * This routine adds a multicast address to whatever the driver
  1003. * is already listening for.  
  1004. *
  1005. */
  1006. LOCAL STATUS ei82596MCastAdrsAdd
  1007.     (
  1008.     END_CTRL * pDrvCtrl,
  1009.     char * pAddr
  1010.     )
  1011.     {
  1012.     int retVal;
  1013.     
  1014.     DRV_LOG (DRV_DEBUG_IOCTL,
  1015.                   "eiMCastAdrsAdd - %x:%x:%x:%x:%x:%xn",
  1016.                   pAddr[0], pAddr[1], pAddr[2], pAddr[3], pAddr[4], pAddr[5]);
  1017.     retVal = etherMultiAdd (&pDrvCtrl->endObj.multiList, pAddr);
  1018.     if (retVal == ENETRESET)
  1019.         {
  1020.         pDrvCtrl->endObj.nMulti++;
  1021.         if (pDrvCtrl->endObj.nMulti > N_MCAST)
  1022.             {
  1023.             etherMultiDel (&pDrvCtrl->endObj.multiList, pAddr);
  1024.             pDrvCtrl->endObj.nMulti--;
  1025.             }
  1026.         else
  1027.             return ei82596MCastConfig (pDrvCtrl);
  1028.         }
  1029.     return ((retVal == OK) ? OK : ERROR);
  1030.     }
  1031. /*******************************************************************************
  1032. *
  1033. * ei82596MCastAdrsDel - delete a multicast address for the device
  1034. *
  1035. * This routine deletes a multicast address from the current list of
  1036. * multicast addresses.
  1037. *
  1038. */
  1039. LOCAL STATUS ei82596MCastAdrsDel
  1040.     (
  1041.     END_CTRL * pDrvCtrl,
  1042.     char *  pAddr
  1043.     )
  1044.     {
  1045.     int retVal;
  1046.     
  1047.     DRV_LOG (DRV_DEBUG_LOAD,
  1048.                   "eiMCastAdrsDeln", 0, 0, 0, 0, 0, 0);
  1049.     retVal = etherMultiDel (&pDrvCtrl->endObj.multiList, pAddr);
  1050.     if (retVal == ENETRESET)
  1051.         {
  1052.         pDrvCtrl->endObj.nMulti--;
  1053.         return ei82596MCastConfig (pDrvCtrl);
  1054.         }
  1055.     return ((retVal == OK) ? OK : ERROR);
  1056.     }
  1057. /*******************************************************************************
  1058. *
  1059. * ei82596MCastAdrsGet - get the current multicast address list
  1060. *
  1061. * This routine returns the current multicast address list in <pTable>
  1062. *
  1063. */
  1064. LOCAL STATUS ei82596MCastAdrsGet
  1065.     (
  1066.     END_CTRL * pDrvCtrl,
  1067.     MULTI_TABLE *pTable
  1068.     )
  1069.     {
  1070.     
  1071.     DRV_LOG (DRV_DEBUG_LOAD,
  1072.                   "eiMCastAdrsGetn", 0, 0, 0, 0, 0, 0);
  1073.     return (etherMultiGet (&pDrvCtrl->endObj.multiList, pTable));
  1074.     }
  1075. /*******************************************************************************
  1076. *
  1077. * ei82596MCastConfig - configure multicast addresses.
  1078. *
  1079. */
  1080. LOCAL STATUS ei82596MCastConfig
  1081.     (
  1082.     END_CTRL *pDrvCtrl
  1083.     )
  1084.     {
  1085.     int count=0;
  1086.     char *pAddr;
  1087.     ETHER_MULTI *pMCastNode;
  1088.     
  1089.     DRV_LOG (DRV_DEBUG_IOCTL,
  1090.                   "eiMCastConfign", 0, 0, 0, 0, 0, 0);
  1091.     bzero ((char *)&pDrvCtrl->pCfd->cfdMcast, sizeof (AC_MCAST));
  1092.     pAddr = (char *)pDrvCtrl->pCfd->cfdMcast.cmAddrList;
  1093.     pMCastNode = (ETHER_MULTI *)lstFirst (&pDrvCtrl->endObj.multiList);
  1094.     while (pMCastNode != NULL)
  1095.         {
  1096.         count++;
  1097.         bcopy (pMCastNode->addr, pAddr, 6);
  1098.         pAddr += 6;
  1099.         pMCastNode = (ETHER_MULTI *)lstNext (&pMCastNode->node);
  1100.         }
  1101.     pDrvCtrl->pCfd->cfdMcast.cmMcCount = count * 6; /* byte count */
  1102.     SYS_INT_DISABLE( pDrvCtrl );
  1103.     ei82596Action (pDrvCtrl, CFD_C_MASETUP);
  1104.     SYS_INT_ENABLE (pDrvCtrl);
  1105.     return (OK);
  1106.     }
  1107. /*******************************************************************************
  1108. *
  1109. * ei82596Send - arrange to transmit a packet
  1110. *
  1111. * This routine takes a NET_BUFFER and a NET_ADDRESS and sends the data in the
  1112. * NET_BUFFER to the NET_ADDRESS.
  1113. *
  1114. * RETURNS:
  1115. */
  1116. LOCAL STATUS ei82596Send
  1117.     (
  1118.     END_CTRL *pDrvCtrl,
  1119.     M_BLK_ID pMblk
  1120.     )
  1121.     {
  1122.     TFD * pTfd;
  1123.     int len;
  1124.     DRV_PRINT (DRV_DEBUG_TX, ("t "));
  1125. #if 0
  1126.     SYS_INT_DISABLE (pDrvCtrl);
  1127.     if (pDrvCtrl->txBlocked)
  1128.         {
  1129.         SYS_INT_ENABLE (pDrvCtrl);
  1130.         return (END_ERR_BLOCK);
  1131.         }
  1132.     SYS_INT_ENABLE (pDrvCtrl);
  1133. #endif    
  1134.             
  1135.     /* check device mode */
  1136.     if (DRV_FLAGS_ISSET(EI_POLLING))
  1137.         {
  1138. #if 0
  1139. #ifdef DRV_DEBUG
  1140.         if (eiDebug & DRV_DEBUG_POLL_REDIR)
  1141.             {
  1142.             ei82596PollSend (pDrvCtrl, pNetBuf);
  1143.             return (OK);
  1144.             }
  1145. #endif /*DRV_DEBUG*/        
  1146. #endif
  1147.         netMblkClChainFree (pMblk); /* free the given mBlk chain */
  1148. errno = EINVAL;
  1149.         return (ERROR);
  1150.         }
  1151.     SYS_INT_DISABLE( pDrvCtrl );
  1152.     if ((pTfd = (TFD *) ei82596QGet (&pDrvCtrl->freeQueue)) != NULL)
  1153.         {
  1154.         SYS_INT_ENABLE( pDrvCtrl );
  1155.         len = netMblkToBufCopy (pMblk, (char *)pTfd->enetHdr, NULL);
  1156.         netMblkClChainFree (pMblk);
  1157.         /* set up the byte count field; use a min frame size of ETHERSMALL */
  1158.         pTfd->count = max (ETHERSMALL, len);
  1159.         pTfd->count &= ~0xc000;
  1160.         /* arrange to to transmit the buffer */
  1161.         SYS_INT_DISABLE( pDrvCtrl );
  1162.         ei82596TxQPut (pDrvCtrl, pTfd);
  1163.         SYS_INT_ENABLE( pDrvCtrl );
  1164.         }
  1165.     else /* case if the pfd is equal to NULL */
  1166.         {
  1167.         pDrvCtrl->txBlocked = TRUE;
  1168.         SYS_INT_ENABLE( pDrvCtrl );
  1169.         return (END_ERR_BLOCK);
  1170.         }
  1171.     return (OK);
  1172.     }
  1173. /*******************************************************************************
  1174. *
  1175. * ei82596Int - entry point for handling interrupts from the 82596
  1176. *
  1177. * The interrupting events are acknowledged to the device, so that the device
  1178. * will deassert its interrupt signal.  The amount of work done here is kept
  1179. * to a minimum; the bulk of the work is defered to the netTask.  Several flags
  1180. * are used here to synchronize with task level code and eliminate races.
  1181. */
  1182. LOCAL void ei82596Int
  1183.     (
  1184.     END_CTRL *pDrvCtrl
  1185.     )
  1186.     {
  1187.     SCB *pScb=pDrvCtrl->pScb;
  1188.     int unit=pDrvCtrl->unit;
  1189.     UINT16 event;
  1190.     event = pScb->scbStatus & (SCB_S_CX | SCB_S_FR | SCB_S_CNA | SCB_S_RNR);
  1191.     DRV_PRINT (DRV_DEBUG_INT, ("eiInt: event=0x%xn", event));
  1192.     ei82596Command (pDrvCtrl, event);        /* ack the events */
  1193.     sys596IntAck (unit);                     /* ack 596 interrupt */
  1194.     /* Handle transmitter interrupt */
  1195.     if (event & SCB_S_CNA)                   /* reclaim tx tfds */
  1196.         {
  1197.         pDrvCtrl->wdTxTimeout = 0;           /* reset timeout count */
  1198.         ei82596QCat (&pDrvCtrl->cleanQueue, &pDrvCtrl->cblQueue);
  1199.         ei82596QInit (&pDrvCtrl->cblQueue);
  1200.         
  1201.         if (! pDrvCtrl->txCleaning)          /* not cleaning? */
  1202.             {
  1203.             pDrvCtrl->txCleaning = TRUE;
  1204.             /* defer cleanup */
  1205.             netJobAdd ((FUNCPTR) ei82596TxCleanQ, (int) pDrvCtrl, 0, 0, 0, 0);
  1206.             }
  1207.         if (pDrvCtrl->txBlocked)
  1208.             {
  1209.             /* potential race condition ??? */
  1210.             pDrvCtrl->txBlocked = FALSE;
  1211.             netJobAdd ((FUNCPTR) muxTxRestart, (int) &pDrvCtrl->endObj, 0, 0,
  1212.                        0, 0);
  1213.             }
  1214.         if (pDrvCtrl->txQueue.head != NULL)  /* anything to flush? */
  1215.             ei82596TxQFlush (pDrvCtrl);      /* flush the tx q */
  1216.         else
  1217.             pDrvCtrl->txIdle = TRUE;      /* transmitter idle */
  1218.         }
  1219.     /* Handle receiver interrupt */
  1220.     if (event & SCB_S_FR)
  1221. {
  1222. pDrvCtrl->wdRxTimeout = 0;           /* reset timeout count */
  1223. if (! pDrvCtrl->rxHandling)
  1224.             {
  1225.             pDrvCtrl->rxHandling = TRUE;
  1226.             (void) netJobAdd ((FUNCPTR) ei82596RxIntHandle,
  1227.                               (int) pDrvCtrl,0, 0, 0, 0);/* netTask processes */
  1228.     }
  1229.         }
  1230.     }
  1231. /*******************************************************************************
  1232. *
  1233. * ei82596TxCleanQ - checks errors in completed TFDs and moves TFDs to free queue
  1234. *
  1235. * This routine is executed by netTask.  It "cleans" the TFDs on the clean-up
  1236. * queue by checking each one for errors and then returning the TFD to the
  1237. * "free TFD" queue.  The startup routine is sometimes called here to eliminate
  1238. * the lock-out case where the driver input queue is full but there are no
  1239. * TFDs available.
  1240. */
  1241. LOCAL void ei82596TxCleanQ
  1242.     (
  1243.     END_CTRL *pDrvCtrl
  1244.     )
  1245.     {
  1246.     TFD * pTfd;
  1247.     do
  1248.         {
  1249.         pDrvCtrl->txCleaning = TRUE;
  1250.         /* process transmitted frames */
  1251.         while (1)
  1252.             {
  1253.             /* INT and SEM locks while manipulating this queue */
  1254.             END_TX_SEM_TAKE (&pDrvCtrl->endObj, WAIT_FOREVER);
  1255.             SYS_INT_DISABLE( pDrvCtrl );
  1256.             pTfd = (TFD*) ei82596QGet ((EI_LIST *)&pDrvCtrl->cleanQueue);
  1257.             SYS_INT_ENABLE( pDrvCtrl );
  1258.             END_TX_SEM_GIVE (&pDrvCtrl->endObj);
  1259.             
  1260.             if (pTfd == NULL)
  1261.                 break;
  1262.             if (!(pTfd->status & CFD_S_OK))          /* packet not sent */
  1263.                 {
  1264.                 END_ERR_ADD (&pDrvCtrl->endObj, MIB2_OUT_ERRS,  +1);
  1265.                 END_ERR_ADD (&pDrvCtrl->endObj, MIB2_OUT_UCAST, -1);
  1266.                 }
  1267.             /* return to tfdQ */
  1268.             END_TX_SEM_TAKE (&pDrvCtrl->endObj, WAIT_FOREVER);
  1269.             ei82596QPut (pDrvCtrl,(EI_LIST *)&pDrvCtrl->freeQueue,
  1270.                          (EI_NODE*)pTfd);
  1271. #ifdef DRV_DEBUG
  1272.             nLoan--;
  1273. #endif
  1274.             END_TX_SEM_GIVE (&pDrvCtrl->endObj);
  1275.             
  1276.             }
  1277.         pDrvCtrl->txCleaning = FALSE;
  1278.         }
  1279.     while (pDrvCtrl->cleanQueue.head != NULL);       /* check again */
  1280.     }
  1281. /*******************************************************************************
  1282. *
  1283. * ei82596RxIntHandle - task level interrupt service for input packets
  1284. *
  1285. * This routine is called at task level indirectly by the interrupt
  1286. * service routine to do any message received processing.
  1287. */
  1288. LOCAL void ei82596RxIntHandle
  1289.     (
  1290.     END_CTRL *pDrvCtrl
  1291.     )
  1292.     {
  1293.     RFD *pRfd;
  1294.     do
  1295.         {
  1296.         pDrvCtrl->rxHandling = TRUE;         /* interlock with ei82596Int()*/
  1297.         while ((pRfd = ei82596RxQGet (pDrvCtrl)) != NULL)
  1298.             ei82596Recv (pDrvCtrl, pRfd);
  1299.         pDrvCtrl->rxHandling = FALSE;        /* interlock with ei82596Int()*/
  1300.         }
  1301.     while (ei82596RxQFull (pDrvCtrl));          /* make sure rx q still empty */
  1302.     }
  1303. /*******************************************************************************
  1304. *
  1305. * ei82596Recv - pass a received frame to the upper layer
  1306. *
  1307. *
  1308. * RETURNS: 
  1309. */
  1310. LOCAL void ei82596Recv
  1311.     (
  1312.     END_CTRL * pDrvCtrl,
  1313.     RFD * pRfd
  1314.     )
  1315.     {
  1316.     RFD *  pRfdLoaned  = NULL;
  1317.     M_BLK_ID pMblk = NULL;
  1318.     CL_BLK_ID pClBlk = NULL;
  1319.     /* process the frame, if there are no errors */
  1320.     if ((pRfd->status & (RFD_S_OK | RFD_S_COMPLETE)) != 
  1321.      (RFD_S_OK | RFD_S_COMPLETE))
  1322. goto eiRecvError;
  1323.     if ((pMblk = netMblkGet (pDrvCtrl->endObj.pNetPool,
  1324.                              M_DONTWAIT, MT_DATA)) == NULL)
  1325.         goto eiRecvError;
  1326.     if ((pClBlk = netClBlkGet (pDrvCtrl->endObj.pNetPool, M_DONTWAIT)) == NULL)
  1327.         goto eiRecvError;
  1328.     
  1329.     if ((pRfdLoaned = (RFD *) netClusterGet (pDrvCtrl->endObj.pNetPool,
  1330.                                              pDrvCtrl->pClPoolId)) == NULL)
  1331.         goto eiRecvError;
  1332.     /* offset pRfdLoaned if needed */
  1333.     pRfdLoaned = (RFD *) (((char *) pRfdLoaned) + pDrvCtrl->offset );
  1334.     DRV_PRINT (DRV_DEBUG_RX, ("r "));
  1335.     netClBlkJoin (pClBlk, ((char *)pRfd) - pDrvCtrl->offset,
  1336.   sizeof (RFD) + pDrvCtrl->offset,
  1337.   NULL, 0, 0, 0);
  1338.     netMblkClJoin (pMblk, pClBlk);
  1339.     END_ERR_ADD (&pDrvCtrl->endObj, MIB2_IN_UCAST, +1);
  1340.     pMblk->mBlkHdr.mFlags  |= M_PKTHDR;
  1341.     pMblk->mBlkHdr.mData   = (char *)&pRfd->enetHdr [0];
  1342.     pMblk->mBlkHdr.mLen = pRfd->count & ~0xc000;
  1343.     pMblk->mBlkPktHdr.len  = pMblk->mBlkHdr.mLen;
  1344.     /* return the buffer to the receive queue */
  1345.     ei82596RxQPut (pDrvCtrl, (RFD *)pRfdLoaned);
  1346.     
  1347.     END_RCV_RTN_CALL (&pDrvCtrl->endObj, pMblk);
  1348.     return; 
  1349. eiRecvError:
  1350.     END_ERR_ADD (&pDrvCtrl->endObj, MIB2_IN_ERRS, +1);
  1351.     /* return the buffer to the receive queue */
  1352.     ei82596RxQPut (pDrvCtrl, (RFD *)pRfd);
  1353.     if (pClBlk)
  1354.         netClBlkFree (pDrvCtrl->endObj.pNetPool, pClBlk); 
  1355.     if (pMblk)
  1356.         netMblkFree (pDrvCtrl->endObj.pNetPool, pMblk); 
  1357.     return;
  1358.     }
  1359. /*******************************************************************************
  1360. *
  1361. * ei82596PollStart - start polling mode
  1362. *
  1363. * RETURNS:
  1364. */
  1365. LOCAL STATUS ei82596PollStart
  1366.     (
  1367.     END_CTRL  *pDrvCtrl
  1368.     )
  1369.     {
  1370.     int intLevel;
  1371.     DRV_LOG (DRV_DEBUG_POLL, "PollStart", 0, 1, 2, 3, 4, 5 );
  1372.     intLevel = intLock();                         /* lock interrupts */
  1373.     SYS_INT_DISABLE( pDrvCtrl );
  1374.     DRV_FLAGS_SET (EI_POLLING);
  1375.     intUnlock (intLevel);                         /* unlock interupts */
  1376.     return (OK);
  1377.     }
  1378. /*******************************************************************************
  1379. *
  1380. * ei82596PollStop - stop polling mode
  1381. *
  1382. * RETURNS:
  1383. */
  1384. LOCAL STATUS ei82596PollStop
  1385.     (
  1386.     END_CTRL  *pDrvCtrl
  1387.     )
  1388.     {
  1389.     int intLevel;
  1390.     DRV_LOG (DRV_DEBUG_POLL, "PollStop", 0, 1, 2, 3, 4, 5);
  1391.     
  1392.     intLevel = intLock();
  1393.     SYS_INT_ENABLE( pDrvCtrl );
  1394.     DRV_FLAGS_CLR (EI_POLLING);
  1395.     intUnlock (intLevel);
  1396.     return (OK);
  1397.     }
  1398. /*******************************************************************************
  1399. *
  1400. * ei82596PollSend - transmit a packet in polled mode
  1401. *
  1402. * RETURNS:
  1403. */
  1404. LOCAL STATUS ei82596PollSend
  1405.     (
  1406.     END_CTRL  *pDrvCtrl,
  1407.     M_BLK_ID pMblk /* pointer to the mBlk/cluster pair */
  1408.     )
  1409.     {
  1410.     TFD  *pTfd;
  1411.     char  *pTemp;
  1412.     int len;
  1413.     DRV_LOG (DRV_DEBUG_POLL_TX, "T", 0, 1, 2, 3, 4, 5);
  1414.     /* check if the command unit is active */
  1415.     if (pDrvCtrl->pScb->scbStatus & SCB_S_CUACTIVE)
  1416.         {
  1417.         DRV_LOG (DRV_DEBUG_POLL_TX, "e ", 0, 1, 2, 3, 4, 5);
  1418.         return (EAGAIN);
  1419.         }
  1420.     /* Is this ours? */
  1421.     pTfd = pDrvCtrl->pPollTfd;
  1422.     len = netMblkToBufCopy (pMblk, (char *)pTfd->enetHdr, NULL);
  1423.     
  1424.     DRV_LOG (DRV_DEBUG_POLL_TX, "h ", 0, 1, 2, 3, 4, 5);
  1425.         
  1426.     pTfd->count = max (len, ETHERSMALL) & ~0xc000;
  1427.     /* transmit the buffer */
  1428.     pTfd->status   = 0;
  1429.     pTfd->command  = CFD_C_XMIT | CFD_C_EL;
  1430.     pTfd->count   |= TFD_CNT_EOF;
  1431.     pTfd->reserved = 0;
  1432.     LINK_WR (&pTfd->lBufDesc, NULL);
  1433.     
  1434.     pTemp = CACHE_DRV_VIRT_TO_PHYS (&pDrvCtrl->cacheFuncs, pTfd);
  1435.     LINK_WR (&pDrvCtrl->pScb->pCB, pTemp);
  1436.     ei82596Command (pDrvCtrl, SCB_C_CUSTART);
  1437.     
  1438.     /* wait for the command to complete */
  1439.     while (pDrvCtrl->pScb->scbStatus & SCB_S_CUACTIVE)
  1440.         ;                       /* HELP: timeout */
  1441.     /* update statistics */
  1442.     
  1443.     if (pTfd->status & CFD_S_OK)
  1444.         END_ERR_ADD (&pDrvCtrl->endObj, MIB2_OUT_UCAST, +1);
  1445.     if (pTfd->status & CFD_S_RETRY)
  1446.         END_ERR_ADD (&pDrvCtrl->endObj, MIB2_OUT_ERRS, +1);
  1447.     
  1448.     return (OK);
  1449.     }
  1450. /*******************************************************************************
  1451. *
  1452. * ei82596PollReceive - receive a packet in polled mode
  1453. *
  1454. * RETURNS:
  1455. */
  1456. LOCAL STATUS ei82596PollReceive
  1457.     (
  1458.     END_CTRL *pDrvCtrl,
  1459.     M_BLK_ID pMblk
  1460.     )
  1461.     {
  1462.     RFD  *pRfd;
  1463.     int len;
  1464.     while ((pRfd = ei82596RxQGet (pDrvCtrl)) != NULL)
  1465.         {
  1466.         len = (pRfd->count & ~0xc000);
  1467.         if (((pRfd->status & (RFD_S_OK | RFD_S_COMPLETE)) !=
  1468.              (RFD_S_OK | RFD_S_COMPLETE)) ||
  1469.             (pMblk->mBlkHdr.mLen < len) ||
  1470.             (!(pMblk->mBlkHdr.mFlags & M_EXT)))
  1471.             {
  1472.             END_ERR_ADD (&pDrvCtrl->endObj, MIB2_IN_ERRS, +1);
  1473.             ei82596RxQPut (pDrvCtrl, pRfd);
  1474.             continue;
  1475.             }
  1476.         END_ERR_ADD (&pDrvCtrl->endObj, MIB2_IN_UCAST, +1);
  1477.         pMblk->mBlkHdr.mFlags  |= M_PKTHDR;
  1478.         pMblk->mBlkHdr.mLen = len;
  1479.         pMblk->mBlkPktHdr.len  = pMblk->mBlkHdr.mLen;
  1480.         bcopy ((char *)pRfd->enetHdr, (char *)pMblk->mBlkHdr.mData, len);
  1481.         ei82596RxQPut (pDrvCtrl, pRfd);
  1482.         DRV_LOG (DRV_DEBUG_POLL_RX, "R+ ", 0, 1, 2, 3, 4, 5);
  1483.         return (OK);
  1484.         }
  1485.     return (EAGAIN);
  1486.     }
  1487. /*******************************************************************************
  1488. *
  1489. * ei82596DeviceStart - reset and start the device
  1490. *
  1491. * This routine assumes interrupts from the device have been disabled, and
  1492. * that the driver control structure has been initialized.
  1493. */
  1494. LOCAL STATUS ei82596DeviceStart
  1495.     (
  1496.     END_CTRL  *pDrvCtrl
  1497.     )
  1498.     {
  1499.     void     *pTemp;
  1500.     SCP      *pScp;                       /* system config ptr */
  1501.     ISCP     *pIscp;                      /* intermediate system config ptr */
  1502.     SCB      *pScb;                       /* system control block ptr */
  1503.     int      unit=pDrvCtrl->unit;
  1504.     pDrvCtrl->txBlocked  = FALSE;
  1505.     /* Get pointers */
  1506.     pScp = pDrvCtrl->pScp;
  1507.     pIscp = pDrvCtrl->pIscp;
  1508.     pScb = pDrvCtrl->pScb;
  1509.     /* perform board specific initializations */
  1510.     sys596Init (pDrvCtrl->unit);
  1511.     /* Issue the reset operation to the device */
  1512.     sys596Port (unit, PORT_RESET, 0);
  1513.     /* Initialize the SCP */
  1514.     pScp->scpRsv1 =
  1515.         pScp->scpRsv2 =
  1516.         pScp->scpRsv3 = 0;
  1517.     pScp->scpSysbus = pDrvCtrl->sysbus;
  1518.     pTemp = CACHE_DRV_VIRT_TO_PHYS (&pDrvCtrl->cacheFuncs, pIscp);
  1519.     LINK_WR (&pScp->pIscp, pTemp);              /* point SCP to ISCP */
  1520.     /* Initialize the ISCP */
  1521.     pIscp->iscpBusy = 1;
  1522.     pIscp->iscpRsv1 = 0;
  1523.     pTemp = CACHE_DRV_VIRT_TO_PHYS (&pDrvCtrl->cacheFuncs, pScb);
  1524.     LINK_WR (&pIscp->pScb, pTemp);              /* point ISCP to SCB */
  1525.     /* Initialize the SCB */
  1526.     bzero ((char *)pScb, sizeof (SCB));
  1527.     /* Tell the device where the SCP is located */
  1528.     pTemp = CACHE_DRV_VIRT_TO_PHYS (&pDrvCtrl->cacheFuncs, pScp);
  1529.     sys596Port (unit, PORT_NEWSCP, (UINT32) pTemp);
  1530.     sys596ChanAtn (unit);
  1531.     /*
  1532.      * The device will now read our SCP and ISCP. It will clear the busy
  1533.      * flag in the ISCP.
  1534.      */
  1535.     taskDelay (50);
  1536.     
  1537.     if ( pIscp->iscpBusy == 1 )
  1538.         {
  1539.         printf ("nei%d: device did not initializen", pDrvCtrl->unit);
  1540.         return (ERROR);
  1541.         }
  1542.     return (OK);
  1543.     }
  1544. /*******************************************************************************
  1545. *
  1546. * ei82596Diag - format and issue a diagnostic command
  1547. *
  1548. * Assumes that device interrupts are disabled.
  1549. */
  1550. LOCAL STATUS ei82596Diag
  1551.     (
  1552.     END_CTRL  *pDrvCtrl
  1553.     )
  1554.     {
  1555.     bzero ((char *)pDrvCtrl->pCfd, sizeof (CFD));   /* zero command frame */
  1556.     ei82596Action (pDrvCtrl, CFD_C_DIAG);     /* run diagnostics */
  1557.     if (!(pDrvCtrl->pCfd->cfdStatus & CFD_S_OK))
  1558.         {
  1559.         printErr ("eiDiag: i82596 diagnostics failed. cfdStatus=0x%xn",
  1560.                   pDrvCtrl->pCfd->cfdStatus);
  1561.         return (ERROR);
  1562.         }
  1563.     return (OK);
  1564.    }
  1565. /*******************************************************************************
  1566. *
  1567. * ei82596Config - format and issue a config command
  1568. */
  1569. LOCAL void ei82596Config
  1570.     (
  1571.     END_CTRL  *pDrvCtrl
  1572.     )
  1573.     {
  1574.     bzero ((char *)pDrvCtrl->pCfd, sizeof (CFD));   /* zero command frame */
  1575.     /* Recommeded i82596 User's Manual configuration values.  Note that
  1576.      * the original manual, #296443-001, was full of errors.  Errors in the
  1577.      * description of the config bytes that I am aware of are noted below.
  1578.      * It is possible there are further errors.  Intel has replaced the
  1579.      * manual with #296853-001, which does correct some errors, but not all.
  1580.      */
  1581.     pDrvCtrl->pCfd->cfdConfig.ccByte8  = 0x8e;
  1582.     pDrvCtrl->pCfd->cfdConfig.ccByte9  = 0xc8;
  1583.     /* The manual is wrong about bit 7 in byte 10.
  1584.      * A '0' allows reception of bad packets.
  1585.      * A '1' causes rejection of bad packets.
  1586.      */
  1587.     pDrvCtrl->pCfd->cfdConfig.ccByte10 = 0xc0;
  1588.     pDrvCtrl->pCfd->cfdConfig.ccByte11 = 0x2e;      /* loopback, NSAI */
  1589.     pDrvCtrl->pCfd->cfdConfig.ccByte12 = 0x00;
  1590.     pDrvCtrl->pCfd->cfdConfig.ccByte13 = 0x60;
  1591.     pDrvCtrl->pCfd->cfdConfig.ccByte14 = 0x00;
  1592.     pDrvCtrl->pCfd->cfdConfig.ccByte15 = 0xf2;
  1593.     
  1594.     pDrvCtrl->pCfd->cfdConfig.ccByte16 = 
  1595.         DRV_FLAGS_ISSET (EI_PROMISC) ? 0x01 : 0x00;
  1596.         
  1597.     pDrvCtrl->pCfd->cfdConfig.ccByte17 = 0x00;
  1598.     pDrvCtrl->pCfd->cfdConfig.ccByte18 = 0x40;
  1599.     /* The manual is wrong about 2 bits in byte 19.
  1600.      * Bit 5, multicast, a '1' disables.
  1601.      * Bit 2, include CRC, a '1' disables.
  1602.      */
  1603.     pDrvCtrl->pCfd->cfdConfig.ccByte19 =
  1604.         DRV_FLAGS_ISSET (EI_MCAST) ? 0xdf : 0xff;
  1605.     
  1606.     pDrvCtrl->pCfd->cfdConfig.ccByte20 = 0x00;
  1607.     pDrvCtrl->pCfd->cfdConfig.ccByte21 = 0x3f;
  1608.     ei82596Action (pDrvCtrl, CFD_C_CONFIG);   /* configure the chip */
  1609.     }
  1610. /*******************************************************************************
  1611. *
  1612. * eiIASetup - format and issue an interface address command
  1613. */
  1614. LOCAL void ei82596IASetup
  1615.     (
  1616.     END_CTRL * pDrvCtrl
  1617.     )
  1618.     {
  1619.     bzero ((char *)pDrvCtrl->pCfd, sizeof (CFD));  /* zero command frame */
  1620.     bcopy   (
  1621.             (char *)END_HADDR(&pDrvCtrl->endObj),
  1622.             (char *)pDrvCtrl->pCfd->cfdIASetup.ciAddress,
  1623.             EADDR_LEN
  1624.             );
  1625.     ei82596Action (pDrvCtrl, CFD_C_IASETUP); /* setup the address */
  1626.     }
  1627. /*******************************************************************************
  1628. *
  1629. * ei82596RxStartup - start up the Receive Unit
  1630. *
  1631. * Starts up the Receive Unit.  Assumes that the receive structures are set up.
  1632. */
  1633. LOCAL void ei82596RxStartup
  1634.     (
  1635.     END_CTRL *pDrvCtrl
  1636.     )
  1637.     {
  1638.     SCB *pScb = pDrvCtrl->pScb;
  1639.     void * pTemp;
  1640.     if (pScb->scbStatus & SCB_S_RUREADY)          /* already running */
  1641.         {
  1642.         return;
  1643.         }
  1644.     pTemp = CACHE_DRV_VIRT_TO_PHYS (&pDrvCtrl->cacheFuncs, pDrvCtrl->pFreeRfd);
  1645.     LINK_WR (&pScb->pRF, pTemp);                  /* point to free Rfd */
  1646.     if (! DRV_FLAGS_ISSET (EI_POLLING))
  1647.         SYS_INT_DISABLE( pDrvCtrl );
  1648.     if ((pScb->scbStatus & SCB_S_RUMASK) != SCB_S_RUIDLE)
  1649.         ei82596Command (pDrvCtrl, SCB_C_RUABORT); /* abort if not idle */
  1650.     ei82596Command (pDrvCtrl, SCB_C_RUSTART);     /* start receive unit */
  1651.     if (! DRV_FLAGS_ISSET (EI_POLLING))
  1652.         SYS_INT_ENABLE( pDrvCtrl );
  1653.     }
  1654. /*******************************************************************************
  1655. *
  1656. * ei82596Action - execute the specified action with the CFD
  1657. *
  1658. * Do the command contained in the CFD synchronously, so that we know
  1659. * it's complete upon return.  This routine assumes that interrupts from the
  1660. * device have been disabled.
  1661. */
  1662. LOCAL void ei82596Action
  1663.     (
  1664.     END_CTRL *pDrvCtrl,
  1665.     UINT16 action
  1666.     )
  1667.     {
  1668.     void *pTemp;
  1669.     CFD *pCfd;
  1670.     SCB *pScb;
  1671.     int unit=pDrvCtrl->unit;
  1672.     pCfd = pDrvCtrl->pCfd;
  1673.     pScb = pDrvCtrl->pScb;
  1674.     while (1)                   /* wait for idle command unit */
  1675.         {
  1676.         if ((pScb->scbStatus & SCB_S_CUMASK) == SCB_S_CUIDLE)
  1677.             break;
  1678.         }
  1679.     { /* Prepare and issue the command to the device */
  1680.     /* fill in CFD */
  1681.     pCfd->cfdStatus  = 0;                       /* clear status */
  1682.     pCfd->cfdCommand = CFD_C_EL | action;       /* fill in action */
  1683.     LINK_WR (&pCfd->link, NULL);                /* terminate link */
  1684.     /* and the SCB */
  1685.     pScb->scbCommand =
  1686.                         SCB_S_CX |              /* ack any events */
  1687.                         SCB_S_FR |
  1688.                         SCB_S_CNA |
  1689.                         SCB_S_RNR |
  1690.                         SCB_C_CUSTART;          /* start command unit */
  1691.     pTemp = CACHE_DRV_VIRT_TO_PHYS (&pDrvCtrl->cacheFuncs, pCfd);
  1692.     LINK_WR (&pScb->pCB, pTemp);                /* point chip at CFD */
  1693.     sys596ChanAtn (unit);               /* notify device of new command */
  1694.     }
  1695.     while (1)               /* wait for command acceptance and interrupt */
  1696.         {
  1697.         if ((pScb->scbCommand == 0) && (pScb->scbStatus & SCB_S_CNA))
  1698.             break;
  1699.         }
  1700.     /* Acknowledge the event to the device */
  1701.     pScb->scbCommand = (SCB_S_CX | SCB_S_CNA);
  1702.     sys596ChanAtn (unit);
  1703.     while (1)               /* wait for acknowledge acceptance */
  1704.         {
  1705.         if (pScb->scbCommand == 0)
  1706.             break;
  1707.         }
  1708.     }
  1709. /*******************************************************************************
  1710. *
  1711. * ei82596Command - deliver a command to the 82596 via SCB
  1712. *
  1713. * This function causes the device to execute a command.  It should be called
  1714. * with interrupts from the device disabled.  An error status is returned if
  1715. * the command field does not return to zero, from a previous command, in a
  1716. * reasonable amount of time.
  1717. */
  1718. LOCAL STATUS ei82596Command
  1719.     (
  1720.     END_CTRL *pDrvCtrl,
  1721.     UINT16    cmd
  1722.     )
  1723.     {
  1724.     int loopy;
  1725.     SCB * pScb;
  1726.     pScb = pDrvCtrl->pScb;
  1727.     for (loopy = 0x8000; loopy--;)
  1728.         {
  1729.         if (pScb->scbCommand == 0)                  /* wait for cmd zero */
  1730.             break;
  1731.         }
  1732.     if (loopy > 0)
  1733.         {
  1734.         pScb->scbCommand = cmd;                     /* fill in command */
  1735.         sys596ChanAtn (pDrvCtrl->unit);             /* channel attention */
  1736.         return (OK);
  1737.         }
  1738.     else
  1739.         {
  1740.         logMsg("ei driver: command field frozenn", 0, 0, 0, 0, 0, 0);
  1741.         return (ERROR);
  1742.         }
  1743.     }
  1744. /*******************************************************************************
  1745. *
  1746. * ei82596DeviceRestart - reset the chip and reinitialize the tx and rx queues
  1747. *
  1748. */
  1749. LOCAL void ei82596DeviceRestart
  1750.     (
  1751.     END_CTRL * pDrvCtrl
  1752.     )
  1753.     {
  1754.     EI_LIST tmpQueue;
  1755.     EI_NODE     *pNode;
  1756.     BOOL        doMuxTxRestart;        /* Do we need to restart the mux? */
  1757.     int intLockLevel;
  1758.     /* mark the interface -- down */
  1759.     END_FLAGS_CLR (&pDrvCtrl->endObj, (IFF_UP | IFF_RUNNING));
  1760.     /* disable interrupts */
  1761.     SYS_INT_DISABLE( pDrvCtrl );
  1762.     doMuxTxRestart = pDrvCtrl->txBlocked;
  1763.     /* reset the device */
  1764.     if (ei82596DeviceStart (pDrvCtrl) == ERROR)
  1765.         return;
  1766.     /* discard the current cbl list, thread it to clean list */
  1767.     END_TX_SEM_TAKE (&pDrvCtrl->endObj, WAIT_FOREVER);
  1768.     ei82596QCat (&pDrvCtrl->cleanQueue, &pDrvCtrl->cblQueue);
  1769.     ei82596QInit (&pDrvCtrl->cblQueue);
  1770.     END_TX_SEM_GIVE (&pDrvCtrl->endObj);
  1771.             
  1772.     /* reset watchdog timer counts */
  1773.     pDrvCtrl->wdTxTimeout = 0;
  1774.     pDrvCtrl->wdRxTimeout = 0;
  1775.     /* stop the receiver, and command units */
  1776.     ei82596Command (pDrvCtrl, SCB_C_RUABORT);
  1777.     ei82596Command (pDrvCtrl, SCB_C_CUABORT);
  1778.     
  1779.     if (ei82596Diag (pDrvCtrl) == ERROR)
  1780.         return;
  1781.     ei82596Config (pDrvCtrl);
  1782.     ei82596IASetup (pDrvCtrl);
  1783.     /* If we are not cleaning now, schedule one */
  1784.     if (! pDrvCtrl->txCleaning)          
  1785.         {
  1786.         pDrvCtrl->txCleaning = TRUE;
  1787.         netJobAdd ((FUNCPTR) ei82596TxCleanQ, (int) pDrvCtrl, 0, 0, 0, 0);
  1788.         }
  1789.     if (pDrvCtrl->txQueue.head != NULL)      /* anything to flush? */
  1790.         ei82596TxQFlush (pDrvCtrl);          /* flush the tx q */
  1791.     else
  1792.         pDrvCtrl->txIdle = TRUE;             /* transmitter idle */
  1793.     /* interlock with ei82596Int() -- SPR 70154
  1794.      * 
  1795.      * When restarting the device, we normally go through the
  1796.      * list of RFDs and simply drop packets which have been
  1797.      * queued but not yet processed.  However, we do not want
  1798.      * to do that if the interrupt handler is running, since
  1799.      * that could result in dropped RFDs and a non-functional
  1800.      * interface.  So, we use the rxHandling mechanism
  1801.      * intended to provide communication between the ISR and
  1802.      * the ei82596RxIntHandle().
  1803.      * 
  1804.      * There are two other things relevant to this.  First,
  1805.      * this is a real corner case, which is not likely to
  1806.      * happen often.  Second, if we don't process the queue
  1807.      * here, then the results will be that old frames will be
  1808.      * sent up to the network stack, which is not really a
  1809.      * terrible thing.  So, if an interrupt is already being
  1810.      * processed, simply avoid processing the RX queue.
  1811.      */
  1812.     intLockLevel = intLock();
  1813.     if ( ! pDrvCtrl->rxHandling )
  1814.         {
  1815. pDrvCtrl->rxHandling = TRUE;
  1816. intUnlock(intLockLevel);
  1817. /* process the rx queue */
  1818. tmpQueue = pDrvCtrl->rxQueue;
  1819. ei82596QInit (&pDrvCtrl->rxQueue);
  1820. pDrvCtrl->pFreeRfd = NULL;
  1821. while ((pNode = ei82596QGet (&tmpQueue)) != NULL)
  1822.     ei82596RxQPut (pDrvCtrl, (RFD *)pNode);
  1823. }
  1824.     else
  1825. {
  1826. intUnlock(intLockLevel);
  1827. }
  1828.     /* We may have missed an interrupt, since rxHandling was TRUE and
  1829.      * ei82596Int() drops interrupts when that is so.
  1830.      *
  1831.      * Call the handler, just in case.  ei82596RxIntHandle() will
  1832.      * just return if there is no work for it to do.
  1833.      */
  1834.     (void) netJobAdd ((FUNCPTR) ei82596RxIntHandle,
  1835.       (int) pDrvCtrl,0, 0, 0, 0);
  1836.     /* mark the interface -- up */
  1837.     END_FLAGS_SET (&pDrvCtrl->endObj, (IFF_UP | IFF_RUNNING));
  1838.     /* enable interrupts */
  1839.     SYS_INT_ENABLE( pDrvCtrl );
  1840.     if (doMuxTxRestart)
  1841. muxTxRestart (&pDrvCtrl->endObj);
  1842.     wdStart (pDrvCtrl->wid, (int) pDrvCtrl->wdInterval, 
  1843.              (FUNCPTR) ei82596WatchDog, (int)pDrvCtrl);
  1844.     return;
  1845.     }
  1846. /*******************************************************************************
  1847. *
  1848. * ei82596TxQPut - place a transmit frame on the transmit queue
  1849. *
  1850. * The TFD has been filled in with the network pertinent data.  This
  1851. * routine will enqueue the TFD for transmission and attempt to feed
  1852. * the queue to the device.
  1853. */
  1854. LOCAL void ei82596TxQPut
  1855.     (
  1856.     END_CTRL * pDrvCtrl,
  1857.     TFD * pTfd
  1858.     )
  1859.     {
  1860.     pTfd->status    = 0;                     /* fill in TFD fields */
  1861.     pTfd->command   = CFD_C_XMIT;            /* EL set later */
  1862.     pTfd->count     |= TFD_CNT_EOF;          /* data kept in frame */
  1863.     pTfd->reserved  = 0;                     /* must be zero */
  1864.     LINK_WR (& pTfd->lBufDesc, NULL);        /* TBDs not used */
  1865.     SYS_INT_DISABLE( pDrvCtrl );
  1866.     /* enqueue the TFD */
  1867.     ei82596QPut (pDrvCtrl, (EI_LIST *)&pDrvCtrl->txQueue, (EI_NODE*)pTfd);
  1868.     if (pDrvCtrl->txIdle)                    /* transmitter idle */
  1869.         ei82596TxQFlush (pDrvCtrl);          /* flush txQueue */
  1870.     SYS_INT_ENABLE( pDrvCtrl );
  1871.     }
  1872. /*******************************************************************************
  1873. *
  1874. * ei82596TxQFlush - make cmd unit of device start processing cmds
  1875. *
  1876. * This routine flushes the contents of the txQ to the cblQ and starts the
  1877. * device transmitting the cblQ.  Called only if transmit queue is not empty.
  1878. * Sometimes called from interrupt handler.
  1879. */
  1880. LOCAL void ei82596TxQFlush
  1881.     (
  1882.     END_CTRL *pDrvCtrl
  1883.     )
  1884.     {
  1885.     void * pTemp;
  1886.     extern int sysClkRateGet();     /* we call this */
  1887.     ((TFD*)pDrvCtrl->txQueue.tail)->command |= CFD_C_EL;/* EL terminate q */
  1888.     
  1889.     pDrvCtrl->cblQueue.head = pDrvCtrl->txQueue.head;   /* remember cbl head */
  1890.     pDrvCtrl->cblQueue.tail = pDrvCtrl->txQueue.tail;   /* remember cbl tail */
  1891.     ei82596QInit ((EI_LIST *)&pDrvCtrl->txQueue);       /* tx queue now empty */
  1892.     pTemp = CACHE_DRV_VIRT_TO_PHYS (&pDrvCtrl->cacheFuncs,
  1893.                                     pDrvCtrl->cblQueue.head);
  1894.     LINK_WR (&pDrvCtrl->pScb->pCB, pTemp);   /* point CU to head */
  1895.     pDrvCtrl->txIdle=FALSE;                  /* transmitter busy */
  1896.     /* start command unit */
  1897.     ei82596Command (pDrvCtrl, SCB_C_CUSTART);
  1898.     }
  1899. /*******************************************************************************
  1900. *
  1901. * ei82596RxQPut - return a RFD to the receive queue for use by the device
  1902. */
  1903. LOCAL void ei82596RxQPut
  1904.     (
  1905.     END_CTRL *pDrvCtrl,
  1906.     RFD *pRfd
  1907.     )
  1908.     {
  1909.     RFD * pTail;
  1910.     RFD * pFree; /* temporary for updating pFreeRfd */
  1911.     pRfd->status    = 0;                    /* clear status */
  1912.     pRfd->command   = CFD_C_EL;             /* new end of list */
  1913.     pRfd->count     = 0;                    /* clear actual count */
  1914.     pRfd->bufSize   = ETHERMTU + EH_SIZE;   /* fill in size */
  1915.     LINK_WR (& pRfd->lBufDesc, 0xffffffff); /* no RBD used */
  1916.     pTail = (RFD *) pDrvCtrl->rxQueue.tail; /* remember tail */
  1917.     /* Put the RFD on the list */
  1918.     ei82596QPut (pDrvCtrl, (EI_LIST *) & pDrvCtrl->rxQueue, (EI_NODE *) pRfd);
  1919.     if (pTail != NULL)
  1920.         {
  1921.         pDrvCtrl->wdRxTimeout = 0;          /* reset timeout count */
  1922.         pTail->command &= ~CFD_C_EL;        /* clear old tail EL */
  1923.         if (pTail->status & (CFD_S_COMPLETE | CFD_S_BUSY))
  1924.             {
  1925.             pDrvCtrl->pFreeRfd = pRfd;      /* link questionable */
  1926.             }
  1927.         else if (!(pDrvCtrl->pScb->scbStatus & SCB_S_RUREADY))
  1928.             /* receiver dormant */
  1929.             {
  1930.             /* SPR #70148
  1931.      * It is not possible to maintain pFreeRfd during normal operation.
  1932.      *
  1933.      * If we do not update pFreeRfd before starting the device, then
  1934.      * the result will be multiple pointers to a single cluster.  This
  1935.      * will cause the network stack to die.  Usually, tNetTask will
  1936.      * crash with an access to address 0xa002XXXX.
  1937.      *
  1938.      * To avoid this, we go through the RX queue and explicitly
  1939.      * find the first free RFD.
  1940.      */
  1941.     /* first update pFreeRfd */
  1942.             pFree = (RFD *)pDrvCtrl->rxQueue.head;
  1943.             while ( pFree && ( pFree->status & ( CFD_S_COMPLETE | CFD_S_BUSY ) ) )
  1944.                 {
  1945.                 /* use logical address for linked list */
  1946.                 pFree = (RFD *)(LINK_RD(&pFree->lNext));
  1947.                 }
  1948.             /* use physical address for pFreeRfd */
  1949.             pDrvCtrl->pFreeRfd = CACHE_DRV_VIRT_TO_PHYS (&pDrvCtrl->cacheFuncs, pFree);
  1950.     /* now start the receiver */
  1951.             ei82596RxStartup (pDrvCtrl);    /* start receive unit */
  1952.             }
  1953.         }
  1954.     else
  1955.         {
  1956.         pDrvCtrl->pFreeRfd = pRfd;          /* first free RFD */
  1957.         }
  1958.     }
  1959. /*******************************************************************************
  1960. *
  1961. * ei82596RxQGet - get a successfully received frame from the receive queue
  1962. *
  1963. * RETURNS: ptr to valid RFD, or NULL if none available
  1964. */
  1965. LOCAL RFD *ei82596RxQGet
  1966.     (
  1967.     END_CTRL *pDrvCtrl
  1968.     )
  1969.     {
  1970.     RFD *pRfd = NULL;
  1971.     if (ei82596RxQFull (pDrvCtrl))
  1972.         pRfd = (RFD *) ei82596QGet ((EI_LIST *)&pDrvCtrl->rxQueue);
  1973.     return (pRfd);
  1974.     }
  1975. /*******************************************************************************
  1976. *
  1977. * ei82596RxQFull - boolean function to determine fullness of receive queue
  1978. *
  1979. * RETURNS: TRUE if completely received frame is available, FALSE otherwise.
  1980. */
  1981. LOCAL BOOL ei82596RxQFull
  1982.     (
  1983.     END_CTRL *pDrvCtrl
  1984.     )
  1985.     {
  1986.     return ((pDrvCtrl->rxQueue.head != NULL) &&
  1987.         (((RFD*)pDrvCtrl->rxQueue.head)->status & CFD_S_COMPLETE));
  1988.     }
  1989. /*******************************************************************************
  1990. *
  1991. * ei82596QInit - initialize a singly linked node queue
  1992. */
  1993. LOCAL void ei82596QInit
  1994.     (
  1995.     volatile EI_LIST *pQueue
  1996.     )
  1997.     {
  1998.     pQueue->head = pQueue->tail = NULL;         /* init head & tail */
  1999.     }
  2000. /*******************************************************************************
  2001. *
  2002. * ei82596QCat - Concatenate a queue to another
  2003. *
  2004. * This routine concatenates the queue <pQSrc> to the tail of <pQDest>.
  2005. *
  2006. * RETURNS: NONE
  2007. */
  2008. LOCAL void ei82596QCat
  2009.     (
  2010.     volatile EI_LIST * pQDest,         /* Destination Queue */
  2011.     volatile EI_LIST * pQSrc           /* Source Queue */
  2012.     )
  2013.     {
  2014.     if (pQSrc->head == NULL)
  2015.         return;
  2016.     if (pQDest->head == NULL)
  2017.         pQDest->head = pQSrc->head;
  2018.     else
  2019. LINK_WR(&pQDest->tail->pNext, (EI_NODE *)pQSrc->head);
  2020.     pQDest->tail = pQSrc->tail;
  2021.     }
  2022. /*******************************************************************************
  2023. *
  2024. * ei82596QGet - get a node from the head of a node queue
  2025. *
  2026. * RETURNS: ptr to useable node, or NULL ptr if none available
  2027. */
  2028. LOCAL EI_NODE *ei82596QGet
  2029.     (
  2030.     volatile EI_LIST *pQueue
  2031.     )
  2032.     {
  2033.     EI_NODE *pNode;
  2034.     if ((pNode = (EI_NODE *) pQueue->head) != NULL)     /* if list not empty */
  2035.         pQueue->head = (EI_NODE *) LINK_RD (&pNode->pNext); /* advance ptr */
  2036.     return (pNode);
  2037.     }
  2038. /*******************************************************************************
  2039. *
  2040. * ei82596QPut - put a node on the tail of a node queue
  2041. */
  2042. LOCAL void ei82596QPut
  2043.     (
  2044.     END_CTRL *pDrvCtrl,
  2045.     EI_LIST *pQueue,
  2046.     EI_NODE *pNode
  2047.     )
  2048.     {
  2049.     void * pTemp;
  2050.     LINK_WR (&pNode->lNext, NULL);                    /* mark "end of list" */
  2051.     LINK_WR (&pNode->pNext, NULL);
  2052.     if (pQueue->head == NULL)                        /* if list empty */
  2053.         pQueue->tail = pQueue->head = pNode;         /* set both ptrs */
  2054.     else
  2055.         {
  2056.         pTemp = CACHE_DRV_VIRT_TO_PHYS (&pDrvCtrl->cacheFuncs, pNode);
  2057.         LINK_WR (&pQueue->tail->lNext, pTemp);       /* link node on tail */
  2058.         LINK_WR (&pQueue->tail->pNext, pNode);
  2059.         pQueue->tail = pNode;                        /* update tail ptr */
  2060.         }
  2061.     }
  2062. /*******************************************************************************
  2063. *
  2064. * ei82596WatchDog - if the watchdog timer fired off, we've hung during transmit
  2065. *
  2066. * Check the scb command to verify and if so, reinit.
  2067. */
  2068. LOCAL void ei82596WatchDog
  2069.     (
  2070.     END_CTRL *pDrvCtrl
  2071.     )
  2072.     {
  2073.     SCB *pScb;
  2074.     int reset = FALSE;
  2075.     pScb = pDrvCtrl->pScb;
  2076.     /* Test for transmit timeout.
  2077.      *
  2078.      * Timeout occurs if the scb status indicates that CU (transmit) 
  2079.      * remains active for EI_TX_TIMEOUT iterations of ei82596WatchDog.
  2080.      * It might make sense to loop through the cfd's to look for
  2081.      * a complete bit as a sanity check, but given that transmit
  2082.      * was active, we will go ahead and do a reset.
  2083.      */
  2084.     if ((! pDrvCtrl->txIdle)
  2085.         && (pScb->scbStatus & SCB_S_CUACTIVE))
  2086.         {
  2087.         if (++(pDrvCtrl->wdTxTimeout) > EI_TX_TIMEOUT)
  2088.             {
  2089.             pDrvCtrl->txLockups++;   /* failure count */
  2090.             END_ERR_ADD (&pDrvCtrl->endObj, MIB2_OUT_ERRS, +1);
  2091.             reset = TRUE;
  2092.             }
  2093.         }
  2094.     /* Test for receive timeout.
  2095.      *
  2096.      * Timeout occurs if the scb status indicates that RU (receive) 
  2097.      * remains out of resources for EI_RX_TIMEOUT iterations of ei82596WatchDog.
  2098.      */
  2099.     if (pScb->scbStatus & SCB_S_RUNORSRC)
  2100.         {
  2101.         if (++(pDrvCtrl->wdRxTimeout) > EI_RX_TIMEOUT)
  2102.             {
  2103.             pDrvCtrl->rxLockups++;   /* failure count */
  2104.             reset = TRUE;
  2105.             }
  2106.         }
  2107.     /* reinitialize the unit or restart the watchdog */
  2108.     if (reset)
  2109.         {
  2110.         logMsg ("nei%d: resetn", pDrvCtrl->unit, 0, 0, 0, 0, 0);
  2111. #ifdef DRV_DEBUG
  2112.         logMsg ("rxLockups=%d txLockups=%dn", (int)pDrvCtrl->rxLockups,
  2113.                 (int)pDrvCtrl->txLockups, 0, 0, 0, 0);
  2114. #endif
  2115.         (void) netJobAdd ((FUNCPTR) ei82596DeviceRestart, (int) pDrvCtrl
  2116.   , 2, 3, 4, 5);
  2117. return;
  2118.         }
  2119.     if (pDrvCtrl->txBlocked)
  2120.             {
  2121.             pDrvCtrl->txBlocked = FALSE;
  2122.             netJobAdd ((FUNCPTR) muxTxRestart, (int) &pDrvCtrl->endObj, 0, 0,
  2123.                        0, 0);
  2124.             }
  2125.     wdStart (pDrvCtrl->wid, (int) pDrvCtrl->wdInterval, 
  2126.              (FUNCPTR) ei82596WatchDog, (int)pDrvCtrl);
  2127.     }
  2128. /* END OF DRIVER */
  2129. #ifdef DRV_DEBUG
  2130. eiPoolShow ()
  2131.     {
  2132.     END_CTRL *pDrvCtrl = (END_CTRL *)endFindByName ("ei", 0);
  2133.     netPoolShow (pDrvCtrl->endObj.pNetPool);
  2134.     }
  2135. eiTxRestart  ()
  2136.     {
  2137.     END_CTRL *pDrvCtrl = pEndCtrl;
  2138.     pDrvCtrl->txBlocked = FALSE;
  2139.     
  2140.     muxTxRestart (&pDrvCtrl->endObj);
  2141.     }
  2142.  
  2143. eiQShow
  2144.     (
  2145.     char *str,
  2146.     EI_LIST *pQ
  2147.     )
  2148.     {
  2149.     printf ("%s head=0x%x tail=0x%xn", str, pQ->head, pQ->tail);
  2150.     taskDelay (2);
  2151.     return 0;
  2152.     }
  2153. /*******************************************************************************
  2154. *
  2155. * ei82596NodeCount - count the number of nodes in an EI_LIST
  2156. *
  2157. */
  2158. LOCAL int ei82596NodeCount
  2159.     (
  2160.     volatile EI_LIST *pList
  2161.     )
  2162.     {
  2163.     int count=0;
  2164.     volatile EI_NODE *pNode = pList->head;
  2165.     while (pNode)
  2166.         {
  2167.         count++;
  2168.         pNode = LINK_RD (&pNode->pNext);
  2169.         }
  2170.     return count;
  2171.     }
  2172. int eiShow()
  2173.     {
  2174.     END_CTRL *pDrvCtrl = pEndCtrl;
  2175.     int cblCount;
  2176.     int freeCount;
  2177.     int cleanCount;
  2178.     int txCount;
  2179.     int rxCount;
  2180.     eiQShow ("cbl", &pDrvCtrl->cblQueue);
  2181.     eiQShow ("free", &pDrvCtrl->freeQueue);
  2182.     eiQShow ("clean", &pDrvCtrl->cleanQueue);
  2183.     eiQShow ("tx", &pDrvCtrl->txQueue);
  2184.     eiQShow ("rx", &pDrvCtrl->rxQueue);
  2185.     
  2186.     END_TX_SEM_TAKE (&pDrvCtrl->endObj, WAIT_FOREVER);
  2187.     cblCount = ei82596NodeCount (&pDrvCtrl->cblQueue);
  2188.     freeCount = ei82596NodeCount (&pDrvCtrl->freeQueue);
  2189.     cleanCount = ei82596NodeCount (&pDrvCtrl->cleanQueue);
  2190.     txCount = ei82596NodeCount (&pDrvCtrl->txQueue);
  2191.     END_TX_SEM_GIVE (&pDrvCtrl->endObj);
  2192.     rxCount = ei82596NodeCount (&pDrvCtrl->rxQueue);
  2193.     printf ("ei%d: END_CTRL=0x%x flags=0x%x txIdle=%d "
  2194.             "txCleaning=%d rxHandling=%dn",
  2195.             pDrvCtrl->unit, (int)pDrvCtrl, pDrvCtrl->flags, pDrvCtrl->txIdle,
  2196.             pDrvCtrl->txCleaning, pDrvCtrl->rxHandling);
  2197.     printf ("ei%d: rxLockups=%d txLockups=%d resetCount=%dn",
  2198.             pDrvCtrl->unit, (int)pDrvCtrl->rxLockups, (int)pDrvCtrl->txLockups,
  2199.             pDrvCtrl->resetCount);
  2200.     printf ("ei%d: txQ -- cbl=%d free=%d clean=%d txQueue=%d nLoan=%dn",
  2201.             pDrvCtrl->unit, cblCount, freeCount, cleanCount,txCount, nLoan);
  2202.     printf ("ei%d: rxQ -- count=%dn",
  2203.             pDrvCtrl->unit, rxCount);
  2204.     taskDelay(2);
  2205.     return 0;
  2206.     }
  2207. int printQueue
  2208.     (
  2209.     char *str,
  2210.     EI_LIST *pQueue
  2211.     )
  2212.     {
  2213.     EI_NODE *pNode;
  2214.     printf( "%s: ", str);
  2215.     pNode = pQueue->head;
  2216.     do
  2217.         {
  2218.         printf ("-> 0x%x ", pNode);
  2219.         if (pNode && pNode != 0xffffffff)
  2220.             pNode = LINK_RD (&pNode->pNext);
  2221.         } while (pNode && pNode != pQueue->tail);
  2222.     printf ("n");
  2223.     taskDelay (20);
  2224.     }
  2225. #endif /* DRV_DEBUG */
  2226. /* END OF FILE */