blob: eabcd0afaad62c4071fab1bce4ff4575d27ae519 [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
17//#include <stdint.h>
18
Patrick Ventureda4a5dd2018-08-31 09:42:48 -070019#include "host-ipmid/oemopenbmc.hpp"
20#include "host-ipmid/oemrouter.hpp"
21
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 -080028#include "host-ipmid/ipmid-api.h"
Patrick Venture391b8b02018-03-08 08:31:13 -080029
30enum ManualSubCmd
31{
32 GET_CONTROL_STATE = 0,
33 SET_CONTROL_STATE = 1,
34 GET_FAILSAFE_STATE = 2,
35};
36
Patrick Ventureda4a5dd2018-08-31 09:42:48 -070037struct FanCtrlRequest
38{
Patrick Venture391b8b02018-03-08 08:31:13 -080039 uint8_t command;
40 uint8_t zone;
41} __attribute__((packed));
42
Patrick Ventureda4a5dd2018-08-31 09:42:48 -070043struct FanCtrlRequestSet
44{
Patrick Venture391b8b02018-03-08 08:31:13 -080045 uint8_t command;
46 uint8_t zone;
47 uint8_t value;
48} __attribute__((packed));
49
50static constexpr auto objectPath = "/xyz/openbmc_project/settings/fanctrl/zone";
51static constexpr auto busName = "xyz.openbmc_project.State.FanCtrl";
Patrick Venturedc3b7902018-03-24 10:41:19 -070052static constexpr auto intf = "xyz.openbmc_project.Control.Mode";
Patrick Venture391b8b02018-03-08 08:31:13 -080053static constexpr auto manualProperty = "Manual";
54static constexpr auto failsafeProperty = "FailSafe";
55static constexpr auto propertiesintf = "org.freedesktop.DBus.Properties";
56
57using Property = std::string;
58using Value = sdbusplus::message::variant<bool>;
59using PropertyMap = std::map<Property, Value>;
60
61/* The following was copied directly from my manual thread handler. */
62static std::string GetControlPath(int8_t zone)
63{
64 return std::string(objectPath) + std::to_string(zone);
65}
66
67/*
68 * busctl call xyz.openbmc_project.State.FanCtrl \
69 * /xyz/openbmc_project/settings/fanctrl/zone1 \
70 * org.freedesktop.DBus.Properties \
71 * GetAll \
72 * s \
Patrick Venturedc3b7902018-03-24 10:41:19 -070073 * xyz.openbmc_project.Control.Mode
Patrick Venture391b8b02018-03-08 08:31:13 -080074 * a{sv} 2 "Manual" b false "FailSafe" b false
75 */
76
Patrick Ventureda4a5dd2018-08-31 09:42:48 -070077static ipmi_ret_t GetFanCtrlProperty(uint8_t zoneId, bool* value,
78 const std::string& property)
Patrick Venture391b8b02018-03-08 08:31:13 -080079{
80 std::string path = GetControlPath(zoneId);
81
82 auto propertyReadBus = sdbusplus::bus::new_default();
Patrick Ventureda4a5dd2018-08-31 09:42:48 -070083 auto pimMsg = propertyReadBus.new_method_call(busName, path.c_str(),
84 propertiesintf, "GetAll");
Patrick Venture391b8b02018-03-08 08:31:13 -080085 pimMsg.append(intf);
86
87 auto valueResponseMsg = propertyReadBus.call(pimMsg);
88 if (valueResponseMsg.is_method_error())
89 {
90 return IPMI_CC_INVALID;
91 }
92
93 PropertyMap propMap;
94 valueResponseMsg.read(propMap);
95
96 if (propMap.size() != 2)
97 {
98 return IPMI_CC_INVALID;
99 }
100
101 *value = sdbusplus::message::variant_ns::get<bool>(propMap[property]);
102
103 return IPMI_CC_OK;
104}
105
Patrick Ventureda4a5dd2018-08-31 09:42:48 -0700106static ipmi_ret_t GetFailsafeModeState(const uint8_t* reqBuf, uint8_t* replyBuf,
107 size_t* dataLen)
Patrick Venture391b8b02018-03-08 08:31:13 -0800108{
109 ipmi_ret_t rc = IPMI_CC_OK;
110 bool current;
111
112 if (*dataLen < sizeof(struct FanCtrlRequest))
113 {
114 return IPMI_CC_INVALID;
115 }
116
117 const auto request =
Patrick Ventureda4a5dd2018-08-31 09:42:48 -0700118 reinterpret_cast<const struct FanCtrlRequest*>(&reqBuf[0]);
Patrick Venture391b8b02018-03-08 08:31:13 -0800119
120 rc = GetFanCtrlProperty(request->zone, &current, failsafeProperty);
121 if (rc)
122 {
123 return rc;
124 }
125
126 *replyBuf = (uint8_t)current;
127 *dataLen = sizeof(uint8_t);
128 return rc;
129}
130
131/*
132 * <method name="GetAll">
133 * <arg name="interface" direction="in" type="s"/>
134 * <arg name="properties" direction="out" type="a{sv}"/>
135 * </method>
136 */
Patrick Ventureda4a5dd2018-08-31 09:42:48 -0700137static ipmi_ret_t GetManualModeState(const uint8_t* reqBuf, uint8_t* replyBuf,
138 size_t* dataLen)
Patrick Venture391b8b02018-03-08 08:31:13 -0800139{
140 ipmi_ret_t rc = IPMI_CC_OK;
141 bool current;
142
143 if (*dataLen < sizeof(struct FanCtrlRequest))
144 {
145 return IPMI_CC_INVALID;
146 }
147
148 const auto request =
Patrick Ventureda4a5dd2018-08-31 09:42:48 -0700149 reinterpret_cast<const struct FanCtrlRequest*>(&reqBuf[0]);
Patrick Venture391b8b02018-03-08 08:31:13 -0800150
151 rc = GetFanCtrlProperty(request->zone, &current, manualProperty);
152 if (rc)
153 {
154 return rc;
155 }
156
157 *replyBuf = (uint8_t)current;
158 *dataLen = sizeof(uint8_t);
159 return rc;
160}
161
162/*
163 * <method name="Set">
164 * <arg name="interface" direction="in" type="s"/>
165 * <arg name="property" direction="in" type="s"/>
166 * <arg name="value" direction="in" type="v"/>
167 * </method>
168 */
Patrick Ventureda4a5dd2018-08-31 09:42:48 -0700169static ipmi_ret_t SetManualModeState(const uint8_t* reqBuf, uint8_t* replyBuf,
170 size_t* dataLen)
Patrick Venture391b8b02018-03-08 08:31:13 -0800171{
172 ipmi_ret_t rc = IPMI_CC_OK;
173 if (*dataLen < sizeof(struct FanCtrlRequestSet))
174 {
175 return IPMI_CC_INVALID;
176 }
177
178 using Value = sdbusplus::message::variant<bool>;
179
180 const auto request =
Patrick Ventureda4a5dd2018-08-31 09:42:48 -0700181 reinterpret_cast<const struct FanCtrlRequestSet*>(&reqBuf[0]);
Patrick Venture391b8b02018-03-08 08:31:13 -0800182
183 /* 0 is false, 1 is true */
184 bool setValue = static_cast<bool>(request->value);
Patrick Ventureda4a5dd2018-08-31 09:42:48 -0700185 Value v{setValue};
Patrick Venture391b8b02018-03-08 08:31:13 -0800186
187 auto PropertyWriteBus = sdbusplus::bus::new_default();
188
189 std::string path = GetControlPath(request->zone);
190
Patrick Ventureda4a5dd2018-08-31 09:42:48 -0700191 auto pimMsg = PropertyWriteBus.new_method_call(busName, path.c_str(),
192 propertiesintf, "Set");
Patrick Venture391b8b02018-03-08 08:31:13 -0800193 pimMsg.append(intf);
194 pimMsg.append(manualProperty);
195 pimMsg.append(v);
196 auto responseMsg = PropertyWriteBus.call(pimMsg);
197 if (responseMsg.is_method_error())
198 {
199 rc = IPMI_CC_INVALID;
200 }
201 /* TODO(venture): Should sanity check the result. */
202
203 return rc;
204}
205
206/* Three command packages: get, set true, set false */
Patrick Ventureda4a5dd2018-08-31 09:42:48 -0700207static ipmi_ret_t ManualModeControl(ipmi_cmd_t cmd, const uint8_t* reqBuf,
208 uint8_t* replyCmdBuf, size_t* dataLen)
Patrick Venture391b8b02018-03-08 08:31:13 -0800209{
210 ipmi_ret_t rc = IPMI_CC_OK;
211 // FanCtrlRequest is the smaller of the requests, so it's at a minimum.
212 if (*dataLen < sizeof(struct FanCtrlRequest))
213 {
214 return IPMI_CC_INVALID;
215 }
216
217 const auto request =
Patrick Ventureda4a5dd2018-08-31 09:42:48 -0700218 reinterpret_cast<const struct FanCtrlRequest*>(&reqBuf[0]);
Patrick Venture391b8b02018-03-08 08:31:13 -0800219
220 switch (request->command)
221 {
222 case GET_CONTROL_STATE:
223 return GetManualModeState(reqBuf, replyCmdBuf, dataLen);
224 case SET_CONTROL_STATE:
225 return SetManualModeState(reqBuf, replyCmdBuf, dataLen);
226 case GET_FAILSAFE_STATE:
227 return GetFailsafeModeState(reqBuf, replyCmdBuf, dataLen);
228 default:
229 rc = IPMI_CC_INVALID;
230 }
231
232 return rc;
233}
234
235void setupGlobalOemFanControl() __attribute__((constructor));
236
237void setupGlobalOemFanControl()
238{
Patrick Ventureba003432018-07-27 06:59:05 -0700239 oem::Router* router = oem::mutableRouter();
Patrick Venture391b8b02018-03-08 08:31:13 -0800240
241 fprintf(stderr,
242 "Registering OEM:[%#08X], Cmd:[%#04X] for Manual Zone Control\n",
Patrick Ventureda4a5dd2018-08-31 09:42:48 -0700243 oem::obmcOemNumber, oem::Cmd::fanManualCmd);
Patrick Venture391b8b02018-03-08 08:31:13 -0800244
Patrick Ventureda4a5dd2018-08-31 09:42:48 -0700245 router->registerHandler(oem::obmcOemNumber, oem::Cmd::fanManualCmd,
246 ManualModeControl);
Patrick Venture391b8b02018-03-08 08:31:13 -0800247}