1 #include "watchdog_service.hpp"
2 
3 #include <phosphor-logging/elog.hpp>
4 #include <phosphor-logging/elog-errors.hpp>
5 #include <phosphor-logging/log.hpp>
6 #include <sdbusplus/bus.hpp>
7 #include <sdbusplus/message.hpp>
8 #include <string>
9 #include <xyz/openbmc_project/Common/error.hpp>
10 #include <xyz/openbmc_project/State/Watchdog/server.hpp>
11 
12 #include "host-ipmid/ipmid-api.h"
13 
14 using phosphor::logging::entry;
15 using phosphor::logging::elog;
16 using phosphor::logging::level;
17 using phosphor::logging::log;
18 using sdbusplus::message::variant_ns::get;
19 using sdbusplus::message::variant_ns::variant;
20 using sdbusplus::xyz::openbmc_project::Common::Error::InternalFailure;
21 using sdbusplus::xyz::openbmc_project::State::server::convertForMessage;
22 using sdbusplus::xyz::openbmc_project::State::server::Watchdog;
23 
24 static constexpr char wd_path[] = "/xyz/openbmc_project/watchdog/host0";
25 static constexpr char wd_intf[] = "xyz.openbmc_project.State.Watchdog";
26 static constexpr char prop_intf[] = "org.freedesktop.DBus.Properties";
27 
28 ipmi::ServiceCache WatchdogService::wd_service(wd_intf, wd_path);
29 
30 WatchdogService::WatchdogService()
31     : bus(ipmid_get_sd_bus_connection())
32 {
33 }
34 
35 void WatchdogService::resetTimeRemaining(bool enableWatchdog)
36 {
37     bool wasValid = wd_service.isValid(bus);
38     auto request = wd_service.newMethodCall(
39             bus, wd_intf, "ResetTimeRemaining");
40     request.append(enableWatchdog);
41     auto response = bus.call(request);
42     if (response.is_method_error())
43     {
44         wd_service.invalidate();
45         if (wasValid)
46         {
47             // Retry the request once in case the cached service was stale
48             return resetTimeRemaining(enableWatchdog);
49         }
50         log<level::ERR>(
51                 "WatchdogService: Method error resetting time remaining",
52                 entry("ENABLE_WATCHDOG=%d", !!enableWatchdog));
53         elog<InternalFailure>();
54     }
55 }
56 
57 WatchdogService::Properties WatchdogService::getProperties()
58 {
59     bool wasValid = wd_service.isValid(bus);
60     auto request = wd_service.newMethodCall(bus, prop_intf, "GetAll");
61     request.append(wd_intf);
62     auto response = bus.call(request);
63     if (response.is_method_error())
64     {
65         wd_service.invalidate();
66         if (wasValid)
67         {
68             // Retry the request once in case the cached service was stale
69             return getProperties();
70         }
71         log<level::ERR>("WatchdogService: Method error getting properties");
72         elog<InternalFailure>();
73     }
74 
75     std::map<std::string, variant<bool, uint64_t, std::string>> properties;
76     response.read(properties);
77     Properties wd_prop;
78     wd_prop.initialized = get<bool>(properties.at("Initialized"));
79     wd_prop.enabled = get<bool>(properties.at("Enabled"));
80     wd_prop.expireAction = Watchdog::convertActionFromString(
81             get<std::string>(properties.at("ExpireAction")));
82     wd_prop.interval = get<uint64_t>(properties.at("Interval"));
83     wd_prop.timeRemaining = get<uint64_t>(properties.at("TimeRemaining"));
84     return wd_prop;
85 }
86 
87 template <typename T>
88 T WatchdogService::getProperty(const std::string& key)
89 {
90     bool wasValid = wd_service.isValid(bus);
91     auto request = wd_service.newMethodCall(bus, prop_intf, "Get");
92     request.append(wd_intf, key);
93     auto response = bus.call(request);
94     if (response.is_method_error())
95     {
96         wd_service.invalidate();
97         if (wasValid)
98         {
99             // Retry the request once in case the cached service was stale
100             return getProperty<T>(key);
101         }
102         log<level::ERR>("WatchdogService: Method error getting property",
103                         entry("PROPERTY=%s", key.c_str()));
104         elog<InternalFailure>();
105     }
106     variant<T> value;
107     response.read(value);
108     return get<T>(value);
109 }
110 
111 template <typename T>
112 void WatchdogService::setProperty(const std::string& key, const T& val)
113 {
114     bool wasValid = wd_service.isValid(bus);
115     auto request = wd_service.newMethodCall(bus, prop_intf, "Set");
116     request.append(wd_intf, key, variant<T>(val));
117     auto response = bus.call(request);
118     if (response.is_method_error())
119     {
120         wd_service.invalidate();
121         if (wasValid)
122         {
123             // Retry the request once in case the cached service was stale
124             return setProperty(key, val);
125         }
126         log<level::ERR>("WatchdogService: Method error setting property",
127                         entry("PROPERTY=%s", key.c_str()));
128         elog<InternalFailure>();
129     }
130 }
131 
132 bool WatchdogService::getInitialized()
133 {
134     return getProperty<bool>("Initialized");
135 }
136 
137 void WatchdogService::setInitialized(bool initialized)
138 {
139     setProperty("Initialized", initialized);
140 }
141 
142 void WatchdogService::setEnabled(bool enabled)
143 {
144     setProperty("Enabled", enabled);
145 }
146 
147 void WatchdogService::setExpireAction(Action expireAction)
148 {
149     setProperty("ExpireAction", convertForMessage(expireAction));
150 }
151 
152 void WatchdogService::setInterval(uint64_t interval)
153 {
154     setProperty("Interval", interval);
155 }
156 
157 void WatchdogService::setTimeRemaining(uint64_t timeRemaining)
158 {
159     setProperty("TimeRemaining", timeRemaining);
160 }
161