blob: 4af355dd2d049a077269f6b08de55c57f4cc49c3 [file] [log] [blame]
Patrick Venture0b02be92018-08-31 11:55:55 -07001#include "config.h"
2
Tom Josephbe5eaa12017-07-12 19:54:44 +05303#include "dcmihandler.hpp"
Patrick Venture0b02be92018-08-31 11:55:55 -07004
Johnathan Mantey74a21022018-12-13 13:17:56 -08005#include "user_channel/channel_layer.hpp"
Patrick Venture0b02be92018-08-31 11:55:55 -07006
Vernon Mauerye08fbff2019-04-03 09:19:34 -07007#include <ipmid/api.hpp>
Vernon Mauery6a98fe72019-03-11 15:57:48 -07008#include <ipmid/utils.hpp>
Patrick Venture0b02be92018-08-31 11:55:55 -07009#include <nlohmann/json.hpp>
Tom Josephbe5eaa12017-07-12 19:54:44 +053010#include <phosphor-logging/elog-errors.hpp>
Andrew Geissler50c0c8f2017-07-11 16:18:51 -050011#include <phosphor-logging/log.hpp>
12#include <sdbusplus/bus.hpp>
Patrick Venture0b02be92018-08-31 11:55:55 -070013#include <xyz/openbmc_project/Common/error.hpp>
Thang Tran55cbf552023-01-31 14:43:02 +070014#include <xyz/openbmc_project/Network/EthernetInterface/server.hpp>
Patrick Venture0b02be92018-08-31 11:55:55 -070015
Patrick Williamsfbc6c9d2023-05-10 07:50:16 -050016#include <bitset>
17#include <cmath>
18#include <fstream>
19#include <variant>
20
Tom Josephbe5eaa12017-07-12 19:54:44 +053021using namespace phosphor::logging;
Thang Tran55cbf552023-01-31 14:43:02 +070022using sdbusplus::xyz::openbmc_project::Network::server::EthernetInterface;
23
Tom Josephbe5eaa12017-07-12 19:54:44 +053024using InternalFailure =
Patrick Venture0b02be92018-08-31 11:55:55 -070025 sdbusplus::xyz::openbmc_project::Common::Error::InternalFailure;
Chris Austen1810bec2015-10-13 12:12:39 -050026
27void register_netfn_dcmi_functions() __attribute__((constructor));
28
Vernon Maueryd4222fd2023-07-27 11:26:51 -070029constexpr auto pcapPath = "/xyz/openbmc_project/control/host0/power_cap";
30constexpr auto pcapInterface = "xyz.openbmc_project.Control.Power.Cap";
Andrew Geissler50c0c8f2017-07-11 16:18:51 -050031
Vernon Maueryd4222fd2023-07-27 11:26:51 -070032constexpr auto powerCapProp = "PowerCap";
33constexpr auto powerCapEnableProp = "PowerCapEnable";
Andrew Geissler50c0c8f2017-07-11 16:18:51 -050034
Dhruvaraj Subhashchandrane29be412018-01-16 05:11:56 -060035constexpr auto DCMI_PARAMETER_REVISION = 2;
36constexpr auto DCMI_SPEC_MAJOR_VERSION = 1;
37constexpr auto DCMI_SPEC_MINOR_VERSION = 5;
Nagaraju Goruganti22be97b2018-02-07 01:19:59 -060038constexpr auto DCMI_CONFIG_PARAMETER_REVISION = 1;
39constexpr auto DCMI_RAND_BACK_OFF_MASK = 0x80;
40constexpr auto DCMI_OPTION_60_43_MASK = 0x02;
41constexpr auto DCMI_OPTION_12_MASK = 0x01;
42constexpr auto DCMI_ACTIVATE_DHCP_MASK = 0x01;
43constexpr auto DCMI_ACTIVATE_DHCP_REPLY = 0x00;
William A. Kennington III5d06cc62019-04-25 02:10:55 -070044constexpr auto DCMI_SET_CONF_PARAM_REQ_PACKET_MAX_SIZE = 0x04;
45constexpr auto DCMI_SET_CONF_PARAM_REQ_PACKET_MIN_SIZE = 0x03;
Patrick Venture0b02be92018-08-31 11:55:55 -070046constexpr auto DHCP_TIMING1 = 0x04; // 4 sec
47constexpr auto DHCP_TIMING2_UPPER = 0x00; // 2 min
Nagaraju Goruganti22be97b2018-02-07 01:19:59 -060048constexpr auto DHCP_TIMING2_LOWER = 0x78;
Patrick Venture0b02be92018-08-31 11:55:55 -070049constexpr auto DHCP_TIMING3_UPPER = 0x00; // 64 sec
Nagaraju Goruganti22be97b2018-02-07 01:19:59 -060050constexpr auto DHCP_TIMING3_LOWER = 0x40;
51// When DHCP Option 12 is enabled the string "SendHostName=true" will be
52// added into n/w configuration file and the parameter
53// SendHostNameEnabled will set to true.
54constexpr auto DHCP_OPT12_ENABLED = "SendHostNameEnabled";
55
Marri Devender Rao66c5fda2018-01-18 10:48:37 -060056constexpr auto SENSOR_VALUE_INTF = "xyz.openbmc_project.Sensor.Value";
57constexpr auto SENSOR_VALUE_PROP = "Value";
Marri Devender Rao66c5fda2018-01-18 10:48:37 -060058
Andrew Geissler50c0c8f2017-07-11 16:18:51 -050059using namespace phosphor::logging;
60
Tom Josephb9d86f42017-07-26 18:03:47 +053061namespace dcmi
62{
Vernon Mauerydca47202023-07-27 11:32:01 -070063constexpr auto assetTagMaxOffset = 62;
64constexpr auto assetTagMaxSize = 63;
65constexpr auto maxBytes = 16;
66constexpr size_t maxCtrlIdStrLen = 63;
Tom Josephb9d86f42017-07-26 18:03:47 +053067
Deepak Kodihalli0b459552018-02-06 06:25:12 -060068// Refer Table 6-14, DCMI Entity ID Extension, DCMI v1.5 spec
Patrick Venture0b02be92018-08-31 11:55:55 -070069static const std::map<uint8_t, std::string> entityIdToName{
70 {0x40, "inlet"}, {0x37, "inlet"}, {0x41, "cpu"},
71 {0x03, "cpu"}, {0x42, "baseboard"}, {0x07, "baseboard"}};
Deepak Kodihalli0b459552018-02-06 06:25:12 -060072
Kirill Pakhomov2c2af2c2018-11-06 16:06:10 +030073bool isDCMIPowerMgmtSupported()
74{
Vernon Maueryf4eb35d2023-07-27 11:08:49 -070075 static bool parsed = false;
76 static bool supported = false;
77 if (!parsed)
78 {
79 auto data = parseJSONConfig(gDCMICapabilitiesConfig);
Kirill Pakhomov2c2af2c2018-11-06 16:06:10 +030080
Vernon Maueryf4eb35d2023-07-27 11:08:49 -070081 supported = (gDCMIPowerMgmtSupported ==
82 data.value(gDCMIPowerMgmtCapability, 0));
83 }
84 return supported;
Kirill Pakhomov2c2af2c2018-11-06 16:06:10 +030085}
86
Vernon Maueryd4222fd2023-07-27 11:26:51 -070087std::optional<uint32_t> getPcap(ipmi::Context::ptr& ctx)
Andrew Geissler50c0c8f2017-07-11 16:18:51 -050088{
Vernon Maueryd4222fd2023-07-27 11:26:51 -070089 std::string service{};
90 boost::system::error_code ec = ipmi::getService(ctx, pcapInterface,
91 pcapPath, service);
92 if (ec.value())
Andrew Geissler50c0c8f2017-07-11 16:18:51 -050093 {
Vernon Maueryd4222fd2023-07-27 11:26:51 -070094 return std::nullopt;
George Liu3e3cc352023-07-26 15:59:31 +080095 }
Vernon Maueryd4222fd2023-07-27 11:26:51 -070096 uint32_t pcap{};
97 ec = ipmi::getDbusProperty(ctx, service, pcapPath, pcapInterface,
98 powerCapProp, pcap);
99 if (ec.value())
George Liu3e3cc352023-07-26 15:59:31 +0800100 {
Vernon Maueryd4222fd2023-07-27 11:26:51 -0700101 log<level::ERR>("Error in getPcap prop",
102 entry("ERROR=%s", ec.message().c_str()));
Tom Josephb9d86f42017-07-26 18:03:47 +0530103 elog<InternalFailure>();
Vernon Maueryd4222fd2023-07-27 11:26:51 -0700104 return std::nullopt;
Andrew Geissler50c0c8f2017-07-11 16:18:51 -0500105 }
Vernon Maueryd4222fd2023-07-27 11:26:51 -0700106 return pcap;
Andrew Geissler50c0c8f2017-07-11 16:18:51 -0500107}
108
Vernon Maueryd4222fd2023-07-27 11:26:51 -0700109std::optional<bool> getPcapEnabled(ipmi::Context::ptr& ctx)
Andrew Geissler50c0c8f2017-07-11 16:18:51 -0500110{
Vernon Maueryd4222fd2023-07-27 11:26:51 -0700111 std::string service{};
112 boost::system::error_code ec = ipmi::getService(ctx, pcapInterface,
113 pcapPath, service);
114 if (ec.value())
Andrew Geissler50c0c8f2017-07-11 16:18:51 -0500115 {
Vernon Maueryd4222fd2023-07-27 11:26:51 -0700116 return std::nullopt;
George Liu3e3cc352023-07-26 15:59:31 +0800117 }
Vernon Maueryd4222fd2023-07-27 11:26:51 -0700118 bool pcapEnabled{};
119 ec = ipmi::getDbusProperty(ctx, service, pcapPath, pcapInterface,
120 powerCapEnableProp, pcapEnabled);
121 if (ec.value())
George Liu3e3cc352023-07-26 15:59:31 +0800122 {
Vernon Maueryd4222fd2023-07-27 11:26:51 -0700123 log<level::ERR>("Error in getPcap prop");
Tom Josephb9d86f42017-07-26 18:03:47 +0530124 elog<InternalFailure>();
Vernon Maueryd4222fd2023-07-27 11:26:51 -0700125 return std::nullopt;
Andrew Geissler50c0c8f2017-07-11 16:18:51 -0500126 }
Vernon Maueryd4222fd2023-07-27 11:26:51 -0700127 return pcapEnabled;
Andrew Geissler50c0c8f2017-07-11 16:18:51 -0500128}
Chris Austen1810bec2015-10-13 12:12:39 -0500129
Vernon Maueryd4222fd2023-07-27 11:26:51 -0700130bool setPcap(ipmi::Context::ptr& ctx, const uint32_t powerCap)
Tom Joseph46fa37d2017-07-26 18:11:55 +0530131{
Vernon Maueryd4222fd2023-07-27 11:26:51 -0700132 std::string service{};
133 boost::system::error_code ec = ipmi::getService(ctx, pcapInterface,
134 pcapPath, service);
135 if (ec.value())
Tom Joseph46fa37d2017-07-26 18:11:55 +0530136 {
Vernon Maueryd4222fd2023-07-27 11:26:51 -0700137 return false;
George Liu3e3cc352023-07-26 15:59:31 +0800138 }
Vernon Maueryd4222fd2023-07-27 11:26:51 -0700139
140 ec = ipmi::setDbusProperty(ctx, service, pcapPath, pcapInterface,
141 powerCapProp, powerCap);
142 if (ec.value())
George Liu3e3cc352023-07-26 15:59:31 +0800143 {
144 log<level::ERR>("Error in setPcap property",
Vernon Maueryd4222fd2023-07-27 11:26:51 -0700145 entry("ERROR=%s", ec.message().c_str()));
Tom Joseph46fa37d2017-07-26 18:11:55 +0530146 elog<InternalFailure>();
Vernon Maueryd4222fd2023-07-27 11:26:51 -0700147 return false;
Tom Joseph46fa37d2017-07-26 18:11:55 +0530148 }
Vernon Maueryd4222fd2023-07-27 11:26:51 -0700149 return true;
Tom Joseph46fa37d2017-07-26 18:11:55 +0530150}
151
Vernon Maueryd4222fd2023-07-27 11:26:51 -0700152bool setPcapEnable(ipmi::Context::ptr& ctx, bool enabled)
Tom Joseph6c8d51b2017-07-26 18:18:06 +0530153{
Vernon Maueryd4222fd2023-07-27 11:26:51 -0700154 std::string service{};
155 boost::system::error_code ec = ipmi::getService(ctx, pcapInterface,
156 pcapPath, service);
157 if (ec.value())
Tom Joseph6c8d51b2017-07-26 18:18:06 +0530158 {
Vernon Maueryd4222fd2023-07-27 11:26:51 -0700159 return false;
George Liu3e3cc352023-07-26 15:59:31 +0800160 }
Vernon Maueryd4222fd2023-07-27 11:26:51 -0700161
162 ec = ipmi::setDbusProperty(ctx, service, pcapPath, pcapInterface,
163 powerCapEnableProp, enabled);
164 if (ec.value())
George Liu3e3cc352023-07-26 15:59:31 +0800165 {
166 log<level::ERR>("Error in setPcapEnabled property",
Vernon Maueryd4222fd2023-07-27 11:26:51 -0700167 entry("ERROR=%s", ec.message().c_str()));
Tom Joseph6c8d51b2017-07-26 18:18:06 +0530168 elog<InternalFailure>();
Vernon Maueryd4222fd2023-07-27 11:26:51 -0700169 return false;
Tom Joseph6c8d51b2017-07-26 18:18:06 +0530170 }
Vernon Maueryd4222fd2023-07-27 11:26:51 -0700171 return true;
Tom Joseph6c8d51b2017-07-26 18:18:06 +0530172}
173
Vernon Mauerydca47202023-07-27 11:32:01 -0700174std::optional<std::string> readAssetTag(ipmi::Context::ptr& ctx)
Tom Josephbe5eaa12017-07-12 19:54:44 +0530175{
Tom Josephbe5eaa12017-07-12 19:54:44 +0530176 // Read the object tree with the inventory root to figure out the object
177 // that has implemented the Asset tag interface.
Vernon Mauerydca47202023-07-27 11:32:01 -0700178 ipmi::DbusObjectInfo objectInfo;
179 boost::system::error_code ec = getDbusObject(
180 ctx, dcmi::assetTagIntf, ipmi::sensor::inventoryRoot, "", objectInfo);
181 if (ec.value())
Tom Josephbe5eaa12017-07-12 19:54:44 +0530182 {
Vernon Mauerydca47202023-07-27 11:32:01 -0700183 return std::nullopt;
George Liu3e3cc352023-07-26 15:59:31 +0800184 }
Vernon Mauerydca47202023-07-27 11:32:01 -0700185
186 std::string assetTag{};
187 ec = ipmi::getDbusProperty(ctx, objectInfo.second, objectInfo.first,
188 dcmi::assetTagIntf, dcmi::assetTagProp,
189 assetTag);
190 if (ec.value())
George Liu3e3cc352023-07-26 15:59:31 +0800191 {
192 log<level::ERR>("Error in reading asset tag",
Vernon Mauerydca47202023-07-27 11:32:01 -0700193 entry("ERROR=%s", ec.message().c_str()));
Tom Josephbe5eaa12017-07-12 19:54:44 +0530194 elog<InternalFailure>();
Vernon Mauerydca47202023-07-27 11:32:01 -0700195 return std::nullopt;
Tom Josephbe5eaa12017-07-12 19:54:44 +0530196 }
Vernon Mauerydca47202023-07-27 11:32:01 -0700197
198 return assetTag;
Tom Josephbe5eaa12017-07-12 19:54:44 +0530199}
200
Vernon Mauerydca47202023-07-27 11:32:01 -0700201bool writeAssetTag(ipmi::Context::ptr& ctx, const std::string& assetTag)
Tom Josephbe5b9892017-07-15 00:55:23 +0530202{
Tom Josephbe5b9892017-07-15 00:55:23 +0530203 // Read the object tree with the inventory root to figure out the object
204 // that has implemented the Asset tag interface.
Vernon Mauerydca47202023-07-27 11:32:01 -0700205 ipmi::DbusObjectInfo objectInfo;
206 boost::system::error_code ec = getDbusObject(
207 ctx, dcmi::assetTagIntf, ipmi::sensor::inventoryRoot, "", objectInfo);
208 if (ec.value())
Tom Josephbe5b9892017-07-15 00:55:23 +0530209 {
Vernon Mauerydca47202023-07-27 11:32:01 -0700210 return false;
George Liu3e3cc352023-07-26 15:59:31 +0800211 }
Vernon Mauerydca47202023-07-27 11:32:01 -0700212
213 ec = ipmi::setDbusProperty(ctx, objectInfo.second, objectInfo.first,
214 dcmi::assetTagIntf, dcmi::assetTagProp,
215 assetTag);
216 if (ec.value())
George Liu3e3cc352023-07-26 15:59:31 +0800217 {
218 log<level::ERR>("Error in writing asset tag",
Vernon Mauerydca47202023-07-27 11:32:01 -0700219 entry("ERROR=%s", ec.message().c_str()));
Tom Josephbe5b9892017-07-15 00:55:23 +0530220 elog<InternalFailure>();
Vernon Mauerydca47202023-07-27 11:32:01 -0700221 return false;
Tom Josephbe5b9892017-07-15 00:55:23 +0530222 }
Vernon Mauerydca47202023-07-27 11:32:01 -0700223 return true;
Tom Josephbe5b9892017-07-15 00:55:23 +0530224}
225
Vernon Maueryefb5ae52023-07-27 11:35:43 -0700226std::optional<std::string> getHostName(ipmi::Context::ptr& ctx)
Vladislav Vovchenko8f7a6f62017-08-17 00:31:14 +0300227{
Vernon Maueryefb5ae52023-07-27 11:35:43 -0700228 std::string service{};
229 boost::system::error_code ec = ipmi::getService(ctx, networkConfigIntf,
230 networkConfigObj, service);
231 if (ec.value())
232 {
233 return std::nullopt;
234 }
235 std::string hostname{};
236 ec = ipmi::getDbusProperty(ctx, service, networkConfigObj,
237 networkConfigIntf, hostNameProp, hostname);
238 if (ec.value())
239 {
240 log<level::ERR>("Error fetching hostname");
241 elog<InternalFailure>();
242 return std::nullopt;
243 }
244 return hostname;
Vladislav Vovchenko8f7a6f62017-08-17 00:31:14 +0300245}
246
Thang Tran55cbf552023-01-31 14:43:02 +0700247EthernetInterface::DHCPConf getDHCPEnabled()
Nagaraju Goruganti22be97b2018-02-07 01:19:59 -0600248{
Patrick Williams5d82f472022-07-22 19:26:53 -0500249 sdbusplus::bus_t bus{ipmid_get_sd_bus_connection()};
Nagaraju Goruganti22be97b2018-02-07 01:19:59 -0600250
Johnathan Mantey74a21022018-12-13 13:17:56 -0800251 auto ethdevice = ipmi::getChannelName(ethernetDefaultChannelNum);
Patrick Williamsfbc6c9d2023-05-10 07:50:16 -0500252 auto ethernetObj = ipmi::getDbusObject(bus, ethernetIntf, networkRoot,
253 ethdevice);
Nagaraju Goruganti22be97b2018-02-07 01:19:59 -0600254 auto service = ipmi::getService(bus, ethernetIntf, ethernetObj.first);
Patrick Venture0b02be92018-08-31 11:55:55 -0700255 auto value = ipmi::getDbusProperty(bus, service, ethernetObj.first,
256 ethernetIntf, "DHCPEnabled");
Nagaraju Goruganti22be97b2018-02-07 01:19:59 -0600257
Thang Tran55cbf552023-01-31 14:43:02 +0700258 return EthernetInterface::convertDHCPConfFromString(
259 std::get<std::string>(value));
Nagaraju Goruganti22be97b2018-02-07 01:19:59 -0600260}
261
262bool getDHCPOption(std::string prop)
263{
Patrick Williams5d82f472022-07-22 19:26:53 -0500264 sdbusplus::bus_t bus{ipmid_get_sd_bus_connection()};
Nagaraju Goruganti22be97b2018-02-07 01:19:59 -0600265
266 auto service = ipmi::getService(bus, dhcpIntf, dhcpObj);
267 auto value = ipmi::getDbusProperty(bus, service, dhcpObj, dhcpIntf, prop);
268
Vernon Maueryf442e112019-04-09 11:44:36 -0700269 return std::get<bool>(value);
Nagaraju Goruganti22be97b2018-02-07 01:19:59 -0600270}
271
Nagaraju Goruganti22be97b2018-02-07 01:19:59 -0600272void setDHCPOption(std::string prop, bool value)
273{
Patrick Williams5d82f472022-07-22 19:26:53 -0500274 sdbusplus::bus_t bus{ipmid_get_sd_bus_connection()};
Nagaraju Goruganti22be97b2018-02-07 01:19:59 -0600275
276 auto service = ipmi::getService(bus, dhcpIntf, dhcpObj);
277 ipmi::setDbusProperty(bus, service, dhcpObj, dhcpIntf, prop, value);
278}
279
Kirill Pakhomova2573622018-11-02 19:00:18 +0300280Json parseJSONConfig(const std::string& configFile)
Deepak Kodihalli0b459552018-02-06 06:25:12 -0600281{
282 std::ifstream jsonFile(configFile);
283 if (!jsonFile.is_open())
284 {
285 log<level::ERR>("Temperature readings JSON file not found");
286 elog<InternalFailure>();
287 }
288
289 auto data = Json::parse(jsonFile, nullptr, false);
290 if (data.is_discarded())
291 {
292 log<level::ERR>("Temperature readings JSON parser failure");
293 elog<InternalFailure>();
294 }
295
296 return data;
297}
298
Tom Josephbe5eaa12017-07-12 19:54:44 +0530299} // namespace dcmi
Chris Austen1810bec2015-10-13 12:12:39 -0500300
Vernon Maueryd4222fd2023-07-27 11:26:51 -0700301constexpr uint8_t exceptionPowerOff = 0x01;
302ipmi::RspType<uint16_t, // reserved
303 uint8_t, // exception actions
304 uint16_t, // power limit requested in watts
305 uint32_t, // correction time in milliseconds
306 uint16_t, // reserved
307 uint16_t // statistics sampling period in seconds
308 >
309 getPowerLimit(ipmi::Context::ptr ctx, uint16_t reserved)
Tom Josephb9d86f42017-07-26 18:03:47 +0530310{
Kirill Pakhomov2c2af2c2018-11-06 16:06:10 +0300311 if (!dcmi::isDCMIPowerMgmtSupported())
312 {
Vernon Maueryd4222fd2023-07-27 11:26:51 -0700313 return ipmi::responseInvalidCommand();
Kirill Pakhomov2c2af2c2018-11-06 16:06:10 +0300314 }
Vernon Maueryd4222fd2023-07-27 11:26:51 -0700315 if (reserved)
Tom Josephb9d86f42017-07-26 18:03:47 +0530316 {
Vernon Maueryd4222fd2023-07-27 11:26:51 -0700317 return ipmi::responseInvalidFieldRequest();
Tom Josephb9d86f42017-07-26 18:03:47 +0530318 }
319
Vernon Maueryd4222fd2023-07-27 11:26:51 -0700320 std::optional<uint16_t> pcapValue = dcmi::getPcap(ctx);
321 std::optional<bool> pcapEnable = dcmi::getPcapEnabled(ctx);
322 if (!pcapValue || !pcapEnable)
323 {
324 return ipmi::responseUnspecifiedError();
325 }
326
327 constexpr uint16_t reserved1{};
328 constexpr uint16_t reserved2{};
Tom Josephb9d86f42017-07-26 18:03:47 +0530329 /*
330 * Exception action if power limit is exceeded and cannot be controlled
331 * with the correction time limit is hardcoded to Hard Power Off system
332 * and log event to SEL.
333 */
Vernon Maueryd4222fd2023-07-27 11:26:51 -0700334 constexpr uint8_t exception = exceptionPowerOff;
Tom Josephb9d86f42017-07-26 18:03:47 +0530335 /*
336 * Correction time limit and Statistics sampling period is currently not
337 * populated.
338 */
Vernon Maueryd4222fd2023-07-27 11:26:51 -0700339 constexpr uint32_t correctionTime{};
340 constexpr uint16_t statsPeriod{};
341 if (!pcapEnable)
Tom Josephb9d86f42017-07-26 18:03:47 +0530342 {
Vernon Maueryd4222fd2023-07-27 11:26:51 -0700343 constexpr ipmi::Cc responseNoPowerLimitSet = 0x80;
344 constexpr uint16_t noPcap{};
345 return ipmi::response(responseNoPowerLimitSet, reserved1, exception,
346 noPcap, correctionTime, reserved2, statsPeriod);
Tom Josephb9d86f42017-07-26 18:03:47 +0530347 }
Vernon Maueryd4222fd2023-07-27 11:26:51 -0700348 return ipmi::responseSuccess(reserved1, exception, *pcapValue,
349 correctionTime, reserved2, statsPeriod);
Tom Josephb9d86f42017-07-26 18:03:47 +0530350}
351
Vernon Maueryd4222fd2023-07-27 11:26:51 -0700352ipmi::RspType<> setPowerLimit(ipmi::Context::ptr& ctx, uint16_t reserved1,
353 uint8_t exceptionAction, uint16_t powerLimit,
354 uint32_t correctionTime, uint16_t reserved2,
355 uint16_t statsPeriod)
Tom Joseph46fa37d2017-07-26 18:11:55 +0530356{
Kirill Pakhomov2c2af2c2018-11-06 16:06:10 +0300357 if (!dcmi::isDCMIPowerMgmtSupported())
358 {
Kirill Pakhomov2c2af2c2018-11-06 16:06:10 +0300359 log<level::ERR>("DCMI Power management is unsupported!");
Vernon Maueryd4222fd2023-07-27 11:26:51 -0700360 return ipmi::responseInvalidCommand();
Kirill Pakhomov2c2af2c2018-11-06 16:06:10 +0300361 }
362
Vernon Maueryd4222fd2023-07-27 11:26:51 -0700363 // Only process the power limit requested in watts. Return errors
364 // for other fields that are set
365 if (reserved1 || reserved2 || correctionTime || statsPeriod ||
366 exceptionAction != exceptionPowerOff)
Tom Joseph46fa37d2017-07-26 18:11:55 +0530367 {
Vernon Maueryd4222fd2023-07-27 11:26:51 -0700368 return ipmi::responseInvalidFieldRequest();
Tom Joseph46fa37d2017-07-26 18:11:55 +0530369 }
Vernon Maueryd4222fd2023-07-27 11:26:51 -0700370
371 if (!dcmi::setPcap(ctx, powerLimit))
Tom Joseph46fa37d2017-07-26 18:11:55 +0530372 {
Vernon Maueryd4222fd2023-07-27 11:26:51 -0700373 return ipmi::responseUnspecifiedError();
Tom Joseph46fa37d2017-07-26 18:11:55 +0530374 }
375
Vernon Maueryd4222fd2023-07-27 11:26:51 -0700376 log<level::INFO>("Set Power Cap", entry("POWERCAP=%u", powerLimit));
Tom Joseph46fa37d2017-07-26 18:11:55 +0530377
Vernon Maueryd4222fd2023-07-27 11:26:51 -0700378 return ipmi::responseSuccess();
Tom Joseph46fa37d2017-07-26 18:11:55 +0530379}
380
Vernon Maueryd4222fd2023-07-27 11:26:51 -0700381ipmi::RspType<> applyPowerLimit(ipmi::Context::ptr& ctx, bool enabled,
382 uint7_t reserved1, uint16_t reserved2)
Tom Joseph6c8d51b2017-07-26 18:18:06 +0530383{
Kirill Pakhomov2c2af2c2018-11-06 16:06:10 +0300384 if (!dcmi::isDCMIPowerMgmtSupported())
385 {
Kirill Pakhomov2c2af2c2018-11-06 16:06:10 +0300386 log<level::ERR>("DCMI Power management is unsupported!");
Vernon Maueryd4222fd2023-07-27 11:26:51 -0700387 return ipmi::responseInvalidCommand();
388 }
389 if (reserved1 || reserved2)
390 {
391 return ipmi::responseInvalidFieldRequest();
Kirill Pakhomov2c2af2c2018-11-06 16:06:10 +0300392 }
393
Vernon Maueryd4222fd2023-07-27 11:26:51 -0700394 if (!dcmi::setPcapEnable(ctx, enabled))
Tom Joseph6c8d51b2017-07-26 18:18:06 +0530395 {
Vernon Maueryd4222fd2023-07-27 11:26:51 -0700396 return ipmi::responseUnspecifiedError();
Tom Joseph6c8d51b2017-07-26 18:18:06 +0530397 }
398
399 log<level::INFO>("Set Power Cap Enable",
Vernon Maueryd4222fd2023-07-27 11:26:51 -0700400 entry("POWERCAPENABLE=%u", static_cast<uint8_t>(enabled)));
Tom Joseph6c8d51b2017-07-26 18:18:06 +0530401
Vernon Maueryd4222fd2023-07-27 11:26:51 -0700402 return ipmi::responseSuccess();
Tom Joseph6c8d51b2017-07-26 18:18:06 +0530403}
404
Vernon Mauerydca47202023-07-27 11:32:01 -0700405ipmi::RspType<uint8_t, // total tag length
406 std::vector<char> // tag data
407 >
408 getAssetTag(ipmi::Context::ptr& ctx, uint8_t offset, uint8_t count)
Tom Joseph6f6dd4d2017-07-12 20:07:11 +0530409{
Vernon Mauerydca47202023-07-27 11:32:01 -0700410 // Verify offset to read and number of bytes to read are not exceeding
411 // the range.
412 if ((offset > dcmi::assetTagMaxOffset) || (count > dcmi::maxBytes) ||
413 ((offset + count) > dcmi::assetTagMaxSize))
Tom Joseph6f6dd4d2017-07-12 20:07:11 +0530414 {
Vernon Mauerydca47202023-07-27 11:32:01 -0700415 return ipmi::responseParmOutOfRange();
Tom Joseph6f6dd4d2017-07-12 20:07:11 +0530416 }
417
Vernon Mauerydca47202023-07-27 11:32:01 -0700418 std::optional<std::string> assetTagResp = dcmi::readAssetTag(ctx);
419 if (!assetTagResp)
Tom Joseph6f6dd4d2017-07-12 20:07:11 +0530420 {
Vernon Mauerydca47202023-07-27 11:32:01 -0700421 return ipmi::responseUnspecifiedError();
Tom Joseph6f6dd4d2017-07-12 20:07:11 +0530422 }
423
Vernon Mauerydca47202023-07-27 11:32:01 -0700424 std::string& assetTag = assetTagResp.value();
425 // If the asset tag is longer than 63 bytes, restrict it to 63 bytes to
426 // suit Get Asset Tag command.
Tom Joseph6f6dd4d2017-07-12 20:07:11 +0530427 if (assetTag.size() > dcmi::assetTagMaxSize)
428 {
429 assetTag.resize(dcmi::assetTagMaxSize);
430 }
431
Vernon Mauerydca47202023-07-27 11:32:01 -0700432 if (offset >= assetTag.size())
Tom Joseph6f6dd4d2017-07-12 20:07:11 +0530433 {
Vernon Mauerydca47202023-07-27 11:32:01 -0700434 return ipmi::responseParmOutOfRange();
Tom Joseph6f6dd4d2017-07-12 20:07:11 +0530435 }
436
Vernon Mauerydca47202023-07-27 11:32:01 -0700437 // silently truncate reads beyond the end of assetTag
438 if ((offset + count) >= assetTag.size())
439 {
440 count = assetTag.size() - offset;
441 }
Tom Joseph6f6dd4d2017-07-12 20:07:11 +0530442
Vernon Mauerydca47202023-07-27 11:32:01 -0700443 auto totalTagSize = static_cast<uint8_t>(assetTag.size());
444 std::vector<char> data{assetTag.begin() + offset,
445 assetTag.begin() + offset + count};
Tom Joseph6f6dd4d2017-07-12 20:07:11 +0530446
Vernon Mauerydca47202023-07-27 11:32:01 -0700447 return ipmi::responseSuccess(totalTagSize, data);
Tom Joseph6f6dd4d2017-07-12 20:07:11 +0530448}
449
Vernon Mauerydca47202023-07-27 11:32:01 -0700450ipmi::RspType<uint8_t // new asset tag length
451 >
452 setAssetTag(ipmi::Context::ptr& ctx, uint8_t offset, uint8_t count,
453 const std::vector<char>& data)
Tom Joseph545dd232017-07-12 20:20:49 +0530454{
Vernon Mauerydca47202023-07-27 11:32:01 -0700455 // Verify offset to read and number of bytes to read are not exceeding
456 // the range.
457 if ((offset > dcmi::assetTagMaxOffset) || (count > dcmi::maxBytes) ||
458 ((offset + count) > dcmi::assetTagMaxSize))
Tom Joseph545dd232017-07-12 20:20:49 +0530459 {
Vernon Mauerydca47202023-07-27 11:32:01 -0700460 return ipmi::responseParmOutOfRange();
461 }
462 if (data.size() != count)
463 {
464 return ipmi::responseReqDataLenInvalid();
Tom Joseph545dd232017-07-12 20:20:49 +0530465 }
466
Vernon Mauerydca47202023-07-27 11:32:01 -0700467 std::optional<std::string> assetTagResp = dcmi::readAssetTag(ctx);
468 if (!assetTagResp)
Tom Joseph545dd232017-07-12 20:20:49 +0530469 {
Vernon Mauerydca47202023-07-27 11:32:01 -0700470 return ipmi::responseUnspecifiedError();
Tom Joseph545dd232017-07-12 20:20:49 +0530471 }
Vernon Mauerydca47202023-07-27 11:32:01 -0700472
473 std::string& assetTag = assetTagResp.value();
474
475 if (offset > assetTag.size())
Tom Joseph545dd232017-07-12 20:20:49 +0530476 {
Vernon Mauerydca47202023-07-27 11:32:01 -0700477 return ipmi::responseParmOutOfRange();
Tom Joseph545dd232017-07-12 20:20:49 +0530478 }
Vernon Mauerydca47202023-07-27 11:32:01 -0700479
480 // operation is to truncate at offset and append new data
481 assetTag.resize(offset);
482 assetTag.append(data.begin(), data.end());
483
484 if (!dcmi::writeAssetTag(ctx, assetTag))
485 {
486 return ipmi::responseUnspecifiedError();
487 }
488
489 auto totalTagSize = static_cast<uint8_t>(assetTag.size());
490 return ipmi::responseSuccess(totalTagSize);
Tom Joseph545dd232017-07-12 20:20:49 +0530491}
492
Vernon Maueryefb5ae52023-07-27 11:35:43 -0700493ipmi::RspType<uint8_t, // length
494 std::vector<char> // data
495 >
496 getMgmntCtrlIdStr(ipmi::Context::ptr& ctx, uint8_t offset, uint8_t count)
Vladislav Vovchenko8f7a6f62017-08-17 00:31:14 +0300497{
Vernon Maueryefb5ae52023-07-27 11:35:43 -0700498 if (count > dcmi::maxBytes || offset + count > dcmi::maxCtrlIdStrLen)
Vladislav Vovchenko8f7a6f62017-08-17 00:31:14 +0300499 {
Vernon Maueryefb5ae52023-07-27 11:35:43 -0700500 return ipmi::responseParmOutOfRange();
Vladislav Vovchenko8f7a6f62017-08-17 00:31:14 +0300501 }
502
Vernon Maueryefb5ae52023-07-27 11:35:43 -0700503 std::optional<std::string> hostnameResp = dcmi::getHostName(ctx);
504 if (!hostnameResp)
Vladislav Vovchenko8f7a6f62017-08-17 00:31:14 +0300505 {
Vernon Maueryefb5ae52023-07-27 11:35:43 -0700506 return ipmi::responseUnspecifiedError();
Vladislav Vovchenko8f7a6f62017-08-17 00:31:14 +0300507 }
508
Vernon Maueryefb5ae52023-07-27 11:35:43 -0700509 std::string& hostname = hostnameResp.value();
510 // If the id string is longer than 63 bytes, restrict it to 63 bytes to
511 // suit set management ctrl str command.
512 if (hostname.size() > dcmi::maxCtrlIdStrLen)
Vladislav Vovchenko8f7a6f62017-08-17 00:31:14 +0300513 {
Vernon Maueryefb5ae52023-07-27 11:35:43 -0700514 hostname.resize(dcmi::maxCtrlIdStrLen);
Vladislav Vovchenko8f7a6f62017-08-17 00:31:14 +0300515 }
Vladislav Vovchenko8f7a6f62017-08-17 00:31:14 +0300516
Vernon Maueryefb5ae52023-07-27 11:35:43 -0700517 if (offset >= hostname.size())
518 {
519 return ipmi::responseParmOutOfRange();
520 }
521
522 // silently truncate reads beyond the end of hostname
523 if ((offset + count) >= hostname.size())
524 {
525 count = hostname.size() - offset;
526 }
527
528 auto nameSize = static_cast<uint8_t>(hostname.size());
529 std::vector<char> data{hostname.begin() + offset,
530 hostname.begin() + offset + count};
531
532 return ipmi::responseSuccess(nameSize, data);
Vladislav Vovchenko8f7a6f62017-08-17 00:31:14 +0300533}
534
Vernon Maueryefb5ae52023-07-27 11:35:43 -0700535ipmi::RspType<uint8_t> setMgmntCtrlIdStr(ipmi::Context::ptr& ctx,
536 uint8_t offset, uint8_t count,
537 std::vector<char> data)
Vladislav Vovchenko8f7a6f62017-08-17 00:31:14 +0300538{
Vernon Maueryefb5ae52023-07-27 11:35:43 -0700539 if ((offset > dcmi::maxCtrlIdStrLen) || (count > dcmi::maxBytes) ||
540 ((offset + count) > dcmi::maxCtrlIdStrLen))
Vladislav Vovchenko8f7a6f62017-08-17 00:31:14 +0300541 {
Vernon Maueryefb5ae52023-07-27 11:35:43 -0700542 return ipmi::responseParmOutOfRange();
543 }
544 if (data.size() != count)
545 {
546 return ipmi::responseReqDataLenInvalid();
547 }
548 bool terminalWrite{data.back() == '\0'};
549 if (terminalWrite)
550 {
551 // remove the null termination from the data (no need with std::string)
552 data.resize(count - 1);
Vladislav Vovchenko8f7a6f62017-08-17 00:31:14 +0300553 }
554
Vernon Maueryefb5ae52023-07-27 11:35:43 -0700555 static std::string hostname{};
556 // read in the current value if not starting at offset 0
557 if (hostname.size() == 0 && offset != 0)
Vladislav Vovchenko8f7a6f62017-08-17 00:31:14 +0300558 {
Vernon Maueryefb5ae52023-07-27 11:35:43 -0700559 /* read old ctrlIdStr */
560 std::optional<std::string> hostnameResp = dcmi::getHostName(ctx);
561 if (!hostnameResp)
Vladislav Vovchenko8f7a6f62017-08-17 00:31:14 +0300562 {
Vernon Maueryefb5ae52023-07-27 11:35:43 -0700563 return ipmi::responseUnspecifiedError();
Vladislav Vovchenko8f7a6f62017-08-17 00:31:14 +0300564 }
Vernon Maueryefb5ae52023-07-27 11:35:43 -0700565 hostname = hostnameResp.value();
566 hostname.resize(offset);
Vladislav Vovchenko8f7a6f62017-08-17 00:31:14 +0300567 }
568
Vernon Maueryefb5ae52023-07-27 11:35:43 -0700569 // operation is to truncate at offset and append new data
570 hostname.append(data.begin(), data.end());
571
572 // do the update if this is the last write
573 if (terminalWrite)
574 {
575 boost::system::error_code ec = ipmi::setDbusProperty(
576 ctx, dcmi::networkServiceName, dcmi::networkConfigObj,
577 dcmi::networkConfigIntf, dcmi::hostNameProp, hostname);
578 hostname.clear();
579 if (ec.value())
580 {
581 return ipmi::responseUnspecifiedError();
582 }
583 }
584
585 auto totalIdSize = static_cast<uint8_t>(offset + count);
586 return ipmi::responseSuccess(totalIdSize);
Vladislav Vovchenko8f7a6f62017-08-17 00:31:14 +0300587}
588
Patrick Venture0b02be92018-08-31 11:55:55 -0700589// List of the capabilities under each parameter
590dcmi::DCMICaps dcmiCaps = {
591 // Supported DCMI Capabilities
592 {dcmi::DCMICapParameters::SUPPORTED_DCMI_CAPS,
593 {3,
594 {{"PowerManagement", 2, 0, 1},
595 {"OOBSecondaryLan", 3, 2, 1},
596 {"SerialTMODE", 3, 1, 1},
597 {"InBandSystemInterfaceChannel", 3, 0, 1}}}},
598 // Mandatory Platform Attributes
599 {dcmi::DCMICapParameters::MANDATORY_PLAT_ATTRIBUTES,
600 {5,
601 {{"SELAutoRollOver", 1, 15, 1},
602 {"FlushEntireSELUponRollOver", 1, 14, 1},
603 {"RecordLevelSELFlushUponRollOver", 1, 13, 1},
604 {"NumberOfSELEntries", 1, 0, 12},
605 {"TempMonitoringSamplingFreq", 5, 0, 8}}}},
606 // Optional Platform Attributes
607 {dcmi::DCMICapParameters::OPTIONAL_PLAT_ATTRIBUTES,
608 {2,
609 {{"PowerMgmtDeviceSlaveAddress", 1, 1, 7},
610 {"BMCChannelNumber", 2, 4, 4},
611 {"DeviceRivision", 2, 0, 4}}}},
612 // Manageability Access Attributes
613 {dcmi::DCMICapParameters::MANAGEABILITY_ACCESS_ATTRIBUTES,
614 {3,
615 {{"MandatoryPrimaryLanOOBSupport", 1, 0, 8},
616 {"OptionalSecondaryLanOOBSupport", 2, 0, 8},
617 {"OptionalSerialOOBMTMODECapability", 3, 0, 8}}}}};
Dhruvaraj Subhashchandrane29be412018-01-16 05:11:56 -0600618
Willy Tu11d68892022-01-20 10:37:34 -0800619ipmi_ret_t getDCMICapabilities(ipmi_netfn_t, ipmi_cmd_t, ipmi_request_t request,
620 ipmi_response_t response,
621 ipmi_data_len_t data_len, ipmi_context_t)
Dhruvaraj Subhashchandrane29be412018-01-16 05:11:56 -0600622{
Kirill Pakhomova2573622018-11-02 19:00:18 +0300623 std::ifstream dcmiCapFile(dcmi::gDCMICapabilitiesConfig);
Dhruvaraj Subhashchandrane29be412018-01-16 05:11:56 -0600624 if (!dcmiCapFile.is_open())
625 {
626 log<level::ERR>("DCMI Capabilities file not found");
627 return IPMI_CC_UNSPECIFIED_ERROR;
628 }
629
630 auto data = nlohmann::json::parse(dcmiCapFile, nullptr, false);
631 if (data.is_discarded())
632 {
633 log<level::ERR>("DCMI Capabilities JSON parser failure");
634 return IPMI_CC_UNSPECIFIED_ERROR;
635 }
636
Patrick Venture0b02be92018-08-31 11:55:55 -0700637 auto requestData =
638 reinterpret_cast<const dcmi::GetDCMICapRequest*>(request);
Dhruvaraj Subhashchandrane29be412018-01-16 05:11:56 -0600639
Patrick Venture0b02be92018-08-31 11:55:55 -0700640 // get list of capabilities in a parameter
Dhruvaraj Subhashchandrane29be412018-01-16 05:11:56 -0600641 auto caps =
642 dcmiCaps.find(static_cast<dcmi::DCMICapParameters>(requestData->param));
643 if (caps == dcmiCaps.end())
644 {
645 log<level::ERR>("Invalid input parameter");
646 return IPMI_CC_INVALID_FIELD_REQUEST;
647 }
648
Patrick Venture0b02be92018-08-31 11:55:55 -0700649 auto responseData = reinterpret_cast<dcmi::GetDCMICapResponse*>(response);
Dhruvaraj Subhashchandrane29be412018-01-16 05:11:56 -0600650
Patrick Venture0b02be92018-08-31 11:55:55 -0700651 // For each capabilities in a parameter fill the data from
652 // the json file based on the capability name.
Dhruvaraj Subhashchandrane29be412018-01-16 05:11:56 -0600653 for (auto cap : caps->second.capList)
654 {
Patrick Venture0b02be92018-08-31 11:55:55 -0700655 // If the data is beyond first byte boundary, insert in a
656 // 16bit pattern for example number of SEL entries are represented
657 // in 12bits.
Kirill Pakhomovdb5d9b02018-11-06 19:17:51 +0300658 if ((cap.length + cap.position) > dcmi::gByteBitSize)
Dhruvaraj Subhashchandrane29be412018-01-16 05:11:56 -0600659 {
Kirill Pakhomovdb5d9b02018-11-06 19:17:51 +0300660 uint16_t val = data.value(cap.name.c_str(), 0);
661 // According to DCMI spec v1.5, max number of SEL entries is
662 // 4096, but bit 12b of DCMI capabilities Mandatory Platform
663 // Attributes field is reserved and therefore we can use only
664 // the provided 12 bits with maximum value of 4095.
665 // We're playing safe here by applying the mask
666 // to ensure that provided value will fit into 12 bits.
667 if (cap.length > dcmi::gByteBitSize)
668 {
669 val &= dcmi::gMaxSELEntriesMask;
670 }
Dhruvaraj Subhashchandrane29be412018-01-16 05:11:56 -0600671 val <<= cap.position;
Kirill Pakhomovdb5d9b02018-11-06 19:17:51 +0300672 responseData->data[cap.bytePosition - 1] |=
673 static_cast<uint8_t>(val);
674 responseData->data[cap.bytePosition] |= val >> dcmi::gByteBitSize;
Dhruvaraj Subhashchandrane29be412018-01-16 05:11:56 -0600675 }
676 else
677 {
678 responseData->data[cap.bytePosition - 1] |=
679 data.value(cap.name.c_str(), 0) << cap.position;
680 }
681 }
682
Dhruvaraj Subhashchandrane29be412018-01-16 05:11:56 -0600683 responseData->major = DCMI_SPEC_MAJOR_VERSION;
684 responseData->minor = DCMI_SPEC_MINOR_VERSION;
685 responseData->paramRevision = DCMI_PARAMETER_REVISION;
686 *data_len = sizeof(*responseData) + caps->second.size;
687
688 return IPMI_CC_OK;
689}
690
Deepak Kodihalliee717d72018-01-24 04:53:09 -0600691namespace dcmi
692{
693namespace temp_readings
694{
695
Deepak Kodihallib1e8fba2018-01-24 04:57:10 -0600696Temperature readTemp(const std::string& dbusService,
697 const std::string& dbusPath)
698{
699 // Read the temperature value from d-bus object. Need some conversion.
700 // As per the interface xyz.openbmc_project.Sensor.Value, the temperature
James Feist9cc0ea52018-10-09 10:53:11 -0700701 // is an double and in degrees C. It needs to be scaled by using the
Deepak Kodihallib1e8fba2018-01-24 04:57:10 -0600702 // formula Value * 10^Scale. The ipmi spec has the temperature as a uint8_t,
703 // with a separate single bit for the sign.
704
Patrick Williams5d82f472022-07-22 19:26:53 -0500705 sdbusplus::bus_t bus{ipmid_get_sd_bus_connection()};
Patrick Venture0b02be92018-08-31 11:55:55 -0700706 auto result = ipmi::getAllDbusProperties(
707 bus, dbusService, dbusPath, "xyz.openbmc_project.Sensor.Value");
Patrick Williamsfbc6c9d2023-05-10 07:50:16 -0500708 auto temperature = std::visit(ipmi::VariantToDoubleVisitor(),
709 result.at("Value"));
James Feist9cc0ea52018-10-09 10:53:11 -0700710 double absTemp = std::abs(temperature);
Deepak Kodihallib1e8fba2018-01-24 04:57:10 -0600711
James Feist9cc0ea52018-10-09 10:53:11 -0700712 auto findFactor = result.find("Scale");
713 double factor = 0.0;
714 if (findFactor != result.end())
Deepak Kodihallib1e8fba2018-01-24 04:57:10 -0600715 {
Vernon Maueryf442e112019-04-09 11:44:36 -0700716 factor = std::visit(ipmi::VariantToDoubleVisitor(), findFactor->second);
Deepak Kodihallib1e8fba2018-01-24 04:57:10 -0600717 }
James Feist9cc0ea52018-10-09 10:53:11 -0700718 double scale = std::pow(10, factor);
719
720 auto tempDegrees = absTemp * scale;
Deepak Kodihallib1e8fba2018-01-24 04:57:10 -0600721 // Max absolute temp as per ipmi spec is 128.
722 if (tempDegrees > maxTemp)
723 {
724 tempDegrees = maxTemp;
725 }
726
727 return std::make_tuple(static_cast<uint8_t>(tempDegrees),
728 (temperature < 0));
729}
730
Deepak Kodihalliee717d72018-01-24 04:53:09 -0600731std::tuple<Response, NumInstances> read(const std::string& type,
732 uint8_t instance)
733{
Deepak Kodihallib1e8fba2018-01-24 04:57:10 -0600734 Response response{};
Patrick Williams5d82f472022-07-22 19:26:53 -0500735 sdbusplus::bus_t bus{ipmid_get_sd_bus_connection()};
Deepak Kodihallib1e8fba2018-01-24 04:57:10 -0600736
737 if (!instance)
738 {
739 log<level::ERR>("Expected non-zero instance");
740 elog<InternalFailure>();
741 }
742
Kirill Pakhomova2573622018-11-02 19:00:18 +0300743 auto data = parseJSONConfig(gDCMISensorsConfig);
Deepak Kodihallib1e8fba2018-01-24 04:57:10 -0600744 static const std::vector<Json> empty{};
745 std::vector<Json> readings = data.value(type, empty);
746 size_t numInstances = readings.size();
747 for (const auto& j : readings)
748 {
749 uint8_t instanceNum = j.value("instance", 0);
750 // Not the instance we're interested in
751 if (instanceNum != instance)
752 {
753 continue;
754 }
755
756 std::string path = j.value("dbus", "");
757 std::string service;
758 try
759 {
Patrick Williamsfbc6c9d2023-05-10 07:50:16 -0500760 service = ipmi::getService(bus, "xyz.openbmc_project.Sensor.Value",
761 path);
Deepak Kodihallib1e8fba2018-01-24 04:57:10 -0600762 }
Patrick Williamsa2ad2da2021-10-06 12:21:46 -0500763 catch (const std::exception& e)
Deepak Kodihallib1e8fba2018-01-24 04:57:10 -0600764 {
765 log<level::DEBUG>(e.what());
766 return std::make_tuple(response, numInstances);
767 }
768
769 response.instance = instance;
770 uint8_t temp{};
771 bool sign{};
772 std::tie(temp, sign) = readTemp(service, path);
773 response.temperature = temp;
774 response.sign = sign;
775
776 // Found the instance we're interested in
777 break;
778 }
779
780 if (numInstances > maxInstances)
781 {
782 numInstances = maxInstances;
783 }
784 return std::make_tuple(response, numInstances);
Deepak Kodihalliee717d72018-01-24 04:53:09 -0600785}
786
787std::tuple<ResponseList, NumInstances> readAll(const std::string& type,
788 uint8_t instanceStart)
789{
Deepak Kodihallib1e8fba2018-01-24 04:57:10 -0600790 ResponseList response{};
Patrick Williams5d82f472022-07-22 19:26:53 -0500791 sdbusplus::bus_t bus{ipmid_get_sd_bus_connection()};
Deepak Kodihallib1e8fba2018-01-24 04:57:10 -0600792
793 size_t numInstances = 0;
Kirill Pakhomova2573622018-11-02 19:00:18 +0300794 auto data = parseJSONConfig(gDCMISensorsConfig);
Deepak Kodihallib1e8fba2018-01-24 04:57:10 -0600795 static const std::vector<Json> empty{};
796 std::vector<Json> readings = data.value(type, empty);
797 numInstances = readings.size();
798 for (const auto& j : readings)
799 {
800 try
801 {
802 // Max of 8 response data sets
803 if (response.size() == maxDataSets)
804 {
805 break;
806 }
807
808 uint8_t instanceNum = j.value("instance", 0);
809 // Not in the instance range we're interested in
810 if (instanceNum < instanceStart)
811 {
812 continue;
813 }
814
815 std::string path = j.value("dbus", "");
816 auto service =
Patrick Venture0b02be92018-08-31 11:55:55 -0700817 ipmi::getService(bus, "xyz.openbmc_project.Sensor.Value", path);
Deepak Kodihallib1e8fba2018-01-24 04:57:10 -0600818
819 Response r{};
820 r.instance = instanceNum;
821 uint8_t temp{};
822 bool sign{};
823 std::tie(temp, sign) = readTemp(service, path);
824 r.temperature = temp;
825 r.sign = sign;
826 response.push_back(r);
827 }
Patrick Williamsa2ad2da2021-10-06 12:21:46 -0500828 catch (const std::exception& e)
Deepak Kodihallib1e8fba2018-01-24 04:57:10 -0600829 {
830 log<level::DEBUG>(e.what());
831 continue;
832 }
833 }
834
835 if (numInstances > maxInstances)
836 {
837 numInstances = maxInstances;
838 }
839 return std::make_tuple(response, numInstances);
Deepak Kodihalliee717d72018-01-24 04:53:09 -0600840}
841
Patrick Venture0b02be92018-08-31 11:55:55 -0700842} // namespace temp_readings
843} // namespace dcmi
Deepak Kodihalliee717d72018-01-24 04:53:09 -0600844
Willy Tu11d68892022-01-20 10:37:34 -0800845ipmi_ret_t getTempReadings(ipmi_netfn_t, ipmi_cmd_t, ipmi_request_t request,
846 ipmi_response_t response, ipmi_data_len_t data_len,
847 ipmi_context_t)
Deepak Kodihalliee717d72018-01-24 04:53:09 -0600848{
Deepak Kodihalliee717d72018-01-24 04:53:09 -0600849 auto requestData =
850 reinterpret_cast<const dcmi::GetTempReadingsRequest*>(request);
851 auto responseData =
852 reinterpret_cast<dcmi::GetTempReadingsResponseHdr*>(response);
853
854 if (*data_len != sizeof(dcmi::GetTempReadingsRequest))
855 {
856 log<level::ERR>("Malformed request data",
857 entry("DATA_SIZE=%d", *data_len));
858 return IPMI_CC_REQ_DATA_LEN_INVALID;
859 }
860 *data_len = 0;
861
Deepak Kodihalli0b459552018-02-06 06:25:12 -0600862 auto it = dcmi::entityIdToName.find(requestData->entityId);
863 if (it == dcmi::entityIdToName.end())
Deepak Kodihalliee717d72018-01-24 04:53:09 -0600864 {
865 log<level::ERR>("Unknown Entity ID",
866 entry("ENTITY_ID=%d", requestData->entityId));
867 return IPMI_CC_INVALID_FIELD_REQUEST;
868 }
869
Deepak Kodihalliee717d72018-01-24 04:53:09 -0600870 if (requestData->sensorType != dcmi::temperatureSensorType)
871 {
872 log<level::ERR>("Invalid sensor type",
873 entry("SENSOR_TYPE=%d", requestData->sensorType));
874 return IPMI_CC_INVALID_FIELD_REQUEST;
875 }
876
877 dcmi::temp_readings::ResponseList temps{};
878 try
879 {
880 if (!requestData->entityInstance)
881 {
882 // Read all instances
883 std::tie(temps, responseData->numInstances) =
884 dcmi::temp_readings::readAll(it->second,
885 requestData->instanceStart);
886 }
887 else
888 {
889 // Read one instance
890 temps.resize(1);
891 std::tie(temps[0], responseData->numInstances) =
892 dcmi::temp_readings::read(it->second,
893 requestData->entityInstance);
894 }
895 responseData->numDataSets = temps.size();
896 }
Patrick Williamsa2ad2da2021-10-06 12:21:46 -0500897 catch (const InternalFailure& e)
Deepak Kodihalliee717d72018-01-24 04:53:09 -0600898 {
899 return IPMI_CC_UNSPECIFIED_ERROR;
900 }
901
Patrick Venture0b02be92018-08-31 11:55:55 -0700902 size_t payloadSize = temps.size() * sizeof(dcmi::temp_readings::Response);
Deepak Kodihalliee717d72018-01-24 04:53:09 -0600903 if (!temps.empty())
904 {
905 memcpy(responseData + 1, // copy payload right after the response header
Patrick Venture0b02be92018-08-31 11:55:55 -0700906 temps.data(), payloadSize);
Deepak Kodihalliee717d72018-01-24 04:53:09 -0600907 }
908 *data_len = sizeof(dcmi::GetTempReadingsResponseHdr) + payloadSize;
909
910 return IPMI_CC_OK;
911}
912
Patrick Williams5d82f472022-07-22 19:26:53 -0500913int64_t getPowerReading(sdbusplus::bus_t& bus)
Marri Devender Rao66c5fda2018-01-18 10:48:37 -0600914{
915 std::ifstream sensorFile(POWER_READING_SENSOR);
916 std::string objectPath;
917 if (!sensorFile.is_open())
918 {
919 log<level::ERR>("Power reading configuration file not found",
Patrick Venture0b02be92018-08-31 11:55:55 -0700920 entry("POWER_SENSOR_FILE=%s", POWER_READING_SENSOR));
Marri Devender Rao66c5fda2018-01-18 10:48:37 -0600921 elog<InternalFailure>();
922 }
923
924 auto data = nlohmann::json::parse(sensorFile, nullptr, false);
925 if (data.is_discarded())
926 {
927 log<level::ERR>("Error in parsing configuration file",
Patrick Venture0b02be92018-08-31 11:55:55 -0700928 entry("POWER_SENSOR_FILE=%s", POWER_READING_SENSOR));
Marri Devender Rao66c5fda2018-01-18 10:48:37 -0600929 elog<InternalFailure>();
930 }
931
932 objectPath = data.value("path", "");
933 if (objectPath.empty())
934 {
935 log<level::ERR>("Power sensor D-Bus object path is empty",
936 entry("POWER_SENSOR_FILE=%s", POWER_READING_SENSOR));
937 elog<InternalFailure>();
938 }
939
Marri Devender Raoce6a7952018-02-11 08:45:00 -0600940 // Return default value if failed to read from D-Bus object
941 int64_t power = 0;
942 try
943 {
944 auto service = ipmi::getService(bus, SENSOR_VALUE_INTF, objectPath);
Marri Devender Rao66c5fda2018-01-18 10:48:37 -0600945
Patrick Venture0b02be92018-08-31 11:55:55 -0700946 // Read the sensor value and scale properties
Chris Cain4cc61e02022-01-12 17:23:14 -0600947 auto value = ipmi::getDbusProperty(
948 bus, service, objectPath, SENSOR_VALUE_INTF, SENSOR_VALUE_PROP);
949 power = std::get<double>(value);
Marri Devender Raoce6a7952018-02-11 08:45:00 -0600950 }
Patrick Williamsa2ad2da2021-10-06 12:21:46 -0500951 catch (const std::exception& e)
Marri Devender Raoce6a7952018-02-11 08:45:00 -0600952 {
Chris Cain4cc61e02022-01-12 17:23:14 -0600953 log<level::ERR>("Failure to read power value from D-Bus object",
954 entry("OBJECT_PATH=%s", objectPath.c_str()),
955 entry("INTERFACE=%s", SENSOR_VALUE_INTF));
Marri Devender Raoce6a7952018-02-11 08:45:00 -0600956 }
Marri Devender Rao66c5fda2018-01-18 10:48:37 -0600957 return power;
958}
959
Willy Tu11d68892022-01-20 10:37:34 -0800960ipmi_ret_t setDCMIConfParams(ipmi_netfn_t, ipmi_cmd_t, ipmi_request_t request,
961 ipmi_response_t, ipmi_data_len_t data_len,
962 ipmi_context_t)
Nagaraju Goruganti22be97b2018-02-07 01:19:59 -0600963{
Patrick Venture0b02be92018-08-31 11:55:55 -0700964 auto requestData =
965 reinterpret_cast<const dcmi::SetConfParamsRequest*>(request);
Nagaraju Goruganti22be97b2018-02-07 01:19:59 -0600966
William A. Kennington III5d06cc62019-04-25 02:10:55 -0700967 if (*data_len < DCMI_SET_CONF_PARAM_REQ_PACKET_MIN_SIZE ||
Patrick Venture0b02be92018-08-31 11:55:55 -0700968 *data_len > DCMI_SET_CONF_PARAM_REQ_PACKET_MAX_SIZE)
Nagaraju Goruganti22be97b2018-02-07 01:19:59 -0600969 {
William A. Kennington III5d06cc62019-04-25 02:10:55 -0700970 log<level::ERR>("Invalid Requested Packet size",
Nagaraju Goruganti22be97b2018-02-07 01:19:59 -0600971 entry("PACKET SIZE=%d", *data_len));
William A. Kennington III5d06cc62019-04-25 02:10:55 -0700972 *data_len = 0;
Nagaraju Goruganti22be97b2018-02-07 01:19:59 -0600973 return IPMI_CC_INVALID_FIELD_REQUEST;
974 }
Nagaraju Goruganti22be97b2018-02-07 01:19:59 -0600975 *data_len = 0;
976
977 try
978 {
979 // Take action based on the Parameter Selector
Patrick Venture0b02be92018-08-31 11:55:55 -0700980 switch (
981 static_cast<dcmi::DCMIConfigParameters>(requestData->paramSelect))
Nagaraju Goruganti22be97b2018-02-07 01:19:59 -0600982 {
983 case dcmi::DCMIConfigParameters::ActivateDHCP:
984
985 if ((requestData->data[0] & DCMI_ACTIVATE_DHCP_MASK) &&
Thang Tran55cbf552023-01-31 14:43:02 +0700986 (dcmi::getDHCPEnabled() !=
987 EthernetInterface::DHCPConf::none))
Nagaraju Goruganti22be97b2018-02-07 01:19:59 -0600988 {
Patrick Venture0b02be92018-08-31 11:55:55 -0700989 // When these conditions are met we have to trigger DHCP
990 // protocol restart using the latest parameter settings, but
991 // as per n/w manager design, each time when we update n/w
992 // parameters, n/w service is restarted. So we no need to
993 // take any action in this case.
Nagaraju Goruganti22be97b2018-02-07 01:19:59 -0600994 }
995 break;
996
997 case dcmi::DCMIConfigParameters::DiscoveryConfig:
998
999 if (requestData->data[0] & DCMI_OPTION_12_MASK)
1000 {
1001 dcmi::setDHCPOption(DHCP_OPT12_ENABLED, true);
1002 }
1003 else
1004 {
1005 dcmi::setDHCPOption(DHCP_OPT12_ENABLED, false);
1006 }
1007
1008 // Systemd-networkd doesn't support Random Back off
1009 if (requestData->data[0] & DCMI_RAND_BACK_OFF_MASK)
1010 {
1011 return IPMI_CC_INVALID;
1012 }
1013 break;
1014 // Systemd-networkd doesn't allow to configure DHCP timigs
1015 case dcmi::DCMIConfigParameters::DHCPTiming1:
1016 case dcmi::DCMIConfigParameters::DHCPTiming2:
1017 case dcmi::DCMIConfigParameters::DHCPTiming3:
1018 default:
1019 return IPMI_CC_INVALID;
1020 }
1021 }
Patrick Williamsa2ad2da2021-10-06 12:21:46 -05001022 catch (const std::exception& e)
Nagaraju Goruganti22be97b2018-02-07 01:19:59 -06001023 {
1024 log<level::ERR>(e.what());
1025 return IPMI_CC_UNSPECIFIED_ERROR;
1026 }
Nagaraju Goruganti22be97b2018-02-07 01:19:59 -06001027 return IPMI_CC_OK;
1028}
1029
Willy Tu11d68892022-01-20 10:37:34 -08001030ipmi_ret_t getDCMIConfParams(ipmi_netfn_t, ipmi_cmd_t, ipmi_request_t request,
1031 ipmi_response_t response, ipmi_data_len_t data_len,
1032 ipmi_context_t)
Nagaraju Goruganti22be97b2018-02-07 01:19:59 -06001033{
Patrick Venture0b02be92018-08-31 11:55:55 -07001034 auto requestData =
1035 reinterpret_cast<const dcmi::GetConfParamsRequest*>(request);
1036 auto responseData =
1037 reinterpret_cast<dcmi::GetConfParamsResponse*>(response);
Nagaraju Goruganti22be97b2018-02-07 01:19:59 -06001038
1039 responseData->data[0] = 0x00;
1040
William A. Kennington III5d06cc62019-04-25 02:10:55 -07001041 if (*data_len != sizeof(dcmi::GetConfParamsRequest))
Nagaraju Goruganti22be97b2018-02-07 01:19:59 -06001042 {
William A. Kennington III5d06cc62019-04-25 02:10:55 -07001043 log<level::ERR>("Invalid Requested Packet size",
Nagaraju Goruganti22be97b2018-02-07 01:19:59 -06001044 entry("PACKET SIZE=%d", *data_len));
1045 return IPMI_CC_INVALID_FIELD_REQUEST;
1046 }
1047
1048 *data_len = 0;
1049
1050 try
1051 {
1052 // Take action based on the Parameter Selector
Patrick Venture0b02be92018-08-31 11:55:55 -07001053 switch (
1054 static_cast<dcmi::DCMIConfigParameters>(requestData->paramSelect))
Nagaraju Goruganti22be97b2018-02-07 01:19:59 -06001055 {
1056 case dcmi::DCMIConfigParameters::ActivateDHCP:
1057 responseData->data[0] = DCMI_ACTIVATE_DHCP_REPLY;
1058 *data_len = sizeof(dcmi::GetConfParamsResponse) + 1;
1059 break;
1060 case dcmi::DCMIConfigParameters::DiscoveryConfig:
1061 if (dcmi::getDHCPOption(DHCP_OPT12_ENABLED))
1062 {
1063 responseData->data[0] |= DCMI_OPTION_12_MASK;
1064 }
1065 *data_len = sizeof(dcmi::GetConfParamsResponse) + 1;
1066 break;
1067 // Get below values from Systemd-networkd source code
1068 case dcmi::DCMIConfigParameters::DHCPTiming1:
1069 responseData->data[0] = DHCP_TIMING1;
1070 *data_len = sizeof(dcmi::GetConfParamsResponse) + 1;
1071 break;
1072 case dcmi::DCMIConfigParameters::DHCPTiming2:
1073 responseData->data[0] = DHCP_TIMING2_LOWER;
1074 responseData->data[1] = DHCP_TIMING2_UPPER;
1075 *data_len = sizeof(dcmi::GetConfParamsResponse) + 2;
1076 break;
1077 case dcmi::DCMIConfigParameters::DHCPTiming3:
1078 responseData->data[0] = DHCP_TIMING3_LOWER;
1079 responseData->data[1] = DHCP_TIMING3_UPPER;
1080 *data_len = sizeof(dcmi::GetConfParamsResponse) + 2;
1081 break;
1082 default:
1083 *data_len = 0;
1084 return IPMI_CC_INVALID;
1085 }
1086 }
Patrick Williamsa2ad2da2021-10-06 12:21:46 -05001087 catch (const std::exception& e)
Nagaraju Goruganti22be97b2018-02-07 01:19:59 -06001088 {
1089 log<level::ERR>(e.what());
1090 return IPMI_CC_UNSPECIFIED_ERROR;
1091 }
1092
Nagaraju Goruganti22be97b2018-02-07 01:19:59 -06001093 responseData->major = DCMI_SPEC_MAJOR_VERSION;
1094 responseData->minor = DCMI_SPEC_MINOR_VERSION;
1095 responseData->paramRevision = DCMI_CONFIG_PARAMETER_REVISION;
1096
1097 return IPMI_CC_OK;
1098}
1099
Willy Tu11d68892022-01-20 10:37:34 -08001100ipmi_ret_t getPowerReading(ipmi_netfn_t, ipmi_cmd_t, ipmi_request_t,
1101 ipmi_response_t response, ipmi_data_len_t data_len,
1102 ipmi_context_t)
Marri Devender Rao66c5fda2018-01-18 10:48:37 -06001103{
Chalapathi Venkataramashetty90e81fa2021-05-11 09:13:23 +00001104 *data_len = 0;
Kirill Pakhomov2c2af2c2018-11-06 16:06:10 +03001105 if (!dcmi::isDCMIPowerMgmtSupported())
1106 {
Kirill Pakhomov2c2af2c2018-11-06 16:06:10 +03001107 log<level::ERR>("DCMI Power management is unsupported!");
1108 return IPMI_CC_INVALID;
1109 }
1110
Marri Devender Rao66c5fda2018-01-18 10:48:37 -06001111 ipmi_ret_t rc = IPMI_CC_OK;
Patrick Venture0b02be92018-08-31 11:55:55 -07001112 auto responseData =
1113 reinterpret_cast<dcmi::GetPowerReadingResponse*>(response);
Marri Devender Rao9c966e02018-01-22 05:55:10 -06001114
Patrick Williams5d82f472022-07-22 19:26:53 -05001115 sdbusplus::bus_t bus{ipmid_get_sd_bus_connection()};
Marri Devender Rao9c966e02018-01-22 05:55:10 -06001116 int64_t power = 0;
Marri Devender Rao66c5fda2018-01-18 10:48:37 -06001117 try
1118 {
Marri Devender Rao9c966e02018-01-22 05:55:10 -06001119 power = getPowerReading(bus);
Marri Devender Rao66c5fda2018-01-18 10:48:37 -06001120 }
Patrick Williamsa2ad2da2021-10-06 12:21:46 -05001121 catch (const InternalFailure& e)
Marri Devender Rao66c5fda2018-01-18 10:48:37 -06001122 {
1123 log<level::ERR>("Error in reading power sensor value",
1124 entry("INTERFACE=%s", SENSOR_VALUE_INTF),
1125 entry("PROPERTY=%s", SENSOR_VALUE_PROP));
1126 return IPMI_CC_UNSPECIFIED_ERROR;
1127 }
Marri Devender Rao9c966e02018-01-22 05:55:10 -06001128
1129 // TODO: openbmc/openbmc#2819
Gunnar Mills8466b792018-03-23 12:18:12 -05001130 // Minimum, Maximum, Average power, TimeFrame, TimeStamp,
Marri Devender Rao9c966e02018-01-22 05:55:10 -06001131 // PowerReadingState readings need to be populated
1132 // after Telemetry changes.
1133 uint16_t totalPower = static_cast<uint16_t>(power);
1134 responseData->currentPower = totalPower;
1135 responseData->minimumPower = totalPower;
1136 responseData->maximumPower = totalPower;
1137 responseData->averagePower = totalPower;
1138
1139 *data_len = sizeof(*responseData);
Marri Devender Rao66c5fda2018-01-18 10:48:37 -06001140 return rc;
1141}
1142
Deepak Kodihalli0b459552018-02-06 06:25:12 -06001143namespace dcmi
1144{
1145namespace sensor_info
1146{
1147
Deepak Kodihallidd4cff12018-02-06 06:48:29 -06001148Response createFromJson(const Json& config)
1149{
1150 Response response{};
1151 uint16_t recordId = config.value("record_id", 0);
1152 response.recordIdLsb = recordId & 0xFF;
1153 response.recordIdMsb = (recordId >> 8) & 0xFF;
1154 return response;
1155}
1156
Deepak Kodihalli0b459552018-02-06 06:25:12 -06001157std::tuple<Response, NumInstances> read(const std::string& type,
Patrick Venture0b02be92018-08-31 11:55:55 -07001158 uint8_t instance, const Json& config)
Deepak Kodihalli0b459552018-02-06 06:25:12 -06001159{
Deepak Kodihallidd4cff12018-02-06 06:48:29 -06001160 Response response{};
1161
1162 if (!instance)
1163 {
1164 log<level::ERR>("Expected non-zero instance");
1165 elog<InternalFailure>();
1166 }
1167
1168 static const std::vector<Json> empty{};
1169 std::vector<Json> readings = config.value(type, empty);
1170 size_t numInstances = readings.size();
1171 for (const auto& reading : readings)
1172 {
1173 uint8_t instanceNum = reading.value("instance", 0);
1174 // Not the instance we're interested in
1175 if (instanceNum != instance)
1176 {
1177 continue;
1178 }
1179
1180 response = createFromJson(reading);
1181
1182 // Found the instance we're interested in
1183 break;
1184 }
1185
1186 if (numInstances > maxInstances)
1187 {
1188 log<level::DEBUG>("Trimming IPMI num instances",
1189 entry("NUM_INSTANCES=%d", numInstances));
1190 numInstances = maxInstances;
1191 }
1192 return std::make_tuple(response, numInstances);
Deepak Kodihalli0b459552018-02-06 06:25:12 -06001193}
1194
Patrick Venture0b02be92018-08-31 11:55:55 -07001195std::tuple<ResponseList, NumInstances>
1196 readAll(const std::string& type, uint8_t instanceStart, const Json& config)
Deepak Kodihalli0b459552018-02-06 06:25:12 -06001197{
Deepak Kodihallidd4cff12018-02-06 06:48:29 -06001198 ResponseList responses{};
1199
1200 size_t numInstances = 0;
1201 static const std::vector<Json> empty{};
1202 std::vector<Json> readings = config.value(type, empty);
1203 numInstances = readings.size();
1204 for (const auto& reading : readings)
1205 {
1206 try
1207 {
1208 // Max of 8 records
1209 if (responses.size() == maxRecords)
1210 {
1211 break;
1212 }
1213
1214 uint8_t instanceNum = reading.value("instance", 0);
1215 // Not in the instance range we're interested in
1216 if (instanceNum < instanceStart)
1217 {
1218 continue;
1219 }
1220
1221 Response response = createFromJson(reading);
1222 responses.push_back(response);
1223 }
Patrick Williamsa2ad2da2021-10-06 12:21:46 -05001224 catch (const std::exception& e)
Deepak Kodihallidd4cff12018-02-06 06:48:29 -06001225 {
1226 log<level::DEBUG>(e.what());
1227 continue;
1228 }
1229 }
1230
1231 if (numInstances > maxInstances)
1232 {
1233 log<level::DEBUG>("Trimming IPMI num instances",
1234 entry("NUM_INSTANCES=%d", numInstances));
1235 numInstances = maxInstances;
1236 }
1237 return std::make_tuple(responses, numInstances);
Deepak Kodihalli0b459552018-02-06 06:25:12 -06001238}
1239
1240} // namespace sensor_info
1241} // namespace dcmi
1242
Willy Tu11d68892022-01-20 10:37:34 -08001243ipmi_ret_t getSensorInfo(ipmi_netfn_t, ipmi_cmd_t, ipmi_request_t request,
1244 ipmi_response_t response, ipmi_data_len_t data_len,
1245 ipmi_context_t)
Deepak Kodihalli0b459552018-02-06 06:25:12 -06001246{
1247 auto requestData =
1248 reinterpret_cast<const dcmi::GetSensorInfoRequest*>(request);
1249 auto responseData =
1250 reinterpret_cast<dcmi::GetSensorInfoResponseHdr*>(response);
1251
1252 if (*data_len != sizeof(dcmi::GetSensorInfoRequest))
1253 {
1254 log<level::ERR>("Malformed request data",
1255 entry("DATA_SIZE=%d", *data_len));
1256 return IPMI_CC_REQ_DATA_LEN_INVALID;
1257 }
1258 *data_len = 0;
1259
1260 auto it = dcmi::entityIdToName.find(requestData->entityId);
1261 if (it == dcmi::entityIdToName.end())
1262 {
1263 log<level::ERR>("Unknown Entity ID",
1264 entry("ENTITY_ID=%d", requestData->entityId));
1265 return IPMI_CC_INVALID_FIELD_REQUEST;
1266 }
1267
Deepak Kodihalli0b459552018-02-06 06:25:12 -06001268 if (requestData->sensorType != dcmi::temperatureSensorType)
1269 {
1270 log<level::ERR>("Invalid sensor type",
1271 entry("SENSOR_TYPE=%d", requestData->sensorType));
1272 return IPMI_CC_INVALID_FIELD_REQUEST;
1273 }
1274
1275 dcmi::sensor_info::ResponseList sensors{};
1276 static dcmi::Json config{};
1277 static bool parsed = false;
1278
1279 try
1280 {
1281 if (!parsed)
1282 {
Kirill Pakhomova2573622018-11-02 19:00:18 +03001283 config = dcmi::parseJSONConfig(dcmi::gDCMISensorsConfig);
Deepak Kodihalli0b459552018-02-06 06:25:12 -06001284 parsed = true;
1285 }
1286
1287 if (!requestData->entityInstance)
1288 {
1289 // Read all instances
1290 std::tie(sensors, responseData->numInstances) =
1291 dcmi::sensor_info::readAll(it->second,
Patrick Venture0b02be92018-08-31 11:55:55 -07001292 requestData->instanceStart, config);
Deepak Kodihalli0b459552018-02-06 06:25:12 -06001293 }
1294 else
1295 {
1296 // Read one instance
1297 sensors.resize(1);
1298 std::tie(sensors[0], responseData->numInstances) =
Patrick Venture0b02be92018-08-31 11:55:55 -07001299 dcmi::sensor_info::read(it->second, requestData->entityInstance,
Deepak Kodihalli0b459552018-02-06 06:25:12 -06001300 config);
1301 }
1302 responseData->numRecords = sensors.size();
1303 }
Patrick Williamsa2ad2da2021-10-06 12:21:46 -05001304 catch (const InternalFailure& e)
Deepak Kodihalli0b459552018-02-06 06:25:12 -06001305 {
1306 return IPMI_CC_UNSPECIFIED_ERROR;
1307 }
1308
Deepak Kodihalli0b459552018-02-06 06:25:12 -06001309 size_t payloadSize = sensors.size() * sizeof(dcmi::sensor_info::Response);
1310 if (!sensors.empty())
1311 {
1312 memcpy(responseData + 1, // copy payload right after the response header
Patrick Venture0b02be92018-08-31 11:55:55 -07001313 sensors.data(), payloadSize);
Deepak Kodihalli0b459552018-02-06 06:25:12 -06001314 }
1315 *data_len = sizeof(dcmi::GetSensorInfoResponseHdr) + payloadSize;
1316
1317 return IPMI_CC_OK;
1318}
1319
Chris Austen1810bec2015-10-13 12:12:39 -05001320void register_netfn_dcmi_functions()
1321{
Tom05732372016-09-06 17:21:23 +05301322 // <Get Power Limit>
Vernon Maueryd4222fd2023-07-27 11:26:51 -07001323 registerGroupHandler(ipmi::prioOpenBmcBase, ipmi::groupDCMI,
1324 ipmi::dcmi::cmdGetPowerLimit, ipmi::Privilege::User,
1325 getPowerLimit);
Tom Joseph6f6dd4d2017-07-12 20:07:11 +05301326
Tom Joseph46fa37d2017-07-26 18:11:55 +05301327 // <Set Power Limit>
Vernon Maueryd4222fd2023-07-27 11:26:51 -07001328 registerGroupHandler(ipmi::prioOpenBmcBase, ipmi::groupDCMI,
1329 ipmi::dcmi::cmdSetPowerLimit,
1330 ipmi::Privilege::Operator, setPowerLimit);
Tom Joseph46fa37d2017-07-26 18:11:55 +05301331
Tom Joseph6c8d51b2017-07-26 18:18:06 +05301332 // <Activate/Deactivate Power Limit>
Vernon Maueryd4222fd2023-07-27 11:26:51 -07001333 registerGroupHandler(ipmi::prioOpenBmcBase, ipmi::groupDCMI,
1334 ipmi::dcmi::cmdActDeactivatePwrLimit,
1335 ipmi::Privilege::Operator, applyPowerLimit);
Tom Joseph6c8d51b2017-07-26 18:18:06 +05301336
Tom Joseph6f6dd4d2017-07-12 20:07:11 +05301337 // <Get Asset Tag>
Vernon Mauerydca47202023-07-27 11:32:01 -07001338 registerGroupHandler(ipmi::prioOpenBmcBase, ipmi::groupDCMI,
1339 ipmi::dcmi::cmdGetAssetTag, ipmi::Privilege::User,
1340 getAssetTag);
Tom Joseph545dd232017-07-12 20:20:49 +05301341
1342 // <Set Asset Tag>
Vernon Mauerydca47202023-07-27 11:32:01 -07001343 registerGroupHandler(ipmi::prioOpenBmcBase, ipmi::groupDCMI,
1344 ipmi::dcmi::cmdSetAssetTag, ipmi::Privilege::Operator,
1345 setAssetTag);
Vladislav Vovchenko8f7a6f62017-08-17 00:31:14 +03001346
Gunnar Mills8991dd62017-10-25 17:11:29 -05001347 // <Get Management Controller Identifier String>
Vernon Maueryefb5ae52023-07-27 11:35:43 -07001348 registerGroupHandler(ipmi::prioOpenBmcBase, ipmi::groupDCMI,
1349 ipmi::dcmi::cmdGetMgmtCntlrIdString,
1350 ipmi::Privilege::User, getMgmntCtrlIdStr);
Vladislav Vovchenko8f7a6f62017-08-17 00:31:14 +03001351
1352 // <Set Management Controller Identifier String>
Vernon Maueryefb5ae52023-07-27 11:35:43 -07001353 registerGroupHandler(ipmi::prioOpenBmcBase, ipmi::groupDCMI,
1354 ipmi::dcmi::cmdSetMgmtCntlrIdString,
1355 ipmi::Privilege::Admin, setMgmntCtrlIdStr);
Vladislav Vovchenko8f7a6f62017-08-17 00:31:14 +03001356
Dhruvaraj Subhashchandrane29be412018-01-16 05:11:56 -06001357 // <Get DCMI capabilities>
1358 ipmi_register_callback(NETFUN_GRPEXT, dcmi::Commands::GET_CAPABILITIES,
Patrick Venture0b02be92018-08-31 11:55:55 -07001359 NULL, getDCMICapabilities, PRIVILEGE_USER);
Deepak Kodihalliee717d72018-01-24 04:53:09 -06001360
1361 // <Get Temperature Readings>
1362 ipmi_register_callback(NETFUN_GRPEXT, dcmi::Commands::GET_TEMP_READINGS,
1363 NULL, getTempReadings, PRIVILEGE_USER);
1364
Marri Devender Rao66c5fda2018-01-18 10:48:37 -06001365 // <Get Power Reading>
1366 ipmi_register_callback(NETFUN_GRPEXT, dcmi::Commands::GET_POWER_READING,
1367 NULL, getPowerReading, PRIVILEGE_USER);
adarshgrami042e9db2022-09-15 10:34:34 +05301368// The Get sensor should get the senor details dynamically when
1369// FEATURE_DYNAMIC_SENSORS is enabled.
1370#ifndef FEATURE_DYNAMIC_SENSORS
Deepak Kodihalli0b459552018-02-06 06:25:12 -06001371 // <Get Sensor Info>
Patrick Venture0b02be92018-08-31 11:55:55 -07001372 ipmi_register_callback(NETFUN_GRPEXT, dcmi::Commands::GET_SENSOR_INFO, NULL,
Chau Lyd74df5f2023-05-25 10:33:00 +00001373 getSensorInfo, PRIVILEGE_OPERATOR);
adarshgrami042e9db2022-09-15 10:34:34 +05301374#endif
Nagaraju Goruganti22be97b2018-02-07 01:19:59 -06001375 // <Get DCMI Configuration Parameters>
Patrick Venture0b02be92018-08-31 11:55:55 -07001376 ipmi_register_callback(NETFUN_GRPEXT, dcmi::Commands::GET_CONF_PARAMS, NULL,
1377 getDCMIConfParams, PRIVILEGE_USER);
Nagaraju Goruganti22be97b2018-02-07 01:19:59 -06001378
1379 // <Set DCMI Configuration Parameters>
Patrick Venture0b02be92018-08-31 11:55:55 -07001380 ipmi_register_callback(NETFUN_GRPEXT, dcmi::Commands::SET_CONF_PARAMS, NULL,
1381 setDCMIConfParams, PRIVILEGE_ADMIN);
Nagaraju Goruganti22be97b2018-02-07 01:19:59 -06001382
Chris Austen1810bec2015-10-13 12:12:39 -05001383 return;
1384}
Tom05732372016-09-06 17:21:23 +05301385// 956379