| /* |
| ** ************************************************************************* |
| ** |
| ** |
| ** 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; |
| PDPA pDpa = dev->priv; |
| U32 pciBaseAddr = dev->base_addr; |
| PU8 p_msgbuf = pDpa->PLanApiPA; |
| PU8 p_phymsgbuf = (PU8) virt_to_bus ((void *) p_msgbuf); |
| |
| dprintk |
| ("InitI2O: Adapter:0x%x ATU:0x%x msgbuf:0x%x phymsgbuf:0x%x\n" |
| "TransmitCallbackFunction:0x%x ReceiveCallbackFunction:0x%x\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) { |
| dprintk (KERN_WARNING |
| "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) { |
| dprintk (KERN_ERR |
| "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) { |
| dprintk (KERN_INFO "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 virtual address of msg - virtual 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 virtual address of msg - virtual 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%x p8Msg:0x%x p32:0x%x\n", |
| (u32) pPab, (u32) p8Msg, (u32) p32); |
| dprintk ("msg: 0x%x:0x%x:0x%x:0x%x\n", |
| p32[0], p32[1], p32[2], p32[3]); |
| dprintk (" 0x%x:0x%x:0x%x:0x%x\n", |
| p32[4], p32[5], p32[6], p32[7]); |
| dprintk (" 0x%x:0X%x:0x%x:0x%x\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: |
| dprintk (KERN_WARNING |
| "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 PU32 pMsg; |
| volatile PU32 p32, pReturnAddr; |
| P_NICSTAT pStats; |
| int i; |
| PPAB pPab = ((PDPA) dev->priv)->pPab; |
| |
| /*dprintk("Get82558Stats() StatsReturnAddr:0x%x\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 virtual address of msg - virtual already mapped to physical */ |
| pMsg = (PU32) (pPab->pPci45LinBaseAddr + msgOffset); |
| |
| /*dprintk("Get82558Stats - pMsg = 0x%x, InQ msgOffset = 0x%x\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; |
| p32 = (PU32)pPab->pLinOutMsgBlock; |
| pStats = (P_NICSTAT) pPab->pLinOutMsgBlock; |
| pStats->dump_status = 0xFFFFFFFF; |
| |
| /* post to Inbound Post Q */ |
| pPab->p_atu->InQueue = msgOffset; |
| |
| i = 0; |
| while (pStats->dump_status == 0xFFFFFFFF) { |
| if (i++ > 0xff) { |
| dprintk ("Timeout waiting for NIC statistics\n"); |
| return RC_RTN_MSG_REPLY_TIMEOUT; |
| } |
| udelay(50); |
| } |
| 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) |
| { |
| int i; |
| U32 msgOffset; |
| volatile PU32 pMsg; |
| volatile PU32 p32; |
| PPAB pPab = ((PDPA) dev->priv)->pPab; |
| |
| dprintk ("Get82558LinkStatus() ReturnPhysAddr:0x%x\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 virtual address of msg - virtual already mapped to physical */ |
| pMsg = (PU32) (pPab->pPci45LinBaseAddr + msgOffset); |
| /*dprintk("Get82558LinkStatus - pMsg = 0x%x, InQ msgOffset = 0x%x\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; |
| |
| i = 0; |
| while (*p32 == 0xFFFFFFFF) { |
| if (i++ > 0xff) { |
| dprintk ("Timeout waiting for link status\n"); |
| return RC_RTN_MSG_REPLY_TIMEOUT; |
| } |
| udelay(50); |
| } |
| |
| *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) |
| { |
| U32 off, i; |
| 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 */ |
| i = 0; |
| while (0 == p_atu->EtherMacLow) { |
| if (i++ > 0xff) { |
| dprintk ("rc_getmac: Timeout\n"); |
| return RC_RTN_MSG_REPLY_TIMEOUT; |
| } |
| udelay(50); |
| } |
| |
| /* 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) |
| { |
| PU32 pMsg; |
| volatile PU32 p32; |
| U32 msgOffset, i; |
| PPAB pPab = ((PDPA) dev->priv)->pPab; |
| |
| msgOffset = pPab->p_atu->InQueue; |
| |
| if (msgOffset == 0xFFFFFFFF) { |
| dprintk (KERN_WARNING |
| "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; |
| |
| i = 0; |
| |
| /* wait for response */ |
| while (p32[0] == 0xff) { |
| if (i++ > 0xff) { |
| dprintk ("Timeout waiting for promiscuous mode\n"); |
| return RC_RTN_NO_LINK_SPEED; |
| } |
| udelay(50); |
| } |
| |
| /* 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; |
| PU32 pMsg; |
| volatile PU32 p32; |
| PPAB pPab = ((PDPA) dev->priv)->pPab; |
| |
| msgOffset = pPab->p_atu->InQueue; |
| |
| if (msgOffset == 0xFFFFFFFF) { |
| dprintk (KERN_WARNING |
| "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 */ |
| if (p32[0] == 0xff) { |
| dprintk (KERN_WARNING |
| "Timeout waiting for promiscuous mode\n"); |
| 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, i; |
| PU32 pMsg; |
| volatile PU32 p32; |
| U8 IOPLinkSpeed; |
| PPAB pPab = ((PDPA) dev->priv)->pPab; |
| |
| msgOffset = pPab->p_atu->InQueue; |
| |
| if (msgOffset == 0xFFFFFFFF) { |
| dprintk (KERN_WARNING |
| "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 */ |
| i = 0; |
| while (p32[0] == 0xff) { |
| if (i++ > 0xff) { |
| dprintk ("Timeout waiting for link speed\n"); |
| return RC_RTN_NO_LINK_SPEED; |
| } |
| udelay(50); |
| } |
| /* 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, i; |
| 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 */ |
| i = 0; |
| while (p32[0] == 0xff) { |
| if (i++ > 0xff) { |
| dprintk ("Timeout waiting for link speed\n"); |
| return RC_RTN_NO_FIRM_VER; |
| } |
| udelay(50); |
| } |
| 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); |
| mdelay (1); |
| timeout++; |
| if (timeout > 200) { |
| 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, i; |
| 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 */ |
| |
| /* virtual 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 */ |
| i = 0; |
| while (!p32[0] && !p32[1]) { |
| if (i++ > 0xff) { |
| dprintk ("RCResetIOP timeout\n"); |
| return RC_RTN_MSG_REPLY_TIMEOUT; |
| } |
| udelay(100); |
| } |
| 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); |
| mdelay (1); |
| timeout++; |
| if (timeout > 200) { |
| dprintk (KERN_WARNING |
| "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) |
| { |
| U32 off, i; |
| PU32 pMsg, p32; |
| PPAB pPab = ((PDPA) dev->priv)->pPab; |
| PATU p_atu; |
| |
| dprintk |
| ("RCGetRavlinIPandMask: pIpAddr is 0x%x, *IpAddr is 0x%x\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%x, off 0x%x, p32 0x%x\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%x, off 0x%x, p32 0x%x\n", |
| (u32) p_atu, off, (u32) p32); |
| |
| /* wait for the rcpci45 board to update the info */ |
| i = 0; |
| while (0xffffffff == *p32) { |
| if (i++ > 0xff) { |
| dprintk ("RCGetRavlinIPandMask: Timeout\n"); |
| return RC_RTN_MSG_REPLY_TIMEOUT; |
| } |
| udelay(50); |
| } |
| |
| dprintk |
| ("RCGetRavlinIPandMask: after time out\np32[0] (IpAddr) 0x%x, p32[1] (IPmask) 0x%x\n", |
| p32[0], p32[1]); |
| |
| /* send IP and mask to user's space */ |
| *pIpAddr = p32[0]; |
| *pNetMask = p32[1]; |
| |
| dprintk |
| ("RCGetRavlinIPandMask: pIpAddr is 0x%x, *IpAddr is 0x%x\n", |
| (u32) pIpAddr, *pIpAddr); |
| |
| return RC_RTN_NO_ERROR; |
| } |
| |
| /* |
| ** ///////////////////////////////////////////////////////////////////////// |
| ** ///////////////////////////////////////////////////////////////////////// |
| ** |
| ** local functions |
| ** |
| ** ///////////////////////////////////////////////////////////////////////// |
| ** ///////////////////////////////////////////////////////////////////////// |
| */ |
| |
| /* |
| ** ========================================================================= |
| ** SendI2OOutboundQInitMsg() |
| ** |
| ** ========================================================================= |
| */ |
| static int |
| SendI2OOutboundQInitMsg (PPAB pPab) |
| { |
| U32 msgOffset, 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 virtual address of msg - virtual already mapped to physical */ |
| pMsg = (PU32) (pPab->pPci45LinBaseAddr + msgOffset); |
| |
| dprintk |
| ("SendI2OOutboundQInitMsg - pMsg = 0x%x, InQ msgOffset = 0x%x\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; |
| |
| /* virtual 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 */ |
| i = 0; |
| while (!p32[0]) { |
| if (i++ > 0xff) { |
| printk("rc: InitOutQ timeout\n"); |
| return RC_RTN_NO_I2O_STATUS; |
| } |
| udelay(50); |
| } |
| if (p32[0] != I2O_EXEC_OUTBOUND_INIT_COMPLETE) { |
| printk("rc: exec outbound init failed (%x)\n", |
| p32[0]); |
| 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, i; |
| 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 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_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 */ |
| |
| /* virtual pointer to return buffer - clear first two dwords */ |
| p32 = (volatile PU32) pPab->pLinOutMsgBlock; |
| p32[0] = 0; |
| p32[1] = 0; |
| |
| dprintk |
| ("GetI2OStatus - pMsg:0x%x, msgOffset:0x%x, [1]:0x%x, [6]:0x%x\n", |
| (u32) pMsg, msgOffset, pMsg[1], pMsg[6]); |
| |
| /* post to Inbound Post Q */ |
| pPab->p_atu->InQueue = msgOffset; |
| |
| dprintk ("Return status to p32 = 0x%x\n", (u32) p32); |
| |
| /* wait for response */ |
| i = 0; |
| while (!p32[0] || !p32[1]) { |
| if (i++ > 0xff) { |
| dprintk ("Timeout waiting for status from IOP\n"); |
| return RC_RTN_NO_I2O_STATUS; |
| } |
| udelay(50); |
| } |
| |
| dprintk ("0x%x:0x%x:0x%x:0x%x\n", p32[0], p32[1], |
| p32[2], p32[3]); |
| dprintk ("0x%x:0x%x:0x%x:0x%x\n", p32[4], p32[5], |
| p32[6], p32[7]); |
| dprintk ("0x%x:0x%x:0x%x:0x%x\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%x InFrameSize = 0x%x\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 virtual address of msg - virtual already mapped to physical */ |
| pMsg = (PU32) (pPab->pPci45LinBaseAddr + msgOffset); |
| |
| dprintk |
| ("SendEnableSysMsg - pMsg = 0x%x, InQ msgOffset = 0x%x\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 - virtual 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%x:0x%x:0x%x:0x%x:0x%x\n", |
| pTCB[0], pTCB[1], pTCB[2], pTCB[3], pTCB[4]); |
| dprintk ("pTCB 0x%x, pMsg 0x%x\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%x, phyAdr 0x%x, linAdr 0x%x\n", |
| (u32) pPab, phyAddrMsg, (u32) p8Msg); |
| dprintk ("msg :0x%x:0x%x:0x%x:0x%x\n", p32[0], p32[1], |
| p32[2], p32[3]); |
| dprintk ("msg :0x%x:0x%x:0x%x:0x%x\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; |
| } |
| } |