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