blob: cb14005d9d893fda8faf6d28e885ec447cfff87b [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
Johnathan Mantey74a21022018-12-13 13:17:56 -08005#include "user_channel/channel_layer.hpp"
Patrick Venture0b02be92018-08-31 11:55:55 -07006
William A. Kennington III194375f2018-12-14 02:14:33 -08007#include <ipmid/api.h>
Patrick Venture0b02be92018-08-31 11:55:55 -07008
9#include <bitset>
10#include <cmath>
11#include <fstream>
Vernon Mauery6a98fe72019-03-11 15:57:48 -070012#include <ipmid/utils.hpp>
Patrick Venture0b02be92018-08-31 11:55:55 -070013#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
Marri Devender Rao66c5fda2018-01-18 10:48:37 -060053constexpr auto SENSOR_VALUE_INTF = "xyz.openbmc_project.Sensor.Value";
54constexpr auto SENSOR_VALUE_PROP = "Value";
55constexpr auto SENSOR_SCALE_PROP = "Scale";
56
Andrew Geissler50c0c8f2017-07-11 16:18:51 -050057using namespace phosphor::logging;
William A. Kennington III4c008022018-10-12 17:18:14 -070058namespace variant_ns = sdbusplus::message::variant_ns;
Andrew Geissler50c0c8f2017-07-11 16:18:51 -050059
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
Kirill Pakhomov2c2af2c2018-11-06 16:06:10 +030068bool isDCMIPowerMgmtSupported()
69{
70 auto data = parseJSONConfig(gDCMICapabilitiesConfig);
71
72 return (gDCMIPowerMgmtSupported == data.value(gDCMIPowerMgmtCapability, 0));
73}
74
Andrew Geissler50c0c8f2017-07-11 16:18:51 -050075uint32_t getPcap(sdbusplus::bus::bus& bus)
76{
Patrick Venture0b02be92018-08-31 11:55:55 -070077 auto settingService = ipmi::getService(bus, PCAP_INTERFACE, PCAP_PATH);
Andrew Geissler50c0c8f2017-07-11 16:18:51 -050078
Patrick Venture0b02be92018-08-31 11:55:55 -070079 auto method = bus.new_method_call(settingService.c_str(), PCAP_PATH,
80 "org.freedesktop.DBus.Properties", "Get");
Andrew Geissler50c0c8f2017-07-11 16:18:51 -050081
82 method.append(PCAP_INTERFACE, POWER_CAP_PROP);
83 auto reply = bus.call(method);
84
85 if (reply.is_method_error())
86 {
87 log<level::ERR>("Error in getPcap prop");
Tom Josephb9d86f42017-07-26 18:03:47 +053088 elog<InternalFailure>();
Andrew Geissler50c0c8f2017-07-11 16:18:51 -050089 }
90 sdbusplus::message::variant<uint32_t> pcap;
91 reply.read(pcap);
92
William A. Kennington III4c008022018-10-12 17:18:14 -070093 return variant_ns::get<uint32_t>(pcap);
Andrew Geissler50c0c8f2017-07-11 16:18:51 -050094}
95
96bool getPcapEnabled(sdbusplus::bus::bus& bus)
97{
Patrick Venture0b02be92018-08-31 11:55:55 -070098 auto settingService = ipmi::getService(bus, PCAP_INTERFACE, PCAP_PATH);
Andrew Geissler50c0c8f2017-07-11 16:18:51 -050099
Patrick Venture0b02be92018-08-31 11:55:55 -0700100 auto method = bus.new_method_call(settingService.c_str(), PCAP_PATH,
101 "org.freedesktop.DBus.Properties", "Get");
Andrew Geissler50c0c8f2017-07-11 16:18:51 -0500102
103 method.append(PCAP_INTERFACE, POWER_CAP_ENABLE_PROP);
104 auto reply = bus.call(method);
105
106 if (reply.is_method_error())
107 {
108 log<level::ERR>("Error in getPcapEnabled prop");
Tom Josephb9d86f42017-07-26 18:03:47 +0530109 elog<InternalFailure>();
Andrew Geissler50c0c8f2017-07-11 16:18:51 -0500110 }
111 sdbusplus::message::variant<bool> pcapEnabled;
112 reply.read(pcapEnabled);
113
William A. Kennington III4c008022018-10-12 17:18:14 -0700114 return variant_ns::get<bool>(pcapEnabled);
Andrew Geissler50c0c8f2017-07-11 16:18:51 -0500115}
Chris Austen1810bec2015-10-13 12:12:39 -0500116
Tom Joseph46fa37d2017-07-26 18:11:55 +0530117void setPcap(sdbusplus::bus::bus& bus, const uint32_t powerCap)
118{
119 auto service = ipmi::getService(bus, PCAP_INTERFACE, PCAP_PATH);
120
Patrick Venture0b02be92018-08-31 11:55:55 -0700121 auto method = bus.new_method_call(service.c_str(), PCAP_PATH,
122 "org.freedesktop.DBus.Properties", "Set");
Tom Joseph46fa37d2017-07-26 18:11:55 +0530123
124 method.append(PCAP_INTERFACE, POWER_CAP_PROP);
125 method.append(sdbusplus::message::variant<uint32_t>(powerCap));
126
127 auto reply = bus.call(method);
128
129 if (reply.is_method_error())
130 {
131 log<level::ERR>("Error in setPcap property");
132 elog<InternalFailure>();
133 }
134}
135
Tom Joseph6c8d51b2017-07-26 18:18:06 +0530136void setPcapEnable(sdbusplus::bus::bus& bus, bool enabled)
137{
138 auto service = ipmi::getService(bus, PCAP_INTERFACE, PCAP_PATH);
139
Patrick Venture0b02be92018-08-31 11:55:55 -0700140 auto method = bus.new_method_call(service.c_str(), PCAP_PATH,
141 "org.freedesktop.DBus.Properties", "Set");
Tom Joseph6c8d51b2017-07-26 18:18:06 +0530142
143 method.append(PCAP_INTERFACE, POWER_CAP_ENABLE_PROP);
144 method.append(sdbusplus::message::variant<bool>(enabled));
145
146 auto reply = bus.call(method);
147
148 if (reply.is_method_error())
149 {
150 log<level::ERR>("Error in setPcapEnabled property");
151 elog<InternalFailure>();
152 }
153}
154
Tom Josephbe5eaa12017-07-12 19:54:44 +0530155void readAssetTagObjectTree(dcmi::assettag::ObjectTree& objectTree)
156{
157 static constexpr auto mapperBusName = "xyz.openbmc_project.ObjectMapper";
158 static constexpr auto mapperObjPath = "/xyz/openbmc_project/object_mapper";
159 static constexpr auto mapperIface = "xyz.openbmc_project.ObjectMapper";
160 static constexpr auto inventoryRoot = "/xyz/openbmc_project/inventory/";
161
162 sdbusplus::bus::bus bus{ipmid_get_sd_bus_connection()};
163 auto depth = 0;
164
Patrick Venture0b02be92018-08-31 11:55:55 -0700165 auto mapperCall = bus.new_method_call(mapperBusName, mapperObjPath,
166 mapperIface, "GetSubTree");
Tom Josephbe5eaa12017-07-12 19:54:44 +0530167
168 mapperCall.append(inventoryRoot);
169 mapperCall.append(depth);
170 mapperCall.append(std::vector<std::string>({dcmi::assetTagIntf}));
171
172 auto mapperReply = bus.call(mapperCall);
173 if (mapperReply.is_method_error())
174 {
175 log<level::ERR>("Error in mapper call");
176 elog<InternalFailure>();
177 }
178
179 mapperReply.read(objectTree);
180
181 if (objectTree.empty())
182 {
183 log<level::ERR>("AssetTag property is not populated");
184 elog<InternalFailure>();
185 }
186}
187
188std::string readAssetTag()
189{
190 sdbusplus::bus::bus bus{ipmid_get_sd_bus_connection()};
191 dcmi::assettag::ObjectTree objectTree;
192
193 // Read the object tree with the inventory root to figure out the object
194 // that has implemented the Asset tag interface.
195 readAssetTagObjectTree(objectTree);
196
197 auto method = bus.new_method_call(
Patrick Venture0b02be92018-08-31 11:55:55 -0700198 (objectTree.begin()->second.begin()->first).c_str(),
199 (objectTree.begin()->first).c_str(), dcmi::propIntf, "Get");
Tom Josephbe5eaa12017-07-12 19:54:44 +0530200 method.append(dcmi::assetTagIntf);
201 method.append(dcmi::assetTagProp);
202
203 auto reply = bus.call(method);
204 if (reply.is_method_error())
205 {
206 log<level::ERR>("Error in reading asset tag");
207 elog<InternalFailure>();
208 }
209
210 sdbusplus::message::variant<std::string> assetTag;
211 reply.read(assetTag);
212
William A. Kennington III4c008022018-10-12 17:18:14 -0700213 return variant_ns::get<std::string>(assetTag);
Tom Josephbe5eaa12017-07-12 19:54:44 +0530214}
215
Tom Josephbe5b9892017-07-15 00:55:23 +0530216void writeAssetTag(const std::string& assetTag)
217{
218 sdbusplus::bus::bus bus{ipmid_get_sd_bus_connection()};
219 dcmi::assettag::ObjectTree objectTree;
220
221 // Read the object tree with the inventory root to figure out the object
222 // that has implemented the Asset tag interface.
223 readAssetTagObjectTree(objectTree);
224
225 auto method = bus.new_method_call(
Patrick Venture0b02be92018-08-31 11:55:55 -0700226 (objectTree.begin()->second.begin()->first).c_str(),
227 (objectTree.begin()->first).c_str(), dcmi::propIntf, "Set");
Tom Josephbe5b9892017-07-15 00:55:23 +0530228 method.append(dcmi::assetTagIntf);
229 method.append(dcmi::assetTagProp);
230 method.append(sdbusplus::message::variant<std::string>(assetTag));
231
232 auto reply = bus.call(method);
233 if (reply.is_method_error())
234 {
235 log<level::ERR>("Error in writing asset tag");
236 elog<InternalFailure>();
237 }
238}
239
Vladislav Vovchenko8f7a6f62017-08-17 00:31:14 +0300240std::string getHostName(void)
241{
Patrick Venture0b02be92018-08-31 11:55:55 -0700242 sdbusplus::bus::bus bus{ipmid_get_sd_bus_connection()};
Vladislav Vovchenko8f7a6f62017-08-17 00:31:14 +0300243
244 auto service = ipmi::getService(bus, networkConfigIntf, networkConfigObj);
Patrick Venture0b02be92018-08-31 11:55:55 -0700245 auto value = ipmi::getDbusProperty(bus, service, networkConfigObj,
246 networkConfigIntf, hostNameProp);
Vladislav Vovchenko8f7a6f62017-08-17 00:31:14 +0300247
William A. Kennington III4c008022018-10-12 17:18:14 -0700248 return variant_ns::get<std::string>(value);
Vladislav Vovchenko8f7a6f62017-08-17 00:31:14 +0300249}
250
Nagaraju Goruganti22be97b2018-02-07 01:19:59 -0600251bool getDHCPEnabled()
252{
253 sdbusplus::bus::bus bus{ipmid_get_sd_bus_connection()};
254
Johnathan Mantey74a21022018-12-13 13:17:56 -0800255 auto ethdevice = ipmi::getChannelName(ethernetDefaultChannelNum);
Patrick Venture0b02be92018-08-31 11:55:55 -0700256 auto ethernetObj =
257 ipmi::getDbusObject(bus, ethernetIntf, networkRoot, ethdevice);
Nagaraju Goruganti22be97b2018-02-07 01:19:59 -0600258 auto service = ipmi::getService(bus, ethernetIntf, ethernetObj.first);
Patrick Venture0b02be92018-08-31 11:55:55 -0700259 auto value = ipmi::getDbusProperty(bus, service, ethernetObj.first,
260 ethernetIntf, "DHCPEnabled");
Nagaraju Goruganti22be97b2018-02-07 01:19:59 -0600261
William A. Kennington III4c008022018-10-12 17:18:14 -0700262 return variant_ns::get<bool>(value);
Nagaraju Goruganti22be97b2018-02-07 01:19:59 -0600263}
264
265bool getDHCPOption(std::string prop)
266{
267 sdbusplus::bus::bus bus{ipmid_get_sd_bus_connection()};
268
269 auto service = ipmi::getService(bus, dhcpIntf, dhcpObj);
270 auto value = ipmi::getDbusProperty(bus, service, dhcpObj, dhcpIntf, prop);
271
William A. Kennington III4c008022018-10-12 17:18:14 -0700272 return variant_ns::get<bool>(value);
Nagaraju Goruganti22be97b2018-02-07 01:19:59 -0600273}
274
Nagaraju Goruganti22be97b2018-02-07 01:19:59 -0600275void setDHCPOption(std::string prop, bool value)
276{
277 sdbusplus::bus::bus bus{ipmid_get_sd_bus_connection()};
278
279 auto service = ipmi::getService(bus, dhcpIntf, dhcpObj);
280 ipmi::setDbusProperty(bus, service, dhcpObj, dhcpIntf, prop, value);
281}
282
Kirill Pakhomova2573622018-11-02 19:00:18 +0300283Json parseJSONConfig(const std::string& configFile)
Deepak Kodihalli0b459552018-02-06 06:25:12 -0600284{
285 std::ifstream jsonFile(configFile);
286 if (!jsonFile.is_open())
287 {
288 log<level::ERR>("Temperature readings JSON file not found");
289 elog<InternalFailure>();
290 }
291
292 auto data = Json::parse(jsonFile, nullptr, false);
293 if (data.is_discarded())
294 {
295 log<level::ERR>("Temperature readings JSON parser failure");
296 elog<InternalFailure>();
297 }
298
299 return data;
300}
301
Tom Josephbe5eaa12017-07-12 19:54:44 +0530302} // namespace dcmi
Chris Austen1810bec2015-10-13 12:12:39 -0500303
Tom Josephb9d86f42017-07-26 18:03:47 +0530304ipmi_ret_t getPowerLimit(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
305 ipmi_request_t request, ipmi_response_t response,
306 ipmi_data_len_t data_len, ipmi_context_t context)
307{
Kirill Pakhomov2c2af2c2018-11-06 16:06:10 +0300308 if (!dcmi::isDCMIPowerMgmtSupported())
309 {
310 *data_len = 0;
311 log<level::ERR>("DCMI Power management is unsupported!");
312 return IPMI_CC_INVALID;
313 }
314
Patrick Venture0b02be92018-08-31 11:55:55 -0700315 auto requestData =
316 reinterpret_cast<const dcmi::GetPowerLimitRequest*>(request);
Tom Josephb9d86f42017-07-26 18:03:47 +0530317 std::vector<uint8_t> outPayload(sizeof(dcmi::GetPowerLimitResponse));
Patrick Venture0b02be92018-08-31 11:55:55 -0700318 auto responseData =
319 reinterpret_cast<dcmi::GetPowerLimitResponse*>(outPayload.data());
Tom Josephb9d86f42017-07-26 18:03:47 +0530320
321 if (requestData->groupID != dcmi::groupExtId)
322 {
323 *data_len = 0;
324 return IPMI_CC_INVALID_FIELD_REQUEST;
325 }
326
Patrick Venture0b02be92018-08-31 11:55:55 -0700327 sdbusplus::bus::bus sdbus{ipmid_get_sd_bus_connection()};
Tom Josephb9d86f42017-07-26 18:03:47 +0530328 uint32_t pcapValue = 0;
329 bool pcapEnable = false;
330
331 try
332 {
333 pcapValue = dcmi::getPcap(sdbus);
334 pcapEnable = dcmi::getPcapEnabled(sdbus);
335 }
336 catch (InternalFailure& e)
337 {
338 *data_len = 0;
339 return IPMI_CC_UNSPECIFIED_ERROR;
340 }
341
342 responseData->groupID = dcmi::groupExtId;
343
344 /*
345 * Exception action if power limit is exceeded and cannot be controlled
346 * with the correction time limit is hardcoded to Hard Power Off system
347 * and log event to SEL.
348 */
349 constexpr auto exception = 0x01;
350 responseData->exceptionAction = exception;
351
352 responseData->powerLimit = static_cast<uint16_t>(pcapValue);
353
354 /*
355 * Correction time limit and Statistics sampling period is currently not
356 * populated.
357 */
358
359 *data_len = outPayload.size();
360 memcpy(response, outPayload.data(), *data_len);
361
362 if (pcapEnable)
363 {
364 return IPMI_CC_OK;
365 }
366 else
367 {
368 return IPMI_DCMI_CC_NO_ACTIVE_POWER_LIMIT;
369 }
370}
371
Tom Joseph46fa37d2017-07-26 18:11:55 +0530372ipmi_ret_t setPowerLimit(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
373 ipmi_request_t request, ipmi_response_t response,
374 ipmi_data_len_t data_len, ipmi_context_t context)
375{
Kirill Pakhomov2c2af2c2018-11-06 16:06:10 +0300376 if (!dcmi::isDCMIPowerMgmtSupported())
377 {
378 *data_len = 0;
379 log<level::ERR>("DCMI Power management is unsupported!");
380 return IPMI_CC_INVALID;
381 }
382
Patrick Venture0b02be92018-08-31 11:55:55 -0700383 auto requestData =
384 reinterpret_cast<const dcmi::SetPowerLimitRequest*>(request);
Tom Joseph46fa37d2017-07-26 18:11:55 +0530385 std::vector<uint8_t> outPayload(sizeof(dcmi::SetPowerLimitResponse));
Patrick Venture0b02be92018-08-31 11:55:55 -0700386 auto responseData =
387 reinterpret_cast<dcmi::SetPowerLimitResponse*>(outPayload.data());
Tom Joseph46fa37d2017-07-26 18:11:55 +0530388
389 if (requestData->groupID != dcmi::groupExtId)
390 {
391 *data_len = 0;
392 return IPMI_CC_INVALID_FIELD_REQUEST;
393 }
394
Patrick Venture0b02be92018-08-31 11:55:55 -0700395 sdbusplus::bus::bus sdbus{ipmid_get_sd_bus_connection()};
Tom Joseph46fa37d2017-07-26 18:11:55 +0530396
397 // Only process the power limit requested in watts.
398 try
399 {
400 dcmi::setPcap(sdbus, requestData->powerLimit);
401 }
402 catch (InternalFailure& e)
403 {
404 *data_len = 0;
405 return IPMI_CC_UNSPECIFIED_ERROR;
406 }
407
408 log<level::INFO>("Set Power Cap",
409 entry("POWERCAP=%u", requestData->powerLimit));
410
411 responseData->groupID = dcmi::groupExtId;
412 memcpy(response, outPayload.data(), outPayload.size());
413 *data_len = outPayload.size();
414
415 return IPMI_CC_OK;
416}
417
Tom Joseph6c8d51b2017-07-26 18:18:06 +0530418ipmi_ret_t applyPowerLimit(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
419 ipmi_request_t request, ipmi_response_t response,
420 ipmi_data_len_t data_len, ipmi_context_t context)
421{
Kirill Pakhomov2c2af2c2018-11-06 16:06:10 +0300422 if (!dcmi::isDCMIPowerMgmtSupported())
423 {
424 *data_len = 0;
425 log<level::ERR>("DCMI Power management is unsupported!");
426 return IPMI_CC_INVALID;
427 }
428
Patrick Venture0b02be92018-08-31 11:55:55 -0700429 auto requestData =
430 reinterpret_cast<const dcmi::ApplyPowerLimitRequest*>(request);
Tom Joseph6c8d51b2017-07-26 18:18:06 +0530431 std::vector<uint8_t> outPayload(sizeof(dcmi::ApplyPowerLimitResponse));
Patrick Venture0b02be92018-08-31 11:55:55 -0700432 auto responseData =
433 reinterpret_cast<dcmi::ApplyPowerLimitResponse*>(outPayload.data());
Tom Joseph6c8d51b2017-07-26 18:18:06 +0530434
435 if (requestData->groupID != dcmi::groupExtId)
436 {
437 *data_len = 0;
438 return IPMI_CC_INVALID_FIELD_REQUEST;
439 }
440
Patrick Venture0b02be92018-08-31 11:55:55 -0700441 sdbusplus::bus::bus sdbus{ipmid_get_sd_bus_connection()};
Tom Joseph6c8d51b2017-07-26 18:18:06 +0530442
443 try
444 {
445 dcmi::setPcapEnable(sdbus,
446 static_cast<bool>(requestData->powerLimitAction));
447 }
448 catch (InternalFailure& e)
449 {
450 *data_len = 0;
451 return IPMI_CC_UNSPECIFIED_ERROR;
452 }
453
454 log<level::INFO>("Set Power Cap Enable",
455 entry("POWERCAPENABLE=%u", requestData->powerLimitAction));
456
457 responseData->groupID = dcmi::groupExtId;
458 memcpy(response, outPayload.data(), outPayload.size());
459 *data_len = outPayload.size();
460
461 return IPMI_CC_OK;
462}
463
Tom Joseph6f6dd4d2017-07-12 20:07:11 +0530464ipmi_ret_t getAssetTag(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
465 ipmi_request_t request, ipmi_response_t response,
466 ipmi_data_len_t data_len, ipmi_context_t context)
467{
Patrick Venture0b02be92018-08-31 11:55:55 -0700468 auto requestData =
469 reinterpret_cast<const dcmi::GetAssetTagRequest*>(request);
Tom Joseph6f6dd4d2017-07-12 20:07:11 +0530470 std::vector<uint8_t> outPayload(sizeof(dcmi::GetAssetTagResponse));
Patrick Venture0b02be92018-08-31 11:55:55 -0700471 auto responseData =
472 reinterpret_cast<dcmi::GetAssetTagResponse*>(outPayload.data());
Tom Joseph6f6dd4d2017-07-12 20:07:11 +0530473
474 if (requestData->groupID != dcmi::groupExtId)
475 {
476 *data_len = 0;
477 return IPMI_CC_INVALID_FIELD_REQUEST;
478 }
479
480 // Verify offset to read and number of bytes to read are not exceeding the
481 // range.
482 if ((requestData->offset > dcmi::assetTagMaxOffset) ||
483 (requestData->bytes > dcmi::maxBytes) ||
484 ((requestData->offset + requestData->bytes) > dcmi::assetTagMaxSize))
485 {
486 *data_len = 0;
487 return IPMI_CC_PARM_OUT_OF_RANGE;
488 }
489
490 std::string assetTag;
491
492 try
493 {
494 assetTag = dcmi::readAssetTag();
495 }
496 catch (InternalFailure& e)
497 {
498 *data_len = 0;
499 return IPMI_CC_UNSPECIFIED_ERROR;
500 }
501
502 responseData->groupID = dcmi::groupExtId;
503
504 // Return if the asset tag is not populated.
505 if (!assetTag.size())
506 {
507 responseData->tagLength = 0;
508 memcpy(response, outPayload.data(), outPayload.size());
509 *data_len = outPayload.size();
510 return IPMI_CC_OK;
511 }
512
513 // If the asset tag is longer than 63 bytes, restrict it to 63 bytes to suit
514 // Get Asset Tag command.
515 if (assetTag.size() > dcmi::assetTagMaxSize)
516 {
517 assetTag.resize(dcmi::assetTagMaxSize);
518 }
519
520 // If the requested offset is beyond the asset tag size.
521 if (requestData->offset >= assetTag.size())
522 {
523 *data_len = 0;
524 return IPMI_CC_PARM_OUT_OF_RANGE;
525 }
526
527 auto returnData = assetTag.substr(requestData->offset, requestData->bytes);
528
529 responseData->tagLength = assetTag.size();
530
531 memcpy(response, outPayload.data(), outPayload.size());
532 memcpy(static_cast<uint8_t*>(response) + outPayload.size(),
533 returnData.data(), returnData.size());
534 *data_len = outPayload.size() + returnData.size();
535
536 return IPMI_CC_OK;
537}
538
Tom Joseph545dd232017-07-12 20:20:49 +0530539ipmi_ret_t setAssetTag(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
540 ipmi_request_t request, ipmi_response_t response,
541 ipmi_data_len_t data_len, ipmi_context_t context)
542{
Patrick Venture0b02be92018-08-31 11:55:55 -0700543 auto requestData =
544 reinterpret_cast<const dcmi::SetAssetTagRequest*>(request);
Tom Joseph545dd232017-07-12 20:20:49 +0530545 std::vector<uint8_t> outPayload(sizeof(dcmi::SetAssetTagResponse));
Patrick Venture0b02be92018-08-31 11:55:55 -0700546 auto responseData =
547 reinterpret_cast<dcmi::SetAssetTagResponse*>(outPayload.data());
Tom Joseph545dd232017-07-12 20:20:49 +0530548
549 if (requestData->groupID != dcmi::groupExtId)
550 {
551 *data_len = 0;
552 return IPMI_CC_INVALID_FIELD_REQUEST;
553 }
554
555 // Verify offset to read and number of bytes to read are not exceeding the
556 // range.
557 if ((requestData->offset > dcmi::assetTagMaxOffset) ||
558 (requestData->bytes > dcmi::maxBytes) ||
559 ((requestData->offset + requestData->bytes) > dcmi::assetTagMaxSize))
560 {
561 *data_len = 0;
562 return IPMI_CC_PARM_OUT_OF_RANGE;
563 }
564
565 std::string assetTag;
566
567 try
568 {
569 assetTag = dcmi::readAssetTag();
570
571 if (requestData->offset > assetTag.size())
572 {
573 *data_len = 0;
574 return IPMI_CC_PARM_OUT_OF_RANGE;
575 }
576
577 assetTag.replace(requestData->offset,
578 assetTag.size() - requestData->offset,
579 static_cast<const char*>(request) +
Patrick Venture0b02be92018-08-31 11:55:55 -0700580 sizeof(dcmi::SetAssetTagRequest),
Tom Joseph545dd232017-07-12 20:20:49 +0530581 requestData->bytes);
582
583 dcmi::writeAssetTag(assetTag);
584
585 responseData->groupID = dcmi::groupExtId;
586 responseData->tagLength = assetTag.size();
587 memcpy(response, outPayload.data(), outPayload.size());
588 *data_len = outPayload.size();
589
590 return IPMI_CC_OK;
591 }
592 catch (InternalFailure& e)
593 {
594 *data_len = 0;
595 return IPMI_CC_UNSPECIFIED_ERROR;
596 }
597}
598
Vladislav Vovchenko8f7a6f62017-08-17 00:31:14 +0300599ipmi_ret_t getMgmntCtrlIdStr(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
Patrick Venture0b02be92018-08-31 11:55:55 -0700600 ipmi_request_t request, ipmi_response_t response,
601 ipmi_data_len_t data_len, ipmi_context_t context)
Vladislav Vovchenko8f7a6f62017-08-17 00:31:14 +0300602{
Patrick Venture0b02be92018-08-31 11:55:55 -0700603 auto requestData =
604 reinterpret_cast<const dcmi::GetMgmntCtrlIdStrRequest*>(request);
605 auto responseData =
606 reinterpret_cast<dcmi::GetMgmntCtrlIdStrResponse*>(response);
Vladislav Vovchenko8f7a6f62017-08-17 00:31:14 +0300607 std::string hostName;
608
609 *data_len = 0;
610
611 if (requestData->groupID != dcmi::groupExtId ||
612 requestData->bytes > dcmi::maxBytes ||
613 requestData->offset + requestData->bytes > dcmi::maxCtrlIdStrLen)
614 {
615 return IPMI_CC_INVALID_FIELD_REQUEST;
616 }
617
618 try
619 {
620 hostName = dcmi::getHostName();
621 }
622 catch (InternalFailure& e)
623 {
624 return IPMI_CC_UNSPECIFIED_ERROR;
625 }
626
627 if (requestData->offset > hostName.length())
628 {
629 return IPMI_CC_PARM_OUT_OF_RANGE;
630 }
631 auto responseStr = hostName.substr(requestData->offset, requestData->bytes);
632 auto responseStrLen = std::min(static_cast<std::size_t>(requestData->bytes),
Patrick Venture0b02be92018-08-31 11:55:55 -0700633 responseStr.length() + 1);
Vladislav Vovchenko8f7a6f62017-08-17 00:31:14 +0300634 responseData->groupID = dcmi::groupExtId;
635 responseData->strLen = hostName.length();
636 std::copy(begin(responseStr), end(responseStr), responseData->data);
637
638 *data_len = sizeof(*responseData) + responseStrLen;
639 return IPMI_CC_OK;
640}
641
642ipmi_ret_t setMgmntCtrlIdStr(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
Patrick Venture0b02be92018-08-31 11:55:55 -0700643 ipmi_request_t request, ipmi_response_t response,
644 ipmi_data_len_t data_len, ipmi_context_t context)
Vladislav Vovchenko8f7a6f62017-08-17 00:31:14 +0300645{
646 static std::array<char, dcmi::maxCtrlIdStrLen + 1> newCtrlIdStr;
647
Patrick Venture0b02be92018-08-31 11:55:55 -0700648 auto requestData =
649 reinterpret_cast<const dcmi::SetMgmntCtrlIdStrRequest*>(request);
650 auto responseData =
651 reinterpret_cast<dcmi::SetMgmntCtrlIdStrResponse*>(response);
Vladislav Vovchenko8f7a6f62017-08-17 00:31:14 +0300652
653 *data_len = 0;
654
655 if (requestData->groupID != dcmi::groupExtId ||
656 requestData->bytes > dcmi::maxBytes ||
657 requestData->offset + requestData->bytes > dcmi::maxCtrlIdStrLen + 1 ||
Patrick Venture0b02be92018-08-31 11:55:55 -0700658 (requestData->offset + requestData->bytes ==
659 dcmi::maxCtrlIdStrLen + 1 &&
660 requestData->data[requestData->bytes - 1] != '\0'))
Vladislav Vovchenko8f7a6f62017-08-17 00:31:14 +0300661 {
662 return IPMI_CC_INVALID_FIELD_REQUEST;
663 }
664
665 try
666 {
667 /* if there is no old value and offset is not 0 */
668 if (newCtrlIdStr[0] == '\0' && requestData->offset != 0)
669 {
670 /* read old ctrlIdStr */
671 auto hostName = dcmi::getHostName();
672 hostName.resize(dcmi::maxCtrlIdStrLen);
673 std::copy(begin(hostName), end(hostName), begin(newCtrlIdStr));
674 newCtrlIdStr[hostName.length()] = '\0';
675 }
676
677 /* replace part of string and mark byte after the last as \0 */
Patrick Venture0b02be92018-08-31 11:55:55 -0700678 auto restStrIter =
679 std::copy_n(requestData->data, requestData->bytes,
680 begin(newCtrlIdStr) + requestData->offset);
Vladislav Vovchenko8f7a6f62017-08-17 00:31:14 +0300681 /* if the last written byte is not 64th - add '\0' */
682 if (requestData->offset + requestData->bytes <= dcmi::maxCtrlIdStrLen)
683 {
684 *restStrIter = '\0';
685 }
686
687 /* if input data contains '\0' whole string is sent - update hostname */
688 auto it = std::find(requestData->data,
Patrick Venture0b02be92018-08-31 11:55:55 -0700689 requestData->data + requestData->bytes, '\0');
Vladislav Vovchenko8f7a6f62017-08-17 00:31:14 +0300690 if (it != requestData->data + requestData->bytes)
691 {
Patrick Venture0b02be92018-08-31 11:55:55 -0700692 sdbusplus::bus::bus bus{ipmid_get_sd_bus_connection()};
Vladislav Vovchenko8f7a6f62017-08-17 00:31:14 +0300693 ipmi::setDbusProperty(bus, dcmi::networkServiceName,
Patrick Venture0b02be92018-08-31 11:55:55 -0700694 dcmi::networkConfigObj,
695 dcmi::networkConfigIntf, dcmi::hostNameProp,
696 std::string(newCtrlIdStr.data()));
Vladislav Vovchenko8f7a6f62017-08-17 00:31:14 +0300697 }
698 }
699 catch (InternalFailure& e)
700 {
701 *data_len = 0;
702 return IPMI_CC_UNSPECIFIED_ERROR;
703 }
704
705 responseData->groupID = dcmi::groupExtId;
706 responseData->offset = requestData->offset + requestData->bytes;
707 *data_len = sizeof(*responseData);
708 return IPMI_CC_OK;
709}
710
Patrick Venture0b02be92018-08-31 11:55:55 -0700711// List of the capabilities under each parameter
712dcmi::DCMICaps dcmiCaps = {
713 // Supported DCMI Capabilities
714 {dcmi::DCMICapParameters::SUPPORTED_DCMI_CAPS,
715 {3,
716 {{"PowerManagement", 2, 0, 1},
717 {"OOBSecondaryLan", 3, 2, 1},
718 {"SerialTMODE", 3, 1, 1},
719 {"InBandSystemInterfaceChannel", 3, 0, 1}}}},
720 // Mandatory Platform Attributes
721 {dcmi::DCMICapParameters::MANDATORY_PLAT_ATTRIBUTES,
722 {5,
723 {{"SELAutoRollOver", 1, 15, 1},
724 {"FlushEntireSELUponRollOver", 1, 14, 1},
725 {"RecordLevelSELFlushUponRollOver", 1, 13, 1},
726 {"NumberOfSELEntries", 1, 0, 12},
727 {"TempMonitoringSamplingFreq", 5, 0, 8}}}},
728 // Optional Platform Attributes
729 {dcmi::DCMICapParameters::OPTIONAL_PLAT_ATTRIBUTES,
730 {2,
731 {{"PowerMgmtDeviceSlaveAddress", 1, 1, 7},
732 {"BMCChannelNumber", 2, 4, 4},
733 {"DeviceRivision", 2, 0, 4}}}},
734 // Manageability Access Attributes
735 {dcmi::DCMICapParameters::MANAGEABILITY_ACCESS_ATTRIBUTES,
736 {3,
737 {{"MandatoryPrimaryLanOOBSupport", 1, 0, 8},
738 {"OptionalSecondaryLanOOBSupport", 2, 0, 8},
739 {"OptionalSerialOOBMTMODECapability", 3, 0, 8}}}}};
Dhruvaraj Subhashchandrane29be412018-01-16 05:11:56 -0600740
741ipmi_ret_t getDCMICapabilities(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
742 ipmi_request_t request, ipmi_response_t response,
743 ipmi_data_len_t data_len, ipmi_context_t context)
744{
745
Kirill Pakhomova2573622018-11-02 19:00:18 +0300746 std::ifstream dcmiCapFile(dcmi::gDCMICapabilitiesConfig);
Dhruvaraj Subhashchandrane29be412018-01-16 05:11:56 -0600747 if (!dcmiCapFile.is_open())
748 {
749 log<level::ERR>("DCMI Capabilities file not found");
750 return IPMI_CC_UNSPECIFIED_ERROR;
751 }
752
753 auto data = nlohmann::json::parse(dcmiCapFile, nullptr, false);
754 if (data.is_discarded())
755 {
756 log<level::ERR>("DCMI Capabilities JSON parser failure");
757 return IPMI_CC_UNSPECIFIED_ERROR;
758 }
759
Patrick Venture0b02be92018-08-31 11:55:55 -0700760 auto requestData =
761 reinterpret_cast<const dcmi::GetDCMICapRequest*>(request);
Dhruvaraj Subhashchandrane29be412018-01-16 05:11:56 -0600762
Patrick Venture0b02be92018-08-31 11:55:55 -0700763 // get list of capabilities in a parameter
Dhruvaraj Subhashchandrane29be412018-01-16 05:11:56 -0600764 auto caps =
765 dcmiCaps.find(static_cast<dcmi::DCMICapParameters>(requestData->param));
766 if (caps == dcmiCaps.end())
767 {
768 log<level::ERR>("Invalid input parameter");
769 return IPMI_CC_INVALID_FIELD_REQUEST;
770 }
771
772 if (requestData->groupID != dcmi::groupExtId)
773 {
774 *data_len = 0;
775 return IPMI_CC_INVALID_FIELD_REQUEST;
776 }
777
Patrick Venture0b02be92018-08-31 11:55:55 -0700778 auto responseData = reinterpret_cast<dcmi::GetDCMICapResponse*>(response);
Dhruvaraj Subhashchandrane29be412018-01-16 05:11:56 -0600779
Patrick Venture0b02be92018-08-31 11:55:55 -0700780 // For each capabilities in a parameter fill the data from
781 // the json file based on the capability name.
Dhruvaraj Subhashchandrane29be412018-01-16 05:11:56 -0600782 for (auto cap : caps->second.capList)
783 {
Patrick Venture0b02be92018-08-31 11:55:55 -0700784 // If the data is beyond first byte boundary, insert in a
785 // 16bit pattern for example number of SEL entries are represented
786 // in 12bits.
Kirill Pakhomovdb5d9b02018-11-06 19:17:51 +0300787 if ((cap.length + cap.position) > dcmi::gByteBitSize)
Dhruvaraj Subhashchandrane29be412018-01-16 05:11:56 -0600788 {
Kirill Pakhomovdb5d9b02018-11-06 19:17:51 +0300789 uint16_t val = data.value(cap.name.c_str(), 0);
790 // According to DCMI spec v1.5, max number of SEL entries is
791 // 4096, but bit 12b of DCMI capabilities Mandatory Platform
792 // Attributes field is reserved and therefore we can use only
793 // the provided 12 bits with maximum value of 4095.
794 // We're playing safe here by applying the mask
795 // to ensure that provided value will fit into 12 bits.
796 if (cap.length > dcmi::gByteBitSize)
797 {
798 val &= dcmi::gMaxSELEntriesMask;
799 }
Dhruvaraj Subhashchandrane29be412018-01-16 05:11:56 -0600800 val <<= cap.position;
Kirill Pakhomovdb5d9b02018-11-06 19:17:51 +0300801 responseData->data[cap.bytePosition - 1] |=
802 static_cast<uint8_t>(val);
803 responseData->data[cap.bytePosition] |= val >> dcmi::gByteBitSize;
Dhruvaraj Subhashchandrane29be412018-01-16 05:11:56 -0600804 }
805 else
806 {
807 responseData->data[cap.bytePosition - 1] |=
808 data.value(cap.name.c_str(), 0) << cap.position;
809 }
810 }
811
812 responseData->groupID = dcmi::groupExtId;
813 responseData->major = DCMI_SPEC_MAJOR_VERSION;
814 responseData->minor = DCMI_SPEC_MINOR_VERSION;
815 responseData->paramRevision = DCMI_PARAMETER_REVISION;
816 *data_len = sizeof(*responseData) + caps->second.size;
817
818 return IPMI_CC_OK;
819}
820
Deepak Kodihalliee717d72018-01-24 04:53:09 -0600821namespace dcmi
822{
823namespace temp_readings
824{
825
Deepak Kodihallib1e8fba2018-01-24 04:57:10 -0600826Temperature readTemp(const std::string& dbusService,
827 const std::string& dbusPath)
828{
829 // Read the temperature value from d-bus object. Need some conversion.
830 // As per the interface xyz.openbmc_project.Sensor.Value, the temperature
James Feist9cc0ea52018-10-09 10:53:11 -0700831 // is an double and in degrees C. It needs to be scaled by using the
Deepak Kodihallib1e8fba2018-01-24 04:57:10 -0600832 // formula Value * 10^Scale. The ipmi spec has the temperature as a uint8_t,
833 // with a separate single bit for the sign.
834
835 sdbusplus::bus::bus bus{ipmid_get_sd_bus_connection()};
Patrick Venture0b02be92018-08-31 11:55:55 -0700836 auto result = ipmi::getAllDbusProperties(
837 bus, dbusService, dbusPath, "xyz.openbmc_project.Sensor.Value");
James Feist9cc0ea52018-10-09 10:53:11 -0700838 auto temperature = sdbusplus::message::variant_ns::visit(
839 ipmi::VariantToDoubleVisitor(), result.at("Value"));
840 double absTemp = std::abs(temperature);
Deepak Kodihallib1e8fba2018-01-24 04:57:10 -0600841
James Feist9cc0ea52018-10-09 10:53:11 -0700842 auto findFactor = result.find("Scale");
843 double factor = 0.0;
844 if (findFactor != result.end())
Deepak Kodihallib1e8fba2018-01-24 04:57:10 -0600845 {
James Feist9cc0ea52018-10-09 10:53:11 -0700846 factor = sdbusplus::message::variant_ns::visit(
847 ipmi::VariantToDoubleVisitor(), findFactor->second);
Deepak Kodihallib1e8fba2018-01-24 04:57:10 -0600848 }
James Feist9cc0ea52018-10-09 10:53:11 -0700849 double scale = std::pow(10, factor);
850
851 auto tempDegrees = absTemp * scale;
Deepak Kodihallib1e8fba2018-01-24 04:57:10 -0600852 // Max absolute temp as per ipmi spec is 128.
853 if (tempDegrees > maxTemp)
854 {
855 tempDegrees = maxTemp;
856 }
857
858 return std::make_tuple(static_cast<uint8_t>(tempDegrees),
859 (temperature < 0));
860}
861
Deepak Kodihalliee717d72018-01-24 04:53:09 -0600862std::tuple<Response, NumInstances> read(const std::string& type,
863 uint8_t instance)
864{
Deepak Kodihallib1e8fba2018-01-24 04:57:10 -0600865 Response response{};
866 sdbusplus::bus::bus bus{ipmid_get_sd_bus_connection()};
867
868 if (!instance)
869 {
870 log<level::ERR>("Expected non-zero instance");
871 elog<InternalFailure>();
872 }
873
Kirill Pakhomova2573622018-11-02 19:00:18 +0300874 auto data = parseJSONConfig(gDCMISensorsConfig);
Deepak Kodihallib1e8fba2018-01-24 04:57:10 -0600875 static const std::vector<Json> empty{};
876 std::vector<Json> readings = data.value(type, empty);
877 size_t numInstances = readings.size();
878 for (const auto& j : readings)
879 {
880 uint8_t instanceNum = j.value("instance", 0);
881 // Not the instance we're interested in
882 if (instanceNum != instance)
883 {
884 continue;
885 }
886
887 std::string path = j.value("dbus", "");
888 std::string service;
889 try
890 {
891 service =
Patrick Venture0b02be92018-08-31 11:55:55 -0700892 ipmi::getService(bus, "xyz.openbmc_project.Sensor.Value", path);
Deepak Kodihallib1e8fba2018-01-24 04:57:10 -0600893 }
894 catch (std::exception& e)
895 {
896 log<level::DEBUG>(e.what());
897 return std::make_tuple(response, numInstances);
898 }
899
900 response.instance = instance;
901 uint8_t temp{};
902 bool sign{};
903 std::tie(temp, sign) = readTemp(service, path);
904 response.temperature = temp;
905 response.sign = sign;
906
907 // Found the instance we're interested in
908 break;
909 }
910
911 if (numInstances > maxInstances)
912 {
913 numInstances = maxInstances;
914 }
915 return std::make_tuple(response, numInstances);
Deepak Kodihalliee717d72018-01-24 04:53:09 -0600916}
917
918std::tuple<ResponseList, NumInstances> readAll(const std::string& type,
919 uint8_t instanceStart)
920{
Deepak Kodihallib1e8fba2018-01-24 04:57:10 -0600921 ResponseList response{};
922 sdbusplus::bus::bus bus{ipmid_get_sd_bus_connection()};
923
924 size_t numInstances = 0;
Kirill Pakhomova2573622018-11-02 19:00:18 +0300925 auto data = parseJSONConfig(gDCMISensorsConfig);
Deepak Kodihallib1e8fba2018-01-24 04:57:10 -0600926 static const std::vector<Json> empty{};
927 std::vector<Json> readings = data.value(type, empty);
928 numInstances = readings.size();
929 for (const auto& j : readings)
930 {
931 try
932 {
933 // Max of 8 response data sets
934 if (response.size() == maxDataSets)
935 {
936 break;
937 }
938
939 uint8_t instanceNum = j.value("instance", 0);
940 // Not in the instance range we're interested in
941 if (instanceNum < instanceStart)
942 {
943 continue;
944 }
945
946 std::string path = j.value("dbus", "");
947 auto service =
Patrick Venture0b02be92018-08-31 11:55:55 -0700948 ipmi::getService(bus, "xyz.openbmc_project.Sensor.Value", path);
Deepak Kodihallib1e8fba2018-01-24 04:57:10 -0600949
950 Response r{};
951 r.instance = instanceNum;
952 uint8_t temp{};
953 bool sign{};
954 std::tie(temp, sign) = readTemp(service, path);
955 r.temperature = temp;
956 r.sign = sign;
957 response.push_back(r);
958 }
959 catch (std::exception& e)
960 {
961 log<level::DEBUG>(e.what());
962 continue;
963 }
964 }
965
966 if (numInstances > maxInstances)
967 {
968 numInstances = maxInstances;
969 }
970 return std::make_tuple(response, numInstances);
Deepak Kodihalliee717d72018-01-24 04:53:09 -0600971}
972
Patrick Venture0b02be92018-08-31 11:55:55 -0700973} // namespace temp_readings
974} // namespace dcmi
Deepak Kodihalliee717d72018-01-24 04:53:09 -0600975
976ipmi_ret_t getTempReadings(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
Patrick Venture0b02be92018-08-31 11:55:55 -0700977 ipmi_request_t request, ipmi_response_t response,
978 ipmi_data_len_t data_len, ipmi_context_t context)
Deepak Kodihalliee717d72018-01-24 04:53:09 -0600979{
Deepak Kodihalliee717d72018-01-24 04:53:09 -0600980 auto requestData =
981 reinterpret_cast<const dcmi::GetTempReadingsRequest*>(request);
982 auto responseData =
983 reinterpret_cast<dcmi::GetTempReadingsResponseHdr*>(response);
984
985 if (*data_len != sizeof(dcmi::GetTempReadingsRequest))
986 {
987 log<level::ERR>("Malformed request data",
988 entry("DATA_SIZE=%d", *data_len));
989 return IPMI_CC_REQ_DATA_LEN_INVALID;
990 }
991 *data_len = 0;
992
Deepak Kodihalli0b459552018-02-06 06:25:12 -0600993 auto it = dcmi::entityIdToName.find(requestData->entityId);
994 if (it == dcmi::entityIdToName.end())
Deepak Kodihalliee717d72018-01-24 04:53:09 -0600995 {
996 log<level::ERR>("Unknown Entity ID",
997 entry("ENTITY_ID=%d", requestData->entityId));
998 return IPMI_CC_INVALID_FIELD_REQUEST;
999 }
1000
1001 if (requestData->groupID != dcmi::groupExtId)
1002 {
1003 log<level::ERR>("Invalid Group ID",
1004 entry("GROUP_ID=%d", requestData->groupID));
1005 return IPMI_CC_INVALID_FIELD_REQUEST;
1006 }
1007
1008 if (requestData->sensorType != dcmi::temperatureSensorType)
1009 {
1010 log<level::ERR>("Invalid sensor type",
1011 entry("SENSOR_TYPE=%d", requestData->sensorType));
1012 return IPMI_CC_INVALID_FIELD_REQUEST;
1013 }
1014
1015 dcmi::temp_readings::ResponseList temps{};
1016 try
1017 {
1018 if (!requestData->entityInstance)
1019 {
1020 // Read all instances
1021 std::tie(temps, responseData->numInstances) =
1022 dcmi::temp_readings::readAll(it->second,
1023 requestData->instanceStart);
1024 }
1025 else
1026 {
1027 // Read one instance
1028 temps.resize(1);
1029 std::tie(temps[0], responseData->numInstances) =
1030 dcmi::temp_readings::read(it->second,
1031 requestData->entityInstance);
1032 }
1033 responseData->numDataSets = temps.size();
1034 }
1035 catch (InternalFailure& e)
1036 {
1037 return IPMI_CC_UNSPECIFIED_ERROR;
1038 }
1039
1040 responseData->groupID = dcmi::groupExtId;
Patrick Venture0b02be92018-08-31 11:55:55 -07001041 size_t payloadSize = temps.size() * sizeof(dcmi::temp_readings::Response);
Deepak Kodihalliee717d72018-01-24 04:53:09 -06001042 if (!temps.empty())
1043 {
1044 memcpy(responseData + 1, // copy payload right after the response header
Patrick Venture0b02be92018-08-31 11:55:55 -07001045 temps.data(), payloadSize);
Deepak Kodihalliee717d72018-01-24 04:53:09 -06001046 }
1047 *data_len = sizeof(dcmi::GetTempReadingsResponseHdr) + payloadSize;
1048
1049 return IPMI_CC_OK;
1050}
1051
Marri Devender Rao66c5fda2018-01-18 10:48:37 -06001052int64_t getPowerReading(sdbusplus::bus::bus& bus)
1053{
1054 std::ifstream sensorFile(POWER_READING_SENSOR);
1055 std::string objectPath;
1056 if (!sensorFile.is_open())
1057 {
1058 log<level::ERR>("Power reading configuration file not found",
Patrick Venture0b02be92018-08-31 11:55:55 -07001059 entry("POWER_SENSOR_FILE=%s", POWER_READING_SENSOR));
Marri Devender Rao66c5fda2018-01-18 10:48:37 -06001060 elog<InternalFailure>();
1061 }
1062
1063 auto data = nlohmann::json::parse(sensorFile, nullptr, false);
1064 if (data.is_discarded())
1065 {
1066 log<level::ERR>("Error in parsing configuration file",
Patrick Venture0b02be92018-08-31 11:55:55 -07001067 entry("POWER_SENSOR_FILE=%s", POWER_READING_SENSOR));
Marri Devender Rao66c5fda2018-01-18 10:48:37 -06001068 elog<InternalFailure>();
1069 }
1070
1071 objectPath = data.value("path", "");
1072 if (objectPath.empty())
1073 {
1074 log<level::ERR>("Power sensor D-Bus object path is empty",
1075 entry("POWER_SENSOR_FILE=%s", POWER_READING_SENSOR));
1076 elog<InternalFailure>();
1077 }
1078
Marri Devender Raoce6a7952018-02-11 08:45:00 -06001079 // Return default value if failed to read from D-Bus object
1080 int64_t power = 0;
1081 try
1082 {
1083 auto service = ipmi::getService(bus, SENSOR_VALUE_INTF, objectPath);
Marri Devender Rao66c5fda2018-01-18 10:48:37 -06001084
Patrick Venture0b02be92018-08-31 11:55:55 -07001085 // Read the sensor value and scale properties
1086 auto properties = ipmi::getAllDbusProperties(bus, service, objectPath,
1087 SENSOR_VALUE_INTF);
William A. Kennington III4c008022018-10-12 17:18:14 -07001088 auto value = variant_ns::get<int64_t>(properties[SENSOR_VALUE_PROP]);
1089 auto scale = variant_ns::get<int64_t>(properties[SENSOR_SCALE_PROP]);
Marri Devender Rao66c5fda2018-01-18 10:48:37 -06001090
Marri Devender Raoce6a7952018-02-11 08:45:00 -06001091 // Power reading needs to be scaled with the Scale value using the
1092 // formula Value * 10^Scale.
1093 power = value * std::pow(10, scale);
1094 }
1095 catch (std::exception& e)
1096 {
1097 log<level::INFO>("Failure to read power value from D-Bus object",
Patrick Venture0b02be92018-08-31 11:55:55 -07001098 entry("OBJECT_PATH=%s", objectPath.c_str()),
1099 entry("INTERFACE=%s", SENSOR_VALUE_INTF));
Marri Devender Raoce6a7952018-02-11 08:45:00 -06001100 }
Marri Devender Rao66c5fda2018-01-18 10:48:37 -06001101 return power;
1102}
1103
Nagaraju Goruganti22be97b2018-02-07 01:19:59 -06001104ipmi_ret_t setDCMIConfParams(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
1105 ipmi_request_t request, ipmi_response_t response,
1106 ipmi_data_len_t data_len, ipmi_context_t context)
1107{
Patrick Venture0b02be92018-08-31 11:55:55 -07001108 auto requestData =
1109 reinterpret_cast<const dcmi::SetConfParamsRequest*>(request);
1110 auto responseData =
1111 reinterpret_cast<dcmi::SetConfParamsResponse*>(response);
Nagaraju Goruganti22be97b2018-02-07 01:19:59 -06001112
Patrick Venture0b02be92018-08-31 11:55:55 -07001113 if (requestData->groupID != dcmi::groupExtId ||
1114 *data_len < DCMI_SET_CONF_PARAM_REQ_PACKET_MIN_SIZE ||
1115 *data_len > DCMI_SET_CONF_PARAM_REQ_PACKET_MAX_SIZE)
Nagaraju Goruganti22be97b2018-02-07 01:19:59 -06001116 {
Gunnar Mills8466b792018-03-23 12:18:12 -05001117 log<level::ERR>("Invalid Group ID or Invalid Requested Packet size",
Nagaraju Goruganti22be97b2018-02-07 01:19:59 -06001118 entry("GROUP_ID=%d", requestData->groupID),
1119 entry("PACKET SIZE=%d", *data_len));
1120 return IPMI_CC_INVALID_FIELD_REQUEST;
1121 }
1122
1123 *data_len = 0;
1124
1125 try
1126 {
1127 // Take action based on the Parameter Selector
Patrick Venture0b02be92018-08-31 11:55:55 -07001128 switch (
1129 static_cast<dcmi::DCMIConfigParameters>(requestData->paramSelect))
Nagaraju Goruganti22be97b2018-02-07 01:19:59 -06001130 {
1131 case dcmi::DCMIConfigParameters::ActivateDHCP:
1132
1133 if ((requestData->data[0] & DCMI_ACTIVATE_DHCP_MASK) &&
Patrick Venture0b02be92018-08-31 11:55:55 -07001134 dcmi::getDHCPEnabled())
Nagaraju Goruganti22be97b2018-02-07 01:19:59 -06001135 {
Patrick Venture0b02be92018-08-31 11:55:55 -07001136 // When these conditions are met we have to trigger DHCP
1137 // protocol restart using the latest parameter settings, but
1138 // as per n/w manager design, each time when we update n/w
1139 // parameters, n/w service is restarted. So we no need to
1140 // take any action in this case.
Nagaraju Goruganti22be97b2018-02-07 01:19:59 -06001141 }
1142 break;
1143
1144 case dcmi::DCMIConfigParameters::DiscoveryConfig:
1145
1146 if (requestData->data[0] & DCMI_OPTION_12_MASK)
1147 {
1148 dcmi::setDHCPOption(DHCP_OPT12_ENABLED, true);
1149 }
1150 else
1151 {
1152 dcmi::setDHCPOption(DHCP_OPT12_ENABLED, false);
1153 }
1154
1155 // Systemd-networkd doesn't support Random Back off
1156 if (requestData->data[0] & DCMI_RAND_BACK_OFF_MASK)
1157 {
1158 return IPMI_CC_INVALID;
1159 }
1160 break;
1161 // Systemd-networkd doesn't allow to configure DHCP timigs
1162 case dcmi::DCMIConfigParameters::DHCPTiming1:
1163 case dcmi::DCMIConfigParameters::DHCPTiming2:
1164 case dcmi::DCMIConfigParameters::DHCPTiming3:
1165 default:
1166 return IPMI_CC_INVALID;
1167 }
1168 }
1169 catch (std::exception& e)
1170 {
1171 log<level::ERR>(e.what());
1172 return IPMI_CC_UNSPECIFIED_ERROR;
1173 }
1174 responseData->groupID = dcmi::groupExtId;
1175 *data_len = sizeof(dcmi::SetConfParamsResponse);
1176
1177 return IPMI_CC_OK;
1178}
1179
1180ipmi_ret_t getDCMIConfParams(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
1181 ipmi_request_t request, ipmi_response_t response,
1182 ipmi_data_len_t data_len, ipmi_context_t context)
1183{
1184
Patrick Venture0b02be92018-08-31 11:55:55 -07001185 auto requestData =
1186 reinterpret_cast<const dcmi::GetConfParamsRequest*>(request);
1187 auto responseData =
1188 reinterpret_cast<dcmi::GetConfParamsResponse*>(response);
Nagaraju Goruganti22be97b2018-02-07 01:19:59 -06001189
1190 responseData->data[0] = 0x00;
1191
Patrick Venture0b02be92018-08-31 11:55:55 -07001192 if (requestData->groupID != dcmi::groupExtId ||
1193 *data_len != sizeof(dcmi::GetConfParamsRequest))
Nagaraju Goruganti22be97b2018-02-07 01:19:59 -06001194 {
Gunnar Mills8466b792018-03-23 12:18:12 -05001195 log<level::ERR>("Invalid Group ID or Invalid Requested Packet size",
Nagaraju Goruganti22be97b2018-02-07 01:19:59 -06001196 entry("GROUP_ID=%d", requestData->groupID),
1197 entry("PACKET SIZE=%d", *data_len));
1198 return IPMI_CC_INVALID_FIELD_REQUEST;
1199 }
1200
1201 *data_len = 0;
1202
1203 try
1204 {
1205 // Take action based on the Parameter Selector
Patrick Venture0b02be92018-08-31 11:55:55 -07001206 switch (
1207 static_cast<dcmi::DCMIConfigParameters>(requestData->paramSelect))
Nagaraju Goruganti22be97b2018-02-07 01:19:59 -06001208 {
1209 case dcmi::DCMIConfigParameters::ActivateDHCP:
1210 responseData->data[0] = DCMI_ACTIVATE_DHCP_REPLY;
1211 *data_len = sizeof(dcmi::GetConfParamsResponse) + 1;
1212 break;
1213 case dcmi::DCMIConfigParameters::DiscoveryConfig:
1214 if (dcmi::getDHCPOption(DHCP_OPT12_ENABLED))
1215 {
1216 responseData->data[0] |= DCMI_OPTION_12_MASK;
1217 }
1218 *data_len = sizeof(dcmi::GetConfParamsResponse) + 1;
1219 break;
1220 // Get below values from Systemd-networkd source code
1221 case dcmi::DCMIConfigParameters::DHCPTiming1:
1222 responseData->data[0] = DHCP_TIMING1;
1223 *data_len = sizeof(dcmi::GetConfParamsResponse) + 1;
1224 break;
1225 case dcmi::DCMIConfigParameters::DHCPTiming2:
1226 responseData->data[0] = DHCP_TIMING2_LOWER;
1227 responseData->data[1] = DHCP_TIMING2_UPPER;
1228 *data_len = sizeof(dcmi::GetConfParamsResponse) + 2;
1229 break;
1230 case dcmi::DCMIConfigParameters::DHCPTiming3:
1231 responseData->data[0] = DHCP_TIMING3_LOWER;
1232 responseData->data[1] = DHCP_TIMING3_UPPER;
1233 *data_len = sizeof(dcmi::GetConfParamsResponse) + 2;
1234 break;
1235 default:
1236 *data_len = 0;
1237 return IPMI_CC_INVALID;
1238 }
1239 }
1240 catch (std::exception& e)
1241 {
1242 log<level::ERR>(e.what());
1243 return IPMI_CC_UNSPECIFIED_ERROR;
1244 }
1245
1246 responseData->groupID = dcmi::groupExtId;
1247 responseData->major = DCMI_SPEC_MAJOR_VERSION;
1248 responseData->minor = DCMI_SPEC_MINOR_VERSION;
1249 responseData->paramRevision = DCMI_CONFIG_PARAMETER_REVISION;
1250
1251 return IPMI_CC_OK;
1252}
1253
Marri Devender Rao66c5fda2018-01-18 10:48:37 -06001254ipmi_ret_t getPowerReading(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
Patrick Venture0b02be92018-08-31 11:55:55 -07001255 ipmi_request_t request, ipmi_response_t response,
1256 ipmi_data_len_t data_len, ipmi_context_t context)
Marri Devender Rao66c5fda2018-01-18 10:48:37 -06001257{
Kirill Pakhomov2c2af2c2018-11-06 16:06:10 +03001258 if (!dcmi::isDCMIPowerMgmtSupported())
1259 {
1260 *data_len = 0;
1261 log<level::ERR>("DCMI Power management is unsupported!");
1262 return IPMI_CC_INVALID;
1263 }
1264
Marri Devender Rao66c5fda2018-01-18 10:48:37 -06001265 ipmi_ret_t rc = IPMI_CC_OK;
Patrick Venture0b02be92018-08-31 11:55:55 -07001266 auto requestData =
1267 reinterpret_cast<const dcmi::GetPowerReadingRequest*>(request);
1268 auto responseData =
1269 reinterpret_cast<dcmi::GetPowerReadingResponse*>(response);
Marri Devender Rao9c966e02018-01-22 05:55:10 -06001270
1271 if (requestData->groupID != dcmi::groupExtId)
1272 {
1273 *data_len = 0;
1274 return IPMI_CC_INVALID_FIELD_REQUEST;
1275 }
1276
Marri Devender Rao66c5fda2018-01-18 10:48:37 -06001277 sdbusplus::bus::bus bus{ipmid_get_sd_bus_connection()};
Marri Devender Rao9c966e02018-01-22 05:55:10 -06001278 int64_t power = 0;
Marri Devender Rao66c5fda2018-01-18 10:48:37 -06001279 try
1280 {
Marri Devender Rao9c966e02018-01-22 05:55:10 -06001281 power = getPowerReading(bus);
Marri Devender Rao66c5fda2018-01-18 10:48:37 -06001282 }
1283 catch (InternalFailure& e)
1284 {
1285 log<level::ERR>("Error in reading power sensor value",
1286 entry("INTERFACE=%s", SENSOR_VALUE_INTF),
1287 entry("PROPERTY=%s", SENSOR_VALUE_PROP));
1288 return IPMI_CC_UNSPECIFIED_ERROR;
1289 }
Marri Devender Rao9c966e02018-01-22 05:55:10 -06001290 responseData->groupID = dcmi::groupExtId;
1291
1292 // TODO: openbmc/openbmc#2819
Gunnar Mills8466b792018-03-23 12:18:12 -05001293 // Minimum, Maximum, Average power, TimeFrame, TimeStamp,
Marri Devender Rao9c966e02018-01-22 05:55:10 -06001294 // PowerReadingState readings need to be populated
1295 // after Telemetry changes.
1296 uint16_t totalPower = static_cast<uint16_t>(power);
1297 responseData->currentPower = totalPower;
1298 responseData->minimumPower = totalPower;
1299 responseData->maximumPower = totalPower;
1300 responseData->averagePower = totalPower;
1301
1302 *data_len = sizeof(*responseData);
Marri Devender Rao66c5fda2018-01-18 10:48:37 -06001303 return rc;
1304}
1305
Deepak Kodihalli0b459552018-02-06 06:25:12 -06001306namespace dcmi
1307{
1308namespace sensor_info
1309{
1310
Deepak Kodihallidd4cff12018-02-06 06:48:29 -06001311Response createFromJson(const Json& config)
1312{
1313 Response response{};
1314 uint16_t recordId = config.value("record_id", 0);
1315 response.recordIdLsb = recordId & 0xFF;
1316 response.recordIdMsb = (recordId >> 8) & 0xFF;
1317 return response;
1318}
1319
Deepak Kodihalli0b459552018-02-06 06:25:12 -06001320std::tuple<Response, NumInstances> read(const std::string& type,
Patrick Venture0b02be92018-08-31 11:55:55 -07001321 uint8_t instance, const Json& config)
Deepak Kodihalli0b459552018-02-06 06:25:12 -06001322{
Deepak Kodihallidd4cff12018-02-06 06:48:29 -06001323 Response response{};
1324
1325 if (!instance)
1326 {
1327 log<level::ERR>("Expected non-zero instance");
1328 elog<InternalFailure>();
1329 }
1330
1331 static const std::vector<Json> empty{};
1332 std::vector<Json> readings = config.value(type, empty);
1333 size_t numInstances = readings.size();
1334 for (const auto& reading : readings)
1335 {
1336 uint8_t instanceNum = reading.value("instance", 0);
1337 // Not the instance we're interested in
1338 if (instanceNum != instance)
1339 {
1340 continue;
1341 }
1342
1343 response = createFromJson(reading);
1344
1345 // Found the instance we're interested in
1346 break;
1347 }
1348
1349 if (numInstances > maxInstances)
1350 {
1351 log<level::DEBUG>("Trimming IPMI num instances",
1352 entry("NUM_INSTANCES=%d", numInstances));
1353 numInstances = maxInstances;
1354 }
1355 return std::make_tuple(response, numInstances);
Deepak Kodihalli0b459552018-02-06 06:25:12 -06001356}
1357
Patrick Venture0b02be92018-08-31 11:55:55 -07001358std::tuple<ResponseList, NumInstances>
1359 readAll(const std::string& type, uint8_t instanceStart, const Json& config)
Deepak Kodihalli0b459552018-02-06 06:25:12 -06001360{
Deepak Kodihallidd4cff12018-02-06 06:48:29 -06001361 ResponseList responses{};
1362
1363 size_t numInstances = 0;
1364 static const std::vector<Json> empty{};
1365 std::vector<Json> readings = config.value(type, empty);
1366 numInstances = readings.size();
1367 for (const auto& reading : readings)
1368 {
1369 try
1370 {
1371 // Max of 8 records
1372 if (responses.size() == maxRecords)
1373 {
1374 break;
1375 }
1376
1377 uint8_t instanceNum = reading.value("instance", 0);
1378 // Not in the instance range we're interested in
1379 if (instanceNum < instanceStart)
1380 {
1381 continue;
1382 }
1383
1384 Response response = createFromJson(reading);
1385 responses.push_back(response);
1386 }
1387 catch (std::exception& e)
1388 {
1389 log<level::DEBUG>(e.what());
1390 continue;
1391 }
1392 }
1393
1394 if (numInstances > maxInstances)
1395 {
1396 log<level::DEBUG>("Trimming IPMI num instances",
1397 entry("NUM_INSTANCES=%d", numInstances));
1398 numInstances = maxInstances;
1399 }
1400 return std::make_tuple(responses, numInstances);
Deepak Kodihalli0b459552018-02-06 06:25:12 -06001401}
1402
1403} // namespace sensor_info
1404} // namespace dcmi
1405
1406ipmi_ret_t getSensorInfo(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
1407 ipmi_request_t request, ipmi_response_t response,
1408 ipmi_data_len_t data_len, ipmi_context_t context)
1409{
1410 auto requestData =
1411 reinterpret_cast<const dcmi::GetSensorInfoRequest*>(request);
1412 auto responseData =
1413 reinterpret_cast<dcmi::GetSensorInfoResponseHdr*>(response);
1414
1415 if (*data_len != sizeof(dcmi::GetSensorInfoRequest))
1416 {
1417 log<level::ERR>("Malformed request data",
1418 entry("DATA_SIZE=%d", *data_len));
1419 return IPMI_CC_REQ_DATA_LEN_INVALID;
1420 }
1421 *data_len = 0;
1422
1423 auto it = dcmi::entityIdToName.find(requestData->entityId);
1424 if (it == dcmi::entityIdToName.end())
1425 {
1426 log<level::ERR>("Unknown Entity ID",
1427 entry("ENTITY_ID=%d", requestData->entityId));
1428 return IPMI_CC_INVALID_FIELD_REQUEST;
1429 }
1430
1431 if (requestData->groupID != dcmi::groupExtId)
1432 {
1433 log<level::ERR>("Invalid Group ID",
1434 entry("GROUP_ID=%d", requestData->groupID));
1435 return IPMI_CC_INVALID_FIELD_REQUEST;
1436 }
1437
1438 if (requestData->sensorType != dcmi::temperatureSensorType)
1439 {
1440 log<level::ERR>("Invalid sensor type",
1441 entry("SENSOR_TYPE=%d", requestData->sensorType));
1442 return IPMI_CC_INVALID_FIELD_REQUEST;
1443 }
1444
1445 dcmi::sensor_info::ResponseList sensors{};
1446 static dcmi::Json config{};
1447 static bool parsed = false;
1448
1449 try
1450 {
1451 if (!parsed)
1452 {
Kirill Pakhomova2573622018-11-02 19:00:18 +03001453 config = dcmi::parseJSONConfig(dcmi::gDCMISensorsConfig);
Deepak Kodihalli0b459552018-02-06 06:25:12 -06001454 parsed = true;
1455 }
1456
1457 if (!requestData->entityInstance)
1458 {
1459 // Read all instances
1460 std::tie(sensors, responseData->numInstances) =
1461 dcmi::sensor_info::readAll(it->second,
Patrick Venture0b02be92018-08-31 11:55:55 -07001462 requestData->instanceStart, config);
Deepak Kodihalli0b459552018-02-06 06:25:12 -06001463 }
1464 else
1465 {
1466 // Read one instance
1467 sensors.resize(1);
1468 std::tie(sensors[0], responseData->numInstances) =
Patrick Venture0b02be92018-08-31 11:55:55 -07001469 dcmi::sensor_info::read(it->second, requestData->entityInstance,
Deepak Kodihalli0b459552018-02-06 06:25:12 -06001470 config);
1471 }
1472 responseData->numRecords = sensors.size();
1473 }
1474 catch (InternalFailure& e)
1475 {
1476 return IPMI_CC_UNSPECIFIED_ERROR;
1477 }
1478
1479 responseData->groupID = dcmi::groupExtId;
1480 size_t payloadSize = sensors.size() * sizeof(dcmi::sensor_info::Response);
1481 if (!sensors.empty())
1482 {
1483 memcpy(responseData + 1, // copy payload right after the response header
Patrick Venture0b02be92018-08-31 11:55:55 -07001484 sensors.data(), payloadSize);
Deepak Kodihalli0b459552018-02-06 06:25:12 -06001485 }
1486 *data_len = sizeof(dcmi::GetSensorInfoResponseHdr) + payloadSize;
1487
1488 return IPMI_CC_OK;
1489}
1490
Chris Austen1810bec2015-10-13 12:12:39 -05001491void register_netfn_dcmi_functions()
1492{
Tom05732372016-09-06 17:21:23 +05301493 // <Get Power Limit>
Ratan Gupta11ddbd22017-08-05 11:59:39 +05301494
Patrick Venture0b02be92018-08-31 11:55:55 -07001495 ipmi_register_callback(NETFUN_GRPEXT, dcmi::Commands::GET_POWER_LIMIT, NULL,
1496 getPowerLimit, PRIVILEGE_USER);
Tom Joseph6f6dd4d2017-07-12 20:07:11 +05301497
Tom Joseph46fa37d2017-07-26 18:11:55 +05301498 // <Set Power Limit>
Ratan Gupta11ddbd22017-08-05 11:59:39 +05301499
Patrick Venture0b02be92018-08-31 11:55:55 -07001500 ipmi_register_callback(NETFUN_GRPEXT, dcmi::Commands::SET_POWER_LIMIT, NULL,
1501 setPowerLimit, PRIVILEGE_OPERATOR);
Tom Joseph46fa37d2017-07-26 18:11:55 +05301502
Tom Joseph6c8d51b2017-07-26 18:18:06 +05301503 // <Activate/Deactivate Power Limit>
Ratan Gupta11ddbd22017-08-05 11:59:39 +05301504
1505 ipmi_register_callback(NETFUN_GRPEXT, dcmi::Commands::APPLY_POWER_LIMIT,
1506 NULL, applyPowerLimit, PRIVILEGE_OPERATOR);
Tom Joseph6c8d51b2017-07-26 18:18:06 +05301507
Tom Joseph6f6dd4d2017-07-12 20:07:11 +05301508 // <Get Asset Tag>
Ratan Gupta11ddbd22017-08-05 11:59:39 +05301509
Patrick Venture0b02be92018-08-31 11:55:55 -07001510 ipmi_register_callback(NETFUN_GRPEXT, dcmi::Commands::GET_ASSET_TAG, NULL,
1511 getAssetTag, PRIVILEGE_USER);
Tom Joseph545dd232017-07-12 20:20:49 +05301512
1513 // <Set Asset Tag>
Ratan Gupta11ddbd22017-08-05 11:59:39 +05301514
Patrick Venture0b02be92018-08-31 11:55:55 -07001515 ipmi_register_callback(NETFUN_GRPEXT, dcmi::Commands::SET_ASSET_TAG, NULL,
1516 setAssetTag, PRIVILEGE_OPERATOR);
Vladislav Vovchenko8f7a6f62017-08-17 00:31:14 +03001517
Gunnar Mills8991dd62017-10-25 17:11:29 -05001518 // <Get Management Controller Identifier String>
Vladislav Vovchenko8f7a6f62017-08-17 00:31:14 +03001519
1520 ipmi_register_callback(NETFUN_GRPEXT, dcmi::Commands::GET_MGMNT_CTRL_ID_STR,
Patrick Venture0b02be92018-08-31 11:55:55 -07001521 NULL, getMgmntCtrlIdStr, PRIVILEGE_USER);
Vladislav Vovchenko8f7a6f62017-08-17 00:31:14 +03001522
1523 // <Set Management Controller Identifier String>
Vladislav Vovchenko8f7a6f62017-08-17 00:31:14 +03001524 ipmi_register_callback(NETFUN_GRPEXT, dcmi::Commands::SET_MGMNT_CTRL_ID_STR,
Patrick Venture0b02be92018-08-31 11:55:55 -07001525 NULL, setMgmntCtrlIdStr, PRIVILEGE_ADMIN);
Vladislav Vovchenko8f7a6f62017-08-17 00:31:14 +03001526
Dhruvaraj Subhashchandrane29be412018-01-16 05:11:56 -06001527 // <Get DCMI capabilities>
1528 ipmi_register_callback(NETFUN_GRPEXT, dcmi::Commands::GET_CAPABILITIES,
Patrick Venture0b02be92018-08-31 11:55:55 -07001529 NULL, getDCMICapabilities, PRIVILEGE_USER);
Deepak Kodihalliee717d72018-01-24 04:53:09 -06001530
1531 // <Get Temperature Readings>
1532 ipmi_register_callback(NETFUN_GRPEXT, dcmi::Commands::GET_TEMP_READINGS,
1533 NULL, getTempReadings, PRIVILEGE_USER);
1534
Marri Devender Rao66c5fda2018-01-18 10:48:37 -06001535 // <Get Power Reading>
1536 ipmi_register_callback(NETFUN_GRPEXT, dcmi::Commands::GET_POWER_READING,
1537 NULL, getPowerReading, PRIVILEGE_USER);
Deepak Kodihalli0b459552018-02-06 06:25:12 -06001538
1539 // <Get Sensor Info>
Patrick Venture0b02be92018-08-31 11:55:55 -07001540 ipmi_register_callback(NETFUN_GRPEXT, dcmi::Commands::GET_SENSOR_INFO, NULL,
1541 getSensorInfo, PRIVILEGE_USER);
Deepak Kodihalli0b459552018-02-06 06:25:12 -06001542
Nagaraju Goruganti22be97b2018-02-07 01:19:59 -06001543 // <Get DCMI Configuration Parameters>
Patrick Venture0b02be92018-08-31 11:55:55 -07001544 ipmi_register_callback(NETFUN_GRPEXT, dcmi::Commands::GET_CONF_PARAMS, NULL,
1545 getDCMIConfParams, PRIVILEGE_USER);
Nagaraju Goruganti22be97b2018-02-07 01:19:59 -06001546
1547 // <Set DCMI Configuration Parameters>
Patrick Venture0b02be92018-08-31 11:55:55 -07001548 ipmi_register_callback(NETFUN_GRPEXT, dcmi::Commands::SET_CONF_PARAMS, NULL,
1549 setDCMIConfParams, PRIVILEGE_ADMIN);
Nagaraju Goruganti22be97b2018-02-07 01:19:59 -06001550
Chris Austen1810bec2015-10-13 12:12:39 -05001551 return;
1552}
Tom05732372016-09-06 17:21:23 +05301553// 956379