19c0715b6SMatt Spinler /**
29c0715b6SMatt Spinler * Copyright © 2021 IBM Corporation
39c0715b6SMatt Spinler *
49c0715b6SMatt Spinler * Licensed under the Apache License, Version 2.0 (the "License");
59c0715b6SMatt Spinler * you may not use this file except in compliance with the License.
69c0715b6SMatt Spinler * You may obtain a copy of the License at
79c0715b6SMatt Spinler *
89c0715b6SMatt Spinler * http://www.apache.org/licenses/LICENSE-2.0
99c0715b6SMatt Spinler *
109c0715b6SMatt Spinler * Unless required by applicable law or agreed to in writing, software
119c0715b6SMatt Spinler * distributed under the License is distributed on an "AS IS" BASIS,
129c0715b6SMatt Spinler * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
139c0715b6SMatt Spinler * See the License for the specific language governing permissions and
149c0715b6SMatt Spinler * limitations under the License.
159c0715b6SMatt Spinler */
169c0715b6SMatt Spinler #include "config.h"
179c0715b6SMatt Spinler
189c0715b6SMatt Spinler #include "shutdown_alarm_monitor.hpp"
199c0715b6SMatt Spinler
203efec61cSMatt Spinler #include <unistd.h>
219c0715b6SMatt Spinler
22*32c4feffSAnwaar Hadi #include <phosphor-logging/lg2.hpp>
23ffd54674SMatt Spinler #include <xyz/openbmc_project/Logging/Entry/server.hpp>
249c0715b6SMatt Spinler
259c0715b6SMatt Spinler namespace sensor::monitor
269c0715b6SMatt Spinler {
279c0715b6SMatt Spinler using namespace phosphor::fan::util;
289c0715b6SMatt Spinler using namespace phosphor::fan;
299c0715b6SMatt Spinler namespace fs = std::filesystem;
309c0715b6SMatt Spinler
319c0715b6SMatt Spinler const std::map<ShutdownType, std::string> shutdownInterfaces{
329c0715b6SMatt Spinler {ShutdownType::hard, "xyz.openbmc_project.Sensor.Threshold.HardShutdown"},
339c0715b6SMatt Spinler {ShutdownType::soft, "xyz.openbmc_project.Sensor.Threshold.SoftShutdown"}};
349c0715b6SMatt Spinler
359c0715b6SMatt Spinler const std::map<ShutdownType, std::map<AlarmType, std::string>> alarmProperties{
369c0715b6SMatt Spinler {ShutdownType::hard,
379c0715b6SMatt Spinler {{AlarmType::low, "HardShutdownAlarmLow"},
389c0715b6SMatt Spinler {AlarmType::high, "HardShutdownAlarmHigh"}}},
399c0715b6SMatt Spinler {ShutdownType::soft,
409c0715b6SMatt Spinler {{AlarmType::low, "SoftShutdownAlarmLow"},
419c0715b6SMatt Spinler {AlarmType::high, "SoftShutdownAlarmHigh"}}}};
429c0715b6SMatt Spinler
430b839516SMatt Spinler const std::map<ShutdownType, std::chrono::milliseconds> shutdownDelays{
440b839516SMatt Spinler {ShutdownType::hard,
450b839516SMatt Spinler std::chrono::milliseconds{SHUTDOWN_ALARM_HARD_SHUTDOWN_DELAY_MS}},
460b839516SMatt Spinler {ShutdownType::soft,
470b839516SMatt Spinler std::chrono::milliseconds{SHUTDOWN_ALARM_SOFT_SHUTDOWN_DELAY_MS}}};
480b839516SMatt Spinler
49ffd54674SMatt Spinler const std::map<ShutdownType, std::map<AlarmType, std::string>> alarmEventLogs{
50ffd54674SMatt Spinler {ShutdownType::hard,
51ffd54674SMatt Spinler {{AlarmType::high,
52ffd54674SMatt Spinler "xyz.openbmc_project.Sensor.Threshold.Error.HardShutdownAlarmHigh"},
53ffd54674SMatt Spinler {AlarmType::low, "xyz.openbmc_project.Sensor.Threshold.Error."
54ffd54674SMatt Spinler "HardShutdownAlarmLow"}}},
55ffd54674SMatt Spinler {ShutdownType::soft,
56ffd54674SMatt Spinler {{AlarmType::high,
57ffd54674SMatt Spinler "xyz.openbmc_project.Sensor.Threshold.Error.SoftShutdownAlarmHigh"},
58ffd54674SMatt Spinler {AlarmType::low, "xyz.openbmc_project.Sensor.Threshold.Error."
59ffd54674SMatt Spinler "SoftShutdownAlarmLow"}}}};
60ffd54674SMatt Spinler
61ffd54674SMatt Spinler const std::map<ShutdownType, std::map<AlarmType, std::string>>
62ffd54674SMatt Spinler alarmClearEventLogs{
63ffd54674SMatt Spinler {ShutdownType::hard,
64ffd54674SMatt Spinler {{AlarmType::high, "xyz.openbmc_project.Sensor.Threshold.Error."
65ffd54674SMatt Spinler "HardShutdownAlarmHighClear"},
66ffd54674SMatt Spinler {AlarmType::low, "xyz.openbmc_project.Sensor.Threshold.Error."
67ffd54674SMatt Spinler "HardShutdownAlarmLowClear"}}},
68ffd54674SMatt Spinler {ShutdownType::soft,
69ffd54674SMatt Spinler {{AlarmType::high, "xyz.openbmc_project.Sensor.Threshold.Error."
70ffd54674SMatt Spinler "SoftShutdownAlarmHighClear"},
71ffd54674SMatt Spinler {AlarmType::low, "xyz.openbmc_project.Sensor.Threshold.Error."
72ffd54674SMatt Spinler "SoftShutdownAlarmLowClear"}}}};
73ffd54674SMatt Spinler
740b839516SMatt Spinler constexpr auto systemdService = "org.freedesktop.systemd1";
750b839516SMatt Spinler constexpr auto systemdPath = "/org/freedesktop/systemd1";
760b839516SMatt Spinler constexpr auto systemdMgrIface = "org.freedesktop.systemd1.Manager";
770b839516SMatt Spinler constexpr auto valueInterface = "xyz.openbmc_project.Sensor.Value";
780b839516SMatt Spinler constexpr auto valueProperty = "Value";
79ffd54674SMatt Spinler const auto loggingService = "xyz.openbmc_project.Logging";
80ffd54674SMatt Spinler const auto loggingPath = "/xyz/openbmc_project/logging";
81ffd54674SMatt Spinler const auto loggingCreateIface = "xyz.openbmc_project.Logging.Create";
820b839516SMatt Spinler
839c0715b6SMatt Spinler using namespace sdbusplus::bus::match;
849c0715b6SMatt Spinler
ShutdownAlarmMonitor(sdbusplus::bus_t & bus,sdeventplus::Event & event,std::shared_ptr<PowerState> powerState)857f6946b2SMatt Spinler ShutdownAlarmMonitor::ShutdownAlarmMonitor(
86cb356d48SPatrick Williams sdbusplus::bus_t& bus, sdeventplus::Event& event,
877f6946b2SMatt Spinler std::shared_ptr<PowerState> powerState) :
88dfddd648SPatrick Williams bus(bus), event(event), _powerState(std::move(powerState)),
899c0715b6SMatt Spinler hardShutdownMatch(bus,
909c0715b6SMatt Spinler "type='signal',member='PropertiesChanged',"
919c0715b6SMatt Spinler "path_namespace='/xyz/openbmc_project/sensors',"
929c0715b6SMatt Spinler "arg0='" +
93d914ebf4SMatthew Barth shutdownInterfaces.at(ShutdownType::hard) + "'",
949c0715b6SMatt Spinler std::bind(&ShutdownAlarmMonitor::propertiesChanged, this,
959c0715b6SMatt Spinler std::placeholders::_1)),
969c0715b6SMatt Spinler softShutdownMatch(bus,
979c0715b6SMatt Spinler "type='signal',member='PropertiesChanged',"
989c0715b6SMatt Spinler "path_namespace='/xyz/openbmc_project/sensors',"
999c0715b6SMatt Spinler "arg0='" +
100d914ebf4SMatthew Barth shutdownInterfaces.at(ShutdownType::soft) + "'",
1019c0715b6SMatt Spinler std::bind(&ShutdownAlarmMonitor::propertiesChanged, this,
1027f6946b2SMatt Spinler std::placeholders::_1))
1039c0715b6SMatt Spinler {
1047f6946b2SMatt Spinler _powerState->addCallback("shutdownMon",
1057f6946b2SMatt Spinler std::bind(&ShutdownAlarmMonitor::powerStateChanged,
1067f6946b2SMatt Spinler this, std::placeholders::_1));
1079c0715b6SMatt Spinler findAlarms();
1089c0715b6SMatt Spinler
1099c0715b6SMatt Spinler if (_powerState->isPowerOn())
1109c0715b6SMatt Spinler {
1119c0715b6SMatt Spinler checkAlarms();
11208a66efaSMatt Spinler
11308a66efaSMatt Spinler // Get rid of any previous saved timestamps that don't
11408a66efaSMatt Spinler // apply anymore.
11508a66efaSMatt Spinler timestamps.prune(alarms);
11608a66efaSMatt Spinler }
11708a66efaSMatt Spinler else
11808a66efaSMatt Spinler {
11908a66efaSMatt Spinler timestamps.clear();
1209c0715b6SMatt Spinler }
1219c0715b6SMatt Spinler }
1229c0715b6SMatt Spinler
findAlarms()1239c0715b6SMatt Spinler void ShutdownAlarmMonitor::findAlarms()
1249c0715b6SMatt Spinler {
1259c0715b6SMatt Spinler // Find all shutdown threshold ifaces currently on D-Bus.
1269c0715b6SMatt Spinler for (const auto& [shutdownType, interface] : shutdownInterfaces)
1279c0715b6SMatt Spinler {
1289c0715b6SMatt Spinler auto paths = SDBusPlus::getSubTreePathsRaw(bus, "/", interface, 0);
1299c0715b6SMatt Spinler
130808d7fe8SMike Capps auto shutdownType2 = shutdownType;
131808d7fe8SMike Capps
132dfddd648SPatrick Williams std::for_each(
133dfddd648SPatrick Williams paths.begin(), paths.end(),
134808d7fe8SMike Capps [this, shutdownType2](const auto& path) {
135808d7fe8SMike Capps alarms.emplace(AlarmKey{path, shutdownType2, AlarmType::high},
1369c0715b6SMatt Spinler nullptr);
137808d7fe8SMike Capps alarms.emplace(AlarmKey{path, shutdownType2, AlarmType::low},
1389c0715b6SMatt Spinler nullptr);
1399c0715b6SMatt Spinler });
1409c0715b6SMatt Spinler }
1419c0715b6SMatt Spinler }
1429c0715b6SMatt Spinler
checkAlarms()1439c0715b6SMatt Spinler void ShutdownAlarmMonitor::checkAlarms()
1449c0715b6SMatt Spinler {
1459c0715b6SMatt Spinler for (auto& [alarmKey, timer] : alarms)
1469c0715b6SMatt Spinler {
1479c0715b6SMatt Spinler const auto& [sensorPath, shutdownType, alarmType] = alarmKey;
1489c0715b6SMatt Spinler const auto& interface = shutdownInterfaces.at(shutdownType);
1499c0715b6SMatt Spinler auto propertyName = alarmProperties.at(shutdownType).at(alarmType);
1509c0715b6SMatt Spinler bool value;
1519c0715b6SMatt Spinler
1529c0715b6SMatt Spinler try
1539c0715b6SMatt Spinler {
1549c0715b6SMatt Spinler value = SDBusPlus::getProperty<bool>(bus, sensorPath, interface,
1559c0715b6SMatt Spinler propertyName);
1569c0715b6SMatt Spinler }
1579c0715b6SMatt Spinler catch (const DBusServiceError& e)
1589c0715b6SMatt Spinler {
1599c0715b6SMatt Spinler // The sensor isn't on D-Bus anymore
160*32c4feffSAnwaar Hadi lg2::info("No {INTERFACE} interface on {SENSOR_PATH} anymore.",
161*32c4feffSAnwaar Hadi "INTERFACE", interface, "SENSOR_PATH", sensorPath);
1629c0715b6SMatt Spinler continue;
1639c0715b6SMatt Spinler }
1649c0715b6SMatt Spinler
1659c0715b6SMatt Spinler checkAlarm(value, alarmKey);
1669c0715b6SMatt Spinler }
1679c0715b6SMatt Spinler }
1689c0715b6SMatt Spinler
propertiesChanged(sdbusplus::message_t & message)169cb356d48SPatrick Williams void ShutdownAlarmMonitor::propertiesChanged(sdbusplus::message_t& message)
1709c0715b6SMatt Spinler {
17116c7dc1eSMatt Spinler std::map<std::string, std::variant<bool>> properties;
17216c7dc1eSMatt Spinler std::string interface;
17316c7dc1eSMatt Spinler
17416c7dc1eSMatt Spinler if (!_powerState->isPowerOn())
17516c7dc1eSMatt Spinler {
17616c7dc1eSMatt Spinler return;
17716c7dc1eSMatt Spinler }
17816c7dc1eSMatt Spinler
17916c7dc1eSMatt Spinler message.read(interface, properties);
18016c7dc1eSMatt Spinler
18116c7dc1eSMatt Spinler auto type = getShutdownType(interface);
18216c7dc1eSMatt Spinler if (!type)
18316c7dc1eSMatt Spinler {
18416c7dc1eSMatt Spinler return;
18516c7dc1eSMatt Spinler }
18616c7dc1eSMatt Spinler
18716c7dc1eSMatt Spinler std::string sensorPath = message.get_path();
18816c7dc1eSMatt Spinler
18916c7dc1eSMatt Spinler const auto& lowAlarmName = alarmProperties.at(*type).at(AlarmType::low);
19016c7dc1eSMatt Spinler if (properties.count(lowAlarmName) > 0)
19116c7dc1eSMatt Spinler {
19216c7dc1eSMatt Spinler AlarmKey alarmKey{sensorPath, *type, AlarmType::low};
19316c7dc1eSMatt Spinler auto alarm = alarms.find(alarmKey);
19416c7dc1eSMatt Spinler if (alarm == alarms.end())
19516c7dc1eSMatt Spinler {
19616c7dc1eSMatt Spinler alarms.emplace(alarmKey, nullptr);
19716c7dc1eSMatt Spinler }
19816c7dc1eSMatt Spinler checkAlarm(std::get<bool>(properties.at(lowAlarmName)), alarmKey);
19916c7dc1eSMatt Spinler }
20016c7dc1eSMatt Spinler
20116c7dc1eSMatt Spinler const auto& highAlarmName = alarmProperties.at(*type).at(AlarmType::high);
20216c7dc1eSMatt Spinler if (properties.count(highAlarmName) > 0)
20316c7dc1eSMatt Spinler {
20416c7dc1eSMatt Spinler AlarmKey alarmKey{sensorPath, *type, AlarmType::high};
20516c7dc1eSMatt Spinler auto alarm = alarms.find(alarmKey);
20616c7dc1eSMatt Spinler if (alarm == alarms.end())
20716c7dc1eSMatt Spinler {
20816c7dc1eSMatt Spinler alarms.emplace(alarmKey, nullptr);
20916c7dc1eSMatt Spinler }
21016c7dc1eSMatt Spinler checkAlarm(std::get<bool>(properties.at(highAlarmName)), alarmKey);
21116c7dc1eSMatt Spinler }
2129c0715b6SMatt Spinler }
2139c0715b6SMatt Spinler
checkAlarm(bool value,const AlarmKey & alarmKey)2149c0715b6SMatt Spinler void ShutdownAlarmMonitor::checkAlarm(bool value, const AlarmKey& alarmKey)
2159c0715b6SMatt Spinler {
2160b839516SMatt Spinler auto alarm = alarms.find(alarmKey);
2170b839516SMatt Spinler if (alarm == alarms.end())
2180b839516SMatt Spinler {
2190b839516SMatt Spinler return;
2200b839516SMatt Spinler }
2210b839516SMatt Spinler
2220b839516SMatt Spinler // Start or stop the timer if necessary.
2230b839516SMatt Spinler auto& timer = alarm->second;
2240b839516SMatt Spinler if (value)
2250b839516SMatt Spinler {
2260b839516SMatt Spinler if (!timer)
2270b839516SMatt Spinler {
2280b839516SMatt Spinler startTimer(alarmKey);
2290b839516SMatt Spinler }
2300b839516SMatt Spinler }
2310b839516SMatt Spinler else
2320b839516SMatt Spinler {
2330b839516SMatt Spinler if (timer)
2340b839516SMatt Spinler {
2350b839516SMatt Spinler stopTimer(alarmKey);
2360b839516SMatt Spinler }
2370b839516SMatt Spinler }
2380b839516SMatt Spinler }
2390b839516SMatt Spinler
startTimer(const AlarmKey & alarmKey)2400b839516SMatt Spinler void ShutdownAlarmMonitor::startTimer(const AlarmKey& alarmKey)
2410b839516SMatt Spinler {
2420b839516SMatt Spinler const auto& [sensorPath, shutdownType, alarmType] = alarmKey;
2430b839516SMatt Spinler const auto& propertyName = alarmProperties.at(shutdownType).at(alarmType);
2440b839516SMatt Spinler std::chrono::milliseconds shutdownDelay{shutdownDelays.at(shutdownType)};
2450b839516SMatt Spinler std::optional<double> value;
2460b839516SMatt Spinler
2470b839516SMatt Spinler auto alarm = alarms.find(alarmKey);
2480b839516SMatt Spinler if (alarm == alarms.end())
2490b839516SMatt Spinler {
2500b839516SMatt Spinler throw std::runtime_error("Couldn't find alarm inside startTimer");
2510b839516SMatt Spinler }
2520b839516SMatt Spinler
2530b839516SMatt Spinler try
2540b839516SMatt Spinler {
2550b839516SMatt Spinler value = SDBusPlus::getProperty<double>(bus, sensorPath, valueInterface,
2560b839516SMatt Spinler valueProperty);
2570b839516SMatt Spinler }
2580b839516SMatt Spinler catch (const DBusServiceError& e)
2590b839516SMatt Spinler {
2600b839516SMatt Spinler // If the sensor was just added, the Value interface for it may
2610b839516SMatt Spinler // not be in the mapper yet. This could only happen if the sensor
2620b839516SMatt Spinler // application was started with power up and the value exceeded the
2630b839516SMatt Spinler // threshold immediately.
2640b839516SMatt Spinler }
2650b839516SMatt Spinler
266ffd54674SMatt Spinler createEventLog(alarmKey, true, value);
267ffd54674SMatt Spinler
26808a66efaSMatt Spinler uint64_t now = std::chrono::duration_cast<std::chrono::milliseconds>(
26908a66efaSMatt Spinler std::chrono::system_clock::now().time_since_epoch())
27008a66efaSMatt Spinler .count();
27108a66efaSMatt Spinler
27208a66efaSMatt Spinler // If there is a saved timestamp for this timer, then we were restarted
27308a66efaSMatt Spinler // while the timer was running. Calculate the remaining time to use
27408a66efaSMatt Spinler // for the timer.
27508a66efaSMatt Spinler auto previousStartTime = timestamps.get().find(alarmKey);
27608a66efaSMatt Spinler if (previousStartTime != timestamps.get().end())
27708a66efaSMatt Spinler {
27808a66efaSMatt Spinler const uint64_t& original = previousStartTime->second;
27908a66efaSMatt Spinler
280*32c4feffSAnwaar Hadi lg2::info("Found previously running {PROPERTY_NAME} timer "
281*32c4feffSAnwaar Hadi "for {SENSOR_PATH} with start time {START_TIME}",
282*32c4feffSAnwaar Hadi "PROPERTY_NAME", propertyName, "SENSOR_PATH", sensorPath,
283*32c4feffSAnwaar Hadi "START_TIME", original);
28408a66efaSMatt Spinler // Sanity check it isn't total garbage.
28508a66efaSMatt Spinler if (now > original)
28608a66efaSMatt Spinler {
28708a66efaSMatt Spinler uint64_t remainingTime = 0;
28808a66efaSMatt Spinler auto elapsedTime = now - original;
28908a66efaSMatt Spinler
29008a66efaSMatt Spinler if (elapsedTime < static_cast<uint64_t>(shutdownDelay.count()))
29108a66efaSMatt Spinler {
29261b73296SPatrick Williams remainingTime = static_cast<uint64_t>(shutdownDelay.count()) -
29361b73296SPatrick Williams elapsedTime;
29408a66efaSMatt Spinler }
29508a66efaSMatt Spinler
29608a66efaSMatt Spinler shutdownDelay = std::chrono::milliseconds{remainingTime};
29708a66efaSMatt Spinler }
29808a66efaSMatt Spinler else
29908a66efaSMatt Spinler {
300*32c4feffSAnwaar Hadi lg2::warning(
301*32c4feffSAnwaar Hadi "Restarting {PROPERTY_NAME} shutdown timer for {SENSOR_PATH} for full "
302*32c4feffSAnwaar Hadi "time because saved time {SAVED_TIME} is after current time {CURRENT_TIME}",
303*32c4feffSAnwaar Hadi "PROPERTY_NAME", propertyName, "SENSOR_PATH", sensorPath,
304*32c4feffSAnwaar Hadi "SAVED_TIME", original, "CURRENT_TIME", now);
30508a66efaSMatt Spinler }
30608a66efaSMatt Spinler }
30708a66efaSMatt Spinler
308*32c4feffSAnwaar Hadi lg2::info(
309*32c4feffSAnwaar Hadi "Starting {TIME}ms {PROPERTY_NAME} shutdown timer due to sensor {SENSOR_PATH} value {VALUE}",
310*32c4feffSAnwaar Hadi "TIME", shutdownDelay.count(), "PROPERTY_NAME", propertyName,
311*32c4feffSAnwaar Hadi "SENSOR_PATH", sensorPath, "VALUE", *value);
3120b839516SMatt Spinler
3130b839516SMatt Spinler auto& timer = alarm->second;
3140b839516SMatt Spinler
3150b839516SMatt Spinler timer = std::make_unique<
3160b839516SMatt Spinler sdeventplus::utility::Timer<sdeventplus::ClockId::Monotonic>>(
3170b839516SMatt Spinler event, std::bind(&ShutdownAlarmMonitor::timerExpired, this, alarmKey));
3180b839516SMatt Spinler
3190b839516SMatt Spinler timer->restartOnce(shutdownDelay);
32008a66efaSMatt Spinler
32108a66efaSMatt Spinler // Note that if this key is already in the timestamps map because
32208a66efaSMatt Spinler // the timer was already running the timestamp wil not be updated.
32308a66efaSMatt Spinler timestamps.add(alarmKey, now);
3240b839516SMatt Spinler }
3250b839516SMatt Spinler
stopTimer(const AlarmKey & alarmKey)3260b839516SMatt Spinler void ShutdownAlarmMonitor::stopTimer(const AlarmKey& alarmKey)
3270b839516SMatt Spinler {
3280b839516SMatt Spinler const auto& [sensorPath, shutdownType, alarmType] = alarmKey;
3290b839516SMatt Spinler const auto& propertyName = alarmProperties.at(shutdownType).at(alarmType);
3300b839516SMatt Spinler
3310b839516SMatt Spinler auto value = SDBusPlus::getProperty<double>(bus, sensorPath, valueInterface,
3320b839516SMatt Spinler valueProperty);
3330b839516SMatt Spinler
3340b839516SMatt Spinler auto alarm = alarms.find(alarmKey);
3350b839516SMatt Spinler if (alarm == alarms.end())
3360b839516SMatt Spinler {
3370b839516SMatt Spinler throw std::runtime_error("Couldn't find alarm inside stopTimer");
3380b839516SMatt Spinler }
3390b839516SMatt Spinler
340ffd54674SMatt Spinler createEventLog(alarmKey, false, value);
341ffd54674SMatt Spinler
342*32c4feffSAnwaar Hadi lg2::info(
343*32c4feffSAnwaar Hadi "Stopping {PROPERTY_NAME} shutdown timer due to sensor {SENSOR_PATH} value {VALUE}",
344*32c4feffSAnwaar Hadi "PROPERTY_NAME", propertyName, "SENSOR_PATH", sensorPath, "VALUE",
345*32c4feffSAnwaar Hadi value);
3460b839516SMatt Spinler auto& timer = alarm->second;
3470b839516SMatt Spinler timer->setEnabled(false);
3480b839516SMatt Spinler timer.reset();
34908a66efaSMatt Spinler
35008a66efaSMatt Spinler timestamps.erase(alarmKey);
3510b839516SMatt Spinler }
3520b839516SMatt Spinler
createBmcDump() const353683a96c6SMike Capps void ShutdownAlarmMonitor::createBmcDump() const
354683a96c6SMike Capps {
355683a96c6SMike Capps try
356683a96c6SMike Capps {
357683a96c6SMike Capps util::SDBusPlus::callMethod(
358683a96c6SMike Capps "xyz.openbmc_project.Dump.Manager", "/xyz/openbmc_project/dump/bmc",
359683a96c6SMike Capps "xyz.openbmc_project.Dump.Create", "CreateDump",
360683a96c6SMike Capps std::vector<
361683a96c6SMike Capps std::pair<std::string, std::variant<std::string, uint64_t>>>());
362683a96c6SMike Capps }
363477b13bdSMike Capps catch (const std::exception& e)
364477b13bdSMike Capps {
365*32c4feffSAnwaar Hadi lg2::error("Caught exception while creating BMC dump: {ERROR}", "ERROR",
366*32c4feffSAnwaar Hadi e);
367477b13bdSMike Capps }
368683a96c6SMike Capps }
369683a96c6SMike Capps
timerExpired(const AlarmKey & alarmKey)3700b839516SMatt Spinler void ShutdownAlarmMonitor::timerExpired(const AlarmKey& alarmKey)
3710b839516SMatt Spinler {
3720b839516SMatt Spinler const auto& [sensorPath, shutdownType, alarmType] = alarmKey;
3730b839516SMatt Spinler const auto& propertyName = alarmProperties.at(shutdownType).at(alarmType);
3740b839516SMatt Spinler
375ffd54674SMatt Spinler auto value = SDBusPlus::getProperty<double>(bus, sensorPath, valueInterface,
376ffd54674SMatt Spinler valueProperty);
377ffd54674SMatt Spinler
378*32c4feffSAnwaar Hadi lg2::error(
379*32c4feffSAnwaar Hadi "The {PROPERTY_NAME} shutdown timer expired for sensor {SENSOR_PATH}, shutting down",
380*32c4feffSAnwaar Hadi "PROPERTY_NAME", propertyName, "SENSOR_PATH", sensorPath);
3810b839516SMatt Spinler
382ffd54674SMatt Spinler // Re-send the event log. If someone didn't want this it could be
383ffd54674SMatt Spinler // wrapped by a compile option.
3842a6b39c8SMatt Spinler createEventLog(alarmKey, true, value, true);
385ffd54674SMatt Spinler
3860b839516SMatt Spinler SDBusPlus::callMethod(systemdService, systemdPath, systemdMgrIface,
3870b839516SMatt Spinler "StartUnit", "obmc-chassis-hard-poweroff@0.target",
3880b839516SMatt Spinler "replace");
38908a66efaSMatt Spinler
39008a66efaSMatt Spinler timestamps.erase(alarmKey);
391683a96c6SMike Capps createBmcDump();
3929c0715b6SMatt Spinler }
3939c0715b6SMatt Spinler
powerStateChanged(bool powerStateOn)3949c0715b6SMatt Spinler void ShutdownAlarmMonitor::powerStateChanged(bool powerStateOn)
3959c0715b6SMatt Spinler {
3969c0715b6SMatt Spinler if (powerStateOn)
3979c0715b6SMatt Spinler {
3989c0715b6SMatt Spinler checkAlarms();
3999c0715b6SMatt Spinler }
4009c0715b6SMatt Spinler else
4019c0715b6SMatt Spinler {
40208a66efaSMatt Spinler timestamps.clear();
40308a66efaSMatt Spinler
4049c0715b6SMatt Spinler // Cancel and delete all timers
4050b839516SMatt Spinler std::for_each(alarms.begin(), alarms.end(), [](auto& alarm) {
4060b839516SMatt Spinler auto& timer = alarm.second;
4070b839516SMatt Spinler if (timer)
4080b839516SMatt Spinler {
4090b839516SMatt Spinler timer->setEnabled(false);
4100b839516SMatt Spinler timer.reset();
4110b839516SMatt Spinler }
4120b839516SMatt Spinler });
4139c0715b6SMatt Spinler }
4149c0715b6SMatt Spinler }
4159c0715b6SMatt Spinler
createEventLog(const AlarmKey & alarmKey,bool alarmValue,const std::optional<double> & sensorValue,bool isPowerOffError)416ffd54674SMatt Spinler void ShutdownAlarmMonitor::createEventLog(
417ffd54674SMatt Spinler const AlarmKey& alarmKey, bool alarmValue,
4182a6b39c8SMatt Spinler const std::optional<double>& sensorValue, bool isPowerOffError)
419ffd54674SMatt Spinler {
420ffd54674SMatt Spinler using namespace sdbusplus::xyz::openbmc_project::Logging::server;
421ffd54674SMatt Spinler const auto& [sensorPath, shutdownType, alarmType] = alarmKey;
4223efec61cSMatt Spinler std::map<std::string, std::string> ad{{"SENSOR_NAME", sensorPath},
4233efec61cSMatt Spinler {"_PID", std::to_string(getpid())}};
424ffd54674SMatt Spinler
425ffd54674SMatt Spinler std::string errorName =
426ffd54674SMatt Spinler (alarmValue) ? alarmEventLogs.at(shutdownType).at(alarmType)
427ffd54674SMatt Spinler : alarmClearEventLogs.at(shutdownType).at(alarmType);
428ffd54674SMatt Spinler
4292a6b39c8SMatt Spinler // severity = Critical if a power off
4302a6b39c8SMatt Spinler // severity = Error if alarm was asserted
4312a6b39c8SMatt Spinler // severity = Informational if alarm was deasserted
4322a6b39c8SMatt Spinler Entry::Level severity = Entry::Level::Error;
4332a6b39c8SMatt Spinler if (isPowerOffError)
4342a6b39c8SMatt Spinler {
4352a6b39c8SMatt Spinler severity = Entry::Level::Critical;
4362a6b39c8SMatt Spinler }
4372a6b39c8SMatt Spinler else if (!alarmValue)
4382a6b39c8SMatt Spinler {
4392a6b39c8SMatt Spinler severity = Entry::Level::Informational;
4402a6b39c8SMatt Spinler }
441ffd54674SMatt Spinler
442ffd54674SMatt Spinler if (sensorValue)
443ffd54674SMatt Spinler {
444ffd54674SMatt Spinler ad.emplace("SENSOR_VALUE", std::to_string(*sensorValue));
445ffd54674SMatt Spinler }
446ffd54674SMatt Spinler
4472a6b39c8SMatt Spinler // If this is a power off, specify that it's a power
4482a6b39c8SMatt Spinler // fault and a system termination. This is used by some
4492a6b39c8SMatt Spinler // implementations for service reasons.
4502a6b39c8SMatt Spinler if (isPowerOffError)
4512a6b39c8SMatt Spinler {
4522a6b39c8SMatt Spinler ad.emplace("SEVERITY_DETAIL", "SYSTEM_TERM");
4532a6b39c8SMatt Spinler }
4542a6b39c8SMatt Spinler
455ffd54674SMatt Spinler SDBusPlus::callMethod(loggingService, loggingPath, loggingCreateIface,
456ffd54674SMatt Spinler "Create", errorName, convertForMessage(severity), ad);
457ffd54674SMatt Spinler }
458ffd54674SMatt Spinler
getShutdownType(const std::string & interface) const4594fa67aa1SPatrick Williams std::optional<ShutdownType> ShutdownAlarmMonitor::getShutdownType(
4604fa67aa1SPatrick Williams const std::string& interface) const
46116c7dc1eSMatt Spinler {
4625e15c3baSPatrick Williams auto it = std::find_if(
4635e15c3baSPatrick Williams shutdownInterfaces.begin(), shutdownInterfaces.end(),
4645e15c3baSPatrick Williams [interface](const auto& a) { return a.second == interface; });
46516c7dc1eSMatt Spinler
46616c7dc1eSMatt Spinler if (it == shutdownInterfaces.end())
46716c7dc1eSMatt Spinler {
46816c7dc1eSMatt Spinler return std::nullopt;
46916c7dc1eSMatt Spinler }
47016c7dc1eSMatt Spinler
47116c7dc1eSMatt Spinler return it->first;
47216c7dc1eSMatt Spinler }
47316c7dc1eSMatt Spinler
4749c0715b6SMatt Spinler } // namespace sensor::monitor
475