blob: 73eec2044b2c17ba214362760d47277009a35073 [file] [log] [blame]
Patrick Venture391b8b02018-03-08 08:31:13 -08001/**
2 * Copyright 2017 Google Inc.
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
Patrick Venture07c3a802018-09-19 10:06:30 -070017#include <host-ipmid/ipmid-api.h>
Patrick Venture391b8b02018-03-08 08:31:13 -080018
Patrick Venture07c3a802018-09-19 10:06:30 -070019#include <host-ipmid/iana.hpp>
20#include <host-ipmid/oemopenbmc.hpp>
21#include <host-ipmid/oemrouter.hpp>
Patrick Venture391b8b02018-03-08 08:31:13 -080022#include <map>
Patrick Ventureda4a5dd2018-08-31 09:42:48 -070023#include <sdbusplus/bus.hpp>
24#include <sdbusplus/message.hpp>
Patrick Venture391b8b02018-03-08 08:31:13 -080025#include <string>
26#include <tuple>
27
Patrick Venture391b8b02018-03-08 08:31:13 -080028enum ManualSubCmd
29{
30 GET_CONTROL_STATE = 0,
31 SET_CONTROL_STATE = 1,
32 GET_FAILSAFE_STATE = 2,
33};
34
Patrick Ventureda4a5dd2018-08-31 09:42:48 -070035struct FanCtrlRequest
36{
Patrick Venture391b8b02018-03-08 08:31:13 -080037 uint8_t command;
38 uint8_t zone;
39} __attribute__((packed));
40
Patrick Ventureda4a5dd2018-08-31 09:42:48 -070041struct FanCtrlRequestSet
42{
Patrick Venture391b8b02018-03-08 08:31:13 -080043 uint8_t command;
44 uint8_t zone;
45 uint8_t value;
46} __attribute__((packed));
47
48static constexpr auto objectPath = "/xyz/openbmc_project/settings/fanctrl/zone";
49static constexpr auto busName = "xyz.openbmc_project.State.FanCtrl";
Patrick Venturedc3b7902018-03-24 10:41:19 -070050static constexpr auto intf = "xyz.openbmc_project.Control.Mode";
Patrick Venture391b8b02018-03-08 08:31:13 -080051static constexpr auto manualProperty = "Manual";
52static constexpr auto failsafeProperty = "FailSafe";
53static constexpr auto propertiesintf = "org.freedesktop.DBus.Properties";
54
55using Property = std::string;
56using Value = sdbusplus::message::variant<bool>;
57using PropertyMap = std::map<Property, Value>;
58
59/* The following was copied directly from my manual thread handler. */
Patrick Venture7af157b2018-10-30 11:24:40 -070060static std::string getControlPath(int8_t zone)
Patrick Venture391b8b02018-03-08 08:31:13 -080061{
62 return std::string(objectPath) + std::to_string(zone);
63}
64
65/*
66 * busctl call xyz.openbmc_project.State.FanCtrl \
67 * /xyz/openbmc_project/settings/fanctrl/zone1 \
68 * org.freedesktop.DBus.Properties \
69 * GetAll \
70 * s \
Patrick Venturedc3b7902018-03-24 10:41:19 -070071 * xyz.openbmc_project.Control.Mode
Patrick Venture391b8b02018-03-08 08:31:13 -080072 * a{sv} 2 "Manual" b false "FailSafe" b false
73 */
74
Patrick Venture7af157b2018-10-30 11:24:40 -070075static ipmi_ret_t getFanCtrlProperty(uint8_t zoneId, bool* value,
Patrick Ventureda4a5dd2018-08-31 09:42:48 -070076 const std::string& property)
Patrick Venture391b8b02018-03-08 08:31:13 -080077{
Patrick Venture7af157b2018-10-30 11:24:40 -070078 std::string path = getControlPath(zoneId);
Patrick Venture391b8b02018-03-08 08:31:13 -080079
James Feist9fa90c12019-01-11 15:35:22 -080080 auto propertyReadBus = sdbusplus::bus::new_system();
Patrick Ventureda4a5dd2018-08-31 09:42:48 -070081 auto pimMsg = propertyReadBus.new_method_call(busName, path.c_str(),
82 propertiesintf, "GetAll");
Patrick Venture391b8b02018-03-08 08:31:13 -080083 pimMsg.append(intf);
84
Patrick Ventureacecf6b2018-09-06 17:56:41 -070085 try
86 {
Patrick Ventureacecf6b2018-09-06 17:56:41 -070087 PropertyMap propMap;
Patrick Venture8f179142018-09-10 09:24:12 -070088
89 /* a method could error but the call not error. */
90 auto valueResponseMsg = propertyReadBus.call(pimMsg);
Patrick Venture8f179142018-09-10 09:24:12 -070091
Patrick Ventureacecf6b2018-09-06 17:56:41 -070092 valueResponseMsg.read(propMap);
93
94 *value = sdbusplus::message::variant_ns::get<bool>(propMap[property]);
95 }
96 catch (const sdbusplus::exception::SdBusError& ex)
Patrick Venture391b8b02018-03-08 08:31:13 -080097 {
98 return IPMI_CC_INVALID;
99 }
100
Patrick Venture391b8b02018-03-08 08:31:13 -0800101 return IPMI_CC_OK;
102}
103
Patrick Venture7af157b2018-10-30 11:24:40 -0700104static ipmi_ret_t getFailsafeModeState(const uint8_t* reqBuf, uint8_t* replyBuf,
Patrick Ventureda4a5dd2018-08-31 09:42:48 -0700105 size_t* dataLen)
Patrick Venture391b8b02018-03-08 08:31:13 -0800106{
107 ipmi_ret_t rc = IPMI_CC_OK;
108 bool current;
109
110 if (*dataLen < sizeof(struct FanCtrlRequest))
111 {
112 return IPMI_CC_INVALID;
113 }
114
115 const auto request =
Patrick Ventureda4a5dd2018-08-31 09:42:48 -0700116 reinterpret_cast<const struct FanCtrlRequest*>(&reqBuf[0]);
Patrick Venture391b8b02018-03-08 08:31:13 -0800117
Patrick Venture7af157b2018-10-30 11:24:40 -0700118 rc = getFanCtrlProperty(request->zone, &current, failsafeProperty);
Patrick Venture391b8b02018-03-08 08:31:13 -0800119 if (rc)
120 {
121 return rc;
122 }
123
124 *replyBuf = (uint8_t)current;
125 *dataLen = sizeof(uint8_t);
126 return rc;
127}
128
129/*
130 * <method name="GetAll">
131 * <arg name="interface" direction="in" type="s"/>
132 * <arg name="properties" direction="out" type="a{sv}"/>
133 * </method>
134 */
Patrick Venture7af157b2018-10-30 11:24:40 -0700135static ipmi_ret_t getManualModeState(const uint8_t* reqBuf, uint8_t* replyBuf,
Patrick Ventureda4a5dd2018-08-31 09:42:48 -0700136 size_t* dataLen)
Patrick Venture391b8b02018-03-08 08:31:13 -0800137{
138 ipmi_ret_t rc = IPMI_CC_OK;
139 bool current;
140
141 if (*dataLen < sizeof(struct FanCtrlRequest))
142 {
143 return IPMI_CC_INVALID;
144 }
145
146 const auto request =
Patrick Ventureda4a5dd2018-08-31 09:42:48 -0700147 reinterpret_cast<const struct FanCtrlRequest*>(&reqBuf[0]);
Patrick Venture391b8b02018-03-08 08:31:13 -0800148
Patrick Venture7af157b2018-10-30 11:24:40 -0700149 rc = getFanCtrlProperty(request->zone, &current, manualProperty);
Patrick Venture391b8b02018-03-08 08:31:13 -0800150 if (rc)
151 {
152 return rc;
153 }
154
155 *replyBuf = (uint8_t)current;
156 *dataLen = sizeof(uint8_t);
157 return rc;
158}
159
160/*
161 * <method name="Set">
162 * <arg name="interface" direction="in" type="s"/>
163 * <arg name="property" direction="in" type="s"/>
164 * <arg name="value" direction="in" type="v"/>
165 * </method>
166 */
Patrick Venture7af157b2018-10-30 11:24:40 -0700167static ipmi_ret_t setManualModeState(const uint8_t* reqBuf, uint8_t* replyBuf,
Patrick Ventureda4a5dd2018-08-31 09:42:48 -0700168 size_t* dataLen)
Patrick Venture391b8b02018-03-08 08:31:13 -0800169{
170 ipmi_ret_t rc = IPMI_CC_OK;
171 if (*dataLen < sizeof(struct FanCtrlRequestSet))
172 {
173 return IPMI_CC_INVALID;
174 }
175
176 using Value = sdbusplus::message::variant<bool>;
177
178 const auto request =
Patrick Ventureda4a5dd2018-08-31 09:42:48 -0700179 reinterpret_cast<const struct FanCtrlRequestSet*>(&reqBuf[0]);
Patrick Venture391b8b02018-03-08 08:31:13 -0800180
181 /* 0 is false, 1 is true */
182 bool setValue = static_cast<bool>(request->value);
Patrick Ventureda4a5dd2018-08-31 09:42:48 -0700183 Value v{setValue};
Patrick Venture391b8b02018-03-08 08:31:13 -0800184
James Feist9fa90c12019-01-11 15:35:22 -0800185 auto PropertyWriteBus = sdbusplus::bus::new_system();
Patrick Venture391b8b02018-03-08 08:31:13 -0800186
Patrick Venture7af157b2018-10-30 11:24:40 -0700187 std::string path = getControlPath(request->zone);
Patrick Venture391b8b02018-03-08 08:31:13 -0800188
Patrick Ventureda4a5dd2018-08-31 09:42:48 -0700189 auto pimMsg = PropertyWriteBus.new_method_call(busName, path.c_str(),
190 propertiesintf, "Set");
Patrick Venture391b8b02018-03-08 08:31:13 -0800191 pimMsg.append(intf);
192 pimMsg.append(manualProperty);
193 pimMsg.append(v);
Patrick Ventureacecf6b2018-09-06 17:56:41 -0700194
195 try
196 {
197 PropertyWriteBus.call_noreply(pimMsg);
198 }
199 catch (const sdbusplus::exception::SdBusError& ex)
Patrick Venture391b8b02018-03-08 08:31:13 -0800200 {
201 rc = IPMI_CC_INVALID;
202 }
203 /* TODO(venture): Should sanity check the result. */
204
205 return rc;
206}
207
208/* Three command packages: get, set true, set false */
Patrick Venture7af157b2018-10-30 11:24:40 -0700209static ipmi_ret_t manualModeControl(ipmi_cmd_t cmd, const uint8_t* reqBuf,
Patrick Ventureda4a5dd2018-08-31 09:42:48 -0700210 uint8_t* replyCmdBuf, size_t* dataLen)
Patrick Venture391b8b02018-03-08 08:31:13 -0800211{
212 ipmi_ret_t rc = IPMI_CC_OK;
213 // FanCtrlRequest is the smaller of the requests, so it's at a minimum.
214 if (*dataLen < sizeof(struct FanCtrlRequest))
215 {
216 return IPMI_CC_INVALID;
217 }
218
219 const auto request =
Patrick Ventureda4a5dd2018-08-31 09:42:48 -0700220 reinterpret_cast<const struct FanCtrlRequest*>(&reqBuf[0]);
Patrick Venture391b8b02018-03-08 08:31:13 -0800221
222 switch (request->command)
223 {
224 case GET_CONTROL_STATE:
Patrick Venture7af157b2018-10-30 11:24:40 -0700225 return getManualModeState(reqBuf, replyCmdBuf, dataLen);
Patrick Venture391b8b02018-03-08 08:31:13 -0800226 case SET_CONTROL_STATE:
Patrick Venture7af157b2018-10-30 11:24:40 -0700227 return setManualModeState(reqBuf, replyCmdBuf, dataLen);
Patrick Venture391b8b02018-03-08 08:31:13 -0800228 case GET_FAILSAFE_STATE:
Patrick Venture7af157b2018-10-30 11:24:40 -0700229 return getFailsafeModeState(reqBuf, replyCmdBuf, dataLen);
Patrick Venture391b8b02018-03-08 08:31:13 -0800230 default:
231 rc = IPMI_CC_INVALID;
232 }
233
234 return rc;
235}
236
237void setupGlobalOemFanControl() __attribute__((constructor));
238
239void setupGlobalOemFanControl()
240{
Patrick Ventureba003432018-07-27 06:59:05 -0700241 oem::Router* router = oem::mutableRouter();
Patrick Venture391b8b02018-03-08 08:31:13 -0800242
243 fprintf(stderr,
244 "Registering OEM:[%#08X], Cmd:[%#04X] for Manual Zone Control\n",
Patrick Ventureda4a5dd2018-08-31 09:42:48 -0700245 oem::obmcOemNumber, oem::Cmd::fanManualCmd);
Patrick Venture391b8b02018-03-08 08:31:13 -0800246
Patrick Ventureda4a5dd2018-08-31 09:42:48 -0700247 router->registerHandler(oem::obmcOemNumber, oem::Cmd::fanManualCmd,
Patrick Venture7af157b2018-10-30 11:24:40 -0700248 manualModeControl);
Patrick Venture391b8b02018-03-08 08:31:13 -0800249}