xref: /openbmc/phosphor-state-manager/discover_system_state.cpp (revision 3d5062804ce3eb4f198ffd2bed2f4f4876af8aee)
1769a62f1SAndrew Geissler #include "config.h"
2e426b589SAndrew Geissler 
33ed10085SMichael Tritz #include "host_state_manager.hpp"
455f132bfSDeepak Kodihalli #include "settings.hpp"
549e6713aSAndrew Geissler #include "utils.hpp"
655f132bfSDeepak Kodihalli #include "xyz/openbmc_project/Common/error.hpp"
755f132bfSDeepak Kodihalli #include "xyz/openbmc_project/Control/Power/RestorePolicy/server.hpp"
83ed10085SMichael Tritz 
9e426b589SAndrew Geissler #include <getopt.h>
10e426b589SAndrew Geissler #include <systemd/sd-bus.h>
11e426b589SAndrew Geissler 
12e426b589SAndrew Geissler #include <phosphor-logging/elog-errors.hpp>
138ffdb269SAndrew Geissler #include <phosphor-logging/lg2.hpp>
14e426b589SAndrew Geissler #include <sdbusplus/exception.hpp>
15e426b589SAndrew Geissler #include <sdbusplus/server.hpp>
169a286db2SPatrick Williams #include <xyz/openbmc_project/State/BMC/client.hpp>
179a286db2SPatrick Williams #include <xyz/openbmc_project/State/Host/client.hpp>
18e426b589SAndrew Geissler 
19bcbee4a2SNodeMan97 #include <filesystem>
20e426b589SAndrew Geissler #include <iostream>
21e426b589SAndrew Geissler #include <map>
22e426b589SAndrew Geissler #include <string>
23358de95eSNodeMan97 #include <thread>
24e426b589SAndrew Geissler 
253ed10085SMichael Tritz namespace phosphor
263ed10085SMichael Tritz {
273ed10085SMichael Tritz namespace state
283ed10085SMichael Tritz {
293ed10085SMichael Tritz namespace manager
303ed10085SMichael Tritz {
313ed10085SMichael Tritz 
328ffdb269SAndrew Geissler PHOSPHOR_LOG2_USING;
338ffdb269SAndrew Geissler 
343ed10085SMichael Tritz using namespace phosphor::logging;
3555f132bfSDeepak Kodihalli using namespace sdbusplus::xyz::openbmc_project::Common::Error;
367e969cb9SPatrick Williams using namespace sdbusplus::server::xyz::openbmc_project::control::power;
37f566c964SAmithash Prasasd using HostState = sdbusplus::client::xyz::openbmc_project::state::Host<>;
38f566c964SAmithash Prasasd using BMCState = sdbusplus::client::xyz::openbmc_project::state::BMC<>;
393ed10085SMichael Tritz 
403ed10085SMichael Tritz } // namespace manager
413ed10085SMichael Tritz } // namespace state
42a965cf06SAndrew Geissler } // namespace phosphor
433ed10085SMichael Tritz 
main(int argc,char ** argv)44d50f6578SMichael Tritz int main(int argc, char** argv)
453ed10085SMichael Tritz {
4655f132bfSDeepak Kodihalli     using namespace phosphor::logging;
4755f132bfSDeepak Kodihalli 
48c328a4cfSPotin Lai     size_t hostId = 0;
49d50f6578SMichael Tritz     int arg;
50d50f6578SMichael Tritz     int optIndex = 0;
51d50f6578SMichael Tritz 
52f15b9544SPavithra Barithaya     static struct option longOpts[] = {
53f15b9544SPavithra Barithaya         {"host", required_argument, nullptr, 'h'}, {nullptr, 0, nullptr, 0}};
54d50f6578SMichael Tritz 
55d50f6578SMichael Tritz     while ((arg = getopt_long(argc, argv, "h:", longOpts, &optIndex)) != -1)
56d50f6578SMichael Tritz     {
57d50f6578SMichael Tritz         switch (arg)
58d50f6578SMichael Tritz         {
59d50f6578SMichael Tritz             case 'h':
60c328a4cfSPotin Lai                 hostId = std::stoul(optarg);
61d50f6578SMichael Tritz                 break;
62d50f6578SMichael Tritz             default:
63d50f6578SMichael Tritz                 break;
64d50f6578SMichael Tritz         }
65d50f6578SMichael Tritz     }
66d50f6578SMichael Tritz 
679a286db2SPatrick Williams     using Host = sdbusplus::client::xyz::openbmc_project::state::Host<>;
681b2c3c03SPatrick Williams     std::string hostPath =
691b2c3c03SPatrick Williams         std::string(Host::namespace_path::value) + "/" +
701b2c3c03SPatrick Williams         std::string(Host::namespace_path::host) + std::to_string(hostId);
719a286db2SPatrick Williams 
723ed10085SMichael Tritz     auto bus = sdbusplus::bus::new_default();
733ed10085SMichael Tritz 
7455f132bfSDeepak Kodihalli     using namespace settings;
75c328a4cfSPotin Lai     HostObjects settings(bus, hostId);
7655f132bfSDeepak Kodihalli 
773ed10085SMichael Tritz     using namespace phosphor::state::manager;
787e969cb9SPatrick Williams     namespace server = sdbusplus::server::xyz::openbmc_project::state;
793ed10085SMichael Tritz 
80033fc3bdSAndrew Geissler     // This application is only run if chassis power is off
813ed10085SMichael Tritz 
82b2b3d9c2SAndrew Geissler     // If the BMC was rebooted due to a user initiated pinhole reset, do not
83b2b3d9c2SAndrew Geissler     // implement any power restore policies
849a286db2SPatrick Williams     using BMC = sdbusplus::client::xyz::openbmc_project::state::BMC<>;
859a286db2SPatrick Williams     auto bmcPath = sdbusplus::message::object_path(BMC::namespace_path::value) /
869a286db2SPatrick Williams                    BMC::namespace_path::bmc;
879a286db2SPatrick Williams 
889a286db2SPatrick Williams     auto bmcRebootCause =
899a286db2SPatrick Williams         sdbusplus::message::convert_from_string<BMC::RebootCause>(
909a286db2SPatrick Williams             phosphor::state::manager::utils::getProperty(
91f566c964SAmithash Prasasd                 bus, bmcPath.str, BMCState::interface, "LastRebootCause"));
929a286db2SPatrick Williams 
939a286db2SPatrick Williams     if (bmcRebootCause == BMC::RebootCause::PinholeReset)
94b2b3d9c2SAndrew Geissler     {
95b2b3d9c2SAndrew Geissler         info(
96b2b3d9c2SAndrew Geissler             "BMC was reset due to pinhole reset, no power restore policy will be run");
97b2b3d9c2SAndrew Geissler         return 0;
98b2b3d9c2SAndrew Geissler     }
999a286db2SPatrick Williams     else if (bmcRebootCause == BMC::RebootCause::Watchdog)
100b669ea30SThang Q. Nguyen     {
101b669ea30SThang Q. Nguyen         info(
102b669ea30SThang Q. Nguyen             "BMC was reset due to cold reset, no power restore policy will be run");
103b669ea30SThang Q. Nguyen         return 0;
104b669ea30SThang Q. Nguyen     }
105b2b3d9c2SAndrew Geissler 
10635ca2e34SAndrew Geissler     /* The logic here is to first check the one-time PowerRestorePolicy setting.
10735ca2e34SAndrew Geissler      * If this property is not the default then look at the persistent
10835ca2e34SAndrew Geissler      * user setting in the non one-time object, otherwise honor the one-time
10935ca2e34SAndrew Geissler      * setting.
11035ca2e34SAndrew Geissler      */
11135ca2e34SAndrew Geissler     auto methodOneTime = bus.new_method_call(
11235ca2e34SAndrew Geissler         settings.service(settings.powerRestorePolicy, powerRestoreIntf).c_str(),
11335ca2e34SAndrew Geissler         settings.powerRestorePolicyOneTime.c_str(),
11435ca2e34SAndrew Geissler         "org.freedesktop.DBus.Properties", "Get");
11535ca2e34SAndrew Geissler     methodOneTime.append(powerRestoreIntf, "PowerRestorePolicy");
11635ca2e34SAndrew Geissler 
11735ca2e34SAndrew Geissler     auto methodUserSetting = bus.new_method_call(
11858a18013SAndrew Geissler         settings.service(settings.powerRestorePolicy, powerRestoreIntf).c_str(),
11958a18013SAndrew Geissler         settings.powerRestorePolicy.c_str(), "org.freedesktop.DBus.Properties",
12055f132bfSDeepak Kodihalli         "Get");
12135ca2e34SAndrew Geissler     methodUserSetting.append(powerRestoreIntf, "PowerRestorePolicy");
12232c532eaSAnthony Wilson 
1232975e26fSPatrick Williams     std::variant<std::string> result;
12432c532eaSAnthony Wilson     try
12555f132bfSDeepak Kodihalli     {
12635ca2e34SAndrew Geissler         auto reply = bus.call(methodOneTime);
12732c532eaSAnthony Wilson         reply.read(result);
12837413dcbSPatrick Williams         auto powerPolicy = std::get<std::string>(result);
1293ed10085SMichael Tritz 
13035ca2e34SAndrew Geissler         if (RestorePolicy::Policy::None ==
13135ca2e34SAndrew Geissler             RestorePolicy::convertPolicyFromString(powerPolicy))
13235ca2e34SAndrew Geissler         {
13335ca2e34SAndrew Geissler             // one_time is set to None so use the customer setting
1348ffdb269SAndrew Geissler             info("One time not set, check user setting of power policy");
135bcbee4a2SNodeMan97 
13635ca2e34SAndrew Geissler             auto reply = bus.call(methodUserSetting);
13735ca2e34SAndrew Geissler             reply.read(result);
13835ca2e34SAndrew Geissler             powerPolicy = std::get<std::string>(result);
13935ca2e34SAndrew Geissler         }
14035ca2e34SAndrew Geissler         else
14135ca2e34SAndrew Geissler         {
14235ca2e34SAndrew Geissler             // one_time setting was set so we're going to use it. Reset it
14335ca2e34SAndrew Geissler             // to default for next time.
1448ffdb269SAndrew Geissler             info("One time set, use it and reset to default");
14549e6713aSAndrew Geissler             phosphor::state::manager::utils::setProperty(
146695888deSPavithra Barithaya                 bus, settings.powerRestorePolicyOneTime, powerRestoreIntf,
147695888deSPavithra Barithaya                 "PowerRestorePolicy",
14835ca2e34SAndrew Geissler                 convertForMessage(RestorePolicy::Policy::None));
14935ca2e34SAndrew Geissler         }
15035ca2e34SAndrew Geissler 
151358de95eSNodeMan97         auto methodUserSettingDelay = bus.new_method_call(
152358de95eSNodeMan97             settings.service(settings.powerRestorePolicy, powerRestoreIntf)
153358de95eSNodeMan97                 .c_str(),
154358de95eSNodeMan97             settings.powerRestorePolicy.c_str(),
155358de95eSNodeMan97             "org.freedesktop.DBus.Properties", "Get");
156358de95eSNodeMan97 
157358de95eSNodeMan97         methodUserSettingDelay.append(powerRestoreIntf, "PowerRestoreDelay");
158358de95eSNodeMan97 
159358de95eSNodeMan97         std::variant<uint64_t> restoreDelay;
160358de95eSNodeMan97 
161358de95eSNodeMan97         auto delayResult = bus.call(methodUserSettingDelay);
162358de95eSNodeMan97         delayResult.read(restoreDelay);
163358de95eSNodeMan97         auto powerRestoreDelayUsec =
164358de95eSNodeMan97             std::chrono::microseconds(std::get<uint64_t>(restoreDelay));
165358de95eSNodeMan97         auto powerRestoreDelaySec =
166358de95eSNodeMan97             std::chrono::duration_cast<std::chrono::seconds>(
167358de95eSNodeMan97                 powerRestoreDelayUsec);
168358de95eSNodeMan97 
1698ffdb269SAndrew Geissler         info("Host power is off, processing power policy {POWER_POLICY}",
1708ffdb269SAndrew Geissler              "POWER_POLICY", powerPolicy);
1713ed10085SMichael Tritz 
17255f132bfSDeepak Kodihalli         if (RestorePolicy::Policy::AlwaysOn ==
17355f132bfSDeepak Kodihalli             RestorePolicy::convertPolicyFromString(powerPolicy))
1743ed10085SMichael Tritz         {
175358de95eSNodeMan97             info(
176358de95eSNodeMan97                 "power_policy=ALWAYS_POWER_ON, powering host on ({DELAY}s delay)",
177358de95eSNodeMan97                 "DELAY", powerRestoreDelaySec.count());
178*3d506280SPrithvi Pai #ifdef APPLY_POWER_POLICY_WHEN_BMC_READY
1790886545dSPotin Lai             utils::waitBmcReady(bus, powerRestoreDelaySec);
180*3d506280SPrithvi Pai #else
181*3d506280SPrithvi Pai             std::this_thread::sleep_for(powerRestoreDelayUsec);
182*3d506280SPrithvi Pai #endif
18349e6713aSAndrew Geissler             phosphor::state::manager::utils::setProperty(
184f566c964SAmithash Prasasd                 bus, hostPath, HostState::interface, "RestartCause",
185744e5617SAndrew Geissler                 convertForMessage(
186744e5617SAndrew Geissler                     server::Host::RestartCause::PowerPolicyAlwaysOn));
18749e6713aSAndrew Geissler             phosphor::state::manager::utils::setProperty(
188f566c964SAmithash Prasasd                 bus, hostPath, HostState::interface, "RequestedHostTransition",
1893ed10085SMichael Tritz                 convertForMessage(server::Host::Transition::On));
1903ed10085SMichael Tritz         }
19170b48f31SAndrew Geissler         // Always execute power on if AlwaysOn is set, otherwise check config
19270b48f31SAndrew Geissler         // option (and AC loss status) on whether to execute other policy
19370b48f31SAndrew Geissler         // settings
194e960184dSPotin Lai #if ONLY_RUN_APR_ON_POWER_LOSS
19570b48f31SAndrew Geissler         else if (!phosphor::state::manager::utils::checkACLoss(hostId))
19670b48f31SAndrew Geissler         {
19770b48f31SAndrew Geissler             info(
19870b48f31SAndrew Geissler                 "Chassis power was not on prior to BMC reboot so do not run any further power policy");
19970b48f31SAndrew Geissler             return 0;
20070b48f31SAndrew Geissler         }
20170b48f31SAndrew Geissler #endif
2021fc48456SThang Tran         else if (RestorePolicy::Policy::AlwaysOff ==
2031fc48456SThang Tran                  RestorePolicy::convertPolicyFromString(powerPolicy))
2041fc48456SThang Tran         {
205358de95eSNodeMan97             info(
206358de95eSNodeMan97                 "power_policy=ALWAYS_POWER_OFF, set requested state to off ({DELAY}s delay)",
207358de95eSNodeMan97                 "DELAY", powerRestoreDelaySec.count());
208*3d506280SPrithvi Pai #ifdef APPLY_POWER_POLICY_WHEN_BMC_READY
2090886545dSPotin Lai             utils::waitBmcReady(bus, powerRestoreDelaySec);
210*3d506280SPrithvi Pai #else
211*3d506280SPrithvi Pai             std::this_thread::sleep_for(powerRestoreDelayUsec);
212*3d506280SPrithvi Pai #endif
2136810ad50SThang Tran             // Read last requested state and re-request it to execute it
2146810ad50SThang Tran             auto hostReqState = phosphor::state::manager::utils::getProperty(
215f566c964SAmithash Prasasd                 bus, hostPath, HostState::interface, "RequestedHostTransition");
216744fe627SNodeMan97             if (hostReqState !=
217744fe627SNodeMan97                 convertForMessage(server::Host::Transition::Off))
2186810ad50SThang Tran             {
219d93da775SAndrew Geissler                 phosphor::state::manager::utils::setProperty(
220f566c964SAmithash Prasasd                     bus, hostPath, HostState::interface,
221f566c964SAmithash Prasasd                     "RequestedHostTransition",
2221fc48456SThang Tran                     convertForMessage(server::Host::Transition::Off));
2231fc48456SThang Tran             }
2246810ad50SThang Tran         }
225033fc3bdSAndrew Geissler         else if (RestorePolicy::Policy::Restore ==
226033fc3bdSAndrew Geissler                  RestorePolicy::convertPolicyFromString(powerPolicy))
227033fc3bdSAndrew Geissler         {
228358de95eSNodeMan97             info("power_policy=RESTORE, restoring last state ({DELAY}s delay)",
229358de95eSNodeMan97                  "DELAY", powerRestoreDelaySec.count());
230*3d506280SPrithvi Pai #ifdef APPLY_POWER_POLICY_WHEN_BMC_READY
2310886545dSPotin Lai             utils::waitBmcReady(bus, powerRestoreDelaySec);
232*3d506280SPrithvi Pai #else
233*3d506280SPrithvi Pai             std::this_thread::sleep_for(powerRestoreDelayUsec);
234*3d506280SPrithvi Pai #endif
2356810ad50SThang Tran             // Read last requested state and re-request it to execute it
2366810ad50SThang Tran             auto hostReqState = phosphor::state::manager::utils::getProperty(
237f566c964SAmithash Prasasd                 bus, hostPath, HostState::interface, "RequestedHostTransition");
238744fe627SNodeMan97 
239744fe627SNodeMan97             // As long as the host transition is not 'Off' power on host state.
240744fe627SNodeMan97             if (hostReqState !=
241744fe627SNodeMan97                 convertForMessage(server::Host::Transition::Off))
2426810ad50SThang Tran             {
24349e6713aSAndrew Geissler                 phosphor::state::manager::utils::setProperty(
244f566c964SAmithash Prasasd                     bus, hostPath, HostState::interface, "RestartCause",
245744e5617SAndrew Geissler                     convertForMessage(
246744e5617SAndrew Geissler                         server::Host::RestartCause::PowerPolicyPreviousState));
24749e6713aSAndrew Geissler                 phosphor::state::manager::utils::setProperty(
248f566c964SAmithash Prasasd                     bus, hostPath, HostState::interface,
249f566c964SAmithash Prasasd                     "RequestedHostTransition",
250744fe627SNodeMan97                     convertForMessage(server::Host::Transition::On));
2513ed10085SMichael Tritz             }
25235ca2e34SAndrew Geissler         }
2536810ad50SThang Tran     }
254f053e6feSPatrick Williams     catch (const sdbusplus::exception_t& e)
25535ca2e34SAndrew Geissler     {
2568ffdb269SAndrew Geissler         error("Error in PowerRestorePolicy Get: {ERROR}", "ERROR", e);
25735ca2e34SAndrew Geissler         elog<InternalFailure>();
25835ca2e34SAndrew Geissler     }
2593ed10085SMichael Tritz 
2603ed10085SMichael Tritz     return 0;
2613ed10085SMichael Tritz }
262