blob: a82dfa650d143da53f9610098d91869cc9557788 [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
Patrick Ventureacecf6b2018-09-06 17:56:41 -070087 try
88 {
Patrick Ventureacecf6b2018-09-06 17:56:41 -070089 PropertyMap propMap;
Patrick Venture8f179142018-09-10 09:24:12 -070090
91 /* a method could error but the call not error. */
92 auto valueResponseMsg = propertyReadBus.call(pimMsg);
93 if (valueResponseMsg.is_method_error())
94 {
95 return IPMI_CC_INVALID;
96 }
97
Patrick Ventureacecf6b2018-09-06 17:56:41 -070098 valueResponseMsg.read(propMap);
99
100 *value = sdbusplus::message::variant_ns::get<bool>(propMap[property]);
101 }
102 catch (const sdbusplus::exception::SdBusError& ex)
Patrick Venture391b8b02018-03-08 08:31:13 -0800103 {
104 return IPMI_CC_INVALID;
105 }
106
Patrick Venture391b8b02018-03-08 08:31:13 -0800107 return IPMI_CC_OK;
108}
109
Patrick Ventureda4a5dd2018-08-31 09:42:48 -0700110static ipmi_ret_t GetFailsafeModeState(const uint8_t* reqBuf, uint8_t* replyBuf,
111 size_t* dataLen)
Patrick Venture391b8b02018-03-08 08:31:13 -0800112{
113 ipmi_ret_t rc = IPMI_CC_OK;
114 bool current;
115
116 if (*dataLen < sizeof(struct FanCtrlRequest))
117 {
118 return IPMI_CC_INVALID;
119 }
120
121 const auto request =
Patrick Ventureda4a5dd2018-08-31 09:42:48 -0700122 reinterpret_cast<const struct FanCtrlRequest*>(&reqBuf[0]);
Patrick Venture391b8b02018-03-08 08:31:13 -0800123
124 rc = GetFanCtrlProperty(request->zone, &current, failsafeProperty);
125 if (rc)
126 {
127 return rc;
128 }
129
130 *replyBuf = (uint8_t)current;
131 *dataLen = sizeof(uint8_t);
132 return rc;
133}
134
135/*
136 * <method name="GetAll">
137 * <arg name="interface" direction="in" type="s"/>
138 * <arg name="properties" direction="out" type="a{sv}"/>
139 * </method>
140 */
Patrick Ventureda4a5dd2018-08-31 09:42:48 -0700141static ipmi_ret_t GetManualModeState(const uint8_t* reqBuf, uint8_t* replyBuf,
142 size_t* dataLen)
Patrick Venture391b8b02018-03-08 08:31:13 -0800143{
144 ipmi_ret_t rc = IPMI_CC_OK;
145 bool current;
146
147 if (*dataLen < sizeof(struct FanCtrlRequest))
148 {
149 return IPMI_CC_INVALID;
150 }
151
152 const auto request =
Patrick Ventureda4a5dd2018-08-31 09:42:48 -0700153 reinterpret_cast<const struct FanCtrlRequest*>(&reqBuf[0]);
Patrick Venture391b8b02018-03-08 08:31:13 -0800154
155 rc = GetFanCtrlProperty(request->zone, &current, manualProperty);
156 if (rc)
157 {
158 return rc;
159 }
160
161 *replyBuf = (uint8_t)current;
162 *dataLen = sizeof(uint8_t);
163 return rc;
164}
165
166/*
167 * <method name="Set">
168 * <arg name="interface" direction="in" type="s"/>
169 * <arg name="property" direction="in" type="s"/>
170 * <arg name="value" direction="in" type="v"/>
171 * </method>
172 */
Patrick Ventureda4a5dd2018-08-31 09:42:48 -0700173static ipmi_ret_t SetManualModeState(const uint8_t* reqBuf, uint8_t* replyBuf,
174 size_t* dataLen)
Patrick Venture391b8b02018-03-08 08:31:13 -0800175{
176 ipmi_ret_t rc = IPMI_CC_OK;
177 if (*dataLen < sizeof(struct FanCtrlRequestSet))
178 {
179 return IPMI_CC_INVALID;
180 }
181
182 using Value = sdbusplus::message::variant<bool>;
183
184 const auto request =
Patrick Ventureda4a5dd2018-08-31 09:42:48 -0700185 reinterpret_cast<const struct FanCtrlRequestSet*>(&reqBuf[0]);
Patrick Venture391b8b02018-03-08 08:31:13 -0800186
187 /* 0 is false, 1 is true */
188 bool setValue = static_cast<bool>(request->value);
Patrick Ventureda4a5dd2018-08-31 09:42:48 -0700189 Value v{setValue};
Patrick Venture391b8b02018-03-08 08:31:13 -0800190
191 auto PropertyWriteBus = sdbusplus::bus::new_default();
192
193 std::string path = GetControlPath(request->zone);
194
Patrick Ventureda4a5dd2018-08-31 09:42:48 -0700195 auto pimMsg = PropertyWriteBus.new_method_call(busName, path.c_str(),
196 propertiesintf, "Set");
Patrick Venture391b8b02018-03-08 08:31:13 -0800197 pimMsg.append(intf);
198 pimMsg.append(manualProperty);
199 pimMsg.append(v);
Patrick Ventureacecf6b2018-09-06 17:56:41 -0700200
201 try
202 {
203 PropertyWriteBus.call_noreply(pimMsg);
204 }
205 catch (const sdbusplus::exception::SdBusError& ex)
Patrick Venture391b8b02018-03-08 08:31:13 -0800206 {
207 rc = IPMI_CC_INVALID;
208 }
209 /* TODO(venture): Should sanity check the result. */
210
211 return rc;
212}
213
214/* Three command packages: get, set true, set false */
Patrick Ventureda4a5dd2018-08-31 09:42:48 -0700215static ipmi_ret_t ManualModeControl(ipmi_cmd_t cmd, const uint8_t* reqBuf,
216 uint8_t* replyCmdBuf, size_t* dataLen)
Patrick Venture391b8b02018-03-08 08:31:13 -0800217{
218 ipmi_ret_t rc = IPMI_CC_OK;
219 // FanCtrlRequest is the smaller of the requests, so it's at a minimum.
220 if (*dataLen < sizeof(struct FanCtrlRequest))
221 {
222 return IPMI_CC_INVALID;
223 }
224
225 const auto request =
Patrick Ventureda4a5dd2018-08-31 09:42:48 -0700226 reinterpret_cast<const struct FanCtrlRequest*>(&reqBuf[0]);
Patrick Venture391b8b02018-03-08 08:31:13 -0800227
228 switch (request->command)
229 {
230 case GET_CONTROL_STATE:
231 return GetManualModeState(reqBuf, replyCmdBuf, dataLen);
232 case SET_CONTROL_STATE:
233 return SetManualModeState(reqBuf, replyCmdBuf, dataLen);
234 case GET_FAILSAFE_STATE:
235 return GetFailsafeModeState(reqBuf, replyCmdBuf, dataLen);
236 default:
237 rc = IPMI_CC_INVALID;
238 }
239
240 return rc;
241}
242
243void setupGlobalOemFanControl() __attribute__((constructor));
244
245void setupGlobalOemFanControl()
246{
Patrick Ventureba003432018-07-27 06:59:05 -0700247 oem::Router* router = oem::mutableRouter();
Patrick Venture391b8b02018-03-08 08:31:13 -0800248
249 fprintf(stderr,
250 "Registering OEM:[%#08X], Cmd:[%#04X] for Manual Zone Control\n",
Patrick Ventureda4a5dd2018-08-31 09:42:48 -0700251 oem::obmcOemNumber, oem::Cmd::fanManualCmd);
Patrick Venture391b8b02018-03-08 08:31:13 -0800252
Patrick Ventureda4a5dd2018-08-31 09:42:48 -0700253 router->registerHandler(oem::obmcOemNumber, oem::Cmd::fanManualCmd,
254 ManualModeControl);
Patrick Venture391b8b02018-03-08 08:31:13 -0800255}