blob: 45610cb265b2a0d1fcd9149fb500d3c0ce0d4036 [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. */
60static std::string GetControlPath(int8_t zone)
61{
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 Ventureda4a5dd2018-08-31 09:42:48 -070075static ipmi_ret_t GetFanCtrlProperty(uint8_t zoneId, bool* value,
76 const std::string& property)
Patrick Venture391b8b02018-03-08 08:31:13 -080077{
78 std::string path = GetControlPath(zoneId);
79
80 auto propertyReadBus = sdbusplus::bus::new_default();
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);
91 if (valueResponseMsg.is_method_error())
92 {
93 return IPMI_CC_INVALID;
94 }
95
Patrick Ventureacecf6b2018-09-06 17:56:41 -070096 valueResponseMsg.read(propMap);
97
98 *value = sdbusplus::message::variant_ns::get<bool>(propMap[property]);
99 }
100 catch (const sdbusplus::exception::SdBusError& ex)
Patrick Venture391b8b02018-03-08 08:31:13 -0800101 {
102 return IPMI_CC_INVALID;
103 }
104
Patrick Venture391b8b02018-03-08 08:31:13 -0800105 return IPMI_CC_OK;
106}
107
Patrick Ventureda4a5dd2018-08-31 09:42:48 -0700108static ipmi_ret_t GetFailsafeModeState(const uint8_t* reqBuf, uint8_t* replyBuf,
109 size_t* dataLen)
Patrick Venture391b8b02018-03-08 08:31:13 -0800110{
111 ipmi_ret_t rc = IPMI_CC_OK;
112 bool current;
113
114 if (*dataLen < sizeof(struct FanCtrlRequest))
115 {
116 return IPMI_CC_INVALID;
117 }
118
119 const auto request =
Patrick Ventureda4a5dd2018-08-31 09:42:48 -0700120 reinterpret_cast<const struct FanCtrlRequest*>(&reqBuf[0]);
Patrick Venture391b8b02018-03-08 08:31:13 -0800121
122 rc = GetFanCtrlProperty(request->zone, &current, failsafeProperty);
123 if (rc)
124 {
125 return rc;
126 }
127
128 *replyBuf = (uint8_t)current;
129 *dataLen = sizeof(uint8_t);
130 return rc;
131}
132
133/*
134 * <method name="GetAll">
135 * <arg name="interface" direction="in" type="s"/>
136 * <arg name="properties" direction="out" type="a{sv}"/>
137 * </method>
138 */
Patrick Ventureda4a5dd2018-08-31 09:42:48 -0700139static ipmi_ret_t GetManualModeState(const uint8_t* reqBuf, uint8_t* replyBuf,
140 size_t* dataLen)
Patrick Venture391b8b02018-03-08 08:31:13 -0800141{
142 ipmi_ret_t rc = IPMI_CC_OK;
143 bool current;
144
145 if (*dataLen < sizeof(struct FanCtrlRequest))
146 {
147 return IPMI_CC_INVALID;
148 }
149
150 const auto request =
Patrick Ventureda4a5dd2018-08-31 09:42:48 -0700151 reinterpret_cast<const struct FanCtrlRequest*>(&reqBuf[0]);
Patrick Venture391b8b02018-03-08 08:31:13 -0800152
153 rc = GetFanCtrlProperty(request->zone, &current, manualProperty);
154 if (rc)
155 {
156 return rc;
157 }
158
159 *replyBuf = (uint8_t)current;
160 *dataLen = sizeof(uint8_t);
161 return rc;
162}
163
164/*
165 * <method name="Set">
166 * <arg name="interface" direction="in" type="s"/>
167 * <arg name="property" direction="in" type="s"/>
168 * <arg name="value" direction="in" type="v"/>
169 * </method>
170 */
Patrick Ventureda4a5dd2018-08-31 09:42:48 -0700171static ipmi_ret_t SetManualModeState(const uint8_t* reqBuf, uint8_t* replyBuf,
172 size_t* dataLen)
Patrick Venture391b8b02018-03-08 08:31:13 -0800173{
174 ipmi_ret_t rc = IPMI_CC_OK;
175 if (*dataLen < sizeof(struct FanCtrlRequestSet))
176 {
177 return IPMI_CC_INVALID;
178 }
179
180 using Value = sdbusplus::message::variant<bool>;
181
182 const auto request =
Patrick Ventureda4a5dd2018-08-31 09:42:48 -0700183 reinterpret_cast<const struct FanCtrlRequestSet*>(&reqBuf[0]);
Patrick Venture391b8b02018-03-08 08:31:13 -0800184
185 /* 0 is false, 1 is true */
186 bool setValue = static_cast<bool>(request->value);
Patrick Ventureda4a5dd2018-08-31 09:42:48 -0700187 Value v{setValue};
Patrick Venture391b8b02018-03-08 08:31:13 -0800188
189 auto PropertyWriteBus = sdbusplus::bus::new_default();
190
191 std::string path = GetControlPath(request->zone);
192
Patrick Ventureda4a5dd2018-08-31 09:42:48 -0700193 auto pimMsg = PropertyWriteBus.new_method_call(busName, path.c_str(),
194 propertiesintf, "Set");
Patrick Venture391b8b02018-03-08 08:31:13 -0800195 pimMsg.append(intf);
196 pimMsg.append(manualProperty);
197 pimMsg.append(v);
Patrick Ventureacecf6b2018-09-06 17:56:41 -0700198
199 try
200 {
201 PropertyWriteBus.call_noreply(pimMsg);
202 }
203 catch (const sdbusplus::exception::SdBusError& ex)
Patrick Venture391b8b02018-03-08 08:31:13 -0800204 {
205 rc = IPMI_CC_INVALID;
206 }
207 /* TODO(venture): Should sanity check the result. */
208
209 return rc;
210}
211
212/* Three command packages: get, set true, set false */
Patrick Ventureda4a5dd2018-08-31 09:42:48 -0700213static ipmi_ret_t ManualModeControl(ipmi_cmd_t cmd, const uint8_t* reqBuf,
214 uint8_t* replyCmdBuf, size_t* dataLen)
Patrick Venture391b8b02018-03-08 08:31:13 -0800215{
216 ipmi_ret_t rc = IPMI_CC_OK;
217 // FanCtrlRequest is the smaller of the requests, so it's at a minimum.
218 if (*dataLen < sizeof(struct FanCtrlRequest))
219 {
220 return IPMI_CC_INVALID;
221 }
222
223 const auto request =
Patrick Ventureda4a5dd2018-08-31 09:42:48 -0700224 reinterpret_cast<const struct FanCtrlRequest*>(&reqBuf[0]);
Patrick Venture391b8b02018-03-08 08:31:13 -0800225
226 switch (request->command)
227 {
228 case GET_CONTROL_STATE:
229 return GetManualModeState(reqBuf, replyCmdBuf, dataLen);
230 case SET_CONTROL_STATE:
231 return SetManualModeState(reqBuf, replyCmdBuf, dataLen);
232 case GET_FAILSAFE_STATE:
233 return GetFailsafeModeState(reqBuf, replyCmdBuf, dataLen);
234 default:
235 rc = IPMI_CC_INVALID;
236 }
237
238 return rc;
239}
240
241void setupGlobalOemFanControl() __attribute__((constructor));
242
243void setupGlobalOemFanControl()
244{
Patrick Ventureba003432018-07-27 06:59:05 -0700245 oem::Router* router = oem::mutableRouter();
Patrick Venture391b8b02018-03-08 08:31:13 -0800246
247 fprintf(stderr,
248 "Registering OEM:[%#08X], Cmd:[%#04X] for Manual Zone Control\n",
Patrick Ventureda4a5dd2018-08-31 09:42:48 -0700249 oem::obmcOemNumber, oem::Cmd::fanManualCmd);
Patrick Venture391b8b02018-03-08 08:31:13 -0800250
Patrick Ventureda4a5dd2018-08-31 09:42:48 -0700251 router->registerHandler(oem::obmcOemNumber, oem::Cmd::fanManualCmd,
252 ManualModeControl);
Patrick Venture391b8b02018-03-08 08:31:13 -0800253}