diff options
Diffstat (limited to 'drivers/net/rclanmtl.c')
-rw-r--r-- | drivers/net/rclanmtl.c | 2307 |
1 files changed, 2307 insertions, 0 deletions
diff --git a/drivers/net/rclanmtl.c b/drivers/net/rclanmtl.c new file mode 100644 index 000000000..971fb49b6 --- /dev/null +++ b/drivers/net/rclanmtl.c @@ -0,0 +1,2307 @@ +/* +** ************************************************************************* +** +** +** R C L A N M T L . C $Revision: 5 $ +** +** +** RedCreek I2O LAN Message Transport Layer program module. +** +** --------------------------------------------------------------------- +** --- Copyright (c) 1997-1999, RedCreek Communications Inc. --- +** --- All rights reserved. --- +** --------------------------------------------------------------------- +** +** File Description: +** +** Host side I2O (Intelligent I/O) LAN 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 "rclanmtl.h" + +#define dprintf kprintf + +extern int printk(const char * fmt, ...); + + /* RedCreek LAN device Target ID */ +#define RC_LAN_TARGET_ID 0x10 + /* RedCreek's OSM default LAN receive Initiator */ +#define DEFAULT_RECV_INIT_CONTEXT 0xA17 + + +/* +** I2O message structures +*/ + +#define I2O_TID_SZ 12 +#define I2O_FUNCTION_SZ 8 + +/* Transaction Reply Lists (TRL) Control Word structure */ + +#define I2O_TRL_FLAGS_SINGLE_FIXED_LENGTH 0x00 +#define I2O_TRL_FLAGS_SINGLE_VARIABLE_LENGTH 0x40 +#define I2O_TRL_FLAGS_MULTIPLE_FIXED_LENGTH 0x80 + +/* LAN Class specific functions */ + +#define I2O_LAN_PACKET_SEND 0x3B +#define I2O_LAN_SDU_SEND 0x3D +#define I2O_LAN_RECEIVE_POST 0x3E +#define I2O_LAN_RESET 0x35 +#define I2O_LAN_SHUTDOWN 0x37 + +/* Private Class specfic function */ +#define I2O_PRIVATE 0xFF + +/* I2O Executive Function Codes. */ + +#define I2O_EXEC_ADAPTER_ASSIGN 0xB3 +#define I2O_EXEC_ADAPTER_READ 0xB2 +#define I2O_EXEC_ADAPTER_RELEASE 0xB5 +#define I2O_EXEC_BIOS_INFO_SET 0xA5 +#define I2O_EXEC_BOOT_DEVICE_SET 0xA7 +#define I2O_EXEC_CONFIG_VALIDATE 0xBB +#define I2O_EXEC_CONN_SETUP 0xCA +#define I2O_EXEC_DEVICE_ASSIGN 0xB7 +#define I2O_EXEC_DEVICE_RELEASE 0xB9 +#define I2O_EXEC_HRT_GET 0xA8 +#define I2O_EXEC_IOP_CLEAR 0xBE +#define I2O_EXEC_IOP_CONNECT 0xC9 +#define I2O_EXEC_IOP_RESET 0xBD +#define I2O_EXEC_LCT_NOTIFY 0xA2 +#define I2O_EXEC_OUTBOUND_INIT 0xA1 +#define I2O_EXEC_PATH_ENABLE 0xD3 +#define I2O_EXEC_PATH_QUIESCE 0xC5 +#define I2O_EXEC_PATH_RESET 0xD7 +#define I2O_EXEC_STATIC_MF_CREATE 0xDD +#define I2O_EXEC_STATIC_MF_RELEASE 0xDF +#define I2O_EXEC_STATUS_GET 0xA0 +#define I2O_EXEC_SW_DOWNLOAD 0xA9 +#define I2O_EXEC_SW_UPLOAD 0xAB +#define I2O_EXEC_SW_REMOVE 0xAD +#define I2O_EXEC_SYS_ENABLE 0xD1 +#define I2O_EXEC_SYS_MODIFY 0xC1 +#define I2O_EXEC_SYS_QUIESCE 0xC3 +#define I2O_EXEC_SYS_TAB_SET 0xA3 + + + /* Init Outbound Q status */ +#define I2O_EXEC_OUTBOUND_INIT_IN_PROGRESS 0x01 +#define I2O_EXEC_OUTBOUND_INIT_REJECTED 0x02 +#define I2O_EXEC_OUTBOUND_INIT_FAILED 0x03 +#define I2O_EXEC_OUTBOUND_INIT_COMPLETE 0x04 + + +#define I2O_UTIL_NOP 0x00 + + +/* I2O Get Status State values */ + +#define I2O_IOP_STATE_INITIALIZING 0x01 +#define I2O_IOP_STATE_RESET 0x02 +#define I2O_IOP_STATE_HOLD 0x04 +#define I2O_IOP_STATE_READY 0x05 +#define I2O_IOP_STATE_OPERATIONAL 0x08 +#define I2O_IOP_STATE_FAILED 0x10 +#define I2O_IOP_STATE_FAULTED 0x11 + + +/* Defines for Request Status Codes: Table 3-1 Reply Status Codes. */ + +#define I2O_REPLY_STATUS_SUCCESS 0x00 +#define I2O_REPLY_STATUS_ABORT_DIRTY 0x01 +#define I2O_REPLY_STATUS_ABORT_NO_DATA_TRANSFER 0x02 +#define I2O_REPLY_STATUS_ABORT_PARTIAL_TRANSFER 0x03 +#define I2O_REPLY_STATUS_ERROR_DIRTY 0x04 +#define I2O_REPLY_STATUS_ERROR_NO_DATA_TRANSFER 0x05 +#define I2O_REPLY_STATUS_ERROR_PARTIAL_TRANSFER 0x06 +#define I2O_REPLY_STATUS_PROCESS_ABORT_DIRTY 0x07 +#define I2O_REPLY_STATUS_PROCESS_ABORT_NO_DATA_TRANSFER 0x08 +#define I2O_REPLY_STATUS_PROCESS_ABORT_PARTIAL_TRANSFER 0x09 +#define I2O_REPLY_STATUS_TRANSACTION_ERROR 0x0A +#define I2O_REPLY_STATUS_PROGRESS_REPORT 0x80 + + +/* DetailedStatusCode defines for ALL messages: Table 3-2 Detailed Status Codes.*/ + +#define I2O_DETAIL_STATUS_SUCCESS 0x0000 +#define I2O_DETAIL_STATUS_BAD_KEY 0x0001 +#define I2O_DETAIL_STATUS_CHAIN_BUFFER_TOO_LARGE 0x0002 +#define I2O_DETAIL_STATUS_DEVICE_BUSY 0x0003 +#define I2O_DETAIL_STATUS_DEVICE_LOCKED 0x0004 +#define I2O_DETAIL_STATUS_DEVICE_NOT_AVAILABLE 0x0005 +#define I2O_DETAIL_STATUS_DEVICE_RESET 0x0006 +#define I2O_DETAIL_STATUS_INAPPROPRIATE_FUNCTION 0x0007 +#define I2O_DETAIL_STATUS_INSUFFICIENT_RESOURCE_HARD 0x0008 +#define I2O_DETAIL_STATUS_INSUFFICIENT_RESOURCE_SOFT 0x0009 +#define I2O_DETAIL_STATUS_INVALID_INITIATOR_ADDRESS 0x000A +#define I2O_DETAIL_STATUS_INVALID_MESSAGE_FLAGS 0x000B +#define I2O_DETAIL_STATUS_INVALID_OFFSET 0x000C +#define I2O_DETAIL_STATUS_INVALID_PARAMETER 0x000D +#define I2O_DETAIL_STATUS_INVALID_REQUEST 0x000E +#define I2O_DETAIL_STATUS_INVALID_TARGET_ADDRESS 0x000F +#define I2O_DETAIL_STATUS_MESSAGE_TOO_LARGE 0x0010 +#define I2O_DETAIL_STATUS_MESSAGE_TOO_SMALL 0x0011 +#define I2O_DETAIL_STATUS_MISSING_PARAMETER 0x0012 +#define I2O_DETAIL_STATUS_NO_SUCH_PAGE 0x0013 +#define I2O_DETAIL_STATUS_REPLY_BUFFER_FULL 0x0014 +#define I2O_DETAIL_STATUS_TCL_ERROR 0x0015 +#define I2O_DETAIL_STATUS_TIMEOUT 0x0016 +#define I2O_DETAIL_STATUS_UNKNOWN_ERROR 0x0017 +#define I2O_DETAIL_STATUS_UNKNOWN_FUNCTION 0x0018 +#define I2O_DETAIL_STATUS_UNSUPPORTED_FUNCTION 0x0019 +#define I2O_DETAIL_STATUS_UNSUPPORTED_VERSION 0x001A + + /* I2O msg header defines for VersionOffset */ +#define I2OMSGVER_1_5 0x0001 +#define SGL_OFFSET_0 I2OMSGVER_1_5 +#define SGL_OFFSET_4 (0x0040 | I2OMSGVER_1_5) +#define TRL_OFFSET_5 (0x0050 | I2OMSGVER_1_5) +#define TRL_OFFSET_6 (0x0060 | I2OMSGVER_1_5) + + /* I2O 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 I2O_IOP_TID 0 +#define I2O_HOST_TID 1 + + /* RedCreek I2O private message codes */ +#define RC_PRIVATE_GET_MAC_ADDR 0x0001/**/ /* OBSOLETE */ +#define RC_PRIVATE_SET_MAC_ADDR 0x0002 +#define RC_PRIVATE_GET_NIC_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_SET_PROMISCUOUS_MODE 0x000e +#define RC_PRIVATE_GET_PROMISCUOUS_MODE 0x000f +#define RC_PRIVATE_SET_BROADCAST_MODE 0x0010 +#define RC_PRIVATE_GET_BROADCAST_MODE 0x0011 + +#define RC_PRIVATE_REBOOT 0x00FF + + +/* I2O message header */ +typedef struct _I2O_MESSAGE_FRAME +{ + U8 VersionOffset; + U8 MsgFlags; + U16 MessageSize; + BF TargetAddress:I2O_TID_SZ; + BF InitiatorAddress:I2O_TID_SZ; + BF Function:I2O_FUNCTION_SZ; + U32 InitiatorContext; + /* SGL[] */ +} +I2O_MESSAGE_FRAME, *PI2O_MESSAGE_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 IOPState; + 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 ProcessOutboundI2OMsg(PPAB pPab, U32 phyMsgAddr); +static int FillI2OMsgSGLFromTCB(PU32 pMsg, PRCTCB pXmitCntrlBlock); +static int GetI2OStatus(PPAB pPab); +static int SendI2OOutboundQInitMsg(PPAB pPab); +static int SendEnableSysMsg(PPAB pPab); + + +/* 1st 100h bytes of message block is reserved for messenger instance */ +#define ADAPTER_BLOCK_RESERVED_SPACE 0x100 + +/* +** ========================================================================= +** RCInitI2OMsgLayer() +** +** Initialize the RedCreek I2O 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 +RCInitI2OMsgLayer(U16 AdapterID, U32 pciBaseAddr, + PU8 p_msgbuf, PU8 p_phymsgbuf, + PFNTXCALLBACK TransmitCallbackFunction, + PFNRXCALLBACK ReceiveCallbackFunction, + PFNCALLBACK RebootCallbackFunction) +{ + int result; + PPAB pPab; + +#ifdef DEBUG + kprintf("InitI2O: 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 I2O IOP + */ + result = GetI2OStatus(pPab); + + if (result != RC_RTN_NO_ERROR) + return result; + + if (pPab->IOPState == I2O_IOP_STATE_OPERATIONAL) + { + printk("pPab->IOPState == op: resetting adapter\n"); + RCResetLANCard(AdapterID, 0, (PU32)NULL, (PFNCALLBACK)NULL); + } + + result = SendI2OOutboundQInitMsg(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 I2O interrupts. I2O 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 RCI2OSendPacket() functions. Disabling I2O interrupts +** will prevent hardware interrupt to host even though the outbound I2O msg +** queue is not emtpy. +** ========================================================================= +*/ +#define i960_OUT_POST_Q_INT_BIT 0x0008 /* bit set masks interrupts */ + +RC_RETURN RCDisableI2OInterrupts(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 RCEnableI2OInterrupts(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; + +} + + +/* +** ========================================================================= +** RCI2OSendPacket() +** ========================================================================= +*/ +RC_RETURN +RCI2OSendPacket(U16 AdapterID, U32 InitiatorContext, PRCTCB pTransCtrlBlock) +{ + U32 msgOffset; + PU32 pMsg; + int size; + PPAB pPab; + +#ifdef DEBUG + kprintf("RCI2OSendPacket()...\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("RCI2OSendPacket(): 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 = FillI2OMsgSGLFromTCB(pMsg + 4, pTransCtrlBlock); + + if (size == -1) /* error processing TCB - send NOP msg */ + { +#ifdef DEBUG + kprintf("RCI2OSendPacket(): Error Rrocess TCB!\n"); +#endif /* DEBUG */ + pMsg[0] = THREE_WORD_MSG_SIZE | SGL_OFFSET_0; + pMsg[1] = I2O_UTIL_NOP << 24 | I2O_HOST_TID << 12 | RC_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] = I2O_LAN_PACKET_SEND << 24 | I2O_HOST_TID << 12 | RC_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; + } +} + + +/* +** ========================================================================= +** RCI2OPostRecvBuffer() +** +** 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 = FillI2OMsgSGLFromTCB(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] = I2O_UTIL_NOP << 24 | I2O_HOST_TID << 12 | RC_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] = I2O_LAN_RECEIVE_POST << 24 | I2O_HOST_TID << 12 | RC_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; + } +} + + +/* +** ========================================================================= +** RCProcI2OMsgQ() +** +** Process I2O outbound message queue until empty. +** ========================================================================= +*/ +void +RCProcI2OMsgQ(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 (I2O_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 (I2O_LAN_RECEIVE_POST == p8Msg[7]) + { +#ifdef DEBUG + kprintf("I2O_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 (I2O_LAN_RESET == p8Msg[7] || I2O_LAN_SHUTDOWN == p8Msg[7]) + { + if (pPab->pCallbackFunc) + { + (*pPab->pCallbackFunc)(p8Msg[19],0,0,AdapterID); + } + else + { + pPab->pCallbackFunc = (PFNCALLBACK) 1; + } + //PCIAdapterBlock[AdapterID] = 0; + } + else if (I2O_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 I2O_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 I2O msg received: 0x%x\n", + p32[5]); + break; + } + } + + /* + ** Process other Msg's + */ + else + { + ProcessOutboundI2OMsg(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] = I2O_PRIVATE << 24 | I2O_HOST_TID << 12 | RC_LAN_TARGET_ID; + pMsg[2] = DEFAULT_RECV_INIT_CONTEXT; + pMsg[3] = 0x112; /* transaction context */ + pMsg[4] = RC_PCI45_VENDOR_ID << 16 | RC_PRIVATE_GET_NIC_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] = I2O_PRIVATE << 24 | I2O_HOST_TID << 12 | RC_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] = I2O_PRIVATE << 24 | I2O_HOST_TID << 12 | RC_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 I2O 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] = I2O_PRIVATE << 24 | I2O_HOST_TID << 12 | RC_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 I2O 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] = I2O_PRIVATE << 24 | I2O_HOST_TID << 12 | RC_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 I2O device */ + + return RC_RTN_NO_ERROR ; +} +/* +** ========================================================================= +** RCSetPromiscuousMode() +** +** Defined values for Mode: +** 0 - turn off promiscuous mode +** 1 - turn on promiscuous mode +** +** ========================================================================= +*/ +RC_RETURN +RCSetPromiscuousMode(U16 AdapterID, U16 Mode) +{ + 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] = I2O_PRIVATE << 24 | I2O_HOST_TID << 12 | RC_LAN_TARGET_ID; + pMsg[2] = 0; /* initiator context */ + pMsg[3] = 0x219; /* transaction context */ + pMsg[4] = RC_PCI45_VENDOR_ID << 16 | RC_PRIVATE_SET_PROMISCUOUS_MODE; + pMsg[5] = Mode; /* promiscuous mode setting */ + + pPab->p_atu->InQueue = off; /* send it to the device */ + + return RC_RTN_NO_ERROR ; +} +/* +** ========================================================================= +** RCGetPromiscuousMode() +** +** get promiscuous mode setting +** +** Possible return values placed in pMode: +** 0 = promisuous mode not set +** 1 = promisuous mode is set +** +** ========================================================================= +*/ +RC_RETURN +RCGetPromiscuousMode(U16 AdapterID, PU32 pMode, PFNWAITCALLBACK WaitCallback) +{ + U32 msgOffset, timeout; + PU32 pMsg; + volatile PU32 p32; + 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] = I2O_PRIVATE << 24 | I2O_HOST_TID << 12 | RC_LAN_TARGET_ID; + pMsg[2] = 0; /* initiator context */ + pMsg[3] = 0x219; /* transaction context */ + pMsg[4] = RC_PCI45_VENDOR_ID << 16 | RC_PRIVATE_GET_PROMISCUOUS_MODE; + /* 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 promiscuous mode from adapter\n"); + kprintf("0x%08.8ulx\n", p32[0]); + return RC_RTN_NO_LINK_SPEED; + } + } + + /* get mode */ + *pMode = (U8)((volatile PU8)p32)[0] & 0x0f; + + return RC_RTN_NO_ERROR; +} +/* +** ========================================================================= +** RCSetBroadcastMode() +** +** Defined values for Mode: +** 0 - turn off promiscuous mode +** 1 - turn on promiscuous mode +** +** ========================================================================= +*/ +RC_RETURN +RCSetBroadcastMode(U16 AdapterID, U16 Mode) +{ + 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] = I2O_PRIVATE << 24 | I2O_HOST_TID << 12 | RC_LAN_TARGET_ID; + pMsg[2] = 0; /* initiator context */ + pMsg[3] = 0x219; /* transaction context */ + pMsg[4] = RC_PCI45_VENDOR_ID << 16 | RC_PRIVATE_SET_BROADCAST_MODE; + pMsg[5] = Mode; /* promiscuous mode setting */ + + pPab->p_atu->InQueue = off; /* send it to the device */ + + return RC_RTN_NO_ERROR ; +} +/* +** ========================================================================= +** RCGetBroadcastMode() +** +** get promiscuous mode setting +** +** Possible return values placed in pMode: +** 0 = promisuous mode not set +** 1 = promisuous mode is set +** +** ========================================================================= +*/ +RC_RETURN +RCGetBroadcastMode(U16 AdapterID, PU32 pMode, PFNWAITCALLBACK WaitCallback) +{ + U32 msgOffset, timeout; + PU32 pMsg; + volatile PU32 p32; + 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] = I2O_PRIVATE << 24 | I2O_HOST_TID << 12 | RC_LAN_TARGET_ID; + pMsg[2] = 0; /* initiator context */ + pMsg[3] = 0x219; /* transaction context */ + pMsg[4] = RC_PCI45_VENDOR_ID << 16 | RC_PRIVATE_GET_BROADCAST_MODE; + /* 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 promiscuous mode from adapter\n"); + kprintf("0x%08.8ulx\n", p32[0]); + return RC_RTN_NO_LINK_SPEED; + } + } + + /* get mode */ + *pMode = (U8)((volatile PU8)p32)[0] & 0x0f; + + 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 IOPLinkSpeed; + 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] = I2O_PRIVATE << 24 | I2O_HOST_TID << 12 | RC_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 IOP\n"); + kprintf("0x%08.8ulx\n", p32[0]); + return RC_RTN_NO_LINK_SPEED; + } + } + + /* get Link speed */ + IOPLinkSpeed = (U8)((volatile PU8)p32)[0] & 0x0f; + + *pLinkSpeedCode= IOPLinkSpeed; + + 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] = I2O_PRIVATE << 24 | I2O_HOST_TID << 12 | RC_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 I2O 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] = I2O_PRIVATE << 24 | I2O_HOST_TID << 12 | RC_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 IOP\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] = I2O_LAN_RESET << 24 | I2O_HOST_TID << 12 | RC_LAN_TARGET_ID; + pMsg[2] = DEFAULT_RECV_INIT_CONTEXT; + pMsg[3] = ResourceFlags << 16; /* resource flags */ + + pPab->p_atu->InQueue = off; /* send it to the I2O device */ + + if (CallbackFunction == (PFNCALLBACK)NULL) + { + /* call RCProcI2OMsgQ() until something in pPab->pCallbackFunc + or until timer goes off */ + while (pPab->pCallbackFunc == (PFNCALLBACK)NULL) + { + RCProcI2OMsgQ(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 ; +} +/* +** ========================================================================= +** RCResetIOP() +** +** Send StatusGet Msg, wait for results return directly to buffer. +** +** ========================================================================= +*/ +RC_RETURN +RCResetIOP(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] = I2O_EXEC_IOP_RESET << 24 | I2O_HOST_TID << 12 | I2O_IOP_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("RCResetIOP 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] = I2O_LAN_SHUTDOWN << 24 | I2O_HOST_TID << 12 | RC_LAN_TARGET_ID; + pMsg[2] = DEFAULT_RECV_INIT_CONTEXT; + pMsg[3] = ResourceFlags << 16; /* resource flags */ + + pPab->p_atu->InQueue = off; /* send it to the I2O device */ + + if (CallbackFunction == (PFNCALLBACK)NULL) + { + /* call RCProcI2OMsgQ() until something in pPab->pCallbackFunc + or until timer goes off */ + while (pPab->pCallbackFunc == (PFNCALLBACK)NULL) + { + RCProcI2OMsgQ(AdapterID); + for (i = 0; i < 100000; i++) /* please don't hog the bus!!! */ + ; + timeout++; + if (timeout > 10000) + { + printk("RCShutdownLANCard(): timeout\n"); + 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] = I2O_PRIVATE << 24 | I2O_HOST_TID << 12 | RC_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 I2O 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] = I2O_PRIVATE << 24 | I2O_HOST_TID << 12 | RC_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 I2O 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 +** +** ///////////////////////////////////////////////////////////////////////// +** ///////////////////////////////////////////////////////////////////////// +*/ + +/* +** ========================================================================= +** SendI2OOutboundQInitMsg() +** +** ========================================================================= +*/ +static int +SendI2OOutboundQInitMsg(PPAB pPab) +{ + U32 msgOffset, timeout, phyOutQFrames, i; + volatile PU32 pMsg; + volatile PU32 p32; + + + + msgOffset = pPab->p_atu->InQueue; + + + if (msgOffset == 0xFFFFFFFF) + { +#ifdef DEBUG + kprintf("SendI2OOutboundQInitMsg(): 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("SendI2OOutboundQInitMsg - 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] = I2O_EXEC_OUTBOUND_INIT << 24 | I2O_HOST_TID << 12 | I2O_IOP_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 IOP\n"); +#endif /* DEBUG */ + return RC_RTN_NO_I2O_STATUS; + } + } + + timeout = 100000; + while(1) + { + for (i = 0; i < 1000; i++) /* please don't hog the bus!!! */ + ; + + if (p32[0] == I2O_EXEC_OUTBOUND_INIT_COMPLETE) + break; + + if (!timeout--) + { +#ifdef DEBUG + kprintf("Timeout wait for InitOutQ Complete status from IOP\n"); +#endif /* DEBUG */ + return RC_RTN_NO_I2O_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; +} + + +/* +** ========================================================================= +** GetI2OStatus() +** +** Send StatusGet Msg, wait for results return directly to buffer. +** +** ========================================================================= +*/ +static int +GetI2OStatus(PPAB pPab) +{ + U32 msgOffset, timeout; + PU32 pMsg; + volatile PU32 p32; + + + msgOffset = pPab->p_atu->InQueue; +#ifdef DEBUG + printk("GetI2OStatus: msg offset = 0x%x\n", msgOffset); +#endif /* DEBUG */ + if (msgOffset == 0xFFFFFFFF) + { +#ifdef DEBUG + kprintf("GetI2OStatus(): 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] = I2O_EXEC_STATUS_GET << 24 | I2O_HOST_TID << 12 | I2O_IOP_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("GetI2OStatus - 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 IOP\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_I2O_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 IOP state */ + pPab->IOPState = ((volatile PU8)p32)[10]; + pPab->InboundMFrameSize = ((volatile PU16)p32)[6]; + +#ifdef DEBUG + kprintf("IOP state 0x%02.2x InFrameSize = 0x%04.4x\n", + pPab->IOPState, 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] = I2O_EXEC_SYS_ENABLE << 24 | I2O_HOST_TID << 12 | I2O_IOP_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; +} + + +/* +** ========================================================================= +** FillI2OMsgFromTCB() +** +** 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 +FillI2OMsgSGLFromTCB(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("FillI2OMsgSGLFromTCBX\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; +} + + +/* +** ========================================================================= +** ProcessOutboundI2OMsg() +** +** process I2O reply message +** * change to msg structure * +** ========================================================================= +*/ +static void +ProcessOutboundI2OMsg(PPAB pPab, U32 phyAddrMsg) +{ + PU8 p8Msg; + PU32 p32; + // U16 count; + + + p8Msg = pPab->pLinOutMsgBlock + (phyAddrMsg - pPab->outMsgBlockPhyAddr); + p32 = (PU32)p8Msg; + +#ifdef DEBUG + kprintf("VXD: ProcessOutboundI2OMsg - 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 != I2O_REPLY_STATUS_SUCCESS) + { +#ifdef DEBUG + kprintf("Message reply status not success\n"); +#endif /* DEBUG */ + return; + } + + switch (p8Msg[7] ) /* function code byte */ + { + case I2O_EXEC_SYS_TAB_SET: + msgFlag = 1; +#ifdef DEBUG + kprintf("Received I2O_EXEC_SYS_TAB_SET reply\n"); +#endif /* DEBUG */ + break; + + case I2O_EXEC_HRT_GET: + msgFlag = 1; +#ifdef DEBUG + kprintf("Received I2O_EXEC_HRT_GET reply\n"); +#endif /* DEBUG */ + break; + + case I2O_EXEC_LCT_NOTIFY: + msgFlag = 1; +#ifdef DEBUG + kprintf("Received I2O_EXEC_LCT_NOTIFY reply\n"); +#endif /* DEBUG */ + break; + + case I2O_EXEC_SYS_ENABLE: + msgFlag = 1; +#ifdef DEBUG + kprintf("Received I2O_EXEC_SYS_ENABLE reply\n"); +#endif /* DEBUG */ + break; + + default: +#ifdef DEBUG + kprintf("Received UNKNOWN reply\n"); +#endif /* DEBUG */ + break; + } +} |