/// <summary> /// Sets the energy storage status in the internal database /// This method updates the database in an atomic manner /// </summary> /// <param name="battId">The battery identifier.</param> /// <param name="newStatus">The new energy storage status.</param> /// <returns>True: Status set successfully. /// False: Failed to set status. /// </returns> internal static bool SetEnergyStorageStatus(int battId, ChassisEnergyStorageStatus newStatus) { if (battId > ConfigLoaded.NumBatteries) { return(false); } lock (energyStorageLock) { ChassisEnergyStorage[battId - 1] = newStatus; } return(true); }
/// <summary> /// Gets the energy storage status in the internal database /// This method reads the database in an atomic manner /// </summary> /// <param name="battId">The battery identifier.</param> /// <returns>Chassis energy storage status for the battery ID</returns> internal static ChassisEnergyStorageStatus GetEnergyStorageStatus(int battId) { ChassisEnergyStorageStatus currStatus = new ChassisEnergyStorageStatus(false, EnergyStorageState.Unknown, 0, 0, false); if (battId > ConfigLoaded.NumBatteries) { Tracer.WriteError(string.Format("BatteryId {0} is out of range", battId)); } else { lock (energyStorageLock) { currStatus = ChassisEnergyStorage[battId - 1]; } } return(currStatus); }
/// <summary> /// Sets the energy storage status in the internal database /// This method updates the database in an atomic manner /// </summary> /// <param name="battId">The battery identifier.</param> /// <param name="newStatus">The new energy storage status.</param> /// <returns>True: Status set successfully. /// False: Failed to set status. /// </returns> internal static bool SetEnergyStorageStatus(int battId, ChassisEnergyStorageStatus newStatus) { if (battId > ConfigLoaded.NumBatteries) { return false; } lock (energyStorageLock) { ChassisEnergyStorage[battId - 1] = newStatus; } return true; }
/// <summary> /// Gets the energy storage status in the internal database /// This method reads the database in an atomic manner /// </summary> /// <param name="battId">The battery identifier.</param> /// <returns>Chassis energy storage status for the battery ID</returns> internal static ChassisEnergyStorageStatus GetEnergyStorageStatus(int battId) { ChassisEnergyStorageStatus currStatus = new ChassisEnergyStorageStatus(false, EnergyStorageState.Unknown, 0, 0, false); if (battId > ConfigLoaded.NumBatteries) { Tracer.WriteError(string.Format("BatteryId {0} is out of range", battId)); } else { lock (energyStorageLock) { currStatus = ChassisEnergyStorage[battId - 1]; } } return currStatus; }
/// <summary> /// Attempt to resolve Psu Faults /// </summary> private static Dictionary <byte, PsuAlertFaultStatus> PsuAlertRemediate(Dictionary <byte, PsuAlertFaultType> psuFailures) { Dictionary <byte, PsuAlertFaultStatus> failedPsu = new Dictionary <byte, PsuAlertFaultStatus>(); foreach (KeyValuePair <byte, PsuAlertFaultType> psu in psuFailures) { // If firmware update is in progress, skip this PSU if (ChassisState.PsuFwUpdateInProgress[psu.Key - 1]) { continue; } lock (ChassisState.psuLock[psu.Key - 1]) { // Log PSU faults ChassisState.Psu[psu.Key - 1].LogPsuFaultStatus(); // Clear PSU faults, which will clear PSU_ALERT CompletionCode clearAlert = ClearPsuFault(psu.Key); if (clearAlert != CompletionCode.Success) { // PSU clear faults failed. Log failure and continue to next PSU. failedPsu.Add(psu.Key, PsuAlertFaultStatus.PsuClearFaultFailed); Tracer.WriteError("PsuAlertRemediate: ClearPsuFault failed on PsuId: {0}", psu.Key); continue; } if (psu.Value == PsuAlertFaultType.PsuFailure) { // Check that the PSU is on PsuStatusPacket psuStatus = ChassisState.Psu[psu.Key - 1].GetPsuStatus(); if (psuStatus.CompletionCode != CompletionCode.Success) { failedPsu.Add(psu.Key, PsuAlertFaultStatus.PsuFault); Tracer.WriteError("PsuAlertRemediate: GetPsuStatus on PSU ({0}) failed with return code {1}", psu.Key, psuStatus.CompletionCode); } else { if (psuStatus.PsuStatus == (byte)Contracts.PowerState.ON) { // Check PSU power output PsuPowerPacket power = ChassisState.Psu[psu.Key - 1].GetPsuPower(); if ((power.CompletionCode == CompletionCode.Success) && (power.PsuPower != 0)) { Tracer.WriteInfo("PsuStatus clear faults succeeded. Psu: {0} drawing power: {1} Watts", psu.Key, power.PsuPower); } else { // PSU is not outputting power. failedPsu.Add(psu.Key, PsuAlertFaultStatus.PsuNoOutputPower); Tracer.WriteError("PsuAlertRemediate failed Psu. PsuId: {0} Psu Error State: {1}", psu.Key, PsuAlertFaultStatus.PsuNoOutputPower.ToString()); } } else { // PSU is turned off. failedPsu.Add(psu.Key, PsuAlertFaultStatus.PsuPowerOff); Tracer.WriteError("PsuAlertRemediate failed Psu. PsuId: {0} Psu Error State: {1}", psu.Key, PsuAlertFaultStatus.PsuPowerOff.ToString()); } } } else if ((ConfigLoaded.BatteryMonitoringEnabled) && (ChassisState.Psu[(psu.Key - 1)] is EmersonPsu)) { // convert psu from base class object EmersonPsu emersonPsu = (EmersonPsu)ChassisState.Psu[(psu.Key - 1)]; if (psu.Value == PsuAlertFaultType.BatteryFault) { // clear battery fault status CompletionCode clearFault = emersonPsu.ClearBatteryFaultIndicator(); if (clearFault == CompletionCode.Success) { EmersonPsu.BatteryFaultIndicatorPacket faultIndicator = emersonPsu.GetBatteryFaultIndicator(); if (faultIndicator.BatteryFault == 1) { if (!failedPsu.ContainsKey(emersonPsu.PsuId)) { // Psu Clear faults did not succeed. failedPsu.Add(psu.Key, PsuAlertFaultStatus.BatteryFault); } Tracer.WriteError("PsuAlertRemediate failed to clear battery fault. PsuId: {0} Battery Error State: {1}", psu.Key, PsuAlertFaultStatus.BatteryFault.ToString()); } } } else if (psu.Value == PsuAlertFaultType.OnBattery && ConfigLoaded.NumBatteries > 0) { // Check if we need to trigger delegate to process battery status if (ConfigLoaded.ProcessBatteryStatus) { double sumBatteryChargeLevel = 0; ChassisEnergyStorageStatus status = null; // list to store battery charge levels List <string> batteryStates = new List <string>(); // battery present or not, set to true if even one battery is present. // default to false bool isBatteryPresent = false; // Calculate average battery charge level for (int index = 1; index <= ConfigLoaded.NumBatteries; index++) { status = ChassisState.GetEnergyStorageStatus((byte)index); // Add to the list battery charge levels batteryStates.Add(status.State.ToString()); // If even one battery is present, set flag to true if (status.Present) { isBatteryPresent = true; } // If battery state is not unknown, add up the charge level. if (status.State != EnergyStorageState.Unknown) { sumBatteryChargeLevel += status.PercentCharge; } } double avgChargeLevel = (sumBatteryChargeLevel / ConfigLoaded.NumBatteries); // Process battery status if battery discharge time is greater than the allowed discharge time // from app.config( default 35 seconds) or Average battery charge level is below a given threshold value. if (BatteryDischargeTimer.Elapsed > new System.TimeSpan(0, 0, ConfigLoaded.BatteryDischargeTimeInSecs) || avgChargeLevel < ConfigLoaded.BatteryChargeLevelThreshold) { // Invoke method to trigger NVDIMM backup for critical battery status ThreadPool.QueueUserWorkItem(new WaitCallback(ChassisManagerInternal.ProcessCriticalBatteryStatus)); } // Calculate backup energy available per blade and per NVDIMM double bladeEnergy = (ConfigLoaded.NumPsus * BATT_POUT_MAX * BATT_OP_TIME_100_LOAD * avgChargeLevel) / ConfigLoaded.Population; double nvdimmEnergy = (ConfigLoaded.NumPsus * BATT_POUT_EXTENDED * BATT_OP_TIME_75W_LOAD) / (ConfigLoaded.Population * ConfigLoaded.NvDimmPerBlade); // Scale the values bladeEnergy = bladeEnergy / ENERGY_STORAGE_SCALING_JOULES; nvdimmEnergy = nvdimmEnergy / ENERGY_STORAGE_SCALING_JOULES; // Send battery status to BMC, check returned completion code for success Dictionary <byte, CompletionCode> results = WcsBladeFacade.BroadcastSetEnergyStorage (isBatteryPresent, GetBatteryStateToBroadcast(batteryStates), ENERGY_STORAGE_SCALING_JOULES, (ushort)bladeEnergy, (byte)nvdimmEnergy); // Check if broadcast failed for any blade, if yes log error. for (int index = 1; index <= ConfigLoaded.Population; index++) { CompletionCode code; if (results.TryGetValue((byte)index, out code)) { // If completion code returned is not success if (code != CompletionCode.Success) { Tracer.WriteError("PsuMonitor: ProcessBatteryStatus: " + "Failed to update battery status to BMC for blade: " + index + ", completion code returned: " + code); } } else { // If blade entry does not exist. Tracer.WriteError("PsuMonitor: ProcessBatteryStatus : " + "Failed to update battery status to BMC for blade: " + index); } } } } } } // lock... } // foreach... return(failedPsu); }
/// <summary> /// Checks for faults on each PSU /// </summary> private static Dictionary <byte, PsuAlertFaultType> PsuAlertInvestigate() { Dictionary <byte, PsuAlertFaultType> failures = new Dictionary <byte, PsuAlertFaultType>(); // Check status for all PSU foreach (PsuBase psu in ChassisState.Psu) { // If firmware update is in progress, skip this PSU if (ChassisState.PsuFwUpdateInProgress[psu.PsuId - 1]) { continue; } lock (ChassisState.psuLock[psu.PsuId - 1]) { PsuStatusPacket psuStatus = psu.GetPsuStatus(); if (psuStatus.CompletionCode != CompletionCode.Success) { Tracer.WriteError("PsuAlertInvestigate: GetPsuStatus on PSU ({0}) failed with return code {1}", psu.PsuId, psuStatus.CompletionCode); failures.Add(psu.PsuId, PsuAlertFaultType.PsuFailure); } else { if (psuStatus.PsuStatus != (byte)Contracts.PowerState.ON) { // PSU is completely turned off failures.Add(psu.PsuId, PsuAlertFaultType.PsuFailure); } else if ((ConfigLoaded.BatteryMonitoringEnabled) && (ChassisState.Psu[psu.PsuId - 1] is EmersonPsu)) { // Check battery status for Emerson PSU EmersonPsu emersonPsu = (EmersonPsu)psu; // Get battery status and health BatteryStatusPacket battStatus = emersonPsu.GetBatteryStatus(); EmersonPsu.BatteryHealthStatusPacket battHealth = emersonPsu.GetBatteryHealthStatus(); if ((battStatus.CompletionCode == CompletionCode.Success) && (battHealth.CompletionCode == CompletionCode.Success)) { // Update chassis energy storage variables bool batteryPresent = (battStatus.Presence == 1) ? true : false; bool batteryFault = (battStatus.FaultDetected == 1) ? true : false; EnergyStorageState battState = EnergyStorageState.Unknown; if (batteryPresent) { if (batteryFault) { // Battery Fault Detected. failures.Add(emersonPsu.PsuId, PsuAlertFaultType.BatteryFault); Tracer.WriteError("PsuAlertInvestigate Battery Fault Detected. PsuId {0}", emersonPsu.PsuId); } else // if no fault detected, check if system is on battery. { // Determine battery state if (battHealth.Discharging == 0) { battState = EnergyStorageState.Charging; // We are charging, reset the timer. if (BatteryDischargeTimer.IsRunning) { BatteryDischargeTimer.Reset(); } } else { // Emerson stated that we can have discharging even when on AC since the charger will have hysteresis. // Hence we need to check Discharging and Battery Power Output to determine if we are on Battery. if (battStatus.BatteryPowerOutput != 0) { battState = EnergyStorageState.Discharging; } else { battState = EnergyStorageState.Floating; } } if (battState == EnergyStorageState.Discharging) { // Start the timer if not already running. if (!BatteryDischargeTimer.IsRunning) { BatteryDischargeTimer.Start(); } // Psu Battery is Discharging. System is on battery. // Log it as a failure for processing in PsuAlertRemediate() which is called outside this method failures.Add(emersonPsu.PsuId, PsuAlertFaultType.OnBattery); Tracer.WriteInfo("PsuAlertInvestigate Psu Battery discharging. PsuId {0}", emersonPsu.PsuId); } } } else { Tracer.WriteInfo("PsuAlertInvestigate, no battery present for Psu: {0}", emersonPsu.PsuId); } // Update chassis energy storage values ChassisEnergyStorageStatus chassisEnergyStatus = new ChassisEnergyStorageStatus(batteryPresent, battState, battStatus.BatteryChargeLevel, battStatus.BatteryPowerOutput, batteryFault); if (!ChassisState.SetEnergyStorageStatus(emersonPsu.PsuId, chassisEnergyStatus)) { Tracer.WriteError( string.Format("PsuAlertInvestigate: SetEnergyStorageStatus failed for BatteryId {0}", emersonPsu.PsuId)); } } else { // Failed to get battery status or health. Log as battery fault failures.Add(emersonPsu.PsuId, PsuAlertFaultType.BatteryFault); Tracer.WriteError("PsuAlertInvestigate failed to get Battery Status. PsuId {0} Status Completion Code: {1} Health Completion Code: {2}", emersonPsu.PsuId, battStatus.CompletionCode, battHealth.CompletionCode); } } // If PSU is on and there are no battery faults, check if other faults are present // Add PSU to failure list so that we can log it in PsuAlertRemediate() if ((!failures.ContainsKey(psu.PsuId)) && (psuStatus.FaultPresent)) { failures.Add(psu.PsuId, PsuAlertFaultType.PsuFaultPresent); } } } // lock... } // foreach... return(failures); }
/// <summary> /// Checks for faults on each PSU /// </summary> private static Dictionary<byte, PsuAlertFaultType> PsuAlertInvestigate() { Dictionary<byte, PsuAlertFaultType> failures = new Dictionary<byte, PsuAlertFaultType>(); // Check status for all PSU foreach (PsuBase psu in ChassisState.Psu) { // If firmware update is in progress, skip this PSU if (ChassisState.PsuFwUpdateInProgress[psu.PsuId - 1]) { continue; } lock (ChassisState.psuLock[psu.PsuId - 1]) { PsuStatusPacket psuStatus = psu.GetPsuStatus(); if (psuStatus.CompletionCode != CompletionCode.Success) { Tracer.WriteError("PsuAlertInvestigate: GetPsuStatus on PSU ({0}) failed with return code {1}", psu.PsuId, psuStatus.CompletionCode); failures.Add(psu.PsuId, PsuAlertFaultType.PsuFailure); } else { if (psuStatus.PsuStatus != (byte)Contracts.PowerState.ON) { // PSU is completely turned off failures.Add(psu.PsuId, PsuAlertFaultType.PsuFailure); } else if ((ConfigLoaded.BatteryMonitoringEnabled) && (ChassisState.Psu[psu.PsuId - 1] is EmersonPsu)) { // Check battery status for Emerson PSU EmersonPsu emersonPsu = (EmersonPsu)psu; // Get battery status and health BatteryStatusPacket battStatus = emersonPsu.GetBatteryStatus(); EmersonPsu.BatteryHealthStatusPacket battHealth = emersonPsu.GetBatteryHealthStatus(); if ((battStatus.CompletionCode == CompletionCode.Success) && (battHealth.CompletionCode == CompletionCode.Success)) { // Update chassis energy storage variables bool batteryPresent = (battStatus.Presence == 1) ? true : false; bool batteryFault = (battStatus.FaultDetected == 1) ? true : false; EnergyStorageState battState = EnergyStorageState.Unknown; if (batteryPresent) { if (batteryFault) { // Battery Fault Detected. failures.Add(emersonPsu.PsuId, PsuAlertFaultType.BatteryFault); Tracer.WriteError("PsuAlertInvestigate Battery Fault Detected. PsuId {0}", emersonPsu.PsuId); } else // if no fault detected, check if system is on battery. { // Determine battery state if (battHealth.Discharging == 0) { battState = EnergyStorageState.Charging; // We are charging, reset the timer. if (BatteryDischargeTimer.IsRunning) { BatteryDischargeTimer.Reset(); } } else { // Emerson stated that we can have discharging even when on AC since the charger will have hysteresis. // Hence we need to check Discharging and Battery Power Output to determine if we are on Battery. if (battStatus.BatteryPowerOutput != 0) { battState = EnergyStorageState.Discharging; } else { battState = EnergyStorageState.Floating; } } if (battState == EnergyStorageState.Discharging) { // Start the timer if not already running. if (!BatteryDischargeTimer.IsRunning) { BatteryDischargeTimer.Start(); } // Psu Battery is Discharging. System is on battery. // Log it as a failure for processing in PsuAlertRemediate() which is called outside this method failures.Add(emersonPsu.PsuId, PsuAlertFaultType.OnBattery); Tracer.WriteInfo("PsuAlertInvestigate Psu Battery discharging. PsuId {0}", emersonPsu.PsuId); } } } else { Tracer.WriteInfo("PsuAlertInvestigate, no battery present for Psu: {0}", emersonPsu.PsuId); } // Update chassis energy storage values ChassisEnergyStorageStatus chassisEnergyStatus = new ChassisEnergyStorageStatus(batteryPresent, battState, battStatus.BatteryChargeLevel, battStatus.BatteryPowerOutput, batteryFault); if (!ChassisState.SetEnergyStorageStatus(emersonPsu.PsuId, chassisEnergyStatus)) { Tracer.WriteError( string.Format("PsuAlertInvestigate: SetEnergyStorageStatus failed for BatteryId {0}", emersonPsu.PsuId)); } } else { // Failed to get battery status or health. Log as battery fault failures.Add(emersonPsu.PsuId, PsuAlertFaultType.BatteryFault); Tracer.WriteError("PsuAlertInvestigate failed to get Battery Status. PsuId {0} Status Completion Code: {1} Health Completion Code: {2}", emersonPsu.PsuId, battStatus.CompletionCode, battHealth.CompletionCode); } } // If PSU is on and there are no battery faults, check if other faults are present // Add PSU to failure list so that we can log it in PsuAlertRemediate() if ((!failures.ContainsKey(psu.PsuId)) && (psuStatus.FaultPresent)) { failures.Add(psu.PsuId, PsuAlertFaultType.PsuFaultPresent); } } } // lock... } // foreach... return failures; }