/****************************************************************************** * * Name: skrlmt.c * Project: GEnesis, PCI Gigabit Ethernet Adapter * Version: $Revision: 2.4 $ * Date: $Date: 2005/12/14 16:11:10 $ * Purpose: Manage links on SK-NET Adapters, esp. redundant ones. * ******************************************************************************/ /****************************************************************************** * * LICENSE: * (C)Copyright 1998-2002 SysKonnect GmbH. * (C)Copyright 2002-2003 Marvell. * * 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. * * The information in this file is provided "AS IS" without warranty. * /LICENSE * ******************************************************************************/ /****************************************************************************** * * Description: * * This module contains code for Link ManagemenT (LMT) of SK-NET Adapters. * It is mainly intended for adapters with more than one link. * For such adapters, this module realizes Redundant Link ManagemenT (RLMT). * * Include File Hierarchy: * * "skdrv1st.h" * "skdrv2nd.h" * ******************************************************************************/ #include #ifdef CONFIG_SK98 #ifndef lint static const char SysKonnectFileId[] = "@(#) $Id: skrlmt.c,v 2.4 2005/12/14 16:11:10 ibrueder Exp $ (C) Marvell."; #endif /* !defined(lint) */ #define __SKRLMT_C #ifdef __cplusplus extern "C" { #endif /* cplusplus */ #include "h/skdrv1st.h" #include "h/skdrv2nd.h" /* defines ********************************************************************/ #ifndef SK_HWAC_LINK_LED #define SK_HWAC_LINK_LED(a,b,c,d) #endif /* !defined(SK_HWAC_LINK_LED) */ #ifndef DEBUG #define RLMT_STATIC static #else /* DEBUG */ #define RLMT_STATIC #ifndef SK_LITTLE_ENDIAN /* First 32 bits */ #define OFFS_LO32 1 /* Second 32 bits */ #define OFFS_HI32 0 #else /* SK_LITTLE_ENDIAN */ /* First 32 bits */ #define OFFS_LO32 0 /* Second 32 bits */ #define OFFS_HI32 1 #endif /* SK_LITTLE_ENDIAN */ #endif /* DEBUG */ /* ----- Private timeout values ----- */ #define SK_RLMT_MIN_TO_VAL 125000 /* 1/8 sec. */ #define SK_RLMT_DEF_TO_VAL 1000000 /* 1 sec. */ #define SK_RLMT_PORTDOWN_TIM_VAL 900000 /* another 0.9 sec. */ #define SK_RLMT_PORTSTART_TIM_VAL 100000 /* 0.1 sec. */ #define SK_RLMT_PORTUP_TIM_VAL 2500000 /* 2.5 sec. */ #define SK_RLMT_SEG_TO_VAL 900000000 /* 15 min. */ /* Assume tick counter increment is 1 - may be set OS-dependent. */ #ifndef SK_TICK_INCR #define SK_TICK_INCR SK_CONSTU64(1) #endif /* !defined(SK_TICK_INCR) */ /* * Amount that a time stamp must be later to be recognized as "substantially * later". This is about 1/128 sec, but above 1 tick counter increment. */ #define SK_RLMT_BC_DELTA (1 + ((SK_TICKS_PER_SEC >> 7) > SK_TICK_INCR ? \ (SK_TICKS_PER_SEC >> 7) : SK_TICK_INCR)) /* ----- Private RLMT defaults ----- */ #define SK_RLMT_DEF_PREF_PORT 0 /* "Lower" port. */ #define SK_RLMT_DEF_MODE SK_RLMT_CHECK_LINK /* Default RLMT Mode. */ /* ----- Private RLMT checking states ----- */ #define SK_RLMT_RCS_SEG 1 /* RLMT Check State: check seg. */ #define SK_RLMT_RCS_START_SEG 2 /* RLMT Check State: start check seg. */ #define SK_RLMT_RCS_SEND_SEG 4 /* RLMT Check State: send BPDU packet */ #define SK_RLMT_RCS_REPORT_SEG 8 /* RLMT Check State: report seg. */ /* ----- Private PORT checking states ----- */ #define SK_RLMT_PCS_TX 1 /* Port Check State: check tx. */ #define SK_RLMT_PCS_RX 2 /* Port Check State: check rx. */ /* ----- Private PORT events ----- */ /* Note: Update simulation when changing these. */ #define SK_RLMT_PORTSTART_TIM 1100 /* Port start timeout. */ #define SK_RLMT_PORTUP_TIM 1101 /* Port can now go up. */ #define SK_RLMT_PORTDOWN_RX_TIM 1102 /* Port did not receive once ... */ #define SK_RLMT_PORTDOWN 1103 /* Port went down. */ #define SK_RLMT_PORTDOWN_TX_TIM 1104 /* Partner did not receive ... */ /* ----- Private RLMT events ----- */ /* Note: Update simulation when changing these. */ #define SK_RLMT_TIM 2100 /* RLMT timeout. */ #define SK_RLMT_SEG_TIM 2101 /* RLMT segmentation check timeout. */ #define TO_SHORTEN(tim) ((tim) / 2) /* Error numbers and messages. */ #define SKERR_RLMT_E001 (SK_ERRBASE_RLMT + 0) #define SKERR_RLMT_E001_MSG "No Packet." #define SKERR_RLMT_E002 (SKERR_RLMT_E001 + 1) #define SKERR_RLMT_E002_MSG "Short Packet." #define SKERR_RLMT_E003 (SKERR_RLMT_E002 + 1) #define SKERR_RLMT_E003_MSG "Unknown RLMT event." #define SKERR_RLMT_E004 (SKERR_RLMT_E003 + 1) #define SKERR_RLMT_E004_MSG "PortsUp incorrect." #define SKERR_RLMT_E005 (SKERR_RLMT_E004 + 1) #define SKERR_RLMT_E005_MSG \ "Net seems to be segmented (different root bridges are reported on the ports)." #define SKERR_RLMT_E006 (SKERR_RLMT_E005 + 1) #define SKERR_RLMT_E006_MSG "Duplicate MAC Address detected." #define SKERR_RLMT_E007 (SKERR_RLMT_E006 + 1) #define SKERR_RLMT_E007_MSG "LinksUp incorrect." #define SKERR_RLMT_E008 (SKERR_RLMT_E007 + 1) #define SKERR_RLMT_E008_MSG "Port not started but link came up." #define SKERR_RLMT_E009 (SKERR_RLMT_E008 + 1) #define SKERR_RLMT_E009_MSG "Corrected illegal setting of Preferred Port." #define SKERR_RLMT_E010 (SKERR_RLMT_E009 + 1) #define SKERR_RLMT_E010_MSG "Ignored illegal Preferred Port." /* LLC field values. */ #define LLC_COMMAND_RESPONSE_BIT 1 #define LLC_TEST_COMMAND 0xE3 #define LLC_UI 0x03 /* RLMT Packet fields. */ #define SK_RLMT_DSAP 0 #define SK_RLMT_SSAP 0 #define SK_RLMT_CTRL (LLC_TEST_COMMAND) #define SK_RLMT_INDICATOR0 0x53 /* S */ #define SK_RLMT_INDICATOR1 0x4B /* K */ #define SK_RLMT_INDICATOR2 0x2D /* - */ #define SK_RLMT_INDICATOR3 0x52 /* R */ #define SK_RLMT_INDICATOR4 0x4C /* L */ #define SK_RLMT_INDICATOR5 0x4D /* M */ #define SK_RLMT_INDICATOR6 0x54 /* T */ #define SK_RLMT_PACKET_VERSION 0 /* RLMT SPT Flag values. */ #define SK_RLMT_SPT_FLAG_CHANGE 0x01 #define SK_RLMT_SPT_FLAG_CHANGE_ACK 0x80 /* RLMT SPT Packet fields. */ #define SK_RLMT_SPT_DSAP 0x42 #define SK_RLMT_SPT_SSAP 0x42 #define SK_RLMT_SPT_CTRL (LLC_UI) #define SK_RLMT_SPT_PROTOCOL_ID0 0x00 #define SK_RLMT_SPT_PROTOCOL_ID1 0x00 #define SK_RLMT_SPT_PROTOCOL_VERSION_ID 0x00 #define SK_RLMT_SPT_BPDU_TYPE 0x00 #define SK_RLMT_SPT_FLAGS 0x00 /* ?? */ #define SK_RLMT_SPT_ROOT_ID0 0xFF /* Lowest possible priority. */ #define SK_RLMT_SPT_ROOT_ID1 0xFF /* Lowest possible priority. */ /* Remaining 6 bytes will be the current port address. */ #define SK_RLMT_SPT_ROOT_PATH_COST0 0x00 #define SK_RLMT_SPT_ROOT_PATH_COST1 0x00 #define SK_RLMT_SPT_ROOT_PATH_COST2 0x00 #define SK_RLMT_SPT_ROOT_PATH_COST3 0x00 #define SK_RLMT_SPT_BRIDGE_ID0 0xFF /* Lowest possible priority. */ #define SK_RLMT_SPT_BRIDGE_ID1 0xFF /* Lowest possible priority. */ /* Remaining 6 bytes will be the current port address. */ #define SK_RLMT_SPT_PORT_ID0 0xFF /* Lowest possible priority. */ #define SK_RLMT_SPT_PORT_ID1 0xFF /* Lowest possible priority. */ #define SK_RLMT_SPT_MSG_AGE0 0x00 #define SK_RLMT_SPT_MSG_AGE1 0x00 #define SK_RLMT_SPT_MAX_AGE0 0x00 #define SK_RLMT_SPT_MAX_AGE1 0xFF #define SK_RLMT_SPT_HELLO_TIME0 0x00 #define SK_RLMT_SPT_HELLO_TIME1 0xFF #define SK_RLMT_SPT_FWD_DELAY0 0x00 #define SK_RLMT_SPT_FWD_DELAY1 0x40 /* Size defines. */ #define SK_RLMT_MIN_PACKET_SIZE 34 #define SK_RLMT_MAX_PACKET_SIZE (SK_RLMT_MAX_TX_BUF_SIZE) #define SK_PACKET_DATA_LEN (SK_RLMT_MAX_PACKET_SIZE - \ SK_RLMT_MIN_PACKET_SIZE) /* ----- RLMT packet types ----- */ #define SK_PACKET_ANNOUNCE 1 /* Port announcement. */ #define SK_PACKET_ALIVE 2 /* Alive packet to port. */ #define SK_PACKET_ADDR_CHANGED 3 /* Port address changed. */ #define SK_PACKET_CHECK_TX 4 /* Check your tx line. */ #ifdef SK_LITTLE_ENDIAN #define SK_U16_TO_NETWORK_ORDER(Val,Addr) { \ SK_U8 *_Addr = (SK_U8*)(Addr); \ SK_U16 _Val = (SK_U16)(Val); \ *_Addr++ = (SK_U8)(_Val >> 8); \ *_Addr = (SK_U8)(_Val & 0xFF); \ } #endif /* SK_LITTLE_ENDIAN */ #ifdef SK_BIG_ENDIAN #define SK_U16_TO_NETWORK_ORDER(Val,Addr) (*(SK_U16*)(Addr) = (SK_U16)(Val)) #endif /* SK_BIG_ENDIAN */ #define AUTONEG_FAILED SK_FALSE #define AUTONEG_SUCCESS SK_TRUE /* typedefs *******************************************************************/ /* RLMT packet. Length: SK_RLMT_MAX_PACKET_SIZE (60) bytes. */ typedef struct s_RlmtPacket { SK_U8 DstAddr[SK_MAC_ADDR_LEN]; SK_U8 SrcAddr[SK_MAC_ADDR_LEN]; SK_U8 TypeLen[2]; SK_U8 DSap; SK_U8 SSap; SK_U8 Ctrl; SK_U8 Indicator[7]; SK_U8 RlmtPacketType[2]; SK_U8 Align1[2]; SK_U8 Random[4]; /* Random value of requesting(!) station. */ SK_U8 RlmtPacketVersion[2]; /* RLMT Packet version. */ SK_U8 Data[SK_PACKET_DATA_LEN]; } SK_RLMT_PACKET; typedef struct s_SpTreeRlmtPacket { SK_U8 DstAddr[SK_MAC_ADDR_LEN]; SK_U8 SrcAddr[SK_MAC_ADDR_LEN]; SK_U8 TypeLen[2]; SK_U8 DSap; SK_U8 SSap; SK_U8 Ctrl; SK_U8 ProtocolId[2]; SK_U8 ProtocolVersionId; SK_U8 BpduType; SK_U8 Flags; SK_U8 RootId[8]; SK_U8 RootPathCost[4]; SK_U8 BridgeId[8]; SK_U8 PortId[2]; SK_U8 MessageAge[2]; SK_U8 MaxAge[2]; SK_U8 HelloTime[2]; SK_U8 ForwardDelay[2]; } SK_SPTREE_PACKET; /* global variables ***********************************************************/ SK_MAC_ADDR SkRlmtMcAddr = {{0x01, 0x00, 0x5A, 0x52, 0x4C, 0x4D}}; SK_MAC_ADDR BridgeMcAddr = {{0x01, 0x80, 0xC2, 0x00, 0x00, 0x00}}; SK_MAC_ADDR BcAddr = {{0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF}}; /* local variables ************************************************************/ /* None. */ /* functions ******************************************************************/ RLMT_STATIC void SkRlmtCheckSwitch( SK_AC *pAC, SK_IOC IoC, SK_U32 NetIdx); RLMT_STATIC void SkRlmtCheckSeg( SK_AC *pAC, SK_IOC IoC, SK_U32 NetIdx); RLMT_STATIC void SkRlmtEvtSetNets( SK_AC *pAC, SK_IOC IoC, SK_EVPARA Para); /****************************************************************************** * * SkRlmtInit - initialize data, set state to init * * Description: * * SK_INIT_DATA * ============ * * This routine initializes all RLMT-related variables to a known state. * The initial state is SK_RLMT_RS_INIT. * All ports are initialized to SK_RLMT_PS_INIT. * * * SK_INIT_IO * ========== * * Nothing. * * * SK_INIT_RUN * =========== * * Determine the adapter's random value. * Set the hw registers, the "logical MAC address", the * RLMT multicast address, and eventually the BPDU multicast address. * * Context: * init, pageable * * Returns: * Nothing. */ void SkRlmtInit( SK_AC *pAC, /* Adapter Context */ SK_IOC IoC, /* I/O Context */ int Level) /* Initialization Level */ { SK_U32 i, j; SK_U64 Random; SK_EVPARA Para; SK_MAC_ADDR VirtualMacAddress; SK_MAC_ADDR PhysicalAMacAddress; SK_BOOL VirtualMacAddressSet; SK_BOOL PhysicalAMacAddressSet; SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_INIT, ("RLMT Init level %d.\n", Level)); switch (Level) { case SK_INIT_DATA: /* Initialize data structures. */ SK_MEMSET((char *)&pAC->Rlmt, 0, sizeof(SK_RLMT)); for (i = 0; i < SK_MAX_MACS; i++) { pAC->Rlmt.Port[i].PortState = SK_RLMT_PS_INIT; pAC->Rlmt.Port[i].LinkDown = SK_TRUE; pAC->Rlmt.Port[i].PortDown = SK_TRUE; pAC->Rlmt.Port[i].PortStarted = SK_FALSE; pAC->Rlmt.Port[i].PortNoRx = SK_FALSE; pAC->Rlmt.Port[i].RootIdSet = SK_FALSE; pAC->Rlmt.Port[i].PortNumber = i; pAC->Rlmt.Port[i].Net = &pAC->Rlmt.Net[0]; pAC->Rlmt.Port[i].AddrPort = &pAC->Addr.Port[i]; } pAC->Rlmt.NumNets = 1; for (i = 0; i < SK_MAX_NETS; i++) { pAC->Rlmt.Net[i].RlmtState = SK_RLMT_RS_INIT; pAC->Rlmt.Net[i].RootIdSet = SK_FALSE; pAC->Rlmt.Net[i].PrefPort = SK_RLMT_DEF_PREF_PORT; pAC->Rlmt.Net[i].Preference = 0xFFFFFFFF; /* Automatic. */ /* Just assuming. */ pAC->Rlmt.Net[i].ActivePort = pAC->Rlmt.Net[i].PrefPort; pAC->Rlmt.Net[i].RlmtMode = SK_RLMT_DEF_MODE; pAC->Rlmt.Net[i].TimeoutValue = SK_RLMT_DEF_TO_VAL; pAC->Rlmt.Net[i].NetNumber = i; } pAC->Rlmt.Net[0].Port[0] = &pAC->Rlmt.Port[0]; pAC->Rlmt.Net[0].Port[1] = &pAC->Rlmt.Port[1]; #if SK_MAX_NETS > 1 pAC->Rlmt.Net[1].Port[0] = &pAC->Rlmt.Port[1]; #endif /* SK_MAX_NETS > 1 */ break; case SK_INIT_IO: /* GIMacsFound first available here. */ SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_INIT, ("RLMT: %d MACs were detected.\n", pAC->GIni.GIMacsFound)); pAC->Rlmt.Net[0].NumPorts = pAC->GIni.GIMacsFound; /* Initialize HW registers? */ if (pAC->GIni.GIMacsFound == 1) { Para.Para32[0] = SK_RLMT_MODE_CLS; Para.Para32[1] = 0; (void)SkRlmtEvent(pAC, IoC, SK_RLMT_MODE_CHANGE, Para); } break; case SK_INIT_RUN: /* Ensure RLMT is set to one net. */ if (pAC->Rlmt.NumNets > 1) { Para.Para32[0] = 1; Para.Para32[1] = -1; SkRlmtEvtSetNets(pAC, IoC, Para); } for (i = 0; i < (SK_U32)pAC->GIni.GIMacsFound; i++) { Random = SkOsGetTime(pAC); *(SK_U32*)&pAC->Rlmt.Port[i].Random = *(SK_U32*)&Random; for (j = 0; j < 4; j++) { pAC->Rlmt.Port[i].Random[j] ^= pAC->Rlmt.Port[i].AddrPort-> CurrentMacAddress.a[SK_MAC_ADDR_LEN - 1 - j]; } (void)SkAddrMcClear(pAC, IoC, i, SK_ADDR_PERMANENT | SK_MC_SW_ONLY); /* Add RLMT MC address. */ (void)SkAddrMcAdd(pAC, IoC, i, &SkRlmtMcAddr, SK_ADDR_PERMANENT); if (pAC->Rlmt.Net[0].RlmtMode & SK_RLMT_CHECK_SEG) { /* Add BPDU MC address. */ (void)SkAddrMcAdd(pAC, IoC, i, &BridgeMcAddr, SK_ADDR_PERMANENT); } (void)SkAddrMcUpdate(pAC, IoC, i); } VirtualMacAddressSet = SK_FALSE; /* Read virtual MAC address from Control Register File. */ for (j = 0; j < SK_MAC_ADDR_LEN; j++) { SK_IN8(IoC, B2_MAC_1 + j, &VirtualMacAddress.a[j]); VirtualMacAddressSet |= VirtualMacAddress.a[j]; } PhysicalAMacAddressSet = SK_FALSE; /* Read physical MAC address for MAC A from Control Register File. */ for (j = 0; j < SK_MAC_ADDR_LEN; j++) { SK_IN8(IoC, B2_MAC_2 + j, &PhysicalAMacAddress.a[j]); PhysicalAMacAddressSet |= PhysicalAMacAddress.a[j]; } /* check if the two mac addresses contain reasonable values */ if (!VirtualMacAddressSet || !PhysicalAMacAddressSet) { pAC->Rlmt.RlmtOff = SK_TRUE; } /* if the two mac addresses are equal switch off the RLMT_PRE_LOOKAHEAD and the RLMT_LOOKAHEAD macros */ else if (SK_ADDR_EQUAL(PhysicalAMacAddress.a, VirtualMacAddress.a)) { pAC->Rlmt.RlmtOff = SK_TRUE; } else { pAC->Rlmt.RlmtOff = SK_FALSE; } break; default: /* error */ break; } return; } /* SkRlmtInit */ /****************************************************************************** * * SkRlmtBuildCheckChain - build the check chain * * Description: * This routine builds the local check chain: * - Each port that is up checks the next port. * - The last port that is up checks the first port that is up. * * Notes: * - Currently only local ports are considered when building the chain. * - Currently the SuspectState is just reset; * it would be better to save it ... * * Context: * runtime, pageable? * * Returns: * Nothing */ RLMT_STATIC void SkRlmtBuildCheckChain( SK_AC *pAC, /* Adapter Context */ SK_U32 NetIdx) /* Net Number */ { SK_U32 i; SK_U32 NumMacsUp; SK_RLMT_PORT * FirstMacUp; SK_RLMT_PORT * PrevMacUp; FirstMacUp = NULL; PrevMacUp = NULL; if (!(pAC->Rlmt.Net[NetIdx].RlmtMode & SK_RLMT_CHECK_LOC_LINK)) { for (i = 0; i < pAC->Rlmt.Net[i].NumPorts; i++) { pAC->Rlmt.Net[NetIdx].Port[i]->PortsChecked = 0; } return; /* Done. */ } SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL, ("SkRlmtBuildCheckChain.\n")); NumMacsUp = 0; for (i = 0; i < pAC->Rlmt.Net[NetIdx].NumPorts; i++) { pAC->Rlmt.Net[NetIdx].Port[i]->PortsChecked = 0; pAC->Rlmt.Net[NetIdx].Port[i]->PortsSuspect = 0; pAC->Rlmt.Net[NetIdx].Port[i]->CheckingState &= ~(SK_RLMT_PCS_RX | SK_RLMT_PCS_TX); /* * If more than two links are detected we should consider * checking at least two other ports: * 1. the next port that is not LinkDown and * 2. the next port that is not PortDown. */ if (!pAC->Rlmt.Net[NetIdx].Port[i]->LinkDown) { if (NumMacsUp == 0) { FirstMacUp = pAC->Rlmt.Net[NetIdx].Port[i]; } else { PrevMacUp->PortCheck[ pAC->Rlmt.Net[NetIdx].Port[i]->PortsChecked].CheckAddr = pAC->Rlmt.Net[NetIdx].Port[i]->AddrPort->CurrentMacAddress; PrevMacUp->PortCheck[ PrevMacUp->PortsChecked].SuspectTx = SK_FALSE; PrevMacUp->PortsChecked++; } PrevMacUp = pAC->Rlmt.Net[NetIdx].Port[i]; NumMacsUp++; } } if (NumMacsUp > 1) { PrevMacUp->PortCheck[PrevMacUp->PortsChecked].CheckAddr = FirstMacUp->AddrPort->CurrentMacAddress; PrevMacUp->PortCheck[PrevMacUp->PortsChecked].SuspectTx = SK_FALSE; PrevMacUp->PortsChecked++; } #ifdef DEBUG for (i = 0; i < pAC->Rlmt.Net[NetIdx].NumPorts; i++) { SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL, ("Port %d checks %d other ports: %2X.\n", i, pAC->Rlmt.Net[NetIdx].Port[i]->PortsChecked, pAC->Rlmt.Net[NetIdx].Port[i]->PortCheck[0].CheckAddr.a[5])); } #endif /* DEBUG */ return; } /* SkRlmtBuildCheckChain */ /****************************************************************************** * * SkRlmtBuildPacket - build an RLMT packet * * Description: * This routine sets up an RLMT packet. * * Context: * runtime, pageable? * * Returns: * NULL or pointer to RLMT mbuf */ RLMT_STATIC SK_MBUF *SkRlmtBuildPacket( SK_AC *pAC, /* Adapter Context */ SK_IOC IoC, /* I/O Context */ SK_U32 PortNumber, /* Sending port */ SK_U16 PacketType, /* RLMT packet type */ SK_MAC_ADDR *SrcAddr, /* Source address */ SK_MAC_ADDR *DestAddr) /* Destination address */ { int i; SK_U16 Length; SK_MBUF *pMb; SK_RLMT_PACKET *pPacket; #ifdef DEBUG SK_U8 CheckSrc = 0; SK_U8 CheckDest = 0; for (i = 0; i < SK_MAC_ADDR_LEN; ++i) { CheckSrc |= SrcAddr->a[i]; CheckDest |= DestAddr->a[i]; } if ((CheckSrc == 0) || (CheckDest == 0)) { SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_ERR, ("SkRlmtBuildPacket: Invalid %s%saddr.\n", (CheckSrc == 0 ? "Src" : ""), (CheckDest == 0 ? "Dest" : ""))); } #endif if ((pMb = SkDrvAllocRlmtMbuf(pAC, IoC, SK_RLMT_MAX_PACKET_SIZE)) != NULL) { pPacket = (SK_RLMT_PACKET*)pMb->pData; for (i = 0; i < SK_MAC_ADDR_LEN; i++) { pPacket->DstAddr[i] = DestAddr->a[i]; pPacket->SrcAddr[i] = SrcAddr->a[i]; } pPacket->DSap = SK_RLMT_DSAP; pPacket->SSap = SK_RLMT_SSAP; pPacket->Ctrl = SK_RLMT_CTRL; pPacket->Indicator[0] = SK_RLMT_INDICATOR0; pPacket->Indicator[1] = SK_RLMT_INDICATOR1; pPacket->Indicator[2] = SK_RLMT_INDICATOR2; pPacket->Indicator[3] = SK_RLMT_INDICATOR3; pPacket->Indicator[4] = SK_RLMT_INDICATOR4; pPacket->Indicator[5] = SK_RLMT_INDICATOR5; pPacket->Indicator[6] = SK_RLMT_INDICATOR6; SK_U16_TO_NETWORK_ORDER(PacketType, &pPacket->RlmtPacketType[0]); for (i = 0; i < 4; i++) { pPacket->Random[i] = pAC->Rlmt.Port[PortNumber].Random[i]; } SK_U16_TO_NETWORK_ORDER( SK_RLMT_PACKET_VERSION, &pPacket->RlmtPacketVersion[0]); for (i = 0; i < SK_PACKET_DATA_LEN; i++) { pPacket->Data[i] = 0x00; } Length = SK_RLMT_MAX_PACKET_SIZE; /* Or smaller. */ pMb->Length = Length; pMb->PortIdx = PortNumber; Length -= 14; SK_U16_TO_NETWORK_ORDER(Length, &pPacket->TypeLen[0]); if (PacketType == SK_PACKET_ALIVE) { pAC->Rlmt.Port[PortNumber].TxHelloCts++; } } return (pMb); } /* SkRlmtBuildPacket */ /****************************************************************************** * * SkRlmtBuildSpanningTreePacket - build spanning tree check packet * * Description: * This routine sets up a BPDU packet for spanning tree check. * * Context: * runtime, pageable? * * Returns: * NULL or pointer to RLMT mbuf */ RLMT_STATIC SK_MBUF *SkRlmtBuildSpanningTreePacket( SK_AC *pAC, /* Adapter Context */ SK_IOC IoC, /* I/O Context */ SK_U32 PortNumber) /* Sending port */ { unsigned i; SK_U16 Length; SK_MBUF *pMb; SK_SPTREE_PACKET *pSPacket; if ((pMb = SkDrvAllocRlmtMbuf(pAC, IoC, SK_RLMT_MAX_PACKET_SIZE)) != NULL) { pSPacket = (SK_SPTREE_PACKET*)pMb->pData; for (i = 0; i < SK_MAC_ADDR_LEN; i++) { pSPacket->DstAddr[i] = BridgeMcAddr.a[i]; pSPacket->SrcAddr[i] = pAC->Addr.Port[PortNumber].CurrentMacAddress.a[i]; } pSPacket->DSap = SK_RLMT_SPT_DSAP; pSPacket->SSap = SK_RLMT_SPT_SSAP; pSPacket->Ctrl = SK_RLMT_SPT_CTRL; pSPacket->ProtocolId[0] = SK_RLMT_SPT_PROTOCOL_ID0; pSPacket->ProtocolId[1] = SK_RLMT_SPT_PROTOCOL_ID1; pSPacket->ProtocolVersionId = SK_RLMT_SPT_PROTOCOL_VERSION_ID; pSPacket->BpduType = SK_RLMT_SPT_BPDU_TYPE; pSPacket->Flags = SK_RLMT_SPT_FLAGS; pSPacket->RootId[0] = SK_RLMT_SPT_ROOT_ID0; pSPacket->RootId[1] = SK_RLMT_SPT_ROOT_ID1; pSPacket->RootPathCost[0] = SK_RLMT_SPT_ROOT_PATH_COST0; pSPacket->RootPathCost[1] = SK_RLMT_SPT_ROOT_PATH_COST1; pSPacket->RootPathCost[2] = SK_RLMT_SPT_ROOT_PATH_COST2; pSPacket->RootPathCost[3] = SK_RLMT_SPT_ROOT_PATH_COST3; pSPacket->BridgeId[0] = SK_RLMT_SPT_BRIDGE_ID0; pSPacket->BridgeId[1] = SK_RLMT_SPT_BRIDGE_ID1; /* * Use logical MAC address as bridge ID and filter these packets * on receive. */ for (i = 0; i < SK_MAC_ADDR_LEN; i++) { pSPacket->BridgeId[i + 2] = pSPacket->RootId[i + 2] = pAC->Addr.Net[pAC->Rlmt.Port[PortNumber].Net->NetNumber]. CurrentMacAddress.a[i]; } pSPacket->PortId[0] = SK_RLMT_SPT_PORT_ID0; pSPacket->PortId[1] = SK_RLMT_SPT_PORT_ID1; pSPacket->MessageAge[0] = SK_RLMT_SPT_MSG_AGE0; pSPacket->MessageAge[1] = SK_RLMT_SPT_MSG_AGE1; pSPacket->MaxAge[0] = SK_RLMT_SPT_MAX_AGE0; pSPacket->MaxAge[1] = SK_RLMT_SPT_MAX_AGE1; pSPacket->HelloTime[0] = SK_RLMT_SPT_HELLO_TIME0; pSPacket->HelloTime[1] = SK_RLMT_SPT_HELLO_TIME1; pSPacket->ForwardDelay[0] = SK_RLMT_SPT_FWD_DELAY0; pSPacket->ForwardDelay[1] = SK_RLMT_SPT_FWD_DELAY1; Length = SK_RLMT_MAX_PACKET_SIZE; /* Or smaller. */ pMb->Length = Length; pMb->PortIdx = PortNumber; Length -= 14; SK_U16_TO_NETWORK_ORDER(Length, &pSPacket->TypeLen[0]); pAC->Rlmt.Port[PortNumber].TxSpHelloReqCts++; } return (pMb); } /* SkRlmtBuildSpanningTreePacket */ /****************************************************************************** * * SkRlmtSend - build and send check packets * * Description: * Depending on the RLMT state and the checking state, several packets * are sent through the indicated port. * * Context: * runtime, pageable? * * Returns: * Nothing. */ RLMT_STATIC void SkRlmtSend( SK_AC *pAC, /* Adapter Context */ SK_IOC IoC, /* I/O Context */ SK_U32 PortNumber) /* Sending port */ { unsigned j; SK_EVPARA Para; SK_RLMT_PORT *pRPort; pRPort = &pAC->Rlmt.Port[PortNumber]; if (pAC->Rlmt.Port[PortNumber].Net->RlmtMode & SK_RLMT_CHECK_LOC_LINK) { if (pRPort->CheckingState & (SK_RLMT_PCS_TX | SK_RLMT_PCS_RX)) { /* Port is suspicious. Send the RLMT packet to the RLMT mc addr. */ if ((Para.pParaPtr = SkRlmtBuildPacket(pAC, IoC, PortNumber, SK_PACKET_ALIVE, &pAC->Addr.Port[PortNumber].CurrentMacAddress, &SkRlmtMcAddr)) != NULL) { SkEventQueue(pAC, SKGE_DRV, SK_DRV_RLMT_SEND, Para); } } else { /* * Send a directed RLMT packet to all ports that are * checked by the indicated port. */ for (j = 0; j < pRPort->PortsChecked; j++) { if ((Para.pParaPtr = SkRlmtBuildPacket(pAC, IoC, PortNumber, SK_PACKET_ALIVE, &pAC->Addr.Port[PortNumber].CurrentMacAddress, &pRPort->PortCheck[j].CheckAddr)) != NULL) { SkEventQueue(pAC, SKGE_DRV, SK_DRV_RLMT_SEND, Para); } } } } if ((pAC->Rlmt.Port[PortNumber].Net->RlmtMode & SK_RLMT_CHECK_SEG) && (pAC->Rlmt.Port[PortNumber].Net->CheckingState & SK_RLMT_RCS_SEND_SEG)) { /* * Send a BPDU packet to make a connected switch tell us * the correct root bridge. */ if ((Para.pParaPtr = SkRlmtBuildSpanningTreePacket(pAC, IoC, PortNumber)) != NULL) { pAC->Rlmt.Port[PortNumber].Net->CheckingState &= ~SK_RLMT_RCS_SEND_SEG; pRPort->RootIdSet = SK_FALSE; SkEventQueue(pAC, SKGE_DRV, SK_DRV_RLMT_SEND, Para); SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_TX, ("SkRlmtSend: BPDU Packet on Port %u.\n", PortNumber)); } } return; } /* SkRlmtSend */ /****************************************************************************** * * SkRlmtPortReceives - check if port is (going) down and bring it up * * Description: * This routine checks if a port who received a non-BPDU packet * needs to go up or needs to be stopped going down. * * Context: * runtime, pageable? * * Returns: * Nothing. */ RLMT_STATIC void SkRlmtPortReceives( SK_AC *pAC, /* Adapter Context */ SK_IOC IoC, /* I/O Context */ SK_U32 PortNumber) /* Port to check */ { SK_RLMT_PORT *pRPort; SK_EVPARA Para; pRPort = &pAC->Rlmt.Port[PortNumber]; pRPort->PortNoRx = SK_FALSE; if ((pRPort->PortState == SK_RLMT_PS_DOWN) && !(pRPort->CheckingState & SK_RLMT_PCS_TX)) { /* * Port is marked down (rx), but received a non-BPDU packet. * Bring it up. */ SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_RX, ("SkRlmtPacketReceive: Received on PortDown.\n")); pRPort->PortState = SK_RLMT_PS_GOING_UP; pRPort->GuTimeStamp = SkOsGetTime(pAC); Para.Para32[0] = PortNumber; Para.Para32[1] = (SK_U32)-1; SkTimerStart(pAC, IoC, &pRPort->UpTimer, SK_RLMT_PORTUP_TIM_VAL, SKGE_RLMT, SK_RLMT_PORTUP_TIM, Para); pRPort->CheckingState &= ~SK_RLMT_PCS_RX; /* pAC->Rlmt.CheckSwitch = SK_TRUE; */ SkRlmtCheckSwitch(pAC, IoC, pRPort->Net->NetNumber); } /* PortDown && !SuspectTx */ else if (pRPort->CheckingState & SK_RLMT_PCS_RX) { SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_RX, ("SkRlmtPacketReceive: Stop bringing port down.\n")); SkTimerStop(pAC, IoC, &pRPort->DownRxTimer); pRPort->CheckingState &= ~SK_RLMT_PCS_RX; /* pAC->Rlmt.CheckSwitch = SK_TRUE; */ SkRlmtCheckSwitch(pAC, IoC, pRPort->Net->NetNumber); } /* PortGoingDown */ return; } /* SkRlmtPortReceives */ /****************************************************************************** * * SkRlmtPacketReceive - receive a packet for closer examination * * Description: * This routine examines a packet more closely than SK_RLMT_LOOKAHEAD. * * Context: * runtime, pageable? * * Returns: * Nothing. */ RLMT_STATIC void SkRlmtPacketReceive( SK_AC *pAC, /* Adapter Context */ SK_IOC IoC, /* I/O Context */ SK_MBUF *pMb) /* Received packet */ { #ifdef xDEBUG extern void DumpData(char *p, int size); #endif /* DEBUG */ int i; unsigned j; SK_U16 PacketType; SK_U32 PortNumber; SK_ADDR_PORT *pAPort; SK_RLMT_PORT *pRPort; SK_RLMT_PACKET *pRPacket; SK_SPTREE_PACKET *pSPacket; SK_EVPARA Para; PortNumber = pMb->PortIdx; pAPort = &pAC->Addr.Port[PortNumber]; pRPort = &pAC->Rlmt.Port[PortNumber]; SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_RX, ("SkRlmtPacketReceive: PortNumber == %d.\n", PortNumber)); pRPacket = (SK_RLMT_PACKET*)pMb->pData; pSPacket = (SK_SPTREE_PACKET*)pRPacket; #ifdef xDEBUG DumpData((char *)pRPacket, 32); #endif /* DEBUG */ if ((pRPort->PacketsPerTimeSlot - pRPort->BpduPacketsPerTimeSlot) != 0) { SkRlmtPortReceives(pAC, IoC, PortNumber); } /* Check destination address. */ if (!SK_ADDR_EQUAL(pAPort->CurrentMacAddress.a, pRPacket->DstAddr) && !SK_ADDR_EQUAL(SkRlmtMcAddr.a, pRPacket->DstAddr) && !SK_ADDR_EQUAL(BridgeMcAddr.a, pRPacket->DstAddr)) { /* Not sent to current MAC or registered MC address => Trash it. */ SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_RX, ("SkRlmtPacketReceive: Not for me.\n")); SkDrvFreeRlmtMbuf(pAC, IoC, pMb); return; } else if (SK_ADDR_EQUAL(pAPort->CurrentMacAddress.a, pRPacket->SrcAddr)) { /* * Was sent by same port (may happen during port switching * or in case of duplicate MAC addresses). */ /* * Check for duplicate address here: * If Packet.Random != My.Random => DupAddr. */ for (i = 3; i >= 0; i--) { if (pRPort->Random[i] != pRPacket->Random[i]) { break; } } /* * CAUTION: Do not check for duplicate MAC address in RLMT Alive Reply * packets (they have the LLC_COMMAND_RESPONSE_BIT set in * pRPacket->SSap). */ if (i >= 0 && pRPacket->DSap == SK_RLMT_DSAP && pRPacket->Ctrl == SK_RLMT_CTRL && pRPacket->SSap == SK_RLMT_SSAP && pRPacket->Indicator[0] == SK_RLMT_INDICATOR0 && pRPacket->Indicator[1] == SK_RLMT_INDICATOR1 && pRPacket->Indicator[2] == SK_RLMT_INDICATOR2 && pRPacket->Indicator[3] == SK_RLMT_INDICATOR3 && pRPacket->Indicator[4] == SK_RLMT_INDICATOR4 && pRPacket->Indicator[5] == SK_RLMT_INDICATOR5 && pRPacket->Indicator[6] == SK_RLMT_INDICATOR6) { SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_RX, ("SkRlmtPacketReceive: Duplicate MAC Address.\n")); /* Error Log entry. */ SK_ERR_LOG(pAC, SK_ERRCL_COMM, SKERR_RLMT_E006, SKERR_RLMT_E006_MSG); } else { /* Simply trash it. */ SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_RX, ("SkRlmtPacketReceive: Sent by me.\n")); } SkDrvFreeRlmtMbuf(pAC, IoC, pMb); return; } /* Check SuspectTx entries. */ if (pRPort->PortsSuspect > 0) { for (j = 0; j < pRPort->PortsChecked; j++) { if (pRPort->PortCheck[j].SuspectTx && SK_ADDR_EQUAL( pRPacket->SrcAddr, pRPort->PortCheck[j].CheckAddr.a)) { pRPort->PortCheck[j].SuspectTx = SK_FALSE; pRPort->PortsSuspect--; break; } } } /* Determine type of packet. */ if (pRPacket->DSap == SK_RLMT_DSAP && pRPacket->Ctrl == SK_RLMT_CTRL && (pRPacket->SSap & ~LLC_COMMAND_RESPONSE_BIT) == SK_RLMT_SSAP && pRPacket->Indicator[0] == SK_RLMT_INDICATOR0 && pRPacket->Indicator[1] == SK_RLMT_INDICATOR1 && pRPacket->Indicator[2] == SK_RLMT_INDICATOR2 && pRPacket->Indicator[3] == SK_RLMT_INDICATOR3 && pRPacket->Indicator[4] == SK_RLMT_INDICATOR4 && pRPacket->Indicator[5] == SK_RLMT_INDICATOR5 && pRPacket->Indicator[6] == SK_RLMT_INDICATOR6) { /* It's an RLMT packet. */ PacketType = (SK_U16)((pRPacket->RlmtPacketType[0] << 8) | pRPacket->RlmtPacketType[1]); switch (PacketType) { case SK_PACKET_ANNOUNCE: /* Not yet used. */ #if 0 /* Build the check chain. */ SkRlmtBuildCheckChain(pAC); #endif /* 0 */ SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_RX, ("SkRlmtPacketReceive: Announce.\n")); SkDrvFreeRlmtMbuf(pAC, IoC, pMb); break; case SK_PACKET_ALIVE: if (pRPacket->SSap & LLC_COMMAND_RESPONSE_BIT) { SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_RX, ("SkRlmtPacketReceive: Alive Reply.\n")); if (!(pAC->Addr.Port[PortNumber].PromMode & SK_PROM_MODE_LLC) || SK_ADDR_EQUAL( pRPacket->DstAddr, pAPort->CurrentMacAddress.a)) { /* Obviously we could send something. */ if (pRPort->CheckingState & SK_RLMT_PCS_TX) { pRPort->CheckingState &= ~SK_RLMT_PCS_TX; SkTimerStop(pAC, IoC, &pRPort->DownTxTimer); } if ((pRPort->PortState == SK_RLMT_PS_DOWN) && !(pRPort->CheckingState & SK_RLMT_PCS_RX)) { pRPort->PortState = SK_RLMT_PS_GOING_UP; pRPort->GuTimeStamp = SkOsGetTime(pAC); SkTimerStop(pAC, IoC, &pRPort->DownTxTimer); Para.Para32[0] = PortNumber; Para.Para32[1] = (SK_U32)-1; SkTimerStart(pAC, IoC, &pRPort->UpTimer, SK_RLMT_PORTUP_TIM_VAL, SKGE_RLMT, SK_RLMT_PORTUP_TIM, Para); } } /* Mark sending port as alive? */ SkDrvFreeRlmtMbuf(pAC, IoC, pMb); } else { /* Alive Request Packet. */ SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_RX, ("SkRlmtPacketReceive: Alive Request.\n")); pRPort->RxHelloCts++; /* Answer. */ for (i = 0; i < SK_MAC_ADDR_LEN; i++) { pRPacket->DstAddr[i] = pRPacket->SrcAddr[i]; pRPacket->SrcAddr[i] = pAC->Addr.Port[PortNumber].CurrentMacAddress.a[i]; } pRPacket->SSap |= LLC_COMMAND_RESPONSE_BIT; Para.pParaPtr = pMb; SkEventQueue(pAC, SKGE_DRV, SK_DRV_RLMT_SEND, Para); } break; case SK_PACKET_CHECK_TX: SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_RX, ("SkRlmtPacketReceive: Check your tx line.\n")); /* A port checking us requests us to check our tx line. */ pRPort->CheckingState |= SK_RLMT_PCS_TX; /* Start PortDownTx timer. */ Para.Para32[0] = PortNumber; Para.Para32[1] = (SK_U32)-1; SkTimerStart(pAC, IoC, &pRPort->DownTxTimer, SK_RLMT_PORTDOWN_TIM_VAL, SKGE_RLMT, SK_RLMT_PORTDOWN_TX_TIM, Para); SkDrvFreeRlmtMbuf(pAC, IoC, pMb); if ((Para.pParaPtr = SkRlmtBuildPacket(pAC, IoC, PortNumber, SK_PACKET_ALIVE, &pAC->Addr.Port[PortNumber].CurrentMacAddress, &SkRlmtMcAddr)) != NULL) { SkEventQueue(pAC, SKGE_DRV, SK_DRV_RLMT_SEND, Para); } break; case SK_PACKET_ADDR_CHANGED: SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_RX, ("SkRlmtPacketReceive: Address Change.\n")); /* Build the check chain. */ SkRlmtBuildCheckChain(pAC, pRPort->Net->NetNumber); SkDrvFreeRlmtMbuf(pAC, IoC, pMb); break; default: SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_RX, ("SkRlmtPacketReceive: Unknown RLMT packet.\n")); /* RA;:;: ??? */ SkDrvFreeRlmtMbuf(pAC, IoC, pMb); } } else if (pSPacket->DSap == SK_RLMT_SPT_DSAP && pSPacket->Ctrl == SK_RLMT_SPT_CTRL && (pSPacket->SSap & ~LLC_COMMAND_RESPONSE_BIT) == SK_RLMT_SPT_SSAP) { SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_RX, ("SkRlmtPacketReceive: BPDU Packet.\n")); /* Spanning Tree packet. */ pRPort->RxSpHelloCts++; if (!SK_ADDR_EQUAL(&pSPacket->RootId[2], &pAC->Addr.Net[pAC->Rlmt. Port[PortNumber].Net->NetNumber].CurrentMacAddress.a[0])) { /* * Check segmentation if a new root bridge is set and * the segmentation check is not currently running. */ if (!SK_ADDR_EQUAL(&pSPacket->RootId[2], &pRPort->Root.Id[2]) && (pAC->Rlmt.Port[PortNumber].Net->LinksUp > 1) && (pAC->Rlmt.Port[PortNumber].Net->RlmtMode & SK_RLMT_CHECK_SEG) != 0 && (pAC->Rlmt.Port[PortNumber].Net->CheckingState & SK_RLMT_RCS_SEG) == 0) { pAC->Rlmt.Port[PortNumber].Net->CheckingState |= SK_RLMT_RCS_START_SEG | SK_RLMT_RCS_SEND_SEG; } /* Store tree view of this port. */ for (i = 0; i < 8; i++) { pRPort->Root.Id[i] = pSPacket->RootId[i]; } pRPort->RootIdSet = SK_TRUE; SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_DUMP, ("Root ID %d: %02x %02x %02x %02x %02x %02x %02x %02x.\n", PortNumber, pRPort->Root.Id[0], pRPort->Root.Id[1], pRPort->Root.Id[2], pRPort->Root.Id[3], pRPort->Root.Id[4], pRPort->Root.Id[5], pRPort->Root.Id[6], pRPort->Root.Id[7])); } SkDrvFreeRlmtMbuf(pAC, IoC, pMb); if ((pAC->Rlmt.Port[PortNumber].Net->CheckingState & SK_RLMT_RCS_REPORT_SEG) != 0) { SkRlmtCheckSeg(pAC, IoC, pAC->Rlmt.Port[PortNumber].Net->NetNumber); } } else { SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_RX, ("SkRlmtPacketReceive: Unknown Packet Type.\n")); /* Unknown packet. */ SkDrvFreeRlmtMbuf(pAC, IoC, pMb); } return; } /* SkRlmtPacketReceive */ /****************************************************************************** * * SkRlmtCheckPort - check if a port works * * Description: * This routine checks if a port whose link is up received something * and if it seems to transmit successfully. * * # PortState: PsInit, PsLinkDown, PsDown, PsGoingUp, PsUp * # PortCheckingState (Bitfield): ChkTx, ChkRx, ChkSeg * # RlmtCheckingState (Bitfield): ChkSeg, StartChkSeg, ReportSeg * * if (Rx - RxBpdu == 0) { # No rx. * if (state == PsUp) { * PortCheckingState |= ChkRx * } * if (ModeCheckSeg && (Timeout == * TO_SHORTEN(RLMT_DEFAULT_TIMEOUT))) { * RlmtCheckingState |= ChkSeg) * PortCheckingState |= ChkSeg * } * NewTimeout = TO_SHORTEN(Timeout) * if (NewTimeout < RLMT_MIN_TIMEOUT) { * NewTimeout = RLMT_MIN_TIMEOUT * PortState = PsDown * ... * } * } * else { # something was received * # Set counter to 0 at LinkDown? * # No - rx may be reported after LinkDown ??? * PortCheckingState &= ~ChkRx * NewTimeout = RLMT_DEFAULT_TIMEOUT * if (RxAck == 0) { * possible reasons: * is my tx line bad? -- * send RLMT multicast and report * back internally? (only possible * between ports on same adapter) * } * if (RxChk == 0) { * possible reasons: * - tx line of port set to check me * maybe bad * - no other port/adapter available or set * to check me * - adapter checking me has a longer * timeout * ??? anything that can be done here? * } * } * * Context: * runtime, pageable? * * Returns: * New timeout value. */ RLMT_STATIC SK_U32 SkRlmtCheckPort( SK_AC *pAC, /* Adapter Context */ SK_IOC IoC, /* I/O Context */ SK_U32 PortNumber) /* Port to check */ { unsigned i; SK_U32 NewTimeout; SK_RLMT_PORT *pRPort; SK_EVPARA Para; pRPort = &pAC->Rlmt.Port[PortNumber]; if ((pRPort->PacketsPerTimeSlot - pRPort->BpduPacketsPerTimeSlot) == 0) { SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL, ("SkRlmtCheckPort %d: No (%d) receives in last time slot.\n", PortNumber, pRPort->PacketsPerTimeSlot)); /* * Check segmentation if there was no receive at least twice * in a row (PortNoRx is already set) and the segmentation * check is not currently running. */ if (pRPort->PortNoRx && (pAC->Rlmt.Port[PortNumber].Net->LinksUp > 1) && (pAC->Rlmt.Port[PortNumber].Net->RlmtMode & SK_RLMT_CHECK_SEG) && !(pAC->Rlmt.Port[PortNumber].Net->CheckingState & SK_RLMT_RCS_SEG)) { pAC->Rlmt.Port[PortNumber].Net->CheckingState |= SK_RLMT_RCS_START_SEG | SK_RLMT_RCS_SEND_SEG; } SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL, ("SkRlmtCheckPort: PortsSuspect %d, PcsRx %d.\n", pRPort->PortsSuspect, pRPort->CheckingState & SK_RLMT_PCS_RX)); if (pRPort->PortState != SK_RLMT_PS_DOWN) { NewTimeout = TO_SHORTEN(pAC->Rlmt.Port[PortNumber].Net->TimeoutValue); if (NewTimeout < SK_RLMT_MIN_TO_VAL) { NewTimeout = SK_RLMT_MIN_TO_VAL; } if (!(pRPort->CheckingState & SK_RLMT_PCS_RX)) { Para.Para32[0] = PortNumber; pRPort->CheckingState |= SK_RLMT_PCS_RX; /* * What shall we do if the port checked by this one receives * our request frames? What's bad - our rx line or his tx line? */ Para.Para32[1] = (SK_U32)-1; SkTimerStart(pAC, IoC, &pRPort->DownRxTimer, SK_RLMT_PORTDOWN_TIM_VAL, SKGE_RLMT, SK_RLMT_PORTDOWN_RX_TIM, Para); for (i = 0; i < pRPort->PortsChecked; i++) { if (pRPort->PortCheck[i].SuspectTx) { continue; } pRPort->PortCheck[i].SuspectTx = SK_TRUE; pRPort->PortsSuspect++; if ((Para.pParaPtr = SkRlmtBuildPacket(pAC, IoC, PortNumber, SK_PACKET_CHECK_TX, &pAC->Addr.Port[PortNumber].CurrentMacAddress, &pRPort->PortCheck[i].CheckAddr)) != NULL) { SkEventQueue(pAC, SKGE_DRV, SK_DRV_RLMT_SEND, Para); } } } } else { /* PortDown -- or all partners suspect. */ NewTimeout = SK_RLMT_DEF_TO_VAL; } pRPort->PortNoRx = SK_TRUE; } else { /* A non-BPDU packet was received. */ SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL, ("SkRlmtCheckPort %d: %d (%d) receives in last time slot.\n", PortNumber, pRPort->PacketsPerTimeSlot - pRPort->BpduPacketsPerTimeSlot, pRPort->PacketsPerTimeSlot)); SkRlmtPortReceives(pAC, IoC, PortNumber); if (pAC->Rlmt.CheckSwitch) { SkRlmtCheckSwitch(pAC, IoC, pRPort->Net->NetNumber); } NewTimeout = SK_RLMT_DEF_TO_VAL; } return (NewTimeout); } /* SkRlmtCheckPort */ /****************************************************************************** * * SkRlmtSelectBcRx - select new active port, criteria 1 (CLP) * * Description: * This routine selects the port that received a broadcast frame * substantially later than all other ports. * * Context: * runtime, pageable? * * Returns: * SK_BOOL */ RLMT_STATIC SK_BOOL SkRlmtSelectBcRx( SK_AC *pAC, /* Adapter Context */ SK_IOC IoC, /* I/O Context */ SK_U32 Active, /* Active port */ SK_U32 PrefPort, /* Preferred port */ SK_U32 *pSelect) /* New active port */ { SK_U64 BcTimeStamp; SK_U32 i; SK_BOOL PortFound; BcTimeStamp = 0; /* Not totally necessary, but feeling better. */ PortFound = SK_FALSE; /* Select port with the latest TimeStamp. */ for (i = 0; i < (SK_U32)pAC->GIni.GIMacsFound; i++) { SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL, ("TimeStamp Port %d (Down: %d, NoRx: %d): %08x %08x.\n", i, pAC->Rlmt.Port[i].PortDown, pAC->Rlmt.Port[i].PortNoRx, *((SK_U32*)(&pAC->Rlmt.Port[i].BcTimeStamp) + OFFS_HI32), *((SK_U32*)(&pAC->Rlmt.Port[i].BcTimeStamp) + OFFS_LO32))); if (!pAC->Rlmt.Port[i].PortDown && !pAC->Rlmt.Port[i].PortNoRx) { if (!PortFound || pAC->Rlmt.Port[i].BcTimeStamp > BcTimeStamp) { BcTimeStamp = pAC->Rlmt.Port[i].BcTimeStamp; *pSelect = i; PortFound = SK_TRUE; } } } if (PortFound) { SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL, ("Port %d received the last broadcast.\n", *pSelect)); /* Look if another port's time stamp is similar. */ for (i = 0; i < (SK_U32)pAC->GIni.GIMacsFound; i++) { if (i == *pSelect) { continue; } if (!pAC->Rlmt.Port[i].PortDown && !pAC->Rlmt.Port[i].PortNoRx && (pAC->Rlmt.Port[i].BcTimeStamp > BcTimeStamp - SK_RLMT_BC_DELTA || pAC->Rlmt.Port[i].BcTimeStamp + SK_RLMT_BC_DELTA > BcTimeStamp)) { PortFound = SK_FALSE; SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL, ("Port %d received a broadcast at a similar time.\n", i)); break; } } } #ifdef DEBUG if (PortFound) { SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL, ("SK_RLMT_SELECT_BCRX found Port %d receiving the substantially " "latest broadcast (%u).\n", *pSelect, BcTimeStamp - pAC->Rlmt.Port[1 - *pSelect].BcTimeStamp)); } #endif /* DEBUG */ return (PortFound); } /* SkRlmtSelectBcRx */ /****************************************************************************** * * SkRlmtSelectNotSuspect - select new active port, criteria 2 (CLP) * * Description: * This routine selects a good port (it is PortUp && !SuspectRx). * * Context: * runtime, pageable? * * Returns: * SK_BOOL */ RLMT_STATIC SK_BOOL SkRlmtSelectNotSuspect( SK_AC *pAC, /* Adapter Context */ SK_IOC IoC, /* I/O Context */ SK_U32 Active, /* Active port */ SK_U32 PrefPort, /* Preferred port */ SK_U32 *pSelect) /* New active port */ { SK_U32 i; SK_BOOL PortFound; PortFound = SK_FALSE; /* Select first port that is PortUp && !SuspectRx. */ for (i = 0; i < (SK_U32)pAC->GIni.GIMacsFound; i++) { if (!pAC->Rlmt.Port[i].PortDown && !(pAC->Rlmt.Port[i].CheckingState & SK_RLMT_PCS_RX)) { *pSelect = i; if (!pAC->Rlmt.Port[Active].PortDown && !(pAC->Rlmt.Port[Active].CheckingState & SK_RLMT_PCS_RX)) { *pSelect = Active; } if (!pAC->Rlmt.Port[PrefPort].PortDown && !(pAC->Rlmt.Port[PrefPort].CheckingState & SK_RLMT_PCS_RX)) { *pSelect = PrefPort; } PortFound = SK_TRUE; SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL, ("SK_RLMT_SELECT_NOTSUSPECT found Port %d up and not check RX.\n", *pSelect)); break; } } return (PortFound); } /* SkRlmtSelectNotSuspect */ /****************************************************************************** * * SkRlmtSelectUp - select new active port, criteria 3, 4 (CLP) * * Description: * This routine selects a port that is up. * * Context: * runtime, pageable? * * Returns: * SK_BOOL */ RLMT_STATIC SK_BOOL SkRlmtSelectUp( SK_AC *pAC, /* Adapter Context */ SK_IOC IoC, /* I/O Context */ SK_U32 Active, /* Active port */ SK_U32 PrefPort, /* Preferred port */ SK_U32 *pSelect, /* New active port */ SK_BOOL AutoNegDone) /* Successfully auto-negotiated? */ { SK_U32 i; SK_BOOL PortFound; PortFound = SK_FALSE; /* Select first port that is PortUp. */ for (i = 0; i < (SK_U32)pAC->GIni.GIMacsFound; i++) { if (pAC->Rlmt.Port[i].PortState == SK_RLMT_PS_UP && pAC->GIni.GP[i].PAutoNegFail != AutoNegDone) { *pSelect = i; if (pAC->Rlmt.Port[Active].PortState == SK_RLMT_PS_UP && pAC->GIni.GP[Active].PAutoNegFail != AutoNegDone) { *pSelect = Active; } if (pAC->Rlmt.Port[PrefPort].PortState == SK_RLMT_PS_UP && pAC->GIni.GP[PrefPort].PAutoNegFail != AutoNegDone) { *pSelect = PrefPort; } PortFound = SK_TRUE; SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL, ("SK_RLMT_SELECT_UP found Port %d up.\n", *pSelect)); break; } } return (PortFound); } /* SkRlmtSelectUp */ /****************************************************************************** * * SkRlmtSelectGoingUp - select new active port, criteria 5, 6 (CLP) * * Description: * This routine selects the port that is going up for the longest time. * * Context: * runtime, pageable? * * Returns: * SK_BOOL */ RLMT_STATIC SK_BOOL SkRlmtSelectGoingUp( SK_AC *pAC, /* Adapter Context */ SK_IOC IoC, /* I/O Context */ SK_U32 Active, /* Active port */ SK_U32 PrefPort, /* Preferred port */ SK_U32 *pSelect, /* New active port */ SK_BOOL AutoNegDone) /* Successfully auto-negotiated? */ { SK_U64 GuTimeStamp; SK_U32 i; SK_BOOL PortFound; GuTimeStamp = 0; PortFound = SK_FALSE; /* Select port that is PortGoingUp for the longest time. */ for (i = 0; i < (SK_U32)pAC->GIni.GIMacsFound; i++) { if (pAC->Rlmt.Port[i].PortState == SK_RLMT_PS_GOING_UP && pAC->GIni.GP[i].PAutoNegFail != AutoNegDone) { GuTimeStamp = pAC->Rlmt.Port[i].GuTimeStamp; *pSelect = i; PortFound = SK_TRUE; break; } } if (!PortFound) { return (SK_FALSE); } for (i = *pSelect + 1; i < (SK_U32)pAC->GIni.GIMacsFound; i++) { if (pAC->Rlmt.Port[i].PortState == SK_RLMT_PS_GOING_UP && pAC->Rlmt.Port[i].GuTimeStamp < GuTimeStamp && pAC->GIni.GP[i].PAutoNegFail != AutoNegDone) { GuTimeStamp = pAC->Rlmt.Port[i].GuTimeStamp; *pSelect = i; } } SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL, ("SK_RLMT_SELECT_GOINGUP found Port %d going up.\n", *pSelect)); return (SK_TRUE); } /* SkRlmtSelectGoingUp */ /****************************************************************************** * * SkRlmtSelectDown - select new active port, criteria 7, 8 (CLP) * * Description: * This routine selects a port that is down. * * Context: * runtime, pageable? * * Returns: * SK_BOOL */ RLMT_STATIC SK_BOOL SkRlmtSelectDown( SK_AC *pAC, /* Adapter Context */ SK_IOC IoC, /* I/O Context */ SK_U32 Active, /* Active port */ SK_U32 PrefPort, /* Preferred port */ SK_U32 *pSelect, /* New active port */ SK_BOOL AutoNegDone) /* Successfully auto-negotiated? */ { SK_U32 i; SK_BOOL PortFound; PortFound = SK_FALSE; /* Select first port that is PortDown. */ for (i = 0; i < (SK_U32)pAC->GIni.GIMacsFound; i++) { if (pAC->Rlmt.Port[i].PortState == SK_RLMT_PS_DOWN && pAC->GIni.GP[i].PAutoNegFail != AutoNegDone) { *pSelect = i; if (pAC->Rlmt.Port[Active].PortState == SK_RLMT_PS_DOWN && pAC->GIni.GP[Active].PAutoNegFail != AutoNegDone) { *pSelect = Active; } if (pAC->Rlmt.Port[PrefPort].PortState == SK_RLMT_PS_DOWN && pAC->GIni.GP[PrefPort].PAutoNegFail != AutoNegDone) { *pSelect = PrefPort; } PortFound = SK_TRUE; SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL, ("SK_RLMT_SELECT_DOWN found Port %d down.\n", *pSelect)); break; } } return (PortFound); } /* SkRlmtSelectDown */ /****************************************************************************** * * SkRlmtCheckSwitch - select new active port and switch to it * * Description: * This routine decides which port should be the active one and queues * port switching if necessary. * * Context: * runtime, pageable? * * Returns: * Nothing. */ RLMT_STATIC void SkRlmtCheckSwitch( SK_AC *pAC, /* Adapter Context */ SK_IOC IoC, /* I/O Context */ SK_U32 NetIdx) /* Net index */ { SK_EVPARA Para; SK_U32 Active; SK_U32 PrefPort; SK_U32 i; SK_BOOL PortFound; Active = pAC->Rlmt.Net[NetIdx].ActivePort; /* Index of active port. */ PrefPort = pAC->Rlmt.Net[NetIdx].PrefPort; /* Index of preferred port. */ PortFound = SK_FALSE; pAC->Rlmt.CheckSwitch = SK_FALSE; #if 0 /* RW 2001/10/18 - active port becomes always prefered one */ if (pAC->Rlmt.Net[NetIdx].Preference == 0xFFFFFFFF) { /* Automatic */ /* disable auto-fail back */ PrefPort = Active; } #endif if (pAC->Rlmt.Net[NetIdx].LinksUp == 0) { /* Last link went down - shut down the net. */ pAC->Rlmt.Net[NetIdx].RlmtState = SK_RLMT_RS_NET_DOWN; Para.Para32[0] = SK_RLMT_NET_DOWN_TEMP; Para.Para32[1] = NetIdx; SkEventQueue(pAC, SKGE_DRV, SK_DRV_NET_DOWN, Para); Para.Para32[0] = pAC->Rlmt.Net[NetIdx]. Port[pAC->Rlmt.Net[NetIdx].ActivePort]->PortNumber; Para.Para32[1] = NetIdx; SkEventQueue(pAC, SKGE_PNMI, SK_PNMI_EVT_RLMT_ACTIVE_DOWN, Para); return; } /* pAC->Rlmt.LinksUp == 0 */ else if (pAC->Rlmt.Net[NetIdx].LinksUp == 1 && pAC->Rlmt.Net[NetIdx].RlmtState == SK_RLMT_RS_NET_DOWN) { /* First link came up - get the net up. */ pAC->Rlmt.Net[NetIdx].RlmtState = SK_RLMT_RS_NET_UP; /* * If pAC->Rlmt.ActivePort != Para.Para32[0], * the DRV switches to the port that came up. */ for (i = 0; i < pAC->Rlmt.Net[NetIdx].NumPorts; i++) { if (!pAC->Rlmt.Net[NetIdx].Port[i]->LinkDown) { if (!pAC->Rlmt.Net[NetIdx].Port[Active]->LinkDown) { i = Active; } if (!pAC->Rlmt.Net[NetIdx].Port[PrefPort]->LinkDown) { i = PrefPort; } PortFound = SK_TRUE; break; } } if (PortFound) { Para.Para32[0] = pAC->Rlmt.Net[NetIdx].Port[i]->PortNumber; Para.Para32[1] = NetIdx; SkEventQueue(pAC, SKGE_PNMI, SK_PNMI_EVT_RLMT_ACTIVE_UP, Para); pAC->Rlmt.Net[NetIdx].ActivePort = i; Para.Para32[0] = pAC->Rlmt.Net[NetIdx].Port[i]->PortNumber; Para.Para32[1] = NetIdx; SkEventQueue(pAC, SKGE_DRV, SK_DRV_NET_UP, Para); if (pAC->Rlmt.NumNets == 1) { if ((pAC->Rlmt.Net[NetIdx].RlmtMode & SK_RLMT_TRANSPARENT) == 0 && (Para.pParaPtr = SkRlmtBuildPacket(pAC, IoC, pAC->Rlmt.Net[NetIdx].Port[i]->PortNumber, SK_PACKET_ANNOUNCE, &pAC->Addr.Net[NetIdx]. CurrentMacAddress, &SkRlmtMcAddr)) != NULL) { /* * Send announce packet to RLMT multicast address to force * switches to learn the new location of the logical MAC address. */ SkEventQueue(pAC, SKGE_DRV, SK_DRV_RLMT_SEND, Para); } } } else { SK_ERR_LOG(pAC, SK_ERRCL_SW, SKERR_RLMT_E007, SKERR_RLMT_E007_MSG); } return; } /* LinksUp == 1 && RlmtState == SK_RLMT_RS_NET_DOWN */ else { /* Cannot be reached in dual-net mode. */ Para.Para32[0] = Active; /* * Preselection: * If RLMT Mode != CheckLinkState * select port that received a broadcast frame substantially later * than all other ports * else select first port that is not SuspectRx * else select first port that is PortUp * else select port that is PortGoingUp for the longest time * else select first port that is PortDown * else stop. * * For the preselected port: * If ActivePort is equal in quality, select ActivePort. * * If PrefPort is equal in quality, select PrefPort. * * If ActivePort != SelectedPort, * If old ActivePort is LinkDown, * SwitchHard * else * SwitchSoft */ /* check of ChgBcPrio flag added */ if ((pAC->Rlmt.Net[0].RlmtMode != SK_RLMT_MODE_CLS) && (!pAC->Rlmt.Net[0].ChgBcPrio)) { if (!PortFound) { PortFound = SkRlmtSelectBcRx( pAC, IoC, Active, PrefPort, &Para.Para32[1]); } if (!PortFound) { PortFound = SkRlmtSelectNotSuspect( pAC, IoC, Active, PrefPort, &Para.Para32[1]); } } /* pAC->Rlmt.RlmtMode != SK_RLMT_MODE_CLS */ /* with changed priority for last broadcast received */ if ((pAC->Rlmt.Net[0].RlmtMode != SK_RLMT_MODE_CLS) && (pAC->Rlmt.Net[0].ChgBcPrio)) { if (!PortFound) { PortFound = SkRlmtSelectNotSuspect( pAC, IoC, Active, PrefPort, &Para.Para32[1]); } if (!PortFound) { PortFound = SkRlmtSelectBcRx( pAC, IoC, Active, PrefPort, &Para.Para32[1]); } } /* pAC->Rlmt.RlmtMode != SK_RLMT_MODE_CLS */ if (!PortFound) { PortFound = SkRlmtSelectUp( pAC, IoC, Active, PrefPort, &Para.Para32[1], AUTONEG_SUCCESS); } if (!PortFound) { PortFound = SkRlmtSelectUp( pAC, IoC, Active, PrefPort, &Para.Para32[1], AUTONEG_FAILED); } if (!PortFound) { PortFound = SkRlmtSelectGoingUp( pAC, IoC, Active, PrefPort, &Para.Para32[1], AUTONEG_SUCCESS); } if (!PortFound) { PortFound = SkRlmtSelectGoingUp( pAC, IoC, Active, PrefPort, &Para.Para32[1], AUTONEG_FAILED); } if (pAC->Rlmt.Net[0].RlmtMode != SK_RLMT_MODE_CLS) { if (!PortFound) { PortFound = SkRlmtSelectDown(pAC, IoC, Active, PrefPort, &Para.Para32[1], AUTONEG_SUCCESS); } if (!PortFound) { PortFound = SkRlmtSelectDown(pAC, IoC, Active, PrefPort, &Para.Para32[1], AUTONEG_FAILED); } } /* pAC->Rlmt.RlmtMode != SK_RLMT_MODE_CLS */ if (PortFound) { if (Para.Para32[1] != Active) { SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL, ("Active: %d, Para1: %d.\n", Active, Para.Para32[1])); pAC->Rlmt.Net[NetIdx].ActivePort = Para.Para32[1]; Para.Para32[0] = pAC->Rlmt.Net[NetIdx]. Port[Para.Para32[0]]->PortNumber; Para.Para32[1] = pAC->Rlmt.Net[NetIdx]. Port[Para.Para32[1]]->PortNumber; SK_HWAC_LINK_LED(pAC, IoC, Para.Para32[1], SK_LED_ACTIVE); if (pAC->Rlmt.Port[Active].LinkDown) { SkEventQueue(pAC, SKGE_DRV, SK_DRV_SWITCH_HARD, Para); } else { SK_HWAC_LINK_LED(pAC, IoC, Para.Para32[0], SK_LED_STANDBY); SkEventQueue(pAC, SKGE_DRV, SK_DRV_SWITCH_SOFT, Para); } Para.Para32[1] = NetIdx; Para.Para32[0] = pAC->Rlmt.Net[NetIdx].Port[Para.Para32[0]]->PortNumber; SkEventQueue(pAC, SKGE_PNMI, SK_PNMI_EVT_RLMT_ACTIVE_DOWN, Para); Para.Para32[0] = pAC->Rlmt.Net[NetIdx]. Port[pAC->Rlmt.Net[NetIdx].ActivePort]->PortNumber; SkEventQueue(pAC, SKGE_PNMI, SK_PNMI_EVT_RLMT_ACTIVE_UP, Para); if ((pAC->Rlmt.Net[NetIdx].RlmtMode & SK_RLMT_TRANSPARENT) == 0 && (Para.pParaPtr = SkRlmtBuildPacket(pAC, IoC, Para.Para32[0], SK_PACKET_ANNOUNCE, &pAC->Addr.Net[NetIdx].CurrentMacAddress, &SkRlmtMcAddr)) != NULL) { /* * Send announce packet to RLMT multicast address to force * switches to learn the new location of the logical * MAC address. */ SkEventQueue(pAC, SKGE_DRV, SK_DRV_RLMT_SEND, Para); } /* (Para.pParaPtr = SkRlmtBuildPacket(...)) != NULL */ } /* Para.Para32[1] != Active */ } /* PortFound */ else { SK_ERR_LOG(pAC, SK_ERRCL_SW, SKERR_RLMT_E004, SKERR_RLMT_E004_MSG); } } /* LinksUp > 1 || LinksUp == 1 && RlmtState != SK_RLMT_RS_NET_DOWN */ return; } /* SkRlmtCheckSwitch */ /****************************************************************************** * * SkRlmtCheckSeg - Report if segmentation is detected * * Description: * This routine checks if the ports see different root bridges and reports * segmentation in such a case. * * Context: * runtime, pageable? * * Returns: * Nothing. */ RLMT_STATIC void SkRlmtCheckSeg( SK_AC *pAC, /* Adapter Context */ SK_IOC IoC, /* I/O Context */ SK_U32 NetIdx) /* Net number */ { SK_EVPARA Para; SK_RLMT_NET *pNet; SK_U32 i, j; SK_BOOL Equal; pNet = &pAC->Rlmt.Net[NetIdx]; pNet->RootIdSet = SK_FALSE; Equal = SK_TRUE; for (i = 0; i < pNet->NumPorts; i++) { if (pNet->Port[i]->LinkDown || !pNet->Port[i]->RootIdSet) { continue; } SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_DUMP, ("Root ID %d: %02x %02x %02x %02x %02x %02x %02x %02x.\n", i, pNet->Port[i]->Root.Id[0], pNet->Port[i]->Root.Id[1], pNet->Port[i]->Root.Id[2], pNet->Port[i]->Root.Id[3], pNet->Port[i]->Root.Id[4], pNet->Port[i]->Root.Id[5], pNet->Port[i]->Root.Id[6], pNet->Port[i]->Root.Id[7])); if (!pNet->RootIdSet) { pNet->Root = pNet->Port[i]->Root; pNet->RootIdSet = SK_TRUE; continue; } for (j = 0; j < 8; j ++) { Equal &= pNet->Port[i]->Root.Id[j] == pNet->Root.Id[j]; if (!Equal) { break; } } if (!Equal) { SK_ERR_LOG(pAC, SK_ERRCL_COMM, SKERR_RLMT_E005, SKERR_RLMT_E005_MSG); Para.Para32[0] = NetIdx; Para.Para32[1] = (SK_U32)-1; SkEventQueue(pAC, SKGE_PNMI, SK_PNMI_EVT_RLMT_SEGMENTATION, Para); pNet->CheckingState &= ~SK_RLMT_RCS_REPORT_SEG; /* 2000-03-06 RA: New. */ Para.Para32[0] = NetIdx; Para.Para32[1] = (SK_U32)-1; SkTimerStart(pAC, IoC, &pNet->SegTimer, SK_RLMT_SEG_TO_VAL, SKGE_RLMT, SK_RLMT_SEG_TIM, Para); break; } } /* for (i = 0; i < pNet->NumPorts; i++) */ /* 2000-03-06 RA: Moved here. */ /* Segmentation check not running anymore. */ pNet->CheckingState &= ~SK_RLMT_RCS_SEG; } /* SkRlmtCheckSeg */ /****************************************************************************** * * SkRlmtPortStart - initialize port variables and start port * * Description: * This routine initializes a port's variables and issues a PORT_START * to the HWAC module. This handles retries if the start fails or the * link eventually goes down. * * Context: * runtime, pageable? * * Returns: * Nothing */ RLMT_STATIC void SkRlmtPortStart( SK_AC *pAC, /* Adapter Context */ SK_IOC IoC, /* I/O Context */ SK_U32 PortNumber) /* Port number */ { SK_EVPARA Para; pAC->Rlmt.Port[PortNumber].PortState = SK_RLMT_PS_LINK_DOWN; pAC->Rlmt.Port[PortNumber].PortStarted = SK_TRUE; pAC->Rlmt.Port[PortNumber].LinkDown = SK_TRUE; pAC->Rlmt.Port[PortNumber].PortDown = SK_TRUE; pAC->Rlmt.Port[PortNumber].CheckingState = 0; pAC->Rlmt.Port[PortNumber].RootIdSet = SK_FALSE; Para.Para32[0] = PortNumber; Para.Para32[1] = (SK_U32)-1; SkEventQueue(pAC, SKGE_HWAC, SK_HWEV_PORT_START, Para); } /* SkRlmtPortStart */ /****************************************************************************** * * SkRlmtEvtPortStartTim - PORT_START_TIM * * Description: * This routine handles PORT_START_TIM events. * * Context: * runtime, pageable? * may be called after SK_INIT_IO * * Returns: * Nothing */ RLMT_STATIC void SkRlmtEvtPortStartTim( SK_AC *pAC, /* Adapter Context */ SK_IOC IoC, /* I/O Context */ SK_EVPARA Para) /* SK_U32 PortNumber; SK_U32 -1 */ { SK_U32 i; SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL, ("SK_RLMT_PORTSTART_TIMEOUT Port %d Event BEGIN.\n", Para.Para32[0])); if (Para.Para32[1] != (SK_U32)-1) { SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL, ("Bad Parameter.\n")); SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL, ("SK_RLMT_PORTSTART_TIMEOUT Event EMPTY.\n")); return; } /* * Used to start non-preferred ports if the preferred one * does not come up. * This timeout needs only be set when starting the first * (preferred) port. */ if (pAC->Rlmt.Port[Para.Para32[0]].LinkDown) { /* PORT_START failed. */ for (i = 0; i < pAC->Rlmt.Port[Para.Para32[0]].Net->NumPorts; i++) { if (!pAC->Rlmt.Port[Para.Para32[0]].Net->Port[i]->PortStarted) { SkRlmtPortStart(pAC, IoC, pAC->Rlmt.Port[Para.Para32[0]].Net->Port[i]->PortNumber); } } } SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL, ("SK_RLMT_PORTSTART_TIMEOUT Event END.\n")); } /* SkRlmtEvtPortStartTim */ /****************************************************************************** * * SkRlmtEvtLinkUp - LINK_UP * * Description: * This routine handles LLINK_UP events. * * Context: * runtime, pageable? * may be called after SK_INIT_IO * * Returns: * Nothing */ RLMT_STATIC void SkRlmtEvtLinkUp( SK_AC *pAC, /* Adapter Context */ SK_IOC IoC, /* I/O Context */ SK_EVPARA Para) /* SK_U32 PortNumber; SK_U32 Undefined */ { SK_U32 i; SK_RLMT_PORT *pRPort; SK_EVPARA Para2; SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL, ("SK_RLMT_LINK_UP Port %d Event BEGIN.\n", Para.Para32[0])); pRPort = &pAC->Rlmt.Port[Para.Para32[0]]; if (!pRPort->PortStarted) { SK_ERR_LOG(pAC, SK_ERRCL_SW, SKERR_RLMT_E008, SKERR_RLMT_E008_MSG); SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL, ("SK_RLMT_LINK_UP Event EMPTY.\n")); return; } if (!pRPort->LinkDown) { /* RA;:;: Any better solution? */ SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL, ("SK_RLMT_LINK_UP Event EMPTY.\n")); return; } SkTimerStop(pAC, IoC, &pRPort->UpTimer); SkTimerStop(pAC, IoC, &pRPort->DownRxTimer); SkTimerStop(pAC, IoC, &pRPort->DownTxTimer); /* Do something if timer already fired? */ pRPort->LinkDown = SK_FALSE; pRPort->PortState = SK_RLMT_PS_GOING_UP; pRPort->GuTimeStamp = SkOsGetTime(pAC); pRPort->BcTimeStamp = 0; pRPort->Net->LinksUp++; if (pRPort->Net->LinksUp == 1) { SK_HWAC_LINK_LED(pAC, IoC, Para.Para32[0], SK_LED_ACTIVE); } else { SK_HWAC_LINK_LED(pAC, IoC, Para.Para32[0], SK_LED_STANDBY); } for (i = 0; i < pRPort->Net->NumPorts; i++) { if (!pRPort->Net->Port[i]->PortStarted) { SkRlmtPortStart(pAC, IoC, pRPort->Net->Port[i]->PortNumber); } } SkRlmtCheckSwitch(pAC, IoC, pRPort->Net->NetNumber); if (pRPort->Net->LinksUp >= 2) { if (pRPort->Net->RlmtMode & SK_RLMT_CHECK_LOC_LINK) { /* Build the check chain. */ SkRlmtBuildCheckChain(pAC, pRPort->Net->NetNumber); } } /* If the first link comes up, start the periodical RLMT timeout. */ if (pRPort->Net->NumPorts > 1 && pRPort->Net->LinksUp == 1 && (pRPort->Net->RlmtMode & SK_RLMT_CHECK_OTHERS) != 0) { Para2.Para32[0] = pRPort->Net->NetNumber; Para2.Para32[1] = (SK_U32)-1; SkTimerStart(pAC, IoC, &pRPort->Net->LocTimer, pRPort->Net->TimeoutValue, SKGE_RLMT, SK_RLMT_TIM, Para2); } Para2 = Para; Para2.Para32[1] = (SK_U32)-1; SkTimerStart(pAC, IoC, &pRPort->UpTimer, SK_RLMT_PORTUP_TIM_VAL, SKGE_RLMT, SK_RLMT_PORTUP_TIM, Para2); /* Later: if (pAC->Rlmt.RlmtMode & SK_RLMT_CHECK_LOC_LINK) && */ if (pAC->Rlmt.NumNets == 1) { if ((pRPort->Net->RlmtMode & SK_RLMT_TRANSPARENT) == 0 && (pRPort->Net->RlmtMode & SK_RLMT_CHECK_LINK) != 0 && (Para2.pParaPtr = SkRlmtBuildPacket(pAC, IoC, Para.Para32[0], SK_PACKET_ANNOUNCE, &pAC->Addr.Port[Para.Para32[0]].CurrentMacAddress, &SkRlmtMcAddr) ) != NULL) { /* Send "new" packet to RLMT multicast address. */ SkEventQueue(pAC, SKGE_DRV, SK_DRV_RLMT_SEND, Para2); } } if (pRPort->Net->RlmtMode & SK_RLMT_CHECK_SEG) { if ((Para2.pParaPtr = SkRlmtBuildSpanningTreePacket(pAC, IoC, Para.Para32[0])) != NULL) { pAC->Rlmt.Port[Para.Para32[0]].RootIdSet = SK_FALSE; pRPort->Net->CheckingState |= SK_RLMT_RCS_SEG | SK_RLMT_RCS_REPORT_SEG; SkEventQueue(pAC, SKGE_DRV, SK_DRV_RLMT_SEND, Para2); Para.Para32[1] = (SK_U32)-1; SkTimerStart(pAC, IoC, &pRPort->Net->SegTimer, SK_RLMT_SEG_TO_VAL, SKGE_RLMT, SK_RLMT_SEG_TIM, Para); } } SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL, ("SK_RLMT_LINK_UP Event END.\n")); } /* SkRlmtEvtLinkUp */ /****************************************************************************** * * SkRlmtEvtPortUpTim - PORT_UP_TIM * * Description: * This routine handles PORT_UP_TIM events. * * Context: * runtime, pageable? * may be called after SK_INIT_IO * * Returns: * Nothing */ RLMT_STATIC void SkRlmtEvtPortUpTim( SK_AC *pAC, /* Adapter Context */ SK_IOC IoC, /* I/O Context */ SK_EVPARA Para) /* SK_U32 PortNumber; SK_U32 -1 */ { SK_RLMT_PORT *pRPort; SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL, ("SK_RLMT_PORTUP_TIM Port %d Event BEGIN.\n", Para.Para32[0])); if (Para.Para32[1] != (SK_U32)-1) { SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL, ("Bad Parameter.\n")); SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL, ("SK_RLMT_PORTUP_TIM Event EMPTY.\n")); return; } pRPort = &pAC->Rlmt.Port[Para.Para32[0]]; if (pRPort->LinkDown || (pRPort->PortState == SK_RLMT_PS_UP)) { SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL, ("SK_RLMT_PORTUP_TIM Port %d Event EMPTY.\n", Para.Para32[0])); return; } pRPort->PortDown = SK_FALSE; pRPort->PortState = SK_RLMT_PS_UP; pRPort->Net->PortsUp++; if (pRPort->Net->RlmtState != SK_RLMT_RS_INIT) { if (pAC->Rlmt.NumNets <= 1) { SkRlmtCheckSwitch(pAC, IoC, pRPort->Net->NetNumber); } SkEventQueue(pAC, SKGE_PNMI, SK_PNMI_EVT_RLMT_PORT_UP, Para); } SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL, ("SK_RLMT_PORTUP_TIM Event END.\n")); } /* SkRlmtEvtPortUpTim */ /****************************************************************************** * * SkRlmtEvtPortDownTim - PORT_DOWN_* * * Description: * This routine handles PORT_DOWN_* events. * * Context: * runtime, pageable? * may be called after SK_INIT_IO * * Returns: * Nothing */ RLMT_STATIC void SkRlmtEvtPortDownX( SK_AC *pAC, /* Adapter Context */ SK_IOC IoC, /* I/O Context */ SK_U32 Event, /* Event code */ SK_EVPARA Para) /* SK_U32 PortNumber; SK_U32 -1 */ { SK_RLMT_PORT *pRPort; SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL, ("SK_RLMT_PORTDOWN* Port %d Event (%d) BEGIN.\n", Para.Para32[0], Event)); if (Para.Para32[1] != (SK_U32)-1) { SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL, ("Bad Parameter.\n")); SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL, ("SK_RLMT_PORTDOWN* Event EMPTY.\n")); return; } pRPort = &pAC->Rlmt.Port[Para.Para32[0]]; if (!pRPort->PortStarted || (Event == SK_RLMT_PORTDOWN_TX_TIM && !(pRPort->CheckingState & SK_RLMT_PCS_TX))) { SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL, ("SK_RLMT_PORTDOWN* Event (%d) EMPTY.\n", Event)); return; } /* Stop port's timers. */ SkTimerStop(pAC, IoC, &pRPort->UpTimer); SkTimerStop(pAC, IoC, &pRPort->DownRxTimer); SkTimerStop(pAC, IoC, &pRPort->DownTxTimer); if (pRPort->PortState != SK_RLMT_PS_LINK_DOWN) { pRPort->PortState = SK_RLMT_PS_DOWN; } if (!pRPort->PortDown) { pRPort->Net->PortsUp--; pRPort->PortDown = SK_TRUE; SkEventQueue(pAC, SKGE_PNMI, SK_PNMI_EVT_RLMT_PORT_DOWN, Para); } pRPort->PacketsPerTimeSlot = 0; /* pRPort->DataPacketsPerTimeSlot = 0; */ pRPort->BpduPacketsPerTimeSlot = 0; pRPort->BcTimeStamp = 0; /* * RA;:;: To be checked: * - actions at RLMT_STOP: We should not switch anymore. */ if (pRPort->Net->RlmtState != SK_RLMT_RS_INIT) { if (Para.Para32[0] == pRPort->Net->Port[pRPort->Net->ActivePort]->PortNumber) { /* Active Port went down. */ SkRlmtCheckSwitch(pAC, IoC, pRPort->Net->NetNumber); } } SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL, ("SK_RLMT_PORTDOWN* Event (%d) END.\n", Event)); } /* SkRlmtEvtPortDownX */ /****************************************************************************** * * SkRlmtEvtLinkDown - LINK_DOWN * * Description: * This routine handles LINK_DOWN events. * * Context: * runtime, pageable? * may be called after SK_INIT_IO * * Returns: * Nothing */ RLMT_STATIC void SkRlmtEvtLinkDown( SK_AC *pAC, /* Adapter Context */ SK_IOC IoC, /* I/O Context */ SK_EVPARA Para) /* SK_U32 PortNumber; SK_U32 Undefined */ { SK_RLMT_PORT *pRPort; pRPort = &pAC->Rlmt.Port[Para.Para32[0]]; SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL, ("SK_RLMT_LINK_DOWN Port %d Event BEGIN.\n", Para.Para32[0])); if (!pAC->Rlmt.Port[Para.Para32[0]].LinkDown) { pRPort->Net->LinksUp--; pRPort->LinkDown = SK_TRUE; pRPort->PortState = SK_RLMT_PS_LINK_DOWN; SK_HWAC_LINK_LED(pAC, IoC, Para.Para32[0], SK_LED_OFF); if ((pRPort->Net->RlmtMode & SK_RLMT_CHECK_LOC_LINK) != 0) { /* Build the check chain. */ SkRlmtBuildCheckChain(pAC, pRPort->Net->NetNumber); } /* Ensure that port is marked down. */ Para.Para32[1] = -1; (void)SkRlmtEvent(pAC, IoC, SK_RLMT_PORTDOWN, Para); } SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL, ("SK_RLMT_LINK_DOWN Event END.\n")); } /* SkRlmtEvtLinkDown */ /****************************************************************************** * * SkRlmtEvtPortAddr - PORT_ADDR * * Description: * This routine handles PORT_ADDR events. * * Context: * runtime, pageable? * may be called after SK_INIT_IO * * Returns: * Nothing */ RLMT_STATIC void SkRlmtEvtPortAddr( SK_AC *pAC, /* Adapter Context */ SK_IOC IoC, /* I/O Context */ SK_EVPARA Para) /* SK_U32 PortNumber; SK_U32 -1 */ { SK_U32 i, j; SK_RLMT_PORT *pRPort; SK_MAC_ADDR *pOldMacAddr; SK_MAC_ADDR *pNewMacAddr; SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL, ("SK_RLMT_PORT_ADDR Port %d Event BEGIN.\n", Para.Para32[0])); if (Para.Para32[1] != (SK_U32)-1) { SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL, ("Bad Parameter.\n")); SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL, ("SK_RLMT_PORT_ADDR Event EMPTY.\n")); return; } /* Port's physical MAC address changed. */ pOldMacAddr = &pAC->Addr.Port[Para.Para32[0]].PreviousMacAddress; pNewMacAddr = &pAC->Addr.Port[Para.Para32[0]].CurrentMacAddress; /* * NOTE: This is not scalable for solutions where ports are * checked remotely. There, we need to send an RLMT * address change packet - and how do we ensure delivery? */ for (i = 0; i < (SK_U32)pAC->GIni.GIMacsFound; i++) { pRPort = &pAC->Rlmt.Port[i]; for (j = 0; j < pRPort->PortsChecked; j++) { if (SK_ADDR_EQUAL( pRPort->PortCheck[j].CheckAddr.a, pOldMacAddr->a)) { pRPort->PortCheck[j].CheckAddr = *pNewMacAddr; } } } SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL, ("SK_RLMT_PORT_ADDR Event END.\n")); } /* SkRlmtEvtPortAddr */ /****************************************************************************** * * SkRlmtEvtStart - START * * Description: * This routine handles START events. * * Context: * runtime, pageable? * may be called after SK_INIT_IO * * Returns: * Nothing */ RLMT_STATIC void SkRlmtEvtStart( SK_AC *pAC, /* Adapter Context */ SK_IOC IoC, /* I/O Context */ SK_EVPARA Para) /* SK_U32 NetNumber; SK_U32 -1 */ { SK_EVPARA Para2; SK_U32 PortIdx; SK_U32 PortNumber; SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL, ("SK_RLMT_START Net %d Event BEGIN.\n", Para.Para32[0])); if (Para.Para32[1] != (SK_U32)-1) { SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL, ("Bad Parameter.\n")); SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL, ("SK_RLMT_START Event EMPTY.\n")); return; } if (Para.Para32[0] >= pAC->Rlmt.NumNets) { SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL, ("Bad NetNumber %d.\n", Para.Para32[0])); SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL, ("SK_RLMT_START Event EMPTY.\n")); return; } if (pAC->Rlmt.Net[Para.Para32[0]].RlmtState != SK_RLMT_RS_INIT) { SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL, ("SK_RLMT_START Event EMPTY.\n")); return; } if (pAC->Rlmt.NetsStarted >= pAC->Rlmt.NumNets) { SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL, ("All nets should have been started.\n")); SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL, ("SK_RLMT_START Event EMPTY.\n")); return; } if (pAC->Rlmt.Net[Para.Para32[0]].PrefPort >= pAC->Rlmt.Net[Para.Para32[0]].NumPorts) { SK_ERR_LOG(pAC, SK_ERRCL_SW, SKERR_RLMT_E009, SKERR_RLMT_E009_MSG); /* Change PrefPort to internal default. */ Para2.Para32[0] = 0xFFFFFFFF; Para2.Para32[1] = Para.Para32[0]; (void)SkRlmtEvent(pAC, IoC, SK_RLMT_PREFPORT_CHANGE, Para2); } PortIdx = pAC->Rlmt.Net[Para.Para32[0]].PrefPort; PortNumber = pAC->Rlmt.Net[Para.Para32[0]].Port[PortIdx]->PortNumber; pAC->Rlmt.Net[Para.Para32[0]].LinksUp = 0; pAC->Rlmt.Net[Para.Para32[0]].PortsUp = 0; pAC->Rlmt.Net[Para.Para32[0]].CheckingState = 0; pAC->Rlmt.Net[Para.Para32[0]].RlmtState = SK_RLMT_RS_NET_DOWN; /* Start preferred port. */ SkRlmtPortStart(pAC, IoC, PortNumber); /* Start Timer (for first port only). */ Para2.Para32[0] = PortNumber; Para2.Para32[1] = (SK_U32)-1; SkTimerStart(pAC, IoC, &pAC->Rlmt.Port[PortNumber].UpTimer, SK_RLMT_PORTSTART_TIM_VAL, SKGE_RLMT, SK_RLMT_PORTSTART_TIM, Para2); pAC->Rlmt.NetsStarted++; SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL, ("SK_RLMT_START Event END.\n")); } /* SkRlmtEvtStart */ /****************************************************************************** * * SkRlmtEvtStop - STOP * * Description: * This routine handles STOP events. * * Context: * runtime, pageable? * may be called after SK_INIT_IO * * Returns: * Nothing */ RLMT_STATIC void SkRlmtEvtStop( SK_AC *pAC, /* Adapter Context */ SK_IOC IoC, /* I/O Context */ SK_EVPARA Para) /* SK_U32 NetNumber; SK_U32 -1 */ { SK_EVPARA Para2; SK_U32 PortNumber; SK_U32 i; SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL, ("SK_RLMT_STOP Net %d Event BEGIN.\n", Para.Para32[0])); if (Para.Para32[1] != (SK_U32)-1) { SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL, ("Bad Parameter.\n")); SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL, ("SK_RLMT_STOP Event EMPTY.\n")); return; } if (Para.Para32[0] >= pAC->Rlmt.NumNets) { SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL, ("Bad NetNumber %d.\n", Para.Para32[0])); SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL, ("SK_RLMT_STOP Event EMPTY.\n")); return; } if (pAC->Rlmt.Net[Para.Para32[0]].RlmtState == SK_RLMT_RS_INIT) { SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL, ("SK_RLMT_STOP Event EMPTY.\n")); return; } if (pAC->Rlmt.NetsStarted == 0) { SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL, ("All nets are stopped.\n")); SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL, ("SK_RLMT_STOP Event EMPTY.\n")); return; } /* Stop RLMT timers. */ SkTimerStop(pAC, IoC, &pAC->Rlmt.Net[Para.Para32[0]].LocTimer); SkTimerStop(pAC, IoC, &pAC->Rlmt.Net[Para.Para32[0]].SegTimer); /* Stop net. */ pAC->Rlmt.Net[Para.Para32[0]].RlmtState = SK_RLMT_RS_INIT; pAC->Rlmt.Net[Para.Para32[0]].RootIdSet = SK_FALSE; Para2.Para32[0] = SK_RLMT_NET_DOWN_FINAL; Para2.Para32[1] = Para.Para32[0]; /* Net# */ SkEventQueue(pAC, SKGE_DRV, SK_DRV_NET_DOWN, Para2); /* Stop ports. */ for (i = 0; i < pAC->Rlmt.Net[Para.Para32[0]].NumPorts; i++) { PortNumber = pAC->Rlmt.Net[Para.Para32[0]].Port[i]->PortNumber; if (pAC->Rlmt.Port[PortNumber].PortState != SK_RLMT_PS_INIT) { SkTimerStop(pAC, IoC, &pAC->Rlmt.Port[PortNumber].UpTimer); SkTimerStop(pAC, IoC, &pAC->Rlmt.Port[PortNumber].DownRxTimer); SkTimerStop(pAC, IoC, &pAC->Rlmt.Port[PortNumber].DownTxTimer); pAC->Rlmt.Port[PortNumber].PortState = SK_RLMT_PS_INIT; pAC->Rlmt.Port[PortNumber].RootIdSet = SK_FALSE; pAC->Rlmt.Port[PortNumber].PortStarted = SK_FALSE; Para2.Para32[0] = PortNumber; Para2.Para32[1] = (SK_U32)-1; SkEventQueue(pAC, SKGE_HWAC, SK_HWEV_PORT_STOP, Para2); } } pAC->Rlmt.NetsStarted--; SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL, ("SK_RLMT_STOP Event END.\n")); } /* SkRlmtEvtStop */ /****************************************************************************** * * SkRlmtEvtTim - TIM * * Description: * This routine handles TIM events. * * Context: * runtime, pageable? * may be called after SK_INIT_IO * * Returns: * Nothing */ RLMT_STATIC void SkRlmtEvtTim( SK_AC *pAC, /* Adapter Context */ SK_IOC IoC, /* I/O Context */ SK_EVPARA Para) /* SK_U32 NetNumber; SK_U32 -1 */ { SK_RLMT_PORT *pRPort; SK_U32 Timeout; SK_U32 NewTimeout; SK_U32 PortNumber; SK_U32 i; SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL, ("SK_RLMT_TIM Event BEGIN.\n")); if (Para.Para32[1] != (SK_U32)-1) { SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL, ("Bad Parameter.\n")); SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL, ("SK_RLMT_TIM Event EMPTY.\n")); return; } if ((pAC->Rlmt.Net[Para.Para32[0]].RlmtMode & SK_RLMT_CHECK_OTHERS) == 0 || pAC->Rlmt.Net[Para.Para32[0]].LinksUp == 0) { /* Mode changed or all links down: No more link checking. */ return; } #if 0 pAC->Rlmt.SwitchCheckCounter--; if (pAC->Rlmt.SwitchCheckCounter == 0) { pAC->Rlmt.SwitchCheckCounter; } #endif /* 0 */ NewTimeout = SK_RLMT_DEF_TO_VAL; for (i = 0; i < pAC->Rlmt.Net[Para.Para32[0]].NumPorts; i++) { PortNumber = pAC->Rlmt.Net[Para.Para32[0]].Port[i]->PortNumber; pRPort = &pAC->Rlmt.Port[PortNumber]; if (!pRPort->LinkDown) { Timeout = SkRlmtCheckPort(pAC, IoC, PortNumber); if (Timeout < NewTimeout) { NewTimeout = Timeout; } /* * These counters should be set to 0 for all ports before the * first frame is sent in the next loop. */ pRPort->PacketsPerTimeSlot = 0; /* pRPort->DataPacketsPerTimeSlot = 0; */ pRPort->BpduPacketsPerTimeSlot = 0; } } pAC->Rlmt.Net[Para.Para32[0]].TimeoutValue = NewTimeout; if (pAC->Rlmt.Net[Para.Para32[0]].LinksUp > 1) { /* * If checking remote ports, also send packets if * (LinksUp == 1) && * this port checks at least one (remote) port. */ /* * Must be new loop, as SkRlmtCheckPort can request to * check segmentation when e.g. checking the last port. */ for (i = 0; i < pAC->Rlmt.Net[Para.Para32[0]].NumPorts; i++) { if (!pAC->Rlmt.Net[Para.Para32[0]].Port[i]->LinkDown) { SkRlmtSend(pAC, IoC, pAC->Rlmt.Net[Para.Para32[0]].Port[i]->PortNumber); } } } SkTimerStart(pAC, IoC, &pAC->Rlmt.Net[Para.Para32[0]].LocTimer, pAC->Rlmt.Net[Para.Para32[0]].TimeoutValue, SKGE_RLMT, SK_RLMT_TIM, Para); if (pAC->Rlmt.Net[Para.Para32[0]].LinksUp > 1 && (pAC->Rlmt.Net[Para.Para32[0]].RlmtMode & SK_RLMT_CHECK_SEG) && (pAC->Rlmt.Net[Para.Para32[0]].CheckingState & SK_RLMT_RCS_START_SEG)) { SkTimerStart(pAC, IoC, &pAC->Rlmt.Net[Para.Para32[0]].SegTimer, SK_RLMT_SEG_TO_VAL, SKGE_RLMT, SK_RLMT_SEG_TIM, Para); pAC->Rlmt.Net[Para.Para32[0]].CheckingState &= ~SK_RLMT_RCS_START_SEG; pAC->Rlmt.Net[Para.Para32[0]].CheckingState |= SK_RLMT_RCS_SEG | SK_RLMT_RCS_REPORT_SEG; } SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL, ("SK_RLMT_TIM Event END.\n")); } /* SkRlmtEvtTim */ /****************************************************************************** * * SkRlmtEvtSegTim - SEG_TIM * * Description: * This routine handles SEG_TIM events. * * Context: * runtime, pageable? * may be called after SK_INIT_IO * * Returns: * Nothing */ RLMT_STATIC void SkRlmtEvtSegTim( SK_AC *pAC, /* Adapter Context */ SK_IOC IoC, /* I/O Context */ SK_EVPARA Para) /* SK_U32 NetNumber; SK_U32 -1 */ { #ifdef xDEBUG int j; #endif /* DEBUG */ SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL, ("SK_RLMT_SEG_TIM Event BEGIN.\n")); if (Para.Para32[1] != (SK_U32)-1) { SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL, ("Bad Parameter.\n")); SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL, ("SK_RLMT_SEG_TIM Event EMPTY.\n")); return; } #ifdef xDEBUG for (j = 0; j < pAC->Rlmt.Net[Para.Para32[0]].NumPorts; j++) { SK_ADDR_PORT *pAPort; SK_U32 k; SK_U16 *InAddr; SK_U8 InAddr8[6]; InAddr = (SK_U16 *)&InAddr8[0]; pAPort = pAC->Rlmt.Net[Para.Para32[0]].Port[j]->AddrPort; for (k = 0; k < pAPort->NextExactMatchRlmt; k++) { /* Get exact match address k from port j. */ XM_INADDR(IoC, pAC->Rlmt.Net[Para.Para32[0]].Port[j]->PortNumber, XM_EXM(k), InAddr); SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL, ("MC address %d on Port %u: %02x %02x %02x %02x %02x %02x -- %02x %02x %02x %02x %02x %02x.\n", k, pAC->Rlmt.Net[Para.Para32[0]].Port[j]->PortNumber, InAddr8[0], InAddr8[1], InAddr8[2], InAddr8[3], InAddr8[4], InAddr8[5], pAPort->Exact[k].a[0], pAPort->Exact[k].a[1], pAPort->Exact[k].a[2], pAPort->Exact[k].a[3], pAPort->Exact[k].a[4], pAPort->Exact[k].a[5])); } } #endif /* xDEBUG */ SkRlmtCheckSeg(pAC, IoC, Para.Para32[0]); SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL, ("SK_RLMT_SEG_TIM Event END.\n")); } /* SkRlmtEvtSegTim */ /****************************************************************************** * * SkRlmtEvtPacketRx - PACKET_RECEIVED * * Description: * This routine handles PACKET_RECEIVED events. * * Context: * runtime, pageable? * may be called after SK_INIT_IO * * Returns: * Nothing */ RLMT_STATIC void SkRlmtEvtPacketRx( SK_AC *pAC, /* Adapter Context */ SK_IOC IoC, /* I/O Context */ SK_EVPARA Para) /* SK_MBUF *pMb */ { SK_MBUF *pMb; SK_MBUF *pNextMb; SK_U32 NetNumber; SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL, ("SK_RLMT_PACKET_RECEIVED Event BEGIN.\n")); /* Should we ignore frames during port switching? */ #ifdef DEBUG pMb = Para.pParaPtr; if (pMb == NULL) { SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL, ("No mbuf.\n")); } else if (pMb->pNext != NULL) { SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL, ("More than one mbuf or pMb->pNext not set.\n")); } #endif /* DEBUG */ for (pMb = Para.pParaPtr; pMb != NULL; pMb = pNextMb) { pNextMb = pMb->pNext; pMb->pNext = NULL; NetNumber = pAC->Rlmt.Port[pMb->PortIdx].Net->NetNumber; if (pAC->Rlmt.Net[NetNumber].RlmtState == SK_RLMT_RS_INIT) { SkDrvFreeRlmtMbuf(pAC, IoC, pMb); } else { SkRlmtPacketReceive(pAC, IoC, pMb); } } SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL, ("SK_RLMT_PACKET_RECEIVED Event END.\n")); } /* SkRlmtEvtPacketRx */ /****************************************************************************** * * SkRlmtEvtStatsClear - STATS_CLEAR * * Description: * This routine handles STATS_CLEAR events. * * Context: * runtime, pageable? * may be called after SK_INIT_IO * * Returns: * Nothing */ RLMT_STATIC void SkRlmtEvtStatsClear( SK_AC *pAC, /* Adapter Context */ SK_IOC IoC, /* I/O Context */ SK_EVPARA Para) /* SK_U32 NetNumber; SK_U32 -1 */ { SK_U32 i; SK_RLMT_PORT *pRPort; SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL, ("SK_RLMT_STATS_CLEAR Event BEGIN.\n")); if (Para.Para32[1] != (SK_U32)-1) { SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL, ("Bad Parameter.\n")); SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL, ("SK_RLMT_STATS_CLEAR Event EMPTY.\n")); return; } if (Para.Para32[0] >= pAC->Rlmt.NumNets) { SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL, ("Bad NetNumber %d.\n", Para.Para32[0])); SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL, ("SK_RLMT_STATS_CLEAR Event EMPTY.\n")); return; } /* Clear statistics for logical and physical ports. */ for (i = 0; i < pAC->Rlmt.Net[Para.Para32[0]].NumPorts; i++) { pRPort = &pAC->Rlmt.Port[pAC->Rlmt.Net[Para.Para32[0]].Port[i]->PortNumber]; pRPort->TxHelloCts = 0; pRPort->RxHelloCts = 0; pRPort->TxSpHelloReqCts = 0; pRPort->RxSpHelloCts = 0; } SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL, ("SK_RLMT_STATS_CLEAR Event END.\n")); } /* SkRlmtEvtStatsClear */ /****************************************************************************** * * SkRlmtEvtStatsUpdate - STATS_UPDATE * * Description: * This routine handles STATS_UPDATE events. * * Context: * runtime, pageable? * may be called after SK_INIT_IO * * Returns: * Nothing */ RLMT_STATIC void SkRlmtEvtStatsUpdate( SK_AC *pAC, /* Adapter Context */ SK_IOC IoC, /* I/O Context */ SK_EVPARA Para) /* SK_U32 NetNumber; SK_U32 -1 */ { SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL, ("SK_RLMT_STATS_UPDATE Event BEGIN.\n")); if (Para.Para32[1] != (SK_U32)-1) { SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL, ("Bad Parameter.\n")); SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL, ("SK_RLMT_STATS_UPDATE Event EMPTY.\n")); return; } if (Para.Para32[0] >= pAC->Rlmt.NumNets) { SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL, ("Bad NetNumber %d.\n", Para.Para32[0])); SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL, ("SK_RLMT_STATS_UPDATE Event EMPTY.\n")); return; } /* Update statistics - currently always up-to-date. */ SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL, ("SK_RLMT_STATS_UPDATE Event END.\n")); } /* SkRlmtEvtStatsUpdate */ /****************************************************************************** * * SkRlmtEvtPrefportChange - PREFPORT_CHANGE * * Description: * This routine handles PREFPORT_CHANGE events. * * Context: * runtime, pageable? * may be called after SK_INIT_IO * * Returns: * Nothing */ RLMT_STATIC void SkRlmtEvtPrefportChange( SK_AC *pAC, /* Adapter Context */ SK_IOC IoC, /* I/O Context */ SK_EVPARA Para) /* SK_U32 PortIndex; SK_U32 NetNumber */ { SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL, ("SK_RLMT_PREFPORT_CHANGE to Port %d Event BEGIN.\n", Para.Para32[0])); if (Para.Para32[1] >= pAC->Rlmt.NumNets) { SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL, ("Bad NetNumber %d.\n", Para.Para32[1])); SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL, ("SK_RLMT_PREFPORT_CHANGE Event EMPTY.\n")); return; } /* 0xFFFFFFFF == auto-mode. */ if (Para.Para32[0] == 0xFFFFFFFF) { pAC->Rlmt.Net[Para.Para32[1]].PrefPort = SK_RLMT_DEF_PREF_PORT; } else { if (Para.Para32[0] >= pAC->Rlmt.Net[Para.Para32[1]].NumPorts) { SK_ERR_LOG(pAC, SK_ERRCL_SW, SKERR_RLMT_E010, SKERR_RLMT_E010_MSG); SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL, ("SK_RLMT_PREFPORT_CHANGE Event EMPTY.\n")); return; } pAC->Rlmt.Net[Para.Para32[1]].PrefPort = Para.Para32[0]; } pAC->Rlmt.Net[Para.Para32[1]].Preference = Para.Para32[0]; if (pAC->Rlmt.Net[Para.Para32[1]].RlmtState != SK_RLMT_RS_INIT) { SkRlmtCheckSwitch(pAC, IoC, Para.Para32[1]); } SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL, ("SK_RLMT_PREFPORT_CHANGE Event END.\n")); } /* SkRlmtEvtPrefportChange */ /****************************************************************************** * * SkRlmtEvtSetNets - SET_NETS * * Description: * This routine handles SET_NETS events. * * Context: * runtime, pageable? * may be called after SK_INIT_IO * * Returns: * Nothing */ RLMT_STATIC void SkRlmtEvtSetNets( SK_AC *pAC, /* Adapter Context */ SK_IOC IoC, /* I/O Context */ SK_EVPARA Para) /* SK_U32 NumNets; SK_U32 -1 */ { int i; SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL, ("SK_RLMT_SET_NETS Event BEGIN.\n")); if (Para.Para32[1] != (SK_U32)-1) { SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL, ("Bad Parameter.\n")); SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL, ("SK_RLMT_SET_NETS Event EMPTY.\n")); return; } if (Para.Para32[0] == 0 || Para.Para32[0] > SK_MAX_NETS || Para.Para32[0] > (SK_U32)pAC->GIni.GIMacsFound) { SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL, ("Bad number of nets: %d.\n", Para.Para32[0])); SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL, ("SK_RLMT_SET_NETS Event EMPTY.\n")); return; } if (Para.Para32[0] == pAC->Rlmt.NumNets) { /* No change. */ SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL, ("SK_RLMT_SET_NETS Event EMPTY.\n")); return; } /* Entering and leaving dual mode only allowed while nets are stopped. */ if (pAC->Rlmt.NetsStarted > 0) { SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL, ("Changing dual mode only allowed while all nets are stopped.\n")); SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL, ("SK_RLMT_SET_NETS Event EMPTY.\n")); return; } if (Para.Para32[0] == 1) { if (pAC->Rlmt.NumNets > 1) { /* Clear logical MAC addr from second net's active port. */ (void)SkAddrOverride(pAC, IoC, pAC->Rlmt.Net[1].Port[pAC->Addr. Net[1].ActivePort]->PortNumber, NULL, SK_ADDR_CLEAR_LOGICAL); pAC->Rlmt.Net[1].NumPorts = 0; } pAC->Rlmt.NumNets = Para.Para32[0]; for (i = 0; (SK_U32)i < pAC->Rlmt.NumNets; i++) { pAC->Rlmt.Net[i].RlmtState = SK_RLMT_RS_INIT; pAC->Rlmt.Net[i].RootIdSet = SK_FALSE; pAC->Rlmt.Net[i].Preference = 0xFFFFFFFF; /* "Automatic" */ pAC->Rlmt.Net[i].PrefPort = SK_RLMT_DEF_PREF_PORT; /* Just assuming. */ pAC->Rlmt.Net[i].ActivePort = pAC->Rlmt.Net[i].PrefPort; pAC->Rlmt.Net[i].RlmtMode = SK_RLMT_DEF_MODE; pAC->Rlmt.Net[i].TimeoutValue = SK_RLMT_DEF_TO_VAL; pAC->Rlmt.Net[i].NetNumber = i; } pAC->Rlmt.Port[1].Net= &pAC->Rlmt.Net[0]; pAC->Rlmt.Net[0].NumPorts = pAC->GIni.GIMacsFound; SkEventQueue(pAC, SKGE_PNMI, SK_PNMI_EVT_RLMT_SET_NETS, Para); SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL, ("RLMT: Changed to one net with two ports.\n")); } else if (Para.Para32[0] == 2) { pAC->Rlmt.RlmtOff = SK_TRUE; pAC->Rlmt.Port[1].Net= &pAC->Rlmt.Net[1]; pAC->Rlmt.Net[1].NumPorts = pAC->GIni.GIMacsFound - 1; pAC->Rlmt.Net[0].NumPorts = pAC->GIni.GIMacsFound - pAC->Rlmt.Net[1].NumPorts; pAC->Rlmt.NumNets = Para.Para32[0]; for (i = 0; (SK_U32)i < pAC->Rlmt.NumNets; i++) { pAC->Rlmt.Net[i].RlmtState = SK_RLMT_RS_INIT; pAC->Rlmt.Net[i].RootIdSet = SK_FALSE; pAC->Rlmt.Net[i].Preference = 0xFFFFFFFF; /* "Automatic" */ pAC->Rlmt.Net[i].PrefPort = SK_RLMT_DEF_PREF_PORT; /* Just assuming. */ pAC->Rlmt.Net[i].ActivePort = pAC->Rlmt.Net[i].PrefPort; pAC->Rlmt.Net[i].RlmtMode = SK_RLMT_DEF_MODE; pAC->Rlmt.Net[i].TimeoutValue = SK_RLMT_DEF_TO_VAL; pAC->Rlmt.Net[i].NetNumber = i; } /* Set logical MAC addr on second net's active port. */ (void)SkAddrOverride(pAC, IoC, pAC->Rlmt.Net[1].Port[pAC->Addr. Net[1].ActivePort]->PortNumber, NULL, SK_ADDR_SET_LOGICAL); SkEventQueue(pAC, SKGE_PNMI, SK_PNMI_EVT_RLMT_SET_NETS, Para); SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL, ("RLMT: Changed to two nets with one port each.\n")); } else { /* Not implemented for more than two nets. */ SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL, ("SetNets not implemented for more than two nets.\n")); SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL, ("SK_RLMT_SET_NETS Event EMPTY.\n")); return; } SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL, ("SK_RLMT_SET_NETS Event END.\n")); } /* SkRlmtSetNets */ /****************************************************************************** * * SkRlmtEvtModeChange - MODE_CHANGE * * Description: * This routine handles MODE_CHANGE events. * * Context: * runtime, pageable? * may be called after SK_INIT_IO * * Returns: * Nothing */ RLMT_STATIC void SkRlmtEvtModeChange( SK_AC *pAC, /* Adapter Context */ SK_IOC IoC, /* I/O Context */ SK_EVPARA Para) /* SK_U32 NewMode; SK_U32 NetNumber */ { SK_EVPARA Para2; SK_U32 i; SK_U32 PrevRlmtMode; SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL, ("SK_RLMT_MODE_CHANGE Event BEGIN.\n")); if (Para.Para32[1] >= pAC->Rlmt.NumNets) { SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL, ("Bad NetNumber %d.\n", Para.Para32[1])); SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL, ("SK_RLMT_MODE_CHANGE Event EMPTY.\n")); return; } Para.Para32[0] |= SK_RLMT_CHECK_LINK; if ((pAC->Rlmt.Net[Para.Para32[1]].NumPorts == 1) && Para.Para32[0] != SK_RLMT_MODE_CLS) { pAC->Rlmt.Net[Para.Para32[1]].RlmtMode = SK_RLMT_MODE_CLS; SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL, ("Forced RLMT mode to CLS on single port net.\n")); SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL, ("SK_RLMT_MODE_CHANGE Event EMPTY.\n")); return; } /* Update RLMT mode. */ PrevRlmtMode = pAC->Rlmt.Net[Para.Para32[1]].RlmtMode; pAC->Rlmt.Net[Para.Para32[1]].RlmtMode = Para.Para32[0]; if ((PrevRlmtMode & SK_RLMT_CHECK_LOC_LINK) != (pAC->Rlmt.Net[Para.Para32[1]].RlmtMode & SK_RLMT_CHECK_LOC_LINK)) { /* SK_RLMT_CHECK_LOC_LINK bit changed. */ if ((PrevRlmtMode & SK_RLMT_CHECK_OTHERS) == 0 && pAC->Rlmt.Net[Para.Para32[1]].NumPorts > 1 && pAC->Rlmt.Net[Para.Para32[1]].PortsUp >= 1) { /* 20001207 RA: Was "PortsUp == 1". */ Para2.Para32[0] = Para.Para32[1]; Para2.Para32[1] = (SK_U32)-1; SkTimerStart(pAC, IoC, &pAC->Rlmt.Net[Para.Para32[1]].LocTimer, pAC->Rlmt.Net[Para.Para32[1]].TimeoutValue, SKGE_RLMT, SK_RLMT_TIM, Para2); } } if ((PrevRlmtMode & SK_RLMT_CHECK_SEG) != (pAC->Rlmt.Net[Para.Para32[1]].RlmtMode & SK_RLMT_CHECK_SEG)) { /* SK_RLMT_CHECK_SEG bit changed. */ for (i = 0; i < pAC->Rlmt.Net[Para.Para32[1]].NumPorts; i++) { (void)SkAddrMcClear(pAC, IoC, pAC->Rlmt.Net[Para.Para32[1]].Port[i]->PortNumber, SK_ADDR_PERMANENT | SK_MC_SW_ONLY); /* Add RLMT MC address. */ (void)SkAddrMcAdd(pAC, IoC, pAC->Rlmt.Net[Para.Para32[1]].Port[i]->PortNumber, &SkRlmtMcAddr, SK_ADDR_PERMANENT); if ((pAC->Rlmt.Net[Para.Para32[1]].RlmtMode & SK_RLMT_CHECK_SEG) != 0) { /* Add BPDU MC address. */ (void)SkAddrMcAdd(pAC, IoC, pAC->Rlmt.Net[Para.Para32[1]].Port[i]->PortNumber, &BridgeMcAddr, SK_ADDR_PERMANENT); if (pAC->Rlmt.Net[Para.Para32[1]].RlmtState != SK_RLMT_RS_INIT) { if (!pAC->Rlmt.Net[Para.Para32[1]].Port[i]->LinkDown && (Para2.pParaPtr = SkRlmtBuildSpanningTreePacket( pAC, IoC, i)) != NULL) { pAC->Rlmt.Net[Para.Para32[1]].Port[i]->RootIdSet = SK_FALSE; SkEventQueue(pAC, SKGE_DRV, SK_DRV_RLMT_SEND, Para2); } } } (void)SkAddrMcUpdate(pAC, IoC, pAC->Rlmt.Net[Para.Para32[1]].Port[i]->PortNumber); } /* for ... */ if ((pAC->Rlmt.Net[Para.Para32[1]].RlmtMode & SK_RLMT_CHECK_SEG) != 0) { Para2.Para32[0] = Para.Para32[1]; Para2.Para32[1] = (SK_U32)-1; SkTimerStart(pAC, IoC, &pAC->Rlmt.Net[Para.Para32[1]].SegTimer, SK_RLMT_SEG_TO_VAL, SKGE_RLMT, SK_RLMT_SEG_TIM, Para2); } } /* SK_RLMT_CHECK_SEG bit changed. */ SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL, ("SK_RLMT_MODE_CHANGE Event END.\n")); } /* SkRlmtEvtModeChange */ /****************************************************************************** * * SkRlmtEvent - a PORT- or an RLMT-specific event happened * * Description: * This routine calls subroutines to handle PORT- and RLMT-specific events. * * Context: * runtime, pageable? * may be called after SK_INIT_IO * * Returns: * 0 */ int SkRlmtEvent( SK_AC *pAC, /* Adapter Context */ SK_IOC IoC, /* I/O Context */ SK_U32 Event, /* Event code */ SK_EVPARA Para) /* Event-specific parameter */ { switch (Event) { /* ----- PORT events ----- */ case SK_RLMT_PORTSTART_TIM: /* From RLMT via TIME. */ SkRlmtEvtPortStartTim(pAC, IoC, Para); break; case SK_RLMT_LINK_UP: /* From SIRQ. */ SkRlmtEvtLinkUp(pAC, IoC, Para); break; case SK_RLMT_PORTUP_TIM: /* From RLMT via TIME. */ SkRlmtEvtPortUpTim(pAC, IoC, Para); break; case SK_RLMT_PORTDOWN: /* From RLMT. */ case SK_RLMT_PORTDOWN_RX_TIM: /* From RLMT via TIME. */ case SK_RLMT_PORTDOWN_TX_TIM: /* From RLMT via TIME. */ SkRlmtEvtPortDownX(pAC, IoC, Event, Para); break; case SK_RLMT_LINK_DOWN: /* From SIRQ. */ SkRlmtEvtLinkDown(pAC, IoC, Para); break; case SK_RLMT_PORT_ADDR: /* From ADDR. */ SkRlmtEvtPortAddr(pAC, IoC, Para); break; /* ----- RLMT events ----- */ case SK_RLMT_START: /* From DRV. */ SkRlmtEvtStart(pAC, IoC, Para); break; case SK_RLMT_STOP: /* From DRV. */ SkRlmtEvtStop(pAC, IoC, Para); break; case SK_RLMT_TIM: /* From RLMT via TIME. */ SkRlmtEvtTim(pAC, IoC, Para); break; case SK_RLMT_SEG_TIM: SkRlmtEvtSegTim(pAC, IoC, Para); break; case SK_RLMT_PACKET_RECEIVED: /* From DRV. */ SkRlmtEvtPacketRx(pAC, IoC, Para); break; case SK_RLMT_STATS_CLEAR: /* From PNMI. */ SkRlmtEvtStatsClear(pAC, IoC, Para); break; case SK_RLMT_STATS_UPDATE: /* From PNMI. */ SkRlmtEvtStatsUpdate(pAC, IoC, Para); break; case SK_RLMT_PREFPORT_CHANGE: /* From PNMI. */ SkRlmtEvtPrefportChange(pAC, IoC, Para); break; case SK_RLMT_MODE_CHANGE: /* From PNMI. */ SkRlmtEvtModeChange(pAC, IoC, Para); break; case SK_RLMT_SET_NETS: /* From DRV. */ SkRlmtEvtSetNets(pAC, IoC, Para); break; /* ----- Unknown events ----- */ default: /* Create error log entry. */ SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL, ("Unknown RLMT Event %d.\n", Event)); SK_ERR_LOG(pAC, SK_ERRCL_SW, SKERR_RLMT_E003, SKERR_RLMT_E003_MSG); break; } /* switch() */ return (0); } /* SkRlmtEvent */ #ifdef __cplusplus } #endif /* __cplusplus */ #endif