blob: 415262e9e359cdf9c726923b9f7d1276655c8e3f [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
William A. Kennington III331143c2019-02-07 15:52:44 -080017#include <ipmid/api.h>
Patrick Venture391b8b02018-03-08 08:31:13 -080018
William A. Kennington III331143c2019-02-07 15:52:44 -080019#include <ipmid/iana.hpp>
20#include <ipmid/oemopenbmc.hpp>
21#include <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>
James Feist1f802f52019-02-08 13:51:43 -080027#include <variant>
Patrick Venture391b8b02018-03-08 08:31:13 -080028
Patrick Venture391b8b02018-03-08 08:31:13 -080029enum ManualSubCmd
30{
31 GET_CONTROL_STATE = 0,
32 SET_CONTROL_STATE = 1,
33 GET_FAILSAFE_STATE = 2,
34};
35
Patrick Ventureda4a5dd2018-08-31 09:42:48 -070036struct FanCtrlRequest
37{
Patrick Venture391b8b02018-03-08 08:31:13 -080038 uint8_t command;
39 uint8_t zone;
40} __attribute__((packed));
41
Patrick Ventureda4a5dd2018-08-31 09:42:48 -070042struct FanCtrlRequestSet
43{
Patrick Venture391b8b02018-03-08 08:31:13 -080044 uint8_t command;
45 uint8_t zone;
46 uint8_t value;
47} __attribute__((packed));
48
49static constexpr auto objectPath = "/xyz/openbmc_project/settings/fanctrl/zone";
50static constexpr auto busName = "xyz.openbmc_project.State.FanCtrl";
Patrick Venturedc3b7902018-03-24 10:41:19 -070051static constexpr auto intf = "xyz.openbmc_project.Control.Mode";
Patrick Venture391b8b02018-03-08 08:31:13 -080052static constexpr auto manualProperty = "Manual";
53static constexpr auto failsafeProperty = "FailSafe";
54static constexpr auto propertiesintf = "org.freedesktop.DBus.Properties";
55
56using Property = std::string;
57using Value = sdbusplus::message::variant<bool>;
58using PropertyMap = std::map<Property, Value>;
59
60/* The following was copied directly from my manual thread handler. */
Patrick Venture7af157b2018-10-30 11:24:40 -070061static std::string getControlPath(int8_t zone)
Patrick Venture391b8b02018-03-08 08:31:13 -080062{
63 return std::string(objectPath) + std::to_string(zone);
64}
65
66/*
67 * busctl call xyz.openbmc_project.State.FanCtrl \
68 * /xyz/openbmc_project/settings/fanctrl/zone1 \
69 * org.freedesktop.DBus.Properties \
70 * GetAll \
71 * s \
Patrick Venturedc3b7902018-03-24 10:41:19 -070072 * xyz.openbmc_project.Control.Mode
Patrick Venture391b8b02018-03-08 08:31:13 -080073 * a{sv} 2 "Manual" b false "FailSafe" b false
74 */
75
Patrick Venture7af157b2018-10-30 11:24:40 -070076static ipmi_ret_t getFanCtrlProperty(uint8_t zoneId, bool* value,
Patrick Ventureda4a5dd2018-08-31 09:42:48 -070077 const std::string& property)
Patrick Venture391b8b02018-03-08 08:31:13 -080078{
Patrick Venture7af157b2018-10-30 11:24:40 -070079 std::string path = getControlPath(zoneId);
Patrick Venture391b8b02018-03-08 08:31:13 -080080
James Feist9fa90c12019-01-11 15:35:22 -080081 auto propertyReadBus = sdbusplus::bus::new_system();
Patrick Ventureda4a5dd2018-08-31 09:42:48 -070082 auto pimMsg = propertyReadBus.new_method_call(busName, path.c_str(),
83 propertiesintf, "GetAll");
Patrick Venture391b8b02018-03-08 08:31:13 -080084 pimMsg.append(intf);
85
Patrick Ventureacecf6b2018-09-06 17:56:41 -070086 try
87 {
Patrick Ventureacecf6b2018-09-06 17:56:41 -070088 PropertyMap propMap;
Patrick Venture8f179142018-09-10 09:24:12 -070089
90 /* a method could error but the call not error. */
91 auto valueResponseMsg = propertyReadBus.call(pimMsg);
Patrick Venture8f179142018-09-10 09:24:12 -070092
Patrick Ventureacecf6b2018-09-06 17:56:41 -070093 valueResponseMsg.read(propMap);
94
James Feist1f802f52019-02-08 13:51:43 -080095 *value = std::get<bool>(propMap[property]);
Patrick Ventureacecf6b2018-09-06 17:56:41 -070096 }
97 catch (const sdbusplus::exception::SdBusError& ex)
Patrick Venture391b8b02018-03-08 08:31:13 -080098 {
99 return IPMI_CC_INVALID;
100 }
101
Patrick Venture391b8b02018-03-08 08:31:13 -0800102 return IPMI_CC_OK;
103}
104
Patrick Venture7af157b2018-10-30 11:24:40 -0700105static ipmi_ret_t getFailsafeModeState(const uint8_t* reqBuf, uint8_t* replyBuf,
Patrick Ventureda4a5dd2018-08-31 09:42:48 -0700106 size_t* dataLen)
Patrick Venture391b8b02018-03-08 08:31:13 -0800107{
108 ipmi_ret_t rc = IPMI_CC_OK;
109 bool current;
110
111 if (*dataLen < sizeof(struct FanCtrlRequest))
112 {
113 return IPMI_CC_INVALID;
114 }
115
116 const auto request =
Patrick Ventureda4a5dd2018-08-31 09:42:48 -0700117 reinterpret_cast<const struct FanCtrlRequest*>(&reqBuf[0]);
Patrick Venture391b8b02018-03-08 08:31:13 -0800118
Patrick Venture7af157b2018-10-30 11:24:40 -0700119 rc = getFanCtrlProperty(request->zone, &current, failsafeProperty);
Patrick Venture391b8b02018-03-08 08:31:13 -0800120 if (rc)
121 {
122 return rc;
123 }
124
125 *replyBuf = (uint8_t)current;
126 *dataLen = sizeof(uint8_t);
127 return rc;
128}
129
130/*
131 * <method name="GetAll">
132 * <arg name="interface" direction="in" type="s"/>
133 * <arg name="properties" direction="out" type="a{sv}"/>
134 * </method>
135 */
Patrick Venture7af157b2018-10-30 11:24:40 -0700136static ipmi_ret_t getManualModeState(const uint8_t* reqBuf, uint8_t* replyBuf,
Patrick Ventureda4a5dd2018-08-31 09:42:48 -0700137 size_t* dataLen)
Patrick Venture391b8b02018-03-08 08:31:13 -0800138{
139 ipmi_ret_t rc = IPMI_CC_OK;
140 bool current;
141
142 if (*dataLen < sizeof(struct FanCtrlRequest))
143 {
144 return IPMI_CC_INVALID;
145 }
146
147 const auto request =
Patrick Ventureda4a5dd2018-08-31 09:42:48 -0700148 reinterpret_cast<const struct FanCtrlRequest*>(&reqBuf[0]);
Patrick Venture391b8b02018-03-08 08:31:13 -0800149
Patrick Venture7af157b2018-10-30 11:24:40 -0700150 rc = getFanCtrlProperty(request->zone, &current, manualProperty);
Patrick Venture391b8b02018-03-08 08:31:13 -0800151 if (rc)
152 {
153 return rc;
154 }
155
156 *replyBuf = (uint8_t)current;
157 *dataLen = sizeof(uint8_t);
158 return rc;
159}
160
161/*
162 * <method name="Set">
163 * <arg name="interface" direction="in" type="s"/>
164 * <arg name="property" direction="in" type="s"/>
165 * <arg name="value" direction="in" type="v"/>
166 * </method>
167 */
Patrick Venture7af157b2018-10-30 11:24:40 -0700168static ipmi_ret_t setManualModeState(const uint8_t* reqBuf, uint8_t* replyBuf,
Patrick Ventureda4a5dd2018-08-31 09:42:48 -0700169 size_t* dataLen)
Patrick Venture391b8b02018-03-08 08:31:13 -0800170{
171 ipmi_ret_t rc = IPMI_CC_OK;
172 if (*dataLen < sizeof(struct FanCtrlRequestSet))
173 {
174 return IPMI_CC_INVALID;
175 }
176
177 using Value = sdbusplus::message::variant<bool>;
178
179 const auto request =
Patrick Ventureda4a5dd2018-08-31 09:42:48 -0700180 reinterpret_cast<const struct FanCtrlRequestSet*>(&reqBuf[0]);
Patrick Venture391b8b02018-03-08 08:31:13 -0800181
182 /* 0 is false, 1 is true */
183 bool setValue = static_cast<bool>(request->value);
Patrick Ventureda4a5dd2018-08-31 09:42:48 -0700184 Value v{setValue};
Patrick Venture391b8b02018-03-08 08:31:13 -0800185
James Feist9fa90c12019-01-11 15:35:22 -0800186 auto PropertyWriteBus = sdbusplus::bus::new_system();
Patrick Venture391b8b02018-03-08 08:31:13 -0800187
Patrick Venture7af157b2018-10-30 11:24:40 -0700188 std::string path = getControlPath(request->zone);
Patrick Venture391b8b02018-03-08 08:31:13 -0800189
Patrick Ventureda4a5dd2018-08-31 09:42:48 -0700190 auto pimMsg = PropertyWriteBus.new_method_call(busName, path.c_str(),
191 propertiesintf, "Set");
Patrick Venture391b8b02018-03-08 08:31:13 -0800192 pimMsg.append(intf);
193 pimMsg.append(manualProperty);
194 pimMsg.append(v);
Patrick Ventureacecf6b2018-09-06 17:56:41 -0700195
196 try
197 {
198 PropertyWriteBus.call_noreply(pimMsg);
199 }
200 catch (const sdbusplus::exception::SdBusError& ex)
Patrick Venture391b8b02018-03-08 08:31:13 -0800201 {
202 rc = IPMI_CC_INVALID;
203 }
204 /* TODO(venture): Should sanity check the result. */
205
206 return rc;
207}
208
209/* Three command packages: get, set true, set false */
Patrick Venture7af157b2018-10-30 11:24:40 -0700210static ipmi_ret_t manualModeControl(ipmi_cmd_t cmd, const uint8_t* reqBuf,
Patrick Ventureda4a5dd2018-08-31 09:42:48 -0700211 uint8_t* replyCmdBuf, size_t* dataLen)
Patrick Venture391b8b02018-03-08 08:31:13 -0800212{
213 ipmi_ret_t rc = IPMI_CC_OK;
214 // FanCtrlRequest is the smaller of the requests, so it's at a minimum.
215 if (*dataLen < sizeof(struct FanCtrlRequest))
216 {
217 return IPMI_CC_INVALID;
218 }
219
220 const auto request =
Patrick Ventureda4a5dd2018-08-31 09:42:48 -0700221 reinterpret_cast<const struct FanCtrlRequest*>(&reqBuf[0]);
Patrick Venture391b8b02018-03-08 08:31:13 -0800222
223 switch (request->command)
224 {
225 case GET_CONTROL_STATE:
Patrick Venture7af157b2018-10-30 11:24:40 -0700226 return getManualModeState(reqBuf, replyCmdBuf, dataLen);
Patrick Venture391b8b02018-03-08 08:31:13 -0800227 case SET_CONTROL_STATE:
Patrick Venture7af157b2018-10-30 11:24:40 -0700228 return setManualModeState(reqBuf, replyCmdBuf, dataLen);
Patrick Venture391b8b02018-03-08 08:31:13 -0800229 case GET_FAILSAFE_STATE:
Patrick Venture7af157b2018-10-30 11:24:40 -0700230 return getFailsafeModeState(reqBuf, replyCmdBuf, dataLen);
Patrick Venture391b8b02018-03-08 08:31:13 -0800231 default:
232 rc = IPMI_CC_INVALID;
233 }
234
235 return rc;
236}
237
238void setupGlobalOemFanControl() __attribute__((constructor));
239
240void setupGlobalOemFanControl()
241{
Patrick Ventureba003432018-07-27 06:59:05 -0700242 oem::Router* router = oem::mutableRouter();
Patrick Venture391b8b02018-03-08 08:31:13 -0800243
244 fprintf(stderr,
245 "Registering OEM:[%#08X], Cmd:[%#04X] for Manual Zone Control\n",
Patrick Ventureda4a5dd2018-08-31 09:42:48 -0700246 oem::obmcOemNumber, oem::Cmd::fanManualCmd);
Patrick Venture391b8b02018-03-08 08:31:13 -0800247
Patrick Ventureda4a5dd2018-08-31 09:42:48 -0700248 router->registerHandler(oem::obmcOemNumber, oem::Cmd::fanManualCmd,
Patrick Venture7af157b2018-10-30 11:24:40 -0700249 manualModeControl);
Patrick Venture391b8b02018-03-08 08:31:13 -0800250}