blob: 2ab02f33159240b701e0b7a164787dcb79476ad6 [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>
Vernon Mauery16b86932019-05-01 08:36:11 -070016#include <variant>
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;
William A. Kennington III5d06cc62019-04-25 02:10:55 -070040constexpr auto DCMI_SET_CONF_PARAM_REQ_PACKET_MAX_SIZE = 0x04;
41constexpr auto DCMI_SET_CONF_PARAM_REQ_PACKET_MIN_SIZE = 0x03;
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;
57
Tom Josephb9d86f42017-07-26 18:03:47 +053058namespace dcmi
59{
60
Deepak Kodihalli0b459552018-02-06 06:25:12 -060061// Refer Table 6-14, DCMI Entity ID Extension, DCMI v1.5 spec
Patrick Venture0b02be92018-08-31 11:55:55 -070062static const std::map<uint8_t, std::string> entityIdToName{
63 {0x40, "inlet"}, {0x37, "inlet"}, {0x41, "cpu"},
64 {0x03, "cpu"}, {0x42, "baseboard"}, {0x07, "baseboard"}};
Deepak Kodihalli0b459552018-02-06 06:25:12 -060065
Kirill Pakhomov2c2af2c2018-11-06 16:06:10 +030066bool isDCMIPowerMgmtSupported()
67{
68 auto data = parseJSONConfig(gDCMICapabilitiesConfig);
69
70 return (gDCMIPowerMgmtSupported == data.value(gDCMIPowerMgmtCapability, 0));
71}
72
Andrew Geissler50c0c8f2017-07-11 16:18:51 -050073uint32_t getPcap(sdbusplus::bus::bus& bus)
74{
Patrick Venture0b02be92018-08-31 11:55:55 -070075 auto settingService = ipmi::getService(bus, PCAP_INTERFACE, PCAP_PATH);
Andrew Geissler50c0c8f2017-07-11 16:18:51 -050076
Patrick Venture0b02be92018-08-31 11:55:55 -070077 auto method = bus.new_method_call(settingService.c_str(), PCAP_PATH,
78 "org.freedesktop.DBus.Properties", "Get");
Andrew Geissler50c0c8f2017-07-11 16:18:51 -050079
80 method.append(PCAP_INTERFACE, POWER_CAP_PROP);
81 auto reply = bus.call(method);
82
83 if (reply.is_method_error())
84 {
85 log<level::ERR>("Error in getPcap prop");
Tom Josephb9d86f42017-07-26 18:03:47 +053086 elog<InternalFailure>();
Andrew Geissler50c0c8f2017-07-11 16:18:51 -050087 }
Vernon Mauery16b86932019-05-01 08:36:11 -070088 std::variant<uint32_t> pcap;
Andrew Geissler50c0c8f2017-07-11 16:18:51 -050089 reply.read(pcap);
90
Vernon Maueryf442e112019-04-09 11:44:36 -070091 return std::get<uint32_t>(pcap);
Andrew Geissler50c0c8f2017-07-11 16:18:51 -050092}
93
94bool getPcapEnabled(sdbusplus::bus::bus& bus)
95{
Patrick Venture0b02be92018-08-31 11:55:55 -070096 auto settingService = ipmi::getService(bus, PCAP_INTERFACE, PCAP_PATH);
Andrew Geissler50c0c8f2017-07-11 16:18:51 -050097
Patrick Venture0b02be92018-08-31 11:55:55 -070098 auto method = bus.new_method_call(settingService.c_str(), PCAP_PATH,
99 "org.freedesktop.DBus.Properties", "Get");
Andrew Geissler50c0c8f2017-07-11 16:18:51 -0500100
101 method.append(PCAP_INTERFACE, POWER_CAP_ENABLE_PROP);
102 auto reply = bus.call(method);
103
104 if (reply.is_method_error())
105 {
106 log<level::ERR>("Error in getPcapEnabled prop");
Tom Josephb9d86f42017-07-26 18:03:47 +0530107 elog<InternalFailure>();
Andrew Geissler50c0c8f2017-07-11 16:18:51 -0500108 }
Vernon Mauery16b86932019-05-01 08:36:11 -0700109 std::variant<bool> pcapEnabled;
Andrew Geissler50c0c8f2017-07-11 16:18:51 -0500110 reply.read(pcapEnabled);
111
Vernon Maueryf442e112019-04-09 11:44:36 -0700112 return std::get<bool>(pcapEnabled);
Andrew Geissler50c0c8f2017-07-11 16:18:51 -0500113}
Chris Austen1810bec2015-10-13 12:12:39 -0500114
Tom Joseph46fa37d2017-07-26 18:11:55 +0530115void setPcap(sdbusplus::bus::bus& bus, const uint32_t powerCap)
116{
117 auto service = ipmi::getService(bus, PCAP_INTERFACE, PCAP_PATH);
118
Patrick Venture0b02be92018-08-31 11:55:55 -0700119 auto method = bus.new_method_call(service.c_str(), PCAP_PATH,
120 "org.freedesktop.DBus.Properties", "Set");
Tom Joseph46fa37d2017-07-26 18:11:55 +0530121
122 method.append(PCAP_INTERFACE, POWER_CAP_PROP);
Vernon Mauery16b86932019-05-01 08:36:11 -0700123 method.append(std::variant<uint32_t>(powerCap));
Tom Joseph46fa37d2017-07-26 18:11:55 +0530124
125 auto reply = bus.call(method);
126
127 if (reply.is_method_error())
128 {
129 log<level::ERR>("Error in setPcap property");
130 elog<InternalFailure>();
131 }
132}
133
Tom Joseph6c8d51b2017-07-26 18:18:06 +0530134void setPcapEnable(sdbusplus::bus::bus& bus, bool enabled)
135{
136 auto service = ipmi::getService(bus, PCAP_INTERFACE, PCAP_PATH);
137
Patrick Venture0b02be92018-08-31 11:55:55 -0700138 auto method = bus.new_method_call(service.c_str(), PCAP_PATH,
139 "org.freedesktop.DBus.Properties", "Set");
Tom Joseph6c8d51b2017-07-26 18:18:06 +0530140
141 method.append(PCAP_INTERFACE, POWER_CAP_ENABLE_PROP);
Vernon Mauery16b86932019-05-01 08:36:11 -0700142 method.append(std::variant<bool>(enabled));
Tom Joseph6c8d51b2017-07-26 18:18:06 +0530143
144 auto reply = bus.call(method);
145
146 if (reply.is_method_error())
147 {
148 log<level::ERR>("Error in setPcapEnabled property");
149 elog<InternalFailure>();
150 }
151}
152
Tom Josephbe5eaa12017-07-12 19:54:44 +0530153void readAssetTagObjectTree(dcmi::assettag::ObjectTree& objectTree)
154{
155 static constexpr auto mapperBusName = "xyz.openbmc_project.ObjectMapper";
156 static constexpr auto mapperObjPath = "/xyz/openbmc_project/object_mapper";
157 static constexpr auto mapperIface = "xyz.openbmc_project.ObjectMapper";
158 static constexpr auto inventoryRoot = "/xyz/openbmc_project/inventory/";
159
160 sdbusplus::bus::bus bus{ipmid_get_sd_bus_connection()};
161 auto depth = 0;
162
Patrick Venture0b02be92018-08-31 11:55:55 -0700163 auto mapperCall = bus.new_method_call(mapperBusName, mapperObjPath,
164 mapperIface, "GetSubTree");
Tom Josephbe5eaa12017-07-12 19:54:44 +0530165
166 mapperCall.append(inventoryRoot);
167 mapperCall.append(depth);
168 mapperCall.append(std::vector<std::string>({dcmi::assetTagIntf}));
169
170 auto mapperReply = bus.call(mapperCall);
171 if (mapperReply.is_method_error())
172 {
173 log<level::ERR>("Error in mapper call");
174 elog<InternalFailure>();
175 }
176
177 mapperReply.read(objectTree);
178
179 if (objectTree.empty())
180 {
181 log<level::ERR>("AssetTag property is not populated");
182 elog<InternalFailure>();
183 }
184}
185
186std::string readAssetTag()
187{
188 sdbusplus::bus::bus bus{ipmid_get_sd_bus_connection()};
189 dcmi::assettag::ObjectTree objectTree;
190
191 // Read the object tree with the inventory root to figure out the object
192 // that has implemented the Asset tag interface.
193 readAssetTagObjectTree(objectTree);
194
195 auto method = bus.new_method_call(
Patrick Venture0b02be92018-08-31 11:55:55 -0700196 (objectTree.begin()->second.begin()->first).c_str(),
197 (objectTree.begin()->first).c_str(), dcmi::propIntf, "Get");
Tom Josephbe5eaa12017-07-12 19:54:44 +0530198 method.append(dcmi::assetTagIntf);
199 method.append(dcmi::assetTagProp);
200
201 auto reply = bus.call(method);
202 if (reply.is_method_error())
203 {
204 log<level::ERR>("Error in reading asset tag");
205 elog<InternalFailure>();
206 }
207
Vernon Mauery16b86932019-05-01 08:36:11 -0700208 std::variant<std::string> assetTag;
Tom Josephbe5eaa12017-07-12 19:54:44 +0530209 reply.read(assetTag);
210
Vernon Maueryf442e112019-04-09 11:44:36 -0700211 return std::get<std::string>(assetTag);
Tom Josephbe5eaa12017-07-12 19:54:44 +0530212}
213
Tom Josephbe5b9892017-07-15 00:55:23 +0530214void writeAssetTag(const std::string& assetTag)
215{
216 sdbusplus::bus::bus bus{ipmid_get_sd_bus_connection()};
217 dcmi::assettag::ObjectTree objectTree;
218
219 // Read the object tree with the inventory root to figure out the object
220 // that has implemented the Asset tag interface.
221 readAssetTagObjectTree(objectTree);
222
223 auto method = bus.new_method_call(
Patrick Venture0b02be92018-08-31 11:55:55 -0700224 (objectTree.begin()->second.begin()->first).c_str(),
225 (objectTree.begin()->first).c_str(), dcmi::propIntf, "Set");
Tom Josephbe5b9892017-07-15 00:55:23 +0530226 method.append(dcmi::assetTagIntf);
227 method.append(dcmi::assetTagProp);
Vernon Mauery16b86932019-05-01 08:36:11 -0700228 method.append(std::variant<std::string>(assetTag));
Tom Josephbe5b9892017-07-15 00:55:23 +0530229
230 auto reply = bus.call(method);
231 if (reply.is_method_error())
232 {
233 log<level::ERR>("Error in writing asset tag");
234 elog<InternalFailure>();
235 }
236}
237
Vladislav Vovchenko8f7a6f62017-08-17 00:31:14 +0300238std::string getHostName(void)
239{
Patrick Venture0b02be92018-08-31 11:55:55 -0700240 sdbusplus::bus::bus bus{ipmid_get_sd_bus_connection()};
Vladislav Vovchenko8f7a6f62017-08-17 00:31:14 +0300241
242 auto service = ipmi::getService(bus, networkConfigIntf, networkConfigObj);
Patrick Venture0b02be92018-08-31 11:55:55 -0700243 auto value = ipmi::getDbusProperty(bus, service, networkConfigObj,
244 networkConfigIntf, hostNameProp);
Vladislav Vovchenko8f7a6f62017-08-17 00:31:14 +0300245
Vernon Maueryf442e112019-04-09 11:44:36 -0700246 return std::get<std::string>(value);
Vladislav Vovchenko8f7a6f62017-08-17 00:31:14 +0300247}
248
Nagaraju Goruganti22be97b2018-02-07 01:19:59 -0600249bool getDHCPEnabled()
250{
251 sdbusplus::bus::bus bus{ipmid_get_sd_bus_connection()};
252
Johnathan Mantey74a21022018-12-13 13:17:56 -0800253 auto ethdevice = ipmi::getChannelName(ethernetDefaultChannelNum);
Patrick Venture0b02be92018-08-31 11:55:55 -0700254 auto ethernetObj =
255 ipmi::getDbusObject(bus, ethernetIntf, networkRoot, ethdevice);
Nagaraju Goruganti22be97b2018-02-07 01:19:59 -0600256 auto service = ipmi::getService(bus, ethernetIntf, ethernetObj.first);
Patrick Venture0b02be92018-08-31 11:55:55 -0700257 auto value = ipmi::getDbusProperty(bus, service, ethernetObj.first,
258 ethernetIntf, "DHCPEnabled");
Nagaraju Goruganti22be97b2018-02-07 01:19:59 -0600259
Vernon Maueryf442e112019-04-09 11:44:36 -0700260 return std::get<bool>(value);
Nagaraju Goruganti22be97b2018-02-07 01:19:59 -0600261}
262
263bool getDHCPOption(std::string prop)
264{
265 sdbusplus::bus::bus bus{ipmid_get_sd_bus_connection()};
266
267 auto service = ipmi::getService(bus, dhcpIntf, dhcpObj);
268 auto value = ipmi::getDbusProperty(bus, service, dhcpObj, dhcpIntf, prop);
269
Vernon Maueryf442e112019-04-09 11:44:36 -0700270 return std::get<bool>(value);
Nagaraju Goruganti22be97b2018-02-07 01:19:59 -0600271}
272
Nagaraju Goruganti22be97b2018-02-07 01:19:59 -0600273void setDHCPOption(std::string prop, bool value)
274{
275 sdbusplus::bus::bus bus{ipmid_get_sd_bus_connection()};
276
277 auto service = ipmi::getService(bus, dhcpIntf, dhcpObj);
278 ipmi::setDbusProperty(bus, service, dhcpObj, dhcpIntf, prop, value);
279}
280
Kirill Pakhomova2573622018-11-02 19:00:18 +0300281Json parseJSONConfig(const std::string& configFile)
Deepak Kodihalli0b459552018-02-06 06:25:12 -0600282{
283 std::ifstream jsonFile(configFile);
284 if (!jsonFile.is_open())
285 {
286 log<level::ERR>("Temperature readings JSON file not found");
287 elog<InternalFailure>();
288 }
289
290 auto data = Json::parse(jsonFile, nullptr, false);
291 if (data.is_discarded())
292 {
293 log<level::ERR>("Temperature readings JSON parser failure");
294 elog<InternalFailure>();
295 }
296
297 return data;
298}
299
Tom Josephbe5eaa12017-07-12 19:54:44 +0530300} // namespace dcmi
Chris Austen1810bec2015-10-13 12:12:39 -0500301
Tom Josephb9d86f42017-07-26 18:03:47 +0530302ipmi_ret_t getPowerLimit(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
303 ipmi_request_t request, ipmi_response_t response,
304 ipmi_data_len_t data_len, ipmi_context_t context)
305{
Kirill Pakhomov2c2af2c2018-11-06 16:06:10 +0300306 if (!dcmi::isDCMIPowerMgmtSupported())
307 {
308 *data_len = 0;
309 log<level::ERR>("DCMI Power management is unsupported!");
310 return IPMI_CC_INVALID;
311 }
312
Tom Josephb9d86f42017-07-26 18:03:47 +0530313 std::vector<uint8_t> outPayload(sizeof(dcmi::GetPowerLimitResponse));
Patrick Venture0b02be92018-08-31 11:55:55 -0700314 auto responseData =
315 reinterpret_cast<dcmi::GetPowerLimitResponse*>(outPayload.data());
Tom Josephb9d86f42017-07-26 18:03:47 +0530316
Patrick Venture0b02be92018-08-31 11:55:55 -0700317 sdbusplus::bus::bus sdbus{ipmid_get_sd_bus_connection()};
Tom Josephb9d86f42017-07-26 18:03:47 +0530318 uint32_t pcapValue = 0;
319 bool pcapEnable = false;
320
321 try
322 {
323 pcapValue = dcmi::getPcap(sdbus);
324 pcapEnable = dcmi::getPcapEnabled(sdbus);
325 }
Patrick Williamsa2ad2da2021-10-06 12:21:46 -0500326 catch (const InternalFailure& e)
Tom Josephb9d86f42017-07-26 18:03:47 +0530327 {
328 *data_len = 0;
329 return IPMI_CC_UNSPECIFIED_ERROR;
330 }
331
Tom Josephb9d86f42017-07-26 18:03:47 +0530332 /*
333 * Exception action if power limit is exceeded and cannot be controlled
334 * with the correction time limit is hardcoded to Hard Power Off system
335 * and log event to SEL.
336 */
337 constexpr auto exception = 0x01;
338 responseData->exceptionAction = exception;
339
340 responseData->powerLimit = static_cast<uint16_t>(pcapValue);
341
342 /*
343 * Correction time limit and Statistics sampling period is currently not
344 * populated.
345 */
346
347 *data_len = outPayload.size();
348 memcpy(response, outPayload.data(), *data_len);
349
350 if (pcapEnable)
351 {
352 return IPMI_CC_OK;
353 }
354 else
355 {
356 return IPMI_DCMI_CC_NO_ACTIVE_POWER_LIMIT;
357 }
358}
359
Tom Joseph46fa37d2017-07-26 18:11:55 +0530360ipmi_ret_t setPowerLimit(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
361 ipmi_request_t request, ipmi_response_t response,
362 ipmi_data_len_t data_len, ipmi_context_t context)
363{
Kirill Pakhomov2c2af2c2018-11-06 16:06:10 +0300364 if (!dcmi::isDCMIPowerMgmtSupported())
365 {
366 *data_len = 0;
367 log<level::ERR>("DCMI Power management is unsupported!");
368 return IPMI_CC_INVALID;
369 }
370
Patrick Venture0b02be92018-08-31 11:55:55 -0700371 auto requestData =
372 reinterpret_cast<const dcmi::SetPowerLimitRequest*>(request);
Tom Joseph46fa37d2017-07-26 18:11:55 +0530373
Patrick Venture0b02be92018-08-31 11:55:55 -0700374 sdbusplus::bus::bus sdbus{ipmid_get_sd_bus_connection()};
Tom Joseph46fa37d2017-07-26 18:11:55 +0530375
376 // Only process the power limit requested in watts.
377 try
378 {
379 dcmi::setPcap(sdbus, requestData->powerLimit);
380 }
Patrick Williamsa2ad2da2021-10-06 12:21:46 -0500381 catch (const InternalFailure& e)
Tom Joseph46fa37d2017-07-26 18:11:55 +0530382 {
383 *data_len = 0;
384 return IPMI_CC_UNSPECIFIED_ERROR;
385 }
386
387 log<level::INFO>("Set Power Cap",
388 entry("POWERCAP=%u", requestData->powerLimit));
389
William A. Kennington III5d06cc62019-04-25 02:10:55 -0700390 *data_len = 0;
Tom Joseph46fa37d2017-07-26 18:11:55 +0530391 return IPMI_CC_OK;
392}
393
Tom Joseph6c8d51b2017-07-26 18:18:06 +0530394ipmi_ret_t applyPowerLimit(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
395 ipmi_request_t request, ipmi_response_t response,
396 ipmi_data_len_t data_len, ipmi_context_t context)
397{
Kirill Pakhomov2c2af2c2018-11-06 16:06:10 +0300398 if (!dcmi::isDCMIPowerMgmtSupported())
399 {
400 *data_len = 0;
401 log<level::ERR>("DCMI Power management is unsupported!");
402 return IPMI_CC_INVALID;
403 }
404
Patrick Venture0b02be92018-08-31 11:55:55 -0700405 auto requestData =
406 reinterpret_cast<const dcmi::ApplyPowerLimitRequest*>(request);
Tom Joseph6c8d51b2017-07-26 18:18:06 +0530407
Patrick Venture0b02be92018-08-31 11:55:55 -0700408 sdbusplus::bus::bus sdbus{ipmid_get_sd_bus_connection()};
Tom Joseph6c8d51b2017-07-26 18:18:06 +0530409
410 try
411 {
412 dcmi::setPcapEnable(sdbus,
413 static_cast<bool>(requestData->powerLimitAction));
414 }
Patrick Williamsa2ad2da2021-10-06 12:21:46 -0500415 catch (const InternalFailure& e)
Tom Joseph6c8d51b2017-07-26 18:18:06 +0530416 {
417 *data_len = 0;
418 return IPMI_CC_UNSPECIFIED_ERROR;
419 }
420
421 log<level::INFO>("Set Power Cap Enable",
422 entry("POWERCAPENABLE=%u", requestData->powerLimitAction));
423
William A. Kennington III5d06cc62019-04-25 02:10:55 -0700424 *data_len = 0;
Tom Joseph6c8d51b2017-07-26 18:18:06 +0530425 return IPMI_CC_OK;
426}
427
Tom Joseph6f6dd4d2017-07-12 20:07:11 +0530428ipmi_ret_t getAssetTag(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
429 ipmi_request_t request, ipmi_response_t response,
430 ipmi_data_len_t data_len, ipmi_context_t context)
431{
Patrick Venture0b02be92018-08-31 11:55:55 -0700432 auto requestData =
433 reinterpret_cast<const dcmi::GetAssetTagRequest*>(request);
Tom Joseph6f6dd4d2017-07-12 20:07:11 +0530434 std::vector<uint8_t> outPayload(sizeof(dcmi::GetAssetTagResponse));
Patrick Venture0b02be92018-08-31 11:55:55 -0700435 auto responseData =
436 reinterpret_cast<dcmi::GetAssetTagResponse*>(outPayload.data());
Tom Joseph6f6dd4d2017-07-12 20:07:11 +0530437
Tom Joseph6f6dd4d2017-07-12 20:07:11 +0530438 // Verify offset to read and number of bytes to read are not exceeding the
439 // range.
440 if ((requestData->offset > dcmi::assetTagMaxOffset) ||
441 (requestData->bytes > dcmi::maxBytes) ||
442 ((requestData->offset + requestData->bytes) > dcmi::assetTagMaxSize))
443 {
444 *data_len = 0;
445 return IPMI_CC_PARM_OUT_OF_RANGE;
446 }
447
448 std::string assetTag;
449
450 try
451 {
452 assetTag = dcmi::readAssetTag();
453 }
Patrick Williamsa2ad2da2021-10-06 12:21:46 -0500454 catch (const InternalFailure& e)
Tom Joseph6f6dd4d2017-07-12 20:07:11 +0530455 {
456 *data_len = 0;
457 return IPMI_CC_UNSPECIFIED_ERROR;
458 }
459
Tom Joseph6f6dd4d2017-07-12 20:07:11 +0530460 // Return if the asset tag is not populated.
461 if (!assetTag.size())
462 {
463 responseData->tagLength = 0;
464 memcpy(response, outPayload.data(), outPayload.size());
465 *data_len = outPayload.size();
466 return IPMI_CC_OK;
467 }
468
469 // If the asset tag is longer than 63 bytes, restrict it to 63 bytes to suit
470 // Get Asset Tag command.
471 if (assetTag.size() > dcmi::assetTagMaxSize)
472 {
473 assetTag.resize(dcmi::assetTagMaxSize);
474 }
475
476 // If the requested offset is beyond the asset tag size.
477 if (requestData->offset >= assetTag.size())
478 {
479 *data_len = 0;
480 return IPMI_CC_PARM_OUT_OF_RANGE;
481 }
482
483 auto returnData = assetTag.substr(requestData->offset, requestData->bytes);
484
485 responseData->tagLength = assetTag.size();
486
487 memcpy(response, outPayload.data(), outPayload.size());
488 memcpy(static_cast<uint8_t*>(response) + outPayload.size(),
489 returnData.data(), returnData.size());
490 *data_len = outPayload.size() + returnData.size();
491
492 return IPMI_CC_OK;
493}
494
Tom Joseph545dd232017-07-12 20:20:49 +0530495ipmi_ret_t setAssetTag(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
496 ipmi_request_t request, ipmi_response_t response,
497 ipmi_data_len_t data_len, ipmi_context_t context)
498{
Patrick Venture0b02be92018-08-31 11:55:55 -0700499 auto requestData =
500 reinterpret_cast<const dcmi::SetAssetTagRequest*>(request);
Tom Joseph545dd232017-07-12 20:20:49 +0530501 std::vector<uint8_t> outPayload(sizeof(dcmi::SetAssetTagResponse));
Patrick Venture0b02be92018-08-31 11:55:55 -0700502 auto responseData =
503 reinterpret_cast<dcmi::SetAssetTagResponse*>(outPayload.data());
Tom Joseph545dd232017-07-12 20:20:49 +0530504
Tom Joseph545dd232017-07-12 20:20:49 +0530505 // Verify offset to read and number of bytes to read are not exceeding the
506 // range.
507 if ((requestData->offset > dcmi::assetTagMaxOffset) ||
508 (requestData->bytes > dcmi::maxBytes) ||
509 ((requestData->offset + requestData->bytes) > dcmi::assetTagMaxSize))
510 {
511 *data_len = 0;
512 return IPMI_CC_PARM_OUT_OF_RANGE;
513 }
514
515 std::string assetTag;
516
517 try
518 {
519 assetTag = dcmi::readAssetTag();
520
521 if (requestData->offset > assetTag.size())
522 {
523 *data_len = 0;
524 return IPMI_CC_PARM_OUT_OF_RANGE;
525 }
526
527 assetTag.replace(requestData->offset,
528 assetTag.size() - requestData->offset,
529 static_cast<const char*>(request) +
Patrick Venture0b02be92018-08-31 11:55:55 -0700530 sizeof(dcmi::SetAssetTagRequest),
Tom Joseph545dd232017-07-12 20:20:49 +0530531 requestData->bytes);
532
533 dcmi::writeAssetTag(assetTag);
534
Tom Joseph545dd232017-07-12 20:20:49 +0530535 responseData->tagLength = assetTag.size();
536 memcpy(response, outPayload.data(), outPayload.size());
537 *data_len = outPayload.size();
538
539 return IPMI_CC_OK;
540 }
Patrick Williamsa2ad2da2021-10-06 12:21:46 -0500541 catch (const InternalFailure& e)
Tom Joseph545dd232017-07-12 20:20:49 +0530542 {
543 *data_len = 0;
544 return IPMI_CC_UNSPECIFIED_ERROR;
545 }
546}
547
Vladislav Vovchenko8f7a6f62017-08-17 00:31:14 +0300548ipmi_ret_t getMgmntCtrlIdStr(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
Patrick Venture0b02be92018-08-31 11:55:55 -0700549 ipmi_request_t request, ipmi_response_t response,
550 ipmi_data_len_t data_len, ipmi_context_t context)
Vladislav Vovchenko8f7a6f62017-08-17 00:31:14 +0300551{
Patrick Venture0b02be92018-08-31 11:55:55 -0700552 auto requestData =
553 reinterpret_cast<const dcmi::GetMgmntCtrlIdStrRequest*>(request);
554 auto responseData =
555 reinterpret_cast<dcmi::GetMgmntCtrlIdStrResponse*>(response);
Vladislav Vovchenko8f7a6f62017-08-17 00:31:14 +0300556 std::string hostName;
557
558 *data_len = 0;
559
William A. Kennington III5d06cc62019-04-25 02:10:55 -0700560 if (requestData->bytes > dcmi::maxBytes ||
Vladislav Vovchenko8f7a6f62017-08-17 00:31:14 +0300561 requestData->offset + requestData->bytes > dcmi::maxCtrlIdStrLen)
562 {
563 return IPMI_CC_INVALID_FIELD_REQUEST;
564 }
565
566 try
567 {
568 hostName = dcmi::getHostName();
569 }
Patrick Williamsa2ad2da2021-10-06 12:21:46 -0500570 catch (const InternalFailure& e)
Vladislav Vovchenko8f7a6f62017-08-17 00:31:14 +0300571 {
572 return IPMI_CC_UNSPECIFIED_ERROR;
573 }
574
575 if (requestData->offset > hostName.length())
576 {
577 return IPMI_CC_PARM_OUT_OF_RANGE;
578 }
579 auto responseStr = hostName.substr(requestData->offset, requestData->bytes);
580 auto responseStrLen = std::min(static_cast<std::size_t>(requestData->bytes),
Patrick Venture0b02be92018-08-31 11:55:55 -0700581 responseStr.length() + 1);
Vladislav Vovchenko8f7a6f62017-08-17 00:31:14 +0300582 responseData->strLen = hostName.length();
583 std::copy(begin(responseStr), end(responseStr), responseData->data);
584
585 *data_len = sizeof(*responseData) + responseStrLen;
586 return IPMI_CC_OK;
587}
588
589ipmi_ret_t setMgmntCtrlIdStr(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
Patrick Venture0b02be92018-08-31 11:55:55 -0700590 ipmi_request_t request, ipmi_response_t response,
591 ipmi_data_len_t data_len, ipmi_context_t context)
Vladislav Vovchenko8f7a6f62017-08-17 00:31:14 +0300592{
593 static std::array<char, dcmi::maxCtrlIdStrLen + 1> newCtrlIdStr;
594
Patrick Venture0b02be92018-08-31 11:55:55 -0700595 auto requestData =
596 reinterpret_cast<const dcmi::SetMgmntCtrlIdStrRequest*>(request);
597 auto responseData =
598 reinterpret_cast<dcmi::SetMgmntCtrlIdStrResponse*>(response);
Vladislav Vovchenko8f7a6f62017-08-17 00:31:14 +0300599
600 *data_len = 0;
601
William A. Kennington III5d06cc62019-04-25 02:10:55 -0700602 if (requestData->bytes > dcmi::maxBytes ||
Vladislav Vovchenko8f7a6f62017-08-17 00:31:14 +0300603 requestData->offset + requestData->bytes > dcmi::maxCtrlIdStrLen + 1 ||
Patrick Venture0b02be92018-08-31 11:55:55 -0700604 (requestData->offset + requestData->bytes ==
605 dcmi::maxCtrlIdStrLen + 1 &&
606 requestData->data[requestData->bytes - 1] != '\0'))
Vladislav Vovchenko8f7a6f62017-08-17 00:31:14 +0300607 {
608 return IPMI_CC_INVALID_FIELD_REQUEST;
609 }
610
611 try
612 {
613 /* if there is no old value and offset is not 0 */
614 if (newCtrlIdStr[0] == '\0' && requestData->offset != 0)
615 {
616 /* read old ctrlIdStr */
617 auto hostName = dcmi::getHostName();
618 hostName.resize(dcmi::maxCtrlIdStrLen);
619 std::copy(begin(hostName), end(hostName), begin(newCtrlIdStr));
620 newCtrlIdStr[hostName.length()] = '\0';
621 }
622
623 /* replace part of string and mark byte after the last as \0 */
Patrick Venture0b02be92018-08-31 11:55:55 -0700624 auto restStrIter =
625 std::copy_n(requestData->data, requestData->bytes,
626 begin(newCtrlIdStr) + requestData->offset);
Vladislav Vovchenko8f7a6f62017-08-17 00:31:14 +0300627 /* if the last written byte is not 64th - add '\0' */
628 if (requestData->offset + requestData->bytes <= dcmi::maxCtrlIdStrLen)
629 {
630 *restStrIter = '\0';
631 }
632
633 /* if input data contains '\0' whole string is sent - update hostname */
634 auto it = std::find(requestData->data,
Patrick Venture0b02be92018-08-31 11:55:55 -0700635 requestData->data + requestData->bytes, '\0');
Vladislav Vovchenko8f7a6f62017-08-17 00:31:14 +0300636 if (it != requestData->data + requestData->bytes)
637 {
Patrick Venture0b02be92018-08-31 11:55:55 -0700638 sdbusplus::bus::bus bus{ipmid_get_sd_bus_connection()};
Vladislav Vovchenko8f7a6f62017-08-17 00:31:14 +0300639 ipmi::setDbusProperty(bus, dcmi::networkServiceName,
Patrick Venture0b02be92018-08-31 11:55:55 -0700640 dcmi::networkConfigObj,
641 dcmi::networkConfigIntf, dcmi::hostNameProp,
642 std::string(newCtrlIdStr.data()));
Vladislav Vovchenko8f7a6f62017-08-17 00:31:14 +0300643 }
644 }
Patrick Williamsa2ad2da2021-10-06 12:21:46 -0500645 catch (const InternalFailure& e)
Vladislav Vovchenko8f7a6f62017-08-17 00:31:14 +0300646 {
647 *data_len = 0;
648 return IPMI_CC_UNSPECIFIED_ERROR;
649 }
650
Vladislav Vovchenko8f7a6f62017-08-17 00:31:14 +0300651 responseData->offset = requestData->offset + requestData->bytes;
652 *data_len = sizeof(*responseData);
653 return IPMI_CC_OK;
654}
655
Patrick Venture0b02be92018-08-31 11:55:55 -0700656// List of the capabilities under each parameter
657dcmi::DCMICaps dcmiCaps = {
658 // Supported DCMI Capabilities
659 {dcmi::DCMICapParameters::SUPPORTED_DCMI_CAPS,
660 {3,
661 {{"PowerManagement", 2, 0, 1},
662 {"OOBSecondaryLan", 3, 2, 1},
663 {"SerialTMODE", 3, 1, 1},
664 {"InBandSystemInterfaceChannel", 3, 0, 1}}}},
665 // Mandatory Platform Attributes
666 {dcmi::DCMICapParameters::MANDATORY_PLAT_ATTRIBUTES,
667 {5,
668 {{"SELAutoRollOver", 1, 15, 1},
669 {"FlushEntireSELUponRollOver", 1, 14, 1},
670 {"RecordLevelSELFlushUponRollOver", 1, 13, 1},
671 {"NumberOfSELEntries", 1, 0, 12},
672 {"TempMonitoringSamplingFreq", 5, 0, 8}}}},
673 // Optional Platform Attributes
674 {dcmi::DCMICapParameters::OPTIONAL_PLAT_ATTRIBUTES,
675 {2,
676 {{"PowerMgmtDeviceSlaveAddress", 1, 1, 7},
677 {"BMCChannelNumber", 2, 4, 4},
678 {"DeviceRivision", 2, 0, 4}}}},
679 // Manageability Access Attributes
680 {dcmi::DCMICapParameters::MANAGEABILITY_ACCESS_ATTRIBUTES,
681 {3,
682 {{"MandatoryPrimaryLanOOBSupport", 1, 0, 8},
683 {"OptionalSecondaryLanOOBSupport", 2, 0, 8},
684 {"OptionalSerialOOBMTMODECapability", 3, 0, 8}}}}};
Dhruvaraj Subhashchandrane29be412018-01-16 05:11:56 -0600685
686ipmi_ret_t getDCMICapabilities(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
687 ipmi_request_t request, ipmi_response_t response,
688 ipmi_data_len_t data_len, ipmi_context_t context)
689{
690
Kirill Pakhomova2573622018-11-02 19:00:18 +0300691 std::ifstream dcmiCapFile(dcmi::gDCMICapabilitiesConfig);
Dhruvaraj Subhashchandrane29be412018-01-16 05:11:56 -0600692 if (!dcmiCapFile.is_open())
693 {
694 log<level::ERR>("DCMI Capabilities file not found");
695 return IPMI_CC_UNSPECIFIED_ERROR;
696 }
697
698 auto data = nlohmann::json::parse(dcmiCapFile, nullptr, false);
699 if (data.is_discarded())
700 {
701 log<level::ERR>("DCMI Capabilities JSON parser failure");
702 return IPMI_CC_UNSPECIFIED_ERROR;
703 }
704
Patrick Venture0b02be92018-08-31 11:55:55 -0700705 auto requestData =
706 reinterpret_cast<const dcmi::GetDCMICapRequest*>(request);
Dhruvaraj Subhashchandrane29be412018-01-16 05:11:56 -0600707
Patrick Venture0b02be92018-08-31 11:55:55 -0700708 // get list of capabilities in a parameter
Dhruvaraj Subhashchandrane29be412018-01-16 05:11:56 -0600709 auto caps =
710 dcmiCaps.find(static_cast<dcmi::DCMICapParameters>(requestData->param));
711 if (caps == dcmiCaps.end())
712 {
713 log<level::ERR>("Invalid input parameter");
714 return IPMI_CC_INVALID_FIELD_REQUEST;
715 }
716
Patrick Venture0b02be92018-08-31 11:55:55 -0700717 auto responseData = reinterpret_cast<dcmi::GetDCMICapResponse*>(response);
Dhruvaraj Subhashchandrane29be412018-01-16 05:11:56 -0600718
Patrick Venture0b02be92018-08-31 11:55:55 -0700719 // For each capabilities in a parameter fill the data from
720 // the json file based on the capability name.
Dhruvaraj Subhashchandrane29be412018-01-16 05:11:56 -0600721 for (auto cap : caps->second.capList)
722 {
Patrick Venture0b02be92018-08-31 11:55:55 -0700723 // If the data is beyond first byte boundary, insert in a
724 // 16bit pattern for example number of SEL entries are represented
725 // in 12bits.
Kirill Pakhomovdb5d9b02018-11-06 19:17:51 +0300726 if ((cap.length + cap.position) > dcmi::gByteBitSize)
Dhruvaraj Subhashchandrane29be412018-01-16 05:11:56 -0600727 {
Kirill Pakhomovdb5d9b02018-11-06 19:17:51 +0300728 uint16_t val = data.value(cap.name.c_str(), 0);
729 // According to DCMI spec v1.5, max number of SEL entries is
730 // 4096, but bit 12b of DCMI capabilities Mandatory Platform
731 // Attributes field is reserved and therefore we can use only
732 // the provided 12 bits with maximum value of 4095.
733 // We're playing safe here by applying the mask
734 // to ensure that provided value will fit into 12 bits.
735 if (cap.length > dcmi::gByteBitSize)
736 {
737 val &= dcmi::gMaxSELEntriesMask;
738 }
Dhruvaraj Subhashchandrane29be412018-01-16 05:11:56 -0600739 val <<= cap.position;
Kirill Pakhomovdb5d9b02018-11-06 19:17:51 +0300740 responseData->data[cap.bytePosition - 1] |=
741 static_cast<uint8_t>(val);
742 responseData->data[cap.bytePosition] |= val >> dcmi::gByteBitSize;
Dhruvaraj Subhashchandrane29be412018-01-16 05:11:56 -0600743 }
744 else
745 {
746 responseData->data[cap.bytePosition - 1] |=
747 data.value(cap.name.c_str(), 0) << cap.position;
748 }
749 }
750
Dhruvaraj Subhashchandrane29be412018-01-16 05:11:56 -0600751 responseData->major = DCMI_SPEC_MAJOR_VERSION;
752 responseData->minor = DCMI_SPEC_MINOR_VERSION;
753 responseData->paramRevision = DCMI_PARAMETER_REVISION;
754 *data_len = sizeof(*responseData) + caps->second.size;
755
756 return IPMI_CC_OK;
757}
758
Deepak Kodihalliee717d72018-01-24 04:53:09 -0600759namespace dcmi
760{
761namespace temp_readings
762{
763
Deepak Kodihallib1e8fba2018-01-24 04:57:10 -0600764Temperature readTemp(const std::string& dbusService,
765 const std::string& dbusPath)
766{
767 // Read the temperature value from d-bus object. Need some conversion.
768 // As per the interface xyz.openbmc_project.Sensor.Value, the temperature
James Feist9cc0ea52018-10-09 10:53:11 -0700769 // is an double and in degrees C. It needs to be scaled by using the
Deepak Kodihallib1e8fba2018-01-24 04:57:10 -0600770 // formula Value * 10^Scale. The ipmi spec has the temperature as a uint8_t,
771 // with a separate single bit for the sign.
772
773 sdbusplus::bus::bus bus{ipmid_get_sd_bus_connection()};
Patrick Venture0b02be92018-08-31 11:55:55 -0700774 auto result = ipmi::getAllDbusProperties(
775 bus, dbusService, dbusPath, "xyz.openbmc_project.Sensor.Value");
Vernon Maueryf442e112019-04-09 11:44:36 -0700776 auto temperature =
777 std::visit(ipmi::VariantToDoubleVisitor(), result.at("Value"));
James Feist9cc0ea52018-10-09 10:53:11 -0700778 double absTemp = std::abs(temperature);
Deepak Kodihallib1e8fba2018-01-24 04:57:10 -0600779
James Feist9cc0ea52018-10-09 10:53:11 -0700780 auto findFactor = result.find("Scale");
781 double factor = 0.0;
782 if (findFactor != result.end())
Deepak Kodihallib1e8fba2018-01-24 04:57:10 -0600783 {
Vernon Maueryf442e112019-04-09 11:44:36 -0700784 factor = std::visit(ipmi::VariantToDoubleVisitor(), findFactor->second);
Deepak Kodihallib1e8fba2018-01-24 04:57:10 -0600785 }
James Feist9cc0ea52018-10-09 10:53:11 -0700786 double scale = std::pow(10, factor);
787
788 auto tempDegrees = absTemp * scale;
Deepak Kodihallib1e8fba2018-01-24 04:57:10 -0600789 // Max absolute temp as per ipmi spec is 128.
790 if (tempDegrees > maxTemp)
791 {
792 tempDegrees = maxTemp;
793 }
794
795 return std::make_tuple(static_cast<uint8_t>(tempDegrees),
796 (temperature < 0));
797}
798
Deepak Kodihalliee717d72018-01-24 04:53:09 -0600799std::tuple<Response, NumInstances> read(const std::string& type,
800 uint8_t instance)
801{
Deepak Kodihallib1e8fba2018-01-24 04:57:10 -0600802 Response response{};
803 sdbusplus::bus::bus bus{ipmid_get_sd_bus_connection()};
804
805 if (!instance)
806 {
807 log<level::ERR>("Expected non-zero instance");
808 elog<InternalFailure>();
809 }
810
Kirill Pakhomova2573622018-11-02 19:00:18 +0300811 auto data = parseJSONConfig(gDCMISensorsConfig);
Deepak Kodihallib1e8fba2018-01-24 04:57:10 -0600812 static const std::vector<Json> empty{};
813 std::vector<Json> readings = data.value(type, empty);
814 size_t numInstances = readings.size();
815 for (const auto& j : readings)
816 {
817 uint8_t instanceNum = j.value("instance", 0);
818 // Not the instance we're interested in
819 if (instanceNum != instance)
820 {
821 continue;
822 }
823
824 std::string path = j.value("dbus", "");
825 std::string service;
826 try
827 {
828 service =
Patrick Venture0b02be92018-08-31 11:55:55 -0700829 ipmi::getService(bus, "xyz.openbmc_project.Sensor.Value", path);
Deepak Kodihallib1e8fba2018-01-24 04:57:10 -0600830 }
Patrick Williamsa2ad2da2021-10-06 12:21:46 -0500831 catch (const std::exception& e)
Deepak Kodihallib1e8fba2018-01-24 04:57:10 -0600832 {
833 log<level::DEBUG>(e.what());
834 return std::make_tuple(response, numInstances);
835 }
836
837 response.instance = instance;
838 uint8_t temp{};
839 bool sign{};
840 std::tie(temp, sign) = readTemp(service, path);
841 response.temperature = temp;
842 response.sign = sign;
843
844 // Found the instance we're interested in
845 break;
846 }
847
848 if (numInstances > maxInstances)
849 {
850 numInstances = maxInstances;
851 }
852 return std::make_tuple(response, numInstances);
Deepak Kodihalliee717d72018-01-24 04:53:09 -0600853}
854
855std::tuple<ResponseList, NumInstances> readAll(const std::string& type,
856 uint8_t instanceStart)
857{
Deepak Kodihallib1e8fba2018-01-24 04:57:10 -0600858 ResponseList response{};
859 sdbusplus::bus::bus bus{ipmid_get_sd_bus_connection()};
860
861 size_t numInstances = 0;
Kirill Pakhomova2573622018-11-02 19:00:18 +0300862 auto data = parseJSONConfig(gDCMISensorsConfig);
Deepak Kodihallib1e8fba2018-01-24 04:57:10 -0600863 static const std::vector<Json> empty{};
864 std::vector<Json> readings = data.value(type, empty);
865 numInstances = readings.size();
866 for (const auto& j : readings)
867 {
868 try
869 {
870 // Max of 8 response data sets
871 if (response.size() == maxDataSets)
872 {
873 break;
874 }
875
876 uint8_t instanceNum = j.value("instance", 0);
877 // Not in the instance range we're interested in
878 if (instanceNum < instanceStart)
879 {
880 continue;
881 }
882
883 std::string path = j.value("dbus", "");
884 auto service =
Patrick Venture0b02be92018-08-31 11:55:55 -0700885 ipmi::getService(bus, "xyz.openbmc_project.Sensor.Value", path);
Deepak Kodihallib1e8fba2018-01-24 04:57:10 -0600886
887 Response r{};
888 r.instance = instanceNum;
889 uint8_t temp{};
890 bool sign{};
891 std::tie(temp, sign) = readTemp(service, path);
892 r.temperature = temp;
893 r.sign = sign;
894 response.push_back(r);
895 }
Patrick Williamsa2ad2da2021-10-06 12:21:46 -0500896 catch (const std::exception& e)
Deepak Kodihallib1e8fba2018-01-24 04:57:10 -0600897 {
898 log<level::DEBUG>(e.what());
899 continue;
900 }
901 }
902
903 if (numInstances > maxInstances)
904 {
905 numInstances = maxInstances;
906 }
907 return std::make_tuple(response, numInstances);
Deepak Kodihalliee717d72018-01-24 04:53:09 -0600908}
909
Patrick Venture0b02be92018-08-31 11:55:55 -0700910} // namespace temp_readings
911} // namespace dcmi
Deepak Kodihalliee717d72018-01-24 04:53:09 -0600912
913ipmi_ret_t getTempReadings(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
Patrick Venture0b02be92018-08-31 11:55:55 -0700914 ipmi_request_t request, ipmi_response_t response,
915 ipmi_data_len_t data_len, ipmi_context_t context)
Deepak Kodihalliee717d72018-01-24 04:53:09 -0600916{
Deepak Kodihalliee717d72018-01-24 04:53:09 -0600917 auto requestData =
918 reinterpret_cast<const dcmi::GetTempReadingsRequest*>(request);
919 auto responseData =
920 reinterpret_cast<dcmi::GetTempReadingsResponseHdr*>(response);
921
922 if (*data_len != sizeof(dcmi::GetTempReadingsRequest))
923 {
924 log<level::ERR>("Malformed request data",
925 entry("DATA_SIZE=%d", *data_len));
926 return IPMI_CC_REQ_DATA_LEN_INVALID;
927 }
928 *data_len = 0;
929
Deepak Kodihalli0b459552018-02-06 06:25:12 -0600930 auto it = dcmi::entityIdToName.find(requestData->entityId);
931 if (it == dcmi::entityIdToName.end())
Deepak Kodihalliee717d72018-01-24 04:53:09 -0600932 {
933 log<level::ERR>("Unknown Entity ID",
934 entry("ENTITY_ID=%d", requestData->entityId));
935 return IPMI_CC_INVALID_FIELD_REQUEST;
936 }
937
Deepak Kodihalliee717d72018-01-24 04:53:09 -0600938 if (requestData->sensorType != dcmi::temperatureSensorType)
939 {
940 log<level::ERR>("Invalid sensor type",
941 entry("SENSOR_TYPE=%d", requestData->sensorType));
942 return IPMI_CC_INVALID_FIELD_REQUEST;
943 }
944
945 dcmi::temp_readings::ResponseList temps{};
946 try
947 {
948 if (!requestData->entityInstance)
949 {
950 // Read all instances
951 std::tie(temps, responseData->numInstances) =
952 dcmi::temp_readings::readAll(it->second,
953 requestData->instanceStart);
954 }
955 else
956 {
957 // Read one instance
958 temps.resize(1);
959 std::tie(temps[0], responseData->numInstances) =
960 dcmi::temp_readings::read(it->second,
961 requestData->entityInstance);
962 }
963 responseData->numDataSets = temps.size();
964 }
Patrick Williamsa2ad2da2021-10-06 12:21:46 -0500965 catch (const InternalFailure& e)
Deepak Kodihalliee717d72018-01-24 04:53:09 -0600966 {
967 return IPMI_CC_UNSPECIFIED_ERROR;
968 }
969
Patrick Venture0b02be92018-08-31 11:55:55 -0700970 size_t payloadSize = temps.size() * sizeof(dcmi::temp_readings::Response);
Deepak Kodihalliee717d72018-01-24 04:53:09 -0600971 if (!temps.empty())
972 {
973 memcpy(responseData + 1, // copy payload right after the response header
Patrick Venture0b02be92018-08-31 11:55:55 -0700974 temps.data(), payloadSize);
Deepak Kodihalliee717d72018-01-24 04:53:09 -0600975 }
976 *data_len = sizeof(dcmi::GetTempReadingsResponseHdr) + payloadSize;
977
978 return IPMI_CC_OK;
979}
980
Marri Devender Rao66c5fda2018-01-18 10:48:37 -0600981int64_t getPowerReading(sdbusplus::bus::bus& bus)
982{
983 std::ifstream sensorFile(POWER_READING_SENSOR);
984 std::string objectPath;
985 if (!sensorFile.is_open())
986 {
987 log<level::ERR>("Power reading configuration file not found",
Patrick Venture0b02be92018-08-31 11:55:55 -0700988 entry("POWER_SENSOR_FILE=%s", POWER_READING_SENSOR));
Marri Devender Rao66c5fda2018-01-18 10:48:37 -0600989 elog<InternalFailure>();
990 }
991
992 auto data = nlohmann::json::parse(sensorFile, nullptr, false);
993 if (data.is_discarded())
994 {
995 log<level::ERR>("Error in parsing configuration file",
Patrick Venture0b02be92018-08-31 11:55:55 -0700996 entry("POWER_SENSOR_FILE=%s", POWER_READING_SENSOR));
Marri Devender Rao66c5fda2018-01-18 10:48:37 -0600997 elog<InternalFailure>();
998 }
999
1000 objectPath = data.value("path", "");
1001 if (objectPath.empty())
1002 {
1003 log<level::ERR>("Power sensor D-Bus object path is empty",
1004 entry("POWER_SENSOR_FILE=%s", POWER_READING_SENSOR));
1005 elog<InternalFailure>();
1006 }
1007
Marri Devender Raoce6a7952018-02-11 08:45:00 -06001008 // Return default value if failed to read from D-Bus object
1009 int64_t power = 0;
1010 try
1011 {
1012 auto service = ipmi::getService(bus, SENSOR_VALUE_INTF, objectPath);
Marri Devender Rao66c5fda2018-01-18 10:48:37 -06001013
Patrick Venture0b02be92018-08-31 11:55:55 -07001014 // Read the sensor value and scale properties
1015 auto properties = ipmi::getAllDbusProperties(bus, service, objectPath,
1016 SENSOR_VALUE_INTF);
Vernon Maueryf442e112019-04-09 11:44:36 -07001017 auto value = std::get<int64_t>(properties[SENSOR_VALUE_PROP]);
1018 auto scale = std::get<int64_t>(properties[SENSOR_SCALE_PROP]);
Marri Devender Rao66c5fda2018-01-18 10:48:37 -06001019
Marri Devender Raoce6a7952018-02-11 08:45:00 -06001020 // Power reading needs to be scaled with the Scale value using the
1021 // formula Value * 10^Scale.
1022 power = value * std::pow(10, scale);
1023 }
Patrick Williamsa2ad2da2021-10-06 12:21:46 -05001024 catch (const std::exception& e)
Marri Devender Raoce6a7952018-02-11 08:45:00 -06001025 {
1026 log<level::INFO>("Failure to read power value from D-Bus object",
Patrick Venture0b02be92018-08-31 11:55:55 -07001027 entry("OBJECT_PATH=%s", objectPath.c_str()),
1028 entry("INTERFACE=%s", SENSOR_VALUE_INTF));
Marri Devender Raoce6a7952018-02-11 08:45:00 -06001029 }
Marri Devender Rao66c5fda2018-01-18 10:48:37 -06001030 return power;
1031}
1032
Nagaraju Goruganti22be97b2018-02-07 01:19:59 -06001033ipmi_ret_t setDCMIConfParams(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
1034 ipmi_request_t request, ipmi_response_t response,
1035 ipmi_data_len_t data_len, ipmi_context_t context)
1036{
Patrick Venture0b02be92018-08-31 11:55:55 -07001037 auto requestData =
1038 reinterpret_cast<const dcmi::SetConfParamsRequest*>(request);
Nagaraju Goruganti22be97b2018-02-07 01:19:59 -06001039
William A. Kennington III5d06cc62019-04-25 02:10:55 -07001040 if (*data_len < DCMI_SET_CONF_PARAM_REQ_PACKET_MIN_SIZE ||
Patrick Venture0b02be92018-08-31 11:55:55 -07001041 *data_len > DCMI_SET_CONF_PARAM_REQ_PACKET_MAX_SIZE)
Nagaraju Goruganti22be97b2018-02-07 01:19:59 -06001042 {
William A. Kennington III5d06cc62019-04-25 02:10:55 -07001043 log<level::ERR>("Invalid Requested Packet size",
Nagaraju Goruganti22be97b2018-02-07 01:19:59 -06001044 entry("PACKET SIZE=%d", *data_len));
William A. Kennington III5d06cc62019-04-25 02:10:55 -07001045 *data_len = 0;
Nagaraju Goruganti22be97b2018-02-07 01:19:59 -06001046 return IPMI_CC_INVALID_FIELD_REQUEST;
1047 }
Nagaraju Goruganti22be97b2018-02-07 01:19:59 -06001048 *data_len = 0;
1049
1050 try
1051 {
1052 // Take action based on the Parameter Selector
Patrick Venture0b02be92018-08-31 11:55:55 -07001053 switch (
1054 static_cast<dcmi::DCMIConfigParameters>(requestData->paramSelect))
Nagaraju Goruganti22be97b2018-02-07 01:19:59 -06001055 {
1056 case dcmi::DCMIConfigParameters::ActivateDHCP:
1057
1058 if ((requestData->data[0] & DCMI_ACTIVATE_DHCP_MASK) &&
Patrick Venture0b02be92018-08-31 11:55:55 -07001059 dcmi::getDHCPEnabled())
Nagaraju Goruganti22be97b2018-02-07 01:19:59 -06001060 {
Patrick Venture0b02be92018-08-31 11:55:55 -07001061 // When these conditions are met we have to trigger DHCP
1062 // protocol restart using the latest parameter settings, but
1063 // as per n/w manager design, each time when we update n/w
1064 // parameters, n/w service is restarted. So we no need to
1065 // take any action in this case.
Nagaraju Goruganti22be97b2018-02-07 01:19:59 -06001066 }
1067 break;
1068
1069 case dcmi::DCMIConfigParameters::DiscoveryConfig:
1070
1071 if (requestData->data[0] & DCMI_OPTION_12_MASK)
1072 {
1073 dcmi::setDHCPOption(DHCP_OPT12_ENABLED, true);
1074 }
1075 else
1076 {
1077 dcmi::setDHCPOption(DHCP_OPT12_ENABLED, false);
1078 }
1079
1080 // Systemd-networkd doesn't support Random Back off
1081 if (requestData->data[0] & DCMI_RAND_BACK_OFF_MASK)
1082 {
1083 return IPMI_CC_INVALID;
1084 }
1085 break;
1086 // Systemd-networkd doesn't allow to configure DHCP timigs
1087 case dcmi::DCMIConfigParameters::DHCPTiming1:
1088 case dcmi::DCMIConfigParameters::DHCPTiming2:
1089 case dcmi::DCMIConfigParameters::DHCPTiming3:
1090 default:
1091 return IPMI_CC_INVALID;
1092 }
1093 }
Patrick Williamsa2ad2da2021-10-06 12:21:46 -05001094 catch (const std::exception& e)
Nagaraju Goruganti22be97b2018-02-07 01:19:59 -06001095 {
1096 log<level::ERR>(e.what());
1097 return IPMI_CC_UNSPECIFIED_ERROR;
1098 }
Nagaraju Goruganti22be97b2018-02-07 01:19:59 -06001099 return IPMI_CC_OK;
1100}
1101
1102ipmi_ret_t getDCMIConfParams(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
1103 ipmi_request_t request, ipmi_response_t response,
1104 ipmi_data_len_t data_len, ipmi_context_t context)
1105{
1106
Patrick Venture0b02be92018-08-31 11:55:55 -07001107 auto requestData =
1108 reinterpret_cast<const dcmi::GetConfParamsRequest*>(request);
1109 auto responseData =
1110 reinterpret_cast<dcmi::GetConfParamsResponse*>(response);
Nagaraju Goruganti22be97b2018-02-07 01:19:59 -06001111
1112 responseData->data[0] = 0x00;
1113
William A. Kennington III5d06cc62019-04-25 02:10:55 -07001114 if (*data_len != sizeof(dcmi::GetConfParamsRequest))
Nagaraju Goruganti22be97b2018-02-07 01:19:59 -06001115 {
William A. Kennington III5d06cc62019-04-25 02:10:55 -07001116 log<level::ERR>("Invalid Requested Packet size",
Nagaraju Goruganti22be97b2018-02-07 01:19:59 -06001117 entry("PACKET SIZE=%d", *data_len));
1118 return IPMI_CC_INVALID_FIELD_REQUEST;
1119 }
1120
1121 *data_len = 0;
1122
1123 try
1124 {
1125 // Take action based on the Parameter Selector
Patrick Venture0b02be92018-08-31 11:55:55 -07001126 switch (
1127 static_cast<dcmi::DCMIConfigParameters>(requestData->paramSelect))
Nagaraju Goruganti22be97b2018-02-07 01:19:59 -06001128 {
1129 case dcmi::DCMIConfigParameters::ActivateDHCP:
1130 responseData->data[0] = DCMI_ACTIVATE_DHCP_REPLY;
1131 *data_len = sizeof(dcmi::GetConfParamsResponse) + 1;
1132 break;
1133 case dcmi::DCMIConfigParameters::DiscoveryConfig:
1134 if (dcmi::getDHCPOption(DHCP_OPT12_ENABLED))
1135 {
1136 responseData->data[0] |= DCMI_OPTION_12_MASK;
1137 }
1138 *data_len = sizeof(dcmi::GetConfParamsResponse) + 1;
1139 break;
1140 // Get below values from Systemd-networkd source code
1141 case dcmi::DCMIConfigParameters::DHCPTiming1:
1142 responseData->data[0] = DHCP_TIMING1;
1143 *data_len = sizeof(dcmi::GetConfParamsResponse) + 1;
1144 break;
1145 case dcmi::DCMIConfigParameters::DHCPTiming2:
1146 responseData->data[0] = DHCP_TIMING2_LOWER;
1147 responseData->data[1] = DHCP_TIMING2_UPPER;
1148 *data_len = sizeof(dcmi::GetConfParamsResponse) + 2;
1149 break;
1150 case dcmi::DCMIConfigParameters::DHCPTiming3:
1151 responseData->data[0] = DHCP_TIMING3_LOWER;
1152 responseData->data[1] = DHCP_TIMING3_UPPER;
1153 *data_len = sizeof(dcmi::GetConfParamsResponse) + 2;
1154 break;
1155 default:
1156 *data_len = 0;
1157 return IPMI_CC_INVALID;
1158 }
1159 }
Patrick Williamsa2ad2da2021-10-06 12:21:46 -05001160 catch (const std::exception& e)
Nagaraju Goruganti22be97b2018-02-07 01:19:59 -06001161 {
1162 log<level::ERR>(e.what());
1163 return IPMI_CC_UNSPECIFIED_ERROR;
1164 }
1165
Nagaraju Goruganti22be97b2018-02-07 01:19:59 -06001166 responseData->major = DCMI_SPEC_MAJOR_VERSION;
1167 responseData->minor = DCMI_SPEC_MINOR_VERSION;
1168 responseData->paramRevision = DCMI_CONFIG_PARAMETER_REVISION;
1169
1170 return IPMI_CC_OK;
1171}
1172
Marri Devender Rao66c5fda2018-01-18 10:48:37 -06001173ipmi_ret_t getPowerReading(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
Patrick Venture0b02be92018-08-31 11:55:55 -07001174 ipmi_request_t request, ipmi_response_t response,
1175 ipmi_data_len_t data_len, ipmi_context_t context)
Marri Devender Rao66c5fda2018-01-18 10:48:37 -06001176{
Chalapathi Venkataramashetty90e81fa2021-05-11 09:13:23 +00001177 *data_len = 0;
Kirill Pakhomov2c2af2c2018-11-06 16:06:10 +03001178 if (!dcmi::isDCMIPowerMgmtSupported())
1179 {
Kirill Pakhomov2c2af2c2018-11-06 16:06:10 +03001180 log<level::ERR>("DCMI Power management is unsupported!");
1181 return IPMI_CC_INVALID;
1182 }
1183
Marri Devender Rao66c5fda2018-01-18 10:48:37 -06001184 ipmi_ret_t rc = IPMI_CC_OK;
Patrick Venture0b02be92018-08-31 11:55:55 -07001185 auto responseData =
1186 reinterpret_cast<dcmi::GetPowerReadingResponse*>(response);
Marri Devender Rao9c966e02018-01-22 05:55:10 -06001187
Marri Devender Rao66c5fda2018-01-18 10:48:37 -06001188 sdbusplus::bus::bus bus{ipmid_get_sd_bus_connection()};
Marri Devender Rao9c966e02018-01-22 05:55:10 -06001189 int64_t power = 0;
Marri Devender Rao66c5fda2018-01-18 10:48:37 -06001190 try
1191 {
Marri Devender Rao9c966e02018-01-22 05:55:10 -06001192 power = getPowerReading(bus);
Marri Devender Rao66c5fda2018-01-18 10:48:37 -06001193 }
Patrick Williamsa2ad2da2021-10-06 12:21:46 -05001194 catch (const InternalFailure& e)
Marri Devender Rao66c5fda2018-01-18 10:48:37 -06001195 {
1196 log<level::ERR>("Error in reading power sensor value",
1197 entry("INTERFACE=%s", SENSOR_VALUE_INTF),
1198 entry("PROPERTY=%s", SENSOR_VALUE_PROP));
1199 return IPMI_CC_UNSPECIFIED_ERROR;
1200 }
Marri Devender Rao9c966e02018-01-22 05:55:10 -06001201
1202 // TODO: openbmc/openbmc#2819
Gunnar Mills8466b792018-03-23 12:18:12 -05001203 // Minimum, Maximum, Average power, TimeFrame, TimeStamp,
Marri Devender Rao9c966e02018-01-22 05:55:10 -06001204 // PowerReadingState readings need to be populated
1205 // after Telemetry changes.
1206 uint16_t totalPower = static_cast<uint16_t>(power);
1207 responseData->currentPower = totalPower;
1208 responseData->minimumPower = totalPower;
1209 responseData->maximumPower = totalPower;
1210 responseData->averagePower = totalPower;
1211
1212 *data_len = sizeof(*responseData);
Marri Devender Rao66c5fda2018-01-18 10:48:37 -06001213 return rc;
1214}
1215
Deepak Kodihalli0b459552018-02-06 06:25:12 -06001216namespace dcmi
1217{
1218namespace sensor_info
1219{
1220
Deepak Kodihallidd4cff12018-02-06 06:48:29 -06001221Response createFromJson(const Json& config)
1222{
1223 Response response{};
1224 uint16_t recordId = config.value("record_id", 0);
1225 response.recordIdLsb = recordId & 0xFF;
1226 response.recordIdMsb = (recordId >> 8) & 0xFF;
1227 return response;
1228}
1229
Deepak Kodihalli0b459552018-02-06 06:25:12 -06001230std::tuple<Response, NumInstances> read(const std::string& type,
Patrick Venture0b02be92018-08-31 11:55:55 -07001231 uint8_t instance, const Json& config)
Deepak Kodihalli0b459552018-02-06 06:25:12 -06001232{
Deepak Kodihallidd4cff12018-02-06 06:48:29 -06001233 Response response{};
1234
1235 if (!instance)
1236 {
1237 log<level::ERR>("Expected non-zero instance");
1238 elog<InternalFailure>();
1239 }
1240
1241 static const std::vector<Json> empty{};
1242 std::vector<Json> readings = config.value(type, empty);
1243 size_t numInstances = readings.size();
1244 for (const auto& reading : readings)
1245 {
1246 uint8_t instanceNum = reading.value("instance", 0);
1247 // Not the instance we're interested in
1248 if (instanceNum != instance)
1249 {
1250 continue;
1251 }
1252
1253 response = createFromJson(reading);
1254
1255 // Found the instance we're interested in
1256 break;
1257 }
1258
1259 if (numInstances > maxInstances)
1260 {
1261 log<level::DEBUG>("Trimming IPMI num instances",
1262 entry("NUM_INSTANCES=%d", numInstances));
1263 numInstances = maxInstances;
1264 }
1265 return std::make_tuple(response, numInstances);
Deepak Kodihalli0b459552018-02-06 06:25:12 -06001266}
1267
Patrick Venture0b02be92018-08-31 11:55:55 -07001268std::tuple<ResponseList, NumInstances>
1269 readAll(const std::string& type, uint8_t instanceStart, const Json& config)
Deepak Kodihalli0b459552018-02-06 06:25:12 -06001270{
Deepak Kodihallidd4cff12018-02-06 06:48:29 -06001271 ResponseList responses{};
1272
1273 size_t numInstances = 0;
1274 static const std::vector<Json> empty{};
1275 std::vector<Json> readings = config.value(type, empty);
1276 numInstances = readings.size();
1277 for (const auto& reading : readings)
1278 {
1279 try
1280 {
1281 // Max of 8 records
1282 if (responses.size() == maxRecords)
1283 {
1284 break;
1285 }
1286
1287 uint8_t instanceNum = reading.value("instance", 0);
1288 // Not in the instance range we're interested in
1289 if (instanceNum < instanceStart)
1290 {
1291 continue;
1292 }
1293
1294 Response response = createFromJson(reading);
1295 responses.push_back(response);
1296 }
Patrick Williamsa2ad2da2021-10-06 12:21:46 -05001297 catch (const std::exception& e)
Deepak Kodihallidd4cff12018-02-06 06:48:29 -06001298 {
1299 log<level::DEBUG>(e.what());
1300 continue;
1301 }
1302 }
1303
1304 if (numInstances > maxInstances)
1305 {
1306 log<level::DEBUG>("Trimming IPMI num instances",
1307 entry("NUM_INSTANCES=%d", numInstances));
1308 numInstances = maxInstances;
1309 }
1310 return std::make_tuple(responses, numInstances);
Deepak Kodihalli0b459552018-02-06 06:25:12 -06001311}
1312
1313} // namespace sensor_info
1314} // namespace dcmi
1315
1316ipmi_ret_t getSensorInfo(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
1317 ipmi_request_t request, ipmi_response_t response,
1318 ipmi_data_len_t data_len, ipmi_context_t context)
1319{
1320 auto requestData =
1321 reinterpret_cast<const dcmi::GetSensorInfoRequest*>(request);
1322 auto responseData =
1323 reinterpret_cast<dcmi::GetSensorInfoResponseHdr*>(response);
1324
1325 if (*data_len != sizeof(dcmi::GetSensorInfoRequest))
1326 {
1327 log<level::ERR>("Malformed request data",
1328 entry("DATA_SIZE=%d", *data_len));
1329 return IPMI_CC_REQ_DATA_LEN_INVALID;
1330 }
1331 *data_len = 0;
1332
1333 auto it = dcmi::entityIdToName.find(requestData->entityId);
1334 if (it == dcmi::entityIdToName.end())
1335 {
1336 log<level::ERR>("Unknown Entity ID",
1337 entry("ENTITY_ID=%d", requestData->entityId));
1338 return IPMI_CC_INVALID_FIELD_REQUEST;
1339 }
1340
Deepak Kodihalli0b459552018-02-06 06:25:12 -06001341 if (requestData->sensorType != dcmi::temperatureSensorType)
1342 {
1343 log<level::ERR>("Invalid sensor type",
1344 entry("SENSOR_TYPE=%d", requestData->sensorType));
1345 return IPMI_CC_INVALID_FIELD_REQUEST;
1346 }
1347
1348 dcmi::sensor_info::ResponseList sensors{};
1349 static dcmi::Json config{};
1350 static bool parsed = false;
1351
1352 try
1353 {
1354 if (!parsed)
1355 {
Kirill Pakhomova2573622018-11-02 19:00:18 +03001356 config = dcmi::parseJSONConfig(dcmi::gDCMISensorsConfig);
Deepak Kodihalli0b459552018-02-06 06:25:12 -06001357 parsed = true;
1358 }
1359
1360 if (!requestData->entityInstance)
1361 {
1362 // Read all instances
1363 std::tie(sensors, responseData->numInstances) =
1364 dcmi::sensor_info::readAll(it->second,
Patrick Venture0b02be92018-08-31 11:55:55 -07001365 requestData->instanceStart, config);
Deepak Kodihalli0b459552018-02-06 06:25:12 -06001366 }
1367 else
1368 {
1369 // Read one instance
1370 sensors.resize(1);
1371 std::tie(sensors[0], responseData->numInstances) =
Patrick Venture0b02be92018-08-31 11:55:55 -07001372 dcmi::sensor_info::read(it->second, requestData->entityInstance,
Deepak Kodihalli0b459552018-02-06 06:25:12 -06001373 config);
1374 }
1375 responseData->numRecords = sensors.size();
1376 }
Patrick Williamsa2ad2da2021-10-06 12:21:46 -05001377 catch (const InternalFailure& e)
Deepak Kodihalli0b459552018-02-06 06:25:12 -06001378 {
1379 return IPMI_CC_UNSPECIFIED_ERROR;
1380 }
1381
Deepak Kodihalli0b459552018-02-06 06:25:12 -06001382 size_t payloadSize = sensors.size() * sizeof(dcmi::sensor_info::Response);
1383 if (!sensors.empty())
1384 {
1385 memcpy(responseData + 1, // copy payload right after the response header
Patrick Venture0b02be92018-08-31 11:55:55 -07001386 sensors.data(), payloadSize);
Deepak Kodihalli0b459552018-02-06 06:25:12 -06001387 }
1388 *data_len = sizeof(dcmi::GetSensorInfoResponseHdr) + payloadSize;
1389
1390 return IPMI_CC_OK;
1391}
1392
Chris Austen1810bec2015-10-13 12:12:39 -05001393void register_netfn_dcmi_functions()
1394{
Tom05732372016-09-06 17:21:23 +05301395 // <Get Power Limit>
Ratan Gupta11ddbd22017-08-05 11:59:39 +05301396
Patrick Venture0b02be92018-08-31 11:55:55 -07001397 ipmi_register_callback(NETFUN_GRPEXT, dcmi::Commands::GET_POWER_LIMIT, NULL,
1398 getPowerLimit, PRIVILEGE_USER);
Tom Joseph6f6dd4d2017-07-12 20:07:11 +05301399
Tom Joseph46fa37d2017-07-26 18:11:55 +05301400 // <Set Power Limit>
Ratan Gupta11ddbd22017-08-05 11:59:39 +05301401
Patrick Venture0b02be92018-08-31 11:55:55 -07001402 ipmi_register_callback(NETFUN_GRPEXT, dcmi::Commands::SET_POWER_LIMIT, NULL,
1403 setPowerLimit, PRIVILEGE_OPERATOR);
Tom Joseph46fa37d2017-07-26 18:11:55 +05301404
Tom Joseph6c8d51b2017-07-26 18:18:06 +05301405 // <Activate/Deactivate Power Limit>
Ratan Gupta11ddbd22017-08-05 11:59:39 +05301406
1407 ipmi_register_callback(NETFUN_GRPEXT, dcmi::Commands::APPLY_POWER_LIMIT,
1408 NULL, applyPowerLimit, PRIVILEGE_OPERATOR);
Tom Joseph6c8d51b2017-07-26 18:18:06 +05301409
Tom Joseph6f6dd4d2017-07-12 20:07:11 +05301410 // <Get Asset Tag>
Ratan Gupta11ddbd22017-08-05 11:59:39 +05301411
Patrick Venture0b02be92018-08-31 11:55:55 -07001412 ipmi_register_callback(NETFUN_GRPEXT, dcmi::Commands::GET_ASSET_TAG, NULL,
1413 getAssetTag, PRIVILEGE_USER);
Tom Joseph545dd232017-07-12 20:20:49 +05301414
1415 // <Set Asset Tag>
Ratan Gupta11ddbd22017-08-05 11:59:39 +05301416
Patrick Venture0b02be92018-08-31 11:55:55 -07001417 ipmi_register_callback(NETFUN_GRPEXT, dcmi::Commands::SET_ASSET_TAG, NULL,
1418 setAssetTag, PRIVILEGE_OPERATOR);
Vladislav Vovchenko8f7a6f62017-08-17 00:31:14 +03001419
Gunnar Mills8991dd62017-10-25 17:11:29 -05001420 // <Get Management Controller Identifier String>
Vladislav Vovchenko8f7a6f62017-08-17 00:31:14 +03001421
1422 ipmi_register_callback(NETFUN_GRPEXT, dcmi::Commands::GET_MGMNT_CTRL_ID_STR,
Patrick Venture0b02be92018-08-31 11:55:55 -07001423 NULL, getMgmntCtrlIdStr, PRIVILEGE_USER);
Vladislav Vovchenko8f7a6f62017-08-17 00:31:14 +03001424
1425 // <Set Management Controller Identifier String>
Vladislav Vovchenko8f7a6f62017-08-17 00:31:14 +03001426 ipmi_register_callback(NETFUN_GRPEXT, dcmi::Commands::SET_MGMNT_CTRL_ID_STR,
Patrick Venture0b02be92018-08-31 11:55:55 -07001427 NULL, setMgmntCtrlIdStr, PRIVILEGE_ADMIN);
Vladislav Vovchenko8f7a6f62017-08-17 00:31:14 +03001428
Dhruvaraj Subhashchandrane29be412018-01-16 05:11:56 -06001429 // <Get DCMI capabilities>
1430 ipmi_register_callback(NETFUN_GRPEXT, dcmi::Commands::GET_CAPABILITIES,
Patrick Venture0b02be92018-08-31 11:55:55 -07001431 NULL, getDCMICapabilities, PRIVILEGE_USER);
Deepak Kodihalliee717d72018-01-24 04:53:09 -06001432
1433 // <Get Temperature Readings>
1434 ipmi_register_callback(NETFUN_GRPEXT, dcmi::Commands::GET_TEMP_READINGS,
1435 NULL, getTempReadings, PRIVILEGE_USER);
1436
Marri Devender Rao66c5fda2018-01-18 10:48:37 -06001437 // <Get Power Reading>
1438 ipmi_register_callback(NETFUN_GRPEXT, dcmi::Commands::GET_POWER_READING,
1439 NULL, getPowerReading, PRIVILEGE_USER);
Deepak Kodihalli0b459552018-02-06 06:25:12 -06001440
1441 // <Get Sensor Info>
Patrick Venture0b02be92018-08-31 11:55:55 -07001442 ipmi_register_callback(NETFUN_GRPEXT, dcmi::Commands::GET_SENSOR_INFO, NULL,
1443 getSensorInfo, PRIVILEGE_USER);
Deepak Kodihalli0b459552018-02-06 06:25:12 -06001444
Nagaraju Goruganti22be97b2018-02-07 01:19:59 -06001445 // <Get DCMI Configuration Parameters>
Patrick Venture0b02be92018-08-31 11:55:55 -07001446 ipmi_register_callback(NETFUN_GRPEXT, dcmi::Commands::GET_CONF_PARAMS, NULL,
1447 getDCMIConfParams, PRIVILEGE_USER);
Nagaraju Goruganti22be97b2018-02-07 01:19:59 -06001448
1449 // <Set DCMI Configuration Parameters>
Patrick Venture0b02be92018-08-31 11:55:55 -07001450 ipmi_register_callback(NETFUN_GRPEXT, dcmi::Commands::SET_CONF_PARAMS, NULL,
1451 setDCMIConfParams, PRIVILEGE_ADMIN);
Nagaraju Goruganti22be97b2018-02-07 01:19:59 -06001452
Chris Austen1810bec2015-10-13 12:12:39 -05001453 return;
1454}
Tom05732372016-09-06 17:21:23 +05301455// 956379