blob: 6408ef4e015001de7f080bc434995d10278d5369 [file] [log] [blame]
Matthew Barthc95c5272020-06-15 19:51:13 -05001/**
Mike Capps7b34ee02022-05-04 14:16:12 -04002 * Copyright © 2022 IBM Corporation
Matthew Barthc95c5272020-06-15 19:51:13 -05003 *
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 */
Matthew Barthc95c5272020-06-15 19:51:13 -050016#include "system.hpp"
17
Mike Cappsbf8e56f2022-06-29 14:23:07 -040018#include "dbus_paths.hpp"
Matthew Barthc95c5272020-06-15 19:51:13 -050019#include "fan.hpp"
20#include "fan_defs.hpp"
21#include "tach_sensor.hpp"
22#include "trust_manager.hpp"
23#include "types.hpp"
Mike Cappsfdcd5db2021-05-20 12:47:10 -040024#include "utility.hpp"
Matthew Barthc95c5272020-06-15 19:51:13 -050025#ifdef MONITOR_USE_JSON
Mike Cappsb4379a12021-10-11 14:18:06 -040026#include "json_config.hpp"
Matthew Barthc95c5272020-06-15 19:51:13 -050027#include "json_parser.hpp"
28#endif
29
Matt Spinlerc8d3c512021-01-06 14:22:25 -060030#include "config.h"
31
Matt Spinlerbb449c12021-06-14 11:45:28 -060032#include "hwmon_ffdc.hpp"
33
Matthew Barthc95c5272020-06-15 19:51:13 -050034#include <nlohmann/json.hpp>
Matthew Barthd06905c2020-06-12 08:13:06 -050035#include <phosphor-logging/log.hpp>
Matthew Barthc95c5272020-06-15 19:51:13 -050036#include <sdbusplus/bus.hpp>
Patrick Williamscb356d42022-07-22 19:26:53 -050037#include <sdbusplus/bus/match.hpp>
Matthew Barthc95c5272020-06-15 19:51:13 -050038#include <sdeventplus/event.hpp>
Matthew Barthd06905c2020-06-12 08:13:06 -050039#include <sdeventplus/source/signal.hpp>
Matthew Barthc95c5272020-06-15 19:51:13 -050040
41namespace phosphor::fan::monitor
42{
43
44using json = nlohmann::json;
Matt Spinlerf13b42e2020-10-26 15:29:49 -050045using Severity = sdbusplus::xyz::openbmc_project::Logging::server::Entry::Level;
46
Matthew Barthd06905c2020-06-12 08:13:06 -050047using namespace phosphor::logging;
Matthew Barthc95c5272020-06-15 19:51:13 -050048
Matt Spinler4f472a82022-08-26 13:55:34 -050049const std::string System::dumpFile = "/tmp/fan_monitor_dump.json";
50
Patrick Williamscb356d42022-07-22 19:26:53 -050051System::System(Mode mode, sdbusplus::bus_t& bus,
Matthew Barthc95c5272020-06-15 19:51:13 -050052 const sdeventplus::Event& event) :
53 _mode(mode),
Matt Spinlerc8d3c512021-01-06 14:22:25 -060054 _bus(bus), _event(event),
55 _powerState(std::make_unique<PGoodState>(
Matt Spinlere892e392020-10-14 13:21:31 -050056 bus, std::bind(std::mem_fn(&System::powerStateChanged), this,
Matt Spinlerc8d3c512021-01-06 14:22:25 -060057 std::placeholders::_1))),
58 _thermalAlert(bus, THERMAL_ALERT_OBJPATH)
Matt Spinler7d135642021-02-04 12:44:17 -060059{}
Matt Spinlere892e392020-10-14 13:21:31 -050060
Matthew Barth823bc492021-06-21 14:19:09 -050061void System::start()
Matt Spinler7d135642021-02-04 12:44:17 -060062{
Mike Cappsb4379a12021-10-11 14:18:06 -040063 namespace match = sdbusplus::bus::match;
64
65 // must be done before service detection
Patrick Williamscb356d42022-07-22 19:26:53 -050066 _inventoryMatch = std::make_unique<sdbusplus::bus::match_t>(
Mike Cappsb4379a12021-10-11 14:18:06 -040067 _bus, match::rules::nameOwnerChanged(util::INVENTORY_SVC),
68 std::bind(&System::inventoryOnlineCb, this, std::placeholders::_1));
69
70 bool invServiceRunning = util::SDBusPlus::callMethodAndRead<bool>(
71 _bus, "org.freedesktop.DBus", "/org/freedesktop/DBus",
72 "org.freedesktop.DBus", "NameHasOwner", util::INVENTORY_SVC);
73
74 if (invServiceRunning)
75 {
76 _inventoryMatch.reset();
77
78 if (!_loaded)
79 {
80 load();
81 }
82 }
83}
84
85void System::load()
86{
Matthew Barthc95c5272020-06-15 19:51:13 -050087 json jsonObj = json::object();
88#ifdef MONITOR_USE_JSON
Mike Cappsb4379a12021-10-11 14:18:06 -040089 try
90 {
Mike Capps808d7fe2022-06-13 10:12:16 -040091 jsonObj = getJsonObj();
Matthew Barthc95c5272020-06-15 19:51:13 -050092#endif
Mike Cappsb4379a12021-10-11 14:18:06 -040093 auto trustGrps = getTrustGroups(jsonObj);
94 auto fanDefs = getFanDefinitions(jsonObj);
95 // Retrieve and set trust groups within the trust manager
96 setTrustMgr(getTrustGroups(jsonObj));
97 // Clear/set configured fan definitions
98 _fans.clear();
99 _fanHealth.clear();
100 // Retrieve fan definitions and create fan objects to be monitored
101 setFans(fanDefs);
102 setFaultConfig(jsonObj);
103 log<level::INFO>("Configuration loaded");
104
105 _loaded = true;
106#ifdef MONITOR_USE_JSON
107 }
108 catch (const phosphor::fan::NoConfigFound&)
109 {}
110#endif
Matt Spinlere892e392020-10-14 13:21:31 -0500111
Matt Spinlere892e392020-10-14 13:21:31 -0500112 if (_powerState->isPowerOn())
113 {
Matt Spinler752f24e2022-07-06 15:57:54 -0500114 // Fans could be missing on startup, so check the power off rules.
115 // Tach sensors default to functional, so they wouldn't cause a power
116 // off here.
Matt Spinlere892e392020-10-14 13:21:31 -0500117 std::for_each(_powerOffRules.begin(), _powerOffRules.end(),
118 [this](auto& rule) {
Matt Spinlere892e392020-10-14 13:21:31 -0500119 rule->check(PowerRuleState::runtime, _fanHealth);
120 });
121 }
Mike Cappsfdcd5db2021-05-20 12:47:10 -0400122
Mike Cappsb4379a12021-10-11 14:18:06 -0400123 subscribeSensorsToServices();
Mike Cappsfdcd5db2021-05-20 12:47:10 -0400124}
125
Mike Capps25f03272021-09-13 13:38:44 -0400126void System::subscribeSensorsToServices()
Mike Cappsfdcd5db2021-05-20 12:47:10 -0400127{
Mike Capps25f03272021-09-13 13:38:44 -0400128 namespace match = sdbusplus::bus::match;
129
Mike Cappsb4379a12021-10-11 14:18:06 -0400130 _sensorMatch.clear();
131
Mike Cappsfdcd5db2021-05-20 12:47:10 -0400132 SensorMapType sensorMap;
133
134 // build a list of all interfaces, always including the value interface
135 // using set automatically guards against duplicates
136 std::set<std::string> unique_interfaces{util::FAN_SENSOR_VALUE_INTF};
137
138 for (const auto& fan : _fans)
139 {
140 for (const auto& sensor : fan->sensors())
141 {
142 unique_interfaces.insert(sensor->getInterface());
143 }
144 }
145 // convert them to vector to pass into getSubTreeRaw
146 std::vector<std::string> interfaces(unique_interfaces.begin(),
147 unique_interfaces.end());
148
Mike Capps25f03272021-09-13 13:38:44 -0400149 try
Mike Cappsfdcd5db2021-05-20 12:47:10 -0400150 {
Mike Capps25f03272021-09-13 13:38:44 -0400151 // get service information for all service names that are
152 // hosting these interfaces
153 auto serviceObjects = util::SDBusPlus::getSubTreeRaw(
154 _bus, FAN_SENSOR_PATH, interfaces, 0);
155
156 for (const auto& fan : _fans)
Mike Cappsfdcd5db2021-05-20 12:47:10 -0400157 {
Mike Capps25f03272021-09-13 13:38:44 -0400158 // For every sensor in each fan
159 for (const auto& sensor : fan->sensors())
Mike Cappsfdcd5db2021-05-20 12:47:10 -0400160 {
Mike Capps25f03272021-09-13 13:38:44 -0400161 const auto itServ = serviceObjects.find(sensor->name());
Mike Cappsfdcd5db2021-05-20 12:47:10 -0400162
Mike Capps25f03272021-09-13 13:38:44 -0400163 if (serviceObjects.end() == itServ || itServ->second.empty())
164 {
165 getLogger().log(
166 fmt::format("Fan sensor entry {} not found in D-Bus",
167 sensor->name()),
168 Logger::error);
169 continue;
170 }
171
172 for (const auto& [serviceName, unused] : itServ->second)
173 {
174 // associate service name with sensor
175 sensorMap[serviceName].insert(sensor);
176 }
Mike Cappsfdcd5db2021-05-20 12:47:10 -0400177 }
178 }
Mike Cappsfdcd5db2021-05-20 12:47:10 -0400179
Mike Capps25f03272021-09-13 13:38:44 -0400180 // only create 1 match per service
181 for (const auto& [serviceName, unused] : sensorMap)
182 {
183 // map its service name to the sensor
Patrick Williamscb356d42022-07-22 19:26:53 -0500184 _sensorMatch.emplace_back(std::make_unique<sdbusplus::bus::match_t>(
Mike Capps25f03272021-09-13 13:38:44 -0400185 _bus, match::rules::nameOwnerChanged(serviceName),
186 std::bind(&System::tachSignalOffline, this,
187 std::placeholders::_1, sensorMap)));
188 }
189 }
190 catch (const util::DBusError&)
191 {
192 // catch exception from getSubTreeRaw() when fan sensor paths don't
193 // exist yet
194 }
Matthew Barthd06905c2020-06-12 08:13:06 -0500195}
196
Patrick Williamscb356d42022-07-22 19:26:53 -0500197void System::inventoryOnlineCb(sdbusplus::message_t& msg)
Mike Cappsb4379a12021-10-11 14:18:06 -0400198{
199 namespace match = sdbusplus::bus::match;
200
201 std::string iface;
202 msg.read(iface);
203
204 if (util::INVENTORY_INTF != iface)
205 {
206 return;
207 }
208
209 std::string oldName;
210 msg.read(oldName);
211
212 std::string newName;
213 msg.read(newName);
214
215 // newName should never be empty since match was reset on the first
216 // nameOwnerChanged signal received from the service.
217 if (!_loaded && !newName.empty())
218 {
219 load();
220 }
221
222 // cancel any further notifications about the service state
223 _inventoryMatch.reset();
224}
225
Matthew Barthd06905c2020-06-12 08:13:06 -0500226void System::sighupHandler(sdeventplus::source::Signal&,
227 const struct signalfd_siginfo*)
228{
229 try
Matthew Barthc95c5272020-06-15 19:51:13 -0500230 {
Mike Cappsb4379a12021-10-11 14:18:06 -0400231 load();
Matthew Barthd06905c2020-06-12 08:13:06 -0500232 }
Mike Cappsb4379a12021-10-11 14:18:06 -0400233 catch (std::runtime_error& re)
Matthew Barthd06905c2020-06-12 08:13:06 -0500234 {
235 log<level::ERR>("Error reloading config, no config changes made",
236 entry("LOAD_ERROR=%s", re.what()));
Matthew Barthc95c5272020-06-15 19:51:13 -0500237 }
238}
239
240const std::vector<CreateGroupFunction>
Mike Capps808d7fe2022-06-13 10:12:16 -0400241 System::getTrustGroups([[maybe_unused]] const json& jsonObj)
Matthew Barthc95c5272020-06-15 19:51:13 -0500242{
243#ifdef MONITOR_USE_JSON
244 return getTrustGrps(jsonObj);
245#else
246 return trustGroups;
247#endif
248}
249
Matthew Barthd06905c2020-06-12 08:13:06 -0500250void System::setTrustMgr(const std::vector<CreateGroupFunction>& groupFuncs)
251{
252 _trust = std::make_unique<trust::Manager>(groupFuncs);
253}
254
Mike Capps808d7fe2022-06-13 10:12:16 -0400255const std::vector<FanDefinition>
256 System::getFanDefinitions([[maybe_unused]] const json& jsonObj)
Matthew Barthc95c5272020-06-15 19:51:13 -0500257{
258#ifdef MONITOR_USE_JSON
259 return getFanDefs(jsonObj);
260#else
261 return fanDefinitions;
262#endif
263}
264
Matthew Barthd06905c2020-06-12 08:13:06 -0500265void System::setFans(const std::vector<FanDefinition>& fanDefs)
266{
267 for (const auto& fanDef : fanDefs)
268 {
269 // Check if a condition exists on the fan
270 auto condition = std::get<conditionField>(fanDef);
271 if (condition)
272 {
273 // Condition exists, skip adding fan if it fails
274 if (!(*condition)(_bus))
275 {
276 continue;
277 }
278 }
279 _fans.emplace_back(
Matt Spinlerb0412d02020-10-12 16:53:52 -0500280 std::make_unique<Fan>(_mode, _bus, _event, _trust, fanDef, *this));
Matt Spinlerb63aa092020-10-14 09:45:11 -0500281
282 updateFanHealth(*(_fans.back()));
Matthew Barthd06905c2020-06-12 08:13:06 -0500283 }
284}
285
Mike Cappsfdcd5db2021-05-20 12:47:10 -0400286// callback indicating a service went [on|off]line.
287// Determine on/offline status, set all sensors for that service
288// to new state
289//
Patrick Williamscb356d42022-07-22 19:26:53 -0500290void System::tachSignalOffline(sdbusplus::message_t& msg,
Mike Cappsfdcd5db2021-05-20 12:47:10 -0400291 SensorMapType const& sensorMap)
292{
293 std::string serviceName, oldOwner, newOwner;
294
295 msg.read(serviceName);
296 msg.read(oldOwner);
297 msg.read(newOwner);
298
299 // true if sensor server came back online, false -> went offline
300 bool hasOwner = !newOwner.empty() && oldOwner.empty();
301
302 std::string stateStr(hasOwner ? "online" : "offline");
303 getLogger().log(fmt::format("Changing sensors for service {} to {}",
304 serviceName, stateStr),
305 Logger::info);
306
307 auto sensorItr(sensorMap.find(serviceName));
308
309 if (sensorItr != sensorMap.end())
310 {
311 // set all sensors' owner state to not-owned
312 for (auto& sensor : sensorItr->second)
313 {
314 sensor->setOwner(hasOwner);
315 sensor->getFan().process(*sensor);
316 }
317 }
318}
319
Matt Spinlerb63aa092020-10-14 09:45:11 -0500320void System::updateFanHealth(const Fan& fan)
321{
322 std::vector<bool> sensorStatus;
323 for (const auto& sensor : fan.sensors())
324 {
325 sensorStatus.push_back(sensor->functional());
326 }
327
328 _fanHealth[fan.getName()] =
329 std::make_tuple(fan.present(), std::move(sensorStatus));
330}
331
Matt Spinler4283c5d2021-03-01 15:56:00 -0600332void System::fanStatusChange(const Fan& fan, bool skipRulesCheck)
Matt Spinlerb63aa092020-10-14 09:45:11 -0500333{
334 updateFanHealth(fan);
Matt Spinlere892e392020-10-14 13:21:31 -0500335
Matt Spinler4283c5d2021-03-01 15:56:00 -0600336 if (_powerState->isPowerOn() && !skipRulesCheck)
Matt Spinlere892e392020-10-14 13:21:31 -0500337 {
338 std::for_each(_powerOffRules.begin(), _powerOffRules.end(),
339 [this](auto& rule) {
340 rule->check(PowerRuleState::runtime, _fanHealth);
341 });
342 }
343}
344
Mike Capps808d7fe2022-06-13 10:12:16 -0400345void System::setFaultConfig([[maybe_unused]] const json& jsonObj)
Matt Spinlere892e392020-10-14 13:21:31 -0500346{
347#ifdef MONITOR_USE_JSON
348 std::shared_ptr<PowerInterfaceBase> powerInterface =
Matt Spinlerba3ee9a2021-01-06 14:45:50 -0600349 std::make_shared<PowerInterface>(_thermalAlert);
Matt Spinlere892e392020-10-14 13:21:31 -0500350
Matt Spinlerac1efc12020-10-27 10:20:11 -0500351 PowerOffAction::PrePowerOffFunc func =
352 std::bind(std::mem_fn(&System::logShutdownError), this);
353
354 _powerOffRules = getPowerOffRules(jsonObj, powerInterface, func);
Matt Spinlerf13b42e2020-10-26 15:29:49 -0500355
356 _numNonfuncSensorsBeforeError = getNumNonfuncRotorsBeforeError(jsonObj);
Matt Spinlere892e392020-10-14 13:21:31 -0500357#endif
358}
359
360void System::powerStateChanged(bool powerStateOn)
361{
Matt Spinler7d135642021-02-04 12:44:17 -0600362 std::for_each(_fans.begin(), _fans.end(), [powerStateOn](auto& fan) {
363 fan->powerStateChanged(powerStateOn);
364 });
365
Matt Spinlere892e392020-10-14 13:21:31 -0500366 if (powerStateOn)
367 {
Mike Cappsb4379a12021-10-11 14:18:06 -0400368 if (!_loaded)
Matt Spinler7d135642021-02-04 12:44:17 -0600369 {
370 log<level::ERR>("No conf file found at power on");
Matthew Barthba53d3e2021-02-24 07:48:37 -0600371 throw std::runtime_error("No conf file found at power on");
Matt Spinler7d135642021-02-04 12:44:17 -0600372 }
373
Matt Spinlerbb449c12021-06-14 11:45:28 -0600374 // If no fan has its sensors on D-Bus, then there is a problem
375 // with the fan controller. Log an error and shut down.
376 if (std::all_of(_fans.begin(), _fans.end(), [](const auto& fan) {
377 return fan->numSensorsOnDBusAtPowerOn() == 0;
378 }))
379 {
Chau Ly751c8be2023-01-13 08:21:03 +0000380#if DELAY_HOST_CONTROL > 0
381 sleep(DELAY_HOST_CONTROL);
382 std::for_each(_fans.begin(), _fans.end(),
383 [powerStateOn](auto& fan) {
384 fan->powerStateChanged(powerStateOn);
385 });
386 if (std::all_of(_fans.begin(), _fans.end(), [](const auto& fan) {
387 return fan->numSensorsOnDBusAtPowerOn() == 0;
388 }))
389 {
390 handleOfflineFanController();
391 return;
392 }
393#else
Matt Spinlerbb449c12021-06-14 11:45:28 -0600394 handleOfflineFanController();
395 return;
Chau Ly751c8be2023-01-13 08:21:03 +0000396#endif
Matt Spinlerbb449c12021-06-14 11:45:28 -0600397 }
398
Mike Capps25f03272021-09-13 13:38:44 -0400399 if (_sensorMatch.empty())
400 {
401 subscribeSensorsToServices();
402 }
403
Matt Spinlere892e392020-10-14 13:21:31 -0500404 std::for_each(_powerOffRules.begin(), _powerOffRules.end(),
405 [this](auto& rule) {
406 rule->check(PowerRuleState::atPgood, _fanHealth);
407 });
408 std::for_each(_powerOffRules.begin(), _powerOffRules.end(),
409 [this](auto& rule) {
410 rule->check(PowerRuleState::runtime, _fanHealth);
411 });
412 }
413 else
414 {
Matt Spinlerc8d3c512021-01-06 14:22:25 -0600415 _thermalAlert.enabled(false);
416
Matt Spinlere892e392020-10-14 13:21:31 -0500417 // Cancel any in-progress power off actions
418 std::for_each(_powerOffRules.begin(), _powerOffRules.end(),
419 [this](auto& rule) { rule->cancel(); });
420 }
Matt Spinlerb63aa092020-10-14 09:45:11 -0500421}
422
Matt Spinlerf13b42e2020-10-26 15:29:49 -0500423void System::sensorErrorTimerExpired(const Fan& fan, const TachSensor& sensor)
424{
425 std::string fanPath{util::INVENTORY_PATH + fan.getName()};
426
427 getLogger().log(
428 fmt::format("Creating event log for faulted fan {} sensor {}", fanPath,
429 sensor.name()),
430 Logger::error);
431
432 // In order to know if the event log should have a severity of error or
433 // informational, count the number of existing nonfunctional sensors and
434 // compare it to _numNonfuncSensorsBeforeError.
435 size_t nonfuncSensors = 0;
436 for (const auto& fan : _fans)
437 {
438 for (const auto& s : fan->sensors())
439 {
440 // Don't count nonfunctional sensors that still have their
441 // error timer running as nonfunctional since they haven't
442 // had event logs created for those errors yet.
443 if (!s->functional() && !s->errorTimerRunning())
444 {
445 nonfuncSensors++;
446 }
447 }
448 }
449
450 Severity severity = Severity::Error;
451 if (nonfuncSensors < _numNonfuncSensorsBeforeError)
452 {
453 severity = Severity::Informational;
454 }
455
456 auto error =
457 std::make_unique<FanError>("xyz.openbmc_project.Fan.Error.Fault",
458 fanPath, sensor.name(), severity);
459
460 auto sensorData = captureSensorData();
461 error->commit(sensorData);
462
Matt Spinlerac1efc12020-10-27 10:20:11 -0500463 // Save the error so it can be committed again on a power off.
464 _lastError = std::move(error);
Matt Spinlerf13b42e2020-10-26 15:29:49 -0500465}
466
Matt Spinler27f6b682020-10-27 08:43:37 -0500467void System::fanMissingErrorTimerExpired(const Fan& fan)
468{
469 std::string fanPath{util::INVENTORY_PATH + fan.getName()};
470
471 getLogger().log(
472 fmt::format("Creating event log for missing fan {}", fanPath),
473 Logger::error);
474
475 auto error = std::make_unique<FanError>(
476 "xyz.openbmc_project.Fan.Error.Missing", fanPath, "", Severity::Error);
477
478 auto sensorData = captureSensorData();
479 error->commit(sensorData);
480
Matt Spinlerac1efc12020-10-27 10:20:11 -0500481 // Save the error so it can be committed again on a power off.
482 _lastError = std::move(error);
483}
484
485void System::logShutdownError()
486{
487 if (_lastError)
488 {
489 getLogger().log("Re-committing previous fan error before power off");
490
491 // Still use the latest sensor data
492 auto sensorData = captureSensorData();
Matt Spinlerf435eb12021-05-11 14:44:25 -0500493 _lastError->commit(sensorData, true);
Matt Spinlerac1efc12020-10-27 10:20:11 -0500494 }
Matt Spinler27f6b682020-10-27 08:43:37 -0500495}
496
Matt Spinlerf13b42e2020-10-26 15:29:49 -0500497json System::captureSensorData()
498{
499 json data;
500
501 for (const auto& fan : _fans)
502 {
503 for (const auto& sensor : fan->sensors())
504 {
505 json values;
506 values["present"] = fan->present();
507 values["functional"] = sensor->functional();
Matt Spinlerd16d4642022-08-26 13:32:07 -0500508 values["in_range"] = !fan->outOfRange(*sensor);
Matt Spinlerf13b42e2020-10-26 15:29:49 -0500509 values["tach"] = sensor->getInput();
Mike Capps7b34ee02022-05-04 14:16:12 -0400510
Matt Spinlerf13b42e2020-10-26 15:29:49 -0500511 if (sensor->hasTarget())
512 {
513 values["target"] = sensor->getTarget();
514 }
515
Mike Capps7b34ee02022-05-04 14:16:12 -0400516 // convert between string/json to remove newlines
517 values["prev_tachs"] = json(sensor->getPrevTach()).dump();
518
519 if (sensor->hasTarget())
520 {
521 values["prev_targets"] = json(sensor->getPrevTarget()).dump();
522 }
523
Matt Spinler87f9adc2022-08-11 13:17:09 -0500524 if (sensor->getMethod() == MethodMode::count)
525 {
526 values["ticks"] = sensor->getCounter();
527 }
Matt Spinlerf13b42e2020-10-26 15:29:49 -0500528 data["sensors"][sensor->name()] = values;
529 }
530 }
531
532 return data;
533}
534
Matt Spinlerbb449c12021-06-14 11:45:28 -0600535void System::handleOfflineFanController()
536{
537 getLogger().log("The fan controller appears to be offline. Shutting down.",
538 Logger::error);
539
540 auto ffdc = collectHwmonFFDC();
541
542 FanError error{"xyz.openbmc_project.Fan.Error.FanControllerOffline",
543 Severity::Critical};
544 error.commit(ffdc, true);
545
546 PowerInterface::executeHardPowerOff();
Mike Capps683a96c2022-04-27 16:46:06 -0400547
548 createBmcDump();
549}
550
551/**
552 * @brief Create a BMC Dump
553 */
554void System::createBmcDump() const
555{
556 try
557 {
558 util::SDBusPlus::callMethod(
559 "xyz.openbmc_project.Dump.Manager", "/xyz/openbmc_project/dump/bmc",
560 "xyz.openbmc_project.Dump.Create", "CreateDump",
561 std::vector<
562 std::pair<std::string, std::variant<std::string, uint64_t>>>());
563 }
Mike Capps477b13b2022-07-11 10:45:46 -0400564 catch (const std::exception& e)
565 {
566 getLogger().log(
567 fmt::format("Caught exception while creating BMC dump: {}",
568 e.what()),
569 Logger::error);
570 }
Matt Spinlerbb449c12021-06-14 11:45:28 -0600571}
572
Matt Spinler4f472a82022-08-26 13:55:34 -0500573void System::dumpDebugData(sdeventplus::source::Signal&,
574 const struct signalfd_siginfo*)
575{
576 json output;
577
578 if (_loaded)
579 {
580 output["logs"] = getLogger().getLogs();
581 output["sensors"] = captureSensorData();
582 }
583 else
584 {
585 output["error"] = "Fan monitor not loaded yet. Try again later.";
586 }
587
588 std::ofstream file{System::dumpFile};
589 if (!file)
590 {
591 log<level::ERR>("Could not open file for fan monitor dump");
592 }
593 else
594 {
595 file << std::setw(4) << output;
596 }
597}
598
Matthew Barthc95c5272020-06-15 19:51:13 -0500599} // namespace phosphor::fan::monitor