blob: e2c01675fc12f781cc0c87130e404af5c1667ee4 [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
Vernon Maueryd4222fd2023-07-27 11:26:51 -070029constexpr auto pcapPath = "/xyz/openbmc_project/control/host0/power_cap";
30constexpr auto pcapInterface = "xyz.openbmc_project.Control.Power.Cap";
Andrew Geissler50c0c8f2017-07-11 16:18:51 -050031
Vernon Maueryd4222fd2023-07-27 11:26:51 -070032constexpr auto powerCapProp = "PowerCap";
33constexpr auto powerCapEnableProp = "PowerCapEnable";
Andrew Geissler50c0c8f2017-07-11 16:18:51 -050034
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{
Vernon Mauerydca47202023-07-27 11:32:01 -070063constexpr auto assetTagMaxOffset = 62;
64constexpr auto assetTagMaxSize = 63;
65constexpr auto maxBytes = 16;
66constexpr size_t maxCtrlIdStrLen = 63;
Tom Josephb9d86f42017-07-26 18:03:47 +053067
Deepak Kodihalli0b459552018-02-06 06:25:12 -060068// Refer Table 6-14, DCMI Entity ID Extension, DCMI v1.5 spec
Patrick Venture0b02be92018-08-31 11:55:55 -070069static const std::map<uint8_t, std::string> entityIdToName{
70 {0x40, "inlet"}, {0x37, "inlet"}, {0x41, "cpu"},
71 {0x03, "cpu"}, {0x42, "baseboard"}, {0x07, "baseboard"}};
Deepak Kodihalli0b459552018-02-06 06:25:12 -060072
Kirill Pakhomov2c2af2c2018-11-06 16:06:10 +030073bool isDCMIPowerMgmtSupported()
74{
Vernon Maueryf4eb35d2023-07-27 11:08:49 -070075 static bool parsed = false;
76 static bool supported = false;
77 if (!parsed)
78 {
79 auto data = parseJSONConfig(gDCMICapabilitiesConfig);
Kirill Pakhomov2c2af2c2018-11-06 16:06:10 +030080
Vernon Maueryf4eb35d2023-07-27 11:08:49 -070081 supported = (gDCMIPowerMgmtSupported ==
82 data.value(gDCMIPowerMgmtCapability, 0));
83 }
84 return supported;
Kirill Pakhomov2c2af2c2018-11-06 16:06:10 +030085}
86
Vernon Maueryd4222fd2023-07-27 11:26:51 -070087std::optional<uint32_t> getPcap(ipmi::Context::ptr& ctx)
Andrew Geissler50c0c8f2017-07-11 16:18:51 -050088{
Vernon Maueryd4222fd2023-07-27 11:26:51 -070089 std::string service{};
90 boost::system::error_code ec = ipmi::getService(ctx, pcapInterface,
91 pcapPath, service);
92 if (ec.value())
Andrew Geissler50c0c8f2017-07-11 16:18:51 -050093 {
Vernon Maueryd4222fd2023-07-27 11:26:51 -070094 return std::nullopt;
George Liu3e3cc352023-07-26 15:59:31 +080095 }
Vernon Maueryd4222fd2023-07-27 11:26:51 -070096 uint32_t pcap{};
97 ec = ipmi::getDbusProperty(ctx, service, pcapPath, pcapInterface,
98 powerCapProp, pcap);
99 if (ec.value())
George Liu3e3cc352023-07-26 15:59:31 +0800100 {
Vernon Maueryd4222fd2023-07-27 11:26:51 -0700101 log<level::ERR>("Error in getPcap prop",
102 entry("ERROR=%s", ec.message().c_str()));
Tom Josephb9d86f42017-07-26 18:03:47 +0530103 elog<InternalFailure>();
Vernon Maueryd4222fd2023-07-27 11:26:51 -0700104 return std::nullopt;
Andrew Geissler50c0c8f2017-07-11 16:18:51 -0500105 }
Vernon Maueryd4222fd2023-07-27 11:26:51 -0700106 return pcap;
Andrew Geissler50c0c8f2017-07-11 16:18:51 -0500107}
108
Vernon Maueryd4222fd2023-07-27 11:26:51 -0700109std::optional<bool> getPcapEnabled(ipmi::Context::ptr& ctx)
Andrew Geissler50c0c8f2017-07-11 16:18:51 -0500110{
Vernon Maueryd4222fd2023-07-27 11:26:51 -0700111 std::string service{};
112 boost::system::error_code ec = ipmi::getService(ctx, pcapInterface,
113 pcapPath, service);
114 if (ec.value())
Andrew Geissler50c0c8f2017-07-11 16:18:51 -0500115 {
Vernon Maueryd4222fd2023-07-27 11:26:51 -0700116 return std::nullopt;
George Liu3e3cc352023-07-26 15:59:31 +0800117 }
Vernon Maueryd4222fd2023-07-27 11:26:51 -0700118 bool pcapEnabled{};
119 ec = ipmi::getDbusProperty(ctx, service, pcapPath, pcapInterface,
120 powerCapEnableProp, pcapEnabled);
121 if (ec.value())
George Liu3e3cc352023-07-26 15:59:31 +0800122 {
Vernon Maueryd4222fd2023-07-27 11:26:51 -0700123 log<level::ERR>("Error in getPcap prop");
Tom Josephb9d86f42017-07-26 18:03:47 +0530124 elog<InternalFailure>();
Vernon Maueryd4222fd2023-07-27 11:26:51 -0700125 return std::nullopt;
Andrew Geissler50c0c8f2017-07-11 16:18:51 -0500126 }
Vernon Maueryd4222fd2023-07-27 11:26:51 -0700127 return pcapEnabled;
Andrew Geissler50c0c8f2017-07-11 16:18:51 -0500128}
Chris Austen1810bec2015-10-13 12:12:39 -0500129
Vernon Maueryd4222fd2023-07-27 11:26:51 -0700130bool setPcap(ipmi::Context::ptr& ctx, const uint32_t powerCap)
Tom Joseph46fa37d2017-07-26 18:11:55 +0530131{
Vernon Maueryd4222fd2023-07-27 11:26:51 -0700132 std::string service{};
133 boost::system::error_code ec = ipmi::getService(ctx, pcapInterface,
134 pcapPath, service);
135 if (ec.value())
Tom Joseph46fa37d2017-07-26 18:11:55 +0530136 {
Vernon Maueryd4222fd2023-07-27 11:26:51 -0700137 return false;
George Liu3e3cc352023-07-26 15:59:31 +0800138 }
Vernon Maueryd4222fd2023-07-27 11:26:51 -0700139
140 ec = ipmi::setDbusProperty(ctx, service, pcapPath, pcapInterface,
141 powerCapProp, powerCap);
142 if (ec.value())
George Liu3e3cc352023-07-26 15:59:31 +0800143 {
144 log<level::ERR>("Error in setPcap property",
Vernon Maueryd4222fd2023-07-27 11:26:51 -0700145 entry("ERROR=%s", ec.message().c_str()));
Tom Joseph46fa37d2017-07-26 18:11:55 +0530146 elog<InternalFailure>();
Vernon Maueryd4222fd2023-07-27 11:26:51 -0700147 return false;
Tom Joseph46fa37d2017-07-26 18:11:55 +0530148 }
Vernon Maueryd4222fd2023-07-27 11:26:51 -0700149 return true;
Tom Joseph46fa37d2017-07-26 18:11:55 +0530150}
151
Vernon Maueryd4222fd2023-07-27 11:26:51 -0700152bool setPcapEnable(ipmi::Context::ptr& ctx, bool enabled)
Tom Joseph6c8d51b2017-07-26 18:18:06 +0530153{
Vernon Maueryd4222fd2023-07-27 11:26:51 -0700154 std::string service{};
155 boost::system::error_code ec = ipmi::getService(ctx, pcapInterface,
156 pcapPath, service);
157 if (ec.value())
Tom Joseph6c8d51b2017-07-26 18:18:06 +0530158 {
Vernon Maueryd4222fd2023-07-27 11:26:51 -0700159 return false;
George Liu3e3cc352023-07-26 15:59:31 +0800160 }
Vernon Maueryd4222fd2023-07-27 11:26:51 -0700161
162 ec = ipmi::setDbusProperty(ctx, service, pcapPath, pcapInterface,
163 powerCapEnableProp, enabled);
164 if (ec.value())
George Liu3e3cc352023-07-26 15:59:31 +0800165 {
166 log<level::ERR>("Error in setPcapEnabled property",
Vernon Maueryd4222fd2023-07-27 11:26:51 -0700167 entry("ERROR=%s", ec.message().c_str()));
Tom Joseph6c8d51b2017-07-26 18:18:06 +0530168 elog<InternalFailure>();
Vernon Maueryd4222fd2023-07-27 11:26:51 -0700169 return false;
Tom Joseph6c8d51b2017-07-26 18:18:06 +0530170 }
Vernon Maueryd4222fd2023-07-27 11:26:51 -0700171 return true;
Tom Joseph6c8d51b2017-07-26 18:18:06 +0530172}
173
Vernon Mauerydca47202023-07-27 11:32:01 -0700174std::optional<std::string> readAssetTag(ipmi::Context::ptr& ctx)
Tom Josephbe5eaa12017-07-12 19:54:44 +0530175{
Tom Josephbe5eaa12017-07-12 19:54:44 +0530176 // Read the object tree with the inventory root to figure out the object
177 // that has implemented the Asset tag interface.
Vernon Mauerydca47202023-07-27 11:32:01 -0700178 ipmi::DbusObjectInfo objectInfo;
179 boost::system::error_code ec = getDbusObject(
180 ctx, dcmi::assetTagIntf, ipmi::sensor::inventoryRoot, "", objectInfo);
181 if (ec.value())
Tom Josephbe5eaa12017-07-12 19:54:44 +0530182 {
Vernon Mauerydca47202023-07-27 11:32:01 -0700183 return std::nullopt;
George Liu3e3cc352023-07-26 15:59:31 +0800184 }
Vernon Mauerydca47202023-07-27 11:32:01 -0700185
186 std::string assetTag{};
187 ec = ipmi::getDbusProperty(ctx, objectInfo.second, objectInfo.first,
188 dcmi::assetTagIntf, dcmi::assetTagProp,
189 assetTag);
190 if (ec.value())
George Liu3e3cc352023-07-26 15:59:31 +0800191 {
192 log<level::ERR>("Error in reading asset tag",
Vernon Mauerydca47202023-07-27 11:32:01 -0700193 entry("ERROR=%s", ec.message().c_str()));
Tom Josephbe5eaa12017-07-12 19:54:44 +0530194 elog<InternalFailure>();
Vernon Mauerydca47202023-07-27 11:32:01 -0700195 return std::nullopt;
Tom Josephbe5eaa12017-07-12 19:54:44 +0530196 }
Vernon Mauerydca47202023-07-27 11:32:01 -0700197
198 return assetTag;
Tom Josephbe5eaa12017-07-12 19:54:44 +0530199}
200
Vernon Mauerydca47202023-07-27 11:32:01 -0700201bool writeAssetTag(ipmi::Context::ptr& ctx, const std::string& assetTag)
Tom Josephbe5b9892017-07-15 00:55:23 +0530202{
Tom Josephbe5b9892017-07-15 00:55:23 +0530203 // Read the object tree with the inventory root to figure out the object
204 // that has implemented the Asset tag interface.
Vernon Mauerydca47202023-07-27 11:32:01 -0700205 ipmi::DbusObjectInfo objectInfo;
206 boost::system::error_code ec = getDbusObject(
207 ctx, dcmi::assetTagIntf, ipmi::sensor::inventoryRoot, "", objectInfo);
208 if (ec.value())
Tom Josephbe5b9892017-07-15 00:55:23 +0530209 {
Vernon Mauerydca47202023-07-27 11:32:01 -0700210 return false;
George Liu3e3cc352023-07-26 15:59:31 +0800211 }
Vernon Mauerydca47202023-07-27 11:32:01 -0700212
213 ec = ipmi::setDbusProperty(ctx, objectInfo.second, objectInfo.first,
214 dcmi::assetTagIntf, dcmi::assetTagProp,
215 assetTag);
216 if (ec.value())
George Liu3e3cc352023-07-26 15:59:31 +0800217 {
218 log<level::ERR>("Error in writing asset tag",
Vernon Mauerydca47202023-07-27 11:32:01 -0700219 entry("ERROR=%s", ec.message().c_str()));
Tom Josephbe5b9892017-07-15 00:55:23 +0530220 elog<InternalFailure>();
Vernon Mauerydca47202023-07-27 11:32:01 -0700221 return false;
Tom Josephbe5b9892017-07-15 00:55:23 +0530222 }
Vernon Mauerydca47202023-07-27 11:32:01 -0700223 return true;
Tom Josephbe5b9892017-07-15 00:55:23 +0530224}
225
Vladislav Vovchenko8f7a6f62017-08-17 00:31:14 +0300226std::string getHostName(void)
227{
Patrick Williams5d82f472022-07-22 19:26:53 -0500228 sdbusplus::bus_t bus{ipmid_get_sd_bus_connection()};
Vladislav Vovchenko8f7a6f62017-08-17 00:31:14 +0300229
230 auto service = ipmi::getService(bus, networkConfigIntf, networkConfigObj);
Patrick Venture0b02be92018-08-31 11:55:55 -0700231 auto value = ipmi::getDbusProperty(bus, service, networkConfigObj,
232 networkConfigIntf, hostNameProp);
Vladislav Vovchenko8f7a6f62017-08-17 00:31:14 +0300233
Vernon Maueryf442e112019-04-09 11:44:36 -0700234 return std::get<std::string>(value);
Vladislav Vovchenko8f7a6f62017-08-17 00:31:14 +0300235}
236
Thang Tran55cbf552023-01-31 14:43:02 +0700237EthernetInterface::DHCPConf getDHCPEnabled()
Nagaraju Goruganti22be97b2018-02-07 01:19:59 -0600238{
Patrick Williams5d82f472022-07-22 19:26:53 -0500239 sdbusplus::bus_t bus{ipmid_get_sd_bus_connection()};
Nagaraju Goruganti22be97b2018-02-07 01:19:59 -0600240
Johnathan Mantey74a21022018-12-13 13:17:56 -0800241 auto ethdevice = ipmi::getChannelName(ethernetDefaultChannelNum);
Patrick Williamsfbc6c9d2023-05-10 07:50:16 -0500242 auto ethernetObj = ipmi::getDbusObject(bus, ethernetIntf, networkRoot,
243 ethdevice);
Nagaraju Goruganti22be97b2018-02-07 01:19:59 -0600244 auto service = ipmi::getService(bus, ethernetIntf, ethernetObj.first);
Patrick Venture0b02be92018-08-31 11:55:55 -0700245 auto value = ipmi::getDbusProperty(bus, service, ethernetObj.first,
246 ethernetIntf, "DHCPEnabled");
Nagaraju Goruganti22be97b2018-02-07 01:19:59 -0600247
Thang Tran55cbf552023-01-31 14:43:02 +0700248 return EthernetInterface::convertDHCPConfFromString(
249 std::get<std::string>(value));
Nagaraju Goruganti22be97b2018-02-07 01:19:59 -0600250}
251
252bool getDHCPOption(std::string prop)
253{
Patrick Williams5d82f472022-07-22 19:26:53 -0500254 sdbusplus::bus_t bus{ipmid_get_sd_bus_connection()};
Nagaraju Goruganti22be97b2018-02-07 01:19:59 -0600255
256 auto service = ipmi::getService(bus, dhcpIntf, dhcpObj);
257 auto value = ipmi::getDbusProperty(bus, service, dhcpObj, dhcpIntf, prop);
258
Vernon Maueryf442e112019-04-09 11:44:36 -0700259 return std::get<bool>(value);
Nagaraju Goruganti22be97b2018-02-07 01:19:59 -0600260}
261
Nagaraju Goruganti22be97b2018-02-07 01:19:59 -0600262void setDHCPOption(std::string prop, bool value)
263{
Patrick Williams5d82f472022-07-22 19:26:53 -0500264 sdbusplus::bus_t bus{ipmid_get_sd_bus_connection()};
Nagaraju Goruganti22be97b2018-02-07 01:19:59 -0600265
266 auto service = ipmi::getService(bus, dhcpIntf, dhcpObj);
267 ipmi::setDbusProperty(bus, service, dhcpObj, dhcpIntf, prop, value);
268}
269
Kirill Pakhomova2573622018-11-02 19:00:18 +0300270Json parseJSONConfig(const std::string& configFile)
Deepak Kodihalli0b459552018-02-06 06:25:12 -0600271{
272 std::ifstream jsonFile(configFile);
273 if (!jsonFile.is_open())
274 {
275 log<level::ERR>("Temperature readings JSON file not found");
276 elog<InternalFailure>();
277 }
278
279 auto data = Json::parse(jsonFile, nullptr, false);
280 if (data.is_discarded())
281 {
282 log<level::ERR>("Temperature readings JSON parser failure");
283 elog<InternalFailure>();
284 }
285
286 return data;
287}
288
Tom Josephbe5eaa12017-07-12 19:54:44 +0530289} // namespace dcmi
Chris Austen1810bec2015-10-13 12:12:39 -0500290
Vernon Maueryd4222fd2023-07-27 11:26:51 -0700291constexpr uint8_t exceptionPowerOff = 0x01;
292ipmi::RspType<uint16_t, // reserved
293 uint8_t, // exception actions
294 uint16_t, // power limit requested in watts
295 uint32_t, // correction time in milliseconds
296 uint16_t, // reserved
297 uint16_t // statistics sampling period in seconds
298 >
299 getPowerLimit(ipmi::Context::ptr ctx, uint16_t reserved)
Tom Josephb9d86f42017-07-26 18:03:47 +0530300{
Kirill Pakhomov2c2af2c2018-11-06 16:06:10 +0300301 if (!dcmi::isDCMIPowerMgmtSupported())
302 {
Vernon Maueryd4222fd2023-07-27 11:26:51 -0700303 return ipmi::responseInvalidCommand();
Kirill Pakhomov2c2af2c2018-11-06 16:06:10 +0300304 }
Vernon Maueryd4222fd2023-07-27 11:26:51 -0700305 if (reserved)
Tom Josephb9d86f42017-07-26 18:03:47 +0530306 {
Vernon Maueryd4222fd2023-07-27 11:26:51 -0700307 return ipmi::responseInvalidFieldRequest();
Tom Josephb9d86f42017-07-26 18:03:47 +0530308 }
309
Vernon Maueryd4222fd2023-07-27 11:26:51 -0700310 std::optional<uint16_t> pcapValue = dcmi::getPcap(ctx);
311 std::optional<bool> pcapEnable = dcmi::getPcapEnabled(ctx);
312 if (!pcapValue || !pcapEnable)
313 {
314 return ipmi::responseUnspecifiedError();
315 }
316
317 constexpr uint16_t reserved1{};
318 constexpr uint16_t reserved2{};
Tom Josephb9d86f42017-07-26 18:03:47 +0530319 /*
320 * Exception action if power limit is exceeded and cannot be controlled
321 * with the correction time limit is hardcoded to Hard Power Off system
322 * and log event to SEL.
323 */
Vernon Maueryd4222fd2023-07-27 11:26:51 -0700324 constexpr uint8_t exception = exceptionPowerOff;
Tom Josephb9d86f42017-07-26 18:03:47 +0530325 /*
326 * Correction time limit and Statistics sampling period is currently not
327 * populated.
328 */
Vernon Maueryd4222fd2023-07-27 11:26:51 -0700329 constexpr uint32_t correctionTime{};
330 constexpr uint16_t statsPeriod{};
331 if (!pcapEnable)
Tom Josephb9d86f42017-07-26 18:03:47 +0530332 {
Vernon Maueryd4222fd2023-07-27 11:26:51 -0700333 constexpr ipmi::Cc responseNoPowerLimitSet = 0x80;
334 constexpr uint16_t noPcap{};
335 return ipmi::response(responseNoPowerLimitSet, reserved1, exception,
336 noPcap, correctionTime, reserved2, statsPeriod);
Tom Josephb9d86f42017-07-26 18:03:47 +0530337 }
Vernon Maueryd4222fd2023-07-27 11:26:51 -0700338 return ipmi::responseSuccess(reserved1, exception, *pcapValue,
339 correctionTime, reserved2, statsPeriod);
Tom Josephb9d86f42017-07-26 18:03:47 +0530340}
341
Vernon Maueryd4222fd2023-07-27 11:26:51 -0700342ipmi::RspType<> setPowerLimit(ipmi::Context::ptr& ctx, uint16_t reserved1,
343 uint8_t exceptionAction, uint16_t powerLimit,
344 uint32_t correctionTime, uint16_t reserved2,
345 uint16_t statsPeriod)
Tom Joseph46fa37d2017-07-26 18:11:55 +0530346{
Kirill Pakhomov2c2af2c2018-11-06 16:06:10 +0300347 if (!dcmi::isDCMIPowerMgmtSupported())
348 {
Kirill Pakhomov2c2af2c2018-11-06 16:06:10 +0300349 log<level::ERR>("DCMI Power management is unsupported!");
Vernon Maueryd4222fd2023-07-27 11:26:51 -0700350 return ipmi::responseInvalidCommand();
Kirill Pakhomov2c2af2c2018-11-06 16:06:10 +0300351 }
352
Vernon Maueryd4222fd2023-07-27 11:26:51 -0700353 // Only process the power limit requested in watts. Return errors
354 // for other fields that are set
355 if (reserved1 || reserved2 || correctionTime || statsPeriod ||
356 exceptionAction != exceptionPowerOff)
Tom Joseph46fa37d2017-07-26 18:11:55 +0530357 {
Vernon Maueryd4222fd2023-07-27 11:26:51 -0700358 return ipmi::responseInvalidFieldRequest();
Tom Joseph46fa37d2017-07-26 18:11:55 +0530359 }
Vernon Maueryd4222fd2023-07-27 11:26:51 -0700360
361 if (!dcmi::setPcap(ctx, powerLimit))
Tom Joseph46fa37d2017-07-26 18:11:55 +0530362 {
Vernon Maueryd4222fd2023-07-27 11:26:51 -0700363 return ipmi::responseUnspecifiedError();
Tom Joseph46fa37d2017-07-26 18:11:55 +0530364 }
365
Vernon Maueryd4222fd2023-07-27 11:26:51 -0700366 log<level::INFO>("Set Power Cap", entry("POWERCAP=%u", powerLimit));
Tom Joseph46fa37d2017-07-26 18:11:55 +0530367
Vernon Maueryd4222fd2023-07-27 11:26:51 -0700368 return ipmi::responseSuccess();
Tom Joseph46fa37d2017-07-26 18:11:55 +0530369}
370
Vernon Maueryd4222fd2023-07-27 11:26:51 -0700371ipmi::RspType<> applyPowerLimit(ipmi::Context::ptr& ctx, bool enabled,
372 uint7_t reserved1, uint16_t reserved2)
Tom Joseph6c8d51b2017-07-26 18:18:06 +0530373{
Kirill Pakhomov2c2af2c2018-11-06 16:06:10 +0300374 if (!dcmi::isDCMIPowerMgmtSupported())
375 {
Kirill Pakhomov2c2af2c2018-11-06 16:06:10 +0300376 log<level::ERR>("DCMI Power management is unsupported!");
Vernon Maueryd4222fd2023-07-27 11:26:51 -0700377 return ipmi::responseInvalidCommand();
378 }
379 if (reserved1 || reserved2)
380 {
381 return ipmi::responseInvalidFieldRequest();
Kirill Pakhomov2c2af2c2018-11-06 16:06:10 +0300382 }
383
Vernon Maueryd4222fd2023-07-27 11:26:51 -0700384 if (!dcmi::setPcapEnable(ctx, enabled))
Tom Joseph6c8d51b2017-07-26 18:18:06 +0530385 {
Vernon Maueryd4222fd2023-07-27 11:26:51 -0700386 return ipmi::responseUnspecifiedError();
Tom Joseph6c8d51b2017-07-26 18:18:06 +0530387 }
388
389 log<level::INFO>("Set Power Cap Enable",
Vernon Maueryd4222fd2023-07-27 11:26:51 -0700390 entry("POWERCAPENABLE=%u", static_cast<uint8_t>(enabled)));
Tom Joseph6c8d51b2017-07-26 18:18:06 +0530391
Vernon Maueryd4222fd2023-07-27 11:26:51 -0700392 return ipmi::responseSuccess();
Tom Joseph6c8d51b2017-07-26 18:18:06 +0530393}
394
Vernon Mauerydca47202023-07-27 11:32:01 -0700395ipmi::RspType<uint8_t, // total tag length
396 std::vector<char> // tag data
397 >
398 getAssetTag(ipmi::Context::ptr& ctx, uint8_t offset, uint8_t count)
Tom Joseph6f6dd4d2017-07-12 20:07:11 +0530399{
Vernon Mauerydca47202023-07-27 11:32:01 -0700400 // Verify offset to read and number of bytes to read are not exceeding
401 // the range.
402 if ((offset > dcmi::assetTagMaxOffset) || (count > dcmi::maxBytes) ||
403 ((offset + count) > dcmi::assetTagMaxSize))
Tom Joseph6f6dd4d2017-07-12 20:07:11 +0530404 {
Vernon Mauerydca47202023-07-27 11:32:01 -0700405 return ipmi::responseParmOutOfRange();
Tom Joseph6f6dd4d2017-07-12 20:07:11 +0530406 }
407
Vernon Mauerydca47202023-07-27 11:32:01 -0700408 std::optional<std::string> assetTagResp = dcmi::readAssetTag(ctx);
409 if (!assetTagResp)
Tom Joseph6f6dd4d2017-07-12 20:07:11 +0530410 {
Vernon Mauerydca47202023-07-27 11:32:01 -0700411 return ipmi::responseUnspecifiedError();
Tom Joseph6f6dd4d2017-07-12 20:07:11 +0530412 }
413
Vernon Mauerydca47202023-07-27 11:32:01 -0700414 std::string& assetTag = assetTagResp.value();
415 // If the asset tag is longer than 63 bytes, restrict it to 63 bytes to
416 // suit Get Asset Tag command.
Tom Joseph6f6dd4d2017-07-12 20:07:11 +0530417 if (assetTag.size() > dcmi::assetTagMaxSize)
418 {
419 assetTag.resize(dcmi::assetTagMaxSize);
420 }
421
Vernon Mauerydca47202023-07-27 11:32:01 -0700422 if (offset >= assetTag.size())
Tom Joseph6f6dd4d2017-07-12 20:07:11 +0530423 {
Vernon Mauerydca47202023-07-27 11:32:01 -0700424 return ipmi::responseParmOutOfRange();
Tom Joseph6f6dd4d2017-07-12 20:07:11 +0530425 }
426
Vernon Mauerydca47202023-07-27 11:32:01 -0700427 // silently truncate reads beyond the end of assetTag
428 if ((offset + count) >= assetTag.size())
429 {
430 count = assetTag.size() - offset;
431 }
Tom Joseph6f6dd4d2017-07-12 20:07:11 +0530432
Vernon Mauerydca47202023-07-27 11:32:01 -0700433 auto totalTagSize = static_cast<uint8_t>(assetTag.size());
434 std::vector<char> data{assetTag.begin() + offset,
435 assetTag.begin() + offset + count};
Tom Joseph6f6dd4d2017-07-12 20:07:11 +0530436
Vernon Mauerydca47202023-07-27 11:32:01 -0700437 return ipmi::responseSuccess(totalTagSize, data);
Tom Joseph6f6dd4d2017-07-12 20:07:11 +0530438}
439
Vernon Mauerydca47202023-07-27 11:32:01 -0700440ipmi::RspType<uint8_t // new asset tag length
441 >
442 setAssetTag(ipmi::Context::ptr& ctx, uint8_t offset, uint8_t count,
443 const std::vector<char>& data)
Tom Joseph545dd232017-07-12 20:20:49 +0530444{
Vernon Mauerydca47202023-07-27 11:32:01 -0700445 // Verify offset to read and number of bytes to read are not exceeding
446 // the range.
447 if ((offset > dcmi::assetTagMaxOffset) || (count > dcmi::maxBytes) ||
448 ((offset + count) > dcmi::assetTagMaxSize))
Tom Joseph545dd232017-07-12 20:20:49 +0530449 {
Vernon Mauerydca47202023-07-27 11:32:01 -0700450 return ipmi::responseParmOutOfRange();
451 }
452 if (data.size() != count)
453 {
454 return ipmi::responseReqDataLenInvalid();
Tom Joseph545dd232017-07-12 20:20:49 +0530455 }
456
Vernon Mauerydca47202023-07-27 11:32:01 -0700457 std::optional<std::string> assetTagResp = dcmi::readAssetTag(ctx);
458 if (!assetTagResp)
Tom Joseph545dd232017-07-12 20:20:49 +0530459 {
Vernon Mauerydca47202023-07-27 11:32:01 -0700460 return ipmi::responseUnspecifiedError();
Tom Joseph545dd232017-07-12 20:20:49 +0530461 }
Vernon Mauerydca47202023-07-27 11:32:01 -0700462
463 std::string& assetTag = assetTagResp.value();
464
465 if (offset > assetTag.size())
Tom Joseph545dd232017-07-12 20:20:49 +0530466 {
Vernon Mauerydca47202023-07-27 11:32:01 -0700467 return ipmi::responseParmOutOfRange();
Tom Joseph545dd232017-07-12 20:20:49 +0530468 }
Vernon Mauerydca47202023-07-27 11:32:01 -0700469
470 // operation is to truncate at offset and append new data
471 assetTag.resize(offset);
472 assetTag.append(data.begin(), data.end());
473
474 if (!dcmi::writeAssetTag(ctx, assetTag))
475 {
476 return ipmi::responseUnspecifiedError();
477 }
478
479 auto totalTagSize = static_cast<uint8_t>(assetTag.size());
480 return ipmi::responseSuccess(totalTagSize);
Tom Joseph545dd232017-07-12 20:20:49 +0530481}
482
Willy Tu11d68892022-01-20 10:37:34 -0800483ipmi_ret_t getMgmntCtrlIdStr(ipmi_netfn_t, ipmi_cmd_t, ipmi_request_t request,
484 ipmi_response_t response, ipmi_data_len_t data_len,
485 ipmi_context_t)
Vladislav Vovchenko8f7a6f62017-08-17 00:31:14 +0300486{
Patrick Venture0b02be92018-08-31 11:55:55 -0700487 auto requestData =
488 reinterpret_cast<const dcmi::GetMgmntCtrlIdStrRequest*>(request);
489 auto responseData =
490 reinterpret_cast<dcmi::GetMgmntCtrlIdStrResponse*>(response);
Vladislav Vovchenko8f7a6f62017-08-17 00:31:14 +0300491 std::string hostName;
492
493 *data_len = 0;
494
William A. Kennington III5d06cc62019-04-25 02:10:55 -0700495 if (requestData->bytes > dcmi::maxBytes ||
Vladislav Vovchenko8f7a6f62017-08-17 00:31:14 +0300496 requestData->offset + requestData->bytes > dcmi::maxCtrlIdStrLen)
497 {
498 return IPMI_CC_INVALID_FIELD_REQUEST;
499 }
500
501 try
502 {
503 hostName = dcmi::getHostName();
504 }
Patrick Williamsa2ad2da2021-10-06 12:21:46 -0500505 catch (const InternalFailure& e)
Vladislav Vovchenko8f7a6f62017-08-17 00:31:14 +0300506 {
507 return IPMI_CC_UNSPECIFIED_ERROR;
508 }
509
510 if (requestData->offset > hostName.length())
511 {
512 return IPMI_CC_PARM_OUT_OF_RANGE;
513 }
514 auto responseStr = hostName.substr(requestData->offset, requestData->bytes);
515 auto responseStrLen = std::min(static_cast<std::size_t>(requestData->bytes),
Patrick Venture0b02be92018-08-31 11:55:55 -0700516 responseStr.length() + 1);
Vladislav Vovchenko8f7a6f62017-08-17 00:31:14 +0300517 responseData->strLen = hostName.length();
518 std::copy(begin(responseStr), end(responseStr), responseData->data);
519
520 *data_len = sizeof(*responseData) + responseStrLen;
521 return IPMI_CC_OK;
522}
523
Willy Tu11d68892022-01-20 10:37:34 -0800524ipmi_ret_t setMgmntCtrlIdStr(ipmi_netfn_t, ipmi_cmd_t, ipmi_request_t request,
525 ipmi_response_t response, ipmi_data_len_t data_len,
526 ipmi_context_t)
Vladislav Vovchenko8f7a6f62017-08-17 00:31:14 +0300527{
528 static std::array<char, dcmi::maxCtrlIdStrLen + 1> newCtrlIdStr;
529
Patrick Venture0b02be92018-08-31 11:55:55 -0700530 auto requestData =
531 reinterpret_cast<const dcmi::SetMgmntCtrlIdStrRequest*>(request);
532 auto responseData =
533 reinterpret_cast<dcmi::SetMgmntCtrlIdStrResponse*>(response);
Vladislav Vovchenko8f7a6f62017-08-17 00:31:14 +0300534
535 *data_len = 0;
536
William A. Kennington III5d06cc62019-04-25 02:10:55 -0700537 if (requestData->bytes > dcmi::maxBytes ||
Vladislav Vovchenko8f7a6f62017-08-17 00:31:14 +0300538 requestData->offset + requestData->bytes > dcmi::maxCtrlIdStrLen + 1 ||
Patrick Venture0b02be92018-08-31 11:55:55 -0700539 (requestData->offset + requestData->bytes ==
540 dcmi::maxCtrlIdStrLen + 1 &&
541 requestData->data[requestData->bytes - 1] != '\0'))
Vladislav Vovchenko8f7a6f62017-08-17 00:31:14 +0300542 {
543 return IPMI_CC_INVALID_FIELD_REQUEST;
544 }
545
546 try
547 {
548 /* if there is no old value and offset is not 0 */
549 if (newCtrlIdStr[0] == '\0' && requestData->offset != 0)
550 {
551 /* read old ctrlIdStr */
552 auto hostName = dcmi::getHostName();
553 hostName.resize(dcmi::maxCtrlIdStrLen);
554 std::copy(begin(hostName), end(hostName), begin(newCtrlIdStr));
555 newCtrlIdStr[hostName.length()] = '\0';
556 }
557
558 /* replace part of string and mark byte after the last as \0 */
Patrick Venture0b02be92018-08-31 11:55:55 -0700559 auto restStrIter =
560 std::copy_n(requestData->data, requestData->bytes,
561 begin(newCtrlIdStr) + requestData->offset);
Vladislav Vovchenko8f7a6f62017-08-17 00:31:14 +0300562 /* if the last written byte is not 64th - add '\0' */
563 if (requestData->offset + requestData->bytes <= dcmi::maxCtrlIdStrLen)
564 {
565 *restStrIter = '\0';
566 }
567
568 /* if input data contains '\0' whole string is sent - update hostname */
569 auto it = std::find(requestData->data,
Patrick Venture0b02be92018-08-31 11:55:55 -0700570 requestData->data + requestData->bytes, '\0');
Vladislav Vovchenko8f7a6f62017-08-17 00:31:14 +0300571 if (it != requestData->data + requestData->bytes)
572 {
Patrick Williams5d82f472022-07-22 19:26:53 -0500573 sdbusplus::bus_t bus{ipmid_get_sd_bus_connection()};
Vladislav Vovchenko8f7a6f62017-08-17 00:31:14 +0300574 ipmi::setDbusProperty(bus, dcmi::networkServiceName,
Patrick Venture0b02be92018-08-31 11:55:55 -0700575 dcmi::networkConfigObj,
576 dcmi::networkConfigIntf, dcmi::hostNameProp,
577 std::string(newCtrlIdStr.data()));
Vladislav Vovchenko8f7a6f62017-08-17 00:31:14 +0300578 }
579 }
Patrick Williamsa2ad2da2021-10-06 12:21:46 -0500580 catch (const InternalFailure& e)
Vladislav Vovchenko8f7a6f62017-08-17 00:31:14 +0300581 {
582 *data_len = 0;
583 return IPMI_CC_UNSPECIFIED_ERROR;
584 }
585
Vladislav Vovchenko8f7a6f62017-08-17 00:31:14 +0300586 responseData->offset = requestData->offset + requestData->bytes;
587 *data_len = sizeof(*responseData);
588 return IPMI_CC_OK;
589}
590
Patrick Venture0b02be92018-08-31 11:55:55 -0700591// List of the capabilities under each parameter
592dcmi::DCMICaps dcmiCaps = {
593 // Supported DCMI Capabilities
594 {dcmi::DCMICapParameters::SUPPORTED_DCMI_CAPS,
595 {3,
596 {{"PowerManagement", 2, 0, 1},
597 {"OOBSecondaryLan", 3, 2, 1},
598 {"SerialTMODE", 3, 1, 1},
599 {"InBandSystemInterfaceChannel", 3, 0, 1}}}},
600 // Mandatory Platform Attributes
601 {dcmi::DCMICapParameters::MANDATORY_PLAT_ATTRIBUTES,
602 {5,
603 {{"SELAutoRollOver", 1, 15, 1},
604 {"FlushEntireSELUponRollOver", 1, 14, 1},
605 {"RecordLevelSELFlushUponRollOver", 1, 13, 1},
606 {"NumberOfSELEntries", 1, 0, 12},
607 {"TempMonitoringSamplingFreq", 5, 0, 8}}}},
608 // Optional Platform Attributes
609 {dcmi::DCMICapParameters::OPTIONAL_PLAT_ATTRIBUTES,
610 {2,
611 {{"PowerMgmtDeviceSlaveAddress", 1, 1, 7},
612 {"BMCChannelNumber", 2, 4, 4},
613 {"DeviceRivision", 2, 0, 4}}}},
614 // Manageability Access Attributes
615 {dcmi::DCMICapParameters::MANAGEABILITY_ACCESS_ATTRIBUTES,
616 {3,
617 {{"MandatoryPrimaryLanOOBSupport", 1, 0, 8},
618 {"OptionalSecondaryLanOOBSupport", 2, 0, 8},
619 {"OptionalSerialOOBMTMODECapability", 3, 0, 8}}}}};
Dhruvaraj Subhashchandrane29be412018-01-16 05:11:56 -0600620
Willy Tu11d68892022-01-20 10:37:34 -0800621ipmi_ret_t getDCMICapabilities(ipmi_netfn_t, ipmi_cmd_t, ipmi_request_t request,
622 ipmi_response_t response,
623 ipmi_data_len_t data_len, ipmi_context_t)
Dhruvaraj Subhashchandrane29be412018-01-16 05:11:56 -0600624{
Kirill Pakhomova2573622018-11-02 19:00:18 +0300625 std::ifstream dcmiCapFile(dcmi::gDCMICapabilitiesConfig);
Dhruvaraj Subhashchandrane29be412018-01-16 05:11:56 -0600626 if (!dcmiCapFile.is_open())
627 {
628 log<level::ERR>("DCMI Capabilities file not found");
629 return IPMI_CC_UNSPECIFIED_ERROR;
630 }
631
632 auto data = nlohmann::json::parse(dcmiCapFile, nullptr, false);
633 if (data.is_discarded())
634 {
635 log<level::ERR>("DCMI Capabilities JSON parser failure");
636 return IPMI_CC_UNSPECIFIED_ERROR;
637 }
638
Patrick Venture0b02be92018-08-31 11:55:55 -0700639 auto requestData =
640 reinterpret_cast<const dcmi::GetDCMICapRequest*>(request);
Dhruvaraj Subhashchandrane29be412018-01-16 05:11:56 -0600641
Patrick Venture0b02be92018-08-31 11:55:55 -0700642 // get list of capabilities in a parameter
Dhruvaraj Subhashchandrane29be412018-01-16 05:11:56 -0600643 auto caps =
644 dcmiCaps.find(static_cast<dcmi::DCMICapParameters>(requestData->param));
645 if (caps == dcmiCaps.end())
646 {
647 log<level::ERR>("Invalid input parameter");
648 return IPMI_CC_INVALID_FIELD_REQUEST;
649 }
650
Patrick Venture0b02be92018-08-31 11:55:55 -0700651 auto responseData = reinterpret_cast<dcmi::GetDCMICapResponse*>(response);
Dhruvaraj Subhashchandrane29be412018-01-16 05:11:56 -0600652
Patrick Venture0b02be92018-08-31 11:55:55 -0700653 // For each capabilities in a parameter fill the data from
654 // the json file based on the capability name.
Dhruvaraj Subhashchandrane29be412018-01-16 05:11:56 -0600655 for (auto cap : caps->second.capList)
656 {
Patrick Venture0b02be92018-08-31 11:55:55 -0700657 // If the data is beyond first byte boundary, insert in a
658 // 16bit pattern for example number of SEL entries are represented
659 // in 12bits.
Kirill Pakhomovdb5d9b02018-11-06 19:17:51 +0300660 if ((cap.length + cap.position) > dcmi::gByteBitSize)
Dhruvaraj Subhashchandrane29be412018-01-16 05:11:56 -0600661 {
Kirill Pakhomovdb5d9b02018-11-06 19:17:51 +0300662 uint16_t val = data.value(cap.name.c_str(), 0);
663 // According to DCMI spec v1.5, max number of SEL entries is
664 // 4096, but bit 12b of DCMI capabilities Mandatory Platform
665 // Attributes field is reserved and therefore we can use only
666 // the provided 12 bits with maximum value of 4095.
667 // We're playing safe here by applying the mask
668 // to ensure that provided value will fit into 12 bits.
669 if (cap.length > dcmi::gByteBitSize)
670 {
671 val &= dcmi::gMaxSELEntriesMask;
672 }
Dhruvaraj Subhashchandrane29be412018-01-16 05:11:56 -0600673 val <<= cap.position;
Kirill Pakhomovdb5d9b02018-11-06 19:17:51 +0300674 responseData->data[cap.bytePosition - 1] |=
675 static_cast<uint8_t>(val);
676 responseData->data[cap.bytePosition] |= val >> dcmi::gByteBitSize;
Dhruvaraj Subhashchandrane29be412018-01-16 05:11:56 -0600677 }
678 else
679 {
680 responseData->data[cap.bytePosition - 1] |=
681 data.value(cap.name.c_str(), 0) << cap.position;
682 }
683 }
684
Dhruvaraj Subhashchandrane29be412018-01-16 05:11:56 -0600685 responseData->major = DCMI_SPEC_MAJOR_VERSION;
686 responseData->minor = DCMI_SPEC_MINOR_VERSION;
687 responseData->paramRevision = DCMI_PARAMETER_REVISION;
688 *data_len = sizeof(*responseData) + caps->second.size;
689
690 return IPMI_CC_OK;
691}
692
Deepak Kodihalliee717d72018-01-24 04:53:09 -0600693namespace dcmi
694{
695namespace temp_readings
696{
697
Deepak Kodihallib1e8fba2018-01-24 04:57:10 -0600698Temperature readTemp(const std::string& dbusService,
699 const std::string& dbusPath)
700{
701 // Read the temperature value from d-bus object. Need some conversion.
702 // As per the interface xyz.openbmc_project.Sensor.Value, the temperature
James Feist9cc0ea52018-10-09 10:53:11 -0700703 // is an double and in degrees C. It needs to be scaled by using the
Deepak Kodihallib1e8fba2018-01-24 04:57:10 -0600704 // formula Value * 10^Scale. The ipmi spec has the temperature as a uint8_t,
705 // with a separate single bit for the sign.
706
Patrick Williams5d82f472022-07-22 19:26:53 -0500707 sdbusplus::bus_t bus{ipmid_get_sd_bus_connection()};
Patrick Venture0b02be92018-08-31 11:55:55 -0700708 auto result = ipmi::getAllDbusProperties(
709 bus, dbusService, dbusPath, "xyz.openbmc_project.Sensor.Value");
Patrick Williamsfbc6c9d2023-05-10 07:50:16 -0500710 auto temperature = std::visit(ipmi::VariantToDoubleVisitor(),
711 result.at("Value"));
James Feist9cc0ea52018-10-09 10:53:11 -0700712 double absTemp = std::abs(temperature);
Deepak Kodihallib1e8fba2018-01-24 04:57:10 -0600713
James Feist9cc0ea52018-10-09 10:53:11 -0700714 auto findFactor = result.find("Scale");
715 double factor = 0.0;
716 if (findFactor != result.end())
Deepak Kodihallib1e8fba2018-01-24 04:57:10 -0600717 {
Vernon Maueryf442e112019-04-09 11:44:36 -0700718 factor = std::visit(ipmi::VariantToDoubleVisitor(), findFactor->second);
Deepak Kodihallib1e8fba2018-01-24 04:57:10 -0600719 }
James Feist9cc0ea52018-10-09 10:53:11 -0700720 double scale = std::pow(10, factor);
721
722 auto tempDegrees = absTemp * scale;
Deepak Kodihallib1e8fba2018-01-24 04:57:10 -0600723 // Max absolute temp as per ipmi spec is 128.
724 if (tempDegrees > maxTemp)
725 {
726 tempDegrees = maxTemp;
727 }
728
729 return std::make_tuple(static_cast<uint8_t>(tempDegrees),
730 (temperature < 0));
731}
732
Deepak Kodihalliee717d72018-01-24 04:53:09 -0600733std::tuple<Response, NumInstances> read(const std::string& type,
734 uint8_t instance)
735{
Deepak Kodihallib1e8fba2018-01-24 04:57:10 -0600736 Response response{};
Patrick Williams5d82f472022-07-22 19:26:53 -0500737 sdbusplus::bus_t bus{ipmid_get_sd_bus_connection()};
Deepak Kodihallib1e8fba2018-01-24 04:57:10 -0600738
739 if (!instance)
740 {
741 log<level::ERR>("Expected non-zero instance");
742 elog<InternalFailure>();
743 }
744
Kirill Pakhomova2573622018-11-02 19:00:18 +0300745 auto data = parseJSONConfig(gDCMISensorsConfig);
Deepak Kodihallib1e8fba2018-01-24 04:57:10 -0600746 static const std::vector<Json> empty{};
747 std::vector<Json> readings = data.value(type, empty);
748 size_t numInstances = readings.size();
749 for (const auto& j : readings)
750 {
751 uint8_t instanceNum = j.value("instance", 0);
752 // Not the instance we're interested in
753 if (instanceNum != instance)
754 {
755 continue;
756 }
757
758 std::string path = j.value("dbus", "");
759 std::string service;
760 try
761 {
Patrick Williamsfbc6c9d2023-05-10 07:50:16 -0500762 service = ipmi::getService(bus, "xyz.openbmc_project.Sensor.Value",
763 path);
Deepak Kodihallib1e8fba2018-01-24 04:57:10 -0600764 }
Patrick Williamsa2ad2da2021-10-06 12:21:46 -0500765 catch (const std::exception& e)
Deepak Kodihallib1e8fba2018-01-24 04:57:10 -0600766 {
767 log<level::DEBUG>(e.what());
768 return std::make_tuple(response, numInstances);
769 }
770
771 response.instance = instance;
772 uint8_t temp{};
773 bool sign{};
774 std::tie(temp, sign) = readTemp(service, path);
775 response.temperature = temp;
776 response.sign = sign;
777
778 // Found the instance we're interested in
779 break;
780 }
781
782 if (numInstances > maxInstances)
783 {
784 numInstances = maxInstances;
785 }
786 return std::make_tuple(response, numInstances);
Deepak Kodihalliee717d72018-01-24 04:53:09 -0600787}
788
789std::tuple<ResponseList, NumInstances> readAll(const std::string& type,
790 uint8_t instanceStart)
791{
Deepak Kodihallib1e8fba2018-01-24 04:57:10 -0600792 ResponseList response{};
Patrick Williams5d82f472022-07-22 19:26:53 -0500793 sdbusplus::bus_t bus{ipmid_get_sd_bus_connection()};
Deepak Kodihallib1e8fba2018-01-24 04:57:10 -0600794
795 size_t numInstances = 0;
Kirill Pakhomova2573622018-11-02 19:00:18 +0300796 auto data = parseJSONConfig(gDCMISensorsConfig);
Deepak Kodihallib1e8fba2018-01-24 04:57:10 -0600797 static const std::vector<Json> empty{};
798 std::vector<Json> readings = data.value(type, empty);
799 numInstances = readings.size();
800 for (const auto& j : readings)
801 {
802 try
803 {
804 // Max of 8 response data sets
805 if (response.size() == maxDataSets)
806 {
807 break;
808 }
809
810 uint8_t instanceNum = j.value("instance", 0);
811 // Not in the instance range we're interested in
812 if (instanceNum < instanceStart)
813 {
814 continue;
815 }
816
817 std::string path = j.value("dbus", "");
818 auto service =
Patrick Venture0b02be92018-08-31 11:55:55 -0700819 ipmi::getService(bus, "xyz.openbmc_project.Sensor.Value", path);
Deepak Kodihallib1e8fba2018-01-24 04:57:10 -0600820
821 Response r{};
822 r.instance = instanceNum;
823 uint8_t temp{};
824 bool sign{};
825 std::tie(temp, sign) = readTemp(service, path);
826 r.temperature = temp;
827 r.sign = sign;
828 response.push_back(r);
829 }
Patrick Williamsa2ad2da2021-10-06 12:21:46 -0500830 catch (const std::exception& e)
Deepak Kodihallib1e8fba2018-01-24 04:57:10 -0600831 {
832 log<level::DEBUG>(e.what());
833 continue;
834 }
835 }
836
837 if (numInstances > maxInstances)
838 {
839 numInstances = maxInstances;
840 }
841 return std::make_tuple(response, numInstances);
Deepak Kodihalliee717d72018-01-24 04:53:09 -0600842}
843
Patrick Venture0b02be92018-08-31 11:55:55 -0700844} // namespace temp_readings
845} // namespace dcmi
Deepak Kodihalliee717d72018-01-24 04:53:09 -0600846
Willy Tu11d68892022-01-20 10:37:34 -0800847ipmi_ret_t getTempReadings(ipmi_netfn_t, ipmi_cmd_t, ipmi_request_t request,
848 ipmi_response_t response, ipmi_data_len_t data_len,
849 ipmi_context_t)
Deepak Kodihalliee717d72018-01-24 04:53:09 -0600850{
Deepak Kodihalliee717d72018-01-24 04:53:09 -0600851 auto requestData =
852 reinterpret_cast<const dcmi::GetTempReadingsRequest*>(request);
853 auto responseData =
854 reinterpret_cast<dcmi::GetTempReadingsResponseHdr*>(response);
855
856 if (*data_len != sizeof(dcmi::GetTempReadingsRequest))
857 {
858 log<level::ERR>("Malformed request data",
859 entry("DATA_SIZE=%d", *data_len));
860 return IPMI_CC_REQ_DATA_LEN_INVALID;
861 }
862 *data_len = 0;
863
Deepak Kodihalli0b459552018-02-06 06:25:12 -0600864 auto it = dcmi::entityIdToName.find(requestData->entityId);
865 if (it == dcmi::entityIdToName.end())
Deepak Kodihalliee717d72018-01-24 04:53:09 -0600866 {
867 log<level::ERR>("Unknown Entity ID",
868 entry("ENTITY_ID=%d", requestData->entityId));
869 return IPMI_CC_INVALID_FIELD_REQUEST;
870 }
871
Deepak Kodihalliee717d72018-01-24 04:53:09 -0600872 if (requestData->sensorType != dcmi::temperatureSensorType)
873 {
874 log<level::ERR>("Invalid sensor type",
875 entry("SENSOR_TYPE=%d", requestData->sensorType));
876 return IPMI_CC_INVALID_FIELD_REQUEST;
877 }
878
879 dcmi::temp_readings::ResponseList temps{};
880 try
881 {
882 if (!requestData->entityInstance)
883 {
884 // Read all instances
885 std::tie(temps, responseData->numInstances) =
886 dcmi::temp_readings::readAll(it->second,
887 requestData->instanceStart);
888 }
889 else
890 {
891 // Read one instance
892 temps.resize(1);
893 std::tie(temps[0], responseData->numInstances) =
894 dcmi::temp_readings::read(it->second,
895 requestData->entityInstance);
896 }
897 responseData->numDataSets = temps.size();
898 }
Patrick Williamsa2ad2da2021-10-06 12:21:46 -0500899 catch (const InternalFailure& e)
Deepak Kodihalliee717d72018-01-24 04:53:09 -0600900 {
901 return IPMI_CC_UNSPECIFIED_ERROR;
902 }
903
Patrick Venture0b02be92018-08-31 11:55:55 -0700904 size_t payloadSize = temps.size() * sizeof(dcmi::temp_readings::Response);
Deepak Kodihalliee717d72018-01-24 04:53:09 -0600905 if (!temps.empty())
906 {
907 memcpy(responseData + 1, // copy payload right after the response header
Patrick Venture0b02be92018-08-31 11:55:55 -0700908 temps.data(), payloadSize);
Deepak Kodihalliee717d72018-01-24 04:53:09 -0600909 }
910 *data_len = sizeof(dcmi::GetTempReadingsResponseHdr) + payloadSize;
911
912 return IPMI_CC_OK;
913}
914
Patrick Williams5d82f472022-07-22 19:26:53 -0500915int64_t getPowerReading(sdbusplus::bus_t& bus)
Marri Devender Rao66c5fda2018-01-18 10:48:37 -0600916{
917 std::ifstream sensorFile(POWER_READING_SENSOR);
918 std::string objectPath;
919 if (!sensorFile.is_open())
920 {
921 log<level::ERR>("Power reading configuration file not found",
Patrick Venture0b02be92018-08-31 11:55:55 -0700922 entry("POWER_SENSOR_FILE=%s", POWER_READING_SENSOR));
Marri Devender Rao66c5fda2018-01-18 10:48:37 -0600923 elog<InternalFailure>();
924 }
925
926 auto data = nlohmann::json::parse(sensorFile, nullptr, false);
927 if (data.is_discarded())
928 {
929 log<level::ERR>("Error in parsing configuration file",
Patrick Venture0b02be92018-08-31 11:55:55 -0700930 entry("POWER_SENSOR_FILE=%s", POWER_READING_SENSOR));
Marri Devender Rao66c5fda2018-01-18 10:48:37 -0600931 elog<InternalFailure>();
932 }
933
934 objectPath = data.value("path", "");
935 if (objectPath.empty())
936 {
937 log<level::ERR>("Power sensor D-Bus object path is empty",
938 entry("POWER_SENSOR_FILE=%s", POWER_READING_SENSOR));
939 elog<InternalFailure>();
940 }
941
Marri Devender Raoce6a7952018-02-11 08:45:00 -0600942 // Return default value if failed to read from D-Bus object
943 int64_t power = 0;
944 try
945 {
946 auto service = ipmi::getService(bus, SENSOR_VALUE_INTF, objectPath);
Marri Devender Rao66c5fda2018-01-18 10:48:37 -0600947
Patrick Venture0b02be92018-08-31 11:55:55 -0700948 // Read the sensor value and scale properties
Chris Cain4cc61e02022-01-12 17:23:14 -0600949 auto value = ipmi::getDbusProperty(
950 bus, service, objectPath, SENSOR_VALUE_INTF, SENSOR_VALUE_PROP);
951 power = std::get<double>(value);
Marri Devender Raoce6a7952018-02-11 08:45:00 -0600952 }
Patrick Williamsa2ad2da2021-10-06 12:21:46 -0500953 catch (const std::exception& e)
Marri Devender Raoce6a7952018-02-11 08:45:00 -0600954 {
Chris Cain4cc61e02022-01-12 17:23:14 -0600955 log<level::ERR>("Failure to read power value from D-Bus object",
956 entry("OBJECT_PATH=%s", objectPath.c_str()),
957 entry("INTERFACE=%s", SENSOR_VALUE_INTF));
Marri Devender Raoce6a7952018-02-11 08:45:00 -0600958 }
Marri Devender Rao66c5fda2018-01-18 10:48:37 -0600959 return power;
960}
961
Willy Tu11d68892022-01-20 10:37:34 -0800962ipmi_ret_t setDCMIConfParams(ipmi_netfn_t, ipmi_cmd_t, ipmi_request_t request,
963 ipmi_response_t, ipmi_data_len_t data_len,
964 ipmi_context_t)
Nagaraju Goruganti22be97b2018-02-07 01:19:59 -0600965{
Patrick Venture0b02be92018-08-31 11:55:55 -0700966 auto requestData =
967 reinterpret_cast<const dcmi::SetConfParamsRequest*>(request);
Nagaraju Goruganti22be97b2018-02-07 01:19:59 -0600968
William A. Kennington III5d06cc62019-04-25 02:10:55 -0700969 if (*data_len < DCMI_SET_CONF_PARAM_REQ_PACKET_MIN_SIZE ||
Patrick Venture0b02be92018-08-31 11:55:55 -0700970 *data_len > DCMI_SET_CONF_PARAM_REQ_PACKET_MAX_SIZE)
Nagaraju Goruganti22be97b2018-02-07 01:19:59 -0600971 {
William A. Kennington III5d06cc62019-04-25 02:10:55 -0700972 log<level::ERR>("Invalid Requested Packet size",
Nagaraju Goruganti22be97b2018-02-07 01:19:59 -0600973 entry("PACKET SIZE=%d", *data_len));
William A. Kennington III5d06cc62019-04-25 02:10:55 -0700974 *data_len = 0;
Nagaraju Goruganti22be97b2018-02-07 01:19:59 -0600975 return IPMI_CC_INVALID_FIELD_REQUEST;
976 }
Nagaraju Goruganti22be97b2018-02-07 01:19:59 -0600977 *data_len = 0;
978
979 try
980 {
981 // Take action based on the Parameter Selector
Patrick Venture0b02be92018-08-31 11:55:55 -0700982 switch (
983 static_cast<dcmi::DCMIConfigParameters>(requestData->paramSelect))
Nagaraju Goruganti22be97b2018-02-07 01:19:59 -0600984 {
985 case dcmi::DCMIConfigParameters::ActivateDHCP:
986
987 if ((requestData->data[0] & DCMI_ACTIVATE_DHCP_MASK) &&
Thang Tran55cbf552023-01-31 14:43:02 +0700988 (dcmi::getDHCPEnabled() !=
989 EthernetInterface::DHCPConf::none))
Nagaraju Goruganti22be97b2018-02-07 01:19:59 -0600990 {
Patrick Venture0b02be92018-08-31 11:55:55 -0700991 // When these conditions are met we have to trigger DHCP
992 // protocol restart using the latest parameter settings, but
993 // as per n/w manager design, each time when we update n/w
994 // parameters, n/w service is restarted. So we no need to
995 // take any action in this case.
Nagaraju Goruganti22be97b2018-02-07 01:19:59 -0600996 }
997 break;
998
999 case dcmi::DCMIConfigParameters::DiscoveryConfig:
1000
1001 if (requestData->data[0] & DCMI_OPTION_12_MASK)
1002 {
1003 dcmi::setDHCPOption(DHCP_OPT12_ENABLED, true);
1004 }
1005 else
1006 {
1007 dcmi::setDHCPOption(DHCP_OPT12_ENABLED, false);
1008 }
1009
1010 // Systemd-networkd doesn't support Random Back off
1011 if (requestData->data[0] & DCMI_RAND_BACK_OFF_MASK)
1012 {
1013 return IPMI_CC_INVALID;
1014 }
1015 break;
1016 // Systemd-networkd doesn't allow to configure DHCP timigs
1017 case dcmi::DCMIConfigParameters::DHCPTiming1:
1018 case dcmi::DCMIConfigParameters::DHCPTiming2:
1019 case dcmi::DCMIConfigParameters::DHCPTiming3:
1020 default:
1021 return IPMI_CC_INVALID;
1022 }
1023 }
Patrick Williamsa2ad2da2021-10-06 12:21:46 -05001024 catch (const std::exception& e)
Nagaraju Goruganti22be97b2018-02-07 01:19:59 -06001025 {
1026 log<level::ERR>(e.what());
1027 return IPMI_CC_UNSPECIFIED_ERROR;
1028 }
Nagaraju Goruganti22be97b2018-02-07 01:19:59 -06001029 return IPMI_CC_OK;
1030}
1031
Willy Tu11d68892022-01-20 10:37:34 -08001032ipmi_ret_t getDCMIConfParams(ipmi_netfn_t, ipmi_cmd_t, ipmi_request_t request,
1033 ipmi_response_t response, ipmi_data_len_t data_len,
1034 ipmi_context_t)
Nagaraju Goruganti22be97b2018-02-07 01:19:59 -06001035{
Patrick Venture0b02be92018-08-31 11:55:55 -07001036 auto requestData =
1037 reinterpret_cast<const dcmi::GetConfParamsRequest*>(request);
1038 auto responseData =
1039 reinterpret_cast<dcmi::GetConfParamsResponse*>(response);
Nagaraju Goruganti22be97b2018-02-07 01:19:59 -06001040
1041 responseData->data[0] = 0x00;
1042
William A. Kennington III5d06cc62019-04-25 02:10:55 -07001043 if (*data_len != sizeof(dcmi::GetConfParamsRequest))
Nagaraju Goruganti22be97b2018-02-07 01:19:59 -06001044 {
William A. Kennington III5d06cc62019-04-25 02:10:55 -07001045 log<level::ERR>("Invalid Requested Packet size",
Nagaraju Goruganti22be97b2018-02-07 01:19:59 -06001046 entry("PACKET SIZE=%d", *data_len));
1047 return IPMI_CC_INVALID_FIELD_REQUEST;
1048 }
1049
1050 *data_len = 0;
1051
1052 try
1053 {
1054 // Take action based on the Parameter Selector
Patrick Venture0b02be92018-08-31 11:55:55 -07001055 switch (
1056 static_cast<dcmi::DCMIConfigParameters>(requestData->paramSelect))
Nagaraju Goruganti22be97b2018-02-07 01:19:59 -06001057 {
1058 case dcmi::DCMIConfigParameters::ActivateDHCP:
1059 responseData->data[0] = DCMI_ACTIVATE_DHCP_REPLY;
1060 *data_len = sizeof(dcmi::GetConfParamsResponse) + 1;
1061 break;
1062 case dcmi::DCMIConfigParameters::DiscoveryConfig:
1063 if (dcmi::getDHCPOption(DHCP_OPT12_ENABLED))
1064 {
1065 responseData->data[0] |= DCMI_OPTION_12_MASK;
1066 }
1067 *data_len = sizeof(dcmi::GetConfParamsResponse) + 1;
1068 break;
1069 // Get below values from Systemd-networkd source code
1070 case dcmi::DCMIConfigParameters::DHCPTiming1:
1071 responseData->data[0] = DHCP_TIMING1;
1072 *data_len = sizeof(dcmi::GetConfParamsResponse) + 1;
1073 break;
1074 case dcmi::DCMIConfigParameters::DHCPTiming2:
1075 responseData->data[0] = DHCP_TIMING2_LOWER;
1076 responseData->data[1] = DHCP_TIMING2_UPPER;
1077 *data_len = sizeof(dcmi::GetConfParamsResponse) + 2;
1078 break;
1079 case dcmi::DCMIConfigParameters::DHCPTiming3:
1080 responseData->data[0] = DHCP_TIMING3_LOWER;
1081 responseData->data[1] = DHCP_TIMING3_UPPER;
1082 *data_len = sizeof(dcmi::GetConfParamsResponse) + 2;
1083 break;
1084 default:
1085 *data_len = 0;
1086 return IPMI_CC_INVALID;
1087 }
1088 }
Patrick Williamsa2ad2da2021-10-06 12:21:46 -05001089 catch (const std::exception& e)
Nagaraju Goruganti22be97b2018-02-07 01:19:59 -06001090 {
1091 log<level::ERR>(e.what());
1092 return IPMI_CC_UNSPECIFIED_ERROR;
1093 }
1094
Nagaraju Goruganti22be97b2018-02-07 01:19:59 -06001095 responseData->major = DCMI_SPEC_MAJOR_VERSION;
1096 responseData->minor = DCMI_SPEC_MINOR_VERSION;
1097 responseData->paramRevision = DCMI_CONFIG_PARAMETER_REVISION;
1098
1099 return IPMI_CC_OK;
1100}
1101
Willy Tu11d68892022-01-20 10:37:34 -08001102ipmi_ret_t getPowerReading(ipmi_netfn_t, ipmi_cmd_t, ipmi_request_t,
1103 ipmi_response_t response, ipmi_data_len_t data_len,
1104 ipmi_context_t)
Marri Devender Rao66c5fda2018-01-18 10:48:37 -06001105{
Chalapathi Venkataramashetty90e81fa2021-05-11 09:13:23 +00001106 *data_len = 0;
Kirill Pakhomov2c2af2c2018-11-06 16:06:10 +03001107 if (!dcmi::isDCMIPowerMgmtSupported())
1108 {
Kirill Pakhomov2c2af2c2018-11-06 16:06:10 +03001109 log<level::ERR>("DCMI Power management is unsupported!");
1110 return IPMI_CC_INVALID;
1111 }
1112
Marri Devender Rao66c5fda2018-01-18 10:48:37 -06001113 ipmi_ret_t rc = IPMI_CC_OK;
Patrick Venture0b02be92018-08-31 11:55:55 -07001114 auto responseData =
1115 reinterpret_cast<dcmi::GetPowerReadingResponse*>(response);
Marri Devender Rao9c966e02018-01-22 05:55:10 -06001116
Patrick Williams5d82f472022-07-22 19:26:53 -05001117 sdbusplus::bus_t bus{ipmid_get_sd_bus_connection()};
Marri Devender Rao9c966e02018-01-22 05:55:10 -06001118 int64_t power = 0;
Marri Devender Rao66c5fda2018-01-18 10:48:37 -06001119 try
1120 {
Marri Devender Rao9c966e02018-01-22 05:55:10 -06001121 power = getPowerReading(bus);
Marri Devender Rao66c5fda2018-01-18 10:48:37 -06001122 }
Patrick Williamsa2ad2da2021-10-06 12:21:46 -05001123 catch (const InternalFailure& e)
Marri Devender Rao66c5fda2018-01-18 10:48:37 -06001124 {
1125 log<level::ERR>("Error in reading power sensor value",
1126 entry("INTERFACE=%s", SENSOR_VALUE_INTF),
1127 entry("PROPERTY=%s", SENSOR_VALUE_PROP));
1128 return IPMI_CC_UNSPECIFIED_ERROR;
1129 }
Marri Devender Rao9c966e02018-01-22 05:55:10 -06001130
1131 // TODO: openbmc/openbmc#2819
Gunnar Mills8466b792018-03-23 12:18:12 -05001132 // Minimum, Maximum, Average power, TimeFrame, TimeStamp,
Marri Devender Rao9c966e02018-01-22 05:55:10 -06001133 // PowerReadingState readings need to be populated
1134 // after Telemetry changes.
1135 uint16_t totalPower = static_cast<uint16_t>(power);
1136 responseData->currentPower = totalPower;
1137 responseData->minimumPower = totalPower;
1138 responseData->maximumPower = totalPower;
1139 responseData->averagePower = totalPower;
1140
1141 *data_len = sizeof(*responseData);
Marri Devender Rao66c5fda2018-01-18 10:48:37 -06001142 return rc;
1143}
1144
Deepak Kodihalli0b459552018-02-06 06:25:12 -06001145namespace dcmi
1146{
1147namespace sensor_info
1148{
1149
Deepak Kodihallidd4cff12018-02-06 06:48:29 -06001150Response createFromJson(const Json& config)
1151{
1152 Response response{};
1153 uint16_t recordId = config.value("record_id", 0);
1154 response.recordIdLsb = recordId & 0xFF;
1155 response.recordIdMsb = (recordId >> 8) & 0xFF;
1156 return response;
1157}
1158
Deepak Kodihalli0b459552018-02-06 06:25:12 -06001159std::tuple<Response, NumInstances> read(const std::string& type,
Patrick Venture0b02be92018-08-31 11:55:55 -07001160 uint8_t instance, const Json& config)
Deepak Kodihalli0b459552018-02-06 06:25:12 -06001161{
Deepak Kodihallidd4cff12018-02-06 06:48:29 -06001162 Response response{};
1163
1164 if (!instance)
1165 {
1166 log<level::ERR>("Expected non-zero instance");
1167 elog<InternalFailure>();
1168 }
1169
1170 static const std::vector<Json> empty{};
1171 std::vector<Json> readings = config.value(type, empty);
1172 size_t numInstances = readings.size();
1173 for (const auto& reading : readings)
1174 {
1175 uint8_t instanceNum = reading.value("instance", 0);
1176 // Not the instance we're interested in
1177 if (instanceNum != instance)
1178 {
1179 continue;
1180 }
1181
1182 response = createFromJson(reading);
1183
1184 // Found the instance we're interested in
1185 break;
1186 }
1187
1188 if (numInstances > maxInstances)
1189 {
1190 log<level::DEBUG>("Trimming IPMI num instances",
1191 entry("NUM_INSTANCES=%d", numInstances));
1192 numInstances = maxInstances;
1193 }
1194 return std::make_tuple(response, numInstances);
Deepak Kodihalli0b459552018-02-06 06:25:12 -06001195}
1196
Patrick Venture0b02be92018-08-31 11:55:55 -07001197std::tuple<ResponseList, NumInstances>
1198 readAll(const std::string& type, uint8_t instanceStart, const Json& config)
Deepak Kodihalli0b459552018-02-06 06:25:12 -06001199{
Deepak Kodihallidd4cff12018-02-06 06:48:29 -06001200 ResponseList responses{};
1201
1202 size_t numInstances = 0;
1203 static const std::vector<Json> empty{};
1204 std::vector<Json> readings = config.value(type, empty);
1205 numInstances = readings.size();
1206 for (const auto& reading : readings)
1207 {
1208 try
1209 {
1210 // Max of 8 records
1211 if (responses.size() == maxRecords)
1212 {
1213 break;
1214 }
1215
1216 uint8_t instanceNum = reading.value("instance", 0);
1217 // Not in the instance range we're interested in
1218 if (instanceNum < instanceStart)
1219 {
1220 continue;
1221 }
1222
1223 Response response = createFromJson(reading);
1224 responses.push_back(response);
1225 }
Patrick Williamsa2ad2da2021-10-06 12:21:46 -05001226 catch (const std::exception& e)
Deepak Kodihallidd4cff12018-02-06 06:48:29 -06001227 {
1228 log<level::DEBUG>(e.what());
1229 continue;
1230 }
1231 }
1232
1233 if (numInstances > maxInstances)
1234 {
1235 log<level::DEBUG>("Trimming IPMI num instances",
1236 entry("NUM_INSTANCES=%d", numInstances));
1237 numInstances = maxInstances;
1238 }
1239 return std::make_tuple(responses, numInstances);
Deepak Kodihalli0b459552018-02-06 06:25:12 -06001240}
1241
1242} // namespace sensor_info
1243} // namespace dcmi
1244
Willy Tu11d68892022-01-20 10:37:34 -08001245ipmi_ret_t getSensorInfo(ipmi_netfn_t, ipmi_cmd_t, ipmi_request_t request,
1246 ipmi_response_t response, ipmi_data_len_t data_len,
1247 ipmi_context_t)
Deepak Kodihalli0b459552018-02-06 06:25:12 -06001248{
1249 auto requestData =
1250 reinterpret_cast<const dcmi::GetSensorInfoRequest*>(request);
1251 auto responseData =
1252 reinterpret_cast<dcmi::GetSensorInfoResponseHdr*>(response);
1253
1254 if (*data_len != sizeof(dcmi::GetSensorInfoRequest))
1255 {
1256 log<level::ERR>("Malformed request data",
1257 entry("DATA_SIZE=%d", *data_len));
1258 return IPMI_CC_REQ_DATA_LEN_INVALID;
1259 }
1260 *data_len = 0;
1261
1262 auto it = dcmi::entityIdToName.find(requestData->entityId);
1263 if (it == dcmi::entityIdToName.end())
1264 {
1265 log<level::ERR>("Unknown Entity ID",
1266 entry("ENTITY_ID=%d", requestData->entityId));
1267 return IPMI_CC_INVALID_FIELD_REQUEST;
1268 }
1269
Deepak Kodihalli0b459552018-02-06 06:25:12 -06001270 if (requestData->sensorType != dcmi::temperatureSensorType)
1271 {
1272 log<level::ERR>("Invalid sensor type",
1273 entry("SENSOR_TYPE=%d", requestData->sensorType));
1274 return IPMI_CC_INVALID_FIELD_REQUEST;
1275 }
1276
1277 dcmi::sensor_info::ResponseList sensors{};
1278 static dcmi::Json config{};
1279 static bool parsed = false;
1280
1281 try
1282 {
1283 if (!parsed)
1284 {
Kirill Pakhomova2573622018-11-02 19:00:18 +03001285 config = dcmi::parseJSONConfig(dcmi::gDCMISensorsConfig);
Deepak Kodihalli0b459552018-02-06 06:25:12 -06001286 parsed = true;
1287 }
1288
1289 if (!requestData->entityInstance)
1290 {
1291 // Read all instances
1292 std::tie(sensors, responseData->numInstances) =
1293 dcmi::sensor_info::readAll(it->second,
Patrick Venture0b02be92018-08-31 11:55:55 -07001294 requestData->instanceStart, config);
Deepak Kodihalli0b459552018-02-06 06:25:12 -06001295 }
1296 else
1297 {
1298 // Read one instance
1299 sensors.resize(1);
1300 std::tie(sensors[0], responseData->numInstances) =
Patrick Venture0b02be92018-08-31 11:55:55 -07001301 dcmi::sensor_info::read(it->second, requestData->entityInstance,
Deepak Kodihalli0b459552018-02-06 06:25:12 -06001302 config);
1303 }
1304 responseData->numRecords = sensors.size();
1305 }
Patrick Williamsa2ad2da2021-10-06 12:21:46 -05001306 catch (const InternalFailure& e)
Deepak Kodihalli0b459552018-02-06 06:25:12 -06001307 {
1308 return IPMI_CC_UNSPECIFIED_ERROR;
1309 }
1310
Deepak Kodihalli0b459552018-02-06 06:25:12 -06001311 size_t payloadSize = sensors.size() * sizeof(dcmi::sensor_info::Response);
1312 if (!sensors.empty())
1313 {
1314 memcpy(responseData + 1, // copy payload right after the response header
Patrick Venture0b02be92018-08-31 11:55:55 -07001315 sensors.data(), payloadSize);
Deepak Kodihalli0b459552018-02-06 06:25:12 -06001316 }
1317 *data_len = sizeof(dcmi::GetSensorInfoResponseHdr) + payloadSize;
1318
1319 return IPMI_CC_OK;
1320}
1321
Chris Austen1810bec2015-10-13 12:12:39 -05001322void register_netfn_dcmi_functions()
1323{
Tom05732372016-09-06 17:21:23 +05301324 // <Get Power Limit>
Vernon Maueryd4222fd2023-07-27 11:26:51 -07001325 registerGroupHandler(ipmi::prioOpenBmcBase, ipmi::groupDCMI,
1326 ipmi::dcmi::cmdGetPowerLimit, ipmi::Privilege::User,
1327 getPowerLimit);
Tom Joseph6f6dd4d2017-07-12 20:07:11 +05301328
Tom Joseph46fa37d2017-07-26 18:11:55 +05301329 // <Set Power Limit>
Vernon Maueryd4222fd2023-07-27 11:26:51 -07001330 registerGroupHandler(ipmi::prioOpenBmcBase, ipmi::groupDCMI,
1331 ipmi::dcmi::cmdSetPowerLimit,
1332 ipmi::Privilege::Operator, setPowerLimit);
Tom Joseph46fa37d2017-07-26 18:11:55 +05301333
Tom Joseph6c8d51b2017-07-26 18:18:06 +05301334 // <Activate/Deactivate Power Limit>
Vernon Maueryd4222fd2023-07-27 11:26:51 -07001335 registerGroupHandler(ipmi::prioOpenBmcBase, ipmi::groupDCMI,
1336 ipmi::dcmi::cmdActDeactivatePwrLimit,
1337 ipmi::Privilege::Operator, applyPowerLimit);
Tom Joseph6c8d51b2017-07-26 18:18:06 +05301338
Tom Joseph6f6dd4d2017-07-12 20:07:11 +05301339 // <Get Asset Tag>
Vernon Mauerydca47202023-07-27 11:32:01 -07001340 registerGroupHandler(ipmi::prioOpenBmcBase, ipmi::groupDCMI,
1341 ipmi::dcmi::cmdGetAssetTag, ipmi::Privilege::User,
1342 getAssetTag);
Tom Joseph545dd232017-07-12 20:20:49 +05301343
1344 // <Set Asset Tag>
Vernon Mauerydca47202023-07-27 11:32:01 -07001345 registerGroupHandler(ipmi::prioOpenBmcBase, ipmi::groupDCMI,
1346 ipmi::dcmi::cmdSetAssetTag, ipmi::Privilege::Operator,
1347 setAssetTag);
Vladislav Vovchenko8f7a6f62017-08-17 00:31:14 +03001348
Gunnar Mills8991dd62017-10-25 17:11:29 -05001349 // <Get Management Controller Identifier String>
Vladislav Vovchenko8f7a6f62017-08-17 00:31:14 +03001350
1351 ipmi_register_callback(NETFUN_GRPEXT, dcmi::Commands::GET_MGMNT_CTRL_ID_STR,
Patrick Venture0b02be92018-08-31 11:55:55 -07001352 NULL, getMgmntCtrlIdStr, PRIVILEGE_USER);
Vladislav Vovchenko8f7a6f62017-08-17 00:31:14 +03001353
1354 // <Set Management Controller Identifier String>
Vladislav Vovchenko8f7a6f62017-08-17 00:31:14 +03001355 ipmi_register_callback(NETFUN_GRPEXT, dcmi::Commands::SET_MGMNT_CTRL_ID_STR,
Patrick Venture0b02be92018-08-31 11:55:55 -07001356 NULL, setMgmntCtrlIdStr, PRIVILEGE_ADMIN);
Vladislav Vovchenko8f7a6f62017-08-17 00:31:14 +03001357
Dhruvaraj Subhashchandrane29be412018-01-16 05:11:56 -06001358 // <Get DCMI capabilities>
1359 ipmi_register_callback(NETFUN_GRPEXT, dcmi::Commands::GET_CAPABILITIES,
Patrick Venture0b02be92018-08-31 11:55:55 -07001360 NULL, getDCMICapabilities, PRIVILEGE_USER);
Deepak Kodihalliee717d72018-01-24 04:53:09 -06001361
1362 // <Get Temperature Readings>
1363 ipmi_register_callback(NETFUN_GRPEXT, dcmi::Commands::GET_TEMP_READINGS,
1364 NULL, getTempReadings, PRIVILEGE_USER);
1365
Marri Devender Rao66c5fda2018-01-18 10:48:37 -06001366 // <Get Power Reading>
1367 ipmi_register_callback(NETFUN_GRPEXT, dcmi::Commands::GET_POWER_READING,
1368 NULL, getPowerReading, PRIVILEGE_USER);
adarshgrami042e9db2022-09-15 10:34:34 +05301369// The Get sensor should get the senor details dynamically when
1370// FEATURE_DYNAMIC_SENSORS is enabled.
1371#ifndef FEATURE_DYNAMIC_SENSORS
Deepak Kodihalli0b459552018-02-06 06:25:12 -06001372 // <Get Sensor Info>
Patrick Venture0b02be92018-08-31 11:55:55 -07001373 ipmi_register_callback(NETFUN_GRPEXT, dcmi::Commands::GET_SENSOR_INFO, NULL,
Chau Lyd74df5f2023-05-25 10:33:00 +00001374 getSensorInfo, PRIVILEGE_OPERATOR);
adarshgrami042e9db2022-09-15 10:34:34 +05301375#endif
Nagaraju Goruganti22be97b2018-02-07 01:19:59 -06001376 // <Get DCMI Configuration Parameters>
Patrick Venture0b02be92018-08-31 11:55:55 -07001377 ipmi_register_callback(NETFUN_GRPEXT, dcmi::Commands::GET_CONF_PARAMS, NULL,
1378 getDCMIConfParams, PRIVILEGE_USER);
Nagaraju Goruganti22be97b2018-02-07 01:19:59 -06001379
1380 // <Set DCMI Configuration Parameters>
Patrick Venture0b02be92018-08-31 11:55:55 -07001381 ipmi_register_callback(NETFUN_GRPEXT, dcmi::Commands::SET_CONF_PARAMS, NULL,
1382 setDCMIConfParams, PRIVILEGE_ADMIN);
Nagaraju Goruganti22be97b2018-02-07 01:19:59 -06001383
Chris Austen1810bec2015-10-13 12:12:39 -05001384 return;
1385}
Tom05732372016-09-06 17:21:23 +05301386// 956379