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