blob: f06441bb5984d7912656e5b6f0f0eb52ca964c24 [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>
Thang Tran55cbf552023-01-31 14:43:02 +070018#include <xyz/openbmc_project/Network/EthernetInterface/server.hpp>
Patrick Venture0b02be92018-08-31 11:55:55 -070019
Tom Josephbe5eaa12017-07-12 19:54:44 +053020using namespace phosphor::logging;
Thang Tran55cbf552023-01-31 14:43:02 +070021using sdbusplus::xyz::openbmc_project::Network::server::EthernetInterface;
22
Tom Josephbe5eaa12017-07-12 19:54:44 +053023using InternalFailure =
Patrick Venture0b02be92018-08-31 11:55:55 -070024 sdbusplus::xyz::openbmc_project::Common::Error::InternalFailure;
Chris Austen1810bec2015-10-13 12:12:39 -050025
26void register_netfn_dcmi_functions() __attribute__((constructor));
27
Patrick Venture0b02be92018-08-31 11:55:55 -070028constexpr auto PCAP_PATH = "/xyz/openbmc_project/control/host0/power_cap";
Andrew Geissler50c0c8f2017-07-11 16:18:51 -050029constexpr auto PCAP_INTERFACE = "xyz.openbmc_project.Control.Power.Cap";
30
31constexpr auto POWER_CAP_PROP = "PowerCap";
32constexpr auto POWER_CAP_ENABLE_PROP = "PowerCapEnable";
33
Dhruvaraj Subhashchandrane29be412018-01-16 05:11:56 -060034constexpr auto DCMI_PARAMETER_REVISION = 2;
35constexpr auto DCMI_SPEC_MAJOR_VERSION = 1;
36constexpr auto DCMI_SPEC_MINOR_VERSION = 5;
Nagaraju Goruganti22be97b2018-02-07 01:19:59 -060037constexpr auto DCMI_CONFIG_PARAMETER_REVISION = 1;
38constexpr auto DCMI_RAND_BACK_OFF_MASK = 0x80;
39constexpr auto DCMI_OPTION_60_43_MASK = 0x02;
40constexpr auto DCMI_OPTION_12_MASK = 0x01;
41constexpr auto DCMI_ACTIVATE_DHCP_MASK = 0x01;
42constexpr auto DCMI_ACTIVATE_DHCP_REPLY = 0x00;
William A. Kennington III5d06cc62019-04-25 02:10:55 -070043constexpr auto DCMI_SET_CONF_PARAM_REQ_PACKET_MAX_SIZE = 0x04;
44constexpr auto DCMI_SET_CONF_PARAM_REQ_PACKET_MIN_SIZE = 0x03;
Patrick Venture0b02be92018-08-31 11:55:55 -070045constexpr auto DHCP_TIMING1 = 0x04; // 4 sec
46constexpr auto DHCP_TIMING2_UPPER = 0x00; // 2 min
Nagaraju Goruganti22be97b2018-02-07 01:19:59 -060047constexpr auto DHCP_TIMING2_LOWER = 0x78;
Patrick Venture0b02be92018-08-31 11:55:55 -070048constexpr auto DHCP_TIMING3_UPPER = 0x00; // 64 sec
Nagaraju Goruganti22be97b2018-02-07 01:19:59 -060049constexpr auto DHCP_TIMING3_LOWER = 0x40;
50// When DHCP Option 12 is enabled the string "SendHostName=true" will be
51// added into n/w configuration file and the parameter
52// SendHostNameEnabled will set to true.
53constexpr auto DHCP_OPT12_ENABLED = "SendHostNameEnabled";
54
Marri Devender Rao66c5fda2018-01-18 10:48:37 -060055constexpr auto SENSOR_VALUE_INTF = "xyz.openbmc_project.Sensor.Value";
56constexpr auto SENSOR_VALUE_PROP = "Value";
Marri Devender Rao66c5fda2018-01-18 10:48:37 -060057
Andrew Geissler50c0c8f2017-07-11 16:18:51 -050058using namespace phosphor::logging;
59
Tom Josephb9d86f42017-07-26 18:03:47 +053060namespace dcmi
61{
62
Deepak Kodihalli0b459552018-02-06 06:25:12 -060063// Refer Table 6-14, DCMI Entity ID Extension, DCMI v1.5 spec
Patrick Venture0b02be92018-08-31 11:55:55 -070064static const std::map<uint8_t, std::string> entityIdToName{
65 {0x40, "inlet"}, {0x37, "inlet"}, {0x41, "cpu"},
66 {0x03, "cpu"}, {0x42, "baseboard"}, {0x07, "baseboard"}};
Deepak Kodihalli0b459552018-02-06 06:25:12 -060067
Kirill Pakhomov2c2af2c2018-11-06 16:06:10 +030068bool isDCMIPowerMgmtSupported()
69{
70 auto data = parseJSONConfig(gDCMICapabilitiesConfig);
71
72 return (gDCMIPowerMgmtSupported == data.value(gDCMIPowerMgmtCapability, 0));
73}
74
Patrick Williams5d82f472022-07-22 19:26:53 -050075uint32_t getPcap(sdbusplus::bus_t& bus)
Andrew Geissler50c0c8f2017-07-11 16:18:51 -050076{
Patrick Venture0b02be92018-08-31 11:55:55 -070077 auto settingService = ipmi::getService(bus, PCAP_INTERFACE, PCAP_PATH);
Andrew Geissler50c0c8f2017-07-11 16:18:51 -050078
Patrick Venture0b02be92018-08-31 11:55:55 -070079 auto method = bus.new_method_call(settingService.c_str(), PCAP_PATH,
80 "org.freedesktop.DBus.Properties", "Get");
Andrew Geissler50c0c8f2017-07-11 16:18:51 -050081
82 method.append(PCAP_INTERFACE, POWER_CAP_PROP);
83 auto reply = bus.call(method);
84
85 if (reply.is_method_error())
86 {
87 log<level::ERR>("Error in getPcap prop");
Tom Josephb9d86f42017-07-26 18:03:47 +053088 elog<InternalFailure>();
Andrew Geissler50c0c8f2017-07-11 16:18:51 -050089 }
Vernon Mauery16b86932019-05-01 08:36:11 -070090 std::variant<uint32_t> pcap;
Andrew Geissler50c0c8f2017-07-11 16:18:51 -050091 reply.read(pcap);
92
Vernon Maueryf442e112019-04-09 11:44:36 -070093 return std::get<uint32_t>(pcap);
Andrew Geissler50c0c8f2017-07-11 16:18:51 -050094}
95
Patrick Williams5d82f472022-07-22 19:26:53 -050096bool getPcapEnabled(sdbusplus::bus_t& bus)
Andrew Geissler50c0c8f2017-07-11 16:18:51 -050097{
Patrick Venture0b02be92018-08-31 11:55:55 -070098 auto settingService = ipmi::getService(bus, PCAP_INTERFACE, PCAP_PATH);
Andrew Geissler50c0c8f2017-07-11 16:18:51 -050099
Patrick Venture0b02be92018-08-31 11:55:55 -0700100 auto method = bus.new_method_call(settingService.c_str(), PCAP_PATH,
101 "org.freedesktop.DBus.Properties", "Get");
Andrew Geissler50c0c8f2017-07-11 16:18:51 -0500102
103 method.append(PCAP_INTERFACE, POWER_CAP_ENABLE_PROP);
104 auto reply = bus.call(method);
105
106 if (reply.is_method_error())
107 {
108 log<level::ERR>("Error in getPcapEnabled prop");
Tom Josephb9d86f42017-07-26 18:03:47 +0530109 elog<InternalFailure>();
Andrew Geissler50c0c8f2017-07-11 16:18:51 -0500110 }
Vernon Mauery16b86932019-05-01 08:36:11 -0700111 std::variant<bool> pcapEnabled;
Andrew Geissler50c0c8f2017-07-11 16:18:51 -0500112 reply.read(pcapEnabled);
113
Vernon Maueryf442e112019-04-09 11:44:36 -0700114 return std::get<bool>(pcapEnabled);
Andrew Geissler50c0c8f2017-07-11 16:18:51 -0500115}
Chris Austen1810bec2015-10-13 12:12:39 -0500116
Patrick Williams5d82f472022-07-22 19:26:53 -0500117void setPcap(sdbusplus::bus_t& bus, const uint32_t powerCap)
Tom Joseph46fa37d2017-07-26 18:11:55 +0530118{
119 auto service = ipmi::getService(bus, PCAP_INTERFACE, PCAP_PATH);
120
Patrick Venture0b02be92018-08-31 11:55:55 -0700121 auto method = bus.new_method_call(service.c_str(), PCAP_PATH,
122 "org.freedesktop.DBus.Properties", "Set");
Tom Joseph46fa37d2017-07-26 18:11:55 +0530123
124 method.append(PCAP_INTERFACE, POWER_CAP_PROP);
Vernon Mauery16b86932019-05-01 08:36:11 -0700125 method.append(std::variant<uint32_t>(powerCap));
Tom Joseph46fa37d2017-07-26 18:11:55 +0530126
127 auto reply = bus.call(method);
128
129 if (reply.is_method_error())
130 {
131 log<level::ERR>("Error in setPcap property");
132 elog<InternalFailure>();
133 }
134}
135
Patrick Williams5d82f472022-07-22 19:26:53 -0500136void setPcapEnable(sdbusplus::bus_t& bus, bool enabled)
Tom Joseph6c8d51b2017-07-26 18:18:06 +0530137{
138 auto service = ipmi::getService(bus, PCAP_INTERFACE, PCAP_PATH);
139
Patrick Venture0b02be92018-08-31 11:55:55 -0700140 auto method = bus.new_method_call(service.c_str(), PCAP_PATH,
141 "org.freedesktop.DBus.Properties", "Set");
Tom Joseph6c8d51b2017-07-26 18:18:06 +0530142
143 method.append(PCAP_INTERFACE, POWER_CAP_ENABLE_PROP);
Vernon Mauery16b86932019-05-01 08:36:11 -0700144 method.append(std::variant<bool>(enabled));
Tom Joseph6c8d51b2017-07-26 18:18:06 +0530145
146 auto reply = bus.call(method);
147
148 if (reply.is_method_error())
149 {
150 log<level::ERR>("Error in setPcapEnabled property");
151 elog<InternalFailure>();
152 }
153}
154
Tom Josephbe5eaa12017-07-12 19:54:44 +0530155void readAssetTagObjectTree(dcmi::assettag::ObjectTree& objectTree)
156{
157 static constexpr auto mapperBusName = "xyz.openbmc_project.ObjectMapper";
158 static constexpr auto mapperObjPath = "/xyz/openbmc_project/object_mapper";
159 static constexpr auto mapperIface = "xyz.openbmc_project.ObjectMapper";
160 static constexpr auto inventoryRoot = "/xyz/openbmc_project/inventory/";
161
Patrick Williams5d82f472022-07-22 19:26:53 -0500162 sdbusplus::bus_t bus{ipmid_get_sd_bus_connection()};
Tom Josephbe5eaa12017-07-12 19:54:44 +0530163 auto depth = 0;
164
Patrick Venture0b02be92018-08-31 11:55:55 -0700165 auto mapperCall = bus.new_method_call(mapperBusName, mapperObjPath,
166 mapperIface, "GetSubTree");
Tom Josephbe5eaa12017-07-12 19:54:44 +0530167
168 mapperCall.append(inventoryRoot);
169 mapperCall.append(depth);
170 mapperCall.append(std::vector<std::string>({dcmi::assetTagIntf}));
171
172 auto mapperReply = bus.call(mapperCall);
173 if (mapperReply.is_method_error())
174 {
175 log<level::ERR>("Error in mapper call");
176 elog<InternalFailure>();
177 }
178
179 mapperReply.read(objectTree);
180
181 if (objectTree.empty())
182 {
183 log<level::ERR>("AssetTag property is not populated");
184 elog<InternalFailure>();
185 }
186}
187
188std::string readAssetTag()
189{
Patrick Williams5d82f472022-07-22 19:26:53 -0500190 sdbusplus::bus_t bus{ipmid_get_sd_bus_connection()};
Tom Josephbe5eaa12017-07-12 19:54:44 +0530191 dcmi::assettag::ObjectTree objectTree;
192
193 // Read the object tree with the inventory root to figure out the object
194 // that has implemented the Asset tag interface.
195 readAssetTagObjectTree(objectTree);
196
197 auto method = bus.new_method_call(
Patrick Venture0b02be92018-08-31 11:55:55 -0700198 (objectTree.begin()->second.begin()->first).c_str(),
199 (objectTree.begin()->first).c_str(), dcmi::propIntf, "Get");
Tom Josephbe5eaa12017-07-12 19:54:44 +0530200 method.append(dcmi::assetTagIntf);
201 method.append(dcmi::assetTagProp);
202
203 auto reply = bus.call(method);
204 if (reply.is_method_error())
205 {
206 log<level::ERR>("Error in reading asset tag");
207 elog<InternalFailure>();
208 }
209
Vernon Mauery16b86932019-05-01 08:36:11 -0700210 std::variant<std::string> assetTag;
Tom Josephbe5eaa12017-07-12 19:54:44 +0530211 reply.read(assetTag);
212
Vernon Maueryf442e112019-04-09 11:44:36 -0700213 return std::get<std::string>(assetTag);
Tom Josephbe5eaa12017-07-12 19:54:44 +0530214}
215
Tom Josephbe5b9892017-07-15 00:55:23 +0530216void writeAssetTag(const std::string& assetTag)
217{
Patrick Williams5d82f472022-07-22 19:26:53 -0500218 sdbusplus::bus_t bus{ipmid_get_sd_bus_connection()};
Tom Josephbe5b9892017-07-15 00:55:23 +0530219 dcmi::assettag::ObjectTree objectTree;
220
221 // Read the object tree with the inventory root to figure out the object
222 // that has implemented the Asset tag interface.
223 readAssetTagObjectTree(objectTree);
224
225 auto method = bus.new_method_call(
Patrick Venture0b02be92018-08-31 11:55:55 -0700226 (objectTree.begin()->second.begin()->first).c_str(),
227 (objectTree.begin()->first).c_str(), dcmi::propIntf, "Set");
Tom Josephbe5b9892017-07-15 00:55:23 +0530228 method.append(dcmi::assetTagIntf);
229 method.append(dcmi::assetTagProp);
Vernon Mauery16b86932019-05-01 08:36:11 -0700230 method.append(std::variant<std::string>(assetTag));
Tom Josephbe5b9892017-07-15 00:55:23 +0530231
232 auto reply = bus.call(method);
233 if (reply.is_method_error())
234 {
235 log<level::ERR>("Error in writing asset tag");
236 elog<InternalFailure>();
237 }
238}
239
Vladislav Vovchenko8f7a6f62017-08-17 00:31:14 +0300240std::string getHostName(void)
241{
Patrick Williams5d82f472022-07-22 19:26:53 -0500242 sdbusplus::bus_t bus{ipmid_get_sd_bus_connection()};
Vladislav Vovchenko8f7a6f62017-08-17 00:31:14 +0300243
244 auto service = ipmi::getService(bus, networkConfigIntf, networkConfigObj);
Patrick Venture0b02be92018-08-31 11:55:55 -0700245 auto value = ipmi::getDbusProperty(bus, service, networkConfigObj,
246 networkConfigIntf, hostNameProp);
Vladislav Vovchenko8f7a6f62017-08-17 00:31:14 +0300247
Vernon Maueryf442e112019-04-09 11:44:36 -0700248 return std::get<std::string>(value);
Vladislav Vovchenko8f7a6f62017-08-17 00:31:14 +0300249}
250
Thang Tran55cbf552023-01-31 14:43:02 +0700251EthernetInterface::DHCPConf getDHCPEnabled()
Nagaraju Goruganti22be97b2018-02-07 01:19:59 -0600252{
Patrick Williams5d82f472022-07-22 19:26:53 -0500253 sdbusplus::bus_t bus{ipmid_get_sd_bus_connection()};
Nagaraju Goruganti22be97b2018-02-07 01:19:59 -0600254
Johnathan Mantey74a21022018-12-13 13:17:56 -0800255 auto ethdevice = ipmi::getChannelName(ethernetDefaultChannelNum);
Patrick Venture0b02be92018-08-31 11:55:55 -0700256 auto ethernetObj =
257 ipmi::getDbusObject(bus, ethernetIntf, networkRoot, ethdevice);
Nagaraju Goruganti22be97b2018-02-07 01:19:59 -0600258 auto service = ipmi::getService(bus, ethernetIntf, ethernetObj.first);
Patrick Venture0b02be92018-08-31 11:55:55 -0700259 auto value = ipmi::getDbusProperty(bus, service, ethernetObj.first,
260 ethernetIntf, "DHCPEnabled");
Nagaraju Goruganti22be97b2018-02-07 01:19:59 -0600261
Thang Tran55cbf552023-01-31 14:43:02 +0700262 return EthernetInterface::convertDHCPConfFromString(
263 std::get<std::string>(value));
Nagaraju Goruganti22be97b2018-02-07 01:19:59 -0600264}
265
266bool getDHCPOption(std::string prop)
267{
Patrick Williams5d82f472022-07-22 19:26:53 -0500268 sdbusplus::bus_t bus{ipmid_get_sd_bus_connection()};
Nagaraju Goruganti22be97b2018-02-07 01:19:59 -0600269
270 auto service = ipmi::getService(bus, dhcpIntf, dhcpObj);
271 auto value = ipmi::getDbusProperty(bus, service, dhcpObj, dhcpIntf, prop);
272
Vernon Maueryf442e112019-04-09 11:44:36 -0700273 return std::get<bool>(value);
Nagaraju Goruganti22be97b2018-02-07 01:19:59 -0600274}
275
Nagaraju Goruganti22be97b2018-02-07 01:19:59 -0600276void setDHCPOption(std::string prop, bool value)
277{
Patrick Williams5d82f472022-07-22 19:26:53 -0500278 sdbusplus::bus_t bus{ipmid_get_sd_bus_connection()};
Nagaraju Goruganti22be97b2018-02-07 01:19:59 -0600279
280 auto service = ipmi::getService(bus, dhcpIntf, dhcpObj);
281 ipmi::setDbusProperty(bus, service, dhcpObj, dhcpIntf, prop, value);
282}
283
Kirill Pakhomova2573622018-11-02 19:00:18 +0300284Json parseJSONConfig(const std::string& configFile)
Deepak Kodihalli0b459552018-02-06 06:25:12 -0600285{
286 std::ifstream jsonFile(configFile);
287 if (!jsonFile.is_open())
288 {
289 log<level::ERR>("Temperature readings JSON file not found");
290 elog<InternalFailure>();
291 }
292
293 auto data = Json::parse(jsonFile, nullptr, false);
294 if (data.is_discarded())
295 {
296 log<level::ERR>("Temperature readings JSON parser failure");
297 elog<InternalFailure>();
298 }
299
300 return data;
301}
302
Tom Josephbe5eaa12017-07-12 19:54:44 +0530303} // namespace dcmi
Chris Austen1810bec2015-10-13 12:12:39 -0500304
Willy Tu11d68892022-01-20 10:37:34 -0800305ipmi_ret_t getPowerLimit(ipmi_netfn_t, ipmi_cmd_t, ipmi_request_t,
306 ipmi_response_t response, ipmi_data_len_t data_len,
307 ipmi_context_t)
Tom Josephb9d86f42017-07-26 18:03:47 +0530308{
Kirill Pakhomov2c2af2c2018-11-06 16:06:10 +0300309 if (!dcmi::isDCMIPowerMgmtSupported())
310 {
311 *data_len = 0;
312 log<level::ERR>("DCMI Power management is unsupported!");
313 return IPMI_CC_INVALID;
314 }
315
Tom Josephb9d86f42017-07-26 18:03:47 +0530316 std::vector<uint8_t> outPayload(sizeof(dcmi::GetPowerLimitResponse));
Patrick Venture0b02be92018-08-31 11:55:55 -0700317 auto responseData =
318 reinterpret_cast<dcmi::GetPowerLimitResponse*>(outPayload.data());
Tom Josephb9d86f42017-07-26 18:03:47 +0530319
Patrick Williams5d82f472022-07-22 19:26:53 -0500320 sdbusplus::bus_t sdbus{ipmid_get_sd_bus_connection()};
Tom Josephb9d86f42017-07-26 18:03:47 +0530321 uint32_t pcapValue = 0;
322 bool pcapEnable = false;
323
324 try
325 {
326 pcapValue = dcmi::getPcap(sdbus);
327 pcapEnable = dcmi::getPcapEnabled(sdbus);
328 }
Patrick Williamsa2ad2da2021-10-06 12:21:46 -0500329 catch (const InternalFailure& e)
Tom Josephb9d86f42017-07-26 18:03:47 +0530330 {
331 *data_len = 0;
332 return IPMI_CC_UNSPECIFIED_ERROR;
333 }
334
Tom Josephb9d86f42017-07-26 18:03:47 +0530335 /*
336 * Exception action if power limit is exceeded and cannot be controlled
337 * with the correction time limit is hardcoded to Hard Power Off system
338 * and log event to SEL.
339 */
340 constexpr auto exception = 0x01;
341 responseData->exceptionAction = exception;
342
343 responseData->powerLimit = static_cast<uint16_t>(pcapValue);
344
345 /*
346 * Correction time limit and Statistics sampling period is currently not
347 * populated.
348 */
349
350 *data_len = outPayload.size();
351 memcpy(response, outPayload.data(), *data_len);
352
353 if (pcapEnable)
354 {
355 return IPMI_CC_OK;
356 }
357 else
358 {
359 return IPMI_DCMI_CC_NO_ACTIVE_POWER_LIMIT;
360 }
361}
362
Willy Tu11d68892022-01-20 10:37:34 -0800363ipmi_ret_t setPowerLimit(ipmi_netfn_t, ipmi_cmd_t, ipmi_request_t request,
364 ipmi_response_t, ipmi_data_len_t data_len,
365 ipmi_context_t)
Tom Joseph46fa37d2017-07-26 18:11:55 +0530366{
Kirill Pakhomov2c2af2c2018-11-06 16:06:10 +0300367 if (!dcmi::isDCMIPowerMgmtSupported())
368 {
369 *data_len = 0;
370 log<level::ERR>("DCMI Power management is unsupported!");
371 return IPMI_CC_INVALID;
372 }
373
Patrick Venture0b02be92018-08-31 11:55:55 -0700374 auto requestData =
375 reinterpret_cast<const dcmi::SetPowerLimitRequest*>(request);
Tom Joseph46fa37d2017-07-26 18:11:55 +0530376
Patrick Williams5d82f472022-07-22 19:26:53 -0500377 sdbusplus::bus_t sdbus{ipmid_get_sd_bus_connection()};
Tom Joseph46fa37d2017-07-26 18:11:55 +0530378
379 // Only process the power limit requested in watts.
380 try
381 {
382 dcmi::setPcap(sdbus, requestData->powerLimit);
383 }
Patrick Williamsa2ad2da2021-10-06 12:21:46 -0500384 catch (const InternalFailure& e)
Tom Joseph46fa37d2017-07-26 18:11:55 +0530385 {
386 *data_len = 0;
387 return IPMI_CC_UNSPECIFIED_ERROR;
388 }
389
390 log<level::INFO>("Set Power Cap",
391 entry("POWERCAP=%u", requestData->powerLimit));
392
William A. Kennington III5d06cc62019-04-25 02:10:55 -0700393 *data_len = 0;
Tom Joseph46fa37d2017-07-26 18:11:55 +0530394 return IPMI_CC_OK;
395}
396
Willy Tu11d68892022-01-20 10:37:34 -0800397ipmi_ret_t applyPowerLimit(ipmi_netfn_t, ipmi_cmd_t, ipmi_request_t request,
398 ipmi_response_t, ipmi_data_len_t data_len,
399 ipmi_context_t)
Tom Joseph6c8d51b2017-07-26 18:18:06 +0530400{
Kirill Pakhomov2c2af2c2018-11-06 16:06:10 +0300401 if (!dcmi::isDCMIPowerMgmtSupported())
402 {
403 *data_len = 0;
404 log<level::ERR>("DCMI Power management is unsupported!");
405 return IPMI_CC_INVALID;
406 }
407
Patrick Venture0b02be92018-08-31 11:55:55 -0700408 auto requestData =
409 reinterpret_cast<const dcmi::ApplyPowerLimitRequest*>(request);
Tom Joseph6c8d51b2017-07-26 18:18:06 +0530410
Patrick Williams5d82f472022-07-22 19:26:53 -0500411 sdbusplus::bus_t sdbus{ipmid_get_sd_bus_connection()};
Tom Joseph6c8d51b2017-07-26 18:18:06 +0530412
413 try
414 {
415 dcmi::setPcapEnable(sdbus,
416 static_cast<bool>(requestData->powerLimitAction));
417 }
Patrick Williamsa2ad2da2021-10-06 12:21:46 -0500418 catch (const InternalFailure& e)
Tom Joseph6c8d51b2017-07-26 18:18:06 +0530419 {
420 *data_len = 0;
421 return IPMI_CC_UNSPECIFIED_ERROR;
422 }
423
424 log<level::INFO>("Set Power Cap Enable",
425 entry("POWERCAPENABLE=%u", requestData->powerLimitAction));
426
William A. Kennington III5d06cc62019-04-25 02:10:55 -0700427 *data_len = 0;
Tom Joseph6c8d51b2017-07-26 18:18:06 +0530428 return IPMI_CC_OK;
429}
430
Willy Tu11d68892022-01-20 10:37:34 -0800431ipmi_ret_t getAssetTag(ipmi_netfn_t, ipmi_cmd_t, ipmi_request_t request,
432 ipmi_response_t response, ipmi_data_len_t data_len,
433 ipmi_context_t)
Tom Joseph6f6dd4d2017-07-12 20:07:11 +0530434{
Patrick Venture0b02be92018-08-31 11:55:55 -0700435 auto requestData =
436 reinterpret_cast<const dcmi::GetAssetTagRequest*>(request);
Tom Joseph6f6dd4d2017-07-12 20:07:11 +0530437 std::vector<uint8_t> outPayload(sizeof(dcmi::GetAssetTagResponse));
Patrick Venture0b02be92018-08-31 11:55:55 -0700438 auto responseData =
439 reinterpret_cast<dcmi::GetAssetTagResponse*>(outPayload.data());
Tom Joseph6f6dd4d2017-07-12 20:07:11 +0530440
Tom Joseph6f6dd4d2017-07-12 20:07:11 +0530441 // Verify offset to read and number of bytes to read are not exceeding the
442 // range.
443 if ((requestData->offset > dcmi::assetTagMaxOffset) ||
444 (requestData->bytes > dcmi::maxBytes) ||
445 ((requestData->offset + requestData->bytes) > dcmi::assetTagMaxSize))
446 {
447 *data_len = 0;
448 return IPMI_CC_PARM_OUT_OF_RANGE;
449 }
450
451 std::string assetTag;
452
453 try
454 {
455 assetTag = dcmi::readAssetTag();
456 }
Patrick Williamsa2ad2da2021-10-06 12:21:46 -0500457 catch (const InternalFailure& e)
Tom Joseph6f6dd4d2017-07-12 20:07:11 +0530458 {
459 *data_len = 0;
460 return IPMI_CC_UNSPECIFIED_ERROR;
461 }
462
Tom Joseph6f6dd4d2017-07-12 20:07:11 +0530463 // Return if the asset tag is not populated.
464 if (!assetTag.size())
465 {
466 responseData->tagLength = 0;
467 memcpy(response, outPayload.data(), outPayload.size());
468 *data_len = outPayload.size();
469 return IPMI_CC_OK;
470 }
471
472 // If the asset tag is longer than 63 bytes, restrict it to 63 bytes to suit
473 // Get Asset Tag command.
474 if (assetTag.size() > dcmi::assetTagMaxSize)
475 {
476 assetTag.resize(dcmi::assetTagMaxSize);
477 }
478
479 // If the requested offset is beyond the asset tag size.
480 if (requestData->offset >= assetTag.size())
481 {
482 *data_len = 0;
483 return IPMI_CC_PARM_OUT_OF_RANGE;
484 }
485
486 auto returnData = assetTag.substr(requestData->offset, requestData->bytes);
487
488 responseData->tagLength = assetTag.size();
489
490 memcpy(response, outPayload.data(), outPayload.size());
491 memcpy(static_cast<uint8_t*>(response) + outPayload.size(),
492 returnData.data(), returnData.size());
493 *data_len = outPayload.size() + returnData.size();
494
495 return IPMI_CC_OK;
496}
497
Willy Tu11d68892022-01-20 10:37:34 -0800498ipmi_ret_t setAssetTag(ipmi_netfn_t, ipmi_cmd_t, ipmi_request_t request,
499 ipmi_response_t response, ipmi_data_len_t data_len,
500 ipmi_context_t)
Tom Joseph545dd232017-07-12 20:20:49 +0530501{
Patrick Venture0b02be92018-08-31 11:55:55 -0700502 auto requestData =
503 reinterpret_cast<const dcmi::SetAssetTagRequest*>(request);
Tom Joseph545dd232017-07-12 20:20:49 +0530504 std::vector<uint8_t> outPayload(sizeof(dcmi::SetAssetTagResponse));
Patrick Venture0b02be92018-08-31 11:55:55 -0700505 auto responseData =
506 reinterpret_cast<dcmi::SetAssetTagResponse*>(outPayload.data());
Tom Joseph545dd232017-07-12 20:20:49 +0530507
Tom Joseph545dd232017-07-12 20:20:49 +0530508 // Verify offset to read and number of bytes to read are not exceeding the
509 // range.
510 if ((requestData->offset > dcmi::assetTagMaxOffset) ||
511 (requestData->bytes > dcmi::maxBytes) ||
512 ((requestData->offset + requestData->bytes) > dcmi::assetTagMaxSize))
513 {
514 *data_len = 0;
515 return IPMI_CC_PARM_OUT_OF_RANGE;
516 }
517
518 std::string assetTag;
519
520 try
521 {
522 assetTag = dcmi::readAssetTag();
523
524 if (requestData->offset > assetTag.size())
525 {
526 *data_len = 0;
527 return IPMI_CC_PARM_OUT_OF_RANGE;
528 }
529
530 assetTag.replace(requestData->offset,
531 assetTag.size() - requestData->offset,
532 static_cast<const char*>(request) +
Patrick Venture0b02be92018-08-31 11:55:55 -0700533 sizeof(dcmi::SetAssetTagRequest),
Tom Joseph545dd232017-07-12 20:20:49 +0530534 requestData->bytes);
535
536 dcmi::writeAssetTag(assetTag);
537
Tom Joseph545dd232017-07-12 20:20:49 +0530538 responseData->tagLength = assetTag.size();
539 memcpy(response, outPayload.data(), outPayload.size());
540 *data_len = outPayload.size();
541
542 return IPMI_CC_OK;
543 }
Patrick Williamsa2ad2da2021-10-06 12:21:46 -0500544 catch (const InternalFailure& e)
Tom Joseph545dd232017-07-12 20:20:49 +0530545 {
546 *data_len = 0;
547 return IPMI_CC_UNSPECIFIED_ERROR;
548 }
549}
550
Willy Tu11d68892022-01-20 10:37:34 -0800551ipmi_ret_t getMgmntCtrlIdStr(ipmi_netfn_t, ipmi_cmd_t, ipmi_request_t request,
552 ipmi_response_t response, ipmi_data_len_t data_len,
553 ipmi_context_t)
Vladislav Vovchenko8f7a6f62017-08-17 00:31:14 +0300554{
Patrick Venture0b02be92018-08-31 11:55:55 -0700555 auto requestData =
556 reinterpret_cast<const dcmi::GetMgmntCtrlIdStrRequest*>(request);
557 auto responseData =
558 reinterpret_cast<dcmi::GetMgmntCtrlIdStrResponse*>(response);
Vladislav Vovchenko8f7a6f62017-08-17 00:31:14 +0300559 std::string hostName;
560
561 *data_len = 0;
562
William A. Kennington III5d06cc62019-04-25 02:10:55 -0700563 if (requestData->bytes > dcmi::maxBytes ||
Vladislav Vovchenko8f7a6f62017-08-17 00:31:14 +0300564 requestData->offset + requestData->bytes > dcmi::maxCtrlIdStrLen)
565 {
566 return IPMI_CC_INVALID_FIELD_REQUEST;
567 }
568
569 try
570 {
571 hostName = dcmi::getHostName();
572 }
Patrick Williamsa2ad2da2021-10-06 12:21:46 -0500573 catch (const InternalFailure& e)
Vladislav Vovchenko8f7a6f62017-08-17 00:31:14 +0300574 {
575 return IPMI_CC_UNSPECIFIED_ERROR;
576 }
577
578 if (requestData->offset > hostName.length())
579 {
580 return IPMI_CC_PARM_OUT_OF_RANGE;
581 }
582 auto responseStr = hostName.substr(requestData->offset, requestData->bytes);
583 auto responseStrLen = std::min(static_cast<std::size_t>(requestData->bytes),
Patrick Venture0b02be92018-08-31 11:55:55 -0700584 responseStr.length() + 1);
Vladislav Vovchenko8f7a6f62017-08-17 00:31:14 +0300585 responseData->strLen = hostName.length();
586 std::copy(begin(responseStr), end(responseStr), responseData->data);
587
588 *data_len = sizeof(*responseData) + responseStrLen;
589 return IPMI_CC_OK;
590}
591
Willy Tu11d68892022-01-20 10:37:34 -0800592ipmi_ret_t setMgmntCtrlIdStr(ipmi_netfn_t, ipmi_cmd_t, ipmi_request_t request,
593 ipmi_response_t response, ipmi_data_len_t data_len,
594 ipmi_context_t)
Vladislav Vovchenko8f7a6f62017-08-17 00:31:14 +0300595{
596 static std::array<char, dcmi::maxCtrlIdStrLen + 1> newCtrlIdStr;
597
Patrick Venture0b02be92018-08-31 11:55:55 -0700598 auto requestData =
599 reinterpret_cast<const dcmi::SetMgmntCtrlIdStrRequest*>(request);
600 auto responseData =
601 reinterpret_cast<dcmi::SetMgmntCtrlIdStrResponse*>(response);
Vladislav Vovchenko8f7a6f62017-08-17 00:31:14 +0300602
603 *data_len = 0;
604
William A. Kennington III5d06cc62019-04-25 02:10:55 -0700605 if (requestData->bytes > dcmi::maxBytes ||
Vladislav Vovchenko8f7a6f62017-08-17 00:31:14 +0300606 requestData->offset + requestData->bytes > dcmi::maxCtrlIdStrLen + 1 ||
Patrick Venture0b02be92018-08-31 11:55:55 -0700607 (requestData->offset + requestData->bytes ==
608 dcmi::maxCtrlIdStrLen + 1 &&
609 requestData->data[requestData->bytes - 1] != '\0'))
Vladislav Vovchenko8f7a6f62017-08-17 00:31:14 +0300610 {
611 return IPMI_CC_INVALID_FIELD_REQUEST;
612 }
613
614 try
615 {
616 /* if there is no old value and offset is not 0 */
617 if (newCtrlIdStr[0] == '\0' && requestData->offset != 0)
618 {
619 /* read old ctrlIdStr */
620 auto hostName = dcmi::getHostName();
621 hostName.resize(dcmi::maxCtrlIdStrLen);
622 std::copy(begin(hostName), end(hostName), begin(newCtrlIdStr));
623 newCtrlIdStr[hostName.length()] = '\0';
624 }
625
626 /* replace part of string and mark byte after the last as \0 */
Patrick Venture0b02be92018-08-31 11:55:55 -0700627 auto restStrIter =
628 std::copy_n(requestData->data, requestData->bytes,
629 begin(newCtrlIdStr) + requestData->offset);
Vladislav Vovchenko8f7a6f62017-08-17 00:31:14 +0300630 /* if the last written byte is not 64th - add '\0' */
631 if (requestData->offset + requestData->bytes <= dcmi::maxCtrlIdStrLen)
632 {
633 *restStrIter = '\0';
634 }
635
636 /* if input data contains '\0' whole string is sent - update hostname */
637 auto it = std::find(requestData->data,
Patrick Venture0b02be92018-08-31 11:55:55 -0700638 requestData->data + requestData->bytes, '\0');
Vladislav Vovchenko8f7a6f62017-08-17 00:31:14 +0300639 if (it != requestData->data + requestData->bytes)
640 {
Patrick Williams5d82f472022-07-22 19:26:53 -0500641 sdbusplus::bus_t bus{ipmid_get_sd_bus_connection()};
Vladislav Vovchenko8f7a6f62017-08-17 00:31:14 +0300642 ipmi::setDbusProperty(bus, dcmi::networkServiceName,
Patrick Venture0b02be92018-08-31 11:55:55 -0700643 dcmi::networkConfigObj,
644 dcmi::networkConfigIntf, dcmi::hostNameProp,
645 std::string(newCtrlIdStr.data()));
Vladislav Vovchenko8f7a6f62017-08-17 00:31:14 +0300646 }
647 }
Patrick Williamsa2ad2da2021-10-06 12:21:46 -0500648 catch (const InternalFailure& e)
Vladislav Vovchenko8f7a6f62017-08-17 00:31:14 +0300649 {
650 *data_len = 0;
651 return IPMI_CC_UNSPECIFIED_ERROR;
652 }
653
Vladislav Vovchenko8f7a6f62017-08-17 00:31:14 +0300654 responseData->offset = requestData->offset + requestData->bytes;
655 *data_len = sizeof(*responseData);
656 return IPMI_CC_OK;
657}
658
Patrick Venture0b02be92018-08-31 11:55:55 -0700659// List of the capabilities under each parameter
660dcmi::DCMICaps dcmiCaps = {
661 // Supported DCMI Capabilities
662 {dcmi::DCMICapParameters::SUPPORTED_DCMI_CAPS,
663 {3,
664 {{"PowerManagement", 2, 0, 1},
665 {"OOBSecondaryLan", 3, 2, 1},
666 {"SerialTMODE", 3, 1, 1},
667 {"InBandSystemInterfaceChannel", 3, 0, 1}}}},
668 // Mandatory Platform Attributes
669 {dcmi::DCMICapParameters::MANDATORY_PLAT_ATTRIBUTES,
670 {5,
671 {{"SELAutoRollOver", 1, 15, 1},
672 {"FlushEntireSELUponRollOver", 1, 14, 1},
673 {"RecordLevelSELFlushUponRollOver", 1, 13, 1},
674 {"NumberOfSELEntries", 1, 0, 12},
675 {"TempMonitoringSamplingFreq", 5, 0, 8}}}},
676 // Optional Platform Attributes
677 {dcmi::DCMICapParameters::OPTIONAL_PLAT_ATTRIBUTES,
678 {2,
679 {{"PowerMgmtDeviceSlaveAddress", 1, 1, 7},
680 {"BMCChannelNumber", 2, 4, 4},
681 {"DeviceRivision", 2, 0, 4}}}},
682 // Manageability Access Attributes
683 {dcmi::DCMICapParameters::MANAGEABILITY_ACCESS_ATTRIBUTES,
684 {3,
685 {{"MandatoryPrimaryLanOOBSupport", 1, 0, 8},
686 {"OptionalSecondaryLanOOBSupport", 2, 0, 8},
687 {"OptionalSerialOOBMTMODECapability", 3, 0, 8}}}}};
Dhruvaraj Subhashchandrane29be412018-01-16 05:11:56 -0600688
Willy Tu11d68892022-01-20 10:37:34 -0800689ipmi_ret_t getDCMICapabilities(ipmi_netfn_t, ipmi_cmd_t, ipmi_request_t request,
690 ipmi_response_t response,
691 ipmi_data_len_t data_len, ipmi_context_t)
Dhruvaraj Subhashchandrane29be412018-01-16 05:11:56 -0600692{
693
Kirill Pakhomova2573622018-11-02 19:00:18 +0300694 std::ifstream dcmiCapFile(dcmi::gDCMICapabilitiesConfig);
Dhruvaraj Subhashchandrane29be412018-01-16 05:11:56 -0600695 if (!dcmiCapFile.is_open())
696 {
697 log<level::ERR>("DCMI Capabilities file not found");
698 return IPMI_CC_UNSPECIFIED_ERROR;
699 }
700
701 auto data = nlohmann::json::parse(dcmiCapFile, nullptr, false);
702 if (data.is_discarded())
703 {
704 log<level::ERR>("DCMI Capabilities JSON parser failure");
705 return IPMI_CC_UNSPECIFIED_ERROR;
706 }
707
Patrick Venture0b02be92018-08-31 11:55:55 -0700708 auto requestData =
709 reinterpret_cast<const dcmi::GetDCMICapRequest*>(request);
Dhruvaraj Subhashchandrane29be412018-01-16 05:11:56 -0600710
Patrick Venture0b02be92018-08-31 11:55:55 -0700711 // get list of capabilities in a parameter
Dhruvaraj Subhashchandrane29be412018-01-16 05:11:56 -0600712 auto caps =
713 dcmiCaps.find(static_cast<dcmi::DCMICapParameters>(requestData->param));
714 if (caps == dcmiCaps.end())
715 {
716 log<level::ERR>("Invalid input parameter");
717 return IPMI_CC_INVALID_FIELD_REQUEST;
718 }
719
Patrick Venture0b02be92018-08-31 11:55:55 -0700720 auto responseData = reinterpret_cast<dcmi::GetDCMICapResponse*>(response);
Dhruvaraj Subhashchandrane29be412018-01-16 05:11:56 -0600721
Patrick Venture0b02be92018-08-31 11:55:55 -0700722 // For each capabilities in a parameter fill the data from
723 // the json file based on the capability name.
Dhruvaraj Subhashchandrane29be412018-01-16 05:11:56 -0600724 for (auto cap : caps->second.capList)
725 {
Patrick Venture0b02be92018-08-31 11:55:55 -0700726 // If the data is beyond first byte boundary, insert in a
727 // 16bit pattern for example number of SEL entries are represented
728 // in 12bits.
Kirill Pakhomovdb5d9b02018-11-06 19:17:51 +0300729 if ((cap.length + cap.position) > dcmi::gByteBitSize)
Dhruvaraj Subhashchandrane29be412018-01-16 05:11:56 -0600730 {
Kirill Pakhomovdb5d9b02018-11-06 19:17:51 +0300731 uint16_t val = data.value(cap.name.c_str(), 0);
732 // According to DCMI spec v1.5, max number of SEL entries is
733 // 4096, but bit 12b of DCMI capabilities Mandatory Platform
734 // Attributes field is reserved and therefore we can use only
735 // the provided 12 bits with maximum value of 4095.
736 // We're playing safe here by applying the mask
737 // to ensure that provided value will fit into 12 bits.
738 if (cap.length > dcmi::gByteBitSize)
739 {
740 val &= dcmi::gMaxSELEntriesMask;
741 }
Dhruvaraj Subhashchandrane29be412018-01-16 05:11:56 -0600742 val <<= cap.position;
Kirill Pakhomovdb5d9b02018-11-06 19:17:51 +0300743 responseData->data[cap.bytePosition - 1] |=
744 static_cast<uint8_t>(val);
745 responseData->data[cap.bytePosition] |= val >> dcmi::gByteBitSize;
Dhruvaraj Subhashchandrane29be412018-01-16 05:11:56 -0600746 }
747 else
748 {
749 responseData->data[cap.bytePosition - 1] |=
750 data.value(cap.name.c_str(), 0) << cap.position;
751 }
752 }
753
Dhruvaraj Subhashchandrane29be412018-01-16 05:11:56 -0600754 responseData->major = DCMI_SPEC_MAJOR_VERSION;
755 responseData->minor = DCMI_SPEC_MINOR_VERSION;
756 responseData->paramRevision = DCMI_PARAMETER_REVISION;
757 *data_len = sizeof(*responseData) + caps->second.size;
758
759 return IPMI_CC_OK;
760}
761
Deepak Kodihalliee717d72018-01-24 04:53:09 -0600762namespace dcmi
763{
764namespace temp_readings
765{
766
Deepak Kodihallib1e8fba2018-01-24 04:57:10 -0600767Temperature readTemp(const std::string& dbusService,
768 const std::string& dbusPath)
769{
770 // Read the temperature value from d-bus object. Need some conversion.
771 // As per the interface xyz.openbmc_project.Sensor.Value, the temperature
James Feist9cc0ea52018-10-09 10:53:11 -0700772 // is an double and in degrees C. It needs to be scaled by using the
Deepak Kodihallib1e8fba2018-01-24 04:57:10 -0600773 // formula Value * 10^Scale. The ipmi spec has the temperature as a uint8_t,
774 // with a separate single bit for the sign.
775
Patrick Williams5d82f472022-07-22 19:26:53 -0500776 sdbusplus::bus_t bus{ipmid_get_sd_bus_connection()};
Patrick Venture0b02be92018-08-31 11:55:55 -0700777 auto result = ipmi::getAllDbusProperties(
778 bus, dbusService, dbusPath, "xyz.openbmc_project.Sensor.Value");
Vernon Maueryf442e112019-04-09 11:44:36 -0700779 auto temperature =
780 std::visit(ipmi::VariantToDoubleVisitor(), result.at("Value"));
James Feist9cc0ea52018-10-09 10:53:11 -0700781 double absTemp = std::abs(temperature);
Deepak Kodihallib1e8fba2018-01-24 04:57:10 -0600782
James Feist9cc0ea52018-10-09 10:53:11 -0700783 auto findFactor = result.find("Scale");
784 double factor = 0.0;
785 if (findFactor != result.end())
Deepak Kodihallib1e8fba2018-01-24 04:57:10 -0600786 {
Vernon Maueryf442e112019-04-09 11:44:36 -0700787 factor = std::visit(ipmi::VariantToDoubleVisitor(), findFactor->second);
Deepak Kodihallib1e8fba2018-01-24 04:57:10 -0600788 }
James Feist9cc0ea52018-10-09 10:53:11 -0700789 double scale = std::pow(10, factor);
790
791 auto tempDegrees = absTemp * scale;
Deepak Kodihallib1e8fba2018-01-24 04:57:10 -0600792 // Max absolute temp as per ipmi spec is 128.
793 if (tempDegrees > maxTemp)
794 {
795 tempDegrees = maxTemp;
796 }
797
798 return std::make_tuple(static_cast<uint8_t>(tempDegrees),
799 (temperature < 0));
800}
801
Deepak Kodihalliee717d72018-01-24 04:53:09 -0600802std::tuple<Response, NumInstances> read(const std::string& type,
803 uint8_t instance)
804{
Deepak Kodihallib1e8fba2018-01-24 04:57:10 -0600805 Response response{};
Patrick Williams5d82f472022-07-22 19:26:53 -0500806 sdbusplus::bus_t bus{ipmid_get_sd_bus_connection()};
Deepak Kodihallib1e8fba2018-01-24 04:57:10 -0600807
808 if (!instance)
809 {
810 log<level::ERR>("Expected non-zero instance");
811 elog<InternalFailure>();
812 }
813
Kirill Pakhomova2573622018-11-02 19:00:18 +0300814 auto data = parseJSONConfig(gDCMISensorsConfig);
Deepak Kodihallib1e8fba2018-01-24 04:57:10 -0600815 static const std::vector<Json> empty{};
816 std::vector<Json> readings = data.value(type, empty);
817 size_t numInstances = readings.size();
818 for (const auto& j : readings)
819 {
820 uint8_t instanceNum = j.value("instance", 0);
821 // Not the instance we're interested in
822 if (instanceNum != instance)
823 {
824 continue;
825 }
826
827 std::string path = j.value("dbus", "");
828 std::string service;
829 try
830 {
831 service =
Patrick Venture0b02be92018-08-31 11:55:55 -0700832 ipmi::getService(bus, "xyz.openbmc_project.Sensor.Value", path);
Deepak Kodihallib1e8fba2018-01-24 04:57:10 -0600833 }
Patrick Williamsa2ad2da2021-10-06 12:21:46 -0500834 catch (const std::exception& e)
Deepak Kodihallib1e8fba2018-01-24 04:57:10 -0600835 {
836 log<level::DEBUG>(e.what());
837 return std::make_tuple(response, numInstances);
838 }
839
840 response.instance = instance;
841 uint8_t temp{};
842 bool sign{};
843 std::tie(temp, sign) = readTemp(service, path);
844 response.temperature = temp;
845 response.sign = sign;
846
847 // Found the instance we're interested in
848 break;
849 }
850
851 if (numInstances > maxInstances)
852 {
853 numInstances = maxInstances;
854 }
855 return std::make_tuple(response, numInstances);
Deepak Kodihalliee717d72018-01-24 04:53:09 -0600856}
857
858std::tuple<ResponseList, NumInstances> readAll(const std::string& type,
859 uint8_t instanceStart)
860{
Deepak Kodihallib1e8fba2018-01-24 04:57:10 -0600861 ResponseList response{};
Patrick Williams5d82f472022-07-22 19:26:53 -0500862 sdbusplus::bus_t bus{ipmid_get_sd_bus_connection()};
Deepak Kodihallib1e8fba2018-01-24 04:57:10 -0600863
864 size_t numInstances = 0;
Kirill Pakhomova2573622018-11-02 19:00:18 +0300865 auto data = parseJSONConfig(gDCMISensorsConfig);
Deepak Kodihallib1e8fba2018-01-24 04:57:10 -0600866 static const std::vector<Json> empty{};
867 std::vector<Json> readings = data.value(type, empty);
868 numInstances = readings.size();
869 for (const auto& j : readings)
870 {
871 try
872 {
873 // Max of 8 response data sets
874 if (response.size() == maxDataSets)
875 {
876 break;
877 }
878
879 uint8_t instanceNum = j.value("instance", 0);
880 // Not in the instance range we're interested in
881 if (instanceNum < instanceStart)
882 {
883 continue;
884 }
885
886 std::string path = j.value("dbus", "");
887 auto service =
Patrick Venture0b02be92018-08-31 11:55:55 -0700888 ipmi::getService(bus, "xyz.openbmc_project.Sensor.Value", path);
Deepak Kodihallib1e8fba2018-01-24 04:57:10 -0600889
890 Response r{};
891 r.instance = instanceNum;
892 uint8_t temp{};
893 bool sign{};
894 std::tie(temp, sign) = readTemp(service, path);
895 r.temperature = temp;
896 r.sign = sign;
897 response.push_back(r);
898 }
Patrick Williamsa2ad2da2021-10-06 12:21:46 -0500899 catch (const std::exception& e)
Deepak Kodihallib1e8fba2018-01-24 04:57:10 -0600900 {
901 log<level::DEBUG>(e.what());
902 continue;
903 }
904 }
905
906 if (numInstances > maxInstances)
907 {
908 numInstances = maxInstances;
909 }
910 return std::make_tuple(response, numInstances);
Deepak Kodihalliee717d72018-01-24 04:53:09 -0600911}
912
Patrick Venture0b02be92018-08-31 11:55:55 -0700913} // namespace temp_readings
914} // namespace dcmi
Deepak Kodihalliee717d72018-01-24 04:53:09 -0600915
Willy Tu11d68892022-01-20 10:37:34 -0800916ipmi_ret_t getTempReadings(ipmi_netfn_t, ipmi_cmd_t, ipmi_request_t request,
917 ipmi_response_t response, ipmi_data_len_t data_len,
918 ipmi_context_t)
Deepak Kodihalliee717d72018-01-24 04:53:09 -0600919{
Deepak Kodihalliee717d72018-01-24 04:53:09 -0600920 auto requestData =
921 reinterpret_cast<const dcmi::GetTempReadingsRequest*>(request);
922 auto responseData =
923 reinterpret_cast<dcmi::GetTempReadingsResponseHdr*>(response);
924
925 if (*data_len != sizeof(dcmi::GetTempReadingsRequest))
926 {
927 log<level::ERR>("Malformed request data",
928 entry("DATA_SIZE=%d", *data_len));
929 return IPMI_CC_REQ_DATA_LEN_INVALID;
930 }
931 *data_len = 0;
932
Deepak Kodihalli0b459552018-02-06 06:25:12 -0600933 auto it = dcmi::entityIdToName.find(requestData->entityId);
934 if (it == dcmi::entityIdToName.end())
Deepak Kodihalliee717d72018-01-24 04:53:09 -0600935 {
936 log<level::ERR>("Unknown Entity ID",
937 entry("ENTITY_ID=%d", requestData->entityId));
938 return IPMI_CC_INVALID_FIELD_REQUEST;
939 }
940
Deepak Kodihalliee717d72018-01-24 04:53:09 -0600941 if (requestData->sensorType != dcmi::temperatureSensorType)
942 {
943 log<level::ERR>("Invalid sensor type",
944 entry("SENSOR_TYPE=%d", requestData->sensorType));
945 return IPMI_CC_INVALID_FIELD_REQUEST;
946 }
947
948 dcmi::temp_readings::ResponseList temps{};
949 try
950 {
951 if (!requestData->entityInstance)
952 {
953 // Read all instances
954 std::tie(temps, responseData->numInstances) =
955 dcmi::temp_readings::readAll(it->second,
956 requestData->instanceStart);
957 }
958 else
959 {
960 // Read one instance
961 temps.resize(1);
962 std::tie(temps[0], responseData->numInstances) =
963 dcmi::temp_readings::read(it->second,
964 requestData->entityInstance);
965 }
966 responseData->numDataSets = temps.size();
967 }
Patrick Williamsa2ad2da2021-10-06 12:21:46 -0500968 catch (const InternalFailure& e)
Deepak Kodihalliee717d72018-01-24 04:53:09 -0600969 {
970 return IPMI_CC_UNSPECIFIED_ERROR;
971 }
972
Patrick Venture0b02be92018-08-31 11:55:55 -0700973 size_t payloadSize = temps.size() * sizeof(dcmi::temp_readings::Response);
Deepak Kodihalliee717d72018-01-24 04:53:09 -0600974 if (!temps.empty())
975 {
976 memcpy(responseData + 1, // copy payload right after the response header
Patrick Venture0b02be92018-08-31 11:55:55 -0700977 temps.data(), payloadSize);
Deepak Kodihalliee717d72018-01-24 04:53:09 -0600978 }
979 *data_len = sizeof(dcmi::GetTempReadingsResponseHdr) + payloadSize;
980
981 return IPMI_CC_OK;
982}
983
Patrick Williams5d82f472022-07-22 19:26:53 -0500984int64_t getPowerReading(sdbusplus::bus_t& bus)
Marri Devender Rao66c5fda2018-01-18 10:48:37 -0600985{
986 std::ifstream sensorFile(POWER_READING_SENSOR);
987 std::string objectPath;
988 if (!sensorFile.is_open())
989 {
990 log<level::ERR>("Power reading configuration file not found",
Patrick Venture0b02be92018-08-31 11:55:55 -0700991 entry("POWER_SENSOR_FILE=%s", POWER_READING_SENSOR));
Marri Devender Rao66c5fda2018-01-18 10:48:37 -0600992 elog<InternalFailure>();
993 }
994
995 auto data = nlohmann::json::parse(sensorFile, nullptr, false);
996 if (data.is_discarded())
997 {
998 log<level::ERR>("Error in parsing configuration file",
Patrick Venture0b02be92018-08-31 11:55:55 -0700999 entry("POWER_SENSOR_FILE=%s", POWER_READING_SENSOR));
Marri Devender Rao66c5fda2018-01-18 10:48:37 -06001000 elog<InternalFailure>();
1001 }
1002
1003 objectPath = data.value("path", "");
1004 if (objectPath.empty())
1005 {
1006 log<level::ERR>("Power sensor D-Bus object path is empty",
1007 entry("POWER_SENSOR_FILE=%s", POWER_READING_SENSOR));
1008 elog<InternalFailure>();
1009 }
1010
Marri Devender Raoce6a7952018-02-11 08:45:00 -06001011 // Return default value if failed to read from D-Bus object
1012 int64_t power = 0;
1013 try
1014 {
1015 auto service = ipmi::getService(bus, SENSOR_VALUE_INTF, objectPath);
Marri Devender Rao66c5fda2018-01-18 10:48:37 -06001016
Patrick Venture0b02be92018-08-31 11:55:55 -07001017 // Read the sensor value and scale properties
Chris Cain4cc61e02022-01-12 17:23:14 -06001018 auto value = ipmi::getDbusProperty(
1019 bus, service, objectPath, SENSOR_VALUE_INTF, SENSOR_VALUE_PROP);
1020 power = std::get<double>(value);
Marri Devender Raoce6a7952018-02-11 08:45:00 -06001021 }
Patrick Williamsa2ad2da2021-10-06 12:21:46 -05001022 catch (const std::exception& e)
Marri Devender Raoce6a7952018-02-11 08:45:00 -06001023 {
Chris Cain4cc61e02022-01-12 17:23:14 -06001024 log<level::ERR>("Failure to read power value from D-Bus object",
1025 entry("OBJECT_PATH=%s", objectPath.c_str()),
1026 entry("INTERFACE=%s", SENSOR_VALUE_INTF));
Marri Devender Raoce6a7952018-02-11 08:45:00 -06001027 }
Marri Devender Rao66c5fda2018-01-18 10:48:37 -06001028 return power;
1029}
1030
Willy Tu11d68892022-01-20 10:37:34 -08001031ipmi_ret_t setDCMIConfParams(ipmi_netfn_t, ipmi_cmd_t, ipmi_request_t request,
1032 ipmi_response_t, ipmi_data_len_t data_len,
1033 ipmi_context_t)
Nagaraju Goruganti22be97b2018-02-07 01:19:59 -06001034{
Patrick Venture0b02be92018-08-31 11:55:55 -07001035 auto requestData =
1036 reinterpret_cast<const dcmi::SetConfParamsRequest*>(request);
Nagaraju Goruganti22be97b2018-02-07 01:19:59 -06001037
William A. Kennington III5d06cc62019-04-25 02:10:55 -07001038 if (*data_len < DCMI_SET_CONF_PARAM_REQ_PACKET_MIN_SIZE ||
Patrick Venture0b02be92018-08-31 11:55:55 -07001039 *data_len > DCMI_SET_CONF_PARAM_REQ_PACKET_MAX_SIZE)
Nagaraju Goruganti22be97b2018-02-07 01:19:59 -06001040 {
William A. Kennington III5d06cc62019-04-25 02:10:55 -07001041 log<level::ERR>("Invalid Requested Packet size",
Nagaraju Goruganti22be97b2018-02-07 01:19:59 -06001042 entry("PACKET SIZE=%d", *data_len));
William A. Kennington III5d06cc62019-04-25 02:10:55 -07001043 *data_len = 0;
Nagaraju Goruganti22be97b2018-02-07 01:19:59 -06001044 return IPMI_CC_INVALID_FIELD_REQUEST;
1045 }
Nagaraju Goruganti22be97b2018-02-07 01:19:59 -06001046 *data_len = 0;
1047
1048 try
1049 {
1050 // Take action based on the Parameter Selector
Patrick Venture0b02be92018-08-31 11:55:55 -07001051 switch (
1052 static_cast<dcmi::DCMIConfigParameters>(requestData->paramSelect))
Nagaraju Goruganti22be97b2018-02-07 01:19:59 -06001053 {
1054 case dcmi::DCMIConfigParameters::ActivateDHCP:
1055
1056 if ((requestData->data[0] & DCMI_ACTIVATE_DHCP_MASK) &&
Thang Tran55cbf552023-01-31 14:43:02 +07001057 (dcmi::getDHCPEnabled() !=
1058 EthernetInterface::DHCPConf::none))
Nagaraju Goruganti22be97b2018-02-07 01:19:59 -06001059 {
Patrick Venture0b02be92018-08-31 11:55:55 -07001060 // When these conditions are met we have to trigger DHCP
1061 // protocol restart using the latest parameter settings, but
1062 // as per n/w manager design, each time when we update n/w
1063 // parameters, n/w service is restarted. So we no need to
1064 // take any action in this case.
Nagaraju Goruganti22be97b2018-02-07 01:19:59 -06001065 }
1066 break;
1067
1068 case dcmi::DCMIConfigParameters::DiscoveryConfig:
1069
1070 if (requestData->data[0] & DCMI_OPTION_12_MASK)
1071 {
1072 dcmi::setDHCPOption(DHCP_OPT12_ENABLED, true);
1073 }
1074 else
1075 {
1076 dcmi::setDHCPOption(DHCP_OPT12_ENABLED, false);
1077 }
1078
1079 // Systemd-networkd doesn't support Random Back off
1080 if (requestData->data[0] & DCMI_RAND_BACK_OFF_MASK)
1081 {
1082 return IPMI_CC_INVALID;
1083 }
1084 break;
1085 // Systemd-networkd doesn't allow to configure DHCP timigs
1086 case dcmi::DCMIConfigParameters::DHCPTiming1:
1087 case dcmi::DCMIConfigParameters::DHCPTiming2:
1088 case dcmi::DCMIConfigParameters::DHCPTiming3:
1089 default:
1090 return IPMI_CC_INVALID;
1091 }
1092 }
Patrick Williamsa2ad2da2021-10-06 12:21:46 -05001093 catch (const std::exception& e)
Nagaraju Goruganti22be97b2018-02-07 01:19:59 -06001094 {
1095 log<level::ERR>(e.what());
1096 return IPMI_CC_UNSPECIFIED_ERROR;
1097 }
Nagaraju Goruganti22be97b2018-02-07 01:19:59 -06001098 return IPMI_CC_OK;
1099}
1100
Willy Tu11d68892022-01-20 10:37:34 -08001101ipmi_ret_t getDCMIConfParams(ipmi_netfn_t, ipmi_cmd_t, ipmi_request_t request,
1102 ipmi_response_t response, ipmi_data_len_t data_len,
1103 ipmi_context_t)
Nagaraju Goruganti22be97b2018-02-07 01:19:59 -06001104{
1105
Patrick Venture0b02be92018-08-31 11:55:55 -07001106 auto requestData =
1107 reinterpret_cast<const dcmi::GetConfParamsRequest*>(request);
1108 auto responseData =
1109 reinterpret_cast<dcmi::GetConfParamsResponse*>(response);
Nagaraju Goruganti22be97b2018-02-07 01:19:59 -06001110
1111 responseData->data[0] = 0x00;
1112
William A. Kennington III5d06cc62019-04-25 02:10:55 -07001113 if (*data_len != sizeof(dcmi::GetConfParamsRequest))
Nagaraju Goruganti22be97b2018-02-07 01:19:59 -06001114 {
William A. Kennington III5d06cc62019-04-25 02:10:55 -07001115 log<level::ERR>("Invalid Requested Packet size",
Nagaraju Goruganti22be97b2018-02-07 01:19:59 -06001116 entry("PACKET SIZE=%d", *data_len));
1117 return IPMI_CC_INVALID_FIELD_REQUEST;
1118 }
1119
1120 *data_len = 0;
1121
1122 try
1123 {
1124 // Take action based on the Parameter Selector
Patrick Venture0b02be92018-08-31 11:55:55 -07001125 switch (
1126 static_cast<dcmi::DCMIConfigParameters>(requestData->paramSelect))
Nagaraju Goruganti22be97b2018-02-07 01:19:59 -06001127 {
1128 case dcmi::DCMIConfigParameters::ActivateDHCP:
1129 responseData->data[0] = DCMI_ACTIVATE_DHCP_REPLY;
1130 *data_len = sizeof(dcmi::GetConfParamsResponse) + 1;
1131 break;
1132 case dcmi::DCMIConfigParameters::DiscoveryConfig:
1133 if (dcmi::getDHCPOption(DHCP_OPT12_ENABLED))
1134 {
1135 responseData->data[0] |= DCMI_OPTION_12_MASK;
1136 }
1137 *data_len = sizeof(dcmi::GetConfParamsResponse) + 1;
1138 break;
1139 // Get below values from Systemd-networkd source code
1140 case dcmi::DCMIConfigParameters::DHCPTiming1:
1141 responseData->data[0] = DHCP_TIMING1;
1142 *data_len = sizeof(dcmi::GetConfParamsResponse) + 1;
1143 break;
1144 case dcmi::DCMIConfigParameters::DHCPTiming2:
1145 responseData->data[0] = DHCP_TIMING2_LOWER;
1146 responseData->data[1] = DHCP_TIMING2_UPPER;
1147 *data_len = sizeof(dcmi::GetConfParamsResponse) + 2;
1148 break;
1149 case dcmi::DCMIConfigParameters::DHCPTiming3:
1150 responseData->data[0] = DHCP_TIMING3_LOWER;
1151 responseData->data[1] = DHCP_TIMING3_UPPER;
1152 *data_len = sizeof(dcmi::GetConfParamsResponse) + 2;
1153 break;
1154 default:
1155 *data_len = 0;
1156 return IPMI_CC_INVALID;
1157 }
1158 }
Patrick Williamsa2ad2da2021-10-06 12:21:46 -05001159 catch (const std::exception& e)
Nagaraju Goruganti22be97b2018-02-07 01:19:59 -06001160 {
1161 log<level::ERR>(e.what());
1162 return IPMI_CC_UNSPECIFIED_ERROR;
1163 }
1164
Nagaraju Goruganti22be97b2018-02-07 01:19:59 -06001165 responseData->major = DCMI_SPEC_MAJOR_VERSION;
1166 responseData->minor = DCMI_SPEC_MINOR_VERSION;
1167 responseData->paramRevision = DCMI_CONFIG_PARAMETER_REVISION;
1168
1169 return IPMI_CC_OK;
1170}
1171
Willy Tu11d68892022-01-20 10:37:34 -08001172ipmi_ret_t getPowerReading(ipmi_netfn_t, ipmi_cmd_t, ipmi_request_t,
1173 ipmi_response_t response, ipmi_data_len_t data_len,
1174 ipmi_context_t)
Marri Devender Rao66c5fda2018-01-18 10:48:37 -06001175{
Chalapathi Venkataramashetty90e81fa2021-05-11 09:13:23 +00001176 *data_len = 0;
Kirill Pakhomov2c2af2c2018-11-06 16:06:10 +03001177 if (!dcmi::isDCMIPowerMgmtSupported())
1178 {
Kirill Pakhomov2c2af2c2018-11-06 16:06:10 +03001179 log<level::ERR>("DCMI Power management is unsupported!");
1180 return IPMI_CC_INVALID;
1181 }
1182
Marri Devender Rao66c5fda2018-01-18 10:48:37 -06001183 ipmi_ret_t rc = IPMI_CC_OK;
Patrick Venture0b02be92018-08-31 11:55:55 -07001184 auto responseData =
1185 reinterpret_cast<dcmi::GetPowerReadingResponse*>(response);
Marri Devender Rao9c966e02018-01-22 05:55:10 -06001186
Patrick Williams5d82f472022-07-22 19:26:53 -05001187 sdbusplus::bus_t bus{ipmid_get_sd_bus_connection()};
Marri Devender Rao9c966e02018-01-22 05:55:10 -06001188 int64_t power = 0;
Marri Devender Rao66c5fda2018-01-18 10:48:37 -06001189 try
1190 {
Marri Devender Rao9c966e02018-01-22 05:55:10 -06001191 power = getPowerReading(bus);
Marri Devender Rao66c5fda2018-01-18 10:48:37 -06001192 }
Patrick Williamsa2ad2da2021-10-06 12:21:46 -05001193 catch (const InternalFailure& e)
Marri Devender Rao66c5fda2018-01-18 10:48:37 -06001194 {
1195 log<level::ERR>("Error in reading power sensor value",
1196 entry("INTERFACE=%s", SENSOR_VALUE_INTF),
1197 entry("PROPERTY=%s", SENSOR_VALUE_PROP));
1198 return IPMI_CC_UNSPECIFIED_ERROR;
1199 }
Marri Devender Rao9c966e02018-01-22 05:55:10 -06001200
1201 // TODO: openbmc/openbmc#2819
Gunnar Mills8466b792018-03-23 12:18:12 -05001202 // Minimum, Maximum, Average power, TimeFrame, TimeStamp,
Marri Devender Rao9c966e02018-01-22 05:55:10 -06001203 // PowerReadingState readings need to be populated
1204 // after Telemetry changes.
1205 uint16_t totalPower = static_cast<uint16_t>(power);
1206 responseData->currentPower = totalPower;
1207 responseData->minimumPower = totalPower;
1208 responseData->maximumPower = totalPower;
1209 responseData->averagePower = totalPower;
1210
1211 *data_len = sizeof(*responseData);
Marri Devender Rao66c5fda2018-01-18 10:48:37 -06001212 return rc;
1213}
1214
Deepak Kodihalli0b459552018-02-06 06:25:12 -06001215namespace dcmi
1216{
1217namespace sensor_info
1218{
1219
Deepak Kodihallidd4cff12018-02-06 06:48:29 -06001220Response createFromJson(const Json& config)
1221{
1222 Response response{};
1223 uint16_t recordId = config.value("record_id", 0);
1224 response.recordIdLsb = recordId & 0xFF;
1225 response.recordIdMsb = (recordId >> 8) & 0xFF;
1226 return response;
1227}
1228
Deepak Kodihalli0b459552018-02-06 06:25:12 -06001229std::tuple<Response, NumInstances> read(const std::string& type,
Patrick Venture0b02be92018-08-31 11:55:55 -07001230 uint8_t instance, const Json& config)
Deepak Kodihalli0b459552018-02-06 06:25:12 -06001231{
Deepak Kodihallidd4cff12018-02-06 06:48:29 -06001232 Response response{};
1233
1234 if (!instance)
1235 {
1236 log<level::ERR>("Expected non-zero instance");
1237 elog<InternalFailure>();
1238 }
1239
1240 static const std::vector<Json> empty{};
1241 std::vector<Json> readings = config.value(type, empty);
1242 size_t numInstances = readings.size();
1243 for (const auto& reading : readings)
1244 {
1245 uint8_t instanceNum = reading.value("instance", 0);
1246 // Not the instance we're interested in
1247 if (instanceNum != instance)
1248 {
1249 continue;
1250 }
1251
1252 response = createFromJson(reading);
1253
1254 // Found the instance we're interested in
1255 break;
1256 }
1257
1258 if (numInstances > maxInstances)
1259 {
1260 log<level::DEBUG>("Trimming IPMI num instances",
1261 entry("NUM_INSTANCES=%d", numInstances));
1262 numInstances = maxInstances;
1263 }
1264 return std::make_tuple(response, numInstances);
Deepak Kodihalli0b459552018-02-06 06:25:12 -06001265}
1266
Patrick Venture0b02be92018-08-31 11:55:55 -07001267std::tuple<ResponseList, NumInstances>
1268 readAll(const std::string& type, uint8_t instanceStart, const Json& config)
Deepak Kodihalli0b459552018-02-06 06:25:12 -06001269{
Deepak Kodihallidd4cff12018-02-06 06:48:29 -06001270 ResponseList responses{};
1271
1272 size_t numInstances = 0;
1273 static const std::vector<Json> empty{};
1274 std::vector<Json> readings = config.value(type, empty);
1275 numInstances = readings.size();
1276 for (const auto& reading : readings)
1277 {
1278 try
1279 {
1280 // Max of 8 records
1281 if (responses.size() == maxRecords)
1282 {
1283 break;
1284 }
1285
1286 uint8_t instanceNum = reading.value("instance", 0);
1287 // Not in the instance range we're interested in
1288 if (instanceNum < instanceStart)
1289 {
1290 continue;
1291 }
1292
1293 Response response = createFromJson(reading);
1294 responses.push_back(response);
1295 }
Patrick Williamsa2ad2da2021-10-06 12:21:46 -05001296 catch (const std::exception& e)
Deepak Kodihallidd4cff12018-02-06 06:48:29 -06001297 {
1298 log<level::DEBUG>(e.what());
1299 continue;
1300 }
1301 }
1302
1303 if (numInstances > maxInstances)
1304 {
1305 log<level::DEBUG>("Trimming IPMI num instances",
1306 entry("NUM_INSTANCES=%d", numInstances));
1307 numInstances = maxInstances;
1308 }
1309 return std::make_tuple(responses, numInstances);
Deepak Kodihalli0b459552018-02-06 06:25:12 -06001310}
1311
1312} // namespace sensor_info
1313} // namespace dcmi
1314
Willy Tu11d68892022-01-20 10:37:34 -08001315ipmi_ret_t getSensorInfo(ipmi_netfn_t, ipmi_cmd_t, ipmi_request_t request,
1316 ipmi_response_t response, ipmi_data_len_t data_len,
1317 ipmi_context_t)
Deepak Kodihalli0b459552018-02-06 06:25:12 -06001318{
1319 auto requestData =
1320 reinterpret_cast<const dcmi::GetSensorInfoRequest*>(request);
1321 auto responseData =
1322 reinterpret_cast<dcmi::GetSensorInfoResponseHdr*>(response);
1323
1324 if (*data_len != sizeof(dcmi::GetSensorInfoRequest))
1325 {
1326 log<level::ERR>("Malformed request data",
1327 entry("DATA_SIZE=%d", *data_len));
1328 return IPMI_CC_REQ_DATA_LEN_INVALID;
1329 }
1330 *data_len = 0;
1331
1332 auto it = dcmi::entityIdToName.find(requestData->entityId);
1333 if (it == dcmi::entityIdToName.end())
1334 {
1335 log<level::ERR>("Unknown Entity ID",
1336 entry("ENTITY_ID=%d", requestData->entityId));
1337 return IPMI_CC_INVALID_FIELD_REQUEST;
1338 }
1339
Deepak Kodihalli0b459552018-02-06 06:25:12 -06001340 if (requestData->sensorType != dcmi::temperatureSensorType)
1341 {
1342 log<level::ERR>("Invalid sensor type",
1343 entry("SENSOR_TYPE=%d", requestData->sensorType));
1344 return IPMI_CC_INVALID_FIELD_REQUEST;
1345 }
1346
1347 dcmi::sensor_info::ResponseList sensors{};
1348 static dcmi::Json config{};
1349 static bool parsed = false;
1350
1351 try
1352 {
1353 if (!parsed)
1354 {
Kirill Pakhomova2573622018-11-02 19:00:18 +03001355 config = dcmi::parseJSONConfig(dcmi::gDCMISensorsConfig);
Deepak Kodihalli0b459552018-02-06 06:25:12 -06001356 parsed = true;
1357 }
1358
1359 if (!requestData->entityInstance)
1360 {
1361 // Read all instances
1362 std::tie(sensors, responseData->numInstances) =
1363 dcmi::sensor_info::readAll(it->second,
Patrick Venture0b02be92018-08-31 11:55:55 -07001364 requestData->instanceStart, config);
Deepak Kodihalli0b459552018-02-06 06:25:12 -06001365 }
1366 else
1367 {
1368 // Read one instance
1369 sensors.resize(1);
1370 std::tie(sensors[0], responseData->numInstances) =
Patrick Venture0b02be92018-08-31 11:55:55 -07001371 dcmi::sensor_info::read(it->second, requestData->entityInstance,
Deepak Kodihalli0b459552018-02-06 06:25:12 -06001372 config);
1373 }
1374 responseData->numRecords = sensors.size();
1375 }
Patrick Williamsa2ad2da2021-10-06 12:21:46 -05001376 catch (const InternalFailure& e)
Deepak Kodihalli0b459552018-02-06 06:25:12 -06001377 {
1378 return IPMI_CC_UNSPECIFIED_ERROR;
1379 }
1380
Deepak Kodihalli0b459552018-02-06 06:25:12 -06001381 size_t payloadSize = sensors.size() * sizeof(dcmi::sensor_info::Response);
1382 if (!sensors.empty())
1383 {
1384 memcpy(responseData + 1, // copy payload right after the response header
Patrick Venture0b02be92018-08-31 11:55:55 -07001385 sensors.data(), payloadSize);
Deepak Kodihalli0b459552018-02-06 06:25:12 -06001386 }
1387 *data_len = sizeof(dcmi::GetSensorInfoResponseHdr) + payloadSize;
1388
1389 return IPMI_CC_OK;
1390}
1391
Chris Austen1810bec2015-10-13 12:12:39 -05001392void register_netfn_dcmi_functions()
1393{
Tom05732372016-09-06 17:21:23 +05301394 // <Get 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::GET_POWER_LIMIT, NULL,
1397 getPowerLimit, PRIVILEGE_USER);
Tom Joseph6f6dd4d2017-07-12 20:07:11 +05301398
Tom Joseph46fa37d2017-07-26 18:11:55 +05301399 // <Set Power Limit>
Ratan Gupta11ddbd22017-08-05 11:59:39 +05301400
Patrick Venture0b02be92018-08-31 11:55:55 -07001401 ipmi_register_callback(NETFUN_GRPEXT, dcmi::Commands::SET_POWER_LIMIT, NULL,
1402 setPowerLimit, PRIVILEGE_OPERATOR);
Tom Joseph46fa37d2017-07-26 18:11:55 +05301403
Tom Joseph6c8d51b2017-07-26 18:18:06 +05301404 // <Activate/Deactivate Power Limit>
Ratan Gupta11ddbd22017-08-05 11:59:39 +05301405
1406 ipmi_register_callback(NETFUN_GRPEXT, dcmi::Commands::APPLY_POWER_LIMIT,
1407 NULL, applyPowerLimit, PRIVILEGE_OPERATOR);
Tom Joseph6c8d51b2017-07-26 18:18:06 +05301408
Tom Joseph6f6dd4d2017-07-12 20:07:11 +05301409 // <Get 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::GET_ASSET_TAG, NULL,
1412 getAssetTag, PRIVILEGE_USER);
Tom Joseph545dd232017-07-12 20:20:49 +05301413
1414 // <Set Asset Tag>
Ratan Gupta11ddbd22017-08-05 11:59:39 +05301415
Patrick Venture0b02be92018-08-31 11:55:55 -07001416 ipmi_register_callback(NETFUN_GRPEXT, dcmi::Commands::SET_ASSET_TAG, NULL,
1417 setAssetTag, PRIVILEGE_OPERATOR);
Vladislav Vovchenko8f7a6f62017-08-17 00:31:14 +03001418
Gunnar Mills8991dd62017-10-25 17:11:29 -05001419 // <Get Management Controller Identifier String>
Vladislav Vovchenko8f7a6f62017-08-17 00:31:14 +03001420
1421 ipmi_register_callback(NETFUN_GRPEXT, dcmi::Commands::GET_MGMNT_CTRL_ID_STR,
Patrick Venture0b02be92018-08-31 11:55:55 -07001422 NULL, getMgmntCtrlIdStr, PRIVILEGE_USER);
Vladislav Vovchenko8f7a6f62017-08-17 00:31:14 +03001423
1424 // <Set Management Controller Identifier String>
Vladislav Vovchenko8f7a6f62017-08-17 00:31:14 +03001425 ipmi_register_callback(NETFUN_GRPEXT, dcmi::Commands::SET_MGMNT_CTRL_ID_STR,
Patrick Venture0b02be92018-08-31 11:55:55 -07001426 NULL, setMgmntCtrlIdStr, PRIVILEGE_ADMIN);
Vladislav Vovchenko8f7a6f62017-08-17 00:31:14 +03001427
Dhruvaraj Subhashchandrane29be412018-01-16 05:11:56 -06001428 // <Get DCMI capabilities>
1429 ipmi_register_callback(NETFUN_GRPEXT, dcmi::Commands::GET_CAPABILITIES,
Patrick Venture0b02be92018-08-31 11:55:55 -07001430 NULL, getDCMICapabilities, PRIVILEGE_USER);
Deepak Kodihalliee717d72018-01-24 04:53:09 -06001431
1432 // <Get Temperature Readings>
1433 ipmi_register_callback(NETFUN_GRPEXT, dcmi::Commands::GET_TEMP_READINGS,
1434 NULL, getTempReadings, PRIVILEGE_USER);
1435
Marri Devender Rao66c5fda2018-01-18 10:48:37 -06001436 // <Get Power Reading>
1437 ipmi_register_callback(NETFUN_GRPEXT, dcmi::Commands::GET_POWER_READING,
1438 NULL, getPowerReading, PRIVILEGE_USER);
adarshgrami042e9db2022-09-15 10:34:34 +05301439// The Get sensor should get the senor details dynamically when
1440// FEATURE_DYNAMIC_SENSORS is enabled.
1441#ifndef FEATURE_DYNAMIC_SENSORS
Deepak Kodihalli0b459552018-02-06 06:25:12 -06001442 // <Get Sensor Info>
Patrick Venture0b02be92018-08-31 11:55:55 -07001443 ipmi_register_callback(NETFUN_GRPEXT, dcmi::Commands::GET_SENSOR_INFO, NULL,
1444 getSensorInfo, PRIVILEGE_USER);
adarshgrami042e9db2022-09-15 10:34:34 +05301445#endif
Nagaraju Goruganti22be97b2018-02-07 01:19:59 -06001446 // <Get DCMI Configuration Parameters>
Patrick Venture0b02be92018-08-31 11:55:55 -07001447 ipmi_register_callback(NETFUN_GRPEXT, dcmi::Commands::GET_CONF_PARAMS, NULL,
1448 getDCMIConfParams, PRIVILEGE_USER);
Nagaraju Goruganti22be97b2018-02-07 01:19:59 -06001449
1450 // <Set DCMI Configuration Parameters>
Patrick Venture0b02be92018-08-31 11:55:55 -07001451 ipmi_register_callback(NETFUN_GRPEXT, dcmi::Commands::SET_CONF_PARAMS, NULL,
1452 setDCMIConfParams, PRIVILEGE_ADMIN);
Nagaraju Goruganti22be97b2018-02-07 01:19:59 -06001453
Chris Austen1810bec2015-10-13 12:12:39 -05001454 return;
1455}
Tom05732372016-09-06 17:21:23 +05301456// 956379