blob: ca2ee7dfcedc5b6b8de0299eaee0ae1739e99d55 [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
Vernon Mauerye08fbff2019-04-03 09:19:34 -07007#include <ipmid/api.hpp>
Vernon Mauery6a98fe72019-03-11 15:57:48 -07008#include <ipmid/utils.hpp>
Patrick Venture0b02be92018-08-31 11:55:55 -07009#include <nlohmann/json.hpp>
Tom Josephbe5eaa12017-07-12 19:54:44 +053010#include <phosphor-logging/elog-errors.hpp>
Andrew Geissler50c0c8f2017-07-11 16:18:51 -050011#include <phosphor-logging/log.hpp>
12#include <sdbusplus/bus.hpp>
Patrick Venture0b02be92018-08-31 11:55:55 -070013#include <xyz/openbmc_project/Common/error.hpp>
Thang Tran55cbf552023-01-31 14:43:02 +070014#include <xyz/openbmc_project/Network/EthernetInterface/server.hpp>
Patrick Venture0b02be92018-08-31 11:55:55 -070015
Patrick Williamsfbc6c9d2023-05-10 07:50:16 -050016#include <bitset>
17#include <cmath>
18#include <fstream>
19#include <variant>
20
Tom Josephbe5eaa12017-07-12 19:54:44 +053021using namespace phosphor::logging;
Thang Tran55cbf552023-01-31 14:43:02 +070022using sdbusplus::xyz::openbmc_project::Network::server::EthernetInterface;
23
Tom Josephbe5eaa12017-07-12 19:54:44 +053024using InternalFailure =
Patrick Venture0b02be92018-08-31 11:55:55 -070025 sdbusplus::xyz::openbmc_project::Common::Error::InternalFailure;
Chris Austen1810bec2015-10-13 12:12:39 -050026
27void register_netfn_dcmi_functions() __attribute__((constructor));
28
Patrick Venture0b02be92018-08-31 11:55:55 -070029constexpr auto PCAP_PATH = "/xyz/openbmc_project/control/host0/power_cap";
Andrew Geissler50c0c8f2017-07-11 16:18:51 -050030constexpr auto PCAP_INTERFACE = "xyz.openbmc_project.Control.Power.Cap";
31
32constexpr auto POWER_CAP_PROP = "PowerCap";
33constexpr auto POWER_CAP_ENABLE_PROP = "PowerCapEnable";
34
Dhruvaraj Subhashchandrane29be412018-01-16 05:11:56 -060035constexpr auto DCMI_PARAMETER_REVISION = 2;
36constexpr auto DCMI_SPEC_MAJOR_VERSION = 1;
37constexpr auto DCMI_SPEC_MINOR_VERSION = 5;
Nagaraju Goruganti22be97b2018-02-07 01:19:59 -060038constexpr auto DCMI_CONFIG_PARAMETER_REVISION = 1;
39constexpr auto DCMI_RAND_BACK_OFF_MASK = 0x80;
40constexpr auto DCMI_OPTION_60_43_MASK = 0x02;
41constexpr auto DCMI_OPTION_12_MASK = 0x01;
42constexpr auto DCMI_ACTIVATE_DHCP_MASK = 0x01;
43constexpr auto DCMI_ACTIVATE_DHCP_REPLY = 0x00;
William A. Kennington III5d06cc62019-04-25 02:10:55 -070044constexpr auto DCMI_SET_CONF_PARAM_REQ_PACKET_MAX_SIZE = 0x04;
45constexpr auto DCMI_SET_CONF_PARAM_REQ_PACKET_MIN_SIZE = 0x03;
Patrick Venture0b02be92018-08-31 11:55:55 -070046constexpr auto DHCP_TIMING1 = 0x04; // 4 sec
47constexpr auto DHCP_TIMING2_UPPER = 0x00; // 2 min
Nagaraju Goruganti22be97b2018-02-07 01:19:59 -060048constexpr auto DHCP_TIMING2_LOWER = 0x78;
Patrick Venture0b02be92018-08-31 11:55:55 -070049constexpr auto DHCP_TIMING3_UPPER = 0x00; // 64 sec
Nagaraju Goruganti22be97b2018-02-07 01:19:59 -060050constexpr auto DHCP_TIMING3_LOWER = 0x40;
51// When DHCP Option 12 is enabled the string "SendHostName=true" will be
52// added into n/w configuration file and the parameter
53// SendHostNameEnabled will set to true.
54constexpr auto DHCP_OPT12_ENABLED = "SendHostNameEnabled";
55
Marri Devender Rao66c5fda2018-01-18 10:48:37 -060056constexpr auto SENSOR_VALUE_INTF = "xyz.openbmc_project.Sensor.Value";
57constexpr auto SENSOR_VALUE_PROP = "Value";
Marri Devender Rao66c5fda2018-01-18 10:48:37 -060058
Andrew Geissler50c0c8f2017-07-11 16:18:51 -050059using namespace phosphor::logging;
60
Tom Josephb9d86f42017-07-26 18:03:47 +053061namespace dcmi
62{
63
Deepak Kodihalli0b459552018-02-06 06:25:12 -060064// Refer Table 6-14, DCMI Entity ID Extension, DCMI v1.5 spec
Patrick Venture0b02be92018-08-31 11:55:55 -070065static const std::map<uint8_t, std::string> entityIdToName{
66 {0x40, "inlet"}, {0x37, "inlet"}, {0x41, "cpu"},
67 {0x03, "cpu"}, {0x42, "baseboard"}, {0x07, "baseboard"}};
Deepak Kodihalli0b459552018-02-06 06:25:12 -060068
Kirill Pakhomov2c2af2c2018-11-06 16:06:10 +030069bool isDCMIPowerMgmtSupported()
70{
71 auto data = parseJSONConfig(gDCMICapabilitiesConfig);
72
73 return (gDCMIPowerMgmtSupported == data.value(gDCMIPowerMgmtCapability, 0));
74}
75
Patrick Williams5d82f472022-07-22 19:26:53 -050076uint32_t getPcap(sdbusplus::bus_t& bus)
Andrew Geissler50c0c8f2017-07-11 16:18:51 -050077{
Patrick Venture0b02be92018-08-31 11:55:55 -070078 auto settingService = ipmi::getService(bus, PCAP_INTERFACE, PCAP_PATH);
Andrew Geissler50c0c8f2017-07-11 16:18:51 -050079
Patrick Venture0b02be92018-08-31 11:55:55 -070080 auto method = bus.new_method_call(settingService.c_str(), PCAP_PATH,
81 "org.freedesktop.DBus.Properties", "Get");
Andrew Geissler50c0c8f2017-07-11 16:18:51 -050082
83 method.append(PCAP_INTERFACE, POWER_CAP_PROP);
Andrew Geissler50c0c8f2017-07-11 16:18:51 -050084
George Liu3e3cc352023-07-26 15:59:31 +080085 std::variant<uint32_t> pcap;
86 try
Andrew Geissler50c0c8f2017-07-11 16:18:51 -050087 {
George Liu3e3cc352023-07-26 15:59:31 +080088 auto reply = bus.call(method);
89 reply.read(pcap);
90 return std::get<uint32_t>(pcap);
91 }
92 catch (const std::exception& e)
93 {
94 log<level::ERR>("Error in getPcap prop", entry("ERROR=%s", e.what()));
Tom Josephb9d86f42017-07-26 18:03:47 +053095 elog<InternalFailure>();
Andrew Geissler50c0c8f2017-07-11 16:18:51 -050096 }
Andrew Geissler50c0c8f2017-07-11 16:18:51 -050097}
98
Patrick Williams5d82f472022-07-22 19:26:53 -050099bool getPcapEnabled(sdbusplus::bus_t& bus)
Andrew Geissler50c0c8f2017-07-11 16:18:51 -0500100{
Patrick Venture0b02be92018-08-31 11:55:55 -0700101 auto settingService = ipmi::getService(bus, PCAP_INTERFACE, PCAP_PATH);
Andrew Geissler50c0c8f2017-07-11 16:18:51 -0500102
Patrick Venture0b02be92018-08-31 11:55:55 -0700103 auto method = bus.new_method_call(settingService.c_str(), PCAP_PATH,
104 "org.freedesktop.DBus.Properties", "Get");
Andrew Geissler50c0c8f2017-07-11 16:18:51 -0500105
106 method.append(PCAP_INTERFACE, POWER_CAP_ENABLE_PROP);
Andrew Geissler50c0c8f2017-07-11 16:18:51 -0500107
George Liu3e3cc352023-07-26 15:59:31 +0800108 std::variant<bool> pcapEnabled;
109 try
Andrew Geissler50c0c8f2017-07-11 16:18:51 -0500110 {
George Liu3e3cc352023-07-26 15:59:31 +0800111 auto reply = bus.call(method);
112 reply.read(pcapEnabled);
113 return std::get<bool>(pcapEnabled);
114 }
115 catch (const std::exception& e)
116 {
117 log<level::ERR>("Error in getPcapEnabled prop",
118 entry("ERROR=%s", e.what()));
Tom Josephb9d86f42017-07-26 18:03:47 +0530119 elog<InternalFailure>();
Andrew Geissler50c0c8f2017-07-11 16:18:51 -0500120 }
Andrew Geissler50c0c8f2017-07-11 16:18:51 -0500121}
Chris Austen1810bec2015-10-13 12:12:39 -0500122
Patrick Williams5d82f472022-07-22 19:26:53 -0500123void setPcap(sdbusplus::bus_t& bus, const uint32_t powerCap)
Tom Joseph46fa37d2017-07-26 18:11:55 +0530124{
125 auto service = ipmi::getService(bus, PCAP_INTERFACE, PCAP_PATH);
126
Patrick Venture0b02be92018-08-31 11:55:55 -0700127 auto method = bus.new_method_call(service.c_str(), PCAP_PATH,
128 "org.freedesktop.DBus.Properties", "Set");
Tom Joseph46fa37d2017-07-26 18:11:55 +0530129
130 method.append(PCAP_INTERFACE, POWER_CAP_PROP);
Vernon Mauery16b86932019-05-01 08:36:11 -0700131 method.append(std::variant<uint32_t>(powerCap));
Tom Joseph46fa37d2017-07-26 18:11:55 +0530132
George Liu3e3cc352023-07-26 15:59:31 +0800133 try
Tom Joseph46fa37d2017-07-26 18:11:55 +0530134 {
George Liu3e3cc352023-07-26 15:59:31 +0800135 auto reply = bus.call(method);
136 }
137 catch (const std::exception& e)
138 {
139 log<level::ERR>("Error in setPcap property",
140 entry("ERROR=%s", e.what()));
Tom Joseph46fa37d2017-07-26 18:11:55 +0530141 elog<InternalFailure>();
142 }
143}
144
Patrick Williams5d82f472022-07-22 19:26:53 -0500145void setPcapEnable(sdbusplus::bus_t& bus, bool enabled)
Tom Joseph6c8d51b2017-07-26 18:18:06 +0530146{
147 auto service = ipmi::getService(bus, PCAP_INTERFACE, PCAP_PATH);
148
Patrick Venture0b02be92018-08-31 11:55:55 -0700149 auto method = bus.new_method_call(service.c_str(), PCAP_PATH,
150 "org.freedesktop.DBus.Properties", "Set");
Tom Joseph6c8d51b2017-07-26 18:18:06 +0530151
152 method.append(PCAP_INTERFACE, POWER_CAP_ENABLE_PROP);
Vernon Mauery16b86932019-05-01 08:36:11 -0700153 method.append(std::variant<bool>(enabled));
Tom Joseph6c8d51b2017-07-26 18:18:06 +0530154
George Liu3e3cc352023-07-26 15:59:31 +0800155 try
Tom Joseph6c8d51b2017-07-26 18:18:06 +0530156 {
George Liu3e3cc352023-07-26 15:59:31 +0800157 auto reply = bus.call(method);
158 }
159 catch (const std::exception& e)
160 {
161 log<level::ERR>("Error in setPcapEnabled property",
162 entry("ERROR=%s", e.what()));
Tom Joseph6c8d51b2017-07-26 18:18:06 +0530163 elog<InternalFailure>();
164 }
165}
166
Tom Josephbe5eaa12017-07-12 19:54:44 +0530167void readAssetTagObjectTree(dcmi::assettag::ObjectTree& objectTree)
168{
169 static constexpr auto mapperBusName = "xyz.openbmc_project.ObjectMapper";
170 static constexpr auto mapperObjPath = "/xyz/openbmc_project/object_mapper";
171 static constexpr auto mapperIface = "xyz.openbmc_project.ObjectMapper";
172 static constexpr auto inventoryRoot = "/xyz/openbmc_project/inventory/";
173
Patrick Williams5d82f472022-07-22 19:26:53 -0500174 sdbusplus::bus_t bus{ipmid_get_sd_bus_connection()};
Tom Josephbe5eaa12017-07-12 19:54:44 +0530175 auto depth = 0;
176
Patrick Venture0b02be92018-08-31 11:55:55 -0700177 auto mapperCall = bus.new_method_call(mapperBusName, mapperObjPath,
178 mapperIface, "GetSubTree");
Tom Josephbe5eaa12017-07-12 19:54:44 +0530179
180 mapperCall.append(inventoryRoot);
181 mapperCall.append(depth);
182 mapperCall.append(std::vector<std::string>({dcmi::assetTagIntf}));
183
George Liu3e3cc352023-07-26 15:59:31 +0800184 try
Tom Josephbe5eaa12017-07-12 19:54:44 +0530185 {
George Liu3e3cc352023-07-26 15:59:31 +0800186 auto mapperReply = bus.call(mapperCall);
187 mapperReply.read(objectTree);
188
189 if (objectTree.empty())
190 {
191 log<level::ERR>("AssetTag property is not populated");
192 elog<InternalFailure>();
193 }
Tom Josephbe5eaa12017-07-12 19:54:44 +0530194 }
George Liu3e3cc352023-07-26 15:59:31 +0800195 catch (const std::exception& e)
Tom Josephbe5eaa12017-07-12 19:54:44 +0530196 {
George Liu3e3cc352023-07-26 15:59:31 +0800197 log<level::ERR>("Error in mapper call", entry("ERROR=%s", e.what()));
Tom Josephbe5eaa12017-07-12 19:54:44 +0530198 elog<InternalFailure>();
199 }
200}
201
202std::string readAssetTag()
203{
Patrick Williams5d82f472022-07-22 19:26:53 -0500204 sdbusplus::bus_t bus{ipmid_get_sd_bus_connection()};
Tom Josephbe5eaa12017-07-12 19:54:44 +0530205 dcmi::assettag::ObjectTree objectTree;
206
207 // Read the object tree with the inventory root to figure out the object
208 // that has implemented the Asset tag interface.
209 readAssetTagObjectTree(objectTree);
210
211 auto method = bus.new_method_call(
Patrick Venture0b02be92018-08-31 11:55:55 -0700212 (objectTree.begin()->second.begin()->first).c_str(),
213 (objectTree.begin()->first).c_str(), dcmi::propIntf, "Get");
Tom Josephbe5eaa12017-07-12 19:54:44 +0530214 method.append(dcmi::assetTagIntf);
215 method.append(dcmi::assetTagProp);
216
George Liu3e3cc352023-07-26 15:59:31 +0800217 std::variant<std::string> assetTag;
218 try
Tom Josephbe5eaa12017-07-12 19:54:44 +0530219 {
George Liu3e3cc352023-07-26 15:59:31 +0800220 auto reply = bus.call(method);
221 reply.read(assetTag);
222 return std::get<std::string>(assetTag);
223 }
224 catch (const std::exception& e)
225 {
226 log<level::ERR>("Error in reading asset tag",
227 entry("ERROR=%s", e.what()));
Tom Josephbe5eaa12017-07-12 19:54:44 +0530228 elog<InternalFailure>();
229 }
Tom Josephbe5eaa12017-07-12 19:54:44 +0530230}
231
Tom Josephbe5b9892017-07-15 00:55:23 +0530232void writeAssetTag(const std::string& assetTag)
233{
Patrick Williams5d82f472022-07-22 19:26:53 -0500234 sdbusplus::bus_t bus{ipmid_get_sd_bus_connection()};
Tom Josephbe5b9892017-07-15 00:55:23 +0530235 dcmi::assettag::ObjectTree objectTree;
236
237 // Read the object tree with the inventory root to figure out the object
238 // that has implemented the Asset tag interface.
239 readAssetTagObjectTree(objectTree);
240
241 auto method = bus.new_method_call(
Patrick Venture0b02be92018-08-31 11:55:55 -0700242 (objectTree.begin()->second.begin()->first).c_str(),
243 (objectTree.begin()->first).c_str(), dcmi::propIntf, "Set");
Tom Josephbe5b9892017-07-15 00:55:23 +0530244 method.append(dcmi::assetTagIntf);
245 method.append(dcmi::assetTagProp);
Vernon Mauery16b86932019-05-01 08:36:11 -0700246 method.append(std::variant<std::string>(assetTag));
Tom Josephbe5b9892017-07-15 00:55:23 +0530247
George Liu3e3cc352023-07-26 15:59:31 +0800248 try
Tom Josephbe5b9892017-07-15 00:55:23 +0530249 {
George Liu3e3cc352023-07-26 15:59:31 +0800250 auto reply = bus.call(method);
251 }
252 catch (const std::exception& e)
253 {
254 log<level::ERR>("Error in writing asset tag",
255 entry("ERROR=%s", e.what()));
Tom Josephbe5b9892017-07-15 00:55:23 +0530256 elog<InternalFailure>();
257 }
258}
259
Vladislav Vovchenko8f7a6f62017-08-17 00:31:14 +0300260std::string getHostName(void)
261{
Patrick Williams5d82f472022-07-22 19:26:53 -0500262 sdbusplus::bus_t bus{ipmid_get_sd_bus_connection()};
Vladislav Vovchenko8f7a6f62017-08-17 00:31:14 +0300263
264 auto service = ipmi::getService(bus, networkConfigIntf, networkConfigObj);
Patrick Venture0b02be92018-08-31 11:55:55 -0700265 auto value = ipmi::getDbusProperty(bus, service, networkConfigObj,
266 networkConfigIntf, hostNameProp);
Vladislav Vovchenko8f7a6f62017-08-17 00:31:14 +0300267
Vernon Maueryf442e112019-04-09 11:44:36 -0700268 return std::get<std::string>(value);
Vladislav Vovchenko8f7a6f62017-08-17 00:31:14 +0300269}
270
Thang Tran55cbf552023-01-31 14:43:02 +0700271EthernetInterface::DHCPConf getDHCPEnabled()
Nagaraju Goruganti22be97b2018-02-07 01:19:59 -0600272{
Patrick Williams5d82f472022-07-22 19:26:53 -0500273 sdbusplus::bus_t bus{ipmid_get_sd_bus_connection()};
Nagaraju Goruganti22be97b2018-02-07 01:19:59 -0600274
Johnathan Mantey74a21022018-12-13 13:17:56 -0800275 auto ethdevice = ipmi::getChannelName(ethernetDefaultChannelNum);
Patrick Williamsfbc6c9d2023-05-10 07:50:16 -0500276 auto ethernetObj = ipmi::getDbusObject(bus, ethernetIntf, networkRoot,
277 ethdevice);
Nagaraju Goruganti22be97b2018-02-07 01:19:59 -0600278 auto service = ipmi::getService(bus, ethernetIntf, ethernetObj.first);
Patrick Venture0b02be92018-08-31 11:55:55 -0700279 auto value = ipmi::getDbusProperty(bus, service, ethernetObj.first,
280 ethernetIntf, "DHCPEnabled");
Nagaraju Goruganti22be97b2018-02-07 01:19:59 -0600281
Thang Tran55cbf552023-01-31 14:43:02 +0700282 return EthernetInterface::convertDHCPConfFromString(
283 std::get<std::string>(value));
Nagaraju Goruganti22be97b2018-02-07 01:19:59 -0600284}
285
286bool getDHCPOption(std::string prop)
287{
Patrick Williams5d82f472022-07-22 19:26:53 -0500288 sdbusplus::bus_t bus{ipmid_get_sd_bus_connection()};
Nagaraju Goruganti22be97b2018-02-07 01:19:59 -0600289
290 auto service = ipmi::getService(bus, dhcpIntf, dhcpObj);
291 auto value = ipmi::getDbusProperty(bus, service, dhcpObj, dhcpIntf, prop);
292
Vernon Maueryf442e112019-04-09 11:44:36 -0700293 return std::get<bool>(value);
Nagaraju Goruganti22be97b2018-02-07 01:19:59 -0600294}
295
Nagaraju Goruganti22be97b2018-02-07 01:19:59 -0600296void setDHCPOption(std::string prop, bool value)
297{
Patrick Williams5d82f472022-07-22 19:26:53 -0500298 sdbusplus::bus_t bus{ipmid_get_sd_bus_connection()};
Nagaraju Goruganti22be97b2018-02-07 01:19:59 -0600299
300 auto service = ipmi::getService(bus, dhcpIntf, dhcpObj);
301 ipmi::setDbusProperty(bus, service, dhcpObj, dhcpIntf, prop, value);
302}
303
Kirill Pakhomova2573622018-11-02 19:00:18 +0300304Json parseJSONConfig(const std::string& configFile)
Deepak Kodihalli0b459552018-02-06 06:25:12 -0600305{
306 std::ifstream jsonFile(configFile);
307 if (!jsonFile.is_open())
308 {
309 log<level::ERR>("Temperature readings JSON file not found");
310 elog<InternalFailure>();
311 }
312
313 auto data = Json::parse(jsonFile, nullptr, false);
314 if (data.is_discarded())
315 {
316 log<level::ERR>("Temperature readings JSON parser failure");
317 elog<InternalFailure>();
318 }
319
320 return data;
321}
322
Tom Josephbe5eaa12017-07-12 19:54:44 +0530323} // namespace dcmi
Chris Austen1810bec2015-10-13 12:12:39 -0500324
Willy Tu11d68892022-01-20 10:37:34 -0800325ipmi_ret_t getPowerLimit(ipmi_netfn_t, ipmi_cmd_t, ipmi_request_t,
326 ipmi_response_t response, ipmi_data_len_t data_len,
327 ipmi_context_t)
Tom Josephb9d86f42017-07-26 18:03:47 +0530328{
Kirill Pakhomov2c2af2c2018-11-06 16:06:10 +0300329 if (!dcmi::isDCMIPowerMgmtSupported())
330 {
331 *data_len = 0;
332 log<level::ERR>("DCMI Power management is unsupported!");
333 return IPMI_CC_INVALID;
334 }
335
Tom Josephb9d86f42017-07-26 18:03:47 +0530336 std::vector<uint8_t> outPayload(sizeof(dcmi::GetPowerLimitResponse));
Patrick Venture0b02be92018-08-31 11:55:55 -0700337 auto responseData =
338 reinterpret_cast<dcmi::GetPowerLimitResponse*>(outPayload.data());
Tom Josephb9d86f42017-07-26 18:03:47 +0530339
Patrick Williams5d82f472022-07-22 19:26:53 -0500340 sdbusplus::bus_t sdbus{ipmid_get_sd_bus_connection()};
Tom Josephb9d86f42017-07-26 18:03:47 +0530341 uint32_t pcapValue = 0;
342 bool pcapEnable = false;
343
344 try
345 {
346 pcapValue = dcmi::getPcap(sdbus);
347 pcapEnable = dcmi::getPcapEnabled(sdbus);
348 }
Patrick Williamsa2ad2da2021-10-06 12:21:46 -0500349 catch (const InternalFailure& e)
Tom Josephb9d86f42017-07-26 18:03:47 +0530350 {
351 *data_len = 0;
352 return IPMI_CC_UNSPECIFIED_ERROR;
353 }
354
Tom Josephb9d86f42017-07-26 18:03:47 +0530355 /*
356 * Exception action if power limit is exceeded and cannot be controlled
357 * with the correction time limit is hardcoded to Hard Power Off system
358 * and log event to SEL.
359 */
360 constexpr auto exception = 0x01;
361 responseData->exceptionAction = exception;
362
363 responseData->powerLimit = static_cast<uint16_t>(pcapValue);
364
365 /*
366 * Correction time limit and Statistics sampling period is currently not
367 * populated.
368 */
369
370 *data_len = outPayload.size();
371 memcpy(response, outPayload.data(), *data_len);
372
373 if (pcapEnable)
374 {
375 return IPMI_CC_OK;
376 }
377 else
378 {
379 return IPMI_DCMI_CC_NO_ACTIVE_POWER_LIMIT;
380 }
381}
382
Willy Tu11d68892022-01-20 10:37:34 -0800383ipmi_ret_t setPowerLimit(ipmi_netfn_t, ipmi_cmd_t, ipmi_request_t request,
384 ipmi_response_t, ipmi_data_len_t data_len,
385 ipmi_context_t)
Tom Joseph46fa37d2017-07-26 18:11:55 +0530386{
Kirill Pakhomov2c2af2c2018-11-06 16:06:10 +0300387 if (!dcmi::isDCMIPowerMgmtSupported())
388 {
389 *data_len = 0;
390 log<level::ERR>("DCMI Power management is unsupported!");
391 return IPMI_CC_INVALID;
392 }
393
Patrick Venture0b02be92018-08-31 11:55:55 -0700394 auto requestData =
395 reinterpret_cast<const dcmi::SetPowerLimitRequest*>(request);
Tom Joseph46fa37d2017-07-26 18:11:55 +0530396
Patrick Williams5d82f472022-07-22 19:26:53 -0500397 sdbusplus::bus_t sdbus{ipmid_get_sd_bus_connection()};
Tom Joseph46fa37d2017-07-26 18:11:55 +0530398
399 // Only process the power limit requested in watts.
400 try
401 {
402 dcmi::setPcap(sdbus, requestData->powerLimit);
403 }
Patrick Williamsa2ad2da2021-10-06 12:21:46 -0500404 catch (const InternalFailure& e)
Tom Joseph46fa37d2017-07-26 18:11:55 +0530405 {
406 *data_len = 0;
407 return IPMI_CC_UNSPECIFIED_ERROR;
408 }
409
410 log<level::INFO>("Set Power Cap",
411 entry("POWERCAP=%u", requestData->powerLimit));
412
William A. Kennington III5d06cc62019-04-25 02:10:55 -0700413 *data_len = 0;
Tom Joseph46fa37d2017-07-26 18:11:55 +0530414 return IPMI_CC_OK;
415}
416
Willy Tu11d68892022-01-20 10:37:34 -0800417ipmi_ret_t applyPowerLimit(ipmi_netfn_t, ipmi_cmd_t, ipmi_request_t request,
418 ipmi_response_t, ipmi_data_len_t data_len,
419 ipmi_context_t)
Tom Joseph6c8d51b2017-07-26 18:18:06 +0530420{
Kirill Pakhomov2c2af2c2018-11-06 16:06:10 +0300421 if (!dcmi::isDCMIPowerMgmtSupported())
422 {
423 *data_len = 0;
424 log<level::ERR>("DCMI Power management is unsupported!");
425 return IPMI_CC_INVALID;
426 }
427
Patrick Venture0b02be92018-08-31 11:55:55 -0700428 auto requestData =
429 reinterpret_cast<const dcmi::ApplyPowerLimitRequest*>(request);
Tom Joseph6c8d51b2017-07-26 18:18:06 +0530430
Patrick Williams5d82f472022-07-22 19:26:53 -0500431 sdbusplus::bus_t sdbus{ipmid_get_sd_bus_connection()};
Tom Joseph6c8d51b2017-07-26 18:18:06 +0530432
433 try
434 {
435 dcmi::setPcapEnable(sdbus,
436 static_cast<bool>(requestData->powerLimitAction));
437 }
Patrick Williamsa2ad2da2021-10-06 12:21:46 -0500438 catch (const InternalFailure& e)
Tom Joseph6c8d51b2017-07-26 18:18:06 +0530439 {
440 *data_len = 0;
441 return IPMI_CC_UNSPECIFIED_ERROR;
442 }
443
444 log<level::INFO>("Set Power Cap Enable",
445 entry("POWERCAPENABLE=%u", requestData->powerLimitAction));
446
William A. Kennington III5d06cc62019-04-25 02:10:55 -0700447 *data_len = 0;
Tom Joseph6c8d51b2017-07-26 18:18:06 +0530448 return IPMI_CC_OK;
449}
450
Willy Tu11d68892022-01-20 10:37:34 -0800451ipmi_ret_t getAssetTag(ipmi_netfn_t, ipmi_cmd_t, ipmi_request_t request,
452 ipmi_response_t response, ipmi_data_len_t data_len,
453 ipmi_context_t)
Tom Joseph6f6dd4d2017-07-12 20:07:11 +0530454{
Patrick Venture0b02be92018-08-31 11:55:55 -0700455 auto requestData =
456 reinterpret_cast<const dcmi::GetAssetTagRequest*>(request);
Tom Joseph6f6dd4d2017-07-12 20:07:11 +0530457 std::vector<uint8_t> outPayload(sizeof(dcmi::GetAssetTagResponse));
Patrick Venture0b02be92018-08-31 11:55:55 -0700458 auto responseData =
459 reinterpret_cast<dcmi::GetAssetTagResponse*>(outPayload.data());
Tom Joseph6f6dd4d2017-07-12 20:07:11 +0530460
Tom Joseph6f6dd4d2017-07-12 20:07:11 +0530461 // Verify offset to read and number of bytes to read are not exceeding the
462 // range.
463 if ((requestData->offset > dcmi::assetTagMaxOffset) ||
464 (requestData->bytes > dcmi::maxBytes) ||
465 ((requestData->offset + requestData->bytes) > dcmi::assetTagMaxSize))
466 {
467 *data_len = 0;
468 return IPMI_CC_PARM_OUT_OF_RANGE;
469 }
470
471 std::string assetTag;
472
473 try
474 {
475 assetTag = dcmi::readAssetTag();
476 }
Patrick Williamsa2ad2da2021-10-06 12:21:46 -0500477 catch (const InternalFailure& e)
Tom Joseph6f6dd4d2017-07-12 20:07:11 +0530478 {
479 *data_len = 0;
480 return IPMI_CC_UNSPECIFIED_ERROR;
481 }
482
Tom Joseph6f6dd4d2017-07-12 20:07:11 +0530483 // Return if the asset tag is not populated.
484 if (!assetTag.size())
485 {
486 responseData->tagLength = 0;
487 memcpy(response, outPayload.data(), outPayload.size());
488 *data_len = outPayload.size();
489 return IPMI_CC_OK;
490 }
491
492 // If the asset tag is longer than 63 bytes, restrict it to 63 bytes to suit
493 // Get Asset Tag command.
494 if (assetTag.size() > dcmi::assetTagMaxSize)
495 {
496 assetTag.resize(dcmi::assetTagMaxSize);
497 }
498
499 // If the requested offset is beyond the asset tag size.
500 if (requestData->offset >= assetTag.size())
501 {
502 *data_len = 0;
503 return IPMI_CC_PARM_OUT_OF_RANGE;
504 }
505
506 auto returnData = assetTag.substr(requestData->offset, requestData->bytes);
507
508 responseData->tagLength = assetTag.size();
509
510 memcpy(response, outPayload.data(), outPayload.size());
511 memcpy(static_cast<uint8_t*>(response) + outPayload.size(),
512 returnData.data(), returnData.size());
513 *data_len = outPayload.size() + returnData.size();
514
515 return IPMI_CC_OK;
516}
517
Willy Tu11d68892022-01-20 10:37:34 -0800518ipmi_ret_t setAssetTag(ipmi_netfn_t, ipmi_cmd_t, ipmi_request_t request,
519 ipmi_response_t response, ipmi_data_len_t data_len,
520 ipmi_context_t)
Tom Joseph545dd232017-07-12 20:20:49 +0530521{
Patrick Venture0b02be92018-08-31 11:55:55 -0700522 auto requestData =
523 reinterpret_cast<const dcmi::SetAssetTagRequest*>(request);
Tom Joseph545dd232017-07-12 20:20:49 +0530524 std::vector<uint8_t> outPayload(sizeof(dcmi::SetAssetTagResponse));
Patrick Venture0b02be92018-08-31 11:55:55 -0700525 auto responseData =
526 reinterpret_cast<dcmi::SetAssetTagResponse*>(outPayload.data());
Tom Joseph545dd232017-07-12 20:20:49 +0530527
Tom Joseph545dd232017-07-12 20:20:49 +0530528 // Verify offset to read and number of bytes to read are not exceeding the
529 // range.
530 if ((requestData->offset > dcmi::assetTagMaxOffset) ||
531 (requestData->bytes > dcmi::maxBytes) ||
532 ((requestData->offset + requestData->bytes) > dcmi::assetTagMaxSize))
533 {
534 *data_len = 0;
535 return IPMI_CC_PARM_OUT_OF_RANGE;
536 }
537
538 std::string assetTag;
539
540 try
541 {
542 assetTag = dcmi::readAssetTag();
543
544 if (requestData->offset > assetTag.size())
545 {
546 *data_len = 0;
547 return IPMI_CC_PARM_OUT_OF_RANGE;
548 }
549
550 assetTag.replace(requestData->offset,
551 assetTag.size() - requestData->offset,
552 static_cast<const char*>(request) +
Patrick Venture0b02be92018-08-31 11:55:55 -0700553 sizeof(dcmi::SetAssetTagRequest),
Tom Joseph545dd232017-07-12 20:20:49 +0530554 requestData->bytes);
555
556 dcmi::writeAssetTag(assetTag);
557
Tom Joseph545dd232017-07-12 20:20:49 +0530558 responseData->tagLength = assetTag.size();
559 memcpy(response, outPayload.data(), outPayload.size());
560 *data_len = outPayload.size();
561
562 return IPMI_CC_OK;
563 }
Patrick Williamsa2ad2da2021-10-06 12:21:46 -0500564 catch (const InternalFailure& e)
Tom Joseph545dd232017-07-12 20:20:49 +0530565 {
566 *data_len = 0;
567 return IPMI_CC_UNSPECIFIED_ERROR;
568 }
569}
570
Willy Tu11d68892022-01-20 10:37:34 -0800571ipmi_ret_t getMgmntCtrlIdStr(ipmi_netfn_t, ipmi_cmd_t, ipmi_request_t request,
572 ipmi_response_t response, ipmi_data_len_t data_len,
573 ipmi_context_t)
Vladislav Vovchenko8f7a6f62017-08-17 00:31:14 +0300574{
Patrick Venture0b02be92018-08-31 11:55:55 -0700575 auto requestData =
576 reinterpret_cast<const dcmi::GetMgmntCtrlIdStrRequest*>(request);
577 auto responseData =
578 reinterpret_cast<dcmi::GetMgmntCtrlIdStrResponse*>(response);
Vladislav Vovchenko8f7a6f62017-08-17 00:31:14 +0300579 std::string hostName;
580
581 *data_len = 0;
582
William A. Kennington III5d06cc62019-04-25 02:10:55 -0700583 if (requestData->bytes > dcmi::maxBytes ||
Vladislav Vovchenko8f7a6f62017-08-17 00:31:14 +0300584 requestData->offset + requestData->bytes > dcmi::maxCtrlIdStrLen)
585 {
586 return IPMI_CC_INVALID_FIELD_REQUEST;
587 }
588
589 try
590 {
591 hostName = dcmi::getHostName();
592 }
Patrick Williamsa2ad2da2021-10-06 12:21:46 -0500593 catch (const InternalFailure& e)
Vladislav Vovchenko8f7a6f62017-08-17 00:31:14 +0300594 {
595 return IPMI_CC_UNSPECIFIED_ERROR;
596 }
597
598 if (requestData->offset > hostName.length())
599 {
600 return IPMI_CC_PARM_OUT_OF_RANGE;
601 }
602 auto responseStr = hostName.substr(requestData->offset, requestData->bytes);
603 auto responseStrLen = std::min(static_cast<std::size_t>(requestData->bytes),
Patrick Venture0b02be92018-08-31 11:55:55 -0700604 responseStr.length() + 1);
Vladislav Vovchenko8f7a6f62017-08-17 00:31:14 +0300605 responseData->strLen = hostName.length();
606 std::copy(begin(responseStr), end(responseStr), responseData->data);
607
608 *data_len = sizeof(*responseData) + responseStrLen;
609 return IPMI_CC_OK;
610}
611
Willy Tu11d68892022-01-20 10:37:34 -0800612ipmi_ret_t setMgmntCtrlIdStr(ipmi_netfn_t, ipmi_cmd_t, ipmi_request_t request,
613 ipmi_response_t response, ipmi_data_len_t data_len,
614 ipmi_context_t)
Vladislav Vovchenko8f7a6f62017-08-17 00:31:14 +0300615{
616 static std::array<char, dcmi::maxCtrlIdStrLen + 1> newCtrlIdStr;
617
Patrick Venture0b02be92018-08-31 11:55:55 -0700618 auto requestData =
619 reinterpret_cast<const dcmi::SetMgmntCtrlIdStrRequest*>(request);
620 auto responseData =
621 reinterpret_cast<dcmi::SetMgmntCtrlIdStrResponse*>(response);
Vladislav Vovchenko8f7a6f62017-08-17 00:31:14 +0300622
623 *data_len = 0;
624
William A. Kennington III5d06cc62019-04-25 02:10:55 -0700625 if (requestData->bytes > dcmi::maxBytes ||
Vladislav Vovchenko8f7a6f62017-08-17 00:31:14 +0300626 requestData->offset + requestData->bytes > dcmi::maxCtrlIdStrLen + 1 ||
Patrick Venture0b02be92018-08-31 11:55:55 -0700627 (requestData->offset + requestData->bytes ==
628 dcmi::maxCtrlIdStrLen + 1 &&
629 requestData->data[requestData->bytes - 1] != '\0'))
Vladislav Vovchenko8f7a6f62017-08-17 00:31:14 +0300630 {
631 return IPMI_CC_INVALID_FIELD_REQUEST;
632 }
633
634 try
635 {
636 /* if there is no old value and offset is not 0 */
637 if (newCtrlIdStr[0] == '\0' && requestData->offset != 0)
638 {
639 /* read old ctrlIdStr */
640 auto hostName = dcmi::getHostName();
641 hostName.resize(dcmi::maxCtrlIdStrLen);
642 std::copy(begin(hostName), end(hostName), begin(newCtrlIdStr));
643 newCtrlIdStr[hostName.length()] = '\0';
644 }
645
646 /* replace part of string and mark byte after the last as \0 */
Patrick Venture0b02be92018-08-31 11:55:55 -0700647 auto restStrIter =
648 std::copy_n(requestData->data, requestData->bytes,
649 begin(newCtrlIdStr) + requestData->offset);
Vladislav Vovchenko8f7a6f62017-08-17 00:31:14 +0300650 /* if the last written byte is not 64th - add '\0' */
651 if (requestData->offset + requestData->bytes <= dcmi::maxCtrlIdStrLen)
652 {
653 *restStrIter = '\0';
654 }
655
656 /* if input data contains '\0' whole string is sent - update hostname */
657 auto it = std::find(requestData->data,
Patrick Venture0b02be92018-08-31 11:55:55 -0700658 requestData->data + requestData->bytes, '\0');
Vladislav Vovchenko8f7a6f62017-08-17 00:31:14 +0300659 if (it != requestData->data + requestData->bytes)
660 {
Patrick Williams5d82f472022-07-22 19:26:53 -0500661 sdbusplus::bus_t bus{ipmid_get_sd_bus_connection()};
Vladislav Vovchenko8f7a6f62017-08-17 00:31:14 +0300662 ipmi::setDbusProperty(bus, dcmi::networkServiceName,
Patrick Venture0b02be92018-08-31 11:55:55 -0700663 dcmi::networkConfigObj,
664 dcmi::networkConfigIntf, dcmi::hostNameProp,
665 std::string(newCtrlIdStr.data()));
Vladislav Vovchenko8f7a6f62017-08-17 00:31:14 +0300666 }
667 }
Patrick Williamsa2ad2da2021-10-06 12:21:46 -0500668 catch (const InternalFailure& e)
Vladislav Vovchenko8f7a6f62017-08-17 00:31:14 +0300669 {
670 *data_len = 0;
671 return IPMI_CC_UNSPECIFIED_ERROR;
672 }
673
Vladislav Vovchenko8f7a6f62017-08-17 00:31:14 +0300674 responseData->offset = requestData->offset + requestData->bytes;
675 *data_len = sizeof(*responseData);
676 return IPMI_CC_OK;
677}
678
Patrick Venture0b02be92018-08-31 11:55:55 -0700679// List of the capabilities under each parameter
680dcmi::DCMICaps dcmiCaps = {
681 // Supported DCMI Capabilities
682 {dcmi::DCMICapParameters::SUPPORTED_DCMI_CAPS,
683 {3,
684 {{"PowerManagement", 2, 0, 1},
685 {"OOBSecondaryLan", 3, 2, 1},
686 {"SerialTMODE", 3, 1, 1},
687 {"InBandSystemInterfaceChannel", 3, 0, 1}}}},
688 // Mandatory Platform Attributes
689 {dcmi::DCMICapParameters::MANDATORY_PLAT_ATTRIBUTES,
690 {5,
691 {{"SELAutoRollOver", 1, 15, 1},
692 {"FlushEntireSELUponRollOver", 1, 14, 1},
693 {"RecordLevelSELFlushUponRollOver", 1, 13, 1},
694 {"NumberOfSELEntries", 1, 0, 12},
695 {"TempMonitoringSamplingFreq", 5, 0, 8}}}},
696 // Optional Platform Attributes
697 {dcmi::DCMICapParameters::OPTIONAL_PLAT_ATTRIBUTES,
698 {2,
699 {{"PowerMgmtDeviceSlaveAddress", 1, 1, 7},
700 {"BMCChannelNumber", 2, 4, 4},
701 {"DeviceRivision", 2, 0, 4}}}},
702 // Manageability Access Attributes
703 {dcmi::DCMICapParameters::MANAGEABILITY_ACCESS_ATTRIBUTES,
704 {3,
705 {{"MandatoryPrimaryLanOOBSupport", 1, 0, 8},
706 {"OptionalSecondaryLanOOBSupport", 2, 0, 8},
707 {"OptionalSerialOOBMTMODECapability", 3, 0, 8}}}}};
Dhruvaraj Subhashchandrane29be412018-01-16 05:11:56 -0600708
Willy Tu11d68892022-01-20 10:37:34 -0800709ipmi_ret_t getDCMICapabilities(ipmi_netfn_t, ipmi_cmd_t, ipmi_request_t request,
710 ipmi_response_t response,
711 ipmi_data_len_t data_len, ipmi_context_t)
Dhruvaraj Subhashchandrane29be412018-01-16 05:11:56 -0600712{
Kirill Pakhomova2573622018-11-02 19:00:18 +0300713 std::ifstream dcmiCapFile(dcmi::gDCMICapabilitiesConfig);
Dhruvaraj Subhashchandrane29be412018-01-16 05:11:56 -0600714 if (!dcmiCapFile.is_open())
715 {
716 log<level::ERR>("DCMI Capabilities file not found");
717 return IPMI_CC_UNSPECIFIED_ERROR;
718 }
719
720 auto data = nlohmann::json::parse(dcmiCapFile, nullptr, false);
721 if (data.is_discarded())
722 {
723 log<level::ERR>("DCMI Capabilities JSON parser failure");
724 return IPMI_CC_UNSPECIFIED_ERROR;
725 }
726
Patrick Venture0b02be92018-08-31 11:55:55 -0700727 auto requestData =
728 reinterpret_cast<const dcmi::GetDCMICapRequest*>(request);
Dhruvaraj Subhashchandrane29be412018-01-16 05:11:56 -0600729
Patrick Venture0b02be92018-08-31 11:55:55 -0700730 // get list of capabilities in a parameter
Dhruvaraj Subhashchandrane29be412018-01-16 05:11:56 -0600731 auto caps =
732 dcmiCaps.find(static_cast<dcmi::DCMICapParameters>(requestData->param));
733 if (caps == dcmiCaps.end())
734 {
735 log<level::ERR>("Invalid input parameter");
736 return IPMI_CC_INVALID_FIELD_REQUEST;
737 }
738
Patrick Venture0b02be92018-08-31 11:55:55 -0700739 auto responseData = reinterpret_cast<dcmi::GetDCMICapResponse*>(response);
Dhruvaraj Subhashchandrane29be412018-01-16 05:11:56 -0600740
Patrick Venture0b02be92018-08-31 11:55:55 -0700741 // For each capabilities in a parameter fill the data from
742 // the json file based on the capability name.
Dhruvaraj Subhashchandrane29be412018-01-16 05:11:56 -0600743 for (auto cap : caps->second.capList)
744 {
Patrick Venture0b02be92018-08-31 11:55:55 -0700745 // If the data is beyond first byte boundary, insert in a
746 // 16bit pattern for example number of SEL entries are represented
747 // in 12bits.
Kirill Pakhomovdb5d9b02018-11-06 19:17:51 +0300748 if ((cap.length + cap.position) > dcmi::gByteBitSize)
Dhruvaraj Subhashchandrane29be412018-01-16 05:11:56 -0600749 {
Kirill Pakhomovdb5d9b02018-11-06 19:17:51 +0300750 uint16_t val = data.value(cap.name.c_str(), 0);
751 // According to DCMI spec v1.5, max number of SEL entries is
752 // 4096, but bit 12b of DCMI capabilities Mandatory Platform
753 // Attributes field is reserved and therefore we can use only
754 // the provided 12 bits with maximum value of 4095.
755 // We're playing safe here by applying the mask
756 // to ensure that provided value will fit into 12 bits.
757 if (cap.length > dcmi::gByteBitSize)
758 {
759 val &= dcmi::gMaxSELEntriesMask;
760 }
Dhruvaraj Subhashchandrane29be412018-01-16 05:11:56 -0600761 val <<= cap.position;
Kirill Pakhomovdb5d9b02018-11-06 19:17:51 +0300762 responseData->data[cap.bytePosition - 1] |=
763 static_cast<uint8_t>(val);
764 responseData->data[cap.bytePosition] |= val >> dcmi::gByteBitSize;
Dhruvaraj Subhashchandrane29be412018-01-16 05:11:56 -0600765 }
766 else
767 {
768 responseData->data[cap.bytePosition - 1] |=
769 data.value(cap.name.c_str(), 0) << cap.position;
770 }
771 }
772
Dhruvaraj Subhashchandrane29be412018-01-16 05:11:56 -0600773 responseData->major = DCMI_SPEC_MAJOR_VERSION;
774 responseData->minor = DCMI_SPEC_MINOR_VERSION;
775 responseData->paramRevision = DCMI_PARAMETER_REVISION;
776 *data_len = sizeof(*responseData) + caps->second.size;
777
778 return IPMI_CC_OK;
779}
780
Deepak Kodihalliee717d72018-01-24 04:53:09 -0600781namespace dcmi
782{
783namespace temp_readings
784{
785
Deepak Kodihallib1e8fba2018-01-24 04:57:10 -0600786Temperature readTemp(const std::string& dbusService,
787 const std::string& dbusPath)
788{
789 // Read the temperature value from d-bus object. Need some conversion.
790 // As per the interface xyz.openbmc_project.Sensor.Value, the temperature
James Feist9cc0ea52018-10-09 10:53:11 -0700791 // is an double and in degrees C. It needs to be scaled by using the
Deepak Kodihallib1e8fba2018-01-24 04:57:10 -0600792 // formula Value * 10^Scale. The ipmi spec has the temperature as a uint8_t,
793 // with a separate single bit for the sign.
794
Patrick Williams5d82f472022-07-22 19:26:53 -0500795 sdbusplus::bus_t bus{ipmid_get_sd_bus_connection()};
Patrick Venture0b02be92018-08-31 11:55:55 -0700796 auto result = ipmi::getAllDbusProperties(
797 bus, dbusService, dbusPath, "xyz.openbmc_project.Sensor.Value");
Patrick Williamsfbc6c9d2023-05-10 07:50:16 -0500798 auto temperature = std::visit(ipmi::VariantToDoubleVisitor(),
799 result.at("Value"));
James Feist9cc0ea52018-10-09 10:53:11 -0700800 double absTemp = std::abs(temperature);
Deepak Kodihallib1e8fba2018-01-24 04:57:10 -0600801
James Feist9cc0ea52018-10-09 10:53:11 -0700802 auto findFactor = result.find("Scale");
803 double factor = 0.0;
804 if (findFactor != result.end())
Deepak Kodihallib1e8fba2018-01-24 04:57:10 -0600805 {
Vernon Maueryf442e112019-04-09 11:44:36 -0700806 factor = std::visit(ipmi::VariantToDoubleVisitor(), findFactor->second);
Deepak Kodihallib1e8fba2018-01-24 04:57:10 -0600807 }
James Feist9cc0ea52018-10-09 10:53:11 -0700808 double scale = std::pow(10, factor);
809
810 auto tempDegrees = absTemp * scale;
Deepak Kodihallib1e8fba2018-01-24 04:57:10 -0600811 // Max absolute temp as per ipmi spec is 128.
812 if (tempDegrees > maxTemp)
813 {
814 tempDegrees = maxTemp;
815 }
816
817 return std::make_tuple(static_cast<uint8_t>(tempDegrees),
818 (temperature < 0));
819}
820
Deepak Kodihalliee717d72018-01-24 04:53:09 -0600821std::tuple<Response, NumInstances> read(const std::string& type,
822 uint8_t instance)
823{
Deepak Kodihallib1e8fba2018-01-24 04:57:10 -0600824 Response response{};
Patrick Williams5d82f472022-07-22 19:26:53 -0500825 sdbusplus::bus_t bus{ipmid_get_sd_bus_connection()};
Deepak Kodihallib1e8fba2018-01-24 04:57:10 -0600826
827 if (!instance)
828 {
829 log<level::ERR>("Expected non-zero instance");
830 elog<InternalFailure>();
831 }
832
Kirill Pakhomova2573622018-11-02 19:00:18 +0300833 auto data = parseJSONConfig(gDCMISensorsConfig);
Deepak Kodihallib1e8fba2018-01-24 04:57:10 -0600834 static const std::vector<Json> empty{};
835 std::vector<Json> readings = data.value(type, empty);
836 size_t numInstances = readings.size();
837 for (const auto& j : readings)
838 {
839 uint8_t instanceNum = j.value("instance", 0);
840 // Not the instance we're interested in
841 if (instanceNum != instance)
842 {
843 continue;
844 }
845
846 std::string path = j.value("dbus", "");
847 std::string service;
848 try
849 {
Patrick Williamsfbc6c9d2023-05-10 07:50:16 -0500850 service = ipmi::getService(bus, "xyz.openbmc_project.Sensor.Value",
851 path);
Deepak Kodihallib1e8fba2018-01-24 04:57:10 -0600852 }
Patrick Williamsa2ad2da2021-10-06 12:21:46 -0500853 catch (const std::exception& e)
Deepak Kodihallib1e8fba2018-01-24 04:57:10 -0600854 {
855 log<level::DEBUG>(e.what());
856 return std::make_tuple(response, numInstances);
857 }
858
859 response.instance = instance;
860 uint8_t temp{};
861 bool sign{};
862 std::tie(temp, sign) = readTemp(service, path);
863 response.temperature = temp;
864 response.sign = sign;
865
866 // Found the instance we're interested in
867 break;
868 }
869
870 if (numInstances > maxInstances)
871 {
872 numInstances = maxInstances;
873 }
874 return std::make_tuple(response, numInstances);
Deepak Kodihalliee717d72018-01-24 04:53:09 -0600875}
876
877std::tuple<ResponseList, NumInstances> readAll(const std::string& type,
878 uint8_t instanceStart)
879{
Deepak Kodihallib1e8fba2018-01-24 04:57:10 -0600880 ResponseList response{};
Patrick Williams5d82f472022-07-22 19:26:53 -0500881 sdbusplus::bus_t bus{ipmid_get_sd_bus_connection()};
Deepak Kodihallib1e8fba2018-01-24 04:57:10 -0600882
883 size_t numInstances = 0;
Kirill Pakhomova2573622018-11-02 19:00:18 +0300884 auto data = parseJSONConfig(gDCMISensorsConfig);
Deepak Kodihallib1e8fba2018-01-24 04:57:10 -0600885 static const std::vector<Json> empty{};
886 std::vector<Json> readings = data.value(type, empty);
887 numInstances = readings.size();
888 for (const auto& j : readings)
889 {
890 try
891 {
892 // Max of 8 response data sets
893 if (response.size() == maxDataSets)
894 {
895 break;
896 }
897
898 uint8_t instanceNum = j.value("instance", 0);
899 // Not in the instance range we're interested in
900 if (instanceNum < instanceStart)
901 {
902 continue;
903 }
904
905 std::string path = j.value("dbus", "");
906 auto service =
Patrick Venture0b02be92018-08-31 11:55:55 -0700907 ipmi::getService(bus, "xyz.openbmc_project.Sensor.Value", path);
Deepak Kodihallib1e8fba2018-01-24 04:57:10 -0600908
909 Response r{};
910 r.instance = instanceNum;
911 uint8_t temp{};
912 bool sign{};
913 std::tie(temp, sign) = readTemp(service, path);
914 r.temperature = temp;
915 r.sign = sign;
916 response.push_back(r);
917 }
Patrick Williamsa2ad2da2021-10-06 12:21:46 -0500918 catch (const std::exception& e)
Deepak Kodihallib1e8fba2018-01-24 04:57:10 -0600919 {
920 log<level::DEBUG>(e.what());
921 continue;
922 }
923 }
924
925 if (numInstances > maxInstances)
926 {
927 numInstances = maxInstances;
928 }
929 return std::make_tuple(response, numInstances);
Deepak Kodihalliee717d72018-01-24 04:53:09 -0600930}
931
Patrick Venture0b02be92018-08-31 11:55:55 -0700932} // namespace temp_readings
933} // namespace dcmi
Deepak Kodihalliee717d72018-01-24 04:53:09 -0600934
Willy Tu11d68892022-01-20 10:37:34 -0800935ipmi_ret_t getTempReadings(ipmi_netfn_t, ipmi_cmd_t, ipmi_request_t request,
936 ipmi_response_t response, ipmi_data_len_t data_len,
937 ipmi_context_t)
Deepak Kodihalliee717d72018-01-24 04:53:09 -0600938{
Deepak Kodihalliee717d72018-01-24 04:53:09 -0600939 auto requestData =
940 reinterpret_cast<const dcmi::GetTempReadingsRequest*>(request);
941 auto responseData =
942 reinterpret_cast<dcmi::GetTempReadingsResponseHdr*>(response);
943
944 if (*data_len != sizeof(dcmi::GetTempReadingsRequest))
945 {
946 log<level::ERR>("Malformed request data",
947 entry("DATA_SIZE=%d", *data_len));
948 return IPMI_CC_REQ_DATA_LEN_INVALID;
949 }
950 *data_len = 0;
951
Deepak Kodihalli0b459552018-02-06 06:25:12 -0600952 auto it = dcmi::entityIdToName.find(requestData->entityId);
953 if (it == dcmi::entityIdToName.end())
Deepak Kodihalliee717d72018-01-24 04:53:09 -0600954 {
955 log<level::ERR>("Unknown Entity ID",
956 entry("ENTITY_ID=%d", requestData->entityId));
957 return IPMI_CC_INVALID_FIELD_REQUEST;
958 }
959
Deepak Kodihalliee717d72018-01-24 04:53:09 -0600960 if (requestData->sensorType != dcmi::temperatureSensorType)
961 {
962 log<level::ERR>("Invalid sensor type",
963 entry("SENSOR_TYPE=%d", requestData->sensorType));
964 return IPMI_CC_INVALID_FIELD_REQUEST;
965 }
966
967 dcmi::temp_readings::ResponseList temps{};
968 try
969 {
970 if (!requestData->entityInstance)
971 {
972 // Read all instances
973 std::tie(temps, responseData->numInstances) =
974 dcmi::temp_readings::readAll(it->second,
975 requestData->instanceStart);
976 }
977 else
978 {
979 // Read one instance
980 temps.resize(1);
981 std::tie(temps[0], responseData->numInstances) =
982 dcmi::temp_readings::read(it->second,
983 requestData->entityInstance);
984 }
985 responseData->numDataSets = temps.size();
986 }
Patrick Williamsa2ad2da2021-10-06 12:21:46 -0500987 catch (const InternalFailure& e)
Deepak Kodihalliee717d72018-01-24 04:53:09 -0600988 {
989 return IPMI_CC_UNSPECIFIED_ERROR;
990 }
991
Patrick Venture0b02be92018-08-31 11:55:55 -0700992 size_t payloadSize = temps.size() * sizeof(dcmi::temp_readings::Response);
Deepak Kodihalliee717d72018-01-24 04:53:09 -0600993 if (!temps.empty())
994 {
995 memcpy(responseData + 1, // copy payload right after the response header
Patrick Venture0b02be92018-08-31 11:55:55 -0700996 temps.data(), payloadSize);
Deepak Kodihalliee717d72018-01-24 04:53:09 -0600997 }
998 *data_len = sizeof(dcmi::GetTempReadingsResponseHdr) + payloadSize;
999
1000 return IPMI_CC_OK;
1001}
1002
Patrick Williams5d82f472022-07-22 19:26:53 -05001003int64_t getPowerReading(sdbusplus::bus_t& bus)
Marri Devender Rao66c5fda2018-01-18 10:48:37 -06001004{
1005 std::ifstream sensorFile(POWER_READING_SENSOR);
1006 std::string objectPath;
1007 if (!sensorFile.is_open())
1008 {
1009 log<level::ERR>("Power reading configuration file not found",
Patrick Venture0b02be92018-08-31 11:55:55 -07001010 entry("POWER_SENSOR_FILE=%s", POWER_READING_SENSOR));
Marri Devender Rao66c5fda2018-01-18 10:48:37 -06001011 elog<InternalFailure>();
1012 }
1013
1014 auto data = nlohmann::json::parse(sensorFile, nullptr, false);
1015 if (data.is_discarded())
1016 {
1017 log<level::ERR>("Error in parsing configuration file",
Patrick Venture0b02be92018-08-31 11:55:55 -07001018 entry("POWER_SENSOR_FILE=%s", POWER_READING_SENSOR));
Marri Devender Rao66c5fda2018-01-18 10:48:37 -06001019 elog<InternalFailure>();
1020 }
1021
1022 objectPath = data.value("path", "");
1023 if (objectPath.empty())
1024 {
1025 log<level::ERR>("Power sensor D-Bus object path is empty",
1026 entry("POWER_SENSOR_FILE=%s", POWER_READING_SENSOR));
1027 elog<InternalFailure>();
1028 }
1029
Marri Devender Raoce6a7952018-02-11 08:45:00 -06001030 // Return default value if failed to read from D-Bus object
1031 int64_t power = 0;
1032 try
1033 {
1034 auto service = ipmi::getService(bus, SENSOR_VALUE_INTF, objectPath);
Marri Devender Rao66c5fda2018-01-18 10:48:37 -06001035
Patrick Venture0b02be92018-08-31 11:55:55 -07001036 // Read the sensor value and scale properties
Chris Cain4cc61e02022-01-12 17:23:14 -06001037 auto value = ipmi::getDbusProperty(
1038 bus, service, objectPath, SENSOR_VALUE_INTF, SENSOR_VALUE_PROP);
1039 power = std::get<double>(value);
Marri Devender Raoce6a7952018-02-11 08:45:00 -06001040 }
Patrick Williamsa2ad2da2021-10-06 12:21:46 -05001041 catch (const std::exception& e)
Marri Devender Raoce6a7952018-02-11 08:45:00 -06001042 {
Chris Cain4cc61e02022-01-12 17:23:14 -06001043 log<level::ERR>("Failure to read power value from D-Bus object",
1044 entry("OBJECT_PATH=%s", objectPath.c_str()),
1045 entry("INTERFACE=%s", SENSOR_VALUE_INTF));
Marri Devender Raoce6a7952018-02-11 08:45:00 -06001046 }
Marri Devender Rao66c5fda2018-01-18 10:48:37 -06001047 return power;
1048}
1049
Willy Tu11d68892022-01-20 10:37:34 -08001050ipmi_ret_t setDCMIConfParams(ipmi_netfn_t, ipmi_cmd_t, ipmi_request_t request,
1051 ipmi_response_t, ipmi_data_len_t data_len,
1052 ipmi_context_t)
Nagaraju Goruganti22be97b2018-02-07 01:19:59 -06001053{
Patrick Venture0b02be92018-08-31 11:55:55 -07001054 auto requestData =
1055 reinterpret_cast<const dcmi::SetConfParamsRequest*>(request);
Nagaraju Goruganti22be97b2018-02-07 01:19:59 -06001056
William A. Kennington III5d06cc62019-04-25 02:10:55 -07001057 if (*data_len < DCMI_SET_CONF_PARAM_REQ_PACKET_MIN_SIZE ||
Patrick Venture0b02be92018-08-31 11:55:55 -07001058 *data_len > DCMI_SET_CONF_PARAM_REQ_PACKET_MAX_SIZE)
Nagaraju Goruganti22be97b2018-02-07 01:19:59 -06001059 {
William A. Kennington III5d06cc62019-04-25 02:10:55 -07001060 log<level::ERR>("Invalid Requested Packet size",
Nagaraju Goruganti22be97b2018-02-07 01:19:59 -06001061 entry("PACKET SIZE=%d", *data_len));
William A. Kennington III5d06cc62019-04-25 02:10:55 -07001062 *data_len = 0;
Nagaraju Goruganti22be97b2018-02-07 01:19:59 -06001063 return IPMI_CC_INVALID_FIELD_REQUEST;
1064 }
Nagaraju Goruganti22be97b2018-02-07 01:19:59 -06001065 *data_len = 0;
1066
1067 try
1068 {
1069 // Take action based on the Parameter Selector
Patrick Venture0b02be92018-08-31 11:55:55 -07001070 switch (
1071 static_cast<dcmi::DCMIConfigParameters>(requestData->paramSelect))
Nagaraju Goruganti22be97b2018-02-07 01:19:59 -06001072 {
1073 case dcmi::DCMIConfigParameters::ActivateDHCP:
1074
1075 if ((requestData->data[0] & DCMI_ACTIVATE_DHCP_MASK) &&
Thang Tran55cbf552023-01-31 14:43:02 +07001076 (dcmi::getDHCPEnabled() !=
1077 EthernetInterface::DHCPConf::none))
Nagaraju Goruganti22be97b2018-02-07 01:19:59 -06001078 {
Patrick Venture0b02be92018-08-31 11:55:55 -07001079 // When these conditions are met we have to trigger DHCP
1080 // protocol restart using the latest parameter settings, but
1081 // as per n/w manager design, each time when we update n/w
1082 // parameters, n/w service is restarted. So we no need to
1083 // take any action in this case.
Nagaraju Goruganti22be97b2018-02-07 01:19:59 -06001084 }
1085 break;
1086
1087 case dcmi::DCMIConfigParameters::DiscoveryConfig:
1088
1089 if (requestData->data[0] & DCMI_OPTION_12_MASK)
1090 {
1091 dcmi::setDHCPOption(DHCP_OPT12_ENABLED, true);
1092 }
1093 else
1094 {
1095 dcmi::setDHCPOption(DHCP_OPT12_ENABLED, false);
1096 }
1097
1098 // Systemd-networkd doesn't support Random Back off
1099 if (requestData->data[0] & DCMI_RAND_BACK_OFF_MASK)
1100 {
1101 return IPMI_CC_INVALID;
1102 }
1103 break;
1104 // Systemd-networkd doesn't allow to configure DHCP timigs
1105 case dcmi::DCMIConfigParameters::DHCPTiming1:
1106 case dcmi::DCMIConfigParameters::DHCPTiming2:
1107 case dcmi::DCMIConfigParameters::DHCPTiming3:
1108 default:
1109 return IPMI_CC_INVALID;
1110 }
1111 }
Patrick Williamsa2ad2da2021-10-06 12:21:46 -05001112 catch (const std::exception& e)
Nagaraju Goruganti22be97b2018-02-07 01:19:59 -06001113 {
1114 log<level::ERR>(e.what());
1115 return IPMI_CC_UNSPECIFIED_ERROR;
1116 }
Nagaraju Goruganti22be97b2018-02-07 01:19:59 -06001117 return IPMI_CC_OK;
1118}
1119
Willy Tu11d68892022-01-20 10:37:34 -08001120ipmi_ret_t getDCMIConfParams(ipmi_netfn_t, ipmi_cmd_t, ipmi_request_t request,
1121 ipmi_response_t response, ipmi_data_len_t data_len,
1122 ipmi_context_t)
Nagaraju Goruganti22be97b2018-02-07 01:19:59 -06001123{
Patrick Venture0b02be92018-08-31 11:55:55 -07001124 auto requestData =
1125 reinterpret_cast<const dcmi::GetConfParamsRequest*>(request);
1126 auto responseData =
1127 reinterpret_cast<dcmi::GetConfParamsResponse*>(response);
Nagaraju Goruganti22be97b2018-02-07 01:19:59 -06001128
1129 responseData->data[0] = 0x00;
1130
William A. Kennington III5d06cc62019-04-25 02:10:55 -07001131 if (*data_len != sizeof(dcmi::GetConfParamsRequest))
Nagaraju Goruganti22be97b2018-02-07 01:19:59 -06001132 {
William A. Kennington III5d06cc62019-04-25 02:10:55 -07001133 log<level::ERR>("Invalid Requested Packet size",
Nagaraju Goruganti22be97b2018-02-07 01:19:59 -06001134 entry("PACKET SIZE=%d", *data_len));
1135 return IPMI_CC_INVALID_FIELD_REQUEST;
1136 }
1137
1138 *data_len = 0;
1139
1140 try
1141 {
1142 // Take action based on the Parameter Selector
Patrick Venture0b02be92018-08-31 11:55:55 -07001143 switch (
1144 static_cast<dcmi::DCMIConfigParameters>(requestData->paramSelect))
Nagaraju Goruganti22be97b2018-02-07 01:19:59 -06001145 {
1146 case dcmi::DCMIConfigParameters::ActivateDHCP:
1147 responseData->data[0] = DCMI_ACTIVATE_DHCP_REPLY;
1148 *data_len = sizeof(dcmi::GetConfParamsResponse) + 1;
1149 break;
1150 case dcmi::DCMIConfigParameters::DiscoveryConfig:
1151 if (dcmi::getDHCPOption(DHCP_OPT12_ENABLED))
1152 {
1153 responseData->data[0] |= DCMI_OPTION_12_MASK;
1154 }
1155 *data_len = sizeof(dcmi::GetConfParamsResponse) + 1;
1156 break;
1157 // Get below values from Systemd-networkd source code
1158 case dcmi::DCMIConfigParameters::DHCPTiming1:
1159 responseData->data[0] = DHCP_TIMING1;
1160 *data_len = sizeof(dcmi::GetConfParamsResponse) + 1;
1161 break;
1162 case dcmi::DCMIConfigParameters::DHCPTiming2:
1163 responseData->data[0] = DHCP_TIMING2_LOWER;
1164 responseData->data[1] = DHCP_TIMING2_UPPER;
1165 *data_len = sizeof(dcmi::GetConfParamsResponse) + 2;
1166 break;
1167 case dcmi::DCMIConfigParameters::DHCPTiming3:
1168 responseData->data[0] = DHCP_TIMING3_LOWER;
1169 responseData->data[1] = DHCP_TIMING3_UPPER;
1170 *data_len = sizeof(dcmi::GetConfParamsResponse) + 2;
1171 break;
1172 default:
1173 *data_len = 0;
1174 return IPMI_CC_INVALID;
1175 }
1176 }
Patrick Williamsa2ad2da2021-10-06 12:21:46 -05001177 catch (const std::exception& e)
Nagaraju Goruganti22be97b2018-02-07 01:19:59 -06001178 {
1179 log<level::ERR>(e.what());
1180 return IPMI_CC_UNSPECIFIED_ERROR;
1181 }
1182
Nagaraju Goruganti22be97b2018-02-07 01:19:59 -06001183 responseData->major = DCMI_SPEC_MAJOR_VERSION;
1184 responseData->minor = DCMI_SPEC_MINOR_VERSION;
1185 responseData->paramRevision = DCMI_CONFIG_PARAMETER_REVISION;
1186
1187 return IPMI_CC_OK;
1188}
1189
Willy Tu11d68892022-01-20 10:37:34 -08001190ipmi_ret_t getPowerReading(ipmi_netfn_t, ipmi_cmd_t, ipmi_request_t,
1191 ipmi_response_t response, ipmi_data_len_t data_len,
1192 ipmi_context_t)
Marri Devender Rao66c5fda2018-01-18 10:48:37 -06001193{
Chalapathi Venkataramashetty90e81fa2021-05-11 09:13:23 +00001194 *data_len = 0;
Kirill Pakhomov2c2af2c2018-11-06 16:06:10 +03001195 if (!dcmi::isDCMIPowerMgmtSupported())
1196 {
Kirill Pakhomov2c2af2c2018-11-06 16:06:10 +03001197 log<level::ERR>("DCMI Power management is unsupported!");
1198 return IPMI_CC_INVALID;
1199 }
1200
Marri Devender Rao66c5fda2018-01-18 10:48:37 -06001201 ipmi_ret_t rc = IPMI_CC_OK;
Patrick Venture0b02be92018-08-31 11:55:55 -07001202 auto responseData =
1203 reinterpret_cast<dcmi::GetPowerReadingResponse*>(response);
Marri Devender Rao9c966e02018-01-22 05:55:10 -06001204
Patrick Williams5d82f472022-07-22 19:26:53 -05001205 sdbusplus::bus_t bus{ipmid_get_sd_bus_connection()};
Marri Devender Rao9c966e02018-01-22 05:55:10 -06001206 int64_t power = 0;
Marri Devender Rao66c5fda2018-01-18 10:48:37 -06001207 try
1208 {
Marri Devender Rao9c966e02018-01-22 05:55:10 -06001209 power = getPowerReading(bus);
Marri Devender Rao66c5fda2018-01-18 10:48:37 -06001210 }
Patrick Williamsa2ad2da2021-10-06 12:21:46 -05001211 catch (const InternalFailure& e)
Marri Devender Rao66c5fda2018-01-18 10:48:37 -06001212 {
1213 log<level::ERR>("Error in reading power sensor value",
1214 entry("INTERFACE=%s", SENSOR_VALUE_INTF),
1215 entry("PROPERTY=%s", SENSOR_VALUE_PROP));
1216 return IPMI_CC_UNSPECIFIED_ERROR;
1217 }
Marri Devender Rao9c966e02018-01-22 05:55:10 -06001218
1219 // TODO: openbmc/openbmc#2819
Gunnar Mills8466b792018-03-23 12:18:12 -05001220 // Minimum, Maximum, Average power, TimeFrame, TimeStamp,
Marri Devender Rao9c966e02018-01-22 05:55:10 -06001221 // PowerReadingState readings need to be populated
1222 // after Telemetry changes.
1223 uint16_t totalPower = static_cast<uint16_t>(power);
1224 responseData->currentPower = totalPower;
1225 responseData->minimumPower = totalPower;
1226 responseData->maximumPower = totalPower;
1227 responseData->averagePower = totalPower;
1228
1229 *data_len = sizeof(*responseData);
Marri Devender Rao66c5fda2018-01-18 10:48:37 -06001230 return rc;
1231}
1232
Deepak Kodihalli0b459552018-02-06 06:25:12 -06001233namespace dcmi
1234{
1235namespace sensor_info
1236{
1237
Deepak Kodihallidd4cff12018-02-06 06:48:29 -06001238Response createFromJson(const Json& config)
1239{
1240 Response response{};
1241 uint16_t recordId = config.value("record_id", 0);
1242 response.recordIdLsb = recordId & 0xFF;
1243 response.recordIdMsb = (recordId >> 8) & 0xFF;
1244 return response;
1245}
1246
Deepak Kodihalli0b459552018-02-06 06:25:12 -06001247std::tuple<Response, NumInstances> read(const std::string& type,
Patrick Venture0b02be92018-08-31 11:55:55 -07001248 uint8_t instance, const Json& config)
Deepak Kodihalli0b459552018-02-06 06:25:12 -06001249{
Deepak Kodihallidd4cff12018-02-06 06:48:29 -06001250 Response response{};
1251
1252 if (!instance)
1253 {
1254 log<level::ERR>("Expected non-zero instance");
1255 elog<InternalFailure>();
1256 }
1257
1258 static const std::vector<Json> empty{};
1259 std::vector<Json> readings = config.value(type, empty);
1260 size_t numInstances = readings.size();
1261 for (const auto& reading : readings)
1262 {
1263 uint8_t instanceNum = reading.value("instance", 0);
1264 // Not the instance we're interested in
1265 if (instanceNum != instance)
1266 {
1267 continue;
1268 }
1269
1270 response = createFromJson(reading);
1271
1272 // Found the instance we're interested in
1273 break;
1274 }
1275
1276 if (numInstances > maxInstances)
1277 {
1278 log<level::DEBUG>("Trimming IPMI num instances",
1279 entry("NUM_INSTANCES=%d", numInstances));
1280 numInstances = maxInstances;
1281 }
1282 return std::make_tuple(response, numInstances);
Deepak Kodihalli0b459552018-02-06 06:25:12 -06001283}
1284
Patrick Venture0b02be92018-08-31 11:55:55 -07001285std::tuple<ResponseList, NumInstances>
1286 readAll(const std::string& type, uint8_t instanceStart, const Json& config)
Deepak Kodihalli0b459552018-02-06 06:25:12 -06001287{
Deepak Kodihallidd4cff12018-02-06 06:48:29 -06001288 ResponseList responses{};
1289
1290 size_t numInstances = 0;
1291 static const std::vector<Json> empty{};
1292 std::vector<Json> readings = config.value(type, empty);
1293 numInstances = readings.size();
1294 for (const auto& reading : readings)
1295 {
1296 try
1297 {
1298 // Max of 8 records
1299 if (responses.size() == maxRecords)
1300 {
1301 break;
1302 }
1303
1304 uint8_t instanceNum = reading.value("instance", 0);
1305 // Not in the instance range we're interested in
1306 if (instanceNum < instanceStart)
1307 {
1308 continue;
1309 }
1310
1311 Response response = createFromJson(reading);
1312 responses.push_back(response);
1313 }
Patrick Williamsa2ad2da2021-10-06 12:21:46 -05001314 catch (const std::exception& e)
Deepak Kodihallidd4cff12018-02-06 06:48:29 -06001315 {
1316 log<level::DEBUG>(e.what());
1317 continue;
1318 }
1319 }
1320
1321 if (numInstances > maxInstances)
1322 {
1323 log<level::DEBUG>("Trimming IPMI num instances",
1324 entry("NUM_INSTANCES=%d", numInstances));
1325 numInstances = maxInstances;
1326 }
1327 return std::make_tuple(responses, numInstances);
Deepak Kodihalli0b459552018-02-06 06:25:12 -06001328}
1329
1330} // namespace sensor_info
1331} // namespace dcmi
1332
Willy Tu11d68892022-01-20 10:37:34 -08001333ipmi_ret_t getSensorInfo(ipmi_netfn_t, ipmi_cmd_t, ipmi_request_t request,
1334 ipmi_response_t response, ipmi_data_len_t data_len,
1335 ipmi_context_t)
Deepak Kodihalli0b459552018-02-06 06:25:12 -06001336{
1337 auto requestData =
1338 reinterpret_cast<const dcmi::GetSensorInfoRequest*>(request);
1339 auto responseData =
1340 reinterpret_cast<dcmi::GetSensorInfoResponseHdr*>(response);
1341
1342 if (*data_len != sizeof(dcmi::GetSensorInfoRequest))
1343 {
1344 log<level::ERR>("Malformed request data",
1345 entry("DATA_SIZE=%d", *data_len));
1346 return IPMI_CC_REQ_DATA_LEN_INVALID;
1347 }
1348 *data_len = 0;
1349
1350 auto it = dcmi::entityIdToName.find(requestData->entityId);
1351 if (it == dcmi::entityIdToName.end())
1352 {
1353 log<level::ERR>("Unknown Entity ID",
1354 entry("ENTITY_ID=%d", requestData->entityId));
1355 return IPMI_CC_INVALID_FIELD_REQUEST;
1356 }
1357
Deepak Kodihalli0b459552018-02-06 06:25:12 -06001358 if (requestData->sensorType != dcmi::temperatureSensorType)
1359 {
1360 log<level::ERR>("Invalid sensor type",
1361 entry("SENSOR_TYPE=%d", requestData->sensorType));
1362 return IPMI_CC_INVALID_FIELD_REQUEST;
1363 }
1364
1365 dcmi::sensor_info::ResponseList sensors{};
1366 static dcmi::Json config{};
1367 static bool parsed = false;
1368
1369 try
1370 {
1371 if (!parsed)
1372 {
Kirill Pakhomova2573622018-11-02 19:00:18 +03001373 config = dcmi::parseJSONConfig(dcmi::gDCMISensorsConfig);
Deepak Kodihalli0b459552018-02-06 06:25:12 -06001374 parsed = true;
1375 }
1376
1377 if (!requestData->entityInstance)
1378 {
1379 // Read all instances
1380 std::tie(sensors, responseData->numInstances) =
1381 dcmi::sensor_info::readAll(it->second,
Patrick Venture0b02be92018-08-31 11:55:55 -07001382 requestData->instanceStart, config);
Deepak Kodihalli0b459552018-02-06 06:25:12 -06001383 }
1384 else
1385 {
1386 // Read one instance
1387 sensors.resize(1);
1388 std::tie(sensors[0], responseData->numInstances) =
Patrick Venture0b02be92018-08-31 11:55:55 -07001389 dcmi::sensor_info::read(it->second, requestData->entityInstance,
Deepak Kodihalli0b459552018-02-06 06:25:12 -06001390 config);
1391 }
1392 responseData->numRecords = sensors.size();
1393 }
Patrick Williamsa2ad2da2021-10-06 12:21:46 -05001394 catch (const InternalFailure& e)
Deepak Kodihalli0b459552018-02-06 06:25:12 -06001395 {
1396 return IPMI_CC_UNSPECIFIED_ERROR;
1397 }
1398
Deepak Kodihalli0b459552018-02-06 06:25:12 -06001399 size_t payloadSize = sensors.size() * sizeof(dcmi::sensor_info::Response);
1400 if (!sensors.empty())
1401 {
1402 memcpy(responseData + 1, // copy payload right after the response header
Patrick Venture0b02be92018-08-31 11:55:55 -07001403 sensors.data(), payloadSize);
Deepak Kodihalli0b459552018-02-06 06:25:12 -06001404 }
1405 *data_len = sizeof(dcmi::GetSensorInfoResponseHdr) + payloadSize;
1406
1407 return IPMI_CC_OK;
1408}
1409
Chris Austen1810bec2015-10-13 12:12:39 -05001410void register_netfn_dcmi_functions()
1411{
Tom05732372016-09-06 17:21:23 +05301412 // <Get Power Limit>
Ratan Gupta11ddbd22017-08-05 11:59:39 +05301413
Patrick Venture0b02be92018-08-31 11:55:55 -07001414 ipmi_register_callback(NETFUN_GRPEXT, dcmi::Commands::GET_POWER_LIMIT, NULL,
1415 getPowerLimit, PRIVILEGE_USER);
Tom Joseph6f6dd4d2017-07-12 20:07:11 +05301416
Tom Joseph46fa37d2017-07-26 18:11:55 +05301417 // <Set Power Limit>
Ratan Gupta11ddbd22017-08-05 11:59:39 +05301418
Patrick Venture0b02be92018-08-31 11:55:55 -07001419 ipmi_register_callback(NETFUN_GRPEXT, dcmi::Commands::SET_POWER_LIMIT, NULL,
1420 setPowerLimit, PRIVILEGE_OPERATOR);
Tom Joseph46fa37d2017-07-26 18:11:55 +05301421
Tom Joseph6c8d51b2017-07-26 18:18:06 +05301422 // <Activate/Deactivate Power Limit>
Ratan Gupta11ddbd22017-08-05 11:59:39 +05301423
1424 ipmi_register_callback(NETFUN_GRPEXT, dcmi::Commands::APPLY_POWER_LIMIT,
1425 NULL, applyPowerLimit, PRIVILEGE_OPERATOR);
Tom Joseph6c8d51b2017-07-26 18:18:06 +05301426
Tom Joseph6f6dd4d2017-07-12 20:07:11 +05301427 // <Get Asset Tag>
Ratan Gupta11ddbd22017-08-05 11:59:39 +05301428
Patrick Venture0b02be92018-08-31 11:55:55 -07001429 ipmi_register_callback(NETFUN_GRPEXT, dcmi::Commands::GET_ASSET_TAG, NULL,
1430 getAssetTag, PRIVILEGE_USER);
Tom Joseph545dd232017-07-12 20:20:49 +05301431
1432 // <Set Asset Tag>
Ratan Gupta11ddbd22017-08-05 11:59:39 +05301433
Patrick Venture0b02be92018-08-31 11:55:55 -07001434 ipmi_register_callback(NETFUN_GRPEXT, dcmi::Commands::SET_ASSET_TAG, NULL,
1435 setAssetTag, PRIVILEGE_OPERATOR);
Vladislav Vovchenko8f7a6f62017-08-17 00:31:14 +03001436
Gunnar Mills8991dd62017-10-25 17:11:29 -05001437 // <Get Management Controller Identifier String>
Vladislav Vovchenko8f7a6f62017-08-17 00:31:14 +03001438
1439 ipmi_register_callback(NETFUN_GRPEXT, dcmi::Commands::GET_MGMNT_CTRL_ID_STR,
Patrick Venture0b02be92018-08-31 11:55:55 -07001440 NULL, getMgmntCtrlIdStr, PRIVILEGE_USER);
Vladislav Vovchenko8f7a6f62017-08-17 00:31:14 +03001441
1442 // <Set Management Controller Identifier String>
Vladislav Vovchenko8f7a6f62017-08-17 00:31:14 +03001443 ipmi_register_callback(NETFUN_GRPEXT, dcmi::Commands::SET_MGMNT_CTRL_ID_STR,
Patrick Venture0b02be92018-08-31 11:55:55 -07001444 NULL, setMgmntCtrlIdStr, PRIVILEGE_ADMIN);
Vladislav Vovchenko8f7a6f62017-08-17 00:31:14 +03001445
Dhruvaraj Subhashchandrane29be412018-01-16 05:11:56 -06001446 // <Get DCMI capabilities>
1447 ipmi_register_callback(NETFUN_GRPEXT, dcmi::Commands::GET_CAPABILITIES,
Patrick Venture0b02be92018-08-31 11:55:55 -07001448 NULL, getDCMICapabilities, PRIVILEGE_USER);
Deepak Kodihalliee717d72018-01-24 04:53:09 -06001449
1450 // <Get Temperature Readings>
1451 ipmi_register_callback(NETFUN_GRPEXT, dcmi::Commands::GET_TEMP_READINGS,
1452 NULL, getTempReadings, PRIVILEGE_USER);
1453
Marri Devender Rao66c5fda2018-01-18 10:48:37 -06001454 // <Get Power Reading>
1455 ipmi_register_callback(NETFUN_GRPEXT, dcmi::Commands::GET_POWER_READING,
1456 NULL, getPowerReading, PRIVILEGE_USER);
adarshgrami042e9db2022-09-15 10:34:34 +05301457// The Get sensor should get the senor details dynamically when
1458// FEATURE_DYNAMIC_SENSORS is enabled.
1459#ifndef FEATURE_DYNAMIC_SENSORS
Deepak Kodihalli0b459552018-02-06 06:25:12 -06001460 // <Get Sensor Info>
Patrick Venture0b02be92018-08-31 11:55:55 -07001461 ipmi_register_callback(NETFUN_GRPEXT, dcmi::Commands::GET_SENSOR_INFO, NULL,
Chau Lyd74df5f2023-05-25 10:33:00 +00001462 getSensorInfo, PRIVILEGE_OPERATOR);
adarshgrami042e9db2022-09-15 10:34:34 +05301463#endif
Nagaraju Goruganti22be97b2018-02-07 01:19:59 -06001464 // <Get DCMI Configuration Parameters>
Patrick Venture0b02be92018-08-31 11:55:55 -07001465 ipmi_register_callback(NETFUN_GRPEXT, dcmi::Commands::GET_CONF_PARAMS, NULL,
1466 getDCMIConfParams, PRIVILEGE_USER);
Nagaraju Goruganti22be97b2018-02-07 01:19:59 -06001467
1468 // <Set DCMI Configuration Parameters>
Patrick Venture0b02be92018-08-31 11:55:55 -07001469 ipmi_register_callback(NETFUN_GRPEXT, dcmi::Commands::SET_CONF_PARAMS, NULL,
1470 setDCMIConfParams, PRIVILEGE_ADMIN);
Nagaraju Goruganti22be97b2018-02-07 01:19:59 -06001471
Chris Austen1810bec2015-10-13 12:12:39 -05001472 return;
1473}
Tom05732372016-09-06 17:21:23 +05301474// 956379