blob: d01787ed3ec72293796a2dbccf4af0e503ec4708 [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
10#include <bitset>
11#include <cmath>
12#include <fstream>
13#include <nlohmann/json.hpp>
Tom Josephbe5eaa12017-07-12 19:54:44 +053014#include <phosphor-logging/elog-errors.hpp>
Andrew Geissler50c0c8f2017-07-11 16:18:51 -050015#include <phosphor-logging/log.hpp>
16#include <sdbusplus/bus.hpp>
Patrick Venture0b02be92018-08-31 11:55:55 -070017#include <xyz/openbmc_project/Common/error.hpp>
18
Tom Josephbe5eaa12017-07-12 19:54:44 +053019using namespace phosphor::logging;
20using InternalFailure =
Patrick Venture0b02be92018-08-31 11:55:55 -070021 sdbusplus::xyz::openbmc_project::Common::Error::InternalFailure;
Chris Austen1810bec2015-10-13 12:12:39 -050022
23void register_netfn_dcmi_functions() __attribute__((constructor));
24
Patrick Venture0b02be92018-08-31 11:55:55 -070025constexpr auto PCAP_PATH = "/xyz/openbmc_project/control/host0/power_cap";
Andrew Geissler50c0c8f2017-07-11 16:18:51 -050026constexpr auto PCAP_INTERFACE = "xyz.openbmc_project.Control.Power.Cap";
27
28constexpr auto POWER_CAP_PROP = "PowerCap";
29constexpr auto POWER_CAP_ENABLE_PROP = "PowerCapEnable";
30
Dhruvaraj Subhashchandrane29be412018-01-16 05:11:56 -060031constexpr auto DCMI_PARAMETER_REVISION = 2;
32constexpr auto DCMI_SPEC_MAJOR_VERSION = 1;
33constexpr auto DCMI_SPEC_MINOR_VERSION = 5;
Nagaraju Goruganti22be97b2018-02-07 01:19:59 -060034constexpr auto DCMI_CONFIG_PARAMETER_REVISION = 1;
35constexpr auto DCMI_RAND_BACK_OFF_MASK = 0x80;
36constexpr auto DCMI_OPTION_60_43_MASK = 0x02;
37constexpr auto DCMI_OPTION_12_MASK = 0x01;
38constexpr auto DCMI_ACTIVATE_DHCP_MASK = 0x01;
39constexpr auto DCMI_ACTIVATE_DHCP_REPLY = 0x00;
40constexpr auto DCMI_SET_CONF_PARAM_REQ_PACKET_MAX_SIZE = 0x05;
41constexpr auto DCMI_SET_CONF_PARAM_REQ_PACKET_MIN_SIZE = 0x04;
Patrick Venture0b02be92018-08-31 11:55:55 -070042constexpr auto DHCP_TIMING1 = 0x04; // 4 sec
43constexpr auto DHCP_TIMING2_UPPER = 0x00; // 2 min
Nagaraju Goruganti22be97b2018-02-07 01:19:59 -060044constexpr auto DHCP_TIMING2_LOWER = 0x78;
Patrick Venture0b02be92018-08-31 11:55:55 -070045constexpr auto DHCP_TIMING3_UPPER = 0x00; // 64 sec
Nagaraju Goruganti22be97b2018-02-07 01:19:59 -060046constexpr auto DHCP_TIMING3_LOWER = 0x40;
47// When DHCP Option 12 is enabled the string "SendHostName=true" will be
48// added into n/w configuration file and the parameter
49// SendHostNameEnabled will set to true.
50constexpr auto DHCP_OPT12_ENABLED = "SendHostNameEnabled";
51
Dhruvaraj Subhashchandrane29be412018-01-16 05:11:56 -060052constexpr auto DCMI_CAP_JSON_FILE = "/usr/share/ipmi-providers/dcmi_cap.json";
53
Marri Devender Rao66c5fda2018-01-18 10:48:37 -060054constexpr auto SENSOR_VALUE_INTF = "xyz.openbmc_project.Sensor.Value";
55constexpr auto SENSOR_VALUE_PROP = "Value";
56constexpr auto SENSOR_SCALE_PROP = "Scale";
57
Andrew Geissler50c0c8f2017-07-11 16:18:51 -050058using namespace phosphor::logging;
59
Tom Josephb9d86f42017-07-26 18:03:47 +053060namespace dcmi
61{
62
Deepak Kodihalli0b459552018-02-06 06:25:12 -060063// Refer Table 6-14, DCMI Entity ID Extension, DCMI v1.5 spec
Patrick Venture0b02be92018-08-31 11:55:55 -070064static const std::map<uint8_t, std::string> entityIdToName{
65 {0x40, "inlet"}, {0x37, "inlet"}, {0x41, "cpu"},
66 {0x03, "cpu"}, {0x42, "baseboard"}, {0x07, "baseboard"}};
Deepak Kodihalli0b459552018-02-06 06:25:12 -060067
Andrew Geissler50c0c8f2017-07-11 16:18:51 -050068uint32_t getPcap(sdbusplus::bus::bus& bus)
69{
Patrick Venture0b02be92018-08-31 11:55:55 -070070 auto settingService = ipmi::getService(bus, PCAP_INTERFACE, PCAP_PATH);
Andrew Geissler50c0c8f2017-07-11 16:18:51 -050071
Patrick Venture0b02be92018-08-31 11:55:55 -070072 auto method = bus.new_method_call(settingService.c_str(), PCAP_PATH,
73 "org.freedesktop.DBus.Properties", "Get");
Andrew Geissler50c0c8f2017-07-11 16:18:51 -050074
75 method.append(PCAP_INTERFACE, POWER_CAP_PROP);
76 auto reply = bus.call(method);
77
78 if (reply.is_method_error())
79 {
80 log<level::ERR>("Error in getPcap prop");
Tom Josephb9d86f42017-07-26 18:03:47 +053081 elog<InternalFailure>();
Andrew Geissler50c0c8f2017-07-11 16:18:51 -050082 }
83 sdbusplus::message::variant<uint32_t> pcap;
84 reply.read(pcap);
85
Tom Josephb9d86f42017-07-26 18:03:47 +053086 return pcap.get<uint32_t>();
Andrew Geissler50c0c8f2017-07-11 16:18:51 -050087}
88
89bool getPcapEnabled(sdbusplus::bus::bus& bus)
90{
Patrick Venture0b02be92018-08-31 11:55:55 -070091 auto settingService = ipmi::getService(bus, PCAP_INTERFACE, PCAP_PATH);
Andrew Geissler50c0c8f2017-07-11 16:18:51 -050092
Patrick Venture0b02be92018-08-31 11:55:55 -070093 auto method = bus.new_method_call(settingService.c_str(), PCAP_PATH,
94 "org.freedesktop.DBus.Properties", "Get");
Andrew Geissler50c0c8f2017-07-11 16:18:51 -050095
96 method.append(PCAP_INTERFACE, POWER_CAP_ENABLE_PROP);
97 auto reply = bus.call(method);
98
99 if (reply.is_method_error())
100 {
101 log<level::ERR>("Error in getPcapEnabled prop");
Tom Josephb9d86f42017-07-26 18:03:47 +0530102 elog<InternalFailure>();
Andrew Geissler50c0c8f2017-07-11 16:18:51 -0500103 }
104 sdbusplus::message::variant<bool> pcapEnabled;
105 reply.read(pcapEnabled);
106
Tom Josephb9d86f42017-07-26 18:03:47 +0530107 return pcapEnabled.get<bool>();
Andrew Geissler50c0c8f2017-07-11 16:18:51 -0500108}
Chris Austen1810bec2015-10-13 12:12:39 -0500109
Tom Joseph46fa37d2017-07-26 18:11:55 +0530110void setPcap(sdbusplus::bus::bus& bus, const uint32_t powerCap)
111{
112 auto service = ipmi::getService(bus, PCAP_INTERFACE, PCAP_PATH);
113
Patrick Venture0b02be92018-08-31 11:55:55 -0700114 auto method = bus.new_method_call(service.c_str(), PCAP_PATH,
115 "org.freedesktop.DBus.Properties", "Set");
Tom Joseph46fa37d2017-07-26 18:11:55 +0530116
117 method.append(PCAP_INTERFACE, POWER_CAP_PROP);
118 method.append(sdbusplus::message::variant<uint32_t>(powerCap));
119
120 auto reply = bus.call(method);
121
122 if (reply.is_method_error())
123 {
124 log<level::ERR>("Error in setPcap property");
125 elog<InternalFailure>();
126 }
127}
128
Tom Joseph6c8d51b2017-07-26 18:18:06 +0530129void setPcapEnable(sdbusplus::bus::bus& bus, bool enabled)
130{
131 auto service = ipmi::getService(bus, PCAP_INTERFACE, PCAP_PATH);
132
Patrick Venture0b02be92018-08-31 11:55:55 -0700133 auto method = bus.new_method_call(service.c_str(), PCAP_PATH,
134 "org.freedesktop.DBus.Properties", "Set");
Tom Joseph6c8d51b2017-07-26 18:18:06 +0530135
136 method.append(PCAP_INTERFACE, POWER_CAP_ENABLE_PROP);
137 method.append(sdbusplus::message::variant<bool>(enabled));
138
139 auto reply = bus.call(method);
140
141 if (reply.is_method_error())
142 {
143 log<level::ERR>("Error in setPcapEnabled property");
144 elog<InternalFailure>();
145 }
146}
147
Tom Josephbe5eaa12017-07-12 19:54:44 +0530148void readAssetTagObjectTree(dcmi::assettag::ObjectTree& objectTree)
149{
150 static constexpr auto mapperBusName = "xyz.openbmc_project.ObjectMapper";
151 static constexpr auto mapperObjPath = "/xyz/openbmc_project/object_mapper";
152 static constexpr auto mapperIface = "xyz.openbmc_project.ObjectMapper";
153 static constexpr auto inventoryRoot = "/xyz/openbmc_project/inventory/";
154
155 sdbusplus::bus::bus bus{ipmid_get_sd_bus_connection()};
156 auto depth = 0;
157
Patrick Venture0b02be92018-08-31 11:55:55 -0700158 auto mapperCall = bus.new_method_call(mapperBusName, mapperObjPath,
159 mapperIface, "GetSubTree");
Tom Josephbe5eaa12017-07-12 19:54:44 +0530160
161 mapperCall.append(inventoryRoot);
162 mapperCall.append(depth);
163 mapperCall.append(std::vector<std::string>({dcmi::assetTagIntf}));
164
165 auto mapperReply = bus.call(mapperCall);
166 if (mapperReply.is_method_error())
167 {
168 log<level::ERR>("Error in mapper call");
169 elog<InternalFailure>();
170 }
171
172 mapperReply.read(objectTree);
173
174 if (objectTree.empty())
175 {
176 log<level::ERR>("AssetTag property is not populated");
177 elog<InternalFailure>();
178 }
179}
180
181std::string readAssetTag()
182{
183 sdbusplus::bus::bus bus{ipmid_get_sd_bus_connection()};
184 dcmi::assettag::ObjectTree objectTree;
185
186 // Read the object tree with the inventory root to figure out the object
187 // that has implemented the Asset tag interface.
188 readAssetTagObjectTree(objectTree);
189
190 auto method = bus.new_method_call(
Patrick Venture0b02be92018-08-31 11:55:55 -0700191 (objectTree.begin()->second.begin()->first).c_str(),
192 (objectTree.begin()->first).c_str(), dcmi::propIntf, "Get");
Tom Josephbe5eaa12017-07-12 19:54:44 +0530193 method.append(dcmi::assetTagIntf);
194 method.append(dcmi::assetTagProp);
195
196 auto reply = bus.call(method);
197 if (reply.is_method_error())
198 {
199 log<level::ERR>("Error in reading asset tag");
200 elog<InternalFailure>();
201 }
202
203 sdbusplus::message::variant<std::string> assetTag;
204 reply.read(assetTag);
205
206 return assetTag.get<std::string>();
207}
208
Tom Josephbe5b9892017-07-15 00:55:23 +0530209void writeAssetTag(const std::string& assetTag)
210{
211 sdbusplus::bus::bus bus{ipmid_get_sd_bus_connection()};
212 dcmi::assettag::ObjectTree objectTree;
213
214 // Read the object tree with the inventory root to figure out the object
215 // that has implemented the Asset tag interface.
216 readAssetTagObjectTree(objectTree);
217
218 auto method = bus.new_method_call(
Patrick Venture0b02be92018-08-31 11:55:55 -0700219 (objectTree.begin()->second.begin()->first).c_str(),
220 (objectTree.begin()->first).c_str(), dcmi::propIntf, "Set");
Tom Josephbe5b9892017-07-15 00:55:23 +0530221 method.append(dcmi::assetTagIntf);
222 method.append(dcmi::assetTagProp);
223 method.append(sdbusplus::message::variant<std::string>(assetTag));
224
225 auto reply = bus.call(method);
226 if (reply.is_method_error())
227 {
228 log<level::ERR>("Error in writing asset tag");
229 elog<InternalFailure>();
230 }
231}
232
Vladislav Vovchenko8f7a6f62017-08-17 00:31:14 +0300233std::string getHostName(void)
234{
Patrick Venture0b02be92018-08-31 11:55:55 -0700235 sdbusplus::bus::bus bus{ipmid_get_sd_bus_connection()};
Vladislav Vovchenko8f7a6f62017-08-17 00:31:14 +0300236
237 auto service = ipmi::getService(bus, networkConfigIntf, networkConfigObj);
Patrick Venture0b02be92018-08-31 11:55:55 -0700238 auto value = ipmi::getDbusProperty(bus, service, networkConfigObj,
239 networkConfigIntf, hostNameProp);
Vladislav Vovchenko8f7a6f62017-08-17 00:31:14 +0300240
241 return value.get<std::string>();
242}
243
Nagaraju Goruganti22be97b2018-02-07 01:19:59 -0600244bool getDHCPEnabled()
245{
246 sdbusplus::bus::bus bus{ipmid_get_sd_bus_connection()};
247
Patrick Venture0b02be92018-08-31 11:55:55 -0700248 auto ethdevice =
249 ipmi::network::ChanneltoEthernet(ethernetDefaultChannelNum);
250 auto ethernetObj =
251 ipmi::getDbusObject(bus, ethernetIntf, networkRoot, ethdevice);
Nagaraju Goruganti22be97b2018-02-07 01:19:59 -0600252 auto service = ipmi::getService(bus, ethernetIntf, ethernetObj.first);
Patrick Venture0b02be92018-08-31 11:55:55 -0700253 auto value = ipmi::getDbusProperty(bus, service, ethernetObj.first,
254 ethernetIntf, "DHCPEnabled");
Nagaraju Goruganti22be97b2018-02-07 01:19:59 -0600255
256 return value.get<bool>();
257}
258
259bool getDHCPOption(std::string prop)
260{
261 sdbusplus::bus::bus bus{ipmid_get_sd_bus_connection()};
262
263 auto service = ipmi::getService(bus, dhcpIntf, dhcpObj);
264 auto value = ipmi::getDbusProperty(bus, service, dhcpObj, dhcpIntf, prop);
265
266 return value.get<bool>();
267}
268
Nagaraju Goruganti22be97b2018-02-07 01:19:59 -0600269void setDHCPOption(std::string prop, bool value)
270{
271 sdbusplus::bus::bus bus{ipmid_get_sd_bus_connection()};
272
273 auto service = ipmi::getService(bus, dhcpIntf, dhcpObj);
274 ipmi::setDbusProperty(bus, service, dhcpObj, dhcpIntf, prop, value);
275}
276
Deepak Kodihalli0b459552018-02-06 06:25:12 -0600277Json parseSensorConfig()
278{
279 std::ifstream jsonFile(configFile);
280 if (!jsonFile.is_open())
281 {
282 log<level::ERR>("Temperature readings JSON file not found");
283 elog<InternalFailure>();
284 }
285
286 auto data = Json::parse(jsonFile, nullptr, false);
287 if (data.is_discarded())
288 {
289 log<level::ERR>("Temperature readings JSON parser failure");
290 elog<InternalFailure>();
291 }
292
293 return data;
294}
295
Tom Josephbe5eaa12017-07-12 19:54:44 +0530296} // namespace dcmi
Chris Austen1810bec2015-10-13 12:12:39 -0500297
Tom Josephb9d86f42017-07-26 18:03:47 +0530298ipmi_ret_t getPowerLimit(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
299 ipmi_request_t request, ipmi_response_t response,
300 ipmi_data_len_t data_len, ipmi_context_t context)
301{
Patrick Venture0b02be92018-08-31 11:55:55 -0700302 auto requestData =
303 reinterpret_cast<const dcmi::GetPowerLimitRequest*>(request);
Tom Josephb9d86f42017-07-26 18:03:47 +0530304 std::vector<uint8_t> outPayload(sizeof(dcmi::GetPowerLimitResponse));
Patrick Venture0b02be92018-08-31 11:55:55 -0700305 auto responseData =
306 reinterpret_cast<dcmi::GetPowerLimitResponse*>(outPayload.data());
Tom Josephb9d86f42017-07-26 18:03:47 +0530307
308 if (requestData->groupID != dcmi::groupExtId)
309 {
310 *data_len = 0;
311 return IPMI_CC_INVALID_FIELD_REQUEST;
312 }
313
Patrick Venture0b02be92018-08-31 11:55:55 -0700314 sdbusplus::bus::bus sdbus{ipmid_get_sd_bus_connection()};
Tom Josephb9d86f42017-07-26 18:03:47 +0530315 uint32_t pcapValue = 0;
316 bool pcapEnable = false;
317
318 try
319 {
320 pcapValue = dcmi::getPcap(sdbus);
321 pcapEnable = dcmi::getPcapEnabled(sdbus);
322 }
323 catch (InternalFailure& e)
324 {
325 *data_len = 0;
326 return IPMI_CC_UNSPECIFIED_ERROR;
327 }
328
329 responseData->groupID = dcmi::groupExtId;
330
331 /*
332 * Exception action if power limit is exceeded and cannot be controlled
333 * with the correction time limit is hardcoded to Hard Power Off system
334 * and log event to SEL.
335 */
336 constexpr auto exception = 0x01;
337 responseData->exceptionAction = exception;
338
339 responseData->powerLimit = static_cast<uint16_t>(pcapValue);
340
341 /*
342 * Correction time limit and Statistics sampling period is currently not
343 * populated.
344 */
345
346 *data_len = outPayload.size();
347 memcpy(response, outPayload.data(), *data_len);
348
349 if (pcapEnable)
350 {
351 return IPMI_CC_OK;
352 }
353 else
354 {
355 return IPMI_DCMI_CC_NO_ACTIVE_POWER_LIMIT;
356 }
357}
358
Tom Joseph46fa37d2017-07-26 18:11:55 +0530359ipmi_ret_t setPowerLimit(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
360 ipmi_request_t request, ipmi_response_t response,
361 ipmi_data_len_t data_len, ipmi_context_t context)
362{
Patrick Venture0b02be92018-08-31 11:55:55 -0700363 auto requestData =
364 reinterpret_cast<const dcmi::SetPowerLimitRequest*>(request);
Tom Joseph46fa37d2017-07-26 18:11:55 +0530365 std::vector<uint8_t> outPayload(sizeof(dcmi::SetPowerLimitResponse));
Patrick Venture0b02be92018-08-31 11:55:55 -0700366 auto responseData =
367 reinterpret_cast<dcmi::SetPowerLimitResponse*>(outPayload.data());
Tom Joseph46fa37d2017-07-26 18:11:55 +0530368
369 if (requestData->groupID != dcmi::groupExtId)
370 {
371 *data_len = 0;
372 return IPMI_CC_INVALID_FIELD_REQUEST;
373 }
374
Patrick Venture0b02be92018-08-31 11:55:55 -0700375 sdbusplus::bus::bus sdbus{ipmid_get_sd_bus_connection()};
Tom Joseph46fa37d2017-07-26 18:11:55 +0530376
377 // Only process the power limit requested in watts.
378 try
379 {
380 dcmi::setPcap(sdbus, requestData->powerLimit);
381 }
382 catch (InternalFailure& e)
383 {
384 *data_len = 0;
385 return IPMI_CC_UNSPECIFIED_ERROR;
386 }
387
388 log<level::INFO>("Set Power Cap",
389 entry("POWERCAP=%u", requestData->powerLimit));
390
391 responseData->groupID = dcmi::groupExtId;
392 memcpy(response, outPayload.data(), outPayload.size());
393 *data_len = outPayload.size();
394
395 return IPMI_CC_OK;
396}
397
Tom Joseph6c8d51b2017-07-26 18:18:06 +0530398ipmi_ret_t applyPowerLimit(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
399 ipmi_request_t request, ipmi_response_t response,
400 ipmi_data_len_t data_len, ipmi_context_t context)
401{
Patrick Venture0b02be92018-08-31 11:55:55 -0700402 auto requestData =
403 reinterpret_cast<const dcmi::ApplyPowerLimitRequest*>(request);
Tom Joseph6c8d51b2017-07-26 18:18:06 +0530404 std::vector<uint8_t> outPayload(sizeof(dcmi::ApplyPowerLimitResponse));
Patrick Venture0b02be92018-08-31 11:55:55 -0700405 auto responseData =
406 reinterpret_cast<dcmi::ApplyPowerLimitResponse*>(outPayload.data());
Tom Joseph6c8d51b2017-07-26 18:18:06 +0530407
408 if (requestData->groupID != dcmi::groupExtId)
409 {
410 *data_len = 0;
411 return IPMI_CC_INVALID_FIELD_REQUEST;
412 }
413
Patrick Venture0b02be92018-08-31 11:55:55 -0700414 sdbusplus::bus::bus sdbus{ipmid_get_sd_bus_connection()};
Tom Joseph6c8d51b2017-07-26 18:18:06 +0530415
416 try
417 {
418 dcmi::setPcapEnable(sdbus,
419 static_cast<bool>(requestData->powerLimitAction));
420 }
421 catch (InternalFailure& e)
422 {
423 *data_len = 0;
424 return IPMI_CC_UNSPECIFIED_ERROR;
425 }
426
427 log<level::INFO>("Set Power Cap Enable",
428 entry("POWERCAPENABLE=%u", requestData->powerLimitAction));
429
430 responseData->groupID = dcmi::groupExtId;
431 memcpy(response, outPayload.data(), outPayload.size());
432 *data_len = outPayload.size();
433
434 return IPMI_CC_OK;
435}
436
Tom Joseph6f6dd4d2017-07-12 20:07:11 +0530437ipmi_ret_t getAssetTag(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
438 ipmi_request_t request, ipmi_response_t response,
439 ipmi_data_len_t data_len, ipmi_context_t context)
440{
Patrick Venture0b02be92018-08-31 11:55:55 -0700441 auto requestData =
442 reinterpret_cast<const dcmi::GetAssetTagRequest*>(request);
Tom Joseph6f6dd4d2017-07-12 20:07:11 +0530443 std::vector<uint8_t> outPayload(sizeof(dcmi::GetAssetTagResponse));
Patrick Venture0b02be92018-08-31 11:55:55 -0700444 auto responseData =
445 reinterpret_cast<dcmi::GetAssetTagResponse*>(outPayload.data());
Tom Joseph6f6dd4d2017-07-12 20:07:11 +0530446
447 if (requestData->groupID != dcmi::groupExtId)
448 {
449 *data_len = 0;
450 return IPMI_CC_INVALID_FIELD_REQUEST;
451 }
452
453 // Verify offset to read and number of bytes to read are not exceeding the
454 // range.
455 if ((requestData->offset > dcmi::assetTagMaxOffset) ||
456 (requestData->bytes > dcmi::maxBytes) ||
457 ((requestData->offset + requestData->bytes) > dcmi::assetTagMaxSize))
458 {
459 *data_len = 0;
460 return IPMI_CC_PARM_OUT_OF_RANGE;
461 }
462
463 std::string assetTag;
464
465 try
466 {
467 assetTag = dcmi::readAssetTag();
468 }
469 catch (InternalFailure& e)
470 {
471 *data_len = 0;
472 return IPMI_CC_UNSPECIFIED_ERROR;
473 }
474
475 responseData->groupID = dcmi::groupExtId;
476
477 // Return if the asset tag is not populated.
478 if (!assetTag.size())
479 {
480 responseData->tagLength = 0;
481 memcpy(response, outPayload.data(), outPayload.size());
482 *data_len = outPayload.size();
483 return IPMI_CC_OK;
484 }
485
486 // If the asset tag is longer than 63 bytes, restrict it to 63 bytes to suit
487 // Get Asset Tag command.
488 if (assetTag.size() > dcmi::assetTagMaxSize)
489 {
490 assetTag.resize(dcmi::assetTagMaxSize);
491 }
492
493 // If the requested offset is beyond the asset tag size.
494 if (requestData->offset >= assetTag.size())
495 {
496 *data_len = 0;
497 return IPMI_CC_PARM_OUT_OF_RANGE;
498 }
499
500 auto returnData = assetTag.substr(requestData->offset, requestData->bytes);
501
502 responseData->tagLength = assetTag.size();
503
504 memcpy(response, outPayload.data(), outPayload.size());
505 memcpy(static_cast<uint8_t*>(response) + outPayload.size(),
506 returnData.data(), returnData.size());
507 *data_len = outPayload.size() + returnData.size();
508
509 return IPMI_CC_OK;
510}
511
Tom Joseph545dd232017-07-12 20:20:49 +0530512ipmi_ret_t setAssetTag(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
513 ipmi_request_t request, ipmi_response_t response,
514 ipmi_data_len_t data_len, ipmi_context_t context)
515{
Patrick Venture0b02be92018-08-31 11:55:55 -0700516 auto requestData =
517 reinterpret_cast<const dcmi::SetAssetTagRequest*>(request);
Tom Joseph545dd232017-07-12 20:20:49 +0530518 std::vector<uint8_t> outPayload(sizeof(dcmi::SetAssetTagResponse));
Patrick Venture0b02be92018-08-31 11:55:55 -0700519 auto responseData =
520 reinterpret_cast<dcmi::SetAssetTagResponse*>(outPayload.data());
Tom Joseph545dd232017-07-12 20:20:49 +0530521
522 if (requestData->groupID != dcmi::groupExtId)
523 {
524 *data_len = 0;
525 return IPMI_CC_INVALID_FIELD_REQUEST;
526 }
527
528 // Verify offset to read and number of bytes to read are not exceeding the
529 // range.
530 if ((requestData->offset > dcmi::assetTagMaxOffset) ||
531 (requestData->bytes > dcmi::maxBytes) ||
532 ((requestData->offset + requestData->bytes) > dcmi::assetTagMaxSize))
533 {
534 *data_len = 0;
535 return IPMI_CC_PARM_OUT_OF_RANGE;
536 }
537
538 std::string assetTag;
539
540 try
541 {
542 assetTag = dcmi::readAssetTag();
543
544 if (requestData->offset > assetTag.size())
545 {
546 *data_len = 0;
547 return IPMI_CC_PARM_OUT_OF_RANGE;
548 }
549
550 assetTag.replace(requestData->offset,
551 assetTag.size() - requestData->offset,
552 static_cast<const char*>(request) +
Patrick Venture0b02be92018-08-31 11:55:55 -0700553 sizeof(dcmi::SetAssetTagRequest),
Tom Joseph545dd232017-07-12 20:20:49 +0530554 requestData->bytes);
555
556 dcmi::writeAssetTag(assetTag);
557
558 responseData->groupID = dcmi::groupExtId;
559 responseData->tagLength = assetTag.size();
560 memcpy(response, outPayload.data(), outPayload.size());
561 *data_len = outPayload.size();
562
563 return IPMI_CC_OK;
564 }
565 catch (InternalFailure& e)
566 {
567 *data_len = 0;
568 return IPMI_CC_UNSPECIFIED_ERROR;
569 }
570}
571
Vladislav Vovchenko8f7a6f62017-08-17 00:31:14 +0300572ipmi_ret_t getMgmntCtrlIdStr(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
Patrick Venture0b02be92018-08-31 11:55:55 -0700573 ipmi_request_t request, ipmi_response_t response,
574 ipmi_data_len_t data_len, ipmi_context_t context)
Vladislav Vovchenko8f7a6f62017-08-17 00:31:14 +0300575{
Patrick Venture0b02be92018-08-31 11:55:55 -0700576 auto requestData =
577 reinterpret_cast<const dcmi::GetMgmntCtrlIdStrRequest*>(request);
578 auto responseData =
579 reinterpret_cast<dcmi::GetMgmntCtrlIdStrResponse*>(response);
Vladislav Vovchenko8f7a6f62017-08-17 00:31:14 +0300580 std::string hostName;
581
582 *data_len = 0;
583
584 if (requestData->groupID != dcmi::groupExtId ||
585 requestData->bytes > dcmi::maxBytes ||
586 requestData->offset + requestData->bytes > dcmi::maxCtrlIdStrLen)
587 {
588 return IPMI_CC_INVALID_FIELD_REQUEST;
589 }
590
591 try
592 {
593 hostName = dcmi::getHostName();
594 }
595 catch (InternalFailure& e)
596 {
597 return IPMI_CC_UNSPECIFIED_ERROR;
598 }
599
600 if (requestData->offset > hostName.length())
601 {
602 return IPMI_CC_PARM_OUT_OF_RANGE;
603 }
604 auto responseStr = hostName.substr(requestData->offset, requestData->bytes);
605 auto responseStrLen = std::min(static_cast<std::size_t>(requestData->bytes),
Patrick Venture0b02be92018-08-31 11:55:55 -0700606 responseStr.length() + 1);
Vladislav Vovchenko8f7a6f62017-08-17 00:31:14 +0300607 responseData->groupID = dcmi::groupExtId;
608 responseData->strLen = hostName.length();
609 std::copy(begin(responseStr), end(responseStr), responseData->data);
610
611 *data_len = sizeof(*responseData) + responseStrLen;
612 return IPMI_CC_OK;
613}
614
615ipmi_ret_t setMgmntCtrlIdStr(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
Patrick Venture0b02be92018-08-31 11:55:55 -0700616 ipmi_request_t request, ipmi_response_t response,
617 ipmi_data_len_t data_len, ipmi_context_t context)
Vladislav Vovchenko8f7a6f62017-08-17 00:31:14 +0300618{
619 static std::array<char, dcmi::maxCtrlIdStrLen + 1> newCtrlIdStr;
620
Patrick Venture0b02be92018-08-31 11:55:55 -0700621 auto requestData =
622 reinterpret_cast<const dcmi::SetMgmntCtrlIdStrRequest*>(request);
623 auto responseData =
624 reinterpret_cast<dcmi::SetMgmntCtrlIdStrResponse*>(response);
Vladislav Vovchenko8f7a6f62017-08-17 00:31:14 +0300625
626 *data_len = 0;
627
628 if (requestData->groupID != dcmi::groupExtId ||
629 requestData->bytes > dcmi::maxBytes ||
630 requestData->offset + requestData->bytes > dcmi::maxCtrlIdStrLen + 1 ||
Patrick Venture0b02be92018-08-31 11:55:55 -0700631 (requestData->offset + requestData->bytes ==
632 dcmi::maxCtrlIdStrLen + 1 &&
633 requestData->data[requestData->bytes - 1] != '\0'))
Vladislav Vovchenko8f7a6f62017-08-17 00:31:14 +0300634 {
635 return IPMI_CC_INVALID_FIELD_REQUEST;
636 }
637
638 try
639 {
640 /* if there is no old value and offset is not 0 */
641 if (newCtrlIdStr[0] == '\0' && requestData->offset != 0)
642 {
643 /* read old ctrlIdStr */
644 auto hostName = dcmi::getHostName();
645 hostName.resize(dcmi::maxCtrlIdStrLen);
646 std::copy(begin(hostName), end(hostName), begin(newCtrlIdStr));
647 newCtrlIdStr[hostName.length()] = '\0';
648 }
649
650 /* replace part of string and mark byte after the last as \0 */
Patrick Venture0b02be92018-08-31 11:55:55 -0700651 auto restStrIter =
652 std::copy_n(requestData->data, requestData->bytes,
653 begin(newCtrlIdStr) + requestData->offset);
Vladislav Vovchenko8f7a6f62017-08-17 00:31:14 +0300654 /* if the last written byte is not 64th - add '\0' */
655 if (requestData->offset + requestData->bytes <= dcmi::maxCtrlIdStrLen)
656 {
657 *restStrIter = '\0';
658 }
659
660 /* if input data contains '\0' whole string is sent - update hostname */
661 auto it = std::find(requestData->data,
Patrick Venture0b02be92018-08-31 11:55:55 -0700662 requestData->data + requestData->bytes, '\0');
Vladislav Vovchenko8f7a6f62017-08-17 00:31:14 +0300663 if (it != requestData->data + requestData->bytes)
664 {
Patrick Venture0b02be92018-08-31 11:55:55 -0700665 sdbusplus::bus::bus bus{ipmid_get_sd_bus_connection()};
Vladislav Vovchenko8f7a6f62017-08-17 00:31:14 +0300666 ipmi::setDbusProperty(bus, dcmi::networkServiceName,
Patrick Venture0b02be92018-08-31 11:55:55 -0700667 dcmi::networkConfigObj,
668 dcmi::networkConfigIntf, dcmi::hostNameProp,
669 std::string(newCtrlIdStr.data()));
Vladislav Vovchenko8f7a6f62017-08-17 00:31:14 +0300670 }
671 }
672 catch (InternalFailure& e)
673 {
674 *data_len = 0;
675 return IPMI_CC_UNSPECIFIED_ERROR;
676 }
677
678 responseData->groupID = dcmi::groupExtId;
679 responseData->offset = requestData->offset + requestData->bytes;
680 *data_len = sizeof(*responseData);
681 return IPMI_CC_OK;
682}
683
Patrick Venture0b02be92018-08-31 11:55:55 -0700684// List of the capabilities under each parameter
685dcmi::DCMICaps dcmiCaps = {
686 // Supported DCMI Capabilities
687 {dcmi::DCMICapParameters::SUPPORTED_DCMI_CAPS,
688 {3,
689 {{"PowerManagement", 2, 0, 1},
690 {"OOBSecondaryLan", 3, 2, 1},
691 {"SerialTMODE", 3, 1, 1},
692 {"InBandSystemInterfaceChannel", 3, 0, 1}}}},
693 // Mandatory Platform Attributes
694 {dcmi::DCMICapParameters::MANDATORY_PLAT_ATTRIBUTES,
695 {5,
696 {{"SELAutoRollOver", 1, 15, 1},
697 {"FlushEntireSELUponRollOver", 1, 14, 1},
698 {"RecordLevelSELFlushUponRollOver", 1, 13, 1},
699 {"NumberOfSELEntries", 1, 0, 12},
700 {"TempMonitoringSamplingFreq", 5, 0, 8}}}},
701 // Optional Platform Attributes
702 {dcmi::DCMICapParameters::OPTIONAL_PLAT_ATTRIBUTES,
703 {2,
704 {{"PowerMgmtDeviceSlaveAddress", 1, 1, 7},
705 {"BMCChannelNumber", 2, 4, 4},
706 {"DeviceRivision", 2, 0, 4}}}},
707 // Manageability Access Attributes
708 {dcmi::DCMICapParameters::MANAGEABILITY_ACCESS_ATTRIBUTES,
709 {3,
710 {{"MandatoryPrimaryLanOOBSupport", 1, 0, 8},
711 {"OptionalSecondaryLanOOBSupport", 2, 0, 8},
712 {"OptionalSerialOOBMTMODECapability", 3, 0, 8}}}}};
Dhruvaraj Subhashchandrane29be412018-01-16 05:11:56 -0600713
714ipmi_ret_t getDCMICapabilities(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
715 ipmi_request_t request, ipmi_response_t response,
716 ipmi_data_len_t data_len, ipmi_context_t context)
717{
718
719 std::ifstream dcmiCapFile(DCMI_CAP_JSON_FILE);
720 if (!dcmiCapFile.is_open())
721 {
722 log<level::ERR>("DCMI Capabilities file not found");
723 return IPMI_CC_UNSPECIFIED_ERROR;
724 }
725
726 auto data = nlohmann::json::parse(dcmiCapFile, nullptr, false);
727 if (data.is_discarded())
728 {
729 log<level::ERR>("DCMI Capabilities JSON parser failure");
730 return IPMI_CC_UNSPECIFIED_ERROR;
731 }
732
Patrick Venture0b02be92018-08-31 11:55:55 -0700733 auto requestData =
734 reinterpret_cast<const dcmi::GetDCMICapRequest*>(request);
Dhruvaraj Subhashchandrane29be412018-01-16 05:11:56 -0600735
Patrick Venture0b02be92018-08-31 11:55:55 -0700736 // get list of capabilities in a parameter
Dhruvaraj Subhashchandrane29be412018-01-16 05:11:56 -0600737 auto caps =
738 dcmiCaps.find(static_cast<dcmi::DCMICapParameters>(requestData->param));
739 if (caps == dcmiCaps.end())
740 {
741 log<level::ERR>("Invalid input parameter");
742 return IPMI_CC_INVALID_FIELD_REQUEST;
743 }
744
745 if (requestData->groupID != dcmi::groupExtId)
746 {
747 *data_len = 0;
748 return IPMI_CC_INVALID_FIELD_REQUEST;
749 }
750
Patrick Venture0b02be92018-08-31 11:55:55 -0700751 auto responseData = reinterpret_cast<dcmi::GetDCMICapResponse*>(response);
Dhruvaraj Subhashchandrane29be412018-01-16 05:11:56 -0600752
Patrick Venture0b02be92018-08-31 11:55:55 -0700753 // For each capabilities in a parameter fill the data from
754 // the json file based on the capability name.
Dhruvaraj Subhashchandrane29be412018-01-16 05:11:56 -0600755 for (auto cap : caps->second.capList)
756 {
Patrick Venture0b02be92018-08-31 11:55:55 -0700757 // If the data is beyond first byte boundary, insert in a
758 // 16bit pattern for example number of SEL entries are represented
759 // in 12bits.
Dhruvaraj Subhashchandrane29be412018-01-16 05:11:56 -0600760 if ((cap.length + cap.position) > 8)
761 {
Patrick Venture0b02be92018-08-31 11:55:55 -0700762 // Read the value corresponding to capability name and assign to
763 // 16bit bitset.
Dhruvaraj Subhashchandrane29be412018-01-16 05:11:56 -0600764 std::bitset<16> val(data.value(cap.name.c_str(), 0));
765 val <<= cap.position;
Patrick Venture0b02be92018-08-31 11:55:55 -0700766 reinterpret_cast<uint16_t*>(
767 responseData
768 ->data)[(cap.bytePosition - 1) / sizeof(uint16_t)] |=
769 val.to_ulong();
Dhruvaraj Subhashchandrane29be412018-01-16 05:11:56 -0600770 }
771 else
772 {
773 responseData->data[cap.bytePosition - 1] |=
774 data.value(cap.name.c_str(), 0) << cap.position;
775 }
776 }
777
778 responseData->groupID = dcmi::groupExtId;
779 responseData->major = DCMI_SPEC_MAJOR_VERSION;
780 responseData->minor = DCMI_SPEC_MINOR_VERSION;
781 responseData->paramRevision = DCMI_PARAMETER_REVISION;
782 *data_len = sizeof(*responseData) + caps->second.size;
783
784 return IPMI_CC_OK;
785}
786
Deepak Kodihalliee717d72018-01-24 04:53:09 -0600787namespace dcmi
788{
789namespace temp_readings
790{
791
Deepak Kodihallib1e8fba2018-01-24 04:57:10 -0600792Temperature readTemp(const std::string& dbusService,
793 const std::string& dbusPath)
794{
795 // Read the temperature value from d-bus object. Need some conversion.
796 // As per the interface xyz.openbmc_project.Sensor.Value, the temperature
797 // is an int64_t and in degrees C. It needs to be scaled by using the
798 // formula Value * 10^Scale. The ipmi spec has the temperature as a uint8_t,
799 // with a separate single bit for the sign.
800
801 sdbusplus::bus::bus bus{ipmid_get_sd_bus_connection()};
Patrick Venture0b02be92018-08-31 11:55:55 -0700802 auto result = ipmi::getAllDbusProperties(
803 bus, dbusService, dbusPath, "xyz.openbmc_project.Sensor.Value");
Deepak Kodihallib1e8fba2018-01-24 04:57:10 -0600804 auto temperature = result.at("Value").get<int64_t>();
805 uint64_t absTemp = std::abs(temperature);
806
807 auto factor = result.at("Scale").get<int64_t>();
808 uint64_t scale = std::pow(10, factor); // pow() returns float/double
809 unsigned long long tempDegrees = 0;
810 // Overflow safe multiplication when the scale is > 0
Patrick Venture0b02be92018-08-31 11:55:55 -0700811 if (scale && __builtin_umulll_overflow(absTemp, scale, &tempDegrees))
Deepak Kodihallib1e8fba2018-01-24 04:57:10 -0600812 {
813 log<level::ERR>("Multiplication overflow detected",
814 entry("TEMP_VALUE=%llu", absTemp),
815 entry("SCALE_FACTOR=%llu", scale));
816 elog<InternalFailure>();
817 }
818 else
819 {
820 // The (uint64_t)scale value is 0, effectively this is division
821 tempDegrees = absTemp * std::pow(10, factor);
822 }
823 // Max absolute temp as per ipmi spec is 128.
824 if (tempDegrees > maxTemp)
825 {
826 tempDegrees = maxTemp;
827 }
828
829 return std::make_tuple(static_cast<uint8_t>(tempDegrees),
830 (temperature < 0));
831}
832
Deepak Kodihalliee717d72018-01-24 04:53:09 -0600833std::tuple<Response, NumInstances> read(const std::string& type,
834 uint8_t instance)
835{
Deepak Kodihallib1e8fba2018-01-24 04:57:10 -0600836 Response response{};
837 sdbusplus::bus::bus bus{ipmid_get_sd_bus_connection()};
838
839 if (!instance)
840 {
841 log<level::ERR>("Expected non-zero instance");
842 elog<InternalFailure>();
843 }
844
Deepak Kodihalli0b459552018-02-06 06:25:12 -0600845 auto data = parseSensorConfig();
Deepak Kodihallib1e8fba2018-01-24 04:57:10 -0600846 static const std::vector<Json> empty{};
847 std::vector<Json> readings = data.value(type, empty);
848 size_t numInstances = readings.size();
849 for (const auto& j : readings)
850 {
851 uint8_t instanceNum = j.value("instance", 0);
852 // Not the instance we're interested in
853 if (instanceNum != instance)
854 {
855 continue;
856 }
857
858 std::string path = j.value("dbus", "");
859 std::string service;
860 try
861 {
862 service =
Patrick Venture0b02be92018-08-31 11:55:55 -0700863 ipmi::getService(bus, "xyz.openbmc_project.Sensor.Value", path);
Deepak Kodihallib1e8fba2018-01-24 04:57:10 -0600864 }
865 catch (std::exception& e)
866 {
867 log<level::DEBUG>(e.what());
868 return std::make_tuple(response, numInstances);
869 }
870
871 response.instance = instance;
872 uint8_t temp{};
873 bool sign{};
874 std::tie(temp, sign) = readTemp(service, path);
875 response.temperature = temp;
876 response.sign = sign;
877
878 // Found the instance we're interested in
879 break;
880 }
881
882 if (numInstances > maxInstances)
883 {
884 numInstances = maxInstances;
885 }
886 return std::make_tuple(response, numInstances);
Deepak Kodihalliee717d72018-01-24 04:53:09 -0600887}
888
889std::tuple<ResponseList, NumInstances> readAll(const std::string& type,
890 uint8_t instanceStart)
891{
Deepak Kodihallib1e8fba2018-01-24 04:57:10 -0600892 ResponseList response{};
893 sdbusplus::bus::bus bus{ipmid_get_sd_bus_connection()};
894
895 size_t numInstances = 0;
Deepak Kodihalli0b459552018-02-06 06:25:12 -0600896 auto data = parseSensorConfig();
Deepak Kodihallib1e8fba2018-01-24 04:57:10 -0600897 static const std::vector<Json> empty{};
898 std::vector<Json> readings = data.value(type, empty);
899 numInstances = readings.size();
900 for (const auto& j : readings)
901 {
902 try
903 {
904 // Max of 8 response data sets
905 if (response.size() == maxDataSets)
906 {
907 break;
908 }
909
910 uint8_t instanceNum = j.value("instance", 0);
911 // Not in the instance range we're interested in
912 if (instanceNum < instanceStart)
913 {
914 continue;
915 }
916
917 std::string path = j.value("dbus", "");
918 auto service =
Patrick Venture0b02be92018-08-31 11:55:55 -0700919 ipmi::getService(bus, "xyz.openbmc_project.Sensor.Value", path);
Deepak Kodihallib1e8fba2018-01-24 04:57:10 -0600920
921 Response r{};
922 r.instance = instanceNum;
923 uint8_t temp{};
924 bool sign{};
925 std::tie(temp, sign) = readTemp(service, path);
926 r.temperature = temp;
927 r.sign = sign;
928 response.push_back(r);
929 }
930 catch (std::exception& e)
931 {
932 log<level::DEBUG>(e.what());
933 continue;
934 }
935 }
936
937 if (numInstances > maxInstances)
938 {
939 numInstances = maxInstances;
940 }
941 return std::make_tuple(response, numInstances);
Deepak Kodihalliee717d72018-01-24 04:53:09 -0600942}
943
Patrick Venture0b02be92018-08-31 11:55:55 -0700944} // namespace temp_readings
945} // namespace dcmi
Deepak Kodihalliee717d72018-01-24 04:53:09 -0600946
947ipmi_ret_t getTempReadings(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
Patrick Venture0b02be92018-08-31 11:55:55 -0700948 ipmi_request_t request, ipmi_response_t response,
949 ipmi_data_len_t data_len, ipmi_context_t context)
Deepak Kodihalliee717d72018-01-24 04:53:09 -0600950{
Deepak Kodihalliee717d72018-01-24 04:53:09 -0600951 auto requestData =
952 reinterpret_cast<const dcmi::GetTempReadingsRequest*>(request);
953 auto responseData =
954 reinterpret_cast<dcmi::GetTempReadingsResponseHdr*>(response);
955
956 if (*data_len != sizeof(dcmi::GetTempReadingsRequest))
957 {
958 log<level::ERR>("Malformed request data",
959 entry("DATA_SIZE=%d", *data_len));
960 return IPMI_CC_REQ_DATA_LEN_INVALID;
961 }
962 *data_len = 0;
963
Deepak Kodihalli0b459552018-02-06 06:25:12 -0600964 auto it = dcmi::entityIdToName.find(requestData->entityId);
965 if (it == dcmi::entityIdToName.end())
Deepak Kodihalliee717d72018-01-24 04:53:09 -0600966 {
967 log<level::ERR>("Unknown Entity ID",
968 entry("ENTITY_ID=%d", requestData->entityId));
969 return IPMI_CC_INVALID_FIELD_REQUEST;
970 }
971
972 if (requestData->groupID != dcmi::groupExtId)
973 {
974 log<level::ERR>("Invalid Group ID",
975 entry("GROUP_ID=%d", requestData->groupID));
976 return IPMI_CC_INVALID_FIELD_REQUEST;
977 }
978
979 if (requestData->sensorType != dcmi::temperatureSensorType)
980 {
981 log<level::ERR>("Invalid sensor type",
982 entry("SENSOR_TYPE=%d", requestData->sensorType));
983 return IPMI_CC_INVALID_FIELD_REQUEST;
984 }
985
986 dcmi::temp_readings::ResponseList temps{};
987 try
988 {
989 if (!requestData->entityInstance)
990 {
991 // Read all instances
992 std::tie(temps, responseData->numInstances) =
993 dcmi::temp_readings::readAll(it->second,
994 requestData->instanceStart);
995 }
996 else
997 {
998 // Read one instance
999 temps.resize(1);
1000 std::tie(temps[0], responseData->numInstances) =
1001 dcmi::temp_readings::read(it->second,
1002 requestData->entityInstance);
1003 }
1004 responseData->numDataSets = temps.size();
1005 }
1006 catch (InternalFailure& e)
1007 {
1008 return IPMI_CC_UNSPECIFIED_ERROR;
1009 }
1010
1011 responseData->groupID = dcmi::groupExtId;
Patrick Venture0b02be92018-08-31 11:55:55 -07001012 size_t payloadSize = temps.size() * sizeof(dcmi::temp_readings::Response);
Deepak Kodihalliee717d72018-01-24 04:53:09 -06001013 if (!temps.empty())
1014 {
1015 memcpy(responseData + 1, // copy payload right after the response header
Patrick Venture0b02be92018-08-31 11:55:55 -07001016 temps.data(), payloadSize);
Deepak Kodihalliee717d72018-01-24 04:53:09 -06001017 }
1018 *data_len = sizeof(dcmi::GetTempReadingsResponseHdr) + payloadSize;
1019
1020 return IPMI_CC_OK;
1021}
1022
Marri Devender Rao66c5fda2018-01-18 10:48:37 -06001023int64_t getPowerReading(sdbusplus::bus::bus& bus)
1024{
1025 std::ifstream sensorFile(POWER_READING_SENSOR);
1026 std::string objectPath;
1027 if (!sensorFile.is_open())
1028 {
1029 log<level::ERR>("Power reading configuration file not found",
Patrick Venture0b02be92018-08-31 11:55:55 -07001030 entry("POWER_SENSOR_FILE=%s", POWER_READING_SENSOR));
Marri Devender Rao66c5fda2018-01-18 10:48:37 -06001031 elog<InternalFailure>();
1032 }
1033
1034 auto data = nlohmann::json::parse(sensorFile, nullptr, false);
1035 if (data.is_discarded())
1036 {
1037 log<level::ERR>("Error in parsing configuration file",
Patrick Venture0b02be92018-08-31 11:55:55 -07001038 entry("POWER_SENSOR_FILE=%s", POWER_READING_SENSOR));
Marri Devender Rao66c5fda2018-01-18 10:48:37 -06001039 elog<InternalFailure>();
1040 }
1041
1042 objectPath = data.value("path", "");
1043 if (objectPath.empty())
1044 {
1045 log<level::ERR>("Power sensor D-Bus object path is empty",
1046 entry("POWER_SENSOR_FILE=%s", POWER_READING_SENSOR));
1047 elog<InternalFailure>();
1048 }
1049
Marri Devender Raoce6a7952018-02-11 08:45:00 -06001050 // Return default value if failed to read from D-Bus object
1051 int64_t power = 0;
1052 try
1053 {
1054 auto service = ipmi::getService(bus, SENSOR_VALUE_INTF, objectPath);
Marri Devender Rao66c5fda2018-01-18 10:48:37 -06001055
Patrick Venture0b02be92018-08-31 11:55:55 -07001056 // Read the sensor value and scale properties
1057 auto properties = ipmi::getAllDbusProperties(bus, service, objectPath,
1058 SENSOR_VALUE_INTF);
Marri Devender Raoce6a7952018-02-11 08:45:00 -06001059 auto value = properties[SENSOR_VALUE_PROP].get<int64_t>();
1060 auto scale = properties[SENSOR_SCALE_PROP].get<int64_t>();
Marri Devender Rao66c5fda2018-01-18 10:48:37 -06001061
Marri Devender Raoce6a7952018-02-11 08:45:00 -06001062 // Power reading needs to be scaled with the Scale value using the
1063 // formula Value * 10^Scale.
1064 power = value * std::pow(10, scale);
1065 }
1066 catch (std::exception& e)
1067 {
1068 log<level::INFO>("Failure to read power value from D-Bus object",
Patrick Venture0b02be92018-08-31 11:55:55 -07001069 entry("OBJECT_PATH=%s", objectPath.c_str()),
1070 entry("INTERFACE=%s", SENSOR_VALUE_INTF));
Marri Devender Raoce6a7952018-02-11 08:45:00 -06001071 }
Marri Devender Rao66c5fda2018-01-18 10:48:37 -06001072 return power;
1073}
1074
Nagaraju Goruganti22be97b2018-02-07 01:19:59 -06001075ipmi_ret_t setDCMIConfParams(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
1076 ipmi_request_t request, ipmi_response_t response,
1077 ipmi_data_len_t data_len, ipmi_context_t context)
1078{
Patrick Venture0b02be92018-08-31 11:55:55 -07001079 auto requestData =
1080 reinterpret_cast<const dcmi::SetConfParamsRequest*>(request);
1081 auto responseData =
1082 reinterpret_cast<dcmi::SetConfParamsResponse*>(response);
Nagaraju Goruganti22be97b2018-02-07 01:19:59 -06001083
Patrick Venture0b02be92018-08-31 11:55:55 -07001084 if (requestData->groupID != dcmi::groupExtId ||
1085 *data_len < DCMI_SET_CONF_PARAM_REQ_PACKET_MIN_SIZE ||
1086 *data_len > DCMI_SET_CONF_PARAM_REQ_PACKET_MAX_SIZE)
Nagaraju Goruganti22be97b2018-02-07 01:19:59 -06001087 {
Gunnar Mills8466b792018-03-23 12:18:12 -05001088 log<level::ERR>("Invalid Group ID or Invalid Requested Packet size",
Nagaraju Goruganti22be97b2018-02-07 01:19:59 -06001089 entry("GROUP_ID=%d", requestData->groupID),
1090 entry("PACKET SIZE=%d", *data_len));
1091 return IPMI_CC_INVALID_FIELD_REQUEST;
1092 }
1093
1094 *data_len = 0;
1095
1096 try
1097 {
1098 // Take action based on the Parameter Selector
Patrick Venture0b02be92018-08-31 11:55:55 -07001099 switch (
1100 static_cast<dcmi::DCMIConfigParameters>(requestData->paramSelect))
Nagaraju Goruganti22be97b2018-02-07 01:19:59 -06001101 {
1102 case dcmi::DCMIConfigParameters::ActivateDHCP:
1103
1104 if ((requestData->data[0] & DCMI_ACTIVATE_DHCP_MASK) &&
Patrick Venture0b02be92018-08-31 11:55:55 -07001105 dcmi::getDHCPEnabled())
Nagaraju Goruganti22be97b2018-02-07 01:19:59 -06001106 {
Patrick Venture0b02be92018-08-31 11:55:55 -07001107 // When these conditions are met we have to trigger DHCP
1108 // protocol restart using the latest parameter settings, but
1109 // as per n/w manager design, each time when we update n/w
1110 // parameters, n/w service is restarted. So we no need to
1111 // take any action in this case.
Nagaraju Goruganti22be97b2018-02-07 01:19:59 -06001112 }
1113 break;
1114
1115 case dcmi::DCMIConfigParameters::DiscoveryConfig:
1116
1117 if (requestData->data[0] & DCMI_OPTION_12_MASK)
1118 {
1119 dcmi::setDHCPOption(DHCP_OPT12_ENABLED, true);
1120 }
1121 else
1122 {
1123 dcmi::setDHCPOption(DHCP_OPT12_ENABLED, false);
1124 }
1125
1126 // Systemd-networkd doesn't support Random Back off
1127 if (requestData->data[0] & DCMI_RAND_BACK_OFF_MASK)
1128 {
1129 return IPMI_CC_INVALID;
1130 }
1131 break;
1132 // Systemd-networkd doesn't allow to configure DHCP timigs
1133 case dcmi::DCMIConfigParameters::DHCPTiming1:
1134 case dcmi::DCMIConfigParameters::DHCPTiming2:
1135 case dcmi::DCMIConfigParameters::DHCPTiming3:
1136 default:
1137 return IPMI_CC_INVALID;
1138 }
1139 }
1140 catch (std::exception& e)
1141 {
1142 log<level::ERR>(e.what());
1143 return IPMI_CC_UNSPECIFIED_ERROR;
1144 }
1145 responseData->groupID = dcmi::groupExtId;
1146 *data_len = sizeof(dcmi::SetConfParamsResponse);
1147
1148 return IPMI_CC_OK;
1149}
1150
1151ipmi_ret_t getDCMIConfParams(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
1152 ipmi_request_t request, ipmi_response_t response,
1153 ipmi_data_len_t data_len, ipmi_context_t context)
1154{
1155
Patrick Venture0b02be92018-08-31 11:55:55 -07001156 auto requestData =
1157 reinterpret_cast<const dcmi::GetConfParamsRequest*>(request);
1158 auto responseData =
1159 reinterpret_cast<dcmi::GetConfParamsResponse*>(response);
Nagaraju Goruganti22be97b2018-02-07 01:19:59 -06001160
1161 responseData->data[0] = 0x00;
1162
Patrick Venture0b02be92018-08-31 11:55:55 -07001163 if (requestData->groupID != dcmi::groupExtId ||
1164 *data_len != sizeof(dcmi::GetConfParamsRequest))
Nagaraju Goruganti22be97b2018-02-07 01:19:59 -06001165 {
Gunnar Mills8466b792018-03-23 12:18:12 -05001166 log<level::ERR>("Invalid Group ID or Invalid Requested Packet size",
Nagaraju Goruganti22be97b2018-02-07 01:19:59 -06001167 entry("GROUP_ID=%d", requestData->groupID),
1168 entry("PACKET SIZE=%d", *data_len));
1169 return IPMI_CC_INVALID_FIELD_REQUEST;
1170 }
1171
1172 *data_len = 0;
1173
1174 try
1175 {
1176 // Take action based on the Parameter Selector
Patrick Venture0b02be92018-08-31 11:55:55 -07001177 switch (
1178 static_cast<dcmi::DCMIConfigParameters>(requestData->paramSelect))
Nagaraju Goruganti22be97b2018-02-07 01:19:59 -06001179 {
1180 case dcmi::DCMIConfigParameters::ActivateDHCP:
1181 responseData->data[0] = DCMI_ACTIVATE_DHCP_REPLY;
1182 *data_len = sizeof(dcmi::GetConfParamsResponse) + 1;
1183 break;
1184 case dcmi::DCMIConfigParameters::DiscoveryConfig:
1185 if (dcmi::getDHCPOption(DHCP_OPT12_ENABLED))
1186 {
1187 responseData->data[0] |= DCMI_OPTION_12_MASK;
1188 }
1189 *data_len = sizeof(dcmi::GetConfParamsResponse) + 1;
1190 break;
1191 // Get below values from Systemd-networkd source code
1192 case dcmi::DCMIConfigParameters::DHCPTiming1:
1193 responseData->data[0] = DHCP_TIMING1;
1194 *data_len = sizeof(dcmi::GetConfParamsResponse) + 1;
1195 break;
1196 case dcmi::DCMIConfigParameters::DHCPTiming2:
1197 responseData->data[0] = DHCP_TIMING2_LOWER;
1198 responseData->data[1] = DHCP_TIMING2_UPPER;
1199 *data_len = sizeof(dcmi::GetConfParamsResponse) + 2;
1200 break;
1201 case dcmi::DCMIConfigParameters::DHCPTiming3:
1202 responseData->data[0] = DHCP_TIMING3_LOWER;
1203 responseData->data[1] = DHCP_TIMING3_UPPER;
1204 *data_len = sizeof(dcmi::GetConfParamsResponse) + 2;
1205 break;
1206 default:
1207 *data_len = 0;
1208 return IPMI_CC_INVALID;
1209 }
1210 }
1211 catch (std::exception& e)
1212 {
1213 log<level::ERR>(e.what());
1214 return IPMI_CC_UNSPECIFIED_ERROR;
1215 }
1216
1217 responseData->groupID = dcmi::groupExtId;
1218 responseData->major = DCMI_SPEC_MAJOR_VERSION;
1219 responseData->minor = DCMI_SPEC_MINOR_VERSION;
1220 responseData->paramRevision = DCMI_CONFIG_PARAMETER_REVISION;
1221
1222 return IPMI_CC_OK;
1223}
1224
Marri Devender Rao66c5fda2018-01-18 10:48:37 -06001225ipmi_ret_t getPowerReading(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
Patrick Venture0b02be92018-08-31 11:55:55 -07001226 ipmi_request_t request, ipmi_response_t response,
1227 ipmi_data_len_t data_len, ipmi_context_t context)
Marri Devender Rao66c5fda2018-01-18 10:48:37 -06001228{
1229 ipmi_ret_t rc = IPMI_CC_OK;
Patrick Venture0b02be92018-08-31 11:55:55 -07001230 auto requestData =
1231 reinterpret_cast<const dcmi::GetPowerReadingRequest*>(request);
1232 auto responseData =
1233 reinterpret_cast<dcmi::GetPowerReadingResponse*>(response);
Marri Devender Rao9c966e02018-01-22 05:55:10 -06001234
1235 if (requestData->groupID != dcmi::groupExtId)
1236 {
1237 *data_len = 0;
1238 return IPMI_CC_INVALID_FIELD_REQUEST;
1239 }
1240
Marri Devender Rao66c5fda2018-01-18 10:48:37 -06001241 sdbusplus::bus::bus bus{ipmid_get_sd_bus_connection()};
Marri Devender Rao9c966e02018-01-22 05:55:10 -06001242 int64_t power = 0;
Marri Devender Rao66c5fda2018-01-18 10:48:37 -06001243 try
1244 {
Marri Devender Rao9c966e02018-01-22 05:55:10 -06001245 power = getPowerReading(bus);
Marri Devender Rao66c5fda2018-01-18 10:48:37 -06001246 }
1247 catch (InternalFailure& e)
1248 {
1249 log<level::ERR>("Error in reading power sensor value",
1250 entry("INTERFACE=%s", SENSOR_VALUE_INTF),
1251 entry("PROPERTY=%s", SENSOR_VALUE_PROP));
1252 return IPMI_CC_UNSPECIFIED_ERROR;
1253 }
Marri Devender Rao9c966e02018-01-22 05:55:10 -06001254 responseData->groupID = dcmi::groupExtId;
1255
1256 // TODO: openbmc/openbmc#2819
Gunnar Mills8466b792018-03-23 12:18:12 -05001257 // Minimum, Maximum, Average power, TimeFrame, TimeStamp,
Marri Devender Rao9c966e02018-01-22 05:55:10 -06001258 // PowerReadingState readings need to be populated
1259 // after Telemetry changes.
1260 uint16_t totalPower = static_cast<uint16_t>(power);
1261 responseData->currentPower = totalPower;
1262 responseData->minimumPower = totalPower;
1263 responseData->maximumPower = totalPower;
1264 responseData->averagePower = totalPower;
1265
1266 *data_len = sizeof(*responseData);
Marri Devender Rao66c5fda2018-01-18 10:48:37 -06001267 return rc;
1268}
1269
Deepak Kodihalli0b459552018-02-06 06:25:12 -06001270namespace dcmi
1271{
1272namespace sensor_info
1273{
1274
Deepak Kodihallidd4cff12018-02-06 06:48:29 -06001275Response createFromJson(const Json& config)
1276{
1277 Response response{};
1278 uint16_t recordId = config.value("record_id", 0);
1279 response.recordIdLsb = recordId & 0xFF;
1280 response.recordIdMsb = (recordId >> 8) & 0xFF;
1281 return response;
1282}
1283
Deepak Kodihalli0b459552018-02-06 06:25:12 -06001284std::tuple<Response, NumInstances> read(const std::string& type,
Patrick Venture0b02be92018-08-31 11:55:55 -07001285 uint8_t instance, const Json& config)
Deepak Kodihalli0b459552018-02-06 06:25:12 -06001286{
Deepak Kodihallidd4cff12018-02-06 06:48:29 -06001287 Response response{};
1288
1289 if (!instance)
1290 {
1291 log<level::ERR>("Expected non-zero instance");
1292 elog<InternalFailure>();
1293 }
1294
1295 static const std::vector<Json> empty{};
1296 std::vector<Json> readings = config.value(type, empty);
1297 size_t numInstances = readings.size();
1298 for (const auto& reading : readings)
1299 {
1300 uint8_t instanceNum = reading.value("instance", 0);
1301 // Not the instance we're interested in
1302 if (instanceNum != instance)
1303 {
1304 continue;
1305 }
1306
1307 response = createFromJson(reading);
1308
1309 // Found the instance we're interested in
1310 break;
1311 }
1312
1313 if (numInstances > maxInstances)
1314 {
1315 log<level::DEBUG>("Trimming IPMI num instances",
1316 entry("NUM_INSTANCES=%d", numInstances));
1317 numInstances = maxInstances;
1318 }
1319 return std::make_tuple(response, numInstances);
Deepak Kodihalli0b459552018-02-06 06:25:12 -06001320}
1321
Patrick Venture0b02be92018-08-31 11:55:55 -07001322std::tuple<ResponseList, NumInstances>
1323 readAll(const std::string& type, uint8_t instanceStart, const Json& config)
Deepak Kodihalli0b459552018-02-06 06:25:12 -06001324{
Deepak Kodihallidd4cff12018-02-06 06:48:29 -06001325 ResponseList responses{};
1326
1327 size_t numInstances = 0;
1328 static const std::vector<Json> empty{};
1329 std::vector<Json> readings = config.value(type, empty);
1330 numInstances = readings.size();
1331 for (const auto& reading : readings)
1332 {
1333 try
1334 {
1335 // Max of 8 records
1336 if (responses.size() == maxRecords)
1337 {
1338 break;
1339 }
1340
1341 uint8_t instanceNum = reading.value("instance", 0);
1342 // Not in the instance range we're interested in
1343 if (instanceNum < instanceStart)
1344 {
1345 continue;
1346 }
1347
1348 Response response = createFromJson(reading);
1349 responses.push_back(response);
1350 }
1351 catch (std::exception& e)
1352 {
1353 log<level::DEBUG>(e.what());
1354 continue;
1355 }
1356 }
1357
1358 if (numInstances > maxInstances)
1359 {
1360 log<level::DEBUG>("Trimming IPMI num instances",
1361 entry("NUM_INSTANCES=%d", numInstances));
1362 numInstances = maxInstances;
1363 }
1364 return std::make_tuple(responses, numInstances);
Deepak Kodihalli0b459552018-02-06 06:25:12 -06001365}
1366
1367} // namespace sensor_info
1368} // namespace dcmi
1369
1370ipmi_ret_t getSensorInfo(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
1371 ipmi_request_t request, ipmi_response_t response,
1372 ipmi_data_len_t data_len, ipmi_context_t context)
1373{
1374 auto requestData =
1375 reinterpret_cast<const dcmi::GetSensorInfoRequest*>(request);
1376 auto responseData =
1377 reinterpret_cast<dcmi::GetSensorInfoResponseHdr*>(response);
1378
1379 if (*data_len != sizeof(dcmi::GetSensorInfoRequest))
1380 {
1381 log<level::ERR>("Malformed request data",
1382 entry("DATA_SIZE=%d", *data_len));
1383 return IPMI_CC_REQ_DATA_LEN_INVALID;
1384 }
1385 *data_len = 0;
1386
1387 auto it = dcmi::entityIdToName.find(requestData->entityId);
1388 if (it == dcmi::entityIdToName.end())
1389 {
1390 log<level::ERR>("Unknown Entity ID",
1391 entry("ENTITY_ID=%d", requestData->entityId));
1392 return IPMI_CC_INVALID_FIELD_REQUEST;
1393 }
1394
1395 if (requestData->groupID != dcmi::groupExtId)
1396 {
1397 log<level::ERR>("Invalid Group ID",
1398 entry("GROUP_ID=%d", requestData->groupID));
1399 return IPMI_CC_INVALID_FIELD_REQUEST;
1400 }
1401
1402 if (requestData->sensorType != dcmi::temperatureSensorType)
1403 {
1404 log<level::ERR>("Invalid sensor type",
1405 entry("SENSOR_TYPE=%d", requestData->sensorType));
1406 return IPMI_CC_INVALID_FIELD_REQUEST;
1407 }
1408
1409 dcmi::sensor_info::ResponseList sensors{};
1410 static dcmi::Json config{};
1411 static bool parsed = false;
1412
1413 try
1414 {
1415 if (!parsed)
1416 {
1417 config = dcmi::parseSensorConfig();
1418 parsed = true;
1419 }
1420
1421 if (!requestData->entityInstance)
1422 {
1423 // Read all instances
1424 std::tie(sensors, responseData->numInstances) =
1425 dcmi::sensor_info::readAll(it->second,
Patrick Venture0b02be92018-08-31 11:55:55 -07001426 requestData->instanceStart, config);
Deepak Kodihalli0b459552018-02-06 06:25:12 -06001427 }
1428 else
1429 {
1430 // Read one instance
1431 sensors.resize(1);
1432 std::tie(sensors[0], responseData->numInstances) =
Patrick Venture0b02be92018-08-31 11:55:55 -07001433 dcmi::sensor_info::read(it->second, requestData->entityInstance,
Deepak Kodihalli0b459552018-02-06 06:25:12 -06001434 config);
1435 }
1436 responseData->numRecords = sensors.size();
1437 }
1438 catch (InternalFailure& e)
1439 {
1440 return IPMI_CC_UNSPECIFIED_ERROR;
1441 }
1442
1443 responseData->groupID = dcmi::groupExtId;
1444 size_t payloadSize = sensors.size() * sizeof(dcmi::sensor_info::Response);
1445 if (!sensors.empty())
1446 {
1447 memcpy(responseData + 1, // copy payload right after the response header
Patrick Venture0b02be92018-08-31 11:55:55 -07001448 sensors.data(), payloadSize);
Deepak Kodihalli0b459552018-02-06 06:25:12 -06001449 }
1450 *data_len = sizeof(dcmi::GetSensorInfoResponseHdr) + payloadSize;
1451
1452 return IPMI_CC_OK;
1453}
1454
Chris Austen1810bec2015-10-13 12:12:39 -05001455void register_netfn_dcmi_functions()
1456{
Tom05732372016-09-06 17:21:23 +05301457 // <Get Power Limit>
Ratan Gupta11ddbd22017-08-05 11:59:39 +05301458
Patrick Venture0b02be92018-08-31 11:55:55 -07001459 ipmi_register_callback(NETFUN_GRPEXT, dcmi::Commands::GET_POWER_LIMIT, NULL,
1460 getPowerLimit, PRIVILEGE_USER);
Tom Joseph6f6dd4d2017-07-12 20:07:11 +05301461
Tom Joseph46fa37d2017-07-26 18:11:55 +05301462 // <Set Power Limit>
Ratan Gupta11ddbd22017-08-05 11:59:39 +05301463
Patrick Venture0b02be92018-08-31 11:55:55 -07001464 ipmi_register_callback(NETFUN_GRPEXT, dcmi::Commands::SET_POWER_LIMIT, NULL,
1465 setPowerLimit, PRIVILEGE_OPERATOR);
Tom Joseph46fa37d2017-07-26 18:11:55 +05301466
Tom Joseph6c8d51b2017-07-26 18:18:06 +05301467 // <Activate/Deactivate Power Limit>
Ratan Gupta11ddbd22017-08-05 11:59:39 +05301468
1469 ipmi_register_callback(NETFUN_GRPEXT, dcmi::Commands::APPLY_POWER_LIMIT,
1470 NULL, applyPowerLimit, PRIVILEGE_OPERATOR);
Tom Joseph6c8d51b2017-07-26 18:18:06 +05301471
Tom Joseph6f6dd4d2017-07-12 20:07:11 +05301472 // <Get Asset Tag>
Ratan Gupta11ddbd22017-08-05 11:59:39 +05301473
Patrick Venture0b02be92018-08-31 11:55:55 -07001474 ipmi_register_callback(NETFUN_GRPEXT, dcmi::Commands::GET_ASSET_TAG, NULL,
1475 getAssetTag, PRIVILEGE_USER);
Tom Joseph545dd232017-07-12 20:20:49 +05301476
1477 // <Set Asset Tag>
Ratan Gupta11ddbd22017-08-05 11:59:39 +05301478
Patrick Venture0b02be92018-08-31 11:55:55 -07001479 ipmi_register_callback(NETFUN_GRPEXT, dcmi::Commands::SET_ASSET_TAG, NULL,
1480 setAssetTag, PRIVILEGE_OPERATOR);
Vladislav Vovchenko8f7a6f62017-08-17 00:31:14 +03001481
Gunnar Mills8991dd62017-10-25 17:11:29 -05001482 // <Get Management Controller Identifier String>
Vladislav Vovchenko8f7a6f62017-08-17 00:31:14 +03001483
1484 ipmi_register_callback(NETFUN_GRPEXT, dcmi::Commands::GET_MGMNT_CTRL_ID_STR,
Patrick Venture0b02be92018-08-31 11:55:55 -07001485 NULL, getMgmntCtrlIdStr, PRIVILEGE_USER);
Vladislav Vovchenko8f7a6f62017-08-17 00:31:14 +03001486
1487 // <Set Management Controller Identifier String>
Vladislav Vovchenko8f7a6f62017-08-17 00:31:14 +03001488 ipmi_register_callback(NETFUN_GRPEXT, dcmi::Commands::SET_MGMNT_CTRL_ID_STR,
Patrick Venture0b02be92018-08-31 11:55:55 -07001489 NULL, setMgmntCtrlIdStr, PRIVILEGE_ADMIN);
Vladislav Vovchenko8f7a6f62017-08-17 00:31:14 +03001490
Dhruvaraj Subhashchandrane29be412018-01-16 05:11:56 -06001491 // <Get DCMI capabilities>
1492 ipmi_register_callback(NETFUN_GRPEXT, dcmi::Commands::GET_CAPABILITIES,
Patrick Venture0b02be92018-08-31 11:55:55 -07001493 NULL, getDCMICapabilities, PRIVILEGE_USER);
Deepak Kodihalliee717d72018-01-24 04:53:09 -06001494
1495 // <Get Temperature Readings>
1496 ipmi_register_callback(NETFUN_GRPEXT, dcmi::Commands::GET_TEMP_READINGS,
1497 NULL, getTempReadings, PRIVILEGE_USER);
1498
Marri Devender Rao66c5fda2018-01-18 10:48:37 -06001499 // <Get Power Reading>
1500 ipmi_register_callback(NETFUN_GRPEXT, dcmi::Commands::GET_POWER_READING,
1501 NULL, getPowerReading, PRIVILEGE_USER);
Deepak Kodihalli0b459552018-02-06 06:25:12 -06001502
1503 // <Get Sensor Info>
Patrick Venture0b02be92018-08-31 11:55:55 -07001504 ipmi_register_callback(NETFUN_GRPEXT, dcmi::Commands::GET_SENSOR_INFO, NULL,
1505 getSensorInfo, PRIVILEGE_USER);
Deepak Kodihalli0b459552018-02-06 06:25:12 -06001506
Nagaraju Goruganti22be97b2018-02-07 01:19:59 -06001507 // <Get DCMI Configuration Parameters>
Patrick Venture0b02be92018-08-31 11:55:55 -07001508 ipmi_register_callback(NETFUN_GRPEXT, dcmi::Commands::GET_CONF_PARAMS, NULL,
1509 getDCMIConfParams, PRIVILEGE_USER);
Nagaraju Goruganti22be97b2018-02-07 01:19:59 -06001510
1511 // <Set DCMI Configuration Parameters>
Patrick Venture0b02be92018-08-31 11:55:55 -07001512 ipmi_register_callback(NETFUN_GRPEXT, dcmi::Commands::SET_CONF_PARAMS, NULL,
1513 setDCMIConfParams, PRIVILEGE_ADMIN);
Nagaraju Goruganti22be97b2018-02-07 01:19:59 -06001514
Chris Austen1810bec2015-10-13 12:12:39 -05001515 return;
1516}
Tom05732372016-09-06 17:21:23 +05301517// 956379