xref: /openbmc/phosphor-power/phosphor-regulators/src/phase_fault_detection.cpp (revision f54021972b91be5058b50e9046bb0dd5a3b22a80)
19284c307SShawn McCarney /**
29284c307SShawn McCarney  * Copyright © 2021 IBM Corporation
39284c307SShawn McCarney  *
49284c307SShawn McCarney  * Licensed under the Apache License, Version 2.0 (the "License");
59284c307SShawn McCarney  * you may not use this file except in compliance with the License.
69284c307SShawn McCarney  * You may obtain a copy of the License at
79284c307SShawn McCarney  *
89284c307SShawn McCarney  *     http://www.apache.org/licenses/LICENSE-2.0
99284c307SShawn McCarney  *
109284c307SShawn McCarney  * Unless required by applicable law or agreed to in writing, software
119284c307SShawn McCarney  * distributed under the License is distributed on an "AS IS" BASIS,
129284c307SShawn McCarney  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
139284c307SShawn McCarney  * See the License for the specific language governing permissions and
149284c307SShawn McCarney  * limitations under the License.
159284c307SShawn McCarney  */
169284c307SShawn McCarney 
179284c307SShawn McCarney #include "phase_fault_detection.hpp"
189284c307SShawn McCarney 
199284c307SShawn McCarney #include "action_utils.hpp"
209284c307SShawn McCarney #include "chassis.hpp"
219284c307SShawn McCarney #include "device.hpp"
229284c307SShawn McCarney #include "error_logging.hpp"
239284c307SShawn McCarney #include "error_logging_utils.hpp"
249284c307SShawn McCarney #include "exception_utils.hpp"
259284c307SShawn McCarney #include "journal.hpp"
269284c307SShawn McCarney #include "system.hpp"
279284c307SShawn McCarney 
289284c307SShawn McCarney #include <exception>
299284c307SShawn McCarney #include <map>
309284c307SShawn McCarney 
319284c307SShawn McCarney namespace phosphor::power::regulators
329284c307SShawn McCarney {
339284c307SShawn McCarney 
349284c307SShawn McCarney /**
359284c307SShawn McCarney  * Maximum number of action errors to write to the journal.
369284c307SShawn McCarney  */
379284c307SShawn McCarney constexpr unsigned short maxActionErrorCount{3};
389284c307SShawn McCarney 
399284c307SShawn McCarney /**
409284c307SShawn McCarney  * Number of consecutive phase faults required to log an error.  This provides
419284c307SShawn McCarney  * "de-glitching" to ignore transient hardware problems.
429284c307SShawn McCarney  */
439284c307SShawn McCarney constexpr unsigned short requiredConsecutiveFaults{2};
449284c307SShawn McCarney 
execute(Services & services,System & system,Chassis &,Device & regulator)459284c307SShawn McCarney void PhaseFaultDetection::execute(Services& services, System& system,
469284c307SShawn McCarney                                   Chassis& /*chassis*/, Device& regulator)
479284c307SShawn McCarney {
489284c307SShawn McCarney     try
499284c307SShawn McCarney     {
509284c307SShawn McCarney         // Find the device ID to use.  If the deviceID data member is empty, use
519284c307SShawn McCarney         // the ID of the specified regulator.
529284c307SShawn McCarney         const std::string& effectiveDeviceID =
539284c307SShawn McCarney             deviceID.empty() ? regulator.getID() : deviceID;
549284c307SShawn McCarney 
559284c307SShawn McCarney         // Create ActionEnvironment
569284c307SShawn McCarney         ActionEnvironment environment{system.getIDMap(), effectiveDeviceID,
579284c307SShawn McCarney                                       services};
589284c307SShawn McCarney 
599284c307SShawn McCarney         // Execute the actions to detect phase faults
609284c307SShawn McCarney         action_utils::execute(actions, environment);
619284c307SShawn McCarney 
629284c307SShawn McCarney         // Check for any N or N+1 phase faults that were detected
639284c307SShawn McCarney         checkForPhaseFault(PhaseFaultType::n, services, regulator, environment);
649284c307SShawn McCarney         checkForPhaseFault(PhaseFaultType::n_plus_1, services, regulator,
659284c307SShawn McCarney                            environment);
669284c307SShawn McCarney     }
679284c307SShawn McCarney     catch (const std::exception& e)
689284c307SShawn McCarney     {
699284c307SShawn McCarney         // Log error messages in journal if we haven't hit the max
709284c307SShawn McCarney         if (actionErrorCount < maxActionErrorCount)
719284c307SShawn McCarney         {
729284c307SShawn McCarney             ++actionErrorCount;
739284c307SShawn McCarney             services.getJournal().logError(exception_utils::getMessages(e));
749284c307SShawn McCarney             services.getJournal().logError(
759284c307SShawn McCarney                 "Unable to detect phase faults in regulator " +
769284c307SShawn McCarney                 regulator.getID());
779284c307SShawn McCarney         }
789284c307SShawn McCarney 
799284c307SShawn McCarney         // Create error log entry if this type hasn't already been logged
809284c307SShawn McCarney         error_logging_utils::logError(std::current_exception(),
819284c307SShawn McCarney                                       Entry::Level::Warning, services,
829284c307SShawn McCarney                                       errorHistory);
839284c307SShawn McCarney     }
849284c307SShawn McCarney }
859284c307SShawn McCarney 
checkForPhaseFault(PhaseFaultType faultType,Services & services,Device & regulator,ActionEnvironment & environment)86*f5402197SPatrick Williams void PhaseFaultDetection::checkForPhaseFault(
87*f5402197SPatrick Williams     PhaseFaultType faultType, Services& services, Device& regulator,
889284c307SShawn McCarney     ActionEnvironment& environment)
899284c307SShawn McCarney {
909284c307SShawn McCarney     // Find ErrorType that corresponds to PhaseFaultType; used by ErrorHistory
919284c307SShawn McCarney     ErrorType errorType = toErrorType(faultType);
929284c307SShawn McCarney 
939284c307SShawn McCarney     // If this error has not been logged yet
949284c307SShawn McCarney     if (!errorHistory.wasLogged(errorType))
959284c307SShawn McCarney     {
969284c307SShawn McCarney         // Create reference to consecutive fault count data member
979284c307SShawn McCarney         unsigned short& faultCount =
989284c307SShawn McCarney             (faultType == PhaseFaultType::n) ? nFaultCount : nPlus1FaultCount;
999284c307SShawn McCarney 
1009284c307SShawn McCarney         // Check if the phase fault was detected
1019284c307SShawn McCarney         if (environment.getPhaseFaults().count(faultType) == 0)
1029284c307SShawn McCarney         {
1039284c307SShawn McCarney             // Phase fault not detected; reset consecutive fault count
1049284c307SShawn McCarney             faultCount = 0;
1059284c307SShawn McCarney         }
1069284c307SShawn McCarney         else
1079284c307SShawn McCarney         {
1089284c307SShawn McCarney             // Phase fault detected; increment consecutive fault count
1099284c307SShawn McCarney             ++faultCount;
1109284c307SShawn McCarney 
1119284c307SShawn McCarney             // Log error message in journal
1129284c307SShawn McCarney             services.getJournal().logError(
1139284c307SShawn McCarney                 toString(faultType) + " phase fault detected in regulator " +
1149284c307SShawn McCarney                 regulator.getID() + ": count=" + std::to_string(faultCount));
1159284c307SShawn McCarney 
1169284c307SShawn McCarney             // If the required number of consecutive faults have been detected
1179284c307SShawn McCarney             if (faultCount >= requiredConsecutiveFaults)
1189284c307SShawn McCarney             {
1199284c307SShawn McCarney                 // Log phase fault error and update ErrorHistory
1209284c307SShawn McCarney                 logPhaseFault(faultType, services, regulator, environment);
1219284c307SShawn McCarney                 errorHistory.setWasLogged(errorType, true);
1229284c307SShawn McCarney             }
1239284c307SShawn McCarney         }
1249284c307SShawn McCarney     }
1259284c307SShawn McCarney }
1269284c307SShawn McCarney 
logPhaseFault(PhaseFaultType faultType,Services & services,Device & regulator,ActionEnvironment & environment)1279284c307SShawn McCarney void PhaseFaultDetection::logPhaseFault(PhaseFaultType faultType,
1289284c307SShawn McCarney                                         Services& services, Device& regulator,
1299284c307SShawn McCarney                                         ActionEnvironment& environment)
1309284c307SShawn McCarney {
1319284c307SShawn McCarney     ErrorLogging& errorLogging = services.getErrorLogging();
1329284c307SShawn McCarney     Entry::Level severity = (faultType == PhaseFaultType::n)
1339284c307SShawn McCarney                                 ? Entry::Level::Warning
1349284c307SShawn McCarney                                 : Entry::Level::Informational;
1359284c307SShawn McCarney     Journal& journal = services.getJournal();
1369284c307SShawn McCarney     const std::string& inventoryPath = regulator.getFRU();
1379284c307SShawn McCarney     const std::map<std::string, std::string>& additionalData =
1389284c307SShawn McCarney         environment.getAdditionalErrorData();
1399284c307SShawn McCarney     errorLogging.logPhaseFault(severity, journal, faultType, inventoryPath,
1409284c307SShawn McCarney                                additionalData);
1419284c307SShawn McCarney }
1429284c307SShawn McCarney 
1439284c307SShawn McCarney } // namespace phosphor::power::regulators
144