blob: e64cb72c2376e45441b1a7fa3d6fd09ea2e5f0d1 [file] [log] [blame]
Patrick Venture5e6ac712017-10-25 12:16:19 -07001#include "watchdog.hpp"
2
Patrick Venture0b02be92018-08-31 11:55:55 -07003#include "watchdog_service.hpp"
4
William A. Kennington III52575252018-02-09 15:54:56 -08005#include <endian.h>
Patrick Venture0b02be92018-08-31 11:55:55 -07006
Vernon Mauerye08fbff2019-04-03 09:19:34 -07007#include <ipmid/api.hpp>
William A. Kennington III021b4c12018-05-10 11:12:51 -07008#include <phosphor-logging/elog-errors.hpp>
Patrick Venture0b02be92018-08-31 11:55:55 -07009#include <phosphor-logging/elog.hpp>
William A. Kennington III52575252018-02-09 15:54:56 -080010#include <phosphor-logging/log.hpp>
William A. Kennington III021b4c12018-05-10 11:12:51 -070011#include <xyz/openbmc_project/Common/error.hpp>
Patrick Venture894571d2017-11-09 14:46:54 -080012
Patrick Williamsfbc6c9d2023-05-10 07:50:16 -050013#include <bitset>
14#include <cstdint>
15#include <string>
16
William A. Kennington IIIbae471c2018-06-15 10:38:01 -070017using phosphor::logging::commit;
William A. Kennington III52575252018-02-09 15:54:56 -080018using phosphor::logging::level;
19using phosphor::logging::log;
Willy Tu523e2d12023-09-05 11:36:48 -070020using sdbusplus::error::xyz::openbmc_project::common::InternalFailure;
Patrick Venture5e6ac712017-10-25 12:16:19 -070021
William A. Kennington IIIbae471c2018-06-15 10:38:01 -070022static bool lastCallSuccessful = false;
23
24void reportError()
25{
26 // We don't want to fill the SEL with errors if the daemon dies and doesn't
27 // come back but the watchdog keeps on ticking. Instead, we only report the
28 // error if we haven't reported one since the last successful call
29 if (!lastCallSuccessful)
30 {
31 return;
32 }
33 lastCallSuccessful = false;
34
35 // TODO: This slow down the end of the IPMI transaction waiting
36 // for the commit to finish. commit<>() can take at least 5 seconds
37 // to complete. 5s is very slow for an IPMI command and ends up
38 // congesting the IPMI channel needlessly, especially if the watchdog
39 // is ticking fairly quickly and we have some transient issues.
40 commit<InternalFailure>();
41}
42
Vernon Mauery11df4f62019-03-25 14:17:54 -070043ipmi::RspType<> ipmiAppResetWatchdogTimer()
Patrick Venture5e6ac712017-10-25 12:16:19 -070044{
William A. Kennington III52575252018-02-09 15:54:56 -080045 try
46 {
47 WatchdogService wd_service;
William A. Kennington III52575252018-02-09 15:54:56 -080048
William A. Kennington IIIde14a022018-02-09 16:11:18 -080049 // Notify the caller if we haven't initialized our timer yet
50 // so it can configure actions and timeouts
William A. Kennington III2ecf5122018-04-27 14:31:51 -070051 if (!wd_service.getInitialized())
William A. Kennington IIIde14a022018-02-09 16:11:18 -080052 {
William A. Kennington IIIbae471c2018-06-15 10:38:01 -070053 lastCallSuccessful = true;
Vernon Mauery11df4f62019-03-25 14:17:54 -070054
55 constexpr uint8_t ccWatchdogNotInit = 0x80;
56 return ipmi::response(ccWatchdogNotInit);
William A. Kennington IIIde14a022018-02-09 16:11:18 -080057 }
58
William A. Kennington III4b017a92018-04-27 14:31:08 -070059 // The ipmi standard dictates we enable the watchdog during reset
60 wd_service.resetTimeRemaining(true);
William A. Kennington IIIbae471c2018-06-15 10:38:01 -070061 lastCallSuccessful = true;
Vernon Mauery11df4f62019-03-25 14:17:54 -070062 return ipmi::responseSuccess();
Patrick Venture5e6ac712017-10-25 12:16:19 -070063 }
William A. Kennington III021b4c12018-05-10 11:12:51 -070064 catch (const InternalFailure& e)
65 {
William A. Kennington IIIbae471c2018-06-15 10:38:01 -070066 reportError();
Vernon Mauery11df4f62019-03-25 14:17:54 -070067 return ipmi::responseUnspecifiedError();
William A. Kennington III021b4c12018-05-10 11:12:51 -070068 }
William A. Kennington III52575252018-02-09 15:54:56 -080069 catch (const std::exception& e)
70 {
71 const std::string e_str = std::string("wd_reset: ") + e.what();
72 log<level::ERR>(e_str.c_str());
Vernon Mauery11df4f62019-03-25 14:17:54 -070073 return ipmi::responseUnspecifiedError();
William A. Kennington III5325f2c2018-01-08 15:17:09 -080074 }
William A. Kennington III52575252018-02-09 15:54:56 -080075 catch (...)
76 {
77 log<level::ERR>("wd_reset: Unknown Error");
Vernon Mauery11df4f62019-03-25 14:17:54 -070078 return ipmi::responseUnspecifiedError();
William A. Kennington III5325f2c2018-01-08 15:17:09 -080079 }
Patrick Venture5e6ac712017-10-25 12:16:19 -070080}
William A. Kennington III61d5f7b2018-02-09 15:23:53 -080081
William A. Kennington III52575252018-02-09 15:54:56 -080082static constexpr uint8_t wd_dont_stop = 0x1 << 6;
83static constexpr uint8_t wd_timeout_action_mask = 0x3;
84
Deepak Kumar Sahucfae9482019-05-20 14:58:58 +000085static constexpr uint8_t wdTimerUseResTimer1 = 0x0;
86static constexpr uint8_t wdTimerUseResTimer2 = 0x6;
87static constexpr uint8_t wdTimerUseResTimer3 = 0x7;
88
Yong Li4dd71af2019-09-29 14:18:07 +080089static constexpr uint8_t wdTimeoutActionMax = 3;
Deepak Kumar Sahucfae9482019-05-20 14:58:58 +000090static constexpr uint8_t wdTimeoutInterruptTimer = 0x04;
Yong Li118907e2019-01-11 17:36:17 +080091
Patrick Venture0b02be92018-08-31 11:55:55 -070092enum class IpmiAction : uint8_t
93{
William A. Kennington III52575252018-02-09 15:54:56 -080094 None = 0x0,
95 HardReset = 0x1,
96 PowerOff = 0x2,
97 PowerCycle = 0x3,
98};
99
William A. Kennington IIIb638de22018-02-09 16:12:53 -0800100/** @brief Converts an IPMI Watchdog Action to DBUS defined action
101 * @param[in] ipmi_action The IPMI Watchdog Action
102 * @return The Watchdog Action that the ipmi_action maps to
103 */
104WatchdogService::Action ipmiActionToWdAction(IpmiAction ipmi_action)
105{
Patrick Venture0b02be92018-08-31 11:55:55 -0700106 switch (ipmi_action)
William A. Kennington IIIb638de22018-02-09 16:12:53 -0800107 {
108 case IpmiAction::None:
109 {
110 return WatchdogService::Action::None;
111 }
112 case IpmiAction::HardReset:
113 {
114 return WatchdogService::Action::HardReset;
115 }
116 case IpmiAction::PowerOff:
117 {
118 return WatchdogService::Action::PowerOff;
119 }
120 case IpmiAction::PowerCycle:
121 {
122 return WatchdogService::Action::PowerCycle;
123 }
124 default:
125 {
126 throw std::domain_error("IPMI Action is invalid");
127 }
128 }
129}
130
Yong Li118907e2019-01-11 17:36:17 +0800131enum class IpmiTimerUse : uint8_t
132{
133 Reserved = 0x0,
134 BIOSFRB2 = 0x1,
135 BIOSPOST = 0x2,
136 OSLoad = 0x3,
137 SMSOS = 0x4,
138 OEM = 0x5,
139};
140
141WatchdogService::TimerUse ipmiTimerUseToWdTimerUse(IpmiTimerUse ipmiTimerUse)
142{
143 switch (ipmiTimerUse)
144 {
145 case IpmiTimerUse::Reserved:
146 {
147 return WatchdogService::TimerUse::Reserved;
148 }
149 case IpmiTimerUse::BIOSFRB2:
150 {
151 return WatchdogService::TimerUse::BIOSFRB2;
152 }
153 case IpmiTimerUse::BIOSPOST:
154 {
155 return WatchdogService::TimerUse::BIOSPOST;
156 }
157 case IpmiTimerUse::OSLoad:
158 {
159 return WatchdogService::TimerUse::OSLoad;
160 }
161 case IpmiTimerUse::SMSOS:
162 {
163 return WatchdogService::TimerUse::SMSOS;
164 }
165 case IpmiTimerUse::OEM:
166 {
167 return WatchdogService::TimerUse::OEM;
168 }
169 default:
170 {
171 return WatchdogService::TimerUse::Reserved;
172 }
173 }
174}
175
Yong Li4dd71af2019-09-29 14:18:07 +0800176static bool timerNotLogFlags = false;
Yong Lia729bf42019-10-14 12:42:10 +0800177static std::bitset<8> timerUseExpirationFlags = 0;
Yong Li4dd71af2019-09-29 14:18:07 +0800178static uint3_t timerPreTimeoutInterrupt = 0;
Yong Lia729bf42019-10-14 12:42:10 +0800179static constexpr uint8_t wdExpirationFlagReservedBit0 = 0x0;
180static constexpr uint8_t wdExpirationFlagReservedBit6 = 0x6;
181static constexpr uint8_t wdExpirationFlagReservedBit7 = 0x7;
William A. Kennington III52575252018-02-09 15:54:56 -0800182
Deepak Kumar Sahucfae9482019-05-20 14:58:58 +0000183/**@brief The Set Watchdog Timer ipmi command.
184 *
185 * @param
186 * - timerUse
187 * - dontStopTimer
188 * - dontLog
189 * - timerAction
190 * - pretimeout
191 * - expireFlags
192 * - initialCountdown
193 *
194 * @return completion code on success.
195 **/
Yong Lia729bf42019-10-14 12:42:10 +0800196ipmi::RspType<>
197 ipmiSetWatchdogTimer(uint3_t timerUse, uint3_t reserved, bool dontStopTimer,
198 bool dontLog, uint3_t timeoutAction, uint1_t reserved1,
199 uint3_t preTimeoutInterrupt, uint1_t reserved2,
200 uint8_t preTimeoutInterval,
201 std::bitset<8> expFlagValue, uint16_t initialCountdown)
William A. Kennington III61d5f7b2018-02-09 15:23:53 -0800202{
Deepak Kumar Sahucfae9482019-05-20 14:58:58 +0000203 if ((timerUse == wdTimerUseResTimer1) ||
204 (timerUse == wdTimerUseResTimer2) ||
205 (timerUse == wdTimerUseResTimer3) ||
Yong Li4dd71af2019-09-29 14:18:07 +0800206 (timeoutAction > wdTimeoutActionMax) ||
Deepak Kumar Sahucfae9482019-05-20 14:58:58 +0000207 (preTimeoutInterrupt == wdTimeoutInterruptTimer) ||
Yong Lia729bf42019-10-14 12:42:10 +0800208 (reserved | reserved1 | reserved2 |
209 expFlagValue.test(wdExpirationFlagReservedBit0) |
210 expFlagValue.test(wdExpirationFlagReservedBit6) |
211 expFlagValue.test(wdExpirationFlagReservedBit7)))
William A. Kennington III52575252018-02-09 15:54:56 -0800212 {
Deepak Kumar Sahucfae9482019-05-20 14:58:58 +0000213 return ipmi::responseInvalidFieldRequest();
William A. Kennington III52575252018-02-09 15:54:56 -0800214 }
Deepak Kumar Sahucfae9482019-05-20 14:58:58 +0000215
216 if (preTimeoutInterval > (initialCountdown / 10))
217 {
218 return ipmi::responseInvalidFieldRequest();
219 }
220
Yong Li4dd71af2019-09-29 14:18:07 +0800221 timerNotLogFlags = dontLog;
222 timerPreTimeoutInterrupt = preTimeoutInterrupt;
William A. Kennington III61d5f7b2018-02-09 15:23:53 -0800223
William A. Kennington III52575252018-02-09 15:54:56 -0800224 try
William A. Kennington III61d5f7b2018-02-09 15:23:53 -0800225 {
William A. Kennington III52575252018-02-09 15:54:56 -0800226 WatchdogService wd_service;
227 // Stop the timer if the don't stop bit is not set
Deepak Kumar Sahucfae9482019-05-20 14:58:58 +0000228 if (!(dontStopTimer))
William A. Kennington III52575252018-02-09 15:54:56 -0800229 {
230 wd_service.setEnabled(false);
William A. Kennington III61d5f7b2018-02-09 15:23:53 -0800231 }
232
William A. Kennington III52575252018-02-09 15:54:56 -0800233 // Set the action based on the request
Deepak Kumar Sahucfae9482019-05-20 14:58:58 +0000234 const auto ipmi_action = static_cast<IpmiAction>(
235 static_cast<uint8_t>(timeoutAction) & wd_timeout_action_mask);
William A. Kennington IIIb638de22018-02-09 16:12:53 -0800236 wd_service.setExpireAction(ipmiActionToWdAction(ipmi_action));
William A. Kennington III52575252018-02-09 15:54:56 -0800237
William A. Kennington III7a0e5df2021-05-19 13:31:29 -0700238 const auto ipmiTimerUse = types::enum_cast<IpmiTimerUse>(timerUse);
Yong Li118907e2019-01-11 17:36:17 +0800239 wd_service.setTimerUse(ipmiTimerUseToWdTimerUse(ipmiTimerUse));
240
Deepak Kumar Sahucfae9482019-05-20 14:58:58 +0000241 wd_service.setExpiredTimerUse(WatchdogService::TimerUse::Reserved);
242
Yong Lia729bf42019-10-14 12:42:10 +0800243 timerUseExpirationFlags &= ~expFlagValue;
Deepak Kumar Sahucfae9482019-05-20 14:58:58 +0000244
William A. Kennington III52575252018-02-09 15:54:56 -0800245 // Set the new interval and the time remaining deci -> mill seconds
Deepak Kumar Sahucfae9482019-05-20 14:58:58 +0000246 const uint64_t interval = initialCountdown * 100;
William A. Kennington III52575252018-02-09 15:54:56 -0800247 wd_service.setInterval(interval);
William A. Kennington IIIebc53cb2019-12-05 17:04:29 -0800248 wd_service.resetTimeRemaining(false);
William A. Kennington III52575252018-02-09 15:54:56 -0800249
William A. Kennington IIIde14a022018-02-09 16:11:18 -0800250 // Mark as initialized so that future resets behave correctly
251 wd_service.setInitialized(true);
Tim Chao65362f42023-11-14 14:47:25 +0800252 wd_service.setLogTimeout(!dontLog);
William A. Kennington IIIde14a022018-02-09 16:11:18 -0800253
William A. Kennington IIIbae471c2018-06-15 10:38:01 -0700254 lastCallSuccessful = true;
Deepak Kumar Sahucfae9482019-05-20 14:58:58 +0000255 return ipmi::responseSuccess();
William A. Kennington III61d5f7b2018-02-09 15:23:53 -0800256 }
Patrick Venture0b02be92018-08-31 11:55:55 -0700257 catch (const std::domain_error&)
William A. Kennington III52575252018-02-09 15:54:56 -0800258 {
Deepak Kumar Sahucfae9482019-05-20 14:58:58 +0000259 return ipmi::responseInvalidFieldRequest();
William A. Kennington III52575252018-02-09 15:54:56 -0800260 }
William A. Kennington III021b4c12018-05-10 11:12:51 -0700261 catch (const InternalFailure& e)
262 {
William A. Kennington IIIbae471c2018-06-15 10:38:01 -0700263 reportError();
Deepak Kumar Sahucfae9482019-05-20 14:58:58 +0000264 return ipmi::responseUnspecifiedError();
William A. Kennington III021b4c12018-05-10 11:12:51 -0700265 }
William A. Kennington III52575252018-02-09 15:54:56 -0800266 catch (const std::exception& e)
267 {
268 const std::string e_str = std::string("wd_set: ") + e.what();
269 log<level::ERR>(e_str.c_str());
Deepak Kumar Sahucfae9482019-05-20 14:58:58 +0000270 return ipmi::responseUnspecifiedError();
William A. Kennington III52575252018-02-09 15:54:56 -0800271 }
272 catch (...)
273 {
274 log<level::ERR>("wd_set: Unknown Error");
Deepak Kumar Sahucfae9482019-05-20 14:58:58 +0000275 return ipmi::responseUnspecifiedError();
William A. Kennington III52575252018-02-09 15:54:56 -0800276 }
William A. Kennington III61d5f7b2018-02-09 15:23:53 -0800277}
William A. Kennington III73f44512018-02-09 15:28:46 -0800278
279/** @brief Converts a DBUS Watchdog Action to IPMI defined action
280 * @param[in] wd_action The DBUS Watchdog Action
281 * @return The IpmiAction that the wd_action maps to
282 */
283IpmiAction wdActionToIpmiAction(WatchdogService::Action wd_action)
284{
Patrick Venture0b02be92018-08-31 11:55:55 -0700285 switch (wd_action)
William A. Kennington III73f44512018-02-09 15:28:46 -0800286 {
287 case WatchdogService::Action::None:
288 {
289 return IpmiAction::None;
290 }
291 case WatchdogService::Action::HardReset:
292 {
293 return IpmiAction::HardReset;
294 }
295 case WatchdogService::Action::PowerOff:
296 {
297 return IpmiAction::PowerOff;
298 }
299 case WatchdogService::Action::PowerCycle:
300 {
301 return IpmiAction::PowerCycle;
302 }
303 default:
304 {
305 // We have no method via IPMI to signal that the action is unknown
306 // or unmappable in some way.
307 // Just ignore the error and return NONE so the host can reconcile.
308 return IpmiAction::None;
309 }
310 }
311}
312
Yong Li118907e2019-01-11 17:36:17 +0800313IpmiTimerUse wdTimerUseToIpmiTimerUse(WatchdogService::TimerUse wdTimerUse)
314{
315 switch (wdTimerUse)
316 {
317 case WatchdogService::TimerUse::Reserved:
318 {
319 return IpmiTimerUse::Reserved;
320 }
321 case WatchdogService::TimerUse::BIOSFRB2:
322 {
323 return IpmiTimerUse::BIOSFRB2;
324 }
325 case WatchdogService::TimerUse::BIOSPOST:
326 {
327 return IpmiTimerUse::BIOSPOST;
328 }
329 case WatchdogService::TimerUse::OSLoad:
330 {
331 return IpmiTimerUse::OSLoad;
332 }
333
334 case WatchdogService::TimerUse::SMSOS:
335 {
336 return IpmiTimerUse::SMSOS;
337 }
338 case WatchdogService::TimerUse::OEM:
339 {
340 return IpmiTimerUse::OEM;
341 }
342 default:
343 {
344 return IpmiTimerUse::Reserved;
345 }
346 }
347}
348
William A. Kennington III73f44512018-02-09 15:28:46 -0800349static constexpr uint8_t wd_running = 0x1 << 6;
350
Deepak Kumar Sahucfae9482019-05-20 14:58:58 +0000351/**@brief The getWatchdogTimer ipmi command.
352 *
353 * @return Completion code plus timer details.
354 * - timerUse
355 * - timerAction
356 * - pretimeout
357 * - expireFlags
358 * - initialCountdown
359 * - presentCountdown
360 **/
Patrick Williamsfbc6c9d2023-05-10 07:50:16 -0500361ipmi::RspType<uint3_t, // timerUse - timer use
362 uint3_t, // timerUse - reserved
363 bool, // timerUse - timer is started
364 bool, // timerUse - don't log
Yong Li4dd71af2019-09-29 14:18:07 +0800365
Patrick Williamsfbc6c9d2023-05-10 07:50:16 -0500366 uint3_t, // timerAction - timeout action
367 uint1_t, // timerAction - reserved
368 uint3_t, // timerAction - pre-timeout interrupt
369 uint1_t, // timerAction - reserved
Yong Li4dd71af2019-09-29 14:18:07 +0800370
Yong Lia729bf42019-10-14 12:42:10 +0800371 uint8_t, // pretimeout
372 std::bitset<8>, // expireFlags
373 uint16_t, // initial Countdown - Little Endian (deciseconds)
374 uint16_t // present Countdown - Little Endian (deciseconds)
Deepak Kumar Sahucfae9482019-05-20 14:58:58 +0000375 >
376 ipmiGetWatchdogTimer()
William A. Kennington III73f44512018-02-09 15:28:46 -0800377{
Deepak Kumar Sahucfae9482019-05-20 14:58:58 +0000378 uint16_t presentCountdown = 0;
379 uint8_t pretimeout = 0;
William A. Kennington III73f44512018-02-09 15:28:46 -0800380
381 try
382 {
383 WatchdogService wd_service;
384 WatchdogService::Properties wd_prop = wd_service.getProperties();
385
386 // Build and return the response
Yong Lif7c9db02019-01-15 13:45:33 +0800387 // Interval and timeRemaining need converted from milli -> deci seconds
Deepak Kumar Sahucfae9482019-05-20 14:58:58 +0000388 uint16_t initialCountdown = htole16(wd_prop.interval / 100);
389
390 if (wd_prop.expiredTimerUse != WatchdogService::TimerUse::Reserved)
391 {
Yong Lia729bf42019-10-14 12:42:10 +0800392 timerUseExpirationFlags.set(static_cast<uint8_t>(
393 wdTimerUseToIpmiTimerUse(wd_prop.expiredTimerUse)));
Deepak Kumar Sahucfae9482019-05-20 14:58:58 +0000394 }
395
William A. Kennington III73f44512018-02-09 15:28:46 -0800396 if (wd_prop.enabled)
397 {
Deepak Kumar Sahucfae9482019-05-20 14:58:58 +0000398 presentCountdown = htole16(wd_prop.timeRemaining / 100);
Yong Lif7c9db02019-01-15 13:45:33 +0800399 }
400 else
401 {
Deepak Kumar Sahucfae9482019-05-20 14:58:58 +0000402 if (wd_prop.expiredTimerUse == WatchdogService::TimerUse::Reserved)
403 {
404 presentCountdown = initialCountdown;
Deepak Kumar Sahucfae9482019-05-20 14:58:58 +0000405 }
406 else
407 {
408 presentCountdown = 0;
Yong Li4dd71af2019-09-29 14:18:07 +0800409 // Automatically clear it whenever a timer expiration occurs.
410 timerNotLogFlags = false;
Deepak Kumar Sahucfae9482019-05-20 14:58:58 +0000411 }
William A. Kennington III73f44512018-02-09 15:28:46 -0800412 }
Yong Li118907e2019-01-11 17:36:17 +0800413
William A. Kennington III73f44512018-02-09 15:28:46 -0800414 // TODO: Do something about having pretimeout support
Deepak Kumar Sahucfae9482019-05-20 14:58:58 +0000415 pretimeout = 0;
416
William A. Kennington IIIbae471c2018-06-15 10:38:01 -0700417 lastCallSuccessful = true;
Yong Li4dd71af2019-09-29 14:18:07 +0800418 return ipmi::responseSuccess(
William A. Kennington III7a0e5df2021-05-19 13:31:29 -0700419 types::enum_cast<uint3_t>(
420 wdTimerUseToIpmiTimerUse(wd_prop.timerUse)),
421 0, wd_prop.enabled, timerNotLogFlags,
422 types::enum_cast<uint3_t>(
423 wdActionToIpmiAction(wd_prop.expireAction)),
424 0, timerPreTimeoutInterrupt, 0, pretimeout, timerUseExpirationFlags,
Yong Li4dd71af2019-09-29 14:18:07 +0800425 initialCountdown, presentCountdown);
William A. Kennington III73f44512018-02-09 15:28:46 -0800426 }
William A. Kennington III021b4c12018-05-10 11:12:51 -0700427 catch (const InternalFailure& e)
428 {
William A. Kennington IIIbae471c2018-06-15 10:38:01 -0700429 reportError();
Deepak Kumar Sahucfae9482019-05-20 14:58:58 +0000430 return ipmi::responseUnspecifiedError();
William A. Kennington III021b4c12018-05-10 11:12:51 -0700431 }
William A. Kennington III73f44512018-02-09 15:28:46 -0800432 catch (const std::exception& e)
433 {
434 const std::string e_str = std::string("wd_get: ") + e.what();
435 log<level::ERR>(e_str.c_str());
Deepak Kumar Sahucfae9482019-05-20 14:58:58 +0000436 return ipmi::responseUnspecifiedError();
William A. Kennington III73f44512018-02-09 15:28:46 -0800437 }
438 catch (...)
439 {
440 log<level::ERR>("wd_get: Unknown Error");
Deepak Kumar Sahucfae9482019-05-20 14:58:58 +0000441 return ipmi::responseUnspecifiedError();
William A. Kennington III73f44512018-02-09 15:28:46 -0800442 }
443}