1 /** 2 * Copyright © 2024 IBM Corporation 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 #include "standard_device.hpp" 18 19 #include "format_utils.hpp" 20 21 #include <exception> 22 #include <format> 23 #include <span> 24 #include <stdexcept> 25 26 namespace phosphor::power::sequencer 27 { 28 29 std::string StandardDevice::findPgoodFault( 30 Services& services, const std::string& powerSupplyError, 31 std::map<std::string, std::string>& additionalData) 32 { 33 std::string error{}; 34 try 35 { 36 prepareForPgoodFaultDetection(services); 37 38 // Get all GPIO values (if possible) from device. They may be slow to 39 // obtain, so obtain them once and then pass values to each Rail object. 40 std::vector<int> gpioValues = getGPIOValuesIfPossible(); 41 42 // Loop through all the rails checking if any detected a pgood fault. 43 // The rails are in power-on-sequence order. 44 for (std::unique_ptr<Rail>& rail : rails) 45 { 46 if (rail->hasPgoodFault(*this, services, gpioValues, 47 additionalData)) 48 { 49 services.logErrorMsg(std::format( 50 "Pgood fault found in rail monitored by device {}", name)); 51 52 // If this is a PSU rail and a PSU error was previously detected 53 if (rail->isPowerSupplyRail() && !powerSupplyError.empty()) 54 { 55 // Return power supply error as root cause 56 error = powerSupplyError; 57 } 58 else 59 { 60 // Return pgood fault as root cause 61 error = 62 "xyz.openbmc_project.Power.Error.PowerSequencerVoltageFault"; 63 } 64 65 storePgoodFaultDebugData(services, gpioValues, additionalData); 66 break; 67 } 68 } 69 } 70 catch (const std::exception& e) 71 { 72 throw std::runtime_error{std::format( 73 "Unable to determine if a pgood fault occurred in device {}: {}", 74 name, e.what())}; 75 } 76 return error; 77 } 78 79 std::vector<int> StandardDevice::getGPIOValuesIfPossible() 80 { 81 std::vector<int> values{}; 82 try 83 { 84 values = getGPIOValues(); 85 } 86 catch (...) 87 {} 88 return values; 89 } 90 91 void StandardDevice::storePgoodFaultDebugData( 92 Services& services, const std::vector<int>& gpioValues, 93 std::map<std::string, std::string>& additionalData) 94 { 95 additionalData.emplace("DEVICE_NAME", name); 96 if (!gpioValues.empty()) 97 { 98 std::string valuesStr = format_utils::toString(std::span(gpioValues)); 99 services.logInfoMsg( 100 std::format("Device {} GPIO values: {}", name, valuesStr)); 101 additionalData.emplace("GPIO_VALUES", valuesStr); 102 } 103 } 104 105 } // namespace phosphor::power::sequencer 106