summaryrefslogtreecommitdiffstats
path: root/app/watchdog.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'app/watchdog.cpp')
-rw-r--r--app/watchdog.cpp270
1 files changed, 90 insertions, 180 deletions
diff --git a/app/watchdog.cpp b/app/watchdog.cpp
index c8c9ced..d537683 100644
--- a/app/watchdog.cpp
+++ b/app/watchdog.cpp
@@ -1,25 +1,16 @@
#include "watchdog.hpp"
-#include "utils.hpp"
-#include <systemd/sd-bus.h>
+#include <cstdint>
+#include <endian.h>
+#include <phosphor-logging/log.hpp>
+#include <string>
-#include <mapper.h>
-#include <sdbusplus/bus.hpp>
+#include "watchdog_service.hpp"
+#include "host-ipmid/ipmid-api.h"
+#include "ipmid.hpp"
-extern sd_bus *bus;
-
-struct set_wd_data_t {
- uint8_t timer_use;
- uint8_t timer_action;
- uint8_t preset;
- uint8_t flags;
- uint8_t ls;
- uint8_t ms;
-} __attribute__ ((packed));
-
-static constexpr auto objname = "/xyz/openbmc_project/watchdog/host0";
-static constexpr auto iface = "xyz.openbmc_project.State.Watchdog";
-static constexpr auto property_iface = "org.freedesktop.DBus.Properties";
+using phosphor::logging::level;
+using phosphor::logging::log;
ipmi_ret_t ipmi_app_watchdog_reset(
ipmi_netfn_t netfn,
@@ -29,102 +20,55 @@ ipmi_ret_t ipmi_app_watchdog_reset(
ipmi_data_len_t data_len,
ipmi_context_t context)
{
- sd_bus_message *reply = NULL;
- sd_bus_error error = SD_BUS_ERROR_NULL;
- int r = 0;
- char *busname = NULL;
-
- // Current properties of the watchdog daemon.
- int enabled = 0;
- uint64_t interval = 0;
-
- // Status code.
- ipmi_ret_t ret = IPMI_CC_UNSPECIFIED_ERROR;
+ // We never return data with this command so immediately get rid of it
*data_len = 0;
- printf("WATCHDOG RESET\n");
- // Get bus name
- r = mapper_get_service(bus, objname, &busname);
- if (r < 0) {
- fprintf(stderr, "Failed to get %s bus name: %s\n",
- objname, strerror(-r));
- ret = IPMI_CC_BUSY;
- goto finish;
- }
+ try
+ {
+ WatchdogService wd_service;
+ WatchdogService::Properties wd_prop = wd_service.getProperties();
- // Check if our watchdog is running
- r = sd_bus_call_method(bus, busname, objname, property_iface,
- "Get", &error, &reply, "ss",
- iface, "Enabled");
- if(r < 0) {
- fprintf(stderr, "Failed to get current Enabled msg: %s\n",
- strerror(-r));
- ret = IPMI_CC_BUSY;
- goto finish;
- }
+ // Reset the countdown to make sure we don't expire our timer
+ wd_service.setTimeRemaining(wd_prop.interval);
- // Now extract the value
- r = sd_bus_message_read(reply, "v", "b", &enabled);
- if (r < 0) {
- fprintf(stderr, "Failed to read current Enabled: %s\n",
- strerror(-r));
- ret = IPMI_CC_BUSY;
- goto finish;
- }
+ // The spec states that the timer is activated by reset
+ wd_service.setEnabled(true);
- // If we are not enable we should indicate that
- if (!enabled) {
- printf("Watchdog not enabled during reset\n");
- ret = IPMI_WDOG_CC_NOT_INIT;
- goto finish;
+ return IPMI_CC_OK;
}
-
- sd_bus_error_free(&error);
- reply = sd_bus_message_unref(reply);
-
- // Get the current interval and set it back.
- r = sd_bus_call_method(bus, busname, objname, property_iface,
- "Get", &error, &reply, "ss",
- iface, "Interval");
-
- if(r < 0) {
- fprintf(stderr, "Failed to get current Interval msg: %s\n",
- strerror(-r));
- ret = IPMI_CC_BUSY;
- goto finish;
+ catch (const std::exception& e)
+ {
+ const std::string e_str = std::string("wd_reset: ") + e.what();
+ log<level::ERR>(e_str.c_str());
+ return IPMI_CC_UNSPECIFIED_ERROR;
}
-
- // Now extract the value
- r = sd_bus_message_read(reply, "v", "t", &interval);
- if (r < 0) {
- fprintf(stderr, "Failed to read current interval: %s\n",
- strerror(-r));
- ret = IPMI_CC_BUSY;
- goto finish;
+ catch (...)
+ {
+ log<level::ERR>("wd_reset: Unknown Error");
+ return IPMI_CC_UNSPECIFIED_ERROR;
}
+}
- sd_bus_error_free(&error);
- reply = sd_bus_message_unref(reply);
-
- // Set watchdog timer
- r = sd_bus_call_method(bus, busname, objname, property_iface,
- "Set", &error, &reply, "ssv",
- iface, "TimeRemaining", "t", interval);
- if(r < 0) {
- fprintf(stderr, "Failed to refresh the timer: %s\n",
- strerror(-r));
- ret = IPMI_CC_BUSY;
- goto finish;
- }
+static constexpr uint8_t wd_dont_stop = 0x1 << 6;
+static constexpr uint8_t wd_timeout_action_mask = 0x3;
- ret = IPMI_CC_OK;
-finish:
- sd_bus_error_free(&error);
- reply = sd_bus_message_unref(reply);
- free(busname);
+enum class IpmiAction : uint8_t {
+ None = 0x0,
+ HardReset = 0x1,
+ PowerOff = 0x2,
+ PowerCycle = 0x3,
+};
- return ret;
-}
+struct wd_set_req {
+ uint8_t timer_use;
+ uint8_t timer_action;
+ uint8_t pretimeout; // (seconds)
+ uint8_t expire_flags;
+ uint16_t initial_countdown; // Little Endian (deciseconds)
+} __attribute__ ((packed));
+static_assert(sizeof(wd_set_req) == 6, "wd_set_req has invalid size.");
+static_assert(sizeof(wd_set_req) <= MAX_IPMI_BUFFER,
+ "wd_get_res can't fit in request buffer.");
ipmi_ret_t ipmi_app_watchdog_set(
ipmi_netfn_t netfn,
@@ -134,91 +78,57 @@ ipmi_ret_t ipmi_app_watchdog_set(
ipmi_data_len_t data_len,
ipmi_context_t context)
{
- sd_bus_message *reply = NULL;
- sd_bus_error error = SD_BUS_ERROR_NULL;
- int r = 0;
- ipmi_ret_t ret = IPMI_CC_UNSPECIFIED_ERROR;
-
- set_wd_data_t *reqptr = (set_wd_data_t*) request;
-
- uint16_t timer = 0;
-
- // Making this uint64_t to match with provider
- uint64_t timer_ms = 0;
- char *busname = NULL;
+ // Extract the request data
+ if (*data_len < sizeof(wd_set_req))
+ {
+ *data_len = 0;
+ return IPMI_CC_REQ_DATA_LEN_INVALID;
+ }
+ wd_set_req req;
+ memcpy(&req, request, sizeof(req));
+ req.initial_countdown = le16toh(req.initial_countdown);
*data_len = 0;
- // Get number of 100ms intervals
- timer = (((uint16_t)reqptr->ms) << 8) + reqptr->ls;
- // Get timer value in ms
- timer_ms = timer * 100;
+ try
+ {
+ WatchdogService wd_service;
+ // Stop the timer if the don't stop bit is not set
+ if (!(req.timer_use & wd_dont_stop))
+ {
+ wd_service.setEnabled(false);
+ }
+
+ // Set the action based on the request
+ // Unfortunately we only really support enable or disable
+ // and don't actually support a real action. Until we have proper
+ // action support just map NONE as a disable action.
+ const auto ipmi_action = static_cast<IpmiAction>(
+ req.timer_action & wd_timeout_action_mask);
+ if (ipmi_action == IpmiAction::None)
+ {
+ wd_service.setEnabled(false);
+ }
- printf("WATCHDOG SET Timer:[0x%X] 100ms intervals\n",timer);
+ // Set the new interval and the time remaining deci -> mill seconds
+ const uint64_t interval = req.initial_countdown * 100;
+ wd_service.setInterval(interval);
+ wd_service.setTimeRemaining(interval);
- // Get bus name
- r = mapper_get_service(bus, objname, &busname);
- if (r < 0) {
- fprintf(stderr, "Failed to get %s bus name: %s\n",
- objname, strerror(-r));
- ret = IPMI_CC_BUSY;
- goto finish;
+ return IPMI_CC_OK;
}
-
- // Disable watchdog if running
- r = sd_bus_call_method(bus, busname, objname, property_iface,
- "Set", &error, &reply, "ssv",
- iface, "Enabled", "b", false);
- if(r < 0) {
- fprintf(stderr, "Failed to disable Watchdog: %s\n",
- strerror(-r));
- ret = IPMI_CC_BUSY;
- goto finish;
+ catch (const std::domain_error &)
+ {
+ return IPMI_CC_INVALID_FIELD_REQUEST;
}
-
- /*
- * If the action is 0, it means, do nothing. Multiple actions on timer
- * expiration aren't supported by phosphor-watchdog yet, so when the
- * action set is "none", we should just leave the timer disabled.
- */
- if (0 == reqptr->timer_action)
+ catch (const std::exception& e)
{
- ret = IPMI_CC_OK;
- goto finish;
+ const std::string e_str = std::string("wd_set: ") + e.what();
+ log<level::ERR>(e_str.c_str());
+ return IPMI_CC_UNSPECIFIED_ERROR;
}
-
- if (reqptr->timer_use & 0x40)
+ catch (...)
{
- sd_bus_error_free(&error);
- reply = sd_bus_message_unref(reply);
-
- // Set the Interval for the Watchdog
- r = sd_bus_call_method(bus, busname, objname, property_iface,
- "Set", &error, &reply, "ssv",
- iface, "Interval", "t", timer_ms);
- if(r < 0) {
- fprintf(stderr, "Failed to set new expiration time: %s\n",
- strerror(-r));
- ret = IPMI_CC_BUSY;
- goto finish;
- }
-
- // Now Enable Watchdog
- r = sd_bus_call_method(bus, busname, objname, property_iface,
- "Set", &error, &reply, "ssv",
- iface, "Enabled", "b", true);
- if(r < 0) {
- fprintf(stderr, "Failed to Enable Watchdog: %s\n",
- strerror(-r));
- ret = IPMI_CC_BUSY;
- goto finish;
- }
+ log<level::ERR>("wd_set: Unknown Error");
+ return IPMI_CC_UNSPECIFIED_ERROR;
}
-
- ret = IPMI_CC_OK;
-finish:
- sd_bus_error_free(&error);
- reply = sd_bus_message_unref(reply);
- free(busname);
-
- return ret;
}
OpenPOWER on IntegriCloud