1e426b589SAndrew Geissler #include "config.h"
2e426b589SAndrew Geissler
3e426b589SAndrew Geissler #include "chassis_state_manager.hpp"
4e426b589SAndrew Geissler
5f8ae6a02SAndrew Geissler #include "utils.hpp"
6e426b589SAndrew Geissler #include "xyz/openbmc_project/Common/error.hpp"
7e426b589SAndrew Geissler #include "xyz/openbmc_project/State/Shutdown/Power/error.hpp"
8e426b589SAndrew Geissler
9e426b589SAndrew Geissler #include <cereal/archives/json.hpp>
109a286db2SPatrick Williams #include <org/freedesktop/UPower/Device/client.hpp>
11e426b589SAndrew Geissler #include <phosphor-logging/elog-errors.hpp>
128ffdb269SAndrew Geissler #include <phosphor-logging/lg2.hpp>
130029a5d2SAndrew Geissler #include <sdbusplus/bus.hpp>
1409568ff7SWilliam A. Kennington III #include <sdbusplus/exception.hpp>
15d998f82bSWilliam A. Kennington III #include <sdeventplus/event.hpp>
16d998f82bSWilliam A. Kennington III #include <sdeventplus/exception.hpp>
179a286db2SPatrick Williams #include <xyz/openbmc_project/ObjectMapper/client.hpp>
18765446aeSAndrew Geissler #include <xyz/openbmc_project/State/Chassis/error.hpp>
19396ed8a5SAdriana Kobylak #include <xyz/openbmc_project/State/Decorator/PowerSystemInputs/server.hpp>
20e426b589SAndrew Geissler
21f2b22e8eSAndrew Geissler #include <filesystem>
2278c066f6SPatrick Williams #include <format>
23e426b589SAndrew Geissler #include <fstream>
24cb781fe1SNagaraju Goruganti
25a90a31a9SAndrew Geissler namespace phosphor
26a90a31a9SAndrew Geissler {
27a90a31a9SAndrew Geissler namespace state
28a90a31a9SAndrew Geissler {
29a90a31a9SAndrew Geissler namespace manager
30a90a31a9SAndrew Geissler {
31a90a31a9SAndrew Geissler
328ffdb269SAndrew Geissler PHOSPHOR_LOG2_USING;
338ffdb269SAndrew Geissler
34a90a31a9SAndrew Geissler // When you see server:: you know we're referencing our base class
357e969cb9SPatrick Williams namespace server = sdbusplus::server::xyz::openbmc_project::state;
36396ed8a5SAdriana Kobylak namespace decoratorServer =
377e969cb9SPatrick Williams sdbusplus::server::xyz::openbmc_project::state::decorator;
38a90a31a9SAndrew Geissler
399a286db2SPatrick Williams using ObjectMapper = sdbusplus::client::xyz::openbmc_project::ObjectMapper<>;
409a286db2SPatrick Williams using UPowerDevice = sdbusplus::client::org::freedesktop::u_power::Device<>;
419a286db2SPatrick Williams
42a90a31a9SAndrew Geissler using namespace phosphor::logging;
43d998f82bSWilliam A. Kennington III using sdbusplus::xyz::openbmc_project::Common::Error::InternalFailure;
4427115aecSAatir Manzur using sdbusplus::xyz::openbmc_project::State::Shutdown::Power::Error::Blackout;
452c36e5adSBen Tyner using sdbusplus::xyz::openbmc_project::State::Shutdown::Power::Error::Regulator;
4670f36d8eSPotin Lai constexpr auto CHASSIS_STATE_POWEROFF_TGT_FMT =
4770f36d8eSPotin Lai "obmc-chassis-poweroff@{}.target";
4870f36d8eSPotin Lai constexpr auto CHASSIS_STATE_HARD_POWEROFF_TGT_FMT =
4970f36d8eSPotin Lai "obmc-chassis-hard-poweroff@{}.target";
5070f36d8eSPotin Lai constexpr auto CHASSIS_STATE_POWERON_TGT_FMT = "obmc-chassis-poweron@{}.target";
517e0e4e92SCorey_Hardesty constexpr auto CHASSIS_BLACKOUT_TGT_FMT = "obmc-chassis-blackout@{}.target";
520688132aSDelphineCCChiu constexpr auto CHASSIS_STATE_POWERCYCLE_TGT_FMT =
530688132aSDelphineCCChiu "obmc-chassis-powercycle@{}.target";
5477a91831SAndrew Geissler constexpr auto AUTO_POWER_RESTORE_SVC_FMT =
5577a91831SAndrew Geissler "phosphor-discover-system-state@{}.service";
56697474c5SJosh D. King constexpr auto ACTIVE_STATE = "active";
57697474c5SJosh D. King constexpr auto ACTIVATING_STATE = "activating";
58697474c5SJosh D. King
592cf2a268SAndrew Geissler // Details at https://upower.freedesktop.org/docs/Device.html
602cf2a268SAndrew Geissler constexpr uint TYPE_UPS = 3;
612cf2a268SAndrew Geissler constexpr uint STATE_FULLY_CHARGED = 4;
622cf2a268SAndrew Geissler constexpr uint BATTERY_LVL_FULL = 8;
632cf2a268SAndrew Geissler
64ce80f24cSAndrew Geissler constexpr auto SYSTEMD_SERVICE = "org.freedesktop.systemd1";
65ce80f24cSAndrew Geissler constexpr auto SYSTEMD_OBJ_PATH = "/org/freedesktop/systemd1";
66ce80f24cSAndrew Geissler constexpr auto SYSTEMD_INTERFACE = "org.freedesktop.systemd1.Manager";
67ce80f24cSAndrew Geissler
68697474c5SJosh D. King constexpr auto SYSTEMD_PROPERTY_IFACE = "org.freedesktop.DBus.Properties";
69697474c5SJosh D. King constexpr auto SYSTEMD_INTERFACE_UNIT = "org.freedesktop.systemd1.Unit";
70697474c5SJosh D. King
718b1f8620SAndrew Geissler constexpr auto PROPERTY_INTERFACE = "org.freedesktop.DBus.Properties";
728b1f8620SAndrew Geissler
createSystemdTargetTable()7370f36d8eSPotin Lai void Chassis::createSystemdTargetTable()
7470f36d8eSPotin Lai {
7570f36d8eSPotin Lai systemdTargetTable = {
7670f36d8eSPotin Lai // Use the hard off target to ensure we shutdown immediately
7778c066f6SPatrick Williams {Transition::Off, std::format(CHASSIS_STATE_HARD_POWEROFF_TGT_FMT, id)},
7878c066f6SPatrick Williams {Transition::On, std::format(CHASSIS_STATE_POWERON_TGT_FMT, id)},
790688132aSDelphineCCChiu {Transition::PowerCycle,
8078c066f6SPatrick Williams std::format(CHASSIS_STATE_POWERCYCLE_TGT_FMT, id)}};
8170f36d8eSPotin Lai }
8270f36d8eSPotin Lai
83dff50ed6SAndrew Geissler // TODO - Will be rewritten once sdbusplus client bindings are in place
84dff50ed6SAndrew Geissler // and persistent storage design is in place and sdbusplus
85dff50ed6SAndrew Geissler // has read property function
determineInitialState()86dff50ed6SAndrew Geissler void Chassis::determineInitialState()
87dff50ed6SAndrew Geissler {
882cf2a268SAndrew Geissler // Monitor for any properties changed signals on UPower device path
892cf2a268SAndrew Geissler uPowerPropChangeSignal = std::make_unique<sdbusplus::bus::match_t>(
902cf2a268SAndrew Geissler bus,
912cf2a268SAndrew Geissler sdbusplus::bus::match::rules::propertiesChangedNamespace(
929a286db2SPatrick Williams "/org/freedesktop/UPower", UPowerDevice::interface),
932cf2a268SAndrew Geissler [this](auto& msg) { this->uPowerChangeEvent(msg); });
942cf2a268SAndrew Geissler
95396ed8a5SAdriana Kobylak // Monitor for any properties changed signals on PowerSystemInputs
96396ed8a5SAdriana Kobylak powerSysInputsPropChangeSignal = std::make_unique<sdbusplus::bus::match_t>(
97396ed8a5SAdriana Kobylak bus,
98396ed8a5SAdriana Kobylak sdbusplus::bus::match::rules::propertiesChangedNamespace(
9978c066f6SPatrick Williams std::format(
100396ed8a5SAdriana Kobylak "/xyz/openbmc_project/power/power_supplies/chassis{}/psus", id),
1019a286db2SPatrick Williams decoratorServer::PowerSystemInputs::interface),
102396ed8a5SAdriana Kobylak [this](auto& msg) { this->powerSysInputsChangeEvent(msg); });
103396ed8a5SAdriana Kobylak
1048b1f8620SAndrew Geissler determineStatusOfPower();
1058b1f8620SAndrew Geissler
1062975e26fSPatrick Williams std::variant<int> pgood = -1;
10758a18013SAndrew Geissler auto method = this->bus.new_method_call(
10858a18013SAndrew Geissler "org.openbmc.control.Power", "/org/openbmc/control/power0",
10958a18013SAndrew Geissler "org.freedesktop.DBus.Properties", "Get");
110dff50ed6SAndrew Geissler
111dff50ed6SAndrew Geissler method.append("org.openbmc.control.Power", "pgood");
1129a2f37cfSWilliam A. Kennington III try
1139a2f37cfSWilliam A. Kennington III {
114dff50ed6SAndrew Geissler auto reply = this->bus.call(method);
115dff50ed6SAndrew Geissler reply.read(pgood);
116dff50ed6SAndrew Geissler
11737413dcbSPatrick Williams if (std::get<int>(pgood) == 1)
118dff50ed6SAndrew Geissler {
1198ffdb269SAndrew Geissler info("Initial Chassis State will be On");
120dff50ed6SAndrew Geissler server::Chassis::currentPowerState(PowerState::On);
121dff50ed6SAndrew Geissler server::Chassis::requestedPowerTransition(Transition::On);
12209568ff7SWilliam A. Kennington III return;
123dff50ed6SAndrew Geissler }
1249eab9861SMatt Spinler else
1259eab9861SMatt Spinler {
1269eab9861SMatt Spinler // The system is off. If we think it should be on then
1279eab9861SMatt Spinler // we probably lost AC while up, so set a new state
1289eab9861SMatt Spinler // change time.
1299eab9861SMatt Spinler uint64_t lastTime;
1309eab9861SMatt Spinler PowerState lastState;
1319eab9861SMatt Spinler
1329eab9861SMatt Spinler if (deserializeStateChangeTime(lastTime, lastState))
1339eab9861SMatt Spinler {
1347ed36236SAndrew Geissler // If power was on before the BMC reboot and the reboot reason
1357ed36236SAndrew Geissler // was not a pinhole reset, log an error
1369eab9861SMatt Spinler if (lastState == PowerState::On)
1379eab9861SMatt Spinler {
1387ed36236SAndrew Geissler info(
1397ed36236SAndrew Geissler "Chassis power was on before the BMC reboot and it is off now");
140be6efabcSMatthew Barth
141be6efabcSMatthew Barth // Reset host sensors since system is off now
1427e0e4e92SCorey_Hardesty // Ensure Power Leds are off.
14378c066f6SPatrick Williams startUnit(std::format(CHASSIS_BLACKOUT_TGT_FMT, id));
144be6efabcSMatthew Barth
1457ed36236SAndrew Geissler setStateChangeTime();
146bcbee4a2SNodeMan97 // Generate file indicating AC loss occurred
147bcbee4a2SNodeMan97 std::string chassisLostPowerFileFmt =
14878c066f6SPatrick Williams std::format(CHASSIS_LOST_POWER_FILE, id);
149bcbee4a2SNodeMan97 fs::create_directories(BASE_FILE_DIR);
150bcbee4a2SNodeMan97 fs::path chassisPowerLossFile{chassisLostPowerFileFmt};
151bcbee4a2SNodeMan97 std::ofstream outfile(chassisPowerLossFile);
152bcbee4a2SNodeMan97 outfile.close();
1537ed36236SAndrew Geissler
1544fe860f5SBrandon Wyman // 0 indicates pinhole reset. 1 is NOT pinhole reset
1557ed36236SAndrew Geissler if (phosphor::state::manager::utils::getGpioValue(
1564fe860f5SBrandon Wyman "reset-cause-pinhole") != 0)
1577ed36236SAndrew Geissler {
1582c36e5adSBen Tyner if (standbyVoltageRegulatorFault())
1592c36e5adSBen Tyner {
1602c36e5adSBen Tyner report<Regulator>();
1612c36e5adSBen Tyner }
1622c36e5adSBen Tyner else
1632c36e5adSBen Tyner {
164073fa2b3SMike Capps report<Blackout>(Entry::Level::Critical);
1652c36e5adSBen Tyner }
1667ed36236SAndrew Geissler }
1674fe860f5SBrandon Wyman else
1684fe860f5SBrandon Wyman {
1694fe860f5SBrandon Wyman info("Pinhole reset");
1704fe860f5SBrandon Wyman }
1719eab9861SMatt Spinler }
1729eab9861SMatt Spinler }
1739eab9861SMatt Spinler }
1749a2f37cfSWilliam A. Kennington III }
175f053e6feSPatrick Williams catch (const sdbusplus::exception_t& e)
1769a2f37cfSWilliam A. Kennington III {
1779a2f37cfSWilliam A. Kennington III // It's acceptable for the pgood state service to not be available
1789a2f37cfSWilliam A. Kennington III // since it will notify us of the pgood state when it comes up.
1799a2f37cfSWilliam A. Kennington III if (e.name() != nullptr &&
1809a2f37cfSWilliam A. Kennington III strcmp("org.freedesktop.DBus.Error.ServiceUnknown", e.name()) == 0)
1819a2f37cfSWilliam A. Kennington III {
1829a2f37cfSWilliam A. Kennington III goto fail;
1839a2f37cfSWilliam A. Kennington III }
1849a2f37cfSWilliam A. Kennington III
1859a2f37cfSWilliam A. Kennington III // Only log for unexpected error types.
1868ffdb269SAndrew Geissler error("Error performing call to get pgood: {ERROR}", "ERROR", e);
1879a2f37cfSWilliam A. Kennington III goto fail;
1889a2f37cfSWilliam A. Kennington III }
18909568ff7SWilliam A. Kennington III
19009568ff7SWilliam A. Kennington III fail:
1918ffdb269SAndrew Geissler info("Initial Chassis State will be Off");
192dff50ed6SAndrew Geissler server::Chassis::currentPowerState(PowerState::Off);
193dff50ed6SAndrew Geissler server::Chassis::requestedPowerTransition(Transition::Off);
194dff50ed6SAndrew Geissler
195dff50ed6SAndrew Geissler return;
196dff50ed6SAndrew Geissler }
197dff50ed6SAndrew Geissler
determineStatusOfPower()1988b1f8620SAndrew Geissler void Chassis::determineStatusOfPower()
1998b1f8620SAndrew Geissler {
20077a91831SAndrew Geissler auto initialPowerStatus = server::Chassis::currentPowerStatus();
20177a91831SAndrew Geissler
20266aacdc4SAndrew Geissler bool powerGood = determineStatusOfUPSPower();
20366aacdc4SAndrew Geissler if (!powerGood)
204396ed8a5SAdriana Kobylak {
205396ed8a5SAdriana Kobylak return;
206396ed8a5SAdriana Kobylak }
207396ed8a5SAdriana Kobylak
20866aacdc4SAndrew Geissler powerGood = determineStatusOfPSUPower();
20966aacdc4SAndrew Geissler if (powerGood)
21066aacdc4SAndrew Geissler {
21166aacdc4SAndrew Geissler // All checks passed, set power status to good
21266aacdc4SAndrew Geissler server::Chassis::currentPowerStatus(PowerStatus::Good);
21377a91831SAndrew Geissler
21477a91831SAndrew Geissler // If power status transitioned from bad to good and chassis power is
21577a91831SAndrew Geissler // off then call Auto Power Restart to see if the system should auto
21677a91831SAndrew Geissler // power on now that power status is good
21777a91831SAndrew Geissler if ((initialPowerStatus != PowerStatus::Good) &&
21877a91831SAndrew Geissler (server::Chassis::currentPowerState() == PowerState::Off))
21977a91831SAndrew Geissler {
22077a91831SAndrew Geissler info("power status transitioned from {START_PWR_STATE} to Good and "
22177a91831SAndrew Geissler "chassis power is off, calling APR",
22277a91831SAndrew Geissler "START_PWR_STATE", initialPowerStatus);
22378c066f6SPatrick Williams restartUnit(std::format(AUTO_POWER_RESTORE_SVC_FMT, this->id));
22477a91831SAndrew Geissler }
22566aacdc4SAndrew Geissler }
226396ed8a5SAdriana Kobylak }
227396ed8a5SAdriana Kobylak
determineStatusOfUPSPower()22866aacdc4SAndrew Geissler bool Chassis::determineStatusOfUPSPower()
229396ed8a5SAdriana Kobylak {
2308b1f8620SAndrew Geissler // Find all implementations of the UPower interface
2319a286db2SPatrick Williams auto mapper = bus.new_method_call(ObjectMapper::default_service,
2329a286db2SPatrick Williams ObjectMapper::instance_path,
2339a286db2SPatrick Williams ObjectMapper::interface, "GetSubTree");
2348b1f8620SAndrew Geissler
2359a286db2SPatrick Williams mapper.append("/", 0, std::vector<std::string>({UPowerDevice::interface}));
2368b1f8620SAndrew Geissler
2378b1f8620SAndrew Geissler std::map<std::string, std::map<std::string, std::vector<std::string>>>
2388b1f8620SAndrew Geissler mapperResponse;
2398b1f8620SAndrew Geissler
2408b1f8620SAndrew Geissler try
2418b1f8620SAndrew Geissler {
2428b1f8620SAndrew Geissler auto mapperResponseMsg = bus.call(mapper);
2438b1f8620SAndrew Geissler mapperResponseMsg.read(mapperResponse);
2448b1f8620SAndrew Geissler }
245f053e6feSPatrick Williams catch (const sdbusplus::exception_t& e)
2468b1f8620SAndrew Geissler {
2478b1f8620SAndrew Geissler error("Error in mapper GetSubTree call for UPS: {ERROR}", "ERROR", e);
2488b1f8620SAndrew Geissler throw;
2498b1f8620SAndrew Geissler }
2508b1f8620SAndrew Geissler
2518b1f8620SAndrew Geissler if (mapperResponse.empty())
2528b1f8620SAndrew Geissler {
2538b1f8620SAndrew Geissler debug("No UPower devices found in system");
2548b1f8620SAndrew Geissler }
2558b1f8620SAndrew Geissler
2568b1f8620SAndrew Geissler // Iterate through all returned Upower interfaces and look for UPS's
2578b1f8620SAndrew Geissler for (const auto& [path, services] : mapperResponse)
2588b1f8620SAndrew Geissler {
2598b1f8620SAndrew Geissler for (const auto& serviceIter : services)
2608b1f8620SAndrew Geissler {
2618b1f8620SAndrew Geissler const std::string& service = serviceIter.first;
2628b1f8620SAndrew Geissler
2638b1f8620SAndrew Geissler try
2648b1f8620SAndrew Geissler {
2658b1f8620SAndrew Geissler auto method = bus.new_method_call(service.c_str(), path.c_str(),
2668b1f8620SAndrew Geissler PROPERTY_INTERFACE, "GetAll");
2679a286db2SPatrick Williams method.append(UPowerDevice::interface);
2688b1f8620SAndrew Geissler
2698b1f8620SAndrew Geissler auto response = bus.call(method);
2708b1f8620SAndrew Geissler using Property = std::string;
2718b1f8620SAndrew Geissler using Value = std::variant<bool, uint>;
2728b1f8620SAndrew Geissler using PropertyMap = std::map<Property, Value>;
2738b1f8620SAndrew Geissler PropertyMap properties;
2748b1f8620SAndrew Geissler response.read(properties);
2758b1f8620SAndrew Geissler
2768b1f8620SAndrew Geissler if (std::get<uint>(properties["Type"]) != TYPE_UPS)
2778b1f8620SAndrew Geissler {
2788b1f8620SAndrew Geissler info("UPower device {OBJ_PATH} is not a UPS device",
2798b1f8620SAndrew Geissler "OBJ_PATH", path);
2808b1f8620SAndrew Geissler continue;
2818b1f8620SAndrew Geissler }
2828b1f8620SAndrew Geissler
28344bbf11dSPavithra Barithaya if (!std::get<bool>(properties["IsPresent"]))
2842cf2a268SAndrew Geissler {
2852cf2a268SAndrew Geissler // There is a UPS detected but it is not officially
2862cf2a268SAndrew Geissler // "present" yet. Monitor it for state change.
2872cf2a268SAndrew Geissler info("UPower device {OBJ_PATH} is not present", "OBJ_PATH",
2882cf2a268SAndrew Geissler path);
2892cf2a268SAndrew Geissler continue;
2902cf2a268SAndrew Geissler }
2912cf2a268SAndrew Geissler
2928b1f8620SAndrew Geissler if (std::get<uint>(properties["State"]) == STATE_FULLY_CHARGED)
2938b1f8620SAndrew Geissler {
2948b1f8620SAndrew Geissler info("UPS is fully charged");
2958b1f8620SAndrew Geissler }
2968b1f8620SAndrew Geissler else
2978b1f8620SAndrew Geissler {
2988b1f8620SAndrew Geissler info("UPS is not fully charged: {UPS_STATE}", "UPS_STATE",
2998b1f8620SAndrew Geissler std::get<uint>(properties["State"]));
3008b1f8620SAndrew Geissler server::Chassis::currentPowerStatus(
3018b1f8620SAndrew Geissler PowerStatus::UninterruptiblePowerSupply);
30266aacdc4SAndrew Geissler return false;
3038b1f8620SAndrew Geissler }
3048b1f8620SAndrew Geissler
3058b1f8620SAndrew Geissler if (std::get<uint>(properties["BatteryLevel"]) ==
3068b1f8620SAndrew Geissler BATTERY_LVL_FULL)
3078b1f8620SAndrew Geissler {
3088b1f8620SAndrew Geissler info("UPS Battery Level is Full");
3092cf2a268SAndrew Geissler // Only one UPS per system, we've found it and it's all
3102cf2a268SAndrew Geissler // good so exit function
31166aacdc4SAndrew Geissler return true;
3128b1f8620SAndrew Geissler }
3138b1f8620SAndrew Geissler else
3148b1f8620SAndrew Geissler {
3158b1f8620SAndrew Geissler info("UPS Battery Level is Low: {UPS_BAT_LEVEL}",
3168b1f8620SAndrew Geissler "UPS_BAT_LEVEL",
3178b1f8620SAndrew Geissler std::get<uint>(properties["BatteryLevel"]));
3188b1f8620SAndrew Geissler server::Chassis::currentPowerStatus(
3198b1f8620SAndrew Geissler PowerStatus::UninterruptiblePowerSupply);
32066aacdc4SAndrew Geissler return false;
3218b1f8620SAndrew Geissler }
3228b1f8620SAndrew Geissler }
323f053e6feSPatrick Williams catch (const sdbusplus::exception_t& e)
3248b1f8620SAndrew Geissler {
3258b1f8620SAndrew Geissler error("Error reading UPS property, error: {ERROR}, "
3268b1f8620SAndrew Geissler "service: {SERVICE} path: {PATH}",
3278b1f8620SAndrew Geissler "ERROR", e, "SERVICE", service, "PATH", path);
3288b1f8620SAndrew Geissler throw;
3298b1f8620SAndrew Geissler }
3308b1f8620SAndrew Geissler }
3318b1f8620SAndrew Geissler }
33266aacdc4SAndrew Geissler return true;
3338b1f8620SAndrew Geissler }
3348b1f8620SAndrew Geissler
determineStatusOfPSUPower()33566aacdc4SAndrew Geissler bool Chassis::determineStatusOfPSUPower()
336396ed8a5SAdriana Kobylak {
337396ed8a5SAdriana Kobylak // Find all implementations of the PowerSystemInputs interface
3389a286db2SPatrick Williams auto mapper = bus.new_method_call(ObjectMapper::default_service,
3399a286db2SPatrick Williams ObjectMapper::instance_path,
3409a286db2SPatrick Williams ObjectMapper::interface, "GetSubTree");
341396ed8a5SAdriana Kobylak
3429a286db2SPatrick Williams mapper.append("/", 0,
3439a286db2SPatrick Williams std::vector<std::string>(
3449a286db2SPatrick Williams {decoratorServer::PowerSystemInputs::interface}));
345396ed8a5SAdriana Kobylak
346396ed8a5SAdriana Kobylak std::map<std::string, std::map<std::string, std::vector<std::string>>>
347396ed8a5SAdriana Kobylak mapperResponse;
348396ed8a5SAdriana Kobylak
349396ed8a5SAdriana Kobylak try
350396ed8a5SAdriana Kobylak {
351396ed8a5SAdriana Kobylak auto mapperResponseMsg = bus.call(mapper);
352396ed8a5SAdriana Kobylak mapperResponseMsg.read(mapperResponse);
353396ed8a5SAdriana Kobylak }
354f053e6feSPatrick Williams catch (const sdbusplus::exception_t& e)
355396ed8a5SAdriana Kobylak {
356396ed8a5SAdriana Kobylak error("Error in mapper GetSubTree call for PowerSystemInputs: {ERROR}",
357396ed8a5SAdriana Kobylak "ERROR", e);
358396ed8a5SAdriana Kobylak throw;
359396ed8a5SAdriana Kobylak }
360396ed8a5SAdriana Kobylak
361396ed8a5SAdriana Kobylak for (const auto& [path, services] : mapperResponse)
362396ed8a5SAdriana Kobylak {
363396ed8a5SAdriana Kobylak for (const auto& serviceIter : services)
364396ed8a5SAdriana Kobylak {
365396ed8a5SAdriana Kobylak const std::string& service = serviceIter.first;
366396ed8a5SAdriana Kobylak
367396ed8a5SAdriana Kobylak try
368396ed8a5SAdriana Kobylak {
369396ed8a5SAdriana Kobylak auto method = bus.new_method_call(service.c_str(), path.c_str(),
370396ed8a5SAdriana Kobylak PROPERTY_INTERFACE, "GetAll");
3719a286db2SPatrick Williams method.append(decoratorServer::PowerSystemInputs::interface);
372396ed8a5SAdriana Kobylak
373396ed8a5SAdriana Kobylak auto response = bus.call(method);
374396ed8a5SAdriana Kobylak using Property = std::string;
375396ed8a5SAdriana Kobylak using Value = std::variant<std::string>;
376396ed8a5SAdriana Kobylak using PropertyMap = std::map<Property, Value>;
377396ed8a5SAdriana Kobylak PropertyMap properties;
378396ed8a5SAdriana Kobylak response.read(properties);
379396ed8a5SAdriana Kobylak
380396ed8a5SAdriana Kobylak auto statusStr = std::get<std::string>(properties["Status"]);
381396ed8a5SAdriana Kobylak auto status =
382396ed8a5SAdriana Kobylak decoratorServer::PowerSystemInputs::convertStatusFromString(
383396ed8a5SAdriana Kobylak statusStr);
384396ed8a5SAdriana Kobylak
385396ed8a5SAdriana Kobylak if (status == decoratorServer::PowerSystemInputs::Status::Fault)
386396ed8a5SAdriana Kobylak {
387396ed8a5SAdriana Kobylak info("Power System Inputs status is in Fault state");
388396ed8a5SAdriana Kobylak server::Chassis::currentPowerStatus(PowerStatus::BrownOut);
38966aacdc4SAndrew Geissler return false;
390396ed8a5SAdriana Kobylak }
391396ed8a5SAdriana Kobylak }
392f053e6feSPatrick Williams catch (const sdbusplus::exception_t& e)
393396ed8a5SAdriana Kobylak {
394396ed8a5SAdriana Kobylak error(
395396ed8a5SAdriana Kobylak "Error reading Power System Inputs property, error: {ERROR}, "
396396ed8a5SAdriana Kobylak "service: {SERVICE} path: {PATH}",
397396ed8a5SAdriana Kobylak "ERROR", e, "SERVICE", service, "PATH", path);
398396ed8a5SAdriana Kobylak throw;
399396ed8a5SAdriana Kobylak }
400396ed8a5SAdriana Kobylak }
401396ed8a5SAdriana Kobylak }
40266aacdc4SAndrew Geissler return true;
403396ed8a5SAdriana Kobylak }
404396ed8a5SAdriana Kobylak
uPowerChangeEvent(sdbusplus::message_t & msg)405f053e6feSPatrick Williams void Chassis::uPowerChangeEvent(sdbusplus::message_t& msg)
4062cf2a268SAndrew Geissler {
4072cf2a268SAndrew Geissler debug("UPS Property Change Event Triggered");
4082cf2a268SAndrew Geissler std::string statusInterface;
4092cf2a268SAndrew Geissler std::map<std::string, std::variant<uint, bool>> msgData;
4102cf2a268SAndrew Geissler msg.read(statusInterface, msgData);
4112cf2a268SAndrew Geissler
412396ed8a5SAdriana Kobylak // If the change is to any of the properties we are interested in, then call
413396ed8a5SAdriana Kobylak // determineStatusOfPower(), which looks at all the power-related
414396ed8a5SAdriana Kobylak // interfaces, to see if a power status change is needed
4152cf2a268SAndrew Geissler auto propertyMap = msgData.find("IsPresent");
4162cf2a268SAndrew Geissler if (propertyMap != msgData.end())
4172cf2a268SAndrew Geissler {
4182cf2a268SAndrew Geissler info("UPS presence changed to {UPS_PRES_INFO}", "UPS_PRES_INFO",
4192cf2a268SAndrew Geissler std::get<bool>(propertyMap->second));
4202cf2a268SAndrew Geissler determineStatusOfPower();
4212cf2a268SAndrew Geissler return;
4222cf2a268SAndrew Geissler }
4232cf2a268SAndrew Geissler
4242cf2a268SAndrew Geissler propertyMap = msgData.find("State");
4252cf2a268SAndrew Geissler if (propertyMap != msgData.end())
4262cf2a268SAndrew Geissler {
4272cf2a268SAndrew Geissler info("UPS State changed to {UPS_STATE}", "UPS_STATE",
4282cf2a268SAndrew Geissler std::get<uint>(propertyMap->second));
4292cf2a268SAndrew Geissler determineStatusOfPower();
4302cf2a268SAndrew Geissler return;
4312cf2a268SAndrew Geissler }
4322cf2a268SAndrew Geissler
4332cf2a268SAndrew Geissler propertyMap = msgData.find("BatteryLevel");
4342cf2a268SAndrew Geissler if (propertyMap != msgData.end())
4352cf2a268SAndrew Geissler {
4362cf2a268SAndrew Geissler info("UPS BatteryLevel changed to {UPS_BAT_LEVEL}", "UPS_BAT_LEVEL",
4372cf2a268SAndrew Geissler std::get<uint>(propertyMap->second));
4382cf2a268SAndrew Geissler determineStatusOfPower();
4392cf2a268SAndrew Geissler return;
4402cf2a268SAndrew Geissler }
4412cf2a268SAndrew Geissler return;
4422cf2a268SAndrew Geissler }
4432cf2a268SAndrew Geissler
powerSysInputsChangeEvent(sdbusplus::message_t & msg)444f053e6feSPatrick Williams void Chassis::powerSysInputsChangeEvent(sdbusplus::message_t& msg)
445396ed8a5SAdriana Kobylak {
446396ed8a5SAdriana Kobylak debug("Power System Inputs Property Change Event Triggered");
447396ed8a5SAdriana Kobylak std::string statusInterface;
448396ed8a5SAdriana Kobylak std::map<std::string, std::variant<std::string>> msgData;
449396ed8a5SAdriana Kobylak msg.read(statusInterface, msgData);
450396ed8a5SAdriana Kobylak
451396ed8a5SAdriana Kobylak // If the change is to any of the properties we are interested in, then call
452396ed8a5SAdriana Kobylak // determineStatusOfPower(), which looks at all the power-related
453396ed8a5SAdriana Kobylak // interfaces, to see if a power status change is needed
454396ed8a5SAdriana Kobylak auto propertyMap = msgData.find("Status");
455396ed8a5SAdriana Kobylak if (propertyMap != msgData.end())
456396ed8a5SAdriana Kobylak {
457396ed8a5SAdriana Kobylak info("Power System Inputs status changed to {POWER_SYS_INPUT_STATUS}",
458396ed8a5SAdriana Kobylak "POWER_SYS_INPUT_STATUS",
459396ed8a5SAdriana Kobylak std::get<std::string>(propertyMap->second));
460396ed8a5SAdriana Kobylak determineStatusOfPower();
461396ed8a5SAdriana Kobylak return;
462396ed8a5SAdriana Kobylak }
463396ed8a5SAdriana Kobylak return;
464396ed8a5SAdriana Kobylak }
465396ed8a5SAdriana Kobylak
startUnit(const std::string & sysdUnit)466be6efabcSMatthew Barth void Chassis::startUnit(const std::string& sysdUnit)
467ce80f24cSAndrew Geissler {
46858a18013SAndrew Geissler auto method = this->bus.new_method_call(SYSTEMD_SERVICE, SYSTEMD_OBJ_PATH,
46958a18013SAndrew Geissler SYSTEMD_INTERFACE, "StartUnit");
470ce80f24cSAndrew Geissler
471be6efabcSMatthew Barth method.append(sysdUnit);
472ce80f24cSAndrew Geissler method.append("replace");
473ce80f24cSAndrew Geissler
474ce80f24cSAndrew Geissler this->bus.call_noreply(method);
475ce80f24cSAndrew Geissler
476ce80f24cSAndrew Geissler return;
477ce80f24cSAndrew Geissler }
478ce80f24cSAndrew Geissler
restartUnit(const std::string & sysdUnit)47977a91831SAndrew Geissler void Chassis::restartUnit(const std::string& sysdUnit)
48077a91831SAndrew Geissler {
48177a91831SAndrew Geissler auto method = this->bus.new_method_call(SYSTEMD_SERVICE, SYSTEMD_OBJ_PATH,
48277a91831SAndrew Geissler SYSTEMD_INTERFACE, "RestartUnit");
48377a91831SAndrew Geissler
48477a91831SAndrew Geissler method.append(sysdUnit);
48577a91831SAndrew Geissler method.append("replace");
48677a91831SAndrew Geissler
48777a91831SAndrew Geissler this->bus.call_noreply(method);
48877a91831SAndrew Geissler
48977a91831SAndrew Geissler return;
49077a91831SAndrew Geissler }
49177a91831SAndrew Geissler
stateActive(const std::string & target)492697474c5SJosh D. King bool Chassis::stateActive(const std::string& target)
493697474c5SJosh D. King {
4942975e26fSPatrick Williams std::variant<std::string> currentState;
495697474c5SJosh D. King sdbusplus::message::object_path unitTargetPath;
496697474c5SJosh D. King
49758a18013SAndrew Geissler auto method = this->bus.new_method_call(SYSTEMD_SERVICE, SYSTEMD_OBJ_PATH,
49858a18013SAndrew Geissler SYSTEMD_INTERFACE, "GetUnit");
499697474c5SJosh D. King
500697474c5SJosh D. King method.append(target);
501697474c5SJosh D. King
50209568ff7SWilliam A. Kennington III try
50309568ff7SWilliam A. Kennington III {
50432c532eaSAnthony Wilson auto result = this->bus.call(method);
505697474c5SJosh D. King result.read(unitTargetPath);
50609568ff7SWilliam A. Kennington III }
507f053e6feSPatrick Williams catch (const sdbusplus::exception_t& e)
50809568ff7SWilliam A. Kennington III {
5098ffdb269SAndrew Geissler error("Error in GetUnit call: {ERROR}", "ERROR", e);
51009568ff7SWilliam A. Kennington III return false;
51109568ff7SWilliam A. Kennington III }
512697474c5SJosh D. King
51358a18013SAndrew Geissler method = this->bus.new_method_call(
51458a18013SAndrew Geissler SYSTEMD_SERVICE,
51558a18013SAndrew Geissler static_cast<const std::string&>(unitTargetPath).c_str(),
51658a18013SAndrew Geissler SYSTEMD_PROPERTY_IFACE, "Get");
517697474c5SJosh D. King
518697474c5SJosh D. King method.append(SYSTEMD_INTERFACE_UNIT, "ActiveState");
519697474c5SJosh D. King
52032c532eaSAnthony Wilson try
521697474c5SJosh D. King {
52232c532eaSAnthony Wilson auto result = this->bus.call(method);
52332c532eaSAnthony Wilson result.read(currentState);
52432c532eaSAnthony Wilson }
525f053e6feSPatrick Williams catch (const sdbusplus::exception_t& e)
52632c532eaSAnthony Wilson {
5278ffdb269SAndrew Geissler error("Error in ActiveState Get: {ERROR}", "ERROR", e);
528697474c5SJosh D. King return false;
529697474c5SJosh D. King }
530697474c5SJosh D. King
53137413dcbSPatrick Williams const auto& currentStateStr = std::get<std::string>(currentState);
5327a0689a9SWilliam A. Kennington III return currentStateStr == ACTIVE_STATE ||
5337a0689a9SWilliam A. Kennington III currentStateStr == ACTIVATING_STATE;
534697474c5SJosh D. King }
535697474c5SJosh D. King
sysStateChange(sdbusplus::message_t & msg)536f053e6feSPatrick Williams int Chassis::sysStateChange(sdbusplus::message_t& msg)
5370029a5d2SAndrew Geissler {
5380029a5d2SAndrew Geissler sdbusplus::message::object_path newStateObjPath;
5390029a5d2SAndrew Geissler std::string newStateUnit{};
5400029a5d2SAndrew Geissler std::string newStateResult{};
5410029a5d2SAndrew Geissler
5420029a5d2SAndrew Geissler // Read the msg and populate each variable
54309568ff7SWilliam A. Kennington III try
54409568ff7SWilliam A. Kennington III {
5459b8af4f2SAndrew Geissler // newStateID is a throwaway that is needed in order to read the
5469b8af4f2SAndrew Geissler // parameters that are useful out of the dbus message
5479b8af4f2SAndrew Geissler uint32_t newStateID{};
5488f8ba39fSPatrick Williams msg.read(newStateID, newStateObjPath, newStateUnit, newStateResult);
54909568ff7SWilliam A. Kennington III }
550f053e6feSPatrick Williams catch (const sdbusplus::exception_t& e)
55109568ff7SWilliam A. Kennington III {
5528ffdb269SAndrew Geissler error("Error in state change - bad encoding: {ERROR} {REPLY_SIG}",
5538ffdb269SAndrew Geissler "ERROR", e, "REPLY_SIG", msg.get_signature());
55409568ff7SWilliam A. Kennington III return 0;
55509568ff7SWilliam A. Kennington III }
5560029a5d2SAndrew Geissler
55778c066f6SPatrick Williams if ((newStateUnit == std::format(CHASSIS_STATE_POWEROFF_TGT_FMT, id)) &&
55870f36d8eSPotin Lai (newStateResult == "done") &&
55970f36d8eSPotin Lai (!stateActive(systemdTargetTable[Transition::On])))
5600029a5d2SAndrew Geissler {
5618ffdb269SAndrew Geissler info("Received signal that power OFF is complete");
5620029a5d2SAndrew Geissler this->currentPowerState(server::Chassis::PowerState::Off);
5639eab9861SMatt Spinler this->setStateChangeTime();
5640029a5d2SAndrew Geissler }
56570f36d8eSPotin Lai else if ((newStateUnit == systemdTargetTable[Transition::On]) &&
566697474c5SJosh D. King (newStateResult == "done") &&
56770f36d8eSPotin Lai (stateActive(systemdTargetTable[Transition::On])))
5680029a5d2SAndrew Geissler {
5698ffdb269SAndrew Geissler info("Received signal that power ON is complete");
5700029a5d2SAndrew Geissler this->currentPowerState(server::Chassis::PowerState::On);
5719eab9861SMatt Spinler this->setStateChangeTime();
572f2b22e8eSAndrew Geissler
573f2b22e8eSAndrew Geissler // Remove temporary file which is utilized for scenarios where the
574f2b22e8eSAndrew Geissler // BMC is rebooted while the chassis power is still on.
575f2b22e8eSAndrew Geissler // This file is used to indicate to chassis related systemd services
576f2b22e8eSAndrew Geissler // that the chassis is already on and they should skip running.
577f2b22e8eSAndrew Geissler // Once the chassis state is back to on we can clear this file.
57878c066f6SPatrick Williams auto chassisFile = std::format(CHASSIS_ON_FILE, 0);
57978c066f6SPatrick Williams if (std::filesystem::exists(chassisFile))
580f2b22e8eSAndrew Geissler {
58178c066f6SPatrick Williams std::filesystem::remove(chassisFile);
582f2b22e8eSAndrew Geissler }
5830029a5d2SAndrew Geissler }
5840029a5d2SAndrew Geissler
5850029a5d2SAndrew Geissler return 0;
5860029a5d2SAndrew Geissler }
5870029a5d2SAndrew Geissler
requestedPowerTransition(Transition value)588a90a31a9SAndrew Geissler Chassis::Transition Chassis::requestedPowerTransition(Transition value)
589a90a31a9SAndrew Geissler {
5908ffdb269SAndrew Geissler info("Change to Chassis Requested Power State: {REQ_POWER_TRAN}",
5918ffdb269SAndrew Geissler "REQ_POWER_TRAN", value);
592765446aeSAndrew Geissler #if ONLY_ALLOW_BOOT_WHEN_BMC_READY
593765446aeSAndrew Geissler if ((value != Transition::Off) && (!utils::isBmcReady(this->bus)))
594765446aeSAndrew Geissler {
595765446aeSAndrew Geissler info("BMC State is not Ready so no chassis on operations allowed");
596765446aeSAndrew Geissler throw sdbusplus::xyz::openbmc_project::State::Chassis::Error::
597765446aeSAndrew Geissler BMCNotReady();
598765446aeSAndrew Geissler }
599765446aeSAndrew Geissler #endif
600*9f38152aSThang Tran
601*9f38152aSThang Tran #ifdef CHECK_FWUPDATE_BEFORE_DO_TRANSITION
602*9f38152aSThang Tran /*
603*9f38152aSThang Tran * Do not do transition when the any firmware being updated
604*9f38152aSThang Tran */
605*9f38152aSThang Tran if ((value != Transition::Off) &&
606*9f38152aSThang Tran (phosphor::state::manager::utils::isFirmwareUpdating(this->bus)))
607*9f38152aSThang Tran {
608*9f38152aSThang Tran info("Firmware being updated, reject the transition request");
609*9f38152aSThang Tran throw sdbusplus::xyz::openbmc_project::Common::Error::Unavailable();
610*9f38152aSThang Tran }
611*9f38152aSThang Tran #endif // CHECK_FWUPDATE_BEFORE_DO_TRANSITION
612*9f38152aSThang Tran
61370f36d8eSPotin Lai startUnit(systemdTargetTable.find(value)->second);
614a90a31a9SAndrew Geissler return server::Chassis::requestedPowerTransition(value);
615a90a31a9SAndrew Geissler }
616a90a31a9SAndrew Geissler
currentPowerState(PowerState value)617a90a31a9SAndrew Geissler Chassis::PowerState Chassis::currentPowerState(PowerState value)
618a90a31a9SAndrew Geissler {
619cb781fe1SNagaraju Goruganti PowerState chassisPowerState;
6208ffdb269SAndrew Geissler info("Change to Chassis Power State: {CUR_POWER_STATE}", "CUR_POWER_STATE",
6218ffdb269SAndrew Geissler value);
622cb781fe1SNagaraju Goruganti
623cb781fe1SNagaraju Goruganti chassisPowerState = server::Chassis::currentPowerState(value);
6246d582a88Sshamim ali if (chassisPowerState == PowerState::On)
6256d582a88Sshamim ali {
6266d582a88Sshamim ali pohTimer.resetRemaining();
6276d582a88Sshamim ali }
628cb781fe1SNagaraju Goruganti return chassisPowerState;
629cb781fe1SNagaraju Goruganti }
630cb781fe1SNagaraju Goruganti
pohCounter(uint32_t value)63145a1ed71SPatrick Williams uint32_t Chassis::pohCounter(uint32_t value)
632cb781fe1SNagaraju Goruganti {
63345a1ed71SPatrick Williams if (value != pohCounter())
634cb781fe1SNagaraju Goruganti {
63545a1ed71SPatrick Williams ChassisInherit::pohCounter(value);
63681957841SMatt Spinler serializePOH();
637cb781fe1SNagaraju Goruganti }
63845a1ed71SPatrick Williams return pohCounter();
639cb781fe1SNagaraju Goruganti }
640cb781fe1SNagaraju Goruganti
pohCallback()64145a1ed71SPatrick Williams void Chassis::pohCallback()
642d998f82bSWilliam A. Kennington III {
643d998f82bSWilliam A. Kennington III if (ChassisInherit::currentPowerState() == PowerState::On)
644d998f82bSWilliam A. Kennington III {
64545a1ed71SPatrick Williams pohCounter(pohCounter() + 1);
646d998f82bSWilliam A. Kennington III }
647d998f82bSWilliam A. Kennington III }
648d998f82bSWilliam A. Kennington III
restorePOHCounter()649cb781fe1SNagaraju Goruganti void Chassis::restorePOHCounter()
650cb781fe1SNagaraju Goruganti {
651cb781fe1SNagaraju Goruganti uint32_t counter;
652ba182f0cSAllen.Wang if (!deserializePOH(counter))
653cb781fe1SNagaraju Goruganti {
654cb781fe1SNagaraju Goruganti // set to default value
65545a1ed71SPatrick Williams pohCounter(0);
656cb781fe1SNagaraju Goruganti }
657cb781fe1SNagaraju Goruganti else
658cb781fe1SNagaraju Goruganti {
65945a1ed71SPatrick Williams pohCounter(counter);
660cb781fe1SNagaraju Goruganti }
661cb781fe1SNagaraju Goruganti }
662cb781fe1SNagaraju Goruganti
serializePOH()663ba182f0cSAllen.Wang fs::path Chassis::serializePOH()
664cb781fe1SNagaraju Goruganti {
66578c066f6SPatrick Williams fs::path path{std::format(POH_COUNTER_PERSIST_PATH, id)};
666cb781fe1SNagaraju Goruganti std::ofstream os(path.c_str(), std::ios::binary);
667cb781fe1SNagaraju Goruganti cereal::JSONOutputArchive oarchive(os);
66845a1ed71SPatrick Williams oarchive(pohCounter());
669cb781fe1SNagaraju Goruganti return path;
670cb781fe1SNagaraju Goruganti }
671cb781fe1SNagaraju Goruganti
deserializePOH(uint32_t & pohCounter)672ba182f0cSAllen.Wang bool Chassis::deserializePOH(uint32_t& pohCounter)
673cb781fe1SNagaraju Goruganti {
67478c066f6SPatrick Williams fs::path path{std::format(POH_COUNTER_PERSIST_PATH, id)};
675cb781fe1SNagaraju Goruganti try
676cb781fe1SNagaraju Goruganti {
677cb781fe1SNagaraju Goruganti if (fs::exists(path))
678cb781fe1SNagaraju Goruganti {
679cb781fe1SNagaraju Goruganti std::ifstream is(path.c_str(), std::ios::in | std::ios::binary);
680cb781fe1SNagaraju Goruganti cereal::JSONInputArchive iarchive(is);
68145a1ed71SPatrick Williams iarchive(pohCounter);
682cb781fe1SNagaraju Goruganti return true;
683cb781fe1SNagaraju Goruganti }
684cb781fe1SNagaraju Goruganti return false;
685cb781fe1SNagaraju Goruganti }
6868583b3b9SPatrick Williams catch (const cereal::Exception& e)
687cb781fe1SNagaraju Goruganti {
6888ffdb269SAndrew Geissler error("deserialize exception: {ERROR}", "ERROR", e);
689cb781fe1SNagaraju Goruganti fs::remove(path);
690cb781fe1SNagaraju Goruganti return false;
691cb781fe1SNagaraju Goruganti }
692cb781fe1SNagaraju Goruganti catch (const fs::filesystem_error& e)
693cb781fe1SNagaraju Goruganti {
694cb781fe1SNagaraju Goruganti return false;
695cb781fe1SNagaraju Goruganti }
696cb781fe1SNagaraju Goruganti
697cb781fe1SNagaraju Goruganti return false;
698cb781fe1SNagaraju Goruganti }
699cb781fe1SNagaraju Goruganti
startPOHCounter()700cb781fe1SNagaraju Goruganti void Chassis::startPOHCounter()
701cb781fe1SNagaraju Goruganti {
702cb781fe1SNagaraju Goruganti auto dir = fs::path(POH_COUNTER_PERSIST_PATH).parent_path();
703cb781fe1SNagaraju Goruganti fs::create_directories(dir);
704cb781fe1SNagaraju Goruganti
705cb781fe1SNagaraju Goruganti try
706cb781fe1SNagaraju Goruganti {
707d998f82bSWilliam A. Kennington III auto event = sdeventplus::Event::get_default();
708d998f82bSWilliam A. Kennington III bus.attach_event(event.get(), SD_EVENT_PRIORITY_NORMAL);
709d998f82bSWilliam A. Kennington III event.loop();
710cb781fe1SNagaraju Goruganti }
711d998f82bSWilliam A. Kennington III catch (const sdeventplus::SdEventError& e)
712cb781fe1SNagaraju Goruganti {
7138ffdb269SAndrew Geissler error("Error occurred during the sdeventplus loop: {ERROR}", "ERROR",
7148ffdb269SAndrew Geissler e);
715cb781fe1SNagaraju Goruganti phosphor::logging::commit<InternalFailure>();
716cb781fe1SNagaraju Goruganti }
717a90a31a9SAndrew Geissler }
718a90a31a9SAndrew Geissler
serializeStateChangeTime()7199eab9861SMatt Spinler void Chassis::serializeStateChangeTime()
7209eab9861SMatt Spinler {
72178c066f6SPatrick Williams fs::path path{std::format(CHASSIS_STATE_CHANGE_PERSIST_PATH, id)};
7229eab9861SMatt Spinler std::ofstream os(path.c_str(), std::ios::binary);
7239eab9861SMatt Spinler cereal::JSONOutputArchive oarchive(os);
7249eab9861SMatt Spinler
7259eab9861SMatt Spinler oarchive(ChassisInherit::lastStateChangeTime(),
7269eab9861SMatt Spinler ChassisInherit::currentPowerState());
7279eab9861SMatt Spinler }
7289eab9861SMatt Spinler
deserializeStateChangeTime(uint64_t & time,PowerState & state)7299eab9861SMatt Spinler bool Chassis::deserializeStateChangeTime(uint64_t& time, PowerState& state)
7309eab9861SMatt Spinler {
73178c066f6SPatrick Williams fs::path path{std::format(CHASSIS_STATE_CHANGE_PERSIST_PATH, id)};
7329eab9861SMatt Spinler
7339eab9861SMatt Spinler try
7349eab9861SMatt Spinler {
7359eab9861SMatt Spinler if (fs::exists(path))
7369eab9861SMatt Spinler {
7379eab9861SMatt Spinler std::ifstream is(path.c_str(), std::ios::in | std::ios::binary);
7389eab9861SMatt Spinler cereal::JSONInputArchive iarchive(is);
7399eab9861SMatt Spinler iarchive(time, state);
7409eab9861SMatt Spinler return true;
7419eab9861SMatt Spinler }
7429eab9861SMatt Spinler }
7438583b3b9SPatrick Williams catch (const std::exception& e)
7449eab9861SMatt Spinler {
7458ffdb269SAndrew Geissler error("deserialize exception: {ERROR}", "ERROR", e);
7469eab9861SMatt Spinler fs::remove(path);
7479eab9861SMatt Spinler }
7489eab9861SMatt Spinler
7499eab9861SMatt Spinler return false;
7509eab9861SMatt Spinler }
7519eab9861SMatt Spinler
restoreChassisStateChangeTime()7529eab9861SMatt Spinler void Chassis::restoreChassisStateChangeTime()
7539eab9861SMatt Spinler {
7549eab9861SMatt Spinler uint64_t time;
7559eab9861SMatt Spinler PowerState state;
7569eab9861SMatt Spinler
7579eab9861SMatt Spinler if (!deserializeStateChangeTime(time, state))
7589eab9861SMatt Spinler {
7599eab9861SMatt Spinler ChassisInherit::lastStateChangeTime(0);
7609eab9861SMatt Spinler }
7619eab9861SMatt Spinler else
7629eab9861SMatt Spinler {
7639eab9861SMatt Spinler ChassisInherit::lastStateChangeTime(time);
7649eab9861SMatt Spinler }
7659eab9861SMatt Spinler }
7669eab9861SMatt Spinler
setStateChangeTime()7679eab9861SMatt Spinler void Chassis::setStateChangeTime()
7689eab9861SMatt Spinler {
7699eab9861SMatt Spinler using namespace std::chrono;
7709eab9861SMatt Spinler uint64_t lastTime;
7719eab9861SMatt Spinler PowerState lastState;
7729eab9861SMatt Spinler
7739eab9861SMatt Spinler auto now =
7749eab9861SMatt Spinler duration_cast<milliseconds>(system_clock::now().time_since_epoch())
7759eab9861SMatt Spinler .count();
7769eab9861SMatt Spinler
7779eab9861SMatt Spinler // If power is on when the BMC is rebooted, this function will get called
7789eab9861SMatt Spinler // because sysStateChange() runs. Since the power state didn't change
7799eab9861SMatt Spinler // in this case, neither should the state change time, so check that
7809eab9861SMatt Spinler // the power state actually did change here.
7819eab9861SMatt Spinler if (deserializeStateChangeTime(lastTime, lastState))
7829eab9861SMatt Spinler {
7839eab9861SMatt Spinler if (lastState == ChassisInherit::currentPowerState())
7849eab9861SMatt Spinler {
7859eab9861SMatt Spinler return;
7869eab9861SMatt Spinler }
7879eab9861SMatt Spinler }
7889eab9861SMatt Spinler
7899eab9861SMatt Spinler ChassisInherit::lastStateChangeTime(now);
7909eab9861SMatt Spinler serializeStateChangeTime();
7919eab9861SMatt Spinler }
7929eab9861SMatt Spinler
standbyVoltageRegulatorFault()7932c36e5adSBen Tyner bool Chassis::standbyVoltageRegulatorFault()
7942c36e5adSBen Tyner {
7952c36e5adSBen Tyner bool regulatorFault = false;
7962c36e5adSBen Tyner
797f8ae6a02SAndrew Geissler // find standby voltage regulator fault via gpiog
7982c36e5adSBen Tyner
799f8ae6a02SAndrew Geissler auto gpioval = utils::getGpioValue("regulator-standby-faulted");
8002c36e5adSBen Tyner
8012c36e5adSBen Tyner if (-1 == gpioval)
8022c36e5adSBen Tyner {
8032c36e5adSBen Tyner error("Failed reading regulator-standby-faulted GPIO");
8042c36e5adSBen Tyner }
8052c36e5adSBen Tyner
8062c36e5adSBen Tyner if (1 == gpioval)
8072c36e5adSBen Tyner {
8082c36e5adSBen Tyner info("Detected standby voltage regulator fault");
8092c36e5adSBen Tyner regulatorFault = true;
8102c36e5adSBen Tyner }
811f8ae6a02SAndrew Geissler
8122c36e5adSBen Tyner return regulatorFault;
8132c36e5adSBen Tyner }
8142c36e5adSBen Tyner
815a90a31a9SAndrew Geissler } // namespace manager
816a90a31a9SAndrew Geissler } // namespace state
817a965cf06SAndrew Geissler } // namespace phosphor
818