blob: 26b32d18ad1c16f0a62b15a8b164c44940edc553 [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_SPEC_MAJOR_VERSION = 1;
36constexpr auto DCMI_SPEC_MINOR_VERSION = 5;
Nagaraju Goruganti22be97b2018-02-07 01:19:59 -060037constexpr auto DCMI_CONFIG_PARAMETER_REVISION = 1;
38constexpr auto DCMI_RAND_BACK_OFF_MASK = 0x80;
39constexpr auto DCMI_OPTION_60_43_MASK = 0x02;
40constexpr auto DCMI_OPTION_12_MASK = 0x01;
41constexpr auto DCMI_ACTIVATE_DHCP_MASK = 0x01;
42constexpr auto DCMI_ACTIVATE_DHCP_REPLY = 0x00;
William A. Kennington III5d06cc62019-04-25 02:10:55 -070043constexpr auto DCMI_SET_CONF_PARAM_REQ_PACKET_MAX_SIZE = 0x04;
44constexpr auto DCMI_SET_CONF_PARAM_REQ_PACKET_MIN_SIZE = 0x03;
Patrick Venture0b02be92018-08-31 11:55:55 -070045constexpr auto DHCP_TIMING1 = 0x04; // 4 sec
46constexpr auto DHCP_TIMING2_UPPER = 0x00; // 2 min
Nagaraju Goruganti22be97b2018-02-07 01:19:59 -060047constexpr auto DHCP_TIMING2_LOWER = 0x78;
Patrick Venture0b02be92018-08-31 11:55:55 -070048constexpr auto DHCP_TIMING3_UPPER = 0x00; // 64 sec
Nagaraju Goruganti22be97b2018-02-07 01:19:59 -060049constexpr auto DHCP_TIMING3_LOWER = 0x40;
50// When DHCP Option 12 is enabled the string "SendHostName=true" will be
51// added into n/w configuration file and the parameter
52// SendHostNameEnabled will set to true.
53constexpr auto DHCP_OPT12_ENABLED = "SendHostNameEnabled";
54
Marri Devender Rao66c5fda2018-01-18 10:48:37 -060055constexpr auto SENSOR_VALUE_INTF = "xyz.openbmc_project.Sensor.Value";
56constexpr auto SENSOR_VALUE_PROP = "Value";
Marri Devender Rao66c5fda2018-01-18 10:48:37 -060057
Andrew Geissler50c0c8f2017-07-11 16:18:51 -050058using namespace phosphor::logging;
59
Tom Josephb9d86f42017-07-26 18:03:47 +053060namespace dcmi
61{
Vernon Mauerydca47202023-07-27 11:32:01 -070062constexpr auto assetTagMaxOffset = 62;
63constexpr auto assetTagMaxSize = 63;
64constexpr auto maxBytes = 16;
65constexpr size_t maxCtrlIdStrLen = 63;
Tom Josephb9d86f42017-07-26 18:03:47 +053066
Vernon Maueryf038dc02023-07-27 14:06:11 -070067constexpr uint8_t parameterRevision = 2;
68constexpr uint8_t specMajorVersion = 1;
69constexpr uint8_t specMinorVersion = 5;
Vernon Mauerycce9ffd2023-07-27 14:15:17 -070070constexpr auto sensorValueIntf = "xyz.openbmc_project.Sensor.Value";
71constexpr auto sensorValueProp = "Value";
Vernon Maueryf038dc02023-07-27 14:06:11 -070072
Deepak Kodihalli0b459552018-02-06 06:25:12 -060073// Refer Table 6-14, DCMI Entity ID Extension, DCMI v1.5 spec
Patrick Venture0b02be92018-08-31 11:55:55 -070074static const std::map<uint8_t, std::string> entityIdToName{
75 {0x40, "inlet"}, {0x37, "inlet"}, {0x41, "cpu"},
76 {0x03, "cpu"}, {0x42, "baseboard"}, {0x07, "baseboard"}};
Deepak Kodihalli0b459552018-02-06 06:25:12 -060077
Kirill Pakhomov2c2af2c2018-11-06 16:06:10 +030078bool isDCMIPowerMgmtSupported()
79{
Vernon Maueryf4eb35d2023-07-27 11:08:49 -070080 static bool parsed = false;
81 static bool supported = false;
82 if (!parsed)
83 {
84 auto data = parseJSONConfig(gDCMICapabilitiesConfig);
Kirill Pakhomov2c2af2c2018-11-06 16:06:10 +030085
Vernon Maueryf4eb35d2023-07-27 11:08:49 -070086 supported = (gDCMIPowerMgmtSupported ==
87 data.value(gDCMIPowerMgmtCapability, 0));
88 }
89 return supported;
Kirill Pakhomov2c2af2c2018-11-06 16:06:10 +030090}
91
Vernon Maueryd4222fd2023-07-27 11:26:51 -070092std::optional<uint32_t> getPcap(ipmi::Context::ptr& ctx)
Andrew Geissler50c0c8f2017-07-11 16:18:51 -050093{
Vernon Maueryd4222fd2023-07-27 11:26:51 -070094 std::string service{};
95 boost::system::error_code ec = ipmi::getService(ctx, pcapInterface,
96 pcapPath, service);
97 if (ec.value())
Andrew Geissler50c0c8f2017-07-11 16:18:51 -050098 {
Vernon Maueryd4222fd2023-07-27 11:26:51 -070099 return std::nullopt;
George Liu3e3cc352023-07-26 15:59:31 +0800100 }
Vernon Maueryd4222fd2023-07-27 11:26:51 -0700101 uint32_t pcap{};
102 ec = ipmi::getDbusProperty(ctx, service, pcapPath, pcapInterface,
103 powerCapProp, pcap);
104 if (ec.value())
George Liu3e3cc352023-07-26 15:59:31 +0800105 {
Vernon Maueryd4222fd2023-07-27 11:26:51 -0700106 log<level::ERR>("Error in getPcap prop",
107 entry("ERROR=%s", ec.message().c_str()));
Tom Josephb9d86f42017-07-26 18:03:47 +0530108 elog<InternalFailure>();
Vernon Maueryd4222fd2023-07-27 11:26:51 -0700109 return std::nullopt;
Andrew Geissler50c0c8f2017-07-11 16:18:51 -0500110 }
Vernon Maueryd4222fd2023-07-27 11:26:51 -0700111 return pcap;
Andrew Geissler50c0c8f2017-07-11 16:18:51 -0500112}
113
Vernon Maueryd4222fd2023-07-27 11:26:51 -0700114std::optional<bool> getPcapEnabled(ipmi::Context::ptr& ctx)
Andrew Geissler50c0c8f2017-07-11 16:18:51 -0500115{
Vernon Maueryd4222fd2023-07-27 11:26:51 -0700116 std::string service{};
117 boost::system::error_code ec = ipmi::getService(ctx, pcapInterface,
118 pcapPath, service);
119 if (ec.value())
Andrew Geissler50c0c8f2017-07-11 16:18:51 -0500120 {
Vernon Maueryd4222fd2023-07-27 11:26:51 -0700121 return std::nullopt;
George Liu3e3cc352023-07-26 15:59:31 +0800122 }
Vernon Maueryd4222fd2023-07-27 11:26:51 -0700123 bool pcapEnabled{};
124 ec = ipmi::getDbusProperty(ctx, service, pcapPath, pcapInterface,
125 powerCapEnableProp, pcapEnabled);
126 if (ec.value())
George Liu3e3cc352023-07-26 15:59:31 +0800127 {
Vernon Maueryd4222fd2023-07-27 11:26:51 -0700128 log<level::ERR>("Error in getPcap prop");
Tom Josephb9d86f42017-07-26 18:03:47 +0530129 elog<InternalFailure>();
Vernon Maueryd4222fd2023-07-27 11:26:51 -0700130 return std::nullopt;
Andrew Geissler50c0c8f2017-07-11 16:18:51 -0500131 }
Vernon Maueryd4222fd2023-07-27 11:26:51 -0700132 return pcapEnabled;
Andrew Geissler50c0c8f2017-07-11 16:18:51 -0500133}
Chris Austen1810bec2015-10-13 12:12:39 -0500134
Vernon Maueryd4222fd2023-07-27 11:26:51 -0700135bool setPcap(ipmi::Context::ptr& ctx, const uint32_t powerCap)
Tom Joseph46fa37d2017-07-26 18:11:55 +0530136{
Vernon Maueryd4222fd2023-07-27 11:26:51 -0700137 std::string service{};
138 boost::system::error_code ec = ipmi::getService(ctx, pcapInterface,
139 pcapPath, service);
140 if (ec.value())
Tom Joseph46fa37d2017-07-26 18:11:55 +0530141 {
Vernon Maueryd4222fd2023-07-27 11:26:51 -0700142 return false;
George Liu3e3cc352023-07-26 15:59:31 +0800143 }
Vernon Maueryd4222fd2023-07-27 11:26:51 -0700144
145 ec = ipmi::setDbusProperty(ctx, service, pcapPath, pcapInterface,
146 powerCapProp, powerCap);
147 if (ec.value())
George Liu3e3cc352023-07-26 15:59:31 +0800148 {
149 log<level::ERR>("Error in setPcap property",
Vernon Maueryd4222fd2023-07-27 11:26:51 -0700150 entry("ERROR=%s", ec.message().c_str()));
Tom Joseph46fa37d2017-07-26 18:11:55 +0530151 elog<InternalFailure>();
Vernon Maueryd4222fd2023-07-27 11:26:51 -0700152 return false;
Tom Joseph46fa37d2017-07-26 18:11:55 +0530153 }
Vernon Maueryd4222fd2023-07-27 11:26:51 -0700154 return true;
Tom Joseph46fa37d2017-07-26 18:11:55 +0530155}
156
Vernon Maueryd4222fd2023-07-27 11:26:51 -0700157bool setPcapEnable(ipmi::Context::ptr& ctx, bool enabled)
Tom Joseph6c8d51b2017-07-26 18:18:06 +0530158{
Vernon Maueryd4222fd2023-07-27 11:26:51 -0700159 std::string service{};
160 boost::system::error_code ec = ipmi::getService(ctx, pcapInterface,
161 pcapPath, service);
162 if (ec.value())
Tom Joseph6c8d51b2017-07-26 18:18:06 +0530163 {
Vernon Maueryd4222fd2023-07-27 11:26:51 -0700164 return false;
George Liu3e3cc352023-07-26 15:59:31 +0800165 }
Vernon Maueryd4222fd2023-07-27 11:26:51 -0700166
167 ec = ipmi::setDbusProperty(ctx, service, pcapPath, pcapInterface,
168 powerCapEnableProp, enabled);
169 if (ec.value())
George Liu3e3cc352023-07-26 15:59:31 +0800170 {
171 log<level::ERR>("Error in setPcapEnabled property",
Vernon Maueryd4222fd2023-07-27 11:26:51 -0700172 entry("ERROR=%s", ec.message().c_str()));
Tom Joseph6c8d51b2017-07-26 18:18:06 +0530173 elog<InternalFailure>();
Vernon Maueryd4222fd2023-07-27 11:26:51 -0700174 return false;
Tom Joseph6c8d51b2017-07-26 18:18:06 +0530175 }
Vernon Maueryd4222fd2023-07-27 11:26:51 -0700176 return true;
Tom Joseph6c8d51b2017-07-26 18:18:06 +0530177}
178
Vernon Mauerydca47202023-07-27 11:32:01 -0700179std::optional<std::string> readAssetTag(ipmi::Context::ptr& ctx)
Tom Josephbe5eaa12017-07-12 19:54:44 +0530180{
Tom Josephbe5eaa12017-07-12 19:54:44 +0530181 // Read the object tree with the inventory root to figure out the object
182 // that has implemented the Asset tag interface.
Vernon Mauerydca47202023-07-27 11:32:01 -0700183 ipmi::DbusObjectInfo objectInfo;
184 boost::system::error_code ec = getDbusObject(
185 ctx, dcmi::assetTagIntf, ipmi::sensor::inventoryRoot, "", objectInfo);
186 if (ec.value())
Tom Josephbe5eaa12017-07-12 19:54:44 +0530187 {
Vernon Mauerydca47202023-07-27 11:32:01 -0700188 return std::nullopt;
George Liu3e3cc352023-07-26 15:59:31 +0800189 }
Vernon Mauerydca47202023-07-27 11:32:01 -0700190
191 std::string assetTag{};
192 ec = ipmi::getDbusProperty(ctx, objectInfo.second, objectInfo.first,
193 dcmi::assetTagIntf, dcmi::assetTagProp,
194 assetTag);
195 if (ec.value())
George Liu3e3cc352023-07-26 15:59:31 +0800196 {
197 log<level::ERR>("Error in reading asset tag",
Vernon Mauerydca47202023-07-27 11:32:01 -0700198 entry("ERROR=%s", ec.message().c_str()));
Tom Josephbe5eaa12017-07-12 19:54:44 +0530199 elog<InternalFailure>();
Vernon Mauerydca47202023-07-27 11:32:01 -0700200 return std::nullopt;
Tom Josephbe5eaa12017-07-12 19:54:44 +0530201 }
Vernon Mauerydca47202023-07-27 11:32:01 -0700202
203 return assetTag;
Tom Josephbe5eaa12017-07-12 19:54:44 +0530204}
205
Vernon Mauerydca47202023-07-27 11:32:01 -0700206bool writeAssetTag(ipmi::Context::ptr& ctx, const std::string& assetTag)
Tom Josephbe5b9892017-07-15 00:55:23 +0530207{
Tom Josephbe5b9892017-07-15 00:55:23 +0530208 // Read the object tree with the inventory root to figure out the object
209 // that has implemented the Asset tag interface.
Vernon Mauerydca47202023-07-27 11:32:01 -0700210 ipmi::DbusObjectInfo objectInfo;
211 boost::system::error_code ec = getDbusObject(
212 ctx, dcmi::assetTagIntf, ipmi::sensor::inventoryRoot, "", objectInfo);
213 if (ec.value())
Tom Josephbe5b9892017-07-15 00:55:23 +0530214 {
Vernon Mauerydca47202023-07-27 11:32:01 -0700215 return false;
George Liu3e3cc352023-07-26 15:59:31 +0800216 }
Vernon Mauerydca47202023-07-27 11:32:01 -0700217
218 ec = ipmi::setDbusProperty(ctx, objectInfo.second, objectInfo.first,
219 dcmi::assetTagIntf, dcmi::assetTagProp,
220 assetTag);
221 if (ec.value())
George Liu3e3cc352023-07-26 15:59:31 +0800222 {
223 log<level::ERR>("Error in writing asset tag",
Vernon Mauerydca47202023-07-27 11:32:01 -0700224 entry("ERROR=%s", ec.message().c_str()));
Tom Josephbe5b9892017-07-15 00:55:23 +0530225 elog<InternalFailure>();
Vernon Mauerydca47202023-07-27 11:32:01 -0700226 return false;
Tom Josephbe5b9892017-07-15 00:55:23 +0530227 }
Vernon Mauerydca47202023-07-27 11:32:01 -0700228 return true;
Tom Josephbe5b9892017-07-15 00:55:23 +0530229}
230
Vernon Maueryefb5ae52023-07-27 11:35:43 -0700231std::optional<std::string> getHostName(ipmi::Context::ptr& ctx)
Vladislav Vovchenko8f7a6f62017-08-17 00:31:14 +0300232{
Vernon Maueryefb5ae52023-07-27 11:35:43 -0700233 std::string service{};
234 boost::system::error_code ec = ipmi::getService(ctx, networkConfigIntf,
235 networkConfigObj, service);
236 if (ec.value())
237 {
238 return std::nullopt;
239 }
240 std::string hostname{};
241 ec = ipmi::getDbusProperty(ctx, service, networkConfigObj,
242 networkConfigIntf, hostNameProp, hostname);
243 if (ec.value())
244 {
245 log<level::ERR>("Error fetching hostname");
246 elog<InternalFailure>();
247 return std::nullopt;
248 }
249 return hostname;
Vladislav Vovchenko8f7a6f62017-08-17 00:31:14 +0300250}
251
Thang Tran55cbf552023-01-31 14:43:02 +0700252EthernetInterface::DHCPConf getDHCPEnabled()
Nagaraju Goruganti22be97b2018-02-07 01:19:59 -0600253{
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
Johnathan Mantey74a21022018-12-13 13:17:56 -0800256 auto ethdevice = ipmi::getChannelName(ethernetDefaultChannelNum);
Patrick Williamsfbc6c9d2023-05-10 07:50:16 -0500257 auto ethernetObj = ipmi::getDbusObject(bus, ethernetIntf, networkRoot,
258 ethdevice);
Nagaraju Goruganti22be97b2018-02-07 01:19:59 -0600259 auto service = ipmi::getService(bus, ethernetIntf, ethernetObj.first);
Patrick Venture0b02be92018-08-31 11:55:55 -0700260 auto value = ipmi::getDbusProperty(bus, service, ethernetObj.first,
261 ethernetIntf, "DHCPEnabled");
Nagaraju Goruganti22be97b2018-02-07 01:19:59 -0600262
Thang Tran55cbf552023-01-31 14:43:02 +0700263 return EthernetInterface::convertDHCPConfFromString(
264 std::get<std::string>(value));
Nagaraju Goruganti22be97b2018-02-07 01:19:59 -0600265}
266
267bool getDHCPOption(std::string prop)
268{
Patrick Williams5d82f472022-07-22 19:26:53 -0500269 sdbusplus::bus_t bus{ipmid_get_sd_bus_connection()};
Nagaraju Goruganti22be97b2018-02-07 01:19:59 -0600270
271 auto service = ipmi::getService(bus, dhcpIntf, dhcpObj);
272 auto value = ipmi::getDbusProperty(bus, service, dhcpObj, dhcpIntf, prop);
273
Vernon Maueryf442e112019-04-09 11:44:36 -0700274 return std::get<bool>(value);
Nagaraju Goruganti22be97b2018-02-07 01:19:59 -0600275}
276
Nagaraju Goruganti22be97b2018-02-07 01:19:59 -0600277void setDHCPOption(std::string prop, bool value)
278{
Patrick Williams5d82f472022-07-22 19:26:53 -0500279 sdbusplus::bus_t bus{ipmid_get_sd_bus_connection()};
Nagaraju Goruganti22be97b2018-02-07 01:19:59 -0600280
281 auto service = ipmi::getService(bus, dhcpIntf, dhcpObj);
282 ipmi::setDbusProperty(bus, service, dhcpObj, dhcpIntf, prop, value);
283}
284
Kirill Pakhomova2573622018-11-02 19:00:18 +0300285Json parseJSONConfig(const std::string& configFile)
Deepak Kodihalli0b459552018-02-06 06:25:12 -0600286{
287 std::ifstream jsonFile(configFile);
288 if (!jsonFile.is_open())
289 {
290 log<level::ERR>("Temperature readings JSON file not found");
291 elog<InternalFailure>();
292 }
293
294 auto data = Json::parse(jsonFile, nullptr, false);
295 if (data.is_discarded())
296 {
297 log<level::ERR>("Temperature readings JSON parser failure");
298 elog<InternalFailure>();
299 }
300
301 return data;
302}
303
Tom Josephbe5eaa12017-07-12 19:54:44 +0530304} // namespace dcmi
Chris Austen1810bec2015-10-13 12:12:39 -0500305
Vernon Maueryd4222fd2023-07-27 11:26:51 -0700306constexpr uint8_t exceptionPowerOff = 0x01;
307ipmi::RspType<uint16_t, // reserved
308 uint8_t, // exception actions
309 uint16_t, // power limit requested in watts
310 uint32_t, // correction time in milliseconds
311 uint16_t, // reserved
312 uint16_t // statistics sampling period in seconds
313 >
314 getPowerLimit(ipmi::Context::ptr ctx, uint16_t reserved)
Tom Josephb9d86f42017-07-26 18:03:47 +0530315{
Kirill Pakhomov2c2af2c2018-11-06 16:06:10 +0300316 if (!dcmi::isDCMIPowerMgmtSupported())
317 {
Vernon Maueryd4222fd2023-07-27 11:26:51 -0700318 return ipmi::responseInvalidCommand();
Kirill Pakhomov2c2af2c2018-11-06 16:06:10 +0300319 }
Vernon Maueryd4222fd2023-07-27 11:26:51 -0700320 if (reserved)
Tom Josephb9d86f42017-07-26 18:03:47 +0530321 {
Vernon Maueryd4222fd2023-07-27 11:26:51 -0700322 return ipmi::responseInvalidFieldRequest();
Tom Josephb9d86f42017-07-26 18:03:47 +0530323 }
324
Vernon Maueryd4222fd2023-07-27 11:26:51 -0700325 std::optional<uint16_t> pcapValue = dcmi::getPcap(ctx);
326 std::optional<bool> pcapEnable = dcmi::getPcapEnabled(ctx);
327 if (!pcapValue || !pcapEnable)
328 {
329 return ipmi::responseUnspecifiedError();
330 }
331
332 constexpr uint16_t reserved1{};
333 constexpr uint16_t reserved2{};
Tom Josephb9d86f42017-07-26 18:03:47 +0530334 /*
335 * Exception action if power limit is exceeded and cannot be controlled
336 * with the correction time limit is hardcoded to Hard Power Off system
337 * and log event to SEL.
338 */
Vernon Maueryd4222fd2023-07-27 11:26:51 -0700339 constexpr uint8_t exception = exceptionPowerOff;
Tom Josephb9d86f42017-07-26 18:03:47 +0530340 /*
341 * Correction time limit and Statistics sampling period is currently not
342 * populated.
343 */
Vernon Maueryd4222fd2023-07-27 11:26:51 -0700344 constexpr uint32_t correctionTime{};
345 constexpr uint16_t statsPeriod{};
346 if (!pcapEnable)
Tom Josephb9d86f42017-07-26 18:03:47 +0530347 {
Vernon Maueryd4222fd2023-07-27 11:26:51 -0700348 constexpr ipmi::Cc responseNoPowerLimitSet = 0x80;
349 constexpr uint16_t noPcap{};
350 return ipmi::response(responseNoPowerLimitSet, reserved1, exception,
351 noPcap, correctionTime, reserved2, statsPeriod);
Tom Josephb9d86f42017-07-26 18:03:47 +0530352 }
Vernon Maueryd4222fd2023-07-27 11:26:51 -0700353 return ipmi::responseSuccess(reserved1, exception, *pcapValue,
354 correctionTime, reserved2, statsPeriod);
Tom Josephb9d86f42017-07-26 18:03:47 +0530355}
356
Vernon Maueryd4222fd2023-07-27 11:26:51 -0700357ipmi::RspType<> setPowerLimit(ipmi::Context::ptr& ctx, uint16_t reserved1,
358 uint8_t exceptionAction, uint16_t powerLimit,
359 uint32_t correctionTime, uint16_t reserved2,
360 uint16_t statsPeriod)
Tom Joseph46fa37d2017-07-26 18:11:55 +0530361{
Kirill Pakhomov2c2af2c2018-11-06 16:06:10 +0300362 if (!dcmi::isDCMIPowerMgmtSupported())
363 {
Kirill Pakhomov2c2af2c2018-11-06 16:06:10 +0300364 log<level::ERR>("DCMI Power management is unsupported!");
Vernon Maueryd4222fd2023-07-27 11:26:51 -0700365 return ipmi::responseInvalidCommand();
Kirill Pakhomov2c2af2c2018-11-06 16:06:10 +0300366 }
367
Vernon Maueryd4222fd2023-07-27 11:26:51 -0700368 // Only process the power limit requested in watts. Return errors
369 // for other fields that are set
370 if (reserved1 || reserved2 || correctionTime || statsPeriod ||
371 exceptionAction != exceptionPowerOff)
Tom Joseph46fa37d2017-07-26 18:11:55 +0530372 {
Vernon Maueryd4222fd2023-07-27 11:26:51 -0700373 return ipmi::responseInvalidFieldRequest();
Tom Joseph46fa37d2017-07-26 18:11:55 +0530374 }
Vernon Maueryd4222fd2023-07-27 11:26:51 -0700375
376 if (!dcmi::setPcap(ctx, powerLimit))
Tom Joseph46fa37d2017-07-26 18:11:55 +0530377 {
Vernon Maueryd4222fd2023-07-27 11:26:51 -0700378 return ipmi::responseUnspecifiedError();
Tom Joseph46fa37d2017-07-26 18:11:55 +0530379 }
380
Vernon Maueryd4222fd2023-07-27 11:26:51 -0700381 log<level::INFO>("Set Power Cap", entry("POWERCAP=%u", powerLimit));
Tom Joseph46fa37d2017-07-26 18:11:55 +0530382
Vernon Maueryd4222fd2023-07-27 11:26:51 -0700383 return ipmi::responseSuccess();
Tom Joseph46fa37d2017-07-26 18:11:55 +0530384}
385
Vernon Maueryd4222fd2023-07-27 11:26:51 -0700386ipmi::RspType<> applyPowerLimit(ipmi::Context::ptr& ctx, bool enabled,
387 uint7_t reserved1, uint16_t reserved2)
Tom Joseph6c8d51b2017-07-26 18:18:06 +0530388{
Kirill Pakhomov2c2af2c2018-11-06 16:06:10 +0300389 if (!dcmi::isDCMIPowerMgmtSupported())
390 {
Kirill Pakhomov2c2af2c2018-11-06 16:06:10 +0300391 log<level::ERR>("DCMI Power management is unsupported!");
Vernon Maueryd4222fd2023-07-27 11:26:51 -0700392 return ipmi::responseInvalidCommand();
393 }
394 if (reserved1 || reserved2)
395 {
396 return ipmi::responseInvalidFieldRequest();
Kirill Pakhomov2c2af2c2018-11-06 16:06:10 +0300397 }
398
Vernon Maueryd4222fd2023-07-27 11:26:51 -0700399 if (!dcmi::setPcapEnable(ctx, enabled))
Tom Joseph6c8d51b2017-07-26 18:18:06 +0530400 {
Vernon Maueryd4222fd2023-07-27 11:26:51 -0700401 return ipmi::responseUnspecifiedError();
Tom Joseph6c8d51b2017-07-26 18:18:06 +0530402 }
403
404 log<level::INFO>("Set Power Cap Enable",
Vernon Maueryd4222fd2023-07-27 11:26:51 -0700405 entry("POWERCAPENABLE=%u", static_cast<uint8_t>(enabled)));
Tom Joseph6c8d51b2017-07-26 18:18:06 +0530406
Vernon Maueryd4222fd2023-07-27 11:26:51 -0700407 return ipmi::responseSuccess();
Tom Joseph6c8d51b2017-07-26 18:18:06 +0530408}
409
Vernon Mauerydca47202023-07-27 11:32:01 -0700410ipmi::RspType<uint8_t, // total tag length
411 std::vector<char> // tag data
412 >
413 getAssetTag(ipmi::Context::ptr& ctx, uint8_t offset, uint8_t count)
Tom Joseph6f6dd4d2017-07-12 20:07:11 +0530414{
Vernon Mauerydca47202023-07-27 11:32:01 -0700415 // Verify offset to read and number of bytes to read are not exceeding
416 // the range.
417 if ((offset > dcmi::assetTagMaxOffset) || (count > dcmi::maxBytes) ||
418 ((offset + count) > dcmi::assetTagMaxSize))
Tom Joseph6f6dd4d2017-07-12 20:07:11 +0530419 {
Vernon Mauerydca47202023-07-27 11:32:01 -0700420 return ipmi::responseParmOutOfRange();
Tom Joseph6f6dd4d2017-07-12 20:07:11 +0530421 }
422
Vernon Mauerydca47202023-07-27 11:32:01 -0700423 std::optional<std::string> assetTagResp = dcmi::readAssetTag(ctx);
424 if (!assetTagResp)
Tom Joseph6f6dd4d2017-07-12 20:07:11 +0530425 {
Vernon Mauerydca47202023-07-27 11:32:01 -0700426 return ipmi::responseUnspecifiedError();
Tom Joseph6f6dd4d2017-07-12 20:07:11 +0530427 }
428
Vernon Mauerydca47202023-07-27 11:32:01 -0700429 std::string& assetTag = assetTagResp.value();
430 // If the asset tag is longer than 63 bytes, restrict it to 63 bytes to
431 // suit Get Asset Tag command.
Tom Joseph6f6dd4d2017-07-12 20:07:11 +0530432 if (assetTag.size() > dcmi::assetTagMaxSize)
433 {
434 assetTag.resize(dcmi::assetTagMaxSize);
435 }
436
Vernon Mauerydca47202023-07-27 11:32:01 -0700437 if (offset >= assetTag.size())
Tom Joseph6f6dd4d2017-07-12 20:07:11 +0530438 {
Vernon Mauerydca47202023-07-27 11:32:01 -0700439 return ipmi::responseParmOutOfRange();
Tom Joseph6f6dd4d2017-07-12 20:07:11 +0530440 }
441
Vernon Mauerydca47202023-07-27 11:32:01 -0700442 // silently truncate reads beyond the end of assetTag
443 if ((offset + count) >= assetTag.size())
444 {
445 count = assetTag.size() - offset;
446 }
Tom Joseph6f6dd4d2017-07-12 20:07:11 +0530447
Vernon Mauerydca47202023-07-27 11:32:01 -0700448 auto totalTagSize = static_cast<uint8_t>(assetTag.size());
449 std::vector<char> data{assetTag.begin() + offset,
450 assetTag.begin() + offset + count};
Tom Joseph6f6dd4d2017-07-12 20:07:11 +0530451
Vernon Mauerydca47202023-07-27 11:32:01 -0700452 return ipmi::responseSuccess(totalTagSize, data);
Tom Joseph6f6dd4d2017-07-12 20:07:11 +0530453}
454
Vernon Mauerydca47202023-07-27 11:32:01 -0700455ipmi::RspType<uint8_t // new asset tag length
456 >
457 setAssetTag(ipmi::Context::ptr& ctx, uint8_t offset, uint8_t count,
458 const std::vector<char>& data)
Tom Joseph545dd232017-07-12 20:20:49 +0530459{
Vernon Mauerydca47202023-07-27 11:32:01 -0700460 // Verify offset to read and number of bytes to read are not exceeding
461 // the range.
462 if ((offset > dcmi::assetTagMaxOffset) || (count > dcmi::maxBytes) ||
463 ((offset + count) > dcmi::assetTagMaxSize))
Tom Joseph545dd232017-07-12 20:20:49 +0530464 {
Vernon Mauerydca47202023-07-27 11:32:01 -0700465 return ipmi::responseParmOutOfRange();
466 }
467 if (data.size() != count)
468 {
469 return ipmi::responseReqDataLenInvalid();
Tom Joseph545dd232017-07-12 20:20:49 +0530470 }
471
Vernon Mauerydca47202023-07-27 11:32:01 -0700472 std::optional<std::string> assetTagResp = dcmi::readAssetTag(ctx);
473 if (!assetTagResp)
Tom Joseph545dd232017-07-12 20:20:49 +0530474 {
Vernon Mauerydca47202023-07-27 11:32:01 -0700475 return ipmi::responseUnspecifiedError();
Tom Joseph545dd232017-07-12 20:20:49 +0530476 }
Vernon Mauerydca47202023-07-27 11:32:01 -0700477
478 std::string& assetTag = assetTagResp.value();
479
480 if (offset > assetTag.size())
Tom Joseph545dd232017-07-12 20:20:49 +0530481 {
Vernon Mauerydca47202023-07-27 11:32:01 -0700482 return ipmi::responseParmOutOfRange();
Tom Joseph545dd232017-07-12 20:20:49 +0530483 }
Vernon Mauerydca47202023-07-27 11:32:01 -0700484
485 // operation is to truncate at offset and append new data
486 assetTag.resize(offset);
487 assetTag.append(data.begin(), data.end());
488
489 if (!dcmi::writeAssetTag(ctx, assetTag))
490 {
491 return ipmi::responseUnspecifiedError();
492 }
493
494 auto totalTagSize = static_cast<uint8_t>(assetTag.size());
495 return ipmi::responseSuccess(totalTagSize);
Tom Joseph545dd232017-07-12 20:20:49 +0530496}
497
Vernon Maueryefb5ae52023-07-27 11:35:43 -0700498ipmi::RspType<uint8_t, // length
499 std::vector<char> // data
500 >
501 getMgmntCtrlIdStr(ipmi::Context::ptr& ctx, uint8_t offset, uint8_t count)
Vladislav Vovchenko8f7a6f62017-08-17 00:31:14 +0300502{
Vernon Maueryefb5ae52023-07-27 11:35:43 -0700503 if (count > dcmi::maxBytes || offset + count > dcmi::maxCtrlIdStrLen)
Vladislav Vovchenko8f7a6f62017-08-17 00:31:14 +0300504 {
Vernon Maueryefb5ae52023-07-27 11:35:43 -0700505 return ipmi::responseParmOutOfRange();
Vladislav Vovchenko8f7a6f62017-08-17 00:31:14 +0300506 }
507
Vernon Maueryefb5ae52023-07-27 11:35:43 -0700508 std::optional<std::string> hostnameResp = dcmi::getHostName(ctx);
509 if (!hostnameResp)
Vladislav Vovchenko8f7a6f62017-08-17 00:31:14 +0300510 {
Vernon Maueryefb5ae52023-07-27 11:35:43 -0700511 return ipmi::responseUnspecifiedError();
Vladislav Vovchenko8f7a6f62017-08-17 00:31:14 +0300512 }
513
Vernon Maueryefb5ae52023-07-27 11:35:43 -0700514 std::string& hostname = hostnameResp.value();
515 // If the id string is longer than 63 bytes, restrict it to 63 bytes to
516 // suit set management ctrl str command.
517 if (hostname.size() > dcmi::maxCtrlIdStrLen)
Vladislav Vovchenko8f7a6f62017-08-17 00:31:14 +0300518 {
Vernon Maueryefb5ae52023-07-27 11:35:43 -0700519 hostname.resize(dcmi::maxCtrlIdStrLen);
Vladislav Vovchenko8f7a6f62017-08-17 00:31:14 +0300520 }
Vladislav Vovchenko8f7a6f62017-08-17 00:31:14 +0300521
Vernon Maueryefb5ae52023-07-27 11:35:43 -0700522 if (offset >= hostname.size())
523 {
524 return ipmi::responseParmOutOfRange();
525 }
526
527 // silently truncate reads beyond the end of hostname
528 if ((offset + count) >= hostname.size())
529 {
530 count = hostname.size() - offset;
531 }
532
533 auto nameSize = static_cast<uint8_t>(hostname.size());
534 std::vector<char> data{hostname.begin() + offset,
535 hostname.begin() + offset + count};
536
537 return ipmi::responseSuccess(nameSize, data);
Vladislav Vovchenko8f7a6f62017-08-17 00:31:14 +0300538}
539
Vernon Maueryefb5ae52023-07-27 11:35:43 -0700540ipmi::RspType<uint8_t> setMgmntCtrlIdStr(ipmi::Context::ptr& ctx,
541 uint8_t offset, uint8_t count,
542 std::vector<char> data)
Vladislav Vovchenko8f7a6f62017-08-17 00:31:14 +0300543{
Vernon Maueryefb5ae52023-07-27 11:35:43 -0700544 if ((offset > dcmi::maxCtrlIdStrLen) || (count > dcmi::maxBytes) ||
545 ((offset + count) > dcmi::maxCtrlIdStrLen))
Vladislav Vovchenko8f7a6f62017-08-17 00:31:14 +0300546 {
Vernon Maueryefb5ae52023-07-27 11:35:43 -0700547 return ipmi::responseParmOutOfRange();
548 }
549 if (data.size() != count)
550 {
551 return ipmi::responseReqDataLenInvalid();
552 }
553 bool terminalWrite{data.back() == '\0'};
554 if (terminalWrite)
555 {
556 // remove the null termination from the data (no need with std::string)
557 data.resize(count - 1);
Vladislav Vovchenko8f7a6f62017-08-17 00:31:14 +0300558 }
559
Vernon Maueryefb5ae52023-07-27 11:35:43 -0700560 static std::string hostname{};
561 // read in the current value if not starting at offset 0
562 if (hostname.size() == 0 && offset != 0)
Vladislav Vovchenko8f7a6f62017-08-17 00:31:14 +0300563 {
Vernon Maueryefb5ae52023-07-27 11:35:43 -0700564 /* read old ctrlIdStr */
565 std::optional<std::string> hostnameResp = dcmi::getHostName(ctx);
566 if (!hostnameResp)
Vladislav Vovchenko8f7a6f62017-08-17 00:31:14 +0300567 {
Vernon Maueryefb5ae52023-07-27 11:35:43 -0700568 return ipmi::responseUnspecifiedError();
Vladislav Vovchenko8f7a6f62017-08-17 00:31:14 +0300569 }
Vernon Maueryefb5ae52023-07-27 11:35:43 -0700570 hostname = hostnameResp.value();
571 hostname.resize(offset);
Vladislav Vovchenko8f7a6f62017-08-17 00:31:14 +0300572 }
573
Vernon Maueryefb5ae52023-07-27 11:35:43 -0700574 // operation is to truncate at offset and append new data
575 hostname.append(data.begin(), data.end());
576
577 // do the update if this is the last write
578 if (terminalWrite)
579 {
580 boost::system::error_code ec = ipmi::setDbusProperty(
581 ctx, dcmi::networkServiceName, dcmi::networkConfigObj,
582 dcmi::networkConfigIntf, dcmi::hostNameProp, hostname);
583 hostname.clear();
584 if (ec.value())
585 {
586 return ipmi::responseUnspecifiedError();
587 }
588 }
589
590 auto totalIdSize = static_cast<uint8_t>(offset + count);
591 return ipmi::responseSuccess(totalIdSize);
Vladislav Vovchenko8f7a6f62017-08-17 00:31:14 +0300592}
593
Vernon Maueryf038dc02023-07-27 14:06:11 -0700594ipmi::RspType<ipmi::message::Payload> getDCMICapabilities(uint8_t parameter)
Dhruvaraj Subhashchandrane29be412018-01-16 05:11:56 -0600595{
Kirill Pakhomova2573622018-11-02 19:00:18 +0300596 std::ifstream dcmiCapFile(dcmi::gDCMICapabilitiesConfig);
Dhruvaraj Subhashchandrane29be412018-01-16 05:11:56 -0600597 if (!dcmiCapFile.is_open())
598 {
599 log<level::ERR>("DCMI Capabilities file not found");
Vernon Maueryf038dc02023-07-27 14:06:11 -0700600 return ipmi::responseUnspecifiedError();
Dhruvaraj Subhashchandrane29be412018-01-16 05:11:56 -0600601 }
602
603 auto data = nlohmann::json::parse(dcmiCapFile, nullptr, false);
604 if (data.is_discarded())
605 {
606 log<level::ERR>("DCMI Capabilities JSON parser failure");
Vernon Maueryf038dc02023-07-27 14:06:11 -0700607 return ipmi::responseUnspecifiedError();
Dhruvaraj Subhashchandrane29be412018-01-16 05:11:56 -0600608 }
609
Vernon Maueryf038dc02023-07-27 14:06:11 -0700610 constexpr bool reserved1{};
611 constexpr uint5_t reserved5{};
612 constexpr uint7_t reserved7{};
613 constexpr uint8_t reserved8{};
614 constexpr uint16_t reserved16{};
Dhruvaraj Subhashchandrane29be412018-01-16 05:11:56 -0600615
Vernon Maueryf038dc02023-07-27 14:06:11 -0700616 ipmi::message::Payload payload;
617 payload.pack(dcmi::specMajorVersion, dcmi::specMinorVersion,
618 dcmi::parameterRevision);
619
620 enum class DCMICapParameters : uint8_t
Dhruvaraj Subhashchandrane29be412018-01-16 05:11:56 -0600621 {
Vernon Maueryf038dc02023-07-27 14:06:11 -0700622 SupportedDcmiCaps = 0x01, // Supported DCMI Capabilities
623 MandatoryPlatAttributes = 0x02, // Mandatory Platform Attributes
624 OptionalPlatAttributes = 0x03, // Optional Platform Attributes
625 ManageabilityAccessAttributes = 0x04, // Manageability Access Attributes
626 };
Dhruvaraj Subhashchandrane29be412018-01-16 05:11:56 -0600627
Vernon Maueryf038dc02023-07-27 14:06:11 -0700628 switch (static_cast<DCMICapParameters>(parameter))
Dhruvaraj Subhashchandrane29be412018-01-16 05:11:56 -0600629 {
Vernon Maueryf038dc02023-07-27 14:06:11 -0700630 case DCMICapParameters::SupportedDcmiCaps:
Dhruvaraj Subhashchandrane29be412018-01-16 05:11:56 -0600631 {
Vernon Maueryf038dc02023-07-27 14:06:11 -0700632 bool powerManagement = data.value("PowerManagement", 0);
633 bool oobSecondaryLan = data.value("OOBSecondaryLan", 0);
634 bool serialTMode = data.value("SerialTMODE", 0);
635 bool inBandSystemInterfaceChannel =
636 data.value("InBandSystemInterfaceChannel", 0);
637 payload.pack(reserved8, powerManagement, reserved7,
638 inBandSystemInterfaceChannel, serialTMode,
639 oobSecondaryLan, reserved5);
640 break;
Dhruvaraj Subhashchandrane29be412018-01-16 05:11:56 -0600641 }
Vernon Maueryf038dc02023-07-27 14:06:11 -0700642 // Mandatory Platform Attributes
643 case DCMICapParameters::MandatoryPlatAttributes:
Dhruvaraj Subhashchandrane29be412018-01-16 05:11:56 -0600644 {
Vernon Maueryf038dc02023-07-27 14:06:11 -0700645 bool selAutoRollOver = data.value("SELAutoRollOver", 0);
646 bool flushEntireSELUponRollOver =
647 data.value("FlushEntireSELUponRollOver", 0);
648 bool recordLevelSELFlushUponRollOver =
649 data.value("RecordLevelSELFlushUponRollOver", 0);
650 uint12_t numberOfSELEntries = data.value("NumberOfSELEntries",
651 0xcac);
652 uint8_t tempMonitoringSamplingFreq =
653 data.value("TempMonitoringSamplingFreq", 0);
654 payload.pack(numberOfSELEntries, reserved1,
655 recordLevelSELFlushUponRollOver,
656 flushEntireSELUponRollOver, selAutoRollOver,
657 reserved16, tempMonitoringSamplingFreq);
658 break;
659 }
660 // Optional Platform Attributes
661 case DCMICapParameters::OptionalPlatAttributes:
662 {
663 uint7_t powerMgmtDeviceSlaveAddress =
664 data.value("PowerMgmtDeviceSlaveAddress", 0);
665 uint4_t bmcChannelNumber = data.value("BMCChannelNumber", 0);
666 uint4_t deviceRivision = data.value("DeviceRivision", 0);
667 payload.pack(powerMgmtDeviceSlaveAddress, reserved1, deviceRivision,
668 bmcChannelNumber);
669 break;
670 }
671 // Manageability Access Attributes
672 case DCMICapParameters::ManageabilityAccessAttributes:
673 {
674 uint8_t mandatoryPrimaryLanOOBSupport =
675 data.value("MandatoryPrimaryLanOOBSupport", 0xff);
676 uint8_t optionalSecondaryLanOOBSupport =
677 data.value("OptionalSecondaryLanOOBSupport", 0xff);
678 uint8_t optionalSerialOOBMTMODECapability =
679 data.value("OptionalSerialOOBMTMODECapability", 0xff);
680 payload.pack(mandatoryPrimaryLanOOBSupport,
681 optionalSecondaryLanOOBSupport,
682 optionalSerialOOBMTMODECapability);
683 break;
684 }
685 default:
686 {
687 log<level::ERR>("Invalid input parameter");
688 return ipmi::responseInvalidFieldRequest();
Dhruvaraj Subhashchandrane29be412018-01-16 05:11:56 -0600689 }
690 }
691
Vernon Maueryf038dc02023-07-27 14:06:11 -0700692 return ipmi::responseSuccess(payload);
Dhruvaraj Subhashchandrane29be412018-01-16 05:11:56 -0600693}
694
Deepak Kodihalliee717d72018-01-24 04:53:09 -0600695namespace dcmi
696{
697namespace temp_readings
698{
699
Vernon Mauerycce9ffd2023-07-27 14:15:17 -0700700std::tuple<bool, bool, uint8_t> readTemp(ipmi::Context::ptr& ctx,
701 const std::string& dbusService,
702 const std::string& dbusPath)
Deepak Kodihallib1e8fba2018-01-24 04:57:10 -0600703{
704 // Read the temperature value from d-bus object. Need some conversion.
Vernon Mauerycce9ffd2023-07-27 14:15:17 -0700705 // As per the interface xyz.openbmc_project.Sensor.Value, the
706 // temperature is an double and in degrees C. It needs to be scaled by
707 // using the formula Value * 10^Scale. The ipmi spec has the temperature
708 // as a uint8_t, with a separate single bit for the sign.
Deepak Kodihallib1e8fba2018-01-24 04:57:10 -0600709
Vernon Mauerycce9ffd2023-07-27 14:15:17 -0700710 ipmi::PropertyMap result{};
711 boost::system::error_code ec = ipmi::getAllDbusProperties(
712 ctx, dbusService, dbusPath, "xyz.openbmc_project.Sensor.Value", result);
713 if (ec.value())
714 {
715 return std::make_tuple(false, false, 0);
716 }
Patrick Williamsfbc6c9d2023-05-10 07:50:16 -0500717 auto temperature = std::visit(ipmi::VariantToDoubleVisitor(),
718 result.at("Value"));
James Feist9cc0ea52018-10-09 10:53:11 -0700719 double absTemp = std::abs(temperature);
Deepak Kodihallib1e8fba2018-01-24 04:57:10 -0600720
James Feist9cc0ea52018-10-09 10:53:11 -0700721 auto findFactor = result.find("Scale");
722 double factor = 0.0;
723 if (findFactor != result.end())
Deepak Kodihallib1e8fba2018-01-24 04:57:10 -0600724 {
Vernon Maueryf442e112019-04-09 11:44:36 -0700725 factor = std::visit(ipmi::VariantToDoubleVisitor(), findFactor->second);
Deepak Kodihallib1e8fba2018-01-24 04:57:10 -0600726 }
James Feist9cc0ea52018-10-09 10:53:11 -0700727 double scale = std::pow(10, factor);
728
729 auto tempDegrees = absTemp * scale;
Vernon Mauerycce9ffd2023-07-27 14:15:17 -0700730 // Max absolute temp as per ipmi spec is 127.
731 constexpr auto maxTemp = 127;
Deepak Kodihallib1e8fba2018-01-24 04:57:10 -0600732 if (tempDegrees > maxTemp)
733 {
734 tempDegrees = maxTemp;
735 }
736
Vernon Mauerycce9ffd2023-07-27 14:15:17 -0700737 return std::make_tuple(true, (temperature < 0),
738 static_cast<uint8_t>(tempDegrees));
Deepak Kodihallib1e8fba2018-01-24 04:57:10 -0600739}
740
Vernon Mauerycce9ffd2023-07-27 14:15:17 -0700741std::tuple<std::vector<std::tuple<uint7_t, bool, uint8_t>>, uint8_t>
742 read(ipmi::Context::ptr& ctx, const std::string& type, uint8_t instance,
743 size_t count)
Deepak Kodihalliee717d72018-01-24 04:53:09 -0600744{
Vernon Mauerycce9ffd2023-07-27 14:15:17 -0700745 std::vector<std::tuple<uint7_t, bool, uint8_t>> response{};
Deepak Kodihallib1e8fba2018-01-24 04:57:10 -0600746
Kirill Pakhomova2573622018-11-02 19:00:18 +0300747 auto data = parseJSONConfig(gDCMISensorsConfig);
Vernon Mauerycce9ffd2023-07-27 14:15:17 -0700748 static const std::vector<nlohmann::json> empty{};
749 std::vector<nlohmann::json> readings = data.value(type, empty);
Deepak Kodihallib1e8fba2018-01-24 04:57:10 -0600750 for (const auto& j : readings)
751 {
Vernon Mauerycce9ffd2023-07-27 14:15:17 -0700752 // Max of 8 response data sets
753 if (response.size() == count)
754 {
755 break;
756 }
757
Deepak Kodihallib1e8fba2018-01-24 04:57:10 -0600758 uint8_t instanceNum = j.value("instance", 0);
Vernon Mauerycce9ffd2023-07-27 14:15:17 -0700759 // Not in the instance range we're interested in
760 if (instanceNum < instance)
Deepak Kodihallib1e8fba2018-01-24 04:57:10 -0600761 {
762 continue;
763 }
764
765 std::string path = j.value("dbus", "");
Vernon Mauerycce9ffd2023-07-27 14:15:17 -0700766 std::string service{};
767 boost::system::error_code ec = ipmi::getService(
768 ctx, "xyz.openbmc_project.Sensor.Value", path, service);
769 if (ec.value())
Deepak Kodihallib1e8fba2018-01-24 04:57:10 -0600770 {
Vernon Mauerycce9ffd2023-07-27 14:15:17 -0700771 // not found on dbus
Deepak Kodihallib1e8fba2018-01-24 04:57:10 -0600772 continue;
773 }
Vernon Mauerycce9ffd2023-07-27 14:15:17 -0700774
775 const auto& [ok, sign, temp] = readTemp(ctx, service, path);
776 if (ok)
777 {
778 response.emplace_back(uint7_t{temp}, sign, instanceNum);
779 }
Deepak Kodihallib1e8fba2018-01-24 04:57:10 -0600780 }
781
Vernon Mauerycce9ffd2023-07-27 14:15:17 -0700782 auto totalInstances =
783 static_cast<uint8_t>(std::min(readings.size(), maxInstances));
784 return std::make_tuple(response, totalInstances);
Deepak Kodihalliee717d72018-01-24 04:53:09 -0600785}
786
Patrick Venture0b02be92018-08-31 11:55:55 -0700787} // namespace temp_readings
788} // namespace dcmi
Deepak Kodihalliee717d72018-01-24 04:53:09 -0600789
Vernon Mauerycce9ffd2023-07-27 14:15:17 -0700790ipmi::RspType<uint8_t, // total instances for entity id
791 uint8_t, // number of instances in this reply
792 std::vector< // zero or more of the following two bytes
793 std::tuple<uint7_t, // temperature value
794 bool, // sign bit
795 uint8_t // entity instance
796 >>>
797 getTempReadings(ipmi::Context::ptr& ctx, uint8_t sensorType,
798 uint8_t entityId, uint8_t entityInstance,
799 uint8_t instanceStart)
Deepak Kodihalliee717d72018-01-24 04:53:09 -0600800{
Vernon Mauerycce9ffd2023-07-27 14:15:17 -0700801 auto it = dcmi::entityIdToName.find(entityId);
Deepak Kodihalli0b459552018-02-06 06:25:12 -0600802 if (it == dcmi::entityIdToName.end())
Deepak Kodihalliee717d72018-01-24 04:53:09 -0600803 {
Vernon Mauerycce9ffd2023-07-27 14:15:17 -0700804 log<level::ERR>("Unknown Entity ID", entry("ENTITY_ID=%d", entityId));
805 return ipmi::responseInvalidFieldRequest();
Deepak Kodihalliee717d72018-01-24 04:53:09 -0600806 }
807
Vernon Mauerycce9ffd2023-07-27 14:15:17 -0700808 if (sensorType != dcmi::temperatureSensorType)
Deepak Kodihalliee717d72018-01-24 04:53:09 -0600809 {
810 log<level::ERR>("Invalid sensor type",
Vernon Mauerycce9ffd2023-07-27 14:15:17 -0700811 entry("SENSOR_TYPE=%d", sensorType));
812 return ipmi::responseInvalidFieldRequest();
Deepak Kodihalliee717d72018-01-24 04:53:09 -0600813 }
814
Vernon Mauerycce9ffd2023-07-27 14:15:17 -0700815 uint8_t requestedRecords = (entityInstance == 0) ? dcmi::maxRecords : 1;
Deepak Kodihalliee717d72018-01-24 04:53:09 -0600816
Vernon Mauerycce9ffd2023-07-27 14:15:17 -0700817 // Read requested instances
818 const auto& [temps, totalInstances] = dcmi::temp_readings::read(
819 ctx, it->second, instanceStart, requestedRecords);
Deepak Kodihalliee717d72018-01-24 04:53:09 -0600820
Vernon Mauerycce9ffd2023-07-27 14:15:17 -0700821 auto numInstances = static_cast<uint8_t>(temps.size());
822
823 return ipmi::responseSuccess(totalInstances, numInstances, temps);
Deepak Kodihalliee717d72018-01-24 04:53:09 -0600824}
825
Patrick Williams5d82f472022-07-22 19:26:53 -0500826int64_t getPowerReading(sdbusplus::bus_t& bus)
Marri Devender Rao66c5fda2018-01-18 10:48:37 -0600827{
828 std::ifstream sensorFile(POWER_READING_SENSOR);
829 std::string objectPath;
830 if (!sensorFile.is_open())
831 {
832 log<level::ERR>("Power reading configuration file not found",
Patrick Venture0b02be92018-08-31 11:55:55 -0700833 entry("POWER_SENSOR_FILE=%s", POWER_READING_SENSOR));
Marri Devender Rao66c5fda2018-01-18 10:48:37 -0600834 elog<InternalFailure>();
835 }
836
837 auto data = nlohmann::json::parse(sensorFile, nullptr, false);
838 if (data.is_discarded())
839 {
840 log<level::ERR>("Error in parsing configuration file",
Patrick Venture0b02be92018-08-31 11:55:55 -0700841 entry("POWER_SENSOR_FILE=%s", POWER_READING_SENSOR));
Marri Devender Rao66c5fda2018-01-18 10:48:37 -0600842 elog<InternalFailure>();
843 }
844
845 objectPath = data.value("path", "");
846 if (objectPath.empty())
847 {
848 log<level::ERR>("Power sensor D-Bus object path is empty",
849 entry("POWER_SENSOR_FILE=%s", POWER_READING_SENSOR));
850 elog<InternalFailure>();
851 }
852
Marri Devender Raoce6a7952018-02-11 08:45:00 -0600853 // Return default value if failed to read from D-Bus object
854 int64_t power = 0;
855 try
856 {
857 auto service = ipmi::getService(bus, SENSOR_VALUE_INTF, objectPath);
Marri Devender Rao66c5fda2018-01-18 10:48:37 -0600858
Patrick Venture0b02be92018-08-31 11:55:55 -0700859 // Read the sensor value and scale properties
Chris Cain4cc61e02022-01-12 17:23:14 -0600860 auto value = ipmi::getDbusProperty(
861 bus, service, objectPath, SENSOR_VALUE_INTF, SENSOR_VALUE_PROP);
862 power = std::get<double>(value);
Marri Devender Raoce6a7952018-02-11 08:45:00 -0600863 }
Patrick Williamsa2ad2da2021-10-06 12:21:46 -0500864 catch (const std::exception& e)
Marri Devender Raoce6a7952018-02-11 08:45:00 -0600865 {
Chris Cain4cc61e02022-01-12 17:23:14 -0600866 log<level::ERR>("Failure to read power value from D-Bus object",
867 entry("OBJECT_PATH=%s", objectPath.c_str()),
868 entry("INTERFACE=%s", SENSOR_VALUE_INTF));
Marri Devender Raoce6a7952018-02-11 08:45:00 -0600869 }
Marri Devender Rao66c5fda2018-01-18 10:48:37 -0600870 return power;
871}
872
Willy Tu11d68892022-01-20 10:37:34 -0800873ipmi_ret_t setDCMIConfParams(ipmi_netfn_t, ipmi_cmd_t, ipmi_request_t request,
874 ipmi_response_t, ipmi_data_len_t data_len,
875 ipmi_context_t)
Nagaraju Goruganti22be97b2018-02-07 01:19:59 -0600876{
Patrick Venture0b02be92018-08-31 11:55:55 -0700877 auto requestData =
878 reinterpret_cast<const dcmi::SetConfParamsRequest*>(request);
Nagaraju Goruganti22be97b2018-02-07 01:19:59 -0600879
William A. Kennington III5d06cc62019-04-25 02:10:55 -0700880 if (*data_len < DCMI_SET_CONF_PARAM_REQ_PACKET_MIN_SIZE ||
Patrick Venture0b02be92018-08-31 11:55:55 -0700881 *data_len > DCMI_SET_CONF_PARAM_REQ_PACKET_MAX_SIZE)
Nagaraju Goruganti22be97b2018-02-07 01:19:59 -0600882 {
William A. Kennington III5d06cc62019-04-25 02:10:55 -0700883 log<level::ERR>("Invalid Requested Packet size",
Nagaraju Goruganti22be97b2018-02-07 01:19:59 -0600884 entry("PACKET SIZE=%d", *data_len));
William A. Kennington III5d06cc62019-04-25 02:10:55 -0700885 *data_len = 0;
Nagaraju Goruganti22be97b2018-02-07 01:19:59 -0600886 return IPMI_CC_INVALID_FIELD_REQUEST;
887 }
Nagaraju Goruganti22be97b2018-02-07 01:19:59 -0600888 *data_len = 0;
889
890 try
891 {
892 // Take action based on the Parameter Selector
Patrick Venture0b02be92018-08-31 11:55:55 -0700893 switch (
894 static_cast<dcmi::DCMIConfigParameters>(requestData->paramSelect))
Nagaraju Goruganti22be97b2018-02-07 01:19:59 -0600895 {
896 case dcmi::DCMIConfigParameters::ActivateDHCP:
897
898 if ((requestData->data[0] & DCMI_ACTIVATE_DHCP_MASK) &&
Thang Tran55cbf552023-01-31 14:43:02 +0700899 (dcmi::getDHCPEnabled() !=
900 EthernetInterface::DHCPConf::none))
Nagaraju Goruganti22be97b2018-02-07 01:19:59 -0600901 {
Patrick Venture0b02be92018-08-31 11:55:55 -0700902 // When these conditions are met we have to trigger DHCP
903 // protocol restart using the latest parameter settings, but
904 // as per n/w manager design, each time when we update n/w
905 // parameters, n/w service is restarted. So we no need to
906 // take any action in this case.
Nagaraju Goruganti22be97b2018-02-07 01:19:59 -0600907 }
908 break;
909
910 case dcmi::DCMIConfigParameters::DiscoveryConfig:
911
912 if (requestData->data[0] & DCMI_OPTION_12_MASK)
913 {
914 dcmi::setDHCPOption(DHCP_OPT12_ENABLED, true);
915 }
916 else
917 {
918 dcmi::setDHCPOption(DHCP_OPT12_ENABLED, false);
919 }
920
921 // Systemd-networkd doesn't support Random Back off
922 if (requestData->data[0] & DCMI_RAND_BACK_OFF_MASK)
923 {
924 return IPMI_CC_INVALID;
925 }
926 break;
927 // Systemd-networkd doesn't allow to configure DHCP timigs
928 case dcmi::DCMIConfigParameters::DHCPTiming1:
929 case dcmi::DCMIConfigParameters::DHCPTiming2:
930 case dcmi::DCMIConfigParameters::DHCPTiming3:
931 default:
932 return IPMI_CC_INVALID;
933 }
934 }
Patrick Williamsa2ad2da2021-10-06 12:21:46 -0500935 catch (const std::exception& e)
Nagaraju Goruganti22be97b2018-02-07 01:19:59 -0600936 {
937 log<level::ERR>(e.what());
938 return IPMI_CC_UNSPECIFIED_ERROR;
939 }
Nagaraju Goruganti22be97b2018-02-07 01:19:59 -0600940 return IPMI_CC_OK;
941}
942
Willy Tu11d68892022-01-20 10:37:34 -0800943ipmi_ret_t getDCMIConfParams(ipmi_netfn_t, ipmi_cmd_t, ipmi_request_t request,
944 ipmi_response_t response, ipmi_data_len_t data_len,
945 ipmi_context_t)
Nagaraju Goruganti22be97b2018-02-07 01:19:59 -0600946{
Patrick Venture0b02be92018-08-31 11:55:55 -0700947 auto requestData =
948 reinterpret_cast<const dcmi::GetConfParamsRequest*>(request);
949 auto responseData =
950 reinterpret_cast<dcmi::GetConfParamsResponse*>(response);
Nagaraju Goruganti22be97b2018-02-07 01:19:59 -0600951
952 responseData->data[0] = 0x00;
953
William A. Kennington III5d06cc62019-04-25 02:10:55 -0700954 if (*data_len != sizeof(dcmi::GetConfParamsRequest))
Nagaraju Goruganti22be97b2018-02-07 01:19:59 -0600955 {
William A. Kennington III5d06cc62019-04-25 02:10:55 -0700956 log<level::ERR>("Invalid Requested Packet size",
Nagaraju Goruganti22be97b2018-02-07 01:19:59 -0600957 entry("PACKET SIZE=%d", *data_len));
958 return IPMI_CC_INVALID_FIELD_REQUEST;
959 }
960
961 *data_len = 0;
962
963 try
964 {
965 // Take action based on the Parameter Selector
Patrick Venture0b02be92018-08-31 11:55:55 -0700966 switch (
967 static_cast<dcmi::DCMIConfigParameters>(requestData->paramSelect))
Nagaraju Goruganti22be97b2018-02-07 01:19:59 -0600968 {
969 case dcmi::DCMIConfigParameters::ActivateDHCP:
970 responseData->data[0] = DCMI_ACTIVATE_DHCP_REPLY;
971 *data_len = sizeof(dcmi::GetConfParamsResponse) + 1;
972 break;
973 case dcmi::DCMIConfigParameters::DiscoveryConfig:
974 if (dcmi::getDHCPOption(DHCP_OPT12_ENABLED))
975 {
976 responseData->data[0] |= DCMI_OPTION_12_MASK;
977 }
978 *data_len = sizeof(dcmi::GetConfParamsResponse) + 1;
979 break;
980 // Get below values from Systemd-networkd source code
981 case dcmi::DCMIConfigParameters::DHCPTiming1:
982 responseData->data[0] = DHCP_TIMING1;
983 *data_len = sizeof(dcmi::GetConfParamsResponse) + 1;
984 break;
985 case dcmi::DCMIConfigParameters::DHCPTiming2:
986 responseData->data[0] = DHCP_TIMING2_LOWER;
987 responseData->data[1] = DHCP_TIMING2_UPPER;
988 *data_len = sizeof(dcmi::GetConfParamsResponse) + 2;
989 break;
990 case dcmi::DCMIConfigParameters::DHCPTiming3:
991 responseData->data[0] = DHCP_TIMING3_LOWER;
992 responseData->data[1] = DHCP_TIMING3_UPPER;
993 *data_len = sizeof(dcmi::GetConfParamsResponse) + 2;
994 break;
995 default:
996 *data_len = 0;
997 return IPMI_CC_INVALID;
998 }
999 }
Patrick Williamsa2ad2da2021-10-06 12:21:46 -05001000 catch (const std::exception& e)
Nagaraju Goruganti22be97b2018-02-07 01:19:59 -06001001 {
1002 log<level::ERR>(e.what());
1003 return IPMI_CC_UNSPECIFIED_ERROR;
1004 }
1005
Nagaraju Goruganti22be97b2018-02-07 01:19:59 -06001006 responseData->major = DCMI_SPEC_MAJOR_VERSION;
1007 responseData->minor = DCMI_SPEC_MINOR_VERSION;
1008 responseData->paramRevision = DCMI_CONFIG_PARAMETER_REVISION;
1009
1010 return IPMI_CC_OK;
1011}
1012
Willy Tu11d68892022-01-20 10:37:34 -08001013ipmi_ret_t getPowerReading(ipmi_netfn_t, ipmi_cmd_t, ipmi_request_t,
1014 ipmi_response_t response, ipmi_data_len_t data_len,
1015 ipmi_context_t)
Marri Devender Rao66c5fda2018-01-18 10:48:37 -06001016{
Chalapathi Venkataramashetty90e81fa2021-05-11 09:13:23 +00001017 *data_len = 0;
Kirill Pakhomov2c2af2c2018-11-06 16:06:10 +03001018 if (!dcmi::isDCMIPowerMgmtSupported())
1019 {
Kirill Pakhomov2c2af2c2018-11-06 16:06:10 +03001020 log<level::ERR>("DCMI Power management is unsupported!");
1021 return IPMI_CC_INVALID;
1022 }
1023
Marri Devender Rao66c5fda2018-01-18 10:48:37 -06001024 ipmi_ret_t rc = IPMI_CC_OK;
Patrick Venture0b02be92018-08-31 11:55:55 -07001025 auto responseData =
1026 reinterpret_cast<dcmi::GetPowerReadingResponse*>(response);
Marri Devender Rao9c966e02018-01-22 05:55:10 -06001027
Patrick Williams5d82f472022-07-22 19:26:53 -05001028 sdbusplus::bus_t bus{ipmid_get_sd_bus_connection()};
Marri Devender Rao9c966e02018-01-22 05:55:10 -06001029 int64_t power = 0;
Marri Devender Rao66c5fda2018-01-18 10:48:37 -06001030 try
1031 {
Marri Devender Rao9c966e02018-01-22 05:55:10 -06001032 power = getPowerReading(bus);
Marri Devender Rao66c5fda2018-01-18 10:48:37 -06001033 }
Patrick Williamsa2ad2da2021-10-06 12:21:46 -05001034 catch (const InternalFailure& e)
Marri Devender Rao66c5fda2018-01-18 10:48:37 -06001035 {
1036 log<level::ERR>("Error in reading power sensor value",
1037 entry("INTERFACE=%s", SENSOR_VALUE_INTF),
1038 entry("PROPERTY=%s", SENSOR_VALUE_PROP));
1039 return IPMI_CC_UNSPECIFIED_ERROR;
1040 }
Marri Devender Rao9c966e02018-01-22 05:55:10 -06001041
1042 // TODO: openbmc/openbmc#2819
Gunnar Mills8466b792018-03-23 12:18:12 -05001043 // Minimum, Maximum, Average power, TimeFrame, TimeStamp,
Marri Devender Rao9c966e02018-01-22 05:55:10 -06001044 // PowerReadingState readings need to be populated
1045 // after Telemetry changes.
1046 uint16_t totalPower = static_cast<uint16_t>(power);
1047 responseData->currentPower = totalPower;
1048 responseData->minimumPower = totalPower;
1049 responseData->maximumPower = totalPower;
1050 responseData->averagePower = totalPower;
1051
1052 *data_len = sizeof(*responseData);
Marri Devender Rao66c5fda2018-01-18 10:48:37 -06001053 return rc;
1054}
1055
Deepak Kodihalli0b459552018-02-06 06:25:12 -06001056namespace dcmi
1057{
1058namespace sensor_info
1059{
1060
Deepak Kodihallidd4cff12018-02-06 06:48:29 -06001061Response createFromJson(const Json& config)
1062{
1063 Response response{};
1064 uint16_t recordId = config.value("record_id", 0);
1065 response.recordIdLsb = recordId & 0xFF;
1066 response.recordIdMsb = (recordId >> 8) & 0xFF;
1067 return response;
1068}
1069
Deepak Kodihalli0b459552018-02-06 06:25:12 -06001070std::tuple<Response, NumInstances> read(const std::string& type,
Patrick Venture0b02be92018-08-31 11:55:55 -07001071 uint8_t instance, const Json& config)
Deepak Kodihalli0b459552018-02-06 06:25:12 -06001072{
Deepak Kodihallidd4cff12018-02-06 06:48:29 -06001073 Response response{};
1074
1075 if (!instance)
1076 {
1077 log<level::ERR>("Expected non-zero instance");
1078 elog<InternalFailure>();
1079 }
1080
1081 static const std::vector<Json> empty{};
1082 std::vector<Json> readings = config.value(type, empty);
1083 size_t numInstances = readings.size();
1084 for (const auto& reading : readings)
1085 {
1086 uint8_t instanceNum = reading.value("instance", 0);
1087 // Not the instance we're interested in
1088 if (instanceNum != instance)
1089 {
1090 continue;
1091 }
1092
1093 response = createFromJson(reading);
1094
1095 // Found the instance we're interested in
1096 break;
1097 }
1098
1099 if (numInstances > maxInstances)
1100 {
1101 log<level::DEBUG>("Trimming IPMI num instances",
1102 entry("NUM_INSTANCES=%d", numInstances));
1103 numInstances = maxInstances;
1104 }
1105 return std::make_tuple(response, numInstances);
Deepak Kodihalli0b459552018-02-06 06:25:12 -06001106}
1107
Patrick Venture0b02be92018-08-31 11:55:55 -07001108std::tuple<ResponseList, NumInstances>
1109 readAll(const std::string& type, uint8_t instanceStart, const Json& config)
Deepak Kodihalli0b459552018-02-06 06:25:12 -06001110{
Deepak Kodihallidd4cff12018-02-06 06:48:29 -06001111 ResponseList responses{};
1112
1113 size_t numInstances = 0;
1114 static const std::vector<Json> empty{};
1115 std::vector<Json> readings = config.value(type, empty);
1116 numInstances = readings.size();
1117 for (const auto& reading : readings)
1118 {
1119 try
1120 {
1121 // Max of 8 records
1122 if (responses.size() == maxRecords)
1123 {
1124 break;
1125 }
1126
1127 uint8_t instanceNum = reading.value("instance", 0);
1128 // Not in the instance range we're interested in
1129 if (instanceNum < instanceStart)
1130 {
1131 continue;
1132 }
1133
1134 Response response = createFromJson(reading);
1135 responses.push_back(response);
1136 }
Patrick Williamsa2ad2da2021-10-06 12:21:46 -05001137 catch (const std::exception& e)
Deepak Kodihallidd4cff12018-02-06 06:48:29 -06001138 {
1139 log<level::DEBUG>(e.what());
1140 continue;
1141 }
1142 }
1143
1144 if (numInstances > maxInstances)
1145 {
1146 log<level::DEBUG>("Trimming IPMI num instances",
1147 entry("NUM_INSTANCES=%d", numInstances));
1148 numInstances = maxInstances;
1149 }
1150 return std::make_tuple(responses, numInstances);
Deepak Kodihalli0b459552018-02-06 06:25:12 -06001151}
1152
1153} // namespace sensor_info
1154} // namespace dcmi
1155
Willy Tu11d68892022-01-20 10:37:34 -08001156ipmi_ret_t getSensorInfo(ipmi_netfn_t, ipmi_cmd_t, ipmi_request_t request,
1157 ipmi_response_t response, ipmi_data_len_t data_len,
1158 ipmi_context_t)
Deepak Kodihalli0b459552018-02-06 06:25:12 -06001159{
1160 auto requestData =
1161 reinterpret_cast<const dcmi::GetSensorInfoRequest*>(request);
1162 auto responseData =
1163 reinterpret_cast<dcmi::GetSensorInfoResponseHdr*>(response);
1164
1165 if (*data_len != sizeof(dcmi::GetSensorInfoRequest))
1166 {
1167 log<level::ERR>("Malformed request data",
1168 entry("DATA_SIZE=%d", *data_len));
1169 return IPMI_CC_REQ_DATA_LEN_INVALID;
1170 }
1171 *data_len = 0;
1172
1173 auto it = dcmi::entityIdToName.find(requestData->entityId);
1174 if (it == dcmi::entityIdToName.end())
1175 {
1176 log<level::ERR>("Unknown Entity ID",
1177 entry("ENTITY_ID=%d", requestData->entityId));
1178 return IPMI_CC_INVALID_FIELD_REQUEST;
1179 }
1180
Deepak Kodihalli0b459552018-02-06 06:25:12 -06001181 if (requestData->sensorType != dcmi::temperatureSensorType)
1182 {
1183 log<level::ERR>("Invalid sensor type",
1184 entry("SENSOR_TYPE=%d", requestData->sensorType));
1185 return IPMI_CC_INVALID_FIELD_REQUEST;
1186 }
1187
1188 dcmi::sensor_info::ResponseList sensors{};
1189 static dcmi::Json config{};
1190 static bool parsed = false;
1191
1192 try
1193 {
1194 if (!parsed)
1195 {
Kirill Pakhomova2573622018-11-02 19:00:18 +03001196 config = dcmi::parseJSONConfig(dcmi::gDCMISensorsConfig);
Deepak Kodihalli0b459552018-02-06 06:25:12 -06001197 parsed = true;
1198 }
1199
1200 if (!requestData->entityInstance)
1201 {
1202 // Read all instances
1203 std::tie(sensors, responseData->numInstances) =
1204 dcmi::sensor_info::readAll(it->second,
Patrick Venture0b02be92018-08-31 11:55:55 -07001205 requestData->instanceStart, config);
Deepak Kodihalli0b459552018-02-06 06:25:12 -06001206 }
1207 else
1208 {
1209 // Read one instance
1210 sensors.resize(1);
1211 std::tie(sensors[0], responseData->numInstances) =
Patrick Venture0b02be92018-08-31 11:55:55 -07001212 dcmi::sensor_info::read(it->second, requestData->entityInstance,
Deepak Kodihalli0b459552018-02-06 06:25:12 -06001213 config);
1214 }
1215 responseData->numRecords = sensors.size();
1216 }
Patrick Williamsa2ad2da2021-10-06 12:21:46 -05001217 catch (const InternalFailure& e)
Deepak Kodihalli0b459552018-02-06 06:25:12 -06001218 {
1219 return IPMI_CC_UNSPECIFIED_ERROR;
1220 }
1221
Deepak Kodihalli0b459552018-02-06 06:25:12 -06001222 size_t payloadSize = sensors.size() * sizeof(dcmi::sensor_info::Response);
1223 if (!sensors.empty())
1224 {
1225 memcpy(responseData + 1, // copy payload right after the response header
Patrick Venture0b02be92018-08-31 11:55:55 -07001226 sensors.data(), payloadSize);
Deepak Kodihalli0b459552018-02-06 06:25:12 -06001227 }
1228 *data_len = sizeof(dcmi::GetSensorInfoResponseHdr) + payloadSize;
1229
1230 return IPMI_CC_OK;
1231}
1232
Chris Austen1810bec2015-10-13 12:12:39 -05001233void register_netfn_dcmi_functions()
1234{
Tom05732372016-09-06 17:21:23 +05301235 // <Get Power Limit>
Vernon Maueryd4222fd2023-07-27 11:26:51 -07001236 registerGroupHandler(ipmi::prioOpenBmcBase, ipmi::groupDCMI,
1237 ipmi::dcmi::cmdGetPowerLimit, ipmi::Privilege::User,
1238 getPowerLimit);
Tom Joseph6f6dd4d2017-07-12 20:07:11 +05301239
Tom Joseph46fa37d2017-07-26 18:11:55 +05301240 // <Set Power Limit>
Vernon Maueryd4222fd2023-07-27 11:26:51 -07001241 registerGroupHandler(ipmi::prioOpenBmcBase, ipmi::groupDCMI,
1242 ipmi::dcmi::cmdSetPowerLimit,
1243 ipmi::Privilege::Operator, setPowerLimit);
Tom Joseph46fa37d2017-07-26 18:11:55 +05301244
Tom Joseph6c8d51b2017-07-26 18:18:06 +05301245 // <Activate/Deactivate Power Limit>
Vernon Maueryd4222fd2023-07-27 11:26:51 -07001246 registerGroupHandler(ipmi::prioOpenBmcBase, ipmi::groupDCMI,
1247 ipmi::dcmi::cmdActDeactivatePwrLimit,
1248 ipmi::Privilege::Operator, applyPowerLimit);
Tom Joseph6c8d51b2017-07-26 18:18:06 +05301249
Tom Joseph6f6dd4d2017-07-12 20:07:11 +05301250 // <Get Asset Tag>
Vernon Mauerydca47202023-07-27 11:32:01 -07001251 registerGroupHandler(ipmi::prioOpenBmcBase, ipmi::groupDCMI,
1252 ipmi::dcmi::cmdGetAssetTag, ipmi::Privilege::User,
1253 getAssetTag);
Tom Joseph545dd232017-07-12 20:20:49 +05301254
1255 // <Set Asset Tag>
Vernon Mauerydca47202023-07-27 11:32:01 -07001256 registerGroupHandler(ipmi::prioOpenBmcBase, ipmi::groupDCMI,
1257 ipmi::dcmi::cmdSetAssetTag, ipmi::Privilege::Operator,
1258 setAssetTag);
Vladislav Vovchenko8f7a6f62017-08-17 00:31:14 +03001259
Gunnar Mills8991dd62017-10-25 17:11:29 -05001260 // <Get Management Controller Identifier String>
Vernon Maueryefb5ae52023-07-27 11:35:43 -07001261 registerGroupHandler(ipmi::prioOpenBmcBase, ipmi::groupDCMI,
1262 ipmi::dcmi::cmdGetMgmtCntlrIdString,
1263 ipmi::Privilege::User, getMgmntCtrlIdStr);
Vladislav Vovchenko8f7a6f62017-08-17 00:31:14 +03001264
1265 // <Set Management Controller Identifier String>
Vernon Maueryefb5ae52023-07-27 11:35:43 -07001266 registerGroupHandler(ipmi::prioOpenBmcBase, ipmi::groupDCMI,
1267 ipmi::dcmi::cmdSetMgmtCntlrIdString,
1268 ipmi::Privilege::Admin, setMgmntCtrlIdStr);
Vladislav Vovchenko8f7a6f62017-08-17 00:31:14 +03001269
Dhruvaraj Subhashchandrane29be412018-01-16 05:11:56 -06001270 // <Get DCMI capabilities>
Vernon Maueryf038dc02023-07-27 14:06:11 -07001271 registerGroupHandler(ipmi::prioOpenBmcBase, ipmi::groupDCMI,
1272 ipmi::dcmi::cmdGetDcmiCapabilitiesInfo,
1273 ipmi::Privilege::User, getDCMICapabilities);
Deepak Kodihalliee717d72018-01-24 04:53:09 -06001274
1275 // <Get Temperature Readings>
Vernon Mauerycce9ffd2023-07-27 14:15:17 -07001276 registerGroupHandler(ipmi::prioOpenBmcBase, ipmi::groupDCMI,
1277 ipmi::dcmi::cmdGetTemperatureReadings,
1278 ipmi::Privilege::User, getTempReadings);
Deepak Kodihalliee717d72018-01-24 04:53:09 -06001279
Marri Devender Rao66c5fda2018-01-18 10:48:37 -06001280 // <Get Power Reading>
1281 ipmi_register_callback(NETFUN_GRPEXT, dcmi::Commands::GET_POWER_READING,
1282 NULL, getPowerReading, PRIVILEGE_USER);
adarshgrami042e9db2022-09-15 10:34:34 +05301283// The Get sensor should get the senor details dynamically when
1284// FEATURE_DYNAMIC_SENSORS is enabled.
1285#ifndef FEATURE_DYNAMIC_SENSORS
Deepak Kodihalli0b459552018-02-06 06:25:12 -06001286 // <Get Sensor Info>
Patrick Venture0b02be92018-08-31 11:55:55 -07001287 ipmi_register_callback(NETFUN_GRPEXT, dcmi::Commands::GET_SENSOR_INFO, NULL,
Chau Lyd74df5f2023-05-25 10:33:00 +00001288 getSensorInfo, PRIVILEGE_OPERATOR);
adarshgrami042e9db2022-09-15 10:34:34 +05301289#endif
Nagaraju Goruganti22be97b2018-02-07 01:19:59 -06001290 // <Get DCMI Configuration Parameters>
Patrick Venture0b02be92018-08-31 11:55:55 -07001291 ipmi_register_callback(NETFUN_GRPEXT, dcmi::Commands::GET_CONF_PARAMS, NULL,
1292 getDCMIConfParams, PRIVILEGE_USER);
Nagaraju Goruganti22be97b2018-02-07 01:19:59 -06001293
1294 // <Set DCMI Configuration Parameters>
Patrick Venture0b02be92018-08-31 11:55:55 -07001295 ipmi_register_callback(NETFUN_GRPEXT, dcmi::Commands::SET_CONF_PARAMS, NULL,
1296 setDCMIConfParams, PRIVILEGE_ADMIN);
Nagaraju Goruganti22be97b2018-02-07 01:19:59 -06001297
Chris Austen1810bec2015-10-13 12:12:39 -05001298 return;
1299}
Tom05732372016-09-06 17:21:23 +05301300// 956379