1 #include "watchdog_service.hpp"
2
3 #include <ipmid/api.hpp>
4 #include <phosphor-logging/elog-errors.hpp>
5 #include <phosphor-logging/elog.hpp>
6 #include <phosphor-logging/log.hpp>
7 #include <sdbusplus/bus.hpp>
8 #include <sdbusplus/message.hpp>
9 #include <xyz/openbmc_project/Common/error.hpp>
10 #include <xyz/openbmc_project/State/Watchdog/server.hpp>
11
12 #include <exception>
13 #include <stdexcept>
14 #include <string>
15
16 using phosphor::logging::elog;
17 using phosphor::logging::entry;
18 using phosphor::logging::level;
19 using phosphor::logging::log;
20 using sdbusplus::common::xyz::openbmc_project::state::convertForMessage;
21 using sdbusplus::error::xyz::openbmc_project::common::InternalFailure;
22 using sdbusplus::server::xyz::openbmc_project::state::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
WatchdogService()30 WatchdogService::WatchdogService() : bus(ipmid_get_sd_bus_connection()) {}
31
resetTimeRemaining(bool enableWatchdog)32 void WatchdogService::resetTimeRemaining(bool enableWatchdog)
33 {
34 bool wasValid = wd_service.isValid(bus);
35 auto request = wd_service.newMethodCall(bus, wd_intf, "ResetTimeRemaining");
36 request.append(enableWatchdog);
37 try
38 {
39 auto response = bus.call(request);
40 }
41 catch (const std::exception& e)
42 {
43 wd_service.invalidate();
44 if (wasValid)
45 {
46 // Retry the request once in case the cached service was stale
47 return resetTimeRemaining(enableWatchdog);
48 }
49 log<level::ERR>(
50 "WatchdogService: Method error resetting time remaining",
51 entry("ENABLE_WATCHDOG=%d", !!enableWatchdog),
52 entry("ERROR=%s", e.what()));
53 elog<InternalFailure>();
54 }
55 }
56
getProperties()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
63 std::map<std::string, std::variant<bool, uint64_t, std::string>> properties;
64 try
65 {
66 auto response = bus.call(request);
67 response.read(properties);
68 }
69 catch (const std::exception& e)
70 {
71 wd_service.invalidate();
72 if (wasValid)
73 {
74 // Retry the request once in case the cached service was stale
75 return getProperties();
76 }
77 log<level::ERR>("WatchdogService: Method error getting properties",
78 entry("ERROR=%s", e.what()));
79 elog<InternalFailure>();
80 }
81
82 try
83 {
84 Properties wd_prop;
85 wd_prop.initialized = std::get<bool>(properties.at("Initialized"));
86 wd_prop.enabled = std::get<bool>(properties.at("Enabled"));
87 wd_prop.expireAction = Watchdog::convertActionFromString(
88 std::get<std::string>(properties.at("ExpireAction")));
89 wd_prop.timerUse = Watchdog::convertTimerUseFromString(
90 std::get<std::string>(properties.at("CurrentTimerUse")));
91 wd_prop.expiredTimerUse = Watchdog::convertTimerUseFromString(
92 std::get<std::string>(properties.at("ExpiredTimerUse")));
93
94 wd_prop.interval = std::get<uint64_t>(properties.at("Interval"));
95 wd_prop.timeRemaining =
96 std::get<uint64_t>(properties.at("TimeRemaining"));
97 return wd_prop;
98 }
99 catch (const std::exception& e)
100 {
101 log<level::ERR>("WatchdogService: Decode error in get properties",
102 entry("ERROR=%s", e.what()));
103 elog<InternalFailure>();
104 }
105
106 // Needed instead of elog<InternalFailure>() since the compiler can't
107 // deduce the that elog<>() always throws
108 throw std::runtime_error(
109 "WatchdogService: Should not reach end of getProperties");
110 }
111
112 template <typename T>
getProperty(const std::string & key)113 T WatchdogService::getProperty(const std::string& key)
114 {
115 bool wasValid = wd_service.isValid(bus);
116 auto request = wd_service.newMethodCall(bus, prop_intf, "Get");
117 request.append(wd_intf, key);
118 try
119 {
120 auto response = bus.call(request);
121 std::variant<T> value;
122 response.read(value);
123 return std::get<T>(value);
124 }
125 catch (const std::exception& e)
126 {
127 wd_service.invalidate();
128 if (wasValid)
129 {
130 // Retry the request once in case the cached service was stale
131 return getProperty<T>(key);
132 }
133 log<level::ERR>("WatchdogService: Method error getting property",
134 entry("PROPERTY=%s", key.c_str()),
135 entry("ERROR=%s", e.what()));
136 elog<InternalFailure>();
137 }
138
139 // Needed instead of elog<InternalFailure>() since the compiler can't
140 // deduce the that elog<>() always throws
141 throw std::runtime_error(
142 "WatchdogService: Should not reach end of getProperty");
143 }
144
145 template <typename T>
setProperty(const std::string & key,const T & val)146 void WatchdogService::setProperty(const std::string& key, const T& val)
147 {
148 bool wasValid = wd_service.isValid(bus);
149 auto request = wd_service.newMethodCall(bus, prop_intf, "Set");
150 request.append(wd_intf, key, std::variant<T>(val));
151 try
152 {
153 auto response = bus.call(request);
154 }
155 catch (const std::exception& e)
156 {
157 wd_service.invalidate();
158 if (wasValid)
159 {
160 // Retry the request once in case the cached service was stale
161 setProperty(key, val);
162 return;
163 }
164 log<level::ERR>("WatchdogService: Method error setting property",
165 entry("PROPERTY=%s", key.c_str()),
166 entry("ERROR=%s", e.what()));
167 elog<InternalFailure>();
168 }
169 }
170
getInitialized()171 bool WatchdogService::getInitialized()
172 {
173 return getProperty<bool>("Initialized");
174 }
175
setInitialized(bool initialized)176 void WatchdogService::setInitialized(bool initialized)
177 {
178 setProperty("Initialized", initialized);
179 }
180
setEnabled(bool enabled)181 void WatchdogService::setEnabled(bool enabled)
182 {
183 setProperty("Enabled", enabled);
184 }
185
setLogTimeout(bool LogTimeout)186 void WatchdogService::setLogTimeout(bool LogTimeout)
187 {
188 setProperty("LogTimeout", LogTimeout);
189 }
190
setExpireAction(Action expireAction)191 void WatchdogService::setExpireAction(Action expireAction)
192 {
193 setProperty("ExpireAction", convertForMessage(expireAction));
194 }
195
setTimerUse(TimerUse timerUse)196 void WatchdogService::setTimerUse(TimerUse timerUse)
197 {
198 setProperty("CurrentTimerUse", convertForMessage(timerUse));
199 }
200
setExpiredTimerUse(TimerUse timerUse)201 void WatchdogService::setExpiredTimerUse(TimerUse timerUse)
202 {
203 setProperty("ExpiredTimerUse", convertForMessage(timerUse));
204 }
205
setInterval(uint64_t interval)206 void WatchdogService::setInterval(uint64_t interval)
207 {
208 setProperty("Interval", interval);
209 }
210