blob: 31f9224efff638badcc0f9640cb38ec6ed128a00 [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";
Marri Devender Rao66c5fda2018-01-18 10:48:37 -060054
Andrew Geissler50c0c8f2017-07-11 16:18:51 -050055using namespace phosphor::logging;
56
Tom Josephb9d86f42017-07-26 18:03:47 +053057namespace dcmi
58{
59
Deepak Kodihalli0b459552018-02-06 06:25:12 -060060// Refer Table 6-14, DCMI Entity ID Extension, DCMI v1.5 spec
Patrick Venture0b02be92018-08-31 11:55:55 -070061static const std::map<uint8_t, std::string> entityIdToName{
62 {0x40, "inlet"}, {0x37, "inlet"}, {0x41, "cpu"},
63 {0x03, "cpu"}, {0x42, "baseboard"}, {0x07, "baseboard"}};
Deepak Kodihalli0b459552018-02-06 06:25:12 -060064
Kirill Pakhomov2c2af2c2018-11-06 16:06:10 +030065bool isDCMIPowerMgmtSupported()
66{
67 auto data = parseJSONConfig(gDCMICapabilitiesConfig);
68
69 return (gDCMIPowerMgmtSupported == data.value(gDCMIPowerMgmtCapability, 0));
70}
71
Patrick Williams5d82f472022-07-22 19:26:53 -050072uint32_t getPcap(sdbusplus::bus_t& bus)
Andrew Geissler50c0c8f2017-07-11 16:18:51 -050073{
Patrick Venture0b02be92018-08-31 11:55:55 -070074 auto settingService = ipmi::getService(bus, PCAP_INTERFACE, PCAP_PATH);
Andrew Geissler50c0c8f2017-07-11 16:18:51 -050075
Patrick Venture0b02be92018-08-31 11:55:55 -070076 auto method = bus.new_method_call(settingService.c_str(), PCAP_PATH,
77 "org.freedesktop.DBus.Properties", "Get");
Andrew Geissler50c0c8f2017-07-11 16:18:51 -050078
79 method.append(PCAP_INTERFACE, POWER_CAP_PROP);
80 auto reply = bus.call(method);
81
82 if (reply.is_method_error())
83 {
84 log<level::ERR>("Error in getPcap prop");
Tom Josephb9d86f42017-07-26 18:03:47 +053085 elog<InternalFailure>();
Andrew Geissler50c0c8f2017-07-11 16:18:51 -050086 }
Vernon Mauery16b86932019-05-01 08:36:11 -070087 std::variant<uint32_t> pcap;
Andrew Geissler50c0c8f2017-07-11 16:18:51 -050088 reply.read(pcap);
89
Vernon Maueryf442e112019-04-09 11:44:36 -070090 return std::get<uint32_t>(pcap);
Andrew Geissler50c0c8f2017-07-11 16:18:51 -050091}
92
Patrick Williams5d82f472022-07-22 19:26:53 -050093bool getPcapEnabled(sdbusplus::bus_t& bus)
Andrew Geissler50c0c8f2017-07-11 16:18:51 -050094{
Patrick Venture0b02be92018-08-31 11:55:55 -070095 auto settingService = ipmi::getService(bus, PCAP_INTERFACE, PCAP_PATH);
Andrew Geissler50c0c8f2017-07-11 16:18:51 -050096
Patrick Venture0b02be92018-08-31 11:55:55 -070097 auto method = bus.new_method_call(settingService.c_str(), PCAP_PATH,
98 "org.freedesktop.DBus.Properties", "Get");
Andrew Geissler50c0c8f2017-07-11 16:18:51 -050099
100 method.append(PCAP_INTERFACE, POWER_CAP_ENABLE_PROP);
101 auto reply = bus.call(method);
102
103 if (reply.is_method_error())
104 {
105 log<level::ERR>("Error in getPcapEnabled prop");
Tom Josephb9d86f42017-07-26 18:03:47 +0530106 elog<InternalFailure>();
Andrew Geissler50c0c8f2017-07-11 16:18:51 -0500107 }
Vernon Mauery16b86932019-05-01 08:36:11 -0700108 std::variant<bool> pcapEnabled;
Andrew Geissler50c0c8f2017-07-11 16:18:51 -0500109 reply.read(pcapEnabled);
110
Vernon Maueryf442e112019-04-09 11:44:36 -0700111 return std::get<bool>(pcapEnabled);
Andrew Geissler50c0c8f2017-07-11 16:18:51 -0500112}
Chris Austen1810bec2015-10-13 12:12:39 -0500113
Patrick Williams5d82f472022-07-22 19:26:53 -0500114void setPcap(sdbusplus::bus_t& bus, const uint32_t powerCap)
Tom Joseph46fa37d2017-07-26 18:11:55 +0530115{
116 auto service = ipmi::getService(bus, PCAP_INTERFACE, PCAP_PATH);
117
Patrick Venture0b02be92018-08-31 11:55:55 -0700118 auto method = bus.new_method_call(service.c_str(), PCAP_PATH,
119 "org.freedesktop.DBus.Properties", "Set");
Tom Joseph46fa37d2017-07-26 18:11:55 +0530120
121 method.append(PCAP_INTERFACE, POWER_CAP_PROP);
Vernon Mauery16b86932019-05-01 08:36:11 -0700122 method.append(std::variant<uint32_t>(powerCap));
Tom Joseph46fa37d2017-07-26 18:11:55 +0530123
124 auto reply = bus.call(method);
125
126 if (reply.is_method_error())
127 {
128 log<level::ERR>("Error in setPcap property");
129 elog<InternalFailure>();
130 }
131}
132
Patrick Williams5d82f472022-07-22 19:26:53 -0500133void setPcapEnable(sdbusplus::bus_t& bus, bool enabled)
Tom Joseph6c8d51b2017-07-26 18:18:06 +0530134{
135 auto service = ipmi::getService(bus, PCAP_INTERFACE, PCAP_PATH);
136
Patrick Venture0b02be92018-08-31 11:55:55 -0700137 auto method = bus.new_method_call(service.c_str(), PCAP_PATH,
138 "org.freedesktop.DBus.Properties", "Set");
Tom Joseph6c8d51b2017-07-26 18:18:06 +0530139
140 method.append(PCAP_INTERFACE, POWER_CAP_ENABLE_PROP);
Vernon Mauery16b86932019-05-01 08:36:11 -0700141 method.append(std::variant<bool>(enabled));
Tom Joseph6c8d51b2017-07-26 18:18:06 +0530142
143 auto reply = bus.call(method);
144
145 if (reply.is_method_error())
146 {
147 log<level::ERR>("Error in setPcapEnabled property");
148 elog<InternalFailure>();
149 }
150}
151
Tom Josephbe5eaa12017-07-12 19:54:44 +0530152void readAssetTagObjectTree(dcmi::assettag::ObjectTree& objectTree)
153{
154 static constexpr auto mapperBusName = "xyz.openbmc_project.ObjectMapper";
155 static constexpr auto mapperObjPath = "/xyz/openbmc_project/object_mapper";
156 static constexpr auto mapperIface = "xyz.openbmc_project.ObjectMapper";
157 static constexpr auto inventoryRoot = "/xyz/openbmc_project/inventory/";
158
Patrick Williams5d82f472022-07-22 19:26:53 -0500159 sdbusplus::bus_t bus{ipmid_get_sd_bus_connection()};
Tom Josephbe5eaa12017-07-12 19:54:44 +0530160 auto depth = 0;
161
Patrick Venture0b02be92018-08-31 11:55:55 -0700162 auto mapperCall = bus.new_method_call(mapperBusName, mapperObjPath,
163 mapperIface, "GetSubTree");
Tom Josephbe5eaa12017-07-12 19:54:44 +0530164
165 mapperCall.append(inventoryRoot);
166 mapperCall.append(depth);
167 mapperCall.append(std::vector<std::string>({dcmi::assetTagIntf}));
168
169 auto mapperReply = bus.call(mapperCall);
170 if (mapperReply.is_method_error())
171 {
172 log<level::ERR>("Error in mapper call");
173 elog<InternalFailure>();
174 }
175
176 mapperReply.read(objectTree);
177
178 if (objectTree.empty())
179 {
180 log<level::ERR>("AssetTag property is not populated");
181 elog<InternalFailure>();
182 }
183}
184
185std::string readAssetTag()
186{
Patrick Williams5d82f472022-07-22 19:26:53 -0500187 sdbusplus::bus_t bus{ipmid_get_sd_bus_connection()};
Tom Josephbe5eaa12017-07-12 19:54:44 +0530188 dcmi::assettag::ObjectTree objectTree;
189
190 // Read the object tree with the inventory root to figure out the object
191 // that has implemented the Asset tag interface.
192 readAssetTagObjectTree(objectTree);
193
194 auto method = bus.new_method_call(
Patrick Venture0b02be92018-08-31 11:55:55 -0700195 (objectTree.begin()->second.begin()->first).c_str(),
196 (objectTree.begin()->first).c_str(), dcmi::propIntf, "Get");
Tom Josephbe5eaa12017-07-12 19:54:44 +0530197 method.append(dcmi::assetTagIntf);
198 method.append(dcmi::assetTagProp);
199
200 auto reply = bus.call(method);
201 if (reply.is_method_error())
202 {
203 log<level::ERR>("Error in reading asset tag");
204 elog<InternalFailure>();
205 }
206
Vernon Mauery16b86932019-05-01 08:36:11 -0700207 std::variant<std::string> assetTag;
Tom Josephbe5eaa12017-07-12 19:54:44 +0530208 reply.read(assetTag);
209
Vernon Maueryf442e112019-04-09 11:44:36 -0700210 return std::get<std::string>(assetTag);
Tom Josephbe5eaa12017-07-12 19:54:44 +0530211}
212
Tom Josephbe5b9892017-07-15 00:55:23 +0530213void writeAssetTag(const std::string& assetTag)
214{
Patrick Williams5d82f472022-07-22 19:26:53 -0500215 sdbusplus::bus_t bus{ipmid_get_sd_bus_connection()};
Tom Josephbe5b9892017-07-15 00:55:23 +0530216 dcmi::assettag::ObjectTree objectTree;
217
218 // Read the object tree with the inventory root to figure out the object
219 // that has implemented the Asset tag interface.
220 readAssetTagObjectTree(objectTree);
221
222 auto method = bus.new_method_call(
Patrick Venture0b02be92018-08-31 11:55:55 -0700223 (objectTree.begin()->second.begin()->first).c_str(),
224 (objectTree.begin()->first).c_str(), dcmi::propIntf, "Set");
Tom Josephbe5b9892017-07-15 00:55:23 +0530225 method.append(dcmi::assetTagIntf);
226 method.append(dcmi::assetTagProp);
Vernon Mauery16b86932019-05-01 08:36:11 -0700227 method.append(std::variant<std::string>(assetTag));
Tom Josephbe5b9892017-07-15 00:55:23 +0530228
229 auto reply = bus.call(method);
230 if (reply.is_method_error())
231 {
232 log<level::ERR>("Error in writing asset tag");
233 elog<InternalFailure>();
234 }
235}
236
Vladislav Vovchenko8f7a6f62017-08-17 00:31:14 +0300237std::string getHostName(void)
238{
Patrick Williams5d82f472022-07-22 19:26:53 -0500239 sdbusplus::bus_t bus{ipmid_get_sd_bus_connection()};
Vladislav Vovchenko8f7a6f62017-08-17 00:31:14 +0300240
241 auto service = ipmi::getService(bus, networkConfigIntf, networkConfigObj);
Patrick Venture0b02be92018-08-31 11:55:55 -0700242 auto value = ipmi::getDbusProperty(bus, service, networkConfigObj,
243 networkConfigIntf, hostNameProp);
Vladislav Vovchenko8f7a6f62017-08-17 00:31:14 +0300244
Vernon Maueryf442e112019-04-09 11:44:36 -0700245 return std::get<std::string>(value);
Vladislav Vovchenko8f7a6f62017-08-17 00:31:14 +0300246}
247
Nagaraju Goruganti22be97b2018-02-07 01:19:59 -0600248bool getDHCPEnabled()
249{
Patrick Williams5d82f472022-07-22 19:26:53 -0500250 sdbusplus::bus_t bus{ipmid_get_sd_bus_connection()};
Nagaraju Goruganti22be97b2018-02-07 01:19:59 -0600251
Johnathan Mantey74a21022018-12-13 13:17:56 -0800252 auto ethdevice = ipmi::getChannelName(ethernetDefaultChannelNum);
Patrick Venture0b02be92018-08-31 11:55:55 -0700253 auto ethernetObj =
254 ipmi::getDbusObject(bus, ethernetIntf, networkRoot, ethdevice);
Nagaraju Goruganti22be97b2018-02-07 01:19:59 -0600255 auto service = ipmi::getService(bus, ethernetIntf, ethernetObj.first);
Patrick Venture0b02be92018-08-31 11:55:55 -0700256 auto value = ipmi::getDbusProperty(bus, service, ethernetObj.first,
257 ethernetIntf, "DHCPEnabled");
Nagaraju Goruganti22be97b2018-02-07 01:19:59 -0600258
Vernon Maueryf442e112019-04-09 11:44:36 -0700259 return std::get<bool>(value);
Nagaraju Goruganti22be97b2018-02-07 01:19:59 -0600260}
261
262bool getDHCPOption(std::string prop)
263{
Patrick Williams5d82f472022-07-22 19:26:53 -0500264 sdbusplus::bus_t bus{ipmid_get_sd_bus_connection()};
Nagaraju Goruganti22be97b2018-02-07 01:19:59 -0600265
266 auto service = ipmi::getService(bus, dhcpIntf, dhcpObj);
267 auto value = ipmi::getDbusProperty(bus, service, dhcpObj, dhcpIntf, prop);
268
Vernon Maueryf442e112019-04-09 11:44:36 -0700269 return std::get<bool>(value);
Nagaraju Goruganti22be97b2018-02-07 01:19:59 -0600270}
271
Nagaraju Goruganti22be97b2018-02-07 01:19:59 -0600272void setDHCPOption(std::string prop, bool value)
273{
Patrick Williams5d82f472022-07-22 19:26:53 -0500274 sdbusplus::bus_t bus{ipmid_get_sd_bus_connection()};
Nagaraju Goruganti22be97b2018-02-07 01:19:59 -0600275
276 auto service = ipmi::getService(bus, dhcpIntf, dhcpObj);
277 ipmi::setDbusProperty(bus, service, dhcpObj, dhcpIntf, prop, value);
278}
279
Kirill Pakhomova2573622018-11-02 19:00:18 +0300280Json parseJSONConfig(const std::string& configFile)
Deepak Kodihalli0b459552018-02-06 06:25:12 -0600281{
282 std::ifstream jsonFile(configFile);
283 if (!jsonFile.is_open())
284 {
285 log<level::ERR>("Temperature readings JSON file not found");
286 elog<InternalFailure>();
287 }
288
289 auto data = Json::parse(jsonFile, nullptr, false);
290 if (data.is_discarded())
291 {
292 log<level::ERR>("Temperature readings JSON parser failure");
293 elog<InternalFailure>();
294 }
295
296 return data;
297}
298
Tom Josephbe5eaa12017-07-12 19:54:44 +0530299} // namespace dcmi
Chris Austen1810bec2015-10-13 12:12:39 -0500300
Willy Tu11d68892022-01-20 10:37:34 -0800301ipmi_ret_t getPowerLimit(ipmi_netfn_t, ipmi_cmd_t, ipmi_request_t,
302 ipmi_response_t response, ipmi_data_len_t data_len,
303 ipmi_context_t)
Tom Josephb9d86f42017-07-26 18:03:47 +0530304{
Kirill Pakhomov2c2af2c2018-11-06 16:06:10 +0300305 if (!dcmi::isDCMIPowerMgmtSupported())
306 {
307 *data_len = 0;
308 log<level::ERR>("DCMI Power management is unsupported!");
309 return IPMI_CC_INVALID;
310 }
311
Tom Josephb9d86f42017-07-26 18:03:47 +0530312 std::vector<uint8_t> outPayload(sizeof(dcmi::GetPowerLimitResponse));
Patrick Venture0b02be92018-08-31 11:55:55 -0700313 auto responseData =
314 reinterpret_cast<dcmi::GetPowerLimitResponse*>(outPayload.data());
Tom Josephb9d86f42017-07-26 18:03:47 +0530315
Patrick Williams5d82f472022-07-22 19:26:53 -0500316 sdbusplus::bus_t sdbus{ipmid_get_sd_bus_connection()};
Tom Josephb9d86f42017-07-26 18:03:47 +0530317 uint32_t pcapValue = 0;
318 bool pcapEnable = false;
319
320 try
321 {
322 pcapValue = dcmi::getPcap(sdbus);
323 pcapEnable = dcmi::getPcapEnabled(sdbus);
324 }
Patrick Williamsa2ad2da2021-10-06 12:21:46 -0500325 catch (const InternalFailure& e)
Tom Josephb9d86f42017-07-26 18:03:47 +0530326 {
327 *data_len = 0;
328 return IPMI_CC_UNSPECIFIED_ERROR;
329 }
330
Tom Josephb9d86f42017-07-26 18:03:47 +0530331 /*
332 * Exception action if power limit is exceeded and cannot be controlled
333 * with the correction time limit is hardcoded to Hard Power Off system
334 * and log event to SEL.
335 */
336 constexpr auto exception = 0x01;
337 responseData->exceptionAction = exception;
338
339 responseData->powerLimit = static_cast<uint16_t>(pcapValue);
340
341 /*
342 * Correction time limit and Statistics sampling period is currently not
343 * populated.
344 */
345
346 *data_len = outPayload.size();
347 memcpy(response, outPayload.data(), *data_len);
348
349 if (pcapEnable)
350 {
351 return IPMI_CC_OK;
352 }
353 else
354 {
355 return IPMI_DCMI_CC_NO_ACTIVE_POWER_LIMIT;
356 }
357}
358
Willy Tu11d68892022-01-20 10:37:34 -0800359ipmi_ret_t setPowerLimit(ipmi_netfn_t, ipmi_cmd_t, ipmi_request_t request,
360 ipmi_response_t, ipmi_data_len_t data_len,
361 ipmi_context_t)
Tom Joseph46fa37d2017-07-26 18:11:55 +0530362{
Kirill Pakhomov2c2af2c2018-11-06 16:06:10 +0300363 if (!dcmi::isDCMIPowerMgmtSupported())
364 {
365 *data_len = 0;
366 log<level::ERR>("DCMI Power management is unsupported!");
367 return IPMI_CC_INVALID;
368 }
369
Patrick Venture0b02be92018-08-31 11:55:55 -0700370 auto requestData =
371 reinterpret_cast<const dcmi::SetPowerLimitRequest*>(request);
Tom Joseph46fa37d2017-07-26 18:11:55 +0530372
Patrick Williams5d82f472022-07-22 19:26:53 -0500373 sdbusplus::bus_t sdbus{ipmid_get_sd_bus_connection()};
Tom Joseph46fa37d2017-07-26 18:11:55 +0530374
375 // Only process the power limit requested in watts.
376 try
377 {
378 dcmi::setPcap(sdbus, requestData->powerLimit);
379 }
Patrick Williamsa2ad2da2021-10-06 12:21:46 -0500380 catch (const InternalFailure& e)
Tom Joseph46fa37d2017-07-26 18:11:55 +0530381 {
382 *data_len = 0;
383 return IPMI_CC_UNSPECIFIED_ERROR;
384 }
385
386 log<level::INFO>("Set Power Cap",
387 entry("POWERCAP=%u", requestData->powerLimit));
388
William A. Kennington III5d06cc62019-04-25 02:10:55 -0700389 *data_len = 0;
Tom Joseph46fa37d2017-07-26 18:11:55 +0530390 return IPMI_CC_OK;
391}
392
Willy Tu11d68892022-01-20 10:37:34 -0800393ipmi_ret_t applyPowerLimit(ipmi_netfn_t, ipmi_cmd_t, ipmi_request_t request,
394 ipmi_response_t, ipmi_data_len_t data_len,
395 ipmi_context_t)
Tom Joseph6c8d51b2017-07-26 18:18:06 +0530396{
Kirill Pakhomov2c2af2c2018-11-06 16:06:10 +0300397 if (!dcmi::isDCMIPowerMgmtSupported())
398 {
399 *data_len = 0;
400 log<level::ERR>("DCMI Power management is unsupported!");
401 return IPMI_CC_INVALID;
402 }
403
Patrick Venture0b02be92018-08-31 11:55:55 -0700404 auto requestData =
405 reinterpret_cast<const dcmi::ApplyPowerLimitRequest*>(request);
Tom Joseph6c8d51b2017-07-26 18:18:06 +0530406
Patrick Williams5d82f472022-07-22 19:26:53 -0500407 sdbusplus::bus_t sdbus{ipmid_get_sd_bus_connection()};
Tom Joseph6c8d51b2017-07-26 18:18:06 +0530408
409 try
410 {
411 dcmi::setPcapEnable(sdbus,
412 static_cast<bool>(requestData->powerLimitAction));
413 }
Patrick Williamsa2ad2da2021-10-06 12:21:46 -0500414 catch (const InternalFailure& e)
Tom Joseph6c8d51b2017-07-26 18:18:06 +0530415 {
416 *data_len = 0;
417 return IPMI_CC_UNSPECIFIED_ERROR;
418 }
419
420 log<level::INFO>("Set Power Cap Enable",
421 entry("POWERCAPENABLE=%u", requestData->powerLimitAction));
422
William A. Kennington III5d06cc62019-04-25 02:10:55 -0700423 *data_len = 0;
Tom Joseph6c8d51b2017-07-26 18:18:06 +0530424 return IPMI_CC_OK;
425}
426
Willy Tu11d68892022-01-20 10:37:34 -0800427ipmi_ret_t getAssetTag(ipmi_netfn_t, ipmi_cmd_t, ipmi_request_t request,
428 ipmi_response_t response, ipmi_data_len_t data_len,
429 ipmi_context_t)
Tom Joseph6f6dd4d2017-07-12 20:07:11 +0530430{
Patrick Venture0b02be92018-08-31 11:55:55 -0700431 auto requestData =
432 reinterpret_cast<const dcmi::GetAssetTagRequest*>(request);
Tom Joseph6f6dd4d2017-07-12 20:07:11 +0530433 std::vector<uint8_t> outPayload(sizeof(dcmi::GetAssetTagResponse));
Patrick Venture0b02be92018-08-31 11:55:55 -0700434 auto responseData =
435 reinterpret_cast<dcmi::GetAssetTagResponse*>(outPayload.data());
Tom Joseph6f6dd4d2017-07-12 20:07:11 +0530436
Tom Joseph6f6dd4d2017-07-12 20:07:11 +0530437 // Verify offset to read and number of bytes to read are not exceeding the
438 // range.
439 if ((requestData->offset > dcmi::assetTagMaxOffset) ||
440 (requestData->bytes > dcmi::maxBytes) ||
441 ((requestData->offset + requestData->bytes) > dcmi::assetTagMaxSize))
442 {
443 *data_len = 0;
444 return IPMI_CC_PARM_OUT_OF_RANGE;
445 }
446
447 std::string assetTag;
448
449 try
450 {
451 assetTag = dcmi::readAssetTag();
452 }
Patrick Williamsa2ad2da2021-10-06 12:21:46 -0500453 catch (const InternalFailure& e)
Tom Joseph6f6dd4d2017-07-12 20:07:11 +0530454 {
455 *data_len = 0;
456 return IPMI_CC_UNSPECIFIED_ERROR;
457 }
458
Tom Joseph6f6dd4d2017-07-12 20:07:11 +0530459 // Return if the asset tag is not populated.
460 if (!assetTag.size())
461 {
462 responseData->tagLength = 0;
463 memcpy(response, outPayload.data(), outPayload.size());
464 *data_len = outPayload.size();
465 return IPMI_CC_OK;
466 }
467
468 // If the asset tag is longer than 63 bytes, restrict it to 63 bytes to suit
469 // Get Asset Tag command.
470 if (assetTag.size() > dcmi::assetTagMaxSize)
471 {
472 assetTag.resize(dcmi::assetTagMaxSize);
473 }
474
475 // If the requested offset is beyond the asset tag size.
476 if (requestData->offset >= assetTag.size())
477 {
478 *data_len = 0;
479 return IPMI_CC_PARM_OUT_OF_RANGE;
480 }
481
482 auto returnData = assetTag.substr(requestData->offset, requestData->bytes);
483
484 responseData->tagLength = assetTag.size();
485
486 memcpy(response, outPayload.data(), outPayload.size());
487 memcpy(static_cast<uint8_t*>(response) + outPayload.size(),
488 returnData.data(), returnData.size());
489 *data_len = outPayload.size() + returnData.size();
490
491 return IPMI_CC_OK;
492}
493
Willy Tu11d68892022-01-20 10:37:34 -0800494ipmi_ret_t setAssetTag(ipmi_netfn_t, ipmi_cmd_t, ipmi_request_t request,
495 ipmi_response_t response, ipmi_data_len_t data_len,
496 ipmi_context_t)
Tom Joseph545dd232017-07-12 20:20:49 +0530497{
Patrick Venture0b02be92018-08-31 11:55:55 -0700498 auto requestData =
499 reinterpret_cast<const dcmi::SetAssetTagRequest*>(request);
Tom Joseph545dd232017-07-12 20:20:49 +0530500 std::vector<uint8_t> outPayload(sizeof(dcmi::SetAssetTagResponse));
Patrick Venture0b02be92018-08-31 11:55:55 -0700501 auto responseData =
502 reinterpret_cast<dcmi::SetAssetTagResponse*>(outPayload.data());
Tom Joseph545dd232017-07-12 20:20:49 +0530503
Tom Joseph545dd232017-07-12 20:20:49 +0530504 // Verify offset to read and number of bytes to read are not exceeding the
505 // range.
506 if ((requestData->offset > dcmi::assetTagMaxOffset) ||
507 (requestData->bytes > dcmi::maxBytes) ||
508 ((requestData->offset + requestData->bytes) > dcmi::assetTagMaxSize))
509 {
510 *data_len = 0;
511 return IPMI_CC_PARM_OUT_OF_RANGE;
512 }
513
514 std::string assetTag;
515
516 try
517 {
518 assetTag = dcmi::readAssetTag();
519
520 if (requestData->offset > assetTag.size())
521 {
522 *data_len = 0;
523 return IPMI_CC_PARM_OUT_OF_RANGE;
524 }
525
526 assetTag.replace(requestData->offset,
527 assetTag.size() - requestData->offset,
528 static_cast<const char*>(request) +
Patrick Venture0b02be92018-08-31 11:55:55 -0700529 sizeof(dcmi::SetAssetTagRequest),
Tom Joseph545dd232017-07-12 20:20:49 +0530530 requestData->bytes);
531
532 dcmi::writeAssetTag(assetTag);
533
Tom Joseph545dd232017-07-12 20:20:49 +0530534 responseData->tagLength = assetTag.size();
535 memcpy(response, outPayload.data(), outPayload.size());
536 *data_len = outPayload.size();
537
538 return IPMI_CC_OK;
539 }
Patrick Williamsa2ad2da2021-10-06 12:21:46 -0500540 catch (const InternalFailure& e)
Tom Joseph545dd232017-07-12 20:20:49 +0530541 {
542 *data_len = 0;
543 return IPMI_CC_UNSPECIFIED_ERROR;
544 }
545}
546
Willy Tu11d68892022-01-20 10:37:34 -0800547ipmi_ret_t getMgmntCtrlIdStr(ipmi_netfn_t, ipmi_cmd_t, ipmi_request_t request,
548 ipmi_response_t response, ipmi_data_len_t data_len,
549 ipmi_context_t)
Vladislav Vovchenko8f7a6f62017-08-17 00:31:14 +0300550{
Patrick Venture0b02be92018-08-31 11:55:55 -0700551 auto requestData =
552 reinterpret_cast<const dcmi::GetMgmntCtrlIdStrRequest*>(request);
553 auto responseData =
554 reinterpret_cast<dcmi::GetMgmntCtrlIdStrResponse*>(response);
Vladislav Vovchenko8f7a6f62017-08-17 00:31:14 +0300555 std::string hostName;
556
557 *data_len = 0;
558
William A. Kennington III5d06cc62019-04-25 02:10:55 -0700559 if (requestData->bytes > dcmi::maxBytes ||
Vladislav Vovchenko8f7a6f62017-08-17 00:31:14 +0300560 requestData->offset + requestData->bytes > dcmi::maxCtrlIdStrLen)
561 {
562 return IPMI_CC_INVALID_FIELD_REQUEST;
563 }
564
565 try
566 {
567 hostName = dcmi::getHostName();
568 }
Patrick Williamsa2ad2da2021-10-06 12:21:46 -0500569 catch (const InternalFailure& e)
Vladislav Vovchenko8f7a6f62017-08-17 00:31:14 +0300570 {
571 return IPMI_CC_UNSPECIFIED_ERROR;
572 }
573
574 if (requestData->offset > hostName.length())
575 {
576 return IPMI_CC_PARM_OUT_OF_RANGE;
577 }
578 auto responseStr = hostName.substr(requestData->offset, requestData->bytes);
579 auto responseStrLen = std::min(static_cast<std::size_t>(requestData->bytes),
Patrick Venture0b02be92018-08-31 11:55:55 -0700580 responseStr.length() + 1);
Vladislav Vovchenko8f7a6f62017-08-17 00:31:14 +0300581 responseData->strLen = hostName.length();
582 std::copy(begin(responseStr), end(responseStr), responseData->data);
583
584 *data_len = sizeof(*responseData) + responseStrLen;
585 return IPMI_CC_OK;
586}
587
Willy Tu11d68892022-01-20 10:37:34 -0800588ipmi_ret_t setMgmntCtrlIdStr(ipmi_netfn_t, ipmi_cmd_t, ipmi_request_t request,
589 ipmi_response_t response, ipmi_data_len_t data_len,
590 ipmi_context_t)
Vladislav Vovchenko8f7a6f62017-08-17 00:31:14 +0300591{
592 static std::array<char, dcmi::maxCtrlIdStrLen + 1> newCtrlIdStr;
593
Patrick Venture0b02be92018-08-31 11:55:55 -0700594 auto requestData =
595 reinterpret_cast<const dcmi::SetMgmntCtrlIdStrRequest*>(request);
596 auto responseData =
597 reinterpret_cast<dcmi::SetMgmntCtrlIdStrResponse*>(response);
Vladislav Vovchenko8f7a6f62017-08-17 00:31:14 +0300598
599 *data_len = 0;
600
William A. Kennington III5d06cc62019-04-25 02:10:55 -0700601 if (requestData->bytes > dcmi::maxBytes ||
Vladislav Vovchenko8f7a6f62017-08-17 00:31:14 +0300602 requestData->offset + requestData->bytes > dcmi::maxCtrlIdStrLen + 1 ||
Patrick Venture0b02be92018-08-31 11:55:55 -0700603 (requestData->offset + requestData->bytes ==
604 dcmi::maxCtrlIdStrLen + 1 &&
605 requestData->data[requestData->bytes - 1] != '\0'))
Vladislav Vovchenko8f7a6f62017-08-17 00:31:14 +0300606 {
607 return IPMI_CC_INVALID_FIELD_REQUEST;
608 }
609
610 try
611 {
612 /* if there is no old value and offset is not 0 */
613 if (newCtrlIdStr[0] == '\0' && requestData->offset != 0)
614 {
615 /* read old ctrlIdStr */
616 auto hostName = dcmi::getHostName();
617 hostName.resize(dcmi::maxCtrlIdStrLen);
618 std::copy(begin(hostName), end(hostName), begin(newCtrlIdStr));
619 newCtrlIdStr[hostName.length()] = '\0';
620 }
621
622 /* replace part of string and mark byte after the last as \0 */
Patrick Venture0b02be92018-08-31 11:55:55 -0700623 auto restStrIter =
624 std::copy_n(requestData->data, requestData->bytes,
625 begin(newCtrlIdStr) + requestData->offset);
Vladislav Vovchenko8f7a6f62017-08-17 00:31:14 +0300626 /* if the last written byte is not 64th - add '\0' */
627 if (requestData->offset + requestData->bytes <= dcmi::maxCtrlIdStrLen)
628 {
629 *restStrIter = '\0';
630 }
631
632 /* if input data contains '\0' whole string is sent - update hostname */
633 auto it = std::find(requestData->data,
Patrick Venture0b02be92018-08-31 11:55:55 -0700634 requestData->data + requestData->bytes, '\0');
Vladislav Vovchenko8f7a6f62017-08-17 00:31:14 +0300635 if (it != requestData->data + requestData->bytes)
636 {
Patrick Williams5d82f472022-07-22 19:26:53 -0500637 sdbusplus::bus_t bus{ipmid_get_sd_bus_connection()};
Vladislav Vovchenko8f7a6f62017-08-17 00:31:14 +0300638 ipmi::setDbusProperty(bus, dcmi::networkServiceName,
Patrick Venture0b02be92018-08-31 11:55:55 -0700639 dcmi::networkConfigObj,
640 dcmi::networkConfigIntf, dcmi::hostNameProp,
641 std::string(newCtrlIdStr.data()));
Vladislav Vovchenko8f7a6f62017-08-17 00:31:14 +0300642 }
643 }
Patrick Williamsa2ad2da2021-10-06 12:21:46 -0500644 catch (const InternalFailure& e)
Vladislav Vovchenko8f7a6f62017-08-17 00:31:14 +0300645 {
646 *data_len = 0;
647 return IPMI_CC_UNSPECIFIED_ERROR;
648 }
649
Vladislav Vovchenko8f7a6f62017-08-17 00:31:14 +0300650 responseData->offset = requestData->offset + requestData->bytes;
651 *data_len = sizeof(*responseData);
652 return IPMI_CC_OK;
653}
654
Patrick Venture0b02be92018-08-31 11:55:55 -0700655// List of the capabilities under each parameter
656dcmi::DCMICaps dcmiCaps = {
657 // Supported DCMI Capabilities
658 {dcmi::DCMICapParameters::SUPPORTED_DCMI_CAPS,
659 {3,
660 {{"PowerManagement", 2, 0, 1},
661 {"OOBSecondaryLan", 3, 2, 1},
662 {"SerialTMODE", 3, 1, 1},
663 {"InBandSystemInterfaceChannel", 3, 0, 1}}}},
664 // Mandatory Platform Attributes
665 {dcmi::DCMICapParameters::MANDATORY_PLAT_ATTRIBUTES,
666 {5,
667 {{"SELAutoRollOver", 1, 15, 1},
668 {"FlushEntireSELUponRollOver", 1, 14, 1},
669 {"RecordLevelSELFlushUponRollOver", 1, 13, 1},
670 {"NumberOfSELEntries", 1, 0, 12},
671 {"TempMonitoringSamplingFreq", 5, 0, 8}}}},
672 // Optional Platform Attributes
673 {dcmi::DCMICapParameters::OPTIONAL_PLAT_ATTRIBUTES,
674 {2,
675 {{"PowerMgmtDeviceSlaveAddress", 1, 1, 7},
676 {"BMCChannelNumber", 2, 4, 4},
677 {"DeviceRivision", 2, 0, 4}}}},
678 // Manageability Access Attributes
679 {dcmi::DCMICapParameters::MANAGEABILITY_ACCESS_ATTRIBUTES,
680 {3,
681 {{"MandatoryPrimaryLanOOBSupport", 1, 0, 8},
682 {"OptionalSecondaryLanOOBSupport", 2, 0, 8},
683 {"OptionalSerialOOBMTMODECapability", 3, 0, 8}}}}};
Dhruvaraj Subhashchandrane29be412018-01-16 05:11:56 -0600684
Willy Tu11d68892022-01-20 10:37:34 -0800685ipmi_ret_t getDCMICapabilities(ipmi_netfn_t, ipmi_cmd_t, ipmi_request_t request,
686 ipmi_response_t response,
687 ipmi_data_len_t data_len, ipmi_context_t)
Dhruvaraj Subhashchandrane29be412018-01-16 05:11:56 -0600688{
689
Kirill Pakhomova2573622018-11-02 19:00:18 +0300690 std::ifstream dcmiCapFile(dcmi::gDCMICapabilitiesConfig);
Dhruvaraj Subhashchandrane29be412018-01-16 05:11:56 -0600691 if (!dcmiCapFile.is_open())
692 {
693 log<level::ERR>("DCMI Capabilities file not found");
694 return IPMI_CC_UNSPECIFIED_ERROR;
695 }
696
697 auto data = nlohmann::json::parse(dcmiCapFile, nullptr, false);
698 if (data.is_discarded())
699 {
700 log<level::ERR>("DCMI Capabilities JSON parser failure");
701 return IPMI_CC_UNSPECIFIED_ERROR;
702 }
703
Patrick Venture0b02be92018-08-31 11:55:55 -0700704 auto requestData =
705 reinterpret_cast<const dcmi::GetDCMICapRequest*>(request);
Dhruvaraj Subhashchandrane29be412018-01-16 05:11:56 -0600706
Patrick Venture0b02be92018-08-31 11:55:55 -0700707 // get list of capabilities in a parameter
Dhruvaraj Subhashchandrane29be412018-01-16 05:11:56 -0600708 auto caps =
709 dcmiCaps.find(static_cast<dcmi::DCMICapParameters>(requestData->param));
710 if (caps == dcmiCaps.end())
711 {
712 log<level::ERR>("Invalid input parameter");
713 return IPMI_CC_INVALID_FIELD_REQUEST;
714 }
715
Patrick Venture0b02be92018-08-31 11:55:55 -0700716 auto responseData = reinterpret_cast<dcmi::GetDCMICapResponse*>(response);
Dhruvaraj Subhashchandrane29be412018-01-16 05:11:56 -0600717
Patrick Venture0b02be92018-08-31 11:55:55 -0700718 // For each capabilities in a parameter fill the data from
719 // the json file based on the capability name.
Dhruvaraj Subhashchandrane29be412018-01-16 05:11:56 -0600720 for (auto cap : caps->second.capList)
721 {
Patrick Venture0b02be92018-08-31 11:55:55 -0700722 // If the data is beyond first byte boundary, insert in a
723 // 16bit pattern for example number of SEL entries are represented
724 // in 12bits.
Kirill Pakhomovdb5d9b02018-11-06 19:17:51 +0300725 if ((cap.length + cap.position) > dcmi::gByteBitSize)
Dhruvaraj Subhashchandrane29be412018-01-16 05:11:56 -0600726 {
Kirill Pakhomovdb5d9b02018-11-06 19:17:51 +0300727 uint16_t val = data.value(cap.name.c_str(), 0);
728 // According to DCMI spec v1.5, max number of SEL entries is
729 // 4096, but bit 12b of DCMI capabilities Mandatory Platform
730 // Attributes field is reserved and therefore we can use only
731 // the provided 12 bits with maximum value of 4095.
732 // We're playing safe here by applying the mask
733 // to ensure that provided value will fit into 12 bits.
734 if (cap.length > dcmi::gByteBitSize)
735 {
736 val &= dcmi::gMaxSELEntriesMask;
737 }
Dhruvaraj Subhashchandrane29be412018-01-16 05:11:56 -0600738 val <<= cap.position;
Kirill Pakhomovdb5d9b02018-11-06 19:17:51 +0300739 responseData->data[cap.bytePosition - 1] |=
740 static_cast<uint8_t>(val);
741 responseData->data[cap.bytePosition] |= val >> dcmi::gByteBitSize;
Dhruvaraj Subhashchandrane29be412018-01-16 05:11:56 -0600742 }
743 else
744 {
745 responseData->data[cap.bytePosition - 1] |=
746 data.value(cap.name.c_str(), 0) << cap.position;
747 }
748 }
749
Dhruvaraj Subhashchandrane29be412018-01-16 05:11:56 -0600750 responseData->major = DCMI_SPEC_MAJOR_VERSION;
751 responseData->minor = DCMI_SPEC_MINOR_VERSION;
752 responseData->paramRevision = DCMI_PARAMETER_REVISION;
753 *data_len = sizeof(*responseData) + caps->second.size;
754
755 return IPMI_CC_OK;
756}
757
Deepak Kodihalliee717d72018-01-24 04:53:09 -0600758namespace dcmi
759{
760namespace temp_readings
761{
762
Deepak Kodihallib1e8fba2018-01-24 04:57:10 -0600763Temperature readTemp(const std::string& dbusService,
764 const std::string& dbusPath)
765{
766 // Read the temperature value from d-bus object. Need some conversion.
767 // As per the interface xyz.openbmc_project.Sensor.Value, the temperature
James Feist9cc0ea52018-10-09 10:53:11 -0700768 // is an double and in degrees C. It needs to be scaled by using the
Deepak Kodihallib1e8fba2018-01-24 04:57:10 -0600769 // formula Value * 10^Scale. The ipmi spec has the temperature as a uint8_t,
770 // with a separate single bit for the sign.
771
Patrick Williams5d82f472022-07-22 19:26:53 -0500772 sdbusplus::bus_t bus{ipmid_get_sd_bus_connection()};
Patrick Venture0b02be92018-08-31 11:55:55 -0700773 auto result = ipmi::getAllDbusProperties(
774 bus, dbusService, dbusPath, "xyz.openbmc_project.Sensor.Value");
Vernon Maueryf442e112019-04-09 11:44:36 -0700775 auto temperature =
776 std::visit(ipmi::VariantToDoubleVisitor(), result.at("Value"));
James Feist9cc0ea52018-10-09 10:53:11 -0700777 double absTemp = std::abs(temperature);
Deepak Kodihallib1e8fba2018-01-24 04:57:10 -0600778
James Feist9cc0ea52018-10-09 10:53:11 -0700779 auto findFactor = result.find("Scale");
780 double factor = 0.0;
781 if (findFactor != result.end())
Deepak Kodihallib1e8fba2018-01-24 04:57:10 -0600782 {
Vernon Maueryf442e112019-04-09 11:44:36 -0700783 factor = std::visit(ipmi::VariantToDoubleVisitor(), findFactor->second);
Deepak Kodihallib1e8fba2018-01-24 04:57:10 -0600784 }
James Feist9cc0ea52018-10-09 10:53:11 -0700785 double scale = std::pow(10, factor);
786
787 auto tempDegrees = absTemp * scale;
Deepak Kodihallib1e8fba2018-01-24 04:57:10 -0600788 // Max absolute temp as per ipmi spec is 128.
789 if (tempDegrees > maxTemp)
790 {
791 tempDegrees = maxTemp;
792 }
793
794 return std::make_tuple(static_cast<uint8_t>(tempDegrees),
795 (temperature < 0));
796}
797
Deepak Kodihalliee717d72018-01-24 04:53:09 -0600798std::tuple<Response, NumInstances> read(const std::string& type,
799 uint8_t instance)
800{
Deepak Kodihallib1e8fba2018-01-24 04:57:10 -0600801 Response response{};
Patrick Williams5d82f472022-07-22 19:26:53 -0500802 sdbusplus::bus_t bus{ipmid_get_sd_bus_connection()};
Deepak Kodihallib1e8fba2018-01-24 04:57:10 -0600803
804 if (!instance)
805 {
806 log<level::ERR>("Expected non-zero instance");
807 elog<InternalFailure>();
808 }
809
Kirill Pakhomova2573622018-11-02 19:00:18 +0300810 auto data = parseJSONConfig(gDCMISensorsConfig);
Deepak Kodihallib1e8fba2018-01-24 04:57:10 -0600811 static const std::vector<Json> empty{};
812 std::vector<Json> readings = data.value(type, empty);
813 size_t numInstances = readings.size();
814 for (const auto& j : readings)
815 {
816 uint8_t instanceNum = j.value("instance", 0);
817 // Not the instance we're interested in
818 if (instanceNum != instance)
819 {
820 continue;
821 }
822
823 std::string path = j.value("dbus", "");
824 std::string service;
825 try
826 {
827 service =
Patrick Venture0b02be92018-08-31 11:55:55 -0700828 ipmi::getService(bus, "xyz.openbmc_project.Sensor.Value", path);
Deepak Kodihallib1e8fba2018-01-24 04:57:10 -0600829 }
Patrick Williamsa2ad2da2021-10-06 12:21:46 -0500830 catch (const std::exception& e)
Deepak Kodihallib1e8fba2018-01-24 04:57:10 -0600831 {
832 log<level::DEBUG>(e.what());
833 return std::make_tuple(response, numInstances);
834 }
835
836 response.instance = instance;
837 uint8_t temp{};
838 bool sign{};
839 std::tie(temp, sign) = readTemp(service, path);
840 response.temperature = temp;
841 response.sign = sign;
842
843 // Found the instance we're interested in
844 break;
845 }
846
847 if (numInstances > maxInstances)
848 {
849 numInstances = maxInstances;
850 }
851 return std::make_tuple(response, numInstances);
Deepak Kodihalliee717d72018-01-24 04:53:09 -0600852}
853
854std::tuple<ResponseList, NumInstances> readAll(const std::string& type,
855 uint8_t instanceStart)
856{
Deepak Kodihallib1e8fba2018-01-24 04:57:10 -0600857 ResponseList response{};
Patrick Williams5d82f472022-07-22 19:26:53 -0500858 sdbusplus::bus_t bus{ipmid_get_sd_bus_connection()};
Deepak Kodihallib1e8fba2018-01-24 04:57:10 -0600859
860 size_t numInstances = 0;
Kirill Pakhomova2573622018-11-02 19:00:18 +0300861 auto data = parseJSONConfig(gDCMISensorsConfig);
Deepak Kodihallib1e8fba2018-01-24 04:57:10 -0600862 static const std::vector<Json> empty{};
863 std::vector<Json> readings = data.value(type, empty);
864 numInstances = readings.size();
865 for (const auto& j : readings)
866 {
867 try
868 {
869 // Max of 8 response data sets
870 if (response.size() == maxDataSets)
871 {
872 break;
873 }
874
875 uint8_t instanceNum = j.value("instance", 0);
876 // Not in the instance range we're interested in
877 if (instanceNum < instanceStart)
878 {
879 continue;
880 }
881
882 std::string path = j.value("dbus", "");
883 auto service =
Patrick Venture0b02be92018-08-31 11:55:55 -0700884 ipmi::getService(bus, "xyz.openbmc_project.Sensor.Value", path);
Deepak Kodihallib1e8fba2018-01-24 04:57:10 -0600885
886 Response r{};
887 r.instance = instanceNum;
888 uint8_t temp{};
889 bool sign{};
890 std::tie(temp, sign) = readTemp(service, path);
891 r.temperature = temp;
892 r.sign = sign;
893 response.push_back(r);
894 }
Patrick Williamsa2ad2da2021-10-06 12:21:46 -0500895 catch (const std::exception& e)
Deepak Kodihallib1e8fba2018-01-24 04:57:10 -0600896 {
897 log<level::DEBUG>(e.what());
898 continue;
899 }
900 }
901
902 if (numInstances > maxInstances)
903 {
904 numInstances = maxInstances;
905 }
906 return std::make_tuple(response, numInstances);
Deepak Kodihalliee717d72018-01-24 04:53:09 -0600907}
908
Patrick Venture0b02be92018-08-31 11:55:55 -0700909} // namespace temp_readings
910} // namespace dcmi
Deepak Kodihalliee717d72018-01-24 04:53:09 -0600911
Willy Tu11d68892022-01-20 10:37:34 -0800912ipmi_ret_t getTempReadings(ipmi_netfn_t, ipmi_cmd_t, ipmi_request_t request,
913 ipmi_response_t response, ipmi_data_len_t data_len,
914 ipmi_context_t)
Deepak Kodihalliee717d72018-01-24 04:53:09 -0600915{
Deepak Kodihalliee717d72018-01-24 04:53:09 -0600916 auto requestData =
917 reinterpret_cast<const dcmi::GetTempReadingsRequest*>(request);
918 auto responseData =
919 reinterpret_cast<dcmi::GetTempReadingsResponseHdr*>(response);
920
921 if (*data_len != sizeof(dcmi::GetTempReadingsRequest))
922 {
923 log<level::ERR>("Malformed request data",
924 entry("DATA_SIZE=%d", *data_len));
925 return IPMI_CC_REQ_DATA_LEN_INVALID;
926 }
927 *data_len = 0;
928
Deepak Kodihalli0b459552018-02-06 06:25:12 -0600929 auto it = dcmi::entityIdToName.find(requestData->entityId);
930 if (it == dcmi::entityIdToName.end())
Deepak Kodihalliee717d72018-01-24 04:53:09 -0600931 {
932 log<level::ERR>("Unknown Entity ID",
933 entry("ENTITY_ID=%d", requestData->entityId));
934 return IPMI_CC_INVALID_FIELD_REQUEST;
935 }
936
Deepak Kodihalliee717d72018-01-24 04:53:09 -0600937 if (requestData->sensorType != dcmi::temperatureSensorType)
938 {
939 log<level::ERR>("Invalid sensor type",
940 entry("SENSOR_TYPE=%d", requestData->sensorType));
941 return IPMI_CC_INVALID_FIELD_REQUEST;
942 }
943
944 dcmi::temp_readings::ResponseList temps{};
945 try
946 {
947 if (!requestData->entityInstance)
948 {
949 // Read all instances
950 std::tie(temps, responseData->numInstances) =
951 dcmi::temp_readings::readAll(it->second,
952 requestData->instanceStart);
953 }
954 else
955 {
956 // Read one instance
957 temps.resize(1);
958 std::tie(temps[0], responseData->numInstances) =
959 dcmi::temp_readings::read(it->second,
960 requestData->entityInstance);
961 }
962 responseData->numDataSets = temps.size();
963 }
Patrick Williamsa2ad2da2021-10-06 12:21:46 -0500964 catch (const InternalFailure& e)
Deepak Kodihalliee717d72018-01-24 04:53:09 -0600965 {
966 return IPMI_CC_UNSPECIFIED_ERROR;
967 }
968
Patrick Venture0b02be92018-08-31 11:55:55 -0700969 size_t payloadSize = temps.size() * sizeof(dcmi::temp_readings::Response);
Deepak Kodihalliee717d72018-01-24 04:53:09 -0600970 if (!temps.empty())
971 {
972 memcpy(responseData + 1, // copy payload right after the response header
Patrick Venture0b02be92018-08-31 11:55:55 -0700973 temps.data(), payloadSize);
Deepak Kodihalliee717d72018-01-24 04:53:09 -0600974 }
975 *data_len = sizeof(dcmi::GetTempReadingsResponseHdr) + payloadSize;
976
977 return IPMI_CC_OK;
978}
979
Patrick Williams5d82f472022-07-22 19:26:53 -0500980int64_t getPowerReading(sdbusplus::bus_t& bus)
Marri Devender Rao66c5fda2018-01-18 10:48:37 -0600981{
982 std::ifstream sensorFile(POWER_READING_SENSOR);
983 std::string objectPath;
984 if (!sensorFile.is_open())
985 {
986 log<level::ERR>("Power reading configuration file not found",
Patrick Venture0b02be92018-08-31 11:55:55 -0700987 entry("POWER_SENSOR_FILE=%s", POWER_READING_SENSOR));
Marri Devender Rao66c5fda2018-01-18 10:48:37 -0600988 elog<InternalFailure>();
989 }
990
991 auto data = nlohmann::json::parse(sensorFile, nullptr, false);
992 if (data.is_discarded())
993 {
994 log<level::ERR>("Error in parsing configuration file",
Patrick Venture0b02be92018-08-31 11:55:55 -0700995 entry("POWER_SENSOR_FILE=%s", POWER_READING_SENSOR));
Marri Devender Rao66c5fda2018-01-18 10:48:37 -0600996 elog<InternalFailure>();
997 }
998
999 objectPath = data.value("path", "");
1000 if (objectPath.empty())
1001 {
1002 log<level::ERR>("Power sensor D-Bus object path is empty",
1003 entry("POWER_SENSOR_FILE=%s", POWER_READING_SENSOR));
1004 elog<InternalFailure>();
1005 }
1006
Marri Devender Raoce6a7952018-02-11 08:45:00 -06001007 // Return default value if failed to read from D-Bus object
1008 int64_t power = 0;
1009 try
1010 {
1011 auto service = ipmi::getService(bus, SENSOR_VALUE_INTF, objectPath);
Marri Devender Rao66c5fda2018-01-18 10:48:37 -06001012
Patrick Venture0b02be92018-08-31 11:55:55 -07001013 // Read the sensor value and scale properties
Chris Cain4cc61e02022-01-12 17:23:14 -06001014 auto value = ipmi::getDbusProperty(
1015 bus, service, objectPath, SENSOR_VALUE_INTF, SENSOR_VALUE_PROP);
1016 power = std::get<double>(value);
Marri Devender Raoce6a7952018-02-11 08:45:00 -06001017 }
Patrick Williamsa2ad2da2021-10-06 12:21:46 -05001018 catch (const std::exception& e)
Marri Devender Raoce6a7952018-02-11 08:45:00 -06001019 {
Chris Cain4cc61e02022-01-12 17:23:14 -06001020 log<level::ERR>("Failure to read power value from D-Bus object",
1021 entry("OBJECT_PATH=%s", objectPath.c_str()),
1022 entry("INTERFACE=%s", SENSOR_VALUE_INTF));
Marri Devender Raoce6a7952018-02-11 08:45:00 -06001023 }
Marri Devender Rao66c5fda2018-01-18 10:48:37 -06001024 return power;
1025}
1026
Willy Tu11d68892022-01-20 10:37:34 -08001027ipmi_ret_t setDCMIConfParams(ipmi_netfn_t, ipmi_cmd_t, ipmi_request_t request,
1028 ipmi_response_t, ipmi_data_len_t data_len,
1029 ipmi_context_t)
Nagaraju Goruganti22be97b2018-02-07 01:19:59 -06001030{
Patrick Venture0b02be92018-08-31 11:55:55 -07001031 auto requestData =
1032 reinterpret_cast<const dcmi::SetConfParamsRequest*>(request);
Nagaraju Goruganti22be97b2018-02-07 01:19:59 -06001033
William A. Kennington III5d06cc62019-04-25 02:10:55 -07001034 if (*data_len < DCMI_SET_CONF_PARAM_REQ_PACKET_MIN_SIZE ||
Patrick Venture0b02be92018-08-31 11:55:55 -07001035 *data_len > DCMI_SET_CONF_PARAM_REQ_PACKET_MAX_SIZE)
Nagaraju Goruganti22be97b2018-02-07 01:19:59 -06001036 {
William A. Kennington III5d06cc62019-04-25 02:10:55 -07001037 log<level::ERR>("Invalid Requested Packet size",
Nagaraju Goruganti22be97b2018-02-07 01:19:59 -06001038 entry("PACKET SIZE=%d", *data_len));
William A. Kennington III5d06cc62019-04-25 02:10:55 -07001039 *data_len = 0;
Nagaraju Goruganti22be97b2018-02-07 01:19:59 -06001040 return IPMI_CC_INVALID_FIELD_REQUEST;
1041 }
Nagaraju Goruganti22be97b2018-02-07 01:19:59 -06001042 *data_len = 0;
1043
1044 try
1045 {
1046 // Take action based on the Parameter Selector
Patrick Venture0b02be92018-08-31 11:55:55 -07001047 switch (
1048 static_cast<dcmi::DCMIConfigParameters>(requestData->paramSelect))
Nagaraju Goruganti22be97b2018-02-07 01:19:59 -06001049 {
1050 case dcmi::DCMIConfigParameters::ActivateDHCP:
1051
1052 if ((requestData->data[0] & DCMI_ACTIVATE_DHCP_MASK) &&
Patrick Venture0b02be92018-08-31 11:55:55 -07001053 dcmi::getDHCPEnabled())
Nagaraju Goruganti22be97b2018-02-07 01:19:59 -06001054 {
Patrick Venture0b02be92018-08-31 11:55:55 -07001055 // When these conditions are met we have to trigger DHCP
1056 // protocol restart using the latest parameter settings, but
1057 // as per n/w manager design, each time when we update n/w
1058 // parameters, n/w service is restarted. So we no need to
1059 // take any action in this case.
Nagaraju Goruganti22be97b2018-02-07 01:19:59 -06001060 }
1061 break;
1062
1063 case dcmi::DCMIConfigParameters::DiscoveryConfig:
1064
1065 if (requestData->data[0] & DCMI_OPTION_12_MASK)
1066 {
1067 dcmi::setDHCPOption(DHCP_OPT12_ENABLED, true);
1068 }
1069 else
1070 {
1071 dcmi::setDHCPOption(DHCP_OPT12_ENABLED, false);
1072 }
1073
1074 // Systemd-networkd doesn't support Random Back off
1075 if (requestData->data[0] & DCMI_RAND_BACK_OFF_MASK)
1076 {
1077 return IPMI_CC_INVALID;
1078 }
1079 break;
1080 // Systemd-networkd doesn't allow to configure DHCP timigs
1081 case dcmi::DCMIConfigParameters::DHCPTiming1:
1082 case dcmi::DCMIConfigParameters::DHCPTiming2:
1083 case dcmi::DCMIConfigParameters::DHCPTiming3:
1084 default:
1085 return IPMI_CC_INVALID;
1086 }
1087 }
Patrick Williamsa2ad2da2021-10-06 12:21:46 -05001088 catch (const std::exception& e)
Nagaraju Goruganti22be97b2018-02-07 01:19:59 -06001089 {
1090 log<level::ERR>(e.what());
1091 return IPMI_CC_UNSPECIFIED_ERROR;
1092 }
Nagaraju Goruganti22be97b2018-02-07 01:19:59 -06001093 return IPMI_CC_OK;
1094}
1095
Willy Tu11d68892022-01-20 10:37:34 -08001096ipmi_ret_t getDCMIConfParams(ipmi_netfn_t, ipmi_cmd_t, ipmi_request_t request,
1097 ipmi_response_t response, ipmi_data_len_t data_len,
1098 ipmi_context_t)
Nagaraju Goruganti22be97b2018-02-07 01:19:59 -06001099{
1100
Patrick Venture0b02be92018-08-31 11:55:55 -07001101 auto requestData =
1102 reinterpret_cast<const dcmi::GetConfParamsRequest*>(request);
1103 auto responseData =
1104 reinterpret_cast<dcmi::GetConfParamsResponse*>(response);
Nagaraju Goruganti22be97b2018-02-07 01:19:59 -06001105
1106 responseData->data[0] = 0x00;
1107
William A. Kennington III5d06cc62019-04-25 02:10:55 -07001108 if (*data_len != sizeof(dcmi::GetConfParamsRequest))
Nagaraju Goruganti22be97b2018-02-07 01:19:59 -06001109 {
William A. Kennington III5d06cc62019-04-25 02:10:55 -07001110 log<level::ERR>("Invalid Requested Packet size",
Nagaraju Goruganti22be97b2018-02-07 01:19:59 -06001111 entry("PACKET SIZE=%d", *data_len));
1112 return IPMI_CC_INVALID_FIELD_REQUEST;
1113 }
1114
1115 *data_len = 0;
1116
1117 try
1118 {
1119 // Take action based on the Parameter Selector
Patrick Venture0b02be92018-08-31 11:55:55 -07001120 switch (
1121 static_cast<dcmi::DCMIConfigParameters>(requestData->paramSelect))
Nagaraju Goruganti22be97b2018-02-07 01:19:59 -06001122 {
1123 case dcmi::DCMIConfigParameters::ActivateDHCP:
1124 responseData->data[0] = DCMI_ACTIVATE_DHCP_REPLY;
1125 *data_len = sizeof(dcmi::GetConfParamsResponse) + 1;
1126 break;
1127 case dcmi::DCMIConfigParameters::DiscoveryConfig:
1128 if (dcmi::getDHCPOption(DHCP_OPT12_ENABLED))
1129 {
1130 responseData->data[0] |= DCMI_OPTION_12_MASK;
1131 }
1132 *data_len = sizeof(dcmi::GetConfParamsResponse) + 1;
1133 break;
1134 // Get below values from Systemd-networkd source code
1135 case dcmi::DCMIConfigParameters::DHCPTiming1:
1136 responseData->data[0] = DHCP_TIMING1;
1137 *data_len = sizeof(dcmi::GetConfParamsResponse) + 1;
1138 break;
1139 case dcmi::DCMIConfigParameters::DHCPTiming2:
1140 responseData->data[0] = DHCP_TIMING2_LOWER;
1141 responseData->data[1] = DHCP_TIMING2_UPPER;
1142 *data_len = sizeof(dcmi::GetConfParamsResponse) + 2;
1143 break;
1144 case dcmi::DCMIConfigParameters::DHCPTiming3:
1145 responseData->data[0] = DHCP_TIMING3_LOWER;
1146 responseData->data[1] = DHCP_TIMING3_UPPER;
1147 *data_len = sizeof(dcmi::GetConfParamsResponse) + 2;
1148 break;
1149 default:
1150 *data_len = 0;
1151 return IPMI_CC_INVALID;
1152 }
1153 }
Patrick Williamsa2ad2da2021-10-06 12:21:46 -05001154 catch (const std::exception& e)
Nagaraju Goruganti22be97b2018-02-07 01:19:59 -06001155 {
1156 log<level::ERR>(e.what());
1157 return IPMI_CC_UNSPECIFIED_ERROR;
1158 }
1159
Nagaraju Goruganti22be97b2018-02-07 01:19:59 -06001160 responseData->major = DCMI_SPEC_MAJOR_VERSION;
1161 responseData->minor = DCMI_SPEC_MINOR_VERSION;
1162 responseData->paramRevision = DCMI_CONFIG_PARAMETER_REVISION;
1163
1164 return IPMI_CC_OK;
1165}
1166
Willy Tu11d68892022-01-20 10:37:34 -08001167ipmi_ret_t getPowerReading(ipmi_netfn_t, ipmi_cmd_t, ipmi_request_t,
1168 ipmi_response_t response, ipmi_data_len_t data_len,
1169 ipmi_context_t)
Marri Devender Rao66c5fda2018-01-18 10:48:37 -06001170{
Chalapathi Venkataramashetty90e81fa2021-05-11 09:13:23 +00001171 *data_len = 0;
Kirill Pakhomov2c2af2c2018-11-06 16:06:10 +03001172 if (!dcmi::isDCMIPowerMgmtSupported())
1173 {
Kirill Pakhomov2c2af2c2018-11-06 16:06:10 +03001174 log<level::ERR>("DCMI Power management is unsupported!");
1175 return IPMI_CC_INVALID;
1176 }
1177
Marri Devender Rao66c5fda2018-01-18 10:48:37 -06001178 ipmi_ret_t rc = IPMI_CC_OK;
Patrick Venture0b02be92018-08-31 11:55:55 -07001179 auto responseData =
1180 reinterpret_cast<dcmi::GetPowerReadingResponse*>(response);
Marri Devender Rao9c966e02018-01-22 05:55:10 -06001181
Patrick Williams5d82f472022-07-22 19:26:53 -05001182 sdbusplus::bus_t bus{ipmid_get_sd_bus_connection()};
Marri Devender Rao9c966e02018-01-22 05:55:10 -06001183 int64_t power = 0;
Marri Devender Rao66c5fda2018-01-18 10:48:37 -06001184 try
1185 {
Marri Devender Rao9c966e02018-01-22 05:55:10 -06001186 power = getPowerReading(bus);
Marri Devender Rao66c5fda2018-01-18 10:48:37 -06001187 }
Patrick Williamsa2ad2da2021-10-06 12:21:46 -05001188 catch (const InternalFailure& e)
Marri Devender Rao66c5fda2018-01-18 10:48:37 -06001189 {
1190 log<level::ERR>("Error in reading power sensor value",
1191 entry("INTERFACE=%s", SENSOR_VALUE_INTF),
1192 entry("PROPERTY=%s", SENSOR_VALUE_PROP));
1193 return IPMI_CC_UNSPECIFIED_ERROR;
1194 }
Marri Devender Rao9c966e02018-01-22 05:55:10 -06001195
1196 // TODO: openbmc/openbmc#2819
Gunnar Mills8466b792018-03-23 12:18:12 -05001197 // Minimum, Maximum, Average power, TimeFrame, TimeStamp,
Marri Devender Rao9c966e02018-01-22 05:55:10 -06001198 // PowerReadingState readings need to be populated
1199 // after Telemetry changes.
1200 uint16_t totalPower = static_cast<uint16_t>(power);
1201 responseData->currentPower = totalPower;
1202 responseData->minimumPower = totalPower;
1203 responseData->maximumPower = totalPower;
1204 responseData->averagePower = totalPower;
1205
1206 *data_len = sizeof(*responseData);
Marri Devender Rao66c5fda2018-01-18 10:48:37 -06001207 return rc;
1208}
1209
Deepak Kodihalli0b459552018-02-06 06:25:12 -06001210namespace dcmi
1211{
1212namespace sensor_info
1213{
1214
Deepak Kodihallidd4cff12018-02-06 06:48:29 -06001215Response createFromJson(const Json& config)
1216{
1217 Response response{};
1218 uint16_t recordId = config.value("record_id", 0);
1219 response.recordIdLsb = recordId & 0xFF;
1220 response.recordIdMsb = (recordId >> 8) & 0xFF;
1221 return response;
1222}
1223
Deepak Kodihalli0b459552018-02-06 06:25:12 -06001224std::tuple<Response, NumInstances> read(const std::string& type,
Patrick Venture0b02be92018-08-31 11:55:55 -07001225 uint8_t instance, const Json& config)
Deepak Kodihalli0b459552018-02-06 06:25:12 -06001226{
Deepak Kodihallidd4cff12018-02-06 06:48:29 -06001227 Response response{};
1228
1229 if (!instance)
1230 {
1231 log<level::ERR>("Expected non-zero instance");
1232 elog<InternalFailure>();
1233 }
1234
1235 static const std::vector<Json> empty{};
1236 std::vector<Json> readings = config.value(type, empty);
1237 size_t numInstances = readings.size();
1238 for (const auto& reading : readings)
1239 {
1240 uint8_t instanceNum = reading.value("instance", 0);
1241 // Not the instance we're interested in
1242 if (instanceNum != instance)
1243 {
1244 continue;
1245 }
1246
1247 response = createFromJson(reading);
1248
1249 // Found the instance we're interested in
1250 break;
1251 }
1252
1253 if (numInstances > maxInstances)
1254 {
1255 log<level::DEBUG>("Trimming IPMI num instances",
1256 entry("NUM_INSTANCES=%d", numInstances));
1257 numInstances = maxInstances;
1258 }
1259 return std::make_tuple(response, numInstances);
Deepak Kodihalli0b459552018-02-06 06:25:12 -06001260}
1261
Patrick Venture0b02be92018-08-31 11:55:55 -07001262std::tuple<ResponseList, NumInstances>
1263 readAll(const std::string& type, uint8_t instanceStart, const Json& config)
Deepak Kodihalli0b459552018-02-06 06:25:12 -06001264{
Deepak Kodihallidd4cff12018-02-06 06:48:29 -06001265 ResponseList responses{};
1266
1267 size_t numInstances = 0;
1268 static const std::vector<Json> empty{};
1269 std::vector<Json> readings = config.value(type, empty);
1270 numInstances = readings.size();
1271 for (const auto& reading : readings)
1272 {
1273 try
1274 {
1275 // Max of 8 records
1276 if (responses.size() == maxRecords)
1277 {
1278 break;
1279 }
1280
1281 uint8_t instanceNum = reading.value("instance", 0);
1282 // Not in the instance range we're interested in
1283 if (instanceNum < instanceStart)
1284 {
1285 continue;
1286 }
1287
1288 Response response = createFromJson(reading);
1289 responses.push_back(response);
1290 }
Patrick Williamsa2ad2da2021-10-06 12:21:46 -05001291 catch (const std::exception& e)
Deepak Kodihallidd4cff12018-02-06 06:48:29 -06001292 {
1293 log<level::DEBUG>(e.what());
1294 continue;
1295 }
1296 }
1297
1298 if (numInstances > maxInstances)
1299 {
1300 log<level::DEBUG>("Trimming IPMI num instances",
1301 entry("NUM_INSTANCES=%d", numInstances));
1302 numInstances = maxInstances;
1303 }
1304 return std::make_tuple(responses, numInstances);
Deepak Kodihalli0b459552018-02-06 06:25:12 -06001305}
1306
1307} // namespace sensor_info
1308} // namespace dcmi
1309
Willy Tu11d68892022-01-20 10:37:34 -08001310ipmi_ret_t getSensorInfo(ipmi_netfn_t, ipmi_cmd_t, ipmi_request_t request,
1311 ipmi_response_t response, ipmi_data_len_t data_len,
1312 ipmi_context_t)
Deepak Kodihalli0b459552018-02-06 06:25:12 -06001313{
1314 auto requestData =
1315 reinterpret_cast<const dcmi::GetSensorInfoRequest*>(request);
1316 auto responseData =
1317 reinterpret_cast<dcmi::GetSensorInfoResponseHdr*>(response);
1318
1319 if (*data_len != sizeof(dcmi::GetSensorInfoRequest))
1320 {
1321 log<level::ERR>("Malformed request data",
1322 entry("DATA_SIZE=%d", *data_len));
1323 return IPMI_CC_REQ_DATA_LEN_INVALID;
1324 }
1325 *data_len = 0;
1326
1327 auto it = dcmi::entityIdToName.find(requestData->entityId);
1328 if (it == dcmi::entityIdToName.end())
1329 {
1330 log<level::ERR>("Unknown Entity ID",
1331 entry("ENTITY_ID=%d", requestData->entityId));
1332 return IPMI_CC_INVALID_FIELD_REQUEST;
1333 }
1334
Deepak Kodihalli0b459552018-02-06 06:25:12 -06001335 if (requestData->sensorType != dcmi::temperatureSensorType)
1336 {
1337 log<level::ERR>("Invalid sensor type",
1338 entry("SENSOR_TYPE=%d", requestData->sensorType));
1339 return IPMI_CC_INVALID_FIELD_REQUEST;
1340 }
1341
1342 dcmi::sensor_info::ResponseList sensors{};
1343 static dcmi::Json config{};
1344 static bool parsed = false;
1345
1346 try
1347 {
1348 if (!parsed)
1349 {
Kirill Pakhomova2573622018-11-02 19:00:18 +03001350 config = dcmi::parseJSONConfig(dcmi::gDCMISensorsConfig);
Deepak Kodihalli0b459552018-02-06 06:25:12 -06001351 parsed = true;
1352 }
1353
1354 if (!requestData->entityInstance)
1355 {
1356 // Read all instances
1357 std::tie(sensors, responseData->numInstances) =
1358 dcmi::sensor_info::readAll(it->second,
Patrick Venture0b02be92018-08-31 11:55:55 -07001359 requestData->instanceStart, config);
Deepak Kodihalli0b459552018-02-06 06:25:12 -06001360 }
1361 else
1362 {
1363 // Read one instance
1364 sensors.resize(1);
1365 std::tie(sensors[0], responseData->numInstances) =
Patrick Venture0b02be92018-08-31 11:55:55 -07001366 dcmi::sensor_info::read(it->second, requestData->entityInstance,
Deepak Kodihalli0b459552018-02-06 06:25:12 -06001367 config);
1368 }
1369 responseData->numRecords = sensors.size();
1370 }
Patrick Williamsa2ad2da2021-10-06 12:21:46 -05001371 catch (const InternalFailure& e)
Deepak Kodihalli0b459552018-02-06 06:25:12 -06001372 {
1373 return IPMI_CC_UNSPECIFIED_ERROR;
1374 }
1375
Deepak Kodihalli0b459552018-02-06 06:25:12 -06001376 size_t payloadSize = sensors.size() * sizeof(dcmi::sensor_info::Response);
1377 if (!sensors.empty())
1378 {
1379 memcpy(responseData + 1, // copy payload right after the response header
Patrick Venture0b02be92018-08-31 11:55:55 -07001380 sensors.data(), payloadSize);
Deepak Kodihalli0b459552018-02-06 06:25:12 -06001381 }
1382 *data_len = sizeof(dcmi::GetSensorInfoResponseHdr) + payloadSize;
1383
1384 return IPMI_CC_OK;
1385}
1386
Chris Austen1810bec2015-10-13 12:12:39 -05001387void register_netfn_dcmi_functions()
1388{
Tom05732372016-09-06 17:21:23 +05301389 // <Get Power Limit>
Ratan Gupta11ddbd22017-08-05 11:59:39 +05301390
Patrick Venture0b02be92018-08-31 11:55:55 -07001391 ipmi_register_callback(NETFUN_GRPEXT, dcmi::Commands::GET_POWER_LIMIT, NULL,
1392 getPowerLimit, PRIVILEGE_USER);
Tom Joseph6f6dd4d2017-07-12 20:07:11 +05301393
Tom Joseph46fa37d2017-07-26 18:11:55 +05301394 // <Set Power Limit>
Ratan Gupta11ddbd22017-08-05 11:59:39 +05301395
Patrick Venture0b02be92018-08-31 11:55:55 -07001396 ipmi_register_callback(NETFUN_GRPEXT, dcmi::Commands::SET_POWER_LIMIT, NULL,
1397 setPowerLimit, PRIVILEGE_OPERATOR);
Tom Joseph46fa37d2017-07-26 18:11:55 +05301398
Tom Joseph6c8d51b2017-07-26 18:18:06 +05301399 // <Activate/Deactivate Power Limit>
Ratan Gupta11ddbd22017-08-05 11:59:39 +05301400
1401 ipmi_register_callback(NETFUN_GRPEXT, dcmi::Commands::APPLY_POWER_LIMIT,
1402 NULL, applyPowerLimit, PRIVILEGE_OPERATOR);
Tom Joseph6c8d51b2017-07-26 18:18:06 +05301403
Tom Joseph6f6dd4d2017-07-12 20:07:11 +05301404 // <Get Asset Tag>
Ratan Gupta11ddbd22017-08-05 11:59:39 +05301405
Patrick Venture0b02be92018-08-31 11:55:55 -07001406 ipmi_register_callback(NETFUN_GRPEXT, dcmi::Commands::GET_ASSET_TAG, NULL,
1407 getAssetTag, PRIVILEGE_USER);
Tom Joseph545dd232017-07-12 20:20:49 +05301408
1409 // <Set Asset Tag>
Ratan Gupta11ddbd22017-08-05 11:59:39 +05301410
Patrick Venture0b02be92018-08-31 11:55:55 -07001411 ipmi_register_callback(NETFUN_GRPEXT, dcmi::Commands::SET_ASSET_TAG, NULL,
1412 setAssetTag, PRIVILEGE_OPERATOR);
Vladislav Vovchenko8f7a6f62017-08-17 00:31:14 +03001413
Gunnar Mills8991dd62017-10-25 17:11:29 -05001414 // <Get Management Controller Identifier String>
Vladislav Vovchenko8f7a6f62017-08-17 00:31:14 +03001415
1416 ipmi_register_callback(NETFUN_GRPEXT, dcmi::Commands::GET_MGMNT_CTRL_ID_STR,
Patrick Venture0b02be92018-08-31 11:55:55 -07001417 NULL, getMgmntCtrlIdStr, PRIVILEGE_USER);
Vladislav Vovchenko8f7a6f62017-08-17 00:31:14 +03001418
1419 // <Set Management Controller Identifier String>
Vladislav Vovchenko8f7a6f62017-08-17 00:31:14 +03001420 ipmi_register_callback(NETFUN_GRPEXT, dcmi::Commands::SET_MGMNT_CTRL_ID_STR,
Patrick Venture0b02be92018-08-31 11:55:55 -07001421 NULL, setMgmntCtrlIdStr, PRIVILEGE_ADMIN);
Vladislav Vovchenko8f7a6f62017-08-17 00:31:14 +03001422
Dhruvaraj Subhashchandrane29be412018-01-16 05:11:56 -06001423 // <Get DCMI capabilities>
1424 ipmi_register_callback(NETFUN_GRPEXT, dcmi::Commands::GET_CAPABILITIES,
Patrick Venture0b02be92018-08-31 11:55:55 -07001425 NULL, getDCMICapabilities, PRIVILEGE_USER);
Deepak Kodihalliee717d72018-01-24 04:53:09 -06001426
1427 // <Get Temperature Readings>
1428 ipmi_register_callback(NETFUN_GRPEXT, dcmi::Commands::GET_TEMP_READINGS,
1429 NULL, getTempReadings, PRIVILEGE_USER);
1430
Marri Devender Rao66c5fda2018-01-18 10:48:37 -06001431 // <Get Power Reading>
1432 ipmi_register_callback(NETFUN_GRPEXT, dcmi::Commands::GET_POWER_READING,
1433 NULL, getPowerReading, PRIVILEGE_USER);
Deepak Kodihalli0b459552018-02-06 06:25:12 -06001434
1435 // <Get Sensor Info>
Patrick Venture0b02be92018-08-31 11:55:55 -07001436 ipmi_register_callback(NETFUN_GRPEXT, dcmi::Commands::GET_SENSOR_INFO, NULL,
1437 getSensorInfo, PRIVILEGE_USER);
Deepak Kodihalli0b459552018-02-06 06:25:12 -06001438
Nagaraju Goruganti22be97b2018-02-07 01:19:59 -06001439 // <Get DCMI Configuration Parameters>
Patrick Venture0b02be92018-08-31 11:55:55 -07001440 ipmi_register_callback(NETFUN_GRPEXT, dcmi::Commands::GET_CONF_PARAMS, NULL,
1441 getDCMIConfParams, PRIVILEGE_USER);
Nagaraju Goruganti22be97b2018-02-07 01:19:59 -06001442
1443 // <Set DCMI Configuration Parameters>
Patrick Venture0b02be92018-08-31 11:55:55 -07001444 ipmi_register_callback(NETFUN_GRPEXT, dcmi::Commands::SET_CONF_PARAMS, NULL,
1445 setDCMIConfParams, PRIVILEGE_ADMIN);
Nagaraju Goruganti22be97b2018-02-07 01:19:59 -06001446
Chris Austen1810bec2015-10-13 12:12:39 -05001447 return;
1448}
Tom05732372016-09-06 17:21:23 +05301449// 956379