1 #include "config.h" 2 3 #include "host_state_manager.hpp" 4 #include "settings.hpp" 5 #include "utils.hpp" 6 #include "xyz/openbmc_project/Common/error.hpp" 7 #include "xyz/openbmc_project/Control/Power/RestorePolicy/server.hpp" 8 9 #include <getopt.h> 10 #include <systemd/sd-bus.h> 11 12 #include <phosphor-logging/elog-errors.hpp> 13 #include <phosphor-logging/lg2.hpp> 14 #include <sdbusplus/exception.hpp> 15 #include <sdbusplus/server.hpp> 16 17 #include <iostream> 18 #include <map> 19 #include <string> 20 21 namespace phosphor 22 { 23 namespace state 24 { 25 namespace manager 26 { 27 28 PHOSPHOR_LOG2_USING; 29 30 using namespace phosphor::logging; 31 using namespace sdbusplus::xyz::openbmc_project::Common::Error; 32 using namespace sdbusplus::xyz::openbmc_project::Control::Power::server; 33 34 } // namespace manager 35 } // namespace state 36 } // namespace phosphor 37 38 int main(int argc, char** argv) 39 { 40 using namespace phosphor::logging; 41 42 std::string hostPath = "/xyz/openbmc_project/state/host0"; 43 int arg; 44 int optIndex = 0; 45 46 static struct option longOpts[] = {{"host", required_argument, 0, 'h'}, 47 {0, 0, 0, 0}}; 48 49 while ((arg = getopt_long(argc, argv, "h:", longOpts, &optIndex)) != -1) 50 { 51 switch (arg) 52 { 53 case 'h': 54 hostPath = 55 std::string("/xyz/openbmc_project/state/host") + optarg; 56 break; 57 default: 58 break; 59 } 60 } 61 62 auto bus = sdbusplus::bus::new_default(); 63 64 using namespace settings; 65 Objects settings(bus); 66 67 using namespace phosphor::state::manager; 68 namespace server = sdbusplus::xyz::openbmc_project::State::server; 69 70 // This application is only run if chassis power is off 71 72 // If the BMC was rebooted due to a user initiated pinhole reset, do not 73 // implement any power restore policies 74 auto bmcRebootCause = phosphor::state::manager::utils::getProperty( 75 bus, "/xyz/openbmc_project/state/bmc0", BMC_BUSNAME, "LastRebootCause"); 76 if (bmcRebootCause == 77 "xyz.openbmc_project.State.BMC.RebootCause.PinholeReset") 78 { 79 info( 80 "BMC was reset due to pinhole reset, no power restore policy will be run"); 81 return 0; 82 } 83 84 /* The logic here is to first check the one-time PowerRestorePolicy setting. 85 * If this property is not the default then look at the persistent 86 * user setting in the non one-time object, otherwise honor the one-time 87 * setting. 88 */ 89 auto methodOneTime = bus.new_method_call( 90 settings.service(settings.powerRestorePolicy, powerRestoreIntf).c_str(), 91 settings.powerRestorePolicyOneTime.c_str(), 92 "org.freedesktop.DBus.Properties", "Get"); 93 methodOneTime.append(powerRestoreIntf, "PowerRestorePolicy"); 94 95 auto methodUserSetting = bus.new_method_call( 96 settings.service(settings.powerRestorePolicy, powerRestoreIntf).c_str(), 97 settings.powerRestorePolicy.c_str(), "org.freedesktop.DBus.Properties", 98 "Get"); 99 methodUserSetting.append(powerRestoreIntf, "PowerRestorePolicy"); 100 101 std::variant<std::string> result; 102 try 103 { 104 auto reply = bus.call(methodOneTime); 105 reply.read(result); 106 auto powerPolicy = std::get<std::string>(result); 107 108 if (RestorePolicy::Policy::None == 109 RestorePolicy::convertPolicyFromString(powerPolicy)) 110 { 111 // one_time is set to None so use the customer setting 112 info("One time not set, check user setting of power policy"); 113 auto reply = bus.call(methodUserSetting); 114 reply.read(result); 115 powerPolicy = std::get<std::string>(result); 116 } 117 else 118 { 119 // one_time setting was set so we're going to use it. Reset it 120 // to default for next time. 121 info("One time set, use it and reset to default"); 122 phosphor::state::manager::utils::setProperty( 123 bus, settings.powerRestorePolicyOneTime.c_str(), 124 powerRestoreIntf, "PowerRestorePolicy", 125 convertForMessage(RestorePolicy::Policy::None)); 126 } 127 128 info("Host power is off, processing power policy {POWER_POLICY}", 129 "POWER_POLICY", powerPolicy); 130 131 if (RestorePolicy::Policy::AlwaysOn == 132 RestorePolicy::convertPolicyFromString(powerPolicy)) 133 { 134 info("power_policy=ALWAYS_POWER_ON, powering host on"); 135 phosphor::state::manager::utils::setProperty( 136 bus, hostPath, HOST_BUSNAME, "RestartCause", 137 convertForMessage( 138 server::Host::RestartCause::PowerPolicyAlwaysOn)); 139 phosphor::state::manager::utils::setProperty( 140 bus, hostPath, HOST_BUSNAME, "RequestedHostTransition", 141 convertForMessage(server::Host::Transition::On)); 142 } 143 else if (RestorePolicy::Policy::AlwaysOff == 144 RestorePolicy::convertPolicyFromString(powerPolicy)) 145 { 146 info("power_policy=ALWAYS_POWER_OFF, set requested state to off"); 147 // Read last requested state and re-request it to execute it 148 auto hostReqState = phosphor::state::manager::utils::getProperty( 149 bus, hostPath, HOST_BUSNAME, "RequestedHostTransition"); 150 if (hostReqState == convertForMessage(server::Host::Transition::On)) 151 { 152 phosphor::state::manager::utils::setProperty( 153 bus, hostPath, HOST_BUSNAME, "RequestedHostTransition", 154 convertForMessage(server::Host::Transition::Off)); 155 } 156 } 157 else if (RestorePolicy::Policy::Restore == 158 RestorePolicy::convertPolicyFromString(powerPolicy)) 159 { 160 info("power_policy=RESTORE, restoring last state"); 161 // Read last requested state and re-request it to execute it 162 auto hostReqState = phosphor::state::manager::utils::getProperty( 163 bus, hostPath, HOST_BUSNAME, "RequestedHostTransition"); 164 if (hostReqState == convertForMessage(server::Host::Transition::On)) 165 { 166 phosphor::state::manager::utils::setProperty( 167 bus, hostPath, HOST_BUSNAME, "RestartCause", 168 convertForMessage( 169 server::Host::RestartCause::PowerPolicyPreviousState)); 170 phosphor::state::manager::utils::setProperty( 171 bus, hostPath, HOST_BUSNAME, "RequestedHostTransition", 172 hostReqState); 173 } 174 } 175 } 176 catch (const sdbusplus::exception::exception& e) 177 { 178 error("Error in PowerRestorePolicy Get: {ERROR}", "ERROR", e); 179 elog<InternalFailure>(); 180 } 181 182 return 0; 183 } 184