patch-2.1.132 linux/drivers/net/rcmtl.c

Next file: linux/drivers/net/rcmtl.h
Previous file: linux/drivers/net/rcif.h
Back to the patch index
Back to the overall index

diff -u --recursive --new-file v2.1.131/linux/drivers/net/rcmtl.c linux/drivers/net/rcmtl.c
@@ -0,0 +1,2058 @@
+/*
+** *************************************************************************
+**
+**
+**     R C M T L . C             $Revision: 1.1 $
+**
+**
+**  RedCreek Message Transport Layer program module.
+**
+**  ---------------------------------------------------------------------
+**  ---     Copyright (c) 1997-1998, RedCreek Communications Inc.     ---
+**  ---                   All rights reserved.                        ---
+**  ---------------------------------------------------------------------
+**
+** File Description:
+**
+** Host side message transport layer.
+**
+**  This program is free software; you can redistribute it and/or modify
+**  it under the terms of the GNU General Public License as published by
+**  the Free Software Foundation; either version 2 of the License, or
+**  (at your option) any later version.
+
+**  This program is distributed in the hope that it will be useful,
+**  but WITHOUT ANY WARRANTY; without even the implied warranty of
+**  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+**  GNU General Public License for more details.
+
+**  You should have received a copy of the GNU General Public License
+**  along with this program; if not, write to the Free Software
+**  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+**
+***************************************************************************/
+
+#undef DEBUG
+
+#define RC_LINUX_MODULE
+#include "rcmtl.h"
+
+#define dprintf kprintf
+
+extern int printk(const char * fmt, ...);
+
+ /* RedCreek LAN device Target ID */
+#define LAN_TARGET_ID  0x10 
+ /* RedCreek's OSM default LAN receive Initiator */
+#define DEFAULT_RECV_INIT_CONTEXT  0xA17  
+
+
+/*
+** message structures
+*/
+
+#define    TID_SZ                                  12
+#define    FUNCTION_SZ                             8
+
+/* Transaction Reply Lists (TRL) Control Word structure */
+
+#define    TRL_SINGLE_FIXED_LENGTH           0x00
+#define    TRL_SINGLE_VARIABLE_LENGTH        0x40
+#define    TRL_MULTIPLE_FIXED_LENGTH         0x80
+
+/* LAN Class specific functions */
+
+#define    LAN_PACKET_SEND                         0x3B
+#define    LAN_SDU_SEND                            0x3D
+#define    LAN_RECEIVE_POST                        0x3E
+#define    LAN_RESET                               0x35
+#define    LAN_SHUTDOWN                            0x37
+
+/* Private Class specfic function */
+#define    RC_PRIVATE                                 0xFF
+
+/*  RC Executive Function Codes.  */
+
+#define    RC_CMD_ADAPTER_ASSIGN                     0xB3
+#define    RC_CMD_ADAPTER_READ                       0xB2
+#define    RC_CMD_ADAPTER_RELEASE                    0xB5
+#define    RC_CMD_BIOS_INFO_SET                      0xA5
+#define    RC_CMD_BOOT_DEVICE_SET                    0xA7
+#define    RC_CMD_CONFIG_VALIDATE                    0xBB
+#define    RC_CMD_CONN_SETUP                         0xCA
+#define    RC_CMD_DEVICE_ASSIGN                      0xB7
+#define    RC_CMD_DEVICE_RELEASE                     0xB9
+#define    RC_CMD_HRT_GET                            0xA8
+#define    RC_CMD_ADAPTER_CLEAR                          0xBE
+#define    RC_CMD_ADAPTER_CONNECT                        0xC9
+#define    RC_CMD_ADAPTER_RESET                          0xBD
+#define    RC_CMD_LCT_NOTIFY                         0xA2
+#define    RC_CMD_OUTBOUND_INIT                      0xA1
+#define    RC_CMD_PATH_ENABLE                        0xD3
+#define    RC_CMD_PATH_QUIESCE                       0xC5
+#define    RC_CMD_PATH_RESET                         0xD7
+#define    RC_CMD_STATIC_MF_CREATE                   0xDD
+#define    RC_CMD_STATIC_MF_RELEASE                  0xDF
+#define    RC_CMD_STATUS_GET                         0xA0
+#define    RC_CMD_SW_DOWNLOAD                        0xA9
+#define    RC_CMD_SW_UPLOAD                          0xAB
+#define    RC_CMD_SW_REMOVE                          0xAD
+#define    RC_CMD_SYS_ENABLE                         0xD1
+#define    RC_CMD_SYS_MODIFY                         0xC1
+#define    RC_CMD_SYS_QUIESCE                        0xC3
+#define    RC_CMD_SYS_TAB_SET                        0xA3
+
+
+ /* Init Outbound Q status */
+#define    RC_CMD_OUTBOUND_INIT_IN_PROGRESS          0x01
+#define    RC_CMD_OUTBOUND_INIT_REJECTED             0x02
+#define    RC_CMD_OUTBOUND_INIT_FAILED               0x03
+#define    RC_CMD_OUTBOUND_INIT_COMPLETE             0x04
+
+
+#define    UTIL_NOP                                0x00
+
+
+/* RC Get Status State values */
+
+#define    ADAPTER_STATE_INITIALIZING                  0x01
+#define    ADAPTER_STATE_RESET                         0x02
+#define    ADAPTER_STATE_HOLD                          0x04
+#define    ADAPTER_STATE_READY                         0x05
+#define    ADAPTER_STATE_OPERATIONAL                   0x08
+#define    ADAPTER_STATE_FAILED                        0x10
+#define    ADAPTER_STATE_FAULTED                       0x11
+
+
+/* Defines for Request Status Codes:  Table 3-1 Reply Status Codes.  */
+
+#define    RC_REPLY_STATUS_SUCCESS                    0x00
+#define    RC_REPLY_STATUS_ABORT_DIRTY                0x01
+#define    RC_REPLY_STATUS_ABORT_NO_DATA_TRANSFER     0x02
+#define    RC_REPLY_STATUS_ABORT_PARTIAL_TRANSFER     0x03
+#define    RC_REPLY_STATUS_ERROR_DIRTY                0x04
+#define    RC_REPLY_STATUS_ERROR_NO_DATA_TRANSFER     0x05
+#define    RC_REPLY_STATUS_ERROR_PARTIAL_TRANSFER     0x06
+#define    RC_REPLY_STATUS_PROCESS_ABORT_DIRTY        0x07
+#define    RC_REPLY_STATUS_PROCESS_ABORT_NO_DATA_TRANSFER   0x08
+#define    RC_REPLY_STATUS_PROCESS_ABORT_PARTIAL_TRANSFER   0x09
+#define    RC_REPLY_STATUS_TRANSACTION_ERROR          0x0A
+#define    RC_REPLY_STATUS_PROGRESS_REPORT            0x80
+
+
+/* DetailedStatusCode defines for ALL messages: Table 3-2 Detailed Status Codes.*/
+
+#define    RC_DS_SUCCESS                        0x0000
+#define    RC_DS_BAD_KEY                        0x0001
+#define    RC_DS_CHAIN_BUFFER_TOO_LARGE         0x0002
+#define    RC_DS_DEVICE_BUSY                    0x0003
+#define    RC_DS_DEVICE_LOCKED                  0x0004
+#define    RC_DS_DEVICE_NOT_AVAILABLE           0x0005
+#define    RC_DS_DEVICE_RESET                   0x0006
+#define    RC_DS_INAPPROPRIATE_FUNCTION         0x0007
+#define    RC_DS_INSUFFICIENT_RESOURCE_HARD     0x0008
+#define    RC_DS_INSUFFICIENT_RESOURCE_SOFT     0x0009
+#define    RC_DS_INVALID_INITIATOR_ADDRESS      0x000A
+#define    RC_DS_INVALID_MESSAGE_FLAGS          0x000B
+#define    RC_DS_INVALID_OFFSET                 0x000C
+#define    RC_DS_INVALID_PARAMETER              0x000D
+#define    RC_DS_INVALID_REQUEST                0x000E
+#define    RC_DS_INVALID_TARGET_ADDRESS         0x000F
+#define    RC_DS_MESSAGE_TOO_LARGE              0x0010
+#define    RC_DS_MESSAGE_TOO_SMALL              0x0011
+#define    RC_DS_MISSING_PARAMETER              0x0012
+#define    RC_DS_NO_SUCH_PAGE                   0x0013
+#define    RC_DS_REPLY_BUFFER_FULL              0x0014
+#define    RC_DS_TCL_ERROR                      0x0015
+#define    RC_DS_TIMEOUT                        0x0016
+#define    RC_DS_UNKNOWN_ERROR                  0x0017
+#define    RC_DS_UNKNOWN_FUNCTION               0x0018
+#define    RC_DS_UNSUPPORTED_FUNCTION           0x0019
+#define    RC_DS_UNSUPPORTED_VERSION            0x001A
+
+ /* msg header defines for VersionOffset */
+#define RCMSGVER_1   0x0001
+#define SGL_OFFSET_0    RCMSGVER_1
+#define SGL_OFFSET_4    (0x0040 | RCMSGVER_1)
+#define TRL_OFFSET_5    (0x0050 | RCMSGVER_1)
+#define TRL_OFFSET_6    (0x0060 | RCMSGVER_1)
+
+ /* msg header defines for MsgFlags */
+#define MSG_STATIC      0x0100
+#define MSG_64BIT_CNTXT 0x0200
+#define MSG_MULTI_TRANS 0x1000
+#define MSG_FAIL        0x2000
+#define MSG_LAST        0x4000
+#define MSG_REPLY       0x8000
+
+  /* normal LAN request message MsgFlags and VersionOffset (0x1041) */
+#define LAN_MSG_REQST  (MSG_MULTI_TRANS | SGL_OFFSET_4)
+
+ /* minimum size msg */
+#define THREE_WORD_MSG_SIZE 0x00030000
+#define FOUR_WORD_MSG_SIZE  0x00040000
+#define FIVE_WORD_MSG_SIZE  0x00050000
+#define SIX_WORD_MSG_SIZE   0x00060000
+#define SEVEN_WORD_MSG_SIZE 0x00070000
+#define EIGHT_WORD_MSG_SIZE 0x00080000
+#define NINE_WORD_MSG_SIZE  0x00090000
+
+/* Special TID Assignments */
+
+#define ADAPTER_TID   0
+#define HOST_TID  1
+
+ /* RedCreek private message codes */
+#define RC_PRIVATE_GET_MAC_ADDR     0x0001/**/ /* OBSOLETE */
+#define RC_PRIVATE_SET_MAC_ADDR     0x0002
+#define RC_PRIVATE_GET_LAN_STATS    0x0003
+#define RC_PRIVATE_GET_LINK_STATUS  0x0004
+#define RC_PRIVATE_SET_LINK_SPEED   0x0005
+#define RC_PRIVATE_SET_IP_AND_MASK  0x0006
+/* #define RC_PRIVATE_GET_IP_AND_MASK  0x0007 */ /* OBSOLETE */
+#define RC_PRIVATE_GET_LINK_SPEED   0x0008
+#define RC_PRIVATE_GET_FIRMWARE_REV 0x0009
+/* #define RC_PRIVATE_GET_MAC_ADDR     0x000A *//**/
+#define RC_PRIVATE_GET_IP_AND_MASK  0x000B /**/
+#define RC_PRIVATE_DEBUG_MSG        0x000C
+#define RC_PRIVATE_REPORT_DRIVER_CAPABILITY  0x000D
+
+#define RC_PRIVATE_REBOOT           0x00FF
+
+
+/* RC message header */
+typedef struct _RC_MSG_FRAME 
+{
+   U8                          VersionOffset;
+   U8                          MsgFlags;
+   U16                         MessageSize;
+   BF                          TargetAddress:TID_SZ;
+   BF                          InitiatorAddress:TID_SZ;
+   BF                          Function:FUNCTION_SZ;
+   U32                         InitiatorContext;
+   /* SGL[] */ 
+}
+ RC_MSG_FRAME, *PRC_MSG_FRAME;
+
+
+ /* assumed a 16K minus 256 byte space for outbound queue message frames */
+#define MSG_FRAME_SIZE  512
+#define NMBR_MSG_FRAMES 30
+
+/*
+**  Message Unit CSR definitions for RedCreek PCI45 board
+*/
+typedef struct tag_rcatu 
+{
+    volatile unsigned long APICRegSel;  /* APIC Register Select */
+    volatile unsigned long reserved0;
+    volatile unsigned long APICWinReg;  /* APIC Window Register */
+    volatile unsigned long reserved1;
+    volatile unsigned long InMsgReg0;   /* inbound message register 0 */
+    volatile unsigned long InMsgReg1;   /* inbound message register 1 */
+    volatile unsigned long OutMsgReg0;  /* outbound message register 0 */
+    volatile unsigned long OutMsgReg1;  /* outbound message register 1 */
+    volatile unsigned long InDoorReg;   /* inbound doorbell register */
+    volatile unsigned long InIntStat;   /* inbound interrupt status register */
+    volatile unsigned long InIntMask;   /* inbound interrupt mask register */
+    volatile unsigned long OutDoorReg;  /* outbound doorbell register */
+    volatile unsigned long OutIntStat;  /* outbound interrupt status register */
+    volatile unsigned long OutIntMask;  /* outbound interrupt mask register */
+    volatile unsigned long reserved2;
+    volatile unsigned long reserved3;
+    volatile unsigned long InQueue;     /* inbound queue port */
+    volatile unsigned long OutQueue;    /* outbound queue port */
+    volatile unsigned long reserved4;
+    volatile unsigned long reserver5;
+     /* RedCreek extension */
+    volatile unsigned long EtherMacLow;
+    volatile unsigned long EtherMacHi;
+    volatile unsigned long IPaddr;
+    volatile unsigned long IPmask;
+}
+ ATU, *PATU;
+
+ /* 
+ ** typedef PAB
+ **
+ ** PCI Adapter Block - holds instance specific information and is located
+ ** in a reserved space at the start of the message buffer allocated by user.
+ */
+typedef struct
+{
+    PATU             p_atu;                /* ptr to  ATU register block */
+    PU8              pPci45LinBaseAddr;
+    PU8              pLinOutMsgBlock;
+    U32              outMsgBlockPhyAddr; 
+    PFNTXCALLBACK    pTransCallbackFunc;
+    PFNRXCALLBACK    pRecvCallbackFunc;
+    PFNCALLBACK      pRebootCallbackFunc;
+    PFNCALLBACK      pCallbackFunc;
+    U16              ADAPTERState;
+    U16              InboundMFrameSize;
+}
+ PAB, *PPAB;
+
+ /* 
+ ** in reserved space right after PAB in host memory is area for returning
+ ** values from card 
+ */
+
+ /* 
+ ** Array of pointers to PCI Adapter Blocks.
+ ** Indexed by a zero based (0-31) interface number.
+ */ 
+#define MAX_ADAPTERS 32
+static PPAB  PCIAdapterBlock[MAX_ADAPTERS] = 
+{
+    NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+    NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+    NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+    NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL
+};
+
+
+/*
+** typedef NICSTAT
+**
+** Data structure for NIC statistics retruned from PCI card.  Data copied from
+** here to user allocated RCLINKSTATS (see rclanmtl.h) structure.
+*/
+typedef struct tag_NicStat 
+{
+        unsigned long   TX_good; 
+        unsigned long   TX_maxcol;
+        unsigned long   TX_latecol;
+        unsigned long   TX_urun;
+        unsigned long   TX_crs;         /* lost carrier sense */
+        unsigned long   TX_def;         /* transmit deferred */
+        unsigned long   TX_singlecol;   /* single collisions */
+        unsigned long   TX_multcol;
+        unsigned long   TX_totcol;
+        unsigned long   Rcv_good;
+        unsigned long   Rcv_CRCerr;
+        unsigned long   Rcv_alignerr;
+        unsigned long   Rcv_reserr;     /* rnr'd pkts */
+        unsigned long   Rcv_orun;
+        unsigned long   Rcv_cdt;
+        unsigned long   Rcv_runt;
+        unsigned long   dump_status;    /* last field directly from the chip */
+} 
+ NICSTAT, *P_NICSTAT;
+ 
+
+#define DUMP_DONE   0x0000A005      /* completed statistical dump */
+#define DUMP_CLEAR  0x0000A007      /* completed stat dump and clear counters */
+
+
+static volatile int msgFlag;
+
+
+/* local function prototypes */
+static void ProcessOutboundAdapterMsg(PPAB pPab, U32 phyMsgAddr);
+static int FillAdapterMsgSGLFromTCB(PU32 pMsg, PRCTCB pXmitCntrlBlock);
+static int GetAdapterStatus(PPAB pPab);
+static int SendAdapterOutboundQInitMsg(PPAB pPab);
+static int SendEnableSysMsg(PPAB pPab);
+
+
+ /* 1st 100h bytes of message block is reserved for messenger instance */
+#define ADAPTER_BLOCK_RESERVED_SPACE 0x100
+
+/*
+** =========================================================================
+** InitRCApiMsgLayer()
+**
+** Initialize the RedCreek API Module and adapter.
+**
+** Inputs:  AdapterID - interface number from 0 to 15
+**          pciBaseAddr - virual base address of PCI (set by BIOS)
+**          p_msgbuf - virual address to private message block (min. 16K)
+**          p_phymsgbuf - physical address of private message block
+**          TransmitCallbackFunction - address of transmit callback function
+**          ReceiveCallbackFunction  - address of receive  callback function
+**
+** private message block is allocated by user.  It must be in locked pages.
+** p_msgbuf and p_phymsgbuf point to the same location.  Must be contigous
+** memory block of a minimum of 16K byte and long word aligned.
+** =========================================================================
+*/
+RC_RETURN
+InitRCApiMsgLayer(U16 AdapterID, U32 pciBaseAddr, 
+                  PU8 p_msgbuf,  PU8 p_phymsgbuf,
+                  PFNTXCALLBACK  TransmitCallbackFunction,
+                  PFNRXCALLBACK  ReceiveCallbackFunction,
+                  PFNCALLBACK    RebootCallbackFunction)
+{
+     int result;
+     PPAB pPab; 
+    
+#ifdef DEBUG
+     kprintf("InitAPI: Adapter:0x%04.4ux ATU:0x%08.8ulx msgbuf:0x%08.8ulx phymsgbuf:0x%08.8ulx\n"
+             "TransmitCallbackFunction:0x%08.8ulx  ReceiveCallbackFunction:0x%08.8ulx\n",
+             AdapterID, pciBaseAddr, p_msgbuf, p_phymsgbuf, TransmitCallbackFunction, ReceiveCallbackFunction);
+#endif /* DEBUG */
+
+    
+     /* Check if this interface already initialized - if so, shut it down */
+     if (PCIAdapterBlock[AdapterID] != NULL)
+     {
+          printk("PCIAdapterBlock[%d]!=NULL\n", AdapterID);
+//        RCResetLANCard(AdapterID, 0, (PU32)NULL, (PFNCALLBACK)NULL);
+          PCIAdapterBlock[AdapterID] = NULL;
+     }
+
+    /* 
+    ** store adapter instance values in adapter block.
+    ** Adapter block is at beginning of message buffer
+    */  
+    pPab = (PPAB)p_msgbuf;
+    
+    pPab->p_atu = (PATU)pciBaseAddr;
+    pPab->pPci45LinBaseAddr =  (PU8)pciBaseAddr;
+    
+     /* Set outbound message frame addr - skip over Adapter Block */
+    pPab->outMsgBlockPhyAddr = (U32)(p_phymsgbuf + ADAPTER_BLOCK_RESERVED_SPACE);
+    pPab->pLinOutMsgBlock    = (PU8)(p_msgbuf + ADAPTER_BLOCK_RESERVED_SPACE);
+
+     /* store callback function addresses */
+    pPab->pTransCallbackFunc = TransmitCallbackFunction;
+    pPab->pRecvCallbackFunc  = ReceiveCallbackFunction;
+    pPab->pRebootCallbackFunc  = RebootCallbackFunction;
+    pPab->pCallbackFunc  = (PFNCALLBACK)NULL;
+
+    /*
+    ** Initialize API 
+    */
+    result = GetAdapterStatus(pPab);
+    
+    if (result != RC_RTN_NO_ERROR)
+        return result;
+
+    if (pPab->ADAPTERState == ADAPTER_STATE_OPERATIONAL)
+    {
+         printk("pPab->ADAPTERState == op: resetting adapter\n");
+         RCResetLANCard(AdapterID, 0, (PU32)NULL, (PFNCALLBACK)NULL);
+    }
+        
+    result = SendAdapterOutboundQInitMsg(pPab);
+    
+    if (result != RC_RTN_NO_ERROR)
+         return result;
+
+    result = SendEnableSysMsg(pPab);
+   
+    if (result != RC_RTN_NO_ERROR)
+         return result;
+   
+    PCIAdapterBlock[AdapterID] = pPab;
+    return RC_RTN_NO_ERROR;
+}
+
+/*
+** =========================================================================
+** Disable and Enable Adapter interrupts.  Adapter interrupts are enabled at Init time
+** but can be disabled and re-enabled through these two function calls.
+** Packets will still be put into any posted received buffers and packets will
+** be sent through RCSendPacket() functions.  Disabling Adapter interrupts
+** will prevent hardware interrupt to host even though the outbound Adapter msg
+** queue is not emtpy.
+** =========================================================================
+*/
+#define i960_OUT_POST_Q_INT_BIT        0x0008 /* bit set masks interrupts */
+
+RC_RETURN RCDisableAdapterInterrupts(U16 AdapterID)
+{
+    PPAB pPab;
+
+
+    pPab = PCIAdapterBlock[AdapterID];
+    
+    if (pPab == NULL)
+        return RC_RTN_ADPTR_NOT_REGISTERED;
+        
+    pPab->p_atu->OutIntMask |= i960_OUT_POST_Q_INT_BIT;
+
+    return RC_RTN_NO_ERROR;
+}
+
+RC_RETURN RCEnableAdapterInterrupts(U16 AdapterID)
+{
+    PPAB pPab;
+
+    pPab = PCIAdapterBlock[AdapterID];
+    
+    if (pPab == NULL)
+         return RC_RTN_ADPTR_NOT_REGISTERED;
+    
+    pPab->p_atu->OutIntMask &= ~i960_OUT_POST_Q_INT_BIT;
+    
+    return RC_RTN_NO_ERROR;
+
+}
+
+
+/*
+** =========================================================================
+** RCSendPacket()
+** =========================================================================
+*/
+RC_RETURN
+RCSendPacket(U16 AdapterID, U32 InitiatorContext, PRCTCB pTransCtrlBlock)
+{
+    U32 msgOffset;
+    PU32 pMsg;
+    int size;
+    PPAB pPab;
+
+#ifdef DEBUG
+kprintf("RCSendPacket()...\n");
+#endif /* DEBUG */
+    
+    pPab = PCIAdapterBlock[AdapterID];
+
+    if (pPab == NULL)
+        return RC_RTN_ADPTR_NOT_REGISTERED;
+    
+     /* get Inbound free Q entry - reading from In Q gets free Q entry */
+     /* offset to Msg Frame in PCI msg block */
+
+    msgOffset = pPab->p_atu->InQueue; 
+
+    if (msgOffset == 0xFFFFFFFF)
+    {
+#ifdef DEBUG
+        kprintf("RCSendPacket(): Inbound Free Q empty!\n");
+#endif /* DEBUG */
+        return RC_RTN_FREE_Q_EMPTY;
+    }
+        
+     /* calc virual address of msg - virual already mapped to physical */    
+    pMsg = (PU32)(pPab->pPci45LinBaseAddr + msgOffset);
+
+    size = FillAdapterMsgSGLFromTCB(pMsg + 4, pTransCtrlBlock);
+
+    if (size == -1) /* error processing TCB - send NOP msg */
+    {
+#ifdef DEBUG
+            kprintf("RCSendPacket(): Error Rrocess TCB!\n");
+#endif /* DEBUG */
+        pMsg[0] = THREE_WORD_MSG_SIZE | SGL_OFFSET_0;
+        pMsg[1] = UTIL_NOP << 24 | HOST_TID << 12 | LAN_TARGET_ID;
+        return RC_RTN_TCB_ERROR;
+    }
+    else /* send over msg header */
+    {    
+        pMsg[0] = (size + 4) << 16 | LAN_MSG_REQST; /* send over message size and flags */
+        pMsg[1] = LAN_PACKET_SEND << 24 | HOST_TID << 12 | LAN_TARGET_ID;
+        pMsg[2] = InitiatorContext;
+        pMsg[3] = 0;  /* batch reply */
+         /* post to Inbound Post Q */   
+        pPab->p_atu->InQueue = msgOffset;
+        return RC_RTN_NO_ERROR;
+    }
+}
+ 
+
+/*
+** =========================================================================
+** RCPostRecvBuffer()
+**
+** inputs:  pBufrCntrlBlock - pointer to buffer control block
+**
+** returns TRUE if successful in sending message, else FALSE.
+** =========================================================================
+*/
+RC_RETURN
+RCPostRecvBuffers(U16 AdapterID, PRCTCB pTransCtrlBlock)
+{
+    U32 msgOffset;
+    PU32 pMsg;
+    int size;
+    PPAB pPab;
+
+#ifdef DEBUG
+kprintf("RCPostRecvBuffers()...\n");
+#endif /* DEBUG */
+    
+     /* search for DeviceHandle */
+    pPab = PCIAdapterBlock[AdapterID];
+
+    if (pPab == NULL)
+        return RC_RTN_ADPTR_NOT_REGISTERED;
+    
+
+     /* get Inbound free Q entry - reading from In Q gets free Q entry */
+     /* offset to Msg Frame in PCI msg block */
+    msgOffset = pPab->p_atu->InQueue; 
+
+    if (msgOffset == 0xFFFFFFFF)
+    {
+#ifdef DEBUG
+            kprintf("RCPostRecvBuffers(): Inbound Free Q empty!\n");
+#endif /* DEBUG */
+        return RC_RTN_FREE_Q_EMPTY;
+   
+    }
+     /* calc virual address of msg - virual already mapped to physical */    
+    pMsg = (PU32)(pPab->pPci45LinBaseAddr + msgOffset);
+
+    size = FillAdapterMsgSGLFromTCB(pMsg + 4, pTransCtrlBlock);
+
+    if (size == -1) /* error prcessing TCB - send 3 DWORD private msg == NOP */
+    {
+#ifdef DEBUG
+        kprintf("RCPostRecvBuffers(): Error Processing TCB! size = %d\n", size);
+#endif /* DEBUG */
+        pMsg[0] = THREE_WORD_MSG_SIZE | SGL_OFFSET_0;
+        pMsg[1] = UTIL_NOP << 24 | HOST_TID << 12 | LAN_TARGET_ID;
+         /* post to Post Q */   
+        pPab->p_atu->InQueue = msgOffset;
+        return RC_RTN_TCB_ERROR;
+    }
+    else /* send over size msg header */
+    {    
+        pMsg[0] = (size + 4) << 16 | LAN_MSG_REQST; /* send over message size and flags */
+        pMsg[1] = LAN_RECEIVE_POST << 24 | HOST_TID << 12 | LAN_TARGET_ID;
+        pMsg[2] = DEFAULT_RECV_INIT_CONTEXT;
+        pMsg[3] = *(PU32)pTransCtrlBlock; /* number of packet buffers */
+         /* post to Post Q */   
+        pPab->p_atu->InQueue = msgOffset;
+        return RC_RTN_NO_ERROR;
+    }
+}
+
+
+/*
+** =========================================================================
+** RCProcMsgQ()
+**
+** Process outbound message queue until empty.
+** =========================================================================
+*/
+void 
+RCProcMsgQ(U16 AdapterID)
+{
+    U32 phyAddrMsg;
+    PU8 p8Msg;
+    PU32 p32;
+    U16 count;
+    PPAB pPab;
+    unsigned char debug_msg[20];
+    
+    pPab = PCIAdapterBlock[AdapterID];
+    
+    if (pPab == NULL)
+        return;
+    
+    phyAddrMsg = pPab->p_atu->OutQueue;
+
+    while (phyAddrMsg != 0xFFFFFFFF)
+    {
+        p8Msg = pPab->pLinOutMsgBlock + (phyAddrMsg - pPab->outMsgBlockPhyAddr);
+        p32 = (PU32)p8Msg;
+        
+        //printk(" msg: 0x%x  0x%x \n", p8Msg[7], p32[5]);
+
+     /* 
+     ** Send Packet Reply Msg
+     */
+        if (LAN_PACKET_SEND == p8Msg[7])  /* function code byte */
+        {
+            count = *(PU16)(p8Msg+2);
+            count -= p8Msg[0] >> 4;
+                                      /* status, count, context[], adapter */
+           (*pPab->pTransCallbackFunc)(p8Msg[19], count, p32+5, AdapterID);
+        }             
+     /* 
+     ** Receive Packet Reply Msg */
+        else if (LAN_RECEIVE_POST == p8Msg[7])
+        {
+#ifdef DEBUG    
+    kprintf("RECV_REPLY pPab:0x%08.8ulx p8Msg:0x%08.8ulx p32:0x%08.8ulx\n", pPab, p8Msg, p32);
+    kprintf("msg: 0x%08.8ulx:0x%08.8ulx:0x%08.8ulx:0x%08.8ulx\n",
+            p32[0], p32[1], p32[2], p32[3]);
+    kprintf("     0x%08.8ulx:0x%08.8ulx:0x%08.8ulx:0x%08.8ulx\n",
+            p32[4], p32[5], p32[6], p32[7]);
+    kprintf("     0x%08.8ulx:0X%08.8ulx:0x%08.8ulx:0x%08.8ulx\n",
+            p32[8], p32[9], p32[10], p32[11]);
+#endif
+               /*  status, count, buckets remaining, packetParmBlock, adapter */
+          (*pPab->pRecvCallbackFunc)(p8Msg[19], p8Msg[12], p32[5], p32+6, AdapterID);
+      
+      
+        }
+        else if (LAN_RESET == p8Msg[7] || LAN_SHUTDOWN == p8Msg[7])
+        {
+            if (pPab->pCallbackFunc)
+            {
+                (*pPab->pCallbackFunc)(p8Msg[19],0,0,AdapterID);
+            }
+            else
+            {
+                pPab->pCallbackFunc = (PFNCALLBACK) 1;
+            }
+            //PCIAdapterBlock[AdapterID] = 0;
+        }
+        else if (RC_PRIVATE == p8Msg[7])
+        {
+            //printk("i2o private 0x%x, 0x%x \n", p8Msg[7], p32[5]);
+          switch (p32[5])
+          {
+          case RC_PRIVATE_DEBUG_MSG:
+               msgFlag = 1;
+               /*printk("Received RC_PRIVATE msg\n");*/
+               debug_msg[15]  = (p32[6]&0xff000000) >> 24;
+               debug_msg[14]  = (p32[6]&0x00ff0000) >> 16;
+               debug_msg[13]  = (p32[6]&0x0000ff00) >> 8;
+               debug_msg[12]  = (p32[6]&0x000000ff);
+
+               debug_msg[11]  = (p32[7]&0xff000000) >> 24;
+               debug_msg[10]  = (p32[7]&0x00ff0000) >> 16;
+               debug_msg[ 9]  = (p32[7]&0x0000ff00) >> 8;
+               debug_msg[ 8]  = (p32[7]&0x000000ff);
+
+               debug_msg[ 7]  = (p32[8]&0xff000000) >> 24;
+               debug_msg[ 6]  = (p32[8]&0x00ff0000) >> 16;
+               debug_msg[ 5] = (p32[8]&0x0000ff00) >> 8;
+               debug_msg[ 4] = (p32[8]&0x000000ff);
+
+               debug_msg[ 3] = (p32[9]&0xff000000) >> 24;
+               debug_msg[ 2] = (p32[9]&0x00ff0000) >> 16;
+               debug_msg[ 1] = (p32[9]&0x0000ff00) >> 8;
+               debug_msg[ 0] = (p32[9]&0x000000ff);
+
+               debug_msg[16] = '\0';
+               printk (debug_msg);
+               break;
+          case RC_PRIVATE_REBOOT:
+               printk("Adapter reboot initiated...\n");
+               if (pPab->pRebootCallbackFunc)
+               {
+                    (*pPab->pRebootCallbackFunc)(0,0,0,AdapterID);
+               }
+               break;
+          default:
+                printk("Unknown private msg received: 0x%x\n",
+                      p32[5]);
+               break;
+          }
+        }
+
+     /* 
+     ** Process other Msg's
+     */
+        else
+        {
+            ProcessOutboundAdapterMsg(pPab, phyAddrMsg);
+        }
+        
+         /* return MFA to outbound free Q*/
+        pPab->p_atu->OutQueue = phyAddrMsg;
+    
+         /* any more msgs? */
+        phyAddrMsg = pPab->p_atu->OutQueue;
+    }
+}
+
+
+/*
+** =========================================================================
+**  Returns LAN interface statistical counters to space provided by caller at
+**  StatsReturnAddr.  Returns 0 if success, else RC_RETURN code.
+**  This function will call the WaitCallback function provided by
+**  user while waiting for card to respond.
+** =========================================================================
+*/
+RC_RETURN
+RCGetLinkStatistics(U16 AdapterID, 
+                    P_RCLINKSTATS StatsReturnAddr,
+                    PFNWAITCALLBACK WaitCallback)
+{
+    U32 msgOffset;
+    volatile U32 timeout;
+    volatile PU32 pMsg;
+    volatile PU32 p32, pReturnAddr;
+    P_NICSTAT pStats;
+    int i;
+    PPAB pPab;
+
+/*kprintf("Get82558Stats() StatsReturnAddr:0x%08.8ulx\n", StatsReturnAddr);*/
+
+    pPab = PCIAdapterBlock[AdapterID];
+
+    if (pPab == NULL)
+        return RC_RTN_ADPTR_NOT_REGISTERED;
+    
+    msgOffset = pPab->p_atu->InQueue;
+
+    if (msgOffset == 0xFFFFFFFF)
+    {
+    #ifdef DEBUG
+        kprintf("Get8255XStats(): Inbound Free Q empty!\n");
+    #endif
+        return RC_RTN_FREE_Q_EMPTY;
+    }
+
+     /* calc virual address of msg - virual already mapped to physical */
+    pMsg = (PU32)(pPab->pPci45LinBaseAddr + msgOffset);
+
+/*dprintf("Get82558Stats - pMsg = 0x%08ulx, InQ msgOffset = 0x%08ulx\n", pMsg, msgOffset);*/
+/*dprintf("Get82558Stats - pMsg = 0x%08X, InQ msgOffset = 0x%08X\n", pMsg, msgOffset);*/
+
+    pMsg[0] = SIX_WORD_MSG_SIZE | SGL_OFFSET_0;
+    pMsg[1] = RC_PRIVATE << 24 | HOST_TID << 12 | LAN_TARGET_ID;
+    pMsg[2] = DEFAULT_RECV_INIT_CONTEXT;
+    pMsg[3] = 0x112; /* transaction context */
+    pMsg[4] = RC_PCI45_VENDOR_ID << 16 | RC_PRIVATE_GET_LAN_STATS;
+    pMsg[5] = pPab->outMsgBlockPhyAddr - ADAPTER_BLOCK_RESERVED_SPACE + sizeof(PAB); 
+
+    p32 = (PU32)(pPab->pLinOutMsgBlock - ADAPTER_BLOCK_RESERVED_SPACE + sizeof(PAB));
+
+    pStats = (P_NICSTAT)p32;
+    pStats->dump_status = 0xFFFFFFFF;
+
+     /* post to Inbound Post Q */
+    pPab->p_atu->InQueue = msgOffset;
+
+    timeout = 100000;
+    while (1)
+    {
+        if (WaitCallback)
+                (*WaitCallback)();
+        
+        for (i = 0; i < 1000; i++)
+            ;
+
+        if (pStats->dump_status != 0xFFFFFFFF)
+            break;
+
+        if (!timeout--)
+        {
+        #ifdef DEBUG
+            kprintf("RCGet82558Stats() Timeout waiting for NIC statistics\n");
+        #endif
+            return RC_RTN_MSG_REPLY_TIMEOUT;
+        }
+    }
+    
+    pReturnAddr = (PU32)StatsReturnAddr;
+    
+     /* copy Nic stats to user's structure */
+    for (i = 0; i < (int) sizeof(RCLINKSTATS) / 4; i++)
+        pReturnAddr[i] = p32[i];
+   
+    return RC_RTN_NO_ERROR;     
+}
+
+
+/*
+** =========================================================================
+** Get82558LinkStatus()
+** =========================================================================
+*/
+RC_RETURN
+RCGetLinkStatus(U16 AdapterID, PU32 ReturnAddr, PFNWAITCALLBACK WaitCallback)
+{
+    U32 msgOffset;
+    volatile U32 timeout;
+    volatile PU32 pMsg;
+    volatile PU32 p32;
+    PPAB pPab;
+
+/*kprintf("Get82558LinkStatus() ReturnPhysAddr:0x%08.8ulx\n", ReturnAddr);*/
+
+    pPab = PCIAdapterBlock[AdapterID];
+
+    if (pPab == NULL)
+        return RC_RTN_ADPTR_NOT_REGISTERED;
+    
+    msgOffset = pPab->p_atu->InQueue;
+
+    if (msgOffset == 0xFFFFFFFF)
+    {
+    #ifdef DEBUG
+        dprintf("Get82558LinkStatus(): Inbound Free Q empty!\n");
+    #endif
+        return RC_RTN_FREE_Q_EMPTY;
+    }
+
+     /* calc virual address of msg - virual already mapped to physical */
+    pMsg = (PU32)(pPab->pPci45LinBaseAddr + msgOffset);
+/*dprintf("Get82558LinkStatus - pMsg = 0x%08ulx, InQ msgOffset = 0x%08ulx\n", pMsg, msgOffset);*/
+/*dprintf("Get82558LinkStatus - pMsg = 0x%08X, InQ msgOffset = 0x%08X\n", pMsg, msgOffset);*/
+
+    pMsg[0] = SIX_WORD_MSG_SIZE | SGL_OFFSET_0;
+    pMsg[1] = RC_PRIVATE << 24 | HOST_TID << 12 | LAN_TARGET_ID;
+    pMsg[2] = DEFAULT_RECV_INIT_CONTEXT;
+    pMsg[3] = 0x112; /* transaction context */
+    pMsg[4] = RC_PCI45_VENDOR_ID << 16 | RC_PRIVATE_GET_LINK_STATUS;
+    pMsg[5] = pPab->outMsgBlockPhyAddr - ADAPTER_BLOCK_RESERVED_SPACE + sizeof(PAB); 
+
+    p32 = (PU32)(pPab->pLinOutMsgBlock - ADAPTER_BLOCK_RESERVED_SPACE + sizeof(PAB));
+    *p32 = 0xFFFFFFFF;
+    
+     /* post to Inbound Post Q */
+    pPab->p_atu->InQueue = msgOffset;
+
+    timeout = 100000;
+    while (1)
+    {
+        U32 i;
+
+        if (WaitCallback)
+                (*WaitCallback)();
+        
+        for (i = 0; i < 1000; i++)
+            ;
+
+        if (*p32 != 0xFFFFFFFF)
+            break;
+
+        if (!timeout--)
+        {
+        #ifdef DEBUG
+            kprintf("Timeout waiting for link status\n");
+        #endif    
+            return RC_RTN_MSG_REPLY_TIMEOUT;
+        }
+    }
+    
+    *ReturnAddr = *p32; /* 1 = up 0 = down */
+    
+    return RC_RTN_NO_ERROR;
+    
+}
+
+/*
+** =========================================================================
+** RCGetMAC()
+**
+** get the MAC address the adapter is listening for in non-promiscous mode.
+** MAC address is in media format.
+** =========================================================================
+*/
+RC_RETURN
+RCGetMAC(U16 AdapterID, PU8 mac, PFNWAITCALLBACK WaitCallback)
+{
+     unsigned i, timeout;
+     U32      off;
+     PU32     p;
+     U32      temp[2];
+     PPAB     pPab;
+     PATU     p_atu;
+    
+     pPab = PCIAdapterBlock[AdapterID];
+    
+     if (pPab == NULL)
+          return RC_RTN_ADPTR_NOT_REGISTERED;
+    
+     p_atu = pPab->p_atu;
+
+     p_atu->EtherMacLow = 0;     /* first zero return data */
+     p_atu->EtherMacHi = 0;
+    
+     off = p_atu->InQueue;   /* get addresss of message */
+ 
+     if (0xFFFFFFFF == off)
+          return RC_RTN_FREE_Q_EMPTY;
+
+     p = (PU32)(pPab->pPci45LinBaseAddr + off);
+
+#ifdef RCDEBUG
+     printk("RCGetMAC: p_atu 0x%08x, off 0x%08x, p 0x%08x\n", 
+            (uint)p_atu, (uint)off, (uint)p);
+#endif /* RCDEBUG */
+     /* setup private message */
+     p[0] = FIVE_WORD_MSG_SIZE | SGL_OFFSET_0;
+     p[1] = RC_PRIVATE << 24 | HOST_TID << 12 | LAN_TARGET_ID;
+     p[2] = 0;               /* initiator context */
+     p[3] = 0x218;           /* transaction context */
+     p[4] = RC_PCI45_VENDOR_ID << 16 | RC_PRIVATE_GET_MAC_ADDR;
+
+
+     p_atu->InQueue = off;   /* send it to the device */
+#ifdef RCDEBUG
+     printk("RCGetMAC: p_atu 0x%08x, off 0x%08x, p 0x%08x\n", 
+            (uint)p_atu, (uint)off, (uint)p);
+#endif /* RCDEBUG */
+
+     /* wait for the rcpci45 board to update the info */
+     timeout = 1000000;
+     while (0 == p_atu->EtherMacLow) 
+     {
+          if (WaitCallback)
+               (*WaitCallback)();
+    
+          for (i = 0; i < 1000; i++)
+               ;
+
+          if (!timeout--)
+          {
+               printk("rc_getmac: Timeout\n");
+               return RC_RTN_MSG_REPLY_TIMEOUT;
+          }
+     }
+    
+     /* read the mac address  */
+     temp[0] = p_atu->EtherMacLow;
+     temp[1] = p_atu->EtherMacHi;
+     memcpy((char *)mac, (char *)temp, 6);
+
+
+#ifdef RCDEBUG
+//    printk("rc_getmac: 0x%X\n", ptr);
+#endif /* RCDEBUG */
+
+     return RC_RTN_NO_ERROR;
+}
+
+ 
+/*
+** =========================================================================
+** RCSetMAC()
+**
+** set MAC address the adapter is listening for in non-promiscous mode.
+** MAC address is in media format.
+** =========================================================================
+*/
+RC_RETURN
+RCSetMAC(U16 AdapterID, PU8 mac)
+{
+    U32  off;
+    PU32 pMsg;
+    PPAB pPab;
+
+
+    pPab = PCIAdapterBlock[AdapterID];
+    
+    if (pPab == NULL)
+        return RC_RTN_ADPTR_NOT_REGISTERED;
+    
+    off = pPab->p_atu->InQueue; /* get addresss of message */
+    
+    if (0xFFFFFFFF == off)
+         return RC_RTN_FREE_Q_EMPTY;
+    
+    pMsg = (PU32)(pPab->pPci45LinBaseAddr + off);
+
+    /* setup private message */
+    pMsg[0] = SEVEN_WORD_MSG_SIZE | SGL_OFFSET_0;
+    pMsg[1] = RC_PRIVATE << 24 | HOST_TID << 12 | LAN_TARGET_ID;
+    pMsg[2] = 0;                 /* initiator context */
+    pMsg[3] = 0x219;             /* transaction context */
+    pMsg[4] = RC_PCI45_VENDOR_ID << 16 | RC_PRIVATE_SET_MAC_ADDR;
+    pMsg[5] = *(unsigned *)mac;  /* first four bytes */
+    pMsg[6] = *(unsigned *)(mac + 4); /* last two bytes */
+    
+    pPab->p_atu->InQueue = off;   /* send it to the device */
+
+    return RC_RTN_NO_ERROR ;
+}
+
+
+/*
+** =========================================================================
+** RCSetLinkSpeed()
+**
+** set ethernet link speed. 
+** input: speedControl - determines action to take as follows
+**          0 = reset and auto-negotiate (NWay)
+**          1 = Full Duplex 100BaseT
+**          2 = Half duplex 100BaseT
+**          3 = Full Duplex  10BaseT
+**          4 = Half duplex  10BaseT
+**          all other values are ignore (do nothing)
+** =========================================================================
+*/
+RC_RETURN
+RCSetLinkSpeed(U16 AdapterID, U16 LinkSpeedCode)
+{
+    U32  off;
+    PU32 pMsg;
+    PPAB pPab;
+
+    
+    pPab =PCIAdapterBlock[AdapterID];
+     
+    if (pPab == NULL)
+        return RC_RTN_ADPTR_NOT_REGISTERED;
+    
+    off = pPab->p_atu->InQueue; /* get addresss of message */
+    
+    if (0xFFFFFFFF == off)
+         return RC_RTN_FREE_Q_EMPTY;
+    
+    pMsg = (PU32)(pPab->pPci45LinBaseAddr + off);
+
+    /* setup private message */
+    pMsg[0] = SIX_WORD_MSG_SIZE | SGL_OFFSET_0;
+    pMsg[1] = RC_PRIVATE << 24 | HOST_TID << 12 | LAN_TARGET_ID;
+    pMsg[2] = 0;                 /* initiator context */
+    pMsg[3] = 0x219;             /* transaction context */
+    pMsg[4] = RC_PCI45_VENDOR_ID << 16 | RC_PRIVATE_SET_LINK_SPEED;
+    pMsg[5] = LinkSpeedCode;     /* link speed code */
+
+    pPab->p_atu->InQueue = off;   /* send it to the device */
+
+    return RC_RTN_NO_ERROR ;
+}
+
+/*
+** =========================================================================
+** RCGetLinkSpeed()
+**
+** get ethernet link speed. 
+**
+** 0 = Unknown
+** 1 = Full Duplex 100BaseT
+** 2 = Half duplex 100BaseT
+** 3 = Full Duplex  10BaseT
+** 4 = Half duplex  10BaseT
+**
+** =========================================================================
+*/
+RC_RETURN
+RCGetLinkSpeed(U16 AdapterID, PU32 pLinkSpeedCode, PFNWAITCALLBACK WaitCallback)
+{
+     U32 msgOffset, timeout;
+     PU32 pMsg;
+     volatile PU32 p32;
+     U8 AdapterLinkSpeed;
+     PPAB pPab;
+
+     pPab =PCIAdapterBlock[AdapterID];
+
+
+     msgOffset = pPab->p_atu->InQueue;
+
+
+     if (msgOffset == 0xFFFFFFFF)
+     {
+          kprintf("RCGetLinkSpeed(): Inbound Free Q empty!\n");
+          return RC_RTN_FREE_Q_EMPTY;
+     }
+
+     /* calc virtual address of msg - virtual already mapped to physical */    
+     pMsg = (PU32)(pPab->pPci45LinBaseAddr + msgOffset);
+
+     /* virtual pointer to return buffer - clear first two dwords */
+     p32 = (volatile PU32)(pPab->pLinOutMsgBlock - ADAPTER_BLOCK_RESERVED_SPACE + sizeof(PAB));
+     p32[0] = 0xff;
+
+     /* setup private message */
+     pMsg[0] = SIX_WORD_MSG_SIZE | SGL_OFFSET_0;
+     pMsg[1] = RC_PRIVATE << 24 | HOST_TID << 12 | LAN_TARGET_ID;
+     pMsg[2] = 0;                 /* initiator context */
+     pMsg[3] = 0x219;             /* transaction context */
+     pMsg[4] = RC_PCI45_VENDOR_ID << 16 | RC_PRIVATE_GET_LINK_SPEED;
+     /* phys address to return status - area right after PAB */
+     pMsg[5] = pPab->outMsgBlockPhyAddr - ADAPTER_BLOCK_RESERVED_SPACE + sizeof(PAB); 
+   
+     /* post to Inbound Post Q */   
+
+     pPab->p_atu->InQueue = msgOffset;
+
+     /* wait for response */
+     timeout = 1000000;
+     while(1)
+     {
+          int i;
+        
+          if (WaitCallback)
+                (*WaitCallback)();
+
+          for (i = 0; i < 1000; i++)      /* please don't hog the bus!!! */
+               ;
+            
+          if (p32[0] != 0xff)
+               break;
+            
+          if (!timeout--)
+          {
+               kprintf("Timeout waiting for link speed from adapter\n");
+               kprintf("0x%08.8ulx\n", p32[0]);
+               return RC_RTN_NO_LINK_SPEED;
+          }
+     }
+
+     /* get Link speed */
+     AdapterLinkSpeed = (U8)((volatile PU8)p32)[0] & 0x0f;
+
+     *pLinkSpeedCode= AdapterLinkSpeed;
+
+     return RC_RTN_NO_ERROR;
+}
+
+/*
+** =========================================================================
+** RCReportDriverCapability(U16 AdapterID, U32 capability)
+**
+** Currently defined bits:
+** WARM_REBOOT_CAPABLE   0x01
+**
+** =========================================================================
+*/
+RC_RETURN
+RCReportDriverCapability(U16 AdapterID, U32 capability)
+{
+    U32  off;
+    PU32 pMsg;
+    PPAB pPab;
+
+    pPab =PCIAdapterBlock[AdapterID];
+     
+    if (pPab == NULL)
+        return RC_RTN_ADPTR_NOT_REGISTERED;
+    
+    off = pPab->p_atu->InQueue; /* get addresss of message */
+    
+    if (0xFFFFFFFF == off)
+         return RC_RTN_FREE_Q_EMPTY;
+    
+    pMsg = (PU32)(pPab->pPci45LinBaseAddr + off);
+
+    /* setup private message */
+    pMsg[0] = SIX_WORD_MSG_SIZE | SGL_OFFSET_0;
+    pMsg[1] = RC_PRIVATE << 24 | HOST_TID << 12 | LAN_TARGET_ID;
+    pMsg[2] = 0;                 /* initiator context */
+    pMsg[3] = 0x219;             /* transaction context */
+    pMsg[4] = RC_PCI45_VENDOR_ID << 16 | RC_PRIVATE_REPORT_DRIVER_CAPABILITY;
+    pMsg[5] = capability;
+
+    pPab->p_atu->InQueue = off;   /* send it to the device */
+
+    return RC_RTN_NO_ERROR ;
+}
+
+/*
+** =========================================================================
+** RCGetFirmwareVer()
+**
+** Return firmware version in the form "SoftwareVersion : Bt BootVersion"
+**
+** =========================================================================
+*/
+RC_RETURN
+RCGetFirmwareVer(U16 AdapterID, PU8 pFirmString, PFNWAITCALLBACK WaitCallback)
+{
+     U32 msgOffset, timeout;
+     PU32 pMsg;
+     volatile PU32 p32;
+     PPAB pPab;
+
+     pPab =PCIAdapterBlock[AdapterID];
+
+     msgOffset = pPab->p_atu->InQueue;
+
+
+     if (msgOffset == 0xFFFFFFFF)
+     {
+          kprintf("RCGetFirmwareVer(): Inbound Free Q empty!\n");
+          return RC_RTN_FREE_Q_EMPTY;
+     }
+
+     /* calc virtual address of msg - virtual already mapped to physical */    
+     pMsg = (PU32)(pPab->pPci45LinBaseAddr + msgOffset);
+
+     /* virtual pointer to return buffer - clear first two dwords */
+     p32 = (volatile PU32)(pPab->pLinOutMsgBlock - ADAPTER_BLOCK_RESERVED_SPACE + sizeof(PAB));
+     p32[0] = 0xff;
+
+     /* setup private message */
+     pMsg[0] = SIX_WORD_MSG_SIZE | SGL_OFFSET_0;
+     pMsg[1] = RC_PRIVATE << 24 | HOST_TID << 12 | LAN_TARGET_ID;
+     pMsg[2] = 0;                 /* initiator context */
+     pMsg[3] = 0x219;             /* transaction context */
+     pMsg[4] = RC_PCI45_VENDOR_ID << 16 | RC_PRIVATE_GET_FIRMWARE_REV;
+     /* phys address to return status - area right after PAB */
+     pMsg[5] = pPab->outMsgBlockPhyAddr - ADAPTER_BLOCK_RESERVED_SPACE + sizeof(PAB); 
+
+
+   
+     /* post to Inbound Post Q */   
+
+     pPab->p_atu->InQueue = msgOffset;
+
+    
+     /* wait for response */
+     timeout = 1000000;
+     while(1)
+     {
+          int i;
+        
+          if (WaitCallback)
+                (*WaitCallback)();
+            
+          for (i = 0; i < 1000; i++)      /* please don't hog the bus!!! */
+               ;
+
+          if (p32[0] != 0xff)
+               break;
+            
+          if (!timeout--)
+          {
+               kprintf("Timeout waiting for link speed from adapter\n");
+               return RC_RTN_NO_FIRM_VER;
+          }
+     }
+
+     strcpy(pFirmString, (PU8)p32);
+     return RC_RTN_NO_ERROR;
+}
+
+/*
+** =========================================================================
+** RCResetLANCard()
+**
+** ResourceFlags indicates whether to return buffer resource explicitly
+** to host or keep and reuse.
+** CallbackFunction (if not NULL) is the function to be called when 
+** reset is complete.
+** If CallbackFunction is NULL, ReturnAddr will have a 1 placed in it when
+** reset is done (if not NULL).
+**
+** =========================================================================
+*/
+RC_RETURN 
+RCResetLANCard(U16 AdapterID, U16 ResourceFlags, PU32 ReturnAddr, PFNCALLBACK CallbackFunction)
+{
+    unsigned long off;
+    unsigned long *pMsg;
+    PPAB pPab;
+    int i;
+    long timeout = 0;
+
+    
+    pPab =PCIAdapterBlock[AdapterID];
+     
+    if (pPab == NULL)
+        return RC_RTN_ADPTR_NOT_REGISTERED;
+
+    off = pPab->p_atu->InQueue; /* get addresss of message */
+    
+    if (0xFFFFFFFF == off)
+         return RC_RTN_FREE_Q_EMPTY;
+    
+    pPab->pCallbackFunc = CallbackFunction;
+
+    pMsg = (PU32)(pPab->pPci45LinBaseAddr + off);
+
+    /* setup message */
+    pMsg[0] = FOUR_WORD_MSG_SIZE | SGL_OFFSET_0;
+    pMsg[1] = LAN_RESET << 24 | HOST_TID << 12 | LAN_TARGET_ID;
+    pMsg[2] = DEFAULT_RECV_INIT_CONTEXT;
+    pMsg[3] = ResourceFlags << 16;   /* resource flags */
+
+    pPab->p_atu->InQueue = off;   /* send it to the device */
+
+    if (CallbackFunction == (PFNCALLBACK)NULL)
+    {
+        /* call RCProcMsgQ() until something in pPab->pCallbackFunc
+           or until timer goes off */
+        while (pPab->pCallbackFunc == (PFNCALLBACK)NULL)
+        {
+            RCProcMsgQ(AdapterID);
+            for (i = 0; i < 100000; i++)     /* please don't hog the bus!!! */
+               ;
+            timeout++;
+            if (timeout > 10000)
+            {
+                break;
+            }
+        }
+        if (ReturnAddr != (PU32)NULL)
+           *ReturnAddr = (U32)pPab->pCallbackFunc;
+    }
+
+    return RC_RTN_NO_ERROR ;
+}
+/*
+** =========================================================================
+** RCResetAdapter()
+**
+** Send StatusGet Msg, wait for results return directly to buffer.
+**
+** =========================================================================
+*/
+RC_RETURN 
+RCResetAdapter(U16 AdapterID)
+{
+     U32 msgOffset, timeout;
+     PU32 pMsg;
+     PPAB pPab;
+     volatile PU32 p32;
+    
+     pPab = PCIAdapterBlock[AdapterID];
+     msgOffset = pPab->p_atu->InQueue;
+
+     if (msgOffset == 0xFFFFFFFF)
+     {
+          return RC_RTN_FREE_Q_EMPTY;
+     }
+
+     /* calc virtual address of msg - virtual already mapped to physical */    
+     pMsg = (PU32)(pPab->pPci45LinBaseAddr + msgOffset);
+
+     pMsg[0] = NINE_WORD_MSG_SIZE | SGL_OFFSET_0;
+     pMsg[1] = RC_CMD_ADAPTER_RESET << 24 | HOST_TID << 12 | ADAPTER_TID;
+     pMsg[2] = 0; /* universal context */
+     pMsg[3] = 0; /* universal context */
+     pMsg[4] = 0; /* universal context */
+     pMsg[5] = 0; /* universal context */
+     /* phys address to return status - area right after PAB */
+     pMsg[6] = pPab->outMsgBlockPhyAddr - ADAPTER_BLOCK_RESERVED_SPACE + sizeof(PAB); 
+     pMsg[7] = 0;
+     pMsg[8] = 1;  /*  return 1 byte */
+
+     /* virual pointer to return buffer - clear first two dwords */
+     p32 = (volatile PU32)(pPab->pLinOutMsgBlock - ADAPTER_BLOCK_RESERVED_SPACE + sizeof(PAB));
+     p32[0] = 0;
+     p32[1] = 0;
+
+     /* post to Inbound Post Q */   
+
+     pPab->p_atu->InQueue = msgOffset;
+
+     /* wait for response */
+     timeout = 1000000;
+     while(1)
+     {
+          int i;
+        
+          for (i = 0; i < 1000; i++)      /* please don't hog the bus!!! */
+               ;
+            
+          if (p32[0] || p32[1])
+               break;
+            
+          if (!timeout--)
+          {
+               printk("RCResetAdapter timeout\n");
+               return RC_RTN_MSG_REPLY_TIMEOUT;
+          }
+     }
+     return RC_RTN_NO_ERROR;
+}
+
+/*
+** =========================================================================
+** RCShutdownLANCard()
+**
+** ResourceFlags indicates whether to return buffer resource explicitly
+** to host or keep and reuse.
+** CallbackFunction (if not NULL) is the function to be called when 
+** shutdown is complete.
+** If CallbackFunction is NULL, ReturnAddr will have a 1 placed in it when
+** shutdown is done (if not NULL).
+**
+** =========================================================================
+*/
+RC_RETURN 
+RCShutdownLANCard(U16 AdapterID, U16 ResourceFlags, PU32 ReturnAddr, PFNCALLBACK CallbackFunction)
+{
+    volatile PU32 pMsg;
+    U32 off;
+    PPAB pPab;
+    int i;
+    long timeout = 0;
+
+    pPab = PCIAdapterBlock[AdapterID];
+
+    if (pPab == NULL)
+        return RC_RTN_ADPTR_NOT_REGISTERED;
+
+    off = pPab->p_atu->InQueue; /* get addresss of message */
+    
+    if (0xFFFFFFFF == off)
+         return RC_RTN_FREE_Q_EMPTY;
+
+    pPab->pCallbackFunc = CallbackFunction;
+    
+    pMsg = (PU32)(pPab->pPci45LinBaseAddr + off);
+
+    /* setup message */
+    pMsg[0] = FOUR_WORD_MSG_SIZE | SGL_OFFSET_0;
+    pMsg[1] = LAN_SHUTDOWN << 24 | HOST_TID << 12 | LAN_TARGET_ID;
+    pMsg[2] = DEFAULT_RECV_INIT_CONTEXT;
+    pMsg[3] = ResourceFlags << 16;   /* resource flags */
+
+    pPab->p_atu->InQueue = off;   /* send it to the device */
+
+    if (CallbackFunction == (PFNCALLBACK)NULL)
+    {
+        /* call RCProcMsgQ() until something in pPab->pCallbackFunc
+           or until timer goes off */
+        while (pPab->pCallbackFunc == (PFNCALLBACK)NULL)
+        {
+            RCProcMsgQ(AdapterID);
+            for (i = 0; i < 100000; i++)     /* please don't hog the bus!!! */
+               ;
+            timeout++;
+            if (timeout > 10000)
+            {
+                break;
+            }
+        }
+        if (ReturnAddr != (PU32)NULL)
+           *ReturnAddr = (U32)pPab->pCallbackFunc;
+    }
+    return RC_RTN_NO_ERROR ;
+}
+
+
+/*
+** =========================================================================
+** RCSetRavlinIPandMask()
+**
+** Set the Ravlin 45/PCI cards IP address and network mask.
+**
+** IP address and mask must be in network byte order.
+** For example, IP address 1.2.3.4 and mask 255.255.255.0 would be
+** 0x04030201 and 0x00FFFFFF on a little endian machine.
+**
+** =========================================================================
+*/
+RC_RETURN
+RCSetRavlinIPandMask(U16 AdapterID, U32 ipAddr, U32 netMask)
+{
+    volatile PU32 pMsg;
+    U32 off;
+    PPAB pPab;
+
+    pPab = PCIAdapterBlock[AdapterID];
+
+    if (pPab == NULL)
+        return RC_RTN_ADPTR_NOT_REGISTERED;
+
+    off = pPab->p_atu->InQueue; /* get addresss of message */
+    
+    if (0xFFFFFFFF == off)
+         return RC_RTN_FREE_Q_EMPTY;
+    
+    pMsg = (PU32)(pPab->pPci45LinBaseAddr + off);
+
+    /* setup private message */
+    pMsg[0] = SEVEN_WORD_MSG_SIZE | SGL_OFFSET_0;
+    pMsg[1] = RC_PRIVATE << 24 | HOST_TID << 12 | LAN_TARGET_ID;
+    pMsg[2] = 0;                 /* initiator context */
+    pMsg[3] = 0x219;             /* transaction context */
+    pMsg[4] = RC_PCI45_VENDOR_ID << 16 | RC_PRIVATE_SET_IP_AND_MASK;
+    pMsg[5] = ipAddr; 
+    pMsg[6] = netMask;
+
+
+    pPab->p_atu->InQueue = off;   /* send it to the device */
+    return RC_RTN_NO_ERROR ;
+
+}
+
+/*
+** =========================================================================
+** RCGetRavlinIPandMask()
+**
+** get the IP address and MASK from the card
+** 
+** =========================================================================
+*/
+RC_RETURN
+RCGetRavlinIPandMask(U16 AdapterID, PU32 pIpAddr, PU32 pNetMask, 
+                        PFNWAITCALLBACK WaitCallback)
+{
+    unsigned i, timeout;
+    U32      off;
+    PU32     pMsg, p32;
+    PPAB     pPab;
+    PATU     p_atu;
+    
+#ifdef DEBUG
+    kprintf("RCGetRavlinIPandMask: pIpAddr is 0x%08.8ulx, *IpAddr is 0x%08.8ulx\n", pIpAddr, *pIpAddr);
+#endif /* DEBUG */
+
+    pPab = PCIAdapterBlock[AdapterID];
+    
+    if (pPab == NULL)
+        return RC_RTN_ADPTR_NOT_REGISTERED;
+    
+    p_atu = pPab->p_atu;
+    off = p_atu->InQueue;   /* get addresss of message */
+ 
+   if (0xFFFFFFFF == off)
+         return RC_RTN_FREE_Q_EMPTY;
+
+    p32 = (volatile PU32)(pPab->pLinOutMsgBlock - ADAPTER_BLOCK_RESERVED_SPACE + sizeof(PAB));
+    *p32 = 0xFFFFFFFF;
+
+    pMsg = (PU32)(pPab->pPci45LinBaseAddr + off);
+
+#ifdef DEBUG
+    kprintf("RCGetRavlinIPandMask: p_atu 0x%08.8ulx, off 0x%08.8ulx, p32 0x%08.8ulx\n", p_atu, off, p32);
+#endif /* DEBUG */
+    /* setup private message */
+    pMsg[0] = FIVE_WORD_MSG_SIZE | SGL_OFFSET_0;
+    pMsg[1] = RC_PRIVATE << 24 | HOST_TID << 12 | LAN_TARGET_ID;
+    pMsg[2] = 0;               /* initiator context */
+    pMsg[3] = 0x218;           /* transaction context */
+    pMsg[4] = RC_PCI45_VENDOR_ID << 16 | RC_PRIVATE_GET_IP_AND_MASK;
+    pMsg[5] = pPab->outMsgBlockPhyAddr - ADAPTER_BLOCK_RESERVED_SPACE + sizeof(PAB); 
+
+    p_atu->InQueue = off;   /* send it to the device */
+#ifdef DEBUG
+    kprintf("RCGetRavlinIPandMask: p_atu 0x%08.8ulx, off 0x%08.8ulx, p32 0x%08.8ulx\n", p_atu, off, p32);
+#endif /* DEBUG */
+
+     /* wait for the rcpci45 board to update the info */
+    timeout = 100000;
+    while (0xffffffff == *p32)
+    {
+        if (WaitCallback)
+                (*WaitCallback)();
+    
+        for (i = 0; i < 1000; i++)
+            ;
+
+        if (!timeout--)
+        {
+        #ifdef DEBUG
+            kprintf("RCGetRavlinIPandMask: Timeout\n");
+        #endif /* DEBUG */
+             return RC_RTN_MSG_REPLY_TIMEOUT;
+        }
+    }
+
+#ifdef DEBUG
+    kprintf("RCGetRavlinIPandMask: after time out\n", \
+            "p32[0] (IpAddr) 0x%08.8ulx, p32[1] (IPmask) 0x%08.8ulx\n", p32[0], p32[1]);
+#endif /* DEBUG */
+    
+    /* send IP and mask to user's space  */
+    *pIpAddr  = p32[0];
+    *pNetMask = p32[1];
+
+
+#ifdef DEBUG
+    kprintf("RCGetRavlinIPandMask: pIpAddr is 0x%08.8ulx, *IpAddr is 0x%08.8ulx\n", pIpAddr, *pIpAddr);
+#endif /* DEBUG */
+
+    return RC_RTN_NO_ERROR;
+}
+
+/* 
+** /////////////////////////////////////////////////////////////////////////
+** /////////////////////////////////////////////////////////////////////////
+**
+**                        local functions
+**
+** /////////////////////////////////////////////////////////////////////////
+** /////////////////////////////////////////////////////////////////////////
+*/
+
+/*
+** =========================================================================
+** SendAdapterOutboundQInitMsg()
+**
+** =========================================================================
+*/
+static int 
+SendAdapterOutboundQInitMsg(PPAB pPab)
+{
+    U32 msgOffset, timeout, phyOutQFrames, i;
+    volatile PU32 pMsg;
+    volatile PU32 p32;
+    
+    
+    
+    msgOffset = pPab->p_atu->InQueue;
+
+    
+    if (msgOffset == 0xFFFFFFFF)
+    {
+#ifdef DEBUG
+        kprintf("SendAdapterOutboundQInitMsg(): Inbound Free Q empty!\n");
+#endif /* DEBUG */
+        return RC_RTN_FREE_Q_EMPTY;
+    }
+    
+    
+     /* calc virual address of msg - virual already mapped to physical */    
+    pMsg = (PU32)(pPab->pPci45LinBaseAddr + msgOffset);
+
+#ifdef DEBUG
+kprintf("SendAdapterOutboundQInitMsg - pMsg = 0x%08.8ulx, InQ msgOffset = 0x%08.8ulx\n", pMsg, msgOffset);
+#endif /* DEBUG */
+
+    pMsg[0] = EIGHT_WORD_MSG_SIZE | TRL_OFFSET_6;
+    pMsg[1] = RC_CMD_OUTBOUND_INIT << 24 | HOST_TID << 12 | ADAPTER_TID;
+    pMsg[2] = DEFAULT_RECV_INIT_CONTEXT;
+    pMsg[3] = 0x106; /* transaction context */
+    pMsg[4] = 4096; /* Host page frame size */
+    pMsg[5] = MSG_FRAME_SIZE  << 16 | 0x80; /* outbound msg frame size and Initcode */
+    pMsg[6] = 0xD0000004;       /* simple sgl element LE, EOB */
+     /* phys address to return status - area right after PAB */
+    pMsg[7] = pPab->outMsgBlockPhyAddr - ADAPTER_BLOCK_RESERVED_SPACE + sizeof(PAB); 
+
+     /* virual pointer to return buffer - clear first two dwords */
+    p32 = (PU32)(pPab->pLinOutMsgBlock - ADAPTER_BLOCK_RESERVED_SPACE + sizeof(PAB));
+    p32[0] = 0;
+    
+     /* post to Inbound Post Q */   
+    pPab->p_atu->InQueue = msgOffset;
+    
+  /* wait for response */
+    timeout = 100000;
+    while(1)
+    {
+        for (i = 0; i < 1000; i++)      /* please don't hog the bus!!! */
+            ;
+            
+        if (p32[0])
+            break;
+            
+        if (!timeout--)
+        {
+#ifdef DEBUG
+            kprintf("Timeout wait for InitOutQ InPrgress status from adapter\n");
+#endif /* DEBUG */
+            return RC_RTN_NO_STATUS;
+        }
+    }
+
+    timeout = 100000;
+    while(1)
+    {
+        for (i = 0; i < 1000; i++)      /* please don't hog the bus!!! */
+            ;
+            
+        if (p32[0] == RC_CMD_OUTBOUND_INIT_COMPLETE)
+            break;
+
+        if (!timeout--)
+        {
+#ifdef DEBUG
+            kprintf("Timeout wait for InitOutQ Complete status from adapter\n");
+#endif /* DEBUG */
+            return RC_RTN_NO_STATUS;
+        }
+    }
+
+     /* load PCI outbound free Q with MF physical addresses */
+    phyOutQFrames = pPab->outMsgBlockPhyAddr;
+
+    for (i = 0; i < NMBR_MSG_FRAMES; i++)
+    {
+        pPab->p_atu->OutQueue = phyOutQFrames;
+        phyOutQFrames += MSG_FRAME_SIZE;
+    }
+    return RC_RTN_NO_ERROR;
+}
+
+
+/*
+** =========================================================================
+** GetAdapterStatus()
+**
+** Send StatusGet Msg, wait for results return directly to buffer.
+**
+** =========================================================================
+*/
+static int 
+GetAdapterStatus(PPAB pPab)
+{
+    U32 msgOffset, timeout;
+    PU32 pMsg;
+    volatile PU32 p32;
+    
+    
+    msgOffset = pPab->p_atu->InQueue; 
+    printk("GetAdapterStatus: msg offset = 0x%x\n", msgOffset);
+    if (msgOffset == 0xFFFFFFFF)
+    {
+#ifdef DEBUG
+        kprintf("GetAdapterStatus(): Inbound Free Q empty!\n");
+#endif /* DEBUG */
+        return RC_RTN_FREE_Q_EMPTY;
+    }
+
+     /* calc virual address of msg - virual already mapped to physical */    
+    pMsg = (PU32)(pPab->pPci45LinBaseAddr + msgOffset);
+
+    pMsg[0] = NINE_WORD_MSG_SIZE | SGL_OFFSET_0;
+    pMsg[1] = RC_CMD_STATUS_GET << 24 | HOST_TID << 12 | ADAPTER_TID;
+    pMsg[2] = 0; /* universal context */
+    pMsg[3] = 0; /* universal context */
+    pMsg[4] = 0; /* universal context */
+    pMsg[5] = 0; /* universal context */
+     /* phys address to return status - area right after PAB */
+    pMsg[6] = pPab->outMsgBlockPhyAddr - ADAPTER_BLOCK_RESERVED_SPACE + sizeof(PAB); 
+    pMsg[7] = 0;
+    pMsg[8] = 88;  /*  return 88 bytes */
+
+     /* virual pointer to return buffer - clear first two dwords */
+    p32 = (volatile PU32)(pPab->pLinOutMsgBlock - ADAPTER_BLOCK_RESERVED_SPACE + sizeof(PAB));
+    p32[0] = 0;
+    p32[1] = 0;
+
+#ifdef DEBUG
+kprintf("GetAdapterStatus - pMsg:0x%08.8ulx, msgOffset:0x%08.8ulx, [1]:0x%08.8ulx, [6]:0x%08.8ulx\n",
+    pMsg, msgOffset, pMsg[1], pMsg[6]);
+#endif /* DEBUG */
+   
+     /* post to Inbound Post Q */   
+    pPab->p_atu->InQueue = msgOffset;
+    
+#ifdef DEBUG
+kprintf("Return status to p32 = 0x%08.8ulx\n", p32);
+#endif /* DEBUG */
+    
+     /* wait for response */
+    timeout = 1000000;
+    while(1)
+    {
+        int i;
+        
+        for (i = 0; i < 1000; i++)      /* please don't hog the bus!!! */
+            ;
+            
+        if (p32[0] && p32[1])
+            break;
+            
+        if (!timeout--)
+        {
+#ifdef DEBUG
+            kprintf("Timeout waiting for status from adapter\n");
+kprintf("0x%08.8ulx:0x%08.8ulx:0x%08.8ulx:0x%08.8ulx\n", p32[0], p32[1], p32[2], p32[3]);
+kprintf("0x%08.8ulx:0x%08.8ulx:0x%08.8ulx:0x%08.8ulx\n", p32[4], p32[5], p32[6], p32[7]);
+kprintf("0x%08.8ulx:0x%08.8ulx:0x%08.8ulx:0x%08.8ulx\n", p32[8], p32[9], p32[10], p32[11]);
+#endif /* DEBUG */
+            return RC_RTN_NO_STATUS;
+        }
+    }
+            
+#ifdef DEBUG
+kprintf("0x%08.8ulx:0x%08.8ulx:0x%08.8ulx:0x%08.8ulx\n", p32[0], p32[1], p32[2], p32[3]);
+kprintf("0x%08.8ulx:0x%08.8ulx:0x%08.8ulx:0x%08.8ulx\n", p32[4], p32[5], p32[6], p32[7]);
+kprintf("0x%08.8ulx:0x%08.8ulx:0x%08.8ulx:0x%08.8ulx\n", p32[8], p32[9], p32[10], p32[11]);
+#endif /* DEBUG */
+    /* get adapter state */
+    pPab->ADAPTERState = ((volatile PU8)p32)[10];
+    pPab->InboundMFrameSize  = ((volatile PU16)p32)[6];
+    
+#ifdef DEBUG
+    kprintf("adapter state 0x%02.2x InFrameSize = 0x%04.4x\n", 
+                        pPab->ADAPTERState, pPab->InboundMFrameSize);
+#endif /* DEBUG */
+    return RC_RTN_NO_ERROR;
+}
+
+
+/*
+** =========================================================================
+** SendEnableSysMsg()
+**
+**
+** =========================================================================
+*/
+static int 
+SendEnableSysMsg(PPAB pPab)
+{
+    U32 msgOffset; // timeout;
+    volatile PU32 pMsg;
+
+    msgOffset = pPab->p_atu->InQueue;
+
+    if (msgOffset == 0xFFFFFFFF)
+    {
+#ifdef DEBUG
+        kprintf("SendEnableSysMsg(): Inbound Free Q empty!\n");
+#endif /* DEBUG */
+        return RC_RTN_FREE_Q_EMPTY;
+    }
+
+     /* calc virual address of msg - virual already mapped to physical */
+    pMsg = (PU32)(pPab->pPci45LinBaseAddr + msgOffset);
+
+#ifdef DEBUG
+kprintf("SendEnableSysMsg - pMsg = 0x%08.8ulx, InQ msgOffset = 0x%08.8ulx\n", pMsg, msgOffset);
+#endif /* DEBUG */
+
+    pMsg[0] = FOUR_WORD_MSG_SIZE | SGL_OFFSET_0;
+    pMsg[1] = RC_CMD_SYS_ENABLE << 24 | HOST_TID << 12 | ADAPTER_TID;
+    pMsg[2] = DEFAULT_RECV_INIT_CONTEXT;
+    pMsg[3] = 0x110; /* transaction context */
+    pMsg[4] = 0x50657465; /*  RedCreek Private */
+
+     /* post to Inbound Post Q */
+    pPab->p_atu->InQueue = msgOffset;
+
+    return RC_RTN_NO_ERROR;
+}
+
+
+/*
+** =========================================================================
+** FillI12OMsgFromTCB()
+**
+** inputs   pMsgU32 - virual pointer (mapped to physical) of message frame
+**          pXmitCntrlBlock - pointer to caller buffer control block.
+**
+** fills in LAN SGL after Transaction Control Word or Bucket Count.
+** =========================================================================
+*/
+static int 
+FillAdapterMsgSGLFromTCB(PU32 pMsgFrame, PRCTCB pTransCtrlBlock)
+{
+    unsigned int nmbrBuffers, nmbrSeg, nmbrDwords, context, flags;
+    PU32 pTCB, pMsg;
+
+ /* SGL element flags */   
+#define EOB        0x40000000
+#define LE         0x80000000
+#define SIMPLE_SGL 0x10000000
+#define BC_PRESENT 0x01000000
+
+    pTCB = (PU32)pTransCtrlBlock;
+    pMsg = pMsgFrame;
+    nmbrDwords = 0;
+
+#ifdef DEBUG
+ kprintf("FillAdapterMsgSGLFromTCBX\n");
+kprintf("TCB  0x%08.8ulx:0x%08.8ulx:0x%08.8ulx:0x%08.8ulx:0x%08.8ulx\n",
+               pTCB[0], pTCB[1], pTCB[2], pTCB[3], pTCB[4]);
+kprintf("pTCB 0x%08.8ulx, pMsg 0x%08.8ulx\n", pTCB, pMsg);
+#endif /* DEBUG */
+    
+    nmbrBuffers = *pTCB++;
+    
+    if (!nmbrBuffers)
+    {
+        return -1;
+    }
+
+    do
+    {
+        context = *pTCB++; /* buffer tag (context) */
+        nmbrSeg = *pTCB++; /* number of segments */
+
+        if (!nmbrSeg)
+        {
+            return -1;
+        }
+        
+        flags = SIMPLE_SGL | BC_PRESENT;
+
+        if (1 == nmbrSeg)
+        {
+            flags |= EOB;
+        
+            if (1 == nmbrBuffers)
+                flags |= LE;
+        }    
+
+         /* 1st SGL buffer element has context */
+        pMsg[0] = pTCB[0] | flags ; /* send over count (segment size) */
+        pMsg[1] = context;
+        pMsg[2] = pTCB[1]; /* send buffer segment physical address */
+        nmbrDwords += 3;
+        pMsg += 3;
+        pTCB += 2;
+
+        
+        if (--nmbrSeg)
+        {
+            do
+            {
+                flags = SIMPLE_SGL;
+                
+                if (1 == nmbrSeg)
+                {
+                    flags |= EOB;
+                
+                    if (1 == nmbrBuffers)
+                        flags |= LE;
+                }    
+                
+                pMsg[0] = pTCB[0] | flags;  /* send over count */
+                pMsg[1] = pTCB[1];   /* send buffer segment physical address */
+                nmbrDwords += 2;
+                pTCB += 2;
+                pMsg += 2;
+        
+            } while (--nmbrSeg);
+        }
+        
+    } while (--nmbrBuffers);
+    
+    return nmbrDwords;
+}
+
+
+/*
+** =========================================================================
+** ProcessOutboundAdapterMsg()
+**
+** process reply message
+** * change to msg structure *
+** =========================================================================
+*/
+static void 
+ProcessOutboundAdapterMsg(PPAB pPab, U32 phyAddrMsg)
+{
+    PU8 p8Msg;
+    PU32 p32;
+  //  U16 count;
+    
+    
+    p8Msg = pPab->pLinOutMsgBlock + (phyAddrMsg - pPab->outMsgBlockPhyAddr);
+    p32 = (PU32)p8Msg;
+    
+#ifdef DEBUG
+ kprintf("VXD: ProcessOutboundAdapterMsg - pPab 0x%08.8ulx, phyAdr 0x%08.8ulx, linAdr 0x%08.8ulx\n", pPab, phyAddrMsg, p8Msg);
+ kprintf("msg :0x%08.8ulx:0x%08.8ulx:0x%08.8ulx:0x%08.8ulx\n", p32[0], p32[1], p32[2], p32[3]);
+ kprintf("msg :0x%08.8ulx:0x%08.8ulx:0x%08.8ulx:0x%08.8ulx\n", p32[4], p32[5], p32[6], p32[7]);
+#endif /* DEBUG */
+
+    if (p32[4] >> 24 != RC_REPLY_STATUS_SUCCESS)
+    {
+#ifdef DEBUG
+        kprintf("Message reply status not success\n");
+#endif /* DEBUG */
+        return;
+    }
+    
+    switch (p8Msg[7] )  /* function code byte */
+    {
+        case RC_CMD_SYS_TAB_SET:
+            msgFlag = 1;
+#ifdef DEBUG
+        kprintf("Received RC_CMD_SYS_TAB_SET reply\n");
+#endif /* DEBUG */
+            break;
+
+        case RC_CMD_HRT_GET:
+            msgFlag = 1;
+#ifdef DEBUG
+        kprintf("Received RC_CMD_HRT_GET reply\n");
+#endif /* DEBUG */
+            break;
+        
+        case RC_CMD_LCT_NOTIFY:
+            msgFlag = 1;
+#ifdef DEBUG
+        kprintf("Received RC_CMD_LCT_NOTIFY reply\n");
+#endif /* DEBUG */
+            break;
+        
+        case RC_CMD_SYS_ENABLE:
+            msgFlag = 1;
+#ifdef DEBUG
+        kprintf("Received RC_CMD_SYS_ENABLE reply\n");
+#endif /* DEBUG */
+            break;
+
+        default:    
+#ifdef DEBUG
+        kprintf("Received UNKNOWN reply\n");
+#endif /* DEBUG */
+            break;
+    }
+}

FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen, slshen@lbl.gov