blob: 2e626a3606c0059d343547c5a06e874500ba570e [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
Andrew Geissler50c0c8f2017-07-11 16:18:51 -050055using namespace phosphor::logging;
56
Tom Josephb9d86f42017-07-26 18:03:47 +053057namespace dcmi
58{
Vernon Mauerydca47202023-07-27 11:32:01 -070059constexpr auto assetTagMaxOffset = 62;
60constexpr auto assetTagMaxSize = 63;
61constexpr auto maxBytes = 16;
62constexpr size_t maxCtrlIdStrLen = 63;
Tom Josephb9d86f42017-07-26 18:03:47 +053063
Vernon Maueryf038dc02023-07-27 14:06:11 -070064constexpr uint8_t parameterRevision = 2;
65constexpr uint8_t specMajorVersion = 1;
66constexpr uint8_t specMinorVersion = 5;
Vernon Mauerycce9ffd2023-07-27 14:15:17 -070067constexpr auto sensorValueIntf = "xyz.openbmc_project.Sensor.Value";
68constexpr auto sensorValueProp = "Value";
Vernon Maueryf038dc02023-07-27 14:06:11 -070069
Deepak Kodihalli0b459552018-02-06 06:25:12 -060070// Refer Table 6-14, DCMI Entity ID Extension, DCMI v1.5 spec
Patrick Venture0b02be92018-08-31 11:55:55 -070071static const std::map<uint8_t, std::string> entityIdToName{
72 {0x40, "inlet"}, {0x37, "inlet"}, {0x41, "cpu"},
73 {0x03, "cpu"}, {0x42, "baseboard"}, {0x07, "baseboard"}};
Deepak Kodihalli0b459552018-02-06 06:25:12 -060074
Kirill Pakhomov2c2af2c2018-11-06 16:06:10 +030075bool isDCMIPowerMgmtSupported()
76{
Vernon Maueryf4eb35d2023-07-27 11:08:49 -070077 static bool parsed = false;
78 static bool supported = false;
79 if (!parsed)
80 {
81 auto data = parseJSONConfig(gDCMICapabilitiesConfig);
Kirill Pakhomov2c2af2c2018-11-06 16:06:10 +030082
Vernon Maueryf4eb35d2023-07-27 11:08:49 -070083 supported = (gDCMIPowerMgmtSupported ==
84 data.value(gDCMIPowerMgmtCapability, 0));
85 }
86 return supported;
Kirill Pakhomov2c2af2c2018-11-06 16:06:10 +030087}
88
Vernon Maueryd4222fd2023-07-27 11:26:51 -070089std::optional<uint32_t> getPcap(ipmi::Context::ptr& ctx)
Andrew Geissler50c0c8f2017-07-11 16:18:51 -050090{
Vernon Maueryd4222fd2023-07-27 11:26:51 -070091 std::string service{};
92 boost::system::error_code ec = ipmi::getService(ctx, pcapInterface,
93 pcapPath, service);
94 if (ec.value())
Andrew Geissler50c0c8f2017-07-11 16:18:51 -050095 {
Vernon Maueryd4222fd2023-07-27 11:26:51 -070096 return std::nullopt;
George Liu3e3cc352023-07-26 15:59:31 +080097 }
Vernon Maueryd4222fd2023-07-27 11:26:51 -070098 uint32_t pcap{};
99 ec = ipmi::getDbusProperty(ctx, service, pcapPath, pcapInterface,
100 powerCapProp, pcap);
101 if (ec.value())
George Liu3e3cc352023-07-26 15:59:31 +0800102 {
Vernon Maueryd4222fd2023-07-27 11:26:51 -0700103 log<level::ERR>("Error in getPcap prop",
104 entry("ERROR=%s", ec.message().c_str()));
Tom Josephb9d86f42017-07-26 18:03:47 +0530105 elog<InternalFailure>();
Vernon Maueryd4222fd2023-07-27 11:26:51 -0700106 return std::nullopt;
Andrew Geissler50c0c8f2017-07-11 16:18:51 -0500107 }
Vernon Maueryd4222fd2023-07-27 11:26:51 -0700108 return pcap;
Andrew Geissler50c0c8f2017-07-11 16:18:51 -0500109}
110
Vernon Maueryd4222fd2023-07-27 11:26:51 -0700111std::optional<bool> getPcapEnabled(ipmi::Context::ptr& ctx)
Andrew Geissler50c0c8f2017-07-11 16:18:51 -0500112{
Vernon Maueryd4222fd2023-07-27 11:26:51 -0700113 std::string service{};
114 boost::system::error_code ec = ipmi::getService(ctx, pcapInterface,
115 pcapPath, service);
116 if (ec.value())
Andrew Geissler50c0c8f2017-07-11 16:18:51 -0500117 {
Vernon Maueryd4222fd2023-07-27 11:26:51 -0700118 return std::nullopt;
George Liu3e3cc352023-07-26 15:59:31 +0800119 }
Vernon Maueryd4222fd2023-07-27 11:26:51 -0700120 bool pcapEnabled{};
121 ec = ipmi::getDbusProperty(ctx, service, pcapPath, pcapInterface,
122 powerCapEnableProp, pcapEnabled);
123 if (ec.value())
George Liu3e3cc352023-07-26 15:59:31 +0800124 {
Vernon Maueryd4222fd2023-07-27 11:26:51 -0700125 log<level::ERR>("Error in getPcap prop");
Tom Josephb9d86f42017-07-26 18:03:47 +0530126 elog<InternalFailure>();
Vernon Maueryd4222fd2023-07-27 11:26:51 -0700127 return std::nullopt;
Andrew Geissler50c0c8f2017-07-11 16:18:51 -0500128 }
Vernon Maueryd4222fd2023-07-27 11:26:51 -0700129 return pcapEnabled;
Andrew Geissler50c0c8f2017-07-11 16:18:51 -0500130}
Chris Austen1810bec2015-10-13 12:12:39 -0500131
Vernon Maueryd4222fd2023-07-27 11:26:51 -0700132bool setPcap(ipmi::Context::ptr& ctx, const uint32_t powerCap)
Tom Joseph46fa37d2017-07-26 18:11:55 +0530133{
Vernon Maueryd4222fd2023-07-27 11:26:51 -0700134 std::string service{};
135 boost::system::error_code ec = ipmi::getService(ctx, pcapInterface,
136 pcapPath, service);
137 if (ec.value())
Tom Joseph46fa37d2017-07-26 18:11:55 +0530138 {
Vernon Maueryd4222fd2023-07-27 11:26:51 -0700139 return false;
George Liu3e3cc352023-07-26 15:59:31 +0800140 }
Vernon Maueryd4222fd2023-07-27 11:26:51 -0700141
142 ec = ipmi::setDbusProperty(ctx, service, pcapPath, pcapInterface,
143 powerCapProp, powerCap);
144 if (ec.value())
George Liu3e3cc352023-07-26 15:59:31 +0800145 {
146 log<level::ERR>("Error in setPcap property",
Vernon Maueryd4222fd2023-07-27 11:26:51 -0700147 entry("ERROR=%s", ec.message().c_str()));
Tom Joseph46fa37d2017-07-26 18:11:55 +0530148 elog<InternalFailure>();
Vernon Maueryd4222fd2023-07-27 11:26:51 -0700149 return false;
Tom Joseph46fa37d2017-07-26 18:11:55 +0530150 }
Vernon Maueryd4222fd2023-07-27 11:26:51 -0700151 return true;
Tom Joseph46fa37d2017-07-26 18:11:55 +0530152}
153
Vernon Maueryd4222fd2023-07-27 11:26:51 -0700154bool setPcapEnable(ipmi::Context::ptr& ctx, bool enabled)
Tom Joseph6c8d51b2017-07-26 18:18:06 +0530155{
Vernon Maueryd4222fd2023-07-27 11:26:51 -0700156 std::string service{};
157 boost::system::error_code ec = ipmi::getService(ctx, pcapInterface,
158 pcapPath, service);
159 if (ec.value())
Tom Joseph6c8d51b2017-07-26 18:18:06 +0530160 {
Vernon Maueryd4222fd2023-07-27 11:26:51 -0700161 return false;
George Liu3e3cc352023-07-26 15:59:31 +0800162 }
Vernon Maueryd4222fd2023-07-27 11:26:51 -0700163
164 ec = ipmi::setDbusProperty(ctx, service, pcapPath, pcapInterface,
165 powerCapEnableProp, enabled);
166 if (ec.value())
George Liu3e3cc352023-07-26 15:59:31 +0800167 {
168 log<level::ERR>("Error in setPcapEnabled property",
Vernon Maueryd4222fd2023-07-27 11:26:51 -0700169 entry("ERROR=%s", ec.message().c_str()));
Tom Joseph6c8d51b2017-07-26 18:18:06 +0530170 elog<InternalFailure>();
Vernon Maueryd4222fd2023-07-27 11:26:51 -0700171 return false;
Tom Joseph6c8d51b2017-07-26 18:18:06 +0530172 }
Vernon Maueryd4222fd2023-07-27 11:26:51 -0700173 return true;
Tom Joseph6c8d51b2017-07-26 18:18:06 +0530174}
175
Vernon Mauerydca47202023-07-27 11:32:01 -0700176std::optional<std::string> readAssetTag(ipmi::Context::ptr& ctx)
Tom Josephbe5eaa12017-07-12 19:54:44 +0530177{
Tom Josephbe5eaa12017-07-12 19:54:44 +0530178 // Read the object tree with the inventory root to figure out the object
179 // that has implemented the Asset tag interface.
Vernon Mauerydca47202023-07-27 11:32:01 -0700180 ipmi::DbusObjectInfo objectInfo;
181 boost::system::error_code ec = getDbusObject(
182 ctx, dcmi::assetTagIntf, ipmi::sensor::inventoryRoot, "", objectInfo);
183 if (ec.value())
Tom Josephbe5eaa12017-07-12 19:54:44 +0530184 {
Vernon Mauerydca47202023-07-27 11:32:01 -0700185 return std::nullopt;
George Liu3e3cc352023-07-26 15:59:31 +0800186 }
Vernon Mauerydca47202023-07-27 11:32:01 -0700187
188 std::string assetTag{};
189 ec = ipmi::getDbusProperty(ctx, objectInfo.second, objectInfo.first,
190 dcmi::assetTagIntf, dcmi::assetTagProp,
191 assetTag);
192 if (ec.value())
George Liu3e3cc352023-07-26 15:59:31 +0800193 {
194 log<level::ERR>("Error in reading asset tag",
Vernon Mauerydca47202023-07-27 11:32:01 -0700195 entry("ERROR=%s", ec.message().c_str()));
Tom Josephbe5eaa12017-07-12 19:54:44 +0530196 elog<InternalFailure>();
Vernon Mauerydca47202023-07-27 11:32:01 -0700197 return std::nullopt;
Tom Josephbe5eaa12017-07-12 19:54:44 +0530198 }
Vernon Mauerydca47202023-07-27 11:32:01 -0700199
200 return assetTag;
Tom Josephbe5eaa12017-07-12 19:54:44 +0530201}
202
Vernon Mauerydca47202023-07-27 11:32:01 -0700203bool writeAssetTag(ipmi::Context::ptr& ctx, const std::string& assetTag)
Tom Josephbe5b9892017-07-15 00:55:23 +0530204{
Tom Josephbe5b9892017-07-15 00:55:23 +0530205 // Read the object tree with the inventory root to figure out the object
206 // that has implemented the Asset tag interface.
Vernon Mauerydca47202023-07-27 11:32:01 -0700207 ipmi::DbusObjectInfo objectInfo;
208 boost::system::error_code ec = getDbusObject(
209 ctx, dcmi::assetTagIntf, ipmi::sensor::inventoryRoot, "", objectInfo);
210 if (ec.value())
Tom Josephbe5b9892017-07-15 00:55:23 +0530211 {
Vernon Mauerydca47202023-07-27 11:32:01 -0700212 return false;
George Liu3e3cc352023-07-26 15:59:31 +0800213 }
Vernon Mauerydca47202023-07-27 11:32:01 -0700214
215 ec = ipmi::setDbusProperty(ctx, objectInfo.second, objectInfo.first,
216 dcmi::assetTagIntf, dcmi::assetTagProp,
217 assetTag);
218 if (ec.value())
George Liu3e3cc352023-07-26 15:59:31 +0800219 {
220 log<level::ERR>("Error in writing asset tag",
Vernon Mauerydca47202023-07-27 11:32:01 -0700221 entry("ERROR=%s", ec.message().c_str()));
Tom Josephbe5b9892017-07-15 00:55:23 +0530222 elog<InternalFailure>();
Vernon Mauerydca47202023-07-27 11:32:01 -0700223 return false;
Tom Josephbe5b9892017-07-15 00:55:23 +0530224 }
Vernon Mauerydca47202023-07-27 11:32:01 -0700225 return true;
Tom Josephbe5b9892017-07-15 00:55:23 +0530226}
227
Vernon Maueryefb5ae52023-07-27 11:35:43 -0700228std::optional<std::string> getHostName(ipmi::Context::ptr& ctx)
Vladislav Vovchenko8f7a6f62017-08-17 00:31:14 +0300229{
Vernon Maueryefb5ae52023-07-27 11:35:43 -0700230 std::string service{};
231 boost::system::error_code ec = ipmi::getService(ctx, networkConfigIntf,
232 networkConfigObj, service);
233 if (ec.value())
234 {
235 return std::nullopt;
236 }
237 std::string hostname{};
238 ec = ipmi::getDbusProperty(ctx, service, networkConfigObj,
239 networkConfigIntf, hostNameProp, hostname);
240 if (ec.value())
241 {
242 log<level::ERR>("Error fetching hostname");
243 elog<InternalFailure>();
244 return std::nullopt;
245 }
246 return hostname;
Vladislav Vovchenko8f7a6f62017-08-17 00:31:14 +0300247}
248
Thang Tran55cbf552023-01-31 14:43:02 +0700249EthernetInterface::DHCPConf getDHCPEnabled()
Nagaraju Goruganti22be97b2018-02-07 01:19:59 -0600250{
Patrick Williams5d82f472022-07-22 19:26:53 -0500251 sdbusplus::bus_t bus{ipmid_get_sd_bus_connection()};
Nagaraju Goruganti22be97b2018-02-07 01:19:59 -0600252
Johnathan Mantey74a21022018-12-13 13:17:56 -0800253 auto ethdevice = ipmi::getChannelName(ethernetDefaultChannelNum);
Patrick Williamsfbc6c9d2023-05-10 07:50:16 -0500254 auto ethernetObj = ipmi::getDbusObject(bus, ethernetIntf, networkRoot,
255 ethdevice);
Nagaraju Goruganti22be97b2018-02-07 01:19:59 -0600256 auto service = ipmi::getService(bus, ethernetIntf, ethernetObj.first);
Patrick Venture0b02be92018-08-31 11:55:55 -0700257 auto value = ipmi::getDbusProperty(bus, service, ethernetObj.first,
258 ethernetIntf, "DHCPEnabled");
Nagaraju Goruganti22be97b2018-02-07 01:19:59 -0600259
Thang Tran55cbf552023-01-31 14:43:02 +0700260 return EthernetInterface::convertDHCPConfFromString(
261 std::get<std::string>(value));
Nagaraju Goruganti22be97b2018-02-07 01:19:59 -0600262}
263
264bool getDHCPOption(std::string prop)
265{
Patrick Williams5d82f472022-07-22 19:26:53 -0500266 sdbusplus::bus_t bus{ipmid_get_sd_bus_connection()};
Nagaraju Goruganti22be97b2018-02-07 01:19:59 -0600267
268 auto service = ipmi::getService(bus, dhcpIntf, dhcpObj);
269 auto value = ipmi::getDbusProperty(bus, service, dhcpObj, dhcpIntf, prop);
270
Vernon Maueryf442e112019-04-09 11:44:36 -0700271 return std::get<bool>(value);
Nagaraju Goruganti22be97b2018-02-07 01:19:59 -0600272}
273
Nagaraju Goruganti22be97b2018-02-07 01:19:59 -0600274void setDHCPOption(std::string prop, bool value)
275{
Patrick Williams5d82f472022-07-22 19:26:53 -0500276 sdbusplus::bus_t bus{ipmid_get_sd_bus_connection()};
Nagaraju Goruganti22be97b2018-02-07 01:19:59 -0600277
278 auto service = ipmi::getService(bus, dhcpIntf, dhcpObj);
279 ipmi::setDbusProperty(bus, service, dhcpObj, dhcpIntf, prop, value);
280}
281
Kirill Pakhomova2573622018-11-02 19:00:18 +0300282Json parseJSONConfig(const std::string& configFile)
Deepak Kodihalli0b459552018-02-06 06:25:12 -0600283{
284 std::ifstream jsonFile(configFile);
285 if (!jsonFile.is_open())
286 {
287 log<level::ERR>("Temperature readings JSON file not found");
288 elog<InternalFailure>();
289 }
290
291 auto data = Json::parse(jsonFile, nullptr, false);
292 if (data.is_discarded())
293 {
294 log<level::ERR>("Temperature readings JSON parser failure");
295 elog<InternalFailure>();
296 }
297
298 return data;
299}
300
Tom Josephbe5eaa12017-07-12 19:54:44 +0530301} // namespace dcmi
Chris Austen1810bec2015-10-13 12:12:39 -0500302
Vernon Maueryd4222fd2023-07-27 11:26:51 -0700303constexpr uint8_t exceptionPowerOff = 0x01;
304ipmi::RspType<uint16_t, // reserved
305 uint8_t, // exception actions
306 uint16_t, // power limit requested in watts
307 uint32_t, // correction time in milliseconds
308 uint16_t, // reserved
309 uint16_t // statistics sampling period in seconds
310 >
311 getPowerLimit(ipmi::Context::ptr ctx, uint16_t reserved)
Tom Josephb9d86f42017-07-26 18:03:47 +0530312{
Kirill Pakhomov2c2af2c2018-11-06 16:06:10 +0300313 if (!dcmi::isDCMIPowerMgmtSupported())
314 {
Vernon Maueryd4222fd2023-07-27 11:26:51 -0700315 return ipmi::responseInvalidCommand();
Kirill Pakhomov2c2af2c2018-11-06 16:06:10 +0300316 }
Vernon Maueryd4222fd2023-07-27 11:26:51 -0700317 if (reserved)
Tom Josephb9d86f42017-07-26 18:03:47 +0530318 {
Vernon Maueryd4222fd2023-07-27 11:26:51 -0700319 return ipmi::responseInvalidFieldRequest();
Tom Josephb9d86f42017-07-26 18:03:47 +0530320 }
321
Vernon Maueryd4222fd2023-07-27 11:26:51 -0700322 std::optional<uint16_t> pcapValue = dcmi::getPcap(ctx);
323 std::optional<bool> pcapEnable = dcmi::getPcapEnabled(ctx);
324 if (!pcapValue || !pcapEnable)
325 {
326 return ipmi::responseUnspecifiedError();
327 }
328
329 constexpr uint16_t reserved1{};
330 constexpr uint16_t reserved2{};
Tom Josephb9d86f42017-07-26 18:03:47 +0530331 /*
332 * Exception action if power limit is exceeded and cannot be controlled
333 * with the correction time limit is hardcoded to Hard Power Off system
334 * and log event to SEL.
335 */
Vernon Maueryd4222fd2023-07-27 11:26:51 -0700336 constexpr uint8_t exception = exceptionPowerOff;
Tom Josephb9d86f42017-07-26 18:03:47 +0530337 /*
338 * Correction time limit and Statistics sampling period is currently not
339 * populated.
340 */
Vernon Maueryd4222fd2023-07-27 11:26:51 -0700341 constexpr uint32_t correctionTime{};
342 constexpr uint16_t statsPeriod{};
343 if (!pcapEnable)
Tom Josephb9d86f42017-07-26 18:03:47 +0530344 {
Vernon Maueryd4222fd2023-07-27 11:26:51 -0700345 constexpr ipmi::Cc responseNoPowerLimitSet = 0x80;
346 constexpr uint16_t noPcap{};
347 return ipmi::response(responseNoPowerLimitSet, reserved1, exception,
348 noPcap, correctionTime, reserved2, statsPeriod);
Tom Josephb9d86f42017-07-26 18:03:47 +0530349 }
Vernon Maueryd4222fd2023-07-27 11:26:51 -0700350 return ipmi::responseSuccess(reserved1, exception, *pcapValue,
351 correctionTime, reserved2, statsPeriod);
Tom Josephb9d86f42017-07-26 18:03:47 +0530352}
353
Vernon Maueryd4222fd2023-07-27 11:26:51 -0700354ipmi::RspType<> setPowerLimit(ipmi::Context::ptr& ctx, uint16_t reserved1,
355 uint8_t exceptionAction, uint16_t powerLimit,
356 uint32_t correctionTime, uint16_t reserved2,
357 uint16_t statsPeriod)
Tom Joseph46fa37d2017-07-26 18:11:55 +0530358{
Kirill Pakhomov2c2af2c2018-11-06 16:06:10 +0300359 if (!dcmi::isDCMIPowerMgmtSupported())
360 {
Kirill Pakhomov2c2af2c2018-11-06 16:06:10 +0300361 log<level::ERR>("DCMI Power management is unsupported!");
Vernon Maueryd4222fd2023-07-27 11:26:51 -0700362 return ipmi::responseInvalidCommand();
Kirill Pakhomov2c2af2c2018-11-06 16:06:10 +0300363 }
364
Vernon Maueryd4222fd2023-07-27 11:26:51 -0700365 // Only process the power limit requested in watts. Return errors
366 // for other fields that are set
367 if (reserved1 || reserved2 || correctionTime || statsPeriod ||
368 exceptionAction != exceptionPowerOff)
Tom Joseph46fa37d2017-07-26 18:11:55 +0530369 {
Vernon Maueryd4222fd2023-07-27 11:26:51 -0700370 return ipmi::responseInvalidFieldRequest();
Tom Joseph46fa37d2017-07-26 18:11:55 +0530371 }
Vernon Maueryd4222fd2023-07-27 11:26:51 -0700372
373 if (!dcmi::setPcap(ctx, powerLimit))
Tom Joseph46fa37d2017-07-26 18:11:55 +0530374 {
Vernon Maueryd4222fd2023-07-27 11:26:51 -0700375 return ipmi::responseUnspecifiedError();
Tom Joseph46fa37d2017-07-26 18:11:55 +0530376 }
377
Vernon Maueryd4222fd2023-07-27 11:26:51 -0700378 log<level::INFO>("Set Power Cap", entry("POWERCAP=%u", powerLimit));
Tom Joseph46fa37d2017-07-26 18:11:55 +0530379
Vernon Maueryd4222fd2023-07-27 11:26:51 -0700380 return ipmi::responseSuccess();
Tom Joseph46fa37d2017-07-26 18:11:55 +0530381}
382
Vernon Maueryd4222fd2023-07-27 11:26:51 -0700383ipmi::RspType<> applyPowerLimit(ipmi::Context::ptr& ctx, bool enabled,
384 uint7_t reserved1, uint16_t reserved2)
Tom Joseph6c8d51b2017-07-26 18:18:06 +0530385{
Kirill Pakhomov2c2af2c2018-11-06 16:06:10 +0300386 if (!dcmi::isDCMIPowerMgmtSupported())
387 {
Kirill Pakhomov2c2af2c2018-11-06 16:06:10 +0300388 log<level::ERR>("DCMI Power management is unsupported!");
Vernon Maueryd4222fd2023-07-27 11:26:51 -0700389 return ipmi::responseInvalidCommand();
390 }
391 if (reserved1 || reserved2)
392 {
393 return ipmi::responseInvalidFieldRequest();
Kirill Pakhomov2c2af2c2018-11-06 16:06:10 +0300394 }
395
Vernon Maueryd4222fd2023-07-27 11:26:51 -0700396 if (!dcmi::setPcapEnable(ctx, enabled))
Tom Joseph6c8d51b2017-07-26 18:18:06 +0530397 {
Vernon Maueryd4222fd2023-07-27 11:26:51 -0700398 return ipmi::responseUnspecifiedError();
Tom Joseph6c8d51b2017-07-26 18:18:06 +0530399 }
400
401 log<level::INFO>("Set Power Cap Enable",
Vernon Maueryd4222fd2023-07-27 11:26:51 -0700402 entry("POWERCAPENABLE=%u", static_cast<uint8_t>(enabled)));
Tom Joseph6c8d51b2017-07-26 18:18:06 +0530403
Vernon Maueryd4222fd2023-07-27 11:26:51 -0700404 return ipmi::responseSuccess();
Tom Joseph6c8d51b2017-07-26 18:18:06 +0530405}
406
Vernon Mauerydca47202023-07-27 11:32:01 -0700407ipmi::RspType<uint8_t, // total tag length
408 std::vector<char> // tag data
409 >
410 getAssetTag(ipmi::Context::ptr& ctx, uint8_t offset, uint8_t count)
Tom Joseph6f6dd4d2017-07-12 20:07:11 +0530411{
Vernon Mauerydca47202023-07-27 11:32:01 -0700412 // Verify offset to read and number of bytes to read are not exceeding
413 // the range.
414 if ((offset > dcmi::assetTagMaxOffset) || (count > dcmi::maxBytes) ||
415 ((offset + count) > dcmi::assetTagMaxSize))
Tom Joseph6f6dd4d2017-07-12 20:07:11 +0530416 {
Vernon Mauerydca47202023-07-27 11:32:01 -0700417 return ipmi::responseParmOutOfRange();
Tom Joseph6f6dd4d2017-07-12 20:07:11 +0530418 }
419
Vernon Mauerydca47202023-07-27 11:32:01 -0700420 std::optional<std::string> assetTagResp = dcmi::readAssetTag(ctx);
421 if (!assetTagResp)
Tom Joseph6f6dd4d2017-07-12 20:07:11 +0530422 {
Vernon Mauerydca47202023-07-27 11:32:01 -0700423 return ipmi::responseUnspecifiedError();
Tom Joseph6f6dd4d2017-07-12 20:07:11 +0530424 }
425
Vernon Mauerydca47202023-07-27 11:32:01 -0700426 std::string& assetTag = assetTagResp.value();
427 // If the asset tag is longer than 63 bytes, restrict it to 63 bytes to
428 // suit Get Asset Tag command.
Tom Joseph6f6dd4d2017-07-12 20:07:11 +0530429 if (assetTag.size() > dcmi::assetTagMaxSize)
430 {
431 assetTag.resize(dcmi::assetTagMaxSize);
432 }
433
Vernon Mauerydca47202023-07-27 11:32:01 -0700434 if (offset >= assetTag.size())
Tom Joseph6f6dd4d2017-07-12 20:07:11 +0530435 {
Vernon Mauerydca47202023-07-27 11:32:01 -0700436 return ipmi::responseParmOutOfRange();
Tom Joseph6f6dd4d2017-07-12 20:07:11 +0530437 }
438
Vernon Mauerydca47202023-07-27 11:32:01 -0700439 // silently truncate reads beyond the end of assetTag
440 if ((offset + count) >= assetTag.size())
441 {
442 count = assetTag.size() - offset;
443 }
Tom Joseph6f6dd4d2017-07-12 20:07:11 +0530444
Vernon Mauerydca47202023-07-27 11:32:01 -0700445 auto totalTagSize = static_cast<uint8_t>(assetTag.size());
446 std::vector<char> data{assetTag.begin() + offset,
447 assetTag.begin() + offset + count};
Tom Joseph6f6dd4d2017-07-12 20:07:11 +0530448
Vernon Mauerydca47202023-07-27 11:32:01 -0700449 return ipmi::responseSuccess(totalTagSize, data);
Tom Joseph6f6dd4d2017-07-12 20:07:11 +0530450}
451
Vernon Mauerydca47202023-07-27 11:32:01 -0700452ipmi::RspType<uint8_t // new asset tag length
453 >
454 setAssetTag(ipmi::Context::ptr& ctx, uint8_t offset, uint8_t count,
455 const std::vector<char>& data)
Tom Joseph545dd232017-07-12 20:20:49 +0530456{
Vernon Mauerydca47202023-07-27 11:32:01 -0700457 // Verify offset to read and number of bytes to read are not exceeding
458 // the range.
459 if ((offset > dcmi::assetTagMaxOffset) || (count > dcmi::maxBytes) ||
460 ((offset + count) > dcmi::assetTagMaxSize))
Tom Joseph545dd232017-07-12 20:20:49 +0530461 {
Vernon Mauerydca47202023-07-27 11:32:01 -0700462 return ipmi::responseParmOutOfRange();
463 }
464 if (data.size() != count)
465 {
466 return ipmi::responseReqDataLenInvalid();
Tom Joseph545dd232017-07-12 20:20:49 +0530467 }
468
Vernon Mauerydca47202023-07-27 11:32:01 -0700469 std::optional<std::string> assetTagResp = dcmi::readAssetTag(ctx);
470 if (!assetTagResp)
Tom Joseph545dd232017-07-12 20:20:49 +0530471 {
Vernon Mauerydca47202023-07-27 11:32:01 -0700472 return ipmi::responseUnspecifiedError();
Tom Joseph545dd232017-07-12 20:20:49 +0530473 }
Vernon Mauerydca47202023-07-27 11:32:01 -0700474
475 std::string& assetTag = assetTagResp.value();
476
477 if (offset > assetTag.size())
Tom Joseph545dd232017-07-12 20:20:49 +0530478 {
Vernon Mauerydca47202023-07-27 11:32:01 -0700479 return ipmi::responseParmOutOfRange();
Tom Joseph545dd232017-07-12 20:20:49 +0530480 }
Vernon Mauerydca47202023-07-27 11:32:01 -0700481
482 // operation is to truncate at offset and append new data
483 assetTag.resize(offset);
484 assetTag.append(data.begin(), data.end());
485
486 if (!dcmi::writeAssetTag(ctx, assetTag))
487 {
488 return ipmi::responseUnspecifiedError();
489 }
490
491 auto totalTagSize = static_cast<uint8_t>(assetTag.size());
492 return ipmi::responseSuccess(totalTagSize);
Tom Joseph545dd232017-07-12 20:20:49 +0530493}
494
Vernon Maueryefb5ae52023-07-27 11:35:43 -0700495ipmi::RspType<uint8_t, // length
496 std::vector<char> // data
497 >
498 getMgmntCtrlIdStr(ipmi::Context::ptr& ctx, uint8_t offset, uint8_t count)
Vladislav Vovchenko8f7a6f62017-08-17 00:31:14 +0300499{
Vernon Maueryefb5ae52023-07-27 11:35:43 -0700500 if (count > dcmi::maxBytes || offset + count > dcmi::maxCtrlIdStrLen)
Vladislav Vovchenko8f7a6f62017-08-17 00:31:14 +0300501 {
Vernon Maueryefb5ae52023-07-27 11:35:43 -0700502 return ipmi::responseParmOutOfRange();
Vladislav Vovchenko8f7a6f62017-08-17 00:31:14 +0300503 }
504
Vernon Maueryefb5ae52023-07-27 11:35:43 -0700505 std::optional<std::string> hostnameResp = dcmi::getHostName(ctx);
506 if (!hostnameResp)
Vladislav Vovchenko8f7a6f62017-08-17 00:31:14 +0300507 {
Vernon Maueryefb5ae52023-07-27 11:35:43 -0700508 return ipmi::responseUnspecifiedError();
Vladislav Vovchenko8f7a6f62017-08-17 00:31:14 +0300509 }
510
Vernon Maueryefb5ae52023-07-27 11:35:43 -0700511 std::string& hostname = hostnameResp.value();
512 // If the id string is longer than 63 bytes, restrict it to 63 bytes to
513 // suit set management ctrl str command.
514 if (hostname.size() > dcmi::maxCtrlIdStrLen)
Vladislav Vovchenko8f7a6f62017-08-17 00:31:14 +0300515 {
Vernon Maueryefb5ae52023-07-27 11:35:43 -0700516 hostname.resize(dcmi::maxCtrlIdStrLen);
Vladislav Vovchenko8f7a6f62017-08-17 00:31:14 +0300517 }
Vladislav Vovchenko8f7a6f62017-08-17 00:31:14 +0300518
Vernon Maueryefb5ae52023-07-27 11:35:43 -0700519 if (offset >= hostname.size())
520 {
521 return ipmi::responseParmOutOfRange();
522 }
523
524 // silently truncate reads beyond the end of hostname
525 if ((offset + count) >= hostname.size())
526 {
527 count = hostname.size() - offset;
528 }
529
530 auto nameSize = static_cast<uint8_t>(hostname.size());
531 std::vector<char> data{hostname.begin() + offset,
532 hostname.begin() + offset + count};
533
534 return ipmi::responseSuccess(nameSize, data);
Vladislav Vovchenko8f7a6f62017-08-17 00:31:14 +0300535}
536
Vernon Maueryefb5ae52023-07-27 11:35:43 -0700537ipmi::RspType<uint8_t> setMgmntCtrlIdStr(ipmi::Context::ptr& ctx,
538 uint8_t offset, uint8_t count,
539 std::vector<char> data)
Vladislav Vovchenko8f7a6f62017-08-17 00:31:14 +0300540{
Vernon Maueryefb5ae52023-07-27 11:35:43 -0700541 if ((offset > dcmi::maxCtrlIdStrLen) || (count > dcmi::maxBytes) ||
542 ((offset + count) > dcmi::maxCtrlIdStrLen))
Vladislav Vovchenko8f7a6f62017-08-17 00:31:14 +0300543 {
Vernon Maueryefb5ae52023-07-27 11:35:43 -0700544 return ipmi::responseParmOutOfRange();
545 }
546 if (data.size() != count)
547 {
548 return ipmi::responseReqDataLenInvalid();
549 }
550 bool terminalWrite{data.back() == '\0'};
551 if (terminalWrite)
552 {
553 // remove the null termination from the data (no need with std::string)
554 data.resize(count - 1);
Vladislav Vovchenko8f7a6f62017-08-17 00:31:14 +0300555 }
556
Vernon Maueryefb5ae52023-07-27 11:35:43 -0700557 static std::string hostname{};
558 // read in the current value if not starting at offset 0
559 if (hostname.size() == 0 && offset != 0)
Vladislav Vovchenko8f7a6f62017-08-17 00:31:14 +0300560 {
Vernon Maueryefb5ae52023-07-27 11:35:43 -0700561 /* read old ctrlIdStr */
562 std::optional<std::string> hostnameResp = dcmi::getHostName(ctx);
563 if (!hostnameResp)
Vladislav Vovchenko8f7a6f62017-08-17 00:31:14 +0300564 {
Vernon Maueryefb5ae52023-07-27 11:35:43 -0700565 return ipmi::responseUnspecifiedError();
Vladislav Vovchenko8f7a6f62017-08-17 00:31:14 +0300566 }
Vernon Maueryefb5ae52023-07-27 11:35:43 -0700567 hostname = hostnameResp.value();
568 hostname.resize(offset);
Vladislav Vovchenko8f7a6f62017-08-17 00:31:14 +0300569 }
570
Vernon Maueryefb5ae52023-07-27 11:35:43 -0700571 // operation is to truncate at offset and append new data
572 hostname.append(data.begin(), data.end());
573
574 // do the update if this is the last write
575 if (terminalWrite)
576 {
577 boost::system::error_code ec = ipmi::setDbusProperty(
578 ctx, dcmi::networkServiceName, dcmi::networkConfigObj,
579 dcmi::networkConfigIntf, dcmi::hostNameProp, hostname);
580 hostname.clear();
581 if (ec.value())
582 {
583 return ipmi::responseUnspecifiedError();
584 }
585 }
586
587 auto totalIdSize = static_cast<uint8_t>(offset + count);
588 return ipmi::responseSuccess(totalIdSize);
Vladislav Vovchenko8f7a6f62017-08-17 00:31:14 +0300589}
590
Vernon Maueryf038dc02023-07-27 14:06:11 -0700591ipmi::RspType<ipmi::message::Payload> getDCMICapabilities(uint8_t parameter)
Dhruvaraj Subhashchandrane29be412018-01-16 05:11:56 -0600592{
Kirill Pakhomova2573622018-11-02 19:00:18 +0300593 std::ifstream dcmiCapFile(dcmi::gDCMICapabilitiesConfig);
Dhruvaraj Subhashchandrane29be412018-01-16 05:11:56 -0600594 if (!dcmiCapFile.is_open())
595 {
596 log<level::ERR>("DCMI Capabilities file not found");
Vernon Maueryf038dc02023-07-27 14:06:11 -0700597 return ipmi::responseUnspecifiedError();
Dhruvaraj Subhashchandrane29be412018-01-16 05:11:56 -0600598 }
599
600 auto data = nlohmann::json::parse(dcmiCapFile, nullptr, false);
601 if (data.is_discarded())
602 {
603 log<level::ERR>("DCMI Capabilities JSON parser failure");
Vernon Maueryf038dc02023-07-27 14:06:11 -0700604 return ipmi::responseUnspecifiedError();
Dhruvaraj Subhashchandrane29be412018-01-16 05:11:56 -0600605 }
606
Vernon Maueryf038dc02023-07-27 14:06:11 -0700607 constexpr bool reserved1{};
608 constexpr uint5_t reserved5{};
609 constexpr uint7_t reserved7{};
610 constexpr uint8_t reserved8{};
611 constexpr uint16_t reserved16{};
Dhruvaraj Subhashchandrane29be412018-01-16 05:11:56 -0600612
Vernon Maueryf038dc02023-07-27 14:06:11 -0700613 ipmi::message::Payload payload;
614 payload.pack(dcmi::specMajorVersion, dcmi::specMinorVersion,
615 dcmi::parameterRevision);
616
617 enum class DCMICapParameters : uint8_t
Dhruvaraj Subhashchandrane29be412018-01-16 05:11:56 -0600618 {
Vernon Maueryf038dc02023-07-27 14:06:11 -0700619 SupportedDcmiCaps = 0x01, // Supported DCMI Capabilities
620 MandatoryPlatAttributes = 0x02, // Mandatory Platform Attributes
621 OptionalPlatAttributes = 0x03, // Optional Platform Attributes
622 ManageabilityAccessAttributes = 0x04, // Manageability Access Attributes
623 };
Dhruvaraj Subhashchandrane29be412018-01-16 05:11:56 -0600624
Vernon Maueryf038dc02023-07-27 14:06:11 -0700625 switch (static_cast<DCMICapParameters>(parameter))
Dhruvaraj Subhashchandrane29be412018-01-16 05:11:56 -0600626 {
Vernon Maueryf038dc02023-07-27 14:06:11 -0700627 case DCMICapParameters::SupportedDcmiCaps:
Dhruvaraj Subhashchandrane29be412018-01-16 05:11:56 -0600628 {
Vernon Maueryf038dc02023-07-27 14:06:11 -0700629 bool powerManagement = data.value("PowerManagement", 0);
630 bool oobSecondaryLan = data.value("OOBSecondaryLan", 0);
631 bool serialTMode = data.value("SerialTMODE", 0);
632 bool inBandSystemInterfaceChannel =
633 data.value("InBandSystemInterfaceChannel", 0);
634 payload.pack(reserved8, powerManagement, reserved7,
635 inBandSystemInterfaceChannel, serialTMode,
636 oobSecondaryLan, reserved5);
637 break;
Dhruvaraj Subhashchandrane29be412018-01-16 05:11:56 -0600638 }
Vernon Maueryf038dc02023-07-27 14:06:11 -0700639 // Mandatory Platform Attributes
640 case DCMICapParameters::MandatoryPlatAttributes:
Dhruvaraj Subhashchandrane29be412018-01-16 05:11:56 -0600641 {
Vernon Maueryf038dc02023-07-27 14:06:11 -0700642 bool selAutoRollOver = data.value("SELAutoRollOver", 0);
643 bool flushEntireSELUponRollOver =
644 data.value("FlushEntireSELUponRollOver", 0);
645 bool recordLevelSELFlushUponRollOver =
646 data.value("RecordLevelSELFlushUponRollOver", 0);
647 uint12_t numberOfSELEntries = data.value("NumberOfSELEntries",
648 0xcac);
649 uint8_t tempMonitoringSamplingFreq =
650 data.value("TempMonitoringSamplingFreq", 0);
651 payload.pack(numberOfSELEntries, reserved1,
652 recordLevelSELFlushUponRollOver,
653 flushEntireSELUponRollOver, selAutoRollOver,
654 reserved16, tempMonitoringSamplingFreq);
655 break;
656 }
657 // Optional Platform Attributes
658 case DCMICapParameters::OptionalPlatAttributes:
659 {
660 uint7_t powerMgmtDeviceSlaveAddress =
661 data.value("PowerMgmtDeviceSlaveAddress", 0);
662 uint4_t bmcChannelNumber = data.value("BMCChannelNumber", 0);
663 uint4_t deviceRivision = data.value("DeviceRivision", 0);
664 payload.pack(powerMgmtDeviceSlaveAddress, reserved1, deviceRivision,
665 bmcChannelNumber);
666 break;
667 }
668 // Manageability Access Attributes
669 case DCMICapParameters::ManageabilityAccessAttributes:
670 {
671 uint8_t mandatoryPrimaryLanOOBSupport =
672 data.value("MandatoryPrimaryLanOOBSupport", 0xff);
673 uint8_t optionalSecondaryLanOOBSupport =
674 data.value("OptionalSecondaryLanOOBSupport", 0xff);
675 uint8_t optionalSerialOOBMTMODECapability =
676 data.value("OptionalSerialOOBMTMODECapability", 0xff);
677 payload.pack(mandatoryPrimaryLanOOBSupport,
678 optionalSecondaryLanOOBSupport,
679 optionalSerialOOBMTMODECapability);
680 break;
681 }
682 default:
683 {
684 log<level::ERR>("Invalid input parameter");
685 return ipmi::responseInvalidFieldRequest();
Dhruvaraj Subhashchandrane29be412018-01-16 05:11:56 -0600686 }
687 }
688
Vernon Maueryf038dc02023-07-27 14:06:11 -0700689 return ipmi::responseSuccess(payload);
Dhruvaraj Subhashchandrane29be412018-01-16 05:11:56 -0600690}
691
Deepak Kodihalliee717d72018-01-24 04:53:09 -0600692namespace dcmi
693{
694namespace temp_readings
695{
696
Vernon Mauerycce9ffd2023-07-27 14:15:17 -0700697std::tuple<bool, bool, uint8_t> readTemp(ipmi::Context::ptr& ctx,
698 const std::string& dbusService,
699 const std::string& dbusPath)
Deepak Kodihallib1e8fba2018-01-24 04:57:10 -0600700{
701 // Read the temperature value from d-bus object. Need some conversion.
Vernon Mauerycce9ffd2023-07-27 14:15:17 -0700702 // As per the interface xyz.openbmc_project.Sensor.Value, the
703 // temperature is an double and in degrees C. It needs to be scaled by
704 // using the formula Value * 10^Scale. The ipmi spec has the temperature
705 // as a uint8_t, with a separate single bit for the sign.
Deepak Kodihallib1e8fba2018-01-24 04:57:10 -0600706
Vernon Mauerycce9ffd2023-07-27 14:15:17 -0700707 ipmi::PropertyMap result{};
708 boost::system::error_code ec = ipmi::getAllDbusProperties(
709 ctx, dbusService, dbusPath, "xyz.openbmc_project.Sensor.Value", result);
710 if (ec.value())
711 {
712 return std::make_tuple(false, false, 0);
713 }
Patrick Williamsfbc6c9d2023-05-10 07:50:16 -0500714 auto temperature = std::visit(ipmi::VariantToDoubleVisitor(),
715 result.at("Value"));
James Feist9cc0ea52018-10-09 10:53:11 -0700716 double absTemp = std::abs(temperature);
Deepak Kodihallib1e8fba2018-01-24 04:57:10 -0600717
James Feist9cc0ea52018-10-09 10:53:11 -0700718 auto findFactor = result.find("Scale");
719 double factor = 0.0;
720 if (findFactor != result.end())
Deepak Kodihallib1e8fba2018-01-24 04:57:10 -0600721 {
Vernon Maueryf442e112019-04-09 11:44:36 -0700722 factor = std::visit(ipmi::VariantToDoubleVisitor(), findFactor->second);
Deepak Kodihallib1e8fba2018-01-24 04:57:10 -0600723 }
James Feist9cc0ea52018-10-09 10:53:11 -0700724 double scale = std::pow(10, factor);
725
726 auto tempDegrees = absTemp * scale;
Vernon Mauerycce9ffd2023-07-27 14:15:17 -0700727 // Max absolute temp as per ipmi spec is 127.
728 constexpr auto maxTemp = 127;
Deepak Kodihallib1e8fba2018-01-24 04:57:10 -0600729 if (tempDegrees > maxTemp)
730 {
731 tempDegrees = maxTemp;
732 }
733
Vernon Mauerycce9ffd2023-07-27 14:15:17 -0700734 return std::make_tuple(true, (temperature < 0),
735 static_cast<uint8_t>(tempDegrees));
Deepak Kodihallib1e8fba2018-01-24 04:57:10 -0600736}
737
Vernon Mauerycce9ffd2023-07-27 14:15:17 -0700738std::tuple<std::vector<std::tuple<uint7_t, bool, uint8_t>>, uint8_t>
739 read(ipmi::Context::ptr& ctx, const std::string& type, uint8_t instance,
740 size_t count)
Deepak Kodihalliee717d72018-01-24 04:53:09 -0600741{
Vernon Mauerycce9ffd2023-07-27 14:15:17 -0700742 std::vector<std::tuple<uint7_t, bool, uint8_t>> response{};
Deepak Kodihallib1e8fba2018-01-24 04:57:10 -0600743
Kirill Pakhomova2573622018-11-02 19:00:18 +0300744 auto data = parseJSONConfig(gDCMISensorsConfig);
Vernon Mauerycce9ffd2023-07-27 14:15:17 -0700745 static const std::vector<nlohmann::json> empty{};
746 std::vector<nlohmann::json> readings = data.value(type, empty);
Deepak Kodihallib1e8fba2018-01-24 04:57:10 -0600747 for (const auto& j : readings)
748 {
Vernon Mauerycce9ffd2023-07-27 14:15:17 -0700749 // Max of 8 response data sets
750 if (response.size() == count)
751 {
752 break;
753 }
754
Deepak Kodihallib1e8fba2018-01-24 04:57:10 -0600755 uint8_t instanceNum = j.value("instance", 0);
Vernon Mauerycce9ffd2023-07-27 14:15:17 -0700756 // Not in the instance range we're interested in
757 if (instanceNum < instance)
Deepak Kodihallib1e8fba2018-01-24 04:57:10 -0600758 {
759 continue;
760 }
761
762 std::string path = j.value("dbus", "");
Vernon Mauerycce9ffd2023-07-27 14:15:17 -0700763 std::string service{};
764 boost::system::error_code ec = ipmi::getService(
765 ctx, "xyz.openbmc_project.Sensor.Value", path, service);
766 if (ec.value())
Deepak Kodihallib1e8fba2018-01-24 04:57:10 -0600767 {
Vernon Mauerycce9ffd2023-07-27 14:15:17 -0700768 // not found on dbus
Deepak Kodihallib1e8fba2018-01-24 04:57:10 -0600769 continue;
770 }
Vernon Mauerycce9ffd2023-07-27 14:15:17 -0700771
772 const auto& [ok, sign, temp] = readTemp(ctx, service, path);
773 if (ok)
774 {
775 response.emplace_back(uint7_t{temp}, sign, instanceNum);
776 }
Deepak Kodihallib1e8fba2018-01-24 04:57:10 -0600777 }
778
Vernon Mauerycce9ffd2023-07-27 14:15:17 -0700779 auto totalInstances =
780 static_cast<uint8_t>(std::min(readings.size(), maxInstances));
781 return std::make_tuple(response, totalInstances);
Deepak Kodihalliee717d72018-01-24 04:53:09 -0600782}
783
Patrick Venture0b02be92018-08-31 11:55:55 -0700784} // namespace temp_readings
785} // namespace dcmi
Deepak Kodihalliee717d72018-01-24 04:53:09 -0600786
Vernon Mauerycce9ffd2023-07-27 14:15:17 -0700787ipmi::RspType<uint8_t, // total instances for entity id
788 uint8_t, // number of instances in this reply
789 std::vector< // zero or more of the following two bytes
790 std::tuple<uint7_t, // temperature value
791 bool, // sign bit
792 uint8_t // entity instance
793 >>>
794 getTempReadings(ipmi::Context::ptr& ctx, uint8_t sensorType,
795 uint8_t entityId, uint8_t entityInstance,
796 uint8_t instanceStart)
Deepak Kodihalliee717d72018-01-24 04:53:09 -0600797{
Vernon Mauerycce9ffd2023-07-27 14:15:17 -0700798 auto it = dcmi::entityIdToName.find(entityId);
Deepak Kodihalli0b459552018-02-06 06:25:12 -0600799 if (it == dcmi::entityIdToName.end())
Deepak Kodihalliee717d72018-01-24 04:53:09 -0600800 {
Vernon Mauerycce9ffd2023-07-27 14:15:17 -0700801 log<level::ERR>("Unknown Entity ID", entry("ENTITY_ID=%d", entityId));
802 return ipmi::responseInvalidFieldRequest();
Deepak Kodihalliee717d72018-01-24 04:53:09 -0600803 }
804
Vernon Mauerycce9ffd2023-07-27 14:15:17 -0700805 if (sensorType != dcmi::temperatureSensorType)
Deepak Kodihalliee717d72018-01-24 04:53:09 -0600806 {
807 log<level::ERR>("Invalid sensor type",
Vernon Mauerycce9ffd2023-07-27 14:15:17 -0700808 entry("SENSOR_TYPE=%d", sensorType));
809 return ipmi::responseInvalidFieldRequest();
Deepak Kodihalliee717d72018-01-24 04:53:09 -0600810 }
811
Vernon Mauerycce9ffd2023-07-27 14:15:17 -0700812 uint8_t requestedRecords = (entityInstance == 0) ? dcmi::maxRecords : 1;
Deepak Kodihalliee717d72018-01-24 04:53:09 -0600813
Vernon Mauerycce9ffd2023-07-27 14:15:17 -0700814 // Read requested instances
815 const auto& [temps, totalInstances] = dcmi::temp_readings::read(
816 ctx, it->second, instanceStart, requestedRecords);
Deepak Kodihalliee717d72018-01-24 04:53:09 -0600817
Vernon Mauerycce9ffd2023-07-27 14:15:17 -0700818 auto numInstances = static_cast<uint8_t>(temps.size());
819
820 return ipmi::responseSuccess(totalInstances, numInstances, temps);
Deepak Kodihalliee717d72018-01-24 04:53:09 -0600821}
822
Willy Tu11d68892022-01-20 10:37:34 -0800823ipmi_ret_t setDCMIConfParams(ipmi_netfn_t, ipmi_cmd_t, ipmi_request_t request,
824 ipmi_response_t, ipmi_data_len_t data_len,
825 ipmi_context_t)
Nagaraju Goruganti22be97b2018-02-07 01:19:59 -0600826{
Patrick Venture0b02be92018-08-31 11:55:55 -0700827 auto requestData =
828 reinterpret_cast<const dcmi::SetConfParamsRequest*>(request);
Nagaraju Goruganti22be97b2018-02-07 01:19:59 -0600829
William A. Kennington III5d06cc62019-04-25 02:10:55 -0700830 if (*data_len < DCMI_SET_CONF_PARAM_REQ_PACKET_MIN_SIZE ||
Patrick Venture0b02be92018-08-31 11:55:55 -0700831 *data_len > DCMI_SET_CONF_PARAM_REQ_PACKET_MAX_SIZE)
Nagaraju Goruganti22be97b2018-02-07 01:19:59 -0600832 {
William A. Kennington III5d06cc62019-04-25 02:10:55 -0700833 log<level::ERR>("Invalid Requested Packet size",
Nagaraju Goruganti22be97b2018-02-07 01:19:59 -0600834 entry("PACKET SIZE=%d", *data_len));
William A. Kennington III5d06cc62019-04-25 02:10:55 -0700835 *data_len = 0;
Nagaraju Goruganti22be97b2018-02-07 01:19:59 -0600836 return IPMI_CC_INVALID_FIELD_REQUEST;
837 }
Nagaraju Goruganti22be97b2018-02-07 01:19:59 -0600838 *data_len = 0;
839
840 try
841 {
842 // Take action based on the Parameter Selector
Patrick Venture0b02be92018-08-31 11:55:55 -0700843 switch (
844 static_cast<dcmi::DCMIConfigParameters>(requestData->paramSelect))
Nagaraju Goruganti22be97b2018-02-07 01:19:59 -0600845 {
846 case dcmi::DCMIConfigParameters::ActivateDHCP:
847
848 if ((requestData->data[0] & DCMI_ACTIVATE_DHCP_MASK) &&
Thang Tran55cbf552023-01-31 14:43:02 +0700849 (dcmi::getDHCPEnabled() !=
850 EthernetInterface::DHCPConf::none))
Nagaraju Goruganti22be97b2018-02-07 01:19:59 -0600851 {
Patrick Venture0b02be92018-08-31 11:55:55 -0700852 // When these conditions are met we have to trigger DHCP
853 // protocol restart using the latest parameter settings, but
854 // as per n/w manager design, each time when we update n/w
855 // parameters, n/w service is restarted. So we no need to
856 // take any action in this case.
Nagaraju Goruganti22be97b2018-02-07 01:19:59 -0600857 }
858 break;
859
860 case dcmi::DCMIConfigParameters::DiscoveryConfig:
861
862 if (requestData->data[0] & DCMI_OPTION_12_MASK)
863 {
864 dcmi::setDHCPOption(DHCP_OPT12_ENABLED, true);
865 }
866 else
867 {
868 dcmi::setDHCPOption(DHCP_OPT12_ENABLED, false);
869 }
870
871 // Systemd-networkd doesn't support Random Back off
872 if (requestData->data[0] & DCMI_RAND_BACK_OFF_MASK)
873 {
874 return IPMI_CC_INVALID;
875 }
876 break;
877 // Systemd-networkd doesn't allow to configure DHCP timigs
878 case dcmi::DCMIConfigParameters::DHCPTiming1:
879 case dcmi::DCMIConfigParameters::DHCPTiming2:
880 case dcmi::DCMIConfigParameters::DHCPTiming3:
881 default:
882 return IPMI_CC_INVALID;
883 }
884 }
Patrick Williamsa2ad2da2021-10-06 12:21:46 -0500885 catch (const std::exception& e)
Nagaraju Goruganti22be97b2018-02-07 01:19:59 -0600886 {
887 log<level::ERR>(e.what());
888 return IPMI_CC_UNSPECIFIED_ERROR;
889 }
Nagaraju Goruganti22be97b2018-02-07 01:19:59 -0600890 return IPMI_CC_OK;
891}
892
Willy Tu11d68892022-01-20 10:37:34 -0800893ipmi_ret_t getDCMIConfParams(ipmi_netfn_t, ipmi_cmd_t, ipmi_request_t request,
894 ipmi_response_t response, ipmi_data_len_t data_len,
895 ipmi_context_t)
Nagaraju Goruganti22be97b2018-02-07 01:19:59 -0600896{
Patrick Venture0b02be92018-08-31 11:55:55 -0700897 auto requestData =
898 reinterpret_cast<const dcmi::GetConfParamsRequest*>(request);
899 auto responseData =
900 reinterpret_cast<dcmi::GetConfParamsResponse*>(response);
Nagaraju Goruganti22be97b2018-02-07 01:19:59 -0600901
902 responseData->data[0] = 0x00;
903
William A. Kennington III5d06cc62019-04-25 02:10:55 -0700904 if (*data_len != sizeof(dcmi::GetConfParamsRequest))
Nagaraju Goruganti22be97b2018-02-07 01:19:59 -0600905 {
William A. Kennington III5d06cc62019-04-25 02:10:55 -0700906 log<level::ERR>("Invalid Requested Packet size",
Nagaraju Goruganti22be97b2018-02-07 01:19:59 -0600907 entry("PACKET SIZE=%d", *data_len));
908 return IPMI_CC_INVALID_FIELD_REQUEST;
909 }
910
911 *data_len = 0;
912
913 try
914 {
915 // Take action based on the Parameter Selector
Patrick Venture0b02be92018-08-31 11:55:55 -0700916 switch (
917 static_cast<dcmi::DCMIConfigParameters>(requestData->paramSelect))
Nagaraju Goruganti22be97b2018-02-07 01:19:59 -0600918 {
919 case dcmi::DCMIConfigParameters::ActivateDHCP:
920 responseData->data[0] = DCMI_ACTIVATE_DHCP_REPLY;
921 *data_len = sizeof(dcmi::GetConfParamsResponse) + 1;
922 break;
923 case dcmi::DCMIConfigParameters::DiscoveryConfig:
924 if (dcmi::getDHCPOption(DHCP_OPT12_ENABLED))
925 {
926 responseData->data[0] |= DCMI_OPTION_12_MASK;
927 }
928 *data_len = sizeof(dcmi::GetConfParamsResponse) + 1;
929 break;
930 // Get below values from Systemd-networkd source code
931 case dcmi::DCMIConfigParameters::DHCPTiming1:
932 responseData->data[0] = DHCP_TIMING1;
933 *data_len = sizeof(dcmi::GetConfParamsResponse) + 1;
934 break;
935 case dcmi::DCMIConfigParameters::DHCPTiming2:
936 responseData->data[0] = DHCP_TIMING2_LOWER;
937 responseData->data[1] = DHCP_TIMING2_UPPER;
938 *data_len = sizeof(dcmi::GetConfParamsResponse) + 2;
939 break;
940 case dcmi::DCMIConfigParameters::DHCPTiming3:
941 responseData->data[0] = DHCP_TIMING3_LOWER;
942 responseData->data[1] = DHCP_TIMING3_UPPER;
943 *data_len = sizeof(dcmi::GetConfParamsResponse) + 2;
944 break;
945 default:
946 *data_len = 0;
947 return IPMI_CC_INVALID;
948 }
949 }
Patrick Williamsa2ad2da2021-10-06 12:21:46 -0500950 catch (const std::exception& e)
Nagaraju Goruganti22be97b2018-02-07 01:19:59 -0600951 {
952 log<level::ERR>(e.what());
953 return IPMI_CC_UNSPECIFIED_ERROR;
954 }
955
Nagaraju Goruganti22be97b2018-02-07 01:19:59 -0600956 responseData->major = DCMI_SPEC_MAJOR_VERSION;
957 responseData->minor = DCMI_SPEC_MINOR_VERSION;
958 responseData->paramRevision = DCMI_CONFIG_PARAMETER_REVISION;
959
960 return IPMI_CC_OK;
961}
962
Vernon Mauery056fab12023-07-27 14:25:24 -0700963static std::optional<uint16_t> readPower(ipmi::Context::ptr& ctx)
Marri Devender Rao66c5fda2018-01-18 10:48:37 -0600964{
Vernon Mauery056fab12023-07-27 14:25:24 -0700965 std::ifstream sensorFile(POWER_READING_SENSOR);
966 std::string objectPath;
967 if (!sensorFile.is_open())
968 {
969 log<level::ERR>("Power reading configuration file not found",
970 entry("POWER_SENSOR_FILE=%s", POWER_READING_SENSOR));
971 return std::nullopt;
972 }
973
974 auto data = nlohmann::json::parse(sensorFile, nullptr, false);
975 if (data.is_discarded())
976 {
977 log<level::ERR>("Error in parsing configuration file",
978 entry("POWER_SENSOR_FILE=%s", POWER_READING_SENSOR));
979 return std::nullopt;
980 }
981
982 objectPath = data.value("path", "");
983 if (objectPath.empty())
984 {
985 log<level::ERR>("Power sensor D-Bus object path is empty",
986 entry("POWER_SENSOR_FILE=%s", POWER_READING_SENSOR));
987 return std::nullopt;
988 }
989
990 // Return default value if failed to read from D-Bus object
991 std::string service{};
992 boost::system::error_code ec = ipmi::getService(ctx, dcmi::sensorValueIntf,
993 objectPath, service);
994 if (ec.value())
995 {
996 log<level::ERR>("Failed to fetch service for D-Bus object",
997 entry("OBJECT_PATH=%s", objectPath.c_str()),
998 entry("INTERFACE=%s", dcmi::sensorValueIntf));
999 return std::nullopt;
1000 }
1001
1002 // Read the sensor value and scale properties
1003 double value{};
1004 ec = ipmi::getDbusProperty(ctx, service, objectPath, dcmi::sensorValueIntf,
1005 dcmi::sensorValueProp, value);
1006 if (ec.value())
1007 {
1008 log<level::ERR>("Failure to read power value from D-Bus object",
1009 entry("OBJECT_PATH=%s", objectPath.c_str()),
1010 entry("INTERFACE=%s", dcmi::sensorValueIntf));
1011 return std::nullopt;
1012 }
1013 auto power = static_cast<uint16_t>(value);
1014 return power;
1015}
1016
1017ipmi::RspType<uint16_t, // current power
1018 uint16_t, // minimum power
1019 uint16_t, // maximum power
1020 uint16_t, // average power
1021 uint32_t, // timestamp
1022 uint32_t, // sample period ms
1023 uint6_t, // reserved
1024 bool, // power measurement active
1025 bool // reserved
1026 >
1027 getPowerReading(ipmi::Context::ptr& ctx, uint8_t mode, uint8_t attributes,
1028 uint8_t reserved)
1029{
Kirill Pakhomov2c2af2c2018-11-06 16:06:10 +03001030 if (!dcmi::isDCMIPowerMgmtSupported())
1031 {
Kirill Pakhomov2c2af2c2018-11-06 16:06:10 +03001032 log<level::ERR>("DCMI Power management is unsupported!");
Vernon Mauery056fab12023-07-27 14:25:24 -07001033 return ipmi::responseInvalidCommand();
1034 }
1035 if (reserved)
1036 {
1037 return ipmi::responseInvalidFieldRequest();
Kirill Pakhomov2c2af2c2018-11-06 16:06:10 +03001038 }
1039
Vernon Mauery056fab12023-07-27 14:25:24 -07001040 enum class PowerMode : uint8_t
1041 {
1042 SystemPowerStatistics = 1,
1043 EnhancedSystemPowerStatistics = 2,
1044 };
Marri Devender Rao9c966e02018-01-22 05:55:10 -06001045
Vernon Mauery056fab12023-07-27 14:25:24 -07001046 if (static_cast<PowerMode>(mode) != PowerMode::SystemPowerStatistics)
Marri Devender Rao66c5fda2018-01-18 10:48:37 -06001047 {
Vernon Mauery056fab12023-07-27 14:25:24 -07001048 return ipmi::responseInvalidFieldRequest();
Marri Devender Rao66c5fda2018-01-18 10:48:37 -06001049 }
Vernon Mauery056fab12023-07-27 14:25:24 -07001050 if (attributes)
Marri Devender Rao66c5fda2018-01-18 10:48:37 -06001051 {
Vernon Mauery056fab12023-07-27 14:25:24 -07001052 return ipmi::responseInvalidFieldRequest();
Marri Devender Rao66c5fda2018-01-18 10:48:37 -06001053 }
Marri Devender Rao9c966e02018-01-22 05:55:10 -06001054
Vernon Mauery056fab12023-07-27 14:25:24 -07001055 std::optional<uint16_t> powerResp = readPower(ctx);
1056 if (!powerResp)
1057 {
1058 return ipmi::responseUnspecifiedError();
1059 }
1060 auto& power = powerResp.value();
1061
Marri Devender Rao9c966e02018-01-22 05:55:10 -06001062 // TODO: openbmc/openbmc#2819
Gunnar Mills8466b792018-03-23 12:18:12 -05001063 // Minimum, Maximum, Average power, TimeFrame, TimeStamp,
Marri Devender Rao9c966e02018-01-22 05:55:10 -06001064 // PowerReadingState readings need to be populated
1065 // after Telemetry changes.
Vernon Mauery056fab12023-07-27 14:25:24 -07001066 constexpr uint32_t samplePeriod = 1;
1067 constexpr uint6_t reserved1 = 0;
1068 constexpr bool measurementActive = true;
1069 constexpr bool reserved2 = false;
1070 auto timestamp = static_cast<uint32_t>(time(nullptr));
1071 return ipmi::responseSuccess(power, power, power, power, timestamp,
1072 samplePeriod, reserved1, measurementActive,
1073 reserved2);
Marri Devender Rao66c5fda2018-01-18 10:48:37 -06001074}
1075
Deepak Kodihalli0b459552018-02-06 06:25:12 -06001076namespace dcmi
1077{
1078namespace sensor_info
1079{
1080
Deepak Kodihallidd4cff12018-02-06 06:48:29 -06001081Response createFromJson(const Json& config)
1082{
1083 Response response{};
1084 uint16_t recordId = config.value("record_id", 0);
1085 response.recordIdLsb = recordId & 0xFF;
1086 response.recordIdMsb = (recordId >> 8) & 0xFF;
1087 return response;
1088}
1089
Deepak Kodihalli0b459552018-02-06 06:25:12 -06001090std::tuple<Response, NumInstances> read(const std::string& type,
Patrick Venture0b02be92018-08-31 11:55:55 -07001091 uint8_t instance, const Json& config)
Deepak Kodihalli0b459552018-02-06 06:25:12 -06001092{
Deepak Kodihallidd4cff12018-02-06 06:48:29 -06001093 Response response{};
1094
1095 if (!instance)
1096 {
1097 log<level::ERR>("Expected non-zero instance");
1098 elog<InternalFailure>();
1099 }
1100
1101 static const std::vector<Json> empty{};
1102 std::vector<Json> readings = config.value(type, empty);
1103 size_t numInstances = readings.size();
1104 for (const auto& reading : readings)
1105 {
1106 uint8_t instanceNum = reading.value("instance", 0);
1107 // Not the instance we're interested in
1108 if (instanceNum != instance)
1109 {
1110 continue;
1111 }
1112
1113 response = createFromJson(reading);
1114
1115 // Found the instance we're interested in
1116 break;
1117 }
1118
1119 if (numInstances > maxInstances)
1120 {
1121 log<level::DEBUG>("Trimming IPMI num instances",
1122 entry("NUM_INSTANCES=%d", numInstances));
1123 numInstances = maxInstances;
1124 }
1125 return std::make_tuple(response, numInstances);
Deepak Kodihalli0b459552018-02-06 06:25:12 -06001126}
1127
Patrick Venture0b02be92018-08-31 11:55:55 -07001128std::tuple<ResponseList, NumInstances>
1129 readAll(const std::string& type, uint8_t instanceStart, const Json& config)
Deepak Kodihalli0b459552018-02-06 06:25:12 -06001130{
Deepak Kodihallidd4cff12018-02-06 06:48:29 -06001131 ResponseList responses{};
1132
1133 size_t numInstances = 0;
1134 static const std::vector<Json> empty{};
1135 std::vector<Json> readings = config.value(type, empty);
1136 numInstances = readings.size();
1137 for (const auto& reading : readings)
1138 {
1139 try
1140 {
1141 // Max of 8 records
1142 if (responses.size() == maxRecords)
1143 {
1144 break;
1145 }
1146
1147 uint8_t instanceNum = reading.value("instance", 0);
1148 // Not in the instance range we're interested in
1149 if (instanceNum < instanceStart)
1150 {
1151 continue;
1152 }
1153
1154 Response response = createFromJson(reading);
1155 responses.push_back(response);
1156 }
Patrick Williamsa2ad2da2021-10-06 12:21:46 -05001157 catch (const std::exception& e)
Deepak Kodihallidd4cff12018-02-06 06:48:29 -06001158 {
1159 log<level::DEBUG>(e.what());
1160 continue;
1161 }
1162 }
1163
1164 if (numInstances > maxInstances)
1165 {
1166 log<level::DEBUG>("Trimming IPMI num instances",
1167 entry("NUM_INSTANCES=%d", numInstances));
1168 numInstances = maxInstances;
1169 }
1170 return std::make_tuple(responses, numInstances);
Deepak Kodihalli0b459552018-02-06 06:25:12 -06001171}
1172
1173} // namespace sensor_info
1174} // namespace dcmi
1175
Willy Tu11d68892022-01-20 10:37:34 -08001176ipmi_ret_t getSensorInfo(ipmi_netfn_t, ipmi_cmd_t, ipmi_request_t request,
1177 ipmi_response_t response, ipmi_data_len_t data_len,
1178 ipmi_context_t)
Deepak Kodihalli0b459552018-02-06 06:25:12 -06001179{
1180 auto requestData =
1181 reinterpret_cast<const dcmi::GetSensorInfoRequest*>(request);
1182 auto responseData =
1183 reinterpret_cast<dcmi::GetSensorInfoResponseHdr*>(response);
1184
1185 if (*data_len != sizeof(dcmi::GetSensorInfoRequest))
1186 {
1187 log<level::ERR>("Malformed request data",
1188 entry("DATA_SIZE=%d", *data_len));
1189 return IPMI_CC_REQ_DATA_LEN_INVALID;
1190 }
1191 *data_len = 0;
1192
1193 auto it = dcmi::entityIdToName.find(requestData->entityId);
1194 if (it == dcmi::entityIdToName.end())
1195 {
1196 log<level::ERR>("Unknown Entity ID",
1197 entry("ENTITY_ID=%d", requestData->entityId));
1198 return IPMI_CC_INVALID_FIELD_REQUEST;
1199 }
1200
Deepak Kodihalli0b459552018-02-06 06:25:12 -06001201 if (requestData->sensorType != dcmi::temperatureSensorType)
1202 {
1203 log<level::ERR>("Invalid sensor type",
1204 entry("SENSOR_TYPE=%d", requestData->sensorType));
1205 return IPMI_CC_INVALID_FIELD_REQUEST;
1206 }
1207
1208 dcmi::sensor_info::ResponseList sensors{};
1209 static dcmi::Json config{};
1210 static bool parsed = false;
1211
1212 try
1213 {
1214 if (!parsed)
1215 {
Kirill Pakhomova2573622018-11-02 19:00:18 +03001216 config = dcmi::parseJSONConfig(dcmi::gDCMISensorsConfig);
Deepak Kodihalli0b459552018-02-06 06:25:12 -06001217 parsed = true;
1218 }
1219
1220 if (!requestData->entityInstance)
1221 {
1222 // Read all instances
1223 std::tie(sensors, responseData->numInstances) =
1224 dcmi::sensor_info::readAll(it->second,
Patrick Venture0b02be92018-08-31 11:55:55 -07001225 requestData->instanceStart, config);
Deepak Kodihalli0b459552018-02-06 06:25:12 -06001226 }
1227 else
1228 {
1229 // Read one instance
1230 sensors.resize(1);
1231 std::tie(sensors[0], responseData->numInstances) =
Patrick Venture0b02be92018-08-31 11:55:55 -07001232 dcmi::sensor_info::read(it->second, requestData->entityInstance,
Deepak Kodihalli0b459552018-02-06 06:25:12 -06001233 config);
1234 }
1235 responseData->numRecords = sensors.size();
1236 }
Patrick Williamsa2ad2da2021-10-06 12:21:46 -05001237 catch (const InternalFailure& e)
Deepak Kodihalli0b459552018-02-06 06:25:12 -06001238 {
1239 return IPMI_CC_UNSPECIFIED_ERROR;
1240 }
1241
Deepak Kodihalli0b459552018-02-06 06:25:12 -06001242 size_t payloadSize = sensors.size() * sizeof(dcmi::sensor_info::Response);
1243 if (!sensors.empty())
1244 {
1245 memcpy(responseData + 1, // copy payload right after the response header
Patrick Venture0b02be92018-08-31 11:55:55 -07001246 sensors.data(), payloadSize);
Deepak Kodihalli0b459552018-02-06 06:25:12 -06001247 }
1248 *data_len = sizeof(dcmi::GetSensorInfoResponseHdr) + payloadSize;
1249
1250 return IPMI_CC_OK;
1251}
1252
Chris Austen1810bec2015-10-13 12:12:39 -05001253void register_netfn_dcmi_functions()
1254{
Tom05732372016-09-06 17:21:23 +05301255 // <Get Power Limit>
Vernon Maueryd4222fd2023-07-27 11:26:51 -07001256 registerGroupHandler(ipmi::prioOpenBmcBase, ipmi::groupDCMI,
1257 ipmi::dcmi::cmdGetPowerLimit, ipmi::Privilege::User,
1258 getPowerLimit);
Tom Joseph6f6dd4d2017-07-12 20:07:11 +05301259
Tom Joseph46fa37d2017-07-26 18:11:55 +05301260 // <Set Power Limit>
Vernon Maueryd4222fd2023-07-27 11:26:51 -07001261 registerGroupHandler(ipmi::prioOpenBmcBase, ipmi::groupDCMI,
1262 ipmi::dcmi::cmdSetPowerLimit,
1263 ipmi::Privilege::Operator, setPowerLimit);
Tom Joseph46fa37d2017-07-26 18:11:55 +05301264
Tom Joseph6c8d51b2017-07-26 18:18:06 +05301265 // <Activate/Deactivate Power Limit>
Vernon Maueryd4222fd2023-07-27 11:26:51 -07001266 registerGroupHandler(ipmi::prioOpenBmcBase, ipmi::groupDCMI,
1267 ipmi::dcmi::cmdActDeactivatePwrLimit,
1268 ipmi::Privilege::Operator, applyPowerLimit);
Tom Joseph6c8d51b2017-07-26 18:18:06 +05301269
Tom Joseph6f6dd4d2017-07-12 20:07:11 +05301270 // <Get Asset Tag>
Vernon Mauerydca47202023-07-27 11:32:01 -07001271 registerGroupHandler(ipmi::prioOpenBmcBase, ipmi::groupDCMI,
1272 ipmi::dcmi::cmdGetAssetTag, ipmi::Privilege::User,
1273 getAssetTag);
Tom Joseph545dd232017-07-12 20:20:49 +05301274
1275 // <Set Asset Tag>
Vernon Mauerydca47202023-07-27 11:32:01 -07001276 registerGroupHandler(ipmi::prioOpenBmcBase, ipmi::groupDCMI,
1277 ipmi::dcmi::cmdSetAssetTag, ipmi::Privilege::Operator,
1278 setAssetTag);
Vladislav Vovchenko8f7a6f62017-08-17 00:31:14 +03001279
Gunnar Mills8991dd62017-10-25 17:11:29 -05001280 // <Get Management Controller Identifier String>
Vernon Maueryefb5ae52023-07-27 11:35:43 -07001281 registerGroupHandler(ipmi::prioOpenBmcBase, ipmi::groupDCMI,
1282 ipmi::dcmi::cmdGetMgmtCntlrIdString,
1283 ipmi::Privilege::User, getMgmntCtrlIdStr);
Vladislav Vovchenko8f7a6f62017-08-17 00:31:14 +03001284
1285 // <Set Management Controller Identifier String>
Vernon Maueryefb5ae52023-07-27 11:35:43 -07001286 registerGroupHandler(ipmi::prioOpenBmcBase, ipmi::groupDCMI,
1287 ipmi::dcmi::cmdSetMgmtCntlrIdString,
1288 ipmi::Privilege::Admin, setMgmntCtrlIdStr);
Vladislav Vovchenko8f7a6f62017-08-17 00:31:14 +03001289
Dhruvaraj Subhashchandrane29be412018-01-16 05:11:56 -06001290 // <Get DCMI capabilities>
Vernon Maueryf038dc02023-07-27 14:06:11 -07001291 registerGroupHandler(ipmi::prioOpenBmcBase, ipmi::groupDCMI,
1292 ipmi::dcmi::cmdGetDcmiCapabilitiesInfo,
1293 ipmi::Privilege::User, getDCMICapabilities);
Deepak Kodihalliee717d72018-01-24 04:53:09 -06001294
1295 // <Get Temperature Readings>
Vernon Mauerycce9ffd2023-07-27 14:15:17 -07001296 registerGroupHandler(ipmi::prioOpenBmcBase, ipmi::groupDCMI,
1297 ipmi::dcmi::cmdGetTemperatureReadings,
1298 ipmi::Privilege::User, getTempReadings);
Deepak Kodihalliee717d72018-01-24 04:53:09 -06001299
Marri Devender Rao66c5fda2018-01-18 10:48:37 -06001300 // <Get Power Reading>
Vernon Mauery056fab12023-07-27 14:25:24 -07001301 registerGroupHandler(ipmi::prioOpenBmcBase, ipmi::groupDCMI,
1302 ipmi::dcmi::cmdGetPowerReading, ipmi::Privilege::User,
1303 getPowerReading);
1304
adarshgrami042e9db2022-09-15 10:34:34 +05301305// The Get sensor should get the senor details dynamically when
1306// FEATURE_DYNAMIC_SENSORS is enabled.
1307#ifndef FEATURE_DYNAMIC_SENSORS
Deepak Kodihalli0b459552018-02-06 06:25:12 -06001308 // <Get Sensor Info>
Patrick Venture0b02be92018-08-31 11:55:55 -07001309 ipmi_register_callback(NETFUN_GRPEXT, dcmi::Commands::GET_SENSOR_INFO, NULL,
Chau Lyd74df5f2023-05-25 10:33:00 +00001310 getSensorInfo, PRIVILEGE_OPERATOR);
adarshgrami042e9db2022-09-15 10:34:34 +05301311#endif
Nagaraju Goruganti22be97b2018-02-07 01:19:59 -06001312 // <Get DCMI Configuration Parameters>
Patrick Venture0b02be92018-08-31 11:55:55 -07001313 ipmi_register_callback(NETFUN_GRPEXT, dcmi::Commands::GET_CONF_PARAMS, NULL,
1314 getDCMIConfParams, PRIVILEGE_USER);
Nagaraju Goruganti22be97b2018-02-07 01:19:59 -06001315
1316 // <Set DCMI Configuration Parameters>
Patrick Venture0b02be92018-08-31 11:55:55 -07001317 ipmi_register_callback(NETFUN_GRPEXT, dcmi::Commands::SET_CONF_PARAMS, NULL,
1318 setDCMIConfParams, PRIVILEGE_ADMIN);
Nagaraju Goruganti22be97b2018-02-07 01:19:59 -06001319
Chris Austen1810bec2015-10-13 12:12:39 -05001320 return;
1321}
Tom05732372016-09-06 17:21:23 +05301322// 956379