blob: 763781630f45306d5f69703180de7a18d7aa04e8 [file] [log] [blame]
Andrew Geisslere426b582020-05-28 12:40:55 -05001#include "config.h"
2
3#include "host_state_manager.hpp"
4
Andrew Geissler0d1c3f12021-07-27 16:21:01 -04005#include "host_check.hpp"
Andrew Geissler1ab2b6c2022-03-10 16:16:15 -06006#include "utils.hpp"
Andrew Geissler0d1c3f12021-07-27 16:21:01 -04007
Andrew Geisslere426b582020-05-28 12:40:55 -05008#include <systemd/sd-bus.h>
9
10#include <cereal/archives/json.hpp>
11#include <cereal/cereal.hpp>
12#include <cereal/types/string.hpp>
13#include <cereal/types/tuple.hpp>
14#include <cereal/types/vector.hpp>
15#include <phosphor-logging/elog-errors.hpp>
Andrew Geissler8ffdb262021-09-20 15:25:19 -050016#include <phosphor-logging/lg2.hpp>
Andrew Geisslere426b582020-05-28 12:40:55 -050017#include <sdbusplus/exception.hpp>
18#include <sdbusplus/server.hpp>
19#include <xyz/openbmc_project/Common/error.hpp>
20#include <xyz/openbmc_project/Control/Power/RestorePolicy/server.hpp>
Andrew Geissler765446a2023-05-25 15:38:20 -040021#include <xyz/openbmc_project/State/Host/error.hpp>
Andrew Geisslere426b582020-05-28 12:40:55 -050022
Andrew Geissler4ccaeaa2025-10-14 09:08:29 -050023#include <chrono>
Andrew Geissler131d04a2021-03-12 11:02:41 -060024#include <filesystem>
Patrick Williams78c066f2024-02-13 12:25:58 -060025#include <format>
Andrew Geisslere426b582020-05-28 12:40:55 -050026#include <fstream>
Andrew Geissler36529022016-11-29 15:23:54 -060027#include <iostream>
Andrew Geissler0cd2eaf2016-12-07 10:50:13 -060028#include <map>
Andrew Geissler54ce6392024-02-23 10:09:09 -060029#include <set>
Andrew Geissler0cd2eaf2016-12-07 10:50:13 -060030#include <string>
Dhruvaraj Subhashchandran3f475242017-07-12 00:44:27 -050031
Vishwanatha Subbanna0a838732017-10-05 12:43:19 +053032// Register class version with Cereal
Andrew Geissler769a62f2019-12-06 13:36:08 -060033CEREAL_CLASS_VERSION(phosphor::state::manager::Host, CLASS_VERSION)
Andrew Geissler36529022016-11-29 15:23:54 -060034
35namespace phosphor
36{
37namespace state
38{
39namespace manager
40{
41
Andrew Geissler8ffdb262021-09-20 15:25:19 -050042PHOSPHOR_LOG2_USING;
43
Andrew Geissler7b90a622017-08-08 11:41:08 -050044// When you see server:: or reboot:: you know we're referencing our base class
Patrick Williams7e969cb2023-08-23 16:24:23 -050045namespace server = sdbusplus::server::xyz::openbmc_project::state;
46namespace reboot = sdbusplus::server::xyz::openbmc_project::control::boot;
47namespace bootprogress = sdbusplus::server::xyz::openbmc_project::state::boot;
Dhruvaraj Subhashchandrana3b8d7e2017-08-10 05:40:04 -050048namespace osstatus =
Patrick Williams7e969cb2023-08-23 16:24:23 -050049 sdbusplus::server::xyz::openbmc_project::state::operating_system;
Andrew Geissler1e3bf942016-12-13 15:32:22 -060050using namespace phosphor::logging;
Patrick Williams6ed41ea2022-04-05 15:50:21 -050051namespace fs = std::filesystem;
Andrew Geissler2f60aae2019-09-12 13:25:21 -050052using sdbusplus::xyz::openbmc_project::Common::Error::InternalFailure;
Andrew Geissler1e3bf942016-12-13 15:32:22 -060053
Josh D. King929ef702017-03-02 10:58:11 -060054constexpr auto ACTIVE_STATE = "active";
55constexpr auto ACTIVATING_STATE = "activating";
56
Andrew Geissler58a18012018-01-19 19:36:05 -080057constexpr auto SYSTEMD_SERVICE = "org.freedesktop.systemd1";
58constexpr auto SYSTEMD_OBJ_PATH = "/org/freedesktop/systemd1";
Andrew Geissler0cd2eaf2016-12-07 10:50:13 -060059constexpr auto SYSTEMD_INTERFACE = "org.freedesktop.systemd1.Manager";
60
Josh D. King929ef702017-03-02 10:58:11 -060061constexpr auto SYSTEMD_PROPERTY_IFACE = "org.freedesktop.DBus.Properties";
62constexpr auto SYSTEMD_INTERFACE_UNIT = "org.freedesktop.systemd1.Unit";
63
Andrew Geissleref3c1842016-12-01 12:33:09 -060064void Host::determineInitialState()
65{
Allen.Wang79b45002022-02-10 17:59:20 +080066 if (stateActive(getTarget(server::Host::HostState::Running)) ||
Potin Lai70f36d82022-03-15 10:25:39 +080067 isHostRunning(id))
Andrew Geissleref3c1842016-12-01 12:33:09 -060068 {
Andrew Geissler8ffdb262021-09-20 15:25:19 -050069 info("Initial Host State will be Running");
Peter Yin73d7ad02024-03-14 13:41:11 +080070 server::Host::currentHostState(HostState::Running, true);
71 server::Host::requestedHostTransition(Transition::On, true);
Andrew Geissleref3c1842016-12-01 12:33:09 -060072 }
73 else
74 {
Andrew Geissler8ffdb262021-09-20 15:25:19 -050075 info("Initial Host State will be Off");
Peter Yin73d7ad02024-03-14 13:41:11 +080076 server::Host::currentHostState(HostState::Off, true);
77 server::Host::requestedHostTransition(Transition::Off, true);
Andrew Geissleref3c1842016-12-01 12:33:09 -060078 }
79
Allen.Wangba182f02022-03-23 19:01:53 +080080 if (!deserialize())
Dhruvaraj Subhashchandran3f475242017-07-12 00:44:27 -050081 {
Andrew Geissler58a18012018-01-19 19:36:05 -080082 // set to default value.
Peter Yin73d7ad02024-03-14 13:41:11 +080083 server::Host::requestedHostTransition(Transition::Off, true);
Dhruvaraj Subhashchandran3f475242017-07-12 00:44:27 -050084 }
Andrew Geissleref3c1842016-12-01 12:33:09 -060085 return;
86}
87
Andrew Geissler54ce6392024-02-23 10:09:09 -060088void Host::setupSupportedTransitions()
89{
90 std::set<Transition> supportedTransitions = {
Andrew Geissler31cddb72024-02-27 14:20:26 -060091 Transition::On,
92 Transition::Off,
93 Transition::Reboot,
94 Transition::GracefulWarmReboot,
95#if ENABLE_FORCE_WARM_REBOOT
96 Transition::ForceWarmReboot,
97#endif
98 };
Andrew Geissler54ce6392024-02-23 10:09:09 -060099 server::Host::allowedHostTransitions(supportedTransitions);
100}
101
Allen.Wang79b45002022-02-10 17:59:20 +0800102void Host::createSystemdTargetMaps()
103{
104 stateTargetTable = {
Patrick Williams78c066f2024-02-13 12:25:58 -0600105 {HostState::Off, std::format("obmc-host-stop@{}.target", id)},
106 {HostState::Running, std::format("obmc-host-startmin@{}.target", id)},
107 {HostState::Quiesced, std::format("obmc-host-quiesce@{}.target", id)},
Allen.Wang79b45002022-02-10 17:59:20 +0800108 {HostState::DiagnosticMode,
Patrick Williams78c066f2024-02-13 12:25:58 -0600109 std::format("obmc-host-diagnostic-mode@{}.target", id)}};
Allen.Wang79b45002022-02-10 17:59:20 +0800110
111 transitionTargetTable = {
Patrick Williams78c066f2024-02-13 12:25:58 -0600112 {Transition::Off, std::format("obmc-host-shutdown@{}.target", id)},
113 {Transition::On, std::format("obmc-host-start@{}.target", id)},
114 {Transition::Reboot, std::format("obmc-host-reboot@{}.target", id)},
Allen.Wang79b45002022-02-10 17:59:20 +0800115// Some systems do not support a warm reboot so just map the reboot
116// requests to our normal cold reboot in that case
117#if ENABLE_WARM_REBOOT
118 {Transition::GracefulWarmReboot,
Patrick Williams78c066f2024-02-13 12:25:58 -0600119 std::format("obmc-host-warm-reboot@{}.target", id)},
Allen.Wang79b45002022-02-10 17:59:20 +0800120 {Transition::ForceWarmReboot,
Patrick Williams1b2c3c02024-08-16 15:20:29 -0400121 std::format("obmc-host-force-warm-reboot@{}.target", id)}};
Allen.Wang79b45002022-02-10 17:59:20 +0800122#else
123 {Transition::GracefulWarmReboot,
Patrick Williams78c066f2024-02-13 12:25:58 -0600124 std::format("obmc-host-reboot@{}.target", id)},
Allen.Wang79b45002022-02-10 17:59:20 +0800125 {Transition::ForceWarmReboot,
Patrick Williams1b2c3c02024-08-16 15:20:29 -0400126 std::format("obmc-host-reboot@{}.target", id)}};
Allen.Wang79b45002022-02-10 17:59:20 +0800127#endif
Patrick Williams78c066f2024-02-13 12:25:58 -0600128 hostCrashTarget = std::format("obmc-host-crash@{}.target", id);
Allen.Wang79b45002022-02-10 17:59:20 +0800129}
130
131const std::string& Host::getTarget(HostState state)
132{
133 return stateTargetTable[state];
134};
135
136const std::string& Host::getTarget(Transition tranReq)
137{
138 return transitionTargetTable[tranReq];
139};
140
Andrew Geissler0cd2eaf2016-12-07 10:50:13 -0600141void Host::executeTransition(Transition tranReq)
142{
Pavithra Barithaya319eda42024-06-21 11:54:43 -0500143 const auto& sysdUnit = getTarget(tranReq);
Andrew Geissler0cd2eaf2016-12-07 10:50:13 -0600144
Andrew Geissler58a18012018-01-19 19:36:05 -0800145 auto method = this->bus.new_method_call(SYSTEMD_SERVICE, SYSTEMD_OBJ_PATH,
146 SYSTEMD_INTERFACE, "StartUnit");
Andrew Geissler0cd2eaf2016-12-07 10:50:13 -0600147
148 method.append(sysdUnit);
149 method.append("replace");
150
Andrew Geissler4da7e002017-01-24 15:21:40 -0600151 this->bus.call_noreply(method);
Andrew Geissler0cd2eaf2016-12-07 10:50:13 -0600152
153 return;
154}
155
Josh D. King929ef702017-03-02 10:58:11 -0600156bool Host::stateActive(const std::string& target)
157{
Patrick Williams2975e262020-05-13 18:01:09 -0500158 std::variant<std::string> currentState;
Josh D. King929ef702017-03-02 10:58:11 -0600159 sdbusplus::message::object_path unitTargetPath;
160
Andrew Geissler58a18012018-01-19 19:36:05 -0800161 auto method = this->bus.new_method_call(SYSTEMD_SERVICE, SYSTEMD_OBJ_PATH,
162 SYSTEMD_INTERFACE, "GetUnit");
Josh D. King929ef702017-03-02 10:58:11 -0600163
164 method.append(target);
Josh D. King929ef702017-03-02 10:58:11 -0600165
Anthony Wilson32c532e2018-10-25 21:56:07 -0500166 try
Josh D. King929ef702017-03-02 10:58:11 -0600167 {
Anthony Wilson32c532e2018-10-25 21:56:07 -0500168 auto result = this->bus.call(method);
169 result.read(unitTargetPath);
170 }
Patrick Williamsf053e6f2022-07-22 19:26:54 -0500171 catch (const sdbusplus::exception_t& e)
Anthony Wilson32c532e2018-10-25 21:56:07 -0500172 {
Andrew Geissler8ffdb262021-09-20 15:25:19 -0500173 error("Error in GetUnit call: {ERROR}", "ERROR", e);
Josh D. King929ef702017-03-02 10:58:11 -0600174 return false;
175 }
176
Andrew Geissler58a18012018-01-19 19:36:05 -0800177 method = this->bus.new_method_call(
178 SYSTEMD_SERVICE,
179 static_cast<const std::string&>(unitTargetPath).c_str(),
180 SYSTEMD_PROPERTY_IFACE, "Get");
Josh D. King929ef702017-03-02 10:58:11 -0600181
182 method.append(SYSTEMD_INTERFACE_UNIT, "ActiveState");
Josh D. King929ef702017-03-02 10:58:11 -0600183
Anthony Wilson32c532e2018-10-25 21:56:07 -0500184 try
Josh D. King929ef702017-03-02 10:58:11 -0600185 {
Anthony Wilson32c532e2018-10-25 21:56:07 -0500186 auto result = this->bus.call(method);
187 result.read(currentState);
188 }
Patrick Williamsf053e6f2022-07-22 19:26:54 -0500189 catch (const sdbusplus::exception_t& e)
Anthony Wilson32c532e2018-10-25 21:56:07 -0500190 {
Andrew Geissler8ffdb262021-09-20 15:25:19 -0500191 error("Error in ActiveState Get: {ERROR}", "ERROR", e);
Josh D. King929ef702017-03-02 10:58:11 -0600192 return false;
193 }
194
Patrick Williams37413dc2020-05-13 11:29:54 -0500195 const auto& currentStateStr = std::get<std::string>(currentState);
William A. Kennington III7a0689a2018-11-12 17:19:33 -0800196 return currentStateStr == ACTIVE_STATE ||
197 currentStateStr == ACTIVATING_STATE;
Josh D. King929ef702017-03-02 10:58:11 -0600198}
199
Michael Tritz206a8332017-02-06 16:01:23 -0600200bool Host::isAutoReboot()
201{
Deepak Kodihalli3dd08a52017-07-25 07:34:44 -0500202 using namespace settings;
Michael Tritz206a8332017-02-06 16:01:23 -0600203
Andrew Geissler7f620832020-10-23 08:25:52 -0500204 /* The logic here is to first check the one-time AutoReboot setting.
205 * If this property is true (the default) then look at the persistent
206 * user setting in the non one-time object, otherwise honor the one-time
207 * setting and do not auto reboot.
208 */
209 auto methodOneTime = bus.new_method_call(
Andrew Geissler58a18012018-01-19 19:36:05 -0800210 settings.service(settings.autoReboot, autoRebootIntf).c_str(),
Andrew Geissler7f620832020-10-23 08:25:52 -0500211 settings.autoRebootOneTime.c_str(), SYSTEMD_PROPERTY_IFACE, "Get");
212 methodOneTime.append(autoRebootIntf, "AutoReboot");
213
214 auto methodUserSetting = bus.new_method_call(
215 settings.service(settings.autoReboot, autoRebootIntf).c_str(),
216 settings.autoReboot.c_str(), SYSTEMD_PROPERTY_IFACE, "Get");
217 methodUserSetting.append(autoRebootIntf, "AutoReboot");
Michael Tritz206a8332017-02-06 16:01:23 -0600218
Anthony Wilson32c532e2018-10-25 21:56:07 -0500219 try
Michael Tritz206a8332017-02-06 16:01:23 -0600220 {
Andrew Geissler7f620832020-10-23 08:25:52 -0500221 auto reply = bus.call(methodOneTime);
Patrick Williams2975e262020-05-13 18:01:09 -0500222 std::variant<bool> result;
Anthony Wilson32c532e2018-10-25 21:56:07 -0500223 reply.read(result);
Patrick Williams37413dc2020-05-13 11:29:54 -0500224 auto autoReboot = std::get<bool>(result);
Andrew Geissler7f620832020-10-23 08:25:52 -0500225
226 if (!autoReboot)
227 {
Andrew Geissler8ffdb262021-09-20 15:25:19 -0500228 info("Auto reboot (one-time) disabled");
Andrew Geissler7f620832020-10-23 08:25:52 -0500229 return false;
230 }
231 else
232 {
233 // one-time is true so read the user setting
234 reply = bus.call(methodUserSetting);
235 reply.read(result);
236 autoReboot = std::get<bool>(result);
237 }
238
Anthony Wilson32c532e2018-10-25 21:56:07 -0500239 auto rebootCounterParam = reboot::RebootAttempts::attemptsLeft();
240
241 if (autoReboot)
Saqib Khancbe08d12017-03-10 01:29:20 -0600242 {
Anthony Wilson32c532e2018-10-25 21:56:07 -0500243 if (rebootCounterParam > 0)
244 {
245 // Reduce BOOTCOUNT by 1
Andrew Geisslerad65b2d2021-09-21 12:53:29 -0500246 info(
247 "Auto reboot enabled and boot count at {BOOTCOUNT}, rebooting",
248 "BOOTCOUNT", rebootCounterParam);
Anthony Wilson32c532e2018-10-25 21:56:07 -0500249 return true;
250 }
Anthony Wilson32c532e2018-10-25 21:56:07 -0500251 else
252 {
Andrew Geissler43284792021-09-23 10:32:15 -0500253 // We are at 0 so reset reboot counter and go to quiesce state
254 info("Auto reboot enabled but HOST BOOTCOUNT already set to 0");
NodeMan97b4cbfac2022-05-09 23:56:39 -0500255 attemptsLeft(reboot::RebootAttempts::retryAttempts());
Andrew Geissler1ab2b6c2022-03-10 16:16:15 -0600256
257 // Generate log since we will now be sitting in Quiesce
258 const std::string errorMsg =
259 "xyz.openbmc_project.State.Error.HostQuiesce";
260 utils::createError(this->bus, errorMsg,
261 sdbusplus::xyz::openbmc_project::Logging::
262 server::Entry::Level::Critical);
Andrew Geissler5bcaee12022-04-19 15:40:40 -0400263
264 // Generate BMC dump to assist with debug
265 utils::createBmcDump(this->bus);
266
Anthony Wilson32c532e2018-10-25 21:56:07 -0500267 return false;
268 }
Saqib Khand5ac6352017-04-04 09:53:59 -0500269 }
270 else
271 {
Andrew Geissler8ffdb262021-09-20 15:25:19 -0500272 info("Auto reboot disabled.");
Saqib Khancbe08d12017-03-10 01:29:20 -0600273 return false;
274 }
Michael Tritz206a8332017-02-06 16:01:23 -0600275 }
Patrick Williamsf053e6f2022-07-22 19:26:54 -0500276 catch (const sdbusplus::exception_t& e)
Saqib Khand5ac6352017-04-04 09:53:59 -0500277 {
Andrew Geissler8ffdb262021-09-20 15:25:19 -0500278 error("Error in AutoReboot Get, {ERROR}", "ERROR", e);
Saqib Khand5ac6352017-04-04 09:53:59 -0500279 return false;
280 }
Michael Tritz206a8332017-02-06 16:01:23 -0600281}
282
Patrick Williamsf053e6f2022-07-22 19:26:54 -0500283void Host::sysStateChangeJobRemoved(sdbusplus::message_t& msg)
Andrew Geissler4da7e002017-01-24 15:21:40 -0600284{
Andrew Geissler58a18012018-01-19 19:36:05 -0800285 uint32_t newStateID{};
Andrew Geissler4da7e002017-01-24 15:21:40 -0600286 sdbusplus::message::object_path newStateObjPath;
287 std::string newStateUnit{};
288 std::string newStateResult{};
289
Andrew Geissler58a18012018-01-19 19:36:05 -0800290 // Read the msg and populate each variable
Patrick Williamsd22706f2017-05-04 05:42:49 -0500291 msg.read(newStateID, newStateObjPath, newStateUnit, newStateResult);
Andrew Geissler4da7e002017-01-24 15:21:40 -0600292
Allen.Wang79b45002022-02-10 17:59:20 +0800293 if ((newStateUnit == getTarget(server::Host::HostState::Off)) &&
Andrew Geissler969b2612018-03-29 10:16:51 -0700294 (newStateResult == "done") &&
Allen.Wang79b45002022-02-10 17:59:20 +0800295 (!stateActive(getTarget(server::Host::HostState::Running))))
Andrew Geissleref621162016-12-08 12:56:21 -0600296 {
Andrew Geissler8ffdb262021-09-20 15:25:19 -0500297 info("Received signal that host is off");
Andrew Geissler4da7e002017-01-24 15:21:40 -0600298 this->currentHostState(server::Host::HostState::Off);
Dhruvaraj Subhashchandrana3b8d7e2017-08-10 05:40:04 -0500299 this->bootProgress(bootprogress::Progress::ProgressStages::Unspecified);
300 this->operatingSystemState(osstatus::Status::OSStatus::Inactive);
Andrew Geissleref621162016-12-08 12:56:21 -0600301 }
Allen.Wang79b45002022-02-10 17:59:20 +0800302 else if ((newStateUnit == getTarget(server::Host::HostState::Running)) &&
Andrew Geissler58a18012018-01-19 19:36:05 -0800303 (newStateResult == "done") &&
Allen.Wang79b45002022-02-10 17:59:20 +0800304 (stateActive(getTarget(server::Host::HostState::Running))))
Andrew Geissler58a18012018-01-19 19:36:05 -0800305 {
Andrew Geissler8ffdb262021-09-20 15:25:19 -0500306 info("Received signal that host is running");
Andrew Geissler58a18012018-01-19 19:36:05 -0800307 this->currentHostState(server::Host::HostState::Running);
Andrew Geissler131d04a2021-03-12 11:02:41 -0600308
309 // Remove temporary file which is utilized for scenarios where the
310 // BMC is rebooted while the host is still up.
311 // This file is used to indicate to host related systemd services
312 // that the host is already running and they should skip running.
313 // Once the host state is back to running we can clear this file.
Patrick Williams78c066f2024-02-13 12:25:58 -0600314 std::string hostFile = std::format(HOST_RUNNING_FILE, 0);
315 if (std::filesystem::exists(hostFile))
Andrew Geissler131d04a2021-03-12 11:02:41 -0600316 {
Patrick Williams78c066f2024-02-13 12:25:58 -0600317 std::filesystem::remove(hostFile);
Andrew Geissler131d04a2021-03-12 11:02:41 -0600318 }
Andrew Geissler58a18012018-01-19 19:36:05 -0800319 }
Allen.Wang79b45002022-02-10 17:59:20 +0800320 else if ((newStateUnit == getTarget(server::Host::HostState::Quiesced)) &&
Josh D. King29d025d2017-04-27 12:40:22 -0500321 (newStateResult == "done") &&
Allen.Wang79b45002022-02-10 17:59:20 +0800322 (stateActive(getTarget(server::Host::HostState::Quiesced))))
Andrew Geissler58a18012018-01-19 19:36:05 -0800323 {
324 if (Host::isAutoReboot())
325 {
Andrew Geissler8ffdb262021-09-20 15:25:19 -0500326 info("Beginning reboot...");
Andrew Geissler58a18012018-01-19 19:36:05 -0800327 Host::requestedHostTransition(server::Host::Transition::Reboot);
328 }
329 else
330 {
Andrew Geissler8ffdb262021-09-20 15:25:19 -0500331 info("Maintaining quiesce");
Andrew Geissler58a18012018-01-19 19:36:05 -0800332 this->currentHostState(server::Host::HostState::Quiesced);
333 }
334 }
Andrew Geissleref621162016-12-08 12:56:21 -0600335}
336
Patrick Williamsf053e6f2022-07-22 19:26:54 -0500337void Host::sysStateChangeJobNew(sdbusplus::message_t& msg)
Andrew Geissler47b96122020-02-11 16:13:13 -0600338{
339 uint32_t newStateID{};
340 sdbusplus::message::object_path newStateObjPath;
341 std::string newStateUnit{};
342
343 // Read the msg and populate each variable
344 msg.read(newStateID, newStateObjPath, newStateUnit);
345
Allen.Wang79b45002022-02-10 17:59:20 +0800346 if (newStateUnit == getTarget(server::Host::HostState::DiagnosticMode))
Andrew Geissler47b96122020-02-11 16:13:13 -0600347 {
Andrew Geissler8ffdb262021-09-20 15:25:19 -0500348 info("Received signal that host is in diagnostice mode");
Andrew Geissler47b96122020-02-11 16:13:13 -0600349 this->currentHostState(server::Host::HostState::DiagnosticMode);
350 }
Andrew Geissler128ea8e2022-06-22 12:28:15 -0400351 else if ((newStateUnit == hostCrashTarget) &&
352 (server::Host::currentHostState() ==
353 server::Host::HostState::Running))
354 {
355 // Only decrease the boot count if host was running when the host crash
356 // target was started. Systemd will sometimes trigger multiple
357 // JobNew events for the same target. This seems to be related to
358 // how OpenBMC utilizes the targets in the reboot scenario
359 info("Received signal that host has crashed, decrement reboot count");
360
361 // A host crash can cause a reboot of the host so decrement the reboot
362 // count
363 decrementRebootCount();
364 }
Andrew Geissler47b96122020-02-11 16:13:13 -0600365}
366
Andrew Geissler7b90a622017-08-08 11:41:08 -0500367uint32_t Host::decrementRebootCount()
368{
369 auto rebootCount = reboot::RebootAttempts::attemptsLeft();
Andrew Geissler58a18012018-01-19 19:36:05 -0800370 if (rebootCount > 0)
Andrew Geissler7b90a622017-08-08 11:41:08 -0500371 {
Andrew Geissler58a18012018-01-19 19:36:05 -0800372 return (reboot::RebootAttempts::attemptsLeft(rebootCount - 1));
Andrew Geissler7b90a622017-08-08 11:41:08 -0500373 }
374 return rebootCount;
375}
376
Allen.Wangba182f02022-03-23 19:01:53 +0800377fs::path Host::serialize()
Andrew Geissler033fc3b2017-08-30 15:11:44 -0500378{
Patrick Williams78c066f2024-02-13 12:25:58 -0600379 fs::path path{std::format(HOST_STATE_PERSIST_PATH, id)};
Allen.Wangba182f02022-03-23 19:01:53 +0800380 std::ofstream os(path.c_str(), std::ios::binary);
Andrew Geissler033fc3b2017-08-30 15:11:44 -0500381 cereal::JSONOutputArchive oarchive(os);
382 oarchive(*this);
Allen.Wangba182f02022-03-23 19:01:53 +0800383 return path;
Andrew Geissler033fc3b2017-08-30 15:11:44 -0500384}
385
Allen.Wangba182f02022-03-23 19:01:53 +0800386bool Host::deserialize()
Andrew Geissler033fc3b2017-08-30 15:11:44 -0500387{
Patrick Williams78c066f2024-02-13 12:25:58 -0600388 fs::path path{std::format(HOST_STATE_PERSIST_PATH, id)};
Jayanth Othayothe39f3792017-09-19 23:53:31 -0500389 try
Andrew Geissler033fc3b2017-08-30 15:11:44 -0500390 {
Jayanth Othayothe39f3792017-09-19 23:53:31 -0500391 if (fs::exists(path))
392 {
393 std::ifstream is(path.c_str(), std::ios::in | std::ios::binary);
394 cereal::JSONInputArchive iarchive(is);
395 iarchive(*this);
396 return true;
397 }
398 return false;
Andrew Geissler033fc3b2017-08-30 15:11:44 -0500399 }
Patrick Williams8583b3b2021-10-06 12:19:20 -0500400 catch (const cereal::Exception& e)
Jayanth Othayothe39f3792017-09-19 23:53:31 -0500401 {
Andrew Geissler8ffdb262021-09-20 15:25:19 -0500402 error("deserialize exception: {ERROR}", "ERROR", e);
Jayanth Othayothe39f3792017-09-19 23:53:31 -0500403 fs::remove(path);
404 return false;
405 }
Andrew Geissler033fc3b2017-08-30 15:11:44 -0500406}
407
Andrew Geissleref3c1842016-12-01 12:33:09 -0600408Host::Transition Host::requestedHostTransition(Transition value)
409{
Zoey YJ Chung840ac402025-08-29 13:09:01 +0800410 info("Host{HOST_ID} state transition request of {REQ}", "HOST_ID", id,
411 "REQ", value);
Andrew Geissler765446a2023-05-25 15:38:20 -0400412
413#if ONLY_ALLOW_BOOT_WHEN_BMC_READY
414 if ((value != Transition::Off) && (!utils::isBmcReady(this->bus)))
415 {
416 info("BMC State is not Ready so no host on operations allowed");
417 throw sdbusplus::xyz::openbmc_project::State::Host::Error::
418 BMCNotReady();
419 }
420#endif
421
Andrew Geissler7b90a622017-08-08 11:41:08 -0500422 // If this is not a power off request then we need to
423 // decrement the reboot counter. This code should
424 // never prevent a power on, it should just decrement
425 // the count to 0. The quiesce handling is where the
426 // check of this count will occur
Andrew Geissler58a18012018-01-19 19:36:05 -0800427 if (value != server::Host::Transition::Off)
Andrew Geissler7b90a622017-08-08 11:41:08 -0500428 {
Thang Tran9f381522024-10-18 10:11:01 +0700429#ifdef CHECK_FWUPDATE_BEFORE_DO_TRANSITION
430 /*
431 * Do not do transition when the any firmware being updated
432 */
433 if (phosphor::state::manager::utils::isFirmwareUpdating(this->bus))
434 {
435 info("Firmware being updated, reject the transition request");
436 throw sdbusplus::xyz::openbmc_project::Common::Error::Unavailable();
437 }
438#endif // CHECK_FWUPDATE_BEFORE_DO_TRANSITION
439
Andrew Geissler7b90a622017-08-08 11:41:08 -0500440 decrementRebootCount();
441 }
442
Andrew Geisslera27a6e82017-07-27 16:44:43 -0500443 executeTransition(value);
Andrew Geissler7b90a622017-08-08 11:41:08 -0500444
Andrew Geissler58a18012018-01-19 19:36:05 -0800445 auto retVal = server::Host::requestedHostTransition(value);
Allen.Wangba182f02022-03-23 19:01:53 +0800446
Andrew Geissler033fc3b2017-08-30 15:11:44 -0500447 serialize();
Dhruvaraj Subhashchandran3f475242017-07-12 00:44:27 -0500448 return retVal;
Andrew Geissleref3c1842016-12-01 12:33:09 -0600449}
450
Dhruvaraj Subhashchandran4e6534f2017-09-19 06:13:20 -0500451Host::ProgressStages Host::bootProgress(ProgressStages value)
452{
453 auto retVal = bootprogress::Progress::bootProgress(value);
Andrew Geissler4ccaeaa2025-10-14 09:08:29 -0500454
455 // Update the BootProgressLastUpdate anytime BootProgress is updated
456 auto timeStamp = std::chrono::duration_cast<std::chrono::microseconds>(
457 std::chrono::system_clock::now().time_since_epoch())
458 .count();
459 this->bootProgressLastUpdate(timeStamp);
460 serialize();
461 return retVal;
462}
463
464uint64_t Host::bootProgressLastUpdate(uint64_t value)
465{
466 auto retVal = bootprogress::Progress::bootProgressLastUpdate(value);
Dhruvaraj Subhashchandran4e6534f2017-09-19 06:13:20 -0500467 serialize();
468 return retVal;
469}
470
471Host::OSStatus Host::operatingSystemState(OSStatus value)
472{
473 auto retVal = osstatus::Status::operatingSystemState(value);
474 serialize();
475 return retVal;
476}
477
Andrew Geissleref3c1842016-12-01 12:33:09 -0600478Host::HostState Host::currentHostState(HostState value)
479{
Zoey YJ Chung840ac402025-08-29 13:09:01 +0800480 info("Change to Host{HOST_ID} State: {STATE}", "HOST_ID", id, "STATE",
481 value);
Andrew Geissleref621162016-12-08 12:56:21 -0600482 return server::Host::currentHostState(value);
Andrew Geissleref3c1842016-12-01 12:33:09 -0600483}
484
Andrew Geissler36529022016-11-29 15:23:54 -0600485} // namespace manager
486} // namespace state
Andrew Geisslera965cf02018-08-31 08:37:05 -0700487} // namespace phosphor