blob: 603c0ef731d9082d1a6e568cac9bbcbf9d55d629 [file] [log] [blame]
Brandon Wymana0f33ce2019-10-17 18:32:29 -05001#include "psu_manager.hpp"
2
3#include "utility.hpp"
4
Brandon Wymanb76ab242020-09-16 18:06:06 -05005#include <fmt/format.h>
6#include <sys/types.h>
7#include <unistd.h>
8
Brandon Wymanecbecbc2021-08-31 22:53:21 +00009#include <regex>
10
Brandon Wymanaed1f752019-11-25 18:10:52 -060011using namespace phosphor::logging;
12
Brandon Wyman63ea78b2020-09-24 16:49:09 -050013namespace phosphor::power::manager
Brandon Wymana0f33ce2019-10-17 18:32:29 -050014{
15
Brandon Wyman510acaa2020-11-05 18:32:04 -060016constexpr auto IBMCFFPSInterface =
17 "xyz.openbmc_project.Configuration.IBMCFFPSConnector";
18constexpr auto i2cBusProp = "I2CBus";
19constexpr auto i2cAddressProp = "I2CAddress";
20constexpr auto psuNameProp = "Name";
B. J. Wyman681b2a32021-04-20 22:31:22 +000021constexpr auto presLineName = "NamedPresenceGpio";
Brandon Wyman510acaa2020-11-05 18:32:04 -060022
Adriana Kobylak9bab9e12021-02-24 15:32:03 -060023constexpr auto supportedConfIntf =
24 "xyz.openbmc_project.Configuration.SupportedConfiguration";
Adriana Kobylak9bab9e12021-02-24 15:32:03 -060025
Brandon Wyman510acaa2020-11-05 18:32:04 -060026PSUManager::PSUManager(sdbusplus::bus::bus& bus, const sdeventplus::Event& e) :
27 bus(bus)
28{
Brandon Wyman510acaa2020-11-05 18:32:04 -060029 // Subscribe to InterfacesAdded before doing a property read, otherwise
30 // the interface could be created after the read attempt but before the
31 // match is created.
32 entityManagerIfacesAddedMatch = std::make_unique<sdbusplus::bus::match_t>(
33 bus,
34 sdbusplus::bus::match::rules::interfacesAdded() +
35 sdbusplus::bus::match::rules::sender(
36 "xyz.openbmc_project.EntityManager"),
37 std::bind(&PSUManager::entityManagerIfaceAdded, this,
38 std::placeholders::_1));
39 getPSUConfiguration();
40 getSystemProperties();
41
42 using namespace sdeventplus;
43 auto interval = std::chrono::milliseconds(1000);
44 timer = std::make_unique<utility::Timer<ClockId::Monotonic>>(
45 e, std::bind(&PSUManager::analyze, this), interval);
46
47 // Subscribe to power state changes
48 powerService = util::getService(POWER_OBJ_PATH, POWER_IFACE, bus);
49 powerOnMatch = std::make_unique<sdbusplus::bus::match_t>(
50 bus,
51 sdbusplus::bus::match::rules::propertiesChanged(POWER_OBJ_PATH,
52 POWER_IFACE),
53 [this](auto& msg) { this->powerStateChanged(msg); });
54
55 initialize();
56}
57
Brandon Wyman510acaa2020-11-05 18:32:04 -060058void PSUManager::getPSUConfiguration()
59{
60 using namespace phosphor::power::util;
61 auto depth = 0;
62 auto objects = getSubTree(bus, "/", IBMCFFPSInterface, depth);
63
64 psus.clear();
65
66 // I should get a map of objects back.
67 // Each object will have a path, a service, and an interface.
68 // The interface should match the one passed into this function.
69 for (const auto& [path, services] : objects)
70 {
71 auto service = services.begin()->first;
72
73 if (path.empty() || service.empty())
74 {
75 continue;
76 }
77
78 // For each object in the array of objects, I want to get properties
79 // from the service, path, and interface.
80 auto properties =
81 getAllProperties(bus, path, IBMCFFPSInterface, service);
82
83 getPSUProperties(properties);
84 }
85
86 if (psus.empty())
87 {
88 // Interface or properties not found. Let the Interfaces Added callback
89 // process the information once the interfaces are added to D-Bus.
90 log<level::INFO>(fmt::format("No power supplies to monitor").c_str());
91 }
92}
93
94void PSUManager::getPSUProperties(util::DbusPropertyMap& properties)
95{
96 // From passed in properties, I want to get: I2CBus, I2CAddress,
97 // and Name. Create a power supply object, using Name to build the inventory
98 // path.
99 const auto basePSUInvPath =
100 "/xyz/openbmc_project/inventory/system/chassis/motherboard/powersupply";
101 uint64_t* i2cbus = nullptr;
102 uint64_t* i2caddr = nullptr;
103 std::string* psuname = nullptr;
B. J. Wyman681b2a32021-04-20 22:31:22 +0000104 std::string* preslineptr = nullptr;
Brandon Wyman510acaa2020-11-05 18:32:04 -0600105
106 for (const auto& property : properties)
107 {
108 try
109 {
110 if (property.first == i2cBusProp)
111 {
112 i2cbus = std::get_if<uint64_t>(&properties[i2cBusProp]);
113 }
114 else if (property.first == i2cAddressProp)
115 {
116 i2caddr = std::get_if<uint64_t>(&properties[i2cAddressProp]);
117 }
118 else if (property.first == psuNameProp)
119 {
120 psuname = std::get_if<std::string>(&properties[psuNameProp]);
121 }
B. J. Wyman681b2a32021-04-20 22:31:22 +0000122 else if (property.first == presLineName)
123 {
124 preslineptr =
125 std::get_if<std::string>(&properties[presLineName]);
126 }
Brandon Wyman510acaa2020-11-05 18:32:04 -0600127 }
128 catch (std::exception& e)
Adriana Kobylak0c9a33d2021-09-13 18:05:09 +0000129 {}
Brandon Wyman510acaa2020-11-05 18:32:04 -0600130 }
131
132 if ((i2cbus) && (i2caddr) && (psuname) && (!psuname->empty()))
133 {
134 std::string invpath = basePSUInvPath;
135 invpath.push_back(psuname->back());
B. J. Wyman681b2a32021-04-20 22:31:22 +0000136 std::string presline = "";
Brandon Wyman510acaa2020-11-05 18:32:04 -0600137
138 log<level::DEBUG>(fmt::format("Inventory Path: {}", invpath).c_str());
139
B. J. Wyman681b2a32021-04-20 22:31:22 +0000140 if (nullptr != preslineptr)
141 {
142 presline = *preslineptr;
143 }
144
Brandon Wymanecbecbc2021-08-31 22:53:21 +0000145 auto invMatch =
146 std::find_if(psus.begin(), psus.end(), [&invpath](auto& psu) {
147 return psu->getInventoryPath() == invpath;
148 });
149 if (invMatch != psus.end())
150 {
151 // This power supply has the same inventory path as the one with
152 // information just added to D-Bus.
153 // Changes to GPIO line name unlikely, so skip checking.
154 // Changes to the I2C bus and address unlikely, as that would
155 // require corresponding device tree updates.
156 // Return out to avoid duplicate object creation.
157 return;
158 }
159
B. J. Wyman681b2a32021-04-20 22:31:22 +0000160 log<level::DEBUG>(
161 fmt::format("make PowerSupply bus: {} addr: {} presline: {}",
162 *i2cbus, *i2caddr, presline)
163 .c_str());
164 auto psu = std::make_unique<PowerSupply>(bus, invpath, *i2cbus,
165 *i2caddr, presline);
Brandon Wyman510acaa2020-11-05 18:32:04 -0600166 psus.emplace_back(std::move(psu));
167 }
168
169 if (psus.empty())
170 {
171 log<level::INFO>(fmt::format("No power supplies to monitor").c_str());
172 }
173}
174
Adriana Kobylake1074d82021-03-16 20:46:44 +0000175void PSUManager::populateSysProperties(const util::DbusPropertyMap& properties)
176{
177 try
178 {
Adriana Kobylak9ea66a62021-03-24 17:54:14 +0000179 auto propIt = properties.find("SupportedType");
180 if (propIt == properties.end())
181 {
182 return;
183 }
184 const std::string* type = std::get_if<std::string>(&(propIt->second));
185 if ((type == nullptr) || (*type != "PowerSupply"))
186 {
187 return;
188 }
189
Adriana Kobylak9ea66a62021-03-24 17:54:14 +0000190 propIt = properties.find("SupportedModel");
191 if (propIt == properties.end())
192 {
193 return;
194 }
Adriana Kobylakd3a70d92021-06-04 16:24:45 +0000195 const std::string* model = std::get_if<std::string>(&(propIt->second));
196 if (model == nullptr)
Adriana Kobylak9ea66a62021-03-24 17:54:14 +0000197 {
198 return;
199 }
Adriana Kobylak9ea66a62021-03-24 17:54:14 +0000200
Adriana Kobylakd3a70d92021-06-04 16:24:45 +0000201 sys_properties sys;
Adriana Kobylak9ea66a62021-03-24 17:54:14 +0000202 propIt = properties.find("RedundantCount");
Adriana Kobylake1074d82021-03-16 20:46:44 +0000203 if (propIt != properties.end())
204 {
205 const uint64_t* count = std::get_if<uint64_t>(&(propIt->second));
206 if (count != nullptr)
207 {
Adriana Kobylakd3a70d92021-06-04 16:24:45 +0000208 sys.powerSupplyCount = *count;
Adriana Kobylake1074d82021-03-16 20:46:44 +0000209 }
210 }
Adriana Kobylak9ea66a62021-03-24 17:54:14 +0000211 propIt = properties.find("InputVoltage");
212 if (propIt != properties.end())
213 {
Adriana Kobylakd3a70d92021-06-04 16:24:45 +0000214 const std::vector<uint64_t>* voltage =
215 std::get_if<std::vector<uint64_t>>(&(propIt->second));
Adriana Kobylak9ea66a62021-03-24 17:54:14 +0000216 if (voltage != nullptr)
217 {
218 sys.inputVoltage = *voltage;
219 }
220 }
221
Adriana Kobylakd3a70d92021-06-04 16:24:45 +0000222 supportedConfigs.emplace(*model, sys);
Adriana Kobylake1074d82021-03-16 20:46:44 +0000223 }
224 catch (std::exception& e)
Adriana Kobylak0c9a33d2021-09-13 18:05:09 +0000225 {}
Adriana Kobylake1074d82021-03-16 20:46:44 +0000226}
227
Adriana Kobylak9bab9e12021-02-24 15:32:03 -0600228void PSUManager::getSystemProperties()
229{
Adriana Kobylak9bab9e12021-02-24 15:32:03 -0600230
Adriana Kobylak9bab9e12021-02-24 15:32:03 -0600231 try
232 {
233 util::DbusSubtree subtree =
234 util::getSubTree(bus, INVENTORY_OBJ_PATH, supportedConfIntf, 0);
Adriana Kobylake1074d82021-03-16 20:46:44 +0000235 if (subtree.empty())
Adriana Kobylak9bab9e12021-02-24 15:32:03 -0600236 {
237 throw std::runtime_error("Supported Configuration Not Found");
238 }
Adriana Kobylak9bab9e12021-02-24 15:32:03 -0600239
Adriana Kobylake1074d82021-03-16 20:46:44 +0000240 for (const auto& [objPath, services] : subtree)
241 {
242 std::string service = services.begin()->first;
243 if (objPath.empty() || service.empty())
244 {
245 continue;
Adriana Kobylak9bab9e12021-02-24 15:32:03 -0600246 }
Adriana Kobylake1074d82021-03-16 20:46:44 +0000247 auto properties = util::getAllProperties(
248 bus, objPath, supportedConfIntf, service);
249 populateSysProperties(properties);
Adriana Kobylak9bab9e12021-02-24 15:32:03 -0600250 }
251 }
252 catch (std::exception& e)
253 {
254 // Interface or property not found. Let the Interfaces Added callback
255 // process the information once the interfaces are added to D-Bus.
256 }
257}
258
Brandon Wyman3e429132021-03-18 18:03:14 -0500259void PSUManager::entityManagerIfaceAdded(sdbusplus::message::message& msg)
Adriana Kobylak9bab9e12021-02-24 15:32:03 -0600260{
261 try
262 {
263 sdbusplus::message::object_path objPath;
Adriana Kobylake1074d82021-03-16 20:46:44 +0000264 std::map<std::string, std::map<std::string, util::DbusVariant>>
Adriana Kobylak9bab9e12021-02-24 15:32:03 -0600265 interfaces;
266 msg.read(objPath, interfaces);
267
268 auto itIntf = interfaces.find(supportedConfIntf);
Brandon Wyman510acaa2020-11-05 18:32:04 -0600269 if (itIntf != interfaces.cend())
Adriana Kobylak9bab9e12021-02-24 15:32:03 -0600270 {
Brandon Wyman510acaa2020-11-05 18:32:04 -0600271 populateSysProperties(itIntf->second);
Adriana Kobylak9bab9e12021-02-24 15:32:03 -0600272 }
273
Brandon Wyman510acaa2020-11-05 18:32:04 -0600274 itIntf = interfaces.find(IBMCFFPSInterface);
275 if (itIntf != interfaces.cend())
276 {
277 log<level::INFO>(
278 fmt::format("InterfacesAdded for: {}", IBMCFFPSInterface)
279 .c_str());
280 getPSUProperties(itIntf->second);
281 }
Adriana Kobylak8f16fb52021-03-31 15:50:15 +0000282
283 // Call to validate the psu configuration if the power is on and both
284 // the IBMCFFPSConnector and SupportedConfiguration interfaces have been
285 // processed
286 if (powerOn && !psus.empty() && !supportedConfigs.empty())
287 {
288 validateConfig();
289 }
Adriana Kobylak9bab9e12021-02-24 15:32:03 -0600290 }
291 catch (std::exception& e)
292 {
293 // Ignore, the property may be of a different type than expected.
294 }
295}
296
Brandon Wymana0f33ce2019-10-17 18:32:29 -0500297void PSUManager::powerStateChanged(sdbusplus::message::message& msg)
298{
299 int32_t state = 0;
300 std::string msgSensor;
Patrick Williamsabe49412020-05-13 17:59:47 -0500301 std::map<std::string, std::variant<int32_t>> msgData;
Brandon Wymana0f33ce2019-10-17 18:32:29 -0500302 msg.read(msgSensor, msgData);
303
304 // Check if it was the Present property that changed.
305 auto valPropMap = msgData.find("state");
306 if (valPropMap != msgData.end())
307 {
308 state = std::get<int32_t>(valPropMap->second);
309
310 // Power is on when state=1. Clear faults.
311 if (state)
312 {
313 powerOn = true;
Adriana Kobylak8f16fb52021-03-31 15:50:15 +0000314 validateConfig();
Brandon Wymana0f33ce2019-10-17 18:32:29 -0500315 clearFaults();
316 }
317 else
318 {
319 powerOn = false;
Adriana Kobylak8f16fb52021-03-31 15:50:15 +0000320 runValidateConfig = true;
Brandon Wymana0f33ce2019-10-17 18:32:29 -0500321 }
322 }
323}
324
Brandon Wymanb76ab242020-09-16 18:06:06 -0500325void PSUManager::createError(
326 const std::string& faultName,
327 const std::map<std::string, std::string>& additionalData)
328{
329 using namespace sdbusplus::xyz::openbmc_project;
330 constexpr auto loggingObjectPath = "/xyz/openbmc_project/logging";
331 constexpr auto loggingCreateInterface =
332 "xyz.openbmc_project.Logging.Create";
333
334 try
335 {
336 auto service =
337 util::getService(loggingObjectPath, loggingCreateInterface, bus);
338
339 if (service.empty())
340 {
341 log<level::ERR>("Unable to get logging manager service");
342 return;
343 }
344
345 auto method = bus.new_method_call(service.c_str(), loggingObjectPath,
346 loggingCreateInterface, "Create");
347
348 auto level = Logging::server::Entry::Level::Error;
349 method.append(faultName, level, additionalData);
350
351 auto reply = bus.call(method);
352 }
353 catch (std::exception& e)
354 {
355 log<level::ERR>(
356 fmt::format(
357 "Failed creating event log for fault {} due to error {}",
358 faultName, e.what())
359 .c_str());
360 }
361}
362
Brandon Wyman63ea78b2020-09-24 16:49:09 -0500363void PSUManager::analyze()
364{
365 for (auto& psu : psus)
366 {
367 psu->analyze();
368 }
369
Brandon Wyman3180f4d2020-12-08 17:53:46 -0600370 if (powerOn)
Brandon Wyman63ea78b2020-09-24 16:49:09 -0500371 {
Adriana Kobylakf2ba1462021-06-24 15:16:17 +0000372 std::map<std::string, std::string> additionalData;
373 auto requiredPSUsPresent = hasRequiredPSUs(additionalData);
374
Brandon Wyman3180f4d2020-12-08 17:53:46 -0600375 for (auto& psu : psus)
Brandon Wyman63ea78b2020-09-24 16:49:09 -0500376 {
Brandon Wyman3180f4d2020-12-08 17:53:46 -0600377 additionalData["_PID"] = std::to_string(getpid());
378 // TODO: Fault priorities #918
379 if (!psu->isFaultLogged() && !psu->isPresent())
380 {
Adriana Kobylakf2ba1462021-06-24 15:16:17 +0000381 if (!requiredPSUsPresent)
382 {
383 // Create error for power supply missing.
384 additionalData["CALLOUT_INVENTORY_PATH"] =
385 psu->getInventoryPath();
386 additionalData["CALLOUT_PRIORITY"] = "H";
387 createError(
388 "xyz.openbmc_project.Power.PowerSupply.Error.Missing",
389 additionalData);
390 }
Brandon Wyman3180f4d2020-12-08 17:53:46 -0600391 psu->setFaultLogged();
392 }
393 else if (!psu->isFaultLogged() && psu->isFaulted())
394 {
395 additionalData["STATUS_WORD"] =
396 std::to_string(psu->getStatusWord());
Jay Meyer10d94052020-11-30 14:41:21 -0600397 additionalData["STATUS_MFR"] =
398 std::to_string(psu->getMFRFault());
Brandon Wyman3180f4d2020-12-08 17:53:46 -0600399 // If there are faults being reported, they possibly could be
400 // related to a bug in the firmware version running on the power
401 // supply. Capture that data into the error as well.
402 additionalData["FW_VERSION"] = psu->getFWVersion();
403
404 if ((psu->hasInputFault() || psu->hasVINUVFault()))
405 {
406 /* The power supply location might be needed if the input
407 * fault is due to a problem with the power supply itself.
408 * Include the inventory path with a call out priority of
409 * low.
410 */
411 additionalData["CALLOUT_INVENTORY_PATH"] =
412 psu->getInventoryPath();
413 additionalData["CALLOUT_PRIORITY"] = "L";
414 createError("xyz.openbmc_project.Power.PowerSupply.Error."
415 "InputFault",
416 additionalData);
417 psu->setFaultLogged();
418 }
419 else if (psu->hasMFRFault())
420 {
421 /* This can represent a variety of faults that result in
422 * calling out the power supply for replacement: Output
423 * OverCurrent, Output Under Voltage, and potentially other
424 * faults.
425 *
426 * Also plan on putting specific fault in AdditionalData,
427 * along with register names and register values
428 * (STATUS_WORD, STATUS_MFR, etc.).*/
429
430 additionalData["CALLOUT_INVENTORY_PATH"] =
431 psu->getInventoryPath();
432
433 createError(
434 "xyz.openbmc_project.Power.PowerSupply.Error.Fault",
Brandon Wyman52e54e82020-10-08 14:44:58 -0500435 additionalData);
Brandon Wyman63ea78b2020-09-24 16:49:09 -0500436
Brandon Wyman3180f4d2020-12-08 17:53:46 -0600437 psu->setFaultLogged();
438 }
439 else if (psu->hasCommFault())
440 {
441 /* Attempts to communicate with the power supply have
442 * reached there limit. Create an error. */
443 additionalData["CALLOUT_DEVICE_PATH"] =
444 psu->getDevicePath();
Brandon Wymanb76ab242020-09-16 18:06:06 -0500445
Brandon Wyman3180f4d2020-12-08 17:53:46 -0600446 createError(
447 "xyz.openbmc_project.Power.PowerSupply.Error.CommFault",
448 additionalData);
Brandon Wymanb76ab242020-09-16 18:06:06 -0500449
Brandon Wyman3180f4d2020-12-08 17:53:46 -0600450 psu->setFaultLogged();
451 }
Brandon Wyman4176d6b2020-10-07 17:41:06 -0500452 }
Brandon Wyman63ea78b2020-09-24 16:49:09 -0500453 }
454 }
455}
456
Adriana Kobylak8f16fb52021-03-31 15:50:15 +0000457void PSUManager::validateConfig()
458{
Adriana Kobylak70e7f932021-06-10 18:53:56 +0000459 if (!runValidateConfig || supportedConfigs.empty())
Adriana Kobylak8f16fb52021-03-31 15:50:15 +0000460 {
461 return;
462 }
463
Adriana Kobylak4d9aaf92021-06-30 15:27:42 +0000464 std::map<std::string, std::string> additionalData;
465 auto supported = hasRequiredPSUs(additionalData);
466 if (supported)
467 {
468 runValidateConfig = false;
469 return;
470 }
471
472 // Validation failed, create an error log.
473 // Return without setting the runValidateConfig flag to false because
474 // it may be that an additional supported configuration interface is
475 // added and we need to validate it to see if it matches this system.
476 createError("xyz.openbmc_project.Power.PowerSupply.Error.NotSupported",
477 additionalData);
478}
479
480bool PSUManager::hasRequiredPSUs(
481 std::map<std::string, std::string>& additionalData)
482{
Adriana Kobylak8f16fb52021-03-31 15:50:15 +0000483 // Check that all PSUs have the same model name. Initialize the model
484 // variable with the first PSU name found, then use it as a base to compare
485 // against the rest of the PSUs.
486 std::string model{};
Adriana Kobylak4d9aaf92021-06-30 15:27:42 +0000487 for (const auto& psu : psus)
Adriana Kobylak8f16fb52021-03-31 15:50:15 +0000488 {
Adriana Kobylak4d9aaf92021-06-30 15:27:42 +0000489 auto psuModel = psu->getModelName();
Adriana Kobylak8f16fb52021-03-31 15:50:15 +0000490 if (psuModel.empty())
491 {
492 continue;
493 }
494 if (model.empty())
495 {
496 model = psuModel;
497 continue;
498 }
Adriana Kobylak4d9aaf92021-06-30 15:27:42 +0000499 if (psuModel != model)
Adriana Kobylak8f16fb52021-03-31 15:50:15 +0000500 {
Adriana Kobylak8f16fb52021-03-31 15:50:15 +0000501 additionalData["EXPECTED_MODEL"] = model;
502 additionalData["ACTUAL_MODEL"] = psuModel;
Adriana Kobylak4d9aaf92021-06-30 15:27:42 +0000503 additionalData["CALLOUT_INVENTORY_PATH"] = psu->getInventoryPath();
504 return false;
Adriana Kobylak8f16fb52021-03-31 15:50:15 +0000505 }
506 }
Adriana Kobylak70e7f932021-06-10 18:53:56 +0000507
Adriana Kobylak4d9aaf92021-06-30 15:27:42 +0000508 auto presentCount =
509 std::count_if(psus.begin(), psus.end(),
510 [](const auto& psu) { return psu->isPresent(); });
511
Adriana Kobylak70e7f932021-06-10 18:53:56 +0000512 // Validate the supported configurations. A system may support more than one
Adriana Kobylak4175ffb2021-08-02 14:51:05 +0000513 // power supply model configuration. Since all configurations need to be
514 // checked, the additional data would contain only the information of the
515 // last configuration that did not match.
516 std::map<std::string, std::string> tmpAdditionalData;
Adriana Kobylak70e7f932021-06-10 18:53:56 +0000517 for (const auto& config : supportedConfigs)
518 {
Adriana Kobylak4d9aaf92021-06-30 15:27:42 +0000519 if (config.first != model)
Adriana Kobylak70e7f932021-06-10 18:53:56 +0000520 {
521 continue;
522 }
523 if (presentCount != config.second.powerSupplyCount)
524 {
Adriana Kobylak4175ffb2021-08-02 14:51:05 +0000525 tmpAdditionalData.clear();
526 tmpAdditionalData["EXPECTED_COUNT"] =
Adriana Kobylak70e7f932021-06-10 18:53:56 +0000527 std::to_string(config.second.powerSupplyCount);
Adriana Kobylak4175ffb2021-08-02 14:51:05 +0000528 tmpAdditionalData["ACTUAL_COUNT"] = std::to_string(presentCount);
Adriana Kobylak70e7f932021-06-10 18:53:56 +0000529 continue;
530 }
Adriana Kobylak4175ffb2021-08-02 14:51:05 +0000531
532 bool voltageValidated = true;
533 for (const auto& psu : psus)
534 {
535 if (!psu->isPresent())
536 {
537 // Only present PSUs report a valid input voltage
538 continue;
539 }
540
541 double actualInputVoltage;
542 int inputVoltage;
543 psu->getInputVoltage(actualInputVoltage, inputVoltage);
544
545 if (std::find(config.second.inputVoltage.begin(),
546 config.second.inputVoltage.end(),
547 inputVoltage) == config.second.inputVoltage.end())
548 {
549 tmpAdditionalData.clear();
550 tmpAdditionalData["ACTUAL_VOLTAGE"] =
551 std::to_string(actualInputVoltage);
552 for (const auto& voltage : config.second.inputVoltage)
553 {
554 tmpAdditionalData["EXPECTED_VOLTAGE"] +=
555 std::to_string(voltage) + " ";
556 }
557 tmpAdditionalData["CALLOUT_INVENTORY_PATH"] =
558 psu->getInventoryPath();
559
560 voltageValidated = false;
561 break;
562 }
563 }
564 if (!voltageValidated)
565 {
566 continue;
567 }
568
Adriana Kobylak4d9aaf92021-06-30 15:27:42 +0000569 return true;
Adriana Kobylak70e7f932021-06-10 18:53:56 +0000570 }
Adriana Kobylak70e7f932021-06-10 18:53:56 +0000571
Adriana Kobylak4175ffb2021-08-02 14:51:05 +0000572 additionalData.insert(tmpAdditionalData.begin(), tmpAdditionalData.end());
Adriana Kobylak4d9aaf92021-06-30 15:27:42 +0000573 return false;
Adriana Kobylak8f16fb52021-03-31 15:50:15 +0000574}
575
Brandon Wyman63ea78b2020-09-24 16:49:09 -0500576} // namespace phosphor::power::manager