blob: 11a3730dd8a9d6843a6128cfdb19b4f0daf843f4 [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 Josephbe5eaa12017-07-12 19:54:44 +053098void readAssetTagObjectTree(dcmi::assettag::ObjectTree& objectTree)
99{
100 static constexpr auto mapperBusName = "xyz.openbmc_project.ObjectMapper";
101 static constexpr auto mapperObjPath = "/xyz/openbmc_project/object_mapper";
102 static constexpr auto mapperIface = "xyz.openbmc_project.ObjectMapper";
103 static constexpr auto inventoryRoot = "/xyz/openbmc_project/inventory/";
104
105 sdbusplus::bus::bus bus{ipmid_get_sd_bus_connection()};
106 auto depth = 0;
107
108 auto mapperCall = bus.new_method_call(mapperBusName,
109 mapperObjPath,
110 mapperIface,
111 "GetSubTree");
112
113 mapperCall.append(inventoryRoot);
114 mapperCall.append(depth);
115 mapperCall.append(std::vector<std::string>({dcmi::assetTagIntf}));
116
117 auto mapperReply = bus.call(mapperCall);
118 if (mapperReply.is_method_error())
119 {
120 log<level::ERR>("Error in mapper call");
121 elog<InternalFailure>();
122 }
123
124 mapperReply.read(objectTree);
125
126 if (objectTree.empty())
127 {
128 log<level::ERR>("AssetTag property is not populated");
129 elog<InternalFailure>();
130 }
131}
132
133std::string readAssetTag()
134{
135 sdbusplus::bus::bus bus{ipmid_get_sd_bus_connection()};
136 dcmi::assettag::ObjectTree objectTree;
137
138 // Read the object tree with the inventory root to figure out the object
139 // that has implemented the Asset tag interface.
140 readAssetTagObjectTree(objectTree);
141
142 auto method = bus.new_method_call(
143 (objectTree.begin()->second.begin()->first).c_str(),
144 (objectTree.begin()->first).c_str(),
145 dcmi::propIntf,
146 "Get");
147 method.append(dcmi::assetTagIntf);
148 method.append(dcmi::assetTagProp);
149
150 auto reply = bus.call(method);
151 if (reply.is_method_error())
152 {
153 log<level::ERR>("Error in reading asset tag");
154 elog<InternalFailure>();
155 }
156
157 sdbusplus::message::variant<std::string> assetTag;
158 reply.read(assetTag);
159
160 return assetTag.get<std::string>();
161}
162
Tom Josephbe5b9892017-07-15 00:55:23 +0530163void writeAssetTag(const std::string& assetTag)
164{
165 sdbusplus::bus::bus bus{ipmid_get_sd_bus_connection()};
166 dcmi::assettag::ObjectTree objectTree;
167
168 // Read the object tree with the inventory root to figure out the object
169 // that has implemented the Asset tag interface.
170 readAssetTagObjectTree(objectTree);
171
172 auto method = bus.new_method_call(
173 (objectTree.begin()->second.begin()->first).c_str(),
174 (objectTree.begin()->first).c_str(),
175 dcmi::propIntf,
176 "Set");
177 method.append(dcmi::assetTagIntf);
178 method.append(dcmi::assetTagProp);
179 method.append(sdbusplus::message::variant<std::string>(assetTag));
180
181 auto reply = bus.call(method);
182 if (reply.is_method_error())
183 {
184 log<level::ERR>("Error in writing asset tag");
185 elog<InternalFailure>();
186 }
187}
188
Tom Josephbe5eaa12017-07-12 19:54:44 +0530189} // namespace dcmi
Chris Austen1810bec2015-10-13 12:12:39 -0500190
Tom Josephb9d86f42017-07-26 18:03:47 +0530191ipmi_ret_t getPowerLimit(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
192 ipmi_request_t request, ipmi_response_t response,
193 ipmi_data_len_t data_len, ipmi_context_t context)
194{
195 auto requestData = reinterpret_cast<const dcmi::GetPowerLimitRequest*>
196 (request);
197 std::vector<uint8_t> outPayload(sizeof(dcmi::GetPowerLimitResponse));
198 auto responseData = reinterpret_cast<dcmi::GetPowerLimitResponse*>
199 (outPayload.data());
200
201 if (requestData->groupID != dcmi::groupExtId)
202 {
203 *data_len = 0;
204 return IPMI_CC_INVALID_FIELD_REQUEST;
205 }
206
207 sdbusplus::bus::bus sdbus {ipmid_get_sd_bus_connection()};
208 uint32_t pcapValue = 0;
209 bool pcapEnable = false;
210
211 try
212 {
213 pcapValue = dcmi::getPcap(sdbus);
214 pcapEnable = dcmi::getPcapEnabled(sdbus);
215 }
216 catch (InternalFailure& e)
217 {
218 *data_len = 0;
219 return IPMI_CC_UNSPECIFIED_ERROR;
220 }
221
222 responseData->groupID = dcmi::groupExtId;
223
224 /*
225 * Exception action if power limit is exceeded and cannot be controlled
226 * with the correction time limit is hardcoded to Hard Power Off system
227 * and log event to SEL.
228 */
229 constexpr auto exception = 0x01;
230 responseData->exceptionAction = exception;
231
232 responseData->powerLimit = static_cast<uint16_t>(pcapValue);
233
234 /*
235 * Correction time limit and Statistics sampling period is currently not
236 * populated.
237 */
238
239 *data_len = outPayload.size();
240 memcpy(response, outPayload.data(), *data_len);
241
242 if (pcapEnable)
243 {
244 return IPMI_CC_OK;
245 }
246 else
247 {
248 return IPMI_DCMI_CC_NO_ACTIVE_POWER_LIMIT;
249 }
250}
251
Tom Joseph46fa37d2017-07-26 18:11:55 +0530252ipmi_ret_t setPowerLimit(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
253 ipmi_request_t request, ipmi_response_t response,
254 ipmi_data_len_t data_len, ipmi_context_t context)
255{
256 auto requestData = reinterpret_cast<const dcmi::SetPowerLimitRequest*>
257 (request);
258 std::vector<uint8_t> outPayload(sizeof(dcmi::SetPowerLimitResponse));
259 auto responseData = reinterpret_cast<dcmi::SetPowerLimitResponse*>
260 (outPayload.data());
261
262 if (requestData->groupID != dcmi::groupExtId)
263 {
264 *data_len = 0;
265 return IPMI_CC_INVALID_FIELD_REQUEST;
266 }
267
268 sdbusplus::bus::bus sdbus {ipmid_get_sd_bus_connection()};
269
270 // Only process the power limit requested in watts.
271 try
272 {
273 dcmi::setPcap(sdbus, requestData->powerLimit);
274 }
275 catch (InternalFailure& e)
276 {
277 *data_len = 0;
278 return IPMI_CC_UNSPECIFIED_ERROR;
279 }
280
281 log<level::INFO>("Set Power Cap",
282 entry("POWERCAP=%u", requestData->powerLimit));
283
284 responseData->groupID = dcmi::groupExtId;
285 memcpy(response, outPayload.data(), outPayload.size());
286 *data_len = outPayload.size();
287
288 return IPMI_CC_OK;
289}
290
Tom Joseph6f6dd4d2017-07-12 20:07:11 +0530291ipmi_ret_t getAssetTag(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
292 ipmi_request_t request, ipmi_response_t response,
293 ipmi_data_len_t data_len, ipmi_context_t context)
294{
295 auto requestData = reinterpret_cast<const dcmi::GetAssetTagRequest*>
296 (request);
297 std::vector<uint8_t> outPayload(sizeof(dcmi::GetAssetTagResponse));
298 auto responseData = reinterpret_cast<dcmi::GetAssetTagResponse*>
299 (outPayload.data());
300
301 if (requestData->groupID != dcmi::groupExtId)
302 {
303 *data_len = 0;
304 return IPMI_CC_INVALID_FIELD_REQUEST;
305 }
306
307 // Verify offset to read and number of bytes to read are not exceeding the
308 // range.
309 if ((requestData->offset > dcmi::assetTagMaxOffset) ||
310 (requestData->bytes > dcmi::maxBytes) ||
311 ((requestData->offset + requestData->bytes) > dcmi::assetTagMaxSize))
312 {
313 *data_len = 0;
314 return IPMI_CC_PARM_OUT_OF_RANGE;
315 }
316
317 std::string assetTag;
318
319 try
320 {
321 assetTag = dcmi::readAssetTag();
322 }
323 catch (InternalFailure& e)
324 {
325 *data_len = 0;
326 return IPMI_CC_UNSPECIFIED_ERROR;
327 }
328
329 responseData->groupID = dcmi::groupExtId;
330
331 // Return if the asset tag is not populated.
332 if (!assetTag.size())
333 {
334 responseData->tagLength = 0;
335 memcpy(response, outPayload.data(), outPayload.size());
336 *data_len = outPayload.size();
337 return IPMI_CC_OK;
338 }
339
340 // If the asset tag is longer than 63 bytes, restrict it to 63 bytes to suit
341 // Get Asset Tag command.
342 if (assetTag.size() > dcmi::assetTagMaxSize)
343 {
344 assetTag.resize(dcmi::assetTagMaxSize);
345 }
346
347 // If the requested offset is beyond the asset tag size.
348 if (requestData->offset >= assetTag.size())
349 {
350 *data_len = 0;
351 return IPMI_CC_PARM_OUT_OF_RANGE;
352 }
353
354 auto returnData = assetTag.substr(requestData->offset, requestData->bytes);
355
356 responseData->tagLength = assetTag.size();
357
358 memcpy(response, outPayload.data(), outPayload.size());
359 memcpy(static_cast<uint8_t*>(response) + outPayload.size(),
360 returnData.data(), returnData.size());
361 *data_len = outPayload.size() + returnData.size();
362
363 return IPMI_CC_OK;
364}
365
Tom Joseph545dd232017-07-12 20:20:49 +0530366ipmi_ret_t setAssetTag(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
367 ipmi_request_t request, ipmi_response_t response,
368 ipmi_data_len_t data_len, ipmi_context_t context)
369{
370 auto requestData = reinterpret_cast<const dcmi::SetAssetTagRequest*>
371 (request);
372 std::vector<uint8_t> outPayload(sizeof(dcmi::SetAssetTagResponse));
373 auto responseData = reinterpret_cast<dcmi::SetAssetTagResponse*>
374 (outPayload.data());
375
376 if (requestData->groupID != dcmi::groupExtId)
377 {
378 *data_len = 0;
379 return IPMI_CC_INVALID_FIELD_REQUEST;
380 }
381
382 // Verify offset to read and number of bytes to read are not exceeding the
383 // range.
384 if ((requestData->offset > dcmi::assetTagMaxOffset) ||
385 (requestData->bytes > dcmi::maxBytes) ||
386 ((requestData->offset + requestData->bytes) > dcmi::assetTagMaxSize))
387 {
388 *data_len = 0;
389 return IPMI_CC_PARM_OUT_OF_RANGE;
390 }
391
392 std::string assetTag;
393
394 try
395 {
396 assetTag = dcmi::readAssetTag();
397
398 if (requestData->offset > assetTag.size())
399 {
400 *data_len = 0;
401 return IPMI_CC_PARM_OUT_OF_RANGE;
402 }
403
404 assetTag.replace(requestData->offset,
405 assetTag.size() - requestData->offset,
406 static_cast<const char*>(request) +
407 sizeof(dcmi::SetAssetTagRequest),
408 requestData->bytes);
409
410 dcmi::writeAssetTag(assetTag);
411
412 responseData->groupID = dcmi::groupExtId;
413 responseData->tagLength = assetTag.size();
414 memcpy(response, outPayload.data(), outPayload.size());
415 *data_len = outPayload.size();
416
417 return IPMI_CC_OK;
418 }
419 catch (InternalFailure& e)
420 {
421 *data_len = 0;
422 return IPMI_CC_UNSPECIFIED_ERROR;
423 }
424}
425
Chris Austen1810bec2015-10-13 12:12:39 -0500426void register_netfn_dcmi_functions()
427{
Tom05732372016-09-06 17:21:23 +0530428 // <Get Power Limit>
Tom Josephb9d86f42017-07-26 18:03:47 +0530429 printf("Registering NetFn:[0x%X], Cmd:[0x%X]\n",NETFUN_GRPEXT, IPMI_CMD_DCMI_GET_POWER_LIMIT);
430 ipmi_register_callback(NETFUN_GRPEXT, IPMI_CMD_DCMI_GET_POWER_LIMIT, NULL, getPowerLimit,
Tom05732372016-09-06 17:21:23 +0530431 PRIVILEGE_USER);
Tom Joseph6f6dd4d2017-07-12 20:07:11 +0530432
Tom Joseph46fa37d2017-07-26 18:11:55 +0530433 // <Set Power Limit>
434 printf("Registering NetFn:[0x%X], Cmd:[0x%X]\n",NETFUN_GRPEXT, IPMI_CMD_DCMI_SET_POWER_LIMIT);
435 ipmi_register_callback(NETFUN_GRPEXT, IPMI_CMD_DCMI_SET_POWER_LIMIT, NULL, setPowerLimit,
436 PRIVILEGE_OPERATOR);
437
Tom Joseph6f6dd4d2017-07-12 20:07:11 +0530438 // <Get Asset Tag>
439 printf("Registering NetFn:[0x%X], Cmd:[0x%X]\n",NETFUN_GRPEXT, IPMI_CMD_DCMI_GET_ASSET_TAG);
440 ipmi_register_callback(NETFUN_GRPEXT, IPMI_CMD_DCMI_GET_ASSET_TAG, NULL, getAssetTag,
441 PRIVILEGE_USER);
Tom Joseph545dd232017-07-12 20:20:49 +0530442
443 // <Set Asset Tag>
444 printf("Registering NetFn:[0x%X], Cmd:[0x%X]\n",NETFUN_GRPEXT, IPMI_CMD_DCMI_SET_ASSET_TAG);
445 ipmi_register_callback(NETFUN_GRPEXT, IPMI_CMD_DCMI_SET_ASSET_TAG, NULL, setAssetTag,
446 PRIVILEGE_OPERATOR);
Chris Austen1810bec2015-10-13 12:12:39 -0500447 return;
448}
Tom05732372016-09-06 17:21:23 +0530449// 956379