blob: e1a44b579e8a5577be0ac0e9275d98253d7c16ee [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>
William A. Kennington III4c008022018-10-12 17:18:14 -070017#include <sdbusplus/message/types.hpp>
Patrick Venture0b02be92018-08-31 11:55:55 -070018#include <xyz/openbmc_project/Common/error.hpp>
19
Tom Josephbe5eaa12017-07-12 19:54:44 +053020using namespace phosphor::logging;
21using InternalFailure =
Patrick Venture0b02be92018-08-31 11:55:55 -070022 sdbusplus::xyz::openbmc_project::Common::Error::InternalFailure;
Chris Austen1810bec2015-10-13 12:12:39 -050023
24void register_netfn_dcmi_functions() __attribute__((constructor));
25
Patrick Venture0b02be92018-08-31 11:55:55 -070026constexpr auto PCAP_PATH = "/xyz/openbmc_project/control/host0/power_cap";
Andrew Geissler50c0c8f2017-07-11 16:18:51 -050027constexpr auto PCAP_INTERFACE = "xyz.openbmc_project.Control.Power.Cap";
28
29constexpr auto POWER_CAP_PROP = "PowerCap";
30constexpr auto POWER_CAP_ENABLE_PROP = "PowerCapEnable";
31
Dhruvaraj Subhashchandrane29be412018-01-16 05:11:56 -060032constexpr auto DCMI_PARAMETER_REVISION = 2;
33constexpr auto DCMI_SPEC_MAJOR_VERSION = 1;
34constexpr auto DCMI_SPEC_MINOR_VERSION = 5;
Nagaraju Goruganti22be97b2018-02-07 01:19:59 -060035constexpr auto DCMI_CONFIG_PARAMETER_REVISION = 1;
36constexpr auto DCMI_RAND_BACK_OFF_MASK = 0x80;
37constexpr auto DCMI_OPTION_60_43_MASK = 0x02;
38constexpr auto DCMI_OPTION_12_MASK = 0x01;
39constexpr auto DCMI_ACTIVATE_DHCP_MASK = 0x01;
40constexpr auto DCMI_ACTIVATE_DHCP_REPLY = 0x00;
41constexpr auto DCMI_SET_CONF_PARAM_REQ_PACKET_MAX_SIZE = 0x05;
42constexpr auto DCMI_SET_CONF_PARAM_REQ_PACKET_MIN_SIZE = 0x04;
Patrick Venture0b02be92018-08-31 11:55:55 -070043constexpr auto DHCP_TIMING1 = 0x04; // 4 sec
44constexpr auto DHCP_TIMING2_UPPER = 0x00; // 2 min
Nagaraju Goruganti22be97b2018-02-07 01:19:59 -060045constexpr auto DHCP_TIMING2_LOWER = 0x78;
Patrick Venture0b02be92018-08-31 11:55:55 -070046constexpr auto DHCP_TIMING3_UPPER = 0x00; // 64 sec
Nagaraju Goruganti22be97b2018-02-07 01:19:59 -060047constexpr auto DHCP_TIMING3_LOWER = 0x40;
48// When DHCP Option 12 is enabled the string "SendHostName=true" will be
49// added into n/w configuration file and the parameter
50// SendHostNameEnabled will set to true.
51constexpr auto DHCP_OPT12_ENABLED = "SendHostNameEnabled";
52
Dhruvaraj Subhashchandrane29be412018-01-16 05:11:56 -060053constexpr auto DCMI_CAP_JSON_FILE = "/usr/share/ipmi-providers/dcmi_cap.json";
54
Marri Devender Rao66c5fda2018-01-18 10:48:37 -060055constexpr auto SENSOR_VALUE_INTF = "xyz.openbmc_project.Sensor.Value";
56constexpr auto SENSOR_VALUE_PROP = "Value";
57constexpr auto SENSOR_SCALE_PROP = "Scale";
58
Andrew Geissler50c0c8f2017-07-11 16:18:51 -050059using namespace phosphor::logging;
William A. Kennington III4c008022018-10-12 17:18:14 -070060namespace variant_ns = sdbusplus::message::variant_ns;
Andrew Geissler50c0c8f2017-07-11 16:18:51 -050061
Tom Josephb9d86f42017-07-26 18:03:47 +053062namespace dcmi
63{
64
Deepak Kodihalli0b459552018-02-06 06:25:12 -060065// Refer Table 6-14, DCMI Entity ID Extension, DCMI v1.5 spec
Patrick Venture0b02be92018-08-31 11:55:55 -070066static const std::map<uint8_t, std::string> entityIdToName{
67 {0x40, "inlet"}, {0x37, "inlet"}, {0x41, "cpu"},
68 {0x03, "cpu"}, {0x42, "baseboard"}, {0x07, "baseboard"}};
Deepak Kodihalli0b459552018-02-06 06:25:12 -060069
Andrew Geissler50c0c8f2017-07-11 16:18:51 -050070uint32_t getPcap(sdbusplus::bus::bus& bus)
71{
Patrick Venture0b02be92018-08-31 11:55:55 -070072 auto settingService = ipmi::getService(bus, PCAP_INTERFACE, PCAP_PATH);
Andrew Geissler50c0c8f2017-07-11 16:18:51 -050073
Patrick Venture0b02be92018-08-31 11:55:55 -070074 auto method = bus.new_method_call(settingService.c_str(), PCAP_PATH,
75 "org.freedesktop.DBus.Properties", "Get");
Andrew Geissler50c0c8f2017-07-11 16:18:51 -050076
77 method.append(PCAP_INTERFACE, POWER_CAP_PROP);
78 auto reply = bus.call(method);
79
80 if (reply.is_method_error())
81 {
82 log<level::ERR>("Error in getPcap prop");
Tom Josephb9d86f42017-07-26 18:03:47 +053083 elog<InternalFailure>();
Andrew Geissler50c0c8f2017-07-11 16:18:51 -050084 }
85 sdbusplus::message::variant<uint32_t> pcap;
86 reply.read(pcap);
87
William A. Kennington III4c008022018-10-12 17:18:14 -070088 return variant_ns::get<uint32_t>(pcap);
Andrew Geissler50c0c8f2017-07-11 16:18:51 -050089}
90
91bool getPcapEnabled(sdbusplus::bus::bus& bus)
92{
Patrick Venture0b02be92018-08-31 11:55:55 -070093 auto settingService = ipmi::getService(bus, PCAP_INTERFACE, PCAP_PATH);
Andrew Geissler50c0c8f2017-07-11 16:18:51 -050094
Patrick Venture0b02be92018-08-31 11:55:55 -070095 auto method = bus.new_method_call(settingService.c_str(), PCAP_PATH,
96 "org.freedesktop.DBus.Properties", "Get");
Andrew Geissler50c0c8f2017-07-11 16:18:51 -050097
98 method.append(PCAP_INTERFACE, POWER_CAP_ENABLE_PROP);
99 auto reply = bus.call(method);
100
101 if (reply.is_method_error())
102 {
103 log<level::ERR>("Error in getPcapEnabled prop");
Tom Josephb9d86f42017-07-26 18:03:47 +0530104 elog<InternalFailure>();
Andrew Geissler50c0c8f2017-07-11 16:18:51 -0500105 }
106 sdbusplus::message::variant<bool> pcapEnabled;
107 reply.read(pcapEnabled);
108
William A. Kennington III4c008022018-10-12 17:18:14 -0700109 return variant_ns::get<bool>(pcapEnabled);
Andrew Geissler50c0c8f2017-07-11 16:18:51 -0500110}
Chris Austen1810bec2015-10-13 12:12:39 -0500111
Tom Joseph46fa37d2017-07-26 18:11:55 +0530112void setPcap(sdbusplus::bus::bus& bus, const uint32_t powerCap)
113{
114 auto service = ipmi::getService(bus, PCAP_INTERFACE, PCAP_PATH);
115
Patrick Venture0b02be92018-08-31 11:55:55 -0700116 auto method = bus.new_method_call(service.c_str(), PCAP_PATH,
117 "org.freedesktop.DBus.Properties", "Set");
Tom Joseph46fa37d2017-07-26 18:11:55 +0530118
119 method.append(PCAP_INTERFACE, POWER_CAP_PROP);
120 method.append(sdbusplus::message::variant<uint32_t>(powerCap));
121
122 auto reply = bus.call(method);
123
124 if (reply.is_method_error())
125 {
126 log<level::ERR>("Error in setPcap property");
127 elog<InternalFailure>();
128 }
129}
130
Tom Joseph6c8d51b2017-07-26 18:18:06 +0530131void setPcapEnable(sdbusplus::bus::bus& bus, bool enabled)
132{
133 auto service = ipmi::getService(bus, PCAP_INTERFACE, PCAP_PATH);
134
Patrick Venture0b02be92018-08-31 11:55:55 -0700135 auto method = bus.new_method_call(service.c_str(), PCAP_PATH,
136 "org.freedesktop.DBus.Properties", "Set");
Tom Joseph6c8d51b2017-07-26 18:18:06 +0530137
138 method.append(PCAP_INTERFACE, POWER_CAP_ENABLE_PROP);
139 method.append(sdbusplus::message::variant<bool>(enabled));
140
141 auto reply = bus.call(method);
142
143 if (reply.is_method_error())
144 {
145 log<level::ERR>("Error in setPcapEnabled property");
146 elog<InternalFailure>();
147 }
148}
149
Tom Josephbe5eaa12017-07-12 19:54:44 +0530150void readAssetTagObjectTree(dcmi::assettag::ObjectTree& objectTree)
151{
152 static constexpr auto mapperBusName = "xyz.openbmc_project.ObjectMapper";
153 static constexpr auto mapperObjPath = "/xyz/openbmc_project/object_mapper";
154 static constexpr auto mapperIface = "xyz.openbmc_project.ObjectMapper";
155 static constexpr auto inventoryRoot = "/xyz/openbmc_project/inventory/";
156
157 sdbusplus::bus::bus bus{ipmid_get_sd_bus_connection()};
158 auto depth = 0;
159
Patrick Venture0b02be92018-08-31 11:55:55 -0700160 auto mapperCall = bus.new_method_call(mapperBusName, mapperObjPath,
161 mapperIface, "GetSubTree");
Tom Josephbe5eaa12017-07-12 19:54:44 +0530162
163 mapperCall.append(inventoryRoot);
164 mapperCall.append(depth);
165 mapperCall.append(std::vector<std::string>({dcmi::assetTagIntf}));
166
167 auto mapperReply = bus.call(mapperCall);
168 if (mapperReply.is_method_error())
169 {
170 log<level::ERR>("Error in mapper call");
171 elog<InternalFailure>();
172 }
173
174 mapperReply.read(objectTree);
175
176 if (objectTree.empty())
177 {
178 log<level::ERR>("AssetTag property is not populated");
179 elog<InternalFailure>();
180 }
181}
182
183std::string readAssetTag()
184{
185 sdbusplus::bus::bus bus{ipmid_get_sd_bus_connection()};
186 dcmi::assettag::ObjectTree objectTree;
187
188 // Read the object tree with the inventory root to figure out the object
189 // that has implemented the Asset tag interface.
190 readAssetTagObjectTree(objectTree);
191
192 auto method = bus.new_method_call(
Patrick Venture0b02be92018-08-31 11:55:55 -0700193 (objectTree.begin()->second.begin()->first).c_str(),
194 (objectTree.begin()->first).c_str(), dcmi::propIntf, "Get");
Tom Josephbe5eaa12017-07-12 19:54:44 +0530195 method.append(dcmi::assetTagIntf);
196 method.append(dcmi::assetTagProp);
197
198 auto reply = bus.call(method);
199 if (reply.is_method_error())
200 {
201 log<level::ERR>("Error in reading asset tag");
202 elog<InternalFailure>();
203 }
204
205 sdbusplus::message::variant<std::string> assetTag;
206 reply.read(assetTag);
207
William A. Kennington III4c008022018-10-12 17:18:14 -0700208 return variant_ns::get<std::string>(assetTag);
Tom Josephbe5eaa12017-07-12 19:54:44 +0530209}
210
Tom Josephbe5b9892017-07-15 00:55:23 +0530211void writeAssetTag(const std::string& assetTag)
212{
213 sdbusplus::bus::bus bus{ipmid_get_sd_bus_connection()};
214 dcmi::assettag::ObjectTree objectTree;
215
216 // Read the object tree with the inventory root to figure out the object
217 // that has implemented the Asset tag interface.
218 readAssetTagObjectTree(objectTree);
219
220 auto method = bus.new_method_call(
Patrick Venture0b02be92018-08-31 11:55:55 -0700221 (objectTree.begin()->second.begin()->first).c_str(),
222 (objectTree.begin()->first).c_str(), dcmi::propIntf, "Set");
Tom Josephbe5b9892017-07-15 00:55:23 +0530223 method.append(dcmi::assetTagIntf);
224 method.append(dcmi::assetTagProp);
225 method.append(sdbusplus::message::variant<std::string>(assetTag));
226
227 auto reply = bus.call(method);
228 if (reply.is_method_error())
229 {
230 log<level::ERR>("Error in writing asset tag");
231 elog<InternalFailure>();
232 }
233}
234
Vladislav Vovchenko8f7a6f62017-08-17 00:31:14 +0300235std::string getHostName(void)
236{
Patrick Venture0b02be92018-08-31 11:55:55 -0700237 sdbusplus::bus::bus bus{ipmid_get_sd_bus_connection()};
Vladislav Vovchenko8f7a6f62017-08-17 00:31:14 +0300238
239 auto service = ipmi::getService(bus, networkConfigIntf, networkConfigObj);
Patrick Venture0b02be92018-08-31 11:55:55 -0700240 auto value = ipmi::getDbusProperty(bus, service, networkConfigObj,
241 networkConfigIntf, hostNameProp);
Vladislav Vovchenko8f7a6f62017-08-17 00:31:14 +0300242
William A. Kennington III4c008022018-10-12 17:18:14 -0700243 return variant_ns::get<std::string>(value);
Vladislav Vovchenko8f7a6f62017-08-17 00:31:14 +0300244}
245
Nagaraju Goruganti22be97b2018-02-07 01:19:59 -0600246bool getDHCPEnabled()
247{
248 sdbusplus::bus::bus bus{ipmid_get_sd_bus_connection()};
249
Patrick Venture0b02be92018-08-31 11:55:55 -0700250 auto ethdevice =
251 ipmi::network::ChanneltoEthernet(ethernetDefaultChannelNum);
252 auto ethernetObj =
253 ipmi::getDbusObject(bus, ethernetIntf, networkRoot, ethdevice);
Nagaraju Goruganti22be97b2018-02-07 01:19:59 -0600254 auto service = ipmi::getService(bus, ethernetIntf, ethernetObj.first);
Patrick Venture0b02be92018-08-31 11:55:55 -0700255 auto value = ipmi::getDbusProperty(bus, service, ethernetObj.first,
256 ethernetIntf, "DHCPEnabled");
Nagaraju Goruganti22be97b2018-02-07 01:19:59 -0600257
William A. Kennington III4c008022018-10-12 17:18:14 -0700258 return variant_ns::get<bool>(value);
Nagaraju Goruganti22be97b2018-02-07 01:19:59 -0600259}
260
261bool getDHCPOption(std::string prop)
262{
263 sdbusplus::bus::bus bus{ipmid_get_sd_bus_connection()};
264
265 auto service = ipmi::getService(bus, dhcpIntf, dhcpObj);
266 auto value = ipmi::getDbusProperty(bus, service, dhcpObj, dhcpIntf, prop);
267
William A. Kennington III4c008022018-10-12 17:18:14 -0700268 return variant_ns::get<bool>(value);
Nagaraju Goruganti22be97b2018-02-07 01:19:59 -0600269}
270
Nagaraju Goruganti22be97b2018-02-07 01:19:59 -0600271void setDHCPOption(std::string prop, bool value)
272{
273 sdbusplus::bus::bus bus{ipmid_get_sd_bus_connection()};
274
275 auto service = ipmi::getService(bus, dhcpIntf, dhcpObj);
276 ipmi::setDbusProperty(bus, service, dhcpObj, dhcpIntf, prop, value);
277}
278
Deepak Kodihalli0b459552018-02-06 06:25:12 -0600279Json parseSensorConfig()
280{
281 std::ifstream jsonFile(configFile);
282 if (!jsonFile.is_open())
283 {
284 log<level::ERR>("Temperature readings JSON file not found");
285 elog<InternalFailure>();
286 }
287
288 auto data = Json::parse(jsonFile, nullptr, false);
289 if (data.is_discarded())
290 {
291 log<level::ERR>("Temperature readings JSON parser failure");
292 elog<InternalFailure>();
293 }
294
295 return data;
296}
297
Tom Josephbe5eaa12017-07-12 19:54:44 +0530298} // namespace dcmi
Chris Austen1810bec2015-10-13 12:12:39 -0500299
Tom Josephb9d86f42017-07-26 18:03:47 +0530300ipmi_ret_t getPowerLimit(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
301 ipmi_request_t request, ipmi_response_t response,
302 ipmi_data_len_t data_len, ipmi_context_t context)
303{
Patrick Venture0b02be92018-08-31 11:55:55 -0700304 auto requestData =
305 reinterpret_cast<const dcmi::GetPowerLimitRequest*>(request);
Tom Josephb9d86f42017-07-26 18:03:47 +0530306 std::vector<uint8_t> outPayload(sizeof(dcmi::GetPowerLimitResponse));
Patrick Venture0b02be92018-08-31 11:55:55 -0700307 auto responseData =
308 reinterpret_cast<dcmi::GetPowerLimitResponse*>(outPayload.data());
Tom Josephb9d86f42017-07-26 18:03:47 +0530309
310 if (requestData->groupID != dcmi::groupExtId)
311 {
312 *data_len = 0;
313 return IPMI_CC_INVALID_FIELD_REQUEST;
314 }
315
Patrick Venture0b02be92018-08-31 11:55:55 -0700316 sdbusplus::bus::bus sdbus{ipmid_get_sd_bus_connection()};
Tom Josephb9d86f42017-07-26 18:03:47 +0530317 uint32_t pcapValue = 0;
318 bool pcapEnable = false;
319
320 try
321 {
322 pcapValue = dcmi::getPcap(sdbus);
323 pcapEnable = dcmi::getPcapEnabled(sdbus);
324 }
325 catch (InternalFailure& e)
326 {
327 *data_len = 0;
328 return IPMI_CC_UNSPECIFIED_ERROR;
329 }
330
331 responseData->groupID = dcmi::groupExtId;
332
333 /*
334 * Exception action if power limit is exceeded and cannot be controlled
335 * with the correction time limit is hardcoded to Hard Power Off system
336 * and log event to SEL.
337 */
338 constexpr auto exception = 0x01;
339 responseData->exceptionAction = exception;
340
341 responseData->powerLimit = static_cast<uint16_t>(pcapValue);
342
343 /*
344 * Correction time limit and Statistics sampling period is currently not
345 * populated.
346 */
347
348 *data_len = outPayload.size();
349 memcpy(response, outPayload.data(), *data_len);
350
351 if (pcapEnable)
352 {
353 return IPMI_CC_OK;
354 }
355 else
356 {
357 return IPMI_DCMI_CC_NO_ACTIVE_POWER_LIMIT;
358 }
359}
360
Tom Joseph46fa37d2017-07-26 18:11:55 +0530361ipmi_ret_t setPowerLimit(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
362 ipmi_request_t request, ipmi_response_t response,
363 ipmi_data_len_t data_len, ipmi_context_t context)
364{
Patrick Venture0b02be92018-08-31 11:55:55 -0700365 auto requestData =
366 reinterpret_cast<const dcmi::SetPowerLimitRequest*>(request);
Tom Joseph46fa37d2017-07-26 18:11:55 +0530367 std::vector<uint8_t> outPayload(sizeof(dcmi::SetPowerLimitResponse));
Patrick Venture0b02be92018-08-31 11:55:55 -0700368 auto responseData =
369 reinterpret_cast<dcmi::SetPowerLimitResponse*>(outPayload.data());
Tom Joseph46fa37d2017-07-26 18:11:55 +0530370
371 if (requestData->groupID != dcmi::groupExtId)
372 {
373 *data_len = 0;
374 return IPMI_CC_INVALID_FIELD_REQUEST;
375 }
376
Patrick Venture0b02be92018-08-31 11:55:55 -0700377 sdbusplus::bus::bus sdbus{ipmid_get_sd_bus_connection()};
Tom Joseph46fa37d2017-07-26 18:11:55 +0530378
379 // Only process the power limit requested in watts.
380 try
381 {
382 dcmi::setPcap(sdbus, requestData->powerLimit);
383 }
384 catch (InternalFailure& e)
385 {
386 *data_len = 0;
387 return IPMI_CC_UNSPECIFIED_ERROR;
388 }
389
390 log<level::INFO>("Set Power Cap",
391 entry("POWERCAP=%u", requestData->powerLimit));
392
393 responseData->groupID = dcmi::groupExtId;
394 memcpy(response, outPayload.data(), outPayload.size());
395 *data_len = outPayload.size();
396
397 return IPMI_CC_OK;
398}
399
Tom Joseph6c8d51b2017-07-26 18:18:06 +0530400ipmi_ret_t applyPowerLimit(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
401 ipmi_request_t request, ipmi_response_t response,
402 ipmi_data_len_t data_len, ipmi_context_t context)
403{
Patrick Venture0b02be92018-08-31 11:55:55 -0700404 auto requestData =
405 reinterpret_cast<const dcmi::ApplyPowerLimitRequest*>(request);
Tom Joseph6c8d51b2017-07-26 18:18:06 +0530406 std::vector<uint8_t> outPayload(sizeof(dcmi::ApplyPowerLimitResponse));
Patrick Venture0b02be92018-08-31 11:55:55 -0700407 auto responseData =
408 reinterpret_cast<dcmi::ApplyPowerLimitResponse*>(outPayload.data());
Tom Joseph6c8d51b2017-07-26 18:18:06 +0530409
410 if (requestData->groupID != dcmi::groupExtId)
411 {
412 *data_len = 0;
413 return IPMI_CC_INVALID_FIELD_REQUEST;
414 }
415
Patrick Venture0b02be92018-08-31 11:55:55 -0700416 sdbusplus::bus::bus sdbus{ipmid_get_sd_bus_connection()};
Tom Joseph6c8d51b2017-07-26 18:18:06 +0530417
418 try
419 {
420 dcmi::setPcapEnable(sdbus,
421 static_cast<bool>(requestData->powerLimitAction));
422 }
423 catch (InternalFailure& e)
424 {
425 *data_len = 0;
426 return IPMI_CC_UNSPECIFIED_ERROR;
427 }
428
429 log<level::INFO>("Set Power Cap Enable",
430 entry("POWERCAPENABLE=%u", requestData->powerLimitAction));
431
432 responseData->groupID = dcmi::groupExtId;
433 memcpy(response, outPayload.data(), outPayload.size());
434 *data_len = outPayload.size();
435
436 return IPMI_CC_OK;
437}
438
Tom Joseph6f6dd4d2017-07-12 20:07:11 +0530439ipmi_ret_t getAssetTag(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
440 ipmi_request_t request, ipmi_response_t response,
441 ipmi_data_len_t data_len, ipmi_context_t context)
442{
Patrick Venture0b02be92018-08-31 11:55:55 -0700443 auto requestData =
444 reinterpret_cast<const dcmi::GetAssetTagRequest*>(request);
Tom Joseph6f6dd4d2017-07-12 20:07:11 +0530445 std::vector<uint8_t> outPayload(sizeof(dcmi::GetAssetTagResponse));
Patrick Venture0b02be92018-08-31 11:55:55 -0700446 auto responseData =
447 reinterpret_cast<dcmi::GetAssetTagResponse*>(outPayload.data());
Tom Joseph6f6dd4d2017-07-12 20:07:11 +0530448
449 if (requestData->groupID != dcmi::groupExtId)
450 {
451 *data_len = 0;
452 return IPMI_CC_INVALID_FIELD_REQUEST;
453 }
454
455 // Verify offset to read and number of bytes to read are not exceeding the
456 // range.
457 if ((requestData->offset > dcmi::assetTagMaxOffset) ||
458 (requestData->bytes > dcmi::maxBytes) ||
459 ((requestData->offset + requestData->bytes) > dcmi::assetTagMaxSize))
460 {
461 *data_len = 0;
462 return IPMI_CC_PARM_OUT_OF_RANGE;
463 }
464
465 std::string assetTag;
466
467 try
468 {
469 assetTag = dcmi::readAssetTag();
470 }
471 catch (InternalFailure& e)
472 {
473 *data_len = 0;
474 return IPMI_CC_UNSPECIFIED_ERROR;
475 }
476
477 responseData->groupID = dcmi::groupExtId;
478
479 // Return if the asset tag is not populated.
480 if (!assetTag.size())
481 {
482 responseData->tagLength = 0;
483 memcpy(response, outPayload.data(), outPayload.size());
484 *data_len = outPayload.size();
485 return IPMI_CC_OK;
486 }
487
488 // If the asset tag is longer than 63 bytes, restrict it to 63 bytes to suit
489 // Get Asset Tag command.
490 if (assetTag.size() > dcmi::assetTagMaxSize)
491 {
492 assetTag.resize(dcmi::assetTagMaxSize);
493 }
494
495 // If the requested offset is beyond the asset tag size.
496 if (requestData->offset >= assetTag.size())
497 {
498 *data_len = 0;
499 return IPMI_CC_PARM_OUT_OF_RANGE;
500 }
501
502 auto returnData = assetTag.substr(requestData->offset, requestData->bytes);
503
504 responseData->tagLength = assetTag.size();
505
506 memcpy(response, outPayload.data(), outPayload.size());
507 memcpy(static_cast<uint8_t*>(response) + outPayload.size(),
508 returnData.data(), returnData.size());
509 *data_len = outPayload.size() + returnData.size();
510
511 return IPMI_CC_OK;
512}
513
Tom Joseph545dd232017-07-12 20:20:49 +0530514ipmi_ret_t setAssetTag(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
515 ipmi_request_t request, ipmi_response_t response,
516 ipmi_data_len_t data_len, ipmi_context_t context)
517{
Patrick Venture0b02be92018-08-31 11:55:55 -0700518 auto requestData =
519 reinterpret_cast<const dcmi::SetAssetTagRequest*>(request);
Tom Joseph545dd232017-07-12 20:20:49 +0530520 std::vector<uint8_t> outPayload(sizeof(dcmi::SetAssetTagResponse));
Patrick Venture0b02be92018-08-31 11:55:55 -0700521 auto responseData =
522 reinterpret_cast<dcmi::SetAssetTagResponse*>(outPayload.data());
Tom Joseph545dd232017-07-12 20:20:49 +0530523
524 if (requestData->groupID != dcmi::groupExtId)
525 {
526 *data_len = 0;
527 return IPMI_CC_INVALID_FIELD_REQUEST;
528 }
529
530 // Verify offset to read and number of bytes to read are not exceeding the
531 // range.
532 if ((requestData->offset > dcmi::assetTagMaxOffset) ||
533 (requestData->bytes > dcmi::maxBytes) ||
534 ((requestData->offset + requestData->bytes) > dcmi::assetTagMaxSize))
535 {
536 *data_len = 0;
537 return IPMI_CC_PARM_OUT_OF_RANGE;
538 }
539
540 std::string assetTag;
541
542 try
543 {
544 assetTag = dcmi::readAssetTag();
545
546 if (requestData->offset > assetTag.size())
547 {
548 *data_len = 0;
549 return IPMI_CC_PARM_OUT_OF_RANGE;
550 }
551
552 assetTag.replace(requestData->offset,
553 assetTag.size() - requestData->offset,
554 static_cast<const char*>(request) +
Patrick Venture0b02be92018-08-31 11:55:55 -0700555 sizeof(dcmi::SetAssetTagRequest),
Tom Joseph545dd232017-07-12 20:20:49 +0530556 requestData->bytes);
557
558 dcmi::writeAssetTag(assetTag);
559
560 responseData->groupID = dcmi::groupExtId;
561 responseData->tagLength = assetTag.size();
562 memcpy(response, outPayload.data(), outPayload.size());
563 *data_len = outPayload.size();
564
565 return IPMI_CC_OK;
566 }
567 catch (InternalFailure& e)
568 {
569 *data_len = 0;
570 return IPMI_CC_UNSPECIFIED_ERROR;
571 }
572}
573
Vladislav Vovchenko8f7a6f62017-08-17 00:31:14 +0300574ipmi_ret_t getMgmntCtrlIdStr(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
Patrick Venture0b02be92018-08-31 11:55:55 -0700575 ipmi_request_t request, ipmi_response_t response,
576 ipmi_data_len_t data_len, ipmi_context_t context)
Vladislav Vovchenko8f7a6f62017-08-17 00:31:14 +0300577{
Patrick Venture0b02be92018-08-31 11:55:55 -0700578 auto requestData =
579 reinterpret_cast<const dcmi::GetMgmntCtrlIdStrRequest*>(request);
580 auto responseData =
581 reinterpret_cast<dcmi::GetMgmntCtrlIdStrResponse*>(response);
Vladislav Vovchenko8f7a6f62017-08-17 00:31:14 +0300582 std::string hostName;
583
584 *data_len = 0;
585
586 if (requestData->groupID != dcmi::groupExtId ||
587 requestData->bytes > dcmi::maxBytes ||
588 requestData->offset + requestData->bytes > dcmi::maxCtrlIdStrLen)
589 {
590 return IPMI_CC_INVALID_FIELD_REQUEST;
591 }
592
593 try
594 {
595 hostName = dcmi::getHostName();
596 }
597 catch (InternalFailure& e)
598 {
599 return IPMI_CC_UNSPECIFIED_ERROR;
600 }
601
602 if (requestData->offset > hostName.length())
603 {
604 return IPMI_CC_PARM_OUT_OF_RANGE;
605 }
606 auto responseStr = hostName.substr(requestData->offset, requestData->bytes);
607 auto responseStrLen = std::min(static_cast<std::size_t>(requestData->bytes),
Patrick Venture0b02be92018-08-31 11:55:55 -0700608 responseStr.length() + 1);
Vladislav Vovchenko8f7a6f62017-08-17 00:31:14 +0300609 responseData->groupID = dcmi::groupExtId;
610 responseData->strLen = hostName.length();
611 std::copy(begin(responseStr), end(responseStr), responseData->data);
612
613 *data_len = sizeof(*responseData) + responseStrLen;
614 return IPMI_CC_OK;
615}
616
617ipmi_ret_t setMgmntCtrlIdStr(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
Patrick Venture0b02be92018-08-31 11:55:55 -0700618 ipmi_request_t request, ipmi_response_t response,
619 ipmi_data_len_t data_len, ipmi_context_t context)
Vladislav Vovchenko8f7a6f62017-08-17 00:31:14 +0300620{
621 static std::array<char, dcmi::maxCtrlIdStrLen + 1> newCtrlIdStr;
622
Patrick Venture0b02be92018-08-31 11:55:55 -0700623 auto requestData =
624 reinterpret_cast<const dcmi::SetMgmntCtrlIdStrRequest*>(request);
625 auto responseData =
626 reinterpret_cast<dcmi::SetMgmntCtrlIdStrResponse*>(response);
Vladislav Vovchenko8f7a6f62017-08-17 00:31:14 +0300627
628 *data_len = 0;
629
630 if (requestData->groupID != dcmi::groupExtId ||
631 requestData->bytes > dcmi::maxBytes ||
632 requestData->offset + requestData->bytes > dcmi::maxCtrlIdStrLen + 1 ||
Patrick Venture0b02be92018-08-31 11:55:55 -0700633 (requestData->offset + requestData->bytes ==
634 dcmi::maxCtrlIdStrLen + 1 &&
635 requestData->data[requestData->bytes - 1] != '\0'))
Vladislav Vovchenko8f7a6f62017-08-17 00:31:14 +0300636 {
637 return IPMI_CC_INVALID_FIELD_REQUEST;
638 }
639
640 try
641 {
642 /* if there is no old value and offset is not 0 */
643 if (newCtrlIdStr[0] == '\0' && requestData->offset != 0)
644 {
645 /* read old ctrlIdStr */
646 auto hostName = dcmi::getHostName();
647 hostName.resize(dcmi::maxCtrlIdStrLen);
648 std::copy(begin(hostName), end(hostName), begin(newCtrlIdStr));
649 newCtrlIdStr[hostName.length()] = '\0';
650 }
651
652 /* replace part of string and mark byte after the last as \0 */
Patrick Venture0b02be92018-08-31 11:55:55 -0700653 auto restStrIter =
654 std::copy_n(requestData->data, requestData->bytes,
655 begin(newCtrlIdStr) + requestData->offset);
Vladislav Vovchenko8f7a6f62017-08-17 00:31:14 +0300656 /* if the last written byte is not 64th - add '\0' */
657 if (requestData->offset + requestData->bytes <= dcmi::maxCtrlIdStrLen)
658 {
659 *restStrIter = '\0';
660 }
661
662 /* if input data contains '\0' whole string is sent - update hostname */
663 auto it = std::find(requestData->data,
Patrick Venture0b02be92018-08-31 11:55:55 -0700664 requestData->data + requestData->bytes, '\0');
Vladislav Vovchenko8f7a6f62017-08-17 00:31:14 +0300665 if (it != requestData->data + requestData->bytes)
666 {
Patrick Venture0b02be92018-08-31 11:55:55 -0700667 sdbusplus::bus::bus bus{ipmid_get_sd_bus_connection()};
Vladislav Vovchenko8f7a6f62017-08-17 00:31:14 +0300668 ipmi::setDbusProperty(bus, dcmi::networkServiceName,
Patrick Venture0b02be92018-08-31 11:55:55 -0700669 dcmi::networkConfigObj,
670 dcmi::networkConfigIntf, dcmi::hostNameProp,
671 std::string(newCtrlIdStr.data()));
Vladislav Vovchenko8f7a6f62017-08-17 00:31:14 +0300672 }
673 }
674 catch (InternalFailure& e)
675 {
676 *data_len = 0;
677 return IPMI_CC_UNSPECIFIED_ERROR;
678 }
679
680 responseData->groupID = dcmi::groupExtId;
681 responseData->offset = requestData->offset + requestData->bytes;
682 *data_len = sizeof(*responseData);
683 return IPMI_CC_OK;
684}
685
Patrick Venture0b02be92018-08-31 11:55:55 -0700686// List of the capabilities under each parameter
687dcmi::DCMICaps dcmiCaps = {
688 // Supported DCMI Capabilities
689 {dcmi::DCMICapParameters::SUPPORTED_DCMI_CAPS,
690 {3,
691 {{"PowerManagement", 2, 0, 1},
692 {"OOBSecondaryLan", 3, 2, 1},
693 {"SerialTMODE", 3, 1, 1},
694 {"InBandSystemInterfaceChannel", 3, 0, 1}}}},
695 // Mandatory Platform Attributes
696 {dcmi::DCMICapParameters::MANDATORY_PLAT_ATTRIBUTES,
697 {5,
698 {{"SELAutoRollOver", 1, 15, 1},
699 {"FlushEntireSELUponRollOver", 1, 14, 1},
700 {"RecordLevelSELFlushUponRollOver", 1, 13, 1},
701 {"NumberOfSELEntries", 1, 0, 12},
702 {"TempMonitoringSamplingFreq", 5, 0, 8}}}},
703 // Optional Platform Attributes
704 {dcmi::DCMICapParameters::OPTIONAL_PLAT_ATTRIBUTES,
705 {2,
706 {{"PowerMgmtDeviceSlaveAddress", 1, 1, 7},
707 {"BMCChannelNumber", 2, 4, 4},
708 {"DeviceRivision", 2, 0, 4}}}},
709 // Manageability Access Attributes
710 {dcmi::DCMICapParameters::MANAGEABILITY_ACCESS_ATTRIBUTES,
711 {3,
712 {{"MandatoryPrimaryLanOOBSupport", 1, 0, 8},
713 {"OptionalSecondaryLanOOBSupport", 2, 0, 8},
714 {"OptionalSerialOOBMTMODECapability", 3, 0, 8}}}}};
Dhruvaraj Subhashchandrane29be412018-01-16 05:11:56 -0600715
716ipmi_ret_t getDCMICapabilities(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
717 ipmi_request_t request, ipmi_response_t response,
718 ipmi_data_len_t data_len, ipmi_context_t context)
719{
720
721 std::ifstream dcmiCapFile(DCMI_CAP_JSON_FILE);
722 if (!dcmiCapFile.is_open())
723 {
724 log<level::ERR>("DCMI Capabilities file not found");
725 return IPMI_CC_UNSPECIFIED_ERROR;
726 }
727
728 auto data = nlohmann::json::parse(dcmiCapFile, nullptr, false);
729 if (data.is_discarded())
730 {
731 log<level::ERR>("DCMI Capabilities JSON parser failure");
732 return IPMI_CC_UNSPECIFIED_ERROR;
733 }
734
Patrick Venture0b02be92018-08-31 11:55:55 -0700735 auto requestData =
736 reinterpret_cast<const dcmi::GetDCMICapRequest*>(request);
Dhruvaraj Subhashchandrane29be412018-01-16 05:11:56 -0600737
Patrick Venture0b02be92018-08-31 11:55:55 -0700738 // get list of capabilities in a parameter
Dhruvaraj Subhashchandrane29be412018-01-16 05:11:56 -0600739 auto caps =
740 dcmiCaps.find(static_cast<dcmi::DCMICapParameters>(requestData->param));
741 if (caps == dcmiCaps.end())
742 {
743 log<level::ERR>("Invalid input parameter");
744 return IPMI_CC_INVALID_FIELD_REQUEST;
745 }
746
747 if (requestData->groupID != dcmi::groupExtId)
748 {
749 *data_len = 0;
750 return IPMI_CC_INVALID_FIELD_REQUEST;
751 }
752
Patrick Venture0b02be92018-08-31 11:55:55 -0700753 auto responseData = reinterpret_cast<dcmi::GetDCMICapResponse*>(response);
Dhruvaraj Subhashchandrane29be412018-01-16 05:11:56 -0600754
Patrick Venture0b02be92018-08-31 11:55:55 -0700755 // For each capabilities in a parameter fill the data from
756 // the json file based on the capability name.
Dhruvaraj Subhashchandrane29be412018-01-16 05:11:56 -0600757 for (auto cap : caps->second.capList)
758 {
Patrick Venture0b02be92018-08-31 11:55:55 -0700759 // If the data is beyond first byte boundary, insert in a
760 // 16bit pattern for example number of SEL entries are represented
761 // in 12bits.
Dhruvaraj Subhashchandrane29be412018-01-16 05:11:56 -0600762 if ((cap.length + cap.position) > 8)
763 {
Patrick Venture0b02be92018-08-31 11:55:55 -0700764 // Read the value corresponding to capability name and assign to
765 // 16bit bitset.
Dhruvaraj Subhashchandrane29be412018-01-16 05:11:56 -0600766 std::bitset<16> val(data.value(cap.name.c_str(), 0));
767 val <<= cap.position;
Patrick Venture0b02be92018-08-31 11:55:55 -0700768 reinterpret_cast<uint16_t*>(
769 responseData
770 ->data)[(cap.bytePosition - 1) / sizeof(uint16_t)] |=
771 val.to_ulong();
Dhruvaraj Subhashchandrane29be412018-01-16 05:11:56 -0600772 }
773 else
774 {
775 responseData->data[cap.bytePosition - 1] |=
776 data.value(cap.name.c_str(), 0) << cap.position;
777 }
778 }
779
780 responseData->groupID = dcmi::groupExtId;
781 responseData->major = DCMI_SPEC_MAJOR_VERSION;
782 responseData->minor = DCMI_SPEC_MINOR_VERSION;
783 responseData->paramRevision = DCMI_PARAMETER_REVISION;
784 *data_len = sizeof(*responseData) + caps->second.size;
785
786 return IPMI_CC_OK;
787}
788
Deepak Kodihalliee717d72018-01-24 04:53:09 -0600789namespace dcmi
790{
791namespace temp_readings
792{
793
Deepak Kodihallib1e8fba2018-01-24 04:57:10 -0600794Temperature readTemp(const std::string& dbusService,
795 const std::string& dbusPath)
796{
797 // Read the temperature value from d-bus object. Need some conversion.
798 // As per the interface xyz.openbmc_project.Sensor.Value, the temperature
James Feist9cc0ea52018-10-09 10:53:11 -0700799 // is an double and in degrees C. It needs to be scaled by using the
Deepak Kodihallib1e8fba2018-01-24 04:57:10 -0600800 // formula Value * 10^Scale. The ipmi spec has the temperature as a uint8_t,
801 // with a separate single bit for the sign.
802
803 sdbusplus::bus::bus bus{ipmid_get_sd_bus_connection()};
Patrick Venture0b02be92018-08-31 11:55:55 -0700804 auto result = ipmi::getAllDbusProperties(
805 bus, dbusService, dbusPath, "xyz.openbmc_project.Sensor.Value");
James Feist9cc0ea52018-10-09 10:53:11 -0700806 auto temperature = sdbusplus::message::variant_ns::visit(
807 ipmi::VariantToDoubleVisitor(), result.at("Value"));
808 double absTemp = std::abs(temperature);
Deepak Kodihallib1e8fba2018-01-24 04:57:10 -0600809
James Feist9cc0ea52018-10-09 10:53:11 -0700810 auto findFactor = result.find("Scale");
811 double factor = 0.0;
812 if (findFactor != result.end())
Deepak Kodihallib1e8fba2018-01-24 04:57:10 -0600813 {
James Feist9cc0ea52018-10-09 10:53:11 -0700814 factor = sdbusplus::message::variant_ns::visit(
815 ipmi::VariantToDoubleVisitor(), findFactor->second);
Deepak Kodihallib1e8fba2018-01-24 04:57:10 -0600816 }
James Feist9cc0ea52018-10-09 10:53:11 -0700817 double scale = std::pow(10, factor);
818
819 auto tempDegrees = absTemp * scale;
Deepak Kodihallib1e8fba2018-01-24 04:57:10 -0600820 // Max absolute temp as per ipmi spec is 128.
821 if (tempDegrees > maxTemp)
822 {
823 tempDegrees = maxTemp;
824 }
825
826 return std::make_tuple(static_cast<uint8_t>(tempDegrees),
827 (temperature < 0));
828}
829
Deepak Kodihalliee717d72018-01-24 04:53:09 -0600830std::tuple<Response, NumInstances> read(const std::string& type,
831 uint8_t instance)
832{
Deepak Kodihallib1e8fba2018-01-24 04:57:10 -0600833 Response response{};
834 sdbusplus::bus::bus bus{ipmid_get_sd_bus_connection()};
835
836 if (!instance)
837 {
838 log<level::ERR>("Expected non-zero instance");
839 elog<InternalFailure>();
840 }
841
Deepak Kodihalli0b459552018-02-06 06:25:12 -0600842 auto data = parseSensorConfig();
Deepak Kodihallib1e8fba2018-01-24 04:57:10 -0600843 static const std::vector<Json> empty{};
844 std::vector<Json> readings = data.value(type, empty);
845 size_t numInstances = readings.size();
846 for (const auto& j : readings)
847 {
848 uint8_t instanceNum = j.value("instance", 0);
849 // Not the instance we're interested in
850 if (instanceNum != instance)
851 {
852 continue;
853 }
854
855 std::string path = j.value("dbus", "");
856 std::string service;
857 try
858 {
859 service =
Patrick Venture0b02be92018-08-31 11:55:55 -0700860 ipmi::getService(bus, "xyz.openbmc_project.Sensor.Value", path);
Deepak Kodihallib1e8fba2018-01-24 04:57:10 -0600861 }
862 catch (std::exception& e)
863 {
864 log<level::DEBUG>(e.what());
865 return std::make_tuple(response, numInstances);
866 }
867
868 response.instance = instance;
869 uint8_t temp{};
870 bool sign{};
871 std::tie(temp, sign) = readTemp(service, path);
872 response.temperature = temp;
873 response.sign = sign;
874
875 // Found the instance we're interested in
876 break;
877 }
878
879 if (numInstances > maxInstances)
880 {
881 numInstances = maxInstances;
882 }
883 return std::make_tuple(response, numInstances);
Deepak Kodihalliee717d72018-01-24 04:53:09 -0600884}
885
886std::tuple<ResponseList, NumInstances> readAll(const std::string& type,
887 uint8_t instanceStart)
888{
Deepak Kodihallib1e8fba2018-01-24 04:57:10 -0600889 ResponseList response{};
890 sdbusplus::bus::bus bus{ipmid_get_sd_bus_connection()};
891
892 size_t numInstances = 0;
Deepak Kodihalli0b459552018-02-06 06:25:12 -0600893 auto data = parseSensorConfig();
Deepak Kodihallib1e8fba2018-01-24 04:57:10 -0600894 static const std::vector<Json> empty{};
895 std::vector<Json> readings = data.value(type, empty);
896 numInstances = readings.size();
897 for (const auto& j : readings)
898 {
899 try
900 {
901 // Max of 8 response data sets
902 if (response.size() == maxDataSets)
903 {
904 break;
905 }
906
907 uint8_t instanceNum = j.value("instance", 0);
908 // Not in the instance range we're interested in
909 if (instanceNum < instanceStart)
910 {
911 continue;
912 }
913
914 std::string path = j.value("dbus", "");
915 auto service =
Patrick Venture0b02be92018-08-31 11:55:55 -0700916 ipmi::getService(bus, "xyz.openbmc_project.Sensor.Value", path);
Deepak Kodihallib1e8fba2018-01-24 04:57:10 -0600917
918 Response r{};
919 r.instance = instanceNum;
920 uint8_t temp{};
921 bool sign{};
922 std::tie(temp, sign) = readTemp(service, path);
923 r.temperature = temp;
924 r.sign = sign;
925 response.push_back(r);
926 }
927 catch (std::exception& e)
928 {
929 log<level::DEBUG>(e.what());
930 continue;
931 }
932 }
933
934 if (numInstances > maxInstances)
935 {
936 numInstances = maxInstances;
937 }
938 return std::make_tuple(response, numInstances);
Deepak Kodihalliee717d72018-01-24 04:53:09 -0600939}
940
Patrick Venture0b02be92018-08-31 11:55:55 -0700941} // namespace temp_readings
942} // namespace dcmi
Deepak Kodihalliee717d72018-01-24 04:53:09 -0600943
944ipmi_ret_t getTempReadings(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
Patrick Venture0b02be92018-08-31 11:55:55 -0700945 ipmi_request_t request, ipmi_response_t response,
946 ipmi_data_len_t data_len, ipmi_context_t context)
Deepak Kodihalliee717d72018-01-24 04:53:09 -0600947{
Deepak Kodihalliee717d72018-01-24 04:53:09 -0600948 auto requestData =
949 reinterpret_cast<const dcmi::GetTempReadingsRequest*>(request);
950 auto responseData =
951 reinterpret_cast<dcmi::GetTempReadingsResponseHdr*>(response);
952
953 if (*data_len != sizeof(dcmi::GetTempReadingsRequest))
954 {
955 log<level::ERR>("Malformed request data",
956 entry("DATA_SIZE=%d", *data_len));
957 return IPMI_CC_REQ_DATA_LEN_INVALID;
958 }
959 *data_len = 0;
960
Deepak Kodihalli0b459552018-02-06 06:25:12 -0600961 auto it = dcmi::entityIdToName.find(requestData->entityId);
962 if (it == dcmi::entityIdToName.end())
Deepak Kodihalliee717d72018-01-24 04:53:09 -0600963 {
964 log<level::ERR>("Unknown Entity ID",
965 entry("ENTITY_ID=%d", requestData->entityId));
966 return IPMI_CC_INVALID_FIELD_REQUEST;
967 }
968
969 if (requestData->groupID != dcmi::groupExtId)
970 {
971 log<level::ERR>("Invalid Group ID",
972 entry("GROUP_ID=%d", requestData->groupID));
973 return IPMI_CC_INVALID_FIELD_REQUEST;
974 }
975
976 if (requestData->sensorType != dcmi::temperatureSensorType)
977 {
978 log<level::ERR>("Invalid sensor type",
979 entry("SENSOR_TYPE=%d", requestData->sensorType));
980 return IPMI_CC_INVALID_FIELD_REQUEST;
981 }
982
983 dcmi::temp_readings::ResponseList temps{};
984 try
985 {
986 if (!requestData->entityInstance)
987 {
988 // Read all instances
989 std::tie(temps, responseData->numInstances) =
990 dcmi::temp_readings::readAll(it->second,
991 requestData->instanceStart);
992 }
993 else
994 {
995 // Read one instance
996 temps.resize(1);
997 std::tie(temps[0], responseData->numInstances) =
998 dcmi::temp_readings::read(it->second,
999 requestData->entityInstance);
1000 }
1001 responseData->numDataSets = temps.size();
1002 }
1003 catch (InternalFailure& e)
1004 {
1005 return IPMI_CC_UNSPECIFIED_ERROR;
1006 }
1007
1008 responseData->groupID = dcmi::groupExtId;
Patrick Venture0b02be92018-08-31 11:55:55 -07001009 size_t payloadSize = temps.size() * sizeof(dcmi::temp_readings::Response);
Deepak Kodihalliee717d72018-01-24 04:53:09 -06001010 if (!temps.empty())
1011 {
1012 memcpy(responseData + 1, // copy payload right after the response header
Patrick Venture0b02be92018-08-31 11:55:55 -07001013 temps.data(), payloadSize);
Deepak Kodihalliee717d72018-01-24 04:53:09 -06001014 }
1015 *data_len = sizeof(dcmi::GetTempReadingsResponseHdr) + payloadSize;
1016
1017 return IPMI_CC_OK;
1018}
1019
Marri Devender Rao66c5fda2018-01-18 10:48:37 -06001020int64_t getPowerReading(sdbusplus::bus::bus& bus)
1021{
1022 std::ifstream sensorFile(POWER_READING_SENSOR);
1023 std::string objectPath;
1024 if (!sensorFile.is_open())
1025 {
1026 log<level::ERR>("Power reading configuration file not found",
Patrick Venture0b02be92018-08-31 11:55:55 -07001027 entry("POWER_SENSOR_FILE=%s", POWER_READING_SENSOR));
Marri Devender Rao66c5fda2018-01-18 10:48:37 -06001028 elog<InternalFailure>();
1029 }
1030
1031 auto data = nlohmann::json::parse(sensorFile, nullptr, false);
1032 if (data.is_discarded())
1033 {
1034 log<level::ERR>("Error in parsing configuration file",
Patrick Venture0b02be92018-08-31 11:55:55 -07001035 entry("POWER_SENSOR_FILE=%s", POWER_READING_SENSOR));
Marri Devender Rao66c5fda2018-01-18 10:48:37 -06001036 elog<InternalFailure>();
1037 }
1038
1039 objectPath = data.value("path", "");
1040 if (objectPath.empty())
1041 {
1042 log<level::ERR>("Power sensor D-Bus object path is empty",
1043 entry("POWER_SENSOR_FILE=%s", POWER_READING_SENSOR));
1044 elog<InternalFailure>();
1045 }
1046
Marri Devender Raoce6a7952018-02-11 08:45:00 -06001047 // Return default value if failed to read from D-Bus object
1048 int64_t power = 0;
1049 try
1050 {
1051 auto service = ipmi::getService(bus, SENSOR_VALUE_INTF, objectPath);
Marri Devender Rao66c5fda2018-01-18 10:48:37 -06001052
Patrick Venture0b02be92018-08-31 11:55:55 -07001053 // Read the sensor value and scale properties
1054 auto properties = ipmi::getAllDbusProperties(bus, service, objectPath,
1055 SENSOR_VALUE_INTF);
William A. Kennington III4c008022018-10-12 17:18:14 -07001056 auto value = variant_ns::get<int64_t>(properties[SENSOR_VALUE_PROP]);
1057 auto scale = variant_ns::get<int64_t>(properties[SENSOR_SCALE_PROP]);
Marri Devender Rao66c5fda2018-01-18 10:48:37 -06001058
Marri Devender Raoce6a7952018-02-11 08:45:00 -06001059 // Power reading needs to be scaled with the Scale value using the
1060 // formula Value * 10^Scale.
1061 power = value * std::pow(10, scale);
1062 }
1063 catch (std::exception& e)
1064 {
1065 log<level::INFO>("Failure to read power value from D-Bus object",
Patrick Venture0b02be92018-08-31 11:55:55 -07001066 entry("OBJECT_PATH=%s", objectPath.c_str()),
1067 entry("INTERFACE=%s", SENSOR_VALUE_INTF));
Marri Devender Raoce6a7952018-02-11 08:45:00 -06001068 }
Marri Devender Rao66c5fda2018-01-18 10:48:37 -06001069 return power;
1070}
1071
Nagaraju Goruganti22be97b2018-02-07 01:19:59 -06001072ipmi_ret_t setDCMIConfParams(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
1073 ipmi_request_t request, ipmi_response_t response,
1074 ipmi_data_len_t data_len, ipmi_context_t context)
1075{
Patrick Venture0b02be92018-08-31 11:55:55 -07001076 auto requestData =
1077 reinterpret_cast<const dcmi::SetConfParamsRequest*>(request);
1078 auto responseData =
1079 reinterpret_cast<dcmi::SetConfParamsResponse*>(response);
Nagaraju Goruganti22be97b2018-02-07 01:19:59 -06001080
Patrick Venture0b02be92018-08-31 11:55:55 -07001081 if (requestData->groupID != dcmi::groupExtId ||
1082 *data_len < DCMI_SET_CONF_PARAM_REQ_PACKET_MIN_SIZE ||
1083 *data_len > DCMI_SET_CONF_PARAM_REQ_PACKET_MAX_SIZE)
Nagaraju Goruganti22be97b2018-02-07 01:19:59 -06001084 {
Gunnar Mills8466b792018-03-23 12:18:12 -05001085 log<level::ERR>("Invalid Group ID or Invalid Requested Packet size",
Nagaraju Goruganti22be97b2018-02-07 01:19:59 -06001086 entry("GROUP_ID=%d", requestData->groupID),
1087 entry("PACKET SIZE=%d", *data_len));
1088 return IPMI_CC_INVALID_FIELD_REQUEST;
1089 }
1090
1091 *data_len = 0;
1092
1093 try
1094 {
1095 // Take action based on the Parameter Selector
Patrick Venture0b02be92018-08-31 11:55:55 -07001096 switch (
1097 static_cast<dcmi::DCMIConfigParameters>(requestData->paramSelect))
Nagaraju Goruganti22be97b2018-02-07 01:19:59 -06001098 {
1099 case dcmi::DCMIConfigParameters::ActivateDHCP:
1100
1101 if ((requestData->data[0] & DCMI_ACTIVATE_DHCP_MASK) &&
Patrick Venture0b02be92018-08-31 11:55:55 -07001102 dcmi::getDHCPEnabled())
Nagaraju Goruganti22be97b2018-02-07 01:19:59 -06001103 {
Patrick Venture0b02be92018-08-31 11:55:55 -07001104 // When these conditions are met we have to trigger DHCP
1105 // protocol restart using the latest parameter settings, but
1106 // as per n/w manager design, each time when we update n/w
1107 // parameters, n/w service is restarted. So we no need to
1108 // take any action in this case.
Nagaraju Goruganti22be97b2018-02-07 01:19:59 -06001109 }
1110 break;
1111
1112 case dcmi::DCMIConfigParameters::DiscoveryConfig:
1113
1114 if (requestData->data[0] & DCMI_OPTION_12_MASK)
1115 {
1116 dcmi::setDHCPOption(DHCP_OPT12_ENABLED, true);
1117 }
1118 else
1119 {
1120 dcmi::setDHCPOption(DHCP_OPT12_ENABLED, false);
1121 }
1122
1123 // Systemd-networkd doesn't support Random Back off
1124 if (requestData->data[0] & DCMI_RAND_BACK_OFF_MASK)
1125 {
1126 return IPMI_CC_INVALID;
1127 }
1128 break;
1129 // Systemd-networkd doesn't allow to configure DHCP timigs
1130 case dcmi::DCMIConfigParameters::DHCPTiming1:
1131 case dcmi::DCMIConfigParameters::DHCPTiming2:
1132 case dcmi::DCMIConfigParameters::DHCPTiming3:
1133 default:
1134 return IPMI_CC_INVALID;
1135 }
1136 }
1137 catch (std::exception& e)
1138 {
1139 log<level::ERR>(e.what());
1140 return IPMI_CC_UNSPECIFIED_ERROR;
1141 }
1142 responseData->groupID = dcmi::groupExtId;
1143 *data_len = sizeof(dcmi::SetConfParamsResponse);
1144
1145 return IPMI_CC_OK;
1146}
1147
1148ipmi_ret_t getDCMIConfParams(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
1149 ipmi_request_t request, ipmi_response_t response,
1150 ipmi_data_len_t data_len, ipmi_context_t context)
1151{
1152
Patrick Venture0b02be92018-08-31 11:55:55 -07001153 auto requestData =
1154 reinterpret_cast<const dcmi::GetConfParamsRequest*>(request);
1155 auto responseData =
1156 reinterpret_cast<dcmi::GetConfParamsResponse*>(response);
Nagaraju Goruganti22be97b2018-02-07 01:19:59 -06001157
1158 responseData->data[0] = 0x00;
1159
Patrick Venture0b02be92018-08-31 11:55:55 -07001160 if (requestData->groupID != dcmi::groupExtId ||
1161 *data_len != sizeof(dcmi::GetConfParamsRequest))
Nagaraju Goruganti22be97b2018-02-07 01:19:59 -06001162 {
Gunnar Mills8466b792018-03-23 12:18:12 -05001163 log<level::ERR>("Invalid Group ID or Invalid Requested Packet size",
Nagaraju Goruganti22be97b2018-02-07 01:19:59 -06001164 entry("GROUP_ID=%d", requestData->groupID),
1165 entry("PACKET SIZE=%d", *data_len));
1166 return IPMI_CC_INVALID_FIELD_REQUEST;
1167 }
1168
1169 *data_len = 0;
1170
1171 try
1172 {
1173 // Take action based on the Parameter Selector
Patrick Venture0b02be92018-08-31 11:55:55 -07001174 switch (
1175 static_cast<dcmi::DCMIConfigParameters>(requestData->paramSelect))
Nagaraju Goruganti22be97b2018-02-07 01:19:59 -06001176 {
1177 case dcmi::DCMIConfigParameters::ActivateDHCP:
1178 responseData->data[0] = DCMI_ACTIVATE_DHCP_REPLY;
1179 *data_len = sizeof(dcmi::GetConfParamsResponse) + 1;
1180 break;
1181 case dcmi::DCMIConfigParameters::DiscoveryConfig:
1182 if (dcmi::getDHCPOption(DHCP_OPT12_ENABLED))
1183 {
1184 responseData->data[0] |= DCMI_OPTION_12_MASK;
1185 }
1186 *data_len = sizeof(dcmi::GetConfParamsResponse) + 1;
1187 break;
1188 // Get below values from Systemd-networkd source code
1189 case dcmi::DCMIConfigParameters::DHCPTiming1:
1190 responseData->data[0] = DHCP_TIMING1;
1191 *data_len = sizeof(dcmi::GetConfParamsResponse) + 1;
1192 break;
1193 case dcmi::DCMIConfigParameters::DHCPTiming2:
1194 responseData->data[0] = DHCP_TIMING2_LOWER;
1195 responseData->data[1] = DHCP_TIMING2_UPPER;
1196 *data_len = sizeof(dcmi::GetConfParamsResponse) + 2;
1197 break;
1198 case dcmi::DCMIConfigParameters::DHCPTiming3:
1199 responseData->data[0] = DHCP_TIMING3_LOWER;
1200 responseData->data[1] = DHCP_TIMING3_UPPER;
1201 *data_len = sizeof(dcmi::GetConfParamsResponse) + 2;
1202 break;
1203 default:
1204 *data_len = 0;
1205 return IPMI_CC_INVALID;
1206 }
1207 }
1208 catch (std::exception& e)
1209 {
1210 log<level::ERR>(e.what());
1211 return IPMI_CC_UNSPECIFIED_ERROR;
1212 }
1213
1214 responseData->groupID = dcmi::groupExtId;
1215 responseData->major = DCMI_SPEC_MAJOR_VERSION;
1216 responseData->minor = DCMI_SPEC_MINOR_VERSION;
1217 responseData->paramRevision = DCMI_CONFIG_PARAMETER_REVISION;
1218
1219 return IPMI_CC_OK;
1220}
1221
Marri Devender Rao66c5fda2018-01-18 10:48:37 -06001222ipmi_ret_t getPowerReading(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
Patrick Venture0b02be92018-08-31 11:55:55 -07001223 ipmi_request_t request, ipmi_response_t response,
1224 ipmi_data_len_t data_len, ipmi_context_t context)
Marri Devender Rao66c5fda2018-01-18 10:48:37 -06001225{
1226 ipmi_ret_t rc = IPMI_CC_OK;
Patrick Venture0b02be92018-08-31 11:55:55 -07001227 auto requestData =
1228 reinterpret_cast<const dcmi::GetPowerReadingRequest*>(request);
1229 auto responseData =
1230 reinterpret_cast<dcmi::GetPowerReadingResponse*>(response);
Marri Devender Rao9c966e02018-01-22 05:55:10 -06001231
1232 if (requestData->groupID != dcmi::groupExtId)
1233 {
1234 *data_len = 0;
1235 return IPMI_CC_INVALID_FIELD_REQUEST;
1236 }
1237
Marri Devender Rao66c5fda2018-01-18 10:48:37 -06001238 sdbusplus::bus::bus bus{ipmid_get_sd_bus_connection()};
Marri Devender Rao9c966e02018-01-22 05:55:10 -06001239 int64_t power = 0;
Marri Devender Rao66c5fda2018-01-18 10:48:37 -06001240 try
1241 {
Marri Devender Rao9c966e02018-01-22 05:55:10 -06001242 power = getPowerReading(bus);
Marri Devender Rao66c5fda2018-01-18 10:48:37 -06001243 }
1244 catch (InternalFailure& e)
1245 {
1246 log<level::ERR>("Error in reading power sensor value",
1247 entry("INTERFACE=%s", SENSOR_VALUE_INTF),
1248 entry("PROPERTY=%s", SENSOR_VALUE_PROP));
1249 return IPMI_CC_UNSPECIFIED_ERROR;
1250 }
Marri Devender Rao9c966e02018-01-22 05:55:10 -06001251 responseData->groupID = dcmi::groupExtId;
1252
1253 // TODO: openbmc/openbmc#2819
Gunnar Mills8466b792018-03-23 12:18:12 -05001254 // Minimum, Maximum, Average power, TimeFrame, TimeStamp,
Marri Devender Rao9c966e02018-01-22 05:55:10 -06001255 // PowerReadingState readings need to be populated
1256 // after Telemetry changes.
1257 uint16_t totalPower = static_cast<uint16_t>(power);
1258 responseData->currentPower = totalPower;
1259 responseData->minimumPower = totalPower;
1260 responseData->maximumPower = totalPower;
1261 responseData->averagePower = totalPower;
1262
1263 *data_len = sizeof(*responseData);
Marri Devender Rao66c5fda2018-01-18 10:48:37 -06001264 return rc;
1265}
1266
Deepak Kodihalli0b459552018-02-06 06:25:12 -06001267namespace dcmi
1268{
1269namespace sensor_info
1270{
1271
Deepak Kodihallidd4cff12018-02-06 06:48:29 -06001272Response createFromJson(const Json& config)
1273{
1274 Response response{};
1275 uint16_t recordId = config.value("record_id", 0);
1276 response.recordIdLsb = recordId & 0xFF;
1277 response.recordIdMsb = (recordId >> 8) & 0xFF;
1278 return response;
1279}
1280
Deepak Kodihalli0b459552018-02-06 06:25:12 -06001281std::tuple<Response, NumInstances> read(const std::string& type,
Patrick Venture0b02be92018-08-31 11:55:55 -07001282 uint8_t instance, const Json& config)
Deepak Kodihalli0b459552018-02-06 06:25:12 -06001283{
Deepak Kodihallidd4cff12018-02-06 06:48:29 -06001284 Response response{};
1285
1286 if (!instance)
1287 {
1288 log<level::ERR>("Expected non-zero instance");
1289 elog<InternalFailure>();
1290 }
1291
1292 static const std::vector<Json> empty{};
1293 std::vector<Json> readings = config.value(type, empty);
1294 size_t numInstances = readings.size();
1295 for (const auto& reading : readings)
1296 {
1297 uint8_t instanceNum = reading.value("instance", 0);
1298 // Not the instance we're interested in
1299 if (instanceNum != instance)
1300 {
1301 continue;
1302 }
1303
1304 response = createFromJson(reading);
1305
1306 // Found the instance we're interested in
1307 break;
1308 }
1309
1310 if (numInstances > maxInstances)
1311 {
1312 log<level::DEBUG>("Trimming IPMI num instances",
1313 entry("NUM_INSTANCES=%d", numInstances));
1314 numInstances = maxInstances;
1315 }
1316 return std::make_tuple(response, numInstances);
Deepak Kodihalli0b459552018-02-06 06:25:12 -06001317}
1318
Patrick Venture0b02be92018-08-31 11:55:55 -07001319std::tuple<ResponseList, NumInstances>
1320 readAll(const std::string& type, uint8_t instanceStart, const Json& config)
Deepak Kodihalli0b459552018-02-06 06:25:12 -06001321{
Deepak Kodihallidd4cff12018-02-06 06:48:29 -06001322 ResponseList responses{};
1323
1324 size_t numInstances = 0;
1325 static const std::vector<Json> empty{};
1326 std::vector<Json> readings = config.value(type, empty);
1327 numInstances = readings.size();
1328 for (const auto& reading : readings)
1329 {
1330 try
1331 {
1332 // Max of 8 records
1333 if (responses.size() == maxRecords)
1334 {
1335 break;
1336 }
1337
1338 uint8_t instanceNum = reading.value("instance", 0);
1339 // Not in the instance range we're interested in
1340 if (instanceNum < instanceStart)
1341 {
1342 continue;
1343 }
1344
1345 Response response = createFromJson(reading);
1346 responses.push_back(response);
1347 }
1348 catch (std::exception& e)
1349 {
1350 log<level::DEBUG>(e.what());
1351 continue;
1352 }
1353 }
1354
1355 if (numInstances > maxInstances)
1356 {
1357 log<level::DEBUG>("Trimming IPMI num instances",
1358 entry("NUM_INSTANCES=%d", numInstances));
1359 numInstances = maxInstances;
1360 }
1361 return std::make_tuple(responses, numInstances);
Deepak Kodihalli0b459552018-02-06 06:25:12 -06001362}
1363
1364} // namespace sensor_info
1365} // namespace dcmi
1366
1367ipmi_ret_t getSensorInfo(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
1368 ipmi_request_t request, ipmi_response_t response,
1369 ipmi_data_len_t data_len, ipmi_context_t context)
1370{
1371 auto requestData =
1372 reinterpret_cast<const dcmi::GetSensorInfoRequest*>(request);
1373 auto responseData =
1374 reinterpret_cast<dcmi::GetSensorInfoResponseHdr*>(response);
1375
1376 if (*data_len != sizeof(dcmi::GetSensorInfoRequest))
1377 {
1378 log<level::ERR>("Malformed request data",
1379 entry("DATA_SIZE=%d", *data_len));
1380 return IPMI_CC_REQ_DATA_LEN_INVALID;
1381 }
1382 *data_len = 0;
1383
1384 auto it = dcmi::entityIdToName.find(requestData->entityId);
1385 if (it == dcmi::entityIdToName.end())
1386 {
1387 log<level::ERR>("Unknown Entity ID",
1388 entry("ENTITY_ID=%d", requestData->entityId));
1389 return IPMI_CC_INVALID_FIELD_REQUEST;
1390 }
1391
1392 if (requestData->groupID != dcmi::groupExtId)
1393 {
1394 log<level::ERR>("Invalid Group ID",
1395 entry("GROUP_ID=%d", requestData->groupID));
1396 return IPMI_CC_INVALID_FIELD_REQUEST;
1397 }
1398
1399 if (requestData->sensorType != dcmi::temperatureSensorType)
1400 {
1401 log<level::ERR>("Invalid sensor type",
1402 entry("SENSOR_TYPE=%d", requestData->sensorType));
1403 return IPMI_CC_INVALID_FIELD_REQUEST;
1404 }
1405
1406 dcmi::sensor_info::ResponseList sensors{};
1407 static dcmi::Json config{};
1408 static bool parsed = false;
1409
1410 try
1411 {
1412 if (!parsed)
1413 {
1414 config = dcmi::parseSensorConfig();
1415 parsed = true;
1416 }
1417
1418 if (!requestData->entityInstance)
1419 {
1420 // Read all instances
1421 std::tie(sensors, responseData->numInstances) =
1422 dcmi::sensor_info::readAll(it->second,
Patrick Venture0b02be92018-08-31 11:55:55 -07001423 requestData->instanceStart, config);
Deepak Kodihalli0b459552018-02-06 06:25:12 -06001424 }
1425 else
1426 {
1427 // Read one instance
1428 sensors.resize(1);
1429 std::tie(sensors[0], responseData->numInstances) =
Patrick Venture0b02be92018-08-31 11:55:55 -07001430 dcmi::sensor_info::read(it->second, requestData->entityInstance,
Deepak Kodihalli0b459552018-02-06 06:25:12 -06001431 config);
1432 }
1433 responseData->numRecords = sensors.size();
1434 }
1435 catch (InternalFailure& e)
1436 {
1437 return IPMI_CC_UNSPECIFIED_ERROR;
1438 }
1439
1440 responseData->groupID = dcmi::groupExtId;
1441 size_t payloadSize = sensors.size() * sizeof(dcmi::sensor_info::Response);
1442 if (!sensors.empty())
1443 {
1444 memcpy(responseData + 1, // copy payload right after the response header
Patrick Venture0b02be92018-08-31 11:55:55 -07001445 sensors.data(), payloadSize);
Deepak Kodihalli0b459552018-02-06 06:25:12 -06001446 }
1447 *data_len = sizeof(dcmi::GetSensorInfoResponseHdr) + payloadSize;
1448
1449 return IPMI_CC_OK;
1450}
1451
Chris Austen1810bec2015-10-13 12:12:39 -05001452void register_netfn_dcmi_functions()
1453{
Tom05732372016-09-06 17:21:23 +05301454 // <Get Power Limit>
Ratan Gupta11ddbd22017-08-05 11:59:39 +05301455
Patrick Venture0b02be92018-08-31 11:55:55 -07001456 ipmi_register_callback(NETFUN_GRPEXT, dcmi::Commands::GET_POWER_LIMIT, NULL,
1457 getPowerLimit, PRIVILEGE_USER);
Tom Joseph6f6dd4d2017-07-12 20:07:11 +05301458
Tom Joseph46fa37d2017-07-26 18:11:55 +05301459 // <Set Power Limit>
Ratan Gupta11ddbd22017-08-05 11:59:39 +05301460
Patrick Venture0b02be92018-08-31 11:55:55 -07001461 ipmi_register_callback(NETFUN_GRPEXT, dcmi::Commands::SET_POWER_LIMIT, NULL,
1462 setPowerLimit, PRIVILEGE_OPERATOR);
Tom Joseph46fa37d2017-07-26 18:11:55 +05301463
Tom Joseph6c8d51b2017-07-26 18:18:06 +05301464 // <Activate/Deactivate Power Limit>
Ratan Gupta11ddbd22017-08-05 11:59:39 +05301465
1466 ipmi_register_callback(NETFUN_GRPEXT, dcmi::Commands::APPLY_POWER_LIMIT,
1467 NULL, applyPowerLimit, PRIVILEGE_OPERATOR);
Tom Joseph6c8d51b2017-07-26 18:18:06 +05301468
Tom Joseph6f6dd4d2017-07-12 20:07:11 +05301469 // <Get Asset Tag>
Ratan Gupta11ddbd22017-08-05 11:59:39 +05301470
Patrick Venture0b02be92018-08-31 11:55:55 -07001471 ipmi_register_callback(NETFUN_GRPEXT, dcmi::Commands::GET_ASSET_TAG, NULL,
1472 getAssetTag, PRIVILEGE_USER);
Tom Joseph545dd232017-07-12 20:20:49 +05301473
1474 // <Set Asset Tag>
Ratan Gupta11ddbd22017-08-05 11:59:39 +05301475
Patrick Venture0b02be92018-08-31 11:55:55 -07001476 ipmi_register_callback(NETFUN_GRPEXT, dcmi::Commands::SET_ASSET_TAG, NULL,
1477 setAssetTag, PRIVILEGE_OPERATOR);
Vladislav Vovchenko8f7a6f62017-08-17 00:31:14 +03001478
Gunnar Mills8991dd62017-10-25 17:11:29 -05001479 // <Get Management Controller Identifier String>
Vladislav Vovchenko8f7a6f62017-08-17 00:31:14 +03001480
1481 ipmi_register_callback(NETFUN_GRPEXT, dcmi::Commands::GET_MGMNT_CTRL_ID_STR,
Patrick Venture0b02be92018-08-31 11:55:55 -07001482 NULL, getMgmntCtrlIdStr, PRIVILEGE_USER);
Vladislav Vovchenko8f7a6f62017-08-17 00:31:14 +03001483
1484 // <Set Management Controller Identifier String>
Vladislav Vovchenko8f7a6f62017-08-17 00:31:14 +03001485 ipmi_register_callback(NETFUN_GRPEXT, dcmi::Commands::SET_MGMNT_CTRL_ID_STR,
Patrick Venture0b02be92018-08-31 11:55:55 -07001486 NULL, setMgmntCtrlIdStr, PRIVILEGE_ADMIN);
Vladislav Vovchenko8f7a6f62017-08-17 00:31:14 +03001487
Dhruvaraj Subhashchandrane29be412018-01-16 05:11:56 -06001488 // <Get DCMI capabilities>
1489 ipmi_register_callback(NETFUN_GRPEXT, dcmi::Commands::GET_CAPABILITIES,
Patrick Venture0b02be92018-08-31 11:55:55 -07001490 NULL, getDCMICapabilities, PRIVILEGE_USER);
Deepak Kodihalliee717d72018-01-24 04:53:09 -06001491
1492 // <Get Temperature Readings>
1493 ipmi_register_callback(NETFUN_GRPEXT, dcmi::Commands::GET_TEMP_READINGS,
1494 NULL, getTempReadings, PRIVILEGE_USER);
1495
Marri Devender Rao66c5fda2018-01-18 10:48:37 -06001496 // <Get Power Reading>
1497 ipmi_register_callback(NETFUN_GRPEXT, dcmi::Commands::GET_POWER_READING,
1498 NULL, getPowerReading, PRIVILEGE_USER);
Deepak Kodihalli0b459552018-02-06 06:25:12 -06001499
1500 // <Get Sensor Info>
Patrick Venture0b02be92018-08-31 11:55:55 -07001501 ipmi_register_callback(NETFUN_GRPEXT, dcmi::Commands::GET_SENSOR_INFO, NULL,
1502 getSensorInfo, PRIVILEGE_USER);
Deepak Kodihalli0b459552018-02-06 06:25:12 -06001503
Nagaraju Goruganti22be97b2018-02-07 01:19:59 -06001504 // <Get DCMI Configuration Parameters>
Patrick Venture0b02be92018-08-31 11:55:55 -07001505 ipmi_register_callback(NETFUN_GRPEXT, dcmi::Commands::GET_CONF_PARAMS, NULL,
1506 getDCMIConfParams, PRIVILEGE_USER);
Nagaraju Goruganti22be97b2018-02-07 01:19:59 -06001507
1508 // <Set DCMI Configuration Parameters>
Patrick Venture0b02be92018-08-31 11:55:55 -07001509 ipmi_register_callback(NETFUN_GRPEXT, dcmi::Commands::SET_CONF_PARAMS, NULL,
1510 setDCMIConfParams, PRIVILEGE_ADMIN);
Nagaraju Goruganti22be97b2018-02-07 01:19:59 -06001511
Chris Austen1810bec2015-10-13 12:12:39 -05001512 return;
1513}
Tom05732372016-09-06 17:21:23 +05301514// 956379