blob: 80522149c48eab8243f93fd3d955413092408649 [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{
Vernon Maueryf4eb35d2023-07-27 11:08:49 -070071 static bool parsed = false;
72 static bool supported = false;
73 if (!parsed)
74 {
75 auto data = parseJSONConfig(gDCMICapabilitiesConfig);
Kirill Pakhomov2c2af2c2018-11-06 16:06:10 +030076
Vernon Maueryf4eb35d2023-07-27 11:08:49 -070077 supported = (gDCMIPowerMgmtSupported ==
78 data.value(gDCMIPowerMgmtCapability, 0));
79 }
80 return supported;
Kirill Pakhomov2c2af2c2018-11-06 16:06:10 +030081}
82
Patrick Williams5d82f472022-07-22 19:26:53 -050083uint32_t getPcap(sdbusplus::bus_t& bus)
Andrew Geissler50c0c8f2017-07-11 16:18:51 -050084{
Patrick Venture0b02be92018-08-31 11:55:55 -070085 auto settingService = ipmi::getService(bus, PCAP_INTERFACE, PCAP_PATH);
Andrew Geissler50c0c8f2017-07-11 16:18:51 -050086
Patrick Venture0b02be92018-08-31 11:55:55 -070087 auto method = bus.new_method_call(settingService.c_str(), PCAP_PATH,
88 "org.freedesktop.DBus.Properties", "Get");
Andrew Geissler50c0c8f2017-07-11 16:18:51 -050089
90 method.append(PCAP_INTERFACE, POWER_CAP_PROP);
Andrew Geissler50c0c8f2017-07-11 16:18:51 -050091
George Liu3e3cc352023-07-26 15:59:31 +080092 std::variant<uint32_t> pcap;
93 try
Andrew Geissler50c0c8f2017-07-11 16:18:51 -050094 {
George Liu3e3cc352023-07-26 15:59:31 +080095 auto reply = bus.call(method);
96 reply.read(pcap);
97 return std::get<uint32_t>(pcap);
98 }
99 catch (const std::exception& e)
100 {
101 log<level::ERR>("Error in getPcap prop", entry("ERROR=%s", e.what()));
Tom Josephb9d86f42017-07-26 18:03:47 +0530102 elog<InternalFailure>();
Andrew Geissler50c0c8f2017-07-11 16:18:51 -0500103 }
Andrew Geissler50c0c8f2017-07-11 16:18:51 -0500104}
105
Patrick Williams5d82f472022-07-22 19:26:53 -0500106bool getPcapEnabled(sdbusplus::bus_t& bus)
Andrew Geissler50c0c8f2017-07-11 16:18:51 -0500107{
Patrick Venture0b02be92018-08-31 11:55:55 -0700108 auto settingService = ipmi::getService(bus, PCAP_INTERFACE, PCAP_PATH);
Andrew Geissler50c0c8f2017-07-11 16:18:51 -0500109
Patrick Venture0b02be92018-08-31 11:55:55 -0700110 auto method = bus.new_method_call(settingService.c_str(), PCAP_PATH,
111 "org.freedesktop.DBus.Properties", "Get");
Andrew Geissler50c0c8f2017-07-11 16:18:51 -0500112
113 method.append(PCAP_INTERFACE, POWER_CAP_ENABLE_PROP);
Andrew Geissler50c0c8f2017-07-11 16:18:51 -0500114
George Liu3e3cc352023-07-26 15:59:31 +0800115 std::variant<bool> pcapEnabled;
116 try
Andrew Geissler50c0c8f2017-07-11 16:18:51 -0500117 {
George Liu3e3cc352023-07-26 15:59:31 +0800118 auto reply = bus.call(method);
119 reply.read(pcapEnabled);
120 return std::get<bool>(pcapEnabled);
121 }
122 catch (const std::exception& e)
123 {
124 log<level::ERR>("Error in getPcapEnabled prop",
125 entry("ERROR=%s", e.what()));
Tom Josephb9d86f42017-07-26 18:03:47 +0530126 elog<InternalFailure>();
Andrew Geissler50c0c8f2017-07-11 16:18:51 -0500127 }
Andrew Geissler50c0c8f2017-07-11 16:18:51 -0500128}
Chris Austen1810bec2015-10-13 12:12:39 -0500129
Patrick Williams5d82f472022-07-22 19:26:53 -0500130void setPcap(sdbusplus::bus_t& bus, const uint32_t powerCap)
Tom Joseph46fa37d2017-07-26 18:11:55 +0530131{
132 auto service = ipmi::getService(bus, PCAP_INTERFACE, PCAP_PATH);
133
Patrick Venture0b02be92018-08-31 11:55:55 -0700134 auto method = bus.new_method_call(service.c_str(), PCAP_PATH,
135 "org.freedesktop.DBus.Properties", "Set");
Tom Joseph46fa37d2017-07-26 18:11:55 +0530136
137 method.append(PCAP_INTERFACE, POWER_CAP_PROP);
Vernon Mauery16b86932019-05-01 08:36:11 -0700138 method.append(std::variant<uint32_t>(powerCap));
Tom Joseph46fa37d2017-07-26 18:11:55 +0530139
George Liu3e3cc352023-07-26 15:59:31 +0800140 try
Tom Joseph46fa37d2017-07-26 18:11:55 +0530141 {
George Liu3e3cc352023-07-26 15:59:31 +0800142 auto reply = bus.call(method);
143 }
144 catch (const std::exception& e)
145 {
146 log<level::ERR>("Error in setPcap property",
147 entry("ERROR=%s", e.what()));
Tom Joseph46fa37d2017-07-26 18:11:55 +0530148 elog<InternalFailure>();
149 }
150}
151
Patrick Williams5d82f472022-07-22 19:26:53 -0500152void setPcapEnable(sdbusplus::bus_t& bus, bool enabled)
Tom Joseph6c8d51b2017-07-26 18:18:06 +0530153{
154 auto service = ipmi::getService(bus, PCAP_INTERFACE, PCAP_PATH);
155
Patrick Venture0b02be92018-08-31 11:55:55 -0700156 auto method = bus.new_method_call(service.c_str(), PCAP_PATH,
157 "org.freedesktop.DBus.Properties", "Set");
Tom Joseph6c8d51b2017-07-26 18:18:06 +0530158
159 method.append(PCAP_INTERFACE, POWER_CAP_ENABLE_PROP);
Vernon Mauery16b86932019-05-01 08:36:11 -0700160 method.append(std::variant<bool>(enabled));
Tom Joseph6c8d51b2017-07-26 18:18:06 +0530161
George Liu3e3cc352023-07-26 15:59:31 +0800162 try
Tom Joseph6c8d51b2017-07-26 18:18:06 +0530163 {
George Liu3e3cc352023-07-26 15:59:31 +0800164 auto reply = bus.call(method);
165 }
166 catch (const std::exception& e)
167 {
168 log<level::ERR>("Error in setPcapEnabled property",
169 entry("ERROR=%s", e.what()));
Tom Joseph6c8d51b2017-07-26 18:18:06 +0530170 elog<InternalFailure>();
171 }
172}
173
Tom Josephbe5eaa12017-07-12 19:54:44 +0530174void readAssetTagObjectTree(dcmi::assettag::ObjectTree& objectTree)
175{
176 static constexpr auto mapperBusName = "xyz.openbmc_project.ObjectMapper";
177 static constexpr auto mapperObjPath = "/xyz/openbmc_project/object_mapper";
178 static constexpr auto mapperIface = "xyz.openbmc_project.ObjectMapper";
179 static constexpr auto inventoryRoot = "/xyz/openbmc_project/inventory/";
180
Patrick Williams5d82f472022-07-22 19:26:53 -0500181 sdbusplus::bus_t bus{ipmid_get_sd_bus_connection()};
Tom Josephbe5eaa12017-07-12 19:54:44 +0530182 auto depth = 0;
183
Patrick Venture0b02be92018-08-31 11:55:55 -0700184 auto mapperCall = bus.new_method_call(mapperBusName, mapperObjPath,
185 mapperIface, "GetSubTree");
Tom Josephbe5eaa12017-07-12 19:54:44 +0530186
187 mapperCall.append(inventoryRoot);
188 mapperCall.append(depth);
189 mapperCall.append(std::vector<std::string>({dcmi::assetTagIntf}));
190
George Liu3e3cc352023-07-26 15:59:31 +0800191 try
Tom Josephbe5eaa12017-07-12 19:54:44 +0530192 {
George Liu3e3cc352023-07-26 15:59:31 +0800193 auto mapperReply = bus.call(mapperCall);
194 mapperReply.read(objectTree);
195
196 if (objectTree.empty())
197 {
198 log<level::ERR>("AssetTag property is not populated");
199 elog<InternalFailure>();
200 }
Tom Josephbe5eaa12017-07-12 19:54:44 +0530201 }
George Liu3e3cc352023-07-26 15:59:31 +0800202 catch (const std::exception& e)
Tom Josephbe5eaa12017-07-12 19:54:44 +0530203 {
George Liu3e3cc352023-07-26 15:59:31 +0800204 log<level::ERR>("Error in mapper call", entry("ERROR=%s", e.what()));
Tom Josephbe5eaa12017-07-12 19:54:44 +0530205 elog<InternalFailure>();
206 }
207}
208
209std::string readAssetTag()
210{
Patrick Williams5d82f472022-07-22 19:26:53 -0500211 sdbusplus::bus_t bus{ipmid_get_sd_bus_connection()};
Tom Josephbe5eaa12017-07-12 19:54:44 +0530212 dcmi::assettag::ObjectTree objectTree;
213
214 // Read the object tree with the inventory root to figure out the object
215 // that has implemented the Asset tag interface.
216 readAssetTagObjectTree(objectTree);
217
218 auto method = bus.new_method_call(
Patrick Venture0b02be92018-08-31 11:55:55 -0700219 (objectTree.begin()->second.begin()->first).c_str(),
220 (objectTree.begin()->first).c_str(), dcmi::propIntf, "Get");
Tom Josephbe5eaa12017-07-12 19:54:44 +0530221 method.append(dcmi::assetTagIntf);
222 method.append(dcmi::assetTagProp);
223
George Liu3e3cc352023-07-26 15:59:31 +0800224 std::variant<std::string> assetTag;
225 try
Tom Josephbe5eaa12017-07-12 19:54:44 +0530226 {
George Liu3e3cc352023-07-26 15:59:31 +0800227 auto reply = bus.call(method);
228 reply.read(assetTag);
229 return std::get<std::string>(assetTag);
230 }
231 catch (const std::exception& e)
232 {
233 log<level::ERR>("Error in reading asset tag",
234 entry("ERROR=%s", e.what()));
Tom Josephbe5eaa12017-07-12 19:54:44 +0530235 elog<InternalFailure>();
236 }
Tom Josephbe5eaa12017-07-12 19:54:44 +0530237}
238
Tom Josephbe5b9892017-07-15 00:55:23 +0530239void writeAssetTag(const std::string& assetTag)
240{
Patrick Williams5d82f472022-07-22 19:26:53 -0500241 sdbusplus::bus_t bus{ipmid_get_sd_bus_connection()};
Tom Josephbe5b9892017-07-15 00:55:23 +0530242 dcmi::assettag::ObjectTree objectTree;
243
244 // Read the object tree with the inventory root to figure out the object
245 // that has implemented the Asset tag interface.
246 readAssetTagObjectTree(objectTree);
247
248 auto method = bus.new_method_call(
Patrick Venture0b02be92018-08-31 11:55:55 -0700249 (objectTree.begin()->second.begin()->first).c_str(),
250 (objectTree.begin()->first).c_str(), dcmi::propIntf, "Set");
Tom Josephbe5b9892017-07-15 00:55:23 +0530251 method.append(dcmi::assetTagIntf);
252 method.append(dcmi::assetTagProp);
Vernon Mauery16b86932019-05-01 08:36:11 -0700253 method.append(std::variant<std::string>(assetTag));
Tom Josephbe5b9892017-07-15 00:55:23 +0530254
George Liu3e3cc352023-07-26 15:59:31 +0800255 try
Tom Josephbe5b9892017-07-15 00:55:23 +0530256 {
George Liu3e3cc352023-07-26 15:59:31 +0800257 auto reply = bus.call(method);
258 }
259 catch (const std::exception& e)
260 {
261 log<level::ERR>("Error in writing asset tag",
262 entry("ERROR=%s", e.what()));
Tom Josephbe5b9892017-07-15 00:55:23 +0530263 elog<InternalFailure>();
264 }
265}
266
Vladislav Vovchenko8f7a6f62017-08-17 00:31:14 +0300267std::string getHostName(void)
268{
Patrick Williams5d82f472022-07-22 19:26:53 -0500269 sdbusplus::bus_t bus{ipmid_get_sd_bus_connection()};
Vladislav Vovchenko8f7a6f62017-08-17 00:31:14 +0300270
271 auto service = ipmi::getService(bus, networkConfigIntf, networkConfigObj);
Patrick Venture0b02be92018-08-31 11:55:55 -0700272 auto value = ipmi::getDbusProperty(bus, service, networkConfigObj,
273 networkConfigIntf, hostNameProp);
Vladislav Vovchenko8f7a6f62017-08-17 00:31:14 +0300274
Vernon Maueryf442e112019-04-09 11:44:36 -0700275 return std::get<std::string>(value);
Vladislav Vovchenko8f7a6f62017-08-17 00:31:14 +0300276}
277
Thang Tran55cbf552023-01-31 14:43:02 +0700278EthernetInterface::DHCPConf getDHCPEnabled()
Nagaraju Goruganti22be97b2018-02-07 01:19:59 -0600279{
Patrick Williams5d82f472022-07-22 19:26:53 -0500280 sdbusplus::bus_t bus{ipmid_get_sd_bus_connection()};
Nagaraju Goruganti22be97b2018-02-07 01:19:59 -0600281
Johnathan Mantey74a21022018-12-13 13:17:56 -0800282 auto ethdevice = ipmi::getChannelName(ethernetDefaultChannelNum);
Patrick Williamsfbc6c9d2023-05-10 07:50:16 -0500283 auto ethernetObj = ipmi::getDbusObject(bus, ethernetIntf, networkRoot,
284 ethdevice);
Nagaraju Goruganti22be97b2018-02-07 01:19:59 -0600285 auto service = ipmi::getService(bus, ethernetIntf, ethernetObj.first);
Patrick Venture0b02be92018-08-31 11:55:55 -0700286 auto value = ipmi::getDbusProperty(bus, service, ethernetObj.first,
287 ethernetIntf, "DHCPEnabled");
Nagaraju Goruganti22be97b2018-02-07 01:19:59 -0600288
Thang Tran55cbf552023-01-31 14:43:02 +0700289 return EthernetInterface::convertDHCPConfFromString(
290 std::get<std::string>(value));
Nagaraju Goruganti22be97b2018-02-07 01:19:59 -0600291}
292
293bool getDHCPOption(std::string prop)
294{
Patrick Williams5d82f472022-07-22 19:26:53 -0500295 sdbusplus::bus_t bus{ipmid_get_sd_bus_connection()};
Nagaraju Goruganti22be97b2018-02-07 01:19:59 -0600296
297 auto service = ipmi::getService(bus, dhcpIntf, dhcpObj);
298 auto value = ipmi::getDbusProperty(bus, service, dhcpObj, dhcpIntf, prop);
299
Vernon Maueryf442e112019-04-09 11:44:36 -0700300 return std::get<bool>(value);
Nagaraju Goruganti22be97b2018-02-07 01:19:59 -0600301}
302
Nagaraju Goruganti22be97b2018-02-07 01:19:59 -0600303void setDHCPOption(std::string prop, bool value)
304{
Patrick Williams5d82f472022-07-22 19:26:53 -0500305 sdbusplus::bus_t bus{ipmid_get_sd_bus_connection()};
Nagaraju Goruganti22be97b2018-02-07 01:19:59 -0600306
307 auto service = ipmi::getService(bus, dhcpIntf, dhcpObj);
308 ipmi::setDbusProperty(bus, service, dhcpObj, dhcpIntf, prop, value);
309}
310
Kirill Pakhomova2573622018-11-02 19:00:18 +0300311Json parseJSONConfig(const std::string& configFile)
Deepak Kodihalli0b459552018-02-06 06:25:12 -0600312{
313 std::ifstream jsonFile(configFile);
314 if (!jsonFile.is_open())
315 {
316 log<level::ERR>("Temperature readings JSON file not found");
317 elog<InternalFailure>();
318 }
319
320 auto data = Json::parse(jsonFile, nullptr, false);
321 if (data.is_discarded())
322 {
323 log<level::ERR>("Temperature readings JSON parser failure");
324 elog<InternalFailure>();
325 }
326
327 return data;
328}
329
Tom Josephbe5eaa12017-07-12 19:54:44 +0530330} // namespace dcmi
Chris Austen1810bec2015-10-13 12:12:39 -0500331
Willy Tu11d68892022-01-20 10:37:34 -0800332ipmi_ret_t getPowerLimit(ipmi_netfn_t, ipmi_cmd_t, ipmi_request_t,
333 ipmi_response_t response, ipmi_data_len_t data_len,
334 ipmi_context_t)
Tom Josephb9d86f42017-07-26 18:03:47 +0530335{
Kirill Pakhomov2c2af2c2018-11-06 16:06:10 +0300336 if (!dcmi::isDCMIPowerMgmtSupported())
337 {
338 *data_len = 0;
339 log<level::ERR>("DCMI Power management is unsupported!");
340 return IPMI_CC_INVALID;
341 }
342
Tom Josephb9d86f42017-07-26 18:03:47 +0530343 std::vector<uint8_t> outPayload(sizeof(dcmi::GetPowerLimitResponse));
Patrick Venture0b02be92018-08-31 11:55:55 -0700344 auto responseData =
345 reinterpret_cast<dcmi::GetPowerLimitResponse*>(outPayload.data());
Tom Josephb9d86f42017-07-26 18:03:47 +0530346
Patrick Williams5d82f472022-07-22 19:26:53 -0500347 sdbusplus::bus_t sdbus{ipmid_get_sd_bus_connection()};
Tom Josephb9d86f42017-07-26 18:03:47 +0530348 uint32_t pcapValue = 0;
349 bool pcapEnable = false;
350
351 try
352 {
353 pcapValue = dcmi::getPcap(sdbus);
354 pcapEnable = dcmi::getPcapEnabled(sdbus);
355 }
Patrick Williamsa2ad2da2021-10-06 12:21:46 -0500356 catch (const InternalFailure& e)
Tom Josephb9d86f42017-07-26 18:03:47 +0530357 {
358 *data_len = 0;
359 return IPMI_CC_UNSPECIFIED_ERROR;
360 }
361
Tom Josephb9d86f42017-07-26 18:03:47 +0530362 /*
363 * Exception action if power limit is exceeded and cannot be controlled
364 * with the correction time limit is hardcoded to Hard Power Off system
365 * and log event to SEL.
366 */
367 constexpr auto exception = 0x01;
368 responseData->exceptionAction = exception;
369
370 responseData->powerLimit = static_cast<uint16_t>(pcapValue);
371
372 /*
373 * Correction time limit and Statistics sampling period is currently not
374 * populated.
375 */
376
377 *data_len = outPayload.size();
378 memcpy(response, outPayload.data(), *data_len);
379
380 if (pcapEnable)
381 {
382 return IPMI_CC_OK;
383 }
384 else
385 {
386 return IPMI_DCMI_CC_NO_ACTIVE_POWER_LIMIT;
387 }
388}
389
Willy Tu11d68892022-01-20 10:37:34 -0800390ipmi_ret_t setPowerLimit(ipmi_netfn_t, ipmi_cmd_t, ipmi_request_t request,
391 ipmi_response_t, ipmi_data_len_t data_len,
392 ipmi_context_t)
Tom Joseph46fa37d2017-07-26 18:11:55 +0530393{
Kirill Pakhomov2c2af2c2018-11-06 16:06:10 +0300394 if (!dcmi::isDCMIPowerMgmtSupported())
395 {
396 *data_len = 0;
397 log<level::ERR>("DCMI Power management is unsupported!");
398 return IPMI_CC_INVALID;
399 }
400
Patrick Venture0b02be92018-08-31 11:55:55 -0700401 auto requestData =
402 reinterpret_cast<const dcmi::SetPowerLimitRequest*>(request);
Tom Joseph46fa37d2017-07-26 18:11:55 +0530403
Patrick Williams5d82f472022-07-22 19:26:53 -0500404 sdbusplus::bus_t sdbus{ipmid_get_sd_bus_connection()};
Tom Joseph46fa37d2017-07-26 18:11:55 +0530405
406 // Only process the power limit requested in watts.
407 try
408 {
409 dcmi::setPcap(sdbus, requestData->powerLimit);
410 }
Patrick Williamsa2ad2da2021-10-06 12:21:46 -0500411 catch (const InternalFailure& e)
Tom Joseph46fa37d2017-07-26 18:11:55 +0530412 {
413 *data_len = 0;
414 return IPMI_CC_UNSPECIFIED_ERROR;
415 }
416
417 log<level::INFO>("Set Power Cap",
418 entry("POWERCAP=%u", requestData->powerLimit));
419
William A. Kennington III5d06cc62019-04-25 02:10:55 -0700420 *data_len = 0;
Tom Joseph46fa37d2017-07-26 18:11:55 +0530421 return IPMI_CC_OK;
422}
423
Willy Tu11d68892022-01-20 10:37:34 -0800424ipmi_ret_t applyPowerLimit(ipmi_netfn_t, ipmi_cmd_t, ipmi_request_t request,
425 ipmi_response_t, ipmi_data_len_t data_len,
426 ipmi_context_t)
Tom Joseph6c8d51b2017-07-26 18:18:06 +0530427{
Kirill Pakhomov2c2af2c2018-11-06 16:06:10 +0300428 if (!dcmi::isDCMIPowerMgmtSupported())
429 {
430 *data_len = 0;
431 log<level::ERR>("DCMI Power management is unsupported!");
432 return IPMI_CC_INVALID;
433 }
434
Patrick Venture0b02be92018-08-31 11:55:55 -0700435 auto requestData =
436 reinterpret_cast<const dcmi::ApplyPowerLimitRequest*>(request);
Tom Joseph6c8d51b2017-07-26 18:18:06 +0530437
Patrick Williams5d82f472022-07-22 19:26:53 -0500438 sdbusplus::bus_t sdbus{ipmid_get_sd_bus_connection()};
Tom Joseph6c8d51b2017-07-26 18:18:06 +0530439
440 try
441 {
442 dcmi::setPcapEnable(sdbus,
443 static_cast<bool>(requestData->powerLimitAction));
444 }
Patrick Williamsa2ad2da2021-10-06 12:21:46 -0500445 catch (const InternalFailure& e)
Tom Joseph6c8d51b2017-07-26 18:18:06 +0530446 {
447 *data_len = 0;
448 return IPMI_CC_UNSPECIFIED_ERROR;
449 }
450
451 log<level::INFO>("Set Power Cap Enable",
452 entry("POWERCAPENABLE=%u", requestData->powerLimitAction));
453
William A. Kennington III5d06cc62019-04-25 02:10:55 -0700454 *data_len = 0;
Tom Joseph6c8d51b2017-07-26 18:18:06 +0530455 return IPMI_CC_OK;
456}
457
Willy Tu11d68892022-01-20 10:37:34 -0800458ipmi_ret_t getAssetTag(ipmi_netfn_t, ipmi_cmd_t, ipmi_request_t request,
459 ipmi_response_t response, ipmi_data_len_t data_len,
460 ipmi_context_t)
Tom Joseph6f6dd4d2017-07-12 20:07:11 +0530461{
Patrick Venture0b02be92018-08-31 11:55:55 -0700462 auto requestData =
463 reinterpret_cast<const dcmi::GetAssetTagRequest*>(request);
Tom Joseph6f6dd4d2017-07-12 20:07:11 +0530464 std::vector<uint8_t> outPayload(sizeof(dcmi::GetAssetTagResponse));
Patrick Venture0b02be92018-08-31 11:55:55 -0700465 auto responseData =
466 reinterpret_cast<dcmi::GetAssetTagResponse*>(outPayload.data());
Tom Joseph6f6dd4d2017-07-12 20:07:11 +0530467
Tom Joseph6f6dd4d2017-07-12 20:07:11 +0530468 // Verify offset to read and number of bytes to read are not exceeding the
469 // range.
470 if ((requestData->offset > dcmi::assetTagMaxOffset) ||
471 (requestData->bytes > dcmi::maxBytes) ||
472 ((requestData->offset + requestData->bytes) > dcmi::assetTagMaxSize))
473 {
474 *data_len = 0;
475 return IPMI_CC_PARM_OUT_OF_RANGE;
476 }
477
478 std::string assetTag;
479
480 try
481 {
482 assetTag = dcmi::readAssetTag();
483 }
Patrick Williamsa2ad2da2021-10-06 12:21:46 -0500484 catch (const InternalFailure& e)
Tom Joseph6f6dd4d2017-07-12 20:07:11 +0530485 {
486 *data_len = 0;
487 return IPMI_CC_UNSPECIFIED_ERROR;
488 }
489
Tom Joseph6f6dd4d2017-07-12 20:07:11 +0530490 // Return if the asset tag is not populated.
491 if (!assetTag.size())
492 {
493 responseData->tagLength = 0;
494 memcpy(response, outPayload.data(), outPayload.size());
495 *data_len = outPayload.size();
496 return IPMI_CC_OK;
497 }
498
499 // If the asset tag is longer than 63 bytes, restrict it to 63 bytes to suit
500 // Get Asset Tag command.
501 if (assetTag.size() > dcmi::assetTagMaxSize)
502 {
503 assetTag.resize(dcmi::assetTagMaxSize);
504 }
505
506 // If the requested offset is beyond the asset tag size.
507 if (requestData->offset >= assetTag.size())
508 {
509 *data_len = 0;
510 return IPMI_CC_PARM_OUT_OF_RANGE;
511 }
512
513 auto returnData = assetTag.substr(requestData->offset, requestData->bytes);
514
515 responseData->tagLength = assetTag.size();
516
517 memcpy(response, outPayload.data(), outPayload.size());
518 memcpy(static_cast<uint8_t*>(response) + outPayload.size(),
519 returnData.data(), returnData.size());
520 *data_len = outPayload.size() + returnData.size();
521
522 return IPMI_CC_OK;
523}
524
Willy Tu11d68892022-01-20 10:37:34 -0800525ipmi_ret_t setAssetTag(ipmi_netfn_t, ipmi_cmd_t, ipmi_request_t request,
526 ipmi_response_t response, ipmi_data_len_t data_len,
527 ipmi_context_t)
Tom Joseph545dd232017-07-12 20:20:49 +0530528{
Patrick Venture0b02be92018-08-31 11:55:55 -0700529 auto requestData =
530 reinterpret_cast<const dcmi::SetAssetTagRequest*>(request);
Tom Joseph545dd232017-07-12 20:20:49 +0530531 std::vector<uint8_t> outPayload(sizeof(dcmi::SetAssetTagResponse));
Patrick Venture0b02be92018-08-31 11:55:55 -0700532 auto responseData =
533 reinterpret_cast<dcmi::SetAssetTagResponse*>(outPayload.data());
Tom Joseph545dd232017-07-12 20:20:49 +0530534
Tom Joseph545dd232017-07-12 20:20:49 +0530535 // Verify offset to read and number of bytes to read are not exceeding the
536 // range.
537 if ((requestData->offset > dcmi::assetTagMaxOffset) ||
538 (requestData->bytes > dcmi::maxBytes) ||
539 ((requestData->offset + requestData->bytes) > dcmi::assetTagMaxSize))
540 {
541 *data_len = 0;
542 return IPMI_CC_PARM_OUT_OF_RANGE;
543 }
544
545 std::string assetTag;
546
547 try
548 {
549 assetTag = dcmi::readAssetTag();
550
551 if (requestData->offset > assetTag.size())
552 {
553 *data_len = 0;
554 return IPMI_CC_PARM_OUT_OF_RANGE;
555 }
556
557 assetTag.replace(requestData->offset,
558 assetTag.size() - requestData->offset,
559 static_cast<const char*>(request) +
Patrick Venture0b02be92018-08-31 11:55:55 -0700560 sizeof(dcmi::SetAssetTagRequest),
Tom Joseph545dd232017-07-12 20:20:49 +0530561 requestData->bytes);
562
563 dcmi::writeAssetTag(assetTag);
564
Tom Joseph545dd232017-07-12 20:20:49 +0530565 responseData->tagLength = assetTag.size();
566 memcpy(response, outPayload.data(), outPayload.size());
567 *data_len = outPayload.size();
568
569 return IPMI_CC_OK;
570 }
Patrick Williamsa2ad2da2021-10-06 12:21:46 -0500571 catch (const InternalFailure& e)
Tom Joseph545dd232017-07-12 20:20:49 +0530572 {
573 *data_len = 0;
574 return IPMI_CC_UNSPECIFIED_ERROR;
575 }
576}
577
Willy Tu11d68892022-01-20 10:37:34 -0800578ipmi_ret_t getMgmntCtrlIdStr(ipmi_netfn_t, ipmi_cmd_t, ipmi_request_t request,
579 ipmi_response_t response, ipmi_data_len_t data_len,
580 ipmi_context_t)
Vladislav Vovchenko8f7a6f62017-08-17 00:31:14 +0300581{
Patrick Venture0b02be92018-08-31 11:55:55 -0700582 auto requestData =
583 reinterpret_cast<const dcmi::GetMgmntCtrlIdStrRequest*>(request);
584 auto responseData =
585 reinterpret_cast<dcmi::GetMgmntCtrlIdStrResponse*>(response);
Vladislav Vovchenko8f7a6f62017-08-17 00:31:14 +0300586 std::string hostName;
587
588 *data_len = 0;
589
William A. Kennington III5d06cc62019-04-25 02:10:55 -0700590 if (requestData->bytes > dcmi::maxBytes ||
Vladislav Vovchenko8f7a6f62017-08-17 00:31:14 +0300591 requestData->offset + requestData->bytes > dcmi::maxCtrlIdStrLen)
592 {
593 return IPMI_CC_INVALID_FIELD_REQUEST;
594 }
595
596 try
597 {
598 hostName = dcmi::getHostName();
599 }
Patrick Williamsa2ad2da2021-10-06 12:21:46 -0500600 catch (const InternalFailure& e)
Vladislav Vovchenko8f7a6f62017-08-17 00:31:14 +0300601 {
602 return IPMI_CC_UNSPECIFIED_ERROR;
603 }
604
605 if (requestData->offset > hostName.length())
606 {
607 return IPMI_CC_PARM_OUT_OF_RANGE;
608 }
609 auto responseStr = hostName.substr(requestData->offset, requestData->bytes);
610 auto responseStrLen = std::min(static_cast<std::size_t>(requestData->bytes),
Patrick Venture0b02be92018-08-31 11:55:55 -0700611 responseStr.length() + 1);
Vladislav Vovchenko8f7a6f62017-08-17 00:31:14 +0300612 responseData->strLen = hostName.length();
613 std::copy(begin(responseStr), end(responseStr), responseData->data);
614
615 *data_len = sizeof(*responseData) + responseStrLen;
616 return IPMI_CC_OK;
617}
618
Willy Tu11d68892022-01-20 10:37:34 -0800619ipmi_ret_t setMgmntCtrlIdStr(ipmi_netfn_t, ipmi_cmd_t, ipmi_request_t request,
620 ipmi_response_t response, ipmi_data_len_t data_len,
621 ipmi_context_t)
Vladislav Vovchenko8f7a6f62017-08-17 00:31:14 +0300622{
623 static std::array<char, dcmi::maxCtrlIdStrLen + 1> newCtrlIdStr;
624
Patrick Venture0b02be92018-08-31 11:55:55 -0700625 auto requestData =
626 reinterpret_cast<const dcmi::SetMgmntCtrlIdStrRequest*>(request);
627 auto responseData =
628 reinterpret_cast<dcmi::SetMgmntCtrlIdStrResponse*>(response);
Vladislav Vovchenko8f7a6f62017-08-17 00:31:14 +0300629
630 *data_len = 0;
631
William A. Kennington III5d06cc62019-04-25 02:10:55 -0700632 if (requestData->bytes > dcmi::maxBytes ||
Vladislav Vovchenko8f7a6f62017-08-17 00:31:14 +0300633 requestData->offset + requestData->bytes > dcmi::maxCtrlIdStrLen + 1 ||
Patrick Venture0b02be92018-08-31 11:55:55 -0700634 (requestData->offset + requestData->bytes ==
635 dcmi::maxCtrlIdStrLen + 1 &&
636 requestData->data[requestData->bytes - 1] != '\0'))
Vladislav Vovchenko8f7a6f62017-08-17 00:31:14 +0300637 {
638 return IPMI_CC_INVALID_FIELD_REQUEST;
639 }
640
641 try
642 {
643 /* if there is no old value and offset is not 0 */
644 if (newCtrlIdStr[0] == '\0' && requestData->offset != 0)
645 {
646 /* read old ctrlIdStr */
647 auto hostName = dcmi::getHostName();
648 hostName.resize(dcmi::maxCtrlIdStrLen);
649 std::copy(begin(hostName), end(hostName), begin(newCtrlIdStr));
650 newCtrlIdStr[hostName.length()] = '\0';
651 }
652
653 /* replace part of string and mark byte after the last as \0 */
Patrick Venture0b02be92018-08-31 11:55:55 -0700654 auto restStrIter =
655 std::copy_n(requestData->data, requestData->bytes,
656 begin(newCtrlIdStr) + requestData->offset);
Vladislav Vovchenko8f7a6f62017-08-17 00:31:14 +0300657 /* if the last written byte is not 64th - add '\0' */
658 if (requestData->offset + requestData->bytes <= dcmi::maxCtrlIdStrLen)
659 {
660 *restStrIter = '\0';
661 }
662
663 /* if input data contains '\0' whole string is sent - update hostname */
664 auto it = std::find(requestData->data,
Patrick Venture0b02be92018-08-31 11:55:55 -0700665 requestData->data + requestData->bytes, '\0');
Vladislav Vovchenko8f7a6f62017-08-17 00:31:14 +0300666 if (it != requestData->data + requestData->bytes)
667 {
Patrick Williams5d82f472022-07-22 19:26:53 -0500668 sdbusplus::bus_t bus{ipmid_get_sd_bus_connection()};
Vladislav Vovchenko8f7a6f62017-08-17 00:31:14 +0300669 ipmi::setDbusProperty(bus, dcmi::networkServiceName,
Patrick Venture0b02be92018-08-31 11:55:55 -0700670 dcmi::networkConfigObj,
671 dcmi::networkConfigIntf, dcmi::hostNameProp,
672 std::string(newCtrlIdStr.data()));
Vladislav Vovchenko8f7a6f62017-08-17 00:31:14 +0300673 }
674 }
Patrick Williamsa2ad2da2021-10-06 12:21:46 -0500675 catch (const InternalFailure& e)
Vladislav Vovchenko8f7a6f62017-08-17 00:31:14 +0300676 {
677 *data_len = 0;
678 return IPMI_CC_UNSPECIFIED_ERROR;
679 }
680
Vladislav Vovchenko8f7a6f62017-08-17 00:31:14 +0300681 responseData->offset = requestData->offset + requestData->bytes;
682 *data_len = sizeof(*responseData);
683 return IPMI_CC_OK;
684}
685
Patrick Venture0b02be92018-08-31 11:55:55 -0700686// List of the capabilities under each parameter
687dcmi::DCMICaps dcmiCaps = {
688 // Supported DCMI Capabilities
689 {dcmi::DCMICapParameters::SUPPORTED_DCMI_CAPS,
690 {3,
691 {{"PowerManagement", 2, 0, 1},
692 {"OOBSecondaryLan", 3, 2, 1},
693 {"SerialTMODE", 3, 1, 1},
694 {"InBandSystemInterfaceChannel", 3, 0, 1}}}},
695 // Mandatory Platform Attributes
696 {dcmi::DCMICapParameters::MANDATORY_PLAT_ATTRIBUTES,
697 {5,
698 {{"SELAutoRollOver", 1, 15, 1},
699 {"FlushEntireSELUponRollOver", 1, 14, 1},
700 {"RecordLevelSELFlushUponRollOver", 1, 13, 1},
701 {"NumberOfSELEntries", 1, 0, 12},
702 {"TempMonitoringSamplingFreq", 5, 0, 8}}}},
703 // Optional Platform Attributes
704 {dcmi::DCMICapParameters::OPTIONAL_PLAT_ATTRIBUTES,
705 {2,
706 {{"PowerMgmtDeviceSlaveAddress", 1, 1, 7},
707 {"BMCChannelNumber", 2, 4, 4},
708 {"DeviceRivision", 2, 0, 4}}}},
709 // Manageability Access Attributes
710 {dcmi::DCMICapParameters::MANAGEABILITY_ACCESS_ATTRIBUTES,
711 {3,
712 {{"MandatoryPrimaryLanOOBSupport", 1, 0, 8},
713 {"OptionalSecondaryLanOOBSupport", 2, 0, 8},
714 {"OptionalSerialOOBMTMODECapability", 3, 0, 8}}}}};
Dhruvaraj Subhashchandrane29be412018-01-16 05:11:56 -0600715
Willy Tu11d68892022-01-20 10:37:34 -0800716ipmi_ret_t getDCMICapabilities(ipmi_netfn_t, ipmi_cmd_t, ipmi_request_t request,
717 ipmi_response_t response,
718 ipmi_data_len_t data_len, ipmi_context_t)
Dhruvaraj Subhashchandrane29be412018-01-16 05:11:56 -0600719{
Kirill Pakhomova2573622018-11-02 19:00:18 +0300720 std::ifstream dcmiCapFile(dcmi::gDCMICapabilitiesConfig);
Dhruvaraj Subhashchandrane29be412018-01-16 05:11:56 -0600721 if (!dcmiCapFile.is_open())
722 {
723 log<level::ERR>("DCMI Capabilities file not found");
724 return IPMI_CC_UNSPECIFIED_ERROR;
725 }
726
727 auto data = nlohmann::json::parse(dcmiCapFile, nullptr, false);
728 if (data.is_discarded())
729 {
730 log<level::ERR>("DCMI Capabilities JSON parser failure");
731 return IPMI_CC_UNSPECIFIED_ERROR;
732 }
733
Patrick Venture0b02be92018-08-31 11:55:55 -0700734 auto requestData =
735 reinterpret_cast<const dcmi::GetDCMICapRequest*>(request);
Dhruvaraj Subhashchandrane29be412018-01-16 05:11:56 -0600736
Patrick Venture0b02be92018-08-31 11:55:55 -0700737 // get list of capabilities in a parameter
Dhruvaraj Subhashchandrane29be412018-01-16 05:11:56 -0600738 auto caps =
739 dcmiCaps.find(static_cast<dcmi::DCMICapParameters>(requestData->param));
740 if (caps == dcmiCaps.end())
741 {
742 log<level::ERR>("Invalid input parameter");
743 return IPMI_CC_INVALID_FIELD_REQUEST;
744 }
745
Patrick Venture0b02be92018-08-31 11:55:55 -0700746 auto responseData = reinterpret_cast<dcmi::GetDCMICapResponse*>(response);
Dhruvaraj Subhashchandrane29be412018-01-16 05:11:56 -0600747
Patrick Venture0b02be92018-08-31 11:55:55 -0700748 // For each capabilities in a parameter fill the data from
749 // the json file based on the capability name.
Dhruvaraj Subhashchandrane29be412018-01-16 05:11:56 -0600750 for (auto cap : caps->second.capList)
751 {
Patrick Venture0b02be92018-08-31 11:55:55 -0700752 // If the data is beyond first byte boundary, insert in a
753 // 16bit pattern for example number of SEL entries are represented
754 // in 12bits.
Kirill Pakhomovdb5d9b02018-11-06 19:17:51 +0300755 if ((cap.length + cap.position) > dcmi::gByteBitSize)
Dhruvaraj Subhashchandrane29be412018-01-16 05:11:56 -0600756 {
Kirill Pakhomovdb5d9b02018-11-06 19:17:51 +0300757 uint16_t val = data.value(cap.name.c_str(), 0);
758 // According to DCMI spec v1.5, max number of SEL entries is
759 // 4096, but bit 12b of DCMI capabilities Mandatory Platform
760 // Attributes field is reserved and therefore we can use only
761 // the provided 12 bits with maximum value of 4095.
762 // We're playing safe here by applying the mask
763 // to ensure that provided value will fit into 12 bits.
764 if (cap.length > dcmi::gByteBitSize)
765 {
766 val &= dcmi::gMaxSELEntriesMask;
767 }
Dhruvaraj Subhashchandrane29be412018-01-16 05:11:56 -0600768 val <<= cap.position;
Kirill Pakhomovdb5d9b02018-11-06 19:17:51 +0300769 responseData->data[cap.bytePosition - 1] |=
770 static_cast<uint8_t>(val);
771 responseData->data[cap.bytePosition] |= val >> dcmi::gByteBitSize;
Dhruvaraj Subhashchandrane29be412018-01-16 05:11:56 -0600772 }
773 else
774 {
775 responseData->data[cap.bytePosition - 1] |=
776 data.value(cap.name.c_str(), 0) << cap.position;
777 }
778 }
779
Dhruvaraj Subhashchandrane29be412018-01-16 05:11:56 -0600780 responseData->major = DCMI_SPEC_MAJOR_VERSION;
781 responseData->minor = DCMI_SPEC_MINOR_VERSION;
782 responseData->paramRevision = DCMI_PARAMETER_REVISION;
783 *data_len = sizeof(*responseData) + caps->second.size;
784
785 return IPMI_CC_OK;
786}
787
Deepak Kodihalliee717d72018-01-24 04:53:09 -0600788namespace dcmi
789{
790namespace temp_readings
791{
792
Deepak Kodihallib1e8fba2018-01-24 04:57:10 -0600793Temperature readTemp(const std::string& dbusService,
794 const std::string& dbusPath)
795{
796 // Read the temperature value from d-bus object. Need some conversion.
797 // As per the interface xyz.openbmc_project.Sensor.Value, the temperature
James Feist9cc0ea52018-10-09 10:53:11 -0700798 // is an double and in degrees C. It needs to be scaled by using the
Deepak Kodihallib1e8fba2018-01-24 04:57:10 -0600799 // formula Value * 10^Scale. The ipmi spec has the temperature as a uint8_t,
800 // with a separate single bit for the sign.
801
Patrick Williams5d82f472022-07-22 19:26:53 -0500802 sdbusplus::bus_t bus{ipmid_get_sd_bus_connection()};
Patrick Venture0b02be92018-08-31 11:55:55 -0700803 auto result = ipmi::getAllDbusProperties(
804 bus, dbusService, dbusPath, "xyz.openbmc_project.Sensor.Value");
Patrick Williamsfbc6c9d2023-05-10 07:50:16 -0500805 auto temperature = std::visit(ipmi::VariantToDoubleVisitor(),
806 result.at("Value"));
James Feist9cc0ea52018-10-09 10:53:11 -0700807 double absTemp = std::abs(temperature);
Deepak Kodihallib1e8fba2018-01-24 04:57:10 -0600808
James Feist9cc0ea52018-10-09 10:53:11 -0700809 auto findFactor = result.find("Scale");
810 double factor = 0.0;
811 if (findFactor != result.end())
Deepak Kodihallib1e8fba2018-01-24 04:57:10 -0600812 {
Vernon Maueryf442e112019-04-09 11:44:36 -0700813 factor = std::visit(ipmi::VariantToDoubleVisitor(), findFactor->second);
Deepak Kodihallib1e8fba2018-01-24 04:57:10 -0600814 }
James Feist9cc0ea52018-10-09 10:53:11 -0700815 double scale = std::pow(10, factor);
816
817 auto tempDegrees = absTemp * scale;
Deepak Kodihallib1e8fba2018-01-24 04:57:10 -0600818 // Max absolute temp as per ipmi spec is 128.
819 if (tempDegrees > maxTemp)
820 {
821 tempDegrees = maxTemp;
822 }
823
824 return std::make_tuple(static_cast<uint8_t>(tempDegrees),
825 (temperature < 0));
826}
827
Deepak Kodihalliee717d72018-01-24 04:53:09 -0600828std::tuple<Response, NumInstances> read(const std::string& type,
829 uint8_t instance)
830{
Deepak Kodihallib1e8fba2018-01-24 04:57:10 -0600831 Response response{};
Patrick Williams5d82f472022-07-22 19:26:53 -0500832 sdbusplus::bus_t bus{ipmid_get_sd_bus_connection()};
Deepak Kodihallib1e8fba2018-01-24 04:57:10 -0600833
834 if (!instance)
835 {
836 log<level::ERR>("Expected non-zero instance");
837 elog<InternalFailure>();
838 }
839
Kirill Pakhomova2573622018-11-02 19:00:18 +0300840 auto data = parseJSONConfig(gDCMISensorsConfig);
Deepak Kodihallib1e8fba2018-01-24 04:57:10 -0600841 static const std::vector<Json> empty{};
842 std::vector<Json> readings = data.value(type, empty);
843 size_t numInstances = readings.size();
844 for (const auto& j : readings)
845 {
846 uint8_t instanceNum = j.value("instance", 0);
847 // Not the instance we're interested in
848 if (instanceNum != instance)
849 {
850 continue;
851 }
852
853 std::string path = j.value("dbus", "");
854 std::string service;
855 try
856 {
Patrick Williamsfbc6c9d2023-05-10 07:50:16 -0500857 service = ipmi::getService(bus, "xyz.openbmc_project.Sensor.Value",
858 path);
Deepak Kodihallib1e8fba2018-01-24 04:57:10 -0600859 }
Patrick Williamsa2ad2da2021-10-06 12:21:46 -0500860 catch (const std::exception& e)
Deepak Kodihallib1e8fba2018-01-24 04:57:10 -0600861 {
862 log<level::DEBUG>(e.what());
863 return std::make_tuple(response, numInstances);
864 }
865
866 response.instance = instance;
867 uint8_t temp{};
868 bool sign{};
869 std::tie(temp, sign) = readTemp(service, path);
870 response.temperature = temp;
871 response.sign = sign;
872
873 // Found the instance we're interested in
874 break;
875 }
876
877 if (numInstances > maxInstances)
878 {
879 numInstances = maxInstances;
880 }
881 return std::make_tuple(response, numInstances);
Deepak Kodihalliee717d72018-01-24 04:53:09 -0600882}
883
884std::tuple<ResponseList, NumInstances> readAll(const std::string& type,
885 uint8_t instanceStart)
886{
Deepak Kodihallib1e8fba2018-01-24 04:57:10 -0600887 ResponseList response{};
Patrick Williams5d82f472022-07-22 19:26:53 -0500888 sdbusplus::bus_t bus{ipmid_get_sd_bus_connection()};
Deepak Kodihallib1e8fba2018-01-24 04:57:10 -0600889
890 size_t numInstances = 0;
Kirill Pakhomova2573622018-11-02 19:00:18 +0300891 auto data = parseJSONConfig(gDCMISensorsConfig);
Deepak Kodihallib1e8fba2018-01-24 04:57:10 -0600892 static const std::vector<Json> empty{};
893 std::vector<Json> readings = data.value(type, empty);
894 numInstances = readings.size();
895 for (const auto& j : readings)
896 {
897 try
898 {
899 // Max of 8 response data sets
900 if (response.size() == maxDataSets)
901 {
902 break;
903 }
904
905 uint8_t instanceNum = j.value("instance", 0);
906 // Not in the instance range we're interested in
907 if (instanceNum < instanceStart)
908 {
909 continue;
910 }
911
912 std::string path = j.value("dbus", "");
913 auto service =
Patrick Venture0b02be92018-08-31 11:55:55 -0700914 ipmi::getService(bus, "xyz.openbmc_project.Sensor.Value", path);
Deepak Kodihallib1e8fba2018-01-24 04:57:10 -0600915
916 Response r{};
917 r.instance = instanceNum;
918 uint8_t temp{};
919 bool sign{};
920 std::tie(temp, sign) = readTemp(service, path);
921 r.temperature = temp;
922 r.sign = sign;
923 response.push_back(r);
924 }
Patrick Williamsa2ad2da2021-10-06 12:21:46 -0500925 catch (const std::exception& e)
Deepak Kodihallib1e8fba2018-01-24 04:57:10 -0600926 {
927 log<level::DEBUG>(e.what());
928 continue;
929 }
930 }
931
932 if (numInstances > maxInstances)
933 {
934 numInstances = maxInstances;
935 }
936 return std::make_tuple(response, numInstances);
Deepak Kodihalliee717d72018-01-24 04:53:09 -0600937}
938
Patrick Venture0b02be92018-08-31 11:55:55 -0700939} // namespace temp_readings
940} // namespace dcmi
Deepak Kodihalliee717d72018-01-24 04:53:09 -0600941
Willy Tu11d68892022-01-20 10:37:34 -0800942ipmi_ret_t getTempReadings(ipmi_netfn_t, ipmi_cmd_t, ipmi_request_t request,
943 ipmi_response_t response, ipmi_data_len_t data_len,
944 ipmi_context_t)
Deepak Kodihalliee717d72018-01-24 04:53:09 -0600945{
Deepak Kodihalliee717d72018-01-24 04:53:09 -0600946 auto requestData =
947 reinterpret_cast<const dcmi::GetTempReadingsRequest*>(request);
948 auto responseData =
949 reinterpret_cast<dcmi::GetTempReadingsResponseHdr*>(response);
950
951 if (*data_len != sizeof(dcmi::GetTempReadingsRequest))
952 {
953 log<level::ERR>("Malformed request data",
954 entry("DATA_SIZE=%d", *data_len));
955 return IPMI_CC_REQ_DATA_LEN_INVALID;
956 }
957 *data_len = 0;
958
Deepak Kodihalli0b459552018-02-06 06:25:12 -0600959 auto it = dcmi::entityIdToName.find(requestData->entityId);
960 if (it == dcmi::entityIdToName.end())
Deepak Kodihalliee717d72018-01-24 04:53:09 -0600961 {
962 log<level::ERR>("Unknown Entity ID",
963 entry("ENTITY_ID=%d", requestData->entityId));
964 return IPMI_CC_INVALID_FIELD_REQUEST;
965 }
966
Deepak Kodihalliee717d72018-01-24 04:53:09 -0600967 if (requestData->sensorType != dcmi::temperatureSensorType)
968 {
969 log<level::ERR>("Invalid sensor type",
970 entry("SENSOR_TYPE=%d", requestData->sensorType));
971 return IPMI_CC_INVALID_FIELD_REQUEST;
972 }
973
974 dcmi::temp_readings::ResponseList temps{};
975 try
976 {
977 if (!requestData->entityInstance)
978 {
979 // Read all instances
980 std::tie(temps, responseData->numInstances) =
981 dcmi::temp_readings::readAll(it->second,
982 requestData->instanceStart);
983 }
984 else
985 {
986 // Read one instance
987 temps.resize(1);
988 std::tie(temps[0], responseData->numInstances) =
989 dcmi::temp_readings::read(it->second,
990 requestData->entityInstance);
991 }
992 responseData->numDataSets = temps.size();
993 }
Patrick Williamsa2ad2da2021-10-06 12:21:46 -0500994 catch (const InternalFailure& e)
Deepak Kodihalliee717d72018-01-24 04:53:09 -0600995 {
996 return IPMI_CC_UNSPECIFIED_ERROR;
997 }
998
Patrick Venture0b02be92018-08-31 11:55:55 -0700999 size_t payloadSize = temps.size() * sizeof(dcmi::temp_readings::Response);
Deepak Kodihalliee717d72018-01-24 04:53:09 -06001000 if (!temps.empty())
1001 {
1002 memcpy(responseData + 1, // copy payload right after the response header
Patrick Venture0b02be92018-08-31 11:55:55 -07001003 temps.data(), payloadSize);
Deepak Kodihalliee717d72018-01-24 04:53:09 -06001004 }
1005 *data_len = sizeof(dcmi::GetTempReadingsResponseHdr) + payloadSize;
1006
1007 return IPMI_CC_OK;
1008}
1009
Patrick Williams5d82f472022-07-22 19:26:53 -05001010int64_t getPowerReading(sdbusplus::bus_t& bus)
Marri Devender Rao66c5fda2018-01-18 10:48:37 -06001011{
1012 std::ifstream sensorFile(POWER_READING_SENSOR);
1013 std::string objectPath;
1014 if (!sensorFile.is_open())
1015 {
1016 log<level::ERR>("Power reading configuration file not found",
Patrick Venture0b02be92018-08-31 11:55:55 -07001017 entry("POWER_SENSOR_FILE=%s", POWER_READING_SENSOR));
Marri Devender Rao66c5fda2018-01-18 10:48:37 -06001018 elog<InternalFailure>();
1019 }
1020
1021 auto data = nlohmann::json::parse(sensorFile, nullptr, false);
1022 if (data.is_discarded())
1023 {
1024 log<level::ERR>("Error in parsing configuration file",
Patrick Venture0b02be92018-08-31 11:55:55 -07001025 entry("POWER_SENSOR_FILE=%s", POWER_READING_SENSOR));
Marri Devender Rao66c5fda2018-01-18 10:48:37 -06001026 elog<InternalFailure>();
1027 }
1028
1029 objectPath = data.value("path", "");
1030 if (objectPath.empty())
1031 {
1032 log<level::ERR>("Power sensor D-Bus object path is empty",
1033 entry("POWER_SENSOR_FILE=%s", POWER_READING_SENSOR));
1034 elog<InternalFailure>();
1035 }
1036
Marri Devender Raoce6a7952018-02-11 08:45:00 -06001037 // Return default value if failed to read from D-Bus object
1038 int64_t power = 0;
1039 try
1040 {
1041 auto service = ipmi::getService(bus, SENSOR_VALUE_INTF, objectPath);
Marri Devender Rao66c5fda2018-01-18 10:48:37 -06001042
Patrick Venture0b02be92018-08-31 11:55:55 -07001043 // Read the sensor value and scale properties
Chris Cain4cc61e02022-01-12 17:23:14 -06001044 auto value = ipmi::getDbusProperty(
1045 bus, service, objectPath, SENSOR_VALUE_INTF, SENSOR_VALUE_PROP);
1046 power = std::get<double>(value);
Marri Devender Raoce6a7952018-02-11 08:45:00 -06001047 }
Patrick Williamsa2ad2da2021-10-06 12:21:46 -05001048 catch (const std::exception& e)
Marri Devender Raoce6a7952018-02-11 08:45:00 -06001049 {
Chris Cain4cc61e02022-01-12 17:23:14 -06001050 log<level::ERR>("Failure to read power value from D-Bus object",
1051 entry("OBJECT_PATH=%s", objectPath.c_str()),
1052 entry("INTERFACE=%s", SENSOR_VALUE_INTF));
Marri Devender Raoce6a7952018-02-11 08:45:00 -06001053 }
Marri Devender Rao66c5fda2018-01-18 10:48:37 -06001054 return power;
1055}
1056
Willy Tu11d68892022-01-20 10:37:34 -08001057ipmi_ret_t setDCMIConfParams(ipmi_netfn_t, ipmi_cmd_t, ipmi_request_t request,
1058 ipmi_response_t, ipmi_data_len_t data_len,
1059 ipmi_context_t)
Nagaraju Goruganti22be97b2018-02-07 01:19:59 -06001060{
Patrick Venture0b02be92018-08-31 11:55:55 -07001061 auto requestData =
1062 reinterpret_cast<const dcmi::SetConfParamsRequest*>(request);
Nagaraju Goruganti22be97b2018-02-07 01:19:59 -06001063
William A. Kennington III5d06cc62019-04-25 02:10:55 -07001064 if (*data_len < DCMI_SET_CONF_PARAM_REQ_PACKET_MIN_SIZE ||
Patrick Venture0b02be92018-08-31 11:55:55 -07001065 *data_len > DCMI_SET_CONF_PARAM_REQ_PACKET_MAX_SIZE)
Nagaraju Goruganti22be97b2018-02-07 01:19:59 -06001066 {
William A. Kennington III5d06cc62019-04-25 02:10:55 -07001067 log<level::ERR>("Invalid Requested Packet size",
Nagaraju Goruganti22be97b2018-02-07 01:19:59 -06001068 entry("PACKET SIZE=%d", *data_len));
William A. Kennington III5d06cc62019-04-25 02:10:55 -07001069 *data_len = 0;
Nagaraju Goruganti22be97b2018-02-07 01:19:59 -06001070 return IPMI_CC_INVALID_FIELD_REQUEST;
1071 }
Nagaraju Goruganti22be97b2018-02-07 01:19:59 -06001072 *data_len = 0;
1073
1074 try
1075 {
1076 // Take action based on the Parameter Selector
Patrick Venture0b02be92018-08-31 11:55:55 -07001077 switch (
1078 static_cast<dcmi::DCMIConfigParameters>(requestData->paramSelect))
Nagaraju Goruganti22be97b2018-02-07 01:19:59 -06001079 {
1080 case dcmi::DCMIConfigParameters::ActivateDHCP:
1081
1082 if ((requestData->data[0] & DCMI_ACTIVATE_DHCP_MASK) &&
Thang Tran55cbf552023-01-31 14:43:02 +07001083 (dcmi::getDHCPEnabled() !=
1084 EthernetInterface::DHCPConf::none))
Nagaraju Goruganti22be97b2018-02-07 01:19:59 -06001085 {
Patrick Venture0b02be92018-08-31 11:55:55 -07001086 // When these conditions are met we have to trigger DHCP
1087 // protocol restart using the latest parameter settings, but
1088 // as per n/w manager design, each time when we update n/w
1089 // parameters, n/w service is restarted. So we no need to
1090 // take any action in this case.
Nagaraju Goruganti22be97b2018-02-07 01:19:59 -06001091 }
1092 break;
1093
1094 case dcmi::DCMIConfigParameters::DiscoveryConfig:
1095
1096 if (requestData->data[0] & DCMI_OPTION_12_MASK)
1097 {
1098 dcmi::setDHCPOption(DHCP_OPT12_ENABLED, true);
1099 }
1100 else
1101 {
1102 dcmi::setDHCPOption(DHCP_OPT12_ENABLED, false);
1103 }
1104
1105 // Systemd-networkd doesn't support Random Back off
1106 if (requestData->data[0] & DCMI_RAND_BACK_OFF_MASK)
1107 {
1108 return IPMI_CC_INVALID;
1109 }
1110 break;
1111 // Systemd-networkd doesn't allow to configure DHCP timigs
1112 case dcmi::DCMIConfigParameters::DHCPTiming1:
1113 case dcmi::DCMIConfigParameters::DHCPTiming2:
1114 case dcmi::DCMIConfigParameters::DHCPTiming3:
1115 default:
1116 return IPMI_CC_INVALID;
1117 }
1118 }
Patrick Williamsa2ad2da2021-10-06 12:21:46 -05001119 catch (const std::exception& e)
Nagaraju Goruganti22be97b2018-02-07 01:19:59 -06001120 {
1121 log<level::ERR>(e.what());
1122 return IPMI_CC_UNSPECIFIED_ERROR;
1123 }
Nagaraju Goruganti22be97b2018-02-07 01:19:59 -06001124 return IPMI_CC_OK;
1125}
1126
Willy Tu11d68892022-01-20 10:37:34 -08001127ipmi_ret_t getDCMIConfParams(ipmi_netfn_t, ipmi_cmd_t, ipmi_request_t request,
1128 ipmi_response_t response, ipmi_data_len_t data_len,
1129 ipmi_context_t)
Nagaraju Goruganti22be97b2018-02-07 01:19:59 -06001130{
Patrick Venture0b02be92018-08-31 11:55:55 -07001131 auto requestData =
1132 reinterpret_cast<const dcmi::GetConfParamsRequest*>(request);
1133 auto responseData =
1134 reinterpret_cast<dcmi::GetConfParamsResponse*>(response);
Nagaraju Goruganti22be97b2018-02-07 01:19:59 -06001135
1136 responseData->data[0] = 0x00;
1137
William A. Kennington III5d06cc62019-04-25 02:10:55 -07001138 if (*data_len != sizeof(dcmi::GetConfParamsRequest))
Nagaraju Goruganti22be97b2018-02-07 01:19:59 -06001139 {
William A. Kennington III5d06cc62019-04-25 02:10:55 -07001140 log<level::ERR>("Invalid Requested Packet size",
Nagaraju Goruganti22be97b2018-02-07 01:19:59 -06001141 entry("PACKET SIZE=%d", *data_len));
1142 return IPMI_CC_INVALID_FIELD_REQUEST;
1143 }
1144
1145 *data_len = 0;
1146
1147 try
1148 {
1149 // Take action based on the Parameter Selector
Patrick Venture0b02be92018-08-31 11:55:55 -07001150 switch (
1151 static_cast<dcmi::DCMIConfigParameters>(requestData->paramSelect))
Nagaraju Goruganti22be97b2018-02-07 01:19:59 -06001152 {
1153 case dcmi::DCMIConfigParameters::ActivateDHCP:
1154 responseData->data[0] = DCMI_ACTIVATE_DHCP_REPLY;
1155 *data_len = sizeof(dcmi::GetConfParamsResponse) + 1;
1156 break;
1157 case dcmi::DCMIConfigParameters::DiscoveryConfig:
1158 if (dcmi::getDHCPOption(DHCP_OPT12_ENABLED))
1159 {
1160 responseData->data[0] |= DCMI_OPTION_12_MASK;
1161 }
1162 *data_len = sizeof(dcmi::GetConfParamsResponse) + 1;
1163 break;
1164 // Get below values from Systemd-networkd source code
1165 case dcmi::DCMIConfigParameters::DHCPTiming1:
1166 responseData->data[0] = DHCP_TIMING1;
1167 *data_len = sizeof(dcmi::GetConfParamsResponse) + 1;
1168 break;
1169 case dcmi::DCMIConfigParameters::DHCPTiming2:
1170 responseData->data[0] = DHCP_TIMING2_LOWER;
1171 responseData->data[1] = DHCP_TIMING2_UPPER;
1172 *data_len = sizeof(dcmi::GetConfParamsResponse) + 2;
1173 break;
1174 case dcmi::DCMIConfigParameters::DHCPTiming3:
1175 responseData->data[0] = DHCP_TIMING3_LOWER;
1176 responseData->data[1] = DHCP_TIMING3_UPPER;
1177 *data_len = sizeof(dcmi::GetConfParamsResponse) + 2;
1178 break;
1179 default:
1180 *data_len = 0;
1181 return IPMI_CC_INVALID;
1182 }
1183 }
Patrick Williamsa2ad2da2021-10-06 12:21:46 -05001184 catch (const std::exception& e)
Nagaraju Goruganti22be97b2018-02-07 01:19:59 -06001185 {
1186 log<level::ERR>(e.what());
1187 return IPMI_CC_UNSPECIFIED_ERROR;
1188 }
1189
Nagaraju Goruganti22be97b2018-02-07 01:19:59 -06001190 responseData->major = DCMI_SPEC_MAJOR_VERSION;
1191 responseData->minor = DCMI_SPEC_MINOR_VERSION;
1192 responseData->paramRevision = DCMI_CONFIG_PARAMETER_REVISION;
1193
1194 return IPMI_CC_OK;
1195}
1196
Willy Tu11d68892022-01-20 10:37:34 -08001197ipmi_ret_t getPowerReading(ipmi_netfn_t, ipmi_cmd_t, ipmi_request_t,
1198 ipmi_response_t response, ipmi_data_len_t data_len,
1199 ipmi_context_t)
Marri Devender Rao66c5fda2018-01-18 10:48:37 -06001200{
Chalapathi Venkataramashetty90e81fa2021-05-11 09:13:23 +00001201 *data_len = 0;
Kirill Pakhomov2c2af2c2018-11-06 16:06:10 +03001202 if (!dcmi::isDCMIPowerMgmtSupported())
1203 {
Kirill Pakhomov2c2af2c2018-11-06 16:06:10 +03001204 log<level::ERR>("DCMI Power management is unsupported!");
1205 return IPMI_CC_INVALID;
1206 }
1207
Marri Devender Rao66c5fda2018-01-18 10:48:37 -06001208 ipmi_ret_t rc = IPMI_CC_OK;
Patrick Venture0b02be92018-08-31 11:55:55 -07001209 auto responseData =
1210 reinterpret_cast<dcmi::GetPowerReadingResponse*>(response);
Marri Devender Rao9c966e02018-01-22 05:55:10 -06001211
Patrick Williams5d82f472022-07-22 19:26:53 -05001212 sdbusplus::bus_t bus{ipmid_get_sd_bus_connection()};
Marri Devender Rao9c966e02018-01-22 05:55:10 -06001213 int64_t power = 0;
Marri Devender Rao66c5fda2018-01-18 10:48:37 -06001214 try
1215 {
Marri Devender Rao9c966e02018-01-22 05:55:10 -06001216 power = getPowerReading(bus);
Marri Devender Rao66c5fda2018-01-18 10:48:37 -06001217 }
Patrick Williamsa2ad2da2021-10-06 12:21:46 -05001218 catch (const InternalFailure& e)
Marri Devender Rao66c5fda2018-01-18 10:48:37 -06001219 {
1220 log<level::ERR>("Error in reading power sensor value",
1221 entry("INTERFACE=%s", SENSOR_VALUE_INTF),
1222 entry("PROPERTY=%s", SENSOR_VALUE_PROP));
1223 return IPMI_CC_UNSPECIFIED_ERROR;
1224 }
Marri Devender Rao9c966e02018-01-22 05:55:10 -06001225
1226 // TODO: openbmc/openbmc#2819
Gunnar Mills8466b792018-03-23 12:18:12 -05001227 // Minimum, Maximum, Average power, TimeFrame, TimeStamp,
Marri Devender Rao9c966e02018-01-22 05:55:10 -06001228 // PowerReadingState readings need to be populated
1229 // after Telemetry changes.
1230 uint16_t totalPower = static_cast<uint16_t>(power);
1231 responseData->currentPower = totalPower;
1232 responseData->minimumPower = totalPower;
1233 responseData->maximumPower = totalPower;
1234 responseData->averagePower = totalPower;
1235
1236 *data_len = sizeof(*responseData);
Marri Devender Rao66c5fda2018-01-18 10:48:37 -06001237 return rc;
1238}
1239
Deepak Kodihalli0b459552018-02-06 06:25:12 -06001240namespace dcmi
1241{
1242namespace sensor_info
1243{
1244
Deepak Kodihallidd4cff12018-02-06 06:48:29 -06001245Response createFromJson(const Json& config)
1246{
1247 Response response{};
1248 uint16_t recordId = config.value("record_id", 0);
1249 response.recordIdLsb = recordId & 0xFF;
1250 response.recordIdMsb = (recordId >> 8) & 0xFF;
1251 return response;
1252}
1253
Deepak Kodihalli0b459552018-02-06 06:25:12 -06001254std::tuple<Response, NumInstances> read(const std::string& type,
Patrick Venture0b02be92018-08-31 11:55:55 -07001255 uint8_t instance, const Json& config)
Deepak Kodihalli0b459552018-02-06 06:25:12 -06001256{
Deepak Kodihallidd4cff12018-02-06 06:48:29 -06001257 Response response{};
1258
1259 if (!instance)
1260 {
1261 log<level::ERR>("Expected non-zero instance");
1262 elog<InternalFailure>();
1263 }
1264
1265 static const std::vector<Json> empty{};
1266 std::vector<Json> readings = config.value(type, empty);
1267 size_t numInstances = readings.size();
1268 for (const auto& reading : readings)
1269 {
1270 uint8_t instanceNum = reading.value("instance", 0);
1271 // Not the instance we're interested in
1272 if (instanceNum != instance)
1273 {
1274 continue;
1275 }
1276
1277 response = createFromJson(reading);
1278
1279 // Found the instance we're interested in
1280 break;
1281 }
1282
1283 if (numInstances > maxInstances)
1284 {
1285 log<level::DEBUG>("Trimming IPMI num instances",
1286 entry("NUM_INSTANCES=%d", numInstances));
1287 numInstances = maxInstances;
1288 }
1289 return std::make_tuple(response, numInstances);
Deepak Kodihalli0b459552018-02-06 06:25:12 -06001290}
1291
Patrick Venture0b02be92018-08-31 11:55:55 -07001292std::tuple<ResponseList, NumInstances>
1293 readAll(const std::string& type, uint8_t instanceStart, const Json& config)
Deepak Kodihalli0b459552018-02-06 06:25:12 -06001294{
Deepak Kodihallidd4cff12018-02-06 06:48:29 -06001295 ResponseList responses{};
1296
1297 size_t numInstances = 0;
1298 static const std::vector<Json> empty{};
1299 std::vector<Json> readings = config.value(type, empty);
1300 numInstances = readings.size();
1301 for (const auto& reading : readings)
1302 {
1303 try
1304 {
1305 // Max of 8 records
1306 if (responses.size() == maxRecords)
1307 {
1308 break;
1309 }
1310
1311 uint8_t instanceNum = reading.value("instance", 0);
1312 // Not in the instance range we're interested in
1313 if (instanceNum < instanceStart)
1314 {
1315 continue;
1316 }
1317
1318 Response response = createFromJson(reading);
1319 responses.push_back(response);
1320 }
Patrick Williamsa2ad2da2021-10-06 12:21:46 -05001321 catch (const std::exception& e)
Deepak Kodihallidd4cff12018-02-06 06:48:29 -06001322 {
1323 log<level::DEBUG>(e.what());
1324 continue;
1325 }
1326 }
1327
1328 if (numInstances > maxInstances)
1329 {
1330 log<level::DEBUG>("Trimming IPMI num instances",
1331 entry("NUM_INSTANCES=%d", numInstances));
1332 numInstances = maxInstances;
1333 }
1334 return std::make_tuple(responses, numInstances);
Deepak Kodihalli0b459552018-02-06 06:25:12 -06001335}
1336
1337} // namespace sensor_info
1338} // namespace dcmi
1339
Willy Tu11d68892022-01-20 10:37:34 -08001340ipmi_ret_t getSensorInfo(ipmi_netfn_t, ipmi_cmd_t, ipmi_request_t request,
1341 ipmi_response_t response, ipmi_data_len_t data_len,
1342 ipmi_context_t)
Deepak Kodihalli0b459552018-02-06 06:25:12 -06001343{
1344 auto requestData =
1345 reinterpret_cast<const dcmi::GetSensorInfoRequest*>(request);
1346 auto responseData =
1347 reinterpret_cast<dcmi::GetSensorInfoResponseHdr*>(response);
1348
1349 if (*data_len != sizeof(dcmi::GetSensorInfoRequest))
1350 {
1351 log<level::ERR>("Malformed request data",
1352 entry("DATA_SIZE=%d", *data_len));
1353 return IPMI_CC_REQ_DATA_LEN_INVALID;
1354 }
1355 *data_len = 0;
1356
1357 auto it = dcmi::entityIdToName.find(requestData->entityId);
1358 if (it == dcmi::entityIdToName.end())
1359 {
1360 log<level::ERR>("Unknown Entity ID",
1361 entry("ENTITY_ID=%d", requestData->entityId));
1362 return IPMI_CC_INVALID_FIELD_REQUEST;
1363 }
1364
Deepak Kodihalli0b459552018-02-06 06:25:12 -06001365 if (requestData->sensorType != dcmi::temperatureSensorType)
1366 {
1367 log<level::ERR>("Invalid sensor type",
1368 entry("SENSOR_TYPE=%d", requestData->sensorType));
1369 return IPMI_CC_INVALID_FIELD_REQUEST;
1370 }
1371
1372 dcmi::sensor_info::ResponseList sensors{};
1373 static dcmi::Json config{};
1374 static bool parsed = false;
1375
1376 try
1377 {
1378 if (!parsed)
1379 {
Kirill Pakhomova2573622018-11-02 19:00:18 +03001380 config = dcmi::parseJSONConfig(dcmi::gDCMISensorsConfig);
Deepak Kodihalli0b459552018-02-06 06:25:12 -06001381 parsed = true;
1382 }
1383
1384 if (!requestData->entityInstance)
1385 {
1386 // Read all instances
1387 std::tie(sensors, responseData->numInstances) =
1388 dcmi::sensor_info::readAll(it->second,
Patrick Venture0b02be92018-08-31 11:55:55 -07001389 requestData->instanceStart, config);
Deepak Kodihalli0b459552018-02-06 06:25:12 -06001390 }
1391 else
1392 {
1393 // Read one instance
1394 sensors.resize(1);
1395 std::tie(sensors[0], responseData->numInstances) =
Patrick Venture0b02be92018-08-31 11:55:55 -07001396 dcmi::sensor_info::read(it->second, requestData->entityInstance,
Deepak Kodihalli0b459552018-02-06 06:25:12 -06001397 config);
1398 }
1399 responseData->numRecords = sensors.size();
1400 }
Patrick Williamsa2ad2da2021-10-06 12:21:46 -05001401 catch (const InternalFailure& e)
Deepak Kodihalli0b459552018-02-06 06:25:12 -06001402 {
1403 return IPMI_CC_UNSPECIFIED_ERROR;
1404 }
1405
Deepak Kodihalli0b459552018-02-06 06:25:12 -06001406 size_t payloadSize = sensors.size() * sizeof(dcmi::sensor_info::Response);
1407 if (!sensors.empty())
1408 {
1409 memcpy(responseData + 1, // copy payload right after the response header
Patrick Venture0b02be92018-08-31 11:55:55 -07001410 sensors.data(), payloadSize);
Deepak Kodihalli0b459552018-02-06 06:25:12 -06001411 }
1412 *data_len = sizeof(dcmi::GetSensorInfoResponseHdr) + payloadSize;
1413
1414 return IPMI_CC_OK;
1415}
1416
Chris Austen1810bec2015-10-13 12:12:39 -05001417void register_netfn_dcmi_functions()
1418{
Tom05732372016-09-06 17:21:23 +05301419 // <Get Power Limit>
Ratan Gupta11ddbd22017-08-05 11:59:39 +05301420
Patrick Venture0b02be92018-08-31 11:55:55 -07001421 ipmi_register_callback(NETFUN_GRPEXT, dcmi::Commands::GET_POWER_LIMIT, NULL,
1422 getPowerLimit, PRIVILEGE_USER);
Tom Joseph6f6dd4d2017-07-12 20:07:11 +05301423
Tom Joseph46fa37d2017-07-26 18:11:55 +05301424 // <Set Power Limit>
Ratan Gupta11ddbd22017-08-05 11:59:39 +05301425
Patrick Venture0b02be92018-08-31 11:55:55 -07001426 ipmi_register_callback(NETFUN_GRPEXT, dcmi::Commands::SET_POWER_LIMIT, NULL,
1427 setPowerLimit, PRIVILEGE_OPERATOR);
Tom Joseph46fa37d2017-07-26 18:11:55 +05301428
Tom Joseph6c8d51b2017-07-26 18:18:06 +05301429 // <Activate/Deactivate Power Limit>
Ratan Gupta11ddbd22017-08-05 11:59:39 +05301430
1431 ipmi_register_callback(NETFUN_GRPEXT, dcmi::Commands::APPLY_POWER_LIMIT,
1432 NULL, applyPowerLimit, PRIVILEGE_OPERATOR);
Tom Joseph6c8d51b2017-07-26 18:18:06 +05301433
Tom Joseph6f6dd4d2017-07-12 20:07:11 +05301434 // <Get Asset Tag>
Ratan Gupta11ddbd22017-08-05 11:59:39 +05301435
Patrick Venture0b02be92018-08-31 11:55:55 -07001436 ipmi_register_callback(NETFUN_GRPEXT, dcmi::Commands::GET_ASSET_TAG, NULL,
1437 getAssetTag, PRIVILEGE_USER);
Tom Joseph545dd232017-07-12 20:20:49 +05301438
1439 // <Set Asset Tag>
Ratan Gupta11ddbd22017-08-05 11:59:39 +05301440
Patrick Venture0b02be92018-08-31 11:55:55 -07001441 ipmi_register_callback(NETFUN_GRPEXT, dcmi::Commands::SET_ASSET_TAG, NULL,
1442 setAssetTag, PRIVILEGE_OPERATOR);
Vladislav Vovchenko8f7a6f62017-08-17 00:31:14 +03001443
Gunnar Mills8991dd62017-10-25 17:11:29 -05001444 // <Get Management Controller Identifier String>
Vladislav Vovchenko8f7a6f62017-08-17 00:31:14 +03001445
1446 ipmi_register_callback(NETFUN_GRPEXT, dcmi::Commands::GET_MGMNT_CTRL_ID_STR,
Patrick Venture0b02be92018-08-31 11:55:55 -07001447 NULL, getMgmntCtrlIdStr, PRIVILEGE_USER);
Vladislav Vovchenko8f7a6f62017-08-17 00:31:14 +03001448
1449 // <Set Management Controller Identifier String>
Vladislav Vovchenko8f7a6f62017-08-17 00:31:14 +03001450 ipmi_register_callback(NETFUN_GRPEXT, dcmi::Commands::SET_MGMNT_CTRL_ID_STR,
Patrick Venture0b02be92018-08-31 11:55:55 -07001451 NULL, setMgmntCtrlIdStr, PRIVILEGE_ADMIN);
Vladislav Vovchenko8f7a6f62017-08-17 00:31:14 +03001452
Dhruvaraj Subhashchandrane29be412018-01-16 05:11:56 -06001453 // <Get DCMI capabilities>
1454 ipmi_register_callback(NETFUN_GRPEXT, dcmi::Commands::GET_CAPABILITIES,
Patrick Venture0b02be92018-08-31 11:55:55 -07001455 NULL, getDCMICapabilities, PRIVILEGE_USER);
Deepak Kodihalliee717d72018-01-24 04:53:09 -06001456
1457 // <Get Temperature Readings>
1458 ipmi_register_callback(NETFUN_GRPEXT, dcmi::Commands::GET_TEMP_READINGS,
1459 NULL, getTempReadings, PRIVILEGE_USER);
1460
Marri Devender Rao66c5fda2018-01-18 10:48:37 -06001461 // <Get Power Reading>
1462 ipmi_register_callback(NETFUN_GRPEXT, dcmi::Commands::GET_POWER_READING,
1463 NULL, getPowerReading, PRIVILEGE_USER);
adarshgrami042e9db2022-09-15 10:34:34 +05301464// The Get sensor should get the senor details dynamically when
1465// FEATURE_DYNAMIC_SENSORS is enabled.
1466#ifndef FEATURE_DYNAMIC_SENSORS
Deepak Kodihalli0b459552018-02-06 06:25:12 -06001467 // <Get Sensor Info>
Patrick Venture0b02be92018-08-31 11:55:55 -07001468 ipmi_register_callback(NETFUN_GRPEXT, dcmi::Commands::GET_SENSOR_INFO, NULL,
Chau Lyd74df5f2023-05-25 10:33:00 +00001469 getSensorInfo, PRIVILEGE_OPERATOR);
adarshgrami042e9db2022-09-15 10:34:34 +05301470#endif
Nagaraju Goruganti22be97b2018-02-07 01:19:59 -06001471 // <Get DCMI Configuration Parameters>
Patrick Venture0b02be92018-08-31 11:55:55 -07001472 ipmi_register_callback(NETFUN_GRPEXT, dcmi::Commands::GET_CONF_PARAMS, NULL,
1473 getDCMIConfParams, PRIVILEGE_USER);
Nagaraju Goruganti22be97b2018-02-07 01:19:59 -06001474
1475 // <Set DCMI Configuration Parameters>
Patrick Venture0b02be92018-08-31 11:55:55 -07001476 ipmi_register_callback(NETFUN_GRPEXT, dcmi::Commands::SET_CONF_PARAMS, NULL,
1477 setDCMIConfParams, PRIVILEGE_ADMIN);
Nagaraju Goruganti22be97b2018-02-07 01:19:59 -06001478
Chris Austen1810bec2015-10-13 12:12:39 -05001479 return;
1480}
Tom05732372016-09-06 17:21:23 +05301481// 956379