blob: 5df6559c80abea18892b065b63f010dab2baed3b [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 Joseph46fa37d2017-07-26 18:11:55 +053077void setPcap(sdbusplus::bus::bus& bus, const uint32_t powerCap)
78{
79 auto service = ipmi::getService(bus, PCAP_INTERFACE, PCAP_PATH);
80
81 auto method = bus.new_method_call(service.c_str(),
82 PCAP_PATH,
83 "org.freedesktop.DBus.Properties",
84 "Set");
85
86 method.append(PCAP_INTERFACE, POWER_CAP_PROP);
87 method.append(sdbusplus::message::variant<uint32_t>(powerCap));
88
89 auto reply = bus.call(method);
90
91 if (reply.is_method_error())
92 {
93 log<level::ERR>("Error in setPcap property");
94 elog<InternalFailure>();
95 }
96}
97
Tom Joseph6c8d51b2017-07-26 18:18:06 +053098void setPcapEnable(sdbusplus::bus::bus& bus, bool enabled)
99{
100 auto service = ipmi::getService(bus, PCAP_INTERFACE, PCAP_PATH);
101
102 auto method = bus.new_method_call(service.c_str(),
103 PCAP_PATH,
104 "org.freedesktop.DBus.Properties",
105 "Set");
106
107 method.append(PCAP_INTERFACE, POWER_CAP_ENABLE_PROP);
108 method.append(sdbusplus::message::variant<bool>(enabled));
109
110 auto reply = bus.call(method);
111
112 if (reply.is_method_error())
113 {
114 log<level::ERR>("Error in setPcapEnabled property");
115 elog<InternalFailure>();
116 }
117}
118
Tom Josephbe5eaa12017-07-12 19:54:44 +0530119void readAssetTagObjectTree(dcmi::assettag::ObjectTree& objectTree)
120{
121 static constexpr auto mapperBusName = "xyz.openbmc_project.ObjectMapper";
122 static constexpr auto mapperObjPath = "/xyz/openbmc_project/object_mapper";
123 static constexpr auto mapperIface = "xyz.openbmc_project.ObjectMapper";
124 static constexpr auto inventoryRoot = "/xyz/openbmc_project/inventory/";
125
126 sdbusplus::bus::bus bus{ipmid_get_sd_bus_connection()};
127 auto depth = 0;
128
129 auto mapperCall = bus.new_method_call(mapperBusName,
130 mapperObjPath,
131 mapperIface,
132 "GetSubTree");
133
134 mapperCall.append(inventoryRoot);
135 mapperCall.append(depth);
136 mapperCall.append(std::vector<std::string>({dcmi::assetTagIntf}));
137
138 auto mapperReply = bus.call(mapperCall);
139 if (mapperReply.is_method_error())
140 {
141 log<level::ERR>("Error in mapper call");
142 elog<InternalFailure>();
143 }
144
145 mapperReply.read(objectTree);
146
147 if (objectTree.empty())
148 {
149 log<level::ERR>("AssetTag property is not populated");
150 elog<InternalFailure>();
151 }
152}
153
154std::string readAssetTag()
155{
156 sdbusplus::bus::bus bus{ipmid_get_sd_bus_connection()};
157 dcmi::assettag::ObjectTree objectTree;
158
159 // Read the object tree with the inventory root to figure out the object
160 // that has implemented the Asset tag interface.
161 readAssetTagObjectTree(objectTree);
162
163 auto method = bus.new_method_call(
164 (objectTree.begin()->second.begin()->first).c_str(),
165 (objectTree.begin()->first).c_str(),
166 dcmi::propIntf,
167 "Get");
168 method.append(dcmi::assetTagIntf);
169 method.append(dcmi::assetTagProp);
170
171 auto reply = bus.call(method);
172 if (reply.is_method_error())
173 {
174 log<level::ERR>("Error in reading asset tag");
175 elog<InternalFailure>();
176 }
177
178 sdbusplus::message::variant<std::string> assetTag;
179 reply.read(assetTag);
180
181 return assetTag.get<std::string>();
182}
183
Tom Josephbe5b9892017-07-15 00:55:23 +0530184void writeAssetTag(const std::string& assetTag)
185{
186 sdbusplus::bus::bus bus{ipmid_get_sd_bus_connection()};
187 dcmi::assettag::ObjectTree objectTree;
188
189 // Read the object tree with the inventory root to figure out the object
190 // that has implemented the Asset tag interface.
191 readAssetTagObjectTree(objectTree);
192
193 auto method = bus.new_method_call(
194 (objectTree.begin()->second.begin()->first).c_str(),
195 (objectTree.begin()->first).c_str(),
196 dcmi::propIntf,
197 "Set");
198 method.append(dcmi::assetTagIntf);
199 method.append(dcmi::assetTagProp);
200 method.append(sdbusplus::message::variant<std::string>(assetTag));
201
202 auto reply = bus.call(method);
203 if (reply.is_method_error())
204 {
205 log<level::ERR>("Error in writing asset tag");
206 elog<InternalFailure>();
207 }
208}
209
Tom Josephbe5eaa12017-07-12 19:54:44 +0530210} // namespace dcmi
Chris Austen1810bec2015-10-13 12:12:39 -0500211
Tom Josephb9d86f42017-07-26 18:03:47 +0530212ipmi_ret_t getPowerLimit(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
213 ipmi_request_t request, ipmi_response_t response,
214 ipmi_data_len_t data_len, ipmi_context_t context)
215{
216 auto requestData = reinterpret_cast<const dcmi::GetPowerLimitRequest*>
217 (request);
218 std::vector<uint8_t> outPayload(sizeof(dcmi::GetPowerLimitResponse));
219 auto responseData = reinterpret_cast<dcmi::GetPowerLimitResponse*>
220 (outPayload.data());
221
222 if (requestData->groupID != dcmi::groupExtId)
223 {
224 *data_len = 0;
225 return IPMI_CC_INVALID_FIELD_REQUEST;
226 }
227
228 sdbusplus::bus::bus sdbus {ipmid_get_sd_bus_connection()};
229 uint32_t pcapValue = 0;
230 bool pcapEnable = false;
231
232 try
233 {
234 pcapValue = dcmi::getPcap(sdbus);
235 pcapEnable = dcmi::getPcapEnabled(sdbus);
236 }
237 catch (InternalFailure& e)
238 {
239 *data_len = 0;
240 return IPMI_CC_UNSPECIFIED_ERROR;
241 }
242
243 responseData->groupID = dcmi::groupExtId;
244
245 /*
246 * Exception action if power limit is exceeded and cannot be controlled
247 * with the correction time limit is hardcoded to Hard Power Off system
248 * and log event to SEL.
249 */
250 constexpr auto exception = 0x01;
251 responseData->exceptionAction = exception;
252
253 responseData->powerLimit = static_cast<uint16_t>(pcapValue);
254
255 /*
256 * Correction time limit and Statistics sampling period is currently not
257 * populated.
258 */
259
260 *data_len = outPayload.size();
261 memcpy(response, outPayload.data(), *data_len);
262
263 if (pcapEnable)
264 {
265 return IPMI_CC_OK;
266 }
267 else
268 {
269 return IPMI_DCMI_CC_NO_ACTIVE_POWER_LIMIT;
270 }
271}
272
Tom Joseph46fa37d2017-07-26 18:11:55 +0530273ipmi_ret_t setPowerLimit(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
274 ipmi_request_t request, ipmi_response_t response,
275 ipmi_data_len_t data_len, ipmi_context_t context)
276{
277 auto requestData = reinterpret_cast<const dcmi::SetPowerLimitRequest*>
278 (request);
279 std::vector<uint8_t> outPayload(sizeof(dcmi::SetPowerLimitResponse));
280 auto responseData = reinterpret_cast<dcmi::SetPowerLimitResponse*>
281 (outPayload.data());
282
283 if (requestData->groupID != dcmi::groupExtId)
284 {
285 *data_len = 0;
286 return IPMI_CC_INVALID_FIELD_REQUEST;
287 }
288
289 sdbusplus::bus::bus sdbus {ipmid_get_sd_bus_connection()};
290
291 // Only process the power limit requested in watts.
292 try
293 {
294 dcmi::setPcap(sdbus, requestData->powerLimit);
295 }
296 catch (InternalFailure& e)
297 {
298 *data_len = 0;
299 return IPMI_CC_UNSPECIFIED_ERROR;
300 }
301
302 log<level::INFO>("Set Power Cap",
303 entry("POWERCAP=%u", requestData->powerLimit));
304
305 responseData->groupID = dcmi::groupExtId;
306 memcpy(response, outPayload.data(), outPayload.size());
307 *data_len = outPayload.size();
308
309 return IPMI_CC_OK;
310}
311
Tom Joseph6c8d51b2017-07-26 18:18:06 +0530312ipmi_ret_t applyPowerLimit(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
313 ipmi_request_t request, ipmi_response_t response,
314 ipmi_data_len_t data_len, ipmi_context_t context)
315{
316 auto requestData = reinterpret_cast<const dcmi::ApplyPowerLimitRequest*>
317 (request);
318 std::vector<uint8_t> outPayload(sizeof(dcmi::ApplyPowerLimitResponse));
319 auto responseData = reinterpret_cast<dcmi::ApplyPowerLimitResponse*>
320 (outPayload.data());
321
322 if (requestData->groupID != dcmi::groupExtId)
323 {
324 *data_len = 0;
325 return IPMI_CC_INVALID_FIELD_REQUEST;
326 }
327
328 sdbusplus::bus::bus sdbus {ipmid_get_sd_bus_connection()};
329
330 try
331 {
332 dcmi::setPcapEnable(sdbus,
333 static_cast<bool>(requestData->powerLimitAction));
334 }
335 catch (InternalFailure& e)
336 {
337 *data_len = 0;
338 return IPMI_CC_UNSPECIFIED_ERROR;
339 }
340
341 log<level::INFO>("Set Power Cap Enable",
342 entry("POWERCAPENABLE=%u", requestData->powerLimitAction));
343
344 responseData->groupID = dcmi::groupExtId;
345 memcpy(response, outPayload.data(), outPayload.size());
346 *data_len = outPayload.size();
347
348 return IPMI_CC_OK;
349}
350
Tom Joseph6f6dd4d2017-07-12 20:07:11 +0530351ipmi_ret_t getAssetTag(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
352 ipmi_request_t request, ipmi_response_t response,
353 ipmi_data_len_t data_len, ipmi_context_t context)
354{
355 auto requestData = reinterpret_cast<const dcmi::GetAssetTagRequest*>
356 (request);
357 std::vector<uint8_t> outPayload(sizeof(dcmi::GetAssetTagResponse));
358 auto responseData = reinterpret_cast<dcmi::GetAssetTagResponse*>
359 (outPayload.data());
360
361 if (requestData->groupID != dcmi::groupExtId)
362 {
363 *data_len = 0;
364 return IPMI_CC_INVALID_FIELD_REQUEST;
365 }
366
367 // Verify offset to read and number of bytes to read are not exceeding the
368 // range.
369 if ((requestData->offset > dcmi::assetTagMaxOffset) ||
370 (requestData->bytes > dcmi::maxBytes) ||
371 ((requestData->offset + requestData->bytes) > dcmi::assetTagMaxSize))
372 {
373 *data_len = 0;
374 return IPMI_CC_PARM_OUT_OF_RANGE;
375 }
376
377 std::string assetTag;
378
379 try
380 {
381 assetTag = dcmi::readAssetTag();
382 }
383 catch (InternalFailure& e)
384 {
385 *data_len = 0;
386 return IPMI_CC_UNSPECIFIED_ERROR;
387 }
388
389 responseData->groupID = dcmi::groupExtId;
390
391 // Return if the asset tag is not populated.
392 if (!assetTag.size())
393 {
394 responseData->tagLength = 0;
395 memcpy(response, outPayload.data(), outPayload.size());
396 *data_len = outPayload.size();
397 return IPMI_CC_OK;
398 }
399
400 // If the asset tag is longer than 63 bytes, restrict it to 63 bytes to suit
401 // Get Asset Tag command.
402 if (assetTag.size() > dcmi::assetTagMaxSize)
403 {
404 assetTag.resize(dcmi::assetTagMaxSize);
405 }
406
407 // If the requested offset is beyond the asset tag size.
408 if (requestData->offset >= assetTag.size())
409 {
410 *data_len = 0;
411 return IPMI_CC_PARM_OUT_OF_RANGE;
412 }
413
414 auto returnData = assetTag.substr(requestData->offset, requestData->bytes);
415
416 responseData->tagLength = assetTag.size();
417
418 memcpy(response, outPayload.data(), outPayload.size());
419 memcpy(static_cast<uint8_t*>(response) + outPayload.size(),
420 returnData.data(), returnData.size());
421 *data_len = outPayload.size() + returnData.size();
422
423 return IPMI_CC_OK;
424}
425
Tom Joseph545dd232017-07-12 20:20:49 +0530426ipmi_ret_t setAssetTag(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
427 ipmi_request_t request, ipmi_response_t response,
428 ipmi_data_len_t data_len, ipmi_context_t context)
429{
430 auto requestData = reinterpret_cast<const dcmi::SetAssetTagRequest*>
431 (request);
432 std::vector<uint8_t> outPayload(sizeof(dcmi::SetAssetTagResponse));
433 auto responseData = reinterpret_cast<dcmi::SetAssetTagResponse*>
434 (outPayload.data());
435
436 if (requestData->groupID != dcmi::groupExtId)
437 {
438 *data_len = 0;
439 return IPMI_CC_INVALID_FIELD_REQUEST;
440 }
441
442 // Verify offset to read and number of bytes to read are not exceeding the
443 // range.
444 if ((requestData->offset > dcmi::assetTagMaxOffset) ||
445 (requestData->bytes > dcmi::maxBytes) ||
446 ((requestData->offset + requestData->bytes) > dcmi::assetTagMaxSize))
447 {
448 *data_len = 0;
449 return IPMI_CC_PARM_OUT_OF_RANGE;
450 }
451
452 std::string assetTag;
453
454 try
455 {
456 assetTag = dcmi::readAssetTag();
457
458 if (requestData->offset > assetTag.size())
459 {
460 *data_len = 0;
461 return IPMI_CC_PARM_OUT_OF_RANGE;
462 }
463
464 assetTag.replace(requestData->offset,
465 assetTag.size() - requestData->offset,
466 static_cast<const char*>(request) +
467 sizeof(dcmi::SetAssetTagRequest),
468 requestData->bytes);
469
470 dcmi::writeAssetTag(assetTag);
471
472 responseData->groupID = dcmi::groupExtId;
473 responseData->tagLength = assetTag.size();
474 memcpy(response, outPayload.data(), outPayload.size());
475 *data_len = outPayload.size();
476
477 return IPMI_CC_OK;
478 }
479 catch (InternalFailure& e)
480 {
481 *data_len = 0;
482 return IPMI_CC_UNSPECIFIED_ERROR;
483 }
484}
485
Chris Austen1810bec2015-10-13 12:12:39 -0500486void register_netfn_dcmi_functions()
487{
Tom05732372016-09-06 17:21:23 +0530488 // <Get Power Limit>
Ratan Gupta11ddbd22017-08-05 11:59:39 +0530489 printf("Registering NetFn:[0x%X], Cmd:[0x%X]\n",
490 NETFUN_GRPEXT, dcmi::Commands::GET_POWER_LIMIT);
491
492 ipmi_register_callback(NETFUN_GRPEXT, dcmi::Commands::GET_POWER_LIMIT,
493 NULL, getPowerLimit, PRIVILEGE_USER);
Tom Joseph6f6dd4d2017-07-12 20:07:11 +0530494
Tom Joseph46fa37d2017-07-26 18:11:55 +0530495 // <Set Power Limit>
Ratan Gupta11ddbd22017-08-05 11:59:39 +0530496 printf("Registering NetFn:[0x%X], Cmd:[0x%X]\n",
497 NETFUN_GRPEXT, dcmi::Commands::SET_POWER_LIMIT);
498
499 ipmi_register_callback(NETFUN_GRPEXT, dcmi::Commands::SET_POWER_LIMIT,
500 NULL, setPowerLimit, PRIVILEGE_OPERATOR);
Tom Joseph46fa37d2017-07-26 18:11:55 +0530501
Tom Joseph6c8d51b2017-07-26 18:18:06 +0530502 // <Activate/Deactivate Power Limit>
Ratan Gupta11ddbd22017-08-05 11:59:39 +0530503 printf("Registering NetFn:[0x%X], Cmd:[0x%X]\n",
504 NETFUN_GRPEXT, dcmi::Commands::APPLY_POWER_LIMIT);
505
506 ipmi_register_callback(NETFUN_GRPEXT, dcmi::Commands::APPLY_POWER_LIMIT,
507 NULL, applyPowerLimit, PRIVILEGE_OPERATOR);
Tom Joseph6c8d51b2017-07-26 18:18:06 +0530508
Tom Joseph6f6dd4d2017-07-12 20:07:11 +0530509 // <Get Asset Tag>
Ratan Gupta11ddbd22017-08-05 11:59:39 +0530510 printf("Registering NetFn:[0x%X], Cmd:[0x%X]\n",
511 NETFUN_GRPEXT, dcmi::Commands::GET_ASSET_TAG);
512
513 ipmi_register_callback(NETFUN_GRPEXT, dcmi::Commands::GET_ASSET_TAG,
514 NULL, getAssetTag, PRIVILEGE_USER);
Tom Joseph545dd232017-07-12 20:20:49 +0530515
516 // <Set Asset Tag>
Ratan Gupta11ddbd22017-08-05 11:59:39 +0530517 printf("Registering NetFn:[0x%X], Cmd:[0x%X]\n",
518 NETFUN_GRPEXT, dcmi::Commands::SET_ASSET_TAG);
519
520 ipmi_register_callback(NETFUN_GRPEXT, dcmi::Commands::SET_ASSET_TAG,
521 NULL, setAssetTag, PRIVILEGE_OPERATOR);
Chris Austen1810bec2015-10-13 12:12:39 -0500522 return;
523}
Tom05732372016-09-06 17:21:23 +0530524// 956379