xref: /openbmc/phosphor-state-manager/utils.cpp (revision 9f38152abf80aba2f0177cb55729ff107f54947d)
127d1e14cSNodeMan97 #include "config.h"
227d1e14cSNodeMan97 
3dc059399SCarol Wang #include "utils.hpp"
4dc059399SCarol Wang 
5f8ae6a02SAndrew Geissler #include <gpiod.h>
6f8ae6a02SAndrew Geissler 
78ffdb269SAndrew Geissler #include <phosphor-logging/lg2.hpp>
89a286db2SPatrick Williams #include <xyz/openbmc_project/Dump/Create/client.hpp>
99a286db2SPatrick Williams #include <xyz/openbmc_project/Logging/Create/client.hpp>
109a286db2SPatrick Williams #include <xyz/openbmc_project/ObjectMapper/client.hpp>
11*9f38152aSThang Tran #include <xyz/openbmc_project/Software/ActivationBlocksTransition/client.hpp>
129a286db2SPatrick Williams #include <xyz/openbmc_project/State/BMC/client.hpp>
13dc059399SCarol Wang 
1448a4e5e5SAndrew Geissler #include <chrono>
1527d1e14cSNodeMan97 #include <filesystem>
1678c066f6SPatrick Williams #include <format>
1727d1e14cSNodeMan97 
18dc059399SCarol Wang namespace phosphor
19dc059399SCarol Wang {
20dc059399SCarol Wang namespace state
21dc059399SCarol Wang {
22dc059399SCarol Wang namespace manager
23dc059399SCarol Wang {
24dc059399SCarol Wang namespace utils
25dc059399SCarol Wang {
26dc059399SCarol Wang 
2748a4e5e5SAndrew Geissler using namespace std::literals::chrono_literals;
2848a4e5e5SAndrew Geissler 
298ffdb269SAndrew Geissler PHOSPHOR_LOG2_USING;
30dc059399SCarol Wang 
31928bbf15SAndrew Geissler constexpr auto SYSTEMD_SERVICE = "org.freedesktop.systemd1";
32928bbf15SAndrew Geissler constexpr auto SYSTEMD_OBJ_PATH = "/org/freedesktop/systemd1";
33928bbf15SAndrew Geissler constexpr auto SYSTEMD_INTERFACE = "org.freedesktop.systemd1.Manager";
34dc059399SCarol Wang constexpr auto PROPERTY_INTERFACE = "org.freedesktop.DBus.Properties";
35dc059399SCarol Wang 
369a286db2SPatrick Williams using ObjectMapper = sdbusplus::client::xyz::openbmc_project::ObjectMapper<>;
37*9f38152aSThang Tran using ActBlockTrans = sdbusplus::client::xyz::openbmc_project::software::
38*9f38152aSThang Tran     ActivationBlocksTransition<>;
399a286db2SPatrick Williams 
subscribeToSystemdSignals(sdbusplus::bus_t & bus)405c4a0822SPatrick Williams void subscribeToSystemdSignals(sdbusplus::bus_t& bus)
41928bbf15SAndrew Geissler {
42928bbf15SAndrew Geissler     auto method = bus.new_method_call(SYSTEMD_SERVICE, SYSTEMD_OBJ_PATH,
43928bbf15SAndrew Geissler                                       SYSTEMD_INTERFACE, "Subscribe");
44928bbf15SAndrew Geissler 
45928bbf15SAndrew Geissler     try
46928bbf15SAndrew Geissler     {
4748a4e5e5SAndrew Geissler         // On OpenBMC based systems, systemd has had a few situations where it
4848a4e5e5SAndrew Geissler         // has been unable to respond to this call within the default d-bus
4948a4e5e5SAndrew Geissler         // timeout of 25 seconds. This is due to the large amount of work being
5048a4e5e5SAndrew Geissler         // done by systemd during OpenBMC startup. Set the timeout for this call
5148a4e5e5SAndrew Geissler         // to 60 seconds (worst case seen was around 30s so double it).
5248a4e5e5SAndrew Geissler         bus.call(method, 60s);
53928bbf15SAndrew Geissler     }
54928bbf15SAndrew Geissler     catch (const sdbusplus::exception_t& e)
55928bbf15SAndrew Geissler     {
56928bbf15SAndrew Geissler         error("Failed to subscribe to systemd signals: {ERROR}", "ERROR", e);
57928bbf15SAndrew Geissler         throw std::runtime_error("Unable to subscribe to systemd signals");
58928bbf15SAndrew Geissler     }
59928bbf15SAndrew Geissler     return;
60928bbf15SAndrew Geissler }
61928bbf15SAndrew Geissler 
getService(sdbusplus::bus_t & bus,std::string path,std::string interface)625c4a0822SPatrick Williams std::string getService(sdbusplus::bus_t& bus, std::string path,
63dc059399SCarol Wang                        std::string interface)
64dc059399SCarol Wang {
659a286db2SPatrick Williams     auto mapper = bus.new_method_call(ObjectMapper::default_service,
669a286db2SPatrick Williams                                       ObjectMapper::instance_path,
679a286db2SPatrick Williams                                       ObjectMapper::interface, "GetObject");
68dc059399SCarol Wang 
69dc059399SCarol Wang     mapper.append(path, std::vector<std::string>({interface}));
70dc059399SCarol Wang 
71dc059399SCarol Wang     std::vector<std::pair<std::string, std::vector<std::string>>>
72dc059399SCarol Wang         mapperResponse;
73dc059399SCarol Wang 
74dc059399SCarol Wang     try
75dc059399SCarol Wang     {
76dc059399SCarol Wang         auto mapperResponseMsg = bus.call(mapper);
77dc059399SCarol Wang 
78dc059399SCarol Wang         mapperResponseMsg.read(mapperResponse);
79dc059399SCarol Wang         if (mapperResponse.empty())
80dc059399SCarol Wang         {
81ad65b2d6SAndrew Geissler             error(
82ad65b2d6SAndrew Geissler                 "Error no matching service with path {PATH} and interface {INTERFACE}",
838ffdb269SAndrew Geissler                 "PATH", path, "INTERFACE", interface);
84dc059399SCarol Wang             throw std::runtime_error("Error no matching service");
85dc059399SCarol Wang         }
86dc059399SCarol Wang     }
87f053e6feSPatrick Williams     catch (const sdbusplus::exception_t& e)
88dc059399SCarol Wang     {
898ffdb269SAndrew Geissler         error("Error in mapper call with path {PATH}, interface "
908ffdb269SAndrew Geissler               "{INTERFACE}, and exception {ERROR}",
918ffdb269SAndrew Geissler               "PATH", path, "INTERFACE", interface, "ERROR", e);
92dc059399SCarol Wang         throw;
93dc059399SCarol Wang     }
94dc059399SCarol Wang 
95dc059399SCarol Wang     return mapperResponse.begin()->first;
96dc059399SCarol Wang }
97dc059399SCarol Wang 
getProperty(sdbusplus::bus_t & bus,const std::string & path,const std::string & interface,const std::string & propertyName)98f053e6feSPatrick Williams std::string getProperty(sdbusplus::bus_t& bus, const std::string& path,
9949e6713aSAndrew Geissler                         const std::string& interface,
10049e6713aSAndrew Geissler                         const std::string& propertyName)
10149e6713aSAndrew Geissler {
10249e6713aSAndrew Geissler     std::variant<std::string> property;
10349e6713aSAndrew Geissler     std::string service = getService(bus, path, interface);
10449e6713aSAndrew Geissler 
10549e6713aSAndrew Geissler     auto method = bus.new_method_call(service.c_str(), path.c_str(),
10649e6713aSAndrew Geissler                                       PROPERTY_INTERFACE, "Get");
10749e6713aSAndrew Geissler 
10849e6713aSAndrew Geissler     method.append(interface, propertyName);
10949e6713aSAndrew Geissler 
11049e6713aSAndrew Geissler     try
11149e6713aSAndrew Geissler     {
11249e6713aSAndrew Geissler         auto reply = bus.call(method);
11349e6713aSAndrew Geissler         reply.read(property);
11449e6713aSAndrew Geissler     }
115f053e6feSPatrick Williams     catch (const sdbusplus::exception_t& e)
11649e6713aSAndrew Geissler     {
11749e6713aSAndrew Geissler         error("Error in property Get, error {ERROR}, property {PROPERTY}",
11849e6713aSAndrew Geissler               "ERROR", e, "PROPERTY", propertyName);
11949e6713aSAndrew Geissler         throw;
12049e6713aSAndrew Geissler     }
12149e6713aSAndrew Geissler 
12249e6713aSAndrew Geissler     if (std::get<std::string>(property).empty())
12349e6713aSAndrew Geissler     {
12449e6713aSAndrew Geissler         error("Error reading property response for {PROPERTY}", "PROPERTY",
12549e6713aSAndrew Geissler               propertyName);
12649e6713aSAndrew Geissler         throw std::runtime_error("Error reading property response");
12749e6713aSAndrew Geissler     }
12849e6713aSAndrew Geissler 
12949e6713aSAndrew Geissler     return std::get<std::string>(property);
13049e6713aSAndrew Geissler }
13149e6713aSAndrew Geissler 
setProperty(sdbusplus::bus_t & bus,const std::string & path,const std::string & interface,const std::string & property,const std::string & value)132f053e6feSPatrick Williams void setProperty(sdbusplus::bus_t& bus, const std::string& path,
133dc059399SCarol Wang                  const std::string& interface, const std::string& property,
134dc059399SCarol Wang                  const std::string& value)
135dc059399SCarol Wang {
1362975e26fSPatrick Williams     std::variant<std::string> variantValue = value;
137dc059399SCarol Wang     std::string service = getService(bus, path, interface);
138dc059399SCarol Wang 
139dc059399SCarol Wang     auto method = bus.new_method_call(service.c_str(), path.c_str(),
140dc059399SCarol Wang                                       PROPERTY_INTERFACE, "Set");
141dc059399SCarol Wang 
142dc059399SCarol Wang     method.append(interface, property, variantValue);
143dc059399SCarol Wang     bus.call_noreply(method);
144dc059399SCarol Wang 
145dc059399SCarol Wang     return;
146dc059399SCarol Wang }
147dc059399SCarol Wang 
getGpioValue(const std::string & gpioName)148f8ae6a02SAndrew Geissler int getGpioValue(const std::string& gpioName)
149f8ae6a02SAndrew Geissler {
150f8ae6a02SAndrew Geissler     int gpioval = -1;
151f8ae6a02SAndrew Geissler     gpiod_line* line = gpiod_line_find(gpioName.c_str());
152f8ae6a02SAndrew Geissler 
153f8ae6a02SAndrew Geissler     if (nullptr != line)
154f8ae6a02SAndrew Geissler     {
155f8ae6a02SAndrew Geissler         // take ownership of gpio
156f8ae6a02SAndrew Geissler         if (0 != gpiod_line_request_input(line, "state-manager"))
157f8ae6a02SAndrew Geissler         {
158f8ae6a02SAndrew Geissler             error("Failed request for {GPIO_NAME} GPIO", "GPIO_NAME", gpioName);
159f8ae6a02SAndrew Geissler         }
160f8ae6a02SAndrew Geissler         else
161f8ae6a02SAndrew Geissler         {
162f8ae6a02SAndrew Geissler             // get gpio value
163f8ae6a02SAndrew Geissler             gpioval = gpiod_line_get_value(line);
164f8ae6a02SAndrew Geissler 
165f8ae6a02SAndrew Geissler             // release ownership of gpio
166f8ae6a02SAndrew Geissler             gpiod_line_close_chip(line);
167f8ae6a02SAndrew Geissler         }
168f8ae6a02SAndrew Geissler     }
169f8ae6a02SAndrew Geissler     return gpioval;
170f8ae6a02SAndrew Geissler }
171f8ae6a02SAndrew Geissler 
createError(sdbusplus::bus_t & bus,const std::string & errorMsg,sdbusplus::server::xyz::openbmc_project::logging::Entry::Level errLevel,std::map<std::string,std::string> additionalData)1729d4d0c91SAndrew Geissler void createError(
173f053e6feSPatrick Williams     sdbusplus::bus_t& bus, const std::string& errorMsg,
1747e969cb9SPatrick Williams     sdbusplus::server::xyz::openbmc_project::logging::Entry::Level errLevel,
175d49f51edSAndrew Geissler     std::map<std::string, std::string> additionalData)
1769d4d0c91SAndrew Geissler {
1779d4d0c91SAndrew Geissler     try
1789d4d0c91SAndrew Geissler     {
179d49f51edSAndrew Geissler         // Always add the _PID on for some extra logging debug
1809d4d0c91SAndrew Geissler         additionalData.emplace("_PID", std::to_string(getpid()));
1819d4d0c91SAndrew Geissler 
1829a286db2SPatrick Williams         using LoggingCreate =
1839a286db2SPatrick Williams             sdbusplus::client::xyz::openbmc_project::logging::Create<>;
1849a286db2SPatrick Williams 
1859a286db2SPatrick Williams         auto method = bus.new_method_call(LoggingCreate::default_service,
1869a286db2SPatrick Williams                                           LoggingCreate::instance_path,
1879a286db2SPatrick Williams                                           LoggingCreate::interface, "Create");
1889d4d0c91SAndrew Geissler 
1899d4d0c91SAndrew Geissler         method.append(errorMsg, errLevel, additionalData);
1909d4d0c91SAndrew Geissler         auto resp = bus.call(method);
1919d4d0c91SAndrew Geissler     }
192f053e6feSPatrick Williams     catch (const sdbusplus::exception_t& e)
1939d4d0c91SAndrew Geissler     {
1949d4d0c91SAndrew Geissler         error("sdbusplus D-Bus call exception, error {ERROR} trying to create "
1959d4d0c91SAndrew Geissler               "an error with {ERROR_MSG}",
1969d4d0c91SAndrew Geissler               "ERROR", e, "ERROR_MSG", errorMsg);
1979d4d0c91SAndrew Geissler 
1989d4d0c91SAndrew Geissler         throw std::runtime_error(
1999d4d0c91SAndrew Geissler             "Error in invoking D-Bus logging create interface");
2009d4d0c91SAndrew Geissler     }
2019d4d0c91SAndrew Geissler     catch (const std::exception& e)
2029d4d0c91SAndrew Geissler     {
2039d4d0c91SAndrew Geissler         error("D-bus call exception: {ERROR}", "ERROR", e);
2049d4d0c91SAndrew Geissler         throw e;
2059d4d0c91SAndrew Geissler     }
2069d4d0c91SAndrew Geissler }
2079d4d0c91SAndrew Geissler 
createBmcDump(sdbusplus::bus_t & bus)208f053e6feSPatrick Williams void createBmcDump(sdbusplus::bus_t& bus)
20955e96ac5SAndrew Geissler {
2109a286db2SPatrick Williams     using DumpCreate = sdbusplus::client::xyz::openbmc_project::dump::Create<>;
2119a286db2SPatrick Williams     auto dumpPath =
2129a286db2SPatrick Williams         sdbusplus::message::object_path(DumpCreate::namespace_path::value) /
2139a286db2SPatrick Williams         DumpCreate::namespace_path::bmc;
2149a286db2SPatrick Williams 
2151b2c3c03SPatrick Williams     auto method =
2161b2c3c03SPatrick Williams         bus.new_method_call(DumpCreate::default_service, dumpPath.str.c_str(),
2179a286db2SPatrick Williams                             DumpCreate::interface, "CreateDump");
21855e96ac5SAndrew Geissler     method.append(
21955e96ac5SAndrew Geissler         std::vector<
22055e96ac5SAndrew Geissler             std::pair<std::string, std::variant<std::string, uint64_t>>>());
22155e96ac5SAndrew Geissler     try
22255e96ac5SAndrew Geissler     {
22355e96ac5SAndrew Geissler         bus.call_noreply(method);
22455e96ac5SAndrew Geissler     }
225f053e6feSPatrick Williams     catch (const sdbusplus::exception_t& e)
22655e96ac5SAndrew Geissler     {
22755e96ac5SAndrew Geissler         error("Failed to create BMC dump, exception:{ERROR}", "ERROR", e);
22855e96ac5SAndrew Geissler         // just continue, this is error path anyway so we're just collecting
22955e96ac5SAndrew Geissler         // what we can
23055e96ac5SAndrew Geissler     }
23155e96ac5SAndrew Geissler }
23255e96ac5SAndrew Geissler 
checkACLoss(size_t & chassisId)23327d1e14cSNodeMan97 bool checkACLoss(size_t& chassisId)
23427d1e14cSNodeMan97 {
2351b2c3c03SPatrick Williams     std::string chassisLostPowerFileFmt =
2361b2c3c03SPatrick Williams         std::format(CHASSIS_LOST_POWER_FILE, chassisId);
23727d1e14cSNodeMan97 
23827d1e14cSNodeMan97     std::filesystem::path chassisPowerLossFile{chassisLostPowerFileFmt};
23944bbf11dSPavithra Barithaya     return std::filesystem::exists(chassisPowerLossFile);
24027d1e14cSNodeMan97 }
24127d1e14cSNodeMan97 
isBmcReady(sdbusplus::bus_t & bus)242fc1020f2SAndrew Geissler bool isBmcReady(sdbusplus::bus_t& bus)
243fc1020f2SAndrew Geissler {
2449a286db2SPatrick Williams     using BMC = sdbusplus::client::xyz::openbmc_project::state::BMC<>;
2459a286db2SPatrick Williams     auto bmcPath = sdbusplus::message::object_path(BMC::namespace_path::value) /
2469a286db2SPatrick Williams                    BMC::namespace_path::bmc;
2479a286db2SPatrick Williams 
2481b2c3c03SPatrick Williams     auto bmcState =
2491b2c3c03SPatrick Williams         getProperty(bus, bmcPath.str, BMC::interface, "CurrentBMCState");
2509a286db2SPatrick Williams 
2519a286db2SPatrick Williams     if (sdbusplus::message::convert_from_string<BMC::BMCState>(bmcState) !=
2529a286db2SPatrick Williams         BMC::BMCState::Ready)
253fc1020f2SAndrew Geissler     {
254fc1020f2SAndrew Geissler         debug("BMC State is {BMC_STATE}", "BMC_STATE", bmcState);
255fc1020f2SAndrew Geissler         return false;
256fc1020f2SAndrew Geissler     }
257fc1020f2SAndrew Geissler     return true;
258fc1020f2SAndrew Geissler }
259fc1020f2SAndrew Geissler 
waitBmcReady(sdbusplus::bus_t & bus,std::chrono::seconds timeout)2600886545dSPotin Lai bool waitBmcReady(sdbusplus::bus_t& bus, std::chrono::seconds timeout)
2610886545dSPotin Lai {
2620886545dSPotin Lai     while (timeout.count() != 0)
2630886545dSPotin Lai     {
2640886545dSPotin Lai         timeout--;
2650886545dSPotin Lai         if (isBmcReady(bus))
2660886545dSPotin Lai         {
2670886545dSPotin Lai             return true;
2680886545dSPotin Lai         }
2690886545dSPotin Lai         std::this_thread::sleep_for(std::chrono::seconds(1));
2700886545dSPotin Lai     }
2710886545dSPotin Lai     return false;
2720886545dSPotin Lai }
2730886545dSPotin Lai 
274*9f38152aSThang Tran #ifdef CHECK_FWUPDATE_BEFORE_DO_TRANSITION
isFirmwareUpdating(sdbusplus::bus_t & bus)275*9f38152aSThang Tran bool isFirmwareUpdating(sdbusplus::bus_t& bus)
276*9f38152aSThang Tran {
277*9f38152aSThang Tran     /*
278*9f38152aSThang Tran      * This method looks for ActivationBlocksTransition interface, if any object
279*9f38152aSThang Tran      * path is including this interface, the Transition action should be
280*9f38152aSThang Tran      * prevented.
281*9f38152aSThang Tran      */
282*9f38152aSThang Tran     auto mapper = bus.new_method_call(
283*9f38152aSThang Tran         ObjectMapper::default_service, ObjectMapper::instance_path,
284*9f38152aSThang Tran         ObjectMapper::interface, "GetSubTreePaths");
285*9f38152aSThang Tran 
286*9f38152aSThang Tran     mapper.append("/", 0, std::vector<std::string>({ActBlockTrans::interface}));
287*9f38152aSThang Tran 
288*9f38152aSThang Tran     std::vector<std::string> mapperResponse;
289*9f38152aSThang Tran 
290*9f38152aSThang Tran     try
291*9f38152aSThang Tran     {
292*9f38152aSThang Tran         auto mapperResponseMsg = bus.call(mapper);
293*9f38152aSThang Tran 
294*9f38152aSThang Tran         mapperResponseMsg.read(mapperResponse);
295*9f38152aSThang Tran     }
296*9f38152aSThang Tran     catch (const sdbusplus::exception_t& e)
297*9f38152aSThang Tran     {
298*9f38152aSThang Tran         error("Error in mapper call with root path, interface "
299*9f38152aSThang Tran               "ActivationBlocksTransition, and exception {ERROR}",
300*9f38152aSThang Tran               "ERROR", e);
301*9f38152aSThang Tran         return false;
302*9f38152aSThang Tran     }
303*9f38152aSThang Tran 
304*9f38152aSThang Tran     return !mapperResponse.empty();
305*9f38152aSThang Tran }
306*9f38152aSThang Tran #endif // CHECK_FWUPDATE_BEFORE_DO_TRANSITION
307*9f38152aSThang Tran 
308dc059399SCarol Wang } // namespace utils
309dc059399SCarol Wang } // namespace manager
310dc059399SCarol Wang } // namespace state
311dc059399SCarol Wang } // namespace phosphor
312