| /****************************************************************************** |
| * |
| * Name: skrlmt.c |
| * Project: GEnesis, PCI Gigabit Ethernet Adapter |
| * Version: $Revision: 1.69 $ |
| * Date: $Date: 2003/04/15 09:39:22 $ |
| * Purpose: Manage links on SK-NET Adapters, esp. redundant ones. |
| * |
| ******************************************************************************/ |
| |
| /****************************************************************************** |
| * |
| * (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. |
| * |
| ******************************************************************************/ |
| |
| /****************************************************************************** |
| * |
| * 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" |
| * |
| ******************************************************************************/ |
| |
| #ifndef lint |
| static const char SysKonnectFileId[] = |
| "@(#) $Id: skrlmt.c,v 1.69 2003/04/15 09:39:22 tschilli 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.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 ((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.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 */ |