blob: 0816180fbec70e912a0e2942705d178c3cc8a979 [file] [log] [blame]
Brandon Wyman24e422f2017-07-25 19:40:14 -05001/**
2 * Copyright © 2017 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 */
Brandon Wyman442035f2017-08-08 15:58:45 -050016#include <phosphor-logging/log.hpp>
17#include <phosphor-logging/elog.hpp>
Brandon Wymane0eb45c2017-10-06 12:58:42 -050018#include <org/open_power/Witherspoon/Fault/error.hpp>
Matt Spinlerceacf942017-10-05 13:55:02 -050019#include <xyz/openbmc_project/Common/Device/error.hpp>
Brandon Wyman442035f2017-08-08 15:58:45 -050020#include "elog-errors.hpp"
Brandon Wyman10295542017-08-09 18:20:44 -050021#include "names_values.hpp"
Brandon Wyman24e422f2017-07-25 19:40:14 -050022#include "power_supply.hpp"
Brandon Wyman442035f2017-08-08 15:58:45 -050023#include "pmbus.hpp"
24#include "utility.hpp"
25
Brandon Wyman1db9a9e2017-07-26 18:50:22 -050026namespace witherspoon
Brandon Wyman24e422f2017-07-25 19:40:14 -050027{
28namespace power
29{
30namespace psu
31{
32
Matt Spinler589e8722018-01-04 15:24:49 -060033using namespace phosphor::logging;
34using namespace sdbusplus::org::open_power::Witherspoon::Fault::Error;
35using namespace sdbusplus::xyz::openbmc_project::Common::Device::Error;
36
37constexpr auto ASSOCIATION_IFACE = "org.openbmc.Association";
38constexpr auto LOGGING_IFACE = "xyz.openbmc_project.Logging.Entry";
39constexpr auto INVENTORY_IFACE = "xyz.openbmc_project.Inventory.Item";
40constexpr auto POWER_IFACE = "org.openbmc.control.Power";
41
42constexpr auto ENDPOINTS_PROP = "endpoints";
43constexpr auto MESSAGE_PROP = "Message";
44constexpr auto RESOLVED_PROP = "Resolved";
Brandon Wyman10295542017-08-09 18:20:44 -050045constexpr auto PRESENT_PROP = "Present";
Matt Spinler589e8722018-01-04 15:24:49 -060046
47constexpr auto INVENTORY_OBJ_PATH = "/xyz/openbmc_project/inventory";
Brandon Wyman431fbe42017-08-18 16:22:09 -050048constexpr auto POWER_OBJ_PATH = "/org/openbmc/control/power0";
Brandon Wyman10295542017-08-09 18:20:44 -050049
50PowerSupply::PowerSupply(const std::string& name, size_t inst,
Brandon Wyman431fbe42017-08-18 16:22:09 -050051 const std::string& objpath,
52 const std::string& invpath,
53 sdbusplus::bus::bus& bus,
54 event::Event& e,
Brandon Wyman590fc282017-11-01 18:22:25 -050055 std::chrono::seconds& t,
56 std::chrono::seconds& p)
Brandon Wyman431fbe42017-08-18 16:22:09 -050057 : Device(name, inst), monitorPath(objpath), pmbusIntf(objpath),
Brandon Wyman50bb85d2017-11-01 18:36:00 -050058 inventoryPath(INVENTORY_OBJ_PATH + invpath), bus(bus), event(e),
59 presentInterval(p),
Brandon Wyman590fc282017-11-01 18:22:25 -050060 presentTimer(e, [this]()
61 {
Brandon Wyman2877add2017-11-10 17:44:19 -060062 // The hwmon path may have changed.
63 pmbusIntf.findHwmonDir();
Brandon Wyman590fc282017-11-01 18:22:25 -050064 this->present = true;
Matt Spinler234ce0d2018-01-04 15:06:57 -060065
66 // Update the inventory for the new device
67 updateInventory();
Brandon Wyman590fc282017-11-01 18:22:25 -050068 }),
69 powerOnInterval(t),
Brandon Wyman431fbe42017-08-18 16:22:09 -050070 powerOnTimer(e, [this]()
71 {
72 this->powerOn = true;
73 })
Brandon Wyman10295542017-08-09 18:20:44 -050074{
Brandon Wyman10295542017-08-09 18:20:44 -050075 using namespace sdbusplus::bus;
Brandon Wyman10295542017-08-09 18:20:44 -050076 presentMatch = std::make_unique<match_t>(bus,
77 match::rules::propertiesChanged(
Brandon Wyman50bb85d2017-11-01 18:36:00 -050078 inventoryPath,
Matt Spinler589e8722018-01-04 15:24:49 -060079 INVENTORY_IFACE),
Brandon Wyman10295542017-08-09 18:20:44 -050080 [this](auto& msg)
Brandon Wyman431fbe42017-08-18 16:22:09 -050081 {
82 this->inventoryChanged(msg);
83 });
84 // Get initial presence state.
Brandon Wyman253dc9b2017-08-12 13:45:52 -050085 updatePresence();
Brandon Wyman431fbe42017-08-18 16:22:09 -050086
Matt Spinler234ce0d2018-01-04 15:06:57 -060087 // Write the SN, PN, etc to the inventory
88 updateInventory();
89
Brandon Wyman431fbe42017-08-18 16:22:09 -050090 // Subscribe to power state changes
91 powerOnMatch = std::make_unique<match_t>(bus,
92 match::rules::propertiesChanged(
93 POWER_OBJ_PATH,
Matt Spinler589e8722018-01-04 15:24:49 -060094 POWER_IFACE),
Brandon Wyman431fbe42017-08-18 16:22:09 -050095 [this](auto& msg)
96 {
97 this->powerStateChanged(msg);
98 });
99 // Get initial power state.
100 updatePowerState();
Brandon Wyman10295542017-08-09 18:20:44 -0500101}
Brandon Wyman442035f2017-08-08 15:58:45 -0500102
Brandon Wymana1e96342017-09-25 16:47:44 -0500103void PowerSupply::captureCmd(util::NamesValues& nv, const std::string& cmd,
104 witherspoon::pmbus::Type type)
105{
106 if (pmbusIntf.exists(cmd, type))
107 {
108 try
109 {
110 auto val = pmbusIntf.read(cmd, type);
111 nv.add(cmd, val);
112 }
113 catch (std::exception& e)
114 {
115 log<level::INFO>("Unable to capture metadata", entry("CMD=%s",
116 cmd));
117 }
118 }
119}
Brandon Wyman431fbe42017-08-18 16:22:09 -0500120
Brandon Wyman1db9a9e2017-07-26 18:50:22 -0500121void PowerSupply::analyze()
122{
Brandon Wyman442035f2017-08-08 15:58:45 -0500123 using namespace witherspoon::pmbus;
124
125 try
126 {
Brandon Wyman10295542017-08-09 18:20:44 -0500127 if (present)
Brandon Wyman442035f2017-08-08 15:58:45 -0500128 {
Brandon Wyman764c7972017-08-22 17:05:36 -0500129 std::uint16_t statusWord = 0;
Brandon Wyman764c7972017-08-22 17:05:36 -0500130
131 // Read the 2 byte STATUS_WORD value to check for faults.
132 statusWord = pmbusIntf.read(STATUS_WORD, Type::Debug);
Brandon Wymane4af9802017-11-13 15:58:33 -0600133 readFail = 0;
Brandon Wyman764c7972017-08-22 17:05:36 -0500134
Brandon Wyman603cc002017-08-28 18:17:58 -0500135 checkInputFault(statusWord);
Brandon Wyman764c7972017-08-22 17:05:36 -0500136
Brandon Wyman3343e822017-11-03 16:54:11 -0500137 if (powerOn && !faultFound)
Brandon Wyman764c7972017-08-22 17:05:36 -0500138 {
Brandon Wyman12661f12017-08-31 15:28:21 -0500139 checkFanFault(statusWord);
Brandon Wyman875b3632017-09-13 18:46:03 -0500140 checkTemperatureFault(statusWord);
Brandon Wymancfa032b2017-09-25 17:37:50 -0500141 checkOutputOvervoltageFault(statusWord);
142 checkCurrentOutOverCurrentFault(statusWord);
143 checkPGOrUnitOffFault(statusWord);
Brandon Wyman442035f2017-08-08 15:58:45 -0500144 }
145 }
146 }
147 catch (ReadFailure& e)
148 {
Brandon Wymane4af9802017-11-13 15:58:33 -0600149 if (readFail < FAULT_COUNT)
150 {
151 readFail++;
152 }
153
154 if (!readFailLogged && readFail >= FAULT_COUNT)
Brandon Wyman442035f2017-08-08 15:58:45 -0500155 {
156 commit<ReadFailure>();
157 readFailLogged = true;
Brandon Wyman442035f2017-08-08 15:58:45 -0500158 }
159 }
160
Brandon Wyman1db9a9e2017-07-26 18:50:22 -0500161 return;
162}
163
Brandon Wyman10295542017-08-09 18:20:44 -0500164void PowerSupply::inventoryChanged(sdbusplus::message::message& msg)
165{
166 std::string msgSensor;
167 std::map<std::string, sdbusplus::message::variant<uint32_t, bool>> msgData;
168 msg.read(msgSensor, msgData);
169
170 // Check if it was the Present property that changed.
171 auto valPropMap = msgData.find(PRESENT_PROP);
172 if (valPropMap != msgData.end())
173 {
Brandon Wyman2ef48cf2017-11-21 15:43:54 -0600174 if (sdbusplus::message::variant_ns::get<bool>(valPropMap->second))
Brandon Wyman10295542017-08-09 18:20:44 -0500175 {
Brandon Wyman6ccce0b2017-10-26 15:13:10 -0500176 clearFaults();
Brandon Wyman590fc282017-11-01 18:22:25 -0500177 presentTimer.start(presentInterval, Timer::TimerType::oneshot);
178 }
179 else
180 {
Brandon Wyman2ef48cf2017-11-21 15:43:54 -0600181 present = false;
Brandon Wyman590fc282017-11-01 18:22:25 -0500182 presentTimer.stop();
Matt Spinler234ce0d2018-01-04 15:06:57 -0600183
184 //Clear out the now outdated inventory properties
185 updateInventory();
Brandon Wyman10295542017-08-09 18:20:44 -0500186 }
187 }
188
189 return;
190}
191
192void PowerSupply::updatePresence()
193{
194 // Use getProperty utility function to get presence status.
Brandon Wyman10295542017-08-09 18:20:44 -0500195 std::string service = "xyz.openbmc_project.Inventory.Manager";
Matt Spinler589e8722018-01-04 15:24:49 -0600196 util::getProperty(INVENTORY_IFACE, PRESENT_PROP, inventoryPath,
Brandon Wyman50bb85d2017-11-01 18:36:00 -0500197 service, bus, this->present);
Brandon Wyman10295542017-08-09 18:20:44 -0500198}
199
Brandon Wyman431fbe42017-08-18 16:22:09 -0500200void PowerSupply::powerStateChanged(sdbusplus::message::message& msg)
201{
202 int32_t state = 0;
203 std::string msgSensor;
204 std::map<std::string, sdbusplus::message::variant<int32_t, int32_t>>
205 msgData;
206 msg.read(msgSensor, msgData);
207
208 // Check if it was the Present property that changed.
209 auto valPropMap = msgData.find("state");
210 if (valPropMap != msgData.end())
211 {
212 state = sdbusplus::message::variant_ns::get<int32_t>(valPropMap->second);
213
214 // Power is on when state=1. Set the fault logged variables to false
215 // and start the power on timer when the state changes to 1.
216 if (state)
217 {
Brandon Wyman6ccce0b2017-10-26 15:13:10 -0500218 clearFaults();
Brandon Wyman431fbe42017-08-18 16:22:09 -0500219 powerOnTimer.start(powerOnInterval, Timer::TimerType::oneshot);
220 }
221 else
222 {
223 powerOnTimer.stop();
224 powerOn = false;
225 }
226 }
227
228}
229
230void PowerSupply::updatePowerState()
231{
232 // When state = 1, system is powered on
233 int32_t state = 0;
234
235 try
236 {
237 auto service = util::getService(POWER_OBJ_PATH,
Matt Spinler589e8722018-01-04 15:24:49 -0600238 POWER_IFACE,
Brandon Wyman431fbe42017-08-18 16:22:09 -0500239 bus);
240
241 // Use getProperty utility function to get power state.
Matt Spinler589e8722018-01-04 15:24:49 -0600242 util::getProperty<int32_t>(POWER_IFACE,
Brandon Wyman431fbe42017-08-18 16:22:09 -0500243 "state",
244 POWER_OBJ_PATH,
245 service,
246 bus,
247 state);
248
249 if (state)
250 {
251 powerOn = true;
252 }
253 else
254 {
255 powerOn = false;
256 }
257 }
258 catch (std::exception& e)
259 {
260 log<level::INFO>("Failed to get power state. Assuming it is off.");
261 powerOn = false;
262 }
263
264}
265
Brandon Wyman603cc002017-08-28 18:17:58 -0500266void PowerSupply::checkInputFault(const uint16_t statusWord)
267{
268 using namespace witherspoon::pmbus;
269
Brandon Wymana3c675c2017-11-14 14:54:54 -0600270 if ((inputFault < FAULT_COUNT) &&
271 ((statusWord & status_word::INPUT_FAULT_WARN) ||
272 (statusWord & status_word::VIN_UV_FAULT)))
Brandon Wyman603cc002017-08-28 18:17:58 -0500273 {
Brandon Wymana3c675c2017-11-14 14:54:54 -0600274 inputFault++;
Brandon Wyman603cc002017-08-28 18:17:58 -0500275 }
276 else
277 {
Brandon Wymana3c675c2017-11-14 14:54:54 -0600278 if ((inputFault > 0) &&
Brandon Wymand20686a2017-11-01 17:45:23 -0500279 !(statusWord & status_word::INPUT_FAULT_WARN) &&
280 !(statusWord & status_word::VIN_UV_FAULT))
Brandon Wyman603cc002017-08-28 18:17:58 -0500281 {
Brandon Wymana3c675c2017-11-14 14:54:54 -0600282 inputFault = 0;
Brandon Wyman3343e822017-11-03 16:54:11 -0500283 faultFound = false;
Brandon Wyman69591bd2017-11-01 18:07:23 -0500284
Brandon Wyman603cc002017-08-28 18:17:58 -0500285 log<level::INFO>("INPUT_FAULT_WARN cleared",
Brandon Wymana3c675c2017-11-14 14:54:54 -0600286 entry("POWERSUPPLY=%s", inventoryPath.c_str()));
Brandon Wyman69591bd2017-11-01 18:07:23 -0500287
Brandon Wyman08b05712017-11-30 17:53:56 -0600288 resolveError(inventoryPath,
289 std::string(PowerSupplyInputFault::errName));
290
Brandon Wyman69591bd2017-11-01 18:07:23 -0500291 if (powerOn)
292 {
293 // The power supply will not be immediately powered on after
294 // the input power is restored.
295 powerOn = false;
296 // Start up the timer that will set the state to indicate we
297 // are ready for the powered on fault checks.
298 powerOnTimer.start(powerOnInterval, Timer::TimerType::oneshot);
299 }
Brandon Wyman603cc002017-08-28 18:17:58 -0500300 }
301 }
Brandon Wymana3c675c2017-11-14 14:54:54 -0600302
303 if (!faultFound && (inputFault >= FAULT_COUNT))
304 {
305 util::NamesValues nv;
306 nv.add("STATUS_WORD", statusWord);
307 captureCmd(nv, STATUS_INPUT, Type::Debug);
308
309 using metadata = org::open_power::Witherspoon::Fault::
310 PowerSupplyInputFault;
311
312 report<PowerSupplyInputFault>(
313 metadata::RAW_STATUS(nv.get().c_str()),
314 metadata::CALLOUT_INVENTORY_PATH(inventoryPath.c_str()));
315 faultFound = true;
316 }
317
Brandon Wyman603cc002017-08-28 18:17:58 -0500318}
319
320void PowerSupply::checkPGOrUnitOffFault(const uint16_t statusWord)
321{
322 using namespace witherspoon::pmbus;
323
Brandon Wyman593d24f2017-10-13 18:15:23 -0500324 if (powerOnFault < FAULT_COUNT)
Brandon Wyman603cc002017-08-28 18:17:58 -0500325 {
Brandon Wyman593d24f2017-10-13 18:15:23 -0500326 // Check PG# and UNIT_IS_OFF
327 if ((statusWord & status_word::POWER_GOOD_NEGATED) ||
328 (statusWord & status_word::UNIT_IS_OFF))
329 {
330 log<level::INFO>("PGOOD or UNIT_IS_OFF bit bad",
331 entry("STATUS_WORD=0x%04X", statusWord));
332 powerOnFault++;
333 }
334 else
335 {
336 if (powerOnFault > 0)
337 {
338 log<level::INFO>("PGOOD and UNIT_IS_OFF bits good");
339 powerOnFault = 0;
340 }
341 }
Brandon Wyman603cc002017-08-28 18:17:58 -0500342
Brandon Wymane2fc7aa2017-11-13 17:37:10 -0600343 if (!faultFound && (powerOnFault >= FAULT_COUNT))
Brandon Wyman593d24f2017-10-13 18:15:23 -0500344 {
Brandon Wyman3343e822017-11-03 16:54:11 -0500345 faultFound = true;
346
Brandon Wyman593d24f2017-10-13 18:15:23 -0500347 util::NamesValues nv;
348 nv.add("STATUS_WORD", statusWord);
349 captureCmd(nv, STATUS_INPUT, Type::Debug);
350 auto status0Vout = pmbusIntf.insertPageNum(STATUS_VOUT, 0);
351 captureCmd(nv, status0Vout, Type::Debug);
352 captureCmd(nv, STATUS_IOUT, Type::Debug);
353 captureCmd(nv, STATUS_MFR, Type::Debug);
Brandon Wyman603cc002017-08-28 18:17:58 -0500354
Brandon Wyman593d24f2017-10-13 18:15:23 -0500355 using metadata = org::open_power::Witherspoon::Fault::
356 PowerSupplyShouldBeOn;
Brandon Wyman603cc002017-08-28 18:17:58 -0500357
Brandon Wyman593d24f2017-10-13 18:15:23 -0500358 // A power supply is OFF (or pgood low) but should be on.
359 report<PowerSupplyShouldBeOn>(
360 metadata::RAW_STATUS(nv.get().c_str()),
361 metadata::CALLOUT_INVENTORY_PATH(
362 inventoryPath.c_str()));
363 }
Brandon Wyman603cc002017-08-28 18:17:58 -0500364 }
365
366}
367
368void PowerSupply::checkCurrentOutOverCurrentFault(const uint16_t statusWord)
369{
370 using namespace witherspoon::pmbus;
371
Brandon Wymandd61be42017-11-07 18:38:54 -0600372 if (outputOCFault < FAULT_COUNT)
Brandon Wyman603cc002017-08-28 18:17:58 -0500373 {
Brandon Wymandd61be42017-11-07 18:38:54 -0600374 // Check for an output overcurrent fault.
375 if ((statusWord & status_word::IOUT_OC_FAULT))
376 {
377 outputOCFault++;
378 }
379 else
380 {
381 if (outputOCFault > 0)
382 {
383 outputOCFault = 0;
384 }
385 }
Brandon Wyman603cc002017-08-28 18:17:58 -0500386
Brandon Wymane2fc7aa2017-11-13 17:37:10 -0600387 if (!faultFound && (outputOCFault >= FAULT_COUNT))
Brandon Wymandd61be42017-11-07 18:38:54 -0600388 {
389 util::NamesValues nv;
390 nv.add("STATUS_WORD", statusWord);
391 captureCmd(nv, STATUS_INPUT, Type::Debug);
392 auto status0Vout = pmbusIntf.insertPageNum(STATUS_VOUT, 0);
393 captureCmd(nv, status0Vout, Type::Debug);
394 captureCmd(nv, STATUS_IOUT, Type::Debug);
395 captureCmd(nv, STATUS_MFR, Type::Debug);
Brandon Wyman603cc002017-08-28 18:17:58 -0500396
Brandon Wymandd61be42017-11-07 18:38:54 -0600397 using metadata = org::open_power::Witherspoon::Fault::
398 PowerSupplyOutputOvercurrent;
Brandon Wyman603cc002017-08-28 18:17:58 -0500399
Brandon Wymandd61be42017-11-07 18:38:54 -0600400 report<PowerSupplyOutputOvercurrent>(
401 metadata::RAW_STATUS(nv.get().c_str()),
402 metadata::CALLOUT_INVENTORY_PATH(inventoryPath.c_str()));
403
404 faultFound = true;
405 }
Brandon Wyman603cc002017-08-28 18:17:58 -0500406 }
407}
408
Brandon Wymanab05c072017-08-30 18:26:41 -0500409void PowerSupply::checkOutputOvervoltageFault(const uint16_t statusWord)
410{
411 using namespace witherspoon::pmbus;
412
Brandon Wyman2ab319b2017-11-08 17:34:59 -0600413 if (outputOVFault < FAULT_COUNT)
Brandon Wymanab05c072017-08-30 18:26:41 -0500414 {
Brandon Wyman2ab319b2017-11-08 17:34:59 -0600415 // Check for an output overvoltage fault.
416 if (statusWord & status_word::VOUT_OV_FAULT)
417 {
418 outputOVFault++;
419 }
420 else
421 {
422 if (outputOVFault > 0)
423 {
424 outputOVFault = 0;
425 }
426 }
Brandon Wymanab05c072017-08-30 18:26:41 -0500427
Brandon Wymane2fc7aa2017-11-13 17:37:10 -0600428 if (!faultFound && (outputOVFault >= FAULT_COUNT))
Brandon Wyman2ab319b2017-11-08 17:34:59 -0600429 {
430 util::NamesValues nv;
431 nv.add("STATUS_WORD", statusWord);
432 captureCmd(nv, STATUS_INPUT, Type::Debug);
433 auto status0Vout = pmbusIntf.insertPageNum(STATUS_VOUT, 0);
434 captureCmd(nv, status0Vout, Type::Debug);
435 captureCmd(nv, STATUS_IOUT, Type::Debug);
436 captureCmd(nv, STATUS_MFR, Type::Debug);
Brandon Wymanab05c072017-08-30 18:26:41 -0500437
Brandon Wyman2ab319b2017-11-08 17:34:59 -0600438 using metadata = org::open_power::Witherspoon::Fault::
439 PowerSupplyOutputOvervoltage;
Brandon Wymanab05c072017-08-30 18:26:41 -0500440
Brandon Wyman2ab319b2017-11-08 17:34:59 -0600441 report<PowerSupplyOutputOvervoltage>(
442 metadata::RAW_STATUS(nv.get().c_str()),
443 metadata::CALLOUT_INVENTORY_PATH(inventoryPath.c_str()));
444
445 faultFound = true;
446 }
Brandon Wymanab05c072017-08-30 18:26:41 -0500447 }
448}
449
Brandon Wyman12661f12017-08-31 15:28:21 -0500450void PowerSupply::checkFanFault(const uint16_t statusWord)
451{
452 using namespace witherspoon::pmbus;
453
Brandon Wymanba255532017-11-08 17:44:10 -0600454 if (fanFault < FAULT_COUNT)
Brandon Wyman12661f12017-08-31 15:28:21 -0500455 {
Brandon Wymanba255532017-11-08 17:44:10 -0600456 // Check for a fan fault or warning condition
457 if (statusWord & status_word::FAN_FAULT)
458 {
459 fanFault++;
460 }
461 else
462 {
463 if (fanFault > 0)
464 {
465 fanFault = 0;
466 }
467 }
Brandon Wyman12661f12017-08-31 15:28:21 -0500468
Brandon Wymane2fc7aa2017-11-13 17:37:10 -0600469 if (!faultFound && (fanFault >= FAULT_COUNT))
Brandon Wymanba255532017-11-08 17:44:10 -0600470 {
471 util::NamesValues nv;
472 nv.add("STATUS_WORD", statusWord);
473 captureCmd(nv, STATUS_MFR, Type::Debug);
474 captureCmd(nv, STATUS_TEMPERATURE, Type::Debug);
475 captureCmd(nv, STATUS_FANS_1_2, Type::Debug);
Brandon Wyman12661f12017-08-31 15:28:21 -0500476
Brandon Wymanba255532017-11-08 17:44:10 -0600477 using metadata = org::open_power::Witherspoon::Fault::
478 PowerSupplyFanFault;
Brandon Wyman12661f12017-08-31 15:28:21 -0500479
Brandon Wymanba255532017-11-08 17:44:10 -0600480 report<PowerSupplyFanFault>(
481 metadata::RAW_STATUS(nv.get().c_str()),
482 metadata::CALLOUT_INVENTORY_PATH(inventoryPath.c_str()));
483
484 faultFound = true;
485 }
Brandon Wyman12661f12017-08-31 15:28:21 -0500486 }
487}
488
Brandon Wyman875b3632017-09-13 18:46:03 -0500489void PowerSupply::checkTemperatureFault(const uint16_t statusWord)
490{
491 using namespace witherspoon::pmbus;
492
493 // Due to how the PMBus core device driver sends a clear faults command
494 // the bit in STATUS_WORD will likely be cleared when we attempt to examine
495 // it for a Thermal Fault or Warning. So, check the STATUS_WORD and the
496 // STATUS_TEMPERATURE bits. If either indicates a fault, proceed with
497 // logging the over-temperature condition.
498 std::uint8_t statusTemperature = 0;
499 statusTemperature = pmbusIntf.read(STATUS_TEMPERATURE, Type::Debug);
Brandon Wyman50044ea2017-11-08 17:58:56 -0600500 if (temperatureFault < FAULT_COUNT)
Brandon Wyman875b3632017-09-13 18:46:03 -0500501 {
Brandon Wyman50044ea2017-11-08 17:58:56 -0600502 if ((statusWord & status_word::TEMPERATURE_FAULT_WARN) ||
503 (statusTemperature & status_temperature::OT_FAULT))
504 {
505 temperatureFault++;
506 }
507 else
508 {
509 if (temperatureFault > 0)
510 {
511 temperatureFault = 0;
512 }
513 }
Brandon Wyman875b3632017-09-13 18:46:03 -0500514
Brandon Wymane2fc7aa2017-11-13 17:37:10 -0600515 if (!faultFound && (temperatureFault >= FAULT_COUNT))
Brandon Wyman50044ea2017-11-08 17:58:56 -0600516 {
517 // The power supply has had an over-temperature condition.
518 // This may not result in a shutdown if experienced for a short
519 // duration.
520 // This should not occur under normal conditions.
521 // The power supply may be faulty, or the paired supply may be
522 // putting out less current.
523 // Capture command responses with potentially relevant information,
524 // and call out the power supply reporting the condition.
525 util::NamesValues nv;
526 nv.add("STATUS_WORD", statusWord);
527 captureCmd(nv, STATUS_MFR, Type::Debug);
528 captureCmd(nv, STATUS_IOUT, Type::Debug);
529 nv.add("STATUS_TEMPERATURE", statusTemperature);
530 captureCmd(nv, STATUS_FANS_1_2, Type::Debug);
Brandon Wyman875b3632017-09-13 18:46:03 -0500531
Brandon Wyman50044ea2017-11-08 17:58:56 -0600532 using metadata = org::open_power::Witherspoon::Fault::
533 PowerSupplyTemperatureFault;
Brandon Wyman875b3632017-09-13 18:46:03 -0500534
Brandon Wyman50044ea2017-11-08 17:58:56 -0600535 report<PowerSupplyTemperatureFault>(
536 metadata::RAW_STATUS(nv.get().c_str()),
537 metadata::CALLOUT_INVENTORY_PATH(inventoryPath.c_str()));
538
539 faultFound = true;
540 }
Brandon Wyman875b3632017-09-13 18:46:03 -0500541 }
542}
543
Brandon Wyman1db9a9e2017-07-26 18:50:22 -0500544void PowerSupply::clearFaults()
545{
Brandon Wymane4af9802017-11-13 15:58:33 -0600546 readFail = 0;
Brandon Wyman6ccce0b2017-10-26 15:13:10 -0500547 readFailLogged = false;
Brandon Wymana3c675c2017-11-14 14:54:54 -0600548 inputFault = 0;
Brandon Wyman6ccce0b2017-10-26 15:13:10 -0500549 powerOnFault = 0;
Brandon Wymandd61be42017-11-07 18:38:54 -0600550 outputOCFault = 0;
Brandon Wyman2ab319b2017-11-08 17:34:59 -0600551 outputOVFault = 0;
Brandon Wymanba255532017-11-08 17:44:10 -0600552 fanFault = 0;
Brandon Wyman50044ea2017-11-08 17:58:56 -0600553 temperatureFault = 0;
Brandon Wyman3343e822017-11-03 16:54:11 -0500554 faultFound = false;
Brandon Wyman6ccce0b2017-10-26 15:13:10 -0500555
Brandon Wyman1db9a9e2017-07-26 18:50:22 -0500556 return;
557}
558
Brandon Wyman43ce2082017-11-30 17:24:01 -0600559void PowerSupply::resolveError(const std::string& callout,
560 const std::string& message)
561{
Brandon Wyman01741f12017-12-01 17:22:08 -0600562 using EndpointList = std::vector<std::string>;
563
564 try
565 {
566 auto path = callout + "/fault";
567 // Get the service name from the mapper for the fault callout
568 auto service = util::getService(path,
569 ASSOCIATION_IFACE,
570 bus);
571
572 // Use getProperty utility function to get log entries (endpoints)
573 EndpointList logEntries;
Matt Spinler589e8722018-01-04 15:24:49 -0600574 util::getProperty(ASSOCIATION_IFACE, ENDPOINTS_PROP, path, service,
Brandon Wyman01741f12017-12-01 17:22:08 -0600575 bus, logEntries);
576
577 // It is possible that all such entries for this callout have since
578 // been deleted.
579 if (logEntries.empty())
580 {
581 return;
582 }
583
584 auto logEntryService = util::getService(logEntries[0], LOGGING_IFACE,
585 bus);
586 if (logEntryService.empty())
587 {
588 return;
589 }
590
591 // go through each log entry that matches this callout path
592 std::string logMessage;
593 for (const auto& logEntry : logEntries)
594 {
595 // Check to see if this logEntry has a message that matches.
Matt Spinler589e8722018-01-04 15:24:49 -0600596 util::getProperty(LOGGING_IFACE, MESSAGE_PROP, logEntry,
Brandon Wyman01741f12017-12-01 17:22:08 -0600597 logEntryService, bus, logMessage);
598
599 if (message == logMessage)
600 {
601 // Log entry matches call out and message, set Resolved to true
602 bool resolved = true;
Matt Spinler589e8722018-01-04 15:24:49 -0600603 util::setProperty(LOGGING_IFACE, RESOLVED_PROP, logEntry,
Brandon Wyman01741f12017-12-01 17:22:08 -0600604 logEntryService, bus, resolved);
605 }
606
607 }
608
609 }
610 catch (std::exception& e)
611 {
612 log<level::INFO>("Failed to resolve error",
613 entry("CALLOUT=%s", callout.c_str()),
614 entry("MESSAGE=%s", message.c_str()));
615 }
616
Brandon Wyman43ce2082017-11-30 17:24:01 -0600617}
618
Matt Spinler234ce0d2018-01-04 15:06:57 -0600619void PowerSupply::updateInventory()
620{
621}
622
Brandon Wyman24e422f2017-07-25 19:40:14 -0500623}
624}
625}