blob: 31885851c1164aabcd6d439b57718f0bd2c05321 [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
Patrick Venture0b02be92018-08-31 11:55:55 -07007#include <bitset>
8#include <cmath>
9#include <fstream>
Vernon Mauerye08fbff2019-04-03 09:19:34 -070010#include <ipmid/api.hpp>
Vernon Mauery6a98fe72019-03-11 15:57:48 -070011#include <ipmid/utils.hpp>
Patrick Venture0b02be92018-08-31 11:55:55 -070012#include <nlohmann/json.hpp>
Tom Josephbe5eaa12017-07-12 19:54:44 +053013#include <phosphor-logging/elog-errors.hpp>
Andrew Geissler50c0c8f2017-07-11 16:18:51 -050014#include <phosphor-logging/log.hpp>
15#include <sdbusplus/bus.hpp>
William A. Kennington III4c008022018-10-12 17:18:14 -070016#include <sdbusplus/message/types.hpp>
Patrick Venture0b02be92018-08-31 11:55:55 -070017#include <xyz/openbmc_project/Common/error.hpp>
18
Tom Josephbe5eaa12017-07-12 19:54:44 +053019using namespace phosphor::logging;
20using InternalFailure =
Patrick Venture0b02be92018-08-31 11:55:55 -070021 sdbusplus::xyz::openbmc_project::Common::Error::InternalFailure;
Chris Austen1810bec2015-10-13 12:12:39 -050022
23void register_netfn_dcmi_functions() __attribute__((constructor));
24
Patrick Venture0b02be92018-08-31 11:55:55 -070025constexpr auto PCAP_PATH = "/xyz/openbmc_project/control/host0/power_cap";
Andrew Geissler50c0c8f2017-07-11 16:18:51 -050026constexpr auto PCAP_INTERFACE = "xyz.openbmc_project.Control.Power.Cap";
27
28constexpr auto POWER_CAP_PROP = "PowerCap";
29constexpr auto POWER_CAP_ENABLE_PROP = "PowerCapEnable";
30
Dhruvaraj Subhashchandrane29be412018-01-16 05:11:56 -060031constexpr auto DCMI_PARAMETER_REVISION = 2;
32constexpr auto DCMI_SPEC_MAJOR_VERSION = 1;
33constexpr auto DCMI_SPEC_MINOR_VERSION = 5;
Nagaraju Goruganti22be97b2018-02-07 01:19:59 -060034constexpr auto DCMI_CONFIG_PARAMETER_REVISION = 1;
35constexpr auto DCMI_RAND_BACK_OFF_MASK = 0x80;
36constexpr auto DCMI_OPTION_60_43_MASK = 0x02;
37constexpr auto DCMI_OPTION_12_MASK = 0x01;
38constexpr auto DCMI_ACTIVATE_DHCP_MASK = 0x01;
39constexpr auto DCMI_ACTIVATE_DHCP_REPLY = 0x00;
40constexpr auto DCMI_SET_CONF_PARAM_REQ_PACKET_MAX_SIZE = 0x05;
41constexpr auto DCMI_SET_CONF_PARAM_REQ_PACKET_MIN_SIZE = 0x04;
Patrick Venture0b02be92018-08-31 11:55:55 -070042constexpr auto DHCP_TIMING1 = 0x04; // 4 sec
43constexpr auto DHCP_TIMING2_UPPER = 0x00; // 2 min
Nagaraju Goruganti22be97b2018-02-07 01:19:59 -060044constexpr auto DHCP_TIMING2_LOWER = 0x78;
Patrick Venture0b02be92018-08-31 11:55:55 -070045constexpr auto DHCP_TIMING3_UPPER = 0x00; // 64 sec
Nagaraju Goruganti22be97b2018-02-07 01:19:59 -060046constexpr auto DHCP_TIMING3_LOWER = 0x40;
47// When DHCP Option 12 is enabled the string "SendHostName=true" will be
48// added into n/w configuration file and the parameter
49// SendHostNameEnabled will set to true.
50constexpr auto DHCP_OPT12_ENABLED = "SendHostNameEnabled";
51
Marri Devender Rao66c5fda2018-01-18 10:48:37 -060052constexpr auto SENSOR_VALUE_INTF = "xyz.openbmc_project.Sensor.Value";
53constexpr auto SENSOR_VALUE_PROP = "Value";
54constexpr auto SENSOR_SCALE_PROP = "Scale";
55
Andrew Geissler50c0c8f2017-07-11 16:18:51 -050056using namespace phosphor::logging;
William A. Kennington III4c008022018-10-12 17:18:14 -070057namespace variant_ns = sdbusplus::message::variant_ns;
Andrew Geissler50c0c8f2017-07-11 16:18:51 -050058
Tom Josephb9d86f42017-07-26 18:03:47 +053059namespace dcmi
60{
61
Deepak Kodihalli0b459552018-02-06 06:25:12 -060062// Refer Table 6-14, DCMI Entity ID Extension, DCMI v1.5 spec
Patrick Venture0b02be92018-08-31 11:55:55 -070063static const std::map<uint8_t, std::string> entityIdToName{
64 {0x40, "inlet"}, {0x37, "inlet"}, {0x41, "cpu"},
65 {0x03, "cpu"}, {0x42, "baseboard"}, {0x07, "baseboard"}};
Deepak Kodihalli0b459552018-02-06 06:25:12 -060066
Kirill Pakhomov2c2af2c2018-11-06 16:06:10 +030067bool isDCMIPowerMgmtSupported()
68{
69 auto data = parseJSONConfig(gDCMICapabilitiesConfig);
70
71 return (gDCMIPowerMgmtSupported == data.value(gDCMIPowerMgmtCapability, 0));
72}
73
Andrew Geissler50c0c8f2017-07-11 16:18:51 -050074uint32_t getPcap(sdbusplus::bus::bus& bus)
75{
Patrick Venture0b02be92018-08-31 11:55:55 -070076 auto settingService = ipmi::getService(bus, PCAP_INTERFACE, PCAP_PATH);
Andrew Geissler50c0c8f2017-07-11 16:18:51 -050077
Patrick Venture0b02be92018-08-31 11:55:55 -070078 auto method = bus.new_method_call(settingService.c_str(), PCAP_PATH,
79 "org.freedesktop.DBus.Properties", "Get");
Andrew Geissler50c0c8f2017-07-11 16:18:51 -050080
81 method.append(PCAP_INTERFACE, POWER_CAP_PROP);
82 auto reply = bus.call(method);
83
84 if (reply.is_method_error())
85 {
86 log<level::ERR>("Error in getPcap prop");
Tom Josephb9d86f42017-07-26 18:03:47 +053087 elog<InternalFailure>();
Andrew Geissler50c0c8f2017-07-11 16:18:51 -050088 }
89 sdbusplus::message::variant<uint32_t> pcap;
90 reply.read(pcap);
91
William A. Kennington III4c008022018-10-12 17:18:14 -070092 return variant_ns::get<uint32_t>(pcap);
Andrew Geissler50c0c8f2017-07-11 16:18:51 -050093}
94
95bool getPcapEnabled(sdbusplus::bus::bus& bus)
96{
Patrick Venture0b02be92018-08-31 11:55:55 -070097 auto settingService = ipmi::getService(bus, PCAP_INTERFACE, PCAP_PATH);
Andrew Geissler50c0c8f2017-07-11 16:18:51 -050098
Patrick Venture0b02be92018-08-31 11:55:55 -070099 auto method = bus.new_method_call(settingService.c_str(), PCAP_PATH,
100 "org.freedesktop.DBus.Properties", "Get");
Andrew Geissler50c0c8f2017-07-11 16:18:51 -0500101
102 method.append(PCAP_INTERFACE, POWER_CAP_ENABLE_PROP);
103 auto reply = bus.call(method);
104
105 if (reply.is_method_error())
106 {
107 log<level::ERR>("Error in getPcapEnabled prop");
Tom Josephb9d86f42017-07-26 18:03:47 +0530108 elog<InternalFailure>();
Andrew Geissler50c0c8f2017-07-11 16:18:51 -0500109 }
110 sdbusplus::message::variant<bool> pcapEnabled;
111 reply.read(pcapEnabled);
112
William A. Kennington III4c008022018-10-12 17:18:14 -0700113 return variant_ns::get<bool>(pcapEnabled);
Andrew Geissler50c0c8f2017-07-11 16:18:51 -0500114}
Chris Austen1810bec2015-10-13 12:12:39 -0500115
Tom Joseph46fa37d2017-07-26 18:11:55 +0530116void setPcap(sdbusplus::bus::bus& bus, const uint32_t powerCap)
117{
118 auto service = ipmi::getService(bus, PCAP_INTERFACE, PCAP_PATH);
119
Patrick Venture0b02be92018-08-31 11:55:55 -0700120 auto method = bus.new_method_call(service.c_str(), PCAP_PATH,
121 "org.freedesktop.DBus.Properties", "Set");
Tom Joseph46fa37d2017-07-26 18:11:55 +0530122
123 method.append(PCAP_INTERFACE, POWER_CAP_PROP);
124 method.append(sdbusplus::message::variant<uint32_t>(powerCap));
125
126 auto reply = bus.call(method);
127
128 if (reply.is_method_error())
129 {
130 log<level::ERR>("Error in setPcap property");
131 elog<InternalFailure>();
132 }
133}
134
Tom Joseph6c8d51b2017-07-26 18:18:06 +0530135void setPcapEnable(sdbusplus::bus::bus& bus, bool enabled)
136{
137 auto service = ipmi::getService(bus, PCAP_INTERFACE, PCAP_PATH);
138
Patrick Venture0b02be92018-08-31 11:55:55 -0700139 auto method = bus.new_method_call(service.c_str(), PCAP_PATH,
140 "org.freedesktop.DBus.Properties", "Set");
Tom Joseph6c8d51b2017-07-26 18:18:06 +0530141
142 method.append(PCAP_INTERFACE, POWER_CAP_ENABLE_PROP);
143 method.append(sdbusplus::message::variant<bool>(enabled));
144
145 auto reply = bus.call(method);
146
147 if (reply.is_method_error())
148 {
149 log<level::ERR>("Error in setPcapEnabled property");
150 elog<InternalFailure>();
151 }
152}
153
Tom Josephbe5eaa12017-07-12 19:54:44 +0530154void readAssetTagObjectTree(dcmi::assettag::ObjectTree& objectTree)
155{
156 static constexpr auto mapperBusName = "xyz.openbmc_project.ObjectMapper";
157 static constexpr auto mapperObjPath = "/xyz/openbmc_project/object_mapper";
158 static constexpr auto mapperIface = "xyz.openbmc_project.ObjectMapper";
159 static constexpr auto inventoryRoot = "/xyz/openbmc_project/inventory/";
160
161 sdbusplus::bus::bus bus{ipmid_get_sd_bus_connection()};
162 auto depth = 0;
163
Patrick Venture0b02be92018-08-31 11:55:55 -0700164 auto mapperCall = bus.new_method_call(mapperBusName, mapperObjPath,
165 mapperIface, "GetSubTree");
Tom Josephbe5eaa12017-07-12 19:54:44 +0530166
167 mapperCall.append(inventoryRoot);
168 mapperCall.append(depth);
169 mapperCall.append(std::vector<std::string>({dcmi::assetTagIntf}));
170
171 auto mapperReply = bus.call(mapperCall);
172 if (mapperReply.is_method_error())
173 {
174 log<level::ERR>("Error in mapper call");
175 elog<InternalFailure>();
176 }
177
178 mapperReply.read(objectTree);
179
180 if (objectTree.empty())
181 {
182 log<level::ERR>("AssetTag property is not populated");
183 elog<InternalFailure>();
184 }
185}
186
187std::string readAssetTag()
188{
189 sdbusplus::bus::bus bus{ipmid_get_sd_bus_connection()};
190 dcmi::assettag::ObjectTree objectTree;
191
192 // Read the object tree with the inventory root to figure out the object
193 // that has implemented the Asset tag interface.
194 readAssetTagObjectTree(objectTree);
195
196 auto method = bus.new_method_call(
Patrick Venture0b02be92018-08-31 11:55:55 -0700197 (objectTree.begin()->second.begin()->first).c_str(),
198 (objectTree.begin()->first).c_str(), dcmi::propIntf, "Get");
Tom Josephbe5eaa12017-07-12 19:54:44 +0530199 method.append(dcmi::assetTagIntf);
200 method.append(dcmi::assetTagProp);
201
202 auto reply = bus.call(method);
203 if (reply.is_method_error())
204 {
205 log<level::ERR>("Error in reading asset tag");
206 elog<InternalFailure>();
207 }
208
209 sdbusplus::message::variant<std::string> assetTag;
210 reply.read(assetTag);
211
William A. Kennington III4c008022018-10-12 17:18:14 -0700212 return variant_ns::get<std::string>(assetTag);
Tom Josephbe5eaa12017-07-12 19:54:44 +0530213}
214
Tom Josephbe5b9892017-07-15 00:55:23 +0530215void writeAssetTag(const std::string& assetTag)
216{
217 sdbusplus::bus::bus bus{ipmid_get_sd_bus_connection()};
218 dcmi::assettag::ObjectTree objectTree;
219
220 // Read the object tree with the inventory root to figure out the object
221 // that has implemented the Asset tag interface.
222 readAssetTagObjectTree(objectTree);
223
224 auto method = bus.new_method_call(
Patrick Venture0b02be92018-08-31 11:55:55 -0700225 (objectTree.begin()->second.begin()->first).c_str(),
226 (objectTree.begin()->first).c_str(), dcmi::propIntf, "Set");
Tom Josephbe5b9892017-07-15 00:55:23 +0530227 method.append(dcmi::assetTagIntf);
228 method.append(dcmi::assetTagProp);
229 method.append(sdbusplus::message::variant<std::string>(assetTag));
230
231 auto reply = bus.call(method);
232 if (reply.is_method_error())
233 {
234 log<level::ERR>("Error in writing asset tag");
235 elog<InternalFailure>();
236 }
237}
238
Vladislav Vovchenko8f7a6f62017-08-17 00:31:14 +0300239std::string getHostName(void)
240{
Patrick Venture0b02be92018-08-31 11:55:55 -0700241 sdbusplus::bus::bus bus{ipmid_get_sd_bus_connection()};
Vladislav Vovchenko8f7a6f62017-08-17 00:31:14 +0300242
243 auto service = ipmi::getService(bus, networkConfigIntf, networkConfigObj);
Patrick Venture0b02be92018-08-31 11:55:55 -0700244 auto value = ipmi::getDbusProperty(bus, service, networkConfigObj,
245 networkConfigIntf, hostNameProp);
Vladislav Vovchenko8f7a6f62017-08-17 00:31:14 +0300246
William A. Kennington III4c008022018-10-12 17:18:14 -0700247 return variant_ns::get<std::string>(value);
Vladislav Vovchenko8f7a6f62017-08-17 00:31:14 +0300248}
249
Nagaraju Goruganti22be97b2018-02-07 01:19:59 -0600250bool getDHCPEnabled()
251{
252 sdbusplus::bus::bus bus{ipmid_get_sd_bus_connection()};
253
Johnathan Mantey74a21022018-12-13 13:17:56 -0800254 auto ethdevice = ipmi::getChannelName(ethernetDefaultChannelNum);
Patrick Venture0b02be92018-08-31 11:55:55 -0700255 auto ethernetObj =
256 ipmi::getDbusObject(bus, ethernetIntf, networkRoot, ethdevice);
Nagaraju Goruganti22be97b2018-02-07 01:19:59 -0600257 auto service = ipmi::getService(bus, ethernetIntf, ethernetObj.first);
Patrick Venture0b02be92018-08-31 11:55:55 -0700258 auto value = ipmi::getDbusProperty(bus, service, ethernetObj.first,
259 ethernetIntf, "DHCPEnabled");
Nagaraju Goruganti22be97b2018-02-07 01:19:59 -0600260
William A. Kennington III4c008022018-10-12 17:18:14 -0700261 return variant_ns::get<bool>(value);
Nagaraju Goruganti22be97b2018-02-07 01:19:59 -0600262}
263
264bool getDHCPOption(std::string prop)
265{
266 sdbusplus::bus::bus bus{ipmid_get_sd_bus_connection()};
267
268 auto service = ipmi::getService(bus, dhcpIntf, dhcpObj);
269 auto value = ipmi::getDbusProperty(bus, service, dhcpObj, dhcpIntf, prop);
270
William A. Kennington III4c008022018-10-12 17:18:14 -0700271 return variant_ns::get<bool>(value);
Nagaraju Goruganti22be97b2018-02-07 01:19:59 -0600272}
273
Nagaraju Goruganti22be97b2018-02-07 01:19:59 -0600274void setDHCPOption(std::string prop, bool value)
275{
276 sdbusplus::bus::bus bus{ipmid_get_sd_bus_connection()};
277
278 auto service = ipmi::getService(bus, dhcpIntf, dhcpObj);
279 ipmi::setDbusProperty(bus, service, dhcpObj, dhcpIntf, prop, value);
280}
281
Kirill Pakhomova2573622018-11-02 19:00:18 +0300282Json parseJSONConfig(const std::string& configFile)
Deepak Kodihalli0b459552018-02-06 06:25:12 -0600283{
284 std::ifstream jsonFile(configFile);
285 if (!jsonFile.is_open())
286 {
287 log<level::ERR>("Temperature readings JSON file not found");
288 elog<InternalFailure>();
289 }
290
291 auto data = Json::parse(jsonFile, nullptr, false);
292 if (data.is_discarded())
293 {
294 log<level::ERR>("Temperature readings JSON parser failure");
295 elog<InternalFailure>();
296 }
297
298 return data;
299}
300
Tom Josephbe5eaa12017-07-12 19:54:44 +0530301} // namespace dcmi
Chris Austen1810bec2015-10-13 12:12:39 -0500302
Tom Josephb9d86f42017-07-26 18:03:47 +0530303ipmi_ret_t getPowerLimit(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
304 ipmi_request_t request, ipmi_response_t response,
305 ipmi_data_len_t data_len, ipmi_context_t context)
306{
Kirill Pakhomov2c2af2c2018-11-06 16:06:10 +0300307 if (!dcmi::isDCMIPowerMgmtSupported())
308 {
309 *data_len = 0;
310 log<level::ERR>("DCMI Power management is unsupported!");
311 return IPMI_CC_INVALID;
312 }
313
Patrick Venture0b02be92018-08-31 11:55:55 -0700314 auto requestData =
315 reinterpret_cast<const dcmi::GetPowerLimitRequest*>(request);
Tom Josephb9d86f42017-07-26 18:03:47 +0530316 std::vector<uint8_t> outPayload(sizeof(dcmi::GetPowerLimitResponse));
Patrick Venture0b02be92018-08-31 11:55:55 -0700317 auto responseData =
318 reinterpret_cast<dcmi::GetPowerLimitResponse*>(outPayload.data());
Tom Josephb9d86f42017-07-26 18:03:47 +0530319
320 if (requestData->groupID != dcmi::groupExtId)
321 {
322 *data_len = 0;
323 return IPMI_CC_INVALID_FIELD_REQUEST;
324 }
325
Patrick Venture0b02be92018-08-31 11:55:55 -0700326 sdbusplus::bus::bus sdbus{ipmid_get_sd_bus_connection()};
Tom Josephb9d86f42017-07-26 18:03:47 +0530327 uint32_t pcapValue = 0;
328 bool pcapEnable = false;
329
330 try
331 {
332 pcapValue = dcmi::getPcap(sdbus);
333 pcapEnable = dcmi::getPcapEnabled(sdbus);
334 }
335 catch (InternalFailure& e)
336 {
337 *data_len = 0;
338 return IPMI_CC_UNSPECIFIED_ERROR;
339 }
340
341 responseData->groupID = dcmi::groupExtId;
342
343 /*
344 * Exception action if power limit is exceeded and cannot be controlled
345 * with the correction time limit is hardcoded to Hard Power Off system
346 * and log event to SEL.
347 */
348 constexpr auto exception = 0x01;
349 responseData->exceptionAction = exception;
350
351 responseData->powerLimit = static_cast<uint16_t>(pcapValue);
352
353 /*
354 * Correction time limit and Statistics sampling period is currently not
355 * populated.
356 */
357
358 *data_len = outPayload.size();
359 memcpy(response, outPayload.data(), *data_len);
360
361 if (pcapEnable)
362 {
363 return IPMI_CC_OK;
364 }
365 else
366 {
367 return IPMI_DCMI_CC_NO_ACTIVE_POWER_LIMIT;
368 }
369}
370
Tom Joseph46fa37d2017-07-26 18:11:55 +0530371ipmi_ret_t setPowerLimit(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
372 ipmi_request_t request, ipmi_response_t response,
373 ipmi_data_len_t data_len, ipmi_context_t context)
374{
Kirill Pakhomov2c2af2c2018-11-06 16:06:10 +0300375 if (!dcmi::isDCMIPowerMgmtSupported())
376 {
377 *data_len = 0;
378 log<level::ERR>("DCMI Power management is unsupported!");
379 return IPMI_CC_INVALID;
380 }
381
Patrick Venture0b02be92018-08-31 11:55:55 -0700382 auto requestData =
383 reinterpret_cast<const dcmi::SetPowerLimitRequest*>(request);
Tom Joseph46fa37d2017-07-26 18:11:55 +0530384 std::vector<uint8_t> outPayload(sizeof(dcmi::SetPowerLimitResponse));
Patrick Venture0b02be92018-08-31 11:55:55 -0700385 auto responseData =
386 reinterpret_cast<dcmi::SetPowerLimitResponse*>(outPayload.data());
Tom Joseph46fa37d2017-07-26 18:11:55 +0530387
388 if (requestData->groupID != dcmi::groupExtId)
389 {
390 *data_len = 0;
391 return IPMI_CC_INVALID_FIELD_REQUEST;
392 }
393
Patrick Venture0b02be92018-08-31 11:55:55 -0700394 sdbusplus::bus::bus sdbus{ipmid_get_sd_bus_connection()};
Tom Joseph46fa37d2017-07-26 18:11:55 +0530395
396 // Only process the power limit requested in watts.
397 try
398 {
399 dcmi::setPcap(sdbus, requestData->powerLimit);
400 }
401 catch (InternalFailure& e)
402 {
403 *data_len = 0;
404 return IPMI_CC_UNSPECIFIED_ERROR;
405 }
406
407 log<level::INFO>("Set Power Cap",
408 entry("POWERCAP=%u", requestData->powerLimit));
409
410 responseData->groupID = dcmi::groupExtId;
411 memcpy(response, outPayload.data(), outPayload.size());
412 *data_len = outPayload.size();
413
414 return IPMI_CC_OK;
415}
416
Tom Joseph6c8d51b2017-07-26 18:18:06 +0530417ipmi_ret_t applyPowerLimit(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
418 ipmi_request_t request, ipmi_response_t response,
419 ipmi_data_len_t data_len, ipmi_context_t context)
420{
Kirill Pakhomov2c2af2c2018-11-06 16:06:10 +0300421 if (!dcmi::isDCMIPowerMgmtSupported())
422 {
423 *data_len = 0;
424 log<level::ERR>("DCMI Power management is unsupported!");
425 return IPMI_CC_INVALID;
426 }
427
Patrick Venture0b02be92018-08-31 11:55:55 -0700428 auto requestData =
429 reinterpret_cast<const dcmi::ApplyPowerLimitRequest*>(request);
Tom Joseph6c8d51b2017-07-26 18:18:06 +0530430 std::vector<uint8_t> outPayload(sizeof(dcmi::ApplyPowerLimitResponse));
Patrick Venture0b02be92018-08-31 11:55:55 -0700431 auto responseData =
432 reinterpret_cast<dcmi::ApplyPowerLimitResponse*>(outPayload.data());
Tom Joseph6c8d51b2017-07-26 18:18:06 +0530433
434 if (requestData->groupID != dcmi::groupExtId)
435 {
436 *data_len = 0;
437 return IPMI_CC_INVALID_FIELD_REQUEST;
438 }
439
Patrick Venture0b02be92018-08-31 11:55:55 -0700440 sdbusplus::bus::bus sdbus{ipmid_get_sd_bus_connection()};
Tom Joseph6c8d51b2017-07-26 18:18:06 +0530441
442 try
443 {
444 dcmi::setPcapEnable(sdbus,
445 static_cast<bool>(requestData->powerLimitAction));
446 }
447 catch (InternalFailure& e)
448 {
449 *data_len = 0;
450 return IPMI_CC_UNSPECIFIED_ERROR;
451 }
452
453 log<level::INFO>("Set Power Cap Enable",
454 entry("POWERCAPENABLE=%u", requestData->powerLimitAction));
455
456 responseData->groupID = dcmi::groupExtId;
457 memcpy(response, outPayload.data(), outPayload.size());
458 *data_len = outPayload.size();
459
460 return IPMI_CC_OK;
461}
462
Tom Joseph6f6dd4d2017-07-12 20:07:11 +0530463ipmi_ret_t getAssetTag(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
464 ipmi_request_t request, ipmi_response_t response,
465 ipmi_data_len_t data_len, ipmi_context_t context)
466{
Patrick Venture0b02be92018-08-31 11:55:55 -0700467 auto requestData =
468 reinterpret_cast<const dcmi::GetAssetTagRequest*>(request);
Tom Joseph6f6dd4d2017-07-12 20:07:11 +0530469 std::vector<uint8_t> outPayload(sizeof(dcmi::GetAssetTagResponse));
Patrick Venture0b02be92018-08-31 11:55:55 -0700470 auto responseData =
471 reinterpret_cast<dcmi::GetAssetTagResponse*>(outPayload.data());
Tom Joseph6f6dd4d2017-07-12 20:07:11 +0530472
473 if (requestData->groupID != dcmi::groupExtId)
474 {
475 *data_len = 0;
476 return IPMI_CC_INVALID_FIELD_REQUEST;
477 }
478
479 // Verify offset to read and number of bytes to read are not exceeding the
480 // range.
481 if ((requestData->offset > dcmi::assetTagMaxOffset) ||
482 (requestData->bytes > dcmi::maxBytes) ||
483 ((requestData->offset + requestData->bytes) > dcmi::assetTagMaxSize))
484 {
485 *data_len = 0;
486 return IPMI_CC_PARM_OUT_OF_RANGE;
487 }
488
489 std::string assetTag;
490
491 try
492 {
493 assetTag = dcmi::readAssetTag();
494 }
495 catch (InternalFailure& e)
496 {
497 *data_len = 0;
498 return IPMI_CC_UNSPECIFIED_ERROR;
499 }
500
501 responseData->groupID = dcmi::groupExtId;
502
503 // Return if the asset tag is not populated.
504 if (!assetTag.size())
505 {
506 responseData->tagLength = 0;
507 memcpy(response, outPayload.data(), outPayload.size());
508 *data_len = outPayload.size();
509 return IPMI_CC_OK;
510 }
511
512 // If the asset tag is longer than 63 bytes, restrict it to 63 bytes to suit
513 // Get Asset Tag command.
514 if (assetTag.size() > dcmi::assetTagMaxSize)
515 {
516 assetTag.resize(dcmi::assetTagMaxSize);
517 }
518
519 // If the requested offset is beyond the asset tag size.
520 if (requestData->offset >= assetTag.size())
521 {
522 *data_len = 0;
523 return IPMI_CC_PARM_OUT_OF_RANGE;
524 }
525
526 auto returnData = assetTag.substr(requestData->offset, requestData->bytes);
527
528 responseData->tagLength = assetTag.size();
529
530 memcpy(response, outPayload.data(), outPayload.size());
531 memcpy(static_cast<uint8_t*>(response) + outPayload.size(),
532 returnData.data(), returnData.size());
533 *data_len = outPayload.size() + returnData.size();
534
535 return IPMI_CC_OK;
536}
537
Tom Joseph545dd232017-07-12 20:20:49 +0530538ipmi_ret_t setAssetTag(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
539 ipmi_request_t request, ipmi_response_t response,
540 ipmi_data_len_t data_len, ipmi_context_t context)
541{
Patrick Venture0b02be92018-08-31 11:55:55 -0700542 auto requestData =
543 reinterpret_cast<const dcmi::SetAssetTagRequest*>(request);
Tom Joseph545dd232017-07-12 20:20:49 +0530544 std::vector<uint8_t> outPayload(sizeof(dcmi::SetAssetTagResponse));
Patrick Venture0b02be92018-08-31 11:55:55 -0700545 auto responseData =
546 reinterpret_cast<dcmi::SetAssetTagResponse*>(outPayload.data());
Tom Joseph545dd232017-07-12 20:20:49 +0530547
548 if (requestData->groupID != dcmi::groupExtId)
549 {
550 *data_len = 0;
551 return IPMI_CC_INVALID_FIELD_REQUEST;
552 }
553
554 // Verify offset to read and number of bytes to read are not exceeding the
555 // range.
556 if ((requestData->offset > dcmi::assetTagMaxOffset) ||
557 (requestData->bytes > dcmi::maxBytes) ||
558 ((requestData->offset + requestData->bytes) > dcmi::assetTagMaxSize))
559 {
560 *data_len = 0;
561 return IPMI_CC_PARM_OUT_OF_RANGE;
562 }
563
564 std::string assetTag;
565
566 try
567 {
568 assetTag = dcmi::readAssetTag();
569
570 if (requestData->offset > assetTag.size())
571 {
572 *data_len = 0;
573 return IPMI_CC_PARM_OUT_OF_RANGE;
574 }
575
576 assetTag.replace(requestData->offset,
577 assetTag.size() - requestData->offset,
578 static_cast<const char*>(request) +
Patrick Venture0b02be92018-08-31 11:55:55 -0700579 sizeof(dcmi::SetAssetTagRequest),
Tom Joseph545dd232017-07-12 20:20:49 +0530580 requestData->bytes);
581
582 dcmi::writeAssetTag(assetTag);
583
584 responseData->groupID = dcmi::groupExtId;
585 responseData->tagLength = assetTag.size();
586 memcpy(response, outPayload.data(), outPayload.size());
587 *data_len = outPayload.size();
588
589 return IPMI_CC_OK;
590 }
591 catch (InternalFailure& e)
592 {
593 *data_len = 0;
594 return IPMI_CC_UNSPECIFIED_ERROR;
595 }
596}
597
Vladislav Vovchenko8f7a6f62017-08-17 00:31:14 +0300598ipmi_ret_t getMgmntCtrlIdStr(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
Patrick Venture0b02be92018-08-31 11:55:55 -0700599 ipmi_request_t request, ipmi_response_t response,
600 ipmi_data_len_t data_len, ipmi_context_t context)
Vladislav Vovchenko8f7a6f62017-08-17 00:31:14 +0300601{
Patrick Venture0b02be92018-08-31 11:55:55 -0700602 auto requestData =
603 reinterpret_cast<const dcmi::GetMgmntCtrlIdStrRequest*>(request);
604 auto responseData =
605 reinterpret_cast<dcmi::GetMgmntCtrlIdStrResponse*>(response);
Vladislav Vovchenko8f7a6f62017-08-17 00:31:14 +0300606 std::string hostName;
607
608 *data_len = 0;
609
610 if (requestData->groupID != dcmi::groupExtId ||
611 requestData->bytes > dcmi::maxBytes ||
612 requestData->offset + requestData->bytes > dcmi::maxCtrlIdStrLen)
613 {
614 return IPMI_CC_INVALID_FIELD_REQUEST;
615 }
616
617 try
618 {
619 hostName = dcmi::getHostName();
620 }
621 catch (InternalFailure& e)
622 {
623 return IPMI_CC_UNSPECIFIED_ERROR;
624 }
625
626 if (requestData->offset > hostName.length())
627 {
628 return IPMI_CC_PARM_OUT_OF_RANGE;
629 }
630 auto responseStr = hostName.substr(requestData->offset, requestData->bytes);
631 auto responseStrLen = std::min(static_cast<std::size_t>(requestData->bytes),
Patrick Venture0b02be92018-08-31 11:55:55 -0700632 responseStr.length() + 1);
Vladislav Vovchenko8f7a6f62017-08-17 00:31:14 +0300633 responseData->groupID = dcmi::groupExtId;
634 responseData->strLen = hostName.length();
635 std::copy(begin(responseStr), end(responseStr), responseData->data);
636
637 *data_len = sizeof(*responseData) + responseStrLen;
638 return IPMI_CC_OK;
639}
640
641ipmi_ret_t setMgmntCtrlIdStr(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
Patrick Venture0b02be92018-08-31 11:55:55 -0700642 ipmi_request_t request, ipmi_response_t response,
643 ipmi_data_len_t data_len, ipmi_context_t context)
Vladislav Vovchenko8f7a6f62017-08-17 00:31:14 +0300644{
645 static std::array<char, dcmi::maxCtrlIdStrLen + 1> newCtrlIdStr;
646
Patrick Venture0b02be92018-08-31 11:55:55 -0700647 auto requestData =
648 reinterpret_cast<const dcmi::SetMgmntCtrlIdStrRequest*>(request);
649 auto responseData =
650 reinterpret_cast<dcmi::SetMgmntCtrlIdStrResponse*>(response);
Vladislav Vovchenko8f7a6f62017-08-17 00:31:14 +0300651
652 *data_len = 0;
653
654 if (requestData->groupID != dcmi::groupExtId ||
655 requestData->bytes > dcmi::maxBytes ||
656 requestData->offset + requestData->bytes > dcmi::maxCtrlIdStrLen + 1 ||
Patrick Venture0b02be92018-08-31 11:55:55 -0700657 (requestData->offset + requestData->bytes ==
658 dcmi::maxCtrlIdStrLen + 1 &&
659 requestData->data[requestData->bytes - 1] != '\0'))
Vladislav Vovchenko8f7a6f62017-08-17 00:31:14 +0300660 {
661 return IPMI_CC_INVALID_FIELD_REQUEST;
662 }
663
664 try
665 {
666 /* if there is no old value and offset is not 0 */
667 if (newCtrlIdStr[0] == '\0' && requestData->offset != 0)
668 {
669 /* read old ctrlIdStr */
670 auto hostName = dcmi::getHostName();
671 hostName.resize(dcmi::maxCtrlIdStrLen);
672 std::copy(begin(hostName), end(hostName), begin(newCtrlIdStr));
673 newCtrlIdStr[hostName.length()] = '\0';
674 }
675
676 /* replace part of string and mark byte after the last as \0 */
Patrick Venture0b02be92018-08-31 11:55:55 -0700677 auto restStrIter =
678 std::copy_n(requestData->data, requestData->bytes,
679 begin(newCtrlIdStr) + requestData->offset);
Vladislav Vovchenko8f7a6f62017-08-17 00:31:14 +0300680 /* if the last written byte is not 64th - add '\0' */
681 if (requestData->offset + requestData->bytes <= dcmi::maxCtrlIdStrLen)
682 {
683 *restStrIter = '\0';
684 }
685
686 /* if input data contains '\0' whole string is sent - update hostname */
687 auto it = std::find(requestData->data,
Patrick Venture0b02be92018-08-31 11:55:55 -0700688 requestData->data + requestData->bytes, '\0');
Vladislav Vovchenko8f7a6f62017-08-17 00:31:14 +0300689 if (it != requestData->data + requestData->bytes)
690 {
Patrick Venture0b02be92018-08-31 11:55:55 -0700691 sdbusplus::bus::bus bus{ipmid_get_sd_bus_connection()};
Vladislav Vovchenko8f7a6f62017-08-17 00:31:14 +0300692 ipmi::setDbusProperty(bus, dcmi::networkServiceName,
Patrick Venture0b02be92018-08-31 11:55:55 -0700693 dcmi::networkConfigObj,
694 dcmi::networkConfigIntf, dcmi::hostNameProp,
695 std::string(newCtrlIdStr.data()));
Vladislav Vovchenko8f7a6f62017-08-17 00:31:14 +0300696 }
697 }
698 catch (InternalFailure& e)
699 {
700 *data_len = 0;
701 return IPMI_CC_UNSPECIFIED_ERROR;
702 }
703
704 responseData->groupID = dcmi::groupExtId;
705 responseData->offset = requestData->offset + requestData->bytes;
706 *data_len = sizeof(*responseData);
707 return IPMI_CC_OK;
708}
709
Patrick Venture0b02be92018-08-31 11:55:55 -0700710// List of the capabilities under each parameter
711dcmi::DCMICaps dcmiCaps = {
712 // Supported DCMI Capabilities
713 {dcmi::DCMICapParameters::SUPPORTED_DCMI_CAPS,
714 {3,
715 {{"PowerManagement", 2, 0, 1},
716 {"OOBSecondaryLan", 3, 2, 1},
717 {"SerialTMODE", 3, 1, 1},
718 {"InBandSystemInterfaceChannel", 3, 0, 1}}}},
719 // Mandatory Platform Attributes
720 {dcmi::DCMICapParameters::MANDATORY_PLAT_ATTRIBUTES,
721 {5,
722 {{"SELAutoRollOver", 1, 15, 1},
723 {"FlushEntireSELUponRollOver", 1, 14, 1},
724 {"RecordLevelSELFlushUponRollOver", 1, 13, 1},
725 {"NumberOfSELEntries", 1, 0, 12},
726 {"TempMonitoringSamplingFreq", 5, 0, 8}}}},
727 // Optional Platform Attributes
728 {dcmi::DCMICapParameters::OPTIONAL_PLAT_ATTRIBUTES,
729 {2,
730 {{"PowerMgmtDeviceSlaveAddress", 1, 1, 7},
731 {"BMCChannelNumber", 2, 4, 4},
732 {"DeviceRivision", 2, 0, 4}}}},
733 // Manageability Access Attributes
734 {dcmi::DCMICapParameters::MANAGEABILITY_ACCESS_ATTRIBUTES,
735 {3,
736 {{"MandatoryPrimaryLanOOBSupport", 1, 0, 8},
737 {"OptionalSecondaryLanOOBSupport", 2, 0, 8},
738 {"OptionalSerialOOBMTMODECapability", 3, 0, 8}}}}};
Dhruvaraj Subhashchandrane29be412018-01-16 05:11:56 -0600739
740ipmi_ret_t getDCMICapabilities(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
741 ipmi_request_t request, ipmi_response_t response,
742 ipmi_data_len_t data_len, ipmi_context_t context)
743{
744
Kirill Pakhomova2573622018-11-02 19:00:18 +0300745 std::ifstream dcmiCapFile(dcmi::gDCMICapabilitiesConfig);
Dhruvaraj Subhashchandrane29be412018-01-16 05:11:56 -0600746 if (!dcmiCapFile.is_open())
747 {
748 log<level::ERR>("DCMI Capabilities file not found");
749 return IPMI_CC_UNSPECIFIED_ERROR;
750 }
751
752 auto data = nlohmann::json::parse(dcmiCapFile, nullptr, false);
753 if (data.is_discarded())
754 {
755 log<level::ERR>("DCMI Capabilities JSON parser failure");
756 return IPMI_CC_UNSPECIFIED_ERROR;
757 }
758
Patrick Venture0b02be92018-08-31 11:55:55 -0700759 auto requestData =
760 reinterpret_cast<const dcmi::GetDCMICapRequest*>(request);
Dhruvaraj Subhashchandrane29be412018-01-16 05:11:56 -0600761
Patrick Venture0b02be92018-08-31 11:55:55 -0700762 // get list of capabilities in a parameter
Dhruvaraj Subhashchandrane29be412018-01-16 05:11:56 -0600763 auto caps =
764 dcmiCaps.find(static_cast<dcmi::DCMICapParameters>(requestData->param));
765 if (caps == dcmiCaps.end())
766 {
767 log<level::ERR>("Invalid input parameter");
768 return IPMI_CC_INVALID_FIELD_REQUEST;
769 }
770
771 if (requestData->groupID != dcmi::groupExtId)
772 {
773 *data_len = 0;
774 return IPMI_CC_INVALID_FIELD_REQUEST;
775 }
776
Patrick Venture0b02be92018-08-31 11:55:55 -0700777 auto responseData = reinterpret_cast<dcmi::GetDCMICapResponse*>(response);
Dhruvaraj Subhashchandrane29be412018-01-16 05:11:56 -0600778
Patrick Venture0b02be92018-08-31 11:55:55 -0700779 // For each capabilities in a parameter fill the data from
780 // the json file based on the capability name.
Dhruvaraj Subhashchandrane29be412018-01-16 05:11:56 -0600781 for (auto cap : caps->second.capList)
782 {
Patrick Venture0b02be92018-08-31 11:55:55 -0700783 // If the data is beyond first byte boundary, insert in a
784 // 16bit pattern for example number of SEL entries are represented
785 // in 12bits.
Kirill Pakhomovdb5d9b02018-11-06 19:17:51 +0300786 if ((cap.length + cap.position) > dcmi::gByteBitSize)
Dhruvaraj Subhashchandrane29be412018-01-16 05:11:56 -0600787 {
Kirill Pakhomovdb5d9b02018-11-06 19:17:51 +0300788 uint16_t val = data.value(cap.name.c_str(), 0);
789 // According to DCMI spec v1.5, max number of SEL entries is
790 // 4096, but bit 12b of DCMI capabilities Mandatory Platform
791 // Attributes field is reserved and therefore we can use only
792 // the provided 12 bits with maximum value of 4095.
793 // We're playing safe here by applying the mask
794 // to ensure that provided value will fit into 12 bits.
795 if (cap.length > dcmi::gByteBitSize)
796 {
797 val &= dcmi::gMaxSELEntriesMask;
798 }
Dhruvaraj Subhashchandrane29be412018-01-16 05:11:56 -0600799 val <<= cap.position;
Kirill Pakhomovdb5d9b02018-11-06 19:17:51 +0300800 responseData->data[cap.bytePosition - 1] |=
801 static_cast<uint8_t>(val);
802 responseData->data[cap.bytePosition] |= val >> dcmi::gByteBitSize;
Dhruvaraj Subhashchandrane29be412018-01-16 05:11:56 -0600803 }
804 else
805 {
806 responseData->data[cap.bytePosition - 1] |=
807 data.value(cap.name.c_str(), 0) << cap.position;
808 }
809 }
810
811 responseData->groupID = dcmi::groupExtId;
812 responseData->major = DCMI_SPEC_MAJOR_VERSION;
813 responseData->minor = DCMI_SPEC_MINOR_VERSION;
814 responseData->paramRevision = DCMI_PARAMETER_REVISION;
815 *data_len = sizeof(*responseData) + caps->second.size;
816
817 return IPMI_CC_OK;
818}
819
Deepak Kodihalliee717d72018-01-24 04:53:09 -0600820namespace dcmi
821{
822namespace temp_readings
823{
824
Deepak Kodihallib1e8fba2018-01-24 04:57:10 -0600825Temperature readTemp(const std::string& dbusService,
826 const std::string& dbusPath)
827{
828 // Read the temperature value from d-bus object. Need some conversion.
829 // As per the interface xyz.openbmc_project.Sensor.Value, the temperature
James Feist9cc0ea52018-10-09 10:53:11 -0700830 // is an double and in degrees C. It needs to be scaled by using the
Deepak Kodihallib1e8fba2018-01-24 04:57:10 -0600831 // formula Value * 10^Scale. The ipmi spec has the temperature as a uint8_t,
832 // with a separate single bit for the sign.
833
834 sdbusplus::bus::bus bus{ipmid_get_sd_bus_connection()};
Patrick Venture0b02be92018-08-31 11:55:55 -0700835 auto result = ipmi::getAllDbusProperties(
836 bus, dbusService, dbusPath, "xyz.openbmc_project.Sensor.Value");
James Feist9cc0ea52018-10-09 10:53:11 -0700837 auto temperature = sdbusplus::message::variant_ns::visit(
838 ipmi::VariantToDoubleVisitor(), result.at("Value"));
839 double absTemp = std::abs(temperature);
Deepak Kodihallib1e8fba2018-01-24 04:57:10 -0600840
James Feist9cc0ea52018-10-09 10:53:11 -0700841 auto findFactor = result.find("Scale");
842 double factor = 0.0;
843 if (findFactor != result.end())
Deepak Kodihallib1e8fba2018-01-24 04:57:10 -0600844 {
James Feist9cc0ea52018-10-09 10:53:11 -0700845 factor = sdbusplus::message::variant_ns::visit(
846 ipmi::VariantToDoubleVisitor(), findFactor->second);
Deepak Kodihallib1e8fba2018-01-24 04:57:10 -0600847 }
James Feist9cc0ea52018-10-09 10:53:11 -0700848 double scale = std::pow(10, factor);
849
850 auto tempDegrees = absTemp * scale;
Deepak Kodihallib1e8fba2018-01-24 04:57:10 -0600851 // Max absolute temp as per ipmi spec is 128.
852 if (tempDegrees > maxTemp)
853 {
854 tempDegrees = maxTemp;
855 }
856
857 return std::make_tuple(static_cast<uint8_t>(tempDegrees),
858 (temperature < 0));
859}
860
Deepak Kodihalliee717d72018-01-24 04:53:09 -0600861std::tuple<Response, NumInstances> read(const std::string& type,
862 uint8_t instance)
863{
Deepak Kodihallib1e8fba2018-01-24 04:57:10 -0600864 Response response{};
865 sdbusplus::bus::bus bus{ipmid_get_sd_bus_connection()};
866
867 if (!instance)
868 {
869 log<level::ERR>("Expected non-zero instance");
870 elog<InternalFailure>();
871 }
872
Kirill Pakhomova2573622018-11-02 19:00:18 +0300873 auto data = parseJSONConfig(gDCMISensorsConfig);
Deepak Kodihallib1e8fba2018-01-24 04:57:10 -0600874 static const std::vector<Json> empty{};
875 std::vector<Json> readings = data.value(type, empty);
876 size_t numInstances = readings.size();
877 for (const auto& j : readings)
878 {
879 uint8_t instanceNum = j.value("instance", 0);
880 // Not the instance we're interested in
881 if (instanceNum != instance)
882 {
883 continue;
884 }
885
886 std::string path = j.value("dbus", "");
887 std::string service;
888 try
889 {
890 service =
Patrick Venture0b02be92018-08-31 11:55:55 -0700891 ipmi::getService(bus, "xyz.openbmc_project.Sensor.Value", path);
Deepak Kodihallib1e8fba2018-01-24 04:57:10 -0600892 }
893 catch (std::exception& e)
894 {
895 log<level::DEBUG>(e.what());
896 return std::make_tuple(response, numInstances);
897 }
898
899 response.instance = instance;
900 uint8_t temp{};
901 bool sign{};
902 std::tie(temp, sign) = readTemp(service, path);
903 response.temperature = temp;
904 response.sign = sign;
905
906 // Found the instance we're interested in
907 break;
908 }
909
910 if (numInstances > maxInstances)
911 {
912 numInstances = maxInstances;
913 }
914 return std::make_tuple(response, numInstances);
Deepak Kodihalliee717d72018-01-24 04:53:09 -0600915}
916
917std::tuple<ResponseList, NumInstances> readAll(const std::string& type,
918 uint8_t instanceStart)
919{
Deepak Kodihallib1e8fba2018-01-24 04:57:10 -0600920 ResponseList response{};
921 sdbusplus::bus::bus bus{ipmid_get_sd_bus_connection()};
922
923 size_t numInstances = 0;
Kirill Pakhomova2573622018-11-02 19:00:18 +0300924 auto data = parseJSONConfig(gDCMISensorsConfig);
Deepak Kodihallib1e8fba2018-01-24 04:57:10 -0600925 static const std::vector<Json> empty{};
926 std::vector<Json> readings = data.value(type, empty);
927 numInstances = readings.size();
928 for (const auto& j : readings)
929 {
930 try
931 {
932 // Max of 8 response data sets
933 if (response.size() == maxDataSets)
934 {
935 break;
936 }
937
938 uint8_t instanceNum = j.value("instance", 0);
939 // Not in the instance range we're interested in
940 if (instanceNum < instanceStart)
941 {
942 continue;
943 }
944
945 std::string path = j.value("dbus", "");
946 auto service =
Patrick Venture0b02be92018-08-31 11:55:55 -0700947 ipmi::getService(bus, "xyz.openbmc_project.Sensor.Value", path);
Deepak Kodihallib1e8fba2018-01-24 04:57:10 -0600948
949 Response r{};
950 r.instance = instanceNum;
951 uint8_t temp{};
952 bool sign{};
953 std::tie(temp, sign) = readTemp(service, path);
954 r.temperature = temp;
955 r.sign = sign;
956 response.push_back(r);
957 }
958 catch (std::exception& e)
959 {
960 log<level::DEBUG>(e.what());
961 continue;
962 }
963 }
964
965 if (numInstances > maxInstances)
966 {
967 numInstances = maxInstances;
968 }
969 return std::make_tuple(response, numInstances);
Deepak Kodihalliee717d72018-01-24 04:53:09 -0600970}
971
Patrick Venture0b02be92018-08-31 11:55:55 -0700972} // namespace temp_readings
973} // namespace dcmi
Deepak Kodihalliee717d72018-01-24 04:53:09 -0600974
975ipmi_ret_t getTempReadings(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
Patrick Venture0b02be92018-08-31 11:55:55 -0700976 ipmi_request_t request, ipmi_response_t response,
977 ipmi_data_len_t data_len, ipmi_context_t context)
Deepak Kodihalliee717d72018-01-24 04:53:09 -0600978{
Deepak Kodihalliee717d72018-01-24 04:53:09 -0600979 auto requestData =
980 reinterpret_cast<const dcmi::GetTempReadingsRequest*>(request);
981 auto responseData =
982 reinterpret_cast<dcmi::GetTempReadingsResponseHdr*>(response);
983
984 if (*data_len != sizeof(dcmi::GetTempReadingsRequest))
985 {
986 log<level::ERR>("Malformed request data",
987 entry("DATA_SIZE=%d", *data_len));
988 return IPMI_CC_REQ_DATA_LEN_INVALID;
989 }
990 *data_len = 0;
991
Deepak Kodihalli0b459552018-02-06 06:25:12 -0600992 auto it = dcmi::entityIdToName.find(requestData->entityId);
993 if (it == dcmi::entityIdToName.end())
Deepak Kodihalliee717d72018-01-24 04:53:09 -0600994 {
995 log<level::ERR>("Unknown Entity ID",
996 entry("ENTITY_ID=%d", requestData->entityId));
997 return IPMI_CC_INVALID_FIELD_REQUEST;
998 }
999
1000 if (requestData->groupID != dcmi::groupExtId)
1001 {
1002 log<level::ERR>("Invalid Group ID",
1003 entry("GROUP_ID=%d", requestData->groupID));
1004 return IPMI_CC_INVALID_FIELD_REQUEST;
1005 }
1006
1007 if (requestData->sensorType != dcmi::temperatureSensorType)
1008 {
1009 log<level::ERR>("Invalid sensor type",
1010 entry("SENSOR_TYPE=%d", requestData->sensorType));
1011 return IPMI_CC_INVALID_FIELD_REQUEST;
1012 }
1013
1014 dcmi::temp_readings::ResponseList temps{};
1015 try
1016 {
1017 if (!requestData->entityInstance)
1018 {
1019 // Read all instances
1020 std::tie(temps, responseData->numInstances) =
1021 dcmi::temp_readings::readAll(it->second,
1022 requestData->instanceStart);
1023 }
1024 else
1025 {
1026 // Read one instance
1027 temps.resize(1);
1028 std::tie(temps[0], responseData->numInstances) =
1029 dcmi::temp_readings::read(it->second,
1030 requestData->entityInstance);
1031 }
1032 responseData->numDataSets = temps.size();
1033 }
1034 catch (InternalFailure& e)
1035 {
1036 return IPMI_CC_UNSPECIFIED_ERROR;
1037 }
1038
1039 responseData->groupID = dcmi::groupExtId;
Patrick Venture0b02be92018-08-31 11:55:55 -07001040 size_t payloadSize = temps.size() * sizeof(dcmi::temp_readings::Response);
Deepak Kodihalliee717d72018-01-24 04:53:09 -06001041 if (!temps.empty())
1042 {
1043 memcpy(responseData + 1, // copy payload right after the response header
Patrick Venture0b02be92018-08-31 11:55:55 -07001044 temps.data(), payloadSize);
Deepak Kodihalliee717d72018-01-24 04:53:09 -06001045 }
1046 *data_len = sizeof(dcmi::GetTempReadingsResponseHdr) + payloadSize;
1047
1048 return IPMI_CC_OK;
1049}
1050
Marri Devender Rao66c5fda2018-01-18 10:48:37 -06001051int64_t getPowerReading(sdbusplus::bus::bus& bus)
1052{
1053 std::ifstream sensorFile(POWER_READING_SENSOR);
1054 std::string objectPath;
1055 if (!sensorFile.is_open())
1056 {
1057 log<level::ERR>("Power reading configuration file not found",
Patrick Venture0b02be92018-08-31 11:55:55 -07001058 entry("POWER_SENSOR_FILE=%s", POWER_READING_SENSOR));
Marri Devender Rao66c5fda2018-01-18 10:48:37 -06001059 elog<InternalFailure>();
1060 }
1061
1062 auto data = nlohmann::json::parse(sensorFile, nullptr, false);
1063 if (data.is_discarded())
1064 {
1065 log<level::ERR>("Error in parsing configuration file",
Patrick Venture0b02be92018-08-31 11:55:55 -07001066 entry("POWER_SENSOR_FILE=%s", POWER_READING_SENSOR));
Marri Devender Rao66c5fda2018-01-18 10:48:37 -06001067 elog<InternalFailure>();
1068 }
1069
1070 objectPath = data.value("path", "");
1071 if (objectPath.empty())
1072 {
1073 log<level::ERR>("Power sensor D-Bus object path is empty",
1074 entry("POWER_SENSOR_FILE=%s", POWER_READING_SENSOR));
1075 elog<InternalFailure>();
1076 }
1077
Marri Devender Raoce6a7952018-02-11 08:45:00 -06001078 // Return default value if failed to read from D-Bus object
1079 int64_t power = 0;
1080 try
1081 {
1082 auto service = ipmi::getService(bus, SENSOR_VALUE_INTF, objectPath);
Marri Devender Rao66c5fda2018-01-18 10:48:37 -06001083
Patrick Venture0b02be92018-08-31 11:55:55 -07001084 // Read the sensor value and scale properties
1085 auto properties = ipmi::getAllDbusProperties(bus, service, objectPath,
1086 SENSOR_VALUE_INTF);
William A. Kennington III4c008022018-10-12 17:18:14 -07001087 auto value = variant_ns::get<int64_t>(properties[SENSOR_VALUE_PROP]);
1088 auto scale = variant_ns::get<int64_t>(properties[SENSOR_SCALE_PROP]);
Marri Devender Rao66c5fda2018-01-18 10:48:37 -06001089
Marri Devender Raoce6a7952018-02-11 08:45:00 -06001090 // Power reading needs to be scaled with the Scale value using the
1091 // formula Value * 10^Scale.
1092 power = value * std::pow(10, scale);
1093 }
1094 catch (std::exception& e)
1095 {
1096 log<level::INFO>("Failure to read power value from D-Bus object",
Patrick Venture0b02be92018-08-31 11:55:55 -07001097 entry("OBJECT_PATH=%s", objectPath.c_str()),
1098 entry("INTERFACE=%s", SENSOR_VALUE_INTF));
Marri Devender Raoce6a7952018-02-11 08:45:00 -06001099 }
Marri Devender Rao66c5fda2018-01-18 10:48:37 -06001100 return power;
1101}
1102
Nagaraju Goruganti22be97b2018-02-07 01:19:59 -06001103ipmi_ret_t setDCMIConfParams(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
1104 ipmi_request_t request, ipmi_response_t response,
1105 ipmi_data_len_t data_len, ipmi_context_t context)
1106{
Patrick Venture0b02be92018-08-31 11:55:55 -07001107 auto requestData =
1108 reinterpret_cast<const dcmi::SetConfParamsRequest*>(request);
1109 auto responseData =
1110 reinterpret_cast<dcmi::SetConfParamsResponse*>(response);
Nagaraju Goruganti22be97b2018-02-07 01:19:59 -06001111
Patrick Venture0b02be92018-08-31 11:55:55 -07001112 if (requestData->groupID != dcmi::groupExtId ||
1113 *data_len < DCMI_SET_CONF_PARAM_REQ_PACKET_MIN_SIZE ||
1114 *data_len > DCMI_SET_CONF_PARAM_REQ_PACKET_MAX_SIZE)
Nagaraju Goruganti22be97b2018-02-07 01:19:59 -06001115 {
Gunnar Mills8466b792018-03-23 12:18:12 -05001116 log<level::ERR>("Invalid Group ID or Invalid Requested Packet size",
Nagaraju Goruganti22be97b2018-02-07 01:19:59 -06001117 entry("GROUP_ID=%d", requestData->groupID),
1118 entry("PACKET SIZE=%d", *data_len));
1119 return IPMI_CC_INVALID_FIELD_REQUEST;
1120 }
1121
1122 *data_len = 0;
1123
1124 try
1125 {
1126 // Take action based on the Parameter Selector
Patrick Venture0b02be92018-08-31 11:55:55 -07001127 switch (
1128 static_cast<dcmi::DCMIConfigParameters>(requestData->paramSelect))
Nagaraju Goruganti22be97b2018-02-07 01:19:59 -06001129 {
1130 case dcmi::DCMIConfigParameters::ActivateDHCP:
1131
1132 if ((requestData->data[0] & DCMI_ACTIVATE_DHCP_MASK) &&
Patrick Venture0b02be92018-08-31 11:55:55 -07001133 dcmi::getDHCPEnabled())
Nagaraju Goruganti22be97b2018-02-07 01:19:59 -06001134 {
Patrick Venture0b02be92018-08-31 11:55:55 -07001135 // When these conditions are met we have to trigger DHCP
1136 // protocol restart using the latest parameter settings, but
1137 // as per n/w manager design, each time when we update n/w
1138 // parameters, n/w service is restarted. So we no need to
1139 // take any action in this case.
Nagaraju Goruganti22be97b2018-02-07 01:19:59 -06001140 }
1141 break;
1142
1143 case dcmi::DCMIConfigParameters::DiscoveryConfig:
1144
1145 if (requestData->data[0] & DCMI_OPTION_12_MASK)
1146 {
1147 dcmi::setDHCPOption(DHCP_OPT12_ENABLED, true);
1148 }
1149 else
1150 {
1151 dcmi::setDHCPOption(DHCP_OPT12_ENABLED, false);
1152 }
1153
1154 // Systemd-networkd doesn't support Random Back off
1155 if (requestData->data[0] & DCMI_RAND_BACK_OFF_MASK)
1156 {
1157 return IPMI_CC_INVALID;
1158 }
1159 break;
1160 // Systemd-networkd doesn't allow to configure DHCP timigs
1161 case dcmi::DCMIConfigParameters::DHCPTiming1:
1162 case dcmi::DCMIConfigParameters::DHCPTiming2:
1163 case dcmi::DCMIConfigParameters::DHCPTiming3:
1164 default:
1165 return IPMI_CC_INVALID;
1166 }
1167 }
1168 catch (std::exception& e)
1169 {
1170 log<level::ERR>(e.what());
1171 return IPMI_CC_UNSPECIFIED_ERROR;
1172 }
1173 responseData->groupID = dcmi::groupExtId;
1174 *data_len = sizeof(dcmi::SetConfParamsResponse);
1175
1176 return IPMI_CC_OK;
1177}
1178
1179ipmi_ret_t getDCMIConfParams(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
1180 ipmi_request_t request, ipmi_response_t response,
1181 ipmi_data_len_t data_len, ipmi_context_t context)
1182{
1183
Patrick Venture0b02be92018-08-31 11:55:55 -07001184 auto requestData =
1185 reinterpret_cast<const dcmi::GetConfParamsRequest*>(request);
1186 auto responseData =
1187 reinterpret_cast<dcmi::GetConfParamsResponse*>(response);
Nagaraju Goruganti22be97b2018-02-07 01:19:59 -06001188
1189 responseData->data[0] = 0x00;
1190
Patrick Venture0b02be92018-08-31 11:55:55 -07001191 if (requestData->groupID != dcmi::groupExtId ||
1192 *data_len != sizeof(dcmi::GetConfParamsRequest))
Nagaraju Goruganti22be97b2018-02-07 01:19:59 -06001193 {
Gunnar Mills8466b792018-03-23 12:18:12 -05001194 log<level::ERR>("Invalid Group ID or Invalid Requested Packet size",
Nagaraju Goruganti22be97b2018-02-07 01:19:59 -06001195 entry("GROUP_ID=%d", requestData->groupID),
1196 entry("PACKET SIZE=%d", *data_len));
1197 return IPMI_CC_INVALID_FIELD_REQUEST;
1198 }
1199
1200 *data_len = 0;
1201
1202 try
1203 {
1204 // Take action based on the Parameter Selector
Patrick Venture0b02be92018-08-31 11:55:55 -07001205 switch (
1206 static_cast<dcmi::DCMIConfigParameters>(requestData->paramSelect))
Nagaraju Goruganti22be97b2018-02-07 01:19:59 -06001207 {
1208 case dcmi::DCMIConfigParameters::ActivateDHCP:
1209 responseData->data[0] = DCMI_ACTIVATE_DHCP_REPLY;
1210 *data_len = sizeof(dcmi::GetConfParamsResponse) + 1;
1211 break;
1212 case dcmi::DCMIConfigParameters::DiscoveryConfig:
1213 if (dcmi::getDHCPOption(DHCP_OPT12_ENABLED))
1214 {
1215 responseData->data[0] |= DCMI_OPTION_12_MASK;
1216 }
1217 *data_len = sizeof(dcmi::GetConfParamsResponse) + 1;
1218 break;
1219 // Get below values from Systemd-networkd source code
1220 case dcmi::DCMIConfigParameters::DHCPTiming1:
1221 responseData->data[0] = DHCP_TIMING1;
1222 *data_len = sizeof(dcmi::GetConfParamsResponse) + 1;
1223 break;
1224 case dcmi::DCMIConfigParameters::DHCPTiming2:
1225 responseData->data[0] = DHCP_TIMING2_LOWER;
1226 responseData->data[1] = DHCP_TIMING2_UPPER;
1227 *data_len = sizeof(dcmi::GetConfParamsResponse) + 2;
1228 break;
1229 case dcmi::DCMIConfigParameters::DHCPTiming3:
1230 responseData->data[0] = DHCP_TIMING3_LOWER;
1231 responseData->data[1] = DHCP_TIMING3_UPPER;
1232 *data_len = sizeof(dcmi::GetConfParamsResponse) + 2;
1233 break;
1234 default:
1235 *data_len = 0;
1236 return IPMI_CC_INVALID;
1237 }
1238 }
1239 catch (std::exception& e)
1240 {
1241 log<level::ERR>(e.what());
1242 return IPMI_CC_UNSPECIFIED_ERROR;
1243 }
1244
1245 responseData->groupID = dcmi::groupExtId;
1246 responseData->major = DCMI_SPEC_MAJOR_VERSION;
1247 responseData->minor = DCMI_SPEC_MINOR_VERSION;
1248 responseData->paramRevision = DCMI_CONFIG_PARAMETER_REVISION;
1249
1250 return IPMI_CC_OK;
1251}
1252
Marri Devender Rao66c5fda2018-01-18 10:48:37 -06001253ipmi_ret_t getPowerReading(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
Patrick Venture0b02be92018-08-31 11:55:55 -07001254 ipmi_request_t request, ipmi_response_t response,
1255 ipmi_data_len_t data_len, ipmi_context_t context)
Marri Devender Rao66c5fda2018-01-18 10:48:37 -06001256{
Kirill Pakhomov2c2af2c2018-11-06 16:06:10 +03001257 if (!dcmi::isDCMIPowerMgmtSupported())
1258 {
1259 *data_len = 0;
1260 log<level::ERR>("DCMI Power management is unsupported!");
1261 return IPMI_CC_INVALID;
1262 }
1263
Marri Devender Rao66c5fda2018-01-18 10:48:37 -06001264 ipmi_ret_t rc = IPMI_CC_OK;
Patrick Venture0b02be92018-08-31 11:55:55 -07001265 auto requestData =
1266 reinterpret_cast<const dcmi::GetPowerReadingRequest*>(request);
1267 auto responseData =
1268 reinterpret_cast<dcmi::GetPowerReadingResponse*>(response);
Marri Devender Rao9c966e02018-01-22 05:55:10 -06001269
1270 if (requestData->groupID != dcmi::groupExtId)
1271 {
1272 *data_len = 0;
1273 return IPMI_CC_INVALID_FIELD_REQUEST;
1274 }
1275
Marri Devender Rao66c5fda2018-01-18 10:48:37 -06001276 sdbusplus::bus::bus bus{ipmid_get_sd_bus_connection()};
Marri Devender Rao9c966e02018-01-22 05:55:10 -06001277 int64_t power = 0;
Marri Devender Rao66c5fda2018-01-18 10:48:37 -06001278 try
1279 {
Marri Devender Rao9c966e02018-01-22 05:55:10 -06001280 power = getPowerReading(bus);
Marri Devender Rao66c5fda2018-01-18 10:48:37 -06001281 }
1282 catch (InternalFailure& e)
1283 {
1284 log<level::ERR>("Error in reading power sensor value",
1285 entry("INTERFACE=%s", SENSOR_VALUE_INTF),
1286 entry("PROPERTY=%s", SENSOR_VALUE_PROP));
1287 return IPMI_CC_UNSPECIFIED_ERROR;
1288 }
Marri Devender Rao9c966e02018-01-22 05:55:10 -06001289 responseData->groupID = dcmi::groupExtId;
1290
1291 // TODO: openbmc/openbmc#2819
Gunnar Mills8466b792018-03-23 12:18:12 -05001292 // Minimum, Maximum, Average power, TimeFrame, TimeStamp,
Marri Devender Rao9c966e02018-01-22 05:55:10 -06001293 // PowerReadingState readings need to be populated
1294 // after Telemetry changes.
1295 uint16_t totalPower = static_cast<uint16_t>(power);
1296 responseData->currentPower = totalPower;
1297 responseData->minimumPower = totalPower;
1298 responseData->maximumPower = totalPower;
1299 responseData->averagePower = totalPower;
1300
1301 *data_len = sizeof(*responseData);
Marri Devender Rao66c5fda2018-01-18 10:48:37 -06001302 return rc;
1303}
1304
Deepak Kodihalli0b459552018-02-06 06:25:12 -06001305namespace dcmi
1306{
1307namespace sensor_info
1308{
1309
Deepak Kodihallidd4cff12018-02-06 06:48:29 -06001310Response createFromJson(const Json& config)
1311{
1312 Response response{};
1313 uint16_t recordId = config.value("record_id", 0);
1314 response.recordIdLsb = recordId & 0xFF;
1315 response.recordIdMsb = (recordId >> 8) & 0xFF;
1316 return response;
1317}
1318
Deepak Kodihalli0b459552018-02-06 06:25:12 -06001319std::tuple<Response, NumInstances> read(const std::string& type,
Patrick Venture0b02be92018-08-31 11:55:55 -07001320 uint8_t instance, const Json& config)
Deepak Kodihalli0b459552018-02-06 06:25:12 -06001321{
Deepak Kodihallidd4cff12018-02-06 06:48:29 -06001322 Response response{};
1323
1324 if (!instance)
1325 {
1326 log<level::ERR>("Expected non-zero instance");
1327 elog<InternalFailure>();
1328 }
1329
1330 static const std::vector<Json> empty{};
1331 std::vector<Json> readings = config.value(type, empty);
1332 size_t numInstances = readings.size();
1333 for (const auto& reading : readings)
1334 {
1335 uint8_t instanceNum = reading.value("instance", 0);
1336 // Not the instance we're interested in
1337 if (instanceNum != instance)
1338 {
1339 continue;
1340 }
1341
1342 response = createFromJson(reading);
1343
1344 // Found the instance we're interested in
1345 break;
1346 }
1347
1348 if (numInstances > maxInstances)
1349 {
1350 log<level::DEBUG>("Trimming IPMI num instances",
1351 entry("NUM_INSTANCES=%d", numInstances));
1352 numInstances = maxInstances;
1353 }
1354 return std::make_tuple(response, numInstances);
Deepak Kodihalli0b459552018-02-06 06:25:12 -06001355}
1356
Patrick Venture0b02be92018-08-31 11:55:55 -07001357std::tuple<ResponseList, NumInstances>
1358 readAll(const std::string& type, uint8_t instanceStart, const Json& config)
Deepak Kodihalli0b459552018-02-06 06:25:12 -06001359{
Deepak Kodihallidd4cff12018-02-06 06:48:29 -06001360 ResponseList responses{};
1361
1362 size_t numInstances = 0;
1363 static const std::vector<Json> empty{};
1364 std::vector<Json> readings = config.value(type, empty);
1365 numInstances = readings.size();
1366 for (const auto& reading : readings)
1367 {
1368 try
1369 {
1370 // Max of 8 records
1371 if (responses.size() == maxRecords)
1372 {
1373 break;
1374 }
1375
1376 uint8_t instanceNum = reading.value("instance", 0);
1377 // Not in the instance range we're interested in
1378 if (instanceNum < instanceStart)
1379 {
1380 continue;
1381 }
1382
1383 Response response = createFromJson(reading);
1384 responses.push_back(response);
1385 }
1386 catch (std::exception& e)
1387 {
1388 log<level::DEBUG>(e.what());
1389 continue;
1390 }
1391 }
1392
1393 if (numInstances > maxInstances)
1394 {
1395 log<level::DEBUG>("Trimming IPMI num instances",
1396 entry("NUM_INSTANCES=%d", numInstances));
1397 numInstances = maxInstances;
1398 }
1399 return std::make_tuple(responses, numInstances);
Deepak Kodihalli0b459552018-02-06 06:25:12 -06001400}
1401
1402} // namespace sensor_info
1403} // namespace dcmi
1404
1405ipmi_ret_t getSensorInfo(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
1406 ipmi_request_t request, ipmi_response_t response,
1407 ipmi_data_len_t data_len, ipmi_context_t context)
1408{
1409 auto requestData =
1410 reinterpret_cast<const dcmi::GetSensorInfoRequest*>(request);
1411 auto responseData =
1412 reinterpret_cast<dcmi::GetSensorInfoResponseHdr*>(response);
1413
1414 if (*data_len != sizeof(dcmi::GetSensorInfoRequest))
1415 {
1416 log<level::ERR>("Malformed request data",
1417 entry("DATA_SIZE=%d", *data_len));
1418 return IPMI_CC_REQ_DATA_LEN_INVALID;
1419 }
1420 *data_len = 0;
1421
1422 auto it = dcmi::entityIdToName.find(requestData->entityId);
1423 if (it == dcmi::entityIdToName.end())
1424 {
1425 log<level::ERR>("Unknown Entity ID",
1426 entry("ENTITY_ID=%d", requestData->entityId));
1427 return IPMI_CC_INVALID_FIELD_REQUEST;
1428 }
1429
1430 if (requestData->groupID != dcmi::groupExtId)
1431 {
1432 log<level::ERR>("Invalid Group ID",
1433 entry("GROUP_ID=%d", requestData->groupID));
1434 return IPMI_CC_INVALID_FIELD_REQUEST;
1435 }
1436
1437 if (requestData->sensorType != dcmi::temperatureSensorType)
1438 {
1439 log<level::ERR>("Invalid sensor type",
1440 entry("SENSOR_TYPE=%d", requestData->sensorType));
1441 return IPMI_CC_INVALID_FIELD_REQUEST;
1442 }
1443
1444 dcmi::sensor_info::ResponseList sensors{};
1445 static dcmi::Json config{};
1446 static bool parsed = false;
1447
1448 try
1449 {
1450 if (!parsed)
1451 {
Kirill Pakhomova2573622018-11-02 19:00:18 +03001452 config = dcmi::parseJSONConfig(dcmi::gDCMISensorsConfig);
Deepak Kodihalli0b459552018-02-06 06:25:12 -06001453 parsed = true;
1454 }
1455
1456 if (!requestData->entityInstance)
1457 {
1458 // Read all instances
1459 std::tie(sensors, responseData->numInstances) =
1460 dcmi::sensor_info::readAll(it->second,
Patrick Venture0b02be92018-08-31 11:55:55 -07001461 requestData->instanceStart, config);
Deepak Kodihalli0b459552018-02-06 06:25:12 -06001462 }
1463 else
1464 {
1465 // Read one instance
1466 sensors.resize(1);
1467 std::tie(sensors[0], responseData->numInstances) =
Patrick Venture0b02be92018-08-31 11:55:55 -07001468 dcmi::sensor_info::read(it->second, requestData->entityInstance,
Deepak Kodihalli0b459552018-02-06 06:25:12 -06001469 config);
1470 }
1471 responseData->numRecords = sensors.size();
1472 }
1473 catch (InternalFailure& e)
1474 {
1475 return IPMI_CC_UNSPECIFIED_ERROR;
1476 }
1477
1478 responseData->groupID = dcmi::groupExtId;
1479 size_t payloadSize = sensors.size() * sizeof(dcmi::sensor_info::Response);
1480 if (!sensors.empty())
1481 {
1482 memcpy(responseData + 1, // copy payload right after the response header
Patrick Venture0b02be92018-08-31 11:55:55 -07001483 sensors.data(), payloadSize);
Deepak Kodihalli0b459552018-02-06 06:25:12 -06001484 }
1485 *data_len = sizeof(dcmi::GetSensorInfoResponseHdr) + payloadSize;
1486
1487 return IPMI_CC_OK;
1488}
1489
Chris Austen1810bec2015-10-13 12:12:39 -05001490void register_netfn_dcmi_functions()
1491{
Tom05732372016-09-06 17:21:23 +05301492 // <Get Power Limit>
Ratan Gupta11ddbd22017-08-05 11:59:39 +05301493
Patrick Venture0b02be92018-08-31 11:55:55 -07001494 ipmi_register_callback(NETFUN_GRPEXT, dcmi::Commands::GET_POWER_LIMIT, NULL,
1495 getPowerLimit, PRIVILEGE_USER);
Tom Joseph6f6dd4d2017-07-12 20:07:11 +05301496
Tom Joseph46fa37d2017-07-26 18:11:55 +05301497 // <Set Power Limit>
Ratan Gupta11ddbd22017-08-05 11:59:39 +05301498
Patrick Venture0b02be92018-08-31 11:55:55 -07001499 ipmi_register_callback(NETFUN_GRPEXT, dcmi::Commands::SET_POWER_LIMIT, NULL,
1500 setPowerLimit, PRIVILEGE_OPERATOR);
Tom Joseph46fa37d2017-07-26 18:11:55 +05301501
Tom Joseph6c8d51b2017-07-26 18:18:06 +05301502 // <Activate/Deactivate Power Limit>
Ratan Gupta11ddbd22017-08-05 11:59:39 +05301503
1504 ipmi_register_callback(NETFUN_GRPEXT, dcmi::Commands::APPLY_POWER_LIMIT,
1505 NULL, applyPowerLimit, PRIVILEGE_OPERATOR);
Tom Joseph6c8d51b2017-07-26 18:18:06 +05301506
Tom Joseph6f6dd4d2017-07-12 20:07:11 +05301507 // <Get Asset Tag>
Ratan Gupta11ddbd22017-08-05 11:59:39 +05301508
Patrick Venture0b02be92018-08-31 11:55:55 -07001509 ipmi_register_callback(NETFUN_GRPEXT, dcmi::Commands::GET_ASSET_TAG, NULL,
1510 getAssetTag, PRIVILEGE_USER);
Tom Joseph545dd232017-07-12 20:20:49 +05301511
1512 // <Set Asset Tag>
Ratan Gupta11ddbd22017-08-05 11:59:39 +05301513
Patrick Venture0b02be92018-08-31 11:55:55 -07001514 ipmi_register_callback(NETFUN_GRPEXT, dcmi::Commands::SET_ASSET_TAG, NULL,
1515 setAssetTag, PRIVILEGE_OPERATOR);
Vladislav Vovchenko8f7a6f62017-08-17 00:31:14 +03001516
Gunnar Mills8991dd62017-10-25 17:11:29 -05001517 // <Get Management Controller Identifier String>
Vladislav Vovchenko8f7a6f62017-08-17 00:31:14 +03001518
1519 ipmi_register_callback(NETFUN_GRPEXT, dcmi::Commands::GET_MGMNT_CTRL_ID_STR,
Patrick Venture0b02be92018-08-31 11:55:55 -07001520 NULL, getMgmntCtrlIdStr, PRIVILEGE_USER);
Vladislav Vovchenko8f7a6f62017-08-17 00:31:14 +03001521
1522 // <Set Management Controller Identifier String>
Vladislav Vovchenko8f7a6f62017-08-17 00:31:14 +03001523 ipmi_register_callback(NETFUN_GRPEXT, dcmi::Commands::SET_MGMNT_CTRL_ID_STR,
Patrick Venture0b02be92018-08-31 11:55:55 -07001524 NULL, setMgmntCtrlIdStr, PRIVILEGE_ADMIN);
Vladislav Vovchenko8f7a6f62017-08-17 00:31:14 +03001525
Dhruvaraj Subhashchandrane29be412018-01-16 05:11:56 -06001526 // <Get DCMI capabilities>
1527 ipmi_register_callback(NETFUN_GRPEXT, dcmi::Commands::GET_CAPABILITIES,
Patrick Venture0b02be92018-08-31 11:55:55 -07001528 NULL, getDCMICapabilities, PRIVILEGE_USER);
Deepak Kodihalliee717d72018-01-24 04:53:09 -06001529
1530 // <Get Temperature Readings>
1531 ipmi_register_callback(NETFUN_GRPEXT, dcmi::Commands::GET_TEMP_READINGS,
1532 NULL, getTempReadings, PRIVILEGE_USER);
1533
Marri Devender Rao66c5fda2018-01-18 10:48:37 -06001534 // <Get Power Reading>
1535 ipmi_register_callback(NETFUN_GRPEXT, dcmi::Commands::GET_POWER_READING,
1536 NULL, getPowerReading, PRIVILEGE_USER);
Deepak Kodihalli0b459552018-02-06 06:25:12 -06001537
1538 // <Get Sensor Info>
Patrick Venture0b02be92018-08-31 11:55:55 -07001539 ipmi_register_callback(NETFUN_GRPEXT, dcmi::Commands::GET_SENSOR_INFO, NULL,
1540 getSensorInfo, PRIVILEGE_USER);
Deepak Kodihalli0b459552018-02-06 06:25:12 -06001541
Nagaraju Goruganti22be97b2018-02-07 01:19:59 -06001542 // <Get DCMI Configuration Parameters>
Patrick Venture0b02be92018-08-31 11:55:55 -07001543 ipmi_register_callback(NETFUN_GRPEXT, dcmi::Commands::GET_CONF_PARAMS, NULL,
1544 getDCMIConfParams, PRIVILEGE_USER);
Nagaraju Goruganti22be97b2018-02-07 01:19:59 -06001545
1546 // <Set DCMI Configuration Parameters>
Patrick Venture0b02be92018-08-31 11:55:55 -07001547 ipmi_register_callback(NETFUN_GRPEXT, dcmi::Commands::SET_CONF_PARAMS, NULL,
1548 setDCMIConfParams, PRIVILEGE_ADMIN);
Nagaraju Goruganti22be97b2018-02-07 01:19:59 -06001549
Chris Austen1810bec2015-10-13 12:12:39 -05001550 return;
1551}
Tom05732372016-09-06 17:21:23 +05301552// 956379