blob: 2e0204dd95046b08f64905327e4bbe6c6d1b1188 [file] [log] [blame]
Tom Josephbe5eaa12017-07-12 19:54:44 +05301#include "dcmihandler.hpp"
Patrick Williams37af7332016-09-02 21:21:42 -05002#include "host-ipmid/ipmid-api.h"
Tom Josephbe5eaa12017-07-12 19:54:44 +05303#include <phosphor-logging/elog-errors.hpp>
Andrew Geissler50c0c8f2017-07-11 16:18:51 -05004#include <phosphor-logging/log.hpp>
5#include <sdbusplus/bus.hpp>
6#include "utils.hpp"
Chris Austen1810bec2015-10-13 12:12:39 -05007#include <stdio.h>
8#include <string.h>
9#include <stdint.h>
Tom Josephbe5eaa12017-07-12 19:54:44 +053010#include "xyz/openbmc_project/Common/error.hpp"
11
12using namespace phosphor::logging;
13using InternalFailure =
14 sdbusplus::xyz::openbmc_project::Common::Error::InternalFailure;
Chris Austen1810bec2015-10-13 12:12:39 -050015
16void register_netfn_dcmi_functions() __attribute__((constructor));
17
Andrew Geissler50c0c8f2017-07-11 16:18:51 -050018constexpr auto PCAP_PATH = "/xyz/openbmc_project/control/host0/power_cap";
19constexpr auto PCAP_INTERFACE = "xyz.openbmc_project.Control.Power.Cap";
20
21constexpr auto POWER_CAP_PROP = "PowerCap";
22constexpr auto POWER_CAP_ENABLE_PROP = "PowerCapEnable";
23
24using namespace phosphor::logging;
25
Tom Josephb9d86f42017-07-26 18:03:47 +053026namespace dcmi
27{
28
Andrew Geissler50c0c8f2017-07-11 16:18:51 -050029uint32_t getPcap(sdbusplus::bus::bus& bus)
30{
31 auto settingService = ipmi::getService(bus,
Andrew Geisslera944d432017-07-19 17:53:44 -050032 PCAP_INTERFACE,PCAP_PATH);
Andrew Geissler50c0c8f2017-07-11 16:18:51 -050033
34 auto method = bus.new_method_call(settingService.c_str(),
35 PCAP_PATH,
36 "org.freedesktop.DBus.Properties",
37 "Get");
38
39 method.append(PCAP_INTERFACE, POWER_CAP_PROP);
40 auto reply = bus.call(method);
41
42 if (reply.is_method_error())
43 {
44 log<level::ERR>("Error in getPcap prop");
Tom Josephb9d86f42017-07-26 18:03:47 +053045 elog<InternalFailure>();
Andrew Geissler50c0c8f2017-07-11 16:18:51 -050046 }
47 sdbusplus::message::variant<uint32_t> pcap;
48 reply.read(pcap);
49
Tom Josephb9d86f42017-07-26 18:03:47 +053050 return pcap.get<uint32_t>();
Andrew Geissler50c0c8f2017-07-11 16:18:51 -050051}
52
53bool getPcapEnabled(sdbusplus::bus::bus& bus)
54{
55 auto settingService = ipmi::getService(bus,
Andrew Geisslera944d432017-07-19 17:53:44 -050056 PCAP_INTERFACE,PCAP_PATH);
Andrew Geissler50c0c8f2017-07-11 16:18:51 -050057
58 auto method = bus.new_method_call(settingService.c_str(),
59 PCAP_PATH,
60 "org.freedesktop.DBus.Properties",
61 "Get");
62
63 method.append(PCAP_INTERFACE, POWER_CAP_ENABLE_PROP);
64 auto reply = bus.call(method);
65
66 if (reply.is_method_error())
67 {
68 log<level::ERR>("Error in getPcapEnabled prop");
Tom Josephb9d86f42017-07-26 18:03:47 +053069 elog<InternalFailure>();
Andrew Geissler50c0c8f2017-07-11 16:18:51 -050070 }
71 sdbusplus::message::variant<bool> pcapEnabled;
72 reply.read(pcapEnabled);
73
Tom Josephb9d86f42017-07-26 18:03:47 +053074 return pcapEnabled.get<bool>();
Andrew Geissler50c0c8f2017-07-11 16:18:51 -050075}
Chris Austen1810bec2015-10-13 12:12:39 -050076
Tom Josephbe5eaa12017-07-12 19:54:44 +053077void readAssetTagObjectTree(dcmi::assettag::ObjectTree& objectTree)
78{
79 static constexpr auto mapperBusName = "xyz.openbmc_project.ObjectMapper";
80 static constexpr auto mapperObjPath = "/xyz/openbmc_project/object_mapper";
81 static constexpr auto mapperIface = "xyz.openbmc_project.ObjectMapper";
82 static constexpr auto inventoryRoot = "/xyz/openbmc_project/inventory/";
83
84 sdbusplus::bus::bus bus{ipmid_get_sd_bus_connection()};
85 auto depth = 0;
86
87 auto mapperCall = bus.new_method_call(mapperBusName,
88 mapperObjPath,
89 mapperIface,
90 "GetSubTree");
91
92 mapperCall.append(inventoryRoot);
93 mapperCall.append(depth);
94 mapperCall.append(std::vector<std::string>({dcmi::assetTagIntf}));
95
96 auto mapperReply = bus.call(mapperCall);
97 if (mapperReply.is_method_error())
98 {
99 log<level::ERR>("Error in mapper call");
100 elog<InternalFailure>();
101 }
102
103 mapperReply.read(objectTree);
104
105 if (objectTree.empty())
106 {
107 log<level::ERR>("AssetTag property is not populated");
108 elog<InternalFailure>();
109 }
110}
111
112std::string readAssetTag()
113{
114 sdbusplus::bus::bus bus{ipmid_get_sd_bus_connection()};
115 dcmi::assettag::ObjectTree objectTree;
116
117 // Read the object tree with the inventory root to figure out the object
118 // that has implemented the Asset tag interface.
119 readAssetTagObjectTree(objectTree);
120
121 auto method = bus.new_method_call(
122 (objectTree.begin()->second.begin()->first).c_str(),
123 (objectTree.begin()->first).c_str(),
124 dcmi::propIntf,
125 "Get");
126 method.append(dcmi::assetTagIntf);
127 method.append(dcmi::assetTagProp);
128
129 auto reply = bus.call(method);
130 if (reply.is_method_error())
131 {
132 log<level::ERR>("Error in reading asset tag");
133 elog<InternalFailure>();
134 }
135
136 sdbusplus::message::variant<std::string> assetTag;
137 reply.read(assetTag);
138
139 return assetTag.get<std::string>();
140}
141
Tom Josephbe5b9892017-07-15 00:55:23 +0530142void writeAssetTag(const std::string& assetTag)
143{
144 sdbusplus::bus::bus bus{ipmid_get_sd_bus_connection()};
145 dcmi::assettag::ObjectTree objectTree;
146
147 // Read the object tree with the inventory root to figure out the object
148 // that has implemented the Asset tag interface.
149 readAssetTagObjectTree(objectTree);
150
151 auto method = bus.new_method_call(
152 (objectTree.begin()->second.begin()->first).c_str(),
153 (objectTree.begin()->first).c_str(),
154 dcmi::propIntf,
155 "Set");
156 method.append(dcmi::assetTagIntf);
157 method.append(dcmi::assetTagProp);
158 method.append(sdbusplus::message::variant<std::string>(assetTag));
159
160 auto reply = bus.call(method);
161 if (reply.is_method_error())
162 {
163 log<level::ERR>("Error in writing asset tag");
164 elog<InternalFailure>();
165 }
166}
167
Tom Josephbe5eaa12017-07-12 19:54:44 +0530168} // namespace dcmi
Chris Austen1810bec2015-10-13 12:12:39 -0500169
Tom Josephb9d86f42017-07-26 18:03:47 +0530170ipmi_ret_t getPowerLimit(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
171 ipmi_request_t request, ipmi_response_t response,
172 ipmi_data_len_t data_len, ipmi_context_t context)
173{
174 auto requestData = reinterpret_cast<const dcmi::GetPowerLimitRequest*>
175 (request);
176 std::vector<uint8_t> outPayload(sizeof(dcmi::GetPowerLimitResponse));
177 auto responseData = reinterpret_cast<dcmi::GetPowerLimitResponse*>
178 (outPayload.data());
179
180 if (requestData->groupID != dcmi::groupExtId)
181 {
182 *data_len = 0;
183 return IPMI_CC_INVALID_FIELD_REQUEST;
184 }
185
186 sdbusplus::bus::bus sdbus {ipmid_get_sd_bus_connection()};
187 uint32_t pcapValue = 0;
188 bool pcapEnable = false;
189
190 try
191 {
192 pcapValue = dcmi::getPcap(sdbus);
193 pcapEnable = dcmi::getPcapEnabled(sdbus);
194 }
195 catch (InternalFailure& e)
196 {
197 *data_len = 0;
198 return IPMI_CC_UNSPECIFIED_ERROR;
199 }
200
201 responseData->groupID = dcmi::groupExtId;
202
203 /*
204 * Exception action if power limit is exceeded and cannot be controlled
205 * with the correction time limit is hardcoded to Hard Power Off system
206 * and log event to SEL.
207 */
208 constexpr auto exception = 0x01;
209 responseData->exceptionAction = exception;
210
211 responseData->powerLimit = static_cast<uint16_t>(pcapValue);
212
213 /*
214 * Correction time limit and Statistics sampling period is currently not
215 * populated.
216 */
217
218 *data_len = outPayload.size();
219 memcpy(response, outPayload.data(), *data_len);
220
221 if (pcapEnable)
222 {
223 return IPMI_CC_OK;
224 }
225 else
226 {
227 return IPMI_DCMI_CC_NO_ACTIVE_POWER_LIMIT;
228 }
229}
230
Tom Joseph6f6dd4d2017-07-12 20:07:11 +0530231ipmi_ret_t getAssetTag(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
232 ipmi_request_t request, ipmi_response_t response,
233 ipmi_data_len_t data_len, ipmi_context_t context)
234{
235 auto requestData = reinterpret_cast<const dcmi::GetAssetTagRequest*>
236 (request);
237 std::vector<uint8_t> outPayload(sizeof(dcmi::GetAssetTagResponse));
238 auto responseData = reinterpret_cast<dcmi::GetAssetTagResponse*>
239 (outPayload.data());
240
241 if (requestData->groupID != dcmi::groupExtId)
242 {
243 *data_len = 0;
244 return IPMI_CC_INVALID_FIELD_REQUEST;
245 }
246
247 // Verify offset to read and number of bytes to read are not exceeding the
248 // range.
249 if ((requestData->offset > dcmi::assetTagMaxOffset) ||
250 (requestData->bytes > dcmi::maxBytes) ||
251 ((requestData->offset + requestData->bytes) > dcmi::assetTagMaxSize))
252 {
253 *data_len = 0;
254 return IPMI_CC_PARM_OUT_OF_RANGE;
255 }
256
257 std::string assetTag;
258
259 try
260 {
261 assetTag = dcmi::readAssetTag();
262 }
263 catch (InternalFailure& e)
264 {
265 *data_len = 0;
266 return IPMI_CC_UNSPECIFIED_ERROR;
267 }
268
269 responseData->groupID = dcmi::groupExtId;
270
271 // Return if the asset tag is not populated.
272 if (!assetTag.size())
273 {
274 responseData->tagLength = 0;
275 memcpy(response, outPayload.data(), outPayload.size());
276 *data_len = outPayload.size();
277 return IPMI_CC_OK;
278 }
279
280 // If the asset tag is longer than 63 bytes, restrict it to 63 bytes to suit
281 // Get Asset Tag command.
282 if (assetTag.size() > dcmi::assetTagMaxSize)
283 {
284 assetTag.resize(dcmi::assetTagMaxSize);
285 }
286
287 // If the requested offset is beyond the asset tag size.
288 if (requestData->offset >= assetTag.size())
289 {
290 *data_len = 0;
291 return IPMI_CC_PARM_OUT_OF_RANGE;
292 }
293
294 auto returnData = assetTag.substr(requestData->offset, requestData->bytes);
295
296 responseData->tagLength = assetTag.size();
297
298 memcpy(response, outPayload.data(), outPayload.size());
299 memcpy(static_cast<uint8_t*>(response) + outPayload.size(),
300 returnData.data(), returnData.size());
301 *data_len = outPayload.size() + returnData.size();
302
303 return IPMI_CC_OK;
304}
305
Tom Joseph545dd232017-07-12 20:20:49 +0530306ipmi_ret_t setAssetTag(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
307 ipmi_request_t request, ipmi_response_t response,
308 ipmi_data_len_t data_len, ipmi_context_t context)
309{
310 auto requestData = reinterpret_cast<const dcmi::SetAssetTagRequest*>
311 (request);
312 std::vector<uint8_t> outPayload(sizeof(dcmi::SetAssetTagResponse));
313 auto responseData = reinterpret_cast<dcmi::SetAssetTagResponse*>
314 (outPayload.data());
315
316 if (requestData->groupID != dcmi::groupExtId)
317 {
318 *data_len = 0;
319 return IPMI_CC_INVALID_FIELD_REQUEST;
320 }
321
322 // Verify offset to read and number of bytes to read are not exceeding the
323 // range.
324 if ((requestData->offset > dcmi::assetTagMaxOffset) ||
325 (requestData->bytes > dcmi::maxBytes) ||
326 ((requestData->offset + requestData->bytes) > dcmi::assetTagMaxSize))
327 {
328 *data_len = 0;
329 return IPMI_CC_PARM_OUT_OF_RANGE;
330 }
331
332 std::string assetTag;
333
334 try
335 {
336 assetTag = dcmi::readAssetTag();
337
338 if (requestData->offset > assetTag.size())
339 {
340 *data_len = 0;
341 return IPMI_CC_PARM_OUT_OF_RANGE;
342 }
343
344 assetTag.replace(requestData->offset,
345 assetTag.size() - requestData->offset,
346 static_cast<const char*>(request) +
347 sizeof(dcmi::SetAssetTagRequest),
348 requestData->bytes);
349
350 dcmi::writeAssetTag(assetTag);
351
352 responseData->groupID = dcmi::groupExtId;
353 responseData->tagLength = assetTag.size();
354 memcpy(response, outPayload.data(), outPayload.size());
355 *data_len = outPayload.size();
356
357 return IPMI_CC_OK;
358 }
359 catch (InternalFailure& e)
360 {
361 *data_len = 0;
362 return IPMI_CC_UNSPECIFIED_ERROR;
363 }
364}
365
Chris Austen1810bec2015-10-13 12:12:39 -0500366void register_netfn_dcmi_functions()
367{
Tom05732372016-09-06 17:21:23 +0530368 // <Get Power Limit>
Tom Josephb9d86f42017-07-26 18:03:47 +0530369 printf("Registering NetFn:[0x%X], Cmd:[0x%X]\n",NETFUN_GRPEXT, IPMI_CMD_DCMI_GET_POWER_LIMIT);
370 ipmi_register_callback(NETFUN_GRPEXT, IPMI_CMD_DCMI_GET_POWER_LIMIT, NULL, getPowerLimit,
Tom05732372016-09-06 17:21:23 +0530371 PRIVILEGE_USER);
Tom Joseph6f6dd4d2017-07-12 20:07:11 +0530372
373 // <Get Asset Tag>
374 printf("Registering NetFn:[0x%X], Cmd:[0x%X]\n",NETFUN_GRPEXT, IPMI_CMD_DCMI_GET_ASSET_TAG);
375 ipmi_register_callback(NETFUN_GRPEXT, IPMI_CMD_DCMI_GET_ASSET_TAG, NULL, getAssetTag,
376 PRIVILEGE_USER);
Tom Joseph545dd232017-07-12 20:20:49 +0530377
378 // <Set Asset Tag>
379 printf("Registering NetFn:[0x%X], Cmd:[0x%X]\n",NETFUN_GRPEXT, IPMI_CMD_DCMI_SET_ASSET_TAG);
380 ipmi_register_callback(NETFUN_GRPEXT, IPMI_CMD_DCMI_SET_ASSET_TAG, NULL, setAssetTag,
381 PRIVILEGE_OPERATOR);
Chris Austen1810bec2015-10-13 12:12:39 -0500382 return;
383}
Tom05732372016-09-06 17:21:23 +0530384// 956379