/* ** ************************************************************************* ** ** ** R C L A N M T L . C $Revision: 6 $ ** ** ** 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. ** ** 1998-1999, LAN API was modified and enhanced by Alice Hennessy. ** ** Sometime in 1997, LAN API was written from scratch by Wendell Nichols. ** ************************************************************************* */ #define DEBUG 1 #define RC_LINUX_MODULE #include "rclanmtl.h" /* 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 0xB91 /* 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 /* ** in reserved space right after PAB in host memory is area for returning ** values from card */ /* ** 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); /* ** ========================================================================= ** RCInitI2OMsgLayer() ** ** Initialize the RedCreek I2O Module and adapter. ** ** Inputs: dev - the devices net_device struct ** 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(struct net_device *dev, PFNTXCALLBACK TransmitCallbackFunction, PFNRXCALLBACK ReceiveCallbackFunction, PFNCALLBACK RebootCallbackFunction) { int result; PPAB pPab; U32 pciBaseAddr = dev->base_addr; PDPA pDpa = dev->priv; PU8 p_msgbuf = pDpa->PLanApiPA; PU8 p_phymsgbuf = (PU8)virt_to_bus((void *) p_msgbuf); dprintk("InitI2O: Adapter:0x%04ux ATU:0x%08ulx msgbuf:0x%08ulx phymsgbuf:0x%08ulx\n" "TransmitCallbackFunction:0x%08ulx ReceiveCallbackFunction:0x%08ulx\n", pDpa->id, pciBaseAddr, (u32)p_msgbuf, (u32)p_phymsgbuf, (u32)TransmitCallbackFunction, (u32)ReceiveCallbackFunction); /* Check if this interface already initialized - if so, shut it down */ if (pDpa->pPab != NULL) { printk(KERN_WARNING "(rcpci45 driver:) pDpa->pPab [%d] != NULL\n", pDpa->id); /* RCResetLANCard(pDpa->id, 0, (PU32)NULL, (PFNCALLBACK)NULL); */ pDpa->pPab = NULL; } /* store adapter instance values in adapter block. * Adapter block is at beginning of message buffer */ pPab = kmalloc(sizeof(*pPab), GFP_KERNEL); if (!pPab) { printk(KERN_ERR "(rcpci45 driver:) RCInitI2OMsgLayer: Could not allocate memory for PAB struct!\n"); result = RC_RTN_MALLOC_ERROR; goto err_out; } memset(pPab, 0, sizeof(*pPab)); pDpa->pPab = pPab; pPab->p_atu = (PATU)pciBaseAddr; pPab->pPci45LinBaseAddr = (PU8)pciBaseAddr; /* Set outbound message frame addr */ pPab->outMsgBlockPhyAddr = (U32)p_phymsgbuf; pPab->pLinOutMsgBlock = (PU8)p_msgbuf; /* 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) goto err_out_dealloc; if (pPab->IOPState == I2O_IOP_STATE_OPERATIONAL) { printk(KERN_INFO "(rcpci45 driver:) pPab->IOPState == op: resetting adapter\n"); RCResetLANCard(dev, 0, (PU32)NULL, (PFNCALLBACK)NULL); } result = SendI2OOutboundQInitMsg(pPab); if (result != RC_RTN_NO_ERROR) goto err_out_dealloc; result = SendEnableSysMsg(pPab); if (result != RC_RTN_NO_ERROR) goto err_out_dealloc; return RC_RTN_NO_ERROR; err_out_dealloc: kfree(pPab); err_out: return result; } /* ** ========================================================================= ** 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(struct net_device *dev) { PPAB pPab = ((PDPA)dev->priv)->pPab; 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(struct net_device *dev) { PPAB pPab = ((PDPA)dev->priv)->pPab; 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(struct net_device *dev, U32 InitiatorContext, PRCTCB pTransCtrlBlock) { U32 msgOffset; PU32 pMsg; int size; PPAB pPab = ((PDPA)dev->priv)->pPab; dprintk("RCI2OSendPacket()...\n"); 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) { dprintk("RCI2OSendPacket(): Inbound Free Q empty!\n"); 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 */ { dprintk("RCI2OSendPacket(): Error Rrocess TCB!\n"); 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(struct net_device *dev, PRCTCB pTransCtrlBlock) { U32 msgOffset; PU32 pMsg; int size; PPAB pPab = ((PDPA)dev->priv)->pPab; dprintk("RCPostRecvBuffers()...\n"); /* search for DeviceHandle */ 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) { dprintk("RCPostRecvBuffers(): Inbound Free Q empty!\n"); 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 */ { dprintk("RCPostRecvBuffers(): Error Processing TCB! size = %d\n", size); 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(struct net_device *dev) { U32 phyAddrMsg; PU8 p8Msg; PU32 p32; U16 count; PPAB pPab = ((PDPA)dev->priv)->pPab; unsigned char debug_msg[20]; if (pPab == NULL) return; phyAddrMsg = pPab->p_atu->OutQueue; while (phyAddrMsg != 0xFFFFFFFF) { p8Msg = pPab->pLinOutMsgBlock + (phyAddrMsg - pPab->outMsgBlockPhyAddr); p32 = (PU32)p8Msg; dprintk("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, dev); } else if (I2O_LAN_RECEIVE_POST == p8Msg[7]) { /* Receive Packet Reply Msg */ dprintk("I2O_RECV_REPLY pPab:0x%08ulx p8Msg:0x%08ulx p32:0x%08ulx\n", (u32)pPab, (u32)p8Msg, (u32)p32); dprintk("msg: 0x%08ulx:0x%08ulx:0x%08ulx:0x%08ulx\n", p32[0], p32[1], p32[2], p32[3]); dprintk(" 0x%08ulx:0x%08ulx:0x%08ulx:0x%08ulx\n", p32[4], p32[5], p32[6], p32[7]); dprintk(" 0x%08ulx:0X%08ulx:0x%08ulx:0x%08ulx\n", p32[8], p32[9], p32[10], p32[11]); /* status, count, buckets remaining, packetParmBlock, adapter */ (*pPab->pRecvCallbackFunc)(p8Msg[19], p8Msg[12], p32[5], p32+6, dev); } else if (I2O_LAN_RESET == p8Msg[7] || I2O_LAN_SHUTDOWN == p8Msg[7]) if (pPab->pCallbackFunc) (*pPab->pCallbackFunc)(p8Msg[19],0,0,dev); else pPab->pCallbackFunc = (PFNCALLBACK) 1; else if (I2O_PRIVATE == p8Msg[7]) { dprintk("i2o private 0x%x, 0x%x \n", p8Msg[7], p32[5]); switch (p32[5]) { case RC_PRIVATE_DEBUG_MSG: msgFlag = 1; dprintk("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'; dprintk("%s", debug_msg); break; case RC_PRIVATE_REBOOT: dprintk("Adapter reboot initiated...\n"); if (pPab->pRebootCallbackFunc) (*pPab->pRebootCallbackFunc)(0,0,0,dev); break; default: printk(KERN_WARNING "(rcpci45 driver:) 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(struct net_device *dev, P_RCLINKSTATS StatsReturnAddr, PFNWAITCALLBACK WaitCallback) { U32 msgOffset; volatile U32 timeout; volatile PU32 pMsg; volatile PU32 p32, pReturnAddr; P_NICSTAT pStats; int i; PPAB pPab = ((PDPA)dev->priv)->pPab; /*dprintk("Get82558Stats() StatsReturnAddr:0x%08ulx\n", StatsReturnAddr); */ if (pPab == NULL) return RC_RTN_ADPTR_NOT_REGISTERED; msgOffset = pPab->p_atu->InQueue; if (msgOffset == 0xFFFFFFFF) { dprintk("Get8255XStats(): Inbound Free Q empty!\n"); return RC_RTN_FREE_Q_EMPTY; } /* calc virual address of msg - virual already mapped to physical */ pMsg = (PU32)(pPab->pPci45LinBaseAddr + msgOffset); /*dprintk("Get82558Stats - pMsg = 0x%08ulx, InQ msgOffset = 0x%08ulx\n", pMsg, msgOffset);*/ /*dprintk("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; p32 = (PU32) pPab->outMsgBlockPhyAddr; pStats = (P_NICSTAT)pPab->pLinOutMsgBlock; pStats->dump_status = 0xFFFFFFFF; /* post to Inbound Post Q */ pPab->p_atu->InQueue = msgOffset; timeout = 100000; while (1) { if (WaitCallback) (*WaitCallback)(); udelay(10); if (pStats->dump_status != 0xFFFFFFFF) break; if (!timeout--) { dprintk("RCGet82558Stats() Timeout waiting for NIC statistics\n"); 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(struct net_device *dev, PU32 ReturnAddr, PFNWAITCALLBACK WaitCallback) { U32 msgOffset; volatile U32 timeout; volatile PU32 pMsg; volatile PU32 p32; PPAB pPab = ((PDPA)dev->priv)->pPab; dprintk("Get82558LinkStatus() ReturnPhysAddr:0x%08ulx\n", (u32)ReturnAddr); if (pPab == NULL) return RC_RTN_ADPTR_NOT_REGISTERED; msgOffset = pPab->p_atu->InQueue; if (msgOffset == 0xFFFFFFFF) { dprintk("Get82558LinkStatus(): Inbound Free Q empty!\n"); return RC_RTN_FREE_Q_EMPTY; } /* calc virual address of msg - virual already mapped to physical */ pMsg = (PU32)(pPab->pPci45LinBaseAddr + msgOffset); /*dprintk("Get82558LinkStatus - pMsg = 0x%08ulx, InQ msgOffset = 0x%08ulx\n", pMsg, msgOffset);*/ /*dprintk("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; p32 = (PU32)pPab->pLinOutMsgBlock; *p32 = 0xFFFFFFFF; /* post to Inbound Post Q */ pPab->p_atu->InQueue = msgOffset; timeout = 100000; while (1) { if (WaitCallback) (*WaitCallback)(); udelay(10); if (*p32 != 0xFFFFFFFF) break; if (!timeout--) { dprintk("Timeout waiting for link status\n"); 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(struct net_device *dev, PFNWAITCALLBACK WaitCallback) { unsigned timeout; U32 off; PU8 mac = dev->dev_addr; PU32 p; U32 temp[2]; PPAB pPab = ((PDPA)dev->priv)->pPab; PATU p_atu; 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); dprintk("RCGetMAC: p_atu 0x%08x, off 0x%08x, p 0x%08x\n", (uint)p_atu, (uint)off, (uint)p); /* 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 */ dprintk("RCGetMAC: p_atu 0x%08x, off 0x%08x, p 0x%08x\n", (uint)p_atu, (uint)off, (uint)p); /* wait for the rcpci45 board to update the info */ timeout = 1000000; while (0 == p_atu->EtherMacLow) { if (WaitCallback) (*WaitCallback)(); udelay(10); 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); dprintk("rc_getmac: 0x%x\n", (u32)mac); 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(struct net_device *dev, PU8 mac) { U32 off; PU32 pMsg; PPAB pPab = ((PDPA)dev->priv)->pPab; 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(struct net_device *dev, U16 LinkSpeedCode) { U32 off; PU32 pMsg; PPAB pPab = ((PDPA)dev->priv)->pPab; 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(struct net_device *dev, U16 Mode) { U32 off; PU32 pMsg; PPAB pPab = ((PDPA)dev->priv)->pPab; 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(struct net_device *dev, PU32 pMode, PFNWAITCALLBACK WaitCallback) { U32 msgOffset, timeout; PU32 pMsg; volatile PU32 p32; PPAB pPab = ((PDPA)dev->priv)->pPab; msgOffset = pPab->p_atu->InQueue; if (msgOffset == 0xFFFFFFFF) { printk(KERN_WARNING "(rcpci45 driver:) 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; 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; /* post to Inbound Post Q */ pPab->p_atu->InQueue = msgOffset; /* wait for response */ timeout = 1000000; while(1) { if (WaitCallback) (*WaitCallback)(); udelay(10); /* please don't hog the bus!!! */ if (p32[0] != 0xff) break; if (!timeout--) { dprintk("Timeout waiting for promiscuous mode from adapter\n"); dprintk("0x%8x\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(struct net_device *dev, U16 Mode) { U32 off; PU32 pMsg; PPAB pPab = ((PDPA)dev->priv)->pPab; 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(struct net_device *dev, PU32 pMode, PFNWAITCALLBACK WaitCallback) { U32 msgOffset, timeout; PU32 pMsg; volatile PU32 p32; PPAB pPab = ((PDPA)dev->priv)->pPab; msgOffset = pPab->p_atu->InQueue; if (msgOffset == 0xFFFFFFFF) { printk(KERN_WARNING "(rcpci45 driver:) 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; 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; /* post to Inbound Post Q */ pPab->p_atu->InQueue = msgOffset; /* wait for response */ timeout = 1000000; while(1) { if (WaitCallback) (*WaitCallback)(); udelay(10); /* please don't hog the bus!!! */ if (p32[0] != 0xff) break; if (!timeout--) { printk(KERN_WARNING "(rcpci45 driver:) Timeout waiting for promiscuous mode from adapter\n"); printk(KERN_WARNING "(rcpci45 driver:) 0x%8x\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(struct net_device *dev, PU32 pLinkSpeedCode, PFNWAITCALLBACK WaitCallback) { U32 msgOffset, timeout; PU32 pMsg; volatile PU32 p32; U8 IOPLinkSpeed; PPAB pPab = ((PDPA)dev->priv)->pPab; msgOffset = pPab->p_atu->InQueue; if (msgOffset == 0xFFFFFFFF) { printk(KERN_WARNING "(rcpci45 driver:) 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; 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; /* post to Inbound Post Q */ pPab->p_atu->InQueue = msgOffset; /* wait for response */ timeout = 1000000; while(1) { if (WaitCallback) (*WaitCallback)(); udelay(10); /* please don't hog the bus!!! */ if (p32[0] != 0xff) break; if (!timeout--) { dprintk("Timeout waiting for link speed from IOP\n"); dprintk("0x%8x\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(struct net_device *dev, U32 capability) ** ** Currently defined bits: ** WARM_REBOOT_CAPABLE 0x01 ** ** ========================================================================= */ RC_RETURN RCReportDriverCapability(struct net_device *dev, U32 capability) { U32 off; PU32 pMsg; PPAB pPab = ((PDPA)dev->priv)->pPab; 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(struct net_device *dev, PU8 pFirmString, PFNWAITCALLBACK WaitCallback) { U32 msgOffset, timeout; PU32 pMsg; volatile PU32 p32; PPAB pPab = ((PDPA)dev->priv)->pPab; msgOffset = pPab->p_atu->InQueue; if (msgOffset == 0xFFFFFFFF) { dprintk("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; 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; /* post to Inbound Post Q */ pPab->p_atu->InQueue = msgOffset; /* wait for response */ timeout = 1000000; while(1) { if (WaitCallback) (*WaitCallback)(); udelay(10); /* please don't hog the bus!!! */ if (p32[0] != 0xff) break; if (!timeout--) { dprintk("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(struct net_device *dev, U16 ResourceFlags, PU32 ReturnAddr, PFNCALLBACK CallbackFunction) { unsigned long off; PU32 pMsg; PPAB pPab = ((PDPA)dev->priv)->pPab; long timeout = 0; 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(dev); udelay(1000); /* 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(struct net_device *dev) { U32 msgOffset, timeout; PU32 pMsg; PPAB pPab = ((PDPA)dev->priv)->pPab; volatile PU32 p32; 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; pMsg[7] = 0; pMsg[8] = 1; /* return 1 byte */ /* virual pointer to return buffer - clear first two dwords */ p32 = (volatile PU32)pPab->pLinOutMsgBlock; p32[0] = 0; p32[1] = 0; /* post to Inbound Post Q */ pPab->p_atu->InQueue = msgOffset; /* wait for response */ timeout = 1000000; while(1) { udelay(10); /* please don't hog the bus!!! */ if (p32[0] || p32[1]) break; if (!timeout--) { dprintk("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(struct net_device *dev, U16 ResourceFlags, PU32 ReturnAddr, PFNCALLBACK CallbackFunction) { volatile PU32 pMsg; U32 off; PPAB pPab = ((PDPA)dev->priv)->pPab; long timeout = 0; 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(dev); udelay(1000); /* please don't hog the bus!!! */ timeout++; if (timeout > 10000) { printk(KERN_WARNING "(rcpci45 driver:) 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(struct net_device *dev, U32 ipAddr, U32 netMask) { volatile PU32 pMsg; U32 off; PPAB pPab = ((PDPA)dev->priv)->pPab; 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(struct net_device *dev, PU32 pIpAddr, PU32 pNetMask, PFNWAITCALLBACK WaitCallback) { unsigned timeout; U32 off; PU32 pMsg, p32; PPAB pPab = ((PDPA)dev->priv)->pPab; PATU p_atu; dprintk("RCGetRavlinIPandMask: pIpAddr is 0x%08ulx, *IpAddr is 0x%08ulx\n", (u32)pIpAddr, *pIpAddr); 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; *p32 = 0xFFFFFFFF; pMsg = (PU32)(pPab->pPci45LinBaseAddr + off); dprintk("RCGetRavlinIPandMask: p_atu 0x%08ulx, off 0x%08ulx, p32 0x%08ulx\n", (u32)p_atu, off, (u32)p32); /* 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; p_atu->InQueue = off; /* send it to the I2O device */ dprintk("RCGetRavlinIPandMask: p_atu 0x%08ulx, off 0x%08ulx, p32 0x%08ulx\n", (u32)p_atu, off, (u32)p32); /* wait for the rcpci45 board to update the info */ timeout = 100000; while (0xffffffff == *p32) { if (WaitCallback) (*WaitCallback)(); udelay(10); if (!timeout--) { dprintk("RCGetRavlinIPandMask: Timeout\n"); return RC_RTN_MSG_REPLY_TIMEOUT; } } dprintk("RCGetRavlinIPandMask: after time out\np32[0] (IpAddr) 0x%08ulx, p32[1] (IPmask) 0x%08ulx\n", p32[0], p32[1]); /* send IP and mask to user's space */ *pIpAddr = p32[0]; *pNetMask = p32[1]; dprintk("RCGetRavlinIPandMask: pIpAddr is 0x%08ulx, *IpAddr is 0x%08ulx\n", (u32)pIpAddr, *pIpAddr); 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) { dprintk("SendI2OOutboundQInitMsg(): Inbound Free Q empty!\n"); return RC_RTN_FREE_Q_EMPTY; } /* calc virual address of msg - virual already mapped to physical */ pMsg = (PU32)(pPab->pPci45LinBaseAddr + msgOffset); dprintk("SendI2OOutboundQInitMsg - pMsg = 0x%08ulx, InQ msgOffset = 0x%08ulx\n", (u32)pMsg, msgOffset); 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; /* virual pointer to return buffer - clear first two dwords */ p32 = (PU32)pPab->pLinOutMsgBlock; p32[0] = 0; /* post to Inbound Post Q */ pPab->p_atu->InQueue = msgOffset; /* wait for response */ timeout = 100000; while(1) { udelay(10); /* please don't hog the bus!!! */ if (p32[0]) break; if (!timeout--) { dprintk("Timeout wait for InitOutQ InPrgress status from IOP\n"); return RC_RTN_NO_I2O_STATUS; } } timeout = 100000; while(1) { udelay(10); /* please don't hog the bus!!! */ if (p32[0] == I2O_EXEC_OUTBOUND_INIT_COMPLETE) break; if (!timeout--) { dprintk("Timeout wait for InitOutQ Complete status from IOP\n"); 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; dprintk("GetI2OStatus: msg offset = 0x%x\n", msgOffset); if (msgOffset == 0xFFFFFFFF) { dprintk("GetI2OStatus(): Inbound Free Q empty!\n"); 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; pMsg[7] = 0; pMsg[8] = 88; /* return 88 bytes */ /* virual pointer to return buffer - clear first two dwords */ p32 = (volatile PU32)pPab->pLinOutMsgBlock; p32[0] = 0; p32[1] = 0; dprintk("GetI2OStatus - pMsg:0x%08ulx, msgOffset:0x%08ulx, [1]:0x%08ulx, [6]:0x%08ulx\n", (u32)pMsg, msgOffset, pMsg[1], pMsg[6]); /* post to Inbound Post Q */ pPab->p_atu->InQueue = msgOffset; dprintk("Return status to p32 = 0x%08ulx\n", (u32)p32); /* wait for response */ timeout = 1000000; while(1) { udelay(10); /* please don't hog the bus!!! */ if (p32[0] && p32[1]) break; if (!timeout--) { dprintk("Timeout waiting for status from IOP\n"); dprintk("0x%08ulx:0x%08ulx:0x%08ulx:0x%08ulx\n", p32[0], p32[1], p32[2], p32[3]); dprintk("0x%08ulx:0x%08ulx:0x%08ulx:0x%08ulx\n", p32[4], p32[5], p32[6], p32[7]); dprintk("0x%08ulx:0x%08ulx:0x%08ulx:0x%08ulx\n", p32[8], p32[9], p32[10], p32[11]); return RC_RTN_NO_I2O_STATUS; } } dprintk("0x%08ulx:0x%08ulx:0x%08ulx:0x%08ulx\n", p32[0], p32[1], p32[2], p32[3]); dprintk("0x%08ulx:0x%08ulx:0x%08ulx:0x%08ulx\n", p32[4], p32[5], p32[6], p32[7]); dprintk("0x%08ulx:0x%08ulx:0x%08ulx:0x%08ulx\n", p32[8], p32[9], p32[10], p32[11]); /* get IOP state */ pPab->IOPState = ((volatile PU8)p32)[10]; pPab->InboundMFrameSize = ((volatile PU16)p32)[6]; dprintk("IOP state 0x%02x InFrameSize = 0x%04x\n", pPab->IOPState, pPab->InboundMFrameSize); return RC_RTN_NO_ERROR; } /* ** ========================================================================= ** SendEnableSysMsg() ** ** ** ========================================================================= */ static int SendEnableSysMsg(PPAB pPab) { U32 msgOffset; volatile PU32 pMsg; msgOffset = pPab->p_atu->InQueue; if (msgOffset == 0xFFFFFFFF) { dprintk("SendEnableSysMsg(): Inbound Free Q empty!\n"); return RC_RTN_FREE_Q_EMPTY; } /* calc virual address of msg - virual already mapped to physical */ pMsg = (PU32)(pPab->pPci45LinBaseAddr + msgOffset); dprintk("SendEnableSysMsg - pMsg = 0x%08ulx, InQ msgOffset = 0x%08ulx\n", (u32)pMsg, msgOffset); 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; dprintk("FillI2OMsgSGLFromTCBX\n"); dprintk("TCB 0x%08ulx:0x%08ulx:0x%08ulx:0x%08ulx:0x%08ulx\n", pTCB[0], pTCB[1], pTCB[2], pTCB[3], pTCB[4]); dprintk("pTCB 0x%08ulx, pMsg 0x%08ulx\n", (u32)pTCB, (u32)pMsg); 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; dprintk("VXD: ProcessOutboundI2OMsg - pPab 0x%08ulx, phyAdr 0x%08ulx, linAdr 0x%08ulx\n", (u32)pPab, phyAddrMsg, (u32)p8Msg); dprintk("msg :0x%08ulx:0x%08ulx:0x%08ulx:0x%08ulx\n", p32[0], p32[1], p32[2], p32[3]); dprintk("msg :0x%08ulx:0x%08ulx:0x%08ulx:0x%08ulx\n", p32[4], p32[5], p32[6], p32[7]); if (p32[4] >> 24 != I2O_REPLY_STATUS_SUCCESS) { dprintk("Message reply status not success\n"); return; } switch (p8Msg[7] ) /* function code byte */ { case I2O_EXEC_SYS_TAB_SET: msgFlag = 1; dprintk("Received I2O_EXEC_SYS_TAB_SET reply\n"); break; case I2O_EXEC_HRT_GET: msgFlag = 1; dprintk("Received I2O_EXEC_HRT_GET reply\n"); break; case I2O_EXEC_LCT_NOTIFY: msgFlag = 1; dprintk("Received I2O_EXEC_LCT_NOTIFY reply\n"); break; case I2O_EXEC_SYS_ENABLE: msgFlag = 1; dprintk("Received I2O_EXEC_SYS_ENABLE reply\n"); break; default: dprintk("Received UNKNOWN reply\n"); break; } }