diff options
author | Patrick Venture <venture@google.com> | 2018-03-08 08:31:13 -0800 |
---|---|---|
committer | Patrick Venture <venture@google.com> | 2018-03-08 08:31:13 -0800 |
commit | 391b8b0fc41891b5d1c2ccfb997ef53133092302 (patch) | |
tree | c5168dc9329b7003c89771497e871d8941d34960 /ipmi | |
parent | 863b9246dd43464da91ec789deaa42d15c45f84d (diff) | |
download | phosphor-pid-control-391b8b0fc41891b5d1c2ccfb997ef53133092302.tar.gz phosphor-pid-control-391b8b0fc41891b5d1c2ccfb997ef53133092302.zip |
The OEM IPMI interface for status
This lets one get/set various aspects of the control daemon,
including whether it's fallen into fail-safe mode, or whether a
zone is in manual mode. Manual mode in this implementation is
zone specific and not fan specific.
Change-Id: I1611fefad198b64c28a780073674896d6efbf877
Signed-off-by: Patrick Venture <venture@google.com>
Diffstat (limited to 'ipmi')
-rw-r--r-- | ipmi/README | 13 | ||||
-rw-r--r-- | ipmi/manualcmds.cpp | 256 | ||||
-rw-r--r-- | ipmi/manualcmds.hpp | 2 |
3 files changed, 271 insertions, 0 deletions
diff --git a/ipmi/README b/ipmi/README new file mode 100644 index 0000000..8bf37cf --- /dev/null +++ b/ipmi/README @@ -0,0 +1,13 @@ +This holds the source for the library we install to handle the manual control +OEM IPMI command. + +The command is a simple series of bytes: +[0] = Subcommand, Get(0) or Set(1), Get(2) for fail-safe mode. +[1] = ZoneId +[2] = Value if Set + +If Value == 1, then ManualMode is True and enabled, otherwise it's in normal +mode. + +If Value == 1 (and Subcommand == 2), Failsafe mode is enabled, otherwise it's +not. diff --git a/ipmi/manualcmds.cpp b/ipmi/manualcmds.cpp new file mode 100644 index 0000000..2d2d53b --- /dev/null +++ b/ipmi/manualcmds.cpp @@ -0,0 +1,256 @@ +/** + * Copyright 2017 Google Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +//#include <stdint.h> + +#include <map> +#include <string> +#include <tuple> + +#include <sdbusplus/bus.hpp> +#include <sdbusplus/message.hpp> + +#include "host-ipmid/ipmid-api.h" +#include "host-ipmid/oemopenbmc.hpp" +#include "host-ipmid/oemrouter.hpp" + +enum ManualSubCmd +{ + GET_CONTROL_STATE = 0, + SET_CONTROL_STATE = 1, + GET_FAILSAFE_STATE = 2, +}; + +struct FanCtrlRequest { + uint8_t command; + uint8_t zone; +} __attribute__((packed)); + +struct FanCtrlRequestSet { + uint8_t command; + uint8_t zone; + uint8_t value; +} __attribute__((packed)); + +static constexpr auto objectPath = "/xyz/openbmc_project/settings/fanctrl/zone"; +static constexpr auto busName = "xyz.openbmc_project.State.FanCtrl"; +static constexpr auto intf = "xyz.openbmc_project.Control.FanCtrl.Mode"; +static constexpr auto manualProperty = "Manual"; +static constexpr auto failsafeProperty = "FailSafe"; +static constexpr auto propertiesintf = "org.freedesktop.DBus.Properties"; + +using Property = std::string; +using Value = sdbusplus::message::variant<bool>; +using PropertyMap = std::map<Property, Value>; + +/* The following was copied directly from my manual thread handler. */ +static std::string GetControlPath(int8_t zone) +{ + return std::string(objectPath) + std::to_string(zone); +} + +/* + * busctl call xyz.openbmc_project.State.FanCtrl \ + * /xyz/openbmc_project/settings/fanctrl/zone1 \ + * org.freedesktop.DBus.Properties \ + * GetAll \ + * s \ + * xyz.openbmc_project.Control.FanCtrl.Mode + * a{sv} 2 "Manual" b false "FailSafe" b false + */ + +static ipmi_ret_t +GetFanCtrlProperty(uint8_t zoneId, bool *value, const std::string &property) +{ + std::string path = GetControlPath(zoneId); + + auto propertyReadBus = sdbusplus::bus::new_default(); + auto pimMsg = propertyReadBus.new_method_call(busName, + path.c_str(), + propertiesintf, + "GetAll"); + pimMsg.append(intf); + + auto valueResponseMsg = propertyReadBus.call(pimMsg); + if (valueResponseMsg.is_method_error()) + { + return IPMI_CC_INVALID; + } + + PropertyMap propMap; + valueResponseMsg.read(propMap); + + if (propMap.size() != 2) + { + return IPMI_CC_INVALID; + } + + *value = sdbusplus::message::variant_ns::get<bool>(propMap[property]); + + return IPMI_CC_OK; +} + +static ipmi_ret_t +GetFailsafeModeState(const uint8_t* reqBuf, uint8_t* replyBuf, size_t* dataLen) +{ + ipmi_ret_t rc = IPMI_CC_OK; + bool current; + + if (*dataLen < sizeof(struct FanCtrlRequest)) + { + return IPMI_CC_INVALID; + } + + const auto request = + reinterpret_cast<const struct FanCtrlRequest*>(&reqBuf[0]); + + rc = GetFanCtrlProperty(request->zone, ¤t, failsafeProperty); + if (rc) + { + return rc; + } + + *replyBuf = (uint8_t)current; + *dataLen = sizeof(uint8_t); + return rc; +} + +/* + * <method name="GetAll"> + * <arg name="interface" direction="in" type="s"/> + * <arg name="properties" direction="out" type="a{sv}"/> + * </method> + */ +static ipmi_ret_t +GetManualModeState(const uint8_t* reqBuf, uint8_t* replyBuf, size_t* dataLen) +{ + ipmi_ret_t rc = IPMI_CC_OK; + bool current; + + if (*dataLen < sizeof(struct FanCtrlRequest)) + { + return IPMI_CC_INVALID; + } + + const auto request = + reinterpret_cast<const struct FanCtrlRequest*>(&reqBuf[0]); + + rc = GetFanCtrlProperty(request->zone, ¤t, manualProperty); + if (rc) + { + return rc; + } + + *replyBuf = (uint8_t)current; + *dataLen = sizeof(uint8_t); + return rc; +} + +/* + * <method name="Set"> + * <arg name="interface" direction="in" type="s"/> + * <arg name="property" direction="in" type="s"/> + * <arg name="value" direction="in" type="v"/> + * </method> + */ +static ipmi_ret_t +SetManualModeState(const uint8_t* reqBuf, uint8_t* replyBuf, size_t* dataLen) +{ + ipmi_ret_t rc = IPMI_CC_OK; + if (*dataLen < sizeof(struct FanCtrlRequestSet)) + { + return IPMI_CC_INVALID; + } + + using Value = sdbusplus::message::variant<bool>; + + const auto request = + reinterpret_cast<const struct FanCtrlRequestSet*>(&reqBuf[0]); + + /* 0 is false, 1 is true */ + bool setValue = static_cast<bool>(request->value); + Value v {setValue}; + + auto PropertyWriteBus = sdbusplus::bus::new_default(); + + std::string path = GetControlPath(request->zone); + + auto pimMsg = PropertyWriteBus.new_method_call(busName, + path.c_str(), + propertiesintf, + "Set"); + pimMsg.append(intf); + pimMsg.append(manualProperty); + pimMsg.append(v); + auto responseMsg = PropertyWriteBus.call(pimMsg); + if (responseMsg.is_method_error()) + { + rc = IPMI_CC_INVALID; + } + /* TODO(venture): Should sanity check the result. */ + + return rc; +} + +/* Three command packages: get, set true, set false */ +static ipmi_ret_t +ManualModeControl( + ipmi_cmd_t cmd, + const uint8_t* reqBuf, + uint8_t* replyCmdBuf, + size_t* dataLen) +{ + ipmi_ret_t rc = IPMI_CC_OK; + // FanCtrlRequest is the smaller of the requests, so it's at a minimum. + if (*dataLen < sizeof(struct FanCtrlRequest)) + { + return IPMI_CC_INVALID; + } + + const auto request = + reinterpret_cast<const struct FanCtrlRequest*>(&reqBuf[0]); + + switch (request->command) + { + case GET_CONTROL_STATE: + return GetManualModeState(reqBuf, replyCmdBuf, dataLen); + case SET_CONTROL_STATE: + return SetManualModeState(reqBuf, replyCmdBuf, dataLen); + case GET_FAILSAFE_STATE: + return GetFailsafeModeState(reqBuf, replyCmdBuf, dataLen); + default: + rc = IPMI_CC_INVALID; + } + + return rc; +} + +void setupGlobalOemFanControl() __attribute__((constructor)); + +void setupGlobalOemFanControl() +{ + ipmid::OemRouter* oemRouter = ipmid::mutableOemRouter(); + + fprintf(stderr, + "Registering OEM:[%#08X], Cmd:[%#04X] for Manual Zone Control\n", + ipmid::oem::openbmc::obmcOemNumber, + ipmid::oem::openbmc::OemCmd::fanManualCmd); + + oemRouter->registerHandler( + ipmid::oem::openbmc::obmcOemNumber, + ipmid::oem::openbmc::OemCmd::fanManualCmd, + ManualModeControl); +} diff --git a/ipmi/manualcmds.hpp b/ipmi/manualcmds.hpp new file mode 100644 index 0000000..3f59c93 --- /dev/null +++ b/ipmi/manualcmds.hpp @@ -0,0 +1,2 @@ +#pragma once + |