blob: fa3b55be18d63ba49ad8c89ad71d6a85095aa9d5 [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>
Marri Devender Rao66c5fda2018-01-18 10:48:37 -06006#include <nlohmann/json.hpp>
Andrew Geissler50c0c8f2017-07-11 16:18:51 -05007#include "utils.hpp"
Chris Austen1810bec2015-10-13 12:12:39 -05008#include <stdio.h>
9#include <string.h>
10#include <stdint.h>
Dhruvaraj Subhashchandrane29be412018-01-16 05:11:56 -060011#include <fstream>
12#include <bitset>
Deepak Kodihallib1e8fba2018-01-24 04:57:10 -060013#include <cmath>
Tom Josephbe5eaa12017-07-12 19:54:44 +053014#include "xyz/openbmc_project/Common/error.hpp"
Marri Devender Rao66c5fda2018-01-18 10:48:37 -060015#include "config.h"
Tom Josephbe5eaa12017-07-12 19:54:44 +053016
17using namespace phosphor::logging;
18using InternalFailure =
19 sdbusplus::xyz::openbmc_project::Common::Error::InternalFailure;
Chris Austen1810bec2015-10-13 12:12:39 -050020
21void register_netfn_dcmi_functions() __attribute__((constructor));
22
Andrew Geissler50c0c8f2017-07-11 16:18:51 -050023constexpr auto PCAP_PATH = "/xyz/openbmc_project/control/host0/power_cap";
24constexpr auto PCAP_INTERFACE = "xyz.openbmc_project.Control.Power.Cap";
25
26constexpr auto POWER_CAP_PROP = "PowerCap";
27constexpr auto POWER_CAP_ENABLE_PROP = "PowerCapEnable";
28
Dhruvaraj Subhashchandrane29be412018-01-16 05:11:56 -060029constexpr auto DCMI_PARAMETER_REVISION = 2;
30constexpr auto DCMI_SPEC_MAJOR_VERSION = 1;
31constexpr auto DCMI_SPEC_MINOR_VERSION = 5;
32constexpr auto DCMI_CAP_JSON_FILE = "/usr/share/ipmi-providers/dcmi_cap.json";
33
Marri Devender Rao66c5fda2018-01-18 10:48:37 -060034constexpr auto SENSOR_VALUE_INTF = "xyz.openbmc_project.Sensor.Value";
35constexpr auto SENSOR_VALUE_PROP = "Value";
36constexpr auto SENSOR_SCALE_PROP = "Scale";
37
Andrew Geissler50c0c8f2017-07-11 16:18:51 -050038using namespace phosphor::logging;
39
Tom Josephb9d86f42017-07-26 18:03:47 +053040namespace dcmi
41{
42
Deepak Kodihalli0b459552018-02-06 06:25:12 -060043// Refer Table 6-14, DCMI Entity ID Extension, DCMI v1.5 spec
44static const std::map<uint8_t, std::string> entityIdToName
45{
46 {0x40, "inlet"},
47 {0x37, "inlet"},
48 {0x41, "cpu"},
49 {0x03, "cpu"},
50 {0x42, "baseboard"},
51 {0x07, "baseboard"}
52};
53
54
Andrew Geissler50c0c8f2017-07-11 16:18:51 -050055uint32_t getPcap(sdbusplus::bus::bus& bus)
56{
57 auto settingService = ipmi::getService(bus,
Andrew Geisslera944d432017-07-19 17:53:44 -050058 PCAP_INTERFACE,PCAP_PATH);
Andrew Geissler50c0c8f2017-07-11 16:18:51 -050059
60 auto method = bus.new_method_call(settingService.c_str(),
61 PCAP_PATH,
62 "org.freedesktop.DBus.Properties",
63 "Get");
64
65 method.append(PCAP_INTERFACE, POWER_CAP_PROP);
66 auto reply = bus.call(method);
67
68 if (reply.is_method_error())
69 {
70 log<level::ERR>("Error in getPcap prop");
Tom Josephb9d86f42017-07-26 18:03:47 +053071 elog<InternalFailure>();
Andrew Geissler50c0c8f2017-07-11 16:18:51 -050072 }
73 sdbusplus::message::variant<uint32_t> pcap;
74 reply.read(pcap);
75
Tom Josephb9d86f42017-07-26 18:03:47 +053076 return pcap.get<uint32_t>();
Andrew Geissler50c0c8f2017-07-11 16:18:51 -050077}
78
79bool getPcapEnabled(sdbusplus::bus::bus& bus)
80{
81 auto settingService = ipmi::getService(bus,
Andrew Geisslera944d432017-07-19 17:53:44 -050082 PCAP_INTERFACE,PCAP_PATH);
Andrew Geissler50c0c8f2017-07-11 16:18:51 -050083
84 auto method = bus.new_method_call(settingService.c_str(),
85 PCAP_PATH,
86 "org.freedesktop.DBus.Properties",
87 "Get");
88
89 method.append(PCAP_INTERFACE, POWER_CAP_ENABLE_PROP);
90 auto reply = bus.call(method);
91
92 if (reply.is_method_error())
93 {
94 log<level::ERR>("Error in getPcapEnabled prop");
Tom Josephb9d86f42017-07-26 18:03:47 +053095 elog<InternalFailure>();
Andrew Geissler50c0c8f2017-07-11 16:18:51 -050096 }
97 sdbusplus::message::variant<bool> pcapEnabled;
98 reply.read(pcapEnabled);
99
Tom Josephb9d86f42017-07-26 18:03:47 +0530100 return pcapEnabled.get<bool>();
Andrew Geissler50c0c8f2017-07-11 16:18:51 -0500101}
Chris Austen1810bec2015-10-13 12:12:39 -0500102
Tom Joseph46fa37d2017-07-26 18:11:55 +0530103void setPcap(sdbusplus::bus::bus& bus, const uint32_t powerCap)
104{
105 auto service = ipmi::getService(bus, PCAP_INTERFACE, PCAP_PATH);
106
107 auto method = bus.new_method_call(service.c_str(),
108 PCAP_PATH,
109 "org.freedesktop.DBus.Properties",
110 "Set");
111
112 method.append(PCAP_INTERFACE, POWER_CAP_PROP);
113 method.append(sdbusplus::message::variant<uint32_t>(powerCap));
114
115 auto reply = bus.call(method);
116
117 if (reply.is_method_error())
118 {
119 log<level::ERR>("Error in setPcap property");
120 elog<InternalFailure>();
121 }
122}
123
Tom Joseph6c8d51b2017-07-26 18:18:06 +0530124void setPcapEnable(sdbusplus::bus::bus& bus, bool enabled)
125{
126 auto service = ipmi::getService(bus, PCAP_INTERFACE, PCAP_PATH);
127
128 auto method = bus.new_method_call(service.c_str(),
129 PCAP_PATH,
130 "org.freedesktop.DBus.Properties",
131 "Set");
132
133 method.append(PCAP_INTERFACE, POWER_CAP_ENABLE_PROP);
134 method.append(sdbusplus::message::variant<bool>(enabled));
135
136 auto reply = bus.call(method);
137
138 if (reply.is_method_error())
139 {
140 log<level::ERR>("Error in setPcapEnabled property");
141 elog<InternalFailure>();
142 }
143}
144
Tom Josephbe5eaa12017-07-12 19:54:44 +0530145void readAssetTagObjectTree(dcmi::assettag::ObjectTree& objectTree)
146{
147 static constexpr auto mapperBusName = "xyz.openbmc_project.ObjectMapper";
148 static constexpr auto mapperObjPath = "/xyz/openbmc_project/object_mapper";
149 static constexpr auto mapperIface = "xyz.openbmc_project.ObjectMapper";
150 static constexpr auto inventoryRoot = "/xyz/openbmc_project/inventory/";
151
152 sdbusplus::bus::bus bus{ipmid_get_sd_bus_connection()};
153 auto depth = 0;
154
155 auto mapperCall = bus.new_method_call(mapperBusName,
156 mapperObjPath,
157 mapperIface,
158 "GetSubTree");
159
160 mapperCall.append(inventoryRoot);
161 mapperCall.append(depth);
162 mapperCall.append(std::vector<std::string>({dcmi::assetTagIntf}));
163
164 auto mapperReply = bus.call(mapperCall);
165 if (mapperReply.is_method_error())
166 {
167 log<level::ERR>("Error in mapper call");
168 elog<InternalFailure>();
169 }
170
171 mapperReply.read(objectTree);
172
173 if (objectTree.empty())
174 {
175 log<level::ERR>("AssetTag property is not populated");
176 elog<InternalFailure>();
177 }
178}
179
180std::string readAssetTag()
181{
182 sdbusplus::bus::bus bus{ipmid_get_sd_bus_connection()};
183 dcmi::assettag::ObjectTree objectTree;
184
185 // Read the object tree with the inventory root to figure out the object
186 // that has implemented the Asset tag interface.
187 readAssetTagObjectTree(objectTree);
188
189 auto method = bus.new_method_call(
190 (objectTree.begin()->second.begin()->first).c_str(),
191 (objectTree.begin()->first).c_str(),
192 dcmi::propIntf,
193 "Get");
194 method.append(dcmi::assetTagIntf);
195 method.append(dcmi::assetTagProp);
196
197 auto reply = bus.call(method);
198 if (reply.is_method_error())
199 {
200 log<level::ERR>("Error in reading asset tag");
201 elog<InternalFailure>();
202 }
203
204 sdbusplus::message::variant<std::string> assetTag;
205 reply.read(assetTag);
206
207 return assetTag.get<std::string>();
208}
209
Tom Josephbe5b9892017-07-15 00:55:23 +0530210void writeAssetTag(const std::string& assetTag)
211{
212 sdbusplus::bus::bus bus{ipmid_get_sd_bus_connection()};
213 dcmi::assettag::ObjectTree objectTree;
214
215 // Read the object tree with the inventory root to figure out the object
216 // that has implemented the Asset tag interface.
217 readAssetTagObjectTree(objectTree);
218
219 auto method = bus.new_method_call(
220 (objectTree.begin()->second.begin()->first).c_str(),
221 (objectTree.begin()->first).c_str(),
222 dcmi::propIntf,
223 "Set");
224 method.append(dcmi::assetTagIntf);
225 method.append(dcmi::assetTagProp);
226 method.append(sdbusplus::message::variant<std::string>(assetTag));
227
228 auto reply = bus.call(method);
229 if (reply.is_method_error())
230 {
231 log<level::ERR>("Error in writing asset tag");
232 elog<InternalFailure>();
233 }
234}
235
Vladislav Vovchenko8f7a6f62017-08-17 00:31:14 +0300236std::string getHostName(void)
237{
238 sdbusplus::bus::bus bus{ ipmid_get_sd_bus_connection() };
239
240 auto service = ipmi::getService(bus, networkConfigIntf, networkConfigObj);
241 auto value = ipmi::getDbusProperty(bus, service,
242 networkConfigObj, networkConfigIntf, hostNameProp);
243
244 return value.get<std::string>();
245}
246
Deepak Kodihalli0b459552018-02-06 06:25:12 -0600247Json parseSensorConfig()
248{
249 std::ifstream jsonFile(configFile);
250 if (!jsonFile.is_open())
251 {
252 log<level::ERR>("Temperature readings JSON file not found");
253 elog<InternalFailure>();
254 }
255
256 auto data = Json::parse(jsonFile, nullptr, false);
257 if (data.is_discarded())
258 {
259 log<level::ERR>("Temperature readings JSON parser failure");
260 elog<InternalFailure>();
261 }
262
263 return data;
264}
265
Tom Josephbe5eaa12017-07-12 19:54:44 +0530266} // namespace dcmi
Chris Austen1810bec2015-10-13 12:12:39 -0500267
Tom Josephb9d86f42017-07-26 18:03:47 +0530268ipmi_ret_t getPowerLimit(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
269 ipmi_request_t request, ipmi_response_t response,
270 ipmi_data_len_t data_len, ipmi_context_t context)
271{
272 auto requestData = reinterpret_cast<const dcmi::GetPowerLimitRequest*>
273 (request);
274 std::vector<uint8_t> outPayload(sizeof(dcmi::GetPowerLimitResponse));
275 auto responseData = reinterpret_cast<dcmi::GetPowerLimitResponse*>
276 (outPayload.data());
277
278 if (requestData->groupID != dcmi::groupExtId)
279 {
280 *data_len = 0;
281 return IPMI_CC_INVALID_FIELD_REQUEST;
282 }
283
284 sdbusplus::bus::bus sdbus {ipmid_get_sd_bus_connection()};
285 uint32_t pcapValue = 0;
286 bool pcapEnable = false;
287
288 try
289 {
290 pcapValue = dcmi::getPcap(sdbus);
291 pcapEnable = dcmi::getPcapEnabled(sdbus);
292 }
293 catch (InternalFailure& e)
294 {
295 *data_len = 0;
296 return IPMI_CC_UNSPECIFIED_ERROR;
297 }
298
299 responseData->groupID = dcmi::groupExtId;
300
301 /*
302 * Exception action if power limit is exceeded and cannot be controlled
303 * with the correction time limit is hardcoded to Hard Power Off system
304 * and log event to SEL.
305 */
306 constexpr auto exception = 0x01;
307 responseData->exceptionAction = exception;
308
309 responseData->powerLimit = static_cast<uint16_t>(pcapValue);
310
311 /*
312 * Correction time limit and Statistics sampling period is currently not
313 * populated.
314 */
315
316 *data_len = outPayload.size();
317 memcpy(response, outPayload.data(), *data_len);
318
319 if (pcapEnable)
320 {
321 return IPMI_CC_OK;
322 }
323 else
324 {
325 return IPMI_DCMI_CC_NO_ACTIVE_POWER_LIMIT;
326 }
327}
328
Tom Joseph46fa37d2017-07-26 18:11:55 +0530329ipmi_ret_t setPowerLimit(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
330 ipmi_request_t request, ipmi_response_t response,
331 ipmi_data_len_t data_len, ipmi_context_t context)
332{
333 auto requestData = reinterpret_cast<const dcmi::SetPowerLimitRequest*>
334 (request);
335 std::vector<uint8_t> outPayload(sizeof(dcmi::SetPowerLimitResponse));
336 auto responseData = reinterpret_cast<dcmi::SetPowerLimitResponse*>
337 (outPayload.data());
338
339 if (requestData->groupID != dcmi::groupExtId)
340 {
341 *data_len = 0;
342 return IPMI_CC_INVALID_FIELD_REQUEST;
343 }
344
345 sdbusplus::bus::bus sdbus {ipmid_get_sd_bus_connection()};
346
347 // Only process the power limit requested in watts.
348 try
349 {
350 dcmi::setPcap(sdbus, requestData->powerLimit);
351 }
352 catch (InternalFailure& e)
353 {
354 *data_len = 0;
355 return IPMI_CC_UNSPECIFIED_ERROR;
356 }
357
358 log<level::INFO>("Set Power Cap",
359 entry("POWERCAP=%u", requestData->powerLimit));
360
361 responseData->groupID = dcmi::groupExtId;
362 memcpy(response, outPayload.data(), outPayload.size());
363 *data_len = outPayload.size();
364
365 return IPMI_CC_OK;
366}
367
Tom Joseph6c8d51b2017-07-26 18:18:06 +0530368ipmi_ret_t applyPowerLimit(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
369 ipmi_request_t request, ipmi_response_t response,
370 ipmi_data_len_t data_len, ipmi_context_t context)
371{
372 auto requestData = reinterpret_cast<const dcmi::ApplyPowerLimitRequest*>
373 (request);
374 std::vector<uint8_t> outPayload(sizeof(dcmi::ApplyPowerLimitResponse));
375 auto responseData = reinterpret_cast<dcmi::ApplyPowerLimitResponse*>
376 (outPayload.data());
377
378 if (requestData->groupID != dcmi::groupExtId)
379 {
380 *data_len = 0;
381 return IPMI_CC_INVALID_FIELD_REQUEST;
382 }
383
384 sdbusplus::bus::bus sdbus {ipmid_get_sd_bus_connection()};
385
386 try
387 {
388 dcmi::setPcapEnable(sdbus,
389 static_cast<bool>(requestData->powerLimitAction));
390 }
391 catch (InternalFailure& e)
392 {
393 *data_len = 0;
394 return IPMI_CC_UNSPECIFIED_ERROR;
395 }
396
397 log<level::INFO>("Set Power Cap Enable",
398 entry("POWERCAPENABLE=%u", requestData->powerLimitAction));
399
400 responseData->groupID = dcmi::groupExtId;
401 memcpy(response, outPayload.data(), outPayload.size());
402 *data_len = outPayload.size();
403
404 return IPMI_CC_OK;
405}
406
Tom Joseph6f6dd4d2017-07-12 20:07:11 +0530407ipmi_ret_t getAssetTag(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
408 ipmi_request_t request, ipmi_response_t response,
409 ipmi_data_len_t data_len, ipmi_context_t context)
410{
411 auto requestData = reinterpret_cast<const dcmi::GetAssetTagRequest*>
412 (request);
413 std::vector<uint8_t> outPayload(sizeof(dcmi::GetAssetTagResponse));
414 auto responseData = reinterpret_cast<dcmi::GetAssetTagResponse*>
415 (outPayload.data());
416
417 if (requestData->groupID != dcmi::groupExtId)
418 {
419 *data_len = 0;
420 return IPMI_CC_INVALID_FIELD_REQUEST;
421 }
422
423 // Verify offset to read and number of bytes to read are not exceeding the
424 // range.
425 if ((requestData->offset > dcmi::assetTagMaxOffset) ||
426 (requestData->bytes > dcmi::maxBytes) ||
427 ((requestData->offset + requestData->bytes) > dcmi::assetTagMaxSize))
428 {
429 *data_len = 0;
430 return IPMI_CC_PARM_OUT_OF_RANGE;
431 }
432
433 std::string assetTag;
434
435 try
436 {
437 assetTag = dcmi::readAssetTag();
438 }
439 catch (InternalFailure& e)
440 {
441 *data_len = 0;
442 return IPMI_CC_UNSPECIFIED_ERROR;
443 }
444
445 responseData->groupID = dcmi::groupExtId;
446
447 // Return if the asset tag is not populated.
448 if (!assetTag.size())
449 {
450 responseData->tagLength = 0;
451 memcpy(response, outPayload.data(), outPayload.size());
452 *data_len = outPayload.size();
453 return IPMI_CC_OK;
454 }
455
456 // If the asset tag is longer than 63 bytes, restrict it to 63 bytes to suit
457 // Get Asset Tag command.
458 if (assetTag.size() > dcmi::assetTagMaxSize)
459 {
460 assetTag.resize(dcmi::assetTagMaxSize);
461 }
462
463 // If the requested offset is beyond the asset tag size.
464 if (requestData->offset >= assetTag.size())
465 {
466 *data_len = 0;
467 return IPMI_CC_PARM_OUT_OF_RANGE;
468 }
469
470 auto returnData = assetTag.substr(requestData->offset, requestData->bytes);
471
472 responseData->tagLength = assetTag.size();
473
474 memcpy(response, outPayload.data(), outPayload.size());
475 memcpy(static_cast<uint8_t*>(response) + outPayload.size(),
476 returnData.data(), returnData.size());
477 *data_len = outPayload.size() + returnData.size();
478
479 return IPMI_CC_OK;
480}
481
Tom Joseph545dd232017-07-12 20:20:49 +0530482ipmi_ret_t setAssetTag(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
483 ipmi_request_t request, ipmi_response_t response,
484 ipmi_data_len_t data_len, ipmi_context_t context)
485{
486 auto requestData = reinterpret_cast<const dcmi::SetAssetTagRequest*>
487 (request);
488 std::vector<uint8_t> outPayload(sizeof(dcmi::SetAssetTagResponse));
489 auto responseData = reinterpret_cast<dcmi::SetAssetTagResponse*>
490 (outPayload.data());
491
492 if (requestData->groupID != dcmi::groupExtId)
493 {
494 *data_len = 0;
495 return IPMI_CC_INVALID_FIELD_REQUEST;
496 }
497
498 // Verify offset to read and number of bytes to read are not exceeding the
499 // range.
500 if ((requestData->offset > dcmi::assetTagMaxOffset) ||
501 (requestData->bytes > dcmi::maxBytes) ||
502 ((requestData->offset + requestData->bytes) > dcmi::assetTagMaxSize))
503 {
504 *data_len = 0;
505 return IPMI_CC_PARM_OUT_OF_RANGE;
506 }
507
508 std::string assetTag;
509
510 try
511 {
512 assetTag = dcmi::readAssetTag();
513
514 if (requestData->offset > assetTag.size())
515 {
516 *data_len = 0;
517 return IPMI_CC_PARM_OUT_OF_RANGE;
518 }
519
520 assetTag.replace(requestData->offset,
521 assetTag.size() - requestData->offset,
522 static_cast<const char*>(request) +
523 sizeof(dcmi::SetAssetTagRequest),
524 requestData->bytes);
525
526 dcmi::writeAssetTag(assetTag);
527
528 responseData->groupID = dcmi::groupExtId;
529 responseData->tagLength = assetTag.size();
530 memcpy(response, outPayload.data(), outPayload.size());
531 *data_len = outPayload.size();
532
533 return IPMI_CC_OK;
534 }
535 catch (InternalFailure& e)
536 {
537 *data_len = 0;
538 return IPMI_CC_UNSPECIFIED_ERROR;
539 }
540}
541
Vladislav Vovchenko8f7a6f62017-08-17 00:31:14 +0300542ipmi_ret_t getMgmntCtrlIdStr(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
543 ipmi_request_t request, ipmi_response_t response,
544 ipmi_data_len_t data_len, ipmi_context_t context)
545{
546 auto requestData = reinterpret_cast<const dcmi::GetMgmntCtrlIdStrRequest *>
547 (request);
548 auto responseData = reinterpret_cast<dcmi::GetMgmntCtrlIdStrResponse *>
549 (response);
550 std::string hostName;
551
552 *data_len = 0;
553
554 if (requestData->groupID != dcmi::groupExtId ||
555 requestData->bytes > dcmi::maxBytes ||
556 requestData->offset + requestData->bytes > dcmi::maxCtrlIdStrLen)
557 {
558 return IPMI_CC_INVALID_FIELD_REQUEST;
559 }
560
561 try
562 {
563 hostName = dcmi::getHostName();
564 }
565 catch (InternalFailure& e)
566 {
567 return IPMI_CC_UNSPECIFIED_ERROR;
568 }
569
570 if (requestData->offset > hostName.length())
571 {
572 return IPMI_CC_PARM_OUT_OF_RANGE;
573 }
574 auto responseStr = hostName.substr(requestData->offset, requestData->bytes);
575 auto responseStrLen = std::min(static_cast<std::size_t>(requestData->bytes),
576 responseStr.length() + 1);
577 responseData->groupID = dcmi::groupExtId;
578 responseData->strLen = hostName.length();
579 std::copy(begin(responseStr), end(responseStr), responseData->data);
580
581 *data_len = sizeof(*responseData) + responseStrLen;
582 return IPMI_CC_OK;
583}
584
585ipmi_ret_t setMgmntCtrlIdStr(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
586 ipmi_request_t request, ipmi_response_t response,
587 ipmi_data_len_t data_len, ipmi_context_t context)
588{
589 static std::array<char, dcmi::maxCtrlIdStrLen + 1> newCtrlIdStr;
590
591 auto requestData = reinterpret_cast<const dcmi::SetMgmntCtrlIdStrRequest *>
592 (request);
593 auto responseData = reinterpret_cast<dcmi::SetMgmntCtrlIdStrResponse *>
594 (response);
595
596 *data_len = 0;
597
598 if (requestData->groupID != dcmi::groupExtId ||
599 requestData->bytes > dcmi::maxBytes ||
600 requestData->offset + requestData->bytes > dcmi::maxCtrlIdStrLen + 1 ||
601 (requestData->offset + requestData->bytes == dcmi::maxCtrlIdStrLen + 1 &&
602 requestData->data[requestData->bytes - 1] != '\0'))
603 {
604 return IPMI_CC_INVALID_FIELD_REQUEST;
605 }
606
607 try
608 {
609 /* if there is no old value and offset is not 0 */
610 if (newCtrlIdStr[0] == '\0' && requestData->offset != 0)
611 {
612 /* read old ctrlIdStr */
613 auto hostName = dcmi::getHostName();
614 hostName.resize(dcmi::maxCtrlIdStrLen);
615 std::copy(begin(hostName), end(hostName), begin(newCtrlIdStr));
616 newCtrlIdStr[hostName.length()] = '\0';
617 }
618
619 /* replace part of string and mark byte after the last as \0 */
620 auto restStrIter = std::copy_n(requestData->data,
621 requestData->bytes, begin(newCtrlIdStr) + requestData->offset);
622 /* if the last written byte is not 64th - add '\0' */
623 if (requestData->offset + requestData->bytes <= dcmi::maxCtrlIdStrLen)
624 {
625 *restStrIter = '\0';
626 }
627
628 /* if input data contains '\0' whole string is sent - update hostname */
629 auto it = std::find(requestData->data,
630 requestData->data + requestData->bytes, '\0');
631 if (it != requestData->data + requestData->bytes)
632 {
633 sdbusplus::bus::bus bus{ ipmid_get_sd_bus_connection() };
634 ipmi::setDbusProperty(bus, dcmi::networkServiceName,
635 dcmi::networkConfigObj, dcmi::networkConfigIntf,
636 dcmi::hostNameProp, std::string(newCtrlIdStr.data()));
637 }
638 }
639 catch (InternalFailure& e)
640 {
641 *data_len = 0;
642 return IPMI_CC_UNSPECIFIED_ERROR;
643 }
644
645 responseData->groupID = dcmi::groupExtId;
646 responseData->offset = requestData->offset + requestData->bytes;
647 *data_len = sizeof(*responseData);
648 return IPMI_CC_OK;
649}
650
Dhruvaraj Subhashchandrane29be412018-01-16 05:11:56 -0600651//List of the capabilities under each parameter
652dcmi::DCMICaps dcmiCaps =
653{
654//Supported DCMI Capabilities
655 {
656 dcmi::DCMICapParameters::SUPPORTED_DCMI_CAPS,
657 {
658 3, {{"PowerManagement", 2, 0, 1},
659 {"OOBSecondaryLan", 3, 2, 1},
660 {"SerialTMODE", 3, 1, 1},
661 {"InBandSystemInterfaceChannel", 3, 0, 1}
662 }
663 }
664 },
665//Mandatory Platform Attributes
666 {
667 dcmi::DCMICapParameters::MANDATORY_PLAT_ATTRIBUTES,
668 {
669 5, {{"SELAutoRollOver", 1, 15, 1},
670 {"FlushEntireSELUponRollOver", 1, 14, 1},
671 {"RecordLevelSELFlushUponRollOver", 1, 13, 1},
672 {"NumberOfSELEntries", 1, 0, 12},
673 {"TempMonitoringSamplingFreq", 5, 0, 8}
674 }
675 }
676 },
677//Optional Platform Attributes
678 {
679 dcmi::DCMICapParameters::OPTIONAL_PLAT_ATTRIBUTES,
680 {
681 2, {{"PowerMgmtDeviceSlaveAddress", 1, 1, 7},
682 {"BMCChannelNumber", 2, 4, 4},
683 {"DeviceRivision", 2, 0, 4}
684 }
685 }
686 },
687//Manageability Access Attributes
688 {
689 dcmi::DCMICapParameters::MANAGEABILITY_ACCESS_ATTRIBUTES,
690 {
691 3, {{"MandatoryPrimaryLanOOBSupport", 1, 0, 8},
692 {"OptionalSecondaryLanOOBSupport", 2, 0, 8},
693 {"OptionalSerialOOBMTMODECapability", 3, 0, 8}
694 }
695 }
696 }
697};
698
699ipmi_ret_t getDCMICapabilities(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
700 ipmi_request_t request, ipmi_response_t response,
701 ipmi_data_len_t data_len, ipmi_context_t context)
702{
703
704 std::ifstream dcmiCapFile(DCMI_CAP_JSON_FILE);
705 if (!dcmiCapFile.is_open())
706 {
707 log<level::ERR>("DCMI Capabilities file not found");
708 return IPMI_CC_UNSPECIFIED_ERROR;
709 }
710
711 auto data = nlohmann::json::parse(dcmiCapFile, nullptr, false);
712 if (data.is_discarded())
713 {
714 log<level::ERR>("DCMI Capabilities JSON parser failure");
715 return IPMI_CC_UNSPECIFIED_ERROR;
716 }
717
718 auto requestData = reinterpret_cast<const dcmi::GetDCMICapRequest*>
719 (request);
720
721 //get list of capabilities in a parameter
722 auto caps =
723 dcmiCaps.find(static_cast<dcmi::DCMICapParameters>(requestData->param));
724 if (caps == dcmiCaps.end())
725 {
726 log<level::ERR>("Invalid input parameter");
727 return IPMI_CC_INVALID_FIELD_REQUEST;
728 }
729
730 if (requestData->groupID != dcmi::groupExtId)
731 {
732 *data_len = 0;
733 return IPMI_CC_INVALID_FIELD_REQUEST;
734 }
735
736 auto responseData = reinterpret_cast<dcmi::GetDCMICapResponse*>
737 (response);
738
739 //For each capabilities in a parameter fill the data from
740 //the json file based on the capability name.
741 for (auto cap : caps->second.capList)
742 {
743 //If the data is beyond first byte boundary, insert in a
744 //16bit pattern for example number of SEL entries are represented
745 //in 12bits.
746 if ((cap.length + cap.position) > 8)
747 {
748 //Read the value corresponding to capability name and assign to
749 //16bit bitset.
750 std::bitset<16> val(data.value(cap.name.c_str(), 0));
751 val <<= cap.position;
752 reinterpret_cast<uint16_t*>(responseData->data)[
753 (cap.bytePosition - 1) / sizeof(uint16_t)] |= val.to_ulong();
754 }
755 else
756 {
757 responseData->data[cap.bytePosition - 1] |=
758 data.value(cap.name.c_str(), 0) << cap.position;
759 }
760 }
761
762 responseData->groupID = dcmi::groupExtId;
763 responseData->major = DCMI_SPEC_MAJOR_VERSION;
764 responseData->minor = DCMI_SPEC_MINOR_VERSION;
765 responseData->paramRevision = DCMI_PARAMETER_REVISION;
766 *data_len = sizeof(*responseData) + caps->second.size;
767
768 return IPMI_CC_OK;
769}
770
Deepak Kodihalliee717d72018-01-24 04:53:09 -0600771namespace dcmi
772{
773namespace temp_readings
774{
775
Deepak Kodihallib1e8fba2018-01-24 04:57:10 -0600776Temperature readTemp(const std::string& dbusService,
777 const std::string& dbusPath)
778{
779 // Read the temperature value from d-bus object. Need some conversion.
780 // As per the interface xyz.openbmc_project.Sensor.Value, the temperature
781 // is an int64_t and in degrees C. It needs to be scaled by using the
782 // formula Value * 10^Scale. The ipmi spec has the temperature as a uint8_t,
783 // with a separate single bit for the sign.
784
785 sdbusplus::bus::bus bus{ipmid_get_sd_bus_connection()};
786 auto result = ipmi::getAllDbusProperties(bus, dbusService, dbusPath,
787 "xyz.openbmc_project.Sensor.Value");
788 auto temperature = result.at("Value").get<int64_t>();
789 uint64_t absTemp = std::abs(temperature);
790
791 auto factor = result.at("Scale").get<int64_t>();
792 uint64_t scale = std::pow(10, factor); // pow() returns float/double
793 unsigned long long tempDegrees = 0;
794 // Overflow safe multiplication when the scale is > 0
795 if (scale && __builtin_umulll_overflow(
796 absTemp, scale, &tempDegrees))
797 {
798 log<level::ERR>("Multiplication overflow detected",
799 entry("TEMP_VALUE=%llu", absTemp),
800 entry("SCALE_FACTOR=%llu", scale));
801 elog<InternalFailure>();
802 }
803 else
804 {
805 // The (uint64_t)scale value is 0, effectively this is division
806 tempDegrees = absTemp * std::pow(10, factor);
807 }
808 // Max absolute temp as per ipmi spec is 128.
809 if (tempDegrees > maxTemp)
810 {
811 tempDegrees = maxTemp;
812 }
813
814 return std::make_tuple(static_cast<uint8_t>(tempDegrees),
815 (temperature < 0));
816}
817
Deepak Kodihalliee717d72018-01-24 04:53:09 -0600818std::tuple<Response, NumInstances> read(const std::string& type,
819 uint8_t instance)
820{
Deepak Kodihallib1e8fba2018-01-24 04:57:10 -0600821 Response response{};
822 sdbusplus::bus::bus bus{ipmid_get_sd_bus_connection()};
823
824 if (!instance)
825 {
826 log<level::ERR>("Expected non-zero instance");
827 elog<InternalFailure>();
828 }
829
Deepak Kodihalli0b459552018-02-06 06:25:12 -0600830 auto data = parseSensorConfig();
Deepak Kodihallib1e8fba2018-01-24 04:57:10 -0600831 static const std::vector<Json> empty{};
832 std::vector<Json> readings = data.value(type, empty);
833 size_t numInstances = readings.size();
834 for (const auto& j : readings)
835 {
836 uint8_t instanceNum = j.value("instance", 0);
837 // Not the instance we're interested in
838 if (instanceNum != instance)
839 {
840 continue;
841 }
842
843 std::string path = j.value("dbus", "");
844 std::string service;
845 try
846 {
847 service =
848 ipmi::getService(bus,
849 "xyz.openbmc_project.Sensor.Value",
850 path);
851 }
852 catch (std::exception& e)
853 {
854 log<level::DEBUG>(e.what());
855 return std::make_tuple(response, numInstances);
856 }
857
858 response.instance = instance;
859 uint8_t temp{};
860 bool sign{};
861 std::tie(temp, sign) = readTemp(service, path);
862 response.temperature = temp;
863 response.sign = sign;
864
865 // Found the instance we're interested in
866 break;
867 }
868
869 if (numInstances > maxInstances)
870 {
871 numInstances = maxInstances;
872 }
873 return std::make_tuple(response, numInstances);
Deepak Kodihalliee717d72018-01-24 04:53:09 -0600874}
875
876std::tuple<ResponseList, NumInstances> readAll(const std::string& type,
877 uint8_t instanceStart)
878{
Deepak Kodihallib1e8fba2018-01-24 04:57:10 -0600879 ResponseList response{};
880 sdbusplus::bus::bus bus{ipmid_get_sd_bus_connection()};
881
882 size_t numInstances = 0;
Deepak Kodihalli0b459552018-02-06 06:25:12 -0600883 auto data = parseSensorConfig();
Deepak Kodihallib1e8fba2018-01-24 04:57:10 -0600884 static const std::vector<Json> empty{};
885 std::vector<Json> readings = data.value(type, empty);
886 numInstances = readings.size();
887 for (const auto& j : readings)
888 {
889 try
890 {
891 // Max of 8 response data sets
892 if (response.size() == maxDataSets)
893 {
894 break;
895 }
896
897 uint8_t instanceNum = j.value("instance", 0);
898 // Not in the instance range we're interested in
899 if (instanceNum < instanceStart)
900 {
901 continue;
902 }
903
904 std::string path = j.value("dbus", "");
905 auto service =
906 ipmi::getService(bus,
907 "xyz.openbmc_project.Sensor.Value",
908 path);
909
910 Response r{};
911 r.instance = instanceNum;
912 uint8_t temp{};
913 bool sign{};
914 std::tie(temp, sign) = readTemp(service, path);
915 r.temperature = temp;
916 r.sign = sign;
917 response.push_back(r);
918 }
919 catch (std::exception& e)
920 {
921 log<level::DEBUG>(e.what());
922 continue;
923 }
924 }
925
926 if (numInstances > maxInstances)
927 {
928 numInstances = maxInstances;
929 }
930 return std::make_tuple(response, numInstances);
Deepak Kodihalliee717d72018-01-24 04:53:09 -0600931}
932
933} // namsespace temp_readings
934} // namsepace dcmi
935
936ipmi_ret_t getTempReadings(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
937 ipmi_request_t request, ipmi_response_t response,
938 ipmi_data_len_t data_len, ipmi_context_t context)
939{
Deepak Kodihalliee717d72018-01-24 04:53:09 -0600940 auto requestData =
941 reinterpret_cast<const dcmi::GetTempReadingsRequest*>(request);
942 auto responseData =
943 reinterpret_cast<dcmi::GetTempReadingsResponseHdr*>(response);
944
945 if (*data_len != sizeof(dcmi::GetTempReadingsRequest))
946 {
947 log<level::ERR>("Malformed request data",
948 entry("DATA_SIZE=%d", *data_len));
949 return IPMI_CC_REQ_DATA_LEN_INVALID;
950 }
951 *data_len = 0;
952
Deepak Kodihalli0b459552018-02-06 06:25:12 -0600953 auto it = dcmi::entityIdToName.find(requestData->entityId);
954 if (it == dcmi::entityIdToName.end())
Deepak Kodihalliee717d72018-01-24 04:53:09 -0600955 {
956 log<level::ERR>("Unknown Entity ID",
957 entry("ENTITY_ID=%d", requestData->entityId));
958 return IPMI_CC_INVALID_FIELD_REQUEST;
959 }
960
961 if (requestData->groupID != dcmi::groupExtId)
962 {
963 log<level::ERR>("Invalid Group ID",
964 entry("GROUP_ID=%d", requestData->groupID));
965 return IPMI_CC_INVALID_FIELD_REQUEST;
966 }
967
968 if (requestData->sensorType != dcmi::temperatureSensorType)
969 {
970 log<level::ERR>("Invalid sensor type",
971 entry("SENSOR_TYPE=%d", requestData->sensorType));
972 return IPMI_CC_INVALID_FIELD_REQUEST;
973 }
974
975 dcmi::temp_readings::ResponseList temps{};
976 try
977 {
978 if (!requestData->entityInstance)
979 {
980 // Read all instances
981 std::tie(temps, responseData->numInstances) =
982 dcmi::temp_readings::readAll(it->second,
983 requestData->instanceStart);
984 }
985 else
986 {
987 // Read one instance
988 temps.resize(1);
989 std::tie(temps[0], responseData->numInstances) =
990 dcmi::temp_readings::read(it->second,
991 requestData->entityInstance);
992 }
993 responseData->numDataSets = temps.size();
994 }
995 catch (InternalFailure& e)
996 {
997 return IPMI_CC_UNSPECIFIED_ERROR;
998 }
999
1000 responseData->groupID = dcmi::groupExtId;
1001 size_t payloadSize =
1002 temps.size() * sizeof(dcmi::temp_readings::Response);
1003 if (!temps.empty())
1004 {
1005 memcpy(responseData + 1, // copy payload right after the response header
1006 temps.data(),
1007 payloadSize);
1008 }
1009 *data_len = sizeof(dcmi::GetTempReadingsResponseHdr) + payloadSize;
1010
1011 return IPMI_CC_OK;
1012}
1013
Marri Devender Rao66c5fda2018-01-18 10:48:37 -06001014int64_t getPowerReading(sdbusplus::bus::bus& bus)
1015{
1016 std::ifstream sensorFile(POWER_READING_SENSOR);
1017 std::string objectPath;
1018 if (!sensorFile.is_open())
1019 {
1020 log<level::ERR>("Power reading configuration file not found",
1021 entry("POWER_SENSOR_FILE=%s", POWER_READING_SENSOR));
1022 elog<InternalFailure>();
1023 }
1024
1025 auto data = nlohmann::json::parse(sensorFile, nullptr, false);
1026 if (data.is_discarded())
1027 {
1028 log<level::ERR>("Error in parsing configuration file",
1029 entry("POWER_SENSOR_FILE=%s", POWER_READING_SENSOR));
1030 elog<InternalFailure>();
1031 }
1032
1033 objectPath = data.value("path", "");
1034 if (objectPath.empty())
1035 {
1036 log<level::ERR>("Power sensor D-Bus object path is empty",
1037 entry("POWER_SENSOR_FILE=%s", POWER_READING_SENSOR));
1038 elog<InternalFailure>();
1039 }
1040
Marri Devender Raoce6a7952018-02-11 08:45:00 -06001041 // Return default value if failed to read from D-Bus object
1042 int64_t power = 0;
1043 try
1044 {
1045 auto service = ipmi::getService(bus, SENSOR_VALUE_INTF, objectPath);
Marri Devender Rao66c5fda2018-01-18 10:48:37 -06001046
Marri Devender Raoce6a7952018-02-11 08:45:00 -06001047 //Read the sensor value and scale properties
1048 auto properties = ipmi::getAllDbusProperties(
1049 bus, service, objectPath, SENSOR_VALUE_INTF);
1050 auto value = properties[SENSOR_VALUE_PROP].get<int64_t>();
1051 auto scale = properties[SENSOR_SCALE_PROP].get<int64_t>();
Marri Devender Rao66c5fda2018-01-18 10:48:37 -06001052
Marri Devender Raoce6a7952018-02-11 08:45:00 -06001053 // Power reading needs to be scaled with the Scale value using the
1054 // formula Value * 10^Scale.
1055 power = value * std::pow(10, scale);
1056 }
1057 catch (std::exception& e)
1058 {
1059 log<level::INFO>("Failure to read power value from D-Bus object",
1060 entry("OBJECT_PATH=%s", objectPath),
1061 entry("INTERFACE=%s", SENSOR_VALUE_INTF));
1062 }
Marri Devender Rao66c5fda2018-01-18 10:48:37 -06001063 return power;
1064}
1065
1066ipmi_ret_t getPowerReading(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
1067 ipmi_request_t request, ipmi_response_t response,
1068 ipmi_data_len_t data_len, ipmi_context_t context)
1069{
1070 ipmi_ret_t rc = IPMI_CC_OK;
Marri Devender Rao9c966e02018-01-22 05:55:10 -06001071 auto requestData = reinterpret_cast<const dcmi::GetPowerReadingRequest*>
1072 (request);
1073 auto responseData = reinterpret_cast<dcmi::GetPowerReadingResponse*>
1074 (response);
1075
1076 if (requestData->groupID != dcmi::groupExtId)
1077 {
1078 *data_len = 0;
1079 return IPMI_CC_INVALID_FIELD_REQUEST;
1080 }
1081
Marri Devender Rao66c5fda2018-01-18 10:48:37 -06001082 sdbusplus::bus::bus bus{ipmid_get_sd_bus_connection()};
Marri Devender Rao9c966e02018-01-22 05:55:10 -06001083 int64_t power = 0;
Marri Devender Rao66c5fda2018-01-18 10:48:37 -06001084 try
1085 {
Marri Devender Rao9c966e02018-01-22 05:55:10 -06001086 power = getPowerReading(bus);
Marri Devender Rao66c5fda2018-01-18 10:48:37 -06001087 }
1088 catch (InternalFailure& e)
1089 {
1090 log<level::ERR>("Error in reading power sensor value",
1091 entry("INTERFACE=%s", SENSOR_VALUE_INTF),
1092 entry("PROPERTY=%s", SENSOR_VALUE_PROP));
1093 return IPMI_CC_UNSPECIFIED_ERROR;
1094 }
Marri Devender Rao9c966e02018-01-22 05:55:10 -06001095 responseData->groupID = dcmi::groupExtId;
1096
1097 // TODO: openbmc/openbmc#2819
1098 // Minumum, Maximum, Average power, TimeFrame, TimeStamp,
1099 // PowerReadingState readings need to be populated
1100 // after Telemetry changes.
1101 uint16_t totalPower = static_cast<uint16_t>(power);
1102 responseData->currentPower = totalPower;
1103 responseData->minimumPower = totalPower;
1104 responseData->maximumPower = totalPower;
1105 responseData->averagePower = totalPower;
1106
1107 *data_len = sizeof(*responseData);
Marri Devender Rao66c5fda2018-01-18 10:48:37 -06001108 return rc;
1109}
1110
Deepak Kodihalli0b459552018-02-06 06:25:12 -06001111namespace dcmi
1112{
1113namespace sensor_info
1114{
1115
Deepak Kodihallidd4cff12018-02-06 06:48:29 -06001116Response createFromJson(const Json& config)
1117{
1118 Response response{};
1119 uint16_t recordId = config.value("record_id", 0);
1120 response.recordIdLsb = recordId & 0xFF;
1121 response.recordIdMsb = (recordId >> 8) & 0xFF;
1122 return response;
1123}
1124
Deepak Kodihalli0b459552018-02-06 06:25:12 -06001125std::tuple<Response, NumInstances> read(const std::string& type,
1126 uint8_t instance,
1127 const Json& config)
1128{
Deepak Kodihallidd4cff12018-02-06 06:48:29 -06001129 Response response{};
1130
1131 if (!instance)
1132 {
1133 log<level::ERR>("Expected non-zero instance");
1134 elog<InternalFailure>();
1135 }
1136
1137 static const std::vector<Json> empty{};
1138 std::vector<Json> readings = config.value(type, empty);
1139 size_t numInstances = readings.size();
1140 for (const auto& reading : readings)
1141 {
1142 uint8_t instanceNum = reading.value("instance", 0);
1143 // Not the instance we're interested in
1144 if (instanceNum != instance)
1145 {
1146 continue;
1147 }
1148
1149 response = createFromJson(reading);
1150
1151 // Found the instance we're interested in
1152 break;
1153 }
1154
1155 if (numInstances > maxInstances)
1156 {
1157 log<level::DEBUG>("Trimming IPMI num instances",
1158 entry("NUM_INSTANCES=%d", numInstances));
1159 numInstances = maxInstances;
1160 }
1161 return std::make_tuple(response, numInstances);
Deepak Kodihalli0b459552018-02-06 06:25:12 -06001162}
1163
1164std::tuple<ResponseList, NumInstances> readAll(const std::string& type,
1165 uint8_t instanceStart,
1166 const Json& config)
1167{
Deepak Kodihallidd4cff12018-02-06 06:48:29 -06001168 ResponseList responses{};
1169
1170 size_t numInstances = 0;
1171 static const std::vector<Json> empty{};
1172 std::vector<Json> readings = config.value(type, empty);
1173 numInstances = readings.size();
1174 for (const auto& reading : readings)
1175 {
1176 try
1177 {
1178 // Max of 8 records
1179 if (responses.size() == maxRecords)
1180 {
1181 break;
1182 }
1183
1184 uint8_t instanceNum = reading.value("instance", 0);
1185 // Not in the instance range we're interested in
1186 if (instanceNum < instanceStart)
1187 {
1188 continue;
1189 }
1190
1191 Response response = createFromJson(reading);
1192 responses.push_back(response);
1193 }
1194 catch (std::exception& e)
1195 {
1196 log<level::DEBUG>(e.what());
1197 continue;
1198 }
1199 }
1200
1201 if (numInstances > maxInstances)
1202 {
1203 log<level::DEBUG>("Trimming IPMI num instances",
1204 entry("NUM_INSTANCES=%d", numInstances));
1205 numInstances = maxInstances;
1206 }
1207 return std::make_tuple(responses, numInstances);
Deepak Kodihalli0b459552018-02-06 06:25:12 -06001208}
1209
1210} // namespace sensor_info
1211} // namespace dcmi
1212
1213ipmi_ret_t getSensorInfo(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
1214 ipmi_request_t request, ipmi_response_t response,
1215 ipmi_data_len_t data_len, ipmi_context_t context)
1216{
1217 auto requestData =
1218 reinterpret_cast<const dcmi::GetSensorInfoRequest*>(request);
1219 auto responseData =
1220 reinterpret_cast<dcmi::GetSensorInfoResponseHdr*>(response);
1221
1222 if (*data_len != sizeof(dcmi::GetSensorInfoRequest))
1223 {
1224 log<level::ERR>("Malformed request data",
1225 entry("DATA_SIZE=%d", *data_len));
1226 return IPMI_CC_REQ_DATA_LEN_INVALID;
1227 }
1228 *data_len = 0;
1229
1230 auto it = dcmi::entityIdToName.find(requestData->entityId);
1231 if (it == dcmi::entityIdToName.end())
1232 {
1233 log<level::ERR>("Unknown Entity ID",
1234 entry("ENTITY_ID=%d", requestData->entityId));
1235 return IPMI_CC_INVALID_FIELD_REQUEST;
1236 }
1237
1238 if (requestData->groupID != dcmi::groupExtId)
1239 {
1240 log<level::ERR>("Invalid Group ID",
1241 entry("GROUP_ID=%d", requestData->groupID));
1242 return IPMI_CC_INVALID_FIELD_REQUEST;
1243 }
1244
1245 if (requestData->sensorType != dcmi::temperatureSensorType)
1246 {
1247 log<level::ERR>("Invalid sensor type",
1248 entry("SENSOR_TYPE=%d", requestData->sensorType));
1249 return IPMI_CC_INVALID_FIELD_REQUEST;
1250 }
1251
1252 dcmi::sensor_info::ResponseList sensors{};
1253 static dcmi::Json config{};
1254 static bool parsed = false;
1255
1256 try
1257 {
1258 if (!parsed)
1259 {
1260 config = dcmi::parseSensorConfig();
1261 parsed = true;
1262 }
1263
1264 if (!requestData->entityInstance)
1265 {
1266 // Read all instances
1267 std::tie(sensors, responseData->numInstances) =
1268 dcmi::sensor_info::readAll(it->second,
1269 requestData->instanceStart,
1270 config);
1271 }
1272 else
1273 {
1274 // Read one instance
1275 sensors.resize(1);
1276 std::tie(sensors[0], responseData->numInstances) =
1277 dcmi::sensor_info::read(it->second,
1278 requestData->entityInstance,
1279 config);
1280 }
1281 responseData->numRecords = sensors.size();
1282 }
1283 catch (InternalFailure& e)
1284 {
1285 return IPMI_CC_UNSPECIFIED_ERROR;
1286 }
1287
1288 responseData->groupID = dcmi::groupExtId;
1289 size_t payloadSize = sensors.size() * sizeof(dcmi::sensor_info::Response);
1290 if (!sensors.empty())
1291 {
1292 memcpy(responseData + 1, // copy payload right after the response header
1293 sensors.data(),
1294 payloadSize);
1295 }
1296 *data_len = sizeof(dcmi::GetSensorInfoResponseHdr) + payloadSize;
1297
1298 return IPMI_CC_OK;
1299}
1300
Chris Austen1810bec2015-10-13 12:12:39 -05001301void register_netfn_dcmi_functions()
1302{
Tom05732372016-09-06 17:21:23 +05301303 // <Get Power Limit>
Ratan Gupta11ddbd22017-08-05 11:59:39 +05301304 printf("Registering NetFn:[0x%X], Cmd:[0x%X]\n",
1305 NETFUN_GRPEXT, dcmi::Commands::GET_POWER_LIMIT);
1306
1307 ipmi_register_callback(NETFUN_GRPEXT, dcmi::Commands::GET_POWER_LIMIT,
1308 NULL, getPowerLimit, PRIVILEGE_USER);
Tom Joseph6f6dd4d2017-07-12 20:07:11 +05301309
Tom Joseph46fa37d2017-07-26 18:11:55 +05301310 // <Set Power Limit>
Ratan Gupta11ddbd22017-08-05 11:59:39 +05301311 printf("Registering NetFn:[0x%X], Cmd:[0x%X]\n",
1312 NETFUN_GRPEXT, dcmi::Commands::SET_POWER_LIMIT);
1313
1314 ipmi_register_callback(NETFUN_GRPEXT, dcmi::Commands::SET_POWER_LIMIT,
1315 NULL, setPowerLimit, PRIVILEGE_OPERATOR);
Tom Joseph46fa37d2017-07-26 18:11:55 +05301316
Tom Joseph6c8d51b2017-07-26 18:18:06 +05301317 // <Activate/Deactivate Power Limit>
Ratan Gupta11ddbd22017-08-05 11:59:39 +05301318 printf("Registering NetFn:[0x%X], Cmd:[0x%X]\n",
1319 NETFUN_GRPEXT, dcmi::Commands::APPLY_POWER_LIMIT);
1320
1321 ipmi_register_callback(NETFUN_GRPEXT, dcmi::Commands::APPLY_POWER_LIMIT,
1322 NULL, applyPowerLimit, PRIVILEGE_OPERATOR);
Tom Joseph6c8d51b2017-07-26 18:18:06 +05301323
Tom Joseph6f6dd4d2017-07-12 20:07:11 +05301324 // <Get Asset Tag>
Ratan Gupta11ddbd22017-08-05 11:59:39 +05301325 printf("Registering NetFn:[0x%X], Cmd:[0x%X]\n",
1326 NETFUN_GRPEXT, dcmi::Commands::GET_ASSET_TAG);
1327
1328 ipmi_register_callback(NETFUN_GRPEXT, dcmi::Commands::GET_ASSET_TAG,
1329 NULL, getAssetTag, PRIVILEGE_USER);
Tom Joseph545dd232017-07-12 20:20:49 +05301330
1331 // <Set Asset Tag>
Ratan Gupta11ddbd22017-08-05 11:59:39 +05301332 printf("Registering NetFn:[0x%X], Cmd:[0x%X]\n",
1333 NETFUN_GRPEXT, dcmi::Commands::SET_ASSET_TAG);
1334
1335 ipmi_register_callback(NETFUN_GRPEXT, dcmi::Commands::SET_ASSET_TAG,
1336 NULL, setAssetTag, PRIVILEGE_OPERATOR);
Vladislav Vovchenko8f7a6f62017-08-17 00:31:14 +03001337
Gunnar Mills8991dd62017-10-25 17:11:29 -05001338 // <Get Management Controller Identifier String>
Vladislav Vovchenko8f7a6f62017-08-17 00:31:14 +03001339 printf("Registering NetFn:[0x%X], Cmd:[0x%X]\n",
1340 NETFUN_GRPEXT, dcmi::Commands::GET_MGMNT_CTRL_ID_STR);
1341
1342 ipmi_register_callback(NETFUN_GRPEXT, dcmi::Commands::GET_MGMNT_CTRL_ID_STR,
1343 NULL, getMgmntCtrlIdStr, PRIVILEGE_USER);
1344
1345 // <Set Management Controller Identifier String>
1346 printf("Registering NetFn:[0x%X], Cmd:[0x%X]\n",
1347 NETFUN_GRPEXT, dcmi::Commands::SET_MGMNT_CTRL_ID_STR);
1348 ipmi_register_callback(NETFUN_GRPEXT, dcmi::Commands::SET_MGMNT_CTRL_ID_STR,
1349 NULL, setMgmntCtrlIdStr, PRIVILEGE_ADMIN);
1350
Dhruvaraj Subhashchandrane29be412018-01-16 05:11:56 -06001351 // <Get DCMI capabilities>
1352 ipmi_register_callback(NETFUN_GRPEXT, dcmi::Commands::GET_CAPABILITIES,
1353 NULL, getDCMICapabilities, PRIVILEGE_USER);
Deepak Kodihalliee717d72018-01-24 04:53:09 -06001354
1355 // <Get Temperature Readings>
1356 ipmi_register_callback(NETFUN_GRPEXT, dcmi::Commands::GET_TEMP_READINGS,
1357 NULL, getTempReadings, PRIVILEGE_USER);
1358
Marri Devender Rao66c5fda2018-01-18 10:48:37 -06001359 // <Get Power Reading>
1360 ipmi_register_callback(NETFUN_GRPEXT, dcmi::Commands::GET_POWER_READING,
1361 NULL, getPowerReading, PRIVILEGE_USER);
Deepak Kodihalli0b459552018-02-06 06:25:12 -06001362
1363 // <Get Sensor Info>
1364 ipmi_register_callback(NETFUN_GRPEXT, dcmi::Commands::GET_SENSOR_INFO,
1365 NULL, getSensorInfo, PRIVILEGE_USER);
1366
Chris Austen1810bec2015-10-13 12:12:39 -05001367 return;
1368}
Tom05732372016-09-06 17:21:23 +05301369// 956379