blob: 5f13ea2857fd007cf13db96fe93578be171c79ff [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
Patrick Venture46470a32018-09-07 19:26:25 -07008#include <host-ipmid/ipmid-api.h>
Patrick Venture0b02be92018-08-31 11:55:55 -07009#include <stdint.h>
10#include <stdio.h>
11#include <string.h>
12
13#include <bitset>
14#include <cmath>
15#include <fstream>
16#include <nlohmann/json.hpp>
Tom Josephbe5eaa12017-07-12 19:54:44 +053017#include <phosphor-logging/elog-errors.hpp>
Andrew Geissler50c0c8f2017-07-11 16:18:51 -050018#include <phosphor-logging/log.hpp>
19#include <sdbusplus/bus.hpp>
Patrick Venture0b02be92018-08-31 11:55:55 -070020#include <xyz/openbmc_project/Common/error.hpp>
21
Tom Josephbe5eaa12017-07-12 19:54:44 +053022using namespace phosphor::logging;
23using InternalFailure =
Patrick Venture0b02be92018-08-31 11:55:55 -070024 sdbusplus::xyz::openbmc_project::Common::Error::InternalFailure;
Chris Austen1810bec2015-10-13 12:12:39 -050025
26void register_netfn_dcmi_functions() __attribute__((constructor));
27
Patrick Venture0b02be92018-08-31 11:55:55 -070028constexpr auto PCAP_PATH = "/xyz/openbmc_project/control/host0/power_cap";
Andrew Geissler50c0c8f2017-07-11 16:18:51 -050029constexpr auto PCAP_INTERFACE = "xyz.openbmc_project.Control.Power.Cap";
30
31constexpr auto POWER_CAP_PROP = "PowerCap";
32constexpr auto POWER_CAP_ENABLE_PROP = "PowerCapEnable";
33
Dhruvaraj Subhashchandrane29be412018-01-16 05:11:56 -060034constexpr auto DCMI_PARAMETER_REVISION = 2;
35constexpr auto DCMI_SPEC_MAJOR_VERSION = 1;
36constexpr auto DCMI_SPEC_MINOR_VERSION = 5;
Nagaraju Goruganti22be97b2018-02-07 01:19:59 -060037constexpr auto DCMI_CONFIG_PARAMETER_REVISION = 1;
38constexpr auto DCMI_RAND_BACK_OFF_MASK = 0x80;
39constexpr auto DCMI_OPTION_60_43_MASK = 0x02;
40constexpr auto DCMI_OPTION_12_MASK = 0x01;
41constexpr auto DCMI_ACTIVATE_DHCP_MASK = 0x01;
42constexpr auto DCMI_ACTIVATE_DHCP_REPLY = 0x00;
43constexpr auto DCMI_SET_CONF_PARAM_REQ_PACKET_MAX_SIZE = 0x05;
44constexpr auto DCMI_SET_CONF_PARAM_REQ_PACKET_MIN_SIZE = 0x04;
Patrick Venture0b02be92018-08-31 11:55:55 -070045constexpr auto DHCP_TIMING1 = 0x04; // 4 sec
46constexpr auto DHCP_TIMING2_UPPER = 0x00; // 2 min
Nagaraju Goruganti22be97b2018-02-07 01:19:59 -060047constexpr auto DHCP_TIMING2_LOWER = 0x78;
Patrick Venture0b02be92018-08-31 11:55:55 -070048constexpr auto DHCP_TIMING3_UPPER = 0x00; // 64 sec
Nagaraju Goruganti22be97b2018-02-07 01:19:59 -060049constexpr auto DHCP_TIMING3_LOWER = 0x40;
50// When DHCP Option 12 is enabled the string "SendHostName=true" will be
51// added into n/w configuration file and the parameter
52// SendHostNameEnabled will set to true.
53constexpr auto DHCP_OPT12_ENABLED = "SendHostNameEnabled";
54
Dhruvaraj Subhashchandrane29be412018-01-16 05:11:56 -060055constexpr auto DCMI_CAP_JSON_FILE = "/usr/share/ipmi-providers/dcmi_cap.json";
56
Marri Devender Rao66c5fda2018-01-18 10:48:37 -060057constexpr auto SENSOR_VALUE_INTF = "xyz.openbmc_project.Sensor.Value";
58constexpr auto SENSOR_VALUE_PROP = "Value";
59constexpr auto SENSOR_SCALE_PROP = "Scale";
60
Andrew Geissler50c0c8f2017-07-11 16:18:51 -050061using namespace phosphor::logging;
62
Tom Josephb9d86f42017-07-26 18:03:47 +053063namespace dcmi
64{
65
Deepak Kodihalli0b459552018-02-06 06:25:12 -060066// Refer Table 6-14, DCMI Entity ID Extension, DCMI v1.5 spec
Patrick Venture0b02be92018-08-31 11:55:55 -070067static const std::map<uint8_t, std::string> entityIdToName{
68 {0x40, "inlet"}, {0x37, "inlet"}, {0x41, "cpu"},
69 {0x03, "cpu"}, {0x42, "baseboard"}, {0x07, "baseboard"}};
Deepak Kodihalli0b459552018-02-06 06:25:12 -060070
Andrew Geissler50c0c8f2017-07-11 16:18:51 -050071uint32_t getPcap(sdbusplus::bus::bus& bus)
72{
Patrick Venture0b02be92018-08-31 11:55:55 -070073 auto settingService = ipmi::getService(bus, PCAP_INTERFACE, PCAP_PATH);
Andrew Geissler50c0c8f2017-07-11 16:18:51 -050074
Patrick Venture0b02be92018-08-31 11:55:55 -070075 auto method = bus.new_method_call(settingService.c_str(), PCAP_PATH,
76 "org.freedesktop.DBus.Properties", "Get");
Andrew Geissler50c0c8f2017-07-11 16:18:51 -050077
78 method.append(PCAP_INTERFACE, POWER_CAP_PROP);
79 auto reply = bus.call(method);
80
81 if (reply.is_method_error())
82 {
83 log<level::ERR>("Error in getPcap prop");
Tom Josephb9d86f42017-07-26 18:03:47 +053084 elog<InternalFailure>();
Andrew Geissler50c0c8f2017-07-11 16:18:51 -050085 }
86 sdbusplus::message::variant<uint32_t> pcap;
87 reply.read(pcap);
88
Tom Josephb9d86f42017-07-26 18:03:47 +053089 return pcap.get<uint32_t>();
Andrew Geissler50c0c8f2017-07-11 16:18:51 -050090}
91
92bool getPcapEnabled(sdbusplus::bus::bus& bus)
93{
Patrick Venture0b02be92018-08-31 11:55:55 -070094 auto settingService = ipmi::getService(bus, PCAP_INTERFACE, PCAP_PATH);
Andrew Geissler50c0c8f2017-07-11 16:18:51 -050095
Patrick Venture0b02be92018-08-31 11:55:55 -070096 auto method = bus.new_method_call(settingService.c_str(), PCAP_PATH,
97 "org.freedesktop.DBus.Properties", "Get");
Andrew Geissler50c0c8f2017-07-11 16:18:51 -050098
99 method.append(PCAP_INTERFACE, POWER_CAP_ENABLE_PROP);
100 auto reply = bus.call(method);
101
102 if (reply.is_method_error())
103 {
104 log<level::ERR>("Error in getPcapEnabled prop");
Tom Josephb9d86f42017-07-26 18:03:47 +0530105 elog<InternalFailure>();
Andrew Geissler50c0c8f2017-07-11 16:18:51 -0500106 }
107 sdbusplus::message::variant<bool> pcapEnabled;
108 reply.read(pcapEnabled);
109
Tom Josephb9d86f42017-07-26 18:03:47 +0530110 return pcapEnabled.get<bool>();
Andrew Geissler50c0c8f2017-07-11 16:18:51 -0500111}
Chris Austen1810bec2015-10-13 12:12:39 -0500112
Tom Joseph46fa37d2017-07-26 18:11:55 +0530113void setPcap(sdbusplus::bus::bus& bus, const uint32_t powerCap)
114{
115 auto service = ipmi::getService(bus, PCAP_INTERFACE, PCAP_PATH);
116
Patrick Venture0b02be92018-08-31 11:55:55 -0700117 auto method = bus.new_method_call(service.c_str(), PCAP_PATH,
118 "org.freedesktop.DBus.Properties", "Set");
Tom Joseph46fa37d2017-07-26 18:11:55 +0530119
120 method.append(PCAP_INTERFACE, POWER_CAP_PROP);
121 method.append(sdbusplus::message::variant<uint32_t>(powerCap));
122
123 auto reply = bus.call(method);
124
125 if (reply.is_method_error())
126 {
127 log<level::ERR>("Error in setPcap property");
128 elog<InternalFailure>();
129 }
130}
131
Tom Joseph6c8d51b2017-07-26 18:18:06 +0530132void setPcapEnable(sdbusplus::bus::bus& bus, bool enabled)
133{
134 auto service = ipmi::getService(bus, PCAP_INTERFACE, PCAP_PATH);
135
Patrick Venture0b02be92018-08-31 11:55:55 -0700136 auto method = bus.new_method_call(service.c_str(), PCAP_PATH,
137 "org.freedesktop.DBus.Properties", "Set");
Tom Joseph6c8d51b2017-07-26 18:18:06 +0530138
139 method.append(PCAP_INTERFACE, POWER_CAP_ENABLE_PROP);
140 method.append(sdbusplus::message::variant<bool>(enabled));
141
142 auto reply = bus.call(method);
143
144 if (reply.is_method_error())
145 {
146 log<level::ERR>("Error in setPcapEnabled property");
147 elog<InternalFailure>();
148 }
149}
150
Tom Josephbe5eaa12017-07-12 19:54:44 +0530151void readAssetTagObjectTree(dcmi::assettag::ObjectTree& objectTree)
152{
153 static constexpr auto mapperBusName = "xyz.openbmc_project.ObjectMapper";
154 static constexpr auto mapperObjPath = "/xyz/openbmc_project/object_mapper";
155 static constexpr auto mapperIface = "xyz.openbmc_project.ObjectMapper";
156 static constexpr auto inventoryRoot = "/xyz/openbmc_project/inventory/";
157
158 sdbusplus::bus::bus bus{ipmid_get_sd_bus_connection()};
159 auto depth = 0;
160
Patrick Venture0b02be92018-08-31 11:55:55 -0700161 auto mapperCall = bus.new_method_call(mapperBusName, mapperObjPath,
162 mapperIface, "GetSubTree");
Tom Josephbe5eaa12017-07-12 19:54:44 +0530163
164 mapperCall.append(inventoryRoot);
165 mapperCall.append(depth);
166 mapperCall.append(std::vector<std::string>({dcmi::assetTagIntf}));
167
168 auto mapperReply = bus.call(mapperCall);
169 if (mapperReply.is_method_error())
170 {
171 log<level::ERR>("Error in mapper call");
172 elog<InternalFailure>();
173 }
174
175 mapperReply.read(objectTree);
176
177 if (objectTree.empty())
178 {
179 log<level::ERR>("AssetTag property is not populated");
180 elog<InternalFailure>();
181 }
182}
183
184std::string readAssetTag()
185{
186 sdbusplus::bus::bus bus{ipmid_get_sd_bus_connection()};
187 dcmi::assettag::ObjectTree objectTree;
188
189 // Read the object tree with the inventory root to figure out the object
190 // that has implemented the Asset tag interface.
191 readAssetTagObjectTree(objectTree);
192
193 auto method = bus.new_method_call(
Patrick Venture0b02be92018-08-31 11:55:55 -0700194 (objectTree.begin()->second.begin()->first).c_str(),
195 (objectTree.begin()->first).c_str(), dcmi::propIntf, "Get");
Tom Josephbe5eaa12017-07-12 19:54:44 +0530196 method.append(dcmi::assetTagIntf);
197 method.append(dcmi::assetTagProp);
198
199 auto reply = bus.call(method);
200 if (reply.is_method_error())
201 {
202 log<level::ERR>("Error in reading asset tag");
203 elog<InternalFailure>();
204 }
205
206 sdbusplus::message::variant<std::string> assetTag;
207 reply.read(assetTag);
208
209 return assetTag.get<std::string>();
210}
211
Tom Josephbe5b9892017-07-15 00:55:23 +0530212void writeAssetTag(const std::string& assetTag)
213{
214 sdbusplus::bus::bus bus{ipmid_get_sd_bus_connection()};
215 dcmi::assettag::ObjectTree objectTree;
216
217 // Read the object tree with the inventory root to figure out the object
218 // that has implemented the Asset tag interface.
219 readAssetTagObjectTree(objectTree);
220
221 auto method = bus.new_method_call(
Patrick Venture0b02be92018-08-31 11:55:55 -0700222 (objectTree.begin()->second.begin()->first).c_str(),
223 (objectTree.begin()->first).c_str(), dcmi::propIntf, "Set");
Tom Josephbe5b9892017-07-15 00:55:23 +0530224 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{
Patrick Venture0b02be92018-08-31 11:55:55 -0700238 sdbusplus::bus::bus bus{ipmid_get_sd_bus_connection()};
Vladislav Vovchenko8f7a6f62017-08-17 00:31:14 +0300239
240 auto service = ipmi::getService(bus, networkConfigIntf, networkConfigObj);
Patrick Venture0b02be92018-08-31 11:55:55 -0700241 auto value = ipmi::getDbusProperty(bus, service, networkConfigObj,
242 networkConfigIntf, hostNameProp);
Vladislav Vovchenko8f7a6f62017-08-17 00:31:14 +0300243
244 return value.get<std::string>();
245}
246
Nagaraju Goruganti22be97b2018-02-07 01:19:59 -0600247bool getDHCPEnabled()
248{
249 sdbusplus::bus::bus bus{ipmid_get_sd_bus_connection()};
250
Patrick Venture0b02be92018-08-31 11:55:55 -0700251 auto ethdevice =
252 ipmi::network::ChanneltoEthernet(ethernetDefaultChannelNum);
253 auto ethernetObj =
254 ipmi::getDbusObject(bus, ethernetIntf, networkRoot, ethdevice);
Nagaraju Goruganti22be97b2018-02-07 01:19:59 -0600255 auto service = ipmi::getService(bus, ethernetIntf, ethernetObj.first);
Patrick Venture0b02be92018-08-31 11:55:55 -0700256 auto value = ipmi::getDbusProperty(bus, service, ethernetObj.first,
257 ethernetIntf, "DHCPEnabled");
Nagaraju Goruganti22be97b2018-02-07 01:19:59 -0600258
259 return value.get<bool>();
260}
261
262bool getDHCPOption(std::string prop)
263{
264 sdbusplus::bus::bus bus{ipmid_get_sd_bus_connection()};
265
266 auto service = ipmi::getService(bus, dhcpIntf, dhcpObj);
267 auto value = ipmi::getDbusProperty(bus, service, dhcpObj, dhcpIntf, prop);
268
269 return value.get<bool>();
270}
271
Nagaraju Goruganti22be97b2018-02-07 01:19:59 -0600272void setDHCPOption(std::string prop, bool value)
273{
274 sdbusplus::bus::bus bus{ipmid_get_sd_bus_connection()};
275
276 auto service = ipmi::getService(bus, dhcpIntf, dhcpObj);
277 ipmi::setDbusProperty(bus, service, dhcpObj, dhcpIntf, prop, value);
278}
279
Deepak Kodihalli0b459552018-02-06 06:25:12 -0600280Json parseSensorConfig()
281{
282 std::ifstream jsonFile(configFile);
283 if (!jsonFile.is_open())
284 {
285 log<level::ERR>("Temperature readings JSON file not found");
286 elog<InternalFailure>();
287 }
288
289 auto data = Json::parse(jsonFile, nullptr, false);
290 if (data.is_discarded())
291 {
292 log<level::ERR>("Temperature readings JSON parser failure");
293 elog<InternalFailure>();
294 }
295
296 return data;
297}
298
Tom Josephbe5eaa12017-07-12 19:54:44 +0530299} // namespace dcmi
Chris Austen1810bec2015-10-13 12:12:39 -0500300
Tom Josephb9d86f42017-07-26 18:03:47 +0530301ipmi_ret_t getPowerLimit(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
302 ipmi_request_t request, ipmi_response_t response,
303 ipmi_data_len_t data_len, ipmi_context_t context)
304{
Patrick Venture0b02be92018-08-31 11:55:55 -0700305 auto requestData =
306 reinterpret_cast<const dcmi::GetPowerLimitRequest*>(request);
Tom Josephb9d86f42017-07-26 18:03:47 +0530307 std::vector<uint8_t> outPayload(sizeof(dcmi::GetPowerLimitResponse));
Patrick Venture0b02be92018-08-31 11:55:55 -0700308 auto responseData =
309 reinterpret_cast<dcmi::GetPowerLimitResponse*>(outPayload.data());
Tom Josephb9d86f42017-07-26 18:03:47 +0530310
311 if (requestData->groupID != dcmi::groupExtId)
312 {
313 *data_len = 0;
314 return IPMI_CC_INVALID_FIELD_REQUEST;
315 }
316
Patrick Venture0b02be92018-08-31 11:55:55 -0700317 sdbusplus::bus::bus sdbus{ipmid_get_sd_bus_connection()};
Tom Josephb9d86f42017-07-26 18:03:47 +0530318 uint32_t pcapValue = 0;
319 bool pcapEnable = false;
320
321 try
322 {
323 pcapValue = dcmi::getPcap(sdbus);
324 pcapEnable = dcmi::getPcapEnabled(sdbus);
325 }
326 catch (InternalFailure& e)
327 {
328 *data_len = 0;
329 return IPMI_CC_UNSPECIFIED_ERROR;
330 }
331
332 responseData->groupID = dcmi::groupExtId;
333
334 /*
335 * Exception action if power limit is exceeded and cannot be controlled
336 * with the correction time limit is hardcoded to Hard Power Off system
337 * and log event to SEL.
338 */
339 constexpr auto exception = 0x01;
340 responseData->exceptionAction = exception;
341
342 responseData->powerLimit = static_cast<uint16_t>(pcapValue);
343
344 /*
345 * Correction time limit and Statistics sampling period is currently not
346 * populated.
347 */
348
349 *data_len = outPayload.size();
350 memcpy(response, outPayload.data(), *data_len);
351
352 if (pcapEnable)
353 {
354 return IPMI_CC_OK;
355 }
356 else
357 {
358 return IPMI_DCMI_CC_NO_ACTIVE_POWER_LIMIT;
359 }
360}
361
Tom Joseph46fa37d2017-07-26 18:11:55 +0530362ipmi_ret_t setPowerLimit(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
363 ipmi_request_t request, ipmi_response_t response,
364 ipmi_data_len_t data_len, ipmi_context_t context)
365{
Patrick Venture0b02be92018-08-31 11:55:55 -0700366 auto requestData =
367 reinterpret_cast<const dcmi::SetPowerLimitRequest*>(request);
Tom Joseph46fa37d2017-07-26 18:11:55 +0530368 std::vector<uint8_t> outPayload(sizeof(dcmi::SetPowerLimitResponse));
Patrick Venture0b02be92018-08-31 11:55:55 -0700369 auto responseData =
370 reinterpret_cast<dcmi::SetPowerLimitResponse*>(outPayload.data());
Tom Joseph46fa37d2017-07-26 18:11:55 +0530371
372 if (requestData->groupID != dcmi::groupExtId)
373 {
374 *data_len = 0;
375 return IPMI_CC_INVALID_FIELD_REQUEST;
376 }
377
Patrick Venture0b02be92018-08-31 11:55:55 -0700378 sdbusplus::bus::bus sdbus{ipmid_get_sd_bus_connection()};
Tom Joseph46fa37d2017-07-26 18:11:55 +0530379
380 // Only process the power limit requested in watts.
381 try
382 {
383 dcmi::setPcap(sdbus, requestData->powerLimit);
384 }
385 catch (InternalFailure& e)
386 {
387 *data_len = 0;
388 return IPMI_CC_UNSPECIFIED_ERROR;
389 }
390
391 log<level::INFO>("Set Power Cap",
392 entry("POWERCAP=%u", requestData->powerLimit));
393
394 responseData->groupID = dcmi::groupExtId;
395 memcpy(response, outPayload.data(), outPayload.size());
396 *data_len = outPayload.size();
397
398 return IPMI_CC_OK;
399}
400
Tom Joseph6c8d51b2017-07-26 18:18:06 +0530401ipmi_ret_t applyPowerLimit(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
402 ipmi_request_t request, ipmi_response_t response,
403 ipmi_data_len_t data_len, ipmi_context_t context)
404{
Patrick Venture0b02be92018-08-31 11:55:55 -0700405 auto requestData =
406 reinterpret_cast<const dcmi::ApplyPowerLimitRequest*>(request);
Tom Joseph6c8d51b2017-07-26 18:18:06 +0530407 std::vector<uint8_t> outPayload(sizeof(dcmi::ApplyPowerLimitResponse));
Patrick Venture0b02be92018-08-31 11:55:55 -0700408 auto responseData =
409 reinterpret_cast<dcmi::ApplyPowerLimitResponse*>(outPayload.data());
Tom Joseph6c8d51b2017-07-26 18:18:06 +0530410
411 if (requestData->groupID != dcmi::groupExtId)
412 {
413 *data_len = 0;
414 return IPMI_CC_INVALID_FIELD_REQUEST;
415 }
416
Patrick Venture0b02be92018-08-31 11:55:55 -0700417 sdbusplus::bus::bus sdbus{ipmid_get_sd_bus_connection()};
Tom Joseph6c8d51b2017-07-26 18:18:06 +0530418
419 try
420 {
421 dcmi::setPcapEnable(sdbus,
422 static_cast<bool>(requestData->powerLimitAction));
423 }
424 catch (InternalFailure& e)
425 {
426 *data_len = 0;
427 return IPMI_CC_UNSPECIFIED_ERROR;
428 }
429
430 log<level::INFO>("Set Power Cap Enable",
431 entry("POWERCAPENABLE=%u", requestData->powerLimitAction));
432
433 responseData->groupID = dcmi::groupExtId;
434 memcpy(response, outPayload.data(), outPayload.size());
435 *data_len = outPayload.size();
436
437 return IPMI_CC_OK;
438}
439
Tom Joseph6f6dd4d2017-07-12 20:07:11 +0530440ipmi_ret_t getAssetTag(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
441 ipmi_request_t request, ipmi_response_t response,
442 ipmi_data_len_t data_len, ipmi_context_t context)
443{
Patrick Venture0b02be92018-08-31 11:55:55 -0700444 auto requestData =
445 reinterpret_cast<const dcmi::GetAssetTagRequest*>(request);
Tom Joseph6f6dd4d2017-07-12 20:07:11 +0530446 std::vector<uint8_t> outPayload(sizeof(dcmi::GetAssetTagResponse));
Patrick Venture0b02be92018-08-31 11:55:55 -0700447 auto responseData =
448 reinterpret_cast<dcmi::GetAssetTagResponse*>(outPayload.data());
Tom Joseph6f6dd4d2017-07-12 20:07:11 +0530449
450 if (requestData->groupID != dcmi::groupExtId)
451 {
452 *data_len = 0;
453 return IPMI_CC_INVALID_FIELD_REQUEST;
454 }
455
456 // Verify offset to read and number of bytes to read are not exceeding the
457 // range.
458 if ((requestData->offset > dcmi::assetTagMaxOffset) ||
459 (requestData->bytes > dcmi::maxBytes) ||
460 ((requestData->offset + requestData->bytes) > dcmi::assetTagMaxSize))
461 {
462 *data_len = 0;
463 return IPMI_CC_PARM_OUT_OF_RANGE;
464 }
465
466 std::string assetTag;
467
468 try
469 {
470 assetTag = dcmi::readAssetTag();
471 }
472 catch (InternalFailure& e)
473 {
474 *data_len = 0;
475 return IPMI_CC_UNSPECIFIED_ERROR;
476 }
477
478 responseData->groupID = dcmi::groupExtId;
479
480 // Return if the asset tag is not populated.
481 if (!assetTag.size())
482 {
483 responseData->tagLength = 0;
484 memcpy(response, outPayload.data(), outPayload.size());
485 *data_len = outPayload.size();
486 return IPMI_CC_OK;
487 }
488
489 // If the asset tag is longer than 63 bytes, restrict it to 63 bytes to suit
490 // Get Asset Tag command.
491 if (assetTag.size() > dcmi::assetTagMaxSize)
492 {
493 assetTag.resize(dcmi::assetTagMaxSize);
494 }
495
496 // If the requested offset is beyond the asset tag size.
497 if (requestData->offset >= assetTag.size())
498 {
499 *data_len = 0;
500 return IPMI_CC_PARM_OUT_OF_RANGE;
501 }
502
503 auto returnData = assetTag.substr(requestData->offset, requestData->bytes);
504
505 responseData->tagLength = assetTag.size();
506
507 memcpy(response, outPayload.data(), outPayload.size());
508 memcpy(static_cast<uint8_t*>(response) + outPayload.size(),
509 returnData.data(), returnData.size());
510 *data_len = outPayload.size() + returnData.size();
511
512 return IPMI_CC_OK;
513}
514
Tom Joseph545dd232017-07-12 20:20:49 +0530515ipmi_ret_t setAssetTag(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
516 ipmi_request_t request, ipmi_response_t response,
517 ipmi_data_len_t data_len, ipmi_context_t context)
518{
Patrick Venture0b02be92018-08-31 11:55:55 -0700519 auto requestData =
520 reinterpret_cast<const dcmi::SetAssetTagRequest*>(request);
Tom Joseph545dd232017-07-12 20:20:49 +0530521 std::vector<uint8_t> outPayload(sizeof(dcmi::SetAssetTagResponse));
Patrick Venture0b02be92018-08-31 11:55:55 -0700522 auto responseData =
523 reinterpret_cast<dcmi::SetAssetTagResponse*>(outPayload.data());
Tom Joseph545dd232017-07-12 20:20:49 +0530524
525 if (requestData->groupID != dcmi::groupExtId)
526 {
527 *data_len = 0;
528 return IPMI_CC_INVALID_FIELD_REQUEST;
529 }
530
531 // Verify offset to read and number of bytes to read are not exceeding the
532 // range.
533 if ((requestData->offset > dcmi::assetTagMaxOffset) ||
534 (requestData->bytes > dcmi::maxBytes) ||
535 ((requestData->offset + requestData->bytes) > dcmi::assetTagMaxSize))
536 {
537 *data_len = 0;
538 return IPMI_CC_PARM_OUT_OF_RANGE;
539 }
540
541 std::string assetTag;
542
543 try
544 {
545 assetTag = dcmi::readAssetTag();
546
547 if (requestData->offset > assetTag.size())
548 {
549 *data_len = 0;
550 return IPMI_CC_PARM_OUT_OF_RANGE;
551 }
552
553 assetTag.replace(requestData->offset,
554 assetTag.size() - requestData->offset,
555 static_cast<const char*>(request) +
Patrick Venture0b02be92018-08-31 11:55:55 -0700556 sizeof(dcmi::SetAssetTagRequest),
Tom Joseph545dd232017-07-12 20:20:49 +0530557 requestData->bytes);
558
559 dcmi::writeAssetTag(assetTag);
560
561 responseData->groupID = dcmi::groupExtId;
562 responseData->tagLength = assetTag.size();
563 memcpy(response, outPayload.data(), outPayload.size());
564 *data_len = outPayload.size();
565
566 return IPMI_CC_OK;
567 }
568 catch (InternalFailure& e)
569 {
570 *data_len = 0;
571 return IPMI_CC_UNSPECIFIED_ERROR;
572 }
573}
574
Vladislav Vovchenko8f7a6f62017-08-17 00:31:14 +0300575ipmi_ret_t getMgmntCtrlIdStr(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
Patrick Venture0b02be92018-08-31 11:55:55 -0700576 ipmi_request_t request, ipmi_response_t response,
577 ipmi_data_len_t data_len, ipmi_context_t context)
Vladislav Vovchenko8f7a6f62017-08-17 00:31:14 +0300578{
Patrick Venture0b02be92018-08-31 11:55:55 -0700579 auto requestData =
580 reinterpret_cast<const dcmi::GetMgmntCtrlIdStrRequest*>(request);
581 auto responseData =
582 reinterpret_cast<dcmi::GetMgmntCtrlIdStrResponse*>(response);
Vladislav Vovchenko8f7a6f62017-08-17 00:31:14 +0300583 std::string hostName;
584
585 *data_len = 0;
586
587 if (requestData->groupID != dcmi::groupExtId ||
588 requestData->bytes > dcmi::maxBytes ||
589 requestData->offset + requestData->bytes > dcmi::maxCtrlIdStrLen)
590 {
591 return IPMI_CC_INVALID_FIELD_REQUEST;
592 }
593
594 try
595 {
596 hostName = dcmi::getHostName();
597 }
598 catch (InternalFailure& e)
599 {
600 return IPMI_CC_UNSPECIFIED_ERROR;
601 }
602
603 if (requestData->offset > hostName.length())
604 {
605 return IPMI_CC_PARM_OUT_OF_RANGE;
606 }
607 auto responseStr = hostName.substr(requestData->offset, requestData->bytes);
608 auto responseStrLen = std::min(static_cast<std::size_t>(requestData->bytes),
Patrick Venture0b02be92018-08-31 11:55:55 -0700609 responseStr.length() + 1);
Vladislav Vovchenko8f7a6f62017-08-17 00:31:14 +0300610 responseData->groupID = dcmi::groupExtId;
611 responseData->strLen = hostName.length();
612 std::copy(begin(responseStr), end(responseStr), responseData->data);
613
614 *data_len = sizeof(*responseData) + responseStrLen;
615 return IPMI_CC_OK;
616}
617
618ipmi_ret_t setMgmntCtrlIdStr(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
Patrick Venture0b02be92018-08-31 11:55:55 -0700619 ipmi_request_t request, ipmi_response_t response,
620 ipmi_data_len_t data_len, ipmi_context_t context)
Vladislav Vovchenko8f7a6f62017-08-17 00:31:14 +0300621{
622 static std::array<char, dcmi::maxCtrlIdStrLen + 1> newCtrlIdStr;
623
Patrick Venture0b02be92018-08-31 11:55:55 -0700624 auto requestData =
625 reinterpret_cast<const dcmi::SetMgmntCtrlIdStrRequest*>(request);
626 auto responseData =
627 reinterpret_cast<dcmi::SetMgmntCtrlIdStrResponse*>(response);
Vladislav Vovchenko8f7a6f62017-08-17 00:31:14 +0300628
629 *data_len = 0;
630
631 if (requestData->groupID != dcmi::groupExtId ||
632 requestData->bytes > dcmi::maxBytes ||
633 requestData->offset + requestData->bytes > dcmi::maxCtrlIdStrLen + 1 ||
Patrick Venture0b02be92018-08-31 11:55:55 -0700634 (requestData->offset + requestData->bytes ==
635 dcmi::maxCtrlIdStrLen + 1 &&
636 requestData->data[requestData->bytes - 1] != '\0'))
Vladislav Vovchenko8f7a6f62017-08-17 00:31:14 +0300637 {
638 return IPMI_CC_INVALID_FIELD_REQUEST;
639 }
640
641 try
642 {
643 /* if there is no old value and offset is not 0 */
644 if (newCtrlIdStr[0] == '\0' && requestData->offset != 0)
645 {
646 /* read old ctrlIdStr */
647 auto hostName = dcmi::getHostName();
648 hostName.resize(dcmi::maxCtrlIdStrLen);
649 std::copy(begin(hostName), end(hostName), begin(newCtrlIdStr));
650 newCtrlIdStr[hostName.length()] = '\0';
651 }
652
653 /* replace part of string and mark byte after the last as \0 */
Patrick Venture0b02be92018-08-31 11:55:55 -0700654 auto restStrIter =
655 std::copy_n(requestData->data, requestData->bytes,
656 begin(newCtrlIdStr) + requestData->offset);
Vladislav Vovchenko8f7a6f62017-08-17 00:31:14 +0300657 /* if the last written byte is not 64th - add '\0' */
658 if (requestData->offset + requestData->bytes <= dcmi::maxCtrlIdStrLen)
659 {
660 *restStrIter = '\0';
661 }
662
663 /* if input data contains '\0' whole string is sent - update hostname */
664 auto it = std::find(requestData->data,
Patrick Venture0b02be92018-08-31 11:55:55 -0700665 requestData->data + requestData->bytes, '\0');
Vladislav Vovchenko8f7a6f62017-08-17 00:31:14 +0300666 if (it != requestData->data + requestData->bytes)
667 {
Patrick Venture0b02be92018-08-31 11:55:55 -0700668 sdbusplus::bus::bus bus{ipmid_get_sd_bus_connection()};
Vladislav Vovchenko8f7a6f62017-08-17 00:31:14 +0300669 ipmi::setDbusProperty(bus, dcmi::networkServiceName,
Patrick Venture0b02be92018-08-31 11:55:55 -0700670 dcmi::networkConfigObj,
671 dcmi::networkConfigIntf, dcmi::hostNameProp,
672 std::string(newCtrlIdStr.data()));
Vladislav Vovchenko8f7a6f62017-08-17 00:31:14 +0300673 }
674 }
675 catch (InternalFailure& e)
676 {
677 *data_len = 0;
678 return IPMI_CC_UNSPECIFIED_ERROR;
679 }
680
681 responseData->groupID = dcmi::groupExtId;
682 responseData->offset = requestData->offset + requestData->bytes;
683 *data_len = sizeof(*responseData);
684 return IPMI_CC_OK;
685}
686
Patrick Venture0b02be92018-08-31 11:55:55 -0700687// List of the capabilities under each parameter
688dcmi::DCMICaps dcmiCaps = {
689 // Supported DCMI Capabilities
690 {dcmi::DCMICapParameters::SUPPORTED_DCMI_CAPS,
691 {3,
692 {{"PowerManagement", 2, 0, 1},
693 {"OOBSecondaryLan", 3, 2, 1},
694 {"SerialTMODE", 3, 1, 1},
695 {"InBandSystemInterfaceChannel", 3, 0, 1}}}},
696 // Mandatory Platform Attributes
697 {dcmi::DCMICapParameters::MANDATORY_PLAT_ATTRIBUTES,
698 {5,
699 {{"SELAutoRollOver", 1, 15, 1},
700 {"FlushEntireSELUponRollOver", 1, 14, 1},
701 {"RecordLevelSELFlushUponRollOver", 1, 13, 1},
702 {"NumberOfSELEntries", 1, 0, 12},
703 {"TempMonitoringSamplingFreq", 5, 0, 8}}}},
704 // Optional Platform Attributes
705 {dcmi::DCMICapParameters::OPTIONAL_PLAT_ATTRIBUTES,
706 {2,
707 {{"PowerMgmtDeviceSlaveAddress", 1, 1, 7},
708 {"BMCChannelNumber", 2, 4, 4},
709 {"DeviceRivision", 2, 0, 4}}}},
710 // Manageability Access Attributes
711 {dcmi::DCMICapParameters::MANAGEABILITY_ACCESS_ATTRIBUTES,
712 {3,
713 {{"MandatoryPrimaryLanOOBSupport", 1, 0, 8},
714 {"OptionalSecondaryLanOOBSupport", 2, 0, 8},
715 {"OptionalSerialOOBMTMODECapability", 3, 0, 8}}}}};
Dhruvaraj Subhashchandrane29be412018-01-16 05:11:56 -0600716
717ipmi_ret_t getDCMICapabilities(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
718 ipmi_request_t request, ipmi_response_t response,
719 ipmi_data_len_t data_len, ipmi_context_t context)
720{
721
722 std::ifstream dcmiCapFile(DCMI_CAP_JSON_FILE);
723 if (!dcmiCapFile.is_open())
724 {
725 log<level::ERR>("DCMI Capabilities file not found");
726 return IPMI_CC_UNSPECIFIED_ERROR;
727 }
728
729 auto data = nlohmann::json::parse(dcmiCapFile, nullptr, false);
730 if (data.is_discarded())
731 {
732 log<level::ERR>("DCMI Capabilities JSON parser failure");
733 return IPMI_CC_UNSPECIFIED_ERROR;
734 }
735
Patrick Venture0b02be92018-08-31 11:55:55 -0700736 auto requestData =
737 reinterpret_cast<const dcmi::GetDCMICapRequest*>(request);
Dhruvaraj Subhashchandrane29be412018-01-16 05:11:56 -0600738
Patrick Venture0b02be92018-08-31 11:55:55 -0700739 // get list of capabilities in a parameter
Dhruvaraj Subhashchandrane29be412018-01-16 05:11:56 -0600740 auto caps =
741 dcmiCaps.find(static_cast<dcmi::DCMICapParameters>(requestData->param));
742 if (caps == dcmiCaps.end())
743 {
744 log<level::ERR>("Invalid input parameter");
745 return IPMI_CC_INVALID_FIELD_REQUEST;
746 }
747
748 if (requestData->groupID != dcmi::groupExtId)
749 {
750 *data_len = 0;
751 return IPMI_CC_INVALID_FIELD_REQUEST;
752 }
753
Patrick Venture0b02be92018-08-31 11:55:55 -0700754 auto responseData = reinterpret_cast<dcmi::GetDCMICapResponse*>(response);
Dhruvaraj Subhashchandrane29be412018-01-16 05:11:56 -0600755
Patrick Venture0b02be92018-08-31 11:55:55 -0700756 // For each capabilities in a parameter fill the data from
757 // the json file based on the capability name.
Dhruvaraj Subhashchandrane29be412018-01-16 05:11:56 -0600758 for (auto cap : caps->second.capList)
759 {
Patrick Venture0b02be92018-08-31 11:55:55 -0700760 // If the data is beyond first byte boundary, insert in a
761 // 16bit pattern for example number of SEL entries are represented
762 // in 12bits.
Dhruvaraj Subhashchandrane29be412018-01-16 05:11:56 -0600763 if ((cap.length + cap.position) > 8)
764 {
Patrick Venture0b02be92018-08-31 11:55:55 -0700765 // Read the value corresponding to capability name and assign to
766 // 16bit bitset.
Dhruvaraj Subhashchandrane29be412018-01-16 05:11:56 -0600767 std::bitset<16> val(data.value(cap.name.c_str(), 0));
768 val <<= cap.position;
Patrick Venture0b02be92018-08-31 11:55:55 -0700769 reinterpret_cast<uint16_t*>(
770 responseData
771 ->data)[(cap.bytePosition - 1) / sizeof(uint16_t)] |=
772 val.to_ulong();
Dhruvaraj Subhashchandrane29be412018-01-16 05:11:56 -0600773 }
774 else
775 {
776 responseData->data[cap.bytePosition - 1] |=
777 data.value(cap.name.c_str(), 0) << cap.position;
778 }
779 }
780
781 responseData->groupID = dcmi::groupExtId;
782 responseData->major = DCMI_SPEC_MAJOR_VERSION;
783 responseData->minor = DCMI_SPEC_MINOR_VERSION;
784 responseData->paramRevision = DCMI_PARAMETER_REVISION;
785 *data_len = sizeof(*responseData) + caps->second.size;
786
787 return IPMI_CC_OK;
788}
789
Deepak Kodihalliee717d72018-01-24 04:53:09 -0600790namespace dcmi
791{
792namespace temp_readings
793{
794
Deepak Kodihallib1e8fba2018-01-24 04:57:10 -0600795Temperature readTemp(const std::string& dbusService,
796 const std::string& dbusPath)
797{
798 // Read the temperature value from d-bus object. Need some conversion.
799 // As per the interface xyz.openbmc_project.Sensor.Value, the temperature
800 // is an int64_t and in degrees C. It needs to be scaled by using the
801 // formula Value * 10^Scale. The ipmi spec has the temperature as a uint8_t,
802 // with a separate single bit for the sign.
803
804 sdbusplus::bus::bus bus{ipmid_get_sd_bus_connection()};
Patrick Venture0b02be92018-08-31 11:55:55 -0700805 auto result = ipmi::getAllDbusProperties(
806 bus, dbusService, dbusPath, "xyz.openbmc_project.Sensor.Value");
Deepak Kodihallib1e8fba2018-01-24 04:57:10 -0600807 auto temperature = result.at("Value").get<int64_t>();
808 uint64_t absTemp = std::abs(temperature);
809
810 auto factor = result.at("Scale").get<int64_t>();
811 uint64_t scale = std::pow(10, factor); // pow() returns float/double
812 unsigned long long tempDegrees = 0;
813 // Overflow safe multiplication when the scale is > 0
Patrick Venture0b02be92018-08-31 11:55:55 -0700814 if (scale && __builtin_umulll_overflow(absTemp, scale, &tempDegrees))
Deepak Kodihallib1e8fba2018-01-24 04:57:10 -0600815 {
816 log<level::ERR>("Multiplication overflow detected",
817 entry("TEMP_VALUE=%llu", absTemp),
818 entry("SCALE_FACTOR=%llu", scale));
819 elog<InternalFailure>();
820 }
821 else
822 {
823 // The (uint64_t)scale value is 0, effectively this is division
824 tempDegrees = absTemp * std::pow(10, factor);
825 }
826 // Max absolute temp as per ipmi spec is 128.
827 if (tempDegrees > maxTemp)
828 {
829 tempDegrees = maxTemp;
830 }
831
832 return std::make_tuple(static_cast<uint8_t>(tempDegrees),
833 (temperature < 0));
834}
835
Deepak Kodihalliee717d72018-01-24 04:53:09 -0600836std::tuple<Response, NumInstances> read(const std::string& type,
837 uint8_t instance)
838{
Deepak Kodihallib1e8fba2018-01-24 04:57:10 -0600839 Response response{};
840 sdbusplus::bus::bus bus{ipmid_get_sd_bus_connection()};
841
842 if (!instance)
843 {
844 log<level::ERR>("Expected non-zero instance");
845 elog<InternalFailure>();
846 }
847
Deepak Kodihalli0b459552018-02-06 06:25:12 -0600848 auto data = parseSensorConfig();
Deepak Kodihallib1e8fba2018-01-24 04:57:10 -0600849 static const std::vector<Json> empty{};
850 std::vector<Json> readings = data.value(type, empty);
851 size_t numInstances = readings.size();
852 for (const auto& j : readings)
853 {
854 uint8_t instanceNum = j.value("instance", 0);
855 // Not the instance we're interested in
856 if (instanceNum != instance)
857 {
858 continue;
859 }
860
861 std::string path = j.value("dbus", "");
862 std::string service;
863 try
864 {
865 service =
Patrick Venture0b02be92018-08-31 11:55:55 -0700866 ipmi::getService(bus, "xyz.openbmc_project.Sensor.Value", path);
Deepak Kodihallib1e8fba2018-01-24 04:57:10 -0600867 }
868 catch (std::exception& e)
869 {
870 log<level::DEBUG>(e.what());
871 return std::make_tuple(response, numInstances);
872 }
873
874 response.instance = instance;
875 uint8_t temp{};
876 bool sign{};
877 std::tie(temp, sign) = readTemp(service, path);
878 response.temperature = temp;
879 response.sign = sign;
880
881 // Found the instance we're interested in
882 break;
883 }
884
885 if (numInstances > maxInstances)
886 {
887 numInstances = maxInstances;
888 }
889 return std::make_tuple(response, numInstances);
Deepak Kodihalliee717d72018-01-24 04:53:09 -0600890}
891
892std::tuple<ResponseList, NumInstances> readAll(const std::string& type,
893 uint8_t instanceStart)
894{
Deepak Kodihallib1e8fba2018-01-24 04:57:10 -0600895 ResponseList response{};
896 sdbusplus::bus::bus bus{ipmid_get_sd_bus_connection()};
897
898 size_t numInstances = 0;
Deepak Kodihalli0b459552018-02-06 06:25:12 -0600899 auto data = parseSensorConfig();
Deepak Kodihallib1e8fba2018-01-24 04:57:10 -0600900 static const std::vector<Json> empty{};
901 std::vector<Json> readings = data.value(type, empty);
902 numInstances = readings.size();
903 for (const auto& j : readings)
904 {
905 try
906 {
907 // Max of 8 response data sets
908 if (response.size() == maxDataSets)
909 {
910 break;
911 }
912
913 uint8_t instanceNum = j.value("instance", 0);
914 // Not in the instance range we're interested in
915 if (instanceNum < instanceStart)
916 {
917 continue;
918 }
919
920 std::string path = j.value("dbus", "");
921 auto service =
Patrick Venture0b02be92018-08-31 11:55:55 -0700922 ipmi::getService(bus, "xyz.openbmc_project.Sensor.Value", path);
Deepak Kodihallib1e8fba2018-01-24 04:57:10 -0600923
924 Response r{};
925 r.instance = instanceNum;
926 uint8_t temp{};
927 bool sign{};
928 std::tie(temp, sign) = readTemp(service, path);
929 r.temperature = temp;
930 r.sign = sign;
931 response.push_back(r);
932 }
933 catch (std::exception& e)
934 {
935 log<level::DEBUG>(e.what());
936 continue;
937 }
938 }
939
940 if (numInstances > maxInstances)
941 {
942 numInstances = maxInstances;
943 }
944 return std::make_tuple(response, numInstances);
Deepak Kodihalliee717d72018-01-24 04:53:09 -0600945}
946
Patrick Venture0b02be92018-08-31 11:55:55 -0700947} // namespace temp_readings
948} // namespace dcmi
Deepak Kodihalliee717d72018-01-24 04:53:09 -0600949
950ipmi_ret_t getTempReadings(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
Patrick Venture0b02be92018-08-31 11:55:55 -0700951 ipmi_request_t request, ipmi_response_t response,
952 ipmi_data_len_t data_len, ipmi_context_t context)
Deepak Kodihalliee717d72018-01-24 04:53:09 -0600953{
Deepak Kodihalliee717d72018-01-24 04:53:09 -0600954 auto requestData =
955 reinterpret_cast<const dcmi::GetTempReadingsRequest*>(request);
956 auto responseData =
957 reinterpret_cast<dcmi::GetTempReadingsResponseHdr*>(response);
958
959 if (*data_len != sizeof(dcmi::GetTempReadingsRequest))
960 {
961 log<level::ERR>("Malformed request data",
962 entry("DATA_SIZE=%d", *data_len));
963 return IPMI_CC_REQ_DATA_LEN_INVALID;
964 }
965 *data_len = 0;
966
Deepak Kodihalli0b459552018-02-06 06:25:12 -0600967 auto it = dcmi::entityIdToName.find(requestData->entityId);
968 if (it == dcmi::entityIdToName.end())
Deepak Kodihalliee717d72018-01-24 04:53:09 -0600969 {
970 log<level::ERR>("Unknown Entity ID",
971 entry("ENTITY_ID=%d", requestData->entityId));
972 return IPMI_CC_INVALID_FIELD_REQUEST;
973 }
974
975 if (requestData->groupID != dcmi::groupExtId)
976 {
977 log<level::ERR>("Invalid Group ID",
978 entry("GROUP_ID=%d", requestData->groupID));
979 return IPMI_CC_INVALID_FIELD_REQUEST;
980 }
981
982 if (requestData->sensorType != dcmi::temperatureSensorType)
983 {
984 log<level::ERR>("Invalid sensor type",
985 entry("SENSOR_TYPE=%d", requestData->sensorType));
986 return IPMI_CC_INVALID_FIELD_REQUEST;
987 }
988
989 dcmi::temp_readings::ResponseList temps{};
990 try
991 {
992 if (!requestData->entityInstance)
993 {
994 // Read all instances
995 std::tie(temps, responseData->numInstances) =
996 dcmi::temp_readings::readAll(it->second,
997 requestData->instanceStart);
998 }
999 else
1000 {
1001 // Read one instance
1002 temps.resize(1);
1003 std::tie(temps[0], responseData->numInstances) =
1004 dcmi::temp_readings::read(it->second,
1005 requestData->entityInstance);
1006 }
1007 responseData->numDataSets = temps.size();
1008 }
1009 catch (InternalFailure& e)
1010 {
1011 return IPMI_CC_UNSPECIFIED_ERROR;
1012 }
1013
1014 responseData->groupID = dcmi::groupExtId;
Patrick Venture0b02be92018-08-31 11:55:55 -07001015 size_t payloadSize = temps.size() * sizeof(dcmi::temp_readings::Response);
Deepak Kodihalliee717d72018-01-24 04:53:09 -06001016 if (!temps.empty())
1017 {
1018 memcpy(responseData + 1, // copy payload right after the response header
Patrick Venture0b02be92018-08-31 11:55:55 -07001019 temps.data(), payloadSize);
Deepak Kodihalliee717d72018-01-24 04:53:09 -06001020 }
1021 *data_len = sizeof(dcmi::GetTempReadingsResponseHdr) + payloadSize;
1022
1023 return IPMI_CC_OK;
1024}
1025
Marri Devender Rao66c5fda2018-01-18 10:48:37 -06001026int64_t getPowerReading(sdbusplus::bus::bus& bus)
1027{
1028 std::ifstream sensorFile(POWER_READING_SENSOR);
1029 std::string objectPath;
1030 if (!sensorFile.is_open())
1031 {
1032 log<level::ERR>("Power reading configuration file not found",
Patrick Venture0b02be92018-08-31 11:55:55 -07001033 entry("POWER_SENSOR_FILE=%s", POWER_READING_SENSOR));
Marri Devender Rao66c5fda2018-01-18 10:48:37 -06001034 elog<InternalFailure>();
1035 }
1036
1037 auto data = nlohmann::json::parse(sensorFile, nullptr, false);
1038 if (data.is_discarded())
1039 {
1040 log<level::ERR>("Error in parsing configuration file",
Patrick Venture0b02be92018-08-31 11:55:55 -07001041 entry("POWER_SENSOR_FILE=%s", POWER_READING_SENSOR));
Marri Devender Rao66c5fda2018-01-18 10:48:37 -06001042 elog<InternalFailure>();
1043 }
1044
1045 objectPath = data.value("path", "");
1046 if (objectPath.empty())
1047 {
1048 log<level::ERR>("Power sensor D-Bus object path is empty",
1049 entry("POWER_SENSOR_FILE=%s", POWER_READING_SENSOR));
1050 elog<InternalFailure>();
1051 }
1052
Marri Devender Raoce6a7952018-02-11 08:45:00 -06001053 // Return default value if failed to read from D-Bus object
1054 int64_t power = 0;
1055 try
1056 {
1057 auto service = ipmi::getService(bus, SENSOR_VALUE_INTF, objectPath);
Marri Devender Rao66c5fda2018-01-18 10:48:37 -06001058
Patrick Venture0b02be92018-08-31 11:55:55 -07001059 // Read the sensor value and scale properties
1060 auto properties = ipmi::getAllDbusProperties(bus, service, objectPath,
1061 SENSOR_VALUE_INTF);
Marri Devender Raoce6a7952018-02-11 08:45:00 -06001062 auto value = properties[SENSOR_VALUE_PROP].get<int64_t>();
1063 auto scale = properties[SENSOR_SCALE_PROP].get<int64_t>();
Marri Devender Rao66c5fda2018-01-18 10:48:37 -06001064
Marri Devender Raoce6a7952018-02-11 08:45:00 -06001065 // Power reading needs to be scaled with the Scale value using the
1066 // formula Value * 10^Scale.
1067 power = value * std::pow(10, scale);
1068 }
1069 catch (std::exception& e)
1070 {
1071 log<level::INFO>("Failure to read power value from D-Bus object",
Patrick Venture0b02be92018-08-31 11:55:55 -07001072 entry("OBJECT_PATH=%s", objectPath.c_str()),
1073 entry("INTERFACE=%s", SENSOR_VALUE_INTF));
Marri Devender Raoce6a7952018-02-11 08:45:00 -06001074 }
Marri Devender Rao66c5fda2018-01-18 10:48:37 -06001075 return power;
1076}
1077
Nagaraju Goruganti22be97b2018-02-07 01:19:59 -06001078ipmi_ret_t setDCMIConfParams(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
1079 ipmi_request_t request, ipmi_response_t response,
1080 ipmi_data_len_t data_len, ipmi_context_t context)
1081{
Patrick Venture0b02be92018-08-31 11:55:55 -07001082 auto requestData =
1083 reinterpret_cast<const dcmi::SetConfParamsRequest*>(request);
1084 auto responseData =
1085 reinterpret_cast<dcmi::SetConfParamsResponse*>(response);
Nagaraju Goruganti22be97b2018-02-07 01:19:59 -06001086
Patrick Venture0b02be92018-08-31 11:55:55 -07001087 if (requestData->groupID != dcmi::groupExtId ||
1088 *data_len < DCMI_SET_CONF_PARAM_REQ_PACKET_MIN_SIZE ||
1089 *data_len > DCMI_SET_CONF_PARAM_REQ_PACKET_MAX_SIZE)
Nagaraju Goruganti22be97b2018-02-07 01:19:59 -06001090 {
Gunnar Mills8466b792018-03-23 12:18:12 -05001091 log<level::ERR>("Invalid Group ID or Invalid Requested Packet size",
Nagaraju Goruganti22be97b2018-02-07 01:19:59 -06001092 entry("GROUP_ID=%d", requestData->groupID),
1093 entry("PACKET SIZE=%d", *data_len));
1094 return IPMI_CC_INVALID_FIELD_REQUEST;
1095 }
1096
1097 *data_len = 0;
1098
1099 try
1100 {
1101 // Take action based on the Parameter Selector
Patrick Venture0b02be92018-08-31 11:55:55 -07001102 switch (
1103 static_cast<dcmi::DCMIConfigParameters>(requestData->paramSelect))
Nagaraju Goruganti22be97b2018-02-07 01:19:59 -06001104 {
1105 case dcmi::DCMIConfigParameters::ActivateDHCP:
1106
1107 if ((requestData->data[0] & DCMI_ACTIVATE_DHCP_MASK) &&
Patrick Venture0b02be92018-08-31 11:55:55 -07001108 dcmi::getDHCPEnabled())
Nagaraju Goruganti22be97b2018-02-07 01:19:59 -06001109 {
Patrick Venture0b02be92018-08-31 11:55:55 -07001110 // When these conditions are met we have to trigger DHCP
1111 // protocol restart using the latest parameter settings, but
1112 // as per n/w manager design, each time when we update n/w
1113 // parameters, n/w service is restarted. So we no need to
1114 // take any action in this case.
Nagaraju Goruganti22be97b2018-02-07 01:19:59 -06001115 }
1116 break;
1117
1118 case dcmi::DCMIConfigParameters::DiscoveryConfig:
1119
1120 if (requestData->data[0] & DCMI_OPTION_12_MASK)
1121 {
1122 dcmi::setDHCPOption(DHCP_OPT12_ENABLED, true);
1123 }
1124 else
1125 {
1126 dcmi::setDHCPOption(DHCP_OPT12_ENABLED, false);
1127 }
1128
1129 // Systemd-networkd doesn't support Random Back off
1130 if (requestData->data[0] & DCMI_RAND_BACK_OFF_MASK)
1131 {
1132 return IPMI_CC_INVALID;
1133 }
1134 break;
1135 // Systemd-networkd doesn't allow to configure DHCP timigs
1136 case dcmi::DCMIConfigParameters::DHCPTiming1:
1137 case dcmi::DCMIConfigParameters::DHCPTiming2:
1138 case dcmi::DCMIConfigParameters::DHCPTiming3:
1139 default:
1140 return IPMI_CC_INVALID;
1141 }
1142 }
1143 catch (std::exception& e)
1144 {
1145 log<level::ERR>(e.what());
1146 return IPMI_CC_UNSPECIFIED_ERROR;
1147 }
1148 responseData->groupID = dcmi::groupExtId;
1149 *data_len = sizeof(dcmi::SetConfParamsResponse);
1150
1151 return IPMI_CC_OK;
1152}
1153
1154ipmi_ret_t getDCMIConfParams(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
1155 ipmi_request_t request, ipmi_response_t response,
1156 ipmi_data_len_t data_len, ipmi_context_t context)
1157{
1158
Patrick Venture0b02be92018-08-31 11:55:55 -07001159 auto requestData =
1160 reinterpret_cast<const dcmi::GetConfParamsRequest*>(request);
1161 auto responseData =
1162 reinterpret_cast<dcmi::GetConfParamsResponse*>(response);
Nagaraju Goruganti22be97b2018-02-07 01:19:59 -06001163
1164 responseData->data[0] = 0x00;
1165
Patrick Venture0b02be92018-08-31 11:55:55 -07001166 if (requestData->groupID != dcmi::groupExtId ||
1167 *data_len != sizeof(dcmi::GetConfParamsRequest))
Nagaraju Goruganti22be97b2018-02-07 01:19:59 -06001168 {
Gunnar Mills8466b792018-03-23 12:18:12 -05001169 log<level::ERR>("Invalid Group ID or Invalid Requested Packet size",
Nagaraju Goruganti22be97b2018-02-07 01:19:59 -06001170 entry("GROUP_ID=%d", requestData->groupID),
1171 entry("PACKET SIZE=%d", *data_len));
1172 return IPMI_CC_INVALID_FIELD_REQUEST;
1173 }
1174
1175 *data_len = 0;
1176
1177 try
1178 {
1179 // Take action based on the Parameter Selector
Patrick Venture0b02be92018-08-31 11:55:55 -07001180 switch (
1181 static_cast<dcmi::DCMIConfigParameters>(requestData->paramSelect))
Nagaraju Goruganti22be97b2018-02-07 01:19:59 -06001182 {
1183 case dcmi::DCMIConfigParameters::ActivateDHCP:
1184 responseData->data[0] = DCMI_ACTIVATE_DHCP_REPLY;
1185 *data_len = sizeof(dcmi::GetConfParamsResponse) + 1;
1186 break;
1187 case dcmi::DCMIConfigParameters::DiscoveryConfig:
1188 if (dcmi::getDHCPOption(DHCP_OPT12_ENABLED))
1189 {
1190 responseData->data[0] |= DCMI_OPTION_12_MASK;
1191 }
1192 *data_len = sizeof(dcmi::GetConfParamsResponse) + 1;
1193 break;
1194 // Get below values from Systemd-networkd source code
1195 case dcmi::DCMIConfigParameters::DHCPTiming1:
1196 responseData->data[0] = DHCP_TIMING1;
1197 *data_len = sizeof(dcmi::GetConfParamsResponse) + 1;
1198 break;
1199 case dcmi::DCMIConfigParameters::DHCPTiming2:
1200 responseData->data[0] = DHCP_TIMING2_LOWER;
1201 responseData->data[1] = DHCP_TIMING2_UPPER;
1202 *data_len = sizeof(dcmi::GetConfParamsResponse) + 2;
1203 break;
1204 case dcmi::DCMIConfigParameters::DHCPTiming3:
1205 responseData->data[0] = DHCP_TIMING3_LOWER;
1206 responseData->data[1] = DHCP_TIMING3_UPPER;
1207 *data_len = sizeof(dcmi::GetConfParamsResponse) + 2;
1208 break;
1209 default:
1210 *data_len = 0;
1211 return IPMI_CC_INVALID;
1212 }
1213 }
1214 catch (std::exception& e)
1215 {
1216 log<level::ERR>(e.what());
1217 return IPMI_CC_UNSPECIFIED_ERROR;
1218 }
1219
1220 responseData->groupID = dcmi::groupExtId;
1221 responseData->major = DCMI_SPEC_MAJOR_VERSION;
1222 responseData->minor = DCMI_SPEC_MINOR_VERSION;
1223 responseData->paramRevision = DCMI_CONFIG_PARAMETER_REVISION;
1224
1225 return IPMI_CC_OK;
1226}
1227
Marri Devender Rao66c5fda2018-01-18 10:48:37 -06001228ipmi_ret_t getPowerReading(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
Patrick Venture0b02be92018-08-31 11:55:55 -07001229 ipmi_request_t request, ipmi_response_t response,
1230 ipmi_data_len_t data_len, ipmi_context_t context)
Marri Devender Rao66c5fda2018-01-18 10:48:37 -06001231{
1232 ipmi_ret_t rc = IPMI_CC_OK;
Patrick Venture0b02be92018-08-31 11:55:55 -07001233 auto requestData =
1234 reinterpret_cast<const dcmi::GetPowerReadingRequest*>(request);
1235 auto responseData =
1236 reinterpret_cast<dcmi::GetPowerReadingResponse*>(response);
Marri Devender Rao9c966e02018-01-22 05:55:10 -06001237
1238 if (requestData->groupID != dcmi::groupExtId)
1239 {
1240 *data_len = 0;
1241 return IPMI_CC_INVALID_FIELD_REQUEST;
1242 }
1243
Marri Devender Rao66c5fda2018-01-18 10:48:37 -06001244 sdbusplus::bus::bus bus{ipmid_get_sd_bus_connection()};
Marri Devender Rao9c966e02018-01-22 05:55:10 -06001245 int64_t power = 0;
Marri Devender Rao66c5fda2018-01-18 10:48:37 -06001246 try
1247 {
Marri Devender Rao9c966e02018-01-22 05:55:10 -06001248 power = getPowerReading(bus);
Marri Devender Rao66c5fda2018-01-18 10:48:37 -06001249 }
1250 catch (InternalFailure& e)
1251 {
1252 log<level::ERR>("Error in reading power sensor value",
1253 entry("INTERFACE=%s", SENSOR_VALUE_INTF),
1254 entry("PROPERTY=%s", SENSOR_VALUE_PROP));
1255 return IPMI_CC_UNSPECIFIED_ERROR;
1256 }
Marri Devender Rao9c966e02018-01-22 05:55:10 -06001257 responseData->groupID = dcmi::groupExtId;
1258
1259 // TODO: openbmc/openbmc#2819
Gunnar Mills8466b792018-03-23 12:18:12 -05001260 // Minimum, Maximum, Average power, TimeFrame, TimeStamp,
Marri Devender Rao9c966e02018-01-22 05:55:10 -06001261 // PowerReadingState readings need to be populated
1262 // after Telemetry changes.
1263 uint16_t totalPower = static_cast<uint16_t>(power);
1264 responseData->currentPower = totalPower;
1265 responseData->minimumPower = totalPower;
1266 responseData->maximumPower = totalPower;
1267 responseData->averagePower = totalPower;
1268
1269 *data_len = sizeof(*responseData);
Marri Devender Rao66c5fda2018-01-18 10:48:37 -06001270 return rc;
1271}
1272
Deepak Kodihalli0b459552018-02-06 06:25:12 -06001273namespace dcmi
1274{
1275namespace sensor_info
1276{
1277
Deepak Kodihallidd4cff12018-02-06 06:48:29 -06001278Response createFromJson(const Json& config)
1279{
1280 Response response{};
1281 uint16_t recordId = config.value("record_id", 0);
1282 response.recordIdLsb = recordId & 0xFF;
1283 response.recordIdMsb = (recordId >> 8) & 0xFF;
1284 return response;
1285}
1286
Deepak Kodihalli0b459552018-02-06 06:25:12 -06001287std::tuple<Response, NumInstances> read(const std::string& type,
Patrick Venture0b02be92018-08-31 11:55:55 -07001288 uint8_t instance, const Json& config)
Deepak Kodihalli0b459552018-02-06 06:25:12 -06001289{
Deepak Kodihallidd4cff12018-02-06 06:48:29 -06001290 Response response{};
1291
1292 if (!instance)
1293 {
1294 log<level::ERR>("Expected non-zero instance");
1295 elog<InternalFailure>();
1296 }
1297
1298 static const std::vector<Json> empty{};
1299 std::vector<Json> readings = config.value(type, empty);
1300 size_t numInstances = readings.size();
1301 for (const auto& reading : readings)
1302 {
1303 uint8_t instanceNum = reading.value("instance", 0);
1304 // Not the instance we're interested in
1305 if (instanceNum != instance)
1306 {
1307 continue;
1308 }
1309
1310 response = createFromJson(reading);
1311
1312 // Found the instance we're interested in
1313 break;
1314 }
1315
1316 if (numInstances > maxInstances)
1317 {
1318 log<level::DEBUG>("Trimming IPMI num instances",
1319 entry("NUM_INSTANCES=%d", numInstances));
1320 numInstances = maxInstances;
1321 }
1322 return std::make_tuple(response, numInstances);
Deepak Kodihalli0b459552018-02-06 06:25:12 -06001323}
1324
Patrick Venture0b02be92018-08-31 11:55:55 -07001325std::tuple<ResponseList, NumInstances>
1326 readAll(const std::string& type, uint8_t instanceStart, const Json& config)
Deepak Kodihalli0b459552018-02-06 06:25:12 -06001327{
Deepak Kodihallidd4cff12018-02-06 06:48:29 -06001328 ResponseList responses{};
1329
1330 size_t numInstances = 0;
1331 static const std::vector<Json> empty{};
1332 std::vector<Json> readings = config.value(type, empty);
1333 numInstances = readings.size();
1334 for (const auto& reading : readings)
1335 {
1336 try
1337 {
1338 // Max of 8 records
1339 if (responses.size() == maxRecords)
1340 {
1341 break;
1342 }
1343
1344 uint8_t instanceNum = reading.value("instance", 0);
1345 // Not in the instance range we're interested in
1346 if (instanceNum < instanceStart)
1347 {
1348 continue;
1349 }
1350
1351 Response response = createFromJson(reading);
1352 responses.push_back(response);
1353 }
1354 catch (std::exception& e)
1355 {
1356 log<level::DEBUG>(e.what());
1357 continue;
1358 }
1359 }
1360
1361 if (numInstances > maxInstances)
1362 {
1363 log<level::DEBUG>("Trimming IPMI num instances",
1364 entry("NUM_INSTANCES=%d", numInstances));
1365 numInstances = maxInstances;
1366 }
1367 return std::make_tuple(responses, numInstances);
Deepak Kodihalli0b459552018-02-06 06:25:12 -06001368}
1369
1370} // namespace sensor_info
1371} // namespace dcmi
1372
1373ipmi_ret_t getSensorInfo(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
1374 ipmi_request_t request, ipmi_response_t response,
1375 ipmi_data_len_t data_len, ipmi_context_t context)
1376{
1377 auto requestData =
1378 reinterpret_cast<const dcmi::GetSensorInfoRequest*>(request);
1379 auto responseData =
1380 reinterpret_cast<dcmi::GetSensorInfoResponseHdr*>(response);
1381
1382 if (*data_len != sizeof(dcmi::GetSensorInfoRequest))
1383 {
1384 log<level::ERR>("Malformed request data",
1385 entry("DATA_SIZE=%d", *data_len));
1386 return IPMI_CC_REQ_DATA_LEN_INVALID;
1387 }
1388 *data_len = 0;
1389
1390 auto it = dcmi::entityIdToName.find(requestData->entityId);
1391 if (it == dcmi::entityIdToName.end())
1392 {
1393 log<level::ERR>("Unknown Entity ID",
1394 entry("ENTITY_ID=%d", requestData->entityId));
1395 return IPMI_CC_INVALID_FIELD_REQUEST;
1396 }
1397
1398 if (requestData->groupID != dcmi::groupExtId)
1399 {
1400 log<level::ERR>("Invalid Group ID",
1401 entry("GROUP_ID=%d", requestData->groupID));
1402 return IPMI_CC_INVALID_FIELD_REQUEST;
1403 }
1404
1405 if (requestData->sensorType != dcmi::temperatureSensorType)
1406 {
1407 log<level::ERR>("Invalid sensor type",
1408 entry("SENSOR_TYPE=%d", requestData->sensorType));
1409 return IPMI_CC_INVALID_FIELD_REQUEST;
1410 }
1411
1412 dcmi::sensor_info::ResponseList sensors{};
1413 static dcmi::Json config{};
1414 static bool parsed = false;
1415
1416 try
1417 {
1418 if (!parsed)
1419 {
1420 config = dcmi::parseSensorConfig();
1421 parsed = true;
1422 }
1423
1424 if (!requestData->entityInstance)
1425 {
1426 // Read all instances
1427 std::tie(sensors, responseData->numInstances) =
1428 dcmi::sensor_info::readAll(it->second,
Patrick Venture0b02be92018-08-31 11:55:55 -07001429 requestData->instanceStart, config);
Deepak Kodihalli0b459552018-02-06 06:25:12 -06001430 }
1431 else
1432 {
1433 // Read one instance
1434 sensors.resize(1);
1435 std::tie(sensors[0], responseData->numInstances) =
Patrick Venture0b02be92018-08-31 11:55:55 -07001436 dcmi::sensor_info::read(it->second, requestData->entityInstance,
Deepak Kodihalli0b459552018-02-06 06:25:12 -06001437 config);
1438 }
1439 responseData->numRecords = sensors.size();
1440 }
1441 catch (InternalFailure& e)
1442 {
1443 return IPMI_CC_UNSPECIFIED_ERROR;
1444 }
1445
1446 responseData->groupID = dcmi::groupExtId;
1447 size_t payloadSize = sensors.size() * sizeof(dcmi::sensor_info::Response);
1448 if (!sensors.empty())
1449 {
1450 memcpy(responseData + 1, // copy payload right after the response header
Patrick Venture0b02be92018-08-31 11:55:55 -07001451 sensors.data(), payloadSize);
Deepak Kodihalli0b459552018-02-06 06:25:12 -06001452 }
1453 *data_len = sizeof(dcmi::GetSensorInfoResponseHdr) + payloadSize;
1454
1455 return IPMI_CC_OK;
1456}
1457
Chris Austen1810bec2015-10-13 12:12:39 -05001458void register_netfn_dcmi_functions()
1459{
Tom05732372016-09-06 17:21:23 +05301460 // <Get Power Limit>
Ratan Gupta11ddbd22017-08-05 11:59:39 +05301461
Patrick Venture0b02be92018-08-31 11:55:55 -07001462 ipmi_register_callback(NETFUN_GRPEXT, dcmi::Commands::GET_POWER_LIMIT, NULL,
1463 getPowerLimit, PRIVILEGE_USER);
Tom Joseph6f6dd4d2017-07-12 20:07:11 +05301464
Tom Joseph46fa37d2017-07-26 18:11:55 +05301465 // <Set Power Limit>
Ratan Gupta11ddbd22017-08-05 11:59:39 +05301466
Patrick Venture0b02be92018-08-31 11:55:55 -07001467 ipmi_register_callback(NETFUN_GRPEXT, dcmi::Commands::SET_POWER_LIMIT, NULL,
1468 setPowerLimit, PRIVILEGE_OPERATOR);
Tom Joseph46fa37d2017-07-26 18:11:55 +05301469
Tom Joseph6c8d51b2017-07-26 18:18:06 +05301470 // <Activate/Deactivate Power Limit>
Ratan Gupta11ddbd22017-08-05 11:59:39 +05301471
1472 ipmi_register_callback(NETFUN_GRPEXT, dcmi::Commands::APPLY_POWER_LIMIT,
1473 NULL, applyPowerLimit, PRIVILEGE_OPERATOR);
Tom Joseph6c8d51b2017-07-26 18:18:06 +05301474
Tom Joseph6f6dd4d2017-07-12 20:07:11 +05301475 // <Get Asset Tag>
Ratan Gupta11ddbd22017-08-05 11:59:39 +05301476
Patrick Venture0b02be92018-08-31 11:55:55 -07001477 ipmi_register_callback(NETFUN_GRPEXT, dcmi::Commands::GET_ASSET_TAG, NULL,
1478 getAssetTag, PRIVILEGE_USER);
Tom Joseph545dd232017-07-12 20:20:49 +05301479
1480 // <Set Asset Tag>
Ratan Gupta11ddbd22017-08-05 11:59:39 +05301481
Patrick Venture0b02be92018-08-31 11:55:55 -07001482 ipmi_register_callback(NETFUN_GRPEXT, dcmi::Commands::SET_ASSET_TAG, NULL,
1483 setAssetTag, PRIVILEGE_OPERATOR);
Vladislav Vovchenko8f7a6f62017-08-17 00:31:14 +03001484
Gunnar Mills8991dd62017-10-25 17:11:29 -05001485 // <Get Management Controller Identifier String>
Vladislav Vovchenko8f7a6f62017-08-17 00:31:14 +03001486
1487 ipmi_register_callback(NETFUN_GRPEXT, dcmi::Commands::GET_MGMNT_CTRL_ID_STR,
Patrick Venture0b02be92018-08-31 11:55:55 -07001488 NULL, getMgmntCtrlIdStr, PRIVILEGE_USER);
Vladislav Vovchenko8f7a6f62017-08-17 00:31:14 +03001489
1490 // <Set Management Controller Identifier String>
Vladislav Vovchenko8f7a6f62017-08-17 00:31:14 +03001491 ipmi_register_callback(NETFUN_GRPEXT, dcmi::Commands::SET_MGMNT_CTRL_ID_STR,
Patrick Venture0b02be92018-08-31 11:55:55 -07001492 NULL, setMgmntCtrlIdStr, PRIVILEGE_ADMIN);
Vladislav Vovchenko8f7a6f62017-08-17 00:31:14 +03001493
Dhruvaraj Subhashchandrane29be412018-01-16 05:11:56 -06001494 // <Get DCMI capabilities>
1495 ipmi_register_callback(NETFUN_GRPEXT, dcmi::Commands::GET_CAPABILITIES,
Patrick Venture0b02be92018-08-31 11:55:55 -07001496 NULL, getDCMICapabilities, PRIVILEGE_USER);
Deepak Kodihalliee717d72018-01-24 04:53:09 -06001497
1498 // <Get Temperature Readings>
1499 ipmi_register_callback(NETFUN_GRPEXT, dcmi::Commands::GET_TEMP_READINGS,
1500 NULL, getTempReadings, PRIVILEGE_USER);
1501
Marri Devender Rao66c5fda2018-01-18 10:48:37 -06001502 // <Get Power Reading>
1503 ipmi_register_callback(NETFUN_GRPEXT, dcmi::Commands::GET_POWER_READING,
1504 NULL, getPowerReading, PRIVILEGE_USER);
Deepak Kodihalli0b459552018-02-06 06:25:12 -06001505
1506 // <Get Sensor Info>
Patrick Venture0b02be92018-08-31 11:55:55 -07001507 ipmi_register_callback(NETFUN_GRPEXT, dcmi::Commands::GET_SENSOR_INFO, NULL,
1508 getSensorInfo, PRIVILEGE_USER);
Deepak Kodihalli0b459552018-02-06 06:25:12 -06001509
Nagaraju Goruganti22be97b2018-02-07 01:19:59 -06001510 // <Get DCMI Configuration Parameters>
Patrick Venture0b02be92018-08-31 11:55:55 -07001511 ipmi_register_callback(NETFUN_GRPEXT, dcmi::Commands::GET_CONF_PARAMS, NULL,
1512 getDCMIConfParams, PRIVILEGE_USER);
Nagaraju Goruganti22be97b2018-02-07 01:19:59 -06001513
1514 // <Set DCMI Configuration Parameters>
Patrick Venture0b02be92018-08-31 11:55:55 -07001515 ipmi_register_callback(NETFUN_GRPEXT, dcmi::Commands::SET_CONF_PARAMS, NULL,
1516 setDCMIConfParams, PRIVILEGE_ADMIN);
Nagaraju Goruganti22be97b2018-02-07 01:19:59 -06001517
Chris Austen1810bec2015-10-13 12:12:39 -05001518 return;
1519}
Tom05732372016-09-06 17:21:23 +05301520// 956379