blob: 951b6ba3a1635fc3e2685a97664ab8ac563cce19 [file] [log] [blame]
Patrick Venture0b02be92018-08-31 11:55:55 -07001#include "config.h"
2
Tom Josephbe5eaa12017-07-12 19:54:44 +05303#include "dcmihandler.hpp"
Patrick Venture0b02be92018-08-31 11:55:55 -07004
5#include "net.hpp"
6#include "utils.hpp"
7
8#include <stdint.h>
9#include <stdio.h>
10#include <string.h>
11
12#include <bitset>
13#include <cmath>
14#include <fstream>
15#include <nlohmann/json.hpp>
Tom Josephbe5eaa12017-07-12 19:54:44 +053016#include <phosphor-logging/elog-errors.hpp>
Andrew Geissler50c0c8f2017-07-11 16:18:51 -050017#include <phosphor-logging/log.hpp>
18#include <sdbusplus/bus.hpp>
Patrick Venture0b02be92018-08-31 11:55:55 -070019#include <xyz/openbmc_project/Common/error.hpp>
20
21#include "host-ipmid/ipmid-api.h"
Tom Josephbe5eaa12017-07-12 19:54:44 +053022
23using namespace phosphor::logging;
24using InternalFailure =
Patrick Venture0b02be92018-08-31 11:55:55 -070025 sdbusplus::xyz::openbmc_project::Common::Error::InternalFailure;
Chris Austen1810bec2015-10-13 12:12:39 -050026
27void register_netfn_dcmi_functions() __attribute__((constructor));
28
Patrick Venture0b02be92018-08-31 11:55:55 -070029constexpr auto PCAP_PATH = "/xyz/openbmc_project/control/host0/power_cap";
Andrew Geissler50c0c8f2017-07-11 16:18:51 -050030constexpr auto PCAP_INTERFACE = "xyz.openbmc_project.Control.Power.Cap";
31
32constexpr auto POWER_CAP_PROP = "PowerCap";
33constexpr auto POWER_CAP_ENABLE_PROP = "PowerCapEnable";
34
Dhruvaraj Subhashchandrane29be412018-01-16 05:11:56 -060035constexpr auto DCMI_PARAMETER_REVISION = 2;
36constexpr auto DCMI_SPEC_MAJOR_VERSION = 1;
37constexpr auto DCMI_SPEC_MINOR_VERSION = 5;
Nagaraju Goruganti22be97b2018-02-07 01:19:59 -060038constexpr auto DCMI_CONFIG_PARAMETER_REVISION = 1;
39constexpr auto DCMI_RAND_BACK_OFF_MASK = 0x80;
40constexpr auto DCMI_OPTION_60_43_MASK = 0x02;
41constexpr auto DCMI_OPTION_12_MASK = 0x01;
42constexpr auto DCMI_ACTIVATE_DHCP_MASK = 0x01;
43constexpr auto DCMI_ACTIVATE_DHCP_REPLY = 0x00;
44constexpr auto DCMI_SET_CONF_PARAM_REQ_PACKET_MAX_SIZE = 0x05;
45constexpr auto DCMI_SET_CONF_PARAM_REQ_PACKET_MIN_SIZE = 0x04;
Patrick Venture0b02be92018-08-31 11:55:55 -070046constexpr auto DHCP_TIMING1 = 0x04; // 4 sec
47constexpr auto DHCP_TIMING2_UPPER = 0x00; // 2 min
Nagaraju Goruganti22be97b2018-02-07 01:19:59 -060048constexpr auto DHCP_TIMING2_LOWER = 0x78;
Patrick Venture0b02be92018-08-31 11:55:55 -070049constexpr auto DHCP_TIMING3_UPPER = 0x00; // 64 sec
Nagaraju Goruganti22be97b2018-02-07 01:19:59 -060050constexpr auto DHCP_TIMING3_LOWER = 0x40;
51// When DHCP Option 12 is enabled the string "SendHostName=true" will be
52// added into n/w configuration file and the parameter
53// SendHostNameEnabled will set to true.
54constexpr auto DHCP_OPT12_ENABLED = "SendHostNameEnabled";
55
Dhruvaraj Subhashchandrane29be412018-01-16 05:11:56 -060056constexpr auto DCMI_CAP_JSON_FILE = "/usr/share/ipmi-providers/dcmi_cap.json";
57
Marri Devender Rao66c5fda2018-01-18 10:48:37 -060058constexpr auto SENSOR_VALUE_INTF = "xyz.openbmc_project.Sensor.Value";
59constexpr auto SENSOR_VALUE_PROP = "Value";
60constexpr auto SENSOR_SCALE_PROP = "Scale";
61
Andrew Geissler50c0c8f2017-07-11 16:18:51 -050062using namespace phosphor::logging;
63
Tom Josephb9d86f42017-07-26 18:03:47 +053064namespace dcmi
65{
66
Deepak Kodihalli0b459552018-02-06 06:25:12 -060067// Refer Table 6-14, DCMI Entity ID Extension, DCMI v1.5 spec
Patrick Venture0b02be92018-08-31 11:55:55 -070068static const std::map<uint8_t, std::string> entityIdToName{
69 {0x40, "inlet"}, {0x37, "inlet"}, {0x41, "cpu"},
70 {0x03, "cpu"}, {0x42, "baseboard"}, {0x07, "baseboard"}};
Deepak Kodihalli0b459552018-02-06 06:25:12 -060071
Andrew Geissler50c0c8f2017-07-11 16:18:51 -050072uint32_t getPcap(sdbusplus::bus::bus& bus)
73{
Patrick Venture0b02be92018-08-31 11:55:55 -070074 auto settingService = ipmi::getService(bus, PCAP_INTERFACE, PCAP_PATH);
Andrew Geissler50c0c8f2017-07-11 16:18:51 -050075
Patrick Venture0b02be92018-08-31 11:55:55 -070076 auto method = bus.new_method_call(settingService.c_str(), PCAP_PATH,
77 "org.freedesktop.DBus.Properties", "Get");
Andrew Geissler50c0c8f2017-07-11 16:18:51 -050078
79 method.append(PCAP_INTERFACE, POWER_CAP_PROP);
80 auto reply = bus.call(method);
81
82 if (reply.is_method_error())
83 {
84 log<level::ERR>("Error in getPcap prop");
Tom Josephb9d86f42017-07-26 18:03:47 +053085 elog<InternalFailure>();
Andrew Geissler50c0c8f2017-07-11 16:18:51 -050086 }
87 sdbusplus::message::variant<uint32_t> pcap;
88 reply.read(pcap);
89
Tom Josephb9d86f42017-07-26 18:03:47 +053090 return pcap.get<uint32_t>();
Andrew Geissler50c0c8f2017-07-11 16:18:51 -050091}
92
93bool getPcapEnabled(sdbusplus::bus::bus& bus)
94{
Patrick Venture0b02be92018-08-31 11:55:55 -070095 auto settingService = ipmi::getService(bus, PCAP_INTERFACE, PCAP_PATH);
Andrew Geissler50c0c8f2017-07-11 16:18:51 -050096
Patrick Venture0b02be92018-08-31 11:55:55 -070097 auto method = bus.new_method_call(settingService.c_str(), PCAP_PATH,
98 "org.freedesktop.DBus.Properties", "Get");
Andrew Geissler50c0c8f2017-07-11 16:18:51 -050099
100 method.append(PCAP_INTERFACE, POWER_CAP_ENABLE_PROP);
101 auto reply = bus.call(method);
102
103 if (reply.is_method_error())
104 {
105 log<level::ERR>("Error in getPcapEnabled prop");
Tom Josephb9d86f42017-07-26 18:03:47 +0530106 elog<InternalFailure>();
Andrew Geissler50c0c8f2017-07-11 16:18:51 -0500107 }
108 sdbusplus::message::variant<bool> pcapEnabled;
109 reply.read(pcapEnabled);
110
Tom Josephb9d86f42017-07-26 18:03:47 +0530111 return pcapEnabled.get<bool>();
Andrew Geissler50c0c8f2017-07-11 16:18:51 -0500112}
Chris Austen1810bec2015-10-13 12:12:39 -0500113
Tom Joseph46fa37d2017-07-26 18:11:55 +0530114void setPcap(sdbusplus::bus::bus& bus, const uint32_t powerCap)
115{
116 auto service = ipmi::getService(bus, PCAP_INTERFACE, PCAP_PATH);
117
Patrick Venture0b02be92018-08-31 11:55:55 -0700118 auto method = bus.new_method_call(service.c_str(), PCAP_PATH,
119 "org.freedesktop.DBus.Properties", "Set");
Tom Joseph46fa37d2017-07-26 18:11:55 +0530120
121 method.append(PCAP_INTERFACE, POWER_CAP_PROP);
122 method.append(sdbusplus::message::variant<uint32_t>(powerCap));
123
124 auto reply = bus.call(method);
125
126 if (reply.is_method_error())
127 {
128 log<level::ERR>("Error in setPcap property");
129 elog<InternalFailure>();
130 }
131}
132
Tom Joseph6c8d51b2017-07-26 18:18:06 +0530133void setPcapEnable(sdbusplus::bus::bus& bus, bool enabled)
134{
135 auto service = ipmi::getService(bus, PCAP_INTERFACE, PCAP_PATH);
136
Patrick Venture0b02be92018-08-31 11:55:55 -0700137 auto method = bus.new_method_call(service.c_str(), PCAP_PATH,
138 "org.freedesktop.DBus.Properties", "Set");
Tom Joseph6c8d51b2017-07-26 18:18:06 +0530139
140 method.append(PCAP_INTERFACE, POWER_CAP_ENABLE_PROP);
141 method.append(sdbusplus::message::variant<bool>(enabled));
142
143 auto reply = bus.call(method);
144
145 if (reply.is_method_error())
146 {
147 log<level::ERR>("Error in setPcapEnabled property");
148 elog<InternalFailure>();
149 }
150}
151
Tom Josephbe5eaa12017-07-12 19:54:44 +0530152void readAssetTagObjectTree(dcmi::assettag::ObjectTree& objectTree)
153{
154 static constexpr auto mapperBusName = "xyz.openbmc_project.ObjectMapper";
155 static constexpr auto mapperObjPath = "/xyz/openbmc_project/object_mapper";
156 static constexpr auto mapperIface = "xyz.openbmc_project.ObjectMapper";
157 static constexpr auto inventoryRoot = "/xyz/openbmc_project/inventory/";
158
159 sdbusplus::bus::bus bus{ipmid_get_sd_bus_connection()};
160 auto depth = 0;
161
Patrick Venture0b02be92018-08-31 11:55:55 -0700162 auto mapperCall = bus.new_method_call(mapperBusName, mapperObjPath,
163 mapperIface, "GetSubTree");
Tom Josephbe5eaa12017-07-12 19:54:44 +0530164
165 mapperCall.append(inventoryRoot);
166 mapperCall.append(depth);
167 mapperCall.append(std::vector<std::string>({dcmi::assetTagIntf}));
168
169 auto mapperReply = bus.call(mapperCall);
170 if (mapperReply.is_method_error())
171 {
172 log<level::ERR>("Error in mapper call");
173 elog<InternalFailure>();
174 }
175
176 mapperReply.read(objectTree);
177
178 if (objectTree.empty())
179 {
180 log<level::ERR>("AssetTag property is not populated");
181 elog<InternalFailure>();
182 }
183}
184
185std::string readAssetTag()
186{
187 sdbusplus::bus::bus bus{ipmid_get_sd_bus_connection()};
188 dcmi::assettag::ObjectTree objectTree;
189
190 // Read the object tree with the inventory root to figure out the object
191 // that has implemented the Asset tag interface.
192 readAssetTagObjectTree(objectTree);
193
194 auto method = bus.new_method_call(
Patrick Venture0b02be92018-08-31 11:55:55 -0700195 (objectTree.begin()->second.begin()->first).c_str(),
196 (objectTree.begin()->first).c_str(), dcmi::propIntf, "Get");
Tom Josephbe5eaa12017-07-12 19:54:44 +0530197 method.append(dcmi::assetTagIntf);
198 method.append(dcmi::assetTagProp);
199
200 auto reply = bus.call(method);
201 if (reply.is_method_error())
202 {
203 log<level::ERR>("Error in reading asset tag");
204 elog<InternalFailure>();
205 }
206
207 sdbusplus::message::variant<std::string> assetTag;
208 reply.read(assetTag);
209
210 return assetTag.get<std::string>();
211}
212
Tom Josephbe5b9892017-07-15 00:55:23 +0530213void writeAssetTag(const std::string& assetTag)
214{
215 sdbusplus::bus::bus bus{ipmid_get_sd_bus_connection()};
216 dcmi::assettag::ObjectTree objectTree;
217
218 // Read the object tree with the inventory root to figure out the object
219 // that has implemented the Asset tag interface.
220 readAssetTagObjectTree(objectTree);
221
222 auto method = bus.new_method_call(
Patrick Venture0b02be92018-08-31 11:55:55 -0700223 (objectTree.begin()->second.begin()->first).c_str(),
224 (objectTree.begin()->first).c_str(), dcmi::propIntf, "Set");
Tom Josephbe5b9892017-07-15 00:55:23 +0530225 method.append(dcmi::assetTagIntf);
226 method.append(dcmi::assetTagProp);
227 method.append(sdbusplus::message::variant<std::string>(assetTag));
228
229 auto reply = bus.call(method);
230 if (reply.is_method_error())
231 {
232 log<level::ERR>("Error in writing asset tag");
233 elog<InternalFailure>();
234 }
235}
236
Vladislav Vovchenko8f7a6f62017-08-17 00:31:14 +0300237std::string getHostName(void)
238{
Patrick Venture0b02be92018-08-31 11:55:55 -0700239 sdbusplus::bus::bus bus{ipmid_get_sd_bus_connection()};
Vladislav Vovchenko8f7a6f62017-08-17 00:31:14 +0300240
241 auto service = ipmi::getService(bus, networkConfigIntf, networkConfigObj);
Patrick Venture0b02be92018-08-31 11:55:55 -0700242 auto value = ipmi::getDbusProperty(bus, service, networkConfigObj,
243 networkConfigIntf, hostNameProp);
Vladislav Vovchenko8f7a6f62017-08-17 00:31:14 +0300244
245 return value.get<std::string>();
246}
247
Nagaraju Goruganti22be97b2018-02-07 01:19:59 -0600248bool getDHCPEnabled()
249{
250 sdbusplus::bus::bus bus{ipmid_get_sd_bus_connection()};
251
Patrick Venture0b02be92018-08-31 11:55:55 -0700252 auto ethdevice =
253 ipmi::network::ChanneltoEthernet(ethernetDefaultChannelNum);
254 auto ethernetObj =
255 ipmi::getDbusObject(bus, ethernetIntf, networkRoot, ethdevice);
Nagaraju Goruganti22be97b2018-02-07 01:19:59 -0600256 auto service = ipmi::getService(bus, ethernetIntf, ethernetObj.first);
Patrick Venture0b02be92018-08-31 11:55:55 -0700257 auto value = ipmi::getDbusProperty(bus, service, ethernetObj.first,
258 ethernetIntf, "DHCPEnabled");
Nagaraju Goruganti22be97b2018-02-07 01:19:59 -0600259
260 return value.get<bool>();
261}
262
263bool getDHCPOption(std::string prop)
264{
265 sdbusplus::bus::bus bus{ipmid_get_sd_bus_connection()};
266
267 auto service = ipmi::getService(bus, dhcpIntf, dhcpObj);
268 auto value = ipmi::getDbusProperty(bus, service, dhcpObj, dhcpIntf, prop);
269
270 return value.get<bool>();
271}
272
Nagaraju Goruganti22be97b2018-02-07 01:19:59 -0600273void setDHCPOption(std::string prop, bool value)
274{
275 sdbusplus::bus::bus bus{ipmid_get_sd_bus_connection()};
276
277 auto service = ipmi::getService(bus, dhcpIntf, dhcpObj);
278 ipmi::setDbusProperty(bus, service, dhcpObj, dhcpIntf, prop, value);
279}
280
Deepak Kodihalli0b459552018-02-06 06:25:12 -0600281Json parseSensorConfig()
282{
283 std::ifstream jsonFile(configFile);
284 if (!jsonFile.is_open())
285 {
286 log<level::ERR>("Temperature readings JSON file not found");
287 elog<InternalFailure>();
288 }
289
290 auto data = Json::parse(jsonFile, nullptr, false);
291 if (data.is_discarded())
292 {
293 log<level::ERR>("Temperature readings JSON parser failure");
294 elog<InternalFailure>();
295 }
296
297 return data;
298}
299
Tom Josephbe5eaa12017-07-12 19:54:44 +0530300} // namespace dcmi
Chris Austen1810bec2015-10-13 12:12:39 -0500301
Tom Josephb9d86f42017-07-26 18:03:47 +0530302ipmi_ret_t getPowerLimit(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
303 ipmi_request_t request, ipmi_response_t response,
304 ipmi_data_len_t data_len, ipmi_context_t context)
305{
Patrick Venture0b02be92018-08-31 11:55:55 -0700306 auto requestData =
307 reinterpret_cast<const dcmi::GetPowerLimitRequest*>(request);
Tom Josephb9d86f42017-07-26 18:03:47 +0530308 std::vector<uint8_t> outPayload(sizeof(dcmi::GetPowerLimitResponse));
Patrick Venture0b02be92018-08-31 11:55:55 -0700309 auto responseData =
310 reinterpret_cast<dcmi::GetPowerLimitResponse*>(outPayload.data());
Tom Josephb9d86f42017-07-26 18:03:47 +0530311
312 if (requestData->groupID != dcmi::groupExtId)
313 {
314 *data_len = 0;
315 return IPMI_CC_INVALID_FIELD_REQUEST;
316 }
317
Patrick Venture0b02be92018-08-31 11:55:55 -0700318 sdbusplus::bus::bus sdbus{ipmid_get_sd_bus_connection()};
Tom Josephb9d86f42017-07-26 18:03:47 +0530319 uint32_t pcapValue = 0;
320 bool pcapEnable = false;
321
322 try
323 {
324 pcapValue = dcmi::getPcap(sdbus);
325 pcapEnable = dcmi::getPcapEnabled(sdbus);
326 }
327 catch (InternalFailure& e)
328 {
329 *data_len = 0;
330 return IPMI_CC_UNSPECIFIED_ERROR;
331 }
332
333 responseData->groupID = dcmi::groupExtId;
334
335 /*
336 * Exception action if power limit is exceeded and cannot be controlled
337 * with the correction time limit is hardcoded to Hard Power Off system
338 * and log event to SEL.
339 */
340 constexpr auto exception = 0x01;
341 responseData->exceptionAction = exception;
342
343 responseData->powerLimit = static_cast<uint16_t>(pcapValue);
344
345 /*
346 * Correction time limit and Statistics sampling period is currently not
347 * populated.
348 */
349
350 *data_len = outPayload.size();
351 memcpy(response, outPayload.data(), *data_len);
352
353 if (pcapEnable)
354 {
355 return IPMI_CC_OK;
356 }
357 else
358 {
359 return IPMI_DCMI_CC_NO_ACTIVE_POWER_LIMIT;
360 }
361}
362
Tom Joseph46fa37d2017-07-26 18:11:55 +0530363ipmi_ret_t setPowerLimit(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
364 ipmi_request_t request, ipmi_response_t response,
365 ipmi_data_len_t data_len, ipmi_context_t context)
366{
Patrick Venture0b02be92018-08-31 11:55:55 -0700367 auto requestData =
368 reinterpret_cast<const dcmi::SetPowerLimitRequest*>(request);
Tom Joseph46fa37d2017-07-26 18:11:55 +0530369 std::vector<uint8_t> outPayload(sizeof(dcmi::SetPowerLimitResponse));
Patrick Venture0b02be92018-08-31 11:55:55 -0700370 auto responseData =
371 reinterpret_cast<dcmi::SetPowerLimitResponse*>(outPayload.data());
Tom Joseph46fa37d2017-07-26 18:11:55 +0530372
373 if (requestData->groupID != dcmi::groupExtId)
374 {
375 *data_len = 0;
376 return IPMI_CC_INVALID_FIELD_REQUEST;
377 }
378
Patrick Venture0b02be92018-08-31 11:55:55 -0700379 sdbusplus::bus::bus sdbus{ipmid_get_sd_bus_connection()};
Tom Joseph46fa37d2017-07-26 18:11:55 +0530380
381 // Only process the power limit requested in watts.
382 try
383 {
384 dcmi::setPcap(sdbus, requestData->powerLimit);
385 }
386 catch (InternalFailure& e)
387 {
388 *data_len = 0;
389 return IPMI_CC_UNSPECIFIED_ERROR;
390 }
391
392 log<level::INFO>("Set Power Cap",
393 entry("POWERCAP=%u", requestData->powerLimit));
394
395 responseData->groupID = dcmi::groupExtId;
396 memcpy(response, outPayload.data(), outPayload.size());
397 *data_len = outPayload.size();
398
399 return IPMI_CC_OK;
400}
401
Tom Joseph6c8d51b2017-07-26 18:18:06 +0530402ipmi_ret_t applyPowerLimit(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
403 ipmi_request_t request, ipmi_response_t response,
404 ipmi_data_len_t data_len, ipmi_context_t context)
405{
Patrick Venture0b02be92018-08-31 11:55:55 -0700406 auto requestData =
407 reinterpret_cast<const dcmi::ApplyPowerLimitRequest*>(request);
Tom Joseph6c8d51b2017-07-26 18:18:06 +0530408 std::vector<uint8_t> outPayload(sizeof(dcmi::ApplyPowerLimitResponse));
Patrick Venture0b02be92018-08-31 11:55:55 -0700409 auto responseData =
410 reinterpret_cast<dcmi::ApplyPowerLimitResponse*>(outPayload.data());
Tom Joseph6c8d51b2017-07-26 18:18:06 +0530411
412 if (requestData->groupID != dcmi::groupExtId)
413 {
414 *data_len = 0;
415 return IPMI_CC_INVALID_FIELD_REQUEST;
416 }
417
Patrick Venture0b02be92018-08-31 11:55:55 -0700418 sdbusplus::bus::bus sdbus{ipmid_get_sd_bus_connection()};
Tom Joseph6c8d51b2017-07-26 18:18:06 +0530419
420 try
421 {
422 dcmi::setPcapEnable(sdbus,
423 static_cast<bool>(requestData->powerLimitAction));
424 }
425 catch (InternalFailure& e)
426 {
427 *data_len = 0;
428 return IPMI_CC_UNSPECIFIED_ERROR;
429 }
430
431 log<level::INFO>("Set Power Cap Enable",
432 entry("POWERCAPENABLE=%u", requestData->powerLimitAction));
433
434 responseData->groupID = dcmi::groupExtId;
435 memcpy(response, outPayload.data(), outPayload.size());
436 *data_len = outPayload.size();
437
438 return IPMI_CC_OK;
439}
440
Tom Joseph6f6dd4d2017-07-12 20:07:11 +0530441ipmi_ret_t getAssetTag(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
442 ipmi_request_t request, ipmi_response_t response,
443 ipmi_data_len_t data_len, ipmi_context_t context)
444{
Patrick Venture0b02be92018-08-31 11:55:55 -0700445 auto requestData =
446 reinterpret_cast<const dcmi::GetAssetTagRequest*>(request);
Tom Joseph6f6dd4d2017-07-12 20:07:11 +0530447 std::vector<uint8_t> outPayload(sizeof(dcmi::GetAssetTagResponse));
Patrick Venture0b02be92018-08-31 11:55:55 -0700448 auto responseData =
449 reinterpret_cast<dcmi::GetAssetTagResponse*>(outPayload.data());
Tom Joseph6f6dd4d2017-07-12 20:07:11 +0530450
451 if (requestData->groupID != dcmi::groupExtId)
452 {
453 *data_len = 0;
454 return IPMI_CC_INVALID_FIELD_REQUEST;
455 }
456
457 // Verify offset to read and number of bytes to read are not exceeding the
458 // range.
459 if ((requestData->offset > dcmi::assetTagMaxOffset) ||
460 (requestData->bytes > dcmi::maxBytes) ||
461 ((requestData->offset + requestData->bytes) > dcmi::assetTagMaxSize))
462 {
463 *data_len = 0;
464 return IPMI_CC_PARM_OUT_OF_RANGE;
465 }
466
467 std::string assetTag;
468
469 try
470 {
471 assetTag = dcmi::readAssetTag();
472 }
473 catch (InternalFailure& e)
474 {
475 *data_len = 0;
476 return IPMI_CC_UNSPECIFIED_ERROR;
477 }
478
479 responseData->groupID = dcmi::groupExtId;
480
481 // Return if the asset tag is not populated.
482 if (!assetTag.size())
483 {
484 responseData->tagLength = 0;
485 memcpy(response, outPayload.data(), outPayload.size());
486 *data_len = outPayload.size();
487 return IPMI_CC_OK;
488 }
489
490 // If the asset tag is longer than 63 bytes, restrict it to 63 bytes to suit
491 // Get Asset Tag command.
492 if (assetTag.size() > dcmi::assetTagMaxSize)
493 {
494 assetTag.resize(dcmi::assetTagMaxSize);
495 }
496
497 // If the requested offset is beyond the asset tag size.
498 if (requestData->offset >= assetTag.size())
499 {
500 *data_len = 0;
501 return IPMI_CC_PARM_OUT_OF_RANGE;
502 }
503
504 auto returnData = assetTag.substr(requestData->offset, requestData->bytes);
505
506 responseData->tagLength = assetTag.size();
507
508 memcpy(response, outPayload.data(), outPayload.size());
509 memcpy(static_cast<uint8_t*>(response) + outPayload.size(),
510 returnData.data(), returnData.size());
511 *data_len = outPayload.size() + returnData.size();
512
513 return IPMI_CC_OK;
514}
515
Tom Joseph545dd232017-07-12 20:20:49 +0530516ipmi_ret_t setAssetTag(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
517 ipmi_request_t request, ipmi_response_t response,
518 ipmi_data_len_t data_len, ipmi_context_t context)
519{
Patrick Venture0b02be92018-08-31 11:55:55 -0700520 auto requestData =
521 reinterpret_cast<const dcmi::SetAssetTagRequest*>(request);
Tom Joseph545dd232017-07-12 20:20:49 +0530522 std::vector<uint8_t> outPayload(sizeof(dcmi::SetAssetTagResponse));
Patrick Venture0b02be92018-08-31 11:55:55 -0700523 auto responseData =
524 reinterpret_cast<dcmi::SetAssetTagResponse*>(outPayload.data());
Tom Joseph545dd232017-07-12 20:20:49 +0530525
526 if (requestData->groupID != dcmi::groupExtId)
527 {
528 *data_len = 0;
529 return IPMI_CC_INVALID_FIELD_REQUEST;
530 }
531
532 // Verify offset to read and number of bytes to read are not exceeding the
533 // range.
534 if ((requestData->offset > dcmi::assetTagMaxOffset) ||
535 (requestData->bytes > dcmi::maxBytes) ||
536 ((requestData->offset + requestData->bytes) > dcmi::assetTagMaxSize))
537 {
538 *data_len = 0;
539 return IPMI_CC_PARM_OUT_OF_RANGE;
540 }
541
542 std::string assetTag;
543
544 try
545 {
546 assetTag = dcmi::readAssetTag();
547
548 if (requestData->offset > assetTag.size())
549 {
550 *data_len = 0;
551 return IPMI_CC_PARM_OUT_OF_RANGE;
552 }
553
554 assetTag.replace(requestData->offset,
555 assetTag.size() - requestData->offset,
556 static_cast<const char*>(request) +
Patrick Venture0b02be92018-08-31 11:55:55 -0700557 sizeof(dcmi::SetAssetTagRequest),
Tom Joseph545dd232017-07-12 20:20:49 +0530558 requestData->bytes);
559
560 dcmi::writeAssetTag(assetTag);
561
562 responseData->groupID = dcmi::groupExtId;
563 responseData->tagLength = assetTag.size();
564 memcpy(response, outPayload.data(), outPayload.size());
565 *data_len = outPayload.size();
566
567 return IPMI_CC_OK;
568 }
569 catch (InternalFailure& e)
570 {
571 *data_len = 0;
572 return IPMI_CC_UNSPECIFIED_ERROR;
573 }
574}
575
Vladislav Vovchenko8f7a6f62017-08-17 00:31:14 +0300576ipmi_ret_t getMgmntCtrlIdStr(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
Patrick Venture0b02be92018-08-31 11:55:55 -0700577 ipmi_request_t request, ipmi_response_t response,
578 ipmi_data_len_t data_len, ipmi_context_t context)
Vladislav Vovchenko8f7a6f62017-08-17 00:31:14 +0300579{
Patrick Venture0b02be92018-08-31 11:55:55 -0700580 auto requestData =
581 reinterpret_cast<const dcmi::GetMgmntCtrlIdStrRequest*>(request);
582 auto responseData =
583 reinterpret_cast<dcmi::GetMgmntCtrlIdStrResponse*>(response);
Vladislav Vovchenko8f7a6f62017-08-17 00:31:14 +0300584 std::string hostName;
585
586 *data_len = 0;
587
588 if (requestData->groupID != dcmi::groupExtId ||
589 requestData->bytes > dcmi::maxBytes ||
590 requestData->offset + requestData->bytes > dcmi::maxCtrlIdStrLen)
591 {
592 return IPMI_CC_INVALID_FIELD_REQUEST;
593 }
594
595 try
596 {
597 hostName = dcmi::getHostName();
598 }
599 catch (InternalFailure& e)
600 {
601 return IPMI_CC_UNSPECIFIED_ERROR;
602 }
603
604 if (requestData->offset > hostName.length())
605 {
606 return IPMI_CC_PARM_OUT_OF_RANGE;
607 }
608 auto responseStr = hostName.substr(requestData->offset, requestData->bytes);
609 auto responseStrLen = std::min(static_cast<std::size_t>(requestData->bytes),
Patrick Venture0b02be92018-08-31 11:55:55 -0700610 responseStr.length() + 1);
Vladislav Vovchenko8f7a6f62017-08-17 00:31:14 +0300611 responseData->groupID = dcmi::groupExtId;
612 responseData->strLen = hostName.length();
613 std::copy(begin(responseStr), end(responseStr), responseData->data);
614
615 *data_len = sizeof(*responseData) + responseStrLen;
616 return IPMI_CC_OK;
617}
618
619ipmi_ret_t setMgmntCtrlIdStr(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
Patrick Venture0b02be92018-08-31 11:55:55 -0700620 ipmi_request_t request, ipmi_response_t response,
621 ipmi_data_len_t data_len, ipmi_context_t context)
Vladislav Vovchenko8f7a6f62017-08-17 00:31:14 +0300622{
623 static std::array<char, dcmi::maxCtrlIdStrLen + 1> newCtrlIdStr;
624
Patrick Venture0b02be92018-08-31 11:55:55 -0700625 auto requestData =
626 reinterpret_cast<const dcmi::SetMgmntCtrlIdStrRequest*>(request);
627 auto responseData =
628 reinterpret_cast<dcmi::SetMgmntCtrlIdStrResponse*>(response);
Vladislav Vovchenko8f7a6f62017-08-17 00:31:14 +0300629
630 *data_len = 0;
631
632 if (requestData->groupID != dcmi::groupExtId ||
633 requestData->bytes > dcmi::maxBytes ||
634 requestData->offset + requestData->bytes > dcmi::maxCtrlIdStrLen + 1 ||
Patrick Venture0b02be92018-08-31 11:55:55 -0700635 (requestData->offset + requestData->bytes ==
636 dcmi::maxCtrlIdStrLen + 1 &&
637 requestData->data[requestData->bytes - 1] != '\0'))
Vladislav Vovchenko8f7a6f62017-08-17 00:31:14 +0300638 {
639 return IPMI_CC_INVALID_FIELD_REQUEST;
640 }
641
642 try
643 {
644 /* if there is no old value and offset is not 0 */
645 if (newCtrlIdStr[0] == '\0' && requestData->offset != 0)
646 {
647 /* read old ctrlIdStr */
648 auto hostName = dcmi::getHostName();
649 hostName.resize(dcmi::maxCtrlIdStrLen);
650 std::copy(begin(hostName), end(hostName), begin(newCtrlIdStr));
651 newCtrlIdStr[hostName.length()] = '\0';
652 }
653
654 /* replace part of string and mark byte after the last as \0 */
Patrick Venture0b02be92018-08-31 11:55:55 -0700655 auto restStrIter =
656 std::copy_n(requestData->data, requestData->bytes,
657 begin(newCtrlIdStr) + requestData->offset);
Vladislav Vovchenko8f7a6f62017-08-17 00:31:14 +0300658 /* if the last written byte is not 64th - add '\0' */
659 if (requestData->offset + requestData->bytes <= dcmi::maxCtrlIdStrLen)
660 {
661 *restStrIter = '\0';
662 }
663
664 /* if input data contains '\0' whole string is sent - update hostname */
665 auto it = std::find(requestData->data,
Patrick Venture0b02be92018-08-31 11:55:55 -0700666 requestData->data + requestData->bytes, '\0');
Vladislav Vovchenko8f7a6f62017-08-17 00:31:14 +0300667 if (it != requestData->data + requestData->bytes)
668 {
Patrick Venture0b02be92018-08-31 11:55:55 -0700669 sdbusplus::bus::bus bus{ipmid_get_sd_bus_connection()};
Vladislav Vovchenko8f7a6f62017-08-17 00:31:14 +0300670 ipmi::setDbusProperty(bus, dcmi::networkServiceName,
Patrick Venture0b02be92018-08-31 11:55:55 -0700671 dcmi::networkConfigObj,
672 dcmi::networkConfigIntf, dcmi::hostNameProp,
673 std::string(newCtrlIdStr.data()));
Vladislav Vovchenko8f7a6f62017-08-17 00:31:14 +0300674 }
675 }
676 catch (InternalFailure& e)
677 {
678 *data_len = 0;
679 return IPMI_CC_UNSPECIFIED_ERROR;
680 }
681
682 responseData->groupID = dcmi::groupExtId;
683 responseData->offset = requestData->offset + requestData->bytes;
684 *data_len = sizeof(*responseData);
685 return IPMI_CC_OK;
686}
687
Patrick Venture0b02be92018-08-31 11:55:55 -0700688// List of the capabilities under each parameter
689dcmi::DCMICaps dcmiCaps = {
690 // Supported DCMI Capabilities
691 {dcmi::DCMICapParameters::SUPPORTED_DCMI_CAPS,
692 {3,
693 {{"PowerManagement", 2, 0, 1},
694 {"OOBSecondaryLan", 3, 2, 1},
695 {"SerialTMODE", 3, 1, 1},
696 {"InBandSystemInterfaceChannel", 3, 0, 1}}}},
697 // Mandatory Platform Attributes
698 {dcmi::DCMICapParameters::MANDATORY_PLAT_ATTRIBUTES,
699 {5,
700 {{"SELAutoRollOver", 1, 15, 1},
701 {"FlushEntireSELUponRollOver", 1, 14, 1},
702 {"RecordLevelSELFlushUponRollOver", 1, 13, 1},
703 {"NumberOfSELEntries", 1, 0, 12},
704 {"TempMonitoringSamplingFreq", 5, 0, 8}}}},
705 // Optional Platform Attributes
706 {dcmi::DCMICapParameters::OPTIONAL_PLAT_ATTRIBUTES,
707 {2,
708 {{"PowerMgmtDeviceSlaveAddress", 1, 1, 7},
709 {"BMCChannelNumber", 2, 4, 4},
710 {"DeviceRivision", 2, 0, 4}}}},
711 // Manageability Access Attributes
712 {dcmi::DCMICapParameters::MANAGEABILITY_ACCESS_ATTRIBUTES,
713 {3,
714 {{"MandatoryPrimaryLanOOBSupport", 1, 0, 8},
715 {"OptionalSecondaryLanOOBSupport", 2, 0, 8},
716 {"OptionalSerialOOBMTMODECapability", 3, 0, 8}}}}};
Dhruvaraj Subhashchandrane29be412018-01-16 05:11:56 -0600717
718ipmi_ret_t getDCMICapabilities(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
719 ipmi_request_t request, ipmi_response_t response,
720 ipmi_data_len_t data_len, ipmi_context_t context)
721{
722
723 std::ifstream dcmiCapFile(DCMI_CAP_JSON_FILE);
724 if (!dcmiCapFile.is_open())
725 {
726 log<level::ERR>("DCMI Capabilities file not found");
727 return IPMI_CC_UNSPECIFIED_ERROR;
728 }
729
730 auto data = nlohmann::json::parse(dcmiCapFile, nullptr, false);
731 if (data.is_discarded())
732 {
733 log<level::ERR>("DCMI Capabilities JSON parser failure");
734 return IPMI_CC_UNSPECIFIED_ERROR;
735 }
736
Patrick Venture0b02be92018-08-31 11:55:55 -0700737 auto requestData =
738 reinterpret_cast<const dcmi::GetDCMICapRequest*>(request);
Dhruvaraj Subhashchandrane29be412018-01-16 05:11:56 -0600739
Patrick Venture0b02be92018-08-31 11:55:55 -0700740 // get list of capabilities in a parameter
Dhruvaraj Subhashchandrane29be412018-01-16 05:11:56 -0600741 auto caps =
742 dcmiCaps.find(static_cast<dcmi::DCMICapParameters>(requestData->param));
743 if (caps == dcmiCaps.end())
744 {
745 log<level::ERR>("Invalid input parameter");
746 return IPMI_CC_INVALID_FIELD_REQUEST;
747 }
748
749 if (requestData->groupID != dcmi::groupExtId)
750 {
751 *data_len = 0;
752 return IPMI_CC_INVALID_FIELD_REQUEST;
753 }
754
Patrick Venture0b02be92018-08-31 11:55:55 -0700755 auto responseData = reinterpret_cast<dcmi::GetDCMICapResponse*>(response);
Dhruvaraj Subhashchandrane29be412018-01-16 05:11:56 -0600756
Patrick Venture0b02be92018-08-31 11:55:55 -0700757 // For each capabilities in a parameter fill the data from
758 // the json file based on the capability name.
Dhruvaraj Subhashchandrane29be412018-01-16 05:11:56 -0600759 for (auto cap : caps->second.capList)
760 {
Patrick Venture0b02be92018-08-31 11:55:55 -0700761 // If the data is beyond first byte boundary, insert in a
762 // 16bit pattern for example number of SEL entries are represented
763 // in 12bits.
Dhruvaraj Subhashchandrane29be412018-01-16 05:11:56 -0600764 if ((cap.length + cap.position) > 8)
765 {
Patrick Venture0b02be92018-08-31 11:55:55 -0700766 // Read the value corresponding to capability name and assign to
767 // 16bit bitset.
Dhruvaraj Subhashchandrane29be412018-01-16 05:11:56 -0600768 std::bitset<16> val(data.value(cap.name.c_str(), 0));
769 val <<= cap.position;
Patrick Venture0b02be92018-08-31 11:55:55 -0700770 reinterpret_cast<uint16_t*>(
771 responseData
772 ->data)[(cap.bytePosition - 1) / sizeof(uint16_t)] |=
773 val.to_ulong();
Dhruvaraj Subhashchandrane29be412018-01-16 05:11:56 -0600774 }
775 else
776 {
777 responseData->data[cap.bytePosition - 1] |=
778 data.value(cap.name.c_str(), 0) << cap.position;
779 }
780 }
781
782 responseData->groupID = dcmi::groupExtId;
783 responseData->major = DCMI_SPEC_MAJOR_VERSION;
784 responseData->minor = DCMI_SPEC_MINOR_VERSION;
785 responseData->paramRevision = DCMI_PARAMETER_REVISION;
786 *data_len = sizeof(*responseData) + caps->second.size;
787
788 return IPMI_CC_OK;
789}
790
Deepak Kodihalliee717d72018-01-24 04:53:09 -0600791namespace dcmi
792{
793namespace temp_readings
794{
795
Deepak Kodihallib1e8fba2018-01-24 04:57:10 -0600796Temperature readTemp(const std::string& dbusService,
797 const std::string& dbusPath)
798{
799 // Read the temperature value from d-bus object. Need some conversion.
800 // As per the interface xyz.openbmc_project.Sensor.Value, the temperature
801 // is an int64_t and in degrees C. It needs to be scaled by using the
802 // formula Value * 10^Scale. The ipmi spec has the temperature as a uint8_t,
803 // with a separate single bit for the sign.
804
805 sdbusplus::bus::bus bus{ipmid_get_sd_bus_connection()};
Patrick Venture0b02be92018-08-31 11:55:55 -0700806 auto result = ipmi::getAllDbusProperties(
807 bus, dbusService, dbusPath, "xyz.openbmc_project.Sensor.Value");
Deepak Kodihallib1e8fba2018-01-24 04:57:10 -0600808 auto temperature = result.at("Value").get<int64_t>();
809 uint64_t absTemp = std::abs(temperature);
810
811 auto factor = result.at("Scale").get<int64_t>();
812 uint64_t scale = std::pow(10, factor); // pow() returns float/double
813 unsigned long long tempDegrees = 0;
814 // Overflow safe multiplication when the scale is > 0
Patrick Venture0b02be92018-08-31 11:55:55 -0700815 if (scale && __builtin_umulll_overflow(absTemp, scale, &tempDegrees))
Deepak Kodihallib1e8fba2018-01-24 04:57:10 -0600816 {
817 log<level::ERR>("Multiplication overflow detected",
818 entry("TEMP_VALUE=%llu", absTemp),
819 entry("SCALE_FACTOR=%llu", scale));
820 elog<InternalFailure>();
821 }
822 else
823 {
824 // The (uint64_t)scale value is 0, effectively this is division
825 tempDegrees = absTemp * std::pow(10, factor);
826 }
827 // Max absolute temp as per ipmi spec is 128.
828 if (tempDegrees > maxTemp)
829 {
830 tempDegrees = maxTemp;
831 }
832
833 return std::make_tuple(static_cast<uint8_t>(tempDegrees),
834 (temperature < 0));
835}
836
Deepak Kodihalliee717d72018-01-24 04:53:09 -0600837std::tuple<Response, NumInstances> read(const std::string& type,
838 uint8_t instance)
839{
Deepak Kodihallib1e8fba2018-01-24 04:57:10 -0600840 Response response{};
841 sdbusplus::bus::bus bus{ipmid_get_sd_bus_connection()};
842
843 if (!instance)
844 {
845 log<level::ERR>("Expected non-zero instance");
846 elog<InternalFailure>();
847 }
848
Deepak Kodihalli0b459552018-02-06 06:25:12 -0600849 auto data = parseSensorConfig();
Deepak Kodihallib1e8fba2018-01-24 04:57:10 -0600850 static const std::vector<Json> empty{};
851 std::vector<Json> readings = data.value(type, empty);
852 size_t numInstances = readings.size();
853 for (const auto& j : readings)
854 {
855 uint8_t instanceNum = j.value("instance", 0);
856 // Not the instance we're interested in
857 if (instanceNum != instance)
858 {
859 continue;
860 }
861
862 std::string path = j.value("dbus", "");
863 std::string service;
864 try
865 {
866 service =
Patrick Venture0b02be92018-08-31 11:55:55 -0700867 ipmi::getService(bus, "xyz.openbmc_project.Sensor.Value", path);
Deepak Kodihallib1e8fba2018-01-24 04:57:10 -0600868 }
869 catch (std::exception& e)
870 {
871 log<level::DEBUG>(e.what());
872 return std::make_tuple(response, numInstances);
873 }
874
875 response.instance = instance;
876 uint8_t temp{};
877 bool sign{};
878 std::tie(temp, sign) = readTemp(service, path);
879 response.temperature = temp;
880 response.sign = sign;
881
882 // Found the instance we're interested in
883 break;
884 }
885
886 if (numInstances > maxInstances)
887 {
888 numInstances = maxInstances;
889 }
890 return std::make_tuple(response, numInstances);
Deepak Kodihalliee717d72018-01-24 04:53:09 -0600891}
892
893std::tuple<ResponseList, NumInstances> readAll(const std::string& type,
894 uint8_t instanceStart)
895{
Deepak Kodihallib1e8fba2018-01-24 04:57:10 -0600896 ResponseList response{};
897 sdbusplus::bus::bus bus{ipmid_get_sd_bus_connection()};
898
899 size_t numInstances = 0;
Deepak Kodihalli0b459552018-02-06 06:25:12 -0600900 auto data = parseSensorConfig();
Deepak Kodihallib1e8fba2018-01-24 04:57:10 -0600901 static const std::vector<Json> empty{};
902 std::vector<Json> readings = data.value(type, empty);
903 numInstances = readings.size();
904 for (const auto& j : readings)
905 {
906 try
907 {
908 // Max of 8 response data sets
909 if (response.size() == maxDataSets)
910 {
911 break;
912 }
913
914 uint8_t instanceNum = j.value("instance", 0);
915 // Not in the instance range we're interested in
916 if (instanceNum < instanceStart)
917 {
918 continue;
919 }
920
921 std::string path = j.value("dbus", "");
922 auto service =
Patrick Venture0b02be92018-08-31 11:55:55 -0700923 ipmi::getService(bus, "xyz.openbmc_project.Sensor.Value", path);
Deepak Kodihallib1e8fba2018-01-24 04:57:10 -0600924
925 Response r{};
926 r.instance = instanceNum;
927 uint8_t temp{};
928 bool sign{};
929 std::tie(temp, sign) = readTemp(service, path);
930 r.temperature = temp;
931 r.sign = sign;
932 response.push_back(r);
933 }
934 catch (std::exception& e)
935 {
936 log<level::DEBUG>(e.what());
937 continue;
938 }
939 }
940
941 if (numInstances > maxInstances)
942 {
943 numInstances = maxInstances;
944 }
945 return std::make_tuple(response, numInstances);
Deepak Kodihalliee717d72018-01-24 04:53:09 -0600946}
947
Patrick Venture0b02be92018-08-31 11:55:55 -0700948} // namespace temp_readings
949} // namespace dcmi
Deepak Kodihalliee717d72018-01-24 04:53:09 -0600950
951ipmi_ret_t getTempReadings(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
Patrick Venture0b02be92018-08-31 11:55:55 -0700952 ipmi_request_t request, ipmi_response_t response,
953 ipmi_data_len_t data_len, ipmi_context_t context)
Deepak Kodihalliee717d72018-01-24 04:53:09 -0600954{
Deepak Kodihalliee717d72018-01-24 04:53:09 -0600955 auto requestData =
956 reinterpret_cast<const dcmi::GetTempReadingsRequest*>(request);
957 auto responseData =
958 reinterpret_cast<dcmi::GetTempReadingsResponseHdr*>(response);
959
960 if (*data_len != sizeof(dcmi::GetTempReadingsRequest))
961 {
962 log<level::ERR>("Malformed request data",
963 entry("DATA_SIZE=%d", *data_len));
964 return IPMI_CC_REQ_DATA_LEN_INVALID;
965 }
966 *data_len = 0;
967
Deepak Kodihalli0b459552018-02-06 06:25:12 -0600968 auto it = dcmi::entityIdToName.find(requestData->entityId);
969 if (it == dcmi::entityIdToName.end())
Deepak Kodihalliee717d72018-01-24 04:53:09 -0600970 {
971 log<level::ERR>("Unknown Entity ID",
972 entry("ENTITY_ID=%d", requestData->entityId));
973 return IPMI_CC_INVALID_FIELD_REQUEST;
974 }
975
976 if (requestData->groupID != dcmi::groupExtId)
977 {
978 log<level::ERR>("Invalid Group ID",
979 entry("GROUP_ID=%d", requestData->groupID));
980 return IPMI_CC_INVALID_FIELD_REQUEST;
981 }
982
983 if (requestData->sensorType != dcmi::temperatureSensorType)
984 {
985 log<level::ERR>("Invalid sensor type",
986 entry("SENSOR_TYPE=%d", requestData->sensorType));
987 return IPMI_CC_INVALID_FIELD_REQUEST;
988 }
989
990 dcmi::temp_readings::ResponseList temps{};
991 try
992 {
993 if (!requestData->entityInstance)
994 {
995 // Read all instances
996 std::tie(temps, responseData->numInstances) =
997 dcmi::temp_readings::readAll(it->second,
998 requestData->instanceStart);
999 }
1000 else
1001 {
1002 // Read one instance
1003 temps.resize(1);
1004 std::tie(temps[0], responseData->numInstances) =
1005 dcmi::temp_readings::read(it->second,
1006 requestData->entityInstance);
1007 }
1008 responseData->numDataSets = temps.size();
1009 }
1010 catch (InternalFailure& e)
1011 {
1012 return IPMI_CC_UNSPECIFIED_ERROR;
1013 }
1014
1015 responseData->groupID = dcmi::groupExtId;
Patrick Venture0b02be92018-08-31 11:55:55 -07001016 size_t payloadSize = temps.size() * sizeof(dcmi::temp_readings::Response);
Deepak Kodihalliee717d72018-01-24 04:53:09 -06001017 if (!temps.empty())
1018 {
1019 memcpy(responseData + 1, // copy payload right after the response header
Patrick Venture0b02be92018-08-31 11:55:55 -07001020 temps.data(), payloadSize);
Deepak Kodihalliee717d72018-01-24 04:53:09 -06001021 }
1022 *data_len = sizeof(dcmi::GetTempReadingsResponseHdr) + payloadSize;
1023
1024 return IPMI_CC_OK;
1025}
1026
Marri Devender Rao66c5fda2018-01-18 10:48:37 -06001027int64_t getPowerReading(sdbusplus::bus::bus& bus)
1028{
1029 std::ifstream sensorFile(POWER_READING_SENSOR);
1030 std::string objectPath;
1031 if (!sensorFile.is_open())
1032 {
1033 log<level::ERR>("Power reading configuration file not found",
Patrick Venture0b02be92018-08-31 11:55:55 -07001034 entry("POWER_SENSOR_FILE=%s", POWER_READING_SENSOR));
Marri Devender Rao66c5fda2018-01-18 10:48:37 -06001035 elog<InternalFailure>();
1036 }
1037
1038 auto data = nlohmann::json::parse(sensorFile, nullptr, false);
1039 if (data.is_discarded())
1040 {
1041 log<level::ERR>("Error in parsing configuration file",
Patrick Venture0b02be92018-08-31 11:55:55 -07001042 entry("POWER_SENSOR_FILE=%s", POWER_READING_SENSOR));
Marri Devender Rao66c5fda2018-01-18 10:48:37 -06001043 elog<InternalFailure>();
1044 }
1045
1046 objectPath = data.value("path", "");
1047 if (objectPath.empty())
1048 {
1049 log<level::ERR>("Power sensor D-Bus object path is empty",
1050 entry("POWER_SENSOR_FILE=%s", POWER_READING_SENSOR));
1051 elog<InternalFailure>();
1052 }
1053
Marri Devender Raoce6a7952018-02-11 08:45:00 -06001054 // Return default value if failed to read from D-Bus object
1055 int64_t power = 0;
1056 try
1057 {
1058 auto service = ipmi::getService(bus, SENSOR_VALUE_INTF, objectPath);
Marri Devender Rao66c5fda2018-01-18 10:48:37 -06001059
Patrick Venture0b02be92018-08-31 11:55:55 -07001060 // Read the sensor value and scale properties
1061 auto properties = ipmi::getAllDbusProperties(bus, service, objectPath,
1062 SENSOR_VALUE_INTF);
Marri Devender Raoce6a7952018-02-11 08:45:00 -06001063 auto value = properties[SENSOR_VALUE_PROP].get<int64_t>();
1064 auto scale = properties[SENSOR_SCALE_PROP].get<int64_t>();
Marri Devender Rao66c5fda2018-01-18 10:48:37 -06001065
Marri Devender Raoce6a7952018-02-11 08:45:00 -06001066 // Power reading needs to be scaled with the Scale value using the
1067 // formula Value * 10^Scale.
1068 power = value * std::pow(10, scale);
1069 }
1070 catch (std::exception& e)
1071 {
1072 log<level::INFO>("Failure to read power value from D-Bus object",
Patrick Venture0b02be92018-08-31 11:55:55 -07001073 entry("OBJECT_PATH=%s", objectPath.c_str()),
1074 entry("INTERFACE=%s", SENSOR_VALUE_INTF));
Marri Devender Raoce6a7952018-02-11 08:45:00 -06001075 }
Marri Devender Rao66c5fda2018-01-18 10:48:37 -06001076 return power;
1077}
1078
Nagaraju Goruganti22be97b2018-02-07 01:19:59 -06001079ipmi_ret_t setDCMIConfParams(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
1080 ipmi_request_t request, ipmi_response_t response,
1081 ipmi_data_len_t data_len, ipmi_context_t context)
1082{
Patrick Venture0b02be92018-08-31 11:55:55 -07001083 auto requestData =
1084 reinterpret_cast<const dcmi::SetConfParamsRequest*>(request);
1085 auto responseData =
1086 reinterpret_cast<dcmi::SetConfParamsResponse*>(response);
Nagaraju Goruganti22be97b2018-02-07 01:19:59 -06001087
Patrick Venture0b02be92018-08-31 11:55:55 -07001088 if (requestData->groupID != dcmi::groupExtId ||
1089 *data_len < DCMI_SET_CONF_PARAM_REQ_PACKET_MIN_SIZE ||
1090 *data_len > DCMI_SET_CONF_PARAM_REQ_PACKET_MAX_SIZE)
Nagaraju Goruganti22be97b2018-02-07 01:19:59 -06001091 {
Gunnar Mills8466b792018-03-23 12:18:12 -05001092 log<level::ERR>("Invalid Group ID or Invalid Requested Packet size",
Nagaraju Goruganti22be97b2018-02-07 01:19:59 -06001093 entry("GROUP_ID=%d", requestData->groupID),
1094 entry("PACKET SIZE=%d", *data_len));
1095 return IPMI_CC_INVALID_FIELD_REQUEST;
1096 }
1097
1098 *data_len = 0;
1099
1100 try
1101 {
1102 // Take action based on the Parameter Selector
Patrick Venture0b02be92018-08-31 11:55:55 -07001103 switch (
1104 static_cast<dcmi::DCMIConfigParameters>(requestData->paramSelect))
Nagaraju Goruganti22be97b2018-02-07 01:19:59 -06001105 {
1106 case dcmi::DCMIConfigParameters::ActivateDHCP:
1107
1108 if ((requestData->data[0] & DCMI_ACTIVATE_DHCP_MASK) &&
Patrick Venture0b02be92018-08-31 11:55:55 -07001109 dcmi::getDHCPEnabled())
Nagaraju Goruganti22be97b2018-02-07 01:19:59 -06001110 {
Patrick Venture0b02be92018-08-31 11:55:55 -07001111 // When these conditions are met we have to trigger DHCP
1112 // protocol restart using the latest parameter settings, but
1113 // as per n/w manager design, each time when we update n/w
1114 // parameters, n/w service is restarted. So we no need to
1115 // take any action in this case.
Nagaraju Goruganti22be97b2018-02-07 01:19:59 -06001116 }
1117 break;
1118
1119 case dcmi::DCMIConfigParameters::DiscoveryConfig:
1120
1121 if (requestData->data[0] & DCMI_OPTION_12_MASK)
1122 {
1123 dcmi::setDHCPOption(DHCP_OPT12_ENABLED, true);
1124 }
1125 else
1126 {
1127 dcmi::setDHCPOption(DHCP_OPT12_ENABLED, false);
1128 }
1129
1130 // Systemd-networkd doesn't support Random Back off
1131 if (requestData->data[0] & DCMI_RAND_BACK_OFF_MASK)
1132 {
1133 return IPMI_CC_INVALID;
1134 }
1135 break;
1136 // Systemd-networkd doesn't allow to configure DHCP timigs
1137 case dcmi::DCMIConfigParameters::DHCPTiming1:
1138 case dcmi::DCMIConfigParameters::DHCPTiming2:
1139 case dcmi::DCMIConfigParameters::DHCPTiming3:
1140 default:
1141 return IPMI_CC_INVALID;
1142 }
1143 }
1144 catch (std::exception& e)
1145 {
1146 log<level::ERR>(e.what());
1147 return IPMI_CC_UNSPECIFIED_ERROR;
1148 }
1149 responseData->groupID = dcmi::groupExtId;
1150 *data_len = sizeof(dcmi::SetConfParamsResponse);
1151
1152 return IPMI_CC_OK;
1153}
1154
1155ipmi_ret_t getDCMIConfParams(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
1156 ipmi_request_t request, ipmi_response_t response,
1157 ipmi_data_len_t data_len, ipmi_context_t context)
1158{
1159
Patrick Venture0b02be92018-08-31 11:55:55 -07001160 auto requestData =
1161 reinterpret_cast<const dcmi::GetConfParamsRequest*>(request);
1162 auto responseData =
1163 reinterpret_cast<dcmi::GetConfParamsResponse*>(response);
Nagaraju Goruganti22be97b2018-02-07 01:19:59 -06001164
1165 responseData->data[0] = 0x00;
1166
Patrick Venture0b02be92018-08-31 11:55:55 -07001167 if (requestData->groupID != dcmi::groupExtId ||
1168 *data_len != sizeof(dcmi::GetConfParamsRequest))
Nagaraju Goruganti22be97b2018-02-07 01:19:59 -06001169 {
Gunnar Mills8466b792018-03-23 12:18:12 -05001170 log<level::ERR>("Invalid Group ID or Invalid Requested Packet size",
Nagaraju Goruganti22be97b2018-02-07 01:19:59 -06001171 entry("GROUP_ID=%d", requestData->groupID),
1172 entry("PACKET SIZE=%d", *data_len));
1173 return IPMI_CC_INVALID_FIELD_REQUEST;
1174 }
1175
1176 *data_len = 0;
1177
1178 try
1179 {
1180 // Take action based on the Parameter Selector
Patrick Venture0b02be92018-08-31 11:55:55 -07001181 switch (
1182 static_cast<dcmi::DCMIConfigParameters>(requestData->paramSelect))
Nagaraju Goruganti22be97b2018-02-07 01:19:59 -06001183 {
1184 case dcmi::DCMIConfigParameters::ActivateDHCP:
1185 responseData->data[0] = DCMI_ACTIVATE_DHCP_REPLY;
1186 *data_len = sizeof(dcmi::GetConfParamsResponse) + 1;
1187 break;
1188 case dcmi::DCMIConfigParameters::DiscoveryConfig:
1189 if (dcmi::getDHCPOption(DHCP_OPT12_ENABLED))
1190 {
1191 responseData->data[0] |= DCMI_OPTION_12_MASK;
1192 }
1193 *data_len = sizeof(dcmi::GetConfParamsResponse) + 1;
1194 break;
1195 // Get below values from Systemd-networkd source code
1196 case dcmi::DCMIConfigParameters::DHCPTiming1:
1197 responseData->data[0] = DHCP_TIMING1;
1198 *data_len = sizeof(dcmi::GetConfParamsResponse) + 1;
1199 break;
1200 case dcmi::DCMIConfigParameters::DHCPTiming2:
1201 responseData->data[0] = DHCP_TIMING2_LOWER;
1202 responseData->data[1] = DHCP_TIMING2_UPPER;
1203 *data_len = sizeof(dcmi::GetConfParamsResponse) + 2;
1204 break;
1205 case dcmi::DCMIConfigParameters::DHCPTiming3:
1206 responseData->data[0] = DHCP_TIMING3_LOWER;
1207 responseData->data[1] = DHCP_TIMING3_UPPER;
1208 *data_len = sizeof(dcmi::GetConfParamsResponse) + 2;
1209 break;
1210 default:
1211 *data_len = 0;
1212 return IPMI_CC_INVALID;
1213 }
1214 }
1215 catch (std::exception& e)
1216 {
1217 log<level::ERR>(e.what());
1218 return IPMI_CC_UNSPECIFIED_ERROR;
1219 }
1220
1221 responseData->groupID = dcmi::groupExtId;
1222 responseData->major = DCMI_SPEC_MAJOR_VERSION;
1223 responseData->minor = DCMI_SPEC_MINOR_VERSION;
1224 responseData->paramRevision = DCMI_CONFIG_PARAMETER_REVISION;
1225
1226 return IPMI_CC_OK;
1227}
1228
Marri Devender Rao66c5fda2018-01-18 10:48:37 -06001229ipmi_ret_t getPowerReading(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
Patrick Venture0b02be92018-08-31 11:55:55 -07001230 ipmi_request_t request, ipmi_response_t response,
1231 ipmi_data_len_t data_len, ipmi_context_t context)
Marri Devender Rao66c5fda2018-01-18 10:48:37 -06001232{
1233 ipmi_ret_t rc = IPMI_CC_OK;
Patrick Venture0b02be92018-08-31 11:55:55 -07001234 auto requestData =
1235 reinterpret_cast<const dcmi::GetPowerReadingRequest*>(request);
1236 auto responseData =
1237 reinterpret_cast<dcmi::GetPowerReadingResponse*>(response);
Marri Devender Rao9c966e02018-01-22 05:55:10 -06001238
1239 if (requestData->groupID != dcmi::groupExtId)
1240 {
1241 *data_len = 0;
1242 return IPMI_CC_INVALID_FIELD_REQUEST;
1243 }
1244
Marri Devender Rao66c5fda2018-01-18 10:48:37 -06001245 sdbusplus::bus::bus bus{ipmid_get_sd_bus_connection()};
Marri Devender Rao9c966e02018-01-22 05:55:10 -06001246 int64_t power = 0;
Marri Devender Rao66c5fda2018-01-18 10:48:37 -06001247 try
1248 {
Marri Devender Rao9c966e02018-01-22 05:55:10 -06001249 power = getPowerReading(bus);
Marri Devender Rao66c5fda2018-01-18 10:48:37 -06001250 }
1251 catch (InternalFailure& e)
1252 {
1253 log<level::ERR>("Error in reading power sensor value",
1254 entry("INTERFACE=%s", SENSOR_VALUE_INTF),
1255 entry("PROPERTY=%s", SENSOR_VALUE_PROP));
1256 return IPMI_CC_UNSPECIFIED_ERROR;
1257 }
Marri Devender Rao9c966e02018-01-22 05:55:10 -06001258 responseData->groupID = dcmi::groupExtId;
1259
1260 // TODO: openbmc/openbmc#2819
Gunnar Mills8466b792018-03-23 12:18:12 -05001261 // Minimum, Maximum, Average power, TimeFrame, TimeStamp,
Marri Devender Rao9c966e02018-01-22 05:55:10 -06001262 // PowerReadingState readings need to be populated
1263 // after Telemetry changes.
1264 uint16_t totalPower = static_cast<uint16_t>(power);
1265 responseData->currentPower = totalPower;
1266 responseData->minimumPower = totalPower;
1267 responseData->maximumPower = totalPower;
1268 responseData->averagePower = totalPower;
1269
1270 *data_len = sizeof(*responseData);
Marri Devender Rao66c5fda2018-01-18 10:48:37 -06001271 return rc;
1272}
1273
Deepak Kodihalli0b459552018-02-06 06:25:12 -06001274namespace dcmi
1275{
1276namespace sensor_info
1277{
1278
Deepak Kodihallidd4cff12018-02-06 06:48:29 -06001279Response createFromJson(const Json& config)
1280{
1281 Response response{};
1282 uint16_t recordId = config.value("record_id", 0);
1283 response.recordIdLsb = recordId & 0xFF;
1284 response.recordIdMsb = (recordId >> 8) & 0xFF;
1285 return response;
1286}
1287
Deepak Kodihalli0b459552018-02-06 06:25:12 -06001288std::tuple<Response, NumInstances> read(const std::string& type,
Patrick Venture0b02be92018-08-31 11:55:55 -07001289 uint8_t instance, const Json& config)
Deepak Kodihalli0b459552018-02-06 06:25:12 -06001290{
Deepak Kodihallidd4cff12018-02-06 06:48:29 -06001291 Response response{};
1292
1293 if (!instance)
1294 {
1295 log<level::ERR>("Expected non-zero instance");
1296 elog<InternalFailure>();
1297 }
1298
1299 static const std::vector<Json> empty{};
1300 std::vector<Json> readings = config.value(type, empty);
1301 size_t numInstances = readings.size();
1302 for (const auto& reading : readings)
1303 {
1304 uint8_t instanceNum = reading.value("instance", 0);
1305 // Not the instance we're interested in
1306 if (instanceNum != instance)
1307 {
1308 continue;
1309 }
1310
1311 response = createFromJson(reading);
1312
1313 // Found the instance we're interested in
1314 break;
1315 }
1316
1317 if (numInstances > maxInstances)
1318 {
1319 log<level::DEBUG>("Trimming IPMI num instances",
1320 entry("NUM_INSTANCES=%d", numInstances));
1321 numInstances = maxInstances;
1322 }
1323 return std::make_tuple(response, numInstances);
Deepak Kodihalli0b459552018-02-06 06:25:12 -06001324}
1325
Patrick Venture0b02be92018-08-31 11:55:55 -07001326std::tuple<ResponseList, NumInstances>
1327 readAll(const std::string& type, uint8_t instanceStart, const Json& config)
Deepak Kodihalli0b459552018-02-06 06:25:12 -06001328{
Deepak Kodihallidd4cff12018-02-06 06:48:29 -06001329 ResponseList responses{};
1330
1331 size_t numInstances = 0;
1332 static const std::vector<Json> empty{};
1333 std::vector<Json> readings = config.value(type, empty);
1334 numInstances = readings.size();
1335 for (const auto& reading : readings)
1336 {
1337 try
1338 {
1339 // Max of 8 records
1340 if (responses.size() == maxRecords)
1341 {
1342 break;
1343 }
1344
1345 uint8_t instanceNum = reading.value("instance", 0);
1346 // Not in the instance range we're interested in
1347 if (instanceNum < instanceStart)
1348 {
1349 continue;
1350 }
1351
1352 Response response = createFromJson(reading);
1353 responses.push_back(response);
1354 }
1355 catch (std::exception& e)
1356 {
1357 log<level::DEBUG>(e.what());
1358 continue;
1359 }
1360 }
1361
1362 if (numInstances > maxInstances)
1363 {
1364 log<level::DEBUG>("Trimming IPMI num instances",
1365 entry("NUM_INSTANCES=%d", numInstances));
1366 numInstances = maxInstances;
1367 }
1368 return std::make_tuple(responses, numInstances);
Deepak Kodihalli0b459552018-02-06 06:25:12 -06001369}
1370
1371} // namespace sensor_info
1372} // namespace dcmi
1373
1374ipmi_ret_t getSensorInfo(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
1375 ipmi_request_t request, ipmi_response_t response,
1376 ipmi_data_len_t data_len, ipmi_context_t context)
1377{
1378 auto requestData =
1379 reinterpret_cast<const dcmi::GetSensorInfoRequest*>(request);
1380 auto responseData =
1381 reinterpret_cast<dcmi::GetSensorInfoResponseHdr*>(response);
1382
1383 if (*data_len != sizeof(dcmi::GetSensorInfoRequest))
1384 {
1385 log<level::ERR>("Malformed request data",
1386 entry("DATA_SIZE=%d", *data_len));
1387 return IPMI_CC_REQ_DATA_LEN_INVALID;
1388 }
1389 *data_len = 0;
1390
1391 auto it = dcmi::entityIdToName.find(requestData->entityId);
1392 if (it == dcmi::entityIdToName.end())
1393 {
1394 log<level::ERR>("Unknown Entity ID",
1395 entry("ENTITY_ID=%d", requestData->entityId));
1396 return IPMI_CC_INVALID_FIELD_REQUEST;
1397 }
1398
1399 if (requestData->groupID != dcmi::groupExtId)
1400 {
1401 log<level::ERR>("Invalid Group ID",
1402 entry("GROUP_ID=%d", requestData->groupID));
1403 return IPMI_CC_INVALID_FIELD_REQUEST;
1404 }
1405
1406 if (requestData->sensorType != dcmi::temperatureSensorType)
1407 {
1408 log<level::ERR>("Invalid sensor type",
1409 entry("SENSOR_TYPE=%d", requestData->sensorType));
1410 return IPMI_CC_INVALID_FIELD_REQUEST;
1411 }
1412
1413 dcmi::sensor_info::ResponseList sensors{};
1414 static dcmi::Json config{};
1415 static bool parsed = false;
1416
1417 try
1418 {
1419 if (!parsed)
1420 {
1421 config = dcmi::parseSensorConfig();
1422 parsed = true;
1423 }
1424
1425 if (!requestData->entityInstance)
1426 {
1427 // Read all instances
1428 std::tie(sensors, responseData->numInstances) =
1429 dcmi::sensor_info::readAll(it->second,
Patrick Venture0b02be92018-08-31 11:55:55 -07001430 requestData->instanceStart, config);
Deepak Kodihalli0b459552018-02-06 06:25:12 -06001431 }
1432 else
1433 {
1434 // Read one instance
1435 sensors.resize(1);
1436 std::tie(sensors[0], responseData->numInstances) =
Patrick Venture0b02be92018-08-31 11:55:55 -07001437 dcmi::sensor_info::read(it->second, requestData->entityInstance,
Deepak Kodihalli0b459552018-02-06 06:25:12 -06001438 config);
1439 }
1440 responseData->numRecords = sensors.size();
1441 }
1442 catch (InternalFailure& e)
1443 {
1444 return IPMI_CC_UNSPECIFIED_ERROR;
1445 }
1446
1447 responseData->groupID = dcmi::groupExtId;
1448 size_t payloadSize = sensors.size() * sizeof(dcmi::sensor_info::Response);
1449 if (!sensors.empty())
1450 {
1451 memcpy(responseData + 1, // copy payload right after the response header
Patrick Venture0b02be92018-08-31 11:55:55 -07001452 sensors.data(), payloadSize);
Deepak Kodihalli0b459552018-02-06 06:25:12 -06001453 }
1454 *data_len = sizeof(dcmi::GetSensorInfoResponseHdr) + payloadSize;
1455
1456 return IPMI_CC_OK;
1457}
1458
Chris Austen1810bec2015-10-13 12:12:39 -05001459void register_netfn_dcmi_functions()
1460{
Tom05732372016-09-06 17:21:23 +05301461 // <Get Power Limit>
Ratan Gupta11ddbd22017-08-05 11:59:39 +05301462
Patrick Venture0b02be92018-08-31 11:55:55 -07001463 ipmi_register_callback(NETFUN_GRPEXT, dcmi::Commands::GET_POWER_LIMIT, NULL,
1464 getPowerLimit, PRIVILEGE_USER);
Tom Joseph6f6dd4d2017-07-12 20:07:11 +05301465
Tom Joseph46fa37d2017-07-26 18:11:55 +05301466 // <Set Power Limit>
Ratan Gupta11ddbd22017-08-05 11:59:39 +05301467
Patrick Venture0b02be92018-08-31 11:55:55 -07001468 ipmi_register_callback(NETFUN_GRPEXT, dcmi::Commands::SET_POWER_LIMIT, NULL,
1469 setPowerLimit, PRIVILEGE_OPERATOR);
Tom Joseph46fa37d2017-07-26 18:11:55 +05301470
Tom Joseph6c8d51b2017-07-26 18:18:06 +05301471 // <Activate/Deactivate Power Limit>
Ratan Gupta11ddbd22017-08-05 11:59:39 +05301472
1473 ipmi_register_callback(NETFUN_GRPEXT, dcmi::Commands::APPLY_POWER_LIMIT,
1474 NULL, applyPowerLimit, PRIVILEGE_OPERATOR);
Tom Joseph6c8d51b2017-07-26 18:18:06 +05301475
Tom Joseph6f6dd4d2017-07-12 20:07:11 +05301476 // <Get Asset Tag>
Ratan Gupta11ddbd22017-08-05 11:59:39 +05301477
Patrick Venture0b02be92018-08-31 11:55:55 -07001478 ipmi_register_callback(NETFUN_GRPEXT, dcmi::Commands::GET_ASSET_TAG, NULL,
1479 getAssetTag, PRIVILEGE_USER);
Tom Joseph545dd232017-07-12 20:20:49 +05301480
1481 // <Set Asset Tag>
Ratan Gupta11ddbd22017-08-05 11:59:39 +05301482
Patrick Venture0b02be92018-08-31 11:55:55 -07001483 ipmi_register_callback(NETFUN_GRPEXT, dcmi::Commands::SET_ASSET_TAG, NULL,
1484 setAssetTag, PRIVILEGE_OPERATOR);
Vladislav Vovchenko8f7a6f62017-08-17 00:31:14 +03001485
Gunnar Mills8991dd62017-10-25 17:11:29 -05001486 // <Get Management Controller Identifier String>
Vladislav Vovchenko8f7a6f62017-08-17 00:31:14 +03001487
1488 ipmi_register_callback(NETFUN_GRPEXT, dcmi::Commands::GET_MGMNT_CTRL_ID_STR,
Patrick Venture0b02be92018-08-31 11:55:55 -07001489 NULL, getMgmntCtrlIdStr, PRIVILEGE_USER);
Vladislav Vovchenko8f7a6f62017-08-17 00:31:14 +03001490
1491 // <Set Management Controller Identifier String>
Vladislav Vovchenko8f7a6f62017-08-17 00:31:14 +03001492 ipmi_register_callback(NETFUN_GRPEXT, dcmi::Commands::SET_MGMNT_CTRL_ID_STR,
Patrick Venture0b02be92018-08-31 11:55:55 -07001493 NULL, setMgmntCtrlIdStr, PRIVILEGE_ADMIN);
Vladislav Vovchenko8f7a6f62017-08-17 00:31:14 +03001494
Dhruvaraj Subhashchandrane29be412018-01-16 05:11:56 -06001495 // <Get DCMI capabilities>
1496 ipmi_register_callback(NETFUN_GRPEXT, dcmi::Commands::GET_CAPABILITIES,
Patrick Venture0b02be92018-08-31 11:55:55 -07001497 NULL, getDCMICapabilities, PRIVILEGE_USER);
Deepak Kodihalliee717d72018-01-24 04:53:09 -06001498
1499 // <Get Temperature Readings>
1500 ipmi_register_callback(NETFUN_GRPEXT, dcmi::Commands::GET_TEMP_READINGS,
1501 NULL, getTempReadings, PRIVILEGE_USER);
1502
Marri Devender Rao66c5fda2018-01-18 10:48:37 -06001503 // <Get Power Reading>
1504 ipmi_register_callback(NETFUN_GRPEXT, dcmi::Commands::GET_POWER_READING,
1505 NULL, getPowerReading, PRIVILEGE_USER);
Deepak Kodihalli0b459552018-02-06 06:25:12 -06001506
1507 // <Get Sensor Info>
Patrick Venture0b02be92018-08-31 11:55:55 -07001508 ipmi_register_callback(NETFUN_GRPEXT, dcmi::Commands::GET_SENSOR_INFO, NULL,
1509 getSensorInfo, PRIVILEGE_USER);
Deepak Kodihalli0b459552018-02-06 06:25:12 -06001510
Nagaraju Goruganti22be97b2018-02-07 01:19:59 -06001511 // <Get DCMI Configuration Parameters>
Patrick Venture0b02be92018-08-31 11:55:55 -07001512 ipmi_register_callback(NETFUN_GRPEXT, dcmi::Commands::GET_CONF_PARAMS, NULL,
1513 getDCMIConfParams, PRIVILEGE_USER);
Nagaraju Goruganti22be97b2018-02-07 01:19:59 -06001514
1515 // <Set DCMI Configuration Parameters>
Patrick Venture0b02be92018-08-31 11:55:55 -07001516 ipmi_register_callback(NETFUN_GRPEXT, dcmi::Commands::SET_CONF_PARAMS, NULL,
1517 setDCMIConfParams, PRIVILEGE_ADMIN);
Nagaraju Goruganti22be97b2018-02-07 01:19:59 -06001518
Chris Austen1810bec2015-10-13 12:12:39 -05001519 return;
1520}
Tom05732372016-09-06 17:21:23 +05301521// 956379