blob: cfe8be26841ee7fc49401ea7e7ca06a3ec7c04bb [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>
George Liu7fa28712024-07-17 19:26:23 +080011#include <phosphor-logging/lg2.hpp>
Andrew Geissler50c0c8f2017-07-11 16:18:51 -050012#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;
Willy Tu523e2d12023-09-05 11:36:48 -070022using sdbusplus::server::xyz::openbmc_project::network::EthernetInterface;
Thang Tran55cbf552023-01-31 14:43:02 +070023
Tom Josephbe5eaa12017-07-12 19:54:44 +053024using InternalFailure =
Willy Tu523e2d12023-09-05 11:36:48 -070025 sdbusplus::error::xyz::openbmc_project::common::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
35using namespace phosphor::logging;
36
Tom Josephb9d86f42017-07-26 18:03:47 +053037namespace dcmi
38{
Vernon Mauerydca47202023-07-27 11:32:01 -070039constexpr auto assetTagMaxOffset = 62;
40constexpr auto assetTagMaxSize = 63;
41constexpr auto maxBytes = 16;
42constexpr size_t maxCtrlIdStrLen = 63;
Tom Josephb9d86f42017-07-26 18:03:47 +053043
Vernon Maueryf038dc02023-07-27 14:06:11 -070044constexpr uint8_t parameterRevision = 2;
45constexpr uint8_t specMajorVersion = 1;
46constexpr uint8_t specMinorVersion = 5;
Vernon Mauerycce9ffd2023-07-27 14:15:17 -070047constexpr auto sensorValueIntf = "xyz.openbmc_project.Sensor.Value";
48constexpr auto sensorValueProp = "Value";
Vernon Mauery6475b5c2023-07-27 14:52:51 -070049constexpr uint8_t configParameterRevision = 1;
50constexpr auto option12Mask = 0x01;
51constexpr auto activateDhcpReply = 0x00;
52constexpr uint8_t dhcpTiming1 = 0x04; // 4 sec
53constexpr uint16_t dhcpTiming2 = 0x78; // 120 sec
54constexpr uint16_t dhcpTiming3 = 0x40; // 60 sec
55// When DHCP Option 12 is enabled the string "SendHostName=true" will be
56// added into n/w configuration file and the parameter
57// SendHostNameEnabled will set to true.
58constexpr auto dhcpOpt12Enabled = "SendHostNameEnabled";
59
60enum class DCMIConfigParameters : uint8_t
61{
62 ActivateDHCP = 1,
63 DiscoveryConfig,
64 DHCPTiming1,
65 DHCPTiming2,
66 DHCPTiming3,
67};
Vernon Maueryf038dc02023-07-27 14:06:11 -070068
Deepak Kodihalli0b459552018-02-06 06:25:12 -060069// Refer Table 6-14, DCMI Entity ID Extension, DCMI v1.5 spec
Patrick Venture0b02be92018-08-31 11:55:55 -070070static const std::map<uint8_t, std::string> entityIdToName{
71 {0x40, "inlet"}, {0x37, "inlet"}, {0x41, "cpu"},
72 {0x03, "cpu"}, {0x42, "baseboard"}, {0x07, "baseboard"}};
Deepak Kodihalli0b459552018-02-06 06:25:12 -060073
Vernon Mauery6475b5c2023-07-27 14:52:51 -070074nlohmann::json parseJSONConfig(const std::string& configFile)
75{
76 std::ifstream jsonFile(configFile);
77 if (!jsonFile.is_open())
78 {
George Liu7fa28712024-07-17 19:26:23 +080079 lg2::error("Temperature readings JSON file not found");
Vernon Mauery6475b5c2023-07-27 14:52:51 -070080 elog<InternalFailure>();
81 }
82
83 auto data = nlohmann::json::parse(jsonFile, nullptr, false);
84 if (data.is_discarded())
85 {
George Liu7fa28712024-07-17 19:26:23 +080086 lg2::error("Temperature readings JSON parser failure");
Vernon Mauery6475b5c2023-07-27 14:52:51 -070087 elog<InternalFailure>();
88 }
89
90 return data;
91}
92
Kirill Pakhomov2c2af2c2018-11-06 16:06:10 +030093bool isDCMIPowerMgmtSupported()
94{
Vernon Maueryf4eb35d2023-07-27 11:08:49 -070095 static bool parsed = false;
96 static bool supported = false;
97 if (!parsed)
98 {
99 auto data = parseJSONConfig(gDCMICapabilitiesConfig);
Kirill Pakhomov2c2af2c2018-11-06 16:06:10 +0300100
Vernon Maueryf4eb35d2023-07-27 11:08:49 -0700101 supported = (gDCMIPowerMgmtSupported ==
102 data.value(gDCMIPowerMgmtCapability, 0));
103 }
104 return supported;
Kirill Pakhomov2c2af2c2018-11-06 16:06:10 +0300105}
106
Vernon Maueryd4222fd2023-07-27 11:26:51 -0700107std::optional<uint32_t> getPcap(ipmi::Context::ptr& ctx)
Andrew Geissler50c0c8f2017-07-11 16:18:51 -0500108{
Vernon Maueryd4222fd2023-07-27 11:26:51 -0700109 std::string service{};
Patrick Williams1318a5e2024-08-16 15:19:54 -0400110 boost::system::error_code ec =
111 ipmi::getService(ctx, pcapInterface, pcapPath, service);
Vernon Maueryd4222fd2023-07-27 11:26:51 -0700112 if (ec.value())
Andrew Geissler50c0c8f2017-07-11 16:18:51 -0500113 {
Vernon Maueryd4222fd2023-07-27 11:26:51 -0700114 return std::nullopt;
George Liu3e3cc352023-07-26 15:59:31 +0800115 }
Vernon Maueryd4222fd2023-07-27 11:26:51 -0700116 uint32_t pcap{};
117 ec = ipmi::getDbusProperty(ctx, service, pcapPath, pcapInterface,
118 powerCapProp, pcap);
119 if (ec.value())
George Liu3e3cc352023-07-26 15:59:31 +0800120 {
George Liu7fa28712024-07-17 19:26:23 +0800121 lg2::error("Error in getPcap prop: {ERROR}", "ERROR", ec.message());
Tom Josephb9d86f42017-07-26 18:03:47 +0530122 elog<InternalFailure>();
Vernon Maueryd4222fd2023-07-27 11:26:51 -0700123 return std::nullopt;
Andrew Geissler50c0c8f2017-07-11 16:18:51 -0500124 }
Vernon Maueryd4222fd2023-07-27 11:26:51 -0700125 return pcap;
Andrew Geissler50c0c8f2017-07-11 16:18:51 -0500126}
127
Vernon Maueryd4222fd2023-07-27 11:26:51 -0700128std::optional<bool> getPcapEnabled(ipmi::Context::ptr& ctx)
Andrew Geissler50c0c8f2017-07-11 16:18:51 -0500129{
Vernon Maueryd4222fd2023-07-27 11:26:51 -0700130 std::string service{};
Patrick Williams1318a5e2024-08-16 15:19:54 -0400131 boost::system::error_code ec =
132 ipmi::getService(ctx, pcapInterface, pcapPath, service);
Vernon Maueryd4222fd2023-07-27 11:26:51 -0700133 if (ec.value())
Andrew Geissler50c0c8f2017-07-11 16:18:51 -0500134 {
Vernon Maueryd4222fd2023-07-27 11:26:51 -0700135 return std::nullopt;
George Liu3e3cc352023-07-26 15:59:31 +0800136 }
Vernon Maueryd4222fd2023-07-27 11:26:51 -0700137 bool pcapEnabled{};
138 ec = ipmi::getDbusProperty(ctx, service, pcapPath, pcapInterface,
139 powerCapEnableProp, pcapEnabled);
140 if (ec.value())
George Liu3e3cc352023-07-26 15:59:31 +0800141 {
George Liu7fa28712024-07-17 19:26:23 +0800142 lg2::error("Error in getPcap prop");
Tom Josephb9d86f42017-07-26 18:03:47 +0530143 elog<InternalFailure>();
Vernon Maueryd4222fd2023-07-27 11:26:51 -0700144 return std::nullopt;
Andrew Geissler50c0c8f2017-07-11 16:18:51 -0500145 }
Vernon Maueryd4222fd2023-07-27 11:26:51 -0700146 return pcapEnabled;
Andrew Geissler50c0c8f2017-07-11 16:18:51 -0500147}
Chris Austen1810bec2015-10-13 12:12:39 -0500148
Vernon Maueryd4222fd2023-07-27 11:26:51 -0700149bool setPcap(ipmi::Context::ptr& ctx, const uint32_t powerCap)
Tom Joseph46fa37d2017-07-26 18:11:55 +0530150{
Vernon Maueryd4222fd2023-07-27 11:26:51 -0700151 std::string service{};
Patrick Williams1318a5e2024-08-16 15:19:54 -0400152 boost::system::error_code ec =
153 ipmi::getService(ctx, pcapInterface, pcapPath, service);
Vernon Maueryd4222fd2023-07-27 11:26:51 -0700154 if (ec.value())
Tom Joseph46fa37d2017-07-26 18:11:55 +0530155 {
Vernon Maueryd4222fd2023-07-27 11:26:51 -0700156 return false;
George Liu3e3cc352023-07-26 15:59:31 +0800157 }
Vernon Maueryd4222fd2023-07-27 11:26:51 -0700158
159 ec = ipmi::setDbusProperty(ctx, service, pcapPath, pcapInterface,
160 powerCapProp, powerCap);
161 if (ec.value())
George Liu3e3cc352023-07-26 15:59:31 +0800162 {
George Liu7fa28712024-07-17 19:26:23 +0800163 lg2::error("Error in setPcap property: {ERROR}", "ERROR", ec.message());
Tom Joseph46fa37d2017-07-26 18:11:55 +0530164 elog<InternalFailure>();
Vernon Maueryd4222fd2023-07-27 11:26:51 -0700165 return false;
Tom Joseph46fa37d2017-07-26 18:11:55 +0530166 }
Vernon Maueryd4222fd2023-07-27 11:26:51 -0700167 return true;
Tom Joseph46fa37d2017-07-26 18:11:55 +0530168}
169
Vernon Maueryd4222fd2023-07-27 11:26:51 -0700170bool setPcapEnable(ipmi::Context::ptr& ctx, bool enabled)
Tom Joseph6c8d51b2017-07-26 18:18:06 +0530171{
Vernon Maueryd4222fd2023-07-27 11:26:51 -0700172 std::string service{};
Patrick Williams1318a5e2024-08-16 15:19:54 -0400173 boost::system::error_code ec =
174 ipmi::getService(ctx, pcapInterface, pcapPath, service);
Vernon Maueryd4222fd2023-07-27 11:26:51 -0700175 if (ec.value())
Tom Joseph6c8d51b2017-07-26 18:18:06 +0530176 {
Vernon Maueryd4222fd2023-07-27 11:26:51 -0700177 return false;
George Liu3e3cc352023-07-26 15:59:31 +0800178 }
Vernon Maueryd4222fd2023-07-27 11:26:51 -0700179
180 ec = ipmi::setDbusProperty(ctx, service, pcapPath, pcapInterface,
181 powerCapEnableProp, enabled);
182 if (ec.value())
George Liu3e3cc352023-07-26 15:59:31 +0800183 {
George Liu7fa28712024-07-17 19:26:23 +0800184 lg2::error("Error in setPcapEnabled property: {ERROR}", "ERROR",
185 ec.message());
Tom Joseph6c8d51b2017-07-26 18:18:06 +0530186 elog<InternalFailure>();
Vernon Maueryd4222fd2023-07-27 11:26:51 -0700187 return false;
Tom Joseph6c8d51b2017-07-26 18:18:06 +0530188 }
Vernon Maueryd4222fd2023-07-27 11:26:51 -0700189 return true;
Tom Joseph6c8d51b2017-07-26 18:18:06 +0530190}
191
Vernon Mauerydca47202023-07-27 11:32:01 -0700192std::optional<std::string> readAssetTag(ipmi::Context::ptr& ctx)
Tom Josephbe5eaa12017-07-12 19:54:44 +0530193{
Tom Josephbe5eaa12017-07-12 19:54:44 +0530194 // Read the object tree with the inventory root to figure out the object
195 // that has implemented the Asset tag interface.
Vernon Mauerydca47202023-07-27 11:32:01 -0700196 ipmi::DbusObjectInfo objectInfo;
197 boost::system::error_code ec = getDbusObject(
198 ctx, dcmi::assetTagIntf, ipmi::sensor::inventoryRoot, "", objectInfo);
199 if (ec.value())
Tom Josephbe5eaa12017-07-12 19:54:44 +0530200 {
Vernon Mauerydca47202023-07-27 11:32:01 -0700201 return std::nullopt;
George Liu3e3cc352023-07-26 15:59:31 +0800202 }
Vernon Mauerydca47202023-07-27 11:32:01 -0700203
204 std::string assetTag{};
Patrick Williams1318a5e2024-08-16 15:19:54 -0400205 ec =
206 ipmi::getDbusProperty(ctx, objectInfo.second, objectInfo.first,
207 dcmi::assetTagIntf, dcmi::assetTagProp, assetTag);
Vernon Mauerydca47202023-07-27 11:32:01 -0700208 if (ec.value())
George Liu3e3cc352023-07-26 15:59:31 +0800209 {
George Liu7fa28712024-07-17 19:26:23 +0800210 lg2::error("Error in reading asset tag: {ERROR}", "ERROR",
211 ec.message());
Tom Josephbe5eaa12017-07-12 19:54:44 +0530212 elog<InternalFailure>();
Vernon Mauerydca47202023-07-27 11:32:01 -0700213 return std::nullopt;
Tom Josephbe5eaa12017-07-12 19:54:44 +0530214 }
Vernon Mauerydca47202023-07-27 11:32:01 -0700215
216 return assetTag;
Tom Josephbe5eaa12017-07-12 19:54:44 +0530217}
218
Vernon Mauerydca47202023-07-27 11:32:01 -0700219bool writeAssetTag(ipmi::Context::ptr& ctx, const std::string& assetTag)
Tom Josephbe5b9892017-07-15 00:55:23 +0530220{
Tom Josephbe5b9892017-07-15 00:55:23 +0530221 // Read the object tree with the inventory root to figure out the object
222 // that has implemented the Asset tag interface.
Vernon Mauerydca47202023-07-27 11:32:01 -0700223 ipmi::DbusObjectInfo objectInfo;
224 boost::system::error_code ec = getDbusObject(
225 ctx, dcmi::assetTagIntf, ipmi::sensor::inventoryRoot, "", objectInfo);
226 if (ec.value())
Tom Josephbe5b9892017-07-15 00:55:23 +0530227 {
Vernon Mauerydca47202023-07-27 11:32:01 -0700228 return false;
George Liu3e3cc352023-07-26 15:59:31 +0800229 }
Vernon Mauerydca47202023-07-27 11:32:01 -0700230
Patrick Williams1318a5e2024-08-16 15:19:54 -0400231 ec =
232 ipmi::setDbusProperty(ctx, objectInfo.second, objectInfo.first,
233 dcmi::assetTagIntf, dcmi::assetTagProp, assetTag);
Vernon Mauerydca47202023-07-27 11:32:01 -0700234 if (ec.value())
George Liu3e3cc352023-07-26 15:59:31 +0800235 {
George Liu7fa28712024-07-17 19:26:23 +0800236 lg2::error("Error in writing asset tag: {ERROR}", "ERROR",
237 ec.message());
Tom Josephbe5b9892017-07-15 00:55:23 +0530238 elog<InternalFailure>();
Vernon Mauerydca47202023-07-27 11:32:01 -0700239 return false;
Tom Josephbe5b9892017-07-15 00:55:23 +0530240 }
Vernon Mauerydca47202023-07-27 11:32:01 -0700241 return true;
Tom Josephbe5b9892017-07-15 00:55:23 +0530242}
243
Vernon Maueryefb5ae52023-07-27 11:35:43 -0700244std::optional<std::string> getHostName(ipmi::Context::ptr& ctx)
Vladislav Vovchenko8f7a6f62017-08-17 00:31:14 +0300245{
Vernon Maueryefb5ae52023-07-27 11:35:43 -0700246 std::string service{};
Patrick Williams1318a5e2024-08-16 15:19:54 -0400247 boost::system::error_code ec =
248 ipmi::getService(ctx, networkConfigIntf, networkConfigObj, service);
Vernon Maueryefb5ae52023-07-27 11:35:43 -0700249 if (ec.value())
250 {
251 return std::nullopt;
252 }
253 std::string hostname{};
254 ec = ipmi::getDbusProperty(ctx, service, networkConfigObj,
255 networkConfigIntf, hostNameProp, hostname);
256 if (ec.value())
257 {
George Liu7fa28712024-07-17 19:26:23 +0800258 lg2::error("Error fetching hostname");
Vernon Maueryefb5ae52023-07-27 11:35:43 -0700259 elog<InternalFailure>();
260 return std::nullopt;
261 }
262 return hostname;
Vladislav Vovchenko8f7a6f62017-08-17 00:31:14 +0300263}
264
Vernon Mauery6475b5c2023-07-27 14:52:51 -0700265std::optional<EthernetInterface::DHCPConf>
266 getDHCPEnabled(ipmi::Context::ptr& ctx)
Nagaraju Goruganti22be97b2018-02-07 01:19:59 -0600267{
Johnathan Mantey74a21022018-12-13 13:17:56 -0800268 auto ethdevice = ipmi::getChannelName(ethernetDefaultChannelNum);
Vernon Mauery6475b5c2023-07-27 14:52:51 -0700269 ipmi::DbusObjectInfo ethernetObj{};
270 boost::system::error_code ec = ipmi::getDbusObject(
271 ctx, ethernetIntf, networkRoot, ethdevice, ethernetObj);
272 if (ec.value())
Deepak Kodihalli0b459552018-02-06 06:25:12 -0600273 {
Vernon Mauery6475b5c2023-07-27 14:52:51 -0700274 return std::nullopt;
275 }
276 std::string service{};
277 ec = ipmi::getService(ctx, ethernetIntf, ethernetObj.first, service);
278 if (ec.value())
279 {
280 return std::nullopt;
281 }
282 std::string dhcpVal{};
283 ec = ipmi::getDbusProperty(ctx, service, ethernetObj.first, ethernetIntf,
284 "DHCPEnabled", dhcpVal);
285 if (ec.value())
286 {
287 return std::nullopt;
Deepak Kodihalli0b459552018-02-06 06:25:12 -0600288 }
289
Vernon Mauery6475b5c2023-07-27 14:52:51 -0700290 return EthernetInterface::convertDHCPConfFromString(dhcpVal);
291}
292
293std::optional<bool> getDHCPOption(ipmi::Context::ptr& ctx,
294 const std::string& prop)
295{
George Liucfd7fa82024-01-22 11:38:29 +0800296 ipmi::ObjectTree objectTree;
297 if (ipmi::getAllDbusObjects(ctx, networkRoot, dhcpIntf, objectTree))
Vernon Mauery6475b5c2023-07-27 14:52:51 -0700298 {
299 return std::nullopt;
Deepak Kodihalli0b459552018-02-06 06:25:12 -0600300 }
301
George Liucfd7fa82024-01-22 11:38:29 +0800302 for (const auto& [path, serviceMap] : objectTree)
303 {
304 for (const auto& [service, object] : serviceMap)
305 {
306 bool value{};
307 if (ipmi::getDbusProperty(ctx, service, path, dhcpIntf, prop,
308 value))
309 {
310 return std::nullopt;
311 }
312
313 if (value)
314 {
315 return true;
316 }
317 }
318 }
319
320 return false;
Vernon Mauery6475b5c2023-07-27 14:52:51 -0700321}
322
323bool setDHCPOption(ipmi::Context::ptr& ctx, std::string prop, bool value)
324{
George Liucfd7fa82024-01-22 11:38:29 +0800325 ipmi::ObjectTree objectTree;
326 if (ipmi::getAllDbusObjects(ctx, networkRoot, dhcpIntf, objectTree))
Vernon Mauery6475b5c2023-07-27 14:52:51 -0700327 {
George Liucfd7fa82024-01-22 11:38:29 +0800328 return false;
Vernon Mauery6475b5c2023-07-27 14:52:51 -0700329 }
George Liucfd7fa82024-01-22 11:38:29 +0800330
331 for (const auto& [path, serviceMap] : objectTree)
332 {
333 for (const auto& [service, object] : serviceMap)
334 {
335 if (ipmi::setDbusProperty(ctx, service, path, dhcpIntf, prop,
336 value))
337 {
338 return false;
339 }
340 }
341 }
342
343 return true;
Deepak Kodihalli0b459552018-02-06 06:25:12 -0600344}
345
Tom Josephbe5eaa12017-07-12 19:54:44 +0530346} // namespace dcmi
Chris Austen1810bec2015-10-13 12:12:39 -0500347
Vernon Maueryd4222fd2023-07-27 11:26:51 -0700348constexpr uint8_t exceptionPowerOff = 0x01;
349ipmi::RspType<uint16_t, // reserved
350 uint8_t, // exception actions
351 uint16_t, // power limit requested in watts
352 uint32_t, // correction time in milliseconds
353 uint16_t, // reserved
354 uint16_t // statistics sampling period in seconds
355 >
356 getPowerLimit(ipmi::Context::ptr ctx, uint16_t reserved)
Tom Josephb9d86f42017-07-26 18:03:47 +0530357{
Kirill Pakhomov2c2af2c2018-11-06 16:06:10 +0300358 if (!dcmi::isDCMIPowerMgmtSupported())
359 {
Vernon Maueryd4222fd2023-07-27 11:26:51 -0700360 return ipmi::responseInvalidCommand();
Kirill Pakhomov2c2af2c2018-11-06 16:06:10 +0300361 }
Vernon Maueryd4222fd2023-07-27 11:26:51 -0700362 if (reserved)
Tom Josephb9d86f42017-07-26 18:03:47 +0530363 {
Vernon Maueryd4222fd2023-07-27 11:26:51 -0700364 return ipmi::responseInvalidFieldRequest();
Tom Josephb9d86f42017-07-26 18:03:47 +0530365 }
366
Vernon Maueryd4222fd2023-07-27 11:26:51 -0700367 std::optional<uint16_t> pcapValue = dcmi::getPcap(ctx);
368 std::optional<bool> pcapEnable = dcmi::getPcapEnabled(ctx);
369 if (!pcapValue || !pcapEnable)
370 {
371 return ipmi::responseUnspecifiedError();
372 }
373
374 constexpr uint16_t reserved1{};
375 constexpr uint16_t reserved2{};
Tom Josephb9d86f42017-07-26 18:03:47 +0530376 /*
377 * Exception action if power limit is exceeded and cannot be controlled
378 * with the correction time limit is hardcoded to Hard Power Off system
379 * and log event to SEL.
380 */
Vernon Maueryd4222fd2023-07-27 11:26:51 -0700381 constexpr uint8_t exception = exceptionPowerOff;
Tom Josephb9d86f42017-07-26 18:03:47 +0530382 /*
383 * Correction time limit and Statistics sampling period is currently not
384 * populated.
385 */
Vernon Maueryd4222fd2023-07-27 11:26:51 -0700386 constexpr uint32_t correctionTime{};
387 constexpr uint16_t statsPeriod{};
Thang Tranfd9c3612023-09-20 11:16:59 +0700388 if (*pcapEnable == false)
Tom Josephb9d86f42017-07-26 18:03:47 +0530389 {
Vernon Maueryd4222fd2023-07-27 11:26:51 -0700390 constexpr ipmi::Cc responseNoPowerLimitSet = 0x80;
Vernon Maueryd4222fd2023-07-27 11:26:51 -0700391 return ipmi::response(responseNoPowerLimitSet, reserved1, exception,
Thang Tranfd9c3612023-09-20 11:16:59 +0700392 *pcapValue, correctionTime, reserved2,
393 statsPeriod);
Tom Josephb9d86f42017-07-26 18:03:47 +0530394 }
Vernon Maueryd4222fd2023-07-27 11:26:51 -0700395 return ipmi::responseSuccess(reserved1, exception, *pcapValue,
396 correctionTime, reserved2, statsPeriod);
Tom Josephb9d86f42017-07-26 18:03:47 +0530397}
398
Vernon Maueryd4222fd2023-07-27 11:26:51 -0700399ipmi::RspType<> setPowerLimit(ipmi::Context::ptr& ctx, uint16_t reserved1,
Thang Tranfd9c3612023-09-20 11:16:59 +0700400 uint8_t reserved2, uint8_t exceptionAction,
401 uint16_t powerLimit, uint32_t correctionTime,
402 uint16_t reserved3, uint16_t statsPeriod)
Tom Joseph46fa37d2017-07-26 18:11:55 +0530403{
Kirill Pakhomov2c2af2c2018-11-06 16:06:10 +0300404 if (!dcmi::isDCMIPowerMgmtSupported())
405 {
George Liu7fa28712024-07-17 19:26:23 +0800406 lg2::error("DCMI Power management is unsupported!");
Vernon Maueryd4222fd2023-07-27 11:26:51 -0700407 return ipmi::responseInvalidCommand();
Kirill Pakhomov2c2af2c2018-11-06 16:06:10 +0300408 }
409
Vernon Maueryd4222fd2023-07-27 11:26:51 -0700410 // Only process the power limit requested in watts. Return errors
411 // for other fields that are set
Thang Tranfd9c3612023-09-20 11:16:59 +0700412 if (reserved1 || reserved2 || reserved3 || correctionTime || statsPeriod ||
Vernon Maueryd4222fd2023-07-27 11:26:51 -0700413 exceptionAction != exceptionPowerOff)
Tom Joseph46fa37d2017-07-26 18:11:55 +0530414 {
Vernon Maueryd4222fd2023-07-27 11:26:51 -0700415 return ipmi::responseInvalidFieldRequest();
Tom Joseph46fa37d2017-07-26 18:11:55 +0530416 }
Vernon Maueryd4222fd2023-07-27 11:26:51 -0700417
418 if (!dcmi::setPcap(ctx, powerLimit))
Tom Joseph46fa37d2017-07-26 18:11:55 +0530419 {
Vernon Maueryd4222fd2023-07-27 11:26:51 -0700420 return ipmi::responseUnspecifiedError();
Tom Joseph46fa37d2017-07-26 18:11:55 +0530421 }
422
George Liu7fa28712024-07-17 19:26:23 +0800423 lg2::info("Set Power Cap: {POWERCAP}", "POWERCAP", powerLimit);
Tom Joseph46fa37d2017-07-26 18:11:55 +0530424
Vernon Maueryd4222fd2023-07-27 11:26:51 -0700425 return ipmi::responseSuccess();
Tom Joseph46fa37d2017-07-26 18:11:55 +0530426}
427
Vernon Maueryd4222fd2023-07-27 11:26:51 -0700428ipmi::RspType<> applyPowerLimit(ipmi::Context::ptr& ctx, bool enabled,
429 uint7_t reserved1, uint16_t reserved2)
Tom Joseph6c8d51b2017-07-26 18:18:06 +0530430{
Kirill Pakhomov2c2af2c2018-11-06 16:06:10 +0300431 if (!dcmi::isDCMIPowerMgmtSupported())
432 {
George Liu7fa28712024-07-17 19:26:23 +0800433 lg2::error("DCMI Power management is unsupported!");
Vernon Maueryd4222fd2023-07-27 11:26:51 -0700434 return ipmi::responseInvalidCommand();
435 }
436 if (reserved1 || reserved2)
437 {
438 return ipmi::responseInvalidFieldRequest();
Kirill Pakhomov2c2af2c2018-11-06 16:06:10 +0300439 }
440
Vernon Maueryd4222fd2023-07-27 11:26:51 -0700441 if (!dcmi::setPcapEnable(ctx, enabled))
Tom Joseph6c8d51b2017-07-26 18:18:06 +0530442 {
Vernon Maueryd4222fd2023-07-27 11:26:51 -0700443 return ipmi::responseUnspecifiedError();
Tom Joseph6c8d51b2017-07-26 18:18:06 +0530444 }
445
George Liu7fa28712024-07-17 19:26:23 +0800446 lg2::info("Set Power Cap Enable: {POWERCAPENABLE}", "POWERCAPENABLE",
447 enabled);
Tom Joseph6c8d51b2017-07-26 18:18:06 +0530448
Vernon Maueryd4222fd2023-07-27 11:26:51 -0700449 return ipmi::responseSuccess();
Tom Joseph6c8d51b2017-07-26 18:18:06 +0530450}
451
Vernon Mauerydca47202023-07-27 11:32:01 -0700452ipmi::RspType<uint8_t, // total tag length
453 std::vector<char> // tag data
454 >
455 getAssetTag(ipmi::Context::ptr& ctx, uint8_t offset, uint8_t count)
Tom Joseph6f6dd4d2017-07-12 20:07:11 +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 Joseph6f6dd4d2017-07-12 20:07:11 +0530461 {
Vernon Mauerydca47202023-07-27 11:32:01 -0700462 return ipmi::responseParmOutOfRange();
Tom Joseph6f6dd4d2017-07-12 20:07:11 +0530463 }
464
Vernon Mauerydca47202023-07-27 11:32:01 -0700465 std::optional<std::string> assetTagResp = dcmi::readAssetTag(ctx);
466 if (!assetTagResp)
Tom Joseph6f6dd4d2017-07-12 20:07:11 +0530467 {
Vernon Mauerydca47202023-07-27 11:32:01 -0700468 return ipmi::responseUnspecifiedError();
Tom Joseph6f6dd4d2017-07-12 20:07:11 +0530469 }
470
Vernon Mauerydca47202023-07-27 11:32:01 -0700471 std::string& assetTag = assetTagResp.value();
472 // If the asset tag is longer than 63 bytes, restrict it to 63 bytes to
473 // suit Get Asset Tag command.
Tom Joseph6f6dd4d2017-07-12 20:07:11 +0530474 if (assetTag.size() > dcmi::assetTagMaxSize)
475 {
476 assetTag.resize(dcmi::assetTagMaxSize);
477 }
478
Vernon Mauerydca47202023-07-27 11:32:01 -0700479 if (offset >= assetTag.size())
Tom Joseph6f6dd4d2017-07-12 20:07:11 +0530480 {
Vernon Mauerydca47202023-07-27 11:32:01 -0700481 return ipmi::responseParmOutOfRange();
Tom Joseph6f6dd4d2017-07-12 20:07:11 +0530482 }
483
Vernon Mauerydca47202023-07-27 11:32:01 -0700484 // silently truncate reads beyond the end of assetTag
485 if ((offset + count) >= assetTag.size())
486 {
487 count = assetTag.size() - offset;
488 }
Tom Joseph6f6dd4d2017-07-12 20:07:11 +0530489
Vernon Mauerydca47202023-07-27 11:32:01 -0700490 auto totalTagSize = static_cast<uint8_t>(assetTag.size());
491 std::vector<char> data{assetTag.begin() + offset,
492 assetTag.begin() + offset + count};
Tom Joseph6f6dd4d2017-07-12 20:07:11 +0530493
Vernon Mauerydca47202023-07-27 11:32:01 -0700494 return ipmi::responseSuccess(totalTagSize, data);
Tom Joseph6f6dd4d2017-07-12 20:07:11 +0530495}
496
Vernon Mauerydca47202023-07-27 11:32:01 -0700497ipmi::RspType<uint8_t // new asset tag length
498 >
499 setAssetTag(ipmi::Context::ptr& ctx, uint8_t offset, uint8_t count,
500 const std::vector<char>& data)
Tom Joseph545dd232017-07-12 20:20:49 +0530501{
Vernon Mauerydca47202023-07-27 11:32:01 -0700502 // Verify offset to read and number of bytes to read are not exceeding
503 // the range.
504 if ((offset > dcmi::assetTagMaxOffset) || (count > dcmi::maxBytes) ||
505 ((offset + count) > dcmi::assetTagMaxSize))
Tom Joseph545dd232017-07-12 20:20:49 +0530506 {
Vernon Mauerydca47202023-07-27 11:32:01 -0700507 return ipmi::responseParmOutOfRange();
508 }
509 if (data.size() != count)
510 {
511 return ipmi::responseReqDataLenInvalid();
Tom Joseph545dd232017-07-12 20:20:49 +0530512 }
513
Vernon Mauerydca47202023-07-27 11:32:01 -0700514 std::optional<std::string> assetTagResp = dcmi::readAssetTag(ctx);
515 if (!assetTagResp)
Tom Joseph545dd232017-07-12 20:20:49 +0530516 {
Vernon Mauerydca47202023-07-27 11:32:01 -0700517 return ipmi::responseUnspecifiedError();
Tom Joseph545dd232017-07-12 20:20:49 +0530518 }
Vernon Mauerydca47202023-07-27 11:32:01 -0700519
520 std::string& assetTag = assetTagResp.value();
521
522 if (offset > assetTag.size())
Tom Joseph545dd232017-07-12 20:20:49 +0530523 {
Vernon Mauerydca47202023-07-27 11:32:01 -0700524 return ipmi::responseParmOutOfRange();
Tom Joseph545dd232017-07-12 20:20:49 +0530525 }
Vernon Mauerydca47202023-07-27 11:32:01 -0700526
527 // operation is to truncate at offset and append new data
528 assetTag.resize(offset);
529 assetTag.append(data.begin(), data.end());
530
531 if (!dcmi::writeAssetTag(ctx, assetTag))
532 {
533 return ipmi::responseUnspecifiedError();
534 }
535
536 auto totalTagSize = static_cast<uint8_t>(assetTag.size());
537 return ipmi::responseSuccess(totalTagSize);
Tom Joseph545dd232017-07-12 20:20:49 +0530538}
539
Vernon Maueryefb5ae52023-07-27 11:35:43 -0700540ipmi::RspType<uint8_t, // length
541 std::vector<char> // data
542 >
543 getMgmntCtrlIdStr(ipmi::Context::ptr& ctx, uint8_t offset, uint8_t count)
Vladislav Vovchenko8f7a6f62017-08-17 00:31:14 +0300544{
Vernon Maueryefb5ae52023-07-27 11:35:43 -0700545 if (count > dcmi::maxBytes || offset + count > dcmi::maxCtrlIdStrLen)
Vladislav Vovchenko8f7a6f62017-08-17 00:31:14 +0300546 {
Vernon Maueryefb5ae52023-07-27 11:35:43 -0700547 return ipmi::responseParmOutOfRange();
Vladislav Vovchenko8f7a6f62017-08-17 00:31:14 +0300548 }
549
Vernon Maueryefb5ae52023-07-27 11:35:43 -0700550 std::optional<std::string> hostnameResp = dcmi::getHostName(ctx);
551 if (!hostnameResp)
Vladislav Vovchenko8f7a6f62017-08-17 00:31:14 +0300552 {
Vernon Maueryefb5ae52023-07-27 11:35:43 -0700553 return ipmi::responseUnspecifiedError();
Vladislav Vovchenko8f7a6f62017-08-17 00:31:14 +0300554 }
555
Vernon Maueryefb5ae52023-07-27 11:35:43 -0700556 std::string& hostname = hostnameResp.value();
557 // If the id string is longer than 63 bytes, restrict it to 63 bytes to
558 // suit set management ctrl str command.
559 if (hostname.size() > dcmi::maxCtrlIdStrLen)
Vladislav Vovchenko8f7a6f62017-08-17 00:31:14 +0300560 {
Vernon Maueryefb5ae52023-07-27 11:35:43 -0700561 hostname.resize(dcmi::maxCtrlIdStrLen);
Vladislav Vovchenko8f7a6f62017-08-17 00:31:14 +0300562 }
Vladislav Vovchenko8f7a6f62017-08-17 00:31:14 +0300563
Vernon Maueryefb5ae52023-07-27 11:35:43 -0700564 if (offset >= hostname.size())
565 {
566 return ipmi::responseParmOutOfRange();
567 }
568
569 // silently truncate reads beyond the end of hostname
570 if ((offset + count) >= hostname.size())
571 {
572 count = hostname.size() - offset;
573 }
574
575 auto nameSize = static_cast<uint8_t>(hostname.size());
576 std::vector<char> data{hostname.begin() + offset,
577 hostname.begin() + offset + count};
578
579 return ipmi::responseSuccess(nameSize, data);
Vladislav Vovchenko8f7a6f62017-08-17 00:31:14 +0300580}
581
Patrick Williams1318a5e2024-08-16 15:19:54 -0400582ipmi::RspType<uint8_t>
583 setMgmntCtrlIdStr(ipmi::Context::ptr& ctx, uint8_t offset, uint8_t count,
584 std::vector<char> data)
Vladislav Vovchenko8f7a6f62017-08-17 00:31:14 +0300585{
Vernon Maueryefb5ae52023-07-27 11:35:43 -0700586 if ((offset > dcmi::maxCtrlIdStrLen) || (count > dcmi::maxBytes) ||
587 ((offset + count) > dcmi::maxCtrlIdStrLen))
Vladislav Vovchenko8f7a6f62017-08-17 00:31:14 +0300588 {
Vernon Maueryefb5ae52023-07-27 11:35:43 -0700589 return ipmi::responseParmOutOfRange();
590 }
591 if (data.size() != count)
592 {
593 return ipmi::responseReqDataLenInvalid();
594 }
595 bool terminalWrite{data.back() == '\0'};
596 if (terminalWrite)
597 {
598 // remove the null termination from the data (no need with std::string)
599 data.resize(count - 1);
Vladislav Vovchenko8f7a6f62017-08-17 00:31:14 +0300600 }
601
Vernon Maueryefb5ae52023-07-27 11:35:43 -0700602 static std::string hostname{};
603 // read in the current value if not starting at offset 0
604 if (hostname.size() == 0 && offset != 0)
Vladislav Vovchenko8f7a6f62017-08-17 00:31:14 +0300605 {
Vernon Maueryefb5ae52023-07-27 11:35:43 -0700606 /* read old ctrlIdStr */
607 std::optional<std::string> hostnameResp = dcmi::getHostName(ctx);
608 if (!hostnameResp)
Vladislav Vovchenko8f7a6f62017-08-17 00:31:14 +0300609 {
Vernon Maueryefb5ae52023-07-27 11:35:43 -0700610 return ipmi::responseUnspecifiedError();
Vladislav Vovchenko8f7a6f62017-08-17 00:31:14 +0300611 }
Vernon Maueryefb5ae52023-07-27 11:35:43 -0700612 hostname = hostnameResp.value();
613 hostname.resize(offset);
Vladislav Vovchenko8f7a6f62017-08-17 00:31:14 +0300614 }
615
Vernon Maueryefb5ae52023-07-27 11:35:43 -0700616 // operation is to truncate at offset and append new data
617 hostname.append(data.begin(), data.end());
618
619 // do the update if this is the last write
620 if (terminalWrite)
621 {
622 boost::system::error_code ec = ipmi::setDbusProperty(
623 ctx, dcmi::networkServiceName, dcmi::networkConfigObj,
624 dcmi::networkConfigIntf, dcmi::hostNameProp, hostname);
625 hostname.clear();
626 if (ec.value())
627 {
628 return ipmi::responseUnspecifiedError();
629 }
630 }
631
632 auto totalIdSize = static_cast<uint8_t>(offset + count);
633 return ipmi::responseSuccess(totalIdSize);
Vladislav Vovchenko8f7a6f62017-08-17 00:31:14 +0300634}
635
Vernon Maueryf038dc02023-07-27 14:06:11 -0700636ipmi::RspType<ipmi::message::Payload> getDCMICapabilities(uint8_t parameter)
Dhruvaraj Subhashchandrane29be412018-01-16 05:11:56 -0600637{
Kirill Pakhomova2573622018-11-02 19:00:18 +0300638 std::ifstream dcmiCapFile(dcmi::gDCMICapabilitiesConfig);
Dhruvaraj Subhashchandrane29be412018-01-16 05:11:56 -0600639 if (!dcmiCapFile.is_open())
640 {
George Liu7fa28712024-07-17 19:26:23 +0800641 lg2::error("DCMI Capabilities file not found");
Vernon Maueryf038dc02023-07-27 14:06:11 -0700642 return ipmi::responseUnspecifiedError();
Dhruvaraj Subhashchandrane29be412018-01-16 05:11:56 -0600643 }
644
645 auto data = nlohmann::json::parse(dcmiCapFile, nullptr, false);
646 if (data.is_discarded())
647 {
George Liu7fa28712024-07-17 19:26:23 +0800648 lg2::error("DCMI Capabilities JSON parser failure");
Vernon Maueryf038dc02023-07-27 14:06:11 -0700649 return ipmi::responseUnspecifiedError();
Dhruvaraj Subhashchandrane29be412018-01-16 05:11:56 -0600650 }
651
Vernon Maueryf038dc02023-07-27 14:06:11 -0700652 constexpr bool reserved1{};
653 constexpr uint5_t reserved5{};
654 constexpr uint7_t reserved7{};
655 constexpr uint8_t reserved8{};
656 constexpr uint16_t reserved16{};
Dhruvaraj Subhashchandrane29be412018-01-16 05:11:56 -0600657
Vernon Maueryf038dc02023-07-27 14:06:11 -0700658 ipmi::message::Payload payload;
659 payload.pack(dcmi::specMajorVersion, dcmi::specMinorVersion,
660 dcmi::parameterRevision);
661
662 enum class DCMICapParameters : uint8_t
Dhruvaraj Subhashchandrane29be412018-01-16 05:11:56 -0600663 {
Vernon Maueryf038dc02023-07-27 14:06:11 -0700664 SupportedDcmiCaps = 0x01, // Supported DCMI Capabilities
665 MandatoryPlatAttributes = 0x02, // Mandatory Platform Attributes
666 OptionalPlatAttributes = 0x03, // Optional Platform Attributes
667 ManageabilityAccessAttributes = 0x04, // Manageability Access Attributes
668 };
Dhruvaraj Subhashchandrane29be412018-01-16 05:11:56 -0600669
Vernon Maueryf038dc02023-07-27 14:06:11 -0700670 switch (static_cast<DCMICapParameters>(parameter))
Dhruvaraj Subhashchandrane29be412018-01-16 05:11:56 -0600671 {
Vernon Maueryf038dc02023-07-27 14:06:11 -0700672 case DCMICapParameters::SupportedDcmiCaps:
Dhruvaraj Subhashchandrane29be412018-01-16 05:11:56 -0600673 {
Vernon Maueryf038dc02023-07-27 14:06:11 -0700674 bool powerManagement = data.value("PowerManagement", 0);
675 bool oobSecondaryLan = data.value("OOBSecondaryLan", 0);
676 bool serialTMode = data.value("SerialTMODE", 0);
677 bool inBandSystemInterfaceChannel =
678 data.value("InBandSystemInterfaceChannel", 0);
679 payload.pack(reserved8, powerManagement, reserved7,
680 inBandSystemInterfaceChannel, serialTMode,
681 oobSecondaryLan, reserved5);
682 break;
Dhruvaraj Subhashchandrane29be412018-01-16 05:11:56 -0600683 }
Vernon Maueryf038dc02023-07-27 14:06:11 -0700684 // Mandatory Platform Attributes
685 case DCMICapParameters::MandatoryPlatAttributes:
Dhruvaraj Subhashchandrane29be412018-01-16 05:11:56 -0600686 {
Vernon Maueryf038dc02023-07-27 14:06:11 -0700687 bool selAutoRollOver = data.value("SELAutoRollOver", 0);
688 bool flushEntireSELUponRollOver =
689 data.value("FlushEntireSELUponRollOver", 0);
690 bool recordLevelSELFlushUponRollOver =
691 data.value("RecordLevelSELFlushUponRollOver", 0);
Patrick Williams1318a5e2024-08-16 15:19:54 -0400692 uint12_t numberOfSELEntries =
693 data.value("NumberOfSELEntries", 0xcac);
Vernon Maueryf038dc02023-07-27 14:06:11 -0700694 uint8_t tempMonitoringSamplingFreq =
695 data.value("TempMonitoringSamplingFreq", 0);
696 payload.pack(numberOfSELEntries, reserved1,
697 recordLevelSELFlushUponRollOver,
698 flushEntireSELUponRollOver, selAutoRollOver,
699 reserved16, tempMonitoringSamplingFreq);
700 break;
701 }
702 // Optional Platform Attributes
703 case DCMICapParameters::OptionalPlatAttributes:
704 {
Matt Simmering68d9d402023-11-09 14:22:11 -0800705 uint7_t powerMgmtDeviceTargetAddress =
Vernon Maueryf038dc02023-07-27 14:06:11 -0700706 data.value("PowerMgmtDeviceSlaveAddress", 0);
707 uint4_t bmcChannelNumber = data.value("BMCChannelNumber", 0);
708 uint4_t deviceRivision = data.value("DeviceRivision", 0);
Matt Simmering68d9d402023-11-09 14:22:11 -0800709 payload.pack(powerMgmtDeviceTargetAddress, reserved1,
710 deviceRivision, bmcChannelNumber);
Vernon Maueryf038dc02023-07-27 14:06:11 -0700711 break;
712 }
713 // Manageability Access Attributes
714 case DCMICapParameters::ManageabilityAccessAttributes:
715 {
716 uint8_t mandatoryPrimaryLanOOBSupport =
717 data.value("MandatoryPrimaryLanOOBSupport", 0xff);
718 uint8_t optionalSecondaryLanOOBSupport =
719 data.value("OptionalSecondaryLanOOBSupport", 0xff);
720 uint8_t optionalSerialOOBMTMODECapability =
721 data.value("OptionalSerialOOBMTMODECapability", 0xff);
722 payload.pack(mandatoryPrimaryLanOOBSupport,
723 optionalSecondaryLanOOBSupport,
724 optionalSerialOOBMTMODECapability);
725 break;
726 }
727 default:
728 {
George Liu7fa28712024-07-17 19:26:23 +0800729 lg2::error("Invalid input parameter");
Vernon Maueryf038dc02023-07-27 14:06:11 -0700730 return ipmi::responseInvalidFieldRequest();
Dhruvaraj Subhashchandrane29be412018-01-16 05:11:56 -0600731 }
732 }
733
Vernon Maueryf038dc02023-07-27 14:06:11 -0700734 return ipmi::responseSuccess(payload);
Dhruvaraj Subhashchandrane29be412018-01-16 05:11:56 -0600735}
736
Deepak Kodihalliee717d72018-01-24 04:53:09 -0600737namespace dcmi
738{
739namespace temp_readings
740{
741
Patrick Williams1318a5e2024-08-16 15:19:54 -0400742std::tuple<bool, bool, uint8_t>
743 readTemp(ipmi::Context::ptr& ctx, const std::string& dbusService,
744 const std::string& dbusPath)
Deepak Kodihallib1e8fba2018-01-24 04:57:10 -0600745{
746 // Read the temperature value from d-bus object. Need some conversion.
Vernon Mauerycce9ffd2023-07-27 14:15:17 -0700747 // As per the interface xyz.openbmc_project.Sensor.Value, the
748 // temperature is an double and in degrees C. It needs to be scaled by
749 // using the formula Value * 10^Scale. The ipmi spec has the temperature
750 // as a uint8_t, with a separate single bit for the sign.
Deepak Kodihallib1e8fba2018-01-24 04:57:10 -0600751
Vernon Mauerycce9ffd2023-07-27 14:15:17 -0700752 ipmi::PropertyMap result{};
753 boost::system::error_code ec = ipmi::getAllDbusProperties(
754 ctx, dbusService, dbusPath, "xyz.openbmc_project.Sensor.Value", result);
755 if (ec.value())
756 {
757 return std::make_tuple(false, false, 0);
758 }
Patrick Williams1318a5e2024-08-16 15:19:54 -0400759 auto temperature =
760 std::visit(ipmi::VariantToDoubleVisitor(), result.at("Value"));
James Feist9cc0ea52018-10-09 10:53:11 -0700761 double absTemp = std::abs(temperature);
Deepak Kodihallib1e8fba2018-01-24 04:57:10 -0600762
James Feist9cc0ea52018-10-09 10:53:11 -0700763 auto findFactor = result.find("Scale");
764 double factor = 0.0;
765 if (findFactor != result.end())
Deepak Kodihallib1e8fba2018-01-24 04:57:10 -0600766 {
Vernon Maueryf442e112019-04-09 11:44:36 -0700767 factor = std::visit(ipmi::VariantToDoubleVisitor(), findFactor->second);
Deepak Kodihallib1e8fba2018-01-24 04:57:10 -0600768 }
James Feist9cc0ea52018-10-09 10:53:11 -0700769 double scale = std::pow(10, factor);
770
771 auto tempDegrees = absTemp * scale;
Vernon Mauerycce9ffd2023-07-27 14:15:17 -0700772 // Max absolute temp as per ipmi spec is 127.
773 constexpr auto maxTemp = 127;
Deepak Kodihallib1e8fba2018-01-24 04:57:10 -0600774 if (tempDegrees > maxTemp)
775 {
776 tempDegrees = maxTemp;
777 }
778
Vernon Mauerycce9ffd2023-07-27 14:15:17 -0700779 return std::make_tuple(true, (temperature < 0),
780 static_cast<uint8_t>(tempDegrees));
Deepak Kodihallib1e8fba2018-01-24 04:57:10 -0600781}
782
Vernon Mauerycce9ffd2023-07-27 14:15:17 -0700783std::tuple<std::vector<std::tuple<uint7_t, bool, uint8_t>>, uint8_t>
784 read(ipmi::Context::ptr& ctx, const std::string& type, uint8_t instance,
785 size_t count)
Deepak Kodihalliee717d72018-01-24 04:53:09 -0600786{
Vernon Mauerycce9ffd2023-07-27 14:15:17 -0700787 std::vector<std::tuple<uint7_t, bool, uint8_t>> response{};
Deepak Kodihallib1e8fba2018-01-24 04:57:10 -0600788
Kirill Pakhomova2573622018-11-02 19:00:18 +0300789 auto data = parseJSONConfig(gDCMISensorsConfig);
Vernon Mauerycce9ffd2023-07-27 14:15:17 -0700790 static const std::vector<nlohmann::json> empty{};
791 std::vector<nlohmann::json> readings = data.value(type, empty);
Deepak Kodihallib1e8fba2018-01-24 04:57:10 -0600792 for (const auto& j : readings)
793 {
Vernon Mauerycce9ffd2023-07-27 14:15:17 -0700794 // Max of 8 response data sets
795 if (response.size() == count)
796 {
797 break;
798 }
799
Deepak Kodihallib1e8fba2018-01-24 04:57:10 -0600800 uint8_t instanceNum = j.value("instance", 0);
Vernon Mauerycce9ffd2023-07-27 14:15:17 -0700801 // Not in the instance range we're interested in
802 if (instanceNum < instance)
Deepak Kodihallib1e8fba2018-01-24 04:57:10 -0600803 {
804 continue;
805 }
806
807 std::string path = j.value("dbus", "");
Vernon Mauerycce9ffd2023-07-27 14:15:17 -0700808 std::string service{};
809 boost::system::error_code ec = ipmi::getService(
810 ctx, "xyz.openbmc_project.Sensor.Value", path, service);
811 if (ec.value())
Deepak Kodihallib1e8fba2018-01-24 04:57:10 -0600812 {
Vernon Mauerycce9ffd2023-07-27 14:15:17 -0700813 // not found on dbus
Deepak Kodihallib1e8fba2018-01-24 04:57:10 -0600814 continue;
815 }
Vernon Mauerycce9ffd2023-07-27 14:15:17 -0700816
817 const auto& [ok, sign, temp] = readTemp(ctx, service, path);
818 if (ok)
819 {
820 response.emplace_back(uint7_t{temp}, sign, instanceNum);
821 }
Deepak Kodihallib1e8fba2018-01-24 04:57:10 -0600822 }
823
Vernon Mauerycce9ffd2023-07-27 14:15:17 -0700824 auto totalInstances =
825 static_cast<uint8_t>(std::min(readings.size(), maxInstances));
826 return std::make_tuple(response, totalInstances);
Deepak Kodihalliee717d72018-01-24 04:53:09 -0600827}
828
Patrick Venture0b02be92018-08-31 11:55:55 -0700829} // namespace temp_readings
830} // namespace dcmi
Deepak Kodihalliee717d72018-01-24 04:53:09 -0600831
Vernon Mauerycce9ffd2023-07-27 14:15:17 -0700832ipmi::RspType<uint8_t, // total instances for entity id
833 uint8_t, // number of instances in this reply
834 std::vector< // zero or more of the following two bytes
835 std::tuple<uint7_t, // temperature value
836 bool, // sign bit
837 uint8_t // entity instance
838 >>>
839 getTempReadings(ipmi::Context::ptr& ctx, uint8_t sensorType,
840 uint8_t entityId, uint8_t entityInstance,
841 uint8_t instanceStart)
Deepak Kodihalliee717d72018-01-24 04:53:09 -0600842{
Vernon Mauerycce9ffd2023-07-27 14:15:17 -0700843 auto it = dcmi::entityIdToName.find(entityId);
Deepak Kodihalli0b459552018-02-06 06:25:12 -0600844 if (it == dcmi::entityIdToName.end())
Deepak Kodihalliee717d72018-01-24 04:53:09 -0600845 {
George Liu7fa28712024-07-17 19:26:23 +0800846 lg2::error("Unknown Entity ID: {ENTITY_ID}", "ENTITY_ID", entityId);
Vernon Mauerycce9ffd2023-07-27 14:15:17 -0700847 return ipmi::responseInvalidFieldRequest();
Deepak Kodihalliee717d72018-01-24 04:53:09 -0600848 }
849
Vernon Mauerycce9ffd2023-07-27 14:15:17 -0700850 if (sensorType != dcmi::temperatureSensorType)
Deepak Kodihalliee717d72018-01-24 04:53:09 -0600851 {
George Liu7fa28712024-07-17 19:26:23 +0800852 lg2::error("Invalid sensor type: {SENSOR_TYPE}", "SENSOR_TYPE",
853 sensorType);
Vernon Mauerycce9ffd2023-07-27 14:15:17 -0700854 return ipmi::responseInvalidFieldRequest();
Deepak Kodihalliee717d72018-01-24 04:53:09 -0600855 }
856
Vernon Mauerycce9ffd2023-07-27 14:15:17 -0700857 uint8_t requestedRecords = (entityInstance == 0) ? dcmi::maxRecords : 1;
Deepak Kodihalliee717d72018-01-24 04:53:09 -0600858
Vernon Mauerycce9ffd2023-07-27 14:15:17 -0700859 // Read requested instances
860 const auto& [temps, totalInstances] = dcmi::temp_readings::read(
861 ctx, it->second, instanceStart, requestedRecords);
Deepak Kodihalliee717d72018-01-24 04:53:09 -0600862
Vernon Mauerycce9ffd2023-07-27 14:15:17 -0700863 auto numInstances = static_cast<uint8_t>(temps.size());
864
865 return ipmi::responseSuccess(totalInstances, numInstances, temps);
Deepak Kodihalliee717d72018-01-24 04:53:09 -0600866}
867
Vernon Mauery6475b5c2023-07-27 14:52:51 -0700868ipmi::RspType<> setDCMIConfParams(ipmi::Context::ptr& ctx, uint8_t parameter,
869 uint8_t setSelector,
870 ipmi::message::Payload& payload)
Nagaraju Goruganti22be97b2018-02-07 01:19:59 -0600871{
Vernon Mauery6475b5c2023-07-27 14:52:51 -0700872 if (setSelector)
Nagaraju Goruganti22be97b2018-02-07 01:19:59 -0600873 {
Vernon Mauery6475b5c2023-07-27 14:52:51 -0700874 return ipmi::responseInvalidFieldRequest();
Nagaraju Goruganti22be97b2018-02-07 01:19:59 -0600875 }
Vernon Mauery6475b5c2023-07-27 14:52:51 -0700876 // Take action based on the Parameter Selector
877 switch (static_cast<dcmi::DCMIConfigParameters>(parameter))
Nagaraju Goruganti22be97b2018-02-07 01:19:59 -0600878 {
Vernon Mauery6475b5c2023-07-27 14:52:51 -0700879 case dcmi::DCMIConfigParameters::ActivateDHCP:
Nagaraju Goruganti22be97b2018-02-07 01:19:59 -0600880 {
Vernon Mauery6475b5c2023-07-27 14:52:51 -0700881 uint7_t reserved{};
882 bool activate{};
883 if (payload.unpack(activate, reserved) || !payload.fullyUnpacked())
884 {
885 return ipmi::responseReqDataLenInvalid();
886 }
887 if (reserved)
888 {
889 return ipmi::responseInvalidFieldRequest();
890 }
891 std::optional<EthernetInterface::DHCPConf> dhcpEnabled =
892 dcmi::getDHCPEnabled(ctx);
893 if (!dhcpEnabled)
894 {
895 return ipmi::responseUnspecifiedError();
896 }
897 if (activate &&
898 (dhcpEnabled.value() != EthernetInterface::DHCPConf::none))
899 {
900 // When these conditions are met we have to trigger DHCP
901 // protocol restart using the latest parameter settings,
902 // but as per n/w manager design, each time when we
903 // update n/w parameters, n/w service is restarted. So
904 // we no need to take any action in this case.
905 }
906 break;
Nagaraju Goruganti22be97b2018-02-07 01:19:59 -0600907 }
Vernon Mauery6475b5c2023-07-27 14:52:51 -0700908 case dcmi::DCMIConfigParameters::DiscoveryConfig:
909 {
910 bool option12{};
911 uint6_t reserved1{};
912 bool randBackOff{};
913 if (payload.unpack(option12, reserved1, randBackOff) ||
914 !payload.fullyUnpacked())
915 {
916 return ipmi::responseReqDataLenInvalid();
917 }
918 // Systemd-networkd doesn't support Random Back off
919 if (reserved1 || randBackOff)
920 {
921 return ipmi::responseInvalidFieldRequest();
922 }
923 dcmi::setDHCPOption(ctx, dcmi::dhcpOpt12Enabled, option12);
924 break;
925 }
926 // Systemd-networkd doesn't allow to configure DHCP timigs
927 case dcmi::DCMIConfigParameters::DHCPTiming1:
928 case dcmi::DCMIConfigParameters::DHCPTiming2:
929 case dcmi::DCMIConfigParameters::DHCPTiming3:
930 default:
931 return ipmi::responseInvalidFieldRequest();
Nagaraju Goruganti22be97b2018-02-07 01:19:59 -0600932 }
Vernon Mauery6475b5c2023-07-27 14:52:51 -0700933 return ipmi::responseSuccess();
Nagaraju Goruganti22be97b2018-02-07 01:19:59 -0600934}
935
Patrick Williams1318a5e2024-08-16 15:19:54 -0400936ipmi::RspType<ipmi::message::Payload> getDCMIConfParams(
937 ipmi::Context::ptr& ctx, uint8_t parameter, uint8_t setSelector)
Nagaraju Goruganti22be97b2018-02-07 01:19:59 -0600938{
Vernon Mauery6475b5c2023-07-27 14:52:51 -0700939 if (setSelector)
Nagaraju Goruganti22be97b2018-02-07 01:19:59 -0600940 {
Vernon Mauery6475b5c2023-07-27 14:52:51 -0700941 return ipmi::responseInvalidFieldRequest();
Nagaraju Goruganti22be97b2018-02-07 01:19:59 -0600942 }
Vernon Mauery6475b5c2023-07-27 14:52:51 -0700943 ipmi::message::Payload payload;
944 payload.pack(dcmi::specMajorVersion, dcmi::specMinorVersion,
945 dcmi::configParameterRevision);
Nagaraju Goruganti22be97b2018-02-07 01:19:59 -0600946
Vernon Mauery6475b5c2023-07-27 14:52:51 -0700947 // Take action based on the Parameter Selector
948 switch (static_cast<dcmi::DCMIConfigParameters>(parameter))
Nagaraju Goruganti22be97b2018-02-07 01:19:59 -0600949 {
Vernon Mauery6475b5c2023-07-27 14:52:51 -0700950 case dcmi::DCMIConfigParameters::ActivateDHCP:
951 payload.pack(dcmi::activateDhcpReply);
952 break;
953 case dcmi::DCMIConfigParameters::DiscoveryConfig:
Nagaraju Goruganti22be97b2018-02-07 01:19:59 -0600954 {
Vernon Mauery6475b5c2023-07-27 14:52:51 -0700955 uint8_t discovery{};
956 std::optional<bool> enabled =
957 dcmi::getDHCPOption(ctx, dcmi::dhcpOpt12Enabled);
958 if (!enabled.has_value())
959 {
960 return ipmi::responseUnspecifiedError();
961 }
962 if (enabled.value())
963 {
964 discovery = dcmi::option12Mask;
965 }
966 payload.pack(discovery);
967 break;
Nagaraju Goruganti22be97b2018-02-07 01:19:59 -0600968 }
Vernon Mauery6475b5c2023-07-27 14:52:51 -0700969 // Get below values from Systemd-networkd source code
970 case dcmi::DCMIConfigParameters::DHCPTiming1:
971 payload.pack(dcmi::dhcpTiming1);
972 break;
973 case dcmi::DCMIConfigParameters::DHCPTiming2:
974 payload.pack(dcmi::dhcpTiming2);
975 break;
976 case dcmi::DCMIConfigParameters::DHCPTiming3:
977 payload.pack(dcmi::dhcpTiming3);
978 break;
979 default:
980 return ipmi::responseInvalidFieldRequest();
Nagaraju Goruganti22be97b2018-02-07 01:19:59 -0600981 }
982
Thang Tranaf762de2023-12-18 11:19:28 +0700983 return ipmi::responseSuccess(payload);
Nagaraju Goruganti22be97b2018-02-07 01:19:59 -0600984}
985
Vernon Mauery056fab12023-07-27 14:25:24 -0700986static std::optional<uint16_t> readPower(ipmi::Context::ptr& ctx)
Marri Devender Rao66c5fda2018-01-18 10:48:37 -0600987{
Vernon Mauery056fab12023-07-27 14:25:24 -0700988 std::ifstream sensorFile(POWER_READING_SENSOR);
989 std::string objectPath;
990 if (!sensorFile.is_open())
991 {
George Liu7fa28712024-07-17 19:26:23 +0800992 lg2::error(
993 "Power reading configuration file not found: {POWER_SENSOR_FILE}",
994 "POWER_SENSOR_FILE", std::string_view{POWER_READING_SENSOR});
Vernon Mauery056fab12023-07-27 14:25:24 -0700995 return std::nullopt;
996 }
997
998 auto data = nlohmann::json::parse(sensorFile, nullptr, false);
999 if (data.is_discarded())
1000 {
George Liu7fa28712024-07-17 19:26:23 +08001001 lg2::error("Error in parsing configuration file: {POWER_SENSOR_FILE}",
1002 "POWER_SENSOR_FILE", std::string_view{POWER_READING_SENSOR});
Vernon Mauery056fab12023-07-27 14:25:24 -07001003 return std::nullopt;
1004 }
1005
1006 objectPath = data.value("path", "");
1007 if (objectPath.empty())
1008 {
George Liu7fa28712024-07-17 19:26:23 +08001009 lg2::error(
1010 "Power sensor D-Bus object path is empty: {POWER_SENSOR_FILE}",
1011 "POWER_SENSOR_FILE", std::string_view{POWER_READING_SENSOR});
Vernon Mauery056fab12023-07-27 14:25:24 -07001012 return std::nullopt;
1013 }
1014
1015 // Return default value if failed to read from D-Bus object
1016 std::string service{};
Patrick Williams1318a5e2024-08-16 15:19:54 -04001017 boost::system::error_code ec =
1018 ipmi::getService(ctx, dcmi::sensorValueIntf, objectPath, service);
Vernon Mauery056fab12023-07-27 14:25:24 -07001019 if (ec.value())
1020 {
George Liu7fa28712024-07-17 19:26:23 +08001021 lg2::error("Failed to fetch service for D-Bus object, "
1022 "object path: {OBJECT_PATH}, interface: {INTERFACE}",
1023 "OBJECT_PATH", objectPath, "INTERFACE",
1024 dcmi::sensorValueIntf);
Vernon Mauery056fab12023-07-27 14:25:24 -07001025 return std::nullopt;
1026 }
1027
1028 // Read the sensor value and scale properties
1029 double value{};
1030 ec = ipmi::getDbusProperty(ctx, service, objectPath, dcmi::sensorValueIntf,
1031 dcmi::sensorValueProp, value);
1032 if (ec.value())
1033 {
George Liu7fa28712024-07-17 19:26:23 +08001034 lg2::error("Failed to read power value from D-Bus object, "
1035 "object path: {OBJECT_PATH}, interface: {INTERFACE}",
1036 "OBJECT_PATH", objectPath, "INTERFACE",
1037 dcmi::sensorValueIntf);
Vernon Mauery056fab12023-07-27 14:25:24 -07001038 return std::nullopt;
1039 }
1040 auto power = static_cast<uint16_t>(value);
1041 return power;
1042}
1043
1044ipmi::RspType<uint16_t, // current power
1045 uint16_t, // minimum power
1046 uint16_t, // maximum power
1047 uint16_t, // average power
1048 uint32_t, // timestamp
1049 uint32_t, // sample period ms
1050 uint6_t, // reserved
1051 bool, // power measurement active
1052 bool // reserved
1053 >
1054 getPowerReading(ipmi::Context::ptr& ctx, uint8_t mode, uint8_t attributes,
1055 uint8_t reserved)
1056{
Kirill Pakhomov2c2af2c2018-11-06 16:06:10 +03001057 if (!dcmi::isDCMIPowerMgmtSupported())
1058 {
George Liu7fa28712024-07-17 19:26:23 +08001059 lg2::error("DCMI Power management is unsupported!");
Vernon Mauery056fab12023-07-27 14:25:24 -07001060 return ipmi::responseInvalidCommand();
1061 }
1062 if (reserved)
1063 {
1064 return ipmi::responseInvalidFieldRequest();
Kirill Pakhomov2c2af2c2018-11-06 16:06:10 +03001065 }
1066
Vernon Mauery056fab12023-07-27 14:25:24 -07001067 enum class PowerMode : uint8_t
1068 {
1069 SystemPowerStatistics = 1,
1070 EnhancedSystemPowerStatistics = 2,
1071 };
Marri Devender Rao9c966e02018-01-22 05:55:10 -06001072
Vernon Mauery056fab12023-07-27 14:25:24 -07001073 if (static_cast<PowerMode>(mode) != PowerMode::SystemPowerStatistics)
Marri Devender Rao66c5fda2018-01-18 10:48:37 -06001074 {
Vernon Mauery056fab12023-07-27 14:25:24 -07001075 return ipmi::responseInvalidFieldRequest();
Marri Devender Rao66c5fda2018-01-18 10:48:37 -06001076 }
Vernon Mauery056fab12023-07-27 14:25:24 -07001077 if (attributes)
Marri Devender Rao66c5fda2018-01-18 10:48:37 -06001078 {
Vernon Mauery056fab12023-07-27 14:25:24 -07001079 return ipmi::responseInvalidFieldRequest();
Marri Devender Rao66c5fda2018-01-18 10:48:37 -06001080 }
Marri Devender Rao9c966e02018-01-22 05:55:10 -06001081
Vernon Mauery056fab12023-07-27 14:25:24 -07001082 std::optional<uint16_t> powerResp = readPower(ctx);
1083 if (!powerResp)
1084 {
1085 return ipmi::responseUnspecifiedError();
1086 }
1087 auto& power = powerResp.value();
1088
Marri Devender Rao9c966e02018-01-22 05:55:10 -06001089 // TODO: openbmc/openbmc#2819
Gunnar Mills8466b792018-03-23 12:18:12 -05001090 // Minimum, Maximum, Average power, TimeFrame, TimeStamp,
Marri Devender Rao9c966e02018-01-22 05:55:10 -06001091 // PowerReadingState readings need to be populated
1092 // after Telemetry changes.
Vernon Mauery056fab12023-07-27 14:25:24 -07001093 constexpr uint32_t samplePeriod = 1;
1094 constexpr uint6_t reserved1 = 0;
1095 constexpr bool measurementActive = true;
1096 constexpr bool reserved2 = false;
1097 auto timestamp = static_cast<uint32_t>(time(nullptr));
1098 return ipmi::responseSuccess(power, power, power, power, timestamp,
1099 samplePeriod, reserved1, measurementActive,
1100 reserved2);
Marri Devender Rao66c5fda2018-01-18 10:48:37 -06001101}
1102
Deepak Kodihalli0b459552018-02-06 06:25:12 -06001103namespace dcmi
1104{
1105namespace sensor_info
1106{
1107
Patrick Williams1318a5e2024-08-16 15:19:54 -04001108std::tuple<std::vector<uint16_t>, uint8_t>
1109 read(const std::string& type, uint8_t instance,
1110 const nlohmann::json& config, uint8_t count)
Deepak Kodihallidd4cff12018-02-06 06:48:29 -06001111{
Vernon Mauery53d0cf12023-07-27 14:32:44 -07001112 std::vector<uint16_t> responses{};
Deepak Kodihallidd4cff12018-02-06 06:48:29 -06001113
Vernon Mauery53d0cf12023-07-27 14:32:44 -07001114 static const std::vector<nlohmann::json> empty{};
1115 std::vector<nlohmann::json> readings = config.value(type, empty);
1116 uint8_t totalInstances = std::min(readings.size(), maxInstances);
Deepak Kodihallidd4cff12018-02-06 06:48:29 -06001117 for (const auto& reading : readings)
1118 {
Vernon Mauery53d0cf12023-07-27 14:32:44 -07001119 // limit to requested count
1120 if (responses.size() == count)
1121 {
1122 break;
1123 }
1124
Deepak Kodihallidd4cff12018-02-06 06:48:29 -06001125 uint8_t instanceNum = reading.value("instance", 0);
Vernon Mauery53d0cf12023-07-27 14:32:44 -07001126 // Not in the instance range we're interested in
1127 if (instanceNum < instance)
Deepak Kodihallidd4cff12018-02-06 06:48:29 -06001128 {
1129 continue;
1130 }
1131
Thang Tran5ea83fa2023-10-16 14:37:56 +07001132 uint16_t recordId = reading.value("record_id", 0);
Vernon Mauery53d0cf12023-07-27 14:32:44 -07001133 responses.emplace_back(recordId);
Deepak Kodihallidd4cff12018-02-06 06:48:29 -06001134 }
1135
Vernon Mauery53d0cf12023-07-27 14:32:44 -07001136 return std::make_tuple(responses, totalInstances);
Deepak Kodihalli0b459552018-02-06 06:25:12 -06001137}
1138
1139} // namespace sensor_info
1140} // namespace dcmi
1141
Vernon Mauery53d0cf12023-07-27 14:32:44 -07001142ipmi::RspType<uint8_t, // total available instances
1143 uint8_t, // number of records in this response
1144 std::vector<uint16_t> // records
1145 >
1146 getSensorInfo(uint8_t sensorType, uint8_t entityId, uint8_t entityInstance,
1147 uint8_t instanceStart)
Deepak Kodihalli0b459552018-02-06 06:25:12 -06001148{
Vernon Mauery53d0cf12023-07-27 14:32:44 -07001149 auto it = dcmi::entityIdToName.find(entityId);
Deepak Kodihalli0b459552018-02-06 06:25:12 -06001150 if (it == dcmi::entityIdToName.end())
1151 {
George Liu7fa28712024-07-17 19:26:23 +08001152 lg2::error("Unknown Entity ID: {ENTITY_ID}", "ENTITY_ID", entityId);
Vernon Mauery53d0cf12023-07-27 14:32:44 -07001153 return ipmi::responseInvalidFieldRequest();
Deepak Kodihalli0b459552018-02-06 06:25:12 -06001154 }
1155
Vernon Mauery53d0cf12023-07-27 14:32:44 -07001156 if (sensorType != dcmi::temperatureSensorType)
Deepak Kodihalli0b459552018-02-06 06:25:12 -06001157 {
George Liu7fa28712024-07-17 19:26:23 +08001158 lg2::error("Invalid sensor type: {SENSOR_TYPE}", "SENSOR_TYPE",
1159 sensorType);
Vernon Mauery53d0cf12023-07-27 14:32:44 -07001160 return ipmi::responseInvalidFieldRequest();
Deepak Kodihalli0b459552018-02-06 06:25:12 -06001161 }
1162
Vernon Mauery53d0cf12023-07-27 14:32:44 -07001163 nlohmann::json config = dcmi::parseJSONConfig(dcmi::gDCMISensorsConfig);
Deepak Kodihalli0b459552018-02-06 06:25:12 -06001164
Vernon Mauery53d0cf12023-07-27 14:32:44 -07001165 uint8_t requestedRecords = (entityInstance == 0) ? dcmi::maxRecords : 1;
1166 // Read requested instances
1167 const auto& [sensors, totalInstances] = dcmi::sensor_info::read(
1168 it->second, instanceStart, config, requestedRecords);
1169 uint8_t numRecords = sensors.size();
Deepak Kodihalli0b459552018-02-06 06:25:12 -06001170
Vernon Mauery53d0cf12023-07-27 14:32:44 -07001171 return ipmi::responseSuccess(totalInstances, numRecords, sensors);
Deepak Kodihalli0b459552018-02-06 06:25:12 -06001172}
1173
Chris Austen1810bec2015-10-13 12:12:39 -05001174void register_netfn_dcmi_functions()
1175{
Tom05732372016-09-06 17:21:23 +05301176 // <Get Power Limit>
Vernon Maueryd4222fd2023-07-27 11:26:51 -07001177 registerGroupHandler(ipmi::prioOpenBmcBase, ipmi::groupDCMI,
1178 ipmi::dcmi::cmdGetPowerLimit, ipmi::Privilege::User,
1179 getPowerLimit);
Tom Joseph6f6dd4d2017-07-12 20:07:11 +05301180
Tom Joseph46fa37d2017-07-26 18:11:55 +05301181 // <Set Power Limit>
Vernon Maueryd4222fd2023-07-27 11:26:51 -07001182 registerGroupHandler(ipmi::prioOpenBmcBase, ipmi::groupDCMI,
1183 ipmi::dcmi::cmdSetPowerLimit,
1184 ipmi::Privilege::Operator, setPowerLimit);
Tom Joseph46fa37d2017-07-26 18:11:55 +05301185
Tom Joseph6c8d51b2017-07-26 18:18:06 +05301186 // <Activate/Deactivate Power Limit>
Vernon Maueryd4222fd2023-07-27 11:26:51 -07001187 registerGroupHandler(ipmi::prioOpenBmcBase, ipmi::groupDCMI,
1188 ipmi::dcmi::cmdActDeactivatePwrLimit,
1189 ipmi::Privilege::Operator, applyPowerLimit);
Tom Joseph6c8d51b2017-07-26 18:18:06 +05301190
Tom Joseph6f6dd4d2017-07-12 20:07:11 +05301191 // <Get Asset Tag>
Vernon Mauerydca47202023-07-27 11:32:01 -07001192 registerGroupHandler(ipmi::prioOpenBmcBase, ipmi::groupDCMI,
1193 ipmi::dcmi::cmdGetAssetTag, ipmi::Privilege::User,
1194 getAssetTag);
Tom Joseph545dd232017-07-12 20:20:49 +05301195
1196 // <Set Asset Tag>
Vernon Mauerydca47202023-07-27 11:32:01 -07001197 registerGroupHandler(ipmi::prioOpenBmcBase, ipmi::groupDCMI,
1198 ipmi::dcmi::cmdSetAssetTag, ipmi::Privilege::Operator,
1199 setAssetTag);
Vladislav Vovchenko8f7a6f62017-08-17 00:31:14 +03001200
Gunnar Mills8991dd62017-10-25 17:11:29 -05001201 // <Get Management Controller Identifier String>
Vernon Maueryefb5ae52023-07-27 11:35:43 -07001202 registerGroupHandler(ipmi::prioOpenBmcBase, ipmi::groupDCMI,
1203 ipmi::dcmi::cmdGetMgmtCntlrIdString,
1204 ipmi::Privilege::User, getMgmntCtrlIdStr);
Vladislav Vovchenko8f7a6f62017-08-17 00:31:14 +03001205
1206 // <Set Management Controller Identifier String>
Vernon Maueryefb5ae52023-07-27 11:35:43 -07001207 registerGroupHandler(ipmi::prioOpenBmcBase, ipmi::groupDCMI,
1208 ipmi::dcmi::cmdSetMgmtCntlrIdString,
1209 ipmi::Privilege::Admin, setMgmntCtrlIdStr);
Vladislav Vovchenko8f7a6f62017-08-17 00:31:14 +03001210
Dhruvaraj Subhashchandrane29be412018-01-16 05:11:56 -06001211 // <Get DCMI capabilities>
Vernon Maueryf038dc02023-07-27 14:06:11 -07001212 registerGroupHandler(ipmi::prioOpenBmcBase, ipmi::groupDCMI,
1213 ipmi::dcmi::cmdGetDcmiCapabilitiesInfo,
1214 ipmi::Privilege::User, getDCMICapabilities);
Deepak Kodihalliee717d72018-01-24 04:53:09 -06001215
Marri Devender Rao66c5fda2018-01-18 10:48:37 -06001216 // <Get Power Reading>
Vernon Mauery056fab12023-07-27 14:25:24 -07001217 registerGroupHandler(ipmi::prioOpenBmcBase, ipmi::groupDCMI,
1218 ipmi::dcmi::cmdGetPowerReading, ipmi::Privilege::User,
1219 getPowerReading);
1220
adarshgrami042e9db2022-09-15 10:34:34 +05301221// The Get sensor should get the senor details dynamically when
1222// FEATURE_DYNAMIC_SENSORS is enabled.
1223#ifndef FEATURE_DYNAMIC_SENSORS
Deepak Kodihalli0b459552018-02-06 06:25:12 -06001224 // <Get Sensor Info>
Vernon Mauery53d0cf12023-07-27 14:32:44 -07001225 registerGroupHandler(ipmi::prioOpenBmcBase, ipmi::groupDCMI,
1226 ipmi::dcmi::cmdGetDcmiSensorInfo,
1227 ipmi::Privilege::Operator, getSensorInfo);
Thang Tran3dad8262023-08-17 15:20:56 +07001228
1229 // <Get Temperature Readings>
1230 registerGroupHandler(ipmi::prioOpenBmcBase, ipmi::groupDCMI,
1231 ipmi::dcmi::cmdGetTemperatureReadings,
1232 ipmi::Privilege::User, getTempReadings);
adarshgrami042e9db2022-09-15 10:34:34 +05301233#endif
Nagaraju Goruganti22be97b2018-02-07 01:19:59 -06001234 // <Get DCMI Configuration Parameters>
Vernon Mauery6475b5c2023-07-27 14:52:51 -07001235 registerGroupHandler(ipmi::prioOpenBmcBase, ipmi::groupDCMI,
1236 ipmi::dcmi::cmdGetDcmiConfigParameters,
1237 ipmi::Privilege::User, getDCMIConfParams);
Nagaraju Goruganti22be97b2018-02-07 01:19:59 -06001238
1239 // <Set DCMI Configuration Parameters>
Vernon Mauery6475b5c2023-07-27 14:52:51 -07001240 registerGroupHandler(ipmi::prioOpenBmcBase, ipmi::groupDCMI,
1241 ipmi::dcmi::cmdSetDcmiConfigParameters,
1242 ipmi::Privilege::Admin, setDCMIConfParams);
Nagaraju Goruganti22be97b2018-02-07 01:19:59 -06001243
Chris Austen1810bec2015-10-13 12:12:39 -05001244 return;
1245}