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

VxWorks

开发平台:

C/C++

  1. /* smEnd.c - END shared memory backplane network interface driver */
  2. /* Copyright 1984-1999 Wind River Systems, Inc. */
  3. /*
  4. modification history
  5. --------------------
  6. 01a,20jan1999,mas  written based on if_sm.c version 01k but with no Unix.
  7. */
  8. /*
  9. DESCRIPTION
  10. This module implements the VxWorks shared memory backplane network
  11. interface enhanced network driver.  
  12. This driver is designed to be moderately generic, operating unmodified
  13. across most targets supported by VxWorks.  To achieve this, the driver must
  14. be given several target-specific parameters, and some external support
  15. routines must be provided.  These parameters are detailed below.
  16. There are no user-callable routines.
  17. This driver is layered between the shared memory packet library and the Mux
  18. modules.  The backplane driver gives CPUs residing on a common backplane 
  19. the ability to communicate using IP (via shared memory).
  20. Macros:
  21. The macro SYS_INT_ENABLE is used to enable the interrupt level for the
  22. end device.  It is called once during initialization.  By default this is
  23. the routine sysLanIntEnable(), defined in the module sysLib.o.
  24. The macro SYS_ENET_ADDR_GET is used to get the ethernet address (MAC)
  25. for the device.  The single argument to this routine is the END_DEVICE
  26. pointer.  By default this routine copies the ethernet address stored in
  27. the global variable sysTemplateEnetAddr into the END_DEVICE structure.
  28. INCLUDES:
  29. end.h endLib.h etherMultiLib.h
  30. INTERNAL
  31. Data flow:
  32.  -------
  33.  | MUX | | multiplexer: interface
  34.  ------- | to network drivers
  35.     | |
  36.     |     |
  37.       -------------- |
  38.       |   smEnd    | | shared memory
  39.       -------------- | backplane driver
  40.     | |
  41.     | |
  42.        ------------ |
  43.        | smPktLib | | shared memory data
  44.        ------------ | packetizer library
  45.     | |
  46.     | |
  47.       ------------- |
  48.       | smUtilLib | | H/W abstraction
  49.       ------------- |
  50.     | |
  51.     | |
  52. =========================== | backplane
  53. MUX
  54. Implements the interface between the protocol layer and the data link layer
  55. which contains the driver.
  56. smEnd
  57. Contains the network interface code that is common to all END based
  58. systems.  It is the interface between the network modules and the backplane.
  59. It does the packet processing.
  60. smPktLib
  61. Reformats data between IP packets and shared memory buffer packets.
  62. smUtilLib
  63. Contains routines to abstract the hardware backplane, giving a uniform
  64. interface to any type of backplane.
  65. MUX Interface:
  66. The interfaces into this module from the MUX module follow.  
  67. smEndLoad -  Called by the MUX, the routine initializes and attaches this
  68. shared memory network interface driver to the MUX.  It is the only globally
  69. accessible entry into this driver.  This routine typically gets called twice
  70. per backplane interface (device) and accepts a pointer to a string of
  71. initialization parameters.  The first call to this routine will be made with
  72. an empty string; it signals the routine to return a device name, not to load
  73. and intialize the driver.  The second call will be with a valid parameter
  74. string, signalling that the driver is to be loaded and initialized with the
  75. parameter values in the string.  The shared memory region must have been
  76. setup and initialized (via smPktSetup) prior to calling smEndLoad().
  77. Although initialized, no devices will become active until smEndStart() is
  78. called.
  79. The following routines are all local to this driver but are listed in the
  80. driver entry function table:
  81. smEndUnload -  Called by the MUX, this routine stops all associated devices,
  82. frees driver resources, and prepares this driver to be unloaded.  If required,
  83. calls to smEndStop() will be made to all active devices.
  84. smEndStart -  Called by the MUX, the routine starts this driver and device(s).
  85. The routine activates this driver and its device(s).  The activities performed
  86. are dependent upon the selected mode of operation, interrupt or polled.
  87. smEndStop -  Called by the MUX, the routine stops this driver by inactivating
  88. the driver and its associated device(s).  Upon completion of this routine,
  89. this driver is left in the same state it was just after smEndLoad() execution.
  90. smEndRecv -  This routine is not called from the MUX.  It gets called from
  91. this drivers interrupt service routine (ISR) to process input shared memory
  92. packets.  It then passes them on to the MUX.
  93. smEndSend -  Called by the MUX, this routine sends a packet via shared memory.
  94. smEndPollRecv - Called by the MUX, this routine polls the shared memory region
  95. designated for this CPU to determine if any new packet buffers are available
  96. to be read.  If so, it reads the packet into the supplied mBlk and returns OK
  97. to the MUX.  If the packet is too big for the mBlk or if no packets are
  98. available, EAGAIN is returned.  If the device is not in polled mode, EIO is
  99. returned.
  100. smEndPollSend -  Called by the MUX, this routine does a polled send of one
  101. packet to shared memory.  Because shared memory buffers act as a message queue,
  102. this routine will attempt to put the polled mode packet at the head of the list
  103. of buffers.  If no free buffers are available, the buffer currently appearing
  104. first in the list is overwritten with the packet.
  105. smEndIoctl -  Called by the MUX, the routine accesses the control routines for
  106. this driver.
  107. smEndMCastAddrAdd -  Called by the MUX, this routine adds an address to a
  108. device's multicast address list.
  109. smEndMCastAddrDel -  Called by the MUX, this routine deletes an address from a
  110. device's multicast address list.
  111. smEndMCastAddrGet -  Called by the MUX, this routine gets the multicast address
  112. list maintained for a specified device.
  113. The following routines do not require shared memory specific logic so the
  114. default END library routines are referenced in the function table:
  115. endEtherAddressForm -  Called by the MUX, this routine forms an address by
  116. adding appropriate link-level (shared memory) information to a specified mBlk
  117. in preparation for transmission.
  118. endEtherPacketDataGet -  Called by the MUX, this routine derives the protocol
  119. specific data within a specified mBlk by stripping the link-level (shared
  120. memory) information from it.  The resulting data are copied to another mBlk.
  121. endEtherPacketAddrGet -  Called by the MUX, this routine extracts address
  122. information from one mBlk, ignoring all other data.  Each source and
  123. destination address is written to its own mBlk.  For ethernet packets, this
  124. routine produces two output mBlks (an address pair).  However, for non-ethernet
  125. packets, up to four mBlks (two address pairs) may be produced; two for an
  126. intermediate address pair and two more for the terminal address pair.
  127. .LP
  128. EXTERNAL SUPPORT REQUIREMENTS
  129. The following routines/macros must be provided for this module: 
  130. sysSmBspLoad() - a routine to dynamically build a parameter string
  131.   for, and call into, smEndLoad().  This routine is typically
  132.   contained within the sysSmCfg.c BSP module.
  133. The following routines/macros may be optionally provided for this module: 
  134. .IP SM_PACKET_XFER()
  135. .CS
  136.     void SM_PACKET_XFER (void * source, void * destination, int numBytes);
  137. .CE
  138. This macro transfers data between clusters and SM packets.  It may optionally
  139. be redefined in the BSP.  By default, bcopy() is used:
  140.     #define SM_PACKET_XFER(source,destination,numBytes)  \
  141.         bcopy((char*)source, (char*)destination, (int)numBytes)
  142. TARGET-SPECIFIC PARAMETERS
  143. These parameters are input to this driver in an ASCII string format, using
  144. colon delimited values, via the sysSmBspLoad() routine in sysSmCfg.c.  Each
  145. parameter have a preselected radix in which they are expected to be read as
  146. shown below.
  147. The sysSmCfg.c module is included in sysLib.c and is compiled with the current
  148. settings for the target-specific parameters defined by the following:
  149. Parameter         Radix Use
  150. ----------------- ----- ------------------------------------------------------
  151. SM_BUS_SPACE       16   bus address space; NONE = local, else, a VME AM or PCI
  152.                         space selector   [**not yet supported in smPktLib.c**]
  153. SM_ANCHOR_ADRS     16   shared memory anchor region  @<SM_BUS_SPACE>
  154. SM_MEM_ADRS        16   shared memory (NONE = allocate)  @<SM_BUS_SPACE>
  155. This value is used by the master CPU when building sm.
  156. SM_MEM_SIZE        16   total shared memory size in bytes
  157. This value is used by the master CPU when building sm.
  158. SM_TAS_TYPE        10   test-and-set type (SM_TAS_HARD or SM_TAS_SOFT)
  159. SM_CPUS_MAX        10   maximum number of CPUs supported on backplane
  160. (0 = default number)
  161. SM_MASTER_CPU      10   master CPU#
  162. SM_PKTS_SIZE       10   max number of data bytes per shared memory packet
  163. (0 = default)
  164. SM_MAX_INPUT_PKTS  10   max number of queued receive packets for this CPU
  165. (0 = default)
  166. SM_INT_TYPE        10   interrupt method (SM_INT_MAILBOX/_BUS/_NONE)
  167. SM_INT_ARG1        16   1st interrupt argument
  168. SM_INT_ARG2        16   2nd interrupt argument
  169. SM_INT_ARG3        16   3rd interrupt argument
  170. SM_NUM_MBLKS       16   number of mBlks in driver memory pool (if < 16,
  171. a default value is used)
  172. SM_NUM_CBLKS       16   number of clBlks in driver memory pool (if < 16,
  173. a default value is used)
  174. DEBUG SUPPORT
  175. This module has a define to enable compilation of debug instrumentation code
  176. called SM_DBG.  There is also a conditionally compiled global called smEndDebug
  177. which is used as a bit array for enabling/disabling debug reporting in various
  178. routines in this module.  This enables selective debugging with little or no
  179. extraneous information from other code sections.
  180. SEE ALSO: muxLib, endLib
  181. .I "Writing an Enhanced Network Driver"
  182. INTERNAL
  183. There are currently certain values stored in what are listed as reserved
  184. locations within various sm structures.  These must be treated with extreme
  185. care so as not to overwrite them:
  186. Structure Reserved field usage
  187. -------------------- ------------------------------------------------------
  188. SM_PKT_MEM_HDR reserved1 - master's sequential IP address
  189. reserved2 - sm heartbeat WD timer ID
  190. SM_CPU_DESC reserved1 - each CPU stores it's non-sequential IP
  191. address here.  There is one SM_CPU_DESC per CPU in sm.
  192. */
  193. /* includes */
  194. #include "vxWorks.h"
  195. #include "stdlib.h"
  196. #include "stdio.h"
  197. #include "cacheLib.h"
  198. #include "intLib.h"
  199. #include "net/if_dl.h"
  200. #include "end.h" /* Common END structures. */
  201. #include "endLib.h"
  202. #include "lstLib.h" /* Needed to maintain protocol list. */
  203. #include "arpLib.h"
  204. #include "wdLib.h"
  205. #include "iv.h"
  206. #include "semLib.h"
  207. #include "taskLib.h"
  208. #include "etherLib.h"
  209. #include "logLib.h"
  210. #include "netLib.h"
  211. #include "sysLib.h"
  212. #include "errno.h"
  213. #include "errnoLib.h"
  214. #include "memLib.h"
  215. #include "muxLib.h"
  216. #include "etherMultiLib.h" /* multicast stuff. */
  217. #include "m2Lib.h"
  218. #include "netinet/if_ether.h"
  219. #include "net/if_subr.h"
  220. #include "net/mbuf.h"
  221. #include "net/unixLib.h"
  222. #include "net/protosw.h"
  223. #include "net/systm.h"
  224. #include "net/route.h"
  225. #include "sys/socket.h"
  226. #include "sys/ioctl.h"
  227. #include "sys/times.h"
  228. #include "drv/end/smEnd.h"
  229. #include "smLib.h"
  230. #include "smPktLib.h"
  231. #include "smUtilLib.h"
  232. IMPORT int endMultiLstCnt (END_OBJ * pEnd);
  233. /* defines */
  234. /*
  235.  * Definitions for the shared memory END State flags field
  236.  *
  237.  * Flag Use
  238.  * --------------- ------------------------------------------------------
  239.  * S_LOADED smEnd successfully loaded
  240.  * S_CPU_ATTACHED local CPU is attached to shared memory
  241.  * S_RUNNING local CPU active in shared memory
  242.  * S_POLLED_SM shared memory interface is operating in polled mode
  243.  * S_POLLED_SM_LOCKED sm interface locked in polled mode, can't enter
  244.  * interrupt mode
  245.  * S_POLLED_END MUX interface is operating in polled mode
  246.  * S_RCV_TASK_ACTIVE interrupt driven receive task is active
  247.  */
  248. #define S_LOADED 0x0001
  249. #define S_CPU_ATTACHED 0x0002
  250. #define S_RUNNING 0x0004
  251. #define S_POLLED_SM 0x0008
  252. #define S_POLLED_SM_LOCKED 0x0010
  253. #define S_POLLED_END 0x0020
  254. #define S_RCV_TASK_ACTIVE 0x0040
  255. /* shared memory END compound states */
  256. #define S_ACTIVE         (S_LOADED | S_CPU_ATTACHED | S_RUNNING)
  257. #define S_POLLED_SM_RDY  (S_ACTIVE | S_POLLED_SM)
  258. #define S_POLLED_END_RDY (S_ACTIVE | S_POLLED_END)
  259. #define S_POLLED_RDY     (S_ACTIVE | S_POLLED_SM | S_POLLED_END)
  260. #define S_INTR_RDY       (S_ACTIVE)
  261. #define MODE_INTR_MASK   (S_ACTIVE | S_POLLED_RDY | S_RCV_TASK_ACTIVE)
  262. /* macros */
  263. /*
  264.  * Default macro definitions for smUtilLib interface.
  265.  * These macros must be redefined when architecture-neutral functional calls
  266.  * exist for: intConnect(), intDisconnect(), intEnable(), intDisable(),
  267.  * sysMailboxDisconnect(), and sysMailboxDisable().
  268.  */
  269. /*
  270.  * XXXmas temporary; someday will have to make a real one based on a
  271.  * functional intDisconnect()!
  272.  */
  273. #define smUtilIntDisconnect(pri,pIsr,isrArg,iType,iArg1,iArg2,iArg3)  OK
  274. /* XXXmas ditto: smUtilLib will someday have real versions of these: */
  275. /* Macro to enable the appropriate interrupt level */
  276. #ifndef   smUtilIntEnable
  277. #define smUtilIntEnable(pSmEndDev) 
  278.     do 
  279.         { 
  280.         if (pSmEndDev->intType == SM_INT_BUS) 
  281.             sysIntEnable (pSmEndDev->intArg1); 
  282.         else if (pSmEndDev->intType != SM_INT_NONE) 
  283.             sysMailboxEnable ((char *)pSmEndDev->intArg2); 
  284.         else 
  285.             taskResume (pollTaskId); 
  286.         } while (0)
  287. #endif /* smUtilIntEnable */
  288. /* Macro to disable the appropriate interrupt level */
  289. #ifndef   smUtilIntDisable
  290. #define smUtilIntDisable(pSmEndDev) 
  291.     do 
  292.         { 
  293.         if (pSmEndDev->intType == SM_INT_BUS) 
  294.             sysIntDisable (pSmEndDev->intArg1); 
  295.         else if (pSmEndDev->intType == SM_INT_NONE) 
  296.             taskSuspend (pollTaskId); 
  297.         } while (0)
  298. #endif /* smUtilIntDisable */
  299. /* A shortcut for getting the hardware address from the MIB II stuff. */
  300. #define END_HW_ADDR(pEnd)
  301. ((pEnd)->mib2Tbl.ifPhysAddress.phyAddress)
  302. #define END_HW_ADDR_LEN(pEnd) 
  303. ((pEnd)->mib2Tbl.ifPhysAddress.addrLength)
  304. #define SM_END_PKT_LEN_GET(pPkt)  ((pPkt)->header.nBytes)
  305. #define SM_END_IS_RUNNING  
  306.     ((END_FLAGS_GET (&pSmEndDev->end) & IFF_RUNNING) != 0)
  307. #define SM_END_IS_LOADED  
  308.     ((pSmEndDev->flags & S_LOADED) != 0)
  309. #define SM_END_UNLOAD  
  310.     (pSmEndDev->flags &= ~S_LOADED)
  311. #define SM_END_IS_ACTIVE  
  312.     ((pSmEndDev->flags & S_ACTIVE) == S_ACTIVE)
  313. #define SM_END_POLL_SM_RDY  
  314.     ((pSmEndDev->flags & S_POLLED_SM_RDY) == S_POLLED_SM_RDY)
  315. #define MUX_IS_POLLING  
  316.     ((pSmEndDev->flags & S_POLLED_END_RDY) == S_POLLED_END_RDY)
  317. #define SM_IS_POLLED_LOCKED  
  318.     ((pSmEndDev->flags & S_POLLED_SM_LOCKED) != 0)
  319. #define SM_END_INTR_RDY  
  320.     ((pSmEndDev->flags & MODE_INTR_MASK) == S_INTR_RDY)
  321. #define SM_END_STOP  
  322.     {pSmEndDev->flags &= ~S_RUNNING; 
  323.      END_FLAGS_CLR (&pSmEndDev->end, IFF_RUNNING);}
  324. #define SM_END_START  
  325.     {pSmEndDev->flags |= S_RUNNING; 
  326.      END_FLAGS_SET (&pSmEndDev->end, IFF_RUNNING);}
  327. #define SM_RCV_TASK_ACTIVE  
  328.     (pSmEndDev->flags |= S_RCV_TASK_ACTIVE)
  329. #define SM_RCV_TASK_INACTIVE  
  330.     (pSmEndDev->flags &= ~S_RCV_TASK_ACTIVE)
  331. /* DEBUG MACROS */
  332. #define TUPLE   /* XXXmas */
  333. #define SM_DBG  /* XXXmas */
  334. #ifdef SM_DBG
  335. #  define SM_DBG_OFF 0x0000
  336. #  define SM_DBG_RX 0x0001
  337. #  define SM_DBG_TX 0x0002
  338. #  define SM_DBG_INT 0x0004
  339. #  define SM_DBG_POLL (SM_DBG_POLL_RX | SM_DBG_POLL_TX)
  340. #  define SM_DBG_POLL_RX 0x0008
  341. #  define SM_DBG_POLL_TX 0x0010
  342. #  define SM_DBG_LOAD 0x0020
  343. #  define SM_DBG_MEM_INIT 0x0040
  344. #  define SM_DBG_UNLOAD 0x0080
  345. #  define SM_DBG_IOCTL 0x0100
  346. #  define SM_DBG_START 0x0200
  347. #  define SM_DBG_STOP 0x0400
  348. #  define SM_DBG_CFG 0x0800
  349. #  define SM_DBG_RSLV 0x1000
  350. #  define SM_LOG(FLG, X0, X1, X2, X3, X4, X5, X6) 
  351. if (smEndDebug & FLG)                    
  352.             {logMsg(X0, X1, X2, X3, X4, X5, X6); taskDelay(3);}
  353. #else /*SM_DBG*/
  354. #  define SM_LOG(FLG, X0, X1, X2, X3, X4, X5, X6)
  355. #endif /*SM_DBG*/
  356. /* typedefs */
  357. /* Allowed State Changes */
  358. typedef enum {SC_NONE, SC_INIT, SC_POLL2INT, SC_INT2POLL} STATE_CHANGE;
  359. /*
  360.  * The definition of the shared memory device control structure
  361.  *
  362.  * typedef struct sm_end_device /@ SM_END_DEV @/
  363.  *  {
  364.  *  END_OBJ end; /@ The class we inherit from. @/
  365.  *  UINT cookie; /@ sm device validation cookie @/
  366.  *  unsigned localCpu; /@ local cpu number @/
  367.  *  int unit; /@ unit number @/
  368.  *  ULONG busSpace; /@ bus address space for pAnchor/pmem@/
  369.  *  SM_ANCHOR * pAnchor; /@ pointer to shared memory anchor @/
  370.  *  char * pMem; /@ pointer to start of shared memory @/
  371.  *  ULONG memSize; /@ total shared memory size in bytes @/
  372.  *  unsigned tasType; /@ test-and-set type (HARD/SOFT) @/
  373.  *  unsigned maxCpus; /@ max #CPUs supported in 'sm' @/
  374.  *  unsigned masterCpu; /@ master CPU number @/
  375.  *  ULONG maxPktBytes; /@ max #packets in shared memory @/
  376.  *  char * startAddr; /@ start of seq addrs (0 = not seq) @/
  377.  *  char * ipAddr; /@ non-seq. IP address @/
  378.  *  int maxPackets; /@ max #packets CPU can receive @/
  379.  *  int intType; /@ interrupt method @/
  380.  *  int intArg1; /@ 1st interrupt argument @/
  381.  *  int intArg2; /@ 2nd interrupt argument @/
  382.  *  int intArg3; /@ 3rd interrupt argument @/
  383.  *  int ticksPerBeat; /@ #CPU ticks per heartbeat @/
  384.  *  ULONG mbNum; /@ number of mBlks to allocate @/
  385.  *  ULONG cbNum; /@ number of clBlks to allocate @/
  386.  *  BOOL smAlloc; /@ sm allocated? @/
  387.  *  BOOL isMaster; /@ we are master CPU? @/
  388.  *  ULONG flags; /@ Our local flags. @/
  389.  *  SM_PKT_MEM_HDR *    pSmPktHdr; /@ sm packet header @/
  390.  *  CL_POOL_ID clPoolId; /@ cluster pool ID @/
  391.  *  M_BLK_ID tupleId; /@ receive-ready tuple (mBlk) ID @/
  392.  *  M_BLK_ID pollQ; /@ polled tuple queue @/
  393.  *  M_BLK_ID pollQLast; /@ polled tuple queue last entry @/
  394.  *  void * pMclBlkCfg; /@ mBlk/clBlk config memory @/
  395.  *  void * pClustMem; /@ cluster pool memory @/
  396.  *
  397.  *  /@ old SM_SOFTC section @/
  398.  *
  399.  *  struct arpcom arpcom; /@ common ethernet structure@/
  400.  *  SM_PKT_DESC smPktDesc; /@ shared mem packet desc @/
  401.  *  u_long masterAddr; /@ master's IP address @/
  402.  *  } SM_END_DEV;
  403.  */
  404. /* globals */
  405. #ifdef SM_DBG
  406. int        smEndDebug  = NONE; /* section debug enable switch */
  407. int        smEndRxInts = 0; /* number of receive interrupts received */
  408. int        smEndTxInts = 0; /* number of transmit interrupts generated */
  409. #endif /* SM_DBG */
  410. /* unit -> SM_END_DEV * Table */
  411. SM_END_DEV ** unitTbl = NULL;
  412. /* LOCALS */
  413. /* forward static functions */
  414. LOCAL STATUS smEndParse (SM_END_DEV * pSmEndDev, char * pParamStr);
  415. LOCAL STATUS smEndMemInit (SM_END_DEV * pSmEndDev);
  416. LOCAL STATUS smEndConfig (SM_END_DEV * pSmEndDev, STATE_CHANGE sDelta);
  417. LOCAL void   smEndHwAddrSet (SM_END_DEV * pSmEndDev);
  418. LOCAL void   smEndIsr (SM_END_DEV * pSmEndDev);
  419. LOCAL void   smEndSrvcRcvInt (SM_END_DEV * pSmEndDev);
  420. LOCAL STATUS smEndRecv (SM_END_DEV * pSmEndDev, SM_PKT * pPkt, M_BLK_ID pMblk);
  421. LOCAL void   smEndPollQPut (SM_END_DEV * pSmEndDev, M_BLK_ID mBlkId);
  422. LOCAL int    smEndPollQGet (SM_END_DEV * pSmEndDev, M_BLK_ID mBlkId);
  423. LOCAL void   smEndPollQFree (SM_END_DEV * pSmEndDev);
  424. LOCAL void   smEndPulse (SM_PKT_MEM_HDR * pSmPktHdr);
  425. LOCAL M_BLK_ID smEndTupleGet (SM_END_DEV * pSmEndDev);
  426. LOCAL STATUS smEndTupleChainWalk (M_BLK * pMblk, UINT * pFragNum,
  427.   UINT16 * pPktType, UINT * pMaxSize);
  428. LOCAL int    smEndAddrResolve (FAST struct arpcom *   pAc,
  429.                                FAST struct rtentry *  pRt,
  430.                                struct mbuf *          pMbuf,
  431.                                FAST struct sockaddr * pDestIP,
  432.                                FAST u_char *          pDestHW);
  433. /* END Specific interfaces */
  434. /* This is the only externally visible interface. */
  435. END_OBJ *    smEndLoad (char* initString);
  436. LOCAL STATUS smEndUnload (void *);
  437. LOCAL STATUS smEndStart  (void *);
  438. LOCAL STATUS smEndStop   (void *);
  439. LOCAL int    smEndIoctl  (void *, int, caddr_t);
  440. LOCAL STATUS smEndSend   (void *, M_BLK_ID);
  441.   
  442. LOCAL STATUS smEndMCastAddrAdd  (void *, char *);
  443. LOCAL STATUS smEndMCastAddrDel  (void *, char *);
  444. LOCAL STATUS smEndMCastAddrGet  (void *, MULTI_TABLE *);
  445. LOCAL STATUS smEndPollSend  (void *, M_BLK_ID);
  446. LOCAL STATUS smEndPollRecv  (void *, M_BLK_ID);
  447. LOCAL STATUS smEndPollStart (void *);
  448. LOCAL STATUS smEndPollStop  (void *);
  449. #if FALSE /* XXXmas future enhancement */
  450. LOCAL void smEndAddrFilterSet (void *);
  451. #endif
  452. /*
  453.  * Declare our function entry table.  This is static across all END driver
  454.  * instances.
  455.  */
  456. LOCAL NET_FUNCS smEndFuncTable =
  457.     {
  458.     (FUNCPTR)smEndStart, /* Function to start the device */
  459.     (FUNCPTR)smEndStop, /* Function to stop the device */
  460.     (FUNCPTR)smEndUnload, /* Unloading function of the driver */
  461.     (FUNCPTR)smEndIoctl, /* Ioctl function of the driver */
  462.     (FUNCPTR)smEndSend, /* Send function of the driver */
  463.     (FUNCPTR)smEndMCastAddrAdd, /* Multicast add function of the driver */
  464.     (FUNCPTR)smEndMCastAddrDel, /* Multicast delete function of the driver */
  465.     (FUNCPTR)smEndMCastAddrGet, /* Multicast retrieve function of the driver */
  466.     (FUNCPTR)smEndPollSend, /* Polling send function */
  467.     (FUNCPTR)smEndPollRecv, /* Polling receive function */
  468.     endEtherAddressForm, /* put address info into a NET_BUFFER */
  469.     endEtherPacketDataGet,  /* get pointer to data in NET_BUFFER */
  470.     endEtherPacketAddrGet  /* Get packet addresses */
  471.     };
  472. LOCAL int  pollTaskId = NONE;
  473. /*
  474.  * This array will only be needed until there are functional intConnect(),
  475.  * intDisconnect(), intEnable() and intDisable() routines for all BSPs.
  476.  */
  477. LOCAL BOOL connected[SM_NUM_INT_TYPES] =
  478.     {FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE};
  479. /******************************************************************************
  480. *
  481. * smEndLoad - attach the sm interface to the MUX, initialize driver and device
  482. *
  483. * This routine attaches an 'sm' Ethernet interface to the network MUX.  This
  484. * routine makes the interface available by allocating and filling in an END_OBJ
  485. * structure, a driver entry table, and a MIB2 interface table.
  486. *
  487. * Calls to this routine evoke different results depending upon the parameter
  488. * string it receives.  If the string is empty, the MUX is requesting that the
  489. * device name be returned, not an intialized END_OBJ pointer.  If the string
  490. * is not empty, a load operation is being requested with initialization being
  491. * done with the parameters parsed from the string.
  492. *
  493. * Upon successful completion of a load operation by this routine, the driver
  494. * will be ready to be started, not active.  The system will start the driver
  495. * when it is ready to accept packets.
  496. *
  497. * The shared memory region will be initialized, via smPktSetup(), during the
  498. * call to this routine if it is executing on the designated master CPU.
  499. * The smEndLoad() routine can be called to load only one device unit at a time.
  500. *
  501. * Input parameters are specified in the form of an ASCII string of colon (:)
  502. * delimited values of the form:
  503. *
  504. * "<unit>:<busSpace>:<pAnchor>:<pMem>:<memSize>:<tasType>:<maxCpus>:
  505. *  <masterCpu>:<maxPktBytes>:<startAddr>:<ipAddr>:<maxInputPkts>:<intType>:
  506. *  <intArg1>:<intArg2>:<intArg3>:<mbNum>:<cbNum>"
  507. *
  508. * The <unit> parameter denotes the logical device unit number assigned by the
  509. * operating system.  Specified using radix 10.
  510. *
  511. * The <busSpace> parameter denotes the bus address space.  NONE = local, else,
  512. * a VME AM or PCI space identifier is required.  This value applies to the
  513. * <pAnchor> and <pMem> parameters.  Specified using radix 16.  [NOT SUPPORTED]
  514. *
  515. * The <pAnchor> parameter is the local address by which the local CPU may
  516. * access the shared memory anchor.  Specified using radix 16.
  517. *
  518. * The <pMem> parameter contains either the local address of shared memory or
  519. * the value NONE (-1), which implies that shared memory is to be allocated
  520. * dynamically.  Specified using radix 16.
  521. *
  522. * The <memSize> parameter is the size, in bytes, of the shared memory region.
  523. * Specified using radix 16.
  524. *
  525. * The <tasType> parameter specifies the test-and-set operation to be used to
  526. * obtain exclusive access to the shared data structures.  It is preferable
  527. * to use a genuine test-and-set instruction, if the hardware permits it.  In
  528. * this case, <tasType> should be SM_TAS_HARD.  If any of the CPUs on the
  529. * backplane network do not support the test-and-set instruction, <tasType>
  530. * should be SM_TAS_SOFT.  Specified using radix 10.
  531. *
  532. * The <maxCpus> parameter specifies the maximum number of CPUs that may
  533. * use the shared memory region.  Specified using radix 10.
  534. *
  535. * The <masterCpu> parameter indicates the shared memory master CPU number.
  536. * Specified in radix 10.
  537. *
  538. * The <maxPktBytes> parameter specifies the size, in bytes, of the data
  539. * buffer in shared memory packets.  This is the largest amount of data
  540. * that may be sent in a single packet.  If this value is not an exact
  541. * multiple of 4 bytes, it will be rounded up to the next multiple of 4.
  542. * If zero, the default size specified in DEFAULT_PKT_SIZE is used.
  543. * Specified using radix 10.
  544. *
  545. * The <startAddr> parameter is only applicable if sequential addressing is
  546. * enabled.  If <startAddr> is non-zero, it specifies the starting address to
  547. * use for sequential addressing on the backplane.  If <startAddr> is zero,
  548. * sequential addressing is disabled and <ipAddr> must be non-zero.  Specified
  549. * using radix 16.
  550. *
  551. * The <ipAddr> parameter is only applicable if sequential addressing is
  552. * not enabled.  If <ipAddr> is non-zero, it specifies the IP address to
  553. * use for this CPU on the backplane.  If <ipAddr> is zero, <startAddr> must
  554. * be non-zero.  Specified using radix 16.
  555. *
  556. * The <maxInputPkts> parameter specifies the maximum number of incoming shared
  557. * memory packets which may be queued to this CPU at one time.  If zero, the
  558. * default value is used.  Specified using radix 10.
  559. *
  560. * The <intType> parameter allows a CPU to announce the method by which it is to
  561. * be notified of input packets which have been queued to it.  Specified using
  562. * radix 10.
  563. *
  564. * The <intArg1>, <intArg2>, and <intArg3> parameters are arguments chosen based
  565. * on, and required by, the interrupt method specified.  They are used to
  566. * generate an interrupt of type <intType>.  Specified using radix 16.
  567. *
  568. * If <mbNum> is non-zero, it specifies the number of mBlks to allocate in the
  569. * driver memory pool.  If <mbNum> is less than 0x10, a default value is used.
  570. * Specified using radix 16.
  571. *
  572. * If <cbNum> is non-zero, it specifies the number of clBlks and, therefore, the
  573. * number of clusters, to allocate in the driver memory pool.  If <cbNum> is
  574. * less than 0x10, a default value is used.  Specified using radix 16.
  575. *
  576. * The number of clBlks is also the number of clusters which will be allocated.
  577. * The clusters allocated in the driver memory pool all have a size of
  578. * SM_END_CLST_SIZ bytes.  This size is defined such that an ethernet address
  579. * plus the largest MTU size can be contained and so that the size as allocated
  580. * by the netPoolInit() routine is an integer multiple of sizeof(int).
  581. *
  582. * XXXmas NOTE: to be added later: multicasting and zero-copy
  583. *
  584. * RETURNS: return values are dependent upon the context implied by the
  585. * parameter string length as shown below.
  586. *
  587. * Length Return Value
  588. * -------- ---------------------------------------------------------------
  589. * 0 OK and device name copied to input string pointer or ERROR if
  590. * NULL string pointer.
  591. * non-0 END_OBJ * to initialized object or ERROR if bogus string or an
  592. * internal error occurs.
  593. *
  594. * SEE ALSO: smEndParse()
  595. */
  596. END_OBJ * smEndLoad
  597.     (
  598.     char * pParamStr /* pointer to initialization parameter string */
  599.     )
  600.     {
  601.     SM_END_DEV * pSmEndDev    = NULL; /* device control pointer */
  602.     SM_ANCHOR * pAnchor; /* addr of anchor */
  603.     int                 anchorSet    = ERROR; /* anchor visible */
  604.     int                 tics = smUtilProcNumGet(); /* sm probe delay period */
  605.     int temp; /* temp for vxMemProbe */
  606.     static UCHAR enetAddr[EADDR_LEN] = {0,0,0,0,0,0}; /* ethernet adrs*/
  607.     static char devName []   = SM_END_DEV_NAME;
  608.     static int smEndDevAttr = (IFF_UP | IFF_NOTRAILERS |
  609.                                         IFF_BROADCAST);
  610. #if FALSE /* XXXmas future enhancement */
  611.     static int smEndDevAttr = (IFF_UP | IFF_NOTRAILERS |
  612.                                         IFF_BROADCAST | IFF_MULTICAST);
  613. #endif
  614. SM_LOG (SM_DBG_LOAD, "smEndLoad: pParamStr = %#X, len = %dn",
  615.         (unsigned)pParamStr, strlen (pParamStr), 0, 0, 0, 0);
  616.     /* If parameter string pointer is NULL, just return ERROR */
  617.     if (pParamStr == NULL)
  618.         {
  619.         SM_LOG (SM_DBG_LOAD, "smEndLoad: ERROR: no param string ptr...n",
  620.                 0, 0, 0, 0, 0, 0);
  621. return ((END_OBJ *)ERROR);
  622.         }
  623.     /*
  624.      * If parameter string is empty, MUX is requesting device name,
  625.      * not a load operation.  Just copy name to pointer and return OK.
  626.      */
  627.     if (*pParamStr == 0)
  628.         {
  629.         strcpy (pParamStr, devName);
  630.         SM_LOG (SM_DBG_LOAD, "smEndLoad: 1st pass: Returning dev name <%s>n",
  631.                 (unsigned)pParamStr, 0, 0, 0, 0, 0);
  632.         return ((END_OBJ *)OK);
  633.         }
  634.     /*
  635.      * load operation requested
  636.      * allocate required memory for structures
  637.      */
  638.     /* allocate the SM_END_DEV structure */
  639.     SM_LOG (SM_DBG_LOAD, "smEndLoad: 2nd passn", 0, 0, 0, 0, 0, 0);
  640.     if ((pSmEndDev = (SM_END_DEV *)calloc (1, sizeof (SM_END_DEV))) == NULL)
  641.         {
  642.         SM_LOG (SM_DBG_LOAD, "smEndLoad: can't Aallocate SM_END_DEVn",
  643.                 0, 0, 0, 0, 0, 0);
  644. return ((END_OBJ *)ERROR);
  645.         }
  646.     /* validate structure */
  647.     pSmEndDev->cookie = SM_END_COOKIE;
  648.     /*
  649.      * Parse the initialization parameter string, extracting all parameters.
  650.      * Parameter values are delimited by spaces.
  651.      */
  652.     SM_LOG (SM_DBG_LOAD, "Parsing string...n", 0, 0, 0, 0, 0, 0);
  653.     if (smEndParse (pSmEndDev, pParamStr) != ERROR)
  654.         {
  655.         /*
  656.          * The <ticksPerBeat> parameter specifies the frequency of the shared
  657.          * memory anchor's heartbeat.  The frequency is expressed in terms of
  658.          * the number of CPU ticks on the local CPU corresponding to one
  659.          * heartbeat period.
  660.          */
  661.         pSmEndDev->ticksPerBeat = sysClkRateGet ();
  662.         /* if initial mode is polled, lock it */
  663.         if (pSmEndDev->intType == SM_INT_NONE)
  664.             pSmEndDev->flags = S_POLLED_SM_LOCKED;
  665.         else
  666.             pSmEndDev->flags = 0;
  667.         /* If not already, allocate unit table and store our ptr in it */
  668.         if (unitTbl != NULL)
  669.             {
  670.             if ((unitTbl = (SM_END_DEV **)calloc (NSM, sizeof (SM_END_DEV)))
  671.                          == NULL)
  672.                 {
  673.                 smEndUnload (pSmEndDev);
  674.                 return ((END_OBJ *)ERROR);
  675.                 }
  676.             }
  677.         unitTbl [pSmEndDev->unit] = pSmEndDev;
  678.         /* If this is the master CPU, determine addressing mode */
  679.         if (pSmEndDev->masterCpu == smUtilProcNumGet ())
  680.             {
  681.             pSmEndDev->isMaster = TRUE;
  682.             if (pSmEndDev->startAddr != NULL)
  683.                 {
  684.                 SM_LOG (SM_DBG_LOAD,
  685.                         "MASTER: sequential addressing enabled at (0x%x)n",
  686.                         (unsigned)pSmEndDev->startAddr, 0, 0, 0, 0, 0);
  687.                 }
  688.             else
  689.                 {
  690.                 SM_LOG (SM_DBG_LOAD,
  691.                         "MASTER: sequential addressing disabledn",
  692.                         0, 0, 0, 0, 0, 0);
  693.                 }
  694.             }
  695.         /* Perform device memory allocation/distribution */
  696.         if (smEndMemInit (pSmEndDev) == ERROR)
  697.             {
  698.             smEndUnload (pSmEndDev);
  699.             return ((END_OBJ *)ERROR);
  700.             }
  701.         /* Initialize the shared memory descriptor.  */
  702.         pAnchor = pSmEndDev->pAnchor;
  703.         smPktInit (&pSmEndDev->smPktDesc, pSmEndDev->pAnchor,
  704.                    pSmEndDev->maxPackets, pSmEndDev->ticksPerBeat,
  705.                    pSmEndDev->intType,    pSmEndDev->intArg1,
  706.                    pSmEndDev->intArg2,    pSmEndDev->intArg3);
  707.         pSmEndDev->smPktDesc.hdrLocalAdrs = pSmEndDev->pSmPktHdr;
  708.         /* initialize the END and MIB2 parts of the device structure */
  709.     
  710.         if ((END_OBJ_INIT (&pSmEndDev->end, (DEV_OBJ *)pSmEndDev,
  711.                            SM_END_DEV_NAME, pSmEndDev->unit, &smEndFuncTable,
  712.                            "Shared Memory END Driver") != ERROR) &&
  713.             (END_MIB_INIT (&pSmEndDev->end, M2_ifType_other, enetAddr,
  714.                            EADDR_LEN, SM_END_CLST_SIZ,
  715.                            SM_END_MIB2_SPEED) != ERROR))
  716.             {
  717.             /* configure the device */
  718.             smEndConfig (pSmEndDev, SC_INIT);
  719.             /* XXX
  720.              * The following code is a hack.  The anchor may not even be
  721.              * mapped to the bus yet!  When probing with the next few lines
  722.              * Bus Errors occur on many boards if the slave beats the master
  723.              * to the pool.  The hack here simply avoids the sequential
  724.              * addressing if the slave gets a BERR looking for the anchor.
  725.              * Therefore, reliable use of sequential addressing can only be
  726.              * guaranteed if the slave is stopped during the booting sequence
  727.              * until the master has fully booted.  Towards this end an initial
  728.              * delay in bus probing is introduced based on processor number.
  729.              * If the first probe is unsuccessful, an exponential increase in
  730.              * delay period is used to reduce bus contention on subsequent
  731.              * probes.  This workaround is no worse than receiving BERRs
  732.              * but does reduce bus contention and the number of BERRs.  Note
  733.              * that the master procesor is assumed to be processor #0 (even
  734.              * though it may not be).  Processor #0 has no effective delay
  735.              * period on the first or subsequent bus probes!  This is so the
  736.              * presumed master processor can proceed with minimal delay.
  737.              */
  738.             for (tics <<= 1; (tics < SM_MAX_WAIT) && (anchorSet == ERROR);
  739.                  tics <<= 1)
  740.                 {
  741.                 smUtilDelay (NULL, tics);
  742.                 if ((anchorSet = smUtilMemProbe ((char *)pAnchor, READ, 4,
  743.                                                  (char *)&temp))
  744.                               != OK)
  745.                     continue;
  746.                 }
  747.             if (tics >= SM_MAX_WAIT)
  748.                 {
  749.                 SM_LOG (SM_DBG_LOAD, "smEndLoad: Error: sm probe timed outn",
  750.                         0, 0, 0, 0, 0, 0);
  751.                 smEndUnload (pSmEndDev);
  752.                 return ((END_OBJ *)ERROR);
  753.                 }
  754.             SM_LOG (SM_DBG_LOAD, "smEndLoad: sm probe worked, tics = %un",
  755.                     tics, 0, 0, 0, 0, 0);
  756.             /*
  757.              * IP -> HW Address Resolution
  758.              * Whether or not sequential addressing is enabled, we calculate
  759.              * the HW address.  ARP protocol does not apply.
  760.              */
  761.             muxAddrResFuncAdd (M2_ifType_other, 0x800, smEndAddrResolve);
  762.             /* set the flags to indicate readiness */
  763.             SM_RCV_TASK_INACTIVE;
  764.             END_OBJ_READY (&pSmEndDev->end, smEndDevAttr);
  765.             pSmEndDev->flags |= S_ACTIVE;
  766.             SM_LOG (SM_DBG_LOAD, "Done loading smEnd - flags = %#lxn",
  767.                     pSmEndDev->flags, 0, 0, 0, 0, 0);
  768.             return (&pSmEndDev->end);
  769.             }
  770.         }
  771.     smEndUnload (pSmEndDev);
  772.     return ((END_OBJ *)ERROR);
  773.     }
  774. /*******************************************************************************
  775. *
  776. * smEndUnload - unload sm device from the system
  777. *
  778. * This routine unloads the device pointed to by <pSmEndDev> from the system.
  779. *
  780. * RETURNS: OK or ERROR.
  781. *
  782. * SEE ALSO: smEndLoad()
  783. */
  784. LOCAL STATUS smEndUnload
  785.     (
  786.     void * pObj /* device control pointer */
  787.     )
  788.     {
  789.     unsigned         i;
  790.     unsigned         cnt;
  791.     SM_END_DEV *     pSmEndDev = (SM_END_DEV *)pObj;
  792.     SM_PKT_MEM_HDR * pSmPktHdr = NULL; /* packet header */
  793.     SM_LOG (SM_DBG_UNLOAD, "smEndUnload: startn", 0, 0, 0, 0, 0, 0);
  794.     if (pSmEndDev == NULL)
  795.         {
  796.         SM_LOG (SM_DBG_UNLOAD, "smEndUnload error: NULL device pointern",
  797.                 0, 0, 0, 0, 0, 0);
  798. return (ERROR);
  799.         }
  800.     /* been there, done that... */
  801.     if (pSmEndDev->cookie != SM_END_COOKIE)
  802.         {
  803.         SM_LOG (SM_DBG_UNLOAD, "smEndUnload warning: dev already unloadedn",
  804.                 0, 0, 0, 0, 0, 0);
  805. return (OK);
  806.         }
  807. #ifdef SM_DBG
  808.     if (!SM_END_IS_LOADED)
  809.         {
  810.         SM_LOG (SM_DBG_UNLOAD, "smEndUnload warning: device not loadedn",
  811.                 0, 0, 0, 0, 0, 0);
  812.         }
  813. #endif /* SM_DBG */
  814.     SM_END_UNLOAD;
  815.     /* detach from shared mem */
  816.     if (pSmEndDev->smPktDesc.status == SM_CPU_ATTACHED)
  817.         {
  818.         (void) smPktDetach (&pSmEndDev->smPktDesc, SM_FLUSH);
  819.         }
  820.     /* clear END status flags */
  821.     END_FLAGS_CLR (&pSmEndDev->end, SM_END_ATTR_CLR);
  822.     pSmEndDev->flags = 0;
  823.     /* finished with END object */
  824.     END_OBJECT_UNLOAD (&pSmEndDev->end);
  825.     /* free allocated memory as necessary */
  826.     if (pSmEndDev->tupleId != NULL)
  827.         netMblkClChainFree (pSmEndDev->tupleId);
  828.     if (pSmEndDev->end.pNetPool != NULL)
  829.         netPoolDelete (pSmEndDev->end.pNetPool);
  830.     if (pSmEndDev->pClustMem != NULL)
  831.         cacheDmaFree (pSmEndDev->pClustMem);
  832.     if (pSmEndDev->pMclBlkCfg != NULL)
  833.         free (pSmEndDev->pMclBlkCfg);
  834.     if (pSmEndDev->end.pNetPool != NULL)
  835.         free (pSmEndDev->end.pNetPool);
  836.     /*
  837.      * If this is the master CPU, delete heartbeat watchdog timer
  838.      * and free shared memory if it was allocated.
  839.      */
  840.     if (pSmEndDev->isMaster)
  841.         {
  842.         pSmPktHdr = SM_OFFSET_TO_LOCAL (ntohl(pSmEndDev->pAnchor->smPktHeader),
  843.                                         (int)pSmEndDev->pAnchor,
  844.                                         SM_PKT_MEM_HDR *);
  845.         if (pSmPktHdr->reserved2 != 0)
  846.             {
  847.             wdDelete ((WDOG_ID) ntohl (pSmPktHdr->reserved2));
  848.             }
  849.         if (pSmEndDev->smAlloc)
  850.             cacheDmaFree (pSmEndDev->pMem);
  851.         }
  852.     /* invalidate structure */
  853.     pSmEndDev->cookie = 0;
  854.     /* if this is the last entry in the unit table, free the table */
  855.     for (i = 0, cnt = 0; i < NSM; ++i)
  856.         {
  857.         if (unitTbl[i] == pSmEndDev)
  858.             unitTbl[i] = NULL;
  859.         else
  860.             ++cnt;
  861.         }
  862.     if (cnt == 0)
  863.         free (unitTbl);
  864.     /* free memory for device control structure */
  865.     free (pSmEndDev);
  866.     pSmEndDev = NULL;
  867.     SM_LOG (SM_DBG_UNLOAD, "smEndUnload: Donen", 0, 0, 0, 0, 0, 0);
  868.     return (OK);
  869.     }
  870. /******************************************************************************
  871. *
  872. * smEndConfig - configure the sm interface to the device
  873. *
  874. * Configure the interface through controlled state changes.
  875. *
  876. * RETURNS: OK or ERROR.
  877. */
  878. LOCAL STATUS smEndConfig
  879.     (
  880.     SM_END_DEV * pSmEndDev, /* device to be configured */
  881.     STATE_CHANGE sDelta /* type of configuration change */
  882.     )
  883.     {
  884.     STATUS      result          = OK;
  885.     /* shutdown device completely if attached and reclaim packets */
  886.     if (pSmEndDev->smPktDesc.status == SM_CPU_ATTACHED)
  887.         {
  888.         (void) smPktDetach (&pSmEndDev->smPktDesc, SM_FLUSH);
  889.         pSmEndDev->smPktDesc.status = 0;
  890.         pSmEndDev->flags &= ~S_CPU_ATTACHED;
  891.         }
  892.     /* Perform requested state change */
  893.     switch (sDelta)
  894.         {
  895.         case SC_INT2POLL:
  896.             if (pollTaskId == NONE)
  897.                 {
  898.                 if ((result = smUtilIntConnect (LOW_PRIORITY,(FUNCPTR)smEndIsr,
  899.                                                 (int)pSmEndDev, SM_INT_NONE,
  900.                                                 0, 0, 0))
  901.                             == OK)
  902.                     {
  903.                     connected[SM_INT_NONE] = TRUE;
  904.                     pollTaskId = taskNameToId (SM_POLL_TASK_NAME);
  905.                     }
  906.                 }
  907.             else
  908.                 {
  909.                 result = taskResume (pollTaskId);
  910.                 }
  911.             break;
  912.         case SC_POLL2INT:
  913.             if (pollTaskId == NONE)
  914.                 {
  915.                 errno = EINVAL;
  916.                 result = ERROR;
  917.                 }
  918.             else
  919.                 {
  920.                 taskSuspend (pollTaskId);
  921.                 if ((!connected[pSmEndDev->intType]) &&
  922.                     (result = smUtilIntConnect (LOW_PRIORITY,
  923.                                                 (FUNCPTR)smEndIsr,
  924.                                                 (int)pSmEndDev,
  925.                                                 pSmEndDev->intType,
  926.                                                 pSmEndDev->intArg1,
  927.                                                 pSmEndDev->intArg2,
  928.                                                 pSmEndDev->intArg3))
  929.                             == OK)
  930.                     {
  931.                     connected[pSmEndDev->intType] = TRUE;
  932.                     }
  933.                 }
  934.             break;
  935.         case SC_INIT:    /* set hardware address */
  936.             smEndHwAddrSet (pSmEndDev);
  937.             break;
  938.         case SC_NONE:
  939.             break;
  940.         default:
  941.             SM_LOG (SM_DBG_CFG, "smEndConfig: unknown state change %xn",
  942.                     sDelta, 0, 0, 0, 0, 0);
  943.             errno  = EINVAL;
  944.             result = ERROR;
  945.         }
  946. #if FALSE /* XXXmas future enhancement */
  947.     /* set up address filter for multicasting */
  948.     if (END_MULTI_LST_CNT(&pSmEndDev->end) > 0)
  949.         {
  950.         smEndAddrFilterSet (pSmEndDev);
  951.         }
  952. #endif
  953.     /* attach to shared memory */
  954.     if (smPktAttach (&pSmEndDev->smPktDesc) == ERROR)
  955. {
  956.         SM_LOG (SM_DBG_CFG, "smEndConfig: ERROR attaching to sm: 0x%xn",
  957.                 errno, 0, 0, 0, 0, 0);
  958.         smEndUnload (pSmEndDev); /* ??? is this necessary? */
  959.      return (ERROR);
  960. }
  961.     pSmEndDev->flags |= S_CPU_ATTACHED;
  962.     return (result);
  963.     }
  964. #if FALSE /* XXXmas future enhancement */
  965. /******************************************************************************
  966. *
  967. * smEndAddrFilterSet - set the address filter for multicast addresses
  968. *
  969. * This routine goes through all of the multicast addresses on the list
  970. * of addresses (added with the endAddrAdd() routine) and sets the
  971. * device's filter correctly.
  972. *
  973. * RETURNS: N/A.
  974. */
  975. void smEndAddrFilterSet
  976.     (
  977.     VOID * pObj /* device to be updated */
  978.     )
  979.     {
  980.     SM_END_DEV *  pSmEndDev = (SM_END_DEV *)pObj; /* device to be updated */
  981.     ETHER_MULTI * pCurr;
  982.     pCurr = END_MULTI_LST_FIRST (&pSmEndDev->end);
  983.     while (pCurr != NULL)
  984. {
  985.         /* TODO - set up the multicast list */
  986.         
  987. pCurr = END_MULTI_LST_NEXT(pCurr);
  988. }
  989.     
  990.     /* TODO - update the device filter list */
  991.     }
  992. #endif
  993. /******************************************************************************
  994. *
  995. * smEndStart - start the device
  996. *
  997. * This function calls the system functions to connect interrupts and start the
  998. * device running in interrupt mode.
  999. *
  1000. * RETURNS: OK or ERROR if this cpu is configured for polled mode only.
  1001. */
  1002. LOCAL STATUS smEndStart
  1003.     (
  1004.     VOID * pObj /* device ID */
  1005.     )
  1006.     {
  1007.     SM_END_DEV * pSmEndDev = (SM_END_DEV *)pObj; /* device to be started */
  1008.     STATUS       result    = OK;
  1009.     /* free all queued tuples */
  1010.     smEndPollQFree (pSmEndDev);
  1011.     /*
  1012.      * If not already connected, connect sm interrupt.
  1013.      * ++ NOTE: This is necessary until a functional intDisconnect() or
  1014.      * smUtilIntDisconnect() routine becomes available.
  1015.      */
  1016.     if (!connected[pSmEndDev->intType])
  1017.         {
  1018.         if ((result = smUtilIntConnect (LOW_PRIORITY, (FUNCPTR)smEndIsr,
  1019.                                         (int)pSmEndDev, pSmEndDev->intType,
  1020.                                         pSmEndDev->intArg1, pSmEndDev->intArg2,
  1021.                                         pSmEndDev->intArg3))
  1022.                     == OK)
  1023.             {
  1024.             connected[pSmEndDev->intType] = TRUE;
  1025.             if ((pSmEndDev->intType == SM_INT_NONE) && (pollTaskId == NONE))
  1026.                 {
  1027.                 pollTaskId = taskNameToId (SM_POLL_TASK_NAME);
  1028.                 }
  1029.             }
  1030.         }
  1031.     if (result == OK)
  1032.         {
  1033.         SM_LOG (SM_DBG_START, "smEndStart: interrupt connectedn",
  1034.                 0, 0, 0, 0, 0, 0);
  1035.         /* enable interrupt */
  1036.         smUtilIntEnable (pSmEndDev);
  1037.         SM_LOG (SM_DBG_START, "smEndStart: interrupt enabledn",
  1038.                 0, 0, 0, 0, 0, 0);
  1039.         /* start the device: enable interrupts */
  1040.         SM_END_START;
  1041.         }
  1042.     else
  1043.         {
  1044.         SM_LOG (SM_DBG_START, "smEndStart: ERROR: can't connect interrupt!n",
  1045.                 0, 0, 0, 0, 0, 0);
  1046.         }
  1047.     return (result);
  1048.     }
  1049. /******************************************************************************
  1050. *
  1051. * smEndStop - stop the device
  1052. *
  1053. * This function calls the system functions to disconnect interrupts and stop
  1054. * the device from operating in interrupt mode.
  1055. *
  1056. * RETURNS: OK or ERROR.
  1057. */
  1058. LOCAL STATUS smEndStop
  1059.     (
  1060.     VOID * pObj /* device to be stopped */
  1061.     )
  1062.     {
  1063.     SM_END_DEV * pSmEndDev = (SM_END_DEV *)pObj; /* device to be stopped */
  1064.     STATUS       result;
  1065.     /* stop/disable the device. */
  1066.     SM_END_STOP;
  1067.     smUtilIntDisable (pSmEndDev);  /* XXXmas someday will be a real call */
  1068.     /*
  1069.      * XXXmas  someday this will have to be a call to a real functional
  1070.      * smUtilIntDisconnect() routine.
  1071.      */
  1072.     if ((result = smUtilIntDisconnect (LOW_PRIORITY, (FUNCPTR)smEndIsr,
  1073.                                        (int)pSmEndDev, pSmEndDev->intType,
  1074.                                        pSmEndDev->intArg1, pSmEndDev->intArg2,
  1075.                                        pSmEndDev->intArg3))
  1076.                 == ERROR)
  1077. {
  1078. SM_LOG (SM_DBG_STOP, "smEndStop: Can't disconnect interrupt!n",
  1079. 0, 0, 0, 0, 0, 0);
  1080. }
  1081.     else
  1082.         {
  1083.         if (pSmEndDev->intType == SM_INT_BUS)
  1084.             connected[SM_INT_BUS] = FALSE;
  1085.         SM_LOG (SM_DBG_STOP, "smEndStop: interrupt disconnectedn",
  1086.                 0, 0, 0, 0, 0, 0);
  1087.         }
  1088.     return (result);
  1089.     }
  1090. /******************************************************************************
  1091. *
  1092. * smEndPollStart - start polled mode operation
  1093. *
  1094. * This function starts full polled mode operation for both the shared memory
  1095. * and END interfaces.
  1096. *
  1097. * RETURNS: OK or ERROR.
  1098. */
  1099. LOCAL STATUS smEndPollStart
  1100.     (
  1101.     void * pObj
  1102.     )
  1103.     {
  1104.     SM_END_DEV * pSmEndDev = (SM_END_DEV *)pObj; /* device receiving command */
  1105.     int          oldLevel;
  1106.     STATUS       result = ERROR;
  1107.     /* if sm is already in polled mode, just set END polled flag */
  1108.     if (SM_END_IS_ACTIVE)
  1109.         {
  1110.         if (!SM_END_POLL_SM_RDY)
  1111.             {
  1112.             oldLevel = intLock ();          /* disable ints during update */
  1113.             smUtilIntDisable (pSmEndDev);
  1114.             pSmEndDev->flags |= S_POLLED_SM;
  1115.             intUnlock (oldLevel);   /* now smEndInt won't get confused */
  1116.             smEndConfig (pSmEndDev, SC_INT2POLL); /* reconfigure device */
  1117.             }
  1118.         pSmEndDev->flags |= S_POLLED_END;
  1119.         result = OK;
  1120.         }
  1121.     else
  1122.         errno = ENODEV;
  1123.     return (result);
  1124.     }
  1125. /******************************************************************************
  1126. *
  1127. * smEndPollStop - stop polled mode operation
  1128. *
  1129. * This function stops polled mode operation for the MUX interface and, if not
  1130. * locked in polled mode, changes shared memory mode to interrupt.
  1131. *
  1132. * RETURNS: OK or ERROR.
  1133. */
  1134. LOCAL STATUS smEndPollStop
  1135.     (
  1136.     void * pObj
  1137.     )
  1138.     {
  1139.     SM_END_DEV * pSmEndDev = (SM_END_DEV *)pObj; /* device receiving command */
  1140.     int          oldLevel;
  1141.     STATUS       result = ERROR;
  1142.     /* if sm is not in polled mode, just clear END polled flag */
  1143.     if (SM_END_IS_ACTIVE)
  1144.         {
  1145.         if (SM_END_POLL_SM_RDY && !SM_IS_POLLED_LOCKED)
  1146.             {
  1147.             oldLevel = intLock ();          /* disable ints during update */
  1148.             smUtilIntEnable (pSmEndDev);
  1149.             pSmEndDev->flags &= ~S_POLLED_SM;
  1150.             intUnlock (oldLevel);   /* now smEndInt won't get confused */
  1151.             smEndConfig (pSmEndDev, SC_POLL2INT); /* reconfigure device */
  1152.             }
  1153.         pSmEndDev->flags &= ~S_POLLED_END;
  1154.         result = OK;
  1155.         }
  1156.     else
  1157.         errno = ENODEV;
  1158.     return (result);
  1159.     }
  1160. /******************************************************************************
  1161. *
  1162. * smEndIoctl - sm device I/O control routine
  1163. *
  1164. * This routine is called to perform control operations on the sm device network
  1165. * interface.  The implemented commands are:
  1166. *
  1167. * Command Data   Function
  1168. * ------------ ----------------  -----------------------------------------
  1169. * EIOCSADDR char *   set sm device address
  1170. * EIOCGADDR char *   get sm device address
  1171. * EIOCSFLAGS int   set sm device flags
  1172. * EIOCGFLAGS int   get sm device flags
  1173. * EIOCPOLLSTART N/A   start polled operation
  1174. * EIOCPOLLSTOP N/A   stop polled operation
  1175. * EIOCGMIB2 M2_INTERFACETBL * return MIB2 information
  1176. * EIOCGFBUF int   return minimum First Buffer for chaining
  1177. *
  1178. * RETURNS: A command specific response, usually OK or an error code:
  1179. * EINVAL (invalid argument) or ENOSUP (unsupported Ioctl command).
  1180. */
  1181. LOCAL int smEndIoctl
  1182.     (
  1183.     VOID *  pObj, /* device receiving command */
  1184.     int     cmd, /* ioctl command code */
  1185.     caddr_t data /* command argument */
  1186.     )
  1187.     {
  1188.     SM_END_DEV * pSmEndDev = (SM_END_DEV *)pObj; /* device receiving command */
  1189.     int          error     = OK;
  1190.     long         value;
  1191.     switch (cmd)
  1192.         {
  1193.         case EIOCSADDR: /* set sm interface address */
  1194.     if (data == NULL)
  1195. return (EINVAL);
  1196.             bcopy ((char *)data, (char *)SM_END_ADDR_GET (&pSmEndDev->end),
  1197.    SM_END_ADDR_LEN_GET (&pSmEndDev->end));
  1198.             break;
  1199.         case EIOCGADDR: /* get sm interface address */
  1200.     if (data == NULL)
  1201. return (EINVAL);
  1202.             bcopy ((char *)SM_END_ADDR_GET (&pSmEndDev->end), (char *)data,
  1203.     SM_END_ADDR_LEN_GET (&pSmEndDev->end));
  1204.             break;
  1205.         case EIOCSFLAGS: /* set sm END device flags */
  1206.     value = (long)data;
  1207.     if (value < 0)
  1208. {
  1209. value = -(--value);
  1210. END_FLAGS_CLR (&pSmEndDev->end, value);
  1211. }
  1212.     else
  1213. {
  1214. value &= ~IFF_MULTICAST;  /* XXXmas temporary */
  1215. END_FLAGS_SET (&pSmEndDev->end, value);
  1216. }
  1217.     smEndConfig (pSmEndDev, SC_NONE);
  1218.             break;
  1219.         case EIOCGFLAGS: /* get sm END device flags */
  1220.     *(int *)data = END_FLAGS_GET(&pSmEndDev->end);
  1221.             break;
  1222.         case EIOCGMWIDTH: /* get sm END memory width (#bytes) */
  1223.     *(int *)data = 0; /* no restrictions on size */
  1224.             break;
  1225.         case EIOCMULTIGET: /* get multicast list (XXXmas future) */
  1226.     return (ENOTSUP);
  1227.             break;
  1228. case EIOCPOLLSTART: /* Begin polled operation */
  1229.     smEndPollStart (pSmEndDev);
  1230.     break;
  1231. case EIOCPOLLSTOP: /* End polled operation */
  1232.     smEndPollStop (pSmEndDev);
  1233.     break;
  1234.         case EIOCGMIB2: /* return MIB information */
  1235.             if (data == NULL)
  1236.                 return (EINVAL);
  1237.             bcopy((char *)&pSmEndDev->end.mib2Tbl, (char *)data,
  1238.                   sizeof(pSmEndDev->end.mib2Tbl));
  1239.             break;
  1240.         case EIOCGFBUF: /* return minimum First Buffer for chaining */
  1241.             if (data == NULL)
  1242.                 return (EINVAL);
  1243.             *(int *)data = SM_END_MIN_FBUF;
  1244.             break;
  1245.         default:
  1246.             SM_LOG (SM_DBG_IOCTL, "smEndIoctl: unsupported command: 0x%xn",
  1247.                     cmd, 0, 0, 0, 0, 0);
  1248.             error = ENOTSUP;
  1249.         }
  1250.     return (error);
  1251.     }
  1252. /******************************************************************************
  1253. *
  1254. * smEndHwAddrSet - set hardware address
  1255. *
  1256. * This routine sets the hardware address associated with the 'sm' device
  1257. * specified by <pSmEndDev>.  It also stores the non-sequential IP address in
  1258. * the associated CPU descriptor for fast address resolution.
  1259. *
  1260. * The 'sm' device H/W address consists of six bytes.  Depending upon whether
  1261. * sequential addressing is selected or not, the last three bytes assume
  1262. * different values:
  1263. *
  1264. * Sequential addressing: { 0x00, 0x02, 0xE2, ip[2], ip[3], ip[4] }
  1265. * where ip is the lower three bytes of the IP interface address.
  1266. *
  1267. * Not sequential addressing: { 0x00, 0x02, 0xE2, 0x00, unit, cpu }
  1268. *
  1269. * RETURNS: N/A
  1270. */
  1271. LOCAL void smEndHwAddrSet
  1272.     (
  1273.     SM_END_DEV * pSmEndDev  /* device for which to set address */
  1274.     )
  1275.     {
  1276.     u_char *  pEaddr; /* ethernet address */
  1277.     u_long addr; /* address */
  1278.     SM_PKT_MEM_HDR * pSmPktHdr; /* packet header */
  1279.     FAST SM_CPU_DESC * pCpuDesc; /* sm CPU descriptor */
  1280.     FAST SM_ANCHOR * pAnchor = pSmEndDev->pAnchor;
  1281.     FAST SM_HDR * pSmHdr;
  1282.     FAST SM_DESC * pSmDesc = &pSmEndDev->smPktDesc.smDesc;
  1283.     pEaddr = etherAddrPtr (pSmEndDev->arpcom.ac_enaddr);
  1284.     bzero ((caddr_t)pEaddr, 6); /* fill in ethernet address */
  1285.     pEaddr [0] = 0x00;
  1286.     pEaddr [1] = 0x02;
  1287.     pEaddr [2] = 0xE2;
  1288.     pSmPktHdr = pSmEndDev->smPktDesc.hdrLocalAdrs;
  1289.     pSmEndDev->localCpu = pSmDesc->cpuNum;
  1290.     SM_LOG (SM_DBG_CFG, "smEndHwAddrSet: rsvrd1 = %#xn",
  1291.             ntohl (pSmPktHdr->reserved1), 0, 0, 0, 0, 0);
  1292.     if (pSmPktHdr->reserved1 != 0) /* sequential addressing */
  1293. {
  1294. /*
  1295.  * The backplane hw address consists of
  1296.  * { 0x00, 0x02, 0xE2, ip[1], ip[2], ip[3] }.
  1297.  * where ip is the lower three bytes of
  1298.  * the IP interface address.
  1299.  */
  1300. pSmEndDev->masterAddr = ntohl (pSmPktHdr->reserved1) & 0x00FFFFFF;
  1301. addr = pSmEndDev->masterAddr + pSmEndDev->localCpu;
  1302. pEaddr [3] = ((addr >> 16) & 0xff);
  1303. pEaddr [4] = ((addr >> 8)  & 0xff);
  1304. pEaddr [5] = (addr & 0xff);
  1305. }
  1306.     else
  1307. {
  1308.      /*
  1309.       * Backplane hw address consists of
  1310.        * { 0x00, 0x02, 0xE2, 0x00, unit, cpu }.
  1311.        */
  1312. pEaddr [3] = 0;
  1313. pEaddr [4] = pSmEndDev->unit;
  1314. pEaddr [5] = pSmEndDev->localCpu;
  1315. /*
  1316.  * store the non-sequential IP address for this CPU in the CPU
  1317.  * descriptor for the local CPU in shared memory for all to see
  1318.  */
  1319.         pSmHdr = SM_OFFSET_TO_LOCAL (ntohl (pAnchor->smHeader), pSmDesc->base,
  1320.                                      SM_HDR *);
  1321.         pCpuDesc = SM_OFFSET_TO_LOCAL (ntohl (pSmHdr->cpuTable), pSmDesc->base,
  1322.                                        SM_CPU_DESC *);
  1323.         pCpuDesc = &(pCpuDesc[pSmDesc->cpuNum]);
  1324.         pCpuDesc->reserved1 = (unsigned)pSmEndDev->ipAddr;
  1325. }
  1326.     SM_LOG (SM_DBG_LOAD, "smEndHwAddrSet: H/W address = %sn",
  1327.             (int)ether_sprintf (pEaddr), 0, 0, 0, 0, 0);
  1328.     }
  1329. /******************************************************************************
  1330. *
  1331. * smEndParse - parse input paramter string and derive parameter values
  1332. *
  1333. * This routine parses the input parameter string, deriving the values of each
  1334. * parameter in the assumed order and radix as shown here:
  1335. *
  1336. * "<unit>:<busSpace>:<pAnchor>:<pMem>:<memSize>:<tasType>:<maxCpus>:
  1337. *  <masterCpu>:<maxPktBytes>:<startAddr>:<ipAddr>:<maxInputPkts>:<intType>:
  1338. *  <intArg1>:<intArg2>:<intArg3>:<mbNum>:<cbNum>"
  1339. *
  1340. * Parameter Radix Use
  1341. * ------------- ----- -------------------------------------------------------
  1342. * unitNumber  10 device unit number assigned by operating system
  1343. * busSpace  16 bus address space; NONE = local, else, VME AM/PCI space
  1344. * [busSpace is not yet supported in smPktLib.c]
  1345. * pAnchor  16 shared memory anchor region @<busSpace>
  1346. * pMem  16 start of shared memory (NONE = allocate) @<busSpace>
  1347. * memSize  16 total shared memory size in bytes
  1348. * tasType  10 test-and-set type (SM_TAS_HARD or SM_TAS_SOFT)
  1349. * maxCpus  10 maximum number of CPUs supported on backplane
  1350. * (0 = default)
  1351. * masterCpu  10 master CPU#
  1352. * maxPktBytes  10 maximum number of bytes per shared memory packet
  1353. * (0 = default)
  1354. * startAddr  16 start of sequential IP addressing (0 = not sequential)
  1355. * ipAddr  16 non-sequential IP address (0 = sequential)
  1356. * maxInputPkts  10 maximum number of queued receive packets for this CPU
  1357. * (0 = default)
  1358. * intType  10 interrupt method (SM_INT_MAILBOX/BUS/NONE)
  1359. * intArg1  16 1st interrupt argument
  1360. * intArg2  16 2nd interrupt argument
  1361. * intArg3  16 3rd interrupt argument
  1362. * mbNum  16 number of mBlks in driver memory pool (if < 16, a
  1363. * default value is used)
  1364. * cbNum  16 number of clBlks in driver memory pool (if < 16, a
  1365. * default value is used)
  1366. *
  1367. * The parameter values are delimited by colons and the EOS.
  1368. *
  1369. * RETURNS: OK or ERROR if bogus string.
  1370. */
  1371. LOCAL STATUS smEndParse
  1372.     (
  1373.     SM_END_DEV * pSmEndDev, /* pointer to device descriptor */
  1374.     char *       pParamStr /* pointer to parameter string to parse */
  1375.     )
  1376.     {
  1377.     char * tok    = NULL; /* parameter value (token) pointer */
  1378.     char * pLast  = NULL; /* string position of last parse */
  1379.     /* derive unit number */
  1380.     if (((tok = strtok_r (pParamStr, ":", &pLast)) == NULL) ||
  1381.         ((pSmEndDev->unit = (unsigned) strtoul (tok, NULL, 10)) >= NSM))
  1382.         {
  1383.         SM_LOG (SM_DBG_LOAD, "missing or illegal unit number: %dn",
  1384.                 pSmEndDev->unit, 0, 0, 0, 0, 0);
  1385.         return (ERROR);
  1386.         }
  1387.     /*
  1388.      * derive bus address space for shared memory anchor and shared memory
  1389.      * addresses; NONE = local bus
  1390.      */
  1391.     if (((tok = strtok_r (NULL, ":", &pLast)) == NULL) ||
  1392.         ((pSmEndDev->busSpace = (ULONG) strtoul (tok, NULL, 16)) == NULL))
  1393.         {
  1394.         SM_LOG (SM_DBG_LOAD, "Missing or NULL SM bus spacen",
  1395.                 0, 0, 0, 0, 0, 0);
  1396.         return (ERROR);
  1397.         }
  1398.     /* derive shared memory anchor address; must not be NULL */
  1399.     if (((tok = strtok_r (NULL, ":", &pLast)) == NULL) ||
  1400.         ((pSmEndDev->pAnchor = (SM_ANCHOR *) strtoul (tok, NULL, 16)) == NULL))
  1401.         {
  1402.         SM_LOG (SM_DBG_LOAD, "Missing or NULL SM anchor addressn",
  1403.                 0, 0, 0, 0, 0, 0);
  1404.         return (ERROR);
  1405.         }
  1406.     /* derive pointer to shared memory; NONE (-1) = allocate dynamically */
  1407.     if (((tok = strtok_r (NULL, ":", &pLast)) == NULL) ||
  1408.         ((pSmEndDev->pMem = (char *) strtoul (tok, NULL, 16)) == NULL))
  1409.         {
  1410.         SM_LOG (SM_DBG_LOAD, "Missing or NULL SM addressn",
  1411.                 0, 0, 0, 0, 0, 0);
  1412.         return (ERROR);
  1413.         }
  1414.     /* derive shared memory size in bytes */
  1415.     if (((tok = strtok_r (NULL, ":", &pLast)) == NULL) ||
  1416.         ((pSmEndDev->memSize = (ULONG) strtoul (tok, NULL, 16)) == 0))
  1417.         {
  1418.         SM_LOG (SM_DBG_LOAD, "Missing or zero SM sizen",
  1419.                 0, 0, 0, 0, 0, 0);
  1420.         return (ERROR);
  1421.         }
  1422.     /* derive test-and-set type */
  1423.     if (((tok = strtok_r (NULL, ":", &pLast)) == NULL) ||
  1424.         ((pSmEndDev->tasType = (unsigned) strtoul (tok, NULL, 10)) >
  1425.          SM_TAS_HARD))
  1426.         {
  1427.         SM_LOG (SM_DBG_LOAD, "Missing or illegal test-and-set type: %dn",
  1428.                 pSmEndDev->tasType, 0, 0, 0, 0, 0);
  1429.         return (ERROR);
  1430.         }
  1431.     /* derive maximum number of CPUs supported in shared memory */
  1432.     if ((tok = strtok_r (NULL, ":", &pLast)) == NULL)
  1433.         {
  1434.         SM_LOG (SM_DBG_LOAD, "Missing number of CPUsn",
  1435.                 0, 0, 0, 0, 0, 0);
  1436.         return (ERROR);
  1437.         }
  1438.     if ((pSmEndDev->maxCpus = (unsigned) strtoul (tok, NULL, 10)) == 0)
  1439.         pSmEndDev->maxCpus = DEFAULT_CPUS_MAX;
  1440.     /* derive master CPU number */
  1441.     if ((tok = strtok_r (NULL, ":", &pLast)) == NULL)
  1442.         {
  1443.         SM_LOG (SM_DBG_LOAD, "Missing master CPU numbern",
  1444.                 0, 0, 0, 0, 0, 0);
  1445.         return (ERROR);
  1446.         }
  1447.     if ((pSmEndDev->masterCpu = (unsigned) strtoul (tok, NULL, 10))
  1448.                               >= pSmEndDev->maxCpus)
  1449.         {
  1450.         SM_LOG (SM_DBG_LOAD, "Master CPU number: %d >= #CPUs (%d)n",
  1451.                 pSmEndDev->masterCpu, pSmEndDev->maxCpus, 0, 0, 0, 0);
  1452.         return (ERROR);
  1453.         }
  1454.     /* derive maximum shared memory packet size */
  1455.     if ((tok = strtok_r (NULL, ":", &pLast)) == NULL)
  1456.         {
  1457.         SM_LOG (SM_DBG_LOAD, "Missing max #bytes per packetn",
  1458.                 0, 0, 0, 0, 0, 0);
  1459.         return (ERROR);
  1460.         }
  1461.     if ((pSmEndDev->maxPktBytes = (ULONG) strtoul (tok, NULL, 10)) == 0)
  1462.         pSmEndDev->maxPktBytes = DEFAULT_PKT_SIZE;
  1463.     /* derive shared memory sequential start IP address (0 = not sequential) */
  1464.     if (((tok = strtok_r (NULL, ":", &pLast)) == NULL))
  1465.         {
  1466.         SM_LOG (SM_DBG_LOAD, "Missing SM sequential starting IP addressn",
  1467.                 0, 0, 0, 0, 0, 0);
  1468.         return (ERROR);
  1469.         }
  1470.     pSmEndDev->startAddr = (char *) strtoul (tok, NULL, 16);
  1471.     /* derive shared memory non-sequential IP address (0 = sequential) */
  1472.     if (((tok = strtok_r (NULL, ":", &pLast)) == NULL))
  1473.         {
  1474.         SM_LOG (SM_DBG_LOAD, "Missing SM non-sequential IP addressn",
  1475.                 0, 0, 0, 0, 0, 0);
  1476.         return (ERROR);
  1477.         }
  1478.     pSmEndDev->ipAddr = (char *) strtoul (tok, NULL, 16);
  1479.     /* derive maximum #packets that can be received; must be > 0 */
  1480.     if (((tok = strtok_r (NULL, ":", &pLast)) == NULL) ||
  1481.         ((pSmEndDev->maxPackets = atoi (tok)) < 0))
  1482.         {
  1483.         SM_LOG (SM_DBG_LOAD, "Missing or illegal number of packets: %dn",
  1484.                 pSmEndDev->maxPackets, 0, 0, 0, 0, 0);
  1485.         return (ERROR);
  1486.         }
  1487.     if (pSmEndDev->maxPackets == 0)
  1488.         pSmEndDev->maxPackets = DEFAULT_PKTS_MAX;
  1489.     /* derive interrupt method */
  1490.     if (((tok = strtok_r (NULL, ":", &pLast)) == NULL) ||
  1491.         ((pSmEndDev->intType = (unsigned) strtoul (tok, NULL, 10)) >
  1492.          SM_INT_MAILBOX_R4))
  1493.         {
  1494.         SM_LOG (SM_DBG_LOAD, "Missing or illegal SM interrupt type: %dn",
  1495.                 pSmEndDev->intType, 0, 0, 0, 0, 0);
  1496.         return (ERROR);
  1497.         }
  1498.     /* derive interrupt argument 1 */
  1499.     if ((tok = strtok_r (NULL, ":", &pLast)) == NULL)
  1500.         {
  1501.         SM_LOG (SM_DBG_LOAD, "Missing SM interrupt 1st argumentn",
  1502.                 0, 0, 0, 0, 0, 0);
  1503.         return (ERROR);
  1504.         }
  1505.     pSmEndDev->intArg1 = (int) strtoul (tok, NULL, 16);
  1506.     /* derive interrupt argument 2 */
  1507.     if ((tok = strtok_r (NULL, ":", &pLast)) == NULL)
  1508.         {
  1509.         SM_LOG (SM_DBG_LOAD, "Missing SM interrupt 2nd argumentn",
  1510.                 0, 0, 0, 0, 0, 0);
  1511.         return (ERROR);
  1512.         }
  1513.     pSmEndDev->intArg2 = (int) strtoul (tok, NULL, 16);
  1514.     /* derive interrupt argument 3 */
  1515.     if ((tok = strtok_r (NULL, ":", &pLast)) == NULL)
  1516.         {
  1517.         SM_LOG (SM_DBG_LOAD, "Missing SM interrupt 3rd argumentn",
  1518.                 0, 0, 0, 0, 0, 0);
  1519.         return (ERROR);
  1520.         }
  1521.     pSmEndDev->intArg3 = (int) strtoul (tok, NULL, 16);
  1522.     /* derive number of mBlks to allocate */
  1523.     if ((tok = strtok_r (NULL, ":", &pLast)) == NULL)
  1524.         {
  1525.         SM_LOG (SM_DBG_LOAD, "Missing number of mBlksn",
  1526.                 0, 0, 0, 0, 0, 0);
  1527.         return (ERROR);
  1528.         }
  1529.     pSmEndDev->mbNum = (uint32_t) strtoul (tok, NULL, 16);
  1530.     if (pSmEndDev->mbNum < SM_MIN_MBLK_NUM)
  1531.         pSmEndDev->mbNum = SM_DFLT_MBLK_NUM;
  1532.     /* derive number of clBlks to allocate */
  1533.     if ((tok = strtok_r (NULL, ":", &pLast)) == NULL)
  1534.         {
  1535.         SM_LOG (SM_DBG_LOAD, "Missing number of cBlksn",
  1536.                 0, 0, 0, 0, 0, 0);
  1537.         return (ERROR);
  1538.         }
  1539.     pSmEndDev->cbNum = (uint32_t) strtoul (tok, NULL, 16);
  1540.     if (pSmEndDev->cbNum < SM_MIN_CLBLK_NUM)
  1541.         pSmEndDev->cbNum = SM_DFLT_CLBLK_NUM;
  1542.     return (OK);
  1543.     }
  1544. /******************************************************************************
  1545. *
  1546. * smEndMemInit - set up and initialize memory for an sm device
  1547. *
  1548. * This routine sets up and initializes a net pool for the specified sm device.
  1549. *
  1550. * RETURNS: OK or ERROR if failure.
  1551. */
  1552. LOCAL STATUS smEndMemInit
  1553.     (
  1554.     SM_END_DEV * pSmEndDev
  1555.     )
  1556.     {
  1557.     SM_PKT_MEM_HDR * pSmPktHdr   = NULL; /* packet header */
  1558.     WDOG_ID          smEndBeatWd = NULL; /* heartbeat watchdog ID */
  1559.     UINT             smPktSize   = 0;
  1560.     M_CL_CONFIG      smEndMclBlkConfig = /* network mBlk/clBlk config table */
  1561.         {
  1562.         /* 
  1563.         no. mBlks no. clBlks memArea memSize
  1564.         ----------- ---------- ------- -------
  1565.         */
  1566.         0,  0,  NULL,  0
  1567.         };
  1568.     CL_DESC          smEndClDescTbl [] = /* network cluster pool config table*/
  1569.         {
  1570.         /* 
  1571.         clSize num memArea memSize
  1572.         ----------- ---- ------- -------
  1573.         */
  1574.         {0, 0, NULL, 0}
  1575.         }; 
  1576.     int              smEndClDescTblNumEnt = (NELEMENTS(smEndClDescTbl));
  1577.     /* If this is the master CPU, setup and initialize shared memory */
  1578.     if (pSmEndDev->isMaster)
  1579.         {
  1580.         /* if not already obtained, allocate the shared memory */
  1581.         if (pSmEndDev->pMem == (char *)NONE)
  1582.             {
  1583.             if (!CACHE_DMA_IS_WRITE_COHERENT () ||
  1584.                 !CACHE_DMA_IS_READ_COHERENT  ()
  1585.                )
  1586.                 {
  1587.                 SM_LOG (SM_DBG_MEM_INIT,
  1588.                         "MASTER: cache coherent buffer not availablen",
  1589.                         0, 0, 0, 0, 0, 0);
  1590.                 smEndUnload (pSmEndDev);
  1591.                 return (ERROR);
  1592.                 }
  1593.             if ((pSmEndDev->pMem =
  1594.                 (char *)cacheDmaMalloc (pSmEndDev->memSize))
  1595.                 == NULL)
  1596.                 {
  1597.                 SM_LOG (SM_DBG_MEM_INIT,
  1598.                         "MASTER: cache coherent 'sm' allocation errorn",
  1599.                         0, 0, 0, 0, 0, 0);
  1600.                 smEndUnload (pSmEndDev);
  1601.                 return (ERROR);
  1602.                 }
  1603.             pSmEndDev->smAlloc = TRUE;
  1604.             }
  1605.         /* else, if shared memory is contiguous with anchor, update info */
  1606.         else if (pSmEndDev->pMem == (char *) pSmEndDev->pAnchor)
  1607.             {
  1608.             pSmEndDev->pMem    += sizeof (SM_ANCHOR);
  1609.             pSmEndDev->memSize -= sizeof (SM_ANCHOR);
  1610.             }
  1611.         SM_LOG (SM_DBG_MEM_INIT,
  1612.                 "MASTER: anchor = 0x%X, memory @ 0x%X, size = %ldn",
  1613.                 (unsigned)pSmEndDev->pAnchor, (unsigned)pSmEndDev->pMem,
  1614.                 pSmEndDev->memSize, 0, 0, 0);
  1615.         /* set up shared memory region */
  1616.         SM_LOG (SM_DBG_MEM_INIT, "MASTER: shared memory setupn",
  1617.                 0, 0, 0, 0, 0, 0);
  1618.         smPktSize = pSmEndDev->maxPktBytes +
  1619.                     SM_PACKET_ROUNDUP(pSmEndDev->maxPktBytes);
  1620.         SM_LOG (SM_DBG_MEM_INIT, "MASTER: sm packet size = 0x%08.8Xn",
  1621.                 smPktSize, 0, 0, 0, 0, 0);
  1622.         if ((smPktSetup (pSmEndDev->pAnchor, pSmEndDev->pMem,
  1623.                          pSmEndDev->memSize, pSmEndDev->tasType,
  1624.                          pSmEndDev->maxCpus, smPktSize) == OK) &&
  1625.             ((smEndBeatWd = wdCreate ()) != NULL))
  1626.             {
  1627.             pSmPktHdr = SM_OFFSET_TO_LOCAL (ntohl (pSmEndDev->pAnchor->
  1628.                                                    smPktHeader),
  1629.                                                    (int)pSmEndDev->pAnchor,
  1630.                                                    SM_PKT_MEM_HDR *);
  1631.             pSmPktHdr->reserved1  = htonl ((unsigned)pSmEndDev->startAddr);
  1632.             pSmPktHdr->reserved2  = htonl ((unsigned)smEndBeatWd);
  1633.             pSmEndDev->pSmPktHdr  = pSmPktHdr;
  1634.             pSmEndDev->maxPackets = ntohl (pSmPktHdr->freeList.limit);
  1635.             SM_LOG (SM_DBG_MEM_INIT,
  1636.                     "MASTER: pSmPktHdr = %#x; rsvd1 = %#x; rsvd2 = %#xn",
  1637.                     (unsigned)pSmPktHdr, ntohl (pSmPktHdr->reserved1),
  1638.                     ntohl (pSmPktHdr->reserved2), 0, 0, 0);
  1639.             /* start heartbeat */
  1640.             SM_LOG (SM_DBG_MEM_INIT, "MASTER: starting heartbeatn",
  1641.                     0, 0, 0, 0, 0, 0);
  1642.             smEndPulse (pSmPktHdr);
  1643.             }
  1644.         else
  1645.             {
  1646.             smEndUnload (pSmEndDev);
  1647.             return (ERROR);
  1648.             }
  1649.         }
  1650.     /* allocate and set up END netPool using netBufLib() */
  1651.     
  1652.     if ((pSmEndDev->end.pNetPool = (NET_POOL_ID)calloc (1, sizeof(NET_POOL)))
  1653.                                  == NULL)
  1654.         {
  1655.         SM_LOG (SM_DBG_MEM_INIT, "smEndMemInit: net pool allocation errorn",
  1656.                 0, 0, 0, 0, 0, 0);
  1657.         smEndUnload (pSmEndDev);
  1658.         return (ERROR);
  1659.         }
  1660.     smEndMclBlkConfig.mBlkNum  = pSmEndDev->mbNum;
  1661.     smEndMclBlkConfig.clBlkNum = pSmEndDev->cbNum;
  1662.     smEndClDescTbl[0].clNum    = pSmEndDev->cbNum;
  1663.     /* Calculate the total memory for all the M-Blks and CL-Blks. */
  1664.     smEndMclBlkConfig.memSize = (smEndMclBlkConfig.mBlkNum *
  1665.                                  (M_BLK_SZ + M_BLK_OVERHEAD)) +
  1666.                                  (smEndMclBlkConfig.clBlkNum * 
  1667.                                  (CL_BLK_SZ + CL_BLK_OVERHEAD));
  1668.     /* allocate aligned memory for m/clBlks */
  1669.     pSmEndDev->pMclBlkCfg = memalign (SM_ALIGN_BOUNDARY,
  1670.                                       smEndMclBlkConfig.memSize);
  1671.     
  1672.     SM_LOG (SM_DBG_MEM_INIT, "smEndMemInit: mBlk/clBlk mem size = 0x%08.8X=n",
  1673.             (UINT)smEndMclBlkConfig.memSize, 0, 0, 0, 0, 0);
  1674.     SM_LOG (SM_DBG_MEM_INIT, "  0x%08.8X mBlks, each 0x%08.8X bytesn",
  1675.             (UINT)smEndMclBlkConfig.mBlkNum, (M_BLK_SZ + M_BLK_OVERHEAD),
  1676.             0, 0, 0, 0);
  1677.     SM_LOG (SM_DBG_MEM_INIT, "  0x%08.8X clBlks, each 0x%08.8X bytesn",
  1678.             (UINT)smEndMclBlkConfig.clBlkNum, (CL_BLK_SZ + CL_BLK_OVERHEAD),
  1679.             0, 0, 0, 0);
  1680.     SM_LOG (SM_DBG_MEM_INIT, "smEndMemInit: mBlk/clBlk mem area = 0x%08.8Xn",
  1681.             (UINT)pSmEndDev->pMclBlkCfg, 0, 0, 0, 0, 0);
  1682.     if ((smEndMclBlkConfig.memArea = (char *)pSmEndDev->pMclBlkCfg) == NULL)
  1683.         {
  1684.         SM_LOG (SM_DBG_MEM_INIT, "smEndMemInit: mBlk/clBlk allocation errorn",
  1685.                 0, 0, 0, 0, 0, 0);
  1686.         smEndUnload (pSmEndDev);
  1687.         return (ERROR);
  1688.         }
  1689.     
  1690.     /* Calculate the memory size of all the clusters. */
  1691.     smEndClDescTbl[0].clSize  = SM_END_CLST_SIZ;
  1692.     smEndClDescTbl[0].memSize = smEndClDescTbl[0].clNum *
  1693.                                 (SM_END_CLST_SIZ + CL_OVERHEAD);
  1694.     /* allocate the memory for the clusters from cache safe memory. */
  1695.     pSmEndDev->pClustMem = cacheDmaMalloc (smEndClDescTbl[0].memSize);
  1696.     SM_LOG (SM_DBG_MEM_INIT, "smEndMemInit: cluster mem size = 0x%08.8X =n",
  1697.             (UINT)smEndClDescTbl[0].memSize, 0, 0, 0, 0, 0);
  1698.     SM_LOG (SM_DBG_MEM_INIT, "  0x%08.8X clusters, each 0x%08.8X bytesn",
  1699.             (UINT)smEndClDescTbl[0].clNum, (UINT)SM_END_CLST_SIZ, 0, 0, 0, 0);
  1700.     SM_LOG (SM_DBG_MEM_INIT, "smEndMemInit: cluster mem area = 0x%08.8Xn",
  1701.             (UINT)pSmEndDev->pClustMem, 0, 0, 0, 0, 0);
  1702.     if ((smEndClDescTbl[0].memArea = (char *)pSmEndDev->pClustMem) == NULL)
  1703.         {
  1704.         SM_LOG (SM_DBG_MEM_INIT, "smEndMemInit: insufficient system memoryn",
  1705.                 0, 0, 0, 0, 0, 0);
  1706.         smEndUnload (pSmEndDev);
  1707.         return (ERROR);
  1708.         }
  1709.     /* Initialize the memory pool. */
  1710.     if (netPoolInit (pSmEndDev->end.pNetPool, &smEndMclBlkConfig,
  1711.                      &smEndClDescTbl[0], smEndClDescTblNumEnt, NULL) == ERROR)
  1712.         {
  1713.         SM_LOG (SM_DBG_MEM_INIT, "smEndMemInit: Can't init net pool: 0x%xn",
  1714.                 errno, 0, 0, 0, 0, 0);
  1715.         smEndUnload (pSmEndDev);
  1716.         return (ERROR);
  1717.         }
  1718.     /* Get our pool ID for future reference */
  1719.     if ((pSmEndDev->clPoolId = netClPoolIdGet (pSmEndDev->end.pNetPool,
  1720.                                                SM_END_CLST_SIZ, FALSE)) ==NULL)
  1721.         {
  1722.         SM_LOG (SM_DBG_MEM_INIT, "smEndMemInit: Can't get cluster pool IDn",
  1723.                 0, 0, 0, 0, 0, 0);
  1724.         smEndUnload (pSmEndDev);
  1725.         return (ERROR);
  1726.         }
  1727.     /*
  1728.      * Prime the tuple pump
  1729.      * Try to always have one pre-allocated tuple available for fast receiving.
  1730.      */
  1731.     if ((pSmEndDev->tupleId = netTupleGet (pSmEndDev->end.pNetPool,
  1732.                                           SM_END_CLST_SIZ, M_DONTWAIT,
  1733.                                           MT_DATA, FALSE))
  1734.                            == NULL)
  1735.         {
  1736.         SM_LOG (SM_DBG_MEM_INIT, "smEndMemInit: Tuple get failed: 0x%xn",
  1737.                 errno, 0, 0, 0, 0, 0);
  1738.         smEndUnload (pSmEndDev);
  1739.         return (ERROR);
  1740.         }
  1741.     SM_LOG (SM_DBG_MEM_INIT, "Memory setup completen", 0, 0, 0, 0, 0, 0);
  1742.     return (OK);
  1743.     }
  1744. /******************************************************************************
  1745. *
  1746. * smEndIsr - shared memory interrupt service routine
  1747. *
  1748. * This routine is the interrupt service routine for shared memory input
  1749. * packets.  It processes the interrupt (if appropriate) then notifies the
  1750. * MUX of the incomming packet by calling the MUX receive routine.  It is
  1751. * enabled/disabled by setting/clearing the S_RUNNING flag bit.
  1752. *
  1753. * RETURNS: N/A
  1754. */
  1755. LOCAL void smEndIsr
  1756.     (
  1757.     SM_END_DEV * pSmEndDev
  1758.     )
  1759.     {
  1760.     if (pSmEndDev != NULL)
  1761.         {
  1762.         if (SM_END_INTR_RDY)
  1763.             {
  1764.             SM_RCV_TASK_ACTIVE;
  1765.             netJobAdd ((FUNCPTR)smEndSrvcRcvInt, (int)pSmEndDev, 0, 0, 0, 0);
  1766.             }
  1767.         /* if bus interrupt, acknowledge it */
  1768.         if (pSmEndDev->intType == SM_INT_BUS)
  1769.             sysBusIntAck (pSmEndDev->intArg1);
  1770.         }
  1771. #ifdef SM_DBG
  1772.     if ((smEndDebug & SM_DBG_INT) != 0)
  1773.         ++smEndRxInts;
  1774. #endif
  1775.     }
  1776. /******************************************************************************
  1777. *
  1778. * smEndPulse - continually pulse the shared memory heartbeat
  1779. *
  1780. * This routine maintains the shared memory heart beat by incrementing 
  1781. * the heartbeat count and then re-scheduling itself to run again 
  1782. * after a "beat" has passed.
  1783. *
  1784. * RETURNS: N/A
  1785. */
  1786. LOCAL void smEndPulse
  1787.     (
  1788.     SM_PKT_MEM_HDR * pSmPktHdr /* pointer to heartbeat */
  1789.     )
  1790.     {
  1791.     smPktBeat (pSmPktHdr);
  1792.     (void) wdStart ((WDOG_ID)ntohl (pSmPktHdr->reserved2),
  1793.                    (int)sysClkRateGet (), (FUNCPTR)smEndPulse, (int)pSmPktHdr);
  1794.     }
  1795. /******************************************************************************
  1796. *
  1797. * smEndTupleGet - get a netBuf tuple
  1798. *
  1799. * This routine gets a netBuf tuple and returns its ID or NULL if error.
  1800. *
  1801. * RETURNS: ID of tuple or NULL if error.
  1802. */
  1803. LOCAL M_BLK_ID smEndTupleGet
  1804.     (
  1805.     SM_END_DEV * pSmEndDev
  1806.     )
  1807.     {
  1808.     M_BLK_ID  pMblk = NULL;
  1809. #ifndef TUPLE
  1810.     char *    pNewCluster;
  1811.     CL_BLK_ID pClBlk;
  1812. #endif /* TUPLE */
  1813.     /*
  1814.      * We are implicitly loaning tuples to the MUX here.
  1815.      * If fast tuple is available, use it, else, create another.
  1816.      */
  1817.     if (pSmEndDev->tupleId != NULL)
  1818.         {
  1819.         pMblk = pSmEndDev->tupleId;
  1820.         pSmEndDev->tupleId = NULL;
  1821.         }
  1822. #ifdef TUPLE
  1823.     else if ((pMblk = netTupleGet (pSmEndDev->end.pNetPool, SM_END_CLST_SIZ,
  1824.                                    M_DONTWAIT, MT_DATA, FALSE))
  1825.                     == NULL)
  1826.         {
  1827.         SM_LOG (SM_DBG_RX, "smEndTupleGet: Tuple get failedn",
  1828.                 0, 0, 0, 0, 0, 0);
  1829.         }
  1830. #else
  1831.     else
  1832.         {
  1833.         pNewCluster = netClusterGet (pSmEndDev->end.pNetPool,
  1834.                                      pSmEndDev->clPoolId);
  1835.         if (pNewCluster == NULL)
  1836.             {
  1837.             SM_LOG (SM_DBG_RX, "smEndRecv: no free clustersn",
  1838.                     0, 0, 0, 0, 0, 0);
  1839.             END_ERR_ADD (&pSmEndDev->end, MIB2_IN_ERRS, +1);
  1840.             }
  1841.         /* Grab a cluster block to marry to the cluster we received. */
  1842.         else if ((pClBlk = netClBlkGet (pSmEndDev->end.pNetPool, M_DONTWAIT))
  1843.                          == NULL)
  1844.             {
  1845.             netClFree (pSmEndDev->end.pNetPool, pNewCluster);
  1846.             SM_LOG (SM_DBG_RX, "smEndRecv: no free clBlksn",
  1847.                     0, 0, 0, 0, 0, 0);
  1848.             END_ERR_ADD (&pSmEndDev->end, MIB2_IN_ERRS, +1);
  1849.             }
  1850.     
  1851.         /*
  1852.          * OK we've got a spare, let's get an M_BLK_ID and marry it to the
  1853.          * one in the ring.
  1854.          */
  1855.         else if ((pMblk = mBlkGet (pSmEndDev->end.pNetPool, M_DONTWAIT,
  1856.                                    MT_DATA))
  1857.                         == NULL)
  1858.             {
  1859.             netClBlkFree (pSmEndDev->end.pNetPool, pClBlk); 
  1860.             netClFree (pSmEndDev->end.pNetPool, pNewCluster);
  1861.             SM_LOG (SM_DBG_RX, "smEndRecv: no free mBlksn", 0, 0, 0, 0, 0, 0);
  1862.             END_ERR_ADD (&pSmEndDev->end, MIB2_IN_ERRS, +1);
  1863.             }
  1864.         else
  1865.             {
  1866.             /* Join the cluster to the MBlock */
  1867.             netClBlkJoin (pClBlk, pNewCluster, SM_END_CLST_SIZ, NULL, 0, 0, 0);
  1868.             netMblkClJoin (pMblk, pClBlk);
  1869.             }
  1870.         }
  1871. #endif /* TUPLE */
  1872.     return (pMblk);
  1873.     }
  1874. /******************************************************************************
  1875. *
  1876. * smEndRecv - process the next incoming packet
  1877. *
  1878. * Handle one incoming packet.  The packet is checked for errors.
  1879. *
  1880. * RETURNS: OK or ERROR.
  1881. */
  1882. LOCAL STATUS smEndRecv
  1883.     (
  1884.     SM_END_DEV * pSmEndDev, /* device structure */
  1885.     SM_PKT *     pPkt, /* packet to process */
  1886.     M_BLK_ID     pMblk /* mBlk to hold packet data */
  1887.     )
  1888.     {
  1889.     int                   len;
  1890.     struct ether_header * pEh    = (struct ether_header *)pPkt->data;
  1891.     u_char *              pData; /* packet data to process */
  1892.     /* Packet must be checked for errors. */
  1893.     if ((len = SM_END_PKT_LEN_GET (pPkt)) < SIZEOF_ETHERHEADER)
  1894.         {
  1895.         SM_LOG (SM_DBG_RX, "smEndRecv: invalid packet len %dn", len,
  1896.                 0, 0, 0, 0, 0);
  1897.         END_ERR_ADD (&pSmEndDev->end, MIB2_IN_ERRS, +1);
  1898.         return (ERROR); /* invalid packet size */
  1899.         }
  1900.     /* debugging aid */
  1901.     SM_LOG (SM_DBG_RX, "smEndRecv: [0x%x] len: %d src:%s ",
  1902.             ntohs (pEh->ether_type), len,
  1903.             (int)ether_sprintf (etherAddrPtr (pEh->ether_shost)), 0, 0, 0);
  1904.     SM_LOG (SM_DBG_RX, "dst:%sn",
  1905.             (int)ether_sprintf (etherAddrPtr (pEh->ether_dhost)),
  1906.             0, 0, 0, 0, 0);
  1907.     /* adjust for enet header */
  1908.     len -= SIZEOF_ETHERHEADER;
  1909.     pData = (u_char *)(pEh + SIZEOF_ETHERHEADER);
  1910.     /* if packet with no data, just return */
  1911.     if (len != 0)
  1912.         {
  1913.         /* copy packet from sm to cluster */
  1914.         SM_END_COPY_TO_CLUSTER (pMblk, pData, len);
  1915.         /* Add one to our unicast data. */
  1916.         END_ERR_ADD (&pSmEndDev->end, MIB2_IN_UCAST, +1);
  1917.         /* set up mBlk */
  1918.         pMblk->mBlkHdr.mData   = pData;
  1919.         pMblk->mBlkHdr.mLen    = len;
  1920.         pMblk->mBlkHdr.mFlags |= M_PKTHDR;
  1921.         pMblk->mBlkPktHdr.len  = len;
  1922.         /* Call the upper layer's receive routine. */
  1923.         SM_LOG (SM_DBG_RX, "smEndRecv: calling MUXn", 0, 0, 0, 0, 0, 0);
  1924.         END_RCV_RTN_CALL (&pSmEndDev->end, pMblk);
  1925.         }
  1926.     return (OK);
  1927.     }
  1928. /******************************************************************************
  1929. *
  1930. * smEndSrvcRcvInt - task level interrupt service for receiving sm packets
  1931. *
  1932. * This routine is called at task level indirectly by the interrupt service
  1933. * routine to do any sm receive packet processing.
  1934. *
  1935. * The double loop is to protect against a race condition where the interrupt
  1936. * code see rxHandling as TRUE, but it is then turned off by task code.
  1937. * This race is not fatal, but does cause occassional delays until a second
  1938. * packet is received and then triggers the netTask to call this routine again.
  1939. *
  1940. * RETURNS: N/A.
  1941. */
  1942. LOCAL void smEndSrvcRcvInt
  1943.     (
  1944.     SM_END_DEV * pSmEndDev /* interrupting device */
  1945.     )
  1946.     {
  1947.     FAST STATUS status;
  1948.     SM_PKT *    pPkt; /* shared memory packet */
  1949.     M_BLK_ID    pMblk;
  1950.     int         cpuNum = pSmEndDev->localCpu;
  1951.     while ((pSmEndDev->smPktDesc.status == SM_CPU_ATTACHED) &&
  1952.            (smEndInputCount (pSmEndDev, cpuNum) > 0))
  1953.         {
  1954.         /*
  1955.          * If there is at least one more free tuple, get it and proceed.
  1956.          * If not, do not perform smPktRecv() because the sm packet would be
  1957.          * lost - there is no way to return a received sm packet to its list.
  1958.          */
  1959.         if (pSmEndDev->tupleId == NULL)
  1960.             {
  1961.          if ((pSmEndDev->tupleId = smEndTupleGet (pSmEndDev)) == NULL)
  1962.              {
  1963.                 END_ERR_ADD (&pSmEndDev->end, MIB2_IN_ERRS, +1);
  1964.                 SM_LOG (SM_DBG_INT, "smEndSrvcRcvInt: no free tuplesn",
  1965.                         0, 0, 0, 0, 0, 0);
  1966.              break;
  1967.              }
  1968.             }
  1969.      if (((status = smPktRecv (&pSmEndDev->smPktDesc, &pPkt)) == OK) &&
  1970.          (pPkt != NULL))
  1971.          {
  1972.          pMblk = pSmEndDev->tupleId;
  1973.          pSmEndDev->tupleId = NULL;
  1974.             smEndRecv (pSmEndDev, pPkt, pMblk);
  1975.          }
  1976. else if (status == ERROR)
  1977.     {
  1978.             END_ERR_ADD (&pSmEndDev->end, MIB2_IN_ERRS, +1);
  1979.             SM_LOG (SM_DBG_INT, "smEndSrvcRcvInt: packet receive errorn",
  1980.                     0, 0, 0, 0, 0, 0);
  1981.     }
  1982. else
  1983.     break; /* no more sm packets to receive */
  1984.         }
  1985.     SM_RCV_TASK_INACTIVE;
  1986.     }
  1987. /******************************************************************************
  1988. *
  1989. * smEndTupleChainWalk - walk and gather information on a tuple chain
  1990. *
  1991. * This routine walks the tuple chain headed by <pMblk>, computes
  1992. * the number of fragments it is made of and the maximum data size of all
  1993. * fragments, and returns this information to the parameters referenced by
  1994. * <pFragNum> and <pMaxSize>.  In addition, it finds out whether the specified
  1995. * chain is unicast or multicast, and sets <pPktType> accordingly.
  1996. *
  1997. * RETURNS: OK, or ERROR in case of invalid mBlk (XXXmas: or multicast).
  1998. */
  1999. LOCAL STATUS smEndTupleChainWalk
  2000.     (
  2001.     M_BLK *  pMblk, /* pointer to the mBlk */
  2002.     UINT  *  pFragNum, /* number of fragments */
  2003.     UINT16 * pPktType, /* packet type */
  2004.     UINT *   pMaxSize /* size of largest fragment */
  2005.     )
  2006.     {
  2007.     M_BLK *  pCurr = pMblk; /* the current mBlk */
  2008.     if (pMblk == NULL)
  2009.         {
  2010.         SM_LOG (SM_DBG_TX, "smEndTupleChainWalk: invalid pMblkn",
  2011.                 0, 0, 0, 0, 0, 0);
  2012.         return (ERROR);
  2013.         }
  2014.     SM_LOG (SM_DBG_TX,
  2015.             "smEndTupleChainWalk: pMblk = %#x; pMblk->mBlkHdr.mNext = %#xn",
  2016.             (unsigned)pMblk, (unsigned)pMblk->mBlkHdr.mNext, 0, 0, 0, 0);
  2017.     SM_LOG (SM_DBG_TX,
  2018.             "    pMblk data ptr = %#x; pMblk data len = %#xn",
  2019.             (unsigned)pMblk->mBlkHdr.mData, (unsigned)pMblk->mBlkHdr.mLen,
  2020.             0, 0, 0, 0);
  2021. #ifdef SM_DBG
  2022.     {
  2023.     char temp[512] = {0,0,0,0,0,0,0,0};
  2024.     char temp2 [8];
  2025.     int  i;
  2026.     for (i = 0; (i < 255) && (i < pMblk->mBlkHdr.mLen); ++i)
  2027.         {
  2028.         sprintf (temp2, "%2.2x", (unsigned)pMblk->mBlkHdr.mData[i]);
  2029.         strcat (temp, temp2);
  2030.         }
  2031.     SM_LOG (SM_DBG_TX, "    pMblk data = %sn", (unsigned)temp, 0, 0, 0, 0, 0);
  2032.     taskDelay (60);
  2033.     }
  2034. #endif /* SM_DBG */
  2035.     /* walk this mBlk */
  2036.     *pMaxSize = 0;
  2037.     *pFragNum = 0;
  2038.     while (pCurr != NULL)
  2039. {
  2040. /* keep track of the number of fragments in this mBlk */
  2041.         *pFragNum += 1;
  2042. /* record largest fragment size */
  2043. if (pCurr->mBlkHdr.mLen > *pMaxSize)
  2044.     *pMaxSize = pCurr->mBlkHdr.mLen;
  2045. pCurr = ((M_BLK *) pCurr->mBlkHdr.mNext);
  2046. }
  2047.     /* set the packet type to multicast or unicast */
  2048.     if (pMblk->mBlkHdr.mData[0] & (UINT8) 0x01)
  2049. {
  2050. /* XXXmas  Multicast is a future enhancement; ignore for now */
  2051. (*pPktType) = PKT_TYPE_MULTI;
  2052.         SM_LOG (SM_DBG_TX, "smEndTupleChainWalk: multicast request ignoredn",
  2053.                 0, 0, 0, 0, 0, 0);
  2054. }
  2055.     else
  2056. {
  2057. (*pPktType) = PKT_TYPE_UNI;
  2058. }
  2059.     return (OK);
  2060.     }
  2061. /*******************************************************************************
  2062. *
  2063. * smEndSend - sm END send routine
  2064. *
  2065. * This routine accepts an M_BLK_ID and sends the data in it to the appropriate
  2066. * shared memory area.
  2067. *
  2068. * The buffer must already have the addressing information properly installed
  2069. * in it.  This is done by a higher layer.
  2070. *
  2071. * The last arguments are a free routine to be called when the device is done
  2072. * with the buffer and a pointer to the argument to pass to the free routine.
  2073. *
  2074. * RETURNS: OK or END_ERROR_BLOCK if we are in polled mode or insufficient
  2075. * sm buffer resources are available.
  2076. */
  2077. LOCAL STATUS smEndSend
  2078.     (
  2079.     void *    pObj, /* device ptr */
  2080.     M_BLK_ID  mBlkId /* ID of mBlk (data) to send */
  2081.     )
  2082.     {
  2083.     SM_END_DEV *          pSmEndDev = (SM_END_DEV *)pObj; /* device ptr */
  2084.     M_BLK *               pMblk     = mBlkId;
  2085.     UINT                  fragNum; /* number of fragments */
  2086.     UINT16                pktType; /* packet type */
  2087.     UINT                  fragSizeMax; /* max frag size (bytes) */
  2088.     unsigned   destCPU; /* destination cpu */
  2089.     struct ether_header * pEh      = NULL; /* enet header */
  2090.     u_char *              pEaddr; /* enet address ptr */
  2091.     unsigned   ipAddr;
  2092.     SM_PKT *              pPkt     = NULL; /* packet pointer */
  2093.     SM_PKT_INFO           smInfo; /* sm info */
  2094.     
  2095.     SM_LOG (SM_DBG_TX, "smEndSend...n", 0, 0, 0, 0, 0, 0);
  2096.     /*
  2097.      * Obtain exclusive access to shared memory.  This is necessary because
  2098.      * we might have more than one stack transmitting at once.
  2099.      */
  2100.     if (!(pSmEndDev->flags & SM_END_POLL_SM_RDY))
  2101.         {
  2102. END_TX_SEM_TAKE (&pSmEndDev->end, WAIT_FOREVER);
  2103.         }
  2104.     else
  2105.         {
  2106.         /* if operating mode is polling, return error */
  2107.         SM_LOG (SM_DBG_TX, "smEndSend: polled mode enabled!n",
  2108.                 0, 0, 0, 0, 0, 0);
  2109.         END_ERR_ADD (&pSmEndDev->end, MIB2_OUT_ERRS, +1);
  2110.         return (END_ERR_BLOCK);
  2111.         }
  2112.     /* walk the mBlk tuple chain */
  2113.     if (smEndTupleChainWalk (mBlkId, &fragNum, &pktType, &fragSizeMax) ==ERROR)
  2114.         {
  2115.         SM_LOG (SM_DBG_TX, "smEndSend: invalid mBlkn",
  2116.                 0, 0, 0, 0, 0, 0);
  2117.         END_ERR_ADD (&pSmEndDev->end, MIB2_OUT_ERRS, +1);
  2118.         END_TX_SEM_GIVE (&pSmEndDev->end);
  2119.         errno = EINVAL;
  2120.         return (END_ERR_BLOCK);
  2121.         }
  2122.     SM_LOG (SM_DBG_TX, "smEndSend: walked %d tuplesn", fragNum,
  2123.             0, 0, 0, 0, 0);
  2124.     /* ensure sufficient sm packet resources for all data */
  2125.     if (smPktInfoGet (&pSmEndDev->smPktDesc, &smInfo) == ERROR)
  2126.         {
  2127.         SM_LOG (SM_DBG_TX, "smEndSend: cpu not attached!n",
  2128.                 0, 0, 0, 0, 0, 0);
  2129.         END_ERR_ADD (&pSmEndDev->end, MIB2_OUT_ERRS, +1);
  2130.         END_TX_SEM_GIVE (&pSmEndDev->end);
  2131.         return (END_ERR_BLOCK);
  2132.         }
  2133.     SM_LOG (SM_DBG_TX, "smEndSend: #free pkts = %dn", smInfo.freePkts,
  2134.             0, 0, 0, 0, 0);
  2135.     if ((fragNum     > smInfo.freePkts) ||
  2136.         (fragSizeMax > pSmEndDev->smPktDesc.maxPktBytes))
  2137.         {
  2138.         SM_LOG (SM_DBG_TX, "smEndSend: sm resource shortage: FRAG    PKTn",
  2139.                 0, 0, 0, 0, 0, 0);
  2140.         SM_LOG (SM_DBG_TX, "                        Number:  %u    %dn",
  2141.                 fragNum, smInfo.freePkts, 0, 0, 0, 0);
  2142.         SM_LOG (SM_DBG_TX, "                          Size:  %u    %dn",
  2143.                 fragSizeMax, pSmEndDev->smPktDesc.maxPktBytes, 0, 0, 0, 0);
  2144.         END_ERR_ADD (&pSmEndDev->end, MIB2_OUT_ERRS, +1);
  2145.         END_TX_SEM_GIVE (&pSmEndDev->end);
  2146.         errno = ENOSPC;
  2147.         return (END_ERR_BLOCK);
  2148.         }
  2149.     /* initiate sm packet transfer */
  2150.     for ( ; (fragNum > 0) && (pMblk != NULL);
  2151.          --fragNum, pMblk = (M_BLK *)pMblk->mBlkHdr.mNext)
  2152.         {
  2153.      if ((smPktFreeGet (&pSmEndDev->smPktDesc, &pPkt) == ERROR) ||
  2154.          (pPkt == NULL))
  2155.             {
  2156.             SM_LOG (SM_DBG_TX, "smEndSend: smPktFreeGet error 0x%xn",
  2157.                     errno, 0, 0, 0, 0, 0);
  2158.             END_ERR_ADD (&pSmEndDev->end, MIB2_OUT_ERRS, +1);
  2159.             continue;
  2160.             }
  2161.      /* point to ether address in local cluster data */
  2162.      pEh = (struct ether_header *)pMblk->mBlkHdr.mData;
  2163.         /* check for broadcast message */
  2164.      if (bcmp ((caddr_t) etherAddrPtr (pEh->ether_dhost),
  2165.   (caddr_t) etherAddrPtr (etherbroadcastaddr) ,
  2166.   sizeof (pEh->ether_dhost)) == 0)
  2167.             {
  2168.          destCPU  = SM_BROADCAST;  /* specify broadcast */
  2169.             SM_LOG (SM_DBG_TX, "smEndSend: broadcast messagen",
  2170.                     0, 0, 0, 0, 0, 0);
  2171.             }
  2172.      else
  2173.          {
  2174.     pEaddr = etherAddrPtr (pEh->ether_dhost);
  2175.             /* sequential addressing */
  2176.             if (pSmEndDev->masterAddr != 0)
  2177. {
  2178. ipAddr = (pEaddr [3] << 16) | (pEaddr [4] << 8) | pEaddr [5];
  2179. destCPU = ipAddr - pSmEndDev->masterAddr;  /* & 0x00FFFFFF ? */
  2180.                 SM_LOG (SM_DBG_TX,
  2181.                         "smEndSend: seq adrs %#x - mstr %#x -> cpu #%un",
  2182.                         ipAddr, pSmEndDev->masterAddr, destCPU, 0, 0, 0);
  2183. }
  2184.     else
  2185.         {
  2186. destCPU = pEaddr [5];
  2187.                 SM_LOG (SM_DBG_TX, "smEndSend: non-seq adrs -> cpu #%un",
  2188.                         destCPU, 0, 0, 0, 0, 0);
  2189.         }
  2190.          /* sending to ourself */
  2191.             SM_LOG (SM_DBG_TX, "smEndSend: dest CPU = %un",
  2192.                     destCPU, 0, 0, 0, 0, 0);
  2193.          if (destCPU == pSmEndDev->localCpu)
  2194.      {
  2195.                 /*
  2196.                  * Call the upper layer's receive routine and
  2197.                  * return unused packet.
  2198.                  */
  2199.                 SM_LOG (SM_DBG_TX, "smEndSend: sent to ourselvesn",
  2200.                         0, 0, 0, 0, 0, 0);
  2201.                 END_RCV_RTN_CALL (&pSmEndDev->end, pMblk);
  2202.                 END_ERR_ADD (&pSmEndDev->end, MIB2_OUT_UCAST, +1);
  2203.                 smPktFreePut (&pSmEndDev->smPktDesc, pPkt);
  2204. continue;
  2205.      }
  2206.          }
  2207.      /* copy data to pkt */
  2208.      pEh = (struct ether_header *)pPkt->data;
  2209.         SM_END_COPY_FROM_CLUSTER (pMblk, (char *)pEh, pMblk->mBlkHdr.mLen);
  2210.      pPkt->header.nBytes = pMblk->mBlkHdr.mLen;
  2211.         /* diagnostics */
  2212.         SM_LOG (SM_DBG_TX, "smEndSend: [0x%x] len:%d src:%sn",
  2213.                 pEh->ether_type, pMblk->mBlkHdr.mLen,
  2214.                 (int)ether_sprintf (etherAddrPtr (pEh->ether_shost)), 0, 0, 0);
  2215.         SM_LOG (SM_DBG_TX, "dst:%s cpu [%#x]n",
  2216.                 (int)ether_sprintf (etherAddrPtr (pEh->ether_dhost)), destCPU,
  2217.                 0, 0, 0, 0);
  2218.         /* now send (announce) packet to destination cpu */
  2219.      if (smPktSend (&pSmEndDev->smPktDesc, pPkt, destCPU) == ERROR)
  2220.          {
  2221.             SM_LOG (SM_DBG_TX, "smEndSend: smPktSend error: 0x%xn",
  2222.                     errno, 0, 0, 0, 0, 0);
  2223.             END_ERR_ADD (&pSmEndDev->end, MIB2_OUT_ERRS, +1);
  2224.     /*
  2225.      * need to return shared memory packet on error,
  2226.      * unless it's an incomplete broadcast error.
  2227.      */
  2228.          if (errno != S_smPktLib_INCOMPLETE_BROADCAST)
  2229.      (void)smPktFreePut (&pSmEndDev->smPktDesc, pPkt);
  2230.          }
  2231.         /* Bump the statistic counter. */
  2232.      else
  2233.             END_ERR_ADD (&pSmEndDev->end, MIB2_OUT_UCAST, +1);
  2234.         }
  2235.     /* relinquish ownership of shared memory */
  2236.     END_TX_SEM_GIVE (&pSmEndDev->end);
  2237.     
  2238.     /* Cleanup.  The driver must free the mBlk(s) now. */
  2239.     netMblkClChainFree (mBlkId);
  2240.     return (OK);
  2241.     }
  2242. /******************************************************************************
  2243. *
  2244. * smEndPollQPut - enqueue a polled mode tuple
  2245. *
  2246. * This routine queues a tuple sent in polled mode to the local cpu so that
  2247. * it may later be returned to an upper layer via a polled receive call.
  2248. *
  2249. * RETURNS: N/A
  2250. *
  2251. * SEE ALSO: smEndPollQGet() and smEndPollQFree()
  2252. */
  2253. LOCAL void smEndPollQPut
  2254.     (
  2255.     SM_END_DEV * pSmEndDev, /* device containing queue */
  2256.     M_BLK_ID     mBlkId /* polled tuple to be queued */
  2257.     )
  2258.     {
  2259.     mBlkId->mBlkHdr.mNext = NULL;
  2260.     /* make first entry in queue */
  2261.     if (pSmEndDev->pollQ == NULL)
  2262.         {
  2263.         pSmEndDev->pollQ     = mBlkId;
  2264.         pSmEndDev->pollQLast = mBlkId;
  2265.         }
  2266.     /*
  2267.      * append to end of queue
  2268.      * mas Note: prioritization could be supported here in the future
  2269.      */
  2270.     else
  2271.         {
  2272.         pSmEndDev->pollQLast->mBlkHdr.mNext = mBlkId;
  2273.         pSmEndDev->pollQLast = mBlkId;
  2274.         }
  2275.     }
  2276. /******************************************************************************
  2277. *
  2278. * smEndPollQGet - get next queued tuple
  2279. *
  2280. * This routine gets the next queued tuple, if any, and copies its cluster to
  2281. * the cluster of the receiving tuple specified by <mBlkId>.
  2282. *
  2283. * RETURNS: OK upon success, NONE if no tuple is available, or EAGAIN if the
  2284. * receiving tuple cluster size is too small.
  2285. *
  2286. * SEE ALSO: smEndPollQPut() and smEndPollQFree()
  2287. */
  2288. LOCAL int smEndPollQGet
  2289.     (
  2290.     SM_END_DEV * pSmEndDev, /* device containing queue */
  2291.     M_BLK_ID     mBlkId /* tuple to receive queued tuple */
  2292.     )
  2293.     {
  2294.     M_BLK_ID pMblk = NULL;
  2295.     /* if no queued tuples, return NONE */
  2296.     if (pSmEndDev->pollQ == NULL)
  2297.         return (NONE);
  2298.     /*
  2299.      * if queued tuple has more data than receiving tuple can hold,
  2300.      * return EAGAIN
  2301.      */
  2302.     pMblk = pSmEndDev->pollQ;
  2303.     if (pMblk->mBlkHdr.mLen > mBlkId->pClBlk->clSize)
  2304.         return (EAGAIN);
  2305.     /* copy data from queued tuple to receiving tuple */
  2306.     bcopy (pMblk->mBlkHdr.mData, mBlkId->mBlkHdr.mData, pMblk->mBlkHdr.mLen);
  2307.     mBlkId->mBlkHdr.mLen   = pMblk->mBlkHdr.mLen;
  2308.     mBlkId->mBlkHdr.mFlags = pMblk->mBlkHdr.mFlags;
  2309.     mBlkId->mBlkPktHdr.len = pMblk->mBlkPktHdr.len;
  2310.     /* remove tuple from queue and free it */
  2311.     pSmEndDev->pollQ = pMblk->mBlkHdr.mNext;
  2312.     if (pSmEndDev->pollQ == NULL)
  2313.         pSmEndDev->pollQLast = NULL;
  2314.     netMblkClFree (pMblk);
  2315.     return (OK);
  2316.     }
  2317. /******************************************************************************
  2318. *
  2319. * smEndPollQFree - free all queued tuples in the specified device
  2320. *
  2321. * This routine frees all tuples, if any, queued in the specified device.
  2322. *
  2323. * RETURNS: N/A
  2324. *
  2325. * SEE ALSO: smEndPollQGet() and smEndPollQPut()
  2326. */
  2327. LOCAL void smEndPollQFree
  2328.     (
  2329.     SM_END_DEV * pSmEndDev /* device containing queue */
  2330.     )
  2331.     {
  2332.     M_BLK_ID pMblk    = NULL;
  2333.     M_BLK_ID pMblkNxt = NULL;
  2334.     pMblk = pSmEndDev->pollQ;
  2335.     while (pMblk != NULL)
  2336.         {
  2337.         pMblkNxt = pMblk->mBlkHdr.mNext;
  2338.         netMblkClFree (pMblk);
  2339.         pMblk = pMblkNxt;
  2340.         }
  2341.     pSmEndDev->pollQLast = pSmEndDev->pollQ = NULL;
  2342.     }
  2343. /******************************************************************************
  2344. *
  2345. * smEndPollRecv - routine to receive a packet in polled mode.
  2346. *
  2347. * This routine is called by a user to try and get a packet from the device.
  2348. *
  2349. * RETURNS: OK upon success.  EAGAIN is returned when no packet is available,
  2350. * the cpu is not attached to sm, or no free mBlks.  EINVAL is returned if
  2351. * either input argument is NULL.  EACCES is returned if device is not in
  2352. * polled mode.
  2353. */
  2354. LOCAL STATUS smEndPollRecv
  2355.     (
  2356.     VOID *    pObj, /* device to be polled */
  2357.     M_BLK_ID  pMblk /* ptr to buffer */
  2358.     )
  2359.     {
  2360.     SM_END_DEV * pSmEndDev = (SM_END_DEV *)pObj; /* device to be polled */
  2361.     int          cpuNum    = pSmEndDev->localCpu;
  2362.     SM_PKT *     pPkt      = NULL; /* shared memory packet */
  2363.     struct ether_header * pEh; /* ethernet header */
  2364.     u_char *     pData; /* packet data to process */
  2365.     int          qStatus;
  2366.     int          len;
  2367.     if ((pObj == NULL) || (pMblk == NULL))
  2368.         {
  2369.         END_ERR_ADD (&pSmEndDev->end, MIB2_IN_ERRS, +1);
  2370.         return (EINVAL);
  2371.         }
  2372.     /* cpu attached and in polled mode? */
  2373.     if (!SM_END_POLL_SM_RDY)
  2374.         {
  2375.         END_ERR_ADD (&pSmEndDev->end, MIB2_IN_ERRS, +1);
  2376.         return (EACCES);
  2377.         }
  2378.     /* return next queued tuple, if any */
  2379.     if ((qStatus = smEndPollQGet (pSmEndDev, pMblk)) != NONE)
  2380.         {
  2381.         if (qStatus == OK)
  2382.             {
  2383.             /* Add one to our unicast data. */
  2384.             END_ERR_ADD (&pSmEndDev->end, MIB2_IN_UCAST, +1);
  2385.             }
  2386.         return (qStatus);
  2387.         }
  2388.     /* any sm packets? */
  2389.     if (smEndInputCount (pSmEndDev, cpuNum) < 1)
  2390.         {
  2391.         END_ERR_ADD (&pSmEndDev->end, MIB2_IN_ERRS, +1);
  2392.         return (EAGAIN);
  2393.         }
  2394.     /* get packet address */
  2395.     if ((smPktRecv (&pSmEndDev->smPktDesc, &pPkt) != OK) ||
  2396.         (pPkt == NULL))
  2397.         {
  2398.         END_ERR_ADD (&pSmEndDev->end, MIB2_IN_ERRS, +1);
  2399.         return (EAGAIN);
  2400.         }
  2401.     /* Get packet length */
  2402.     if ((len = SM_END_PKT_LEN_GET (pPkt)) < SIZEOF_ETHERHEADER)
  2403.         {
  2404.         END_ERR_ADD (&pSmEndDev->end, MIB2_IN_ERRS, +1);
  2405.         return (EAGAIN); /* invalid packet size */
  2406.         }
  2407.     /* adjust for enet header */
  2408.     pEh = (struct ether_header *)pPkt->data; /* ethernet header */
  2409.     len -= SIZEOF_ETHERHEADER;
  2410.     pData = ((u_char *) pEh) + SIZEOF_ETHERHEADER;
  2411.     /* Upper layer must provide a valid buffer */
  2412.     if ((pMblk->mBlkHdr.mLen < len) || (!(pMblk->mBlkHdr.mFlags & M_EXT)))
  2413. {
  2414. return (EAGAIN);
  2415. }
  2416.     /* if packet with no data, just return */
  2417.     if (len == 0)
  2418.         {
  2419. return (EAGAIN);
  2420.         }
  2421.     /* set up mBlk */
  2422.     pMblk->mBlkHdr.mLen    = len;
  2423.     pMblk->mBlkHdr.mFlags |= M_PKTHDR;
  2424.     pMblk->mBlkPktHdr.len  = len;
  2425.     /* copy packet from sm to tuple cluster and return to MUX */
  2426.     SM_END_COPY_TO_CLUSTER (pMblk, pData, len);
  2427.     /* Add one to our unicast data. */
  2428.     END_ERR_ADD (&pSmEndDev->end, MIB2_IN_UCAST, +1);
  2429.     return (OK);
  2430.     }
  2431. /******************************************************************************
  2432. *
  2433. * smEndPollSend - routine to send a packet in polled mode.
  2434. *
  2435. * This routine is called by a user to try and send a packet on the device.
  2436. *
  2437. * RETURNS: OK upon success.  ERROR is returned and errno is set to:
  2438. * EINVAL - if either input argument is NULL.
  2439. * EACCES - if device is not in polled mode.
  2440. * EAGAIN is returned in all other cases.
  2441. */
  2442. LOCAL STATUS smEndPollSend
  2443.     (
  2444.     void *   pObj, /* device to be polled */
  2445.     M_BLK_ID pMblk /* packet to send */
  2446.     )
  2447.     {
  2448.     SM_END_DEV *          pSmEndDev = (SM_END_DEV *)pObj; /* device to poll */
  2449.     unsigned              len;
  2450.     int                   destCPU; /* destination cpu */
  2451.     struct ether_header * pEh      = NULL; /* enet header */
  2452.     u_char *              pEaddr; /* enet address ptr */
  2453.     SM_PKT *              pPkt     = NULL; /* packet pointer */
  2454.     SM_PKT_INFO           smInfo; /* sm info */
  2455.     if ((pObj == NULL) || (pMblk == NULL))
  2456.         {
  2457.         END_ERR_ADD (&pSmEndDev->end, MIB2_OUT_ERRS, +1);
  2458.         errno = EINVAL;
  2459.         return (ERROR);
  2460.         }
  2461.     /* cpu attached and in polled mode? */
  2462.     if (!SM_END_POLL_SM_RDY)
  2463.         {
  2464.         END_ERR_ADD (&pSmEndDev->end, MIB2_OUT_ERRS, +1);
  2465.         errno = EACCES;
  2466.         return (ERROR);
  2467.         }
  2468. /* ??? XXXmas is this next step needed? */
  2469.     /*
  2470.      * Obtain exclusive access to shared memory.  This is necessary because
  2471.      * we might have more than one stack transmitting at once.
  2472.      */
  2473.     END_TX_SEM_TAKE (&pSmEndDev->end, WAIT_FOREVER);
  2474.     /* ensure sufficient sm packet resources for one cluster */
  2475.     if (smPktInfoGet (&pSmEndDev->smPktDesc, &smInfo) == ERROR)
  2476.         {
  2477.         END_ERR_ADD (&pSmEndDev->end, MIB2_OUT_ERRS, +1);
  2478.         END_TX_SEM_GIVE (&pSmEndDev->end);
  2479.         return (EAGAIN);
  2480.         }
  2481.     if (smInfo.freePkts == 0)
  2482.         {
  2483.         END_ERR_ADD (&pSmEndDev->end, MIB2_OUT_ERRS, +1);
  2484.         END_TX_SEM_GIVE (&pSmEndDev->end);
  2485.         return (EAGAIN);
  2486.         }
  2487.     /* get a free sm packet */
  2488.     if ((smPktFreeGet (&pSmEndDev->smPktDesc, &pPkt) == ERROR) ||
  2489.         (pPkt == NULL))
  2490.         {
  2491.         END_ERR_ADD (&pSmEndDev->end, MIB2_OUT_ERRS, +1);
  2492.         return (EAGAIN);
  2493.         }
  2494.     /* point to ether address in local cluster data */
  2495.     pEh = (struct ether_header *)pMblk->mBlkHdr.mData;
  2496.     /* check for broadcast message */
  2497.     if (bcmp ((caddr_t) etherAddrPtr (pEh->ether_dhost),
  2498.               (caddr_t) etherAddrPtr (etherbroadcastaddr) ,
  2499.               sizeof (pEh->ether_dhost)) == 0)
  2500.         destCPU  = SM_BROADCAST;  /* specify broadcast */
  2501.     else
  2502.         {
  2503.         pEaddr = etherAddrPtr (pEh->ether_dhost);
  2504.         /* sequential addressing */
  2505.         if (pSmEndDev->masterAddr != 0)
  2506.             {
  2507.             destCPU = ((pEaddr [3] << 16)|(pEaddr [4] << 8)| pEaddr [5]) -
  2508.                       pSmEndDev->masterAddr;
  2509.             }
  2510.         else
  2511.             destCPU = pEaddr [5];
  2512.         /* sending to ourself */
  2513.         if (destCPU == pSmEndDev->localCpu)
  2514.             {
  2515.             /*
  2516.              * Being in polled mode means we cannot call the upper layer's
  2517.              * receive routine.  Instead, the outbound tuple must be queued
  2518.              * for polled receiving.  Caveat: tuples may be lost if not all
  2519.              * queued tuples are read by the upper layer or interrupt mode
  2520.              * is not entered.  Entering interrupt mode frees queued tuples.
  2521.              */
  2522.             SM_LOG (SM_DBG_TX, "smEndPollSend: sent to ourselvesn",
  2523.                     0, 0, 0, 0, 0, 0);
  2524.             smEndPollQPut (pSmEndDev, pMblk);
  2525.             END_ERR_ADD (&pSmEndDev->end, MIB2_OUT_UCAST, +1);
  2526.             END_TX_SEM_GIVE (&pSmEndDev->end);
  2527.             return (OK);
  2528.             }
  2529.         }
  2530.     /* copy data from cluster to sm packet */
  2531.     pEh = (struct ether_header *)  pPkt->data;
  2532.     len = max (ETHERSMALL, pMblk->mBlkHdr.mLen);
  2533.     SM_END_COPY_FROM_CLUSTER (pMblk, (char *)pEh, len);
  2534.     pPkt->header.nBytes = pMblk->mBlkHdr.mLen;
  2535.     /* now send (announce) packet to destination cpu */
  2536.     if (smPktSend (&pSmEndDev->smPktDesc, pPkt, destCPU) == ERROR)
  2537.         {
  2538.         END_ERR_ADD (&pSmEndDev->end, MIB2_OUT_ERRS, +1);
  2539.         /*
  2540.          * need to return shared memory packet on error,
  2541.          * unless it's an incomplete broadcast error.
  2542.          */
  2543.         if (errno != S_smPktLib_INCOMPLETE_BROADCAST)
  2544.             (void)smPktFreePut (&pSmEndDev->smPktDesc, pPkt);
  2545.         return (EAGAIN);
  2546.         }
  2547.     /* Bump the statistic counter. */
  2548.     else
  2549.         END_ERR_ADD (&pSmEndDev->end, MIB2_OUT_UCAST, +1);
  2550.     /* relinquish ownership of shared memory */
  2551.     END_TX_SEM_GIVE (&pSmEndDev->end);
  2552.     
  2553.     /* Cleanup.  The driver must free the tuple now. */
  2554.     netMblkClFree (pMblk);
  2555.     return (OK);
  2556.     }
  2557. /******************************************************************************
  2558. *
  2559. * smEndMCastAddrAdd - add a multicast address for the device
  2560. *
  2561. * This routine adds a multicast address to whatever the driver
  2562. * is already listening for.
  2563. * RETURNS: OK or ERROR.
  2564. *
  2565. * SEE ALSO: smEndMCastAddrDel() smEndMCastAddrGet()
  2566. */
  2567. LOCAL STATUS smEndMCastAddrAdd
  2568.     (
  2569.     void * pObj, /* cookie pointer */
  2570.     char * pAddr /* address to be added */
  2571.     )
  2572.     {
  2573.     int          retVal    = ERROR;
  2574. #if FALSE /* XXXmas  multicast is a future enhancement */
  2575.     SM_END_DEV * pSmEndDev = (SM_END_DEV *)pObj; /* device ptr */
  2576.     SM_LOG (SM_DBG_MCAST,
  2577.             "smEndMCastAddrAdd addr = 0x%x 0x%x 0x%x 0x%x 0x%x 0x%xn",
  2578.     (int) (*pAddr + 0), (int) (*pAddr + 1), 
  2579.     (int) (*pAddr + 2), (int) (*pAddr + 3), 
  2580.     (int) (*pAddr + 4), (int) (*pAddr + 5));
  2581.     retVal = etherMultiAdd (&pSmEndDev->end.multiList, pAddr);
  2582.     if (retVal == ENETRESET)
  2583. {
  2584.         pSmEndDev->end.nMulti++;
  2585.  
  2586. return (smEndHashTblAdd (pSmEndDev, pAddr));
  2587. }
  2588. #else
  2589.     errno = ENOTSUP;
  2590. #endif
  2591.     return ((retVal == OK) ? OK : ERROR);
  2592.     }
  2593. /******************************************************************************
  2594. *
  2595. * smEndMCastAddrDel - delete a multicast address for the device
  2596. *
  2597. * This routine deletes a multicast address from the current list of
  2598. * multicast addresses.
  2599. * RETURNS: OK or ERROR.
  2600. *
  2601. * SEE ALSO: smEndMCastAddrAdd() smEndMCastAddrGet()
  2602. */
  2603. LOCAL STATUS smEndMCastAddrDel
  2604.     (
  2605.     void * pObj, /* cookie pointer */
  2606.     char * pAddr /* address to be deleted */
  2607.     )
  2608.     {
  2609.     int          retVal    = ERROR;
  2610. #if FALSE /* XXXmas  multicast is a future enhancement */
  2611.     SM_END_DEV * pSmEndDev = (SM_END_DEV *)pObj; /* device ptr */
  2612.     SM_LOG (SM_DBG_MCAST,
  2613.             "smEndMCastAddrDel addr = 0x%x 0x%x 0x%x 0x%x 0x%x 0x%xn",
  2614.     (int) (*pAddr + 0), (int) (*pAddr + 1), 
  2615.     (int) (*pAddr + 2), (int) (*pAddr + 3), 
  2616.     (int) (*pAddr + 4), (int) (*pAddr + 5));
  2617.     retVal = etherMultiDel (&pSmEndDev->end.multiList, pAddr);
  2618.     if (retVal == ENETRESET)
  2619. {
  2620. pSmEndDev->end.nMulti--;
  2621. /* stop the sm device */
  2622. if (smEndStop (pSmEndDev) != OK)
  2623.     return (ERROR);
  2624. /* populate the hash table */
  2625. retVal = smEndHashTblPopulate (pSmEndDev);
  2626. /* restart the sm device */
  2627. if (smEndStart (pSmEndDev) != OK)
  2628.     return (ERROR);
  2629. }
  2630. #else
  2631.     errno = ENOTSUP;
  2632. #endif
  2633.     return ((retVal == OK) ? OK : ERROR);
  2634.     }
  2635. /******************************************************************************
  2636. *
  2637. * smEndMCastAddrGet - get the current multicast address list
  2638. *
  2639. * This routine returns the current multicast address list in <pTable>
  2640. *
  2641. * RETURNS: OK or ERROR.
  2642. *
  2643. * SEE ALSO: smEndMCastAddrAdd() smEndMCastAddrDel()
  2644. */
  2645. LOCAL STATUS smEndMCastAddrGet
  2646.     (
  2647.     void *        pObj, /* cookie pointer */
  2648.     MULTI_TABLE * pTable /* table into which to copy addresses */
  2649.     )
  2650.     {
  2651. #if FALSE /* XXXmas  multicast is a future enhancement */
  2652.     SM_END_DEV * pSmEndDev = (SM_END_DEV *)pObj; /* device ptr */
  2653.     SM_LOG (SM_DBG_MCAST, "smEndMCastAddrGetn", 0, 0, 0, 0, 0, 0);
  2654.     return (etherMultiGet (&pSmEndDev->end.multiList, pTable));
  2655. #else
  2656.     errno = ENOTSUP;
  2657.     return (ERROR);
  2658. #endif
  2659.     }
  2660. /*******************************************************************************
  2661. *
  2662. * smEndAddrResolve - resolve an Ethernet address
  2663. *
  2664. * This routine converts a destination IP address into a destination
  2665. * Ethernet HW address.  If sequential addressing is being used and the
  2666. * destination is attached to shared memory, a simple mapping is performed as
  2667. * explained in smEndHwAddrSet().  Otherwise, a direct lookup in the sm
  2668. * CPU descriptors is performed, matching the specified IP address to an
  2669. * attached CPU.
  2670. *
  2671. * RETURNS: 1 (send packet) if successful, otherwise 0 (pend packet).
  2672. *
  2673. * SEE ALSO: smEndHwAddrSet()
  2674. *
  2675. * INTERNAL: This routine is based on arpioctl(SIOCSARP) rev 01g,03sep98.
  2676. */
  2677. LOCAL int smEndAddrResolve
  2678.     (
  2679.     FAST struct arpcom *   pAc, /* arpcom structure */
  2680.     FAST struct rtentry *  pRt, /* retry entry list */
  2681.     struct mbuf *          pMbuf, /* resolve address for this mbuf */
  2682.     FAST struct sockaddr * pDestIP, /* destination IP address */
  2683.     FAST u_char *          pDestHW /* destination ethernet HW address */
  2684.     )
  2685.     {
  2686.     struct llinfo_arp *  pLa;
  2687.     struct sockaddr_dl * pSdl;
  2688.     SM_PKT_CPU_DESC *  pPktCpuDesc;
  2689.     u_long  dstHostAddr;
  2690.     unsigned  destCpu;
  2691.     unsigned  maxCpus;
  2692.     SM_END_DEV *  pSmEndDev = unitTbl [pAc->ac_if.if_unit];
  2693.     FAST SM_CPU_DESC *  pCpuDesc; /* sm CPU descriptor */
  2694.     FAST SM_ANCHOR *  pAnchor = pSmEndDev->pAnchor;
  2695.     FAST SM_HDR *  pSmHdr;
  2696.     FAST SM_DESC *  pSmDesc = &pSmEndDev->smPktDesc.smDesc;
  2697.     static u_char  etherbroadcastaddr[6] =
  2698.     {0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
  2699.     if (pMbuf != NULL)          /* check if mbuf is not null */
  2700.         {
  2701.         if (pMbuf->m_flags & M_BCAST)
  2702.             {       /* broadcast */
  2703.             bcopy((caddr_t)etherbroadcastaddr, (caddr_t)pDestHW,
  2704.                   sizeof(etherbroadcastaddr));
  2705.             SM_LOG (SM_DBG_RSLV, "smEndAddrResolve: broadcast packetn",
  2706.                     0, 0, 0, 0, 0, 0);
  2707.             return (1);
  2708.             }
  2709.         if (pMbuf->m_flags & M_MCAST)
  2710.             {       /* multicast */
  2711.             ETHER_MAP_IP_MULTICAST(&((struct sockaddr_in *)pDestIP)->sin_addr,
  2712.                                    pDestHW);
  2713.             SM_LOG (SM_DBG_RSLV, "smEndAddrResolve: multicast packetn",
  2714.                     0, 0, 0, 0, 0, 0);
  2715.             return(1);
  2716.             }
  2717.         }
  2718.     /* preliminary lookup */
  2719.     if (pRt != NULL)
  2720.         pLa = (struct llinfo_arp *)pRt->rt_llinfo;
  2721.     else
  2722. #ifndef SM_ARP_SUPPORT
  2723.         {
  2724.         SM_LOG (SM_DBG_RSLV, "smEndAddrResolve: ARP not supported!n",
  2725.                 0, 0, 0, 0, 0, 0);
  2726.         m_freem(pMbuf);
  2727.         return (0);
  2728.         }
  2729. #else
  2730.         {
  2731.         if ((pLa = arplookup(((struct sockaddr_in *)pDestIP)->sin_addr.s_addr,
  2732.                             1, 0)) != NULL)
  2733.             pRt = pLa->la_rt;
  2734.         }
  2735. #endif /* SM_ARP_SUPPORT */
  2736.     if (pLa == NULL || pRt == NULL)
  2737.         {
  2738.         SM_LOG (SM_DBG_RSLV, "smEndAddrResolve: can't allocate llinfon",
  2739.                 0, 0, 0, 0, 0, 0);
  2740.         m_freem(pMbuf);
  2741.         return (0);
  2742.         }
  2743.     /* prepare router table pointer and entry */
  2744.     pSdl = (struct sockaddr_dl *)(pRt->rt_gateway);
  2745.     pRt->rt_rmx.rmx_expire = 0; /* make table entry permanent */
  2746.     /* if entry already exists, just return it */
  2747.     if ((pSdl->sdl_family == AF_LINK) && (pSdl->sdl_alen != 0))
  2748.         {
  2749.         pRt->rt_flags &= ~RTF_REJECT;
  2750.         bcopy ((char *)((caddr_t)(pSdl->sdl_data + pSdl->sdl_nlen)),
  2751.                pDestHW, pSdl->sdl_alen);
  2752.         return (1);
  2753.         }
  2754.     /* derive destination CPU IP address */
  2755.     dstHostAddr = ((struct sockaddr_in *)pDestIP)->sin_addr.s_addr;
  2756.     dstHostAddr &= 0x00ffffff;
  2757.     /*
  2758.      * If sequential addressing mode, use simple address translation
  2759.      * mechanism to resolve HW address.
  2760.      */
  2761.     if (pSmEndDev->masterAddr != 0)
  2762.         {
  2763.         /*
  2764.          * Check for erroneous input or unattached CPU.
  2765.          * If either, free the buffer and return 0.
  2766.          */
  2767.         destCpu = dstHostAddr - pSmEndDev->masterAddr;
  2768.         if ((destCpu < 0) || (destCpu >= pSmEndDev->smPktDesc.smDesc.maxCpus))
  2769.             {
  2770.             SM_LOG (SM_DBG_RSLV, "smEndAddrResolve: illegal CPU #%un",
  2771.                     destCpu, 0, 0, 0, 0, 0);
  2772.             m_freem (pMbuf);
  2773.             return (0);
  2774.             }
  2775.         /*
  2776.          * XXXmas this would reflect current information if the actual sm
  2777.          * structure were read rather than a local copy.  Although it has
  2778.          * greater overhead and impacts bus traffic, it will allow for Hot
  2779.          * Swap of processor boards.  For the future...
  2780.          */
  2781.         pPktCpuDesc = &((pSmEndDev->smPktDesc.cpuLocalAdrs) [destCpu]);
  2782.         if (pPktCpuDesc->status != SM_CPU_ATTACHED)
  2783.             {
  2784.             SM_LOG (SM_DBG_RSLV, "smEndAddrResolve: CPU #%u not attachedn",
  2785.                     destCpu, 0, 0, 0, 0, 0);
  2786.             m_freem (pMbuf);
  2787.             return (0);
  2788.             }
  2789.         pDestHW [0] = 0x00;
  2790.         pDestHW [1] = 0x02;
  2791.         pDestHW [2] = 0xE2;
  2792.         pDestHW [3] = (dstHostAddr >> 16) & 0xff;
  2793.         pDestHW [4] = (dstHostAddr >> 8) & 0xff;
  2794.         pDestHW [5] = dstHostAddr & 0xff;
  2795.         }
  2796.     /*
  2797.      * Non-sequential addressing is used.  Must walk the array of CPU
  2798.      * descriptors in sm and find a match to the specified IP address.
  2799.      * If no match is found, it as assumed that the destination CPU is
  2800.      * not yet attached.  In this case, the buffer is freed and zero is
  2801.      * returned.
  2802.      */
  2803.     else
  2804.         {
  2805.         /* derive major sm structure pointers */
  2806.         pSmHdr   = SM_OFFSET_TO_LOCAL (ntohl (pAnchor->smHeader),
  2807.                                        pSmDesc->base,
  2808.                                        SM_HDR *);
  2809.         pCpuDesc = SM_OFFSET_TO_LOCAL (ntohl (pSmHdr->cpuTable),
  2810.                                        pSmDesc->base,
  2811.                                        SM_CPU_DESC *);
  2812.         /* check each CPU descriptor until IP address match or end of list */
  2813.         for (destCpu = 0, maxCpus = pSmHdr->maxCpus;
  2814.              destCpu < maxCpus;
  2815.              ++destCpu)
  2816.             {
  2817.             if (pCpuDesc[destCpu].reserved1 == dstHostAddr)
  2818.                 break;
  2819.             }
  2820.         if (destCpu >= maxCpus)
  2821.             {
  2822.             SM_LOG (SM_DBG_RSLV,
  2823.                   "smEndAddrResolve: CPU with IP = %u.%u.%u.%u not attachedn",
  2824.                     (dstHostAddr >> 24) & 0x000000FF,
  2825.                     (dstHostAddr >> 16) & 0x000000FF,
  2826.                     (dstHostAddr >>  8) & 0x000000FF,
  2827.                     dstHostAddr & 0x000000FF, 0, 0);
  2828.             m_freem (pMbuf);
  2829.             return (0);
  2830.             }
  2831.         /* match found; derive sm HW address */
  2832.         pDestHW [0] = 0x00;
  2833.         pDestHW [1] = 0x02;
  2834.         pDestHW [2] = 0xE2;
  2835.         pDestHW [3] = 0x00;
  2836.         pDestHW [4] = pSmEndDev->unit & 0xff;
  2837.         pDestHW [5] = destCpu & 0xff;
  2838.         }
  2839.     /* enter directly into arp table for efficency */
  2840.     pSdl->sdl_alen = EADDR_LEN;   /* sizeof ethernet HW address */
  2841.     bcopy (pDestHW, (char *)LLADDR(pSdl), pSdl->sdl_alen); 
  2842.     pRt->rt_flags &= ~RTF_REJECT;
  2843.     return (1);
  2844.     }